From: Paul Ramsey Date: Wed, 1 Feb 2012 23:00:09 +0000 (+0000) Subject: Support curves in lwgeom_homogenize (#1526) X-Git-Tag: 2.0.0alpha4~96 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e34578aeaf1080bd03d64e153e83167f3c9a0ccc;p=postgis Support curves in lwgeom_homogenize (#1526) git-svn-id: http://svn.osgeo.org/postgis/trunk@9008 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/liblwgeom/cunit/cu_homogenize.c b/liblwgeom/cunit/cu_homogenize.c index db18ee62b..811a06796 100644 --- a/liblwgeom/cunit/cu_homogenize.c +++ b/liblwgeom/cunit/cu_homogenize.c @@ -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}; diff --git a/liblwgeom/liblwgeom.h.in b/liblwgeom/liblwgeom.h.in index ce1fcdfe1..067d384b3 100644 --- a/liblwgeom/liblwgeom.h.in +++ b/liblwgeom/liblwgeom.h.in @@ -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); /****************************************************************** diff --git a/liblwgeom/lwhomogenize.c b/liblwgeom/lwhomogenize.c index 2afb02c41..104f6c053 100644 --- a/liblwgeom/lwhomogenize.c +++ b/liblwgeom/lwhomogenize.c @@ -13,79 +13,37 @@ #include #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 index 5bdb3c860..000000000 --- a/liblwgeom/lwhomogenize.h +++ /dev/null @@ -1,24 +0,0 @@ -/********************************************************************** - * $Id:$ - * - * PostGIS - Spatial Types for PostgreSQL - * http://postgis.refractions.net - * Copyright 2010 Olivier Courtin - * - * 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);