From fd927cbe2235d328862a56cec0fdce9b2933786d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Thu, 24 Sep 2015 12:49:39 -0400 Subject: [PATCH] Properly solve issues with self-intersecting special case. (e.g. shapes resembling the infinity sign) --- src/path/Curve.js | 37 +++++++++++++++++++++++------------- src/path/CurveLocation.js | 12 +++--------- src/path/PathItem.Boolean.js | 1 - 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/path/Curve.js b/src/path/Curve.js index 5f1ab1a4..32433fd2 100644 --- a/src/path/Curve.js +++ b/src/path/Curve.js @@ -1040,7 +1040,7 @@ statics: { step /= 2; } var pt = Curve.getPoint(values, minT); - return new CurveLocation(this, minT, pt, point.getDistance(pt)); + return new CurveLocation(this, minT, pt, null, point.getDistance(pt)); }, /** @@ -1357,11 +1357,10 @@ new function() { // Scope for intersection using bezier fat-line clipping function addLocation(locations, param, v1, c1, t1, p1, v2, c2, t2, p2, overlap) { - var loc = null, + var startConnected = param.startConnected, + endConnected = param.endConnected, tMin = /*#=*/Numerical.CURVETIME_EPSILON, - tMax = 1 - tMin, - startConnected = param.startConnected, - endConnected = param.endConnected; + tMax = 1 - tMin; if (t1 == null) t1 = Curve.getParameterOf(v1, p1.x, p1.y); // Check t1 and t2 against correct bounds, based on start-/endConnected: @@ -1372,11 +1371,11 @@ new function() { // Scope for intersection using bezier fat-line clipping // a found overlap. The normal intersection will already be found at // the beginning, and would be added twice otherwise. if (t1 >= (startConnected ? tMin : 0) && - t1 <= (endConnected || !overlap && c1.isLast() ? tMax : 1)) { + t1 <= (endConnected ? tMax : 1)) { if (t2 == null) t2 = Curve.getParameterOf(v2, p2.x, p2.y); if (t2 >= (endConnected ? tMin : 0) && - t2 <= (startConnected || !overlap && c2.isLast() ? tMax : 1)) { + t2 <= (startConnected ? tMax : 1)) { // TODO: Don't we need to check the range of t2 as well? Does it // also need startConnected / endConnected values? var renormalize = param.renormalize; @@ -1385,13 +1384,25 @@ new function() { // Scope for intersection using bezier fat-line clipping t1 = res[0]; t2 = res[1]; } - var include = param.include, - loc = new CurveLocation(c1, t1, - p1 || Curve.getPoint(v1, t1), null, overlap, - new CurveLocation(c2, t2, - p2 || Curve.getPoint(v2, t2), null, overlap)); - if (!include || include(loc)) + var loc1 = new CurveLocation(c1, t1, + p1 || Curve.getPoint(v1, t1), overlap), + loc2 = new CurveLocation(c2, t2, + p2 || Curve.getPoint(v2, t2), overlap), + // For self-intersections, detect the case where the second + // curve wrapped around, and flip them so they can get + // matched to a potentially already existing intersection. + flip = loc1.getPath() === loc2.getPath() + && loc1.getIndex() > loc2.getIndex(), + loc = flip ? loc2 : loc1, + include = param.include; + // Link the two locations to each other. + loc1._intersection = loc2; + loc2._intersection = loc1; + // TODO: Remove this once debug logging is removed. + (flip ? loc1 : loc2)._other = true; + if (!include || include(loc)) { CurveLocation.add(locations, loc, true); + } } } } diff --git a/src/path/CurveLocation.js b/src/path/CurveLocation.js index b66602b7..b1111a35 100644 --- a/src/path/CurveLocation.js +++ b/src/path/CurveLocation.js @@ -42,7 +42,7 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{ * @param {Point} [point] */ initialize: function CurveLocation(curve, parameter, point, - _distance, _overlap, _intersection) { + _overlap, _distance) { // Merge intersections very close to the end of a curve to the // beginning of the next curve. if (parameter >= 1 - /*#=*/Numerical.CURVETIME_EPSILON) { @@ -60,15 +60,9 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{ this._setCurve(curve); this._parameter = parameter; this._point = point || curve.getPointAt(parameter, true); - this._distance = _distance; this._overlap = _overlap; - this._crossing = null; - this._intersection = _intersection; - if (_intersection) { - _intersection._intersection = this; - // TODO: Remove this once debug logging is removed. - _intersection._other = true; - } + this._distance = _distance; + this._intersection = null; }, _setCurve: function(curve) { diff --git a/src/path/PathItem.Boolean.js b/src/path/PathItem.Boolean.js index e31cfb66..9cd124ed 100644 --- a/src/path/PathItem.Boolean.js +++ b/src/path/PathItem.Boolean.js @@ -639,7 +639,6 @@ PathItem.inject(new function() { if (added && (seg === start || seg === otherStart)) { // We've come back to the start, bail out as we're done. drawSegment(seg, null, 'done', i, 'red'); - seg._visited = true; break; } else if (seg._visited && (!other || other._visited)) { // TODO: Do we still need to check other too?