【问题标题】:Convert an SVG-path to polygons for use within Javascript Clipper将 SVG 路径转换为多边形以在 Javascript Clipper 中使用
【发布时间】:2013-02-21 06:22:14
【问题描述】:

我正在尝试使用 JS Clipper 对 SVG 路径(包含贝塞尔曲线,二次和三次)执行布尔运算。

JS Clipper 从多边形开始,然后执行操作,然后似乎将它们转换回 SVG 路径。

下面的函数给出了一个 SVG 路径,但下面的示例以 2 个多边形开头。

一个示例函数:

// Polygon Arrays are expanded for better readability

function clip() {
  var subj_polygons = [
    [{
      X: 10,
      Y: 10
    }, {
      X: 110,
      Y: 10
    }, {
      X: 110,
      Y: 110
    }, {
      X: 10,
      Y: 110
    }],
    [{
      X: 20,
      Y: 20
    }, {
      X: 20,
      Y: 100
    }, {
      X: 100,
      Y: 100
    }, {
      X: 100,
      Y: 20
    }]
  ];

  var clip_polygons = [
    [{
      X: 50,
      Y: 50
    }, {
      X: 150,
      Y: 50
    }, {
      X: 150,
      Y: 150
    }, {
      X: 50,
      Y: 150
    }],
    [{
      X: 60,
      Y: 60
    }, {
      X: 60,
      Y: 140
    }, {
      X: 140,
      Y: 140
    }, {
      X: 140,
      Y: 60
    }]
  ];

  var scale = 100;
  subj_polygons = scaleup(subj_polygons, scale);
  clip_polygons = scaleup(clip_polygons, scale);

  var cpr = new ClipperLib.Clipper();
  cpr.AddPolygons(subj_polygons, ClipperLib.PolyType.ptSubject);
  cpr.AddPolygons(clip_polygons, ClipperLib.PolyType.ptClip);

  var subject_fillType = ClipperLib.PolyFillType.pftNonZero;
  var clip_fillType = ClipperLib.PolyFillType.pftNonZero;
  var clipTypes = [ClipperLib.ClipType.ctUnion];
  var clipTypesTexts = "Union";
  var solution_polygons, svg, cont = document.getElementById('svgcontainer');

  var i;
  for (i = 0; i < clipTypes.length; i++) {
    solution_polygons = new ClipperLib.Polygons();
    cpr.Execute(clipTypes[i], solution_polygons, subject_fillType, clip_fillType);
    console.log(polys2path(solution_polygons, scale));
  }

}

// helper function to scale up polygon coordinates
function scaleup(poly, scale) {
  var i, j;
  if (!scale) scale = 1;
  for (i = 0; i < poly.length; i++) {
    for (j = 0; j < poly[i].length; j++) {
      poly[i][j].X *= scale;
      poly[i][j].Y *= scale;
    }
  }
  return poly;
}

// converts polygons to SVG path string
function polys2path(poly, scale) {
  var path = "",
    i, j;
  if (!scale) scale = 1;
  for (i = 0; i < poly.length; i++) {
    for (j = 0; j < poly[i].length; j++) {
      if (!j) path += "M";
      else path += "L";
      path += (poly[i][j].X / scale) + ", " + (poly[i][j].Y / scale);
    }
    path += "Z";
  }
  return path;

}

