Aquí muestro un poco de optimización sobre la solución de @whuber, y estoy poniendo en términos de "ancho de búfer", porque es útil para integrar la solución de un problema más general: ¿Existe una función inversa de st_buffer que devuelva una estimación de la anchura?
CREATE FUNCTION buffer_width(
-- rectangular strip mean width estimator
p_len float, -- len of the central line of g
p_geom geometry, -- g
p_btype varchar DEFAULT 'endcap=flat' -- st_buffer() parameter
) RETURNS float AS $f$
DECLARE
w_half float;
w float;
BEGIN
w_half := 0.25*ST_Area(p_geom)/p_len;
w := 0.50*ST_Area( ST_Buffer(p_geom,-w_half,p_btype) )/(p_len-2.0*w_half);
RETURN w_half+w;
END
$f$ LANGUAGE plpgsql IMMUTABLE;
Para este problema, la pregunta de @celenius sobre ancho de la calle , sw
la solución es
sw = buffer_width(ST_Length(g1), g2)
donde sw
es la "anchura media", g1
la línea central de g2
y la calle g2
es un POLÍGONO . He utilizado únicamente la biblioteca estándar OGC, probada con PostGIS , y ha resuelto otras aplicaciones prácticas serias con la misma función buffer_width.
DEMONSTRACIÓN
A2
es el área de g2
, L1
la longitud de la línea central ( g1
) de g2
.
Suponiendo que podamos generar g2
por g2=ST_Buffer(g1,w)
y que g1
es una recta, por lo que g2
es un rectángulo de longitud L1
y la anchura 2*w
y
A2 = L1*(2*w) --> w = 0.5*A2/L1
No es la misma fórmula de @whuber, porque aquí w
es una mitad del rectángulo ( g2
) de ancho. Es un buen estimador, pero como podemos ver mediante pruebas (más abajo), no es exacto, y la función lo utiliza como pista, para reducir el g2
y como estimador final.
Aquí no se evalúan los buffers con "endcap=cuadrado" o "endcap=redondo", que necesitan una suma para A2
de un área de un buffer de puntos con el mismo w
.
REFERENCIAS: en un foro similar de 2005 W. Huber explica estas y otras soluciones.
PRUEBAS Y RAZONES
Para las líneas rectas los resultados, como era de esperar, son exactos. Pero para otras geometrías los resultados pueden ser decepcionantes. La razón principal es, quizás, que todo el modelo es para rectángulos exactos, o para geometrías que pueden aproximarse a un "rectángulo de tira". Aquí hay un "kit de prueba" para comprobar los límites de esta aproximación (ver wfactor
en los resultados anteriores).
SELECT *, round(100.0*(w_estim-w)/w,1) as estim_perc_error
FROM (
SELECT btype, round(len,1) AS len, w, round(w/len,3) AS wfactor,
round( buffer_width(len, gbase, btype) ,2) as w_estim ,
round( 0.5*ST_Area(gbase)/len ,2) as w_near
FROM (
SELECT
*, st_length(g) AS len, ST_Buffer(g, w, btype) AS gbase
FROM (
-- SELECT ST_GeomFromText('LINESTRING(50 50,150 150)') AS g, -- straight
SELECT ST_GeomFromText('LINESTRING(50 50,150 150,150 50,250 250)') AS g,
unnest(array[1.0,10.0,20.0,50.0]) AS w
) AS t,
(SELECT unnest(array['endcap=flat','endcap=flat join=bevel']) AS btype
) AS t2
) as t3
) as t4;
RESULTADOS:
CON RECTÁNGULOS (la línea central es una LÍNEA RECTA):
btype | len | w | wfactor | w_estim | w_near | estim_perc_error
------------------------+-------+------+---------+---------+--------+------------------
endcap=flat | 141.4 | 1.0 | 0.007 | 1 | 1 | 0
endcap=flat join=bevel | 141.4 | 1.0 | 0.007 | 1 | 1 | 0
endcap=flat | 141.4 | 10.0 | 0.071 | 10 | 10 | 0
endcap=flat join=bevel | 141.4 | 10.0 | 0.071 | 10 | 10 | 0
endcap=flat | 141.4 | 20.0 | 0.141 | 20 | 20 | 0
endcap=flat join=bevel | 141.4 | 20.0 | 0.141 | 20 | 20 | 0
endcap=flat | 141.4 | 50.0 | 0.354 | 50 | 50 | 0
endcap=flat join=bevel | 141.4 | 50.0 | 0.354 | 50 | 50 | 0
CON OTROS GEOMETROS (línea central doblada):
btype | len | w | wfactor | w_estim | w_near | estim_perc_error
-----------------------+-----+------+---------+---------+--------+------------------
endcap=flat | 465 | 1.0 | 0.002 | 1 | 1 | 0
endcap=flat join=bevel | 465 | 1.0 | 0.002 | 1 | 0.99 | 0
endcap=flat | 465 | 10.0 | 0.022 | 9.98 | 9.55 | -0.2
endcap=flat join=bevel | 465 | 10.0 | 0.022 | 9.88 | 9.35 | -1.2
endcap=flat | 465 | 20.0 | 0.043 | 19.83 | 18.22 | -0.9
endcap=flat join=bevel | 465 | 20.0 | 0.043 | 19.33 | 17.39 | -3.4
endcap=flat | 465 | 50.0 | 0.108 | 46.29 | 40.47 | -7.4
endcap=flat join=bevel | 465 | 50.0 | 0.108 | 41.76 | 36.65 | -16.5
wfactor= w/len
w_near = 0.5*area/len
w_estim is the proposed estimator, the buffer_width function.
Acerca de btype
véase Guía de ST_Buffer con buenas ilustraciones y los LINESTRINGs utilizados aquí.
CONCLUSIONES :
- el estimador de
w_estim
es siempre mejor que w_near
;
- para "cerca de rectangular"
g2
geometrías, está bien, cualquier wfactor
- para otras geometrías (cercanas a las "tiras rectangulares"), utilice el límite
wfactor=~0.01
para un 1% de error en w_estim
. Hasta este factor w, utilice otro estimador.
Precaución y prevención
¿Por qué se produce el error de estimación? Cuando se utiliza ST_Buffer(g,w)
se espera, por el "modelo de banda rectangular", que la nueva área añadida por el buffer de ancho w
se trata de w*ST_Length(g)
o w*ST_Perimeter(g)
... Cuando no es así, normalmente mediante superposiciones (ver líneas dobladas) o mediante "estilización", es cuando la estimación de la media w
fallo . Este es el mensaje principal de las pruebas.
Para detectar este problema en cualquier rey del buffer , comprueba el comportamiento de la generación del buffer:
SELECT btype, w, round(100.0*(a1-len1*2.0*w)/a1)::varchar||'%' AS straight_error,
round(100.0*(a2-len2*2.0*w)/a2)::varchar||'%' AS curve2_error,
round(100.0*(a3-len3*2.0*w)/a3)::varchar||'%' AS curve3_error
FROM (
SELECT
*, st_length(g1) AS len1, ST_Area(ST_Buffer(g1, w, btype)) AS a1,
st_length(g2) AS len2, ST_Area(ST_Buffer(g2, w, btype)) AS a2,
st_length(g3) AS len3, ST_Area(ST_Buffer(g3, w, btype)) AS a3
FROM (
SELECT ST_GeomFromText('LINESTRING(50 50,150 150)') AS g1, -- straight
ST_GeomFromText('LINESTRING(50 50,150 150,150 50)') AS g2,
ST_GeomFromText('LINESTRING(50 50,150 150,150 50,250 250)') AS g3,
unnest(array[1.0,20.0,50.0]) AS w
) AS t,
(SELECT unnest(array['endcap=flat','endcap=flat join=bevel']) AS btype
) AS t2
) as t3;
RESULTADOS:
btype | w | straight_error | curve2_error | curve3_error
------------------------+------+----------------+--------------+--------------
endcap=flat | 1.0 | 0% | -0% | -0%
endcap=flat join=bevel | 1.0 | 0% | -0% | -1%
endcap=flat | 20.0 | 0% | -5% | -10%
endcap=flat join=bevel | 20.0 | 0% | -9% | -15%
endcap=flat | 50.0 | 0% | -14% | -24%
endcap=flat join=bevel | 50.0 | 0% | -26% | -36%
0 votos
¿Has descartado las posibles soluciones en la barra lateral? ie gis.stackexchange.com/questions/2880/ aparentemente marcado como una respuesta trivial a un post potencialmente duplicado
0 votos
@DanPatterson No he visto ninguna pregunta así (muchas están relacionadas, claro). ¿Quieres decir que mi pregunta estaba marcada? No he entendido tu segunda línea.
0 votos
La pregunta relacionada, @Dan, se refiere a una interpretación diferente de "anchura" (bueno, en realidad, la interpretación no está perfectamente clara). Las respuestas parecen centrarse en la búsqueda de la anchura en el punto más ancho, en lugar de una anchura media.
0 votos
Como @whuber quiere centralizar aquí las discusiones, cerrando otras preguntas, sugiero que se edite la pregunta para que la gente entienda " la estimación de la anchura media de una franja rectangular "
0 votos
@Peter: Como una tira rectangular es a fortiori un polígono, el título más general debería mantenerse.
0 votos
@whuber: no es una conclusión obvia, ver mis pruebas y alerta de "precaución"... Sobre el modelado, la hipótesis de la "polilínea recta" no es sólo para simplificar el cálculo, sino también para evitar los "efectos secundarios" de la construcción del buffer cuando no es una "franja rectangular" (ver el
wfactor
criterios). Hay otros problemas con las líneas centrales de los ríos (muy complejas) y las estimaciones de la anchura de los ríos. Generalizar no es tarea fácil (!).0 votos
@djq ¿Cómo has conseguido las líneas centrales de los polígonos?
0 votos
También estoy interesado en examinar la anchura media de las calles, que son polígonos irregulares, para un proyecto escolar. Estoy usando QGIS 2.12.0 Lyon, pero por desgracia no me deshago de los mensajes de error cuando trato de aplicar la solución de Peter Krauss en QGIS. Me parece que no hay una solución perfecta para encontrar la anchura media de los polígonos irregulares, pero una aproximación sería absolutamente suficiente para mí. Especialmente porque mis conocimientos de programación son demasiado malos para esto. Tal vez, para alguien esto is't un gran problema para programar esto para QGIS y explicar todos los pasos necesarios para que pueda
0 votos
Echa un vistazo a esta herramienta para ver si puede ayudarte a acercarte a tu tarea: gis.stackexchange.com/a/341356/120129