凹面ポリゴンの対脚距離(またはポリゴンフェッチまたはポリゴン直径)


8

ArcMap内に実装されたPythonのいくつかのクラスの例に取り組んでおり、ポリゴン内の正反対の距離を計算しています。これは凸型ポリゴンではかなり日常的ですが、凹型ポリゴンでは、完全にポリゴン内になく、ポリゴンの境界上または交差していないソリューション(境界点を結ぶ光線によって形成される)を除外したいと思います。定義を間違って解釈したのか、それともこの獣は別の名前で通じているのか。

これらの2つのポリゴンを考えます

pnts = [[0,0]、[0,1]、[1,4]、[3,5]、[5,4]、[4,1]、[0,0]]#閉ループ凸

pnts = [[0,0]、[2,1]、[1,4]、[3,5]、[5,4]、[4,1]、[0,0]]#閉ループ凹多角形

私の解釈では、ポイント0,0は、それと他のポイントを接続するベクトルがポリゴンと自己交差しているか、ポリゴンの境界上にあるため、それに関連付けられている正反対の距離を持つべきではありません。

誰かが定義や潜在的な解決策について何か明確化をしているなら、私はそれを感謝します。

凸多角形と目的の線(赤で表示)のビジュアルが囲まれています(ポイント0からのサンプルベクトルのみが表示されています)。

内側の対脚距離の例

凸型の例では、最初の点には対蹠ベクトルがありませんが、2番目の点にはあります。

凹型対掌体の例

編集私はウェブ上で「ポリゴンフェッチ」または「ポリゴン直径」を使用した検索に成功しました。これが私が求めているものだと思います。


1
こんにちは、ダン。「対蹠距離」のどの定義を使用していますか?1つの可能性は、ポリゴンの境界に沿った移動によって測定される最も遠いポイントですが、それは説明と一致していないようです。別の定義は、移動がポリゴンの内側または外側のどこでも発生する可能性がある最も遠いポイントです。しかし、3分の1は、ポリゴンの内部と境界内でのみ移動が許可される最も遠いポイントです。
whuber

1
@whuber、私は、ポリゴン境界を形成するラインセグメントを除いて、ポリゴン内のみを移動するソリューションを探していました。私が挙げた凸の例では、ポイントp0からp1、またはp0からp5への移動は、ポリゴンエッジの一部であるため許可されませんが、p0からp2、p3、p4への移動は許可されます。したがって、「対掌型」は正しい用語ではないかもしれないという私の懸念。現時点では、穴のな​​い単一パーツの凸形ポリゴンのみに関心があります。ソリューションでエッジセグメントが詰まっている場合は、後でいつでも削除できます。

1
ここにデリケートな問題があります、ダン:そのようなセグメントは除外されるかもしれませんが、それでもそれらはすべての可能な距離の極限が何になるかを教えてくれます(それらは単にその極限が実際に実現されるのを妨げるだけです)。実用的な解決策は、これらのセグメントの内部を維持しますが、それらに限りなく近いままです。したがって、凸多角形の場合、アルゴリズムは単純です。開始点から最も遠い頂点を見つけます(それらの多くが存在する可能性があります:半円を想像し、元の円の中心から開始します)。
whuber

1
Danの定義はまだわかりません。Dan、どのポリゴンにも "最長パス"がないためです。蛇行して任意の長いパスを作成できます。おそらくあなたが意図しているのは次のことです:(接続された)ポリゴンのポイントPとQの間の距離を、ポリゴン内に完全にあるPからQまでのすべてのパスの長さの最小値になるように定義します。次いでコンパクト接続ポリゴンPのためのもっともらしい「対掌体」は、P(Pは、凸多角形の頂点である場合、その対掌体が再びP.からの最大ユークリッド距離で頂点である)から最大距離で任意の点Qであろう
whuber

2
最も遠い点は、私の前のコメントの「もっともらしい」定義を使用して厳密に特徴付けられています。あなたがそれを見つけることであなたがあなたが端に沿って移動するかもしれないと仮定することが許されることに注意してください。2番目の図では、EはAとBに対して正反対です。AはC、D、およびEに対して正反対です。DとAはどちらもFの反対です。多角形の内部が湖であるカヌーのアナロジーを使用すると、Pに到達しようとする対戦相手に対してQからカヌーレースに参加しているとき、ポイントPは開始点Qの反対です。ある点P 'に到達する前に、P'がどこにあっても、それらはあなたよりも有利ではありません。
whuber

