比较ArcPy中的两个几何?


18

我正在尝试比较两个单独的要素类,以识别它们之间的差异(某种diff函数)。我的基本工作流程:

  1. 我使用SearchCursor提取几何
  2. 使用修改后的两个要素类的几何形状另存为GeoJSON __geo_interface__(从valveLondon获取 return {'type': 'Polygon', 'coordinates': [[((pt.X, pt.Y) if pt else None) for pt in part] for part in self]})。这是为了避免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)为在所指示的Geometry类

我期望找到约140个几何形状的变化,但是我的脚本坚持认为有430个变化。我试图检查那些GeoJSON表示形式,它们是相同的,但是Geometry类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

这里的预期行为应为True(不是False)。

在将所有内容迁移到几何图形之前,有人对它有任何建议吗?(我很犹豫,因为ogr.CreateGeometryFromGeoJSON()需要一个字符串,而arcpy的__geo_interface__返回了一个字典,我觉得我正在增加额外的复杂性)。

发现以下资源很有帮助,即使它们没有回答问题:

  1. gis.stackexchange.com上的arcpy.Geometry问题在我的文字中上面已链接。
  2. 来自arcgis.com论坛的arcpy的Polygon类中的错误(显然,ArcGIS 10.0中存在许多精度错误,理论上在10.1中已解决此问题,但我无法验证,在10.0 SP5中您仍然会收到错误)。

Answers:


12

这个问题很可能是浮点精度之一。在您的情况下,您已经使用arcpy提取了几何图形,并将它们与RUID进行了匹配。

令人高兴的是,由于安装了arcpy,因此有了numpy,这使比较数字数组集变得容易。在这种情况下,我建议使用numpy.allclose函数,该函数在numpy 1.3.0(与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插件)中指出的那样,ArcGIS中存在一个已知的错误,该错误会在没有坐标系的情况下(即使在设置env.XYTolerance环境变量之后)将几何图形截断。在arcpy.AsShape没有办法避免这种情况。幸运的是,geometry.__geo_interface__确实可以从现有几何图形中提取正确的几何图形(尽管没有@JasonScheirer的修复,它不能处理复杂的多边形)。


谢谢。我没有想到使用numpy来做到这一点。另一个解决方案似乎是使用小数模块并完成该工作,但是还需要做更多的工作。
Michalis Avraam,2012年

我认为将numpy.allclose() rtol参数设置为0 很重要。默认情况下,其值为1e-05,如果数组值较大,则可能会导致较大的公差,请参阅:stackoverflow.com/a/57063678/1914034
雷达下方

11

此处的坐标精度将是重要的考虑因素。浮点数不能准确存储。

如果使用“ 功能比较”工具,是否使用默认的XY公差得出预期结果?


我没有检查功能比较工具,因为我正在构建的工具实际上是比较在不同要素类之间移动的各个要素。也就是说,要素可以从CityRoads移至CountyRoads,因此我需要弄清楚除持有该要素的要素类之外,几何形状和属性是否发生了任何变化。共有24个要素类,要素可以在它们之间移动。“要素比较”将仅比较两个要素类,因此它可以告诉我它是否不再存在于FC中。然后,我仍然需要比较功能以确保它没有更改
Michalis Avraam

我使用默认公差(8.983e-009,它很小,但这是文件GDB)检查了功能比较工具,它报告了一些更改,但没有正确的更改。具体来说,它说有69种几何形状更改(我想比以前更好),但似乎假设OID是识别唯一特征(搜索旧OID1和新OID1)的方式,但不一定正确(我将其设置为使用我的RUID,但它不喜欢)。回到画板。
Michalis Avraam

4

除了@ blah328答案,您还可以选择比较两个表以使用Table Compare来报告具有表格值和字段定义的差异和相似性。

例:

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,2012年

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()除掉小数点后第四位的所有值。

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

geom1 == geom2

@ klewis-这是比较几何的一种方法,但是感觉就像geometry.equals(geometry)在比较完全相同的几何时应该返回true。从某种意义上说,截断坐标是一种骇客。如果ESRI无法在内部正确处理浮点值,但可以将它们表示为相等的字符串,则ESRI可能需要开始使用decimal()类型而不是float。
Michalis Avraam

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.