Aquí muestro poca optimización sobre la solución @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: ¿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 acerca @celenius ancho de la calle , sw
la solución es
sw = buffer_width(ST_Length(g1), g2)
donde sw
está el "ancho promedio", g1
la línea central de g2
, y la calle g2
es un POLÍGONO . Utilicé solo la biblioteca estándar OGC, probé con PostGIS y resolví 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 podemos generar g2
por g2=ST_Buffer(g1,w)
, y que g1
es una recta, también lo g2
es un rectángulo con 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
hay una mitad del g2
ancho del rectángulo ( ). Es un buen estimador, pero como podemos ver en las pruebas (a continuación), no es exacto, y la función lo usa como una pista, para reducir el g2
área y como un estimador final.
Aquí no evaluamos buffers con "endcap = square" o "endcap = round", que necesitan una suma A2
de un área de un buffer de puntos con el mismo w
.
REFERENCIAS: en un foro similar de 2005 , W. Huber explica soluciones similares y otras.
PRUEBAS Y RAZONES
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 franja". Aquí un "kit de prueba" para verificar 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 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
ver la guía ST_Buffer , con buenas ilustraciones y los LINESTRING utilizados aquí.
CONCLUSIONES :
- el estimador de
w_estim
siempre es mejor que w_near
;
- para
g2
geometrías "cercanas a rectangulares" , está bien, cualquierwfactor
- para otras geometrías (cerca de "tiras rectangulares"), use el límite
wfactor=~0.01
para 1% de error en w_estim
. Hasta este factor de factor, use otro estimador.
Precaución y prevención
¿Por qué ocurre el error de estimación? Cuando se utiliza ST_Buffer(g,w)
, se espera, por el "modelo de tira rectangular", que la nueva área añadida por el buffer de ancho w
se trata w*ST_Length(g)
o w*ST_Perimeter(g)
... Cuando no está, por lo general por enchapados (ver líneas cruzadas) o por "labrar", es cuando La estimación de la w
falla promedio . Este es el mensaje principal de las pruebas.
Para detectar este problema en cualquier rey del búfer , verifique el comportamiento de la generación del 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%