PostGIS  3.7.0dev-r@@SVN_REVISION@@
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 
37 void
39 {
40  LWCOLLECTION *coll;
41  uint32_t i;
42 
43  switch (lwgeom->type)
44  {
45  case POLYGONTYPE:
46  lwpoly_force_clockwise((LWPOLY *)lwgeom);
47  return;
48 
49  case TRIANGLETYPE:
51  return;
52 
53  /* Not handle POLYHEDRALSURFACE and TIN
54  as they are supposed to be well oriented */
55  case MULTIPOLYGONTYPE:
56  case COLLECTIONTYPE:
57  coll = (LWCOLLECTION *)lwgeom;
58  for (i=0; i<coll->ngeoms; i++)
59  lwgeom_force_clockwise(coll->geoms[i]);
60  return;
61  }
62 }
63 
65 int
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 
76  case MULTIPOLYGONTYPE:
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 
93 LWGEOM *
94 lwgeom_reverse(const LWGEOM *geom)
95 {
96  LWGEOM *geomout = lwgeom_clone_deep(geom);
97  lwgeom_reverse_in_place(geomout);
98  return geomout;
99 }
100 
102 void
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 
178 LWLINE *
179 lwgeom_as_lwline(const LWGEOM *lwgeom)
180 {
181  if ( lwgeom == NULL ) return NULL;
182  if ( lwgeom->type == LINETYPE )
183  return (LWLINE *)lwgeom;
184  else return NULL;
185 }
186 
187 LWCIRCSTRING *
189 {
190  if ( lwgeom == NULL ) return NULL;
191  if ( lwgeom->type == CIRCSTRINGTYPE )
192  return (LWCIRCSTRING *)lwgeom;
193  else return NULL;
194 }
195 
196 LWCOMPOUND *
198 {
199  if ( lwgeom == NULL ) return NULL;
200  if ( lwgeom->type == COMPOUNDTYPE )
201  return (LWCOMPOUND *)lwgeom;
202  else return NULL;
203 }
204 
205 LWCURVEPOLY *
207 {
208  if ( lwgeom == NULL ) return NULL;
209  if ( lwgeom->type == CURVEPOLYTYPE )
210  return (LWCURVEPOLY *)lwgeom;
211  else return NULL;
212 }
213 
214 LWPOLY *
215 lwgeom_as_lwpoly(const LWGEOM *lwgeom)
216 {
217  if ( lwgeom == NULL ) return NULL;
218  if ( lwgeom->type == POLYGONTYPE )
219  return (LWPOLY *)lwgeom;
220  else return NULL;
221 }
222 
223 LWTRIANGLE *
225 {
226  if ( lwgeom == NULL ) return NULL;
227  if ( lwgeom->type == TRIANGLETYPE )
228  return (LWTRIANGLE *)lwgeom;
229  else return NULL;
230 }
231 
232 LWCOLLECTION *
234 {
235  if ( lwgeom == NULL ) return NULL;
236  if ( lwgeom_is_collection(lwgeom) )
237  return (LWCOLLECTION*)lwgeom;
238  else return NULL;
239 }
240 
241 LWMPOINT *
243 {
244  if ( lwgeom == NULL ) return NULL;
245  if ( lwgeom->type == MULTIPOINTTYPE )
246  return (LWMPOINT *)lwgeom;
247  else return NULL;
248 }
249 
250 LWMLINE *
251 lwgeom_as_lwmline(const LWGEOM *lwgeom)
252 {
253  if ( lwgeom == NULL ) return NULL;
254  if ( lwgeom->type == MULTILINETYPE )
255  return (LWMLINE *)lwgeom;
256  else return NULL;
257 }
258 
259 LWMPOLY *
260 lwgeom_as_lwmpoly(const LWGEOM *lwgeom)
261 {
262  if ( lwgeom == NULL ) return NULL;
263  if ( lwgeom->type == MULTIPOLYGONTYPE )
264  return (LWMPOLY *)lwgeom;
265  else return NULL;
266 }
267 
268 LWPSURFACE *
270 {
271  if ( lwgeom->type == POLYHEDRALSURFACETYPE )
272  return (LWPSURFACE *)lwgeom;
273  else return NULL;
274 }
275 
276 LWTIN *
277 lwgeom_as_lwtin(const LWGEOM *lwgeom)
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 
354 uint8_t MULTITYPE[NUMTYPES] =
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 
370 uint8_t lwtype_multitype(uint8_t type)
371 {
372  if (type > 15) return 0;
373  return MULTITYPE[type];
374 }
375 
379 LWGEOM *
380 lwgeom_as_multi(const LWGEOM *lwgeom)
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 
419 LWGEOM *
420 lwgeom_as_curve(const LWGEOM *lwgeom)
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 */
434  ogeom = (LWGEOM*)lwcompound_construct_from_lwline((LWLINE*)lwgeom);
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 
467 void
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  */
490 LWGEOM *
491 lwgeom_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 
528 LWGEOM *
529 lwgeom_clone_deep(const LWGEOM *lwgeom)
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 
564 char*
565 lwgeom_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 
590 char
591 lwgeom_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 
661 int
662 lwpoint_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 
681 void
683 {
684  if ( lwgeom->bbox ) lwfree(lwgeom->bbox);
685  lwgeom->bbox = NULL;
686  FLAGS_SET_BBOX(lwgeom->flags, 0);
687 }
688 
694 void
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 
706 void
708 {
709  lwgeom_drop_bbox(lwgeom);
710  lwgeom_add_bbox(lwgeom);
711 }
712 
713 void
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 
742 const GBOX *
744 {
745  /* add it if not already there */
746  lwgeom_add_bbox((LWGEOM *)lwg);
747  return lwg->bbox;
748 }
749 
750 
755 int 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 
764 void
766 {
767  lwgeom->srid = SRID_UNKNOWN; /* TODO: To be changed to SRID_UNKNOWN */
768 }
769 
770 LWGEOM *
771 lwgeom_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 
792 LWGEOM*
794 {
795  return lwgeom_force_dims(geom, 0, 0, 0, 0);
796 }
797 
798 LWGEOM*
799 lwgeom_force_3dz(const LWGEOM *geom, double zval)
800 {
801  return lwgeom_force_dims(geom, 1, 0, zval, 0);
802 }
803 
804 LWGEOM*
805 lwgeom_force_3dm(const LWGEOM *geom, double mval)
806 {
807  return lwgeom_force_dims(geom, 0, 1, 0, mval);
808 }
809 
810 LWGEOM*
811 lwgeom_force_4d(const LWGEOM *geom, double zval, double mval)
812 {
813  return lwgeom_force_dims(geom, 1, 1, zval, mval);
814 }
815 
816 LWGEOM*
817 lwgeom_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 
848 LWGEOM*
849 lwgeom_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 
873  return lwcollection_as_lwgeom((LWCOLLECTION*)geom);
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 
919  return lwcollection_as_lwgeom((LWCOLLECTION*)geom);
920 
921  default:
922  return (LWGEOM *)geom;
923  }
924 }
925 
926 int32_t
928 {
929  if ( ! geom ) return SRID_UNKNOWN;
930  return geom->srid;
931 }
932 
933 int
934 lwgeom_has_z(const LWGEOM *geom)
935 {
936  if ( ! geom ) return LW_FALSE;
937  return FLAGS_GET_Z(geom->flags);
938 }
939 
940 int
941 lwgeom_has_m(const LWGEOM *geom)
942 {
943  if ( ! geom ) return LW_FALSE;
944  return FLAGS_GET_M(geom->flags);
945 }
946 
947 int
949 {
950  if ( ! geom ) return LW_FALSE;
951  return FLAGS_GET_SOLID(geom->flags);
952 }
953 
954 int
955 lwgeom_ndims(const LWGEOM *geom)
956 {
957  if ( ! geom ) return 0;
958  return FLAGS_NDIMS(geom->flags);
959 }
960 
961 
962 
963 void
965 {
966  LWPOINT *pt;
967  LWLINE *ln;
968  LWPOLY *ply;
969  LWCOLLECTION *col;
970  uint32_t i;
971 
973  if ( geom->bbox )
975 
976  switch(geom->type)
977  {
978  case POINTTYPE:
979  pt = (LWPOINT*)geom;
980  if ( pt->point )
982  break;
983  case LINETYPE:
984  ln = (LWLINE*)geom;
985  if ( ln->points )
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 
1007 void
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++)
1030  ptarray_longitude_shift(poly->rings[i]);
1031  return;
1032  case TRIANGLETYPE:
1033  triangle = (LWTRIANGLE *)lwgeom;
1034  ptarray_longitude_shift(triangle->points);
1035  return;
1036  case MULTIPOINTTYPE:
1037  case MULTILINETYPE:
1038  case MULTIPOLYGONTYPE:
1039  case POLYHEDRALSURFACETYPE:
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 
1052 int
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);
1073  case POLYHEDRALSURFACETYPE:
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  {
1080  LWCOLLECTION *col = lwgeom_as_lwcollection(geom);
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 
1096 int
1098 {
1099  if( ! geom ) return LW_FALSE;
1100  return lwtype_is_collection(geom->type);
1101 }
1102 
1103 int
1104 lwtype_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:
1115  case POLYHEDRALSURFACETYPE:
1116  case TINTYPE:
1117  return LW_TRUE;
1118  break;
1119 
1120  default:
1121  return LW_FALSE;
1122  }
1123 }
1124 
1125 int
1127 {
1128  switch (geom->type)
1129  {
1130  case TINTYPE:
1131  case POLYHEDRALSURFACETYPE:
1132  return LW_TRUE;
1133  break;
1134  default:
1135  return LW_FALSE;
1136  }
1137 }
1138 
1139 int
1141 {
1142  return lwtype_is_unitary(geom->type);
1143 }
1144 
1145 int
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 
1167 int
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:
1180  case POLYHEDRALSURFACETYPE:
1181  case TINTYPE:
1182  return LW_TRUE;
1183  break;
1184 
1185  default:
1186  return LW_FALSE;
1187  }
1188 }
1189 
1193 uint32_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 
1218 void 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:
1238  lwcircstring_free((LWCIRCSTRING *)lwgeom);
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;
1252  case POLYHEDRALSURFACETYPE:
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:
1263  lwcollection_free((LWCOLLECTION *)lwgeom);
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 
1271 int lwgeom_needs_bbox(const LWGEOM *geom)
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 
1309 uint32_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:
1342  case POLYHEDRALSURFACETYPE:
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 
1361 int 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;
1391  case POLYHEDRALSURFACETYPE:
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 
1419 uint32_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:
1449  case POLYHEDRALSURFACETYPE:
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 
1467 int 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 
1489 extern 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 
1517  case POLYHEDRALSURFACETYPE:
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 
1534 extern 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:
1565  ptarray_swap_ordinates(lwgeom_as_lwcircstring(in)->points, o1, o2);
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:
1588  case POLYHEDRALSURFACETYPE:
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  {
1606  lwgeom_refresh_bbox(in);
1607  }
1608 }
1609 
1610 void 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 */
1621  LWCOLLECTION *col = lwgeom_as_lwcollection(geom);
1622  for ( i = 0; i < col->ngeoms; i++ )
1623  {
1624  lwgeom_set_srid(col->geoms[i], srid);
1625  }
1626  }
1627 }
1628 
1629 
1630 /**************************************************************/
1631 
1632 static int
1633 cmp_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 
1649 static int
1650 cmp_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 
1666 int
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;
1680  ptarray_remove_repeated_points_in_place(pa, tolerance, 2);
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;
1697  ptarray_remove_repeated_points_in_place(pa, tolerance, 4);
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 
1822 int
1823 lwgeom_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;
1835  LWTRIANGLE *t = lwgeom_as_lwtriangle(geom);
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 
1956 LWGEOM* 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 
1971 double 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 
1994 double 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 
2016 double 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 )
2022  return lwcurvepoly_perimeter_2d((LWCURVEPOLY*)geom);
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 
2038 double 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 
2060 double 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 
2082 void
2083 lwgeom_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 
2136 void
2137 lwgeom_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 
2190 LWGEOM *
2191 lwgeom_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 
2220 int
2221 lwgeom_startpoint(const LWGEOM *lwgeom, POINT4D *pt)
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:
2243  case POLYHEDRALSURFACETYPE:
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 
2251 static inline double
2252 snap_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  */
2268 static 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 
2288 void
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 
2392 LWGEOM *
2393 lwgeom_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 */
2402 static 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 
2409 static 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 
2590 LWCOLLECTION *
2591 lwgeom_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 
2613 LWCOLLECTION *
2614 lwgeom_subdivide(const LWGEOM *geom, uint32_t maxvertices)
2615 {
2616  return lwgeom_subdivide_prec(geom, maxvertices, -1);
2617 }
2618 
2619 
2620 
2621 int
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]
2635 STATIC_ASSERT(sizeof(double) == sizeof(uint64_t),this_should_be_true);
2636 
2637 static 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 
2665 void 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 
2685 LWGEOM *
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 
2806 int
2807 lwgeom_isfinite(const LWGEOM *lwgeom)
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
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_new(lwflags_t flags)
Create a new gbox with the dimensionality indicated by the flags.
Definition: gbox.c:32
GBOX * gbox_clone(const GBOX *gbox)
Definition: gbox.c:45
LWPOINT * lwpoint_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwpoint.c:151
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:2445
void lwmpoint_free(LWMPOINT *mpt)
Definition: lwmpoint.c:72
LWPOINTITERATOR * lwpointiterator_create(const LWGEOM *g)
Create a new LWPOINTITERATOR over supplied LWGEOM*.
Definition: lwiterator.c:243
LWLINE * lwline_segmentize2d(const LWLINE *line, double dist)
Definition: lwline.c:132
void lwpoint_free(LWPOINT *pt)
Definition: lwpoint.c:213
#define LW_FAILURE
Definition: liblwgeom.h:96
LWCOLLECTION * lwcollection_segmentize2d(const LWCOLLECTION *coll, double dist)
Definition: lwcollection.c:251
#define CURVEPOLYTYPE
Definition: liblwgeom.h:111
void lwmpoly_free(LWMPOLY *mpoly)
Definition: lwmpoly.c:53
#define MULTILINETYPE
Definition: liblwgeom.h:106
LWCURVEPOLY * lwcurvepoly_construct_from_lwpoly(LWPOLY *lwpoly)
Construct an equivalent curve polygon from a polygon.
Definition: lwcurvepoly.c:52
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
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.
Definition: lwgeodetic.c:2876
#define WKT_EXTENDED
Definition: liblwgeom.h:2218
LWGEOM * lwgeom_stroke(const LWGEOM *geom, uint32_t perQuad)
Convert type with arcs into equivalent linearized type.
Definition: lwstroke.c:871
#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
POINTARRAY * ptarray_clone_deep(const POINTARRAY *ptarray)
Deep clone a pointarray (also clones serialized pointlist)
Definition: ptarray.c:643
LWMLINE * lwmline_add_lwline(LWMLINE *mobj, const LWLINE *obj)
Definition: lwmline.c:46
void lwpointiterator_destroy(LWPOINTITERATOR *s)
Free all memory associated with the iterator.
Definition: lwiterator.c:268
LWMLINE * lwmline_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwmline.c:38
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:102
#define FLAGS_GET_Z(flags)
Definition: liblwgeom.h:165
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
LWTRIANGLE * lwtriangle_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwtriangle.c:58
LWMPOINT * lwmpoint_add_lwpoint(LWMPOINT *mobj, const LWPOINT *obj)
Definition: lwmpoint.c:45
#define TINTYPE
Definition: liblwgeom.h:116
LWPOLY * lwpoly_construct_envelope(int32_t srid, double x1, double y1, double x2, double y2)
Definition: lwpoly.c:98
#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
LWGEOM * lwgeom_homogenize(const LWGEOM *geom)
Definition: lwhomogenize.c:208
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)
Definition: lwcircstring.c:97
LWMPOINT * lwmpoint_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwmpoint.c:39
void lwtriangle_free(LWTRIANGLE *triangle)
Definition: lwtriangle.c:69
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:114
#define CIRCSTRINGTYPE
Definition: liblwgeom.h:109
LWPOINTITERATOR * lwpointiterator_create_rw(LWGEOM *g)
Create a new LWPOINTITERATOR over supplied LWGEOM* Supports modification of coordinates during iterat...
Definition: lwiterator.c:252
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
Definition: lwcollection.c:92
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:216
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:166
void lwcollection_free(LWCOLLECTION *col)
Definition: lwcollection.c:357
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
Definition: lwgeom_api.c:125
LWGEOM * lwgeom_intersection_prec(const LWGEOM *geom1, const LWGEOM *geom2, double gridSize)
void ptarray_free(POINTARRAY *pa)
Definition: ptarray.c:327
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 FLAGS_GET_SOLID(flags)
Definition: liblwgeom.h:170
#define FLAGS_GET_ZM(flags)
Definition: liblwgeom.h:180
LWPOLY * lwpoly_segmentize2d(const LWPOLY *line, double dist)
Definition: lwpoly.c:312
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
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
Definition: lwcollection.c:189
#define FLAGS_SET_GEODETIC(flags, value)
Definition: liblwgeom.h:175
void * lwalloc(size_t size)
Definition: lwutil.c:227
LWCOLLECTION * lwcollection_construct(uint8_t type, int32_t srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
Definition: lwcollection.c:42
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
LWCURVEPOLY * lwcurvepoly_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwcurvepoly.c:35
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:215
LWPOLY * lwpoly_from_lwlines(const LWLINE *shell, uint32_t nholes, const LWLINE **holes)
Definition: lwpoly.c:360
#define NUMTYPES
Definition: liblwgeom.h:118
LWCOMPOUND * lwcompound_construct_from_lwline(const LWLINE *lwpoly)
Construct an equivalent compound curve from a linestring.
Definition: lwcompound.c:247
LWPOLY * lwpoly_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwpoly.c:161
LWCIRCSTRING * lwcircstring_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwcircstring.c:79
void lwline_free(LWLINE *line)
Definition: lwline.c:67
LWLINE * lwline_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwline.c:55
#define FLAGS_GET_GEODETIC(flags)
Definition: liblwgeom.h:168
LWPOINT * lwpoint_make(int32_t srid, int hasz, int hasm, const POINT4D *p)
Definition: lwpoint.c:206
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:1502
LWLINE * lwline_clone_deep(const LWLINE *lwgeom)
Definition: lwline.c:109
double lwcircstring_length_2d(const LWCIRCSTRING *circ)
Definition: lwcircstring.c:274
LWPOINT * lwpoint_clone(const LWPOINT *lwgeom)
Definition: lwpoint.c:239
int lwcircstring_is_closed(const LWCIRCSTRING *curve)
Definition: lwcircstring.c:261
void ptarray_reverse_in_place(POINTARRAY *pa)
Definition: ptarray.c:339
LWLINE * lwline_clone(const LWLINE *lwgeom)
Definition: lwline.c:93
char lwcollection_same(const LWCOLLECTION *p1, const LWCOLLECTION *p2)
check for same geometry composition
Definition: lwcollection.c:279
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:1020
#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
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
LWPOINT * lwpoint_force_dims(const LWPOINT *lwpoint, int hasz, int hasm, double zval, double mval)
Definition: lwpoint.c:304
int lwcollection_startpoint(const LWCOLLECTION *col, POINT4D *pt)
Definition: lwcollection.c:550
int ptarray_startpoint(const POINTARRAY *pa, POINT4D *pt)
Definition: ptarray.c:2084
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
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:1539
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:1721
LWLINE * lwline_force_dims(const LWLINE *lwline, int hasz, int hasm, double zval, double mval)
Definition: lwline.c:486
double lwcompound_length(const LWCOMPOUND *comp)
Definition: lwcompound.c:112
LWCOLLECTION * lwcollection_clone_deep(const LWCOLLECTION *lwgeom)
Deep clone LWCOLLECTION object.
Definition: lwcollection.c:151
LWCOLLECTION * lwcollection_force_dims(const LWCOLLECTION *lwcol, int hasz, int hasm, double zval, double mval)
Definition: lwcollection.c:476
void ptarray_grid_in_place(POINTARRAY *pa, gridspec *grid)
Snap to grid.
Definition: ptarray.c:2099
void lwtriangle_force_clockwise(LWTRIANGLE *triangle)
Definition: lwtriangle.c:106
#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:2066
void ptarray_affine(POINTARRAY *pa, const AFFINE *affine)
Affine transform a pointarray.
Definition: ptarray.c:1898
int lwpsurface_is_closed(const LWPSURFACE *psurface)
Definition: lwpsurface.c:99
double lwcurvepoly_perimeter(const LWCURVEPOLY *poly)
Definition: lwcurvepoly.c:147
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
void lwpoly_force_clockwise(LWPOLY *poly)
Definition: lwpoly.c:268
uint32_t lwcollection_count_vertices(const LWCOLLECTION *col)
Definition: lwcollection.c:500
void ptarray_swap_ordinates(POINTARRAY *pa, LWORD o1, LWORD o2)
Swap ordinate values o1 and o2 on a given POINTARRAY.
Definition: ptarray.c:387
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)
Definition: lwcircstring.c:131
LWPOLY * lwpoly_clone_deep(const LWPOLY *lwgeom)
Definition: lwpoly.c:228
double lwcircstring_length(const LWCIRCSTRING *circ)
Definition: lwcircstring.c:269
double lwcurvepoly_area(const LWCURVEPOLY *curvepoly)
This should be rewritten to make use of the curve itself.
Definition: lwcurvepoly.c:133
LWCOLLECTION * lwcollection_clone(const LWCOLLECTION *lwgeom)
Clone LWCOLLECTION object.
Definition: lwcollection.c:125
int lwpoly_is_closed(const LWPOLY *poly)
Definition: lwpoly.c:499
LWPOLY * lwpoly_clone(const LWPOLY *lwgeom)
Definition: lwpoly.c:213
void ptarray_copy_point(POINTARRAY *pa, uint32_t from, uint32_t to)
Definition: lwgeom_api.c:394
double lwcurvepoly_perimeter_2d(const LWCURVEPOLY *poly)
Definition: lwcurvepoly.c:159
double lwpoly_perimeter(const LWPOLY *poly)
Compute the sum of polygon rings length.
Definition: lwpoly.c:467
LWTRIANGLE * lwtriangle_clone(const LWTRIANGLE *lwgeom)
Definition: lwtriangle.c:99
#define FP_NEQUALS(A, B)
char lwpoint_same(const LWPOINT *p1, const LWPOINT *p2)
Definition: lwpoint.c:264
LWCIRCSTRING * lwcircstring_clone(const LWCIRCSTRING *curve)
Definition: lwcircstring.c:124
LWPOLY * lwpoly_force_dims(const LWPOLY *lwpoly, int hasz, int hasm, double zval, double mval)
Definition: lwpoly.c:394
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
void lwgeom_refresh_bbox(LWGEOM *lwgeom)
Drop current bbox and calculate a fresh one.
Definition: lwgeom.c:707
LWGEOM * lwgeom_force_dims(const LWGEOM *geom, int hasz, int hasm, double zval, double mval)
Definition: lwgeom.c:817
static double trim_preserve_decimal_digits(double d, int32_t decimal_digits)
Definition: lwgeom.c:2637
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition: lwgeom.c:179
LWGEOM * lwcompound_as_lwgeom(const LWCOMPOUND *obj)
Definition: lwgeom.c:324
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 * lwgeom_grid(const LWGEOM *lwgeom, gridspec *grid)
Definition: lwgeom.c:2393
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:339
LWGEOM * lwgeom_simplify(const LWGEOM *igeom, double dist, int preserve_collapsed)
Simplification.
Definition: lwgeom.c:1956
char lwgeom_same(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)
geom1 same as geom2 iff
Definition: lwgeom.c:591
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition: lwgeom.c:309
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
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
LWMPOINT * lwgeom_as_lwmpoint(const LWGEOM *lwgeom)
Definition: lwgeom.c:242
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
void lwgeom_longitude_shift(LWGEOM *lwgeom)
Definition: lwgeom.c:1008
LWGEOM * lwgeom_segmentize2d(const LWGEOM *lwgeom, double dist)
Definition: lwgeom.c:771
LWGEOM * lwgeom_as_multi(const LWGEOM *lwgeom)
Create a new LWGEOM of the appropriate MULTI* type.
Definition: lwgeom.c:380
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
static int cmp_point_x(const void *pa, const void *pb)
Definition: lwgeom.c:1633
LWGEOM * lwmline_as_lwgeom(const LWMLINE *obj)
Definition: lwgeom.c:299
LWGEOM * lwmpoint_as_lwgeom(const LWMPOINT *obj)
Definition: lwgeom.c:304
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:329
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_force_sfs(LWGEOM *geom, int version)
Definition: lwgeom.c:849
LWGEOM * lwgeom_clone_deep(const LWGEOM *lwgeom)
Deep-clone an LWGEOM object.
Definition: lwgeom.c:529
static double snap_to_int(double val)
Definition: lwgeom.c:2252
LWMPOLY * lwgeom_as_lwmpoly(const LWGEOM *lwgeom)
Definition: lwgeom.c:260
LWGEOM * lwgeom_force_3dm(const LWGEOM *geom, double mval)
Definition: lwgeom.c:805
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_4d(const LWGEOM *geom, double zval, double mval)
Definition: lwgeom.c:811
double lwgeom_length(const LWGEOM *geom)
Definition: lwgeom.c:2038
LWGEOM * lwgeom_remove_repeated_points(const LWGEOM *in, double tolerance)
Definition: lwgeom.c:1534
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 * lwpsurface_as_lwgeom(const LWPSURFACE *obj)
Definition: lwgeom.c:289
LWGEOM * lwgeom_force_3dz(const LWGEOM *geom, double zval)
Definition: lwgeom.c:799
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition: lwgeom.c:934
LWGEOM * lwmpoly_as_lwgeom(const LWMPOLY *obj)
Definition: lwgeom.c:294
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
char * lwgeom_to_ewkt(const LWGEOM *lwgeom)
Return an allocated string.
Definition: lwgeom.c:565
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
LWTRIANGLE * lwgeom_as_lwtriangle(const LWGEOM *lwgeom)
Definition: lwgeom.c:224
double lwgeom_area(const LWGEOM *geom)
Definition: lwgeom.c:1971
LWMLINE * lwgeom_as_lwmline(const LWGEOM *lwgeom)
Definition: lwgeom.c:251
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 * lwgeom_reverse(const LWGEOM *geom)
Definition: lwgeom.c:94
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
LWCOLLECTION * lwgeom_subdivide(const LWGEOM *geom, uint32_t maxvertices)
Definition: lwgeom.c:2614
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:344
LWGEOM * lwgeom_as_curve(const LWGEOM *lwgeom)
Create a new LWGEOM of the appropriate CURVE* type.
Definition: lwgeom.c:420
void lwgeom_swap_ordinates(LWGEOM *in, LWORD o1, LWORD o2)
Swap ordinate values in every vertex of the geometry.
Definition: lwgeom.c:1541
void lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
Definition: lwgeom.c:2083
uint8_t lwtype_multitype(uint8_t type)
Definition: lwgeom.c:370
LWGEOM * lwgeom_boundary(LWGEOM *lwgeom)
Definition: lwgeom.c:2686
LWCURVEPOLY * lwgeom_as_lwcurvepoly(const LWGEOM *lwgeom)
Definition: lwgeom.c:206
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
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
#define STATIC_ASSERT(COND, MSG)
Definition: lwgeom.c:2634
LWGEOM * lwtin_as_lwgeom(const LWTIN *obj)
Definition: lwgeom.c:284
LWGEOM * lwcurvepoly_as_lwgeom(const LWCURVEPOLY *obj)
Definition: lwgeom.c:319
uint8_t MULTITYPE[NUMTYPES]
Look-up for the correct MULTI* type promotion for singleton types.
Definition: lwgeom.c:354
LWTIN * lwgeom_as_lwtin(const LWGEOM *lwgeom)
Definition: lwgeom.c:277
LWGEOM * lwgeom_clone(const LWGEOM *lwgeom)
Clone LWGEOM object.
Definition: lwgeom.c:491
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
LWGEOM * lwcircstring_as_lwgeom(const LWCIRCSTRING *obj)
Definition: lwgeom.c:314
LWPSURFACE * lwgeom_as_lwpsurface(const LWGEOM *lwgeom)
Definition: lwgeom.c:269
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
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
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
Definition: lwgeom.c:233
void lwgeom_free(LWGEOM *lwgeom)
Definition: lwgeom.c:1218
LWGEOM * lwtriangle_as_lwgeom(const LWTRIANGLE *obj)
Definition: lwgeom.c:334
LWCIRCSTRING * lwgeom_as_lwcircstring(const LWGEOM *lwgeom)
Definition: lwgeom.c:188
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
Definition: lwgeom.c:215
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
LWCOLLECTION * lwgeom_subdivide_prec(const LWGEOM *geom, uint32_t maxvertices, double gridSize)
Definition: lwgeom.c:2591
LWGEOM * lwgeom_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
Definition: lwgeom.c:2191
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
void lwgeom_add_bbox(LWGEOM *lwgeom)
Ensure there's a box in the LWGEOM.
Definition: lwgeom.c:695
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
Definition: lwgeom.c:793
void lwgeom_drop_srid(LWGEOM *lwgeom)
Definition: lwgeom.c:765
LWCOMPOUND * lwgeom_as_lwcompound(const LWGEOM *lwgeom)
Definition: lwgeom.c:197
#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 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 distance2d_sqr_pt_pt(const POINT2D *p1, const POINT2D *p2)
Definition: lwinline.h:33
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 LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Definition: lwinline.h:127
int value
Definition: genraster.py:62
type
Definition: ovdump.py:42
static double pivot(double *left, double *right)
Definition: rt_statistics.c:40
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