1

I've been working on a project where I use Bezier paths to draw the curves I need. Each basic shape in my project consists of three cubic Bezier curves arranged end to end so that the slopes match where they meet.

The basic problem I need to solve is whether the compound curve made of the three Bezier curves intersects with itself. After thinking about it for a while, I've figured out that given the constraints of the curves, I can simplify the task to something else:

The curvature of each of the three Bezier paths should be opposite in curvature direction relative to the curve it's abutted to. In other words, there should be an inflection point where one bezier curve abuts to another one. If that is not the case, I want to reject the parameter set that generated the curves and select a different set.

In any case, my basic question is how to detect whether there is an inflection point where the curves abut each other.

In the illustration, each of the three Bezier curves is shown using a different color. The left black curve curves in the opposite direction from the red curve at the point where they meet, but the right black curve curves in the same direction. There is an inflection point where the red and left black curve meet but not where the red and right black curve meet.

Looping Bezier Path

Edit: Below, I've added another image, showing the polygon enclosing the Bezier path. The crossing lines of the polygon, shown in the black curve, tests for an inflection point, not a loop. I'm guessing that one curve intersecting another can be tested by checking whether the enclosing polygons intersect, as illustrated by the red and blue curves. Bezier Path with control points polygon

P.S. Since there has been some question about the constraints, I will list some of them here:

  • The left most point and the rightmost point have the same y value.
  • The x value of the control point of the leftmost point is less than
    the x value of the control point of the rightmost point. This keeps
    the black and blue curves from intersecting each other.
  • The slope at the leftmost and rightmost points is within about +/- 10 degrees of horizontal.
  • The intersection of the black and red curves, and the intersection of the red and blue curves divide the full curve in approximately thirds. I don't have exact numbers, but a sample bound would be that the x value of the left end of the red curve is somewhere between 25% and 40% of the x value of the rightmost point.
  • The y value of the points of intersection are +/- some small fraction of the overall width.
  • The slope at the intersections is > 0.6 and < 3.0 (positive or negative).
Victor Engel
  • 2,037
  • 2
  • 25
  • 46
  • I'm not sure if your assumption re simpler solution is right because (a) it's possible that they do not intersect despite the absence of inflection point; and (b) it's possible that they do intersect despite the presence of inflection point. Unless you have some other significant constraints on your three bezier segments that you haven't shared with us, I'm pretty sure your "find inflection point" notion doesn't work. In answer to your question, you could look at second derivatives to identify inflection points (and Google could help you there), but I don't think that helps you. – Rob Apr 22 '13 at 07:52
  • Perhaps this might be one approach: http://stackoverflow.com/questions/13394422/bezier-path-see-if-it-crosses – Rob Apr 22 '13 at 08:05
  • 1
    see http://pomax.github.io/bezierinfo/#curveintersection as well as http://pomax.github.io/bezierinfo/#shapes since you're technically using poly-beziers. – Mike 'Pomax' Kamermans Apr 22 '13 at 12:43
  • Rob, indeed, there are some constraints that guarantee what I have stated. One of those constraints is that the slope at each intersection has opposite sign, so the red curve has no inflection point. I didn't think it would be helpful to list those constraints, so I left them off. So, let's dismiss your points a and b. I recognize second derivative at the endpoint is what I need. Is there a built in ios method or function that computes that or do I need to compute it myself! – Victor Engel Apr 22 '13 at 13:36
  • Thanks for the links, @Mike. I already had those bookmarked, but I thought I'd check if there were already a solution before I reinvent the wheel. – Victor Engel Apr 22 '13 at 13:39
  • @VictorEngel Ignoring the premise of the question (still insufficient criteria), but rather focusing on whether there is an inflection point where the two segments meet: The short answer is that I believe you'll have to calculate the second and third derivatives yourself. – Rob Apr 22 '13 at 14:38
  • 1
    A friend of mine suggests that checking if a cubic Bézier loops is equivalent to asking if a line connecting its 4 control points, in order, cross. So that just leaves the intersection of abutting curves. He gave a solution to that, too, which I may share here after I get to a computer. It uses cross products of point differences of the control points. – Victor Engel Apr 22 '13 at 15:19
  • Playing around with my app, it seems that it may be sufficient to test whether the control point polygons overlap. This can be efficiently done by simply checking whether any of the lines intersect. This test seems to work both for one of the curves intersecting itself and for one intersecting another. – Victor Engel Apr 22 '13 at 17:50
  • 1
    @VictorEngel there are infinitely many crossings of control lines that do not actually result in loops, though, but merely result in cusps. As you do not want to perform any intersection-resolution, since there is no intersection, checking for crossings is necessary but not sufficient. – Mike 'Pomax' Kamermans Apr 22 '13 at 18:27
  • Never mind. I see you're right. this idea probably won't work. – Victor Engel Apr 22 '13 at 18:35
  • Actually, I tried eliminating all the cases where the control polygons intersect, and while that solution doesn't produce all the possibilities, the ones that it does produce suit my app well, so I'll stick with it since it's simple and efficient. – Victor Engel Apr 23 '13 at 01:04

