PostGIS  2.1.10dev-r@@SVN_REVISION@@
lwgeom_box3d.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * BOX3D IO and conversions
4  *
5  **********************************************************************/
6 
7 #include "postgres.h"
8 #include "fmgr.h"
9 #include "utils/elog.h"
10 #include "utils/geo_decls.h"
11 
12 #include "../postgis_config.h"
13 #include "lwgeom_pg.h"
14 #include "liblwgeom.h"
15 #include "liblwgeom_internal.h"
16 
17 #include <math.h>
18 #include <float.h>
19 #include <string.h>
20 #include <stdio.h>
21 #include <errno.h>
22 
23 #define SHOW_DIGS_DOUBLE 15
24 #define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1)
25 
26 /* forward defs */
27 Datum BOX3D_in(PG_FUNCTION_ARGS);
28 Datum BOX3D_out(PG_FUNCTION_ARGS);
29 Datum LWGEOM_to_BOX3D(PG_FUNCTION_ARGS);
30 Datum BOX3D_to_LWGEOM(PG_FUNCTION_ARGS);
31 Datum BOX3D_expand(PG_FUNCTION_ARGS);
32 Datum BOX3D_to_BOX2D(PG_FUNCTION_ARGS);
33 Datum BOX3D_to_BOX(PG_FUNCTION_ARGS);
34 Datum BOX3D_xmin(PG_FUNCTION_ARGS);
35 Datum BOX3D_ymin(PG_FUNCTION_ARGS);
36 Datum BOX3D_zmin(PG_FUNCTION_ARGS);
37 Datum BOX3D_xmax(PG_FUNCTION_ARGS);
38 Datum BOX3D_ymax(PG_FUNCTION_ARGS);
39 Datum BOX3D_zmax(PG_FUNCTION_ARGS);
40 Datum BOX3D_combine(PG_FUNCTION_ARGS);
41 
53 Datum BOX3D_in(PG_FUNCTION_ARGS)
54 {
55  char *str = PG_GETARG_CSTRING(0);
56  int nitems;
57  BOX3D *box = (BOX3D *) palloc(sizeof(BOX3D));
58  box->zmin = 0;
59  box->zmax = 0;
60 
61 
62  /*printf( "box3d_in gets '%s'\n",str); */
63 
64  if (strstr(str,"BOX3D(") != str )
65  {
66  pfree(box);
67  elog(ERROR,"BOX3D parser - doesnt start with BOX3D(");
68  PG_RETURN_NULL();
69  }
70 
71  nitems = sscanf(str,"BOX3D(%le %le %le ,%le %le %le)",
72  &box->xmin, &box->ymin, &box->zmin,
73  &box->xmax, &box->ymax, &box->zmax);
74  if (nitems != 6 )
75  {
76  nitems = sscanf(str,"BOX3D(%le %le ,%le %le)",
77  &box->xmin, &box->ymin, &box->xmax, &box->ymax);
78  if (nitems != 4)
79  {
80  pfree(box);
81  elog(ERROR,"BOX3D parser - couldnt parse. It should look like: BOX3D(xmin ymin zmin,xmax ymax zmax) or BOX3D(xmin ymin,xmax ymax)");
82  PG_RETURN_NULL();
83  }
84  }
85 
86  if (box->xmin > box->xmax)
87  {
88  float tmp = box->xmin;
89  box->xmin = box->xmax;
90  box->xmax = tmp;
91  }
92  if (box->ymin > box->ymax)
93  {
94  float tmp = box->ymin;
95  box->ymin = box->ymax;
96  box->ymax = tmp;
97  }
98  if (box->zmin > box->zmax)
99  {
100  float tmp = box->zmin;
101  box->zmin = box->zmax;
102  box->zmax = tmp;
103  }
104  box->srid = SRID_UNKNOWN;
105  PG_RETURN_POINTER(box);
106 }
107 
108 
116 Datum BOX3D_out(PG_FUNCTION_ARGS)
117 {
118  BOX3D *bbox = (BOX3D *) PG_GETARG_POINTER(0);
119  int size;
120  char *result;
121 
122  if (bbox == NULL)
123  {
124  result = palloc(5);
125  strcat(result,"NULL");
126  PG_RETURN_CSTRING(result);
127  }
128 
129 
130  /*double digits+ "BOX3D"+ "()" + commas +null */
131  size = MAX_DIGS_DOUBLE*6+5+2+4+5+1;
132 
133  result = (char *) palloc(size);
134 
135  sprintf(result, "BOX3D(%.15g %.15g %.15g,%.15g %.15g %.15g)",
136  bbox->xmin, bbox->ymin, bbox->zmin,
137  bbox->xmax,bbox->ymax,bbox->zmax);
138 
139  PG_RETURN_CSTRING(result);
140 }
141 
142 
144 Datum BOX3D_to_BOX2D(PG_FUNCTION_ARGS)
145 {
146  BOX3D *in = (BOX3D *)PG_GETARG_POINTER(0);
147  GBOX *out = box3d_to_gbox(in);
148  PG_RETURN_POINTER(out);
149 }
150 
151 static void
152 box3d_to_box_p(BOX3D *box, BOX *out)
153 {
154 #if PARANOIA_LEVEL > 0
155  if (box == NULL) return;
156 #endif
157 
158  out->low.x = box->xmin;
159  out->low.y = box->ymin;
160 
161  out->high.x = box->xmax;
162  out->high.y = box->ymax;
163 }
164 
166 Datum BOX3D_to_BOX(PG_FUNCTION_ARGS)
167 {
168  BOX3D *in = (BOX3D *)PG_GETARG_POINTER(0);
169  BOX *box = palloc(sizeof(BOX));
170 
171  box3d_to_box_p(in, box);
172  PG_RETURN_POINTER(box);
173 }
174 
175 
177 Datum BOX3D_to_LWGEOM(PG_FUNCTION_ARGS)
178 {
179  BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
180  POINTARRAY *pa;
182  POINT4D pt;
183 
184 
196  pa = ptarray_construct_empty(0, 0, 5);
197 
198  if ( (box->xmin == box->xmax) && (box->ymin == box->ymax) )
199  {
200  LWPOINT *lwpt = lwpoint_construct(SRID_UNKNOWN, NULL, pa);
201 
202  pt.x = box->xmin;
203  pt.y = box->ymin;
204  ptarray_append_point(pa, &pt, LW_TRUE);
205 
206  result = geometry_serialize(lwpoint_as_lwgeom(lwpt));
207  }
208  else if (box->xmin == box->xmax ||
209  box->ymin == box->ymax)
210  {
211  LWLINE *lwline = lwline_construct(SRID_UNKNOWN, NULL, pa);
212 
213  pt.x = box->xmin;
214  pt.y = box->ymin;
215  ptarray_append_point(pa, &pt, LW_TRUE);
216  pt.x = box->xmax;
217  pt.y = box->ymax;
218  ptarray_append_point(pa, &pt, LW_TRUE);
219 
220  result = geometry_serialize(lwline_as_lwgeom(lwline));
221  }
222  else
223  {
224  LWPOLY *lwpoly = lwpoly_construct(SRID_UNKNOWN, NULL, 1, &pa);
225 
226  pt.x = box->xmin;
227  pt.y = box->ymin;
228  ptarray_append_point(pa, &pt, LW_TRUE);
229  pt.x = box->xmin;
230  pt.y = box->ymax;
231  ptarray_append_point(pa, &pt, LW_TRUE);
232  pt.x = box->xmax;
233  pt.y = box->ymax;
234  ptarray_append_point(pa, &pt, LW_TRUE);
235  pt.x = box->xmax;
236  pt.y = box->ymin;
237  ptarray_append_point(pa, &pt, LW_TRUE);
238  pt.x = box->xmin;
239  pt.y = box->ymin;
240  ptarray_append_point(pa, &pt, LW_TRUE);
241 
242  result = geometry_serialize(lwpoly_as_lwgeom(lwpoly));
243 
244  }
245 
246  gserialized_set_srid(result, box->srid);
247  PG_RETURN_POINTER(result);
248 }
249 
251 void
252 expand_box3d(BOX3D *box, double d)
253 {
254  box->xmin -= d;
255  box->ymin -= d;
256  box->zmin -= d;
257 
258  box->xmax += d;
259  box->ymax += d;
260  box->zmax += d;
261 }
262 
264 Datum BOX3D_expand(PG_FUNCTION_ARGS)
265 {
266  BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
267  double d = PG_GETARG_FLOAT8(1);
268  BOX3D *result = (BOX3D *)palloc(sizeof(BOX3D));
269 
270  memcpy(result, box, sizeof(BOX3D));
271  expand_box3d(result, d);
272 
273  PG_RETURN_POINTER(result);
274 }
275 
284 Datum LWGEOM_to_BOX3D(PG_FUNCTION_ARGS)
285 {
286  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
287  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
288  GBOX gbox;
289  BOX3D *result;
290  int rv = lwgeom_calculate_gbox(lwgeom, &gbox);
291 
292  if ( rv == LW_FAILURE )
293  PG_RETURN_NULL();
294 
295  result = box3d_from_gbox(&gbox);
296  result->srid = lwgeom->srid;
297 
298  lwgeom_free(lwgeom);
299  PG_RETURN_POINTER(result);
300 }
301 
303 Datum BOX3D_xmin(PG_FUNCTION_ARGS)
304 {
305  BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
306  PG_RETURN_FLOAT8(Min(box->xmin, box->xmax));
307 }
308 
310 Datum BOX3D_ymin(PG_FUNCTION_ARGS)
311 {
312  BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
313  PG_RETURN_FLOAT8(Min(box->ymin, box->ymax));
314 }
315 
317 Datum BOX3D_zmin(PG_FUNCTION_ARGS)
318 {
319  BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
320  PG_RETURN_FLOAT8(Min(box->zmin, box->zmax));
321 }
322 
324 Datum BOX3D_xmax(PG_FUNCTION_ARGS)
325 {
326  BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
327  PG_RETURN_FLOAT8(Max(box->xmin, box->xmax));
328 }
329 
331 Datum BOX3D_ymax(PG_FUNCTION_ARGS)
332 {
333  BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
334  PG_RETURN_FLOAT8(Max(box->ymin, box->ymax));
335 }
336 
338 Datum BOX3D_zmax(PG_FUNCTION_ARGS)
339 {
340  BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
341  PG_RETURN_FLOAT8(Max(box->zmin, box->zmax));
342 }
343 
350 Datum BOX3D_combine(PG_FUNCTION_ARGS)
351 {
352  BOX3D *box = (BOX3D*)PG_GETARG_POINTER(0);
353  GSERIALIZED *geom = PG_ARGISNULL(1) ? NULL : (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_POINTER(1));
354  LWGEOM *lwgeom = NULL;
355  BOX3D *result = NULL;
356  GBOX gbox;
357  int32_t srid;
358  int rv;
359 
360  /* Can't do anything with null inputs */
361  if ( (box == NULL) && (geom == NULL) )
362  PG_RETURN_NULL();
363 
364  /* Null geometry but non-null box, return the box */
365  if (geom == NULL)
366  {
367  result = palloc(sizeof(BOX3D));
368  memcpy(result, box, sizeof(BOX3D));
369  PG_RETURN_POINTER(result);
370  }
371 
372  /* Deserialize geometry and *calculate* the box */
373  /* We can't use the cached box because it's float, we *must* calculate */
374  lwgeom = lwgeom_from_gserialized(geom);
375  srid = lwgeom->srid;
376  rv = lwgeom_calculate_gbox(lwgeom, &gbox);
377  lwgeom_free(lwgeom);
378 
379  /* If we couldn't calculate the box, return what we know */
380  if ( rv == LW_FAILURE )
381  {
382  PG_FREE_IF_COPY(geom, 1);
383  /* No geom box, no input box, so null return */
384  if ( box == NULL )
385  PG_RETURN_NULL();
386  result = palloc(sizeof(BOX3D));
387  memcpy(result, box, sizeof(BOX3D));
388  PG_RETURN_POINTER(result);
389  }
390 
391  /* Null box and non-null geometry, just return the geometry box */
392  if ( box == NULL )
393  {
394  PG_FREE_IF_COPY(geom, 1);
395  result = box3d_from_gbox(&gbox);
396  result->srid = srid;
397  PG_RETURN_POINTER(result);
398  }
399 
400  result = palloc(sizeof(BOX3D));
401  result->xmax = Max(box->xmax, gbox.xmax);
402  result->ymax = Max(box->ymax, gbox.ymax);
403  result->zmax = Max(box->zmax, gbox.zmax);
404  result->xmin = Min(box->xmin, gbox.xmin);
405  result->ymin = Min(box->ymin, gbox.ymin);
406  result->zmin = Min(box->zmin, gbox.zmin);
407  result->srid = srid;
408 
409  PG_FREE_IF_COPY(geom, 1);
410  PG_RETURN_POINTER(result);
411 }
412 
414 Datum BOX3D_construct(PG_FUNCTION_ARGS)
415 {
416  GSERIALIZED *min = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
417  GSERIALIZED *max = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
418  BOX3D *result = palloc(sizeof(BOX3D));
419  LWGEOM *minpoint, *maxpoint;
420  POINT3DZ minp, maxp;
421 
422  minpoint = lwgeom_from_gserialized(min);
423  maxpoint = lwgeom_from_gserialized(max);
424 
425  if ( minpoint->type != POINTTYPE ||
426  maxpoint->type != POINTTYPE )
427  {
428  elog(ERROR, "BOX3D_construct: args must be points");
429  PG_RETURN_NULL();
430  }
431 
432  error_if_srid_mismatch(minpoint->srid, maxpoint->srid);
433 
434  getPoint3dz_p(((LWPOINT *)minpoint)->point, 0, &minp);
435  getPoint3dz_p(((LWPOINT *)maxpoint)->point, 0, &maxp);
436 
437  result->xmax = maxp.x;
438  result->ymax = maxp.y;
439  result->zmax = maxp.z;
440 
441  result->xmin = minp.x;
442  result->ymin = minp.y;
443  result->zmin = minp.z;
444 
445  result->srid = minpoint->srid;
446 
447  PG_RETURN_POINTER(result);
448 }
double x
Definition: liblwgeom.h:308
int32_t srid
Definition: liblwgeom.h:235
double z
Definition: liblwgeom.h:290
double y
Definition: liblwgeom.h:290
Datum BOX3D_ymax(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:331
double x
Definition: liblwgeom.h:290
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
void error_if_srid_mismatch(int srid1, int srid2)
Definition: lwutil.c:317
double xmax
Definition: liblwgeom.h:249
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition: ptarray.c:57
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1006
void gserialized_set_srid(GSERIALIZED *s, int32_t srid)
Write the SRID into the serialized form (it is packed into three bytes so this is a handy function)...
Definition: g_serialized.c:87
Datum BOX3D_in(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:53
Datum BOX3D_combine(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:350
double ymin
Definition: liblwgeom.h:233
char ** result
Definition: liblwgeom.h:218
int32_t srid
Definition: liblwgeom.h:355
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:239
Datum BOX3D_out(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:116
Datum BOX3D_construct(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:414
#define LW_FAILURE
Definition: liblwgeom.h:54
Datum BOX3D_zmax(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:338
int lwgeom_calculate_gbox(const LWGEOM *lwgeom, GBOX *gbox)
Calculate bounding box of a geometry, automatically taking into account whether it is cartesian or ge...
Definition: lwgeom.c:608
double ymin
Definition: liblwgeom.h:250
double zmax
Definition: liblwgeom.h:253
int getPoint3dz_p(const POINTARRAY *pa, int n, POINT3DZ *point)
Definition: lwgeom_api.c:305
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:249
double xmin
Definition: liblwgeom.h:248
int ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int allow_duplicates)
Append a point to the end of an existing POINTARRAY If allow_duplicate is LW_TRUE, then a duplicate point will not be added.
Definition: ptarray.c:141
double xmin
Definition: liblwgeom.h:233
Datum BOX3D_to_LWGEOM(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:177
LWPOLY * lwpoly_construct(int srid, GBOX *bbox, uint32_t nrings, POINTARRAY **points)
Definition: lwpoly.c:29
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:51
Datum BOX3D_xmin(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:303
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:29
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:154
void expand_box3d(BOX3D *box, double d)
Expand given box of 'd' units in all directions.
Definition: lwgeom_box3d.c:252
double ymax
Definition: liblwgeom.h:251
Datum BOX3D_to_BOX2D(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:144
#define MAX_DIGS_DOUBLE
Definition: lwgeom_box3d.c:24
PG_FUNCTION_INFO_V1(BOX3D_in)
BOX3D_in - takes a string rep of BOX3D and returns internal rep.
Datum LWGEOM_to_BOX3D(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:284
GBOX * box3d_to_gbox(const BOX3D *b3d)
Definition: g_box.c:74
BOX3D * box3d_from_gbox(const GBOX *gbox)
Definition: g_box.c:47
Datum BOX3D_ymin(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:310
double xmax
Definition: liblwgeom.h:234
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)
double zmin
Definition: liblwgeom.h:252
static void box3d_to_box_p(BOX3D *box, BOX *out)
Definition: lwgeom_box3d.c:152
Datum BOX3D_xmax(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:324
Datum BOX3D_expand(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:264
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:60
uint8_t type
Definition: liblwgeom.h:352
Datum BOX3D_zmin(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:317
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:254
LWPOINT * lwpoint_construct(int srid, GBOX *bbox, POINTARRAY *point)
Definition: lwpoint.c:96
double y
Definition: liblwgeom.h:308
double ymax
Definition: liblwgeom.h:234
Datum BOX3D_to_BOX(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:166
This library is the generic geometry handling section of PostGIS.
double zmax
Definition: liblwgeom.h:234
double zmin
Definition: liblwgeom.h:233