[PostGIS] #5911: ST_ClipByBox2D shows precision issues when clipping curved geometries
PostGIS
trac at osgeo.org
Wed May 28 01:51:53 PDT 2025
#5911: ST_ClipByBox2D shows precision issues when clipping curved geometries
----------------------------+---------------------------
Reporter: dmyzl | Owner: pramsey
Type: defect | Status: new
Priority: medium | Milestone: PostGIS 3.5.4
Component: postgis | Version: 3.5.x
Keywords: ST_ClipByBox2D |
----------------------------+---------------------------
The return value of the `ST_ClipByBox2D` function appears to be highly
sensitive to floating-point precision. For example, consider the following
case where a curved geometry is created and then clipped using a BOX2D
generated from the same geometry:
{{{
select st_astext(ST_ClipByBox2D(
st_geomfromtext('circularstring(0 0, 20 20, 1 0)', 4369), -- curve
box2d(st_geomfromtext('circularstring(0 0, 20 20, 1 0)', 4369)) --
curve's box2d
));
}}}
I think the result should be identical to the original curve, since the
bounding box is derived from the geometry itself. However, the actual
output is a clipped version of the curve:
{{{
-- expected:
CIRCULARSTRING(0 0,20 20,1 0)
-- actually return:
LINESTRING(0 0,-0.956217377487237 0.048022441162846,-1.908926599762526
0.14290640005694,-2.855832506861942 0.28442329291445,-3.794653919516114
0.472232193145072,-4.723129134710917 0.705880652658024,-5.63902137432812
0.984805791849158,-6.540124173739798 1.308335655627204,-7.424266697374892
1.675690832212453,-8.289318968452221 2.085986330807994,-9.133197000281127
2.538233713620073,-9.953867816767952 3.031343477091301,-10.749354350033514
3.564127676610166,-11.517740203342775
4.135302788373643,-12.257174267872456
4.743492801508452,-12.965875182194335
5.387232533001804,-13.642135623730946 6.064971157455592,-14.28432642184521
6.775075943160619,-14.89090048265519 7.515836185490278,-15.460396516118793
8.285467328137871,-15.991442556409432
9.082115262269028,-16.482759267101912
9.903860793232306,-16.933163023205918
10.748724264067215,-17.341568762622284
11.614670324671216,-17.70699260015264
12.499612835136393,-18.028554197765015
13.401419891443219,-18.305478885405304
14.317918961404084,-18.537099527245235
15.246902118483618,-18.722858128871056
16.18613136088711,-18.86230718154091 17.133344003102838,-18.95511074027262
18.086258126909666,-19.00104523316457 19.04257807871793,-19
19.999999999999993,-18.951977558837154
20.956217377487235,-18.85709359994306
21.908926599762534,-18.715576707085546
22.855832506861944,-18.52776780685493
23.794653919516115,-18.294119347341976
24.723129134710913,-18.015194208150845
25.63902137432811,-17.691664344372796
26.540124173739798,-17.324309167787547
27.424266697374897,-16.914013669192006
28.28931896845222,-16.461766286379927
29.13319700028113,-15.968656522908699
29.953867816767954,-15.435872323389837
30.749354350033506,-14.864697211626357
31.517740203342775,-14.25650719849155
32.25717426787246,-13.612767466998196
32.96587518219434,-12.935028842544408
33.642135623730944,-12.224924056839388
34.28432642184521,-11.484163814509717 34.8909004826552,-10.714532671862129
35.46039651611879,-9.917884737730974 35.99144255640943,-9.096139206767694
36.48275926710191,-8.251275735932785 36.93316302320592,-7.385329675328776
37.34156876262229,-6.500387164863607 37.70699260015264,-5.598580108556783
38.02855419776502,-4.682081038595918 38.30547888540531,-3.753097881516383
38.53709952724523,-2.813868639112898 38.72285812887105,-1.866655996897162
38.86230718154091,-0.913741873090335 38.955110740272616,0.04257807871793
39.001045233164575,0.999999999999992 39,1.956217377487226
38.95197755883716,2.908926599762533 38.857093599943056,3.855832506861944
38.715576707085546,4.794653919516112 38.52776780685493,5.723129134710911
38.294119347341976,6.63902137432811 38.015194208150845,7.540124173739804
37.691664344372796,8.424266697374893 37.32430916778755,9.28931896845222
36.914013669192,10.133197000281125 36.46176628637993,10.95386781676795
35.9686565229087,11.749354350033506 35.43587232338984,12.517740203342772
34.86469721162636,13.257174267872454 34.25650719849155,13.965875182194333
33.6127674669982,14.642135623730944 32.93502884254441,15.284326421845204
32.224924056839384,15.890900482655184 31.484163814509728,16.46039651611879
30.71453267186213,16.99144255640943 29.917884737730972,17.482759267101912
29.096139206767695,17.933163023205918 28.251275735932786,18.34156876262228
27.38532967532879,18.70699260015263 26.500387164863625,19.028554197765015
25.598580108556785,19.305478885405304
24.682081038595918,19.537099527245235
23.753097881516382,19.722858128871056 22.8138686391129,19.86230718154091
21.86665599689718,19.95511074027262 20.913741873090338,20.00104523316457
19.957421921282073,20 19.00000000000001,19.951977558837154
18.043782622512776,19.857093599943063 17.091073400237487,19.71557670708555
16.144167493138056,19.527767806854932 15.205346080483888,19.29411934734198
14.27687086528909,19.015194208150845 13.36097862567189,18.6916643443728
12.459875826260213,18.324309167787547
11.575733302625107,17.914013669192006
10.710681031547782,17.461766286379927 9.866802999718875,16.9686565229087
9.04613218323205,16.435872323389837 8.250645649966497,15.86469721162637
7.482259796657241,15.25650719849155 6.742825732127546,14.612767466998198
6.034124817805667,13.93502884254441 5.357864376269056,13.22492405683939
4.715673578154796,12.484163814509733 4.109099517344816,11.71453267186213
3.539603483881208,10.917884737730978 3.008557443590568,10.096139206767695
2.517240732898088,9.251275735932788 2.066836976794082,8.385329675328794
1.65843123737772,7.500387164863626 1.293007399847369,6.598580108556786
0.971445802234985,5.68208103859592 0.694521114594696,4.753097881516386
0.462900472754765,3.813868639112901 0.277141871128944,2.866655996897182
0.13769281845909,1.913741873090338 0.04488925972738,1 0)
}}}
Upon further inspection, the center of the arc lies at `(0.5, 19.5)`, and
its radius is approximately `19.00640920313115955764`. The bounding box
returned by Box2D appears to slightly underestimate the maximum x value:
{{{
select st_astext(
box2d(st_geomfromtext('circularstring(0 0, 20 20, 1 0)', 4369))
);
-- return:
POLYGON((-19.00640920313116 0,-19.00640920313116
39.006409203131156,20.00640920313116 39.006409203131156,20.00640920313116
0,-19.00640920313116 0))
}}}
To account for this, I tried slightly enlarging the bounding box in all
dimensions to ensure it fully contained the curve, but the result was
still not as expected. I continued adjusting the box until I increased or
decreased the fifth decimal place of the bounding box's min/max
coordinates — only then did the function return the expected result:
{{{
select st_astext(ST_ClipByBox2D(
st_geomfromtext('circularstring(0 0, 20 20, 1 0)', 4369),
st_geomfromtext('POLYGON((-19.00640920313116
-0.00640920313116,-19.00640920313116 39.00640920313116,20.00640920313116
39.00640920313116,20.00640920313116 -0.00640920313116,-19.00640920313116
-0.00640920313116))', 4369)
)
);
-- return:
-- (The very long result above)
select st_astext(ST_ClipByBox2D(
st_geomfromtext('circularstring(0 0, 20 20, 1 0)', 4369),
st_geomfromtext('POLYGON((-19.00641 -0.00641,-19.00641
39.00641,20.00641 39.00641,20.00641 -0.00641,-19.00641 -0.00641))', 4369)
));
-- return:
-- (The very long result above)
select st_astext(ST_ClipByBox2D(
st_geomfromtext('circularstring(0 0, 20 20, 1 0)', 4369),
st_geomfromtext('POLYGON((-19.00642 -0.00642,-19.00642
39.00642,20.00642 39.00642,20.00642 -0.00642,-19.00642 -0.00642))', 4369)
));
-- return:
-- CIRCULARSTRING(0 0,20 20,1 0)
}}}
I'm not sure if this level of sensitivity to floating-point precision is
expected behavior for this function.
postgis_full_version:
{{{
POSTGIS="3.5.3 0" [EXTENSION] PGSQL="170" GEOS="3.13.1-CAPI-1.19.2"
SFCGAL="SFCGAL 1.5.0, CGAL 5.6, BOOST 1.74.0" PROJ="9.3.1
NETWORK_ENABLED=OFF URL_ENDPOINT=https://cdn.proj.org
USER_WRITABLE_DIRECTORY=/home/yzl/.local/share/proj
DATABASE_PATH=/home/yzl/project/build_pg_postgis/proj-9.3.1/tmp_install/share/proj/proj.db"
(compiled against PROJ 9.3.1) GDAL="GDAL 3.7.2, released 2023/09/05"
LIBXML="2.9.13" LIBJSON="0.17" LIBPROTOBUF="1.3.3" WAGYU="0.5.0
(Internal)" (core procs from "3.5.2 dea6d0a" need upgrade) TOPOLOGY
(topology procs from "3.5.2 dea6d0a" need upgrade) RASTER (raster procs
from "3.5.2 dea6d0a" need upgrade) (sfcgal procs from "3.5.2 dea6d0a" need
upgrade)
}}}
--
Ticket URL: <https://trac.osgeo.org/postgis/ticket/5911>
PostGIS <http://trac.osgeo.org/postgis/>
The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project.
More information about the postgis-tickets
mailing list