Độ dày thành tối thiểu của đa giác không lồi có lỗ


9

Cách hiệu quả nhất để tìm độ dày tường tối thiểu (giá trị và vị trí) của một khu vực đa giác không lồi phức tạp bao gồm các lỗ là gì? Xem ví dụ về đa giác màu xanh lam, với độ dày thành tối thiểu màu đỏ, mặc dù trong trường hợp này, vị trí không rõ ràng, nếu hai đường liền kề là song song.

nhập mô tả hình ảnh ở đây

Cho đến nay, chúng tôi đã cố gắng:

  • Chia dòng đa giác và tìm dòng điểm tối thiểu bên trong đa giác (lực lượng vũ phu, không hiệu quả đối với đa giác phức tạp với> 10.000 điểm)
  • Delaunay tam giác và tìm các cạnh tối thiểu bên trong đa giác. Không đủ chính xác, chỉ khả thi nếu kết hợp với phân chia các đường đa giác trước. Đây là ví dụ (Nr 3), trong đó tam giác Delaunay sẽ không tìm thấy các cạnh đơn giản màu đỏ nhưng sẽ bỏ lỡ độ dày thành tối thiểu trong hộp màu xanh lá cây:
    nhập mô tả hình ảnh ở đây
  • Lặp đi lặp lại tăng bộ đệm xói mòn để tìm phần nhỏ nhất, trong đó đa giác xói mòn phá vỡ thành nhiều phần = một nửa độ dày thành tối thiểu. Vấn đề là tìm vị trí của độ dày tường tối thiểu với phương pháp này sau đó. Hơn nữa, xói mòn không phải lúc nào cũng phá vỡ thành nhiều phần và bỏ lỡ "ngõ cụt". Dưới đây là một ví dụ (Nr 2) ăn mòn một đường và không cho độ dày tường tối thiểu sai:
    nhập mô tả hình ảnh ở đây
  • Trước tiên hãy tìm trục trung gian, sau đó tìm kiếm vòng tròn tối thiểu trên trục trung gian đang che nhưng không chồng lấp khu vực đa giác. Chỉnh sửa: Có vấn đề là nhiều "ứng cử viên sai" trên trục trung gian: Ví dụ. (Nr 1) vòng tròn A sẽ sai, vòng tròn B sẽ biểu thị độ dày thành tối thiểu chính xác:
    nhập mô tả hình ảnh ở đây

Lấy khoảng cách giữa tất cả các cặp dòng để tìm những cái gần nhất.
bugmenot123

Vì vậy, điều gì đã sai với cách tiếp cận trục trung gian?
Hornbydd

1
@Hornbydd: Vấn đề là, có nhiều vòng tròn trên trục trung gian đang chạm vào các góc nhưng không xác định độ dày của tường. Xem ví dụ thứ hai : vòng tròn A sẽ sai, vòng tròn B sẽ là vị trí chính xác của độ dày tường tối thiểu. Vì vậy, trục trung gian trông giống như một đường vòng tốn kém tính toán và không cung cấp câu trả lời đúng ...
Oliver Staubli

1
Nếu bạn làm xói mòn cho đến khi đa giác suy biến thành hai đa giác chạm vào một điểm, thì vị trí sẽ là nơi một vòng tròn bán kính giống như bộ đệm ở giữa chạm vào đa giác ban đầu. Đó là một giả thuyết được đưa ra mà không có bằng chứng nhưng tôi không thể thấy một ví dụ ...
Spainedman

