mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-04 03:45:58 -05:00
Handle cases when point y is equal to y of horizontal curve in path
This commit is contained in:
parent
9c1c00c11e
commit
0e3ac9d7f4
1 changed files with 109 additions and 63 deletions
|
@ -319,80 +319,126 @@ PathItem.inject(new function() {
|
||||||
yBottom = (yBottom + py) / 2;
|
yBottom = (yBottom + py) / 2;
|
||||||
if (yTop > -Infinity)
|
if (yTop > -Infinity)
|
||||||
windLeft = getWinding(new Point(px, yTop), curves, false,
|
windLeft = getWinding(new Point(px, yTop), curves, false,
|
||||||
testContains);
|
testContains);
|
||||||
if (yBottom < Infinity)
|
if (yBottom < Infinity)
|
||||||
windRight = getWinding(new Point(px, yBottom), curves, false,
|
windRight = getWinding(new Point(px, yBottom), curves, false,
|
||||||
testContains);
|
testContains);
|
||||||
} else {
|
} else {
|
||||||
var xBefore = px - epsilon,
|
var xBefore = px - epsilon,
|
||||||
xAfter = px + epsilon;
|
xAfter = px + epsilon;
|
||||||
// Find the winding number for right side of the curve, inclusive of
|
var loopStartIndex,
|
||||||
// the curve itself, while tracing along its +-x direction.
|
loopEndIndex = 0;
|
||||||
var startCounted = false,
|
while (loopEndIndex < curves.length) {
|
||||||
prevCurve,
|
// Determine beginning and end of loop and the first and last curve with
|
||||||
prevT;
|
// non-zero winding within the loop
|
||||||
for (var i = 0, l = curves.length; i < l; i++) {
|
loopStartIndex = loopEndIndex; // index of first curve in loop
|
||||||
var curve = curves[i],
|
loopEndIndex = loopStartIndex + 1; // index after last curve in loop
|
||||||
values = curve.values,
|
var curve,
|
||||||
winding = curve.winding;
|
firstWindCrv = null, // first curve in loop with winding != 0
|
||||||
// Since the curves are monotone in y direction, we can just
|
lastWindCrv; // last curve in loop with winding != 0
|
||||||
// compare the endpoints of the curve to determine if the
|
for (var i = loopStartIndex, l = curves.length; i < l; i++) {
|
||||||
// ray from query point along +-x direction will intersect
|
curve = curves[i];
|
||||||
// the monotone curve. Results in quite significant speedup.
|
if (curve.winding) {
|
||||||
if (winding && (winding === 1
|
if (!firstWindCrv)
|
||||||
|
firstWindCrv = curve;
|
||||||
|
lastWindCrv = curve;
|
||||||
|
}
|
||||||
|
if (curve.next !== curves[i + 1]) {
|
||||||
|
loopEndIndex = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// walk through single loop of curves
|
||||||
|
var startCounted = false,
|
||||||
|
prevWindCurve, // non-horizontal curve before current curve
|
||||||
|
nextWindCurve, // non-horizontal curve after current curve
|
||||||
|
prevT = null;
|
||||||
|
curve = null;
|
||||||
|
for (var curveIndex = loopStartIndex; curveIndex < loopEndIndex; curveIndex++) {
|
||||||
|
if (!curve) {
|
||||||
|
prevWindCurve = lastWindCrv;
|
||||||
|
nextWindCurve = firstWindCrv;
|
||||||
|
} else if (curve.winding) {
|
||||||
|
prevWindCurve = curve;
|
||||||
|
}
|
||||||
|
curve = curves[curveIndex];
|
||||||
|
if (curve === nextWindCurve) {
|
||||||
|
nextWindCurve = curve.next;
|
||||||
|
while (nextWindCurve && !nextWindCurve.winding) {
|
||||||
|
nextWindCurve = nextWindCurve.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var values = curve.values,
|
||||||
|
winding = curve.winding;
|
||||||
|
// Since the curves are monotone in y direction, we can just
|
||||||
|
// compare the endpoints of the curve to determine if the
|
||||||
|
// ray from query point along +-x direction will intersect
|
||||||
|
// the monotone curve. Results in quite significant speedup.
|
||||||
|
if (winding && (winding == 1
|
||||||
&& py >= values[1] && py <= values[7]
|
&& py >= values[1] && py <= values[7]
|
||||||
|| py >= values[7] && py <= values[1])
|
|| py >= values[7] && py <= values[1])
|
||||||
&& Curve.solveCubic(values, 1, py, roots, 0, 1) === 1) {
|
&& Curve.solveCubic(values, 1, py, roots, 0, 1) == 1) {
|
||||||
var t = roots[0];
|
var t = roots[0];
|
||||||
// Due to numerical precision issues, two consecutive curves
|
// Due to numerical precision issues, two consecutive curves
|
||||||
// may register an intercept twice, at t = 1 and 0, if y is
|
// may register an intercept twice, at t = 1 and 0, if y is
|
||||||
// almost equal to one of the endpoints of the curves.
|
// almost equal to one of the endpoints of the curves.
|
||||||
// But since curves may contain more than one loop of curves
|
// But since curves may contain more than one loop of curves
|
||||||
// and the end point on the last curve of a loop would not
|
// and the end point on the last curve of a loop would not
|
||||||
// be registered as a double, we need to filter these cases:
|
// be registered as a double, we need to filter these cases:
|
||||||
if (!( // = the following conditions will be excluded:
|
if (!( // = the following conditions will be excluded:
|
||||||
// Detect and exclude intercepts at 'end' of loops
|
// Detect and exclude intercepts at 'end' of loops
|
||||||
// if the start of the loop was already counted.
|
// if the start of the loop was already counted.
|
||||||
// This also works for the last curve: [i + 1] == null
|
t > tMax && startCounted && curve === lastWindCrv
|
||||||
t > tMax && startCounted && curve.next !== curves[i + 1]
|
// Detect 2nd case of a consecutive intercept
|
||||||
// Detect 2nd case of a consecutive intercept, but make
|
|| t < tMin && prevT > tMax)) {
|
||||||
// sure we're still on the same loop.
|
var x = Curve.getPoint(values, t).x,
|
||||||
|| t < tMin && prevT > tMax
|
slope = Curve.getTangent(values, t).y,
|
||||||
&& curve.previous === prevCurve)) {
|
counted = false;
|
||||||
var x = Curve.getPoint(values, t).x,
|
// Take care of cases where the curve and the preceding
|
||||||
slope = Curve.getTangent(values, t).y,
|
// curve merely touches the ray towards +-x direction,
|
||||||
counted = false;
|
// but proceeds to the same side of the ray.
|
||||||
// Take care of cases where the curve and the preceding
|
// This essentially is not a crossing.
|
||||||
// curve merely touches the ray towards +-x direction,
|
if (Numerical.isZero(slope) && !Curve.isStraight(values)
|
||||||
// but proceeds to the same side of the ray.
|
// Does the slope over curve beginning change?
|
||||||
// This essentially is not a crossing.
|
|| t < tMin && prevWindCurve && slope * Curve.getTangent(
|
||||||
if (Numerical.isZero(slope) && !Curve.isStraight(values)
|
prevWindCurve.values, 1).y < 0
|
||||||
// Does the slope over curve beginning change?
|
// Does the slope over curve end change?
|
||||||
|| t < tMin && slope * Curve.getTangent(
|
|| t > tMax && nextWindCurve && slope * Curve.getTangent(
|
||||||
curve.previous.values, 1).y < 0
|
nextWindCurve.values, 0).y < 0) {
|
||||||
// Does the slope over curve end change?
|
if (testContains && x >= xBefore && x <= xAfter) {
|
||||||
|| t > tMax && slope * Curve.getTangent(
|
++windLeft;
|
||||||
curve.next.values, 0).y < 0) {
|
++windRight;
|
||||||
if (testContains && x >= xBefore && x <= xAfter) {
|
counted = true;
|
||||||
++windLeft;
|
}
|
||||||
++windRight;
|
} else if (x <= xBefore) {
|
||||||
|
windLeft += winding;
|
||||||
|
counted = true;
|
||||||
|
} else if (x >= xAfter) {
|
||||||
|
windRight += winding;
|
||||||
counted = true;
|
counted = true;
|
||||||
}
|
}
|
||||||
} else if (x <= xBefore) {
|
// mark the start of the path as counted
|
||||||
windLeft += winding;
|
if (curve === firstWindCrv)
|
||||||
counted = true;
|
startCounted = t < tMin && counted;
|
||||||
} else if (x >= xAfter) {
|
|
||||||
windRight += winding;
|
|
||||||
counted = true;
|
|
||||||
}
|
}
|
||||||
// Detect the beginning of a new loop by comparing with
|
prevT = t;
|
||||||
// the previous curve, and set startCounted accordingly.
|
} else if (!winding) {
|
||||||
// This also works for the first loop where i - 1 == -1
|
// if the point is on a horizontal curve and winding changes between
|
||||||
if (curve.previous !== curves[i - 1])
|
// before and after the curve, we treat this as a 'touch point'
|
||||||
startCounted = t < tMin && counted;
|
if (testContains && py == values[1] &&
|
||||||
|
(xAfter >= values[0] && xBefore <= values[6] ||
|
||||||
|
xAfter >= values[6] && xBefore <= values[0]) &&
|
||||||
|
prevWindCurve && nextWindCurve &&
|
||||||
|
prevWindCurve.winding * nextWindCurve.winding < 0) {
|
||||||
|
++windLeft;
|
||||||
|
++windRight;
|
||||||
|
}
|
||||||
|
// we keep the value for prevT to avoid double counting of intersections
|
||||||
|
// at the end of a curve and the start of the next curve, even if
|
||||||
|
// any number of horizontal curves is between both curves
|
||||||
|
} else {
|
||||||
|
prevT = null;
|
||||||
}
|
}
|
||||||
prevCurve = curve;
|
|
||||||
prevT = t;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue