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 */
30static double
31point_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 */
62double *
63spg_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
81BOX *
82box_copy(BOX *orig)
83{
84 BOX *result = palloc(sizeof(BOX));
85
86 *result = *orig;
87 return result;
88}
89