2015-05-20 3 views
2

Я пытаюсь создать форму, как следующее:Нахождение точки на пути Квадратичная кривая Безье

Spiral

Для кривых спирали, я использованием квадратичного Безье сегментов.

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); 

который выводит соответствующую кривую для одного из путей: animation path displayed

я уверен, что я отметил это вверх неправильно, но вот где и как переменные выше, связанные с кривой Безье.

Quadratic Bezier Curves Points

Теперь то, что я хочу, это точки вдоль кривой.

Path with points on segment

И я не могу получить, что от объекта. Я пытаюсь собрать эти точки, чтобы я мог анимировать движение объектов по пути кривой Безье и остановить их в разных точках кривой. Как я могу это достичь?

+0

ли их вычисления вручную из вопроса \ – ChiefTwoPencils

+0

Да, потому что мне нужно? быть в состоянии добавлять и вычитать объекты по пути. например Путь 1 имеет 7 объектов, путь 8 имеет 13 объектов и т. Д. – Rich

+0

Да, но поскольку новый ответ, на мой взгляд, заключается в том, что вы можете контролировать, сколько очков составляет кривая. Таким образом, вы разделили строки в соответствии с количеством необходимых объектов. – ChiefTwoPencils

ответ

1

Предположим, вы хотите, чтобы вычислить точку одну пятую (или любого размера) пути вдоль кубической кривой Безье из pf1.StartPoint (Р1) до arcs1.Point2 (P3) с контрольной точкой arcs1.Point1 (P2).

Вы сделать это следующим образом:

  • Compute точка одна пятая часть пути по прямой линии от P1 до P2, и называем это
  • Compute точка одна пятая часть пути вдоль прямая линия от P2 до P3 и называть это B
  • Вычислите точку на одну пятую пути по прямой линии от A до B, и это ваш ответ.

Вы можете уменьшить это к polynomial formula, что вы можете просто подключить значения в и получить ответ из, но это, пожалуй, более геометрический интуитивные и вы, вероятно, можете реализовать его легко со встроенными функциями в Point классе.

+0

Хорошо. Спасибо за это, это помогает мне найти точку на пути, но как я могу убедиться, что каждая точка равномерно отстоит от пути? – Rich

+1

Предположим, вам нужно 10 точек на кривой (включая начальную и конечную точки). Начните с 0 и увеличивайте свой параметр на 1/9 каждый раз, до 1. Затем используйте этот параметр в приведенной выше формуле. Итак, первая точка - это 1/9 пути, вторая точка - 2/9 пути и т. Д. – samgak

+0

Отлично. Спасибо, сэр. – Rich

1

Вот полный ответ. Я вычислил общую длину пути с 30 точками, распределенными по самому пути (спасибо за @samgak за это). Я нашел среднюю длину пикселя с интервалом, разделив длину на количество сегментов, а затем сравнил ее с массивом инкрементных вычислений (avg vs next point) между каждой точкой.

Вот выход.

proper curve

Вот код.

  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; 
     } 

С восьмиугольника:

completed.

После того, как все стороны будут завершены:

enter image description here

+0

+1 Выглядит неплохо, но, возможно, вам следует установить float growth = (float) 1/(float) 29; так что вы вычисляете точку прямо в конце кривой? (последнее значение длины в цикле будет равно 29). – samgak

+0

Знаете, после того, как я закончил его, и я начал изменять параметры, изменив это на (float) 29, не помог отрегулировать его по длине. Но это нормально. Я получил результат, который я искал. Проверьте законченную дорожку выше. Я даже получил его анимированный сейчас! :) Еще раз спасибо за все. – Rich

Смежные вопросы