9
$\begingroup$

As part of an iOS app I’m making, I want to draw a decent approximation of an Archimedes spiral. The drawing library I’m using (CGPath in Quartz 2D, which is C-based) supports arcs as well as cubic and quadratic Bézier curves. What is a good method of approximating an Archimedes spiral using either of these path types? For example the wikipedia exemplar image says it was “drawn as a series of minimum-error Bézier segments.” How would one generate such segments?

My math background takes me through Calculus III plus some stuff I picked up from a classical mechanics class, but it’s been a couple of years so I’m rusty. What I have so far:

For a spiral r = a + b $\theta$, I used the information from this page to find that the cartesian slope at any point (r, $\theta$) is equal to

$$\frac{dy}{dx}=\frac{b\sin\theta\space+\space(a + b\theta)\cos\theta}{b\cos\theta\space-\space(a + b\theta)\sin\theta}$$

From here, I could use point-slope to find the equation of a tangent line at any point, but how do I go about finding the proper lengths of the handles (i.e. the positions of the middle two points) for the curve? Or would an approximation with circular arc segments be better/easier/faster?

If I can’t figure it out, I’ll just use a static image in the app, but it occurs to me that I don’t even know of a way to generate a high-quality image of an Archimedes spiral! The Spiral tool in Illustrator, for example, does only logarithmic spirals.

$\endgroup$
10
  • $\begingroup$ Your drawing library can't evaluate trigonometric functions? $\endgroup$ Commented Aug 5, 2012 at 5:21
  • 1
    $\begingroup$ Then, why not just use the actual parametric equations for the Archimedean spiral instead of trying to draw a Bézier approximation? $\endgroup$ Commented Aug 5, 2012 at 5:28
  • 1
    $\begingroup$ @J.M. Most drawing libraries outside of specialized math software only allow drawing primitives like line segments, ellipses, and cubic Bézier curves, but not arbitrary parametric curves. I expect Zev can evaluate trigonometric functions to pick the parameters for these primitives, but cannot make the curve follow an arbitrary parametric path. $\endgroup$
    – user856
    Commented Aug 5, 2012 at 5:41
  • 1
    $\begingroup$ This comment doesn't answer the question as stated, but if I were you, @Zev, I'd just evaluate positions along the curve at small increments of $\theta$ and connect them with a series of line segments. $\endgroup$
    – user856
    Commented Aug 5, 2012 at 5:44
  • 1
    $\begingroup$ Drawing lots of straight-line segments is a bad idea; in many graphics libraries it can cause rendering errors (e.g. because of overlapping antialiasing or rounding issues). Quartz doesn’t suffer so much from that, but under Quartz performance will be hideous because in order to avoid the antialiasing problem it needs to compute self-intersections. $\endgroup$
    – al45tair
    Commented Feb 3, 2014 at 17:38

2 Answers 2

3
$\begingroup$

So it looks like the Wikipedia reference image uses 45 degree sections of these curves. You can use the equation for the spiral to give you the tangent line at the beginning and end of these curve sections. Evaluate the derivative at these two points to get the tangent line slope and then shift your line appropriately to hit the point used. The intersection Of these two lines should be your control point. Once you have found your control point you can put it in the function 'CGPathAddQuadCurveToPoint' for the cx, cy (I think) along with the point you want to go to (also from the spiral equation). For reference--check out the animation under 'quadratic curves' here

For extra speed, you only have to find 8 tangent lines max--just shift them out for the next cycle of the spiral and reuse them.

$\endgroup$
7
  • $\begingroup$ I think your Wikipedia link might work better if you use the syntax [link text](URL goes here). $\endgroup$
    – user856
    Commented Aug 5, 2012 at 5:46
  • $\begingroup$ So, if I understand you, I use the intersection of adjacent tangent lines as the control points for my quad curves? $\endgroup$ Commented Aug 5, 2012 at 5:46
  • $\begingroup$ Your wikipedia link is from the mobile site, and the Stack Exchange link parser doesn't like it. Here's the desktop link: en.wikipedia.org/wiki/… $\endgroup$ Commented Aug 5, 2012 at 5:49
  • 1
    $\begingroup$ @Zav Eisenberg the lines on the animation on Wikipedia are tangent lines, the define the control point. So yes, that is the point you use. $\endgroup$
    – JoshRagem
    Commented Aug 5, 2012 at 5:49
  • $\begingroup$ Thanks for the link, I was typing on my phone so it's a little trickier. $\endgroup$
    – JoshRagem
    Commented Aug 5, 2012 at 5:51
2
$\begingroup$

Bézier cubic has eight parameters, four for x function, four for y function. Impose on the spiral segment that:

  • Endpoints go through correct places (four constraints);
  • Tangent at endpoints have correct angle (two constraints);
  • Curvatures at endpoints are correct (two constraints).

In practice, as tested, for 60° pieces, at any plausible resolution, that is indistinguishable from mathematical perfection.

There is an implementation in PostScript at github.com/jdaw1/placemat/, within which search for /ArchimedeanSpiralPath and /ApproximatingCurve.

This idea generalises beyond a spiral, and there is test output for multiple functions (Archimedes spiral on page 57), some of which approximate well, and others not. (The green line is the correct moveto lineto … lineto mathematical curve; the thin black is the Bézier cubic approximation.) It is ‘discussed’ on comp.lang.postscript.

Also see relevant PNG.

If drawing a circle with a Bézier cubic the error varies as the sixth power of the angle (details on comp.lang.postscript). I suspect, but haven’t bothered to prove, that the same is true here. Assuming that, reducing the angle size from 60° to 45° would reduce the error by a factor of ¾⁶ ≈ 0.178 ≈ 1 / 5.6, and reducing from 60° to 30° would be a 64-fold improvement.

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .