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