From 4c2b8a4a5e2c6012f7ceed4aaa5c3146242c2792 Mon Sep 17 00:00:00 2001 From: Sandro Santilli Date: Tue, 9 Jun 2015 19:38:39 +0000 Subject: [PATCH] ST_DistanceCPA: return distance at closest point of approach Includes regression test and docs. git-svn-id: http://svn.osgeo.org/postgis/trunk@13631 b70326c6-7e19-0410-871a-916f4a2858ee --- NEWS | 1 + doc/reference_temporal.xml | 68 ++++++++++++++++++++++++++++++++++ postgis/lwgeom_functions_lrs.c | 24 ++++++++++++ postgis/postgis.sql.in | 6 +++ regress/temporal.sql | 15 ++++++++ regress/temporal_expected | 4 ++ 6 files changed, 118 insertions(+) diff --git a/NEWS b/NEWS index 8d6e2de33..842851e66 100644 --- a/NEWS +++ b/NEWS @@ -32,6 +32,7 @@ PostGIS 2.2.0 - #3139, ST_BoundingDiagonal (Sandro Santilli / Boundless) - #3129, ST_IsValidTrajectory (Sandro Santilli / Boundless) - #3128, ST_ClosestPointOfApproach (Sandro Santilli / Boundless) + - #3152, ST_DistanceCPA (Sandro Santilli / Boundless) - Canonical output for index key types - ST_SwapOrdinates (Sandro Santilli / Boundless) - #2918, Use GeographicLib functions for geodetics (Mike Toews) diff --git a/doc/reference_temporal.xml b/doc/reference_temporal.xml index f3a34f735..5d688ea39 100644 --- a/doc/reference_temporal.xml +++ b/doc/reference_temporal.xml @@ -142,7 +142,75 @@ FROM points, cpa; See Also , +, , + + + + + + + + + ST_DistanceCPA + +Returns the distance between closest points of approach in two trajectories. + + + + + + + float8 ST_DistanceCPA + geometry track1 + geometry track2 + + + + + + Description + + +Returns the minimum distance two moving objects have ever been each-other. +Inputs must be valid trajectories as checked by +. +Null is returned if the trajectories do not overlap on the M range. + + + Availability: 2.2.0 + &Z_support; + + + + + Examples + +-- Return the minimum distance of two objects moving between 10:00 and 11:00 +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_DistanceCPA(a,b) distance FROM inp; + + distance +------------------ + 1.96036833151395 + + + + + + See Also + +, +, diff --git a/postgis/lwgeom_functions_lrs.c b/postgis/lwgeom_functions_lrs.c index 212f8f1cb..7dc9681eb 100644 --- a/postgis/lwgeom_functions_lrs.c +++ b/postgis/lwgeom_functions_lrs.c @@ -793,3 +793,27 @@ Datum ST_IsValidTrajectory(PG_FUNCTION_ARGS) lwgeom_free(g0); PG_RETURN_BOOL(ret == LW_TRUE); } + +/* + * Return the distance between two trajectories at their + * closest point of approach. + */ +Datum ST_DistanceCPA(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(ST_DistanceCPA); +Datum ST_DistanceCPA(PG_FUNCTION_ARGS) +{ + GSERIALIZED *gs0 = PG_GETARG_GSERIALIZED_P(0); + GSERIALIZED *gs1 = PG_GETARG_GSERIALIZED_P(1); + /* All checks already performed by liblwgeom, not worth checking again */ + LWGEOM *g0 = lwgeom_from_gserialized(gs0); + LWGEOM *g1 = lwgeom_from_gserialized(gs1); + double mindist; + double m = lwgeom_tcpa(g0, g1, &mindist); + lwgeom_free(g0); + lwgeom_free(g1); + PG_FREE_IF_COPY(gs0, 0); + PG_FREE_IF_COPY(gs1, 1); + PG_RETURN_FLOAT8(mindist); +} + + diff --git a/postgis/postgis.sql.in b/postgis/postgis.sql.in index 10692bcdd..efc2eb699 100644 --- a/postgis/postgis.sql.in +++ b/postgis/postgis.sql.in @@ -3051,6 +3051,12 @@ CREATE OR REPLACE FUNCTION ST_ClosestPointOfApproach(geometry, geometry) AS 'MODULE_PATHNAME', 'ST_ClosestPointOfApproach' LANGUAGE 'c' IMMUTABLE STRICT; +-- Availability: 2.2.0 +CREATE OR REPLACE FUNCTION ST_DistanceCPA(geometry, geometry) + RETURNS float8 + AS 'MODULE_PATHNAME', 'gserialized_distance_cpa' -- ST_DistanceCPA + 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 fa245472e..0f27248c9 100644 --- a/regress/temporal.sql +++ b/regress/temporal.sql @@ -47,3 +47,18 @@ WITH inp as ( SELECT SELECT 'cpa#3136', ST_ClosestPointOfApproach(g2,g1), ST_ClosestPointOfApproach(g1,g2) FROM inp; + +---------------------------------------- +-- +-- ST_DistanceCPA +-- +---------------------------------------- + +SELECT 'cpad1', ST_DistanceCPA('LINESTRINGM(0 0 0, 1 0 1)'::geometry + ,'LINESTRINGM(0 0 0, 1 0 1)'::geometry); +SELECT 'cpad2', ST_DistanceCPA('LINESTRINGM(0 0 0, 1 0 1)'::geometry + ,'LINESTRINGM(0 0 1, 1 0 2)'::geometry); +SELECT 'cpad3', ST_DistanceCPA('LINESTRING(0 0 0 0, 1 0 0 1)'::geometry + ,'LINESTRING(0 0 3 0, 1 0 2 1)'::geometry); +SELECT 'invalid', ST_DistanceCPA('LINESTRING(0 0 0, 1 0 0)'::geometry + ,'LINESTRING(0 0 3 0, 1 0 2 1)'::geometry); diff --git a/regress/temporal_expected b/regress/temporal_expected index 41a6136d6..4eebe4dcc 100644 --- a/regress/temporal_expected +++ b/regress/temporal_expected @@ -17,3 +17,7 @@ cpa3|5.5 cpa4|10 cpa5| cpa#3136|80000002|80000002 +cpad1|0 +cpad2|1 +cpad3|2 +ERROR: Both input geometries must have a measure dimension -- 2.40.0