겹치지 않는 새로운 다각형으로 겹치는 부분이 폭발합니까?


10

여러 방식으로 겹치는 여러 다각형이 주어지면 다른 지형과 겹치지 않는 모든 다각형을 반복적으로 이러한 기능에서 내보내고 싶습니다.

이 제품은 서로 합치면 원본을 구성하는 겹침이없는 여러 기능입니다.

그런 다음이 제품을 구역 통계에 대한 입력으로 사용할 수 있으며 이는 각 다각형에서 구역 통계를 반복하는 것보다 훨씬 빠릅니다.

ArcPy에서 이것을 성공적으로 코딩하려고 노력했습니다.

이를 수행하는 코드가 이미 존재합니까?


데이터를 위상 적으로 올바른 세트로 '평평하게'하시겠습니까?
nagytech

@Geoist ZonalStats에는 겹치지 않는 다각형이 필요합니다. 컬렉션이 겹치는 경우 분명하지만 비효율적 인 솔루션은 폴리를 반복하고 구역 통계를 하나씩 계산하는 것입니다. 겹치지 않는 폴리의 하위 집합을 선택하고 zonalstats를 적용하고 반복하는 것이 더 효율적입니다. 질문은 그러한 선택을 효율적으로 만드는 방법을 묻습니다.
whuber

whuber-@Geoist는 입력 다각형의 교차점에서 겹치지 않는 다각형 세트를 만들 것을 제안합니다. 이 이미지를 보십시오 -(댓글에 이미지를 게시 할 수 없습니까?) 입력은 왼쪽에 있습니다. 전체 지역은 3 개의 다각형으로 덮여 있으며 각각 다각형이 서로 교차합니다. 겹치지 않는 유일한 하위 집합은 싱글 톤이며, 노조가 공간을 채우는 Gotanuki의 요구 사항을 충족시키지 못합니다. 나는 Geoist이 zonalstats 유효 오른쪽에 교차하지 않는 지역의 세트를 생성 제안 생각
Llaves

나는 최종 제품이 무엇인지에 대해 약간의 혼란이 있다고 생각합니다. 예를 들어 주시겠습니까? 내 해석은 출력을 겹치지 않는 나머지 다각형으로 선택하고 나머지 다각형은 버리고 녹이기를 원합니다. 하나 이상의 피쳐 클래스로 작업하고 있습니까?
Aaron

1
@gotanuki와 같은 소리는 다각형이 겹치는 다각형 피쳐 클래스에서 겹치지 않는 다각형 만 포함하는 피쳐 클래스의 최소 개수를 만들고 싶습니다.
PolyGeo

답변:


14

이것은 그래프 색상 문제 입니다.

그래프 색상은 가장자리를 공유하는 두 정점이 동일한 색상을 갖지 않도록 그래프의 정점에 색상을 할당하는 것입니다. 구체적으로, 그래프의 (추상) 정점은 다각형입니다. 두 개의 정점은 교차 할 때마다 (다각형으로) (무 방향) 모서리에 연결됩니다. 우리가 문제에 대한 해결책을 취하면 (즉, k의 분리 된 다각형 컬렉션 시퀀스) 시퀀스의 각 컬렉션에 고유 한 색상을 할당 하면 그래프 의 k 색을 얻습니다. . 작은 k 를 찾는 것이 바람직합니다 .

이 문제는 매우 어렵고 임의의 그래프에서는 해결되지 않은 상태입니다. 코딩하기 쉬운 대략적인 솔루션을 고려하십시오. 순차적 인 알고리즘이해야합니다. 웨일즈-포웰 알고리즘은 정점의 차수 순서에 따른 탐욕스러운 솔루션입니다. 원래 다각형의 언어로 번역 된 다음, 다각형을 겹치는 다른 다각형 수의 내림차순으로 정렬합니다. 순서대로 작업하려면 첫 번째 다각형에 초기 색을 지정하십시오. 연속되는 각 단계에서 기존 색상으로 다음 다각형에 색상을 지정하십시오. 즉, 그렇지 않은 색상을 선택하십시오.해당 다각형의 이웃에 이미 사용되었습니다. (사용 가능한 색상 중에서 선택하는 방법은 여러 가지가 있습니다. 가장 많이 사용되지 않은 색상을 선택하거나 무작위로 다른 색상을 선택하십시오.) 다음 다각형에 기존 색상으로 색상을 지정할 수없는 경우 새 색상을 만들어 그 색상으로 색상을 지정하십시오.

