From: Paul Ramsey Date: Mon, 16 Mar 2015 19:59:20 +0000 (+0000) Subject: Add a regression test for ST_Subdivide X-Git-Tag: 2.2.0rc1~592 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=be9d28adadc7fefdaffb25fc4e3e09409a4932f7;p=postgis Add a regression test for ST_Subdivide git-svn-id: http://svn.osgeo.org/postgis/trunk@13342 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/liblwgeom/g_box.c b/liblwgeom/g_box.c index 43ae3fcc8..e53579ee1 100644 --- a/liblwgeom/g_box.c +++ b/liblwgeom/g_box.c @@ -46,6 +46,16 @@ GBOX* gbox_clone(const GBOX *gbox) return g; } +int gbox_has_z(const GBOX *gbox) +{ + return FLAGS_GET_Z(gbox->flags); +} + +int gbox_has_m(const GBOX *gbox) +{ + return FLAGS_GET_M(gbox->flags); +} + /* TODO to be removed */ BOX3D* box3d_from_gbox(const GBOX *gbox) { diff --git a/liblwgeom/liblwgeom.h.in b/liblwgeom/liblwgeom.h.in index 44fe32b47..ec9f3814d 100644 --- a/liblwgeom/liblwgeom.h.in +++ b/liblwgeom/liblwgeom.h.in @@ -1042,6 +1042,10 @@ extern LWCOMPOUND* lwcompound_construct_from_lwline(const LWLINE *lwpoly); */ extern LWCURVEPOLY* lwcurvepoly_construct_from_lwpoly(LWPOLY *lwpoly); +/** +* Construct a new 2D polygon using an envelope as input +*/ +extern LWPOLY* lwpoly_construct_from_gbox(int srid, const GBOX *gbox); /****************************************************************** * LWGEOM functions diff --git a/liblwgeom/liblwgeom_internal.h b/liblwgeom/liblwgeom_internal.h index fff65278c..a5443e411 100644 --- a/liblwgeom/liblwgeom_internal.h +++ b/liblwgeom/liblwgeom_internal.h @@ -440,3 +440,5 @@ int ptarray_npoints_in_rect(const POINTARRAY *pa, const GBOX *gbox); int gbox_contains_point2d(const GBOX *g, const POINT2D *p); int lwgeom_npoints_in_rect(const LWGEOM *geom, const GBOX *gbox); int lwpoly_contains_point(const LWPOLY *poly, const POINT2D *pt); +int gbox_has_z(const GBOX *gbox); +int gbox_has_m(const GBOX *gbox); diff --git a/liblwgeom/lwgeom.c b/liblwgeom/lwgeom.c index 5a9032525..781bb29e0 100644 --- a/liblwgeom/lwgeom.c +++ b/liblwgeom/lwgeom.c @@ -372,14 +372,14 @@ void lwgeom_release(LWGEOM *lwgeom) { if ( ! lwgeom ) - lwerror("lwgeom_release: someone called on 0x0"); + lwerror("%s: someone called on 0x0", __func__); LWDEBUGF(3, "releasing type %s", lwtype_name(lwgeom->type)); /* Drop bounding box (always a copy) */ if ( lwgeom->bbox ) { - LWDEBUGF(3, "lwgeom_release: releasing bbox. %p", lwgeom->bbox); + LWDEBUGF(3, "%s: releasing bbox. %p", __func__, lwgeom->bbox); lwfree(lwgeom->bbox); } lwfree(lwgeom); @@ -421,7 +421,7 @@ lwgeom_clone(const LWGEOM *lwgeom) case COLLECTIONTYPE: return (LWGEOM *)lwcollection_clone((LWCOLLECTION *)lwgeom); default: - lwerror("lwgeom_clone: Unknown geometry type: %s", lwtype_name(lwgeom->type)); + lwerror("%s: Unknown geometry type: %s", __func__, lwtype_name(lwgeom->type)); return NULL; } } @@ -456,7 +456,7 @@ lwgeom_clone_deep(const LWGEOM *lwgeom) case COLLECTIONTYPE: return (LWGEOM *)lwcollection_clone_deep((LWCOLLECTION *)lwgeom); default: - lwerror("lwgeom_clone_deep: Unknown geometry type: %s", lwtype_name(lwgeom->type)); + lwerror("%s: Unknown geometry type: %s", __func__, lwtype_name(lwgeom->type)); return NULL; } } @@ -555,7 +555,7 @@ lwgeom_same(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2) return lwcollection_same((LWCOLLECTION *)lwgeom1, (LWCOLLECTION *)lwgeom2); default: - lwerror("lwgeom_same: unsupported geometry type: %s", + lwerror("%s: unsupported geometry type: %s", __func__, lwtype_name(lwgeom1->type)); return LW_FALSE; } @@ -735,7 +735,7 @@ lwgeom_force_dims(const LWGEOM *geom, int hasz, int hasm) case COLLECTIONTYPE: return lwcollection_as_lwgeom(lwcollection_force_dims((LWCOLLECTION*)geom, hasz, hasm)); default: - lwerror("lwgeom_force_2d: unsupported geom type: %s", lwtype_name(geom->type)); + lwerror("%s: unsupported geom type: %s", __func__, lwtype_name(geom->type)); return NULL; } } @@ -893,7 +893,7 @@ lwgeom_set_geodetic(LWGEOM *geom, int value) lwgeom_set_geodetic(col->geoms[i], value); break; default: - lwerror("lwgeom_set_geodetic: unsupported geom type: %s", lwtype_name(geom->type)); + lwerror("%s: unsupported geom type: %s", __func__, lwtype_name(geom->type)); return; } } @@ -938,8 +938,8 @@ lwgeom_longitude_shift(LWGEOM *lwgeom) lwgeom_longitude_shift(coll->geoms[i]); return; default: - lwerror("lwgeom_longitude_shift: unsupported geom type: %s", - lwtype_name(lwgeom->type)); + lwerror("%s: unsupported geom type: %s", + __func__, lwtype_name(lwgeom->type)); } } @@ -1095,7 +1095,7 @@ void lwgeom_free(LWGEOM *lwgeom) lwcollection_free((LWCOLLECTION *)lwgeom); break; default: - lwerror("lwgeom_free called with unknown type (%d) %s", lwgeom->type, lwtype_name(lwgeom->type)); + lwerror("%s called with unknown type (%d) %s", __func__, lwgeom->type, lwtype_name(lwgeom->type)); } return; } @@ -1144,8 +1144,8 @@ int lwgeom_count_vertices(const LWGEOM *geom) /* Null? Zero. */ if( ! geom ) return 0; - LWDEBUGF(4, "lwgeom_count_vertices got type %s", - lwtype_name(geom->type)); + LWDEBUGF(4, "%s got type %s", + __func__, lwtype_name(geom->type)); /* Empty? Zero. */ if( lwgeom_is_empty(geom) ) return 0; @@ -1176,8 +1176,8 @@ int lwgeom_count_vertices(const LWGEOM *geom) result = lwcollection_count_vertices((LWCOLLECTION *)geom); break; default: - lwerror("lwgeom_count_vertices: unsupported input geometry type: %s", - lwtype_name(geom->type)); + lwerror("%s: unsupported input geometry type: %s", + __func__, lwtype_name(geom->type)); break; } LWDEBUGF(3, "counted %d vertices", result); @@ -1195,8 +1195,8 @@ int lwgeom_dimension(const LWGEOM *geom) /* Null? Zero. */ if( ! geom ) return -1; - LWDEBUGF(4, "lwgeom_dimension got type %s", - lwtype_name(geom->type)); + LWDEBUGF(4, "%s got type %s", + __func__, lwtype_name(geom->type)); /* Empty? Zero. */ /* if( lwgeom_is_empty(geom) ) return 0; */ @@ -1237,8 +1237,8 @@ int lwgeom_dimension(const LWGEOM *geom) return maxdim; } default: - lwerror("lwgeom_dimension: unsupported input geometry type: %s", - lwtype_name(geom->type)); + lwerror("%s: unsupported input geometry type: %s", + __func__, lwtype_name(geom->type)); } return -1; } @@ -1287,7 +1287,7 @@ int lwgeom_count_rings(const LWGEOM *geom) break; } default: - lwerror("lwgeom_count_rings: unsupported input geometry type: %s", lwtype_name(geom->type)); + lwerror("%s: unsupported input geometry type: %s", __func__, lwtype_name(geom->type)); break; } LWDEBUGF(3, "counted %d rings", result); @@ -1297,8 +1297,8 @@ int lwgeom_count_rings(const LWGEOM *geom) int lwgeom_is_empty(const LWGEOM *geom) { int result = LW_FALSE; - LWDEBUGF(4, "lwgeom_is_empty: got type %s", - lwtype_name(geom->type)); + LWDEBUGF(4, "%s: got type %s", + __func__, lwtype_name(geom->type)); switch (geom->type) { @@ -1330,8 +1330,8 @@ int lwgeom_is_empty(const LWGEOM *geom) return lwcollection_is_empty((LWCOLLECTION *)geom); break; default: - lwerror("lwgeom_is_empty: unsupported input geometry type: %s", - lwtype_name(geom->type)); + lwerror("%s: unsupported input geometry type: %s", + __func__, lwtype_name(geom->type)); break; } return result; @@ -1363,8 +1363,8 @@ extern int lwgeom_dimensionality(LWGEOM *geom) { int dim; - LWDEBUGF(3, "lwgeom_dimensionality got type %s", - lwtype_name(geom->type)); + LWDEBUGF(3, "%s got type %s", + __func__, lwtype_name(geom->type)); switch (geom->type) { @@ -1397,8 +1397,8 @@ extern int lwgeom_dimensionality(LWGEOM *geom) return lwcollection_dimensionality((LWCOLLECTION *)geom); break; default: - lwerror("lwgeom_dimensionality: unsupported input geometry type: %s", - lwtype_name(geom->type)); + lwerror("%s: unsupported input geometry type: %s", + __func__, lwtype_name(geom->type)); break; } return 0; @@ -1442,8 +1442,8 @@ extern LWGEOM* lwgeom_remove_repeated_points(LWGEOM *in) return in; default: - lwnotice("lwgeom_remove_repeated_points: unsupported geometry type: %s", - lwtype_name(in->type)); + lwnotice("%s: unsupported geometry type: %s", + __func__, lwtype_name(in->type)); return in; break; } @@ -1518,8 +1518,8 @@ void lwgeom_swap_ordinates(LWGEOM *in, LWORD o1, LWORD o2) break; default: - lwerror("lwgeom_swap_ordinates: unsupported geometry type: %s", - lwtype_name(in->type)); + lwerror("%s: unsupported geometry type: %s", + __func__, lwtype_name(in->type)); return; } @@ -1565,7 +1565,8 @@ LWGEOM* lwgeom_simplify(const LWGEOM *igeom, double dist) case COLLECTIONTYPE: return (LWGEOM*)lwcollection_simplify((LWCOLLECTION *)igeom, dist); default: - lwerror("lwgeom_simplify: unsupported geometry type: %s",lwtype_name(igeom->type)); + lwerror("%s: unsupported geometry type: %s", + __func__, lwtype_name(igeom->type)); } return NULL; } @@ -1725,7 +1726,8 @@ lwgeom_affine(LWGEOM *geom, const AFFINE *affine) } else { - lwerror("lwgeom_affine: unable to handle type '%s'", lwtype_name(type)); + lwerror("%s: unsupported geometry type: %s", + __func__, lwtype_name(type)); } } } @@ -1756,8 +1758,8 @@ lwgeom_construct_empty(uint8_t type, int srid, char hasz, char hasm) case COLLECTIONTYPE: return lwcollection_as_lwgeom(lwcollection_construct_empty(type, srid, hasz, hasm)); default: - lwerror("lwgeom_construct_empty: unsupported geometry type: %s", - lwtype_name(type)); + lwerror("%s: unsupported geometry type: %s", + __func__, lwtype_name(type)); return NULL; } } @@ -1786,8 +1788,8 @@ lwgeom_startpoint(const LWGEOM* lwgeom, POINT4D* pt) case COLLECTIONTYPE: return lwcollection_startpoint((LWCOLLECTION*)lwgeom, pt); default: - lwerror("int: unsupported geometry type: %s", - lwtype_name(lwgeom->type)); + lwerror("%s: unsupported geometry type: %s", + __func__, lwtype_name(lwgeom->type)); return LW_FAILURE; } } @@ -1813,8 +1815,8 @@ lwgeom_grid(const LWGEOM *lwgeom, const gridspec *grid) case CIRCSTRINGTYPE: return (LWGEOM *)lwcircstring_grid((LWCIRCSTRING *)lwgeom, grid); default: - lwerror("lwgeom_grid: Unsupported geometry type: %s", - lwtype_name(lwgeom->type)); + lwerror("%s: Unsupported geometry type: %s", + __func__, lwtype_name(lwgeom->type)); return NULL; } } @@ -1827,7 +1829,10 @@ lwgeom_npoints_in_rect(const LWGEOM *geom, const GBOX *gbox) if ( ! gbox_overlaps_2d(geombox, gbox) ) return 0; - + + if ( gbox_contains_2d(gbox, geombox) ) + return lwgeom_count_vertices(geom); + switch ( geom->type ) { case POINTTYPE: @@ -1864,7 +1869,7 @@ lwgeom_npoints_in_rect(const LWGEOM *geom, const GBOX *gbox) } default: { - lwerror("lwgeom_npoints_in_rect: Unsupported geometry type: %s", + lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(geom->type)); return 0; } @@ -1942,24 +1947,9 @@ lwgeom_subdivide_recursive(const LWGEOM *geom, int maxvertices, LWCOLLECTION *co pt.y = clip->ymin; if ( lwpoly_contains_point((LWPOLY*)geom, &pt) ) { - /* TODO: Probably just making the clipping box into a polygon is a more */ - /* efficient way to do this? */ - LWGEOM *clipped = lwgeom_clip_by_rect(geom, clip->xmin, clip->ymin, clip->xmax, clip->ymax); - /* Hm, clipping left nothing behind, skip it */ - if ( lwgeom_is_empty(clipped) ) - { - return 0; - } - /* Add the clipped part */ - else - { - lwcollection_add_lwgeom(col, clipped); - return 5; - } - } - else - { - return 0; + LWPOLY *clip_poly = lwpoly_construct_from_gbox(geom->srid, clip); + lwcollection_add_lwgeom(col, lwpoly_as_lwgeom(clip_poly)); + return 5; } } else @@ -2021,6 +2011,11 @@ lwgeom_subdivide(const LWGEOM *geom, int maxvertices) { int n = 0; LWCOLLECTION *col; + + /* Guard against terribleness */ + if ( maxvertices < 10 ) + lwerror("%s: must use a vertex count of at least 10", __func__); + col = lwcollection_construct_empty(COLLECTIONTYPE, geom->srid, lwgeom_has_z(geom), lwgeom_has_m(geom)); n = lwgeom_subdivide_recursive(geom, maxvertices, col, NULL); return col; diff --git a/liblwgeom/lwpoly.c b/liblwgeom/lwpoly.c index de219908c..1b1339d8e 100644 --- a/liblwgeom/lwpoly.c +++ b/liblwgeom/lwpoly.c @@ -76,6 +76,53 @@ lwpoly_construct_empty(int srid, char hasz, char hasm) return result; } +LWPOLY* +lwpoly_construct_from_gbox(int srid, const GBOX *gbox) +{ + POINTARRAY *pa; + POINT4D p; + LWPOLY *result = lwalloc(sizeof(LWPOLY)); + result->type = POLYGONTYPE; + result->flags = gflags(0, 0, 0); + result->srid = srid; + result->nrings = 1; + result->maxrings = 1; /* Allocate room for ring, just in case. */ + result->rings = lwalloc(result->maxrings * sizeof(POINTARRAY*)); + result->bbox = gbox_clone(gbox); + + /* Add a ring */ + pa = ptarray_construct_empty(0, 0, 5); + result->rings[0] = pa; + + /* 1st point */ + p.x = gbox->xmin; + p.y = gbox->ymin; + ptarray_append_point(pa, &p, LW_TRUE); + + /* 2nd point */ + p.x = gbox->xmin; + p.y = gbox->ymax; + ptarray_append_point(pa, &p, LW_TRUE); + + /* 3rd point */ + p.x = gbox->xmax; + p.y = gbox->ymax; + ptarray_append_point(pa, &p, LW_TRUE); + + /* 4th point */ + p.x = gbox->xmax; + p.y = gbox->ymin; + ptarray_append_point(pa, &p, LW_TRUE); + + /* 5th point */ + p.x = gbox->xmin; + p.y = gbox->ymin; + ptarray_append_point(pa, &p, LW_TRUE); + + return result; +} + + void lwpoly_free(LWPOLY *poly) { int t; diff --git a/postgis/lwgeom_functions_basic.c b/postgis/lwgeom_functions_basic.c index 2c137c0d2..a35dd1d3d 100644 --- a/postgis/lwgeom_functions_basic.c +++ b/postgis/lwgeom_functions_basic.c @@ -2099,52 +2099,21 @@ Datum ST_MakeEnvelope(PG_FUNCTION_ARGS) { LWPOLY *poly; GSERIALIZED *result; - POINTARRAY **pa; - POINT4D p; - double x1, y1, x2, y2; + GBOX gbox; int srid = SRID_UNKNOWN; POSTGIS_DEBUG(2, "ST_MakeEnvelope called"); - x1 = PG_GETARG_FLOAT8(0); - y1 = PG_GETARG_FLOAT8(1); - x2 = PG_GETARG_FLOAT8(2); - y2 = PG_GETARG_FLOAT8(3); + gbox_init(&gbox); + gbox.xmin = PG_GETARG_FLOAT8(0); + gbox.ymin = PG_GETARG_FLOAT8(1); + gbox.xmax = PG_GETARG_FLOAT8(2); + gbox.ymax = PG_GETARG_FLOAT8(3); if ( PG_NARGS() > 4 ) { srid = PG_GETARG_INT32(4); } - pa = (POINTARRAY**)palloc(sizeof(POINTARRAY**)); - pa[0] = ptarray_construct_empty(0, 0, 5); - - /* 1st point */ - p.x = x1; - p.y = y1; - ptarray_append_point(pa[0], &p, LW_TRUE); - - /* 2nd point */ - p.x = x1; - p.y = y2; - ptarray_append_point(pa[0], &p, LW_TRUE); - - /* 3rd point */ - p.x = x2; - p.y = y2; - ptarray_append_point(pa[0], &p, LW_TRUE); - - /* 4th point */ - p.x = x2; - p.y = y1; - ptarray_append_point(pa[0], &p, LW_TRUE); - - /* 5th point */ - p.x = x1; - p.y = y1; - ptarray_append_point(pa[0], &p, LW_TRUE); - - poly = lwpoly_construct(srid, NULL, 1, pa); - lwgeom_add_bbox(lwpoly_as_lwgeom(poly)); - + poly = lwpoly_construct_from_gbox(srid, &gbox); result = geometry_serialize(lwpoly_as_lwgeom(poly)); lwpoly_free(poly); diff --git a/regress/clipbybox2d.sql b/regress/clipbybox2d.sql index b82207d7d..b2757ba3c 100644 --- a/regress/clipbybox2d.sql +++ b/regress/clipbybox2d.sql @@ -23,3 +23,14 @@ CREATE TEMPORARY TABLE t AS SELECT SELECT ST_AsEWKT(ST_ClipByBox2d(g, ST_MakeEnvelope(-20,-20,-10,-10))) FROM t; -- See http://trac.osgeo.org/postgis/ticket/2954 SELECT ST_AsEWKT(ST_ClipByBox2D('SRID=4326;POINT(0 0)','BOX3D(-1 -1,1 1)'::box3d::box2d)); + + +-- ST_Subdivide requires ST_ClibByBox2D +SELECT Round(Sum(ST_Area(geom))), Count(*) + FROM ST_Subdivide(ST_Segmentize('POLYGON((0 0, 0 100, 100 100, 100 0, 0 0))'::geometry,1),100) AS geom; + +SELECT Round(Sum(ST_Area(geom))), Count(*) + FROM ST_Subdivide(ST_Segmentize('POLYGON((0 0, 0 100, 100 100, 100 0, 0 0))'::geometry,1),24) AS geom; + +SELECT Round(Sum(ST_Area(geom))), Count(*) + FROM ST_Subdivide(ST_Segmentize('POLYGON((0 0, 0 100, 100 100, 100 0, 0 0))'::geometry,1),12) AS geom; diff --git a/regress/clipbybox2d_expected b/regress/clipbybox2d_expected index e58bf780c..13571101f 100644 --- a/regress/clipbybox2d_expected +++ b/regress/clipbybox2d_expected @@ -7,3 +7,6 @@ POLYGON((2.5 2,5 4,5 5,5 4,7.5 2,2.5 2)) POLYGON((2 2,2 5,5 5,5 2,2 2)) SRID=3857;POLYGON EMPTY SRID=4326;POINT(0 0) +10000|13 +10000|64 +10000|148