QGIS에서 Voronoi 폴리곤 생성의 구멍 / 제약을 고려하고 있습니까?


12

QGIS에서 일반 영역에서 "구멍"을 고려하는 보로 노이 다각형을 만들려고합니다. 예를 들면 다음과 같습니다.

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

실제로 GRASS 명령을 통해 QGIS를 사용하여이 이미지에서 Voronois를 생성 한 다음 "Difference"도구를 사용하여 구멍을 생성했습니다. 구멍의 범위를 포함하는 별도의 다각형 모양 파일이 "차이"레이어로 사용되었습니다. 예제 응용 프로그램은 분석에서 제외해야하는 구조간에 수집 된 샘플링 지점 주위에 다각형을 만드는 것입니다.

여기서 두 가지 문제가 발생합니다.

  1. "다각도"기능은 100 % 제대로 작동하지 않는 것으로 보이며 일부 다각형 경계는 "구멍"으로 확장됩니다. 이것은 속성 테이블에서 다각형 ID 번호 (또는 ID "0")가없는 행을 찾아서 해결할 수 있습니다.

  2. 이 유형의 사후 "홀 펀칭"은 이미지에서 빨간색 화살표로 표시되는 것처럼 불연속 다각형을 초래할 수 있습니다.

내 질문은 : 도메인 중심에 "구멍"의 존재를 1 단계 프로세스로 고려하고 불연속 다각형의 생성을 제거 할 수있는 Voronoi 도구 또는 플러그인이 있습니까? 다른 도구가 "구멍"경계에 먼저 닿지 않는 한 그러한 도구가 다각형 경계를 다른 경계와 가장 가까운 교차점까지 확장 할 것으로 생각합니다.


이것은 ArcGIS에서 환경 마스크를 사용하는 것과 비슷하지만 그 반대입니다 . 그러면 생성 된 다각형을 특정 경계 내로 제한 할 수 있습니다. 그러나 복잡한 경계 / 구멍을 사용하는 도구는 알지 못합니다 (ArcGIS에서는 마스크가 그렇게 복잡 할 수 있습니다-테스트하지 않았으며 시간이 있으면 나중에 시도해 볼 수 있습니다).
Chris W

ArcGIS 이론을 테스트했는데 작동하지 않습니다. 연결된 질문에 따라 결과를 외부 모양으로 제한 할 수 있습니다. 그러나 모양의 구멍 절단은 결과 폴리에 의해 무시됩니다. 또한이 구멍에 구멍이 몇 개 있으면 공구 오류가 발생하여 작동하지 않습니다. 나는 첫 번째 문제를 차이점으로 설명 할 수는 없지만 두 번째 슬라이 버가 예기치 않은 것은 아닙니다. 결국 구멍이 있어도 해당 영역은 여전히 ​​동일한 지점에 할당됩니다. 이 방법을 사용하고 정리 방법으로 은색을 이웃에 통합 할 수 있습니다.
Chris W

2
래스터로 이동하면이 문제를 해결할 수 있습니다. 래스터 마스크를 사용하면 다른 점에서 나오는 셀이나 마스크 래스터 (경계 슬램 설명)에 도달 할 때까지 유클리드 거리가 포인트에서 나옵니다. 그런 다음 일부 영역 정리를 수행하고 결과를 벡터화하여 다각형을 얻습니다.
Chris W

1
v.clean을 실행 한 다음 지오메트리를 확인하여 voronoi 지오메트리가 유효한지 확인합니다. 마지막으로 차이를 실행하여 구멍을 만듭니다.
klewis

이 구멍에 대해 보로 노이는 무엇입니까? 깨끗하게 구멍을 뚫고 싶지 않습니까? 폴리곤 레이어가없는 이유는 무엇입니까?
mdsumner

답변:


3

래스터를 사용하여 가능할 수 있습니다. 먼저 점과 경계 다각형을 고해상도 래스터로 변환하십시오. 을 사용하여 경계에 대한 마스크를 설정하십시오 r.mask. 그런 다음 r.grow.distanceGRASS 에서 실행 하고을 사용하십시오 Value= output. 이것은 가장 가까운 지점 인 각 픽셀에 대해 제공합니다. 이것을 다시 벡터 다각형으로 변환하십시오. 은색 다각형을 제거하는 데 추가 단계가 필요할 수 있습니다.


2

이것은 래스터에서 가능합니다.

이 스크린 샷은 문제를보다 명확하게 보여줍니다. 보로 노이의 B 부분은 까마귀가 원래 보로 노이 센터와 '비행하는 것처럼'더 가깝습니다. OP의 질문에 대한 나의 이해는 건물 주위를 걸을 때 보로 노이 가이 여분의 거리를 고려해야한다는 것입니다.

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

