オーバーラップしていない新しいポリゴンにオーバーラップを爆発させますか?


10

複数の方法で重複する複数のポリゴンがある場合、これらの機能から、他のポリゴンと重複しないすべてのポリゴンを繰り返しエクスポートします。

製品は、重なり合わないでオリジナルを構成するいくつかの機能になります。

次に、積をゾーン統計への入力として使用できます。これは、各ポリゴンでゾーン統計を繰り返すよりもはるかに高速です。

私はこれをArcPyでコーディングしようとしましたが、成功しませんでした。

これを行うコードはすでに存在しますか?


データをトポロジ的に正しいセットに「フラット化」したいですか?
nagytech 2012

@Geoist ZonalStatsには、重複しないポリゴンが必要です。重複するコレクションがある場合、明白だが非効率的な解決策は、ポリゴンをループしてゾーン統計を1つずつ計算することです。非重複ポリのサブセットを選択し、それらにゾーンスタットを適用して、反復する方が効率的です。質問は、そのような選択を効率的に行う方法を尋ねます。
whuber

whuber-@Geoistは、入力ポリゴンの交差から重複しないポリゴンのセットを作成することを提案していると思います。この画像を見てください-(コメントに画像を投稿できませんか?)。入力は左側にあります。領域全体が3つのポリゴンで覆われ、それぞれが他の両方のポリゴンと交差しています。オーバーラップしない唯一のサブセットはシングルトンであり、これらは、ユニオンがスペースを満たすというGotanukiの要件を満たしていません。Geoistは、zonalstatsに有効な右側に非交差領域のセットを作成することを提案していると思います
Llaves

最終的な製品がどうあるべきかについて、いくつかの混乱があると思います。例を挙げていただけますか?私の解釈では、残りのポリゴンを破棄またはディゾルブしながら、出力をオーバーラップしないポリゴンの選択にしたいと考えています。1つまたは複数のフィーチャクラスを使用していますか?
アーロン

1
@gotanukiのようなサウンドは、重複するポリゴンを含むポリゴンフィーチャクラスから、重複しないポリゴンのみを含むフィーチャクラスの最小数を作成したい
PolyGeo

回答:


14

これはグラフの色の問題です。

グラフの色付けは、エッジを共有する2つの頂点も同じ色にならないように、グラフの頂点に色を割り当てることを思い出してください。具体的には、グラフの(抽象的な)頂点はポリゴンです。2つの頂点は、(ポリゴンとして)交差するときはいつでも(無向)エッジに接続されます。この問題(ポリゴンの(たとえばk)の互いに素なコレクションのシーケンスです)に対して何らかの解決策を取り、シーケンス内の各コレクションに一意の色を割り当てると、グラフのk-カラーリングが得られます。 。小さなkを見つけることが望ましい。

この問題はかなり難しく、任意のグラフでは未解決のままです。コーディングが簡単な近似解を考えてみましょう。シーケンシャルアルゴリズムを実行する必要があります。ウェールズ-パウエルアルゴリズムは、頂点の次数による降順に基づく貪欲なソリューションです。元のポリゴンの言語に翻訳され、最初に、重なり合う他のポリゴンの数の降順でポリゴンを並べ替えます。順番に作業して、最初のポリゴンに初期色を与えます。それぞれの連続した段階では、既存の色で次のポリゴンに色を試してみてください。つまり、ある色を選択しませんそのポリゴンの近隣のいずれかですでに使用されています。(使用可能な色の中から選択する方法はたくさんあります。最も使用されていないものを試すか、ランダムに選択してください。)次のポリゴンを既存の色で着色できない場合は、新しい色を作成してそれで色を付けます。

少数の色でカラーリングが完了したら、ゾーンごとの色を色ごとに実行します。構成によって、特定の色の2つのポリゴンが重複しないことが保証されます。


これがのサンプルコードですR。(Pythonコードはそれほど変わらないでしょう。)最初に、表示されている7つのポリゴン間のオーバーラップについて説明します。

