Hiểu về việc sử dụng các chỉ số không gian với RTree?


13

Tôi gặp khó khăn trong việc hiểu việc sử dụng các chỉ mục không gian với RTree.

Ví dụ: Tôi có 300 điểm được đệm và tôi cần biết mỗi khu vực giao nhau của bộ đệm với một hình đa giác. Shapefile đa giác có> 20.000 đa giác. Có gợi ý tôi sử dụng các chỉ số không gian để tăng tốc quá trình.

VẬY ... Nếu tôi tạo một chỉ mục không gian cho shapefile đa giác của mình, nó sẽ được "đính kèm" vào tệp theo cách nào đó, hoặc chỉ mục sẽ đứng độc lập? Đó là, sau khi tạo, tôi có thể chạy chức năng giao nhau của mình trên tệp đa giác và nhận được kết quả nhanh hơn không? Giao lộ sẽ "thấy" rằng có các chỉ số không gian và biết phải làm gì? Hoặc, tôi có cần chạy nó trên chỉ mục không, sau đó liên kết các kết quả đó lại với tệp đa giác ban đầu của tôi thông qua FID hoặc một số như vậy?

Tài liệu RTree không giúp tôi nhiều lắm (có lẽ vì tôi chỉ học lập trình). Chúng chỉ ra cách tạo một chỉ mục bằng cách đọc các điểm được tạo thủ công và sau đó truy vấn nó với các điểm được tạo thủ công khác, trả về các id được chứa trong cửa sổ. Có ý nghĩa. Nhưng, họ không giải thích làm thế nào điều đó sẽ liên quan đến một số tệp gốc mà chỉ mục sẽ đến từ đó.

Tôi nghĩ rằng nó phải đi một cái gì đó như thế này:

  1. Kéo các hộp cho mỗi tính năng đa giác từ shapefile đa giác của tôi và đặt chúng vào một chỉ mục không gian, cung cấp cho chúng một id giống như id của chúng trong shapefile.
  2. Truy vấn chỉ mục đó để có được các id giao nhau.
  3. Sau đó chạy lại giao lộ của tôi chỉ với các tính năng trong shapefile ban đầu của tôi đã được xác định bằng cách truy vấn chỉ mục của tôi (không chắc chắn cách tôi thực hiện phần cuối cùng này).

Tôi có ý kiến ​​đúng không? Tôi có thiếu thứ gì không?


Ngay bây giờ tôi đang cố gắng để mã này hoạt động trên một shapefile một điểm chỉ chứa một tính năng điểm và một shapefile đa giác có chứa> 20.000 tính năng đa giác.

Tôi đang nhập các shapefile bằng Fiona, thêm chỉ số không gian bằng RTree và cố gắng thực hiện giao lộ bằng Shapely.

Mã kiểm tra của tôi trông như thế này:

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

Nhưng tôi tiếp tục nhận TypeError: đối tượng 'Đa giác' không thể gọi được


1
Một chỉ mục không gian là không thể tách rời và minh bạch đối với tập dữ liệu (chứa, không phải là một thực thể duy nhất từ ​​góc độ người dùng) Phần mềm thực hiện các giao điểm được biết và sẽ sử dụng các chỉ mục không gian để tạo một danh sách ngắn để thực hiện giao cắt thực bằng cách nhanh chóng thông báo phần mềm có tính năng cần được xem xét để kiểm tra chặt chẽ hơn và rõ ràng là không có nơi nào gần giao nhau. Cách bạn tạo một tùy thuộc vào phần mềm và loại dữ liệu của bạn ... vui lòng cung cấp thêm thông tin về các điểm này để được trợ giúp cụ thể hơn. Đối với tệp hình dạng, đó là tệp .shx.
Michael Promotionson

4
.shx không phải là một chỉ số không gian. Nó chỉ là tệp bù truy cập động ghi chiều rộng thay đổi. .sbn / .sbx là cặp chỉ số không gian shapefile ArcGIS, mặc dù thông số kỹ thuật cho những thứ đó không được phát hành.
Vince

1
Ngoài ra .qixlà chỉ số tứ giác MapServer / GDAL / OGR / SpatiaLite
Mike T

Ý tưởng của bạn hoàn toàn phù hợp với Spatialite không có chỉ số không gian thực sự. Hầu hết các định dạng khác, nếu chúng hỗ trợ các chỉ mục không gian, hãy thực hiện nó một cách minh bạch.
dùng49584

