Optimize new getWinding() code a bit.

By storing additional information along the first curve of a monoCurve loop.
This commit is contained in:
Jürg Lehni 2016-01-07 11:02:51 +01:00
parent 1078e1f8a9
commit 2fc7684efb

View file

@ -350,22 +350,13 @@ PathItem.inject(new function() {
end = 0; end = 0;
while (end < length) { while (end < length) {
start = end; start = end;
// Determine the beginning and end of the loop, along with the // The first curve of a loop holds information about its length
// first and last curve with non-zero winding within the loop: // and the first / last curve with non-zero winding.
var firstCurve = null, // Retrieve and use it here (See _getMonoCurve()).
lastCurve; var curve = curves[start],
for (var i = start; i < length; i++) { firstWinding = curve.firstWinding,
var curve = curves[i]; lastWinding = curve.lastWinding;
if (curve.winding) { end = start + curve.length;
if (!firstCurve)
firstCurve = curve;
lastCurve = curve;
}
if (curve.next !== curves[i + 1]) {
end = i + 1;
break;
}
}
// Walk through one single loop of curves. // Walk through one single loop of curves.
var startCounted = false, var startCounted = false,
prevCurve, // non-horizontal curve before the current curve. prevCurve, // non-horizontal curve before the current curve.
@ -374,8 +365,8 @@ PathItem.inject(new function() {
curve = null; curve = null;
for (var i = start; i < end; i++) { for (var i = start; i < end; i++) {
if (!curve) { if (!curve) {
prevCurve = lastCurve; prevCurve = lastWinding;
nextCurve = firstCurve; nextCurve = firstWinding;
} else if (curve.winding) { } else if (curve.winding) {
prevCurve = curve; prevCurve = curve;
} }
@ -407,17 +398,16 @@ PathItem.inject(new function() {
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.
t > tMax && startCounted && curve === lastCurve t > tMax && startCounted && curve === lastWinding
// Detect 2nd case of a consecutive intercept // Detect 2nd case of a consecutive intercept
|| t < tMin && prevT > tMax)) { || t < tMin && prevT > tMax)) {
var x = Curve.getPoint(values, t).x, var x = Curve.getPoint(values, t).x,
slope = Curve.getTangent(values, t).y,
counted = false; counted = false;
// Take care of cases where the curve and the // Take care of cases where the curve and the
// preceding curve merely touches the ray towards // preceding curve merely touches the ray towards
// +-x direction, but proceeds to the same side of // +-x direction, but proceeds to the same side of
// the ray. This essentially is not a crossing. // the ray. This essentially is not a crossing.
if (Numerical.isZero(slope) if (Numerical.isZero(Curve.getTangent(values, t).y)
&& !Curve.isStraight(values) && !Curve.isStraight(values)
// Does the winding over the edges change? // Does the winding over the edges change?
|| t < tMin && prevCurve || t < tMin && prevCurve
@ -437,7 +427,7 @@ PathItem.inject(new function() {
counted = true; counted = true;
} }
// Mark the start of the path as counted. // Mark the start of the path as counted.
if (curve === firstCurve) { if (curve === firstWinding) {
startCounted = t < tMin && counted; startCounted = t < tMin && counted;
} }
} }
@ -942,19 +932,22 @@ Path.inject(/** @lends Path# */{
*/ */
_getMonoCurves: function() { _getMonoCurves: function() {
var monoCurves = this._monoCurves, var monoCurves = this._monoCurves,
prevCurve; prevCurve,
firstWinding = null,
lastWinding;
// Insert curve values into a cached array // Insert curve values into a cached array
function insertCurve(v) { function insertCurve(v) {
var y0 = v[1], var y0 = v[1],
y1 = v[7], y1 = v[7],
winding = y0 === y1
? 0 // Horizontal
: y0 > y1
? -1 // Decreasing
: 1, // Increasing
curve = { curve = {
values: v, values: v,
winding: y0 === y1 winding: winding,
? 0 // Horizontal
: y0 > y1
? -1 // Decreasing
: 1, // Increasing
// Add a reference to neighboring curves. // Add a reference to neighboring curves.
previous: prevCurve, previous: prevCurve,
next: null // Always set it for hidden class optimization. next: null // Always set it for hidden class optimization.
@ -963,6 +956,12 @@ Path.inject(/** @lends Path# */{
prevCurve.next = curve; prevCurve.next = curve;
monoCurves.push(curve); monoCurves.push(curve);
prevCurve = curve; prevCurve = curve;
// Keep track of the first and last curves with winding numbers.
if (winding) {
if (!firstWinding)
firstWinding = curve;
lastWinding = curve;
}
} }
// Handle bezier curves. We need to chop them into smaller curves with // Handle bezier curves. We need to chop them into smaller curves with
@ -1034,6 +1033,11 @@ Path.inject(/** @lends Path# */{
last = monoCurves[monoCurves.length - 1]; last = monoCurves[monoCurves.length - 1];
first.previous = last; first.previous = last;
last.next = first; last.next = first;
// Add information about the loop length and the first / last
// curve with non-zero winding (Used in getWinding()).
first.length = monoCurves.length;
first.firstWinding = firstWinding;
first.lastWinding = lastWinding;
} }
} }
return monoCurves; return monoCurves;