From 45b0803360cf35b364e7f32d00c114a54872d944 Mon Sep 17 00:00:00 2001 From: Daniel Baston Date: Tue, 15 Mar 2016 01:08:59 +0000 Subject: [PATCH] #3466, Casting from box3d to geometry drops Z dimension (Julien Rouhaud) git-svn-id: http://svn.osgeo.org/postgis/trunk@14786 b70326c6-7e19-0410-871a-916f4a2858ee --- NEWS | 2 + doc/introduction.xml | 1 + liblwgeom/liblwgeom.h.in | 1 + liblwgeom/lwpoly.c | 18 ++++ postgis/lwgeom_box.c | 27 ++---- postgis/lwgeom_box3d.c | 142 ++++++++++++++++++++++++++------ regress/regress.sql | 8 +- regress/regress_expected | 7 +- regress/sfcgal/regress.sql | 7 +- regress/sfcgal/regress_expected | 7 +- 10 files changed, 171 insertions(+), 49 deletions(-) diff --git a/NEWS b/NEWS index ed9283ed9..192d148fe 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,8 @@ PostGIS 2.3.0 2015/XX/XX * Important / Breaking Changes * + - #3466, Casting from box3d to geometry now returns a 3D + geometry (Julien Rouhaud) * Deprecated signatures * * New Features * diff --git a/doc/introduction.xml b/doc/introduction.xml index efc4769ac..35194c0c8 100644 --- a/doc/introduction.xml +++ b/doc/introduction.xml @@ -208,6 +208,7 @@ Ingvild Nystuen, Jason Smith, Jeff Adams, Jose Carlos Martinez Llari, +Julien Rouhaud, Kashif Rasul, Klaus Foerster, Kris Jurka, diff --git a/liblwgeom/liblwgeom.h.in b/liblwgeom/liblwgeom.h.in index 1066ec658..182601cfa 100644 --- a/liblwgeom/liblwgeom.h.in +++ b/liblwgeom/liblwgeom.h.in @@ -1337,6 +1337,7 @@ extern LWLINE *lwline_addpoint(LWLINE *line, LWPOINT *point, uint32_t where); extern LWLINE *lwline_removepoint(LWLINE *line, uint32_t which); extern void lwline_setPoint4d(LWLINE *line, uint32_t which, POINT4D *newpoint); extern LWPOLY *lwpoly_from_lwlines(const LWLINE *shell, uint32_t nholes, const LWLINE **holes); +extern LWPOLY* lwpoly_construct_rectangle(char hasz, char hasm, POINT4D *p1, POINT4D *p2, POINT4D *p3, POINT4D *p4); extern LWTRIANGLE *lwtriangle_from_lwline(const LWLINE *shell); extern LWMPOINT *lwmpoint_from_lwgeom(const LWGEOM *g); /* Extract the coordinates of an LWGEOM into an LWMPOINT */ diff --git a/liblwgeom/lwpoly.c b/liblwgeom/lwpoly.c index ffe3e67a8..684d60047 100644 --- a/liblwgeom/lwpoly.c +++ b/liblwgeom/lwpoly.c @@ -75,6 +75,24 @@ lwpoly_construct(int srid, GBOX *bbox, uint32_t nrings, POINTARRAY **points) return result; } +LWPOLY* +lwpoly_construct_rectangle(char hasz, char hasm, POINT4D *p1, POINT4D *p2, + POINT4D *p3, POINT4D *p4) +{ + POINTARRAY *pa = ptarray_construct_empty(hasz, hasm, 5); + LWPOLY *lwpoly = lwpoly_construct_empty(SRID_UNKNOWN, hasz, hasm); + + ptarray_append_point(pa, p1, LW_TRUE); + ptarray_append_point(pa, p2, LW_TRUE); + ptarray_append_point(pa, p3, LW_TRUE); + ptarray_append_point(pa, p4, LW_TRUE); + ptarray_append_point(pa, p1, LW_TRUE); + + lwpoly_add_ring(lwpoly, pa); + + return lwpoly; +} + LWPOLY* lwpoly_construct_empty(int srid, char hasz, char hasm) { diff --git a/postgis/lwgeom_box.c b/postgis/lwgeom_box.c index c52e911eb..1df91038f 100644 --- a/postgis/lwgeom_box.c +++ b/postgis/lwgeom_box.c @@ -494,29 +494,18 @@ Datum BOX2D_to_LWGEOM(PG_FUNCTION_ARGS) } else { + POINT4D points[4]; LWPOLY *poly; - POINTARRAY **ppa = lwalloc(sizeof(POINTARRAY*)); - /* Assign coordinates to point array */ - pt.x = box->xmin; - pt.y = box->ymin; - ptarray_append_point(pa, &pt, LW_TRUE); - pt.x = box->xmin; - pt.y = box->ymax; - ptarray_append_point(pa, &pt, LW_TRUE); - pt.x = box->xmax; - pt.y = box->ymax; - ptarray_append_point(pa, &pt, LW_TRUE); - pt.x = box->xmax; - pt.y = box->ymin; - ptarray_append_point(pa, &pt, LW_TRUE); - pt.x = box->xmin; - pt.y = box->ymin; - ptarray_append_point(pa, &pt, LW_TRUE); + /* Initialize the 4 vertices of the polygon */ + points[0] = (POINT4D) { box->xmin, box->ymin }; + points[1] = (POINT4D) { box->xmin, box->ymax }; + points[2] = (POINT4D) { box->xmax, box->ymax }; + points[3] = (POINT4D) { box->xmax, box->ymin }; /* Construct polygon */ - ppa[0] = pa; - poly = lwpoly_construct(SRID_UNKNOWN, NULL, 1, ppa); + poly = lwpoly_construct_rectangle(LW_FALSE, LW_FALSE, &points[0], &points[1], + &points[2], &points[3]); result = geometry_serialize(lwpoly_as_lwgeom(poly)); lwpoly_free(poly); } diff --git a/postgis/lwgeom_box3d.c b/postgis/lwgeom_box3d.c index f169e6833..80d81c11c 100644 --- a/postgis/lwgeom_box3d.c +++ b/postgis/lwgeom_box3d.c @@ -199,69 +199,159 @@ Datum BOX3D_to_LWGEOM(PG_FUNCTION_ARGS) GSERIALIZED *result; POINT4D pt; - /** * Alter BOX3D cast so that a valid geometry is always * returned depending upon the size of the BOX3D. The * code makes the following assumptions: * - If the BOX3D is a single point then return a * POINT geometry - * - If the BOX3D represents either a horizontal or - * vertical line, return a LINESTRING geometry - * - Otherwise return a POLYGON + * - If the BOX3D represents a line in any of X, Y + * or Z dimension, return a LINESTRING geometry + * - If the BOX3D represents a plane in the X, Y, + * or Z dimension, return a POLYGON geometry + * - Otherwise return a POLYHEDRALSURFACE geometry */ - pa = ptarray_construct_empty(0, 0, 5); + pa = ptarray_construct_empty(LW_TRUE, LW_FALSE, 5); - if ( (box->xmin == box->xmax) && (box->ymin == box->ymax) ) + /* BOX3D is a point */ + if ( (box->xmin == box->xmax) && (box->ymin == box->ymax) && + (box->zmin == box->zmax) ) { LWPOINT *lwpt = lwpoint_construct(SRID_UNKNOWN, NULL, pa); pt.x = box->xmin; pt.y = box->ymin; + pt.z = box->zmin; ptarray_append_point(pa, &pt, LW_TRUE); result = geometry_serialize(lwpoint_as_lwgeom(lwpt)); + lwpoint_free(lwpt); } - else if (box->xmin == box->xmax || - box->ymin == box->ymax) + /* BOX3D is a line */ + else if (((box->xmin == box->xmax || + box->ymin == box->ymax) && + box->zmin == box->zmax) || + ((box->xmin == box->xmax || + box->zmin == box->zmax) && + box->ymin == box->ymax) || + ((box->ymin == box->ymax || + box->zmin == box->zmax) && + box->xmin == box->xmax)) { LWLINE *lwline = lwline_construct(SRID_UNKNOWN, NULL, pa); pt.x = box->xmin; pt.y = box->ymin; + pt.z = box->zmin; ptarray_append_point(pa, &pt, LW_TRUE); pt.x = box->xmax; pt.y = box->ymax; + pt.z = box->zmax; ptarray_append_point(pa, &pt, LW_TRUE); result = geometry_serialize(lwline_as_lwgeom(lwline)); + lwline_free(lwline); } - else + /* BOX3D is a polygon in the X plane */ + else if (box->xmin == box->xmax) { - LWPOLY *lwpoly = lwpoly_construct(SRID_UNKNOWN, NULL, 1, &pa); + POINT4D points[4]; + LWPOLY *lwpoly; - pt.x = box->xmin; - pt.y = box->ymin; - ptarray_append_point(pa, &pt, LW_TRUE); - pt.x = box->xmin; - pt.y = box->ymax; - ptarray_append_point(pa, &pt, LW_TRUE); - pt.x = box->xmax; - pt.y = box->ymax; - ptarray_append_point(pa, &pt, LW_TRUE); - pt.x = box->xmax; - pt.y = box->ymin; - ptarray_append_point(pa, &pt, LW_TRUE); - pt.x = box->xmin; - pt.y = box->ymin; - ptarray_append_point(pa, &pt, LW_TRUE); + /* Initialize the 4 vertices of the polygon */ + points[0] = (POINT4D) { box->xmin, box->ymin, box->zmin }; + points[1] = (POINT4D) { box->xmin, box->ymax, box->zmin }; + points[2] = (POINT4D) { box->xmin, box->ymax, box->zmax }; + points[3] = (POINT4D) { box->xmin, box->ymin, box->zmax }; + lwpoly = lwpoly_construct_rectangle(LW_TRUE, LW_FALSE, + &points[0], &points[1], &points[2], &points[3]); result = geometry_serialize(lwpoly_as_lwgeom(lwpoly)); - + lwpoly_free(lwpoly); + } + /* BOX3D is a polygon in the Y plane */ + else if (box->ymin == box->ymax) + { + POINT4D points[4]; + LWPOLY *lwpoly; + + /* Initialize the 4 vertices of the polygon */ + points[0] = (POINT4D) { box->xmin, box->ymin, box->zmin }; + points[1] = (POINT4D) { box->xmax, box->ymin, box->zmin }; + points[2] = (POINT4D) { box->xmax, box->ymin, box->zmax }; + points[3] = (POINT4D) { box->xmin, box->ymin, box->zmax }; + + lwpoly = lwpoly_construct_rectangle(LW_TRUE, LW_FALSE, + &points[0], &points[1], &points[2], &points[3]); + result = geometry_serialize(lwpoly_as_lwgeom(lwpoly)); + lwpoly_free(lwpoly); + } + /* BOX3D is a polygon in the Z plane */ + else if (box->zmin == box->zmax) + { + POINT4D points[4]; + LWPOLY *lwpoly; + + /* Initialize the 4 vertices of the polygon */ + points[0] = (POINT4D) { box->xmin, box->ymin, box->zmin }; + points[1] = (POINT4D) { box->xmin, box->ymax, box->zmin }; + points[2] = (POINT4D) { box->xmax, box->ymax, box->zmin }; + points[3] = (POINT4D) { box->xmax, box->ymin, box->zmin }; + + lwpoly = lwpoly_construct_rectangle(LW_TRUE, LW_FALSE, + &points[0], &points[1], &points[2], &points[3]); + result = geometry_serialize(lwpoly_as_lwgeom(lwpoly)); + lwpoly_free(lwpoly); + } + /* BOX3D is a polyhedron */ + else + { + POINT4D points[8]; + static const int ngeoms = 6; + LWGEOM **geoms = (LWGEOM **) lwalloc(sizeof(LWGEOM *) * ngeoms); + LWGEOM *geom = NULL; + + /* Initialize the 8 vertices of the box */ + points[0] = (POINT4D) { box->xmin, box->ymin, box->zmin }; + points[1] = (POINT4D) { box->xmin, box->ymax, box->zmin }; + points[2] = (POINT4D) { box->xmax, box->ymax, box->zmin }; + points[3] = (POINT4D) { box->xmax, box->ymin, box->zmin }; + points[4] = (POINT4D) { box->xmin, box->ymin, box->zmax }; + points[5] = (POINT4D) { box->xmin, box->ymax, box->zmax }; + points[6] = (POINT4D) { box->xmax, box->ymax, box->zmax }; + points[7] = (POINT4D) { box->xmax, box->ymin, box->zmax }; + + /* add bottom polygon */ + geoms[0] = lwpoly_as_lwgeom(lwpoly_construct_rectangle(LW_TRUE, LW_FALSE, + &points[0], &points[1], &points[2], &points[3])); + /* add top polygon */ + geoms[1] = lwpoly_as_lwgeom(lwpoly_construct_rectangle(LW_TRUE, LW_FALSE, + &points[4], &points[5], &points[6], &points[7])); + /* add left polygon */ + geoms[2] = lwpoly_as_lwgeom(lwpoly_construct_rectangle(LW_TRUE, LW_FALSE, + &points[0], &points[1], &points[5], &points[4])); + /* add right polygon */ + geoms[3] = lwpoly_as_lwgeom(lwpoly_construct_rectangle(LW_TRUE, LW_FALSE, + &points[3], &points[2], &points[6], &points[7])); + /* add back polygon */ + geoms[4] = lwpoly_as_lwgeom(lwpoly_construct_rectangle(LW_TRUE, LW_FALSE, + &points[0], &points[3], &points[7], &points[4])); + /* add front polygon */ + geoms[5] = lwpoly_as_lwgeom(lwpoly_construct_rectangle(LW_TRUE, LW_FALSE, + &points[1], &points[2], &points[6], &points[5])); + + geom = (LWGEOM *) lwcollection_construct(POLYHEDRALSURFACETYPE, + SRID_UNKNOWN, NULL, ngeoms, geoms); + + FLAGS_SET_SOLID(geom->flags, 1); + + result = geometry_serialize(geom); + lwcollection_free((LWCOLLECTION *) geom); } gserialized_set_srid(result, box->srid); + PG_RETURN_POINTER(result); } diff --git a/regress/regress.sql b/regress/regress.sql index 1023118cd..712f12d53 100644 --- a/regress/regress.sql +++ b/regress/regress.sql @@ -1,3 +1,4 @@ +-- postgres --- regression test for postGIS @@ -129,7 +130,12 @@ select '76a',ST_OrderingEquals('LINESTRING(1 1, 2 2)'::GEOMETRY,'LINESTRING(1 1, select '106',box3d('MULTIPOINT(0 0, 7 7)'::GEOMETRY) as bvol; -- box3d only type is only used for indexing -- NEVER use one yourself -select '107',ST_AsEWKT(geometry('BOX3D(0 0 0, 7 7 7 )'::BOX3D)); +select '107a',ST_AsEWKT(geometry('BOX3D(1 2 3, 1 2 3 )'::BOX3D)); +select '107b',ST_AsEWKT(geometry('BOX3D(2 3 3, 7 3 3 )'::BOX3D)); +select '107c',ST_AsEWKT(geometry('BOX3D(2 3 5, 6 8 5 )'::BOX3D)); +select '107d',ST_AsEWKT(geometry('BOX3D(1 -1 4, 2 -1 9 )'::BOX3D)); +select '107e',ST_AsEWKT(geometry('BOX3D(-1 3 5, -1 6 8 )'::BOX3D)); +select '107f',ST_AsEWKT(geometry('BOX3D(1 2 3, 4 5 6 )'::BOX3D)); --- debug function testing diff --git a/regress/regress_expected b/regress/regress_expected index 157e1cf6f..86017a7f4 100644 --- a/regress/regress_expected +++ b/regress/regress_expected @@ -87,7 +87,12 @@ ERROR: parse error - invalid geometry at character 23 76|f 76a|f 106|BOX3D(0 0 0,7 7 0) -107|POLYGON((0 0,0 7,7 7,7 0,0 0)) +107a|POINT(1 2 3) +107b|LINESTRING(2 3 3,7 3 3) +107c|POLYGON((2 3 5,2 8 5,6 8 5,6 3 5,2 3 5)) +107d|POLYGON((1 -1 4,2 -1 4,2 -1 9,1 -1 9,1 -1 4)) +107e|POLYGON((-1 3 5,-1 6 5,-1 6 8,-1 3 8,-1 3 5)) +107f|POLYHEDRALSURFACE(((1 2 3,1 5 3,4 5 3,4 2 3,1 2 3)),((1 2 6,1 5 6,4 5 6,4 2 6,1 2 6)),((1 2 3,1 5 3,1 5 6,1 2 6,1 2 3)),((4 2 3,4 5 3,4 5 6,4 2 6,4 2 3)),((1 2 3,4 2 3,4 2 6,1 2 6,1 2 3)),((1 5 3,4 5 3,4 5 6,1 5 6,1 5 3))) 108|2 109|4 110|6 diff --git a/regress/sfcgal/regress.sql b/regress/sfcgal/regress.sql index d469bc750..bcb4cec8a 100644 --- a/regress/sfcgal/regress.sql +++ b/regress/sfcgal/regress.sql @@ -178,7 +178,12 @@ select '105','MULTIPOINT(-0.0001 0, 7 7)'::GEOMETRY @ 'MULTIPOINT(0 0, 10 10)':: select '106',box3d('MULTIPOINT(0 0, 7 7)'::GEOMETRY) as bvol; -- box3d only type is only used for indexing -- NEVER use one yourself -select '107',ST_AsEWKT(geometry('BOX3D(0 0 0, 7 7 7 )'::BOX3D)); +select '107a',ST_AsEWKT(geometry('BOX3D(1 2 3, 1 2 3 )'::BOX3D)); +select '107b',ST_AsEWKT(geometry('BOX3D(2 3 3, 7 3 3 )'::BOX3D)); +select '107c',ST_AsEWKT(geometry('BOX3D(2 3 5, 6 8 5 )'::BOX3D)); +select '107d',ST_AsEWKT(geometry('BOX3D(1 -1 4, 2 -1 9 )'::BOX3D)); +select '107e',ST_AsEWKT(geometry('BOX3D(-1 3 5, -1 6 8 )'::BOX3D)); +select '107f',ST_AsEWKT(geometry('BOX3D(1 2 3, 4 5 6 )'::BOX3D)); --- debug function testing diff --git a/regress/sfcgal/regress_expected b/regress/sfcgal/regress_expected index 38cacf545..d0844e4c7 100644 --- a/regress/sfcgal/regress_expected +++ b/regress/sfcgal/regress_expected @@ -116,7 +116,12 @@ ERROR: parse error - invalid geometry at character 23 104|t 105|f 106|BOX3D(0 0 0,7 7 0) -107|POLYGON((0 0,0 7,7 7,7 0,0 0)) +107a|POINT(1 2 3) +107b|LINESTRING(2 3 3,7 3 3) +107c|POLYGON((2 3 5,2 8 5,6 8 5,6 3 5,2 3 5)) +107d|POLYGON((1 -1 4,2 -1 4,2 -1 9,1 -1 9,1 -1 4)) +107e|POLYGON((-1 3 5,-1 6 5,-1 6 8,-1 3 8,-1 3 5)) +107f|POLYHEDRALSURFACE(((1 2 3,1 5 3,4 5 3,4 2 3,1 2 3)),((1 2 6,1 5 6,4 5 6,4 2 6,1 2 6)),((1 2 3,1 5 3,1 5 6,1 2 6,1 2 3)),((4 2 3,4 5 3,4 5 6,4 2 6,4 2 3)),((1 2 3,4 2 3,4 2 6,1 2 6,1 2 3)),((1 5 3,4 5 3,4 5 6,1 5 6,1 5 3))) 108|2 109|4 110|6 -- 2.40.0