回答:


4

アルゴリズムを作成している場合は、多角形の2つの頂点間の線が、エッジの1つを形成する線と交差するかどうかを確認します。これが私の疑似コードです:

  1. すべての頂点を特定し、リストに保存します
  2. すべてのエッジを識別し、リストに格納します(おそらく1からの頂点のペアとして)
  3. 各頂点について、以下を除く他のすべての頂点までの距離を取得します。
    1. 隣接する頂点(おそらく2でこの頂点とペアを共有しているもの)を除外します
    2. ここから何かを使用して、2.の任意の線と交差する線を除外します
  4. 1の頂点を参照して、すべての有効距離を保存します。

  5. 結果で望むことを何でもし、新しいラインを書き、各ポリゴンの最も長いラインを保存します...

さて、これが目的かどうかはわかりませんが、ArcPyで上記のことを実行できます。

編集:ステップ2.2のコード:

E = B-A = ( Bx-Ax, By-Ay )
F = D-C = ( Dx-Cx, Dy-Cy ) 
P = ( -Ey, Ex )
h = ( (A-C) * P ) / ( F * P )

hが0と1の間の場合、線は交差し、そうでない場合は交差しません。F * Pがゼロの場合、もちろん計算を行うことはできませんが、この場合、線は平行であり、したがって明らかな場合にのみ交差します。hが1の場合、線は同じ点で終わります。これを自由に処理してください!(私は彼らが交差すると言います、それは私をより簡単にします。)

ここからのステップ2.2の別の例:http : //en.wikipedia.org/wiki/Line-line_intersection ここに画像の説明を入力してください

まず、分母が0に等しくないことを確認します。これは、線が平行であることを意味します。

次に、上記で見つかった座標がいずれかの行の境界ボックスの外にないことを確認します。

もっと読む:http : //compgeom.cs.uiuc.edu/~jeffe/teaching/373/notes/x06-sweepline.pdf


私のブログのコードは3.2以外のすべてを実行し、その結果を呼び出し側プログラムに参照して、凸型ポリゴンでうまく機能するさらなる計算を行います。可能な場合はいくつかの参照を希望します。また、曲がり数が線の交点を決定するのに効率的であるか、それとも他のルートに進むべきかを教えてください。

2
リンクした記事から交差計算の例を追加しました。問題になるまで効率は気にならなかったと思います!何かを動作させ、それが十分でない場合は修正してください!
Alex Leith

アレックス、ありがとうございました。これは数千のポリゴンで実行しない例にすぎないため、効率は問題になりません

この答えが何であるかを言うのは難しいですが、それポリゴンが凸かどうかのチェックのようです。「線分」の代わりに「線」を使用しているように見えるのは特に混乱しています。指定されたコードは、線分の
whuber

こんにちは、これは線分をチェックします。私が追加した2番目の例は、おそらくより明確になります。これは、数学が無限線の交差点を計算し、その交差点がいずれかの線の境界ボックス内にあるかどうかを確認する必要があるためです。すべてのベクトル数学と同様に、これを実行するライブラリは確かにありますが、それほど複雑ではなく、OPが実行したいことには必要だと思います。
Alex Leith 2013

3

まるで視線のように、天使を使ってこれをやりたくなります。形状の頂点を反復している間、起点の頂点と終点の頂点の間の角度が一定の方向に続く場合、すべての点が正反対の候補になります。角度が方向を切り替えると、そのポイントは前のポイントによって非表示になるか、非表示になります。前のポイントによって非表示になっている場合は、そのポイントをスキップする必要があります。前のポイントを非表示にする場合は、前のポイントを候補リストから削除する必要があります。

  1. PolygonCandidatesリストを作成する
  2. 各頂点(ポイントk)
    1. 候補(ポイント、角度)の新しいリストを作成する
    2. 現在の頂点を候補リストに追加します(ポイントk)
    3. 残りの各頂点(点i)について、ポリゴンの周りを時計回りに反復します
      1. 現在の点に対する角度(点kから点iまで)が時計回りの方向に続く場合1.点を追加します
      2. 現在のポイントに対する角度が反時計回りに続いている場合
      3. 前の2つの候補ポイントと現在のポイントが右折した場合。
      4. 現在の角度と最後の候補リストの角度が反時計回りになるまで、リストの最後のポイントを削除します。
      5. 現在のポイントを候補リストに追加します
    4. 最初の2つと最後の候補点を除くすべてをPolygonCandidatesリストに追加する
  3. PolygonCandidatesリストで最も遠い点を見つけます。

