Burada @whuber çözümü hakkında çok az optimizasyon gösteriyorum ve "tampon genişliği" terimini kullanıyorum, çünkü daha genel bir sorunun çözümünü bütünleştirmek için kullanışlıdır: genişlik tahmini veren bir st_buffer ters fonksiyonu var mı?
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;
Bu sorun için, yaklaşık @celenius soru sokak genişliği , sw
, çözüm
sw = buffer_width(ST_Length(g1), g2)
Burada sw
"ortalama genişlik", g1
orta hat g2
ve cadde g2
bir POLYGON'dur . Yalnızca PostGIS ile test edilen OGC standart kütüphanesini kullandım ve aynı tampon_width işleviyle diğer ciddi pratik uygulamaları çözdüm.
GÖSTERİ
A2
alanıdır g2
, L1
(merkezi çizgisinin uzunluğu g1
) arasında g2
.
Biz üretebilir olduğu düşünüldüğünde g2
ile g2=ST_Buffer(g1,w)
, ve bu g1
bir düz, yani g2
uzunluğu olan bir dikdörtgendir L1
ve genişliği 2*w
, ve
A2 = L1*(2*w) --> w = 0.5*A2/L1
@Whuber ile aynı formül değil, çünkü burada w
rectangle ( g2
) genişliğinin yarısı var . İyi bir tahmincidir, ancak testlerle görebileceğimiz gibi (aşağıda) kesin değildir ve işlev g2
alanı azaltmak için ve nihai bir tahminci olarak bunu bir ipucu olarak kullanır .
Burada "endcap = square" veya "endcap = round" olan tamponları değerlendirmiyoruz, bununla A2
aynı olan bir nokta tamponu alanının toplamına ihtiyaç var w
.
KAYNAKLAR: 2005 yılının benzer bir forumunda , W. Huber, bunun gibi ve diğer çözümleri açıklar.
TESTLER VE NEDENLER
Düz çizgiler için sonuçlar beklendiği gibi kesindir. Ancak diğer geometriler için sonuçlar hayal kırıklığı yaratabilir. Asıl sebep, belki de tüm model tam dikdörtgenler veya "şerit dikdörtgene" yaklaşılabilen geometriler içindir. İşte bu yaklaşımın sınırlarını kontrol etmek için bir "test kiti" ( wfactor
yukarıdaki sonuçlara bakınız).
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;
SONUÇLAR:
Dikdörtgenler (merkez hattı düz bir çizgidir):
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
DİĞER GEOMETRİLERLE (merkez hattı katlanmış):
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.
Hakkında iyi bir ilustratinler ve burada kullanılan LINESTRING'ler içeren ST_Buffer rehberinebtype
bakınız .
SONUÇLAR :
- tahmincisi
w_estim
daima daha iyidir w_near
;
- "dikdörtgene yakın"
g2
geometriler için, tamamwfactor
- Başka bir geometri için ("dikdörtgen şeritlerin" yakınında),
wfactor=~0.01
hatanın% 1'i için sınırı kullanın w_estim
. Bu wfactor'a kadar başka bir tahmin cihazı kullanın.
Dikkat ve önleme
Tahmin hatası neden oluşur? Kullandığınızda ST_Buffer(g,w)
, "dikdörtgen şerit modeli" ile genişlik tamponu tarafından eklenen yeni alanın w
yaklaşık w*ST_Length(g)
veya w*ST_Perimeter(g)
... olacağını beklersiniz . ortalama w
hatanın tahmini . Bu, testlerin ana mesajıdır.
Bu sorunu herhangi bir tampon kralı için tespit etmek için, tampon üretim davranışını kontrol edin:
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;
SONUÇLAR:
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%