7つのポリゴンの地図

edges <- matrix(c(1,2, 2,3, 3,4, 4,5, 5,1, 2,6, 4,6, 4,7, 5,7, 1,7), ncol=2, byrow=TRUE)

つまり、ポリゴン1と2が重なり、ポリゴン2と3、3と4、...、1と7も重なります。

頂点を降順でソートします。

vertices <- unique(as.vector(edges))
neighbors <- function(i) union(edges[edges[, 1]==i,2], edges[edges[, 2]==i,1])
nbrhoods <- sapply(vertices, neighbors)
degrees <- sapply(nbrhoods, length)
v <- vertices[rev(order(degrees))]

(粗)シーケンシャルカラーリングアルゴリズムは、重なり合うポリゴンでまだ使用されていない最も早い使用可能なカラーを使用します。

color <- function(i) {
  n <- neighbors(i)
  candidate <- min(setdiff(1:color.next, colors[n]))
  if (candidate==color.next) color.next <<- color.next+1
  colors[i] <<- candidate
}

データ構造(colorsおよびcolor.next)を初期化し、アルゴリズムを適用します。

colors <- rep(0, length(vertices))
color.next <- 1
temp <- sapply(v, color)

色に従ってポリゴンをグループに分割します。

split(vertices, colors)

この例の出力では、4つの色を使用しています。

$`1`
[1] 2 4

$`2`
[1] 3 6 7

$`3`
[1] 5

$`4`
[1] 1

ポリゴンの4色

ポリゴンを重複しない4つのグループに分割しました。この場合、解は最適ではありません({{3,6,5}、{2,4}、{1,7}}は、このグラフの3色です)。ただし、一般的に、それが取得するソリューションはそれほど悪くないはずです。


これが質問に答えるかどうか、または質問が何であるかはわかりませんが、それでもなお良い答えです。
nagytech 2012

@ジオイストイラストをより明確にしたり、問題をよりよく説明したりする方法はありますか?
whuber

6

#whuberによって推奨された方法論は、私に新しい方向性をとるように促しました。これが、2つの関数での私の弧状の解決策です。1つ目はcountOverlapsと呼ばれ、「overlaps」と「ovlpCount」の2つのフィールドを作成して、各ポリゴンについて、どのポリゴンがそれとオーバーラップしたか、およびオーバーラップの数を記録します。2番目の関数explodeOverlapsは、3番目のフィールド「expl」を作成します。これは、重複しないポリゴンの各グループに一意の整数を提供します。ユーザーは、このフィールドに基づいて新しいfcをエクスポートできます。countOverlapsツールはそれ自体で有用であると私は思うので、プロセスは2つの関数に分けられます。コードのだらしさ(および不注意な命名規則)はすみません、それはかなり予備的なものですが、機能します。また、「idName」が fieldは、一意のIDを持つフィールドを表します(整数IDでのみテストされます)。この問題に取り組むために必要なフレームワークを提供してくれたwhuberに感謝します!

