RTree ile uzamsal dizinlerin kullanımını anlıyor musunuz?


13

RTree ile uzamsal dizinlerin kullanımını anlamakta zorlanıyorum.

Örnek: 300 arabelleğe alınmış noktam var ve her tamponun kesişim alanını çokgen şekil dosyasıyla bilmem gerekiyor. Çokgen şekil dosyasının> 20.000 çokgen vardır. Süreci hızlandırmak için mekansal indeksler kullanmam önerildi.

SO ... Çokgen şekil dosyam için uzamsal bir dizin oluşturursam, dosyaya bir şekilde "eklenir" mi yoksa dizin tek başına mı kalır? Yani, oluşturduktan sonra çokgen dosyasında kesişim fonksiyonumu çalıştırabilir ve daha hızlı sonuçlar alabilir miyim? Kavşak mekansal endeksler olduğunu "görecek" ve ne yapacağını bilecek mi? Veya, dizin üzerinde çalıştırmak ve daha sonra bu sonuçları FIDs veya benzeri bazı orijinal poligon dosyama ilişkilendirmek gerekir?

RTree belgeleri bana çok yardımcı olmuyor (muhtemelen sadece programlamayı öğreniyorum). Manuel olarak oluşturulan noktalarda okuyarak ve ardından pencerede bulunan kimlikleri döndüren diğer elle oluşturulan noktalara göre sorgulayarak nasıl dizin oluşturulacağını gösterirler. Mantıklı. Ancak, bunun dizinin geleceği orijinal dosyayla nasıl ilişkili olacağını açıklamazlar.

Böyle bir şeye gitmesi gerektiğini düşünüyorum:

  1. Her çokgen özelliğinin bbox'larını çokgen şekil dosyamdan al ve bunları uzamsal bir dizine yerleştirerek şekil dosyasındaki kimlikleriyle aynı bir kimlik verir.
  2. Kesişen kimlikleri almak için bu dizini sorgulayın.
  3. Daha sonra kesişimimi yalnızca orijinal şekil dosyamdaki dizinimi sorgulayarak tanımlanan özellikler üzerinde yeniden çalıştırın (bu son kısmı nasıl yapacağımı bilmiyorum).

Doğru fikrim var mı? Bir şey mi kaçırıyorum?


Şu anda sadece bir nokta özelliği içeren bir nokta şekil dosyası ve> 20.000 çokgen özellikleri içeren bir çokgen şekil dosyası üzerinde çalışmak için bu kodu almaya çalışıyorum.

Fiona'yı kullanarak şekil dosyalarını içe aktarıyorum, RTree kullanarak mekansal dizini ekliyorum ve Shapely kullanarak kesişim yapmaya çalışıyorum.

Test kodum şöyle:

#point shapefile representing location of desired focal statistic
traps = fiona.open('single_pt_speed_test.shp', 'r') 

#polygon shapefile representing land cover of interest 
gl = MultiPolygon([shape(pol['geometry']) for pol in fiona.open('class3_aa.shp', 'r')]) 

#search area
areaKM2 = 20

#create empty spatial index
idx = index.Index()

#set initial search radius for buffer
areaM2 = areaKM2 * 1000000
r = (math.sqrt(areaM2/math.pi))

#create spatial index from gl
for i, shape in enumerate(gl):
    idx.insert(i, shape.bounds)

#query index for ids that intersect with buffer (will eventually have multiple points)
for point in traps:
        pt_buffer = shape(point['geometry']).buffer(r)
        intersect_ids = pt_buffer.intersection(idx)

Ama TypeError almaya devam ediyorum: 'Polygon' nesnesi çağrılabilir değil


1
Bir uzamsal dizin, veri kümesine entegre ve şeffaftır (kullanıcı perspektifinden tek bir varlık değil, içerilir) Kavşakları gerçekleştiren yazılım, hızlı bir şekilde bilgilendirerek gerçek kavşağı gerçekleştirmek için kısa bir liste oluşturmak için uzamsal indeksler kullanır ve kullanır. daha yakından inceleme için hangi özelliklerin göz önünde bulundurulması gerektiği ve kesişme noktasına yakın bir yerde bulunmadığı yazılım Nasıl oluşturacağınız, yazılımınıza ve veri türünüze bağlıdır ... lütfen daha spesifik yardım için bu noktalar hakkında daha fazla bilgi verin. Bir şekil dosyası için bu .shx dosyasıdır.
Michael Stimson

4
.shx bir uzamsal dizin değildir. Sadece değişken genişlikli kayıt dinamik erişim ofset dosyasıdır. .sbn / .sbx, ArcGIS şekil dosyası uzamsal dizin çiftidir, ancak bunların özellikleri yayınlanmamıştır.
Vince

1
Ayrıca .qixMapServer / GDAL / OGR / SpatiaLite dörtlü endeksi
Mike T

Fikriniz, gerçek bir mekânsal indeksi olmayan Spatialite için mükemmel bir şekilde doğrudur. Diğer formatların çoğu, uzamsal dizinleri destekliyorlarsa, bunu şeffaf bir şekilde yapın.
user30184

2
Bu satırla oluşturduğunuz bir Polygon nesnesiyle düzgün bir şekilde içe TypeError: 'Polygon' object is not callableshapefor i, shape in enumerate(gl):
aktardığınız

Yanıtlar:


12

