在PyQGIS中循环执行空间查询


9

我所试图做的事:循环通过一个点shapefile,然后选择属于每个点一个多边形。

以下代码受我在一本书中发现的空间查询示例的启发:

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

这有效,并且确实选择了数据集,但是问题在于它是通过bounding box选择,因此显然返回的点我不感兴趣:

在此处输入图片说明

如何不使用qgis:selectbylocation仅返回多边形的点?

我曾尝试使用inner()intersects()方法,但由于没有使它们起作用,因此我使用了上面的代码。但是也许它们毕竟是关键。

Answers:


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

您无需指定,if geo_pol.contains(geo_point) == True:因为它隐含在if geo_pol.contains(geo_point)(总是True)中
基因

3

在一个同事的一些建议下,我终于使它可以使用inside()了。

一般逻辑

  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

这也适用于intersects()而不是inner()。使用点时,使用哪一个点都没有关系,因为它们都将返回相同的结果。当线/多边形检查,但是,它可以使一个重要的不同:内是()返回的对象完全内,而相交()retuns对象是完全内部分内(即相交与特征,如名称表示)。

在此处输入图片说明


我尝试了您的解决方案。它仅在具有一个多边形的情况下有效,否则仅会选择第一个多边形内的点
ilFonta
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.