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)'
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);
}
+/*
+** 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
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;
/* 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);
}
}
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);
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);