Phát nổ chồng chéo lên đa giác mới không chồng chéo?


10

Với nhiều đa giác trùng nhau theo nhiều cách, tôi muốn xuất từ ​​các tính năng này tất cả các đa giác không trùng lặp với các đa giác, lặp đi lặp lại.

Sản phẩm sẽ là một số tính năng không có sự trùng lặp mà khi kết hợp lại với nhau, tạo thành bản gốc.

Các sản phẩm sau đó có thể được sử dụng làm đầu vào cho Thống kê Zonal và điều này sẽ nhanh hơn nhiều so với việc lặp lại Thống kê Zonal trên mỗi đa giác.

Tôi đã cố gắng mã hóa điều này trong ArcPy nhưng không thành công.

Có mã để làm điều này đã tồn tại?


Bạn có nghĩa là bạn muốn 'làm phẳng' dữ liệu thành một tập hợp tô pô đúng không?
nagytech

@Geoist ZonalStats yêu cầu đa giác không trùng nhau. Khi bạn có một bộ sưu tập chồng chéo, giải pháp rõ ràng nhưng không hiệu quả là lặp qua các polys và tính toán các chỉ số khu vực từng cái một. Sẽ hiệu quả hơn khi chọn một tập hợp con của các polys không chồng lấp, áp dụng các zonalstats cho chúng và lặp lại. Câu hỏi hỏi làm thế nào để thực hiện các lựa chọn như vậy một cách hiệu quả.
whuber

whuber - Tôi nghĩ rằng @Geoist đang đề xuất tạo một tập hợp đa giác không chồng chéo từ các giao điểm của đa giác đầu vào. Nhìn vào hình ảnh này - (không thể đăng hình ảnh trong các bình luận?). Đầu vào ở bên trái. Toàn bộ khu vực được bao phủ bởi ba đa giác, mỗi đa giác giao nhau với cả hai khu vực khác. Các tập hợp con không chồng chéo duy nhất là các singletons và chúng không thỏa mãn yêu cầu của Gotanuki rằng liên minh sẽ lấp đầy không gian. Tôi nghĩ Geoist đang đề xuất tạo tập hợp các vùng không giao nhau ở bên phải, có giá trị cho zonalstats
Llaves

Tôi nghĩ rằng có một số nhầm lẫn về những gì các sản phẩm cuối cùng nên được. Bạn có thể cung cấp một ví dụ? Giải thích của tôi là bạn muốn đầu ra là một lựa chọn các đa giác không trùng nhau - trong khi loại bỏ hoặc hòa tan các đa giác còn lại. Bạn đang làm việc với một hoặc nhiều lớp tính năng?
Aaron

1
Âm thanh với tôi như @gotanuki đang muốn tạo số lượng lớp tính năng tối thiểu chỉ chứa các đa giác không chồng lấp từ một lớp tính năng đa giác với đa giác chồng chéo
PolyGeo

Câu trả lời:


14

Đây là một vấn đề màu đồ thị .

Hãy nhớ lại rằng tô màu đồ thị là sự gán màu cho các đỉnh của đồ thị theo cách mà không có hai đỉnh nào có chung một cạnh cũng sẽ có cùng màu. Cụ thể, các đỉnh (trừu tượng) của đồ thị là các đa giác. Hai đỉnh được kết nối với một cạnh (không bị chặn) bất cứ khi nào chúng giao nhau (dưới dạng đa giác). Nếu chúng ta lấy bất kỳ giải pháp cho vấn đề - đó là một chuỗi các (nói k ) bộ sưu tập rời nhau của đa giác - và chỉ định một màu duy nhất cho mỗi bộ sưu tập trong chuỗi, sau đó chúng tôi sẽ có được một k -coloring của đồ thị . Đó là mong muốn để tìm một k nhỏ .

