mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-07 13:22:07 -05:00
Improve the way intersections are sorted and merged.
Use a binary search to determine insertion index and compare with neighbours to eliminate doubles.
This commit is contained in:
parent
30f1441c26
commit
2750c34090
4 changed files with 55 additions and 37 deletions
|
@ -402,8 +402,8 @@ var Curve = Base.extend(/** @lends Curve# */{
|
||||||
* curves
|
* curves
|
||||||
*/
|
*/
|
||||||
getIntersections: function(curve) {
|
getIntersections: function(curve) {
|
||||||
return Curve._filterIntersections(Curve._getIntersections(
|
return Curve._getIntersections(this.getValues(), curve.getValues(),
|
||||||
this.getValues(), curve.getValues(), this, curve, [], {}));
|
this, curve, [], {});
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO: adjustThroughPoint
|
// TODO: adjustThroughPoint
|
||||||
|
@ -1359,11 +1359,11 @@ new function() { // Scope for intersection using bezier fat-line clipping
|
||||||
if (!Numerical.isZero(d1) || !Numerical.isZero(d2))
|
if (!Numerical.isZero(d1) || !Numerical.isZero(d2))
|
||||||
debugger;
|
debugger;
|
||||||
*/
|
*/
|
||||||
locations.push(
|
CurveLocation.add(locations,
|
||||||
new CurveLocation(c1, t1, p1 || Curve.getPoint(v1, t1),
|
new CurveLocation(c1, t1, p1 || Curve.getPoint(v1, t1),
|
||||||
null, overlap,
|
null, overlap,
|
||||||
new CurveLocation(c2, t2, p2 || Curve.getPoint(v2, t2),
|
new CurveLocation(c2, t2, p2 || Curve.getPoint(v2, t2),
|
||||||
null, overlap)));
|
null, overlap)), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -358,8 +358,8 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
||||||
|| loc instanceof CurveLocation
|
|| loc instanceof CurveLocation
|
||||||
// Call getCurve() and getParameter() to keep in sync
|
// Call getCurve() and getParameter() to keep in sync
|
||||||
&& this.getCurve() === loc.getCurve()
|
&& this.getCurve() === loc.getCurve()
|
||||||
&& this.getPoint().isClose(loc.getPoint(),
|
&& Math.abs(this.getParameter() - loc.getParameter())
|
||||||
/*#=*/Numerical.GEOMETRIC_EPSILON)
|
< /*#=*/Numerical.CURVETIME_EPSILON
|
||||||
&& (_ignoreOther
|
&& (_ignoreOther
|
||||||
|| (!this._intersection && !loc._intersection
|
|| (!this._intersection && !loc._intersection
|
||||||
|| this._intersection && this._intersection.equals(
|
|| this._intersection && this._intersection.equals(
|
||||||
|
@ -388,36 +388,55 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
||||||
},
|
},
|
||||||
|
|
||||||
statics: {
|
statics: {
|
||||||
sort: function(locations) {
|
add: function(locations, loc, merge) {
|
||||||
function compare(l1, l2, _ignoreOther) {
|
// Insert-sort by path-id, curve, parameter so we can easily merge
|
||||||
if (!l1 || !l2)
|
// duplicates with calls to equals() after.
|
||||||
return l1 ? -1 : 0;
|
// NOTE: We don't call getCurve() / getParameter() here, since this
|
||||||
var curve1 = l1._curve,
|
// code is used internally in boolean operations where all this
|
||||||
curve2 = l2._curve,
|
// information remains valid during processing.
|
||||||
|
var l = 0,
|
||||||
|
r = locations.length - 1;
|
||||||
|
while (l <= r) {
|
||||||
|
var m = (l + r) >>> 1,
|
||||||
|
loc2 = locations[m],
|
||||||
|
curve1 = loc._curve,
|
||||||
|
curve2 = loc2._curve,
|
||||||
path1 = curve1._path,
|
path1 = curve1._path,
|
||||||
path2 = curve2._path,
|
path2 = curve2._path;
|
||||||
diff;
|
diff = path1 === path2
|
||||||
// Sort by path-id, curve, parameter, curve2, parameter2 so we
|
? curve1.getIndex() + loc._parameter
|
||||||
// can easily remove duplicates with calls to equals() after.
|
- curve2.getIndex() - loc2._parameter
|
||||||
// NOTE: We don't call getCurve() / getParameter() here, since
|
// Sort by path id to group all locs on same path.
|
||||||
// this code is used internally in boolean operations where all
|
|
||||||
// this information remains valid during processing.
|
|
||||||
return path1 === path2
|
|
||||||
? curve1 === curve2
|
|
||||||
// TODO: Compare points instead of parameter like in
|
|
||||||
// equals? Or time there too? Why was it changed?
|
|
||||||
? Math.abs((diff = l1._parameter - l2._parameter))
|
|
||||||
< /*#=*/Numerical.CURVETIME_EPSILON
|
|
||||||
? _ignoreOther
|
|
||||||
? 0
|
|
||||||
: compare(l1._intersection,
|
|
||||||
l2._intersection, true)
|
|
||||||
: diff
|
|
||||||
: curve1.getIndex() - curve2.getIndex()
|
|
||||||
// Sort by path id to group all locs on the same path.
|
|
||||||
: path1._id - path2._id;
|
: path1._id - path2._id;
|
||||||
|
// Only compare location with equals() if diff is small enough
|
||||||
|
// NOTE: equals() takes the intersection location into account,
|
||||||
|
// while the above calculation of diff doesn't!
|
||||||
|
if (merge && Math.abs(diff) < /*#=*/Numerical.CURVETIME_EPSILON
|
||||||
|
&& loc.equals(loc2)) {
|
||||||
|
// Carry over overlap setting!
|
||||||
|
if (loc._overlap) {
|
||||||
|
loc2._overlap = loc2._intersection._overlap = true;
|
||||||
}
|
}
|
||||||
locations.sort(compare);
|
// We're done, don't insert
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (diff < 0) {
|
||||||
|
r = m - 1;
|
||||||
|
} else {
|
||||||
|
l = m + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
locations.splice(l, 0, loc);
|
||||||
|
},
|
||||||
|
|
||||||
|
expand: function(locations) {
|
||||||
|
// Create a copy since add() keeps modifying the array and inserting
|
||||||
|
// at sorted indices.
|
||||||
|
var copy = locations.slice();
|
||||||
|
for (var i = 0, l = locations.length; i < l; i++) {
|
||||||
|
this.add(copy, locations[i]._intersection, false);
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, Base.each(Curve.evaluateMethods, function(name) {
|
}, Base.each(Curve.evaluateMethods, function(name) {
|
||||||
|
|
|
@ -110,7 +110,7 @@ PathItem.inject(new function() {
|
||||||
// console.timeEnd('self-intersection');
|
// console.timeEnd('self-intersection');
|
||||||
}
|
}
|
||||||
// console.timeEnd('intersection');
|
// console.timeEnd('intersection');
|
||||||
splitPath(Curve._filterIntersections(locations, true));
|
splitPath(CurveLocation.expand(locations));
|
||||||
|
|
||||||
var segments = [],
|
var segments = [],
|
||||||
// Aggregate of all curves in both operands, monotonic in y
|
// Aggregate of all curves in both operands, monotonic in y
|
||||||
|
|
|
@ -63,8 +63,7 @@ var PathItem = Item.extend(/** @lends PathItem# */{
|
||||||
// intersections.
|
// intersections.
|
||||||
// NOTE: The hidden argument _matrix is used internally to override the
|
// NOTE: The hidden argument _matrix is used internally to override the
|
||||||
// passed path's transformation matrix.
|
// passed path's transformation matrix.
|
||||||
return Curve._filterIntersections(this._getIntersections(
|
return this._getIntersections(this !== path ? path : null, _matrix, []);
|
||||||
this !== path ? path : null, _matrix, []));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_getIntersections: function(path, matrix, locations, returnFirst) {
|
_getIntersections: function(path, matrix, locations, returnFirst) {
|
||||||
|
|
Loading…
Reference in a new issue