Opened 13 hours ago

Last modified 12 hours ago

#5835 new defect

The variants of ST_Union gives results that are inconsistent with each other

Reported by: nbvfgh Owned by: pramsey
Priority: high Milestone: PostGIS 3.6.0
Component: postgis Version: 3.5.x
Keywords: Cc:

Description

CREATE TABLE t1(geom geometry);
CREATE TABLE t2(geom geometry);

INSERT INTO t1 VALUES('GEOMETRYCOLLECTION(POLYGON EMPTY, POINT EMPTY, LINESTRING(10 10, 10 10))'::geometry);
INSERT INTO t2 VALUES('POINT(1 1)'::geometry);

-- Two-input variant
SELECT ST_AsText(ST_Union(t1.geom, t2.geom)) FROM t1, t2;
-- result{GEOMETRYCOLLECTION(POLYGON EMPTY,POINT EMPTY,LINESTRING(0 0,0 0),POINT(1 1))}

-- Array variant
SELECT ST_AsText(ST_Union(ST_Collect(ARRAY[t1.geom, t2.geom]))) FROM t1, t2;
-- result:{GEOMETRYCOLLECTION(POINT(1 1),LINESTRING EMPTY)}

Two-input variant returns redundant Empty Geometries, a Linestring of length 0 and a Point, while Array variant only returns an Empty Linestring of length 0 and a Point.

This will result in very inconsistent calculations. For example:

SELECT ST_Buffer(ST_Union(t1.geom, t2.geom), 10) FROM t1, t2;
-- result{POLYGON((0.08966060458567 10.91033939541433,0.192147195967696 11.950903220161283,0.761204674887132 13.826834323650896,1.685303876974546 15.55570233019602,2.928932188134523 17.071067811865476,4.444297669803978 18.314696123025453,6.173165676349097 19.238795325112864,8.049096779838713 19.8078528040323,10 20,11.950903220161283 19.807852804032304,13.8268343236509 19.238795325112868,15.555702330196018 18.314696123025456,17.071067811865476 17.071067811865476,18.314696123025453 15.555702330196022,19.238795325112864 13.826834323650903,19.8078528040323 11.950903220161287,20 10,19.807852804032304 8.049096779838717,19.238795325112868 6.173165676349102,18.314696123025453 4.444297669803978,17.071067811865476 2.928932188134525,15.555702330196024 1.685303876974547,13.826834323650898 0.761204674887132,11.950903220161283 0.192147195967696,10.91033939541433 0.08966060458567,10.807852804032304 -0.950903220161282,10.238795325112868 -2.826834323650898,9.314696123025453 -4.555702330196022,8.071067811865476 -6.071067811865475,6.555702330196023 -7.314696123025453,4.826834323650898 -8.238795325112868,2.950903220161283 -8.807852804032304,1 -9,-0.950903220161282 -8.807852804032304,-2.826834323650897 -8.238795325112868,-4.55570233019602 -7.314696123025454,-6.071067811865475 -6.071067811865476,-7.314696123025453 -4.555702330196022,-8.238795325112868 -2.826834323650899,-8.807852804032304 -0.950903220161286,-9 1,-8.807852804032304 2.950903220161284,-8.238795325112868 4.826834323650896,-7.314696123025454 6.55570233019602,-6.071067811865477 8.071067811865476,-4.555702330196022 9.314696123025453,-2.826834323650903 10.238795325112864,-0.950903220161287 10.807852804032303,0.08966060458567 10.91033939541433))}

