QGIS와 함께 Python을 사용하여 교차점을 얻기 위해 교차하는 선?


10

버스 노선을 나타내는 일련의 노선이 있습니다. 일부 노선은 겹치며 동일한 도로를 이용합니다.

여기에 이미지 설명을 입력하십시오

노드를 추출 할 수 있습니다. 여기에 이미지 설명을 입력하십시오

그러나 나는 다음과 같은 교차점 만 추출하는 데 관심이 있습니다. 여기에 이미지 설명을 입력하십시오

어떻게해야합니까? QGIS 또는 Python을 사용하는 방법을 찾고 있습니다.

GDAL Python에서 교차 방법 을 시도 했지만 기본적으로 정점 만 반환합니다.

QGIS 의 Line Intersections 방법 은 두 선이 교차하면 교차점을 반환합니다. 그러나 두 개의 버스 노선이 동일한 도로에서 노선의 일부를 통과하는 경우, 그들이 합류하는 지점을 알려주지 않습니다.


QGIS에서 선 교차 도구를 사용해 보셨습니까 : 벡터 분석 도구> 선 교차 ... 선의 끝과 시작 노드가 아니라 모든 교차로를 제공합니다.
Jakob

그래, 나는 이것에 대해 질문에 썼다.
ustroetz

나는 모든 선이 이미지에서 동일한 방식으로 상징되기 때문에 당신이 무엇을 요구하는지 확실하지 않습니다. 나는 당신이보고있는 노드 또는 왜 그렇게 많은 노드가 있는지 이해하기 위해 다른 경로를 구별 할 수 없습니다 두 번째 이미지. 경로가 도로에서 일치합니까? 모두 2 점 선 세그먼트입니까, 아니면 연속 폴리선입니까? 설명하는 동작은 ArcGIS의 교차 도구 와 같습니다. 선 출력이있는 선 / 선은 겹치지 만 점 출력이있는 선 / 선은 교차 만 나타냅니다.
Chris W

이를 바탕으로 원하는 것을 얻으려면 두 가지 방법을 모두 사용해야 할 수도 있습니다. 교차점 (line / line = point)을 얻은 다음 오버랩 (line / line = line)을 가져와 해당 오버랩 라인의 시작 / 종료 노드를 추출하십시오. 그것들은 당신이 찾고있는 모든 포인트 / 노드이어야합니다.
Chris W

답변:


21

노드 :

폴리 라인의 끝점 (중간 노드 없음)과 교차점의 두 가지를 원합니다. 추가 문제가 있지만 일부 폴리선 끝점은 교차점이기도합니다.

여기에 이미지 설명을 입력하십시오

해결책은 Python과 ShapelyFiona 모듈을 사용하는 것입니다

1) shapefile을 읽으십시오.

from shapely.geometry import Point, shape
import fiona
lines = [shape(line['geometry']) for line in fiona.open("your_shapefile.shp")]

2) 선의 끝점을 찾으십시오 ( 어떻게 폴리선의 끝점을 얻습니까? ) :

endpts = [(Point(list(line.coords)[0]), Point(list(line.coords)[-1])) for line  in lines]
# flatten the resulting list to a simple list of points
endpts= [pt for sublist in endpts  for pt in sublist] 

여기에 이미지 설명을 입력하십시오

3) 교차점을 계산합니다 ( itertools 모듈 을 사용하여 레이어의 형상 쌍을 통해 반복 ). 일부 교차점의 결과는 MultiPoint이며 점 목록을 원합니다.

import itertools
inters = []
for line1,line2 in  itertools.combinations(lines, 2):
  if  line1.intersects(line2):
    inter = line1.intersection(line2)
    if "Point" == inter.type:
        inters.append(inter)
    elif "MultiPoint" == inter.type:
        inters.extend([pt for pt in inter])
    elif "MultiLineString" == inter.type:
        multiLine = [line for line in inter]
        first_coords = multiLine[0].coords[0]
        last_coords = multiLine[len(multiLine)-1].coords[1]
        inters.append(Point(first_coords[0], first_coords[1]))
        inters.append(Point(last_coords[0], last_coords[1]))
    elif "GeometryCollection" == inter.type:
        for geom in inter:
            if "Point" == geom.type:
                inters.append(geom)
            elif "MultiPoint" == geom.type:
                inters.extend([pt for pt in geom])
            elif "MultiLineString" == geom.type:
                multiLine = [line for line in geom]
                first_coords = multiLine[0].coords[0]
                last_coords = multiLine[len(multiLine)-1].coords[1]
                inters.append(Point(first_coords[0], first_coords[1]))
                inters.append(Point(last_coords[0], last_coords[1]))

여기에 이미지 설명을 입력하십시오

4) 끝점과 교차점 사이의 중복을 제거하십시오 (그림에서 볼 수 있듯이)

result = endpts.extend([pt for pt in inters  if pt not in endpts])

5) 결과 shapefile을 저장하십시오

from shapely.geometry import mapping
# schema of the shapefile
schema = {'geometry': 'Point','properties': {'test': 'int'}}
# creation of the shapefile
with fiona.open('result.shp','w','ESRI Shapefile', schema) as output:
    for i, pt in enumerate(result):
        output.write({'geometry':mapping(pt), 'properties':{'test':i}})

최종 결과:

여기에 이미지 설명을 입력하십시오

선분

노드 사이의 세그먼트를 원한다면 shapefile 을 "평면화"( 평면 그래프 , 가장자리가 서로 교차하지 않음)해야합니다. 이것은 Shapely 의 unary_union 함수 로 수행 할 수 있습니다

from shapely.ops import unary_union
graph = unary_union(lines)

여기에 이미지 설명을 입력하십시오


자세한 답변은 @gene에게 감사드립니다. 다른 지오메트리 유형을 넘어가는 부분을 편집했습니다. 필자의 경우 교차점은 선, 지오메트리 컬렉션 등을 반환하지만 입력 데이터에 따라 다릅니다. 나는 내 질문에 충분히 명확하지 않았다.
ustroetz

좋은 대답입니다. 메소드를 수정 result = endpts.extend([pt for pt in inters if pt not in endpts])하는 것처럼 보이기 때문에 다음을 수행 할 필요가 없다고 덧붙일 수 있습니다 . 내 경우에는 그 수술 후. 그것은 인 결과 정 함유하는 끝.extendendptresult = Noneendpts
user32882
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.