1
/**********************************************************************
2
* $Id: lwgeom.c 4168 2009-06-11 16:44:03Z pramsey $
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 "liblwgeom.h"
22
lwgeom_deserialize(uchar *srl)
24
int type = lwgeom_getType(srl[0]);
26
LWDEBUGF(2, "lwgeom_deserialize got %d - %s", type, lwgeom_typename(type));
31
return (LWGEOM *)lwpoint_deserialize(srl);
33
return (LWGEOM *)lwline_deserialize(srl);
35
return (LWGEOM *)lwcircstring_deserialize(srl);
37
return (LWGEOM *)lwpoly_deserialize(srl);
39
return (LWGEOM *)lwmpoint_deserialize(srl);
41
return (LWGEOM *)lwmline_deserialize(srl);
42
case MULTIPOLYGONTYPE:
43
return (LWGEOM *)lwmpoly_deserialize(srl);
45
return (LWGEOM *)lwcollection_deserialize(srl);
47
return (LWGEOM *)lwcompound_deserialize(srl);
49
return (LWGEOM *)lwcurvepoly_deserialize(srl);
51
return (LWGEOM *)lwmcurve_deserialize(srl);
52
case MULTISURFACETYPE:
53
return (LWGEOM *)lwmsurface_deserialize(srl);
55
lwerror("Unknown geometry type: %d", type);
63
lwgeom_serialize_size(LWGEOM *lwgeom)
65
int type = TYPE_GETTYPE(lwgeom->type);
67
LWDEBUGF(2, "lwgeom_serialize_size(%s) called", lwgeom_typename(type));
72
return lwpoint_serialize_size((LWPOINT *)lwgeom);
74
return lwline_serialize_size((LWLINE *)lwgeom);
76
return lwpoly_serialize_size((LWPOLY *)lwgeom);
78
return lwcircstring_serialize_size((LWCIRCSTRING *)lwgeom);
84
case MULTIPOLYGONTYPE:
85
case MULTISURFACETYPE:
87
return lwcollection_serialize_size((LWCOLLECTION *)lwgeom);
89
lwerror("Unknown geometry type: %d", type);
96
lwgeom_serialize_buf(LWGEOM *lwgeom, uchar *buf, size_t *retsize)
98
int type = TYPE_GETTYPE(lwgeom->type);
100
LWDEBUGF(2, "lwgeom_serialize_buf called with a %s",
101
lwgeom_typename(type));
106
lwpoint_serialize_buf((LWPOINT *)lwgeom, buf, retsize);
109
lwline_serialize_buf((LWLINE *)lwgeom, buf, retsize);
112
lwpoly_serialize_buf((LWPOLY *)lwgeom, buf, retsize);
115
lwcircstring_serialize_buf((LWCIRCSTRING *)lwgeom, buf, retsize);
122
case MULTIPOLYGONTYPE:
123
case MULTISURFACETYPE:
125
lwcollection_serialize_buf((LWCOLLECTION *)lwgeom, buf,
129
lwerror("Unknown geometry type: %d", type);
136
lwgeom_serialize(LWGEOM *lwgeom)
138
size_t size = lwgeom_serialize_size(lwgeom);
140
uchar *serialized = lwalloc(size);
142
lwgeom_serialize_buf(lwgeom, serialized, &retsize);
144
#if POSTGIS_DEBUG_LEVEL > 0
145
if ( retsize != size )
147
lwerror("lwgeom_serialize: computed size %d, returned size %d",
155
/** Force Right-hand-rule on LWGEOM polygons **/
157
lwgeom_force_rhr(LWGEOM *lwgeom)
162
switch (TYPE_GETTYPE(lwgeom->type))
165
lwpoly_forceRHR((LWPOLY *)lwgeom);
168
case MULTIPOLYGONTYPE:
170
coll = (LWCOLLECTION *)lwgeom;
171
for (i=0; i<coll->ngeoms; i++)
172
lwgeom_force_rhr(coll->geoms[i]);
177
/** Reverse vertex order of LWGEOM **/
179
lwgeom_reverse(LWGEOM *lwgeom)
184
switch (TYPE_GETTYPE(lwgeom->type))
187
lwline_reverse((LWLINE *)lwgeom);
190
lwpoly_reverse((LWPOLY *)lwgeom);
193
case MULTIPOLYGONTYPE:
195
col = (LWCOLLECTION *)lwgeom;
196
for (i=0; i<col->ngeoms; i++)
197
lwgeom_reverse(col->geoms[i]);
202
BOX3D *lwgeom_compute_box3d(const LWGEOM *lwgeom)
204
if ( ! lwgeom ) return NULL;
206
switch (TYPE_GETTYPE(lwgeom->type))
209
return lwpoint_compute_box3d((LWPOINT *)lwgeom);
211
return lwline_compute_box3d((LWLINE *)lwgeom);
213
return lwcircstring_compute_box3d((LWCIRCSTRING *)lwgeom);
215
return lwpoly_compute_box3d((LWPOLY *)lwgeom);
221
case MULTIPOLYGONTYPE:
222
case MULTISURFACETYPE:
224
return lwcollection_compute_box3d((LWCOLLECTION *)lwgeom);
226
/* Never get here, please. */
231
lwgeom_compute_box2d_p(LWGEOM *lwgeom, BOX2DFLOAT4 *buf)
233
LWDEBUGF(2, "lwgeom_compute_box2d_p called of %p of type %d.", lwgeom, TYPE_GETTYPE(lwgeom->type));
235
switch (TYPE_GETTYPE(lwgeom->type))
238
return lwpoint_compute_box2d_p((LWPOINT *)lwgeom, buf);
240
return lwline_compute_box2d_p((LWLINE *)lwgeom, buf);
242
return lwcircstring_compute_box2d_p((LWCIRCSTRING *)lwgeom, buf);
244
return lwpoly_compute_box2d_p((LWPOLY *)lwgeom, buf);
250
case MULTIPOLYGONTYPE:
251
case MULTISURFACETYPE:
253
return lwcollection_compute_box2d_p((LWCOLLECTION *)lwgeom, buf);
259
* do not forget to lwfree() result
262
lwgeom_compute_box2d(LWGEOM *lwgeom)
264
BOX2DFLOAT4 *result = lwalloc(sizeof(BOX2DFLOAT4));
265
if ( lwgeom_compute_box2d_p(lwgeom, result) ) return result;
274
lwgeom_as_lwpoint(LWGEOM *lwgeom)
276
if ( TYPE_GETTYPE(lwgeom->type) == POINTTYPE )
277
return (LWPOINT *)lwgeom;
282
lwgeom_as_lwline(LWGEOM *lwgeom)
284
if ( TYPE_GETTYPE(lwgeom->type) == LINETYPE )
285
return (LWLINE *)lwgeom;
290
lwgeom_as_lwcircstring(LWGEOM *lwgeom)
292
if ( TYPE_GETTYPE(lwgeom->type) == CIRCSTRINGTYPE )
293
return (LWCIRCSTRING *)lwgeom;
298
lwgeom_as_lwpoly(LWGEOM *lwgeom)
300
if ( TYPE_GETTYPE(lwgeom->type) == POLYGONTYPE )
301
return (LWPOLY *)lwgeom;
306
lwgeom_as_lwcollection(LWGEOM *lwgeom)
308
if ( TYPE_GETTYPE(lwgeom->type) >= MULTIPOINTTYPE
309
&& TYPE_GETTYPE(lwgeom->type) <= COLLECTIONTYPE)
310
return (LWCOLLECTION *)lwgeom;
315
lwgeom_as_lwmpoint(LWGEOM *lwgeom)
317
if ( TYPE_GETTYPE(lwgeom->type) == MULTIPOINTTYPE )
318
return (LWMPOINT *)lwgeom;
323
lwgeom_as_lwmline(LWGEOM *lwgeom)
325
if ( TYPE_GETTYPE(lwgeom->type) == MULTILINETYPE )
326
return (LWMLINE *)lwgeom;
331
lwgeom_as_lwmpoly(LWGEOM *lwgeom)
333
if ( TYPE_GETTYPE(lwgeom->type) == MULTIPOLYGONTYPE )
334
return (LWMPOLY *)lwgeom;
338
LWGEOM *lwmpoly_as_lwgeom(LWMPOLY *obj)
340
return (LWGEOM *)obj;
342
LWGEOM *lwmline_as_lwgeom(LWMLINE *obj)
344
return (LWGEOM *)obj;
346
LWGEOM *lwmpoint_as_lwgeom(LWMPOINT *obj)
348
return (LWGEOM *)obj;
350
LWGEOM *lwcollection_as_lwgeom(LWCOLLECTION *obj)
352
return (LWGEOM *)obj;
354
LWGEOM *lwcircstring_as_lwgeom(LWCIRCSTRING *obj)
356
return (LWGEOM *)obj;
358
LWGEOM *lwpoly_as_lwgeom(LWPOLY *obj)
360
return (LWGEOM *)obj;
362
LWGEOM *lwline_as_lwgeom(LWLINE *obj)
364
return (LWGEOM *)obj;
366
LWGEOM *lwpoint_as_lwgeom(LWPOINT *obj)
368
return (LWGEOM *)obj;
373
** Look-up for the correct MULTI* type promotion for singleton types.
375
static unsigned char MULTITYPE[16] =
390
* Create a new LWGEOM of the appropriate MULTI* type.
393
lwgeom_as_multi(LWGEOM *lwgeom)
396
LWGEOM *ogeom = NULL;
397
BOX2DFLOAT4 *box = NULL;
400
ogeoms = lwalloc(sizeof(LWGEOM*));
403
** This funx is a no-op only if a bbox cache is already present
406
if ( lwgeom_contains_subgeoms(TYPE_GETTYPE(lwgeom->type)) )
408
return lwgeom_clone(lwgeom);
411
type = TYPE_GETTYPE(lwgeom->type);
413
if ( MULTITYPE[type] )
415
ogeoms[0] = lwgeom_clone(lwgeom);
417
/* Sub-geometries are not allowed to have bboxes or SRIDs, move the bbox to the collection */
418
box = ogeoms[0]->bbox;
419
ogeoms[0]->bbox = NULL;
420
ogeoms[0]->SRID = -1;
422
ogeom = (LWGEOM *)lwcollection_construct(MULTITYPE[type], lwgeom->SRID, box, 1, ogeoms);
426
return lwgeom_clone(lwgeom);
433
lwgeom_release(LWGEOM *lwgeom)
438
#ifdef INTEGRITY_CHECKS
440
lwerror("lwgeom_release: someone called on 0x0");
443
/* Drop bounding box (always a copy) */
446
LWDEBUG(3, "lwgeom_release: releasing bbox.");
448
lwfree(lwgeom->bbox);
452
if ( (col=lwgeom_as_lwcollection(lwgeom)) )
454
LWDEBUG(3, "lwgeom_release: Releasing collection.");
456
for (i=0; i<col->ngeoms; i++)
458
lwgeom_release(col->geoms[i]);
469
/** Clone an LWGEOM object. POINTARRAY are not copied. **/
471
lwgeom_clone(const LWGEOM *lwgeom)
473
LWDEBUGF(2, "lwgeom_clone called with %p, %d", lwgeom, TYPE_GETTYPE(lwgeom->type));
475
switch (TYPE_GETTYPE(lwgeom->type))
478
return (LWGEOM *)lwpoint_clone((LWPOINT *)lwgeom);
480
return (LWGEOM *)lwline_clone((LWLINE *)lwgeom);
482
return (LWGEOM *)lwcircstring_clone((LWCIRCSTRING *)lwgeom);
484
return (LWGEOM *)lwpoly_clone((LWPOLY *)lwgeom);
490
case MULTIPOLYGONTYPE:
491
case MULTISURFACETYPE:
493
return (LWGEOM *)lwcollection_clone((LWCOLLECTION *)lwgeom);
500
* Add 'what' to 'to' at position 'where'
502
* @param where =0 == prepend if -1 == append
504
* Appended-to LWGEOM gets a new type based on new condition.
505
* Mix of dimensions is not allowed.
506
* @todo TODO: allow mix of dimensions?
509
lwgeom_add(const LWGEOM *to, uint32 where, const LWGEOM *what)
511
if ( TYPE_NDIMS(what->type) != TYPE_NDIMS(to->type) )
513
lwerror("lwgeom_add: mixed dimensions not supported");
517
LWDEBUGF(2, "lwgeom_add(%s, %d, %s) called",
518
lwgeom_typename(TYPE_GETTYPE(to->type)),
520
lwgeom_typename(TYPE_GETTYPE(what->type)));
522
switch (TYPE_GETTYPE(to->type))
525
return (LWGEOM *)lwpoint_add((const LWPOINT *)to, where, what);
527
return (LWGEOM *)lwline_add((const LWLINE *)to, where, what);
530
return (LWGEOM *)lwcircstring_add((const LWCIRCSTRING *)to, where, what);
533
return (LWGEOM *)lwpoly_add((const LWPOLY *)to, where, what);
536
return (LWGEOM *)lwcompound_add((const LWCOMPOUND *)to, where, what);
539
return (LWGEOM *)lwcurvepoly_add((const LWCURVEPOLY *)to, where, what);
542
return (LWGEOM *)lwmpoint_add((const LWMPOINT *)to,
546
return (LWGEOM *)lwmline_add((const LWMLINE *)to,
550
return (LWGEOM *)lwmcurve_add((const LWMCURVE *)to,
553
case MULTIPOLYGONTYPE:
554
return (LWGEOM *)lwmpoly_add((const LWMPOLY *)to,
557
case MULTISURFACETYPE:
558
return (LWGEOM *)lwmsurface_add((const LWMSURFACE *)to,
562
return (LWGEOM *)lwcollection_add(
563
(const LWCOLLECTION *)to, where, what);
566
lwerror("lwgeom_add: unknown geometry type: %d",
567
TYPE_GETTYPE(to->type));
574
* Return an alloced string
577
lwgeom_to_ewkt(LWGEOM *lwgeom, int flags)
579
LWGEOM_UNPARSER_RESULT lwg_unparser_result;
580
uchar *serialized = lwgeom_serialize(lwgeom);
585
lwerror("Error serializing geom %p", lwgeom);
588
result = unparse_WKT(&lwg_unparser_result, serialized, lwalloc, lwfree, flags);
591
return lwg_unparser_result.wkoutput;
595
* Return an alloced string
598
lwgeom_to_hexwkb(LWGEOM *lwgeom, int flags, unsigned int byteorder)
600
LWGEOM_UNPARSER_RESULT lwg_unparser_result;
601
uchar *serialized = lwgeom_serialize(lwgeom);
604
result = unparse_WKB(&lwg_unparser_result, serialized, lwalloc, lwfree, flags, byteorder,1);
607
return lwg_unparser_result.wkoutput;
611
* Return an alloced string
614
lwgeom_to_ewkb(LWGEOM *lwgeom, int flags, char byteorder, size_t *outsize)
616
LWGEOM_UNPARSER_RESULT lwg_unparser_result;
617
uchar *serialized = lwgeom_serialize(lwgeom);
621
* We cast return to "unsigned" char as we are
622
* requesting a "binary" output, not HEX
623
* (last argument set to 0)
625
result = unparse_WKB(&lwg_unparser_result, serialized, lwalloc, lwfree,
626
flags, byteorder, 0);
628
return (uchar *)lwg_unparser_result.wkoutput;
632
* Make an LWGEOM object from a EWKB binary representation.
633
* Currently highly unoptimized as it:
634
* - convert EWKB to HEXEWKB
635
* - construct PG_LWGEOM
639
lwgeom_from_ewkb(uchar *ewkb, int flags, size_t size)
641
size_t hexewkblen = size*2;
646
LWGEOM_PARSER_RESULT lwg_parser_result;
648
/* "HEXify" the EWKB */
649
hexewkb = lwalloc(hexewkblen+1);
650
for (i=0; i<size; ++i) deparse_hex(ewkb[i], &hexewkb[i*2]);
651
hexewkb[hexewkblen] = '\0';
653
/* Rely on grammar parser to construct a LWGEOM */
654
result = serialized_lwgeom_from_ewkt(&lwg_parser_result, hexewkb, flags);
656
lwerror("%s", (char *)lwg_parser_result.message);
658
/* Free intermediate HEXified representation */
662
ret = lwgeom_deserialize(lwg_parser_result.serialized_lwgeom);
668
* Make an LWGEOM object from a EWKT representation.
671
lwgeom_from_ewkt(char *ewkt, int flags)
675
LWGEOM_PARSER_RESULT lwg_parser_result;
677
/* Rely on grammar parser to construct a LWGEOM */
678
result = serialized_lwgeom_from_ewkt(&lwg_parser_result, ewkt, flags);
680
lwerror("%s", (char *)lwg_parser_result.message);
683
ret = lwgeom_deserialize(lwg_parser_result.serialized_lwgeom);
689
* Parser functions for working with serialized LWGEOMs. Useful for cases where
690
* the function input is already serialized, e.g. some input and output functions
694
* Make a serialzed LWGEOM object from a WKT input string
697
serialized_lwgeom_from_ewkt(LWGEOM_PARSER_RESULT *lwg_parser_result, char *wkt_input, int flags)
700
int result = parse_lwg(lwg_parser_result, wkt_input, flags,
703
LWDEBUGF(2, "serialized_lwgeom_from_ewkt with %s",wkt_input);
709
* Return an alloced string
712
serialized_lwgeom_to_ewkt(LWGEOM_UNPARSER_RESULT *lwg_unparser_result, uchar *serialized, int flags)
716
result = unparse_WKT(lwg_unparser_result, serialized, lwalloc, lwfree, flags);
722
* Return an alloced string
725
serialized_lwgeom_from_hexwkb(LWGEOM_PARSER_RESULT *lwg_parser_result, char *hexwkb_input, int flags)
727
/* NOTE: it is actually the same combined WKT/WKB parser that decodes HEXEWKB into LWGEOMs! */
728
int result = parse_lwg(lwg_parser_result, hexwkb_input, flags,
731
LWDEBUGF(2, "serialized_lwgeom_from_hexwkb with %s", hexwkb_input);
737
* Return an alloced string
740
serialized_lwgeom_to_hexwkb(LWGEOM_UNPARSER_RESULT *lwg_unparser_result, uchar *serialized, int flags, unsigned int byteorder)
744
result = unparse_WKB(lwg_unparser_result, serialized, lwalloc, lwfree, flags, byteorder, 1);
750
* Return an alloced string
753
serialized_lwgeom_to_ewkb(LWGEOM_UNPARSER_RESULT *lwg_unparser_result, uchar *serialized, int flags, unsigned int byteorder)
757
result = unparse_WKB(lwg_unparser_result, serialized, lwalloc, lwfree, flags, byteorder, 0);
763
* @brief geom1 same as geom2
766
* + have same # objects
768
* + each object in geom1 has a corresponding object in geom2 (see above)
773
lwgeom_same(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)
775
LWDEBUGF(2, "lwgeom_same(%s, %s) called",
776
lwgeom_typename(TYPE_GETTYPE(lwgeom1->type)),
777
lwgeom_typename(TYPE_GETTYPE(lwgeom2->type)));
779
if ( TYPE_GETTYPE(lwgeom1->type) != TYPE_GETTYPE(lwgeom2->type) )
781
LWDEBUG(3, " type differ");
786
if ( TYPE_GETZM(lwgeom1->type) != TYPE_GETZM(lwgeom2->type) )
788
LWDEBUG(3, " ZM flags differ");
793
/* Check boxes if both already computed */
794
if ( lwgeom1->bbox && lwgeom2->bbox )
796
/*lwnotice("bbox1:%p, bbox2:%p", lwgeom1->bbox, lwgeom2->bbox);*/
797
if ( ! box2d_same(lwgeom1->bbox, lwgeom2->bbox) )
799
LWDEBUG(3, " bounding boxes differ");
805
/* geoms have same type, invoke type-specific function */
806
switch (TYPE_GETTYPE(lwgeom1->type))
809
return lwpoint_same((LWPOINT *)lwgeom1,
812
return lwline_same((LWLINE *)lwgeom1,
815
return lwpoly_same((LWPOLY *)lwgeom1,
819
case MULTIPOLYGONTYPE:
821
return lwcollection_same((LWCOLLECTION *)lwgeom1,
822
(LWCOLLECTION *)lwgeom2);
824
lwerror("lwgeom_same: unsupported geometry type: %s",
825
lwgeom_typename(TYPE_GETTYPE(lwgeom1->type)));
832
lwgeom_changed(LWGEOM *lwgeom)
834
if ( lwgeom->bbox ) lwfree(lwgeom->bbox);
836
TYPE_SETHASBBOX(lwgeom->type, 0);
840
lwgeom_drop_bbox(LWGEOM *lwgeom)
842
if ( lwgeom->bbox ) lwfree(lwgeom->bbox);
844
TYPE_SETHASBBOX(lwgeom->type, 0);
848
* Ensure there's a box in the LWGEOM.
849
* If the box is already there just return,
853
lwgeom_add_bbox(LWGEOM *lwgeom)
855
if ( lwgeom->bbox ) return;
856
lwgeom->bbox = lwgeom_compute_box2d(lwgeom);
857
TYPE_SETHASBBOX(lwgeom->type, 1);
861
lwgeom_dropSRID(LWGEOM *lwgeom)
863
TYPE_SETHASSRID(lwgeom->type, 0);
868
lwgeom_segmentize2d(LWGEOM *lwgeom, double dist)
870
switch (TYPE_GETTYPE(lwgeom->type))
873
return (LWGEOM *)lwline_segmentize2d((LWLINE *)lwgeom,
876
return (LWGEOM *)lwpoly_segmentize2d((LWPOLY *)lwgeom,
879
case MULTIPOLYGONTYPE:
881
return (LWGEOM *)lwcollection_segmentize2d(
882
(LWCOLLECTION *)lwgeom, dist);
885
return lwgeom_clone(lwgeom);
890
lwgeom_longitude_shift(LWGEOM *lwgeom)
893
switch (TYPE_GETTYPE(lwgeom->type))
901
point = (LWPOINT *)lwgeom;
902
ptarray_longitude_shift(point->point);
905
line = (LWLINE *)lwgeom;
906
ptarray_longitude_shift(line->points);
909
poly = (LWPOLY *)lwgeom;
910
for (i=0; i<poly->nrings; i++)
911
ptarray_longitude_shift(poly->rings[i]);
915
case MULTIPOLYGONTYPE:
917
coll = (LWCOLLECTION *)lwgeom;
918
for (i=0; i<coll->ngeoms; i++)
919
lwgeom_longitude_shift(coll->geoms[i]);
922
lwerror("%s:%d: unsupported geom type: %s",
924
lwgeom_typename(TYPE_GETTYPE(lwgeom->type)));
928
/** Return TRUE if the geometry may contain sub-geometries, i.e. it is a MULTI* or COMPOUNDCURVE */
930
lwgeom_contains_subgeoms(int type)
937
case MULTIPOLYGONTYPE:
941
case MULTISURFACETYPE:
950
void lwgeom_free(LWGEOM *lwgeom)
953
switch (TYPE_GETTYPE(lwgeom->type))
956
lwpoint_free((LWPOINT *)lwgeom);
959
lwline_free((LWLINE *)lwgeom);
962
lwpoly_free((LWPOLY *)lwgeom);
965
lwmpoint_free((LWMPOINT *)lwgeom);
968
lwmline_free((LWMLINE *)lwgeom);
970
case MULTIPOLYGONTYPE:
971
lwmpoly_free((LWMPOLY *)lwgeom);
974
lwcollection_free((LWCOLLECTION *)lwgeom);