PostGIS 3.0.6dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
lwgeom.c
Go to the documentation of this file.
1/**********************************************************************
2 *
3 * PostGIS - Spatial Types for PostgreSQL
4 * http://postgis.net
5 *
6 * PostGIS is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * PostGIS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18 *
19 **********************************************************************
20 *
21 * Copyright (C) 2001-2006 Refractions Research Inc.
22 * Copyright (C) 2017-2018 Daniel Baston <dbaston@gmail.com>
23 *
24 **********************************************************************/
25
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <stdarg.h>
30
31#include "liblwgeom_internal.h"
32#include "lwgeom_log.h"
33
34
36void
38{
39 LWCOLLECTION *coll;
40 uint32_t i;
41
42 switch (lwgeom->type)
43 {
44 case POLYGONTYPE:
46 return;
47
48 case TRIANGLETYPE:
50 return;
51
52 /* Not handle POLYHEDRALSURFACE and TIN
53 as they are supposed to be well oriented */
55 case COLLECTIONTYPE:
56 coll = (LWCOLLECTION *)lwgeom;
57 for (i=0; i<coll->ngeoms; i++)
59 return;
60 }
61}
62
64int
66{
67 switch (lwgeom->type)
68 {
69 case POLYGONTYPE:
70 return lwpoly_is_clockwise((LWPOLY *)lwgeom);
71
72 case TRIANGLETYPE:
73 return lwtriangle_is_clockwise((LWTRIANGLE *)lwgeom);
74
76 case COLLECTIONTYPE:
77 {
78 uint32_t i;
79 LWCOLLECTION* coll = (LWCOLLECTION *)lwgeom;
80
81 for (i=0; i < coll->ngeoms; i++)
82 if (!lwgeom_is_clockwise(coll->geoms[i]))
83 return LW_FALSE;
84 return LW_TRUE;
85 }
86 default:
87 return LW_TRUE;
88 return LW_FALSE;
89 }
90}
91
92LWGEOM *
94{
95 LWGEOM *geomout = lwgeom_clone_deep(geom);
97 return geomout;
98}
99
101void
103{
104 uint32_t i;
105 LWCOLLECTION *col;
106 if (!geom)
107 return;
108
109 switch (geom->type)
110 {
111 case MULTIPOINTTYPE:
112 case POINTTYPE:
113 {
114 return;
115 }
116 case TRIANGLETYPE:
117 case CIRCSTRINGTYPE:
118 case LINETYPE:
119 {
120 LWLINE *line = (LWLINE *)(geom);
122 return;
123 }
124 case POLYGONTYPE:
125 {
126 LWPOLY *poly = (LWPOLY *)(geom);
127 if (!poly->rings)
128 return;
129 uint32_t r;
130 for (r = 0; r < poly->nrings; r++)
132 return;
133 }
134 case MULTICURVETYPE:
135 case MULTILINETYPE:
136 case MULTIPOLYGONTYPE:
137 case MULTISURFACETYPE:
139 case TINTYPE:
140 case COLLECTIONTYPE:
141 case COMPOUNDTYPE:
142 case CURVEPOLYTYPE:
143 {
144 col = (LWCOLLECTION *)(geom);
145 if (!col->geoms)
146 return;
147 for (i=0; i<col->ngeoms; i++)
149 return;
150 }
151 default:
152 {
153 lwerror("%s: Unknown geometry type: %s", __func__, lwtype_name(geom->type));
154 return;
155 }
156
157 }
158}
159
160LWLINE *
162{
163 if ( lwgeom == NULL ) return NULL;
164 if ( lwgeom->type == LINETYPE )
165 return (LWLINE *)lwgeom;
166 else return NULL;
167}
168
171{
172 if ( lwgeom == NULL ) return NULL;
173 if ( lwgeom->type == CIRCSTRINGTYPE )
174 return (LWCIRCSTRING *)lwgeom;
175 else return NULL;
176}
177
180{
181 if ( lwgeom == NULL ) return NULL;
182 if ( lwgeom->type == COMPOUNDTYPE )
183 return (LWCOMPOUND *)lwgeom;
184 else return NULL;
185}
186
189{
190 if ( lwgeom == NULL ) return NULL;
191 if ( lwgeom->type == CURVEPOLYTYPE )
192 return (LWCURVEPOLY *)lwgeom;
193 else return NULL;
194}
195
196LWPOLY *
198{
199 if ( lwgeom == NULL ) return NULL;
200 if ( lwgeom->type == POLYGONTYPE )
201 return (LWPOLY *)lwgeom;
202 else return NULL;
203}
204
207{
208 if ( lwgeom == NULL ) return NULL;
209 if ( lwgeom->type == TRIANGLETYPE )
210 return (LWTRIANGLE *)lwgeom;
211 else return NULL;
212}
213
216{
217 if ( lwgeom == NULL ) return NULL;
218 if ( lwgeom_is_collection(lwgeom) )
219 return (LWCOLLECTION*)lwgeom;
220 else return NULL;
221}
222
223LWMPOINT *
225{
226 if ( lwgeom == NULL ) return NULL;
227 if ( lwgeom->type == MULTIPOINTTYPE )
228 return (LWMPOINT *)lwgeom;
229 else return NULL;
230}
231
232LWMLINE *
234{
235 if ( lwgeom == NULL ) return NULL;
236 if ( lwgeom->type == MULTILINETYPE )
237 return (LWMLINE *)lwgeom;
238 else return NULL;
239}
240
241LWMPOLY *
243{
244 if ( lwgeom == NULL ) return NULL;
245 if ( lwgeom->type == MULTIPOLYGONTYPE )
246 return (LWMPOLY *)lwgeom;
247 else return NULL;
248}
249
252{
253 if ( lwgeom->type == POLYHEDRALSURFACETYPE )
254 return (LWPSURFACE *)lwgeom;
255 else return NULL;
256}
257
258LWTIN *
260{
261 if ( lwgeom->type == TINTYPE )
262 return (LWTIN *)lwgeom;
263 else return NULL;
264}
265
267{
268 return (LWGEOM *)obj;
269}
270
272{
273 return (LWGEOM *)obj;
274}
275
277{
278 if ( obj == NULL ) return NULL;
279 return (LWGEOM *)obj;
280}
282{
283 if ( obj == NULL ) return NULL;
284 return (LWGEOM *)obj;
285}
287{
288 if ( obj == NULL ) return NULL;
289 return (LWGEOM *)obj;
290}
292{
293 if ( obj == NULL ) return NULL;
294 return (LWGEOM *)obj;
295}
297{
298 if ( obj == NULL ) return NULL;
299 return (LWGEOM *)obj;
300}
302{
303 if ( obj == NULL ) return NULL;
304 return (LWGEOM *)obj;
305}
307{
308 if ( obj == NULL ) return NULL;
309 return (LWGEOM *)obj;
310}
312{
313 if ( obj == NULL ) return NULL;
314 return (LWGEOM *)obj;
315}
317{
318 if ( obj == NULL ) return NULL;
319 return (LWGEOM *)obj;
320}
322{
323 if ( obj == NULL ) return NULL;
324 return (LWGEOM *)obj;
325}
327{
328 if ( obj == NULL ) return NULL;
329 return (LWGEOM *)obj;
330}
331
332
337{
338 0,
339 MULTIPOINTTYPE, /* 1 */
340 MULTILINETYPE, /* 2 */
341 MULTIPOLYGONTYPE, /* 3 */
342 0,0,0,0,
343 MULTICURVETYPE, /* 8 */
344 MULTICURVETYPE, /* 9 */
345 MULTISURFACETYPE, /* 10 */
346 POLYHEDRALSURFACETYPE, /* 11 */
347 0, 0,
348 TINTYPE, /* 14 */
349 0
350};
351
352uint8_t lwtype_multitype(uint8_t type)
353{
354 if (type > 15) return 0;
355 return MULTITYPE[type];
356}
357
361LWGEOM *
363{
364 LWGEOM **ogeoms;
365 LWGEOM *ogeom = NULL;
366 GBOX *box = NULL;
367 int type;
368
369 type = lwgeom->type;
370
371 if ( ! MULTITYPE[type] ) return lwgeom_clone(lwgeom);
372
373 if( lwgeom_is_empty(lwgeom) )
374 {
376 MULTITYPE[type],
377 lwgeom->srid,
378 FLAGS_GET_Z(lwgeom->flags),
379 FLAGS_GET_M(lwgeom->flags)
380 );
381 }
382 else
383 {
384 ogeoms = lwalloc(sizeof(LWGEOM*));
385 ogeoms[0] = lwgeom_clone(lwgeom);
386
387 /* Sub-geometries are not allowed to have bboxes or SRIDs, move the bbox to the collection */
388 box = ogeoms[0]->bbox;
389 ogeoms[0]->bbox = NULL;
390 ogeoms[0]->srid = SRID_UNKNOWN;
391
392 ogeom = (LWGEOM *)lwcollection_construct(MULTITYPE[type], lwgeom->srid, box, 1, ogeoms);
393 }
394
395 return ogeom;
396}
397
401LWGEOM *
403{
404 LWGEOM *ogeom;
405 int type = lwgeom->type;
406 /*
407 int hasz = FLAGS_GET_Z(lwgeom->flags);
408 int hasm = FLAGS_GET_M(lwgeom->flags);
409 int32_t srid = lwgeom->srid;
410 */
411
412 switch(type)
413 {
414 case LINETYPE:
415 /* turn to COMPOUNDCURVE */
417 break;
418 case POLYGONTYPE:
420 break;
421 case MULTILINETYPE:
422 /* turn to MULTICURVE */
423 ogeom = lwgeom_clone(lwgeom);
424 ogeom->type = MULTICURVETYPE;
425 break;
426 case MULTIPOLYGONTYPE:
427 /* turn to MULTISURFACE */
428 ogeom = lwgeom_clone(lwgeom);
429 ogeom->type = MULTISURFACETYPE;
430 break;
431 case COLLECTIONTYPE:
432 default:
433 ogeom = lwgeom_clone(lwgeom);
434 break;
435 }
436
437 /* TODO: copy bbox from input geom ? */
438
439 return ogeom;
440}
441
442
449void
451{
452 if ( ! lwgeom )
453 lwerror("lwgeom_release: someone called on 0x0");
454
455 LWDEBUGF(3, "releasing type %s", lwtype_name(lwgeom->type));
456
457 /* Drop bounding box (always a copy) */
458 if ( lwgeom->bbox )
459 {
460 LWDEBUGF(3, "lwgeom_release: releasing bbox. %p", lwgeom->bbox);
461 lwfree(lwgeom->bbox);
462 }
463 lwfree(lwgeom);
464
465}
466
467
468/* @brief Clone LWGEOM object. Serialized point lists are not copied.
469 *
470 * @see ptarray_clone
471 */
472LWGEOM *
473lwgeom_clone(const LWGEOM *lwgeom)
474{
475 LWDEBUGF(2, "lwgeom_clone called with %p, %s",
476 lwgeom, lwtype_name(lwgeom->type));
477
478 switch (lwgeom->type)
479 {
480 case POINTTYPE:
481 return (LWGEOM *)lwpoint_clone((LWPOINT *)lwgeom);
482 case LINETYPE:
483 return (LWGEOM *)lwline_clone((LWLINE *)lwgeom);
484 case CIRCSTRINGTYPE:
485 return (LWGEOM *)lwcircstring_clone((LWCIRCSTRING *)lwgeom);
486 case POLYGONTYPE:
487 return (LWGEOM *)lwpoly_clone((LWPOLY *)lwgeom);
488 case TRIANGLETYPE:
489 return (LWGEOM *)lwtriangle_clone((LWTRIANGLE *)lwgeom);
490 case COMPOUNDTYPE:
491 case CURVEPOLYTYPE:
492 case MULTICURVETYPE:
493 case MULTISURFACETYPE:
494 case MULTIPOINTTYPE:
495 case MULTILINETYPE:
496 case MULTIPOLYGONTYPE:
498 case TINTYPE:
499 case COLLECTIONTYPE:
500 return (LWGEOM *)lwcollection_clone((LWCOLLECTION *)lwgeom);
501 default:
502 lwerror("lwgeom_clone: Unknown geometry type: %s", lwtype_name(lwgeom->type));
503 return NULL;
504 }
505}
506
510LWGEOM *
512{
513 LWDEBUGF(2, "lwgeom_clone called with %p, %s",
514 lwgeom, lwtype_name(lwgeom->type));
515
516 switch (lwgeom->type)
517 {
518 case POINTTYPE:
519 case LINETYPE:
520 case CIRCSTRINGTYPE:
521 case TRIANGLETYPE:
522 return (LWGEOM *)lwline_clone_deep((LWLINE *)lwgeom);
523 case POLYGONTYPE:
524 return (LWGEOM *)lwpoly_clone_deep((LWPOLY *)lwgeom);
525 case COMPOUNDTYPE:
526 case CURVEPOLYTYPE:
527 case MULTICURVETYPE:
528 case MULTISURFACETYPE:
529 case MULTIPOINTTYPE:
530 case MULTILINETYPE:
531 case MULTIPOLYGONTYPE:
533 case TINTYPE:
534 case COLLECTIONTYPE:
535 return (LWGEOM *)lwcollection_clone_deep((LWCOLLECTION *)lwgeom);
536 default:
537 lwerror("lwgeom_clone_deep: Unknown geometry type: %s", lwtype_name(lwgeom->type));
538 return NULL;
539 }
540}
541
542
546char*
547lwgeom_to_ewkt(const LWGEOM *lwgeom)
548{
549 char* wkt = NULL;
550 size_t wkt_size = 0;
551
552 wkt = lwgeom_to_wkt(lwgeom, WKT_EXTENDED, 12, &wkt_size);
553
554 if ( ! wkt )
555 {
556 lwerror("Error writing geom %p to WKT", lwgeom);
557 }
558
559 return wkt;
560}
561
572char
573lwgeom_same(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)
574{
575 LWDEBUGF(2, "lwgeom_same(%s, %s) called",
576 lwtype_name(lwgeom1->type),
577 lwtype_name(lwgeom2->type));
578
579 if ( lwgeom1->type != lwgeom2->type )
580 {
581 LWDEBUG(3, " type differ");
582
583 return LW_FALSE;
584 }
585
586 if ( FLAGS_GET_ZM(lwgeom1->flags) != FLAGS_GET_ZM(lwgeom2->flags) )
587 {
588 LWDEBUG(3, " ZM flags differ");
589
590 return LW_FALSE;
591 }
592
593 /* Check boxes if both already computed */
594 if ( lwgeom1->bbox && lwgeom2->bbox )
595 {
596 /*lwnotice("bbox1:%p, bbox2:%p", lwgeom1->bbox, lwgeom2->bbox);*/
597 if ( ! gbox_same(lwgeom1->bbox, lwgeom2->bbox) )
598 {
599 LWDEBUG(3, " bounding boxes differ");
600
601 return LW_FALSE;
602 }
603 }
604
605 /* geoms have same type, invoke type-specific function */
606 switch (lwgeom1->type)
607 {
608 case POINTTYPE:
609 return lwpoint_same((LWPOINT *)lwgeom1,
610 (LWPOINT *)lwgeom2);
611 case LINETYPE:
612 return lwline_same((LWLINE *)lwgeom1,
613 (LWLINE *)lwgeom2);
614 case POLYGONTYPE:
615 return lwpoly_same((LWPOLY *)lwgeom1,
616 (LWPOLY *)lwgeom2);
617 case TRIANGLETYPE:
618 return lwtriangle_same((LWTRIANGLE *)lwgeom1,
619 (LWTRIANGLE *)lwgeom2);
620 case CIRCSTRINGTYPE:
621 return lwcircstring_same((LWCIRCSTRING *)lwgeom1,
622 (LWCIRCSTRING *)lwgeom2);
623 case MULTIPOINTTYPE:
624 case MULTILINETYPE:
625 case MULTIPOLYGONTYPE:
626 case MULTICURVETYPE:
627 case MULTISURFACETYPE:
628 case COMPOUNDTYPE:
629 case CURVEPOLYTYPE:
631 case TINTYPE:
632 case COLLECTIONTYPE:
633 return lwcollection_same((LWCOLLECTION *)lwgeom1,
634 (LWCOLLECTION *)lwgeom2);
635 default:
636 lwerror("lwgeom_same: unsupported geometry type: %s",
637 lwtype_name(lwgeom1->type));
638 return LW_FALSE;
639 }
640
641}
642
643int
644lwpoint_inside_circle(const LWPOINT *p, double cx, double cy, double rad)
645{
646 const POINT2D *pt;
647 POINT2D center;
648
649 if ( ! p || ! p->point )
650 return LW_FALSE;
651
652 pt = getPoint2d_cp(p->point, 0);
653
654 center.x = cx;
655 center.y = cy;
656
657 if ( distance2d_pt_pt(pt, &center) < rad )
658 return LW_TRUE;
659
660 return LW_FALSE;
661}
662
663void
665{
666 if ( lwgeom->bbox ) lwfree(lwgeom->bbox);
667 lwgeom->bbox = NULL;
668 FLAGS_SET_BBOX(lwgeom->flags, 0);
669}
670
676void
678{
679 /* an empty LWGEOM has no bbox */
680 if ( lwgeom_is_empty(lwgeom) ) return;
681
682 if ( lwgeom->bbox ) return;
683 FLAGS_SET_BBOX(lwgeom->flags, 1);
684 lwgeom->bbox = gbox_new(lwgeom->flags);
685 lwgeom_calculate_gbox(lwgeom, lwgeom->bbox);
686}
687
688void
690{
691 lwgeom_drop_bbox(lwgeom);
692 lwgeom_add_bbox(lwgeom);
693}
694
695void
697{
698 if ( lwgeom_is_empty(lwgeom) ) return;
699
700 FLAGS_SET_BBOX(lwgeom->flags, 1);
701
702 if ( ! ( gbox || lwgeom->bbox ) )
703 {
704 lwgeom->bbox = gbox_new(lwgeom->flags);
705 lwgeom_calculate_gbox(lwgeom, lwgeom->bbox);
706 }
707 else if ( gbox && ! lwgeom->bbox )
708 {
709 lwgeom->bbox = gbox_clone(gbox);
710 }
711
712 if ( lwgeom_is_collection(lwgeom) )
713 {
714 uint32_t i;
715 LWCOLLECTION *lwcol = (LWCOLLECTION*)lwgeom;
716
717 for ( i = 0; i < lwcol->ngeoms; i++ )
718 {
719 lwgeom_add_bbox_deep(lwcol->geoms[i], lwgeom->bbox);
720 }
721 }
722}
723
724const GBOX *
726{
727 /* add it if not already there */
728 lwgeom_add_bbox((LWGEOM *)lwg);
729 return lwg->bbox;
730}
731
732
737int lwgeom_calculate_gbox(const LWGEOM *lwgeom, GBOX *gbox)
738{
739 gbox->flags = lwgeom->flags;
740 if( FLAGS_GET_GEODETIC(lwgeom->flags) )
741 return lwgeom_calculate_gbox_geodetic(lwgeom, gbox);
742 else
743 return lwgeom_calculate_gbox_cartesian(lwgeom, gbox);
744}
745
746void
748{
749 lwgeom->srid = SRID_UNKNOWN; /* TODO: To be changed to SRID_UNKNOWN */
750}
751
752LWGEOM *
753lwgeom_segmentize2d(const LWGEOM *lwgeom, double dist)
754{
755 switch (lwgeom->type)
756 {
757 case LINETYPE:
758 return (LWGEOM *)lwline_segmentize2d((LWLINE *)lwgeom,
759 dist);
760 case POLYGONTYPE:
761 return (LWGEOM *)lwpoly_segmentize2d((LWPOLY *)lwgeom,
762 dist);
763 case MULTILINETYPE:
764 case MULTIPOLYGONTYPE:
765 case COLLECTIONTYPE:
767 (LWCOLLECTION *)lwgeom, dist);
768
769 default:
770 return lwgeom_clone(lwgeom);
771 }
772}
773
774LWGEOM*
776{
777 return lwgeom_force_dims(geom, 0, 0);
778}
779
780LWGEOM*
782{
783 return lwgeom_force_dims(geom, 1, 0);
784}
785
786LWGEOM*
788{
789 return lwgeom_force_dims(geom, 0, 1);
790}
791
792LWGEOM*
794{
795 return lwgeom_force_dims(geom, 1, 1);
796}
797
798LWGEOM*
799lwgeom_force_dims(const LWGEOM *geom, int hasz, int hasm)
800{
801 if (!geom)
802 return NULL;
803 switch(geom->type)
804 {
805 case POINTTYPE:
806 return lwpoint_as_lwgeom(lwpoint_force_dims((LWPOINT*)geom, hasz, hasm));
807 case CIRCSTRINGTYPE:
808 case LINETYPE:
809 case TRIANGLETYPE:
810 return lwline_as_lwgeom(lwline_force_dims((LWLINE*)geom, hasz, hasm));
811 case POLYGONTYPE:
812 return lwpoly_as_lwgeom(lwpoly_force_dims((LWPOLY*)geom, hasz, hasm));
813 case COMPOUNDTYPE:
814 case CURVEPOLYTYPE:
815 case MULTICURVETYPE:
816 case MULTISURFACETYPE:
817 case MULTIPOINTTYPE:
818 case MULTILINETYPE:
819 case MULTIPOLYGONTYPE:
821 case TINTYPE:
822 case COLLECTIONTYPE:
824 default:
825 lwerror("lwgeom_force_2d: unsupported geom type: %s", lwtype_name(geom->type));
826 return NULL;
827 }
828}
829
830LWGEOM*
831lwgeom_force_sfs(LWGEOM *geom, int version)
832{
833 LWCOLLECTION *col;
834 uint32_t i;
835 LWGEOM *g;
836
837 /* SFS 1.2 version */
838 if (version == 120)
839 {
840 switch(geom->type)
841 {
842 /* SQL/MM types */
843 case CIRCSTRINGTYPE:
844 case COMPOUNDTYPE:
845 case CURVEPOLYTYPE:
846 case MULTICURVETYPE:
847 case MULTISURFACETYPE:
848 return lwgeom_stroke(geom, 32);
849
850 case COLLECTIONTYPE:
851 col = (LWCOLLECTION*)geom;
852 for ( i = 0; i < col->ngeoms; i++ )
853 col->geoms[i] = lwgeom_force_sfs((LWGEOM*)col->geoms[i], version);
854
856
857 default:
858 return (LWGEOM *)geom;
859 }
860 }
861
862
863 /* SFS 1.1 version */
864 switch(geom->type)
865 {
866 /* SQL/MM types */
867 case CIRCSTRINGTYPE:
868 case COMPOUNDTYPE:
869 case CURVEPOLYTYPE:
870 case MULTICURVETYPE:
871 case MULTISURFACETYPE:
872 return lwgeom_stroke(geom, 32);
873
874 /* SFS 1.2 types */
875 case TRIANGLETYPE:
876 g = lwpoly_as_lwgeom(lwpoly_from_lwlines((LWLINE*)geom, 0, NULL));
877 lwgeom_free(geom);
878 return g;
879
880 case TINTYPE:
881 col = (LWCOLLECTION*) geom;
882 for ( i = 0; i < col->ngeoms; i++ )
883 {
884 g = lwpoly_as_lwgeom(lwpoly_from_lwlines((LWLINE*)col->geoms[i], 0, NULL));
885 lwgeom_free(col->geoms[i]);
886 col->geoms[i] = g;
887 }
888 col->type = COLLECTIONTYPE;
889 return lwmpoly_as_lwgeom((LWMPOLY*)geom);
890
892 geom->type = COLLECTIONTYPE;
893 return (LWGEOM *)geom;
894
895 /* Collection */
896 case COLLECTIONTYPE:
897 col = (LWCOLLECTION*)geom;
898 for ( i = 0; i < col->ngeoms; i++ )
899 col->geoms[i] = lwgeom_force_sfs((LWGEOM*)col->geoms[i], version);
900
902
903 default:
904 return (LWGEOM *)geom;
905 }
906}
907
908int32_t
910{
911 if ( ! geom ) return SRID_UNKNOWN;
912 return geom->srid;
913}
914
915int
917{
918 if ( ! geom ) return LW_FALSE;
919 return FLAGS_GET_Z(geom->flags);
920}
921
922int
924{
925 if ( ! geom ) return LW_FALSE;
926 return FLAGS_GET_M(geom->flags);
927}
928
929int
931{
932 if ( ! geom ) return LW_FALSE;
933 return FLAGS_GET_SOLID(geom->flags);
934}
935
936int
938{
939 if ( ! geom ) return 0;
940 return FLAGS_NDIMS(geom->flags);
941}
942
943
944
945void
947{
948 LWPOINT *pt;
949 LWLINE *ln;
950 LWPOLY *ply;
951 LWCOLLECTION *col;
952 uint32_t i;
953
954 FLAGS_SET_GEODETIC(geom->flags, value);
955 if ( geom->bbox )
956 FLAGS_SET_GEODETIC(geom->bbox->flags, value);
957
958 switch(geom->type)
959 {
960 case POINTTYPE:
961 pt = (LWPOINT*)geom;
962 if ( pt->point )
963 FLAGS_SET_GEODETIC(pt->point->flags, value);
964 break;
965 case LINETYPE:
966 ln = (LWLINE*)geom;
967 if ( ln->points )
968 FLAGS_SET_GEODETIC(ln->points->flags, value);
969 break;
970 case POLYGONTYPE:
971 ply = (LWPOLY*)geom;
972 for ( i = 0; i < ply->nrings; i++ )
973 FLAGS_SET_GEODETIC(ply->rings[i]->flags, value);
974 break;
975 case MULTIPOINTTYPE:
976 case MULTILINETYPE:
977 case MULTIPOLYGONTYPE:
978 case COLLECTIONTYPE:
979 col = (LWCOLLECTION*)geom;
980 for ( i = 0; i < col->ngeoms; i++ )
981 lwgeom_set_geodetic(col->geoms[i], value);
982 break;
983 default:
984 lwerror("lwgeom_set_geodetic: unsupported geom type: %s", lwtype_name(geom->type));
985 return;
986 }
987}
988
989void
991{
992 uint32_t i;
993 switch (lwgeom->type)
994 {
995 LWPOINT *point;
996 LWLINE *line;
997 LWPOLY *poly;
998 LWTRIANGLE *triangle;
999 LWCOLLECTION *coll;
1000
1001 case POINTTYPE:
1002 point = (LWPOINT *)lwgeom;
1004 return;
1005 case LINETYPE:
1006 line = (LWLINE *)lwgeom;
1008 return;
1009 case POLYGONTYPE:
1010 poly = (LWPOLY *)lwgeom;
1011 for (i=0; i<poly->nrings; i++)
1013 return;
1014 case TRIANGLETYPE:
1015 triangle = (LWTRIANGLE *)lwgeom;
1017 return;
1018 case MULTIPOINTTYPE:
1019 case MULTILINETYPE:
1020 case MULTIPOLYGONTYPE:
1022 case TINTYPE:
1023 case COLLECTIONTYPE:
1024 coll = (LWCOLLECTION *)lwgeom;
1025 for (i=0; i<coll->ngeoms; i++)
1026 lwgeom_longitude_shift(coll->geoms[i]);
1027 return;
1028 default:
1029 lwerror("lwgeom_longitude_shift: unsupported geom type: %s",
1030 lwtype_name(lwgeom->type));
1031 }
1032}
1033
1034int
1036{
1037 int type = geom->type;
1038
1039 if( lwgeom_is_empty(geom) )
1040 return LW_FALSE;
1041
1042 /* Test linear types for closure */
1043 switch (type)
1044 {
1045 case LINETYPE:
1046 return lwline_is_closed((LWLINE*)geom);
1047 case POLYGONTYPE:
1048 return lwpoly_is_closed((LWPOLY*)geom);
1049 case CIRCSTRINGTYPE:
1050 return lwcircstring_is_closed((LWCIRCSTRING*)geom);
1051 case COMPOUNDTYPE:
1052 return lwcompound_is_closed((LWCOMPOUND*)geom);
1053 case TINTYPE:
1054 return lwtin_is_closed((LWTIN*)geom);
1056 return lwpsurface_is_closed((LWPSURFACE*)geom);
1057 }
1058
1059 /* Recurse into collections and see if anything is not closed */
1060 if ( lwgeom_is_collection(geom) )
1061 {
1063 uint32_t i;
1064 int closed;
1065 for ( i = 0; i < col->ngeoms; i++ )
1066 {
1067 closed = lwgeom_is_closed(col->geoms[i]);
1068 if ( ! closed )
1069 return LW_FALSE;
1070 }
1071 return LW_TRUE;
1072 }
1073
1074 /* All non-linear non-collection types we will call closed */
1075 return LW_TRUE;
1076}
1077
1078int
1080{
1081 if( ! geom ) return LW_FALSE;
1082 return lwtype_is_collection(geom->type);
1083}
1084
1086int
1088{
1089
1090 switch (type)
1091 {
1092 case MULTIPOINTTYPE:
1093 case MULTILINETYPE:
1094 case MULTIPOLYGONTYPE:
1095 case COLLECTIONTYPE:
1096 case CURVEPOLYTYPE:
1097 case COMPOUNDTYPE:
1098 case MULTICURVETYPE:
1099 case MULTISURFACETYPE:
1101 case TINTYPE:
1102 return LW_TRUE;
1103 break;
1104
1105 default:
1106 return LW_FALSE;
1107 }
1108}
1109
1113uint32_t
1115{
1116 switch (type)
1117 {
1118 case POINTTYPE:
1119 return MULTIPOINTTYPE;
1120 case LINETYPE:
1121 return MULTILINETYPE;
1122 case POLYGONTYPE:
1123 return MULTIPOLYGONTYPE;
1124 case CIRCSTRINGTYPE:
1125 return MULTICURVETYPE;
1126 case COMPOUNDTYPE:
1127 return MULTICURVETYPE;
1128 case CURVEPOLYTYPE:
1129 return MULTISURFACETYPE;
1130 case TRIANGLETYPE:
1131 return TINTYPE;
1132 default:
1133 return COLLECTIONTYPE;
1134 }
1135}
1136
1137
1138void lwgeom_free(LWGEOM *lwgeom)
1139{
1140
1141 /* There's nothing here to free... */
1142 if( ! lwgeom ) return;
1143
1144 LWDEBUGF(5,"freeing a %s",lwtype_name(lwgeom->type));
1145
1146 switch (lwgeom->type)
1147 {
1148 case POINTTYPE:
1149 lwpoint_free((LWPOINT *)lwgeom);
1150 break;
1151 case LINETYPE:
1152 lwline_free((LWLINE *)lwgeom);
1153 break;
1154 case POLYGONTYPE:
1155 lwpoly_free((LWPOLY *)lwgeom);
1156 break;
1157 case CIRCSTRINGTYPE:
1159 break;
1160 case TRIANGLETYPE:
1161 lwtriangle_free((LWTRIANGLE *)lwgeom);
1162 break;
1163 case MULTIPOINTTYPE:
1164 lwmpoint_free((LWMPOINT *)lwgeom);
1165 break;
1166 case MULTILINETYPE:
1167 lwmline_free((LWMLINE *)lwgeom);
1168 break;
1169 case MULTIPOLYGONTYPE:
1170 lwmpoly_free((LWMPOLY *)lwgeom);
1171 break;
1173 lwpsurface_free((LWPSURFACE *)lwgeom);
1174 break;
1175 case TINTYPE:
1176 lwtin_free((LWTIN *)lwgeom);
1177 break;
1178 case CURVEPOLYTYPE:
1179 case COMPOUNDTYPE:
1180 case MULTICURVETYPE:
1181 case MULTISURFACETYPE:
1182 case COLLECTIONTYPE:
1184 break;
1185 default:
1186 lwerror("lwgeom_free called with unknown type (%d) %s", lwgeom->type, lwtype_name(lwgeom->type));
1187 }
1188 return;
1189}
1190
1192{
1193 assert(geom);
1194 if ( geom->type == POINTTYPE )
1195 {
1196 return LW_FALSE;
1197 }
1198 else if ( geom->type == LINETYPE )
1199 {
1200 if ( lwgeom_count_vertices(geom) <= 2 )
1201 return LW_FALSE;
1202 else
1203 return LW_TRUE;
1204 }
1205 else if ( geom->type == MULTIPOINTTYPE )
1206 {
1207 if ( ((LWCOLLECTION*)geom)->ngeoms == 1 )
1208 return LW_FALSE;
1209 else
1210 return LW_TRUE;
1211 }
1212 else if ( geom->type == MULTILINETYPE )
1213 {
1214 if ( ((LWCOLLECTION*)geom)->ngeoms == 1 && lwgeom_count_vertices(geom) <= 2 )
1215 return LW_FALSE;
1216 else
1217 return LW_TRUE;
1218 }
1219 else
1220 {
1221 return LW_TRUE;
1222 }
1223}
1224
1229uint32_t lwgeom_count_vertices(const LWGEOM *geom)
1230{
1231 int result = 0;
1232
1233 /* Null? Zero. */
1234 if( ! geom ) return 0;
1235
1236 LWDEBUGF(4, "lwgeom_count_vertices got type %s",
1237 lwtype_name(geom->type));
1238
1239 /* Empty? Zero. */
1240 if( lwgeom_is_empty(geom) ) return 0;
1241
1242 switch (geom->type)
1243 {
1244 case POINTTYPE:
1245 result = 1;
1246 break;
1247 case TRIANGLETYPE:
1248 case CIRCSTRINGTYPE:
1249 case LINETYPE:
1250 result = lwline_count_vertices((LWLINE *)geom);
1251 break;
1252 case POLYGONTYPE:
1253 result = lwpoly_count_vertices((LWPOLY *)geom);
1254 break;
1255 case COMPOUNDTYPE:
1256 case CURVEPOLYTYPE:
1257 case MULTICURVETYPE:
1258 case MULTISURFACETYPE:
1259 case MULTIPOINTTYPE:
1260 case MULTILINETYPE:
1261 case MULTIPOLYGONTYPE:
1263 case TINTYPE:
1264 case COLLECTIONTYPE:
1265 result = lwcollection_count_vertices((LWCOLLECTION *)geom);
1266 break;
1267 default:
1268 lwerror("%s: unsupported input geometry type: %s",
1269 __func__, lwtype_name(geom->type));
1270 break;
1271 }
1272 LWDEBUGF(3, "counted %d vertices", result);
1273 return result;
1274}
1275
1281int lwgeom_dimension(const LWGEOM *geom)
1282{
1283
1284 /* Null? Zero. */
1285 if( ! geom ) return -1;
1286
1287 LWDEBUGF(4, "lwgeom_dimension got type %s",
1288 lwtype_name(geom->type));
1289
1290 /* Empty? Zero. */
1291 /* if( lwgeom_is_empty(geom) ) return 0; */
1292
1293 switch (geom->type)
1294 {
1295 case POINTTYPE:
1296 case MULTIPOINTTYPE:
1297 return 0;
1298 case CIRCSTRINGTYPE:
1299 case LINETYPE:
1300 case COMPOUNDTYPE:
1301 case MULTICURVETYPE:
1302 case MULTILINETYPE:
1303 return 1;
1304 case TRIANGLETYPE:
1305 case POLYGONTYPE:
1306 case CURVEPOLYTYPE:
1307 case MULTISURFACETYPE:
1308 case MULTIPOLYGONTYPE:
1309 case TINTYPE:
1310 return 2;
1312 {
1313 /* A closed polyhedral surface contains a volume. */
1314 int closed = lwpsurface_is_closed((LWPSURFACE*)geom);
1315 return ( closed ? 3 : 2 );
1316 }
1317 case COLLECTIONTYPE:
1318 {
1319 int maxdim = 0;
1320 uint32_t i;
1321 LWCOLLECTION *col = (LWCOLLECTION*)geom;
1322 for( i = 0; i < col->ngeoms; i++ )
1323 {
1324 int dim = lwgeom_dimension(col->geoms[i]);
1325 maxdim = ( dim > maxdim ? dim : maxdim );
1326 }
1327 return maxdim;
1328 }
1329 default:
1330 lwerror("%s: unsupported input geometry type: %s",
1331 __func__, lwtype_name(geom->type));
1332 }
1333 return -1;
1334}
1335
1339uint32_t lwgeom_count_rings(const LWGEOM *geom)
1340{
1341 int result = 0;
1342
1343 /* Null? Empty? Zero. */
1344 if( ! geom || lwgeom_is_empty(geom) )
1345 return 0;
1346
1347 switch (geom->type)
1348 {
1349 case POINTTYPE:
1350 case CIRCSTRINGTYPE:
1351 case COMPOUNDTYPE:
1352 case MULTICURVETYPE:
1353 case MULTIPOINTTYPE:
1354 case MULTILINETYPE:
1355 case LINETYPE:
1356 result = 0;
1357 break;
1358 case TRIANGLETYPE:
1359 result = 1;
1360 break;
1361 case POLYGONTYPE:
1362 result = ((LWPOLY *)geom)->nrings;
1363 break;
1364 case CURVEPOLYTYPE:
1365 result = ((LWCURVEPOLY *)geom)->nrings;
1366 break;
1367 case MULTISURFACETYPE:
1368 case MULTIPOLYGONTYPE:
1370 case TINTYPE:
1371 case COLLECTIONTYPE:
1372 {
1373 LWCOLLECTION *col = (LWCOLLECTION*)geom;
1374 uint32_t i = 0;
1375 for( i = 0; i < col->ngeoms; i++ )
1376 result += lwgeom_count_rings(col->geoms[i]);
1377 break;
1378 }
1379 default:
1380 lwerror("lwgeom_count_rings: unsupported input geometry type: %s", lwtype_name(geom->type));
1381 break;
1382 }
1383 LWDEBUGF(3, "counted %d rings", result);
1384 return result;
1385}
1386
1387int lwgeom_has_srid(const LWGEOM *geom)
1388{
1389 if ( geom->srid != SRID_UNKNOWN )
1390 return LW_TRUE;
1391
1392 return LW_FALSE;
1393}
1394
1395
1397{
1398 uint32_t i;
1399 int dimensionality = 0;
1400 for ( i = 0; i < col->ngeoms; i++ )
1401 {
1402 int d = lwgeom_dimensionality(col->geoms[i]);
1403 if ( d > dimensionality )
1404 dimensionality = d;
1405 }
1406 return dimensionality;
1407}
1408
1409extern int lwgeom_dimensionality(const LWGEOM *geom)
1410{
1411 int dim;
1412
1413 LWDEBUGF(3, "lwgeom_dimensionality got type %s",
1414 lwtype_name(geom->type));
1415
1416 switch (geom->type)
1417 {
1418 case POINTTYPE:
1419 case MULTIPOINTTYPE:
1420 return 0;
1421 break;
1422 case LINETYPE:
1423 case CIRCSTRINGTYPE:
1424 case MULTILINETYPE:
1425 case COMPOUNDTYPE:
1426 case MULTICURVETYPE:
1427 return 1;
1428 break;
1429 case POLYGONTYPE:
1430 case TRIANGLETYPE:
1431 case CURVEPOLYTYPE:
1432 case MULTIPOLYGONTYPE:
1433 case MULTISURFACETYPE:
1434 return 2;
1435 break;
1436
1438 case TINTYPE:
1439 dim = lwgeom_is_closed(geom)?3:2;
1440 return dim;
1441 break;
1442
1443 case COLLECTIONTYPE:
1444 return lwcollection_dimensionality((const LWCOLLECTION *)geom);
1445 break;
1446 default:
1447 lwerror("lwgeom_dimensionality: unsupported input geometry type: %s",
1448 lwtype_name(geom->type));
1449 break;
1450 }
1451 return 0;
1452}
1453
1454extern LWGEOM* lwgeom_remove_repeated_points(const LWGEOM *in, double tolerance)
1455{
1456 LWGEOM *out = lwgeom_clone_deep(in);
1458 return out;
1459}
1460
1462{
1463 LWCOLLECTION *col;
1464 LWPOLY *poly;
1465 uint32_t i;
1466
1467 if ( (!in) || lwgeom_is_empty(in) ) return;
1468
1469 /* TODO: check for lwgeom NOT having the specified dimension ? */
1470
1471 LWDEBUGF(4, "lwgeom_flip_coordinates, got type: %s",
1472 lwtype_name(in->type));
1473
1474 switch (in->type)
1475 {
1476 case POINTTYPE:
1477 ptarray_swap_ordinates(lwgeom_as_lwpoint(in)->point, o1, o2);
1478 break;
1479
1480 case LINETYPE:
1481 ptarray_swap_ordinates(lwgeom_as_lwline(in)->points, o1, o2);
1482 break;
1483
1484 case CIRCSTRINGTYPE:
1486 break;
1487
1488 case POLYGONTYPE:
1489 poly = (LWPOLY *) in;
1490 for (i=0; i<poly->nrings; i++)
1491 {
1492 ptarray_swap_ordinates(poly->rings[i], o1, o2);
1493 }
1494 break;
1495
1496 case TRIANGLETYPE:
1497 ptarray_swap_ordinates(lwgeom_as_lwtriangle(in)->points, o1, o2);
1498 break;
1499
1500 case MULTIPOINTTYPE:
1501 case MULTILINETYPE:
1502 case MULTIPOLYGONTYPE:
1503 case COLLECTIONTYPE:
1504 case COMPOUNDTYPE:
1505 case CURVEPOLYTYPE:
1506 case MULTISURFACETYPE:
1507 case MULTICURVETYPE:
1509 case TINTYPE:
1510 col = (LWCOLLECTION *) in;
1511 for (i=0; i<col->ngeoms; i++)
1512 {
1513 lwgeom_swap_ordinates(col->geoms[i], o1, o2);
1514 }
1515 break;
1516
1517 default:
1518 lwerror("lwgeom_swap_ordinates: unsupported geometry type: %s",
1519 lwtype_name(in->type));
1520 return;
1521 }
1522
1523 /* only refresh bbox if X or Y changed */
1524 if ( in->bbox && (o1 < 2 || o2 < 2) )
1525 {
1527 }
1528}
1529
1530void lwgeom_set_srid(LWGEOM *geom, int32_t srid)
1531{
1532 uint32_t i;
1533
1534 LWDEBUGF(4,"entered with srid=%d",srid);
1535
1536 geom->srid = srid;
1537
1538 if ( lwgeom_is_collection(geom) )
1539 {
1540 /* All the children are set to the same SRID value */
1542 for ( i = 0; i < col->ngeoms; i++ )
1543 {
1544 lwgeom_set_srid(col->geoms[i], srid);
1545 }
1546 }
1547}
1548
1549
1550/**************************************************************/
1551
1552
1553int
1555{
1556 int geometry_modified = LW_FALSE;
1557 switch (geom->type)
1558 {
1559 /* No-op! Cannot remote points */
1560 case POINTTYPE:
1561 case TRIANGLETYPE:
1562 return geometry_modified;
1563 case LINETYPE:
1564 {
1565 LWLINE *g = (LWLINE*)(geom);
1566 POINTARRAY *pa = g->points;
1567 uint32_t npoints = pa->npoints;
1569 geometry_modified = npoints != pa->npoints;
1570 /* Invalid output */
1571 if (pa->npoints == 1 && pa->maxpoints > 1)
1572 {
1573 /* Use first point as last point */
1574 pa->npoints = 2;
1575 ptarray_copy_point(pa, 0, 1);
1576 }
1577 break;
1578 }
1579 case POLYGONTYPE:
1580 {
1581 uint32_t i, j = 0;
1582 LWPOLY *g = (LWPOLY*)(geom);
1583 for (i = 0; i < g->nrings; i++)
1584 {
1585 POINTARRAY *pa = g->rings[i];
1586 int minpoints = 4;
1587 uint32_t npoints = 0;
1588 /* Skip zero'ed out rings */
1589 if(!pa)
1590 continue;
1591 npoints = pa->npoints;
1592 ptarray_remove_repeated_points_in_place(pa, tolerance, minpoints);
1593 geometry_modified |= npoints != pa->npoints;
1594 /* Drop collapsed rings */
1595 if(pa->npoints < 4)
1596 {
1597 geometry_modified = LW_TRUE;
1598 ptarray_free(pa);
1599 continue;
1600 }
1601 g->rings[j++] = pa;
1602 }
1603 /* Update ring count */
1604 g->nrings = j;
1605 break;
1606 }
1607 case MULTIPOINTTYPE:
1608 {
1609 static uint32_t out_stack_size = 32;
1610 double tolsq = tolerance*tolerance;
1611 uint32_t i, j, n = 0;
1612 LWMPOINT *mpt = (LWMPOINT *)(geom);
1613 LWPOINT **out;
1614 LWPOINT *out_stack[out_stack_size];
1615 int use_heap = (mpt->ngeoms > out_stack_size);
1616
1617 /* No-op on empty */
1618 if (mpt->ngeoms < 2)
1619 return geometry_modified;
1620
1621 /* We cannot write directly back to the multipoint */
1622 /* geoms array because we're reading out of it still */
1623 /* so we use a side array */
1624 if (use_heap)
1625 out = lwalloc(sizeof(LWMPOINT *) * mpt->ngeoms);
1626 else
1627 out = out_stack;
1628
1629 /* Inefficient O(n^2) implementation */
1630 for (i = 0; i < mpt->ngeoms; i++)
1631 {
1632 int seen = 0;
1633 LWPOINT *p1 = mpt->geoms[i];
1634 const POINT2D *pt1 = getPoint2d_cp(p1->point, 0);
1635 for (j = 0; j < n; j++)
1636 {
1637 LWPOINT *p2 = out[j];
1638 const POINT2D *pt2 = getPoint2d_cp(p2->point, 0);
1639 if (distance2d_sqr_pt_pt(pt1, pt2) <= tolsq)
1640 {
1641 seen = 1;
1642 break;
1643 }
1644 }
1645 if (seen)
1646 {
1647 lwpoint_free(p1);
1648 continue;
1649 }
1650 out[n++] = p1;
1651 }
1652
1653 /* Copy remaining points back into the input */
1654 /* array */
1655 memcpy(mpt->geoms, out, sizeof(LWPOINT *) * n);
1656 geometry_modified = mpt->ngeoms != n;
1657 mpt->ngeoms = n;
1658 if (use_heap) lwfree(out);
1659 break;
1660 }
1661
1662 case CIRCSTRINGTYPE:
1663 /* Dunno how to handle these, will return untouched */
1664 return geometry_modified;
1665
1666 /* Can process most multi* types as generic collection */
1667 case MULTILINETYPE:
1668 case MULTIPOLYGONTYPE:
1669 case TINTYPE:
1670 case COLLECTIONTYPE:
1671 /* Curve types we mostly ignore, but allow the linear */
1672 /* portions to be processed by recursing into them */
1673 case MULTICURVETYPE:
1674 case CURVEPOLYTYPE:
1675 case MULTISURFACETYPE:
1676 case COMPOUNDTYPE:
1677 {
1678 uint32_t i, j = 0;
1679 LWCOLLECTION *col = (LWCOLLECTION*)(geom);
1680 for (i = 0; i < col->ngeoms; i++)
1681 {
1682 LWGEOM *g = col->geoms[i];
1683 if (!g) continue;
1684 geometry_modified |= lwgeom_remove_repeated_points_in_place(g, tolerance);
1685 /* Drop zero'ed out geometries */
1686 if(lwgeom_is_empty(g))
1687 {
1688 lwgeom_free(g);
1689 continue;
1690 }
1691 col->geoms[j++] = g;
1692 }
1693 /* Update geometry count */
1694 col->ngeoms = j;
1695 break;
1696 }
1697 default:
1698 {
1699 lwerror("%s: unsupported geometry type: %s", __func__, lwtype_name(geom->type));
1700 break;
1701 }
1702 }
1703
1704 if (geometry_modified)
1705 {
1706 lwgeom_drop_bbox(geom);
1707 }
1708 return geometry_modified;
1709}
1710
1711
1712/**************************************************************/
1713
1714int
1715lwgeom_simplify_in_place(LWGEOM *geom, double epsilon, int preserve_collapsed)
1716{
1717 int modified = LW_FALSE;
1718 switch (geom->type)
1719 {
1720 /* No-op! Cannot simplify points or triangles */
1721 case POINTTYPE:
1722 return modified;
1723 case TRIANGLETYPE:
1724 {
1725 if (preserve_collapsed)
1726 return modified;
1728 POINTARRAY *pa = t->points;
1729 ptarray_simplify_in_place(pa, epsilon, 0);
1730 if (pa->npoints < 3)
1731 {
1732 pa->npoints = 0;
1733 modified = LW_TRUE;
1734 }
1735 break;
1736 }
1737 case LINETYPE:
1738 {
1739 LWLINE *g = (LWLINE*)(geom);
1740 POINTARRAY *pa = g->points;
1741 uint32_t in_npoints = pa->npoints;
1742 ptarray_simplify_in_place(pa, epsilon, 2);
1743 modified = in_npoints != pa->npoints;
1744 /* Invalid output */
1745 if (pa->npoints == 1 && pa->maxpoints > 1)
1746 {
1747 /* Use first point as last point */
1748 if (preserve_collapsed)
1749 {
1750 pa->npoints = 2;
1751 ptarray_copy_point(pa, 0, 1);
1752 }
1753 /* Finish the collapse process */
1754 else
1755 {
1756 pa->npoints = 0;
1757 }
1758 }
1759 /* Duped output, force collapse */
1760 if (pa->npoints == 2 && !preserve_collapsed)
1761 {
1762 if (p2d_same(getPoint2d_cp(pa, 0), getPoint2d_cp(pa, 1)))
1763 pa->npoints = 0;
1764 }
1765 break;
1766 }
1767 case POLYGONTYPE:
1768 {
1769 uint32_t i, j = 0;
1770 LWPOLY *g = (LWPOLY*)(geom);
1771 for (i = 0; i < g->nrings; i++)
1772 {
1773 POINTARRAY *pa = g->rings[i];
1774 /* Only stop collapse on first ring */
1775 int minpoints = (preserve_collapsed && i == 0) ? 4 : 0;
1776 /* Skip zero'ed out rings */
1777 if(!pa)
1778 continue;
1779 uint32_t in_npoints = pa->npoints;
1780 ptarray_simplify_in_place(pa, epsilon, minpoints);
1781 modified |= in_npoints != pa->npoints;
1782 /* Drop collapsed rings */
1783 if(pa->npoints < 4)
1784 {
1785 if (i == 0)
1786 {
1787 /* If the outter ring is dropped, all can be dropped */
1788 for (i = 0; i < g->nrings; i++)
1789 {
1790 pa = g->rings[i];
1791 ptarray_free(pa);
1792 }
1793 break;
1794 }
1795 else
1796 {
1797 /* Drop this inner ring only */
1798 ptarray_free(pa);
1799 continue;
1800 }
1801 }
1802 g->rings[j++] = pa;
1803 }
1804 /* Update ring count */
1805 g->nrings = j;
1806 break;
1807 }
1808 /* Can process all multi* types as generic collection */
1809 case MULTIPOINTTYPE:
1810 case MULTILINETYPE:
1811 case MULTIPOLYGONTYPE:
1812 case TINTYPE:
1813 case COLLECTIONTYPE:
1814 {
1815 uint32_t i, j = 0;
1816 LWCOLLECTION *col = (LWCOLLECTION*)geom;
1817 for (i = 0; i < col->ngeoms; i++)
1818 {
1819 LWGEOM *g = col->geoms[i];
1820 if (!g) continue;
1821 modified |= lwgeom_simplify_in_place(g, epsilon, preserve_collapsed);
1822 /* Drop zero'ed out geometries */
1823 if(lwgeom_is_empty(g))
1824 {
1825 lwgeom_free(g);
1826 continue;
1827 }
1828 col->geoms[j++] = g;
1829 }
1830 /* Update geometry count */
1831 col->ngeoms = j;
1832 break;
1833 }
1834 default:
1835 {
1836 lwerror("%s: unsupported geometry type: %s", __func__, lwtype_name(geom->type));
1837 break;
1838 }
1839 }
1840
1841 if (modified)
1842 {
1843 lwgeom_drop_bbox(geom);
1844 }
1845 return modified;
1846}
1847
1848LWGEOM* lwgeom_simplify(const LWGEOM *igeom, double dist, int preserve_collapsed)
1849{
1850 LWGEOM *lwgeom_out = lwgeom_clone_deep(igeom);
1851 lwgeom_simplify_in_place(lwgeom_out, dist, preserve_collapsed);
1852 if (lwgeom_is_empty(lwgeom_out))
1853 {
1854 lwgeom_free(lwgeom_out);
1855 return NULL;
1856 }
1857 return lwgeom_out;
1858}
1859
1860/**************************************************************/
1861
1862
1863double lwgeom_area(const LWGEOM *geom)
1864{
1865 int type = geom->type;
1866
1867 if ( type == POLYGONTYPE )
1868 return lwpoly_area((LWPOLY*)geom);
1869 else if ( type == CURVEPOLYTYPE )
1870 return lwcurvepoly_area((LWCURVEPOLY*)geom);
1871 else if (type == TRIANGLETYPE )
1872 return lwtriangle_area((LWTRIANGLE*)geom);
1873 else if ( lwgeom_is_collection(geom) )
1874 {
1875 double area = 0.0;
1876 uint32_t i;
1877 LWCOLLECTION *col = (LWCOLLECTION*)geom;
1878 for ( i = 0; i < col->ngeoms; i++ )
1879 area += lwgeom_area(col->geoms[i]);
1880 return area;
1881 }
1882 else
1883 return 0.0;
1884}
1885
1886double lwgeom_perimeter(const LWGEOM *geom)
1887{
1888 int type = geom->type;
1889 if ( type == POLYGONTYPE )
1890 return lwpoly_perimeter((LWPOLY*)geom);
1891 else if ( type == CURVEPOLYTYPE )
1892 return lwcurvepoly_perimeter((LWCURVEPOLY*)geom);
1893 else if ( type == TRIANGLETYPE )
1894 return lwtriangle_perimeter((LWTRIANGLE*)geom);
1895 else if ( lwgeom_is_collection(geom) )
1896 {
1897 double perimeter = 0.0;
1898 uint32_t i;
1899 LWCOLLECTION *col = (LWCOLLECTION*)geom;
1900 for ( i = 0; i < col->ngeoms; i++ )
1901 perimeter += lwgeom_perimeter(col->geoms[i]);
1902 return perimeter;
1903 }
1904 else
1905 return 0.0;
1906}
1907
1908double lwgeom_perimeter_2d(const LWGEOM *geom)
1909{
1910 int type = geom->type;
1911 if ( type == POLYGONTYPE )
1912 return lwpoly_perimeter_2d((LWPOLY*)geom);
1913 else if ( type == CURVEPOLYTYPE )
1915 else if ( type == TRIANGLETYPE )
1916 return lwtriangle_perimeter_2d((LWTRIANGLE*)geom);
1917 else if ( lwgeom_is_collection(geom) )
1918 {
1919 double perimeter = 0.0;
1920 uint32_t i;
1921 LWCOLLECTION *col = (LWCOLLECTION*)geom;
1922 for ( i = 0; i < col->ngeoms; i++ )
1923 perimeter += lwgeom_perimeter_2d(col->geoms[i]);
1924 return perimeter;
1925 }
1926 else
1927 return 0.0;
1928}
1929
1930double lwgeom_length(const LWGEOM *geom)
1931{
1932 int type = geom->type;
1933 if ( type == LINETYPE )
1934 return lwline_length((LWLINE*)geom);
1935 else if ( type == CIRCSTRINGTYPE )
1936 return lwcircstring_length((LWCIRCSTRING*)geom);
1937 else if ( type == COMPOUNDTYPE )
1938 return lwcompound_length((LWCOMPOUND*)geom);
1939 else if ( lwgeom_is_collection(geom) )
1940 {
1941 double length = 0.0;
1942 uint32_t i;
1943 LWCOLLECTION *col = (LWCOLLECTION*)geom;
1944 for ( i = 0; i < col->ngeoms; i++ )
1945 length += lwgeom_length(col->geoms[i]);
1946 return length;
1947 }
1948 else
1949 return 0.0;
1950}
1951
1952double lwgeom_length_2d(const LWGEOM *geom)
1953{
1954 int type = geom->type;
1955 if ( type == LINETYPE )
1956 return lwline_length_2d((LWLINE*)geom);
1957 else if ( type == CIRCSTRINGTYPE )
1958 return lwcircstring_length_2d((LWCIRCSTRING*)geom);
1959 else if ( type == COMPOUNDTYPE )
1960 return lwcompound_length_2d((LWCOMPOUND*)geom);
1961 else if ( lwgeom_is_collection(geom) )
1962 {
1963 double length = 0.0;
1964 uint32_t i;
1965 LWCOLLECTION *col = (LWCOLLECTION*)geom;
1966 for ( i = 0; i < col->ngeoms; i++ )
1967 length += lwgeom_length_2d(col->geoms[i]);
1968 return length;
1969 }
1970 else
1971 return 0.0;
1972}
1973
1974void
1975lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
1976{
1977 int type = geom->type;
1978 uint32_t i;
1979
1980 switch(type)
1981 {
1982 /* Take advantage of fact tht pt/ln/circ/tri have same memory structure */
1983 case POINTTYPE:
1984 case LINETYPE:
1985 case CIRCSTRINGTYPE:
1986 case TRIANGLETYPE:
1987 {
1988 LWLINE *l = (LWLINE*)geom;
1989 ptarray_affine(l->points, affine);
1990 break;
1991 }
1992 case POLYGONTYPE:
1993 {
1994 LWPOLY *p = (LWPOLY*)geom;
1995 for( i = 0; i < p->nrings; i++ )
1996 ptarray_affine(p->rings[i], affine);
1997 break;
1998 }
1999 case CURVEPOLYTYPE:
2000 {
2001 LWCURVEPOLY *c = (LWCURVEPOLY*)geom;
2002 for( i = 0; i < c->nrings; i++ )
2003 lwgeom_affine(c->rings[i], affine);
2004 break;
2005 }
2006 default:
2007 {
2008 if( lwgeom_is_collection(geom) )
2009 {
2010 LWCOLLECTION *c = (LWCOLLECTION*)geom;
2011 for( i = 0; i < c->ngeoms; i++ )
2012 {
2013 lwgeom_affine(c->geoms[i], affine);
2014 }
2015 }
2016 else
2017 {
2018 lwerror("lwgeom_affine: unable to handle type '%s'", lwtype_name(type));
2019 }
2020 }
2021 }
2022
2023 /* Recompute bbox if needed */
2024 if (geom->bbox)
2025 lwgeom_refresh_bbox(geom);
2026}
2027
2028void
2029lwgeom_scale(LWGEOM *geom, const POINT4D *factor)
2030{
2031 int type = geom->type;
2032 uint32_t i;
2033
2034 switch(type)
2035 {
2036 /* Take advantage of fact tht pt/ln/circ/tri have same memory structure */
2037 case POINTTYPE:
2038 case LINETYPE:
2039 case CIRCSTRINGTYPE:
2040 case TRIANGLETYPE:
2041 {
2042 LWLINE *l = (LWLINE*)geom;
2043 ptarray_scale(l->points, factor);
2044 break;
2045 }
2046 case POLYGONTYPE:
2047 {
2048 LWPOLY *p = (LWPOLY*)geom;
2049 for( i = 0; i < p->nrings; i++ )
2050 ptarray_scale(p->rings[i], factor);
2051 break;
2052 }
2053 case CURVEPOLYTYPE:
2054 {
2055 LWCURVEPOLY *c = (LWCURVEPOLY*)geom;
2056 for( i = 0; i < c->nrings; i++ )
2057 lwgeom_scale(c->rings[i], factor);
2058 break;
2059 }
2060 default:
2061 {
2062 if( lwgeom_is_collection(geom) )
2063 {
2064 LWCOLLECTION *c = (LWCOLLECTION*)geom;
2065 for( i = 0; i < c->ngeoms; i++ )
2066 {
2067 lwgeom_scale(c->geoms[i], factor);
2068 }
2069 }
2070 else
2071 {
2072 lwerror("lwgeom_scale: unable to handle type '%s'", lwtype_name(type));
2073 }
2074 }
2075 }
2076
2077 /* Recompute bbox if needed */
2078 if (geom->bbox)
2079 lwgeom_refresh_bbox(geom);
2080}
2081
2082LWGEOM *
2083lwgeom_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
2084{
2085 switch(type)
2086 {
2087 case POINTTYPE:
2088 return lwpoint_as_lwgeom(lwpoint_construct_empty(srid, hasz, hasm));
2089 case LINETYPE:
2090 return lwline_as_lwgeom(lwline_construct_empty(srid, hasz, hasm));
2091 case POLYGONTYPE:
2092 return lwpoly_as_lwgeom(lwpoly_construct_empty(srid, hasz, hasm));
2093 case CURVEPOLYTYPE:
2094 return lwcurvepoly_as_lwgeom(lwcurvepoly_construct_empty(srid, hasz, hasm));
2095 case CIRCSTRINGTYPE:
2096 return lwcircstring_as_lwgeom(lwcircstring_construct_empty(srid, hasz, hasm));
2097 case TRIANGLETYPE:
2098 return lwtriangle_as_lwgeom(lwtriangle_construct_empty(srid, hasz, hasm));
2099 case COMPOUNDTYPE:
2100 case MULTIPOINTTYPE:
2101 case MULTILINETYPE:
2102 case MULTIPOLYGONTYPE:
2103 case COLLECTIONTYPE:
2104 return lwcollection_as_lwgeom(lwcollection_construct_empty(type, srid, hasz, hasm));
2105 default:
2106 lwerror("lwgeom_construct_empty: unsupported geometry type: %s",
2107 lwtype_name(type));
2108 return NULL;
2109 }
2110}
2111
2112int
2114{
2115 if ( ! lwgeom )
2116 return LW_FAILURE;
2117
2118 switch( lwgeom->type )
2119 {
2120 case POINTTYPE:
2121 return ptarray_startpoint(((LWPOINT*)lwgeom)->point, pt);
2122 case TRIANGLETYPE:
2123 case CIRCSTRINGTYPE:
2124 case LINETYPE:
2125 return ptarray_startpoint(((LWLINE*)lwgeom)->points, pt);
2126 case POLYGONTYPE:
2127 return lwpoly_startpoint((LWPOLY*)lwgeom, pt);
2128 case TINTYPE:
2129 case CURVEPOLYTYPE:
2130 case COMPOUNDTYPE:
2131 case MULTIPOINTTYPE:
2132 case MULTILINETYPE:
2133 case MULTIPOLYGONTYPE:
2134 case COLLECTIONTYPE:
2136 return lwcollection_startpoint((LWCOLLECTION*)lwgeom, pt);
2137 default:
2138 lwerror("lwgeom_startpoint: unsupported geometry type: %s", lwtype_name(lwgeom->type));
2139 return LW_FAILURE;
2140 }
2141}
2142
2143void
2145{
2146 if (!geom) return;
2147 if (lwgeom_is_empty(geom)) return;
2148 switch ( geom->type )
2149 {
2150 case POINTTYPE:
2151 {
2152 LWPOINT *pt = (LWPOINT*)(geom);
2153 ptarray_grid_in_place(pt->point, grid);
2154 return;
2155 }
2156 case CIRCSTRINGTYPE:
2157 case TRIANGLETYPE:
2158 case LINETYPE:
2159 {
2160 LWLINE *ln = (LWLINE*)(geom);
2161 ptarray_grid_in_place(ln->points, grid);
2162 /* For invalid line, return an EMPTY */
2163 if (ln->points->npoints < 2)
2164 ln->points->npoints = 0;
2165 return;
2166 }
2167 case POLYGONTYPE:
2168 {
2169 LWPOLY *ply = (LWPOLY*)(geom);
2170 if (!ply->rings) return;
2171
2172 /* Check first the external ring */
2173 uint32_t i = 0;
2174 POINTARRAY *pa = ply->rings[0];
2175 ptarray_grid_in_place(pa, grid);
2176 if (pa->npoints < 4)
2177 {
2178 /* External ring collapsed: free everything */
2179 for (i = 0; i < ply->nrings; i++)
2180 {
2181 ptarray_free(ply->rings[i]);
2182 }
2183 ply->nrings = 0;
2184 return;
2185 }
2186
2187 /* Check the other rings */
2188 uint32_t j = 1;
2189 for (i = 1; i < ply->nrings; i++)
2190 {
2191 POINTARRAY *pa = ply->rings[i];
2192 ptarray_grid_in_place(pa, grid);
2193
2194 /* Skip bad rings */
2195 if (pa->npoints >= 4)
2196 {
2197 ply->rings[j++] = pa;
2198 }
2199 else
2200 {
2201 ptarray_free(pa);
2202 }
2203 }
2204 /* Adjust ring count appropriately */
2205 ply->nrings = j;
2206 return;
2207 }
2208 case MULTIPOINTTYPE:
2209 case MULTILINETYPE:
2210 case MULTIPOLYGONTYPE:
2211 case TINTYPE:
2212 case COLLECTIONTYPE:
2213 case COMPOUNDTYPE:
2214 {
2215 LWCOLLECTION *col = (LWCOLLECTION*)(geom);
2216 uint32_t i, j = 0;
2217 if (!col->geoms) return;
2218 for (i = 0; i < col->ngeoms; i++)
2219 {
2220 LWGEOM *g = col->geoms[i];
2221 lwgeom_grid_in_place(g, grid);
2222 /* Empty geoms need to be freed */
2223 /* before we move on */
2224 if (lwgeom_is_empty(g))
2225 {
2226 lwgeom_free(g);
2227 continue;
2228 }
2229 col->geoms[j++] = g;
2230 }
2231 col->ngeoms = j;
2232 return;
2233 }
2234 default:
2235 {
2236 lwerror("%s: Unsupported geometry type: %s", __func__,
2237 lwtype_name(geom->type));
2238 return;
2239 }
2240 }
2241}
2242
2243
2244LWGEOM *
2245lwgeom_grid(const LWGEOM *lwgeom, const gridspec *grid)
2246{
2247 LWGEOM *lwgeom_out = lwgeom_clone_deep(lwgeom);
2248 lwgeom_grid_in_place(lwgeom_out, grid);
2249 return lwgeom_out;
2250}
2251
2252
2253/* Prototype for recursion */
2254static void lwgeom_subdivide_recursive(const LWGEOM *geom,
2255 uint8_t dimension,
2256 uint32_t maxvertices,
2257 uint32_t depth,
2258 LWCOLLECTION *col);
2259
2260static void
2262 uint8_t dimension,
2263 uint32_t maxvertices,
2264 uint32_t depth,
2265 LWCOLLECTION *col)
2266{
2267 const uint32_t maxdepth = 50;
2268
2269 if (!geom)
2270 return;
2271
2272 const GBOX *box_in = lwgeom_get_bbox(geom);
2273 if (!box_in)
2274 return;
2275
2276 GBOX clip;
2277 gbox_duplicate(box_in, &clip);
2278 double width = clip.xmax - clip.xmin;
2279 double height = clip.ymax - clip.ymin;
2280
2281 if ( geom->type == POLYHEDRALSURFACETYPE || geom->type == TINTYPE )
2282 lwerror("%s: unsupported geometry type '%s'", __func__, lwtype_name(geom->type));
2283
2284 if ( width == 0.0 && height == 0.0 )
2285 {
2286 if ( geom->type == POINTTYPE && dimension == 0)
2288 return;
2289 }
2290
2291 if (width == 0.0)
2292 {
2293 clip.xmax += FP_TOLERANCE;
2294 clip.xmin -= FP_TOLERANCE;
2295 width = 2 * FP_TOLERANCE;
2296 }
2297 if (height == 0.0)
2298 {
2299 clip.ymax += FP_TOLERANCE;
2300 clip.ymin -= FP_TOLERANCE;
2301 height = 2 * FP_TOLERANCE;
2302 }
2303
2304 /* Always just recurse into collections */
2305 if ( lwgeom_is_collection(geom) && geom->type != MULTIPOINTTYPE )
2306 {
2307 LWCOLLECTION *incol = (LWCOLLECTION*)geom;
2308 /* Don't increment depth yet, since we aren't actually
2309 * subdividing geometries yet */
2310 for (uint32_t i = 0; i < incol->ngeoms; i++ )
2311 lwgeom_subdivide_recursive(incol->geoms[i], dimension, maxvertices, depth, col);
2312 return;
2313 }
2314
2315 if (lwgeom_dimension(geom) < dimension)
2316 {
2317 /* We've hit a lower dimension object produced by clipping at
2318 * a shallower recursion level. Ignore it. */
2319 return;
2320 }
2321
2322 /* But don't go too far. 2^50 ~= 10^15, that's enough subdivision */
2323 /* Just add what's left */
2324 if ( depth > maxdepth )
2325 {
2327 return;
2328 }
2329
2330 uint32_t nvertices = lwgeom_count_vertices(geom);
2331
2332 /* Skip empties entirely */
2333 if (nvertices == 0)
2334 return;
2335
2336 /* If it is under the vertex tolerance, just add it, we're done */
2337 if (nvertices <= maxvertices)
2338 {
2340 return;
2341 }
2342
2343 uint8_t split_ordinate = (width > height) ? 0 : 1;
2344 double center = (split_ordinate == 0) ? (clip.xmin + clip.xmax) / 2 : (clip.ymin + clip.ymax) / 2;
2345 double pivot = DBL_MAX;
2346 if (geom->type == POLYGONTYPE)
2347 {
2348 uint32_t ring_to_trim = 0;
2349 double ring_area = 0;
2350 double pivot_eps = DBL_MAX;
2351 double pt_eps = DBL_MAX;
2352 POINTARRAY *pa;
2353 LWPOLY *lwpoly = (LWPOLY *)geom;
2354
2355 /* if there are more points in holes than in outer ring */
2356 if (nvertices >= 2 * lwpoly->rings[0]->npoints)
2357 {
2358 /* trim holes starting from biggest */
2359 for (uint32_t i = 1; i < lwpoly->nrings; i++)
2360 {
2361 double current_ring_area = fabs(ptarray_signed_area(lwpoly->rings[i]));
2362 if (current_ring_area >= ring_area)
2363 {
2364 ring_area = current_ring_area;
2365 ring_to_trim = i;
2366 }
2367 }
2368 }
2369
2370 pa = lwpoly->rings[ring_to_trim];
2371
2372 /* find most central point in chosen ring */
2373 for (uint32_t i = 0; i < pa->npoints; i++)
2374 {
2375 double pt;
2376 if (split_ordinate == 0)
2377 pt = getPoint2d_cp(pa, i)->x;
2378 else
2379 pt = getPoint2d_cp(pa, i)->y;
2380 pt_eps = fabs(pt - center);
2381 if (pivot_eps > pt_eps)
2382 {
2383 pivot = pt;
2384 pivot_eps = pt_eps;
2385 }
2386 }
2387 }
2388 GBOX subbox1, subbox2;
2389 gbox_duplicate(&clip, &subbox1);
2390 gbox_duplicate(&clip, &subbox2);
2391
2392 if (pivot == DBL_MAX)
2393 pivot = center;
2394
2395 if (split_ordinate == 0)
2396 {
2397 if (FP_NEQUALS(subbox1.xmax, pivot) && FP_NEQUALS(subbox1.xmin, pivot))
2398 subbox1.xmax = subbox2.xmin = pivot;
2399 else
2400 subbox1.xmax = subbox2.xmin = center;
2401 }
2402 else
2403 {
2404 if (FP_NEQUALS(subbox1.ymax, pivot) && FP_NEQUALS(subbox1.ymin, pivot))
2405 subbox1.ymax = subbox2.ymin = pivot;
2406 else
2407 subbox1.ymax = subbox2.ymin = center;
2408 }
2409
2410 ++depth;
2411
2412 {
2414 geom->srid, subbox1.xmin, subbox1.ymin, subbox1.xmax, subbox1.ymax);
2415 LWGEOM *clipped = lwgeom_intersection(geom, subbox);
2416 lwgeom_simplify_in_place(clipped, 0.0, LW_TRUE);
2417 lwgeom_free(subbox);
2418 if (clipped && !lwgeom_is_empty(clipped))
2419 {
2420 lwgeom_subdivide_recursive(clipped, dimension, maxvertices, depth, col);
2421 lwgeom_free(clipped);
2422 }
2423 }
2424 {
2426 geom->srid, subbox2.xmin, subbox2.ymin, subbox2.xmax, subbox2.ymax);
2427 LWGEOM *clipped = lwgeom_intersection(geom, subbox);
2428 lwgeom_simplify_in_place(clipped, 0.0, LW_TRUE);
2429 lwgeom_free(subbox);
2430 if (clipped && !lwgeom_is_empty(clipped))
2431 {
2432 lwgeom_subdivide_recursive(clipped, dimension, maxvertices, depth, col);
2433 lwgeom_free(clipped);
2434 }
2435 }
2436}
2437
2439lwgeom_subdivide(const LWGEOM *geom, uint32_t maxvertices)
2440{
2441 static uint32_t startdepth = 0;
2442 static uint32_t minmaxvertices = 5;
2443 LWCOLLECTION *col;
2444
2446
2447 if ( lwgeom_is_empty(geom) )
2448 return col;
2449
2450 if ( maxvertices < minmaxvertices )
2451 {
2452 lwcollection_free(col);
2453 lwerror("%s: cannot subdivide to fewer than %d vertices per output", __func__, minmaxvertices);
2454 }
2455
2456 lwgeom_subdivide_recursive(geom, lwgeom_dimension(geom), maxvertices, startdepth, col);
2457 lwgeom_set_srid((LWGEOM*)col, geom->srid);
2458 return col;
2459}
2460
2461int
2463{
2464 int type = geom->type;
2465
2466 if( type != LINETYPE )
2467 {
2468 lwnotice("Geometry is not a LINESTRING");
2469 return LW_FALSE;
2470 }
2471 return lwline_is_trajectory((LWLINE*)geom);
2472}
2473
2474static uint8_t
2475bits_for_precision(int32_t significant_digits)
2476{
2477 int32_t bits_needed = ceil(significant_digits / log10(2));
2478
2479 if (bits_needed > 52)
2480 {
2481 return 52;
2482 }
2483 else if (bits_needed < 1)
2484 {
2485 return 1;
2486 }
2487
2488 return bits_needed;
2489}
2490
2491static double trim_preserve_decimal_digits(double d, int32_t decimal_digits)
2492{
2493 if (d == 0)
2494 return 0;
2495
2496 int digits_left_of_decimal = (int) (1 + log10(fabs(d)));
2497 uint8_t bits_needed = bits_for_precision(decimal_digits + digits_left_of_decimal);
2498 uint64_t mask = 0xffffffffffffffffULL << (52 - bits_needed);
2499 uint64_t dint = 0;
2500 size_t dsz = sizeof(d) < sizeof(dint) ? sizeof(d) : sizeof(dint);
2501
2502 memcpy(&dint, &d, dsz);
2503 dint &= mask;
2504 memcpy(&d, &dint, dsz);
2505 return d;
2506}
2507
2508void lwgeom_trim_bits_in_place(LWGEOM* geom, int32_t prec_x, int32_t prec_y, int32_t prec_z, int32_t prec_m)
2509{
2511 POINT4D p;
2512
2513 while (lwpointiterator_has_next(it))
2514 {
2515 lwpointiterator_peek(it, &p);
2516 p.x = trim_preserve_decimal_digits(p.x, prec_x);
2517 p.y = trim_preserve_decimal_digits(p.y, prec_y);
2518 if (lwgeom_has_z(geom))
2519 p.z = trim_preserve_decimal_digits(p.z, prec_z);
2520 if (lwgeom_has_m(geom))
2521 p.m = trim_preserve_decimal_digits(p.m, prec_m);
2523 }
2524
2526}
2527
2528int
2530{
2532 int hasz = lwgeom_has_z(lwgeom);
2533 int hasm = lwgeom_has_m(lwgeom);
2534
2535 while (lwpointiterator_has_next(it))
2536 {
2537 POINT4D p;
2538 lwpointiterator_next(it, &p);
2539 int finite = isfinite(p.x) &&
2540 isfinite(p.y) &&
2541 (hasz ? isfinite(p.z) : 1) &&
2542 (hasm ? isfinite(p.m) : 1);
2543
2544 if (!finite)
2545 {
2547 return LW_FALSE;
2548 }
2549 }
2551 return LW_TRUE;
2552}
char * r
Definition cu_in_wkt.c:24
int gbox_same(const GBOX *g1, const GBOX *g2)
Check if 2 given Gbox are the same.
Definition gbox.c:164
void gbox_duplicate(const GBOX *original, GBOX *duplicate)
Copy the values of original GBOX into duplicate.
Definition gbox.c:433
GBOX * gbox_new(lwflags_t flags)
Create a new gbox with the dimensionality indicated by the flags.
Definition gbox.c:32
int lwgeom_calculate_gbox_cartesian(const LWGEOM *lwgeom, GBOX *gbox)
Calculate the 2-4D bounding box of a geometry.
Definition gbox.c:740
GBOX * gbox_clone(const GBOX *gbox)
Definition gbox.c:45
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition lwutil.c:216
LWCOLLECTION * lwcollection_construct(uint8_t type, int32_t srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
#define LW_FALSE
Definition liblwgeom.h:108
#define COLLECTIONTYPE
Definition liblwgeom.h:122
#define COMPOUNDTYPE
Definition liblwgeom.h:124
double distance2d_pt_pt(const POINT2D *p1, const POINT2D *p2)
Definition measures.c:2397
void lwmpoint_free(LWMPOINT *mpt)
Definition lwmpoint.c:72
void lwpoint_free(LWPOINT *pt)
Definition lwpoint.c:213
#define LW_FAILURE
Definition liblwgeom.h:110
#define CURVEPOLYTYPE
Definition liblwgeom.h:125
void lwmpoly_free(LWMPOLY *mpoly)
Definition lwmpoly.c:53
LWPOINTITERATOR * lwpointiterator_create(const LWGEOM *g)
Create a new LWPOINTITERATOR over supplied LWGEOM*.
Definition lwiterator.c:242
LWCURVEPOLY * lwcurvepoly_construct_empty(int32_t srid, char hasz, char hasm)
Definition lwcurvepoly.c:35
#define MULTILINETYPE
Definition liblwgeom.h:120
LWPOLY * lwpoly_from_lwlines(const LWLINE *shell, uint32_t nholes, const LWLINE **holes)
Definition lwpoly.c:360
int lwpointiterator_next(LWPOINTITERATOR *s, POINT4D *p)
Attempts to assign the next point in the iterator to p, and advances the iterator to the next point.
Definition lwiterator.c:210
#define MULTISURFACETYPE
Definition liblwgeom.h:127
#define LINETYPE
Definition liblwgeom.h:117
LWCURVEPOLY * lwcurvepoly_construct_from_lwpoly(LWPOLY *lwpoly)
Construct an equivalent curve polygon from a polygon.
Definition lwcurvepoly.c:52
void lwtin_free(LWTIN *tin)
Definition lwtin.c:39
int lwgeom_calculate_gbox_geodetic(const LWGEOM *geom, GBOX *gbox)
Calculate the geodetic bounding box for an LWGEOM.
LWPOINTITERATOR * lwpointiterator_create_rw(LWGEOM *g)
Create a new LWPOINTITERATOR over supplied LWGEOM* Supports modification of coordinates during iterat...
Definition lwiterator.c:251
#define WKT_EXTENDED
Definition liblwgeom.h:2132
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition lwout_wkt.c:676
#define MULTIPOINTTYPE
Definition liblwgeom.h:119
#define FLAGS_SET_BBOX(flags, value)
Definition liblwgeom.h:188
int lwpointiterator_peek(LWPOINTITERATOR *s, POINT4D *p)
Attempts to assigns the next point in the iterator to p.
Definition lwiterator.c:193
void lwpointiterator_destroy(LWPOINTITERATOR *s)
Free all memory associated with the iterator.
Definition lwiterator.c:267
LWCOLLECTION * lwcollection_segmentize2d(const LWCOLLECTION *coll, double dist)
LWPOLY * lwpoly_construct_envelope(int32_t srid, double x1, double y1, double x2, double y2)
Definition lwpoly.c:98
LWTRIANGLE * lwtriangle_construct_empty(int32_t srid, char hasz, char hasm)
Definition lwtriangle.c:58
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition liblwgeom.h:116
#define FLAGS_GET_Z(flags)
Definition liblwgeom.h:179
void * lwalloc(size_t size)
Definition lwutil.c:227
LWGEOM * lwgeom_intersection(const LWGEOM *geom1, const LWGEOM *geom2)
#define TINTYPE
Definition liblwgeom.h:130
#define MULTIPOLYGONTYPE
Definition liblwgeom.h:121
int lwpointiterator_modify_next(LWPOINTITERATOR *s, const POINT4D *p)
Attempts to replace the next point int the iterator with p, and advances the iterator to the next poi...
Definition lwiterator.c:224
void lwfree(void *mem)
Definition lwutil.c:242
#define FLAGS_NDIMS(flags)
Definition liblwgeom.h:193
#define POLYGONTYPE
Definition liblwgeom.h:118
void lwcircstring_free(LWCIRCSTRING *curve)
LWCOMPOUND * lwcompound_construct_from_lwline(const LWLINE *lwpoly)
Construct an equivalent compound curve from a linestring.
Definition lwcompound.c:204
void lwtriangle_free(LWTRIANGLE *triangle)
Definition lwtriangle.c:69
#define POLYHEDRALSURFACETYPE
Definition liblwgeom.h:128
#define CIRCSTRINGTYPE
Definition liblwgeom.h:123
LWPOLY * lwpoly_segmentize2d(const LWPOLY *line, double dist)
Definition lwpoly.c:312
LWPOINT * lwpoint_construct_empty(int32_t srid, char hasz, char hasm)
Definition lwpoint.c:151
#define FLAGS_GET_M(flags)
Definition liblwgeom.h:180
void lwcollection_free(LWCOLLECTION *col)
void ptarray_free(POINTARRAY *pa)
Definition ptarray.c:327
LWLINE * lwline_segmentize2d(const LWLINE *line, double dist)
Definition lwline.c:132
#define FLAGS_GET_SOLID(flags)
Definition liblwgeom.h:184
#define FLAGS_GET_ZM(flags)
Definition liblwgeom.h:194
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
int lwpointiterator_has_next(LWPOINTITERATOR *s)
Returns LW_TRUE if there is another point available in the iterator.
Definition lwiterator.c:202
#define MULTICURVETYPE
Definition liblwgeom.h:126
#define TRIANGLETYPE
Definition liblwgeom.h:129
LWCIRCSTRING * lwcircstring_construct_empty(int32_t srid, char hasz, char hasm)
#define FLAGS_SET_GEODETIC(flags, value)
Definition liblwgeom.h:189
void lwpsurface_free(LWPSURFACE *psurf)
Definition lwpsurface.c:39
void lwpoly_free(LWPOLY *poly)
Definition lwpoly.c:175
void lwmline_free(LWMLINE *mline)
Definition lwmline.c:112
#define LW_TRUE
Return types for functions with status returns.
Definition liblwgeom.h:107
int lwline_is_trajectory(const LWLINE *geom)
Definition lwline.c:454
LWGEOM * lwgeom_stroke(const LWGEOM *geom, uint32_t perQuad)
Definition lwstroke.c:859
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
LWPOLY * lwpoly_construct_empty(int32_t srid, char hasz, char hasm)
Definition lwpoly.c:161
#define SRID_UNKNOWN
Unknown SRID value.
Definition liblwgeom.h:229
LWLINE * lwline_construct_empty(int32_t srid, char hasz, char hasm)
Definition lwline.c:55
#define NUMTYPES
Definition liblwgeom.h:132
void lwline_free(LWLINE *line)
Definition lwline.c:67
#define FLAGS_GET_GEODETIC(flags)
Definition liblwgeom.h:182
enum LWORD_T LWORD
Ordinate names.
double lwline_length_2d(const LWLINE *line)
Definition lwline.c:517
void ptarray_longitude_shift(POINTARRAY *pa)
Longitude shift for a pointarray.
Definition ptarray.c:1423
LWPOLY * lwpoly_clone(const LWPOLY *lwgeom)
Definition lwpoly.c:213
double lwcircstring_length_2d(const LWCIRCSTRING *circ)
int lwcircstring_is_closed(const LWCIRCSTRING *curve)
LWPOLY * lwpoly_force_dims(const LWPOLY *lwpoly, int hasz, int hasm)
Definition lwpoly.c:394
LWPOINT * lwpoint_clone(const LWPOINT *lwgeom)
Definition lwpoint.c:239
void ptarray_reverse_in_place(POINTARRAY *pa)
Definition ptarray.c:339
char lwcollection_same(const LWCOLLECTION *p1, const LWCOLLECTION *p2)
check for same geometry composition
double lwtriangle_area(const LWTRIANGLE *triangle)
Find the area of the outer ring.
Definition lwtriangle.c:178
double lwcompound_length_2d(const LWCOMPOUND *comp)
Definition lwcompound.c:74
uint32_t lwpoly_count_vertices(LWPOLY *poly)
Definition lwpoly.c:418
double ptarray_signed_area(const POINTARRAY *pa)
Returns the area in cartesian units.
Definition ptarray.c:1003
int lwline_is_closed(const LWLINE *line)
Definition lwline.c:445
LWCIRCSTRING * lwcircstring_clone(const LWCIRCSTRING *curve)
char lwtriangle_same(const LWTRIANGLE *p1, const LWTRIANGLE *p2)
Definition lwtriangle.c:126
int lwpoly_startpoint(const LWPOLY *lwpoly, POINT4D *pt)
Definition lwpoly.c:524
LWCOLLECTION * lwcollection_clone_deep(const LWCOLLECTION *lwgeom)
Deep clone LWCOLLECTION object.
int lwcollection_startpoint(const LWCOLLECTION *col, POINT4D *pt)
int ptarray_startpoint(const POINTARRAY *pa, POINT4D *pt)
Definition ptarray.c:1971
int lwcompound_is_closed(const LWCOMPOUND *curve)
Definition lwcompound.c:35
double lwtriangle_perimeter_2d(const LWTRIANGLE *triangle)
Definition lwtriangle.c:210
int lwpoly_is_clockwise(LWPOLY *poly)
Definition lwpoly.c:288
void ptarray_grid_in_place(POINTARRAY *pa, const gridspec *grid)
Snap to grid.
Definition ptarray.c:1986
double lwpoly_area(const LWPOLY *poly)
Find the area of the outer ring - sum (area of inner rings).
Definition lwpoly.c:434
int lwtriangle_is_clockwise(LWTRIANGLE *triangle)
Definition lwtriangle.c:113
char lwline_same(const LWLINE *p1, const LWLINE *p2)
Definition lwline.c:141
void ptarray_remove_repeated_points_in_place(POINTARRAY *pa, double tolerance, uint32_t min_points)
Definition ptarray.c:1460
double lwtriangle_perimeter(const LWTRIANGLE *triangle)
Definition lwtriangle.c:201
void ptarray_simplify_in_place(POINTARRAY *pa, double tolerance, uint32_t minpts)
Definition ptarray.c:1595
double lwcompound_length(const LWCOMPOUND *comp)
Definition lwcompound.c:69
void lwtriangle_force_clockwise(LWTRIANGLE *triangle)
Definition lwtriangle.c:106
LWCOLLECTION * lwcollection_clone(const LWCOLLECTION *lwgeom)
Clone LWCOLLECTION object.
#define FP_TOLERANCE
Floating point comparators.
void ptarray_scale(POINTARRAY *pa, const POINT4D *factor)
WARNING, make sure you send in only 16-member double arrays or obviously things will go pear-shaped f...
Definition ptarray.c:1953
LWLINE * lwline_clone(const LWLINE *lwgeom)
Definition lwline.c:93
LWCOLLECTION * lwcollection_force_dims(const LWCOLLECTION *lwcol, int hasz, int hasm)
void ptarray_affine(POINTARRAY *pa, const AFFINE *affine)
Affine transform a pointarray.
Definition ptarray.c:1766
int lwpsurface_is_closed(const LWPSURFACE *psurface)
Definition lwpsurface.c:99
LWPOINT * lwpoint_force_dims(const LWPOINT *lwpoint, int hasz, int hasm)
Definition lwpoint.c:271
double lwcurvepoly_perimeter(const LWCURVEPOLY *poly)
LWTRIANGLE * lwtriangle_clone(const LWTRIANGLE *lwgeom)
Definition lwtriangle.c:99
char lwpoly_same(const LWPOLY *p1, const LWPOLY *p2)
Definition lwpoly.c:339
double lwline_length(const LWLINE *line)
Definition lwline.c:510
LWLINE * lwline_clone_deep(const LWLINE *lwgeom)
Definition lwline.c:109
void lwpoly_force_clockwise(LWPOLY *poly)
Definition lwpoly.c:268
void ptarray_swap_ordinates(POINTARRAY *pa, LWORD o1, LWORD o2)
Swap ordinate values o1 and o2 on a given POINTARRAY.
Definition ptarray.c:387
LWPOLY * lwpoly_clone_deep(const LWPOLY *lwgeom)
Definition lwpoly.c:228
double lwpoly_perimeter_2d(const LWPOLY *poly)
Compute the sum of polygon rings length (forcing 2d computation).
Definition lwpoly.c:485
LWLINE * lwline_force_dims(const LWLINE *lwline, int hasz, int hasm)
Definition lwline.c:483
int lwtin_is_closed(const LWTIN *tin)
Definition lwtin.c:93
char lwcircstring_same(const LWCIRCSTRING *p1, const LWCIRCSTRING *p2)
double lwcircstring_length(const LWCIRCSTRING *circ)
uint32_t lwcollection_count_vertices(LWCOLLECTION *col)
double lwcurvepoly_area(const LWCURVEPOLY *curvepoly)
This should be rewritten to make use of the curve itself.
int lwpoly_is_closed(const LWPOLY *poly)
Definition lwpoly.c:499
void ptarray_copy_point(POINTARRAY *pa, uint32_t from, uint32_t to)
Definition lwgeom_api.c:401
uint32_t lwline_count_vertices(LWLINE *line)
Definition lwline.c:502
double lwcurvepoly_perimeter_2d(const LWCURVEPOLY *poly)
double lwpoly_perimeter(const LWPOLY *poly)
Compute the sum of polygon rings length.
Definition lwpoly.c:467
#define FP_NEQUALS(A, B)
char lwpoint_same(const LWPOINT *p1, const LWPOINT *p2)
Definition lwpoint.c:264
int p2d_same(const POINT2D *p1, const POINT2D *p2)
Definition lwalgorithm.c:50
LWGEOM * lwgeom_force_dims(const LWGEOM *geom, int hasz, int hasm)
Definition lwgeom.c:799
int lwgeom_is_closed(const LWGEOM *geom)
Return true or false depending on whether a geometry is a linear feature that closes on itself.
Definition lwgeom.c:1035
LWGEOM * lwmpoint_as_lwgeom(const LWMPOINT *obj)
Definition lwgeom.c:286
void lwgeom_refresh_bbox(LWGEOM *lwgeom)
Drop current bbox and calculate a fresh one.
Definition lwgeom.c:689
static double trim_preserve_decimal_digits(double d, int32_t decimal_digits)
Definition lwgeom.c:2491
void lwgeom_set_geodetic(LWGEOM *geom, int value)
Set the FLAGS geodetic bit on geometry an all sub-geometries and pointlists.
Definition lwgeom.c:946
LWGEOM * lwgeom_force_3dm(const LWGEOM *geom)
Definition lwgeom.c:787
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition lwgeom.c:326
char lwgeom_same(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)
geom1 same as geom2 iff
Definition lwgeom.c:573
LWTIN * lwgeom_as_lwtin(const LWGEOM *lwgeom)
Definition lwgeom.c:259
int lwgeom_ndims(const LWGEOM *geom)
Return the number of dimensions (2, 3, 4) in a geometry.
Definition lwgeom.c:937
uint32_t lwtype_get_collectiontype(uint8_t type)
Given an lwtype number, what homogeneous collection can hold it?
Definition lwgeom.c:1114
int32_t lwgeom_get_srid(const LWGEOM *geom)
Return SRID number.
Definition lwgeom.c:909
int lwgeom_startpoint(const LWGEOM *lwgeom, POINT4D *pt)
Definition lwgeom.c:2113
int lwgeom_is_collection(const LWGEOM *geom)
Determine whether a LWGEOM can contain sub-geometries or not.
Definition lwgeom.c:1079
LWGEOM * lwtin_as_lwgeom(const LWTIN *obj)
Definition lwgeom.c:266
void lwgeom_set_srid(LWGEOM *geom, int32_t srid)
Set the SRID on an LWGEOM For collections, only the parent gets an SRID, all the children get SRID_UN...
Definition lwgeom.c:1530
void lwgeom_trim_bits_in_place(LWGEOM *geom, int32_t prec_x, int32_t prec_y, int32_t prec_z, int32_t prec_m)
Trim the bits of an LWGEOM in place, to optimize it for compression.
Definition lwgeom.c:2508
void lwgeom_longitude_shift(LWGEOM *lwgeom)
Definition lwgeom.c:990
LWGEOM * lwgeom_as_multi(const LWGEOM *lwgeom)
Create a new LWGEOM of the appropriate MULTI* type.
Definition lwgeom.c:362
LWGEOM * lwgeom_simplify(const LWGEOM *igeom, double dist, int preserve_collapsed)
Simplification.
Definition lwgeom.c:1848
double lwgeom_perimeter_2d(const LWGEOM *geom)
Definition lwgeom.c:1908
int lwpoint_inside_circle(const LWPOINT *p, double cx, double cy, double rad)
Definition lwgeom.c:644
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
Definition lwgeom.c:215
static uint8_t bits_for_precision(int32_t significant_digits)
Definition lwgeom.c:2475
LWGEOM * lwcompound_as_lwgeom(const LWCOMPOUND *obj)
Definition lwgeom.c:306
int lwgeom_is_trajectory(const LWGEOM *geom)
Return LW_TRUE or LW_FALSE depending on whether or not a geometry is a linestring with measure value ...
Definition lwgeom.c:2462
LWGEOM * lwgeom_as_curve(const LWGEOM *lwgeom)
Create a new LWGEOM of the appropriate CURVE* type.
Definition lwgeom.c:402
LWGEOM * lwpsurface_as_lwgeom(const LWPSURFACE *obj)
Definition lwgeom.c:271
LWGEOM * lwgeom_segmentize2d(const LWGEOM *lwgeom, double dist)
Definition lwgeom.c:753
LWGEOM * lwgeom_force_sfs(LWGEOM *geom, int version)
Definition lwgeom.c:831
int lwgeom_has_srid(const LWGEOM *geom)
Return true or false depending on whether a geometry has a valid SRID set.
Definition lwgeom.c:1387
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
Definition lwgeom.c:775
double lwgeom_length(const LWGEOM *geom)
Definition lwgeom.c:1930
int lwgeom_needs_bbox(const LWGEOM *geom)
Check whether or not a lwgeom is big enough to warrant a bounding box.
Definition lwgeom.c:1191
int lwgeom_remove_repeated_points_in_place(LWGEOM *geom, double tolerance)
Definition lwgeom.c:1554
LWGEOM * lwgeom_clone(const LWGEOM *lwgeom)
Clone LWGEOM object.
Definition lwgeom.c:473
LWCURVEPOLY * lwgeom_as_lwcurvepoly(const LWGEOM *lwgeom)
Definition lwgeom.c:188
char * lwgeom_to_ewkt(const LWGEOM *lwgeom)
Return an alloced string.
Definition lwgeom.c:547
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition lwgeom.c:916
int lwtype_is_collection(uint8_t type)
Return TRUE if the geometry may contain sub-geometries, i.e.
Definition lwgeom.c:1087
void lwgeom_drop_bbox(LWGEOM *lwgeom)
Call this function to drop BBOX and SRID from LWGEOM.
Definition lwgeom.c:664
int lwgeom_isfinite(const LWGEOM *lwgeom)
Check if a LWGEOM has any non-finite (NaN or Inf) coordinates.
Definition lwgeom.c:2529
static int lwcollection_dimensionality(const LWCOLLECTION *col)
Definition lwgeom.c:1396
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
Definition lwgeom.c:197
double lwgeom_area(const LWGEOM *geom)
Definition lwgeom.c:1863
uint32_t lwgeom_count_vertices(const LWGEOM *geom)
Count points in an LWGEOM.
Definition lwgeom.c:1229
LWGEOM * lwcurvepoly_as_lwgeom(const LWCURVEPOLY *obj)
Definition lwgeom.c:301
int lwgeom_dimension(const LWGEOM *geom)
For an LWGEOM, returns 0 for points, 1 for lines, 2 for polygons, 3 for volume, and the max dimension...
Definition lwgeom.c:1281
LWTRIANGLE * lwgeom_as_lwtriangle(const LWGEOM *lwgeom)
Definition lwgeom.c:206
LWCOMPOUND * lwgeom_as_lwcompound(const LWGEOM *lwgeom)
Definition lwgeom.c:179
LWGEOM * lwtriangle_as_lwgeom(const LWTRIANGLE *obj)
Definition lwgeom.c:316
LWGEOM * lwgeom_force_3dz(const LWGEOM *geom)
Definition lwgeom.c:781
void lwgeom_swap_ordinates(LWGEOM *in, LWORD o1, LWORD o2)
Swap ordinate values in every vertex of the geometry.
Definition lwgeom.c:1461
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition lwgeom.c:321
void lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
Definition lwgeom.c:1975
LWMLINE * lwgeom_as_lwmline(const LWGEOM *lwgeom)
Definition lwgeom.c:233
uint8_t lwtype_multitype(uint8_t type)
Definition lwgeom.c:352
LWMPOLY * lwgeom_as_lwmpoly(const LWGEOM *lwgeom)
Definition lwgeom.c:242
LWCIRCSTRING * lwgeom_as_lwcircstring(const LWGEOM *lwgeom)
Definition lwgeom.c:170
double lwgeom_length_2d(const LWGEOM *geom)
Definition lwgeom.c:1952
uint32_t lwgeom_count_rings(const LWGEOM *geom)
Count rings in an LWGEOM.
Definition lwgeom.c:1339
LWGEOM * lwgeom_grid(const LWGEOM *lwgeom, const gridspec *grid)
Definition lwgeom.c:2245
static void lwgeom_subdivide_recursive(const LWGEOM *geom, uint8_t dimension, uint32_t maxvertices, uint32_t depth, LWCOLLECTION *col)
Definition lwgeom.c:2261
void lwgeom_reverse_in_place(LWGEOM *geom)
Reverse vertex order of LWGEOM.
Definition lwgeom.c:102
void lwgeom_force_clockwise(LWGEOM *lwgeom)
Force Right-hand-rule on LWGEOM polygons.
Definition lwgeom.c:37
int lwgeom_is_solid(const LWGEOM *geom)
Return LW_TRUE if geometry has SOLID flag.
Definition lwgeom.c:930
LWGEOM * lwmline_as_lwgeom(const LWMLINE *obj)
Definition lwgeom.c:281
uint8_t MULTITYPE[NUMTYPES]
Look-up for the correct MULTI* type promotion for singleton types.
Definition lwgeom.c:336
LWGEOM * lwcircstring_as_lwgeom(const LWCIRCSTRING *obj)
Definition lwgeom.c:296
int lwgeom_calculate_gbox(const LWGEOM *lwgeom, GBOX *gbox)
Calculate the gbox for this geometry, a cartesian box or geodetic box, depending on how it is flagged...
Definition lwgeom.c:737
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition lwgeom.c:161
LWGEOM * lwgeom_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
Definition lwgeom.c:2083
void lwgeom_add_bbox_deep(LWGEOM *lwgeom, GBOX *gbox)
Compute a box for geom and all sub-geometries, if not already computed.
Definition lwgeom.c:696
LWMPOINT * lwgeom_as_lwmpoint(const LWGEOM *lwgeom)
Definition lwgeom.c:224
int lwgeom_dimensionality(const LWGEOM *geom)
Return the dimensionality (relating to point/line/poly) of an lwgeom.
Definition lwgeom.c:1409
void lwgeom_free(LWGEOM *lwgeom)
Definition lwgeom.c:1138
LWCOLLECTION * lwgeom_subdivide(const LWGEOM *geom, uint32_t maxvertices)
Definition lwgeom.c:2439
LWPSURFACE * lwgeom_as_lwpsurface(const LWGEOM *lwgeom)
Definition lwgeom.c:251
void lwgeom_release(LWGEOM *lwgeom)
Free the containing LWGEOM and the associated BOX.
Definition lwgeom.c:450
double lwgeom_perimeter(const LWGEOM *geom)
Definition lwgeom.c:1886
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition lwgeom.c:923
void lwgeom_scale(LWGEOM *geom, const POINT4D *factor)
Definition lwgeom.c:2029
LWGEOM * lwmpoly_as_lwgeom(const LWMPOLY *obj)
Definition lwgeom.c:276
int lwgeom_is_clockwise(LWGEOM *lwgeom)
Check clockwise orientation on LWGEOM polygons.
Definition lwgeom.c:65
int lwgeom_simplify_in_place(LWGEOM *geom, double epsilon, int preserve_collapsed)
Definition lwgeom.c:1715
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition lwgeom.c:311
void lwgeom_add_bbox(LWGEOM *lwgeom)
Ensure there's a box in the LWGEOM.
Definition lwgeom.c:677
LWGEOM * lwgeom_force_4d(const LWGEOM *geom)
Definition lwgeom.c:793
const GBOX * lwgeom_get_bbox(const LWGEOM *lwg)
Get a non-empty geometry bounding box, computing and caching it if not already there.
Definition lwgeom.c:725
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition lwgeom.c:291
LWGEOM * lwgeom_remove_repeated_points(const LWGEOM *in, double tolerance)
Definition lwgeom.c:1454
void lwgeom_drop_srid(LWGEOM *lwgeom)
Definition lwgeom.c:747
void lwgeom_grid_in_place(LWGEOM *geom, const gridspec *grid)
Definition lwgeom.c:2144
LWGEOM * lwgeom_clone_deep(const LWGEOM *lwgeom)
Deep-clone an LWGEOM object.
Definition lwgeom.c:511
LWGEOM * lwgeom_reverse(const LWGEOM *geom)
Definition lwgeom.c:93
#define LWDEBUG(level, msg)
Definition lwgeom_log.h:83
#define LWDEBUGF(level, msg,...)
Definition lwgeom_log.h:88
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition lwutil.c:190
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
Definition lwutil.c:177
static double distance2d_sqr_pt_pt(const POINT2D *p1, const POINT2D *p2)
Definition lwinline.h:35
static LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Definition lwinline.h:121
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
Definition lwinline.h:193
static const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition lwinline.h:91
static double pivot(double *left, double *right)
double ymax
Definition liblwgeom.h:343
double xmax
Definition liblwgeom.h:341
double ymin
Definition liblwgeom.h:342
double xmin
Definition liblwgeom.h:340
lwflags_t flags
Definition liblwgeom.h:339
uint32_t ngeoms
Definition liblwgeom.h:566
uint8_t type
Definition liblwgeom.h:564
LWGEOM ** geoms
Definition liblwgeom.h:561
LWGEOM ** rings
Definition liblwgeom.h:589
uint32_t nrings
Definition liblwgeom.h:594
uint8_t type
Definition liblwgeom.h:448
GBOX * bbox
Definition liblwgeom.h:444
int32_t srid
Definition liblwgeom.h:446
lwflags_t flags
Definition liblwgeom.h:447
POINTARRAY * points
Definition liblwgeom.h:469
uint8_t type
Definition liblwgeom.h:472
uint32_t ngeoms
Definition liblwgeom.h:524
LWPOINT ** geoms
Definition liblwgeom.h:519
POINTARRAY * point
Definition liblwgeom.h:457
uint8_t type
Definition liblwgeom.h:460
POINTARRAY ** rings
Definition liblwgeom.h:505
uint32_t nrings
Definition liblwgeom.h:510
POINTARRAY * points
Definition liblwgeom.h:481
double y
Definition liblwgeom.h:376
double x
Definition liblwgeom.h:376
double m
Definition liblwgeom.h:400
double x
Definition liblwgeom.h:400
double z
Definition liblwgeom.h:400
double y
Definition liblwgeom.h:400
lwflags_t flags
Definition liblwgeom.h:417
uint32_t maxpoints
Definition liblwgeom.h:414
uint32_t npoints
Definition liblwgeom.h:413
Snap-to-grid.
Definition liblwgeom.h:1341