PostGIS 3.6.2dev-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#define out_stack_size 32
35
37void
39{
40 LWCOLLECTION *coll;
41 uint32_t i;
42
43 switch (lwgeom->type)
44 {
45 case POLYGONTYPE:
47 return;
48
49 case TRIANGLETYPE:
51 return;
52
53 /* Not handle POLYHEDRALSURFACE and TIN
54 as they are supposed to be well oriented */
56 case COLLECTIONTYPE:
57 coll = (LWCOLLECTION *)lwgeom;
58 for (i=0; i<coll->ngeoms; i++)
60 return;
61 }
62}
63
65int
67{
68 switch (lwgeom->type)
69 {
70 case POLYGONTYPE:
71 return lwpoly_is_clockwise((LWPOLY *)lwgeom);
72
73 case TRIANGLETYPE:
74 return lwtriangle_is_clockwise((LWTRIANGLE *)lwgeom);
75
77 case COLLECTIONTYPE:
78 {
79 uint32_t i;
80 LWCOLLECTION* coll = (LWCOLLECTION *)lwgeom;
81
82 for (i=0; i < coll->ngeoms; i++)
83 if (!lwgeom_is_clockwise(coll->geoms[i]))
84 return LW_FALSE;
85 return LW_TRUE;
86 }
87 default:
88 return LW_TRUE;
89 return LW_FALSE;
90 }
91}
92
93LWGEOM *
95{
96 LWGEOM *geomout = lwgeom_clone_deep(geom);
98 return geomout;
99}
100
102void
104{
105 uint32_t i;
106 LWCOLLECTION *col;
107 if (!geom)
108 return;
109
110 switch (geom->type)
111 {
112 case MULTIPOINTTYPE:
113 case POINTTYPE:
114 {
115 return;
116 }
117 case TRIANGLETYPE:
118 case CIRCSTRINGTYPE:
119 case LINETYPE:
120 {
121 LWLINE *line = (LWLINE *)(geom);
123 return;
124 }
125 case POLYGONTYPE:
126 {
127 LWPOLY *poly = (LWPOLY *)(geom);
128 if (!poly->rings)
129 return;
130 uint32_t r;
131 for (r = 0; r < poly->nrings; r++)
133 return;
134 }
135 /* CompoundCurve needs to also reverse the sub-geometries */
136 /* so that the end-points remain coincident */
137 case COMPOUNDTYPE:
138 {
139 uint32_t ngeoms;
140 col = (LWCOLLECTION *)(geom);
141 if (!col->geoms)
142 return;
143 ngeoms = col->ngeoms;
144 for (i=0; i<ngeoms; i++)
146 for (i=0; i<col->ngeoms/2; i++) {
147 LWGEOM* tmp = col->geoms[i];
148 col->geoms[i] = col->geoms[ngeoms-i-1];
149 col->geoms[ngeoms-i-1] = tmp;
150 }
151 return;
152 }
153 case MULTICURVETYPE:
154 case MULTILINETYPE:
155 case MULTIPOLYGONTYPE:
156 case MULTISURFACETYPE:
158 case TINTYPE:
159 case COLLECTIONTYPE:
160 case CURVEPOLYTYPE:
161 {
162 col = (LWCOLLECTION *)(geom);
163 if (!col->geoms)
164 return;
165 for (i=0; i<col->ngeoms; i++)
167 return;
168 }
169 default:
170 {
171 lwerror("%s: Unknown geometry type: %s", __func__, lwtype_name(geom->type));
172 return;
173 }
174
175 }
176}
177
178LWLINE *
180{
181 if ( lwgeom == NULL ) return NULL;
182 if ( lwgeom->type == LINETYPE )
183 return (LWLINE *)lwgeom;
184 else return NULL;
185}
186
189{
190 if ( lwgeom == NULL ) return NULL;
191 if ( lwgeom->type == CIRCSTRINGTYPE )
192 return (LWCIRCSTRING *)lwgeom;
193 else return NULL;
194}
195
198{
199 if ( lwgeom == NULL ) return NULL;
200 if ( lwgeom->type == COMPOUNDTYPE )
201 return (LWCOMPOUND *)lwgeom;
202 else return NULL;
203}
204
207{
208 if ( lwgeom == NULL ) return NULL;
209 if ( lwgeom->type == CURVEPOLYTYPE )
210 return (LWCURVEPOLY *)lwgeom;
211 else return NULL;
212}
213
214LWPOLY *
216{
217 if ( lwgeom == NULL ) return NULL;
218 if ( lwgeom->type == POLYGONTYPE )
219 return (LWPOLY *)lwgeom;
220 else return NULL;
221}
222
225{
226 if ( lwgeom == NULL ) return NULL;
227 if ( lwgeom->type == TRIANGLETYPE )
228 return (LWTRIANGLE *)lwgeom;
229 else return NULL;
230}
231
234{
235 if ( lwgeom == NULL ) return NULL;
236 if ( lwgeom_is_collection(lwgeom) )
237 return (LWCOLLECTION*)lwgeom;
238 else return NULL;
239}
240
241LWMPOINT *
243{
244 if ( lwgeom == NULL ) return NULL;
245 if ( lwgeom->type == MULTIPOINTTYPE )
246 return (LWMPOINT *)lwgeom;
247 else return NULL;
248}
249
250LWMLINE *
252{
253 if ( lwgeom == NULL ) return NULL;
254 if ( lwgeom->type == MULTILINETYPE )
255 return (LWMLINE *)lwgeom;
256 else return NULL;
257}
258
259LWMPOLY *
261{
262 if ( lwgeom == NULL ) return NULL;
263 if ( lwgeom->type == MULTIPOLYGONTYPE )
264 return (LWMPOLY *)lwgeom;
265 else return NULL;
266}
267
270{
271 if ( lwgeom->type == POLYHEDRALSURFACETYPE )
272 return (LWPSURFACE *)lwgeom;
273 else return NULL;
274}
275
276LWTIN *
278{
279 if ( lwgeom->type == TINTYPE )
280 return (LWTIN *)lwgeom;
281 else return NULL;
282}
283
285{
286 return (LWGEOM *)obj;
287}
288
290{
291 return (LWGEOM *)obj;
292}
293
295{
296 if ( obj == NULL ) return NULL;
297 return (LWGEOM *)obj;
298}
300{
301 if ( obj == NULL ) return NULL;
302 return (LWGEOM *)obj;
303}
305{
306 if ( obj == NULL ) return NULL;
307 return (LWGEOM *)obj;
308}
310{
311 if ( obj == NULL ) return NULL;
312 return (LWGEOM *)obj;
313}
315{
316 if ( obj == NULL ) return NULL;
317 return (LWGEOM *)obj;
318}
320{
321 if ( obj == NULL ) return NULL;
322 return (LWGEOM *)obj;
323}
325{
326 if ( obj == NULL ) return NULL;
327 return (LWGEOM *)obj;
328}
330{
331 if ( obj == NULL ) return NULL;
332 return (LWGEOM *)obj;
333}
335{
336 if ( obj == NULL ) return NULL;
337 return (LWGEOM *)obj;
338}
340{
341 if ( obj == NULL ) return NULL;
342 return (LWGEOM *)obj;
343}
345{
346 if ( obj == NULL ) return NULL;
347 return (LWGEOM *)obj;
348}
349
350
355{
356 0,
357 MULTIPOINTTYPE, /* 1 */
358 MULTILINETYPE, /* 2 */
359 MULTIPOLYGONTYPE, /* 3 */
360 0,0,0,0,
361 MULTICURVETYPE, /* 8 */
362 MULTICURVETYPE, /* 9 */
363 MULTISURFACETYPE, /* 10 */
364 POLYHEDRALSURFACETYPE, /* 11 */
365 0, 0,
366 TINTYPE, /* 14 */
367 0
368};
369
370uint8_t lwtype_multitype(uint8_t type)
371{
372 if (type > 15) return 0;
373 return MULTITYPE[type];
374}
375
379LWGEOM *
381{
382 LWGEOM **ogeoms;
383 LWGEOM *ogeom = NULL;
384 GBOX *box = NULL;
385 int type;
386
387 type = lwgeom->type;
388
389 if ( ! MULTITYPE[type] ) return lwgeom_clone(lwgeom);
390
391 if( lwgeom_is_empty(lwgeom) )
392 {
394 MULTITYPE[type],
395 lwgeom->srid,
396 FLAGS_GET_Z(lwgeom->flags),
397 FLAGS_GET_M(lwgeom->flags)
398 );
399 }
400 else
401 {
402 ogeoms = lwalloc(sizeof(LWGEOM*));
403 ogeoms[0] = lwgeom_clone(lwgeom);
404
405 /* Sub-geometries are not allowed to have bboxes or SRIDs, move the bbox to the collection */
406 box = ogeoms[0]->bbox;
407 ogeoms[0]->bbox = NULL;
408 ogeoms[0]->srid = SRID_UNKNOWN;
409
410 ogeom = (LWGEOM *)lwcollection_construct(MULTITYPE[type], lwgeom->srid, box, 1, ogeoms);
411 }
412
413 return ogeom;
414}
415
419LWGEOM *
421{
422 LWGEOM *ogeom;
423 int type = lwgeom->type;
424 /*
425 int hasz = FLAGS_GET_Z(lwgeom->flags);
426 int hasm = FLAGS_GET_M(lwgeom->flags);
427 int32_t srid = lwgeom->srid;
428 */
429
430 switch(type)
431 {
432 case LINETYPE:
433 /* turn to COMPOUNDCURVE */
435 break;
436 case POLYGONTYPE:
438 break;
439 case MULTILINETYPE:
440 /* turn to MULTICURVE */
441 ogeom = lwgeom_clone(lwgeom);
442 ogeom->type = MULTICURVETYPE;
443 break;
444 case MULTIPOLYGONTYPE:
445 /* turn to MULTISURFACE */
446 ogeom = lwgeom_clone(lwgeom);
447 ogeom->type = MULTISURFACETYPE;
448 break;
449 case COLLECTIONTYPE:
450 default:
451 ogeom = lwgeom_clone(lwgeom);
452 break;
453 }
454
455 /* TODO: copy bbox from input geom ? */
456
457 return ogeom;
458}
459
460
467void
469{
470 if ( ! lwgeom )
471 lwerror("lwgeom_release: someone called on 0x0");
472
473 LWDEBUGF(3, "releasing type %s", lwtype_name(lwgeom->type));
474
475 /* Drop bounding box (always a copy) */
476 if ( lwgeom->bbox )
477 {
478 LWDEBUGF(3, "lwgeom_release: releasing bbox. %p", lwgeom->bbox);
479 lwfree(lwgeom->bbox);
480 }
481 lwfree(lwgeom);
482
483}
484
485
486/* @brief Clone LWGEOM object. Serialized point lists are not copied.
487 *
488 * @see ptarray_clone
489 */
490LWGEOM *
491lwgeom_clone(const LWGEOM *lwgeom)
492{
493 LWDEBUGF(2, "lwgeom_clone called with %p, %s",
494 lwgeom, lwtype_name(lwgeom->type));
495
496 switch (lwgeom->type)
497 {
498 case POINTTYPE:
499 return (LWGEOM *)lwpoint_clone((LWPOINT *)lwgeom);
500 case LINETYPE:
501 return (LWGEOM *)lwline_clone((LWLINE *)lwgeom);
502 case CIRCSTRINGTYPE:
503 return (LWGEOM *)lwcircstring_clone((LWCIRCSTRING *)lwgeom);
504 case POLYGONTYPE:
505 return (LWGEOM *)lwpoly_clone((LWPOLY *)lwgeom);
506 case TRIANGLETYPE:
507 return (LWGEOM *)lwtriangle_clone((LWTRIANGLE *)lwgeom);
508 case COMPOUNDTYPE:
509 case CURVEPOLYTYPE:
510 case MULTICURVETYPE:
511 case MULTISURFACETYPE:
512 case MULTIPOINTTYPE:
513 case MULTILINETYPE:
514 case MULTIPOLYGONTYPE:
516 case TINTYPE:
517 case COLLECTIONTYPE:
518 return (LWGEOM *)lwcollection_clone((LWCOLLECTION *)lwgeom);
519 default:
520 lwerror("lwgeom_clone: Unknown geometry type: %s", lwtype_name(lwgeom->type));
521 return NULL;
522 }
523}
524
528LWGEOM *
530{
531 LWDEBUGF(2, "lwgeom_clone called with %p, %s",
532 lwgeom, lwtype_name(lwgeom->type));
533
534 switch (lwgeom->type)
535 {
536 case POINTTYPE:
537 case LINETYPE:
538 case CIRCSTRINGTYPE:
539 case TRIANGLETYPE:
540 return (LWGEOM *)lwline_clone_deep((LWLINE *)lwgeom);
541 case POLYGONTYPE:
542 return (LWGEOM *)lwpoly_clone_deep((LWPOLY *)lwgeom);
543 case COMPOUNDTYPE:
544 case CURVEPOLYTYPE:
545 case MULTICURVETYPE:
546 case MULTISURFACETYPE:
547 case MULTIPOINTTYPE:
548 case MULTILINETYPE:
549 case MULTIPOLYGONTYPE:
551 case TINTYPE:
552 case COLLECTIONTYPE:
553 return (LWGEOM *)lwcollection_clone_deep((LWCOLLECTION *)lwgeom);
554 default:
555 lwerror("lwgeom_clone_deep: Unknown geometry type: %s", lwtype_name(lwgeom->type));
556 return NULL;
557 }
558}
559
560
564char*
565lwgeom_to_ewkt(const LWGEOM *lwgeom)
566{
567 char* wkt = NULL;
568 size_t wkt_size = 0;
569
570 wkt = lwgeom_to_wkt(lwgeom, WKT_EXTENDED, 12, &wkt_size);
571
572 if ( ! wkt )
573 {
574 lwerror("Error writing geom %p to WKT", (void *)lwgeom);
575 }
576
577 return wkt;
578}
579
590char
591lwgeom_same(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)
592{
593 LWDEBUGF(2, "lwgeom_same(%s, %s) called",
594 lwtype_name(lwgeom1->type),
595 lwtype_name(lwgeom2->type));
596
597 if ( lwgeom1->type != lwgeom2->type )
598 {
599 LWDEBUG(3, " type differ");
600
601 return LW_FALSE;
602 }
603
604 if ( FLAGS_GET_ZM(lwgeom1->flags) != FLAGS_GET_ZM(lwgeom2->flags) )
605 {
606 LWDEBUG(3, " ZM flags differ");
607
608 return LW_FALSE;
609 }
610
611 /* Check boxes if both already computed */
612 if ( lwgeom1->bbox && lwgeom2->bbox )
613 {
614 /*lwnotice("bbox1:%p, bbox2:%p", lwgeom1->bbox, lwgeom2->bbox);*/
615 if ( ! gbox_same(lwgeom1->bbox, lwgeom2->bbox) )
616 {
617 LWDEBUG(3, " bounding boxes differ");
618
619 return LW_FALSE;
620 }
621 }
622
623 /* geoms have same type, invoke type-specific function */
624 switch (lwgeom1->type)
625 {
626 case POINTTYPE:
627 return lwpoint_same((LWPOINT *)lwgeom1,
628 (LWPOINT *)lwgeom2);
629 case LINETYPE:
630 return lwline_same((LWLINE *)lwgeom1,
631 (LWLINE *)lwgeom2);
632 case POLYGONTYPE:
633 return lwpoly_same((LWPOLY *)lwgeom1,
634 (LWPOLY *)lwgeom2);
635 case TRIANGLETYPE:
636 return lwtriangle_same((LWTRIANGLE *)lwgeom1,
637 (LWTRIANGLE *)lwgeom2);
638 case CIRCSTRINGTYPE:
639 return lwcircstring_same((LWCIRCSTRING *)lwgeom1,
640 (LWCIRCSTRING *)lwgeom2);
641 case MULTIPOINTTYPE:
642 case MULTILINETYPE:
643 case MULTIPOLYGONTYPE:
644 case MULTICURVETYPE:
645 case MULTISURFACETYPE:
646 case COMPOUNDTYPE:
647 case CURVEPOLYTYPE:
649 case TINTYPE:
650 case COLLECTIONTYPE:
651 return lwcollection_same((LWCOLLECTION *)lwgeom1,
652 (LWCOLLECTION *)lwgeom2);
653 default:
654 lwerror("lwgeom_same: unsupported geometry type: %s",
655 lwtype_name(lwgeom1->type));
656 return LW_FALSE;
657 }
658
659}
660
661int
662lwpoint_inside_circle(const LWPOINT *p, double cx, double cy, double rad)
663{
664 const POINT2D *pt;
665 POINT2D center;
666
667 if ( ! p || ! p->point )
668 return LW_FALSE;
669
670 pt = getPoint2d_cp(p->point, 0);
671
672 center.x = cx;
673 center.y = cy;
674
675 if ( distance2d_pt_pt(pt, &center) < rad )
676 return LW_TRUE;
677
678 return LW_FALSE;
679}
680
681void
683{
684 if ( lwgeom->bbox ) lwfree(lwgeom->bbox);
685 lwgeom->bbox = NULL;
686 FLAGS_SET_BBOX(lwgeom->flags, 0);
687}
688
694void
696{
697 /* an empty LWGEOM has no bbox */
698 if ( lwgeom_is_empty(lwgeom) ) return;
699
700 if ( lwgeom->bbox ) return;
701 FLAGS_SET_BBOX(lwgeom->flags, 1);
702 lwgeom->bbox = gbox_new(lwgeom->flags);
703 lwgeom_calculate_gbox(lwgeom, lwgeom->bbox);
704}
705
706void
708{
709 lwgeom_drop_bbox(lwgeom);
710 lwgeom_add_bbox(lwgeom);
711}
712
713void
715{
716 if ( lwgeom_is_empty(lwgeom) ) return;
717
718 FLAGS_SET_BBOX(lwgeom->flags, 1);
719
720 if ( ! ( gbox || lwgeom->bbox ) )
721 {
722 lwgeom->bbox = gbox_new(lwgeom->flags);
723 lwgeom_calculate_gbox(lwgeom, lwgeom->bbox);
724 }
725 else if ( gbox && ! lwgeom->bbox )
726 {
727 lwgeom->bbox = gbox_clone(gbox);
728 }
729
730 if ( lwgeom_is_collection(lwgeom) )
731 {
732 uint32_t i;
733 LWCOLLECTION *lwcol = (LWCOLLECTION*)lwgeom;
734
735 for ( i = 0; i < lwcol->ngeoms; i++ )
736 {
737 lwgeom_add_bbox_deep(lwcol->geoms[i], lwgeom->bbox);
738 }
739 }
740}
741
742const GBOX *
744{
745 /* add it if not already there */
746 lwgeom_add_bbox((LWGEOM *)lwg);
747 return lwg->bbox;
748}
749
750
755int lwgeom_calculate_gbox(const LWGEOM *lwgeom, GBOX *gbox)
756{
757 gbox->flags = lwgeom->flags;
758 if( FLAGS_GET_GEODETIC(lwgeom->flags) )
759 return lwgeom_calculate_gbox_geodetic(lwgeom, gbox);
760 else
761 return lwgeom_calculate_gbox_cartesian(lwgeom, gbox);
762}
763
764void
766{
767 lwgeom->srid = SRID_UNKNOWN; /* TODO: To be changed to SRID_UNKNOWN */
768}
769
770LWGEOM *
771lwgeom_segmentize2d(const LWGEOM *lwgeom, double dist)
772{
773 switch (lwgeom->type)
774 {
775 case LINETYPE:
776 return (LWGEOM *)lwline_segmentize2d((LWLINE *)lwgeom,
777 dist);
778 case POLYGONTYPE:
779 return (LWGEOM *)lwpoly_segmentize2d((LWPOLY *)lwgeom,
780 dist);
781 case MULTILINETYPE:
782 case MULTIPOLYGONTYPE:
783 case COLLECTIONTYPE:
785 (LWCOLLECTION *)lwgeom, dist);
786
787 default:
788 return lwgeom_clone(lwgeom);
789 }
790}
791
792LWGEOM*
794{
795 return lwgeom_force_dims(geom, 0, 0, 0, 0);
796}
797
798LWGEOM*
799lwgeom_force_3dz(const LWGEOM *geom, double zval)
800{
801 return lwgeom_force_dims(geom, 1, 0, zval, 0);
802}
803
804LWGEOM*
805lwgeom_force_3dm(const LWGEOM *geom, double mval)
806{
807 return lwgeom_force_dims(geom, 0, 1, 0, mval);
808}
809
810LWGEOM*
811lwgeom_force_4d(const LWGEOM *geom, double zval, double mval)
812{
813 return lwgeom_force_dims(geom, 1, 1, zval, mval);
814}
815
816LWGEOM*
817lwgeom_force_dims(const LWGEOM *geom, int hasz, int hasm, double zval, double mval)
818{
819 if (!geom)
820 return NULL;
821 switch(geom->type)
822 {
823 case POINTTYPE:
824 return lwpoint_as_lwgeom(lwpoint_force_dims((LWPOINT*)geom, hasz, hasm, zval, mval));
825 case CIRCSTRINGTYPE:
826 case LINETYPE:
827 case TRIANGLETYPE:
828 return lwline_as_lwgeom(lwline_force_dims((LWLINE*)geom, hasz, hasm, zval, mval));
829 case POLYGONTYPE:
830 return lwpoly_as_lwgeom(lwpoly_force_dims((LWPOLY*)geom, hasz, hasm, zval, mval));
831 case COMPOUNDTYPE:
832 case CURVEPOLYTYPE:
833 case MULTICURVETYPE:
834 case MULTISURFACETYPE:
835 case MULTIPOINTTYPE:
836 case MULTILINETYPE:
837 case MULTIPOLYGONTYPE:
839 case TINTYPE:
840 case COLLECTIONTYPE:
841 return lwcollection_as_lwgeom(lwcollection_force_dims((LWCOLLECTION*)geom, hasz, hasm, zval, mval));
842 default:
843 lwerror("lwgeom_force_2d: unsupported geom type: %s", lwtype_name(geom->type));
844 return NULL;
845 }
846}
847
848LWGEOM*
849lwgeom_force_sfs(LWGEOM *geom, int version)
850{
851 LWCOLLECTION *col;
852 uint32_t i;
853 LWGEOM *g;
854
855 /* SFS 1.2 version */
856 if (version == 120)
857 {
858 switch(geom->type)
859 {
860 /* SQL/MM types */
861 case CIRCSTRINGTYPE:
862 case COMPOUNDTYPE:
863 case CURVEPOLYTYPE:
864 case MULTICURVETYPE:
865 case MULTISURFACETYPE:
866 return lwgeom_stroke(geom, 32);
867
868 case COLLECTIONTYPE:
869 col = (LWCOLLECTION*)geom;
870 for ( i = 0; i < col->ngeoms; i++ )
871 col->geoms[i] = lwgeom_force_sfs((LWGEOM*)col->geoms[i], version);
872
874
875 default:
876 return (LWGEOM *)geom;
877 }
878 }
879
880
881 /* SFS 1.1 version */
882 switch(geom->type)
883 {
884 /* SQL/MM types */
885 case CIRCSTRINGTYPE:
886 case COMPOUNDTYPE:
887 case CURVEPOLYTYPE:
888 case MULTICURVETYPE:
889 case MULTISURFACETYPE:
890 return lwgeom_stroke(geom, 32);
891
892 /* SFS 1.2 types */
893 case TRIANGLETYPE:
894 g = lwpoly_as_lwgeom(lwpoly_from_lwlines((LWLINE*)geom, 0, NULL));
895 lwgeom_free(geom);
896 return g;
897
898 case TINTYPE:
899 col = (LWCOLLECTION*) geom;
900 for ( i = 0; i < col->ngeoms; i++ )
901 {
902 g = lwpoly_as_lwgeom(lwpoly_from_lwlines((LWLINE*)col->geoms[i], 0, NULL));
903 lwgeom_free(col->geoms[i]);
904 col->geoms[i] = g;
905 }
906 col->type = COLLECTIONTYPE;
907 return lwmpoly_as_lwgeom((LWMPOLY*)geom);
908
910 geom->type = COLLECTIONTYPE;
911 return (LWGEOM *)geom;
912
913 /* Collection */
914 case COLLECTIONTYPE:
915 col = (LWCOLLECTION*)geom;
916 for ( i = 0; i < col->ngeoms; i++ )
917 col->geoms[i] = lwgeom_force_sfs((LWGEOM*)col->geoms[i], version);
918
920
921 default:
922 return (LWGEOM *)geom;
923 }
924}
925
926int32_t
928{
929 if ( ! geom ) return SRID_UNKNOWN;
930 return geom->srid;
931}
932
933int
935{
936 if ( ! geom ) return LW_FALSE;
937 return FLAGS_GET_Z(geom->flags);
938}
939
940int
942{
943 if ( ! geom ) return LW_FALSE;
944 return FLAGS_GET_M(geom->flags);
945}
946
947int
949{
950 if ( ! geom ) return LW_FALSE;
951 return FLAGS_GET_SOLID(geom->flags);
952}
953
954int
956{
957 if ( ! geom ) return 0;
958 return FLAGS_NDIMS(geom->flags);
959}
960
961
962
963void
965{
966 LWPOINT *pt;
967 LWLINE *ln;
968 LWPOLY *ply;
969 LWCOLLECTION *col;
970 uint32_t i;
971
972 FLAGS_SET_GEODETIC(geom->flags, value);
973 if ( geom->bbox )
974 FLAGS_SET_GEODETIC(geom->bbox->flags, value);
975
976 switch(geom->type)
977 {
978 case POINTTYPE:
979 pt = (LWPOINT*)geom;
980 if ( pt->point )
981 FLAGS_SET_GEODETIC(pt->point->flags, value);
982 break;
983 case LINETYPE:
984 ln = (LWLINE*)geom;
985 if ( ln->points )
986 FLAGS_SET_GEODETIC(ln->points->flags, value);
987 break;
988 case POLYGONTYPE:
989 ply = (LWPOLY*)geom;
990 for ( i = 0; i < ply->nrings; i++ )
991 FLAGS_SET_GEODETIC(ply->rings[i]->flags, value);
992 break;
993 case MULTIPOINTTYPE:
994 case MULTILINETYPE:
995 case MULTIPOLYGONTYPE:
996 case COLLECTIONTYPE:
997 col = (LWCOLLECTION*)geom;
998 for ( i = 0; i < col->ngeoms; i++ )
999 lwgeom_set_geodetic(col->geoms[i], value);
1000 break;
1001 default:
1002 lwerror("lwgeom_set_geodetic: unsupported geom type: %s", lwtype_name(geom->type));
1003 return;
1004 }
1005}
1006
1007void
1009{
1010 uint32_t i;
1011 switch (lwgeom->type)
1012 {
1013 LWPOINT *point;
1014 LWLINE *line;
1015 LWPOLY *poly;
1016 LWTRIANGLE *triangle;
1017 LWCOLLECTION *coll;
1018
1019 case POINTTYPE:
1020 point = (LWPOINT *)lwgeom;
1022 return;
1023 case LINETYPE:
1024 line = (LWLINE *)lwgeom;
1026 return;
1027 case POLYGONTYPE:
1028 poly = (LWPOLY *)lwgeom;
1029 for (i=0; i<poly->nrings; i++)
1031 return;
1032 case TRIANGLETYPE:
1033 triangle = (LWTRIANGLE *)lwgeom;
1035 return;
1036 case MULTIPOINTTYPE:
1037 case MULTILINETYPE:
1038 case MULTIPOLYGONTYPE:
1040 case TINTYPE:
1041 case COLLECTIONTYPE:
1042 coll = (LWCOLLECTION *)lwgeom;
1043 for (i=0; i<coll->ngeoms; i++)
1044 lwgeom_longitude_shift(coll->geoms[i]);
1045 return;
1046 default:
1047 lwerror("lwgeom_longitude_shift: unsupported geom type: %s",
1048 lwtype_name(lwgeom->type));
1049 }
1050}
1051
1052int
1054{
1055 int type = geom->type;
1056
1057 if( lwgeom_is_empty(geom) )
1058 return LW_FALSE;
1059
1060 /* Test linear types for closure */
1061 switch (type)
1062 {
1063 case LINETYPE:
1064 return lwline_is_closed((LWLINE*)geom);
1065 case POLYGONTYPE:
1066 return lwpoly_is_closed((LWPOLY*)geom);
1067 case CIRCSTRINGTYPE:
1068 return lwcircstring_is_closed((LWCIRCSTRING*)geom);
1069 case COMPOUNDTYPE:
1070 return lwcompound_is_closed((LWCOMPOUND*)geom);
1071 case TINTYPE:
1072 return lwtin_is_closed((LWTIN*)geom);
1074 return lwpsurface_is_closed((LWPSURFACE*)geom);
1075 }
1076
1077 /* Recurse into collections and see if anything is not closed */
1078 if ( lwgeom_is_collection(geom) )
1079 {
1081 uint32_t i;
1082 int closed;
1083 for ( i = 0; i < col->ngeoms; i++ )
1084 {
1085 closed = lwgeom_is_closed(col->geoms[i]);
1086 if ( ! closed )
1087 return LW_FALSE;
1088 }
1089 return LW_TRUE;
1090 }
1091
1092 /* All non-linear non-collection types we will call closed */
1093 return LW_TRUE;
1094}
1095
1096int
1098{
1099 if( ! geom ) return LW_FALSE;
1100 return lwtype_is_collection(geom->type);
1101}
1102
1103int
1104lwtype_is_unitary(uint32_t lwtype)
1105{
1106 switch (lwtype)
1107 {
1108 case POINTTYPE:
1109 case LINETYPE:
1110 case POLYGONTYPE:
1111 case CURVEPOLYTYPE:
1112 case COMPOUNDTYPE:
1113 case CIRCSTRINGTYPE:
1114 case TRIANGLETYPE:
1116 case TINTYPE:
1117 return LW_TRUE;
1118 break;
1119
1120 default:
1121 return LW_FALSE;
1122 }
1123}
1124
1125int
1127{
1128 switch (geom->type)
1129 {
1130 case TINTYPE:
1132 return LW_TRUE;
1133 break;
1134 default:
1135 return LW_FALSE;
1136 }
1137}
1138
1139int
1141{
1142 return lwtype_is_unitary(geom->type);
1143}
1144
1145int
1147{
1148 switch (geom->type)
1149 {
1150 case POLYGONTYPE:
1151 case CURVEPOLYTYPE:
1152 case TRIANGLETYPE:
1153 return LW_TRUE;
1154 break;
1155
1156 default:
1157 return LW_FALSE;
1158 }
1159}
1160
1167int
1169{
1170 switch (type)
1171 {
1172 case MULTIPOINTTYPE:
1173 case MULTILINETYPE:
1174 case MULTIPOLYGONTYPE:
1175 case COLLECTIONTYPE:
1176 case CURVEPOLYTYPE:
1177 case COMPOUNDTYPE:
1178 case MULTICURVETYPE:
1179 case MULTISURFACETYPE:
1181 case TINTYPE:
1182 return LW_TRUE;
1183 break;
1184
1185 default:
1186 return LW_FALSE;
1187 }
1188}
1189
1193uint32_t
1195{
1196 switch (type)
1197 {
1198 case POINTTYPE:
1199 return MULTIPOINTTYPE;
1200 case LINETYPE:
1201 return MULTILINETYPE;
1202 case POLYGONTYPE:
1203 return MULTIPOLYGONTYPE;
1204 case CIRCSTRINGTYPE:
1205 return MULTICURVETYPE;
1206 case COMPOUNDTYPE:
1207 return MULTICURVETYPE;
1208 case CURVEPOLYTYPE:
1209 return MULTISURFACETYPE;
1210 case TRIANGLETYPE:
1211 return TINTYPE;
1212 default:
1213 return COLLECTIONTYPE;
1214 }
1215}
1216
1217
1218void lwgeom_free(LWGEOM *lwgeom)
1219{
1220
1221 /* There's nothing here to free... */
1222 if( ! lwgeom ) return;
1223
1224 LWDEBUGF(5,"freeing a %s",lwtype_name(lwgeom->type));
1225
1226 switch (lwgeom->type)
1227 {
1228 case POINTTYPE:
1229 lwpoint_free((LWPOINT *)lwgeom);
1230 break;
1231 case LINETYPE:
1232 lwline_free((LWLINE *)lwgeom);
1233 break;
1234 case POLYGONTYPE:
1235 lwpoly_free((LWPOLY *)lwgeom);
1236 break;
1237 case CIRCSTRINGTYPE:
1239 break;
1240 case TRIANGLETYPE:
1241 lwtriangle_free((LWTRIANGLE *)lwgeom);
1242 break;
1243 case MULTIPOINTTYPE:
1244 lwmpoint_free((LWMPOINT *)lwgeom);
1245 break;
1246 case MULTILINETYPE:
1247 lwmline_free((LWMLINE *)lwgeom);
1248 break;
1249 case MULTIPOLYGONTYPE:
1250 lwmpoly_free((LWMPOLY *)lwgeom);
1251 break;
1253 lwpsurface_free((LWPSURFACE *)lwgeom);
1254 break;
1255 case TINTYPE:
1256 lwtin_free((LWTIN *)lwgeom);
1257 break;
1258 case CURVEPOLYTYPE:
1259 case COMPOUNDTYPE:
1260 case MULTICURVETYPE:
1261 case MULTISURFACETYPE:
1262 case COLLECTIONTYPE:
1264 break;
1265 default:
1266 lwerror("lwgeom_free called with unknown type (%d) %s", lwgeom->type, lwtype_name(lwgeom->type));
1267 }
1268 return;
1269}
1270
1272{
1273 assert(geom);
1274 if ( geom->type == POINTTYPE )
1275 {
1276 return LW_FALSE;
1277 }
1278 else if ( geom->type == LINETYPE )
1279 {
1280 if ( lwgeom_count_vertices(geom) <= 2 )
1281 return LW_FALSE;
1282 else
1283 return LW_TRUE;
1284 }
1285 else if ( geom->type == MULTIPOINTTYPE )
1286 {
1287 if ( ((LWCOLLECTION*)geom)->ngeoms == 1 )
1288 return LW_FALSE;
1289 else
1290 return LW_TRUE;
1291 }
1292 else if ( geom->type == MULTILINETYPE )
1293 {
1294 if ( ((LWCOLLECTION*)geom)->ngeoms == 1 && lwgeom_count_vertices(geom) <= 2 )
1295 return LW_FALSE;
1296 else
1297 return LW_TRUE;
1298 }
1299 else
1300 {
1301 return LW_TRUE;
1302 }
1303}
1304
1309uint32_t lwgeom_count_vertices(const LWGEOM *geom)
1310{
1311 int result = 0;
1312
1313 /* Null? Zero. */
1314 if( ! geom ) return 0;
1315
1316 LWDEBUGF(4, "lwgeom_count_vertices got type %s",
1317 lwtype_name(geom->type));
1318
1319 /* Empty? Zero. */
1320 if( lwgeom_is_empty(geom) ) return 0;
1321
1322 switch (geom->type)
1323 {
1324 case POINTTYPE:
1325 result = 1;
1326 break;
1327 case TRIANGLETYPE:
1328 case CIRCSTRINGTYPE:
1329 case LINETYPE:
1330 result = lwline_count_vertices((const LWLINE *)geom);
1331 break;
1332 case POLYGONTYPE:
1333 result = lwpoly_count_vertices((const LWPOLY *)geom);
1334 break;
1335 case COMPOUNDTYPE:
1336 case CURVEPOLYTYPE:
1337 case MULTICURVETYPE:
1338 case MULTISURFACETYPE:
1339 case MULTIPOINTTYPE:
1340 case MULTILINETYPE:
1341 case MULTIPOLYGONTYPE:
1343 case TINTYPE:
1344 case COLLECTIONTYPE:
1346 break;
1347 default:
1348 lwerror("%s: unsupported input geometry type: %s",
1349 __func__, lwtype_name(geom->type));
1350 break;
1351 }
1352 LWDEBUGF(3, "counted %d vertices", result);
1353 return result;
1354}
1355
1361int lwgeom_dimension(const LWGEOM *geom)
1362{
1363
1364 /* Null? Zero. */
1365 if( ! geom ) return -1;
1366
1367 LWDEBUGF(4, "lwgeom_dimension got type %s",
1368 lwtype_name(geom->type));
1369
1370 /* Empty? Zero. */
1371 /* if( lwgeom_is_empty(geom) ) return 0; */
1372
1373 switch (geom->type)
1374 {
1375 case POINTTYPE:
1376 case MULTIPOINTTYPE:
1377 return 0;
1378 case CIRCSTRINGTYPE:
1379 case LINETYPE:
1380 case COMPOUNDTYPE:
1381 case MULTICURVETYPE:
1382 case MULTILINETYPE:
1383 return 1;
1384 case TRIANGLETYPE:
1385 case POLYGONTYPE:
1386 case CURVEPOLYTYPE:
1387 case MULTISURFACETYPE:
1388 case MULTIPOLYGONTYPE:
1389 case TINTYPE:
1390 return 2;
1392 {
1393 /* A closed polyhedral surface contains a volume. */
1394 int closed = lwpsurface_is_closed((LWPSURFACE*)geom);
1395 return ( closed ? 3 : 2 );
1396 }
1397 case COLLECTIONTYPE:
1398 {
1399 int maxdim = 0;
1400 uint32_t i;
1401 LWCOLLECTION *col = (LWCOLLECTION*)geom;
1402 for( i = 0; i < col->ngeoms; i++ )
1403 {
1404 int dim = lwgeom_dimension(col->geoms[i]);
1405 maxdim = ( dim > maxdim ? dim : maxdim );
1406 }
1407 return maxdim;
1408 }
1409 default:
1410 lwerror("%s: unsupported input geometry type: %s",
1411 __func__, lwtype_name(geom->type));
1412 }
1413 return -1;
1414}
1415
1419uint32_t lwgeom_count_rings(const LWGEOM *geom)
1420{
1421 int result = 0;
1422
1423 /* Null? Empty? Zero. */
1424 if( ! geom || lwgeom_is_empty(geom) )
1425 return 0;
1426
1427 switch (geom->type)
1428 {
1429 case POINTTYPE:
1430 case CIRCSTRINGTYPE:
1431 case COMPOUNDTYPE:
1432 case MULTICURVETYPE:
1433 case MULTIPOINTTYPE:
1434 case MULTILINETYPE:
1435 case LINETYPE:
1436 result = 0;
1437 break;
1438 case TRIANGLETYPE:
1439 result = 1;
1440 break;
1441 case POLYGONTYPE:
1442 result = ((LWPOLY *)geom)->nrings;
1443 break;
1444 case CURVEPOLYTYPE:
1445 result = ((LWCURVEPOLY *)geom)->nrings;
1446 break;
1447 case MULTISURFACETYPE:
1448 case MULTIPOLYGONTYPE:
1450 case TINTYPE:
1451 case COLLECTIONTYPE:
1452 {
1453 LWCOLLECTION *col = (LWCOLLECTION*)geom;
1454 uint32_t i = 0;
1455 for( i = 0; i < col->ngeoms; i++ )
1456 result += lwgeom_count_rings(col->geoms[i]);
1457 break;
1458 }
1459 default:
1460 lwerror("lwgeom_count_rings: unsupported input geometry type: %s", lwtype_name(geom->type));
1461 break;
1462 }
1463 LWDEBUGF(3, "counted %d rings", result);
1464 return result;
1465}
1466
1467int lwgeom_has_srid(const LWGEOM *geom)
1468{
1469 if ( geom->srid != SRID_UNKNOWN )
1470 return LW_TRUE;
1471
1472 return LW_FALSE;
1473}
1474
1475
1477{
1478 uint32_t i;
1479 int dimensionality = 0;
1480 for ( i = 0; i < col->ngeoms; i++ )
1481 {
1482 int d = lwgeom_dimensionality(col->geoms[i]);
1483 if ( d > dimensionality )
1484 dimensionality = d;
1485 }
1486 return dimensionality;
1487}
1488
1489extern int lwgeom_dimensionality(const LWGEOM *geom)
1490{
1491 int dim;
1492
1493 LWDEBUGF(3, "lwgeom_dimensionality got type %s",
1494 lwtype_name(geom->type));
1495
1496 switch (geom->type)
1497 {
1498 case POINTTYPE:
1499 case MULTIPOINTTYPE:
1500 return 0;
1501 break;
1502 case LINETYPE:
1503 case CIRCSTRINGTYPE:
1504 case MULTILINETYPE:
1505 case COMPOUNDTYPE:
1506 case MULTICURVETYPE:
1507 return 1;
1508 break;
1509 case POLYGONTYPE:
1510 case TRIANGLETYPE:
1511 case CURVEPOLYTYPE:
1512 case MULTIPOLYGONTYPE:
1513 case MULTISURFACETYPE:
1514 return 2;
1515 break;
1516
1518 case TINTYPE:
1519 dim = lwgeom_is_closed(geom)?3:2;
1520 return dim;
1521 break;
1522
1523 case COLLECTIONTYPE:
1524 return lwcollection_dimensionality((const LWCOLLECTION *)geom);
1525 break;
1526 default:
1527 lwerror("lwgeom_dimensionality: unsupported input geometry type: %s",
1528 lwtype_name(geom->type));
1529 break;
1530 }
1531 return 0;
1532}
1533
1534extern LWGEOM* lwgeom_remove_repeated_points(const LWGEOM *in, double tolerance)
1535{
1536 LWGEOM *out = lwgeom_clone_deep(in);
1538 return out;
1539}
1540
1542{
1543 LWCOLLECTION *col;
1544 LWPOLY *poly;
1545 uint32_t i;
1546
1547 if ( (!in) || lwgeom_is_empty(in) ) return;
1548
1549 /* TODO: check for lwgeom NOT having the specified dimension ? */
1550
1551 LWDEBUGF(4, "lwgeom_flip_coordinates, got type: %s",
1552 lwtype_name(in->type));
1553
1554 switch (in->type)
1555 {
1556 case POINTTYPE:
1557 ptarray_swap_ordinates(lwgeom_as_lwpoint(in)->point, o1, o2);
1558 break;
1559
1560 case LINETYPE:
1561 ptarray_swap_ordinates(lwgeom_as_lwline(in)->points, o1, o2);
1562 break;
1563
1564 case CIRCSTRINGTYPE:
1566 break;
1567
1568 case POLYGONTYPE:
1569 poly = (LWPOLY *) in;
1570 for (i=0; i<poly->nrings; i++)
1571 {
1572 ptarray_swap_ordinates(poly->rings[i], o1, o2);
1573 }
1574 break;
1575
1576 case TRIANGLETYPE:
1577 ptarray_swap_ordinates(lwgeom_as_lwtriangle(in)->points, o1, o2);
1578 break;
1579
1580 case MULTIPOINTTYPE:
1581 case MULTILINETYPE:
1582 case MULTIPOLYGONTYPE:
1583 case COLLECTIONTYPE:
1584 case COMPOUNDTYPE:
1585 case CURVEPOLYTYPE:
1586 case MULTISURFACETYPE:
1587 case MULTICURVETYPE:
1589 case TINTYPE:
1590 col = (LWCOLLECTION *) in;
1591 for (i=0; i<col->ngeoms; i++)
1592 {
1593 lwgeom_swap_ordinates(col->geoms[i], o1, o2);
1594 }
1595 break;
1596
1597 default:
1598 lwerror("lwgeom_swap_ordinates: unsupported geometry type: %s",
1599 lwtype_name(in->type));
1600 return;
1601 }
1602
1603 /* only refresh bbox if X or Y changed */
1604 if ( in->bbox && (o1 < 2 || o2 < 2) )
1605 {
1607 }
1608}
1609
1610void lwgeom_set_srid(LWGEOM *geom, int32_t srid)
1611{
1612 uint32_t i;
1613
1614 LWDEBUGF(4,"entered with srid=%d",srid);
1615
1616 geom->srid = srid;
1617
1618 if ( lwgeom_is_collection(geom) )
1619 {
1620 /* All the children are set to the same SRID value */
1622 for ( i = 0; i < col->ngeoms; i++ )
1623 {
1624 lwgeom_set_srid(col->geoms[i], srid);
1625 }
1626 }
1627}
1628
1629
1630/**************************************************************/
1631
1632static int
1633cmp_point_x(const void *pa, const void *pb)
1634{
1635 LWPOINT *p1 = *((LWPOINT **)pa);
1636 LWPOINT *p2 = *((LWPOINT **)pb);
1637
1638 const POINT2D *pt1 = getPoint2d_cp(p1->point, 0);
1639 const POINT2D *pt2 = getPoint2d_cp(p2->point, 0);
1640
1641 if (pt1 && pt2)
1642 return (pt1->x > pt2->x) ? 1 : ((pt1->x < pt2->x) ? -1 : 0);
1643
1644 if (pt1) return -1;
1645 if (pt2) return 1;
1646 return 0;
1647}
1648
1649static int
1650cmp_point_y(const void *pa, const void *pb)
1651{
1652 LWPOINT *p1 = *((LWPOINT **)pa);
1653 LWPOINT *p2 = *((LWPOINT **)pb);
1654
1655 const POINT2D *pt1 = getPoint2d_cp(p1->point, 0);
1656 const POINT2D *pt2 = getPoint2d_cp(p2->point, 0);
1657
1658 if (pt1 && pt2)
1659 return (pt1->y > pt2->y) ? 1 : ((pt1->y < pt2->y) ? -1 : 0);
1660
1661 if (pt1) return -1;
1662 if (pt2) return 1;
1663 return 0;
1664}
1665
1666int
1668{
1669 int geometry_modified = LW_FALSE;
1670 switch (geom->type)
1671 {
1672 /* No-op! Cannot remove points */
1673 case POINTTYPE:
1674 case TRIANGLETYPE:
1675 return geometry_modified;
1676 case LINETYPE: {
1677 LWLINE *g = (LWLINE *)(geom);
1678 POINTARRAY *pa = g->points;
1679 uint32_t npoints = pa->npoints;
1681 geometry_modified = npoints != pa->npoints;
1682 /* Invalid input, discard the collapsed line */
1683 if (pa->npoints < 2)
1684 {
1685 pa->npoints = 0;
1686 geometry_modified = LW_TRUE;
1687 }
1688 break;
1689 }
1690 case POLYGONTYPE: {
1691 uint32_t j = 0;
1692 LWPOLY *g = (LWPOLY *)(geom);
1693 for (uint32_t i = 0; i < g->nrings; i++)
1694 {
1695 POINTARRAY *pa = g->rings[i];
1696 uint32_t npoints = pa->npoints;
1698 geometry_modified |= npoints != pa->npoints;
1699 /* Drop collapsed rings */
1700 if (pa->npoints < 4)
1701 {
1702 geometry_modified = LW_TRUE;
1703 ptarray_free(pa);
1704 continue;
1705 }
1706 g->rings[j++] = pa;
1707 }
1708 /* Update ring count */
1709 g->nrings = j;
1710 break;
1711 }
1712 case MULTIPOINTTYPE: {
1713 double tolsq = tolerance * tolerance;
1714 LWMPOINT *mpt = (LWMPOINT *)geom;
1715
1716 for (uint8_t dim = 0; dim < 2; dim++)
1717 {
1718 /* sort by y, then by x - this way the result is sorted by x */
1719 qsort(mpt->geoms, mpt->ngeoms, sizeof(LWPOINT *), dim ? cmp_point_x : cmp_point_y);
1720 for (uint32_t i = 0; i < mpt->ngeoms; i++)
1721 {
1722 if (!mpt->geoms[i])
1723 continue;
1724
1725 const POINT2D *pti = getPoint2d_cp(mpt->geoms[i]->point, 0);
1726 if (!pti) continue;
1727
1728 /* check upcoming points if they're within tolerance of current one */
1729 for (uint32_t j = i + 1; j < mpt->ngeoms; j++)
1730 {
1731 if (!mpt->geoms[j])
1732 continue;
1733
1734 const POINT2D *ptj = getPoint2d_cp(mpt->geoms[j]->point, 0);
1735 if (!ptj) continue;
1736
1737 /* check that the point is in the strip of tolerance around the point */
1738 if ((dim ? ptj->x - pti->x : ptj->y - pti->y) > tolerance)
1739 break;
1740
1741 /* remove any upcoming point that is within tolerance circle */
1742 if (distance2d_sqr_pt_pt(pti, ptj) <= tolsq)
1743 {
1744 lwpoint_free(mpt->geoms[j]);
1745 mpt->geoms[j] = NULL;
1746 geometry_modified = LW_TRUE;
1747 }
1748 }
1749 }
1750
1751 /* null out empties */
1752 for (uint32_t j = 0; j < mpt->ngeoms; j++)
1753 {
1754 if (mpt->geoms[j] && lwpoint_is_empty(mpt->geoms[j]))
1755 {
1756 lwpoint_free(mpt->geoms[j]);
1757 mpt->geoms[j] = NULL;
1758 geometry_modified = LW_TRUE;
1759 }
1760 }
1761
1762 /* compactify array of points */
1763 uint32_t i = 0;
1764 for (uint32_t j = 0; j < mpt->ngeoms; j++)
1765 if (mpt->geoms[j])
1766 mpt->geoms[i++] = mpt->geoms[j];
1767 mpt->ngeoms = i;
1768 }
1769
1770 break;
1771 }
1772
1773 case CIRCSTRINGTYPE:
1774 /* Dunno how to handle these, will return untouched */
1775 return geometry_modified;
1776
1777 /* Can process most multi* types as generic collection */
1778 case MULTILINETYPE:
1779 case MULTIPOLYGONTYPE:
1780 case TINTYPE:
1781 case COLLECTIONTYPE:
1782 /* Curve types we mostly ignore, but allow the linear */
1783 /* portions to be processed by recursing into them */
1784 case MULTICURVETYPE:
1785 case CURVEPOLYTYPE:
1786 case MULTISURFACETYPE:
1787 case COMPOUNDTYPE: {
1788 uint32_t i, j = 0;
1789 LWCOLLECTION *col = (LWCOLLECTION *)(geom);
1790 for (i = 0; i < col->ngeoms; i++)
1791 {
1792 LWGEOM *g = col->geoms[i];
1793 if (!g)
1794 continue;
1795 geometry_modified |= lwgeom_remove_repeated_points_in_place(g, tolerance);
1796 /* Drop zero'ed out geometries */
1797 if (lwgeom_is_empty(g))
1798 {
1799 lwgeom_free(g);
1800 continue;
1801 }
1802 col->geoms[j++] = g;
1803 }
1804 /* Update geometry count */
1805 col->ngeoms = j;
1806 break;
1807 }
1808 default: {
1809 lwerror("%s: unsupported geometry type: %s", __func__, lwtype_name(geom->type));
1810 break;
1811 }
1812 }
1813
1814 if (geometry_modified)
1815 lwgeom_drop_bbox(geom);
1816 return geometry_modified;
1817}
1818
1819
1820/**************************************************************/
1821
1822int
1823lwgeom_simplify_in_place(LWGEOM *geom, double epsilon, int preserve_collapsed)
1824{
1825 int modified = LW_FALSE;
1826 switch (geom->type)
1827 {
1828 /* No-op! Cannot simplify points or triangles */
1829 case POINTTYPE:
1830 return modified;
1831 case TRIANGLETYPE:
1832 {
1833 if (preserve_collapsed)
1834 return modified;
1836 POINTARRAY *pa = t->points;
1837 ptarray_simplify_in_place(pa, epsilon, 0);
1838 if (pa->npoints < 3)
1839 {
1840 pa->npoints = 0;
1841 modified = LW_TRUE;
1842 }
1843 break;
1844 }
1845 case LINETYPE:
1846 {
1847 LWLINE *g = (LWLINE*)(geom);
1848 POINTARRAY *pa = g->points;
1849 uint32_t in_npoints = pa->npoints;
1850 ptarray_simplify_in_place(pa, epsilon, 2);
1851 modified = in_npoints != pa->npoints;
1852 /* Invalid output */
1853 if (pa->npoints == 1 && pa->maxpoints > 1)
1854 {
1855 /* Use first point as last point */
1856 if (preserve_collapsed)
1857 {
1858 pa->npoints = 2;
1859 ptarray_copy_point(pa, 0, 1);
1860 }
1861 /* Finish the collapse process */
1862 else
1863 {
1864 pa->npoints = 0;
1865 }
1866 }
1867 /* Duped output, force collapse */
1868 if (pa->npoints == 2 && !preserve_collapsed)
1869 {
1870 if (p2d_same(getPoint2d_cp(pa, 0), getPoint2d_cp(pa, 1)))
1871 pa->npoints = 0;
1872 }
1873 break;
1874 }
1875 case POLYGONTYPE:
1876 {
1877 uint32_t i, j = 0;
1878 LWPOLY *g = (LWPOLY*)(geom);
1879 for (i = 0; i < g->nrings; i++)
1880 {
1881 POINTARRAY *pa = g->rings[i];
1882 /* Only stop collapse on first ring */
1883 int minpoints = (preserve_collapsed && i == 0) ? 4 : 0;
1884 /* Skip zero'ed out rings */
1885 if(!pa)
1886 continue;
1887 uint32_t in_npoints = pa->npoints;
1888 ptarray_simplify_in_place(pa, epsilon, minpoints);
1889 modified |= in_npoints != pa->npoints;
1890 /* Drop collapsed rings */
1891 if(pa->npoints < 4)
1892 {
1893 if (i == 0)
1894 {
1895 /* If the outer ring is dropped, all can be dropped */
1896 for (i = 0; i < g->nrings; i++)
1897 {
1898 pa = g->rings[i];
1899 ptarray_free(pa);
1900 }
1901 break;
1902 }
1903 else
1904 {
1905 /* Drop this inner ring only */
1906 ptarray_free(pa);
1907 continue;
1908 }
1909 }
1910 g->rings[j++] = pa;
1911 }
1912 /* Update ring count */
1913 g->nrings = j;
1914 break;
1915 }
1916 /* Can process all multi* types as generic collection */
1917 case MULTIPOINTTYPE:
1918 case MULTILINETYPE:
1919 case MULTIPOLYGONTYPE:
1920 case TINTYPE:
1921 case COLLECTIONTYPE:
1922 {
1923 uint32_t i, j = 0;
1924 LWCOLLECTION *col = (LWCOLLECTION*)geom;
1925 for (i = 0; i < col->ngeoms; i++)
1926 {
1927 LWGEOM *g = col->geoms[i];
1928 if (!g) continue;
1929 modified |= lwgeom_simplify_in_place(g, epsilon, preserve_collapsed);
1930 /* Drop zero'ed out geometries */
1931 if(lwgeom_is_empty(g))
1932 {
1933 lwgeom_free(g);
1934 continue;
1935 }
1936 col->geoms[j++] = g;
1937 }
1938 /* Update geometry count */
1939 col->ngeoms = j;
1940 break;
1941 }
1942 default:
1943 {
1944 lwerror("%s: unsupported geometry type: %s", __func__, lwtype_name(geom->type));
1945 break;
1946 }
1947 }
1948
1949 if (modified)
1950 {
1951 lwgeom_drop_bbox(geom);
1952 }
1953 return modified;
1954}
1955
1956LWGEOM* lwgeom_simplify(const LWGEOM *igeom, double dist, int preserve_collapsed)
1957{
1958 LWGEOM *lwgeom_out = lwgeom_clone_deep(igeom);
1959 lwgeom_simplify_in_place(lwgeom_out, dist, preserve_collapsed);
1960 if (lwgeom_is_empty(lwgeom_out))
1961 {
1962 lwgeom_free(lwgeom_out);
1963 return NULL;
1964 }
1965 return lwgeom_out;
1966}
1967
1968/**************************************************************/
1969
1970
1971double lwgeom_area(const LWGEOM *geom)
1972{
1973 int type = geom->type;
1974
1975 if ( type == POLYGONTYPE )
1976 return lwpoly_area((LWPOLY*)geom);
1977 else if ( type == CURVEPOLYTYPE )
1978 return lwcurvepoly_area((LWCURVEPOLY*)geom);
1979 else if (type == TRIANGLETYPE )
1980 return lwtriangle_area((LWTRIANGLE*)geom);
1981 else if ( lwgeom_is_collection(geom) )
1982 {
1983 double area = 0.0;
1984 uint32_t i;
1985 LWCOLLECTION *col = (LWCOLLECTION*)geom;
1986 for ( i = 0; i < col->ngeoms; i++ )
1987 area += lwgeom_area(col->geoms[i]);
1988 return area;
1989 }
1990 else
1991 return 0.0;
1992}
1993
1994double lwgeom_perimeter(const LWGEOM *geom)
1995{
1996 int type = geom->type;
1997 if ( type == POLYGONTYPE )
1998 return lwpoly_perimeter((LWPOLY*)geom);
1999 else if ( type == CURVEPOLYTYPE )
2000 return lwcurvepoly_perimeter((LWCURVEPOLY*)geom);
2001 else if ( type == TRIANGLETYPE )
2002 return lwtriangle_perimeter((LWTRIANGLE*)geom);
2003 else if ( lwgeom_is_collection(geom) )
2004 {
2005 double perimeter = 0.0;
2006 uint32_t i;
2007 LWCOLLECTION *col = (LWCOLLECTION*)geom;
2008 for ( i = 0; i < col->ngeoms; i++ )
2009 perimeter += lwgeom_perimeter(col->geoms[i]);
2010 return perimeter;
2011 }
2012 else
2013 return 0.0;
2014}
2015
2016double lwgeom_perimeter_2d(const LWGEOM *geom)
2017{
2018 int type = geom->type;
2019 if ( type == POLYGONTYPE )
2020 return lwpoly_perimeter_2d((LWPOLY*)geom);
2021 else if ( type == CURVEPOLYTYPE )
2023 else if ( type == TRIANGLETYPE )
2024 return lwtriangle_perimeter_2d((LWTRIANGLE*)geom);
2025 else if ( lwgeom_is_collection(geom) )
2026 {
2027 double perimeter = 0.0;
2028 uint32_t i;
2029 LWCOLLECTION *col = (LWCOLLECTION*)geom;
2030 for ( i = 0; i < col->ngeoms; i++ )
2031 perimeter += lwgeom_perimeter_2d(col->geoms[i]);
2032 return perimeter;
2033 }
2034 else
2035 return 0.0;
2036}
2037
2038double lwgeom_length(const LWGEOM *geom)
2039{
2040 int type = geom->type;
2041 if ( type == LINETYPE )
2042 return lwline_length((LWLINE*)geom);
2043 else if ( type == CIRCSTRINGTYPE )
2044 return lwcircstring_length((LWCIRCSTRING*)geom);
2045 else if ( type == COMPOUNDTYPE )
2046 return lwcompound_length((LWCOMPOUND*)geom);
2047 else if ( lwgeom_is_collection(geom) )
2048 {
2049 double length = 0.0;
2050 uint32_t i;
2051 LWCOLLECTION *col = (LWCOLLECTION*)geom;
2052 for ( i = 0; i < col->ngeoms; i++ )
2053 length += lwgeom_length(col->geoms[i]);
2054 return length;
2055 }
2056 else
2057 return 0.0;
2058}
2059
2060double lwgeom_length_2d(const LWGEOM *geom)
2061{
2062 int type = geom->type;
2063 if ( type == LINETYPE )
2064 return lwline_length_2d((LWLINE*)geom);
2065 else if ( type == CIRCSTRINGTYPE )
2066 return lwcircstring_length_2d((LWCIRCSTRING*)geom);
2067 else if ( type == COMPOUNDTYPE )
2068 return lwcompound_length_2d((LWCOMPOUND*)geom);
2069 else if ( type != CURVEPOLYTYPE && lwgeom_is_collection(geom) )
2070 {
2071 double length = 0.0;
2072 uint32_t i;
2073 LWCOLLECTION *col = (LWCOLLECTION*)geom;
2074 for ( i = 0; i < col->ngeoms; i++ )
2075 length += lwgeom_length_2d(col->geoms[i]);
2076 return length;
2077 }
2078 else
2079 return 0.0;
2080}
2081
2082void
2083lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
2084{
2085 int type = geom->type;
2086 uint32_t i;
2087
2088 switch(type)
2089 {
2090 /* Take advantage of fact that pt/ln/circ/tri have same memory structure */
2091 case POINTTYPE:
2092 case LINETYPE:
2093 case CIRCSTRINGTYPE:
2094 case TRIANGLETYPE:
2095 {
2096 LWLINE *l = (LWLINE*)geom;
2097 ptarray_affine(l->points, affine);
2098 break;
2099 }
2100 case POLYGONTYPE:
2101 {
2102 LWPOLY *p = (LWPOLY*)geom;
2103 for( i = 0; i < p->nrings; i++ )
2104 ptarray_affine(p->rings[i], affine);
2105 break;
2106 }
2107 case CURVEPOLYTYPE:
2108 {
2109 LWCURVEPOLY *c = (LWCURVEPOLY*)geom;
2110 for( i = 0; i < c->nrings; i++ )
2111 lwgeom_affine(c->rings[i], affine);
2112 break;
2113 }
2114 default:
2115 {
2116 if( lwgeom_is_collection(geom) )
2117 {
2118 LWCOLLECTION *c = (LWCOLLECTION*)geom;
2119 for( i = 0; i < c->ngeoms; i++ )
2120 {
2121 lwgeom_affine(c->geoms[i], affine);
2122 }
2123 }
2124 else
2125 {
2126 lwerror("lwgeom_affine: unable to handle type '%s'", lwtype_name(type));
2127 }
2128 }
2129 }
2130
2131 /* Recompute bbox if needed */
2132 if (geom->bbox)
2133 lwgeom_refresh_bbox(geom);
2134}
2135
2136void
2137lwgeom_scale(LWGEOM *geom, const POINT4D *factor)
2138{
2139 int type = geom->type;
2140 uint32_t i;
2141
2142 switch(type)
2143 {
2144 /* Take advantage of fact that pt/ln/circ/tri have same memory structure */
2145 case POINTTYPE:
2146 case LINETYPE:
2147 case CIRCSTRINGTYPE:
2148 case TRIANGLETYPE:
2149 {
2150 LWLINE *l = (LWLINE*)geom;
2151 ptarray_scale(l->points, factor);
2152 break;
2153 }
2154 case POLYGONTYPE:
2155 {
2156 LWPOLY *p = (LWPOLY*)geom;
2157 for( i = 0; i < p->nrings; i++ )
2158 ptarray_scale(p->rings[i], factor);
2159 break;
2160 }
2161 case CURVEPOLYTYPE:
2162 {
2163 LWCURVEPOLY *c = (LWCURVEPOLY*)geom;
2164 for( i = 0; i < c->nrings; i++ )
2165 lwgeom_scale(c->rings[i], factor);
2166 break;
2167 }
2168 default:
2169 {
2170 if( lwgeom_is_collection(geom) )
2171 {
2172 LWCOLLECTION *c = (LWCOLLECTION*)geom;
2173 for( i = 0; i < c->ngeoms; i++ )
2174 {
2175 lwgeom_scale(c->geoms[i], factor);
2176 }
2177 }
2178 else
2179 {
2180 lwerror("lwgeom_scale: unable to handle type '%s'", lwtype_name(type));
2181 }
2182 }
2183 }
2184
2185 /* Recompute bbox if needed */
2186 if (geom->bbox)
2187 lwgeom_refresh_bbox(geom);
2188}
2189
2190LWGEOM *
2191lwgeom_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
2192{
2193 switch(type)
2194 {
2195 case POINTTYPE:
2196 return lwpoint_as_lwgeom(lwpoint_construct_empty(srid, hasz, hasm));
2197 case LINETYPE:
2198 return lwline_as_lwgeom(lwline_construct_empty(srid, hasz, hasm));
2199 case POLYGONTYPE:
2200 return lwpoly_as_lwgeom(lwpoly_construct_empty(srid, hasz, hasm));
2201 case CURVEPOLYTYPE:
2202 return lwcurvepoly_as_lwgeom(lwcurvepoly_construct_empty(srid, hasz, hasm));
2203 case CIRCSTRINGTYPE:
2204 return lwcircstring_as_lwgeom(lwcircstring_construct_empty(srid, hasz, hasm));
2205 case TRIANGLETYPE:
2206 return lwtriangle_as_lwgeom(lwtriangle_construct_empty(srid, hasz, hasm));
2207 case COMPOUNDTYPE:
2208 case MULTIPOINTTYPE:
2209 case MULTILINETYPE:
2210 case MULTIPOLYGONTYPE:
2211 case COLLECTIONTYPE:
2212 return lwcollection_as_lwgeom(lwcollection_construct_empty(type, srid, hasz, hasm));
2213 default:
2214 lwerror("lwgeom_construct_empty: unsupported geometry type: %s",
2215 lwtype_name(type));
2216 return NULL;
2217 }
2218}
2219
2220int
2222{
2223 if ( ! lwgeom || lwgeom_is_empty(lwgeom) )
2224 return LW_FAILURE;
2225
2226 switch( lwgeom->type )
2227 {
2228 case POINTTYPE:
2229 return ptarray_startpoint(((LWPOINT*)lwgeom)->point, pt);
2230 case TRIANGLETYPE:
2231 case CIRCSTRINGTYPE:
2232 case LINETYPE:
2233 return ptarray_startpoint(((LWLINE*)lwgeom)->points, pt);
2234 case POLYGONTYPE:
2235 return lwpoly_startpoint((LWPOLY*)lwgeom, pt);
2236 case TINTYPE:
2237 case CURVEPOLYTYPE:
2238 case COMPOUNDTYPE:
2239 case MULTIPOINTTYPE:
2240 case MULTILINETYPE:
2241 case MULTIPOLYGONTYPE:
2242 case COLLECTIONTYPE:
2244 return lwcollection_startpoint((LWCOLLECTION*)lwgeom, pt);
2245 default:
2246 lwerror("lwgeom_startpoint: unsupported geometry type: %s", lwtype_name(lwgeom->type));
2247 return LW_FAILURE;
2248 }
2249}
2250
2251static inline double
2252snap_to_int(double val)
2253{
2254 const double tolerance = 1e-6;
2255 double rintval = rint(val);
2256 if (fabs(val - rintval) < tolerance)
2257 {
2258 return rintval;
2259 }
2260 return val;
2261}
2262
2263/*
2264 * See https://github.com/libgeos/geos/pull/956
2265 * We use scale for rounding when gridsize is < 1 and
2266 * gridsize for rounding when scale < 1.
2267 */
2268static inline void
2270{
2271 if(grid->xsize > 0)
2272 {
2273 if(grid->xsize < 1)
2274 grid->xscale = snap_to_int(1/grid->xsize);
2275 else
2276 grid->xsize = snap_to_int(grid->xsize);
2277 }
2278 if(grid->ysize > 0)
2279 {
2280 if(grid->ysize < 1)
2281 grid->yscale = snap_to_int(1/grid->ysize);
2282 else
2283 grid->ysize = snap_to_int(grid->ysize);
2284 }
2285}
2286
2287
2288void
2290{
2291 if (!geom) return;
2292 if (lwgeom_is_empty(geom)) return;
2293
2295
2296 switch ( geom->type )
2297 {
2298 case POINTTYPE:
2299 {
2300 LWPOINT *pt = (LWPOINT*)(geom);
2301 ptarray_grid_in_place(pt->point, grid);
2302 return;
2303 }
2304 case CIRCSTRINGTYPE:
2305 case TRIANGLETYPE:
2306 case LINETYPE:
2307 {
2308 LWLINE *ln = (LWLINE*)(geom);
2309 ptarray_grid_in_place(ln->points, grid);
2310 /* For invalid line, return an EMPTY */
2311 if (ln->points->npoints < 2)
2312 ln->points->npoints = 0;
2313 return;
2314 }
2315 case POLYGONTYPE:
2316 {
2317 LWPOLY *ply = (LWPOLY*)(geom);
2318 if (!ply->rings) return;
2319
2320 /* Check first the external ring */
2321 uint32_t i = 0;
2322 POINTARRAY *pa = ply->rings[0];
2323 ptarray_grid_in_place(pa, grid);
2324 if (pa->npoints < 4)
2325 {
2326 /* External ring collapsed: free everything */
2327 for (i = 0; i < ply->nrings; i++)
2328 {
2329 ptarray_free(ply->rings[i]);
2330 }
2331 ply->nrings = 0;
2332 return;
2333 }
2334
2335 /* Check the other rings */
2336 uint32_t j = 1;
2337 for (i = 1; i < ply->nrings; i++)
2338 {
2339 POINTARRAY *pa = ply->rings[i];
2340 ptarray_grid_in_place(pa, grid);
2341
2342 /* Skip bad rings */
2343 if (pa->npoints >= 4)
2344 {
2345 ply->rings[j++] = pa;
2346 }
2347 else
2348 {
2349 ptarray_free(pa);
2350 }
2351 }
2352 /* Adjust ring count appropriately */
2353 ply->nrings = j;
2354 return;
2355 }
2356 case MULTIPOINTTYPE:
2357 case MULTILINETYPE:
2358 case MULTIPOLYGONTYPE:
2359 case TINTYPE:
2360 case COLLECTIONTYPE:
2361 case COMPOUNDTYPE:
2362 {
2363 LWCOLLECTION *col = (LWCOLLECTION*)(geom);
2364 uint32_t i, j = 0;
2365 if (!col->geoms) return;
2366 for (i = 0; i < col->ngeoms; i++)
2367 {
2368 LWGEOM *g = col->geoms[i];
2369 lwgeom_grid_in_place(g, grid);
2370 /* Empty geoms need to be freed */
2371 /* before we move on */
2372 if (lwgeom_is_empty(g))
2373 {
2374 lwgeom_free(g);
2375 continue;
2376 }
2377 col->geoms[j++] = g;
2378 }
2379 col->ngeoms = j;
2380 return;
2381 }
2382 default:
2383 {
2384 lwerror("%s: Unsupported geometry type: %s", __func__,
2385 lwtype_name(geom->type));
2386 return;
2387 }
2388 }
2389}
2390
2391
2392LWGEOM *
2393lwgeom_grid(const LWGEOM *lwgeom, gridspec *grid)
2394{
2395 LWGEOM *lwgeom_out = lwgeom_clone_deep(lwgeom);
2396 lwgeom_grid_in_place(lwgeom_out, grid);
2397 return lwgeom_out;
2398}
2399
2400
2401/* Prototype for recursion */
2402static void lwgeom_subdivide_recursive(const LWGEOM *geom,
2403 uint8_t dimension,
2404 uint32_t maxvertices,
2405 uint32_t depth,
2406 LWCOLLECTION *col,
2407 double gridSize);
2408
2409static void
2411 uint8_t dimension,
2412 uint32_t maxvertices,
2413 uint32_t depth,
2414 LWCOLLECTION *col,
2415 double gridSize)
2416{
2417 const uint32_t maxdepth = 50;
2418
2419 if (!geom)
2420 return;
2421
2422 const GBOX *box_in = lwgeom_get_bbox(geom);
2423 if (!box_in)
2424 return;
2425
2426 LW_ON_INTERRUPT(return);
2427
2428 GBOX clip;
2429 gbox_duplicate(box_in, &clip);
2430 double width = clip.xmax - clip.xmin;
2431 double height = clip.ymax - clip.ymin;
2432
2433 if ( geom->type == POLYHEDRALSURFACETYPE || geom->type == TINTYPE )
2434 lwerror("%s: unsupported geometry type '%s'", __func__, lwtype_name(geom->type));
2435
2436 if ( width == 0.0 && height == 0.0 )
2437 {
2438 if ( geom->type == POINTTYPE && dimension == 0)
2440 return;
2441 }
2442
2443 if (width == 0.0)
2444 {
2445 clip.xmax += FP_TOLERANCE;
2446 clip.xmin -= FP_TOLERANCE;
2447 width = 2 * FP_TOLERANCE;
2448 }
2449 if (height == 0.0)
2450 {
2451 clip.ymax += FP_TOLERANCE;
2452 clip.ymin -= FP_TOLERANCE;
2453 height = 2 * FP_TOLERANCE;
2454 }
2455
2456 /* Always just recurse into collections */
2457 if ( lwgeom_is_collection(geom) && geom->type != MULTIPOINTTYPE )
2458 {
2459 LWCOLLECTION *incol = (LWCOLLECTION*)geom;
2460 /* Don't increment depth yet, since we aren't actually
2461 * subdividing geometries yet */
2462 for (uint32_t i = 0; i < incol->ngeoms; i++ )
2463 lwgeom_subdivide_recursive(incol->geoms[i], dimension, maxvertices, depth, col, gridSize);
2464 return;
2465 }
2466
2467 if (lwgeom_dimension(geom) < dimension)
2468 {
2469 /* We've hit a lower dimension object produced by clipping at
2470 * a shallower recursion level. Ignore it. */
2471 return;
2472 }
2473
2474 /* But don't go too far. 2^50 ~= 10^15, that's enough subdivision */
2475 /* Just add what's left */
2476 if ( depth > maxdepth )
2477 {
2479 return;
2480 }
2481
2482 uint32_t nvertices = lwgeom_count_vertices(geom);
2483
2484 /* Skip empties entirely */
2485 if (nvertices == 0)
2486 return;
2487
2488 /* If it is under the vertex tolerance, just add it, we're done */
2489 if (nvertices <= maxvertices)
2490 {
2492 return;
2493 }
2494
2495 uint8_t split_ordinate = (width > height) ? 0 : 1;
2496 double center = (split_ordinate == 0) ? (clip.xmin + clip.xmax) / 2 : (clip.ymin + clip.ymax) / 2;
2497 double pivot = DBL_MAX;
2498 if (geom->type == POLYGONTYPE)
2499 {
2500 uint32_t ring_to_trim = 0;
2501 double ring_area = 0;
2502 double pivot_eps = DBL_MAX;
2503 double pt_eps = DBL_MAX;
2504 POINTARRAY *pa;
2505 LWPOLY *lwpoly = (LWPOLY *)geom;
2506
2507 /* if there are more points in holes than in outer ring */
2508 if (nvertices >= 2 * lwpoly->rings[0]->npoints)
2509 {
2510 /* trim holes starting from biggest */
2511 for (uint32_t i = 1; i < lwpoly->nrings; i++)
2512 {
2513 double current_ring_area = fabs(ptarray_signed_area(lwpoly->rings[i]));
2514 if (current_ring_area >= ring_area)
2515 {
2516 ring_area = current_ring_area;
2517 ring_to_trim = i;
2518 }
2519 }
2520 }
2521
2522 pa = lwpoly->rings[ring_to_trim];
2523
2524 /* find most central point in chosen ring */
2525 for (uint32_t i = 0; i < pa->npoints; i++)
2526 {
2527 double pt;
2528 if (split_ordinate == 0)
2529 pt = getPoint2d_cp(pa, i)->x;
2530 else
2531 pt = getPoint2d_cp(pa, i)->y;
2532 pt_eps = fabs(pt - center);
2533 if (pivot_eps > pt_eps)
2534 {
2535 pivot = pt;
2536 pivot_eps = pt_eps;
2537 }
2538 }
2539 }
2540 GBOX subbox1, subbox2;
2541 gbox_duplicate(&clip, &subbox1);
2542 gbox_duplicate(&clip, &subbox2);
2543
2544 if (pivot == DBL_MAX)
2545 pivot = center;
2546
2547 if (split_ordinate == 0)
2548 {
2549 if (FP_NEQUALS(subbox1.xmax, pivot) && FP_NEQUALS(subbox1.xmin, pivot))
2550 subbox1.xmax = subbox2.xmin = pivot;
2551 else
2552 subbox1.xmax = subbox2.xmin = center;
2553 }
2554 else
2555 {
2556 if (FP_NEQUALS(subbox1.ymax, pivot) && FP_NEQUALS(subbox1.ymin, pivot))
2557 subbox1.ymax = subbox2.ymin = pivot;
2558 else
2559 subbox1.ymax = subbox2.ymin = center;
2560 }
2561
2562 ++depth;
2563
2564 {
2566 geom->srid, subbox1.xmin, subbox1.ymin, subbox1.xmax, subbox1.ymax);
2567 LWGEOM *clipped = lwgeom_intersection_prec(geom, subbox, gridSize);
2568 lwgeom_simplify_in_place(clipped, 0.0, LW_TRUE);
2569 lwgeom_free(subbox);
2570 if (clipped && !lwgeom_is_empty(clipped))
2571 {
2572 lwgeom_subdivide_recursive(clipped, dimension, maxvertices, depth, col, gridSize);
2573 lwgeom_free(clipped);
2574 }
2575 }
2576 {
2578 geom->srid, subbox2.xmin, subbox2.ymin, subbox2.xmax, subbox2.ymax);
2579 LWGEOM *clipped = lwgeom_intersection_prec(geom, subbox, gridSize);
2580 lwgeom_simplify_in_place(clipped, 0.0, LW_TRUE);
2581 lwgeom_free(subbox);
2582 if (clipped && !lwgeom_is_empty(clipped))
2583 {
2584 lwgeom_subdivide_recursive(clipped, dimension, maxvertices, depth, col, gridSize);
2585 lwgeom_free(clipped);
2586 }
2587 }
2588}
2589
2591lwgeom_subdivide_prec(const LWGEOM *geom, uint32_t maxvertices, double gridSize)
2592{
2593 static uint32_t startdepth = 0;
2594 static uint32_t minmaxvertices = 5;
2595 LWCOLLECTION *col;
2596
2598
2599 if ( lwgeom_is_empty(geom) )
2600 return col;
2601
2602 if ( maxvertices < minmaxvertices )
2603 {
2604 lwcollection_free(col);
2605 lwerror("%s: cannot subdivide to fewer than %d vertices per output", __func__, minmaxvertices);
2606 }
2607
2608 lwgeom_subdivide_recursive(geom, lwgeom_dimension(geom), maxvertices, startdepth, col, gridSize);
2609 lwgeom_set_srid((LWGEOM*)col, geom->srid);
2610 return col;
2611}
2612
2614lwgeom_subdivide(const LWGEOM *geom, uint32_t maxvertices)
2615{
2616 return lwgeom_subdivide_prec(geom, maxvertices, -1);
2617}
2618
2619
2620
2621int
2623{
2624 int type = geom->type;
2625
2626 if( type != LINETYPE )
2627 {
2628 lwnotice("Geometry is not a LINESTRING");
2629 return LW_FALSE;
2630 }
2631 return lwline_is_trajectory((LWLINE*)geom);
2632}
2633
2634#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1]
2635STATIC_ASSERT(sizeof(double) == sizeof(uint64_t),this_should_be_true);
2636
2637static double trim_preserve_decimal_digits(double d, int32_t decimal_digits)
2638{
2639 uint64_t dint = 0;
2640 memcpy(&dint, &d, sizeof(double));
2641 /* Extract the exponent from the IEEE 754 integer representation, which */
2642 /* corresponds to floor(log2(fabs(d))) */
2643 const int exponent = (int)((dint >> 52) & 2047) - 1023;
2644 /* (x * 851 + 255) / 256 == 1 + (int)(x * log2(10)) for x in [0,30] */
2645 int bits_needed = 1 + exponent + (decimal_digits * 851 + 255) / 256;
2646 /* for negative values, (x * 851 + 255) / 256 == (int)(x * log2(10)), so */
2647 /* subtract one */
2648 if (decimal_digits < 0)
2649 bits_needed --;
2650
2651 /* This will also handle NaN and Inf since exponent = 1023, and thus for */
2652 /* reasonable decimal_digits values bits_needed will be > 52 */
2653 if (bits_needed >= 52)
2654 {
2655 return d;
2656 }
2657 if (bits_needed < 1 )
2658 bits_needed = 1;
2659 const uint64_t mask = 0xffffffffffffffffULL << (52 - bits_needed);
2660 dint &= mask;
2661 memcpy(&d, &dint, sizeof(double));
2662 return d;
2663}
2664
2665void lwgeom_trim_bits_in_place(LWGEOM* geom, int32_t prec_x, int32_t prec_y, int32_t prec_z, int32_t prec_m)
2666{
2668 POINT4D p;
2669
2670 while (lwpointiterator_has_next(it))
2671 {
2672 lwpointiterator_peek(it, &p);
2673 p.x = trim_preserve_decimal_digits(p.x, prec_x);
2674 p.y = trim_preserve_decimal_digits(p.y, prec_y);
2675 if (lwgeom_has_z(geom))
2676 p.z = trim_preserve_decimal_digits(p.z, prec_z);
2677 if (lwgeom_has_m(geom))
2678 p.m = trim_preserve_decimal_digits(p.m, prec_m);
2680 }
2681
2683}
2684
2685LWGEOM *
2687{
2688 int32_t srid = lwgeom_get_srid(lwgeom);
2689 uint8_t hasz = lwgeom_has_z(lwgeom);
2690 uint8_t hasm = lwgeom_has_m(lwgeom);
2691
2692 switch (lwgeom->type)
2693 {
2694 case POINTTYPE:
2695 case MULTIPOINTTYPE: {
2696 return lwgeom_construct_empty(lwgeom->type, srid, hasz, hasm);
2697 }
2698 case LINETYPE:
2699 case CIRCSTRINGTYPE: {
2700 if (lwgeom_is_closed(lwgeom) || lwgeom_is_empty(lwgeom))
2701 return (LWGEOM *)lwmpoint_construct_empty(srid, hasz, hasm);
2702 else
2703 {
2704 LWLINE *lwline = (LWLINE *)lwgeom;
2705 LWMPOINT *lwmpoint = lwmpoint_construct_empty(srid, hasz, hasm);
2706 POINT4D pt;
2707 getPoint4d_p(lwline->points, 0, &pt);
2708 lwmpoint_add_lwpoint(lwmpoint, lwpoint_make(srid, hasz, hasm, &pt));
2709 getPoint4d_p(lwline->points, lwline->points->npoints - 1, &pt);
2710 lwmpoint_add_lwpoint(lwmpoint, lwpoint_make(srid, hasz, hasm, &pt));
2711
2712 return (LWGEOM *)lwmpoint;
2713 }
2714 }
2715 case MULTILINETYPE:
2716 case MULTICURVETYPE: {
2717 LWMLINE *lwmline = (LWMLINE *)lwgeom;
2718 POINT4D *out = lwalloc(sizeof(POINT4D) * lwmline->ngeoms * 2);
2719 uint32_t n = 0;
2720
2721 for (uint32_t i = 0; i < lwmline->ngeoms; i++)
2722 {
2723 LWMPOINT *points = lwgeom_as_lwmpoint(lwgeom_boundary((LWGEOM *)lwmline->geoms[i]));
2724 if (!points)
2725 continue;
2726
2727 for (uint32_t k = 0; k < points->ngeoms; k++)
2728 {
2729 POINT4D pt = getPoint4d(points->geoms[k]->point, 0);
2730
2731 uint8_t seen = LW_FALSE;
2732 for (uint32_t j = 0; j < n; j++)
2733 {
2734 if (memcmp(&(out[j]), &pt, sizeof(POINT4D)) == 0)
2735 {
2736 seen = LW_TRUE;
2737 out[j] = out[--n];
2738 break;
2739 }
2740 }
2741 if (!seen)
2742 out[n++] = pt;
2743 }
2744
2745 lwgeom_free((LWGEOM *)points);
2746 }
2747
2748 LWMPOINT *lwmpoint = lwmpoint_construct_empty(srid, hasz, hasm);
2749
2750 for (uint32_t i = 0; i < n; i++)
2751 lwmpoint_add_lwpoint(lwmpoint, lwpoint_make(srid, hasz, hasm, &(out[i])));
2752
2753 lwfree(out);
2754
2755 return (LWGEOM *)lwmpoint;
2756 }
2757 case TRIANGLETYPE: {
2758 LWTRIANGLE *lwtriangle = (LWTRIANGLE *)lwgeom;
2759 POINTARRAY *points = ptarray_clone_deep(lwtriangle->points);
2760 return (LWGEOM *)lwline_construct(srid, 0, points);
2761 }
2762 case POLYGONTYPE: {
2763 LWPOLY *lwpoly = (LWPOLY *)lwgeom;
2764
2765 LWMLINE *lwmline = lwmline_construct_empty(srid, hasz, hasm);
2766 for (uint32_t i = 0; i < lwpoly->nrings; i++)
2767 {
2768 POINTARRAY *ring = ptarray_clone_deep(lwpoly->rings[i]);
2769 lwmline_add_lwline(lwmline, lwline_construct(srid, 0, ring));
2770 }
2771
2772 /* Homogenize the multilinestring to hopefully get a single LINESTRING */
2773 LWGEOM *lwout = lwgeom_homogenize((LWGEOM *)lwmline);
2774 lwgeom_free((LWGEOM *)lwmline);
2775 return lwout;
2776 }
2777 case CURVEPOLYTYPE: {
2778 LWCURVEPOLY *lwcurvepoly = (LWCURVEPOLY *)lwgeom;
2779 LWCOLLECTION *lwcol = lwcollection_construct_empty(MULTICURVETYPE, srid, hasz, hasm);
2780
2781 for (uint32_t i = 0; i < lwcurvepoly->nrings; i++)
2782 lwcol = lwcollection_add_lwgeom(lwcol, lwgeom_clone_deep(lwcurvepoly->rings[i]));
2783
2784 return (LWGEOM *)lwcol;
2785 }
2786 case MULTIPOLYGONTYPE:
2787 case COLLECTIONTYPE:
2788 case TINTYPE: {
2789 LWCOLLECTION *lwcol = (LWCOLLECTION *)lwgeom;
2790 LWCOLLECTION *lwcol_boundary = lwcollection_construct_empty(COLLECTIONTYPE, srid, hasz, hasm);
2791
2792 for (uint32_t i = 0; i < lwcol->ngeoms; i++)
2793 lwcollection_add_lwgeom(lwcol_boundary, lwgeom_boundary(lwcol->geoms[i]));
2794
2795 LWGEOM *lwout = lwgeom_homogenize((LWGEOM *)lwcol_boundary);
2796 lwgeom_free((LWGEOM *)lwcol_boundary);
2797
2798 return lwout;
2799 }
2800 default:
2801 lwerror("%s: unsupported geometry type: %s", __func__, lwtype_name(lwgeom->type));
2802 return NULL;
2803 }
2804}
2805
2806int
2808{
2810 int hasz = lwgeom_has_z(lwgeom);
2811 int hasm = lwgeom_has_m(lwgeom);
2812
2813 while (lwpointiterator_has_next(it))
2814 {
2815 POINT4D p;
2816 lwpointiterator_next(it, &p);
2817 int finite = isfinite(p.x) &&
2818 isfinite(p.y) &&
2819 (hasz ? isfinite(p.z) : 1) &&
2820 (hasm ? isfinite(p.m) : 1);
2821
2822 if (!finite)
2823 {
2825 return LW_FALSE;
2826 }
2827 }
2829 return LW_TRUE;
2830}
char * r
Definition cu_in_wkt.c:24
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition cu_print.c:267
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:445
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:752
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)
POINT4D getPoint4d(const POINTARRAY *pa, uint32_t n)
Definition lwgeom_api.c:107
#define LW_FALSE
Definition liblwgeom.h:94
#define COLLECTIONTYPE
Definition liblwgeom.h:108
#define COMPOUNDTYPE
Definition liblwgeom.h:110
double distance2d_pt_pt(const POINT2D *p1, const POINT2D *p2)
Definition measures.c:2344
void lwmpoint_free(LWMPOINT *mpt)
Definition lwmpoint.c:72
void lwpoint_free(LWPOINT *pt)
Definition lwpoint.c:213
#define LW_FAILURE
Definition liblwgeom.h:96
#define CURVEPOLYTYPE
Definition liblwgeom.h:111
LWMLINE * lwmline_construct_empty(int32_t srid, char hasz, char hasm)
Definition lwmline.c:38
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:243
LWCURVEPOLY * lwcurvepoly_construct_empty(int32_t srid, char hasz, char hasm)
Definition lwcurvepoly.c:35
#define MULTILINETYPE
Definition liblwgeom.h:106
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:113
#define LINETYPE
Definition liblwgeom.h:103
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:252
#define WKT_EXTENDED
Definition liblwgeom.h:2218
LWMPOINT * lwmpoint_add_lwpoint(LWMPOINT *mobj, const LWPOINT *obj)
Definition lwmpoint.c:45
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition lwout_wkt.c:708
#define MULTIPOINTTYPE
Definition liblwgeom.h:105
#define FLAGS_SET_BBOX(flags, value)
Definition liblwgeom.h:174
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:268
LWGEOM * lwgeom_intersection_prec(const LWGEOM *geom1, const LWGEOM *geom2, double gridSize)
LWCOLLECTION * lwcollection_segmentize2d(const LWCOLLECTION *coll, double dist)
LWGEOM * lwgeom_homogenize(const LWGEOM *geom)
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:102
#define FLAGS_GET_Z(flags)
Definition liblwgeom.h:165
void * lwalloc(size_t size)
Definition lwutil.c:227
#define TINTYPE
Definition liblwgeom.h:116
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition lwline.c:42
#define MULTIPOLYGONTYPE
Definition liblwgeom.h:107
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:248
#define FLAGS_NDIMS(flags)
Definition liblwgeom.h:179
#define POLYGONTYPE
Definition liblwgeom.h:104
void lwcircstring_free(LWCIRCSTRING *curve)
LWCOMPOUND * lwcompound_construct_from_lwline(const LWLINE *lwpoly)
Construct an equivalent compound curve from a linestring.
Definition lwcompound.c:232
LWMLINE * lwmline_add_lwline(LWMLINE *mobj, const LWLINE *obj)
Definition lwmline.c:46
void lwtriangle_free(LWTRIANGLE *triangle)
Definition lwtriangle.c:69
#define POLYHEDRALSURFACETYPE
Definition liblwgeom.h:114
#define CIRCSTRINGTYPE
Definition liblwgeom.h:109
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:166
void lwcollection_free(LWCOLLECTION *col)
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
Definition lwgeom_api.c:125
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:170
LWMPOINT * lwmpoint_construct_empty(int32_t srid, char hasz, char hasm)
Definition lwmpoint.c:39
#define FLAGS_GET_ZM(flags)
Definition liblwgeom.h:180
LWPOINT * lwpoint_make(int32_t srid, int hasz, int hasm, const POINT4D *p)
Definition lwpoint.c:206
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:112
#define TRIANGLETYPE
Definition liblwgeom.h:115
LWCIRCSTRING * lwcircstring_construct_empty(int32_t srid, char hasz, char hasm)
#define FLAGS_SET_GEODETIC(flags, value)
Definition liblwgeom.h:175
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:93
int lwline_is_trajectory(const LWLINE *geom)
Definition lwline.c:454
LWGEOM * lwgeom_stroke(const LWGEOM *geom, uint32_t perQuad)
Convert type with arcs into equivalent linearized type.
Definition lwstroke.c:871
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:215
LWLINE * lwline_construct_empty(int32_t srid, char hasz, char hasm)
Definition lwline.c:55
#define NUMTYPES
Definition liblwgeom.h:118
void lwline_free(LWLINE *line)
Definition lwline.c:67
#define FLAGS_GET_GEODETIC(flags)
Definition liblwgeom.h:168
POINTARRAY * ptarray_clone_deep(const POINTARRAY *ptarray)
Deep clone a pointarray (also clones serialized pointlist)
Definition ptarray.c:643
enum LWORD_T LWORD
Ordinate names.
double lwline_length_2d(const LWLINE *line)
Definition lwline.c:520
void ptarray_longitude_shift(POINTARRAY *pa)
Longitude shift for a pointarray.
Definition ptarray.c:1625
LWPOLY * lwpoly_clone(const LWPOLY *lwgeom)
Definition lwpoly.c:213
double lwcircstring_length_2d(const LWCIRCSTRING *circ)
LWLINE * lwline_force_dims(const LWLINE *lwline, int hasz, int hasm, double zval, double mval)
Definition lwline.c:486
int lwcircstring_is_closed(const LWCIRCSTRING *curve)
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:117
double ptarray_signed_area(const POINTARRAY *pa)
Returns the area in cartesian units.
Definition ptarray.c:1143
#define LW_ON_INTERRUPT(x)
int lwline_is_closed(const LWLINE *line)
Definition lwline.c:445
uint32_t lwline_count_vertices(const LWLINE *line)
Definition lwline.c:505
LWCIRCSTRING * lwcircstring_clone(const LWCIRCSTRING *curve)
LWPOINT * lwpoint_force_dims(const LWPOINT *lwpoint, int hasz, int hasm, double zval, double mval)
Definition lwpoint.c:304
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:2207
int lwcompound_is_closed(const LWCOMPOUND *curve)
Definition lwcompound.c:48
double lwtriangle_perimeter_2d(const LWTRIANGLE *triangle)
Definition lwtriangle.c:210
int lwpoly_is_clockwise(LWPOLY *poly)
Definition lwpoly.c:288
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
LWPOLY * lwpoly_force_dims(const LWPOLY *lwpoly, int hasz, int hasm, double zval, double mval)
Definition lwpoly.c:394
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:1662
double lwtriangle_perimeter(const LWTRIANGLE *triangle)
Definition lwtriangle.c:201
int lwpoint_is_empty(const LWPOINT *point)
void ptarray_simplify_in_place(POINTARRAY *pa, double tolerance, uint32_t minpts)
Definition ptarray.c:1844
double lwcompound_length(const LWCOMPOUND *comp)
Definition lwcompound.c:112
void ptarray_grid_in_place(POINTARRAY *pa, gridspec *grid)
Snap to grid.
Definition ptarray.c:2222
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:2189
LWLINE * lwline_clone(const LWLINE *lwgeom)
Definition lwline.c:93
void ptarray_affine(POINTARRAY *pa, const AFFINE *affine)
Affine transform a pointarray.
Definition ptarray.c:2021
int lwpsurface_is_closed(const LWPSURFACE *psurface)
Definition lwpsurface.c:99
double lwcurvepoly_perimeter(const LWCURVEPOLY *poly)
LWTRIANGLE * lwtriangle_clone(const LWTRIANGLE *lwgeom)
Definition lwtriangle.c:99
uint32_t lwpoly_count_vertices(const LWPOLY *poly)
Definition lwpoly.c:418
char lwpoly_same(const LWPOLY *p1, const LWPOLY *p2)
Definition lwpoly.c:339
double lwline_length(const LWLINE *line)
Definition lwline.c:513
LWLINE * lwline_clone_deep(const LWLINE *lwgeom)
Definition lwline.c:109
void lwpoly_force_clockwise(LWPOLY *poly)
Definition lwpoly.c:268
uint32_t lwcollection_count_vertices(const LWCOLLECTION *col)
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
int lwtin_is_closed(const LWTIN *tin)
Definition lwtin.c:93
char lwcircstring_same(const LWCIRCSTRING *p1, const LWCIRCSTRING *p2)
LWCOLLECTION * lwcollection_force_dims(const LWCOLLECTION *lwcol, int hasz, int hasm, double zval, double mval)
double lwcircstring_length(const LWCIRCSTRING *circ)
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:394
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:57
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:1053
LWGEOM * lwmpoint_as_lwgeom(const LWMPOINT *obj)
Definition lwgeom.c:304
void lwgeom_refresh_bbox(LWGEOM *lwgeom)
Drop current bbox and calculate a fresh one.
Definition lwgeom.c:707
static double trim_preserve_decimal_digits(double d, int32_t decimal_digits)
Definition lwgeom.c:2637
void lwgeom_set_geodetic(LWGEOM *geom, int value)
Set the FLAGS geodetic bit on geometry an all sub-geometries and pointlists.
Definition lwgeom.c:964
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition lwgeom.c:344
char lwgeom_same(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)
geom1 same as geom2 iff
Definition lwgeom.c:591
LWTIN * lwgeom_as_lwtin(const LWGEOM *lwgeom)
Definition lwgeom.c:277
int lwgeom_ndims(const LWGEOM *geom)
Return the number of dimensions (2, 3, 4) in a geometry.
Definition lwgeom.c:955
uint32_t lwtype_get_collectiontype(uint8_t type)
Given an lwtype number, what homogeneous collection can hold it?
Definition lwgeom.c:1194
static void condition_gridspec_scale(gridspec *grid)
Definition lwgeom.c:2269
int32_t lwgeom_get_srid(const LWGEOM *geom)
Return SRID number.
Definition lwgeom.c:927
int lwgeom_is_unitary(const LWGEOM *geom)
Determine whether a Geometry is a bag of sub-geometries.
Definition lwgeom.c:1140
LWGEOM * lwgeom_force_dims(const LWGEOM *geom, int hasz, int hasm, double zval, double mval)
Definition lwgeom.c:817
int lwgeom_startpoint(const LWGEOM *lwgeom, POINT4D *pt)
Definition lwgeom.c:2221
int lwgeom_is_collection(const LWGEOM *geom)
Determine whether a LWGEOM contains sub-geometries or not This basically just checks that the struct ...
Definition lwgeom.c:1097
LWGEOM * lwtin_as_lwgeom(const LWTIN *obj)
Definition lwgeom.c:284
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:1610
int lwgeom_has_rings(const LWGEOM *geom)
Is this a type that has rings enclosing an area, but is not a collection of areas?...
Definition lwgeom.c:1146
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:2665
LWGEOM * lwgeom_grid(const LWGEOM *lwgeom, gridspec *grid)
Definition lwgeom.c:2393
void lwgeom_longitude_shift(LWGEOM *lwgeom)
Definition lwgeom.c:1008
LWGEOM * lwgeom_as_multi(const LWGEOM *lwgeom)
Create a new LWGEOM of the appropriate MULTI* type.
Definition lwgeom.c:380
LWGEOM * lwgeom_boundary(LWGEOM *lwgeom)
Definition lwgeom.c:2686
LWGEOM * lwgeom_simplify(const LWGEOM *igeom, double dist, int preserve_collapsed)
Simplification.
Definition lwgeom.c:1956
double lwgeom_perimeter_2d(const LWGEOM *geom)
Definition lwgeom.c:2016
int lwpoint_inside_circle(const LWPOINT *p, double cx, double cy, double rad)
Definition lwgeom.c:662
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
Definition lwgeom.c:233
static int cmp_point_x(const void *pa, const void *pb)
Definition lwgeom.c:1633
LWGEOM * lwcompound_as_lwgeom(const LWCOMPOUND *obj)
Definition lwgeom.c:324
LWGEOM * lwgeom_force_3dz(const LWGEOM *geom, double zval)
Definition lwgeom.c:799
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:2622
LWGEOM * lwgeom_as_curve(const LWGEOM *lwgeom)
Create a new LWGEOM of the appropriate CURVE* type.
Definition lwgeom.c:420
LWGEOM * lwpsurface_as_lwgeom(const LWPSURFACE *obj)
Definition lwgeom.c:289
static double snap_to_int(double val)
Definition lwgeom.c:2252
LWGEOM * lwgeom_segmentize2d(const LWGEOM *lwgeom, double dist)
Definition lwgeom.c:771
LWGEOM * lwgeom_force_sfs(LWGEOM *geom, int version)
Definition lwgeom.c:849
int lwgeom_has_srid(const LWGEOM *geom)
Return true or false depending on whether a geometry has a valid SRID set.
Definition lwgeom.c:1467
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
Definition lwgeom.c:793
double lwgeom_length(const LWGEOM *geom)
Definition lwgeom.c:2038
int lwgeom_needs_bbox(const LWGEOM *geom)
Check whether or not a lwgeom is big enough to warrant a bounding box.
Definition lwgeom.c:1271
int lwgeom_remove_repeated_points_in_place(LWGEOM *geom, double tolerance)
Definition lwgeom.c:1667
LWGEOM * lwgeom_clone(const LWGEOM *lwgeom)
Clone LWGEOM object.
Definition lwgeom.c:491
LWCURVEPOLY * lwgeom_as_lwcurvepoly(const LWGEOM *lwgeom)
Definition lwgeom.c:206
char * lwgeom_to_ewkt(const LWGEOM *lwgeom)
Return an allocated string.
Definition lwgeom.c:565
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition lwgeom.c:934
int lwtype_is_collection(uint8_t type)
Return TRUE if the geometry is structured as a wrapper on a geoms/ngeoms list of sub-geometries.
Definition lwgeom.c:1168
void lwgeom_drop_bbox(LWGEOM *lwgeom)
Call this function to drop BBOX and SRID from LWGEOM.
Definition lwgeom.c:682
int lwgeom_isfinite(const LWGEOM *lwgeom)
Check if a LWGEOM has any non-finite (NaN or Inf) coordinates.
Definition lwgeom.c:2807
static int lwcollection_dimensionality(const LWCOLLECTION *col)
Definition lwgeom.c:1476
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
Definition lwgeom.c:215
double lwgeom_area(const LWGEOM *geom)
Definition lwgeom.c:1971
uint32_t lwgeom_count_vertices(const LWGEOM *geom)
Count points in an LWGEOM.
Definition lwgeom.c:1309
int lwgeom_has_patches(const LWGEOM *geom)
Definition lwgeom.c:1126
LWGEOM * lwcurvepoly_as_lwgeom(const LWCURVEPOLY *obj)
Definition lwgeom.c:319
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:1361
LWTRIANGLE * lwgeom_as_lwtriangle(const LWGEOM *lwgeom)
Definition lwgeom.c:224
LWCOMPOUND * lwgeom_as_lwcompound(const LWGEOM *lwgeom)
Definition lwgeom.c:197
LWGEOM * lwtriangle_as_lwgeom(const LWTRIANGLE *obj)
Definition lwgeom.c:334
void lwgeom_swap_ordinates(LWGEOM *in, LWORD o1, LWORD o2)
Swap ordinate values in every vertex of the geometry.
Definition lwgeom.c:1541
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition lwgeom.c:339
void lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
Definition lwgeom.c:2083
LWMLINE * lwgeom_as_lwmline(const LWGEOM *lwgeom)
Definition lwgeom.c:251
uint8_t lwtype_multitype(uint8_t type)
Definition lwgeom.c:370
LWMPOLY * lwgeom_as_lwmpoly(const LWGEOM *lwgeom)
Definition lwgeom.c:260
LWCIRCSTRING * lwgeom_as_lwcircstring(const LWGEOM *lwgeom)
Definition lwgeom.c:188
static int cmp_point_y(const void *pa, const void *pb)
Definition lwgeom.c:1650
double lwgeom_length_2d(const LWGEOM *geom)
Definition lwgeom.c:2060
uint32_t lwgeom_count_rings(const LWGEOM *geom)
Count rings in an LWGEOM.
Definition lwgeom.c:1419
void lwgeom_reverse_in_place(LWGEOM *geom)
Reverse vertex order of LWGEOM.
Definition lwgeom.c:103
void lwgeom_force_clockwise(LWGEOM *lwgeom)
Force Right-hand-rule on LWGEOM polygons.
Definition lwgeom.c:38
int lwgeom_is_solid(const LWGEOM *geom)
Return LW_TRUE if geometry has SOLID flag.
Definition lwgeom.c:948
int lwtype_is_unitary(uint32_t lwtype)
Definition lwgeom.c:1104
LWGEOM * lwmline_as_lwgeom(const LWMLINE *obj)
Definition lwgeom.c:299
#define STATIC_ASSERT(COND, MSG)
Definition lwgeom.c:2634
uint8_t MULTITYPE[NUMTYPES]
Look-up for the correct MULTI* type promotion for singleton types.
Definition lwgeom.c:354
LWGEOM * lwcircstring_as_lwgeom(const LWCIRCSTRING *obj)
Definition lwgeom.c:314
LWCOLLECTION * lwgeom_subdivide_prec(const LWGEOM *geom, uint32_t maxvertices, double gridSize)
Definition lwgeom.c:2591
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:755
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition lwgeom.c:179
LWGEOM * lwgeom_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
Definition lwgeom.c:2191
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:714
LWMPOINT * lwgeom_as_lwmpoint(const LWGEOM *lwgeom)
Definition lwgeom.c:242
int lwgeom_dimensionality(const LWGEOM *geom)
Return the dimensionality (relating to point/line/poly) of an lwgeom.
Definition lwgeom.c:1489
void lwgeom_grid_in_place(LWGEOM *geom, gridspec *grid)
Definition lwgeom.c:2289
void lwgeom_free(LWGEOM *lwgeom)
Definition lwgeom.c:1218
LWCOLLECTION * lwgeom_subdivide(const LWGEOM *geom, uint32_t maxvertices)
Definition lwgeom.c:2614
LWPSURFACE * lwgeom_as_lwpsurface(const LWGEOM *lwgeom)
Definition lwgeom.c:269
static void lwgeom_subdivide_recursive(const LWGEOM *geom, uint8_t dimension, uint32_t maxvertices, uint32_t depth, LWCOLLECTION *col, double gridSize)
Definition lwgeom.c:2410
void lwgeom_release(LWGEOM *lwgeom)
Free the containing LWGEOM and the associated BOX.
Definition lwgeom.c:468
double lwgeom_perimeter(const LWGEOM *geom)
Definition lwgeom.c:1994
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition lwgeom.c:941
void lwgeom_scale(LWGEOM *geom, const POINT4D *factor)
Definition lwgeom.c:2137
LWGEOM * lwmpoly_as_lwgeom(const LWMPOLY *obj)
Definition lwgeom.c:294
LWGEOM * lwgeom_force_4d(const LWGEOM *geom, double zval, double mval)
Definition lwgeom.c:811
int lwgeom_is_clockwise(LWGEOM *lwgeom)
Check clockwise orientation on LWGEOM polygons.
Definition lwgeom.c:66
int lwgeom_simplify_in_place(LWGEOM *geom, double epsilon, int preserve_collapsed)
Definition lwgeom.c:1823
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition lwgeom.c:329
LWGEOM * lwgeom_force_3dm(const LWGEOM *geom, double mval)
Definition lwgeom.c:805
void lwgeom_add_bbox(LWGEOM *lwgeom)
Ensure there's a box in the LWGEOM.
Definition lwgeom.c:695
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:743
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition lwgeom.c:309
LWGEOM * lwgeom_remove_repeated_points(const LWGEOM *in, double tolerance)
Definition lwgeom.c:1534
void lwgeom_drop_srid(LWGEOM *lwgeom)
Definition lwgeom.c:765
LWGEOM * lwgeom_clone_deep(const LWGEOM *lwgeom)
Deep-clone an LWGEOM object.
Definition lwgeom.c:529
LWGEOM * lwgeom_reverse(const LWGEOM *geom)
Definition lwgeom.c:94
#define LWDEBUG(level, msg)
Definition lwgeom_log.h:101
#define LWDEBUGF(level, msg,...)
Definition lwgeom_log.h:106
void lwnotice(const char *fmt,...) __attribute__((format(printf
Write a notice out to the notice handler.
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
static double distance2d_sqr_pt_pt(const POINT2D *p1, const POINT2D *p2)
Definition lwinline.h:33
static LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Definition lwinline.h:127
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:199
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:97
static double pivot(double *left, double *right)
double ymax
Definition liblwgeom.h:357
double xmax
Definition liblwgeom.h:355
double ymin
Definition liblwgeom.h:356
double xmin
Definition liblwgeom.h:354
lwflags_t flags
Definition liblwgeom.h:353
uint32_t ngeoms
Definition liblwgeom.h:580
uint8_t type
Definition liblwgeom.h:578
LWGEOM ** geoms
Definition liblwgeom.h:575
LWGEOM ** rings
Definition liblwgeom.h:603
uint32_t nrings
Definition liblwgeom.h:608
uint8_t type
Definition liblwgeom.h:462
GBOX * bbox
Definition liblwgeom.h:458
int32_t srid
Definition liblwgeom.h:460
lwflags_t flags
Definition liblwgeom.h:461
POINTARRAY * points
Definition liblwgeom.h:483
uint8_t type
Definition liblwgeom.h:486
LWLINE ** geoms
Definition liblwgeom.h:547
uint32_t ngeoms
Definition liblwgeom.h:552
uint32_t ngeoms
Definition liblwgeom.h:538
LWPOINT ** geoms
Definition liblwgeom.h:533
POINTARRAY * point
Definition liblwgeom.h:471
uint8_t type
Definition liblwgeom.h:474
POINTARRAY ** rings
Definition liblwgeom.h:519
uint32_t nrings
Definition liblwgeom.h:524
POINTARRAY * points
Definition liblwgeom.h:495
double y
Definition liblwgeom.h:390
double x
Definition liblwgeom.h:390
double m
Definition liblwgeom.h:414
double x
Definition liblwgeom.h:414
double z
Definition liblwgeom.h:414
double y
Definition liblwgeom.h:414
lwflags_t flags
Definition liblwgeom.h:431
uint32_t maxpoints
Definition liblwgeom.h:428
uint32_t npoints
Definition liblwgeom.h:427
double xscale
Definition liblwgeom.h:1407
double ysize
Definition liblwgeom.h:1404
double xsize
Definition liblwgeom.h:1403
double yscale
Definition liblwgeom.h:1408
Snap-to-grid.
Definition liblwgeom.h:1398