SELECT ST_Buffer(ST_Union(ST_Collect(ARRAY[t1.geom, t2.geom])), 10) FROM t1, t2;
--result:{POLYGON((11 1,10.807852804032304 -0.950903220161282,10.238795325112868 -2.826834323650898,9.314696123025453 -4.555702330196022,8.071067811865476 -6.071067811865475,6.555702330196023 -7.314696123025453,4.826834323650898 -8.238795325112868,2.950903220161283 -8.807852804032304,1 -9,-0.950903220161282 -8.807852804032304,-2.826834323650897 -8.238795325112868,-4.55570233019602 -7.314696123025454,-6.071067811865475 -6.071067811865476,-7.314696123025453 -4.555702330196022,-8.238795325112868 -2.826834323650899,-8.807852804032304 -0.950903220161286,-9 1,-8.807852804032304 2.950903220161284,-8.238795325112868 4.826834323650896,-7.314696123025454 6.55570233019602,-6.071067811865477 8.071067811865476,-4.555702330196022 9.314696123025453,-2.826834323650903 10.238795325112864,-0.950903220161287 10.807852804032303,1 11,2.950903220161283 10.807852804032304,4.8268343236509 10.238795325112866,6.555702330196018 9.314696123025454,8.071067811865474 8.071067811865477,9.314696123025453 6.555702330196022,10.238795325112864 4.826834323650904,10.807852804032303 2.950903220161287,11 1))}

The buffer of the ST-Union result set consists of two circular regions, while the buffer of the ST-UnaryUnion result set consists of one circular region. In order to see the difference more intuitively, I have uploaded the relevant attachments

version:POSTGIS="3.6.0dev 3.5.0-91-g593df9088" [EXTENSION] PGSQL="170" GEOS="3.13.0-CAPI-1.19.0" SFCGAL="SFCGAL 1.5.2, CGAL 5.6.1, BOOST 1.84.0"

Attachments (3)

Snipaste_2025-01-09_12-37-01.png (14.9 KB ) - added by nbvfgh 13 hours ago.
Buffer of Array variant
Snipaste_2025-01-09_12-38-10.2.png (10.7 KB ) - added by nbvfgh 13 hours ago.
Buffer of two-input variant
Snipaste_2025-01-09_12-38-10.png (10.7 KB ) - added by nbvfgh 13 hours ago.
Buffer of two-input variant

Download all attachments as: .zip

Change History (6)

by nbvfgh, 13 hours ago

Buffer of Array variant

by nbvfgh, 13 hours ago

Buffer of two-input variant

by nbvfgh, 13 hours ago

Buffer of two-input variant

comment:1 by mdavis, 12 hours ago

Are you sure about the result of the two-input variant? I get:

SELECT ST_AsText(ST_Union(
     'GEOMETRYCOLLECTION(POLYGON EMPTY, POINT EMPTY, LINESTRING(10 10, 10 10))'::geometry, 
     'POINT(1 1)'::geometry));
                                    st_astext                                     
----------------------------------------------------------------------------------
 GEOMETRYCOLLECTION(POLYGON EMPTY,POINT EMPTY,LINESTRING(10 10,10 10),POINT(1 1))

Still inconsistent, of course.

comment:2 by mdavis, 12 hours ago

One bug is that the overlay operations should not return collections containing empty elements.

Apart from that, the inconsistency is probably due to two things:

  • the implementation of ST_Union(A, B) may have a bug in handling GeometryCollections
  • the implementation of ST_Union(C) likely strips zero-length LineStrings from the output. This is a GEOS bug documented here: https://github.com/libgeos/geos/issues/1136

in reply to:  1 comment:3 by nbvfgh, 12 hours ago

Replying to mdavis:

Are you sure about the result of the two-input variant? I get:

SELECT ST_AsText(ST_Union(
     'GEOMETRYCOLLECTION(POLYGON EMPTY, POINT EMPTY, LINESTRING(10 10, 10 10))'::geometry, 
     'POINT(1 1)'::geometry));
                                    st_astext                                     
----------------------------------------------------------------------------------
 GEOMETRYCOLLECTION(POLYGON EMPTY,POINT EMPTY,LINESTRING(10 10,10 10),POINT(1 1))

Still inconsistent, of course.

Yes, I have double-checked it, and I am sure about the result of the two-input variant is GEOMETRYCOLLECTION(POLYGON EMPTY,POINT EMPTY,LINESTRING(0 0,0 0),POINT(1 1))

Note: See TracTickets for help on using tickets.