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