13

JavaScriptキャンバスを使用してプロジェクトに取り組んでおり、ポリゴンから特定の距離にカーソルをスナップできる必要があります。ポリゴン自体にはすでにスナップできますが、カーソルをもっと遠くに置く必要があります。

これを行う最善の方法は、ポリゴンをスケーリングしてそれにスナップすることですが、ポリゴンをスケーリングすると、古いポリゴンのエッジと新しいポリゴンのエッジの間の距離が常に一致するとは限りません。上。

問題の例を次に示します。

ここに画像の説明を入力してください ここに画像の説明を入力してください

編集:灰色は元のポリゴンを表し、赤はポリゴンを通常どおりにスケーリングした場合に得られるものであり、緑は私が達成しようとしているものです

ポリゴンを原点に変換して倍率を掛けてみましたが、各エッジを特定の距離だけスケーリングできないようです。

4

5 に答える 5

9

特定のポリゴンに対して、要件を満たすと思われる外側のポリゴンを計算するjsFiddleを作成しました。私はその背後にある数学をこのpdfドキュメントに入れました。

更新:垂直線を処理するためのコードが作成されました。

function Vector2(x, y)
{
    this.x = x;
    this.y = y;
}

function straight_skeleton(poly, spacing)
{
    // http://stackoverflow.com/a/11970006/796832
    // Accompanying Fiddle: http://jsfiddle.net/vqKvM/35/

    var resulting_path = [];
    var N = poly.length;
    var mi, mi1, li, li1, ri, ri1, si, si1, Xi1, Yi1;
    for(var i = 0; i < N; i++)
    {
        mi = (poly[(i+1) % N].y - poly[i].y)/(poly[(i+1) % N].x - poly[i].x);
        mi1 = (poly[(i+2) % N].y - poly[(i+1) % N].y)/(poly[(i+2) % N].x - poly[(i+1) % N].x);
        li = Math.sqrt((poly[(i+1) % N].x - poly[i].x)*(poly[(i+1) % N].x - poly[i].x)+(poly[(i+1) % N].y - poly[i].y)*(poly[(i+1) % N].y - poly[i].y));
        li1 = Math.sqrt((poly[(i+2) % N].x - poly[(i+1) % N].x)*(poly[(i+2) % N].x - poly[(i+1) % N].x)+(poly[(i+2) % N].y - poly[(i+1) % N].y)*(poly[(i+2) % N].y - poly[(i+1) % N].y));
        ri = poly[i].x+spacing*(poly[(i+1) % N].y - poly[i].y)/li;
        ri1 = poly[(i+1) % N].x+spacing*(poly[(i+2) % N].y - poly[(i+1) % N].y)/li1;
        si = poly[i].y-spacing*(poly[(i+1) % N].x - poly[i].x)/li;
        si1 = poly[(i+1) % N].y-spacing*(poly[(i+2) % N].x - poly[(i+1) % N].x)/li1;
        Xi1 = (mi1*ri1-mi*ri+si-si1)/(mi1-mi);
        Yi1 = (mi*mi1*(ri1-ri)+mi1*si-mi*si1)/(mi1-mi);
        // Correction for vertical lines
        if(poly[(i+1) % N].x - poly[i % N].x==0)
        {
            Xi1 = poly[(i+1) % N].x + spacing*(poly[(i+1) % N].y - poly[i % N].y)/Math.abs(poly[(i+1) % N].y - poly[i % N].y);
            Yi1 = mi1*Xi1 - mi1*ri1 + si1;
        }
        if(poly[(i+2) % N].x - poly[(i+1) % N].x==0 )
        {
            Xi1 = poly[(i+2) % N].x + spacing*(poly[(i+2) % N].y - poly[(i+1) % N].y)/Math.abs(poly[(i+2) % N].y - poly[(i+1) % N].y);
            Yi1 = mi*Xi1 - mi*ri + si;
        }

        //console.log("mi:", mi, "mi1:", mi1, "li:", li, "li1:", li1);
        //console.log("ri:", ri, "ri1:", ri1, "si:", si, "si1:", si1, "Xi1:", Xi1, "Yi1:", Yi1);

        resulting_path.push({
            x: Xi1,
            y: Yi1
        });
    }

    return resulting_path;
}


