~ubuntu-branches/ubuntu/feisty/postgis/feisty

« back to all changes in this revision

Viewing changes to lwgeom/lwgeom_box3d.c

  • Committer: Bazaar Package Importer
  • Author(s): Alex Bodnaru
  • Date: 2005-05-05 10:02:45 UTC
  • Revision ID: james.westby@ubuntu.com-20050505100245-3005l6jn1jwvpsrw
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**********************************************************************
 
2
 *
 
3
 * BOX3D IO and conversions
 
4
 *
 
5
 **********************************************************************/
 
6
 
 
7
#include <math.h>
 
8
#include <float.h>
 
9
#include <string.h>
 
10
#include <stdio.h>
 
11
#include <errno.h>
 
12
 
 
13
#include "postgres.h"
 
14
#include "fmgr.h"
 
15
#include "utils/elog.h"
 
16
#include "utils/geo_decls.h"
 
17
 
 
18
#include "lwgeom_pg.h"
 
19
#include "liblwgeom.h"
 
20
 
 
21
 
 
22
//#define PGIS_DEBUG
 
23
// basic implementation of BOX2D
 
24
 
 
25
#define SHOW_DIGS_DOUBLE 15
 
26
#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1)
 
27
 
 
28
//forward defs
 
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);
 
43
 
 
44
/*
 
45
 *  BOX3D_in - takes a string rep of BOX3D and returns internal rep
 
46
 *
 
47
 *  example:
 
48
 *     "BOX3D(x1 y1 z1,x2 y2 z2)"
 
49
 * or  "BOX3D(x1 y1,x2 y2)"   z1 and z2 = 0.0
 
50
 *
 
51
 *
 
52
 */
 
53
 
 
54
PG_FUNCTION_INFO_V1(BOX3D_in);
 
55
Datum BOX3D_in(PG_FUNCTION_ARGS)
 
56
{
 
57
        char *str = PG_GETARG_CSTRING(0);
 
58
        int nitems;
 
59
        BOX3D *box = (BOX3D *) palloc(sizeof(BOX3D));
 
60
        box->zmin = 0;
 
61
        box->zmax = 0;
 
62
 
 
63
 
 
64
//printf( "box3d_in gets '%s'\n",str);
 
65
 
 
66
        if (strstr(str,"BOX3D(") !=  str )
 
67
        {
 
68
                 pfree(box);
 
69
                 elog(ERROR,"BOX3D parser - doesnt start with BOX3D(");
 
70
                 PG_RETURN_NULL();
 
71
        }
 
72
 
 
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);
 
76
        if (nitems != 6 )
 
77
        {
 
78
                nitems = sscanf(str,"BOX3D(%le %le,%le %le)",
 
79
                        &box->xmin, &box->ymin, &box->xmax, &box->ymax);
 
80
                if (nitems != 4)
 
81
                {
 
82
                         pfree(box);
 
83
                         elog(ERROR,"BOX3D parser - couldnt parse.  It should look like: BOX3D(xmin ymin zmin,xmax ymax zmax) or BOX3D(xmin ymin,xmax ymax)");
 
84
                         PG_RETURN_NULL();
 
85
                }
 
86
        }
 
87
 
 
88
        if (box->xmin > box->xmax)
 
89
        {
 
90
                float tmp = box->xmin;
 
91
                box->xmin = box->xmax;
 
92
                box->xmax = tmp;
 
93
        }
 
94
        if (box->ymin > box->ymax)
 
95
        {
 
96
                float tmp = box->ymin;
 
97
                box->ymin = box->ymax;
 
98
                box->ymax = tmp;
 
99
        }
 
100
        if (box->zmin > box->zmax)
 
101
        {
 
102
                float tmp = box->zmin;
 
103
                box->zmin = box->zmax;
 
104
                box->zmax = tmp;
 
105
        }
 
106
        PG_RETURN_POINTER(box);
 
107
}
 
108
 
 
109
 
 
110
/*
 
111
 *  Takes an internal rep of a BOX3D and returns a string rep.
 
112
 *
 
113
 *  example:
 
114
 *     "BOX3D(xmin ymin zmin, xmin ymin zmin)"
 
115
 */
 
116
PG_FUNCTION_INFO_V1(BOX3D_out);
 
117
Datum BOX3D_out(PG_FUNCTION_ARGS)
 
118
{
 
119
        BOX3D  *bbox = (BOX3D *) PG_GETARG_POINTER(0);
 
120
        int size;
 
121
        char *result;
 
122
 
 
123
        if (bbox == NULL)
 
124
        {
 
125
                result = palloc(5);
 
126
                strcat(result,"NULL");
 
127
                PG_RETURN_CSTRING(result);
 
128
        }
 
129
 
 
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);
 
135
 
 
136
        PG_RETURN_CSTRING(result);
 
137
}
 
