X3

RedSky

导航

WPF点连成曲线,贝塞尔曲线两种画法

先看效果图:

      黑色是需要经过的点;

      黄色为控制点;

      绿色为两点之间的中点。

方式一:

方式二:

<Canvas x:Name="canvas2"/>

 

方法一代码,【这是别人的代码,时间久了忘记原出处了】:

        Path path;
        public void UpdateRoad(List<Point> list)
        {
            double x = this.canvas2.ActualWidth;
            double y = this.canvas2.ActualHeight;
            PathFigure pf = new PathFigure();

            pf.StartPoint = list[0];
            List<Point> controls = new List<Point>();
            for (int i = 0; i < list.Count; i++)
            {
                controls.AddRange(Control1(list, i));
            }
            for (int i = 1; i < list.Count; i++)
            {
                BezierSegment bs = new BezierSegment(controls[i * 2 - 1], controls[i * 2], list[i], true);
                bs.IsSmoothJoin = true;

                pf.Segments.Add(bs);
            }
            PathFigureCollection pfc = new PathFigureCollection();
            pfc.Add(pf);
            PathGeometry pg = new PathGeometry(pfc);

            path = new Path();
            path.Stroke = Brushes.Black;
            path.Data = pg;
            canvas2.Children.Add(path);
        }

        public List<Point> Control1(List<Point> list, int n)
        {
            List<Point> point = new List<Point>();
            point.Add(new Point());
            point.Add(new Point());
            if (n == 0)
            {
                point[0] = list[0];
            }
            else
            {
                point[0] = Average(list[n - 1], list[n]);
            }
            if (n == list.Count - 1)
            {
                point[1] = list[list.Count - 1];
            }
            else
            {
                point[1] = Average(list[n], list[n + 1]);
            }
            Point footPoint = Average(point[0], point[1]);
            Point sh = Sub(list[n], footPoint);
            point[0] = Mul(Add(point[0], sh), list[n]);
            point[1] = Mul(Add(point[1], sh), list[n]);
            AddPoint(point[0]);
            AddPoint(point[1]);
            return point;
        }
        public Point Average(Point x, Point y)
        {
            return new Point((x.X + y.X) / 2, (x.Y + y.Y) / 2);
        }
        public Point Add(Point x, Point y)
        {
            return new Point(x.X + y.X, x.Y + y.Y);
        }
        public Point Sub(Point x, Point y)
        {
            return new Point(x.X - y.X, x.Y - y.Y);
        }
        public Point Mul(Point x, Point y, double d = 0.6)
        {
            Point temp = Sub(x, y);
            temp = new Point(temp.X * d, temp.Y * d);
            temp = Add(y, temp);
            return temp;
        }

 方式二代码:

        Path path2 = null;
        private void PaintLine(List<Point> points)
        {
            StringBuilder data = new StringBuilder("M");
            data.AppendFormat("{0},{1} C", points[0].X, points[0].Y);for (int i = 1; i < points.Count; i++)
            {
                Point pre = new Point((points[i - 1].X + points[i].X) / 2, points[i - 1].Y);  //控制点
                Point next = new Point((points[i - 1].X + points[i].X) / 2, points[i].Y);     //控制点
                data.AppendFormat(" {0},{1} {2},{3} {4},{5}", pre.X, pre.Y, next.X, next.Y, points[i].X, points[i].Y);
            }

            path2 = new Path { Stroke = Brushes.DodgerBlue, StrokeThickness = 1, Data = Geometry.Parse(data.ToString()) };
            this.canvas2.Children.Add(path2);
        }

 方法二逻辑简单得多,代码量也特别少,控制点为两点之间的中点,然后第一个控制点与第一个点水平,第二个控制点与第二个点水平。

posted on 2020-09-02 10:49  HotSky  阅读(2083)  评论(0编辑  收藏  举报