1
/**********************************************************************
2
* $Id: lwgeom.c 3272 2008-11-07 13:18:11Z mcayland $
4
* PostGIS - Spatial Types for PostgreSQL
5
* http://postgis.refractions.net
6
* Copyright 2001-2006 Refractions Research Inc.
8
* This is free software; you can redistribute and/or modify it under
9
* the terms of the GNU General Public Licence. See the COPYING file.
11
**********************************************************************/
17
/*#include "lwgeom_pg.h"*/
18
#include "liblwgeom.h"
21
/*#define PGIS_DEBUG_CALLS 1*/
22
/*#define PGIS_DEBUG 1*/
25
lwgeom_deserialize(uchar *srl)
27
int type = lwgeom_getType(srl[0]);
29
#ifdef PGIS_DEBUG_CALLS
30
lwnotice("lwgeom_deserialize got %d - %s", type, lwgeom_typename(type));
36
return (LWGEOM *)lwpoint_deserialize(srl);
38
return (LWGEOM *)lwline_deserialize(srl);
40
return (LWGEOM *)lwcurve_deserialize(srl);
42
return (LWGEOM *)lwpoly_deserialize(srl);
44
return (LWGEOM *)lwmpoint_deserialize(srl);
46
return (LWGEOM *)lwmline_deserialize(srl);
47
case MULTIPOLYGONTYPE:
48
return (LWGEOM *)lwmpoly_deserialize(srl);
50
return (LWGEOM *)lwcollection_deserialize(srl);
52
return (LWGEOM *)lwcompound_deserialize(srl);
54
return (LWGEOM *)lwcurvepoly_deserialize(srl);
56
return (LWGEOM *)lwmcurve_deserialize(srl);
57
case MULTISURFACETYPE:
58
return (LWGEOM *)lwmsurface_deserialize(srl);
61
lwerror("lwgeom_deserialize: Unknown geometry type: %d", type);
63
lwerror("Unknown geometry type: %d", type);
71
lwgeom_serialize_size(LWGEOM *lwgeom)
73
int type = TYPE_GETTYPE(lwgeom->type);
75
#ifdef PGIS_DEBUG_CALLS
76
lwnotice("lwgeom_serialize_size(%s) called", lwgeom_typename(type));
82
return lwpoint_serialize_size((LWPOINT *)lwgeom);
84
return lwline_serialize_size((LWLINE *)lwgeom);
86
return lwpoly_serialize_size((LWPOLY *)lwgeom);
88
return lwcurve_serialize_size((LWCURVE *)lwgeom);
94
case MULTIPOLYGONTYPE:
95
case MULTISURFACETYPE:
97
return lwcollection_serialize_size((LWCOLLECTION *)lwgeom);
100
lwerror("lwgeom_serialize_size: Unknown geometry type: %d", type);
102
lwerror("Unknown geometry type: %d", type);
109
lwgeom_serialize_buf(LWGEOM *lwgeom, uchar *buf, size_t *retsize)
111
int type = TYPE_GETTYPE(lwgeom->type);
113
#ifdef PGIS_DEBUG_CALLS
114
lwnotice("lwgeom_serialize_buf called with a %s",
115
lwgeom_typename(type));
120
lwpoint_serialize_buf((LWPOINT *)lwgeom, buf, retsize);
123
lwline_serialize_buf((LWLINE *)lwgeom, buf, retsize);
126
lwpoly_serialize_buf((LWPOLY *)lwgeom, buf, retsize);
129
lwcurve_serialize_buf((LWCURVE *)lwgeom, buf, retsize);
136
case MULTIPOLYGONTYPE:
137
case MULTISURFACETYPE:
139
lwcollection_serialize_buf((LWCOLLECTION *)lwgeom, buf,
144
lwerror("lwgeom_serialize_buf: Unknown geometry type: %d", type);
146
lwerror("Unknown geometry type: %d", type);
154
lwgeom_serialize(LWGEOM *lwgeom)
156
size_t size = lwgeom_serialize_size(lwgeom);
158
uchar *serialized = lwalloc(size);
160
lwgeom_serialize_buf(lwgeom, serialized, &retsize);
163
if ( retsize != size )
165
lwerror("lwgeom_serialize: computed size %d, returned size %d",
173
/* Force Right-hand-rule on LWGEOM polygons */
175
lwgeom_forceRHR(LWGEOM *lwgeom)
180
switch (TYPE_GETTYPE(lwgeom->type))
183
lwpoly_forceRHR((LWPOLY *)lwgeom);
186
case MULTIPOLYGONTYPE:
188
coll = (LWCOLLECTION *)lwgeom;
189
for (i=0; i<coll->ngeoms; i++)
190
lwgeom_forceRHR(coll->geoms[i]);
195
/* Reverse vertex order of LWGEOM */
197
lwgeom_reverse(LWGEOM *lwgeom)
202
switch (TYPE_GETTYPE(lwgeom->type))
205
lwline_reverse((LWLINE *)lwgeom);
208
lwpoly_reverse((LWPOLY *)lwgeom);
211
case MULTIPOLYGONTYPE:
213
col = (LWCOLLECTION *)lwgeom;
214
for (i=0; i<col->ngeoms; i++)
215
lwgeom_reverse(col->geoms[i]);
221
lwgeom_compute_box2d_p(LWGEOM *lwgeom, BOX2DFLOAT4 *buf)
223
#ifdef PGIS_DEBUG_CALLS
224
lwnotice("lwgeom_compute_box2d_p called of %p of type %d.", lwgeom, TYPE_GETTYPE(lwgeom->type));
226
switch(TYPE_GETTYPE(lwgeom->type))
229
return lwpoint_compute_box2d_p((LWPOINT *)lwgeom, buf);
231
return lwline_compute_box2d_p((LWLINE *)lwgeom, buf);
233
return lwcurve_compute_box2d_p((LWCURVE *)lwgeom, buf);
235
return lwpoly_compute_box2d_p((LWPOLY *)lwgeom, buf);
241
case MULTIPOLYGONTYPE:
242
case MULTISURFACETYPE:
244
return lwcollection_compute_box2d_p((LWCOLLECTION *)lwgeom, buf);
250
* dont forget to lwfree() result
253
lwgeom_compute_box2d(LWGEOM *lwgeom)
255
BOX2DFLOAT4 *result = lwalloc(sizeof(BOX2DFLOAT4));
256
if ( lwgeom_compute_box2d_p(lwgeom, result) ) return result;
264
lwgeom_as_lwpoint(LWGEOM *lwgeom)
266
if ( TYPE_GETTYPE(lwgeom->type) == POINTTYPE )
267
return (LWPOINT *)lwgeom;
272
lwgeom_as_lwline(LWGEOM *lwgeom)
274
if ( TYPE_GETTYPE(lwgeom->type) == LINETYPE )
275
return (LWLINE *)lwgeom;
280
lwgeom_as_lwcurve(LWGEOM *lwgeom)
282
if( TYPE_GETTYPE(lwgeom->type) == CURVETYPE )
283
return (LWCURVE *)lwgeom;
288
lwgeom_as_lwpoly(LWGEOM *lwgeom)
290
if ( TYPE_GETTYPE(lwgeom->type) == POLYGONTYPE )
291
return (LWPOLY *)lwgeom;
296
lwgeom_as_lwcollection(LWGEOM *lwgeom)
298
if ( TYPE_GETTYPE(lwgeom->type) >= MULTIPOINTTYPE
299
&& TYPE_GETTYPE(lwgeom->type) <= COLLECTIONTYPE)
300
return (LWCOLLECTION *)lwgeom;
305
lwgeom_as_lwmpoint(LWGEOM *lwgeom)
307
if ( TYPE_GETTYPE(lwgeom->type) == MULTIPOINTTYPE )
308
return (LWMPOINT *)lwgeom;
313
lwgeom_as_lwmline(LWGEOM *lwgeom)
315
if ( TYPE_GETTYPE(lwgeom->type) == MULTILINETYPE )
316
return (LWMLINE *)lwgeom;
321
lwgeom_as_lwmpoly(LWGEOM *lwgeom)
323
if ( TYPE_GETTYPE(lwgeom->type) == MULTIPOLYGONTYPE )
324
return (LWMPOLY *)lwgeom;
328
LWGEOM *lwmpoly_as_lwgeom(LWMPOLY *obj) { return (LWGEOM *)obj; }
329
LWGEOM *lwmline_as_lwgeom(LWMLINE *obj) { return (LWGEOM *)obj; }
330
LWGEOM *lwmpoint_as_lwgeom(LWMPOINT *obj) { return (LWGEOM *)obj; }
331
LWGEOM *lwcollection_as_lwgeom(LWCOLLECTION *obj) { return (LWGEOM *)obj; }
332
LWGEOM *lwpoly_as_lwgeom(LWPOLY *obj) { return (LWGEOM *)obj; }
333
LWGEOM *lwline_as_lwgeom(LWLINE *obj) { return (LWGEOM *)obj; }
334
LWGEOM *lwpoint_as_lwgeom(LWPOINT *obj) { return (LWGEOM *)obj; }
337
lwgeom_release(LWGEOM *lwgeom)
342
#ifdef INTEGRITY_CHECKS
344
lwerror("lwgeom_release: someone called on 0x0");
347
/* Drop bounding box (always a copy) */
348
if ( lwgeom->bbox ) {
350
lwnotice("lwgeom_release: releasing bbox.");
352
lwfree(lwgeom->bbox);
356
if ( (col=lwgeom_as_lwcollection(lwgeom)) )
360
lwnotice("lwgeom_release: Releasing collection.");
363
for (i=0; i<col->ngeoms; i++)
365
lwgeom_release(col->geoms[i]);
375
/* Clone an LWGEOM object. POINTARRAY are not copied. */
377
lwgeom_clone(const LWGEOM *lwgeom)
379
#ifdef PGIS_DEBUG_CALLS
380
lwnotice("lwgeom_clone called with %p, %d", lwgeom, TYPE_GETTYPE(lwgeom->type));
382
switch(TYPE_GETTYPE(lwgeom->type))
385
return (LWGEOM *)lwpoint_clone((LWPOINT *)lwgeom);
387
return (LWGEOM *)lwline_clone((LWLINE *)lwgeom);
389
return (LWGEOM *)lwcurve_clone((LWCURVE *)lwgeom);
391
return (LWGEOM *)lwpoly_clone((LWPOLY *)lwgeom);
397
case MULTIPOLYGONTYPE:
398
case MULTISURFACETYPE:
400
return (LWGEOM *)lwcollection_clone((LWCOLLECTION *)lwgeom);
407
* Add 'what' to 'to' at position 'where'
411
* Appended-to LWGEOM gets a new type based on new condition.
412
* Mix of dimensions is not allowed (TODO: allow it?).
415
lwgeom_add(const LWGEOM *to, uint32 where, const LWGEOM *what)
417
if ( TYPE_NDIMS(what->type) != TYPE_NDIMS(to->type) )
419
lwerror("lwgeom_add: mixed dimensions not supported");
423
#ifdef PGIS_DEBUG_CALLS
424
lwnotice("lwgeom_add(%s, %d, %s) called",
425
lwgeom_typename(TYPE_GETTYPE(to->type)),
427
lwgeom_typename(TYPE_GETTYPE(what->type)));
430
switch(TYPE_GETTYPE(to->type))
433
return (LWGEOM *)lwpoint_add((const LWPOINT *)to, where, what);
435
return (LWGEOM *)lwline_add((const LWLINE *)to, where, what);
438
return (LWGEOM *)lwcurve_add((const LWCURVE *)to, where, what);
441
return (LWGEOM *)lwpoly_add((const LWPOLY *)to, where, what);
444
return (LWGEOM *)lwcompound_add((const LWCOMPOUND *)to, where, what);
447
return (LWGEOM *)lwcurvepoly_add((const LWCURVEPOLY *)to, where, what);
450
return (LWGEOM *)lwmpoint_add((const LWMPOINT *)to,
454
return (LWGEOM *)lwmline_add((const LWMLINE *)to,
458
return (LWGEOM *)lwmcurve_add((const LWMCURVE *)to,
461
case MULTIPOLYGONTYPE:
462
return (LWGEOM *)lwmpoly_add((const LWMPOLY *)to,
465
case MULTISURFACETYPE:
466
return (LWGEOM *)lwmsurface_add((const LWMSURFACE *)to,
470
return (LWGEOM *)lwcollection_add(
471
(const LWCOLLECTION *)to, where, what);
474
lwerror("lwgeom_add: unknown geometry type: %d",
475
TYPE_GETTYPE(to->type));
481
* Return an alloced string
484
lwgeom_to_ewkt(LWGEOM *lwgeom)
486
uchar *serialized = lwgeom_serialize(lwgeom);
488
if ( ! serialized ) {
489
lwerror("Error serializing geom %p", lwgeom);
491
ret = unparse_WKT(serialized, lwalloc, lwfree);
497
* Return an alloced string
500
lwgeom_to_hexwkb(LWGEOM *lwgeom, unsigned int byteorder)
502
uchar *serialized = lwgeom_serialize(lwgeom);
503
char *hexwkb = unparse_WKB(serialized, lwalloc, lwfree, byteorder,NULL,1);
509
* Return an alloced string
512
lwgeom_to_ewkb(LWGEOM *lwgeom, char byteorder, size_t *outsize)
514
uchar *serialized = lwgeom_serialize(lwgeom);
517
* We cast return to "unsigned" char as we are
518
* requesting a "binary" output, not HEX
519
* (last argument set to 0)
521
uchar *hexwkb = (uchar *)unparse_WKB(serialized, lwalloc, lwfree,
522
byteorder, outsize, 0);
528
* Make an LWGEOM object from a EWKB binary representation.
529
* Currently highly unoptimized as it:
530
* - convert EWKB to HEXEWKB
531
* - construct PG_LWGEOM
535
lwgeom_from_ewkb(uchar *ewkb, size_t size)
537
size_t hexewkblen = size*2;
541
SERIALIZED_LWGEOM *serialized_lwgeom;
543
/* "HEXify" the EWKB */
544
hexewkb = lwalloc(hexewkblen+1);
545
for (i=0; i<size; ++i) deparse_hex(ewkb[i], &hexewkb[i*2]);
546
hexewkb[hexewkblen] = '\0';
548
/* Rely on grammar parser to construct a LWGEOM */
549
serialized_lwgeom = parse_lwgeom_wkt(hexewkb);
551
/* Free intermediate HEXified representation */
555
ret = lwgeom_deserialize(serialized_lwgeom->lwgeom);
561
* geom1 same as geom2
564
* + have same # objects
566
* + each object in geom1 has a corresponding object in geom2 (see above)
569
lwgeom_same(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)
572
lwnotice("lwgeom_same(%s, %s) called",
573
lwgeom_typename(TYPE_GETTYPE(lwgeom1->type)),
574
lwgeom_typename(TYPE_GETTYPE(lwgeom2->type)));
577
if ( TYPE_GETTYPE(lwgeom1->type) != TYPE_GETTYPE(lwgeom2->type) )
580
lwnotice(" type differ");
585
if ( TYPE_GETZM(lwgeom1->type) != TYPE_GETZM(lwgeom2->type) )
588
lwnotice(" ZM flags differ");
593
/* Check boxes if both already computed */
594
if ( lwgeom1->bbox && lwgeom2->bbox )
596
/*lwnotice("bbox1:%p, bbox2:%p", lwgeom1->bbox, lwgeom2->bbox);*/
597
if ( ! box2d_same(lwgeom1->bbox, lwgeom2->bbox) )
600
lwnotice(" bounding boxes differ");
606
/* geoms have same type, invoke type-specific function */
607
switch(TYPE_GETTYPE(lwgeom1->type))
610
return lwpoint_same((LWPOINT *)lwgeom1,
613
return lwline_same((LWLINE *)lwgeom1,
616
return lwpoly_same((LWPOLY *)lwgeom1,
620
case MULTIPOLYGONTYPE:
622
return lwcollection_same((LWCOLLECTION *)lwgeom1,
623
(LWCOLLECTION *)lwgeom2);
625
lwerror("lwgeom_same: unknown geometry type: %d",
626
TYPE_GETTYPE(lwgeom1->type));
633
lwgeom_changed(LWGEOM *lwgeom)
635
if ( lwgeom->bbox ) lwfree(lwgeom->bbox);
637
TYPE_SETHASBBOX(lwgeom->type, 0);
641
lwgeom_dropBBOX(LWGEOM *lwgeom)
643
if ( lwgeom->bbox ) lwfree(lwgeom->bbox);
645
TYPE_SETHASBBOX(lwgeom->type, 0);
649
* Ensure there's a box in the LWGEOM.
650
* If the box is already there just return,
654
lwgeom_addBBOX(LWGEOM *lwgeom)
656
if ( lwgeom->bbox ) return;
657
lwgeom->bbox = lwgeom_compute_box2d(lwgeom);
658
TYPE_SETHASBBOX(lwgeom->type, 1);
662
lwgeom_dropSRID(LWGEOM *lwgeom)
664
TYPE_SETHASSRID(lwgeom->type, 0);
669
lwgeom_segmentize2d(LWGEOM *lwgeom, double dist)
671
switch(TYPE_GETTYPE(lwgeom->type))
674
return (LWGEOM *)lwline_segmentize2d((LWLINE *)lwgeom,
677
return (LWGEOM *)lwpoly_segmentize2d((LWPOLY *)lwgeom,
680
case MULTIPOLYGONTYPE:
682
return (LWGEOM *)lwcollection_segmentize2d(
683
(LWCOLLECTION *)lwgeom, dist);
686
return lwgeom_clone(lwgeom);
691
lwgeom_longitude_shift(LWGEOM *lwgeom)
694
switch(TYPE_GETTYPE(lwgeom->type))
702
point = (LWPOINT *)lwgeom;
703
ptarray_longitude_shift(point->point);
706
line = (LWLINE *)lwgeom;
707
ptarray_longitude_shift(line->points);
710
poly = (LWPOLY *)lwgeom;
711
for (i=0; i<poly->nrings; i++)
712
ptarray_longitude_shift(poly->rings[i]);
716
case MULTIPOLYGONTYPE:
718
coll = (LWCOLLECTION *)lwgeom;
719
for (i=0; i<coll->ngeoms; i++)
720
lwgeom_longitude_shift(coll->geoms[i]);
723
lwerror("%s:%d: unsupported geom type: %s",
725
lwgeom_typename(TYPE_GETTYPE(lwgeom->type)));