Uno de los métodos más eficientes para encontrar el espesor mínimo de pared (valor y ubicación) de un área de polígono compleja y no convexa que incluye agujeros, podría ser mediante el uso de una capa regularmente espaciada (o aleatoria) de puntos para determinar, primero, el segmento más cercano con contexto para cada punto y, luego, el punto de intersección entre el segmento incremental y el polígono del lado opuesto; basado en directores cosenos.
Las distancias incrementales se pueden usar hasta que el primer segmento alcance e intersecte algún polígono lateral (el grosor mínimo de la pared).
Para probar mi enfoque, cloné su polígono con agujeros y creé una capa de puntos aleatorios dentro del polígono con 100 puntos; como se puede observar en la siguiente imagen:
El código usado de PyQGIS tiene el siguiente aspecto:
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
y produce una capa de memoria de distancias incrementales (solo para fines de visualización) e imprime un grosor de pared mínimo en formato WKT.
Después de ejecutar el código en Python Console de QGIS obtuve el resultado de la siguiente imagen:
Se puede observar que solo una distancia incremental alcanzó primero el lado opuesto en el área esperada.
El formato WKT impreso (para un grosor de pared mínimo) se usa con el complemento QuickWKT de QGIS para visualizar ese segmento en la siguiente imagen:
La ligera inclinación se produjo porque el "segmento más cercano con el contexto" se unió a un vértice; en cambio lado polígono. Sin embargo, se puede evitar con una excepción de código o más puntos.