From: Paul Ramsey Date: Tue, 3 Jul 2012 18:44:21 +0000 (+0000) Subject: Add in ST_DistanceTree for testing purposes. Do not document. X-Git-Tag: 2.1.0beta2~838 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=eb21d3f4d0318efa9747b0b31898625f2395a1ed;p=postgis Add in ST_DistanceTree for testing purposes. Do not document. git-svn-id: http://svn.osgeo.org/postgis/trunk@10013 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/postgis/geography.sql.in.c b/postgis/geography.sql.in.c index d257bced2..47e319b85 100644 --- a/postgis/geography.sql.in.c +++ b/postgis/geography.sql.in.c @@ -558,6 +558,17 @@ CREATE OR REPLACE FUNCTION ST_DistanceCached(geography, geography, boolean) AS 'SELECT _ST_DistanceCached($1, $2, 0.0, $3)' LANGUAGE 'sql' IMMUTABLE STRICT; +CREATE OR REPLACE FUNCTION _ST_DistanceTree(geography, geography, float8, boolean) + RETURNS float8 + AS 'MODULE_PATHNAME','geography_distance_tree' + LANGUAGE 'c' IMMUTABLE STRICT + COST 100; + +CREATE OR REPLACE FUNCTION ST_DistanceTree(geography, geography) + RETURNS float8 + AS 'SELECT _ST_DistanceTree($1, $2, 0.0, true)' + LANGUAGE 'sql' IMMUTABLE STRICT; + CREATE OR REPLACE FUNCTION ST_DistanceCached(geography, geography) RETURNS float8 AS 'SELECT _ST_DistanceCached($1, $2, 0.0, true)' diff --git a/postgis/geography_measurement.c b/postgis/geography_measurement.c index dc843ac2b..ae54df620 100644 --- a/postgis/geography_measurement.c +++ b/postgis/geography_measurement.c @@ -29,6 +29,7 @@ Datum geography_distance(PG_FUNCTION_ARGS); Datum geography_distance_cached(PG_FUNCTION_ARGS); +Datum geography_distance_tree(PG_FUNCTION_ARGS); Datum geography_dwithin(PG_FUNCTION_ARGS); Datum geography_dwithin_cached(PG_FUNCTION_ARGS); Datum geography_area(PG_FUNCTION_ARGS); @@ -229,6 +230,73 @@ Datum geography_dwithin_cached(PG_FUNCTION_ARGS) } +/* +** geography_dwithin(GSERIALIZED *g1, GSERIALIZED *g2, double tolerance, boolean use_spheroid) +** returns double distance in meters +*/ +PG_FUNCTION_INFO_V1(geography_distance_tree); +Datum geography_distance_tree(PG_FUNCTION_ARGS) +{ + GSERIALIZED *g1 = NULL; + GSERIALIZED *g2 = NULL; + double tolerance; + double distance; + bool use_spheroid; + SPHEROID s; + CIRC_NODE* circ_tree1 = NULL; + CIRC_NODE* circ_tree2 = NULL; + LWGEOM* lwgeom1 = NULL; + LWGEOM* lwgeom2 = NULL; + + + /* Get our geometry objects loaded into memory. */ + g1 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + g2 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); + + /* Read our tolerance value. */ + tolerance = PG_GETARG_FLOAT8(2); + + /* Read our calculation type. */ + use_spheroid = PG_GETARG_BOOL(3); + + /* Initialize spheroid */ + spheroid_init_from_srid(fcinfo, gserialized_get_srid(g1), &s); + + /* Set to sphere if requested */ + if ( ! use_spheroid ) + s.a = s.b = s.radius; + + /* Return FALSE on empty arguments. */ + if ( gserialized_is_empty(g1) || gserialized_is_empty(g2) ) + { + PG_FREE_IF_COPY(g1, 0); + PG_FREE_IF_COPY(g2, 1); + PG_RETURN_FLOAT8(0.0); + } + + lwgeom1 = lwgeom_from_gserialized(g1); + lwgeom2 = lwgeom_from_gserialized(g2); + circ_tree1 = lwgeom_calculate_circ_tree(lwgeom1); + circ_tree2 = lwgeom_calculate_circ_tree(lwgeom2); + + if ( CircTreePIP(circ_tree1, g1, lwgeom2) || CircTreePIP(circ_tree2, g2, lwgeom1) ) + { + PG_RETURN_BOOL(FALSE); + } + + /* Calculate tree/tree distance */ + distance = circ_tree_distance_tree(circ_tree1, circ_tree2, &s, tolerance); + circ_tree_free(circ_tree1); + circ_tree_free(circ_tree2); + + lwgeom_free(lwgeom1); + lwgeom_free(lwgeom2); + + PG_RETURN_FLOAT8(distance); +} + + + /* ** geography_dwithin(GSERIALIZED *g1, GSERIALIZED *g2, double tolerance, boolean use_spheroid) ** returns double distance in meters diff --git a/postgis/geography_measurement_trees.c b/postgis/geography_measurement_trees.c index bad94e6ed..93b7c706c 100644 --- a/postgis/geography_measurement_trees.c +++ b/postgis/geography_measurement_trees.c @@ -76,8 +76,8 @@ GetCircTreeGeomCache(FunctionCallInfoData* fcinfo, const GSERIALIZED* g1, const return (CircTreeGeomCache*)GetGeomCache(fcinfo, &CircTreeCacheMethods, g1, g2); } -static int -CircTreePIP(const CircTreeGeomCache* tree_cache, const GSERIALIZED* g, const LWGEOM* lwgeom) +int +CircTreePIP(const CIRC_NODE* tree, const GSERIALIZED* g, const LWGEOM* lwgeom) { int tree_type = gserialized_get_type(g); GBOX gbox; @@ -120,7 +120,7 @@ CircTreePIP(const CircTreeGeomCache* tree_cache, const GSERIALIZED* g, const LWG /* Calculate a definitive outside point */ gbox_pt_outside(&gbox, &pt_outside); /* Test the candidate point for strict containment */ - return circ_tree_contains_point(tree_cache->index, &pt_inside, &pt_outside, NULL); + return circ_tree_contains_point(tree, &pt_inside, &pt_outside, NULL); } } @@ -164,7 +164,7 @@ geography_distance_cache(FunctionCallInfoData* fcinfo, const GSERIALIZED* g1, co else lwerror("geography_distance_cache failed! This will never happen!"); - if ( LW_TRUE == CircTreePIP(tree_cache, g, lwgeom) ) + if ( LW_TRUE == CircTreePIP(tree_cache->index, g, lwgeom) ) { *distance = 0.0; lwgeom_free(lwgeom); @@ -220,7 +220,7 @@ geography_dwithin_cache(FunctionCallInfoData* fcinfo, const GSERIALIZED* g1, con else lwerror("geography_dwithin_cache failed! This will never happen!"); - if ( LW_TRUE == CircTreePIP(tree_cache, g, lwgeom) ) + if ( LW_TRUE == CircTreePIP(tree_cache->index, g, lwgeom) ) { *dwithin = LW_TRUE; lwgeom_free(lwgeom); diff --git a/postgis/geography_measurement_trees.h b/postgis/geography_measurement_trees.h index 3c7bc240b..49fb9abf7 100644 --- a/postgis/geography_measurement_trees.h +++ b/postgis/geography_measurement_trees.h @@ -4,3 +4,4 @@ int geography_dwithin_cache(FunctionCallInfoData* fcinfo, const GSERIALIZED* g1, const GSERIALIZED* g2, const SPHEROID* s, double tolerance, int* dwithin); int geography_distance_cache(FunctionCallInfoData* fcinfo, const GSERIALIZED* g1, const GSERIALIZED* g2, const SPHEROID* s, double* distance); +int CircTreePIP(const CIRC_NODE* tree, const GSERIALIZED* g, const LWGEOM* lwgeom);