From 01e48b3322dd0da97556a998615c794b68ceec16 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrg=20Lehni?= <juerg@scratchdisk.com>
Date: Thu, 13 Jun 2013 15:53:28 -0700
Subject: [PATCH] Improve and clean up fat-line bug fix.

---
 fatline/intersectTests.js |  2 +-
 src/options.js            |  2 +-
 src/path/Curve.js         | 37 ++++++++++++++++++-------------------
 src/path/CurveLocation.js | 24 ++++++++++--------------
 src/util/Numerical.js     |  1 -
 5 files changed, 30 insertions(+), 36 deletions(-)

diff --git a/fatline/intersectTests.js b/fatline/intersectTests.js
index 749fdd65..1b019e36 100644
--- a/fatline/intersectTests.js
+++ b/fatline/intersectTests.js
@@ -485,7 +485,7 @@ function testIntersections(path1, path2, caption, testname, testdata, nomark) {
 			fatTime: t2,
 			success: success
 		});
-		console.log(found);
+		console.log(ixsPaper.length, found);
 		if (!success) {
 			var ser = new XMLSerializer();
 			console.log('failcase:', ser.serializeToString(path1.exportSVG()),
diff --git a/src/options.js b/src/options.js
index 20d1e802..30c88de4 100644
--- a/src/options.js
+++ b/src/options.js
@@ -19,6 +19,6 @@ var options = {
 	browser: true,
 	stats: true,
 	svg: true,
-	fatline: false,
+	fatline: true,
 	debug: false
 };
diff --git a/src/path/Curve.js b/src/path/Curve.js
index de88490d..4875da57 100644
--- a/src/path/Curve.js
+++ b/src/path/Curve.js
@@ -869,7 +869,7 @@ statics: {
 				step /= 2;
 		}
 		var pt = Curve.evaluate(values, minT, true, 0);
-		return new CurveLocation(this, minT, pt, null, null,
+		return new CurveLocation(this, minT, pt, null, null, null,
 				point.getDistance(pt));
 	},
 
@@ -966,7 +966,7 @@ new function() { // Scope for methods that require numerical integration
 				a = 0;
 			if (b === undefined)
 				b = 1;
-			// if (p1 == c1 && p2 == c2):
+			// See if the curve is linear by checking p1 == c1 and p2 == c2
 			if (v[0] == v[2] && v[1] == v[3] && v[6] == v[4] && v[7] == v[5]) {
 				// Straight line
 				var dx = v[6] - v[0], // p2x - p1x
@@ -1030,13 +1030,14 @@ new function() { // Scope for methods that require numerical integration
 		}
 	};
 }, new function() { // Scope for intersection using bezier fat-line clipping
-	function addLocation(locations, curve1, t1, point, curve2, t2) {
+	function addLocation(locations, curve1, t1, point1, curve2, t2, point2) {
 		// Avoid duplicates when hitting segments (closed paths too)
 		var first = locations[0],
 			last = locations[locations.length - 1];
-		if ((!first || !point.equals(first._point))
-				&& (!last || !point.equals(last._point)))
-			locations.push(new CurveLocation(curve1, t1, point, curve2, t2));
+		if ((!first || !point1.equals(first._point))
+				&& (!last || !point1.equals(last._point)))
+			locations.push(
+					new CurveLocation(curve1, t1, point1, curve2, t2, point2));
 	}
 
 	function addCurveIntersections(v1, v2, curve1, curve2, locations,
@@ -1065,9 +1066,7 @@ new function() { // Scope for methods that require numerical integration
 		// degenerate case seperately, where fat-line clipping can become
 		// numerically unstable when one of the curves has converged to a point
 		// and the other hasn't.
-		while (iteration++ < 20
-				&& (Math.abs(range1[1] - range1[0]) > /*#=*/ Numerical.TOLERANCE
-				|| Math.abs(range2[1] - range2[0]) > /*#=*/ Numerical.TOLERANCE)) {
+		while (iteration++ < 20) {
 			// First we clip v2 with v1's fat-line
 			var range,
 				intersects1 = clipFatLine(part1, part2, range = range2.slice()),
@@ -1119,14 +1118,15 @@ new function() { // Scope for methods that require numerical integration
 				}
 			}
 			// We need to bailout of clipping and try a numerically stable
-			// method if both of the parameter ranges have converged reasonably well
-			//     (according to Numerical.TOLERANCE).
-			if (Math.abs(range1[1] - range1[0]) < /*#=*/ Numerical.TOLERANCE &&
-				Math.abs(range2[1] - range2[0]) < /*#=*/ Numerical.TOLERANCE) {
+			// method if both of the parameter ranges have converged reasonably
+			// well (according to Numerical.TOLERANCE).
+			if (Math.abs(range1[1] - range1[0]) <= /*#=*/ Numerical.TOLERANCE &&
+				Math.abs(range2[1] - range2[0]) <= /*#=*/ Numerical.TOLERANCE) {
 				var t1 = (range1[0] + range1[1]) / 2,
 					t2 = (range2[0] + range2[1]) / 2;
-				addLocation(locations, curve1, t1,
-						Curve.evaluate(v1, t1, true, 0), curve2, t2);
+				addLocation(locations,
+						curve1, t1, Curve.evaluate(v1, t1, true, 0),
+						curve2, t2, Curve.evaluate(v2, t2, true, 0));
 				break;
 			}
 		}
@@ -1330,10 +1330,9 @@ new function() { // Scope for methods that require numerical integration
 	 * line is on the X axis, and solve the implicit equations for the X axis
 	 * and the curve.
 	 */
-	function addCurveLineIntersections(v1, v2, curve1, curve2, locations, flip) {
-		if (flip === undefined)
-			flip = Curve.isLinear(v1);
-		var vc = flip ? v2 : v1,
+	function addCurveLineIntersections(v1, v2, curve1, curve2, locations) {
+		var flip = Curve.isLinear(v1),
+			vc = flip ? v2 : v1,
 			vl = flip ? v1 : v2,
 			l1x = vl[0], l1y = vl[1],
 			l2x = vl[6], l2y = vl[7],
diff --git a/src/path/CurveLocation.js b/src/path/CurveLocation.js
index 67bfe74c..c93290c2 100644
--- a/src/path/CurveLocation.js
+++ b/src/path/CurveLocation.js
@@ -36,8 +36,8 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
 	 * @param {Number} parameter
 	 * @param {Point} point
 	 */
-	initialize: function CurveLocation(curve, parameter, point, _otherCurve,
-			_otherParameter, _distance) {
+	initialize: function CurveLocation(curve, parameter, point, _curve2,
+			_parameter2, _point2, _distance) {
 		// Define this CurveLocation's unique id.
 		this._id = CurveLocation._id = (CurveLocation._id || 0) + 1;
 		this._curve = curve;
@@ -48,8 +48,9 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
 		this._segment2 = curve._segment2;
 		this._parameter = parameter;
 		this._point = point;
-		this._otherCurve = _otherCurve;
-		this._otherParameter = _otherParameter;
+		this._curve2 = _curve2;
+		this._parameter2 = _parameter2;
+		this._point2 = _point2;
 		this._distance = _distance;
 	},
 
@@ -110,17 +111,12 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
 	 */
 	getIntersection: function() {
 		var intersection = this._intersection;
-		if (!intersection && this._otherCurve) {
-			var param = this._otherParameter;
+		if (!intersection && this._curve2) {
+			var param = this._parameter2;
 			// If we have the parameter on the other curve use that for
 			// intersection rather than the point.
 			this._intersection = intersection = new CurveLocation(
-					this._otherCurve, param, param ? null : this._point, this);
-			// Force calculate the other point from the parameter.
-			// DEBUG: @jlehni - Not sure why we have to do this? Shouldn't
-			// it auto-calculate upon first access?!
-			if (param)
-				intersection.getPoint();
+					this._curve2, param, this._point2 || this._point, this);
 			intersection._intersection = this;
 		}
 		return intersection;
@@ -197,8 +193,8 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
 	 * @type Point
 	 * @bean
 	 */
-	getPoint: function() {
-		if (!this._point && this._parameter != null) {
+	getPoint: function(/* uncached */) {
+		if ((!this._point || arguments[0]) && this._parameter != null) {
 			var curve = this.getCurve();
 			this._point = curve && curve.getPointAt(this._parameter, true);
 		}
diff --git a/src/util/Numerical.js b/src/util/Numerical.js
index db04302a..11e25a36 100644
--- a/src/util/Numerical.js
+++ b/src/util/Numerical.js
@@ -61,7 +61,6 @@ var Numerical = new function() {
 	return {
 		TOLERANCE: 10e-6,
 		// Precision when comparing against 0
-		// TODO: Find a good value
 		EPSILON: 10e-12,
 		// Kappa, see: http://www.whizkidtech.redprince.net/bezier/circle/kappa/
 		KAPPA: 4 * (sqrt(2) - 1) / 3,