1 : /******************************************************************************
2 : * $Id: ogrgeometrycollection.cpp 16898 2009-05-01 12:23:36Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: The OGRGeometryCollection class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1999, Frank Warmerdam
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "ogr_geometry.h"
31 : #include "ogr_p.h"
32 :
33 : CPL_CVSID("$Id: ogrgeometrycollection.cpp 16898 2009-05-01 12:23:36Z rouault $");
34 :
35 : /************************************************************************/
36 : /* OGRGeometryCollection() */
37 : /************************************************************************/
38 :
39 : /**
40 : * \brief Create an empty geometry collection.
41 : */
42 :
43 632 : OGRGeometryCollection::OGRGeometryCollection()
44 :
45 : {
46 632 : nGeomCount = 0;
47 632 : papoGeoms = NULL;
48 632 : }
49 :
50 : /************************************************************************/
51 : /* ~OGRGeometryCollection() */
52 : /************************************************************************/
53 :
54 705 : OGRGeometryCollection::~OGRGeometryCollection()
55 :
56 : {
57 632 : empty();
58 705 : }
59 :
60 : /************************************************************************/
61 : /* empty() */
62 : /************************************************************************/
63 :
64 863 : void OGRGeometryCollection::empty()
65 :
66 : {
67 863 : if( papoGeoms != NULL )
68 : {
69 1973 : for( int i = 0; i < nGeomCount; i++ )
70 : {
71 1389 : delete papoGeoms[i];
72 : }
73 584 : OGRFree( papoGeoms );
74 : }
75 :
76 863 : nGeomCount = 0;
77 863 : papoGeoms = NULL;
78 863 : nCoordDimension = 2;
79 863 : }
80 :
81 :
82 : /************************************************************************/
83 : /* clone() */
84 : /************************************************************************/
85 :
86 23 : OGRGeometry *OGRGeometryCollection::clone() const
87 :
88 : {
89 : OGRGeometryCollection *poNewGC;
90 :
91 23 : poNewGC = new OGRGeometryCollection;
92 23 : poNewGC->assignSpatialReference( getSpatialReference() );
93 :
94 82 : for( int i = 0; i < nGeomCount; i++ )
95 : {
96 59 : poNewGC->addGeometry( papoGeoms[i] );
97 : }
98 :
99 23 : return poNewGC;
100 : }
101 :
102 : /************************************************************************/
103 : /* getGeometryType() */
104 : /************************************************************************/
105 :
106 201 : OGRwkbGeometryType OGRGeometryCollection::getGeometryType() const
107 :
108 : {
109 201 : if( getCoordinateDimension() == 3 )
110 100 : return wkbGeometryCollection25D;
111 : else
112 101 : return wkbGeometryCollection;
113 : }
114 :
115 : /************************************************************************/
116 : /* getDimension() */
117 : /************************************************************************/
118 :
119 0 : int OGRGeometryCollection::getDimension() const
120 :
121 : {
122 0 : return 2; // This isn't strictly correct. It should be based on members.
123 : }
124 :
125 : /************************************************************************/
126 : /* flattenTo2D() */
127 : /************************************************************************/
128 :
129 3 : void OGRGeometryCollection::flattenTo2D()
130 :
131 : {
132 12 : for( int i = 0; i < nGeomCount; i++ )
133 9 : papoGeoms[i]->flattenTo2D();
134 :
135 3 : nCoordDimension = 2;
136 3 : }
137 :
138 : /************************************************************************/
139 : /* getGeometryName() */
140 : /************************************************************************/
141 :
142 60 : const char * OGRGeometryCollection::getGeometryName() const
143 :
144 : {
145 60 : return "GEOMETRYCOLLECTION";
146 : }
147 :
148 : /************************************************************************/
149 : /* getNumGeometries() */
150 : /************************************************************************/
151 :
152 : /**
153 : * \brief Fetch number of geometries in container.
154 : *
155 : * This method relates to the SFCOM IGeometryCollect::get_NumGeometries()
156 : * method.
157 : *
158 : * @return count of children geometries. May be zero.
159 : */
160 :
161 1663 : int OGRGeometryCollection::getNumGeometries() const
162 :
163 : {
164 1663 : return nGeomCount;
165 : }
166 :
167 : /************************************************************************/
168 : /* getGeometryRef() */
169 : /************************************************************************/
170 :
171 : /**
172 : * \brief Fetch geometry from container.
173 : *
174 : * This method returns a pointer to an geometry within the container. The
175 : * returned geometry remains owned by the container, and should not be
176 : * modified. The pointer is only valid untill the next change to the
177 : * geometry container. Use IGeometry::clone() to make a copy.
178 : *
179 : * This method relates to the SFCOM IGeometryCollection::get_Geometry() method.
180 : *
181 : * @param i the index of the geometry to fetch, between 0 and
182 : * getNumGeometries() - 1.
183 : * @return pointer to requested geometry.
184 : */
185 :
186 762 : OGRGeometry * OGRGeometryCollection::getGeometryRef( int i )
187 :
188 : {
189 762 : if( i < 0 || i >= nGeomCount )
190 0 : return NULL;
191 : else
192 762 : return papoGeoms[i];
193 : }
194 :
195 544 : const OGRGeometry * OGRGeometryCollection::getGeometryRef( int i ) const
196 :
197 : {
198 544 : if( i < 0 || i >= nGeomCount )
199 0 : return NULL;
200 : else
201 544 : return papoGeoms[i];
202 : }
203 :
204 : /************************************************************************/
205 : /* addGeometry() */
206 : /* */
207 : /* Add a new geometry to a collection. Subclasses should */
208 : /* override this to verify the type of the new geometry, and */
209 : /* then call this method to actually add it. */
210 : /************************************************************************/
211 :
212 : /**
213 : * \brief Add a geometry to the container.
214 : *
215 : * Some subclasses of OGRGeometryCollection restrict the types of geometry
216 : * that can be added, and may return an error. The passed geometry is cloned
217 : * to make an internal copy.
218 : *
219 : * There is no SFCOM analog to this method.
220 : *
221 : * This method is the same as the C function OGR_G_AddGeometry().
222 : *
223 : * @param poNewGeom geometry to add to the container.
224 : *
225 : * @return OGRERR_NONE if successful, or OGRERR_UNSUPPORTED_GEOMETRY_TYPE if
226 : * the geometry type is illegal for the type of geometry container.
227 : */
228 :
229 575 : OGRErr OGRGeometryCollection::addGeometry( const OGRGeometry * poNewGeom )
230 :
231 : {
232 575 : OGRGeometry *poClone = poNewGeom->clone();
233 : OGRErr eErr;
234 :
235 575 : eErr = addGeometryDirectly( poClone );
236 575 : if( eErr != OGRERR_NONE )
237 0 : delete poClone;
238 :
239 575 : return eErr;
240 : }
241 :
242 : /************************************************************************/
243 : /* addGeometryDirectly() */
244 : /* */
245 : /* Add a new geometry to a collection. Subclasses should */
246 : /* override this to verify the type of the new geometry, and */
247 : /* then call this method to actually add it. */
248 : /************************************************************************/
249 :
250 : /**
251 : * \brief Add a geometry directly to the container.
252 : *
253 : * Some subclasses of OGRGeometryCollection restrict the types of geometry
254 : * that can be added, and may return an error. Ownership of the passed
255 : * geometry is taken by the container rather than cloning as addGeometry()
256 : * does.
257 : *
258 : * This method is the same as the C function OGR_G_AddGeometryDirectly().
259 : *
260 : * There is no SFCOM analog to this method.
261 : *
262 : * @param poNewGeom geometry to add to the container.
263 : *
264 : * @return OGRERR_NONE if successful, or OGRERR_UNSUPPORTED_GEOMETRY_TYPE if
265 : * the geometry type is illegal for the type of geometry container.
266 : */
267 :
268 1169 : OGRErr OGRGeometryCollection::addGeometryDirectly( OGRGeometry * poNewGeom )
269 :
270 : {
271 : papoGeoms = (OGRGeometry **) OGRRealloc( papoGeoms,
272 1169 : sizeof(void*) * (nGeomCount+1) );
273 :
274 1169 : papoGeoms[nGeomCount] = poNewGeom;
275 :
276 1169 : nGeomCount++;
277 :
278 1169 : if( poNewGeom->getCoordinateDimension() == 3 )
279 217 : nCoordDimension = 3;
280 :
281 1169 : return OGRERR_NONE;
282 : }
283 :
284 : /************************************************************************/
285 : /* removeGeometry() */
286 : /************************************************************************/
287 :
288 : /**
289 : * \brief Remove a geometry from the container.
290 : *
291 : * Removing a geometry will cause the geometry count to drop by one, and all
292 : * "higher" geometries will shuffle down one in index.
293 : *
294 : * There is no SFCOM analog to this method.
295 : *
296 : * This method is the same as the C function OGR_G_RemoveGeometry().
297 : *
298 : * @param iGeom the index of the geometry to delete. A value of -1 is a
299 : * special flag meaning that all geometries should be removed.
300 : *
301 : * @param bDelete if TRUE the geometry will be deallocated, otherwise it will
302 : * not. The default is TRUE as the container is considered to own the
303 : * geometries in it.
304 : *
305 : * @return OGRERR_NONE if successful, or OGRERR_FAILURE if the index is
306 : * out of range.
307 : */
308 :
309 0 : OGRErr OGRGeometryCollection::removeGeometry( int iGeom, int bDelete )
310 :
311 : {
312 0 : if( iGeom < -1 || iGeom >= nGeomCount )
313 0 : return OGRERR_FAILURE;
314 :
315 : // Special case.
316 0 : if( iGeom == -1 )
317 : {
318 0 : while( nGeomCount > 0 )
319 0 : removeGeometry( nGeomCount-1, bDelete );
320 0 : return OGRERR_NONE;
321 : }
322 :
323 0 : if( bDelete )
324 0 : delete papoGeoms[iGeom];
325 :
326 : memmove( papoGeoms + iGeom, papoGeoms + iGeom + 1,
327 0 : sizeof(void*) * (nGeomCount-iGeom-1) );
328 :
329 0 : nGeomCount--;
330 :
331 0 : return OGRERR_NONE;
332 : }
333 :
334 : /************************************************************************/
335 : /* WkbSize() */
336 : /* */
337 : /* Return the size of this object in well known binary */
338 : /* representation including the byte order, and type information. */
339 : /************************************************************************/
340 :
341 32 : int OGRGeometryCollection::WkbSize() const
342 :
343 : {
344 32 : int nSize = 9;
345 :
346 105 : for( int i = 0; i < nGeomCount; i++ )
347 : {
348 73 : nSize += papoGeoms[i]->WkbSize();
349 : }
350 :
351 32 : return nSize;
352 : }
353 :
354 : /************************************************************************/
355 : /* importFromWkb() */
356 : /* */
357 : /* Initialize from serialized stream in well known binary */
358 : /* format. */
359 : /************************************************************************/
360 :
361 78 : OGRErr OGRGeometryCollection::importFromWkb( unsigned char * pabyData,
362 : int nSize )
363 :
364 : {
365 : OGRwkbByteOrder eByteOrder;
366 : int nDataOffset;
367 :
368 78 : if( nSize < 9 && nSize != -1 )
369 0 : return OGRERR_NOT_ENOUGH_DATA;
370 :
371 : /* -------------------------------------------------------------------- */
372 : /* Get the byte order byte. */
373 : /* -------------------------------------------------------------------- */
374 78 : eByteOrder = DB2_V72_FIX_BYTE_ORDER((OGRwkbByteOrder) *pabyData);
375 78 : if (!( eByteOrder == wkbXDR || eByteOrder == wkbNDR ))
376 0 : return OGRERR_CORRUPT_DATA;
377 :
378 : /* -------------------------------------------------------------------- */
379 : /* Get the geometry feature type. For now we assume that */
380 : /* geometry type is between 0 and 255 so we only have to fetch */
381 : /* one byte. */
382 : /* -------------------------------------------------------------------- */
383 : #ifdef DEBUG
384 : OGRwkbGeometryType eGeometryType;
385 :
386 : if( eByteOrder == wkbNDR )
387 : {
388 : eGeometryType = (OGRwkbGeometryType) pabyData[1];
389 : }
390 : else
391 : {
392 : eGeometryType = (OGRwkbGeometryType) pabyData[4];
393 : }
394 :
395 : if (! ( eGeometryType == wkbGeometryCollection
396 : || eGeometryType == wkbMultiPolygon
397 : || eGeometryType == wkbMultiLineString
398 : || eGeometryType == wkbMultiPoint ))
399 : return OGRERR_CORRUPT_DATA;
400 : #endif
401 :
402 : /* -------------------------------------------------------------------- */
403 : /* Clear existing Geoms. */
404 : /* -------------------------------------------------------------------- */
405 78 : empty();
406 :
407 : /* -------------------------------------------------------------------- */
408 : /* Get the geometry count. */
409 : /* -------------------------------------------------------------------- */
410 78 : memcpy( &nGeomCount, pabyData + 5, 4 );
411 :
412 78 : if( OGR_SWAP( eByteOrder ) )
413 17 : nGeomCount = CPL_SWAP32(nGeomCount);
414 :
415 78 : if (nGeomCount < 0 || nGeomCount > INT_MAX / 9)
416 : {
417 0 : nGeomCount = 0;
418 0 : return OGRERR_CORRUPT_DATA;
419 : }
420 :
421 : /* Each geometry has a minimum of 9 bytes */
422 78 : if (nSize != -1 && nSize - 9 < nGeomCount * 9)
423 : {
424 : CPLError( CE_Failure, CPLE_AppDefined,
425 0 : "Length of input WKB is too small" );
426 0 : nGeomCount = 0;
427 0 : return OGRERR_NOT_ENOUGH_DATA;
428 : }
429 :
430 78 : papoGeoms = (OGRGeometry **) VSIMalloc2(sizeof(void*), nGeomCount);
431 78 : if (nGeomCount != 0 && papoGeoms == NULL)
432 : {
433 0 : nGeomCount = 0;
434 0 : return OGRERR_NOT_ENOUGH_MEMORY;
435 : }
436 :
437 78 : nDataOffset = 9;
438 78 : if( nSize != -1 )
439 78 : nSize -= nDataOffset;
440 :
441 : /* -------------------------------------------------------------------- */
442 : /* Get the Geoms. */
443 : /* -------------------------------------------------------------------- */
444 298 : for( int iGeom = 0; iGeom < nGeomCount; iGeom++ )
445 : {
446 : OGRErr eErr;
447 :
448 : eErr = OGRGeometryFactory::
449 : createFromWkb( pabyData + nDataOffset, NULL,
450 220 : papoGeoms + iGeom, nSize );
451 :
452 220 : if( eErr != OGRERR_NONE )
453 : {
454 0 : nGeomCount = iGeom;
455 0 : return eErr;
456 : }
457 :
458 220 : if (papoGeoms[iGeom]->getCoordinateDimension() == 3)
459 48 : nCoordDimension = 3;
460 :
461 220 : if( nSize != -1 )
462 220 : nSize -= papoGeoms[iGeom]->WkbSize();
463 :
464 220 : nDataOffset += papoGeoms[iGeom]->WkbSize();
465 : }
466 :
467 78 : return OGRERR_NONE;
468 : }
469 :
470 : /************************************************************************/
471 : /* exportToWkb() */
472 : /* */
473 : /* Build a well known binary representation of this object. */
474 : /************************************************************************/
475 :
476 32 : OGRErr OGRGeometryCollection::exportToWkb( OGRwkbByteOrder eByteOrder,
477 : unsigned char * pabyData ) const
478 :
479 : {
480 : int nOffset;
481 :
482 : /* -------------------------------------------------------------------- */
483 : /* Set the byte order. */
484 : /* -------------------------------------------------------------------- */
485 32 : pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER((unsigned char) eByteOrder);
486 :
487 : /* -------------------------------------------------------------------- */
488 : /* Set the geometry feature type, ensuring that 3D flag is */
489 : /* preserved. */
490 : /* -------------------------------------------------------------------- */
491 32 : GUInt32 nGType = getGeometryType();
492 :
493 32 : if( eByteOrder == wkbNDR )
494 16 : nGType = CPL_LSBWORD32( nGType );
495 : else
496 16 : nGType = CPL_MSBWORD32( nGType );
497 :
498 32 : memcpy( pabyData + 1, &nGType, 4 );
499 :
500 : /* -------------------------------------------------------------------- */
501 : /* Copy in the raw data. */
502 : /* -------------------------------------------------------------------- */
503 32 : if( OGR_SWAP( eByteOrder ) )
504 : {
505 : int nCount;
506 :
507 16 : nCount = CPL_SWAP32( nGeomCount );
508 16 : memcpy( pabyData+5, &nCount, 4 );
509 : }
510 : else
511 : {
512 16 : memcpy( pabyData+5, &nGeomCount, 4 );
513 : }
514 :
515 32 : nOffset = 9;
516 :
517 : /* ==================================================================== */
518 : /* Serialize each of the Geoms. */
519 : /* ==================================================================== */
520 105 : for( int iGeom = 0; iGeom < nGeomCount; iGeom++ )
521 : {
522 73 : papoGeoms[iGeom]->exportToWkb( eByteOrder, pabyData + nOffset );
523 :
524 73 : nOffset += papoGeoms[iGeom]->WkbSize();
525 : }
526 :
527 32 : return OGRERR_NONE;
528 : }
529 :
530 : /************************************************************************/
531 : /* importFromWkt() */
532 : /************************************************************************/
533 :
534 21 : OGRErr OGRGeometryCollection::importFromWkt( char ** ppszInput )
535 :
536 : {
537 :
538 : char szToken[OGR_WKT_TOKEN_MAX];
539 21 : const char *pszInput = *ppszInput;
540 :
541 : /* -------------------------------------------------------------------- */
542 : /* Clear existing Geoms. */
543 : /* -------------------------------------------------------------------- */
544 21 : empty();
545 :
546 : /* -------------------------------------------------------------------- */
547 : /* Read and verify the type keyword, and ensure it matches the */
548 : /* actual type of this container. */
549 : /* -------------------------------------------------------------------- */
550 21 : pszInput = OGRWktReadToken( pszInput, szToken );
551 :
552 21 : if( !EQUAL(szToken,getGeometryName()) )
553 0 : return OGRERR_CORRUPT_DATA;
554 :
555 : /* -------------------------------------------------------------------- */
556 : /* The next character should be a ( indicating the start of the */
557 : /* list of objects. */
558 : /* -------------------------------------------------------------------- */
559 21 : pszInput = OGRWktReadToken( pszInput, szToken );
560 :
561 21 : if( EQUAL(szToken,"EMPTY") )
562 : {
563 2 : *ppszInput = (char *) pszInput;
564 2 : return OGRERR_NONE;
565 : }
566 :
567 19 : if( szToken[0] != '(' )
568 0 : return OGRERR_CORRUPT_DATA;
569 :
570 : /* -------------------------------------------------------------------- */
571 : /* If the next token is EMPTY, then verify that we have proper */
572 : /* EMPTY format will a trailing closing bracket. */
573 : /* -------------------------------------------------------------------- */
574 19 : OGRWktReadToken( pszInput, szToken );
575 19 : if( EQUAL(szToken,"EMPTY") )
576 : {
577 1 : pszInput = OGRWktReadToken( pszInput, szToken );
578 1 : pszInput = OGRWktReadToken( pszInput, szToken );
579 :
580 1 : *ppszInput = (char *) pszInput;
581 :
582 1 : if( !EQUAL(szToken,")") )
583 0 : return OGRERR_CORRUPT_DATA;
584 : else
585 1 : return OGRERR_NONE;
586 : }
587 :
588 : /* ==================================================================== */
589 : /* Read each subgeometry in turn. */
590 : /* ==================================================================== */
591 59 : do
592 : {
593 59 : OGRGeometry *poGeom = NULL;
594 : OGRErr eErr;
595 :
596 : eErr = OGRGeometryFactory::createFromWkt( (char **) &pszInput,
597 59 : NULL, &poGeom );
598 59 : if( eErr != OGRERR_NONE )
599 0 : return eErr;
600 :
601 59 : addGeometryDirectly( poGeom );
602 :
603 : /* -------------------------------------------------------------------- */
604 : /* Read the delimeter following the ring. */
605 : /* -------------------------------------------------------------------- */
606 :
607 59 : pszInput = OGRWktReadToken( pszInput, szToken );
608 :
609 59 : } while( szToken[0] == ',' );
610 :
611 : /* -------------------------------------------------------------------- */
612 : /* freak if we don't get a closing bracket. */
613 : /* -------------------------------------------------------------------- */
614 18 : if( szToken[0] != ')' )
615 0 : return OGRERR_CORRUPT_DATA;
616 :
617 18 : *ppszInput = (char *) pszInput;
618 :
619 18 : return OGRERR_NONE;
620 : }
621 :
622 : /************************************************************************/
623 : /* exportToWkt() */
624 : /* */
625 : /* Translate this structure into it's well known text format */
626 : /* equivelent. This could be made alot more CPU efficient! */
627 : /************************************************************************/
628 :
629 21 : OGRErr OGRGeometryCollection::exportToWkt( char ** ppszDstText ) const
630 :
631 : {
632 : char **papszGeoms;
633 21 : int iGeom, nCumulativeLength = 0;
634 : OGRErr eErr;
635 :
636 21 : if( getNumGeometries() == 0 )
637 : {
638 5 : *ppszDstText = CPLStrdup("GEOMETRYCOLLECTION EMPTY");
639 5 : return OGRERR_NONE;
640 : }
641 :
642 : /* -------------------------------------------------------------------- */
643 : /* Build a list of strings containing the stuff for each Geom. */
644 : /* -------------------------------------------------------------------- */
645 16 : papszGeoms = (char **) CPLCalloc(sizeof(char *),nGeomCount);
646 :
647 74 : for( iGeom = 0; iGeom < nGeomCount; iGeom++ )
648 : {
649 58 : eErr = papoGeoms[iGeom]->exportToWkt( &(papszGeoms[iGeom]) );
650 58 : if( eErr != OGRERR_NONE )
651 0 : goto error;
652 :
653 58 : nCumulativeLength += strlen(papszGeoms[iGeom]);
654 : }
655 :
656 : /* -------------------------------------------------------------------- */
657 : /* Allocate the right amount of space for the aggregated string */
658 : /* -------------------------------------------------------------------- */
659 16 : *ppszDstText = (char *) VSIMalloc(nCumulativeLength + nGeomCount + 23);
660 :
661 16 : if( *ppszDstText == NULL )
662 : {
663 0 : eErr = OGRERR_NOT_ENOUGH_MEMORY;
664 0 : goto error;
665 : }
666 :
667 : /* -------------------------------------------------------------------- */
668 : /* Build up the string, freeing temporary strings as we go. */
669 : /* -------------------------------------------------------------------- */
670 16 : strcpy( *ppszDstText, getGeometryName() );
671 16 : strcat( *ppszDstText, " (" );
672 16 : nCumulativeLength = strlen(*ppszDstText);
673 :
674 74 : for( iGeom = 0; iGeom < nGeomCount; iGeom++ )
675 : {
676 58 : if( iGeom > 0 )
677 42 : (*ppszDstText)[nCumulativeLength++] = ',';
678 :
679 58 : int nGeomLength = strlen(papszGeoms[iGeom]);
680 58 : memcpy( *ppszDstText + nCumulativeLength, papszGeoms[iGeom], nGeomLength );
681 58 : nCumulativeLength += nGeomLength;
682 58 : VSIFree( papszGeoms[iGeom] );
683 : }
684 :
685 16 : (*ppszDstText)[nCumulativeLength++] = ')';
686 16 : (*ppszDstText)[nCumulativeLength] = '\0';
687 :
688 16 : CPLFree( papszGeoms );
689 :
690 16 : return OGRERR_NONE;
691 :
692 : error:
693 0 : for( iGeom = 0; iGeom < nGeomCount; iGeom++ )
694 0 : CPLFree( papszGeoms[iGeom] );
695 0 : CPLFree( papszGeoms );
696 0 : return eErr;
697 : }
698 :
699 : /************************************************************************/
700 : /* getEnvelope() */
701 : /************************************************************************/
702 :
703 47 : void OGRGeometryCollection::getEnvelope( OGREnvelope * psEnvelope ) const
704 :
705 : {
706 47 : OGREnvelope oGeomEnv;
707 :
708 47 : if( nGeomCount == 0 )
709 4 : return;
710 :
711 43 : papoGeoms[0]->getEnvelope( psEnvelope );
712 :
713 116 : for( int iGeom = 1; iGeom < nGeomCount; iGeom++ )
714 : {
715 73 : papoGeoms[iGeom]->getEnvelope( &oGeomEnv );
716 :
717 73 : if( psEnvelope->MinX > oGeomEnv.MinX )
718 41 : psEnvelope->MinX = oGeomEnv.MinX;
719 73 : if( psEnvelope->MinY > oGeomEnv.MinY )
720 33 : psEnvelope->MinY = oGeomEnv.MinY;
721 73 : if( psEnvelope->MaxX < oGeomEnv.MaxX )
722 23 : psEnvelope->MaxX = oGeomEnv.MaxX;
723 73 : if( psEnvelope->MaxY < oGeomEnv.MaxY )
724 19 : psEnvelope->MaxY = oGeomEnv.MaxY;
725 : }
726 : }
727 :
728 : /************************************************************************/
729 : /* Equals() */
730 : /************************************************************************/
731 :
732 1 : OGRBoolean OGRGeometryCollection::Equals( OGRGeometry * poOther ) const
733 :
734 : {
735 1 : OGRGeometryCollection *poOGC = (OGRGeometryCollection *) poOther;
736 :
737 1 : if( poOGC == this )
738 0 : return TRUE;
739 :
740 1 : if( poOther->getGeometryType() != getGeometryType() )
741 0 : return FALSE;
742 :
743 1 : if( getNumGeometries() != poOGC->getNumGeometries() )
744 0 : return FALSE;
745 :
746 : // we should eventually test the SRS.
747 :
748 3 : for( int iGeom = 0; iGeom < nGeomCount; iGeom++ )
749 : {
750 2 : if( !getGeometryRef(iGeom)->Equals(poOGC->getGeometryRef(iGeom)) )
751 0 : return FALSE;
752 : }
753 :
754 1 : return TRUE;
755 : }
756 :
757 : /************************************************************************/
758 : /* transform() */
759 : /************************************************************************/
760 :
761 3 : OGRErr OGRGeometryCollection::transform( OGRCoordinateTransformation *poCT )
762 :
763 : {
764 : #ifdef DISABLE_OGRGEOM_TRANSFORM
765 : return OGRERR_FAILURE;
766 : #else
767 6 : for( int iGeom = 0; iGeom < nGeomCount; iGeom++ )
768 : {
769 : OGRErr eErr;
770 :
771 3 : eErr = papoGeoms[iGeom]->transform( poCT );
772 3 : if( eErr != OGRERR_NONE )
773 : {
774 0 : if( iGeom != 0 )
775 : {
776 : CPLDebug("OGR",
777 : "OGRGeometryCollection::transform() failed for a geometry other\n"
778 : "than the first, meaning some geometries are transformed\n"
779 0 : "and some are not!\n" );
780 :
781 0 : return OGRERR_FAILURE;
782 : }
783 :
784 0 : return eErr;
785 : }
786 : }
787 :
788 3 : assignSpatialReference( poCT->GetTargetCS() );
789 :
790 3 : return OGRERR_NONE;
791 : #endif
792 : }
793 :
794 : /************************************************************************/
795 : /* closeRings() */
796 : /************************************************************************/
797 :
798 8 : void OGRGeometryCollection::closeRings()
799 :
800 : {
801 32 : for( int iGeom = 0; iGeom < nGeomCount; iGeom++ )
802 : {
803 24 : if( wkbFlatten(papoGeoms[iGeom]->getGeometryType()) == wkbPolygon )
804 7 : ((OGRPolygon *) papoGeoms[iGeom])->closeRings();
805 : }
806 8 : }
807 :
808 : /************************************************************************/
809 : /* setCoordinateDimension() */
810 : /************************************************************************/
811 :
812 42 : void OGRGeometryCollection::setCoordinateDimension( int nNewDimension )
813 :
814 : {
815 104 : for( int iGeom = 0; iGeom < nGeomCount; iGeom++ )
816 : {
817 62 : papoGeoms[iGeom]->setCoordinateDimension( nNewDimension );
818 : }
819 :
820 42 : OGRGeometry::setCoordinateDimension( nNewDimension );
821 42 : }
822 :
823 :
824 : /************************************************************************/
825 : /* get_Area() */
826 : /************************************************************************/
827 :
828 : /**
829 : * \brief Compute area of geometry collection.
830 : *
831 : * The area is computed as the sum of the areas of all members
832 : * in this collection.
833 : *
834 : * @note No warning will be issued if a member of the collection does not
835 : * support the get_Area method.
836 : *
837 : * @return computed area.
838 : */
839 :
840 0 : double OGRGeometryCollection::get_Area() const
841 : {
842 0 : double dfArea = 0.0;
843 0 : for( int iGeom = 0; iGeom < nGeomCount; iGeom++ )
844 : {
845 0 : OGRGeometry* geom = papoGeoms[iGeom];
846 0 : switch( wkbFlatten(geom->getGeometryType()) )
847 : {
848 : case wkbPolygon:
849 0 : dfArea += ((OGRPolygon *) geom)->get_Area();
850 0 : break;
851 :
852 : case wkbMultiPolygon:
853 0 : dfArea += ((OGRMultiPolygon *) geom)->get_Area();
854 0 : break;
855 :
856 : case wkbLinearRing:
857 : case wkbLineString:
858 : /* This test below is required to filter out wkbLineString geometries
859 : * not being of type of wkbLinearRing.
860 : */
861 0 : if( EQUAL( ((OGRGeometry*) geom)->getGeometryName(), "LINEARRING" ) )
862 : {
863 0 : dfArea += ((OGRLinearRing *) geom)->get_Area();
864 : }
865 0 : break;
866 :
867 : case wkbGeometryCollection:
868 0 : dfArea +=((OGRGeometryCollection *) geom)->get_Area();
869 : break;
870 :
871 : default:
872 : break;
873 : }
874 : }
875 :
876 0 : return dfArea;
877 : }
878 :
879 : /************************************************************************/
880 : /* IsEmpty() */
881 : /************************************************************************/
882 :
883 68 : OGRBoolean OGRGeometryCollection::IsEmpty( ) const
884 : {
885 69 : for( int iGeom = 0; iGeom < nGeomCount; iGeom++ )
886 51 : if (papoGeoms[iGeom]->IsEmpty() == FALSE)
887 50 : return FALSE;
888 18 : return TRUE;
889 : }
890 :
891 : /************************************************************************/
892 : /* OGRGeometryCollection::segmentize() */
893 : /************************************************************************/
894 :
895 0 : void OGRGeometryCollection::segmentize( double dfMaxLength )
896 : {
897 0 : for( int iGeom = 0; iGeom < nGeomCount; iGeom++ )
898 0 : papoGeoms[iGeom]->segmentize(dfMaxLength);
899 0 : }
|