1
@OliverStaubli Đề nghị của tôi là kiểm tra không chỉ các cạnh của tam giác delaunay, mà cả chiều cao của các tam giác đó có một cạnh trên đường biên và hai cạnh còn lại ở bên trong đa giác. Trong ví dụ Nr.3 chiều cao của hình tam giác dưới hình vuông màu xanh lá cây là những gì bạn đang tìm kiếm. (tùy thuộc vào các ràng buộc của phép tính tam giác, bạn cũng có thể cần phải lọc ra một số ứng cử viên trong các tam giác bị
che khuất

Câu trả lời:


1

Một trong những phương pháp hiệu quả nhất để tìm độ dày thành tối thiểu (giá trị và vị trí) của một khu vực đa giác không lồi phức tạp bao gồm các lỗ, có thể bằng cách sử dụng một lớp cách đều đặn (hoặc ngẫu nhiên) các điểm để xác định, đầu tiên, phân đoạn gần nhất với bối cảnh cho từng điểm và, tiếp theo, điểm giao nhau giữa phân đoạn tăng dần và đa giác phía đối diện; có trụ sở tại cosines giám đốc.

Khoảng cách tăng dần có thể được sử dụng cho đến khi đoạn đầu tiên chạm tới và giao với một số đa giác bên (độ dày thành tối thiểu).

Để thử cách tiếp cận của tôi, tôi đã nhân bản đa giác của bạn bằng các lỗ và tạo một lớp điểm ngẫu nhiên bên trong đa giác với 100 điểm; như nó có thể được quan sát ở hình ảnh sau:

nhập mô tả hình ảnh ở đây

Mã được sử dụng PyQGIS trông như sau:

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

và nó tạo ra một lớp bộ nhớ khoảng cách gia tăng (chỉ dành cho mục đích trực quan hóa) và in độ dày thành tối thiểu ở định dạng WKT.

Sau khi chạy mã tại Bảng điều khiển Python của QGIS, tôi nhận được kết quả như sau:

nhập mô tả hình ảnh ở đây

Có thể thấy rằng chỉ có một khoảng cách gia tăng đạt được phía đối diện trước tiên trong khu vực dự kiến.

Định dạng WKT được in (cho độ dày thành tối thiểu) được sử dụng với plugin QuickWKT của QGIS để hiển thị phân đoạn đó ở hình ảnh sau:

nhập mô tả hình ảnh ở đây

Độ nghiêng nhẹ được tạo ra do "phân đoạn gần nhất với bối cảnh" được nối với một đỉnh; thay vào đó là đa giác. Tuy nhiên, nó có thể tránh được với một ngoại lệ mã hoặc nhiều điểm hơn.


1

Thêm hai ý tưởng để ném vào nồi:

  1. Rasterize đa giác của bạn và sử dụng một biến đổi khoảng cách (trả về hình ảnh của khoảng cách ngắn nhất từ ​​mỗi pixel khác không thành pixel không). Skeletonize hình ảnh rasterized của bạn, sau đó lấy các giá trị của hình ảnh biến đổi khoảng cách dọc theo bộ xương. Từ bộ đó, bạn sẽ có một số mức tối thiểu tương ứng với chiều rộng hẹp nhất của bạn. Bộ này có thể được sử dụng làm điểm tìm kiếm ban đầu để sau đó thực hiện phương pháp tiếp cận vũ phu của bạn. Tôi nên lưu ý rằng bộ xương sẽ chia đôi các góc của các vật thể và tại các vị trí đó, biến đổi khoảng cách sẽ tiến đến 0 (khi bạn tiến gần hơn đến ranh giới của vật thể). Điều này có thể có vấn đề, nhưng đại diện cho một vấn đề với vấn đề của bạn - tại sao có thể ' t chiều rộng nhỏ nhất nằm ở một góc (và về cơ bản là bằng 0)? Bạn có thể giải quyết vấn đề này bằng cách đặt ngưỡng trên khoảng cách ngắn nhất xung quanh chu vi giữa hai điểm (nếu chúng nằm trên cùng một đối tượng). Bạn có thể sử dụng biến đổi khoảng cách trắc địa trên tập hợp các pixel chu vi để nhanh chóng tìm thấy giá trị đó.

    Phương pháp này yêu cầu bạn đưa ra quyết định về độ phân giải của đa giác rasterized, đưa ra một số phụ thuộc tỷ lệ. Và nếu bạn chọn độ phân giải quá cao, biến đổi khoảng cách có thể tốn thời gian. Nhưng nhìn chung chúng khá nhanh. Phương pháp này có thể không cung cấp cho bạn độ chính xác mà bạn muốn, nhưng ít nhất nó có thể cung cấp cho bạn một bộ vị trí nhỏ hơn cần kiểm tra.

  2. Phương pháp vũ phu của bạn không phải là một nơi tồi tệ để bắt đầu. Tôi đã gặp một vấn đề tương tự khi tôi phải tìm tất cả các giao điểm của một dòng (dài) và tôi có thể tăng tốc độ thời gian tìm kiếm rất nhiều bằng thuật toán tìm kiếm cây kd (lúc đó tôi đã sử dụng công cụ tìm kiếm trong Matlab) điểm trong một khu phố đầu tiên. Theo cách đó, bạn chỉ vũ phu - buộc một tập hợp con nhỏ trong tổng số điểm.


Cảm ơn @jon. Cả hai cách tiếp cận đầy hứa hẹn. Tôi đã xem xét kdTree rồi nhưng hy vọng vấn đề được mô tả có giải pháp "sao chép-dán" nổi tiếng :-) Sẽ phải đào sâu hơn ...
Oliver Staubli

0

Cách tiếp cận trục trung gian là chính xác, bạn chỉ cần một tiêu chí để bỏ qua các vòng tròn xấu: Mỗi vòng tròn ở trục trung gian chạm vào bề mặt trong hai (hoặc nhiều) điểm. Tưởng tượng các vectơ từ tâm của vòng tròn đến các điểm này trên bề mặt và quan sát rằng góc giữa là 180 ° cho vòng tròn B tốt và chỉ 90 ° cho vòng tròn xấu A.

nhập mô tả hình ảnh ở đây


0

Một thuật toán vẽ đa giác chung hoạt động bằng cách sắp xếp các phân đoạn dòng từ trên xuống dưới và làm việc thông qua chúng để vẽ các dòng pixel trực giao. Vì cách phá vỡ đa giác (không có độ cong) rất nhanh chóng, nó có thể được sử dụng làm cơ sở. Thay vì chỉ đi từ trên xuống dưới, bạn có thể đi 0, 30, 60 và 90 độ và tìm phần trực giao ngắn nhất của bạn (= độ dày thành tối thiểu!), Bạn chỉ phải tính toán một lần cho mỗi điểm và không cho bất kỳ loại 'độ phân giải pixel'.

Xem thuật toán máy tính đồ họa-quét-dòng-đa giác-điền

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.