diff --git a/src/path/Curve.js b/src/path/Curve.js index 7285a054..89cf48af 100644 --- a/src/path/Curve.js +++ b/src/path/Curve.js @@ -1356,10 +1356,8 @@ new function() { // Scope for methods that require numerical integration /*#*/ } // options.fatline /** - * Intersections between curve and line becomes rather simple here mostly - * because of Numerical class. We can rotate the curve and line so that the - * line is on the X axis, and solve the implicit equations for the X axis - * and the curve. + * Intersections between curve and line based on the algebraic method + * described at http://www.particleincell.com/blog/2013/cubic-line-intersection/ */ function addCurveLineIntersections(v1, v2, curve1, curve2, locations) { var flip = Curve.isLinear(v1), @@ -1367,38 +1365,46 @@ new function() { // Scope for methods that require numerical integration vl = flip ? v1 : v2, l1x = vl[0], l1y = vl[1], l2x = vl[6], l2y = vl[7], - // Rotate both curve and line around l1 so that line is on x axis - lvx = l2x - l1x, - lvy = l2y - l1y, - // Angle with x axis (1, 0) - angle = Math.atan2(-lvy, lvx), - sin = Math.sin(angle), - cos = Math.cos(angle), - // (rl1x, rl1y) = (0, 0) - rl2x = lvx * cos - lvy * sin, - vcr = []; + vc0 = vc[0], vc1 = vc[1], vc2 = vc[2], vc3 = vc[3], + vc4 = vc[4], vc5 = vc[5], + // Equation of the line Ax + By + C = 0 + A = l2y-l1y, //A=y2-y1 + B = l1x-l2x, //B=x1-x2 + C = l1x*(l1y-l2y) + l1y*(l2x-l1x), //C=x1*(y1-y2)+y1*(x2-x1) + // Bernstein coefficients for the curve + bx0 = -vc0 + 3*vc2 + -3*vc4 + vc[6], + bx1 = 3*vc0 - 6*vc2 + 3*vc4, + bx2 = -3*vc0 + 3*vc2, + bx3 = vc0, + by0 = -vc1 + 3*vc3 + -3*vc5 + vc[7], + by1 = 3*vc1 - 6*vc3 + 3*vc5, + by2 = -3*vc1 + 3*vc3, + by3 = vc1, + // Form the cubic equation + // a*t^3 + b*t^2 + c*t + d = 0 + a = A*bx0 + B*by0, /*t^3*/ + b = A*bx1 + B*by1, /*t^2*/ + c = A*bx2 + B*by2, /*t*/ + d = A*bx3 + B*by3 + C, /*1*/ + roots = [], count, x0, x1, t, tl; - for(var i = 0; i < 8; i += 2) { - var x = vc[i] - l1x, - y = vc[i + 1] - l1y; - vcr.push( - x * cos - y * sin, - y * cos + x * sin); - } - var roots = [], - count = Curve.solveCubic(vcr, 1, 0, roots); + // Solve the cubic equation + count = Numerical.solveCubic(a, b, c, d, roots); // NOTE: count could be -1 for inifnite solutions, but that should only // happen with lines, in which case we should not be here. - for (var i = 0; i < count; i++) { - var t = roots[i]; - if (t >= 0 && t <= 1) { - var point = Curve.evaluate(vcr, t, 0); + for (var i=0;i= 0 && t <= 1.0){ + x0 = bx0*t*t*t + bx1*t*t + bx2*t + bx3; + x1 = by0*t*t*t + by1*t*t + by2*t + by3; // We do have a point on the infinite line. Check if it falls on // the line *segment*. - if (point.x >= 0 && point.x <= rl2x) { + // tl is the parameter of the intersection point in line segment. + // First check if line is vertical + tl = (l2x-l1x) != 0 ? (x0-l1x)/(l2x-l1x) : (x1-l1y)/(l2y-l1y); + if(tl >= 0 && tl <= 1.0){ // Interpolate the parameter for the intersection on line. - var tl = point.x / rl2x, - t1 = flip ? tl : t, + var t1 = flip ? tl : t, t2 = flip ? t : tl; addLocation(locations, curve1, t1, Curve.evaluate(v1, t1, 0),