From f2cd893f45fceacdcc0ccbef70c227ab3db9bbda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Sun, 5 May 2013 22:41:06 -0700 Subject: [PATCH] Implement simpler strategy to iteratively find nearest points on paths. Based on method described on http://pomax.github.io/bezierinfo/ --- examples/Scripts/NearestPoint.html | 76 ++++++++++++++++++++++++++++++ src/path/Curve.js | 42 +++++++++++++++++ src/path/Path.js | 14 ++++++ 3 files changed, 132 insertions(+) create mode 100644 examples/Scripts/NearestPoint.html diff --git a/examples/Scripts/NearestPoint.html b/examples/Scripts/NearestPoint.html new file mode 100644 index 00000000..33a3d3aa --- /dev/null +++ b/examples/Scripts/NearestPoint.html @@ -0,0 +1,76 @@ + + + + + NearestPoint + + + + + + + + + \ No newline at end of file diff --git a/src/path/Curve.js b/src/path/Curve.js index dff14f4d..570e12c9 100644 --- a/src/path/Curve.js +++ b/src/path/Curve.js @@ -1246,6 +1246,48 @@ new function() { // Scope for methods that require numerical integration Math.sqrt(minDist)); }, + _getNearestLocation: function(point) { + var values = this.getValues(), + step = 1 / 100, + minDist = Infinity, + minT = 0; + + for (var t = 0; t <= 1; t += step) { + var pt = Curve.evaluate(values, t, true, 0), + dist = point.getDistance(pt, true); + if (dist < minDist) { + minDist = dist; + minT = t; + } + } + + function refine(t, dist, precision) { + if(precision < 0.0000001) return t; + // refinement + // smaller distances? + var t1 = t - precision; + if (t1 >= 0) { + var dist1 = point.getDistance( + Curve.evaluate(values, t1, true, 0), true); + if (dist1 < dist) + return refine(t1, dist1, precision); + } + var t2 = t + precision; + if (t2 <= 1) { + var dist2 = point.getDistance( + Curve.evaluate(values, t2, true, 0), true); + if (dist2 < dist) + return refine(t2, dist2, precision); + } + // larger distances + return refine(t, dist, precision / 2); + } + + minT = refine(minT, minDist, step); + var pt = Curve.evaluate(values, minT, true, 0); + return new CurveLocation(this, minT, pt, null, point.getDistance(pt)); + }, + getNearestPoint: function(point) { return this.getNearestLocation(point).getPoint(); } diff --git a/src/path/Path.js b/src/path/Path.js index 6f8f3b85..1b29d84b 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -1552,6 +1552,20 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{ return minLoc; }, + _getNearestLocation: function(point) { + var curves = this.getCurves(), + minDist = Infinity, + minLoc = null; + for (var i = 0, l = curves.length; i < l; i++) { + var loc = curves[i]._getNearestLocation(point); + if (loc._distance < minDist) { + minDist = loc._distance; + minLoc = loc; + } + } + return minLoc; + }, + /** * Returns the nearest point on the path to the specified point. *