]> granicus.if.org Git - postgis/commitdiff
<-> for geography committed with recheck
authorPaul Ramsey <pramsey@cleverelephant.ca>
Thu, 21 May 2015 22:48:40 +0000 (22:48 +0000)
committerPaul Ramsey <pramsey@cleverelephant.ca>
Thu, 21 May 2015 22:48:40 +0000 (22:48 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@13538 b70326c6-7e19-0410-871a-916f4a2858ee

postgis/geography.sql.in
postgis/geography_measurement.c
postgis/gserialized_gist_nd.c

index 3d3dbce0f091e228b16b51563a7552a9d1ffa657..4b867556be3cec1e468a34d361c0e848bff62aee 100644 (file)
@@ -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),
index 0bf47ccc9d83cc46b5050ca1112ad45cbec7477c..1390aef2bf450da8d0fe2c22dc80b2709981cb8e 100644 (file)
@@ -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);
index bda70715d42d5e000d3055404a6a58f06424dcb5..84d26db330d466c47b7e06f0e33c8cf9b6891a19 100644 (file)
@@ -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);