Thực hiện truy vấn không gian trong một vòng lặp trong PyQGIS


9

Những gì tôi đang cố gắng làm: lặp qua một shapefile điểm và chọn từng điểm rơi vào một đa giác.

Đoạn mã sau được lấy cảm hứng từ một ví dụ truy vấn không gian mà tôi tìm thấy trong một cuốn sách:

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

Điều này hoạt động, và nó chọn bộ dữ liệu, nhưng vấn đề là nó chọn bằng hộp giới hạn , do đó rõ ràng trả về các điểm tôi không quan tâm:

nhập mô tả hình ảnh ở đây

Làm thế nào tôi có thể đi về chỉ trả lại điểm trong đa giác mà không sử dụng qgis: selectbylocation ?

Tôi đã thử sử dụng các phương thức bên trong ()giao nhau () , nhưng vì tôi không làm cho chúng hoạt động, tôi đã sử dụng mã ở trên. Nhưng có lẽ chúng là chìa khóa sau tất cả.

Câu trả lời:


10

Bạn không cần một chức năng đặc biệt (như "Đúc Ray"), mọi thứ đều nằm trong PyQGIS ( chứa () trong Xử lý hình học 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" 

hoặc trong một dòng

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

Bạn cũng có thể trực tiếp sử dụng

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

Vấn đề ở đây là bạn phải lặp qua tất cả các hình học (đa giác và điểm). Điều thú vị hơn là sử dụng chỉ số không gian giới hạn: bạn chỉ lặp qua các hình học có cơ hội giao nhau với hình học hiện tại của bạn ('bộ lọc', xem Làm thế nào để truy cập hiệu quả các tính năng được trả về bởi QssSpatial Index? )



5

Bạn có thể sử dụng thuật toán "Ray Casting" mà tôi đã điều chỉnh một chút để sử dụng với 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

Áp dụng cho tình huống này:

nhập mô tả hình ảnh ở đây

kết quả, tại Bảng điều khiển Python, là:

[2, 2]

Nó đã làm việc.

Chỉnh sửa ghi chú:

Mã với đề xuất ngắn gọn hơn về gen :

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

Tham khảo tuyệt vời và câu trả lời tuyệt vời! Tôi sẽ đánh dấu bài tôi vừa đăng, tuy nhiên, là giải pháp, vì nó dễ thực hiện hơn một chút. Bạn nên được thưởng rất nhiều upvote mặc dù. +1 từ tôi, chắc chắn.
BritishSteel

Bạn không cần chỉ định if geo_pol.contains(geo_point) == True:vì nó ẩn if geo_pol.contains(geo_point)(luôn luôn đúng)
gen

3

Với một số lời khuyên từ một đồng nghiệp, cuối cùng tôi đã có được nó để làm việc bằng cách sử dụng trong ().

Logic chung

  1. có được các tính năng của đa giác
  2. có được tính năng của điểm
  3. lặp qua từng tính năng từ tệp đa giác và cho mỗi:
    • lấy hình học
    • lặp qua tất cả các điểm
      • lấy hình học của điểm duy nhất
      • kiểm tra nếu hình học nằm trong hình học của đa giác

Đây là mã:

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

Điều này cũng sẽ làm việc với giao điểm () thay vì trong () . Khi sử dụng điểm , bạn sẽ sử dụng điểm nào không quan trọng , vì cả hai sẽ trả về cùng một kết quả. Khi kiểm tra các dòng / đa giác, tuy nhiên, nó có thể làm cho một sự khác biệt quan trọng: trong () đối tượng lợi nhuận mà là hoàn toàn bên trong, trong khi giao cắt () retuns đối tượng là hoàn toàn trong một phần trong (tức là giao nhau với tính năng này, như tên chỉ ra).

nhập mô tả hình ảnh ở đây


Tôi đã thử giải pháp của bạn. Nó chỉ hoạt động nếu bạn có một đa giác, nếu không thì chỉ các điểm trong đa giác đầu tiên sẽ được chọn
ilFonta
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.