LCOV - code coverage report
Current view: top level - core/geometry - qgsgeometrycollection.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 566 617 91.7 %
Date: 2021-04-10 08:29:14 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :                         qgsgeometrycollection.cpp
       3                 :            :   -------------------------------------------------------------------
       4                 :            : Date                 : 28 Oct 2014
       5                 :            : Copyright            : (C) 2014 by Marco Hugentobler
       6                 :            : email                : marco.hugentobler at sourcepole dot com
       7                 :            :  ***************************************************************************
       8                 :            :  *                                                                         *
       9                 :            :  *   This program is free software; you can redistribute it and/or modify  *
      10                 :            :  *   it under the terms of the GNU General Public License as published by  *
      11                 :            :  *   the Free Software Foundation; either version 2 of the License, or     *
      12                 :            :  *   (at your option) any later version.                                   *
      13                 :            :  *                                                                         *
      14                 :            :  ***************************************************************************/
      15                 :            : 
      16                 :            : #include "qgsgeometrycollection.h"
      17                 :            : #include "qgsapplication.h"
      18                 :            : #include "qgsgeometryfactory.h"
      19                 :            : #include "qgsgeometryutils.h"
      20                 :            : #include "qgscircularstring.h"
      21                 :            : #include "qgscompoundcurve.h"
      22                 :            : #include "qgslinestring.h"
      23                 :            : #include "qgsmultilinestring.h"
      24                 :            : #include "qgspoint.h"
      25                 :            : #include "qgsmultipoint.h"
      26                 :            : #include "qgspolygon.h"
      27                 :            : #include "qgsmultipolygon.h"
      28                 :            : #include "qgswkbptr.h"
      29                 :            : #include "qgsgeos.h"
      30                 :            : #include "qgsfeedback.h"
      31                 :            : 
      32                 :            : #include <nlohmann/json.hpp>
      33                 :            : #include <memory>
      34                 :            : 
      35                 :       4814 : QgsGeometryCollection::QgsGeometryCollection()
      36                 :       9628 : {
      37                 :       4814 :   mWkbType = QgsWkbTypes::GeometryCollection;
      38                 :       4814 : }
      39                 :            : 
      40                 :         94 : QgsGeometryCollection::QgsGeometryCollection( const QgsGeometryCollection &c ):
      41                 :         94 :   QgsAbstractGeometry( c ),
      42                 :         94 :   mBoundingBox( c.mBoundingBox ),
      43                 :         94 :   mHasCachedValidity( c.mHasCachedValidity ),
      44                 :         94 :   mValidityFailureReason( c.mValidityFailureReason )
      45                 :        188 : {
      46                 :         94 :   int nGeoms = c.mGeometries.size();
      47                 :         94 :   mGeometries.resize( nGeoms );
      48                 :        191 :   for ( int i = 0; i < nGeoms; ++i )
      49                 :            :   {
      50                 :         97 :     mGeometries[i] = c.mGeometries.at( i )->clone();
      51                 :         97 :   }
      52                 :         94 : }
      53                 :            : 
      54                 :         12 : QgsGeometryCollection &QgsGeometryCollection::operator=( const QgsGeometryCollection &c )
      55                 :            : {
      56                 :         12 :   if ( &c != this )
      57                 :            :   {
      58                 :         12 :     clearCache();
      59                 :         12 :     QgsAbstractGeometry::operator=( c );
      60                 :         12 :     int nGeoms = c.mGeometries.size();
      61                 :         12 :     mGeometries.resize( nGeoms );
      62                 :         24 :     for ( int i = 0; i < nGeoms; ++i )
      63                 :            :     {
      64                 :         12 :       mGeometries[i] = c.mGeometries.at( i )->clone();
      65                 :         12 :     }
      66                 :         12 :   }
      67                 :         12 :   return *this;
      68                 :            : }
      69                 :            : 
      70                 :       2610 : QgsGeometryCollection::~QgsGeometryCollection()
      71                 :       2610 : {
      72                 :       2381 :   clear();
      73                 :       2610 : }
      74                 :            : 
      75                 :          8 : bool QgsGeometryCollection::operator==( const QgsAbstractGeometry &other ) const
      76                 :            : {
      77                 :          8 :   const QgsGeometryCollection *otherCollection = qgsgeometry_cast< const QgsGeometryCollection * >( &other );
      78                 :          8 :   if ( !otherCollection )
      79                 :          2 :     return false;
      80                 :            : 
      81                 :          6 :   if ( mWkbType != otherCollection->mWkbType )
      82                 :          2 :     return false;
      83                 :            : 
      84                 :          4 :   if ( mGeometries.count() != otherCollection->mGeometries.count() )
      85                 :          2 :     return false;
      86                 :            : 
      87                 :          3 :   for ( int i = 0; i < mGeometries.count(); ++i )
      88                 :            :   {
      89                 :          2 :     QgsAbstractGeometry *g1 = mGeometries.at( i );
      90                 :          2 :     QgsAbstractGeometry *g2 = otherCollection->mGeometries.at( i );
      91                 :            : 
      92                 :            :     // Quick check if the geometries are exactly the same
      93                 :          2 :     if ( g1 != g2 )
      94                 :            :     {
      95                 :          2 :       if ( !g1 || !g2 )
      96                 :          0 :         return false;
      97                 :            : 
      98                 :            :       // Slower check, compare the contents of the geometries
      99                 :          2 :       if ( *g1 != *g2 )
     100                 :          1 :         return false;
     101                 :          1 :     }
     102                 :          1 :   }
     103                 :            : 
     104                 :          1 :   return true;
     105                 :          8 : }
     106                 :            : 
     107                 :          5 : bool QgsGeometryCollection::operator!=( const QgsAbstractGeometry &other ) const
     108                 :            : {
     109                 :          5 :   return !operator==( other );
     110                 :            : }
     111                 :            : 
     112                 :          1 : QgsGeometryCollection *QgsGeometryCollection::createEmptyWithSameType() const
     113                 :            : {
     114                 :          1 :   auto result = std::make_unique< QgsGeometryCollection >();
     115                 :          1 :   result->mWkbType = mWkbType;
     116                 :          1 :   return result.release();
     117                 :          1 : }
     118                 :            : 
     119                 :          3 : QgsGeometryCollection *QgsGeometryCollection::clone() const
     120                 :            : {
     121                 :          3 :   return new QgsGeometryCollection( *this );
     122                 :          0 : }
     123                 :            : 
     124                 :       4590 : void QgsGeometryCollection::clear()
     125                 :            : {
     126                 :       4590 :   qDeleteAll( mGeometries );
     127                 :       4590 :   mGeometries.clear();
     128                 :       4590 :   clearCache(); //set bounding box invalid
     129                 :       4590 : }
     130                 :            : 
     131                 :          1 : QgsGeometryCollection *QgsGeometryCollection::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing ) const
     132                 :            : {
     133                 :          1 :   std::unique_ptr<QgsGeometryCollection> result;
     134                 :            : 
     135                 :          5 :   for ( auto geom : mGeometries )
     136                 :            :   {
     137                 :          4 :     std::unique_ptr<QgsAbstractGeometry> gridified { geom->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing ) };
     138                 :          4 :     if ( gridified )
     139                 :            :     {
     140                 :          2 :       if ( !result )
     141                 :          1 :         result = std::unique_ptr<QgsGeometryCollection> { createEmptyWithSameType() };
     142                 :            : 
     143                 :          2 :       result->mGeometries.append( gridified.release() );
     144                 :          2 :     }
     145                 :          4 :   }
     146                 :            : 
     147                 :          1 :   return result.release();
     148                 :          1 : }
     149                 :            : 
     150                 :          9 : bool QgsGeometryCollection::removeDuplicateNodes( double epsilon, bool useZValues )
     151                 :            : {
     152                 :          9 :   bool result = false;
     153                 :         21 :   for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
     154                 :            :   {
     155                 :         12 :     if ( geom->removeDuplicateNodes( epsilon, useZValues ) ) result = true;
     156                 :            :   }
     157                 :          9 :   return result;
     158                 :            : }
     159                 :            : 
     160                 :          2 : QgsAbstractGeometry *QgsGeometryCollection::boundary() const
     161                 :            : {
     162                 :          2 :   return nullptr;
     163                 :            : }
     164                 :            : 
     165                 :         10 : void QgsGeometryCollection::adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex ) const
     166                 :            : {
     167                 :         10 :   if ( vertex.part < 0 || vertex.part >= mGeometries.count() )
     168                 :            :   {
     169                 :          5 :     previousVertex = QgsVertexId();
     170                 :          5 :     nextVertex = QgsVertexId();
     171                 :          5 :     return;
     172                 :            :   }
     173                 :            : 
     174                 :          5 :   mGeometries.at( vertex.part )->adjacentVertices( vertex, previousVertex, nextVertex );
     175                 :         10 : }
     176                 :            : 
     177                 :         58 : int QgsGeometryCollection::vertexNumberFromVertexId( QgsVertexId id ) const
     178                 :            : {
     179                 :         58 :   if ( id.part < 0 || id.part >= mGeometries.count() )
     180                 :          9 :     return -1;
     181                 :            : 
     182                 :         49 :   int number = 0;
     183                 :         49 :   int part = 0;
     184                 :        122 :   for ( QgsAbstractGeometry *geometry : mGeometries )
     185                 :            :   {
     186                 :        122 :     if ( part == id.part )
     187                 :            :     {
     188                 :         49 :       int partNumber =  geometry->vertexNumberFromVertexId( QgsVertexId( 0, id.ring, id.vertex ) );
     189                 :         49 :       if ( partNumber == -1 )
     190                 :         18 :         return -1;
     191                 :         31 :       return number + partNumber;
     192                 :            :     }
     193                 :            :     else
     194                 :            :     {
     195                 :         73 :       number += geometry->nCoordinates();
     196                 :            :     }
     197                 :            : 
     198                 :         73 :     part++;
     199                 :            :   }
     200                 :          0 :   return -1; // should not happen
     201                 :         58 : }
     202                 :            : 
     203                 :          0 : bool QgsGeometryCollection::boundingBoxIntersects( const QgsRectangle &rectangle ) const
     204                 :            : {
     205                 :          0 :   if ( mGeometries.empty() )
     206                 :          0 :     return false;
     207                 :            : 
     208                 :            :   // if we already have the bounding box calculated, then this check is trivial!
     209                 :          0 :   if ( !mBoundingBox.isNull() )
     210                 :            :   {
     211                 :          0 :     return mBoundingBox.intersects( rectangle );
     212                 :            :   }
     213                 :            : 
     214                 :            :   // otherwise loop through each member geometry and test the bounding box intersection.
     215                 :            :   // This gives us a chance to use optimisations which may be present on the individual
     216                 :            :   // geometry subclasses, and at worst it will cause a calculation of the bounding box
     217                 :            :   // of each individual member geometry which we would have to do anyway... (and these
     218                 :            :   // bounding boxes are cached, so would be reused without additional expense)
     219                 :          0 :   for ( const QgsAbstractGeometry *geometry : mGeometries )
     220                 :            :   {
     221                 :          0 :     if ( geometry->boundingBoxIntersects( rectangle ) )
     222                 :          0 :       return true;
     223                 :            :   }
     224                 :            : 
     225                 :            :   // even if we don't intersect the bounding box of any member geometries, we may still intersect the
     226                 :            :   // bounding box of the overall collection.
     227                 :            :   // so here we fall back to the non-optimised base class check which has to first calculate
     228                 :            :   // the overall bounding box of the collection..
     229                 :          0 :   return QgsAbstractGeometry::boundingBoxIntersects( rectangle );
     230                 :          0 : }
     231                 :            : 
     232                 :        123 : void QgsGeometryCollection::reserve( int size )
     233                 :            : {
     234                 :        123 :   mGeometries.reserve( size );
     235                 :        123 : }
     236                 :            : 
     237                 :        689 : QgsAbstractGeometry *QgsGeometryCollection::geometryN( int n )
     238                 :            : {
     239                 :        689 :   clearCache();
     240                 :        689 :   return mGeometries.value( n );
     241                 :            : }
     242                 :            : 
     243                 :       2370 : bool QgsGeometryCollection::isEmpty() const
     244                 :            : {
     245                 :       2370 :   if ( mGeometries.isEmpty() )
     246                 :       2099 :     return true;
     247                 :            : 
     248                 :        271 :   for ( QgsAbstractGeometry *geometry : mGeometries )
     249                 :            :   {
     250                 :        271 :     if ( !geometry->isEmpty() )
     251                 :        271 :       return false;
     252                 :            :   }
     253                 :          0 :   return true;
     254                 :       2370 : }
     255                 :            : 
     256                 :       1607 : bool QgsGeometryCollection::addGeometry( QgsAbstractGeometry *g )
     257                 :            : {
     258                 :       1607 :   if ( !g )
     259                 :            :   {
     260                 :          1 :     return false;
     261                 :            :   }
     262                 :            : 
     263                 :       1606 :   mGeometries.append( g );
     264                 :       1606 :   clearCache(); //set bounding box invalid
     265                 :       1606 :   return true;
     266                 :       1607 : }
     267                 :            : 
     268                 :         11 : bool QgsGeometryCollection::insertGeometry( QgsAbstractGeometry *g, int index )
     269                 :            : {
     270                 :         11 :   if ( !g )
     271                 :            :   {
     272                 :          3 :     return false;
     273                 :            :   }
     274                 :            : 
     275                 :          8 :   index = std::min( static_cast<int>( mGeometries.count() ), index );
     276                 :            : 
     277                 :          8 :   mGeometries.insert( index, g );
     278                 :          8 :   clearCache(); //set bounding box invalid
     279                 :          8 :   return true;
     280                 :         11 : }
     281                 :            : 
     282                 :         25 : bool QgsGeometryCollection::removeGeometry( int nr )
     283                 :            : {
     284                 :         25 :   if ( nr >= mGeometries.size() || nr < 0 )
     285                 :            :   {
     286                 :          5 :     return false;
     287                 :            :   }
     288                 :         20 :   delete mGeometries.at( nr );
     289                 :         20 :   mGeometries.remove( nr );
     290                 :         20 :   clearCache(); //set bounding box invalid
     291                 :         20 :   return true;
     292                 :         25 : }
     293                 :            : 
     294                 :         12 : int QgsGeometryCollection::dimension() const
     295                 :            : {
     296                 :         12 :   int maxDim = 0;
     297                 :         12 :   QVector< QgsAbstractGeometry * >::const_iterator it = mGeometries.constBegin();
     298                 :         18 :   for ( ; it != mGeometries.constEnd(); ++it )
     299                 :            :   {
     300                 :          6 :     int dim = ( *it )->dimension();
     301                 :          6 :     if ( dim > maxDim )
     302                 :            :     {
     303                 :          5 :       maxDim = dim;
     304                 :          5 :     }
     305                 :          6 :   }
     306                 :         12 :   return maxDim;
     307                 :            : }
     308                 :            : 
     309                 :        426 : QString QgsGeometryCollection::geometryType() const
     310                 :            : {
     311                 :        852 :   return QStringLiteral( "GeometryCollection" );
     312                 :            : }
     313                 :            : 
     314                 :         47 : void QgsGeometryCollection::transform( const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d, bool transformZ )
     315                 :            : {
     316                 :         97 :   for ( QgsAbstractGeometry *g : std::as_const( mGeometries ) )
     317                 :            :   {
     318                 :         50 :     g->transform( ct, d, transformZ );
     319                 :            :   }
     320                 :         47 :   clearCache(); //set bounding box invalid
     321                 :         47 : }
     322                 :            : 
     323                 :          1 : void QgsGeometryCollection::transform( const QTransform &t, double zTranslate, double zScale, double mTranslate, double mScale )
     324                 :            : {
     325                 :          3 :   for ( QgsAbstractGeometry *g : std::as_const( mGeometries ) )
     326                 :            :   {
     327                 :          2 :     g->transform( t, zTranslate, zScale, mTranslate, mScale );
     328                 :            :   }
     329                 :          1 :   clearCache(); //set bounding box invalid
     330                 :          1 : }
     331                 :            : 
     332                 :          0 : void QgsGeometryCollection::draw( QPainter &p ) const
     333                 :            : {
     334                 :          0 :   QVector< QgsAbstractGeometry * >::const_iterator it = mGeometries.constBegin();
     335                 :          0 :   for ( ; it != mGeometries.constEnd(); ++it )
     336                 :            :   {
     337                 :          0 :     ( *it )->draw( p );
     338                 :          0 :   }
     339                 :          0 : }
     340                 :            : 
     341                 :          0 : QPainterPath QgsGeometryCollection::asQPainterPath() const
     342                 :            : {
     343                 :          0 :   QPainterPath p;
     344                 :          0 :   for ( const QgsAbstractGeometry *geom : mGeometries )
     345                 :            :   {
     346                 :          0 :     QPainterPath partPath = geom->asQPainterPath();
     347                 :          0 :     if ( !partPath.isEmpty() )
     348                 :          0 :       p.addPath( partPath );
     349                 :       4814 :   }
     350                 :          0 :   return p;
     351                 :          0 : }
     352                 :            : 
     353                 :         36 : bool QgsGeometryCollection::fromWkb( QgsConstWkbPtr &wkbPtr )
     354                 :            : {
     355                 :         36 :   if ( !wkbPtr )
     356                 :            :   {
     357                 :          6 :     return false;
     358                 :            :   }
     359                 :            : 
     360                 :         30 :   QgsWkbTypes::Type wkbType = wkbPtr.readHeader();
     361                 :         30 :   if ( QgsWkbTypes::flatType( wkbType ) != QgsWkbTypes::flatType( mWkbType ) )
     362                 :          6 :     return false;
     363                 :            : 
     364                 :         24 :   mWkbType = wkbType;
     365                 :            : 
     366                 :         24 :   int nGeometries = 0;
     367                 :         24 :   wkbPtr >> nGeometries;
     368                 :            : 
     369                 :         24 :   QVector<QgsAbstractGeometry *> geometryListBackup = mGeometries;
     370                 :         24 :   mGeometries.clear();
     371                 :         24 :   mGeometries.reserve( nGeometries );
     372                 :         72 :   for ( int i = 0; i < nGeometries; ++i )
     373                 :            :   {
     374                 :         48 :     std::unique_ptr< QgsAbstractGeometry > geom( QgsGeometryFactory::geomFromWkb( wkbPtr ) );  // also updates wkbPtr
     375                 :         48 :     if ( geom )
     376                 :            :     {
     377                 :         48 :       if ( !addGeometry( geom.release() ) )
     378                 :            :       {
     379                 :          0 :         qDeleteAll( mGeometries );
     380                 :          0 :         mGeometries = geometryListBackup;
     381                 :          0 :         return false;
     382                 :            :       }
     383                 :         48 :     }
     384                 :         48 :   }
     385                 :         24 :   qDeleteAll( geometryListBackup );
     386                 :            : 
     387                 :         24 :   clearCache(); //set bounding box invalid
     388                 :            : 
     389                 :         24 :   return true;
     390                 :         36 : }
     391                 :            : 
     392                 :        416 : bool QgsGeometryCollection::fromWkt( const QString &wkt )
     393                 :            : {
     394                 :        832 :   return fromCollectionWkt( wkt, QVector<QgsAbstractGeometry *>() << new QgsPoint << new QgsLineString << new QgsPolygon
     395                 :        416 :                             << new QgsCircularString << new QgsCompoundCurve
     396                 :        416 :                             << new QgsCurvePolygon
     397                 :        416 :                             << new QgsMultiPoint << new QgsMultiLineString
     398                 :        416 :                             << new QgsMultiPolygon << new QgsGeometryCollection
     399                 :        832 :                             << new QgsMultiCurve << new QgsMultiSurface, QStringLiteral( "GeometryCollection" ) );
     400                 :          0 : }
     401                 :            : 
     402                 :         39 : int QgsGeometryCollection::wkbSize( QgsAbstractGeometry::WkbFlags flags ) const
     403                 :            : {
     404                 :         39 :   int binarySize = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
     405                 :        108 :   for ( const QgsAbstractGeometry *geom : mGeometries )
     406                 :            :   {
     407                 :         69 :     if ( geom )
     408                 :            :     {
     409                 :         69 :       binarySize += geom->wkbSize( flags );
     410                 :         69 :     }
     411                 :            :   }
     412                 :            : 
     413                 :         39 :   return binarySize;
     414                 :            : }
     415                 :            : 
     416                 :         37 : QByteArray QgsGeometryCollection::asWkb( WkbFlags flags ) const
     417                 :            : {
     418                 :         37 :   int countNonNull = 0;
     419                 :        102 :   for ( const QgsAbstractGeometry *geom : mGeometries )
     420                 :            :   {
     421                 :         65 :     if ( geom )
     422                 :            :     {
     423                 :         65 :       countNonNull ++;
     424                 :         65 :     }
     425                 :            :   }
     426                 :            : 
     427                 :         37 :   QByteArray wkbArray;
     428                 :         37 :   wkbArray.resize( QgsGeometryCollection::wkbSize( flags ) );
     429                 :         37 :   QgsWkbPtr wkb( wkbArray );
     430                 :         37 :   wkb << static_cast<char>( QgsApplication::endian() );
     431                 :         37 :   wkb << static_cast<quint32>( wkbType() );
     432                 :         37 :   wkb << static_cast<quint32>( countNonNull );
     433                 :        102 :   for ( const QgsAbstractGeometry *geom : mGeometries )
     434                 :            :   {
     435                 :         65 :     if ( geom )
     436                 :            :     {
     437                 :         65 :       wkb << geom->asWkb( flags );
     438                 :         65 :     }
     439                 :            :   }
     440                 :         37 :   return wkbArray;
     441                 :         37 : }
     442                 :            : 
     443                 :       2059 : QString QgsGeometryCollection::asWkt( int precision ) const
     444                 :            : {
     445                 :       2059 :   QString wkt = wktTypeStr();
     446                 :            : 
     447                 :       2059 :   if ( isEmpty() )
     448                 :       2014 :     wkt += QLatin1String( " EMPTY" );
     449                 :            :   else
     450                 :            :   {
     451                 :         45 :     wkt += QLatin1String( " (" );
     452                 :        120 :     for ( const QgsAbstractGeometry *geom : mGeometries )
     453                 :            :     {
     454                 :         75 :       QString childWkt = geom->asWkt( precision );
     455                 :         75 :       if ( wktOmitChildType() )
     456                 :            :       {
     457                 :         40 :         childWkt = childWkt.mid( childWkt.indexOf( '(' ) );
     458                 :         40 :       }
     459                 :         75 :       wkt += childWkt + ',';
     460                 :         75 :     }
     461                 :         45 :     if ( wkt.endsWith( ',' ) )
     462                 :            :     {
     463                 :         45 :       wkt.chop( 1 ); // Remove last ','
     464                 :         45 :     }
     465                 :         45 :     wkt += ')';
     466                 :            :   }
     467                 :       2059 :   return wkt;
     468                 :       2059 : }
     469                 :            : 
     470                 :          4 : QDomElement QgsGeometryCollection::asGml2( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
     471                 :            : {
     472                 :          8 :   QDomElement elemMultiGeometry = doc.createElementNS( ns, QStringLiteral( "MultiGeometry" ) );
     473                 :          9 :   for ( const QgsAbstractGeometry *geom : mGeometries )
     474                 :            :   {
     475                 :         10 :     QDomElement elemGeometryMember = doc.createElementNS( ns, QStringLiteral( "geometryMember" ) );
     476                 :          5 :     elemGeometryMember.appendChild( geom->asGml2( doc, precision, ns, axisOrder ) );
     477                 :          5 :     elemMultiGeometry.appendChild( elemGeometryMember );
     478                 :          5 :   }
     479                 :          4 :   return elemMultiGeometry;
     480                 :          4 : }
     481                 :            : 
     482                 :          4 : QDomElement QgsGeometryCollection::asGml3( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
     483                 :            : {
     484                 :          8 :   QDomElement elemMultiGeometry = doc.createElementNS( ns, QStringLiteral( "MultiGeometry" ) );
     485                 :          9 :   for ( const QgsAbstractGeometry *geom : mGeometries )
     486                 :            :   {
     487                 :         10 :     QDomElement elemGeometryMember = doc.createElementNS( ns, QStringLiteral( "geometryMember" ) );
     488                 :          5 :     elemGeometryMember.appendChild( geom->asGml3( doc, precision, ns, axisOrder ) );
     489                 :          5 :     elemMultiGeometry.appendChild( elemGeometryMember );
     490                 :          5 :   }
     491                 :          4 :   return elemMultiGeometry;
     492                 :          4 : }
     493                 :            : 
     494                 :          4 : json QgsGeometryCollection::asJsonObject( int precision ) const
     495                 :            : {
     496                 :          4 :   json coordinates( json::array( ) );
     497                 :          9 :   for ( const QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
     498                 :            :   {
     499                 :          5 :     coordinates.push_back( geom->asJsonObject( precision ) );
     500                 :            :   }
     501                 :         16 :   return
     502                 :         12 :   {
     503                 :          4 :     { "type",  "GeometryCollection" },
     504                 :          4 :     { "geometries", coordinates }
     505                 :            :   };
     506                 :          4 : }
     507                 :            : 
     508                 :         10 : QString QgsGeometryCollection::asKml( int precision ) const
     509                 :            : {
     510                 :         10 :   QString kml;
     511                 :         10 :   kml.append( QLatin1String( "<MultiGeometry>" ) );
     512                 :         10 :   const QVector< QgsAbstractGeometry * > &geometries = mGeometries;
     513                 :         29 :   for ( const QgsAbstractGeometry *geometry : geometries )
     514                 :            :   {
     515                 :         19 :     kml.append( geometry->asKml( precision ) );
     516                 :            :   }
     517                 :         10 :   kml.append( QLatin1String( "</MultiGeometry>" ) );
     518                 :         10 :   return kml;
     519                 :         10 : }
     520                 :            : 
     521                 :       1194 : QgsRectangle QgsGeometryCollection::boundingBox() const
     522                 :            : {
     523                 :       1194 :   if ( mBoundingBox.isNull() )
     524                 :            :   {
     525                 :        995 :     mBoundingBox = calculateBoundingBox();
     526                 :        995 :   }
     527                 :       1194 :   return mBoundingBox;
     528                 :            : }
     529                 :            : 
     530                 :        995 : QgsRectangle QgsGeometryCollection::calculateBoundingBox() const
     531                 :            : {
     532                 :        995 :   if ( mGeometries.empty() )
     533                 :            :   {
     534                 :          1 :     return QgsRectangle();
     535                 :            :   }
     536                 :            : 
     537                 :        994 :   QgsRectangle bbox = mGeometries.at( 0 )->boundingBox();
     538                 :       1055 :   for ( int i = 1; i < mGeometries.size(); ++i )
     539                 :            :   {
     540                 :         61 :     if ( mGeometries.at( i )->isEmpty() )
     541                 :          0 :       continue;
     542                 :            : 
     543                 :         61 :     QgsRectangle geomBox = mGeometries.at( i )->boundingBox();
     544                 :         61 :     if ( bbox.isNull() )
     545                 :            :     {
     546                 :            :       // workaround treatment of a QgsRectangle(0,0,0,0) as a "null"/invalid rectangle
     547                 :            :       // if bbox is null, then the first geometry must have returned a bounding box of (0,0,0,0)
     548                 :            :       // so just manually include that as a point... ew.
     549                 :          3 :       geomBox.combineExtentWith( QPointF( 0, 0 ) );
     550                 :          3 :       bbox = geomBox;
     551                 :          3 :     }
     552                 :         58 :     else if ( geomBox.isNull() )
     553                 :            :     {
     554                 :            :       // ...as above... this part must have a bounding box of (0,0,0,0).
     555                 :            :       // if we try to combine the extent with this "null" box it will just be ignored.
     556                 :          1 :       bbox.combineExtentWith( QPointF( 0, 0 ) );
     557                 :          1 :     }
     558                 :            :     else
     559                 :            :     {
     560                 :         57 :       bbox.combineExtentWith( geomBox );
     561                 :            :     }
     562                 :         61 :   }
     563                 :        994 :   return bbox;
     564                 :        995 : }
     565                 :            : 
     566                 :       7064 : void QgsGeometryCollection::clearCache() const
     567                 :            : {
     568                 :       7064 :   mBoundingBox = QgsRectangle();
     569                 :       7064 :   mHasCachedValidity = false;
     570                 :       7064 :   mValidityFailureReason.clear();
     571                 :       7064 :   QgsAbstractGeometry::clearCache();
     572                 :       7064 : }
     573                 :            : 
     574                 :          2 : QgsCoordinateSequence QgsGeometryCollection::coordinateSequence() const
     575                 :            : {
     576                 :          2 :   QgsCoordinateSequence sequence;
     577                 :          2 :   QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
     578                 :          6 :   for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
     579                 :            :   {
     580                 :          4 :     QgsCoordinateSequence geomCoords = ( *geomIt )->coordinateSequence();
     581                 :            : 
     582                 :          4 :     QgsCoordinateSequence::const_iterator cIt = geomCoords.constBegin();
     583                 :          8 :     for ( ; cIt != geomCoords.constEnd(); ++cIt )
     584                 :            :     {
     585                 :          4 :       sequence.push_back( *cIt );
     586                 :          4 :     }
     587                 :          4 :   }
     588                 :            : 
     589                 :          2 :   return sequence;
     590                 :          2 : }
     591                 :            : 
     592                 :         40 : int QgsGeometryCollection::nCoordinates() const
     593                 :            : {
     594                 :         40 :   int count = 0;
     595                 :            : 
     596                 :         40 :   QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
     597                 :         78 :   for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
     598                 :            :   {
     599                 :         38 :     count += ( *geomIt )->nCoordinates();
     600                 :         38 :   }
     601                 :            : 
     602                 :         40 :   return count;
     603                 :            : }
     604                 :            : 
     605                 :         24 : double QgsGeometryCollection::closestSegment( const QgsPoint &pt, QgsPoint &segmentPt,  QgsVertexId &vertexAfter, int *leftOf, double epsilon ) const
     606                 :            : {
     607                 :         24 :   return QgsGeometryUtils::closestSegmentFromComponents( mGeometries, QgsGeometryUtils::Part, pt, segmentPt, vertexAfter, leftOf, epsilon );
     608                 :            : }
     609                 :            : 
     610                 :         39 : bool QgsGeometryCollection::nextVertex( QgsVertexId &id, QgsPoint &vertex ) const
     611                 :            : {
     612                 :         39 :   if ( id.part < 0 )
     613                 :            :   {
     614                 :          3 :     id.part = 0;
     615                 :          3 :     id.ring = -1;
     616                 :          3 :     id.vertex = -1;
     617                 :          3 :   }
     618                 :         39 :   if ( mGeometries.isEmpty() )
     619                 :            :   {
     620                 :          3 :     return false;
     621                 :            :   }
     622                 :            : 
     623                 :         36 :   if ( id.part >= mGeometries.count() )
     624                 :          2 :     return false;
     625                 :            : 
     626                 :         34 :   QgsAbstractGeometry *geom = mGeometries.at( id.part );
     627                 :         34 :   if ( geom->nextVertex( id, vertex ) )
     628                 :            :   {
     629                 :         30 :     return true;
     630                 :            :   }
     631                 :          4 :   if ( ( id.part + 1 ) >= numGeometries() )
     632                 :            :   {
     633                 :          2 :     return false;
     634                 :            :   }
     635                 :          2 :   ++id.part;
     636                 :          2 :   id.ring = -1;
     637                 :          2 :   id.vertex = -1;
     638                 :          2 :   return mGeometries.at( id.part )->nextVertex( id, vertex );
     639                 :         39 : }
     640                 :            : 
     641                 :         16 : bool QgsGeometryCollection::insertVertex( QgsVertexId position, const QgsPoint &vertex )
     642                 :            : {
     643                 :         16 :   if ( position.part >= mGeometries.size() )
     644                 :            :   {
     645                 :          6 :     return false;
     646                 :            :   }
     647                 :            : 
     648                 :         10 :   bool success = mGeometries.at( position.part )->insertVertex( position, vertex );
     649                 :         10 :   if ( success )
     650                 :            :   {
     651                 :          6 :     clearCache(); //set bounding box invalid
     652                 :          6 :   }
     653                 :         10 :   return success;
     654                 :         16 : }
     655                 :            : 
     656                 :         18 : bool QgsGeometryCollection::moveVertex( QgsVertexId position, const QgsPoint &newPos )
     657                 :            : {
     658                 :         18 :   if ( position.part < 0 || position.part >= mGeometries.size() )
     659                 :            :   {
     660                 :          5 :     return false;
     661                 :            :   }
     662                 :            : 
     663                 :         13 :   bool success = mGeometries.at( position.part )->moveVertex( position, newPos );
     664                 :         13 :   if ( success )
     665                 :            :   {
     666                 :          9 :     clearCache(); //set bounding box invalid
     667                 :          9 :   }
     668                 :         13 :   return success;
     669                 :         18 : }
     670                 :            : 
     671                 :         31 : bool QgsGeometryCollection::deleteVertex( QgsVertexId position )
     672                 :            : {
     673                 :         31 :   if ( position.part < 0 || position.part >= mGeometries.size() )
     674                 :            :   {
     675                 :          6 :     return false;
     676                 :            :   }
     677                 :            : 
     678                 :         25 :   QgsAbstractGeometry *geom = mGeometries.at( position.part );
     679                 :         25 :   if ( !geom )
     680                 :            :   {
     681                 :          0 :     return false;
     682                 :            :   }
     683                 :            : 
     684                 :         25 :   bool success = geom->deleteVertex( position );
     685                 :            : 
     686                 :            :   //remove geometry if no vertices left
     687                 :         25 :   if ( geom->isEmpty() )
     688                 :            :   {
     689                 :          3 :     removeGeometry( position.part );
     690                 :          3 :   }
     691                 :            : 
     692                 :         25 :   if ( success )
     693                 :            :   {
     694                 :         21 :     clearCache(); //set bounding box invalid
     695                 :         21 :   }
     696                 :         25 :   return success;
     697                 :         31 : }
     698                 :            : 
     699                 :          0 : double QgsGeometryCollection::length() const
     700                 :            : {
     701                 :          0 :   double length = 0.0;
     702                 :          0 :   QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
     703                 :          0 :   for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
     704                 :            :   {
     705                 :          0 :     length += ( *geomIt )->length();
     706                 :          0 :   }
     707                 :          0 :   return length;
     708                 :            : }
     709                 :            : 
     710                 :         10 : double QgsGeometryCollection::area() const
     711                 :            : {
     712                 :         10 :   double area = 0.0;
     713                 :         10 :   QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
     714                 :         14 :   for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
     715                 :            :   {
     716                 :          4 :     area += ( *geomIt )->area();
     717                 :          4 :   }
     718                 :         10 :   return area;
     719                 :            : }
     720                 :            : 
     721                 :         10 : double QgsGeometryCollection::perimeter() const
     722                 :            : {
     723                 :         10 :   double perimeter = 0.0;
     724                 :         10 :   QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
     725                 :         14 :   for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
     726                 :            :   {
     727                 :          4 :     perimeter += ( *geomIt )->perimeter();
     728                 :          4 :   }
     729                 :         10 :   return perimeter;
     730                 :            : }
     731                 :            : 
     732                 :       2109 : bool QgsGeometryCollection::fromCollectionWkt( const QString &wkt, const QVector<QgsAbstractGeometry *> &subtypes, const QString &defaultChildWkbType )
     733                 :            : {
     734                 :       2109 :   clear();
     735                 :            : 
     736                 :       2109 :   QPair<QgsWkbTypes::Type, QString> parts = QgsGeometryUtils::wktReadBlock( wkt );
     737                 :            : 
     738                 :       2109 :   if ( QgsWkbTypes::flatType( parts.first ) != QgsWkbTypes::flatType( wkbType() ) )
     739                 :            :   {
     740                 :          6 :     qDeleteAll( subtypes );
     741                 :          6 :     return false;
     742                 :            :   }
     743                 :       2103 :   mWkbType = parts.first;
     744                 :            : 
     745                 :       2103 :   QString secondWithoutParentheses = parts.second;
     746                 :       2103 :   secondWithoutParentheses = secondWithoutParentheses.remove( '(' ).remove( ')' ).simplified().remove( ' ' );
     747                 :       2199 :   if ( ( parts.second.compare( QLatin1String( "EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
     748                 :         96 :        secondWithoutParentheses.isEmpty() )
     749                 :       2026 :     return true;
     750                 :            : 
     751                 :        173 :   QString defChildWkbType = QStringLiteral( "%1%2%3 " ).arg( defaultChildWkbType, is3D() ? QStringLiteral( "Z" ) : QString(), isMeasure() ? QStringLiteral( "M" ) : QString() );
     752                 :            : 
     753                 :         77 :   const QStringList blocks = QgsGeometryUtils::wktGetChildBlocks( parts.second, defChildWkbType );
     754                 :        210 :   for ( const QString &childWkt : blocks )
     755                 :            :   {
     756                 :        141 :     QPair<QgsWkbTypes::Type, QString> childParts = QgsGeometryUtils::wktReadBlock( childWkt );
     757                 :            : 
     758                 :        141 :     bool success = false;
     759                 :        207 :     for ( const QgsAbstractGeometry *geom : subtypes )
     760                 :            :     {
     761                 :        199 :       if ( QgsWkbTypes::flatType( childParts.first ) == QgsWkbTypes::flatType( geom->wkbType() ) )
     762                 :            :       {
     763                 :        141 :         mGeometries.append( geom->clone() );
     764                 :        141 :         if ( mGeometries.back()->fromWkt( childWkt ) )
     765                 :            :         {
     766                 :        133 :           success = true;
     767                 :        133 :           break;
     768                 :            :         }
     769                 :          8 :       }
     770                 :            :     }
     771                 :        141 :     if ( !success )
     772                 :            :     {
     773                 :          8 :       clear();
     774                 :          8 :       qDeleteAll( subtypes );
     775                 :          8 :       return false;
     776                 :            :     }
     777                 :        141 :   }
     778                 :         69 :   qDeleteAll( subtypes );
     779                 :            : 
     780                 :            :   //scan through geometries and check if dimensionality of geometries is different to collection.
     781                 :            :   //if so, update the type dimensionality of the collection to match
     782                 :         69 :   bool hasZ = false;
     783                 :         69 :   bool hasM = false;
     784                 :        188 :   for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
     785                 :            :   {
     786                 :        127 :     hasZ = hasZ || geom->is3D();
     787                 :        127 :     hasM = hasM || geom->isMeasure();
     788                 :        127 :     if ( hasZ && hasM )
     789                 :          8 :       break;
     790                 :            :   }
     791                 :         69 :   if ( hasZ )
     792                 :         11 :     addZValue( 0 );
     793                 :         69 :   if ( hasM )
     794                 :         10 :     addMValue( 0 );
     795                 :            : 
     796                 :         69 :   return true;
     797                 :       2109 : }
     798                 :            : 
     799                 :         15 : bool QgsGeometryCollection::hasCurvedSegments() const
     800                 :            : {
     801                 :         15 :   QVector< QgsAbstractGeometry * >::const_iterator it = mGeometries.constBegin();
     802                 :         21 :   for ( ; it != mGeometries.constEnd(); ++it )
     803                 :            :   {
     804                 :          9 :     if ( ( *it )->hasCurvedSegments() )
     805                 :            :     {
     806                 :          3 :       return true;
     807                 :            :     }
     808                 :          6 :   }
     809                 :         12 :   return false;
     810                 :         15 : }
     811                 :            : 
     812                 :          2 : QgsAbstractGeometry *QgsGeometryCollection::segmentize( double tolerance, SegmentationToleranceType toleranceType ) const
     813                 :            : {
     814                 :          2 :   std::unique_ptr< QgsAbstractGeometry > geom( QgsGeometryFactory::geomFromWkbType( QgsWkbTypes::linearType( mWkbType ) ) );
     815                 :          2 :   QgsGeometryCollection *geomCollection = qgsgeometry_cast<QgsGeometryCollection *>( geom.get() );
     816                 :          2 :   if ( !geomCollection )
     817                 :            :   {
     818                 :          0 :     return clone();
     819                 :            :   }
     820                 :            : 
     821                 :          2 :   geomCollection->reserve( mGeometries.size() );
     822                 :          2 :   QVector< QgsAbstractGeometry * >::const_iterator geomIt = mGeometries.constBegin();
     823                 :          4 :   for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
     824                 :            :   {
     825                 :          2 :     geomCollection->addGeometry( ( *geomIt )->segmentize( tolerance, toleranceType ) );
     826                 :          2 :   }
     827                 :          2 :   return geom.release();
     828                 :          2 : }
     829                 :            : 
     830                 :         33 : double QgsGeometryCollection::vertexAngle( QgsVertexId vertex ) const
     831                 :            : {
     832                 :         33 :   if ( vertex.part < 0 || vertex.part >= mGeometries.size() )
     833                 :            :   {
     834                 :          5 :     return 0.0;
     835                 :            :   }
     836                 :            : 
     837                 :         28 :   QgsAbstractGeometry *geom = mGeometries[vertex.part];
     838                 :         28 :   if ( !geom )
     839                 :            :   {
     840                 :          0 :     return 0.0;
     841                 :            :   }
     842                 :            : 
     843                 :         28 :   return geom->vertexAngle( vertex );
     844                 :         33 : }
     845                 :            : 
     846                 :         37 : double QgsGeometryCollection::segmentLength( QgsVertexId startVertex ) const
     847                 :            : {
     848                 :         37 :   if ( startVertex.part < 0 || startVertex.part >= mGeometries.size() )
     849                 :            :   {
     850                 :         15 :     return 0.0;
     851                 :            :   }
     852                 :            : 
     853                 :         22 :   const QgsAbstractGeometry *geom = mGeometries[startVertex.part];
     854                 :         22 :   if ( !geom )
     855                 :            :   {
     856                 :          0 :     return 0.0;
     857                 :            :   }
     858                 :            : 
     859                 :         22 :   return geom->segmentLength( startVertex );
     860                 :         37 : }
     861                 :            : 
     862                 :        374 : int QgsGeometryCollection::vertexCount( int part, int ring ) const
     863                 :            : {
     864                 :        374 :   if ( part < 0 || part >= mGeometries.size() )
     865                 :            :   {
     866                 :         34 :     return 0;
     867                 :            :   }
     868                 :            : 
     869                 :        340 :   return mGeometries[part]->vertexCount( 0, ring );
     870                 :        374 : }
     871                 :            : 
     872                 :        270 : int QgsGeometryCollection::ringCount( int part ) const
     873                 :            : {
     874                 :        270 :   if ( part < 0 || part >= mGeometries.size() )
     875                 :            :   {
     876                 :         23 :     return 0;
     877                 :            :   }
     878                 :            : 
     879                 :        247 :   return mGeometries[part]->ringCount();
     880                 :        270 : }
     881                 :            : 
     882                 :        537 : int QgsGeometryCollection::partCount() const
     883                 :            : {
     884                 :        537 :   return mGeometries.size();
     885                 :            : }
     886                 :            : 
     887                 :       3328 : QgsPoint QgsGeometryCollection::vertexAt( QgsVertexId id ) const
     888                 :            : {
     889                 :       3328 :   return mGeometries[id.part]->vertexAt( id );
     890                 :            : }
     891                 :            : 
     892                 :          3 : bool QgsGeometryCollection::isValid( QString &error, int flags ) const
     893                 :            : {
     894                 :          3 :   if ( flags == 0 && mHasCachedValidity )
     895                 :            :   {
     896                 :            :     // use cached validity results
     897                 :          0 :     error = mValidityFailureReason;
     898                 :          0 :     return error.isEmpty();
     899                 :            :   }
     900                 :            : 
     901                 :          3 :   QgsGeos geos( this );
     902                 :          3 :   bool res = geos.isValid( &error, flags & QgsGeometry::FlagAllowSelfTouchingHoles, nullptr );
     903                 :          3 :   if ( flags == 0 )
     904                 :            :   {
     905                 :          3 :     mValidityFailureReason = !res ? error : QString();
     906                 :          3 :     mHasCachedValidity = true;
     907                 :          3 :   }
     908                 :          3 :   return res;
     909                 :          3 : }
     910                 :            : 
     911                 :         15 : bool QgsGeometryCollection::addZValue( double zValue )
     912                 :            : {
     913                 :         15 :   if ( QgsWkbTypes::hasZ( mWkbType ) )
     914                 :         10 :     return false;
     915                 :            : 
     916                 :          5 :   mWkbType = QgsWkbTypes::addZ( mWkbType );
     917                 :            : 
     918                 :          7 :   for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
     919                 :            :   {
     920                 :          2 :     geom->addZValue( zValue );
     921                 :            :   }
     922                 :          5 :   clearCache();
     923                 :          5 :   return true;
     924                 :         15 : }
     925                 :            : 
     926                 :         14 : bool QgsGeometryCollection::addMValue( double mValue )
     927                 :            : {
     928                 :         14 :   if ( QgsWkbTypes::hasM( mWkbType ) )
     929                 :          9 :     return false;
     930                 :            : 
     931                 :          5 :   mWkbType = QgsWkbTypes::addM( mWkbType );
     932                 :            : 
     933                 :          7 :   for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
     934                 :            :   {
     935                 :          2 :     geom->addMValue( mValue );
     936                 :            :   }
     937                 :          5 :   clearCache();
     938                 :          5 :   return true;
     939                 :         14 : }
     940                 :            : 
     941                 :            : 
     942                 :          4 : bool QgsGeometryCollection::dropZValue()
     943                 :            : {
     944                 :          4 :   if ( mWkbType != QgsWkbTypes::GeometryCollection && !is3D() )
     945                 :          0 :     return false;
     946                 :            : 
     947                 :          4 :   mWkbType = QgsWkbTypes::dropZ( mWkbType );
     948                 :         10 :   for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
     949                 :            :   {
     950                 :          6 :     geom->dropZValue();
     951                 :            :   }
     952                 :          4 :   clearCache();
     953                 :          4 :   return true;
     954                 :          4 : }
     955                 :            : 
     956                 :          4 : bool QgsGeometryCollection::dropMValue()
     957                 :            : {
     958                 :          4 :   if ( mWkbType != QgsWkbTypes::GeometryCollection && !isMeasure() )
     959                 :          0 :     return false;
     960                 :            : 
     961                 :          4 :   mWkbType = QgsWkbTypes::dropM( mWkbType );
     962                 :         10 :   for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
     963                 :            :   {
     964                 :          6 :     geom->dropMValue();
     965                 :            :   }
     966                 :          4 :   clearCache();
     967                 :          4 :   return true;
     968                 :          4 : }
     969                 :            : 
     970                 :          3 : void QgsGeometryCollection::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
     971                 :            : {
     972                 :          6 :   for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
     973                 :            :   {
     974                 :          3 :     if ( geom )
     975                 :          3 :       geom->filterVertices( filter );
     976                 :            :   }
     977                 :          3 :   clearCache();
     978                 :          3 : }
     979                 :            : 
     980                 :          3 : void QgsGeometryCollection::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
     981                 :            : {
     982                 :          6 :   for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
     983                 :            :   {
     984                 :          3 :     if ( geom )
     985                 :          3 :       geom->transformVertices( transform );
     986                 :            :   }
     987                 :          3 :   clearCache();
     988                 :          3 : }
     989                 :            : 
     990                 :          3 : void QgsGeometryCollection::swapXy()
     991                 :            : {
     992                 :          6 :   for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
     993                 :            :   {
     994                 :          3 :     if ( geom )
     995                 :          3 :       geom->swapXy();
     996                 :            :   }
     997                 :          3 :   clearCache();
     998                 :          3 : }
     999                 :            : 
    1000                 :          1 : QgsGeometryCollection *QgsGeometryCollection::toCurveType() const
    1001                 :            : {
    1002                 :          1 :   std::unique_ptr< QgsGeometryCollection > newCollection( new QgsGeometryCollection() );
    1003                 :          1 :   newCollection->reserve( mGeometries.size() );
    1004                 :          3 :   for ( QgsAbstractGeometry *geom : mGeometries )
    1005                 :            :   {
    1006                 :          2 :     newCollection->addGeometry( geom->toCurveType() );
    1007                 :            :   }
    1008                 :          1 :   return newCollection.release();
    1009                 :          1 : }
    1010                 :            : 
    1011                 :          4 : bool QgsGeometryCollection::transform( QgsAbstractGeometryTransformer *transformer, QgsFeedback *feedback )
    1012                 :            : {
    1013                 :          4 :   if ( !transformer )
    1014                 :          0 :     return false;
    1015                 :            : 
    1016                 :          4 :   bool res = true;
    1017                 :          7 :   for ( QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
    1018                 :            :   {
    1019                 :          4 :     if ( geom )
    1020                 :          4 :       res = geom->transform( transformer, feedback );
    1021                 :            : 
    1022                 :          4 :     if ( feedback && feedback->isCanceled() )
    1023                 :          0 :       res = false;
    1024                 :            : 
    1025                 :          4 :     if ( !res )
    1026                 :          1 :       break;
    1027                 :            :   }
    1028                 :          4 :   clearCache();
    1029                 :          4 :   return res;
    1030                 :          4 : }
    1031                 :            : 
    1032                 :         35 : bool QgsGeometryCollection::wktOmitChildType() const
    1033                 :            : {
    1034                 :         35 :   return false;
    1035                 :            : }
    1036                 :            : 
    1037                 :        578 : int QgsGeometryCollection::childCount() const
    1038                 :            : {
    1039                 :        578 :   return mGeometries.count();
    1040                 :            : }
    1041                 :            : 
    1042                 :         38 : QgsAbstractGeometry *QgsGeometryCollection::childGeometry( int index ) const
    1043                 :            : {
    1044                 :         38 :   if ( index < 0 || index > mGeometries.count() )
    1045                 :          0 :     return nullptr;
    1046                 :         38 :   return mGeometries.at( index );
    1047                 :         38 : }

Generated by: LCOV version 1.14