ポリゴンをどのように「膨張させる」のですか?つまり、私はこれに似た何かをしたいです:
要件は、新しい(膨張した)ポリゴンのエッジ/ポイントがすべて古い(元の)ポリゴンから同じ一定の距離にあることです(例の写真では、膨張した頂点に円弧を使用する必要があるため、そうではありませんが、今のところそれについて忘れてください;))。
私が探しているものの数学用語は、実際には内向き/外向きのポリゴンオフセットです。これを指摘するためにbalintに+1。代替命名法は、ポリゴンバッファリングです。
私の検索結果:
リンクは次のとおりです。
探しているポリゴンは、計算ジオメトリで内向き/外向きオフセットポリゴンと呼ばれ、 ストレートスケルトン 。
これらは、複雑なポリゴンのオフセットポリゴンです。
そして、これは別のポリゴンのまっすぐなスケルトンです:
他のコメントでも指摘されているように、ポリゴンをどれだけ「膨張/収縮」させるかによって、出力の接続性が異なる場合があります。
計算の観点から:まっすぐなスケルトンができたら、オフセットポリゴンを比較的簡単に構築できるはずです。オープンソースおよび(非商用の場合は無料) CGAL ライブラリには、これらの構造を実装するパッケージがあります。 このコード例 を参照して、CGALを使用してオフセットポリゴンを計算してください。
パッケージマニュアル は、CGALを使用しない場合でも、これらの構造を構築する方法に関する適切な出発点を提供するものであり、数学的な定義とプロパティを持つ論文への参照が含まれています。
あなたが望むものは私に聞こえます:
d
に配置された新しい平行エッジに置き換えます。結果のポリゴンは、頂点から「十分に」古いポリゴンから必要な距離にあります。頂点の近くでは、古いポリゴンからの距離d
にあるポイントのセットは、あなたが言うように、ポリゴンではないため、前述の要件を満たすことはできません。
このアルゴリズムに名前、ウェブ上のコード例、または悪意のある最適化があるかどうかはわかりませんが、あなたが望むものを説明していると思います。
これらのタイプの場合、通常 JTS を使用します。デモンストレーションのために、これを作成しました jsFiddleJSTS (JTSのJavaScriptポート)を使用します。必要な座標をJSTS座標に変換するだけです。
function vectorCoordinates2JTS (polygon) {
var coordinates = [];
for (var i = 0; i < polygon.length; i++) {
coordinates.Push(new jsts.geom.Coordinate(polygon[i].x, polygon[i].y));
}
return coordinates;
}
結果は次のようになります。
追加情報:私は通常、地図(リーフレットまたはGoogleマップを使用)。 (lat、lng)ペアをJSTS座標に変換するだけで、他はすべて同じです。例:
各線は、平面を「内側」と「輪郭」に分割する必要があります。通常の内積法を使用してこれを見つけることができます。
すべての行を一定の距離だけ外側に移動します。
隣接線のすべてのペア(線分ではなく線分)を検討し、交差点を見つけます。これらは新しい頂点です。
交差する部分を削除して、新しい頂点をクリーンアップします。 -ここにいくつかのケースがあります
(a)ケース1:
0--7 4--3
| | | |
| 6--5 |
| |
1--------2
あなたがそれを1つ使うと、あなたはこれを手に入れました:
0----a----3
| | |
| | |
| b |
| |
| |
1---------2
7と4が重なります。これが表示されたら、このポイントとその間のすべてのポイントを削除します。
(b)ケース2
0--7 4--3
| | | |
| 6--5 |
| |
1--------2
あなたが2でそれを費やすなら、あなたはこれを手に入れました:
0----47----3
| || |
| || |
| || |
| 56 |
| |
| |
| |
1----------2
これを解決するには、ラインの各セグメントについて、後者のセグメントと重複しているかどうかを確認する必要があります。
(c)ケース3
4--3
0--X9 | |
| 78 | |
| 6--5 |
| |
1--------2
これは、ケース1のより一般的なケースです。
(d)ケース4
case3と同じですが、2つ消費します。
実際、ケース4を処理できる場合、他のすべてのケースは、ラインまたは頂点がオーバーラップする特殊なケースです。
ケース4を実行するには、頂点のスタックを保持します。後の行と重複する行が見つかったらプッシュし、後の行が取得されたらポップします。 -凸包で行うことと同じです。
ここに代替ソリューションがあります。これがより良いかどうかを確認してください。
triangulation を実行します。それはdelaunayである必要はありません-どんな三角形分割でも実行できます。
各三角形を膨らませます-これは簡単なはずです。三角形を反時計回りの順序で保存する場合は、線を右側に移動して交差させます。
変更された Weiler-Athertonクリッピングアルゴリズム を使用してそれらをマージします
GISの世界では、このタスクにネガティブバッファリングを使用します。 http://www-users.cs.umn.edu/~npramod/enc_pdf.pdf
JTSライブラリ がこれを行う必要があります。バッファ操作のドキュメントを参照してください: http://tsusiatsoftware.net/jts/javadoc/com/vividsolutions/jts/operation/buffer/package-summary.html
大まかな概要については、開発者ガイドも参照してください。 http://www.vividsolutions.com/jts/bin/JTS%20Developer%20Guide.pdf
クリッパーライブラリのAngus Johnsonに感謝します。 http://www.angusj.com/delphi/clipper.php#code のクリッパーのホームページには、クリッピングを行うための優れたコードサンプルがありますが、ポリゴンオフセットの例は見当たりませんでした。だから私は自分のコードを投稿すると誰かのために役立つかもしれないと思った:
public static List<Point> GetOffsetPolygon(List<Point> originalPath, double offset)
{
List<Point> resultOffsetPath = new List<Point>();
List<ClipperLib.IntPoint> polygon = new List<ClipperLib.IntPoint>();
foreach (var point in originalPath)
{
polygon.Add(new ClipperLib.IntPoint(point.X, point.Y));
}
ClipperLib.ClipperOffset co = new ClipperLib.ClipperOffset();
co.AddPath(polygon, ClipperLib.JoinType.jtRound, ClipperLib.EndType.etClosedPolygon);
List<List<ClipperLib.IntPoint>> solution = new List<List<ClipperLib.IntPoint>>();
co.Execute(ref solution, offset);
foreach (var offsetPath in solution)
{
foreach (var offsetPathPoint in offsetPath)
{
resultOffsetPath.Add(new Point(Convert.ToInt32(offsetPathPoint.X), Convert.ToInt32(offsetPathPoint.Y)));
}
}
return resultOffsetPath;
}
さらにもう1つのオプションは、 boost :: polygon を使用することです。ドキュメントは多少不足していますが、メソッドresize
およびbloat
、およびオーバーロードされた+=
演算子。実際にバッファリングを実装します。したがって、たとえば、ある値だけポリゴン(またはポリゴンのセット)のサイズを大きくすることは、次のように簡単です。
poly += 2; // buffer polygon by 2
@ JoshO'Brianからのアドバイスに基づいて、rGeos
言語のR
パッケージがこのアルゴリズムを実装しているようです。 rGeos::gBuffer
を参照してください。
使用できるライブラリがいくつかあります(3Dデータセットにも使用できます)。
これらのライブラリに対応する出版物を見つけて、アルゴリズムをより詳細に理解することもできます。
最後のものは、依存関係が最も少なく、自己完結型であり、.objファイルを読み取ることができます。
ステファン
単純なジオメトリを使用します:ベクトルおよび/または三角法
各コーナーで、中間ベクトルと中間角度を見つけます。中間ベクトルは、コーナーのエッジで定義される2つの単位ベクトルの算術平均です。中角は、エッジで定義される角度の半分です。
各エッジからdの量だけポリゴンを拡大(または縮小)する必要がある場合;新しいコーナーポイントを取得するには、d/sin(midAngle)だけ外に出る(入る)必要があります。
すべての角でこれを繰り返します
***方向に注意してください。コーナーを定義する3つのポイントを使用してCounterClockWiseテストを作成します。どちらの道が出ているか、入っているかを調べる.