mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-03 19:45:44 -05:00
Boolean: Improve handling of multiple crossings on the same curve.
This commit is contained in:
parent
357ff0dd43
commit
ed57b82b19
4 changed files with 35 additions and 33 deletions
|
@ -89,10 +89,10 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
||||||
*/
|
*/
|
||||||
getSegment: function() {
|
getSegment: function() {
|
||||||
// Request curve first, so _segment gets invalidated if it's out of sync
|
// Request curve first, so _segment gets invalidated if it's out of sync
|
||||||
var curve = this.getCurve(),
|
var segment = this._segment;
|
||||||
segment = this._segment;
|
|
||||||
if (!segment) {
|
if (!segment) {
|
||||||
var time = this.getTime();
|
var curve = this.getCurve(),
|
||||||
|
time = this.getTime();
|
||||||
if (time === 0) {
|
if (time === 0) {
|
||||||
segment = curve._segment1;
|
segment = curve._segment1;
|
||||||
} else if (time === 1) {
|
} else if (time === 1) {
|
||||||
|
@ -119,10 +119,9 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
||||||
var path = this._path,
|
var path = this._path,
|
||||||
that = this;
|
that = this;
|
||||||
if (path && path._version !== this._version) {
|
if (path && path._version !== this._version) {
|
||||||
// If the path's segments have changed in the meantime, clear the
|
// If the path's segments have changed, clear the cached time and
|
||||||
// internal _time value and force re-fetching of the correct
|
// offset values and force re-fetching of the correct curve.
|
||||||
// curve again here.
|
this._time = this._offset = this._curve = null;
|
||||||
this._time = this._curve = this._offset = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If path is out of sync, access current curve objects through segment1
|
// If path is out of sync, access current curve objects through segment1
|
||||||
|
@ -134,7 +133,6 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
||||||
if (curve && (that._time = curve.getTimeOf(that._point)) != null) {
|
if (curve && (that._time = curve.getTimeOf(that._point)) != null) {
|
||||||
// Fetch path again as it could be on a new one through split()
|
// Fetch path again as it could be on a new one through split()
|
||||||
that._setCurve(curve);
|
that._setCurve(curve);
|
||||||
that._segment = segment;
|
|
||||||
return curve;
|
return curve;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,7 +140,6 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
||||||
return this._curve
|
return this._curve
|
||||||
|| trySegment(this._segment)
|
|| trySegment(this._segment)
|
||||||
|| trySegment(this._segment1)
|
|| trySegment(this._segment1)
|
||||||
|| trySegment(this._segment1.getNext())
|
|
||||||
|| trySegment(this._segment2.getPrevious());
|
|| trySegment(this._segment2.getPrevious());
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1199,10 +1199,9 @@ var Path = PathItem.extend(/** @lends Path# */{
|
||||||
this._add([segments[0]]);
|
this._add([segments[0]]);
|
||||||
path.remove();
|
path.remove();
|
||||||
}
|
}
|
||||||
// Close the resulting path and merge first and last segment if they
|
// If the first and last segment touch, close the resulting path and
|
||||||
// touch, meaning the touched at path ends. Also do this if no path
|
// merge the end segments. Also do this if no path argument was provided
|
||||||
// argument was provided, in which cases the path is joined with itself
|
// in which cases the path is joined with itself only if its ends touch.
|
||||||
// only if its ends touch.
|
|
||||||
var first = this.getFirstSegment(),
|
var first = this.getFirstSegment(),
|
||||||
last = this.getLastSegment();
|
last = this.getLastSegment();
|
||||||
if (first !== last && first._point.isClose(last._point, epsilon)) {
|
if (first !== last && first._point.isClose(last._point, epsilon)) {
|
||||||
|
|
|
@ -148,7 +148,10 @@ PathItem.inject(new function() {
|
||||||
} else {
|
} else {
|
||||||
// When there are no crossings, the result can be determined through
|
// When there are no crossings, the result can be determined through
|
||||||
// a much faster call to reorientPaths():
|
// a much faster call to reorientPaths():
|
||||||
paths = reorientPaths(paths2 ? paths1.concat(paths2) : paths1,
|
paths = reorientPaths(
|
||||||
|
// Make sure reorientPaths() never works on original
|
||||||
|
// _children arrays by calling paths1.slice()
|
||||||
|
paths2 ? paths1.concat(paths2) : paths1.slice(),
|
||||||
function(w) {
|
function(w) {
|
||||||
return !!operator[w];
|
return !!operator[w];
|
||||||
});
|
});
|
||||||
|
@ -357,6 +360,7 @@ PathItem.inject(new function() {
|
||||||
// be changed to the scaled value after splitting previously.
|
// be changed to the scaled value after splitting previously.
|
||||||
// See CurveLocation#getCurve(), #resolveCrossings()
|
// See CurveLocation#getCurve(), #resolveCrossings()
|
||||||
time = loc._time,
|
time = loc._time,
|
||||||
|
origTime = time,
|
||||||
exclude = include && !include(loc),
|
exclude = include && !include(loc),
|
||||||
// Retrieve curve after calling include(), because it may cause
|
// Retrieve curve after calling include(), because it may cause
|
||||||
// a change in the cached location values, see above.
|
// a change in the cached location values, see above.
|
||||||
|
@ -371,12 +375,12 @@ PathItem.inject(new function() {
|
||||||
// renormalization within the curve.
|
// renormalization within the curve.
|
||||||
renormalizeLocs = [];
|
renormalizeLocs = [];
|
||||||
prevTime = null;
|
prevTime = null;
|
||||||
|
prevCurve = curve;
|
||||||
} else if (prevTime >= tMin) {
|
} else if (prevTime >= tMin) {
|
||||||
// Rescale curve-time when we are splitting the same curve
|
// Rescale curve-time when we are splitting the same curve
|
||||||
// multiple times, if splitting was done previously.
|
// multiple times, if splitting was done previously.
|
||||||
loc._time /= prevTime;
|
time /= prevTime;
|
||||||
}
|
}
|
||||||
prevCurve = curve;
|
|
||||||
}
|
}
|
||||||
if (exclude) {
|
if (exclude) {
|
||||||
// Store excluded locations for later renormalization, in case
|
// Store excluded locations for later renormalization, in case
|
||||||
|
@ -387,8 +391,7 @@ PathItem.inject(new function() {
|
||||||
} else if (include) {
|
} else if (include) {
|
||||||
results.unshift(loc);
|
results.unshift(loc);
|
||||||
}
|
}
|
||||||
prevTime = time;
|
prevTime = origTime;
|
||||||
time = loc._time;
|
|
||||||
if (time < tMin) {
|
if (time < tMin) {
|
||||||
segment = curve._segment1;
|
segment = curve._segment1;
|
||||||
} else if (time > tMax) {
|
} else if (time > tMax) {
|
||||||
|
@ -1121,7 +1124,7 @@ PathItem.inject(new function() {
|
||||||
var hasOverlaps = false,
|
var hasOverlaps = false,
|
||||||
hasCrossings = false,
|
hasCrossings = false,
|
||||||
intersections = this.getIntersections(null, function(inter) {
|
intersections = this.getIntersections(null, function(inter) {
|
||||||
return inter._overlap && (hasOverlaps = true) ||
|
return inter.hasOverlap() && (hasOverlaps = true) ||
|
||||||
inter.isCrossing() && (hasCrossings = true);
|
inter.isCrossing() && (hasCrossings = true);
|
||||||
}),
|
}),
|
||||||
// We only need to keep track of curves that need clearing
|
// We only need to keep track of curves that need clearing
|
||||||
|
@ -1132,7 +1135,7 @@ PathItem.inject(new function() {
|
||||||
// First divide in all overlaps, and then remove the inside of
|
// First divide in all overlaps, and then remove the inside of
|
||||||
// the resulting overlap ranges.
|
// the resulting overlap ranges.
|
||||||
var overlaps = divideLocations(intersections, function(inter) {
|
var overlaps = divideLocations(intersections, function(inter) {
|
||||||
return inter._overlap;
|
return inter.hasOverlap();
|
||||||
}, clearCurves);
|
}, clearCurves);
|
||||||
for (var i = overlaps.length - 1; i >= 0; i--) {
|
for (var i = overlaps.length - 1; i >= 0; i--) {
|
||||||
var seg = overlaps[i]._segment,
|
var seg = overlaps[i]._segment,
|
||||||
|
@ -1160,20 +1163,23 @@ PathItem.inject(new function() {
|
||||||
// Check both involved curves to see if they're still valid,
|
// Check both involved curves to see if they're still valid,
|
||||||
// meaning they are still part of their paths.
|
// meaning they are still part of their paths.
|
||||||
var curve1 = inter.getCurve(),
|
var curve1 = inter.getCurve(),
|
||||||
// Do not call getCurve() on the other intersection yet,
|
seg1 = inter.getSegment(),
|
||||||
// as it too is in the intersections array and will be
|
// Do not call getCurve() and getSegment() on the other
|
||||||
// divided later. But do check if its current curve is
|
// intersection yet, as it too is in the intersections
|
||||||
// still valid. This is required by some very rare edge
|
// array and will be divided later. But check if its
|
||||||
|
// current curve is valid, as required by some rare edge
|
||||||
// cases, related to intersections on the same curve.
|
// cases, related to intersections on the same curve.
|
||||||
curve2 = inter._intersection._curve,
|
other = inter._intersection,
|
||||||
seg = inter._segment;
|
curve2 = other._curve,
|
||||||
if (curve1 && curve2 && curve1._path && curve2._path) {
|
seg2 = other._segment;
|
||||||
|
if (curve1 && curve2 && curve1._path && curve2._path)
|
||||||
return true;
|
return true;
|
||||||
} else if (seg) {
|
// Remove all intersections that were involved in the
|
||||||
// Remove all intersections that were involved in the
|
// handling of overlaps, to not confuse tracePaths().
|
||||||
// handling of overlaps, to not confuse tracePaths().
|
if (seg1)
|
||||||
seg._intersection = null;
|
seg1._intersection = null;
|
||||||
}
|
if (seg2)
|
||||||
|
seg2._intersection = null;
|
||||||
}, clearCurves);
|
}, clearCurves);
|
||||||
if (clearCurves)
|
if (clearCurves)
|
||||||
clearCurveHandles(clearCurves);
|
clearCurveHandles(clearCurves);
|
||||||
|
|
|
@ -355,7 +355,7 @@ var PathItem = Item.extend(/** @lends PathItem# */{
|
||||||
// as it should in the known use cases.
|
// as it should in the known use cases.
|
||||||
// The ideal implementation would deal with it in a way outlined in:
|
// The ideal implementation would deal with it in a way outlined in:
|
||||||
// https://github.com/paperjs/paper.js/issues/874#issuecomment-168332391
|
// https://github.com/paperjs/paper.js/issues/874#issuecomment-168332391
|
||||||
return inter._overlap || inter.isCrossing();
|
return inter.hasOverlap() || inter.isCrossing();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue