PyQGISのループで空間クエリを実行する


9

私がやろうとしていること:ポイントシェープファイルをループ、ポリゴンに該当する各ポイントを選択します。

次のコードは、本で見つけた空間クエリの例に基づいています。

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

これは機能し、データセットを選択しますが、問題はバウンディングボックスによって選択されるため、明らかに興味のないポイントを返すことです。

ここに画像の説明を入力してください

qgis:selectbylocationを使用せずにポリゴンのポイントのみを返すにはどうすればよいですか?

私はwithin()およびintersects()メソッドを使用しようとしましたが、それらを機能させなかったため、上記のコードに頼りました。しかし、おそらくそれらは結局のところ鍵です。

回答:


10

あなたは(すべてがPyQGISである、(「レイ・キャスティング」など)特別な機能を必要としない)(含まれている中での取り扱いPyQGISジオメトリ

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" 

または一行で

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

直接使用することもできます

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

ここでの問題は、すべてのジオメトリ(ポリゴンとポイント)を反復処理する必要があることです。境界空間インデックスを使用することはより興味深いです。現在のジオメトリと交差する可能性のあるジオメトリのみを反復処理します(「フィルター」、QgsSpatialIndexによって返される機能に効率的にアクセスする方法を参照してください)。



5

PyQGISで使用するために少し調整した「レイキャスティング」アルゴリズムを使用できます。

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

この状況に適用:

ここに画像の説明を入力してください

Pythonコンソールでの結果は次のとおりです。

[2, 2]

出来た。

ノートの編集:

より簡潔な遺伝子の提案を含むコード

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

素晴らしいリファレンスと素晴らしい答え!ただし、実装した方が少し簡単なので、先ほど投稿したものをソリューションとしてマークします。しかし、あなたは多くの賛成票で報われるべきです。確かに私からの+1。
BritishSteel、2015年

(常にTrue)でif geo_pol.contains(geo_point) == True:暗黙的であるため、指定する必要はありませんif geo_pol.contains(geo_point)
遺伝子

3

同僚からのアドバイスで、ようやくwithin()を使用して動作させることができました。

一般的なロジック

  1. ポリゴンの特徴を取得する
  2. ポイントの特徴を取得する
  3. ポリゴンファイルの各フィーチャをループし、それぞれについて:
    • ジオメトリを取得する
    • すべてのポイントをループする
      • 単一点のジオメトリを取得する
      • ジオメトリがポリゴンのジオメトリ内にあるかどうかをテストします

これがコードです:

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

これは、within()ではなくintersects()でも機能します。ポイントを使用する場合、どちらも同じ結果を返すため、どちらを使用しても問題ありません。ただし、ライン/ポリゴンをチェックする場合、重要な違いが生じる可能性があります。within()は完全に内部にあるオブジェクトを返しますが、intersects()は完全に内部にあり部分的に内部にある(つまり、フィーチャと交差する)オブジェクトを返します。名前が示す)。

ここに画像の説明を入力してください


私はあなたの解決策を試しました。これは、そうでない場合は最初のポリゴン内の点のみが選択されます、あなたは1つのポリゴンを持っている場合にのみ機能します
ilFonta
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.