Vấn đề này là khá khó khăn và vẫn chưa được giải quyết cho các biểu đồ tùy ý. Hãy xem xét một giải pháp gần đúng mà đơn giản để viết mã. Một thuật toán tuần tự nên làm. Thuật toán Welsh-Powell là một giải pháp tham lam dựa trên thứ tự giảm dần của các đỉnh theo mức độ. Được dịch sang ngôn ngữ của đa giác gốc, đầu tiên sắp xếp các đa giác theo thứ tự giảm dần của số lượng đa giác khác mà chúng trùng nhau. Làm việc theo thứ tự, cung cấp cho đa giác đầu tiên một màu ban đầu. Trong mỗi bước tiếp theo, hãy thử tô màu cho đa giác tiếp theo bằng một màu hiện có: đó là chọn một màu khôngđã được sử dụng bởi bất kỳ hàng xóm của đa giác đó. .

Khi bạn đã đạt được màu với một số lượng nhỏ màu, hãy thực hiện màu zonalstats theo màu: bằng cách xây dựng, bạn được đảm bảo rằng không có hai đa giác của một màu trùng nhau.


Đây là mã mẫu trong R. (Mã Python sẽ không khác nhiều.) Đầu tiên, chúng tôi mô tả sự chồng chéo giữa bảy đa giác được hiển thị.

Bản đồ bảy đa giác

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)

Đó là, đa giác 1 và 2 trùng nhau, và đa giác 2 và 3, 3 và 4, ..., 1 và 7 cũng vậy.

Sắp xếp các đỉnh theo mức độ giảm dần:

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))]

Thuật toán tô màu tuần tự (thô) sử dụng màu có sẵn sớm nhất chưa được sử dụng bởi bất kỳ đa giác chồng chéo nào:

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
}

Khởi tạo cấu trúc dữ liệu ( colorscolor.next) và áp dụng thuật toán:

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

Chia đa giác thành các nhóm theo màu:

split(vertices, colors)

Đầu ra trong ví dụ này sử dụng bốn màu:

$`1`
[1] 2 4

$`2`
[1] 3 6 7

$`3`
[1] 5

$`4`
[1] 1

Bốn màu của đa giác

Nó đã phân vùng các đa giác thành bốn nhóm không chồng chéo. Trong trường hợp này, giải pháp không tối ưu ({{3,6,5}, {2,4}, {1,7}} là ba màu cho biểu đồ này). Nói chung, giải pháp không nên quá tệ.


Tôi không chắc chắn nếu điều này trả lời câu hỏi, hoặc câu hỏi là gì, nhưng đó là một câu trả lời tốt không hơn không kém.
nagytech

@Geoist Có cách nào để tôi có thể làm cho hình minh họa rõ ràng hơn hoặc giải thích vấn đề tốt hơn không?
whuber

6

Phương pháp được đề xuất bởi #whuber đã truyền cảm hứng cho tôi để có một hướng đi mới, và đây là giải pháp hấp dẫn của tôi, trong hai chức năng. Trường đầu tiên, được gọi là CountOverlaps, tạo hai trường, "chồng lấp" và "ovlpCount" để ghi lại cho mỗi poly mà polys chồng chéo với nó và có bao nhiêu trùng lặp xảy ra. Hàm thứ hai, explodeOverlaps, tạo trường thứ ba, "expl", cung cấp một số nguyên duy nhất cho mỗi nhóm các polys không chồng lấp. Sau đó, người dùng có thể xuất fc mới dựa trên trường này. Quá trình này được chia thành hai chức năng bởi vì tôi nghĩ rằng công cụ CountOverlaps có thể tự chứng minh là hữu ích. Xin thứ lỗi cho sự chậm chạp của mã (và quy ước đặt tên bất cẩn), vì nó khá sơ bộ, nhưng nó hoạt động. Cũng đảm bảo rằng "idName" trường đại diện cho một trường có ID duy nhất (chỉ được kiểm tra với ID số nguyên). Cảm ơn bạn đã cung cấp cho tôi khuôn khổ cần thiết để tiếp cận vấn đề này!

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
Để kết nối điều này với giải pháp của tôi: bạn countOverlapstương ứng với hai dòng nbrhoods <- sapply(vertices, neighbors); degrees <- sapply(nbrhoods, length)trong mã của tôi: degreeslà số lượng trùng lặp. Tất nhiên mã của bạn dài hơn bởi vì nó phản ánh hầu hết các phân tích GIS được đưa ra trong giải pháp của tôi: cụ thể là trước tiên bạn xác định đa giác nào trùng nhau và cuối cùng bạn sử dụng giải pháp để xuất bộ dữ liệu đa giác. Sẽ là một ý tưởng tốt để đóng gói các tính toán theo lý thuyết đồ thị, vì vậy nếu bạn tìm thấy một thuật toán tô màu tốt hơn, thì có thể dễ dàng cắm vào.
whuber

