| 1 | /*------------------------------------------------------------------------- |
| 2 | * |
| 3 | * spgproc.c |
| 4 | * Common supporting procedures for SP-GiST opclasses. |
| 5 | * |
| 6 | * |
| 7 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
| 8 | * Portions Copyright (c) 1994, Regents of the University of California |
| 9 | * |
| 10 | * IDENTIFICATION |
| 11 | * src/backend/access/spgist/spgproc.c |
| 12 | * |
| 13 | *------------------------------------------------------------------------- |
| 14 | */ |
| 15 | |
| 16 | #include "postgres.h" |
| 17 | |
| 18 | #include <math.h> |
| 19 | |
| 20 | #include "access/spgist_private.h" |
| 21 | #include "utils/builtins.h" |
| 22 | #include "utils/float.h" |
| 23 | #include "utils/geo_decls.h" |
| 24 | |
| 25 | #define point_point_distance(p1,p2) \ |
| 26 | DatumGetFloat8(DirectFunctionCall2(point_distance, \ |
| 27 | PointPGetDatum(p1), PointPGetDatum(p2))) |
| 28 | |
| 29 | /* Point-box distance in the assumption that box is aligned by axis */ |
| 30 | static double |
| 31 | point_box_distance(Point *point, BOX *box) |
| 32 | { |
| 33 | double dx, |
| 34 | dy; |
| 35 | |
| 36 | if (isnan(point->x) || isnan(box->low.x) || |
| 37 | isnan(point->y) || isnan(box->low.y)) |
| 38 | return get_float8_nan(); |
| 39 | |
| 40 | if (point->x < box->low.x) |
| 41 | dx = box->low.x - point->x; |
| 42 | else if (point->x > box->high.x) |
| 43 | dx = point->x - box->high.x; |
| 44 | else |
| 45 | dx = 0.0; |
| 46 | |
| 47 | if (point->y < box->low.y) |
| 48 | dy = box->low.y - point->y; |
| 49 | else if (point->y > box->high.y) |
| 50 | dy = point->y - box->high.y; |
| 51 | else |
| 52 | dy = 0.0; |
| 53 | |
| 54 | return HYPOT(dx, dy); |
| 55 | } |
| 56 | |
| 57 | /* |
| 58 | * Returns distances from given key to array of ordering scan keys. Leaf key |
| 59 | * is expected to be point, non-leaf key is expected to be box. Scan key |
| 60 | * arguments are expected to be points. |
| 61 | */ |
| 62 | double * |
| 63 | spg_key_orderbys_distances(Datum key, bool isLeaf, |
| 64 | ScanKey orderbys, int norderbys) |
| 65 | { |
| 66 | int sk_num; |
| 67 | double *distances = (double *) palloc(norderbys * sizeof(double)), |
| 68 | *distance = distances; |
| 69 | |
| 70 | for (sk_num = 0; sk_num < norderbys; ++sk_num, ++orderbys, ++distance) |
| 71 | { |
| 72 | Point *point = DatumGetPointP(orderbys->sk_argument); |
| 73 | |
| 74 | *distance = isLeaf ? point_point_distance(point, DatumGetPointP(key)) |
| 75 | : point_box_distance(point, DatumGetBoxP(key)); |
| 76 | } |
| 77 | |
| 78 | return distances; |
| 79 | } |
| 80 | |
| 81 | BOX * |
| 82 | box_copy(BOX *orig) |
| 83 | { |
| 84 | BOX *result = palloc(sizeof(BOX)); |
| 85 | |
| 86 | *result = *orig; |
| 87 | return result; |
| 88 | } |
| 89 | |