Change PathItem#getIntersections() so that the simply circularity checks in addLocations() work.

This should address the concerns outlined in https://github.com/paperjs/paper.js/issues/805#issuecomment-147850806
This commit is contained in:
Jürg Lehni 2015-10-20 15:18:09 +02:00
parent e0c31e4a50
commit 63303a59f4
3 changed files with 32 additions and 13 deletions

View file

@ -1917,11 +1917,10 @@ new function() { // Scope for intersection using bezier fat-line clipping
pairs = null;
} else if (!straight) {
// Straight pairs don't need further checks. If we found 2 pairs
// the end points on v1 & v2 should be the same. We only have to
// check if the handles are the same, too.
// the end points on v1 & v2 should be the same.
var o1 = Curve.getPart(v1, pairs[0][0], pairs[1][0]),
o2 = Curve.getPart(v2, pairs[0][1], pairs[1][1]);
// Check that handles of overlapping paths are similar enough.
// Check if handles of the overlapping curves are the same too.
if (abs(o2[2] - o1[2]) > geomEpsilon ||
abs(o2[3] - o1[3]) > geomEpsilon ||
abs(o2[4] - o1[4]) > geomEpsilon ||

View file

@ -492,6 +492,9 @@ new function() { // Scope for statics
return loc2;
// If we reach the beginning/end of the list, also compare with
// the location at the other end, as paths are circular lists.
// NOTE: When merging, the locations array will only contain
// locations on the same path, so it is fine that check for the
// end to address circularity. See PathItem#getIntersections()
if (i === 0 || i === length - 1) {
loc2 = locations[i === 0 ? length - 1 : 0];
if (loc.equals(loc2))

View file

@ -68,25 +68,37 @@ var PathItem = Item.extend(/** @lends PathItem# */{
// NOTE: The hidden argument _matrix is used internally to override the
// passed path's transformation matrix.
var self = this === path || !path, // self-intersections?
curves1 = this.getCurves(),
curves2 = self ? curves1 : path.getCurves(),
matrix1 = this._matrix.orNullIfIdentity(),
matrix2 = self ? matrix1
: (_matrix || path._matrix).orNullIfIdentity(),
length1 = curves1.length,
length2 = self ? length1 : curves2.length,
locations = [],
values2 = [];
: (_matrix || path._matrix).orNullIfIdentity();
// First check the bounds of the two paths. If they don't intersect,
// we don't need to iterate through their curves.
if (!self && !this.getBounds(matrix1).touches(path.getBounds(matrix2)))
return locations;
return [];
var curves1 = this.getCurves(),
curves2 = self ? curves1 : path.getCurves(),
length1 = curves1.length,
length2 = self ? length1 : curves2.length,
values2 = [],
lists = [],
locations,
path;
// Cache values for curves2 as we re-iterate them for each in curves1.
for (var i = 0; i < length2; i++)
values2[i] = curves2[i].getValues(matrix2);
for (var i = 0; i < length1; i++) {
var curve1 = curves1[i],
values1 = self ? values2[i] : curve1.getValues(matrix1);
values1 = self ? values2[i] : curve1.getValues(matrix1),
path1 = curve1.getPath();
// NOTE: Due to the nature of Curve._getIntersections(), we need to
// use separate location arrays per path1, to make sure the
// circularity checks are not getting confused by locations on
// separate paths. We are flattening the separate arrays at the end.
if (path1 !== path) {
path = path1;
locations = [];
lists.push(locations);
}
if (self) {
// First check for self-intersections within the same curve.
Curve._getSelfIntersection(values1, curve1, locations, {
@ -102,7 +114,7 @@ var PathItem = Item.extend(/** @lends PathItem# */{
// There might be already one location from the above
// self-intersection check:
if (_returnFirst && locations.length)
break;
return locations;
var curve2 = curves2[j];
// Avoid end point intersections on consecutive curves when
// self intersecting.
@ -119,6 +131,11 @@ var PathItem = Item.extend(/** @lends PathItem# */{
);
}
}
// Now flatten the list of location arrays to one array and return it.
locations = [];
for (var i = 0, l = lists.length; i < l; i++) {
locations.push.apply(locations, lists[i]);
}
return locations;
},