Start handling self-overlapping paths in getOverlaps()

Relates to #874 and #887
This commit is contained in:
Jürg Lehni 2016-01-05 12:04:40 +01:00
parent a6e1a1a76d
commit 0d172a74f4

View file

@ -1383,8 +1383,10 @@ new function() { // Scope for intersection using bezier fat-line clipping
function addLocation(locations, param, v1, c1, t1, p1, v2, c2, t2, p2, function addLocation(locations, param, v1, c1, t1, p1, v2, c2, t2, p2,
overlap) { overlap) {
var startConnected = param.startConnected, // Do not exclude connecting points between two curves if they were part
endConnected = param.endConnected, // of overlap checks. They could be self-overlapping.
var excludeStart = !overlap && param.startConnected,
excludeEnd = !overlap && param.endConnected,
tMin = /*#=*/Numerical.CURVETIME_EPSILON, tMin = /*#=*/Numerical.CURVETIME_EPSILON,
tMax = 1 - tMin; tMax = 1 - tMin;
if (t1 == null) if (t1 == null)
@ -1396,12 +1398,12 @@ new function() { // Scope for intersection using bezier fat-line clipping
// which connects back to the beginning, but only if it's not part of // which connects back to the beginning, but only if it's not part of
// a found overlap. The normal intersection will already be found at // a found overlap. The normal intersection will already be found at
// the beginning, and would be added twice otherwise. // the beginning, and would be added twice otherwise.
if (t1 !== null && t1 >= (startConnected ? tMin : 0) && if (t1 !== null && t1 >= (excludeStart ? tMin : 0) &&
t1 <= (endConnected ? tMax : 1)) { t1 <= (excludeEnd ? tMax : 1)) {
if (t2 == null) if (t2 == null)
t2 = Curve.getParameterOf(v2, p2); t2 = Curve.getParameterOf(v2, p2);
if (t2 !== null && t2 >= (endConnected ? tMin : 0) && if (t2 !== null && t2 >= (excludeEnd ? tMin : 0) &&
t2 <= (startConnected ? tMax : 1)) { t2 <= (excludeStart ? tMax : 1)) {
var renormalize = param.renormalize; var renormalize = param.renormalize;
if (renormalize) { if (renormalize) {
var res = renormalize(t1, t2); var res = renormalize(t1, t2);
@ -1717,7 +1719,6 @@ new function() { // Scope for intersection using bezier fat-line clipping
max(c2p1y, c2s1y, c2s2y, c2p2y))) max(c2p1y, c2s1y, c2s2y, c2p2y)))
return locations; return locations;
// Now detect and handle overlaps: // Now detect and handle overlaps:
if (!param.startConnected && !param.endConnected) {
var overlaps = Curve.getOverlaps(v1, v2); var overlaps = Curve.getOverlaps(v1, v2);
if (overlaps) { if (overlaps) {
for (var i = 0; i < 2; i++) { for (var i = 0; i < 2; i++) {
@ -1728,7 +1729,6 @@ new function() { // Scope for intersection using bezier fat-line clipping
} }
return locations; return locations;
} }
}
var straight1 = Curve.isStraight(v1), var straight1 = Curve.isStraight(v1),
straight2 = Curve.isStraight(v2), straight2 = Curve.isStraight(v2),
@ -1856,7 +1856,7 @@ new function() { // Scope for intersection using bezier fat-line clipping
geomEpsilon = /*#=*/Numerical.GEOMETRIC_EPSILON, geomEpsilon = /*#=*/Numerical.GEOMETRIC_EPSILON,
straight1 = Curve.isStraight(v1), straight1 = Curve.isStraight(v1),
straight2 = Curve.isStraight(v2), straight2 = Curve.isStraight(v2),
straight = straight1 && straight2; straightBoth = straight1 && straight2;
function getLineLengthSquared(v) { function getLineLengthSquared(v) {
var x = v[6] - v[0], var x = v[6] - v[0],
@ -1864,7 +1864,6 @@ new function() { // Scope for intersection using bezier fat-line clipping
return x * x + y * y; return x * x + y * y;
} }
if (straight) {
// Linear curves can only overlap if they are collinear. Instead // Linear curves can only overlap if they are collinear. Instead
// of using the #isCollinear() check, we pick the longer of the // of using the #isCollinear() check, we pick the longer of the
// two lines and see how far the starting and end points of the // two lines and see how far the starting and end points of the
@ -1873,10 +1872,21 @@ new function() { // Scope for intersection using bezier fat-line clipping
l1 = flip ? v2 : v1, l1 = flip ? v2 : v1,
l2 = flip ? v1 : v2, l2 = flip ? v1 : v2,
line = new Line(l1[0], l1[1], l1[6], l1[7]); line = new Line(l1[0], l1[1], l1[6], l1[7]);
if (line.getDistance(new Point(l2[0], l2[1])) > geomEpsilon || if (line.getDistance(new Point(l2[0], l2[1])) < geomEpsilon &&
line.getDistance(new Point(l2[6], l2[7])) > geomEpsilon) line.getDistance(new Point(l2[6], l2[7])) < geomEpsilon) {
if (!straightBoth &&
line.getDistance(new Point(l1[2], l1[3])) < geomEpsilon &&
line.getDistance(new Point(l1[4], l1[5])) < geomEpsilon &&
line.getDistance(new Point(l2[2], l2[3])) < geomEpsilon &&
line.getDistance(new Point(l2[4], l2[5])) < geomEpsilon) {
straight1 = straight2 = straightBoth = true;
}
} else if (straightBoth) {
// If both curves are straight and not within geometric epsilon
// of each other, there can't be a solution.
return null; return null;
} else if (straight1 ^ straight2) { }
if (straight1 ^ straight2) {
// If one curve is straight, the other curve must be straight, // If one curve is straight, the other curve must be straight,
// too, otherwise they cannot overlap. // too, otherwise they cannot overlap.
return null; return null;
@ -1908,7 +1918,7 @@ new function() { // Scope for intersection using bezier fat-line clipping
} }
if (pairs.length !== 2) { if (pairs.length !== 2) {
pairs = null; pairs = null;
} else if (!straight) { } else if (!straightBoth) {
// Straight pairs don't need further checks. If we found // Straight pairs don't need further checks. If we found
// 2 pairs, the end points on v1 & v2 should be the same. // 2 pairs, the end points on v1 & v2 should be the same.
var o1 = Curve.getPart(v1, pairs[0][0], pairs[1][0]), var o1 = Curve.getPart(v1, pairs[0][0], pairs[1][0]),