QGIS'de Voronoi çokgen yaratımında delikler / kısıtlamalar düşünülüyor mu?


12

Ben QGIS genel etki alanında "delik" düşünün voronoi çokgenler oluşturmaya çalışıyorum. Örnek olarak şunlar verilebilir:

resim açıklamasını buraya girin

Aslında bu görüntüde Voronois'i GRASS komutuyla QGIS kullanarak, sonra da delikler oluşturmak için "Fark" aracını kullanarak oluşturdum. Deliklerin boyutlarını içeren ayrı bir çokgen şekil dosyası "Fark" katmanı olarak kullanılmıştır. Örnek bir uygulama, analizden çıkarılması gereken yapılar arasında toplanan örnekleme noktalarının etrafında çokgenler oluşturmak olacaktır.

Burada iki sorun ortaya çıkıyor:

  1. "Fark" işlevi% 100 düzgün çalışmıyor gibi görünüyor, bazı çokgen sınırları "deliklere" uzanıyor. Bu, Öznitelik Tablosunda çokgen kimlik numarası olmayan (veya "0" kimliği) satır bulunarak düzeltilebilir.

  2. Bu türden sonra "delik delme", ​​görüntüdeki kırmızı okla gösterildiği gibi kesintili çokgenlere neden olabilir.

Sorum şu: tek adımlık bir süreç olarak alan adının merkezinde "delik" varlığını düşünebilen ve aynı zamanda süreksiz poligon oluşumunu ortadan kaldıran bir Voronoi aracı veya eklentisi var mı? Böyle bir aracın, diğer sınır önce bir "delik" sınırına çarpmadığı sürece, çokgen sınırının başka bir sınırla en yakın kavşağa kadar uzanacağını öngörüyorum.


Bu , ArcGIS'te bir çevre maskesi kullanmanın (sanırım) tam tersi olacaktır . Bu, oluşturulan çokgenleri belirli bir sınırla sınırlamanıza izin verir. Ancak karmaşık sınırları / delikleri kullanacak herhangi bir aracın farkında değilim (belki ArcGIS'te maske o kadar karmaşık olabilir - test etmedim ve daha sonra zamanım varsa deneyebilirim).
Chris W

ArcGIS teorisini test ettim ve işe yaramayacak. Bağlantılı soru başına, sonuçları dış bir şekil ile sınırlandırabilirsiniz. Bununla birlikte, sonuçtaki kesikler, şekildeki bir delikten yok sayılır. Ayrıca, bu delikte bazı noktalar varsa, takım hata verir ve çalışmaz. İlk sorununuzu farkla açıklayamıyorum, ancak şeritlerle sonuçlanan ikincisi tamamen beklenmedik değil - sonuçta, delik mevcut olsa bile bu alan aynı noktaya tahsis edilecekti. Bu yöntemi kullanabilir ve daha sonra şeritleri bir temizleme yöntemiyle komşularına dahil edebilirsiniz.
Chris W

2
Rasterleştirerek bunu potansiyel olarak çözebilirsiniz. Bir raster maskesi ile Öklid mesafesi, başka bir noktadan çıkan hücrelere veya maske rasterinize (sınır slam açıklamanız) çarpana kadar noktalarınızdan dışarı çıkar. Sonra bazı bölgesel temizlik yapın ve çokgen elde etmek için sonucu vektörleştirin.
Chris W

1
Voronoi Geometrisinin v.clean komutunu çalıştırarak geçerli olduğundan emin olurdum ve geometriyi kontrol ederim. Son olarak, delikleri oluşturmak için Farkı yürütün.
klewis

Bu delikler hakkında Voronoi nedir? Delikleri temiz bir şekilde delmek istemiyor musunuz? Neden herhangi bir çokgen katmanı yapmasın?
mdsumner

Yanıtlar:


3

Bu rasterler kullanılarak mümkün olabilir. Öncelikle puanlarınızı ve sınır poligonlarınızı yüksek çözünürlüklü bir raster haline dönüştürün. İle sınırlarınız için bir maske ayarlayın r.mask. Ardından, r.grow.distanceGRASS'ta çalıştırın ve Value= output. Bu size en yakın nokta olan her piksel için verecektir. Bunu tekrar vektör çokgenlerine dönüştürün. Şerit çokgenlerden kurtulmak için ek adımlar gerekebilir.


2

Bu kesinlikle rasterlerle mümkündür.

Bu ekran görüntüsü umarım sorunu daha net gösterir. Voronoi'nin B kısmı, 'karga uçarken' orijinal voronoi merkezine daha yakındır, ancak bu, binanın etrafında yürümenin daha uzun süreceği gerçeğini dikkate almaz. OP'nin sorusunu anladığım şey, voronoi'nin binanın etrafında dolaşmak için bu ekstra mesafeyi hesaba katması gerektiğidir.

resim açıklamasını buraya girin

@Guillaume'in önerisini beğendim. Ancak, denediğimde r.grow.distancemaskeyi onurlandırmakta zorlandım (aşağıya bakın. Dalgalar binalardan geçmemelidir).

Çim bilgim olabildiğince güçlü değil, belki de aptalca bir şey yapıyorum. Kesinlikle, bu öneriye bakın, çünkü benimkinden çok daha az iş olacak ;-)

resim açıklamasını buraya girin

Adım 1 - Maliyet yüzeyi oluşturma

