]> granicus.if.org Git - postgis/commitdiff
Add lwgeom_homogenize function. Related to #375. Add cunit related tests
authorOlivier Courtin <olivier.courtin@camptocamp.com>
Sat, 20 Feb 2010 18:25:42 +0000 (18:25 +0000)
committerOlivier Courtin <olivier.courtin@camptocamp.com>
Sat, 20 Feb 2010 18:25:42 +0000 (18:25 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@5265 b70326c6-7e19-0410-871a-916f4a2858ee

liblwgeom/Makefile.in
liblwgeom/cunit/Makefile.in
liblwgeom/cunit/cu_homogenize.c [new file with mode: 0644]
liblwgeom/cunit/cu_homogenize.h [new file with mode: 0644]
liblwgeom/cunit/cu_tester.c
liblwgeom/cunit/cu_tester.h
liblwgeom/liblwgeom.h
liblwgeom/lwcollection.c
liblwgeom/lwhomogenize.c [new file with mode: 0644]
liblwgeom/lwhomogenize.h [new file with mode: 0644]

index 7a1807b3019379f3d965461fd8d61d378cf009c8..f17c9fff0e3cfdae3a32edaed17869b2f9e96af0 100644 (file)
@@ -37,6 +37,7 @@ SA_OBJS = \
        lwmcurve.o \
        lwmsurface.o \
        lwutil.o \
+       lwhomogenize.o \
        lwalgorithm.o \
        lwgunparse.o \
        lwgparse.o \
index 0a052019111d0c4be15369984142425180930528..bbf9d46a2cc024debb6f7ae6cdc454fd1102c591 100644 (file)
@@ -21,6 +21,7 @@ OBJS= \
        cu_geodetic.o \
        cu_measures.o \
        cu_libgeom.o \
+       cu_homogenize.o \
        cu_tester.o 
 
 # If we couldn't find the cunit library then display a helpful message
diff --git a/liblwgeom/cunit/cu_homogenize.c b/liblwgeom/cunit/cu_homogenize.c
new file mode 100644 (file)
index 0000000..31e82df
--- /dev/null
@@ -0,0 +1,278 @@
+/**********************************************************************
+ * $Id$
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ * Copyright 2009 Olivier Courtin <olivier.courtin@oslandia.com>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ **********************************************************************/
+
+#include "cu_homogenize.h"
+
+/*
+** Called from test harness to register the tests in this file.
+*/
+CU_pSuite register_homogenize_suite(void)
+{
+       CU_pSuite pSuite;
+       pSuite = CU_add_suite("Homogenize Suite", init_libgeom_suite, clean_libgeom_suite);
+       if (NULL == pSuite)
+       {
+               CU_cleanup_registry();
+               return NULL;
+       }
+
+       if (    (NULL == CU_add_test(pSuite, "test_coll_point()", test_coll_point)) ||
+               (NULL == CU_add_test(pSuite, "test_coll_line()", test_coll_line))   ||
+               (NULL == CU_add_test(pSuite, "test_coll_poly()", test_coll_poly))   ||
+               (NULL == CU_add_test(pSuite, "test_coll_coll()", test_coll_coll))   ||
+               (NULL == CU_add_test(pSuite, "test_geom()", test_geom))
+          )
+       {
+               CU_cleanup_registry();
+               return NULL;
+       }
+       return pSuite;
+}
+
+/*
+** The suite initialization function.
+** Create any re-used objects.
+*/
+int init_homogenize_suite(void)
+{
+       return 0;
+}
+
+/*
+** The suite cleanup function.
+** Frees any global objects.
+*/
+int clean_homogenize_suite(void)
+{
+       return 0;
+}
+
+
+static do_geom_test(char * in, char * out)
+{
+       LWGEOM *g, *h;
+
+       g = lwgeom_from_ewkt(in, PARSER_CHECK_NONE);
+       h = lwgeom_homogenize(g);
+       if (strcmp(lwgeom_to_ewkt(h, PARSER_CHECK_NONE), out))
+               fprintf(stderr, "\nIn:   %s\nOut:  %s\nTheo: %s\n",
+                       in, lwgeom_to_ewkt(h, PARSER_CHECK_NONE), out);
+       CU_ASSERT_STRING_EQUAL(lwgeom_to_ewkt(h, PARSER_CHECK_NONE), out); 
+       lwfree(g);
+       lwgeom_free(h);
+}
+
+
+static do_coll_test(char * in, char * out)
+{
+       LWGEOM *g, *h;
+
+       g = lwgeom_from_ewkt(in, PARSER_CHECK_NONE);
+       h = lwcollection_homogenize((LWCOLLECTION *) g);
+       if (strcmp(lwgeom_to_ewkt(h, PARSER_CHECK_NONE), out))
+               fprintf(stderr, "\nIn:   %s\nOut:  %s\nTheo: %s\n",
+                       in, lwgeom_to_ewkt(h, PARSER_CHECK_NONE), out);
+       CU_ASSERT_STRING_EQUAL(lwgeom_to_ewkt(h, PARSER_CHECK_NONE), out); 
+       lwfree(g);
+       lwgeom_free(h);
+}
+
+
+void test_coll_point(void)
+{
+       do_coll_test("GEOMETRYCOLLECTION(POINT(1 2))",
+                    "POINT(1 2)");
+
+       do_coll_test("GEOMETRYCOLLECTION(POINT(1 2),POINT(3 4))",
+                    "MULTIPOINT(1 2,3 4)");
+
+       do_coll_test("GEOMETRYCOLLECTION(POINT(1 2),POINT(3 4),POINT(5 6))",
+                    "MULTIPOINT(1 2,3 4,5 6)");
+
+       do_coll_test("GEOMETRYCOLLECTION(MULTIPOINT(1 2,3 4),POINT(5 6))",
+                    "MULTIPOINT(1 2,3 4,5 6)");
+
+       do_coll_test("GEOMETRYCOLLECTION(POINT(1 2),MULTIPOINT(3 4,5 6))",
+                    "MULTIPOINT(1 2,3 4,5 6)");
+
+       do_coll_test("GEOMETRYCOLLECTION(MULTIPOINT(1 2,3 4),MULTIPOINT(5 6,7 8))",
+                    "MULTIPOINT(1 2,3 4,5 6,7 8)");
+}
+
+
+void test_coll_line(void)
+{
+       do_coll_test("GEOMETRYCOLLECTION(LINESTRING(1 2,3 4))",
+                    "LINESTRING(1 2,3 4)");
+
+       do_coll_test("GEOMETRYCOLLECTION(LINESTRING(1 2,3 4),LINESTRING(5 6,7 8))",
+                    "MULTILINESTRING((1 2,3 4),(5 6,7 8))");
+
+       do_coll_test("GEOMETRYCOLLECTION(LINESTRING(1 2,3 4),LINESTRING(5 6,7 8),LINESTRING(9 10,11 12))",
+                    "MULTILINESTRING((1 2,3 4),(5 6,7 8),(9 10,11 12))");
+
+       do_coll_test("GEOMETRYCOLLECTION(MULTILINESTRING((1 2,3 4),(5 6,7 8)),LINESTRING(9 10,11 12))",
+                    "MULTILINESTRING((1 2,3 4),(5 6,7 8),(9 10,11 12))");
+
+       do_coll_test("GEOMETRYCOLLECTION(LINESTRING(1 2,3 4),MULTILINESTRING((5 6,7 8),(9 10,11 12)))",
+                    "MULTILINESTRING((1 2,3 4),(5 6,7 8),(9 10,11 12))");
+
+       do_coll_test("GEOMETRYCOLLECTION(MULTILINESTRING((1 2,3 4),(5 6,7 8)),MULTILINESTRING((9 10,11 12),(13 14,15 16)))",
+                    "MULTILINESTRING((1 2,3 4),(5 6,7 8),(9 10,11 12),(13 14,15 16))");
+}
+
+
+void test_coll_poly(void)
+{
+       do_coll_test("GEOMETRYCOLLECTION(POLYGON((1 2,3 4,5 6,1 2)))",
+                    "POLYGON((1 2,3 4,5 6,1 2))");
+
+       do_coll_test("GEOMETRYCOLLECTION(POLYGON((1 2,3 4,5 6,1 2)),POLYGON((7 8,9 10,11 12,7 8)))",
+                    "MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))");
+
+       do_coll_test("GEOMETRYCOLLECTION(POLYGON((1 2,3 4,5 6,1 2)),POLYGON((7 8,9 10,11 12,7 8)),POLYGON((13 14,15 16,17 18,13 14)))",
+                    "MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)),((13 14,15 16,17 18,13 14)))");
+
+       do_coll_test("GEOMETRYCOLLECTION(MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8))),POLYGON((13 14,15 16,17 18,13 14)))",
+                    "MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)),((13 14,15 16,17 18,13 14)))");
+
+       do_coll_test("GEOMETRYCOLLECTION(POLYGON((1 2,3 4,5 6,1 2)),MULTIPOLYGON(((7 8,9 10,11 12,7 8)),((13 14,15 16,17 18,13 14))))",
+                    "MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)),((13 14,15 16,17 18,13 14)))");
+
+       do_coll_test("GEOMETRYCOLLECTION(MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8))),MULTIPOLYGON(((13 14,15 16,17 18,13 14)),((19 20,21 22,23 24,19 20))))",
+                    "MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)),((13 14,15 16,17 18,13 14)),((19 20,21 22,23 24,19 20)))");
+}
+
+
+void test_coll_coll(void)
+{
+       /* Two different types together must produce a Collection as output */
+       do_coll_test("GEOMETRYCOLLECTION(POINT(1 2),LINESTRING(3 4,5 6))",
+                    "GEOMETRYCOLLECTION(POINT(1 2),LINESTRING(3 4,5 6))");
+
+       do_coll_test("GEOMETRYCOLLECTION(LINESTRING(1 2,3 4),POLYGON((5 6,7 8,9 10,5 6)))",
+                    "GEOMETRYCOLLECTION(LINESTRING(1 2,3 4),POLYGON((5 6,7 8,9 10,5 6)))");
+
+
+       /* Ability to produce a single MULTI with same type */ 
+       do_coll_test("GEOMETRYCOLLECTION(POINT(1 2),LINESTRING(3 4,5 6),POINT(7 8))",
+                    "GEOMETRYCOLLECTION(MULTIPOINT(1 2,7 8),LINESTRING(3 4,5 6))");
+
+       do_coll_test("GEOMETRYCOLLECTION(POINT(1 2),LINESTRING(3 4,5 6),MULTIPOINT(7 8,9 10))",
+                    "GEOMETRYCOLLECTION(MULTIPOINT(1 2,7 8,9 10),LINESTRING(3 4,5 6))");
+
+
+       /* Recursive Collection handle */
+       do_coll_test("GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(1 2))))",
+                    "POINT(1 2)");
+
+       do_coll_test("GEOMETRYCOLLECTION(POINT(1 2),GEOMETRYCOLLECTION(LINESTRING(3 4,5 6)))",
+                    "GEOMETRYCOLLECTION(POINT(1 2),LINESTRING(3 4,5 6))");
+
+
+       /* EMPTY Collection */
+       do_coll_test("GEOMETRYCOLLECTION EMPTY", 
+                    "GEOMETRYCOLLECTION EMPTY"); 
+
+
+       /* Recursive EMPTY Collection */
+       do_coll_test("GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY)",
+                    "GEOMETRYCOLLECTION EMPTY"); 
+
+       do_coll_test("GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY))",
+                    "GEOMETRYCOLLECTION EMPTY"); 
+}
+
+
+void test_geom(void)
+{
+       /* Already simple geometry */
+       do_geom_test("POINT(1 2)",
+                    "POINT(1 2)");
+
+       do_geom_test("LINESTRING(1 2,3 4)",
+                    "LINESTRING(1 2,3 4)");
+
+       do_geom_test("POLYGON((1 2,3 4,5 6,1 2))",
+                    "POLYGON((1 2,3 4,5 6,1 2))");
+
+       do_geom_test("POLYGON((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8))",
+                    "POLYGON((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8))");
+
+
+       /* Empty geometry */
+       do_geom_test("GEOMETRYCOLLECTION EMPTY", 
+                    "GEOMETRYCOLLECTION EMPTY"); 
+
+
+       /* A MULTI with a single geometry inside */
+       do_geom_test("MULTIPOINT(1 2)",
+                    "POINT(1 2)");
+
+       do_geom_test("MULTILINESTRING((1 2,3 4))",
+                    "LINESTRING(1 2,3 4)");
+
+       do_geom_test("MULTIPOLYGON(((1 2,3 4,5 6,1 2)))",
+                    "POLYGON((1 2,3 4,5 6,1 2))");
+
+       do_geom_test("MULTIPOLYGON(((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8)))",
+                    "POLYGON((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8))");
+
+
+       /* A real MULTI */
+       do_geom_test("MULTIPOINT(1 2,3 4)",
+                    "MULTIPOINT(1 2,3 4)");
+
+       do_geom_test("MULTILINESTRING((1 2,3 4),(5 6,7 8))",
+                    "MULTILINESTRING((1 2,3 4),(5 6,7 8))");
+
+       do_geom_test("MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))",
+                    "MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))");
+
+       do_geom_test("MULTIPOLYGON(((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8)),((13 14,15 16,17 18,13 14)))",
+                    "MULTIPOLYGON(((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8)),((13 14,15 16,17 18,13 14)))");
+
+
+       /* A Collection */
+       do_geom_test("GEOMETRYCOLLECTION(POINT(1 2),LINESTRING(3 4,5 6))",
+                    "GEOMETRYCOLLECTION(POINT(1 2),LINESTRING(3 4,5 6))");
+
+
+       /* SRID */
+       do_geom_test("SRID=4326;GEOMETRYCOLLECTION EMPTY",
+                    "SRID=4326;GEOMETRYCOLLECTION EMPTY");
+
+       do_geom_test("SRID=4326;POINT(1 2)",
+                    "SRID=4326;POINT(1 2)");
+
+       do_geom_test("SRID=4326;MULTIPOINT(1 2)",
+                    "SRID=4326;POINT(1 2)");
+
+       do_geom_test("SRID=4326;MULTIPOINT(1 2,3 4)",
+                    "SRID=4326;MULTIPOINT(1 2,3 4)");
+
+       do_geom_test("SRID=4326;MULTILINESTRING((1 2,3 4))",
+                    "SRID=4326;LINESTRING(1 2,3 4)");
+
+       do_geom_test("SRID=4326;MULTILINESTRING((1 2,3 4),(5 6,7 8))",
+                    "SRID=4326;MULTILINESTRING((1 2,3 4),(5 6,7 8))");
+
+       /* 3D and 4D */
+       do_geom_test("POINT(1 2 3)",
+                    "POINT(1 2 3)");
+
+       do_geom_test("POINTM(1 2 3)",
+                    "POINTM(1 2 3)");
+
+       do_geom_test("POINT(1 2 3 4)",
+                    "POINT(1 2 3 4)");
+}
diff --git a/liblwgeom/cunit/cu_homogenize.h b/liblwgeom/cunit/cu_homogenize.h
new file mode 100644 (file)
index 0000000..9ca853f
--- /dev/null
@@ -0,0 +1,29 @@
+/**********************************************************************
+ * $Id:$
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ * Copyright 2009 Olivier Courtin <olivier.courtin@oslandia.com>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ **********************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "CUnit/Basic.h"
+
+#include "libgeom.h"
+#include "cu_tester.h"
+
+/**********************************************************************/
+
+
+/* Test functions */
+void test_coll_point(void);
+void test_coll_line(void);
+void test_coll_poly(void);
+void test_coll_coll(void);
+void test_geom(void);
index 9fd816f0ad10ff1b0e35f49bf7469f90f0dca63c..107c04dee0c55aff79752510a70791fca7ce803e 100644 (file)
@@ -100,6 +100,13 @@ int main()
                return CU_get_error();
        }
 