【问题讨论】:

    标签: javascript svg


    【解决方案1】:

    我假设您的意思是某种 svg 路径到多边形转换。

    我搜索了很多,但没有找到任何可靠且开箱即用的解决方案。

    SVG 路径可以由十个不同的段组成,如果我们同时考虑相对坐标和绝对坐标,则为 20 个。它们在路径元素的 d 属性中表示为字母:相对的为mhvlcqastz,绝对的为MHVLCQASTZ。每个都有不同的属性,a(椭圆弧)是最复杂的一个。最有用和最灵活的类型是c(三次贝塞尔曲线),因为它可以以相当高的精度表示所有其他类型,如以下示例所示:http://jsbin.com/oqojan/32http://jsbin.com/oqojan/42

    Raphael JS 库具有Path2Curve-函数,可以将所有路径段转换为三次曲线,它还可以处理复杂的弧到三次转换。不幸的是它有一个错误,因此它无法处理所有可能的路径段组合,但幸运的是有一个固定版本的库可用:http://jsbin.com/oqojan/32/edit(查看 Javascript 窗口)。

    当所有路径段都转换为三次曲线时,它们可以转换为单独的线段。方法很少,最好的似乎是an adaptive recursive subdivision method,它在曲线的急转弯处产生更多的线段,而在曲线的其他部分产生更少的线段,以实现曲线保真度和低段数的平衡,以最大限度地提高渲染速度,但是不幸的是,它不能处理所有共线的情况。我成功地将 AntiGrain 的方法转换为 Javascript 并添加了预分割功能,它在局部极值(一阶导数根)中分割曲线,之后 AntiGrain 方法还处理所有可能的共线情况:

    水平共线:http://jsbin.com/ivomiq/6
    不同案例集:http://jsbin.com/ivomiq/7
    随机:http://jsbin.com/ivomiq/8
    共线旋转:http://jsbin.com/ivomiq/9

    以上所有样本都有两条相互重叠的路径,以显示自适应算法中可能存在的错误:红色曲线使用非常慢的蛮力方法分割,绿色曲线使用 AntiGrain 方法分割。如果您根本看不到红色,则表明 AntiGrain 的方法 approximate()-function 正在按预期工作。

    好的,现在我们已经修复了 Raphael 并修复了 AntiGrain。如果我们结合这两种方法,我们可以创建一个函数,将任何 svg 路径元素转换为多边形(单个或多个子多边形)。我不能 100% 确定这是最好或最快的方法,但它应该是可用的。当然最好的是原生浏览器实现......

    【讨论】:

    • 无论多么复杂,这个解决方案都适用于任何形状吗?由于多边形转换的路径,我已经放弃尝试使用您的库。我确实设法使用 Phrogz 的这种方法:gist.github.com/Phrogz/845901 转换为只有一个大问题的多边形。我的用户应该绘制非常非常复杂的曲线形状,必须对其进行布尔运算,而不会损失任何曲线的保真度。这需要超过 800 次多边形化所需的采样,这在大多数情况下甚至无法使用 Phrogz 解决方案。您认为 Raphael+AG 会更好吗?
    • 我的解决方案仅适用于 svg-paths,因此您需要先将其他形状转换为路径(请参阅:github.com/johan/svg-js-utils/blob/master/paths.js,pathify() -function)。我认为使用我建议的解决方案转换质量非常好(因为您可以使用角度阈值和整体缩放参数调整精度)。我还测试了 Phrogz 的解决方案,这是典型的蛮力方法,当形状复杂并且容易产生太多或太少的点时,它会很慢。 Antigrain 解决方案产生最佳的点数。什么是AG?
    • 如果我看到了足够多的代码,我会尽力提供帮助。您可以使用 timo.roskapostiREMOVETHIS@hotmail.com 与我联系。也许更好的是我们通过电子邮件继续讨论,当找到解决方案时,在此处发布所需的步骤或功能。
    • 我猜这是一个打字错误(形状表示路径)。我的意思是我的用户应该绘制非常复杂的曲线路径而不是形状。关于 Phrogz 蛮力,它确实非常缓慢。
    • 我刚刚给您发了一封电子邮件,我使用了正确的地址吗??
    【解决方案2】:

    您可以使用De Casteljau's algorithmbezier curve 分解成更小的直线,然后将它们连接起来以创建polygon

    这里是De Casteljau's algorithm的一些参考

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-21
      • 2012-11-07
      • 2015-03-06
      • 1970-01-01
      • 1970-01-01
      • 2021-06-04
      • 1970-01-01
      相关资源
      最近更新 更多