PostGIS  3.3.9dev-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", 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 
1104 int
1106 {
1107  switch (type)
1108  {
1109  case MULTIPOINTTYPE:
1110  case MULTILINETYPE:
1111  case MULTIPOLYGONTYPE:
1112  case COLLECTIONTYPE:
1113  case CURVEPOLYTYPE:
1114  case COMPOUNDTYPE:
1115  case MULTICURVETYPE:
1116  case MULTISURFACETYPE:
1117  case POLYHEDRALSURFACETYPE:
1118  case TINTYPE:
1119  return LW_TRUE;
1120  break;
1121 
1122  default:
1123  return LW_FALSE;
1124  }
1125 }
1126 
1130 uint32_t
1132 {
1133  switch (type)
1134  {
1135  case POINTTYPE:
1136  return MULTIPOINTTYPE;
1137  case LINETYPE:
1138  return MULTILINETYPE;
1139  case POLYGONTYPE:
1140  return MULTIPOLYGONTYPE;
1141  case CIRCSTRINGTYPE:
1142  return MULTICURVETYPE;
1143  case COMPOUNDTYPE:
1144  return MULTICURVETYPE;
1145  case CURVEPOLYTYPE:
1146  return MULTISURFACETYPE;
1147  case TRIANGLETYPE:
1148  return TINTYPE;
1149  default:
1150  return COLLECTIONTYPE;
1151  }
1152 }
1153 
1154 
1155 void lwgeom_free(LWGEOM *lwgeom)
1156 {
1157 
1158  /* There's nothing here to free... */
1159  if( ! lwgeom ) return;
1160 
1161  LWDEBUGF(5,"freeing a %s",lwtype_name(lwgeom->type));
1162 
1163  switch (lwgeom->type)
1164  {
1165  case POINTTYPE:
1166  lwpoint_free((LWPOINT *)lwgeom);
1167  break;
1168  case LINETYPE:
1169  lwline_free((LWLINE *)lwgeom);
1170  break;
1171  case POLYGONTYPE:
1172  lwpoly_free((LWPOLY *)lwgeom);
1173  break;
1174  case CIRCSTRINGTYPE:
1175  lwcircstring_free((LWCIRCSTRING *)lwgeom);
1176  break;
1177  case TRIANGLETYPE:
1178  lwtriangle_free((LWTRIANGLE *)lwgeom);
1179  break;
1180  case MULTIPOINTTYPE:
1181  lwmpoint_free((LWMPOINT *)lwgeom);
1182  break;
1183  case MULTILINETYPE:
1184  lwmline_free((LWMLINE *)lwgeom);
1185  break;
1186  case MULTIPOLYGONTYPE:
1187  lwmpoly_free((LWMPOLY *)lwgeom);
1188  break;
1189  case POLYHEDRALSURFACETYPE:
1190  lwpsurface_free((LWPSURFACE *)lwgeom);
1191  break;
1192  case TINTYPE:
1193  lwtin_free((LWTIN *)lwgeom);
1194  break;
1195  case CURVEPOLYTYPE:
1196  case COMPOUNDTYPE:
1197  case MULTICURVETYPE:
1198  case MULTISURFACETYPE:
1199  case COLLECTIONTYPE:
1200  lwcollection_free((LWCOLLECTION *)lwgeom);
1201  break;
1202  default:
1203  lwerror("lwgeom_free called with unknown type (%d) %s", lwgeom->type, lwtype_name(lwgeom->type));
1204  }
1205  return;
1206 }
1207 
1208 int lwgeom_needs_bbox(const LWGEOM *geom)
1209 {
1210  assert(geom);
1211  if ( geom->type == POINTTYPE )
1212  {
1213  return LW_FALSE;
1214  }
1215  else if ( geom->type == LINETYPE )
1216  {
1217  if ( lwgeom_count_vertices(geom) <= 2 )
1218  return LW_FALSE;
1219  else
1220  return LW_TRUE;
1221  }
1222  else if ( geom->type == MULTIPOINTTYPE )
1223  {
1224  if ( ((LWCOLLECTION*)geom)->ngeoms == 1 )
1225  return LW_FALSE;
1226  else
1227  return LW_TRUE;
1228  }
1229  else if ( geom->type == MULTILINETYPE )
1230  {
1231  if ( ((LWCOLLECTION*)geom)->ngeoms == 1 && lwgeom_count_vertices(geom) <= 2 )
1232  return LW_FALSE;
1233  else
1234  return LW_TRUE;
1235  }
1236  else
1237  {
1238  return LW_TRUE;
1239  }
1240 }
1241 
1246 uint32_t lwgeom_count_vertices(const LWGEOM *geom)
1247 {
1248  int result = 0;
1249 
1250  /* Null? Zero. */
1251  if( ! geom ) return 0;
1252 
1253  LWDEBUGF(4, "lwgeom_count_vertices got type %s",
1254  lwtype_name(geom->type));
1255 
1256  /* Empty? Zero. */
1257  if( lwgeom_is_empty(geom) ) return 0;
1258 
1259  switch (geom->type)
1260  {
1261  case POINTTYPE:
1262  result = 1;
1263  break;
1264  case TRIANGLETYPE:
1265  case CIRCSTRINGTYPE:
1266  case LINETYPE:
1267  result = lwline_count_vertices((LWLINE *)geom);
1268  break;
1269  case POLYGONTYPE:
1270  result = lwpoly_count_vertices((LWPOLY *)geom);
1271  break;
1272  case COMPOUNDTYPE:
1273  case CURVEPOLYTYPE:
1274  case MULTICURVETYPE:
1275  case MULTISURFACETYPE:
1276  case MULTIPOINTTYPE:
1277  case MULTILINETYPE:
1278  case MULTIPOLYGONTYPE:
1279  case POLYHEDRALSURFACETYPE:
1280  case TINTYPE:
1281  case COLLECTIONTYPE:
1283  break;
1284  default:
1285  lwerror("%s: unsupported input geometry type: %s",
1286  __func__, lwtype_name(geom->type));
1287  break;
1288  }
1289  LWDEBUGF(3, "counted %d vertices", result);
1290  return result;
1291 }
1292 
1298 int lwgeom_dimension(const LWGEOM *geom)
1299 {
1300 
1301  /* Null? Zero. */
1302  if( ! geom ) return -1;
1303 
1304  LWDEBUGF(4, "lwgeom_dimension got type %s",
1305  lwtype_name(geom->type));
1306 
1307  /* Empty? Zero. */
1308  /* if( lwgeom_is_empty(geom) ) return 0; */
1309 
1310  switch (geom->type)
1311  {
1312  case POINTTYPE:
1313  case MULTIPOINTTYPE:
1314  return 0;
1315  case CIRCSTRINGTYPE:
1316  case LINETYPE:
1317  case COMPOUNDTYPE:
1318  case MULTICURVETYPE:
1319  case MULTILINETYPE:
1320  return 1;
1321  case TRIANGLETYPE:
1322  case POLYGONTYPE:
1323  case CURVEPOLYTYPE:
1324  case MULTISURFACETYPE:
1325  case MULTIPOLYGONTYPE:
1326  case TINTYPE:
1327  return 2;
1328  case POLYHEDRALSURFACETYPE:
1329  {
1330  /* A closed polyhedral surface contains a volume. */
1331  int closed = lwpsurface_is_closed((LWPSURFACE*)geom);
1332  return ( closed ? 3 : 2 );
1333  }
1334  case COLLECTIONTYPE:
1335  {
1336  int maxdim = 0;
1337  uint32_t i;
1338  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1339  for( i = 0; i < col->ngeoms; i++ )
1340  {
1341  int dim = lwgeom_dimension(col->geoms[i]);
1342  maxdim = ( dim > maxdim ? dim : maxdim );
1343  }
1344  return maxdim;
1345  }
1346  default:
1347  lwerror("%s: unsupported input geometry type: %s",
1348  __func__, lwtype_name(geom->type));
1349  }
1350  return -1;
1351 }
1352 
1356 uint32_t lwgeom_count_rings(const LWGEOM *geom)
1357 {
1358  int result = 0;
1359 
1360  /* Null? Empty? Zero. */
1361  if( ! geom || lwgeom_is_empty(geom) )
1362  return 0;
1363 
1364  switch (geom->type)
1365  {
1366  case POINTTYPE:
1367  case CIRCSTRINGTYPE:
1368  case COMPOUNDTYPE:
1369  case MULTICURVETYPE:
1370  case MULTIPOINTTYPE:
1371  case MULTILINETYPE:
1372  case LINETYPE:
1373  result = 0;
1374  break;
1375  case TRIANGLETYPE:
1376  result = 1;
1377  break;
1378  case POLYGONTYPE:
1379  result = ((LWPOLY *)geom)->nrings;
1380  break;
1381  case CURVEPOLYTYPE:
1382  result = ((LWCURVEPOLY *)geom)->nrings;
1383  break;
1384  case MULTISURFACETYPE:
1385  case MULTIPOLYGONTYPE:
1386  case POLYHEDRALSURFACETYPE:
1387  case TINTYPE:
1388  case COLLECTIONTYPE:
1389  {
1390  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1391  uint32_t i = 0;
1392  for( i = 0; i < col->ngeoms; i++ )
1393  result += lwgeom_count_rings(col->geoms[i]);
1394  break;
1395  }
1396  default:
1397  lwerror("lwgeom_count_rings: unsupported input geometry type: %s", lwtype_name(geom->type));
1398  break;
1399  }
1400  LWDEBUGF(3, "counted %d rings", result);
1401  return result;
1402 }
1403 
1404 int lwgeom_has_srid(const LWGEOM *geom)
1405 {
1406  if ( geom->srid != SRID_UNKNOWN )
1407  return LW_TRUE;
1408 
1409  return LW_FALSE;
1410 }
1411 
1412 
1414 {
1415  uint32_t i;
1416  int dimensionality = 0;
1417  for ( i = 0; i < col->ngeoms; i++ )
1418  {
1419  int d = lwgeom_dimensionality(col->geoms[i]);
1420  if ( d > dimensionality )
1421  dimensionality = d;
1422  }
1423  return dimensionality;
1424 }
1425 
1426 extern int lwgeom_dimensionality(const LWGEOM *geom)
1427 {
1428  int dim;
1429 
1430  LWDEBUGF(3, "lwgeom_dimensionality got type %s",
1431  lwtype_name(geom->type));
1432 
1433  switch (geom->type)
1434  {
1435  case POINTTYPE:
1436  case MULTIPOINTTYPE:
1437  return 0;
1438  break;
1439  case LINETYPE:
1440  case CIRCSTRINGTYPE:
1441  case MULTILINETYPE:
1442  case COMPOUNDTYPE:
1443  case MULTICURVETYPE:
1444  return 1;
1445  break;
1446  case POLYGONTYPE:
1447  case TRIANGLETYPE:
1448  case CURVEPOLYTYPE:
1449  case MULTIPOLYGONTYPE:
1450  case MULTISURFACETYPE:
1451  return 2;
1452  break;
1453 
1454  case POLYHEDRALSURFACETYPE:
1455  case TINTYPE:
1456  dim = lwgeom_is_closed(geom)?3:2;
1457  return dim;
1458  break;
1459 
1460  case COLLECTIONTYPE:
1461  return lwcollection_dimensionality((const LWCOLLECTION *)geom);
1462  break;
1463  default:
1464  lwerror("lwgeom_dimensionality: unsupported input geometry type: %s",
1465  lwtype_name(geom->type));
1466  break;
1467  }
1468  return 0;
1469 }
1470 
1471 extern LWGEOM* lwgeom_remove_repeated_points(const LWGEOM *in, double tolerance)
1472 {
1473  LWGEOM *out = lwgeom_clone_deep(in);
1475  return out;
1476 }
1477 
1479 {
1480  LWCOLLECTION *col;
1481  LWPOLY *poly;
1482  uint32_t i;
1483 
1484  if ( (!in) || lwgeom_is_empty(in) ) return;
1485 
1486  /* TODO: check for lwgeom NOT having the specified dimension ? */
1487 
1488  LWDEBUGF(4, "lwgeom_flip_coordinates, got type: %s",
1489  lwtype_name(in->type));
1490 
1491  switch (in->type)
1492  {
1493  case POINTTYPE:
1494  ptarray_swap_ordinates(lwgeom_as_lwpoint(in)->point, o1, o2);
1495  break;
1496 
1497  case LINETYPE:
1498  ptarray_swap_ordinates(lwgeom_as_lwline(in)->points, o1, o2);
1499  break;
1500 
1501  case CIRCSTRINGTYPE:
1502  ptarray_swap_ordinates(lwgeom_as_lwcircstring(in)->points, o1, o2);
1503  break;
1504 
1505  case POLYGONTYPE:
1506  poly = (LWPOLY *) in;
1507  for (i=0; i<poly->nrings; i++)
1508  {
1509  ptarray_swap_ordinates(poly->rings[i], o1, o2);
1510  }
1511  break;
1512 
1513  case TRIANGLETYPE:
1514  ptarray_swap_ordinates(lwgeom_as_lwtriangle(in)->points, o1, o2);
1515  break;
1516 
1517  case MULTIPOINTTYPE:
1518  case MULTILINETYPE:
1519  case MULTIPOLYGONTYPE:
1520  case COLLECTIONTYPE:
1521  case COMPOUNDTYPE:
1522  case CURVEPOLYTYPE:
1523  case MULTISURFACETYPE:
1524  case MULTICURVETYPE:
1525  case POLYHEDRALSURFACETYPE:
1526  case TINTYPE:
1527  col = (LWCOLLECTION *) in;
1528  for (i=0; i<col->ngeoms; i++)
1529  {
1530  lwgeom_swap_ordinates(col->geoms[i], o1, o2);
1531  }
1532  break;
1533 
1534  default:
1535  lwerror("lwgeom_swap_ordinates: unsupported geometry type: %s",
1536  lwtype_name(in->type));
1537  return;
1538  }
1539 
1540  /* only refresh bbox if X or Y changed */
1541  if ( in->bbox && (o1 < 2 || o2 < 2) )
1542  {
1543  lwgeom_refresh_bbox(in);
1544  }
1545 }
1546 
1547 void lwgeom_set_srid(LWGEOM *geom, int32_t srid)
1548 {
1549  uint32_t i;
1550 
1551  LWDEBUGF(4,"entered with srid=%d",srid);
1552 
1553  geom->srid = srid;
1554 
1555  if ( lwgeom_is_collection(geom) )
1556  {
1557  /* All the children are set to the same SRID value */
1558  LWCOLLECTION *col = lwgeom_as_lwcollection(geom);
1559  for ( i = 0; i < col->ngeoms; i++ )
1560  {
1561  lwgeom_set_srid(col->geoms[i], srid);
1562  }
1563  }
1564 }
1565 
1566 
1567 /**************************************************************/
1568 
1569 static int
1570 cmp_point_x(const void *pa, const void *pb)
1571 {
1572  LWPOINT *p1 = *((LWPOINT **)pa);
1573  LWPOINT *p2 = *((LWPOINT **)pb);
1574 
1575  const POINT2D *pt1 = getPoint2d_cp(p1->point, 0);
1576  const POINT2D *pt2 = getPoint2d_cp(p2->point, 0);
1577 
1578  if (pt1 && pt2)
1579  return (pt1->x > pt2->x) ? 1 : ((pt1->x < pt2->x) ? -1 : 0);
1580 
1581  if (pt1) return -1;
1582  if (pt2) return 1;
1583  return 0;
1584 }
1585 
1586 static int
1587 cmp_point_y(const void *pa, const void *pb)
1588 {
1589  LWPOINT *p1 = *((LWPOINT **)pa);
1590  LWPOINT *p2 = *((LWPOINT **)pb);
1591 
1592  const POINT2D *pt1 = getPoint2d_cp(p1->point, 0);
1593  const POINT2D *pt2 = getPoint2d_cp(p2->point, 0);
1594 
1595  if (pt1 && pt2)
1596  return (pt1->y > pt2->y) ? 1 : ((pt1->y < pt2->y) ? -1 : 0);
1597 
1598  if (pt1) return -1;
1599  if (pt2) return 1;
1600  return 0;
1601 }
1602 
1603 int
1605 {
1606  int geometry_modified = LW_FALSE;
1607  switch (geom->type)
1608  {
1609  /* No-op! Cannot remove points */
1610  case POINTTYPE:
1611  case TRIANGLETYPE:
1612  return geometry_modified;
1613  case LINETYPE: {
1614  LWLINE *g = (LWLINE *)(geom);
1615  POINTARRAY *pa = g->points;
1616  uint32_t npoints = pa->npoints;
1617  ptarray_remove_repeated_points_in_place(pa, tolerance, 2);
1618  geometry_modified = npoints != pa->npoints;
1619  /* Invalid input, discard the collapsed line */
1620  if (pa->npoints < 2)
1621  {
1622  pa->npoints = 0;
1623  geometry_modified = LW_TRUE;
1624  }
1625  break;
1626  }
1627  case POLYGONTYPE: {
1628  uint32_t j = 0;
1629  LWPOLY *g = (LWPOLY *)(geom);
1630  for (uint32_t i = 0; i < g->nrings; i++)
1631  {
1632  POINTARRAY *pa = g->rings[i];
1633  uint32_t npoints = pa->npoints;
1634  ptarray_remove_repeated_points_in_place(pa, tolerance, 4);
1635  geometry_modified |= npoints != pa->npoints;
1636  /* Drop collapsed rings */
1637  if (pa->npoints < 4)
1638  {
1639  geometry_modified = LW_TRUE;
1640  ptarray_free(pa);
1641  continue;
1642  }
1643  g->rings[j++] = pa;
1644  }
1645  /* Update ring count */
1646  g->nrings = j;
1647  break;
1648  }
1649  case MULTIPOINTTYPE: {
1650  double tolsq = tolerance * tolerance;
1651  LWMPOINT *mpt = (LWMPOINT *)geom;
1652 
1653  for (uint8_t dim = 0; dim < 2; dim++)
1654  {
1655  /* sort by y, then by x - this way the result is sorted by x */
1656  qsort(mpt->geoms, mpt->ngeoms, sizeof(LWPOINT *), dim ? cmp_point_x : cmp_point_y);
1657  for (uint32_t i = 0; i < mpt->ngeoms; i++)
1658  {
1659  if (!mpt->geoms[i])
1660  continue;
1661 
1662  const POINT2D *pti = getPoint2d_cp(mpt->geoms[i]->point, 0);
1663  if (!pti) continue;
1664 
1665  /* check upcoming points if they're within tolerance of current one */
1666  for (uint32_t j = i + 1; j < mpt->ngeoms; j++)
1667  {
1668  if (!mpt->geoms[j])
1669  continue;
1670 
1671  const POINT2D *ptj = getPoint2d_cp(mpt->geoms[j]->point, 0);
1672  if (!ptj) continue;
1673 
1674  /* check that the point is in the strip of tolerance around the point */
1675  if ((dim ? ptj->x - pti->x : ptj->y - pti->y) > tolerance)
1676  break;
1677 
1678  /* remove any upcoming point that is within tolerance circle */
1679  if (distance2d_sqr_pt_pt(pti, ptj) <= tolsq)
1680  {
1681  lwpoint_free(mpt->geoms[j]);
1682  mpt->geoms[j] = NULL;
1683  geometry_modified = LW_TRUE;
1684  }
1685  }
1686  }
1687 
1688  /* null out empties */
1689  for (uint32_t j = 0; j < mpt->ngeoms; j++)
1690  {
1691  if (mpt->geoms[j] && lwpoint_is_empty(mpt->geoms[j]))
1692  {
1693  lwpoint_free(mpt->geoms[j]);
1694  mpt->geoms[j] = NULL;
1695  geometry_modified = LW_TRUE;
1696  }
1697  }
1698 
1699  /* compactify array of points */
1700  uint32_t i = 0;
1701  for (uint32_t j = 0; j < mpt->ngeoms; j++)
1702  if (mpt->geoms[j])
1703  mpt->geoms[i++] = mpt->geoms[j];
1704  mpt->ngeoms = i;
1705  }
1706 
1707  break;
1708  }
1709 
1710  case CIRCSTRINGTYPE:
1711  /* Dunno how to handle these, will return untouched */
1712  return geometry_modified;
1713 
1714  /* Can process most multi* types as generic collection */
1715  case MULTILINETYPE:
1716  case MULTIPOLYGONTYPE:
1717  case TINTYPE:
1718  case COLLECTIONTYPE:
1719  /* Curve types we mostly ignore, but allow the linear */
1720  /* portions to be processed by recursing into them */
1721  case MULTICURVETYPE:
1722  case CURVEPOLYTYPE:
1723  case MULTISURFACETYPE:
1724  case COMPOUNDTYPE: {
1725  uint32_t i, j = 0;
1726  LWCOLLECTION *col = (LWCOLLECTION *)(geom);
1727  for (i = 0; i < col->ngeoms; i++)
1728  {
1729  LWGEOM *g = col->geoms[i];
1730  if (!g)
1731  continue;
1732  geometry_modified |= lwgeom_remove_repeated_points_in_place(g, tolerance);
1733  /* Drop zero'ed out geometries */
1734  if (lwgeom_is_empty(g))
1735  {
1736  lwgeom_free(g);
1737  continue;
1738  }
1739  col->geoms[j++] = g;
1740  }
1741  /* Update geometry count */
1742  col->ngeoms = j;
1743  break;
1744  }
1745  default: {
1746  lwerror("%s: unsupported geometry type: %s", __func__, lwtype_name(geom->type));
1747  break;
1748  }
1749  }
1750 
1751  if (geometry_modified)
1752  lwgeom_drop_bbox(geom);
1753  return geometry_modified;
1754 }
1755 
1756 
1757 /**************************************************************/
1758 
1759 int
1760 lwgeom_simplify_in_place(LWGEOM *geom, double epsilon, int preserve_collapsed)
1761 {
1762  int modified = LW_FALSE;
1763  switch (geom->type)
1764  {
1765  /* No-op! Cannot simplify points or triangles */
1766  case POINTTYPE:
1767  return modified;
1768  case TRIANGLETYPE:
1769  {
1770  if (preserve_collapsed)
1771  return modified;
1772  LWTRIANGLE *t = lwgeom_as_lwtriangle(geom);
1773  POINTARRAY *pa = t->points;
1774  ptarray_simplify_in_place(pa, epsilon, 0);
1775  if (pa->npoints < 3)
1776  {
1777  pa->npoints = 0;
1778  modified = LW_TRUE;
1779  }
1780  break;
1781  }
1782  case LINETYPE:
1783  {
1784  LWLINE *g = (LWLINE*)(geom);
1785  POINTARRAY *pa = g->points;
1786  uint32_t in_npoints = pa->npoints;
1787  ptarray_simplify_in_place(pa, epsilon, 2);
1788  modified = in_npoints != pa->npoints;
1789  /* Invalid output */
1790  if (pa->npoints == 1 && pa->maxpoints > 1)
1791  {
1792  /* Use first point as last point */
1793  if (preserve_collapsed)
1794  {
1795  pa->npoints = 2;
1796  ptarray_copy_point(pa, 0, 1);
1797  }
1798  /* Finish the collapse process */
1799  else
1800  {
1801  pa->npoints = 0;
1802  }
1803  }
1804  /* Duped output, force collapse */
1805  if (pa->npoints == 2 && !preserve_collapsed)
1806  {
1807  if (p2d_same(getPoint2d_cp(pa, 0), getPoint2d_cp(pa, 1)))
1808  pa->npoints = 0;
1809  }
1810  break;
1811  }
1812  case POLYGONTYPE:
1813  {
1814  uint32_t i, j = 0;
1815  LWPOLY *g = (LWPOLY*)(geom);
1816  for (i = 0; i < g->nrings; i++)
1817  {
1818  POINTARRAY *pa = g->rings[i];
1819  /* Only stop collapse on first ring */
1820  int minpoints = (preserve_collapsed && i == 0) ? 4 : 0;
1821  /* Skip zero'ed out rings */
1822  if(!pa)
1823  continue;
1824  uint32_t in_npoints = pa->npoints;
1825  ptarray_simplify_in_place(pa, epsilon, minpoints);
1826  modified |= in_npoints != pa->npoints;
1827  /* Drop collapsed rings */
1828  if(pa->npoints < 4)
1829  {
1830  if (i == 0)
1831  {
1832  /* If the outter ring is dropped, all can be dropped */
1833  for (i = 0; i < g->nrings; i++)
1834  {
1835  pa = g->rings[i];
1836  ptarray_free(pa);
1837  }
1838  break;
1839  }
1840  else
1841  {
1842  /* Drop this inner ring only */
1843  ptarray_free(pa);
1844  continue;
1845  }
1846  }
1847  g->rings[j++] = pa;
1848  }
1849  /* Update ring count */
1850  g->nrings = j;
1851  break;
1852  }
1853  /* Can process all multi* types as generic collection */
1854  case MULTIPOINTTYPE:
1855  case MULTILINETYPE:
1856  case MULTIPOLYGONTYPE:
1857  case TINTYPE:
1858  case COLLECTIONTYPE:
1859  {
1860  uint32_t i, j = 0;
1861  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1862  for (i = 0; i < col->ngeoms; i++)
1863  {
1864  LWGEOM *g = col->geoms[i];
1865  if (!g) continue;
1866  modified |= lwgeom_simplify_in_place(g, epsilon, preserve_collapsed);
1867  /* Drop zero'ed out geometries */
1868  if(lwgeom_is_empty(g))
1869  {
1870  lwgeom_free(g);
1871  continue;
1872  }
1873  col->geoms[j++] = g;
1874  }
1875  /* Update geometry count */
1876  col->ngeoms = j;
1877  break;
1878  }
1879  default:
1880  {
1881  lwerror("%s: unsupported geometry type: %s", __func__, lwtype_name(geom->type));
1882  break;
1883  }
1884  }
1885 
1886  if (modified)
1887  {
1888  lwgeom_drop_bbox(geom);
1889  }
1890  return modified;
1891 }
1892 
1893 LWGEOM* lwgeom_simplify(const LWGEOM *igeom, double dist, int preserve_collapsed)
1894 {
1895  LWGEOM *lwgeom_out = lwgeom_clone_deep(igeom);
1896  lwgeom_simplify_in_place(lwgeom_out, dist, preserve_collapsed);
1897  if (lwgeom_is_empty(lwgeom_out))
1898  {
1899  lwgeom_free(lwgeom_out);
1900  return NULL;
1901  }
1902  return lwgeom_out;
1903 }
1904 
1905 /**************************************************************/
1906 
1907 
1908 double lwgeom_area(const LWGEOM *geom)
1909 {
1910  int type = geom->type;
1911 
1912  if ( type == POLYGONTYPE )
1913  return lwpoly_area((LWPOLY*)geom);
1914  else if ( type == CURVEPOLYTYPE )
1915  return lwcurvepoly_area((LWCURVEPOLY*)geom);
1916  else if (type == TRIANGLETYPE )
1917  return lwtriangle_area((LWTRIANGLE*)geom);
1918  else if ( lwgeom_is_collection(geom) )
1919  {
1920  double area = 0.0;
1921  uint32_t i;
1922  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1923  for ( i = 0; i < col->ngeoms; i++ )
1924  area += lwgeom_area(col->geoms[i]);
1925  return area;
1926  }
1927  else
1928  return 0.0;
1929 }
1930 
1931 double lwgeom_perimeter(const LWGEOM *geom)
1932 {
1933  int type = geom->type;
1934  if ( type == POLYGONTYPE )
1935  return lwpoly_perimeter((LWPOLY*)geom);
1936  else if ( type == CURVEPOLYTYPE )
1937  return lwcurvepoly_perimeter((LWCURVEPOLY*)geom);
1938  else if ( type == TRIANGLETYPE )
1939  return lwtriangle_perimeter((LWTRIANGLE*)geom);
1940  else if ( lwgeom_is_collection(geom) )
1941  {
1942  double perimeter = 0.0;
1943  uint32_t i;
1944  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1945  for ( i = 0; i < col->ngeoms; i++ )
1946  perimeter += lwgeom_perimeter(col->geoms[i]);
1947  return perimeter;
1948  }
1949  else
1950  return 0.0;
1951 }
1952 
1953 double lwgeom_perimeter_2d(const LWGEOM *geom)
1954 {
1955  int type = geom->type;
1956  if ( type == POLYGONTYPE )
1957  return lwpoly_perimeter_2d((LWPOLY*)geom);
1958  else if ( type == CURVEPOLYTYPE )
1959  return lwcurvepoly_perimeter_2d((LWCURVEPOLY*)geom);
1960  else if ( type == TRIANGLETYPE )
1961  return lwtriangle_perimeter_2d((LWTRIANGLE*)geom);
1962  else if ( lwgeom_is_collection(geom) )
1963  {
1964  double perimeter = 0.0;
1965  uint32_t i;
1966  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1967  for ( i = 0; i < col->ngeoms; i++ )
1968  perimeter += lwgeom_perimeter_2d(col->geoms[i]);
1969  return perimeter;
1970  }
1971  else
1972  return 0.0;
1973 }
1974 
1975 double lwgeom_length(const LWGEOM *geom)
1976 {
1977  int type = geom->type;
1978  if ( type == LINETYPE )
1979  return lwline_length((LWLINE*)geom);
1980  else if ( type == CIRCSTRINGTYPE )
1981  return lwcircstring_length((LWCIRCSTRING*)geom);
1982  else if ( type == COMPOUNDTYPE )
1983  return lwcompound_length((LWCOMPOUND*)geom);
1984  else if ( lwgeom_is_collection(geom) )
1985  {
1986  double length = 0.0;
1987  uint32_t i;
1988  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1989  for ( i = 0; i < col->ngeoms; i++ )
1990  length += lwgeom_length(col->geoms[i]);
1991  return length;
1992  }
1993  else
1994  return 0.0;
1995 }
1996 
1997 double lwgeom_length_2d(const LWGEOM *geom)
1998 {
1999  int type = geom->type;
2000  if ( type == LINETYPE )
2001  return lwline_length_2d((LWLINE*)geom);
2002  else if ( type == CIRCSTRINGTYPE )
2003  return lwcircstring_length_2d((LWCIRCSTRING*)geom);
2004  else if ( type == COMPOUNDTYPE )
2005  return lwcompound_length_2d((LWCOMPOUND*)geom);
2006  else if ( lwgeom_is_collection(geom) )
2007  {
2008  double length = 0.0;
2009  uint32_t i;
2010  LWCOLLECTION *col = (LWCOLLECTION*)geom;
2011  for ( i = 0; i < col->ngeoms; i++ )
2012  length += lwgeom_length_2d(col->geoms[i]);
2013  return length;
2014  }
2015  else
2016  return 0.0;
2017 }
2018 
2019 void
2020 lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
2021 {
2022  int type = geom->type;
2023  uint32_t i;
2024 
2025  switch(type)
2026  {
2027  /* Take advantage of fact tht pt/ln/circ/tri have same memory structure */
2028  case POINTTYPE:
2029  case LINETYPE:
2030  case CIRCSTRINGTYPE:
2031  case TRIANGLETYPE:
2032  {
2033  LWLINE *l = (LWLINE*)geom;
2034  ptarray_affine(l->points, affine);
2035  break;
2036  }
2037  case POLYGONTYPE:
2038  {
2039  LWPOLY *p = (LWPOLY*)geom;
2040  for( i = 0; i < p->nrings; i++ )
2041  ptarray_affine(p->rings[i], affine);
2042  break;
2043  }
2044  case CURVEPOLYTYPE:
2045  {
2046  LWCURVEPOLY *c = (LWCURVEPOLY*)geom;
2047  for( i = 0; i < c->nrings; i++ )
2048  lwgeom_affine(c->rings[i], affine);
2049  break;
2050  }
2051  default:
2052  {
2053  if( lwgeom_is_collection(geom) )
2054  {
2055  LWCOLLECTION *c = (LWCOLLECTION*)geom;
2056  for( i = 0; i < c->ngeoms; i++ )
2057  {
2058  lwgeom_affine(c->geoms[i], affine);
2059  }
2060  }
2061  else
2062  {
2063  lwerror("lwgeom_affine: unable to handle type '%s'", lwtype_name(type));
2064  }
2065  }
2066  }
2067 
2068  /* Recompute bbox if needed */
2069  if (geom->bbox)
2070  lwgeom_refresh_bbox(geom);
2071 }
2072 
2073 void
2074 lwgeom_scale(LWGEOM *geom, const POINT4D *factor)
2075 {
2076  int type = geom->type;
2077  uint32_t i;
2078 
2079  switch(type)
2080  {
2081  /* Take advantage of fact tht pt/ln/circ/tri have same memory structure */
2082  case POINTTYPE:
2083  case LINETYPE:
2084  case CIRCSTRINGTYPE:
2085  case TRIANGLETYPE:
2086  {
2087  LWLINE *l = (LWLINE*)geom;
2088  ptarray_scale(l->points, factor);
2089  break;
2090  }
2091  case POLYGONTYPE:
2092  {
2093  LWPOLY *p = (LWPOLY*)geom;
2094  for( i = 0; i < p->nrings; i++ )
2095  ptarray_scale(p->rings[i], factor);
2096  break;
2097  }
2098  case CURVEPOLYTYPE:
2099  {
2100  LWCURVEPOLY *c = (LWCURVEPOLY*)geom;
2101  for( i = 0; i < c->nrings; i++ )
2102  lwgeom_scale(c->rings[i], factor);
2103  break;
2104  }
2105  default:
2106  {
2107  if( lwgeom_is_collection(geom) )
2108  {
2109  LWCOLLECTION *c = (LWCOLLECTION*)geom;
2110  for( i = 0; i < c->ngeoms; i++ )
2111  {
2112  lwgeom_scale(c->geoms[i], factor);
2113  }
2114  }
2115  else
2116  {
2117  lwerror("lwgeom_scale: unable to handle type '%s'", lwtype_name(type));
2118  }
2119  }
2120  }
2121 
2122  /* Recompute bbox if needed */
2123  if (geom->bbox)
2124  lwgeom_refresh_bbox(geom);
2125 }
2126 
2127 LWGEOM *
2128 lwgeom_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
2129 {
2130  switch(type)
2131  {
2132  case POINTTYPE:
2133  return lwpoint_as_lwgeom(lwpoint_construct_empty(srid, hasz, hasm));
2134  case LINETYPE:
2135  return lwline_as_lwgeom(lwline_construct_empty(srid, hasz, hasm));
2136  case POLYGONTYPE:
2137  return lwpoly_as_lwgeom(lwpoly_construct_empty(srid, hasz, hasm));
2138  case CURVEPOLYTYPE:
2139  return lwcurvepoly_as_lwgeom(lwcurvepoly_construct_empty(srid, hasz, hasm));
2140  case CIRCSTRINGTYPE:
2141  return lwcircstring_as_lwgeom(lwcircstring_construct_empty(srid, hasz, hasm));
2142  case TRIANGLETYPE:
2143  return lwtriangle_as_lwgeom(lwtriangle_construct_empty(srid, hasz, hasm));
2144  case COMPOUNDTYPE:
2145  case MULTIPOINTTYPE:
2146  case MULTILINETYPE:
2147  case MULTIPOLYGONTYPE:
2148  case COLLECTIONTYPE:
2149  return lwcollection_as_lwgeom(lwcollection_construct_empty(type, srid, hasz, hasm));
2150  default:
2151  lwerror("lwgeom_construct_empty: unsupported geometry type: %s",
2152  lwtype_name(type));
2153  return NULL;
2154  }
2155 }
2156 
2157 int
2158 lwgeom_startpoint(const LWGEOM *lwgeom, POINT4D *pt)
2159 {
2160  if ( ! lwgeom || lwgeom_is_empty(lwgeom) )
2161  return LW_FAILURE;
2162 
2163  switch( lwgeom->type )
2164  {
2165  case POINTTYPE:
2166  return ptarray_startpoint(((LWPOINT*)lwgeom)->point, pt);
2167  case TRIANGLETYPE:
2168  case CIRCSTRINGTYPE:
2169  case LINETYPE:
2170  return ptarray_startpoint(((LWLINE*)lwgeom)->points, pt);
2171  case POLYGONTYPE:
2172  return lwpoly_startpoint((LWPOLY*)lwgeom, pt);
2173  case TINTYPE:
2174  case CURVEPOLYTYPE:
2175  case COMPOUNDTYPE:
2176  case MULTIPOINTTYPE:
2177  case MULTILINETYPE:
2178  case MULTIPOLYGONTYPE:
2179  case COLLECTIONTYPE:
2180  case POLYHEDRALSURFACETYPE:
2181  return lwcollection_startpoint((LWCOLLECTION*)lwgeom, pt);
2182  default:
2183  lwerror("lwgeom_startpoint: unsupported geometry type: %s", lwtype_name(lwgeom->type));
2184  return LW_FAILURE;
2185  }
2186 }
2187 
2188 void
2190 {
2191  if (!geom) return;
2192  if (lwgeom_is_empty(geom)) return;
2193  switch ( geom->type )
2194  {
2195  case POINTTYPE:
2196  {
2197  LWPOINT *pt = (LWPOINT*)(geom);
2198  ptarray_grid_in_place(pt->point, grid);
2199  return;
2200  }
2201  case CIRCSTRINGTYPE:
2202  case TRIANGLETYPE:
2203  case LINETYPE:
2204  {
2205  LWLINE *ln = (LWLINE*)(geom);
2206  ptarray_grid_in_place(ln->points, grid);
2207  /* For invalid line, return an EMPTY */
2208  if (ln->points->npoints < 2)
2209  ln->points->npoints = 0;
2210  return;
2211  }
2212  case POLYGONTYPE:
2213  {
2214  LWPOLY *ply = (LWPOLY*)(geom);
2215  if (!ply->rings) return;
2216 
2217  /* Check first the external ring */
2218  uint32_t i = 0;
2219  POINTARRAY *pa = ply->rings[0];
2220  ptarray_grid_in_place(pa, grid);
2221  if (pa->npoints < 4)
2222  {
2223  /* External ring collapsed: free everything */
2224  for (i = 0; i < ply->nrings; i++)
2225  {
2226  ptarray_free(ply->rings[i]);
2227  }
2228  ply->nrings = 0;
2229  return;
2230  }
2231 
2232  /* Check the other rings */
2233  uint32_t j = 1;
2234  for (i = 1; i < ply->nrings; i++)
2235  {
2236  POINTARRAY *pa = ply->rings[i];
2237  ptarray_grid_in_place(pa, grid);
2238 
2239  /* Skip bad rings */
2240  if (pa->npoints >= 4)
2241  {
2242  ply->rings[j++] = pa;
2243  }
2244  else
2245  {
2246  ptarray_free(pa);
2247  }
2248  }
2249  /* Adjust ring count appropriately */
2250  ply->nrings = j;
2251  return;
2252  }
2253  case MULTIPOINTTYPE:
2254  case MULTILINETYPE:
2255  case MULTIPOLYGONTYPE:
2256  case TINTYPE:
2257  case COLLECTIONTYPE:
2258  case COMPOUNDTYPE:
2259  {
2260  LWCOLLECTION *col = (LWCOLLECTION*)(geom);
2261  uint32_t i, j = 0;
2262  if (!col->geoms) return;
2263  for (i = 0; i < col->ngeoms; i++)
2264  {
2265  LWGEOM *g = col->geoms[i];
2266  lwgeom_grid_in_place(g, grid);
2267  /* Empty geoms need to be freed */
2268  /* before we move on */
2269  if (lwgeom_is_empty(g))
2270  {
2271  lwgeom_free(g);
2272  continue;
2273  }
2274  col->geoms[j++] = g;
2275  }
2276  col->ngeoms = j;
2277  return;
2278  }
2279  default:
2280  {
2281  lwerror("%s: Unsupported geometry type: %s", __func__,
2282  lwtype_name(geom->type));
2283  return;
2284  }
2285  }
2286 }
2287 
2288 
2289 LWGEOM *
2290 lwgeom_grid(const LWGEOM *lwgeom, const gridspec *grid)
2291 {
2292  LWGEOM *lwgeom_out = lwgeom_clone_deep(lwgeom);
2293  lwgeom_grid_in_place(lwgeom_out, grid);
2294  return lwgeom_out;
2295 }
2296 
2297 
2298 /* Prototype for recursion */
2299 static void lwgeom_subdivide_recursive(const LWGEOM *geom,
2300  uint8_t dimension,
2301  uint32_t maxvertices,
2302  uint32_t depth,
2303  LWCOLLECTION *col,
2304  double gridSize);
2305 
2306 static void
2308  uint8_t dimension,
2309  uint32_t maxvertices,
2310  uint32_t depth,
2311  LWCOLLECTION *col,
2312  double gridSize)
2313 {
2314  const uint32_t maxdepth = 50;
2315 
2316  if (!geom)
2317  return;
2318 
2319  const GBOX *box_in = lwgeom_get_bbox(geom);
2320  if (!box_in)
2321  return;
2322 
2323  LW_ON_INTERRUPT(return);
2324 
2325  GBOX clip;
2326  gbox_duplicate(box_in, &clip);
2327  double width = clip.xmax - clip.xmin;
2328  double height = clip.ymax - clip.ymin;
2329 
2330  if ( geom->type == POLYHEDRALSURFACETYPE || geom->type == TINTYPE )
2331  lwerror("%s: unsupported geometry type '%s'", __func__, lwtype_name(geom->type));
2332 
2333  if ( width == 0.0 && height == 0.0 )
2334  {
2335  if ( geom->type == POINTTYPE && dimension == 0)
2337  return;
2338  }
2339 
2340  if (width == 0.0)
2341  {
2342  clip.xmax += FP_TOLERANCE;
2343  clip.xmin -= FP_TOLERANCE;
2344  width = 2 * FP_TOLERANCE;
2345  }
2346  if (height == 0.0)
2347  {
2348  clip.ymax += FP_TOLERANCE;
2349  clip.ymin -= FP_TOLERANCE;
2350  height = 2 * FP_TOLERANCE;
2351  }
2352 
2353  /* Always just recurse into collections */
2354  if ( lwgeom_is_collection(geom) && geom->type != MULTIPOINTTYPE )
2355  {
2356  LWCOLLECTION *incol = (LWCOLLECTION*)geom;
2357  /* Don't increment depth yet, since we aren't actually
2358  * subdividing geometries yet */
2359  for (uint32_t i = 0; i < incol->ngeoms; i++ )
2360  lwgeom_subdivide_recursive(incol->geoms[i], dimension, maxvertices, depth, col, gridSize);
2361  return;
2362  }
2363 
2364  if (lwgeom_dimension(geom) < dimension)
2365  {
2366  /* We've hit a lower dimension object produced by clipping at
2367  * a shallower recursion level. Ignore it. */
2368  return;
2369  }
2370 
2371  /* But don't go too far. 2^50 ~= 10^15, that's enough subdivision */
2372  /* Just add what's left */
2373  if ( depth > maxdepth )
2374  {
2376  return;
2377  }
2378 
2379  uint32_t nvertices = lwgeom_count_vertices(geom);
2380 
2381  /* Skip empties entirely */
2382  if (nvertices == 0)
2383  return;
2384 
2385  /* If it is under the vertex tolerance, just add it, we're done */
2386  if (nvertices <= maxvertices)
2387  {
2389  return;
2390  }
2391 
2392  uint8_t split_ordinate = (width > height) ? 0 : 1;
2393  double center = (split_ordinate == 0) ? (clip.xmin + clip.xmax) / 2 : (clip.ymin + clip.ymax) / 2;
2394  double pivot = DBL_MAX;
2395  if (geom->type == POLYGONTYPE)
2396  {
2397  uint32_t ring_to_trim = 0;
2398  double ring_area = 0;
2399  double pivot_eps = DBL_MAX;
2400  double pt_eps = DBL_MAX;
2401  POINTARRAY *pa;
2402  LWPOLY *lwpoly = (LWPOLY *)geom;
2403 
2404  /* if there are more points in holes than in outer ring */
2405  if (nvertices >= 2 * lwpoly->rings[0]->npoints)
2406  {
2407  /* trim holes starting from biggest */
2408  for (uint32_t i = 1; i < lwpoly->nrings; i++)
2409  {
2410  double current_ring_area = fabs(ptarray_signed_area(lwpoly->rings[i]));
2411  if (current_ring_area >= ring_area)
2412  {
2413  ring_area = current_ring_area;
2414  ring_to_trim = i;
2415  }
2416  }
2417  }
2418 
2419  pa = lwpoly->rings[ring_to_trim];
2420 
2421  /* find most central point in chosen ring */
2422  for (uint32_t i = 0; i < pa->npoints; i++)
2423  {
2424  double pt;
2425  if (split_ordinate == 0)
2426  pt = getPoint2d_cp(pa, i)->x;
2427  else
2428  pt = getPoint2d_cp(pa, i)->y;
2429  pt_eps = fabs(pt - center);
2430  if (pivot_eps > pt_eps)
2431  {
2432  pivot = pt;
2433  pivot_eps = pt_eps;
2434  }
2435  }
2436  }
2437  GBOX subbox1, subbox2;
2438  gbox_duplicate(&clip, &subbox1);
2439  gbox_duplicate(&clip, &subbox2);
2440 
2441  if (pivot == DBL_MAX)
2442  pivot = center;
2443 
2444  if (split_ordinate == 0)
2445  {
2446  if (FP_NEQUALS(subbox1.xmax, pivot) && FP_NEQUALS(subbox1.xmin, pivot))
2447  subbox1.xmax = subbox2.xmin = pivot;
2448  else
2449  subbox1.xmax = subbox2.xmin = center;
2450  }
2451  else
2452  {
2453  if (FP_NEQUALS(subbox1.ymax, pivot) && FP_NEQUALS(subbox1.ymin, pivot))
2454  subbox1.ymax = subbox2.ymin = pivot;
2455  else
2456  subbox1.ymax = subbox2.ymin = center;
2457  }
2458 
2459  ++depth;
2460 
2461  {
2463  geom->srid, subbox1.xmin, subbox1.ymin, subbox1.xmax, subbox1.ymax);
2464  LWGEOM *clipped = lwgeom_intersection_prec(geom, subbox, gridSize);
2465  lwgeom_simplify_in_place(clipped, 0.0, LW_TRUE);
2466  lwgeom_free(subbox);
2467  if (clipped && !lwgeom_is_empty(clipped))
2468  {
2469  lwgeom_subdivide_recursive(clipped, dimension, maxvertices, depth, col, gridSize);
2470  lwgeom_free(clipped);
2471  }
2472  }
2473  {
2475  geom->srid, subbox2.xmin, subbox2.ymin, subbox2.xmax, subbox2.ymax);
2476  LWGEOM *clipped = lwgeom_intersection_prec(geom, subbox, gridSize);
2477  lwgeom_simplify_in_place(clipped, 0.0, LW_TRUE);
2478  lwgeom_free(subbox);
2479  if (clipped && !lwgeom_is_empty(clipped))
2480  {
2481  lwgeom_subdivide_recursive(clipped, dimension, maxvertices, depth, col, gridSize);
2482  lwgeom_free(clipped);
2483  }
2484  }
2485 }
2486 
2487 LWCOLLECTION *
2488 lwgeom_subdivide_prec(const LWGEOM *geom, uint32_t maxvertices, double gridSize)
2489 {
2490  static uint32_t startdepth = 0;
2491  static uint32_t minmaxvertices = 5;
2492  LWCOLLECTION *col;
2493 
2495 
2496  if ( lwgeom_is_empty(geom) )
2497  return col;
2498 
2499  if ( maxvertices < minmaxvertices )
2500  {
2501  lwcollection_free(col);
2502  lwerror("%s: cannot subdivide to fewer than %d vertices per output", __func__, minmaxvertices);
2503  }
2504 
2505  lwgeom_subdivide_recursive(geom, lwgeom_dimension(geom), maxvertices, startdepth, col, gridSize);
2506  lwgeom_set_srid((LWGEOM*)col, geom->srid);
2507  return col;
2508 }
2509 
2510 LWCOLLECTION *
2511 lwgeom_subdivide(const LWGEOM *geom, uint32_t maxvertices)
2512 {
2513  return lwgeom_subdivide_prec(geom, maxvertices, -1);
2514 }
2515 
2516 
2517 
2518 int
2520 {
2521  int type = geom->type;
2522 
2523  if( type != LINETYPE )
2524  {
2525  lwnotice("Geometry is not a LINESTRING");
2526  return LW_FALSE;
2527  }
2528  return lwline_is_trajectory((LWLINE*)geom);
2529 }
2530 
2531 static uint8_t
2532 bits_for_precision(int32_t significant_digits)
2533 {
2534  int32_t bits_needed = ceil(significant_digits / log10(2));
2535 
2536  if (bits_needed > 52)
2537  {
2538  return 52;
2539  }
2540  else if (bits_needed < 1)
2541  {
2542  return 1;
2543  }
2544 
2545  return bits_needed;
2546 }
2547 
2548 static double trim_preserve_decimal_digits(double d, int32_t decimal_digits)
2549 {
2550  if (d == 0)
2551  return 0;
2552 
2553  int digits_left_of_decimal = (int) (1 + log10(fabs(d)));
2554  uint8_t bits_needed = bits_for_precision(decimal_digits + digits_left_of_decimal);
2555  uint64_t mask = 0xffffffffffffffffULL << (52 - bits_needed);
2556  uint64_t dint = 0;
2557  size_t dsz = sizeof(d) < sizeof(dint) ? sizeof(d) : sizeof(dint);
2558 
2559  memcpy(&dint, &d, dsz);
2560  dint &= mask;
2561  memcpy(&d, &dint, dsz);
2562  return d;
2563 }
2564 
2565 void lwgeom_trim_bits_in_place(LWGEOM* geom, int32_t prec_x, int32_t prec_y, int32_t prec_z, int32_t prec_m)
2566 {
2568  POINT4D p;
2569 
2570  while (lwpointiterator_has_next(it))
2571  {
2572  lwpointiterator_peek(it, &p);
2573  p.x = trim_preserve_decimal_digits(p.x, prec_x);
2574  p.y = trim_preserve_decimal_digits(p.y, prec_y);
2575  if (lwgeom_has_z(geom))
2576  p.z = trim_preserve_decimal_digits(p.z, prec_z);
2577  if (lwgeom_has_m(geom))
2578  p.m = trim_preserve_decimal_digits(p.m, prec_m);
2580  }
2581 
2583 }
2584 
2585 LWGEOM *
2587 {
2588  int32_t srid = lwgeom_get_srid(lwgeom);
2589  uint8_t hasz = lwgeom_has_z(lwgeom);
2590  uint8_t hasm = lwgeom_has_m(lwgeom);
2591 
2592  switch (lwgeom->type)
2593  {
2594  case POINTTYPE:
2595  case MULTIPOINTTYPE: {
2596  return lwgeom_construct_empty(lwgeom->type, srid, hasz, hasm);
2597  }
2598  case LINETYPE:
2599  case CIRCSTRINGTYPE: {
2600  if (lwgeom_is_closed(lwgeom) || lwgeom_is_empty(lwgeom))
2601  return (LWGEOM *)lwmpoint_construct_empty(srid, hasz, hasm);
2602  else
2603  {
2604  LWLINE *lwline = (LWLINE *)lwgeom;
2605  LWMPOINT *lwmpoint = lwmpoint_construct_empty(srid, hasz, hasm);
2606  POINT4D pt;
2607  getPoint4d_p(lwline->points, 0, &pt);
2608  lwmpoint_add_lwpoint(lwmpoint, lwpoint_make(srid, hasz, hasm, &pt));
2609  getPoint4d_p(lwline->points, lwline->points->npoints - 1, &pt);
2610  lwmpoint_add_lwpoint(lwmpoint, lwpoint_make(srid, hasz, hasm, &pt));
2611 
2612  return (LWGEOM *)lwmpoint;
2613  }
2614  }
2615  case MULTILINETYPE:
2616  case MULTICURVETYPE: {
2617  LWMLINE *lwmline = (LWMLINE *)lwgeom;
2618  POINT4D *out = lwalloc(sizeof(POINT4D) * lwmline->ngeoms * 2);
2619  uint32_t n = 0;
2620 
2621  for (uint32_t i = 0; i < lwmline->ngeoms; i++)
2622  {
2623  LWMPOINT *points = lwgeom_as_lwmpoint(lwgeom_boundary((LWGEOM *)lwmline->geoms[i]));
2624  if (!points)
2625  continue;
2626 
2627  for (uint32_t k = 0; k < points->ngeoms; k++)
2628  {
2629  POINT4D pt = getPoint4d(points->geoms[k]->point, 0);
2630 
2631  uint8_t seen = LW_FALSE;
2632  for (uint32_t j = 0; j < n; j++)
2633  {
2634  if (memcmp(&(out[j]), &pt, sizeof(POINT4D)) == 0)
2635  {
2636  seen = LW_TRUE;
2637  out[j] = out[--n];
2638  break;
2639  }
2640  }
2641  if (!seen)
2642  out[n++] = pt;
2643  }
2644 
2645  lwgeom_free((LWGEOM *)points);
2646  }
2647 
2648  LWMPOINT *lwmpoint = lwmpoint_construct_empty(srid, hasz, hasm);
2649 
2650  for (uint32_t i = 0; i < n; i++)
2651  lwmpoint_add_lwpoint(lwmpoint, lwpoint_make(srid, hasz, hasm, &(out[i])));
2652 
2653  lwfree(out);
2654 
2655  return (LWGEOM *)lwmpoint;
2656  }
2657  case TRIANGLETYPE: {
2658  LWTRIANGLE *lwtriangle = (LWTRIANGLE *)lwgeom;
2659  POINTARRAY *points = ptarray_clone_deep(lwtriangle->points);
2660  return (LWGEOM *)lwline_construct(srid, 0, points);
2661  }
2662  case POLYGONTYPE: {
2663  LWPOLY *lwpoly = (LWPOLY *)lwgeom;
2664 
2665  LWMLINE *lwmline = lwmline_construct_empty(srid, hasz, hasm);
2666  for (uint32_t i = 0; i < lwpoly->nrings; i++)
2667  {
2668  POINTARRAY *ring = ptarray_clone_deep(lwpoly->rings[i]);
2669  lwmline_add_lwline(lwmline, lwline_construct(srid, 0, ring));
2670  }
2671 
2672  /* Homogenize the multilinestring to hopefully get a single LINESTRING */
2673  LWGEOM *lwout = lwgeom_homogenize((LWGEOM *)lwmline);
2674  lwgeom_free((LWGEOM *)lwmline);
2675  return lwout;
2676  }
2677  case CURVEPOLYTYPE: {
2678  LWCURVEPOLY *lwcurvepoly = (LWCURVEPOLY *)lwgeom;
2679  LWCOLLECTION *lwcol = lwcollection_construct_empty(MULTICURVETYPE, srid, hasz, hasm);
2680 
2681  for (uint32_t i = 0; i < lwcurvepoly->nrings; i++)
2682  lwcol = lwcollection_add_lwgeom(lwcol, lwgeom_clone_deep(lwcurvepoly->rings[i]));
2683 
2684  return (LWGEOM *)lwcol;
2685  }
2686  case MULTIPOLYGONTYPE:
2687  case COLLECTIONTYPE:
2688  case TINTYPE: {
2689  LWCOLLECTION *lwcol = (LWCOLLECTION *)lwgeom;
2690  LWCOLLECTION *lwcol_boundary = lwcollection_construct_empty(COLLECTIONTYPE, srid, hasz, hasm);
2691 
2692  for (uint32_t i = 0; i < lwcol->ngeoms; i++)
2693  lwcollection_add_lwgeom(lwcol_boundary, lwgeom_boundary(lwcol->geoms[i]));
2694 
2695  LWGEOM *lwout = lwgeom_homogenize((LWGEOM *)lwcol_boundary);
2696  lwgeom_free((LWGEOM *)lwcol_boundary);
2697 
2698  return lwout;
2699  }
2700  default:
2701  lwerror("%s: unsupported geometry type: %s", __func__, lwtype_name(lwgeom->type));
2702  return NULL;
2703  }
2704 }
2705 
2706 int
2707 lwgeom_isfinite(const LWGEOM *lwgeom)
2708 {
2710  int hasz = lwgeom_has_z(lwgeom);
2711  int hasm = lwgeom_has_m(lwgeom);
2712 
2713  while (lwpointiterator_has_next(it))
2714  {
2715  POINT4D p;
2716  lwpointiterator_next(it, &p);
2717  int finite = isfinite(p.x) &&
2718  isfinite(p.y) &&
2719  (hasz ? isfinite(p.z) : 1) &&
2720  (hasm ? isfinite(p.m) : 1);
2721 
2722  if (!finite)
2723  {
2725  return LW_FALSE;
2726  }
2727  }
2729  return LW_TRUE;
2730 }
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:433
int lwgeom_calculate_gbox_cartesian(const LWGEOM *lwgeom, GBOX *gbox)
Calculate the 2-4D bounding box of a geometry.
Definition: gbox.c:740
GBOX * gbox_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:108
#define LW_FALSE
Definition: liblwgeom.h:109
#define COLLECTIONTYPE
Definition: liblwgeom.h:123
#define COMPOUNDTYPE
Definition: liblwgeom.h:125
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:242
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:111
LWCOLLECTION * lwcollection_segmentize2d(const LWCOLLECTION *coll, double dist)
Definition: lwcollection.c:251
#define CURVEPOLYTYPE
Definition: liblwgeom.h:126
void lwmpoly_free(LWMPOLY *mpoly)
Definition: lwmpoly.c:53
#define MULTILINETYPE
Definition: liblwgeom.h:121
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:128
#define LINETYPE
Definition: liblwgeom.h:118
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:2868
#define WKT_EXTENDED
Definition: liblwgeom.h:2168
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:120
#define FLAGS_SET_BBOX(flags, value)
Definition: liblwgeom.h:189
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:634
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:267
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:117
#define FLAGS_GET_Z(flags)
Definition: liblwgeom.h:180
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:131
LWPOLY * lwpoly_construct_envelope(int32_t srid, double x1, double y1, double x2, double y2)
Definition: lwpoly.c:98
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:122
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:242
#define FLAGS_NDIMS(flags)
Definition: liblwgeom.h:194
#define POLYGONTYPE
Definition: liblwgeom.h:119
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:129
#define CIRCSTRINGTYPE
Definition: liblwgeom.h:124
LWPOINTITERATOR * lwpointiterator_create_rw(LWGEOM *g)
Create a new LWPOINTITERATOR over supplied LWGEOM* Supports modification of coordinates during iterat...
Definition: lwiterator.c:251
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:181
void lwcollection_free(LWCOLLECTION *col)
Definition: lwcollection.c:357
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
Definition: lwgeom_api.c:126
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:185
#define FLAGS_GET_ZM(flags)
Definition: liblwgeom.h:195
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:127
#define TRIANGLETYPE
Definition: liblwgeom.h:130
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
Definition: lwcollection.c:188
#define FLAGS_SET_GEODETIC(flags, value)
Definition: liblwgeom.h:190
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:108
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:230
LWPOLY * lwpoly_from_lwlines(const LWLINE *shell, uint32_t nholes, const LWLINE **holes)
Definition: lwpoly.c:360
#define NUMTYPES
Definition: liblwgeom.h:133
LWCOMPOUND * lwcompound_construct_from_lwline(const LWLINE *lwpoly)
Construct an equivalent compound curve from a linestring.
Definition: lwcompound.c:204
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:183
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:1485
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:74
uint32_t lwpoly_count_vertices(LWPOLY *poly)
Definition: lwpoly.c:418
double ptarray_signed_area(const POINTARRAY *pa)
Returns the area in cartesian units.
Definition: ptarray.c:1003
#define LW_ON_INTERRUPT(x)
int lwline_is_closed(const LWLINE *line)
Definition: lwline.c:445
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:271
int lwcollection_startpoint(const LWCOLLECTION *col, POINT4D *pt)
Definition: lwcollection.c:550
int ptarray_startpoint(const POINTARRAY *pa, POINT4D *pt)
Definition: ptarray.c:2063
int lwcompound_is_closed(const LWCOMPOUND *curve)
Definition: lwcompound.c:35
double lwtriangle_perimeter_2d(const LWTRIANGLE *triangle)
Definition: lwtriangle.c:210
int lwpoly_is_clockwise(LWPOLY *poly)
Definition: lwpoly.c:288
void ptarray_grid_in_place(POINTARRAY *pa, const gridspec *grid)
Snap to grid.
Definition: ptarray.c:2078
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:1522
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:1700
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:69
LWCOLLECTION * lwcollection_clone_deep(const LWCOLLECTION *lwgeom)
Deep clone LWCOLLECTION object.
Definition: lwcollection.c:150
LWCOLLECTION * lwcollection_force_dims(const LWCOLLECTION *lwcol, int hasz, int hasm, double zval, double mval)
Definition: lwcollection.c:476
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:2045
void ptarray_affine(POINTARRAY *pa, const AFFINE *affine)
Affine transform a pointarray.
Definition: ptarray.c:1877
int lwpsurface_is_closed(const LWPSURFACE *psurface)
Definition: lwpsurface.c:99
double lwcurvepoly_perimeter(const LWCURVEPOLY *poly)
Definition: lwcurvepoly.c:147
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
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
uint32_t lwcollection_count_vertices(LWCOLLECTION *col)
Definition: lwcollection.c:500
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:124
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:395
uint32_t lwline_count_vertices(LWLINE *line)
Definition: lwline.c:505
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:50
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:2548
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 * 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:1893
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:1131
int32_t lwgeom_get_srid(const LWGEOM *geom)
Return SRID number.
Definition: lwgeom.c:927
int lwgeom_startpoint(const LWGEOM *lwgeom, POINT4D *pt)
Definition: lwgeom.c:2158
int lwgeom_is_collection(const LWGEOM *geom)
Determine whether a LWGEOM can contain sub-geometries or not.
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:1547
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:2565
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:1953
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:1570
LWGEOM * lwmline_as_lwgeom(const LWMLINE *obj)
Definition: lwgeom.c:299
static uint8_t bits_for_precision(int32_t significant_digits)
Definition: lwgeom.c:2532
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:2519
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
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:1404
LWGEOM * lwgeom_force_4d(const LWGEOM *geom, double zval, double mval)
Definition: lwgeom.c:811
double lwgeom_length(const LWGEOM *geom)
Definition: lwgeom.c:1975
LWGEOM * lwgeom_remove_repeated_points(const LWGEOM *in, double tolerance)
Definition: lwgeom.c:1471
int lwgeom_needs_bbox(const LWGEOM *geom)
Check whether or not a lwgeom is big enough to warrant a bounding box.
Definition: lwgeom.c:1208
int lwgeom_remove_repeated_points_in_place(LWGEOM *geom, double tolerance)
Definition: lwgeom.c:1604
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 may contain sub-geometries, i.e.
Definition: lwgeom.c:1105
char * lwgeom_to_ewkt(const LWGEOM *lwgeom)
Return an alloced 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:2707
static int lwcollection_dimensionality(const LWCOLLECTION *col)
Definition: lwgeom.c:1413
LWTRIANGLE * lwgeom_as_lwtriangle(const LWGEOM *lwgeom)
Definition: lwgeom.c:224
double lwgeom_area(const LWGEOM *geom)
Definition: lwgeom.c:1908
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:1246
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:1298
LWCOLLECTION * lwgeom_subdivide(const LWGEOM *geom, uint32_t maxvertices)
Definition: lwgeom.c:2511
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:1478
void lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
Definition: lwgeom.c:2020
uint8_t lwtype_multitype(uint8_t type)
Definition: lwgeom.c:370
LWGEOM * lwgeom_boundary(LWGEOM *lwgeom)
Definition: lwgeom.c:2586
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:1587
double lwgeom_length_2d(const LWGEOM *geom)
Definition: lwgeom.c:1997
uint32_t lwgeom_count_rings(const LWGEOM *geom)
Count rings in an LWGEOM.
Definition: lwgeom.c:1356
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
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:1426
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
Definition: lwgeom.c:233
void lwgeom_free(LWGEOM *lwgeom)
Definition: lwgeom.c:1155
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:2307
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:1931
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:2074
LWCOLLECTION * lwgeom_subdivide_prec(const LWGEOM *geom, uint32_t maxvertices, double gridSize)
Definition: lwgeom.c:2488
LWGEOM * lwgeom_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
Definition: lwgeom.c:2128
LWGEOM * lwgeom_grid(const LWGEOM *lwgeom, const gridspec *grid)
Definition: lwgeom.c:2290
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:1760
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
void lwgeom_grid_in_place(LWGEOM *geom, const gridspec *grid)
Definition: lwgeom.c:2189
LWCOMPOUND * lwgeom_as_lwcompound(const LWGEOM *lwgeom)
Definition: lwgeom.c:197
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
Definition: lwutil.c:177
static 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:101
static double distance2d_sqr_pt_pt(const POINT2D *p1, const POINT2D *p2)
Definition: lwinline.h:35
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:203
static LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Definition: lwinline.h:131
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:372
double xmax
Definition: liblwgeom.h:370
double ymin
Definition: liblwgeom.h:371
double xmin
Definition: liblwgeom.h:369
lwflags_t flags
Definition: liblwgeom.h:368
uint32_t ngeoms
Definition: liblwgeom.h:595
uint8_t type
Definition: liblwgeom.h:593
LWGEOM ** geoms
Definition: liblwgeom.h:590
LWGEOM ** rings
Definition: liblwgeom.h:618
uint32_t nrings
Definition: liblwgeom.h:623
uint8_t type
Definition: liblwgeom.h:477
GBOX * bbox
Definition: liblwgeom.h:473
int32_t srid
Definition: liblwgeom.h:475
lwflags_t flags
Definition: liblwgeom.h:476
POINTARRAY * points
Definition: liblwgeom.h:498
uint8_t type
Definition: liblwgeom.h:501
LWLINE ** geoms
Definition: liblwgeom.h:562
uint32_t ngeoms
Definition: liblwgeom.h:567
uint32_t ngeoms
Definition: liblwgeom.h:553
LWPOINT ** geoms
Definition: liblwgeom.h:548
POINTARRAY * point
Definition: liblwgeom.h:486
uint8_t type
Definition: liblwgeom.h:489
POINTARRAY ** rings
Definition: liblwgeom.h:534
uint32_t nrings
Definition: liblwgeom.h:539
POINTARRAY * points
Definition: liblwgeom.h:510
double y
Definition: liblwgeom.h:405
double x
Definition: liblwgeom.h:405
double m
Definition: liblwgeom.h:429
double x
Definition: liblwgeom.h:429
double z
Definition: liblwgeom.h:429
double y
Definition: liblwgeom.h:429
lwflags_t flags
Definition: liblwgeom.h:446
uint32_t maxpoints
Definition: liblwgeom.h:443
uint32_t npoints
Definition: liblwgeom.h:442
Snap-to-grid.
Definition: liblwgeom.h:1383