简体   繁体   English

在二次贝塞尔曲线路径上寻找点

[英]Finding Points on a Quadratic Bezier Curve Path

I am attempting to create a shape like the following: 我正在尝试创建如下形状:

螺旋

For the curves of the spiral, I am utilizing Quadratic Bezier Segments. 对于螺旋曲线,我正在使用二次贝塞尔曲线段。

    PathGeometry pg1 = new PathGeometry();
    PathFigure pf1 = new PathFigure()
    {
        StartPoint = new Point(Convert.ToDouble(middle) + 500, Convert.ToDouble(middle) + 500)
    };
    PathSegmentCollection psc1= new PathSegmentCollection();
    QuadraticBezierSegment arcs1 = new QuadraticBezierSegment()
    {
        Point1 = new Point(100, 560),
        Point2 = new Point(pf.StartPoint.X - 300, pf.StartPoint.Y + 200)
    };
    psc1.Add(arcs1);
    pf1.Segments = psc1;
    pg1.Figures.Add(pf1);
    Path spiral1 = new Path()
    {
        Data = pg1,
        Stroke = Brushes.White,
        StrokeThickness = 1.5
    };
    MainScrn.Children.Add(spiral1);

Which outputs an appropriate curve for one of the Paths: 其中一个路径输出适当的曲线: 动画路径显示

I'm sure I marked this up wrong, but here is where and how the variables above are associated with the Bezier Curve. 我确定我标记错了,但是上面的变量在哪里以及如何与Bezier曲线相关联。

二次贝塞尔曲线点

Now what I want is the points along the curve. 现在我想要的是曲线上的点。

段上的点的路径

And I can't receive that from the object. 我不能从对象那里得到它。 I'm trying to collect these points so that I can animate movement of objects along the path of the Bezier Curve and have them stop at different points of the curve. 我正在尝试收集这些点,以便我可以沿Bezier曲线的路径设置物体的运动动画,让它们停在曲线的不同点。 How can I achieve this? 我怎样才能做到这一点?

Suppose you want to compute a point one fifth (or any amount) of the way along the cubic Bezier curve from pf1.StartPoint (P1) to arcs1.Point2 (P3) with the control point arcs1.Point1 (P2). 假设您想要计算沿着三次贝塞尔曲线从pf1.StartPoint (P1)到arcs1.Point2 (P3)的五分之一(或任何数量)的点,控制点为arcs1.Point1 (P2)。

You do it like this: 你这样做:

  • Compute a point one fifth of the way along the straight line from P1 to P2, and call that A 计算从P1到P2的直线的五分之一点,并称之为A.
  • Compute a point one fifth of the way along the straight line from P2 to P3, and call that B 计算从P2到P3的直线的五分之一点,并称之为B.
  • Compute a point one fifth of the way along the straight line from A to B, and that's your answer. 计算从A到B的直线的五分之一点,这就是你的答案。

You can reduce this to a polynomial formula that you can just plug values into and get your answer out of, but this is perhaps more geometrically intuitive and you can probably implement it easily with built in functions in the Point class. 您可以将其缩减为多项式公式 ,您可以将值插入并从中获取答案,但这可能更具几何直观性,您可以使用Point类中的内置函数轻松实现它。

Here's the complete answer. 这是完整的答案。 I calculated the total length of the path with 30 points spread across the path itself (thanks for @samgak for that). 我计算了路径的总长度,在路径上分布了30个点(感谢@samgak)。 I found the average spaced pixel length by dividing the length by the amount of segments, then comparing it to an array of incremented calculations(avg vs next point) between each point. 我通过将长度除以段的数量来找到平均间隔像素长度,然后将其与每个点之间的递增计算(平均值与下一点)的数组进行比较。

Here's the output. 这是输出。

适当的曲线

