mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-07-30 07:39:50 -04:00
Start merging fat-line clipping code into Curve class.
And add a prepro option for now.
This commit is contained in:
parent
7f00ef8f05
commit
502c76dbce
4 changed files with 444 additions and 56 deletions
src/path
|
@ -709,56 +709,6 @@ statics: {
|
|||
+ t * t * t * v3,
|
||||
padding);
|
||||
}
|
||||
},
|
||||
|
||||
// We need to provide the original left curve reference to the
|
||||
// #getIntersections() calls as it is required to create the resulting
|
||||
// CurveLocation objects.
|
||||
getIntersections: function(v1, v2, curve1, curve2, locations) {
|
||||
var bounds1 = Curve.getBounds(v1),
|
||||
bounds2 = Curve.getBounds(v2);
|
||||
if (bounds1.touches(bounds2)) {
|
||||
// See if both curves are flat enough to be treated as lines, either
|
||||
// because they have no control points at all, or are "flat enough"
|
||||
// If the curve was flat in a previous iteration, we don't need to
|
||||
// recalculate since it does not need further subdivision then.
|
||||
if ((Curve.isLinear(v1)
|
||||
|| Curve.isFlatEnough(v1, /*#=*/ Numerical.TOLERANCE))
|
||||
&& (Curve.isLinear(v2)
|
||||
|| Curve.isFlatEnough(v2, /*#=*/ Numerical.TOLERANCE))) {
|
||||
// See if the parametric equations of the lines interesct.
|
||||
// var point = new Line(v1[0], v1[1], v1[6], v1[7], false)
|
||||
// .intersect(new Line(v2[0], v2[1], v2[6], v2[7], false));
|
||||
// Use static version without creation of Line objects, but it
|
||||
// doesn't seem to yield measurable speed improvements!
|
||||
var point = Line.intersect(
|
||||
v1[0], v1[1], v1[6], v1[7],
|
||||
v2[0], v2[1], v2[6], v2[7], false);
|
||||
if (point) {
|
||||
// Avoid duplicates when hitting segments (closed paths too)
|
||||
var first = locations[0],
|
||||
last = locations[locations.length - 1];
|
||||
if ((!first || !point.equals(first._point))
|
||||
&& (!last || !point.equals(last._point)))
|
||||
// Passing null for parameter leads to lazy determination
|
||||
// of parameter values in CurveLocation#getParameter()
|
||||
// only once they are requested.
|
||||
locations.push(new CurveLocation(curve1, null, point,
|
||||
curve2));
|
||||
}
|
||||
} else {
|
||||
// Subdivide both curves, and see if they intersect.
|
||||
// If one of the curves is flat already, no further subdivion
|
||||
// is required.
|
||||
var v1s = Curve.subdivide(v1),
|
||||
v2s = Curve.subdivide(v2);
|
||||
for (var i = 0; i < 2; i++)
|
||||
for (var j = 0; j < 2; j++)
|
||||
Curve.getIntersections(v1s[i], v2s[j], curve1, curve2,
|
||||
locations);
|
||||
}
|
||||
}
|
||||
return locations;
|
||||
}
|
||||
}}, Base.each(['getBounds', 'getStrokeBounds', 'getHandleBounds', 'getRoughBounds'],
|
||||
// Note: Although Curve.getBounds() exists, we are using Path.getBounds() to
|
||||
|
@ -1073,4 +1023,440 @@ new function() { // Scope for methods that require numerical integration
|
|||
a, b, 16, /*#=*/ Numerical.TOLERANCE);
|
||||
}
|
||||
};
|
||||
}, new function() { // Scope for Curve intersection
|
||||
function addLocation(locations, curve1, parameter, point, curve2) {
|
||||
// Avoid duplicates when hitting segments (closed paths too)
|
||||
var first = locations[0],
|
||||
last = locations[locations.length - 1];
|
||||
if ((!first || !point.equals(first._point))
|
||||
&& (!last || !point.equals(last._point)))
|
||||
locations.push(new CurveLocation(curve1, parameter, point, curve2));
|
||||
}
|
||||
|
||||
function getCurveIntersections(v1, v2, curve1, curve2, locations,
|
||||
range1, range2, recursion) {
|
||||
/*#*/ if (options.fatline) {
|
||||
// NOTE: range1 and range1 are only used for recusion
|
||||
recursion = (recursion || 0) + 1;
|
||||
// Avoid endless recursion.
|
||||
// Perhaps we should fall back to a more expensive method after this,
|
||||
// but so far endless recursion happens only when there is no real
|
||||
// intersection and the infinite fatline continue to intersect with the
|
||||
// other curve outside its bounds!
|
||||
if (recursion > 20)
|
||||
return;
|
||||
// Set up the parameter ranges.
|
||||
range1 = range1 || [ 0, 1 ];
|
||||
range2 = range2 || [ 0, 1 ];
|
||||
// Get the clipped parts from the original curve, to avoid cumulative
|
||||
// errors
|
||||
var part1 = Curve.getPart(v1, range1[0], range1[1]),
|
||||
part2 = Curve.getPart(v2, range2[0], range2[1]),
|
||||
iteration = 0;
|
||||
// markCurve(part1, '#f0f', true);
|
||||
// markCurve(part2, '#0ff', false);
|
||||
// Loop until both parameter range converge. We have to handle the
|
||||
// degenerate case seperately, where fat-line clipping can become
|
||||
// numerically unstable when one of the curves has converged to a point
|
||||
// and the other hasn't.
|
||||
while (iteration++ < 20
|
||||
&& (Math.abs(range1[1] - range1[0]) > /*#=*/ Numerical.TOLERANCE
|
||||
|| Math.abs(range2[1] - range2[0]) > /*#=*/ Numerical.TOLERANCE)) {
|
||||
// First we clip v2 with v1's fat-line
|
||||
var range,
|
||||
intersects1 = clipFatLine(part1, part2, range = range2.slice()),
|
||||
intersects2 = 0;
|
||||
// Stop if there are no possible intersections
|
||||
if (intersects1 === 0)
|
||||
break;
|
||||
if (intersects1 > 0) {
|
||||
// Get the clipped parts from the original v2, to avoid
|
||||
// cumulative errors
|
||||
range2 = range;
|
||||
part2 = Curve.getPart(v2, range2[0], range2[1]);
|
||||
// markCurve(part2, '#0ff', false);
|
||||
// Next we clip v1 with nuv2's fat-line
|
||||
intersects2 = clipFatLine(part2, part1, range = range1.slice());
|
||||
// Stop if there are no possible intersections
|
||||
if (intersects2 === 0)
|
||||
break;
|
||||
if (intersects1 > 0) {
|
||||
// Get the clipped parts from the original v2, to avoid
|
||||
// cumulative errors
|
||||
range1 = range;
|
||||
part1 = Curve.getPart(v1, range1[0], range1[1]);
|
||||
}
|
||||
// markCurve(part1, '#f0f', true);
|
||||
}
|
||||
// Get the clipped parts from the original v1
|
||||
// Check if there could be multiple intersections
|
||||
if (intersects1 < 0 || intersects2 < 0) {
|
||||
// Subdivide the curve which has converged the least from the
|
||||
// original range [0,1], which would be the curve with the
|
||||
// largest parameter range after clipping
|
||||
if (range1[1] - range1[0] > range2[1] - range2[0]) {
|
||||
// subdivide v1 and recurse
|
||||
var t = (range1[0] + range1[1]) / 2;
|
||||
getCurveIntersections(v1, v2, curve1, curve2, locations,
|
||||
[ range1[0], t ], range2, recursion);
|
||||
getCurveIntersections(v1, v2, curve1, curve2, locations,
|
||||
[ t, range1[1] ], range2, recursion);
|
||||
break;
|
||||
} else {
|
||||
// subdivide v2 and recurse
|
||||
var t = (range2[0] + range2[1]) / 2;
|
||||
getCurveIntersections(v1, v2, curve1, curve2, locations,
|
||||
range1, [ range2[0], t ], recursion);
|
||||
getCurveIntersections(v1, v2, curve1, curve2, locations,
|
||||
range1, [ t, range2[1] ], recursion);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// We need to bailout of clipping and try a numerically stable
|
||||
// method if any of the following are true.
|
||||
// 1. One of the parameter ranges is converged to a point.
|
||||
// 2. Both of the parameter ranges have converged reasonably well
|
||||
// (according to Numerical.TOLERANCE).
|
||||
// 3. One of the parameter range is converged enough so that it is
|
||||
// *flat enough* to calculate line curve intersection implicitly
|
||||
//
|
||||
// Check if one of the parameter range has converged completely to a
|
||||
// point. Now things could get only worse if we iterate more for the
|
||||
// other curve to converge if it hasn't yet happened so.
|
||||
var converged1 = Math.abs(range1[1] - range1[0]) < /*#=*/ Numerical.TOLERANCE,
|
||||
converged2 = Math.abs(range2[1] - range2[0]) < /*#=*/ Numerical.TOLERANCE;
|
||||
if (converged1 || converged2) {
|
||||
addLocation(locations, curve1, null, converged1
|
||||
? curve1.getPointAt(range1[0], true)
|
||||
: curve2.getPointAt(range2[0], true), curve2);
|
||||
break;
|
||||
}
|
||||
// see if either or both of the curves are flat enough to be treated
|
||||
// as lines.
|
||||
var flat1 = Curve.isFlatEnough(part1, /*#=*/ Numerical.TOLERANCE),
|
||||
flat2 = Curve.isFlatEnough(part2, /*#=*/ Numerical.TOLERANCE);
|
||||
if (flat1 || flat2) {
|
||||
(flat1 && flat2
|
||||
? getLineLineIntersection
|
||||
// Use curve line intersection method while specifying
|
||||
// which curve to be treated as line
|
||||
: getCurveLineIntersections)(part1, part2,
|
||||
curve1, curve2, locations, flat1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*#*/ } else { // !options.fatline
|
||||
var bounds1 = Curve.getBounds(v1),
|
||||
bounds2 = Curve.getBounds(v2);
|
||||
if (bounds1.touches(bounds2)) {
|
||||
// See if both curves are flat enough to be treated as lines, either
|
||||
// because they have no control points at all, or are "flat enough"
|
||||
// If the curve was flat in a previous iteration, we don't need to
|
||||
// recalculate since it does not need further subdivision then.
|
||||
if ((Curve.isLinear(v1)
|
||||
|| Curve.isFlatEnough(v1, /*#=*/ Numerical.TOLERANCE))
|
||||
&& (Curve.isLinear(v2)
|
||||
|| Curve.isFlatEnough(v2, /*#=*/ Numerical.TOLERANCE))) {
|
||||
// See if the parametric equations of the lines interesct.
|
||||
// var point = new Line(v1[0], v1[1], v1[6], v1[7], false)
|
||||
// .intersect(new Line(v2[0], v2[1], v2[6], v2[7], false));
|
||||
// Use static version without creation of Line objects, but it
|
||||
// doesn't seem to yield measurable speed improvements!
|
||||
var point = Line.intersect(
|
||||
v1[0], v1[1], v1[6], v1[7],
|
||||
v2[0], v2[1], v2[6], v2[7], false);
|
||||
if (point)
|
||||
addLocation(locations, curve1, null, point, curve2);
|
||||
} else {
|
||||
// Subdivide both curves, and see if they intersect.
|
||||
// If one of the curves is flat already, no further subdivion
|
||||
// is required.
|
||||
var v1s = Curve.subdivide(v1),
|
||||
v2s = Curve.subdivide(v2);
|
||||
for (var i = 0; i < 2; i++)
|
||||
for (var j = 0; j < 2; j++)
|
||||
Curve.getIntersections(v1s[i], v2s[j], curve1, curve2,
|
||||
locations);
|
||||
}
|
||||
}
|
||||
return locations;
|
||||
/*#*/ } // !options.fatline
|
||||
}
|
||||
|
||||
/*#*/ if (options.fatline) {
|
||||
/**
|
||||
* Clip curve V2 with fat-line of v1
|
||||
* @param {Array} v1 section of the first curve, for which we will make a
|
||||
* fat-line
|
||||
* @param {Array} v2 section of the second curve; we will clip this curve
|
||||
* with the fat-line of v1
|
||||
* @param {Array} range2 the parameter range of v2
|
||||
* @return {Number} 0: no Intersection, 1: one intersection, -1: more than
|
||||
* one ntersection
|
||||
*/
|
||||
function clipFatLine(v1, v2, range2) {
|
||||
// P = first curve, Q = second curve
|
||||
var p0x = v1[0], p0y = v1[1], p1x = v1[2], p1y = v1[3],
|
||||
p2x = v1[4], p2y = v1[5], p3x = v1[6], p3y = v1[7],
|
||||
q0x = v2[0], q0y = v2[1], q1x = v2[2], q1y = v2[3],
|
||||
q2x = v2[4], q2y = v2[5], q3x = v2[6], q3y = v2[7],
|
||||
// Calculate the fat-line L for P is the baseline l and two
|
||||
// offsets which completely encloses the curve P.
|
||||
d1 = getSignedDistance(p0x, p0y, p3x, p3y, p1x, p1y) || 0,
|
||||
d2 = getSignedDistance(p0x, p0y, p3x, p3y, p2x, p2y) || 0,
|
||||
factor = d1 * d2 > 0 ? 3 / 4 : 4 / 9,
|
||||
dmin = factor * Math.min(0, d1, d2),
|
||||
dmax = factor * Math.max(0, d1, d2),
|
||||
// Calculate non-parametric bezier curve D(ti, di(t)) - di(t) is the
|
||||
// distance of Q from the baseline l of the fat-line, ti is equally
|
||||
// spaced in [0, 1]
|
||||
dq0 = getSignedDistance(p0x, p0y, p3x, p3y, q0x, q0y),
|
||||
dq1 = getSignedDistance(p0x, p0y, p3x, p3y, q1x, q1y),
|
||||
dq2 = getSignedDistance(p0x, p0y, p3x, p3y, q2x, q2y),
|
||||
dq3 = getSignedDistance(p0x, p0y, p3x, p3y, q3x, q3y),
|
||||
// Find the minimum and maximum distances from l, this is useful for
|
||||
// checking whether the curves intersect with each other or not.
|
||||
mindist = Math.min(dq0, dq1, dq2, dq3),
|
||||
maxdist = Math.max(dq0, dq1, dq2, dq3);
|
||||
// If the fatlines don't overlap, we have no intersections!
|
||||
if (dmin > maxdist || dmax < mindist)
|
||||
return 0;
|
||||
var Dt = getConvexHull(dq0, dq1, dq2, dq3),
|
||||
tmp;
|
||||
if (dq3 < dq0) {
|
||||
tmp = dmin;
|
||||
dmin = dmax;
|
||||
dmax = tmp;
|
||||
}
|
||||
// Calculate the convex hull for non-parametric bezier curve D(ti, di(t))
|
||||
// Now we clip the convex hulls for D(ti, di(t)) with dmin and dmax
|
||||
// for the coorresponding t values (tmin, tmax): Portions of curve v2
|
||||
// before tmin and after tmax can safely be clipped away.
|
||||
var tmaxdmin = -Infinity,
|
||||
tmin = Infinity,
|
||||
tmax = -Infinity;
|
||||
for (var i = 0, l = Dt.length; i < l; i++) {
|
||||
var Dtl = Dt[i],
|
||||
dtlx1 = Dtl[0],
|
||||
dtly1 = Dtl[1],
|
||||
dtlx2 = Dtl[2],
|
||||
dtly2 = Dtl[3];
|
||||
if (dtly2 < dtly1) {
|
||||
tmp = dtly2;
|
||||
dtly2 = dtly1;
|
||||
dtly1 = tmp;
|
||||
tmp = dtlx2;
|
||||
dtlx2 = dtlx1;
|
||||
dtlx1 = tmp;
|
||||
}
|
||||
// We know that (dtlx2 - dtlx1) is never 0
|
||||
var inv = (dtly2 - dtly1) / (dtlx2 - dtlx1);
|
||||
if (dmin >= dtly1 && dmin <= dtly2) {
|
||||
var ixdx = dtlx1 + (dmin - dtly1) / inv;
|
||||
if (ixdx < tmin)
|
||||
tmin = ixdx;
|
||||
if (ixdx > tmaxdmin)
|
||||
tmaxdmin = ixdx;
|
||||
}
|
||||
if (dmax >= dtly1 && dmax <= dtly2) {
|
||||
var ixdx = dtlx1 + (dmax - dtly1) / inv;
|
||||
if (ixdx > tmax)
|
||||
tmax = ixdx;
|
||||
if (ixdx < tmin)
|
||||
tmin = 0;
|
||||
}
|
||||
}
|
||||
// Return the parameter values for v2 for which we can be sure that the
|
||||
// intersection with v1 lies within.
|
||||
if (tmin !== Infinity && tmax !== -Infinity) {
|
||||
var mindmin = Math.min(dmin, dmax),
|
||||
mindmax = Math.max(dmin, dmax);
|
||||
if (dq3 > mindmin && dq3 < mindmax)
|
||||
tmax = 1;
|
||||
if (dq0 > mindmin && dq0 < mindmax)
|
||||
tmin = 0;
|
||||
if (tmaxdmin > tmax)
|
||||
tmax = 1;
|
||||
// tmin and tmax are within the range (0, 1). We need to project it
|
||||
// to the original parameter range for v2.
|
||||
var v2tmin = range2[0],
|
||||
tdiff = range2[1] - v2tmin;
|
||||
range2[0] = v2tmin + tmin * tdiff;
|
||||
range2[1] = v2tmin + tmax * tdiff;
|
||||
// If the new parameter range fails to converge by atleast 20% of
|
||||
// the original range, possibly we have multiple intersections.
|
||||
// We need to subdivide one of the curves.
|
||||
if ((tdiff - (range2[1] - range2[0])) / tdiff >= 0.2)
|
||||
return 1;
|
||||
}
|
||||
// TODO: Try checking with a perpendicular fatline to see if the curves
|
||||
// overlap if it is any faster than this
|
||||
if (Curve.getBounds(v1).touches(Curve.getBounds(v2)))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the convex hull for the non-paramertic bezier curve D(ti, di(t))
|
||||
* The ti is equally spaced across [0..1] — [0, 1/3, 2/3, 1] for
|
||||
* di(t), [dq0, dq1, dq2, dq3] respectively. In other words our CVs for the
|
||||
* curve are already sorted in the X axis in the increasing order.
|
||||
* Calculating convex-hull is much easier than a set of arbitrary points.
|
||||
*/
|
||||
function getConvexHull(dq0, dq1, dq2, dq3) {
|
||||
var distq1 = getSignedDistance(0, dq0, 1, dq3, 1 / 3, dq1),
|
||||
distq2 = getSignedDistance(0, dq0, 1, dq3, 2 / 3, dq2);
|
||||
// Check if [1/3, dq1] and [2/3, dq2] are on the same side of line
|
||||
// [0,dq0, 1,dq3]
|
||||
if (distq1 * distq2 < 0) {
|
||||
// dq1 and dq2 lie on different sides on [0, q0, 1, q3]. The hull is
|
||||
// a quadrilateral and line [0, q0, 1, q3] is NOT part of the hull
|
||||
// so we are pretty much done here.
|
||||
return [
|
||||
[ 0, dq0, 1 / 3, dq1 ],
|
||||
[ 1 / 3, dq1, 1, dq3 ],
|
||||
[ 2 / 3, dq2, 0, dq0 ],
|
||||
[ 1, dq3, 2 / 3, dq2 ]
|
||||
];
|
||||
}
|
||||
// dq1 and dq2 lie on the same sides on [0, q0, 1, q3]. The hull can be
|
||||
// a triangle or a quadrilateral and line [0, q0, 1, q3] is part of the
|
||||
// hull. Check if the hull is a triangle or a quadrilateral.
|
||||
var dqMaxX, dqMaxY, vqa1a2X, vqa1a2Y, vqa1MaxX, vqa1MaxY, vqa1MinX, vqa1MinY;
|
||||
if (Math.abs(distq1) > Math.abs(distq2)) {
|
||||
dqMaxX = 1 / 3;
|
||||
dqMaxY = dq1;
|
||||
// apex is dq3 and the other apex point is dq0 vector
|
||||
// dqapex->dqapex2 or base vector which is already part of the hull.
|
||||
vqa1a2X = 1;
|
||||
vqa1a2Y = dq3 - dq0;
|
||||
// vector dqapex->dqMax
|
||||
vqa1MaxX = 2 / 3;
|
||||
vqa1MaxY = dq3 - dq1;
|
||||
// vector dqapex->dqmin
|
||||
vqa1MinX = 1 / 3;
|
||||
vqa1MinY = dq3 - dq2;
|
||||
} else {
|
||||
dqMaxX = 2 / 3;
|
||||
dqMaxY = dq2;
|
||||
// apex is dq0 in this case, and the other apex point is dq3 vector
|
||||
// dqapex->dqapex2 or base vector which is already part of the hull.
|
||||
vqa1a2X = -1;
|
||||
vqa1a2Y = dq0 - dq3;
|
||||
// vector dqapex->dqMax
|
||||
vqa1MaxX = -2 / 3;
|
||||
vqa1MaxY = dq0 - dq2;
|
||||
// vector dqapex->dqmin
|
||||
vqa1MinX = -1 / 3;
|
||||
vqa1MinY = dq0 - dq1;
|
||||
}
|
||||
// Compare cross products of these vectors to determine, if
|
||||
// point is in triangles [ dq3, dqMax, dq0 ] or [ dq0, dqMax, dq3 ]
|
||||
var a1a2_a1Min = vqa1a2X * vqa1MinY - vqa1a2Y * vqa1MinX,
|
||||
a1Max_a1Min = vqa1MaxX * vqa1MinY - vqa1MaxY * vqa1MinX;
|
||||
return a1a2_a1Min * a1Max_a1Min < 0
|
||||
// Point [2/3, dq2] is inside the triangle, hull is a triangle.
|
||||
? [
|
||||
[ 0, dq0, dqMaxX, dqMaxY ],
|
||||
[ dqMaxX, dqMaxY, 1, dq3 ],
|
||||
[ 1, dq3, 0, dq0 ]
|
||||
]
|
||||
// Convexhull is a quadrilateral and we need all lines in the
|
||||
// correct order where line [0, q0, 1, q3] is part of the hull.
|
||||
: [
|
||||
[ 0, dq0, 1 / 3, dq1 ],
|
||||
[ 1 / 3, dq1, 2 / 3, dq2 ],
|
||||
[ 2 / 3, dq2, 1, dq3 ],
|
||||
[ 1, dq3, 0, dq0 ]
|
||||
];
|
||||
}
|
||||
|
||||
// This is basically an "unrolled" version of #Line.getDistance() with sign
|
||||
// May be a static method could be better!
|
||||
function getSignedDistance(a1x, a1y, a2x, a2y, bx, by) {
|
||||
var m = (a2y - a1y) / (a2x - a1x),
|
||||
b = a1y - (m * a1x);
|
||||
return (by - (m * bx) - b) / Math.sqrt(m * m + 1);
|
||||
}
|
||||
/*#*/ } // 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.
|
||||
*/
|
||||
function getCurveLineIntersections(v1, v2, curve1, curve2, locations, flip) {
|
||||
if (flip === undefined)
|
||||
flip = Curve.isLinear(v1);
|
||||
var vc = flip ? v2 : v1,
|
||||
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,
|
||||
rl2y = lvy * cos + lvx * sin,
|
||||
vcr = [];
|
||||
|
||||
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);
|
||||
// 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, true, 0);
|
||||
// We do have a point on the infinite line. Check if it falls on
|
||||
// the line *segment*.
|
||||
if (point.x >= 0 && point.x <= rl2x)
|
||||
addLocation(locations,
|
||||
flip ? curve2 : curve1,
|
||||
// The actual intersection point
|
||||
t, Curve.evaluate(vc, t, true, 0),
|
||||
flip ? curve1 : curve2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getLineLineIntersection(v1, v2, curve1, curve2, locations) {
|
||||
var point = Line.intersect(
|
||||
v1[0], v1[1], v1[6], v1[7],
|
||||
v2[0], v2[1], v2[6], v2[7], false);
|
||||
// Passing null for parameter leads to lazy determination of parameter
|
||||
// values in CurveLocation#getParameter() only once they are requested.
|
||||
if (point)
|
||||
addLocation(locations, curve1, null, point, curve2);
|
||||
}
|
||||
|
||||
return { statics: {
|
||||
// We need to provide the original left curve reference to the
|
||||
// #getIntersections() calls as it is required to create the resulting
|
||||
// CurveLocation objects.
|
||||
getIntersections: function(v1, v2, curve1, curve2, locations) {
|
||||
var linear1 = Curve.isLinear(v1),
|
||||
linear2 = Curve.isLinear(v2);
|
||||
// Determine the correct intersection method based on values of
|
||||
// linear1 & 2:
|
||||
(linear1 && linear2
|
||||
? getLineLineIntersection
|
||||
: linear1 || linear2
|
||||
? getCurveLineIntersections
|
||||
: getCurveIntersections)(v1, v2, curve1, curve2, locations);
|
||||
return locations;
|
||||
}
|
||||
}};
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue