mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-03 19:45:44 -05:00
Merge branch 'improved-winding-2' into develop and clean up formatting.
This commit is contained in:
parent
ed38634a80
commit
7583e6ed5f
2 changed files with 69 additions and 70 deletions
|
@ -412,11 +412,8 @@ PathItem.inject(new function() {
|
||||||
paR = pa + epsilon,
|
paR = pa + epsilon,
|
||||||
windingL = 0,
|
windingL = 0,
|
||||||
windingR = 0,
|
windingR = 0,
|
||||||
pathWindingL = 0,
|
|
||||||
pathWindingR = 0,
|
|
||||||
onPath = false,
|
onPath = false,
|
||||||
onPathWinding = 0,
|
quality = 1,
|
||||||
onPathCount = 0,
|
|
||||||
roots = [],
|
roots = [],
|
||||||
vPrev,
|
vPrev,
|
||||||
vClose;
|
vClose;
|
||||||
|
@ -440,7 +437,7 @@ PathItem.inject(new function() {
|
||||||
// +-----+
|
// +-----+
|
||||||
// +----+ |
|
// +----+ |
|
||||||
// +-----+
|
// +-----+
|
||||||
if (a1 < paR && a3 > paL || a3 < paR && a1 > paL) {
|
if (a0 < paR && a3 > paL || a3 < paR && a0 > paL) {
|
||||||
onPath = true;
|
onPath = true;
|
||||||
}
|
}
|
||||||
// If curve does not change in ordinate direction, windings will
|
// If curve does not change in ordinate direction, windings will
|
||||||
|
@ -461,25 +458,24 @@ PathItem.inject(new function() {
|
||||||
winding = o0 > o3 ? 1 : -1,
|
winding = o0 > o3 ? 1 : -1,
|
||||||
windingPrev = vPrev[io] > vPrev[io + 6] ? 1 : -1,
|
windingPrev = vPrev[io] > vPrev[io + 6] ? 1 : -1,
|
||||||
a3Prev = vPrev[ia + 6];
|
a3Prev = vPrev[ia + 6];
|
||||||
|
if (a >= paL && a <= paR) {
|
||||||
|
onPath = true;
|
||||||
|
}
|
||||||
if (po !== o0) {
|
if (po !== o0) {
|
||||||
// Standard case, curve is not crossed at its starting point.
|
// Standard case, curve is not crossed at its starting point.
|
||||||
if (a < paL) {
|
if (a < paL) {
|
||||||
pathWindingL += winding;
|
windingL += winding;
|
||||||
} else if (a > paR) {
|
} else if (a > paR) {
|
||||||
pathWindingR += winding;
|
windingR += winding;
|
||||||
} else {
|
|
||||||
onPath = true;
|
|
||||||
pathWindingL += winding;
|
|
||||||
pathWindingR += winding;
|
|
||||||
}
|
}
|
||||||
} else if (winding !== windingPrev) {
|
} else if (winding !== windingPrev) {
|
||||||
// Curve is crossed at starting point and winding changes from
|
// Curve is crossed at starting point and winding changes from
|
||||||
// previous curve. Cancel the winding from previous curve.
|
// previous curve. Cancel the winding from previous curve.
|
||||||
if (a3Prev < paR) {
|
if (a3Prev < paR) {
|
||||||
pathWindingL += winding;
|
windingL += winding;
|
||||||
}
|
}
|
||||||
if (a3Prev > paL) {
|
if (a3Prev > paL) {
|
||||||
pathWindingR += winding;
|
windingR += winding;
|
||||||
}
|
}
|
||||||
} else if (a3Prev < paL && a > paL || a3Prev > paR && a < paR) {
|
} else if (a3Prev < paL && a > paL || a3Prev > paR && a < paR) {
|
||||||
// Point is on a horizontal curve between the previous non-
|
// Point is on a horizontal curve between the previous non-
|
||||||
|
@ -487,12 +483,26 @@ PathItem.inject(new function() {
|
||||||
onPath = true;
|
onPath = true;
|
||||||
if (a3Prev < paL) {
|
if (a3Prev < paL) {
|
||||||
// left winding was added before, now add right winding.
|
// left winding was added before, now add right winding.
|
||||||
pathWindingR += winding;
|
windingR += winding;
|
||||||
} else if (a3Prev > paR) {
|
} else if (a3Prev > paR) {
|
||||||
// right winding was added before, not add left winding.
|
// right winding was added before, now add left winding.
|
||||||
pathWindingL += winding;
|
windingL += winding;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Determine the quality of the winding calculation. Currently the
|
||||||
|
// quality is reduced with every crossing of the ray very close
|
||||||
|
// to the path. This means that if the point is on or near multiple
|
||||||
|
// curves, the quality becomes less than 0.5
|
||||||
|
// TODO: Set quality depending on distance
|
||||||
|
if (po !== o0) {
|
||||||
|
if (a > pa - 100 * epsilon && a < pa + 100 * epsilon) {
|
||||||
|
//quality *= Math.min(1, (100 * epsilon * Math.abs(a - pa) + 0.5));
|
||||||
|
quality /= 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO:
|
||||||
|
quality = 0;
|
||||||
|
}
|
||||||
vPrev = v;
|
vPrev = v;
|
||||||
// If we're on the curve, look at the tangent to decide whether to
|
// If we're on the curve, look at the tangent to decide whether to
|
||||||
// flip direction to better determine a reliable winding number:
|
// flip direction to better determine a reliable winding number:
|
||||||
|
@ -586,31 +596,10 @@ PathItem.inject(new function() {
|
||||||
// it now to treat the path as closed:
|
// it now to treat the path as closed:
|
||||||
if (vClose && (res = handleCurve(vClose)))
|
if (vClose && (res = handleCurve(vClose)))
|
||||||
return res;
|
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 == 1), the
|
|
||||||
// windings always have opposite sign.
|
|
||||||
var add = path.isClockwise(closed) ^ dir ? 1 : -1;
|
|
||||||
windingL += add;
|
|
||||||
windingR -= add;
|
|
||||||
onPathWinding += add;
|
|
||||||
} else {
|
|
||||||
windingL += pathWindingL;
|
|
||||||
windingR += pathWindingR;
|
|
||||||
pathWindingL = pathWindingR = 0;
|
|
||||||
}
|
|
||||||
if (onPath)
|
|
||||||
onPathCount++;
|
|
||||||
onPath = false;
|
|
||||||
vClose = null;
|
vClose = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!windingL && !windingR) {
|
// TODO: If the winding one
|
||||||
windingL = windingR = onPathWinding;
|
|
||||||
}
|
|
||||||
windingL = windingL && (2 - abs(windingL) % 2);
|
windingL = windingL && (2 - abs(windingL) % 2);
|
||||||
windingR = windingR && (2 - abs(windingR) % 2);
|
windingR = windingR && (2 - abs(windingR) % 2);
|
||||||
// Return the calculated winding contribution and detect if we are
|
// Return the calculated winding contribution and detect if we are
|
||||||
|
@ -621,8 +610,9 @@ PathItem.inject(new function() {
|
||||||
winding: max(windingL, windingR),
|
winding: max(windingL, windingR),
|
||||||
windingL: windingL,
|
windingL: windingL,
|
||||||
windingR: windingR,
|
windingR: windingR,
|
||||||
|
quality: quality,
|
||||||
onContour: !windingL ^ !windingR,
|
onContour: !windingL ^ !windingR,
|
||||||
onPathCount: onPathCount
|
onPath: onPath
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,38 +632,47 @@ PathItem.inject(new function() {
|
||||||
totalLength += length;
|
totalLength += length;
|
||||||
segment = segment.getNext();
|
segment = segment.getNext();
|
||||||
} while (segment && !segment._intersection && segment !== start);
|
} while (segment && !segment._intersection && segment !== start);
|
||||||
// Sample the point at a middle of the chain to get its winding:
|
// Determine winding at three points in the chain. If a winding with
|
||||||
var length = totalLength / 2;
|
// sufficient quality is found, use it. Otherwise use the winding with
|
||||||
for (var j = 0, l = chain.length; j < l; j++) {
|
// the best quality.
|
||||||
var entry = chain[j],
|
var offsets = [0.48, 0.1, 0.9];
|
||||||
curveLength = entry.length;
|
for (var i = 0; (!winding || winding.quality < 0.5) && i < offsets.length; i++) {
|
||||||
if (length <= curveLength) {
|
var length = totalLength * offsets[i];
|
||||||
var curve = entry.curve,
|
for (var j = 0, l = chain.length; j < l; j++) {
|
||||||
path = curve._path,
|
var entry = chain[j],
|
||||||
parent = path._parent,
|
curveLength = entry.length;
|
||||||
t = curve.getTimeAt(length),
|
if (length <= curveLength) {
|
||||||
pt = curve.getPointAtTime(t),
|
var curve = entry.curve,
|
||||||
// Determine the direction in which to check the winding
|
path = curve._path,
|
||||||
// from the point (horizontal or vertical), based on the
|
parent = path._parent,
|
||||||
// curve's direction at that point. If the tangent is less
|
t = curve.getTimeAt(length),
|
||||||
// than 45°, cast the ray vertically, else horizontally.
|
pt = curve.getPointAtTime(t),
|
||||||
dir = abs(curve.getTangentAtTime(t).normalize().y)
|
// Determine the direction in which to check the winding
|
||||||
|
// 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).normalize().y)
|
||||||
< Math.SQRT1_2 ? 1 : 0;
|
< Math.SQRT1_2 ? 1 : 0;
|
||||||
if (parent instanceof CompoundPath)
|
if (parent instanceof CompoundPath)
|
||||||
path = parent;
|
path = parent;
|
||||||
// While subtracting, we need to omit this curve if it is
|
// While subtracting, we need to omit this curve if it is
|
||||||
// contributing to the second operand and is outside the
|
// contributing to the second operand and is outside the
|
||||||
// first operand.
|
// first operand.
|
||||||
winding = !(operator.subtract && path2 && (
|
var windingNew = !(operator.subtract && path2 && (
|
||||||
path === path1 &&
|
path === path1 &&
|
||||||
path2._getWinding(pt, dir, true).winding ||
|
path2._getWinding(pt, dir, true).winding ||
|
||||||
path === path2 &&
|
path === path2 &&
|
||||||
!path1._getWinding(pt, dir, true).winding))
|
!path1._getWinding(pt, dir, true).winding))
|
||||||
? getWinding(pt, curves, dir, true)
|
? getWinding(pt, curves, dir, true)
|
||||||
: { winding: 0 };
|
: { winding: 0 };
|
||||||
break;
|
if (windingNew.winding &&
|
||||||
|
(!winding || winding.quality < windingNew.quality)) {
|
||||||
|
winding = windingNew;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
length -= curveLength;
|
||||||
}
|
}
|
||||||
length -= curveLength;
|
|
||||||
}
|
}
|
||||||
// Now assign the winding to the entire curve chain.
|
// Now assign the winding to the entire curve chain.
|
||||||
for (var j = chain.length - 1; j >= 0; j--) {
|
for (var j = chain.length - 1; j >= 0; j--) {
|
||||||
|
|
|
@ -272,7 +272,7 @@ var PathItem = Item.extend(/** @lends PathItem# */{
|
||||||
this.getBounds({ internal: true, handle: true }))
|
this.getBounds({ internal: true, handle: true }))
|
||||||
? this._getWinding(point)
|
? this._getWinding(point)
|
||||||
: {};
|
: {};
|
||||||
return !!(this.getFillRule() === 'evenodd'
|
return winding.onPath || !!(this.getFillRule() === 'evenodd'
|
||||||
? winding.windingL & 1 || winding.windingR & 1
|
? winding.windingL & 1 || winding.windingR & 1
|
||||||
: winding.winding);
|
: winding.winding);
|
||||||
/*#*/ } // !__options.nativeContains && __options.booleanOperations
|
/*#*/ } // !__options.nativeContains && __options.booleanOperations
|
||||||
|
|
Loading…
Reference in a new issue