我有这个画布,你可以在上面画画,但由于我将在某个时候对整个事物使用物理库,所以我希望绘图不那么详细。我正在考虑以一定的间隔读取鼠标位置,然后画一条直线到新的鼠标位置。我已经用 setInterval 和 setTimeout 尝试过这个,但它从来没有做任何接近我想看到的事情。有人对我如何做到这一点有任何建议吗?
谢谢!
我有这个画布,你可以在上面画画,但由于我将在某个时候对整个事物使用物理库,所以我希望绘图不那么详细。我正在考虑以一定的间隔读取鼠标位置,然后画一条直线到新的鼠标位置。我已经用 setInterval 和 setTimeout 尝试过这个,但它从来没有做任何接近我想看到的事情。有人对我如何做到这一点有任何建议吗?
谢谢!
这是 Douglas-Peucker 路径简化的 javascript 实现。
http://mourner.github.io/simplify-js/
(请参阅下面的 simple.js 的完整代码。)
您也可以考虑使用曲线而不是直线来减少点(路径平滑)
平滑路径是一项经常考虑的任务:
Douglas Alan Schepers(来自 w3c):
http://schepers.cc/getting-to-the-point
Spiro 库(用于 Inkscape 等):
Ken Fyrstenberg Nilsen(SO 的常客):
http://www.codeproject.com/Tips/562175/Draw-Smooth-Lines-on-HTML5-Canvas
Paper.js 具有平滑和简化路径的方法:
http://paperjs.org/tutorials/paths/smoothing-simplifying-flattening/
Simplify.js 的代码(BSD 许可证位于http://mourner.github.io/simplify-js/):
(function (global, undefined) {
// to suit your point format, run search/replace for '.x' and '.y';
// to switch to 3D, uncomment the lines in the next 2 functions
// (configurability would draw significant performance overhead)
function getSquareDistance(p1, p2) { // square distance between 2 points
var dx = p1.x - p2.x,
// dz = p1.z - p2.z,
dy = p1.y - p2.y;
return dx * dx +
// dz * dz +
dy * dy;
}
function getSquareSegmentDistance(p, p1, p2) { // square distance from a point to a segment
var x = p1.x,
y = p1.y,
// z = p1.z,
dx = p2.x - x,
dy = p2.y - y,
// dz = p2.z - z,
t;
if (dx !== 0 || dy !== 0) {
t = ((p.x - x) * dx +
// (p.z - z) * dz +
(p.y - y) * dy) /
(dx * dx +
// dz * dz +
dy * dy);
if (t > 1) {
x = p2.x;
y = p2.y;
// z = p2.z;
} else if (t > 0) {
x += dx * t;
y += dy * t;
// z += dz * t;
}
}
dx = p.x - x;
dy = p.y - y;
// dz = p.z - z;
return dx * dx +
// dz * dz +
dy * dy;
}
// the rest of the code doesn't care for the point format
// basic distance-based simplification
function simplifyRadialDistance(points, sqTolerance) {
var i,
len = points.length,
point,
prevPoint = points[0],
newPoints = [prevPoint];
for (i = 1; i < len; i++) {
point = points[i];
if (getSquareDistance(point, prevPoint) > sqTolerance) {
newPoints.push(point);
prevPoint = point;
}
}
if (prevPoint !== point) {
newPoints.push(point);
}
return newPoints;
}
// simplification using optimized Douglas-Peucker algorithm with recursion elimination
function simplifyDouglasPeucker(points, sqTolerance) {
var len = points.length,
MarkerArray = (typeof Uint8Array !== undefined + '')
? Uint8Array
: Array,
markers = new MarkerArray(len),
first = 0,
last = len - 1,
i,
maxSqDist,
sqDist,
index,
firstStack = [],
lastStack = [],
newPoints = [];
markers[first] = markers[last] = 1;
while (last) {
maxSqDist = 0;
for (i = first + 1; i < last; i++) {
sqDist = getSquareSegmentDistance(points[i], points[first], points[last]);
if (sqDist > maxSqDist) {
index = i;
maxSqDist = sqDist;
}
}
if (maxSqDist > sqTolerance) {
markers[index] = 1;
firstStack.push(first);
lastStack.push(index);
firstStack.push(index);
lastStack.push(last);
}
first = firstStack.pop();
last = lastStack.pop();
}
for (i = 0; i < len; i++) {
if (markers[i]) {
newPoints.push(points[i]);
}
}
return newPoints;
}
// both algorithms combined for awesome performance
function simplify(points, tolerance, highestQuality) {
var sqTolerance = tolerance !== undefined ? tolerance * tolerance : 1;
points = highestQuality ? points : simplifyRadialDistance(points, sqTolerance);
points = simplifyDouglasPeucker(points, sqTolerance);
return points;
};
// export either as a Node.js module, AMD module or a global browser variable
if (typeof exports === 'object') {
module.exports = simplify;
} else if (typeof define === 'function' && define.amd) {
define(function () {
return simplify;
});
} else {
global.simplify = simplify;
}
}(this));