@Guillaume의 제안이 마음에 듭니다. 그러나 그것을 시도했을 때 r.grow.distance마스크를 존중하는 데 문제가있었습니다 (아래 참조. 잔물결이 건물을 통과해서는 안됩니다).

내 잔디 지식은 그다지 강력하지 않으므로 어리석은 짓을하고있을 것입니다. 확실히, 그 제안은 내 것보다 훨씬 적은 작업이므로 먼저 제안을 확인하십시오 ;-)

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

1 단계-비용 표면 생성

첫 번째 단계는 비용 표면을 만드는 것입니다. 이 작업은 한 번만 수행하면됩니다.

  • 편집 가능한 레이어, 구멍 및 모두를 만듭니다.
  • 'unit'이라는 필드를 추가하고 1로 설정하십시오.
  • 'unit'필드를 사용하여 "펀칭 된"벡터 레이어 (구멍이있는 레이어)에 다각형-래스터 사용. 이제 "마스크"라는 레이어가 있습니다. 여기서 1은 여유 공간이고 0은 빌딩입니다.
  • 래스터 계산기를 사용하여 비용면으로 전환하십시오. '야외'를 1로, '실내'를 9999로 설정하겠습니다. 이렇게하면 건물을 통과하는 것이 엄청나게 어려워집니다.

    (( "mask @ 1"= 1) * 1) + (( "mask @ 1"= 0) * 9999)

비용 표면에 약간의 노이즈를 추가하여 더 많은 '유기적'결과를 얻을 수 있습니다 (예 : 실외 pxiels에는 1이 아닌 1에서 3 사이의 난수 사용).

2 단계. 각 보로 노이 센터마다 누적 비용 래스터 생성

이제 r.cost.coordinates비용 표면 레이어에 대해 GRASS 알고리즘을 한 번에 하나의 보로 노이 셀에 대해 실행할 수 있습니다 .

시작 좌표로 vornoi center를 사용하십시오. 끝 좌표로 해당 지역의 모서리 중 하나를 선택하십시오. 더 부드러운 결과를 얻으려면 'Knights Tour'를 사용하는 것이 좋습니다.

결과는 하나의 보로 노이 센터에서 이동 시간이 동일한 선을 보여줍니다. 밴드가 건물 주위를 어떻게 감싸는 지주의하십시오.

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

이것을 자동화하는 가장 좋은 방법을 모르겠습니다. 배치 모드 처리 또는 pyqgis에서 수행 될 수 있습니다.

3 단계. 래스터 병합

아마도 코드가 필요할 것입니다. 알고리즘은

create a raster 'A' to match the size of your cumulative cost images
fill raster 'A' with a suitably high number e.g. 9999
create an array of the same size as the raster.
for each cumulative cost raster number 1..N
    for each cell in image
        if cell < value in raster 'A'
            set value in raster 'A' to cell value
            set corresponding cell in array to cum. cost image number
write out array as a raster

이 접근법은 장애물을 고려하여 가장 가까운 보로 노이 중심으로 각 셀이 분류되는 래스터를 생성해야합니다.

그런 다음 래스터-폴리곤을 사용할 수 있습니다. 그런 다음 일반화 플러그인을 사용 하여 래스터에서 "단계"효과 아티팩트를 제거 할 수 있습니다 .

2 단계와 3 단계의 모호한 점에 대한 사과 ... 더 우아한 솔루션으로 누군가를 유혹하고 있습니다. :)


1
Steven에게 감사합니다. GRASS 래스터 해결 방법이 있지만 현상금 설명에 언급 된 것처럼보다 우아한 솔루션을 원했습니다.
underdark

0

참고 # 1 : 차이 도구가 내가 수행 한 여러 테스트에서 제대로 작동 했기 때문에 제안 된 문제를 재현 할 수 없었습니다 (문제 의 단순한 형상 때문이거나 문제가 발생한 후 도구가 개선 되었기 때문일 수 있습니다) 1 년 전 질문).

그러나 차이 도구를 사용하지 않도록 PyQGIS에서 해결 방법을 제안합니다 . 모든 것은 두 입력 레이어 사이의 로컬 교차점을 기반으로합니다 (아래 그림 참조).

  1. 보로 노이 다각형을 나타내는 다각형 벡터 레이어;
  2. 분석에서 제외해야하는 구멍 / 제약을 나타내는 다각형 벡터 레이어

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

참고 # 2 : 차이 도구 를 사용하고 싶지 않기 때문에 "은색 기"가 생성되는 것을 피할 수 없으므로 (다음 참조) v.clean도구를 실행하여 제거합니다. 또한 @Chris W가 말했듯이

