0

我有这个画布,你可以在上面画画,但由于我将在某个时候对整个事物使用物理库,所以我希望绘图不那么详细。我正在考虑以一定的间隔读取鼠标位置,然后画一条直线到新的鼠标位置。我已经用 setInterval 和 setTimeout 尝试过这个,但它从来没有做任何接近我想看到的事情。有人对我如何做到这一点有任何建议吗?

谢谢!

4

1 回答 1

1

这是 Douglas-Peucker 路径简化的 javascript 实现。

http://mourner.github.io/simplify-js/

(请参阅下面的 simple.js 的完整代码。)

您也可以考虑使用曲线而不是直线来减少点(路径平滑)

平滑路径是一项经常考虑的任务:

Douglas Alan Schepers(来自 w3c):

http://schepers.cc/getting-to-the-point

Spiro 库(用于 Inkscape 等):

http://www.levien.com/spiro/

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));
于 2013-08-24T15:53:34.363 回答