PostGIS  2.2.7dev-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  * Copyright (C) 2001-2006 Refractions Research Inc.
7  *
8  * This is free software; you can redistribute and/or modify it under
9  * the terms of the GNU General Public Licence. See the COPYING file.
10  *
11  **********************************************************************/
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <stdarg.h>
16 
17 #include "liblwgeom_internal.h"
18 #include "lwgeom_log.h"
19 
20 
22 void
24 {
25  LWCOLLECTION *coll;
26  int i;
27 
28  switch (lwgeom->type)
29  {
30  case POLYGONTYPE:
31  lwpoly_force_clockwise((LWPOLY *)lwgeom);
32  return;
33 
34  case TRIANGLETYPE:
36  return;
37 
38  /* Not handle POLYHEDRALSURFACE and TIN
39  as they are supposed to be well oriented */
40  case MULTIPOLYGONTYPE:
41  case COLLECTIONTYPE:
42  coll = (LWCOLLECTION *)lwgeom;
43  for (i=0; i<coll->ngeoms; i++)
44  lwgeom_force_clockwise(coll->geoms[i]);
45  return;
46  }
47 }
48 
50 void
52 {
53  int i;
54  LWCOLLECTION *col;
55 
56  switch (lwgeom->type)
57  {
58  case LINETYPE:
59  lwline_reverse((LWLINE *)lwgeom);
60  return;
61  case POLYGONTYPE:
62  lwpoly_reverse((LWPOLY *)lwgeom);
63  return;
64  case TRIANGLETYPE:
65  lwtriangle_reverse((LWTRIANGLE *)lwgeom);
66  return;
67  case MULTILINETYPE:
68  case MULTIPOLYGONTYPE:
70  case TINTYPE:
71  case COLLECTIONTYPE:
72  col = (LWCOLLECTION *)lwgeom;
73  for (i=0; i<col->ngeoms; i++)
74  lwgeom_reverse(col->geoms[i]);
75  return;
76  }
77 }
78 
79 LWPOINT *
80 lwgeom_as_lwpoint(const LWGEOM *lwgeom)
81 {
82  if ( lwgeom == NULL ) return NULL;
83  if ( lwgeom->type == POINTTYPE )
84  return (LWPOINT *)lwgeom;
85  else return NULL;
86 }
87 
88 LWLINE *
89 lwgeom_as_lwline(const LWGEOM *lwgeom)
90 {
91  if ( lwgeom == NULL ) return NULL;
92  if ( lwgeom->type == LINETYPE )
93  return (LWLINE *)lwgeom;
94  else return NULL;
95 }
96 
99 {
100  if ( lwgeom == NULL ) return NULL;
101  if ( lwgeom->type == CIRCSTRINGTYPE )
102  return (LWCIRCSTRING *)lwgeom;
103  else return NULL;
104 }
105 
106 LWCOMPOUND *
108 {
109  if ( lwgeom == NULL ) return NULL;
110  if ( lwgeom->type == COMPOUNDTYPE )
111  return (LWCOMPOUND *)lwgeom;
112  else return NULL;
113 }
114 
115 LWCURVEPOLY *
117 {
118  if ( lwgeom == NULL ) return NULL;
119  if ( lwgeom->type == CURVEPOLYTYPE )
120  return (LWCURVEPOLY *)lwgeom;
121  else return NULL;
122 }
123 
124 LWPOLY *
125 lwgeom_as_lwpoly(const LWGEOM *lwgeom)
126 {
127  if ( lwgeom == NULL ) return NULL;
128  if ( lwgeom->type == POLYGONTYPE )
129  return (LWPOLY *)lwgeom;
130  else return NULL;
131 }
132 
133 LWTRIANGLE *
135 {
136  if ( lwgeom == NULL ) return NULL;
137  if ( lwgeom->type == TRIANGLETYPE )
138  return (LWTRIANGLE *)lwgeom;
139  else return NULL;
140 }
141 
142 LWCOLLECTION *
144 {
145  if ( lwgeom == NULL ) return NULL;
146  if ( lwgeom_is_collection(lwgeom) )
147  return (LWCOLLECTION*)lwgeom;
148  else return NULL;
149 }
150 
151 LWMPOINT *
153 {
154  if ( lwgeom == NULL ) return NULL;
155  if ( lwgeom->type == MULTIPOINTTYPE )
156  return (LWMPOINT *)lwgeom;
157  else return NULL;
158 }
159 
160 LWMLINE *
161 lwgeom_as_lwmline(const LWGEOM *lwgeom)
162 {
163  if ( lwgeom == NULL ) return NULL;
164  if ( lwgeom->type == MULTILINETYPE )
165  return (LWMLINE *)lwgeom;
166  else return NULL;
167 }
168 
169 LWMPOLY *
170 lwgeom_as_lwmpoly(const LWGEOM *lwgeom)
171 {
172  if ( lwgeom == NULL ) return NULL;
173  if ( lwgeom->type == MULTIPOLYGONTYPE )
174  return (LWMPOLY *)lwgeom;
175  else return NULL;
176 }
177 
178 LWPSURFACE *
180 {
181  if ( lwgeom->type == POLYHEDRALSURFACETYPE )
182  return (LWPSURFACE *)lwgeom;
183  else return NULL;
184 }
185 
186 LWTIN *
187 lwgeom_as_lwtin(const LWGEOM *lwgeom)
188 {
189  if ( lwgeom->type == TINTYPE )
190  return (LWTIN *)lwgeom;
191  else return NULL;
192 }
193 
195 {
196  return (LWGEOM *)obj;
197 }
198 
200 {
201  return (LWGEOM *)obj;
202 }
203 
205 {
206  if ( obj == NULL ) return NULL;
207  return (LWGEOM *)obj;
208 }
210 {
211  if ( obj == NULL ) return NULL;
212  return (LWGEOM *)obj;
213 }
215 {
216  if ( obj == NULL ) return NULL;
217  return (LWGEOM *)obj;
218 }
220 {
221  if ( obj == NULL ) return NULL;
222  return (LWGEOM *)obj;
223 }
225 {
226  if ( obj == NULL ) return NULL;
227  return (LWGEOM *)obj;
228 }
230 {
231  if ( obj == NULL ) return NULL;
232  return (LWGEOM *)obj;
233 }
235 {
236  if ( obj == NULL ) return NULL;
237  return (LWGEOM *)obj;
238 }
240 {
241  if ( obj == NULL ) return NULL;
242  return (LWGEOM *)obj;
243 }
245 {
246  if ( obj == NULL ) return NULL;
247  return (LWGEOM *)obj;
248 }
250 {
251  if ( obj == NULL ) return NULL;
252  return (LWGEOM *)obj;
253 }
255 {
256  if ( obj == NULL ) return NULL;
257  return (LWGEOM *)obj;
258 }
259 
260 
264 uint8_t MULTITYPE[NUMTYPES] =
265 {
266  0,
267  MULTIPOINTTYPE, /* 1 */
268  MULTILINETYPE, /* 2 */
269  MULTIPOLYGONTYPE, /* 3 */
270  0,0,0,0,
271  MULTICURVETYPE, /* 8 */
272  MULTICURVETYPE, /* 9 */
273  MULTISURFACETYPE, /* 10 */
274  POLYHEDRALSURFACETYPE, /* 11 */
275  0, 0,
276  TINTYPE, /* 14 */
277  0
278 };
279 
283 LWGEOM *
284 lwgeom_as_multi(const LWGEOM *lwgeom)
285 {
286  LWGEOM **ogeoms;
287  LWGEOM *ogeom = NULL;
288  GBOX *box = NULL;
289  int type;
290 
291  type = lwgeom->type;
292 
293  if ( ! MULTITYPE[type] ) return lwgeom_clone(lwgeom);
294 
295  if( lwgeom_is_empty(lwgeom) )
296  {
298  MULTITYPE[type],
299  lwgeom->srid,
300  FLAGS_GET_Z(lwgeom->flags),
301  FLAGS_GET_M(lwgeom->flags)
302  );
303  }
304  else
305  {
306  ogeoms = lwalloc(sizeof(LWGEOM*));
307  ogeoms[0] = lwgeom_clone(lwgeom);
308 
309  /* Sub-geometries are not allowed to have bboxes or SRIDs, move the bbox to the collection */
310  box = ogeoms[0]->bbox;
311  ogeoms[0]->bbox = NULL;
312  ogeoms[0]->srid = SRID_UNKNOWN;
313 
314  ogeom = (LWGEOM *)lwcollection_construct(MULTITYPE[type], lwgeom->srid, box, 1, ogeoms);
315  }
316 
317  return ogeom;
318 }
319 
323 LWGEOM *
324 lwgeom_as_curve(const LWGEOM *lwgeom)
325 {
326  LWGEOM *ogeom;
327  int type = lwgeom->type;
328  /*
329  int hasz = FLAGS_GET_Z(lwgeom->flags);
330  int hasm = FLAGS_GET_M(lwgeom->flags);
331  int srid = lwgeom->srid;
332  */
333 
334  switch(type)
335  {
336  case LINETYPE:
337  /* turn to COMPOUNDCURVE */
338  ogeom = (LWGEOM*)lwcompound_construct_from_lwline((LWLINE*)lwgeom);
339  break;
340  case POLYGONTYPE:
342  break;
343  case MULTILINETYPE:
344  /* turn to MULTICURVE */
345  ogeom = lwgeom_clone(lwgeom);
346  ogeom->type = MULTICURVETYPE;
347  break;
348  case MULTIPOLYGONTYPE:
349  /* turn to MULTISURFACE */
350  ogeom = lwgeom_clone(lwgeom);
351  ogeom->type = MULTISURFACETYPE;
352  break;
353  case COLLECTIONTYPE:
354  default:
355  ogeom = lwgeom_clone(lwgeom);
356  break;
357  }
358 
359  /* TODO: copy bbox from input geom ? */
360 
361  return ogeom;
362 }
363 
364 
371 void
373 {
374  if ( ! lwgeom )
375  lwerror("lwgeom_release: someone called on 0x0");
376 
377  LWDEBUGF(3, "releasing type %s", lwtype_name(lwgeom->type));
378 
379  /* Drop bounding box (always a copy) */
380  if ( lwgeom->bbox )
381  {
382  LWDEBUGF(3, "lwgeom_release: releasing bbox. %p", lwgeom->bbox);
383  lwfree(lwgeom->bbox);
384  }
385  lwfree(lwgeom);
386 
387 }
388 
389 
390 /* @brief Clone LWGEOM object. Serialized point lists are not copied.
391  *
392  * @see ptarray_clone
393  */
394 LWGEOM *
395 lwgeom_clone(const LWGEOM *lwgeom)
396 {
397  LWDEBUGF(2, "lwgeom_clone called with %p, %s",
398  lwgeom, lwtype_name(lwgeom->type));
399 
400  switch (lwgeom->type)
401  {
402  case POINTTYPE:
403  return (LWGEOM *)lwpoint_clone((LWPOINT *)lwgeom);
404  case LINETYPE:
405  return (LWGEOM *)lwline_clone((LWLINE *)lwgeom);
406  case CIRCSTRINGTYPE:
407  return (LWGEOM *)lwcircstring_clone((LWCIRCSTRING *)lwgeom);
408  case POLYGONTYPE:
409  return (LWGEOM *)lwpoly_clone((LWPOLY *)lwgeom);
410  case TRIANGLETYPE:
411  return (LWGEOM *)lwtriangle_clone((LWTRIANGLE *)lwgeom);
412  case COMPOUNDTYPE:
413  case CURVEPOLYTYPE:
414  case MULTICURVETYPE:
415  case MULTISURFACETYPE:
416  case MULTIPOINTTYPE:
417  case MULTILINETYPE:
418  case MULTIPOLYGONTYPE:
420  case TINTYPE:
421  case COLLECTIONTYPE:
422  return (LWGEOM *)lwcollection_clone((LWCOLLECTION *)lwgeom);
423  default:
424  lwerror("lwgeom_clone: Unknown geometry type: %s", lwtype_name(lwgeom->type));
425  return NULL;
426  }
427 }
428 
432 LWGEOM *
433 lwgeom_clone_deep(const LWGEOM *lwgeom)
434 {
435  LWDEBUGF(2, "lwgeom_clone called with %p, %s",
436  lwgeom, lwtype_name(lwgeom->type));
437 
438  switch (lwgeom->type)
439  {
440  case POINTTYPE:
441  case LINETYPE:
442  case CIRCSTRINGTYPE:
443  case TRIANGLETYPE:
444  return (LWGEOM *)lwline_clone_deep((LWLINE *)lwgeom);
445  case POLYGONTYPE:
446  return (LWGEOM *)lwpoly_clone_deep((LWPOLY *)lwgeom);
447  case COMPOUNDTYPE:
448  case CURVEPOLYTYPE:
449  case MULTICURVETYPE:
450  case MULTISURFACETYPE:
451  case MULTIPOINTTYPE:
452  case MULTILINETYPE:
453  case MULTIPOLYGONTYPE:
455  case TINTYPE:
456  case COLLECTIONTYPE:
457  return (LWGEOM *)lwcollection_clone_deep((LWCOLLECTION *)lwgeom);
458  default:
459  lwerror("lwgeom_clone_deep: Unknown geometry type: %s", lwtype_name(lwgeom->type));
460  return NULL;
461  }
462 }
463 
464 
468 char*
469 lwgeom_to_ewkt(const LWGEOM *lwgeom)
470 {
471  char* wkt = NULL;
472  size_t wkt_size = 0;
473 
474  wkt = lwgeom_to_wkt(lwgeom, WKT_EXTENDED, 12, &wkt_size);
475 
476  if ( ! wkt )
477  {
478  lwerror("Error writing geom %p to WKT", lwgeom);
479  }
480 
481  return wkt;
482 }
483 
494 char
495 lwgeom_same(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)
496 {
497  LWDEBUGF(2, "lwgeom_same(%s, %s) called",
498  lwtype_name(lwgeom1->type),
499  lwtype_name(lwgeom2->type));
500 
501  if ( lwgeom1->type != lwgeom2->type )
502  {
503  LWDEBUG(3, " type differ");
504 
505  return LW_FALSE;
506  }
507 
508  if ( FLAGS_GET_ZM(lwgeom1->flags) != FLAGS_GET_ZM(lwgeom2->flags) )
509  {
510  LWDEBUG(3, " ZM flags differ");
511 
512  return LW_FALSE;
513  }
514 
515  /* Check boxes if both already computed */
516  if ( lwgeom1->bbox && lwgeom2->bbox )
517  {
518  /*lwnotice("bbox1:%p, bbox2:%p", lwgeom1->bbox, lwgeom2->bbox);*/
519  if ( ! gbox_same(lwgeom1->bbox, lwgeom2->bbox) )
520  {
521  LWDEBUG(3, " bounding boxes differ");
522 
523  return LW_FALSE;
524  }
525  }
526 
527  /* geoms have same type, invoke type-specific function */
528  switch (lwgeom1->type)
529  {
530  case POINTTYPE:
531  return lwpoint_same((LWPOINT *)lwgeom1,
532  (LWPOINT *)lwgeom2);
533  case LINETYPE:
534  return lwline_same((LWLINE *)lwgeom1,
535  (LWLINE *)lwgeom2);
536  case POLYGONTYPE:
537  return lwpoly_same((LWPOLY *)lwgeom1,
538  (LWPOLY *)lwgeom2);
539  case TRIANGLETYPE:
540  return lwtriangle_same((LWTRIANGLE *)lwgeom1,
541  (LWTRIANGLE *)lwgeom2);
542  case CIRCSTRINGTYPE:
543  return lwcircstring_same((LWCIRCSTRING *)lwgeom1,
544  (LWCIRCSTRING *)lwgeom2);
545  case MULTIPOINTTYPE:
546  case MULTILINETYPE:
547  case MULTIPOLYGONTYPE:
548  case MULTICURVETYPE:
549  case MULTISURFACETYPE:
550  case COMPOUNDTYPE:
551  case CURVEPOLYTYPE:
553  case TINTYPE:
554  case COLLECTIONTYPE:
555  return lwcollection_same((LWCOLLECTION *)lwgeom1,
556  (LWCOLLECTION *)lwgeom2);
557  default:
558  lwerror("lwgeom_same: unsupported geometry type: %s",
559  lwtype_name(lwgeom1->type));
560  return LW_FALSE;
561  }
562 
563 }
564 
565 int
566 lwpoint_inside_circle(const LWPOINT *p, double cx, double cy, double rad)
567 {
568  const POINT2D *pt;
569  POINT2D center;
570 
571  if ( ! p || ! p->point )
572  return LW_FALSE;
573 
574  pt = getPoint2d_cp(p->point, 0);
575 
576  center.x = cx;
577  center.y = cy;
578 
579  if ( distance2d_pt_pt(pt, &center) < rad )
580  return LW_TRUE;
581 
582  return LW_FALSE;
583 }
584 
585 void
587 {
588  if ( lwgeom->bbox ) lwfree(lwgeom->bbox);
589  lwgeom->bbox = NULL;
590  FLAGS_SET_BBOX(lwgeom->flags, 0);
591 }
592 
598 void
600 {
601  /* an empty LWGEOM has no bbox */
602  if ( lwgeom_is_empty(lwgeom) ) return;
603 
604  if ( lwgeom->bbox ) return;
605  FLAGS_SET_BBOX(lwgeom->flags, 1);
606  lwgeom->bbox = gbox_new(lwgeom->flags);
607  lwgeom_calculate_gbox(lwgeom, lwgeom->bbox);
608 }
609 
610 void
612 {
613  if ( lwgeom_is_empty(lwgeom) ) return;
614 
615  FLAGS_SET_BBOX(lwgeom->flags, 1);
616 
617  if ( ! ( gbox || lwgeom->bbox ) )
618  {
619  lwgeom->bbox = gbox_new(lwgeom->flags);
620  lwgeom_calculate_gbox(lwgeom, lwgeom->bbox);
621  }
622  else if ( gbox && ! lwgeom->bbox )
623  {
624  lwgeom->bbox = gbox_clone(gbox);
625  }
626 
627  if ( lwgeom_is_collection(lwgeom) )
628  {
629  int i;
630  LWCOLLECTION *lwcol = (LWCOLLECTION*)lwgeom;
631 
632  for ( i = 0; i < lwcol->ngeoms; i++ )
633  {
634  lwgeom_add_bbox_deep(lwcol->geoms[i], lwgeom->bbox);
635  }
636  }
637 }
638 
639 const GBOX *
641 {
642  /* add it if not already there */
643  lwgeom_add_bbox((LWGEOM *)lwg);
644  return lwg->bbox;
645 }
646 
647 
652 int lwgeom_calculate_gbox(const LWGEOM *lwgeom, GBOX *gbox)
653 {
654  gbox->flags = lwgeom->flags;
655  if( FLAGS_GET_GEODETIC(lwgeom->flags) )
656  return lwgeom_calculate_gbox_geodetic(lwgeom, gbox);
657  else
658  return lwgeom_calculate_gbox_cartesian(lwgeom, gbox);
659 }
660 
661 void
663 {
664  lwgeom->srid = SRID_UNKNOWN; /* TODO: To be changed to SRID_UNKNOWN */
665 }
666 
667 LWGEOM *
668 lwgeom_segmentize2d(LWGEOM *lwgeom, double dist)
669 {
670  switch (lwgeom->type)
671  {
672  case LINETYPE:
673  return (LWGEOM *)lwline_segmentize2d((LWLINE *)lwgeom,
674  dist);
675  case POLYGONTYPE:
676  return (LWGEOM *)lwpoly_segmentize2d((LWPOLY *)lwgeom,
677  dist);
678  case MULTILINETYPE:
679  case MULTIPOLYGONTYPE:
680  case COLLECTIONTYPE:
682  (LWCOLLECTION *)lwgeom, dist);
683 
684  default:
685  return lwgeom_clone(lwgeom);
686  }
687 }
688 
689 LWGEOM*
691 {
692  return lwgeom_force_dims(geom, 0, 0);
693 }
694 
695 LWGEOM*
697 {
698  return lwgeom_force_dims(geom, 1, 0);
699 }
700 
701 LWGEOM*
703 {
704  return lwgeom_force_dims(geom, 0, 1);
705 }
706 
707 LWGEOM*
709 {
710  return lwgeom_force_dims(geom, 1, 1);
711 }
712 
713 LWGEOM*
714 lwgeom_force_dims(const LWGEOM *geom, int hasz, int hasm)
715 {
716  switch(geom->type)
717  {
718  case POINTTYPE:
719  return lwpoint_as_lwgeom(lwpoint_force_dims((LWPOINT*)geom, hasz, hasm));
720  case CIRCSTRINGTYPE:
721  case LINETYPE:
722  case TRIANGLETYPE:
723  return lwline_as_lwgeom(lwline_force_dims((LWLINE*)geom, hasz, hasm));
724  case POLYGONTYPE:
725  return lwpoly_as_lwgeom(lwpoly_force_dims((LWPOLY*)geom, hasz, hasm));
726  case COMPOUNDTYPE:
727  case CURVEPOLYTYPE:
728  case MULTICURVETYPE:
729  case MULTISURFACETYPE:
730  case MULTIPOINTTYPE:
731  case MULTILINETYPE:
732  case MULTIPOLYGONTYPE:
734  case TINTYPE:
735  case COLLECTIONTYPE:
736  return lwcollection_as_lwgeom(lwcollection_force_dims((LWCOLLECTION*)geom, hasz, hasm));
737  default:
738  lwerror("lwgeom_force_2d: unsupported geom type: %s", lwtype_name(geom->type));
739  return NULL;
740  }
741 }
742 
743 LWGEOM*
744 lwgeom_force_sfs(LWGEOM *geom, int version)
745 {
746  LWCOLLECTION *col;
747  int i;
748  LWGEOM *g;
749 
750  /* SFS 1.2 version */
751  if (version == 120)
752  {
753  switch(geom->type)
754  {
755  /* SQL/MM types */
756  case CIRCSTRINGTYPE:
757  case COMPOUNDTYPE:
758  case CURVEPOLYTYPE:
759  case MULTICURVETYPE:
760  case MULTISURFACETYPE:
761  return lwgeom_stroke(geom, 32);
762 
763  case COLLECTIONTYPE:
764  col = (LWCOLLECTION*)geom;
765  for ( i = 0; i < col->ngeoms; i++ )
766  col->geoms[i] = lwgeom_force_sfs((LWGEOM*)col->geoms[i], version);
767 
768  return lwcollection_as_lwgeom((LWCOLLECTION*)geom);
769 
770  default:
771  return (LWGEOM *)geom;
772  }
773  }
774 
775 
776  /* SFS 1.1 version */
777  switch(geom->type)
778  {
779  /* SQL/MM types */
780  case CIRCSTRINGTYPE:
781  case COMPOUNDTYPE:
782  case CURVEPOLYTYPE:
783  case MULTICURVETYPE:
784  case MULTISURFACETYPE:
785  return lwgeom_stroke(geom, 32);
786 
787  /* SFS 1.2 types */
788  case TRIANGLETYPE:
789  g = lwpoly_as_lwgeom(lwpoly_from_lwlines((LWLINE*)geom, 0, NULL));
790  lwgeom_free(geom);
791  return g;
792 
793  case TINTYPE:
794  col = (LWCOLLECTION*) geom;
795  for ( i = 0; i < col->ngeoms; i++ )
796  {
797  g = lwpoly_as_lwgeom(lwpoly_from_lwlines((LWLINE*)col->geoms[i], 0, NULL));
798  lwgeom_free(col->geoms[i]);
799  col->geoms[i] = g;
800  }
801  col->type = COLLECTIONTYPE;
802  return lwmpoly_as_lwgeom((LWMPOLY*)geom);
803 
805  geom->type = COLLECTIONTYPE;
806  return (LWGEOM *)geom;
807 
808  /* Collection */
809  case COLLECTIONTYPE:
810  col = (LWCOLLECTION*)geom;
811  for ( i = 0; i < col->ngeoms; i++ )
812  col->geoms[i] = lwgeom_force_sfs((LWGEOM*)col->geoms[i], version);
813 
814  return lwcollection_as_lwgeom((LWCOLLECTION*)geom);
815 
816  default:
817  return (LWGEOM *)geom;
818  }
819 }
820 
821 int32_t
823 {
824  if ( ! geom ) return SRID_UNKNOWN;
825  return geom->srid;
826 }
827 
828 uint32_t
830 {
831  if ( ! geom ) return 0;
832  return geom->type;
833 }
834 
835 int
836 lwgeom_has_z(const LWGEOM *geom)
837 {
838  if ( ! geom ) return LW_FALSE;
839  return FLAGS_GET_Z(geom->flags);
840 }
841 
842 int
843 lwgeom_has_m(const LWGEOM *geom)
844 {
845  if ( ! geom ) return LW_FALSE;
846  return FLAGS_GET_M(geom->flags);
847 }
848 
849 int
850 lwgeom_ndims(const LWGEOM *geom)
851 {
852  if ( ! geom ) return 0;
853  return FLAGS_NDIMS(geom->flags);
854 }
855 
856 
857 void
859 {
860  LWPOINT *pt;
861  LWLINE *ln;
862  LWPOLY *ply;
863  LWCOLLECTION *col;
864  int i;
865 
866  FLAGS_SET_GEODETIC(geom->flags, value);
867  if ( geom->bbox )
868  FLAGS_SET_GEODETIC(geom->bbox->flags, value);
869 
870  switch(geom->type)
871  {
872  case POINTTYPE:
873  pt = (LWPOINT*)geom;
874  if ( pt->point )
875  FLAGS_SET_GEODETIC(pt->point->flags, value);
876  break;
877  case LINETYPE:
878  ln = (LWLINE*)geom;
879  if ( ln->points )
880  FLAGS_SET_GEODETIC(ln->points->flags, value);
881  break;
882  case POLYGONTYPE:
883  ply = (LWPOLY*)geom;
884  for ( i = 0; i < ply->nrings; i++ )
885  FLAGS_SET_GEODETIC(ply->rings[i]->flags, value);
886  break;
887  case MULTIPOINTTYPE:
888  case MULTILINETYPE:
889  case MULTIPOLYGONTYPE:
890  case COLLECTIONTYPE:
891  col = (LWCOLLECTION*)geom;
892  for ( i = 0; i < col->ngeoms; i++ )
893  lwgeom_set_geodetic(col->geoms[i], value);
894  break;
895  default:
896  lwerror("lwgeom_set_geodetic: unsupported geom type: %s", lwtype_name(geom->type));
897  return;
898  }
899 }
900 
901 void
903 {
904  int i;
905  switch (lwgeom->type)
906  {
907  LWPOINT *point;
908  LWLINE *line;
909  LWPOLY *poly;
910  LWTRIANGLE *triangle;
911  LWCOLLECTION *coll;
912 
913  case POINTTYPE:
914  point = (LWPOINT *)lwgeom;
916  return;
917  case LINETYPE:
918  line = (LWLINE *)lwgeom;
920  return;
921  case POLYGONTYPE:
922  poly = (LWPOLY *)lwgeom;
923  for (i=0; i<poly->nrings; i++)
924  ptarray_longitude_shift(poly->rings[i]);
925  return;
926  case TRIANGLETYPE:
927  triangle = (LWTRIANGLE *)lwgeom;
928  ptarray_longitude_shift(triangle->points);
929  return;
930  case MULTIPOINTTYPE:
931  case MULTILINETYPE:
932  case MULTIPOLYGONTYPE:
934  case TINTYPE:
935  case COLLECTIONTYPE:
936  coll = (LWCOLLECTION *)lwgeom;
937  for (i=0; i<coll->ngeoms; i++)
938  lwgeom_longitude_shift(coll->geoms[i]);
939  return;
940  default:
941  lwerror("lwgeom_longitude_shift: unsupported geom type: %s",
942  lwtype_name(lwgeom->type));
943  }
944 }
945 
946 int
948 {
949  int type = geom->type;
950 
951  if( lwgeom_is_empty(geom) )
952  return LW_FALSE;
953 
954  /* Test linear types for closure */
955  switch (type)
956  {
957  case LINETYPE:
958  return lwline_is_closed((LWLINE*)geom);
959  case POLYGONTYPE:
960  return lwpoly_is_closed((LWPOLY*)geom);
961  case CIRCSTRINGTYPE:
962  return lwcircstring_is_closed((LWCIRCSTRING*)geom);
963  case COMPOUNDTYPE:
964  return lwcompound_is_closed((LWCOMPOUND*)geom);
965  case TINTYPE:
966  return lwtin_is_closed((LWTIN*)geom);
968  return lwpsurface_is_closed((LWPSURFACE*)geom);
969  }
970 
971  /* Recurse into collections and see if anything is not closed */
972  if ( lwgeom_is_collection(geom) )
973  {
975  int i;
976  int closed;
977  for ( i = 0; i < col->ngeoms; i++ )
978  {
979  closed = lwgeom_is_closed(col->geoms[i]);
980  if ( ! closed )
981  return LW_FALSE;
982  }
983  return LW_TRUE;
984  }
985 
986  /* All non-linear non-collection types we will call closed */
987  return LW_TRUE;
988 }
989 
990 int
992 {
993  if( ! geom ) return LW_FALSE;
994  return lwtype_is_collection(geom->type);
995 }
996 
998 int
999 lwtype_is_collection(uint8_t type)
1000 {
1001 
1002  switch (type)
1003  {
1004  case MULTIPOINTTYPE:
1005  case MULTILINETYPE:
1006  case MULTIPOLYGONTYPE:
1007  case COLLECTIONTYPE:
1008  case CURVEPOLYTYPE:
1009  case COMPOUNDTYPE:
1010  case MULTICURVETYPE:
1011  case MULTISURFACETYPE:
1012  case POLYHEDRALSURFACETYPE:
1013  case TINTYPE:
1014  return LW_TRUE;
1015  break;
1016 
1017  default:
1018  return LW_FALSE;
1019  }
1020 }
1021 
1025 int
1027 {
1028  switch (type)
1029  {
1030  case POINTTYPE:
1031  return MULTIPOINTTYPE;
1032  case LINETYPE:
1033  return MULTILINETYPE;
1034  case POLYGONTYPE:
1035  return MULTIPOLYGONTYPE;
1036  case CIRCSTRINGTYPE:
1037  return MULTICURVETYPE;
1038  case COMPOUNDTYPE:
1039  return MULTICURVETYPE;
1040  case CURVEPOLYTYPE:
1041  return MULTISURFACETYPE;
1042  case TRIANGLETYPE:
1043  return TINTYPE;
1044  default:
1045  return COLLECTIONTYPE;
1046  }
1047 }
1048 
1049 
1050 void lwgeom_free(LWGEOM *lwgeom)
1051 {
1052 
1053  /* There's nothing here to free... */
1054  if( ! lwgeom ) return;
1055 
1056  LWDEBUGF(5,"freeing a %s",lwtype_name(lwgeom->type));
1057 
1058  switch (lwgeom->type)
1059  {
1060  case POINTTYPE:
1061  lwpoint_free((LWPOINT *)lwgeom);
1062  break;
1063  case LINETYPE:
1064  lwline_free((LWLINE *)lwgeom);
1065  break;
1066  case POLYGONTYPE:
1067  lwpoly_free((LWPOLY *)lwgeom);
1068  break;
1069  case CIRCSTRINGTYPE:
1070  lwcircstring_free((LWCIRCSTRING *)lwgeom);
1071  break;
1072  case TRIANGLETYPE:
1073  lwtriangle_free((LWTRIANGLE *)lwgeom);
1074  break;
1075  case MULTIPOINTTYPE:
1076  lwmpoint_free((LWMPOINT *)lwgeom);
1077  break;
1078  case MULTILINETYPE:
1079  lwmline_free((LWMLINE *)lwgeom);
1080  break;
1081  case MULTIPOLYGONTYPE:
1082  lwmpoly_free((LWMPOLY *)lwgeom);
1083  break;
1084  case POLYHEDRALSURFACETYPE:
1085  lwpsurface_free((LWPSURFACE *)lwgeom);
1086  break;
1087  case TINTYPE:
1088  lwtin_free((LWTIN *)lwgeom);
1089  break;
1090  case CURVEPOLYTYPE:
1091  case COMPOUNDTYPE:
1092  case MULTICURVETYPE:
1093  case MULTISURFACETYPE:
1094  case COLLECTIONTYPE:
1095  lwcollection_free((LWCOLLECTION *)lwgeom);
1096  break;
1097  default:
1098  lwerror("lwgeom_free called with unknown type (%d) %s", lwgeom->type, lwtype_name(lwgeom->type));
1099  }
1100  return;
1101 }
1102 
1103 int lwgeom_needs_bbox(const LWGEOM *geom)
1104 {
1105  assert(geom);
1106  if ( geom->type == POINTTYPE )
1107  {
1108  return LW_FALSE;
1109  }
1110  else if ( geom->type == LINETYPE )
1111  {
1112  if ( lwgeom_count_vertices(geom) <= 2 )
1113  return LW_FALSE;
1114  else
1115  return LW_TRUE;
1116  }
1117  else if ( geom->type == MULTIPOINTTYPE )
1118  {
1119  if ( ((LWCOLLECTION*)geom)->ngeoms == 1 )
1120  return LW_FALSE;
1121  else
1122  return LW_TRUE;
1123  }
1124  else if ( geom->type == MULTILINETYPE )
1125  {
1126  if ( ((LWCOLLECTION*)geom)->ngeoms == 1 && lwgeom_count_vertices(geom) <= 2 )
1127  return LW_FALSE;
1128  else
1129  return LW_TRUE;
1130  }
1131  else
1132  {
1133  return LW_TRUE;
1134  }
1135 }
1136 
1141 {
1142  int result = 0;
1143 
1144  /* Null? Zero. */
1145  if( ! geom ) return 0;
1146 
1147  LWDEBUGF(4, "lwgeom_count_vertices got type %s",
1148  lwtype_name(geom->type));
1149 
1150  /* Empty? Zero. */
1151  if( lwgeom_is_empty(geom) ) return 0;
1152 
1153  switch (geom->type)
1154  {
1155  case POINTTYPE:
1156  result = 1;
1157  break;
1158  case TRIANGLETYPE:
1159  case CIRCSTRINGTYPE:
1160  case LINETYPE:
1161  result = lwline_count_vertices((LWLINE *)geom);
1162  break;
1163  case POLYGONTYPE:
1164  result = lwpoly_count_vertices((LWPOLY *)geom);
1165  break;
1166  case COMPOUNDTYPE:
1167  case CURVEPOLYTYPE:
1168  case MULTICURVETYPE:
1169  case MULTISURFACETYPE:
1170  case MULTIPOINTTYPE:
1171  case MULTILINETYPE:
1172  case MULTIPOLYGONTYPE:
1173  case POLYHEDRALSURFACETYPE:
1174  case TINTYPE:
1175  case COLLECTIONTYPE:
1176  result = lwcollection_count_vertices((LWCOLLECTION *)geom);
1177  break;
1178  default:
1179  lwerror("%s: unsupported input geometry type: %s",
1180  __func__, lwtype_name(geom->type));
1181  break;
1182  }
1183  LWDEBUGF(3, "counted %d vertices", result);
1184  return result;
1185 }
1186 
1192 int lwgeom_dimension(const LWGEOM *geom)
1193 {
1194 
1195  /* Null? Zero. */
1196  if( ! geom ) return -1;
1197 
1198  LWDEBUGF(4, "lwgeom_dimension got type %s",
1199  lwtype_name(geom->type));
1200 
1201  /* Empty? Zero. */
1202  /* if( lwgeom_is_empty(geom) ) return 0; */
1203 
1204  switch (geom->type)
1205  {
1206  case POINTTYPE:
1207  case MULTIPOINTTYPE:
1208  return 0;
1209  case CIRCSTRINGTYPE:
1210  case LINETYPE:
1211  case COMPOUNDTYPE:
1212  case MULTICURVETYPE:
1213  case MULTILINETYPE:
1214  return 1;
1215  case TRIANGLETYPE:
1216  case POLYGONTYPE:
1217  case CURVEPOLYTYPE:
1218  case MULTISURFACETYPE:
1219  case MULTIPOLYGONTYPE:
1220  case TINTYPE:
1221  return 2;
1222  case POLYHEDRALSURFACETYPE:
1223  {
1224  /* A closed polyhedral surface contains a volume. */
1225  int closed = lwpsurface_is_closed((LWPSURFACE*)geom);
1226  return ( closed ? 3 : 2 );
1227  }
1228  case COLLECTIONTYPE:
1229  {
1230  int maxdim = 0, i;
1231  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1232  for( i = 0; i < col->ngeoms; i++ )
1233  {
1234  int dim = lwgeom_dimension(col->geoms[i]);
1235  maxdim = ( dim > maxdim ? dim : maxdim );
1236  }
1237  return maxdim;
1238  }
1239  default:
1240  lwerror("%s: unsupported input geometry type: %s",
1241  __func__, lwtype_name(geom->type));
1242  }
1243  return -1;
1244 }
1245 
1249 int lwgeom_count_rings(const LWGEOM *geom)
1250 {
1251  int result = 0;
1252 
1253  /* Null? Empty? Zero. */
1254  if( ! geom || lwgeom_is_empty(geom) )
1255  return 0;
1256 
1257  switch (geom->type)
1258  {
1259  case POINTTYPE:
1260  case CIRCSTRINGTYPE:
1261  case COMPOUNDTYPE:
1262  case MULTICURVETYPE:
1263  case MULTIPOINTTYPE:
1264  case MULTILINETYPE:
1265  case LINETYPE:
1266  result = 0;
1267  break;
1268  case TRIANGLETYPE:
1269  result = 1;
1270  break;
1271  case POLYGONTYPE:
1272  result = ((LWPOLY *)geom)->nrings;
1273  break;
1274  case CURVEPOLYTYPE:
1275  result = ((LWCURVEPOLY *)geom)->nrings;
1276  break;
1277  case MULTISURFACETYPE:
1278  case MULTIPOLYGONTYPE:
1279  case POLYHEDRALSURFACETYPE:
1280  case TINTYPE:
1281  case COLLECTIONTYPE:
1282  {
1283  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1284  int i = 0;
1285  for( i = 0; i < col->ngeoms; i++ )
1286  result += lwgeom_count_rings(col->geoms[i]);
1287  break;
1288  }
1289  default:
1290  lwerror("lwgeom_count_rings: unsupported input geometry type: %s", lwtype_name(geom->type));
1291  break;
1292  }
1293  LWDEBUGF(3, "counted %d rings", result);
1294  return result;
1295 }
1296 
1297 int lwgeom_is_empty(const LWGEOM *geom)
1298 {
1299  int result = LW_FALSE;
1300  LWDEBUGF(4, "lwgeom_is_empty: got type %s",
1301  lwtype_name(geom->type));
1302 
1303  switch (geom->type)
1304  {
1305  case POINTTYPE:
1306  return lwpoint_is_empty((LWPOINT*)geom);
1307  break;
1308  case LINETYPE:
1309  return lwline_is_empty((LWLINE*)geom);
1310  break;
1311  case CIRCSTRINGTYPE:
1312  return lwcircstring_is_empty((LWCIRCSTRING*)geom);
1313  break;
1314  case POLYGONTYPE:
1315  return lwpoly_is_empty((LWPOLY*)geom);
1316  break;
1317  case TRIANGLETYPE:
1318  return lwtriangle_is_empty((LWTRIANGLE*)geom);
1319  break;
1320  case MULTIPOINTTYPE:
1321  case MULTILINETYPE:
1322  case MULTIPOLYGONTYPE:
1323  case COMPOUNDTYPE:
1324  case CURVEPOLYTYPE:
1325  case MULTICURVETYPE:
1326  case MULTISURFACETYPE:
1327  case POLYHEDRALSURFACETYPE:
1328  case TINTYPE:
1329  case COLLECTIONTYPE:
1330  return lwcollection_is_empty((LWCOLLECTION *)geom);
1331  break;
1332  default:
1333  lwerror("lwgeom_is_empty: unsupported input geometry type: %s",
1334  lwtype_name(geom->type));
1335  break;
1336  }
1337  return result;
1338 }
1339 
1340 int lwgeom_has_srid(const LWGEOM *geom)
1341 {
1342  if ( geom->srid != SRID_UNKNOWN )
1343  return LW_TRUE;
1344 
1345  return LW_FALSE;
1346 }
1347 
1348 
1350 {
1351  int i;
1352  int dimensionality = 0;
1353  for ( i = 0; i < col->ngeoms; i++ )
1354  {
1355  int d = lwgeom_dimensionality(col->geoms[i]);
1356  if ( d > dimensionality )
1357  dimensionality = d;
1358  }
1359  return dimensionality;
1360 }
1361 
1363 {
1364  int dim;
1365 
1366  LWDEBUGF(3, "lwgeom_dimensionality got type %s",
1367  lwtype_name(geom->type));
1368 
1369  switch (geom->type)
1370  {
1371  case POINTTYPE:
1372  case MULTIPOINTTYPE:
1373  return 0;
1374  break;
1375  case LINETYPE:
1376  case CIRCSTRINGTYPE:
1377  case MULTILINETYPE:
1378  case COMPOUNDTYPE:
1379  case MULTICURVETYPE:
1380  return 1;
1381  break;
1382  case POLYGONTYPE:
1383  case TRIANGLETYPE:
1384  case CURVEPOLYTYPE:
1385  case MULTIPOLYGONTYPE:
1386  case MULTISURFACETYPE:
1387  return 2;
1388  break;
1389 
1390  case POLYHEDRALSURFACETYPE:
1391  case TINTYPE:
1392  dim = lwgeom_is_closed(geom)?3:2;
1393  return dim;
1394  break;
1395 
1396  case COLLECTIONTYPE:
1397  return lwcollection_dimensionality((LWCOLLECTION *)geom);
1398  break;
1399  default:
1400  lwerror("lwgeom_dimensionality: unsupported input geometry type: %s",
1401  lwtype_name(geom->type));
1402  break;
1403  }
1404  return 0;
1405 }
1406 
1407 extern LWGEOM* lwgeom_remove_repeated_points(LWGEOM *in, double tolerance)
1408 {
1409  LWDEBUGF(4, "lwgeom_remove_repeated_points got type %s",
1410  lwtype_name(in->type));
1411 
1412  if(lwgeom_is_empty(in))
1413  {
1414  return lwgeom_clone_deep(in);
1415  }
1416 
1417  switch (in->type)
1418  {
1419  case MULTIPOINTTYPE:
1420  return lwmpoint_remove_repeated_points((LWMPOINT*)in, tolerance);
1421  break;
1422  case LINETYPE:
1423  return lwline_remove_repeated_points((LWLINE*)in, tolerance);
1424 
1425  case MULTILINETYPE:
1426  case COLLECTIONTYPE:
1427  case MULTIPOLYGONTYPE:
1428  case POLYHEDRALSURFACETYPE:
1429  return lwcollection_remove_repeated_points((LWCOLLECTION *)in, tolerance);
1430 
1431  case POLYGONTYPE:
1432  return lwpoly_remove_repeated_points((LWPOLY *)in, tolerance);
1433  break;
1434 
1435  case POINTTYPE:
1436  case TRIANGLETYPE:
1437  case TINTYPE:
1438  /* No point is repeated for a single point, or for Triangle or TIN */
1439  return lwgeom_clone_deep(in);
1440 
1441  case CIRCSTRINGTYPE:
1442  case COMPOUNDTYPE:
1443  case MULTICURVETYPE:
1444  case CURVEPOLYTYPE:
1445  case MULTISURFACETYPE:
1446  /* Dunno how to handle these, will return untouched */
1447  return lwgeom_clone_deep(in);
1448 
1449  default:
1450  lwnotice("%s: unsupported geometry type: %s",
1451  __func__, lwtype_name(in->type));
1452  return lwgeom_clone_deep(in);
1453  break;
1454  }
1455  return 0;
1456 }
1457 
1459 {
1461  return in;
1462 }
1463 
1465 {
1466  LWCOLLECTION *col;
1467  LWPOLY *poly;
1468  int i;
1469 
1470 #if PARANOIA_LEVEL > 0
1471  assert(o1 < 4);
1472  assert(o2 < 4);
1473 #endif
1474 
1475  if ( (!in) || lwgeom_is_empty(in) ) return;
1476 
1477  /* TODO: check for lwgeom NOT having the specified dimension ? */
1478 
1479  LWDEBUGF(4, "lwgeom_flip_coordinates, got type: %s",
1480  lwtype_name(in->type));
1481 
1482  switch (in->type)
1483  {
1484  case POINTTYPE:
1485  ptarray_swap_ordinates(lwgeom_as_lwpoint(in)->point, o1, o2);
1486  break;
1487 
1488  case LINETYPE:
1489  ptarray_swap_ordinates(lwgeom_as_lwline(in)->points, o1, o2);
1490  break;
1491 
1492  case CIRCSTRINGTYPE:
1493  ptarray_swap_ordinates(lwgeom_as_lwcircstring(in)->points, o1, o2);
1494  break;
1495 
1496  case POLYGONTYPE:
1497  poly = (LWPOLY *) in;
1498  for (i=0; i<poly->nrings; i++)
1499  {
1500  ptarray_swap_ordinates(poly->rings[i], o1, o2);
1501  }
1502  break;
1503 
1504  case TRIANGLETYPE:
1505  ptarray_swap_ordinates(lwgeom_as_lwtriangle(in)->points, o1, o2);
1506  break;
1507 
1508  case MULTIPOINTTYPE:
1509  case MULTILINETYPE:
1510  case MULTIPOLYGONTYPE:
1511  case COLLECTIONTYPE:
1512  case COMPOUNDTYPE:
1513  case CURVEPOLYTYPE:
1514  case MULTISURFACETYPE:
1515  case MULTICURVETYPE:
1516  case POLYHEDRALSURFACETYPE:
1517  case TINTYPE:
1518  col = (LWCOLLECTION *) in;
1519  for (i=0; i<col->ngeoms; i++)
1520  {
1521  lwgeom_swap_ordinates(col->geoms[i], o1, o2);
1522  }
1523  break;
1524 
1525  default:
1526  lwerror("lwgeom_swap_ordinates: unsupported geometry type: %s",
1527  lwtype_name(in->type));
1528  return;
1529  }
1530 
1531  /* only refresh bbox if X or Y changed */
1532  if ( in->bbox && (o1 < 2 || o2 < 2) )
1533  {
1534  lwgeom_drop_bbox(in);
1535  lwgeom_add_bbox(in);
1536  }
1537 }
1538 
1539 void lwgeom_set_srid(LWGEOM *geom, int32_t srid)
1540 {
1541  int i;
1542 
1543  LWDEBUGF(4,"entered with srid=%d",srid);
1544 
1545  geom->srid = srid;
1546 
1547  if ( lwgeom_is_collection(geom) )
1548  {
1549  /* All the children are set to the same SRID value */
1550  LWCOLLECTION *col = lwgeom_as_lwcollection(geom);
1551  for ( i = 0; i < col->ngeoms; i++ )
1552  {
1553  lwgeom_set_srid(col->geoms[i], srid);
1554  }
1555  }
1556 }
1557 
1558 LWGEOM* lwgeom_simplify(const LWGEOM *igeom, double dist, int preserve_collapsed)
1559 {
1560  switch (igeom->type)
1561  {
1562  case POINTTYPE:
1563  case MULTIPOINTTYPE:
1564  return lwgeom_clone(igeom);
1565  case LINETYPE:
1566  return (LWGEOM*)lwline_simplify((LWLINE*)igeom, dist, preserve_collapsed);
1567  case POLYGONTYPE:
1568  return (LWGEOM*)lwpoly_simplify((LWPOLY*)igeom, dist, preserve_collapsed);
1569  case MULTILINETYPE:
1570  case MULTIPOLYGONTYPE:
1571  case COLLECTIONTYPE:
1572  return (LWGEOM*)lwcollection_simplify((LWCOLLECTION *)igeom, dist, preserve_collapsed);
1573  default:
1574  lwerror("%s: unsupported geometry type: %s", __func__, lwtype_name(igeom->type));
1575  }
1576  return NULL;
1577 }
1578 
1579 double lwgeom_area(const LWGEOM *geom)
1580 {
1581  int type = geom->type;
1582 
1583  if ( type == POLYGONTYPE )
1584  return lwpoly_area((LWPOLY*)geom);
1585  else if ( type == CURVEPOLYTYPE )
1586  return lwcurvepoly_area((LWCURVEPOLY*)geom);
1587  else if (type == TRIANGLETYPE )
1588  return lwtriangle_area((LWTRIANGLE*)geom);
1589  else if ( lwgeom_is_collection(geom) )
1590  {
1591  double area = 0.0;
1592  int i;
1593  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1594  for ( i = 0; i < col->ngeoms; i++ )
1595  area += lwgeom_area(col->geoms[i]);
1596  return area;
1597  }
1598  else
1599  return 0.0;
1600 }
1601 
1602 double lwgeom_perimeter(const LWGEOM *geom)
1603 {
1604  int type = geom->type;
1605  if ( type == POLYGONTYPE )
1606  return lwpoly_perimeter((LWPOLY*)geom);
1607  else if ( type == CURVEPOLYTYPE )
1608  return lwcurvepoly_perimeter((LWCURVEPOLY*)geom);
1609  else if ( type == TRIANGLETYPE )
1610  return lwtriangle_perimeter((LWTRIANGLE*)geom);
1611  else if ( lwgeom_is_collection(geom) )
1612  {
1613  double perimeter = 0.0;
1614  int i;
1615  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1616  for ( i = 0; i < col->ngeoms; i++ )
1617  perimeter += lwgeom_perimeter(col->geoms[i]);
1618  return perimeter;
1619  }
1620  else
1621  return 0.0;
1622 }
1623 
1624 double lwgeom_perimeter_2d(const LWGEOM *geom)
1625 {
1626  int type = geom->type;
1627  if ( type == POLYGONTYPE )
1628  return lwpoly_perimeter_2d((LWPOLY*)geom);
1629  else if ( type == CURVEPOLYTYPE )
1630  return lwcurvepoly_perimeter_2d((LWCURVEPOLY*)geom);
1631  else if ( type == TRIANGLETYPE )
1632  return lwtriangle_perimeter_2d((LWTRIANGLE*)geom);
1633  else if ( lwgeom_is_collection(geom) )
1634  {
1635  double perimeter = 0.0;
1636  int i;
1637  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1638  for ( i = 0; i < col->ngeoms; i++ )
1639  perimeter += lwgeom_perimeter_2d(col->geoms[i]);
1640  return perimeter;
1641  }
1642  else
1643  return 0.0;
1644 }
1645 
1646 double lwgeom_length(const LWGEOM *geom)
1647 {
1648  int type = geom->type;
1649  if ( type == LINETYPE )
1650  return lwline_length((LWLINE*)geom);
1651  else if ( type == CIRCSTRINGTYPE )
1652  return lwcircstring_length((LWCIRCSTRING*)geom);
1653  else if ( type == COMPOUNDTYPE )
1654  return lwcompound_length((LWCOMPOUND*)geom);
1655  else if ( lwgeom_is_collection(geom) )
1656  {
1657  double length = 0.0;
1658  int i;
1659  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1660  for ( i = 0; i < col->ngeoms; i++ )
1661  length += lwgeom_length(col->geoms[i]);
1662  return length;
1663  }
1664  else
1665  return 0.0;
1666 }
1667 
1668 double lwgeom_length_2d(const LWGEOM *geom)
1669 {
1670  int type = geom->type;
1671  if ( type == LINETYPE )
1672  return lwline_length_2d((LWLINE*)geom);
1673  else if ( type == CIRCSTRINGTYPE )
1674  return lwcircstring_length_2d((LWCIRCSTRING*)geom);
1675  else if ( type == COMPOUNDTYPE )
1676  return lwcompound_length_2d((LWCOMPOUND*)geom);
1677  else if ( lwgeom_is_collection(geom) )
1678  {
1679  double length = 0.0;
1680  int i;
1681  LWCOLLECTION *col = (LWCOLLECTION*)geom;
1682  for ( i = 0; i < col->ngeoms; i++ )
1683  length += lwgeom_length_2d(col->geoms[i]);
1684  return length;
1685  }
1686  else
1687  return 0.0;
1688 }
1689 
1690 void
1691 lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
1692 {
1693  int type = geom->type;
1694  int i;
1695 
1696  switch(type)
1697  {
1698  /* Take advantage of fact tht pt/ln/circ/tri have same memory structure */
1699  case POINTTYPE:
1700  case LINETYPE:
1701  case CIRCSTRINGTYPE:
1702  case TRIANGLETYPE:
1703  {
1704  LWLINE *l = (LWLINE*)geom;
1705  ptarray_affine(l->points, affine);
1706  break;
1707  }
1708  case POLYGONTYPE:
1709  {
1710  LWPOLY *p = (LWPOLY*)geom;
1711  for( i = 0; i < p->nrings; i++ )
1712  ptarray_affine(p->rings[i], affine);
1713  break;
1714  }
1715  case CURVEPOLYTYPE:
1716  {
1717  LWCURVEPOLY *c = (LWCURVEPOLY*)geom;
1718  for( i = 0; i < c->nrings; i++ )
1719  lwgeom_affine(c->rings[i], affine);
1720  break;
1721  }
1722  default:
1723  {
1724  if( lwgeom_is_collection(geom) )
1725  {
1726  LWCOLLECTION *c = (LWCOLLECTION*)geom;
1727  for( i = 0; i < c->ngeoms; i++ )
1728  {
1729  lwgeom_affine(c->geoms[i], affine);
1730  }
1731  }
1732  else
1733  {
1734  lwerror("lwgeom_affine: unable to handle type '%s'", lwtype_name(type));
1735  }
1736  }
1737  }
1738 
1739 }
1740 
1741 void
1742 lwgeom_scale(LWGEOM *geom, const POINT4D *factor)
1743 {
1744  int type = geom->type;
1745  int i;
1746 
1747  switch(type)
1748  {
1749  /* Take advantage of fact tht pt/ln/circ/tri have same memory structure */
1750  case POINTTYPE:
1751  case LINETYPE:
1752  case CIRCSTRINGTYPE:
1753  case TRIANGLETYPE:
1754  {
1755  LWLINE *l = (LWLINE*)geom;
1756  ptarray_scale(l->points, factor);
1757  break;
1758  }
1759  case POLYGONTYPE:
1760  {
1761  LWPOLY *p = (LWPOLY*)geom;
1762  for( i = 0; i < p->nrings; i++ )
1763  ptarray_scale(p->rings[i], factor);
1764  break;
1765  }
1766  case CURVEPOLYTYPE:
1767  {
1768  LWCURVEPOLY *c = (LWCURVEPOLY*)geom;
1769  for( i = 0; i < c->nrings; i++ )
1770  lwgeom_scale(c->rings[i], factor);
1771  break;
1772  }
1773  default:
1774  {
1775  if( lwgeom_is_collection(geom) )
1776  {
1777  LWCOLLECTION *c = (LWCOLLECTION*)geom;
1778  for( i = 0; i < c->ngeoms; i++ )
1779  {
1780  lwgeom_scale(c->geoms[i], factor);
1781  }
1782  }
1783  else
1784  {
1785  lwerror("lwgeom_scale: unable to handle type '%s'", lwtype_name(type));
1786  }
1787  }
1788  }
1789 
1790  /* Recompute bbox if needed */
1791 
1792  if ( geom->bbox )
1793  {
1794  /* TODO: expose a gbox_scale function */
1795  geom->bbox->xmin *= factor->x;
1796  geom->bbox->xmax *= factor->x;
1797  geom->bbox->ymin *= factor->y;
1798  geom->bbox->ymax *= factor->y;
1799  geom->bbox->zmin *= factor->z;
1800  geom->bbox->zmax *= factor->z;
1801  geom->bbox->mmin *= factor->m;
1802  geom->bbox->mmax *= factor->m;
1803  }
1804 }
1805 
1806 LWGEOM*
1807 lwgeom_construct_empty(uint8_t type, int srid, char hasz, char hasm)
1808 {
1809  switch(type)
1810  {
1811  case POINTTYPE:
1812  return lwpoint_as_lwgeom(lwpoint_construct_empty(srid, hasz, hasm));
1813  case LINETYPE:
1814  return lwline_as_lwgeom(lwline_construct_empty(srid, hasz, hasm));
1815  case POLYGONTYPE:
1816  return lwpoly_as_lwgeom(lwpoly_construct_empty(srid, hasz, hasm));
1817  case CURVEPOLYTYPE:
1818  return lwcurvepoly_as_lwgeom(lwcurvepoly_construct_empty(srid, hasz, hasm));
1819  case CIRCSTRINGTYPE:
1820  return lwcircstring_as_lwgeom(lwcircstring_construct_empty(srid, hasz, hasm));
1821  case TRIANGLETYPE:
1822  return lwtriangle_as_lwgeom(lwtriangle_construct_empty(srid, hasz, hasm));
1823  case COMPOUNDTYPE:
1824  case MULTIPOINTTYPE:
1825  case MULTILINETYPE:
1826  case MULTIPOLYGONTYPE:
1827  case COLLECTIONTYPE:
1828  return lwcollection_as_lwgeom(lwcollection_construct_empty(type, srid, hasz, hasm));
1829  default:
1830  lwerror("lwgeom_construct_empty: unsupported geometry type: %s",
1831  lwtype_name(type));
1832  return NULL;
1833  }
1834 }
1835 
1836 int
1837 lwgeom_startpoint(const LWGEOM* lwgeom, POINT4D* pt)
1838 {
1839  if ( ! lwgeom )
1840  return LW_FAILURE;
1841 
1842  switch( lwgeom->type )
1843  {
1844  case POINTTYPE:
1845  return ptarray_startpoint(((LWPOINT*)lwgeom)->point, pt);
1846  case TRIANGLETYPE:
1847  case CIRCSTRINGTYPE:
1848  case LINETYPE:
1849  return ptarray_startpoint(((LWLINE*)lwgeom)->points, pt);
1850  case POLYGONTYPE:
1851  return lwpoly_startpoint((LWPOLY*)lwgeom, pt);
1852  case CURVEPOLYTYPE:
1853  case COMPOUNDTYPE:
1854  case MULTIPOINTTYPE:
1855  case MULTILINETYPE:
1856  case MULTIPOLYGONTYPE:
1857  case COLLECTIONTYPE:
1858  return lwcollection_startpoint((LWCOLLECTION*)lwgeom, pt);
1859  default:
1860  lwerror("int: unsupported geometry type: %s",
1861  lwtype_name(lwgeom->type));
1862  return LW_FAILURE;
1863  }
1864 }
1865 
1866 
1867 LWGEOM *
1868 lwgeom_grid(const LWGEOM *lwgeom, const gridspec *grid)
1869 {
1870  switch ( lwgeom->type )
1871  {
1872  case POINTTYPE:
1873  return (LWGEOM *)lwpoint_grid((LWPOINT *)lwgeom, grid);
1874  case LINETYPE:
1875  return (LWGEOM *)lwline_grid((LWLINE *)lwgeom, grid);
1876  case POLYGONTYPE:
1877  return (LWGEOM *)lwpoly_grid((LWPOLY *)lwgeom, grid);
1878  case MULTIPOINTTYPE:
1879  case MULTILINETYPE:
1880  case MULTIPOLYGONTYPE:
1881  case COLLECTIONTYPE:
1882  case COMPOUNDTYPE:
1883  return (LWGEOM *)lwcollection_grid((LWCOLLECTION *)lwgeom, grid);
1884  case CIRCSTRINGTYPE:
1885  return (LWGEOM *)lwcircstring_grid((LWCIRCSTRING *)lwgeom, grid);
1886  default:
1887  lwerror("lwgeom_grid: Unsupported geometry type: %s",
1888  lwtype_name(lwgeom->type));
1889  return NULL;
1890  }
1891 }
1892 
1893 
1894 /* Prototype for recursion */
1895 static int
1896 lwgeom_subdivide_recursive(const LWGEOM *geom, int maxvertices, int depth, LWCOLLECTION *col, const GBOX *clip);
1897 
1898 static int
1899 lwgeom_subdivide_recursive(const LWGEOM *geom, int maxvertices, int depth, LWCOLLECTION *col, const GBOX *clip)
1900 {
1901  const int maxdepth = 50;
1902  int nvertices = 0;
1903  int i, n = 0;
1904  double width = clip->xmax - clip->xmin;
1905  double height = clip->ymax - clip->ymin;
1906  GBOX subbox1, subbox2;
1907  LWGEOM *clipped1, *clipped2;
1908 
1909  if ( geom->type == POLYHEDRALSURFACETYPE || geom->type == TINTYPE )
1910  {
1911  lwerror("%s: unsupported geometry type '%s'", __func__, lwtype_name(geom->type));
1912  }
1913 
1914  if ( width == 0.0 && height == 0.0 )
1915  {
1916  if ( geom->type == POINTTYPE )
1917  {
1919  return 1;
1920  }
1921  else
1922  {
1923  return 0;
1924  }
1925  }
1926 
1927  /* Always just recurse into collections */
1928  if ( lwgeom_is_collection(geom) && geom->type != MULTIPOINTTYPE )
1929  {
1930  LWCOLLECTION *incol = (LWCOLLECTION*)geom;
1931  int n = 0;
1932  for ( i = 0; i < incol->ngeoms; i++ )
1933  {
1934  /* Don't increment depth yet, since we aren't actually subdividing geomtries yet */
1935  n += lwgeom_subdivide_recursive(incol->geoms[i], maxvertices, depth, col, clip);
1936  }
1937  return n;
1938  }
1939 
1940  /* But don't go too far. 2^25 = 33M, that's enough subdivision */
1941  /* Signal callers above that we depth'ed out with a negative */
1942  /* return value */
1943  if ( depth > maxdepth )
1944  {
1945  return 0;
1946  }
1947 
1948  nvertices = lwgeom_count_vertices(geom);
1949  /* Skip empties entirely */
1950  if ( nvertices == 0 )
1951  {
1952  return 0;
1953  }
1954 
1955  /* If it is under the vertex tolerance, just add it, we're done */
1956  if ( nvertices < maxvertices )
1957  {
1959  return 1;
1960  }
1961 
1962  subbox1 = subbox2 = *clip;
1963  if ( width > height )
1964  {
1965  subbox1.xmax = subbox2.xmin = (clip->xmin + clip->xmax)/2;
1966  }
1967  else
1968  {
1969  subbox1.ymax = subbox2.ymin = (clip->ymin + clip->ymax)/2;
1970  }
1971 
1972  if ( height == 0 )
1973  {
1974  subbox1.ymax += FP_TOLERANCE;
1975  subbox2.ymax += FP_TOLERANCE;
1976  subbox1.ymin -= FP_TOLERANCE;
1977  subbox2.ymin -= FP_TOLERANCE;
1978  }
1979 
1980  if ( width == 0 )
1981  {
1982  subbox1.xmax += FP_TOLERANCE;
1983  subbox2.xmax += FP_TOLERANCE;
1984  subbox1.xmin -= FP_TOLERANCE;
1985  subbox2.xmin -= FP_TOLERANCE;
1986  }
1987 
1988  clipped1 = lwgeom_clip_by_rect(geom, subbox1.xmin, subbox1.ymin, subbox1.xmax, subbox1.ymax);
1989  clipped2 = lwgeom_clip_by_rect(geom, subbox2.xmin, subbox2.ymin, subbox2.xmax, subbox2.ymax);
1990 
1991  if ( clipped1 )
1992  {
1993  n += lwgeom_subdivide_recursive(clipped1, maxvertices, ++depth, col, &subbox1);
1994  lwgeom_free(clipped1);
1995  }
1996 
1997  if ( clipped2 )
1998  {
1999  n += lwgeom_subdivide_recursive(clipped2, maxvertices, ++depth, col, &subbox2);
2000  lwgeom_free(clipped2);
2001  }
2002 
2003  return n;
2004 
2005 }
2006 
2007 LWCOLLECTION *
2008 lwgeom_subdivide(const LWGEOM *geom, int maxvertices)
2009 {
2010  static int startdepth = 0;
2011  static int minmaxvertices = 8;
2012  LWCOLLECTION *col;
2013  GBOX clip;
2014 
2016 
2017  if ( lwgeom_is_empty(geom) )
2018  return col;
2019 
2020  if ( maxvertices < minmaxvertices )
2021  {
2022  lwcollection_free(col);
2023  lwerror("%s: cannot subdivide to fewer than %d vertices per output", __func__, minmaxvertices);
2024  }
2025 
2026  clip = *(lwgeom_get_bbox(geom));
2027  lwgeom_subdivide_recursive(geom, maxvertices, startdepth, col, &clip);
2028  lwgeom_set_srid((LWGEOM*)col, geom->srid);
2029  return col;
2030 }
2031 
2032 
2033 int
2035 {
2036  int type = geom->type;
2037 
2038  if( type != LINETYPE )
2039  {
2040  lwnotice("Geometry is not a LINESTRING");
2041  return LW_FALSE;
2042  }
2043  return lwline_is_trajectory((LWLINE*)geom);
2044 }
2045 
LWMPOINT * lwgeom_as_lwmpoint(const LWGEOM *lwgeom)
Definition: lwgeom.c:152
LWCIRCSTRING * lwcircstring_grid(const LWCIRCSTRING *line, const gridspec *grid)
Definition: lwcircstring.c:305
double x
Definition: liblwgeom.h:336
#define LINETYPE
Definition: liblwgeom.h:71
int lwgeom_calculate_gbox_geodetic(const LWGEOM *geom, GBOX *gbox)
Calculate the geodetic bounding box for an LWGEOM.
Definition: lwgeodetic.c:2615
LWPOINT * lwpoint_force_dims(const LWPOINT *lwpoint, int hasz, int hasm)
Definition: lwpoint.c:240
int lwcollection_count_vertices(LWCOLLECTION *col)
Definition: lwcollection.c:494
LWGEOM * lwgeom_stroke(const LWGEOM *geom, uint32_t perQuad)
Definition: lwstroke.c:446
static int lwcollection_dimensionality(LWCOLLECTION *col)
Definition: lwgeom.c:1349
int lwgeom_startpoint(const LWGEOM *lwgeom, POINT4D *pt)
Definition: lwgeom.c:1837
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:239
LWPSURFACE * lwgeom_as_lwpsurface(const LWGEOM *lwgeom)
Definition: lwgeom.c:179
GBOX * gbox_new(uint8_t flags)
Create a new gbox with the dimensionality indicated by the flags.
Definition: g_box.c:28
GBOX * bbox
Definition: liblwgeom.h:382
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:611
LWPOLY * lwpoly_clone_deep(const LWPOLY *lwgeom)
Definition: lwpoly.c:135
LWLINE * lwline_construct_empty(int srid, char hasz, char hasm)
Definition: lwline.c:51
POINTARRAY * points
Definition: liblwgeom.h:417
char lwpoint_same(const LWPOINT *p1, const LWPOINT *p2)
Definition: lwpoint.c:233
double lwcircstring_length(const LWCIRCSTRING *circ)
Definition: lwcircstring.c:270
double m
Definition: liblwgeom.h:336
#define MULTICURVETYPE
Definition: liblwgeom.h:80
void lwgeom_drop_bbox(LWGEOM *lwgeom)
Call this function to drop BBOX and SRID from LWGEOM.
Definition: lwgeom.c:586
GEOGRAPHIC_POINT center
LWCOLLECTION * lwcollection_construct(uint8_t type, int srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
Definition: lwcollection.c:30
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition: lwout_wkt.c:655
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
Definition: lwutil.c:61
void lwgeom_scale(LWGEOM *geom, const POINT4D *factor)
Definition: lwgeom.c:1742
LWGEOM * lwgeom_force_3dm(const LWGEOM *geom)
Definition: lwgeom.c:702
void lwgeom_drop_srid(LWGEOM *lwgeom)
Definition: lwgeom.c:662
void lwmline_free(LWMLINE *mline)
Definition: lwmline.c:98
LWLINE * lwline_segmentize2d(LWLINE *line, double dist)
Definition: lwline.c:134
void lwfree(void *mem)
Definition: lwutil.c:214
LWTRIANGLE * lwtriangle_construct_empty(int srid, char hasz, char hasm)
Definition: lwtriangle.c:45
int lwline_count_vertices(LWLINE *line)
Definition: lwline.c:504
int32_t lwgeom_get_srid(const LWGEOM *geom)
Return SRID number.
Definition: lwgeom.c:822
LWPOLY * lwpoly_simplify(const LWPOLY *ipoly, double dist, int preserve_collapsed)
Definition: lwpoly.c:351
LWGEOM ** rings
Definition: liblwgeom.h:519
LWLINE * lwline_clone(const LWLINE *lwgeom)
Definition: lwline.c:89
int lwtin_is_closed(const LWTIN *tin)
Definition: lwtin.c:80
void ptarray_scale(POINTARRAY *pa, const POINT4D *factor)
Scale a pointarray.
Definition: ptarray.c:1804
uint8_t type
Definition: liblwgeom.h:487
double lwgeom_length(const LWGEOM *geom)
Definition: lwgeom.c:1646
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition: lwgeom.c:843
void lwcircstring_free(LWCIRCSTRING *curve)
Definition: lwcircstring.c:85
void lwgeom_force_clockwise(LWGEOM *lwgeom)
Force Right-hand-rule on LWGEOM polygons.
Definition: lwgeom.c:23
#define FLAGS_GET_GEODETIC(flags)
Definition: liblwgeom.h:127
#define POLYGONTYPE
Definition: liblwgeom.h:72
Datum area(PG_FUNCTION_ARGS)
void lwtin_free(LWTIN *tin)
Definition: lwtin.c:26
uint8_t flags
Definition: liblwgeom.h:381
double xmax
Definition: liblwgeom.h:277
#define CURVEPOLYTYPE
Definition: liblwgeom.h:79
void lwpoint_free(LWPOINT *pt)
Definition: lwpoint.c:182
LWGEOM * lwgeom_clip_by_rect(const LWGEOM *geom1, double x0, double y0, double x1, double y1)
#define COMPOUNDTYPE
Definition: liblwgeom.h:78
#define MULTIPOINTTYPE
Definition: liblwgeom.h:73
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
Definition: lwgeom.c:125
int lwgeom_ndims(const LWGEOM *geom)
Return the number of dimensions (2, 3, 4) in a geometry.
Definition: lwgeom.c:850
void lwgeom_longitude_shift(LWGEOM *lwgeom)
Definition: lwgeom.c:902
void lwline_free(LWLINE *line)
Definition: lwline.c:63
LWGEOM * lwgeom_grid(const LWGEOM *lwgeom, const gridspec *grid)
Definition: lwgeom.c:1868
LWGEOM * lwgeom_segmentize2d(LWGEOM *lwgeom, double dist)
Definition: lwgeom.c:668
LWGEOM * lwgeom_remove_repeated_points(LWGEOM *in, double tolerance)
Remove repeated points!
Definition: lwgeom.c:1407
void lwgeom_swap_ordinates(LWGEOM *in, LWORD o1, LWORD o2)
Swap ordinate values in every vertex of the geometry.
Definition: lwgeom.c:1464
int lwgeom_count_rings(const LWGEOM *geom)
Count rings in an LWGEOM.
Definition: lwgeom.c:1249
double lwtriangle_perimeter_2d(const LWTRIANGLE *triangle)
Definition: lwtriangle.c:205
#define FLAGS_GET_ZM(flags)
Definition: liblwgeom.h:137
double lwcircstring_length_2d(const LWCIRCSTRING *circ)
Definition: lwcircstring.c:275
LWTRIANGLE * lwtriangle_clone(const LWTRIANGLE *lwgeom)
Definition: lwtriangle.c:86
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:50
double lwline_length_2d(const LWLINE *line)
Definition: lwline.c:557
#define TRIANGLETYPE
Definition: liblwgeom.h:83
void lwtriangle_reverse(LWTRIANGLE *triangle)
Definition: lwtriangle.c:100
int lwline_is_trajectory(const LWLINE *geom)
Definition: lwline.c:448
LWGEOM * lwmpoint_as_lwgeom(const LWMPOINT *obj)
Definition: lwgeom.c:214
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:82
int lwgeom_count_vertices(const LWGEOM *geom)
Count points in an LWGEOM.
Definition: lwgeom.c:1140
LWGEOM * lwgeom_simplify(const LWGEOM *igeom, double dist, int preserve_collapsed)
Definition: lwgeom.c:1558
void lwtriangle_force_clockwise(LWTRIANGLE *triangle)
Definition: lwtriangle.c:93
LWLINE * lwline_grid(const LWLINE *line, const gridspec *grid)
Definition: lwline.c:566
LWPOINT * lwpoint_grid(const LWPOINT *point, const gridspec *grid)
Definition: lwpoint.c:269
int lwcompound_is_closed(const LWCOMPOUND *curve)
Definition: lwcompound.c:22
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:254
double distance2d_pt_pt(const POINT2D *p1, const POINT2D *p2)
The old function nessecary for ptarray_segmentize2d in ptarray.c.
Definition: measures.c:2301
#define FLAGS_SET_GEODETIC(flags, value)
Definition: liblwgeom.h:133
LWPOINT * lwpoint_construct_empty(int srid, char hasz, char hasm)
Definition: lwpoint.c:120
void lwpoly_force_clockwise(LWPOLY *poly)
Definition: lwpoly.c:175
LWTRIANGLE * lwgeom_as_lwtriangle(const LWGEOM *lwgeom)
Definition: lwgeom.c:134
double lwtriangle_area(const LWTRIANGLE *triangle)
Find the area of the outer ring.
Definition: lwtriangle.c:173
POINTARRAY * point
Definition: liblwgeom.h:395
int32_t srid
Definition: liblwgeom.h:383
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:947
LWGEOM * lwpsurface_as_lwgeom(const LWPSURFACE *obj)
Definition: lwgeom.c:199
double lwtriangle_perimeter(const LWTRIANGLE *triangle)
Definition: lwtriangle.c:196
char lwgeom_same(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)
geom1 same as geom2 iff
Definition: lwgeom.c:495
#define LW_FAILURE
Definition: liblwgeom.h:64
LWGEOM * lwtin_as_lwgeom(const LWTIN *obj)
Definition: lwgeom.c:194
char lwcollection_same(const LWCOLLECTION *p1, const LWCOLLECTION *p2)
check for same geometry composition
Definition: lwcollection.c:248
double x
Definition: liblwgeom.h:312
LWCOMPOUND * lwgeom_as_lwcompound(const LWGEOM *lwgeom)
Definition: lwgeom.c:107
int lwtriangle_is_empty(const LWTRIANGLE *triangle)
Definition: lwtriangle.c:162
LWCURVEPOLY * lwgeom_as_lwcurvepoly(const LWGEOM *lwgeom)
Definition: lwgeom.c:116
LWCURVEPOLY * lwcurvepoly_construct_from_lwpoly(LWPOLY *lwpoly)
Construct an equivalent curve polygon from a polygon.
Definition: lwcurvepoly.c:40
LWGEOM * lwgeom_clone_deep(const LWGEOM *lwgeom)
Deep-clone an LWGEOM object.
Definition: lwgeom.c:433
void lwmpoly_free(LWMPOLY *mpoly)
Definition: lwmpoly.c:40
void lwmpoint_free(LWMPOINT *mpt)
Definition: lwmpoint.c:59
double zmax
Definition: liblwgeom.h:281
double ymin
Definition: liblwgeom.h:278
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:188
LWGEOM * lwmpoly_as_lwgeom(const LWMPOLY *obj)
Definition: lwgeom.c:204
LWGEOM * lwline_remove_repeated_points(LWLINE *in, double tolerance)
Definition: lwline.c:427
double lwgeom_area(const LWGEOM *geom)
Definition: lwgeom.c:1579
char lwcircstring_same(const LWCIRCSTRING *p1, const LWCIRCSTRING *p2)
Definition: lwcircstring.c:125
double lwgeom_perimeter(const LWGEOM *geom)
Definition: lwgeom.c:1602
double lwcompound_length_2d(const LWCOMPOUND *comp)
Definition: lwcompound.c:61
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:2034
int lwcollection_is_empty(const LWCOLLECTION *col)
Definition: lwcollection.c:481
double xmin
Definition: liblwgeom.h:276
LWCIRCSTRING * lwcircstring_construct_empty(int srid, char hasz, char hasm)
Definition: lwcircstring.c:67
char lwtriangle_same(const LWTRIANGLE *p1, const LWTRIANGLE *p2)
Definition: lwtriangle.c:114
#define LW_FALSE
Definition: liblwgeom.h:62
const POINT2D * getPoint2d_cp(const POINTARRAY *pa, int n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from...
Definition: lwgeom_api.c:472
LWPOLY * lwpoly_force_dims(const LWPOLY *lwpoly, int hasz, int hasm)
Definition: lwpoly.c:308
LWGEOM * lwgeom_force_3dz(const LWGEOM *geom)
Definition: lwgeom.c:696
uint8_t flags
Definition: liblwgeom.h:353
void ptarray_swap_ordinates(POINTARRAY *pa, LWORD o1, LWORD o2)
Swap ordinate values o1 and o2 on a given POINTARRAY.
Definition: ptarray.c:388
void lwpoly_free(LWPOLY *poly)
Definition: lwpoly.c:79
int lwgeom_has_srid(const LWGEOM *geom)
Return true or false depending on whether a geometry has a valid SRID set.
Definition: lwgeom.c:1340
LWPOINT * lwpoint_clone(const LWPOINT *lwgeom)
Definition: lwpoint.c:208
double lwgeom_perimeter_2d(const LWGEOM *geom)
Definition: lwgeom.c:1624
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:61
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition: lwgeom.c:89
LWGEOM ** geoms
Definition: liblwgeom.h:493
int lwpoly_is_closed(const LWPOLY *poly)
Definition: lwpoly.c:476
double lwcompound_length(const LWCOMPOUND *comp)
Definition: lwcompound.c:56
int lwcircstring_is_closed(const LWCIRCSTRING *curve)
Definition: lwcircstring.c:255
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:172
#define TINTYPE
Definition: liblwgeom.h:84
LWCOLLECTION * lwcollection_simplify(const LWCOLLECTION *igeom, double dist, int preserve_collapsed)
Definition: lwcollection.c:506
void lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
Definition: lwgeom.c:1691
LWMLINE * lwgeom_as_lwmline(const LWGEOM *lwgeom)
Definition: lwgeom.c:161
POINTARRAY ** rings
Definition: liblwgeom.h:441
LWCIRCSTRING * lwcircstring_clone(const LWCIRCSTRING *curve)
Definition: lwcircstring.c:112
LWGEOM * lwgeom_as_multi(const LWGEOM *lwgeom)
Create a new LWGEOM of the appropriate MULTI* type.
Definition: lwgeom.c:284
LWGEOM * lwcurvepoly_as_lwgeom(const LWCURVEPOLY *obj)
Definition: lwgeom.c:229
int lwtype_is_collection(uint8_t type)
Return TRUE if the geometry may contain sub-geometries, i.e.
Definition: lwgeom.c:999
LWGEOM * lwgeom_force_4d(const LWGEOM *geom)
Definition: lwgeom.c:708
double lwpoly_area(const LWPOLY *poly)
Find the area of the outer ring - sum (area of inner rings).
Definition: lwpoly.c:411
int lwgeom_dimensionality(LWGEOM *geom)
Return the dimensionality (relating to point/line/poly) of an lwgeom.
Definition: lwgeom.c:1362
int lwpoly_is_empty(const LWPOLY *poly)
Definition: lwpoly.c:332
LWCURVEPOLY * lwcurvepoly_construct_empty(int srid, char hasz, char hasm)
Definition: lwcurvepoly.c:23
uint8_t MULTITYPE[NUMTYPES]
Look-up for the correct MULTI* type promotion for singleton types.
Definition: lwgeom.c:264
double lwcurvepoly_perimeter_2d(const LWCURVEPOLY *poly)
Definition: lwcurvepoly.c:146
LWGEOM * lwgeom_clone(const LWGEOM *lwgeom)
Clone LWGEOM object.
Definition: lwgeom.c:395
#define FP_TOLERANCE
Floating point comparators.
LWGEOM * lwcircstring_as_lwgeom(const LWCIRCSTRING *obj)
Definition: lwgeom.c:224
int nrings
Definition: liblwgeom.h:439
LWPOLY * lwpoly_grid(const LWPOLY *poly, const gridspec *grid)
Definition: lwpoly.c:529
#define NUMTYPES
Definition: liblwgeom.h:86
double ymax
Definition: liblwgeom.h:279
enum LWORD_T LWORD
Ordinate names.
double y
Definition: liblwgeom.h:312
int lwpsurface_is_closed(const LWPSURFACE *psurface)
Definition: lwpsurface.c:86
#define FLAGS_GET_Z(flags)
Macros for manipulating the 'flags' byte.
Definition: liblwgeom.h:124
int lwcollection_startpoint(const LWCOLLECTION *col, POINT4D *pt)
Definition: lwcollection.c:560
double z
Definition: liblwgeom.h:336
LWCOMPOUND * lwcompound_construct_from_lwline(const LWLINE *lwpoly)
Construct an equivalent compound curve from a linestring.
Definition: lwcompound.c:191
LWCOLLECTION * lwcollection_clone_deep(const LWCOLLECTION *lwgeom)
Deep clone LWCOLLECTION object.
Definition: lwcollection.c:136
int lwpoly_startpoint(const LWPOLY *lwpoly, POINT4D *pt)
Definition: lwpoly.c:501
double lwpoly_perimeter_2d(const LWPOLY *poly)
Compute the sum of polygon rings length (forcing 2d computation).
Definition: lwpoly.c:462
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
Definition: lwgeom.c:143
int lwcircstring_is_empty(const LWCIRCSTRING *circ)
Definition: lwcircstring.c:263
uint8_t flags
Definition: liblwgeom.h:275
double lwpoly_perimeter(const LWPOLY *poly)
Compute the sum of polygon rings length.
Definition: lwpoly.c:444
void lwtriangle_free(LWTRIANGLE *triangle)
Definition: lwtriangle.c:56
LWCOLLECTION * lwcollection_segmentize2d(LWCOLLECTION *coll, double dist)
Definition: lwcollection.c:223
void lwpsurface_free(LWPSURFACE *psurf)
Definition: lwpsurface.c:26
LWCIRCSTRING * lwgeom_as_lwcircstring(const LWGEOM *lwgeom)
Definition: lwgeom.c:98
void lwgeom_set_geodetic(LWGEOM *geom, int value)
Set the FLAGS geodetic bit on geometry an all sub-geometries and pointlists.
Definition: lwgeom.c:858
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition: lwgeom.c:219
LWCOLLECTION * lwcollection_force_dims(const LWCOLLECTION *lwcol, int hasz, int hasm)
Definition: lwcollection.c:458
LWCOLLECTION * lwgeom_subdivide(const LWGEOM *geom, int maxvertices)
Definition: lwgeom.c:2008
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:1297
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:75
double lwgeom_length_2d(const LWGEOM *geom)
Definition: lwgeom.c:1668
LWGEOM * lwgeom_force_dims(const LWGEOM *geom, int hasz, int hasm)
Definition: lwgeom.c:714
void lwpoly_reverse(LWPOLY *poly)
Definition: lwpoly.c:201
int ptarray_startpoint(const POINTARRAY *pa, POINT4D *pt)
Definition: ptarray.c:1826
int lwline_is_empty(const LWLINE *line)
Definition: lwline.c:496
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
Definition: lwgeom.c:690
#define WKT_EXTENDED
Definition: liblwgeom.h:1941
LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Definition: lwgeom.c:80
LWPOLY * lwpoly_from_lwlines(const LWLINE *shell, uint32_t nholes, const LWLINE **holes)
Definition: lwpoly.c:255
#define FLAGS_SET_BBOX(flags, value)
Definition: liblwgeom.h:132
int lwpoint_inside_circle(const LWPOINT *p, double cx, double cy, double rad)
Definition: lwgeom.c:566
LWGEOM * lwpoly_remove_repeated_points(LWPOLY *in, double tolerance)
Definition: lwpoly.c:289
double lwcurvepoly_perimeter(const LWCURVEPOLY *poly)
Definition: lwcurvepoly.c:134
void lwline_reverse(LWLINE *line)
Definition: lwline.c:127
LWLINE * lwline_force_dims(const LWLINE *lwline, int hasz, int hasm)
Definition: lwline.c:477
LWGEOM * lwgeom_force_sfs(LWGEOM *geom, int version)
Definition: lwgeom.c:744
int lwgeom_is_collection(const LWGEOM *geom)
Determine whether a LWGEOM can contain sub-geometries or not.
Definition: lwgeom.c:991
void ptarray_longitude_shift(POINTARRAY *pa)
Longitude shift for a pointarray.
Definition: ptarray.c:1414
double lwline_length(const LWLINE *line)
Definition: lwline.c:550
LWGEOM * lwmpoint_remove_repeated_points(LWMPOINT *in, double tolerance)
Definition: lwmpoint.c:79
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:1192
#define MULTISURFACETYPE
Definition: liblwgeom.h:81
double mmin
Definition: liblwgeom.h:282
int lwline_is_closed(const LWLINE *line)
Definition: lwline.c:439
double zmin
Definition: liblwgeom.h:280
char * lwgeom_to_ewkt(const LWGEOM *lwgeom)
Return an alloced string.
Definition: lwgeom.c:469
LWMPOLY * lwgeom_as_lwmpoly(const LWGEOM *lwgeom)
Definition: lwgeom.c:170
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition: lwgeom.c:836
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:70
int lwpoint_is_empty(const LWPOINT *point)
Definition: lwpoint.c:260
LWPOLY * lwpoly_construct_empty(int srid, char hasz, char hasm)
Definition: lwpoly.c:66
LWGEOM * lwmline_as_lwgeom(const LWMLINE *obj)
Definition: lwgeom.c:209
void lwgeom_add_bbox(LWGEOM *lwgeom)
Ensure there's a box in the LWGEOM.
Definition: lwgeom.c:599
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:125
LWCOLLECTION * lwcollection_grid(const LWCOLLECTION *coll, const gridspec *grid)
Definition: lwcollection.c:569
int lwgeom_needs_bbox(const LWGEOM *geom)
Check whether or not a lwgeom is big enough to warrant a bounding box.
Definition: lwgeom.c:1103
int lwtype_get_collectiontype(uint8_t type)
Given an lwtype number, what homogeneous collection can hold it?
Definition: lwgeom.c:1026
uint8_t type
Definition: liblwgeom.h:380
LWCOLLECTION * lwcollection_clone(const LWCOLLECTION *lwgeom)
Clone LWCOLLECTION object.
Definition: lwcollection.c:110
double mmax
Definition: liblwgeom.h:283
void lwcollection_free(LWCOLLECTION *col)
Definition: lwcollection.c:326
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:249
LWGEOM * lwgeom_construct_empty(uint8_t type, int srid, char hasz, char hasm)
Definition: lwgeom.c:1807
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:652
GBOX * gbox_clone(const GBOX *gbox)
Definition: g_box.c:41
LWTIN * lwgeom_as_lwtin(const LWGEOM *lwgeom)
Definition: lwgeom.c:187
void lwgeom_set_srid(LWGEOM *geom, int32_t srid)
Definition: lwgeom.c:1539
#define CIRCSTRINGTYPE
Definition: liblwgeom.h:77
LWPOLY * lwpoly_segmentize2d(LWPOLY *line, double dist)
Definition: lwpoly.c:210
static int lwgeom_subdivide_recursive(const LWGEOM *geom, int maxvertices, int depth, LWCOLLECTION *col, const GBOX *clip)
Definition: lwgeom.c:1899
void * lwalloc(size_t size)
Definition: lwutil.c:199
LWGEOM * lwtriangle_as_lwgeom(const LWTRIANGLE *obj)
Definition: lwgeom.c:244
void lwgeom_free(LWGEOM *lwgeom)
Definition: lwgeom.c:1050
int lwpoly_count_vertices(LWPOLY *poly)
Definition: lwpoly.c:339
uint32_t lwgeom_get_type(const LWGEOM *geom)
Return LWTYPE number.
Definition: lwgeom.c:829
double y
Definition: liblwgeom.h:336
#define MULTILINETYPE
Definition: liblwgeom.h:74
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int srid, char hasz, char hasm)
Definition: lwcollection.c:81
LWPOLY * lwpoly_clone(const LWPOLY *lwgeom)
Definition: lwpoly.c:120
LWLINE * lwline_clone_deep(const LWLINE *lwgeom)
Definition: lwline.c:105
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:55
#define FLAGS_NDIMS(flags)
Definition: liblwgeom.h:136
double lwcurvepoly_area(const LWCURVEPOLY *curvepoly)
This should be rewritten to make use of the curve itself.
Definition: lwcurvepoly.c:120
int gbox_same(const GBOX *g1, const GBOX *g2)
Check if 2 given Gbox are the same.
Definition: g_box.c:141
LWGEOM * lwgeom_flip_coordinates(LWGEOM *in)
Reverse the X and Y coordinate order.
Definition: lwgeom.c:1458
char lwpoly_same(const LWPOLY *p1, const LWPOLY *p2)
Definition: lwpoly.c:234
LWGEOM * lwcompound_as_lwgeom(const LWCOMPOUND *obj)
Definition: lwgeom.c:234
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
Definition: lwcollection.c:174
void lwgeom_release(LWGEOM *lwgeom)
Free the containing LWGEOM and the associated BOX.
Definition: lwgeom.c:372
char lwline_same(const LWLINE *p1, const LWLINE *p2)
Definition: lwline.c:143
LWLINE * lwline_simplify(const LWLINE *iline, double dist, int preserve_collapsed)
Definition: lwline.c:512
LWGEOM * lwgeom_as_curve(const LWGEOM *lwgeom)
Create a new LWGEOM of the appropriate CURVE* type.
Definition: lwgeom.c:324
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:74
#define COLLECTIONTYPE
Definition: liblwgeom.h:76
void ptarray_affine(POINTARRAY *pa, const AFFINE *affine)
Affine transform a pointarray.
Definition: ptarray.c:1753
void lwgeom_reverse(LWGEOM *lwgeom)
Reverse vertex order of LWGEOM.
Definition: lwgeom.c:51
LWGEOM * lwcollection_remove_repeated_points(LWCOLLECTION *in, double tolerance)
Definition: lwcollection.c:440
POINTARRAY * points
Definition: liblwgeom.h:406
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:640
int lwgeom_calculate_gbox_cartesian(const LWGEOM *lwgeom, GBOX *gbox)
Calculate the 2-4D bounding box of a geometry.
Definition: g_box.c:648
Snap to grid.