From 952147e245b51a34463e31fbef4e14ed9e4f8058 Mon Sep 17 00:00:00 2001 From: Paul Ramsey Date: Wed, 24 Jun 2015 22:40:57 +0000 Subject: [PATCH] #3177, gserialized_is_empty cannot handle nested empty cases git-svn-id: http://svn.osgeo.org/postgis/trunk@13700 b70326c6-7e19-0410-871a-916f4a2858ee --- liblwgeom/cunit/cu_libgeom.c | 52 +++++++++++++++++++++++++++++++++--- liblwgeom/g_serialized.c | 45 ++++++++++++++++++++++--------- 2 files changed, 80 insertions(+), 17 deletions(-) diff --git a/liblwgeom/cunit/cu_libgeom.c b/liblwgeom/cunit/cu_libgeom.c index 1d8e1fa5e..99119f7f7 100644 --- a/liblwgeom/cunit/cu_libgeom.c +++ b/liblwgeom/cunit/cu_libgeom.c @@ -306,6 +306,49 @@ static void test_lwgeom_from_gserialized(void) } + +static void test_gserialized_is_empty(void) +{ + int i = 0; + struct gserialized_empty_cases { + const char* wkt; + int isempty; + }; + + struct gserialized_empty_cases cases[] = { + { "POINT EMPTY", 1 }, + { "POINT(1 1)", 0 }, + { "LINESTRING EMPTY", 1 }, + { "MULTILINESTRING EMPTY", 1 }, + { "MULTILINESTRING(EMPTY)", 1 }, + { "MULTILINESTRING(EMPTY,EMPTY)", 1 }, + { "MULTILINESTRING(EMPTY,(0 0,1 1))", 0 }, + { "MULTILINESTRING((0 0,1 1),EMPTY)", 0 }, + { "MULTILINESTRING(EMPTY,(0 0,1 1),EMPTY)", 0 }, + { "MULTILINESTRING(EMPTY,EMPTY,EMPTY)", 1 }, + { "GEOMETRYCOLLECTION(POINT EMPTY,MULTILINESTRING(EMPTY,EMPTY,EMPTY))", 1 }, + { "GEOMETRYCOLLECTION(POINT EMPTY,MULTILINESTRING(EMPTY),POINT(1 1))", 0 }, + { "GEOMETRYCOLLECTION(POINT EMPTY,MULTILINESTRING(EMPTY, (0 0)),POINT EMPTY)", 0 }, + { "GEOMETRYCOLLECTION(POLYGON EMPTY,POINT EMPTY,MULTILINESTRING(EMPTY,EMPTY),POINT EMPTY)", 1 }, + { "GEOMETRYCOLLECTION(POLYGON EMPTY,GEOMETRYCOLLECTION(POINT EMPTY),MULTILINESTRING(EMPTY,EMPTY),POINT EMPTY)", 1 }, + { NULL, 0 } + }; + + while( cases[i].wkt ) + { + // i = 11; + LWGEOM *lw = lwgeom_from_wkt(cases[i].wkt, LW_PARSER_CHECK_NONE); + GSERIALIZED *g = gserialized_from_lwgeom(lw, 0, 0); + int ie = gserialized_is_empty(g); + // printf("%s: we say %d, they say %d\n", cases[i].wkt, cases[i].isempty, ie); + CU_ASSERT_EQUAL(ie, cases[i].isempty); + lwgeom_free(lw); + lwfree(g); + i++; + } +} + + static void test_geometry_type_from_string(void) { int rv; @@ -597,8 +640,8 @@ static void test_lwgeom_flip_coordinates(void) /* - * Srid - */ + * Srid + */ do_lwgeom_flip_coordinates( "SRID=4326;POINT(1 2)", @@ -974,9 +1017,9 @@ static void test_lwgeom_scale(void) geom = lwgeom_from_wkt("SRID=4326;GEOMETRYCOLLECTION(POINT(0 1 2 3),POLYGON((-1 -1 0 1,-1 2.5 0 1,2 2 0 1,2 -1 0 1,-1 -1 0 1),(0 0 1 2,0 1 1 2,1 1 1 2,1 0 2 3,0 0 1 2)),LINESTRING(0 0 0 0, 1 2 3 4))", LW_PARSER_CHECK_NONE); factor.x = 2; factor.y = 3; factor.z = 4; factor.m = 5; - lwgeom_scale(geom, &factor); + lwgeom_scale(geom, &factor); out_ewkt = lwgeom_to_ewkt(geom); - ASSERT_STRING_EQUAL(out_ewkt, "SRID=4326;GEOMETRYCOLLECTION(POINT(0 3 8 15),POLYGON((-2 -3 0 5,-2 7.5 0 5,4 6 0 5,4 -3 0 5,-2 -3 0 5),(0 0 4 10,0 3 4 10,2 3 4 10,2 0 8 15,0 0 4 10)),LINESTRING(0 0 0 0,2 6 12 20))"); + ASSERT_STRING_EQUAL(out_ewkt, "SRID=4326;GEOMETRYCOLLECTION(POINT(0 3 8 15),POLYGON((-2 -3 0 5,-2 7.5 0 5,4 6 0 5,4 -3 0 5,-2 -3 0 5),(0 0 4 10,0 3 4 10,2 3 4 10,2 0 8 15,0 0 4 10)),LINESTRING(0 0 0 0,2 6 12 20))"); lwgeom_free(geom); lwfree(out_ewkt); @@ -1024,4 +1067,5 @@ void libgeom_suite_setup(void) PG_ADD_TEST(suite, test_lwline_from_lwmpoint); PG_ADD_TEST(suite, test_lwgeom_as_curve); PG_ADD_TEST(suite, test_lwgeom_scale); + PG_ADD_TEST(suite, test_gserialized_is_empty); } diff --git a/liblwgeom/g_serialized.c b/liblwgeom/g_serialized.c index 01bda61c4..ced4177b2 100644 --- a/liblwgeom/g_serialized.c +++ b/liblwgeom/g_serialized.c @@ -108,27 +108,46 @@ GSERIALIZED* gserialized_copy(const GSERIALIZED *g) return g_out; } +static size_t gserialized_is_empty_recurse(const uint8_t *p, int *isempty); +static size_t gserialized_is_empty_recurse(const uint8_t *p, int *isempty) +{ + int i; + int32_t type, num; + + memcpy(&type, p, 4); + memcpy(&num, p+4, 4); + + if ( lwtype_is_collection(type) ) + { + size_t lz = 8; + for ( i = 0; i < num; i++ ) + { + lz += gserialized_is_empty_recurse(p+lz, isempty); + if ( ! *isempty ) + return lz; + } + *isempty = LW_TRUE; + return lz; + } + else + { + *isempty = (num == 0 ? LW_TRUE : LW_FALSE); + return 8; + } +} + int gserialized_is_empty(const GSERIALIZED *g) { uint8_t *p = (uint8_t*)g; - int i; + int isempty = 0; assert(g); p += 8; /* Skip varhdr and srid/flags */ if( FLAGS_GET_BBOX(g->flags) ) p += gbox_serialized_size(g->flags); /* Skip the box */ - p += 4; /* Skip type number */ - - /* For point/line/circstring this is npoints */ - /* For polygons this is nrings */ - /* For collections this is ngeoms */ - memcpy(&i, p, sizeof(int)); - - /* If it is non-zero, it's not empty */ - if ( i > 0 ) - return LW_FALSE; - else - return LW_TRUE; + + gserialized_is_empty_recurse(p, &isempty); + return isempty; } char* gserialized_to_string(const GSERIALIZED *g) -- 2.50.0