4 Answers4

4

The equation for curvature is moderately simple. You only need the sign of the curvature, so you can skip a little math. You are basically interested in the sign of the cross product of the first and second derivatives.

This simplification only works because the curves join smoothly. Without equal tangents a more complex test would be needed.

The sign of curvature of curve P:

ax = P[1].x - P[0].x;               //  a = P1 - P0
ay = P[1].y - P[0].y;
bx = P[2].x - P[1].x - ax;          //  b = P2 - P1 - a
by = P[2].y - P[1].y - ay;
cx = P[3].x - P[2].x - bx*2 - ax;   //  c = P3 - P2 - 2b - a
cy = P[3].y - P[2].y - by*2 - ay;

bc = bx*cy - cx*by;
ac = ax*cy - cx*ay;
ab = ax*by - bx*ay;

r = ab + ac*t + bc*t*t;

Note that r is the cross product of the first and second derivative and the sign indicate the direction of curvature. Calculate r at t=1 on the left curve and at t=0 on the right curve. If the product is negative, then there is an inflection point.

If you have curves U, V and W where U is the left black, V is the middle red, and W is the right black, then calculate bc, ac, and ab above for each. The following test will be true if both joins are inflection points:

(Uab+Uac+Ubc)*(Vab) < 0 && (Vab+Vac+Vbc)*(Wab) < 0

The equation for curvature has a denominator that I have ignored. It does not affect the sign of curvature and would only be zero if the curve was a line.

Math summary:

// start with the classic bezier curve equation
P = (1-t)^3*P0 + 3*(1-t)^2*t*P1 + 3*(1-t)*t^2*P2 + t^3*P3
// convert to polynomial
P = P0 + 3*t*(P1 - P0) + 3*t^2*(P2 - 2*P1 + P0) + t^3*(P3 - 3*P2 + 3*P1 - P0)
// rename the terms to a,b,c
P = P0 + 3at + 3btt + cttt
// find the first and second derivatives
P' = 3a + 6bt + 3ctt
P" =      6b  + 6ct
// and the cross product after some reduction 
P' x P" = ab + act + bctt
Biły
  • 21
  • 3
drawnonward
  • 53,459
  • 16
  • 107
  • 112
  • 1
    Thanks, but as explained in comments to my question, my idea on simplification or restating the problem is not valid. It's a useful answer, but I hesitate to mark it as the accepted answer because of my wrong assumption. – Victor Engel Aug 10 '13 at 23:33
1

One of the deterministic ways to check if a bezier curve has a double-point or self-intersection is to calculate the inverse equation and evaluate the root, since the inversion equation of a bezier curve is always zero at the point of self-intersection. As detailed in this example by T.W.Sederberg –course notes. Then for detecting whether two bezier curves (red and black in the question) intersect with each other, there are a few methods, binary subdivision (easier to implement) and bezier clipping (very good balance of efficiency and code complexity), implicitization (not worth it).

But a more efficient way to do it probably is to subdivide the curves into small line-segments and find the intersection. Here is one way to do it. Especially when you are interested in knowing whether the path self-intersect, but not in an accurate point of intersection.

If you have well defined assumptions about the locations of the CVs of the piece-wise bezier curves (or poly-bezier as @Pomax mentioned above), you can try out the curvature based method as you have mentioned in your question.

