RTree와 공간 인덱스 사용 이해?


13

RTree에서 공간 인덱스 사용을 이해하는 데 문제가 있습니다.

예 : 300 개의 버퍼 포인트가 있으며 다각형 모양 파일로 각 버퍼의 교차 영역을 알아야합니다. 다각형 shapefile에는> 20,000 개의 다각형이 있습니다. 공간 인덱스를 사용하여 프로세스 속도를 높이는 것이 좋습니다.

SO ... 폴리곤 쉐이프 파일에 대한 공간 인덱스를 만들면 어떤 방식으로 파일에 "첨부"됩니까, 아니면 인덱스가 독립적입니까? 즉, 폴리곤 파일에서 교차 기능을 실행하고 더 빠른 결과를 얻을 수 있습니까? 교차점은 공간 지수가 있고 무엇을해야하는지 알 수 있습니까? 또는 인덱스에서 실행 한 다음 FID 등을 통해 해당 결과를 원래 다각형 파일과 다시 관련시켜야합니까?

RTree 설명서는별로 도움이되지 않습니다 (아마도 프로그래밍을 배우기 때문일 것입니다). 수동으로 생성 된 포인트를 읽은 다음 인덱스를 생성하여 다른 수동으로 생성 된 포인트와 쿼리하여 창에 포함 된 ID를 반환하는 방법을 보여줍니다. 말이된다. 그러나 그들은 인덱스가 나온 원본 파일과 어떻게 관련이 있는지 설명하지 않습니다.

나는 다음과 같이 가야한다고 생각합니다.

  1. 폴리곤 쉐이프 파일에서 각 폴리곤 피처에 대한 bbox를 가져와 공간 인덱스에 배치하여 쉐이프 파일의 id와 동일한 id를 지정합니다.
  2. 교차하는 ID를 얻으려면 해당 인덱스를 쿼리하십시오.
  3. 그런 다음 인덱스를 쿼리하여 식별 한 원래 shapefile의 피처에 대해서만 교차점을 다시 실행하십시오 (마지막 부분을 어떻게 수행할지 확실하지 않음).

올바른 아이디어가 있습니까? 아무것도 빠졌습니까?


현재이 코드를 하나의 점 피쳐 만 포함하는 하나의 점 shapefile과 20,000 개 이상의 다각형 피쳐를 포함하는 하나의 다각형 shapefile에서 작동 시키려고합니다.

Fiona를 사용하여 shapefile을 가져오고 RTree를 사용하여 공간 인덱스를 추가하고 Shapely를 사용하여 교차를 시도하고 있습니다.

내 테스트 코드는 다음과 같습니다.

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

그러나 TypeError : 'Polygon'객체를 호출 할 수 없습니다.


1
공간 인덱스는 (포함 아니라 사용자의 관점에서 하나의 엔티티) 데이터 집합 수행 교차점 인식하고 생성 할 공간 인덱스를 사용하는 것이 소프트웨어에 통합하고 투명 짧은 목록을 신속히 알려서와 실제 교차로 수행 면밀한 검사를 위해 고려해야 할 기능과 교차가 거의없는 소프트웨어. 소프트웨어 작성 방법은 소프트웨어 및 데이터 유형에 따라 다릅니다.보다 구체적인 도움이 필요하면 다음 사항에 대한 자세한 정보를 제공하십시오. 모양 파일의 경우 .shx 파일입니다.
Michael Stimson

4
.shx는 공간 인덱스가 아닙니다. 가변 너비 레코드 동적 액세스 오프셋 파일 일뿐입니다. .sbn / .sbx는 ArcGIS shapefile 공간 인덱스 쌍이지만 해당 사양은 릴리스되지 않았습니다.
빈스

1
또한 .qixMapServer / GDAL / OGR / SpatiaLite 쿼드 트리 인덱스
Mike T

귀하의 아이디어는 실제 공간 지수가없는 Spatialite에 적합합니다. 공간 인덱스를 전혀 지원하지 않는 대부분의 다른 형식은 투명하게 처리합니다.
user30184

