PostGIS  2.2.8dev-r@@SVN_REVISION@@
lwpoly.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * Copyright (C) 2012 Sandro Santilli <strk@keybit.net>
7  * Copyright (C) 2001-2006 Refractions Research Inc.
8  *
9  * This is free software; you can redistribute and/or modify it under
10  * the terms of the GNU General Public Licence. See the COPYING file.
11  *
12  **********************************************************************/
13 
14 /* basic LWPOLY manipulation */
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include "liblwgeom_internal.h"
20 #include "lwgeom_log.h"
21 
22 
23 #define CHECK_POLY_RINGS_ZM 1
24 
25 /* construct a new LWPOLY. arrays (points/points per ring) will NOT be copied
26  * use SRID=SRID_UNKNOWN for unknown SRID (will have 8bit type's S = 0)
27  */
28 LWPOLY*
29 lwpoly_construct(int srid, GBOX *bbox, uint32_t nrings, POINTARRAY **points)
30 {
31  LWPOLY *result;
32  int hasz, hasm;
33 #ifdef CHECK_POLY_RINGS_ZM
34  char zm;
35  uint32_t i;
36 #endif
37 
38  if ( nrings < 1 ) lwerror("lwpoly_construct: need at least 1 ring");
39 
40  hasz = FLAGS_GET_Z(points[0]->flags);
41  hasm = FLAGS_GET_M(points[0]->flags);
42 
43 #ifdef CHECK_POLY_RINGS_ZM
44  zm = FLAGS_GET_ZM(points[0]->flags);
45  for (i=1; i<nrings; i++)
46  {
47  if ( zm != FLAGS_GET_ZM(points[i]->flags) )
48  lwerror("lwpoly_construct: mixed dimensioned rings");
49  }
50 #endif
51 
52  result = (LWPOLY*) lwalloc(sizeof(LWPOLY));
53  result->type = POLYGONTYPE;
54  result->flags = gflags(hasz, hasm, 0);
55  FLAGS_SET_BBOX(result->flags, bbox?1:0);
56  result->srid = srid;
57  result->nrings = nrings;
58  result->maxrings = nrings;
59  result->rings = points;
60  result->bbox = bbox;
61 
62  return result;
63 }
64 
65 LWPOLY*
66 lwpoly_construct_empty(int srid, char hasz, char hasm)
67 {
68  LWPOLY *result = lwalloc(sizeof(LWPOLY));
69  result->type = POLYGONTYPE;
70  result->flags = gflags(hasz,hasm,0);
71  result->srid = srid;
72  result->nrings = 0;
73  result->maxrings = 1; /* Allocate room for ring, just in case. */
74  result->rings = lwalloc(result->maxrings * sizeof(POINTARRAY*));
75  result->bbox = NULL;
76  return result;
77 }
78 
79 void lwpoly_free(LWPOLY *poly)
80 {
81  int t;
82 
83  if( ! poly ) return;
84 
85  if ( poly->bbox )
86  lwfree(poly->bbox);
87 
88  for (t=0; t<poly->nrings; t++)
89  {
90  if ( poly->rings[t] )
91  ptarray_free(poly->rings[t]);
92  }
93 
94  if ( poly->rings )
95  lwfree(poly->rings);
96 
97  lwfree(poly);
98 }
99 
100 void printLWPOLY(LWPOLY *poly)
101 {
102  int t;
103  lwnotice("LWPOLY {");
104  lwnotice(" ndims = %i", (int)FLAGS_NDIMS(poly->flags));
105  lwnotice(" SRID = %i", (int)poly->srid);
106  lwnotice(" nrings = %i", (int)poly->nrings);
107  for (t=0; t<poly->nrings; t++)
108  {
109  lwnotice(" RING # %i :",t);
110  printPA(poly->rings[t]);
111  }
112  lwnotice("}");
113 }
114 
115 /* @brief Clone LWLINE object. Serialized point lists are not copied.
116  *
117  * @see ptarray_clone
118  */
119 LWPOLY *
121 {
122  int i;
123  LWPOLY *ret = lwalloc(sizeof(LWPOLY));
124  memcpy(ret, g, sizeof(LWPOLY));
125  ret->rings = lwalloc(sizeof(POINTARRAY *)*g->nrings);
126  for ( i = 0; i < g->nrings; i++ ) {
127  ret->rings[i] = ptarray_clone(g->rings[i]);
128  }
129  if ( g->bbox ) ret->bbox = gbox_copy(g->bbox);
130  return ret;
131 }
132 
133 /* Deep clone LWPOLY object. POINTARRAY are copied, as is ring array */
134 LWPOLY *
136 {
137  int i;
138  LWPOLY *ret = lwalloc(sizeof(LWPOLY));
139  memcpy(ret, g, sizeof(LWPOLY));
140  if ( g->bbox ) ret->bbox = gbox_copy(g->bbox);
141  ret->rings = lwalloc(sizeof(POINTARRAY *)*g->nrings);
142  for ( i = 0; i < ret->nrings; i++ )
143  {
144  ret->rings[i] = ptarray_clone_deep(g->rings[i]);
145  }
146  FLAGS_SET_READONLY(ret->flags,0);
147  return ret;
148 }
149 
153 int
155 {
156  if( ! poly || ! pa )
157  return LW_FAILURE;
158 
159  /* We have used up our storage, add some more. */
160  if( poly->nrings >= poly->maxrings )
161  {
162  int new_maxrings = 2 * (poly->nrings + 1);
163  poly->rings = lwrealloc(poly->rings, new_maxrings * sizeof(POINTARRAY*));
164  poly->maxrings = new_maxrings;
165  }
166 
167  /* Add the new ring entry. */
168  poly->rings[poly->nrings] = pa;
169  poly->nrings++;
170 
171  return LW_SUCCESS;
172 }
173 
174 void
176 {
177  int i;
178 
179  /* No-op empties */
180  if ( lwpoly_is_empty(poly) )
181  return;
182 
183  /* External ring */
184  if ( ptarray_isccw(poly->rings[0]) )
185  ptarray_reverse(poly->rings[0]);
186 
187  /* Internal rings */
188  for (i=1; i<poly->nrings; i++)
189  if ( ! ptarray_isccw(poly->rings[i]) )
190  ptarray_reverse(poly->rings[i]);
191 
192 }
193 
194 void
196 {
198 }
199 
200 void
202 {
203  int i;
204  if ( lwpoly_is_empty(poly) ) return;
205  for (i=0; i<poly->nrings; i++)
206  ptarray_reverse(poly->rings[i]);
207 }
208 
209 LWPOLY *
210 lwpoly_segmentize2d(LWPOLY *poly, double dist)
211 {
212  POINTARRAY **newrings;
213  uint32_t i;
214 
215  newrings = lwalloc(sizeof(POINTARRAY *)*poly->nrings);
216  for (i=0; i<poly->nrings; i++)
217  {
218  newrings[i] = ptarray_segmentize2d(poly->rings[i], dist);
219  if ( ! newrings[i] ) {
220  while (i--) ptarray_free(newrings[i]);
221  lwfree(newrings);
222  return NULL;
223  }
224  }
225  return lwpoly_construct(poly->srid, NULL,
226  poly->nrings, newrings);
227 }
228 
229 /*
230  * check coordinate equality
231  * ring and coordinate order is considered
232  */
233 char
234 lwpoly_same(const LWPOLY *p1, const LWPOLY *p2)
235 {
236  uint32_t i;
237 
238  if ( p1->nrings != p2->nrings ) return 0;
239  for (i=0; i<p1->nrings; i++)
240  {
241  if ( ! ptarray_same(p1->rings[i], p2->rings[i]) )
242  return 0;
243  }
244  return 1;
245 }
246 
247 /*
248  * Construct a polygon from a LWLINE being
249  * the shell and an array of LWLINE (possibly NULL) being holes.
250  * Pointarrays from intput geoms are cloned.
251  * SRID must be the same for each input line.
252  * Input lines must have at least 4 points, and be closed.
253  */
254 LWPOLY *
256  uint32_t nholes, const LWLINE **holes)
257 {
258  uint32_t nrings;
259  POINTARRAY **rings = lwalloc((nholes+1)*sizeof(POINTARRAY *));
260  int srid = shell->srid;
261  LWPOLY *ret;
262 
263  if ( shell->points->npoints < 4 )
264  lwerror("lwpoly_from_lwlines: shell must have at least 4 points");
265  if ( ! ptarray_is_closed_2d(shell->points) )
266  lwerror("lwpoly_from_lwlines: shell must be closed");
267  rings[0] = ptarray_clone_deep(shell->points);
268 
269  for (nrings=1; nrings<=nholes; nrings++)
270  {
271  const LWLINE *hole = holes[nrings-1];
272 
273  if ( hole->srid != srid )
274  lwerror("lwpoly_from_lwlines: mixed SRIDs in input lines");
275 
276  if ( hole->points->npoints < 4 )
277  lwerror("lwpoly_from_lwlines: holes must have at least 4 points");
278  if ( ! ptarray_is_closed_2d(hole->points) )
279  lwerror("lwpoly_from_lwlines: holes must be closed");
280 
281  rings[nrings] = ptarray_clone_deep(hole->points);
282  }
283 
284  ret = lwpoly_construct(srid, NULL, nrings, rings);
285  return ret;
286 }
287 
288 LWGEOM*
289 lwpoly_remove_repeated_points(LWPOLY *poly, double tolerance)
290 {
291  uint32_t i;
292  POINTARRAY **newrings;
293 
294  newrings = lwalloc(sizeof(POINTARRAY *)*poly->nrings);
295  for (i=0; i<poly->nrings; i++)
296  {
297  newrings[i] = ptarray_remove_repeated_points_minpoints(poly->rings[i], tolerance, 4);
298  }
299 
300  return (LWGEOM*)lwpoly_construct(poly->srid,
301  poly->bbox ? gbox_copy(poly->bbox) : NULL,
302  poly->nrings, newrings);
303 
304 }
305 
306 
307 LWPOLY*
308 lwpoly_force_dims(const LWPOLY *poly, int hasz, int hasm)
309 {
310  LWPOLY *polyout;
311 
312  /* Return 2D empty */
313  if( lwpoly_is_empty(poly) )
314  {
315  polyout = lwpoly_construct_empty(poly->srid, hasz, hasm);
316  }
317  else
318  {
319  POINTARRAY **rings = NULL;
320  int i;
321  rings = lwalloc(sizeof(POINTARRAY*) * poly->nrings);
322  for( i = 0; i < poly->nrings; i++ )
323  {
324  rings[i] = ptarray_force_dims(poly->rings[i], hasz, hasm);
325  }
326  polyout = lwpoly_construct(poly->srid, NULL, poly->nrings, rings);
327  }
328  polyout->type = poly->type;
329  return polyout;
330 }
331 
332 int lwpoly_is_empty(const LWPOLY *poly)
333 {
334  if ( (poly->nrings < 1) || (!poly->rings) || (!poly->rings[0]) || (poly->rings[0]->npoints < 1) )
335  return LW_TRUE;
336  return LW_FALSE;
337 }
338 
340 {
341  int i = 0;
342  int v = 0; /* vertices */
343  assert(poly);
344  for ( i = 0; i < poly->nrings; i ++ )
345  {
346  v += poly->rings[i]->npoints;
347  }
348  return v;
349 }
350 
351 LWPOLY* lwpoly_simplify(const LWPOLY *ipoly, double dist, int preserve_collapsed)
352 {
353  int i;
354  LWPOLY *opoly = lwpoly_construct_empty(ipoly->srid, FLAGS_GET_Z(ipoly->flags), FLAGS_GET_M(ipoly->flags));
355 
356  LWDEBUGF(2, "%s: simplifying polygon with %d rings", __func__, ipoly->nrings);
357 
358  if ( lwpoly_is_empty(ipoly) )
359  {
360  lwpoly_free(opoly);
361  return NULL;
362  }
363 
364  for ( i = 0; i < ipoly->nrings; i++ )
365  {
366  POINTARRAY *opts;
367  int minvertices = 0;
368 
369  /* We'll still let holes collapse, but if we're preserving */
370  /* and this is a shell, we ensure it is kept */
371  if ( preserve_collapsed && i == 0 )
372  minvertices = 4;
373 
374  opts = ptarray_simplify(ipoly->rings[i], dist, minvertices);
375 
376  LWDEBUGF(3, "ring%d simplified from %d to %d points", i, ipoly->rings[i]->npoints, opts->npoints);
377 
378  /* Less points than are needed to form a closed ring, we can't use this */
379  if ( opts->npoints < 4 )
380  {
381  LWDEBUGF(3, "ring%d skipped (% pts)", i, opts->npoints);
382  ptarray_free(opts);
383  if ( i ) continue;
384  else break; /* Don't scan holes if shell is collapsed */
385  }
386 
387  /* Add ring to simplified polygon */
388  if( lwpoly_add_ring(opoly, opts) == LW_FAILURE )
389  {
390  lwpoly_free(opoly);
391  return NULL;
392  }
393  }
394 
395  LWDEBUGF(3, "simplified polygon with %d rings", ipoly->nrings);
396  opoly->type = ipoly->type;
397 
398  if( lwpoly_is_empty(opoly) )
399  {
400  lwpoly_free(opoly);
401  return NULL;
402  }
403 
404  return opoly;
405 }
406 
410 double
411 lwpoly_area(const LWPOLY *poly)
412 {
413  double poly_area = 0.0;
414  int i;
415 
416  if ( ! poly )
417  lwerror("lwpoly_area called with null polygon pointer!");
418 
419  for ( i=0; i < poly->nrings; i++ )
420  {
421  POINTARRAY *ring = poly->rings[i];
422  double ringarea = 0.0;
423 
424  /* Empty or messed-up ring. */
425  if ( ring->npoints < 3 )
426  continue;
427 
428  ringarea = fabs(ptarray_signed_area(ring));
429  if ( i == 0 ) /* Outer ring, positive area! */
430  poly_area += ringarea;
431  else /* Inner ring, negative area! */
432  poly_area -= ringarea;
433  }
434 
435  return poly_area;
436 }
437 
438 
443 double
445 {
446  double result=0.0;
447  int i;
448 
449  LWDEBUGF(2, "in lwgeom_polygon_perimeter (%d rings)", poly->nrings);
450 
451  for (i=0; i<poly->nrings; i++)
452  result += ptarray_length(poly->rings[i]);
453 
454  return result;
455 }
456 
461 double
463 {
464  double result=0.0;
465  int i;
466 
467  LWDEBUGF(2, "in lwgeom_polygon_perimeter (%d rings)", poly->nrings);
468 
469  for (i=0; i<poly->nrings; i++)
470  result += ptarray_length_2d(poly->rings[i]);
471 
472  return result;
473 }
474 
475 int
477 {
478  int i = 0;
479 
480  if ( poly->nrings == 0 )
481  return LW_TRUE;
482 
483  for ( i = 0; i < poly->nrings; i++ )
484  {
485  if (FLAGS_GET_Z(poly->flags))
486  {
487  if ( ! ptarray_is_closed_3d(poly->rings[i]) )
488  return LW_FALSE;
489  }
490  else
491  {
492  if ( ! ptarray_is_closed_2d(poly->rings[i]) )
493  return LW_FALSE;
494  }
495  }
496 
497  return LW_TRUE;
498 }
499 
500 int
502 {
503  if ( poly->nrings < 1 )
504  return LW_FAILURE;
505  return ptarray_startpoint(poly->rings[0], pt);
506 }
507 
508 int
509 lwpoly_contains_point(const LWPOLY *poly, const POINT2D *pt)
510 {
511  int i;
512 
513  if ( lwpoly_is_empty(poly) )
514  return LW_FALSE;
515 
516  if ( ptarray_contains_point(poly->rings[0], pt) == LW_OUTSIDE )
517  return LW_FALSE;
518 
519  for ( i = 1; i < poly->nrings; i++ )
520  {
521  if ( ptarray_contains_point(poly->rings[i], pt) == LW_INSIDE )
522  return LW_FALSE;
523  }
524  return LW_TRUE;
525 }
526 
527 
528 
529 LWPOLY* lwpoly_grid(const LWPOLY *poly, const gridspec *grid)
530 {
531  LWPOLY *opoly;
532  int ri;
533 
534 #if 0
535  /*
536  * TODO: control this assertion
537  * it is assumed that, since the grid size will be a pixel,
538  * a visible ring should show at least a white pixel inside,
539  * thus, for a square, that would be grid_xsize*grid_ysize
540  */
541  double minvisiblearea = grid->xsize * grid->ysize;
542 #endif
543 
544  LWDEBUGF(3, "lwpoly_grid: applying grid to polygon with %d rings", poly->nrings);
545 
546  opoly = lwpoly_construct_empty(poly->srid, lwgeom_has_z((LWGEOM*)poly), lwgeom_has_m((LWGEOM*)poly));
547 
548  for (ri=0; ri<poly->nrings; ri++)
549  {
550  POINTARRAY *ring = poly->rings[ri];
551  POINTARRAY *newring;
552 
553  newring = ptarray_grid(ring, grid);
554 
555  /* Skip ring if not composed by at least 4 pts (3 segments) */
556  if ( newring->npoints < 4 )
557  {
558  ptarray_free(newring);
559 
560  LWDEBUGF(3, "grid_polygon3d: ring%d skipped ( <4 pts )", ri);
561 
562  if ( ri ) continue;
563  else break; /* this is the external ring, no need to work on holes */
564  }
565 
566  if ( ! lwpoly_add_ring(opoly, newring) )
567  {
568  lwerror("lwpoly_grid, memory error");
569  return NULL;
570  }
571  }
572 
573  LWDEBUGF(3, "lwpoly_grid: simplified polygon with %d rings", opoly->nrings);
574 
575  if ( ! opoly->nrings )
576  {
577  lwpoly_free(opoly);
578  return NULL;
579  }
580 
581  return opoly;
582 }
GBOX * gbox_copy(const GBOX *box)
Return a copy of the GBOX, based on dimensionality of flags.
Definition: g_box.c:403
LWPOLY * lwpoly_grid(const LWPOLY *poly, const gridspec *grid)
Definition: lwpoly.c:529
POINTARRAY * ptarray_clone(const POINTARRAY *ptarray)
Clone a POINTARRAY object.
Definition: ptarray.c:658
double lwpoly_area(const LWPOLY *poly)
Find the area of the outer ring - sum (area of inner rings).
Definition: lwpoly.c:411
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
Definition: lwutil.c:61
void lwfree(void *mem)
Definition: lwutil.c:214
void lwpoly_release(LWPOLY *lwpoly)
Definition: lwpoly.c:195
int npoints
Definition: liblwgeom.h:355
int ptarray_is_closed_3d(const POINTARRAY *pa)
Definition: ptarray.c:707
#define POLYGONTYPE
Definition: liblwgeom.h:72
void ptarray_free(POINTARRAY *pa)
Definition: ptarray.c:330
double lwpoly_perimeter(const LWPOLY *poly)
Compute the sum of polygon rings length.
Definition: lwpoly.c:444
double ptarray_length_2d(const POINTARRAY *pts)
Find the 2d length of the given POINTARRAY (even if it&#39;s 3d)
Definition: ptarray.c:1645
#define LW_SUCCESS
Definition: liblwgeom.h:65
POINTARRAY * ptarray_segmentize2d(const POINTARRAY *ipa, double dist)
Returns a modified POINTARRAY so that no segment is longer than the given distance (computed using 2d...
Definition: ptarray.c:420
void printLWPOLY(LWPOLY *poly)
Definition: lwpoly.c:100
#define FLAGS_GET_ZM(flags)
Definition: liblwgeom.h:137
int lwpoly_add_ring(LWPOLY *poly, POINTARRAY *pa)
Add a ring to a polygon.
Definition: lwpoly.c:154
GBOX * bbox
Definition: liblwgeom.h:437
POINTARRAY * ptarray_remove_repeated_points_minpoints(POINTARRAY *in, double tolerance, int minpoints)
Definition: ptarray.c:1437
int32_t srid
Definition: liblwgeom.h:405
double lwpoly_perimeter_2d(const LWPOLY *poly)
Compute the sum of polygon rings length (forcing 2d computation).
Definition: lwpoly.c:462
LWPOLY * lwpoly_clone(const LWPOLY *g)
Definition: lwpoly.c:120
double ptarray_signed_area(const POINTARRAY *pa)
Returns the area in cartesian units.
Definition: ptarray.c:995
int ptarray_is_closed_2d(const POINTARRAY *pa)
Definition: ptarray.c:694
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition: lwgeom.c:836
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:239
#define LW_FAILURE
Definition: liblwgeom.h:64
int lwpoly_is_closed(const LWPOLY *poly)
Definition: lwpoly.c:476
char lwpoly_same(const LWPOLY *p1, const LWPOLY *p2)
Definition: lwpoly.c:234
LWPOLY * lwpoly_construct(int srid, GBOX *bbox, uint32_t nrings, POINTARRAY **points)
Definition: lwpoly.c:29
int ptarray_isccw(const POINTARRAY *pa)
Definition: ptarray.c:1026
#define LW_FALSE
Definition: liblwgeom.h:62
uint8_t type
Definition: liblwgeom.h:435
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:61
LWPOLY * lwpoly_construct_empty(int srid, char hasz, char hasm)
Definition: lwpoly.c:66
POINTARRAY ** rings
Definition: liblwgeom.h:441
LWPOLY * lwpoly_simplify(const LWPOLY *ipoly, double dist, int preserve_collapsed)
Definition: lwpoly.c:351
POINTARRAY * ptarray_clone_deep(const POINTARRAY *ptarray)
Deep clone a pointarray (also clones serialized pointlist)
Definition: ptarray.c:634
#define LW_INSIDE
Constants for point-in-polygon return values.
POINTARRAY * ptarray_force_dims(const POINTARRAY *pa, int hasz, int hasm)
Definition: ptarray.c:1035
int nrings
Definition: liblwgeom.h:439
int lwpoly_contains_point(const LWPOLY *poly, const POINT2D *pt)
Definition: lwpoly.c:509
LWPOLY * lwpoly_from_lwlines(const LWLINE *shell, uint32_t nholes, const LWLINE **holes)
Definition: lwpoly.c:255
LWPOLY * lwpoly_clone_deep(const LWPOLY *g)
Definition: lwpoly.c:135
#define FLAGS_GET_Z(flags)
Macros for manipulating the &#39;flags&#39; byte.
Definition: liblwgeom.h:124
void lwpoly_reverse(LWPOLY *poly)
Definition: lwpoly.c:201
LWPOLY * lwpoly_force_dims(const LWPOLY *poly, int hasz, int hasm)
Definition: lwpoly.c:308
uint8_t gflags(int hasz, int hasm, int geodetic)
Construct a new flags char.
Definition: g_util.c:130
int lwpoly_startpoint(const LWPOLY *poly, POINT4D *pt)
Definition: lwpoly.c:501
LWPOLY * lwpoly_segmentize2d(LWPOLY *poly, double dist)
Definition: lwpoly.c:210
LWGEOM * lwpoly_remove_repeated_points(LWPOLY *poly, double tolerance)
Definition: lwpoly.c:289
int ptarray_startpoint(const POINTARRAY *pa, POINT4D *pt)
Definition: ptarray.c:1826
double ptarray_length(const POINTARRAY *pts)
Find the 3d/2d length of the given POINTARRAY (depending on its dimensionality)
Definition: ptarray.c:1673
POINTARRAY * ptarray_simplify(POINTARRAY *inpts, double epsilon, unsigned int minpts)
Definition: ptarray.c:1554
#define FLAGS_SET_BBOX(flags, value)
Definition: liblwgeom.h:132
int maxrings
Definition: liblwgeom.h:440
void printPA(POINTARRAY *pa)
Definition: lwgeom_api.c:598
int32_t srid
Definition: liblwgeom.h:438
int lwpoly_count_vertices(LWPOLY *poly)
Definition: lwpoly.c:339
char ptarray_same(const POINTARRAY *pa1, const POINTARRAY *pa2)
Definition: ptarray.c:484
void lwpoly_free(LWPOLY *poly)
Definition: lwpoly.c:79
POINTARRAY * ptarray_grid(const POINTARRAY *pa, const gridspec *grid)
Definition: ptarray.c:1843
void * lwrealloc(void *mem, size_t size)
Definition: lwutil.c:207
void ptarray_reverse(POINTARRAY *pa)
Definition: ptarray.c:343
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:125
void lwgeom_release(LWGEOM *lwgeom)
Free the containing LWGEOM and the associated BOX.
Definition: lwgeom.c:372
int ptarray_contains_point(const POINTARRAY *pa, const POINT2D *pt)
Return 1 if the point is inside the POINTARRAY, -1 if it is outside, and 0 if it is on the boundary...
Definition: ptarray.c:733
void lwpoly_force_clockwise(LWPOLY *poly)
Definition: lwpoly.c:175
uint8_t flags
Definition: liblwgeom.h:436
#define LW_OUTSIDE
void * lwalloc(size_t size)
Definition: lwutil.c:199
opts
Definition: ovdump.py:44
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:55
#define FLAGS_NDIMS(flags)
Definition: liblwgeom.h:136
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition: lwgeom.c:843
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:74
int lwpoly_is_empty(const LWPOLY *poly)
Definition: lwpoly.c:332
#define FLAGS_SET_READONLY(flags, value)
Definition: liblwgeom.h:134
POINTARRAY * points
Definition: liblwgeom.h:406
Snap to grid.