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