1 /******************************************************************************
2 * $Id: ogrcurvecollection.cpp 29330 2015-06-14 12:11:11Z rouault $
3 *
4 * Project: OpenGIS Simple Features Reference Implementation
5 * Purpose: The OGRCurveCollection class.
6 * Author: Even Rouault, even dot rouault at spatialys dot com
7 *
8 ******************************************************************************
9 * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
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 #include <assert.h>
33
34 CPL_CVSID("$Id");
35
36 /************************************************************************/
37 /* OGRCurveCollection() */
38 /************************************************************************/
39
OGRCurveCollection()40 OGRCurveCollection::OGRCurveCollection()
41
42 {
43 nCurveCount = 0;
44 papoCurves = NULL;
45 }
46
47 /************************************************************************/
48 /* ~OGRCurveCollection() */
49 /************************************************************************/
50
~OGRCurveCollection()51 OGRCurveCollection::~OGRCurveCollection()
52
53 {
54 empty(NULL);
55 }
56
57 /************************************************************************/
58 /* WkbSize() */
59 /************************************************************************/
60
WkbSize() const61 int OGRCurveCollection::WkbSize() const
62 {
63 int nSize = 9;
64
65 for( int i = 0; i < nCurveCount; i++ )
66 {
67 nSize += papoCurves[i]->WkbSize();
68 }
69
70 return nSize;
71 }
72
73 /************************************************************************/
74 /* addCurveDirectly() */
75 /************************************************************************/
76
addCurveDirectly(OGRGeometry * poGeom,OGRCurve * poCurve,int bNeedRealloc)77 OGRErr OGRCurveCollection::addCurveDirectly( OGRGeometry* poGeom,
78 OGRCurve* poCurve,
79 int bNeedRealloc )
80 {
81 if( poCurve->getCoordinateDimension() == 3 && poGeom->getCoordinateDimension() != 3 )
82 poGeom->setCoordinateDimension(3);
83 else if( poCurve->getCoordinateDimension() != 3 && poGeom->getCoordinateDimension() == 3 )
84 poCurve->setCoordinateDimension(3);
85
86 if( bNeedRealloc )
87 {
88 papoCurves = (OGRCurve **) OGRRealloc( papoCurves,
89 sizeof(OGRCurve*) * (nCurveCount+1) );
90 }
91
92 papoCurves[nCurveCount] = poCurve;
93
94 nCurveCount++;
95
96 return OGRERR_NONE;
97 }
98
99 /************************************************************************/
100 /* importPreambuleFromWkb() */
101 /************************************************************************/
102
importPreambuleFromWkb(OGRGeometry * poGeom,unsigned char * pabyData,int & nSize,int & nDataOffset,OGRwkbByteOrder & eByteOrder,int nMinSubGeomSize,OGRwkbVariant eWkbVariant)103 OGRErr OGRCurveCollection::importPreambuleFromWkb( OGRGeometry* poGeom,
104 unsigned char * pabyData,
105 int& nSize,
106 int& nDataOffset,
107 OGRwkbByteOrder& eByteOrder,
108 int nMinSubGeomSize,
109 OGRwkbVariant eWkbVariant )
110 {
111 OGRErr eErr = poGeom->importPreambuleOfCollectionFromWkb(
112 pabyData,
113 nSize,
114 nDataOffset,
115 eByteOrder,
116 nMinSubGeomSize,
117 nCurveCount,
118 eWkbVariant );
119 if( eErr >= 0 )
120 return eErr;
121
122 papoCurves = (OGRCurve **) VSIMalloc2(sizeof(void*), nCurveCount);
123 if (nCurveCount != 0 && papoCurves == NULL)
124 {
125 nCurveCount = 0;
126 return OGRERR_NOT_ENOUGH_MEMORY;
127 }
128
129 return -1;
130 }
131
132 /************************************************************************/
133 /* importBodyFromWkb() */
134 /************************************************************************/
135
importBodyFromWkb(OGRGeometry * poGeom,unsigned char * pabyData,int nSize,int nDataOffset,int bAcceptCompoundCurve,OGRErr (* pfnAddCurveDirectlyFromWkb)(OGRGeometry * poGeom,OGRCurve * poCurve),OGRwkbVariant eWkbVariant)136 OGRErr OGRCurveCollection::importBodyFromWkb( OGRGeometry* poGeom,
137 unsigned char * pabyData,
138 int nSize,
139 int nDataOffset,
140 int bAcceptCompoundCurve,
141 OGRErr (*pfnAddCurveDirectlyFromWkb)(OGRGeometry* poGeom, OGRCurve* poCurve),
142 OGRwkbVariant eWkbVariant )
143 {
144
145 /* -------------------------------------------------------------------- */
146 /* Get the Geoms. */
147 /* -------------------------------------------------------------------- */
148 int nIter = nCurveCount;
149 nCurveCount = 0;
150 for( int iGeom = 0; iGeom < nIter; iGeom++ )
151 {
152 OGRErr eErr;
153 OGRGeometry* poSubGeom = NULL;
154
155 /* Parses sub-geometry */
156 unsigned char* pabySubData = pabyData + nDataOffset;
157 if( nSize < 9 && nSize != -1 )
158 return OGRERR_NOT_ENOUGH_DATA;
159
160 OGRwkbGeometryType eSubGeomType;
161 OGRBoolean bIs3D;
162 if ( OGRReadWKBGeometryType( pabySubData, eWkbVariant, &eSubGeomType, &bIs3D ) != OGRERR_NONE )
163 return OGRERR_FAILURE;
164
165 if( (eSubGeomType != wkbCompoundCurve && OGR_GT_IsCurve(eSubGeomType)) ||
166 (bAcceptCompoundCurve && eSubGeomType == wkbCompoundCurve) )
167 {
168 eErr = OGRGeometryFactory::
169 createFromWkb( pabySubData, NULL,
170 &poSubGeom, nSize, eWkbVariant );
171 }
172 else
173 {
174 CPLDebug("OGR", "Cannot add geometry of type (%d) to geometry of type (%d)",
175 eSubGeomType, poGeom->getGeometryType());
176 return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
177 }
178
179 if( eErr == OGRERR_NONE )
180 eErr = pfnAddCurveDirectlyFromWkb(poGeom, (OGRCurve*)poSubGeom);
181 if( eErr != OGRERR_NONE )
182 {
183 delete poSubGeom;
184 return eErr;
185 }
186
187 int nSubGeomWkbSize = poSubGeom->WkbSize();
188 if( nSize != -1 )
189 nSize -= nSubGeomWkbSize;
190
191 nDataOffset += nSubGeomWkbSize;
192 }
193
194 return OGRERR_NONE;
195 }
196
197 /************************************************************************/
198 /* exportToWkt() */
199 /************************************************************************/
200
exportToWkt(const OGRGeometry * poGeom,char ** ppszDstText) const201 OGRErr OGRCurveCollection::exportToWkt( const OGRGeometry* poGeom,
202 char ** ppszDstText ) const
203
204 {
205 char **papszGeoms;
206 int iGeom, nCumulativeLength = 0;
207 OGRErr eErr;
208
209 if( nCurveCount == 0 )
210 {
211 CPLString osEmpty;
212 if( poGeom->getCoordinateDimension() == 3 )
213 osEmpty.Printf("%s Z EMPTY",poGeom->getGeometryName());
214 else
215 osEmpty.Printf("%s EMPTY",poGeom->getGeometryName());
216 *ppszDstText = CPLStrdup(osEmpty);
217 return OGRERR_NONE;
218 }
219
220 /* -------------------------------------------------------------------- */
221 /* Build a list of strings containing the stuff for each Geom. */
222 /* -------------------------------------------------------------------- */
223 papszGeoms = (char **) CPLCalloc(sizeof(char *),nCurveCount);
224
225 for( iGeom = 0; iGeom < nCurveCount; iGeom++ )
226 {
227 eErr = papoCurves[iGeom]->exportToWkt( &(papszGeoms[iGeom]), wkbVariantIso );
228 if( eErr != OGRERR_NONE )
229 goto error;
230
231 nCumulativeLength += strlen(papszGeoms[iGeom]);
232 }
233
234 /* -------------------------------------------------------------------- */
235 /* Allocate the right amount of space for the aggregated string */
236 /* -------------------------------------------------------------------- */
237 *ppszDstText = (char *) VSIMalloc(nCumulativeLength + nCurveCount +
238 strlen(poGeom->getGeometryName()) + 10);
239
240 if( *ppszDstText == NULL )
241 {
242 eErr = OGRERR_NOT_ENOUGH_MEMORY;
243 goto error;
244 }
245
246 /* -------------------------------------------------------------------- */
247 /* Build up the string, freeing temporary strings as we go. */
248 /* -------------------------------------------------------------------- */
249 strcpy( *ppszDstText, poGeom->getGeometryName() );
250 if( poGeom->getCoordinateDimension() == 3 )
251 strcat( *ppszDstText, " Z" );
252 strcat( *ppszDstText, " (" );
253 nCumulativeLength = strlen(*ppszDstText);
254
255 for( iGeom = 0; iGeom < nCurveCount; iGeom++ )
256 {
257 if( iGeom > 0 )
258 (*ppszDstText)[nCumulativeLength++] = ',';
259
260 /* We must strip the explicit "LINESTRING " prefix */
261 int nSkip = 0;
262 if( !papoCurves[iGeom]->IsEmpty() &&
263 EQUALN(papszGeoms[iGeom], "LINESTRING ", strlen("LINESTRING ")) )
264 {
265 nSkip = strlen("LINESTRING ");
266 if( EQUALN(papszGeoms[iGeom] + nSkip, "Z ", 2) )
267 nSkip += 2;
268 }
269
270 int nGeomLength = strlen(papszGeoms[iGeom] + nSkip);
271 memcpy( *ppszDstText + nCumulativeLength, papszGeoms[iGeom] + nSkip, nGeomLength );
272 nCumulativeLength += nGeomLength;
273 VSIFree( papszGeoms[iGeom] );
274 }
275
276 (*ppszDstText)[nCumulativeLength++] = ')';
277 (*ppszDstText)[nCumulativeLength] = '\0';
278
279 CPLFree( papszGeoms );
280
281 return OGRERR_NONE;
282
283 error:
284 for( iGeom = 0; iGeom < nCurveCount; iGeom++ )
285 CPLFree( papszGeoms[iGeom] );
286 CPLFree( papszGeoms );
287 return eErr;
288 }
289
290 /************************************************************************/
291 /* exportToWkb() */
292 /************************************************************************/
293
exportToWkb(const OGRGeometry * poGeom,OGRwkbByteOrder eByteOrder,unsigned char * pabyData,OGRwkbVariant eWkbVariant) const294 OGRErr OGRCurveCollection::exportToWkb( const OGRGeometry* poGeom,
295 OGRwkbByteOrder eByteOrder,
296 unsigned char * pabyData,
297 OGRwkbVariant eWkbVariant ) const
298 {
299 int nOffset;
300
301 /* -------------------------------------------------------------------- */
302 /* Set the byte order. */
303 /* -------------------------------------------------------------------- */
304 pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER((unsigned char) eByteOrder);
305
306 /* -------------------------------------------------------------------- */
307 /* Set the geometry feature type, ensuring that 3D flag is */
308 /* preserved. */
309 /* -------------------------------------------------------------------- */
310 GUInt32 nGType = poGeom->getIsoGeometryType();
311 if( eWkbVariant == wkbVariantPostGIS1 )
312 {
313 int bIs3D = wkbHasZ((OGRwkbGeometryType)nGType);
314 nGType = wkbFlatten(nGType);
315 if( nGType == wkbCurvePolygon )
316 nGType = POSTGIS15_CURVEPOLYGON;
317 if( bIs3D )
318 nGType = (OGRwkbGeometryType)(nGType | wkb25DBitInternalUse); /* yes we explicitly set wkb25DBit */
319 }
320
321 if( eByteOrder == wkbNDR )
322 nGType = CPL_LSBWORD32( nGType );
323 else
324 nGType = CPL_MSBWORD32( nGType );
325
326 memcpy( pabyData + 1, &nGType, 4 );
327
328 /* -------------------------------------------------------------------- */
329 /* Copy in the raw data. */
330 /* -------------------------------------------------------------------- */
331 if( OGR_SWAP( eByteOrder ) )
332 {
333 int nCount;
334
335 nCount = CPL_SWAP32( nCurveCount );
336 memcpy( pabyData+5, &nCount, 4 );
337 }
338 else
339 {
340 memcpy( pabyData+5, &nCurveCount, 4 );
341 }
342
343 nOffset = 9;
344
345 /* ==================================================================== */
346 /* Serialize each of the Geoms. */
347 /* ==================================================================== */
348 for( int iGeom = 0; iGeom < nCurveCount; iGeom++ )
349 {
350 papoCurves[iGeom]->exportToWkb( eByteOrder, pabyData + nOffset, eWkbVariant );
351
352 nOffset += papoCurves[iGeom]->WkbSize();
353 }
354
355 return OGRERR_NONE;
356 }
357
358 /************************************************************************/
359 /* empty() */
360 /************************************************************************/
361
empty(OGRGeometry * poGeom)362 void OGRCurveCollection::empty(OGRGeometry* poGeom)
363 {
364 if( papoCurves != NULL )
365 {
366 for( int i = 0; i < nCurveCount; i++ )
367 {
368 delete papoCurves[i];
369 }
370 OGRFree( papoCurves );
371 }
372
373 nCurveCount = 0;
374 papoCurves = NULL;
375 if( poGeom )
376 poGeom->setCoordinateDimension(2);
377 }
378
379 /************************************************************************/
380 /* getEnvelope() */
381 /************************************************************************/
382
getEnvelope(OGREnvelope * psEnvelope) const383 void OGRCurveCollection::getEnvelope( OGREnvelope * psEnvelope ) const
384 {
385 OGREnvelope3D oEnv3D;
386 getEnvelope(&oEnv3D);
387 psEnvelope->MinX = oEnv3D.MinX;
388 psEnvelope->MinY = oEnv3D.MinY;
389 psEnvelope->MaxX = oEnv3D.MaxX;
390 psEnvelope->MaxY = oEnv3D.MaxY;
391 }
392
393 /************************************************************************/
394 /* getEnvelope() */
395 /************************************************************************/
396
getEnvelope(OGREnvelope3D * psEnvelope) const397 void OGRCurveCollection::getEnvelope( OGREnvelope3D * psEnvelope ) const
398 {
399 OGREnvelope3D oGeomEnv;
400 int bExtentSet = FALSE;
401
402 for( int iGeom = 0; iGeom < nCurveCount; iGeom++ )
403 {
404 if (!papoCurves[iGeom]->IsEmpty())
405 {
406 if (!bExtentSet)
407 {
408 papoCurves[iGeom]->getEnvelope( psEnvelope );
409 bExtentSet = TRUE;
410 }
411 else
412 {
413 papoCurves[iGeom]->getEnvelope( &oGeomEnv );
414 psEnvelope->Merge( oGeomEnv );
415 }
416 }
417 }
418
419 if (!bExtentSet)
420 {
421 psEnvelope->MinX = psEnvelope->MinY = psEnvelope->MinZ = 0;
422 psEnvelope->MaxX = psEnvelope->MaxY = psEnvelope->MaxZ = 0;
423 }
424 }
425
426 /************************************************************************/
427 /* IsEmpty() */
428 /************************************************************************/
429
IsEmpty() const430 OGRBoolean OGRCurveCollection::IsEmpty() const
431 {
432 return nCurveCount == 0;
433 }
434
435 /************************************************************************/
436 /* Equals() */
437 /************************************************************************/
438
Equals(OGRCurveCollection * poOCC) const439 OGRBoolean OGRCurveCollection::Equals( OGRCurveCollection *poOCC ) const
440 {
441 if( getNumCurves() != poOCC->getNumCurves() )
442 return FALSE;
443
444 // we should eventually test the SRS.
445
446 for( int iGeom = 0; iGeom < nCurveCount; iGeom++ )
447 {
448 if( !getCurve(iGeom)->Equals(poOCC->getCurve(iGeom)) )
449 return FALSE;
450 }
451
452 return TRUE;
453 }
454
455 /************************************************************************/
456 /* setCoordinateDimension() */
457 /************************************************************************/
458
setCoordinateDimension(OGRGeometry * poGeom,int nNewDimension)459 void OGRCurveCollection::setCoordinateDimension( OGRGeometry* poGeom,
460 int nNewDimension )
461 {
462 for( int iGeom = 0; iGeom < nCurveCount; iGeom++ )
463 {
464 papoCurves[iGeom]->setCoordinateDimension( nNewDimension );
465 }
466
467 poGeom->OGRGeometry::setCoordinateDimension( nNewDimension );
468 }
469
470 /************************************************************************/
471 /* getNumCurves() */
472 /************************************************************************/
473
getNumCurves() const474 int OGRCurveCollection::getNumCurves() const
475 {
476 return nCurveCount;
477 }
478
479 /************************************************************************/
480 /* getCurve() */
481 /************************************************************************/
482
getCurve(int i)483 OGRCurve *OGRCurveCollection::getCurve( int i )
484 {
485 if( i < 0 || i >= nCurveCount )
486 return NULL;
487 return papoCurves[i];
488 }
489
490 /************************************************************************/
491 /* getCurve() */
492 /************************************************************************/
493
getCurve(int i) const494 const OGRCurve *OGRCurveCollection::getCurve( int i ) const
495 {
496 if( i < 0 || i >= nCurveCount )
497 return NULL;
498 return papoCurves[i];
499 }
500
501 /************************************************************************/
502 /* stealCurve() */
503 /************************************************************************/
504
stealCurve(int i)505 OGRCurve* OGRCurveCollection::stealCurve( int i )
506 {
507 if( i < 0 || i >= nCurveCount )
508 return NULL;
509 OGRCurve* poRet = papoCurves[i];
510 if( i < nCurveCount - 1 )
511 {
512 memmove(papoCurves + i, papoCurves + i + 1, (nCurveCount - i - 1) * sizeof(OGRCurve*));
513 }
514 nCurveCount --;
515 return poRet;
516 }
517
518 /************************************************************************/
519 /* transform() */
520 /************************************************************************/
521
transform(OGRGeometry * poGeom,OGRCoordinateTransformation * poCT)522 OGRErr OGRCurveCollection::transform( OGRGeometry* poGeom,
523 OGRCoordinateTransformation *poCT )
524 {
525 #ifdef DISABLE_OGRGEOM_TRANSFORM
526 return OGRERR_FAILURE;
527 #else
528 for( int iGeom = 0; iGeom < nCurveCount; iGeom++ )
529 {
530 OGRErr eErr;
531
532 eErr = papoCurves[iGeom]->transform( poCT );
533 if( eErr != OGRERR_NONE )
534 {
535 if( iGeom != 0 )
536 {
537 CPLDebug("OGR",
538 "OGRCurveCollection::transform() failed for a geometry other\n"
539 "than the first, meaning some geometries are transformed\n"
540 "and some are not!\n" );
541
542 return OGRERR_FAILURE;
543 }
544
545 return eErr;
546 }
547 }
548
549 poGeom->assignSpatialReference( poCT->GetTargetCS() );
550
551 return OGRERR_NONE;
552 #endif
553 }
554
555 /************************************************************************/
556 /* flattenTo2D() */
557 /************************************************************************/
558
flattenTo2D(OGRGeometry * poGeom)559 void OGRCurveCollection::flattenTo2D(OGRGeometry* poGeom)
560 {
561 for( int i = 0; i < nCurveCount; i++ )
562 papoCurves[i]->flattenTo2D();
563
564 poGeom->setCoordinateDimension(2);
565 }
566
567 /************************************************************************/
568 /* segmentize() */
569 /************************************************************************/
570
segmentize(double dfMaxLength)571 void OGRCurveCollection::segmentize(double dfMaxLength)
572 {
573 for( int i = 0; i < nCurveCount; i++ )
574 papoCurves[i]->segmentize(dfMaxLength);
575 }
576
577 /************************************************************************/
578 /* swapXY() */
579 /************************************************************************/
580
swapXY()581 void OGRCurveCollection::swapXY()
582 {
583 for( int i = 0; i < nCurveCount; i++ )
584 papoCurves[i]->swapXY();
585 }
586
587 /************************************************************************/
588 /* hasCurveGeometry() */
589 /************************************************************************/
590
hasCurveGeometry(int bLookForNonLinear) const591 OGRBoolean OGRCurveCollection::hasCurveGeometry(int bLookForNonLinear) const
592 {
593 for( int i = 0; i < nCurveCount; i++ )
594 {
595 if( papoCurves[i]->hasCurveGeometry(bLookForNonLinear) )
596 return TRUE;
597 }
598 return FALSE;
599 }
600