ArcPy'de iki geometri mi karşılaştırıyorsunuz?


18

Aralarındaki farkları (diff fonksiyonu tür) tanımlamak için iki ayrı özellik sınıfları karşılaştırmaya çalışıyorum. Temel iş akışım:

  1. Bir SearchCursor kullanarak geometrileri çıkarıyorum
  2. Değiştirilmiş __geo_interface__( valveLondon'dan return {'type': 'Polygon', 'coordinates': [[((pt.X, pt.Y) if pt else None) for pt in part] for part in self]} ) kullanarak iki özellik sınıfının geometrilerini GeoJSON olarak kaydedin . Bunun amacı, ESRI'nin imleçlerle kullandığı paylaşılan geometri nesnesinden ve derin kopyalar yapamamaktan kaçınmaktır (gis.stackexchange ile ilgili bazı tartışmalar bunun hakkında konuşur).
  3. Benzersiz bir tanımlayıcıya dayalı olarak iki özellik sınıfının geometrilerini kontrol edin. Örneğin, FC1 OID1 geometrisini FC2 OID1 geometrisiyle karşılaştırın. Bir ESRI nesne, örneğin, çağrı olarak geometri elde etmek için arcpy.AsShape()(deliklerin (yukarıdaki noktası 2 ye bakınız) ile çokgenler değiştirilmiştir return cls(Array([map(lambda p: Point(*p) if p is not None else Point(), part) for part in coordinates])). Sadece karşılaştırma olduğu geom1.equals(geom2)şekilde belirtilen geometri sınıfı .

Geometrilerde ~ 140 değişiklik bulmayı bekliyorum, ama senaryom 430 olduğu konusunda ısrar ediyor. Bu GeoJSON temsillerini kontrol etmeye çalıştım ve aynılar, ancak Geometry Sınıfı eşittir () bunu reddetti.

Aşağıda bir örnek verilmiştir:

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

Burada beklenen davranış Doğru (Yanlış değil) olmalıdır.

Her şeyi ogr geometrilerine taşımadan önce herhangi bir öneriniz var mı? (Ben ogr.CreateGeometryFromGeoJSON () bir dize bekliyor gibi tereddüt ve arcpy's __geo_interface__bir sözlük döndürür ve ekstra karmaşıklık ekliyorum gibi hissediyorum).

Soruyu cevaplamasalar bile aşağıdaki kaynakları yararlı buldular:

  1. arcpy.Geometri sorusu , yukarıda metnimde bağlantılı olan gis.stackexchange.com adresinde.
  2. Arcgis.com forumlarından arcpy'nin Polygon sınıfındaki hatalar (görünüşe göre 10.1'de teorik olarak düzeltilen ArcGIS 10.0'da çok fazla hassas hata var, ancak 10.0 SP5'te hala hatayı aldığınızı doğrulayamıyorum).

Yanıtlar:


12

Sorun büyük olasılıkla kayan nokta hassasiyetidir . Sizin durumunuzda geometrileri zaten arcpy kullanarak çıkardınız ve bunları RUID'nizle eşleştirdiniz.

Mutlu bir şekilde arcpy kurulduğundan beri numpy var, bu da sayısal dizi setlerini karşılaştırmayı kolaylaştırır. Bu durumda , numpy 1.3.0'da (ArcGIS 10 ile yüklü) bulunan numpy.allclose işlevini öneririm .

Yukarıda verdiğiniz örneklerden

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

atolAnahtar kelime tolerans değerini belirtir.

Hiç kullanmamanız gerektiğini unutmayın arcpy.AsShape. Hiç. Bu soruda belirtildiği gibi (/ utanmaz fiş) ArcGIS'te, bir koordinat sistemi olmadan oluşturulduklarında ( env.XYToleranceortam değişkenini ayarladıktan sonra bile) geometrileri kesen bilinen bir hata var . Bundan arcpy.AsShapekaçınmanın bir yolu yok. Neyse ki geometry.__geo_interface__mevcut geometrilerden doğru geometrileri çıkarır (ancak @ JasonScheirer'ın düzeltmesi olmadan karmaşık çokgenleri işlemez).


Teşekkür ederim. Bunu yapmak için numpy kullanmayı düşünmedim. Başka bir çözüm ondalık modülü kullanıyor ve bunun üzerinde çalışıyor gibi görünüyor, ancak çok daha fazla çalışma gerektiriyor.
Michalis Avraam

numpy.allclose() rtolParametreyi 0 olarak ayarlamak önemli olacaktır. Varsayılan olarak 1e-05'dir ve diziler değerleri büyükse büyük bir toleransa yol açabilir: stackoverflow.com/a/57063678/1914034
Radar

11

Koordinat hassasiyeti burada önemli bir husus olacaktır. Kayan nokta numaraları tam olarak kaydedilemez.

Eğer kullanırsanız karşılaştırın Özelliği aracı, varsayılan XY toleransını kullanarak beklenen sonuç buluyor?


Oluşturduğum araç aslında farklı özellik sınıfları arasında hareket eden özellikleri karşılaştırdığından Özellik Karşılaştırma aracını kontrol etmedim. Yani, bir özellik CityRoads CountyRoads taşıyabilir, bu yüzden geometri ve özellik sınıfı dışında tutan nitelikleri değişti olmadığını anlamaya ihtiyacım var. Toplam 24 özellik sınıfı vardır ve bunlar arasında hareket edebilir. Özellik Karşılaştırması yalnızca 2 özellik sınıfını karşılaştırır, böylece artık bir FC'de bulunmadığını bana söyleyebilir. O zaman hala değişmediğinden emin olmak için özelliği karşılaştırmam gerekiyor
Michalis Avraam

Özellik Karşılaştırma aracını varsayılan toleransla (8.983e-009 olan oldukça küçük, ancak bu bir Dosya GDB'si) kontrol ettim ve bazı değişiklikleri bildiriyor, ancak doğru olanları değil. Özellikle, 69 geometri değişikliği (sanırım öncekinden daha iyi) olduğunu söylüyor, ancak OID'nin mutlaka doğru olmayan benzersiz özellikleri (eski OID1 ve yeni OID1'i arar) tanımlamanın yolu olduğunu varsayıyorum (kullanmak için ayarladım) benim RUID bir tür olarak ama hoşuna gitmedi). Yani silbaştan.
Michalis Avraam

4

@ blah328 yanıtının yanı sıra, farklılıkları ve benzerlikleri bildirmek için iki tabloyu tablo değerleri ve alan tanımları ile Tablo Karşılaştırması ile karşılaştırmayı tercih edebilirsiniz .

Misal:

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' 

Özellik verilerini karşılaştırmaya çalıştığımda teşekkür ederim. Şimdilik, daha önemli olan geometrileri karşılaştıramıyorum gibi görünüyor.
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

Eğer .equals()beklendiği gibi işlev çalışmıyor ve / veya koordinatları hafifçe ArcGIS değişmiş, daha sonra Geometri dize eşdeğer karşılaştırmak, XY koordinatlarını masaj yapabilirsiniz. Dikkat edin, truncateCoordinates()4. ondalık basamaktan sonraki tüm değerleri keser.

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

geom1 == geom2

@ klewis- Bu, bir geometriyi karşılaştırmanın bir yoludur, ancak geometri gibi hissedilir. tam olarak aynı geometriyi karşılaştırdığınızda eşittir (geometri) doğru dönmelidir. Koordinatları kısaltmak bir anlamda bir hack'tir. Belki de, kayan nokta değerlerini dahili olarak doğru şekilde işleyemedikleri, ancak eşit dizeler olarak gösterebildikleri takdirde, ESRI'nin kayan nokta yerine ondalık () türünü kullanmaya başlaması gerekir.
Michalis Avraam

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.