1

Đã được một lúc, nhưng tôi đã sử dụng mã này cho ứng dụng của riêng mình và nó đã hoạt động rất tốt - cảm ơn bạn. Tôi đã viết lại một phần của nó để cập nhật nó, áp dụng nó cho các dòng (với dung sai) và tăng tốc đáng kể (bên dưới - Tôi đang chạy nó trên 50 triệu bộ đệm giao nhau và chỉ mất vài giờ).

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

Trong trường hợp này tôi thường sử dụng phương pháp sau:

  • Vượt qua lớp Feature thông qua UNION; (Nó phá vỡ các đa giác trong tất cả các giao điểm của nó)
  • Thêm các trường X, Y và Area và tính toán chúng;
  • Hòa tan kết quả theo các trường X, Y, Area.

Tôi tin rằng kết quả sẽ là kết quả bạn muốn và thậm chí bạn có thể đếm số lượng trùng lặp. Không biết về mặt hiệu suất sẽ tốt hơn cho bạn hay không.


2
phương pháp này không đưa bạn đến sản phẩm mong muốn, đó là một loạt các lựa chọn tối thiểu hoặc các lớp tính năng duy nhất của bản gốc không trùng lặp. các sản phẩm sẽ được đưa vào thống kê khu vực và do đó việc giữ hình dạng ban đầu của từng tính năng là rất quan trọng.
ndimhypervol

Bạn nói đúng, xin lỗi. Tôi không hiểu rõ câu hỏi. Trong trường hợp đó, và tùy thuộc vào kích thước của raster, tôi thường chuyển đổi raster thành một lớp tính năng điểm tạm thời (mỗi ô một điểm) và thực hiện nối không gian giữa nó và lớp đa giác. Có thể cách tiếp cận không thân thiện và hiệu suất rất đơn giản nhưng hiệu quả và đa giác chồng chéo sẽ không gây ra cho bạn bất kỳ vấn đề gì.
Alexandre Neto

Nếu tôi hiểu chính xác ý của bạn về sự tham gia không gian này, thì giải pháp thứ hai của bạn vẫn không hiệu quả, Alexandre, bởi vì có một mối quan hệ nhiều-nhiều giữa các điểm và đa giác. Bất kể, đối với bất kỳ raster khá lớn, phương pháp dựa trên vectơ này sẽ cực kỳ kém hiệu quả và đối với các raster lớn thì sẽ không thể thực hiện được.
whuber

@whuber Bạn nói đúng về một quá trình rất chậm (Toke tôi khoảng nửa giờ với raster 4284 x 3009 và 2401 đa giác, trong RAM kép 2.8Ghz, RAM 3Gb với vista). Nhưng nó hoạt động, như tôi đã thử nó rồi. Trong Spatial Join, bạn phải sử dụng một đến một mối quan hệ và tổng hợp các giá trị raster (như trung bình, Sum, v.v ...). Kết quả sẽ là một lớp đa giác vector tương tự như ban đầu nhưng với một cột mới với các giá trị raster tổng hợp giao nhau với mỗi đa giác. Không phải là một giải pháp tối ưu, điều này có thể hữu ích cho những người có ít kỹ năng lập trình (như tôi :-)).
Alexandre Neto
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.