138
 
 
139
PG_FUNCTION_INFO_V1(BOX3D_to_BOX2DFLOAT4);
 
140
Datum BOX3D_to_BOX2DFLOAT4(PG_FUNCTION_ARGS)
 
141
{
 
142
        BOX3D *in = (BOX3D *)PG_GETARG_POINTER(0);
 
143
        BOX2DFLOAT4 *out = box3d_to_box2df(in);
 
144
        PG_RETURN_POINTER(out);
 
145
}
 
146
 
 
147
PG_FUNCTION_INFO_V1(BOX3D_to_BOX);
 
148
Datum BOX3D_to_BOX(PG_FUNCTION_ARGS)
 
149
{
 
150
        BOX3D *in = (BOX3D *)PG_GETARG_POINTER(0);
 
151
        BOX2DFLOAT4 *box2d = box3d_to_box2df(in);
 
152
        BOX *box = palloc(sizeof(BOX));
 
153
 
 
154
        box2df_to_box_p(box2d, box);
 
155
        PG_RETURN_POINTER(box);
 
156
}
 
157
 
 
158
PG_FUNCTION_INFO_V1(BOX3D_to_LWGEOM);
 
159
Datum BOX3D_to_LWGEOM(PG_FUNCTION_ARGS)
 
160
{
 
161
        BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
 
162
        POINT2D *pts = palloc(sizeof(POINT2D)*5);
 
163
        POINTARRAY *pa[1];
 
164
        LWPOLY *poly;
 
165
        int wantbbox = 0;
 
166
        PG_LWGEOM *result;
 
167
        char *ser;
 
168
 
 
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;
 
175
 
 
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);
 
180
        pa[0]->npoints = 5;
 
181
 
 
182
        // Construct polygon
 
183
        poly = lwpoly_construct(-1, NULL, 1, pa);
 
184
 
 
185
        // Serialize polygon
 
186
        ser = lwpoly_serialize(poly);
 
187
 
 
188
        // Construct PG_LWGEOM 
 
189
        result = PG_LWGEOM_construct(ser, -1, wantbbox);
 
190
        
 
191
        PG_RETURN_POINTER(result);
 
192
}
 
193
 
 
194
/* Expand given box of 'd' units in all directions */
 
195
void
 
196
expand_box3d(BOX3D *box, double d)
 
197
{
 
198
        box->xmin -= d;
 
199
        box->ymin -= d;
 
200
        box->zmin -= d;
 
201
 
 
202
        box->xmax += d;
 
203
        box->ymax += d;
 
204
        box->zmax += d;
 
205
}
 
206
 
 
207
PG_FUNCTION_INFO_V1(BOX3D_expand);
 
208
Datum BOX3D_expand(PG_FUNCTION_ARGS)
 
209
{
 
210
        BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
 
211
        double d = PG_GETARG_FLOAT8(1);
 
212
        BOX3D *result = (BOX3D *)palloc(sizeof(BOX3D));
 
213
 
 
214
        memcpy(result, box, sizeof(BOX3D));
 
215
        expand_box3d(result, d);
 
216
 
 
217
        PG_RETURN_POINTER(result);
 
218
}
 
219
 
 
220
/*
 
221
 * convert a PG_LWGEOM to BOX3D
 
222
 *
 
223
 * NOTE: the bounding box is *always* recomputed as the cache
 
224
 * is a box2d, not a box3d...
 
225
 *
 
226
 */
 
227
PG_FUNCTION_INFO_V1(LWGEOM_to_BOX3D);
 
228
Datum LWGEOM_to_BOX3D(PG_FUNCTION_ARGS)
 
229
{
 
230
        PG_LWGEOM *lwgeom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
 
231
        BOX3D *result;
 
232
 
 
233
        result = compute_serialized_box3d(SERIALIZED_FORM(lwgeom));
 
234
        if ( ! result ) PG_RETURN_NULL();
 
235
 
 
236
        PG_RETURN_POINTER(result);
 
237
}
 
238
 
 
239
PG_FUNCTION_INFO_V1(BOX3D_xmin);
 
240
Datum BOX3D_xmin(PG_FUNCTION_ARGS)
 
241
{
 
242
        BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
 
243
        PG_RETURN_FLOAT8(box->xmin);
 
244
}
 
245
 
 
246
PG_FUNCTION_INFO_V1(BOX3D_ymin);
 
247
Datum BOX3D_ymin(PG_FUNCTION_ARGS)
 
248
{
 
249
        BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
 
250
        PG_RETURN_FLOAT8(box->ymin);
 
251
}
 
252
 
 
253
PG_FUNCTION_INFO_V1(BOX3D_zmin);
 
254
Datum BOX3D_zmin(PG_FUNCTION_ARGS)
 
255
{
 
256
        BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
 
257
        PG_RETURN_FLOAT8(box->zmin);
 
258
}
 
259
 
 
260
PG_FUNCTION_INFO_V1(BOX3D_xmax);
 
