4

JS Clipperを使用して、SVG パス (2 次と 3 次の両方のベジエを含む) でブール演算を実行しようとしています。

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;

}
4

2 に答える 2

6

ある種の svg パスからポリゴンへの変換を意味していると思います。

私はたくさん検索しましたが、信頼できるすぐに使えるソリューションは見つかりませんでした。

SVG パスは、相対座標と絶対座標の両方を考慮すると、10 個の異なるセグメント、または 20 個の異なるセグメントで構成できます。これらは、path 要素の d 属性で文字として表されます。相対のものはmhvlcqastzであり、絶対のものはMHVLCQASTZです。それぞれに異なる属性があり、a(楕円弧) が最も複雑です。これらの例が示すように、他のすべての型をかなり高い精度で表すことができるため、最も使いやすく柔軟な型はc(3 次ベジエ曲線)ですoqojan/42 .

Raphael JS ライブラリにはPath2Curve、すべてのパス セグメントを 3 次曲線に変換できる関数があり、複雑な円弧から 3 次変換も処理できます。残念ながら、これにはバグがあり、考えられるすべてのパス セグメントの組み合わせを処理することはできませんが、幸いなことに、修正されたバージョンのライブラリが利用可能です: http://jsbin.com/oqojan/32/edit (Javascript ウィンドウを見てください)。

すべてのパス セグメントが 3 次曲線に変換されると、個々の線分に変換できます。いくつかの方法がありますが、最良の方法は適応型の再帰的細分化方法であると思われます。これは、曲線の忠実度と少ないセグメント数のバランスをとって、レンダリング速度を最大化するために、曲線の急な曲がり角でより多くの線セグメントを生成し、曲線の他の部分ではより少ない線セグメントを生成します。 、残念ながら、すべての同一線上のケースを処理できませんでした。私は、AntiGrain のメソッドを Javascript に変換することに成功し、事前分割機能を追加しました。これは、曲線を局所的な極値 (一次微分根) で分割します。その後、AntiGrain メソッドは、考えられるすべての共線ケースも処理します。

コリニア水平: http://jsbin.com/ivomiq/6
異なるケースのセット: http://jsbin.com/ivomiq/7
ランダム: http://jsbin.com/ivomiq/8
コリニア回転: http:// jsbin.com/ivomiq/9

上記のすべてのサンプルには、適応アルゴリズムで発生する可能性のあるエラーを示すために、2 つのパスが重なり合っています。赤い曲線は非常に遅い力ずく法を使用して分割され、緑の曲線は AntiGrain メソッドを使用して分割されています。赤がまったく表示されない場合、AntiGrain のメソッドapproximate()-functionは期待どおりに機能しています。

OK、Raphael の修復と AntiGrain の修復が完了しました。これらの両方の方法を組み合わせると、任意の svg パス要素をポリゴン (単一または複数のサブポリゴン) に変換する関数を作成できます。これが最良または最速の方法であると 100% 確信しているわけではありませんが、使用できるはずです。もちろん、ネイティブブラウザの実装が最適です...

于 2013-04-08T22:52:20.317 に答える
0

De Casteljauのアルゴリズムを使用bezier curveして、より小さな直線に分割し、それらを結合してを作成できますpolygon

ここにいくつかの参照がありますDe Casteljau's algorithm

于 2013-03-09T20:03:10.643 に答える