I need to calculate the control points of a Bézier curve passing through N points where N > 2. I have been able to use the equations in this post to get close... but when "negative vectors" (the only thing I can think to call them) are used the control points no longer are in the correct location. I have constructed a simple javascript plotter to illustrate my issue. Here is a screen shot of the exact problem created from the above example:


The control points should always create a line that passes through it's parent point. I can post some of the math I have used here, or anyone familiar with coding/javascript can look through the math in my code by viewing the above example's page-source.

I believe the problem has to do with how I am normalizing the vectors, but am very out of practice with this level of math. This equation was given in the other article but I do not know how to implement it $\vec x'=\vec x/|\vec x|$.

function normalize_v(a){
    var b = new Array();
    b[0] = a[0] / Math.sqrt( sqr(a[0]) + sqr(a[1]) );
    b[1] = a[1] / Math.sqrt( sqr(a[0]) + sqr(a[1]) );
    return b;

This is the math run on each point (other than the first):

var a = new Array(points[p-1].x, points[p-1].y);
var b = new Array(points[p].x, points[p].y);
var c = new Array(points[p+1].x, points[p+1].y);

var delta_a = subtract_v(a, b);
var delta_c = subtract_v(c, b);

// Get vector (m) perpendicular bisector
var m = normalize_v( add_v( normalize_v(delta_a), normalize_v(delta_c) ) );

// Get ma and mc
var ma = normalize_v( subtract_v(delta_a, multiply_v(multiply_v(delta_a,m),m) ) );
var mc = normalize_v( subtract_v(delta_c, multiply_v(multiply_v(delta_c,m),m) ) );

// Get the coordinates
points[p].c2x = b[0] + ( (Math.sqrt( sqr(delta_a[0]) + sqr(delta_a[1]) ) / tightness) * ma[0] );
points[p].c2y = b[1] + ( (Math.sqrt( sqr(delta_a[0]) + sqr(delta_a[1]) ) / tightness) * ma[1] );
points[p+1].c1x = b[0] + ( (Math.sqrt( sqr(delta_c[0]) + sqr(delta_c[1]) ) / tightness) * mc[0] );
points[p+1].c1y = b[1] + ( (Math.sqrt( sqr(delta_c[0]) + sqr(delta_c[1]) ) / tightness) * mc[1] );

Thank you in advance for any help provided!

  • $\begingroup$ Answered at stackoverflow first... whew, I'll post the answer after the 3 day minimum. Answer: var ma = [-m[0],-m[1]]; var mc = m; $\endgroup$ – RANGER Jul 23 '11 at 5:24
  • $\begingroup$ For future reference: The change above is part of a larger change that also flips the order of $a$ and $b$ in $\Delta_a$; it won't work on its own; the full solution is here: stackoverflow.com/questions/6797614/… $\endgroup$ – joriki Jul 25 '11 at 21:58

The parent point and its control points will be collinear if and only if the curve is smooth* at the parent point. If the curve has a sharp corner there, the control points will not lie on opposite sides of the parent point. Looking at your picture, I'd say both the "good" and the "bad" control points seem to lie more or less where they should.

*) I'm using "smooth" in the colloquial sense (has no corners) here, not in the mathematical one (infinitely differentiable).

  • $\begingroup$ Wouldn't "smooth" as you're using it be C-1 continuous (parent point is the midpoint of the line joining its adjacent control points), whereas the condition for collinearity is the weaker G-1 continuous? $\endgroup$ – Peter Taylor Sep 21 '11 at 13:07
  • $\begingroup$ @Peter Taylor: I have to confess to not having heard of $G^1$ continuity before, but after googling it, I must admit that it seems like a natural way to formulate the appropriate condition. Wikipedia does say that "[i]n general, $G^n$ continuity exists if the curves can be reparameterized to have $C^n$ (parametric) continuity", so I don't think I was too far off in using "once differentiable" in a loose sense. $\endgroup$ – Ilmari Karonen Sep 22 '11 at 15:53
  • $\begingroup$ @Peter Taylor: Hmm, I guess the expression "lie on opposite sides of the parent point" might be ambiguous as I used it. Just to clarify, I did not mean that the parent point needs to be the midpoint between the control points, but merely that it needs to lie between the control points on the line joining them. $\endgroup$ – Ilmari Karonen Sep 22 '11 at 16:01
  • $\begingroup$ Precisely, so "if and only if" is wrong. The curve could be non-differentiable at the knot with $\lim_{P\to P_0+}$ and $\lim_{P\to P_0-}$ parallel but non-equal. $\endgroup$ – Peter Taylor Sep 22 '11 at 16:13
  • $\begingroup$ @Peter Taylor: If the derivatives are parallel but non-equal, you should be able to reparametrize the curve so that they're equal. And since I didn't really fix a parametrization anyway... (Although a spline does come with a natural parametrization, whose derivative can be discontinuous even if the curve also admits a $C^1$ parametrization, so I can see where we might be talking past each other.) Anyway, I'll be happy to change "once differentiable" to something else that better captures the notion of $G^1$ continuity in a way a layperson can understand: maybe "has no corners" might do? $\endgroup$ – Ilmari Karonen Sep 22 '11 at 16:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.