PyQGIS'de bir döngüde Uzamsal Sorgu Gerçekleştirme


9

: Yapmak çalışıyorum ne döngü bir nokta shape içinden ve düşen her noktayı seçmek içine bir poligon.

Aşağıdaki kod, bir kitapta bulduğum bir uzamsal sorgu örneğinden esinlenmiştir:

mitte_path = r"D:\PythonTesting\SelectByLocation\mitte.shp"
punkte_path = r"D:\PythonTesting\SelectByLocation\punkte.shp"

polygon = QgsVectorLayer(mitte_path, 'Mitte', 'ogr')
points = QgsVectorLayer(punkte_path, 'Berlin Punkte', 'ogr')

QgsMapLayerRegistry.instance().addMapLayer(polygon)
QgsMapLayerRegistry.instance().addMapLayer(points)

polyFeatures = polygon.getFeatures()

pointsCount = 0

for poly_feat in polyFeatures:
    polyGeom = poly_feat.geometry()
    pointFeatures = points.getFeatures(QgsFeatureRequest().setFilterRect(polyGeom.boundingBox()))
    for point_feat in pointFeatures:
        points.select(point_feat.id())
        pointsCount += 1

print 'Total:',pointsCount

Bu çalışır ve veri kümeleri seçer, ancak sorun sınırlayıcı kutu ile seçer , bu yüzden Açıkçası ilgilenmiyorum noktaları döndürerek:

resim açıklamasını buraya girin

Qgis: selectbylocation kullanmadan yalnızca çokgen içindeki noktaları döndürmeye nasıl gidebilirim ?

İçinde () ve intersects () yöntemlerini kullanarak denedim , ama onları işe almak değildi, ben yukarıdaki koda başvurdu. Ama belki de anahtar onlar.

Yanıtlar:


10

Sen ( "Ray Casting" gibi) özel bir işlev gerekmez, her şey (PyQGIS içindedir içeren () içinde PyQGIS Geometri Taşıma )

polygons = [feature for feature in polygons.getFeatures()]
points = [feature for feature in points.getFeatures()]
for pt in points: 
     point = pt.geometry() # only and not pt.geometry().asPolygon() 
     for pol in polygons:
        poly = pol.geometry()
        if poly.contains(point):
             print "ok" 

veya bir satırda

 polygons = [feature for feature in polygons.getFeatures()]
 points = [feature for feature in points.getFeatures()]
 resulting = [pt for pt in points for poly in polygons if poly.geometry().contains(pt.geometry())]
 print len(resulting)
 ...

Ayrıca doğrudan kullanabilirsiniz

[pt.geometry().asPoint() for pt in points for poly in polygons if poly.geometry().contains(pt.geometry())]

Buradaki sorun, tüm geometrileri (çokgenler ve noktalar) tekrarlamanız gerektiğidir. Sınırlayıcı bir uzamsal indeks kullanmak daha ilginçtir: sadece mevcut geometrinizle kesişme şansı olan geometrileri tekrarlarsınız ('filtre', bkz. QgsSpatialIndex tarafından döndürülen özelliklere nasıl verimli bir şekilde erişilir? )



5

PyQGIS ile kullanmak için biraz uyarladığım "Ray Casting" algoritmasını kullanabilirsiniz:

def point_in_poly(point,poly):
    x = point.x()
    y = point.y()

    n = len(poly)
    inside = False

    p1x,p1y = poly[0]
    for i in range(n+1):
        p2x,p2y = poly[i % n]
        if y > min(p1y,p2y):
            if y <= max(p1y,p2y):
                if x <= max(p1x,p2x):
                    if p1y != p2y:
                        xints = (y-p1y)*(p2x-p1x)/(p2y-p1y)+p1x
                    if p1x == p2x or x <= xints:
                        inside = not inside
        p1x,p1y = p2x,p2y

    return inside

## Test
mapcanvas = iface.mapCanvas()

layers = mapcanvas.layers()

#For polygon 
polygon = [feature.geometry().asPolygon() 
            for feature in layers[1].getFeatures()]

points = [feat.geometry().asPoint() 
           for feat in layers[0].getFeatures()]

## Call the function with the points and the polygon
count = [0]*(layers[1].featureCount())

for point in points:
    i = 0
    for feat in polygon:
        if point_in_poly(point, feat[0]) == True:
            count[i] += 1
        i += 1

print count

Bu duruma uygulanır:

resim açıklamasını buraya girin

Python Konsolunda sonuç şuydu:

[2, 2]

İşe yaradı.

Düzenleme Notu:

Genin daha kısa önerisi ile kodlayın :

mapcanvas = iface.mapCanvas()

layers = mapcanvas.layers()

count = [0]*(layers[1].featureCount())

polygon = [feature
           for feature in layers[1].getFeatures()]

points = [feature
          for feature in layers[0].getFeatures()]

for point in points:

    i = 0

    geo_point = point.geometry()

    for pol in polygon:
        geo_pol = pol.geometry()

        if geo_pol.contains(geo_point):
            count[i] += 1
        i += 1

print count

Mükemmel referans ve harika cevap! Ancak, biraz önce gönderdiğim kişiyi çözüm olarak işaretleyeceğim, çünkü uygulanması biraz daha kolay. Yine de bir sürü upvotes ile ödüllendirilmelidir. Kesinlikle benden +1.
BritishSteel

Belirtmeniz gerekmez, if geo_pol.contains(geo_point) == True:çünkü if geo_pol.contains(geo_point)(her zaman Doğru)
gen

3

Bir iş arkadaşından bazı tavsiyeler ile sonunda () kullanarak çalışmak için aldım.

Genel mantık

  1. çokgen (ler) in özelliklerini alma
  2. puanların özelliklerini al
  3. çokgen dosyasındaki her özellik için döngü ve her biri için:
    • geometri almak
    • tüm noktalarda döngü
      • tek nokta geometrisi edinin
      • geometrinin çokgenin geometrisi içinde olup olmadığını test edin

İşte kod:

mitte_path = r"D:\PythonTesting\SelectByLocation\mitte.shp"
punkte_path = r"D:\PythonTesting\SelectByLocation\punkte.shp"

poly = QgsVectorLayer(mitte_path, 'Mitte', 'ogr')
points = QgsVectorLayer(punkte_path, 'Berlin Punkte', 'ogr')

QgsMapLayerRegistry.instance().addMapLayer(poly)
QgsMapLayerRegistry.instance().addMapLayer(points)

polyFeatures = poly.getFeatures()
pointFeatures = points.getFeatures()

pointCounter = 0

for polyfeat in polyFeatures:
    polyGeom = polyfeat.geometry()
    for pointFeat in pointFeatures:
        pointGeom = pointFeat.geometry()
        if pointGeom.within(polyGeom):
            pointCounter += 1
            points.select(pointFeat.id())

print 'Total',pointCounter

Bu ayrıca within () yerine intersects () ile de çalışır . Noktaları kullanırken, hangisini kullanmanız önemli değildir , çünkü ikisi de aynı sonucu döndürecektir. Satır / çokgen kontrol edilirken, bununla birlikte, önemli bir fark olabilir: () ile döner nesne içinde tamamen kesen () içinde tamamen nesneleri retuns ise, içinde ve vardır kısmen içinde (diğer bir deyişle bu kesiştiği özelliği olarak sahip adı gösterir).

resim açıklamasını buraya girin


Çözümünüzü denedim. Sadece bir çokgeniniz varsa çalışır, aksi takdirde sadece ilk çokgen içindeki noktalar seçilir
ilFonta
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.