mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-01 02:38:43 -05:00
Implement simpler strategy to iteratively find nearest points on paths.
Based on method described on http://pomax.github.io/bezierinfo/
This commit is contained in:
parent
fa34ea5e5b
commit
f2cd893f45
3 changed files with 132 additions and 0 deletions
76
examples/Scripts/NearestPoint.html
Normal file
76
examples/Scripts/NearestPoint.html
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
<title>NearestPoint</title>
|
||||||
|
<link rel="stylesheet" href="../css/style.css">
|
||||||
|
<script type="text/javascript" src="../../dist/paper.js"></script>
|
||||||
|
<script type="text/paperscript" canvas="canvas">
|
||||||
|
window.performance = window.performance || {};
|
||||||
|
performance.now = (function() {
|
||||||
|
return performance.now ||
|
||||||
|
performance.mozNow ||
|
||||||
|
performance.msNow ||
|
||||||
|
performance.oNow ||
|
||||||
|
performance.webkitNow ||
|
||||||
|
function() { return new Date().getTime(); };
|
||||||
|
})();
|
||||||
|
|
||||||
|
var path = project.importSVG(document.getElementById('svg')).firstChild,
|
||||||
|
total = 0,
|
||||||
|
slower = 0;
|
||||||
|
|
||||||
|
function getNearest(point) {
|
||||||
|
var t1 = performance.now();
|
||||||
|
var loc1 = path.getNearestLocation(point);
|
||||||
|
t1 = performance.now() - t1;
|
||||||
|
var t2 = performance.now();
|
||||||
|
var loc2 = path._getNearestLocation(point);
|
||||||
|
t2 = performance.now() - t2;
|
||||||
|
total++;
|
||||||
|
if (t2 > t1) {
|
||||||
|
slower++;
|
||||||
|
console.log('slower', slower / total, t1, t2, point)
|
||||||
|
}
|
||||||
|
if (loc2.distance > loc1.distance) {
|
||||||
|
console.log('not precise');
|
||||||
|
}
|
||||||
|
return [loc1.point, loc2.point];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < 1000; i++) {
|
||||||
|
getNearest(new Point(1028, 286));
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
|
||||||
|
function onMouseMove(event) {
|
||||||
|
var res = getNearest(event.point);
|
||||||
|
console.log(res.join());
|
||||||
|
var circle = new Path.Circle({
|
||||||
|
center: res[0],
|
||||||
|
radius: 2,
|
||||||
|
strokeColor: 'red'
|
||||||
|
}).removeOnMove();
|
||||||
|
var line = new Path.Line({
|
||||||
|
from: res[0],
|
||||||
|
to: event.point,
|
||||||
|
strokeColor: 'red'
|
||||||
|
}).removeOnMove();
|
||||||
|
var circle = new Path.Circle({
|
||||||
|
center: res[1],
|
||||||
|
radius: 4,
|
||||||
|
strokeColor: 'green'
|
||||||
|
}).removeOnMove();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<canvas id="canvas" resize></canvas>
|
||||||
|
<svg id="svg" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" xml:space="preserve" style="display: none;">
|
||||||
|
<path fill="none" stroke="#000000" stroke-miterlimit="10" d="M167,265c33.321,23.568,53,38,72.886,109.353
|
||||||
|
c22.516,80.792-52.284,163.541-74.631,92.135C95,242,393.045,246.871,399.326,431.434C402,510,286.311,474.239,289,369
|
||||||
|
c1.961-76.747,78.663-125.069,162.393-91.026C540,314,562.299,442.872,476.159,390.783C424.547,359.573,382.365,317.41,383,221"/>
|
||||||
|
</svg>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1246,6 +1246,48 @@ new function() { // Scope for methods that require numerical integration
|
||||||
Math.sqrt(minDist));
|
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) {
|
getNearestPoint: function(point) {
|
||||||
return this.getNearestLocation(point).getPoint();
|
return this.getNearestLocation(point).getPoint();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1552,6 +1552,20 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
|
||||||
return minLoc;
|
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.
|
* Returns the nearest point on the path to the specified point.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in a new issue