From 48e9ef62a629d7d7f897fc7a4a9d123ed141b04d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Mon, 20 Mar 2017 01:02:12 +0100 Subject: [PATCH] Boolean: Bring back on-path winding handling. Relates to #1281 --- src/path/Curve.js | 4 ++-- src/path/PathItem.Boolean.js | 43 ++++++++++++++++++++++++++---------- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/path/Curve.js b/src/path/Curve.js index 55363f8d..efe4984d 100644 --- a/src/path/Curve.js +++ b/src/path/Curve.js @@ -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. diff --git a/src/path/PathItem.Boolean.js b/src/path/PathItem.Boolean.js index 1daa4895..2714c75d 100644 --- a/src/path/PathItem.Boolean.js +++ b/src/path/PathItem.Boolean.js @@ -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 @@ -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, @@ -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; } @@ -549,9 +552,9 @@ 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 @@ -559,11 +562,11 @@ PathItem.inject(new function() { // #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; } } @@ -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) { @@ -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; } } @@ -678,7 +698,7 @@ PathItem.inject(new function() { windingL: windingL, windingR: windingR, quality: quality, - onPath: onPath + onPath: onAnyPath }; } @@ -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.