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