From d427e6a0b48d0b53dd882481c5521946192bcbd5 Mon Sep 17 00:00:00 2001 From: Sandro Santilli Date: Tue, 23 Jun 2015 18:56:11 +0000 Subject: [PATCH] Expose ST_CPAWithin to SQL Includes dox and regress test git-svn-id: http://svn.osgeo.org/postgis/trunk@13694 b70326c6-7e19-0410-871a-916f4a2858ee --- NEWS | 1 + doc/reference_temporal.xml | 72 +++++++++++++++++++++++++++++ postgis/lwgeom_functions_temporal.c | 21 +++++++++ postgis/postgis.sql.in | 6 +++ regress/temporal.sql | 26 +++++++++++ regress/temporal_expected | 10 ++++ 6 files changed, 136 insertions(+) diff --git a/NEWS b/NEWS index bef3afd35..0fba1aa1a 100644 --- a/NEWS +++ b/NEWS @@ -31,6 +31,7 @@ PostGIS 2.2.0 * New Features * - #3169, ST_ApproximateMedialAxis (Sandro Santilli) + - ST_CPAWithin (Sandro Santilli / Boundless) - Add |=| operator with CPA semantic and KNN support with PgSQL 9.5+ (Sandro Santilli / Boundless) - #3131, KNN support for the geography type (Paul Ramsey / CartoDB) diff --git a/doc/reference_temporal.xml b/doc/reference_temporal.xml index 37d1f58d7..ab325e621 100644 --- a/doc/reference_temporal.xml +++ b/doc/reference_temporal.xml @@ -212,6 +212,78 @@ SELECT ST_DistanceCPA(a,b) distance FROM inp; , , , + + + + + + + + + ST_CPAWithin + +Returns true if the trajectories' closest points of approach +are within the specified distance. + + + + + + + float8 ST_CPAWithin + geometry track1 + geometry track2 + float8 maxdist + + + + + + Description + + +Checks whether two moving objects have ever been within the +specified max distance. + + +Inputs must be valid trajectories as checked by +. +False is returned if the trajectories do not overlap on the M range. + + + Availability: 2.2.0 + &Z_support; + + + + + Examples + +WITH inp AS ( SELECT + ST_AddMeasure('LINESTRING Z (0 0 0, 10 0 5)'::geometry, + extract(epoch from '2015-05-26 10:00'::timestamptz), + extract(epoch from '2015-05-26 11:00'::timestamptz) + ) a, + ST_AddMeasure('LINESTRING Z (0 2 10, 12 1 2)'::geometry, + extract(epoch from '2015-05-26 10:00'::timestamptz), + extract(epoch from '2015-05-26 11:00'::timestamptz) + ) b +) +SELECT ST_CPAWithin(a,b,2), ST_DistanceCPA(a,b) distance FROM inp; + + st_cpawithin | distance +--------------+------------------ + t | 1.96521473776207 + + + + + + See Also + +, +, +, diff --git a/postgis/lwgeom_functions_temporal.c b/postgis/lwgeom_functions_temporal.c index 463fcc78c..ef3b3ccb5 100644 --- a/postgis/lwgeom_functions_temporal.c +++ b/postgis/lwgeom_functions_temporal.c @@ -89,4 +89,25 @@ Datum ST_DistanceCPA(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(mindist); } +/* + * Return true if the distance between two trajectories at their + * closest point of approach is within the given max. + */ +Datum ST_CPAWithin(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(ST_CPAWithin); +Datum ST_CPAWithin(PG_FUNCTION_ARGS) +{ + GSERIALIZED *gs0 = PG_GETARG_GSERIALIZED_P(0); + GSERIALIZED *gs1 = PG_GETARG_GSERIALIZED_P(1); + double maxdist = PG_GETARG_FLOAT8(2); + /* All checks already performed by liblwgeom, not worth checking again */ + LWGEOM *g0 = lwgeom_from_gserialized(gs0); + LWGEOM *g1 = lwgeom_from_gserialized(gs1); + int ret = lwgeom_cpa_within(g0, g1, maxdist); + lwgeom_free(g0); + lwgeom_free(g1); + PG_FREE_IF_COPY(gs0, 0); + PG_FREE_IF_COPY(gs1, 1); + PG_RETURN_BOOL( ret == LW_TRUE ); +} diff --git a/postgis/postgis.sql.in b/postgis/postgis.sql.in index 6127f0b61..9f3b4f837 100644 --- a/postgis/postgis.sql.in +++ b/postgis/postgis.sql.in @@ -3090,6 +3090,12 @@ CREATE OR REPLACE FUNCTION ST_DistanceCPA(geometry, geometry) AS 'MODULE_PATHNAME', 'ST_DistanceCPA' LANGUAGE 'c' IMMUTABLE STRICT; +-- Availability: 2.2.0 +CREATE OR REPLACE FUNCTION ST_CPAWithin(geometry, geometry, float8) + RETURNS bool + AS 'MODULE_PATHNAME', 'ST_CPAWithin' + LANGUAGE 'c' IMMUTABLE STRICT; + -- Availability: 2.2.0 CREATE OR REPLACE FUNCTION ST_IsValidTrajectory(geometry) RETURNS bool diff --git a/regress/temporal.sql b/regress/temporal.sql index ae4a47090..d3b451ac6 100644 --- a/regress/temporal.sql +++ b/regress/temporal.sql @@ -66,3 +66,29 @@ SELECT 'cpad4', ST_DistanceCPA('LINESTRINGM(0 0 0, 10 0 10)'::geometry SELECT 'invalid', ST_DistanceCPA('LINESTRING(0 0 0, 1 0 0)'::geometry ,'LINESTRING(0 0 3 0, 1 0 2 1)'::geometry); + +---------------------------------------- +-- +-- ST_CPAWithin +-- +---------------------------------------- + +SELECT 'cpaw1', d, ST_CPAWithin( + 'LINESTRINGM(0 0 0, 1 0 1)'::geometry + ,'LINESTRINGM(0 0 0, 1 0 1)'::geometry, d) + FROM ( VALUES (0.0),(1) ) f(d) ORDER BY d; +SELECT 'cpaw2', d, ST_CPAWithin( + 'LINESTRINGM(0 0 0, 1 0 1)'::geometry + ,'LINESTRINGM(0 0 1, 1 0 2)'::geometry, d) + FROM ( VALUES (0.5),(1),(1.2) ) f(d) ORDER BY d; +SELECT 'cpaw3', d, ST_CPAWithin( + 'LINESTRING(0 0 0 0, 1 0 0 1)'::geometry + ,'LINESTRING(0 0 3 0, 1 0 2 1)'::geometry, d) + FROM ( VALUES (1.9),(2),(2.0001) ) f(d) ORDER BY d; +-- temporary disjoint +SELECT 'cpaw4', ST_CPAWithin( + 'LINESTRINGM(0 0 0, 10 0 10)'::geometry + ,'LINESTRINGM(10 0 11, 10 10 20)'::geometry, 1e15); +SELECT 'cpaw_invalid', ST_CPAWithin( + 'LINESTRING(0 0 0, 1 0 0)'::geometry + ,'LINESTRING(0 0 3 0, 1 0 2 1)'::geometry, 1e16); diff --git a/regress/temporal_expected b/regress/temporal_expected index 487745208..64b3e221e 100644 --- a/regress/temporal_expected +++ b/regress/temporal_expected @@ -22,3 +22,13 @@ cpad2|1 cpad3|2 cpad4| ERROR: Both input geometries must have a measure dimension +cpaw1|0.0|t +cpaw1|1|t +cpaw2|0.5|f +cpaw2|1|t +cpaw2|1.2|t +cpaw3|1.9|f +cpaw3|2|t +cpaw3|2.0001|t +cpaw4|f +ERROR: Both input geometries must have a measure dimension -- 2.50.1