Bunun özü bu. R-ağacı çok hızlı bir ilk geçiş yapmanızı sağlar ve size "yanlış pozitifler" içeren bir dizi sonuç verir (sınırlama kutuları geometriler tam olarak olmadığında kesişebilir). Daha sonra adaylar kümesinin üzerinden geçersiniz (dizinlerine göre şekil dosyasından alırsınız) ve örneğin Shapely kullanarak matematiksel olarak hassas bir kavşak testi yaparsınız. Bu, PostGIS gibi uzamsal veritabanlarında kullanılan stratejiyle aynıdır.


1
Güzel cinas (GiST)! GiST normalde bir B-Ağacı varyantı olarak tanımlanır, ancak Postgresql'in bir GiST R-Tree uygulaması vardır. Her ne kadar wiki'nin alıntı yapmak için en iyi referans olmasa da, sınırlayıcı kutu aramalarını açıklamak için güzel bir diyagramı vardır .
MappaGnosis

Adım 2 ve 3'te olduğu gibi R-ağacı dizinini kullanmak için manuel bir yol öğrenmeye değer olabilir. Ayrı veritabanı tabloları olarak R-ağacını da destekleyen OGC GeoPackage hakkında bu blog bazı SQL ve ekran yakalamalarını gösterir openjump.blogspot.fi / 2014/02 /… .
user30184

9

Neredeyse anladınız, ama küçük bir hata yaptınız. intersectionDizini, intersectionarabelleğe alınan noktadaki yönteme iletmek yerine, uzamsal dizinde yöntemi kullanmanız gerekir . Sınırlayıcı kutuların üst üste geldiği özelliklerin bir listesini bulduğunuzda, tamponlu noktanızın gerçekten geometrilerle kesişip kesişmediğini kontrol etmeniz gerekir.

import fiona
from shapely.geometry import mapping
import rtree
import math

areaM2 = areaKM2 * 1000000
r = (math.sqrt(areaM2/math.pi))

# open both layers
with fiona.open('single_pt_speed_test.shp', 'r') as layer_pnt:
    with fiona.open('class3_aa.shp', 'r') as layer_land:

        # create an empty spatial index object
        index = rtree.index.Index()

        # populate the spatial index
        for fid, feature in layer_land.items():
            geometry = shape(feature['geometry'])
            idx.insert(fid, geometry.bounds)

        for feature in layer_pnt:
            # buffer the point
            geometry = shape(feature['geometry'])
            geometry_buffered = geometry.buffer(r)

            # get list of fids where bounding boxes intersect
            fids = [int(i) for i in index.intersection(geometry_buffered.bounds)]

            # access the features that those fids reference
            for fid in fids:
                feature_land = layer_land[fid]
                geometry_land = shape(feature_land['geometry'])

                # check the geometries intersect, not just their bboxs
                if geometry.intersects(geometry_land):
                    print('Found an intersection!')  # do something useful here

Arazi sınıfınıza en az mesafede olan noktaları bulmakla ilgileniyorsanız, distancebunun yerine yöntemi kullanabilirsiniz (önceki bölümden uygun bölümü değiştirin).

for feature in layer_pnt:
    geometry = shape(feature['geometry'])

    # expand bounds by r in all directions
    bounds = [a+b*r for a,b in zip(geometry.bounds, [-1, -1, 1, 1])]

    # get list of fids where bounding boxes intersect
    fids = [int(i) for i in index.intersection(geometry_buffered.bounds)]

    for fid in fids:
        feature_land = layer_land[fid]
        geometry_land = shape(feature_land['geometry'])

        # check the geometries are within r metres
        if geometry.distance(geometry_land) <= r:
            print('Found a match!')

Uzamsal dizininizi oluşturmak uzun zaman alıyorsa ve bunu birkaç kereden fazla yapacaksanız, dizini bir dosyaya serileştirmeye bakmalısınız. Belgelerde bunun nasıl yapılacağı açıklanmaktadır: http://toblerity.org/rtree/tutorial.html#serializing-your-index-to-a-file

Ayrıca, aşağıdaki gibi bir jeneratör kullanarak sınırlayıcı kutuları rtree'ye toplu olarak yüklemeye de bakabilirsiniz:

def gen(collection):
    for fid, feature in collection.items():
        geometry = shape(feature['geometry'])
        yield((fid, geometry.bounds, None))
index = rtree.index.Index(gen(layer_land))

2

Evet fikir bu. Python'da düzgün, Fiona ve geopandalar kullanarak bir r-ağaç uzamsal endeksi kullanma hakkındaki bu öğreticiden bir alıntı :

Bir r-ağacı ayrı ayrı nesneleri ve bunların sınırlayıcı kutularını (“r” “dikdörtgen” içindir) mekansal indeksin en düşük seviyesi olarak temsil eder. Daha sonra yakındaki nesneleri toplar ve bunları dizinin bir üst seviyesindeki toplam sınırlayıcı kutularıyla temsil eder. Daha yüksek seviyelerde, r-ağacı sınırlama kutularını toplar ve her şey bir üst seviye sınırlama kutusuna yerleştirilene kadar tekrarlayan sınırlama kutularıyla temsil eder. Arama yapmak için, r-ağacı bir sorgu kutusu alır ve en üst seviyeden başlayarak hangi (varsa) sınırlayıcı kutuların onu kesiştiğini görür. Daha sonra her kesişen sınırlama kutusunu genişletir ve içindeki alt sınırlama kutularından hangisinin sorgu kutusuyla kesiştiğini görür. Bu, tüm kesişen kutular en düşük seviyeye kadar aranana kadar tekrarlanır ve eşleşen nesneleri en düşük seviyeden döndürür.

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.