Improve debug logging and drawing.

And add more descriptive comments to tracePath().
This commit is contained in:
Jürg Lehni 2015-09-16 09:52:41 +02:00
parent 197aa4b4cf
commit f8bd7a2005
2 changed files with 40 additions and 20 deletions

View file

@ -282,7 +282,7 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
return curve && curve.split(this.getParameter(), true); return curve && curve.split(this.getParameter(), true);
}, },
isCrossing: function(report) { isCrossing: function(_report) {
// Implementation based on work by Andy Finnell: // Implementation based on work by Andy Finnell:
// http://losingfight.com/blog/2011/07/09/how-to-implement-boolean-operations-on-bezier-paths-part-3/ // http://losingfight.com/blog/2011/07/09/how-to-implement-boolean-operations-on-bezier-paths-part-3/
// https://bitbucket.org/andyfinnell/vectorboolean // https://bitbucket.org/andyfinnell/vectorboolean
@ -303,7 +303,6 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
var tMin = /*#=*/Numerical.CURVETIME_EPSILON, var tMin = /*#=*/Numerical.CURVETIME_EPSILON,
tMax = 1 - tMin, tMax = 1 - tMin,
PI = Math.PI, PI = Math.PI,
PI_2 = PI * 2,
// TODO: Make getCurve() sync work in boolean ops after splitting!!! // TODO: Make getCurve() sync work in boolean ops after splitting!!!
c2 = this._curve, c2 = this._curve,
c1 = c2.getPrevious(), c1 = c2.getPrevious(),
@ -311,7 +310,7 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
c3 = c4.getPrevious(); c3 = c4.getPrevious();
if (!c1 || !c3) if (!c1 || !c3)
return this._crossing = false; return this._crossing = false;
if (report) { if (_report) {
new Path.Circle({ new Path.Circle({
center: this.getPoint(), center: this.getPoint(),
radius: 10, radius: 10,
@ -325,13 +324,12 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
segments: [c3.getSegment1(), c3.getSegment2(), c4.getSegment2()], segments: [c3.getSegment1(), c3.getSegment2(), c4.getSegment2()],
strokeColor: 'orange' strokeColor: 'orange'
}); });
console.log(c1.getValues(), c2.getValues(), c3.getValues(), c4.getValues());
} }
function isInRange(angle, min, max) { function isInRange(angle, min, max) {
return min < max return min < max
? angle > min && angle < max ? angle > min && angle < max
// The range wraps around 0: // The range wraps around -PI / PI:
: angle > min && angle <= PI || angle >= -PI && angle < max; : angle > min && angle <= PI || angle >= -PI && angle < max;
} }

View file

@ -149,8 +149,8 @@ PathItem.inject(new function() {
path1, path2); path1, path2);
} }
var scaleFactor = 1; // 1 / 3000; var scaleFactor = 0.25; // 1 / 3000;
var textAngle = 60; var textAngle = 33;
var fontSize = 5; var fontSize = 5;
/** /**
@ -543,36 +543,41 @@ PathItem.inject(new function() {
// resolving self-Intersections. // resolving self-Intersections.
seg = other; seg = other;
} else if (operation !== 'intersect' && inter._overlap) { } else if (operation !== 'intersect' && inter._overlap) {
// Switch to the overlapping intersection segment // Switch to the overlapping intersecting segment if its
// if its winding number along the curve is 1, to // winding number along the curve is 1, meaning we leave the
// leave the overlapping area. // overlapping area.
// NOTE: We cannot check the next (overlapping) // NOTE: We cannot check the next (overlapping) segment
// segment since its winding number will always be 2 // since its winding number will always be 2.
drawSegment(seg, 'overlap', i, 'orange');
var curve = other.getCurve(); var curve = other.getCurve();
if (getWinding(curve.getPointAt(0.5, true), if (getWinding(curve.getPointAt(0.5, true),
monoCurves, curve.isHorizontal()) === 1) { monoCurves, curve.isHorizontal()) === 1) {
drawSegment(seg, 'overlap-cross', i, 'orange');
seg = other; seg = other;
} else {
drawSegment(seg, 'overlap-stay', i, 'orange');
} }
} else if (operation === 'exclude') { } else if (operation === 'exclude') {
// We need to handle exclusion separately, as we want to // We need to handle exclusion separately, as we want to
// switch at each crossing, and at each intersection within // switch at each crossing, and at each intersection within
// the exclusion area even if it is not crossing. // the exclusion area even if it is not a crossing.
if (inter.isCrossing() || path2.contains(seg._point)) { if (inter.isCrossing() || path2.contains(seg._point)) {
seg = other;
drawSegment(seg, 'exclude-cross', i, 'green'); drawSegment(seg, 'exclude-cross', i, 'green');
seg = other;
} else { } else {
drawSegment(other, 'exclude-no-cross', i, 'orange'); drawSegment(seg, 'exclude-stay', i, 'orange');
} }
} else if (operator(seg._winding)) { } else if (operator(seg._winding)) {
// Do not switch to the intersecting segment as it is // Do not switch to the intersecting segment as this segment
// contained inside the boolean result. // is part of the the boolean result.
drawSegment(seg, 'ignore-keep', i, 'black'); drawSegment(seg, 'ignore-keep', i, 'black');
} else if (operator(other._winding) && inter.isCrossing()) { } else if (operator(other._winding) && inter.isCrossing()) {
seg = other; // The other segment is part of the boolean result, and we
// are at crossing, switch over.
drawSegment(seg, 'cross', i, 'green'); drawSegment(seg, 'cross', i, 'green');
seg = other;
} else { } else {
drawSegment(other, 'no-cross', i, 'orange'); // Keep on truckin'
drawSegment(seg, 'stay', i, 'orange');
} }
if (seg._visited) { if (seg._visited) {
// We didn't manage to switch, so stop right here. // We didn't manage to switch, so stop right here.
@ -588,10 +593,27 @@ PathItem.inject(new function() {
seg = seg.getNext(); seg = seg.getNext();
inter = seg && seg._intersection; inter = seg && seg._intersection;
other = inter && inter._segment; other = inter && inter._segment;
if (seg === start || seg === otherStart) {
drawSegment(seg, 'close', i, 'red');
}
if (seg._visited && (!other || other._visited)) {
drawSegment(seg, 'visited', i, 'red');
}
if (!inter && !operator(seg._winding)) {
// TODO: We really should find a way to go backwards perhaps
// and try another path when this happens?
drawSegment(seg, 'discard', i, 'red');
console.error('Excluded segment encountered, aborting #'
+ pathCount + '.' +
(path ? path._segments.length + 1 : 1));
}
} while (seg && seg !== start && seg !== otherStart } while (seg && seg !== start && seg !== otherStart
// If we're about to switch, try to see if we can carry on // If we're about to switch, try to see if we can carry on
// if the other segment wasn't visited yet. // if the other segment wasn't visited yet.
&& (!seg._visited || other && !other._visited) && (!seg._visited || other && !other._visited)
// Intersections are always part of the resulting path, for
// all other segments check the winding contribution to see
// if they are to be kept. If not, the chain has to end here
&& (inter || operator(seg._winding))); && (inter || operator(seg._winding)));
// Finish with closing the paths if necessary, correctly linking up // Finish with closing the paths if necessary, correctly linking up
// curves etc. // curves etc.