From 827113edc2247bb46240e029b4eeeb26aa73050b Mon Sep 17 00:00:00 2001
From: Sandro Santilli <strk@keybit.net>
Date: Thu, 1 Jul 2010 13:20:43 +0000
Subject: [PATCH] Add ST_isCollection (see ticket #549)

git-svn-id: http://svn.osgeo.org/postgis/trunk@5718 b70326c6-7e19-0410-871a-916f4a2858ee
---
 NEWS                             |  1 +
 postgis/lwgeom_functions_basic.c | 16 ++++++++++++++++
 postgis/postgis.sql.in.c         |  6 ++++++
 regress/Makefile.in              |  1 +
 regress/iscollection.sql         | 28 ++++++++++++++++++++++++++++
 regress/iscollection_expected    | 15 +++++++++++++++
 6 files changed, 67 insertions(+)
 create mode 100644 regress/iscollection.sql
 create mode 100644 regress/iscollection_expected

diff --git a/NEWS b/NEWS
index 5dcb028f8..aabecdd61 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,7 @@ YYYY/MM/DD
   - ST_RemoveRepeatedPoints (Sandro Santilli / Faunalia for RT-SIGTA)
   - ST_GeometryN and ST_NumGeometries support for non-collections
     (Sandro Santilli)
+  - ST_isCollection (Sandro Santilli, yabo)
 
  * Enhancements *
 
diff --git a/postgis/lwgeom_functions_basic.c b/postgis/lwgeom_functions_basic.c
index 4c124758b..496157bd4 100644
--- a/postgis/lwgeom_functions_basic.c
+++ b/postgis/lwgeom_functions_basic.c
@@ -84,6 +84,7 @@ Datum optimistic_overlap(PG_FUNCTION_ARGS);
 Datum ST_GeoHash(PG_FUNCTION_ARGS);
 Datum ST_MakeEnvelope(PG_FUNCTION_ARGS);
 Datum ST_CollectionExtract(PG_FUNCTION_ARGS);
+Datum ST_IsCollection(PG_FUNCTION_ARGS);
 
 void lwgeom_affine_ptarray(POINTARRAY *pa, double afac, double bfac, double cfac,
                            double dfac, double efac, double ffac, double gfac, double hfac, double ifac, double xoff, double yoff, double zoff);
@@ -2977,6 +2978,21 @@ Datum ST_MakeEnvelope(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(result);
 }
 
+PG_FUNCTION_INFO_V1(ST_IsCollection);
+Datum ST_IsCollection(PG_FUNCTION_ARGS)
+{
+	PG_LWGEOM* geom;
+	int type;
+
+        /* Pull only a small amount of the tuple,
+	 * enough to get the type. size = header + type */
+	geom = (PG_LWGEOM*)PG_DETOAST_DATUM_SLICE(PG_GETARG_DATUM(0),
+	                   0, VARHDRSZ + 1);
+
+	type = lwgeom_getType(SERIALIZED_FORM(geom)[0]);
+	PG_RETURN_BOOL(lwgeom_is_collection(type));
+}
+
 PG_FUNCTION_INFO_V1(LWGEOM_makepoint);
 Datum LWGEOM_makepoint(PG_FUNCTION_ARGS)
 {
diff --git a/postgis/postgis.sql.in.c b/postgis/postgis.sql.in.c
index 4c455e7cd..57af0b45e 100644
--- a/postgis/postgis.sql.in.c
+++ b/postgis/postgis.sql.in.c
@@ -4580,6 +4580,12 @@ CREATE OR REPLACE FUNCTION ST_IsSimple(geometry)
 	AS 'MODULE_PATHNAME', 'issimple'
 	LANGUAGE 'C' IMMUTABLE STRICT;
 
+-- Availability: 2.0.0
+CREATE OR REPLACE FUNCTION ST_IsCollection(geometry)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME', 'ST_IsCollection'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
 -- Deprecation in 1.2.3
 CREATE OR REPLACE FUNCTION Equals(geometry,geometry)
 	RETURNS boolean
diff --git a/regress/Makefile.in b/regress/Makefile.in
index b1b092e35..de5d3ef3f 100644
--- a/regress/Makefile.in
+++ b/regress/Makefile.in
@@ -60,6 +60,7 @@ TESTS = \
 	out_geography \
 	in_gml \
 	in_kml \
+	iscollection \
 	regress_ogc \
 	regress_ogc_cover \
 	regress_ogc_prep \
diff --git a/regress/iscollection.sql b/regress/iscollection.sql
new file mode 100644
index 000000000..7e630d3f4
--- /dev/null
+++ b/regress/iscollection.sql
@@ -0,0 +1,28 @@
+-- Ensure there are no false-positives
+SELECT 'point', ST_IsCollection('POINT(42 42)');
+SELECT 'poly', ST_IsCollection('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))');
+SELECT 'line', ST_IsCollection('LINESTRING(0 0, 10 10)');
+
+-- PostGIS doesn't support typed empties...
+--SELECT 'empty point', ST_IsCollection('POINT EMPTY');
+--SELECT 'empty poly', ST_IsCollection('POLYGON EMPTY');
+--SELECT 'empty line', ST_IsCollection('LINESTRING EMPTY');
+
+--Ensure that all collections return true (even if they contain a single geometry).
+SELECT 'empty multipoint', ST_IsCollection('MULTIPOINT EMPTY');
+SELECT 'multipoint', ST_IsCollection('MULTIPOINT((0 0))');
+SELECT 'multipoint+', ST_IsCollection('MULTIPOINT((0 0), (42 42))');
+
+SELECT 'empty multiline', ST_IsCollection('MULTILINESTRING EMPTY');
+SELECT 'multiline', ST_IsCollection('MULTILINESTRING((0 0, 10 10))');
+SELECT 'multiline+', ST_IsCollection('MULTILINESTRING((0 0, 10 10), (100 100, 142 142))');
+
+SELECT 'empty multipoly', ST_IsCollection('MULTIPOLYGON EMPTY');
+SELECT 'multipoly', ST_IsCollection('MULTIPOLYGON(((0 0, 10 0, 10 10, 0 10, 0 0)))');
+SELECT 'multipoly+', ST_IsCollection('MULTIPOLYGON(((0 0, 10 0, 10 10, 0 10, 0 0)), ((100 100, 110 100, 110 110, 100 110, 100 100)))');
+
+SELECT 'empty collection', ST_IsCollection('GEOMETRYCOLLECTION EMPTY');
+SELECT 'collection', ST_IsCollection('GEOMETRYCOLLECTION(POINT(0 0))');
+SELECT 'collection+', ST_IsCollection('GEOMETRYCOLLECTION(POINT(0 0), POINT(42 42))');
+
+
diff --git a/regress/iscollection_expected b/regress/iscollection_expected
new file mode 100644
index 000000000..d292b6d07
--- /dev/null
+++ b/regress/iscollection_expected
@@ -0,0 +1,15 @@
+point|f
+poly|f
+line|f
+empty multipoint|t
+multipoint|t
+multipoint+|t
+empty multiline|t
+multiline|t
+multiline+|t
+empty multipoly|t
+multipoly|t
+multipoly+|t
+empty collection|t
+collection|t
+collection+|t
-- 
2.40.0