7

I'm trying to delete a line string using a polygon via ST_Difference. I start with the line string, but when I difference it with a surrounding box, I just get the original line string back:

SELECT 
  ST_AsText(ST_Difference(a, b))
FROM (VALUES(
  ST_GeomFromText('LINESTRING(0 0, 0 1)'),
  ST_GeomFromText('POLYGON((-1 -1, 1 -1, 1 2, -1 2, -1 -1))')
)) AS geom(a, b);

      st_astext      
---------------------
 LINESTRING(0 0,0 1)
(1 row)

Visually, the polygon B fully surrounds line A, as shown below:

+-------------+ B
|             |
|      | A    |
|      |      |
|      |      |
|      |      |
|             |
+-------------+

However, if I shrink the subtracted polygon so it exactly touches the line, then I get an empty line string back:

SELECT 
  ST_AsText(ST_Difference(a, b))
FROM (VALUES(
  ST_GeomFromText('LINESTRING(0 0, 0 1)'),
  ST_GeomFromText('POLYGON((-1 0, 1 0, 1 1, -1 1, -1 0))')
)) AS geom(a, b)


    st_astext     
------------------
 LINESTRING EMPTY
(1 row)

Visually, the second case giving the expected result looks like this, with line A cutting through the middle of polygon B and just touching it:

+------+------+ B
|      | A    |
|      |      |
+------+------+

The documentation specifically says:

If A is completely contained in B then an empty atomic geometry of appropriate type is returned.

So I feel like either this is a bug, or I'm really missing something glaring and/or have a pretty fundamental misunderstanding of what's going on here.

For reference, I'm using the postgis/postgis:14.3.3 docker image (Postgres 14, PostGIS 3.3.1) with a newly created, empty database.

postgis_full_version():

POSTGIS="3.3.1 3786b21" [EXTENSION] PGSQL="140" GEOS="3.9.0-CAPI-1.16.2" PROJ="7.2.1" LIBXML="2.9.10" LIBJSON="0.15" LIBPROTOBUF="1.3.3" WAGYU="0.5.0 (Internal)"
0

2 Answers 2

7

This is almost certainly due to a bug in GEOS 3.9.0. The bug is fixed in GEOS 3.9.1. See this recent GEOS bug report for more details.

3
  • Thank you for the bug fix! This was enough to not just to isolate the cause but to suggest a solution. I was relying on the official docker hub postgis images under the heading "conservative in its release cycle to ensure high stability", but which are compiled against GEOS 3.9.0 containing the bug. There's a separate set of images, also postgis 3.3.1, but compiled against GEOS 3.10.0. As your bug fix is over a year old, the sentence on docker hub suggesting high stability, though entirely defensible, is perhaps a bit unfortunate.
    – rreusser
    Oct 13, 2022 at 22:58
  • (Not to be confused with a lack of gratitude; thanks for the work you do! Postgis and the libraries which power it are amazing. It just feels quite easy to run into this bug, particularly when you're new to postgis and go straight for the path of least resistance, i.e. the "stable" packages at the top of the list on docker hub)
    – rreusser
    Oct 13, 2022 at 23:07
  • 1
    "Stable" in this context means rarely-changing - not necessarily more reliable. It's a quality that's useful when upgrades are difficult or costly, but as @rreusser found, it's double-edged, as it can mean a long wait for a bug-fix. Oct 14, 2022 at 8:15
4

I am getting LINESTRING EMPTY from

SELECT 
  ST_AsText(ST_Difference(a, b))
FROM (VALUES(
  ST_GeomFromText('LINESTRING(0 0, 0 1)'),
  ST_GeomFromText('POLYGON((-1 -1, 1 -1, 1 2, -1 2, -1 -1))')
)) AS geom(a, b);

My versions are:

"PostgreSQL 12.3, compiled by Visual C++ build 1914, 64-bit"

"POSTGIS="3.1.2 3.1.2" [EXTENSION] PGSQL="120" GEOS="3.9.1-CAPI-1.14.1" PROJ="7.1.1" GDAL="GDAL 3.2.3, released 2021/04/27 GDAL_DATA not found" LIBXML="2.9.9" LIBJSON="0.12" LIBPROTOBUF="1.2.1" WAGYU="0.5.0 (Internal)" RASTER"

Please try also with other versions. Hopefully you'll find when the issue appeared so you can make a bug report.

1
  • Thank you! This is very helpful. I'm quite new to postgis, so it seemed almost too simple a query to so easily stumble into a bug, but I'm leaning toward bisecting versions and pursuing this as a bug.
    – rreusser
    Oct 13, 2022 at 19:48

Not the answer you're looking for? Browse other questions tagged or ask your own question.