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 , swrozwiązanie jest
sw = buffer_width(ST_Length(g1), g2)
gdzie swjest „średnia szerokość”, g1środkowa linia g2, a ulica g2to 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
A2Jest to obszar g2, L1długość osi środkowej ( g1I) g2.
Przypuśćmy, że możemy wygenerować g2przez g2=ST_Buffer(g1,w), i że g1jest prosty, więc g2jest prostokątem o długości L1i szerokości 2*w, a
A2 = L1*(2*w) --> w = 0.5*A2/L1
Nie jest to ta sama formuła @whuber, ponieważ tutaj wjest połowa g2szerokoś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ć g2obszar 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 wfactorwyniki 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 btypepatrz przewodnik ST_Buffer z dobrymi ilustracjami i zastosowanymi tutaj LINESTRINGAMI.
WNIOSKI :
- estymator
w_estimjest zawsze lepszy niż w_near;
- dla
g2geometrii „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.011% 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 wwynosi 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 wusterki . 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%
