Tutaj pokazuję małą optymalizację dotyczącą rozwiązania @whuber i mówię o „szerokości bufora”, ponieważ jest to przydatne do zintegrowania rozwiązania bardziej ogólnego problemu: czy istnieje funkcja odwrotna st_buffer, która zwraca oszacowanie szerokości?
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;
W tym problem, @celenius pytanie o szerokości ulicy , sw
rozwiązanie jest
sw = buffer_width(ST_Length(g1), g2)
gdzie sw
jest „średnia szerokość”, g1
środkowa linia g2
, a ulica g2
to POLYGON . Użyłem tylko standardowej biblioteki OGC, przetestowałem z PostGIS i rozwiązałem inne poważne praktyczne aplikacje z tą samą funkcją bufor_width.
DEMONSTRACJA
A2
Jest to obszar g2
, L1
długość osi środkowej ( g1
I) g2
.
Przypuśćmy, że możemy wygenerować g2
przez g2=ST_Buffer(g1,w)
, i że g1
jest prosty, więc g2
jest prostokątem o długości L1
i szerokości 2*w
, a
A2 = L1*(2*w) --> w = 0.5*A2/L1
Nie jest to ta sama formuła @whuber, ponieważ tutaj w
jest połowa g2
szerokości prostokąta ( ). Jest to dobry estymator, ale jak widzimy w testach (poniżej), nie jest dokładny, a funkcja wykorzystuje go jako wskazówkę, aby zmniejszyć g2
obszar i jako ostateczny estymator.
W tym przypadku nie oceniamy buforów za pomocą „endcap = kwadrat” lub „endcap = okrągły”, które potrzebują sumy do A2
obszaru bufora punktowego o tym samym w
.
ODNIESIENIA: na podobnym forum w 2005 r. W. Huber wyjaśnia podobne i inne rozwiązania.
TESTY I POWODY
W przypadku linii prostych wyniki, zgodnie z oczekiwaniami, są dokładne. Ale w przypadku innych geometrii wyniki mogą być rozczarowujące. Być może głównym powodem jest to, że cały model dotyczy dokładnych prostokątów lub geometrii, które można przybliżyć do „prostokąta paska”. Oto „zestaw testowy” do sprawdzenia granic tego przybliżenia (patrz wfactor
wyniki powyżej).
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;
WYNIKI:
Z PROSTOKĄTAMI (linia środkowa to PROSTA LINIA):
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
Z INNYMI GEOMETRIAMI (linia środkowa złożona):
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.
O tym btype
patrz przewodnik ST_Buffer z dobrymi ilustracjami i zastosowanymi tutaj LINESTRINGAMI.
WNIOSKI :
- estymator
w_estim
jest zawsze lepszy niż w_near
;
- dla
g2
geometrii „zbliżonych do prostokątnych” , jest w porządku, dowolnawfactor
- dla innych geometrii (w pobliżu „prostokątnych pasków”), użyj limitu
wfactor=~0.01
1% błędu na w_estim
. Do tego współczynnika użyj innego estymatora.
Ostrożność i zapobieganie
Dlaczego występuje błąd oszacowania? Kiedy używasz ST_Buffer(g,w)
, spodziewasz się, według „modelu paska prostokątnego”, że nowy obszar dodany przez bufor szerokości w
wynosi około w*ST_Length(g)
lub w*ST_Perimeter(g)
… Kiedy nie, zwykle przez nakładki (patrz linie zagięte) lub „stylizację”, kiedy oszacowanie średniej w
usterki . To jest główne przesłanie testów.
Aby wykryć ten problem w dowolnym królu bufora , sprawdź zachowanie generowania bufora:
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;
WYNIKI:
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%