So sánh hai hình học trong ArcPy?


18

Tôi đang cố gắng so sánh hai lớp tính năng riêng biệt để xác định sự khác biệt giữa chúng (loại hàm khác). Quy trình làm việc cơ bản của tôi:

  1. Tôi trích xuất hình học bằng cách sử dụng SearchCoder
  2. Lưu hình học của hai lớp tính năng dưới dạng GeoJSON bằng cách sử dụng một sửa đổi __geo_interface__(lấy nó từ vanLondon return {'type': 'Polygon', 'coordinates': [[((pt.X, pt.Y) if pt else None) for pt in part] for part in self]} ). Điều này là để tránh đối tượng hình học được chia sẻ mà ESRI sử dụng với các con trỏ và không có khả năng tạo các bản sao sâu (một số cuộc thảo luận ở đây trên gis.stackexchange nói về nó).
  3. Kiểm tra hình học của hai lớp tính năng dựa trên một định danh duy nhất. Ví dụ, so sánh hình học FC1 OID1 với hình học FC2 OID1. Để lấy hình học làm đối tượng ESRI, hãy gọi arcpy.AsShape()(sửa đổi để đọc đa giác có lỗ (xem điểm 2 ở trên) với return cls(Array([map(lambda p: Point(*p) if p is not None else Point(), part) for part in coordinates])). So sánh đơn giản geom1.equals(geom2)như được chỉ ra trong Lớp Hình học .

Tôi hy vọng sẽ tìm thấy ~ 140 thay đổi trong hình học, nhưng tập lệnh của tôi khẳng định có 430. Tôi đã cố kiểm tra các biểu diễn GeoJSON đó và chúng giống hệt nhau, nhưng Lớp Hình học bằng () từ chối nói như vậy.

Một ví dụ dưới đây:

>>> geom1geoJSON 
{'type': 'Polygon', 'coordinates': [[(-122.8423481559999, 47.060497293000083), (-122.84239755599992, 47.059262423000064), (-122.84416913599989, 47.059309693000046), (-122.84416913599989, 47.060497293000083), (-122.8423481559999, 47.060497293000083)]]}
>>> geom2geoJSON 
{'type': 'Polygon', 'coordinates': [[(-122.8423481559999, 47.060497293000083), (-122.84239755599992, 47.059262423000064), (-122.84416913599989, 47.059309693000046), (-122.84416913599989, 47.060497293000083), (-122.8423481559999, 47.060497293000083)]]}
>>> geom1 = arcpy.AsShape(geom1geoJSON)
>>> geom2 = arcpy.AsShape(geom2geoJSON)
>>> geom1.equals(geom2)
False
>>> geom2.equals(geom1)
False

Hành vi dự kiến ​​ở đây phải là Đúng (không sai).

Có ai có bất cứ đề nghị nào trước khi tôi chuyển mọi thứ sang hình học ogr không? (Tôi lưỡng lự như ogr.CreateGeometryFromGeoJSON () sẽ là một chuỗi, và arcpy của __geo_interface__lợi nhuận một cuốn từ điển và tôi cảm thấy như tôi đang bổ sung thêm tính phức tạp).

Tìm thấy các tài nguyên sau hữu ích, mặc dù chúng không trả lời câu hỏi:

  1. Arcpy.Geometry câu hỏi ở đây trên gis.stackexchange.com đã được liên kết ở trên trong văn bản của tôi.
  2. Lỗi trong lớp Đa giác của Arcpy từ các diễn đàn arcgis.com (rõ ràng có rất nhiều lỗi chính xác trong ArcGIS 10.0 mà về mặt lý thuyết đã được sửa trong 10.1 nhưng tôi không thể xác minh rằng, trong 10.0 SP5 bạn vẫn gặp lỗi).

Câu trả lời:


12

Vấn đề rất có thể là một trong những điểm chính xác . Trong trường hợp của bạn, bạn đã trích xuất hình học bằng arcpy và bạn đã khớp chúng với RUID của bạn.

Hạnh phúc vì bạn đã cài đặt Arcpy, bạn đã gặp khó khăn, điều này làm cho việc so sánh các tập hợp mảng số trở nên dễ dàng. Trong trường hợp này, tôi đề xuất hàm numpy.allclose , có sẵn trong numpy 1.3.0 (được cài đặt với ArcGIS 10).

Từ các mẫu bạn đã đưa ra ở trên

geom1geoJSON = {'type': 'Polygon', 'coordinates': [[(-122.8423481559999, 47.060497293000083), (-122.84239755599992, 47.059262423000064), (-122.84416913599989, 47.059309693000046), (-122.84416913599989, 47.060497293000083), (-122.8423481559999, 47.060497293000083)]]}
geom2geoJSON = {'type': 'Polygon', 'coordinates': [[(-122.8423481559999, 47.060497293000083), (-122.84239755599992, 47.059262423000064), (-122.84416913599989, 47.059309693000046), (-122.84416913599989, 47.060497293000083), (-122.8423481559999, 47.060497293000083)]]}

import numpy as np

close = np.allclose(np.array(geom1geoJSON["coordinates"]), np.array(geom2geoJSON["coordinates"]), atol=1e-7)
#Returns True

Các atoltừ khóa xác định giá trị khoan dung.

Lưu ý rằng bạn hoàn toàn không nên sử dụng arcpy.AsShape. Không bao giờ. Như tôi đã lưu ý trong câu hỏi này (/ phích cắm không biết xấu hổ) có một lỗi đã biết trong ArcGIS, đó là cắt ngắn hình học khi chúng được tạo mà không có hệ tọa độ (ngay cả sau khi đặt env.XYTolerancebiến môi trường). Trong arcpy.AsShapekhông có cách nào để tránh điều này. May mắn thay geometry.__geo_interface__, trích xuất các hình học chính xác từ một hình học hiện có (mặc dù nó không xử lý các đa giác phức tạp mà không có sửa chữa từ @JasonScheirer).


Cảm ơn bạn. Tôi đã không nghĩ đến việc sử dụng numpy để làm điều này. Một giải pháp khác dường như là sử dụng mô-đun thập phân và thực hiện điều đó, nhưng nó đòi hỏi nhiều công việc hơn.
Michalis Avraam

Tôi nghĩ rằng điều quan trọng là phải đặt numpy.allclose() rtoltham số thành 0. Theo mặc định, đó là 1e-05 và nó có thể dẫn đến dung sai lớn nếu các giá trị mảng lớn xem: stackoverflow.com/a/57063678/1914034
Bên dưới Radar

11

Độ chính xác tọa độ sẽ là một xem xét quan trọng ở đây. Số dấu phẩy động không thể được lưu trữ chính xác.

Nếu bạn sử dụng công cụ So sánh tính năng , nó có đưa ra kết quả mong đợi bằng cách sử dụng dung sai XY mặc định không?


Tôi đã không kiểm tra công cụ So sánh tính năng vì công cụ tôi đang xây dựng thực sự so sánh các tính năng riêng lẻ di chuyển giữa các lớp tính năng khác nhau. Điều đó có nghĩa là, một tính năng có thể chuyển từ CityRoads sang CountyRoads, vì vậy tôi cần tìm hiểu xem có gì thay đổi trong hình học và các thuộc tính khác với lớp tính năng giữ nó không. Có tổng cộng 24 lớp tính năng và các tính năng có thể di chuyển giữa chúng. So sánh tính năng sẽ chỉ so sánh 2 lớp tính năng, vì vậy nó có thể cho tôi biết nếu nó không còn tồn tại trong FC. Sau đó, tôi vẫn cần so sánh tính năng này để đảm bảo nó không thay đổi
Michalis Avraam

Tôi đã kiểm tra công cụ So sánh tính năng với dung sai mặc định (8,983e-009 khá nhỏ nhưng đây là Tệp GDB) và nó báo cáo một số thay đổi, nhưng không phải là thay đổi phù hợp. Cụ thể, nó cho biết có 69 thay đổi hình học (tôi đoán tốt hơn trước) nhưng dường như giả định rằng OID là cách để xác định các tính năng độc đáo (tìm kiếm OID1 cũ và OID1 mới) không nhất thiết phải đúng (tôi đã đặt nó để sử dụng RUID của tôi như một loại nhưng nó không thích nó). Vì vậy, trở lại bảng vẽ.
Michalis Avraam

4

bên cạnh câu trả lời @ blah328, bạn có thể chọn so sánh hai bảng để báo cáo sự khác biệt và tương đồng với các giá trị bảng và định nghĩa trường với So sánh bảng .

Thí dụ:

import arcpy
from arcpy import env
arcpy.TableCompare_management(r'c:\Workspace\wells.dbf', r'c:\Workspace
\wells_new.dbf', 'WELL_ID', 'ALL', 'IGNORE_EXTENSION_PROPERTIES', 'WELL_DEPTH 0.001',
'#','CONTINUE_COMPARE', r'C:\Workspace\well_compare.txt' 

Cảm ơn bạn tôi sẽ xem xét nó khi tôi cố gắng so sánh dữ liệu thuộc tính. Hiện tại, có vẻ như tôi không thể so sánh hình học, điều này quan trọng hơn.
Michalis Avraam

3
def truncateCoordinates(myGeometry)
    trucated_coords = []
    partnum = 0

    for part in (myGeometry):
        for pnt in myGeometry.getPart(partnum):
            if pnt:
                trucated_coords.append("{:10.4f}".format(pnt.X))
                trucated_coords.append("{:10.4f}".format(pnt.Y))
             else:
                continue
        partnum += 1     
    return truncated_coords

Nếu .equals()chức năng không hoạt động như mong đợi và / hoặc tọa độ bị thay đổi một chút trong ArcGIS, bạn có thể xoa bóp tọa độ XY, sau đó so sánh Chuỗi tương đương với Hình học. Lưu ý, truncateCoordinates()cắt bỏ tất cả các giá trị ngoài vị trí thập phân thứ 4.

geom1 = truncateCoordinates(feature1.Shape)
geom2 = truncateCoordinates(feature2.Shape)

geom1 == geom2

@ klewis- Đó là một cách để so sánh một hình học, nhưng cảm giác như hình học.equals (hình học) sẽ trả về đúng khi bạn so sánh chính xác hình học đó. Cắt ngắn tọa độ là một loại hack theo một nghĩa nào đó. Có lẽ ESRI cần bắt đầu sử dụng loại thập phân () thay vì float nếu chúng không thể xử lý chính xác các giá trị dấu phẩy động nhưng có thể biểu diễn chúng dưới dạng các chuỗi bằng nhau.
Michalis Avraam

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.