PostGIS  3.0.0dev-r@@SVN_REVISION@@
lwgeom.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * PostGIS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * PostGIS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18  *
19  **********************************************************************
20  *
21  * Copyright (C) 2001-2006 Refractions Research Inc.
22  * Copyright (C) 2017-2018 Daniel Baston <dbaston@gmail.com>
23  *
24  **********************************************************************/
25 
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 
31 #include "liblwgeom_internal.h"
32 #include "lwgeom_log.h"
33 
34 
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 
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 
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  int 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  switch(geom->type)
802  {
803  case POINTTYPE:
804  return lwpoint_as_lwgeom(lwpoint_force_dims((LWPOINT*)geom, hasz, hasm));
805  case CIRCSTRINGTYPE:
806  case LINETYPE:
807  case TRIANGLETYPE:
808  return lwline_as_lwgeom(lwline_force_dims((LWLINE*)geom, hasz, hasm));
809  case POLYGONTYPE:
810  return lwpoly_as_lwgeom(lwpoly_force_dims((LWPOLY*)geom, hasz, hasm));
811  case COMPOUNDTYPE:
812  case CURVEPOLYTYPE:
813  case MULTICURVETYPE:
814  case MULTISURFACETYPE:
815  case MULTIPOINTTYPE:
816  case MULTILINETYPE:
817  case MULTIPOLYGONTYPE:
819  case TINTYPE:
820  case COLLECTIONTYPE:
821  return lwcollection_as_lwgeom(lwcollection_force_dims((LWCOLLECTION*)geom, hasz, hasm));
822  default:
823  lwerror("lwgeom_force_2d: unsupported geom type: %s", lwtype_name(geom->type));
824  return NULL;
825  }
826 }
827 
828 LWGEOM*
829 lwgeom_force_sfs(LWGEOM *geom, int version)
830 {
831  LWCOLLECTION *col;
832  uint32_t i;
833  LWGEOM *g;
834 
835  /* SFS 1.2 version */
836  if (version == 120)
837  {
838  switch(geom->type)
839  {
840  /* SQL/MM types */
841  case CIRCSTRINGTYPE:
842  case COMPOUNDTYPE:
843  case CURVEPOLYTYPE:
844  case MULTICURVETYPE:
845  case MULTISURFACETYPE:
846  return lwgeom_stroke(geom, 32);
847 
848  case COLLECTIONTYPE:
849  col = (LWCOLLECTION*)geom;
850  for ( i = 0; i < col->ngeoms; i++ )
851  col->geoms[i] = lwgeom_force_sfs((LWGEOM*)col->geoms[i], version);
852 
853  return lwcollection_as_lwgeom((LWCOLLECTION*)geom);
854 
855  default:
856  return (LWGEOM *)geom;
857  }
858  }
859 
860 
861  /* SFS 1.1 version */
862  switch(geom->type)
863  {
864  /* SQL/MM types */
865  case CIRCSTRINGTYPE:
866  case COMPOUNDTYPE:
867  case CURVEPOLYTYPE:
868  case MULTICURVETYPE:
869  case MULTISURFACETYPE:
870  return lwgeom_stroke(geom, 32);
871 
872  /* SFS 1.2 types */
873  case TRIANGLETYPE:
874  g = lwpoly_as_lwgeom(lwpoly_from_lwlines((LWLINE*)geom, 0, NULL));
875  lwgeom_free(geom);
876  return g;
877 
878  case TINTYPE:
879  col = (LWCOLLECTION*) geom;
880  for ( i = 0; i < col->ngeoms; i++ )
881  {
882  g = lwpoly_as_lwgeom(lwpoly_from_lwlines((LWLINE*)col->geoms[i], 0, NULL));
883  lwgeom_free(col->geoms[i]);
884  col->geoms[i] = g;
885  }
886  col->type = COLLECTIONTYPE;
887  return lwmpoly_as_lwgeom((LWMPOLY*)geom);
888 
890  geom->type = COLLECTIONTYPE;
891  return (LWGEOM *)geom;
892 
893  /* Collection */
894  case COLLECTIONTYPE:
895  col = (LWCOLLECTION*)geom;
896  for ( i = 0; i < col->ngeoms; i++ )
897  col->geoms[i] = lwgeom_force_sfs((LWGEOM*)col->geoms[i], version);
898 
899  return lwcollection_as_lwgeom((LWCOLLECTION*)geom);
900 
901  default:
902  return (LWGEOM *)geom;
903  }
904 }
905 
906 int32_t
908 {
909  if ( ! geom ) return SRID_UNKNOWN;
910  return geom->srid;
911 }
912 
913 int
914 lwgeom_has_z(const LWGEOM *geom)
915 {
916  if ( ! geom ) return LW_FALSE;
917  return FLAGS_GET_Z(geom->flags);
918 }
919 
920 int
921 lwgeom_has_m(const LWGEOM *geom)
922 {
923  if ( ! geom ) return LW_FALSE;
924  return FLAGS_GET_M(geom->flags);
925 }
926 
927 int
928 lwgeom_ndims(const LWGEOM *geom)
929 {
930  if ( ! geom ) return 0;
931  return FLAGS_NDIMS(geom->flags);
932 }
933 
934 
935 void
937 {
938  LWPOINT *pt;
939  LWLINE *ln;
940  LWPOLY *ply;
941  LWCOLLECTION *col;
942  uint32_t i;
943 
944  FLAGS_SET_GEODETIC(geom->flags, value);
945  if ( geom->bbox )
946  FLAGS_SET_GEODETIC(geom->bbox->flags, value);
947 
948  switch(geom->type)
949  {
950  case POINTTYPE:
951  pt = (LWPOINT*)geom;
952  if ( pt->point )
953  FLAGS_SET_GEODETIC(pt->point->flags, value);
954  break;
955  case LINETYPE:
956  ln = (LWLINE*)geom;
957  if ( ln->points )
958  FLAGS_SET_GEODETIC(ln->points->flags, value);
959  break;
960  case POLYGONTYPE:
961  ply = (LWPOLY*)geom;
962  for ( i = 0; i < ply->nrings; i++ )
963  FLAGS_SET_GEODETIC(ply->rings[i]->flags, value);
964  break;
965  case MULTIPOINTTYPE:
966  case MULTILINETYPE:
967  case MULTIPOLYGONTYPE:
968  case COLLECTIONTYPE:
969  col = (LWCOLLECTION*)geom;
970  for ( i = 0; i < col->ngeoms; i++ )
971  lwgeom_set_geodetic(col->geoms[i], value);
972  break;
973  default:
974  lwerror("lwgeom_set_geodetic: unsupported geom type: %s", lwtype_name(geom->type));
975  return;
976  }
977 }
978 
979 void
981 {
982  uint32_t i;
983  switch (lwgeom->type)
984  {
985  LWPOINT *point;
986  LWLINE *line;
987  LWPOLY *poly;
988  LWTRIANGLE *triangle;
989  LWCOLLECTION *coll;
990 
991  case POINTTYPE:
992  point = (LWPOINT *)lwgeom;
994  return;
995  case LINETYPE:
996  line = (LWLINE *)lwgeom;
998  return;
999  case POLYGONTYPE:
1000  poly = (LWPOLY *)lwgeom;
1001  for (i=0; i<poly->nrings; i++)
1002  ptarray_longitude_shift(poly->rings[i]);
1003  return;
1004  case TRIANGLETYPE:
1005  triangle = (LWTRIANGLE *)lwgeom;
1006  ptarray_longitude_shift(triangle->points);
1007  return;
1008  case MULTIPOINTTYPE:
1009  case MULTILINETYPE:
1010  case MULTIPOLYGONTYPE:
1011  case POLYHEDRALSURFACETYPE:
1012  case TINTYPE:
1013  case COLLECTIONTYPE:
1014  coll = (LWCOLLECTION *)lwgeom;
1015  for (i=0; i<coll->ngeoms; i++)
1016  lwgeom_longitude_shift(coll->geoms[i]);
1017  return;
1018  default:
1019  lwerror("lwgeom_longitude_shift: unsupported geom type: %s",
1020  lwtype_name(lwgeom->type));
1021  }
1022 }
1023 
1024 int
1026 {
1027  int type = geom->type;
1028 
1029  if( lwgeom_is_empty(geom) )
1030  return LW_FALSE;
1031 
1032  /* Test linear types for closure */
1033  switch (type)
1034  {
1035  case LINETYPE:
1036  return lwline_is_closed((LWLINE*)geom);
1037  case POLYGONTYPE:
1038  return lwpoly_is_closed((LWPOLY*)geom);
1039  case CIRCSTRINGTYPE:
1040  return lwcircstring_is_closed((LWCIRCSTRING*)geom);
1041  case COMPOUNDTYPE:
1042  return lwcompound_is_closed((LWCOMPOUND*)geom);
1043  case TINTYPE:
1044  return lwtin_is_closed((LWTIN*)geom);
1045  case POLYHEDRALSURFACETYPE:
1046  return lwpsurface_is_closed((LWPSURFACE*)geom);
1047  }
1048 
1049  /* Recurse into collections and see if anything is not closed */
1050  if ( lwgeom_is_collection(geom) )
1051  {
1052  LWCOLLECTION *col = lwgeom_as_lwcollection(geom);
1053  uint32_t i;
1054  int closed;
1055  for ( i = 0; i < col->ngeoms; i++ )
1056  {
1057  closed = lwgeom_is_closed(col->geoms[i]);
1058  if ( ! closed )
1059  return LW_FALSE;
1060  }
1061  return LW_TRUE;
1062  }
1063 
1064  /* All non-linear non-collection types we will call closed */
1065  return LW_TRUE;
1066 }
1067 
1068 int
1070 {
1071  if( ! geom ) return LW_FALSE;
1072  return lwtype_is_collection(geom->type);
1073 }
1074 
1076 int
1078 {
1079 
1080  switch (type)
1081  {
1082  case MULTIPOINTTYPE:
1083  case MULTILINETYPE:
1084  case MULTIPOLYGONTYPE:
1085  case COLLECTIONTYPE:
1086  case CURVEPOLYTYPE:
1087  case COMPOUNDTYPE:
1088  case MULTICURVETYPE:
1089  case MULTISURFACETYPE:
1090  case POLYHEDRALSURFACETYPE:
1091  case TINTYPE:
1092  return LW_TRUE;
1093  break;
1094 
1095  default:
1096  return LW_FALSE;
1097  }
1098 }
1099 
1103 uint32_t
1105 {
1106  switch (type)
1107  {
1108  case POINTTYPE:
1109  return MULTIPOINTTYPE;
1110  case LINETYPE:
1111  return MULTILINETYPE;
1112  case POLYGONTYPE:
1113  return MULTIPOLYGONTYPE;
1114  case CIRCSTRINGTYPE:
1115  return MULTICURVETYPE;
1116  case COMPOUNDTYPE:
1117  return MULTICURVETYPE;
1118  case CURVEPOLYTYPE:
1119  return MULTISURFACETYPE;
1120  case TRIANGLETYPE:
1121  return TINTYPE;
1122  default:
1123  return COLLECTIONTYPE;
1124  }
1125 }
1126 
1127 
1128 void lwgeom_free(LWGEOM *lwgeom)
1129 {
1130 
1131  /* There's nothing here to free... */
1132  if( ! lwgeom ) return;
1133 
1134  LWDEBUGF(5,"freeing a %s",lwtype_name(lwgeom->type));
1135 
1136  switch (lwgeom->type)
1137  {
1138  case POINTTYPE:
1139  lwpoint_free((LWPOINT *)lwgeom);
1140  break;
1141  case LINETYPE:
1142  lwline_free((LWLINE *)lwgeom);
1143  break;
1144  case POLYGONTYPE:
1145  lwpoly_free((LWPOLY *)lwgeom);
1146  break;
1147  case CIRCSTRINGTYPE:
1148  lwcircstring_free((LWCIRCSTRING *)lwgeom);
1149  break;
1150  case TRIANGLETYPE:
1151  lwtriangle_free((LWTRIANGLE *)lwgeom);
1152  break;
1153  case MULTIPOINTTYPE:
1154  lwmpoint_free((LWMPOINT *)lwgeom);
1155  break;
1156  case MULTILINETYPE:
1157  lwmline_free((LWMLINE *)lwgeom);
1158  break;
1159  case MULTIPOLYGONTYPE:
1160  lwmpoly_free((LWMPOLY *)lwgeom);
1161  break;
1162  case POLYHEDRALSURFACETYPE:
1163  lwpsurface_free((LWPSURFACE *)lwgeom);
1164  break;
1165  case TINTYPE:
1166  lwtin_free((LWTIN *)lwgeom);
1167  break;
1168  case CURVEPOLYTYPE:
1169  case COMPOUNDTYPE:
1170  case MULTICURVETYPE:
1171  case MULTISURFACETYPE:
1172  case COLLECTIONTYPE:
1173  lwcollection_free((LWCOLLECTION *)lwgeom);
1174  break;
1175  default:
1176  lwerror("lwgeom_free called with unknown type (%d) %s", lwgeom->type, lwtype_name(lwgeom->type));
1177  }
1178  return;
1179 }
1180 
1181 int lwgeom_needs_bbox(const LWGEOM *geom)
1182 {
1183  assert(geom);
1184  if ( geom->type == POINTTYPE )
1185  {
1186  return LW_FALSE;
1187  }
1188  else if ( geom->type == LINETYPE )
1189  {
1190  if ( lwgeom_count_vertices(geom) <= 2 )
1191  return LW_FALSE;
1192  else
1193  return LW_TRUE;
1194  }
1195  else if ( geom->type == MULTIPOINTTYPE )
1196  {
1197  if ( ((LWCOLLECTION*)geom)->ngeoms == 1 )
1198  return LW_FALSE;
1199  else
1200  return LW_TRUE;
1201  }
1202  else if ( geom->type == MULTILINETYPE )
1203  {
1204  if ( ((LWCOLLECTION*)geom)->ngeoms == 1 && lwgeom_count_vertices(geom) <= 2 )
1205  return LW_FALSE;
1206  else
1207  return LW_TRUE;
1208  }
1209  else
1210  {
1211  return LW_TRUE;
1212  }
1213 }
1214 
1220 {
1221  int result = 0;
1222 
1223  /* Null? Zero. */
1224  if( ! geom ) return 0;
1225 
1226  LWDEBUGF(4, "lwgeom_count_vertices got type %s",
1227  lwtype_name(geom->type));
1228 
1229  /* Empty? Zero. */
1230  if( lwgeom_is_empty(geom) ) return 0;
1231 
1232  switch (geom->type)
1233  {
1234  case POINTTYPE:
1235  result = 1;
1236  break;
1237  case TRIANGLETYPE:
1238  case CIRCSTRINGTYPE:
1239  case LINETYPE:
1240  result = lwline_count_vertices((LWLINE *)geom);
1241  break;
1242  case POLYGONTYPE:
1243  result = lwpoly_count_vertices((LWPOLY *)geom);
1244  break;
1245  case COMPOUNDTYPE:
1246  case CURVEPOLYTYPE:
1247  case MULTICURVETYPE:
1248  case MULTISURFACETYPE:
1249  case MULTIPOINTTYPE:
1250  case MULTILINETYPE:
1251  case MULTIPOLYGONTYPE:
1252  case POLYHEDRALSURFACETYPE:
1253  case TINTYPE:
1254  case COLLECTIONTYPE:
1255  result = lwcollection_count_vertices((LWCOLLECTION *)geom);
1256  break;
1257  default:
1258  lwerror("%s: unsupported input geometry type: %s",
1259  __func__, lwtype_name(geom->type));
1260  break;
1261  }
1262  LWDEBUGF(3, "counted %d vertices", result);
1263  return result;
1264 }
1265 
1271 int lwgeom_dimension(const LWGEOM *geom)
1272 {
1273 
1274  /* Null? Zero. */
1275  if( ! geom ) return -1;
1276 
1277  LWDEBUGF(4, "lwgeom_dimension got type %s",
1278  lwtype_name(geom->type));
1279 
1280  /* Empty? Zero. */
1281  /* if( lwgeom_is_empty(geom) ) return 0; */
1282 
1283  switch (geom->type)
1284  {
1285  case POINTTYPE:
1286  case MULTIPOINTTYPE:
1287  return 0;
1288  case CIRCSTRINGTYPE:
1289  case LINETYPE:
1290  case COMPOUNDTYPE:
1291  case MULTICURVETYPE:
1292  case MULTILINETYPE:
1293  return 1;
1294  case TRIANGLETYPE:
1295  case POLYGONTYPE:
1296  case CURVEPOLYTYPE:
1297  case MULTISURFACETYPE:
1298  case MULTIPOLYGONTYPE:
1299  case TINTYPE:
1300  return 2;
1301  case POLYHEDRALSURFACETYPE:
1302  {
1303  /* A closed polyhedral surface contains a volume. */
1304  int closed = lwpsurface_is_closed((LWPSURFACE*)geom);
1305  return ( closed ? 3 : 2 );
1306  }
1307  case COLLECTIONTYPE:
1308  {
1309  int maxdim = 0;
1310  uint32_t i;
1311  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1312  for( i = 0; i < col->ngeoms; i++ )
1313  {
1314  int dim = lwgeom_dimension(col->geoms[i]);
1315  maxdim = ( dim > maxdim ? dim : maxdim );
1316  }
1317  return maxdim;
1318  }
1319  default:
1320  lwerror("%s: unsupported input geometry type: %s",
1321  __func__, lwtype_name(geom->type));
1322  }
1323  return -1;
1324 }
1325 
1330 {
1331  int result = 0;
1332 
1333  /* Null? Empty? Zero. */
1334  if( ! geom || lwgeom_is_empty(geom) )
1335  return 0;
1336 
1337  switch (geom->type)
1338  {
1339  case POINTTYPE:
1340  case CIRCSTRINGTYPE:
1341  case COMPOUNDTYPE:
1342  case MULTICURVETYPE:
1343  case MULTIPOINTTYPE:
1344  case MULTILINETYPE:
1345  case LINETYPE:
1346  result = 0;
1347  break;
1348  case TRIANGLETYPE:
1349  result = 1;
1350  break;
1351  case POLYGONTYPE:
1352  result = ((LWPOLY *)geom)->nrings;
1353  break;
1354  case CURVEPOLYTYPE:
1355  result = ((LWCURVEPOLY *)geom)->nrings;
1356  break;
1357  case MULTISURFACETYPE:
1358  case MULTIPOLYGONTYPE:
1359  case POLYHEDRALSURFACETYPE:
1360  case TINTYPE:
1361  case COLLECTIONTYPE:
1362  {
1363  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1364  uint32_t i = 0;
1365  for( i = 0; i < col->ngeoms; i++ )
1366  result += lwgeom_count_rings(col->geoms[i]);
1367  break;
1368  }
1369  default:
1370  lwerror("lwgeom_count_rings: unsupported input geometry type: %s", lwtype_name(geom->type));
1371  break;
1372  }
1373  LWDEBUGF(3, "counted %d rings", result);
1374  return result;
1375 }
1376 
1377 int lwgeom_has_srid(const LWGEOM *geom)
1378 {
1379  if ( geom->srid != SRID_UNKNOWN )
1380  return LW_TRUE;
1381 
1382  return LW_FALSE;
1383 }
1384 
1385 
1387 {
1388  uint32_t i;
1389  int dimensionality = 0;
1390  for ( i = 0; i < col->ngeoms; i++ )
1391  {
1392  int d = lwgeom_dimensionality(col->geoms[i]);
1393  if ( d > dimensionality )
1394  dimensionality = d;
1395  }
1396  return dimensionality;
1397 }
1398 
1399 extern int lwgeom_dimensionality(const LWGEOM *geom)
1400 {
1401  int dim;
1402 
1403  LWDEBUGF(3, "lwgeom_dimensionality got type %s",
1404  lwtype_name(geom->type));
1405 
1406  switch (geom->type)
1407  {
1408  case POINTTYPE:
1409  case MULTIPOINTTYPE:
1410  return 0;
1411  break;
1412  case LINETYPE:
1413  case CIRCSTRINGTYPE:
1414  case MULTILINETYPE:
1415  case COMPOUNDTYPE:
1416  case MULTICURVETYPE:
1417  return 1;
1418  break;
1419  case POLYGONTYPE:
1420  case TRIANGLETYPE:
1421  case CURVEPOLYTYPE:
1422  case MULTIPOLYGONTYPE:
1423  case MULTISURFACETYPE:
1424  return 2;
1425  break;
1426 
1427  case POLYHEDRALSURFACETYPE:
1428  case TINTYPE:
1429  dim = lwgeom_is_closed(geom)?3:2;
1430  return dim;
1431  break;
1432 
1433  case COLLECTIONTYPE:
1434  return lwcollection_dimensionality((const LWCOLLECTION *)geom);
1435  break;
1436  default:
1437  lwerror("lwgeom_dimensionality: unsupported input geometry type: %s",
1438  lwtype_name(geom->type));
1439  break;
1440  }
1441  return 0;
1442 }
1443 
1444 extern LWGEOM* lwgeom_remove_repeated_points(const LWGEOM *in, double tolerance)
1445 {
1446  LWGEOM *out = lwgeom_clone_deep(in);
1448  return out;
1449 }
1450 
1452 {
1453  LWCOLLECTION *col;
1454  LWPOLY *poly;
1455  uint32_t i;
1456 
1457  if ( (!in) || lwgeom_is_empty(in) ) return;
1458 
1459  /* TODO: check for lwgeom NOT having the specified dimension ? */
1460 
1461  LWDEBUGF(4, "lwgeom_flip_coordinates, got type: %s",
1462  lwtype_name(in->type));
1463 
1464  switch (in->type)
1465  {
1466  case POINTTYPE:
1467  ptarray_swap_ordinates(lwgeom_as_lwpoint(in)->point, o1, o2);
1468  break;
1469 
1470  case LINETYPE:
1471  ptarray_swap_ordinates(lwgeom_as_lwline(in)->points, o1, o2);
1472  break;
1473 
1474  case CIRCSTRINGTYPE:
1475  ptarray_swap_ordinates(lwgeom_as_lwcircstring(in)->points, o1, o2);
1476  break;
1477 
1478  case POLYGONTYPE:
1479  poly = (LWPOLY *) in;
1480  for (i=0; i<poly->nrings; i++)
1481  {
1482  ptarray_swap_ordinates(poly->rings[i], o1, o2);
1483  }
1484  break;
1485 
1486  case TRIANGLETYPE:
1487  ptarray_swap_ordinates(lwgeom_as_lwtriangle(in)->points, o1, o2);
1488  break;
1489 
1490  case MULTIPOINTTYPE:
1491  case MULTILINETYPE:
1492  case MULTIPOLYGONTYPE:
1493  case COLLECTIONTYPE:
1494  case COMPOUNDTYPE:
1495  case CURVEPOLYTYPE:
1496  case MULTISURFACETYPE:
1497  case MULTICURVETYPE:
1498  case POLYHEDRALSURFACETYPE:
1499  case TINTYPE:
1500  col = (LWCOLLECTION *) in;
1501  for (i=0; i<col->ngeoms; i++)
1502  {
1503  lwgeom_swap_ordinates(col->geoms[i], o1, o2);
1504  }
1505  break;
1506 
1507  default:
1508  lwerror("lwgeom_swap_ordinates: unsupported geometry type: %s",
1509  lwtype_name(in->type));
1510  return;
1511  }
1512 
1513  /* only refresh bbox if X or Y changed */
1514  if ( in->bbox && (o1 < 2 || o2 < 2) )
1515  {
1516  lwgeom_refresh_bbox(in);
1517  }
1518 }
1519 
1520 void lwgeom_set_srid(LWGEOM *geom, int32_t srid)
1521 {
1522  uint32_t i;
1523 
1524  LWDEBUGF(4,"entered with srid=%d",srid);
1525 
1526  geom->srid = srid;
1527 
1528  if ( lwgeom_is_collection(geom) )
1529  {
1530  /* All the children are set to the same SRID value */
1531  LWCOLLECTION *col = lwgeom_as_lwcollection(geom);
1532  for ( i = 0; i < col->ngeoms; i++ )
1533  {
1534  lwgeom_set_srid(col->geoms[i], srid);
1535  }
1536  }
1537 }
1538 
1539 
1540 /**************************************************************/
1541 
1542 
1543 void
1545 {
1546  switch (geom->type)
1547  {
1548  /* No-op! Cannot remote points */
1549  case POINTTYPE:
1550  return;
1551  case LINETYPE:
1552  {
1553  LWLINE *g = (LWLINE*)(geom);
1554  POINTARRAY *pa = g->points;
1555  ptarray_remove_repeated_points_in_place(pa, tolerance, 2);
1556  /* Invalid output */
1557  if (pa->npoints == 1 && pa->maxpoints > 1)
1558  {
1559  /* Use first point as last point */
1560  pa->npoints = 2;
1561  ptarray_copy_point(pa, 0, 1);
1562  }
1563  break;
1564  }
1565  case POLYGONTYPE:
1566  {
1567  uint32_t i, j = 0;
1568  LWPOLY *g = (LWPOLY*)(geom);
1569  for (i = 0; i < g->nrings; i++)
1570  {
1571  POINTARRAY *pa = g->rings[i];
1572  int minpoints = 4;
1573  /* Skip zero'ed out rings */
1574  if(!pa)
1575  continue;
1576  ptarray_remove_repeated_points_in_place(pa, tolerance, minpoints);
1577  /* Drop collapsed rings */
1578  if(pa->npoints < 4)
1579  {
1580  ptarray_free(pa);
1581  continue;
1582  }
1583  g->rings[j++] = pa;
1584  }
1585  /* Update ring count */
1586  g->nrings = j;
1587  break;
1588  }
1589  case MULTIPOINTTYPE:
1590  {
1591  static uint32_t out_stack_size = 32;
1592  double tolsq = tolerance*tolerance;
1593  uint32_t i, j, n = 0;
1594  LWMPOINT *mpt = (LWMPOINT *)(geom);
1595  LWPOINT **out;
1596  LWPOINT *out_stack[out_stack_size];
1597  int use_heap = (mpt->ngeoms > out_stack_size);
1598 
1599  /* No-op on empty */
1600  if (mpt->ngeoms == 0) return;
1601 
1602  /* We cannot write directly back to the multipoint */
1603  /* geoms array because we're reading out of it still */
1604  /* so we use a side array */
1605  if (use_heap)
1606  out = lwalloc(sizeof(LWMPOINT *) * mpt->ngeoms);
1607  else
1608  out = out_stack;
1609 
1610  /* Inefficient O(n^2) implementation */
1611  for (i = 0; i < mpt->ngeoms; i++)
1612  {
1613  int seen = 0;
1614  LWPOINT *p1 = mpt->geoms[i];
1615  const POINT2D *pt1 = getPoint2d_cp(p1->point, 0);
1616  for (j = 0; j < n; j++)
1617  {
1618  LWPOINT *p2 = out[j];
1619  const POINT2D *pt2 = getPoint2d_cp(p2->point, 0);
1620  if (distance2d_sqr_pt_pt(pt1, pt2) <= tolsq)
1621  {
1622  seen = 1;
1623  break;
1624  }
1625  }
1626  if (seen)
1627  {
1628  lwpoint_free(p1);
1629  continue;
1630  }
1631  out[n++] = p1;
1632  }
1633 
1634  /* Copy remaining points back into the input */
1635  /* array */
1636  memcpy(mpt->geoms, out, sizeof(LWPOINT *) * n);
1637  mpt->ngeoms = n;
1638  if (use_heap) lwfree(out);
1639  return;
1640  }
1641 
1642  case CIRCSTRINGTYPE:
1643  /* Dunno how to handle these, will return untouched */
1644  return;
1645 
1646  /* Can process most multi* types as generic collection */
1647  case MULTILINETYPE:
1648  case MULTIPOLYGONTYPE:
1649  case COLLECTIONTYPE:
1650  /* Curve types we mostly ignore, but allow the linear */
1651  /* portions to be processed by recursing into them */
1652  case MULTICURVETYPE:
1653  case CURVEPOLYTYPE:
1654  case MULTISURFACETYPE:
1655  case COMPOUNDTYPE:
1656  {
1657  uint32_t i, j = 0;
1658  LWCOLLECTION *col = (LWCOLLECTION*)(geom);
1659  for (i = 0; i < col->ngeoms; i++)
1660  {
1661  LWGEOM *g = col->geoms[i];
1662  if (!g) continue;
1664  /* Drop zero'ed out geometries */
1665  if(lwgeom_is_empty(g))
1666  {
1667  lwgeom_free(g);
1668  continue;
1669  }
1670  col->geoms[j++] = g;
1671  }
1672  /* Update geometry count */
1673  col->ngeoms = j;
1674  break;
1675  }
1676  default:
1677  {
1678  lwerror("%s: unsupported geometry type: %s", __func__, lwtype_name(geom->type));
1679  break;
1680  }
1681  }
1682  return;
1683 }
1684 
1685 
1686 /**************************************************************/
1687 
1688 void
1689 lwgeom_simplify_in_place(LWGEOM *geom, double epsilon, int preserve_collapsed)
1690 {
1691  switch (geom->type)
1692  {
1693  /* No-op! Cannot simplify points */
1694  case POINTTYPE:
1695  return;
1696  case LINETYPE:
1697  {
1698  LWLINE *g = (LWLINE*)(geom);
1699  POINTARRAY *pa = g->points;
1700  ptarray_simplify_in_place(pa, epsilon, 2);
1701  /* Invalid output */
1702  if (pa->npoints == 1 && pa->maxpoints > 1)
1703  {
1704  /* Use first point as last point */
1705  if (preserve_collapsed)
1706  {
1707  pa->npoints = 2;
1708  ptarray_copy_point(pa, 0, 1);
1709  }
1710  /* Finish the collapse process */
1711  else
1712  {
1713  pa->npoints = 0;
1714  }
1715  }
1716  /* Duped output, force collapse */
1717  if (pa->npoints == 2 && !preserve_collapsed)
1718  {
1719  if (p2d_same(getPoint2d_cp(pa, 0), getPoint2d_cp(pa, 1)))
1720  pa->npoints = 0;
1721  }
1722  break;
1723  }
1724  case POLYGONTYPE:
1725  {
1726  uint32_t i, j = 0;
1727  LWPOLY *g = (LWPOLY*)(geom);
1728  for (i = 0; i < g->nrings; i++)
1729  {
1730  POINTARRAY *pa = g->rings[i];
1731  /* Only stop collapse on first ring */
1732  int minpoints = (preserve_collapsed && i == 0) ? 4 : 0;
1733  /* Skip zero'ed out rings */
1734  if(!pa)
1735  continue;
1736  ptarray_simplify_in_place(pa, epsilon, minpoints);
1737  /* Drop collapsed rings */
1738  if(pa->npoints < 4)
1739  {
1740  ptarray_free(pa);
1741  continue;
1742  }
1743  g->rings[j++] = pa;
1744  }
1745  /* Update ring count */
1746  g->nrings = j;
1747  break;
1748  }
1749  /* Can process all multi* types as generic collection */
1750  case MULTIPOINTTYPE:
1751  case MULTILINETYPE:
1752  case MULTIPOLYGONTYPE:
1753  case COLLECTIONTYPE:
1754  {
1755  uint32_t i, j = 0;
1756  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1757  for (i = 0; i < col->ngeoms; i++)
1758  {
1759  LWGEOM *g = col->geoms[i];
1760  if (!g) continue;
1761  lwgeom_simplify_in_place(g, epsilon, preserve_collapsed);
1762  /* Drop zero'ed out geometries */
1763  if(lwgeom_is_empty(g))
1764  {
1765  lwgeom_free(g);
1766  continue;
1767  }
1768  col->geoms[j++] = g;
1769  }
1770  /* Update geometry count */
1771  col->ngeoms = j;
1772  break;
1773  }
1774  default:
1775  {
1776  lwerror("%s: unsupported geometry type: %s", __func__, lwtype_name(geom->type));
1777  break;
1778  }
1779  }
1780  return;
1781 }
1782 
1783 LWGEOM* lwgeom_simplify(const LWGEOM *igeom, double dist, int preserve_collapsed)
1784 {
1785  LWGEOM *lwgeom_out = lwgeom_clone_deep(igeom);
1786  lwgeom_simplify_in_place(lwgeom_out, dist, preserve_collapsed);
1787  if (lwgeom_is_empty(lwgeom_out))
1788  {
1789  lwgeom_free(lwgeom_out);
1790  return NULL;
1791  }
1792  return lwgeom_out;
1793 }
1794 
1795 /**************************************************************/
1796 
1797 
1798 double lwgeom_area(const LWGEOM *geom)
1799 {
1800  int type = geom->type;
1801 
1802  if ( type == POLYGONTYPE )
1803  return lwpoly_area((LWPOLY*)geom);
1804  else if ( type == CURVEPOLYTYPE )
1805  return lwcurvepoly_area((LWCURVEPOLY*)geom);
1806  else if (type == TRIANGLETYPE )
1807  return lwtriangle_area((LWTRIANGLE*)geom);
1808  else if ( lwgeom_is_collection(geom) )
1809  {
1810  double area = 0.0;
1811  uint32_t i;
1812  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1813  for ( i = 0; i < col->ngeoms; i++ )
1814  area += lwgeom_area(col->geoms[i]);
1815  return area;
1816  }
1817  else
1818  return 0.0;
1819 }
1820 
1821 double lwgeom_perimeter(const LWGEOM *geom)
1822 {
1823  int type = geom->type;
1824  if ( type == POLYGONTYPE )
1825  return lwpoly_perimeter((LWPOLY*)geom);
1826  else if ( type == CURVEPOLYTYPE )
1827  return lwcurvepoly_perimeter((LWCURVEPOLY*)geom);
1828  else if ( type == TRIANGLETYPE )
1829  return lwtriangle_perimeter((LWTRIANGLE*)geom);
1830  else if ( lwgeom_is_collection(geom) )
1831  {
1832  double perimeter = 0.0;
1833  uint32_t i;
1834  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1835  for ( i = 0; i < col->ngeoms; i++ )
1836  perimeter += lwgeom_perimeter(col->geoms[i]);
1837  return perimeter;
1838  }
1839  else
1840  return 0.0;
1841 }
1842 
1843 double lwgeom_perimeter_2d(const LWGEOM *geom)
1844 {
1845  int type = geom->type;
1846  if ( type == POLYGONTYPE )
1847  return lwpoly_perimeter_2d((LWPOLY*)geom);
1848  else if ( type == CURVEPOLYTYPE )
1849  return lwcurvepoly_perimeter_2d((LWCURVEPOLY*)geom);
1850  else if ( type == TRIANGLETYPE )
1851  return lwtriangle_perimeter_2d((LWTRIANGLE*)geom);
1852  else if ( lwgeom_is_collection(geom) )
1853  {
1854  double perimeter = 0.0;
1855  uint32_t i;
1856  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1857  for ( i = 0; i < col->ngeoms; i++ )
1858  perimeter += lwgeom_perimeter_2d(col->geoms[i]);
1859  return perimeter;
1860  }
1861  else
1862  return 0.0;
1863 }
1864 
1865 double lwgeom_length(const LWGEOM *geom)
1866 {
1867  int type = geom->type;
1868  if ( type == LINETYPE )
1869  return lwline_length((LWLINE*)geom);
1870  else if ( type == CIRCSTRINGTYPE )
1871  return lwcircstring_length((LWCIRCSTRING*)geom);
1872  else if ( type == COMPOUNDTYPE )
1873  return lwcompound_length((LWCOMPOUND*)geom);
1874  else if ( lwgeom_is_collection(geom) )
1875  {
1876  double length = 0.0;
1877  uint32_t i;
1878  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1879  for ( i = 0; i < col->ngeoms; i++ )
1880  length += lwgeom_length(col->geoms[i]);
1881  return length;
1882  }
1883  else
1884  return 0.0;
1885 }
1886 
1887 double lwgeom_length_2d(const LWGEOM *geom)
1888 {
1889  int type = geom->type;
1890  if ( type == LINETYPE )
1891  return lwline_length_2d((LWLINE*)geom);
1892  else if ( type == CIRCSTRINGTYPE )
1893  return lwcircstring_length_2d((LWCIRCSTRING*)geom);
1894  else if ( type == COMPOUNDTYPE )
1895  return lwcompound_length_2d((LWCOMPOUND*)geom);
1896  else if ( lwgeom_is_collection(geom) )
1897  {
1898  double length = 0.0;
1899  uint32_t i;
1900  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1901  for ( i = 0; i < col->ngeoms; i++ )
1902  length += lwgeom_length_2d(col->geoms[i]);
1903  return length;
1904  }
1905  else
1906  return 0.0;
1907 }
1908 
1909 void
1910 lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
1911 {
1912  int type = geom->type;
1913  uint32_t i;
1914 
1915  switch(type)
1916  {
1917  /* Take advantage of fact tht pt/ln/circ/tri have same memory structure */
1918  case POINTTYPE:
1919  case LINETYPE:
1920  case CIRCSTRINGTYPE:
1921  case TRIANGLETYPE:
1922  {
1923  LWLINE *l = (LWLINE*)geom;
1924  ptarray_affine(l->points, affine);
1925  break;
1926  }
1927  case POLYGONTYPE:
1928  {
1929  LWPOLY *p = (LWPOLY*)geom;
1930  for( i = 0; i < p->nrings; i++ )
1931  ptarray_affine(p->rings[i], affine);
1932  break;
1933  }
1934  case CURVEPOLYTYPE:
1935  {
1936  LWCURVEPOLY *c = (LWCURVEPOLY*)geom;
1937  for( i = 0; i < c->nrings; i++ )
1938  lwgeom_affine(c->rings[i], affine);
1939  break;
1940  }
1941  default:
1942  {
1943  if( lwgeom_is_collection(geom) )
1944  {
1945  LWCOLLECTION *c = (LWCOLLECTION*)geom;
1946  for( i = 0; i < c->ngeoms; i++ )
1947  {
1948  lwgeom_affine(c->geoms[i], affine);
1949  }
1950  }
1951  else
1952  {
1953  lwerror("lwgeom_affine: unable to handle type '%s'", lwtype_name(type));
1954  }
1955  }
1956  }
1957 
1958 }
1959 
1960 void
1961 lwgeom_scale(LWGEOM *geom, const POINT4D *factor)
1962 {
1963  int type = geom->type;
1964  uint32_t i;
1965 
1966  switch(type)
1967  {
1968  /* Take advantage of fact tht pt/ln/circ/tri have same memory structure */
1969  case POINTTYPE:
1970  case LINETYPE:
1971  case CIRCSTRINGTYPE:
1972  case TRIANGLETYPE:
1973  {
1974  LWLINE *l = (LWLINE*)geom;
1975  ptarray_scale(l->points, factor);
1976  break;
1977  }
1978  case POLYGONTYPE:
1979  {
1980  LWPOLY *p = (LWPOLY*)geom;
1981  for( i = 0; i < p->nrings; i++ )
1982  ptarray_scale(p->rings[i], factor);
1983  break;
1984  }
1985  case CURVEPOLYTYPE:
1986  {
1987  LWCURVEPOLY *c = (LWCURVEPOLY*)geom;
1988  for( i = 0; i < c->nrings; i++ )
1989  lwgeom_scale(c->rings[i], factor);
1990  break;
1991  }
1992  default:
1993  {
1994  if( lwgeom_is_collection(geom) )
1995  {
1996  LWCOLLECTION *c = (LWCOLLECTION*)geom;
1997  for( i = 0; i < c->ngeoms; i++ )
1998  {
1999  lwgeom_scale(c->geoms[i], factor);
2000  }
2001  }
2002  else
2003  {
2004  lwerror("lwgeom_scale: unable to handle type '%s'", lwtype_name(type));
2005  }
2006  }
2007  }
2008 
2009  /* Recompute bbox if needed */
2010 
2011  if ( geom->bbox )
2012  {
2013  /* TODO: expose a gbox_scale function */
2014  geom->bbox->xmin *= factor->x;
2015  geom->bbox->xmax *= factor->x;
2016  geom->bbox->ymin *= factor->y;
2017  geom->bbox->ymax *= factor->y;
2018  geom->bbox->zmin *= factor->z;
2019  geom->bbox->zmax *= factor->z;
2020  geom->bbox->mmin *= factor->m;
2021  geom->bbox->mmax *= factor->m;
2022  }
2023 }
2024 
2025 LWGEOM*
2026 lwgeom_construct_empty(uint8_t type, int srid, char hasz, char hasm)
2027 {
2028  switch(type)
2029  {
2030  case POINTTYPE:
2031  return lwpoint_as_lwgeom(lwpoint_construct_empty(srid, hasz, hasm));
2032  case LINETYPE:
2033  return lwline_as_lwgeom(lwline_construct_empty(srid, hasz, hasm));
2034  case POLYGONTYPE:
2035  return lwpoly_as_lwgeom(lwpoly_construct_empty(srid, hasz, hasm));
2036  case CURVEPOLYTYPE:
2037  return lwcurvepoly_as_lwgeom(lwcurvepoly_construct_empty(srid, hasz, hasm));
2038  case CIRCSTRINGTYPE:
2039  return lwcircstring_as_lwgeom(lwcircstring_construct_empty(srid, hasz, hasm));
2040  case TRIANGLETYPE:
2041  return lwtriangle_as_lwgeom(lwtriangle_construct_empty(srid, hasz, hasm));
2042  case COMPOUNDTYPE:
2043  case MULTIPOINTTYPE:
2044  case MULTILINETYPE:
2045  case MULTIPOLYGONTYPE:
2046  case COLLECTIONTYPE:
2047  return lwcollection_as_lwgeom(lwcollection_construct_empty(type, srid, hasz, hasm));
2048  default:
2049  lwerror("lwgeom_construct_empty: unsupported geometry type: %s",
2050  lwtype_name(type));
2051  return NULL;
2052  }
2053 }
2054 
2055 int
2056 lwgeom_startpoint(const LWGEOM *lwgeom, POINT4D *pt)
2057 {
2058  if ( ! lwgeom )
2059  return LW_FAILURE;
2060 
2061  switch( lwgeom->type )
2062  {
2063  case POINTTYPE:
2064  return ptarray_startpoint(((LWPOINT*)lwgeom)->point, pt);
2065  case TRIANGLETYPE:
2066  case CIRCSTRINGTYPE:
2067  case LINETYPE:
2068  return ptarray_startpoint(((LWLINE*)lwgeom)->points, pt);
2069  case POLYGONTYPE:
2070  return lwpoly_startpoint((LWPOLY*)lwgeom, pt);
2071  case CURVEPOLYTYPE:
2072  case COMPOUNDTYPE:
2073  case MULTIPOINTTYPE:
2074  case MULTILINETYPE:
2075  case MULTIPOLYGONTYPE:
2076  case COLLECTIONTYPE:
2077  return lwcollection_startpoint((LWCOLLECTION*)lwgeom, pt);
2078  default:
2079  lwerror("int: unsupported geometry type: %s",
2080  lwtype_name(lwgeom->type));
2081  return LW_FAILURE;
2082  }
2083 }
2084 
2085 void
2087 {
2088  if (!geom) return;
2089  switch ( geom->type )
2090  {
2091  case POINTTYPE:
2092  {
2093  LWPOINT *pt = (LWPOINT*)(geom);
2094  ptarray_grid_in_place(pt->point, grid);
2095  return;
2096  }
2097  case CIRCSTRINGTYPE:
2098  case LINETYPE:
2099  {
2100  LWLINE *ln = (LWLINE*)(geom);
2101  ptarray_grid_in_place(ln->points, grid);
2102  /* For invalid line, return an EMPTY */
2103  if (ln->points->npoints < 2)
2104  ln->points->npoints = 0;
2105  return;
2106  }
2107  case POLYGONTYPE:
2108  {
2109  LWPOLY *ply = (LWPOLY*)(geom);
2110  if (!ply->rings) return;
2111 
2112  /* Check first the external ring */
2113  uint32_t i = 0;
2114  POINTARRAY *pa = ply->rings[0];
2115  ptarray_grid_in_place(pa, grid);
2116  if (pa->npoints < 4)
2117  {
2118  /* External ring collapsed: free everything */
2119  for (i = 0; i < ply->nrings; i++)
2120  {
2121  ptarray_free(ply->rings[i]);
2122  }
2123  ply->nrings = 0;
2124  return;
2125  }
2126 
2127  /* Check the other rings */
2128  uint32_t j = 1;
2129  for (i = 1; i < ply->nrings; i++)
2130  {
2131  POINTARRAY *pa = ply->rings[i];
2132  ptarray_grid_in_place(pa, grid);
2133 
2134  /* Skip bad rings */
2135  if (pa->npoints >= 4)
2136  {
2137  ply->rings[j++] = pa;
2138  }
2139  else
2140  {
2141  ptarray_free(pa);
2142  }
2143  }
2144  /* Adjust ring count appropriately */
2145  ply->nrings = j;
2146  return;
2147  }
2148  case MULTIPOINTTYPE:
2149  case MULTILINETYPE:
2150  case MULTIPOLYGONTYPE:
2151  case COLLECTIONTYPE:
2152  case COMPOUNDTYPE:
2153  {
2154  LWCOLLECTION *col = (LWCOLLECTION*)(geom);
2155  uint32_t i, j = 0;
2156  if (!col->geoms) return;
2157  for (i = 0; i < col->ngeoms; i++)
2158  {
2159  LWGEOM *g = col->geoms[i];
2160  lwgeom_grid_in_place(g, grid);
2161  /* Empty geoms need to be freed */
2162  /* before we move on */
2163  if (lwgeom_is_empty(g))
2164  {
2165  lwgeom_free(g);
2166  continue;
2167  }
2168  col->geoms[j++] = g;
2169  }
2170  col->ngeoms = j;
2171  return;
2172  }
2173  default:
2174  {
2175  lwerror("%s: Unsupported geometry type: %s", __func__,
2176  lwtype_name(geom->type));
2177  return;
2178  }
2179  }
2180 }
2181 
2182 
2183 LWGEOM *
2184 lwgeom_grid(const LWGEOM *lwgeom, const gridspec *grid)
2185 {
2186  LWGEOM *lwgeom_out = lwgeom_clone_deep(lwgeom);
2187  lwgeom_grid_in_place(lwgeom_out, grid);
2188  return lwgeom_out;
2189 }
2190 
2191 
2192 /* Prototype for recursion */
2193 static int lwgeom_subdivide_recursive(const LWGEOM *geom, uint8_t dimension, uint32_t maxvertices, uint32_t depth, LWCOLLECTION *col);
2194 
2195 static int
2196 lwgeom_subdivide_recursive(const LWGEOM *geom, uint8_t dimension, uint32_t maxvertices, uint32_t depth, LWCOLLECTION *col)
2197 {
2198  const uint32_t maxdepth = 50;
2199  GBOX clip, subbox1, subbox2;
2200  uint32_t nvertices = 0;
2201  uint32_t i, n = 0;
2202  uint32_t split_ordinate;
2203  double width;
2204  double height;
2205  double pivot = DBL_MAX;
2206  double center = DBL_MAX;
2207  LWPOLY *lwpoly = NULL;
2208  LWGEOM *clipped;
2209 
2210  gbox_duplicate(lwgeom_get_bbox(geom), &clip);
2211  width = clip.xmax - clip.xmin;
2212  height = clip.ymax - clip.ymin;
2213 
2214  if ( geom->type == POLYHEDRALSURFACETYPE || geom->type == TINTYPE )
2215  lwerror("%s: unsupported geometry type '%s'", __func__, lwtype_name(geom->type));
2216 
2217  if ( width == 0.0 && height == 0.0 )
2218  {
2219  if ( geom->type == POINTTYPE && dimension == 0)
2220  {
2222  return 1;
2223  }
2224  else
2225  return 0;
2226  }
2227 
2228  if (width == 0.0)
2229  {
2230  clip.xmax += FP_TOLERANCE;
2231  clip.xmin -= FP_TOLERANCE;
2232  width = 2 * FP_TOLERANCE;
2233  }
2234  if (height == 0.0)
2235  {
2236  clip.ymax += FP_TOLERANCE;
2237  clip.ymin -= FP_TOLERANCE;
2238  height = 2 * FP_TOLERANCE;
2239  }
2240 
2241  /* Always just recurse into collections */
2242  if ( lwgeom_is_collection(geom) && geom->type != MULTIPOINTTYPE )
2243  {
2244  LWCOLLECTION *incol = (LWCOLLECTION*)geom;
2245  int n = 0;
2246  /* Don't increment depth yet, since we aren't actually
2247  * subdividing geometries yet */
2248  for ( i = 0; i < incol->ngeoms; i++ )
2249  n += lwgeom_subdivide_recursive(incol->geoms[i], dimension, maxvertices, depth, col);
2250  return n;
2251  }
2252 
2253  if (lwgeom_dimension(geom) < dimension)
2254  {
2255  /* We've hit a lower dimension object produced by clipping at
2256  * a shallower recursion level. Ignore it. */
2257  return 0;
2258  }
2259 
2260  /* But don't go too far. 2^50 ~= 10^15, that's enough subdivision */
2261  /* Just add what's left */
2262  if ( depth > maxdepth )
2263  {
2265  return 1;
2266  }
2267 
2268  nvertices = lwgeom_count_vertices(geom);
2269 
2270  /* Skip empties entirely */
2271  if (nvertices == 0) return 0;
2272 
2273  /* If it is under the vertex tolerance, just add it, we're done */
2274  if (nvertices <= maxvertices)
2275  {
2277  return 1;
2278  }
2279 
2280  split_ordinate = (width > height) ? 0 : 1;
2281  if (split_ordinate == 0)
2282  center = (clip.xmin + clip.xmax) / 2;
2283  else
2284  center = (clip.ymin + clip.ymax) / 2;
2285 
2286  if (geom->type == POLYGONTYPE)
2287  {
2288  uint32_t ring_to_trim = 0;
2289  double ring_area = 0;
2290  double pivot_eps = DBL_MAX;
2291  double pt_eps = DBL_MAX;
2292  POINTARRAY *pa;
2293  pivot = DBL_MAX;
2294  lwpoly = (LWPOLY *)geom;
2295 
2296  /* if there are more points in holes than in outer ring */
2297  if (nvertices > 2 * lwpoly->rings[0]->npoints)
2298  {
2299  /* trim holes starting from biggest */
2300  for (i = 1; i < lwpoly->nrings; i++)
2301  {
2302  double current_ring_area = fabs(ptarray_signed_area(lwpoly->rings[i]));
2303  if (current_ring_area >= ring_area)
2304  {
2305  ring_area = current_ring_area;
2306  ring_to_trim = i;
2307  }
2308  }
2309  }
2310 
2311  pa = lwpoly->rings[ring_to_trim];
2312 
2313  /* find most central point in chosen ring */
2314  for (i = 0; i < pa->npoints; i++)
2315  {
2316  double pt;
2317  if (split_ordinate == 0)
2318  pt = getPoint2d_cp(pa, i)->x;
2319  else
2320  pt = getPoint2d_cp(pa, i)->y;
2321  pt_eps = fabs(pt - center);
2322  if (pivot_eps > pt_eps)
2323  {
2324  pivot = pt;
2325  pivot_eps = pt_eps;
2326  }
2327  }
2328  }
2329 
2330  gbox_duplicate(&clip, &subbox1);
2331  gbox_duplicate(&clip, &subbox2);
2332 
2333  if (pivot == DBL_MAX) pivot = center;
2334 
2335  if (split_ordinate == 0)
2336  subbox1.xmax = subbox2.xmin = pivot;
2337  else
2338  subbox1.ymax = subbox2.ymin = pivot;
2339 
2340  ++depth;
2341 
2342  LWGEOM* subbox = (LWGEOM*) lwpoly_construct_envelope(geom->srid, subbox1.xmin, subbox1.ymin, subbox1.xmax, subbox1.ymax);
2343  clipped = lwgeom_intersection(geom, subbox);
2344  lwgeom_simplify_in_place(clipped, 0.0, LW_TRUE);
2345  lwgeom_free(subbox);
2346  if (clipped)
2347  {
2348  n += lwgeom_subdivide_recursive(clipped, dimension, maxvertices, depth, col);
2349  lwgeom_free(clipped);
2350  }
2351 
2352  subbox = (LWGEOM*) lwpoly_construct_envelope(geom->srid, subbox2.xmin, subbox2.ymin, subbox2.xmax, subbox2.ymax);
2353  clipped = lwgeom_intersection(geom, subbox);
2354  lwgeom_simplify_in_place(clipped, 0.0, LW_TRUE);
2355  lwgeom_free(subbox);
2356  if (clipped)
2357  {
2358  n += lwgeom_subdivide_recursive(clipped, dimension, maxvertices, depth, col);
2359  lwgeom_free(clipped);
2360  }
2361 
2362  return n;
2363 }
2364 
2365 LWCOLLECTION *
2366 lwgeom_subdivide(const LWGEOM *geom, uint32_t maxvertices)
2367 {
2368  static uint32_t startdepth = 0;
2369  static uint32_t minmaxvertices = 5;
2370  LWCOLLECTION *col;
2371 
2373 
2374  if ( lwgeom_is_empty(geom) )
2375  return col;
2376 
2377  if ( maxvertices < minmaxvertices )
2378  {
2379  lwcollection_free(col);
2380  lwerror("%s: cannot subdivide to fewer than %d vertices per output", __func__, minmaxvertices);
2381  }
2382 
2383  lwgeom_subdivide_recursive(geom, lwgeom_dimension(geom), maxvertices, startdepth, col);
2384  lwgeom_set_srid((LWGEOM*)col, geom->srid);
2385  return col;
2386 }
2387 
2388 
2389 int
2391 {
2392  int type = geom->type;
2393 
2394  if( type != LINETYPE )
2395  {
2396  lwnotice("Geometry is not a LINESTRING");
2397  return LW_FALSE;
2398  }
2399  return lwline_is_trajectory((LWLINE*)geom);
2400 }
2401 
2402 static uint8_t
2403 bits_for_precision(int32_t significant_digits)
2404 {
2405  int32_t bits_needed = ceil(significant_digits / log10(2));
2406 
2407  if (bits_needed > 52)
2408  {
2409  return 52;
2410  }
2411  else if (bits_needed < 1)
2412  {
2413  return 1;
2414  }
2415 
2416  return bits_needed;
2417 }
2418 
2419 static inline
2420 double mask_double(double d, uint64_t mask)
2421 {
2422  uint64_t* double_bits = (uint64_t*) (&d);
2423 
2424  (*double_bits) &= mask;
2425 
2426  return *((double*) double_bits);
2427 }
2428 
2429 static double trim_preserve_decimal_digits(double d, int32_t decimal_digits)
2430 {
2431  if (d==0)
2432  return 0;
2433 
2434  int digits_left_of_decimal = (int) (1 + log10(fabs(d)));
2435  uint8_t bits_needed = bits_for_precision(decimal_digits + digits_left_of_decimal);
2436 
2437 
2438  uint64_t mask = 0xffffffffffffffff << (52 - bits_needed);
2439 
2440  return mask_double(d, mask);
2441 }
2442 
2443 void lwgeom_trim_bits_in_place(LWGEOM* geom, int32_t prec_x, int32_t prec_y, int32_t prec_z, int32_t prec_m)
2444 {
2446  POINT4D p;
2447 
2448  while (lwpointiterator_has_next(it))
2449  {
2450  lwpointiterator_peek(it, &p);
2451  p.x = trim_preserve_decimal_digits(p.x, prec_x);
2452  p.y = trim_preserve_decimal_digits(p.y, prec_y);
2453  if (lwgeom_has_z(geom))
2454  p.z = trim_preserve_decimal_digits(p.z, prec_z);
2455  if (lwgeom_has_m(geom))
2456  p.m = trim_preserve_decimal_digits(p.m, prec_m);
2458  }
2459 
2461 }
LWMPOINT * lwgeom_as_lwmpoint(const LWGEOM *lwgeom)
Definition: lwgeom.c:224
double x
Definition: liblwgeom.h:354
#define LINETYPE
Definition: liblwgeom.h:85
int lwgeom_calculate_gbox_geodetic(const LWGEOM *geom, GBOX *gbox)
Calculate the geodetic bounding box for an LWGEOM.
Definition: lwgeodetic.c:2940
LWPOINT * lwpoint_force_dims(const LWPOINT *lwpoint, int hasz, int hasm)
Definition: lwpoint.c:271
char lwtriangle_same(const LWTRIANGLE *p1, const LWTRIANGLE *p2)
Definition: lwtriangle.c:126
static LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Definition: lwinline.h:100
LWGEOM * lwgeom_stroke(const LWGEOM *geom, uint32_t perQuad)
Definition: lwstroke.c:760
void lwgeom_reverse_in_place(LWGEOM *geom)
Reverse vertex order of LWGEOM.
Definition: lwgeom.c:102
int lwgeom_startpoint(const LWGEOM *lwgeom, POINT4D *pt)
Definition: lwgeom.c:2056
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:311
LWPSURFACE * lwgeom_as_lwpsurface(const LWGEOM *lwgeom)
Definition: lwgeom.c:251
static int lwgeom_subdivide_recursive(const LWGEOM *geom, uint8_t dimension, uint32_t maxvertices, uint32_t depth, LWCOLLECTION *col)
Definition: lwgeom.c:2196
GBOX * gbox_new(uint8_t flags)
Create a new gbox with the dimensionality indicated by the flags.
Definition: g_box.c:39
GBOX * bbox
Definition: liblwgeom.h:400
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
LWPOLY * lwpoly_clone_deep(const LWPOLY *lwgeom)
Definition: lwpoly.c:228
LWGEOM * lwgeom_reverse(const LWGEOM *geom)
Definition: lwgeom.c:93
LWLINE * lwline_construct_empty(int srid, char hasz, char hasm)
Definition: lwline.c:64
POINTARRAY * points
Definition: liblwgeom.h:435
double lwcircstring_length(const LWCIRCSTRING *circ)
Definition: lwcircstring.c:269
double m
Definition: liblwgeom.h:354
uint8_t lwtype_multitype(uint8_t type)
Definition: lwgeom.c:352
#define MULTICURVETYPE
Definition: liblwgeom.h:94
LWPOLY * lwpoly_segmentize2d(const LWPOLY *line, double dist)
Definition: lwpoly.c:312
uint32_t ngeoms
Definition: liblwgeom.h:470
void lwgeom_drop_bbox(LWGEOM *lwgeom)
Call this function to drop BBOX and SRID from LWGEOM.
Definition: lwgeom.c:664
GEOGRAPHIC_POINT center
LWCOLLECTION * lwcollection_construct(uint8_t type, int srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
Definition: lwcollection.c:43
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:226
char * r
Definition: cu_in_wkt.c:24
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition: lwout_wkt.c:676
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
Definition: lwutil.c:177
void lwgeom_scale(LWGEOM *geom, const POINT4D *factor)
Definition: lwgeom.c:1961
LWGEOM * lwgeom_force_3dm(const LWGEOM *geom)
Definition: lwgeom.c:787
void lwgeom_drop_srid(LWGEOM *lwgeom)
Definition: lwgeom.c:747
void lwpoly_force_clockwise(LWPOLY *poly)
Definition: lwpoly.c:268
void lwmline_free(LWMLINE *mline)
Definition: lwmline.c:112
void gbox_duplicate(const GBOX *original, GBOX *duplicate)
Copy the values of original GBOX into duplicate.
Definition: g_box.c:440
void lwfree(void *mem)
Definition: lwutil.c:242
LWTRIANGLE * lwtriangle_construct_empty(int srid, char hasz, char hasm)
Definition: lwtriangle.c:58
int32_t lwgeom_get_srid(const LWGEOM *geom)
Return SRID number.
Definition: lwgeom.c:907
LWGEOM ** rings
Definition: liblwgeom.h:537
LWLINE * lwline_clone(const LWLINE *lwgeom)
Definition: lwline.c:102
char lwpoint_same(const LWPOINT *p1, const LWPOINT *p2)
Definition: lwpoint.c:264
int lwtin_is_closed(const LWTIN *tin)
Definition: lwtin.c:93
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:1921
uint8_t type
Definition: liblwgeom.h:505
double lwgeom_length(const LWGEOM *geom)
Definition: lwgeom.c:1865
POINT2D * p2
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition: lwgeom.c:921
LWLINE * lwline_segmentize2d(const LWLINE *line, double dist)
Definition: lwline.c:141
uint32_t lwcollection_count_vertices(LWCOLLECTION *col)
Definition: lwcollection.c:509
void lwcircstring_free(LWCIRCSTRING *curve)
Definition: lwcircstring.c:97
void lwgeom_force_clockwise(LWGEOM *lwgeom)
Force Right-hand-rule on LWGEOM polygons.
Definition: lwgeom.c:37
#define FLAGS_GET_GEODETIC(flags)
Definition: liblwgeom.h:142
#define POLYGONTYPE
Definition: liblwgeom.h:86
Datum area(PG_FUNCTION_ARGS)
void lwtin_free(LWTIN *tin)
Definition: lwtin.c:39
uint8_t flags
Definition: liblwgeom.h:399
double xmax
Definition: liblwgeom.h:295
#define CURVEPOLYTYPE
Definition: liblwgeom.h:93
void ptarray_copy_point(POINTARRAY *pa, uint32_t from, uint32_t to)
Definition: lwgeom_api.c:429
void lwpoint_free(LWPOINT *pt)
Definition: lwpoint.c:213
void ptarray_free(POINTARRAY *pa)
Definition: ptarray.c:316
#define COMPOUNDTYPE
Definition: liblwgeom.h:92
POINT2D * p1
#define MULTIPOINTTYPE
Definition: liblwgeom.h:87
uint32_t lwline_count_vertices(LWLINE *line)
Definition: lwline.c:511
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
Definition: lwgeom.c:197
int lwgeom_ndims(const LWGEOM *geom)
Return the number of dimensions (2, 3, 4) in a geometry.
Definition: lwgeom.c:928
uint32_t lwgeom_count_vertices(const LWGEOM *geom)
Count points in an LWGEOM.
Definition: lwgeom.c:1219
void lwgeom_longitude_shift(LWGEOM *lwgeom)
Definition: lwgeom.c:980
void lwline_free(LWLINE *line)
Definition: lwline.c:76
void lwgeom_refresh_bbox(LWGEOM *lwgeom)
Drop current bbox and calculate a fresh one.
Definition: lwgeom.c:689
LWGEOM * lwgeom_grid(const LWGEOM *lwgeom, const gridspec *grid)
Definition: lwgeom.c:2184
LWPOINT * lwpoint_clone(const LWPOINT *lwgeom)
Definition: lwpoint.c:239
void lwgeom_swap_ordinates(LWGEOM *in, LWORD o1, LWORD o2)
Swap ordinate values in every vertex of the geometry.
Definition: lwgeom.c:1451
double lwtriangle_perimeter_2d(const LWTRIANGLE *triangle)
Definition: lwtriangle.c:210
#define FLAGS_GET_ZM(flags)
Definition: liblwgeom.h:152
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:2443
double lwcircstring_length_2d(const LWCIRCSTRING *circ)
Definition: lwcircstring.c:274
LWTRIANGLE * lwtriangle_clone(const LWTRIANGLE *lwgeom)
Definition: lwtriangle.c:99
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
char lwcollection_same(const LWCOLLECTION *p1, const LWCOLLECTION *p2)
check for same geometry composition
Definition: lwcollection.c:278
double lwline_length_2d(const LWLINE *line)
Definition: lwline.c:526
#define TRIANGLETYPE
Definition: liblwgeom.h:97
uint32_t maxpoints
Definition: liblwgeom.h:374
int lwline_is_trajectory(const LWLINE *geom)
Definition: lwline.c:463
LWGEOM * lwmpoint_as_lwgeom(const LWMPOINT *obj)
Definition: lwgeom.c:286
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:96
void lwtriangle_force_clockwise(LWTRIANGLE *triangle)
Definition: lwtriangle.c:106
void lwgeom_grid_in_place(LWGEOM *geom, const gridspec *grid)
Definition: lwgeom.c:2086
LWPOINTITERATOR * lwpointiterator_create_rw(LWGEOM *g)
Create a new LWPOINTITERATOR over supplied LWGEOM* Supports modification of coordinates during iterat...
Definition: lwiterator.c:253
LWGEOM * lwgeom_simplify(const LWGEOM *igeom, double dist, int preserve_collapsed)
Definition: lwgeom.c:1783
void ptarray_longitude_shift(POINTARRAY *pa)
Longitude shift for a pointarray.
Definition: ptarray.c:1403
int lwcompound_is_closed(const LWCOMPOUND *curve)
Definition: lwcompound.c:35
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:326
double distance2d_pt_pt(const POINT2D *p1, const POINT2D *p2)
Definition: measures.c:2313
#define FLAGS_SET_GEODETIC(flags, value)
Definition: liblwgeom.h:148
LWPOINT * lwpoint_construct_empty(int srid, char hasz, char hasm)
Definition: lwpoint.c:151
LWTRIANGLE * lwgeom_as_lwtriangle(const LWGEOM *lwgeom)
Definition: lwgeom.c:206
double lwtriangle_area(const LWTRIANGLE *triangle)
Find the area of the outer ring.
Definition: lwtriangle.c:178
uint32_t ngeoms
Definition: liblwgeom.h:509
POINTARRAY * point
Definition: liblwgeom.h:413
LWCOLLECTION * lwgeom_subdivide(const LWGEOM *geom, uint32_t maxvertices)
Definition: lwgeom.c:2366
double ptarray_signed_area(const POINTARRAY *pa)
Returns the area in cartesian units.
Definition: ptarray.c:984
LWGEOM * lwgeom_segmentize2d(const LWGEOM *lwgeom, double dist)
Definition: lwgeom.c:753
int32_t srid
Definition: liblwgeom.h:401
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:1025
LWGEOM * lwpsurface_as_lwgeom(const LWPSURFACE *obj)
Definition: lwgeom.c:271
uint32_t nrings
Definition: liblwgeom.h:457
double lwtriangle_perimeter(const LWTRIANGLE *triangle)
Definition: lwtriangle.c:201
char lwgeom_same(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)
geom1 same as geom2 iff
Definition: lwgeom.c:573
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:172
void ptarray_simplify_in_place(POINTARRAY *pa, double epsilon, uint32_t minpts)
Definition: ptarray.c:1563
#define LW_FAILURE
Definition: liblwgeom.h:78
void ptarray_grid_in_place(POINTARRAY *pa, const gridspec *grid)
Definition: ptarray.c:1954
static double mask_double(double d, uint64_t mask)
Definition: lwgeom.c:2420
LWGEOM * lwtin_as_lwgeom(const LWTIN *obj)
Definition: lwgeom.c:266
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
LWGEOM * lwgeom_remove_repeated_points(const LWGEOM *in, double tolerance)
Definition: lwgeom.c:1444
unsigned int uint32_t
Definition: uthash.h:78
void lwgeom_remove_repeated_points_in_place(LWGEOM *geom, double tolerance)
Definition: lwgeom.c:1544
double x
Definition: liblwgeom.h:330
LWCOMPOUND * lwgeom_as_lwcompound(const LWGEOM *lwgeom)
Definition: lwgeom.c:179
int lwpointiterator_has_next(LWPOINTITERATOR *s)
Returns LW_TRUE if there is another point available in the iterator.
Definition: lwiterator.c:204
int p2d_same(const POINT2D *p1, const POINT2D *p2)
Definition: lwalgorithm.c:49
LWCURVEPOLY * lwgeom_as_lwcurvepoly(const LWGEOM *lwgeom)
Definition: lwgeom.c:188
LWCURVEPOLY * lwcurvepoly_construct_from_lwpoly(LWPOLY *lwpoly)
Construct an equivalent curve polygon from a polygon.
Definition: lwcurvepoly.c:53
LWPOLY * lwpoly_construct_envelope(int srid, double x1, double y1, double x2, double y2)
Definition: lwpoly.c:98
LWGEOM * lwgeom_clone_deep(const LWGEOM *lwgeom)
Deep-clone an LWGEOM object.
Definition: lwgeom.c:511
void lwmpoly_free(LWMPOLY *mpoly)
Definition: lwmpoly.c:53
void lwmpoint_free(LWMPOINT *mpt)
Definition: lwmpoint.c:72
double zmax
Definition: liblwgeom.h:299
double ymin
Definition: liblwgeom.h:296
void lwpointiterator_destroy(LWPOINTITERATOR *s)
Free all memory associated with the iterator.
Definition: lwiterator.c:269
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:216
LWGEOM * lwmpoly_as_lwgeom(const LWMPOLY *obj)
Definition: lwgeom.c:276
double lwgeom_area(const LWGEOM *geom)
Definition: lwgeom.c:1798
double lwgeom_perimeter(const LWGEOM *geom)
Definition: lwgeom.c:1821
double lwcompound_length_2d(const LWCOMPOUND *comp)
Definition: lwcompound.c:74
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:2390
double xmin
Definition: liblwgeom.h:294
LWCIRCSTRING * lwcircstring_construct_empty(int srid, char hasz, char hasm)
Definition: lwcircstring.c:79
uint32_t lwpoly_count_vertices(LWPOLY *poly)
Definition: lwpoly.c:418
#define LW_FALSE
Definition: liblwgeom.h:76
LWPOLY * lwpoly_force_dims(const LWPOLY *lwpoly, int hasz, int hasm)
Definition: lwpoly.c:394
LWGEOM * lwgeom_force_3dz(const LWGEOM *geom)
Definition: lwgeom.c:781
uint8_t flags
Definition: liblwgeom.h:371
void ptarray_swap_ordinates(POINTARRAY *pa, LWORD o1, LWORD o2)
Swap ordinate values o1 and o2 on a given POINTARRAY.
Definition: ptarray.c:375
void lwpoly_free(LWPOLY *poly)
Definition: lwpoly.c:175
int lwgeom_has_srid(const LWGEOM *geom)
Return true or false depending on whether a geometry has a valid SRID set.
Definition: lwgeom.c:1377
double lwgeom_perimeter_2d(const LWGEOM *geom)
Definition: lwgeom.c:1843
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:75
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition: lwgeom.c:161
LWGEOM ** geoms
Definition: liblwgeom.h:511
int lwpoly_is_closed(const LWPOLY *poly)
Definition: lwpoly.c:499
double lwcompound_length(const LWCOMPOUND *comp)
Definition: lwcompound.c:69
int lwcircstring_is_closed(const LWCIRCSTRING *curve)
Definition: lwcircstring.c:261
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:187
#define TINTYPE
Definition: liblwgeom.h:98
LWGEOM * lwgeom_intersection(const LWGEOM *geom1, const LWGEOM *geom2)
void lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
Definition: lwgeom.c:1910
LWMLINE * lwgeom_as_lwmline(const LWGEOM *lwgeom)
Definition: lwgeom.c:233
POINTARRAY ** rings
Definition: liblwgeom.h:459
LWCIRCSTRING * lwcircstring_clone(const LWCIRCSTRING *curve)
Definition: lwcircstring.c:124
LWGEOM * lwgeom_as_multi(const LWGEOM *lwgeom)
Create a new LWGEOM of the appropriate MULTI* type.
Definition: lwgeom.c:362
LWGEOM * lwcurvepoly_as_lwgeom(const LWCURVEPOLY *obj)
Definition: lwgeom.c:301
int lwtype_is_collection(uint8_t type)
Return TRUE if the geometry may contain sub-geometries, i.e.
Definition: lwgeom.c:1077
LWPOINT ** geoms
Definition: liblwgeom.h:472
LWGEOM * lwgeom_force_4d(const LWGEOM *geom)
Definition: lwgeom.c:793
double lwpoly_area(const LWPOLY *poly)
Find the area of the outer ring - sum (area of inner rings).
Definition: lwpoly.c:434
LWCURVEPOLY * lwcurvepoly_construct_empty(int srid, char hasz, char hasm)
Definition: lwcurvepoly.c:36
uint8_t MULTITYPE[NUMTYPES]
Look-up for the correct MULTI* type promotion for singleton types.
Definition: lwgeom.c:336
double lwcurvepoly_perimeter_2d(const LWCURVEPOLY *poly)
Definition: lwcurvepoly.c:159
LWGEOM * lwgeom_clone(const LWGEOM *lwgeom)
Clone LWGEOM object.
Definition: lwgeom.c:473
#define FP_TOLERANCE
Floating point comparators.
LWGEOM * lwcircstring_as_lwgeom(const LWCIRCSTRING *obj)
Definition: lwgeom.c:296
#define NUMTYPES
Definition: liblwgeom.h:100
double ymax
Definition: liblwgeom.h:297
enum LWORD_T LWORD
Ordinate names.
double y
Definition: liblwgeom.h:330
int lwpsurface_is_closed(const LWPSURFACE *psurface)
Definition: lwpsurface.c:99
#define FLAGS_GET_Z(flags)
Macros for manipulating the &#39;flags&#39; byte.
Definition: liblwgeom.h:139
int lwcollection_startpoint(const LWCOLLECTION *col, POINT4D *pt)
Definition: lwcollection.c:559
void ptarray_reverse_in_place(POINTARRAY *pa)
Definition: ptarray.c:329
double z
Definition: liblwgeom.h:354
static double distance2d_sqr_pt_pt(const POINT2D *p1, const POINT2D *p2)
Definition: lwinline.h:35
LWCOMPOUND * lwcompound_construct_from_lwline(const LWLINE *lwpoly)
Construct an equivalent compound curve from a linestring.
Definition: lwcompound.c:204
LWCOLLECTION * lwcollection_clone_deep(const LWCOLLECTION *lwgeom)
Deep clone LWCOLLECTION object.
Definition: lwcollection.c:149
int lwpoly_startpoint(const LWPOLY *lwpoly, POINT4D *pt)
Definition: lwpoly.c:524
double lwpoly_perimeter_2d(const LWPOLY *poly)
Compute the sum of polygon rings length (forcing 2d computation).
Definition: lwpoly.c:485
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
Definition: lwgeom.c:215
uint8_t flags
Definition: liblwgeom.h:293
double lwpoly_perimeter(const LWPOLY *poly)
Compute the sum of polygon rings length.
Definition: lwpoly.c:467
void lwtriangle_free(LWTRIANGLE *triangle)
Definition: lwtriangle.c:69
void lwpsurface_free(LWPSURFACE *psurf)
Definition: lwpsurface.c:39
LWCIRCSTRING * lwgeom_as_lwcircstring(const LWGEOM *lwgeom)
Definition: lwgeom.c:170
void lwgeom_set_geodetic(LWGEOM *geom, int value)
Set the FLAGS geodetic bit on geometry an all sub-geometries and pointlists.
Definition: lwgeom.c:936
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition: lwgeom.c:291
LWCOLLECTION * lwcollection_force_dims(const LWCOLLECTION *lwcol, int hasz, int hasm)
Definition: lwcollection.c:485
LWCOLLECTION * lwcollection_segmentize2d(const LWCOLLECTION *coll, double dist)
Definition: lwcollection.c:250
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:89
char lwline_same(const LWLINE *p1, const LWLINE *p2)
Definition: lwline.c:150
double lwgeom_length_2d(const LWGEOM *geom)
Definition: lwgeom.c:1887
LWGEOM * lwgeom_force_dims(const LWGEOM *geom, int hasz, int hasm)
Definition: lwgeom.c:799
static double pivot(double *left, double *right)
Definition: rt_statistics.c:40
int ptarray_startpoint(const POINTARRAY *pa, POINT4D *pt)
Definition: ptarray.c:1939
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
Definition: lwgeom.c:775
#define WKT_EXTENDED
Definition: liblwgeom.h:2038
LWPOLY * lwpoly_from_lwlines(const LWLINE *shell, uint32_t nholes, const LWLINE **holes)
Definition: lwpoly.c:360
#define FLAGS_SET_BBOX(flags, value)
Definition: liblwgeom.h:147
int lwpoint_inside_circle(const LWPOINT *p, double cx, double cy, double rad)
Definition: lwgeom.c:644
double lwcurvepoly_perimeter(const LWCURVEPOLY *poly)
Definition: lwcurvepoly.c:147
LWLINE * lwline_force_dims(const LWLINE *lwline, int hasz, int hasm)
Definition: lwline.c:492
LWGEOM * lwgeom_force_sfs(LWGEOM *geom, int version)
Definition: lwgeom.c:829
int lwgeom_is_collection(const LWGEOM *geom)
Determine whether a LWGEOM can contain sub-geometries or not.
Definition: lwgeom.c:1069
double lwline_length(const LWLINE *line)
Definition: lwline.c:519
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:1271
#define MULTISURFACETYPE
Definition: liblwgeom.h:95
double mmin
Definition: liblwgeom.h:300
int lwline_is_closed(const LWLINE *line)
Definition: lwline.c:454
double zmin
Definition: liblwgeom.h:298
char * lwgeom_to_ewkt(const LWGEOM *lwgeom)
Return an alloced string.
Definition: lwgeom.c:547
LWMPOLY * lwgeom_as_lwmpoly(const LWGEOM *lwgeom)
Definition: lwgeom.c:242
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition: lwgeom.c:914
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:84
LWPOLY * lwpoly_construct_empty(int srid, char hasz, char hasm)
Definition: lwpoly.c:161
LWGEOM * lwmline_as_lwgeom(const LWMLINE *obj)
Definition: lwgeom.c:281
void lwgeom_add_bbox(LWGEOM *lwgeom)
Ensure there&#39;s a box in the LWGEOM.
Definition: lwgeom.c:677
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:140
char lwcircstring_same(const LWCIRCSTRING *p1, const LWCIRCSTRING *p2)
Definition: lwcircstring.c:131
static double trim_preserve_decimal_digits(double d, int32_t decimal_digits)
Definition: lwgeom.c:2429
int lwgeom_needs_bbox(const LWGEOM *geom)
Check whether or not a lwgeom is big enough to warrant a bounding box.
Definition: lwgeom.c:1181
void lwgeom_simplify_in_place(LWGEOM *geom, double epsilon, int preserve_collapsed)
Definition: lwgeom.c:1689
uint8_t type
Definition: liblwgeom.h:398
type
Definition: ovdump.py:41
LWCOLLECTION * lwcollection_clone(const LWCOLLECTION *lwgeom)
Clone LWCOLLECTION object.
Definition: lwcollection.c:123
double mmax
Definition: liblwgeom.h:301
void lwcollection_free(LWCOLLECTION *col)
Definition: lwcollection.c:356
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:321
uint32_t nrings
Definition: liblwgeom.h:535
void ptarray_remove_repeated_points_in_place(POINTARRAY *pa, double tolerance, uint32_t min_points)
Definition: ptarray.c:1440
LWGEOM * lwgeom_construct_empty(uint8_t type, int srid, char hasz, char hasm)
Definition: lwgeom.c:2026
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
int lwgeom_is_clockwise(LWGEOM *lwgeom)
Check clockwise orientation on LWGEOM polygons.
Definition: lwgeom.c:65
GBOX * gbox_clone(const GBOX *gbox)
Definition: g_box.c:52
LWTIN * lwgeom_as_lwtin(const LWGEOM *lwgeom)
Definition: lwgeom.c:259
void lwgeom_set_srid(LWGEOM *geom, int32_t srid)
Definition: lwgeom.c:1520
int value
Definition: genraster.py:61
int lwtriangle_is_clockwise(LWTRIANGLE *triangle)
Definition: lwtriangle.c:113
#define CIRCSTRINGTYPE
Definition: liblwgeom.h:91
void * lwalloc(size_t size)
Definition: lwutil.c:227
LWGEOM * lwtriangle_as_lwgeom(const LWTRIANGLE *obj)
Definition: lwgeom.c:316
void lwgeom_free(LWGEOM *lwgeom)
Definition: lwgeom.c:1128
double y
Definition: liblwgeom.h:354
#define MULTILINETYPE
Definition: liblwgeom.h:88
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int srid, char hasz, char hasm)
Definition: lwcollection.c:94
LWPOLY * lwpoly_clone(const LWPOLY *lwgeom)
Definition: lwpoly.c:213
uint32_t lwtype_get_collectiontype(uint8_t type)
Given an lwtype number, what homogeneous collection can hold it?
Definition: lwgeom.c:1104
LWLINE * lwline_clone_deep(const LWLINE *lwgeom)
Definition: lwline.c:118
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
#define FLAGS_NDIMS(flags)
Definition: liblwgeom.h:151
unsigned char uint8_t
Definition: uthash.h:79
double lwcurvepoly_area(const LWCURVEPOLY *curvepoly)
This should be rewritten to make use of the curve itself.
Definition: lwcurvepoly.c:133
int gbox_same(const GBOX *g1, const GBOX *g2)
Check if 2 given Gbox are the same.
Definition: g_box.c:171
LWGEOM * lwcompound_as_lwgeom(const LWCOMPOUND *obj)
Definition: lwgeom.c:306
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
Definition: lwcollection.c:187
void lwgeom_release(LWGEOM *lwgeom)
Free the containing LWGEOM and the associated BOX.
Definition: lwgeom.c:450
int lwpointiterator_peek(LWPOINTITERATOR *s, POINT4D *p)
Attempts to assigns the next point in the iterator to p.
Definition: lwiterator.c:195
LWGEOM * lwgeom_as_curve(const LWGEOM *lwgeom)
Create a new LWGEOM of the appropriate CURVE* type.
Definition: lwgeom.c:402
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
uint32_t lwgeom_count_rings(const LWGEOM *geom)
Count rings in an LWGEOM.
Definition: lwgeom.c:1329
static uint8_t bits_for_precision(int32_t significant_digits)
Definition: lwgeom.c:2403
int lwpoly_is_clockwise(LWPOLY *poly)
Definition: lwpoly.c:288
uint8_t type
Definition: liblwgeom.h:492
#define COLLECTIONTYPE
Definition: liblwgeom.h:90
char lwpoly_same(const LWPOLY *p1, const LWPOLY *p2)
Definition: lwpoly.c:339
void ptarray_affine(POINTARRAY *pa, const AFFINE *affine)
Affine transform a pointarray.
Definition: ptarray.c:1734
static int lwcollection_dimensionality(const LWCOLLECTION *col)
Definition: lwgeom.c:1386
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
POINTARRAY * points
Definition: liblwgeom.h:424
int lwgeom_calculate_gbox_cartesian(const LWGEOM *lwgeom, GBOX *gbox)
Calculate the 2-4D bounding box of a geometry.
Definition: g_box.c:678
int lwgeom_dimensionality(const LWGEOM *geom)
Return the dimensionality (relating to point/line/poly) of an lwgeom.
Definition: lwgeom.c:1399
Snap to grid.
uint32_t npoints
Definition: liblwgeom.h:373