1
/**********************************************************************
3
* BOX3D IO and conversions
5
**********************************************************************/
15
#include "utils/elog.h"
16
#include "utils/geo_decls.h"
18
#include "lwgeom_pg.h"
19
#include "liblwgeom.h"
23
// basic implementation of BOX2D
25
#define SHOW_DIGS_DOUBLE 15
26
#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1)
29
Datum BOX3D_in(PG_FUNCTION_ARGS);
30
Datum BOX3D_out(PG_FUNCTION_ARGS);
31
Datum LWGEOM_to_BOX3D(PG_FUNCTION_ARGS);
32
Datum BOX3D_to_LWGEOM(PG_FUNCTION_ARGS);
33
Datum BOX3D_expand(PG_FUNCTION_ARGS);
34
Datum BOX3D_to_BOX2DFLOAT4(PG_FUNCTION_ARGS);
35
Datum BOX3D_to_BOX(PG_FUNCTION_ARGS);
36
Datum BOX3D_xmin(PG_FUNCTION_ARGS);
37
Datum BOX3D_ymin(PG_FUNCTION_ARGS);
38
Datum BOX3D_zmin(PG_FUNCTION_ARGS);
39
Datum BOX3D_xmax(PG_FUNCTION_ARGS);
40
Datum BOX3D_ymax(PG_FUNCTION_ARGS);
41
Datum BOX3D_zmax(PG_FUNCTION_ARGS);
42
Datum BOX3D_combine(PG_FUNCTION_ARGS);
45
* BOX3D_in - takes a string rep of BOX3D and returns internal rep
48
* "BOX3D(x1 y1 z1,x2 y2 z2)"
49
* or "BOX3D(x1 y1,x2 y2)" z1 and z2 = 0.0
54
PG_FUNCTION_INFO_V1(BOX3D_in);
55
Datum BOX3D_in(PG_FUNCTION_ARGS)
57
char *str = PG_GETARG_CSTRING(0);
59
BOX3D *box = (BOX3D *) palloc(sizeof(BOX3D));
64
//printf( "box3d_in gets '%s'\n",str);
66
if (strstr(str,"BOX3D(") != str )
69
elog(ERROR,"BOX3D parser - doesnt start with BOX3D(");
73
nitems = sscanf(str,"BOX3D(%le %le %le,%le %le %le)",
74
&box->xmin, &box->ymin, &box->zmin,
75
&box->xmax, &box->ymax, &box->zmax);
78
nitems = sscanf(str,"BOX3D(%le %le,%le %le)",
79
&box->xmin, &box->ymin, &box->xmax, &box->ymax);
83
elog(ERROR,"BOX3D parser - couldnt parse. It should look like: BOX3D(xmin ymin zmin,xmax ymax zmax) or BOX3D(xmin ymin,xmax ymax)");
88
if (box->xmin > box->xmax)
90
float tmp = box->xmin;
91
box->xmin = box->xmax;
94
if (box->ymin > box->ymax)
96
float tmp = box->ymin;
97
box->ymin = box->ymax;
100
if (box->zmin > box->zmax)
102
float tmp = box->zmin;
103
box->zmin = box->zmax;
106
PG_RETURN_POINTER(box);
111
* Takes an internal rep of a BOX3D and returns a string rep.
114
* "BOX3D(xmin ymin zmin, xmin ymin zmin)"
116
PG_FUNCTION_INFO_V1(BOX3D_out);
117
Datum BOX3D_out(PG_FUNCTION_ARGS)
119
BOX3D *bbox = (BOX3D *) PG_GETARG_POINTER(0);
126
strcat(result,"NULL");
127
PG_RETURN_CSTRING(result);
130
size = MAX_DIGS_DOUBLE*6+5+2+4+5+1;
131
result = (char *) palloc(size); //double digits+ "BOX3D"+ "()" + commas +null
132
sprintf(result, "BOX3D(%.15g %.15g %.15g,%.15g %.15g %.15g)",
133
bbox->xmin, bbox->ymin, bbox->zmin,
134
bbox->xmax,bbox->ymax,bbox->zmax);
136
PG_RETURN_CSTRING(result);
139
PG_FUNCTION_INFO_V1(BOX3D_to_BOX2DFLOAT4);
140
Datum BOX3D_to_BOX2DFLOAT4(PG_FUNCTION_ARGS)
142
BOX3D *in = (BOX3D *)PG_GETARG_POINTER(0);
143
BOX2DFLOAT4 *out = box3d_to_box2df(in);
144
PG_RETURN_POINTER(out);
147
PG_FUNCTION_INFO_V1(BOX3D_to_BOX);
148
Datum BOX3D_to_BOX(PG_FUNCTION_ARGS)
150
BOX3D *in = (BOX3D *)PG_GETARG_POINTER(0);
151
BOX2DFLOAT4 *box2d = box3d_to_box2df(in);
152
BOX *box = palloc(sizeof(BOX));
154
box2df_to_box_p(box2d, box);
155
PG_RETURN_POINTER(box);
158
PG_FUNCTION_INFO_V1(BOX3D_to_LWGEOM);
159
Datum BOX3D_to_LWGEOM(PG_FUNCTION_ARGS)
161
BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
162
POINT2D *pts = palloc(sizeof(POINT2D)*5);
169
// Assign coordinates to POINT2D array
170
pts[0].x = box->xmin; pts[0].y = box->ymin;
171
pts[1].x = box->xmin; pts[1].y = box->ymax;
172
pts[2].x = box->xmax; pts[2].y = box->ymax;
173
pts[3].x = box->xmax; pts[3].y = box->ymin;
174
pts[4].x = box->xmin; pts[4].y = box->ymin;
176
// Construct point array
177
pa[0] = palloc(sizeof(POINTARRAY));
178
pa[0]->serialized_pointlist = (char *)pts;
179
TYPE_SETZM(pa[0]->dims, 0, 0);
183
poly = lwpoly_construct(-1, NULL, 1, pa);
186
ser = lwpoly_serialize(poly);
188
// Construct PG_LWGEOM
189
result = PG_LWGEOM_construct(ser, -1, wantbbox);
191
PG_RETURN_POINTER(result);
194
/* Expand given box of 'd' units in all directions */
196
expand_box3d(BOX3D *box, double d)
207
PG_FUNCTION_INFO_V1(BOX3D_expand);
208
Datum BOX3D_expand(PG_FUNCTION_ARGS)
210
BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
211
double d = PG_GETARG_FLOAT8(1);
212
BOX3D *result = (BOX3D *)palloc(sizeof(BOX3D));
214
memcpy(result, box, sizeof(BOX3D));
215
expand_box3d(result, d);
217
PG_RETURN_POINTER(result);
221
* convert a PG_LWGEOM to BOX3D
223
* NOTE: the bounding box is *always* recomputed as the cache
224
* is a box2d, not a box3d...
227
PG_FUNCTION_INFO_V1(LWGEOM_to_BOX3D);
228
Datum LWGEOM_to_BOX3D(PG_FUNCTION_ARGS)
230
PG_LWGEOM *lwgeom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
233
result = compute_serialized_box3d(SERIALIZED_FORM(lwgeom));
234
if ( ! result ) PG_RETURN_NULL();
236
PG_RETURN_POINTER(result);
239
PG_FUNCTION_INFO_V1(BOX3D_xmin);
240
Datum BOX3D_xmin(PG_FUNCTION_ARGS)
242
BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
243
PG_RETURN_FLOAT8(box->xmin);
246
PG_FUNCTION_INFO_V1(BOX3D_ymin);
247
Datum BOX3D_ymin(PG_FUNCTION_ARGS)
249
BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
250
PG_RETURN_FLOAT8(box->ymin);
253
PG_FUNCTION_INFO_V1(BOX3D_zmin);
254
Datum BOX3D_zmin(PG_FUNCTION_ARGS)
256
BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
257
PG_RETURN_FLOAT8(box->zmin);
260
PG_FUNCTION_INFO_V1(BOX3D_xmax);
261
Datum BOX3D_xmax(PG_FUNCTION_ARGS)
263
BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
264
PG_RETURN_FLOAT8(box->xmax);
267
PG_FUNCTION_INFO_V1(BOX3D_ymax);
268
Datum BOX3D_ymax(PG_FUNCTION_ARGS)
270
BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
271
PG_RETURN_FLOAT8(box->ymax);
274
PG_FUNCTION_INFO_V1(BOX3D_zmax);
275
Datum BOX3D_zmax(PG_FUNCTION_ARGS)
277
BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
278
PG_RETURN_FLOAT8(box->zmax);
282
PG_FUNCTION_INFO_V1(BOX3D_combine);
283
Datum BOX3D_combine(PG_FUNCTION_ARGS)
285
Pointer box3d_ptr = PG_GETARG_POINTER(0);
286
Pointer geom_ptr = PG_GETARG_POINTER(1);
291
if ( (box3d_ptr == NULL) && (geom_ptr == NULL) )
296
result = (BOX3D *)palloc(sizeof(BOX3D));
298
if (box3d_ptr == NULL)
300
lwgeom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
301
box = compute_serialized_box3d(SERIALIZED_FORM(lwgeom));
303
PG_FREE_IF_COPY(lwgeom, 1);
304
PG_RETURN_NULL(); // must be the empty geom
306
memcpy(result, box, sizeof(BOX3D));
307
PG_RETURN_POINTER(result);
310
// combine_bbox(BOX3D, null) => BOX3D
311
if (geom_ptr == NULL)
313
memcpy(result, (char *)PG_GETARG_DATUM(0), sizeof(BOX3D));
314
PG_RETURN_POINTER(result);
317
lwgeom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
318
box = compute_serialized_box3d(SERIALIZED_FORM(lwgeom));
319
if ( ! box ) // must be the empty geom
321
PG_FREE_IF_COPY(lwgeom, 1);
322
memcpy(result, (char *)PG_GETARG_DATUM(0), sizeof(BOX3D));
323
PG_RETURN_POINTER(result);
326
a = (BOX3D *)PG_GETARG_DATUM(0);
329
result->xmax = LWGEOM_Maxd(a->xmax, b->xmax);
330
result->ymax = LWGEOM_Maxd(a->ymax, b->ymax);
331
result->zmax = LWGEOM_Maxd(a->zmax, b->zmax);
332
result->xmin = LWGEOM_Mind(a->xmin, b->xmin);
333
result->ymin = LWGEOM_Mind(a->ymin, b->ymin);
334
result->zmin = LWGEOM_Mind(a->zmin, b->zmin);
336
PG_RETURN_POINTER(result);
339
PG_FUNCTION_INFO_V1(BOX3D_construct);
340
Datum BOX3D_construct(PG_FUNCTION_ARGS)
342
PG_LWGEOM *min = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
343
PG_LWGEOM *max = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
344
BOX3D *result = palloc(sizeof(BOX3D));
345
LWGEOM *minpoint, *maxpoint;
348
minpoint = lwgeom_deserialize(SERIALIZED_FORM(min));
349
maxpoint = lwgeom_deserialize(SERIALIZED_FORM(max));
351
if ( TYPE_GETTYPE(minpoint->type) != POINTTYPE ||
352
TYPE_GETTYPE(maxpoint->type) != POINTTYPE )
354
elog(ERROR, "BOX2DFLOAT4_construct: args must be points");
358
getPoint3dz_p(((LWPOINT *)minpoint)->point, 0, &minp);
359
getPoint3dz_p(((LWPOINT *)maxpoint)->point, 0, &maxp);
361
result->xmax = maxp.x;
362
result->ymax = maxp.y;
363
result->zmax = maxp.z;
365
result->xmin = minp.x;
366
result->ymin = minp.y;
367
result->zmin = minp.z;
369
PG_RETURN_POINTER(result);
374
LWGEOM_Mind(double a, double b)
383
LWGEOM_Maxd(double a, double b)