def countOverlaps(fc,idName):
    intersect = arcpy.Intersect_analysis(fc,'intersect')
    findID = arcpy.FindIdentical_management(intersect,"explFindID","Shape")
    arcpy.MakeFeatureLayer_management(intersect,"intlyr")
    arcpy.AddJoin_management("intlyr",arcpy.Describe("intlyr").OIDfieldName,findID,"IN_FID","KEEP_ALL")
    segIDs = {}
    featseqName = "explFindID.FEAT_SEQ"
    idNewName = "intersect."+idName

    for row in arcpy.SearchCursor("intlyr"):
        idVal = row.getValue(idNewName)
        featseqVal = row.getValue(featseqName)
        segIDs[featseqVal] = []
    for row in arcpy.SearchCursor("intlyr"):
        idVal = row.getValue(idNewName)
        featseqVal = row.getValue(featseqName)
        segIDs[featseqVal].append(idVal)

    segIDs2 = {}
    for row in arcpy.SearchCursor("intlyr"):
        idVal = row.getValue(idNewName)
        segIDs2[idVal] = []

    for x,y in segIDs.iteritems():
        for segID in y:
            segIDs2[segID].extend([k for k in y if k != segID])

    for x,y in segIDs2.iteritems():
        segIDs2[x] = list(set(y))

    arcpy.RemoveJoin_management("intlyr",arcpy.Describe(findID).name)

    if 'overlaps' not in [k.name for k in arcpy.ListFields(fc)]:
        arcpy.AddField_management(fc,'overlaps',"TEXT")
    if 'ovlpCount' not in [k.name for k in arcpy.ListFields(fc)]:
        arcpy.AddField_management(fc,'ovlpCount',"SHORT")

    urows = arcpy.UpdateCursor(fc)
    for urow in urows:
        idVal = urow.getValue(idName)
        if segIDs2.get(idVal):
            urow.overlaps = str(segIDs2[idVal]).strip('[]')
            urow.ovlpCount = len(segIDs2[idVal])
        urows.updateRow(urow)

def explodeOverlaps(fc,idName):

    countOverlaps(fc,idName)

    arcpy.AddField_management(fc,'expl',"SHORT")

    urows = arcpy.UpdateCursor(fc,'"overlaps" IS NULL')
    for urow in urows:
        urow.expl = 1
        urows.updateRow(urow)

    i=1
    lyr = arcpy.MakeFeatureLayer_management(fc)
    while int(arcpy.GetCount_management(arcpy.SelectLayerByAttribute_management(lyr,"NEW_SELECTION",'"expl" IS NULL')).getOutput(0)) > 0:
        ovList=[]
        urows = arcpy.UpdateCursor(fc,'"expl" IS NULL','','','ovlpCount D')
        for urow in urows:
            ovVal = urow.overlaps
            idVal = urow.getValue(idName)
            intList = ovVal.replace(' ','').split(',')
            for x in intList:
                intList[intList.index(x)] = int(x)
            if idVal not in ovList:
                urow.expl = i
            urows.updateRow(urow)
            ovList.extend(intList)
        i+=1

2
これを私のソリューションに接続countOverlapsするには:あなたnbrhoods <- sapply(vertices, neighbors); degrees <- sapply(nbrhoods, length)は私のコードの2行に対応します:degreesは重複数です。もちろん、私のソリューションで当然とされているGIS分析のほとんどを反映しているため、コードはより長くなります。つまり、最初に重複するポリゴンを特定し、最後にソリューションを使用してポリゴンデータセットを出力します。あなたが今までより良いカラーリングアルゴリズムを見つけた場合ので、それはプラグインに簡単だろう、グラフ理論計算をカプセル化するために良いでしょう。
whuber

1

しばらく前のことですが、このコードを自分のアプリケーションに使用しましたが、うまく機能しています。ありがとうございました。その一部を書き直して更新し、ラインに適用し(許容範囲で)、大幅にスピードアップしました(以下では、5,000万の交差するバッファーで実行しており、数時間しかかかりません)。

