PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
lwpoly.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) 2012 Sandro Santilli <strk@kbt.io>
22 * Copyright (C) 2001-2006 Refractions Research Inc.
23 *
24 **********************************************************************/
25
26
27/* basic LWPOLY manipulation */
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <math.h>
33#include "liblwgeom_internal.h"
34#include "lwgeom_log.h"
35
36
37#define CHECK_POLY_RINGS_ZM 1
38
39/* construct a new LWPOLY. arrays (points/points per ring) will NOT be copied
40 * use SRID=SRID_UNKNOWN for unknown SRID (will have 8bit type's S = 0)
41 */
42LWPOLY *
43lwpoly_construct(int32_t srid, GBOX *bbox, uint32_t nrings, POINTARRAY **points)
44{
46 int hasz, hasm;
47#ifdef CHECK_POLY_RINGS_ZM
48 char zm;
49 uint32_t i;
50#endif
51
52 if ( nrings < 1 ) lwerror("lwpoly_construct: need at least 1 ring");
53
54 hasz = FLAGS_GET_Z(points[0]->flags);
55 hasm = FLAGS_GET_M(points[0]->flags);
56
57#ifdef CHECK_POLY_RINGS_ZM
58 zm = FLAGS_GET_ZM(points[0]->flags);
59 for (i=1; i<nrings; i++)
60 {
61 if ( zm != FLAGS_GET_ZM(points[i]->flags) )
62 lwerror("lwpoly_construct: mixed dimensioned rings");
63 }
64#endif
65
66 result = (LWPOLY*) lwalloc(sizeof(LWPOLY));
67 result->type = POLYGONTYPE;
68 result->flags = lwflags(hasz, hasm, 0);
69 FLAGS_SET_BBOX(result->flags, bbox?1:0);
70 result->srid = srid;
71 result->nrings = nrings;
72 result->maxrings = nrings;
73 result->rings = points;
74 result->bbox = bbox;
75
76 return result;
77}
78
79LWPOLY*
80lwpoly_construct_rectangle(char hasz, char hasm, POINT4D *p1, POINT4D *p2,
81 POINT4D *p3, POINT4D *p4)
82{
83 POINTARRAY *pa = ptarray_construct_empty(hasz, hasm, 5);
84 LWPOLY *lwpoly = lwpoly_construct_empty(SRID_UNKNOWN, hasz, hasm);
85
91
92 lwpoly_add_ring(lwpoly, pa);
93
94 return lwpoly;
95}
96
97LWPOLY *
98lwpoly_construct_envelope(int32_t srid, double x1, double y1, double x2, double y2)
99{
100 POINT4D p1, p2, p3, p4;
101 LWPOLY *poly;
102
103 p1.x = x1;
104 p1.y = y1;
105 p2.x = x1;
106 p2.y = y2;
107 p3.x = x2;
108 p3.y = y2;
109 p4.x = x2;
110 p4.y = y1;
111
112 poly = lwpoly_construct_rectangle(0, 0, &p1, &p2, &p3, &p4);
115
116 return poly;
117}
118
119LWPOLY *
120lwpoly_construct_circle(int32_t srid, double x, double y, double radius, uint32_t segments_per_quarter, char exterior)
121{
122 const uint32_t segments = 4*segments_per_quarter;
123 double theta;
124 LWPOLY *lwpoly;
125 POINTARRAY *pa;
126 POINT4D pt;
127 uint32_t i;
128
129 if (segments_per_quarter == 0)
130 {
131 lwerror("Need at least one segment per quarter-circle.");
132 return NULL;
133 }
134
135 if (radius < 0)
136 {
137 lwerror("Radius must be positive.");
138 return NULL;
139 }
140
141 theta = 2*M_PI / segments;
142
144 pa = ptarray_construct_empty(LW_FALSE, LW_FALSE, segments + 1);
145
146 if (exterior)
147 radius *= sqrt(1 + pow(tan(theta/2), 2));
148
149 for (i = 0; i <= segments; i++)
150 {
151 pt.x = x + radius*sin(i * theta);
152 pt.y = y + radius*cos(i * theta);
154 }
155
156 lwpoly_add_ring(lwpoly, pa);
157 return lwpoly;
158}
159
160LWPOLY *
161lwpoly_construct_empty(int32_t srid, char hasz, char hasm)
162{
163 LWPOLY *result = lwalloc(sizeof(LWPOLY));
164 result->type = POLYGONTYPE;
165 result->flags = lwflags(hasz,hasm,0);
166 result->srid = srid;
167 result->nrings = 0;
168 result->maxrings = 1; /* Allocate room for ring, just in case. */
169 result->rings = lwalloc(result->maxrings * sizeof(POINTARRAY*));
170 result->bbox = NULL;
171 return result;
172}
173
174void
176{
177 uint32_t t;
178
179 if (!poly) return;
180
181 if (poly->bbox) lwfree(poly->bbox);
182
183 if ( poly->rings )
184 {
185 for (t = 0; t < poly->nrings; t++)
186 if (poly->rings[t]) ptarray_free(poly->rings[t]);
187 lwfree(poly->rings);
188 }
189
190 lwfree(poly);
191}
192
194{
195 uint32_t t;
196 lwnotice("LWPOLY {");
197 lwnotice(" ndims = %i", (int)FLAGS_NDIMS(poly->flags));
198 lwnotice(" SRID = %i", (int)poly->srid);
199 lwnotice(" nrings = %i", (int)poly->nrings);
200 for (t=0; t<poly->nrings; t++)
201 {
202 lwnotice(" RING # %i :",t);
203 printPA(poly->rings[t]);
204 }
205 lwnotice("}");
206}
207
208/* @brief Clone LWLINE object. Serialized point lists are not copied.
209 *
210 * @see ptarray_clone
211 */
212LWPOLY *
214{
215 uint32_t i;
216 LWPOLY *ret = lwalloc(sizeof(LWPOLY));
217 memcpy(ret, g, sizeof(LWPOLY));
218 ret->rings = lwalloc(sizeof(POINTARRAY *)*g->nrings);
219 for ( i = 0; i < g->nrings; i++ ) {
220 ret->rings[i] = ptarray_clone(g->rings[i]);
221 }
222 if ( g->bbox ) ret->bbox = gbox_copy(g->bbox);
223 return ret;
224}
225
226/* Deep clone LWPOLY object. POINTARRAY are copied, as is ring array */
227LWPOLY *
229{
230 uint32_t i;
231 LWPOLY *ret = lwalloc(sizeof(LWPOLY));
232 memcpy(ret, g, sizeof(LWPOLY));
233 if ( g->bbox ) ret->bbox = gbox_copy(g->bbox);
234 ret->rings = lwalloc(sizeof(POINTARRAY *)*g->nrings);
235 for ( i = 0; i < ret->nrings; i++ )
236 {
237 ret->rings[i] = ptarray_clone_deep(g->rings[i]);
238 }
240 return ret;
241}
242
246int
248{
249 if( ! poly || ! pa )
250 return LW_FAILURE;
251
252 /* We have used up our storage, add some more. */
253 if( poly->nrings >= poly->maxrings )
254 {
255 int new_maxrings = 2 * (poly->nrings + 1);
256 poly->rings = lwrealloc(poly->rings, new_maxrings * sizeof(POINTARRAY*));
257 poly->maxrings = new_maxrings;
258 }
259
260 /* Add the new ring entry. */
261 poly->rings[poly->nrings] = pa;
262 poly->nrings++;
263
264 return LW_SUCCESS;
265}
266
267void
268lwpoly_force_orientation(LWPOLY *poly, int orientation)
269{
270 /* No-op no orientation */
271 if (orientation == LW_NONE) return;
272
273 /* No-op empties */
274 if (lwpoly_is_empty(poly)) return;
275
276 /* External ring */
277 if (!ptarray_has_orientation(poly->rings[0], orientation))
279
280 /* Internal rings must run opposite to external */
281 for (uint32_t i = 1; i < poly->nrings; i++)
282 if (!ptarray_has_orientation(poly->rings[i], -1 * orientation))
284}
285
286int
287lwpoly_has_orientation(const LWPOLY *poly, int orientation)
288{
289 if (lwpoly_is_empty(poly))
290 return LW_TRUE;
291
292 /* Exterior ring matches orientation? */
293 if(!ptarray_has_orientation(poly->rings[0], orientation))
294 return LW_FALSE;
295
296 /* Interior rings are opposite of orientation? */
297 for (uint32_t i = 1; i < poly->nrings; i++)
298 if (!ptarray_has_orientation(poly->rings[i], -1 * orientation))
299 return LW_FALSE;
300
301 return LW_TRUE;
302}
303
304void
306{
308}
309
310LWPOLY *
311lwpoly_segmentize2d(const LWPOLY *poly, double dist)
312{
313 POINTARRAY **newrings;
314 uint32_t i;
315
316 newrings = lwalloc(sizeof(POINTARRAY *)*poly->nrings);
317 for (i=0; i<poly->nrings; i++)
318 {
319 newrings[i] = ptarray_segmentize2d(poly->rings[i], dist);
320 if ( ! newrings[i] )
321 {
322 uint32_t j = 0;
323 for (j = 0; j < i; j++)
324 ptarray_free(newrings[j]);
325 lwfree(newrings);
326 return NULL;
327 }
328 }
329 return lwpoly_construct(poly->srid, NULL,
330 poly->nrings, newrings);
331}
332
333/*
334 * check coordinate equality
335 * ring and coordinate order is considered
336 */
337char
338lwpoly_same(const LWPOLY *p1, const LWPOLY *p2)
339{
340 uint32_t i;
341
342 if ( p1->nrings != p2->nrings ) return 0;
343 for (i=0; i<p1->nrings; i++)
344 {
345 if ( ! ptarray_same(p1->rings[i], p2->rings[i]) )
346 return 0;
347 }
348 return 1;
349}
350
351/*
352 * Construct a polygon from a LWLINE being
353 * the shell and an array of LWLINE (possibly NULL) being holes.
354 * Pointarrays from input geoms are cloned.
355 * SRID must be the same for each input line.
356 * Input lines must have at least 4 points, and be closed.
357 */
358LWPOLY *
360 uint32_t nholes, const LWLINE **holes)
361{
362 uint32_t nrings;
363 POINTARRAY **rings = lwalloc((nholes+1)*sizeof(POINTARRAY *));
364 int32_t srid = shell->srid;
365 LWPOLY *ret;
366
367 if ( shell->points->npoints < 4 )
368 lwerror("lwpoly_from_lwlines: shell must have at least 4 points");
369 if ( ! ptarray_is_closed_2d(shell->points) )
370 lwerror("lwpoly_from_lwlines: shell must be closed");
371 rings[0] = ptarray_clone_deep(shell->points);
372
373 for (nrings=1; nrings<=nholes; nrings++)
374 {
375 const LWLINE *hole = holes[nrings-1];
376
377 if ( hole->srid != srid )
378 lwerror("lwpoly_from_lwlines: mixed SRIDs in input lines");
379
380 if ( hole->points->npoints < 4 )
381 lwerror("lwpoly_from_lwlines: holes must have at least 4 points");
382 if ( ! ptarray_is_closed_2d(hole->points) )
383 lwerror("lwpoly_from_lwlines: holes must be closed");
384
385 rings[nrings] = ptarray_clone_deep(hole->points);
386 }
387
388 ret = lwpoly_construct(srid, NULL, nrings, rings);
389 return ret;
390}
391
392LWPOLY*
393lwpoly_force_dims(const LWPOLY *poly, int hasz, int hasm, double zval, double mval)
394{
395 LWPOLY *polyout;
396
397 /* Return 2D empty */
398 if( lwpoly_is_empty(poly) )
399 {
400 polyout = lwpoly_construct_empty(poly->srid, hasz, hasm);
401 }
402 else
403 {
404 POINTARRAY **rings = NULL;
405 uint32_t i;
406 rings = lwalloc(sizeof(POINTARRAY*) * poly->nrings);
407 for( i = 0; i < poly->nrings; i++ )
408 {
409 rings[i] = ptarray_force_dims(poly->rings[i], hasz, hasm, zval, mval);
410 }
411 polyout = lwpoly_construct(poly->srid, NULL, poly->nrings, rings);
412 }
413 polyout->type = poly->type;
414 return polyout;
415}
416
417uint32_t lwpoly_count_vertices(const LWPOLY *poly)
418{
419 uint32_t i = 0;
420 uint32_t v = 0; /* vertices */
421 assert(poly);
422 for ( i = 0; i < poly->nrings; i ++ )
423 {
424 v += poly->rings[i]->npoints;
425 }
426 return v;
427}
428
432double
433lwpoly_area(const LWPOLY *poly)
434{
435 double poly_area = 0.0;
436 uint32_t i;
437
438 if ( ! poly )
439 lwerror("lwpoly_area called with null polygon pointer!");
440
441 for ( i=0; i < poly->nrings; i++ )
442 {
443 POINTARRAY *ring = poly->rings[i];
444 double ringarea = 0.0;
445
446 /* Empty or messed-up ring. */
447 if ( ring->npoints < 3 )
448 continue;
449
450 ringarea = fabs(ptarray_signed_area(ring));
451 if ( i == 0 ) /* Outer ring, positive area! */
452 poly_area += ringarea;
453 else /* Inner ring, negative area! */
454 poly_area -= ringarea;
455 }
456
457 return poly_area;
458}
459
460
465double
467{
468 double result=0.0;
469 uint32_t i;
470
471 LWDEBUGF(2, "in lwgeom_polygon_perimeter (%d rings)", poly->nrings);
472
473 for (i=0; i<poly->nrings; i++)
474 result += ptarray_length(poly->rings[i]);
475
476 return result;
477}
478
483double
485{
486 double result=0.0;
487 uint32_t i;
488
489 LWDEBUGF(2, "in lwgeom_polygon_perimeter (%d rings)", poly->nrings);
490
491 for (i=0; i<poly->nrings; i++)
492 result += ptarray_length_2d(poly->rings[i]);
493
494 return result;
495}
496
497int
499{
500 uint32_t i = 0;
501
502 if ( poly->nrings == 0 )
503 return LW_TRUE;
504
505 for ( i = 0; i < poly->nrings; i++ )
506 {
507 if (FLAGS_GET_Z(poly->flags))
508 {
509 if ( ! ptarray_is_closed_3d(poly->rings[i]) )
510 return LW_FALSE;
511 }
512 else
513 {
514 if ( ! ptarray_is_closed_2d(poly->rings[i]) )
515 return LW_FALSE;
516 }
517 }
518
519 return LW_TRUE;
520}
521
522int
524{
525 if ( poly->nrings < 1 )
526 return LW_FAILURE;
527 return ptarray_startpoint(poly->rings[0], pt);
528}
529
530int
531lwpoly_contains_point(const LWPOLY *poly, const POINT2D *pt)
532{
533 uint32_t i;
534 int t;
535
536 if ( lwpoly_is_empty(poly) )
537 return LW_OUTSIDE;
538
539 t = ptarray_contains_point(poly->rings[0], pt);
540
541 if (t == LW_INSIDE)
542 {
543 for (i = 1; i < poly->nrings; i++)
544 {
545 t = ptarray_contains_point(poly->rings[i], pt);
546 if (t == LW_INSIDE)
547 return LW_OUTSIDE;
548 if (t == LW_BOUNDARY)
549 {
550 return LW_BOUNDARY;
551 }
552 }
553 return LW_INSIDE;
554 }
555 else
556 return t;
557}
558
559
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition cu_print.c:267
GBOX * gbox_copy(const GBOX *box)
Return a copy of the GBOX, based on dimensionality of flags.
Definition gbox.c:438
#define LW_FALSE
Definition liblwgeom.h:94
void * lwrealloc(void *mem, size_t size)
Definition lwutil.c:242
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
#define LW_FAILURE
Definition liblwgeom.h:96
int ptarray_is_closed_3d(const POINTARRAY *pa)
Definition ptarray.c:723
#define LW_SUCCESS
Definition liblwgeom.h:97
#define FLAGS_SET_BBOX(flags, value)
Definition liblwgeom.h:174
void printPA(POINTARRAY *pa)
Definition lwgeom_api.c:440
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition ptarray.c:59
double ptarray_length_2d(const POINTARRAY *pts)
Find the 2d length of the given POINTARRAY (even if it's 3d)
Definition ptarray.c:1975
#define FLAGS_GET_Z(flags)
Definition liblwgeom.h:165
void * lwalloc(size_t size)
Definition lwutil.c:227
void lwfree(void *mem)
Definition lwutil.c:248
#define FLAGS_NDIMS(flags)
Definition liblwgeom.h:179
#define POLYGONTYPE
Definition liblwgeom.h:104
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:413
#define FLAGS_GET_M(flags)
Definition liblwgeom.h:166
void ptarray_free(POINTARRAY *pa)
Definition ptarray.c:327
#define FLAGS_GET_ZM(flags)
Definition liblwgeom.h:180
int ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int allow_duplicates)
Append a point to the end of an existing POINTARRAY If allow_duplicate is LW_FALSE,...
Definition ptarray.c:147
#define FLAGS_SET_READONLY(flags, value)
Definition liblwgeom.h:176
int ptarray_is_closed_2d(const POINTARRAY *pa)
Definition ptarray.c:710
lwflags_t lwflags(int hasz, int hasm, int geodetic)
Construct a new flags bitmask.
Definition lwutil.c:477
#define LW_TRUE
Return types for functions with status returns.
Definition liblwgeom.h:93
void lwgeom_release(LWGEOM *lwgeom)
Free the containing LWGEOM and the associated BOX.
Definition lwgeom.c:496
#define SRID_UNKNOWN
Unknown SRID value.
Definition liblwgeom.h:215
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition lwgeom.c:357
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition lwgeom.c:723
POINTARRAY * ptarray_clone_deep(const POINTARRAY *ptarray)
Deep clone a pointarray (also clones serialized pointlist)
Definition ptarray.c:643
#define LW_INSIDE
Constants for point-in-polygon return values.
#define LW_BOUNDARY
void ptarray_reverse_in_place(POINTARRAY *pa)
Definition ptarray.c:339
double ptarray_length(const POINTARRAY *pts)
Find the 3d/2d length of the given POINTARRAY (depending on its dimensionality)
Definition ptarray.c:2003
#define LW_NONE
double ptarray_signed_area(const POINTARRAY *pa)
Returns the area in cartesian units.
Definition ptarray.c:1143
int ptarray_startpoint(const POINTARRAY *pa, POINT4D *pt)
Definition ptarray.c:2219
char ptarray_same(const POINTARRAY *pa1, const POINTARRAY *pa2)
Definition ptarray.c:484
int ptarray_contains_point(const POINTARRAY *pa, const POINT2D *pt)
The following is based on the "Fast Winding Number Inclusion of a Point in a Polygon" algorithm by Da...
Definition ptarray.c:755
int ptarray_has_orientation(const POINTARRAY *pa, int orientation)
Definition ptarray.c:1174
int lwpoly_is_empty(const LWPOLY *poly)
#define LW_OUTSIDE
POINTARRAY * ptarray_clone(const POINTARRAY *ptarray)
Clone a POINTARRAY object.
Definition ptarray.c:674
POINTARRAY * ptarray_force_dims(const POINTARRAY *pa, int hasz, int hasm, double zval, double mval)
Definition ptarray.c:1188
#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.
LWPOLY * lwpoly_construct_circle(int32_t srid, double x, double y, double radius, uint32_t segments_per_quarter, char exterior)
Definition lwpoly.c:120
int lwpoly_startpoint(const LWPOLY *poly, POINT4D *pt)
Definition lwpoly.c:523
LWPOLY * lwpoly_from_lwlines(const LWLINE *shell, uint32_t nholes, const LWLINE **holes)
Definition lwpoly.c:359
void printLWPOLY(LWPOLY *poly)
Definition lwpoly.c:193
LWPOLY * lwpoly_clone_deep(const LWPOLY *g)
Definition lwpoly.c:228
LWPOLY * lwpoly_clone(const LWPOLY *g)
Definition lwpoly.c:213
int lwpoly_add_ring(LWPOLY *poly, POINTARRAY *pa)
Add a ring to a polygon.
Definition lwpoly.c:247
double lwpoly_area(const LWPOLY *poly)
Find the area of the outer ring - sum (area of inner rings).
Definition lwpoly.c:433
LWPOLY * lwpoly_construct_envelope(int32_t srid, double x1, double y1, double x2, double y2)
Definition lwpoly.c:98
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
LWPOLY * lwpoly_segmentize2d(const LWPOLY *poly, double dist)
Definition lwpoly.c:311
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
LWPOLY * lwpoly_construct_rectangle(char hasz, char hasm, POINT4D *p1, POINT4D *p2, POINT4D *p3, POINT4D *p4)
Definition lwpoly.c:80
LWPOLY * lwpoly_force_dims(const LWPOLY *poly, int hasz, int hasm, double zval, double mval)
Definition lwpoly.c:393
LWPOLY * lwpoly_construct(int32_t srid, GBOX *bbox, uint32_t nrings, POINTARRAY **points)
Definition lwpoly.c:43
void lwpoly_release(LWPOLY *lwpoly)
Definition lwpoly.c:305
double lwpoly_perimeter_2d(const LWPOLY *poly)
Compute the sum of polygon rings length (forcing 2d computation).
Definition lwpoly.c:484
int lwpoly_contains_point(const LWPOLY *poly, const POINT2D *pt)
Definition lwpoly.c:531
void lwpoly_free(LWPOLY *poly)
Definition lwpoly.c:175
LWPOLY * lwpoly_construct_empty(int32_t srid, char hasz, char hasm)
Definition lwpoly.c:161
int lwpoly_is_closed(const LWPOLY *poly)
Definition lwpoly.c:498
double lwpoly_perimeter(const LWPOLY *poly)
Compute the sum of polygon rings length.
Definition lwpoly.c:466
POINTARRAY * points
Definition liblwgeom.h:483
int32_t srid
Definition liblwgeom.h:484
POINTARRAY ** rings
Definition liblwgeom.h:519
uint8_t type
Definition liblwgeom.h:522
uint32_t maxrings
Definition liblwgeom.h:525
uint32_t nrings
Definition liblwgeom.h:524
GBOX * bbox
Definition liblwgeom.h:518
lwflags_t flags
Definition liblwgeom.h:521
int32_t srid
Definition liblwgeom.h:520
double x
Definition liblwgeom.h:414
double y
Definition liblwgeom.h:414
uint32_t npoints
Definition liblwgeom.h:427