Hola usuario de nuestro sitio web, hallamos la respuesta a tu pregunta, deslízate y la obtendrás aquí.
Solución:
Parte del problema es encontrar una definición adecuada de “ancho medio”. Varias son naturales pero diferirán, al menos ligeramente. Para simplificar, considere las definiciones basadas en propiedades que son fáciles de calcular (lo que descartará aquellas basadas en la transformación del eje medial o secuencias de búferes, por ejemplo).
Como ejemplo, considere que la intuición arquetípica de un polígono con un “ancho” definido es un pequeño búfer (digamos de radio r con extremos cuadrados) alrededor de una polilínea larga y bastante recta (digamos de longitud L). Pensamos en 2r = w como su ancho. Por lo tanto:
-
Su perímetro PAG es aproximadamente igual a 2L + 2w;
-
Su area A es aproximadamente igual a w L.
La anchura w y longitud L luego se puede recuperar como raíces de la cuadrática x ^ 2 – (P / 2) x + A; en particular, podemos estimar
- w = (P – Cuadrado (P ^ 2 – 16A)) / 4.
Cuando esté seguro de que el polígono es realmente largo y estrecho, como una aproximación adicional puede tomar 2L + 2w para igualar 2L, de donde
- w (toscamente) = 2A / P.
El error relativo en esta aproximación es proporcional a w / L: cuanto más delgado es el polígono, más cercano está w / L a cero y mejor se vuelve la aproximación.
Este enfoque no solo es extremadamente simple (simplemente divida el área por el perímetro y multiplique por 2), con cualquiera de las fórmulas, no importa cómo está orientado el polígono o dónde está situado (porque tales movimientos euclidianos no cambian el área ni el perímetro).
Podría considerar usar cualquiera de estas fórmulas para estimar el ancho promedio para los polígonos que representan segmentos de calles. El error que comete en la estimación original de w (con la fórmula cuadrática) se produce porque el área A también incluye pequeñas cuñas en cada curva de la polilínea original. Si la suma de los ángulos de curvatura es t radianes (esta es la curvatura absoluta total de la polilínea), entonces realmente
-
P = 2L + 2w + 2 Pi tw y
-
A = L w + Pi tw ^ 2.
Inserte estos en la solución anterior (fórmula cuadrática) y simplifique. Cuando el humo se aclara, la contribución del término de curvatura t ¡ha desaparecido! Lo que originalmente parecía una aproximación es perfectamente preciso para los búferes de polilínea que no se intersecan automáticamente (con extremos cuadrados). Para polígonos de ancho variable, esto es, por lo tanto, un valor razonable. definición de ancho medio.
Aquí muestro poca optimización sobre la solución @whuber, y lo estoy poniendo en términos de “ancho de búfer”, porque es útil para integrar la solución de un problema más general: ¿Hay una función inversa st_buffer que devuelve una estimación de ancho?
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 solucion es
sw = buffer_width(ST_Length(g1), g2)
dónde sw
es el “ancho medio”, g1
la línea central de g2
y la calle g2
es un POLÍGONO. Usé solo la biblioteca estándar OGC, probada con PostGISy resolvió otras aplicaciones prácticas serias con la misma función buffer_width.
DEMOSTRACIÓ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 eso g1
es una recta, entonces g2
es un rectángulo de longitud L1
y ancho 2*w
, y
A2 = L1*(2*w) --> w = 0.5*A2/L1
No es la misma fórmula de @whuber, porque aquí w
es la mitad del rectángulo (g2
) ancho. Es un buen estimador, pero como podemos ver en las pruebas (abajo), no es exacto, y la función lo usa como pista para reducir el g2
área, y como estimador final.
Aquí no evaluamos búferes con “endcap = square” o “endcap = round”, que necesitan una suma para A2
de un área de un búfer de puntos con el mismo w
.
REFERENCIAS: en un foro similar de 2005, W. Huber explica tales y otras soluciones.
PRUEBAS Y MOTIVOS
Para líneas rectas, los resultados, como se esperaba, 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 se pueden aproximar a un “rectángulo de tira”. Aquí 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 OTRAS GEOMETRÍAS (línea central plegada):
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.
Sobre btype
consulte la guía ST_Buffer, con buenas ilustraciones y los LINESTRING utilizados aquí.
CONCLUSIONES:
- el estimador de
w_estim
siempre es mejor quew_near
; - para “casi rectangular”
g2
geometrías, está bien, cualquierawfactor
- para otras geometrías (cerca de “franjas rectangulares”), utilice el límite
wfactor=~0.01
para el 1% de error enw_estim
. Hasta este factor, utilice otro estimador.
Precaución y prevención
¿Por qué ocurre el error de estimación? Cuando usas ST_Buffer(g,w)
, usted espera, por el “modelo de franja rectangular”, que la nueva área agregada por el búfer de ancho w
es sobre w*ST_Length(g)
o w*ST_Perimeter(g)
… Cuando no, normalmente por superposiciones (ver líneas dobladas) o por “estilo”, es cuando la estimación del promedio w
culpa. Este es el mensaje principal de las pruebas.
Para detectar este problema en cualquier rey de búfer, verifique el comportamiento de la generación de búfer:
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%
Si puede unir sus datos de polígono a los datos de su línea central (por medios espaciales o tabulares), simplemente sume las áreas del polígono para cada alineación de la línea central y divida por la longitud de la línea central.
Si sostienes algún reparo y forma de arreglar nuestro artículo puedes realizar un informe y con deseo lo estudiaremos.