AS3 – Rounding corners

Interactive demoA few days ago, I was with a few students from Gobelins talking about their school projects. One group was working on some trip-assistant project where they would display itineraries on a city map.

Map itineraries most of the time are painted as straight lines with square corners and so one student suggested that it would look nicer with rounded corners: easy stuff, I said, just get each segment’s direction vector, multiply by the corner radius you want and lineTo/curveTo the path.

For some reason this didn’t seem to be absolutely obvious, so I launched FlashDevelop and quickly hacked the needed code to automatically round the corners.

Geometry basics

Rounding corners diagram Let’s take a typical and unpleasant square corner. You get your ABC from a database and draw moveTo(A), lineTo(B), lineTo(C).

Now you admit it would please the eye to draw moveTo(A), lineTo(A’), curveTo(B, C’), lineTo(C). But how do you compute A’ and B’ automatically, with a nice R radius?

Well BA’ is simply BA (ie. A minus B) normalized to length R (ie. a vector on line BA of length R). Add BA’ to B and you get A’. Repeat with BC to get C’.

Back to ActionScript 3

Now let’s look at ActionScript 3’s Point class. Really, this class is great, it makes such computations so easy that you don’t even need to now your math.

// provided coordinates and radius
var a:Point;
var b:Point;
var c:Point;
var r:Number;

// compute A'
var ba:Point = a.subtract(b);
ba = ba.normalize(r);
var ap:Point = b.add(ba);

// compute C'
var bc:Point = c.subtract(b);
bc = bc.normalize(r);
var cp:Point = b.add(bc);

// draw
graphics.moveTo(a.x, a.y);
graphics.lineTo(ap.x, ap.y);
graphics.curveTo(b.x, b.y, cp.x, cp.y);
graphics.lineTo(c.x, c.y);

Complete implementation

The final code is certainly trickier than just computing one corner – I’ve decided to give it a little more work to make it robust and efficient:

  • radius should be adaptive because some points could be “too close”,
  • computation should be efficient and minimize array access,
  • provide a nice “closed path” option,
  • use Vector.<T> (let’s get used to it).

And here’s the method :)

static public function drawRoundPath(g:Graphics, points:Vector.<Point>,
		radius:Number = 20, closePath:Boolean = false):void
{
	// code by Philippe / http://philippe.elsass.me
	var count:int = points.length;
	if (count < 2) return;
	if (closePath && count < 3) return;

	var p0:Point = points[0];
	var p1:Point = points[1];
	var p2:Point;
	var pp0:Point;
	var pp2:Point;

	var last:Point;
	if (!closePath)
	{
		g.moveTo(p0.x, p0.y);
		last = points[count - 1];
	}

	var n:int = (closePath) ? count + 1 : count - 1;

	for (var i:int = 1; i < n; i++)
	{
		p2 = points[(i + 1) % count];

		var v0:Point = p0.subtract(p1);
		var v2:Point = p2.subtract(p1);
		var r:Number = Math.max(1, Math.min(radius,
			Math.min(v0.length / 2, v2.length / 2)));
		v0.normalize(r);
		v2.normalize(r);
		pp0 = p1.add(v0);
		pp2 = p1.add(v2);

		if (i == 1 && closePath)
		{
			g.moveTo(pp0.x, pp0.y);
			last = pp0;
		}
		else g.lineTo(pp0.x, pp0.y);

		g.curveTo(p1.x, p1.y, pp2.x, pp2.y);
		p0 = p1;
		p1 = p2;
	}

	g.lineTo(last.x, last.y);
}

Possible further development:

  • create another helper method to produce a GraphicsPath collection for reusable drawing.

Interactive demo with source

Feel free to try out the little interactive demo – you can add/drag/remove/insert points and enjoy your rounded work of art:

  1. Gnou says:

    haha quelle réactivité ! Merci msieur.

  2. vitaLee says:

    Really great post.
    You and FlashDevelop code completion rock !!!

  3. Pedro says:

    Hey Dude !

    Thanks for the Great class.

    Cheers

  4. Pedro says:

    Hey Dude !

    Thanks for the Great class.

    Cheers

  5. Ciprian says:

    Very useful demo.. wish adobe would integrate something like this in their framework

    Cheers

  6. A.S. says:

    Sharing is Sexy :) Thanks …

  1. [...] time I gently coded a script for “rounding” the corners of a path. I think the script is really fine, handles nicely closed paths, but, it’s [...]

Leave a Reply