2
Bạn tiếp tục nhận được TypeError: 'Polygon' object is not callablevới ví dụ cập nhật của mình vì bạn đã ghi đè shapechức năng bạn đã nhập từ hình dạng với đối tượng Đa giác bạn tạo bằng dòng này:for i, shape in enumerate(gl):
user2856

Câu trả lời:


12

Đó là ý chính của nó. Cây R cho phép bạn thực hiện vượt qua đầu tiên rất nhanh và cung cấp cho bạn một tập hợp kết quả sẽ có "dương tính giả" (các hộp giới hạn có thể giao nhau khi hình học chính xác không). Sau đó, bạn đi qua tập hợp các ứng cử viên (lấy chúng từ shapefile theo chỉ số của họ) và làm một bài kiểm tra giao nhau chính xác về mặt toán học bằng cách sử dụng, ví dụ, Shapely. Đây là chiến lược tương tự được sử dụng trong các cơ sở dữ liệu không gian như PostGIS.


1
Chơi chữ đẹp (GiST)! GiST thường được mô tả là biến thể B-Tree nhưng Postgresql có triển khai GiST của R-Tree. Mặc dù wiki không nhất thiết là tài liệu tham khảo tốt nhất để trích dẫn nhưng nó có một sơ đồ đẹp để giải thích các tìm kiếm hộp giới hạn.
MappaGnosis

Có thể đáng để học một cách thủ công để sử dụng chỉ mục R-tree như trong bước 2 và 3. Blog này về OGC GeoPackage cũng hỗ trợ R-tree vì các bảng cơ sở dữ liệu riêng biệt hiển thị một số SQL và chụp màn hình openjump.blogspot.fi / 2014/02 / .
dùng49584

9

Bạn gần như đã có nó, nhưng bạn đã mắc một lỗi nhỏ. Bạn cần sử dụng intersectionphương thức trên chỉ mục không gian, thay vì truyền chỉ mục chointersection phương thức trên điểm đệm. Khi bạn đã tìm thấy một danh sách các tính năng trong đó các hộp giới hạn trùng nhau, thì bạn cần kiểm tra xem điểm đệm của bạn có thực sự giao nhau với hình học không.

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

Nếu bạn quan tâm đến việc tìm kiếm các điểm nằm trong khoảng cách tối thiểu đến lớp đất của bạn, bạn có thể sử dụng distance phương pháp thay thế (hoán đổi phần thích hợp từ trước đó).

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!')

Nếu mất nhiều thời gian để xây dựng chỉ mục không gian của bạn và bạn sẽ thực hiện việc này nhiều hơn một vài lần, bạn nên xem xét việc tuần tự hóa chỉ mục thành một tệp. Tài liệu mô tả cách thực hiện việc này: http://toblerity.org/rtree/tutorial.html#serializing-your-index-to-a-file

Bạn cũng có thể xem xét tải hàng loạt các hộp giới hạn vào rtree bằng cách sử dụng một trình tạo, như thế này:

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

Vâng, đó là ý tưởng. Đây là một đoạn trích từ hướng dẫn này về cách sử dụng chỉ số không gian của cây r trong Python , sử dụng hình dạng, Fiona và geopandas:

Một cây r đại diện cho các đối tượng riêng lẻ và các hộp giới hạn của chúng (các r r trên là dành cho hình chữ nhật của Google) là mức thấp nhất của chỉ số không gian. Sau đó, nó tổng hợp các đối tượng gần đó và biểu thị chúng bằng hộp giới hạn tổng hợp của chúng ở cấp cao hơn tiếp theo của chỉ mục. Ở các cấp độ cao hơn, cây r tổng hợp các hộp giới hạn và đại diện cho chúng bằng hộp giới hạn của chúng, lặp đi lặp lại, cho đến khi mọi thứ được lồng vào một hộp giới hạn cấp cao nhất. Để tìm kiếm, cây r lấy một hộp truy vấn và, bắt đầu từ cấp cao nhất, xem các hộp giới hạn (nếu có) giao nhau với nó. Sau đó, nó mở rộng mỗi hộp giới hạn giao nhau và xem hộp giới hạn con nào bên trong nó giao với hộp truy vấn. Điều này tiến hành đệ quy cho đến khi tất cả các hộp giao nhau được tìm kiếm xuống mức thấp nhất và trả về các đối tượng phù hợp từ mức thấp nhất.

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.