mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2024-12-29 09:22:22 -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));
|
||||
},
|
||||
|
||||
_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();
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue