午後わてんのブログ

ベランダ菜園とWindows用アプリ作成(WPFとC#)

マウスクリックでCanvasにベジェ曲線で曲線、PolyBezierSegment

System.Windows.Media.PolyBezierSegment
 
Path.Dataの
PathGeometryの
FigureのSegmentに
PolyBezierSegmentを指定してベジェ曲線
ってのはおとといのベジェ曲線で直線と同じ方法で、制御点座標を調整するようにして曲線にする
 
 
今回のアプリのダウンロード先
イメージ 1
クリックしたところがアンカーポイントになる
 
 
デザイン画面

f:id:gogowaten:20191213095116p:plain

この前と同じ
 
 
コード
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;

namespace _20180610_マウスクリックでベジェ曲線
{
    public partial class MainWindow : Window
    {
        PolyBezierSegment MySegment;
        public MainWindow()
        {
            InitializeComponent();

            MyInitialize();
            MyCanvas.MouseLeftButtonDown += MyCanvas_MouseLeftButtonDown;
            MyCanvas.MouseMove += MyCanvas_MouseMove;
            MyCanvas.MouseRightButtonDown += MyCanvas_MouseRightButtonDown;
        }
        private void MyCanvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            MySegment.Points.Clear();
        }
        //Path.Dataを作成
        private void MyInitialize()
        {
            MySegment = new PolyBezierSegment();
            var pf = new PathFigure();
            pf.Segments.Add(MySegment);
            var pg = new PathGeometry();
            pg.Figures.Add(pf);
            MyPath.Data = pg;
        }
        //マウス移動時、終端のアンカーポイント移動とその他の制御点の位置調整
        private void MyCanvas_MouseMove(object sender, MouseEventArgs e)
        {
            PointCollection ps = MySegment.Points;
            if (ps.Count > 5)
            {               
                Point p = e.GetPosition(MyCanvas);//マウスカーソル位置

                //最後のアンカーポイントの座標は今のカーソル座標
                ps[ps.Count - 1] = p;

                Point ap1 = ps[ps.Count - 4];//一個前のアンカーポイント
                Point ap2;//二個前のアンカーポイント
                if (ps.Count < 7)
                {
                    var pg = (PathGeometry)MyPath.Data;
                    var pathFigureCollection = pg.Figures;
                    ap2 = pathFigureCollection[0].StartPoint;
                }
                else
                {
                    ap2 = ps[ps.Count - 7];
                }

                //最後のアンカーポイントと二個前のアンカーポイントとの距離の1 / 4
                double xDiff = (p.X - ap2.X) / 4.0;
                double yDiff = (p.Y - ap2.Y) / 4.0;
                //一個前のアンカーポイントの制御点座標
                ps[ps.Count - 3] = new Point(ap1.X + xDiff, ap1.Y + yDiff);
                ps[ps.Count - 5] = new Point(ap1.X - xDiff, ap1.Y - yDiff);

                //最後のアンカーポイントと一個前のアンカーポイントの距離の1/4
                xDiff = (p.X - ps[ps.Count - 3].X) / 4.0;
                yDiff = (p.Y - ps[ps.Count - 3].Y) / 4.0;
                //最後のアンカーポイントの制御点座標
                ps[ps.Count - 2] = new Point(p.X - xDiff, p.Y - yDiff);
            }
            else if (MySegment.Points.Count > 0)
            {               
                //最後のアンカーポイントのインデックスはCount-1
                ps[ps.Count - 1] = e.GetPosition(MyCanvas);//カーソル位置に
            }
        }
        //マウスクリック時、アンカーポイントと制御点2つを追加
        private void MyCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var p = e.GetPosition(MyCanvas);
            //最初のクリック時だけはStartPointを指定する
            if (MySegment.Points.Count == 0)
            {
                var pathGeometry = (PathGeometry)MyPath.Data;
                var pathFigureCollection = pathGeometry.Figures;
                pathFigureCollection[0].StartPoint = p;
                //制御点2つとアンカーポイント追加
                MySegment.Points.Add(p);
                MySegment.Points.Add(p);
                MySegment.Points.Add(p);
            }
            else
            {
                //制御点2つとアンカーポイント追加
                MySegment.Points.Add(p);
                MySegment.Points.Add(p);
                MySegment.Points.Add(p);
            }

        }
    }
}
 
前回から変更があったのはマウス移動時のところ
 
 
 
なめらかなベジェ曲線を描くには制御点座標を調整
イメージ 3
灰色がアンカーポイント
紫色が制御点
アンカーポイント03の制御点02と04の座標を調整して
 
イメージ 4
対角線上みたいに配置すると線がなめらかになる
 
 
マウスカーソル位置を終端のアンカーポイントとしたときに連動させる制御点座標の決め方は
Pixtack紫陽花2.6.50.134_マウスクリックでもベジェ曲線を描けるようにした ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/12656208.html
この記事より

f:id:gogowaten:20191213095438p:plain

こんな感じで
 
 
ベジェ曲線はアンカーポイントと制御点の2種類のポイント(座標)があって
始点と終点のアンカーポイントには1つの制御点
それ以外のアンカーポイントには2つの制御点が付く
イメージ 5
始点の00には制御点01
終点の09には制御点08
それ以外の03と06にはそれぞれ2つの制御点02と04、05と07
 
Path.Dataの
PathGeometryの
FigureのSegmentに
PolyBezierSegmentを指定してベジェ曲線
FigureのStartPointに始点座標を指定して、それ以降の座標はPolyBezierSegmentに入れていくことになる
上の図だと
Figure.StartPoint = new Point(50, 50);
PolyBezierSegment.Points.Add(new Point(150, 50);
PolyBezierSegment.Points.Add(new Point(322, 72);
 
なので始点だけ特別扱いみたいになる
 
イメージ 6
49行目からの二個前のアンカーポイントを取得するところがめんどくさくなっているは始点が特別扱いだから、これがなければ58行目だけで済むんだけどなあ
アンカーポイントとその制御点の距離は一個前や二個前のアンカーポイントとの距離の1/4って決めたから4.0で割っている、1/4に決めたのは適当だったから
 
 
MainWindow.xaml
MainWindow.xaml.cs
 
 
 
関連記事
次回、2018/06/12は翌日
ベジェ曲線の方向線とアンカーポイント、制御点を表示してみた ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15547295.html
 
前回、2018/06/09は2日前
マウスクリックでCanvasに直線を描画その3、ベジェ曲線で直線、PolyBezierSegment ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15542192.html
 
2015/1/27は3年前
Pixtack紫陽花2.6.50.134_マウスクリックでもベジェ曲線を描けるようにした ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/12656208.html