gSkinner - Home

Drawing Curved Lines Simplified

Posted on May 30, 2008 by Grant Skinner

I’m bad at drawing curved lines in ActionScript. I’m always too lazy to figure out how to calculate exactly where the control point should go when using curveTo. Because of this, most of my experiments have relied on drawing a lot of short straight line segments to simulate curves, rather than figuring out how to draw the curves properly. For example, my tree experiments are drawn entirely with straight line segments.

While revisiting my grass simulations I decided to bite the bullet and figure out an easy way to work with curves. The result is a couple of “spikes” or isolated test cases that demonstrate the logic behind converting a series of straight lines into a nice looking curve.

The basic concept is to bisect each of the straight lines, then draw a curve between the bisections, using the original points as the curve’s control point. Nothing new I’m sure, but it works really well for me, because I can continue to think in straight lines, but draw in curves.

Click to add points. Click and drag points to move them.

I also extended this logic to work with fills, which is handy for drawing for drawing things like grass, seaweed, and tentacle monsters (I’m looking at you Peter Organa). To do this, you need to calculate the average angle for each point based on the next and previous points, then draw your curves along points tangential to that angle. If that doesn’t make a lot of sense, the example below should clear it up. It’s not perfect (still need to deal with the “flip” point that results in crossed lines), but it’s been good enough for some of my recent experiments.

You can download the test files here.

Follow @gskinner on Twitter for more news and views on interactive media.
26 Comments

whoa, this is crazy timing...i was just experimenting with drawing curves! thanks again for the source, im excited to check it out.

Posted by: jon on May 30, 2008 11:14am URL: http://grenethumb.com

Thanks for saving the day! We just needed this for our project! Thanks for sharing!

Posted by: Jankees on May 30, 2008 11:40am URL: http://blog.6angrymen.com

what can i say? it's beautiful...

Posted by: charon on May 30, 2008 1:41pm

Great stuff. One quick question though. When I grab the control point at the top left of the "G" and drag it toward the top left corner, there is a point at which the lines cross. Any reason for this behavior?

Posted by: jeremy on May 30, 2008 1:55pm

I was also experimenting with something like this, trying to figure out how to manage the control points in the curveTo.

So this is very timely. Thanks for sharing.

Posted by: Gilbert Mizrahi on May 30, 2008 3:37pm URL: http://http:/mylinerider.com

I just recently finished a smooth painter implementation which works essetially like this. I already knew how to go about dividing up the lines, though.

For the smooth painter, though, I couldn't use curveTo because of the way the brush worked, actively sampling the colors below it. So I ended up making a quick point interpolation thing. Same principle as what you made here, though.

I also decided to deprive my self of sleep and play with the curve thing a bit... http://www.box.net/shared/t9mxnbio8w

Posted by: Joseph Sikorski on May 31, 2008 1:30am

jeremy, as I mentioned above, the point at which the tangent points flip needs to be fixed. They should flip at the point at which the angle in and out are reversed (180 deg apart), but they currently flip at a fixed rotation. I'm planning to fix this, just haven't had a chance yet. If anyone gets to it before I do, please post back here.

Posted by: Grant Skinner on May 31, 2008 9:32am URL: http://gskinner.com/blog/

I'm not exactly sure how to solve the flipping with how you did it, though I'm sure it's trivial. Here's how I wrote the draw function, though. And it automatically flips correctly, too.

function draw():void

