Thoughts and adventures in maps, Flash, visualization, and anything in between

Continuous curves with ActionScript 3

Seeing my comrade Zach Johnson’s impressive work on generating isoline maps in Flash, I offered to try to lend a hand with smoothing the lines (point-to-point connections) he was deriving from interpolations via Delauney triangulation. I first turned to the fantastic book Foundation Actionscript 3.0 Animation: Making Things Move!, in which Keith Peters presents a method for drawing a continuous curve based on multiple points. (Grant Skinner has a post with a nice demo of the same method and an even cooler demo of a double-line version for fills.) While the method produces a nice, smooth, continuously curved line, it’s not very appropriate for the isoline problem because the curve doesn’t actually pass through any of the specified points, save the first and last. The points in this case are interpolations, so a smoothed line that is essentially an interpolation of an interpolation would be sacrificing too much accuracy.

Bezier curves

The bottom line is that I had no luck finding a satisfactory way to use Flash’s built-in curveTo method—which draws quadratic Bézier curves—and instead opted for creating cubic Bézier curves (compare the two in the above image from the Flash documentation). Thanks to Flash’s BezierSegment class, it’s pretty easy to construct these curves. With my limited understanding of the math involved, however, finding good control points for a continuous curve was a bit more challenging.

I put together an AS3 CubicBezier class, which for now just contains two methods: one to draw a continuous series of curves through many points (as was my goal), and one to draw a single curve between two points (seemed worthwhile to throw that in), both demonstrated below. I’m sure there are a few kinks (ha!) to work out, but generally the results seem pretty satisfying. This was written with cartographic generalization in mind, but hopefully it can be more broadly useful.

Files:
CubicBezier.as
curveTest.zip (AS plus the above demo)

Tagged , , ,

9 Comments

  1. [...] ensured isolines would still pass through the interpolated values. You can read about the method in his post. Here she [...]

    indiemaps.com/blog » isolining package for ActionScript 3
    9 June 2008 @ 1:16am

  2. [...] Continuous curves with ActionScript 3 [...]

    Kelso’s Corner » Blog Archive » New blog: Cartogrammer
    15 June 2008 @ 2:46pm

  3. Hi…
    Nice work…considering your ‘limited understanding of the math involved’ … Q: Am I blind? Is that i don’t see where you finally use the z factor (third argument of the curveThroughPoints method)… Thanks

    alvaro obyrne
    20 June 2008 @ 2:37pm

  4. Yikes, thanks for noticing that! Looks like I hard coded a number in when I was messing around with it and forgot to change it back.

    Line 146 of CubicBezier.as, which says:
    var controlDist = Math.min(a,b)*.5
    Should be:
    var controlDist = Math.min(a,b)*z

    I’ve loaded the corrected file to the links given in the post.

    Andy Woodruff
    20 June 2008 @ 2:55pm

  5. thanks

    alvaro obyrne
    20 June 2008 @ 3:07pm

  6. Sorry if you don’t consider this is not the place to post this but have you seen the java demo at http://www.sunsite.ubc.ca/LivingMathematics/V001N01/UBCExamples/Bezier/bezier.html the athor of that applet doesn’t use 100 points in each segment of the curve. He uses a variable number of steps according to the curvature (the straighter the less number of points he uses). If I may say: that should be your next step (I should even farther say : this should be our next step).

    alvaro obyrne
    20 June 2008 @ 3:19pm

  7. Thanks for the link; I hadn’t seen that. Yeah, it’d be good to draw the curves like that. I don’t know that I’ll get around to thinking about that very soon, but if you feel like trying it out I’d definitely love to see what you come up with!

    Andy Woodruff
    20 June 2008 @ 6:55pm

  8. On line 150
    var theta = Math.atan(ry / rx);

    if ry and rx is 0, theata gets NaN, because it cant be 0/0

    if (isNaN(theta)){
    theta = 0;
    }

    Is it right? =)

    //Dennis Öhman =)

    Dennis Öhman
    4 August 2008 @ 4:53am

  9. Sorry, it’s not right solution =D

    Dennis Öhman
    4 August 2008 @ 9:41am

Leave a Comment