+       /* Add the homogenize suite to the registry */
+       if (NULL == register_homogenize_suite())
+       {
+               CU_cleanup_registry();
+               return CU_get_error();
+       }
+
        /* Run all tests using the CUnit Basic interface */
        CU_basic_set_mode(CU_BRM_VERBOSE);
        CU_basic_run_tests();
index 8f487c08533568b29f8951896a5ff3067894ffaf..84f981ee6cc036a2eba664f0633d223518bc78ce 100644 (file)
@@ -6,14 +6,17 @@ CU_pSuite register_measures_suite(void);
 CU_pSuite register_geodetic_suite(void);
 CU_pSuite register_libgeom_suite(void);
 CU_pSuite register_cg_suite(void);
+CU_pSuite register_homogenize_suite(void);
 
 int init_measures_suite(void);
 int init_geodetic_suite(void);
 int init_libgeom_suite(void);
 int init_cg_suite(void);
+int init_homogenize_suite(void);
 
 int clean_measures_suite(void);
 int clean_geodetic_suite(void);
 int clean_libgeom_suite(void);
 int clean_cg_suite(void);
+int clean_homogenize_suite(void);
 
index 993769974842f1d46dbb913b8e24be8ba1c5f18e..980afe1552c1c2919f088b324e244641de0c7d11 100644 (file)
@@ -891,6 +891,10 @@ extern uchar *lwgeom_serialize(LWGEOM *geom);
 extern void lwcollection_serialize_buf(LWCOLLECTION *mcoll, uchar *buf, size_t *size);
 extern int lwcollection_ngeoms(const LWCOLLECTION *col);
 
