Implement better calculation of tangential angles in CurveLocation#isCrossing()

Relates to #1074
This commit is contained in:
Jürg Lehni 2016-06-12 18:53:14 +02:00
parent 5854c25dd5
commit 4966f6250f
2 changed files with 20 additions and 16 deletions

View file

@ -448,22 +448,27 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
: angle > min || angle < max;
}
// Calculate angles for all four tangents at the intersection point,
// using values for getTangentAt() that are almost 0 and 1.
// NOTE: Even though getTangentAt() has code to support 0 and 1 instead
// of tMin and tMax, we still need to use tMin / tMaxx instead, as other
// issues emerge from switching to 0 and 1 in edge cases.
// NOTE: VectorBoolean has code that slowly shifts these points inwards
// Calculate angles for all four tangents at the intersection point.
// If the intersection is on an actual segment, step away from it at
// equal offsets on each curve, to calculate tangential angles that are
// unambiguous. The offset is determined by taking 1/64th of the length
// of the shortest of all involved curves. This appears to work well.
// NOTE: VectorBoolean has code that slowly shifts these offsets inwards
// until the resulting tangents are not ambiguous. Do we need this too?
// NOTE: We handle t*Inside here simply by picking t1 / t2 instead of
// tMin / tMax. E.g. if t1Inside is true, c1 will be the same as c2,
// and the code will doe the right thing.
// NOTE: We handle t1 / t2Inside here by getting the tangent at t1 / t2
// instead of at this calculated offset.
// The incomings tangents v1 & v3 are inverted, so that all angles
// are pointing outwards in the right direction from the intersection.
var v2 = c2.getTangentAtTime(t1Inside ? t1 : tMin),
v1 = (t1Inside ? v2 : c1.getTangentAtTime(tMax)).negate(),
v4 = c4.getTangentAtTime(t2Inside ? t2 : tMin),
v3 = (t2Inside ? v4 : c3.getTangentAtTime(tMax)).negate(),
var lenghts = [];
if (!t1Inside)
lenghts.push(c1.getLength(), c2.getLength());
if (!t2Inside)
lenghts.push(c3.getLength(), c4.getLength());
var offset = Math.min.apply(null, lenghts) / 64;
var v2 = t1Inside ? c2.getTangentAtTime(t1) : c2.getTangentAt(offset),
v1 = (t1Inside ? v2 : c1.getTangentAt(-offset)).negate(),
v4 = t2Inside ? c4.getTangentAtTime(t2) : c4.getTangentAt(offset),
v3 = (t2Inside ? v4 : c3.getTangentAt(-offset)).negate(),
// NOTE: For shorter API calls we work with angles in degrees here:
a1 = v1.getAngle(),
a2 = v2.getAngle(),

View file

@ -147,9 +147,8 @@ test('#1066', function() {
test('#1074', function() {
var path1 = new Path('M349.98644,0c-192.98072,0 -349.98644,157.00255 -349.98644,349.98327c0,35.02687 28.39313,63.42 63.42,63.42c35.02687,0 63.42,-28.39313 63.42,-63.42c0,-123.04114 100.10213,-223.14327 223.14644,-223.14327c35.02687,0 63.42,-28.39313 63.42,-63.42c0,-35.02687 -28.39313,-63.42 -63.42,-63.42z');
var path2 = new Path('M349.98644,0c-35.02687,0 -63.42,28.39313 -63.42,63.42c0,35.02687 28.39313,63.42 63.42,63.42c59.25965,0 118.69687,22.57118 158.98443,60.37584c25.54558,23.97593 65.67775,22.6885 89.64417,-2.84756c23.96959,-25.5424 22.69168,-65.67775 -2.84756,-89.64417c-63.21071,-59.31355 -155.09044,-94.72411 -245.78104,-94.72411z');
var inters = path1.getIntersections(path2);
testIntersection(path1.getIntersections(path2), [
{ point: { x: 349.98644, y: 0 }, index: 0, time: 0 },
{ point: { x: 349.98644, y: 126.84 } , index: 4, time: 0 }
{ point: { x: 349.98644, y: 0 }, index: 0, time: 0, crossing: true },
{ point: { x: 349.98644, y: 126.84 } , index: 4, time: 0, crossing: true }
]);
});