[...] 그러나 슬라이 버를 생성하는 두 번째 결과는 예상치 못한 것은 아닙니다. 결국 해당 영역은 구멍이 있어도 동일한 지점에 할당됩니다. 이 방법을 사용하고 정리 방법 으로 은색을 이웃에 통합 할 수 있습니다 .

이 필요한 전제 후 코드를 게시합니다.

##Voronoi_Polygons=vector polygon
##Constraints=vector polygon
##Voronoi_Cleaned=output vector

from qgis.core import *

voronoi = processing.getObject(Voronoi_Polygons)
crs = voronoi.crs().toWkt()
ex = voronoi.extent()
extent = '%f,%f,%f,%f' % (ex.xMinimum(), ex.xMaximum(), ex.yMinimum(), ex.yMaximum())

constraints = processing.getObject(Constraints)

# Create the output layer
voronoi_mod = QgsVectorLayer('Polygon?crs='+ crs, 'voronoi' , 'memory')
prov = voronoi_mod.dataProvider()
fields = voronoi.pendingFields() # Fields from the input layer
prov.addAttributes(fields) # Add input layer fields to the outLayer
voronoi_mod.updateFields()

# Spatial index containing all the 'constraints'
index_builds = QgsSpatialIndex()
for feat in constraints.getFeatures():
    index_builds.insertFeature(feat)

final_geoms = {}
final_attrs = {}

for feat in voronoi.getFeatures():
    input_geom = feat.geometry()
    input_attrs = feat.attributes()
    final_geom = []
    multi_geom = input_geom.asPolygon()
    input_geoms = [] # edges of the input geometry
    for k in multi_geom:
        input_geoms.extend(k)
    final_geom.append(input_geoms)
    idsList = index_builds.intersects(input_geom.boundingBox())
    mid_geom = [] # edges of the holes/constraints
    if len(idsList) > 0:
        req = QgsFeatureRequest().setFilterFids(idsList)
        for ft in constraints.getFeatures(req):
            geom = ft.geometry()
            hole = []
            res = geom.intersection(input_geom)
            res_geom = res.asPolygon()
            for i in res_geom:
                hole.extend(i)
                mid_geom.append(hole)
        final_geom.extend(mid_geom)
    final_geoms[feat.id()] = final_geom
    final_attrs[feat.id()] = input_attrs

# Add the features to the output layer
outGeom = QgsFeature()
for key, value in final_geoms.iteritems():
    outGeom.setGeometry(QgsGeometry.fromPolygon(value))
    outGeom.setAttributes(final_attrs[key])
    prov.addFeatures([outGeom])

# Add 'voronoi_mod' to the Layers panel
QgsMapLayerRegistry.instance().addMapLayer(voronoi_mod)

# Run 'v.clean'
processing.runalg("grass7:v.clean",voronoi_mod, 2, 0.1, extent, -1, 0.0001, Voronoi_Cleaned, None)

# Remove 'voronoi_mod' to the Layers panel
QgsMapLayerRegistry.instance().removeMapLayer(voronoi_mod)

이 결과로 이어집니다.

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

명확성을 위해 v.clean도구를 사용하지 않고 결과를 얻을 수 있습니다 .

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

@LeaningCactus의 결과와의 차이점은 이제 지오메트리가 손상되지 않고 오류없이 "정리"될 수 있다는 것 입니다.


예를 들어 강처럼 전체지도를 절단하는 등 구멍을 더 길게 만들면 문제가 나타납니다. 이웃에 은색을 추가하면 적절한 구속 된 보로 노이 다이어그램과 매우 다른 다각형이 만들어집니다. 나는 그것을 시도했다.
underdark

죄송합니다. 이해가되지 않습니다 : 결과에서 오류를 찾았습니까? 다각형이 질문에서 제안한 다각형과 유사한 경우에 대해서만 코드를 테스트했습니다.
mgri December

불행히도 현재 코드를 테스트 할 수는 없지만 i.stack.imgur.com/Jpfra.png에 스케치 된 구멍의 변화로 얻은 결과를 보여줄 수 있습니까?
underdark

오른쪽의 기능까지 제약 조건을 확장하면 이것을 얻 습니다 . 대신 제약 조건을 직접 이동하면 이것을 얻 습니다 .
mgri December

내 그림의 빨간색 화살표가 가리키는 작은 삼각형이 문제입니다. 거기에 있지 않아야하지만 결과에도 있습니다. 이 접근법은 문제 # 1을 해결하지만 # 2는 해결되지 않은 것처럼 보입니다.
underdark
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.