PostGIS  2.1.10dev-r@@SVN_REVISION@@
geography_btree.c
Go to the documentation of this file.
1 /**********************************************************************
2  * $Id: geography_btree.c 13436 2015-04-23 18:19:47Z pramsey $
3  *
4  * PostGIS - Spatial Types for PostgreSQL
5  * Copyright 2009 Paul Ramsey <pramsey@cleverelephant.ca>
6  *
7  * This is free software; you can redistribute and/or modify it under
8  * the terms of the GNU General Public Licence. See the COPYING file.
9  *
10  **********************************************************************/
11 
12 #include "postgres.h"
13 #include "access/hash.h"
14 
15 #include "../postgis_config.h"
16 
17 #include "liblwgeom.h" /* For standard geometry types. */
18 #include "liblwgeom_internal.h" /* For FP comparators. */
19 #include "lwgeom_pg.h" /* For debugging macros. */
20 #include "gserialized_gist.h"
21 #include "geography.h" /* For utility functions. */
22 
23 Datum geography_lt(PG_FUNCTION_ARGS);
24 Datum geography_le(PG_FUNCTION_ARGS);
25 Datum geography_eq(PG_FUNCTION_ARGS);
26 Datum geography_ge(PG_FUNCTION_ARGS);
27 Datum geography_gt(PG_FUNCTION_ARGS);
28 Datum geography_cmp(PG_FUNCTION_ARGS);
29 
30 
31 /*
32 ** Utility function to return the center point of a
33 ** geocentric bounding box. We don't divide by two
34 ** because we're only using the values for comparison.
35 */
36 static void geography_gidx_center(GIDX *gidx, POINT3D *p)
37 {
38  p->x = GIDX_GET_MIN(gidx, 0) + GIDX_GET_MAX(gidx, 0);
39  p->y = GIDX_GET_MIN(gidx, 1) + GIDX_GET_MAX(gidx, 1);
40  p->z = GIDX_GET_MIN(gidx, 2) + GIDX_GET_MAX(gidx, 2);
41 }
42 
43 /*
44 ** BTree support function. Based on two geographies return true if
45 ** they are "less than" and false otherwise.
46 */
48 Datum geography_lt(PG_FUNCTION_ARGS)
49 {
50  /* Put aside some stack memory and use it for GIDX pointers. */
51  char gboxmem1[GIDX_MAX_SIZE];
52  char gboxmem2[GIDX_MAX_SIZE];
53  GIDX *gbox1 = (GIDX*)gboxmem1;
54  GIDX *gbox2 = (GIDX*)gboxmem2;
55  POINT3D p1, p2;
56 
57  /* Must be able to build box for each argument (ie, not empty geometry) */
58  if ( ! gserialized_datum_get_gidx_p(PG_GETARG_DATUM(0), gbox1) ||
59  ! gserialized_datum_get_gidx_p(PG_GETARG_DATUM(1), gbox2) )
60  {
61  PG_RETURN_BOOL(FALSE);
62  }
63 
64  geography_gidx_center(gbox1, &p1);
65  geography_gidx_center(gbox2, &p2);
66 
67  if ( p1.x < p2.x || p1.y < p2.y || p1.z < p2.z )
68  PG_RETURN_BOOL(TRUE);
69 
70  PG_RETURN_BOOL(FALSE);
71 }
72 
73 /*
74 ** BTree support function. Based on two geographies return true if
75 ** they are "less than or equal" and false otherwise.
76 */
78 Datum geography_le(PG_FUNCTION_ARGS)
79 {
80  /* Put aside some stack memory and use it for GIDX pointers. */
81  char gboxmem1[GIDX_MAX_SIZE];
82  char gboxmem2[GIDX_MAX_SIZE];
83  GIDX *gbox1 = (GIDX*)gboxmem1;
84  GIDX *gbox2 = (GIDX*)gboxmem2;
85  POINT3D p1, p2;
86 
87  /* Must be able to build box for each argument (ie, not empty geometry) */
88  if ( ! gserialized_datum_get_gidx_p(PG_GETARG_DATUM(0), gbox1) ||
89  ! gserialized_datum_get_gidx_p(PG_GETARG_DATUM(1), gbox2) )
90  {
91  PG_RETURN_BOOL(FALSE);
92  }
93 
94  geography_gidx_center(gbox1, &p1);
95  geography_gidx_center(gbox2, &p2);
96 
97  if ( p1.x <= p2.x || p1.y <= p2.y || p1.z <= p2.z )
98  PG_RETURN_BOOL(TRUE);
99 
100  PG_RETURN_BOOL(FALSE);
101 }
102 
103 /*
104 ** BTree support function. Based on two geographies return true if
105 ** they are "greater than" and false otherwise.
106 */
108 Datum geography_gt(PG_FUNCTION_ARGS)
109 {
110  /* Put aside some stack memory and use it for GIDX pointers. */
111  char gboxmem1[GIDX_MAX_SIZE];
112  char gboxmem2[GIDX_MAX_SIZE];
113  GIDX *gbox1 = (GIDX*)gboxmem1;
114  GIDX *gbox2 = (GIDX*)gboxmem2;
115  POINT3D p1, p2;
116 
117  /* Must be able to build box for each argument (ie, not empty geometry) */
118  if ( ! gserialized_datum_get_gidx_p(PG_GETARG_DATUM(0), gbox1) ||
119  ! gserialized_datum_get_gidx_p(PG_GETARG_DATUM(1), gbox2) )
120  {
121  PG_RETURN_BOOL(FALSE);
122  }
123 
124  geography_gidx_center(gbox1, &p1);
125  geography_gidx_center(gbox2, &p2);
126 
127  if ( p1.x > p2.x && p1.y > p2.y && p1.z > p2.z )
128  PG_RETURN_BOOL(TRUE);
129 
130  PG_RETURN_BOOL(FALSE);
131 }
132 
133 /*
134 ** BTree support function. Based on two geographies return true if
135 ** they are "greater than or equal" and false otherwise.
136 */
138 Datum geography_ge(PG_FUNCTION_ARGS)
139 {
140  /* Put aside some stack memory and use it for GIDX pointers. */
141  char gboxmem1[GIDX_MAX_SIZE];
142  char gboxmem2[GIDX_MAX_SIZE];
143  GIDX *gbox1 = (GIDX*)gboxmem1;
144  GIDX *gbox2 = (GIDX*)gboxmem2;
145  POINT3D p1, p2;
146 
147  /* Must be able to build box for each argument (ie, not empty geometry) */
148  if ( ! gserialized_datum_get_gidx_p(PG_GETARG_DATUM(0), gbox1) ||
149  ! gserialized_datum_get_gidx_p(PG_GETARG_DATUM(1), gbox2) )
150  {
151  PG_RETURN_BOOL(FALSE);
152  }
153 
154  geography_gidx_center(gbox1, &p1);
155  geography_gidx_center(gbox2, &p2);
156 
157  if ( p1.x >= p2.x && p1.y >= p2.y && p1.z >= p2.z )
158  PG_RETURN_BOOL(TRUE);
159 
160  PG_RETURN_BOOL(FALSE);
161 }
162 
163 
164 #if 0
165 /*
166 ** Calculate a hash code based on the geometry data alone
167 */
168 static uint32 geography_hash(GSERIALIZED *g)
169 {
170  return DatumGetUInt32(hash_any((void*)g, VARSIZE(g)));
171 }
172 /*
173 ** BTree support function. Based on two geographies return true if
174 ** they are "equal" and false otherwise. This version uses a hash
175 ** function to try and shoot for a more exact equality test.
176 */
178 Datum geography_eq(PG_FUNCTION_ARGS)
179 {
180  /* Perfect equals test based on hash */
181  GSERIALIZED *g1 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
182  GSERIALIZED *g2 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
183 
184  uint32 h1 = geography_hash(g1);
185  uint32 h2 = geography_hash(g2);
186 
187  PG_FREE_IF_COPY(g1,0);
188  PG_FREE_IF_COPY(g2,0);
189 
190  if ( h1 == h2 )
191  PG_RETURN_BOOL(TRUE);
192 
193  PG_RETURN_BOOL(FALSE);
194 }
195 #endif
196 
197 /*
198 ** BTree support function. Based on two geographies return true if
199 ** they are "equal" and false otherwise.
200 */
202 Datum geography_eq(PG_FUNCTION_ARGS)
203 {
204  /* Put aside some stack memory and use it for GIDX pointers. */
205  char gboxmem1[GIDX_MAX_SIZE];
206  char gboxmem2[GIDX_MAX_SIZE];
207  GIDX *gbox1 = (GIDX*)gboxmem1;
208  GIDX *gbox2 = (GIDX*)gboxmem2;
209  POINT3D p1, p2;
210 
211  /* Must be able to build box for each argument (ie, not empty geometry) */
212  if ( ! gserialized_datum_get_gidx_p(PG_GETARG_DATUM(0), gbox1) ||
213  ! gserialized_datum_get_gidx_p(PG_GETARG_DATUM(1), gbox2) )
214  {
215  PG_RETURN_BOOL(FALSE);
216  }
217 
218  geography_gidx_center(gbox1, &p1);
219  geography_gidx_center(gbox2, &p2);
220 
221  if ( FP_EQUALS(p1.x, p2.x) && FP_EQUALS(p1.y, p2.y) && FP_EQUALS(p1.z, p2.z) )
222  PG_RETURN_BOOL(TRUE);
223 
224  PG_RETURN_BOOL(FALSE);
225 
226 }
227 
228 /*
229 ** BTree support function. Based on two geographies return true if
230 ** they are "equal" and false otherwise.
231 */
233 Datum geography_cmp(PG_FUNCTION_ARGS)
234 {
235  /* Put aside some stack memory and use it for GIDX pointers. */
236  char gboxmem1[GIDX_MAX_SIZE];
237  char gboxmem2[GIDX_MAX_SIZE];
238  GIDX *gbox1 = (GIDX*)gboxmem1;
239  GIDX *gbox2 = (GIDX*)gboxmem2;
240  POINT3D p1, p2;
241 
242  /* Must be able to build box for each argument (ie, not empty geometry) */
243  if ( ! gserialized_datum_get_gidx_p(PG_GETARG_DATUM(0), gbox1) ||
244  ! gserialized_datum_get_gidx_p(PG_GETARG_DATUM(1), gbox2) )
245  {
246  PG_RETURN_BOOL(FALSE);
247  }
248 
249  geography_gidx_center(gbox1, &p1);
250  geography_gidx_center(gbox2, &p2);
251 
252  if ( ! FP_EQUALS(p1.x, p2.x) )
253  {
254  if (p1.x < p2.x)
255  {
256  PG_RETURN_INT32(-1);
257  }
258  PG_RETURN_INT32(1);
259  }
260 
261  if ( ! FP_EQUALS(p1.y, p2.y) )
262  {
263  if (p1.y < p2.y)
264  {
265  PG_RETURN_INT32(-1);
266  }
267  PG_RETURN_INT32(1);
268  }
269 
270  if ( ! FP_EQUALS(p1.z, p2.z) )
271  {
272  if (p1.z < p2.z)
273  {
274  PG_RETURN_INT32(-1);
275  }
276  PG_RETURN_INT32(1);
277  }
278 
279  PG_RETURN_INT32(0);
280 }
281 
double y
Definition: liblwgeom.h:296
Datum geography_eq(PG_FUNCTION_ARGS)
Datum geography_gt(PG_FUNCTION_ARGS)
double x
Definition: liblwgeom.h:296
Datum geography_le(PG_FUNCTION_ARGS)
double z
Definition: liblwgeom.h:296
unsigned int uint32
Definition: shpopen.c:274
Datum geography_ge(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(geography_lt)
Datum geography_lt(PG_FUNCTION_ARGS)
static void geography_gidx_center(GIDX *gidx, POINT3D *p)
Datum geography_cmp(PG_FUNCTION_ARGS)
#define FALSE
Definition: dbfopen.c:169
#define FP_EQUALS(A, B)
#define TRUE
Definition: dbfopen.c:170
This library is the generic geometry handling section of PostGIS.