Skip to content

Commit

Permalink
Boolean: Bring back on-path winding handling.
Browse files Browse the repository at this point in the history
Relates to #1281
  • Loading branch information
lehni committed Mar 20, 2017
1 parent 49fca55 commit 48e9ef6
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 14 deletions.
4 changes: 2 additions & 2 deletions src/path/Curve.js
Original file line number Diff line number Diff line change
Expand Up @@ -634,8 +634,8 @@ statics: /** @lends Curve */{
*
* @param {Number[]} v the curve values, as returned by
* {@link Curve#getValues()}
* @param {Number} [dir=0] the direction in which the curves should be
* monotone, `0`: monotone in x-direction, `1`: monotone in y-direction
* @param {Boolean} [dir=false] the direction in which the curves should be
* monotone, `false`: in x-direction, `true`: in y-direction
* @return {Number[][]} an array of curve value arrays of the resulting
* monotone curve. If the original curve was already monotone, an array
* only containing its values are returned.
Expand Down
43 changes: 31 additions & 12 deletions src/path/PathItem.Boolean.js
Original file line number Diff line number Diff line change
Expand Up @@ -452,8 +452,8 @@ PathItem.inject(new function() {
* @param {Curve[]} curves the curves that describe the shape against which
* to check, as returned by {@link Path#getCurves()} or
* {@link CompoundPath#getCurves()}
* @param {Number} [dir=0] the direction in which to determine the
* winding contribution, `0`: in x-direction, `1`: in y-direction
* @param {Boolean} [dir=false] the direction in which to determine the
* winding contribution, `false`: in x-direction, `true`: in y-direction
* @param {Boolean} [closed=false] determines how areas should be closed
* when a curve is part of an open path, `false`: area is closed with a
* straight line, `true`: area is closed taking the handles of the first
Expand All @@ -479,7 +479,10 @@ PathItem.inject(new function() {
paR = pa + windingEpsilon,
windingL = 0,
windingR = 0,
pathWindingL = 0,
pathWindingR = 0,
onPath = false,
onAnyPath = false,
quality = 1,
roots = [],
vPrev,
Expand Down Expand Up @@ -532,9 +535,9 @@ PathItem.inject(new function() {
if (po !== o0) {
// Standard case, curve is not crossed at its starting point.
if (a < paL) {
windingL += winding;
pathWindingL += winding;
} else if (a > paR) {
windingR += winding;
pathWindingR += winding;
} else {
onPath = true;
}
Expand All @@ -549,21 +552,21 @@ PathItem.inject(new function() {
if (winding !== windingPrev) {
// Winding changes from previous curve, cancel its winding.
if (a0 < paL) {
windingL += winding;
pathWindingL += winding;
} else if (a0 > paR) {
windingR += winding;
pathWindingR += winding;
}
} else if (a0 != a3Prev) {
// Handle a horizontal curve between the current and
// previous non-horizontal curve. See
// #1261#issuecomment-282726147 for a detailed explanation:
if (a3Prev < paR && a > paR) {
// Right winding was not added before, so add it now.
windingR += winding;
pathWindingR += winding;
onPath = true;
} else if (a3Prev > paL && a < paL) {
// Left winding was not added before, so add it now.
windingL += winding;
pathWindingL += winding;
onPath = true;
}
}
Expand All @@ -578,7 +581,7 @@ PathItem.inject(new function() {
// again with flipped direction and return that result instead.
return !dontFlip && a > paL && a < paR
&& Curve.getTangent(v, t)[dir ? 'x' : 'y'] === 0
&& getWinding(point, curves, dir ? 0 : 1, closed, true);
&& getWinding(point, curves, !dir, closed, true);
}

function handleCurve(v) {
Expand Down Expand Up @@ -664,6 +667,23 @@ PathItem.inject(new function() {
// it now to treat the path as closed:
if (vClose && (res = handleCurve(vClose)))
return res;
if (onPath && !pathWindingL && !pathWindingR) {
// If the point is on the path and the windings canceled
// each other, we treat the point as if it was inside the
// path. A point inside a path has a winding of [+1,-1]
// for clockwise and [-1,+1] for counter-clockwise paths.
// If the ray is cast in y direction (dir == true), the
// windings always have opposite sign.
pathWindingL = pathWindingR = path.isClockwise(closed) ^ dir
? 1 : -1;
}
windingL += pathWindingL;
windingR += pathWindingR;
pathWindingL = pathWindingR = 0;
if (onPath) {
onAnyPath = true;
onPath = false;
}
vClose = null;
}
}
Expand All @@ -678,7 +698,7 @@ PathItem.inject(new function() {
windingL: windingL,
windingR: windingR,
quality: quality,
onPath: onPath
onPath: onAnyPath
};
}

Expand Down Expand Up @@ -721,8 +741,7 @@ PathItem.inject(new function() {
// from the point (horizontal or vertical), based on the
// curve's direction at that point. If tangent is less
// than 45°, cast the ray vertically, else horizontally.
dir = abs(curve.getTangentAtTime(t).y) < Math.SQRT1_2
? 1 : 0;
dir = abs(curve.getTangentAtTime(t).y) < Math.SQRT1_2;
// While subtracting, we need to omit this curve if it is
// contributing to the second operand and is outside the
// first operand.
Expand Down

0 comments on commit 48e9ef6

Please sign in to comment.