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