{

var g:Graphics = graphics;

g.clear();

var prevMidpta:Point = null;

var prevMidptb:Point = null;

var prevNpa:Point = null;

var prevNpb:Point = null;

var l:Number = pts.length;

for (var i:Number=0; i

Posted by: Joseph Sikorski on May 31, 2008 2:29pm

Hello Grant!

In the context of your experiments, a pretty little problem to solve : how would you draw circle segments with curveTo ?

What I was doing is split the circle curve in 4 or 5 arcs, then interpolate point coords in the last incomplete section ... but i never got to a trully accurate solution.

Any ideas ?

Posted by: laz9 on Jun 1, 2008 5:49am

hi,

I desperately search a method/algorithm for drawing an arc of bezier (partial bezier)

ex:

drawBezierArc(pointA:Point,pointB:Point,pointCtrl:Point,distance:Number)

where distance

Posted by: xeo on Jun 2, 2008 1:59am

Oh, wow! Grant Skinner mentioned me in a blog post. My heart is aflutter!

Alright Grant, I'll give my tentacle monster another shot, this time with better math!

Thanks for posting the code!

I just finished playing with Flickr/as3flickrlib so this will probably be my next project.

Posted by: Peter Organa on Jun 3, 2008 12:46pm URL: http://blog.organa.ca/

laz9: Quadratic splines can't be used to make a perfect circle. Old truetype fonts (which use them) usually had circles represented by an octogon.

xeo: Does it have to be by distance or will t value suffice?

Posted by: Joseph Sikorski on Jun 3, 2008 5:48pm

This reminds me of the "Alt+Drag line" feature to pull/push curves from lines...in the Macromedia Freehand program (RIP). I wanted do something similar with ActionScript. Thanks for posting!

Posted by: Keith H on Jun 8, 2008 9:26am URL: http://keith-hair.com

Good stuff, Grant.

By clicking on your demo, I added a point which controls the curve. However my long-time wish list has been a little different: is there anyway to make it so that by clicking, I can add a point where the curve will go through? I don't care which direction it curves to. :)

Thanks for the code again.

Posted by: hu on Jun 9, 2008 10:54am URL: http://interactivesection.wordpress.com/

hi! i am not able to open the .fla test files ..i am using flash professional8 in win xp..dunno wats wrong..i cant open it in adobe flash player also..i really need to test this code. can ne1 twll me wats wrong?

Posted by: arthi on Jun 23, 2008 12:27am

hi! i cant seem to open the .fla files of the test files..i am using flash8 in win xp..m neitehr able to open it in flash player. can ne1 tell me wats wrong? i realy need to test this code..

Posted by: rt on Jun 23, 2008 12:33am

You will need Flash CS3 to open the FLA.

Posted by: Grant Skinner on Jun 23, 2008 8:45am URL: http://gskinner.com/blog/

Hi Grant,

I am an old fan of your works. We used your UML designer to generate our class hierarchy for our one of very prestigiuos product and am a regular reader of your blog as well.

I must say this demo is "Speechless" stunning and absolutely fabulous.

I have learned a lot from your blog and dont wanna mis the opportunity to say "Thanks .. Thanks a lot"

God bless you. keep writing

Anand

Posted by: anand vardhan on Jun 24, 2008 5:28am URL: http://www.anandvardhan.com

This is nice work, and can be the starting point for a lot of people with regard to smoothing; yet, what would really be interesting to me, is if you could reverse the construction of the quadratic bezier, knowing just the vertex and two additional points on the line, to find the control point; now if you can do that your math_fu is strong.

I have been trying to perfect my line smoothing code for a while now; although, I have been able to find the the control point for the quadratic bezier/parabola if the outermost points are an equal distance from the vertex at any degree; however, I am finding it very difficult to find any documentation on how to find it if the outermost points of the cage are not equidistant from the vertex.

People have gone so far as to tell me it is impossible; to that I respond that the bezier would be impossible if this were true. I have actually reversed the construction for a certain type of triangle that has a degree greater than 90 for one of its corners.

Your still the god of trees in my book; however, could you also be the god of quadratics?

Posted by: Anthony Pace on Jul 7, 2008 8:39pm

Very nice GS, thanks for sharing! I struggled w/ this for a while, and finally found a nice bezier curve-fitting function in the Tweener package.

http://labs.zeh.com.br/blog/?p=104#, the closed shape is something new though. very cool.

Posted by: hebchop on Jul 28, 2008 9:56am URL: http://www.jacobmake.com

This is an amazing example and thank you so much for posting the code. As I attempt to fill in the double-lined shape with a solid color, I am getting undesirable results. Would you please offer a code solution to how to fill in this shape? Thank you so much.

Posted by: chris on Oct 17, 2008 10:22am

That is one cool application of action script. Wow.

Great job and thanks for sharing

Posted by: Domek on Oct 17, 2008 12:09pm URL: http://theanimeblizzard.com/

REFACTORED FOR USE WITH FILL AND CLOSED EDGES

preview:

http://labs.review.one-agency.be/labs/curvetest/

ps( movieclips on stage are named points now);

/**

* CurveTests by Grant Skinner. May 30, 2008

* Visit www.gskinner.com/blog for documentation, updates and more free code.

*

* revisioned by Jelger Muylaert. Jan 6 2009

*

* You may distribute and modify this code freely.

*

*/

// for unloading:

function halt():void {

removeEventListener(MouseEvent.MOUSE_DOWN,handlePress);

stage.removeEventListener(MouseEvent.MOUSE_MOVE,doDrag);

stage.removeEventListener(MouseEvent.MOUSE_UP,endDrag);

}

//

var pts:Array = [point1, point2, point3, point4, point5, point6];

var r:Number = point1.width/2;

var curvePoints:Array = [];

var g:Graphics = graphics;

var color:uint = 0x66ffff;

draw();

function draw():void

{

getCurvePointsBottomUp();

drawCurve();

}

function getCurvePointsBottomUp():void

{

g.clear();

var prevMidpta:Point = null;

var prevMidptb:Point = null;

var prevNpa:Point = null;

var prevNpb:Point = null;

var l:Number = pts.length;

var pt1:Object;

var pt2:Object;

var pt3:Object;

var n1:Point;

var n3:Point;

var npa:Point;

var npb:Point;

var scaledR:Number;

curvePoints = [];

for (var i:uint=0; i

Posted by: Jelger on Jan 6, 2009 3:37pm

Hi, Grant, I've been looking for a lasso tool example source code for my work but I can't find any so I'm trying to develop one DIY & ur code is really helpful. Also thanks to the code enhanced by Joseph Sikorski & Jelger.

Has any one already developed a lasso tool before? Care to give me some help especially the ant-moving animation & how to find all points inside the lasso curved polygon?

Posted by: scott chu on Nov 14, 2009 6:56am

hello. it modifies for several lines. a punteada line is possible thanks

function halt():void {

removeEventListener(MouseEvent.MOUSE_OVER,handlePress);

stage.removeEventListener(MouseEvent.MOUSE_MOVE,doDrag);

stage.removeEventListener(MouseEvent.MOUSE_UP,endDrag);

}

var pts:Array = [pt1,pt2,pt3,pt4,pt5,pt6];

draw();

function draw():void {

var g:Graphics = graphics;

g.clear();

var prevMidpta:Point = null;

var prevMidptb:Point = null;

var prevMidptc:Point = null;

var prevMidptd:Point = null;

var prevMidpte:Point = null;

var prevMidptf:Point = null;

var prevMidptg:Point = null;

var prevMidpth:Point = null;

var l:Number = pts.length;

for (var i:Number=1;i

Posted by: ruth flores on May 23, 2010 8:53pm

hey grant, thanks for sharing!

Posted by: Tox on Jun 28, 2011 10:29am URL: http://www.webcodesign.de

Leave a Reply

Your email is never published nor shared.




You may use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">