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