原点と他の2つの頂点がすべて同じ線上にある場合の対処法がわかりません。その場合、角度は同じになります。穴のあるポリゴンがある場合は、各穴の最小/最大角度を見つけ、その範囲内にある候補点を削除できます。

このアプローチの主な利点は、現在のラインセグメントとすべてのポリゴンエッジ間のラインの交差をテストする必要がないことです。

これはうまくいくと思います。上記の疑似コードとpythonを読みやすくするために更新しました。


これが最後の編集です。以下の例は、与えられたジオメトリの最大のアニポールを見つけます。ポイントとベクターを使用するようにスクリプトを変更して、読みやすくしてみました。

import math
from collections import namedtuple


Point = namedtuple("Point", "position x y")
Vector = namedtuple("Vector", "source dest angle")

def isClockwise(angle1, angle2):
    diff = angle2 - angle1
    #print("         angle1:%s angle2:%s diff: %s" % (angle1, angle2, diff))
    if(diff > math.pi/2):
        diff = diff - math.pi/2
    elif (diff < -math.pi/2):
        diff = diff + math.pi/2
    #print("         diff:%s" % (diff)) 
    if(diff > 0):
        return False
    return True

def getAngle(origin, point):
    return math.atan2(point.y - origin.y, point.x-origin.x)

#returns a list of candidate vertcies.  This will include the first, second, and second to last points 
#the first and last points in the polygon must be the same
#k is the starting position, only vertices after this position will be evaluated
def getCandidates (k, polygon):

    origin = polygon[k]
    candidates = [Vector(k,k,0)]
    prevAngle = 0;
    currentAngle = 0;
    for i in range(k + 1, len(polygon) - 1):

        current = polygon[i]
        #print("vertex i:%s x:%s y:%s  " % (i, current.x, current.y))

        if(i == k+1):
            prevAngle = getAngle(origin, current)
            candidates.append(Vector(k,i,prevAngle))
        else:   
            currentAngle = getAngle(origin, current)
            #print("     prevAngle:%s currentAngle:%s  " % (prevAngle, currentAngle))
            if isClockwise(prevAngle, currentAngle):
                #print("     append")
                candidates.append(Vector(k,i,currentAngle))
                prevAngle = currentAngle
            else:
                #look at the angle between current, candidate-1 and candidate-2
                if(i >= 2):
                    lastCandinate = polygon[candidates[len(candidates) - 1].dest]
                    secondLastCandidate = polygon[candidates[len(candidates) - 2].dest]
                    isleft = ((lastCandinate.x - secondLastCandidate.x)*(current.y - secondLastCandidate.y) - (lastCandinate.y - secondLastCandidate.y)*(current.x - secondLastCandidate.x)) > 0
                    #print("     test for what side of polygon %s" % (isleft))
                    if(i-k >= 2 and not isleft):
                        while isClockwise(currentAngle, candidates[len(candidates) - 1].angle):
                            #print("     remove %s" % (len(candidates) - 1))
                            candidates.pop()
                        #print("     append (after remove)")
                        candidates.append(Vector(k,i,currentAngle))
                        prevAngle = currentAngle

        #for i in range(len(candidates)):
        #   print("candidate i:%s x:%s y:%s a:%s " % (candidates[i][0], candidates[i][1], candidates[i][2], candidates[i][3]))

    return candidates

def calcDistance(point1, point2):
    return math.sqrt(math.pow(point2.x - point1.x, 2) + math.pow(point2.y - point1.y, 2))

def findMaxDistance(polygon, candidates):
    #ignore the first 2 and last result
    maxDistance = 0
    maxVector = Vector(0,0,0);
    for i in range(len(candidates)):
        currentDistance = calcDistance(polygon[candidates[i].source], polygon[candidates[i].dest])
        if(currentDistance > maxDistance):
            maxDistance = currentDistance
            maxVector = candidates[i];
    if(maxDistance > 0):
        print ("The Antipodal distance is %s from %s to %s" % (maxDistance, polygon[candidates[i].source], polygon[candidates[i].dest]))
    else:
        print ("There is no Antipodal distance")

