libgeos / geos

Geometry Engine, Open Source
https://libgeos.org
GNU Lesser General Public License v2.1
1.17k stars 354 forks source link

Multi- empty geometries loose Z/M dimensions #888

Open mwtoews opened 1 year ago

mwtoews commented 1 year ago

Investigating further into HasZ shows some inconsistencies between types. These are expected:

for geom_type in POINT LINESTRING LINEARRING POLYGON; do
  geom="$geom_type Z EMPTY"
  echo "$geom"
  echo -n "  copy: "
  ./bin/geosop -a "$geom" -f wkt
  echo -n "  hasZ: "
  ./bin/geosop -a "$geom" -f txt hasZ
done

outputs

POINT Z EMPTY
  copy: POINT Z EMPTY
  hasZ: true
LINESTRING Z EMPTY
  copy: LINESTRING Z EMPTY
  hasZ: true
LINEARRING Z EMPTY
  copy: LINEARRING Z EMPTY
  hasZ: true
POLYGON Z EMPTY
  copy: POLYGON Z EMPTY
  hasZ: true

and similar expected behaviour with M/ZM coordinate types.

However, these are not expected:

for geom_type in GEOMETRYCOLLECTION MULTIPOINT MULTILINESTRING MULTIPOLYGON; do
  geom="$geom_type Z EMPTY"
  echo "$geom"
  echo -n "  copy: "
  ./bin/geosop -a "$geom" -f wkt
  echo -n "  hasZ: "
  ./bin/geosop -a "$geom" -f txt hasZ
done

outputs

GEOMETRYCOLLECTION Z EMPTY
  copy: GEOMETRYCOLLECTION EMPTY
  hasZ: false
MULTIPOINT Z EMPTY
  copy: MULTIPOINT EMPTY
  hasZ: false
MULTILINESTRING Z EMPTY
  copy: MULTILINESTRING EMPTY
  hasZ: false
MULTIPOLYGON Z EMPTY
  copy: MULTIPOLYGON EMPTY
  hasZ: false

and similar behaviour with M/ZM coordinate types. The expected behaviour should mimic the non-multi empty geometries, similar to PostGIS:

postgis=# select st_astext('POINT Z EMPTY');
   st_astext   
---------------
 POINT Z EMPTY
(1 row)

postgis=# select st_astext('MULTIPOINT Z EMPTY');
     st_astext      
--------------------
 MULTIPOINT Z EMPTY
(1 row)

postgis=# select st_astext('GEOMETRYCOLLECTION Z EMPTY');
         st_astext          
----------------------------
 GEOMETRYCOLLECTION Z EMPTY
(1 row)
mwtoews commented 1 year ago

Unfortunately, this one is beyond my C++ abilities to fix. Any help/pointers would be appreciated!

dbaston commented 1 year ago

The issue is that collections don't actually store their own dimensions, they just check their sub-geometries on request:

https://github.com/libgeos/geos/blob/main/src/geom/GeometryCollection.cpp#L168

To store MULTIPOLYGON Z EMPTY you would need to modify GeometryCollection to store this directly.

pramsey commented 1 year ago

And then the basic geometries go and check their coordinate sequence...

https://github.com/libgeos/geos/blob/main/src/geom/Polygon.cpp#L149

pramsey commented 1 year ago

Doesn't feel like there's anything more elegant solution-wise than an isEmpty member on Geometry, am I missing anything?