Ketebalan dinding minimum poligon non-cembung dengan lubang

9

Apa cara paling efisien untuk menemukan ketebalan dinding minimum (nilai dan lokasi) dari area poligon yang kompleks dan tidak cembung termasuk lubang? Lihat contoh poligon berwarna biru, dengan ketebalan dinding minimum berwarna merah, meskipun dalam hal ini lokasinya ambigu, jika dua garis yang berdekatan sejajar.

masukkan deskripsi gambar di sini

Sejauh ini, kami telah mencoba:

  • Membagi garis poligon dan menemukan garis titik-titik minimum di dalam poligon (brute force, tidak efisien untuk poligon kompleks dengan> 10'000 poin)
  • Delaunay triangulasi dan temukan tepi minimal di dalam poligon. Tidak cukup tepat, hanya layak jika dikombinasikan dengan subdivisi garis poligon terlebih dahulu. Inilah contoh (No. 3), di mana triangulasi Delaunay tidak akan menemukan tepi simpleks berwarna merah tetapi akan kehilangan ketebalan dinding minimal di kotak hijau:
    masukkan deskripsi gambar di sini
  • Iteratif meningkatkan buffer erosi untuk menemukan inset minimal, di mana poligon erosi pecah menjadi beberapa bagian = setengah dari ketebalan dinding minimal. Masalahnya adalah untuk menemukan lokasi ketebalan dinding minimum dengan pendekatan ini sesudahnya. Selain itu, erosi tidak selalu pecah menjadi beberapa bagian dan meleset dari "jalan buntu". Berikut adalah contoh (No. 2) yang mengikis ke garis dan memberikan ketebalan dinding minimal yang salah:
    masukkan deskripsi gambar di sini
  • Temukan sumbu medial terlebih dahulu, kemudian cari lingkaran minimum pada sumbu medial yang menutupi tetapi tidak tumpang tindih area poligon. Sunting: Yang bermasalah adalah banyak "kandidat yang salah" pada sumbu medial: Misalnya. (No. 1) lingkaran A akan salah, lingkaran B akan menunjukkan ketebalan dinding minimum yang benar:
    masukkan deskripsi gambar di sini
Oliver Staubli
sumber
Dapatkan jarak antara semua pasangan garis untuk menemukan pasangan terdekat.
bugmenot123
Jadi apa yang salah dengan pendekatan sumbu medial?
Hornbydd
1
@Hornbydd: Masalahnya adalah, bahwa ada banyak lingkaran pada sumbu medial yang menyentuh sudut tetapi tidak menentukan ketebalan dinding. Lihat contoh kedua : lingkaran A akan salah, lingkaran B akan menjadi lokasi yang benar dari ketebalan dinding minimal. Jadi sumbu medial terlihat seperti jalan memutar yang mahal dan tidak memberikan jawaban yang tepat ...
Oliver Staubli
1
Jika Anda melakukan erosi hingga poligon berdegenerasi menjadi dua poligon yang menyentuh suatu titik, maka lokasi akan berada di tempat lingkaran jari-jari sama dengan penyangga yang berpusat pada titik tersebut menyentuh poligon asli. Itu hipotesis yang disajikan tanpa bukti tetapi saya tidak bisa melihat contoh tandingan ...
Spacedman
1
@OliverStaubli Saran saya adalah untuk memeriksa tidak hanya tepi dari segitiga delaunay, tetapi juga ketinggian dari segitiga yang memiliki satu tepi pada batas dan dua lainnya di bagian dalam poligon. Sebagai contoh No. 3 ketinggian segitiga di bawah kotak hijau adalah yang Anda cari. (tergantung pada kendala triangulasi Anda mungkin perlu juga menyaring beberapa kandidat dalam segitiga tumpul)
mkadunc

Jawaban:

1

Salah satu metode yang paling efisien untuk menemukan ketebalan dinding minimal (nilai dan lokasi) dari area poligon kompleks, non-cembung termasuk lubang, bisa dengan menggunakan lapisan yang diberi spasi secara teratur (atau acak) dari titik-titik untuk menentukan, pertama, segmen terdekat dengan konteks untuk setiap titik dan, selanjutnya, titik untuk persimpangan antara segmen tambahan dan poligon sisi yang berlawanan; berbasis di cosinus direktur.

Jarak inkremental dapat digunakan sampai segmen pertama mencapai dan memotong beberapa poligon samping (ketebalan dinding minimal).

Untuk mencoba pendekatan saya, saya mengkloning poligon Anda dengan lubang dan membuat layer poin acak di dalam poligon dengan 100 poin; karena dapat diamati pada gambar berikut:

masukkan deskripsi gambar di sini

Kode yang digunakan PyQGIS terlihat sebagai berikut:

import math

def azimuth(point1, point2):
   return point1.azimuth(point2) #in degrees

def cosdir_azim(azim):
   azim = math.radians(azim)
   cosa = math.sin(azim)
   cosb = math.cos(azim)
   return cosa,cosb

registry = QgsMapLayerRegistry.instance()    
polygon = registry.mapLayersByName('polygon_with_holes')
point_layer = registry.mapLayersByName('Random_points')
points = [ feat.geometry().asPoint() for feat in point_layer[0].getFeatures() ]
feat_polygon = polygon[0].getFeatures().next()

#producing rings polygons
rings_polygon = feat_polygon.geometry().asPolygon()
segments = []
epsg = point_layer[0].crs().authid()
uri = "LineString?crs=" + epsg + "&field=id:integer""&index=yes"
mem_layer = QgsVectorLayer(uri,
                           'increasing_segments',
                           'memory')
prov = mem_layer.dataProvider()
length = 10
pt2 = 0 
k = 0
while pt2 == 0:
    for i, point in enumerate(points):
        #determining closest distance to vertex or side polygon
        dist1 = feat_polygon.geometry().closestSegmentWithContext(point)[0]
        #determining point with closest distance to vertex or side polygon
        pt = feat_polygon.geometry().closestSegmentWithContext(point)[1]
        cosa, cosb = cosdir_azim(azimuth(pt, point))
        #extending segment in opposite direction based in director cosine and length 
        op_pt  = QgsPoint(point.x() + (length*cosa), point.y() + (length*cosb))
        segments.append([pt,op_pt])
        geom = QgsGeometry.fromPolyline([point,op_pt])
        for ring in rings_polygon:
            geom_ring = QgsGeometry.fromPolyline(ring)
            if geom.intersects(geom_ring):
                pt3 = geom.intersection(geom_ring)
                pt2 = pt3.distance(QgsGeometry.fromPoint(point))
                ms = [pt3.asPoint(), pt]
    length += 100
    k += 1
new_segments = segments[len(segments) -1 - len(segments)/k: len(segments) - 1]

feats = [ QgsFeature() for i in range(len(new_segments)) ]
for i,feat in enumerate(feats):
    feat.setAttributes([i])
    geom = QgsGeometry.fromPolyline(new_segments[i])
    feat.setGeometry(geom)

prov.addFeatures(feats)
QgsMapLayerRegistry.instance().addMapLayer(mem_layer)
minimum_segment = QgsGeometry().fromPolyline(ms).exportToWkt()
print minimum_segment, k

dan itu menghasilkan lapisan memori jarak inkremental (hanya untuk tujuan visualisasi) dan mencetak ketebalan dinding minimal dalam format WKT.

Setelah menjalankan kode di Python Console dari QGIS saya mendapat hasil gambar berikut:

masukkan deskripsi gambar di sini

Dapat diamati bahwa hanya satu jarak tambahan mencapai sisi yang berlawanan pertama di daerah yang diharapkan.

Format WKT tercetak (untuk ketebalan dinding minimal) digunakan dengan plugin QuickWKT dari QGIS untuk memvisualisasikan segmen tersebut pada gambar berikut:

masukkan deskripsi gambar di sini

Kecenderungan sedikit dihasilkan karena "segmen terdekat dengan konteks" digabungkan ke sebuah titik; alih-alih poligon samping. Namun, itu bisa dihindari dengan pengecualian kode atau lebih banyak poin.

xunilk
sumber
1

Dua ide lagi untuk dilemparkan ke dalam pot:

  1. Rasterisasi poligon Anda dan gunakan transformasi jarak (mengembalikan gambar dari jarak terpendek dari setiap piksel bukan nol ke nol-piksel). Skeletonize gambar raster Anda, lalu ambil nilai jarak dari gambar yang diubah sepanjang kerangka. Dari set itu Anda akan memiliki beberapa minimum yang harus sesuai dengan lebar tersempit Anda. Set ini dapat digunakan sebagai titik pencarian awal untuk kemudian menerapkan pendekatan brute force Anda. Saya harus mencatat bahwa kerangka akan membagi dua sudut-sudut objek, dan pada lokasi-lokasi itu transformasi jarak akan mendekati nol (ketika Anda semakin dekat dengan batas objek). Ini mungkin bermasalah, tetapi merupakan masalah dengan masalah Anda - mengapa bisa ' t lebar terkecil berada di sudut (dan pada dasarnya nol)? Anda bisa mengatasi masalah ini dengan menetapkan ambang batas pada jarak terpendek di sekitar perimeter antara dua titik (jika mereka terletak pada objek yang sama). Anda dapat menggunakan transformasi jarak geodesik pada set piksel perimeter untuk menemukan nilai itu dengan cepat.

    Metode ini mengharuskan Anda untuk membuat keputusan tentang resolusi poligon raster, yang memperkenalkan beberapa skala-ketergantungan. Dan jika Anda memilih resolusi yang terlalu tinggi, transformasi jarak dapat memakan waktu. Tetapi umumnya mereka cukup cepat. Metode ini mungkin tidak memberikan Anda presisi yang Anda inginkan, tetapi setidaknya bisa memberi Anda set lokasi yang jauh lebih kecil yang perlu diperiksa.

  2. Metode brute force Anda bukan tempat yang buruk untuk memulai. Saya memiliki masalah yang sama di mana saya harus menemukan semua persimpangan dari garis (panjang) dengan dirinya sendiri, dan saya mampu mempercepat waktu pencarian menggunakan algoritma pencarian pohon kd (saya menggunakan rentang pencarian di Matlab pada saat itu) untuk menemukan poin dalam lingkungan pertama. Dengan begitu Anda hanya memaksa sedikit bagian dari total poin.

Jon
sumber
Terima kasih @jon. Keduanya merupakan pendekatan yang menjanjikan. Saya sedang mempertimbangkan kdTree tetapi berharap masalah yang dijelaskan memiliki solusi "copy-paste" yang terkenal :-) Harus menggali lebih dalam ...
Oliver Staubli
0

Pendekatan sumbu medial benar, Anda hanya perlu kriteria untuk mengabaikan lingkaran buruk: Setiap lingkaran pada sumbu medial menyentuh permukaan dalam dua (atau lebih) titik. Bayangkan vektor dari pusat lingkaran ke titik-titik ini di permukaan dan amati bahwa sudut antara 180 ° untuk lingkaran B yang baik dan hanya 90 ° untuk lingkaran buruk A.

masukkan deskripsi gambar di sini

Geom
sumber
0

Algoritma menggambar poligon generik bekerja dengan menyortir segmen garis dari atas ke bawah, dan bekerja melaluinya untuk menggambar garis piksel orthogonal. Karena cara memecah poligon ini (tanpa lengkungan) sangat cepat, ini dapat digunakan sebagai dasar. Alih-alih hanya pergi dari atas ke bawah, Anda dapat pergi 0, 30, 60, dan 90 derajat, dan menemukan bagian ortogonal terpendek Anda (= ketebalan dinding minimal!), Anda hanya perlu menghitung satu kali per titik dan bukan untuk segala jenis 'resolusi piksel'.

Lihat algoritma komputer-grafik-pindai-garis-poligon-isi

pengguna3042469
sumber