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