2012-06-26 3 views
2

Кто-нибудь видел достойный алгоритм рисования для спиралей cornu (aka, clothoids) или сплайнов? Для дуг и линий у нас есть такие вещи, как алгоритм Брешенема. Является ли это адаптируемым к клотоидам?алгоритм высокоскоростной графики для спирали/сплайна cornu?

Страница Википедии есть этот Sage код:

p = integral(taylor(cos(L^2), L, 0, 12), L) 
q = integral(taylor(sin(L^2), L, 0, 12), L) 
r1 = parametric_plot([p, q], (L, 0, 1), color = 'red') 

Есть ли пример кода для параметрических графиков доступны? Я не вижу многого в поиске в Интернете.

ответ

2

Я не видел ни одного существующего высокоскоростного алгоритма для этого. Однако я пришел к пониманию общего метода рисования таких вещей. По сути, вы рекурсивно разделяете L до тех пор, пока вычисленные левые, средние и правые точки не будут достаточно близки к прямой, чтобы вы могли рисовать эту линию. Я смог использовать MathNet.Numerics.dll для интеграции. Некоторый код:

public static void DrawClothoidAtOrigin(List<Point> lineEndpoints, Point left, Point right, double a, double lengthToMidpoint, double offsetToMidpoint = 0.0) 
    { 
     // the start point and end point are passed in; calculate the midpoint 
     // then, if we're close enough to a straight line, add that line (aka, the right end point) to the list 
     // otherwise split left and right 

     var midpoint = new Point(a * C(lengthToMidpoint + offsetToMidpoint), a * S(lengthToMidpoint + offsetToMidpoint)); 
     var nearest = NearestPointOnLine(left, right, midpoint, false); 
     if (Distance(midpoint, nearest) < 0.4) 
     { 
      lineEndpoints.Add(right); 
      return; 
     } 
     DrawClothoidAtOrigin(lineEndpoints, left, midpoint, a, lengthToMidpoint * 0.5, offsetToMidpoint); 
     DrawClothoidAtOrigin(lineEndpoints, midpoint, right, a, lengthToMidpoint * 0.5, offsetToMidpoint + lengthToMidpoint); 
    } 

    private static double Distance(Point a, Point b) 
    { 
     var x = a.X - b.X; 
     var y = a.Y - b.Y; 
     return Math.Sqrt(x * x + y * y); 
    } 

    private static readonly double PI_N2 = Math.Pow(Math.PI * 2.0, -0.5); 

    public static double C(double theta) 
    { 
     return Integrate.OnClosedInterval(d => Math.Cos(d)/Math.Sqrt(d), 0.0, theta)/PI_N2; 
    } 

    public static double S(double theta) 
    { 
     return Integrate.OnClosedInterval(d => Math.Sin(d)/Math.Sqrt(d), 0.0, theta)/PI_N2; 
    }