root/trunk/liblwgeom/lwcollection.c

Revision 9324, 12.5 KB (checked in by pramsey, 3 months ago)

Try again with line endings, this time using eol-style instead of eol-type (#1605)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/**********************************************************************
2 *
3 * PostGIS - Spatial Types for PostgreSQL
4 * http://postgis.refractions.net
5 *
6 * Copyright (C) 2001-2006 Refractions Research Inc.
7 *
8 * This is free software; you can redistribute and/or modify it under
9 * the terms of the GNU General Public Licence. See the COPYING file.
10 *
11 **********************************************************************/
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include "liblwgeom_internal.h"
17#include "lwgeom_log.h"
18
19
20#define CHECK_LWGEOM_ZM 1
21
22void
23lwcollection_release(LWCOLLECTION *lwcollection)
24{
25        lwgeom_release(lwcollection_as_lwgeom(lwcollection));
26}
27
28
29LWCOLLECTION *
30lwcollection_construct(uint8_t type, int srid, GBOX *bbox,
31                       uint32_t ngeoms, LWGEOM **geoms)
32{
33        LWCOLLECTION *ret;
34        int hasz, hasm;
35#ifdef CHECK_LWGEOM_ZM
36        char zm;
37        uint32_t i;
38#endif
39
40        LWDEBUGF(2, "lwcollection_construct called with %d, %d, %p, %d, %p.", type, srid, bbox, ngeoms, geoms);
41
42        if( ! lwtype_is_collection(type) )
43                lwerror("Non-collection type specified in collection constructor!");
44
45        hasz = 0;
46        hasm = 0;
47        if ( ngeoms > 0 )
48        {
49                hasz = FLAGS_GET_Z(geoms[0]->flags);
50                hasm = FLAGS_GET_M(geoms[0]->flags);
51#ifdef CHECK_LWGEOM_ZM
52                zm = FLAGS_GET_ZM(geoms[0]->flags);
53
54                LWDEBUGF(3, "lwcollection_construct type[0]=%d", geoms[0]->type);
55
56                for (i=1; i<ngeoms; i++)
57                {
58                        LWDEBUGF(3, "lwcollection_construct type=[%d]=%d", i, geoms[i]->type);
59
60                        if ( zm != FLAGS_GET_ZM(geoms[i]->flags) )
61                                lwerror("lwcollection_construct: mixed dimension geometries: %d/%d", zm, FLAGS_GET_ZM(geoms[i]->flags));
62                }
63#endif
64        }
65
66
67        ret = lwalloc(sizeof(LWCOLLECTION));
68        ret->type = type;
69        ret->flags = gflags(hasz,hasm,0);
70        FLAGS_SET_BBOX(ret->flags, bbox?1:0);
71        ret->srid = srid;
72        ret->ngeoms = ngeoms;
73        ret->maxgeoms = ngeoms;
74        ret->geoms = geoms;
75        ret->bbox = bbox;
76
77        return ret;
78}
79
80LWCOLLECTION *
81lwcollection_construct_empty(uint8_t type, int srid, char hasz, char hasm)
82{
83        LWCOLLECTION *ret;
84        if( ! lwtype_is_collection(type) )
85                lwerror("Non-collection type specified in collection constructor!");
86
87        ret = lwalloc(sizeof(LWCOLLECTION));
88        ret->type = type;
89        ret->flags = gflags(hasz,hasm,0);
90        ret->srid = srid;
91        ret->ngeoms = 0;
92        ret->maxgeoms = 1; /* Allocate room for sub-members, just in case. */
93        ret->geoms = lwalloc(ret->maxgeoms * sizeof(LWGEOM*));
94        ret->bbox = NULL;
95
96        return ret;
97}
98
99LWGEOM *
100lwcollection_getsubgeom(LWCOLLECTION *col, int gnum)
101{
102        return (LWGEOM *)col->geoms[gnum];
103}
104
105/**
106 * @brief Clone #LWCOLLECTION object. #POINTARRAY are not copied.
107 *                      Bbox is cloned if present in input.
108 */
109LWCOLLECTION *
110lwcollection_clone(const LWCOLLECTION *g)
111{
112        uint32_t i;
113        LWCOLLECTION *ret = lwalloc(sizeof(LWCOLLECTION));
114        memcpy(ret, g, sizeof(LWCOLLECTION));
115        if ( g->ngeoms > 0 )
116        {
117                ret->geoms = lwalloc(sizeof(LWGEOM *)*g->ngeoms);
118                for (i=0; i<g->ngeoms; i++)
119                {
120                        ret->geoms[i] = lwgeom_clone(g->geoms[i]);
121                }
122                if ( g->bbox ) ret->bbox = gbox_copy(g->bbox);
123        }
124        else
125        {
126                ret->bbox = NULL; /* empty collection */
127                ret->geoms = NULL;
128        }
129        return ret;
130}
131
132/**
133* @brief Deep clone #LWCOLLECTION object. #POINTARRAY are copied.
134*/
135LWCOLLECTION *
136lwcollection_clone_deep(const LWCOLLECTION *g)
137{
138        uint32_t i;
139        LWCOLLECTION *ret = lwalloc(sizeof(LWCOLLECTION));
140        memcpy(ret, g, sizeof(LWCOLLECTION));
141        if ( g->ngeoms > 0 )
142        {
143                ret->geoms = lwalloc(sizeof(LWGEOM *)*g->ngeoms);
144                for (i=0; i<g->ngeoms; i++)
145                {
146                        ret->geoms[i] = lwgeom_clone_deep(g->geoms[i]);
147                }
148                if ( g->bbox ) ret->bbox = gbox_copy(g->bbox);
149        }
150        else
151        {
152                ret->bbox = NULL; /* empty collection */
153                ret->geoms = NULL;
154        }
155        return ret;
156}
157
158/**
159 * Ensure the collection can hold up at least ngeoms
160 */
161void lwcollection_reserve(LWCOLLECTION *col, int ngeoms)
162{
163        if ( ngeoms <= col->maxgeoms ) return;
164
165        /* Allocate more space if we need it */
166        do { col->maxgeoms *= 2; } while ( col->maxgeoms < ngeoms );
167        col->geoms = lwrealloc(col->geoms, sizeof(LWGEOM*) * col->maxgeoms);
168}
169
170/**
171* Appends geom to the collection managed by col. Does not copy or
172* clone, simply takes a reference on the passed geom.
173*/
174LWCOLLECTION* lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
175{
176        int i = 0;
177
178        if ( col == NULL || geom == NULL ) return NULL;
179
180        if ( col->geoms == NULL && (col->ngeoms || col->maxgeoms) ) {
181                lwerror("Collection is in inconsistent state. Null memory but non-zero collection counts.");
182                return NULL;
183        }
184
185        /* Check type compatibility */
186        if ( ! lwcollection_allows_subtype(col->type, geom->type) ) {
187                lwerror("%s cannot contain %s element", lwtype_name(col->type), lwtype_name(geom->type));
188                return NULL;
189        }
190
191        /* In case this is a truly empty, make some initial space  */
192        if ( col->geoms == NULL )
193        {
194                col->maxgeoms = 2;
195                col->ngeoms = 0;
196                col->geoms = lwalloc(col->maxgeoms * sizeof(LWGEOM*));
197        }
198
199        /* Allocate more space if we need it */
200        lwcollection_reserve(col, col->ngeoms + 1);
201
202        /* Make sure we don't already have a reference to this geom */
203        /* TODO: drop this check ... */
204        for ( i = 0; i < col->ngeoms; i++ )
205        {
206                if ( col->geoms[i] == geom )
207                {
208                        LWDEBUGF(4, "Found duplicate geometry in collection %p == %p", col->geoms[i], geom);
209                        return col;
210                }
211        }
212
213        col->geoms[col->ngeoms] = (LWGEOM*)geom;
214        col->ngeoms++;
215        return col;
216}
217
218
219LWCOLLECTION *
220lwcollection_segmentize2d(LWCOLLECTION *col, double dist)
221{
222        uint32_t i;
223        LWGEOM **newgeoms;
224
225        if ( ! col->ngeoms ) return lwcollection_clone(col);
226
227        newgeoms = lwalloc(sizeof(LWGEOM *)*col->ngeoms);
228        for (i=0; i<col->ngeoms; i++)
229                newgeoms[i] = lwgeom_segmentize2d(col->geoms[i], dist);
230
231        return lwcollection_construct(col->type, col->srid, NULL, col->ngeoms, newgeoms);
232}
233
234/** @brief check for same geometry composition
235 *
236 */
237char
238lwcollection_same(const LWCOLLECTION *c1, const LWCOLLECTION *c2)
239{
240        uint32_t i;
241
242        LWDEBUG(2, "lwcollection_same called");
243
244        if ( c1->type != c2->type ) return LW_FALSE;
245        if ( c1->ngeoms != c2->ngeoms ) return LW_FALSE;
246
247        for ( i = 0; i < c1->ngeoms; i++ )
248        {
249                if ( ! lwgeom_same(c1->geoms[i], c2->geoms[i]) )
250                        return LW_FALSE;
251        }
252
253        /* Former method allowed out-of-order equality between collections
254
255                hit = lwalloc(sizeof(uint32_t)*c1->ngeoms);
256                memset(hit, 0, sizeof(uint32_t)*c1->ngeoms);
257
258                for (i=0; i<c1->ngeoms; i++)
259                {
260                        char found=0;
261                        for (j=0; j<c2->ngeoms; j++)
262                        {
263                                if ( hit[j] ) continue;
264                                if ( lwgeom_same(c1->geoms[i], c2->geoms[j]) )
265                                {
266                                        hit[j] = 1;
267                                        found=1;
268                                        break;
269                                }
270                        }
271                        if ( ! found ) return LW_FALSE;
272                }
273        */
274
275        return LW_TRUE;
276}
277
278int lwcollection_ngeoms(const LWCOLLECTION *col)
279{
280        int i;
281        int ngeoms = 0;
282
283        if ( ! col )
284        {
285                lwerror("Null input geometry.");
286                return 0;
287        }
288
289        for ( i = 0; i < col->ngeoms; i++ )
290        {
291                if ( col->geoms[i])
292                {
293                        switch (col->geoms[i]->type)
294                        {
295                        case POINTTYPE:
296                        case LINETYPE:
297                        case CIRCSTRINGTYPE:
298                        case POLYGONTYPE:
299                                ngeoms += 1;
300                                break;
301                        case MULTIPOINTTYPE:
302                        case MULTILINETYPE:
303                        case MULTICURVETYPE:
304                        case MULTIPOLYGONTYPE:
305                                ngeoms += col->ngeoms;
306                                break;
307                        case COLLECTIONTYPE:
308                                ngeoms += lwcollection_ngeoms((LWCOLLECTION*)col->geoms[i]);
309                                break;
310                        }
311                }
312        }
313        return ngeoms;
314}
315
316void lwcollection_free(LWCOLLECTION *col)
317{
318        int i;
319        if ( ! col ) return;
320       
321        if ( col->bbox )
322        {
323                lwfree(col->bbox);
324        }
325        for ( i = 0; i < col->ngeoms; i++ )
326        {
327                LWDEBUGF(4,"freeing geom[%d]", i);
328                if ( col->geoms && col->geoms[i] )
329                        lwgeom_free(col->geoms[i]);
330        }
331        if ( col->geoms )
332        {
333                lwfree(col->geoms);
334        }
335        lwfree(col);
336}
337
338
339/**
340* Takes a potentially heterogeneous collection and returns a homogeneous
341* collection consisting only of the specified type.
342*/
343LWCOLLECTION* lwcollection_extract(LWCOLLECTION *col, int type)
344{
345        int i = 0;
346        LWGEOM **geomlist;
347        LWCOLLECTION *outcol;
348        int geomlistsize = 16;
349        int geomlistlen = 0;
350        uint8_t outtype;
351
352        if ( ! col ) return NULL;
353
354        switch (type)
355        {
356        case POINTTYPE:
357                outtype = MULTIPOINTTYPE;
358                break;
359        case LINETYPE:
360                outtype = MULTILINETYPE;
361                break;
362        case POLYGONTYPE:
363                outtype = MULTIPOLYGONTYPE;
364                break;
365        default:
366                lwerror("Only POLYGON, LINESTRING and POINT are supported by lwcollection_extract. %s requested.", lwtype_name(type));
367                return NULL;
368        }
369
370        geomlist = lwalloc(sizeof(LWGEOM*) * geomlistsize);
371
372        /* Process each sub-geometry */
373        for ( i = 0; i < col->ngeoms; i++ )
374        {
375                int subtype = col->geoms[i]->type;
376                /* Don't bother adding empty sub-geometries */
377                if ( lwgeom_is_empty(col->geoms[i]) )
378                {
379                        continue;
380                }
381                /* Copy our sub-types into the output list */
382                if ( subtype == type )
383                {
384                        /* We've over-run our buffer, double the memory segment */
385                        if ( geomlistlen == geomlistsize )
386                        {
387                                geomlistsize *= 2;
388                                geomlist = lwrealloc(geomlist, sizeof(LWGEOM*) * geomlistsize);
389                        }
390                        geomlist[geomlistlen] = lwgeom_clone(col->geoms[i]);
391                        geomlistlen++;
392                }
393                /* Recurse into sub-collections */
394                if ( lwtype_is_collection( subtype ) )
395                {
396                        int j = 0;
397                        LWCOLLECTION *tmpcol = lwcollection_extract((LWCOLLECTION*)col->geoms[i], type);
398                        for ( j = 0; j < tmpcol->ngeoms; j++ )
399                        {
400                                /* We've over-run our buffer, double the memory segment */
401                                if ( geomlistlen == geomlistsize )
402                                {
403                                        geomlistsize *= 2;
404                                        geomlist = lwrealloc(geomlist, sizeof(LWGEOM*) * geomlistsize);
405                                }
406                                geomlist[geomlistlen] = tmpcol->geoms[j];
407                                geomlistlen++;
408                        }
409                        lwfree(tmpcol);
410                }
411        }
412
413        if ( geomlistlen > 0 )
414        {
415                GBOX gbox;
416                outcol = lwcollection_construct(outtype, col->srid, NULL, geomlistlen, geomlist);
417                lwgeom_calculate_gbox((LWGEOM *) outcol, &gbox);
418                outcol->bbox = gbox_copy(&gbox);
419        }
420        else
421        {
422                lwfree(geomlist);
423                outcol = lwcollection_construct_empty(outtype, col->srid, FLAGS_GET_Z(col->flags), FLAGS_GET_M(col->flags));
424        }
425
426        return outcol;
427}
428
429LWGEOM*
430lwcollection_remove_repeated_points(LWCOLLECTION *coll)
431{
432        uint32_t i;
433        LWGEOM **newgeoms;
434
435        newgeoms = lwalloc(sizeof(LWGEOM *)*coll->ngeoms);
436        for (i=0; i<coll->ngeoms; i++)
437        {
438                newgeoms[i] = lwgeom_remove_repeated_points(coll->geoms[i]);
439        }
440
441        return (LWGEOM*)lwcollection_construct(coll->type,
442                                               coll->srid, coll->bbox ? gbox_copy(coll->bbox) : NULL,
443                                               coll->ngeoms, newgeoms);
444}
445
446
447LWCOLLECTION*
448lwcollection_force_dims(const LWCOLLECTION *col, int hasz, int hasm)
449{
450        LWCOLLECTION *colout;
451       
452        /* Return 2D empty */
453        if( lwcollection_is_empty(col) )
454        {
455                colout = lwcollection_construct_empty(col->type, col->srid, hasz, hasm);
456        }
457        else
458        {
459                int i;
460                LWGEOM **geoms = NULL;
461                geoms = lwalloc(sizeof(LWGEOM*) * col->ngeoms);
462                for( i = 0; i < col->ngeoms; i++ )
463                {
464                        geoms[i] = lwgeom_force_dims(col->geoms[i], hasz, hasm);
465                }
466                colout = lwcollection_construct(col->type, col->srid, NULL, col->ngeoms, geoms);
467        }
468        return colout;
469}
470
471int lwcollection_is_empty(const LWCOLLECTION *col)
472{
473        int i;
474        if ( (col->ngeoms == 0) || (!col->geoms) )
475                return LW_TRUE;
476        for( i = 0; i < col->ngeoms; i++ )
477        {
478                if ( ! lwgeom_is_empty(col->geoms[i]) ) return LW_FALSE;
479        }
480        return LW_TRUE;
481}
482
483
484int lwcollection_count_vertices(LWCOLLECTION *col)
485{
486        int i = 0;
487        int v = 0; /* vertices */
488        assert(col);
489        for ( i = 0; i < col->ngeoms; i++ )
490        {
491                v += lwgeom_count_vertices(col->geoms[i]);
492        }
493        return v;
494}
495
496LWCOLLECTION* lwcollection_simplify(const LWCOLLECTION *igeom, double dist)
497{
498        int i;
499        LWCOLLECTION *out = lwcollection_construct_empty(igeom->type, igeom->srid, FLAGS_GET_Z(igeom->flags), FLAGS_GET_M(igeom->flags));
500
501        if( lwcollection_is_empty(igeom) )
502                return out;
503
504        for( i = 0; i < igeom->ngeoms; i++ )
505        {
506                LWGEOM *ngeom = lwgeom_simplify(igeom->geoms[i], dist);
507                out = lwcollection_add_lwgeom(out, ngeom);
508        }
509
510        return out;
511}
512
513int lwcollection_allows_subtype(int collectiontype, int subtype)
514{
515        if ( collectiontype == COLLECTIONTYPE )
516                return LW_TRUE;
517        if ( collectiontype == MULTIPOINTTYPE &&
518                subtype == POINTTYPE )
519                return LW_TRUE;
520        if ( collectiontype == MULTILINETYPE &&
521                subtype == LINETYPE )
522                return LW_TRUE;
523        if ( collectiontype == MULTIPOLYGONTYPE &&
524                subtype == POLYGONTYPE )
525                return LW_TRUE;
526        if ( collectiontype == COMPOUNDTYPE &&
527                (subtype == LINETYPE || subtype == CIRCSTRINGTYPE) )
528                return LW_TRUE;
529        if ( collectiontype == CURVEPOLYTYPE &&
530                (subtype == CIRCSTRINGTYPE || subtype == LINETYPE || subtype == COMPOUNDTYPE) )
531                return LW_TRUE;
532        if ( collectiontype == MULTICURVETYPE &&
533                (subtype == CIRCSTRINGTYPE || subtype == LINETYPE || subtype == COMPOUNDTYPE) )
534                return LW_TRUE;
535        if ( collectiontype == MULTISURFACETYPE &&
536                (subtype == POLYGONTYPE || subtype == CURVEPOLYTYPE) )
537                return LW_TRUE;
538        if ( collectiontype == POLYHEDRALSURFACETYPE &&
539                subtype == POLYGONTYPE )
540                return LW_TRUE;
541        if ( collectiontype == TINTYPE &&
542                subtype == TRIANGLETYPE )
543                return LW_TRUE;
544
545        /* Must be a bad combination! */
546        return LW_FALSE;
547}
Note: See TracBrowser for help on using the browser.