Here is a plot of the curvature on a similar path as in the question. Under similar circumstances, it seems this could give you the solution you are looking for. Also, in case of a cusp, it seems this quick and dirty method still works!

double-point cusp

hkrish
  • 1,259
  • 1
  • 10
  • 11
  • Thanks for taking the time to post. I can see that my original question may have broader interest than my original purpose, which was to make "random" jigsaw puzzle shapes that made some sort of sense. This will be done on the fly, so the solution I needed had to be efficient. I resorted to using trial and error to determine a set of constraints. This doesn't answer my original question, but it does solve the problem I had with the project. Essentially, there are 14 degrees of freedom, and I impose constraints on them, some depending on others. – Victor Engel Jun 17 '13 at 18:07
  • No worries. I was implementing curvature calculation for bezier path and for some other issues, I was looking through related questions here.. Anyway, good luck with the project! – hkrish Jun 17 '13 at 19:45
1

@ Victor Engel : Thank you for the clarification. Now the solution is even easier.

In short, look at torques of both curves. If they pull together, the "inflexion" occurs, if they are opposed, the "curvature" continues.

Remark: Words "inflexion" and "curvature" have here a more intuitive nature, than a strict mathematical meaning, therefore apostrophes are used.

As before, a set of points P0,P1,P2,P3 defines the first cubic Bezier curve, and Q0,Q1,Q2 and Q3 the second. Moreover, 4 vectors: a,b,u,w will be useful.

a = P2P3
b = P1P2
u = Q0Q1
v = Q1Q2

I will omit a C1-continuity checking, it's already done by you. ( This means P3=Q0 and a x u=0)

Finally, Tp and Tq torques will appear.

Tp = b x a 

( "x" means a vector product, but Tp on the planar is treated like a simple number, not a vector. }

if Tp=0            {very rarely vectors a, b can be parallel.}
    b = P0P1
    Tp = b x a 
    if Tp=0 
        No! It's can't be! Who straightened the curve???
        STOP
    endif
endif

Tq = u x v 
if Tq=0            {also  vectors u, v can be parallel.}
    v = Q2Q3
    Tq = u x v 
    if Tq=0 
        Oh no! What happened to my curve???
        STOP
    endif
endif

Now the final test:

if Tp*Tq < 0  then    Houston! We have AN "INFLEXION"!
              else    WE CONTINUE THE TURN!
Biły
  • 21
  • 3
  • Thanks. It may be some time before I get around to going over this solution. I'll need to take some time to refresh myself on the linear algebra involved (not difficult, I'm just currently very busy). It's an old question, and the solution I wound up using used hard-coded limits determined empirically. So I don't really need the answer. However, it's worth having, so I will get to it at some point. – Victor Engel Aug 15 '16 at 22:42
  • Studying is valuable , but it is not necessary here . Just be a driver to know, you can't instantly change turn left to the right , because it takes time to steer. During this , at one point , the car ends veer left and begins to veer to the right. At this very moment, the vehicle's path has a point of inflection. In your case , there is no reduction of curvature but a sudden jump , therefore from a mathematical point of view , there's no point of inflection. Hence arose a misunderstanding , which fortunately managed to overcome. Good luck. – Biły Aug 16 '16 at 17:08
0

Suppose you have 4 points: P0, P1, P2 and P3, which describes a cubic Bezier's curve (cBc for short) . P0 and P3 are starting and ending points, P1 and P2 are directional points.

When P0, P1 and P2 are collinear, then cBc has an inflection point at P0.

When P1, P2 and P3 are collinear, then cBC has an inflection point at P3.

Remarks.

1) Use the vector product ( P0P1 x P1P2 and P1P2 x P2P3 respectively) to check the collinearity. The result should be a zero-lenght vector.

2) Avoid the situation where P0, P1, P2 and P3 are all collinear, the cBc they create aren't curves in the common sense.

Corollary.

When P1=P2, cBc has inflection points at both sides.

Biły
  • 21
  • 3
  • I think you are missing the point. You seem to be concentrating on special cases where a single Bezier curve has the properties where P0, P1, and P3 are collinear and/or P1, P2, and P3 are collinear. That is never the case in my scenario. Furthermore, my question is about the transition from one Bezier curve to its neighbor, not a property of a single Bezier curve. – Victor Engel Aug 11 '16 at 14:17