261
Datum BOX3D_xmax(PG_FUNCTION_ARGS)
 
262
{
 
263
        BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
 
264
        PG_RETURN_FLOAT8(box->xmax);
 
265
}
 
266
 
 
267
PG_FUNCTION_INFO_V1(BOX3D_ymax);
 
268
Datum BOX3D_ymax(PG_FUNCTION_ARGS)
 
269
{
 
270
        BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
 
271
        PG_RETURN_FLOAT8(box->ymax);
 
272
}
 
273
 
 
274
PG_FUNCTION_INFO_V1(BOX3D_zmax);
 
275
Datum BOX3D_zmax(PG_FUNCTION_ARGS)
 
276
{
 
277
        BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
 
278
        PG_RETURN_FLOAT8(box->zmax);
 
279
}
 
280
 
 
281
 
 
282
PG_FUNCTION_INFO_V1(BOX3D_combine);
 
283
Datum BOX3D_combine(PG_FUNCTION_ARGS)
 
284
{
 
285
        Pointer box3d_ptr = PG_GETARG_POINTER(0);
 
286
        Pointer geom_ptr = PG_GETARG_POINTER(1);
 
287
        BOX3D *a,*b;
 
288
        PG_LWGEOM *lwgeom;
 
289
        BOX3D *box, *result;
 
290
 
 
291
        if  ( (box3d_ptr == NULL) && (geom_ptr == NULL) )
 
292
        {
 
293
                PG_RETURN_NULL(); 
 
294
        }
 
295
 
 
296
        result = (BOX3D *)palloc(sizeof(BOX3D));
 
297
 
 
298
        if (box3d_ptr == NULL)
 
299
        {
 
300
                lwgeom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
 
301
                box = compute_serialized_box3d(SERIALIZED_FORM(lwgeom));
 
302
                if ( ! box ) {
 
303
                        PG_FREE_IF_COPY(lwgeom, 1);
 
304
                        PG_RETURN_NULL(); // must be the empty geom
 
305
                }
 
306
                memcpy(result, box, sizeof(BOX3D));
 
307
                PG_RETURN_POINTER(result);
 
308
        }
 
309
 
 
310
        // combine_bbox(BOX3D, null) => BOX3D
 
311
        if (geom_ptr == NULL)
 
312
        {
 
313
                memcpy(result, (char *)PG_GETARG_DATUM(0), sizeof(BOX3D));
 
314
                PG_RETURN_POINTER(result);
 
315
        }
 
316
 
 
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
 
320
        {
 
321
                PG_FREE_IF_COPY(lwgeom, 1);
 
322
                memcpy(result, (char *)PG_GETARG_DATUM(0), sizeof(BOX3D));
 
323
                PG_RETURN_POINTER(result);
 
324
        }
 
325
 
 
326
        a = (BOX3D *)PG_GETARG_DATUM(0);
 
327
        b = box;
 
328
 
 
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);
 
335
 
 
336
        PG_RETURN_POINTER(result);
 
337
}
 
338
 
 
339
PG_FUNCTION_INFO_V1(BOX3D_construct);
 
340
Datum BOX3D_construct(PG_FUNCTION_ARGS)
 
341
{
 
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;
 
346
        POINT3DZ minp, maxp;
 
347
 
 
348
        minpoint = lwgeom_deserialize(SERIALIZED_FORM(min));
 
349
        maxpoint = lwgeom_deserialize(SERIALIZED_FORM(max));
 
350
 
 
351
        if ( TYPE_GETTYPE(minpoint->type) != POINTTYPE ||
 
352
                TYPE_GETTYPE(maxpoint->type) != POINTTYPE )
 
353
        {
 
354
                elog(ERROR, "BOX2DFLOAT4_construct: args must be points");
 
355
                PG_RETURN_NULL();
 
356
        }
 
357
 
 
358
        getPoint3dz_p(((LWPOINT *)minpoint)->point, 0, &minp);
 
359
        getPoint3dz_p(((LWPOINT *)maxpoint)->point, 0, &maxp);
 
360
 
 
361
        result->xmax = maxp.x;
 
362
        result->ymax = maxp.y;
 
363
        result->zmax = maxp.z;
 
364
 
 
365
        result->xmin = minp.x;
 
366
        result->ymin = minp.y;
 
367
        result->zmin = minp.z;
 
368
 
 
369
        PG_RETURN_POINTER(result);
 
370
}
 
371
 
 
372
//min(a,b)
 
373
double
 
374
LWGEOM_Mind(double a, double b)
 
375
{
 
376
        if (a<b)
 
377
                return a;
 
378
        return b;
 
379
}
 
380
 
 
381
//max(a,b)
 
382
double
 
383
LWGEOM_Maxd(double a, double b)
 
384
{
 
385
        if (b>a)
 
386
                return b;
 
387
        return a;
 
388
}
 
389