ที่นี่ฉันแสดงการเพิ่มประสิทธิภาพเล็กน้อยเกี่ยวกับโซลูชัน @whuber และฉันใส่ในแง่ของ "ความกว้างบัฟเฟอร์" เพราะมันมีประโยชน์สำหรับการรวมการแก้ปัญหาทั่วไปมากขึ้น: มีฟังก์ชั่นผกผัน st_buffer ที่ส่งกลับการประมาณความกว้างหรือไม่
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;
สำหรับปัญหานี้คำถาม @celenius เกี่ยวกับความกว้างของถนน , sw
การแก้ปัญหาคือ
sw = buffer_width(ST_Length(g1), g2)
ที่sw
เป็น "ความกว้างเฉลี่ย" g1
สายกลางg2
และถนนg2
เป็นรูปหลายเหลี่ยม ฉันใช้ไลบรารีมาตรฐาน OGC เท่านั้นทดสอบกับPostGISและแก้ไขแอปพลิเคชั่นที่ใช้งานจริงอื่น ๆ ด้วยฟังก์ชั่น buffer_width เดียวกัน
สาธิต
A2
เป็นพื้นที่ของg2
, L1
ความยาวของเส้นกลาง ( g1
) g2
ของ
สมมติว่าเราสามารถสร้างg2
โดยg2=ST_Buffer(g1,w)
และนั่นg1
คือตรงดังนั้นg2
สี่เหลี่ยมที่มีความยาวL1
และความกว้าง2*w
และ
A2 = L1*(2*w) --> w = 0.5*A2/L1
มันไม่ใช่สูตรเดียวกันของ @whuber เพราะนี่w
คือครึ่งหนึ่งของg2
ความกว้างของสี่เหลี่ยมผืนผ้า ( ) มันเป็นตัวประมาณที่ดี แต่อย่างที่เราเห็นได้จากการทดสอบ (ด้านล่าง) นั้นไม่ถูกต้องและฟังก์ชั่นใช้เป็นเบาะแสเพื่อลดg2
พื้นที่และเป็นตัวประมาณขั้นสุดท้าย
ที่นี่เราไม่ได้ประเมินบัฟเฟอร์ด้วย "ปิดท้ายตาราง =" หรือ "ปิดท้าย = รอบ" ที่ต้องรวมให้ พื้นที่ของบัฟเฟอร์จุดที่มีเหมือนกันA2
w
ข้อมูลอ้างอิง: ในฟอรัมที่คล้ายกันของปี 2005 W. Huber อธิบายวิธีแก้ปัญหาเช่นนี้และอื่น ๆ
การทดสอบและเหตุผล
สำหรับเส้นตรงผลลัพธ์จะเป็นไปตามที่คาดไว้ แต่สำหรับรูปทรงอื่น ๆ ผลลัพธ์อาจน่าผิดหวัง เหตุผลหลักคือบางทีแบบจำลองทั้งหมดมีไว้สำหรับสี่เหลี่ยมที่แน่นอนหรือสำหรับรูปทรงเรขาคณิตที่สามารถประมาณเป็น "สี่เหลี่ยมแถบ" นี่คือ "ชุดทดสอบ" เพื่อตรวจสอบข้อ จำกัด ของการประมาณนี้ (ดูwfactor
ในผลลัพธ์ด้านบน)
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;
ผล:
ด้วย RECTANGLES (เส้นกลางเป็นเส้นตรง):
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
กับ GEOMETRIES อื่น ๆ (พับกึ่งกลาง):
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.
เกี่ยวกับbtype
ดูคู่มือ ST_Bufferด้วย ilustratins ที่ดีและ LINESTRING ที่ใช้ที่นี่
สรุป :
- ประมาณการของ
w_estim
อยู่เสมอดีกว่าw_near
;
- สำหรับรูป
g2
ทรงเรขาคณิต"ใกล้ถึงเป็นรูปสี่เหลี่ยมผืนผ้า" ก็ถือว่าใช้ได้wfactor
- สำหรับรูปทรงเรขาคณิตที่อื่น (ใกล้กับ "แถบสี่เหลี่ยม") ให้ใช้ขีด จำกัด
wfactor=~0.01
สำหรับ 1% w_estim
ของข้อผิดพลาดใน ขึ้นอยู่กับ wfactor นี้ใช้ตัวประมาณค่าอื่น
ข้อควรระวังและการป้องกัน
ทำไมข้อผิดพลาดการประเมินเกิดขึ้น? เมื่อคุณใช้ST_Buffer(g,w)
คุณคาดหวังว่าโดย "สี่เหลี่ยมแถบโมเดล" ว่าพื้นที่ใหม่ที่เพิ่มโดยบัฟเฟอร์ของความกว้างw
เป็นเรื่องเกี่ยวกับw*ST_Length(g)
หรือw*ST_Perimeter(g)
... เมื่อไม่ปกติโดยการวางซ้อน (ดูเส้นพับ) หรือโดย "สไตล์" คือเมื่อ การประมาณค่าของค่าเฉลี่ยw
ความผิด นี่คือข้อความหลักของการทดสอบ
ในการตรวจสอบปัญหานี้ที่ King of bufferให้ตรวจสอบพฤติกรรมของการสร้างบัฟเฟอร์:
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;
ผล:
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%