Question

Has anyone seen a decent drawing algorithm for cornu spirals (aka, clothoids) or splines? For arcs and lines we have things like Bresenham's algorithm. Is that adaptable to clothoids?

The Wikipedia page has this Sage code:

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

Is there any example code for parametric plots available? I'm not seeing much with my web searches.

Was it helpful?

Solution

I didn't see any existing high-speed algorithm for this. However, I did come to understand the common method for drawing things like this. Essentially, you recursively split the L until the left, mid, and right points calculated are close enough to a straight line that you can draw that line. I was able to use the MathNet.Numerics.dll for the integration. Some code:

    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;
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top