3

Given a line made up of several points, how do I make the line smoother/ curvier/ softer through adding intermediate points -- while keeping the original points completely intact and unmoved?

To illustrate, I want to go from the above to the below in this illustration:

enter image description here

Note how in the above picture, if we start at the bottom there will be a sharper right turn. In the bottom image however, this sharp right turn is made a bit "softer" by adding an intermediate point which is positioned in the middle of the two points, and using averages of the angles of the other lines. (Differently put, imagine the lines a race car would drive, as it couldn't abruptly change direction.) Note how, however, none of the original points was "touched", I just added more points.

Thanks!! For what it's worth, I'm implementing this using JavaScript and Canvas.

Philipp Lenssen
  • 8,818
  • 13
  • 56
  • 77
  • You could interpolate along as if it was a Bezier curve: http://en.wikipedia.org/wiki/B%C3%A9zier_curve – Xavier Ho Apr 15 '12 at 15:26
  • Just found a related thread (with no picked answer yet): http://stackoverflow.com/questions/7891740/drawing-smooth-lines-with-canvas – Philipp Lenssen Apr 16 '12 at 22:48

2 Answers2

5

with each edge (e1 & e2) adjacent to each 'middle' edge (me) do

  • let X = 0.5 x length(me)
  • find 2 cubic bezier control points by extending the adjacent edges by X (see algorithm below)
  • get midpoint of cubic bezier (by applying formula below)
  • insert new 'midpoint' between me's two coordinates.

example

FloatPoint ExtendLine(const FloatPoint A, const FloatPoint B, single distance)
{
  FloatPoint newB;
  float lenAB =  sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y));
  newB.X = B.x - (B.x - A.x) / lenAB * distance;
  newB.Y = B.Y - (B.Y - A.Y) / lenAB * distance;
  return newB;
}

Edit: Formula for Bezier Curve midpoint: p(0.5) = 0.125(p0) + 0.375(p1) + 0.375(p2) + 0.125(p3)

Angus Johnson
  • 4,565
  • 2
  • 26
  • 28
  • Thanks so much for adding the code too! Could you please explain again what the distance parameter needs to be? – Philipp Lenssen Apr 16 '12 at 22:13
  • 1
    Looks like JavaScript-Canvas does have some native functionality that looks like it helps, I'm just reading through it: http://w3schools.com/html5/canvas_quadraticcurveto.asp and http://w3schools.com/html5/canvas_beziercurveto.asp – Philipp Lenssen Apr 16 '12 at 22:44
  • Another potentially relevant thread: http://stackoverflow.com/questions/7891740/drawing-smooth-lines-with-canvas – Philipp Lenssen Apr 16 '12 at 22:48
  • `distance` is arbitrary. A good starting value is half the length of the edge you want to smooth. – Xavier Ho Apr 16 '12 at 22:50
  • Sorry, in hospital and out of action. Yes, distance is arbitrary and depends on how prominent the smoothing you wish. – Angus Johnson Apr 19 '12 at 02:25
-2

The following code found elsewhere here does the job for me, in the specific context of JavaScript-Canvas which I'm using -- but please see Angus' answer for a more general approach:

var max = points.length;
context.beginPath();
var i = 0;
context.moveTo(points[i].x, points[i].y);
for (i = 1; i < max - 2; i++) {
    var xc = (points[i].x + points[i + 1].x) * .5;
    var yc = (points[i].y + points[i + 1].y) * .5;
    context.quadraticCurveTo(points[i].x, points[i].y, xc, yc);
}
context.quadraticCurveTo(points[max - 2].x, points[max - 2].y, points[max - 1].x,points[max - 1].y);
context.closePath();
context.stroke();
Community
  • 1
  • 1
Philipp Lenssen
  • 8,818
  • 13
  • 56
  • 77
  • What you're doing there is just creating a quadratic bezier curve based on your (control) vertices, also known as CV Curve. If this works for you, feel free to accept your own answer. :] – Xavier Ho Apr 19 '12 at 23:36
  • It does work in my specific case, thanks again for your comments! OK, I will go ahead and mark this as answer then. – Philipp Lenssen Apr 20 '12 at 09:30