在javascript中简化SVG路径

3df52oht  于 2023-02-02  发布在  Java
关注(0)|答案(2)|浏览(133)

有人知道优化SVG路径的js库/算法吗?我只需要优化路径(减少节点数量)。我的路径是自动生成的,充满了bezier,所以类似问题中提到的simplify.js不适合。我还需要使用浏览器,所以节点支持的模块也不适合。
最完美的优化是由Inkscape完成的,但我不想将1000多行路径优化代码从C++移植到JS。
我在找这样的东西:http://paperjs.org/examples/path-simplification/

sqserrrh

sqserrrh1#

最后用了paperjs,可惜他们还不支持模块化构建

n6lpvg4x

n6lpvg4x2#

我几年前从simplify.js中为我的目的找到了这个

// square distance between 2 points
function getSqDist(p1, p2) {
  var dx = p1.x - p2.x,
    dy = p1.y - p2.y;

  return dx * dx + dy * dy;
}

// square distance from a point to a segment
function getSqSegDist(p, p1, p2) {
  var x = p1.x,
    y = p1.y,
    dx = p2.x - x,
    dy = p2.y - y;

  if (dx !== 0 || dy !== 0) {
    var t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy);

    if (t > 1) {
      x = p2.x;
      y = p2.y;
    } else if (t > 0) {
      x += dx * t;
      y += dy * t;
    }
  }

  dx = p.x - x;
  dy = p.y - y;

  return dx * dx + dy * dy;
}

// rest of the code doesn't care about point format

// basic distance-based simplification
function simplifyRadialDist(points, sqTolerance) {
  var prevPoint = points[0],
    newPoints = [prevPoint],
    point;

  for (var i = 1, len = points.length; i < len; i++) {
    point = points[i];

    if (getSqDist(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,
    stack = [],
    newPoints = [],
    i,
    maxSqDist,
    sqDist,
    index;

  markers[first] = markers[last] = 1;

  while (last) {
    maxSqDist = 0;

    for (i = first + 1; i < last; i++) {
      sqDist = getSqSegDist(points[i], points[first], points[last]);

      if (sqDist > maxSqDist) {
        index = i;
        maxSqDist = sqDist;
      }
    }

    if (maxSqDist > sqTolerance) {
      markers[index] = 1;
      stack.push(first, index, index, last);
    }

    last = stack.pop();
    first = stack.pop();
  }

  for (i = 0; i < len; i++) {
    if (markers[i]) newPoints.push(points[i]);
  }

  return newPoints;
}

// both algorithms combined for awesome performance
export function simplify(points, tolerance, highestQuality) {
  if (points.length <= 1) return points;

  var sqTolerance = tolerance !== undefined ? tolerance * tolerance : 1;

  points = highestQuality ? points : simplifyRadialDist(points, sqTolerance);
  points = simplifyDouglasPeucker(points, sqTolerance);

  return points;
}

用法:

const points = [{x:10, y:20}, {x:15, y:23}, ...];
const simplifiedPoints = simplify(points)

相关问题