İlk adım bir maliyet yüzeyi oluşturmaktır. Bunun sadece bir kez yapılması gerekir.

  • düzenlenebilir bir katman, delikler ve hepsi oluşturun.
  • 'birim' adlı bir alan ekleyin, 1 olarak ayarlayın.
  • "delikli" vektör katmanınızda (deliklere sahip olan) çokgen-raster kullanarak, 'birim' alanını kullanarak. Artık 1 "boş alan ve 0'ın oluşturduğu bir katman" maskesi "var.
  • Bunu maliyet yüzeyine dönüştürmek için raster hesap makinesini kullanın. 'Dış mekanı' 1'e ve 'iç mekanı' 9999'a ayarlayacağım. Bu, binalarda hareket etmeyi oldukça zorlaştıracak.

    (( "Maske @ 1" = 1) * 1) + (( "maske @ 1" = 0) * 9999)

Maliyet yüzeyine biraz gürültü ekleyerek daha fazla 'organik' sonuç elde edebilirsiniz (örneğin, dış mekan pikselleri için 1 yerine 1'den 3'e kadar rastgele sayı kullanın.)

Adım 2. Her bir voronoi merkezi için kümülatif maliyet rasterleri oluşturun

Şimdi (tek seferde bir voronoi hücresi için) GRASS algoritmasını r.cost.coordinatesmaliyet yüzey katmanımıza karşı çalıştırabiliriz.

Başlangıç ​​koordinatı için vornoi merkezini kullanın. Son koordinat için, bölgenizin köşelerinden birini seçin. Daha pürüzsüz sonuçlar verdiği için 'Şövalyeler Turu' kullanmanızı öneririm.

Sonuç, bir voronoi merkezinden eşit seyahat süresi çizgilerini gösterir. Bantların binaların etrafına nasıl sarıldığına dikkat edin.

resim açıklamasını buraya girin

Bunu en iyi nasıl otomatik hale getireceğinden emin değilim. Toplu iş modunu işleyebilir veya pyqgis ile yapabilirsiniz.

3. Adım. Rasterleri birleştir

Bu muhtemelen koda ihtiyaç duyacaktır. Algoritma

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

Bu yaklaşım, her hücrenin, engelleri dikkate alarak, en yakın olduğu voronoi merkezi tarafından kategorize edildiği bir raster vermelidir.

Daha sonra raster-çokgene kullanabilirsiniz. Daha sonra "adım" efekti artefaktlarını taramadan kaldırmak için Generalize eklentisini kullanabilirsiniz .

Adım 2 ve 3'teki belirsizlikler için özür dilerim ... Birisinin daha şık bir çözümle çalmasını umuyorum :)


1
Teşekkürler Steven, çalışan bir GRASS raster çözüm var ama ödül açıklamasında belirtildiği gibi daha zarif bir çözüm umuyordum.
underdark

0

Not # 1 : Fark edilen sorunu, gerçekleştirdiğim birkaç testte benim için iyi çalıştığı için önerilen sorunu yeniden oluşturamadım (belki sorunun basit geometrisinden kaynaklanıyor veya araç sorudan beri geliştirildiğinden) sordu 1 yıl önce).

Ancak, Fark aracını kullanmaktan kaçınmak için PyQGIS'de bir geçici çözüm öneriyorum . Her şey iki giriş katmanı arasındaki yerel kesişime dayanır (aşağıdaki şekle bakın):

  1. Voronoi çokgenlerini temsil eden bir çokgen vektör katmanı;
  2. analizden çıkarılması gereken delikleri / kısıtlamaları temsil eden bir çokgen vektör katmanı.

resim açıklamasını buraya girin

Not # 2 : Fark aracını kullanmak istemediğim için , "şerit" (bundan sonra bakın) oluşturulmasını önleyemiyorum, bu yüzden v.cleanbunları ortadan kaldırmak için aracı çalıştırmak gerekiyordu. Ayrıca, @Chris W'nin dediği gibi,

[...] ancak şeritle sonuçlanan ikinci kısım tamamen beklenmedik değildir - sonuçta, delik mevcut olsa bile bu alan yine aynı noktaya tahsis edilecektir. Bu yöntemi kullanabilir ve daha sonra şeritleri bir temizleme yöntemiyle komşularına dahil edebilirsiniz .

Bu gerekli tesislerden sonra kodumu gönderirim:

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

Bu da bu sonuca götürür:

resim açıklamasını buraya girin

Sadece netlik için, bu v.cleanaleti kullanmadan sonuç olacaktır :

resim açıklamasını buraya girin

@LeaningCactus'un sonucundaki fark, şimdiye kadar geometrilerin kırılmamış olması ve hatasız olarak "temizlenebilmeleridir .


Delikleri daha uzun yapın, örneğin bir nehir gibi tüm haritayı keserek sorunu göreceksiniz. Komşulara şerit eklemek, uygun bir kısıtlanmış Voronoi diyagramından çok farklı görünen çokgenler oluşturur. Bunu denedim.
underdark

Üzgünüm, anlamıyorum: sonuçlarda herhangi bir hata buldunuz mu? Sadece çokgenlerin soruda önerilenlere benzer olduğu durumlar için kodu test ettim.
mgri

Kodu maalesef şu anda test edemiyoruz, ancak i.stack.imgur.com/Jpfra.png adresinde gösterilen deliklerdeki değişiklikle elde edilen sonuçları gösterebilir misiniz ?
underdark

Ben sağda özelliği kısıtlamayı kadar uzatmak, ben elde Bu . Ben doğrudan kısıtlamayı taşırsanız Bunun yerine, ben elde Bu .
mgri

Çizimimdeki kırmızı okun işaret ettiği küçük üçgen konudur. Orada olmamalı ama sonuçlarınızda da olmalı. Görünüşe göre bu yaklaşım sorunun 1 numaralı sorununu çözer ancak 2 numaralı sorunu çözümsüz bırakır.
underdark
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.