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