Here's the code. 这是代码。

            PathGeometry pg1 = new PathGeometry();
            PathFigure pf1 = new PathFigure()
            {
                StartPoint = new Point(Convert.ToDouble(middle) + 500, Convert.ToDouble(middle) + 500)
            };
            PathSegmentCollection psc1= new PathSegmentCollection();
            QuadraticBezierSegment arcs1 = new QuadraticBezierSegment()
            {
                //Point1 = new Point(100, 560),
                Point1 = new Point(150, 480),
                Point2 = new Point(pf.StartPoint.X - 300, pf.StartPoint.Y + 200)
            };
            psc1.Add(arcs1);
            pf1.Segments = psc1;
            pg1.Figures.Add(pf1);
            Path spiral1 = new Path()
            {
                Data = pg1,
                Stroke = Brushes.White,
                StrokeThickness = 1.5
            };
            MainScrn.Children.Add(spiral1);
            Rectangle[] pnt = new Rectangle[30];
            float growth = (float)1 / (float)30;
            float loc = 0;
            MessageBox.Show(growth.ToString());
            double lenOfpath = 0;
            Point pntA = new Point(0, 0);
            int segments = 8; segments++;
            float avgspace = 0;
            for (int length = 0; length < pnt.Count(); length++)
            {
                pnt[length] = new Rectangle();
                pnt[length].Fill = Brushes.Red;
                pnt[length].Width = 10;
                pnt[length].Height = 10;
                double t = loc;
                double left = (1 - t) * (1 - t) * pf.StartPoint.X + 2 * (1 - t) * t * arcs1.Point1.X + t * t * arcs1.Point2.X;
                double top = (1 - t) * (1 - t) * pf.StartPoint.Y + 2 * (1 - t) * t * arcs1.Point1.Y + t * t * arcs1.Point2.Y;
                MainScrn.Children.Add(pnt[length]);
                Canvas.SetLeft(pnt[length], left);
                Canvas.SetTop(pnt[length], top);
                loc = loc + growth;
                if (length > 0)
                {
                    double x10 = Canvas.GetLeft(pnt[length - 1]);
                    double x20 = Canvas.GetLeft(pnt[length]);
                    double y10 = Canvas.GetTop(pnt[length - 1]);
                    double y20 = Canvas.GetTop(pnt[length]);
                    lenOfpath = lenOfpath + Math.Sqrt(Math.Pow(x20 - x10, 2) + Math.Pow(y20 - y10, 2));
                    avgspace = ((float)lenOfpath / (float)segments);
                }
            }
            for (int length = 1; length < pnt.Count(); length++)
            {

                double total = 0;
                double[] smallestpos = new double[pnt.Count()-1];
                for (int digger = length + 1; digger < pnt.Count(); digger++)
                {
                    double x11 = Canvas.GetLeft(pnt[length]);
                    double x22 = Canvas.GetLeft(pnt[digger]);
                    double y11 = Canvas.GetTop(pnt[length]);
                    double y22 = Canvas.GetTop(pnt[digger]);
                    smallestpos[digger-1] = Math.Sqrt(Math.Pow(x22 - x11, 2) + Math.Pow(y22 - y11, 2));
                }
                int takeposition = FindClosest(avgspace, smallestpos);
                double min = smallestpos[takeposition];
                while (length < (takeposition+1))
                {
                    pnt[length].Visibility = System.Windows.Visibility.Hidden;
                    length++;
                }
            }    
        }
        public static int FindClosest(float given_number, double[] listofflts)
        {
            // Start min_delta with first element because it's safer
            int min_index = 0;
            double min_delta = listofflts[0] - given_number;
            // Take absolute value of the min_delta
            if (min_delta < 0)
            {
                min_delta = min_delta * (-1);
            }

            // Iterate through the list of integers to find the minimal delta
            // Skip first element because min_delta is set with first element's
            for (int index = 1; index < listofflts.Count(); index++)
            {
                float cur_delta = (float)listofflts[index] - (float)given_number;
                // Take absolute value of the current delta
                if (cur_delta < 0)
                {
                    cur_delta = cur_delta * (-1);
                }

                // Update the minimum delta and save the index
                if (cur_delta < min_delta)
                {
                    min_delta = cur_delta;
                    min_index = index;
                }
            }
            return min_index;
        }

With Octagons: 八角形:

完成。

Once all sides are completed: 一旦所有方面完成:

在此输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM