]> granicus.if.org Git - postgis/commitdiff
Support curves in lwgeom_homogenize (#1526)
authorPaul Ramsey <pramsey@cleverelephant.ca>
Wed, 1 Feb 2012 23:00:09 +0000 (23:00 +0000)
committerPaul Ramsey <pramsey@cleverelephant.ca>
Wed, 1 Feb 2012 23:00:09 +0000 (23:00 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@9008 b70326c6-7e19-0410-871a-916f4a2858ee

liblwgeom/cunit/cu_homogenize.c
liblwgeom/liblwgeom.h.in
liblwgeom/lwhomogenize.c
liblwgeom/lwhomogenize.h [deleted file]

index db18ee62b44d002b4b1f16288eec69e9f7cded21..811a067962a9c5c418c484f03638d69b6321abb3 100644 (file)
@@ -27,26 +27,7 @@ static void do_geom_test(char * in, char * out)
        h = lwgeom_homogenize(g);
        tmp = lwgeom_to_ewkt(h);
        if (strcmp(tmp, out))
-               fprintf(stderr, "\nIn:   %s\nOut:  %s\nTheo: %s\n",
-                       in, tmp, out);
-       CU_ASSERT_STRING_EQUAL(tmp, out);
-       lwfree(tmp);
-       lwgeom_free(g);
-       /* See http://trac.osgeo.org/postgis/ticket/1104 */
-       lwgeom_free(h);
-}
-
-
-static void do_coll_test(char * in, char * out)
-{
-       LWGEOM *g, *h;
-       char *tmp;
-
-       g = lwgeom_from_wkt(in, LW_PARSER_CHECK_NONE);
-       h = lwcollection_homogenize((LWCOLLECTION *) g);
-       tmp = lwgeom_to_ewkt(h);
-       if (strcmp(tmp, out))
-               fprintf(stderr, "\nIn:   %s\nOut:  %s\nTheo: %s\n",
+               fprintf(stderr, "\nIn:   %s\nOut:  %s\nExp:  %s\n",
                        in, tmp, out);
        CU_ASSERT_STRING_EQUAL(tmp, out);
        lwfree(tmp);
@@ -58,66 +39,66 @@ static void do_coll_test(char * in, char * out)
 
 static void test_coll_point(void)
 {
-       do_coll_test("GEOMETRYCOLLECTION(POINT(1 2))",
+       do_geom_test("GEOMETRYCOLLECTION(POINT(1 2))",
                     "POINT(1 2)");
 
-       do_coll_test("GEOMETRYCOLLECTION(POINT(1 2),POINT(3 4))",
+       do_geom_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))",
+       do_geom_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))",
+       do_geom_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))",
+       do_geom_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))",
+       do_geom_test("GEOMETRYCOLLECTION(MULTIPOINT(1 2,3 4),MULTIPOINT(5 6,7 8))",
                     "MULTIPOINT(1 2,3 4,5 6,7 8)");
 }
 
 
 static void test_coll_line(void)
 {
-       do_coll_test("GEOMETRYCOLLECTION(LINESTRING(1 2,3 4))",
+       do_geom_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))",
+       do_geom_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))",
+       do_geom_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))",
+       do_geom_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)))",
+       do_geom_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)))",
+       do_geom_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))");
 }
 
 
 static void test_coll_poly(void)
 {
-       do_coll_test("GEOMETRYCOLLECTION(POLYGON((1 2,3 4,5 6,1 2)))",
+       do_geom_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)))",
+       do_geom_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)))",
+       do_geom_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)))",
+       do_geom_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))))",
+       do_geom_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))))",
+       do_geom_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)))");
 }
 
@@ -125,42 +106,51 @@ static void test_coll_poly(void)
 static 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))",
+       do_geom_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)))",
+       do_geom_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))",
+       do_geom_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))",
+       do_geom_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))))",
+       do_geom_test("GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(1 2))))",
                     "POINT(1 2)");
 
-       do_coll_test("GEOMETRYCOLLECTION(POINT(1 2),GEOMETRYCOLLECTION(LINESTRING(3 4,5 6)))",
+       do_geom_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",
+       do_geom_test("GEOMETRYCOLLECTION EMPTY",
                     "GEOMETRYCOLLECTION EMPTY");
 
 
        /* Recursive EMPTY Collection */
-       do_coll_test("GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY)",
+       do_geom_test("GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY)",
                     "GEOMETRYCOLLECTION EMPTY");
 
-       do_coll_test("GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY))",
+       do_geom_test("GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY))",
                     "GEOMETRYCOLLECTION EMPTY");
 }
 
+static void test_coll_curve(void)
+{
+       /* Two different types together must produce a Collection as output */
+       do_geom_test("GEOMETRYCOLLECTION(CIRCULARSTRING(0 0,1 1,2 2))",
+                    "CIRCULARSTRING(0 0,1 1,2 2)");
+
+       do_geom_test("GEOMETRYCOLLECTION(CIRCULARSTRING(0 0,1 1,2 2),CIRCULARSTRING(0 0,1 1,2 2))",
+                    "MULTICURVE(CIRCULARSTRING(0 0,1 1,2 2),CIRCULARSTRING(0 0,1 1,2 2))");
+}
 
 static void test_geom(void)
 {
@@ -256,6 +246,7 @@ CU_TestInfo homogenize_tests[] =
        PG_TEST(test_coll_poly),
        PG_TEST(test_coll_coll),
        PG_TEST(test_geom),
+       PG_TEST(test_coll_curve),
        CU_TEST_INFO_NULL
 };
 CU_SuiteInfo homogenize_suite = {"Homogenize Suite",  NULL,  NULL, homogenize_tests};
index ce1fcdfe14d160682a5c3871dde0fa650f4a4331..067d384b305dbfcadf191fac88c9aafefbdac870 100644 (file)
@@ -74,6 +74,8 @@
 #define TRIANGLETYPE            14
 #define TINTYPE                 15
 
+#define NUMTYPES                16
+
 /**
 * Flags applied in EWKB to indicate Z/M dimensions and
 * presence/absence of SRID and bounding boxes
@@ -906,7 +908,6 @@ 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);
 
 
 /******************************************************************
index 2afb02c4159df5df4aa3aae4327646c16ff86d63..104f6c0536589afdf92d9c8aa43de6cc8e6fb049 100644 (file)
 #include <stdlib.h>
 #include "liblwgeom_internal.h"
 #include "lwgeom_log.h"
-#include "lwhomogenize.h"
 
 
-/*
-** Known limitation: not (yet ?) support SQL/MM Curves.
-*/
+typedef struct {
+       int cnt[NUMTYPES];
+       LWCOLLECTION* buf[NUMTYPES];
+} HomogenizeBuffer;
 
-
-/*
-** 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)
+static void
+init_homogenizebuffer(HomogenizeBuffer *buffer)
 {
-       LWGEOM *hgeom;
-
-       /* EMPTY Geometry */
-       if (lwgeom_is_empty(geom)) return lwgeom_clone(geom);
-
-       /* Already a simple Geometry */
-       switch (geom->type)
+       int i;
+       for ( i = 0; i < NUMTYPES; i++ )
        {
-       case POINTTYPE:
-       case LINETYPE:
-       case POLYGONTYPE:
-               return lwgeom_clone(geom);
+               buffer->cnt[i] = 0;
+               buffer->buf[i] = NULL;
        }
+}
 
-       /* A MULTI */
-       switch (geom->type)
+static void
+free_homogenizebuffer(HomogenizeBuffer *buffer)
+{
+       int i;
+       for ( i = 0; i < NUMTYPES; i++ )
        {
-       case MULTIPOINTTYPE:
-       case MULTILINETYPE:
-       case MULTIPOLYGONTYPE:
-
-               /* A MULTI with a single geometry inside */
-               if (((LWCOLLECTION *) geom)->ngeoms == 1)
+               if ( buffer->buf[i] )
                {
-
-                       hgeom = lwgeom_clone((LWGEOM *)
-                                            ((LWCOLLECTION *)geom)->geoms[0]);
-
-                       hgeom->srid = geom->srid;
-                       if (geom->bbox)
-                               hgeom->bbox = gbox_copy(geom->bbox);
-
-                       return hgeom;
+                       lwcollection_free(buffer->buf[i]);
                }
-
-               /* A 'real' MULTI */
-               return lwgeom_clone(geom);
        }
-
-       if (geom->type == COLLECTIONTYPE)
-               return lwcollection_homogenize((LWCOLLECTION *) geom);
-
-       lwerror("lwgeom_homogenize: Geometry Type not supported (%i)",
-               lwtype_name(geom->type));
-
-       return NULL; /*Never reach */
 }
 
-
 /*
 ** Given a generic collection, return the "simplest" form.
 **
@@ -99,147 +57,200 @@ lwgeom_homogenize(const LWGEOM *geom)
 ** Otherwise, return a generic collection, with the subtypes in minimal
 ** typed collections.
 */
-LWGEOM *
-lwcollection_homogenize(const LWCOLLECTION *col)
+static void
+lwcollection_build_buffer(const LWCOLLECTION *col, HomogenizeBuffer *buffer)
 {
-       uint32_t i, srid;
-       uint8_t 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(COLLECTIONTYPE, col->srid, 0, 0);
-
-       hasz = FLAGS_GET_Z(col->flags);
-       hasm = FLAGS_GET_M(col->flags);
-       srid = col->srid;
-
-       /* LWGEOM_HOMOGENIZE struct setup */
-       geoms = lwalloc(sizeof(LWGEOM_HOMOGENIZE));
-       geoms->points = lwmpoint_construct_empty(SRID_UNKNOWN, hasz, hasm);
-       geoms->lines = lwmline_construct_empty(SRID_UNKNOWN, hasz, hasm);
-       geoms->polys = lwmpoly_construct_empty(SRID_UNKNOWN, hasz, hasm);
-
-       LWDEBUGF(4, "geoms->points %p", geoms->points);
-
-       /* 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))
+       int i;
+       
+       if ( ! col ) return;
+       if ( lwgeom_is_empty(lwcollection_as_lwgeom(col)) ) return;
+       for ( i = 0; i < col->ngeoms; i++ )
        {
-               LWDEBUGF(4,"geoms->points->ngeoms %d  geoms->lines->ngeoms %d  geoms->polys->ngeoms %d", geoms->points->ngeoms, geoms->lines->ngeoms, geoms->polys->ngeoms);
-               coll = lwcollection_construct_empty(COLLECTIONTYPE, srid, hasz, hasm);
-
-               LWDEBUGF(4,"coll->ngeoms %d", coll->ngeoms);
-
-               if (col->bbox) coll->bbox = gbox_copy(col->bbox);
-
-               if (geoms->points->ngeoms == 1)
-                       coll = lwcollection_add_lwgeom(coll, lwgeom_clone((LWGEOM*) geoms->points->geoms[0]));
-               else if (geoms->points->ngeoms)
-                       coll = lwcollection_add_lwgeom(coll, lwgeom_clone((LWGEOM*) geoms->points));
-
-               LWDEBUGF(4,"coll->ngeoms %d", coll->ngeoms);
-
-               if (geoms->lines->ngeoms == 1)
-                       coll = lwcollection_add_lwgeom(coll, lwgeom_clone((LWGEOM*) geoms->lines->geoms[0]));
-               else if (geoms->lines->ngeoms)
-                       coll = lwcollection_add_lwgeom(coll, lwgeom_clone((LWGEOM*) geoms->lines));
-
-               LWDEBUGF(4,"coll->ngeoms %d", coll->ngeoms);
-
-               if (geoms->polys->ngeoms == 1)
-                       coll = lwcollection_add_lwgeom(coll, lwgeom_clone((LWGEOM*) geoms->polys->geoms[0]));
-               else if (geoms->polys->ngeoms)
-                       coll = lwcollection_add_lwgeom(coll, lwgeom_clone((LWGEOM*) geoms->polys));
-
-               LWDEBUGF(4,"coll->ngeoms %d", coll->ngeoms);
-
-               /* We could now free the struct */
-               lwmpoint_free(geoms->points);
-               lwmline_free(geoms->lines);
-               lwmpoly_free(geoms->polys);
-               lwfree(geoms);
-
-               for ( i = 0; i < coll->ngeoms; i++ )
-                       LWDEBUGF(2,"coll->geoms[%d]->type %d", i, coll->geoms[i]->type);
-
-
-               return (LWGEOM *) coll;
+               LWGEOM *geom = col->geoms[i];
+               switch(geom->type)
+               {
+                       case POINTTYPE:
+                       case LINETYPE:
+                       case CIRCSTRINGTYPE:
+                       case COMPOUNDTYPE:
+                       case TRIANGLETYPE:
+                       case CURVEPOLYTYPE:
+                       case POLYGONTYPE:
+                       {
+                               /* Init if necessary */
+                               if ( ! buffer->buf[geom->type] )
+                               {
+                                       LWCOLLECTION *bufcol = lwcollection_construct_empty(COLLECTIONTYPE, col->srid, FLAGS_GET_Z(col->flags), FLAGS_GET_M(col->flags));
+                                       bufcol->type = lwtype_get_collectiontype(geom->type);
+                                       buffer->buf[geom->type] = bufcol;
+                               }
+                               /* Add sub-geom to buffer */
+                               lwcollection_add_lwgeom(buffer->buf[geom->type], lwgeom_clone(geom));
+                               /* Increment count for this singleton type */
+                               buffer->cnt[geom->type] = buffer->cnt[geom->type] + 1;
+                       }
+                       default:
+                       {
+                               lwcollection_build_buffer(lwgeom_as_lwcollection(geom), buffer);
+                       }
+               }
        }
-
-       /* 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_free(geoms->points);
-       lwmline_free(geoms->lines);
-       lwmpoly_free(geoms->polys);
-       lwfree(geoms);
-
-       /* Empty (and recursive) Geometry case */
-       if (!res) return (LWGEOM *) lwcollection_construct_empty(COLLECTIONTYPE, col->srid, 0, 0);
-
-       /* Handle srid and Bbox */
-       res->srid = srid;
-       if (col->bbox) res->bbox = gbox_copy(col->bbox);
-
-       return res;
+       return;
 }
 
-static LWGEOM_HOMOGENIZE*
-lwcollection_homogenize_subgeom(LWGEOM_HOMOGENIZE *hgeoms, LWGEOM *geom)
+static LWGEOM*
+lwcollection_homogenize(const LWCOLLECTION *col)
 {
-       uint32_t i;
-
-       if (!geom) lwerror("lwcollection_homogenize: Sub geometry is Null");
-
-       /* We manage the srid in lwcollection_homogenize */
-       geom->srid = SRID_UNKNOWN;
-
-       if (geom->type == POINTTYPE)
+       int i;
+       int ntypes = 0;
+       int type = 0;
+       LWGEOM *outgeom = NULL;
+       
+       HomogenizeBuffer buffer;
+
+       /* Sort all the parts into a buffer */
+       init_homogenizebuffer(&buffer);
+       lwcollection_build_buffer(col, &buffer);
+       
+       /* Check for homogeneity */
+       for ( i = 0; i < NUMTYPES; i++ )
        {
-               hgeoms->points = lwmpoint_add_lwpoint(hgeoms->points, (LWPOINT*)lwgeom_clone(geom));
+               if ( buffer.cnt[i] > 0 )
+               {
+                       ntypes++;
+                       type = i;
+               }
        }
-       else if (geom->type == LINETYPE)
+       
+       /* No types? Huh. Return empty. */
+       if ( ntypes == 0 )
        {
-               hgeoms->lines = lwmline_add_lwline(hgeoms->lines, (LWLINE*)lwgeom_clone(geom));
+               LWCOLLECTION *outcol;
+               outcol = lwcollection_construct_empty(COLLECTIONTYPE, col->srid, FLAGS_GET_Z(col->flags), FLAGS_GET_M(col->flags));
+               outgeom = lwcollection_as_lwgeom(outcol);
        }
-       else if (geom->type == POLYGONTYPE)
+       /* One type, return homogeneous collection */
+       else if ( ntypes == 1 )
        {
-               hgeoms->polys = lwmpoly_add_lwpoly(hgeoms->polys, (LWPOLY*)lwgeom_clone(geom));
+               LWCOLLECTION *outcol;
+               outcol = buffer.buf[type];
+               if ( outcol->ngeoms == 1 )
+               {
+                       outgeom = outcol->geoms[0];
+                       lwfree(outcol);
+               }
+               else
+               {
+                       outgeom = lwcollection_as_lwgeom(outcol);
+               }
        }
-       else if ( lwtype_is_collection(geom->type) )
+       /* Bah, more than out type, return anonymous collection */
+       else if ( ntypes > 1 )
        {
-               LWCOLLECTION *obj = (LWCOLLECTION*)geom;
-               for (i=0; i < obj->ngeoms ; i++)
-                       hgeoms = lwcollection_homogenize_subgeom(hgeoms, obj->geoms[i]);
+               int j;
+               LWCOLLECTION *outcol;
+               outcol = lwcollection_construct_empty(COLLECTIONTYPE, col->srid, FLAGS_GET_Z(col->flags), FLAGS_GET_M(col->flags));
+               for ( j = 0; j < NUMTYPES; j++ )
+               {
+                       if ( buffer.buf[j] )
+                       {
+                               LWCOLLECTION *bcol = buffer.buf[j];
+                               if ( bcol->ngeoms == 1 )
+                               {
+                                       lwcollection_add_lwgeom(outcol, bcol->geoms[0]);
+                                       lwfree(bcol);
+                               }
+                               else 
+                               {
+                                       lwcollection_add_lwgeom(outcol, lwcollection_as_lwgeom(bcol));
+                               }
+                       }
+               }
+               outgeom = lwcollection_as_lwgeom(outcol);
        }
-       else
+       
+       return outgeom;
+}
+
+
+
+
+
+/*
+** 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;
+
+       /* EMPTY Geometry */
+       if (lwgeom_is_empty(geom)) 
        {
-               lwerror("lwcollection_homogenize: Unsupported geometry type");
+               if( lwgeom_is_collection(geom) )
+               {
+                       return lwcollection_as_lwgeom(lwcollection_construct_empty(geom->type, geom->srid, lwgeom_has_z(geom), lwgeom_has_m(geom)));
+               }
+               
+               return lwgeom_clone(geom);
        }
 
