diff options
Diffstat (limited to 'src/backend/utils/adt/geo_spgist.c')
-rw-r--r-- | src/backend/utils/adt/geo_spgist.c | 97 |
1 files changed, 88 insertions, 9 deletions
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c index f9e8db63ddc..e52d80f5e13 100644 --- a/src/backend/utils/adt/geo_spgist.c +++ b/src/backend/utils/adt/geo_spgist.c @@ -74,9 +74,11 @@ #include "postgres.h" #include "access/spgist.h" +#include "access/spgist_private.h" #include "access/stratnum.h" #include "catalog/pg_type.h" #include "utils/float.h" +#include "utils/fmgroids.h" #include "utils/fmgrprotos.h" #include "utils/geo_decls.h" @@ -367,6 +369,31 @@ overAbove4D(RectBox *rect_box, RangeBox *query) return overHigher2D(&rect_box->range_box_y, &query->right); } +/* Lower bound for the distance between point and rect_box */ +static double +pointToRectBoxDistance(Point *point, RectBox *rect_box) +{ + double dx; + double dy; + + if (point->x < rect_box->range_box_x.left.low) + dx = rect_box->range_box_x.left.low - point->x; + else if (point->x > rect_box->range_box_x.right.high) + dx = point->x - rect_box->range_box_x.right.high; + else + dx = 0; + + if (point->y < rect_box->range_box_y.left.low) + dy = rect_box->range_box_y.left.low - point->y; + else if (point->y > rect_box->range_box_y.right.high) + dy = point->y - rect_box->range_box_y.right.high; + else + dy = 0; + + return HYPOT(dx, dy); +} + + /* * SP-GiST config function */ @@ -534,6 +561,15 @@ spg_box_quad_inner_consistent(PG_FUNCTION_ARGS) RangeBox *centroid, **queries; + /* + * We are saving the traversal value or initialize it an unbounded one, if + * we have just begun to walk the tree. + */ + if (in->traversalValue) + rect_box = in->traversalValue; + else + rect_box = initRectBox(); + if (in->allTheSame) { /* Report that all nodes should be visited */ @@ -542,19 +578,33 @@ spg_box_quad_inner_consistent(PG_FUNCTION_ARGS) for (i = 0; i < in->nNodes; i++) out->nodeNumbers[i] = i; + if (in->norderbys > 0 && in->nNodes > 0) + { + double *distances = palloc(sizeof(double) * in->norderbys); + int j; + + for (j = 0; j < in->norderbys; j++) + { + Point *pt = DatumGetPointP(in->orderbys[j].sk_argument); + + distances[j] = pointToRectBoxDistance(pt, rect_box); + } + + out->distances = (double **) palloc(sizeof(double *) * in->nNodes); + out->distances[0] = distances; + + for (i = 1; i < in->nNodes; i++) + { + out->distances[i] = palloc(sizeof(double) * in->norderbys); + memcpy(out->distances[i], distances, + sizeof(double) * in->norderbys); + } + } + PG_RETURN_VOID(); } /* - * We are saving the traversal value or initialize it an unbounded one, if - * we have just begun to walk the tree. - */ - if (in->traversalValue) - rect_box = in->traversalValue; - else - rect_box = initRectBox(); - - /* * We are casting the prefix and queries to RangeBoxes for ease of the * following operations. */ @@ -571,6 +621,8 @@ spg_box_quad_inner_consistent(PG_FUNCTION_ARGS) out->nNodes = 0; out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes); out->traversalValues = (void **) palloc(sizeof(void *) * in->nNodes); + if (in->norderbys > 0) + out->distances = (double **) palloc(sizeof(double *) * in->nNodes); /* * We switch memory context, because we want to allocate memory for new @@ -648,6 +700,22 @@ spg_box_quad_inner_consistent(PG_FUNCTION_ARGS) { out->traversalValues[out->nNodes] = next_rect_box; out->nodeNumbers[out->nNodes] = quadrant; + + if (in->norderbys > 0) + { + double *distances = palloc(sizeof(double) * in->norderbys); + int j; + + out->distances[out->nNodes] = distances; + + for (j = 0; j < in->norderbys; j++) + { + Point *pt = DatumGetPointP(in->orderbys[j].sk_argument); + + distances[j] = pointToRectBoxDistance(pt, next_rect_box); + } + } + out->nNodes++; } else @@ -763,6 +831,17 @@ spg_box_quad_leaf_consistent(PG_FUNCTION_ARGS) break; } + if (flag && in->norderbys > 0) + { + Oid distfnoid = in->orderbys[0].sk_func.fn_oid; + + out->distances = spg_key_orderbys_distances(leaf, false, + in->orderbys, in->norderbys); + + /* Recheck is necessary when computing distance to polygon */ + out->recheckDistances = distfnoid == F_DIST_POLYP; + } + PG_RETURN_BOOL(flag); } |