You’ll find this spline function useful, whenever you want to connect a number of points with a nice, smooth curve instead of a jaggy series of straight lines, as it will interpolate the missing points in between (sorry for this perfectly un-mathematical description of a spline).

Examples:

- to visualize statistical data with nice curves
- to recreate shapes which have formerly been reduced with a Line Generalization tool. To first reduce the drawing data and to later re-interpolate it can make sense as it reduces the amount of data that is being sent back and forth betweem client and server.

Another use case is to smooth the rather shaky lines that are drawn with the mouse.

(developed and originally published in 2005)

## 3 Comments

## 1 Bogdan wrote:

Hi Andreas,

I find this spline function very useful. I am wondering if it’s posible to improve this function.

In a real world situation you have to combine smooth curves with rectangular angles. Let’s take for example the drawing of a street on a map using gps points.

I thought that simply specifying the point twice you could drow a direct line between the points.

What do you think ?

## 2 Andreas Weber wrote:

@Bogdan

Actually I’ve also come across situations where it would be nice if we could exempt a point from the smoothing – to create a sharp corner at this point.

Marking a corner by repeating a point sounds like a very good idea:

Let’s say if we have points A, B, C, D, E and we want C to be an edge, we’d simply do A, B, C, C, D, E.

What I don’t see is that this would / should automatically create a _rectangular_ angle: as I see it, it would just make B-C a straight line and C-D too. Whether these 2 lines happen to form a 90° angle is kind of outside the responsibility of this class.

I hope to find the time to look into this in the coming days!

## 3 Andreas Weber wrote:

How to get ‘sharp corners’ -

Maybe someone has a more elegant solution, but for the moment the best I can think of (because it will also work if we want to tween the line drawing) is to push in additional points before sending the points Array to the Catmull Rom function.

The basic idea is the following: if we want the line that connects points A and B to be straight, we have to find a number of points on that line (break it up into a number of line segments). By doing so we limit the ‘range of curvyness’ of the Catmull Rom function and force it to calculate a ‘curve’ that connects these points – this ‘curve’ will be (or look like) a straight line.

Let’s have a look at this shape:

And here’s the code that creates it:

import com.motiondraw.geometry.CatmullRomSpline ;

var p1 = {x:100, y:100};

var p2 = {x:400, y:100};

var p3 = {x:400, y:250};

var p4 = {x:400, y:400};

var p5 = {x:250, y:400};

var p6 = {x:100, y:400};

// let’s assume we want p4 to be a sharp corner, i.e. p4-p3 is a straight line and p4-p5 too

points = new Array();

var approxLineLength = 5;

points.push(p1);

points.push(p2);

// let’s find points between p3 and p4 – if they describe a straight line, the Catmull Rom function has no room to make a curve
var p = getPointAtT(p3, p4, 1/numSteps*i);
var p = getPointAtT(p4, p5, 1/numSteps*i);

var dist1 = getDistanceBetweenPoints(p3, p4);

var numSteps = Math.ceil(dist1 / approxLineLength);

for(var i=0; i

points.push(p);

}

// let’s find points between p5 and p6

var dist2 = getDistanceBetweenPoints(p4, p5);

var numSteps = Math.ceil(dist2 / approxLineLength);

for(var i=0; i

points.push(p);

}

points.push(p6);

points.push(p1);

var spline:CatmullRomSpline = new CatmullRomSpline(points);

this.createEmptyMovieClip(‘canvas’, this.getNextHighestDepth());

canvas.lineStyle(3, 0);

spline.plotAll(canvas, approxLineLength);

// returns points on the line between p1 and p2

// t is a floating number between 0 (returns p1) and 1 (returns p2)

function getPointAtT(p1, p2, t){

return {x:((1-t)*p1.x ) + (t*p2.x ), y: ((1-t)*p1.y ) + (t*p2.y)};

}

function getDistanceBetweenPoints(p1:Object, p2:Object):Number{

return Math.sqrt(Math.abs(Math.pow(p2.x-p1.x ,2)) + Math.abs(Math.pow(p2.y – p1.y ,2)));

}