-       return hgeoms;
+       switch (geom->type)
+       {
+
+               /* Return simple geometries untouched */
+               case POINTTYPE:
+               case LINETYPE:
+               case CIRCSTRINGTYPE:
+               case COMPOUNDTYPE:
+               case TRIANGLETYPE:
+               case CURVEPOLYTYPE:
+               case POLYGONTYPE:
+                       return lwgeom_clone(geom);
+
+               /* Process homogeneous geometries lightly */
+               case MULTIPOINTTYPE:
+               case MULTILINETYPE:
+               case MULTIPOLYGONTYPE:
+               case MULTICURVETYPE:
+               case MULTISURFACETYPE:
+               case POLYHEDRALSURFACETYPE:
+               case TINTYPE:
+               {
+                       LWCOLLECTION *col = (LWCOLLECTION*)geom;
+
+                       /* Strip single-entry multi-geometries down to singletons */
+                       if ( col->ngeoms == 1 )
+                       {
+                               hgeom = lwgeom_clone((LWGEOM*)(col->geoms[0]));
+                               hgeom->srid = geom->srid;
+                               if (geom->bbox)
+                                       hgeom->bbox = gbox_copy(geom->bbox);
+                               return hgeom;
+                       }
+
+                       /* Return proper multigeometry untouched */
+                       return lwgeom_clone(geom);
+               }
+       
+               /* Work on anonymous collections separately */
+               case COLLECTIONTYPE: 
+                       return lwcollection_homogenize((LWCOLLECTION *) geom);
+       }
+
+       /* Unknown type */
+       lwerror("lwgeom_homogenize: Geometry Type not supported (%i)",
+               lwtype_name(geom->type));
+
+       return NULL; /* Never get here! */
 }
diff --git a/liblwgeom/lwhomogenize.h b/liblwgeom/lwhomogenize.h
deleted file mode 100644 (file)
index 5bdb3c8..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/**********************************************************************
- * $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_internal.h"
-
-
-typedef struct
-{
-       LWMPOINT *points;
-       LWMLINE *lines;
-       LWMPOLY *polys;
-} LWGEOM_HOMOGENIZE;
-
-static LWGEOM_HOMOGENIZE *
-lwcollection_homogenize_subgeom(LWGEOM_HOMOGENIZE *hgeoms, LWGEOM *geom);