2
이 줄을 사용하여 만든 다각형 객체로 매끈하게 가져온 함수 TypeError: 'Polygon' object is not callable를 덮어 쓰기 때문에 업데이트 예제를 계속 shape사용할 수 있습니다.for i, shape in enumerate(gl):
user2856

답변:


12

그것이 요점입니다. R- 트리를 사용하면 매우 빠른 첫 번째 패스를 수행 할 수 있으며 "거짓 긍정"을 갖는 일련의 결과를 제공합니다 (형상이 정확하게 일치하지 않으면 경계 상자가 교차 할 수 있음). 그런 다음 후보 집합을 살펴보고 (색인을 기준으로 모양 파일에서 가져옵니다) Shapely와 같은 수학적으로 정확한 교차 테스트를 수행합니다. 이것은 PostGIS와 같은 공간 데이터베이스에서 사용되는 것과 동일한 전략입니다.


1
좋은 말장난 (GiST)! GiST는 일반적으로 B-Tree 변형으로 설명되지만 Postgresql에는 R-Tree의 GiST 구현이 있습니다. 위키가 인용을위한 가장 좋은 참고 자료는 아니지만 경계 상자 검색을 설명 하는 훌륭한 다이어그램 이 있습니다 .
MappaGnosis

2 단계와 3 단계에서와 같이 R- 트리 인덱스를 사용하는 수동 방법을 배우는 것이 좋습니다. 별도의 데이터베이스 테이블에서 일부 SQL 및 화면 캡처를 보여주는 R- 트리도 지원하는 OGC GeoPackage에 대한이 블로그는 openjump.blogspot.fi / 2014 / 02 / ... .
user30184

9

당신은 거의 그것을 얻었지만 작은 오류를 만들었습니다. intersection인덱스를 intersection버퍼링 된 포인트 의 메소드로 전달하는 대신 공간 인덱스 에서 메소드 를 사용해야합니다 . 경계 상자가 겹치는 피처 목록을 찾았 으면 버퍼링 된 점이 실제로 형상과 교차하는지 확인해야합니다.

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

자신의 육상 클래스와 최소 거리 내에있는 지점을 찾으려면이 distance방법을 대신 사용할 수 있습니다 (이전의 해당 섹션을 교체).

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

공간 인덱스를 작성하는 데 시간이 오래 걸리고 몇 번 이상이 작업을 수행하려는 경우 인덱스를 파일로 직렬화해야합니다. 설명서는이를 수행하는 방법을 설명합니다. http://toblerity.org/rtree/tutorial.html#serializing-your-index-to-a-file

다음과 같이 생성기를 사용하여 경계 상자를 rtree에 대량로드하는 것을 볼 수도 있습니다.

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

그렇습니다. 다음은 shapena, Fiona 및 geopandas를 사용하여 Python에서 r-tree 공간 인덱스 를 사용하는 방법에 대한이 자습서의 일부입니다 .

r- 트리는 개별 객체와 해당 경계 상자 ( "r"은 "사각형")를 공간 인덱스의 가장 낮은 수준으로 나타냅니다. 그런 다음 근처의 개체를 집계하고 다음 상위 수준의 인덱스에서 집계 경계 상자로 표시합니다. 더 높은 수준에서 r-tree는 경계 상자를 집계하고 모든 것이 하나의 최상위 경계 상자에 중첩 될 때까지 경계 상자를 반복하여 나타냅니다. 검색을 위해 r-tree는 쿼리 상자를 가져와 최상위 수준에서 시작하여 어떤 경계 상자와 교차하는지 확인합니다. 그런 다음 각 교차 경계 상자를 확장하고 그 안에있는 하위 경계 상자 중 어느 것이 쿼리 상자와 교차하는지 확인합니다. 모든 교차 상자가 가장 낮은 수준으로 검색 될 때까지 재귀 적으로 진행되고 가장 낮은 수준에서 일치하는 개체를 반환합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.