Boolean: Bring back on-path winding handling.

Relates to #1281
This commit is contained in:
Jürg Lehni 2017-03-20 01:02:12 +01:00
parent 49fca5510e
commit 48e9ef62a6
2 changed files with 33 additions and 14 deletions

View file

@ -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.

View file

@ -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.