ArcPy에서 두 가지 형상을 비교하십니까?


18

두 가지 기능 클래스를 비교하여 차이점을 식별하려고합니다 (일부 diff 함수). 내 기본 워크 플로우 :

  1. SearchCursor를 사용하여 지오메트리를 추출합니다.
  2. 수정 된 __geo_interface__( valveLondon 에서 가져옴return {'type': 'Polygon', 'coordinates': [[((pt.X, pt.Y) if pt else None) for pt in part] for part in self]} )을 사용하여 두 피쳐 클래스의 형상을 GeoJSON으로 저장하십시오 . 이것은 ESRI가 커서와 함께 사용하는 공유 지오메트리 객체와 딥 카피를 만들 수 없다는 것을 피하기위한 것입니다 (gis.stackexchange에 대한 일부 논의는 이에 대해 설명합니다).
  3. 고유 식별자를 기반으로 두 피처 클래스의 형상을 확인하십시오. 예를 들어 FC1 OID1 지오메트리와 FC2 OID1 지오메트리를 비교하십시오. 지오메트리를 ESRI 객체 인스턴스로 가져 오려면을 호출 arcpy.AsShape()하여 구멍이있는 다각형을 읽도록 수정합니다 (위의 포인트 2 참조) return cls(Array([map(lambda p: Point(*p) if p is not None else Point(), part) for part in coordinates])). 비교는 지오메트리 클래스에geom1.equals(geom2) 표시되어 있습니다.

지오메트리에서 ~ 140 개의 변경 사항을 찾을 것으로 예상되지만 스크립트에는 430 개가 있다고 주장합니다. GeoJSON 표현을 확인하려고 시도했지만 동일하지만 Geometry Class equals ()는 그렇지 않습니다.

예는 다음과 같습니다.

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

여기서 예상되는 동작은 False가 아닌 True 여야합니다.

내가 모든 것을 ogr 기하학으로 옮기기 전에 어떤 제안이 있습니까? (ogr.CreateGeometryFromGeoJSON ()이 문자열을 기대하고 arcpy 's __geo_interface__가 사전을 반환하므로 복잡성을 추가하는 것처럼 느낍니다.

다음 질문에 답하지 않아도 도움이되는 다음 자료를 찾아보십시오.

  1. 내 텍스트에서 위에 링크 된 gis.stackexchange.com의 arcpy.Geometry 질문 입니다.
  2. arcgis.com 포럼 에서 arcpy의 Polygon 클래스의 오류 (아마도 ArcGIS 10.0에는 이론적으로 10.1에서 수정 된 많은 정밀 오류가 있지만 10.0 SP5에서는 여전히 오류가 있음을 확인할 수 없습니다).

답변:


12

이 문제는 대부분 부동 소수점 정밀도 중 하나입니다 . 귀하의 경우 이미 arcpy를 사용하여 형상을 추출했으며 RUID와 일치시킵니다.

행복하게 arcpy를 설치 한 후 numpy가있어 숫자 배열 세트를 쉽게 비교할 수 있습니다. 이 경우 numpy 1.3.0에서 사용할 수 있는 numpy.allclose 함수를 제안합니다 (ArcGIS 10과 함께 설치).

위에서 준 샘플에서

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

atol키워드는 공차 값을 지정합니다.

전혀 사용해서는 안됩니다 arcpy.AsShape. 이제까지. 이 질문 (/ shameless plug) 에서 언급했듯이 ArcGIS에는 좌표계없이 생성 될 때 ( env.XYTolerance환경 변수를 설정 한 후에도) 도형을 자르는 알려진 버그가 있습니다. 에서 arcpy.AsShape이를 방지 할 수있는 방법이 없습니다. 다행히도 geometry.__geo_interface__기존 지오메트리에서 올바른 지오메트리를 추출합니다 (@JasonScheirer의 수정없이 복잡한 폴리곤을 처리하지는 않지만).


감사합니다. 나는 이것을하기 위해 numpy를 사용하는 것을 생각하지 않았다. 또 다른 해결책은 10 진수 모듈을 사용하고있는 것으로 보이지만 훨씬 더 많은 작업이 필요합니다.
Michalis Avraam

numpy.allclose() rtol매개 변수를 0 으로 설정하는 것이 중요하다고 생각 합니다. 기본적으로 1e-05이며 배열 값이 큰 경우 큰 공차를 유발할 수 있습니다. stackoverflow.com/a/57063678/1914034
레이더 아래

11

여기서 좌표 정밀도는 중요한 고려 사항이 될 것입니다. 부동 소수점 숫자는 정확하게 저장할 수 없습니다.

당신이 사용하는 경우 비교 기능 도구를, 그것은 기본 XY 허용 오차를 사용하여 예상되는 결과와 오는가?


빌드하는 도구가 실제로 다른 피쳐 클래스간에 이동하는 개별 피쳐를 비교하므로 피쳐 비교 도구를 확인하지 않았습니다. 즉, 지형지 물이 CityRoads에서 CountyRoads로 이동할 수 있으므로 지형지 물과 지형지 물을 보유한 지형지 ​​물 이외의 속성에서 변경된 사항이 있는지 확인해야합니다. 총 24 개의 기능 클래스가 있으며 기능간에 이동할 수 있습니다. 기능 비교는 2 개의 기능 클래스 만 비교하므로 FC에 더 이상 존재하지 않는지 알 수 있습니다. 그럼 난 여전히 변경하지 않은 보장하기 위해 기능을 비교해야
칼리스 아브람

기능 비교 도구를 기본 허용 오차 (8.983e-009로 매우 작지만 파일 GDB 임)로 확인했으며 일부 변경 사항은보고하지만 올바른 변경 사항은보고하지 않습니다. 구체적으로 말하면 69 개의 ​​지오메트리 변경 사항이 있지만 (이전보다 나은 것 같음) OID는 반드시 고유하지 않은 고유 한 기능 (이전 OID1 및 새 OID1 검색)을 식별하는 방법이라고 가정합니다 (사용하도록 설정했습니다) 내 RUID는 일종이지만 좋아하지는 않았습니다). 다시 드로잉 보드로 돌아갑니다.
Michalis Avraam

4

옆 @ blah328 대답, 당신 하바 선택과 표 값과 필드 정의와 차이점과 유사점보고 두 테이블을 비교하는 비교 표 .

예:

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' 

속성 데이터를 비교하려고 할 때 살펴 보겠습니다. 지금은 지오메트리를 비교할 수없는 것 같습니다. 더 중요합니다.
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

경우 .equals()예상대로 기능이 작동하지 않는 및 / 또는 좌표가 약간는 ArcGIS에서 변경되어, 당신은 다음 기하학의 캐릭터와 동등한 비교는 XY 좌표를 마사지 할 수 있습니다. 공지 사항, truncateCoordinates()4 소수 자릿수를 넘어 모든 값 오프 갈비.

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

geom1 == geom2

@ klewis- 이것은 지오메트리를 비교하는 한 가지 방법이지만, 동일한 지오메트리를 비교할 때 geometry.equals (geometry)가 true를 반환해야합니다. 좌표 자르기는 일종의 해킹입니다. 내부적으로 부동 소수점 값을 올바르게 처리 할 수 ​​없지만 동일한 문자열로 표시 할 수있는 경우 ESRI는 float 대신 decimal () 유형을 사용하여 시작해야합니다.
Michalis Avraam

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.