+/* Given a generic geometry/collection, return the "simplest" form. */
+extern LWGEOM *lwgeom_homogenize(const LWGEOM *geom);
+extern LWGEOM *lwcollection_homogenize(const LWCOLLECTION *col);
+
 /*
  * Deserialize an lwgeom serialized form.
  * The deserialized (recursive) structure will store
index f17b257adaa6585f4cefbdbefa4b208352c0cad9..a7c7c77a2dc5d45e53e51eeb2f8e90f650f26c79 100644 (file)
@@ -419,53 +419,6 @@ int lwcollection_ngeoms(const LWCOLLECTION *col)
        return ngeoms;
 }
 
-/*
-** Given a generic collection, return the "simplest" form.
-** eg: GEOMETRYCOLLECTION(MULTILINESTRING()) => MULTELINESTRING()
-**     GEOMETRYCOLLECTION(MULTILINESTRING(), MULTILINESTRING(), POINT()) => GEOMETRYCOLLECTION(MULTILINESTRING(), MULTIPOINT())
-**
-** In general, if the subcomponents are homogeneous, return a properly typed collection.
-** Otherwise, return a generic collection, with the subtypes in minimal typed collections.
-LWCOLLECTION *lwcollection_homogenize(const LWCOLLECTION *c1)
-{
-TODO: pramsey
-}
-*/
-
-/*
-** Given a generic collection, extract and return just the desired types.
-LWGEOM *lwcollection_extract(const LWCOLLECTION *col, char type)
-{
-       LWGEOM **extracted_geoms;
-       extracted_geoms = lwalloc(sizeof(void*)*col->ngeoms);
-       extracted_curgeom = 0;
-       char reqtype = TYPE_GETTYPE(type);
-       for ( i = 0; i < col->ngeoms; i++ )
-       {
-       if( col->geoms[i] )
-               char geomtype = TYPE_GETTYPE(col->geoms[i]->type);
-               if ( geomtype == reqtype )  {
-                       extracted_geoms[extracted_curgeom] = col->geoms[i];
-                       extracted_curgeom++;
-                       continue;
-               }
-               else {
-                       if ( geomtype == COLLECTIONTYPE ) {
-                               LWGEOM *colgeom;
-                               colgeom = lwcollection_extract(col->geoms[i], type);
-                               extracted_geoms[extracted_curgeom] = colgeom->geoms;
-                               extracted_curgeom++;
-                               if( colgeom->bbox ) lwfree(colgeom->bbox);
-                               lwfree(colgeom);
-                               continue;
-                       }
-               }
-TODO: pramsey
-}
-*/
-
-
-
 void lwcollection_free(LWCOLLECTION *col)
 {
        int i;
diff --git a/liblwgeom/lwhomogenize.c b/liblwgeom/lwhomogenize.c
new file mode 100644 (file)
index 0000000..e31005e
--- /dev/null
@@ -0,0 +1,245 @@
+/**********************************************************************
+ * $Id:$
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ * Copyright 2010 Olivier Courtin <olivier.courtin@oslandia.com>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ **********************************************************************/
+
+#include <stdlib.h>
+#include "liblwgeom.h"
+#include "lwhomogenize.h"
+
+
+/*
+ * Known limitation: not (yet ?) support SQL/MM Curves.
+ */
+
+
+/*
+** Given a generic geometry, return the "simplest" form.
+**
+** eg: 
+**     LINESTRING() => LINESTRING()
+**
+**     MULTILINESTRING(with a single line) => LINESTRING()
+**
+**     GEOMETRYCOLLECTION(MULTILINESTRING()) => MULTILINESTRING()
+**
+**     GEOMETRYCOLLECTION(MULTILINESTRING(), MULTILINESTRING(), POINT())
+**      => GEOMETRYCOLLECTION(MULTILINESTRING(), POINT())
+*/
+LWGEOM *
+lwgeom_homogenize(const LWGEOM *geom)
+{
+       LWGEOM *hgeom;
+       unsigned int type=TYPE_GETTYPE(geom->type);
+
+       /* EMPTY Geometry */
+       if (lwgeom_is_empty(geom)) return lwgeom_clone(geom);
+
+       /* Already a simple Geometry */
+       switch (type) {
+               case POINTTYPE:
+               case LINETYPE:
+               case POLYGONTYPE:
+                       return lwgeom_clone(geom);
+       }
+
+       /* A MULTI */
+       switch (type) {
+               case MULTIPOINTTYPE:
+               case MULTILINETYPE:
+               case MULTIPOLYGONTYPE:
+
+                       /* A MULTI with a single geometry inside */
+                       if (((LWCOLLECTION *) geom)->ngeoms == 1) {
+
+                               hgeom =lwgeom_clone((LWGEOM *)
+                                       ((LWCOLLECTION *)geom)->geoms[0]); 
+
+                               hgeom->SRID = geom->SRID;
+                               if (geom->bbox)
+                                       hgeom->bbox = box2d_clone(geom->bbox);
+
+                               return hgeom;
+                       }
+
+                       /* A 'real' MULTI */
+                       return lwgeom_clone(geom);
+       }
+
+       if (type == COLLECTIONTYPE)
+               return lwcollection_homogenize((LWCOLLECTION *) geom);
+
+       lwerror("lwgeom_homogenize: Geometry Type not supported (%i)",
+                       lwgeom_typename(type));
+
+       return NULL; /*Never reach */
+}
+
+
+/*
+** Given a generic collection, return the "simplest" form.
+**
+** eg: GEOMETRYCOLLECTION(MULTILINESTRING()) => MULTILINESTRING()
+**
+**     GEOMETRYCOLLECTION(MULTILINESTRING(), MULTILINESTRING(), POINT())
+**      => GEOMETRYCOLLECTION(MULTILINESTRING(), POINT())
+**
+** In general, if the subcomponents are homogeneous, return a properly
+** typed collection.
+** Otherwise, return a generic collection, with the subtypes in minimal
+** typed collections.
+*/
+LWGEOM *
+lwcollection_homogenize(const LWCOLLECTION *col)
+{
+       unsigned int i;
+        uchar hasz, hasm;
+       LWGEOM *res = NULL;
+        LWCOLLECTION *coll;
+       LWGEOM_HOMOGENIZE *geoms;
+
+        if (!col) lwerror("lwcollection_homogenize: Null input geometry.");
+
+       /* EMPTY Geometry case */
+       if (col->ngeoms == 0)
+                       return (LWGEOM *) lwcollection_construct_empty(col->SRID, 0, 0);
+
+        hasz = TYPE_HASZ(col->type);
+        hasm = TYPE_HASM(col->type);
+
+       /* LWGEOM_HOMOGENIZE struct setup */
+       geoms = lwalloc(sizeof(LWGEOM_HOMOGENIZE));
+        geoms->points = (LWMPOINT *)
+               lwcollection_construct_empty(col->SRID, hasz, hasm);
+        geoms->lines  = (LWMLINE *)
+               lwcollection_construct_empty(col->SRID, hasz, hasm);
+        geoms->polys  = (LWMPOLY *)
+               lwcollection_construct_empty(col->SRID, hasz, hasm);
+
+       /* Parse each sub geom and update LWGEOM_HOMOGENIZE struct */
+        for (i=0 ; i < col->ngeoms ; i++)
+               geoms = lwcollection_homogenize_subgeom(geoms, col->geoms[i]);
+
+       /* Check if struct is mixed typed, and need a COLLECTION as output */
+       if ((geoms->points->ngeoms && geoms->lines->ngeoms) ||
+           (geoms->points->ngeoms && geoms->polys->ngeoms) ||
+           (geoms->lines->ngeoms  && geoms->polys->ngeoms)) {
+
+               coll = lwcollection_construct_empty(col->SRID, hasz, hasm);
+               if (col->bbox) coll->bbox = box2d_clone(col->bbox);
+
+               if (geoms->points->ngeoms == 1)
+                       coll = (LWCOLLECTION *) lwcollection_add(coll, -1,
+                                       (LWGEOM *) geoms->points->geoms[0]);
+               else if (geoms->points->ngeoms)
+                       coll = (LWCOLLECTION *) lwcollection_add(coll, -1,
+                                       (LWGEOM *) geoms->points);
+
+               if (geoms->lines->ngeoms == 1)
+                       coll = (LWCOLLECTION *) lwcollection_add(coll, -1,
+                                       (LWGEOM *) geoms->lines->geoms[0]);
+               else if (geoms->lines->ngeoms)
+                       coll = (LWCOLLECTION *) lwcollection_add(coll, -1,
+                                       (LWGEOM *) geoms->lines);
+
+               if (geoms->polys->ngeoms == 1)
+                       coll = (LWCOLLECTION *) lwcollection_add(coll, -1,
+                                       (LWGEOM *) geoms->polys->geoms[0]);
+               else if (geoms->polys->ngeoms)
+                       coll = (LWCOLLECTION *) lwcollection_add(coll, -1,
+                                       (LWGEOM *) geoms->polys);
+
+               /* We could now free the struct */
+               lwmpoint_release(geoms->points);
+               lwmline_release(geoms->lines);
+               lwmpoly_release(geoms->polys);
+               lwfree(geoms);
+
+               return (LWGEOM *) coll;
+       }
+
+       /* Check if we have to return simple type (i.e not a MULTI) */
+       if (geoms->points->ngeoms == 1)
+               res = lwgeom_clone((LWGEOM *) geoms->points->geoms[0]);
+       if (geoms->lines->ngeoms == 1)
+               res = lwgeom_clone((LWGEOM *) geoms->lines->geoms[0]);
+       if (geoms->polys->ngeoms == 1)
+               res = lwgeom_clone((LWGEOM *) geoms->polys->geoms[0]);
+
+       /* We have to return a single MULTI */
+        if (geoms->points->ngeoms > 1)
+               res = lwgeom_clone((LWGEOM *) geoms->points);
+        if (geoms->lines->ngeoms > 1)
+               res = lwgeom_clone((LWGEOM *) geoms->lines);
+        if (geoms->polys->ngeoms > 1)
+               res = lwgeom_clone((LWGEOM *) geoms->polys);
+
+       /* We could now free the struct */
+       lwmpoint_release(geoms->points);
+       lwmline_release(geoms->lines);
+       lwmpoly_release(geoms->polys);
+       lwfree(geoms);
+
+       /* Empty (and recursive) Geometry case */
+       if (!res) return (LWGEOM *) lwcollection_construct_empty(col->SRID, 0, 0);
+
+       /* Handle SRID and Bbox */
+       res->SRID = col->SRID;
+       if (col->bbox) res->bbox = box2d_clone(col->bbox);
+
+       return res;
+}
+
+
+static LWGEOM_HOMOGENIZE *
+lwcollection_homogenize_subgeom(LWGEOM_HOMOGENIZE *hgeoms, LWGEOM *geom)
+{
+       unsigned int i, type;
+
+       if (!geom) lwerror("lwcollection_homogenize: Sub geometry is Null");
+
+        type = TYPE_GETTYPE(geom->type);
+
+       if (type == POINTTYPE) {
+               hgeoms->points = (LWMPOINT *) lwmpoint_add(hgeoms->points, -1, geom);
+
+       } else if (type == LINETYPE) {
+               hgeoms->lines = (LWMLINE *) lwmline_add(hgeoms->lines, -1, geom);
+
+       } else if (type == POLYGONTYPE) {
+               hgeoms->polys = (LWMPOLY *) lwmpoly_add(hgeoms->polys, -1, geom);
+
+       } else if (type == MULTIPOINTTYPE) {
+               for (i=0 ; i < ((LWMPOINT *) geom)->ngeoms ; i++)
+                       hgeoms->points = (LWMPOINT *) lwmpoint_add(
+                                       hgeoms->points, -1,
+                                       (LWGEOM *) ((LWMPOINT *)geom)->geoms[i]);
+
+       } else if (type == MULTILINETYPE) {
+               for (i=0 ; i < ((LWMLINE *) geom)->ngeoms ; i++)
+                       hgeoms->lines = (LWMLINE *) lwmline_add(
+                                       hgeoms->lines, -1,
+                                       (LWGEOM *) ((LWMLINE *)geom)->geoms[i]);
+
+       } else if (type == MULTIPOLYGONTYPE) {
+               for (i=0 ; i < ((LWMPOLY *) geom)->ngeoms ; i++)
+                       hgeoms->polys = (LWMPOLY *) lwmpoly_add(
+                                       hgeoms->polys, -1,
+                                       (LWGEOM *) ((LWMPOLY *)geom)->geoms[i]);
+
+       } else if (type == COLLECTIONTYPE) {
+               for (i=0; i < ((LWCOLLECTION *) geom)->ngeoms ; i++)
+                       hgeoms = lwcollection_homogenize_subgeom(hgeoms,
+                               ((LWCOLLECTION *) geom)->geoms[i]);
+
+       } else lwerror("lwcollection_homogenize: Unsupported geometry type");
+
+       return hgeoms;
+}
diff --git a/liblwgeom/lwhomogenize.h b/liblwgeom/lwhomogenize.h
new file mode 100644 (file)
index 0000000..5097856
--- /dev/null
@@ -0,0 +1,24 @@
+/**********************************************************************
+ * $Id:$
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ * Copyright 2010 Olivier Courtin <olivier.courtin@oslandia.com>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ **********************************************************************/
+
+#include "liblwgeom.h"
+
+
+typedef struct
+{
+       LWMPOINT *points;
+       LWMLINE *lines;
+       LWMPOLY *polys;
+} LWGEOM_HOMOGENIZE;
+
+static LWGEOM_HOMOGENIZE *
+lwcollection_homogenize_subgeom(LWGEOM_HOMOGENIZE *hgeoms, LWGEOM *geom);