From 803dfb6bb1a613e22ed3a2f2a953d394015c55b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Fri, 10 Jun 2016 12:33:44 +0200 Subject: [PATCH] Improve reliability of Curve#isStraight() Closes #1066 --- src/path/Curve.js | 33 +++++++++++++++++++------------- test/tests/Path_Intersections.js | 18 +++++++++++++++++ 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/path/Curve.js b/src/path/Curve.js index f2386f62..7e2fcc48 100644 --- a/src/path/Curve.js +++ b/src/path/Curve.js @@ -881,22 +881,29 @@ statics: /** @lends Curve */{ if (h1.isZero() && h2.isZero()) { // No handles. return true; - } else if (l.isZero()) { - // Zero-length line, with some handles defined. - return false; - } else if (h1.isCollinear(l) && h2.isCollinear(l)) { - // Collinear handles. Project them onto line to see if they are - // within the line's range: - var div = l.dot(l), - p1 = l.dot(h1) / div, - p2 = l.dot(h2) / div; - return p1 >= 0 && p1 <= 1 && p2 <= 0 && p2 >= -1; + } else { + var v = l.getVector(), + epsilon = /*#=*/Numerical.GEOMETRIC_EPSILON; + if (v.isZero()) { + // Zero-length line, with some handles defined. + return false; + } else if (l.getDistance(h1) < epsilon + && l.getDistance(h2) < epsilon) { + // Collinear handles: Instead of v.isCollinear(h1) checks, we + // need to measure the distance to the line, in order to be able + // to use the same epsilon as in Curve#getTimeOf(), see #1066. + // Project them onto line to see if they are within its range: + var div = v.dot(v), + p1 = v.dot(h1) / div, + p2 = v.dot(h2) / div; + return p1 >= 0 && p1 <= 1 && p2 <= 0 && p2 >= -1; + } } return false; }, isLinear: function(l, h1, h2) { - var third = l.divide(3); + var third = l.getVector().divide(3); return h1.equals(third) && h2.negate().equals(third); } }, function(test, name) { @@ -904,7 +911,7 @@ statics: /** @lends Curve */{ this[name] = function() { var seg1 = this._segment1, seg2 = this._segment2; - return test(seg2._point.subtract(seg1._point), + return test(new Line(seg1._point, seg2._point), seg1._handleOut, seg2._handleIn); }; @@ -912,7 +919,7 @@ statics: /** @lends Curve */{ this.statics[name] = function(v) { var p1x = v[0], p1y = v[1], p2x = v[6], p2y = v[7]; - return test(new Point(p2x - p1x, p2y - p1y), + return test(new Line(p1x, p1y, p2x, p2y), new Point(v[2] - p1x, v[3] - p1y), new Point(v[4] - p2x, v[5] - p2y)); }; diff --git a/test/tests/Path_Intersections.js b/test/tests/Path_Intersections.js index c3ba5208..f3c4b783 100644 --- a/test/tests/Path_Intersections.js +++ b/test/tests/Path_Intersections.js @@ -103,3 +103,21 @@ test('circle and square (existing segments overlaps on curves)', function() { { point: { x: 110, y: 190 }, index: 3, time: 0, crossing: true } ]); }); + +test('#1066', function() { + var path1 = new paper.Path({ + segments: [ + [230.4447915660904, 300], + [230.4447915660904, 180] + ] + }); + var path2 = new paper.Path({ + segments: [ + [221.5842044289023, 189.47264666691018, 0, 0, 9.363067822501023, 28.089207003036847], + [249.67341143193917, 273.74026767602066, -9.363067822501023, -28.08920700303679, 0, 0] + ] + }); + testIntersection(path1.getIntersections(path2), [ + { point: { x: 230.44479, y: 216.05441 }, index: 0, time: 0.63642, crossing: true } + ]); +});