From 6cdead0e8c755c7ba9c75238be9806f482034b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Sun, 11 Oct 2015 16:56:41 +0200 Subject: [PATCH] Add fallback strategy when ending up in a dead-end in tracePaths(). This simple fix appears to be able to catch quite a few glitches with very small curves. --- src/path/PathItem.Boolean.js | 46 ++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/src/path/PathItem.Boolean.js b/src/path/PathItem.Boolean.js index 1ab769fa..b116df36 100644 --- a/src/path/PathItem.Boolean.js +++ b/src/path/PathItem.Boolean.js @@ -751,36 +751,62 @@ PathItem.inject(new function() { drawSegment(seg, null, 'stay', i, 'blue'); } if (seg._visited) { - if (isStart(seg)) { + finished = isStart(seg); + if (finished) { drawSegment(seg, null, 'done', i, 'red'); - finished = true; - } else if (inter) { + } + if (!finished && inter) { var found = findStartSegment(inter, true) || findStartSegment(inter, false); + // This should not happen but due to numerical + // imprecisions we sometimes end up in a dead-end. See + // if we can find a way out by checking all valid + // segments to find one that's close enough. + for (var j = 0; !found && j < l; j++) { + var seg2 = segments[j]; + // Do not start a chain with already visited + // segments, and segments that are not going to + // be part of the resulting operation. + if (seg !== seg2 + && seg._point.isClose(seg2._point, + /*#=*/Numerical.GEOMETRIC_EPSILON) + && (isStart(seg2) || isValid(seg2))) { + found = seg2; + } + } if (found) { seg = found; - drawSegment(seg, null, 'done multiple', i, 'red'); - finished = true; - break; + finished = isStart(seg); + if (window.reportSegments) { + console.log('Switching to: ', + seg._path._id + '.' + seg._index); + } + if (finished) { + drawSegment(seg, null, 'done inter', i, 'red'); + } } } - if (!finished) { + if (finished) + break; + if (!isValid(seg)) { // We didn't manage to switch, so stop right here. console.error('Visited segment encountered, aborting #' + pathCount + '.' + (path ? path._segments.length + 1 : 1) + ', id: ' + seg._path._id + '.' + seg._index + ', multiple: ' + !!(inter && inter._next)); + break; } - break; } if (!path) { path = new Path(Item.NO_INSERT); start = seg; otherStart = other; } - // Add the current segment to the path, and mark the added - // segment as visited. + if (window.reportSegments) { + console.log('Adding', seg._path._id + '.' + seg._index); + } + // Add the segment to the path, and mark it as visited. path.add(new Segment(seg._point, handleIn, seg._handleOut)); seg._visited = true; seg = seg.getNext();