def ExplodeOverlappingLines(fc, tolerance, keep=True):
        print('Buffering lines...')
        idName = "ORIG_FID"
        fcbuf = arcpy.Buffer_analysis(fc, fc+'buf', tolerance, line_side='FULL', line_end_type='FLAT')
        print('Intersecting buffers...')
        intersect = arcpy.Intersect_analysis(fcbuf,'intersect')

        print('Creating dictionary of overlaps...')
        #Find identical shapes and put them together in a dictionary, unique shapes will only have one value
        segIDs = defaultdict(list)
        with arcpy.da.SearchCursor(intersect, ['Shape@WKT', idName]) as cursor:
            x=0
            for row in cursor:
                if x%100000 == 0:
                    print('Processed {} records for duplicate shapes...'.format(x))
                segIDs[row[0]].append(row[1])
                x+=1

        #Build dictionary of all buffers overlapping each buffer
        segIDs2 = defaultdict(list)
        for v in segIDs.values():
            for segID in v:
                segIDs2[segID].extend([k for k in v if k != segID and k not in segIDs2[segID]])

        print('Assigning lines to non-overlapping sets...')
        grpdict = {}
        # Mark all non-overlapping one to group 1
        for row in arcpy.da.SearchCursor(fcbuf, [idName]):
            if row[0] in segIDs2:
                grpdict[row[0]] = None
            else:
                grpdict[row[0]] = 1

        segIDs2sort = sorted(segIDs2.items(), key=lambda x: (len(x[1]), x[0])) #Sort dictionary by number of overlapping features then by keys
        i = 2
        while None in grpdict.values(): #As long as there remain features not assigned to a group
            print(i)
            ovset = set()  # list of all features overlapping features within current group
            s_update = ovset.update
            for rec in segIDs2sort:
                if grpdict[rec[0]] is None: #If feature has not been assigned a group
                    if rec[0] not in ovset: #If does not overlap with a feature in that group
                        grpdict[rec[0]] = i  # Assign current group to feature
                        s_update(rec[1])  # Add all overlapping feature to ovList
            i += 1 #Iterate to the next group

        print('Writing out results to "expl" field in...'.format(fc))
        arcpy.AddField_management(fc, 'expl', "SHORT")
        with arcpy.da.UpdateCursor(fc,
                                   [arcpy.Describe(fc).OIDfieldName, 'expl']) as cursor:
            for row in cursor:
                if row[0] in grpdict:
                    row[1] = grpdict[row[0]]
                    cursor.updateRow(row)

        if keep == False:
            print('Deleting intermediate outputs...')
            for fc in ['intersect', "explFindID"]:
                arcpy.Delete_management(fc)

-3

この場合、私は通常、次の方法を使用します。

  • UNIONを介してFeatureクラスを渡します。(すべての交差部分のポリゴンを壊します)
  • X、Y、Areaフィールドを追加して計算します。
  • X、Y、Areaフィールドで結果を分解します。

結果はあなたが望んだものになると思います、そしてあなたは重複の数を数えることさえできます。パフォーマンスの点であなたにとってより良いかどうかわからない。


2
この方法では、目的の製品は得られません。これは、最小の一連の選択または重複しないオリジナルの固有のフィーチャクラスです。製品はゾーン統計に供給されるため、各フィーチャの元のジオメトリを維持することが重要です。
ndimhypervol 2012

あなたは正しい、ごめんなさい。その質問はよくわかりませんでした。その場合、ラスターのサイズに応じて、通常はラスターを一時的なポイントフィーチャクラス(各セルがポイント)に変換し、それとポリゴンレイヤーの間の空間結合を実行します。多分、それは非常に単純で、パフォーマンスに不利なアプローチですが、機能し、重なり合ったポリゴンは問題を引き起こしません。
Alexandre Neto 2012

この空間結合の意味を正しく理解していれば、2番目のソリューションであるAlexandreは機能しません。これは、ポイントとポリゴンの間に多対多の関係があるためです。いずれにせよ、サイズの大きなラスターの場合、このベクターベースのアプローチは非常に非効率的であり、大きなラスターの場合は実行できません。
whuber

@whuberあなたは非常に遅いプロセスであることについて正しいです(4284 x 3009ラスターと2401ポリゴン、ビスタ付きデュアルコア2.8Ghz、3Gb RAMで約30分かかります)。しかし、私はすでにそれをテストしたので、それは機能します。空間結合では、1対1の関係を使用し、ラスター値を(平均、合計などとして)集計する必要があります。結果は、オリジナルと同様のベクターポリゴンレイヤーになりますが、各ポリゴンと交差する集約ラスター値を持つ新しい列が含まれます。これは最適なソリューションではないので、プログラミングのスキルが低い人(私のように:-)には役立ちます。
Alexandre Neto 2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.