[postgis-tickets] [PostGIS] #4711: ST_Union loses precision on complex multilinestring geometries
PostGIS
trac at osgeo.org
Mon Jun 29 11:01:56 PDT 2020
#4711: ST_Union loses precision on complex multilinestring geometries
-------------------------+---------------------------
Reporter: dannytoone | Owner: pramsey
Type: defect | Status: new
Priority: medium | Milestone: PostGIS 3.1.0
Component: postgis | Version: 2.5.x
Resolution: | Keywords:
-------------------------+---------------------------
Comment (by dannytoone):
I believe I have a reproducible example using generated data. Please let
me know if you have any problems with running or generating the dataset.
Unfortunately, the geometries are not simple, and simple geometries did
not reproduce this bug, so creating a dataset that recreates the bug is
not simple.
For background, the data I'm working on, that I'm trying to emulate with
this generated data set, is roughly analogous to the license geometries in
the MDS/ITFS frequency bands (2.5-2.7ghz), as regulated by the FCC. They
do not overlap when viewing the same frequencies, but across frequencies
they may overlap. The following temp tables set up a data structure that
is somewhat similar to these license boundaries.
{{{
DROP TABLE IF EXISTS areas;
CREATE TEMP TABLE areas AS
WITH centerpoints AS (
SELECT
row_number() over () as id,
floor(random() * 10 + 1) as lic_group,
ST_SetSRID(ST_MakePoint(random() * 10 + 1, random() * 10 +
1),4326) as centerpoint
FROM generate_series(1,10000)
)
SELECT
id,
lic_group,
centerpoint,
ST_Buffer(centerpoint::geography,10000)::geometry as geom
FROM centerpoints
;
CREATE INDEX idx_geom ON areas USING GIST (geom);
CREATE INDEX idx_group ON areas (lic_group);
DROP TABLE IF EXISTS area_exclusions;
CREATE TEMP TABLE area_exclusions AS
WITH split_lines AS (
SELECT
a.id,
b.id as b_id,
a.lic_group,
a.centerpoint,
a.geom as a_geom,
b.geom as b_geom,
ST_LineFromMultiPoint(ST_Intersection(ST_ExteriorRing(a.geom),ST_ExteriorRing(b.geom)))
as split_line
FROM areas a
INNER JOIN areas b
ON ST_Intersects(a.geom,b.geom)
AND a.lic_group = b.lic_group
AND a.id != b.id
), split_areas AS (
SELECT
id,
b_id,
lic_group,
centerpoint,
ST_Split(ST_Union(a_geom,b_geom),split_line) as split_geom
FROM split_lines
)
SELECT
id,
b_id,
lic_group,
CASE ST_ContainsProperly(ST_GeometryN(split_geom,1),centerpoint)
WHEN false THEN ST_GeometryN(split_geom,1)
WHEN true THEN ST_GeometryN(split_geom,2)
END as geom
FROM split_areas
;
CREATE INDEX idx_e_id ON area_exclusions (id,lic_group);
DROP TABLE IF EXISTS processed_areas;
CREATE TEMP TABLE processed_areas AS
WITH exclusions AS (
SELECT
id,
lic_group,
ST_Union(geom) as geom
FROM area_exclusions
GROUP BY
id,
lic_group
)
SELECT
id,
lic_group,
ST_Difference(i.geom,COALESCE(e.geom,ST_GeomFromEWKT('SRID=4326;
POLYGON EMPTY'))) as geom
FROM areas i
LEFT JOIN exclusions e
USING (id,lic_group)
;
}}}
If I am to query a single `lic_group` I can see that they do not have
overlapping geometries:
{{{
SELECT geom
FROM processed_areas
WHERE lic_group = 1;
}}}
However, across several `lic_group`s, there is plenty of overlap:
{{{
SELECT geom
FROM processed_areas;
}}}
.
=======================
Okay, that is the underlying data. Now onto the actual bug. This table is
merely the processed geometries as an exterior ring linestring.
{{{
DROP TABLE IF EXISTS rings;
CREATE TEMP TABLE rings AS
SELECT id, lic_group, ST_ExteriorRing(geom) as geom
FROM processed_areas
;
}}}
Viewing the rings themselves, we can see there is plenty of precision in
the underlying points contributing to the linestrings:
{{{
SELECT Left(ST_AsText(geom),200)
FROM rings;
=====================
LINESTRING(10.8643881174031 3.77734188849076,10.8626209909011
3.75970533281878,10.8574629500733 3.74275385983207,10.8491123276953
3.72713876384977,10.8378900600966 3.71345998467201,10.8242273509016 3.
LINESTRING(7.57876514569725 2.81432363450241,7.57705816723587
2.7966769867886,7.5719601905669 2.77970431048747,7.56366729736813
2.76405788049345,7.55249832730074 2.75033896339531,7.53888260377069 2.73
LINESTRING(8.47788820510008 6.81387172768232,8.46467044867379
6.8125559523933,8.44701315022753 6.81427415953191,8.43003023487508
6.81940188537274,8.41437401669197 6.82774214951577,8.40064591887797 6.8
...
}}}
However, once unioned, that precision is lost:
{{{
SELECT Left(ST_AsText(ST_Union(geom)),200)
FROM rings;
==================
MULTILINESTRING((8 3,7 3),(8 7,9 7),(2 10,2 9),(10 4,9 4),(4 8,3 8),(2 1,2
2),(5 10,5 11),(9 11,8 11),(9 9,8 9),(3 9,2 9),(11 1,10 1),(10 1,11 2),(11
2,11 1),(3 5,3 4),(5 2,5 1),(10 6,9 6),(9 10,8 10)...
}}}
Again, please let me know if this example works for you to be able to
reproduce.
--
Ticket URL: <https://trac.osgeo.org/postgis/ticket/4711#comment:2>
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