적은 수의 색상으로 채색을 완료 한 후에는 색상별로 구역 별 통계를 수행합니다. 구성에 따라 주어진 색상의 두 다각형이 겹치지 않도록 보장 할 수 있습니다.


의 샘플 코드는 다음과 같습니다 R. (파이썬 코드는 크게 다르지 않을 것입니다.) 먼저, 우리는 표시된 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
}

데이터 구조 ( colorscolor.next)를 초기화하고 알고리즘을 적용하십시오.

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

색상에 따라 다각형을 그룹으로 나눕니다.

split(vertices, colors)

이 예제의 출력은 네 가지 색상을 사용합니다.

$`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

@Geoist 일러스트레이션을 더 선명하게하거나 문제를 더 잘 설명 할 수있는 방법이 있습니까?
whuber

6

#whuber가 추천 한 방법론은 새로운 방향으로 나아가도록 영감을 주었으며, 여기에는 두 가지 기능이있는 아크 피 솔루션이 있습니다. countOverlaps라고하는 첫 번째는 "overlaps"와 "ovlpCount"라는 두 개의 필드를 만들어 폴리와 겹친 각 폴리에 대해 기록하고 오버랩이 발생한 횟수를 기록합니다. 두 번째 함수 인 explodeOverlaps는 겹치지 않는 폴리 그룹마다 고유 한 정수를 제공하는 세 번째 필드 인 "expl"을 만듭니다. 그런 다음이 필드를 기반으로 새 fc를 내보낼 수 있습니다. countOverlaps 도구가 그 자체로 유용 할 수 있다고 생각하기 때문에 프로세스는 두 가지 기능으로 나뉩니다. 꽤 예비 적이므로 코드의 부패 (와 부주의 한 명명 규칙)를 용서하십시오. 또한 "idName"이 field는 고유 ID를 가진 필드를 나타냅니다 (정수 ID로만 테스트). 이 문제에 접근하는 데 필요한 프레임 워크를 제공해 주셔서 감사합니다.

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)에 해당합니다 degrees. 물론 코드는 내 솔루션에서 당연한 것으로 여겨지는 대부분의 GIS 분석을 반영하기 때문에 더 길어집니다. 그래프 이론적 계산을 캡슐화하는 것이 좋습니다. 따라서 더 나은 색상 알고리즘을 찾으면 쉽게 연결할 수 있습니다.
whuber

1

시간이 오래 걸렸지 만이 코드를 내 응용 프로그램에 사용했으며 제대로 작동했습니다. 감사합니다. 나는 그것을 업데이트하여 업데이트를 위해 라인에 적용하고 (허용 오차가있는) 라인에 적용하고 속도를 크게 올렸다.

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

네 말이 맞아 미안해 나는 그 질문을 잘 이해하지 못했다. 이 경우 래스터의 크기에 따라 일반적으로 래스터를 임시 포인트 피쳐 클래스 (각 셀은 포인트)로 변환하고이 레이어와 다각형 레이어 사이에 공간 결합을 수행합니다. 어쩌면 매우 단순하고 성능이 좋지 않은 접근법이지만 작동하고 겹친 다각형은 아무런 문제를 일으키지 않습니다.
Alexandre Neto

이 공간 결합의 의미를 올바르게 이해하면 점과 다각형 사이에 많은 관계가 있기 때문에 두 번째 솔루션 인 Alexandre는 여전히 작동하지 않습니다. 그럼에도 불구하고, 크기 조정이 가능한 래스터의 경우이 벡터 기반 접근 방식은 매우 비효율적이며 큰 래스터의 경우에는 수행이 불가능합니다.
whuber

@ whuber 당신은 매우 느린 프로세스에 대해 옳습니다 (듀티 코어 2.8Ghz, 비스타가있는 3Gb RAM의 4284 x 3009 래스터와 2401 다각형으로 약 30 분이 걸렸습니다). 그러나 이미 테스트 했으므로 작동합니다. 공간 조인에서는 일대일 관계를 사용하고 래스터 값 (평균, 합계 등)을 집계해야합니다. 결과는 원본과 비슷하지만 각 다각형과 교차하는 집계 된 래스터 값이있는 새 열이있는 벡터 다각형 레이어가됩니다. 최적의 솔루션이 아니라면 프로그래밍 기술이 적은 사람에게 유용 할 수 있습니다 (예 : 나와 같은).
Alexandre Neto
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.