From a3e647241fd5cb0f17349d261a863945dd85eb2e Mon Sep 17 00:00:00 2001 From: Sandro Santilli Date: Mon, 1 Jun 2015 16:09:22 +0000 Subject: [PATCH] ST_BoundingDiagonal (#3139) Includes tests and documentation git-svn-id: http://svn.osgeo.org/postgis/trunk@13599 b70326c6-7e19-0410-871a-916f4a2858ee --- NEWS | 1 + doc/reference_accessor.xml | 79 ++++++++++++++++++++++++++++++++ postgis/lwgeom_functions_basic.c | 55 ++++++++++++++++++++++ postgis/postgis.sql.in | 6 +++ regress/lwgeom_regress.sql | 21 +++++++++ regress/lwgeom_regress_expected | 6 +++ 6 files changed, 168 insertions(+) diff --git a/NEWS b/NEWS index 765d0d5f9..8d6e2de33 100644 --- a/NEWS +++ b/NEWS @@ -29,6 +29,7 @@ PostGIS 2.2.0 * New Features * + - #3139, ST_BoundingDiagonal (Sandro Santilli / Boundless) - #3129, ST_IsValidTrajectory (Sandro Santilli / Boundless) - #3128, ST_ClosestPointOfApproach (Sandro Santilli / Boundless) - Canonical output for index key types diff --git a/doc/reference_accessor.xml b/doc/reference_accessor.xml index dd9781934..884b3e613 100644 --- a/doc/reference_accessor.xml +++ b/doc/reference_accessor.xml @@ -416,6 +416,85 @@ SELECT Box3D(geom), Box2D(geom), ST_AsText(ST_Envelope(geom)) As envelopewkt + + + ST_BoundingDiagonal + + Returns the diagonal of the supplied geometry's bounding box. + + + + + + geometry ST_BoundingDiagonal + + geometry geom + boolean fits=false + + + + + + Description + + +Returns the diagonal of the supplied geometry's bounding box as linestring. +If the input geometry is empty, the diagonal line is also empty, otherwise +it is a 2-points linestring with minimum values of each dimension in its +start point and maximum values in its end point. + + + +The returned linestring geometry always retains SRID and dimensionality +(Z and M presence) of the input geometry. + + + +The fits parameter specifies if the best fit is needed. +If false, the diagonal of a somewhat larger bounding box can be accepted +(is faster to obtain for geometries with a lot of vertices). In any case +the bounding box of the returned diagonal line always covers the input +geometry. + + + +In degenerate cases (a single vertex in input) the returned linestring +will be topologically invalid (no interior). This does not make the +return semantically invalid. + + + Availability: 2.2.0 + &Z_support; + &M_support; + + + + Examples + + +-- Get the minimum X in a buffer around a point +SELECT ST_X(ST_StartPoint(ST_BoundingDiagonal( + ST_Buffer(ST_MakePoint(0,0),10) +))); + st_x +------ + -10 + + + + See Also + +, +, +, +, +, +, + + + + + ST_ExteriorRing diff --git a/postgis/lwgeom_functions_basic.c b/postgis/lwgeom_functions_basic.c index 6391a9918..7b99320ce 100644 --- a/postgis/lwgeom_functions_basic.c +++ b/postgis/lwgeom_functions_basic.c @@ -2744,3 +2744,58 @@ Datum ST_SwapOrdinates(PG_FUNCTION_ARGS) PG_FREE_IF_COPY(in, 0); PG_RETURN_POINTER(out); } + +/* + * ST_BoundingDiagonal(inp geometry, fits boolean) + */ +Datum ST_BoundingDiagonal(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(ST_BoundingDiagonal); +Datum ST_BoundingDiagonal(PG_FUNCTION_ARGS) +{ + GSERIALIZED *geom_in = PG_GETARG_GSERIALIZED_P(0); + GSERIALIZED *geom_out; + bool fits = PG_GETARG_BOOL(1); + LWGEOM *lwgeom_in = lwgeom_from_gserialized(geom_in); + LWGEOM *lwgeom_out; + const GBOX *gbox; + int hasz = FLAGS_GET_Z(lwgeom_in->flags); + int hasm = FLAGS_GET_M(lwgeom_in->flags); + int srid = lwgeom_in->srid; + POINT4D pt; + POINTARRAY *pa; + + if ( fits ) { + /* unregister any cached bbox to ensure it's recomputed */ + lwgeom_in->bbox = NULL; + } + + gbox = lwgeom_get_bbox(lwgeom_in); + + if ( ! gbox ) + { + lwgeom_out = lwgeom_construct_empty(LINETYPE, srid, hasz, hasm); + } + else + { + pa = ptarray_construct_empty(hasz, hasm, 2); + pt.x = gbox->xmin; + pt.y = gbox->ymin; + pt.z = gbox->zmin; + pt.m = gbox->mmin; + ptarray_append_point(pa, &pt, LW_TRUE); + pt.x = gbox->xmax; + pt.y = gbox->ymax; + pt.z = gbox->zmax; + pt.m = gbox->mmax; + ptarray_append_point(pa, &pt, LW_TRUE); + lwgeom_out = lwline_as_lwgeom( lwline_construct(srid, NULL, pa) ); + } + + lwgeom_free(lwgeom_in); + PG_FREE_IF_COPY(geom_in, 0); + + geom_out = geometry_serialize(lwgeom_out); + lwgeom_free(lwgeom_out); + + PG_RETURN_POINTER(geom_out); +} diff --git a/postgis/postgis.sql.in b/postgis/postgis.sql.in index f812889ae..6171d4b8a 100644 --- a/postgis/postgis.sql.in +++ b/postgis/postgis.sql.in @@ -1478,6 +1478,12 @@ CREATE OR REPLACE FUNCTION ST_Envelope(geometry) AS 'MODULE_PATHNAME', 'LWGEOM_envelope' LANGUAGE 'c' IMMUTABLE STRICT; +-- Availability: 2.2.0 +CREATE OR REPLACE FUNCTION ST_BoundingDiagonal(geom geometry, fits boolean DEFAULT false) + RETURNS geometry + AS 'MODULE_PATHNAME', 'ST_BoundingDiagonal' + LANGUAGE 'c' IMMUTABLE STRICT; + -- Availability: 1.2.2 CREATE OR REPLACE FUNCTION ST_Reverse(geometry) RETURNS geometry diff --git a/regress/lwgeom_regress.sql b/regress/lwgeom_regress.sql index d299c8b4c..9e4807fd8 100644 --- a/regress/lwgeom_regress.sql +++ b/regress/lwgeom_regress.sql @@ -114,3 +114,24 @@ SELECT '#3069', postgis_getbbox('SRID=0;LINESTRING(0 0, 1 1)'::geometry); SELECT '#3069', postgis_getbbox('SRID=0;MULTILINESTRING((0 0, 1 1))'::geometry); SELECT '#3069', postgis_getbbox('SRID=0;MULTIPOINT(1 1)'::geometry); SELECT '#3069', postgis_getbbox('SRID=0;MULTILINESTRING((0 0,1 1))'::geometry); + +-- ST_BoundingDiagonal + +SELECT 'BoundingDiagonal1', ST_AsEwkt(ST_BoundingDiagonal(postgis_addbbox( + 'SRID=4326;POINT(1e+15 1e+15)'::geometry +))); +SELECT 'BoundingDiagonal2', ST_AsEwkt(ST_BoundingDiagonal(postgis_addbbox( + 'SRID=4326;POINT(1e+15 1e+15)'::geometry +), true)); +SELECT 'BoundingDiagonal3', ST_AsEwkt(ST_BoundingDiagonal(postgis_addbbox( + 'SRID=4326;POINT(1e+15 1e+15)'::geometry +), false)); +SELECT 'BoundingDiagonal4', ST_AsEwkt(ST_BoundingDiagonal( + 'SRID=3857;LINESTRING(1 2 3 4, 0 1 -8 2, -1 -2 -3 9)'::geometry +)); +SELECT 'BoundingDiagonal5', ST_AsEwkt(ST_BoundingDiagonal( + 'SRID=3857;LINESTRING M (5 4 0,4 4 1)'::geometry +)); +SELECT 'BoundingDiagonal6', ST_AsEwkt(ST_BoundingDiagonal( + 'SRID=3857;POLYGON M EMPTY'::geometry +)); diff --git a/regress/lwgeom_regress_expected b/regress/lwgeom_regress_expected index c4bdcf4af..6bc193ed0 100644 --- a/regress/lwgeom_regress_expected +++ b/regress/lwgeom_regress_expected @@ -15,3 +15,9 @@ BOX3D(0 0.1 -55,11 12 12) #3069|BOX(0 0,1 1) #3069|BOX(1 1,1 1) #3069|BOX(0 0,1 1) +BoundingDiagonal1|SRID=4326;LINESTRING(999999986991104 999999986991104,999999986991104 999999986991104) +BoundingDiagonal2|SRID=4326;LINESTRING(1e+15 1e+15,1e+15 1e+15) +BoundingDiagonal3|SRID=4326;LINESTRING(999999986991104 999999986991104,999999986991104 999999986991104) +BoundingDiagonal4|SRID=3857;LINESTRING(-1 -2 -8 2,1 2 3 9) +BoundingDiagonal5|SRID=3857;LINESTRINGM(4 4 0,5 4 1) +BoundingDiagonal6|SRID=3857;LINESTRINGM EMPTY -- 2.40.0