var canvas = document.getElementById("Canvas");
var ctx = canvas.getContext("2d");

var poly = [
    new Vector2(150, 170),
    new Vector2(400, 120),
    new Vector2(200, 270),
    new Vector2(350, 400),
    new Vector2(210, 470)
];

draw(poly);
draw(straight_skeleton(poly, 10));

function draw(p) {
    ctx.beginPath();
    ctx.moveTo(p[0].x, p[0].y);
    for(var i = 1; i < p.length; i++)
    {
        ctx.lineTo(p[i].x, p[i].y);
    }
    ctx.strokeStyle = "#000000";
    ctx.closePath();
    ctx.stroke();
}

ポリゴンはポイントオブジェクトの配列に配置されます。

この関数は、キャンバス上にdraw(p)ポリゴンを描画します。p

指定されたポリゴンは配列polyにあり、外側は配列polyにあります。

spacingポリゴン間の距離です(緑色の図の矢印に沿って)


アンガス・ジョンソンのコメントに続いて、私は彼が提起する問題を示すためにさらにいくつかのフィドルを作成しました。この問題は、私が最初に考えたよりもはるかに難しい問題です。

于 2012-08-15T13:18:19.160 に答える
7

私はClipperのjavascriptポートを作成しました。これを使用すると、必要な方法でスケーリングを行うことができます。

これは、ポリゴンを膨らませる例です。

ここに画像の説明を入力してください

JavascriptClipperのLIVEDEMOを確認してください。

https://sourceforge.net/projects/jsclipper/からclipper.jsファイルを取得します。

ポリゴンをオフセットしてhtml5キャンバスに描画する方法の完全なコード例。

必要に応じて、反対の(収縮する)ことも可能です。

ポリゴンのオフセット

于 2013-01-13T17:07:33.160 に答える
3

あなたが求めているのはポリゴンオフセットアルゴリズムまたはライブラリであるというISTM。ポリゴンを膨張/収縮(オフセット、バッファリング)するためのアルゴリズムを
参照 してください。

于 2012-08-14T21:00:27.087 に答える
2

1つの方法は、ポリゴンのすべてのエッジとカーソルポイントの間の距離を見つけ、最小値を維持することです。

ポイントとラインセグメント間の距離を計算するには、ポイントを支持線に投影します。投影が端点の間にある場合、解決策は点と直線の距離です。それ以外の場合、解決策は最も近い端点までの距離です。

これは、ベクトル計算を使用して簡単に計算できます。

于 2012-08-13T21:34:37.700 に答える
1

JSTSライブラリ(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; }

座標を変換したら、ポリゴンを膨らませることができます。

function inflatePolygon(poly, spacing) {
  var geoInput = vectorCoordinates2JTS(poly);
  geoInput.push(geoInput[0]);

  var geometryFactory = new jsts.geom.GeometryFactory();

  var shell = geometryFactory.createPolygon(geoInput);
  var polygon = shell.buffer(spacing);
  //try with different cap style
  //var polygon = shell.buffer(spacing, jsts.operation.buffer.BufferParameters.CAP_FLAT);

  var inflatedCoordinates = [];
  var oCoordinates;
  oCoordinates = polygon.shell.points.coordinates;

  for (i = 0; i < oCoordinates.length; i++) {
    var oItem;
    oItem = oCoordinates[i];
    inflatedCoordinates.push(new Vector2(Math.ceil(oItem.x), Math.ceil(oItem.y)));
  }
  return inflatedCoordinates;
}

私がjsFiddleに投稿したコードを使用すると、次のようなものが得られます。

ここに画像の説明を入力してください

追加情報: 私は通常、このタイプの膨張/収縮(少し変更)を使用して、マップ(リーフレットまたはGoogleマップを使用)に描画されるポリゴンに半径の境界を設定します。lat、lngペアをJSTS座標に変換するだけで、他のすべては同じです。例:

ここに画像の説明を入力してください

于 2016-08-26T09:24:26.860 に答える