PostGIS 3.0.6dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
lwcollection.c
Go to the documentation of this file.
1/**********************************************************************
2 *
3 * PostGIS - Spatial Types for PostgreSQL
4 * http://postgis.net
5 *
6 * PostGIS is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * PostGIS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18 *
19 **********************************************************************
20 *
21 * Copyright (C) 2001-2006 Refractions Research Inc.
22 *
23 **********************************************************************/
24
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include "liblwgeom_internal.h"
30#include "lwgeom_log.h"
31
32
33#define CHECK_LWGEOM_ZM 1
34
35void
40
42lwcollection_construct(uint8_t type, int32_t srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
43{
44 LWCOLLECTION *ret;
45 int hasz, hasm;
46#ifdef CHECK_LWGEOM_ZM
47 char zm;
48 uint32_t i;
49#endif
50
51 LWDEBUGF(2, "lwcollection_construct called with %d, %d, %p, %d, %p.", type, srid, bbox, ngeoms, geoms);
52
53 if( ! lwtype_is_collection(type) )
54 lwerror("Non-collection type specified in collection constructor!");
55
56 hasz = 0;
57 hasm = 0;
58 if ( ngeoms > 0 )
59 {
60 hasz = FLAGS_GET_Z(geoms[0]->flags);
61 hasm = FLAGS_GET_M(geoms[0]->flags);
62#ifdef CHECK_LWGEOM_ZM
63 zm = FLAGS_GET_ZM(geoms[0]->flags);
64
65 LWDEBUGF(3, "lwcollection_construct type[0]=%d", geoms[0]->type);
66
67 for (i=1; i<ngeoms; i++)
68 {
69 LWDEBUGF(3, "lwcollection_construct type=[%d]=%d", i, geoms[i]->type);
70
71 if ( zm != FLAGS_GET_ZM(geoms[i]->flags) )
72 lwerror("lwcollection_construct: mixed dimension geometries: %d/%d", zm, FLAGS_GET_ZM(geoms[i]->flags));
73 }
74#endif
75 }
76
77
78 ret = lwalloc(sizeof(LWCOLLECTION));
79 ret->type = type;
80 ret->flags = lwflags(hasz,hasm,0);
81 FLAGS_SET_BBOX(ret->flags, bbox?1:0);
82 ret->srid = srid;
83 ret->ngeoms = ngeoms;
84 ret->maxgeoms = ngeoms;
85 ret->geoms = geoms;
86 ret->bbox = bbox;
87
88 return ret;
89}
90
92lwcollection_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
93{
94 LWCOLLECTION *ret;
95 if( ! lwtype_is_collection(type) )
96 {
97 lwerror("Non-collection type specified in collection constructor!");
98 return NULL;
99 }
100
101 ret = lwalloc(sizeof(LWCOLLECTION));
102 ret->type = type;
103 ret->flags = lwflags(hasz,hasm,0);
104 ret->srid = srid;
105 ret->ngeoms = 0;
106 ret->maxgeoms = 1; /* Allocate room for sub-members, just in case. */
107 ret->geoms = lwalloc(ret->maxgeoms * sizeof(LWGEOM*));
108 ret->bbox = NULL;
109
110 return ret;
111}
112
113LWGEOM *
115{
116 return (LWGEOM *)col->geoms[gnum];
117}
118
125{
126 uint32_t i;
127 LWCOLLECTION *ret = lwalloc(sizeof(LWCOLLECTION));
128 memcpy(ret, g, sizeof(LWCOLLECTION));
129 if ( g->ngeoms > 0 )
130 {
131 ret->geoms = lwalloc(sizeof(LWGEOM *)*g->ngeoms);
132 for (i=0; i<g->ngeoms; i++)
133 {
134 ret->geoms[i] = lwgeom_clone(g->geoms[i]);
135 }
136 if ( g->bbox ) ret->bbox = gbox_copy(g->bbox);
137 }
138 else
139 {
140 ret->bbox = NULL; /* empty collection */
141 ret->geoms = NULL;
142 }
143 return ret;
144}
145
151{
152 uint32_t i;
153 LWCOLLECTION *ret = lwalloc(sizeof(LWCOLLECTION));
154 memcpy(ret, g, sizeof(LWCOLLECTION));
155 if ( g->ngeoms > 0 )
156 {
157 ret->geoms = lwalloc(sizeof(LWGEOM *)*g->ngeoms);
158 for (i=0; i<g->ngeoms; i++)
159 {
160 ret->geoms[i] = lwgeom_clone_deep(g->geoms[i]);
161 }
162 if ( g->bbox ) ret->bbox = gbox_copy(g->bbox);
163 }
164 else
165 {
166 ret->bbox = NULL; /* empty collection */
167 ret->geoms = NULL;
168 }
169 return ret;
170}
171
175void lwcollection_reserve(LWCOLLECTION *col, uint32_t ngeoms)
176{
177 if ( ngeoms <= col->maxgeoms ) return;
178
179 /* Allocate more space if we need it */
180 do { col->maxgeoms *= 2; } while ( col->maxgeoms < ngeoms );
181 col->geoms = lwrealloc(col->geoms, sizeof(LWGEOM*) * col->maxgeoms);
182}
183
189{
190 if (!col || !geom) return NULL;
191
192 if (!col->geoms && (col->ngeoms || col->maxgeoms))
193 {
194 lwerror("Collection is in inconsistent state. Null memory but non-zero collection counts.");
195 return NULL;
196 }
197
198 /* Check type compatibility */
199 if ( ! lwcollection_allows_subtype(col->type, geom->type) ) {
200 lwerror("%s cannot contain %s element", lwtype_name(col->type), lwtype_name(geom->type));
201 return NULL;
202 }
203
204 /* In case this is a truly empty, make some initial space */
205 if (!col->geoms)
206 {
207 col->maxgeoms = 2;
208 col->ngeoms = 0;
209 col->geoms = lwalloc(col->maxgeoms * sizeof(LWGEOM*));
210 }
211
212 /* Allocate more space if we need it */
213 lwcollection_reserve(col, col->ngeoms + 1);
214
215#if PARANOIA_LEVEL > 1
216 /* See http://trac.osgeo.org/postgis/ticket/2933 */
217 /* Make sure we don't already have a reference to this geom */
218 {
219 uint32_t i = 0;
220 for (i = 0; i < col->ngeoms; i++)
221 {
222 if (col->geoms[i] == geom)
223 {
224 lwerror("%s [%d] found duplicate geometry in collection %p == %p", __FILE__, __LINE__, col->geoms[i], geom);
225 return col;
226 }
227 }
228 }
229#endif
230
231 col->geoms[col->ngeoms] = (LWGEOM*)geom;
232 col->ngeoms++;
233 return col;
234}
235
242{
243 uint32_t i;
244 if (!col1 || !col2) return NULL;
245 for (i = 0; i < col2->ngeoms; i++)
246 col1 = lwcollection_add_lwgeom(col1, col2->geoms[i]);
247 return col1;
248}
249
252{
253 uint32_t i, j;
254 LWGEOM** newgeoms;
255
256 if (!col->ngeoms) return lwcollection_clone(col);
257
258 newgeoms = lwalloc(sizeof(LWGEOM*) * col->ngeoms);
259 for (i = 0; i < col->ngeoms; i++)
260 {
261 newgeoms[i] = lwgeom_segmentize2d(col->geoms[i], dist);
262 if (!newgeoms[i])
263 {
264 for (j = 0; j < i; j++)
265 lwgeom_free(newgeoms[j]);
266 lwfree(newgeoms);
267 return NULL;
268 }
269 }
270
272 col->type, col->srid, NULL, col->ngeoms, newgeoms);
273}
274
278char
280{
281 uint32_t i;
282
283 LWDEBUG(2, "lwcollection_same called");
284
285 if ( c1->type != c2->type ) return LW_FALSE;
286 if ( c1->ngeoms != c2->ngeoms ) return LW_FALSE;
287
288 for ( i = 0; i < c1->ngeoms; i++ )
289 {
290 if ( ! lwgeom_same(c1->geoms[i], c2->geoms[i]) )
291 return LW_FALSE;
292 }
293
294 /* Former method allowed out-of-order equality between collections
295
296 hit = lwalloc(sizeof(uint32_t)*c1->ngeoms);
297 memset(hit, 0, sizeof(uint32_t)*c1->ngeoms);
298
299 for (i=0; i<c1->ngeoms; i++)
300 {
301 char found=0;
302 for (j=0; j<c2->ngeoms; j++)
303 {
304 if ( hit[j] ) continue;
305 if ( lwgeom_same(c1->geoms[i], c2->geoms[j]) )
306 {
307 hit[j] = 1;
308 found=1;
309 break;
310 }
311 }
312 if ( ! found ) return LW_FALSE;
313 }
314 */
315
316 return LW_TRUE;
317}
318
320{
321 uint32_t i;
322 int ngeoms = 0;
323
324 if ( ! col )
325 {
326 lwerror("Null input geometry.");
327 return 0;
328 }
329
330 for ( i = 0; i < col->ngeoms; i++ )
331 {
332 if ( col->geoms[i])
333 {
334 switch (col->geoms[i]->type)
335 {
336 case POINTTYPE:
337 case LINETYPE:
338 case CIRCSTRINGTYPE:
339 case POLYGONTYPE:
340 ngeoms += 1;
341 break;
342 case MULTIPOINTTYPE:
343 case MULTILINETYPE:
344 case MULTICURVETYPE:
345 case MULTIPOLYGONTYPE:
346 ngeoms += col->ngeoms;
347 break;
348 case COLLECTIONTYPE:
349 ngeoms += lwcollection_ngeoms((LWCOLLECTION*)col->geoms[i]);
350 break;
351 }
352 }
353 }
354 return ngeoms;
355}
356
358{
359 uint32_t i;
360 if ( ! col ) return;
361
362 if ( col->bbox )
363 {
364 lwfree(col->bbox);
365 }
366 for ( i = 0; i < col->ngeoms; i++ )
367 {
368 LWDEBUGF(4,"freeing geom[%d]", i);
369 if ( col->geoms && col->geoms[i] )
370 lwgeom_free(col->geoms[i]);
371 }
372 if ( col->geoms )
373 {
374 lwfree(col->geoms);
375 }
376 lwfree(col);
377}
378
379
388{
389 uint32_t i = 0;
390 LWGEOM** geomlist;
391 LWCOLLECTION* outcol;
392 int geomlistsize = 16;
393 int geomlistlen = 0;
394 uint8_t outtype;
395
396 if (!col) return NULL;
397
398 switch (type)
399 {
400 case POINTTYPE:
401 outtype = MULTIPOINTTYPE;
402 break;
403 case LINETYPE:
404 outtype = MULTILINETYPE;
405 break;
406 case POLYGONTYPE:
407 outtype = MULTIPOLYGONTYPE;
408 break;
409 default:
410 lwerror(
411 "Only POLYGON, LINESTRING and POINT are supported by "
412 "lwcollection_extract. %s requested.",
413 lwtype_name(type));
414 return NULL;
415 }
416
417 geomlist = lwalloc(sizeof(LWGEOM*) * geomlistsize);
418
419 /* Process each sub-geometry */
420 for (i = 0; i < col->ngeoms; i++)
421 {
422 int subtype = col->geoms[i]->type;
423 /* Don't bother adding empty sub-geometries */
424 if (lwgeom_is_empty(col->geoms[i])) continue;
425 /* Copy our sub-types into the output list */
426 if (subtype == type)
427 {
428 /* We've over-run our buffer, double the memory segment
429 */
430 if (geomlistlen == geomlistsize)
431 {
432 geomlistsize *= 2;
433 geomlist = lwrealloc(
434 geomlist, sizeof(LWGEOM*) * geomlistsize);
435 }
436 geomlist[geomlistlen] = lwgeom_clone(col->geoms[i]);
437 geomlistlen++;
438 }
439 /* Recurse into sub-collections */
440 if (lwtype_is_collection(subtype))
441 {
442 uint32_t j = 0;
444 (LWCOLLECTION*)col->geoms[i], type);
445 for (j = 0; j < tmpcol->ngeoms; j++)
446 {
447 /* We've over-run our buffer, double the memory
448 * segment */
449 if (geomlistlen == geomlistsize)
450 {
451 geomlistsize *= 2;
452 geomlist = lwrealloc(geomlist,
453 sizeof(LWGEOM*) *
454 geomlistsize);
455 }
456 geomlist[geomlistlen] = tmpcol->geoms[j];
457 geomlistlen++;
458 }
459 if (tmpcol->ngeoms) lwfree(tmpcol->geoms);
460 if (tmpcol->bbox) lwfree(tmpcol->bbox);
461 lwfree(tmpcol);
462 }
463 }
464
465 if (geomlistlen > 0)
466 {
467 GBOX gbox;
468 outcol = lwcollection_construct(
469 outtype, col->srid, NULL, geomlistlen, geomlist);
470 lwgeom_calculate_gbox((LWGEOM*)outcol, &gbox);
471 outcol->bbox = gbox_copy(&gbox);
472 }
473 else
474 {
475 lwfree(geomlist);
476 outcol = lwcollection_construct_empty(outtype,
477 col->srid,
478 FLAGS_GET_Z(col->flags),
479 FLAGS_GET_M(col->flags));
480 }
481
482 return outcol;
483}
484
486lwcollection_force_dims(const LWCOLLECTION *col, int hasz, int hasm)
487{
488 LWCOLLECTION *colout;
489
490 /* Return 2D empty */
491 if( lwcollection_is_empty(col) )
492 {
493 colout = lwcollection_construct_empty(col->type, col->srid, hasz, hasm);
494 }
495 else
496 {
497 uint32_t i;
498 LWGEOM **geoms = NULL;
499 geoms = lwalloc(sizeof(LWGEOM*) * col->ngeoms);
500 for( i = 0; i < col->ngeoms; i++ )
501 {
502 geoms[i] = lwgeom_force_dims(col->geoms[i], hasz, hasm);
503 }
504 colout = lwcollection_construct(col->type, col->srid, NULL, col->ngeoms, geoms);
505 }
506 return colout;
507}
508
509
511{
512 uint32_t i = 0;
513 uint32_t v = 0; /* vertices */
514 assert(col);
515 for ( i = 0; i < col->ngeoms; i++ )
516 {
517 v += lwgeom_count_vertices(col->geoms[i]);
518 }
519 return v;
520}
521
522
523int lwcollection_allows_subtype(int collectiontype, int subtype)
524{
525 if ( collectiontype == COLLECTIONTYPE )
526 return LW_TRUE;
527 if ( collectiontype == MULTIPOINTTYPE &&
528 subtype == POINTTYPE )
529 return LW_TRUE;
530 if ( collectiontype == MULTILINETYPE &&
531 subtype == LINETYPE )
532 return LW_TRUE;
533 if ( collectiontype == MULTIPOLYGONTYPE &&
534 subtype == POLYGONTYPE )
535 return LW_TRUE;
536 if ( collectiontype == COMPOUNDTYPE &&
537 (subtype == LINETYPE || subtype == CIRCSTRINGTYPE) )
538 return LW_TRUE;
539 if ( collectiontype == CURVEPOLYTYPE &&
540 (subtype == CIRCSTRINGTYPE || subtype == LINETYPE || subtype == COMPOUNDTYPE) )
541 return LW_TRUE;
542 if ( collectiontype == MULTICURVETYPE &&
543 (subtype == CIRCSTRINGTYPE || subtype == LINETYPE || subtype == COMPOUNDTYPE) )
544 return LW_TRUE;
545 if ( collectiontype == MULTISURFACETYPE &&
546 (subtype == POLYGONTYPE || subtype == CURVEPOLYTYPE) )
547 return LW_TRUE;
548 if ( collectiontype == POLYHEDRALSURFACETYPE &&
549 subtype == POLYGONTYPE )
550 return LW_TRUE;
551 if ( collectiontype == TINTYPE &&
552 subtype == TRIANGLETYPE )
553 return LW_TRUE;
554
555 /* Must be a bad combination! */
556 return LW_FALSE;
557}
558
559int
561{
562 if ( col->ngeoms < 1 )
563 return LW_FAILURE;
564
565 return lwgeom_startpoint(col->geoms[0], pt);
566}
567
568
GBOX * gbox_copy(const GBOX *box)
Return a copy of the GBOX, based on dimensionality of flags.
Definition gbox.c:426
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition lwutil.c:216
char lwgeom_same(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)
geom1 same as geom2 iff
Definition lwgeom.c:573
#define LW_FALSE
Definition liblwgeom.h:108
#define COLLECTIONTYPE
Definition liblwgeom.h:122
#define COMPOUNDTYPE
Definition liblwgeom.h:124
void * lwrealloc(void *mem, size_t size)
Definition lwutil.c:235
int lwgeom_startpoint(const LWGEOM *lwgeom, POINT4D *pt)
Definition lwgeom.c:2113
#define LW_FAILURE
Definition liblwgeom.h:110
void lwgeom_free(LWGEOM *geom)
Definition lwgeom.c:1138
#define CURVEPOLYTYPE
Definition liblwgeom.h:125
#define MULTILINETYPE
Definition liblwgeom.h:120
#define MULTISURFACETYPE
Definition liblwgeom.h:127
#define LINETYPE
Definition liblwgeom.h:117
#define MULTIPOINTTYPE
Definition liblwgeom.h:119
#define FLAGS_SET_BBOX(flags, value)
Definition liblwgeom.h:188
LWGEOM * lwgeom_clone(const LWGEOM *lwgeom)
Clone LWGEOM object.
Definition lwgeom.c:473
int lwtype_is_collection(uint8_t type)
Determine whether a type number is a collection or not.
Definition lwgeom.c:1087
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition liblwgeom.h:116
#define FLAGS_GET_Z(flags)
Definition liblwgeom.h:179
void * lwalloc(size_t size)
Definition lwutil.c:227
#define TINTYPE
Definition liblwgeom.h:130
#define MULTIPOLYGONTYPE
Definition liblwgeom.h:121
uint32_t lwgeom_count_vertices(const LWGEOM *geom)
Count the total number of vertices in any LWGEOM.
Definition lwgeom.c:1229
void lwfree(void *mem)
Definition lwutil.c:242
#define POLYGONTYPE
Definition liblwgeom.h:118
#define POLYHEDRALSURFACETYPE
Definition liblwgeom.h:128
#define CIRCSTRINGTYPE
Definition liblwgeom.h:123
#define FLAGS_GET_M(flags)
Definition liblwgeom.h:180
#define FLAGS_GET_ZM(flags)
Definition liblwgeom.h:194
int lwgeom_calculate_gbox(const LWGEOM *lwgeom, GBOX *gbox)
Calculate bounding box of a geometry, automatically taking into account whether it is cartesian or ge...
Definition lwgeom.c:737
#define MULTICURVETYPE
Definition liblwgeom.h:126
#define TRIANGLETYPE
Definition liblwgeom.h:129
lwflags_t lwflags(int hasz, int hasm, int geodetic)
Construct a new flags bitmask.
Definition lwutil.c:471
#define LW_TRUE
Return types for functions with status returns.
Definition liblwgeom.h:107
void lwgeom_release(LWGEOM *lwgeom)
Free the containing LWGEOM and the associated BOX.
Definition lwgeom.c:450
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition lwgeom.c:291
LWGEOM * lwgeom_segmentize2d(const LWGEOM *line, double dist)
Definition lwgeom.c:753
LWGEOM * lwgeom_clone_deep(const LWGEOM *lwgeom)
Deep clone an LWGEOM, everything is copied.
Definition lwgeom.c:511
LWGEOM * lwgeom_force_dims(const LWGEOM *lwgeom, int hasz, int hasm)
Definition lwgeom.c:799
int lwcollection_is_empty(const LWCOLLECTION *col)
LWCOLLECTION * lwcollection_construct(uint8_t type, int32_t srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
LWCOLLECTION * lwcollection_clone(const LWCOLLECTION *g)
Clone LWCOLLECTION object.
LWCOLLECTION * lwcollection_extract(LWCOLLECTION *col, int type)
Takes a potentially heterogeneous collection and returns a homogeneous collection consisting only of ...
char lwcollection_same(const LWCOLLECTION *c1, const LWCOLLECTION *c2)
check for same geometry composition
LWCOLLECTION * lwcollection_segmentize2d(const LWCOLLECTION *col, double dist)
int lwcollection_startpoint(const LWCOLLECTION *col, POINT4D *pt)
LWCOLLECTION * lwcollection_force_dims(const LWCOLLECTION *col, int hasz, int hasm)
void lwcollection_release(LWCOLLECTION *lwcollection)
LWCOLLECTION * lwcollection_clone_deep(const LWCOLLECTION *g)
Deep clone LWCOLLECTION object.
void lwcollection_free(LWCOLLECTION *col)
int lwcollection_ngeoms(const LWCOLLECTION *col)
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
void lwcollection_reserve(LWCOLLECTION *col, uint32_t ngeoms)
Ensure the collection can hold up at least ngeoms.
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
uint32_t lwcollection_count_vertices(LWCOLLECTION *col)
int lwcollection_allows_subtype(int collectiontype, int subtype)
Check if subtype is allowed in collectiontype.
LWCOLLECTION * lwcollection_concat_in_place(LWCOLLECTION *col1, const LWCOLLECTION *col2)
Appends all geometries from col2 to col1 in place.
LWGEOM * lwcollection_getsubgeom(LWCOLLECTION *col, int gnum)
#define LWDEBUG(level, msg)
Definition lwgeom_log.h:83
#define LWDEBUGF(level, msg,...)
Definition lwgeom_log.h:88
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition lwutil.c:190
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:193
lwflags_t flags
Definition liblwgeom.h:563
uint32_t ngeoms
Definition liblwgeom.h:566
uint32_t maxgeoms
Definition liblwgeom.h:567
uint8_t type
Definition liblwgeom.h:564
GBOX * bbox
Definition liblwgeom.h:560
LWGEOM ** geoms
Definition liblwgeom.h:561
int32_t srid
Definition liblwgeom.h:562
uint8_t type
Definition liblwgeom.h:448
GBOX * bbox
Definition liblwgeom.h:444