mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-08 05:42:07 -05:00
Improve handling of overlap ambiguity in getIntersection()
Two passes are needed, first strict, then non-strict, to prevent 'better' next candiates over 'worse' ones.
This commit is contained in:
parent
19a17b2918
commit
f6f42fe09b
1 changed files with 41 additions and 17 deletions
|
@ -538,46 +538,63 @@ PathItem.inject(new function() {
|
||||||
// If there are multiple possible intersections, find the one
|
// If there are multiple possible intersections, find the one
|
||||||
// that's either connecting back to start or is not visited yet,
|
// that's either connecting back to start or is not visited yet,
|
||||||
// and will be part of the boolean result:
|
// and will be part of the boolean result:
|
||||||
function getIntersection(inter, prev, ignoreOther) {
|
function getIntersection(strict, inter, prev, ignoreOther) {
|
||||||
if (!inter)
|
if (!inter)
|
||||||
return null;
|
return null;
|
||||||
var seg = inter._segment,
|
var seg = inter._segment,
|
||||||
next = seg.getNext();
|
next = seg.getNext();
|
||||||
if (window.reportSegments) {
|
if (window.reportSegments) {
|
||||||
console.log('getIntersection()'
|
console.log('getIntersection(' + strict + ')'
|
||||||
+ ', seg: ' + seg._path._id + '.' +seg._index
|
+ ', seg: ' + seg._path._id + '.' +seg._index
|
||||||
+ ', next: ' + next._path._id + '.' + next._index
|
+ ', next: ' + next._path._id + '.' + next._index
|
||||||
+ ', seg vis:' + !!seg._visited
|
+ ', seg vis:' + !!seg._visited
|
||||||
+ ', next vis:' + !!next._visited
|
+ ', next vis:' + !!next._visited
|
||||||
+ ', next start:' + (next === start
|
+ ', next start:' + (next === start
|
||||||
|| next === otherStart)
|
|| next === otherStart)
|
||||||
|
+ ', seg wi:' + seg._winding
|
||||||
|
+ ', next wi:' + next._winding
|
||||||
+ ', seg op:' + isValid(seg, true)
|
+ ', seg op:' + isValid(seg, true)
|
||||||
+ ', next op:' + isValid(next)
|
+ ', next op:' + isValid(next)
|
||||||
+ ', next: ' + (!!inter._next));
|
+ ', seg ov: ' + (seg._intersection
|
||||||
|
&& seg._intersection._overlap)
|
||||||
|
+ ', next ov: ' + (next._intersection
|
||||||
|
&& next._intersection._overlap)
|
||||||
|
+ ', more: ' + (!!inter._next));
|
||||||
}
|
}
|
||||||
// See if this segment and next are both not visited yet, or are
|
// See if this segment and next are both not visited yet, or are
|
||||||
// bringing us back to the beginning, and are both part of the
|
// bringing us back to the beginning, and are both part of the
|
||||||
// boolean result.
|
// boolean result.
|
||||||
|
// Handling overlaps correctly here is a bit tricky business, and
|
||||||
|
// requires two passes, first with `strict = true`, then `false`:
|
||||||
|
// In strict mode, the current segment and the next segment are both
|
||||||
|
// checked for validity, and only the current one is allowed to be
|
||||||
|
// an overlap (passing true for `unadjusted` in isValid()). If this
|
||||||
|
// pass does not yield a result, the non-strict mode is used, in
|
||||||
|
// which invalid current segments are tolerated, and overlaps for
|
||||||
|
// the next segment are allowed as long as they are valid when not
|
||||||
|
// adjusted.
|
||||||
return !seg._visited && (!next._visited
|
return !seg._visited && (!next._visited
|
||||||
|| next === start || next === otherStart)
|
|| next === start || next === otherStart)
|
||||||
&& (!operator // Self-intersection doesn't need isValid() calls
|
&& (!operator // Self-intersection doesn't need isValid() calls
|
||||||
// NOTE: We need to use the unadjusted winding here since an
|
// NOTE: We need to use the unadjusted winding here since an
|
||||||
// overlap crossing might have brought us here, in which
|
// overlap crossing might have brought us here, in which
|
||||||
// case isValid(seg, false) might be false.
|
// case isValid(seg, false) might be false.
|
||||||
|| isValid(seg, true) && isValid(next))
|
|| (!strict || isValid(seg, true))
|
||||||
|
&& isValid(next, !strict && inter._overlap))
|
||||||
? inter
|
? inter
|
||||||
// If it's no match, check the other intersection first, then
|
// If it's no match, check the other intersection first, then
|
||||||
// carry on with the next linked intersection.
|
// carry on with the next linked intersection.
|
||||||
: !ignoreOther
|
: !ignoreOther
|
||||||
// We need to get the intersection on the segment, not
|
// We need to get the intersection on the segment, not
|
||||||
// on inter, since they're only linked up through _next
|
// on inter, since multiple solutions are only linked up
|
||||||
// there. But do not check that intersection in the
|
// as a chain through _next there. But do not check that
|
||||||
// first call to getIntersection() (prev == null), since
|
// intersection in the first call to getIntersection()
|
||||||
// we'd go back to the originating segment.
|
// (prev == null), since we'd go straight back to the
|
||||||
|
// originating segment.
|
||||||
&& (prev || seg._intersection !== inter._intersection)
|
&& (prev || seg._intersection !== inter._intersection)
|
||||||
&& getIntersection(seg._intersection, inter, true)
|
&& getIntersection(strict, seg._intersection, inter, true)
|
||||||
|| inter._next !== prev // Prevent circular loops
|
|| inter._next !== prev // Prevent circular loops
|
||||||
&& getIntersection(inter._next, inter, false);
|
&& getIntersection(strict, inter._next, inter, false);
|
||||||
}
|
}
|
||||||
for (var i = 0, l = segments.length; i < l; i++) {
|
for (var i = 0, l = segments.length; i < l; i++) {
|
||||||
var seg = segments[i],
|
var seg = segments[i],
|
||||||
|
@ -593,18 +610,25 @@ PathItem.inject(new function() {
|
||||||
// Once we started a chain, see if there are multiple
|
// Once we started a chain, see if there are multiple
|
||||||
// intersections, and if so, pick the best one:
|
// intersections, and if so, pick the best one:
|
||||||
if (inter && added && window.reportSegments) {
|
if (inter && added && window.reportSegments) {
|
||||||
console.log('Before getIntersection(), seg: '
|
console.log('-----\n'
|
||||||
+ inter._segment._path._id + '.'
|
+'#' + pathCount + '.'
|
||||||
+ inter._segment._index);
|
+ (path ? path._segments.length + 1 : 1)
|
||||||
|
+ ', Before getIntersection()'
|
||||||
|
+ ', seg: ' + seg._path._id + '.' + seg._index
|
||||||
|
+ ', other: ' + inter._segment._path._id + '.'
|
||||||
|
+ inter._segment._index);
|
||||||
}
|
}
|
||||||
inter = added && getIntersection(inter) || inter;
|
inter = added && (getIntersection(true, inter)
|
||||||
|
|| getIntersection(false, inter)) || inter;
|
||||||
var other = inter && inter._segment;
|
var other = inter && inter._segment;
|
||||||
// A switched intersection means we may have changed the segment
|
// A switched intersection means we may have changed the segment
|
||||||
// Point to the other segment in the selected intersection.
|
// Point to the other segment in the selected intersection.
|
||||||
if (inter && added && window.reportSegments) {
|
if (inter && added && window.reportSegments) {
|
||||||
console.log('After getIntersection(), seg: '
|
console.log('After getIntersection()'
|
||||||
+ inter._segment._path._id + '.'
|
+ ', seg: '
|
||||||
+ inter._segment._index);
|
+ seg._path._id + '.' + seg._index
|
||||||
|
+ ', other: ' + inter._segment._path._id + '.'
|
||||||
|
+ inter._segment._index);
|
||||||
}
|
}
|
||||||
if (added && (seg === start || seg === otherStart)) {
|
if (added && (seg === start || seg === otherStart)) {
|
||||||
// We've come back to the start, bail out as we're done.
|
// We've come back to the start, bail out as we're done.
|
||||||
|
|
Loading…
Reference in a new issue