def getAntipodalDist(polygon):
    polygonCandidates = []
    for j in range(0, len(polygon) - 1):
        candidates = getCandidates(j, polygon)
        for i in range(2, len(candidates) - 1):
            #print("candidate i:%s->%s x:%s y:%s  " % (candidates[i].source, candidates[i].dest, candidates[i].x, candidates[i].y))
            polygonCandidates.append(candidates[i])

    for i in range(len(polygonCandidates)):
        print("candidate i:%s->%s" % (polygonCandidates[i].source, polygonCandidates[i].dest))
    findMaxDistance(polygon, polygonCandidates)


getAntipodalDist([Point(0,0,0),Point(1,-2,0),Point(2,-2,3),Point(3,2,2),Point(4,-1,1),Point(5,4,0),Point(6,0,0)])
getAntipodalDist([Point(0,0,0),Point(1,2,1),Point(2,1,4),Point(3,3,5),Point(4,5,4),Point(5,4,1),Point(6,0,0)])
getAntipodalDist([Point(0,0,0),Point(1,1,1),Point(2,2,1),Point(3,1,4),Point(4,3,5),Point(5,5,4),Point(6,4,1),Point(7,0,0)])
getAntipodalDist([Point(0,0,0),Point(1,-1,3),Point(2,1,4),Point(3,3,3),Point(4,2,0),Point(5,-2,-1),Point(6,0,0)])

このアルゴリズムは本当に機能しますか?おそらく、六角形((0,0)、(-2,0)、(-2,3)、(2,2)、(-1,1)、(4 、0)、(0,0))?(0,0)から始めるとどうなりますか?そして、このアルゴリズムは何をするつもりですか?たとえば、(長さが1.2 * sqrt(26)の)ポリゴンで最も長いラインセグメントは検出されません。
whuber

しかし、コメントのおかげで、これはすべてのケースで機能するわけではありません(凹型ハルの例を参照)。isRightTurn(A、B、C)はfalseになり、ACは候補セグメントになりません。Bがさらに北にある場合、セグメントAEの場合はすべて1になる可能性があるため、他のすべてのポイントがチェックされるまで、ポイントAを完全に除外したくありません。

@whuber、そのジオメトリを考えると、最長のラインセグメントが1.2 * sqrt(26)であることがわかりません。私がこの質問について完全に見逃していない限り。(0,0)->(-1,1)または(-2,0)->(-1,1)のいずれかのsqrt(2)ではないでしょうか。
トラビス2013

1
@DanPatterson、私はあなたが求めているものを逃したかもしれません。私の理解は次のとおりです。ポリゴンの境界と交差しない、特定の頂点と他の頂点の間の最大距離は何ですか。スクリプトを更新して、ポリゴンの最大距離を見つけました。
トラビス2013

凸ポリゴンは、Webやテキストで見られる単純な例を考えると問題にはならないようです。凹型の船体のポリゴンの直径には、さまざまな解釈とポリゴンのフェッチがあるようですが、もう1つの魚のやかんに気づき始めています。とにかく、交差しないものは何でも、私が求めているものです。私の懸念は、現実の例での明確な定義と例の欠如です。私は凸形のものをカバーできますが、凹形のものは問題があり、ビルの提案のいくつかによってサポート/強調されている私の数学/計算の専門知識を超えています。

1

おそらく、データセットの三角形分割を検討してください。どのラインがポリゴンエッジに共通しているかを簡単に設定でき、残りのラインを比較して最も長いラインを見つけることができますか?次に問題は、必要な三角測量アルゴリズムです。

それは直感に過ぎませんが、私が(皮肉にも)作成できる「最低品質」の三角形分割には、探している行が含まれている必要があると考えています。たとえば、https://www.google.co.uk/url?sa = t&rct =の図1 j&q =&esrc = s&source = web&cd = 6&ved = 0CEoQFjAF&url = http%3A%2F%2Fhrcak.srce.hr%2Ffile%2F69457&ei = alIcUsb6HsLnswbfnYHoDw&usg = AFQjCNHIaykVRBAQvPLPLKFIBQPLQJQ


私のブログの私のコードは、凹面の船体の場合に何をすべきかと同様に、私が明確にする必要がある用語よりも効果的です。

三角測量は本質的に凹面のハルを処理します(ポリゴンの境界を横切る三角形のエッジを作成しない
限り
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.