Commit dd580816 authored by Paul Ramsey's avatar Paul Ramsey

<-> for geography committed with recheck


git-svn-id: http://svn.osgeo.org/postgis/[email protected] b70326c6-7e19-0410-871a-916f4a2858ee
parent 238f5698
......@@ -247,6 +247,28 @@ CREATE OPERATOR && (
JOIN = gserialized_gist_joinsel_nd
);
#if POSTGIS_PGSQL_VERSION >= 95
-- Availability: 2.2.0
CREATE OR REPLACE FUNCTION geography_knn_distance(geography, geography)
RETURNS float8
AS 'MODULE_PATHNAME','geography_distance'
LANGUAGE 'c' IMMUTABLE STRICT
COST 100;
-- Availability: 2.2.0
CREATE OPERATOR <-> (
LEFTARG = geography, RIGHTARG = geography, PROCEDURE = geography_knn_distance,
COMMUTATOR = '<->'
);
-- Availability: 2.2.0
CREATE OR REPLACE FUNCTION geography_gist_distance(internal, geography, int4)
RETURNS float8
AS 'MODULE_PATHNAME' ,'gserialized_gist_geog_distance'
LANGUAGE 'c';
#endif
-- Availability: 1.5.0
CREATE OPERATOR CLASS gist_geography_ops
......@@ -256,6 +278,11 @@ CREATE OPERATOR CLASS gist_geography_ops
-- OPERATOR 6 ~= ,
-- OPERATOR 7 ~ ,
-- OPERATOR 8 @ ,
#if POSTGIS_PGSQL_VERSION >= 95
-- Availability: 2.2.0
OPERATOR 13 <-> FOR ORDER BY pg_catalog.float_ops,
FUNCTION 8 geography_gist_distance (internal, geography, int4),
#endif
FUNCTION 1 geography_gist_consistent (internal, geography, int4),
FUNCTION 2 geography_gist_union (bytea, internal),
FUNCTION 3 geography_gist_compress (internal),
......
......@@ -126,8 +126,8 @@ Datum geography_distance(PG_FUNCTION_ARGS)
GSERIALIZED* g1 = NULL;
GSERIALIZED* g2 = NULL;
double distance;
double tolerance;
bool use_spheroid;
double tolerance = 0.0;
bool use_spheroid = true;
SPHEROID s;
/* Get our geometry objects loaded into memory. */
......@@ -135,10 +135,12 @@ Datum geography_distance(PG_FUNCTION_ARGS)
g2 = PG_GETARG_GSERIALIZED_P(1);
/* Read our tolerance value. */
tolerance = PG_GETARG_FLOAT8(2);
if ( ! PG_ARGISNULL(2) )
tolerance = PG_GETARG_FLOAT8(2);
/* Read our calculation type. */
use_spheroid = PG_GETARG_BOOL(3);
if ( ! PG_ARGISNULL(3) )
use_spheroid = PG_GETARG_BOOL(3);
/* Initialize spheroid */
spheroid_init_from_srid(fcinfo, gserialized_get_srid(g1), &s);
......@@ -192,9 +194,9 @@ Datum geography_dwithin(PG_FUNCTION_ARGS)
{
GSERIALIZED *g1 = NULL;
GSERIALIZED *g2 = NULL;
double tolerance;
double tolerance = 0.0;
double distance;
bool use_spheroid;
bool use_spheroid = true;
SPHEROID s;
int dwithin = LW_FALSE;
......@@ -203,10 +205,12 @@ Datum geography_dwithin(PG_FUNCTION_ARGS)
g2 = PG_GETARG_GSERIALIZED_P(1);
/* Read our tolerance value. */
tolerance = PG_GETARG_FLOAT8(2);
if ( ! PG_ARGISNULL(2) )
tolerance = PG_GETARG_FLOAT8(2);
/* Read our calculation type. */
use_spheroid = PG_GETARG_BOOL(3);
if ( ! PG_ARGISNULL(3) )
use_spheroid = PG_GETARG_BOOL(3);
/* Initialize spheroid */
spheroid_init_from_srid(fcinfo, gserialized_get_srid(g1), &s);
......@@ -254,9 +258,9 @@ Datum geography_distance_tree(PG_FUNCTION_ARGS)
{
GSERIALIZED *g1 = NULL;
GSERIALIZED *g2 = NULL;
double tolerance;
double tolerance = 0.0;
double distance;
bool use_spheroid;
bool use_spheroid = true;
SPHEROID s;
/* Get our geometry objects loaded into memory. */
......@@ -272,10 +276,12 @@ Datum geography_distance_tree(PG_FUNCTION_ARGS)
}
/* Read our tolerance value. */
tolerance = PG_GETARG_FLOAT8(2);
if ( ! PG_ARGISNULL(2) )
tolerance = PG_GETARG_FLOAT8(2);
/* Read our calculation type. */
use_spheroid = PG_GETARG_BOOL(3);
if ( ! PG_ARGISNULL(3) )
use_spheroid = PG_GETARG_BOOL(3);
/* Initialize spheroid */
spheroid_init_from_srid(fcinfo, gserialized_get_srid(g1), &s);
......@@ -306,9 +312,9 @@ Datum geography_dwithin_uncached(PG_FUNCTION_ARGS)
LWGEOM *lwgeom2 = NULL;
GSERIALIZED *g1 = NULL;
GSERIALIZED *g2 = NULL;
double tolerance;
double tolerance = 0.0;
double distance;
bool use_spheroid;
bool use_spheroid = true;
SPHEROID s;
/* Get our geometry objects loaded into memory. */
......@@ -316,10 +322,12 @@ Datum geography_dwithin_uncached(PG_FUNCTION_ARGS)
g2 = PG_GETARG_GSERIALIZED_P(1);
/* Read our tolerance value. */
tolerance = PG_GETARG_FLOAT8(2);
if ( ! PG_ARGISNULL(2) )
tolerance = PG_GETARG_FLOAT8(2);
/* Read our calculation type. */
use_spheroid = PG_GETARG_BOOL(3);
if ( ! PG_ARGISNULL(3) )
use_spheroid = PG_GETARG_BOOL(3);
/* Initialize spheroid */
spheroid_init_from_srid(fcinfo, gserialized_get_srid(g1), &s);
......
......@@ -78,6 +78,9 @@ Datum gserialized_gist_picksplit(PG_FUNCTION_ARGS);
Datum gserialized_gist_union(PG_FUNCTION_ARGS);
Datum gserialized_gist_same(PG_FUNCTION_ARGS);
Datum gserialized_gist_distance(PG_FUNCTION_ARGS);
#if POSTGIS_PGSQL_VERSION >= 95
Datum gserialized_gist_geog_distance(PG_FUNCTION_ARGS);
#endif
/*
** ND Operator prototypes
......@@ -549,8 +552,46 @@ static double gidx_distance(const GIDX *a, const GIDX *b)
static double gidx_distance_node_centroid(const GIDX *node, const GIDX *query)
{
/* TODO: implement ! */
return 0;
int i;
double sum = 0;
/* Base computation on least available dimensions */
int ndims = Min(GIDX_NDIMS(node), GIDX_NDIMS(query));
for ( i = 0; i < ndims; ++i )
{
double d;
double amin = GIDX_GET_MIN(query,i);
double amax = GIDX_GET_MAX(query,i);
double bmin = GIDX_GET_MIN(node,i);
double bmax = GIDX_GET_MAX(node,i);
double ca = amin + ( ( amax - amin ) / 2.0 );
if ( ( ca <= bmax && ca >= bmin ) )
{
/* overlaps */
d = 0;
}
else if ( bmax < ca )
{
/* is "left" */
d = ca - bmax;
}
else
{
/* is "right" */
assert( bmin > ca );
d = bmin - ca;
}
if ( ! isfinite(d) )
{
/* Can happen if coordinates are corrupted/NaN */
continue;
}
sum += d * d;
POSTGIS_DEBUGF(3, "dist %g, squared %g, grows sum to %g", d, d*d, sum);
}
return sqrt(sum);
}
/**
......@@ -1005,6 +1046,59 @@ Datum gserialized_gist_same(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(result);
}
#if POSTGIS_PGSQL_VERSION >= 95
PG_FUNCTION_INFO_V1(gserialized_gist_geog_distance);
Datum gserialized_gist_geog_distance(PG_FUNCTION_ARGS)
{
GISTENTRY *entry = (GISTENTRY*) PG_GETARG_POINTER(0);
Datum query_datum = PG_GETARG_DATUM(1);
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
bool *recheck = (bool *) PG_GETARG_POINTER(4);
char query_box_mem[GIDX_MAX_SIZE];
GIDX *query_box = (GIDX*)query_box_mem;
GIDX *entry_box;
double distance;
POSTGIS_DEBUGF(4, "[GIST] '%s' function called", __func__);
/* We are using '13' as the gist geography distance <-> strategy number */
if ( strategy != 13 )
{
elog(ERROR, "unrecognized strategy number: %d", strategy);
PG_RETURN_FLOAT8(FLT_MAX);
}
/* Null box should never make this far. */
if ( gserialized_datum_get_gidx_p(query_datum, query_box) == LW_FAILURE )
{
POSTGIS_DEBUG(4, "[GIST] null query_gbox_index!");
PG_RETURN_FLOAT8(FLT_MAX);
}
/* Get the entry box */
entry_box = (GIDX*)DatumGetPointer(entry->key);
/* Return distances from key-based tests should always be */
/* the minimum possible distance, box-to-box */
/* We scale up to "world units" so that the box-to-box distances */
/* compare reasonably with the over-the-spheroid distances that */
/* the recheck process will turn up */
distance = WGS84_RADIUS * gidx_distance(entry_box, query_box);
/* When we hit leaf nodes, it's time to turn on recheck */
if (GIST_LEAF(entry))
{
*recheck = true;
}
PG_RETURN_FLOAT8(distance);
}
#endif
/*
** GiST support function.
** Take in a query and an entry and return the "distance" between them.
......@@ -1032,7 +1126,7 @@ Datum gserialized_gist_distance(PG_FUNCTION_ARGS)
double distance;
POSTGIS_DEBUG(4, "[GIST] 'distance' function called");
/* We are using '13' as the gist distance-betweeen-centroids strategy number
* and '14' as the gist distance-between-boxes strategy number */
if ( strategy != 13 && strategy != 14 ) {
......@@ -1050,23 +1144,25 @@ Datum gserialized_gist_distance(PG_FUNCTION_ARGS)
/* Get the entry box */
entry_box = (GIDX*)DatumGetPointer(entry->key);
/* Box-style distance test */
/* Box-style distance test <<#>> */
if ( strategy == 14 )
{
distance = gidx_distance(entry_box, query_box);
PG_RETURN_FLOAT8(distance);
}
/* Treat leaf node tests different from internal nodes */
if (GIST_LEAF(entry))
{
/* Calculate distance to leaves */
distance = (double)gidx_distance_leaf_centroid(entry_box, query_box);
}
/* Centroid-style distance test <<->> */
else
{
/* Calculate distance for internal nodes */
distance = (double)gidx_distance_node_centroid(entry_box, query_box);
/* Treat leaf node tests different from internal nodes */
if (GIST_LEAF(entry))
{
/* Calculate distance to leaves */
distance = (double)gidx_distance_leaf_centroid(entry_box, query_box);
}
else
{
/* Calculate distance for internal nodes */
distance = (double)gidx_distance_node_centroid(entry_box, query_box);
}
}
PG_RETURN_FLOAT8(distance);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment