LCOV - code coverage report
Current view: top level - home/lbartoletti/qgis/tests/src/core - testqgsgeometry.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 15103 15133 99.8 %
Date: 2021-03-26 12:19:53 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :      testqgsgeometry.cpp
       3                 :            :      --------------------------------------
       4                 :            :     Date                 : 20 Jan 2008
       5                 :            :     Copyright            : (C) 2008 by Tim Sutton
       6                 :            :     Email                : tim @ linfiniti.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                 :            : #include "qgstest.h"
      16                 :            : #include <cmath>
      17                 :            : #include <memory>
      18                 :            : #include <limits>
      19                 :            : #include <QObject>
      20                 :            : #include <QString>
      21                 :            : #include <QStringList>
      22                 :            : #include <QApplication>
      23                 :            : #include <QFileInfo>
      24                 :            : #include <QDir>
      25                 :            : #include <QDesktopServices>
      26                 :            : #include <QVector>
      27                 :            : #include <QPointF>
      28                 :            : #include <QImage>
      29                 :            : #include <QPainter>
      30                 :            : 
      31                 :            : //qgis includes...
      32                 :            : #include <qgsapplication.h>
      33                 :            : #include "qgscompoundcurve.h"
      34                 :            : #include <qgsgeometry.h>
      35                 :            : #include "qgsgeometryutils.h"
      36                 :            : #include <qgspoint.h>
      37                 :            : #include "qgspoint.h"
      38                 :            : #include "qgslinestring.h"
      39                 :            : #include "qgspolygon.h"
      40                 :            : #include "qgstriangle.h"
      41                 :            : #include "qgsgeometryengine.h"
      42                 :            : #include "qgscircle.h"
      43                 :            : #include "qgsellipse.h"
      44                 :            : #include "qgsquadrilateral.h"
      45                 :            : #include "qgsregularpolygon.h"
      46                 :            : #include "qgsmultipoint.h"
      47                 :            : #include "qgsmultilinestring.h"
      48                 :            : #include "qgsmultipolygon.h"
      49                 :            : #include "qgscircularstring.h"
      50                 :            : #include "qgsgeometrycollection.h"
      51                 :            : #include "qgsgeometryfactory.h"
      52                 :            : #include "qgscurvepolygon.h"
      53                 :            : #include "qgsproject.h"
      54                 :            : #include "qgslinesegment.h"
      55                 :            : #include "qgsgeos.h"
      56                 :            : #include "qgsreferencedgeometry.h"
      57                 :            : #include "qgsgeometrytransformer.h"
      58                 :            : 
      59                 :            : //qgs unit test utility class
      60                 :            : #include "qgsrenderchecker.h"
      61                 :            : 
      62                 :         12 : class TestTransformer : public QgsAbstractGeometryTransformer
      63                 :            : {
      64                 :            :   public:
      65                 :            : 
      66                 :         50 :     bool transformPoint( double &x, double &y, double &z, double &m ) override
      67                 :            :     {
      68                 :         50 :       x *= 3;
      69                 :         50 :       y += 14;
      70                 :         50 :       z += 5;
      71                 :         50 :       m -= 1;
      72                 :         50 :       return true;
      73                 :            :     }
      74                 :            : };
      75                 :            : 
      76                 :            : 
      77                 :         12 : class TestFailTransformer : public QgsAbstractGeometryTransformer
      78                 :            : {
      79                 :            :   public:
      80                 :            : 
      81                 :          6 :     bool transformPoint( double &x, double &y, double &z, double &m ) override
      82                 :            :     {
      83                 :          6 :       x *= 3;
      84                 :          6 :       y += 14;
      85                 :          6 :       z += 5;
      86                 :          6 :       m -= 1;
      87                 :          6 :       return false;
      88                 :            :     }
      89                 :            : };
      90                 :            : 
      91                 :            : 
      92                 :            : /**
      93                 :            :  * \ingroup UnitTests
      94                 :            :  * This is a unit test for the different geometry operations on vector features.
      95                 :            :  */
      96                 :          1 : class TestQgsGeometry : public QObject
      97                 :            : {
      98                 :            :     Q_OBJECT
      99                 :            : 
     100                 :            :   public:
     101                 :            :     TestQgsGeometry();
     102                 :            : 
     103                 :         12 :     static QgsAbstractGeometry *createEmpty( QgsAbstractGeometry *geom )
     104                 :            :     {
     105                 :         12 :       return geom->createEmptyWithSameType();
     106                 :            :     }
     107                 :            : 
     108                 :            :   private slots:
     109                 :            :     void initTestCase();// will be called before the first testfunction is executed.
     110                 :            :     void cleanupTestCase();// will be called after the last testfunction was executed.
     111                 :            :     void cleanup();// will be called after every testfunction.
     112                 :            :     void copy();
     113                 :            :     void assignment();
     114                 :            :     void asVariant(); //test conversion to and from a QVariant
     115                 :            :     void referenced();
     116                 :            :     void isEmpty();
     117                 :            :     void isValid();
     118                 :            :     void equality();
     119                 :            :     void vertexIterator();
     120                 :            :     void partIterator();
     121                 :            : 
     122                 :            :     void geos();
     123                 :            : 
     124                 :            :     // geometry types
     125                 :            :     void point(); //test QgsPointV2
     126                 :            :     void lineString(); //test QgsLineString
     127                 :            :     void circularString();
     128                 :            :     void polygon(); //test QgsPolygon
     129                 :            :     void curvePolygon();
     130                 :            :     void triangle();
     131                 :            :     void circle();
     132                 :            :     void ellipse();
     133                 :            :     void quadrilateral();
     134                 :            :     void regularPolygon();
     135                 :            :     void compoundCurve(); //test QgsCompoundCurve
     136                 :            :     void multiPoint();
     137                 :            :     void multiLineString();
     138                 :            :     void multiCurve();
     139                 :            :     void multiSurface();
     140                 :            :     void multiPolygon();
     141                 :            :     void geometryCollection();
     142                 :            : 
     143                 :            :     void fromQgsPointXY();
     144                 :            :     void fromQPoint();
     145                 :            :     void fromQPolygonF();
     146                 :            :     void fromPolyline();
     147                 :            :     void asQPointF();
     148                 :            :     void asQPolygonF();
     149                 :            : 
     150                 :            :     void comparePolylines();
     151                 :            :     void comparePolygons();
     152                 :            : 
     153                 :            :     void createEmptyWithSameType();
     154                 :            : 
     155                 :            :     // MK, Disabled 14.11.2014
     156                 :            :     // Too unclear what exactly should be tested and which variations are allowed for the line
     157                 :            : #if 0
     158                 :            :     void simplifyCheck1();
     159                 :            : #endif
     160                 :            : 
     161                 :            :     void intersectionCheck1();
     162                 :            :     void intersectionCheck2();
     163                 :            :     void translateCheck1();
     164                 :            :     void rotateCheck1();
     165                 :            :     void unionCheck1();
     166                 :            :     void unionCheck2();
     167                 :            :     void differenceCheck1();
     168                 :            :     void differenceCheck2();
     169                 :            :     void bufferCheck();
     170                 :            :     void smoothCheck();
     171                 :            :     void shortestLineEmptyGeometry();
     172                 :            : 
     173                 :            :     void unaryUnion();
     174                 :            : 
     175                 :            :     void dataStream();
     176                 :            : 
     177                 :            :     void exportToGeoJSON();
     178                 :            : 
     179                 :            :     void wkbInOut();
     180                 :            : 
     181                 :            :     void directionNeutralSegmentation();
     182                 :            :     void poleOfInaccessibility();
     183                 :            : 
     184                 :            :     void makeValid();
     185                 :            : 
     186                 :            :     void isSimple_data();
     187                 :            :     void isSimple();
     188                 :            : 
     189                 :            :     void reshapeGeometryLineMerge();
     190                 :            :     void createCollectionOfType();
     191                 :            : 
     192                 :            :     void orientedMinimumBoundingBox( );
     193                 :            :     void minimalEnclosingCircle( );
     194                 :            :     void splitGeometry();
     195                 :            :     void snappedToGrid();
     196                 :            : 
     197                 :            :     void convertGeometryCollectionToSubclass();
     198                 :            : 
     199                 :            :     void emptyJson();
     200                 :            : 
     201                 :            :     void testRandomPointsInPolygon();
     202                 :            : 
     203                 :            :     void wktParser();
     204                 :            : 
     205                 :            :   private:
     206                 :            :     //! Must be called before each render test
     207                 :            :     void initPainterTest();
     208                 :            : 
     209                 :            :     //! A helper method to do a render check to see if the geometry op is as expected
     210                 :            :     bool renderCheck( const QString &testName, const QString &comment = QString(), int mismatchCount = 0 );
     211                 :            :     //! A helper method to dump to qdebug the geometry of a multipolygon
     212                 :            :     void dumpMultiPolygon( QgsMultiPolygonXY &multiPolygon );
     213                 :            :     void paintMultiPolygon( QgsMultiPolygonXY &multiPolygon );
     214                 :            :     //! A helper method to dump to qdebug the geometry of a polygon
     215                 :            :     void dumpPolygon( QgsPolygonXY &polygon );
     216                 :            :     void paintPolygon( QgsPolygonXY &polygon );
     217                 :            :     //! A helper method to dump to qdebug the geometry of a polyline
     218                 :            :     void dumpPolyline( QgsPolylineXY &polyline );
     219                 :            : 
     220                 :            :     // Release return with delete []
     221                 :          2 :     unsigned char *hex2bytes( const char *hex, int *size )
     222                 :            :     {
     223                 :          2 :       QByteArray ba = QByteArray::fromHex( hex );
     224                 :          2 :       unsigned char *out = new unsigned char[ba.size()];
     225                 :          2 :       memcpy( out, ba.data(), ba.size() );
     226                 :          2 :       *size = ba.size();
     227                 :          2 :       return out;
     228                 :          2 :     }
     229                 :            : 
     230                 :            :     QString bytes2hex( const unsigned char *bytes, int size )
     231                 :            :     {
     232                 :            :       QByteArray ba( ( const char * )bytes, size );
     233                 :            :       QString out = ba.toHex();
     234                 :            :       return out;
     235                 :            :     }
     236                 :            : 
     237                 :            : 
     238                 :            :     QString elemToString( const QDomElement &elem ) const;
     239                 :            : 
     240                 :            :     QgsPointXY mPoint1;
     241                 :            :     QgsPointXY mPoint2;
     242                 :            :     QgsPointXY mPoint3;
     243                 :            :     QgsPointXY mPoint4;
     244                 :            :     QgsPointXY mPointA;
     245                 :            :     QgsPointXY mPointB;
     246                 :            :     QgsPointXY mPointC;
     247                 :            :     QgsPointXY mPointD;
     248                 :            :     QgsPointXY mPointW;
     249                 :            :     QgsPointXY mPointX;
     250                 :            :     QgsPointXY mPointY;
     251                 :            :     QgsPointXY mPointZ;
     252                 :            :     QgsPolylineXY mPolylineA;
     253                 :            :     QgsPolylineXY mPolylineB;
     254                 :            :     QgsPolylineXY mPolylineC;
     255                 :            :     QgsGeometry mpPolylineGeometryD;
     256                 :            :     QgsPolygonXY mPolygonA;
     257                 :            :     QgsPolygonXY mPolygonB;
     258                 :            :     QgsPolygonXY mPolygonC;
     259                 :            :     QgsGeometry mpPolygonGeometryA;
     260                 :            :     QgsGeometry mpPolygonGeometryB;
     261                 :            :     QgsGeometry mpPolygonGeometryC;
     262                 :            :     QString mWktLine;
     263                 :            :     QString mTestDataDir;
     264                 :            :     QImage mImage;
     265                 :          1 :     QPainter *mpPainter = nullptr;
     266                 :            :     QPen mPen1;
     267                 :            :     QPen mPen2;
     268                 :            :     QString mReport;
     269                 :            : 
     270                 :            : };
     271                 :            : 
     272                 :          3 : TestQgsGeometry::TestQgsGeometry()
     273                 :          1 :   : mpPolylineGeometryD( nullptr )
     274                 :          1 :   , mpPolygonGeometryA( nullptr )
     275                 :          1 :   , mpPolygonGeometryB( nullptr )
     276                 :          1 :   , mpPolygonGeometryC( nullptr )
     277                 :          2 : {
     278                 :            : 
     279                 :          1 : }
     280                 :            : 
     281                 :          1 : void TestQgsGeometry::initTestCase()
     282                 :            : {
     283                 :            :   // Runs once before any tests are run
     284                 :            :   // init QGIS's paths - true means that all path will be inited from prefix
     285                 :          1 :   QgsApplication::init();
     286                 :          1 :   QgsApplication::initQgis();
     287                 :          1 :   QgsApplication::showSettings();
     288                 :          1 :   mReport += QLatin1String( "<h1>Geometry Tests</h1>\n" );
     289                 :          1 :   mReport += QLatin1String( "<p><font color=\"green\">Green = polygonA</font></p>\n" );
     290                 :          1 :   mReport += QLatin1String( "<p><font color=\"red\">Red = polygonB</font></p>\n" );
     291                 :          1 :   mReport += QLatin1String( "<p><font color=\"blue\">Blue = polygonC</font></p>\n" );
     292                 :          1 : }
     293                 :            : 
     294                 :            : 
     295                 :          1 : void TestQgsGeometry::cleanupTestCase()
     296                 :            : {
     297                 :          1 :   delete mpPainter;
     298                 :          1 :   mpPainter = nullptr;
     299                 :            : 
     300                 :            :   // Runs once after all tests are run
     301                 :          1 :   QString myReportFile = QDir::tempPath() + "/qgistest.html";
     302                 :          1 :   QFile myFile( myReportFile );
     303                 :          1 :   if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) )
     304                 :            :   {
     305                 :          1 :     QTextStream myQTextStream( &myFile );
     306                 :          1 :     myQTextStream << mReport;
     307                 :          1 :     myFile.close();
     308                 :            :     //QDesktopServices::openUrl( "file:///" + myReportFile );
     309                 :          1 :   }
     310                 :            : 
     311                 :          1 :   QgsApplication::exitQgis();
     312                 :          1 : }
     313                 :            : 
     314                 :          6 : void TestQgsGeometry::initPainterTest()
     315                 :            : {
     316                 :          6 :   delete mpPainter;
     317                 :          6 :   mpPainter = nullptr;
     318                 :            :   //
     319                 :            :   // Reset / reinitialize the geometries before each test is run
     320                 :            :   //
     321                 :          6 :   mPoint1 = QgsPointXY( 20.0, 20.0 );
     322                 :          6 :   mPoint2 = QgsPointXY( 80.0, 20.0 );
     323                 :          6 :   mPoint3 = QgsPointXY( 80.0, 80.0 );
     324                 :          6 :   mPoint4 = QgsPointXY( 20.0, 80.0 );
     325                 :          6 :   mPointA = QgsPointXY( 40.0, 40.0 );
     326                 :          6 :   mPointB = QgsPointXY( 100.0, 40.0 );
     327                 :          6 :   mPointC = QgsPointXY( 100.0, 100.0 );
     328                 :          6 :   mPointD = QgsPointXY( 40.0, 100.0 );
     329                 :          6 :   mPointW = QgsPointXY( 200.0, 200.0 );
     330                 :          6 :   mPointX = QgsPointXY( 240.0, 200.0 );
     331                 :          6 :   mPointY = QgsPointXY( 240.0, 240.0 );
     332                 :          6 :   mPointZ = QgsPointXY( 200.0, 240.0 );
     333                 :            : 
     334                 :         12 :   mWktLine = QStringLiteral( "LINESTRING(117.623198 35.198654, 117.581274 35.198654, 117.078178 35.324427, 116.868555 35.534051, 116.617007 35.869448, 116.491233 35.953297, 116.155836 36.288694, 116.071987 36.372544, 115.443117 36.749865, 114.814247 37.043338, 114.311152 37.169112, 113.388810 37.378735, 113.095337 37.378735, 112.592241 37.378735, 111.753748 37.294886, 111.502201 37.252961, 111.082954 37.127187, 110.747557 37.127187, 110.160612 36.917564, 110.034838 36.833715, 109.741366 36.749865, 109.573667 36.666016, 109.238270 36.498317, 109.070571 36.414468, 108.819023 36.288694, 108.693250 36.246770, 108.483626 36.162920, 107.645134 35.911372, 106.597017 35.869448, 106.051997 35.701749, 105.800449 35.617900, 105.590826 35.575975, 105.297354 35.575975, 104.961956 35.575975, 104.710409 35.534051, 104.458861 35.492126, 103.871916 35.492126, 103.788066 35.492126, 103.326895 35.408277, 102.949574 35.408277, 102.488402 35.450201, 102.069156 35.450201, 101.482211 35.450201, 100.937191 35.659825, 100.308321 35.869448, 100.056773 36.037146, 99.050582 36.079071, 97.667069 35.743674, 97.163973 35.617900, 96.115857 35.534051, 95.612761 35.534051, 94.396947 35.911372, 93.684228 36.288694, 92.929584 36.833715, 92.258790 37.169112, 91.629920 37.504509, 90.414105 37.881831, 90.414105 37.881831, 90.246407 37.923755, 89.491763 37.839906, 89.156366 37.672207, 88.485572 37.504509, 87.814778 37.252961, 87.563230 37.169112, 87.143983 37.043338, 85.970093 36.875639, 85.802395 36.875639, 84.083484 36.959489, 84.041560 37.043338, 82.951519 37.546433, 82.699971 37.630283)" );
     335                 :            : 
     336                 :          6 :   mPolygonA.clear();
     337                 :          6 :   mPolygonB.clear();
     338                 :          6 :   mPolygonC.clear();
     339                 :          6 :   mPolylineA.clear();
     340                 :          6 :   mPolylineB.clear();
     341                 :          6 :   mPolylineC.clear();
     342                 :          6 :   mPolylineA << mPoint1 << mPoint2 << mPoint3 << mPoint4 << mPoint1;
     343                 :          6 :   mPolygonA << mPolylineA;
     344                 :            :   //Polygon B intersects Polygon A
     345                 :          6 :   mPolylineB << mPointA << mPointB << mPointC << mPointD << mPointA;
     346                 :          6 :   mPolygonB << mPolylineB;
     347                 :            :   // Polygon C should intersect no other polys
     348                 :          6 :   mPolylineC << mPointW << mPointX << mPointY << mPointZ << mPointW;
     349                 :          6 :   mPolygonC << mPolylineC;
     350                 :            : 
     351                 :          6 :   mpPolylineGeometryD = QgsGeometry::fromWkt( mWktLine );
     352                 :            : 
     353                 :            :   //polygon: first item of the list is outer ring,
     354                 :            :   // inner rings (if any) start from second item
     355                 :          6 :   mpPolygonGeometryA = QgsGeometry::fromPolygonXY( mPolygonA );
     356                 :          6 :   mpPolygonGeometryB = QgsGeometry::fromPolygonXY( mPolygonB );
     357                 :          6 :   mpPolygonGeometryC = QgsGeometry::fromPolygonXY( mPolygonC );
     358                 :            : 
     359                 :          6 :   mImage = QImage( 250, 250, QImage::Format_RGB32 );
     360                 :          6 :   mImage.fill( qRgb( 152, 219, 249 ) );
     361                 :          6 :   mpPainter = new QPainter( &mImage );
     362                 :            : 
     363                 :            :   // Draw the test shapes first
     364                 :          6 :   mPen1 = QPen();
     365                 :          6 :   mPen1.setWidth( 5 );
     366                 :          6 :   mPen1.setBrush( Qt::green );
     367                 :          6 :   mpPainter->setPen( mPen1 );
     368                 :          6 :   paintPolygon( mPolygonA );
     369                 :          6 :   mPen1.setBrush( Qt::red );
     370                 :          6 :   mpPainter->setPen( mPen1 );
     371                 :          6 :   paintPolygon( mPolygonB );
     372                 :          6 :   mPen1.setBrush( Qt::blue );
     373                 :          6 :   mpPainter->setPen( mPen1 );
     374                 :          6 :   paintPolygon( mPolygonC );
     375                 :            : 
     376                 :          6 :   mPen2 = QPen();
     377                 :          6 :   mPen2.setWidth( 1 );
     378                 :          6 :   mPen2.setBrush( Qt::black );
     379                 :          6 :   QBrush myBrush( Qt::DiagCrossPattern );
     380                 :            : 
     381                 :            : 
     382                 :            :   //set the pen to a different color -
     383                 :            :   //any test outs will be drawn in pen2
     384                 :          6 :   mpPainter->setPen( mPen2 );
     385                 :          6 :   mpPainter->setBrush( myBrush );
     386                 :          6 : }
     387                 :            : 
     388                 :         74 : void TestQgsGeometry::cleanup()
     389                 :            : {
     390                 :            :   // will be called after every testfunction.
     391                 :         74 : }
     392                 :            : 
     393                 :          1 : void TestQgsGeometry::copy()
     394                 :            : {
     395                 :            :   //create a point geometry
     396                 :          1 :   QgsGeometry original( new QgsPoint( 1.0, 2.0 ) );
     397                 :          1 :   QCOMPARE( original.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).x(), 1.0 );
     398                 :          1 :   QCOMPARE( original.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).y(), 2.0 );
     399                 :            : 
     400                 :            :   //implicitly shared copy
     401                 :          1 :   QgsGeometry copy( original );
     402                 :          1 :   QCOMPARE( copy.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).x(), 1.0 );
     403                 :          1 :   QCOMPARE( copy.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).y(), 2.0 );
     404                 :            : 
     405                 :            :   //trigger a detach
     406                 :          1 :   copy.set( new QgsPoint( 3.0, 4.0 ) );
     407                 :          1 :   QCOMPARE( copy.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).x(), 3.0 );
     408                 :          1 :   QCOMPARE( copy.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).y(), 4.0 );
     409                 :            : 
     410                 :            :   //make sure original was untouched
     411                 :          1 :   QCOMPARE( original.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).x(), 1.0 );
     412                 :          1 :   QCOMPARE( original.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).y(), 2.0 );
     413                 :          1 : }
     414                 :            : 
     415                 :          1 : void TestQgsGeometry::assignment()
     416                 :            : {
     417                 :            :   //create a point geometry
     418                 :          1 :   QgsGeometry original( new QgsPoint( 1.0, 2.0 ) );
     419                 :          1 :   QCOMPARE( original.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).x(), 1.0 );
     420                 :          1 :   QCOMPARE( original.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).y(), 2.0 );
     421                 :            : 
     422                 :            :   //assign to implicitly shared copy
     423                 :          1 :   QgsGeometry copy;
     424                 :          1 :   copy = original;
     425                 :          1 :   QCOMPARE( copy.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).x(), 1.0 );
     426                 :          1 :   QCOMPARE( copy.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).y(), 2.0 );
     427                 :            : 
     428                 :            :   //trigger a detach
     429                 :          1 :   copy.set( new QgsPoint( 3.0, 4.0 ) );
     430                 :          1 :   QCOMPARE( copy.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).x(), 3.0 );
     431                 :          1 :   QCOMPARE( copy.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).y(), 4.0 );
     432                 :            : 
     433                 :            :   //make sure original was untouched
     434                 :          1 :   QCOMPARE( original.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).x(), 1.0 );
     435                 :          1 :   QCOMPARE( original.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).y(), 2.0 );
     436                 :          1 : }
     437                 :            : 
     438                 :          1 : void TestQgsGeometry::asVariant()
     439                 :            : {
     440                 :            :   //create a point geometry
     441                 :          1 :   QgsGeometry original( new QgsPoint( 1.0, 2.0 ) );
     442                 :          1 :   QCOMPARE( original.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).x(), 1.0 );
     443                 :          1 :   QCOMPARE( original.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).y(), 2.0 );
     444                 :            : 
     445                 :            :   //convert to and from a QVariant
     446                 :          1 :   QVariant var = QVariant::fromValue( original );
     447                 :          1 :   QVERIFY( var.isValid() );
     448                 :          1 :   QVERIFY( !var.canConvert< QgsReferencedGeometry >() );
     449                 :            : 
     450                 :          1 :   QgsGeometry fromVar = qvariant_cast<QgsGeometry>( var );
     451                 :          1 :   QCOMPARE( fromVar.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).x(), 1.0 );
     452                 :          1 :   QCOMPARE( fromVar.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).y(), 2.0 );
     453                 :            : 
     454                 :            :   //also check copying variant
     455                 :          1 :   QVariant var2 = var;
     456                 :          1 :   QVERIFY( var2.isValid() );
     457                 :          1 :   QgsGeometry fromVar2 = qvariant_cast<QgsGeometry>( var2 );
     458                 :          1 :   QCOMPARE( fromVar2.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).x(), 1.0 );
     459                 :          1 :   QCOMPARE( fromVar2.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).y(), 2.0 );
     460                 :            : 
     461                 :            :   //modify original and check detachment
     462                 :          1 :   original.set( new QgsPoint( 3.0, 4.0 ) );
     463                 :          1 :   QgsGeometry fromVar3 = qvariant_cast<QgsGeometry>( var );
     464                 :          1 :   QCOMPARE( fromVar3.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).x(), 1.0 );
     465                 :          1 :   QCOMPARE( fromVar3.constGet()->vertexAt( QgsVertexId( 0, 0, 0 ) ).y(), 2.0 );
     466                 :          1 : }
     467                 :            : 
     468                 :            : 
     469                 :          1 : void TestQgsGeometry::referenced()
     470                 :            : {
     471                 :          2 :   QgsReferencedGeometry geom1 = QgsReferencedGeometry( QgsGeometry::fromPointXY( QgsPointXY( 1, 2 ) ), QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3111" ) ) );
     472                 :          2 :   QCOMPARE( geom1.crs().authid(), QStringLiteral( "EPSG:3111" ) );
     473                 :          2 :   geom1.setCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:28356" ) ) );
     474                 :          2 :   QCOMPARE( geom1.crs().authid(), QStringLiteral( "EPSG:28356" ) );
     475                 :            : 
     476                 :            :   //convert to and from a QVariant
     477                 :          1 :   QVariant var = QVariant::fromValue( geom1 );
     478                 :          1 :   QVERIFY( var.isValid() );
     479                 :            : 
     480                 :          1 :   QVERIFY( var.canConvert< QgsReferencedGeometry >() );
     481                 :            : 
     482                 :          1 :   QgsReferencedGeometry geom2 = qvariant_cast<QgsReferencedGeometry>( var );
     483                 :          1 :   QCOMPARE( geom2.asWkt(), geom1.asWkt() );
     484                 :          2 :   QCOMPARE( geom2.crs().authid(), QStringLiteral( "EPSG:28356" ) );
     485                 :          1 : }
     486                 :            : 
     487                 :            : 
     488                 :          1 : void TestQgsGeometry::isEmpty()
     489                 :            : {
     490                 :          1 :   QgsGeometry geom;
     491                 :          1 :   QVERIFY( geom.isNull() );
     492                 :            : 
     493                 :          1 :   geom.set( new QgsPoint() );
     494                 :          1 :   QVERIFY( geom.isEmpty() );
     495                 :            : 
     496                 :          1 :   geom.set( new QgsPoint( 1.0, 2.0 ) );
     497                 :          1 :   QVERIFY( !geom.isNull() );
     498                 :            : 
     499                 :          1 :   geom.set( nullptr );
     500                 :          1 :   QVERIFY( geom.isNull() );
     501                 :            : 
     502                 :          1 :   QgsGeometryCollection collection;
     503                 :          1 :   QVERIFY( collection.isEmpty() );
     504                 :          1 : }
     505                 :            : 
     506                 :          1 : void TestQgsGeometry::isValid()
     507                 :            : {
     508                 :          1 :   QString error;
     509                 :            :   // LineString
     510                 :          1 :   QgsLineString line;
     511                 :          1 :   QVERIFY( line.isValid( error ) );
     512                 :          1 :   line.addVertex( QgsPoint( 0, 0 ) );
     513                 :          1 :   QVERIFY( !line.isValid( error ) );
     514                 :          2 :   QCOMPARE( error, QStringLiteral( "LineString has less than 2 points and is not empty." ) );
     515                 :          1 :   line.addVertex( QgsPoint( 1, 1 ) );
     516                 :          1 :   QVERIFY( line.isValid( error ) );
     517                 :            : 
     518                 :            :   // CircularString
     519                 :          1 :   QgsCircularString circ;
     520                 :          1 :   QVERIFY( circ.isValid( error ) );
     521                 :          1 :   QgsPointSequence pts = QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 2.5, 2.3 );
     522                 :          1 :   circ.setPoints( pts );
     523                 :          1 :   QVERIFY( !circ.isValid( error ) );
     524                 :          2 :   QCOMPARE( error, QStringLiteral( "CircularString has less than 3 points and is not empty." ) );
     525                 :          1 :   pts.append( QgsPoint( 5, 5 ) );
     526                 :          1 :   circ.setPoints( pts );
     527                 :          1 :   QVERIFY( circ.isValid( error ) );
     528                 :            : 
     529                 :            :   // CompoundCurve
     530                 :          1 :   QgsCompoundCurve curve;
     531                 :          1 :   QVERIFY( curve.isValid( error ) );
     532                 :          1 :   curve.addCurve( line.clone() );
     533                 :          1 :   QVERIFY( curve.isValid( error ) );
     534                 :          1 :   curve.addCurve( circ.clone() );
     535                 :          1 :   QVERIFY( curve.isValid( error ) );
     536                 :          1 :   QgsLineString invalidLine;
     537                 :          1 :   invalidLine.addVertex( QgsPoint( 0, 0 ) );
     538                 :          1 :   curve.addCurve( invalidLine.clone() );
     539                 :          1 :   QVERIFY( !curve.isValid( error ) );
     540                 :          2 :   QCOMPARE( error, QStringLiteral( "Curve[3]: LineString has less than 2 points and is not empty." ) );
     541                 :          1 : }
     542                 :            : 
     543                 :          1 : void TestQgsGeometry::equality()
     544                 :            : {
     545                 :            :   // null geometries
     546                 :          1 :   QVERIFY( !QgsGeometry().equals( QgsGeometry() ) );
     547                 :            : 
     548                 :            :   // compare to null
     549                 :          1 :   QgsGeometry g1( std::make_unique< QgsPoint >( 1.0, 2.0 ) );
     550                 :          1 :   QVERIFY( !g1.equals( QgsGeometry() ) );
     551                 :          1 :   QVERIFY( !QgsGeometry().equals( g1 ) );
     552                 :            : 
     553                 :            :   // compare implicitly shared copies
     554                 :          1 :   QgsGeometry g2( g1 );
     555                 :          1 :   QVERIFY( g2.equals( g1 ) );
     556                 :          1 :   QVERIFY( g1.equals( g2 ) );
     557                 :          1 :   QVERIFY( g1.equals( g1 ) );
     558                 :            : 
     559                 :            :   // equal geometry, but different internal data
     560                 :          1 :   g2 = QgsGeometry::fromWkt( "Point( 1.0 2.0 )" );
     561                 :          1 :   QVERIFY( g2.equals( g1 ) );
     562                 :          1 :   QVERIFY( g1.equals( g2 ) );
     563                 :            : 
     564                 :            :   // different dimensionality
     565                 :          1 :   g2 = QgsGeometry::fromWkt( "PointM( 1.0 2.0 3.0)" );
     566                 :          1 :   QVERIFY( !g2.equals( g1 ) );
     567                 :          1 :   QVERIFY( !g1.equals( g2 ) );
     568                 :            : 
     569                 :            :   // different type
     570                 :          1 :   g2 = QgsGeometry::fromWkt( "LineString( 1.0 2.0, 3.0 4.0 )" );
     571                 :          1 :   QVERIFY( !g2.equals( g1 ) );
     572                 :          1 :   QVERIFY( !g1.equals( g2 ) );
     573                 :            : 
     574                 :            :   // different direction
     575                 :          1 :   g1 = QgsGeometry::fromWkt( "LineString( 3.0 4.0, 1.0 2.0 )" );
     576                 :          1 :   QVERIFY( !g2.equals( g1 ) );
     577                 :          1 :   QVERIFY( !g1.equals( g2 ) );
     578                 :          1 : }
     579                 :            : 
     580                 :          1 : void TestQgsGeometry::vertexIterator()
     581                 :            : {
     582                 :          1 :   QgsGeometry geom;
     583                 :          1 :   QgsVertexIterator it = geom.vertices();
     584                 :          1 :   QVERIFY( !it.hasNext() );
     585                 :            : 
     586                 :          1 :   QgsPolylineXY polyline;
     587                 :          1 :   polyline << QgsPoint( 1, 2 ) << QgsPoint( 3, 4 );
     588                 :          1 :   QgsGeometry geom2 = QgsGeometry::fromPolylineXY( polyline );
     589                 :          1 :   QgsVertexIterator it2 = geom2.vertices();
     590                 :          1 :   QVERIFY( it2.hasNext() );
     591                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 1, 2 ) );
     592                 :          1 :   QVERIFY( it2.hasNext() );
     593                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 3, 4 ) );
     594                 :          1 :   QVERIFY( !it2.hasNext() );
     595                 :            : 
     596                 :          1 :   QgsGeometry emptyGeom = QgsGeometry::fromWkt( "LINESTRING EMPTY" );
     597                 :          1 :   QgsVertexIterator it3 = emptyGeom.vertices();
     598                 :          1 :   QVERIFY( !it3.hasNext() );
     599                 :          1 :   emptyGeom = QgsGeometry::fromWkt( "POINT EMPTY" );
     600                 :          1 :   QgsVertexIterator it4 = emptyGeom.vertices();
     601                 :          1 :   QVERIFY( !it4.hasNext() );
     602                 :          1 : }
     603                 :            : 
     604                 :          1 : void TestQgsGeometry::partIterator()
     605                 :            : {
     606                 :          1 :   QgsGeometry geom;
     607                 :          1 :   QgsGeometryPartIterator it = geom.parts();
     608                 :          1 :   QVERIFY( !it.hasNext() );
     609                 :            : 
     610                 :          2 :   geom = QgsGeometry::fromWkt( QStringLiteral( "Point( 1 2 )" ) );
     611                 :          1 :   QgsGeometryConstPartIterator it2 = geom.constParts();
     612                 :          1 :   QVERIFY( it2.hasNext() );
     613                 :          2 :   QCOMPARE( it2.next()->asWkt(), QStringLiteral( "Point (1 2)" ) );
     614                 :          1 :   QVERIFY( !it2.hasNext() );
     615                 :            : 
     616                 :            :   // test that non-const iterator detaches
     617                 :          1 :   QgsGeometry geom2 = geom;
     618                 :          1 :   it = geom2.parts();
     619                 :          1 :   QVERIFY( it.hasNext() );
     620                 :          1 :   QgsAbstractGeometry *part = it.next();
     621                 :          2 :   QCOMPARE( part->asWkt(), QStringLiteral( "Point (1 2)" ) );
     622                 :          1 :   static_cast< QgsPoint * >( part )->setX( 100 );
     623                 :          2 :   QCOMPARE( geom2.asWkt(), QStringLiteral( "Point (100 2)" ) );
     624                 :          1 :   QVERIFY( !it.hasNext() );
     625                 :            :   // geom2 should have adetached, geom should be unaffected by change
     626                 :          2 :   QCOMPARE( geom.asWkt(), QStringLiteral( "Point (1 2)" ) );
     627                 :            : 
     628                 :            :   // See test_qgsgeometry.py for geometry-type specific checks!
     629                 :          1 : }
     630                 :            : 
     631                 :          1 : void TestQgsGeometry::geos()
     632                 :            : {
     633                 :            :   // test GEOS conversion utils
     634                 :            : 
     635                 :            :   // empty parts should NOT be added to a GEOS collection -- it can cause crashes in GEOS
     636                 :          1 :   QgsMultiPolygon polyWithEmptyParts;
     637                 :          1 :   geos::unique_ptr asGeos( QgsGeos::asGeos( &polyWithEmptyParts ) );
     638                 :          1 :   QgsGeometry res( QgsGeos::fromGeos( asGeos.get() ) );
     639                 :          2 :   QCOMPARE( res.asWkt(), QStringLiteral( "MultiPolygon EMPTY" ) );
     640                 :          1 :   polyWithEmptyParts.addGeometry( new QgsPolygon( new QgsLineString() ) );
     641                 :          1 :   polyWithEmptyParts.addGeometry( new QgsPolygon( new QgsLineString( QVector< QgsPoint >() << QgsPoint( 0, 0 ) << QgsPoint( 0, 1 ) << QgsPoint( 1, 1 ) << QgsPoint( 0, 0 ) ) ) );
     642                 :          1 :   polyWithEmptyParts.addGeometry( new QgsPolygon( new QgsLineString() ) );
     643                 :          1 :   polyWithEmptyParts.addGeometry( new QgsPolygon( new QgsLineString( QVector< QgsPoint >() << QgsPoint( 10, 0 ) << QgsPoint( 10, 1 ) << QgsPoint( 11, 1 ) << QgsPoint( 10, 0 ) ) ) );
     644                 :          1 :   asGeos = QgsGeos::asGeos( &polyWithEmptyParts );
     645                 :          1 :   QCOMPARE( GEOSGetNumGeometries_r( QgsGeos::getGEOSHandler(), asGeos.get() ), 2 );
     646                 :          1 :   res = QgsGeometry( QgsGeos::fromGeos( asGeos.get() ) );
     647                 :          2 :   QCOMPARE( res.asWkt(), QStringLiteral( "MultiPolygon (((0 0, 0 1, 1 1, 0 0)),((10 0, 10 1, 11 1, 10 0)))" ) );
     648                 :            : 
     649                 :            :   // Empty geometry
     650                 :          1 :   QgsPoint point;
     651                 :          1 :   asGeos = QgsGeos::asGeos( &point );
     652                 :            :   // should be treated as a null geometry, not an empty point in order to maintain api compatibility with
     653                 :            :   // earlier QGIS 3.x releases
     654                 :          1 :   QVERIFY( !QgsGeos::fromGeos( asGeos.get() ) );
     655                 :          1 : }
     656                 :            : 
     657                 :          1 : void TestQgsGeometry::point()
     658                 :            : {
     659                 :            :   //test QgsPointV2
     660                 :          1 :   QgsPoint pEmpty;
     661                 :          1 :   QVERIFY( pEmpty.isEmpty() );
     662                 :          1 :   QCOMPARE( pEmpty.wkbType(), QgsWkbTypes::Point );
     663                 :          2 :   QCOMPARE( pEmpty.asWkt(), QStringLiteral( "Point EMPTY" ) );
     664                 :          1 :   pEmpty.setX( 1.0 );
     665                 :          1 :   QVERIFY( pEmpty.isEmpty() );
     666                 :          1 :   QCOMPARE( pEmpty.wkbType(), QgsWkbTypes::Point );
     667                 :          2 :   QCOMPARE( pEmpty.asWkt(), QStringLiteral( "Point EMPTY" ) );
     668                 :          1 :   pEmpty.setY( 2.0 );
     669                 :          1 :   QVERIFY( !pEmpty.isEmpty() );
     670                 :          1 :   QCOMPARE( pEmpty.wkbType(), QgsWkbTypes::Point );
     671                 :          2 :   QCOMPARE( pEmpty.asWkt(), QStringLiteral( "Point (1 2)" ) );
     672                 :            : 
     673                 :            :   //test constructors
     674                 :          1 :   QgsPoint p1( 5.0, 6.0 );
     675                 :          1 :   QCOMPARE( p1.x(), 5.0 );
     676                 :          1 :   QCOMPARE( p1.y(), 6.0 );
     677                 :          1 :   QVERIFY( !p1.isEmpty() );
     678                 :          1 :   QVERIFY( !p1.is3D() );
     679                 :          1 :   QVERIFY( !p1.isMeasure() );
     680                 :          1 :   QCOMPARE( p1.wkbType(), QgsWkbTypes::Point );
     681                 :          1 :   QCOMPARE( p1.wktTypeStr(), QString( "Point" ) );
     682                 :            : 
     683                 :          1 :   QgsPoint p2( QgsPointXY( 3.0, 4.0 ) );
     684                 :          1 :   QCOMPARE( p2.x(), 3.0 );
     685                 :          1 :   QCOMPARE( p2.y(), 4.0 );
     686                 :          1 :   QVERIFY( !p2.isEmpty() );
     687                 :          1 :   QVERIFY( !p2.is3D() );
     688                 :          1 :   QVERIFY( !p2.isMeasure() );
     689                 :          1 :   QCOMPARE( p2.wkbType(), QgsWkbTypes::Point );
     690                 :            : 
     691                 :          1 :   QgsPoint p3( QPointF( 7.0, 9.0 ) );
     692                 :          1 :   QCOMPARE( p3.x(), 7.0 );
     693                 :          1 :   QCOMPARE( p3.y(), 9.0 );
     694                 :          1 :   QVERIFY( !p3.isEmpty() );
     695                 :          1 :   QVERIFY( !p3.is3D() );
     696                 :          1 :   QVERIFY( !p3.isMeasure() );
     697                 :          1 :   QCOMPARE( p3.wkbType(), QgsWkbTypes::Point );
     698                 :            : 
     699                 :          1 :   QgsPoint p4( QgsWkbTypes::Point, 11.0, 13.0 );
     700                 :          1 :   QCOMPARE( p4.x(), 11.0 );
     701                 :          1 :   QCOMPARE( p4.y(), 13.0 );
     702                 :          1 :   QVERIFY( !p4.isEmpty() );
     703                 :          1 :   QVERIFY( !p4.is3D() );
     704                 :          1 :   QVERIFY( !p4.isMeasure() );
     705                 :          1 :   QCOMPARE( p4.wkbType(), QgsWkbTypes::Point );
     706                 :            : 
     707                 :          1 :   QgsPoint p5( QgsWkbTypes::PointZ, 11.0, 13.0, 15.0 );
     708                 :          1 :   QCOMPARE( p5.x(), 11.0 );
     709                 :          1 :   QCOMPARE( p5.y(), 13.0 );
     710                 :          1 :   QCOMPARE( p5.z(), 15.0 );
     711                 :          1 :   QVERIFY( !p5.isEmpty() );
     712                 :          1 :   QVERIFY( p5.is3D() );
     713                 :          1 :   QVERIFY( !p5.isMeasure() );
     714                 :          1 :   QCOMPARE( p5.wkbType(), QgsWkbTypes::PointZ );
     715                 :          1 :   QCOMPARE( p5.wktTypeStr(), QString( "PointZ" ) );
     716                 :            : 
     717                 :          1 :   QgsPoint p6( QgsWkbTypes::PointM, 11.0, 13.0, 0.0, 17.0 );
     718                 :          1 :   QCOMPARE( p6.x(), 11.0 );
     719                 :          1 :   QCOMPARE( p6.y(), 13.0 );
     720                 :          1 :   QCOMPARE( p6.m(), 17.0 );
     721                 :          1 :   QVERIFY( !p6.isEmpty() );
     722                 :          1 :   QVERIFY( !p6.is3D() );
     723                 :          1 :   QVERIFY( p6.isMeasure() );
     724                 :          1 :   QCOMPARE( p6.wkbType(), QgsWkbTypes::PointM );
     725                 :          1 :   QCOMPARE( p6.wktTypeStr(), QString( "PointM" ) );
     726                 :            : 
     727                 :          1 :   QgsPoint p7( QgsWkbTypes::PointZM, 11.0, 13.0, 0.0, 17.0 );
     728                 :          1 :   QCOMPARE( p7.x(), 11.0 );
     729                 :          1 :   QCOMPARE( p7.y(), 13.0 );
     730                 :          1 :   QCOMPARE( p7.m(), 17.0 );
     731                 :          1 :   QVERIFY( !p7.isEmpty() );
     732                 :          1 :   QVERIFY( p7.is3D() );
     733                 :          1 :   QVERIFY( p7.isMeasure() );
     734                 :          1 :   QCOMPARE( p7.wkbType(), QgsWkbTypes::PointZM );
     735                 :          1 :   QCOMPARE( p7.wktTypeStr(), QString( "PointZM" ) );
     736                 :            : 
     737                 :          1 :   QgsPoint noZ( QgsWkbTypes::PointM, 11.0, 13.0, 15.0, 17.0 );
     738                 :          1 :   QCOMPARE( noZ.x(), 11.0 );
     739                 :          1 :   QCOMPARE( noZ.y(), 13.0 );
     740                 :          1 :   QVERIFY( std::isnan( noZ.z() ) );
     741                 :          1 :   QCOMPARE( noZ.m(), 17.0 );
     742                 :          1 :   QCOMPARE( noZ.wkbType(), QgsWkbTypes::PointM );
     743                 :            : 
     744                 :          1 :   QgsPoint noM( QgsWkbTypes::PointZ, 11.0, 13.0, 17.0, 18.0 );
     745                 :          1 :   QCOMPARE( noM.x(), 11.0 );
     746                 :          1 :   QCOMPARE( noM.y(), 13.0 );
     747                 :          1 :   QVERIFY( std::isnan( noM.m() ) );
     748                 :          1 :   QCOMPARE( noM.z(), 17.0 );
     749                 :          1 :   QCOMPARE( noM.wkbType(), QgsWkbTypes::PointZ );
     750                 :            : 
     751                 :          1 :   QgsPoint p8( QgsWkbTypes::Point25D, 21.0, 23.0, 25.0 );
     752                 :          1 :   QCOMPARE( p8.x(), 21.0 );
     753                 :          1 :   QCOMPARE( p8.y(), 23.0 );
     754                 :          1 :   QCOMPARE( p8.z(), 25.0 );
     755                 :          1 :   QVERIFY( !p8.isEmpty() );
     756                 :          1 :   QVERIFY( p8.is3D() );
     757                 :          1 :   QVERIFY( !p8.isMeasure() );
     758                 :          1 :   QCOMPARE( p8.wkbType(), QgsWkbTypes::Point25D );
     759                 :            : 
     760                 :          1 :   QgsPoint pp( QgsWkbTypes::Point );
     761                 :          1 :   QVERIFY( !pp.is3D() );
     762                 :          1 :   QVERIFY( !pp.isMeasure() );
     763                 :            : 
     764                 :          1 :   QgsPoint ppz( QgsWkbTypes::PointZ );
     765                 :          1 :   QVERIFY( ppz.is3D() );
     766                 :          1 :   QVERIFY( !ppz.isMeasure() );
     767                 :            : 
     768                 :          1 :   QgsPoint ppm( QgsWkbTypes::PointM );
     769                 :          1 :   QVERIFY( !ppm.is3D() );
     770                 :          1 :   QVERIFY( ppm.isMeasure() );
     771                 :            : 
     772                 :          1 :   QgsPoint ppzm( QgsWkbTypes::PointZM );
     773                 :          1 :   QVERIFY( ppzm.is3D() );
     774                 :          1 :   QVERIFY( ppzm.isMeasure() );
     775                 :            : 
     776                 :            : #if 0 //should trigger an assert
     777                 :            :   //try creating a point with a nonsense WKB type
     778                 :            :   QgsPoint p9( QgsWkbTypes::PolygonZM, 11.0, 13.0, 9.0, 17.0 );
     779                 :            :   QCOMPARE( p9.wkbType(), QgsWkbTypes::Unknown );
     780                 :            : #endif
     781                 :            : 
     782                 :            :   //test equality operator
     783                 :            : 
     784                 :          1 :   QgsPoint pRight, pLeft;
     785                 :          1 :   QVERIFY( pRight.isEmpty() );
     786                 :          1 :   QVERIFY( pLeft.isEmpty() );
     787                 :          1 :   QVERIFY( pLeft == pRight );
     788                 :          1 :   pRight.setX( 1 );
     789                 :          1 :   pLeft.setY( 1 );
     790                 :          1 :   QVERIFY( pRight.isEmpty() );
     791                 :          1 :   QVERIFY( pLeft.isEmpty() );
     792                 :          1 :   QVERIFY( pLeft != pRight );
     793                 :          1 :   pRight.setY( 1 );
     794                 :          1 :   pLeft.setX( 1 );
     795                 :          1 :   QVERIFY( !pRight.isEmpty() );
     796                 :          1 :   QVERIFY( !pLeft.isEmpty() );
     797                 :          1 :   QVERIFY( pLeft == pRight );
     798                 :            : 
     799                 :            : 
     800                 :          1 :   QVERIFY( QgsPoint( QgsWkbTypes::Point, 2 / 3.0, 1 / 3.0 ) == QgsPoint( QgsWkbTypes::Point, 2 / 3.0, 1 / 3.0 ) );
     801                 :          1 :   QVERIFY( !( QgsPoint( QgsWkbTypes::PointZ, 2 / 3.0, 1 / 3.0 ) == QgsPoint( QgsWkbTypes::Point, 2 / 3.0, 1 / 3.0 ) ) );
     802                 :          1 :   QVERIFY( !( QgsPoint( QgsWkbTypes::Point, 1 / 3.0, 1 / 3.0 ) == QgsPoint( QgsWkbTypes::Point, 2 / 3.0, 1 / 3.0 ) ) );
     803                 :          1 :   QVERIFY( !( QgsPoint( QgsWkbTypes::Point, 2 / 3.0, 2 / 3.0 ) == QgsPoint( QgsWkbTypes::Point, 2 / 3.0, 1 / 3.0 ) ) );
     804                 :          1 :   QVERIFY( QgsPoint( QgsWkbTypes::PointZ, 3.0, 4.0, 1 / 3.0 ) == QgsPoint( QgsWkbTypes::PointZ, 3.0, 4.0, 1 / 3.0 ) );
     805                 :          1 :   QVERIFY( !( QgsPoint( QgsWkbTypes::PointZ, 3.0, 4.0, 1 / 3.0 ) == QgsPoint( QgsWkbTypes::PointZM, 3.0, 4.0, 1 / 3.0 ) ) );
     806                 :          1 :   QVERIFY( !( QgsPoint( QgsWkbTypes::PointZ, 3.0, 4.0, 2 / 3.0 ) == QgsPoint( QgsWkbTypes::PointZ, 3.0, 4.0, 1 / 3.0 ) ) );
     807                 :          1 :   QVERIFY( QgsPoint( QgsWkbTypes::PointM, 3.0, 4.0, 0.0, 1 / 3.0 ) == QgsPoint( QgsWkbTypes::PointM, 3.0, 4.0, 0.0, 1 / 3.0 ) );
     808                 :          1 :   QVERIFY( !( QgsPoint( QgsWkbTypes::PointM, 3.0, 4.0, 0.0, 1 / 3.0 ) == QgsPoint( QgsWkbTypes::PointZ, 3.0, 4.0, 0.0, 1 / 3.0 ) ) );
     809                 :          1 :   QVERIFY( !( QgsPoint( QgsWkbTypes::PointM, 3.0, 4.0, 0.0, 1 / 3.0 ) == QgsPoint( QgsWkbTypes::PointM, 3.0, 4.0, 0.0, 2 / 3.0 ) ) );
     810                 :          1 :   QVERIFY( QgsPoint( QgsWkbTypes::PointZM, 3.0, 4.0, 2 / 3.0, 1 / 3.0 ) == QgsPoint( QgsWkbTypes::PointZM, 3.0, 4.0, 2 / 3.0, 1 / 3.0 ) );
     811                 :          1 :   QVERIFY( QgsPoint( QgsWkbTypes::Point25D, 3.0, 4.0, 2 / 3.0 ) == QgsPoint( QgsWkbTypes::Point25D, 3.0, 4.0, 2 / 3.0 ) );
     812                 :          1 :   QVERIFY( !( QgsPoint( QgsWkbTypes::Point25D, 3.0, 4.0, 2 / 3.0 ) == QgsPoint( QgsWkbTypes::PointZ, 3.0, 4.0, 2 / 3.0 ) ) );
     813                 :            :   //test inequality operator
     814                 :          1 :   QVERIFY( !( QgsPoint( QgsWkbTypes::Point, 2 / 3.0, 1 / 3.0 ) != QgsPoint( QgsWkbTypes::Point, 2 / 3.0, 1 / 3.0 ) ) );
     815                 :          1 :   QVERIFY( QgsPoint( QgsWkbTypes::Point, 2 / 3.0, 1 / 3.0 ) != QgsPoint( QgsWkbTypes::PointZ, 2 / 3.0, 1 / 3.0 ) );
     816                 :            : 
     817                 :          1 :   QgsLineString nonPoint;
     818                 :          1 :   QVERIFY( p8 != nonPoint );
     819                 :          1 :   QVERIFY( !( p8 == nonPoint ) );
     820                 :            : 
     821                 :            :   //test setters and getters
     822                 :            :   //x
     823                 :          1 :   QgsPoint p10( QgsWkbTypes::PointZM );
     824                 :          1 :   p10.setX( 5.0 );
     825                 :          1 :   QCOMPARE( p10.x(), 5.0 );
     826                 :          1 :   QCOMPARE( p10.rx(), 5.0 );
     827                 :          1 :   p10.rx() = 9.0;
     828                 :          1 :   QCOMPARE( p10.x(), 9.0 );
     829                 :            :   //y
     830                 :          1 :   p10.setY( 7.0 );
     831                 :          1 :   QCOMPARE( p10.y(), 7.0 );
     832                 :          1 :   QCOMPARE( p10.ry(), 7.0 );
     833                 :          1 :   p10.ry() = 3.0;
     834                 :          1 :   QCOMPARE( p10.y(), 3.0 );
     835                 :            :   //z
     836                 :          1 :   p10.setZ( 17.0 );
     837                 :          1 :   QCOMPARE( p10.is3D(), true );
     838                 :          1 :   QCOMPARE( p10.z(), 17.0 );
     839                 :          1 :   QCOMPARE( p10.rz(), 17.0 );
     840                 :          1 :   p10.rz() = 13.0;
     841                 :          1 :   QCOMPARE( p10.z(), 13.0 );
     842                 :            :   //m
     843                 :          1 :   p10.setM( 27.0 );
     844                 :          1 :   QCOMPARE( p10.m(), 27.0 );
     845                 :          1 :   QCOMPARE( p10.rm(), 27.0 );
     846                 :          1 :   p10.rm() = 23.0;
     847                 :          1 :   QCOMPARE( p10.m(), 23.0 );
     848                 :            : 
     849                 :            :   //other checks
     850                 :          1 :   QCOMPARE( p10.geometryType(), QString( "Point" ) );
     851                 :          1 :   QCOMPARE( p10.dimension(), 0 );
     852                 :            : 
     853                 :            :   //clone
     854                 :          1 :   std::unique_ptr< QgsPoint >clone( p10.clone() );
     855                 :          1 :   QVERIFY( p10 == *clone );
     856                 :            : 
     857                 :            :   //toCurveType
     858                 :          1 :   clone.reset( p10.toCurveType() );
     859                 :          1 :   QVERIFY( p10 == *clone );
     860                 :            : 
     861                 :            :   //assignment
     862                 :          1 :   QgsPoint original( QgsWkbTypes::PointZM, 1.0, 2.0, 3.0, -4.0 );
     863                 :          1 :   QgsPoint assigned( 6.0, 7.0 );
     864                 :          1 :   assigned = original;
     865                 :          1 :   QVERIFY( assigned == original );
     866                 :            : 
     867                 :            :   //clear
     868                 :          1 :   QgsPoint p11( 5.0, 6.0 );
     869                 :          1 :   p11.clear();
     870                 :          1 :   QCOMPARE( p11.wkbType(), QgsWkbTypes::Point );
     871                 :          1 :   QVERIFY( std::isnan( p11.x() ) );
     872                 :          1 :   QVERIFY( std::isnan( p11.y() ) );
     873                 :            : 
     874                 :            :   //toQPointF
     875                 :          1 :   QgsPoint p11a( 5.0, 9.0 );
     876                 :          1 :   QPointF result = p11a.toQPointF();
     877                 :          1 :   QGSCOMPARENEAR( result.x(), 5.0, 4 * std::numeric_limits<double>::epsilon() );
     878                 :          1 :   QGSCOMPARENEAR( result.y(), 9.0, 4 * std::numeric_limits<double>::epsilon() );
     879                 :            : 
     880                 :            :   //to/from WKB
     881                 :          1 :   QgsPoint p12( QgsWkbTypes::PointZM, 1.0, 2.0, 3.0, -4.0 );
     882                 :          1 :   QByteArray wkb12 = p12.asWkb();
     883                 :          1 :   QCOMPARE( wkb12.size(), p12.wkbSize() );
     884                 :          1 :   QgsPoint p13;
     885                 :          1 :   QgsConstWkbPtr wkb12ptr( wkb12 );
     886                 :          1 :   p13.fromWkb( wkb12ptr );
     887                 :          1 :   QVERIFY( p13 == p12 );
     888                 :            : 
     889                 :            :   //bad WKB - check for no crash
     890                 :          1 :   p13 = QgsPoint( 1, 2 );
     891                 :          1 :   QgsConstWkbPtr nullPtr( nullptr, 0 );
     892                 :          1 :   QVERIFY( !p13.fromWkb( nullPtr ) );
     893                 :          1 :   QCOMPARE( p13.wkbType(), QgsWkbTypes::Point );
     894                 :          1 :   QgsLineString line;
     895                 :          1 :   p13 = QgsPoint( 1, 2 );
     896                 :          1 :   QByteArray wkbLine = line.asWkb();
     897                 :          1 :   QCOMPARE( wkbLine.size(), line.wkbSize() );
     898                 :          1 :   QgsConstWkbPtr wkbLinePtr( wkbLine );
     899                 :          1 :   QVERIFY( !p13.fromWkb( wkbLinePtr ) );
     900                 :          1 :   QCOMPARE( p13.wkbType(), QgsWkbTypes::Point );
     901                 :            : 
     902                 :            :   //to/from WKT
     903                 :          1 :   p13 = QgsPoint( QgsWkbTypes::PointZM, 1.0, 2.0, 3.0, -4.0 );
     904                 :          1 :   QString wkt = p13.asWkt();
     905                 :          1 :   QVERIFY( !wkt.isEmpty() );
     906                 :          1 :   QgsPoint p14;
     907                 :          1 :   QVERIFY( p14.fromWkt( wkt ) );
     908                 :          1 :   QVERIFY( p14 == p13 );
     909                 :            : 
     910                 :            :   //bad WKT
     911                 :          1 :   QVERIFY( !p14.fromWkt( "Polygon()" ) );
     912                 :          1 :   QVERIFY( !p14.fromWkt( "Point(1 )" ) );
     913                 :            : 
     914                 :            :   //asGML2
     915                 :          1 :   QgsPoint exportPoint( 1, 2 );
     916                 :          1 :   QgsPoint exportPointFloat( 1 / 3.0, 2 / 3.0 );
     917                 :          2 :   QDomDocument doc( QStringLiteral( "gml" ) );
     918                 :          2 :   QString expectedGML2( QStringLiteral( "<Point xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">1,2</coordinates></Point>" ) );
     919                 :          3 :   QGSCOMPAREGML( elemToString( exportPoint.asGml2( doc ) ), expectedGML2 );
     920                 :          2 :   QString expectedGML2prec3( QStringLiteral( "<Point xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">0.333,0.667</coordinates></Point>" ) );
     921                 :          3 :   QGSCOMPAREGML( elemToString( exportPointFloat.asGml2( doc, 3 ) ), expectedGML2prec3 );
     922                 :            : 
     923                 :            :   //asGML3
     924                 :          2 :   QString expectedGML3( QStringLiteral( "<Point xmlns=\"gml\"><pos xmlns=\"gml\" srsDimension=\"2\">1 2</pos></Point>" ) );
     925                 :          1 :   QCOMPARE( elemToString( exportPoint.asGml3( doc ) ), expectedGML3 );
     926                 :          2 :   QString expectedGML3prec3( QStringLiteral( "<Point xmlns=\"gml\"><pos xmlns=\"gml\" srsDimension=\"2\">0.333 0.667</pos></Point>" ) );
     927                 :          1 :   QCOMPARE( elemToString( exportPointFloat.asGml3( doc, 3 ) ), expectedGML3prec3 );
     928                 :          1 :   QgsPoint exportPointZ( 1, 2, 3 );
     929                 :          2 :   QString expectedGML3Z( QStringLiteral( "<Point xmlns=\"gml\"><pos xmlns=\"gml\" srsDimension=\"3\">1 2 3</pos></Point>" ) );
     930                 :          3 :   QGSCOMPAREGML( elemToString( exportPointZ.asGml3( doc, 3 ) ), expectedGML3Z );
     931                 :            : 
     932                 :            :   //asGML2 inverted axis
     933                 :          1 :   QgsPoint exportPointInvertedAxis( 1, 2 );
     934                 :          1 :   QgsPoint exportPointFloatInvertedAxis( 1 / 3.0, 2 / 3.0 );
     935                 :          2 :   QDomDocument docInvertedAxis( QStringLiteral( "gml" ) );
     936                 :          2 :   QString expectedGML2InvertedAxis( QStringLiteral( "<Point xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">2,1</coordinates></Point>" ) );
     937                 :          4 :   QGSCOMPAREGML( elemToString( exportPointInvertedAxis.asGml2( docInvertedAxis, 17, QStringLiteral( "gml" ), QgsAbstractGeometry::AxisOrder::YX ) ), expectedGML2InvertedAxis );
     938                 :          2 :   QString expectedGML2prec3InvertedAxis( QStringLiteral( "<Point xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">0.667,0.333</coordinates></Point>" ) );
     939                 :          4 :   QGSCOMPAREGML( elemToString( exportPointFloatInvertedAxis.asGml2( docInvertedAxis, 3, QStringLiteral( "gml" ), QgsAbstractGeometry::AxisOrder::YX ) ), expectedGML2prec3InvertedAxis );
     940                 :            : 
     941                 :            :   //asGML3 inverted axis
     942                 :          2 :   QString expectedGML3InvertedAxis( QStringLiteral( "<Point xmlns=\"gml\"><pos xmlns=\"gml\" srsDimension=\"2\">2 1</pos></Point>" ) );
     943                 :          2 :   QCOMPARE( elemToString( exportPointInvertedAxis.asGml3( docInvertedAxis, 17, QStringLiteral( "gml" ), QgsAbstractGeometry::AxisOrder::YX ) ), expectedGML3InvertedAxis );
     944                 :          2 :   QString expectedGML3prec3InvertedAxis( QStringLiteral( "<Point xmlns=\"gml\"><pos xmlns=\"gml\" srsDimension=\"2\">0.667 0.333</pos></Point>" ) );
     945                 :          2 :   QCOMPARE( elemToString( exportPointFloatInvertedAxis.asGml3( docInvertedAxis, 3, QStringLiteral( "gml" ), QgsAbstractGeometry::AxisOrder::YX ) ), expectedGML3prec3InvertedAxis );
     946                 :          1 :   QgsPoint exportPointZInvertedAxis( 1, 2, 3 );
     947                 :          2 :   QString expectedGML3ZInvertedAxis( QStringLiteral( "<Point xmlns=\"gml\"><pos xmlns=\"gml\" srsDimension=\"3\">2 1 3</pos></Point>" ) );
     948                 :          4 :   QGSCOMPAREGML( elemToString( exportPointZInvertedAxis.asGml3( docInvertedAxis, 3, QStringLiteral( "gml" ), QgsAbstractGeometry::AxisOrder::YX ) ), expectedGML3ZInvertedAxis );
     949                 :            : 
     950                 :            : 
     951                 :            :   //asJSON
     952                 :          2 :   QString expectedJson( QStringLiteral( "{\"coordinates\":[1.0,2.0],\"type\":\"Point\"}" ) );
     953                 :          1 :   QCOMPARE( exportPoint.asJson(), expectedJson );
     954                 :          2 :   QString expectedJsonPrec3( QStringLiteral( "{\"coordinates\":[0.333,0.667],\"type\":\"Point\"}" ) );
     955                 :          1 :   QCOMPARE( exportPointFloat.asJson( 3 ), expectedJsonPrec3 );
     956                 :            : 
     957                 :            :   //asKML
     958                 :          2 :   QString expectedKml( QStringLiteral( "<Point><coordinates>1,2</coordinates></Point>" ) );
     959                 :          1 :   QCOMPARE( exportPoint.asKml(), expectedKml );
     960                 :          2 :   QString expectedKmlPrec3( QStringLiteral( "<Point><coordinates>0.333,0.667</coordinates></Point>" ) );
     961                 :          1 :   QCOMPARE( exportPointFloat.asKml( 3 ), expectedKmlPrec3 );
     962                 :            : 
     963                 :            :   //bounding box
     964                 :          1 :   QgsPoint p15( 1.0, 2.0 );
     965                 :          1 :   QCOMPARE( p15.boundingBox(), QgsRectangle( 1.0, 2.0, 1.0, 2.0 ) );
     966                 :            :   //modify points and test that bounding box is updated accordingly
     967                 :          1 :   p15.setX( 3.0 );
     968                 :          1 :   QCOMPARE( p15.boundingBox(), QgsRectangle( 3.0, 2.0, 3.0, 2.0 ) );
     969                 :          1 :   p15.setY( 6.0 );
     970                 :          1 :   QCOMPARE( p15.boundingBox(), QgsRectangle( 3.0, 6.0, 3.0, 6.0 ) );
     971                 :          1 :   p15.rx() = 4.0;
     972                 :          1 :   QCOMPARE( p15.boundingBox(), QgsRectangle( 4.0, 6.0, 4.0, 6.0 ) );
     973                 :          1 :   p15.ry() = 9.0;
     974                 :          1 :   QCOMPARE( p15.boundingBox(), QgsRectangle( 4.0, 9.0, 4.0, 9.0 ) );
     975                 :          1 :   p15.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 11.0, 13.0 ) );
     976                 :          1 :   QCOMPARE( p15.boundingBox(), QgsRectangle( 11.0, 13.0, 11.0, 13.0 ) );
     977                 :          1 :   p15 = QgsPoint( 21.0, 23.0 );
     978                 :          1 :   QCOMPARE( p15.boundingBox(), QgsRectangle( 21.0, 23.0, 21.0, 23.0 ) );
     979                 :            : 
     980                 :            :   //CRS transform
     981                 :          2 :   QgsCoordinateReferenceSystem sourceSrs( QStringLiteral( "EPSG:3994" ) );
     982                 :          2 :   QgsCoordinateReferenceSystem destSrs( QStringLiteral( "EPSG:4202" ) ); // want a transform with ellipsoid change
     983                 :          1 :   QgsCoordinateTransform tr( sourceSrs, destSrs, QgsProject::instance() );
     984                 :          1 :   QgsPoint p16( QgsWkbTypes::PointZM, 6374985, -3626584, 1, 2 );
     985                 :          1 :   p16.transform( tr, QgsCoordinateTransform::ForwardTransform );
     986                 :          1 :   QGSCOMPARENEAR( p16.x(), 175.771, 0.001 );
     987                 :          1 :   QGSCOMPARENEAR( p16.y(), -39.724, 0.001 );
     988                 :          1 :   QGSCOMPARENEAR( p16.z(), 1.0, 0.001 );
     989                 :          1 :   QCOMPARE( p16.m(), 2.0 );
     990                 :          1 :   p16.transform( tr, QgsCoordinateTransform::ReverseTransform );
     991                 :          1 :   QGSCOMPARENEAR( p16.x(), 6374985, 1 );
     992                 :          1 :   QGSCOMPARENEAR( p16.y(), -3626584, 1 );
     993                 :          1 :   QGSCOMPARENEAR( p16.z(), 1.0, 0.001 );
     994                 :          1 :   QCOMPARE( p16.m(), 2.0 );
     995                 :            : #if PROJ_VERSION_MAJOR<6 // note - z value transform doesn't currently work with proj 6+, because we don't yet support compound CRS definitions
     996                 :            :   //test with z transform
     997                 :            :   p16.transform( tr, QgsCoordinateTransform::ForwardTransform, true );
     998                 :            :   QGSCOMPARENEAR( p16.z(), -19.249, 0.001 );
     999                 :            :   p16.transform( tr, QgsCoordinateTransform::ReverseTransform, true );
    1000                 :            :   QGSCOMPARENEAR( p16.z(), 1.0, 0.001 );
    1001                 :            : #endif
    1002                 :            :   //QTransform transform
    1003                 :          1 :   QTransform qtr = QTransform::fromScale( 2, 3 );
    1004                 :          1 :   QgsPoint p17( QgsWkbTypes::PointZM, 10, 20, 30, 40 );
    1005                 :          1 :   p17.transform( qtr );
    1006                 :          1 :   QVERIFY( p17 == QgsPoint( QgsWkbTypes::PointZM, 20, 60, 30, 40 ) );
    1007                 :          1 :   p17.transform( QTransform::fromScale( 1, 1 ), 11, 2, 3, 4 );
    1008                 :          1 :   QVERIFY( p17 == QgsPoint( QgsWkbTypes::PointZM, 20, 60, 71, 163 ) );
    1009                 :            : 
    1010                 :            :   //coordinateSequence
    1011                 :          1 :   QgsPoint p18( QgsWkbTypes::PointZM, 1.0, 2.0, 3.0, 4.0 );
    1012                 :          1 :   QgsCoordinateSequence coord = p18.coordinateSequence();
    1013                 :          1 :   QCOMPARE( coord.count(), 1 );
    1014                 :          1 :   QCOMPARE( coord.at( 0 ).count(), 1 );
    1015                 :          1 :   QCOMPARE( coord.at( 0 ).at( 0 ).count(), 1 );
    1016                 :          1 :   QCOMPARE( coord.at( 0 ).at( 0 ).at( 0 ), p18 );
    1017                 :            : 
    1018                 :            :   //low level editing
    1019                 :            :   //insertVertex should have no effect
    1020                 :          1 :   QgsPoint p19( QgsWkbTypes::PointZM, 3.0, 4.0, 6.0, 7.0 );
    1021                 :          1 :   p19.insertVertex( QgsVertexId( 1, 2, 3 ), QgsPoint( 6.0, 7.0 ) );
    1022                 :          1 :   QCOMPARE( p19, QgsPoint( QgsWkbTypes::PointZM, 3.0, 4.0, 6.0, 7.0 ) );
    1023                 :            : 
    1024                 :            :   //moveVertex
    1025                 :          1 :   p19.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( QgsWkbTypes::PointZM, 1.0, 2.0, 3.0, 4.0 ) );
    1026                 :          1 :   QCOMPARE( p19, QgsPoint( QgsWkbTypes::PointZM, 1.0, 2.0, 3.0, 4.0 ) );
    1027                 :            :   //invalid vertex id, should not crash
    1028                 :          1 :   p19.moveVertex( QgsVertexId( 1, 2, 3 ), QgsPoint( QgsWkbTypes::PointZM, 2.0, 3.0, 1.0, 2.0 ) );
    1029                 :          1 :   QCOMPARE( p19, QgsPoint( QgsWkbTypes::PointZM, 2.0, 3.0, 1.0, 2.0 ) );
    1030                 :            :   //move PointZM using Point
    1031                 :          1 :   p19.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( QgsWkbTypes::Point, 11.0, 12.0 ) );
    1032                 :          1 :   QCOMPARE( p19, QgsPoint( QgsWkbTypes::PointZM, 11.0, 12.0, 1.0, 2.0 ) );
    1033                 :            :   //move PointZM using PointZ
    1034                 :          1 :   p19.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( QgsWkbTypes::PointZ, 21.0, 22.0, 23.0 ) );
    1035                 :          1 :   QCOMPARE( p19, QgsPoint( QgsWkbTypes::PointZM, 21.0, 22.0, 23.0, 2.0 ) );
    1036                 :            :   //move PointZM using PointM
    1037                 :          1 :   p19.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( QgsWkbTypes::PointM, 31.0, 32.0, 0.0, 43.0 ) );
    1038                 :          1 :   QCOMPARE( p19, QgsPoint( QgsWkbTypes::PointZM, 31.0, 32.0, 23.0, 43.0 ) );
    1039                 :            :   //move Point using PointZM (z/m should be ignored)
    1040                 :          1 :   QgsPoint p20( 3.0, 4.0 );
    1041                 :          1 :   p20.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( QgsWkbTypes::PointZM, 2.0, 3.0, 1.0, 2.0 ) );
    1042                 :          1 :   QCOMPARE( p20, QgsPoint( 2.0, 3.0 ) );
    1043                 :            : 
    1044                 :            :   //deleteVertex - should do nothing, but not crash
    1045                 :          1 :   p20.deleteVertex( QgsVertexId( 0, 0, 0 ) );
    1046                 :          1 :   QCOMPARE( p20, QgsPoint( 2.0, 3.0 ) );
    1047                 :            : 
    1048                 :            :   // closestSegment
    1049                 :          1 :   QgsPoint closest;
    1050                 :          1 :   QgsVertexId after;
    1051                 :            :   // return error - points have no segments
    1052                 :          1 :   QVERIFY( p20.closestSegment( QgsPoint( 4.0, 6.0 ), closest, after ) < 0 );
    1053                 :            : 
    1054                 :            :   //nextVertex
    1055                 :          1 :   QgsPoint p21( 3.0, 4.0 );
    1056                 :          1 :   QgsPoint p22;
    1057                 :          1 :   QgsVertexId v( 0, 0, -1 );
    1058                 :          1 :   QVERIFY( p21.nextVertex( v, p22 ) );
    1059                 :          1 :   QCOMPARE( p22, p21 );
    1060                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 0 ) );
    1061                 :            :   //no more vertices
    1062                 :          1 :   QVERIFY( !p21.nextVertex( v, p22 ) );
    1063                 :          1 :   v = QgsVertexId( 0, 1, -1 ); //test that ring number is maintained
    1064                 :          1 :   QVERIFY( p21.nextVertex( v, p22 ) );
    1065                 :          1 :   QCOMPARE( p22, p21 );
    1066                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 1, 0 ) );
    1067                 :          1 :   v = QgsVertexId( 1, 0, -1 ); //test that part number is maintained
    1068                 :          1 :   QVERIFY( p21.nextVertex( v, p22 ) );
    1069                 :          1 :   QCOMPARE( p22, p21 );
    1070                 :          1 :   QCOMPARE( v, QgsVertexId( 1, 0, 0 ) );
    1071                 :            : 
    1072                 :            :   //adjacent vertices - both should be invalid
    1073                 :          1 :   QgsVertexId prev( 1, 2, 3 ); // start with something
    1074                 :          1 :   QgsVertexId next( 4, 5, 6 );
    1075                 :          1 :   p21.adjacentVertices( v, prev, next );
    1076                 :          1 :   QCOMPARE( prev, QgsVertexId() );
    1077                 :          1 :   QCOMPARE( next, QgsVertexId() );
    1078                 :            : 
    1079                 :            :   // vertex iterator
    1080                 :          1 :   QgsAbstractGeometry::vertex_iterator it1 = p21.vertices_begin();
    1081                 :          1 :   QgsAbstractGeometry::vertex_iterator it1end = p21.vertices_end();
    1082                 :          1 :   QCOMPARE( *it1, p21 );
    1083                 :          1 :   QCOMPARE( it1.vertexId(), QgsVertexId( 0, 0, 0 ) );
    1084                 :          1 :   ++it1;
    1085                 :          1 :   QCOMPARE( it1, it1end );
    1086                 :            : 
    1087                 :            :   // Java-style iterator
    1088                 :          1 :   QgsVertexIterator it2( &p21 );
    1089                 :          1 :   QVERIFY( it2.hasNext() );
    1090                 :          1 :   QCOMPARE( it2.next(), p21 );
    1091                 :          1 :   QVERIFY( !it2.hasNext() );
    1092                 :            : 
    1093                 :            :   //vertexAt - will always be same as point
    1094                 :          1 :   QCOMPARE( p21.vertexAt( QgsVertexId() ), p21 );
    1095                 :          1 :   QCOMPARE( p21.vertexAt( QgsVertexId( 0, 0, 0 ) ), p21 );
    1096                 :            : 
    1097                 :            :   //vertexAngle - undefined, but check that it doesn't crash
    1098                 :          1 :   ( void )p21.vertexAngle( QgsVertexId() );
    1099                 :            : 
    1100                 :            :   //counts
    1101                 :          1 :   QCOMPARE( p20.vertexCount(), 1 );
    1102                 :          1 :   QCOMPARE( p20.ringCount(), 1 );
    1103                 :          1 :   QCOMPARE( p20.partCount(), 1 );
    1104                 :            : 
    1105                 :            :   //measures and other abstract geometry methods
    1106                 :          1 :   QCOMPARE( p20.length(), 0.0 );
    1107                 :          1 :   QCOMPARE( p20.perimeter(), 0.0 );
    1108                 :          1 :   QCOMPARE( p20.area(), 0.0 );
    1109                 :          1 :   QCOMPARE( p20.centroid(), p20 );
    1110                 :          1 :   QVERIFY( !p20.hasCurvedSegments() );
    1111                 :          1 :   std::unique_ptr< QgsPoint >segmented( static_cast< QgsPoint *>( p20.segmentize() ) );
    1112                 :          1 :   QCOMPARE( *segmented, p20 );
    1113                 :            : 
    1114                 :            :   //addZValue
    1115                 :          1 :   QgsPoint p23( 1.0, 2.0 );
    1116                 :          1 :   QVERIFY( p23.addZValue( 5.0 ) );
    1117                 :          1 :   QCOMPARE( p23, QgsPoint( QgsWkbTypes::PointZ, 1.0, 2.0, 5.0 ) );
    1118                 :          1 :   QVERIFY( !p23.addZValue( 6.0 ) );
    1119                 :            : 
    1120                 :            :   //addMValue
    1121                 :          1 :   QgsPoint p24( 1.0, 2.0 );
    1122                 :          1 :   QVERIFY( p24.addMValue( 5.0 ) );
    1123                 :          1 :   QCOMPARE( p24, QgsPoint( QgsWkbTypes::PointM, 1.0, 2.0, 0.0, 5.0 ) );
    1124                 :          1 :   QVERIFY( !p24.addMValue( 6.0 ) );
    1125                 :            : 
    1126                 :            :   //dropZ
    1127                 :          1 :   QgsPoint p25( QgsWkbTypes::PointZ, 1.0, 2.0, 3.0 );
    1128                 :          1 :   QVERIFY( p25.dropZValue() );
    1129                 :          1 :   QCOMPARE( p25, QgsPoint( 1.0, 2.0 ) );
    1130                 :          1 :   QVERIFY( !p25.dropZValue() );
    1131                 :          1 :   QgsPoint p26( QgsWkbTypes::PointZM, 1.0, 2.0, 3.0, 4.0 );
    1132                 :          1 :   QVERIFY( p26.dropZValue() );
    1133                 :          1 :   QCOMPARE( p26, QgsPoint( QgsWkbTypes::PointM, 1.0, 2.0, 0.0, 4.0 ) );
    1134                 :          1 :   QVERIFY( !p26.dropZValue() );
    1135                 :          1 :   QgsPoint p26a( QgsWkbTypes::Point25D, 1.0, 2.0, 3.0 );
    1136                 :          1 :   QVERIFY( p26a.dropZValue() );
    1137                 :          1 :   QCOMPARE( p26a, QgsPoint( QgsWkbTypes::Point, 1.0, 2.0 ) );
    1138                 :          1 :   QVERIFY( !p26a.dropZValue() );
    1139                 :            : 
    1140                 :            :   //dropM
    1141                 :          1 :   QgsPoint p27( QgsWkbTypes::PointM, 1.0, 2.0, 0.0, 3.0 );
    1142                 :          1 :   QVERIFY( p27.dropMValue() );
    1143                 :          1 :   QCOMPARE( p27, QgsPoint( 1.0, 2.0 ) );
    1144                 :          1 :   QVERIFY( !p27.dropMValue() );
    1145                 :          1 :   QgsPoint p28( QgsWkbTypes::PointZM, 1.0, 2.0, 3.0, 4.0 );
    1146                 :          1 :   QVERIFY( p28.dropMValue() );
    1147                 :          1 :   QCOMPARE( p28, QgsPoint( QgsWkbTypes::PointZ, 1.0, 2.0, 3.0, 0.0 ) );
    1148                 :          1 :   QVERIFY( !p28.dropMValue() );
    1149                 :            : 
    1150                 :            :   //convertTo
    1151                 :          1 :   QgsPoint p29( 1.0, 2.0 );
    1152                 :          1 :   QVERIFY( p29.convertTo( QgsWkbTypes::Point ) );
    1153                 :          1 :   QCOMPARE( p29.wkbType(), QgsWkbTypes::Point );
    1154                 :          1 :   QVERIFY( p29.convertTo( QgsWkbTypes::PointZ ) );
    1155                 :          1 :   QCOMPARE( p29.wkbType(), QgsWkbTypes::PointZ );
    1156                 :          1 :   p29.setZ( 5.0 );
    1157                 :          1 :   QVERIFY( p29.convertTo( QgsWkbTypes::Point25D ) );
    1158                 :          1 :   QCOMPARE( p29.wkbType(), QgsWkbTypes::Point25D );
    1159                 :          1 :   QCOMPARE( p29.z(), 5.0 );
    1160                 :          1 :   QVERIFY( p29.convertTo( QgsWkbTypes::PointZM ) );
    1161                 :          1 :   QCOMPARE( p29.wkbType(), QgsWkbTypes::PointZM );
    1162                 :          1 :   QCOMPARE( p29.z(), 5.0 );
    1163                 :          1 :   p29.setM( 9.0 );
    1164                 :          1 :   QVERIFY( p29.convertTo( QgsWkbTypes::PointM ) );
    1165                 :          1 :   QCOMPARE( p29.wkbType(), QgsWkbTypes::PointM );
    1166                 :          1 :   QVERIFY( std::isnan( p29.z() ) );
    1167                 :          1 :   QCOMPARE( p29.m(), 9.0 );
    1168                 :          1 :   QVERIFY( p29.convertTo( QgsWkbTypes::Point ) );
    1169                 :          1 :   QCOMPARE( p29.wkbType(), QgsWkbTypes::Point );
    1170                 :          1 :   QVERIFY( std::isnan( p29.z() ) );
    1171                 :          1 :   QVERIFY( std::isnan( p29.m() ) );
    1172                 :          1 :   QVERIFY( !p29.convertTo( QgsWkbTypes::Polygon ) );
    1173                 :            : 
    1174                 :            :   //boundary
    1175                 :          1 :   QgsPoint p30( 1.0, 2.0 );
    1176                 :          1 :   QVERIFY( !p30.boundary() );
    1177                 :            : 
    1178                 :            :   // distance
    1179                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).distance( QgsPoint( 2, 2 ) ), 1.0 );
    1180                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).distance( 2, 2 ), 1.0 );
    1181                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).distance( QgsPoint( 3, 2 ) ), 2.0 );
    1182                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).distance( 3, 2 ), 2.0 );
    1183                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).distance( QgsPoint( 1, 3 ) ), 1.0 );
    1184                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).distance( 1, 3 ), 1.0 );
    1185                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).distance( QgsPoint( 1, 4 ) ), 2.0 );
    1186                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).distance( 1, 4 ), 2.0 );
    1187                 :          1 :   QCOMPARE( QgsPoint( 1, -2 ).distance( QgsPoint( 1, -4 ) ), 2.0 );
    1188                 :          1 :   QCOMPARE( QgsPoint( 1, -2 ).distance( 1, -4 ), 2.0 );
    1189                 :            : 
    1190                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).distanceSquared( QgsPoint( 2, 2 ) ), 1.0 );
    1191                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).distanceSquared( 2, 2 ), 1.0 );
    1192                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).distanceSquared( QgsPoint( 3, 2 ) ), 4.0 );
    1193                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).distanceSquared( 3, 2 ), 4.0 );
    1194                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).distanceSquared( QgsPoint( 1, 3 ) ), 1.0 );
    1195                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).distanceSquared( 1, 3 ), 1.0 );
    1196                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).distanceSquared( QgsPoint( 1, 4 ) ), 4.0 );
    1197                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).distanceSquared( 1, 4 ), 4.0 );
    1198                 :          1 :   QCOMPARE( QgsPoint( 1, -2 ).distanceSquared( QgsPoint( 1, -4 ) ), 4.0 );
    1199                 :          1 :   QCOMPARE( QgsPoint( 1, -2 ).distanceSquared( 1, -4 ), 4.0 );
    1200                 :            : 
    1201                 :            :   // distance 3D
    1202                 :          1 :   QCOMPARE( QgsPoint( 0, 0 ).distanceSquared3D( QgsPoint( 1, 1 ) ), 2.0 );
    1203                 :          1 :   QVERIFY( std::isnan( QgsPoint( 0, 0 ).distanceSquared3D( 1, 1, 0 ) ) );
    1204                 :          1 :   QVERIFY( std::isnan( QgsPoint( 0, 0 ).distanceSquared3D( QgsPoint( QgsWkbTypes::PointZ, 2, 2, 2, 0 ) ) ) );
    1205                 :          1 :   QVERIFY( std::isnan( QgsPoint( 0, 0 ).distanceSquared3D( 2, 2, 2 ) ) );
    1206                 :          1 :   QVERIFY( std::isnan( QgsPoint( QgsWkbTypes::PointZ, 2, 2, 2, 0 ).distanceSquared3D( QgsPoint( 1, 1 ) ) ) );
    1207                 :          1 :   QCOMPARE( QgsPoint( QgsWkbTypes::PointZ, 2, 2, 2, 0 ).distanceSquared3D( 1, 1, 0 ), 6.0 );
    1208                 :          1 :   QVERIFY( std::isnan( QgsPoint( QgsWkbTypes::PointZ, -2, -2, -2, 0 ).distanceSquared3D( QgsPoint( 0, 0 ) ) ) );
    1209                 :          1 :   QCOMPARE( QgsPoint( QgsWkbTypes::PointZ, -2, -2, -2, 0 ).distanceSquared3D( 0, 0, 0 ), 12.0 );
    1210                 :          1 :   QCOMPARE( QgsPoint( QgsWkbTypes::PointZ, -2, -2, -2, 0 ).distanceSquared3D( QgsPoint( QgsWkbTypes::PointZ, 2, 2, 2, 0 ) ), 48.0 );
    1211                 :          1 :   QCOMPARE( QgsPoint( QgsWkbTypes::PointZ, -2, -2, -2, 0 ).distanceSquared3D( 2, 2, 2 ), 48.0 );
    1212                 :            : 
    1213                 :            : 
    1214                 :          1 :   QCOMPARE( QgsPoint( QgsWkbTypes::PointZ, 1, 1, 2, 0 ).distance3D( QgsPoint( QgsWkbTypes::PointZ, 1, 3, 2, 0 ) ), 2.0 );
    1215                 :          1 :   QCOMPARE( QgsPoint( QgsWkbTypes::PointZ, 1, 1, 2, 0 ).distance3D( 1, 3, 2 ), 2.0 );
    1216                 :          1 :   QCOMPARE( QgsPoint( QgsWkbTypes::PointZ, 1, 1, 2, 0 ).distance3D( QgsPoint( QgsWkbTypes::PointZ, 1, 1, 4, 0 ) ), 2.0 );
    1217                 :          1 :   QCOMPARE( QgsPoint( QgsWkbTypes::PointZ, 1, 1, 2, 0 ).distance3D( 1, 1, 4 ), 2.0 );
    1218                 :          1 :   QCOMPARE( QgsPoint( QgsWkbTypes::PointZ, 1, 1, -2, 0 ).distance3D( QgsPoint( QgsWkbTypes::PointZ, 1, 1, -4, 0 ) ), 2.0 );
    1219                 :          1 :   QCOMPARE( QgsPoint( QgsWkbTypes::PointZ, 1, 1, -2, 0 ).distance3D( 1, 1, -4 ), 2.0 );
    1220                 :            : 
    1221                 :            :   // azimuth
    1222                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).azimuth( QgsPoint( 1, 2 ) ), 0.0 );
    1223                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).azimuth( QgsPoint( 1, 3 ) ), 0.0 );
    1224                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).azimuth( QgsPoint( 2, 2 ) ), 90.0 );
    1225                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).azimuth( QgsPoint( 1, 0 ) ), 180.0 );
    1226                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).azimuth( QgsPoint( 0, 2 ) ), -90.0 );
    1227                 :            : 
    1228                 :            :   // operators
    1229                 :          1 :   QgsPoint p31( 1, 2 );
    1230                 :          1 :   QgsPoint p32( 3, 5 );
    1231                 :          1 :   QCOMPARE( p32 - p31, QgsVector( 2, 3 ) );
    1232                 :          1 :   QCOMPARE( p31 - p32, QgsVector( -2, -3 ) );
    1233                 :            : 
    1234                 :          1 :   p31 = QgsPoint( 1, 2 );
    1235                 :          1 :   QCOMPARE( p31 + QgsVector( 3, 5 ), QgsPoint( 4, 7 ) );
    1236                 :          1 :   p31 += QgsVector( 3, 5 );
    1237                 :          1 :   QCOMPARE( p31, QgsPoint( 4, 7 ) );
    1238                 :            : 
    1239                 :          1 :   QCOMPARE( p31 - QgsVector( 3, 5 ), QgsPoint( 1, 2 ) );
    1240                 :          1 :   p31 -= QgsVector( 3, 5 );
    1241                 :          1 :   QCOMPARE( p31, QgsPoint( 1, 2 ) );
    1242                 :            : 
    1243                 :            :   // test projecting a point
    1244                 :            :   // 2D
    1245                 :          1 :   QgsPoint p33 = QgsPoint( 1, 2 );
    1246                 :          1 :   QCOMPARE( p33.project( 1, 0 ), QgsPoint( 1, 3 ) );
    1247                 :          1 :   QCOMPARE( p33.project( 1, 0, 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2 ) );
    1248                 :          1 :   QCOMPARE( p33.project( 1.5, 90 ), QgsPoint( 2.5, 2 ) );
    1249                 :          1 :   QCOMPARE( p33.project( 1.5, 90, 90 ), QgsPoint( 2.5, 2 ) ); // stay QgsWkbTypes::Point
    1250                 :          1 :   QCOMPARE( p33.project( 2, 180 ), QgsPoint( 1, 0 ) );
    1251                 :          1 :   QCOMPARE( p33.project( 5, 270 ), QgsPoint( -4, 2 ) );
    1252                 :          1 :   QCOMPARE( p33.project( 6, 360 ), QgsPoint( 1, 8 ) );
    1253                 :          1 :   QCOMPARE( p33.project( 5, 450 ), QgsPoint( 6, 2 ) );
    1254                 :          1 :   QCOMPARE( p33.project( 5, 450, 450 ), QgsPoint( 6, 2 ) );  // stay QgsWkbTypes::Point
    1255                 :          1 :   QCOMPARE( p33.project( -1, 0 ), QgsPoint( 1, 1 ) );
    1256                 :          1 :   QCOMPARE( p33.project( 1.5, -90 ), QgsPoint( -0.5, 2 ) );
    1257                 :          1 :   p33.addZValue( 0 );
    1258                 :          1 :   QCOMPARE( p33.project( 1, 0, 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 1 ) );
    1259                 :          1 :   QCOMPARE( p33.project( 2, 180, 180 ), QgsPoint( QgsWkbTypes::PointZ,  1, 2, -2 ) );
    1260                 :          1 :   QCOMPARE( p33.project( 5, 270, 270 ), QgsPoint( QgsWkbTypes::PointZ,  6, 2, 0 ) );
    1261                 :          1 :   QCOMPARE( p33.project( 6, 360, 360 ), QgsPoint( QgsWkbTypes::PointZ,  1, 2, 6 ) );
    1262                 :          1 :   QCOMPARE( p33.project( -1, 0, 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, -1 ) );
    1263                 :          1 :   QCOMPARE( p33.project( 1.5, -90, -90 ), QgsPoint( QgsWkbTypes::PointZ, 2.5, 2, 0 ) );
    1264                 :            : 
    1265                 :            :   // PointM
    1266                 :          1 :   p33.dropZValue();
    1267                 :          1 :   p33.addMValue( 5.0 );
    1268                 :          1 :   QCOMPARE( p33.project( 1, 0 ), QgsPoint( QgsWkbTypes::PointM, 1, 3, 0, 5 ) );
    1269                 :          1 :   QCOMPARE( p33.project( 5, 450, 450 ), QgsPoint( QgsWkbTypes::PointM, 6, 2, 0, 5 ) );
    1270                 :            : 
    1271                 :          1 :   p33.addZValue( 0 );
    1272                 :          1 :   QCOMPARE( p33.project( 1, 0, 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 1, 5 ) );
    1273                 :            : 
    1274                 :            :   // 3D
    1275                 :          1 :   QgsPoint p34 = QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 );
    1276                 :          1 :   QCOMPARE( p34.project( 1, 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 3, 2 ) );
    1277                 :          1 :   QCOMPARE( p34.project( 1, 0, 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) );
    1278                 :          1 :   QCOMPARE( p34.project( 1.5, 90 ), QgsPoint( QgsWkbTypes::PointZ, 2.5, 2, 2 ) );
    1279                 :          1 :   QCOMPARE( p34.project( 1.5, 90, 90 ), QgsPoint( QgsWkbTypes::PointZ, 2.5, 2, 2 ) );
    1280                 :          1 :   QCOMPARE( p34.project( 2, 180 ), QgsPoint( QgsWkbTypes::PointZ, 1, 0, 2 ) );
    1281                 :          1 :   QCOMPARE( p34.project( 2, 180, 180 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 0 ) );
    1282                 :          1 :   QCOMPARE( p34.project( 5, 270 ), QgsPoint( QgsWkbTypes::PointZ, -4, 2, 2 ) );
    1283                 :          1 :   QCOMPARE( p34.project( 5, 270, 270 ), QgsPoint( QgsWkbTypes::PointZ, 6, 2, 2 ) );
    1284                 :          1 :   QCOMPARE( p34.project( 6, 360 ), QgsPoint( QgsWkbTypes::PointZ, 1, 8, 2 ) );
    1285                 :          1 :   QCOMPARE( p34.project( 6, 360, 360 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 8 ) );
    1286                 :          1 :   QCOMPARE( p34.project( 5, 450 ), QgsPoint( QgsWkbTypes::PointZ, 6, 2, 2 ) );
    1287                 :          1 :   QCOMPARE( p34.project( 5, 450, 450 ), QgsPoint( QgsWkbTypes::PointZ, 6, 2, 2 ) );
    1288                 :          1 :   QCOMPARE( p34.project( -1, 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 1, 2 ) );
    1289                 :          1 :   QCOMPARE( p34.project( -1, 0, 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 1 ) );
    1290                 :          1 :   QCOMPARE( p34.project( 1.5, -90 ), QgsPoint( QgsWkbTypes::PointZ, -0.5, 2, 2 ) );
    1291                 :          1 :   QCOMPARE( p34.project( 1.5, -90, -90 ), QgsPoint( QgsWkbTypes::PointZ, 2.5, 2, 2 ) );
    1292                 :            :   // PointM
    1293                 :          1 :   p34.addMValue( 5.0 );
    1294                 :          1 :   QCOMPARE( p34.project( 1, 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 3, 2, 5 ) );
    1295                 :          1 :   QCOMPARE( p34.project( 1, 0, 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 5 ) );
    1296                 :          1 :   QCOMPARE( p34.project( 5, 450 ), QgsPoint( QgsWkbTypes::PointZM, 6, 2, 2, 5 ) );
    1297                 :          1 :   QCOMPARE( p34.project( 5, 450, 450 ), QgsPoint( QgsWkbTypes::PointZM, 6, 2, 2, 5 ) );
    1298                 :            : 
    1299                 :            :   // inclination
    1300                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).inclination( QgsPoint( 1, 2 ) ), 90.0 );
    1301                 :          1 :   QCOMPARE( QgsPoint( QgsWkbTypes::PointZ, 1, 1, 2, 0 ).inclination( QgsPoint( QgsWkbTypes::PointZ, 1, 1, 2, 0 ) ), 90.0 );
    1302                 :          1 :   QCOMPARE( QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ).inclination( QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ).project( 5, 90, 90 ) ), 90.0 );
    1303                 :          1 :   QCOMPARE( QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ).inclination( QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ).project( 5, 90, -90 ) ), 90.0 );
    1304                 :          1 :   QCOMPARE( QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ).inclination( QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ).project( 5, 90, 0 ) ), 0.0 );
    1305                 :          1 :   QCOMPARE( QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ).inclination( QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ).project( 5, 90, 180 ) ), 180.0 );
    1306                 :          1 :   QCOMPARE( QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ).inclination( QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ).project( 5, 90, -180 ) ), 180.0 );
    1307                 :          1 :   QCOMPARE( QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ).inclination( QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ).project( 5, 90, 720 ) ), 0.0 );
    1308                 :          1 :   QCOMPARE( QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ).inclination( QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ).project( 5, 90, 45 ) ), 45.0 );
    1309                 :          1 :   QCOMPARE( QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ).inclination( QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ).project( 5, 90, 135 ) ), 135.0 );
    1310                 :            : 
    1311                 :            :   // vertex number
    1312                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).vertexNumberFromVertexId( QgsVertexId( 0, 0, -1 ) ), -1 );
    1313                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).vertexNumberFromVertexId( QgsVertexId( 0, 0, 1 ) ), -1 );
    1314                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).vertexNumberFromVertexId( QgsVertexId( 0, 0, 0 ) ), 0 );
    1315                 :            : 
    1316                 :            :   //segmentLength
    1317                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).segmentLength( QgsVertexId() ), 0.0 );
    1318                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).segmentLength( QgsVertexId( -1, 0, 0 ) ), 0.0 );
    1319                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).segmentLength( QgsVertexId( -1, 0, 1 ) ), 0.0 );
    1320                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).segmentLength( QgsVertexId( -1, 0, -1 ) ), 0.0 );
    1321                 :          1 :   QCOMPARE( QgsPoint( 1, 2 ).segmentLength( QgsVertexId( 0, 0, 0 ) ), 0.0 );
    1322                 :            : 
    1323                 :            :   // remove duplicate points
    1324                 :          1 :   QgsPoint p = QgsPoint( 1, 2 );
    1325                 :          1 :   QVERIFY( !p.removeDuplicateNodes() );
    1326                 :          1 :   QCOMPARE( p.x(), 1.0 );
    1327                 :          1 :   QCOMPARE( p.y(), 2.0 );
    1328                 :            : 
    1329                 :            :   // swap xy
    1330                 :          1 :   p = QgsPoint( 1.1, 2.2, 3.3, 4.4, QgsWkbTypes::PointZM );
    1331                 :          1 :   p.swapXy();
    1332                 :          1 :   QCOMPARE( p.x(), 2.2 );
    1333                 :          1 :   QCOMPARE( p.y(), 1.1 );
    1334                 :          1 :   QCOMPARE( p.z(), 3.3 );
    1335                 :          1 :   QCOMPARE( p.m(), 4.4 );
    1336                 :          1 :   QCOMPARE( p.wkbType(), QgsWkbTypes::PointZM );
    1337                 :            : 
    1338                 :            :   // filter vertex
    1339                 :          1 :   p = QgsPoint( 1.1, 2.2, 3.3, 4.4, QgsWkbTypes::PointZM );
    1340                 :          1 :   p.filterVertices( []( const QgsPoint & )-> bool { return false; } );
    1341                 :          1 :   QCOMPARE( p.x(), 1.1 );
    1342                 :          1 :   QCOMPARE( p.y(), 2.2 );
    1343                 :          1 :   QCOMPARE( p.z(), 3.3 );
    1344                 :          1 :   QCOMPARE( p.m(), 4.4 );
    1345                 :          1 :   QCOMPARE( p.wkbType(), QgsWkbTypes::PointZM );
    1346                 :            : 
    1347                 :            :   // transform vertex
    1348                 :          1 :   p = QgsPoint( 1.1, 2.2, 3.3, 4.4, QgsWkbTypes::PointZM );
    1349                 :          2 :   p.transformVertices( []( const QgsPoint & p )-> QgsPoint
    1350                 :            :   {
    1351                 :          1 :     return QgsPoint( p.x() + 2, p.y() + 3, p.z() + 1, p.m() + 8 );
    1352                 :            :   } );
    1353                 :          1 :   QCOMPARE( p.x(), 3.1 );
    1354                 :          1 :   QCOMPARE( p.y(), 5.2 );
    1355                 :          1 :   QCOMPARE( p.z(), 4.3 );
    1356                 :          1 :   QCOMPARE( p.m(), 12.4 );
    1357                 :          1 :   QCOMPARE( p.wkbType(), QgsWkbTypes::PointZM );
    1358                 :            :   // no dimensionality change allowed
    1359                 :          2 :   p.transformVertices( []( const QgsPoint & p )-> QgsPoint
    1360                 :            :   {
    1361                 :          1 :     return QgsPoint( p.x() + 2, p.y() + 3 );
    1362                 :            :   } );
    1363                 :          1 :   QCOMPARE( p.x(), 5.1 );
    1364                 :          1 :   QCOMPARE( p.y(), 8.2 );
    1365                 :          1 :   QVERIFY( std::isnan( p.z() ) );
    1366                 :          1 :   QVERIFY( std::isnan( p.m() ) );
    1367                 :          1 :   QCOMPARE( p.wkbType(), QgsWkbTypes::PointZM );
    1368                 :          1 :   p = QgsPoint( 2, 3 );
    1369                 :          2 :   p.transformVertices( []( const QgsPoint & p )-> QgsPoint
    1370                 :            :   {
    1371                 :          1 :     return QgsPoint( p.x() + 2, p.y() + 3, 7, 8 );
    1372                 :            :   } );
    1373                 :          1 :   QCOMPARE( p.x(), 4.0 );
    1374                 :          1 :   QCOMPARE( p.y(), 6.0 );
    1375                 :          1 :   QVERIFY( std::isnan( p.z() ) );
    1376                 :          1 :   QVERIFY( std::isnan( p.m() ) );
    1377                 :          1 :   QCOMPARE( p.wkbType(), QgsWkbTypes::Point );
    1378                 :            : 
    1379                 :            :   // transform using class
    1380                 :          1 :   p = QgsPoint( 1.1, 2.2, 3.3, 4.4, QgsWkbTypes::PointZM );
    1381                 :          1 :   TestTransformer transformer;
    1382                 :          1 :   QVERIFY( p.transform( &transformer ) );
    1383                 :          1 :   QCOMPARE( p.x(), 3.3 );
    1384                 :          1 :   QCOMPARE( p.y(), 16.2 );
    1385                 :          1 :   QCOMPARE( p.z(), 8.3 );
    1386                 :          1 :   QCOMPARE( p.m(), 3.4 );
    1387                 :          1 :   QCOMPARE( p.wkbType(), QgsWkbTypes::PointZM );
    1388                 :            : 
    1389                 :          1 :   TestFailTransformer failTransformer;
    1390                 :          1 :   QVERIFY( !p.transform( &failTransformer ) );
    1391                 :            : 
    1392                 :            :   // test bounding box intersects
    1393                 :          1 :   QVERIFY( QgsPoint( 1, 2 ).boundingBoxIntersects( QgsRectangle( 0, 0.5, 1.5, 3 ) ) );
    1394                 :          1 :   QVERIFY( !QgsPoint( 1, 2 ).boundingBoxIntersects( QgsRectangle( 3, 0.5, 3.5, 3 ) ) );
    1395                 :          1 :   QVERIFY( !QgsPoint().boundingBoxIntersects( QgsRectangle( 0, 0.5, 3.5, 3 ) ) );
    1396                 :          1 : }
    1397                 :            : 
    1398                 :          1 : void TestQgsGeometry::circularString()
    1399                 :            : {
    1400                 :            :   //test constructors
    1401                 :          1 :   QgsCircularString l1;
    1402                 :          1 :   QVERIFY( l1.isEmpty() );
    1403                 :          1 :   QCOMPARE( l1.numPoints(), 0 );
    1404                 :          1 :   QCOMPARE( l1.vertexCount(), 0 );
    1405                 :          1 :   QCOMPARE( l1.nCoordinates(), 0 );
    1406                 :          1 :   QCOMPARE( l1.ringCount(), 0 );
    1407                 :          1 :   QCOMPARE( l1.partCount(), 0 );
    1408                 :          1 :   QVERIFY( !l1.is3D() );
    1409                 :          1 :   QVERIFY( !l1.isMeasure() );
    1410                 :          1 :   QCOMPARE( l1.wkbType(), QgsWkbTypes::CircularString );
    1411                 :          1 :   QCOMPARE( l1.wktTypeStr(), QString( "CircularString" ) );
    1412                 :          1 :   QCOMPARE( l1.geometryType(), QString( "CircularString" ) );
    1413                 :          1 :   QCOMPARE( l1.dimension(), 1 );
    1414                 :          1 :   QVERIFY( l1.hasCurvedSegments() );
    1415                 :          1 :   QCOMPARE( l1.area(), 0.0 );
    1416                 :          1 :   QCOMPARE( l1.perimeter(), 0.0 );
    1417                 :          1 :   QgsPointSequence pts;
    1418                 :          1 :   l1.points( pts );
    1419                 :          1 :   QVERIFY( pts.empty() );
    1420                 :            : 
    1421                 :            :   // from 3 points
    1422                 :          1 :   QgsCircularString from3Pts( QgsPoint( 1, 2 ), QgsPoint( 21, 22 ), QgsPoint( 31, 2 ) );
    1423                 :          1 :   QCOMPARE( from3Pts.wkbType(), QgsWkbTypes::CircularString );
    1424                 :          1 :   QCOMPARE( from3Pts.numPoints(), 3 );
    1425                 :          1 :   QCOMPARE( from3Pts.xAt( 0 ), 1.0 );
    1426                 :          1 :   QCOMPARE( from3Pts.yAt( 0 ), 2.0 );
    1427                 :          1 :   QCOMPARE( from3Pts.xAt( 1 ), 21.0 );
    1428                 :          1 :   QCOMPARE( from3Pts.yAt( 1 ), 22.0 );
    1429                 :          1 :   QCOMPARE( from3Pts.xAt( 2 ), 31.0 );
    1430                 :          1 :   QCOMPARE( from3Pts.yAt( 2 ), 2.0 );
    1431                 :          2 :   from3Pts = QgsCircularString( QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ), QgsPoint( QgsWkbTypes::PointZ, 21, 22, 23 ),
    1432                 :          1 :                                 QgsPoint( QgsWkbTypes::PointZ, 31, 2, 33 ) );
    1433                 :          1 :   QCOMPARE( from3Pts.wkbType(), QgsWkbTypes::CircularStringZ );
    1434                 :          1 :   QCOMPARE( from3Pts.numPoints(), 3 );
    1435                 :          1 :   QCOMPARE( from3Pts.xAt( 0 ), 1.0 );
    1436                 :          1 :   QCOMPARE( from3Pts.yAt( 0 ), 2.0 );
    1437                 :          1 :   QCOMPARE( from3Pts.pointN( 0 ).z(), 3.0 );
    1438                 :          1 :   QCOMPARE( from3Pts.xAt( 1 ), 21.0 );
    1439                 :          1 :   QCOMPARE( from3Pts.yAt( 1 ), 22.0 );
    1440                 :          1 :   QCOMPARE( from3Pts.pointN( 1 ).z(), 23.0 );
    1441                 :          1 :   QCOMPARE( from3Pts.xAt( 2 ), 31.0 );
    1442                 :          1 :   QCOMPARE( from3Pts.yAt( 2 ), 2.0 );
    1443                 :          1 :   QCOMPARE( from3Pts.pointN( 2 ).z(), 33.0 );
    1444                 :          2 :   from3Pts = QgsCircularString( QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 3 ), QgsPoint( QgsWkbTypes::PointM, 21, 22, 0, 23 ),
    1445                 :          1 :                                 QgsPoint( QgsWkbTypes::PointM, 31, 2, 0, 33 ) );
    1446                 :          1 :   QCOMPARE( from3Pts.wkbType(), QgsWkbTypes::CircularStringM );
    1447                 :          1 :   QCOMPARE( from3Pts.numPoints(), 3 );
    1448                 :          1 :   QCOMPARE( from3Pts.xAt( 0 ), 1.0 );
    1449                 :          1 :   QCOMPARE( from3Pts.yAt( 0 ), 2.0 );
    1450                 :          1 :   QCOMPARE( from3Pts.pointN( 0 ).m(), 3.0 );
    1451                 :          1 :   QCOMPARE( from3Pts.xAt( 1 ), 21.0 );
    1452                 :          1 :   QCOMPARE( from3Pts.yAt( 1 ), 22.0 );
    1453                 :          1 :   QCOMPARE( from3Pts.pointN( 1 ).m(), 23.0 );
    1454                 :          1 :   QCOMPARE( from3Pts.xAt( 2 ), 31.0 );
    1455                 :          1 :   QCOMPARE( from3Pts.yAt( 2 ), 2.0 );
    1456                 :          1 :   QCOMPARE( from3Pts.pointN( 2 ).m(), 33.0 );
    1457                 :          2 :   from3Pts = QgsCircularString( QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ), QgsPoint( QgsWkbTypes::PointZM, 21, 22, 23, 24 ),
    1458                 :          1 :                                 QgsPoint( QgsWkbTypes::PointZM, 31, 2, 33, 34 ) );
    1459                 :          1 :   QCOMPARE( from3Pts.wkbType(), QgsWkbTypes::CircularStringZM );
    1460                 :          1 :   QCOMPARE( from3Pts.numPoints(), 3 );
    1461                 :          1 :   QCOMPARE( from3Pts.xAt( 0 ), 1.0 );
    1462                 :          1 :   QCOMPARE( from3Pts.yAt( 0 ), 2.0 );
    1463                 :          1 :   QCOMPARE( from3Pts.pointN( 0 ).z(), 3.0 );
    1464                 :          1 :   QCOMPARE( from3Pts.pointN( 0 ).m(), 4.0 );
    1465                 :          1 :   QCOMPARE( from3Pts.xAt( 1 ), 21.0 );
    1466                 :          1 :   QCOMPARE( from3Pts.yAt( 1 ), 22.0 );
    1467                 :          1 :   QCOMPARE( from3Pts.pointN( 1 ).z(), 23.0 );
    1468                 :          1 :   QCOMPARE( from3Pts.pointN( 1 ).m(), 24.0 );
    1469                 :          1 :   QCOMPARE( from3Pts.xAt( 2 ), 31.0 );
    1470                 :          1 :   QCOMPARE( from3Pts.yAt( 2 ), 2.0 );
    1471                 :          1 :   QCOMPARE( from3Pts.pointN( 2 ).z(), 33.0 );
    1472                 :          1 :   QCOMPARE( from3Pts.pointN( 2 ).m(), 34.0 );
    1473                 :            : 
    1474                 :            :   // from 2 points and center
    1475                 :          1 :   from3Pts = QgsCircularString::fromTwoPointsAndCenter( QgsPoint( 1, 2 ), QgsPoint( 31, 2 ), QgsPoint( 21, 2 ) );
    1476                 :          1 :   QCOMPARE( from3Pts.wkbType(), QgsWkbTypes::CircularString );
    1477                 :          1 :   QCOMPARE( from3Pts.numPoints(), 3 );
    1478                 :          1 :   QCOMPARE( from3Pts.xAt( 0 ), 1.0 );
    1479                 :          1 :   QCOMPARE( from3Pts.yAt( 0 ), 2.0 );
    1480                 :          1 :   QCOMPARE( from3Pts.xAt( 1 ), 21.0 );
    1481                 :          1 :   QCOMPARE( from3Pts.yAt( 1 ), 22.0 );
    1482                 :          1 :   QCOMPARE( from3Pts.xAt( 2 ), 31.0 );
    1483                 :          1 :   QCOMPARE( from3Pts.yAt( 2 ), 2.0 );
    1484                 :          1 :   from3Pts = QgsCircularString::fromTwoPointsAndCenter( QgsPoint( 1, 2 ), QgsPoint( 31, 2 ), QgsPoint( 21, 2 ), false );
    1485                 :          1 :   QCOMPARE( from3Pts.wkbType(), QgsWkbTypes::CircularString );
    1486                 :          1 :   QCOMPARE( from3Pts.numPoints(), 3 );
    1487                 :          1 :   QCOMPARE( from3Pts.xAt( 0 ), 1.0 );
    1488                 :          1 :   QCOMPARE( from3Pts.yAt( 0 ), 2.0 );
    1489                 :          1 :   QCOMPARE( from3Pts.xAt( 1 ), 21.0 );
    1490                 :          1 :   QCOMPARE( from3Pts.yAt( 1 ), -18.0 );
    1491                 :          1 :   QCOMPARE( from3Pts.xAt( 2 ), 31.0 );
    1492                 :          1 :   QCOMPARE( from3Pts.yAt( 2 ), 2.0 );
    1493                 :          2 :   from3Pts = QgsCircularString::fromTwoPointsAndCenter( QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ), QgsPoint( QgsWkbTypes::PointZ, 32, 2, 33 ),
    1494                 :          1 :              QgsPoint( QgsWkbTypes::PointZ, 21, 2, 23 ) );
    1495                 :          1 :   QCOMPARE( from3Pts.wkbType(), QgsWkbTypes::CircularStringZ );
    1496                 :          1 :   QCOMPARE( from3Pts.numPoints(), 3 );
    1497                 :          1 :   QCOMPARE( from3Pts.xAt( 0 ), 1.0 );
    1498                 :          1 :   QCOMPARE( from3Pts.yAt( 0 ), 2.0 );
    1499                 :          1 :   QCOMPARE( from3Pts.pointN( 0 ).z(), 3.0 );
    1500                 :          1 :   QCOMPARE( from3Pts.xAt( 1 ), 21.0 );
    1501                 :          1 :   QCOMPARE( from3Pts.yAt( 1 ), 22.0 );
    1502                 :          1 :   QCOMPARE( from3Pts.pointN( 1 ).z(), 23.0 );
    1503                 :          1 :   QCOMPARE( from3Pts.xAt( 2 ), 32.0 );
    1504                 :          1 :   QCOMPARE( from3Pts.yAt( 2 ), 2.0 );
    1505                 :          1 :   QCOMPARE( from3Pts.pointN( 2 ).z(), 33.0 );
    1506                 :          2 :   from3Pts = QgsCircularString::fromTwoPointsAndCenter( QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 3 ), QgsPoint( QgsWkbTypes::PointM, 31, 2, 0, 33 ),
    1507                 :          1 :              QgsPoint( QgsWkbTypes::PointM, 21, 2, 0, 23 ) );
    1508                 :          1 :   QCOMPARE( from3Pts.wkbType(), QgsWkbTypes::CircularStringM );
    1509                 :          1 :   QCOMPARE( from3Pts.numPoints(), 3 );
    1510                 :          1 :   QCOMPARE( from3Pts.xAt( 0 ), 1.0 );
    1511                 :          1 :   QCOMPARE( from3Pts.yAt( 0 ), 2.0 );
    1512                 :          1 :   QCOMPARE( from3Pts.pointN( 0 ).m(), 3.0 );
    1513                 :          1 :   QCOMPARE( from3Pts.xAt( 1 ), 21.0 );
    1514                 :          1 :   QCOMPARE( from3Pts.yAt( 1 ), 22.0 );
    1515                 :          1 :   QCOMPARE( from3Pts.pointN( 1 ).m(), 23.0 );
    1516                 :          1 :   QCOMPARE( from3Pts.xAt( 2 ), 31.0 );
    1517                 :          1 :   QCOMPARE( from3Pts.yAt( 2 ), 2.0 );
    1518                 :          1 :   QCOMPARE( from3Pts.pointN( 2 ).m(), 33.0 );
    1519                 :          2 :   from3Pts = QgsCircularString::fromTwoPointsAndCenter( QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ), QgsPoint( QgsWkbTypes::PointZM, 31, 2, 33, 34 ),
    1520                 :          1 :              QgsPoint( QgsWkbTypes::PointZM, 21, 2, 23, 24 ) );
    1521                 :          1 :   QCOMPARE( from3Pts.wkbType(), QgsWkbTypes::CircularStringZM );
    1522                 :          1 :   QCOMPARE( from3Pts.numPoints(), 3 );
    1523                 :          1 :   QCOMPARE( from3Pts.xAt( 0 ), 1.0 );
    1524                 :          1 :   QCOMPARE( from3Pts.yAt( 0 ), 2.0 );
    1525                 :          1 :   QCOMPARE( from3Pts.pointN( 0 ).z(), 3.0 );
    1526                 :          1 :   QCOMPARE( from3Pts.pointN( 0 ).m(), 4.0 );
    1527                 :          1 :   QCOMPARE( from3Pts.xAt( 1 ), 21.0 );
    1528                 :          1 :   QCOMPARE( from3Pts.yAt( 1 ), 22.0 );
    1529                 :          1 :   QCOMPARE( from3Pts.pointN( 1 ).z(), 23.0 );
    1530                 :          1 :   QCOMPARE( from3Pts.pointN( 1 ).m(), 24.0 );
    1531                 :          1 :   QCOMPARE( from3Pts.xAt( 2 ), 31.0 );
    1532                 :          1 :   QCOMPARE( from3Pts.yAt( 2 ), 2.0 );
    1533                 :          1 :   QCOMPARE( from3Pts.pointN( 2 ).z(), 33.0 );
    1534                 :          1 :   QCOMPARE( from3Pts.pointN( 2 ).m(), 34.0 );
    1535                 :            : 
    1536                 :            :   //setPoints
    1537                 :          1 :   QgsCircularString l2;
    1538                 :          1 :   l2.setPoints( QgsPointSequence() << QgsPoint( 1.0, 2.0 ) );
    1539                 :          1 :   QVERIFY( !l2.isEmpty() );
    1540                 :          1 :   QCOMPARE( l2.numPoints(), 1 );
    1541                 :          1 :   QCOMPARE( l2.vertexCount(), 1 );
    1542                 :          1 :   QCOMPARE( l2.nCoordinates(), 1 );
    1543                 :          1 :   QCOMPARE( l2.ringCount(), 1 );
    1544                 :          1 :   QCOMPARE( l2.partCount(), 1 );
    1545                 :          1 :   QVERIFY( !l2.is3D() );
    1546                 :          1 :   QVERIFY( !l2.isMeasure() );
    1547                 :          1 :   QCOMPARE( l2.wkbType(), QgsWkbTypes::CircularString );
    1548                 :          1 :   QVERIFY( l2.hasCurvedSegments() );
    1549                 :          1 :   QCOMPARE( l2.area(), 0.0 );
    1550                 :          1 :   QCOMPARE( l2.perimeter(), 0.0 );
    1551                 :          1 :   l2.points( pts );
    1552                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( 1.0, 2.0 ) );
    1553                 :            : 
    1554                 :            :   //setting first vertex should set linestring z/m type
    1555                 :          1 :   QgsCircularString l3;
    1556                 :          1 :   l3.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1.0, 2.0, 3.0 ) );
    1557                 :          1 :   QVERIFY( !l3.isEmpty() );
    1558                 :          1 :   QVERIFY( l3.is3D() );
    1559                 :          1 :   QVERIFY( !l3.isMeasure() );
    1560                 :          1 :   QCOMPARE( l3.wkbType(), QgsWkbTypes::CircularStringZ );
    1561                 :          1 :   QCOMPARE( l3.wktTypeStr(), QString( "CircularStringZ" ) );
    1562                 :          1 :   l3.points( pts );
    1563                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1.0, 2.0, 3.0 ) );
    1564                 :            : 
    1565                 :          1 :   QgsCircularString l4;
    1566                 :          1 :   l4.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1.0, 2.0, 0.0, 3.0 ) );
    1567                 :          1 :   QVERIFY( !l4.isEmpty() );
    1568                 :          1 :   QVERIFY( !l4.is3D() );
    1569                 :          1 :   QVERIFY( l4.isMeasure() );
    1570                 :          1 :   QCOMPARE( l4.wkbType(), QgsWkbTypes::CircularStringM );
    1571                 :          1 :   QCOMPARE( l4.wktTypeStr(), QString( "CircularStringM" ) );
    1572                 :          1 :   l4.points( pts );
    1573                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1.0, 2.0, 0.0, 3.0 ) );
    1574                 :            : 
    1575                 :          1 :   QgsCircularString l5;
    1576                 :          1 :   l5.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1.0, 2.0, 3.0, 4.0 ) );
    1577                 :          1 :   QVERIFY( !l5.isEmpty() );
    1578                 :          1 :   QVERIFY( l5.is3D() );
    1579                 :          1 :   QVERIFY( l5.isMeasure() );
    1580                 :          1 :   QCOMPARE( l5.wkbType(), QgsWkbTypes::CircularStringZM );
    1581                 :          1 :   QCOMPARE( l5.wktTypeStr(), QString( "CircularStringZM" ) );
    1582                 :          1 :   l5.points( pts );
    1583                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1.0, 2.0, 3.0, 4.0 ) );
    1584                 :            : 
    1585                 :            :   //clear
    1586                 :          1 :   l5.clear();
    1587                 :          1 :   QVERIFY( l5.isEmpty() );
    1588                 :          1 :   QCOMPARE( l5.numPoints(), 0 );
    1589                 :          1 :   QCOMPARE( l5.vertexCount(), 0 );
    1590                 :          1 :   QCOMPARE( l5.nCoordinates(), 0 );
    1591                 :          1 :   QCOMPARE( l5.ringCount(), 0 );
    1592                 :          1 :   QCOMPARE( l5.partCount(), 0 );
    1593                 :          1 :   QVERIFY( !l5.is3D() );
    1594                 :          1 :   QVERIFY( !l5.isMeasure() );
    1595                 :          1 :   QCOMPARE( l5.wkbType(), QgsWkbTypes::CircularString );
    1596                 :            : 
    1597                 :            :   //setPoints
    1598                 :          1 :   QgsCircularString l8;
    1599                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 2, 3 ) << QgsPoint( 3, 4 ) );
    1600                 :          1 :   QVERIFY( !l8.isEmpty() );
    1601                 :          1 :   QCOMPARE( l8.numPoints(), 3 );
    1602                 :          1 :   QCOMPARE( l8.vertexCount(), 3 );
    1603                 :          1 :   QCOMPARE( l8.nCoordinates(), 3 );
    1604                 :          1 :   QCOMPARE( l8.ringCount(), 1 );
    1605                 :          1 :   QCOMPARE( l8.partCount(), 1 );
    1606                 :          1 :   QVERIFY( !l8.is3D() );
    1607                 :          1 :   QVERIFY( !l8.isMeasure() );
    1608                 :          1 :   QCOMPARE( l8.wkbType(), QgsWkbTypes::CircularString );
    1609                 :          1 :   QVERIFY( l8.hasCurvedSegments() );
    1610                 :          1 :   l8.points( pts );
    1611                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 2, 3 ) << QgsPoint( 3, 4 ) );
    1612                 :            : 
    1613                 :            :   //setPoints with empty list, should clear linestring
    1614                 :          1 :   l8.setPoints( QgsPointSequence() );
    1615                 :          1 :   QVERIFY( l8.isEmpty() );
    1616                 :          1 :   QCOMPARE( l8.numPoints(), 0 );
    1617                 :          1 :   QCOMPARE( l8.vertexCount(), 0 );
    1618                 :          1 :   QCOMPARE( l8.nCoordinates(), 0 );
    1619                 :          1 :   QCOMPARE( l8.ringCount(), 0 );
    1620                 :          1 :   QCOMPARE( l8.partCount(), 0 );
    1621                 :          1 :   QCOMPARE( l8.wkbType(), QgsWkbTypes::CircularString );
    1622                 :          1 :   l8.points( pts );
    1623                 :          1 :   QVERIFY( pts.empty() );
    1624                 :            : 
    1625                 :            :   //setPoints with z
    1626                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 2, 3, 4 ) );
    1627                 :          1 :   QCOMPARE( l8.numPoints(), 2 );
    1628                 :          1 :   QVERIFY( l8.is3D() );
    1629                 :          1 :   QVERIFY( !l8.isMeasure() );
    1630                 :          1 :   QCOMPARE( l8.wkbType(), QgsWkbTypes::CircularStringZ );
    1631                 :          1 :   l8.points( pts );
    1632                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 2, 3, 4 ) );
    1633                 :            : 
    1634                 :            :   //setPoints with m
    1635                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 3 ) << QgsPoint( QgsWkbTypes::PointM, 2, 3, 0, 4 ) );
    1636                 :          1 :   QCOMPARE( l8.numPoints(), 2 );
    1637                 :          1 :   QVERIFY( !l8.is3D() );
    1638                 :          1 :   QVERIFY( l8.isMeasure() );
    1639                 :          1 :   QCOMPARE( l8.wkbType(), QgsWkbTypes::CircularStringM );
    1640                 :          1 :   l8.points( pts );
    1641                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 3 ) << QgsPoint( QgsWkbTypes::PointM, 2, 3, 0, 4 ) );
    1642                 :            : 
    1643                 :            :   //setPoints with zm
    1644                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 4, 5 ) << QgsPoint( QgsWkbTypes::PointZM, 2, 3, 4, 5 ) );
    1645                 :          1 :   QCOMPARE( l8.numPoints(), 2 );
    1646                 :          1 :   QVERIFY( l8.is3D() );
    1647                 :          1 :   QVERIFY( l8.isMeasure() );
    1648                 :          1 :   QCOMPARE( l8.wkbType(), QgsWkbTypes::CircularStringZM );
    1649                 :          1 :   l8.points( pts );
    1650                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 4, 5 ) << QgsPoint( QgsWkbTypes::PointZM, 2, 3, 4, 5 ) );
    1651                 :            : 
    1652                 :            :   //setPoints with MIXED dimensionality of points
    1653                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 4, 5 ) << QgsPoint( QgsWkbTypes::PointM, 2, 3, 0, 5 ) );
    1654                 :          1 :   QCOMPARE( l8.numPoints(), 2 );
    1655                 :          1 :   QVERIFY( l8.is3D() );
    1656                 :          1 :   QVERIFY( l8.isMeasure() );
    1657                 :          1 :   QCOMPARE( l8.wkbType(), QgsWkbTypes::CircularStringZM );
    1658                 :          1 :   l8.points( pts );
    1659                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 4, 5 ) << QgsPoint( QgsWkbTypes::PointZM, 2, 3, 0, 5 ) );
    1660                 :            : 
    1661                 :            :   //test point
    1662                 :          1 :   QCOMPARE( l8.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 4, 5 ) );
    1663                 :          1 :   QCOMPARE( l8.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 2, 3, 0, 5 ) );
    1664                 :            : 
    1665                 :            :   //out of range - just want no crash here
    1666                 :          1 :   QgsPoint bad = l8.pointN( -1 );
    1667                 :          1 :   bad = l8.pointN( 100 );
    1668                 :            : 
    1669                 :            :   //test getters/setters
    1670                 :          1 :   QgsCircularString l9;
    1671                 :          2 :   l9.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
    1672                 :          1 :                 << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 )
    1673                 :          1 :                 << QgsPoint( QgsWkbTypes::PointZM, 21, 22, 23, 24 ) );
    1674                 :          1 :   QCOMPARE( l9.xAt( 0 ), 1.0 );
    1675                 :          1 :   QCOMPARE( l9.xAt( 1 ), 11.0 );
    1676                 :          1 :   QCOMPARE( l9.xAt( 2 ), 21.0 );
    1677                 :          1 :   QCOMPARE( l9.xAt( -1 ), 0.0 ); //out of range
    1678                 :          1 :   QCOMPARE( l9.xAt( 11 ), 0.0 ); //out of range
    1679                 :            : 
    1680                 :          1 :   l9.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 51.0, 2 ) );
    1681                 :          1 :   QCOMPARE( l9.xAt( 0 ), 51.0 );
    1682                 :          1 :   l9.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 61.0, 12 ) );
    1683                 :          1 :   QCOMPARE( l9.xAt( 1 ), 61.0 );
    1684                 :          1 :   l9.moveVertex( QgsVertexId( 0, 0, -1 ), QgsPoint( 71.0, 2 ) ); //out of range
    1685                 :          1 :   l9.moveVertex( QgsVertexId( 0, 0, 11 ), QgsPoint( 71.0, 2 ) ); //out of range
    1686                 :            : 
    1687                 :          1 :   QCOMPARE( l9.yAt( 0 ), 2.0 );
    1688                 :          1 :   QCOMPARE( l9.yAt( 1 ), 12.0 );
    1689                 :          1 :   QCOMPARE( l9.yAt( 2 ), 22.0 );
    1690                 :          1 :   QCOMPARE( l9.yAt( -1 ), 0.0 ); //out of range
    1691                 :          1 :   QCOMPARE( l9.yAt( 11 ), 0.0 ); //out of range
    1692                 :            : 
    1693                 :          1 :   l9.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 51.0, 52 ) );
    1694                 :          1 :   QCOMPARE( l9.yAt( 0 ), 52.0 );
    1695                 :          1 :   l9.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 61.0, 62 ) );
    1696                 :          1 :   QCOMPARE( l9.yAt( 1 ), 62.0 );
    1697                 :            : 
    1698                 :          1 :   QCOMPARE( l9.pointN( 0 ).z(), 3.0 );
    1699                 :          1 :   QCOMPARE( l9.pointN( 1 ).z(), 13.0 );
    1700                 :          1 :   QCOMPARE( l9.pointN( 2 ).z(), 23.0 );
    1701                 :            : 
    1702                 :          1 :   l9.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 71.0, 2, 53 ) );
    1703                 :          1 :   QCOMPARE( l9.pointN( 0 ).z(), 53.0 );
    1704                 :          1 :   l9.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 71.0, 2, 63 ) );
    1705                 :          1 :   QCOMPARE( l9.pointN( 1 ).z(), 63.0 );
    1706                 :            : 
    1707                 :          1 :   QCOMPARE( l9.pointN( 0 ).m(), 4.0 );
    1708                 :          1 :   QCOMPARE( l9.pointN( 1 ).m(), 14.0 );
    1709                 :          1 :   QCOMPARE( l9.pointN( 2 ).m(), 24.0 );
    1710                 :            : 
    1711                 :          1 :   l9.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 71.0, 2, 53, 54 ) );
    1712                 :          1 :   QCOMPARE( l9.pointN( 0 ).m(), 54.0 );
    1713                 :          1 :   l9.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 71.0, 2, 53, 64 ) );
    1714                 :          1 :   QCOMPARE( l9.pointN( 1 ).m(), 64.0 );
    1715                 :            : 
    1716                 :            :   //check zAt/setZAt with non-3d linestring
    1717                 :          2 :   l9.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 )
    1718                 :          1 :                 << QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 14 )
    1719                 :          1 :                 << QgsPoint( QgsWkbTypes::PointM, 21, 22, 0, 24 ) );
    1720                 :            : 
    1721                 :            :   //basically we just don't want these to crash
    1722                 :          1 :   QVERIFY( std::isnan( l9.pointN( 0 ).z() ) );
    1723                 :          1 :   QVERIFY( std::isnan( l9.pointN( 1 ).z() ) );
    1724                 :          1 :   l9.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 71.0, 2, 53 ) );
    1725                 :          1 :   l9.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 71.0, 2, 63 ) );
    1726                 :            : 
    1727                 :            :   //check mAt/setMAt with non-measure linestring
    1728                 :          2 :   l9.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
    1729                 :          1 :                 << QgsPoint( 11, 12 )
    1730                 :          1 :                 << QgsPoint( 21, 22 ) );
    1731                 :            : 
    1732                 :            :   //basically we just don't want these to crash
    1733                 :          1 :   QVERIFY( std::isnan( l9.pointN( 0 ).m() ) );
    1734                 :          1 :   QVERIFY( std::isnan( l9.pointN( 1 ).m() ) );
    1735                 :          1 :   l9.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 71.0, 2, 0, 53 ) );
    1736                 :          1 :   l9.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 71.0, 2, 0, 63 ) );
    1737                 :            : 
    1738                 :            :   //equality
    1739                 :          1 :   QgsCircularString e1;
    1740                 :          1 :   QgsCircularString e2;
    1741                 :          1 :   QVERIFY( e1 == e2 );
    1742                 :          1 :   QVERIFY( !( e1 != e2 ) );
    1743                 :          1 :   e1.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) );
    1744                 :          1 :   QVERIFY( !( e1 == e2 ) ); //different number of vertices
    1745                 :          1 :   QVERIFY( e1 != e2 );
    1746                 :          1 :   e2.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) );
    1747                 :          1 :   QVERIFY( e1 == e2 );
    1748                 :          1 :   QVERIFY( !( e1 != e2 ) );
    1749                 :          1 :   e1.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 1 / 3.0, 4 / 3.0 ) );
    1750                 :          1 :   e2.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 2 / 6.0, 8 / 6.0 ) );
    1751                 :          1 :   QVERIFY( e1 == e2 ); //check non-integer equality
    1752                 :          1 :   QVERIFY( !( e1 != e2 ) );
    1753                 :          1 :   e1.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 1 / 3.0, 4 / 3.0 ) << QgsPoint( 7, 8 ) );
    1754                 :          1 :   e2.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 2 / 6.0, 8 / 6.0 ) << QgsPoint( 6, 9 ) );
    1755                 :          1 :   QVERIFY( !( e1 == e2 ) ); //different coordinates
    1756                 :          1 :   QVERIFY( e1 != e2 );
    1757                 :          1 :   QgsCircularString e3;
    1758                 :          2 :   e3.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 0 )
    1759                 :          1 :                 << QgsPoint( QgsWkbTypes::PointZ, 1 / 3.0, 4 / 3.0, 0 )
    1760                 :          1 :                 << QgsPoint( QgsWkbTypes::PointZ, 7, 8, 0 ) );
    1761                 :          1 :   QVERIFY( !( e1 == e3 ) ); //different dimension
    1762                 :          1 :   QVERIFY( e1 != e3 );
    1763                 :          1 :   QgsCircularString e4;
    1764                 :          2 :   e4.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 )
    1765                 :          1 :                 << QgsPoint( QgsWkbTypes::PointZ, 1 / 3.0, 4 / 3.0, 3 )
    1766                 :          1 :                 << QgsPoint( QgsWkbTypes::PointZ, 7, 8, 4 ) );
    1767                 :          1 :   QVERIFY( !( e3 == e4 ) ); //different z coordinates
    1768                 :          1 :   QVERIFY( e3 != e4 );
    1769                 :          1 :   QgsCircularString e5;
    1770                 :          2 :   e5.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 1 )
    1771                 :          1 :                 << QgsPoint( QgsWkbTypes::PointM, 1 / 3.0, 4 / 3.0, 0, 2 )
    1772                 :          1 :                 << QgsPoint( QgsWkbTypes::PointM, 7, 8, 0, 3 ) );
    1773                 :          1 :   QgsCircularString e6;
    1774                 :          2 :   e6.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 11 )
    1775                 :          1 :                 << QgsPoint( QgsWkbTypes::PointM, 1 / 3.0, 4 / 3.0, 0, 12 )
    1776                 :          1 :                 << QgsPoint( QgsWkbTypes::PointM, 7, 8, 0, 13 ) );
    1777                 :          1 :   QVERIFY( !( e5 == e6 ) ); //different m values
    1778                 :          1 :   QVERIFY( e5 != e6 );
    1779                 :            : 
    1780                 :          1 :   QVERIFY( e6 != QgsLineString() );
    1781                 :            : 
    1782                 :            :   //isClosed
    1783                 :          1 :   QgsCircularString l11;
    1784                 :          1 :   QVERIFY( !l11.isClosed() );
    1785                 :          2 :   l11.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
    1786                 :          1 :                  << QgsPoint( 11, 2 )
    1787                 :          1 :                  << QgsPoint( 11, 22 )
    1788                 :          1 :                  << QgsPoint( 1, 22 ) );
    1789                 :          1 :   QVERIFY( !l11.isClosed() );
    1790                 :          1 :   QCOMPARE( l11.numPoints(), 4 );
    1791                 :          1 :   QCOMPARE( l11.area(), 0.0 );
    1792                 :          1 :   QCOMPARE( l11.perimeter(), 0.0 );
    1793                 :            : 
    1794                 :            :   //test that m values aren't considered when testing for closedness
    1795                 :          2 :   l11.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 3 )
    1796                 :          1 :                  << QgsPoint( QgsWkbTypes::PointM, 11, 2, 0, 4 )
    1797                 :          1 :                  << QgsPoint( QgsWkbTypes::PointM, 11, 22, 0, 5 )
    1798                 :          1 :                  << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 6 ) );
    1799                 :          1 :   QVERIFY( l11.isClosed() );
    1800                 :            : 
    1801                 :            :   //polygonf
    1802                 :          1 :   QgsCircularString l13;
    1803                 :          2 :   l13.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
    1804                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 2, 11, 14 )
    1805                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 22, 21, 24 ) );
    1806                 :            : 
    1807                 :          1 :   QPolygonF poly = l13.asQPolygonF();
    1808                 :          1 :   QCOMPARE( poly.count(), 181 );
    1809                 :          1 :   QCOMPARE( poly.at( 0 ).x(), 1.0 );
    1810                 :          1 :   QCOMPARE( poly.at( 0 ).y(), 2.0 );
    1811                 :          1 :   QCOMPARE( poly.at( 180 ).x(), 11.0 );
    1812                 :          1 :   QCOMPARE( poly.at( 180 ).y(), 22.0 );
    1813                 :            : 
    1814                 :            :   // clone tests
    1815                 :          1 :   QgsCircularString l14;
    1816                 :          2 :   l14.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
    1817                 :          1 :                  << QgsPoint( 11, 2 )
    1818                 :          1 :                  << QgsPoint( 11, 22 )
    1819                 :          1 :                  << QgsPoint( 1, 22 ) );
    1820                 :          1 :   std::unique_ptr<QgsCircularString> cloned( l14.clone() );
    1821                 :          1 :   QCOMPARE( cloned->numPoints(), 4 );
    1822                 :          1 :   QCOMPARE( cloned->vertexCount(), 4 );
    1823                 :          1 :   QCOMPARE( cloned->ringCount(), 1 );
    1824                 :          1 :   QCOMPARE( cloned->partCount(), 1 );
    1825                 :          1 :   QCOMPARE( cloned->wkbType(), QgsWkbTypes::CircularString );
    1826                 :          1 :   QVERIFY( !cloned->is3D() );
    1827                 :          1 :   QVERIFY( !cloned->isMeasure() );
    1828                 :          1 :   QCOMPARE( cloned->pointN( 0 ), l14.pointN( 0 ) );
    1829                 :          1 :   QCOMPARE( cloned->pointN( 1 ), l14.pointN( 1 ) );
    1830                 :          1 :   QCOMPARE( cloned->pointN( 2 ), l14.pointN( 2 ) );
    1831                 :          1 :   QCOMPARE( cloned->pointN( 3 ), l14.pointN( 3 ) );
    1832                 :            : 
    1833                 :            :   //clone with Z/M
    1834                 :          2 :   l14.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
    1835                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 2, 11, 14 )
    1836                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 22, 21, 24 )
    1837                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 22, 31, 34 ) );
    1838                 :          1 :   cloned.reset( l14.clone() );
    1839                 :          1 :   QCOMPARE( cloned->numPoints(), 4 );
    1840                 :          1 :   QCOMPARE( cloned->wkbType(), QgsWkbTypes::CircularStringZM );
    1841                 :          1 :   QVERIFY( cloned->is3D() );
    1842                 :          1 :   QVERIFY( cloned->isMeasure() );
    1843                 :          1 :   QCOMPARE( cloned->pointN( 0 ), l14.pointN( 0 ) );
    1844                 :          1 :   QCOMPARE( cloned->pointN( 1 ), l14.pointN( 1 ) );
    1845                 :          1 :   QCOMPARE( cloned->pointN( 2 ), l14.pointN( 2 ) );
    1846                 :          1 :   QCOMPARE( cloned->pointN( 3 ), l14.pointN( 3 ) );
    1847                 :            : 
    1848                 :            :   //clone an empty line
    1849                 :          1 :   l14.clear();
    1850                 :          1 :   cloned.reset( l14.clone() );
    1851                 :          1 :   QVERIFY( cloned->isEmpty() );
    1852                 :          1 :   QCOMPARE( cloned->numPoints(), 0 );
    1853                 :          1 :   QVERIFY( !cloned->is3D() );
    1854                 :          1 :   QVERIFY( !cloned->isMeasure() );
    1855                 :          1 :   QCOMPARE( cloned->wkbType(), QgsWkbTypes::CircularString );
    1856                 :            : 
    1857                 :            :   //segmentize tests
    1858                 :          1 :   QgsCircularString toSegment;
    1859                 :          2 :   toSegment.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
    1860                 :          1 :                        << QgsPoint( 11, 10 ) << QgsPoint( 21, 2 ) );
    1861                 :          1 :   std::unique_ptr<QgsLineString> segmentized( static_cast< QgsLineString * >( toSegment.segmentize() ) );
    1862                 :          1 :   QCOMPARE( segmentized->numPoints(), 156 );
    1863                 :          1 :   QCOMPARE( segmentized->vertexCount(), 156 );
    1864                 :          1 :   QCOMPARE( segmentized->ringCount(), 1 );
    1865                 :          1 :   QCOMPARE( segmentized->partCount(), 1 );
    1866                 :          1 :   QCOMPARE( segmentized->wkbType(), QgsWkbTypes::LineString );
    1867                 :          1 :   QVERIFY( !segmentized->is3D() );
    1868                 :          1 :   QVERIFY( !segmentized->isMeasure() );
    1869                 :          1 :   QCOMPARE( segmentized->pointN( 0 ), toSegment.pointN( 0 ) );
    1870                 :          1 :   QCOMPARE( segmentized->pointN( segmentized->numPoints() - 1 ), toSegment.pointN( toSegment.numPoints() - 1 ) );
    1871                 :            : 
    1872                 :            :   //segmentize with Z/M
    1873                 :          2 :   toSegment.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
    1874                 :          1 :                        << QgsPoint( QgsWkbTypes::PointZM, 11, 10, 11, 14 )
    1875                 :          1 :                        << QgsPoint( QgsWkbTypes::PointZM, 21, 2, 21, 24 ) );
    1876                 :          1 :   segmentized.reset( static_cast< QgsLineString * >( toSegment.segmentize() ) );
    1877                 :          1 :   QCOMPARE( segmentized->numPoints(), 156 );
    1878                 :          1 :   QCOMPARE( segmentized->vertexCount(), 156 );
    1879                 :          1 :   QCOMPARE( segmentized->ringCount(), 1 );
    1880                 :          1 :   QCOMPARE( segmentized->partCount(), 1 );
    1881                 :          1 :   QCOMPARE( segmentized->wkbType(), QgsWkbTypes::LineStringZM );
    1882                 :          1 :   QVERIFY( segmentized->is3D() );
    1883                 :          1 :   QVERIFY( segmentized->isMeasure() );
    1884                 :          1 :   QCOMPARE( segmentized->pointN( 0 ), toSegment.pointN( 0 ) );
    1885                 :          1 :   QCOMPARE( segmentized->pointN( segmentized->numPoints() - 1 ), toSegment.pointN( toSegment.numPoints() - 1 ) );
    1886                 :            : 
    1887                 :            :   //segmentize an empty line
    1888                 :          1 :   toSegment.clear();
    1889                 :          1 :   segmentized.reset( static_cast< QgsLineString * >( toSegment.segmentize() ) );
    1890                 :          1 :   QVERIFY( segmentized->isEmpty() );
    1891                 :          1 :   QCOMPARE( segmentized->numPoints(), 0 );
    1892                 :          1 :   QVERIFY( !segmentized->is3D() );
    1893                 :          1 :   QVERIFY( !segmentized->isMeasure() );
    1894                 :          1 :   QCOMPARE( segmentized->wkbType(), QgsWkbTypes::LineString );
    1895                 :            : 
    1896                 :            :   //to/from WKB
    1897                 :          1 :   QgsCircularString l15;
    1898                 :          2 :   l15.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
    1899                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 2, 11, 14 )
    1900                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 22, 21, 24 )
    1901                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 22, 31, 34 ) );
    1902                 :          1 :   QByteArray wkb15 = l15.asWkb();
    1903                 :          1 :   QCOMPARE( wkb15.size(), l15.wkbSize() );
    1904                 :          1 :   QgsCircularString l16;
    1905                 :          1 :   QgsConstWkbPtr wkb15ptr( wkb15 );
    1906                 :          1 :   l16.fromWkb( wkb15ptr );
    1907                 :          1 :   QCOMPARE( l16.numPoints(), 4 );
    1908                 :          1 :   QCOMPARE( l16.vertexCount(), 4 );
    1909                 :          1 :   QCOMPARE( l16.nCoordinates(), 4 );
    1910                 :          1 :   QCOMPARE( l16.ringCount(), 1 );
    1911                 :          1 :   QCOMPARE( l16.partCount(), 1 );
    1912                 :          1 :   QCOMPARE( l16.wkbType(), QgsWkbTypes::CircularStringZM );
    1913                 :          1 :   QVERIFY( l16.is3D() );
    1914                 :          1 :   QVERIFY( l16.isMeasure() );
    1915                 :          1 :   QCOMPARE( l16.pointN( 0 ), l15.pointN( 0 ) );
    1916                 :          1 :   QCOMPARE( l16.pointN( 1 ), l15.pointN( 1 ) );
    1917                 :          1 :   QCOMPARE( l16.pointN( 2 ), l15.pointN( 2 ) );
    1918                 :          1 :   QCOMPARE( l16.pointN( 3 ), l15.pointN( 3 ) );
    1919                 :            : 
    1920                 :            :   //bad WKB - check for no crash
    1921                 :          1 :   l16.clear();
    1922                 :          1 :   QgsConstWkbPtr nullPtr( nullptr, 0 );
    1923                 :          1 :   QVERIFY( !l16.fromWkb( nullPtr ) );
    1924                 :          1 :   QCOMPARE( l16.wkbType(), QgsWkbTypes::CircularString );
    1925                 :          1 :   QgsPoint point( 1, 2 );
    1926                 :          1 :   QByteArray wkb16 = point.asWkb();
    1927                 :          1 :   QgsConstWkbPtr wkb16ptr( wkb16 );
    1928                 :          1 :   QVERIFY( !l16.fromWkb( wkb16ptr ) );
    1929                 :          1 :   QCOMPARE( l16.wkbType(), QgsWkbTypes::CircularString );
    1930                 :            : 
    1931                 :            :   //to/from WKT
    1932                 :          1 :   QgsCircularString l17;
    1933                 :          2 :   l17.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
    1934                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 2, 11, 14 )
    1935                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 22, 21, 24 )
    1936                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 22, 31, 34 ) );
    1937                 :            : 
    1938                 :          1 :   QString wkt = l17.asWkt();
    1939                 :          1 :   QVERIFY( !wkt.isEmpty() );
    1940                 :          1 :   QgsCircularString l18;
    1941                 :          1 :   QVERIFY( l18.fromWkt( wkt ) );
    1942                 :          1 :   QCOMPARE( l18.numPoints(), 4 );
    1943                 :          1 :   QCOMPARE( l18.wkbType(), QgsWkbTypes::CircularStringZM );
    1944                 :          1 :   QVERIFY( l18.is3D() );
    1945                 :          1 :   QVERIFY( l18.isMeasure() );
    1946                 :          1 :   QCOMPARE( l18.pointN( 0 ), l17.pointN( 0 ) );
    1947                 :          1 :   QCOMPARE( l18.pointN( 1 ), l17.pointN( 1 ) );
    1948                 :          1 :   QCOMPARE( l18.pointN( 2 ), l17.pointN( 2 ) );
    1949                 :          1 :   QCOMPARE( l18.pointN( 3 ), l17.pointN( 3 ) );
    1950                 :            : 
    1951                 :            :   //bad WKT
    1952                 :          1 :   QVERIFY( !l18.fromWkt( "Polygon()" ) );
    1953                 :          1 :   QVERIFY( l18.isEmpty() );
    1954                 :          1 :   QCOMPARE( l18.numPoints(), 0 );
    1955                 :          1 :   QVERIFY( !l18.is3D() );
    1956                 :          1 :   QVERIFY( !l18.isMeasure() );
    1957                 :          1 :   QCOMPARE( l18.wkbType(), QgsWkbTypes::CircularString );
    1958                 :            : 
    1959                 :            :   //asGML2
    1960                 :          1 :   QgsCircularString exportLine;
    1961                 :          2 :   exportLine.setPoints( QgsPointSequence() << QgsPoint( 31, 32 )
    1962                 :          1 :                         << QgsPoint( 41, 42 )
    1963                 :          1 :                         << QgsPoint( 51, 52 ) );
    1964                 :          1 :   QgsCircularString exportLineFloat;
    1965                 :          2 :   exportLineFloat.setPoints( QgsPointSequence() << QgsPoint( 1 / 3.0, 2 / 3.0 )
    1966                 :          1 :                              << QgsPoint( 1 + 1 / 3.0, 1 + 2 / 3.0 )
    1967                 :          1 :                              << QgsPoint( 2 + 1 / 3.0, 2 + 2 / 3.0 ) );
    1968                 :          2 :   QDomDocument doc( QStringLiteral( "gml" ) );
    1969                 :          2 :   QString expectedGML2( QStringLiteral( "<LineString xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">31,32 41,42 51,52</coordinates></LineString>" ) );
    1970                 :          3 :   QGSCOMPAREGML( elemToString( exportLine.asGml2( doc ) ), expectedGML2 );
    1971                 :          2 :   QString expectedGML2prec3( QStringLiteral( "<LineString xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">0.333,0.667 1.333,1.667 2.333,2.667</coordinates></LineString>" ) );
    1972                 :          3 :   QGSCOMPAREGML( elemToString( exportLineFloat.asGml2( doc, 3 ) ), expectedGML2prec3 );
    1973                 :          2 :   QString expectedGML2empty( QStringLiteral( "<LineString xmlns=\"gml\"/>" ) );
    1974                 :          3 :   QGSCOMPAREGML( elemToString( QgsCircularString().asGml2( doc ) ), expectedGML2empty );
    1975                 :            : 
    1976                 :            :   //asGML3
    1977                 :          2 :   QString expectedGML3( QStringLiteral( "<Curve xmlns=\"gml\"><segments xmlns=\"gml\"><ArcString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">31 32 41 42 51 52</posList></ArcString></segments></Curve>" ) );
    1978                 :          1 :   QCOMPARE( elemToString( exportLine.asGml3( doc ) ), expectedGML3 );
    1979                 :          2 :   QString expectedGML3prec3( QStringLiteral( "<Curve xmlns=\"gml\"><segments xmlns=\"gml\"><ArcString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">0.333 0.667 1.333 1.667 2.333 2.667</posList></ArcString></segments></Curve>" ) );
    1980                 :          1 :   QCOMPARE( elemToString( exportLineFloat.asGml3( doc, 3 ) ), expectedGML3prec3 );
    1981                 :          2 :   QString expectedGML3empty( QStringLiteral( "<Curve xmlns=\"gml\"/>" ) );
    1982                 :          3 :   QGSCOMPAREGML( elemToString( QgsCircularString().asGml3( doc ) ), expectedGML3empty );
    1983                 :            : 
    1984                 :            :   //asJSON
    1985                 :          2 :   QString expectedJson( QStringLiteral( "{\"coordinates\":[[31.0,32.0],[41.0,42.0],[51.0,52.0]],\"type\":\"LineString\"}" ) );
    1986                 :          1 :   QCOMPARE( exportLine.asJson(), expectedJson );
    1987                 :          2 :   QString expectedJsonPrec3( QStringLiteral( "{\"coordinates\":[[0.333,0.667],[1.333,1.667],[2.333,2.667]],\"type\":\"LineString\"}" ) );
    1988                 :          1 :   QCOMPARE( exportLineFloat.asJson( 3 ), expectedJsonPrec3 );
    1989                 :            : 
    1990                 :            :   //asKML
    1991                 :          2 :   QString expectedKml( QStringLiteral( "<LineString><altitudeMode>clampToGround</altitudeMode><coordinates>31,32,0 41,42,0 51,52,0</coordinates></LineString>" ) );
    1992                 :          1 :   QCOMPARE( exportLine.asKml(), expectedKml );
    1993                 :          2 :   QString expectedKmlPrec3( QStringLiteral( "<LineString><altitudeMode>clampToGround</altitudeMode><coordinates>0.333,0.667,0 1.333,1.667,0 2.333,2.667,0</coordinates></LineString>" ) );
    1994                 :          1 :   QCOMPARE( exportLineFloat.asKml( 3 ), expectedKmlPrec3 );
    1995                 :            : 
    1996                 :            :   //length
    1997                 :          1 :   QgsCircularString l19;
    1998                 :          1 :   QCOMPARE( l19.length(), 0.0 );
    1999                 :          2 :   l19.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 )
    2000                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 10, 4, 5 )
    2001                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 ) );
    2002                 :          1 :   QGSCOMPARENEAR( l19.length(), 26.1433, 0.001 );
    2003                 :            : 
    2004                 :            :   //startPoint
    2005                 :          1 :   QCOMPARE( l19.startPoint(), QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 ) );
    2006                 :            : 
    2007                 :            :   //endPoint
    2008                 :          1 :   QCOMPARE( l19.endPoint(), QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 ) );
    2009                 :            : 
    2010                 :            :   //bad start/end points. Test that this doesn't crash.
    2011                 :          1 :   l19.clear();
    2012                 :          1 :   QVERIFY( l19.startPoint().isEmpty() );
    2013                 :          1 :   QVERIFY( l19.endPoint().isEmpty() );
    2014                 :            : 
    2015                 :            :   //curveToLine - no segmentation required, so should return a clone
    2016                 :          2 :   l19.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 )
    2017                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 10, 4, 5 )
    2018                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 ) );
    2019                 :          1 :   segmentized.reset( l19.curveToLine() );
    2020                 :          1 :   QCOMPARE( segmentized->numPoints(), 181 );
    2021                 :          1 :   QCOMPARE( segmentized->wkbType(), QgsWkbTypes::LineStringZM );
    2022                 :          1 :   QVERIFY( segmentized->is3D() );
    2023                 :          1 :   QVERIFY( segmentized->isMeasure() );
    2024                 :          1 :   QCOMPARE( segmentized->pointN( 0 ), l19.pointN( 0 ) );
    2025                 :          1 :   QCOMPARE( segmentized->pointN( segmentized->numPoints() - 1 ), l19.pointN( l19.numPoints() - 1 ) );
    2026                 :            : 
    2027                 :            :   // points
    2028                 :          1 :   QgsCircularString l20;
    2029                 :          1 :   QgsPointSequence points;
    2030                 :          1 :   l20.points( points );
    2031                 :          1 :   QVERIFY( l20.isEmpty() );
    2032                 :          2 :   l20.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 )
    2033                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 10, 4, 5 )
    2034                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 ) );
    2035                 :          1 :   l20.points( points );
    2036                 :          1 :   QCOMPARE( points.count(), 3 );
    2037                 :          1 :   QCOMPARE( points.at( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 ) );
    2038                 :          1 :   QCOMPARE( points.at( 1 ), QgsPoint( QgsWkbTypes::PointZM, 1, 10, 4, 5 ) );
    2039                 :          1 :   QCOMPARE( points.at( 2 ), QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 ) );
    2040                 :            : 
    2041                 :            :   //CRS transform
    2042                 :          2 :   QgsCoordinateReferenceSystem sourceSrs( QStringLiteral( "EPSG:3994" ) );
    2043                 :          2 :   QgsCoordinateReferenceSystem destSrs( QStringLiteral( "EPSG:4202" ) );// want a transform with ellipsoid change
    2044                 :          1 :   QgsCoordinateTransform tr( sourceSrs, destSrs, QgsProject::instance() );
    2045                 :            : 
    2046                 :            :   // 2d CRS transform
    2047                 :          1 :   QgsCircularString l21;
    2048                 :          2 :   l21.setPoints( QgsPointSequence() << QgsPoint( 6374985, -3626584 )
    2049                 :          1 :                  << QgsPoint( 6474985, -3526584 ) );
    2050                 :          1 :   l21.transform( tr, QgsCoordinateTransform::ForwardTransform );
    2051                 :          1 :   QGSCOMPARENEAR( l21.pointN( 0 ).x(), 175.771, 0.001 );
    2052                 :          1 :   QGSCOMPARENEAR( l21.pointN( 0 ).y(), -39.724, 0.001 );
    2053                 :          1 :   QGSCOMPARENEAR( l21.pointN( 1 ).x(), 176.959, 0.001 );
    2054                 :          1 :   QGSCOMPARENEAR( l21.pointN( 1 ).y(), -38.7999, 0.001 );
    2055                 :          1 :   QGSCOMPARENEAR( l21.boundingBox().xMinimum(), 175.771, 0.001 );
    2056                 :          1 :   QGSCOMPARENEAR( l21.boundingBox().yMinimum(), -39.724, 0.001 );
    2057                 :          1 :   QGSCOMPARENEAR( l21.boundingBox().xMaximum(), 176.959, 0.001 );
    2058                 :          1 :   QGSCOMPARENEAR( l21.boundingBox().yMaximum(), -38.7999, 0.001 );
    2059                 :            : 
    2060                 :            :   //3d CRS transform
    2061                 :          1 :   QgsCircularString l22;
    2062                 :          2 :   l22.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 6374985, -3626584, 1, 2 )
    2063                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 6474985, -3526584, 3, 4 ) );
    2064                 :          1 :   l22.transform( tr, QgsCoordinateTransform::ForwardTransform );
    2065                 :          1 :   QGSCOMPARENEAR( l22.pointN( 0 ).x(), 175.771, 0.001 );
    2066                 :          1 :   QGSCOMPARENEAR( l22.pointN( 0 ).y(), -39.724, 0.001 );
    2067                 :          1 :   QGSCOMPARENEAR( l22.pointN( 0 ).z(), 1.0, 0.001 );
    2068                 :          1 :   QCOMPARE( l22.pointN( 0 ).m(), 2.0 );
    2069                 :          1 :   QGSCOMPARENEAR( l22.pointN( 1 ).x(), 176.959, 0.001 );
    2070                 :          1 :   QGSCOMPARENEAR( l22.pointN( 1 ).y(), -38.7999, 0.001 );
    2071                 :          1 :   QGSCOMPARENEAR( l22.pointN( 1 ).z(), 3.0, 0.001 );
    2072                 :          1 :   QCOMPARE( l22.pointN( 1 ).m(), 4.0 );
    2073                 :            : 
    2074                 :            :   //reverse transform
    2075                 :          1 :   l22.transform( tr, QgsCoordinateTransform::ReverseTransform );
    2076                 :          1 :   QGSCOMPARENEAR( l22.pointN( 0 ).x(), 6374985, 0.01 );
    2077                 :          1 :   QGSCOMPARENEAR( l22.pointN( 0 ).y(), -3626584, 0.01 );
    2078                 :          1 :   QGSCOMPARENEAR( l22.pointN( 0 ).z(), 1, 0.001 );
    2079                 :          1 :   QCOMPARE( l22.pointN( 0 ).m(), 2.0 );
    2080                 :          1 :   QGSCOMPARENEAR( l22.pointN( 1 ).x(), 6474985, 0.01 );
    2081                 :          1 :   QGSCOMPARENEAR( l22.pointN( 1 ).y(), -3526584, 0.01 );
    2082                 :          1 :   QGSCOMPARENEAR( l22.pointN( 1 ).z(), 3, 0.001 );
    2083                 :          1 :   QCOMPARE( l22.pointN( 1 ).m(), 4.0 );
    2084                 :            : 
    2085                 :            : #if PROJ_VERSION_MAJOR<6 // note - z value transform doesn't currently work with proj 6+, because we don't yet support compound CRS definitions
    2086                 :            :   //z value transform
    2087                 :            :   l22.transform( tr, QgsCoordinateTransform::ForwardTransform, true );
    2088                 :            :   QGSCOMPARENEAR( l22.pointN( 0 ).z(), -19.249066, 0.001 );
    2089                 :            :   QGSCOMPARENEAR( l22.pointN( 1 ).z(), -21.092128, 0.001 );
    2090                 :            :   l22.transform( tr, QgsCoordinateTransform::ReverseTransform, true );
    2091                 :            :   QGSCOMPARENEAR( l22.pointN( 0 ).z(), 1.0, 0.001 );
    2092                 :            :   QGSCOMPARENEAR( l22.pointN( 1 ).z(), 3.0, 0.001 );
    2093                 :            : #endif
    2094                 :            : 
    2095                 :            :   //QTransform transform
    2096                 :          1 :   QTransform qtr = QTransform::fromScale( 2, 3 );
    2097                 :          1 :   QgsCircularString l23;
    2098                 :          2 :   l23.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
    2099                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
    2100                 :          1 :   l23.transform( qtr );
    2101                 :          1 :   QCOMPARE( l23.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 2, 6, 3, 4 ) );
    2102                 :          1 :   QCOMPARE( l23.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 22, 36, 13, 14 ) );
    2103                 :          1 :   QCOMPARE( l23.boundingBox(), QgsRectangle( 2, 6, 22, 36 ) );
    2104                 :            : 
    2105                 :          2 :   l23.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
    2106                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
    2107                 :          1 :   l23.transform( QTransform::fromScale( 1, 1 ), 3, 2, 4, 3 );
    2108                 :          1 :   QCOMPARE( l23.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 9, 16 ) );
    2109                 :          1 :   QCOMPARE( l23.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 29, 46 ) );
    2110                 :            : 
    2111                 :            :   //insert vertex
    2112                 :            :   //cannot insert vertex in empty line
    2113                 :          1 :   QgsCircularString l24;
    2114                 :          1 :   QVERIFY( !l24.insertVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    2115                 :          1 :   QCOMPARE( l24.numPoints(), 0 );
    2116                 :            : 
    2117                 :            :   //2d line
    2118                 :          2 :   l24.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
    2119                 :          1 :                  << QgsPoint( 11, 12 ) << QgsPoint( 1, 22 ) );
    2120                 :          1 :   QVERIFY( l24.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 4.0, 7.0 ) ) );
    2121                 :          1 :   QCOMPARE( l24.numPoints(), 5 );
    2122                 :          1 :   QVERIFY( !l24.is3D() );
    2123                 :          1 :   QVERIFY( !l24.isMeasure() );
    2124                 :          1 :   QCOMPARE( l24.wkbType(), QgsWkbTypes::CircularString );
    2125                 :          1 :   QCOMPARE( l24.pointN( 0 ), QgsPoint( 1.0, 2.0 ) );
    2126                 :          1 :   QCOMPARE( l24.pointN( 1 ), QgsPoint( 4.0, 7.0 ) );
    2127                 :          1 :   QGSCOMPARENEAR( l24.pointN( 2 ).x(), 7.192236, 0.01 );
    2128                 :          1 :   QGSCOMPARENEAR( l24.pointN( 2 ).y(), 9.930870, 0.01 );
    2129                 :          1 :   QCOMPARE( l24.pointN( 3 ), QgsPoint( 11.0, 12.0 ) );
    2130                 :          1 :   QCOMPARE( l24.pointN( 4 ), QgsPoint( 1.0, 22.0 ) );
    2131                 :            : 
    2132                 :          1 :   QVERIFY( l24.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 8.0, 9.0 ) ) );
    2133                 :          1 :   QVERIFY( l24.insertVertex( QgsVertexId( 0, 0, 2 ), QgsPoint( 18.0, 16.0 ) ) );
    2134                 :          1 :   QCOMPARE( l24.numPoints(), 9 );
    2135                 :          1 :   QCOMPARE( l24.pointN( 0 ), QgsPoint( 1.0, 2.0 ) );
    2136                 :          1 :   QGSCOMPARENEAR( l24.pointN( 1 ).x(), 4.363083, 0.01 );
    2137                 :          1 :   QGSCOMPARENEAR( l24.pointN( 1 ).y(), 5.636917, 0.01 );
    2138                 :          1 :   QCOMPARE( l24.pointN( 2 ), QgsPoint( 8.0, 9.0 ) );
    2139                 :          1 :   QCOMPARE( l24.pointN( 3 ), QgsPoint( 18.0, 16.0 ) );
    2140                 :          1 :   QGSCOMPARENEAR( l24.pointN( 4 ).x(), 5.876894, 0.01 );
    2141                 :          1 :   QGSCOMPARENEAR( l24.pointN( 4 ).y(), 8.246211, 0.01 );
    2142                 :          1 :   QCOMPARE( l24.pointN( 5 ), QgsPoint( 4.0, 7.0 ) );
    2143                 :          1 :   QGSCOMPARENEAR( l24.pointN( 6 ).x(), 7.192236, 0.01 );
    2144                 :          1 :   QGSCOMPARENEAR( l24.pointN( 6 ).y(), 9.930870, 0.01 );
    2145                 :          1 :   QCOMPARE( l24.pointN( 7 ), QgsPoint( 11.0, 12.0 ) );
    2146                 :          1 :   QCOMPARE( l24.pointN( 8 ), QgsPoint( 1.0, 22.0 ) );
    2147                 :            : 
    2148                 :            :   //insert vertex at end
    2149                 :          1 :   QVERIFY( !l24.insertVertex( QgsVertexId( 0, 0, 9 ), QgsPoint( 31.0, 32.0 ) ) );
    2150                 :            : 
    2151                 :            :   //insert vertex past end
    2152                 :          1 :   QVERIFY( !l24.insertVertex( QgsVertexId( 0, 0, 10 ), QgsPoint( 41.0, 42.0 ) ) );
    2153                 :          1 :   QCOMPARE( l24.numPoints(), 9 );
    2154                 :            : 
    2155                 :            :   //insert vertex before start
    2156                 :          1 :   QVERIFY( !l24.insertVertex( QgsVertexId( 0, 0, -18 ), QgsPoint( 41.0, 42.0 ) ) );
    2157                 :          1 :   QCOMPARE( l24.numPoints(), 9 );
    2158                 :            : 
    2159                 :            :   //insert 4d vertex in 4d line
    2160                 :          2 :   l24.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 )
    2161                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 10, 4, 5 )
    2162                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 ) );
    2163                 :          1 :   QVERIFY( l24.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) ) );
    2164                 :          1 :   QCOMPARE( l24.numPoints(), 5 );
    2165                 :          1 :   QCOMPARE( l24.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
    2166                 :            : 
    2167                 :            :   //insert 2d vertex in 4d line
    2168                 :          1 :   QVERIFY( l24.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 101, 102 ) ) );
    2169                 :          1 :   QCOMPARE( l24.numPoints(), 7 );
    2170                 :          1 :   QCOMPARE( l24.wkbType(), QgsWkbTypes::CircularStringZM );
    2171                 :          1 :   QCOMPARE( l24.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 101, 102 ) );
    2172                 :            : 
    2173                 :            :   //insert 4d vertex in 2d line
    2174                 :          2 :   l24.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
    2175                 :          1 :                  << QgsPoint( 11, 12 ) << QgsPoint( 1, 22 ) );
    2176                 :          1 :   QVERIFY( l24.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( QgsWkbTypes::PointZM, 2, 4, 103, 104 ) ) );
    2177                 :          1 :   QCOMPARE( l24.numPoints(), 5 );
    2178                 :          1 :   QCOMPARE( l24.wkbType(), QgsWkbTypes::CircularString );
    2179                 :          1 :   QCOMPARE( l24.pointN( 1 ), QgsPoint( QgsWkbTypes::Point, 2, 4 ) );
    2180                 :            : 
    2181                 :            :   //move vertex
    2182                 :            : 
    2183                 :            :   //empty line
    2184                 :          1 :   QgsCircularString l25;
    2185                 :          1 :   QVERIFY( !l25.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    2186                 :          1 :   QVERIFY( l25.isEmpty() );
    2187                 :            : 
    2188                 :            :   //valid line
    2189                 :          2 :   l25.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
    2190                 :          1 :                  << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) );
    2191                 :          1 :   QVERIFY( l25.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    2192                 :          1 :   QVERIFY( l25.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 16.0, 17.0 ) ) );
    2193                 :          1 :   QVERIFY( l25.moveVertex( QgsVertexId( 0, 0, 2 ), QgsPoint( 26.0, 27.0 ) ) );
    2194                 :          1 :   QCOMPARE( l25.pointN( 0 ), QgsPoint( 6.0, 7.0 ) );
    2195                 :          1 :   QCOMPARE( l25.pointN( 1 ), QgsPoint( 16.0, 17.0 ) );
    2196                 :          1 :   QCOMPARE( l25.pointN( 2 ), QgsPoint( 26.0, 27.0 ) );
    2197                 :            : 
    2198                 :            :   //out of range
    2199                 :          1 :   QVERIFY( !l25.moveVertex( QgsVertexId( 0, 0, -1 ), QgsPoint( 3.0, 4.0 ) ) );
    2200                 :          1 :   QVERIFY( !l25.moveVertex( QgsVertexId( 0, 0, 10 ), QgsPoint( 3.0, 4.0 ) ) );
    2201                 :          1 :   QCOMPARE( l25.pointN( 0 ), QgsPoint( 6.0, 7.0 ) );
    2202                 :          1 :   QCOMPARE( l25.pointN( 1 ), QgsPoint( 16.0, 17.0 ) );
    2203                 :          1 :   QCOMPARE( l25.pointN( 2 ), QgsPoint( 26.0, 27.0 ) );
    2204                 :            : 
    2205                 :            :   //move 4d point in 4d line
    2206                 :          2 :   l25.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 )
    2207                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 10, 4, 5 )
    2208                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 ) );
    2209                 :          1 :   QVERIFY( l25.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( QgsWkbTypes::PointZM, 6, 7, 12, 13 ) ) );
    2210                 :          1 :   QCOMPARE( l25.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 6, 7, 12, 13 ) );
    2211                 :            : 
    2212                 :            :   //move 2d point in 4d line, existing z/m should be maintained
    2213                 :          1 :   QVERIFY( l25.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 34, 35 ) ) );
    2214                 :          1 :   QCOMPARE( l25.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 34, 35, 12, 13 ) );
    2215                 :            : 
    2216                 :            :   //move 4d point in 2d line
    2217                 :          2 :   l25.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
    2218                 :          1 :                  << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) );
    2219                 :          1 :   QVERIFY( l25.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( QgsWkbTypes::PointZM, 3, 4, 2, 3 ) ) );
    2220                 :          1 :   QCOMPARE( l25.pointN( 0 ), QgsPoint( 3, 4 ) );
    2221                 :            : 
    2222                 :            : 
    2223                 :            :   //delete vertex
    2224                 :            : 
    2225                 :            :   //empty line
    2226                 :          1 :   QgsCircularString l26;
    2227                 :          1 :   QVERIFY( l26.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
    2228                 :          1 :   QVERIFY( l26.isEmpty() );
    2229                 :            : 
    2230                 :            :   //valid line
    2231                 :          2 :   l26.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 )
    2232                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 )
    2233                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 21, 22, 6, 7 )
    2234                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 31, 32, 6, 7 ) );
    2235                 :            :   //out of range vertices
    2236                 :          1 :   QVERIFY( !l26.deleteVertex( QgsVertexId( 0, 0, -1 ) ) );
    2237                 :          1 :   QVERIFY( !l26.deleteVertex( QgsVertexId( 0, 0, 100 ) ) );
    2238                 :            : 
    2239                 :            :   //valid vertices
    2240                 :          1 :   QVERIFY( l26.deleteVertex( QgsVertexId( 0, 0, 1 ) ) );
    2241                 :          1 :   QCOMPARE( l26.numPoints(), 2 );
    2242                 :          1 :   QCOMPARE( l26.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 ) );
    2243                 :          1 :   QCOMPARE( l26.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 31, 32, 6, 7 ) );
    2244                 :            : 
    2245                 :            :   //removing the next vertex removes all remaining vertices
    2246                 :          1 :   QVERIFY( l26.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
    2247                 :          1 :   QCOMPARE( l26.numPoints(), 0 );
    2248                 :          1 :   QVERIFY( l26.isEmpty() );
    2249                 :          1 :   QVERIFY( l26.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
    2250                 :          1 :   QVERIFY( l26.isEmpty() );
    2251                 :            : 
    2252                 :            :   //reversed
    2253                 :          1 :   QgsCircularString l27;
    2254                 :          1 :   std::unique_ptr< QgsCircularString > reversed( l27.reversed() );
    2255                 :          1 :   QVERIFY( reversed->isEmpty() );
    2256                 :          2 :   l27.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 )
    2257                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 )
    2258                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 21, 22, 6, 7 ) );
    2259                 :          1 :   reversed.reset( l27.reversed() );
    2260                 :          1 :   QCOMPARE( reversed->numPoints(), 3 );
    2261                 :          1 :   QCOMPARE( reversed->wkbType(), QgsWkbTypes::CircularStringZM );
    2262                 :          1 :   QVERIFY( reversed->is3D() );
    2263                 :          1 :   QVERIFY( reversed->isMeasure() );
    2264                 :          1 :   QCOMPARE( reversed->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 21, 22, 6, 7 ) );
    2265                 :          1 :   QCOMPARE( reversed->pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 ) );
    2266                 :          1 :   QCOMPARE( reversed->pointN( 2 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 ) );
    2267                 :            : 
    2268                 :            :   //addZValue
    2269                 :            : 
    2270                 :          1 :   QgsCircularString l28;
    2271                 :          1 :   QCOMPARE( l28.wkbType(), QgsWkbTypes::CircularString );
    2272                 :          1 :   QVERIFY( l28.addZValue() );
    2273                 :          1 :   QCOMPARE( l28.wkbType(), QgsWkbTypes::CircularStringZ );
    2274                 :          1 :   l28.clear();
    2275                 :          1 :   QVERIFY( l28.addZValue() );
    2276                 :          1 :   QCOMPARE( l28.wkbType(), QgsWkbTypes::CircularStringZ );
    2277                 :            :   //2d line
    2278                 :          1 :   l28.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
    2279                 :          1 :   QVERIFY( l28.addZValue( 2 ) );
    2280                 :          1 :   QVERIFY( l28.is3D() );
    2281                 :          1 :   QCOMPARE( l28.wkbType(), QgsWkbTypes::CircularStringZ );
    2282                 :          1 :   QCOMPARE( l28.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ) );
    2283                 :          1 :   QCOMPARE( l28.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZ, 11, 12, 2 ) );
    2284                 :          1 :   QVERIFY( !l28.addZValue( 4 ) ); //already has z value, test that existing z is unchanged
    2285                 :          1 :   QCOMPARE( l28.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ) );
    2286                 :          1 :   QCOMPARE( l28.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZ, 11, 12, 2 ) );
    2287                 :            :   //linestring with m
    2288                 :          1 :   l28.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 3 ) << QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 4 ) );
    2289                 :          1 :   QVERIFY( l28.addZValue( 5 ) );
    2290                 :          1 :   QVERIFY( l28.is3D() );
    2291                 :          1 :   QVERIFY( l28.isMeasure() );
    2292                 :          1 :   QCOMPARE( l28.wkbType(), QgsWkbTypes::CircularStringZM );
    2293                 :          1 :   QCOMPARE( l28.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 5, 3 ) );
    2294                 :          1 :   QCOMPARE( l28.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 5, 4 ) );
    2295                 :            : 
    2296                 :            :   //addMValue
    2297                 :            : 
    2298                 :          1 :   QgsCircularString l29;
    2299                 :          1 :   QCOMPARE( l29.wkbType(), QgsWkbTypes::CircularString );
    2300                 :          1 :   QVERIFY( l29.addMValue() );
    2301                 :          1 :   QCOMPARE( l29.wkbType(), QgsWkbTypes::CircularStringM );
    2302                 :          1 :   l29.clear();
    2303                 :          1 :   QVERIFY( l29.addMValue() );
    2304                 :          1 :   QCOMPARE( l29.wkbType(), QgsWkbTypes::CircularStringM );
    2305                 :            :   //2d line
    2306                 :          1 :   l29.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
    2307                 :          1 :   QVERIFY( l29.addMValue( 2 ) );
    2308                 :          1 :   QVERIFY( !l29.is3D() );
    2309                 :          1 :   QVERIFY( l29.isMeasure() );
    2310                 :          1 :   QCOMPARE( l29.wkbType(), QgsWkbTypes::CircularStringM );
    2311                 :          1 :   QCOMPARE( l29.pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 2 ) );
    2312                 :          1 :   QCOMPARE( l29.pointN( 1 ), QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 2 ) );
    2313                 :          1 :   QVERIFY( !l29.addMValue( 4 ) ); //already has m value, test that existing m is unchanged
    2314                 :          1 :   QCOMPARE( l29.pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 2 ) );
    2315                 :          1 :   QCOMPARE( l29.pointN( 1 ), QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 2 ) );
    2316                 :            :   //linestring with z
    2317                 :          1 :   l29.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 11, 12, 4 ) );
    2318                 :          1 :   QVERIFY( l29.addMValue( 5 ) );
    2319                 :          1 :   QVERIFY( l29.is3D() );
    2320                 :          1 :   QVERIFY( l29.isMeasure() );
    2321                 :          1 :   QCOMPARE( l29.wkbType(), QgsWkbTypes::CircularStringZM );
    2322                 :          1 :   QCOMPARE( l29.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 5 ) );
    2323                 :          1 :   QCOMPARE( l29.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 ) );
    2324                 :            : 
    2325                 :            :   //dropZValue
    2326                 :          1 :   QgsCircularString l28d;
    2327                 :          1 :   QVERIFY( !l28d.dropZValue() );
    2328                 :          1 :   l28d.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
    2329                 :          1 :   QVERIFY( !l28d.dropZValue() );
    2330                 :          1 :   l28d.addZValue( 1.0 );
    2331                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::CircularStringZ );
    2332                 :          1 :   QVERIFY( l28d.is3D() );
    2333                 :          1 :   QVERIFY( l28d.dropZValue() );
    2334                 :          1 :   QVERIFY( !l28d.is3D() );
    2335                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::CircularString );
    2336                 :          1 :   QCOMPARE( l28d.pointN( 0 ), QgsPoint( QgsWkbTypes::Point, 1, 2 ) );
    2337                 :          1 :   QCOMPARE( l28d.pointN( 1 ), QgsPoint( QgsWkbTypes::Point, 11, 12 ) );
    2338                 :          1 :   QVERIFY( !l28d.dropZValue() ); //already dropped
    2339                 :            :   //linestring with m
    2340                 :          1 :   l28d.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 3, 4 ) );
    2341                 :          1 :   QVERIFY( l28d.dropZValue() );
    2342                 :          1 :   QVERIFY( !l28d.is3D() );
    2343                 :          1 :   QVERIFY( l28d.isMeasure() );
    2344                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::CircularStringM );
    2345                 :          1 :   QCOMPARE( l28d.pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) );
    2346                 :          1 :   QCOMPARE( l28d.pointN( 1 ), QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 4 ) );
    2347                 :            : 
    2348                 :            :   //dropMValue
    2349                 :          1 :   l28d.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
    2350                 :          1 :   QVERIFY( !l28d.dropMValue() );
    2351                 :          1 :   l28d.addMValue( 1.0 );
    2352                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::CircularStringM );
    2353                 :          1 :   QVERIFY( l28d.isMeasure() );
    2354                 :          1 :   QVERIFY( l28d.dropMValue() );
    2355                 :          1 :   QVERIFY( !l28d.isMeasure() );
    2356                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::CircularString );
    2357                 :          1 :   QCOMPARE( l28d.pointN( 0 ), QgsPoint( QgsWkbTypes::Point, 1, 2 ) );
    2358                 :          1 :   QCOMPARE( l28d.pointN( 1 ), QgsPoint( QgsWkbTypes::Point, 11, 12 ) );
    2359                 :          1 :   QVERIFY( !l28d.dropMValue() ); //already dropped
    2360                 :            :   //linestring with z
    2361                 :          1 :   l28d.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 3, 4 ) );
    2362                 :          1 :   QVERIFY( l28d.dropMValue() );
    2363                 :          1 :   QVERIFY( !l28d.isMeasure() );
    2364                 :          1 :   QVERIFY( l28d.is3D() );
    2365                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::CircularStringZ );
    2366                 :          1 :   QCOMPARE( l28d.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3, 0 ) );
    2367                 :          1 :   QCOMPARE( l28d.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZ, 11, 12, 3, 0 ) );
    2368                 :            : 
    2369                 :            :   //convertTo
    2370                 :          1 :   l28d.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
    2371                 :          1 :   QVERIFY( l28d.convertTo( QgsWkbTypes::CircularString ) );
    2372                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::CircularString );
    2373                 :          1 :   QVERIFY( l28d.convertTo( QgsWkbTypes::CircularStringZ ) );
    2374                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::CircularStringZ );
    2375                 :          1 :   QCOMPARE( l28d.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2 ) );
    2376                 :            : 
    2377                 :          1 :   QVERIFY( l28d.convertTo( QgsWkbTypes::CircularStringZM ) );
    2378                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::CircularStringZM );
    2379                 :          1 :   QCOMPARE( l28d.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2 ) );
    2380                 :          1 :   l28d.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 1, 2, 5 ) );
    2381                 :          1 :   QCOMPARE( l28d.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 5.0 ) );
    2382                 :            :   //l28d.setMAt( 0, 6.0 );
    2383                 :          1 :   QVERIFY( l28d.convertTo( QgsWkbTypes::CircularStringM ) );
    2384                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::CircularStringM );
    2385                 :          1 :   QCOMPARE( l28d.pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 1, 2 ) );
    2386                 :          1 :   l28d.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 1, 2, 0, 6 ) );
    2387                 :          1 :   QCOMPARE( l28d.pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 1, 2, 0.0, 6.0 ) );
    2388                 :          1 :   QVERIFY( l28d.convertTo( QgsWkbTypes::CircularString ) );
    2389                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::CircularString );
    2390                 :          1 :   QCOMPARE( l28d.pointN( 0 ), QgsPoint( 1, 2 ) );
    2391                 :          1 :   QVERIFY( !l28d.convertTo( QgsWkbTypes::Polygon ) );
    2392                 :            : 
    2393                 :            :   //isRing
    2394                 :          1 :   QgsCircularString l30;
    2395                 :          1 :   QVERIFY( !l30.isRing() );
    2396                 :          1 :   l30.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 2 ) );
    2397                 :          1 :   QVERIFY( !l30.isRing() ); //<4 points
    2398                 :          1 :   l30.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) << QgsPoint( 31, 32 ) );
    2399                 :          1 :   QVERIFY( !l30.isRing() ); //not closed
    2400                 :          1 :   l30.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) << QgsPoint( 1, 2 ) );
    2401                 :          1 :   QVERIFY( l30.isRing() );
    2402                 :            : 
    2403                 :            :   //coordinateSequence
    2404                 :          1 :   QgsCircularString l31;
    2405                 :          1 :   QgsCoordinateSequence coords = l31.coordinateSequence();
    2406                 :          1 :   QCOMPARE( coords.count(), 1 );
    2407                 :          1 :   QCOMPARE( coords.at( 0 ).count(), 1 );
    2408                 :          1 :   QVERIFY( coords.at( 0 ).at( 0 ).isEmpty() );
    2409                 :          2 :   l31.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 )
    2410                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 )
    2411                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 21, 22, 6, 7 ) );
    2412                 :          1 :   coords = l31.coordinateSequence();
    2413                 :          1 :   QCOMPARE( coords.count(), 1 );
    2414                 :          1 :   QCOMPARE( coords.at( 0 ).count(), 1 );
    2415                 :          1 :   QCOMPARE( coords.at( 0 ).at( 0 ).count(), 3 );
    2416                 :          1 :   QCOMPARE( coords.at( 0 ).at( 0 ).at( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 ) );
    2417                 :          1 :   QCOMPARE( coords.at( 0 ).at( 0 ).at( 1 ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 ) );
    2418                 :          1 :   QCOMPARE( coords.at( 0 ).at( 0 ).at( 2 ), QgsPoint( QgsWkbTypes::PointZM, 21, 22, 6, 7 ) );
    2419                 :            : 
    2420                 :            :   //nextVertex
    2421                 :            : 
    2422                 :          1 :   QgsCircularString l32;
    2423                 :          1 :   QgsVertexId v;
    2424                 :          1 :   QgsPoint p;
    2425                 :          1 :   QVERIFY( !l32.nextVertex( v, p ) );
    2426                 :          1 :   v = QgsVertexId( 0, 0, -2 );
    2427                 :          1 :   QVERIFY( !l32.nextVertex( v, p ) );
    2428                 :          1 :   v = QgsVertexId( 0, 0, 10 );
    2429                 :          1 :   QVERIFY( !l32.nextVertex( v, p ) );
    2430                 :            : 
    2431                 :            :   //CircularString
    2432                 :          1 :   l32.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
    2433                 :          1 :   v = QgsVertexId( 0, 0, 2 ); //out of range
    2434                 :          1 :   QVERIFY( !l32.nextVertex( v, p ) );
    2435                 :          1 :   v = QgsVertexId( 0, 0, -5 );
    2436                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    2437                 :          1 :   v = QgsVertexId( 0, 0, -1 );
    2438                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    2439                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 0 ) );
    2440                 :          1 :   QCOMPARE( p, QgsPoint( 1, 2 ) );
    2441                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    2442                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    2443                 :          1 :   QCOMPARE( p, QgsPoint( 11, 12 ) );
    2444                 :          1 :   QVERIFY( !l32.nextVertex( v, p ) );
    2445                 :          1 :   v = QgsVertexId( 0, 1, 0 );
    2446                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    2447                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 1, 1 ) ); //test that ring number is maintained
    2448                 :          1 :   QCOMPARE( p, QgsPoint( 11, 12 ) );
    2449                 :          1 :   v = QgsVertexId( 1, 0, 0 );
    2450                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    2451                 :          1 :   QCOMPARE( v, QgsVertexId( 1, 0, 1 ) ); //test that part number is maintained
    2452                 :          1 :   QCOMPARE( p, QgsPoint( 11, 12 ) );
    2453                 :            : 
    2454                 :            :   //CircularStringZ
    2455                 :          1 :   l32.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 ) );
    2456                 :          1 :   v = QgsVertexId( 0, 0, -1 );
    2457                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    2458                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 0 ) );
    2459                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) );
    2460                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    2461                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    2462                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 ) );
    2463                 :          1 :   QVERIFY( !l32.nextVertex( v, p ) );
    2464                 :            :   //CircularStringM
    2465                 :          1 :   l32.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 14 ) );
    2466                 :          1 :   v = QgsVertexId( 0, 0, -1 );
    2467                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    2468                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 0 ) );
    2469                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) );
    2470                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    2471                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    2472                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 14 ) );
    2473                 :          1 :   QVERIFY( !l32.nextVertex( v, p ) );
    2474                 :            :   //CircularStringZM
    2475                 :          1 :   l32.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
    2476                 :          1 :   v = QgsVertexId( 0, 0, -1 );
    2477                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    2478                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 0 ) );
    2479                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) );
    2480                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    2481                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    2482                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
    2483                 :          1 :   QVERIFY( !l32.nextVertex( v, p ) );
    2484                 :            : 
    2485                 :            :   //vertexAt and pointAt
    2486                 :          1 :   QgsCircularString l33;
    2487                 :          1 :   l33.vertexAt( QgsVertexId( 0, 0, -10 ) ); //out of bounds, check for no crash
    2488                 :          1 :   l33.vertexAt( QgsVertexId( 0, 0, 10 ) ); //out of bounds, check for no crash
    2489                 :            :   QgsVertexId::VertexType type;
    2490                 :          1 :   QVERIFY( !l33.pointAt( -10, p, type ) );
    2491                 :          1 :   QVERIFY( !l33.pointAt( 10, p, type ) );
    2492                 :            :   //CircularString
    2493                 :          1 :   l33.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 22 ) );
    2494                 :          1 :   l33.vertexAt( QgsVertexId( 0, 0, -10 ) );
    2495                 :          1 :   l33.vertexAt( QgsVertexId( 0, 0, 10 ) ); //out of bounds, check for no crash
    2496                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( 1, 2 ) );
    2497                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( 11, 12 ) );
    2498                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( 1, 22 ) );
    2499                 :          1 :   QVERIFY( !l33.pointAt( -10, p, type ) );
    2500                 :          1 :   QVERIFY( !l33.pointAt( 10, p, type ) );
    2501                 :          1 :   QVERIFY( l33.pointAt( 0, p, type ) );
    2502                 :          1 :   QCOMPARE( p, QgsPoint( 1, 2 ) );
    2503                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
    2504                 :          1 :   QVERIFY( l33.pointAt( 1, p, type ) );
    2505                 :          1 :   QCOMPARE( p, QgsPoint( 11, 12 ) );
    2506                 :          1 :   QCOMPARE( type, QgsVertexId::CurveVertex );
    2507                 :          1 :   QVERIFY( l33.pointAt( 2, p, type ) );
    2508                 :          1 :   QCOMPARE( p, QgsPoint( 1, 22 ) );
    2509                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
    2510                 :            :   //CircularStringZ
    2511                 :          1 :   l33.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 )  << QgsPoint( QgsWkbTypes::PointZ, 1, 22, 23 ) );
    2512                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) );
    2513                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 ) );
    2514                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( QgsWkbTypes::PointZ, 1, 22, 23 ) );
    2515                 :          1 :   QVERIFY( l33.pointAt( 0, p, type ) );
    2516                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) );
    2517                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
    2518                 :          1 :   QVERIFY( l33.pointAt( 1, p, type ) );
    2519                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 ) );
    2520                 :          1 :   QCOMPARE( type, QgsVertexId::CurveVertex );
    2521                 :          1 :   QVERIFY( l33.pointAt( 2, p, type ) );
    2522                 :          1 :   QCOMPARE( p, QgsPoint( 1, 22, 23 ) );
    2523                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
    2524                 :            :   //CircularStringM
    2525                 :          1 :   l33.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 14 ) << QgsPoint( QgsWkbTypes::PointM, 1, 22, 0, 24 ) );
    2526                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) );
    2527                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 14 ) );
    2528                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( QgsWkbTypes::PointM, 1, 22, 0, 24 ) );
    2529                 :          1 :   QVERIFY( l33.pointAt( 0, p, type ) );
    2530                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) );
    2531                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
    2532                 :          1 :   QVERIFY( l33.pointAt( 1, p, type ) );
    2533                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 14 ) );
    2534                 :          1 :   QCOMPARE( type, QgsVertexId::CurveVertex );
    2535                 :          1 :   QVERIFY( l33.pointAt( 2, p, type ) );
    2536                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointM, 1, 22, 0, 24 ) );
    2537                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
    2538                 :            :   //CircularStringZM
    2539                 :          1 :   l33.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) << QgsPoint( QgsWkbTypes::PointZM, 1, 22, 23, 24 ) );
    2540                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) );
    2541                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
    2542                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( QgsWkbTypes::PointZM, 1, 22, 23, 24 ) );
    2543                 :          1 :   QVERIFY( l33.pointAt( 0, p, type ) );
    2544                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) );
    2545                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
    2546                 :          1 :   QVERIFY( l33.pointAt( 1, p, type ) );
    2547                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
    2548                 :          1 :   QCOMPARE( type, QgsVertexId::CurveVertex );
    2549                 :          1 :   QVERIFY( l33.pointAt( 2, p, type ) );
    2550                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZM, 1, 22, 23, 24 ) );
    2551                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
    2552                 :            : 
    2553                 :            :   //centroid
    2554                 :          1 :   QgsCircularString l34;
    2555                 :          1 :   QCOMPARE( l34.centroid(), QgsPoint( 0, 0 ) );
    2556                 :          1 :   l34.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) );
    2557                 :          1 :   QCOMPARE( l34.centroid(), QgsPoint( 5, 10 ) );
    2558                 :          1 :   l34.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 20, 10 ) << QgsPoint( 2, 9 ) );
    2559                 :          1 :   QgsPoint centroid = l34.centroid();
    2560                 :          1 :   QGSCOMPARENEAR( centroid.x(), 7.333, 0.001 );
    2561                 :          1 :   QGSCOMPARENEAR( centroid.y(), 6.333, 0.001 );
    2562                 :            : 
    2563                 :            :   //closest segment
    2564                 :          1 :   QgsCircularString l35;
    2565                 :          1 :   int leftOf = 0;
    2566                 :          1 :   p = QgsPoint( 0, 0 ); // reset all coords to zero
    2567                 :          1 :   ( void )l35.closestSegment( QgsPoint( 1, 2 ), p, v ); //empty line, just want no crash
    2568                 :          1 :   l35.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) );
    2569                 :          1 :   QVERIFY( l35.closestSegment( QgsPoint( 5, 10 ), p, v ) < 0 );
    2570                 :          1 :   l35.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) << QgsPoint( 7, 12 ) << QgsPoint( 5, 15 ) );
    2571                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 4, 11 ), p, v, &leftOf ), 2.0, 0.0001 );
    2572                 :          1 :   QCOMPARE( p, QgsPoint( 5, 10 ) );
    2573                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    2574                 :          1 :   QCOMPARE( leftOf, -1 );
    2575                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 8, 11 ), p, v, &leftOf ),  1.583512, 0.0001 );
    2576                 :          1 :   QGSCOMPARENEAR( p.x(), 6.84, 0.01 );
    2577                 :          1 :   QGSCOMPARENEAR( p.y(), 11.49, 0.01 );
    2578                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    2579                 :          1 :   QCOMPARE( leftOf, 1 );
    2580                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 5.5, 11.5 ), p, v, &leftOf ), 1.288897, 0.0001 );
    2581                 :          1 :   QGSCOMPARENEAR( p.x(), 6.302776, 0.01 );
    2582                 :          1 :   QGSCOMPARENEAR( p.y(), 10.7, 0.01 );
    2583                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    2584                 :          1 :   QCOMPARE( leftOf, -1 );
    2585                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 7, 16 ), p, v, &leftOf ), 3.068288, 0.0001 );
    2586                 :          1 :   QGSCOMPARENEAR( p.x(), 5.981872, 0.01 );
    2587                 :          1 :   QGSCOMPARENEAR( p.y(), 14.574621, 0.01 );
    2588                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    2589                 :          1 :   QCOMPARE( leftOf, 1 );
    2590                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 5.5, 13.5 ), p, v, &leftOf ), 1.288897, 0.0001 );
    2591                 :          1 :   QGSCOMPARENEAR( p.x(), 6.302776, 0.01 );
    2592                 :          1 :   QGSCOMPARENEAR( p.y(), 14.3, 0.01 );
    2593                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    2594                 :          1 :   QCOMPARE( leftOf, -1 );
    2595                 :            :   // point directly on segment
    2596                 :          1 :   QCOMPARE( l35.closestSegment( QgsPoint( 5, 15 ), p, v, &leftOf ), 0.0 );
    2597                 :          1 :   QCOMPARE( p, QgsPoint( 5, 15 ) );
    2598                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    2599                 :          1 :   QCOMPARE( leftOf, 0 );
    2600                 :            : 
    2601                 :            :   //clockwise string
    2602                 :          1 :   l35.setPoints( QgsPointSequence() << QgsPoint( 5, 15 ) << QgsPoint( 7, 12 ) << QgsPoint( 5, 10 ) );
    2603                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 4, 11 ), p, v, &leftOf ), 2, 0.0001 );
    2604                 :          1 :   QGSCOMPARENEAR( p.x(), 5, 0.01 );
    2605                 :          1 :   QGSCOMPARENEAR( p.y(), 10, 0.01 );
    2606                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    2607                 :          1 :   QCOMPARE( leftOf, 1 );
    2608                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 8, 11 ), p, v, &leftOf ),  1.583512, 0.0001 );
    2609                 :          1 :   QGSCOMPARENEAR( p.x(), 6.84, 0.01 );
    2610                 :          1 :   QGSCOMPARENEAR( p.y(), 11.49, 0.01 );
    2611                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    2612                 :          1 :   QCOMPARE( leftOf, -1 );
    2613                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 5.5, 11.5 ), p, v, &leftOf ), 1.288897, 0.0001 );
    2614                 :          1 :   QGSCOMPARENEAR( p.x(), 6.302776, 0.01 );
    2615                 :          1 :   QGSCOMPARENEAR( p.y(), 10.7, 0.01 );
    2616                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    2617                 :          1 :   QCOMPARE( leftOf, 1 );
    2618                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 7, 16 ), p, v, &leftOf ), 3.068288, 0.0001 );
    2619                 :          1 :   QGSCOMPARENEAR( p.x(), 5.981872, 0.01 );
    2620                 :          1 :   QGSCOMPARENEAR( p.y(), 14.574621, 0.01 );
    2621                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    2622                 :          1 :   QCOMPARE( leftOf, -1 );
    2623                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 5.5, 13.5 ), p, v, &leftOf ), 1.288897, 0.0001 );
    2624                 :          1 :   QGSCOMPARENEAR( p.x(), 6.302776, 0.01 );
    2625                 :          1 :   QGSCOMPARENEAR( p.y(), 14.3, 0.01 );
    2626                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    2627                 :          1 :   QCOMPARE( leftOf, 1 );
    2628                 :            :   // point directly on segment
    2629                 :          1 :   QCOMPARE( l35.closestSegment( QgsPoint( 5, 15 ), p, v, &leftOf ), 0.0 );
    2630                 :          1 :   QCOMPARE( p, QgsPoint( 5, 15 ) );
    2631                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    2632                 :          1 :   QCOMPARE( leftOf, 0 );
    2633                 :            : 
    2634                 :            :   //sumUpArea
    2635                 :          1 :   QgsCircularString l36;
    2636                 :          1 :   double area = 1.0; //sumUpArea adds to area, so start with non-zero value
    2637                 :          1 :   l36.sumUpArea( area );
    2638                 :          1 :   QCOMPARE( area, 1.0 );
    2639                 :          1 :   l36.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) );
    2640                 :          1 :   l36.sumUpArea( area );
    2641                 :          1 :   QCOMPARE( area, 1.0 );
    2642                 :          1 :   l36.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) << QgsPoint( 10, 10 ) );
    2643                 :          1 :   l36.sumUpArea( area );
    2644                 :          1 :   QCOMPARE( area, 1.0 );
    2645                 :          1 :   l36.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 2, 0 ) << QgsPoint( 2, 2 ) );
    2646                 :          1 :   l36.sumUpArea( area );
    2647                 :          1 :   QGSCOMPARENEAR( area, 4.141593, 0.0001 );
    2648                 :          1 :   l36.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 2, 0 ) << QgsPoint( 2, 2 ) << QgsPoint( 0, 2 ) );
    2649                 :          1 :   l36.sumUpArea( area );
    2650                 :          1 :   QGSCOMPARENEAR( area, 7.283185, 0.0001 );
    2651                 :            :   // full circle
    2652                 :          1 :   l36.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 4, 0 ) << QgsPoint( 0, 0 ) );
    2653                 :          1 :   area = 0.0;
    2654                 :          1 :   l36.sumUpArea( area );
    2655                 :          1 :   QGSCOMPARENEAR( area, 12.566370614359172, 0.0001 );
    2656                 :            : 
    2657                 :            :   //boundingBox - test that bounding box is updated after every modification to the circular string
    2658                 :          1 :   QgsCircularString l37;
    2659                 :          1 :   QVERIFY( l37.boundingBox().isNull() );
    2660                 :          1 :   l37.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) << QgsPoint( 10, 15 ) );
    2661                 :          1 :   QCOMPARE( l37.boundingBox(), QgsRectangle( 5, 10, 10, 15 ) );
    2662                 :          1 :   l37.setPoints( QgsPointSequence() << QgsPoint( -5, -10 ) << QgsPoint( -6, -10 ) << QgsPoint( -5.5, -9 ) );
    2663                 :          1 :   QCOMPARE( l37.boundingBox(), QgsRectangle( -6.125, -10.25, -5, -9 ) );
    2664                 :          1 :   QByteArray wkbToAppend = l37.asWkb();
    2665                 :          1 :   l37.clear();
    2666                 :          1 :   QVERIFY( l37.boundingBox().isNull() );
    2667                 :          1 :   QgsConstWkbPtr wkbToAppendPtr( wkbToAppend );
    2668                 :          1 :   l37.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) << QgsPoint( 10, 15 ) );
    2669                 :          1 :   QCOMPARE( l37.boundingBox(), QgsRectangle( 5, 10, 10, 15 ) );
    2670                 :          1 :   l37.fromWkb( wkbToAppendPtr );
    2671                 :          1 :   QCOMPARE( l37.boundingBox(), QgsRectangle( -6.125, -10.25, -5, -9 ) );
    2672                 :          2 :   l37.fromWkt( QStringLiteral( "CircularString( 5 10, 6 10, 5.5 9 )" ) );
    2673                 :          1 :   QCOMPARE( l37.boundingBox(), QgsRectangle( 5, 9, 6.125, 10.25 ) );
    2674                 :          1 :   l37.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( -1, 7 ) );
    2675                 :          1 :   QgsRectangle r = l37.boundingBox();
    2676                 :          1 :   QGSCOMPARENEAR( r.xMinimum(), -3.014, 0.01 );
    2677                 :          1 :   QGSCOMPARENEAR( r.xMaximum(), 14.014, 0.01 );
    2678                 :          1 :   QGSCOMPARENEAR( r.yMinimum(), -7.0146, 0.01 );
    2679                 :          1 :   QGSCOMPARENEAR( r.yMaximum(), 12.4988, 0.01 );
    2680                 :          1 :   l37.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( -3, 10 ) );
    2681                 :          1 :   r = l37.boundingBox();
    2682                 :          1 :   QGSCOMPARENEAR( r.xMinimum(), -10.294, 0.01 );
    2683                 :          1 :   QGSCOMPARENEAR( r.xMaximum(), 12.294, 0.01 );
    2684                 :          1 :   QGSCOMPARENEAR( r.yMinimum(), 9, 0.01 );
    2685                 :          1 :   QGSCOMPARENEAR( r.yMaximum(), 31.856, 0.01 );
    2686                 :          1 :   l37.deleteVertex( QgsVertexId( 0, 0, 1 ) );
    2687                 :          1 :   r = l37.boundingBox();
    2688                 :          1 :   QGSCOMPARENEAR( r.xMinimum(), 5, 0.01 );
    2689                 :          1 :   QGSCOMPARENEAR( r.xMaximum(), 6.125, 0.01 );
    2690                 :          1 :   QGSCOMPARENEAR( r.yMinimum(), 9, 0.01 );
    2691                 :          1 :   QGSCOMPARENEAR( r.yMaximum(), 10.25, 0.01 );
    2692                 :            : 
    2693                 :            :   //angle
    2694                 :          1 :   QgsCircularString l38;
    2695                 :          1 :   ( void )l38.vertexAngle( QgsVertexId() ); //just want no crash
    2696                 :          1 :   ( void )l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ); //just want no crash
    2697                 :          1 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) );
    2698                 :          1 :   ( void )l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ); //just want no crash, any answer is meaningless
    2699                 :          1 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) );
    2700                 :          1 :   ( void )l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ); //just want no crash, any answer is meaningless
    2701                 :          1 :   ( void )l38.vertexAngle( QgsVertexId( 0, 0, 1 ) ); //just want no crash, any answer is meaningless
    2702                 :          1 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 1 ) << QgsPoint( 0, 2 ) );
    2703                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 1.5708, 0.0001 );
    2704                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 0, 0.0001 );
    2705                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 2 ) ), 4.712389, 0.0001 );
    2706                 :          1 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 2 ) << QgsPoint( 1, 1 ) << QgsPoint( 0, 0 ) );
    2707                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 1.5708, 0.0001 );
    2708                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 3.141593, 0.0001 );
    2709                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 2 ) ), 4.712389, 0.0001 );
    2710                 :          1 :   ( void )l38.vertexAngle( QgsVertexId( 0, 0, 20 ) ); // no crash
    2711                 :          2 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 1 ) << QgsPoint( 0, 2 )
    2712                 :          1 :                  << QgsPoint( -1, 3 ) << QgsPoint( 0, 4 ) );
    2713                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 1.5708, 0.0001 );
    2714                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 0, 0.0001 );
    2715                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 2 ) ), 4.712389, 0.0001 );
    2716                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 3 ) ), 0, 0.0001 );
    2717                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 4 ) ), 1.5708, 0.0001 );
    2718                 :          2 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 4 ) << QgsPoint( -1, 3 ) << QgsPoint( 0, 2 )
    2719                 :          1 :                  << QgsPoint( 1, 1 ) << QgsPoint( 0, 0 ) );
    2720                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 4.712389, 0.0001 );
    2721                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 3.141592, 0.0001 );
    2722                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 2 ) ), 1.5708, 0.0001 );
    2723                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 3 ) ), 3.141592, 0.0001 );
    2724                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 4 ) ), 4.712389, 0.0001 );
    2725                 :            : 
    2726                 :            :   //closed circular string
    2727                 :          1 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 0, 0 ) );
    2728                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 0, 0.00001 );
    2729                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 3.141592, 0.00001 );
    2730                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 2 ) ), 0, 0.00001 );
    2731                 :            : 
    2732                 :            :   //removing a vertex from a 3 point circular string should remove the whole line
    2733                 :          1 :   QgsCircularString l39;
    2734                 :          1 :   l39.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 1 ) << QgsPoint( 0, 2 ) );
    2735                 :          1 :   QCOMPARE( l39.numPoints(), 3 );
    2736                 :          1 :   l39.deleteVertex( QgsVertexId( 0, 0, 2 ) );
    2737                 :          1 :   QCOMPARE( l39.numPoints(), 0 );
    2738                 :            : 
    2739                 :            :   //boundary
    2740                 :          1 :   QgsCircularString boundary1;
    2741                 :          1 :   QVERIFY( !boundary1.boundary() );
    2742                 :          1 :   boundary1.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 ) );
    2743                 :          1 :   QgsAbstractGeometry *boundary = boundary1.boundary();
    2744                 :          1 :   QgsMultiPoint *mpBoundary = dynamic_cast< QgsMultiPoint * >( boundary );
    2745                 :          1 :   QVERIFY( mpBoundary );
    2746                 :          1 :   QCOMPARE( mpBoundary->pointN( 0 )->x(), 0.0 );
    2747                 :          1 :   QCOMPARE( mpBoundary->pointN( 0 )->y(), 0.0 );
    2748                 :          1 :   QCOMPARE( mpBoundary->pointN( 1 )->x(), 1.0 );
    2749                 :          1 :   QCOMPARE( mpBoundary->pointN( 1 )->y(), 1.0 );
    2750                 :          1 :   delete boundary;
    2751                 :            : 
    2752                 :            :   // closed string = no boundary
    2753                 :          1 :   boundary1.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 ) << QgsPoint( 0, 0 ) );
    2754                 :          1 :   QVERIFY( !boundary1.boundary() );
    2755                 :            : 
    2756                 :            :   //boundary with z
    2757                 :          1 :   boundary1.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 10 ) << QgsPoint( QgsWkbTypes::PointZ, 1, 0, 15 ) << QgsPoint( QgsWkbTypes::PointZ, 1, 1, 20 ) );
    2758                 :          1 :   boundary = boundary1.boundary();
    2759                 :          1 :   mpBoundary = dynamic_cast< QgsMultiPoint * >( boundary );
    2760                 :          1 :   QVERIFY( mpBoundary );
    2761                 :          1 :   QCOMPARE( mpBoundary->pointN( 0 )->wkbType(), QgsWkbTypes::PointZ );
    2762                 :          1 :   QCOMPARE( mpBoundary->pointN( 0 )->x(), 0.0 );
    2763                 :          1 :   QCOMPARE( mpBoundary->pointN( 0 )->y(), 0.0 );
    2764                 :          1 :   QCOMPARE( mpBoundary->pointN( 0 )->z(), 10.0 );
    2765                 :          1 :   QCOMPARE( mpBoundary->pointN( 1 )->wkbType(), QgsWkbTypes::PointZ );
    2766                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->x(), 1.0 );
    2767                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->y(), 1.0 );
    2768                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->z(), 20.0 );
    2769                 :          1 :   delete boundary;
    2770                 :            : 
    2771                 :            :   // addToPainterPath (note most tests are in test_qgsgeometry.py)
    2772                 :          1 :   QgsCircularString path;
    2773                 :          1 :   QPainterPath pPath;
    2774                 :          1 :   path.addToPainterPath( pPath );
    2775                 :          1 :   QVERIFY( pPath.isEmpty() );
    2776                 :          2 :   path.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 )
    2777                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 21, 2, 3 ) );
    2778                 :          1 :   path.addToPainterPath( pPath );
    2779                 :          1 :   QGSCOMPARENEAR( pPath.currentPosition().x(), 21.0, 0.01 );
    2780                 :          1 :   QGSCOMPARENEAR( pPath.currentPosition().y(), 2.0, 0.01 );
    2781                 :          1 :   QVERIFY( !pPath.isEmpty() );
    2782                 :            : 
    2783                 :            :   // even number of points - should still work
    2784                 :          1 :   pPath = QPainterPath();
    2785                 :          1 :   path.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 ) );
    2786                 :          1 :   path.addToPainterPath( pPath );
    2787                 :          1 :   QGSCOMPARENEAR( pPath.currentPosition().x(), 11.0, 0.01 );
    2788                 :          1 :   QGSCOMPARENEAR( pPath.currentPosition().y(), 12.0, 0.01 );
    2789                 :          1 :   QVERIFY( !pPath.isEmpty() );
    2790                 :            : 
    2791                 :            :   // toCurveType
    2792                 :          1 :   QgsCircularString curveLine1;
    2793                 :          1 :   curveLine1.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 22 ) );
    2794                 :          1 :   std::unique_ptr< QgsCurve > curveType( curveLine1.toCurveType() );
    2795                 :          1 :   QCOMPARE( curveType->wkbType(), QgsWkbTypes::CircularString );
    2796                 :          1 :   QCOMPARE( curveType->numPoints(), 3 );
    2797                 :          1 :   QCOMPARE( curveType->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( 1, 2 ) );
    2798                 :          1 :   QCOMPARE( curveType->vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( 11, 12 ) );
    2799                 :          1 :   QCOMPARE( curveType->vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( 1, 22 ) );
    2800                 :            : 
    2801                 :            :   //segmentLength
    2802                 :          1 :   QgsCircularString curveLine2;
    2803                 :          1 :   QCOMPARE( curveLine2.segmentLength( QgsVertexId( -1, 0, 0 ) ), 0.0 );
    2804                 :          1 :   QCOMPARE( curveLine2.segmentLength( QgsVertexId( 0, 0, 0 ) ), 0.0 );
    2805                 :          1 :   QCOMPARE( curveLine2.segmentLength( QgsVertexId( 1, 0, 0 ) ), 0.0 );
    2806                 :          1 :   curveLine2.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 22 ) );
    2807                 :          1 :   QCOMPARE( curveLine2.segmentLength( QgsVertexId() ), 0.0 );
    2808                 :          1 :   QCOMPARE( curveLine2.segmentLength( QgsVertexId( 0, 0, -1 ) ), 0.0 );
    2809                 :          1 :   QGSCOMPARENEAR( curveLine2.segmentLength( QgsVertexId( 0, 0, 0 ) ), 31.4159, 0.001 );
    2810                 :          1 :   QCOMPARE( curveLine2.segmentLength( QgsVertexId( 0, 0, 1 ) ), 0.0 );
    2811                 :          1 :   QCOMPARE( curveLine2.segmentLength( QgsVertexId( 0, 0, 2 ) ), 0.0 );
    2812                 :          1 :   QCOMPARE( curveLine2.segmentLength( QgsVertexId( -1, 0, -1 ) ), 0.0 );
    2813                 :          1 :   QGSCOMPARENEAR( curveLine2.segmentLength( QgsVertexId( -1, 0, 0 ) ), 31.4159, 0.001 );
    2814                 :          1 :   QCOMPARE( curveLine2.segmentLength( QgsVertexId( 1, 0, 1 ) ), 0.0 );
    2815                 :          1 :   QGSCOMPARENEAR( curveLine2.segmentLength( QgsVertexId( 1, 1, 0 ) ), 31.4159, 0.001 );
    2816                 :          1 :   curveLine2.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 22 ) << QgsPoint( -9, 32 ) << QgsPoint( 1, 42 ) );
    2817                 :          1 :   QCOMPARE( curveLine2.segmentLength( QgsVertexId() ), 0.0 );
    2818                 :          1 :   QCOMPARE( curveLine2.segmentLength( QgsVertexId( 0, 0, -1 ) ), 0.0 );
    2819                 :          1 :   QGSCOMPARENEAR( curveLine2.segmentLength( QgsVertexId( 0, 0, 0 ) ), 31.4159, 0.001 );
    2820                 :          1 :   QCOMPARE( curveLine2.segmentLength( QgsVertexId( 0, 0, 1 ) ), 0.0 );
    2821                 :          1 :   QGSCOMPARENEAR( curveLine2.segmentLength( QgsVertexId( 0, 0, 2 ) ), 31.4159, 0.001 );
    2822                 :          1 :   QCOMPARE( curveLine2.segmentLength( QgsVertexId( 0, 0, 3 ) ), 0.0 );
    2823                 :            : 
    2824                 :            :   //removeDuplicateNodes
    2825                 :          1 :   QgsCircularString nodeLine;
    2826                 :          1 :   QVERIFY( !nodeLine.removeDuplicateNodes() );
    2827                 :          1 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 111, 12 ) );
    2828                 :          1 :   QVERIFY( !nodeLine.removeDuplicateNodes() );
    2829                 :          2 :   QCOMPARE( nodeLine.asWkt(), QStringLiteral( "CircularString (11 2, 11 12, 111 12)" ) );
    2830                 :          1 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 11, 2 ) );
    2831                 :          1 :   QVERIFY( !nodeLine.removeDuplicateNodes() );
    2832                 :          2 :   QCOMPARE( nodeLine.asWkt(), QStringLiteral( "CircularString (11 2, 11 12, 11 2)" ) );
    2833                 :          2 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 10, 3 ) << QgsPoint( 11.01, 1.99 ) << QgsPoint( 9, 3 )
    2834                 :          1 :                       << QgsPoint( 11, 2 ) );
    2835                 :          1 :   QVERIFY( !nodeLine.removeDuplicateNodes( 0.02 ) );
    2836                 :          2 :   QCOMPARE( nodeLine.asWkt( 2 ), QStringLiteral( "CircularString (11 2, 10 3, 11.01 1.99, 9 3, 11 2)" ) );
    2837                 :          2 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11.01, 1.99 ) << QgsPoint( 11.02, 2.01 )
    2838                 :          1 :                       << QgsPoint( 11, 12 ) << QgsPoint( 111, 12 ) << QgsPoint( 111.01, 11.99 ) );
    2839                 :          1 :   QVERIFY( !nodeLine.removeDuplicateNodes() );
    2840                 :          2 :   QCOMPARE( nodeLine.asWkt( 2 ), QStringLiteral( "CircularString (11 2, 11.01 1.99, 11.02 2.01, 11 12, 111 12, 111.01 11.99)" ) );
    2841                 :          1 :   QVERIFY( nodeLine.removeDuplicateNodes( 0.02 ) );
    2842                 :          1 :   QVERIFY( !nodeLine.removeDuplicateNodes( 0.02 ) );
    2843                 :          2 :   QCOMPARE( nodeLine.asWkt( 2 ), QStringLiteral( "CircularString (11 2, 11 12, 111 12, 111.01 11.99)" ) );
    2844                 :            : 
    2845                 :            :   // don't create degenerate lines
    2846                 :          1 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) );
    2847                 :          1 :   QVERIFY( !nodeLine.removeDuplicateNodes( 0.02 ) );
    2848                 :          2 :   QCOMPARE( nodeLine.asWkt( 2 ), QStringLiteral( "CircularString (11 2)" ) );
    2849                 :          1 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11.01, 1.99 ) );
    2850                 :          1 :   QVERIFY( !nodeLine.removeDuplicateNodes( 0.02 ) );
    2851                 :          2 :   QCOMPARE( nodeLine.asWkt( 2 ), QStringLiteral( "CircularString (11 2, 11.01 1.99)" ) );
    2852                 :          1 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11.01, 1.99 ) << QgsPoint( 11, 2 ) );
    2853                 :          1 :   QVERIFY( !nodeLine.removeDuplicateNodes( 0.02 ) );
    2854                 :          2 :   QCOMPARE( nodeLine.asWkt( 2 ), QStringLiteral( "CircularString (11 2, 11.01 1.99, 11 2)" ) );
    2855                 :            : 
    2856                 :            :   // with z
    2857                 :          2 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 1 ) << QgsPoint( 11.01, 1.99, 2 ) << QgsPoint( 11.02, 2.01, 3 )
    2858                 :          1 :                       << QgsPoint( 11, 12, 4 ) << QgsPoint( 111, 12, 5 ) );
    2859                 :          1 :   QVERIFY( nodeLine.removeDuplicateNodes( 0.02 ) );
    2860                 :          2 :   QCOMPARE( nodeLine.asWkt( 2 ), QStringLiteral( "CircularStringZ (11 2 1, 11 12 4, 111 12 5)" ) );
    2861                 :          2 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 1 ) << QgsPoint( 11.01, 1.99, 2 ) << QgsPoint( 11.02, 2.01, 3 )
    2862                 :          1 :                       << QgsPoint( 11, 12, 4 ) << QgsPoint( 111, 12, 5 ) );
    2863                 :          1 :   QVERIFY( !nodeLine.removeDuplicateNodes( 0.02, true ) );
    2864                 :          2 :   QCOMPARE( nodeLine.asWkt( 2 ), QStringLiteral( "CircularStringZ (11 2 1, 11.01 1.99 2, 11.02 2.01 3, 11 12 4, 111 12 5)" ) );
    2865                 :            : 
    2866                 :            :   //swap xy
    2867                 :          1 :   QgsCircularString swapLine;
    2868                 :          1 :   swapLine.swapXy(); // no crash
    2869                 :          1 :   swapLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 11, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 111, 12, 23, 24, QgsWkbTypes::PointZM ) );
    2870                 :          1 :   swapLine.swapXy();
    2871                 :          2 :   QCOMPARE( swapLine.asWkt(), QStringLiteral( "CircularStringZM (2 11 3 4, 12 11 13 14, 12 111 23 24)" ) );
    2872                 :            : 
    2873                 :            :   // filter vertex
    2874                 :          1 :   QgsCircularString filterLine;
    2875                 :          3 :   auto filter = []( const QgsPoint & point )-> bool
    2876                 :            :   {
    2877                 :          3 :     return point.x() < 5;
    2878                 :            :   };
    2879                 :          1 :   filterLine.filterVertices( filter ); // no crash
    2880                 :          1 :   filterLine.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 4, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 111, 12, 23, 24, QgsWkbTypes::PointZM ) );
    2881                 :          1 :   filterLine.filterVertices( filter );
    2882                 :          2 :   QCOMPARE( filterLine.asWkt( 2 ), QStringLiteral( "CircularStringZM (1 2 3 4, 4 12 13 14)" ) );
    2883                 :            : 
    2884                 :            :   // transform vertex
    2885                 :          1 :   QgsCircularString transformLine;
    2886                 :          3 :   auto transform = []( const QgsPoint & point )-> QgsPoint
    2887                 :            :   {
    2888                 :          3 :     return QgsPoint( point.x() + 2, point.y() + 3, point.z() + 4, point.m() + 7 );
    2889                 :            :   };
    2890                 :          1 :   transformLine.transformVertices( transform ); // no crash
    2891                 :          1 :   transformLine.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 4, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 111, 12, 23, 24, QgsWkbTypes::PointZM ) );
    2892                 :          1 :   transformLine.transformVertices( transform );
    2893                 :          2 :   QCOMPARE( transformLine.asWkt( 2 ), QStringLiteral( "CircularStringZM (3 5 7 11, 6 15 17 21, 113 15 27 31)" ) );
    2894                 :            : 
    2895                 :            :   // transform using class
    2896                 :          1 :   QgsCircularString transformLine2;
    2897                 :          1 :   TestTransformer transformer;
    2898                 :            :   // no crash
    2899                 :          1 :   QVERIFY( transformLine2.transform( &transformer ) );
    2900                 :          1 :   transformLine2.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 4, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 111, 12, 23, 24, QgsWkbTypes::PointZM ) );
    2901                 :          1 :   QVERIFY( transformLine2.transform( &transformer ) );
    2902                 :          2 :   QCOMPARE( transformLine2.asWkt( 2 ), QStringLiteral( "CircularStringZM (3 16 8 3, 12 26 18 13, 333 26 28 23)" ) );
    2903                 :            : 
    2904                 :          1 :   TestFailTransformer failTransformer;
    2905                 :          1 :   QVERIFY( !transformLine2.transform( &failTransformer ) );
    2906                 :            : 
    2907                 :            :   // substring
    2908                 :          1 :   QgsCircularString substring;
    2909                 :          1 :   std::unique_ptr< QgsCircularString > substringResult( substring.curveSubstring( 1, 2 ) ); // no crash
    2910                 :          1 :   QVERIFY( substringResult.get() );
    2911                 :          1 :   QVERIFY( substringResult->isEmpty() );
    2912                 :            :   // CircularStringZM (10 0 1 2, 11 1 3 4, 12 0 13 14)
    2913                 :          1 :   substring.setPoints( QgsPointSequence() << QgsPoint( 10, 0, 1, 2 ) <<  QgsPoint( 11, 1, 3, 4 ) <<  QgsPoint( 12, 0, 13, 14 ) );
    2914                 :          1 :   substringResult.reset( substring.curveSubstring( 0, 0 ) );
    2915                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CircularStringZM (10 0 1 2, 10 0 1 2, 10 0 1 2)" ) );
    2916                 :          1 :   substringResult.reset( substring.curveSubstring( -1, -0.1 ) );
    2917                 :          1 :   QVERIFY( substringResult->isEmpty() );
    2918                 :          1 :   substringResult.reset( substring.curveSubstring( 100000, 10000 ) );
    2919                 :          1 :   QVERIFY( substringResult->isEmpty() );
    2920                 :          1 :   substringResult.reset( substring.curveSubstring( -1, 1 ) );
    2921                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CircularStringZM (10 0 1 2, 10.12 0.48 1.64 2.64, 10.46 0.84 2.27 3.27)" ) );
    2922                 :          1 :   substringResult.reset( substring.curveSubstring( 1, -1 ) );
    2923                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CircularStringZM (10.46 0.84 2.27 3.27, 10.46 0.84 2.27 3.27, 10.46 0.84 2.27 3.27)" ) );
    2924                 :          1 :   substringResult.reset( substring.curveSubstring( -1, 10000 ) );
    2925                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CircularStringZM (10 0 1 2, 11 1 3 4, 12 0 13 14)" ) );
    2926                 :          1 :   substringResult.reset( substring.curveSubstring( 1, 10000 ) );
    2927                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CircularStringZM (10.46 0.84 2.27 3.27, 11.48 0.88 6.18 7.18, 12 0 13 14)" ) );
    2928                 :          1 :   substringResult.reset( substring.curveSubstring( 1, 20 ) );
    2929                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CircularStringZM (10.46 0.84 2.27 3.27, 11.48 0.88 6.18 7.18, 12 0 13 14)" ) );
    2930                 :          1 :   substringResult.reset( substring.curveSubstring( 1, 1.5 ) );
    2931                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CircularStringZM (10.46 0.84 2.27 3.27, 10.68 0.95 2.59 3.59, 10.93 1 2.91 3.91)" ) );
    2932                 :            :   // CircularStringZM (10 0 1 2, 11 1 3 4, 12 0 13 14, 14 -1 13 14, 16 1 23 24 )
    2933                 :          2 :   substring.setPoints( QgsPointSequence() << QgsPoint( 10, 0, 1, 2 ) <<  QgsPoint( 11, 1, 3, 4 ) <<  QgsPoint( 12, 0, 13, 14 )
    2934                 :          1 :                        <<  QgsPoint( 14, -1, 13, 14 ) <<  QgsPoint( 16, 1, 23, 24 ) );
    2935                 :          1 :   substringResult.reset( substring.curveSubstring( 1, 1.5 ) );
    2936                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CircularStringZM (10.46 0.84 2.27 3.27, 10.68 0.95 2.59 3.59, 10.93 1 2.91 3.91)" ) );
    2937                 :          1 :   substringResult.reset( substring.curveSubstring( 1, 10 ) );
    2938                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CircularStringZM (10.46 0.84 2.27 3.27, 11.48 0.88 6.18 7.18, 12 0 13 14, 14 -1 13 14, 16 1 23 24)" ) );
    2939                 :          1 :   substringResult.reset( substring.curveSubstring( 1, 6 ) );
    2940                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CircularStringZM (10.46 0.84 2.27 3.27, 11.48 0.88 6.18 7.18, 12 0 13 14, 13.1 -0.88 13 14, 14.5 -0.9 14.65 15.65)" ) );
    2941                 :          1 :   substringResult.reset( substring.curveSubstring( 0, 6 ) );
    2942                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CircularStringZM (10 0 1 2, 11 1 3 4, 12 0 13 14, 13.1 -0.88 13 14, 14.5 -0.9 14.65 15.65)" ) );
    2943                 :          1 :   substringResult.reset( substring.curveSubstring( 5, 6 ) );
    2944                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CircularStringZM (13.51 -0.98 13 14, 14.01 -1 13.03 14.03, 14.5 -0.9 14.65 15.65)" ) );
    2945                 :          1 :   substringResult.reset( substring.curveSubstring( 5, 1000 ) );
    2946                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CircularStringZM (13.51 -0.98 13 14, 15.19 -0.53 17.2 18.2, 16 1 23 24)" ) );
    2947                 :          1 :   substringResult.reset( substring.curveSubstring( QgsGeometryUtils::distanceToVertex( substring, QgsVertexId( 0, 0, 2 ) ), QgsGeometryUtils::distanceToVertex( substring, QgsVertexId( 0, 0, 4 ) ) ) );
    2948                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CircularStringZM (12 0 13 14, 14.36 -0.94 14.19 15.19, 16 1 23 24)" ) );
    2949                 :            : 
    2950                 :          2 :   substring.setPoints( QgsPointSequence() << QgsPoint( 10, 0, 1 ) <<  QgsPoint( 11, 1, 3 ) <<  QgsPoint( 12, 0, 13 )
    2951                 :          1 :                        <<  QgsPoint( 14, -1, 13 ) <<  QgsPoint( 16, 1, 23 ) );
    2952                 :          1 :   substringResult.reset( substring.curveSubstring( 1, 20 ) );
    2953                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CircularStringZ (10.46 0.84 2.27, 11.48 0.88 6.18, 12 0 13, 14 -1 13, 16 1 23)" ) );
    2954                 :          2 :   substring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 10, 0, 0, 1 ) <<  QgsPoint( QgsWkbTypes::PointM, 11, 1, 0, 3 ) <<  QgsPoint( QgsWkbTypes::PointM, 12, 0, 0, 13 )
    2955                 :          1 :                        <<  QgsPoint( QgsWkbTypes::PointM, 14, -1, 0, 13 ) <<  QgsPoint( QgsWkbTypes::PointM, 16, 1, 0, 23 ) );
    2956                 :          1 :   substringResult.reset( substring.curveSubstring( 1, 20 ) );
    2957                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CircularStringM (10.46 0.84 2.27, 11.48 0.88 6.18, 12 0 13, 14 -1 13, 16 1 23)" ) );
    2958                 :          2 :   substring.setPoints( QgsPointSequence() << QgsPoint( 10, 0 ) <<  QgsPoint( 11, 1 ) <<  QgsPoint( 12, 0 )
    2959                 :          1 :                        <<  QgsPoint( 14, -1 ) <<  QgsPoint( 16, 1 ) );
    2960                 :          1 :   substringResult.reset( substring.curveSubstring( 1, 20 ) );
    2961                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CircularString (10.46 0.84, 11.48 0.88, 12 0, 14 -1, 16 1)" ) );
    2962                 :            : 
    2963                 :            :   // interpolate
    2964                 :          1 :   QgsCircularString interpolate;
    2965                 :          1 :   std::unique_ptr< QgsPoint > interpolateResult( interpolate.interpolatePoint( 1 ) ); // no crash
    2966                 :          1 :   QVERIFY( !interpolateResult.get() );
    2967                 :            :   // CircularStringZM (10 0 1 2, 11 1 3 4, 12 0 13 14)
    2968                 :          1 :   interpolate.setPoints( QgsPointSequence() << QgsPoint( 10, 0, 1, 2 ) <<  QgsPoint( 11, 1, 3, 4 ) <<  QgsPoint( 12, 0, 13, 14 ) );
    2969                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 0 ) );
    2970                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointZM (10 0 1 2)" ) );
    2971                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( -1 ) );
    2972                 :          1 :   QVERIFY( !interpolateResult.get() );
    2973                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 100000 ) );
    2974                 :          1 :   QVERIFY( !interpolateResult.get() );
    2975                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 1 ) );
    2976                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointZM (10.46 0.84 2.27 3.27)" ) );
    2977                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 1.5 ) );
    2978                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointZM (10.93 1 2.91 3.91)" ) );
    2979                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( interpolate.length() ) );
    2980                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointZM (12 0 13 14)" ) );
    2981                 :            :   // CircularStringZM (10 0 1 2, 11 1 3 4, 12 0 13 14, 14 -1 13 14, 16 1 23 24 )
    2982                 :          2 :   interpolate.setPoints( QgsPointSequence() << QgsPoint( 10, 0, 1, 2 ) <<  QgsPoint( 11, 1, 3, 4 ) <<  QgsPoint( 12, 0, 13, 14 )
    2983                 :          1 :                          <<  QgsPoint( 14, -1, 13, 14 ) <<  QgsPoint( 16, 1, 23, 24 ) );
    2984                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 1 ) );
    2985                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointZM (10.46 0.84 2.27 3.27)" ) );
    2986                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 1.5 ) );
    2987                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointZM (10.93 1 2.91 3.91)" ) );
    2988                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 10 ) );
    2989                 :          1 :   QVERIFY( !interpolateResult.get() );
    2990                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 6 ) );
    2991                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointZM (14.5 -0.9 14.65 15.65)" ) );
    2992                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 5 ) );
    2993                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointZM (13.51 -0.98 13 14)" ) );
    2994                 :            : 
    2995                 :          2 :   interpolate.setPoints( QgsPointSequence() << QgsPoint( 10, 0, 1 ) <<  QgsPoint( 11, 1, 3 ) <<  QgsPoint( 12, 0, 13 )
    2996                 :          1 :                          <<  QgsPoint( 14, -1, 13 ) <<  QgsPoint( 16, 1, 23 ) );
    2997                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 1 ) );
    2998                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointZ (10.46 0.84 2.27)" ) );
    2999                 :          2 :   interpolate.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 10, 0, 0, 1 ) <<  QgsPoint( QgsWkbTypes::PointM, 11, 1, 0, 3 ) <<  QgsPoint( QgsWkbTypes::PointM, 12, 0, 0, 13 )
    3000                 :          1 :                          <<  QgsPoint( QgsWkbTypes::PointM, 14, -1, 0, 13 ) <<  QgsPoint( QgsWkbTypes::PointM, 16, 1, 0, 23 ) );
    3001                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 1 ) );
    3002                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointM (10.46 0.84 2.27)" ) );
    3003                 :          2 :   interpolate.setPoints( QgsPointSequence() << QgsPoint( 10, 0 ) <<  QgsPoint( 11, 1 ) <<  QgsPoint( 12, 0 )
    3004                 :          1 :                          <<  QgsPoint( 14, -1 ) <<  QgsPoint( 16, 1 ) );
    3005                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 1 ) );
    3006                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "Point (10.46 0.84)" ) );
    3007                 :            : 
    3008                 :            :   // orientation
    3009                 :          1 :   QgsCircularString orientation;
    3010                 :          1 :   ( void )orientation.orientation(); // no crash
    3011                 :          1 :   orientation.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 1 ) << QgsPoint( 1, 1 ) << QgsPoint( 1, 0 ) << QgsPoint( 0, 0 ) );
    3012                 :          1 :   QCOMPARE( orientation.orientation(), QgsCurve::Clockwise );
    3013                 :          1 :   orientation.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 ) << QgsPoint( 0, 1 ) << QgsPoint( 0, 0 ) );
    3014                 :          1 :   QCOMPARE( orientation.orientation(), QgsCurve::CounterClockwise );
    3015                 :          1 : }
    3016                 :            : 
    3017                 :            : 
    3018                 :          1 : void TestQgsGeometry::lineString()
    3019                 :            : {
    3020                 :            :   //test constructors
    3021                 :          1 :   QgsLineString l1;
    3022                 :          1 :   QVERIFY( l1.isEmpty() );
    3023                 :          1 :   QCOMPARE( l1.numPoints(), 0 );
    3024                 :          1 :   QCOMPARE( l1.vertexCount(), 0 );
    3025                 :          1 :   QCOMPARE( l1.nCoordinates(), 0 );
    3026                 :          1 :   QCOMPARE( l1.ringCount(), 0 );
    3027                 :          1 :   QCOMPARE( l1.partCount(), 0 );
    3028                 :          1 :   QVERIFY( !l1.is3D() );
    3029                 :          1 :   QVERIFY( !l1.isMeasure() );
    3030                 :          1 :   QCOMPARE( l1.wkbType(), QgsWkbTypes::LineString );
    3031                 :          1 :   QCOMPARE( l1.wktTypeStr(), QString( "LineString" ) );
    3032                 :          1 :   QCOMPARE( l1.geometryType(), QString( "LineString" ) );
    3033                 :          1 :   QCOMPARE( l1.dimension(), 1 );
    3034                 :          1 :   QVERIFY( !l1.hasCurvedSegments() );
    3035                 :          1 :   QCOMPARE( l1.area(), 0.0 );
    3036                 :          1 :   QCOMPARE( l1.perimeter(), 0.0 );
    3037                 :            : 
    3038                 :            :   // from array
    3039                 :          1 :   QVector< double > xx;
    3040                 :          1 :   xx << 1 << 2 << 3;
    3041                 :          1 :   QVector< double > yy;
    3042                 :          1 :   yy << 11 << 12 << 13;
    3043                 :          1 :   QgsLineString fromArray( xx, yy );
    3044                 :          1 :   QCOMPARE( fromArray.wkbType(), QgsWkbTypes::LineString );
    3045                 :          1 :   QCOMPARE( fromArray.numPoints(), 3 );
    3046                 :          1 :   QCOMPARE( fromArray.xAt( 0 ), 1.0 );
    3047                 :          1 :   QCOMPARE( fromArray.yAt( 0 ), 11.0 );
    3048                 :          1 :   QCOMPARE( fromArray.xAt( 1 ), 2.0 );
    3049                 :          1 :   QCOMPARE( fromArray.yAt( 1 ), 12.0 );
    3050                 :          1 :   QCOMPARE( fromArray.xAt( 2 ), 3.0 );
    3051                 :          1 :   QCOMPARE( fromArray.yAt( 2 ), 13.0 );
    3052                 :          1 :   QCOMPARE( *fromArray.xData(), 1.0 );
    3053                 :          1 :   QCOMPARE( *( fromArray.xData() + 1 ), 2.0 );
    3054                 :          1 :   QCOMPARE( *( fromArray.xData() + 2 ), 3.0 );
    3055                 :          1 :   QCOMPARE( *fromArray.yData(), 11.0 );
    3056                 :          1 :   QCOMPARE( *( fromArray.yData() + 1 ), 12.0 );
    3057                 :          1 :   QCOMPARE( *( fromArray.yData() + 2 ), 13.0 );
    3058                 :            : 
    3059                 :            :   // unbalanced
    3060                 :          1 :   xx = QVector< double >() << 1 << 2;
    3061                 :          1 :   yy = QVector< double >() << 11 << 12 << 13;
    3062                 :          1 :   QgsLineString fromArray2( xx, yy );
    3063                 :          1 :   QCOMPARE( fromArray2.wkbType(), QgsWkbTypes::LineString );
    3064                 :          1 :   QCOMPARE( fromArray2.numPoints(), 2 );
    3065                 :          1 :   QCOMPARE( fromArray2.xAt( 0 ), 1.0 );
    3066                 :          1 :   QCOMPARE( fromArray2.yAt( 0 ), 11.0 );
    3067                 :          1 :   QCOMPARE( fromArray2.xAt( 1 ), 2.0 );
    3068                 :          1 :   QCOMPARE( fromArray2.yAt( 1 ), 12.0 );
    3069                 :          1 :   xx = QVector< double >() << 1 << 2 << 3;
    3070                 :          1 :   yy = QVector< double >() << 11 << 12;
    3071                 :          1 :   QgsLineString fromArray3( xx, yy );
    3072                 :          1 :   QCOMPARE( fromArray3.wkbType(), QgsWkbTypes::LineString );
    3073                 :          1 :   QCOMPARE( fromArray3.numPoints(), 2 );
    3074                 :          1 :   QCOMPARE( fromArray3.xAt( 0 ), 1.0 );
    3075                 :          1 :   QCOMPARE( fromArray3.yAt( 0 ), 11.0 );
    3076                 :          1 :   QCOMPARE( fromArray3.xAt( 1 ), 2.0 );
    3077                 :          1 :   QCOMPARE( fromArray3.yAt( 1 ), 12.0 );
    3078                 :            :   // with z
    3079                 :          1 :   QVector< double > zz;
    3080                 :          1 :   xx = QVector< double >() << 1 << 2 << 3;
    3081                 :          1 :   yy = QVector< double >() << 11 << 12 << 13;
    3082                 :          1 :   zz = QVector< double >() << 21 << 22 << 23;
    3083                 :          1 :   QgsLineString fromArray4( xx, yy, zz );
    3084                 :          1 :   QCOMPARE( fromArray4.wkbType(), QgsWkbTypes::LineStringZ );
    3085                 :          1 :   QCOMPARE( fromArray4.numPoints(), 3 );
    3086                 :          1 :   QCOMPARE( fromArray4.xAt( 0 ), 1.0 );
    3087                 :          1 :   QCOMPARE( fromArray4.yAt( 0 ), 11.0 );
    3088                 :          1 :   QCOMPARE( fromArray4.zAt( 0 ), 21.0 );
    3089                 :          1 :   QCOMPARE( fromArray4.xAt( 1 ), 2.0 );
    3090                 :          1 :   QCOMPARE( fromArray4.yAt( 1 ), 12.0 );
    3091                 :          1 :   QCOMPARE( fromArray4.zAt( 1 ), 22.0 );
    3092                 :          1 :   QCOMPARE( fromArray4.xAt( 2 ), 3.0 );
    3093                 :          1 :   QCOMPARE( fromArray4.yAt( 2 ), 13.0 );
    3094                 :          1 :   QCOMPARE( fromArray4.zAt( 2 ), 23.0 );
    3095                 :          1 :   fromArray4 = QgsLineString( xx, yy, zz, QVector< double >(), true );  // LineString25D
    3096                 :          1 :   QCOMPARE( fromArray4.wkbType(), QgsWkbTypes::LineString25D );
    3097                 :          1 :   QCOMPARE( fromArray4.numPoints(), 3 );
    3098                 :          1 :   QCOMPARE( fromArray4.xAt( 0 ), 1.0 );
    3099                 :          1 :   QCOMPARE( fromArray4.yAt( 0 ), 11.0 );
    3100                 :          1 :   QCOMPARE( fromArray4.zAt( 0 ), 21.0 );
    3101                 :          1 :   QCOMPARE( fromArray4.xAt( 1 ), 2.0 );
    3102                 :          1 :   QCOMPARE( fromArray4.yAt( 1 ), 12.0 );
    3103                 :          1 :   QCOMPARE( fromArray4.zAt( 1 ), 22.0 );
    3104                 :          1 :   QCOMPARE( fromArray4.xAt( 2 ), 3.0 );
    3105                 :          1 :   QCOMPARE( fromArray4.yAt( 2 ), 13.0 );
    3106                 :          1 :   QCOMPARE( fromArray4.zAt( 2 ), 23.0 );
    3107                 :            : 
    3108                 :            :   // unbalanced -> z ignored
    3109                 :          1 :   zz = QVector< double >() << 21 << 22;
    3110                 :          1 :   QgsLineString fromArray5( xx, yy, zz );
    3111                 :          1 :   QCOMPARE( fromArray5.wkbType(), QgsWkbTypes::LineString );
    3112                 :          1 :   QCOMPARE( fromArray5.numPoints(), 3 );
    3113                 :          1 :   QCOMPARE( fromArray5.xAt( 0 ), 1.0 );
    3114                 :          1 :   QCOMPARE( fromArray5.yAt( 0 ), 11.0 );
    3115                 :          1 :   QCOMPARE( fromArray5.xAt( 1 ), 2.0 );
    3116                 :          1 :   QCOMPARE( fromArray5.yAt( 1 ), 12.0 );
    3117                 :          1 :   QCOMPARE( fromArray5.xAt( 2 ), 3.0 );
    3118                 :          1 :   QCOMPARE( fromArray5.yAt( 2 ), 13.0 );
    3119                 :            :   // unbalanced -> z truncated
    3120                 :          1 :   zz = QVector< double >() << 21 << 22 << 23 << 24;
    3121                 :          1 :   fromArray5 = QgsLineString( xx, yy, zz );
    3122                 :          1 :   QCOMPARE( fromArray5.wkbType(), QgsWkbTypes::LineStringZ );
    3123                 :          1 :   QCOMPARE( fromArray5.numPoints(), 3 );
    3124                 :          1 :   QCOMPARE( fromArray5.xAt( 0 ), 1.0 );
    3125                 :          1 :   QCOMPARE( fromArray5.yAt( 0 ), 11.0 );
    3126                 :          1 :   QCOMPARE( fromArray5.zAt( 0 ), 21.0 );
    3127                 :          1 :   QCOMPARE( fromArray5.xAt( 1 ), 2.0 );
    3128                 :          1 :   QCOMPARE( fromArray5.yAt( 1 ), 12.0 );
    3129                 :          1 :   QCOMPARE( fromArray5.zAt( 1 ), 22.0 );
    3130                 :          1 :   QCOMPARE( fromArray5.xAt( 2 ), 3.0 );
    3131                 :          1 :   QCOMPARE( fromArray5.yAt( 2 ), 13.0 );
    3132                 :          1 :   QCOMPARE( fromArray5.zAt( 2 ), 23.0 );
    3133                 :            :   // with m
    3134                 :          1 :   QVector< double > mm;
    3135                 :          1 :   xx = QVector< double >() << 1 << 2 << 3;
    3136                 :          1 :   yy = QVector< double >() << 11 << 12 << 13;
    3137                 :          1 :   mm = QVector< double >() << 21 << 22 << 23;
    3138                 :          1 :   QgsLineString fromArray6( xx, yy, QVector< double >(), mm );
    3139                 :          1 :   QCOMPARE( fromArray6.wkbType(), QgsWkbTypes::LineStringM );
    3140                 :          1 :   QCOMPARE( fromArray6.numPoints(), 3 );
    3141                 :          1 :   QCOMPARE( fromArray6.xAt( 0 ), 1.0 );
    3142                 :          1 :   QCOMPARE( fromArray6.yAt( 0 ), 11.0 );
    3143                 :          1 :   QCOMPARE( fromArray6.mAt( 0 ), 21.0 );
    3144                 :          1 :   QCOMPARE( fromArray6.xAt( 1 ), 2.0 );
    3145                 :          1 :   QCOMPARE( fromArray6.yAt( 1 ), 12.0 );
    3146                 :          1 :   QCOMPARE( fromArray6.mAt( 1 ), 22.0 );
    3147                 :          1 :   QCOMPARE( fromArray6.xAt( 2 ), 3.0 );
    3148                 :          1 :   QCOMPARE( fromArray6.yAt( 2 ), 13.0 );
    3149                 :          1 :   QCOMPARE( fromArray6.mAt( 2 ), 23.0 );
    3150                 :            :   // unbalanced -> m ignored
    3151                 :          1 :   mm = QVector< double >() << 21 << 22;
    3152                 :          1 :   QgsLineString fromArray7( xx, yy, QVector< double >(), mm );
    3153                 :          1 :   QCOMPARE( fromArray7.wkbType(), QgsWkbTypes::LineString );
    3154                 :          1 :   QCOMPARE( fromArray7.numPoints(), 3 );
    3155                 :          1 :   QCOMPARE( fromArray7.xAt( 0 ), 1.0 );
    3156                 :          1 :   QCOMPARE( fromArray7.yAt( 0 ), 11.0 );
    3157                 :          1 :   QCOMPARE( fromArray7.xAt( 1 ), 2.0 );
    3158                 :          1 :   QCOMPARE( fromArray7.yAt( 1 ), 12.0 );
    3159                 :          1 :   QCOMPARE( fromArray7.xAt( 2 ), 3.0 );
    3160                 :          1 :   QCOMPARE( fromArray7.yAt( 2 ), 13.0 );
    3161                 :            :   // unbalanced -> m truncated
    3162                 :          1 :   mm = QVector< double >() << 21 << 22 << 23 << 24;
    3163                 :          1 :   fromArray7 = QgsLineString( xx, yy, QVector< double >(), mm );
    3164                 :          1 :   QCOMPARE( fromArray7.wkbType(), QgsWkbTypes::LineStringM );
    3165                 :          1 :   QCOMPARE( fromArray7.numPoints(), 3 );
    3166                 :          1 :   QCOMPARE( fromArray7.xAt( 0 ), 1.0 );
    3167                 :          1 :   QCOMPARE( fromArray7.yAt( 0 ), 11.0 );
    3168                 :          1 :   QCOMPARE( fromArray7.mAt( 0 ), 21.0 );
    3169                 :          1 :   QCOMPARE( fromArray7.xAt( 1 ), 2.0 );
    3170                 :          1 :   QCOMPARE( fromArray7.yAt( 1 ), 12.0 );
    3171                 :          1 :   QCOMPARE( fromArray7.mAt( 1 ), 22.0 );
    3172                 :          1 :   QCOMPARE( fromArray7.xAt( 2 ), 3.0 );
    3173                 :          1 :   QCOMPARE( fromArray7.yAt( 2 ), 13.0 );
    3174                 :          1 :   QCOMPARE( fromArray7.mAt( 2 ), 23.0 );
    3175                 :            :   // zm
    3176                 :          1 :   xx = QVector< double >() << 1 << 2 << 3;
    3177                 :          1 :   yy = QVector< double >() << 11 << 12 << 13;
    3178                 :          1 :   zz = QVector< double >() << 21 << 22 << 23;
    3179                 :          1 :   mm = QVector< double >() << 31 << 32 << 33;
    3180                 :          1 :   QgsLineString fromArray8( xx, yy, zz, mm );
    3181                 :          1 :   QCOMPARE( fromArray8.wkbType(), QgsWkbTypes::LineStringZM );
    3182                 :          1 :   QCOMPARE( fromArray8.numPoints(), 3 );
    3183                 :          1 :   QCOMPARE( fromArray8.xAt( 0 ), 1.0 );
    3184                 :          1 :   QCOMPARE( fromArray8.yAt( 0 ), 11.0 );
    3185                 :          1 :   QCOMPARE( fromArray8.zAt( 0 ), 21.0 );
    3186                 :          1 :   QCOMPARE( fromArray8.mAt( 0 ), 31.0 );
    3187                 :          1 :   QCOMPARE( fromArray8.xAt( 1 ), 2.0 );
    3188                 :          1 :   QCOMPARE( fromArray8.yAt( 1 ), 12.0 );
    3189                 :          1 :   QCOMPARE( fromArray8.zAt( 1 ), 22.0 );
    3190                 :          1 :   QCOMPARE( fromArray8.mAt( 1 ), 32.0 );
    3191                 :          1 :   QCOMPARE( fromArray8.xAt( 2 ), 3.0 );
    3192                 :          1 :   QCOMPARE( fromArray8.yAt( 2 ), 13.0 );
    3193                 :          1 :   QCOMPARE( fromArray8.zAt( 2 ), 23.0 );
    3194                 :          1 :   QCOMPARE( fromArray8.mAt( 2 ), 33.0 );
    3195                 :            : 
    3196                 :          1 :   QCOMPARE( *fromArray8.xData(), 1.0 );
    3197                 :          1 :   QCOMPARE( *( fromArray8.xData() + 1 ), 2.0 );
    3198                 :          1 :   QCOMPARE( *( fromArray8.xData() + 2 ), 3.0 );
    3199                 :          1 :   QCOMPARE( *fromArray8.yData(), 11.0 );
    3200                 :          1 :   QCOMPARE( *( fromArray8.yData() + 1 ), 12.0 );
    3201                 :          1 :   QCOMPARE( *( fromArray8.yData() + 2 ), 13.0 );
    3202                 :          1 :   QCOMPARE( *fromArray8.zData(), 21.0 );
    3203                 :          1 :   QCOMPARE( *( fromArray8.zData() + 1 ), 22.0 );
    3204                 :          1 :   QCOMPARE( *( fromArray8.zData() + 2 ), 23.0 );
    3205                 :          1 :   QCOMPARE( *fromArray8.mData(), 31.0 );
    3206                 :          1 :   QCOMPARE( *( fromArray8.mData() + 1 ), 32.0 );
    3207                 :          1 :   QCOMPARE( *( fromArray8.mData() + 2 ), 33.0 );
    3208                 :            : 
    3209                 :            :   // from QList<QgsPointXY>
    3210                 :          1 :   QgsLineString fromPtsA = QgsLineString( QgsPointSequence() );
    3211                 :          1 :   QVERIFY( fromPtsA.isEmpty() );
    3212                 :          1 :   QCOMPARE( fromPtsA.wkbType(), QgsWkbTypes::LineString );
    3213                 :            : 
    3214                 :          1 :   fromPtsA = QgsLineString( QgsPointSequence()  << QgsPoint( 1, 2, 0, 4, QgsWkbTypes::PointM ) );
    3215                 :          1 :   QCOMPARE( fromPtsA.numPoints(), 1 );
    3216                 :          1 :   QCOMPARE( fromPtsA.wkbType(), QgsWkbTypes::LineStringM );
    3217                 :            : 
    3218                 :          1 :   QVector<QgsPointXY> ptsA;
    3219                 :          1 :   ptsA << QgsPointXY( 1, 2 ) << QgsPointXY( 11, 12 ) << QgsPointXY( 21, 22 );
    3220                 :          1 :   QgsLineString fromPts( ptsA );
    3221                 :          1 :   QCOMPARE( fromPts.wkbType(), QgsWkbTypes::LineString );
    3222                 :          1 :   QCOMPARE( fromPts.numPoints(), 3 );
    3223                 :          1 :   QCOMPARE( fromPts.xAt( 0 ), 1.0 );
    3224                 :          1 :   QCOMPARE( fromPts.yAt( 0 ), 2.0 );
    3225                 :          1 :   QCOMPARE( fromPts.xAt( 1 ), 11.0 );
    3226                 :          1 :   QCOMPARE( fromPts.yAt( 1 ), 12.0 );
    3227                 :          1 :   QCOMPARE( fromPts.xAt( 2 ), 21.0 );
    3228                 :          1 :   QCOMPARE( fromPts.yAt( 2 ), 22.0 );
    3229                 :            : 
    3230                 :            :   // from QgsPointSequence
    3231                 :          1 :   QgsPointSequence ptsVector;
    3232                 :          1 :   ptsVector << QgsPoint( 10, 20 ) << QgsPoint( 30, 40 );
    3233                 :          1 :   QgsLineString fromVector( ptsVector );
    3234                 :          1 :   QCOMPARE( fromVector.wkbType(), QgsWkbTypes::LineString );
    3235                 :          1 :   QCOMPARE( fromVector.numPoints(), 2 );
    3236                 :          1 :   QCOMPARE( fromVector.xAt( 0 ), 10.0 );
    3237                 :          1 :   QCOMPARE( fromVector.yAt( 0 ), 20.0 );
    3238                 :          1 :   QCOMPARE( fromVector.xAt( 1 ), 30.0 );
    3239                 :          1 :   QCOMPARE( fromVector.yAt( 1 ), 40.0 );
    3240                 :          1 :   QgsPointSequence ptsVector3D;
    3241                 :          1 :   ptsVector3D << QgsPoint( QgsWkbTypes::PointZ, 10, 20, 100 ) << QgsPoint( QgsWkbTypes::PointZ, 30, 40, 200 );
    3242                 :          1 :   QgsLineString fromVector3D( ptsVector3D );
    3243                 :          1 :   QCOMPARE( fromVector3D.wkbType(), QgsWkbTypes::LineStringZ );
    3244                 :          1 :   QCOMPARE( fromVector3D.numPoints(), 2 );
    3245                 :          1 :   QCOMPARE( fromVector3D.xAt( 0 ), 10.0 );
    3246                 :          1 :   QCOMPARE( fromVector3D.yAt( 0 ), 20.0 );
    3247                 :          1 :   QCOMPARE( fromVector3D.zAt( 0 ), 100.0 );
    3248                 :          1 :   QCOMPARE( fromVector3D.xAt( 1 ), 30.0 );
    3249                 :          1 :   QCOMPARE( fromVector3D.yAt( 1 ), 40.0 );
    3250                 :          1 :   QCOMPARE( fromVector3D.zAt( 1 ), 200.0 );
    3251                 :            : 
    3252                 :            :   // from 2 points
    3253                 :          1 :   QgsLineString from2Pts( QgsPoint( 1, 2 ), QgsPoint( 21, 22 ) );
    3254                 :          1 :   QCOMPARE( from2Pts.wkbType(), QgsWkbTypes::LineString );
    3255                 :          1 :   QCOMPARE( from2Pts.numPoints(), 2 );
    3256                 :          1 :   QCOMPARE( from2Pts.xAt( 0 ), 1.0 );
    3257                 :          1 :   QCOMPARE( from2Pts.yAt( 0 ), 2.0 );
    3258                 :          1 :   QCOMPARE( from2Pts.xAt( 1 ), 21.0 );
    3259                 :          1 :   QCOMPARE( from2Pts.yAt( 1 ), 22.0 );
    3260                 :          1 :   from2Pts = QgsLineString( QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ), QgsPoint( QgsWkbTypes::PointZ, 21, 22, 23 ) );
    3261                 :          1 :   QCOMPARE( from2Pts.wkbType(), QgsWkbTypes::LineStringZ );
    3262                 :          1 :   QCOMPARE( from2Pts.numPoints(), 2 );
    3263                 :          1 :   QCOMPARE( from2Pts.xAt( 0 ), 1.0 );
    3264                 :          1 :   QCOMPARE( from2Pts.yAt( 0 ), 2.0 );
    3265                 :          1 :   QCOMPARE( from2Pts.zAt( 0 ), 3.0 );
    3266                 :          1 :   QCOMPARE( from2Pts.xAt( 1 ), 21.0 );
    3267                 :          1 :   QCOMPARE( from2Pts.yAt( 1 ), 22.0 );
    3268                 :          1 :   QCOMPARE( from2Pts.zAt( 1 ), 23.0 );
    3269                 :          1 :   from2Pts = QgsLineString( QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 3 ), QgsPoint( QgsWkbTypes::PointM, 21, 22, 0, 23 ) );
    3270                 :          1 :   QCOMPARE( from2Pts.wkbType(), QgsWkbTypes::LineStringM );
    3271                 :          1 :   QCOMPARE( from2Pts.numPoints(), 2 );
    3272                 :          1 :   QCOMPARE( from2Pts.xAt( 0 ), 1.0 );
    3273                 :          1 :   QCOMPARE( from2Pts.yAt( 0 ), 2.0 );
    3274                 :          1 :   QCOMPARE( from2Pts.mAt( 0 ), 3.0 );
    3275                 :          1 :   QCOMPARE( from2Pts.xAt( 1 ), 21.0 );
    3276                 :          1 :   QCOMPARE( from2Pts.yAt( 1 ), 22.0 );
    3277                 :          1 :   QCOMPARE( from2Pts.mAt( 1 ), 23.0 );
    3278                 :          1 :   from2Pts = QgsLineString( QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ), QgsPoint( QgsWkbTypes::PointZM, 21, 22, 23, 24 ) );
    3279                 :          1 :   QCOMPARE( from2Pts.wkbType(), QgsWkbTypes::LineStringZM );
    3280                 :          1 :   QCOMPARE( from2Pts.numPoints(), 2 );
    3281                 :          1 :   QCOMPARE( from2Pts.xAt( 0 ), 1.0 );
    3282                 :          1 :   QCOMPARE( from2Pts.yAt( 0 ), 2.0 );
    3283                 :          1 :   QCOMPARE( from2Pts.zAt( 0 ), 3.0 );
    3284                 :          1 :   QCOMPARE( from2Pts.mAt( 0 ), 4.0 );
    3285                 :          1 :   QCOMPARE( from2Pts.xAt( 1 ), 21.0 );
    3286                 :          1 :   QCOMPARE( from2Pts.yAt( 1 ), 22.0 );
    3287                 :          1 :   QCOMPARE( from2Pts.zAt( 1 ), 23.0 );
    3288                 :          1 :   QCOMPARE( from2Pts.mAt( 1 ), 24.0 );
    3289                 :            : 
    3290                 :            :   // from lineSegment
    3291                 :          1 :   QgsLineString fromSegment( QgsLineSegment2D( QgsPointXY( 1, 2 ), QgsPointXY( 3, 4 ) ) );
    3292                 :          1 :   QCOMPARE( fromSegment.wkbType(), QgsWkbTypes::LineString );
    3293                 :          1 :   QCOMPARE( fromSegment.numPoints(), 2 );
    3294                 :          1 :   QCOMPARE( fromSegment.xAt( 0 ), 1.0 );
    3295                 :          1 :   QCOMPARE( fromSegment.yAt( 0 ), 2.0 );
    3296                 :          1 :   QCOMPARE( fromSegment.xAt( 1 ), 3.0 );
    3297                 :          1 :   QCOMPARE( fromSegment.yAt( 1 ), 4.0 );
    3298                 :            : 
    3299                 :            :   //addVertex
    3300                 :          1 :   QgsLineString l2;
    3301                 :          1 :   l2.addVertex( QgsPoint( 1.0, 2.0 ) );
    3302                 :          1 :   QVERIFY( !l2.isEmpty() );
    3303                 :          1 :   QCOMPARE( l2.numPoints(), 1 );
    3304                 :          1 :   QCOMPARE( l2.vertexCount(), 1 );
    3305                 :          1 :   QCOMPARE( l2.nCoordinates(), 1 );
    3306                 :          1 :   QCOMPARE( l2.ringCount(), 1 );
    3307                 :          1 :   QCOMPARE( l2.partCount(), 1 );
    3308                 :          1 :   QVERIFY( !l2.is3D() );
    3309                 :          1 :   QVERIFY( !l2.isMeasure() );
    3310                 :          1 :   QCOMPARE( l2.wkbType(), QgsWkbTypes::LineString );
    3311                 :          1 :   QVERIFY( !l2.hasCurvedSegments() );
    3312                 :          1 :   QCOMPARE( l2.area(), 0.0 );
    3313                 :          1 :   QCOMPARE( l2.perimeter(), 0.0 );
    3314                 :            : 
    3315                 :            :   //adding first vertex should set linestring z/m type
    3316                 :          1 :   QgsLineString l3;
    3317                 :          1 :   l3.addVertex( QgsPoint( QgsWkbTypes::PointZ, 1.0, 2.0, 3.0 ) );
    3318                 :          1 :   QVERIFY( !l3.isEmpty() );
    3319                 :          1 :   QVERIFY( l3.is3D() );
    3320                 :          1 :   QVERIFY( !l3.isMeasure() );
    3321                 :          1 :   QCOMPARE( l3.wkbType(), QgsWkbTypes::LineStringZ );
    3322                 :          1 :   QCOMPARE( l3.wktTypeStr(), QString( "LineStringZ" ) );
    3323                 :            : 
    3324                 :          1 :   QgsLineString l4;
    3325                 :          1 :   l4.addVertex( QgsPoint( QgsWkbTypes::PointM, 1.0, 2.0, 0.0, 3.0 ) );
    3326                 :          1 :   QVERIFY( !l4.isEmpty() );
    3327                 :          1 :   QVERIFY( !l4.is3D() );
    3328                 :          1 :   QVERIFY( l4.isMeasure() );
    3329                 :          1 :   QCOMPARE( l4.wkbType(), QgsWkbTypes::LineStringM );
    3330                 :          1 :   QCOMPARE( l4.wktTypeStr(), QString( "LineStringM" ) );
    3331                 :            : 
    3332                 :          1 :   QgsLineString l5;
    3333                 :          1 :   l5.addVertex( QgsPoint( QgsWkbTypes::PointZM, 1.0, 2.0, 3.0, 4.0 ) );
    3334                 :          1 :   QVERIFY( !l5.isEmpty() );
    3335                 :          1 :   QVERIFY( l5.is3D() );
    3336                 :          1 :   QVERIFY( l5.isMeasure() );
    3337                 :          1 :   QCOMPARE( l5.wkbType(), QgsWkbTypes::LineStringZM );
    3338                 :          1 :   QCOMPARE( l5.wktTypeStr(), QString( "LineStringZM" ) );
    3339                 :            : 
    3340                 :          1 :   QgsLineString l25d;
    3341                 :          1 :   l25d.addVertex( QgsPoint( QgsWkbTypes::Point25D, 1.0, 2.0, 3.0 ) );
    3342                 :          1 :   QVERIFY( !l25d.isEmpty() );
    3343                 :          1 :   QVERIFY( l25d.is3D() );
    3344                 :          1 :   QVERIFY( !l25d.isMeasure() );
    3345                 :          1 :   QCOMPARE( l25d.wkbType(), QgsWkbTypes::LineString25D );
    3346                 :          1 :   QCOMPARE( l25d.wktTypeStr(), QString( "LineStringZ" ) );
    3347                 :            : 
    3348                 :            :   //adding subsequent vertices should not alter z/m type, regardless of points type
    3349                 :          1 :   QgsLineString l6;
    3350                 :          1 :   l6.addVertex( QgsPoint( QgsWkbTypes::Point, 1.0, 2.0 ) ); //2d type
    3351                 :          1 :   QCOMPARE( l6.wkbType(), QgsWkbTypes::LineString );
    3352                 :          1 :   l6.addVertex( QgsPoint( QgsWkbTypes::PointZ, 11.0, 12.0, 13.0 ) ); // add 3d point
    3353                 :          1 :   QCOMPARE( l6.numPoints(), 2 );
    3354                 :          1 :   QCOMPARE( l6.vertexCount(), 2 );
    3355                 :          1 :   QCOMPARE( l6.nCoordinates(), 2 );
    3356                 :          1 :   QCOMPARE( l6.ringCount(), 1 );
    3357                 :          1 :   QCOMPARE( l6.partCount(), 1 );
    3358                 :          1 :   QCOMPARE( l6.wkbType(), QgsWkbTypes::LineString ); //should still be 2d
    3359                 :          1 :   QVERIFY( !l6.is3D() );
    3360                 :          1 :   QCOMPARE( l6.area(), 0.0 );
    3361                 :          1 :   QCOMPARE( l6.perimeter(), 0.0 );
    3362                 :            : 
    3363                 :          1 :   QgsLineString l7;
    3364                 :          1 :   l7.addVertex( QgsPoint( QgsWkbTypes::PointZ, 1.0, 2.0, 3.0 ) ); //3d type
    3365                 :          1 :   QCOMPARE( l7.wkbType(), QgsWkbTypes::LineStringZ );
    3366                 :          1 :   l7.addVertex( QgsPoint( QgsWkbTypes::Point, 11.0, 12.0 ) ); //add 2d point
    3367                 :          1 :   QCOMPARE( l7.wkbType(), QgsWkbTypes::LineStringZ ); //should still be 3d
    3368                 :          1 :   QCOMPARE( l7.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZ, 11.0, 12.0 ) );
    3369                 :          1 :   QVERIFY( l7.is3D() );
    3370                 :          1 :   QCOMPARE( l7.numPoints(), 2 );
    3371                 :          1 :   QCOMPARE( l7.vertexCount(), 2 );
    3372                 :          1 :   QCOMPARE( l7.nCoordinates(), 2 );
    3373                 :          1 :   QCOMPARE( l7.ringCount(), 1 );
    3374                 :          1 :   QCOMPARE( l7.partCount(), 1 );
    3375                 :            : 
    3376                 :            :   //clear
    3377                 :          1 :   l7.clear();
    3378                 :          1 :   QVERIFY( l7.isEmpty() );
    3379                 :          1 :   QCOMPARE( l7.numPoints(), 0 );
    3380                 :          1 :   QCOMPARE( l7.vertexCount(), 0 );
    3381                 :          1 :   QCOMPARE( l7.nCoordinates(), 0 );
    3382                 :          1 :   QCOMPARE( l7.ringCount(), 0 );
    3383                 :          1 :   QCOMPARE( l7.partCount(), 0 );
    3384                 :          1 :   QVERIFY( !l7.is3D() );
    3385                 :          1 :   QVERIFY( !l7.isMeasure() );
    3386                 :          1 :   QCOMPARE( l7.wkbType(), QgsWkbTypes::LineString );
    3387                 :            : 
    3388                 :            :   //setPoints
    3389                 :          1 :   QgsLineString l8;
    3390                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 2, 3 ) << QgsPoint( 3, 4 ) );
    3391                 :          1 :   QVERIFY( !l8.isEmpty() );
    3392                 :          1 :   QCOMPARE( l8.numPoints(), 3 );
    3393                 :          1 :   QCOMPARE( l8.vertexCount(), 3 );
    3394                 :          1 :   QCOMPARE( l8.nCoordinates(), 3 );
    3395                 :          1 :   QCOMPARE( l8.ringCount(), 1 );
    3396                 :          1 :   QCOMPARE( l8.partCount(), 1 );
    3397                 :          1 :   QVERIFY( !l8.is3D() );
    3398                 :          1 :   QVERIFY( !l8.isMeasure() );
    3399                 :          1 :   QCOMPARE( l8.wkbType(), QgsWkbTypes::LineString );
    3400                 :          1 :   QVERIFY( !l8.hasCurvedSegments() );
    3401                 :          1 :   QgsPointSequence pts;
    3402                 :          1 :   l8.points( pts );
    3403                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 2, 3 ) << QgsPoint( 3, 4 ) );
    3404                 :          1 :   QCOMPARE( *l8.xData(), 1.0 );
    3405                 :          1 :   QCOMPARE( *( l8.xData() + 1 ), 2.0 );
    3406                 :          1 :   QCOMPARE( *( l8.xData() + 2 ), 3.0 );
    3407                 :          1 :   QCOMPARE( *l8.yData(), 2.0 );
    3408                 :          1 :   QCOMPARE( *( l8.yData() + 1 ), 3.0 );
    3409                 :          1 :   QCOMPARE( *( l8.yData() + 2 ), 4.0 );
    3410                 :            : 
    3411                 :            :   //setPoints with empty list, should clear linestring
    3412                 :          1 :   l8.setPoints( QgsPointSequence() );
    3413                 :          1 :   QVERIFY( l8.isEmpty() );
    3414                 :          1 :   QCOMPARE( l8.numPoints(), 0 );
    3415                 :          1 :   QCOMPARE( l8.vertexCount(), 0 );
    3416                 :          1 :   QCOMPARE( l8.nCoordinates(), 0 );
    3417                 :          1 :   QCOMPARE( l8.ringCount(), 0 );
    3418                 :          1 :   QCOMPARE( l8.partCount(), 0 );
    3419                 :          1 :   QCOMPARE( l8.wkbType(), QgsWkbTypes::LineString );
    3420                 :          1 :   l8.points( pts );
    3421                 :          1 :   QVERIFY( pts.isEmpty() );
    3422                 :            : 
    3423                 :            :   //setPoints with z
    3424                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 2, 3, 4 ) );
    3425                 :          1 :   QCOMPARE( l8.numPoints(), 2 );
    3426                 :          1 :   QVERIFY( l8.is3D() );
    3427                 :          1 :   QVERIFY( !l8.isMeasure() );
    3428                 :          1 :   QCOMPARE( l8.wkbType(), QgsWkbTypes::LineStringZ );
    3429                 :          1 :   l8.points( pts );
    3430                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 2, 3, 4 ) );
    3431                 :            : 
    3432                 :            :   //setPoints with 25d
    3433                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point25D, 1, 2, 4 ) << QgsPoint( QgsWkbTypes::Point25D, 2, 3, 4 ) );
    3434                 :          1 :   QCOMPARE( l8.numPoints(), 2 );
    3435                 :          1 :   QVERIFY( l8.is3D() );
    3436                 :          1 :   QVERIFY( !l8.isMeasure() );
    3437                 :          1 :   QCOMPARE( l8.wkbType(), QgsWkbTypes::LineString25D );
    3438                 :          1 :   QCOMPARE( l8.pointN( 0 ), QgsPoint( QgsWkbTypes::Point25D, 1, 2, 4 ) );
    3439                 :          1 :   l8.points( pts );
    3440                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::Point25D, 1, 2, 4 ) << QgsPoint( QgsWkbTypes::Point25D, 2, 3, 4 ) );
    3441                 :            : 
    3442                 :            :   //setPoints with m
    3443                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 3 ) << QgsPoint( QgsWkbTypes::PointM, 2, 3, 0, 4 ) );
    3444                 :          1 :   QCOMPARE( l8.numPoints(), 2 );
    3445                 :          1 :   QVERIFY( !l8.is3D() );
    3446                 :          1 :   QVERIFY( l8.isMeasure() );
    3447                 :          1 :   QCOMPARE( l8.wkbType(), QgsWkbTypes::LineStringM );
    3448                 :          1 :   l8.points( pts );
    3449                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 3 ) << QgsPoint( QgsWkbTypes::PointM, 2, 3, 0, 4 ) );
    3450                 :            : 
    3451                 :            :   //setPoints with zm
    3452                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 4, 5 ) << QgsPoint( QgsWkbTypes::PointZM, 2, 3, 4, 5 ) );
    3453                 :          1 :   QCOMPARE( l8.numPoints(), 2 );
    3454                 :          1 :   QVERIFY( l8.is3D() );
    3455                 :          1 :   QVERIFY( l8.isMeasure() );
    3456                 :          1 :   QCOMPARE( l8.wkbType(), QgsWkbTypes::LineStringZM );
    3457                 :          1 :   l8.points( pts );
    3458                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 4, 5 ) << QgsPoint( QgsWkbTypes::PointZM, 2, 3, 4, 5 ) );
    3459                 :            : 
    3460                 :            :   //setPoints with MIXED dimensionality of points
    3461                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 4, 5 ) << QgsPoint( QgsWkbTypes::PointM, 2, 3, 0, 5 ) );
    3462                 :          1 :   QCOMPARE( l8.numPoints(), 2 );
    3463                 :          1 :   QVERIFY( l8.is3D() );
    3464                 :          1 :   QVERIFY( l8.isMeasure() );
    3465                 :          1 :   QCOMPARE( l8.wkbType(), QgsWkbTypes::LineStringZM );
    3466                 :          1 :   l8.points( pts );
    3467                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 4, 5 ) << QgsPoint( QgsWkbTypes::PointZM, 2, 3, 0, 5 ) );
    3468                 :            : 
    3469                 :            :   //test point
    3470                 :          1 :   QCOMPARE( l8.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 4, 5 ) );
    3471                 :          1 :   QCOMPARE( l8.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 2, 3, 0, 5 ) );
    3472                 :            : 
    3473                 :            :   //out of range - just want no crash here
    3474                 :          1 :   QgsPoint bad = l8.pointN( -1 );
    3475                 :          1 :   bad = l8.pointN( 100 );
    3476                 :            : 
    3477                 :            :   //test getters/setters
    3478                 :          1 :   QgsLineString l9;
    3479                 :          2 :   l9.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
    3480                 :          1 :                 << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 )
    3481                 :          1 :                 << QgsPoint( QgsWkbTypes::PointZM, 21, 22, 23, 24 ) );
    3482                 :          1 :   QCOMPARE( l9.xAt( 0 ), 1.0 );
    3483                 :          1 :   QCOMPARE( l9.xAt( 1 ), 11.0 );
    3484                 :          1 :   QCOMPARE( l9.xAt( 2 ), 21.0 );
    3485                 :          1 :   QCOMPARE( l9.xAt( -1 ), 0.0 ); //out of range
    3486                 :          1 :   QCOMPARE( l9.xAt( 11 ), 0.0 ); //out of range
    3487                 :            : 
    3488                 :          1 :   l9.setXAt( 0, 51.0 );
    3489                 :          1 :   QCOMPARE( l9.xAt( 0 ), 51.0 );
    3490                 :          1 :   l9.setXAt( 1, 61.0 );
    3491                 :          1 :   QCOMPARE( l9.xAt( 1 ), 61.0 );
    3492                 :          1 :   l9.setXAt( -1, 51.0 ); //out of range
    3493                 :          1 :   l9.setXAt( 11, 51.0 ); //out of range
    3494                 :            : 
    3495                 :          1 :   QCOMPARE( l9.yAt( 0 ), 2.0 );
    3496                 :          1 :   QCOMPARE( l9.yAt( 1 ), 12.0 );
    3497                 :          1 :   QCOMPARE( l9.yAt( 2 ), 22.0 );
    3498                 :          1 :   QCOMPARE( l9.yAt( -1 ), 0.0 ); //out of range
    3499                 :          1 :   QCOMPARE( l9.yAt( 11 ), 0.0 ); //out of range
    3500                 :            : 
    3501                 :          1 :   l9.setYAt( 0, 52.0 );
    3502                 :          1 :   QCOMPARE( l9.yAt( 0 ), 52.0 );
    3503                 :          1 :   l9.setYAt( 1, 62.0 );
    3504                 :          1 :   QCOMPARE( l9.yAt( 1 ), 62.0 );
    3505                 :          1 :   l9.setYAt( -1, 52.0 ); //out of range
    3506                 :          1 :   l9.setYAt( 11, 52.0 ); //out of range
    3507                 :            : 
    3508                 :          1 :   QCOMPARE( l9.zAt( 0 ), 3.0 );
    3509                 :          1 :   QCOMPARE( l9.zAt( 1 ), 13.0 );
    3510                 :          1 :   QCOMPARE( l9.zAt( 2 ), 23.0 );
    3511                 :          1 :   QVERIFY( std::isnan( l9.zAt( -1 ) ) ); //out of range
    3512                 :          1 :   QVERIFY( std::isnan( l9.zAt( 11 ) ) ); //out of range
    3513                 :            : 
    3514                 :          1 :   l9.setZAt( 0, 53.0 );
    3515                 :          1 :   QCOMPARE( l9.zAt( 0 ), 53.0 );
    3516                 :          1 :   l9.setZAt( 1, 63.0 );
    3517                 :          1 :   QCOMPARE( l9.zAt( 1 ), 63.0 );
    3518                 :          1 :   l9.setZAt( -1, 53.0 ); //out of range
    3519                 :          1 :   l9.setZAt( 11, 53.0 ); //out of range
    3520                 :            : 
    3521                 :          1 :   QCOMPARE( l9.mAt( 0 ), 4.0 );
    3522                 :          1 :   QCOMPARE( l9.mAt( 1 ), 14.0 );
    3523                 :          1 :   QCOMPARE( l9.mAt( 2 ), 24.0 );
    3524                 :          1 :   QVERIFY( std::isnan( l9.mAt( -1 ) ) ); //out of range
    3525                 :          1 :   QVERIFY( std::isnan( l9.mAt( 11 ) ) ); //out of range
    3526                 :            : 
    3527                 :          1 :   l9.setMAt( 0, 54.0 );
    3528                 :          1 :   QCOMPARE( l9.mAt( 0 ), 54.0 );
    3529                 :          1 :   l9.setMAt( 1, 64.0 );
    3530                 :          1 :   QCOMPARE( l9.mAt( 1 ), 64.0 );
    3531                 :          1 :   l9.setMAt( -1, 54.0 ); //out of range
    3532                 :          1 :   l9.setMAt( 11, 54.0 ); //out of range
    3533                 :            : 
    3534                 :            :   //check zAt/setZAt with non-3d linestring
    3535                 :          2 :   l9.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 )
    3536                 :          1 :                 << QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 14 )
    3537                 :          1 :                 << QgsPoint( QgsWkbTypes::PointM, 21, 22, 0, 24 ) );
    3538                 :            : 
    3539                 :            :   //basically we just don't want these to crash
    3540                 :          1 :   QVERIFY( std::isnan( l9.zAt( 0 ) ) );
    3541                 :          1 :   QVERIFY( std::isnan( l9.zAt( 1 ) ) );
    3542                 :          1 :   l9.setZAt( 0, 53.0 );
    3543                 :          1 :   l9.setZAt( 1, 63.0 );
    3544                 :            : 
    3545                 :            :   //check mAt/setMAt with non-measure linestring
    3546                 :          2 :   l9.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
    3547                 :          1 :                 << QgsPoint( 11, 12 )
    3548                 :          1 :                 << QgsPoint( 21, 22 ) );
    3549                 :            : 
    3550                 :            :   //basically we just don't want these to crash
    3551                 :          1 :   QVERIFY( std::isnan( l9.mAt( 0 ) ) );
    3552                 :          1 :   QVERIFY( std::isnan( l9.mAt( 1 ) ) );
    3553                 :          1 :   l9.setMAt( 0, 53.0 );
    3554                 :          1 :   l9.setMAt( 1, 63.0 );
    3555                 :            : 
    3556                 :            :   //append linestring
    3557                 :            : 
    3558                 :            :   //append to empty
    3559                 :          1 :   QgsLineString l10;
    3560                 :          1 :   l10.append( nullptr );
    3561                 :          1 :   QVERIFY( l10.isEmpty() );
    3562                 :          1 :   QCOMPARE( l10.numPoints(), 0 );
    3563                 :            : 
    3564                 :          1 :   std::unique_ptr<QgsLineString> toAppend( new QgsLineString() );
    3565                 :          2 :   toAppend->setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
    3566                 :          1 :                        << QgsPoint( 11, 12 )
    3567                 :          1 :                        << QgsPoint( 21, 22 ) );
    3568                 :          1 :   l10.append( toAppend.get() );
    3569                 :          1 :   QVERIFY( !l10.is3D() );
    3570                 :          1 :   QVERIFY( !l10.isMeasure() );
    3571                 :          1 :   QCOMPARE( l10.numPoints(), 3 );
    3572                 :          1 :   QCOMPARE( l10.vertexCount(), 3 );
    3573                 :          1 :   QCOMPARE( l10.nCoordinates(), 3 );
    3574                 :          1 :   QCOMPARE( l10.ringCount(), 1 );
    3575                 :          1 :   QCOMPARE( l10.partCount(), 1 );
    3576                 :          1 :   QCOMPARE( l10.wkbType(), QgsWkbTypes::LineString );
    3577                 :          1 :   QCOMPARE( l10.pointN( 0 ), toAppend->pointN( 0 ) );
    3578                 :          1 :   QCOMPARE( l10.pointN( 1 ), toAppend->pointN( 1 ) );
    3579                 :          1 :   QCOMPARE( l10.pointN( 2 ), toAppend->pointN( 2 ) );
    3580                 :            : 
    3581                 :            :   //add more points
    3582                 :          1 :   toAppend.reset( new QgsLineString() );
    3583                 :          2 :   toAppend->setPoints( QgsPointSequence() << QgsPoint( 31, 32 )
    3584                 :          1 :                        << QgsPoint( 41, 42 )
    3585                 :          1 :                        << QgsPoint( 51, 52 ) );
    3586                 :          1 :   l10.append( toAppend.get() );
    3587                 :          1 :   QCOMPARE( l10.numPoints(), 6 );
    3588                 :          1 :   QCOMPARE( l10.vertexCount(), 6 );
    3589                 :          1 :   QCOMPARE( l10.nCoordinates(), 6 );
    3590                 :          1 :   QCOMPARE( l10.ringCount(), 1 );
    3591                 :          1 :   QCOMPARE( l10.partCount(), 1 );
    3592                 :          1 :   QCOMPARE( l10.pointN( 3 ), toAppend->pointN( 0 ) );
    3593                 :          1 :   QCOMPARE( l10.pointN( 4 ), toAppend->pointN( 1 ) );
    3594                 :          1 :   QCOMPARE( l10.pointN( 5 ), toAppend->pointN( 2 ) );
    3595                 :            : 
    3596                 :            :   //check dimensionality is inherited from append line if initially empty
    3597                 :          1 :   l10.clear();
    3598                 :          1 :   toAppend.reset( new QgsLineString() );
    3599                 :          2 :   toAppend->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 31, 32, 33, 34 )
    3600                 :          1 :                        << QgsPoint( QgsWkbTypes::PointZM, 41, 42, 43, 44 )
    3601                 :          1 :                        << QgsPoint( QgsWkbTypes::PointZM, 51, 52, 53, 54 ) );
    3602                 :          1 :   l10.append( toAppend.get() );
    3603                 :          1 :   QVERIFY( l10.is3D() );
    3604                 :          1 :   QVERIFY( l10.isMeasure() );
    3605                 :          1 :   QCOMPARE( l10.numPoints(), 3 );
    3606                 :          1 :   QCOMPARE( l10.ringCount(), 1 );
    3607                 :          1 :   QCOMPARE( l10.partCount(), 1 );
    3608                 :          1 :   QCOMPARE( l10.wkbType(), QgsWkbTypes::LineStringZM );
    3609                 :          1 :   QCOMPARE( l10.pointN( 0 ), toAppend->pointN( 0 ) );
    3610                 :          1 :   QCOMPARE( l10.pointN( 1 ), toAppend->pointN( 1 ) );
    3611                 :          1 :   QCOMPARE( l10.pointN( 2 ), toAppend->pointN( 2 ) );
    3612                 :            : 
    3613                 :            :   //append points with z to non z linestring
    3614                 :          1 :   l10.clear();
    3615                 :          1 :   l10.addVertex( QgsPoint( 1.0, 2.0 ) );
    3616                 :          1 :   QVERIFY( !l10.is3D() );
    3617                 :          1 :   QCOMPARE( l10.wkbType(), QgsWkbTypes::LineString );
    3618                 :          1 :   toAppend.reset( new QgsLineString() );
    3619                 :          2 :   toAppend->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 31, 32, 33, 34 )
    3620                 :          1 :                        << QgsPoint( QgsWkbTypes::PointZM, 41, 42, 43, 44 )
    3621                 :          1 :                        << QgsPoint( QgsWkbTypes::PointZM, 51, 52, 53, 54 ) );
    3622                 :          1 :   l10.append( toAppend.get() );
    3623                 :          1 :   QCOMPARE( l10.wkbType(), QgsWkbTypes::LineString );
    3624                 :          1 :   QCOMPARE( l10.pointN( 0 ), QgsPoint( 1, 2 ) );
    3625                 :          1 :   QCOMPARE( l10.pointN( 1 ), QgsPoint( 31, 32 ) );
    3626                 :          1 :   QCOMPARE( l10.pointN( 2 ), QgsPoint( 41, 42 ) );
    3627                 :          1 :   QCOMPARE( l10.pointN( 3 ), QgsPoint( 51, 52 ) );
    3628                 :            : 
    3629                 :            :   //append points without z/m to linestring with z & m
    3630                 :          1 :   l10.clear();
    3631                 :          1 :   l10.addVertex( QgsPoint( QgsWkbTypes::PointZM, 1.0, 2.0, 3.0, 4.0 ) );
    3632                 :          1 :   QVERIFY( l10.is3D() );
    3633                 :          1 :   QVERIFY( l10.isMeasure() );
    3634                 :          1 :   QCOMPARE( l10.wkbType(), QgsWkbTypes::LineStringZM );
    3635                 :          1 :   toAppend.reset( new QgsLineString() );
    3636                 :          2 :   toAppend->setPoints( QgsPointSequence() << QgsPoint( 31, 32 )
    3637                 :          1 :                        << QgsPoint( 41, 42 )
    3638                 :          1 :                        << QgsPoint( 51, 52 ) );
    3639                 :          1 :   l10.append( toAppend.get() );
    3640                 :          1 :   QCOMPARE( l10.wkbType(), QgsWkbTypes::LineStringZM );
    3641                 :          1 :   QCOMPARE( l10.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) );
    3642                 :          1 :   QCOMPARE( l10.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 31, 32 ) );
    3643                 :          1 :   QCOMPARE( l10.pointN( 2 ), QgsPoint( QgsWkbTypes::PointZM, 41, 42 ) );
    3644                 :          1 :   QCOMPARE( l10.pointN( 3 ), QgsPoint( QgsWkbTypes::PointZM, 51, 52 ) );
    3645                 :            : 
    3646                 :            :   //25d append
    3647                 :          1 :   l10.clear();
    3648                 :          1 :   toAppend.reset( new QgsLineString() );
    3649                 :          2 :   toAppend->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point25D, 31, 32, 33 )
    3650                 :          1 :                        << QgsPoint( QgsWkbTypes::Point25D, 41, 42, 43 ) );
    3651                 :          1 :   l10.append( toAppend.get() );
    3652                 :          1 :   QVERIFY( l10.is3D() );
    3653                 :          1 :   QVERIFY( !l10.isMeasure() );
    3654                 :          1 :   QCOMPARE( l10.wkbType(), QgsWkbTypes::LineString25D );
    3655                 :          1 :   QCOMPARE( l10.pointN( 0 ), QgsPoint( QgsWkbTypes::Point25D, 31, 32, 33 ) );
    3656                 :          1 :   QCOMPARE( l10.pointN( 1 ), QgsPoint( QgsWkbTypes::Point25D, 41, 42, 43 ) );
    3657                 :          1 :   l10.clear();
    3658                 :          1 :   l10.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point25D, 11, 12, 33 ) );
    3659                 :          1 :   QCOMPARE( l10.wkbType(), QgsWkbTypes::LineString25D );
    3660                 :          1 :   l10.append( toAppend.get() );
    3661                 :          1 :   QVERIFY( l10.is3D() );
    3662                 :          1 :   QVERIFY( !l10.isMeasure() );
    3663                 :          1 :   QCOMPARE( l10.wkbType(), QgsWkbTypes::LineString25D );
    3664                 :          1 :   QCOMPARE( l10.pointN( 0 ), QgsPoint( QgsWkbTypes::Point25D, 11, 12, 33 ) );
    3665                 :          1 :   QCOMPARE( l10.pointN( 1 ), QgsPoint( QgsWkbTypes::Point25D, 31, 32, 33 ) );
    3666                 :          1 :   QCOMPARE( l10.pointN( 2 ), QgsPoint( QgsWkbTypes::Point25D, 41, 42, 43 ) );
    3667                 :            : 
    3668                 :            :   //append another line the closes the original geometry.
    3669                 :            :   //Make sure there are not duplicit points except start and end point
    3670                 :          1 :   l10.clear();
    3671                 :          1 :   toAppend.reset( new QgsLineString() );
    3672                 :          2 :   toAppend->setPoints( QgsPointSequence()
    3673                 :          1 :                        << QgsPoint( 1, 1 )
    3674                 :          1 :                        << QgsPoint( 5, 5 )
    3675                 :          1 :                        << QgsPoint( 10, 1 ) );
    3676                 :          1 :   l10.append( toAppend.get() );
    3677                 :          1 :   QCOMPARE( l10.numPoints(), 3 );
    3678                 :          1 :   QCOMPARE( l10.vertexCount(), 3 );
    3679                 :          1 :   toAppend.reset( new QgsLineString() );
    3680                 :          2 :   toAppend->setPoints( QgsPointSequence()
    3681                 :          1 :                        << QgsPoint( 10, 1 )
    3682                 :          1 :                        << QgsPoint( 1, 1 ) );
    3683                 :          1 :   l10.append( toAppend.get() );
    3684                 :            : 
    3685                 :          1 :   QVERIFY( l10.isClosed() );
    3686                 :          1 :   QCOMPARE( l10.numPoints(), 4 );
    3687                 :          1 :   QCOMPARE( l10.vertexCount(), 4 );
    3688                 :            : 
    3689                 :            :   //equality
    3690                 :          1 :   QgsLineString e1;
    3691                 :          1 :   QgsLineString e2;
    3692                 :          1 :   QVERIFY( e1 == e2 );
    3693                 :          1 :   QVERIFY( !( e1 != e2 ) );
    3694                 :          1 :   e1.addVertex( QgsPoint( 1, 2 ) );
    3695                 :          1 :   QVERIFY( !( e1 == e2 ) ); //different number of vertices
    3696                 :          1 :   QVERIFY( e1 != e2 );
    3697                 :          1 :   e2.addVertex( QgsPoint( 1, 2 ) );
    3698                 :          1 :   QVERIFY( e1 == e2 );
    3699                 :          1 :   QVERIFY( !( e1 != e2 ) );
    3700                 :          1 :   e1.addVertex( QgsPoint( 1 / 3.0, 4 / 3.0 ) );
    3701                 :          1 :   e2.addVertex( QgsPoint( 2 / 6.0, 8 / 6.0 ) );
    3702                 :          1 :   QVERIFY( e1 == e2 ); //check non-integer equality
    3703                 :          1 :   QVERIFY( !( e1 != e2 ) );
    3704                 :          1 :   e1.addVertex( QgsPoint( 7, 8 ) );
    3705                 :          1 :   e2.addVertex( QgsPoint( 6, 9 ) );
    3706                 :          1 :   QVERIFY( !( e1 == e2 ) ); //different coordinates
    3707                 :          1 :   QVERIFY( e1 != e2 );
    3708                 :          1 :   QgsLineString e3;
    3709                 :          2 :   e3.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 0 )
    3710                 :          1 :                 << QgsPoint( QgsWkbTypes::PointZ, 1 / 3.0, 4 / 3.0, 0 )
    3711                 :          1 :                 << QgsPoint( QgsWkbTypes::PointZ, 7, 8, 0 ) );
    3712                 :          1 :   QVERIFY( !( e1 == e3 ) ); //different dimension
    3713                 :          1 :   QVERIFY( e1 != e3 );
    3714                 :          1 :   QgsLineString e4;
    3715                 :          2 :   e4.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 )
    3716                 :          1 :                 << QgsPoint( QgsWkbTypes::PointZ, 1 / 3.0, 4 / 3.0, 3 )
    3717                 :          1 :                 << QgsPoint( QgsWkbTypes::PointZ, 7, 8, 4 ) );
    3718                 :          1 :   QVERIFY( !( e3 == e4 ) ); //different z coordinates
    3719                 :          1 :   QVERIFY( e3 != e4 );
    3720                 :          1 :   QgsLineString e5;
    3721                 :          2 :   e5.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 1 )
    3722                 :          1 :                 << QgsPoint( QgsWkbTypes::PointM, 1 / 3.0, 4 / 3.0, 0, 2 )
    3723                 :          1 :                 << QgsPoint( QgsWkbTypes::PointM, 7, 8, 0, 3 ) );
    3724                 :          1 :   QgsLineString e6;
    3725                 :          2 :   e6.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 11 )
    3726                 :          1 :                 << QgsPoint( QgsWkbTypes::PointM, 1 / 3.0, 4 / 3.0, 0, 12 )
    3727                 :          1 :                 << QgsPoint( QgsWkbTypes::PointM, 7, 8, 0, 13 ) );
    3728                 :          1 :   QVERIFY( !( e5 == e6 ) ); //different m values
    3729                 :          1 :   QVERIFY( e5 != e6 );
    3730                 :            : 
    3731                 :          1 :   QVERIFY( e6 != QgsCircularString() );
    3732                 :          1 :   QgsPoint p1;
    3733                 :          1 :   QVERIFY( !( e6 == p1 ) );
    3734                 :          1 :   QVERIFY( e6 != p1 );
    3735                 :          1 :   QVERIFY( e6 == e6 );
    3736                 :            : 
    3737                 :            :   //close/isClosed
    3738                 :          1 :   QgsLineString l11;
    3739                 :          1 :   QVERIFY( !l11.isClosed() );
    3740                 :          2 :   l11.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
    3741                 :          1 :                  << QgsPoint( 11, 2 )
    3742                 :          1 :                  << QgsPoint( 11, 22 )
    3743                 :          1 :                  << QgsPoint( 1, 22 ) );
    3744                 :          1 :   QVERIFY( !l11.isClosed() );
    3745                 :          1 :   QCOMPARE( l11.numPoints(), 4 );
    3746                 :          1 :   QCOMPARE( l11.area(), 0.0 );
    3747                 :          1 :   QCOMPARE( l11.perimeter(), 0.0 );
    3748                 :          1 :   l11.close();
    3749                 :          1 :   QVERIFY( l11.isClosed() );
    3750                 :          1 :   QCOMPARE( l11.numPoints(), 5 );
    3751                 :          1 :   QCOMPARE( l11.vertexCount(), 5 );
    3752                 :          1 :   QCOMPARE( l11.nCoordinates(), 5 );
    3753                 :          1 :   QCOMPARE( l11.ringCount(), 1 );
    3754                 :          1 :   QCOMPARE( l11.partCount(), 1 );
    3755                 :          1 :   QCOMPARE( l11.pointN( 4 ), QgsPoint( 1, 2 ) );
    3756                 :          1 :   QCOMPARE( l11.area(), 0.0 );
    3757                 :          1 :   QCOMPARE( l11.perimeter(), 0.0 );
    3758                 :            :   //try closing already closed line, should be no change
    3759                 :          1 :   l11.close();
    3760                 :          1 :   QVERIFY( l11.isClosed() );
    3761                 :          1 :   QCOMPARE( l11.numPoints(), 5 );
    3762                 :          1 :   QCOMPARE( l11.pointN( 4 ), QgsPoint( 1, 2 ) );
    3763                 :            : 
    3764                 :            :   // tiny differences
    3765                 :          2 :   l11.setPoints( QgsPointSequence() << QgsPoint( 0.000000000000001, 0.000000000000002 )
    3766                 :          1 :                  << QgsPoint( 0.000000000000011, 0.000000000000002 )
    3767                 :          1 :                  << QgsPoint( 0.000000000000011, 0.000000000000022 )
    3768                 :          1 :                  << QgsPoint( 0.000000000000001, 0.000000000000022 ) );
    3769                 :          1 :   QVERIFY( !l11.isClosed() );
    3770                 :          1 :   l11.close();
    3771                 :          1 :   QVERIFY( l11.isClosed() );
    3772                 :          1 :   QCOMPARE( l11.numPoints(), 5 );
    3773                 :          1 :   QGSCOMPARENEAR( l11.pointN( 4 ).x(), 0.000000000000001, 0.00000000000000001 );
    3774                 :          1 :   QGSCOMPARENEAR( l11.pointN( 4 ).y(), 0.000000000000002, 0.00000000000000001 );
    3775                 :            : 
    3776                 :            :   //test that m values aren't considered when testing for closedness
    3777                 :          2 :   l11.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 3 )
    3778                 :          1 :                  << QgsPoint( QgsWkbTypes::PointM, 11, 2, 0, 4 )
    3779                 :          1 :                  << QgsPoint( QgsWkbTypes::PointM, 11, 22, 0, 5 )
    3780                 :          1 :                  << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 6 ) );
    3781                 :          1 :   QVERIFY( l11.isClosed() );
    3782                 :            : 
    3783                 :            :   //close with z and m
    3784                 :          1 :   QgsLineString l12;
    3785                 :          2 :   l12.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
    3786                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 2, 11, 14 )
    3787                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 22, 21, 24 )
    3788                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 22, 31, 34 ) );
    3789                 :          1 :   l12.close();
    3790                 :          1 :   QCOMPARE( l12.pointN( 4 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) );
    3791                 :            : 
    3792                 :            : 
    3793                 :            :   //polygonf
    3794                 :          1 :   QgsLineString l13;
    3795                 :          2 :   l13.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
    3796                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 2, 11, 14 )
    3797                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 22, 21, 24 )
    3798                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 22, 31, 34 ) );
    3799                 :            : 
    3800                 :          1 :   QPolygonF poly = l13.asQPolygonF();
    3801                 :          1 :   QCOMPARE( poly.count(), 4 );
    3802                 :          1 :   QCOMPARE( poly.at( 0 ).x(), 1.0 );
    3803                 :          1 :   QCOMPARE( poly.at( 0 ).y(), 2.0 );
    3804                 :          1 :   QCOMPARE( poly.at( 1 ).x(), 11.0 );
    3805                 :          1 :   QCOMPARE( poly.at( 1 ).y(), 2.0 );
    3806                 :          1 :   QCOMPARE( poly.at( 2 ).x(), 11.0 );
    3807                 :          1 :   QCOMPARE( poly.at( 2 ).y(), 22.0 );
    3808                 :          1 :   QCOMPARE( poly.at( 3 ).x(), 1.0 );
    3809                 :          1 :   QCOMPARE( poly.at( 3 ).y(), 22.0 );
    3810                 :            : 
    3811                 :            :   // clone tests. At the same time, check segmentize as the result should
    3812                 :            :   // be equal to a clone for LineStrings
    3813                 :          1 :   QgsLineString l14;
    3814                 :          2 :   l14.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
    3815                 :          1 :                  << QgsPoint( 11, 2 )
    3816                 :          1 :                  << QgsPoint( 11, 22 )
    3817                 :          1 :                  << QgsPoint( 1, 22 ) );
    3818                 :          1 :   std::unique_ptr<QgsLineString> cloned( l14.clone() );
    3819                 :          1 :   QCOMPARE( cloned->numPoints(), 4 );
    3820                 :          1 :   QCOMPARE( cloned->vertexCount(), 4 );
    3821                 :          1 :   QCOMPARE( cloned->ringCount(), 1 );
    3822                 :          1 :   QCOMPARE( cloned->partCount(), 1 );
    3823                 :          1 :   QCOMPARE( cloned->wkbType(), QgsWkbTypes::LineString );
    3824                 :          1 :   QVERIFY( !cloned->is3D() );
    3825                 :          1 :   QVERIFY( !cloned->isMeasure() );
    3826                 :          1 :   QCOMPARE( cloned->pointN( 0 ), l14.pointN( 0 ) );
    3827                 :          1 :   QCOMPARE( cloned->pointN( 1 ), l14.pointN( 1 ) );
    3828                 :          1 :   QCOMPARE( cloned->pointN( 2 ), l14.pointN( 2 ) );
    3829                 :          1 :   QCOMPARE( cloned->pointN( 3 ), l14.pointN( 3 ) );
    3830                 :          1 :   std::unique_ptr< QgsLineString > segmentized( static_cast< QgsLineString * >( l14.segmentize() ) );
    3831                 :          1 :   QCOMPARE( segmentized->numPoints(), 4 );
    3832                 :          1 :   QCOMPARE( segmentized->wkbType(), QgsWkbTypes::LineString );
    3833                 :          1 :   QVERIFY( !segmentized->is3D() );
    3834                 :          1 :   QVERIFY( !segmentized->isMeasure() );
    3835                 :          1 :   QCOMPARE( segmentized->pointN( 0 ), l14.pointN( 0 ) );
    3836                 :          1 :   QCOMPARE( segmentized->pointN( 1 ), l14.pointN( 1 ) );
    3837                 :          1 :   QCOMPARE( segmentized->pointN( 2 ), l14.pointN( 2 ) );
    3838                 :          1 :   QCOMPARE( segmentized->pointN( 3 ), l14.pointN( 3 ) );
    3839                 :            : 
    3840                 :            :   //clone with Z/M
    3841                 :          2 :   l14.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
    3842                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 2, 11, 14 )
    3843                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 22, 21, 24 )
    3844                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 22, 31, 34 ) );
    3845                 :          1 :   cloned.reset( l14.clone() );
    3846                 :          1 :   QCOMPARE( cloned->numPoints(), 4 );
    3847                 :          1 :   QCOMPARE( cloned->wkbType(), QgsWkbTypes::LineStringZM );
    3848                 :          1 :   QVERIFY( cloned->is3D() );
    3849                 :          1 :   QVERIFY( cloned->isMeasure() );
    3850                 :          1 :   QCOMPARE( cloned->pointN( 0 ), l14.pointN( 0 ) );
    3851                 :          1 :   QCOMPARE( cloned->pointN( 1 ), l14.pointN( 1 ) );
    3852                 :          1 :   QCOMPARE( cloned->pointN( 2 ), l14.pointN( 2 ) );
    3853                 :          1 :   QCOMPARE( cloned->pointN( 3 ), l14.pointN( 3 ) );
    3854                 :          1 :   segmentized.reset( static_cast< QgsLineString * >( l14.segmentize() ) );
    3855                 :          1 :   QCOMPARE( segmentized->numPoints(), 4 );
    3856                 :          1 :   QCOMPARE( segmentized->wkbType(), QgsWkbTypes::LineStringZM );
    3857                 :          1 :   QVERIFY( segmentized->is3D() );
    3858                 :          1 :   QVERIFY( segmentized->isMeasure() );
    3859                 :          1 :   QCOMPARE( segmentized->pointN( 0 ), l14.pointN( 0 ) );
    3860                 :          1 :   QCOMPARE( segmentized->pointN( 1 ), l14.pointN( 1 ) );
    3861                 :          1 :   QCOMPARE( segmentized->pointN( 2 ), l14.pointN( 2 ) );
    3862                 :          1 :   QCOMPARE( segmentized->pointN( 3 ), l14.pointN( 3 ) );
    3863                 :            : 
    3864                 :            :   //clone an empty line
    3865                 :          1 :   l14.clear();
    3866                 :          1 :   cloned.reset( l14.clone() );
    3867                 :          1 :   QVERIFY( cloned->isEmpty() );
    3868                 :          1 :   QCOMPARE( cloned->numPoints(), 0 );
    3869                 :          1 :   QVERIFY( !cloned->is3D() );
    3870                 :          1 :   QVERIFY( !cloned->isMeasure() );
    3871                 :          1 :   QCOMPARE( cloned->wkbType(), QgsWkbTypes::LineString );
    3872                 :          1 :   segmentized.reset( static_cast< QgsLineString * >( l14.segmentize() ) );
    3873                 :          1 :   QVERIFY( segmentized->isEmpty() );
    3874                 :          1 :   QCOMPARE( segmentized->numPoints(), 0 );
    3875                 :          1 :   QVERIFY( !segmentized->is3D() );
    3876                 :          1 :   QVERIFY( !segmentized->isMeasure() );
    3877                 :          1 :   QCOMPARE( segmentized->wkbType(), QgsWkbTypes::LineString );
    3878                 :            : 
    3879                 :            :   //to/from WKB
    3880                 :          1 :   QgsLineString l15;
    3881                 :          2 :   l15.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
    3882                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 2, 11, 14 )
    3883                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 22, 21, 24 )
    3884                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 22, 31, 34 ) );
    3885                 :          1 :   QByteArray wkb15 = l15.asWkb();
    3886                 :          1 :   QCOMPARE( wkb15.size(), l15.wkbSize() );
    3887                 :          1 :   QgsLineString l16;
    3888                 :          1 :   QgsConstWkbPtr wkb15ptr( wkb15 );
    3889                 :          1 :   l16.fromWkb( wkb15ptr );
    3890                 :          1 :   QCOMPARE( l16.numPoints(), 4 );
    3891                 :          1 :   QCOMPARE( l16.vertexCount(), 4 );
    3892                 :          1 :   QCOMPARE( l16.nCoordinates(), 4 );
    3893                 :          1 :   QCOMPARE( l16.ringCount(), 1 );
    3894                 :          1 :   QCOMPARE( l16.partCount(), 1 );
    3895                 :          1 :   QCOMPARE( l16.wkbType(), QgsWkbTypes::LineStringZM );
    3896                 :          1 :   QVERIFY( l16.is3D() );
    3897                 :          1 :   QVERIFY( l16.isMeasure() );
    3898                 :          1 :   QCOMPARE( l16.pointN( 0 ), l15.pointN( 0 ) );
    3899                 :          1 :   QCOMPARE( l16.pointN( 1 ), l15.pointN( 1 ) );
    3900                 :          1 :   QCOMPARE( l16.pointN( 2 ), l15.pointN( 2 ) );
    3901                 :          1 :   QCOMPARE( l16.pointN( 3 ), l15.pointN( 3 ) );
    3902                 :            : 
    3903                 :            :   //bad WKB - check for no crash
    3904                 :          1 :   l16.clear();
    3905                 :          1 :   QgsConstWkbPtr nullPtr( nullptr, 0 );
    3906                 :          1 :   QVERIFY( !l16.fromWkb( nullPtr ) );
    3907                 :          1 :   QCOMPARE( l16.wkbType(), QgsWkbTypes::LineString );
    3908                 :          1 :   QgsPoint point( 1, 2 );
    3909                 :          1 :   QByteArray wkb16 = point.asWkb();
    3910                 :          1 :   QgsConstWkbPtr wkb16ptr( wkb16 );
    3911                 :          1 :   QVERIFY( !l16.fromWkb( wkb16ptr ) );
    3912                 :          1 :   QCOMPARE( l16.wkbType(), QgsWkbTypes::LineString );
    3913                 :            : 
    3914                 :            :   //to/from WKT
    3915                 :          1 :   QgsLineString l17;
    3916                 :          2 :   l17.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
    3917                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 2, 11, 14 )
    3918                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 22, 21, 24 )
    3919                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 22, 31, 34 ) );
    3920                 :            : 
    3921                 :          1 :   QString wkt = l17.asWkt();
    3922                 :          1 :   QVERIFY( !wkt.isEmpty() );
    3923                 :          1 :   QgsLineString l18;
    3924                 :          1 :   QVERIFY( l18.fromWkt( wkt ) );
    3925                 :          1 :   QCOMPARE( l18.numPoints(), 4 );
    3926                 :          1 :   QCOMPARE( l18.wkbType(), QgsWkbTypes::LineStringZM );
    3927                 :          1 :   QVERIFY( l18.is3D() );
    3928                 :          1 :   QVERIFY( l18.isMeasure() );
    3929                 :          1 :   QCOMPARE( l18.pointN( 0 ), l17.pointN( 0 ) );
    3930                 :          1 :   QCOMPARE( l18.pointN( 1 ), l17.pointN( 1 ) );
    3931                 :          1 :   QCOMPARE( l18.pointN( 2 ), l17.pointN( 2 ) );
    3932                 :          1 :   QCOMPARE( l18.pointN( 3 ), l17.pointN( 3 ) );
    3933                 :            : 
    3934                 :            :   //bad WKT
    3935                 :          1 :   QVERIFY( !l18.fromWkt( "Polygon()" ) );
    3936                 :          1 :   QVERIFY( l18.isEmpty() );
    3937                 :          1 :   QCOMPARE( l18.numPoints(), 0 );
    3938                 :          1 :   QVERIFY( !l18.is3D() );
    3939                 :          1 :   QVERIFY( !l18.isMeasure() );
    3940                 :          1 :   QCOMPARE( l18.wkbType(), QgsWkbTypes::LineString );
    3941                 :            : 
    3942                 :            :   //asGML2
    3943                 :          1 :   QgsLineString exportLine;
    3944                 :          2 :   exportLine.setPoints( QgsPointSequence() << QgsPoint( 31, 32 )
    3945                 :          1 :                         << QgsPoint( 41, 42 )
    3946                 :          1 :                         << QgsPoint( 51, 52 ) );
    3947                 :          1 :   QgsLineString exportLineFloat;
    3948                 :          2 :   exportLineFloat.setPoints( QgsPointSequence() << QgsPoint( 1 / 3.0, 2 / 3.0 )
    3949                 :          1 :                              << QgsPoint( 1 + 1 / 3.0, 1 + 2 / 3.0 )
    3950                 :          1 :                              << QgsPoint( 2 + 1 / 3.0, 2 + 2 / 3.0 ) );
    3951                 :          2 :   QDomDocument doc( QStringLiteral( "gml" ) );
    3952                 :          2 :   QString expectedGML2( QStringLiteral( "<LineString xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">31,32 41,42 51,52</coordinates></LineString>" ) );
    3953                 :          3 :   QGSCOMPAREGML( elemToString( exportLine.asGml2( doc ) ), expectedGML2 );
    3954                 :          2 :   QString expectedGML2prec3( QStringLiteral( "<LineString xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">0.333,0.667 1.333,1.667 2.333,2.667</coordinates></LineString>" ) );
    3955                 :          3 :   QGSCOMPAREGML( elemToString( exportLineFloat.asGml2( doc, 3 ) ), expectedGML2prec3 );
    3956                 :          2 :   QString expectedGML2empty( QStringLiteral( "<LineString xmlns=\"gml\"/>" ) );
    3957                 :          3 :   QGSCOMPAREGML( elemToString( QgsLineString().asGml2( doc ) ), expectedGML2empty );
    3958                 :            : 
    3959                 :            :   //asGML3
    3960                 :          2 :   QString expectedGML3( QStringLiteral( "<LineString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">31 32 41 42 51 52</posList></LineString>" ) );
    3961                 :          1 :   QCOMPARE( elemToString( exportLine.asGml3( doc ) ), expectedGML3 );
    3962                 :          2 :   QString expectedGML3prec3( QStringLiteral( "<LineString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">0.333 0.667 1.333 1.667 2.333 2.667</posList></LineString>" ) );
    3963                 :          1 :   QCOMPARE( elemToString( exportLineFloat.asGml3( doc, 3 ) ), expectedGML3prec3 );
    3964                 :          2 :   QString expectedGML3empty( QStringLiteral( "<LineString xmlns=\"gml\"/>" ) );
    3965                 :          3 :   QGSCOMPAREGML( elemToString( QgsLineString().asGml3( doc ) ), expectedGML3empty );
    3966                 :            : 
    3967                 :            :   //asJSON
    3968                 :          1 :   QString expectedJson( "{\"coordinates\":[[31.0,32.0],[41.0,42.0],[51.0,52.0]],\"type\":\"LineString\"}" );
    3969                 :          1 :   QCOMPARE( exportLine.asJson(), expectedJson );
    3970                 :          1 :   QString expectedJsonPrec3( "{\"coordinates\":[[0.333,0.667],[1.333,1.667],[2.333,2.667]],\"type\":\"LineString\"}" );
    3971                 :          1 :   QCOMPARE( exportLineFloat.asJson( 3 ), expectedJsonPrec3 );
    3972                 :            : 
    3973                 :            :   //asKML
    3974                 :          2 :   QString expectedKml( QStringLiteral( "<LineString><altitudeMode>clampToGround</altitudeMode><coordinates>31,32,0 41,42,0 51,52,0</coordinates></LineString>" ) );
    3975                 :          1 :   QCOMPARE( exportLine.asKml(), expectedKml );
    3976                 :          2 :   QString expectedKmlPrec3( QStringLiteral( "<LineString><altitudeMode>clampToGround</altitudeMode><coordinates>0.333,0.667,0 1.333,1.667,0 2.333,2.667,0</coordinates></LineString>" ) );
    3977                 :          1 :   QCOMPARE( exportLineFloat.asKml( 3 ), expectedKmlPrec3 );
    3978                 :            : 
    3979                 :            :   //length
    3980                 :          1 :   QgsLineString l19;
    3981                 :          1 :   QCOMPARE( l19.length(), 0.0 );
    3982                 :          2 :   l19.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 )
    3983                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 10, 4, 5 )
    3984                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 ) );
    3985                 :          1 :   QCOMPARE( l19.length(), 23.0 );
    3986                 :            : 
    3987                 :            :   //startPoint
    3988                 :          1 :   QCOMPARE( l19.startPoint(), QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 ) );
    3989                 :            : 
    3990                 :            :   //endPoint
    3991                 :          1 :   QCOMPARE( l19.endPoint(), QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 ) );
    3992                 :            : 
    3993                 :            :   //test 3d length
    3994                 :            :   // without vertices
    3995                 :          1 :   l19.clear();
    3996                 :          1 :   QCOMPARE( l19.length3D(), 0.0 );
    3997                 :            : 
    3998                 :            :   // without Z
    3999                 :          1 :   l19.clear();
    4000                 :          2 :   l19.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 0, 0 )
    4001                 :          1 :                  << QgsPoint( QgsWkbTypes::Point, 3, 4 )
    4002                 :          1 :                  << QgsPoint( QgsWkbTypes::Point, 8, 16 ) );
    4003                 :          1 :   QCOMPARE( l19.length3D(), 18.0 );
    4004                 :            : 
    4005                 :            :   // with z
    4006                 :          1 :   l19.clear();
    4007                 :          2 :   l19.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 0 )
    4008                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 )
    4009                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZ, 4, 6, 2 ) );
    4010                 :          1 :   QCOMPARE( l19.length3D(), 8.0 );
    4011                 :            : 
    4012                 :            :   // with z and m
    4013                 :          1 :   l19.clear();
    4014                 :          2 :   l19.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 0, 0 )
    4015                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 13 )
    4016                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 4, 6, 2, 7 ) );
    4017                 :          1 :   QCOMPARE( l19.length3D(), 8.0 );
    4018                 :            : 
    4019                 :            :   //bad start/end points. Test that this doesn't crash.
    4020                 :          1 :   l19.clear();
    4021                 :          1 :   QVERIFY( l19.startPoint().isEmpty() );
    4022                 :          1 :   QVERIFY( l19.endPoint().isEmpty() );
    4023                 :            : 
    4024                 :            :   //curveToLine - no segmentation required, so should return a clone
    4025                 :          2 :   l19.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 )
    4026                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 10, 4, 5 )
    4027                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 ) );
    4028                 :          1 :   segmentized.reset( l19.curveToLine() );
    4029                 :          1 :   QCOMPARE( segmentized->numPoints(), 3 );
    4030                 :          1 :   QCOMPARE( segmentized->wkbType(), QgsWkbTypes::LineStringZM );
    4031                 :          1 :   QVERIFY( segmentized->is3D() );
    4032                 :          1 :   QVERIFY( segmentized->isMeasure() );
    4033                 :          1 :   QCOMPARE( segmentized->pointN( 0 ), l19.pointN( 0 ) );
    4034                 :          1 :   QCOMPARE( segmentized->pointN( 1 ), l19.pointN( 1 ) );
    4035                 :          1 :   QCOMPARE( segmentized->pointN( 2 ), l19.pointN( 2 ) );
    4036                 :            : 
    4037                 :            :   // points
    4038                 :          1 :   QgsLineString l20;
    4039                 :          1 :   QgsPointSequence points;
    4040                 :          1 :   l20.points( points );
    4041                 :          1 :   QVERIFY( l20.isEmpty() );
    4042                 :          2 :   l20.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 )
    4043                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 10, 4, 5 )
    4044                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 ) );
    4045                 :          1 :   l20.points( points );
    4046                 :          1 :   QCOMPARE( points.count(), 3 );
    4047                 :          1 :   QCOMPARE( points.at( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 ) );
    4048                 :          1 :   QCOMPARE( points.at( 1 ), QgsPoint( QgsWkbTypes::PointZM, 1, 10, 4, 5 ) );
    4049                 :          1 :   QCOMPARE( points.at( 2 ), QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 ) );
    4050                 :            : 
    4051                 :            :   //CRS transform
    4052                 :          2 :   QgsCoordinateReferenceSystem sourceSrs( QStringLiteral( "EPSG:3994" ) );
    4053                 :          2 :   QgsCoordinateReferenceSystem destSrs( QStringLiteral( "EPSG:4202" ) );// want a transform with ellipsoid change
    4054                 :          1 :   QgsCoordinateTransform tr( sourceSrs, destSrs, QgsProject::instance() );
    4055                 :            : 
    4056                 :            :   // 2d CRS transform
    4057                 :          1 :   QgsLineString l21;
    4058                 :          2 :   l21.setPoints( QgsPointSequence() << QgsPoint( 6374985, -3626584 )
    4059                 :          1 :                  << QgsPoint( 6474985, -3526584 ) );
    4060                 :          1 :   l21.transform( tr, QgsCoordinateTransform::ForwardTransform );
    4061                 :          1 :   QGSCOMPARENEAR( l21.pointN( 0 ).x(), 175.771, 0.001 );
    4062                 :          1 :   QGSCOMPARENEAR( l21.pointN( 0 ).y(), -39.724, 0.001 );
    4063                 :          1 :   QGSCOMPARENEAR( l21.pointN( 1 ).x(), 176.959, 0.001 );
    4064                 :          1 :   QGSCOMPARENEAR( l21.pointN( 1 ).y(), -38.7999, 0.001 );
    4065                 :          1 :   QGSCOMPARENEAR( l21.boundingBox().xMinimum(), 175.771, 0.001 );
    4066                 :          1 :   QGSCOMPARENEAR( l21.boundingBox().yMinimum(), -39.724, 0.001 );
    4067                 :          1 :   QGSCOMPARENEAR( l21.boundingBox().xMaximum(), 176.959, 0.001 );
    4068                 :          1 :   QGSCOMPARENEAR( l21.boundingBox().yMaximum(), -38.7999, 0.001 );
    4069                 :            : 
    4070                 :            :   //3d CRS transform
    4071                 :          1 :   QgsLineString l22;
    4072                 :          2 :   l22.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 6374985, -3626584, 1, 2 )
    4073                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 6474985, -3526584, 3, 4 ) );
    4074                 :          1 :   l22.transform( tr, QgsCoordinateTransform::ForwardTransform );
    4075                 :          1 :   QGSCOMPARENEAR( l22.pointN( 0 ).x(), 175.771, 0.001 );
    4076                 :          1 :   QGSCOMPARENEAR( l22.pointN( 0 ).y(), -39.724, 0.001 );
    4077                 :          1 :   QGSCOMPARENEAR( l22.pointN( 0 ).z(), 1.0, 0.001 );
    4078                 :          1 :   QCOMPARE( l22.pointN( 0 ).m(), 2.0 );
    4079                 :          1 :   QGSCOMPARENEAR( l22.pointN( 1 ).x(), 176.959, 0.001 );
    4080                 :          1 :   QGSCOMPARENEAR( l22.pointN( 1 ).y(), -38.7999, 0.001 );
    4081                 :          1 :   QGSCOMPARENEAR( l22.pointN( 1 ).z(), 3.0, 0.001 );
    4082                 :          1 :   QCOMPARE( l22.pointN( 1 ).m(), 4.0 );
    4083                 :            : 
    4084                 :            :   //reverse transform
    4085                 :          1 :   l22.transform( tr, QgsCoordinateTransform::ReverseTransform );
    4086                 :          1 :   QGSCOMPARENEAR( l22.pointN( 0 ).x(), 6374985, 0.01 );
    4087                 :          1 :   QGSCOMPARENEAR( l22.pointN( 0 ).y(), -3626584, 0.01 );
    4088                 :          1 :   QGSCOMPARENEAR( l22.pointN( 0 ).z(), 1, 0.001 );
    4089                 :          1 :   QCOMPARE( l22.pointN( 0 ).m(), 2.0 );
    4090                 :          1 :   QGSCOMPARENEAR( l22.pointN( 1 ).x(), 6474985, 0.01 );
    4091                 :          1 :   QGSCOMPARENEAR( l22.pointN( 1 ).y(), -3526584, 0.01 );
    4092                 :          1 :   QGSCOMPARENEAR( l22.pointN( 1 ).z(), 3, 0.001 );
    4093                 :          1 :   QCOMPARE( l22.pointN( 1 ).m(), 4.0 );
    4094                 :            : 
    4095                 :            : #if PROJ_VERSION_MAJOR<6 // note - z value transform doesn't currently work with proj 6+, because we don't yet support compound CRS definitions
    4096                 :            :   //z value transform
    4097                 :            :   l22.transform( tr, QgsCoordinateTransform::ForwardTransform, true );
    4098                 :            :   QGSCOMPARENEAR( l22.pointN( 0 ).z(), -19.249066, 0.001 );
    4099                 :            :   QGSCOMPARENEAR( l22.pointN( 1 ).z(), -21.092128, 0.001 );
    4100                 :            :   l22.transform( tr, QgsCoordinateTransform::ReverseTransform, true );
    4101                 :            :   QGSCOMPARENEAR( l22.pointN( 0 ).z(), 1.0, 0.001 );
    4102                 :            :   QGSCOMPARENEAR( l22.pointN( 1 ).z(), 3.0, 0.001 );
    4103                 :            : #endif
    4104                 :            : 
    4105                 :            :   //QTransform transform
    4106                 :          1 :   QTransform qtr = QTransform::fromScale( 2, 3 );
    4107                 :          1 :   QgsLineString l23;
    4108                 :          2 :   l23.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
    4109                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
    4110                 :          1 :   l23.transform( qtr );
    4111                 :          1 :   QCOMPARE( l23.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 2, 6, 3, 4 ) );
    4112                 :          1 :   QCOMPARE( l23.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 22, 36, 13, 14 ) );
    4113                 :          1 :   QCOMPARE( l23.boundingBox(), QgsRectangle( 2, 6, 22, 36 ) );
    4114                 :            : 
    4115                 :          2 :   l23.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
    4116                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
    4117                 :          1 :   l23.transform( QTransform::fromScale( 1, 1 ), 3, 2, 4, 3 );
    4118                 :          1 :   QCOMPARE( l23.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 9, 16 ) );
    4119                 :          1 :   QCOMPARE( l23.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 29, 46 ) );
    4120                 :            : 
    4121                 :            :   //insert vertex
    4122                 :            : 
    4123                 :            :   //insert vertex in empty line
    4124                 :          1 :   QgsLineString l24;
    4125                 :          1 :   QVERIFY( l24.insertVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    4126                 :          1 :   QCOMPARE( l24.numPoints(), 1 );
    4127                 :          1 :   QVERIFY( !l24.is3D() );
    4128                 :          1 :   QVERIFY( !l24.isMeasure() );
    4129                 :          1 :   QCOMPARE( l24.wkbType(), QgsWkbTypes::LineString );
    4130                 :          1 :   QCOMPARE( l24.pointN( 0 ), QgsPoint( 6.0, 7.0 ) );
    4131                 :            : 
    4132                 :            :   //insert 4d vertex in empty line, should set line to 4d
    4133                 :          1 :   l24.clear();
    4134                 :          1 :   QVERIFY( l24.insertVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( QgsWkbTypes::PointZM, 6.0, 7.0, 1.0, 2.0 ) ) );
    4135                 :          1 :   QCOMPARE( l24.numPoints(), 1 );
    4136                 :          1 :   QVERIFY( l24.is3D() );
    4137                 :          1 :   QVERIFY( l24.isMeasure() );
    4138                 :          1 :   QCOMPARE( l24.wkbType(), QgsWkbTypes::LineStringZM );
    4139                 :          1 :   QCOMPARE( l24.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 6.0, 7.0, 1.0, 2.0 ) );
    4140                 :            : 
    4141                 :            :   //2d line
    4142                 :          2 :   l24.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
    4143                 :          1 :                  << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) );
    4144                 :          1 :   QVERIFY( l24.insertVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    4145                 :          1 :   QCOMPARE( l24.numPoints(), 4 );
    4146                 :          1 :   QVERIFY( !l24.is3D() );
    4147                 :          1 :   QVERIFY( !l24.isMeasure() );
    4148                 :          1 :   QCOMPARE( l24.wkbType(), QgsWkbTypes::LineString );
    4149                 :          1 :   QVERIFY( l24.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 8.0, 9.0 ) ) );
    4150                 :          1 :   QVERIFY( l24.insertVertex( QgsVertexId( 0, 0, 2 ), QgsPoint( 18.0, 19.0 ) ) );
    4151                 :          1 :   QCOMPARE( l24.pointN( 0 ), QgsPoint( 6.0, 7.0 ) );
    4152                 :          1 :   QCOMPARE( l24.pointN( 1 ), QgsPoint( 8.0, 9.0 ) );
    4153                 :          1 :   QCOMPARE( l24.pointN( 2 ), QgsPoint( 18.0, 19.0 ) );
    4154                 :          1 :   QCOMPARE( l24.pointN( 3 ), QgsPoint( 1.0, 2.0 ) );
    4155                 :          1 :   QCOMPARE( l24.pointN( 4 ), QgsPoint( 11.0, 12.0 ) );
    4156                 :          1 :   QCOMPARE( l24.pointN( 5 ), QgsPoint( 21.0, 22.0 ) );
    4157                 :            :   //insert vertex at end
    4158                 :          1 :   QVERIFY( l24.insertVertex( QgsVertexId( 0, 0, 6 ), QgsPoint( 31.0, 32.0 ) ) );
    4159                 :          1 :   QCOMPARE( l24.pointN( 6 ), QgsPoint( 31.0, 32.0 ) );
    4160                 :          1 :   QCOMPARE( l24.numPoints(), 7 );
    4161                 :            : 
    4162                 :            :   //insert vertex past end
    4163                 :          1 :   QVERIFY( !l24.insertVertex( QgsVertexId( 0, 0, 8 ), QgsPoint( 41.0, 42.0 ) ) );
    4164                 :          1 :   QCOMPARE( l24.numPoints(), 7 );
    4165                 :            : 
    4166                 :            :   //insert vertex before start
    4167                 :          1 :   QVERIFY( !l24.insertVertex( QgsVertexId( 0, 0, -18 ), QgsPoint( 41.0, 42.0 ) ) );
    4168                 :          1 :   QCOMPARE( l24.numPoints(), 7 );
    4169                 :            : 
    4170                 :            :   //insert 4d vertex in 4d line
    4171                 :          2 :   l24.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 )
    4172                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 10, 4, 5 )
    4173                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 ) );
    4174                 :          1 :   QVERIFY( l24.insertVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) ) );
    4175                 :          1 :   QCOMPARE( l24.numPoints(), 4 );
    4176                 :          1 :   QCOMPARE( l24.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
    4177                 :            : 
    4178                 :            :   //insert 2d vertex in 4d line
    4179                 :          1 :   QVERIFY( l24.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 101, 102 ) ) );
    4180                 :          1 :   QCOMPARE( l24.numPoints(), 5 );
    4181                 :          1 :   QCOMPARE( l24.wkbType(), QgsWkbTypes::LineStringZM );
    4182                 :          1 :   QCOMPARE( l24.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 101, 102 ) );
    4183                 :            : 
    4184                 :            :   //insert 4d vertex in 2d line
    4185                 :          2 :   l24.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
    4186                 :          1 :                  << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) );
    4187                 :          1 :   QVERIFY( l24.insertVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( QgsWkbTypes::PointZM, 101, 102, 103, 104 ) ) );
    4188                 :          1 :   QCOMPARE( l24.numPoints(), 4 );
    4189                 :          1 :   QCOMPARE( l24.wkbType(), QgsWkbTypes::LineString );
    4190                 :          1 :   QCOMPARE( l24.pointN( 0 ), QgsPoint( QgsWkbTypes::Point, 101, 102 ) );
    4191                 :            : 
    4192                 :            :   //insert first vertex as Point25D
    4193                 :          1 :   l24.clear();
    4194                 :          1 :   QVERIFY( l24.insertVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( QgsWkbTypes::Point25D, 101, 102, 103 ) ) );
    4195                 :          1 :   QCOMPARE( l24.wkbType(), QgsWkbTypes::LineString25D );
    4196                 :          1 :   QCOMPARE( l24.pointN( 0 ), QgsPoint( QgsWkbTypes::Point25D, 101, 102, 103 ) );
    4197                 :            : 
    4198                 :            :   //move vertex
    4199                 :            : 
    4200                 :            :   //empty line
    4201                 :          1 :   QgsLineString l25;
    4202                 :          1 :   QVERIFY( !l25.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    4203                 :          1 :   QVERIFY( l25.isEmpty() );
    4204                 :            : 
    4205                 :            :   //valid line
    4206                 :          2 :   l25.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
    4207                 :          1 :                  << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) );
    4208                 :          1 :   QVERIFY( l25.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    4209                 :          1 :   QVERIFY( l25.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 16.0, 17.0 ) ) );
    4210                 :          1 :   QVERIFY( l25.moveVertex( QgsVertexId( 0, 0, 2 ), QgsPoint( 26.0, 27.0 ) ) );
    4211                 :          1 :   QCOMPARE( l25.pointN( 0 ), QgsPoint( 6.0, 7.0 ) );
    4212                 :          1 :   QCOMPARE( l25.pointN( 1 ), QgsPoint( 16.0, 17.0 ) );
    4213                 :          1 :   QCOMPARE( l25.pointN( 2 ), QgsPoint( 26.0, 27.0 ) );
    4214                 :            : 
    4215                 :            :   //out of range
    4216                 :          1 :   QVERIFY( !l25.moveVertex( QgsVertexId( 0, 0, -1 ), QgsPoint( 3.0, 4.0 ) ) );
    4217                 :          1 :   QVERIFY( !l25.moveVertex( QgsVertexId( 0, 0, 10 ), QgsPoint( 3.0, 4.0 ) ) );
    4218                 :          1 :   QCOMPARE( l25.pointN( 0 ), QgsPoint( 6.0, 7.0 ) );
    4219                 :          1 :   QCOMPARE( l25.pointN( 1 ), QgsPoint( 16.0, 17.0 ) );
    4220                 :          1 :   QCOMPARE( l25.pointN( 2 ), QgsPoint( 26.0, 27.0 ) );
    4221                 :            : 
    4222                 :            :   //move 4d point in 4d line
    4223                 :          2 :   l25.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 )
    4224                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 10, 4, 5 )
    4225                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 ) );
    4226                 :          1 :   QVERIFY( l25.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( QgsWkbTypes::PointZM, 6, 7, 12, 13 ) ) );
    4227                 :          1 :   QCOMPARE( l25.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 6, 7, 12, 13 ) );
    4228                 :            : 
    4229                 :            :   //move 2d point in 4d line, existing z/m should be maintained
    4230                 :          1 :   QVERIFY( l25.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 34, 35 ) ) );
    4231                 :          1 :   QCOMPARE( l25.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 34, 35, 12, 13 ) );
    4232                 :            : 
    4233                 :            :   //move 4d point in 2d line
    4234                 :          2 :   l25.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
    4235                 :          1 :                  << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) );
    4236                 :          1 :   QVERIFY( l25.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( QgsWkbTypes::PointZM, 3, 4, 2, 3 ) ) );
    4237                 :          1 :   QCOMPARE( l25.pointN( 0 ), QgsPoint( 3, 4 ) );
    4238                 :            : 
    4239                 :            : 
    4240                 :            :   //delete vertex
    4241                 :            : 
    4242                 :            :   //empty line
    4243                 :          1 :   QgsLineString l26;
    4244                 :          1 :   QVERIFY( !l26.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
    4245                 :          1 :   QVERIFY( l26.isEmpty() );
    4246                 :            : 
    4247                 :            :   //valid line
    4248                 :          2 :   l26.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 )
    4249                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 )
    4250                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 21, 22, 6, 7 ) );
    4251                 :            :   //out of range vertices
    4252                 :          1 :   QVERIFY( !l26.deleteVertex( QgsVertexId( 0, 0, -1 ) ) );
    4253                 :          1 :   QVERIFY( !l26.deleteVertex( QgsVertexId( 0, 0, 100 ) ) );
    4254                 :            : 
    4255                 :            :   //valid vertices
    4256                 :          1 :   QVERIFY( l26.deleteVertex( QgsVertexId( 0, 0, 1 ) ) );
    4257                 :          1 :   QCOMPARE( l26.numPoints(), 2 );
    4258                 :          1 :   QCOMPARE( l26.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 ) );
    4259                 :          1 :   QCOMPARE( l26.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 21, 22, 6, 7 ) );
    4260                 :            :   //removing the second to last vertex removes both remaining vertices
    4261                 :          1 :   QVERIFY( l26.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
    4262                 :          1 :   QCOMPARE( l26.numPoints(), 0 );
    4263                 :          1 :   QVERIFY( !l26.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
    4264                 :          1 :   QVERIFY( l26.isEmpty() );
    4265                 :            : 
    4266                 :            :   //reversed
    4267                 :          1 :   QgsLineString l27;
    4268                 :          1 :   std::unique_ptr< QgsLineString > reversed( l27.reversed() );
    4269                 :          1 :   QVERIFY( reversed->isEmpty() );
    4270                 :          2 :   l27.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 )
    4271                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 )
    4272                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 21, 22, 6, 7 ) );
    4273                 :          1 :   reversed.reset( l27.reversed() );
    4274                 :          1 :   QCOMPARE( reversed->numPoints(), 3 );
    4275                 :          1 :   QCOMPARE( reversed->wkbType(), QgsWkbTypes::LineStringZM );
    4276                 :          1 :   QVERIFY( reversed->is3D() );
    4277                 :          1 :   QVERIFY( reversed->isMeasure() );
    4278                 :          1 :   QCOMPARE( reversed->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 21, 22, 6, 7 ) );
    4279                 :          1 :   QCOMPARE( reversed->pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 ) );
    4280                 :          1 :   QCOMPARE( reversed->pointN( 2 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 ) );
    4281                 :            : 
    4282                 :            :   //addZValue
    4283                 :            : 
    4284                 :          1 :   QgsLineString l28;
    4285                 :          1 :   QCOMPARE( l28.wkbType(), QgsWkbTypes::LineString );
    4286                 :          1 :   QVERIFY( l28.addZValue() );
    4287                 :          1 :   QCOMPARE( l28.wkbType(), QgsWkbTypes::LineStringZ );
    4288                 :          1 :   l28.clear();
    4289                 :          1 :   QVERIFY( l28.addZValue() );
    4290                 :          1 :   QCOMPARE( l28.wkbType(), QgsWkbTypes::LineStringZ );
    4291                 :            :   //2d line
    4292                 :          1 :   l28.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
    4293                 :          1 :   QVERIFY( l28.addZValue( 2 ) );
    4294                 :          1 :   QVERIFY( l28.is3D() );
    4295                 :          1 :   QCOMPARE( l28.wkbType(), QgsWkbTypes::LineStringZ );
    4296                 :          1 :   QCOMPARE( l28.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ) );
    4297                 :          1 :   QCOMPARE( l28.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZ, 11, 12, 2 ) );
    4298                 :          1 :   QVERIFY( !l28.addZValue( 4 ) ); //already has z value, test that existing z is unchanged
    4299                 :          1 :   QCOMPARE( l28.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ) );
    4300                 :          1 :   QCOMPARE( l28.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZ, 11, 12, 2 ) );
    4301                 :            :   //linestring with m
    4302                 :          1 :   l28.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 3 ) << QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 4 ) );
    4303                 :          1 :   QVERIFY( l28.addZValue( 5 ) );
    4304                 :          1 :   QVERIFY( l28.is3D() );
    4305                 :          1 :   QVERIFY( l28.isMeasure() );
    4306                 :          1 :   QCOMPARE( l28.wkbType(), QgsWkbTypes::LineStringZM );
    4307                 :          1 :   QCOMPARE( l28.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 5, 3 ) );
    4308                 :          1 :   QCOMPARE( l28.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 5, 4 ) );
    4309                 :            :   //linestring25d
    4310                 :          1 :   l28.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point25D, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::Point25D, 11, 12, 4 ) );
    4311                 :          1 :   QCOMPARE( l28.wkbType(), QgsWkbTypes::LineString25D );
    4312                 :          1 :   QVERIFY( !l28.addZValue( 5 ) );
    4313                 :          1 :   QCOMPARE( l28.wkbType(), QgsWkbTypes::LineString25D );
    4314                 :          1 :   QCOMPARE( l28.pointN( 0 ), QgsPoint( QgsWkbTypes::Point25D, 1, 2, 3 ) );
    4315                 :          1 :   QCOMPARE( l28.pointN( 1 ), QgsPoint( QgsWkbTypes::Point25D, 11, 12, 4 ) );
    4316                 :            : 
    4317                 :            :   //addMValue
    4318                 :            : 
    4319                 :          1 :   QgsLineString l29;
    4320                 :          1 :   QCOMPARE( l29.wkbType(), QgsWkbTypes::LineString );
    4321                 :          1 :   QVERIFY( l29.addMValue() );
    4322                 :          1 :   QCOMPARE( l29.wkbType(), QgsWkbTypes::LineStringM );
    4323                 :          1 :   l29.clear();
    4324                 :          1 :   QVERIFY( l29.addMValue() );
    4325                 :          1 :   QCOMPARE( l29.wkbType(), QgsWkbTypes::LineStringM );
    4326                 :            :   //2d line
    4327                 :          1 :   l29.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
    4328                 :          1 :   QVERIFY( l29.addMValue( 2 ) );
    4329                 :          1 :   QVERIFY( !l29.is3D() );
    4330                 :          1 :   QVERIFY( l29.isMeasure() );
    4331                 :          1 :   QCOMPARE( l29.wkbType(), QgsWkbTypes::LineStringM );
    4332                 :          1 :   QCOMPARE( l29.pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 2 ) );
    4333                 :          1 :   QCOMPARE( l29.pointN( 1 ), QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 2 ) );
    4334                 :          1 :   QVERIFY( !l29.addMValue( 4 ) ); //already has m value, test that existing m is unchanged
    4335                 :          1 :   QCOMPARE( l29.pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 2 ) );
    4336                 :          1 :   QCOMPARE( l29.pointN( 1 ), QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 2 ) );
    4337                 :            :   //linestring with z
    4338                 :          1 :   l29.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 11, 12, 4 ) );
    4339                 :          1 :   QVERIFY( l29.addMValue( 5 ) );
    4340                 :          1 :   QVERIFY( l29.is3D() );
    4341                 :          1 :   QVERIFY( l29.isMeasure() );
    4342                 :          1 :   QCOMPARE( l29.wkbType(), QgsWkbTypes::LineStringZM );
    4343                 :          1 :   QCOMPARE( l29.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 5 ) );
    4344                 :          1 :   QCOMPARE( l29.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 ) );
    4345                 :            :   //linestring25d, should become LineStringZM
    4346                 :          1 :   l29.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point25D, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::Point25D, 11, 12, 4 ) );
    4347                 :          1 :   QCOMPARE( l29.wkbType(), QgsWkbTypes::LineString25D );
    4348                 :          1 :   QVERIFY( l29.addMValue( 5 ) );
    4349                 :          1 :   QVERIFY( l29.is3D() );
    4350                 :          1 :   QVERIFY( l29.isMeasure() );
    4351                 :          1 :   QCOMPARE( l29.wkbType(), QgsWkbTypes::LineStringZM );
    4352                 :          1 :   QCOMPARE( l29.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 5 ) );
    4353                 :          1 :   QCOMPARE( l29.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 ) );
    4354                 :            : 
    4355                 :            : 
    4356                 :            :   //dropZValue
    4357                 :          1 :   QgsLineString l28d;
    4358                 :          1 :   QVERIFY( !l28d.dropZValue() );
    4359                 :          1 :   l28d.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
    4360                 :          1 :   QVERIFY( !l28d.dropZValue() );
    4361                 :          1 :   l28d.addZValue( 1.0 );
    4362                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::LineStringZ );
    4363                 :          1 :   QVERIFY( l28d.is3D() );
    4364                 :          1 :   QVERIFY( l28d.dropZValue() );
    4365                 :          1 :   QVERIFY( !l28d.is3D() );
    4366                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::LineString );
    4367                 :          1 :   QCOMPARE( l28d.pointN( 0 ), QgsPoint( QgsWkbTypes::Point, 1, 2 ) );
    4368                 :          1 :   QCOMPARE( l28d.pointN( 1 ), QgsPoint( QgsWkbTypes::Point, 11, 12 ) );
    4369                 :          1 :   QVERIFY( !l28d.dropZValue() ); //already dropped
    4370                 :            :   //linestring with m
    4371                 :          1 :   l28d.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 3, 4 ) );
    4372                 :          1 :   QVERIFY( l28d.dropZValue() );
    4373                 :          1 :   QVERIFY( !l28d.is3D() );
    4374                 :          1 :   QVERIFY( l28d.isMeasure() );
    4375                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::LineStringM );
    4376                 :          1 :   QCOMPARE( l28d.pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) );
    4377                 :          1 :   QCOMPARE( l28d.pointN( 1 ), QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 4 ) );
    4378                 :            :   //linestring25d
    4379                 :          1 :   l28d.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point25D, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::Point25D, 11, 12, 4 ) );
    4380                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::LineString25D );
    4381                 :          1 :   QVERIFY( l28d.dropZValue() );
    4382                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::LineString );
    4383                 :          1 :   QCOMPARE( l28d.pointN( 0 ), QgsPoint( QgsWkbTypes::Point, 1, 2 ) );
    4384                 :          1 :   QCOMPARE( l28d.pointN( 1 ), QgsPoint( QgsWkbTypes::Point, 11, 12 ) );
    4385                 :            : 
    4386                 :            :   //dropMValue
    4387                 :          1 :   l28d.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
    4388                 :          1 :   QVERIFY( !l28d.dropMValue() );
    4389                 :          1 :   l28d.addMValue( 1.0 );
    4390                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::LineStringM );
    4391                 :          1 :   QVERIFY( l28d.isMeasure() );
    4392                 :          1 :   QVERIFY( l28d.dropMValue() );
    4393                 :          1 :   QVERIFY( !l28d.isMeasure() );
    4394                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::LineString );
    4395                 :          1 :   QCOMPARE( l28d.pointN( 0 ), QgsPoint( QgsWkbTypes::Point, 1, 2 ) );
    4396                 :          1 :   QCOMPARE( l28d.pointN( 1 ), QgsPoint( QgsWkbTypes::Point, 11, 12 ) );
    4397                 :          1 :   QVERIFY( !l28d.dropMValue() ); //already dropped
    4398                 :            :   //linestring with z
    4399                 :          1 :   l28d.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 3, 4 ) );
    4400                 :          1 :   QVERIFY( l28d.dropMValue() );
    4401                 :          1 :   QVERIFY( !l28d.isMeasure() );
    4402                 :          1 :   QVERIFY( l28d.is3D() );
    4403                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::LineStringZ );
    4404                 :          1 :   QCOMPARE( l28d.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3, 0 ) );
    4405                 :          1 :   QCOMPARE( l28d.pointN( 1 ), QgsPoint( QgsWkbTypes::PointZ, 11, 12, 3, 0 ) );
    4406                 :            : 
    4407                 :            :   //convertTo
    4408                 :          1 :   l28d.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
    4409                 :          1 :   QVERIFY( l28d.convertTo( QgsWkbTypes::LineString ) );
    4410                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::LineString );
    4411                 :          1 :   QVERIFY( l28d.convertTo( QgsWkbTypes::LineStringZ ) );
    4412                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::LineStringZ );
    4413                 :          1 :   QCOMPARE( l28d.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2 ) );
    4414                 :          1 :   l28d.setZAt( 0, 5.0 );
    4415                 :          1 :   QVERIFY( l28d.convertTo( QgsWkbTypes::LineString25D ) );
    4416                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::LineString25D );
    4417                 :          1 :   QCOMPARE( l28d.pointN( 0 ), QgsPoint( QgsWkbTypes::Point25D, 1, 2, 5.0 ) );
    4418                 :          1 :   QVERIFY( l28d.convertTo( QgsWkbTypes::LineStringZM ) );
    4419                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::LineStringZM );
    4420                 :          1 :   QCOMPARE( l28d.pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 5.0 ) );
    4421                 :          1 :   l28d.setMAt( 0, 6.0 );
    4422                 :          1 :   QVERIFY( l28d.convertTo( QgsWkbTypes::LineStringM ) );
    4423                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::LineStringM );
    4424                 :          1 :   QCOMPARE( l28d.pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 1, 2, 0.0, 6.0 ) );
    4425                 :          1 :   QVERIFY( l28d.convertTo( QgsWkbTypes::LineString ) );
    4426                 :          1 :   QCOMPARE( l28d.wkbType(), QgsWkbTypes::LineString );
    4427                 :          1 :   QCOMPARE( l28d.pointN( 0 ), QgsPoint( 1, 2 ) );
    4428                 :          1 :   QVERIFY( !l28d.convertTo( QgsWkbTypes::Polygon ) );
    4429                 :            : 
    4430                 :            :   //isRing
    4431                 :          1 :   QgsLineString l30;
    4432                 :          1 :   QVERIFY( !l30.isRing() );
    4433                 :          1 :   l30.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 2 ) );
    4434                 :          1 :   QVERIFY( !l30.isRing() ); //<4 points
    4435                 :          1 :   l30.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) << QgsPoint( 31, 32 ) );
    4436                 :          1 :   QVERIFY( !l30.isRing() ); //not closed
    4437                 :          1 :   l30.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) << QgsPoint( 1, 2 ) );
    4438                 :          1 :   QVERIFY( l30.isRing() );
    4439                 :            : 
    4440                 :            :   //coordinateSequence
    4441                 :          1 :   QgsLineString l31;
    4442                 :          1 :   QgsCoordinateSequence coords = l31.coordinateSequence();
    4443                 :          1 :   QCOMPARE( coords.count(), 1 );
    4444                 :          1 :   QCOMPARE( coords.at( 0 ).count(), 1 );
    4445                 :          1 :   QVERIFY( coords.at( 0 ).at( 0 ).isEmpty() );
    4446                 :          2 :   l31.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 )
    4447                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 )
    4448                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 21, 22, 6, 7 ) );
    4449                 :          1 :   coords = l31.coordinateSequence();
    4450                 :          1 :   QCOMPARE( coords.count(), 1 );
    4451                 :          1 :   QCOMPARE( coords.at( 0 ).count(), 1 );
    4452                 :          1 :   QCOMPARE( coords.at( 0 ).at( 0 ).count(), 3 );
    4453                 :          1 :   QCOMPARE( coords.at( 0 ).at( 0 ).at( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 ) );
    4454                 :          1 :   QCOMPARE( coords.at( 0 ).at( 0 ).at( 1 ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 ) );
    4455                 :          1 :   QCOMPARE( coords.at( 0 ).at( 0 ).at( 2 ), QgsPoint( QgsWkbTypes::PointZM, 21, 22, 6, 7 ) );
    4456                 :            : 
    4457                 :            :   //nextVertex
    4458                 :            : 
    4459                 :          1 :   QgsLineString l32;
    4460                 :          1 :   QgsVertexId v;
    4461                 :          1 :   QgsPoint p;
    4462                 :          1 :   QVERIFY( !l32.nextVertex( v, p ) );
    4463                 :          1 :   v = QgsVertexId( 0, 0, -2 );
    4464                 :          1 :   QVERIFY( !l32.nextVertex( v, p ) );
    4465                 :          1 :   v = QgsVertexId( 0, 0, 10 );
    4466                 :          1 :   QVERIFY( !l32.nextVertex( v, p ) );
    4467                 :            : 
    4468                 :            :   // vertex iterator on empty linestring
    4469                 :          1 :   QgsAbstractGeometry::vertex_iterator it1 = l32.vertices_begin();
    4470                 :          1 :   QCOMPARE( it1, l32.vertices_end() );
    4471                 :            : 
    4472                 :            :   // Java-style iterator on empty linetring
    4473                 :          1 :   QgsVertexIterator it1x( &l32 );
    4474                 :          1 :   QVERIFY( !it1x.hasNext() );
    4475                 :            : 
    4476                 :            :   //LineString
    4477                 :          1 :   l32.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
    4478                 :          1 :   v = QgsVertexId( 0, 0, 2 ); //out of range
    4479                 :          1 :   QVERIFY( !l32.nextVertex( v, p ) );
    4480                 :          1 :   v = QgsVertexId( 0, 0, -5 );
    4481                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    4482                 :          1 :   v = QgsVertexId( 0, 0, -1 );
    4483                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    4484                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 0 ) );
    4485                 :          1 :   QCOMPARE( p, QgsPoint( 1, 2 ) );
    4486                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    4487                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    4488                 :          1 :   QCOMPARE( p, QgsPoint( 11, 12 ) );
    4489                 :          1 :   QVERIFY( !l32.nextVertex( v, p ) );
    4490                 :          1 :   v = QgsVertexId( 0, 1, 0 );
    4491                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    4492                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 1, 1 ) ); //test that ring number is maintained
    4493                 :          1 :   QCOMPARE( p, QgsPoint( 11, 12 ) );
    4494                 :          1 :   v = QgsVertexId( 1, 0, 0 );
    4495                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    4496                 :          1 :   QCOMPARE( v, QgsVertexId( 1, 0, 1 ) ); //test that part number is maintained
    4497                 :          1 :   QCOMPARE( p, QgsPoint( 11, 12 ) );
    4498                 :            : 
    4499                 :            :   // vertex iterator
    4500                 :          1 :   QgsAbstractGeometry::vertex_iterator it2 = l32.vertices_begin();
    4501                 :          1 :   QCOMPARE( *it2, QgsPoint( 1, 2 ) );
    4502                 :          1 :   QCOMPARE( it2.vertexId(), QgsVertexId( 0, 0, 0 ) );
    4503                 :          1 :   ++it2;
    4504                 :          1 :   QCOMPARE( *it2, QgsPoint( 11, 12 ) );
    4505                 :          1 :   QCOMPARE( it2.vertexId(), QgsVertexId( 0, 0, 1 ) );
    4506                 :          1 :   ++it2;
    4507                 :          1 :   QCOMPARE( it2, l32.vertices_end() );
    4508                 :            : 
    4509                 :            :   // Java-style iterator
    4510                 :          1 :   QgsVertexIterator it2x( &l32 );
    4511                 :          1 :   QVERIFY( it2x.hasNext() );
    4512                 :          1 :   QCOMPARE( it2x.next(), QgsPoint( 1, 2 ) );
    4513                 :          1 :   QVERIFY( it2x.hasNext() );
    4514                 :          1 :   QCOMPARE( it2x.next(), QgsPoint( 11, 12 ) );
    4515                 :          1 :   QVERIFY( !it2x.hasNext() );
    4516                 :            : 
    4517                 :            :   //LineStringZ
    4518                 :          1 :   l32.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 ) );
    4519                 :          1 :   v = QgsVertexId( 0, 0, -1 );
    4520                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    4521                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 0 ) );
    4522                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) );
    4523                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    4524                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    4525                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 ) );
    4526                 :          1 :   QVERIFY( !l32.nextVertex( v, p ) );
    4527                 :            : 
    4528                 :            :   //LineStringM
    4529                 :          1 :   l32.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 14 ) );
    4530                 :          1 :   v = QgsVertexId( 0, 0, -1 );
    4531                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    4532                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 0 ) );
    4533                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) );
    4534                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    4535                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    4536                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 14 ) );
    4537                 :          1 :   QVERIFY( !l32.nextVertex( v, p ) );
    4538                 :            :   //LineStringZM
    4539                 :          1 :   l32.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
    4540                 :          1 :   v = QgsVertexId( 0, 0, -1 );
    4541                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    4542                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 0 ) );
    4543                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) );
    4544                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    4545                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    4546                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
    4547                 :          1 :   QVERIFY( !l32.nextVertex( v, p ) );
    4548                 :            :   //LineString25D
    4549                 :          1 :   l32.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point25D, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::Point25D, 11, 12, 13 ) );
    4550                 :          1 :   v = QgsVertexId( 0, 0, -1 );
    4551                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    4552                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 0 ) );
    4553                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::Point25D, 1, 2, 3 ) );
    4554                 :          1 :   QVERIFY( l32.nextVertex( v, p ) );
    4555                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    4556                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::Point25D, 11, 12, 13 ) );
    4557                 :          1 :   QVERIFY( !l32.nextVertex( v, p ) );
    4558                 :            : 
    4559                 :            :   //vertexAt and pointAt
    4560                 :          1 :   QgsLineString l33;
    4561                 :          1 :   l33.vertexAt( QgsVertexId( 0, 0, -10 ) ); //out of bounds, check for no crash
    4562                 :          1 :   l33.vertexAt( QgsVertexId( 0, 0, 10 ) ); //out of bounds, check for no crash
    4563                 :            :   QgsVertexId::VertexType type;
    4564                 :          1 :   QVERIFY( !l33.pointAt( -10, p, type ) );
    4565                 :          1 :   QVERIFY( !l33.pointAt( 10, p, type ) );
    4566                 :            :   //LineString
    4567                 :          1 :   l33.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
    4568                 :          1 :   l33.vertexAt( QgsVertexId( 0, 0, -10 ) );
    4569                 :          1 :   l33.vertexAt( QgsVertexId( 0, 0, 10 ) ); //out of bounds, check for no crash
    4570                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( 1, 2 ) );
    4571                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( 11, 12 ) );
    4572                 :          1 :   QVERIFY( !l33.pointAt( -10, p, type ) );
    4573                 :          1 :   QVERIFY( !l33.pointAt( 10, p, type ) );
    4574                 :          1 :   QVERIFY( l33.pointAt( 0, p, type ) );
    4575                 :          1 :   QCOMPARE( p, QgsPoint( 1, 2 ) );
    4576                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
    4577                 :          1 :   QVERIFY( l33.pointAt( 1, p, type ) );
    4578                 :          1 :   QCOMPARE( p, QgsPoint( 11, 12 ) );
    4579                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
    4580                 :            :   //LineStringZ
    4581                 :          1 :   l33.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 ) );
    4582                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) );
    4583                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 ) );
    4584                 :          1 :   QVERIFY( l33.pointAt( 0, p, type ) );
    4585                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) );
    4586                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
    4587                 :          1 :   QVERIFY( l33.pointAt( 1, p, type ) );
    4588                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 ) );
    4589                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
    4590                 :            :   //LineStringM
    4591                 :          1 :   l33.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 14 ) );
    4592                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) );
    4593                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 14 ) );
    4594                 :          1 :   QVERIFY( l33.pointAt( 0, p, type ) );
    4595                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) );
    4596                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
    4597                 :          1 :   QVERIFY( l33.pointAt( 1, p, type ) );
    4598                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 14 ) );
    4599                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
    4600                 :            :   //LineStringZM
    4601                 :          1 :   l33.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
    4602                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) );
    4603                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
    4604                 :          1 :   QVERIFY( l33.pointAt( 0, p, type ) );
    4605                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) );
    4606                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
    4607                 :          1 :   QVERIFY( l33.pointAt( 1, p, type ) );
    4608                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
    4609                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
    4610                 :            :   //LineString25D
    4611                 :          1 :   l33.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point25D, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::Point25D, 11, 12, 13 ) );
    4612                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::Point25D, 1, 2, 3 ) );
    4613                 :          1 :   QCOMPARE( l33.vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( QgsWkbTypes::Point25D, 11, 12, 13 ) );
    4614                 :          1 :   QVERIFY( l33.pointAt( 0, p, type ) );
    4615                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::Point25D, 1, 2, 3 ) );
    4616                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
    4617                 :          1 :   QVERIFY( l33.pointAt( 1, p, type ) );
    4618                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::Point25D, 11, 12, 13 ) );
    4619                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
    4620                 :            : 
    4621                 :            :   //centroid
    4622                 :          1 :   QgsLineString l34;
    4623                 :          1 :   QVERIFY( l34.centroid().isEmpty() );
    4624                 :          1 :   l34.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) );
    4625                 :          1 :   QCOMPARE( l34.centroid(), QgsPoint( 5, 10 ) );
    4626                 :          1 :   l34.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 20, 10 ) );
    4627                 :          1 :   QCOMPARE( l34.centroid(), QgsPoint( 10, 5 ) );
    4628                 :          1 :   l34.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 9 ) << QgsPoint( 2, 9 ) << QgsPoint( 2, 0 ) );
    4629                 :          1 :   QCOMPARE( l34.centroid(), QgsPoint( 1, 4.95 ) );
    4630                 :            :   //linestring with 0 length segment
    4631                 :          1 :   l34.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 9 ) << QgsPoint( 2, 9 ) << QgsPoint( 2, 9 ) << QgsPoint( 2, 0 ) );
    4632                 :          1 :   QCOMPARE( l34.centroid(), QgsPoint( 1, 4.95 ) );
    4633                 :            :   //linestring with 0 total length segment
    4634                 :          1 :   l34.setPoints( QgsPointSequence() << QgsPoint( 5, 4 ) << QgsPoint( 5, 4 ) << QgsPoint( 5, 4 ) );
    4635                 :          1 :   QCOMPARE( l34.centroid(), QgsPoint( 5, 4 ) );
    4636                 :            : 
    4637                 :            :   //closest segment
    4638                 :          1 :   QgsLineString l35;
    4639                 :          1 :   int leftOf = 0;
    4640                 :          1 :   p = QgsPoint( 0, 0 ); // reset all coords to zero
    4641                 :          1 :   ( void )l35.closestSegment( QgsPoint( 1, 2 ), p, v ); //empty line, just want no crash
    4642                 :          1 :   l35.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) );
    4643                 :          1 :   QVERIFY( l35.closestSegment( QgsPoint( 5, 10 ), p, v ) < 0 );
    4644                 :          1 :   l35.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) << QgsPoint( 10, 10 ) );
    4645                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 4, 11 ), p, v, &leftOf ), 2.0, 4 * std::numeric_limits<double>::epsilon() );
    4646                 :          1 :   QCOMPARE( p, QgsPoint( 5, 10 ) );
    4647                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    4648                 :          1 :   QCOMPARE( leftOf, -1 );
    4649                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 8, 11 ), p, v, &leftOf ), 1.0, 4 * std::numeric_limits<double>::epsilon() );
    4650                 :          1 :   QCOMPARE( p, QgsPoint( 8, 10 ) );
    4651                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    4652                 :          1 :   QCOMPARE( leftOf, -1 );
    4653                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 8, 9 ), p, v, &leftOf ), 1.0, 4 * std::numeric_limits<double>::epsilon() );
    4654                 :          1 :   QCOMPARE( p, QgsPoint( 8, 10 ) );
    4655                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    4656                 :          1 :   QCOMPARE( leftOf, 1 );
    4657                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 11, 9 ), p, v, &leftOf ), 2.0, 4 * std::numeric_limits<double>::epsilon() );
    4658                 :          1 :   QCOMPARE( p, QgsPoint( 10, 10 ) );
    4659                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    4660                 :          1 :   QCOMPARE( leftOf, 1 );
    4661                 :          2 :   l35.setPoints( QgsPointSequence() << QgsPoint( 5, 10 )
    4662                 :          1 :                  << QgsPoint( 10, 10 )
    4663                 :          1 :                  << QgsPoint( 10, 15 ) );
    4664                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 11, 12 ), p, v, &leftOf ), 1.0, 4 * std::numeric_limits<double>::epsilon() );
    4665                 :          1 :   QCOMPARE( p, QgsPoint( 10, 12 ) );
    4666                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    4667                 :          1 :   QCOMPARE( leftOf, 1 );
    4668                 :            : 
    4669                 :          2 :   l35.setPoints( QgsPointSequence() << QgsPoint( 5, 5 )
    4670                 :          1 :                  << QgsPoint( 6, 4 )
    4671                 :          1 :                  << QgsPoint( 4, 4 )
    4672                 :          1 :                  << QgsPoint( 5, 5 ) );
    4673                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 2.35, 4 ), p, v, &leftOf ), 2.7225, 4 * std::numeric_limits<double>::epsilon() );
    4674                 :          1 :   QCOMPARE( p, QgsPoint( 4, 4 ) );
    4675                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    4676                 :          1 :   QCOMPARE( leftOf, -1 );
    4677                 :            : 
    4678                 :          2 :   l35.setPoints( QgsPointSequence() << QgsPoint( 5, 5 )
    4679                 :          1 :                  << QgsPoint( 4, 4 )
    4680                 :          1 :                  << QgsPoint( 6, 4 )
    4681                 :          1 :                  << QgsPoint( 5, 5 ) );
    4682                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 2.35, 4 ), p, v, &leftOf ), 2.7225, 4 * std::numeric_limits<double>::epsilon() );
    4683                 :          1 :   QCOMPARE( p, QgsPoint( 4, 4 ) );
    4684                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    4685                 :          1 :   QCOMPARE( leftOf, 1 );
    4686                 :            : 
    4687                 :          2 :   l35.setPoints( QgsPointSequence() << QgsPoint( 5, 5 )
    4688                 :          1 :                  << QgsPoint( 6, 4 )
    4689                 :          1 :                  << QgsPoint( 4, 4 )
    4690                 :          1 :                  << QgsPoint( 5, 5 ) );
    4691                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 3.5, 2 ), p, v, &leftOf ), 4.250000, 4 * std::numeric_limits<double>::epsilon() );
    4692                 :          1 :   QCOMPARE( p, QgsPoint( 4, 4 ) );
    4693                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    4694                 :          1 :   QCOMPARE( leftOf, -1 );
    4695                 :            : 
    4696                 :          2 :   l35.setPoints( QgsPointSequence() << QgsPoint( 5, 5 )
    4697                 :          1 :                  << QgsPoint( 4, 4 )
    4698                 :          1 :                  << QgsPoint( 6, 4 )
    4699                 :          1 :                  << QgsPoint( 5, 5 ) );
    4700                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 3.5, 2 ), p, v, &leftOf ), 4.250000, 4 * std::numeric_limits<double>::epsilon() );
    4701                 :          1 :   QCOMPARE( p, QgsPoint( 4, 4 ) );
    4702                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    4703                 :          1 :   QCOMPARE( leftOf, 1 );
    4704                 :            : 
    4705                 :          2 :   l35.setPoints( QgsPointSequence() << QgsPoint( 1, 1 )
    4706                 :          1 :                  << QgsPoint( 1, 4 )
    4707                 :          1 :                  << QgsPoint( 2, 2 )
    4708                 :          1 :                  << QgsPoint( 1, 1 ) );
    4709                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 1, 0 ), p, v, &leftOf ), 1, 4 * std::numeric_limits<double>::epsilon() );
    4710                 :          1 :   QCOMPARE( p, QgsPoint( 1, 1 ) );
    4711                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    4712                 :          1 :   QCOMPARE( leftOf, -1 );
    4713                 :            : 
    4714                 :          2 :   l35.setPoints( QgsPointSequence() << QgsPoint( 1, 1 )
    4715                 :          1 :                  << QgsPoint( 2, 2 )
    4716                 :          1 :                  << QgsPoint( 1, 4 )
    4717                 :          1 :                  << QgsPoint( 1, 1 ) );
    4718                 :          1 :   QGSCOMPARENEAR( l35.closestSegment( QgsPoint( 1, 0 ), p, v, &leftOf ), 1, 4 * std::numeric_limits<double>::epsilon() );
    4719                 :          1 :   QCOMPARE( p, QgsPoint( 1, 1 ) );
    4720                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    4721                 :          1 :   QCOMPARE( leftOf, 1 );
    4722                 :            : 
    4723                 :            :   //sumUpArea
    4724                 :          1 :   QgsLineString l36;
    4725                 :          1 :   double area = 1.0; //sumUpArea adds to area, so start with non-zero value
    4726                 :          1 :   l36.sumUpArea( area );
    4727                 :          1 :   QCOMPARE( area, 1.0 );
    4728                 :          1 :   l36.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) );
    4729                 :          1 :   l36.sumUpArea( area );
    4730                 :          1 :   QCOMPARE( area, 1.0 );
    4731                 :          1 :   l36.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) << QgsPoint( 10, 10 ) );
    4732                 :          1 :   l36.sumUpArea( area );
    4733                 :          1 :   QGSCOMPARENEAR( area, -24, 4 * std::numeric_limits<double>::epsilon() );
    4734                 :          1 :   l36.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 2, 0 ) << QgsPoint( 2, 2 ) );
    4735                 :          1 :   l36.sumUpArea( area );
    4736                 :          1 :   QGSCOMPARENEAR( area, -22, 4 * std::numeric_limits<double>::epsilon() );
    4737                 :          1 :   l36.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 2, 0 ) << QgsPoint( 2, 2 ) << QgsPoint( 0, 2 ) );
    4738                 :          1 :   l36.sumUpArea( area );
    4739                 :          1 :   QGSCOMPARENEAR( area, -18, 4 * std::numeric_limits<double>::epsilon() );
    4740                 :            : 
    4741                 :            :   //boundingBox - test that bounding box is updated after every modification to the line string
    4742                 :          1 :   QgsLineString l37;
    4743                 :          1 :   QVERIFY( l37.boundingBox().isNull() );
    4744                 :          1 :   l37.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) << QgsPoint( 10, 15 ) );
    4745                 :          1 :   QCOMPARE( l37.boundingBox(), QgsRectangle( 5, 10, 10, 15 ) );
    4746                 :          1 :   l37.setPoints( QgsPointSequence() << QgsPoint( -5, -10 ) << QgsPoint( -6, -10 ) << QgsPoint( -5.5, -9 ) );
    4747                 :          1 :   QCOMPARE( l37.boundingBox(), QgsRectangle( -6, -10, -5, -9 ) );
    4748                 :            :   //setXAt
    4749                 :          1 :   l37.setXAt( 2, -4 );
    4750                 :          1 :   QCOMPARE( l37.boundingBox(), QgsRectangle( -6, -10, -4, -9 ) );
    4751                 :            :   //setYAt
    4752                 :          1 :   l37.setYAt( 1, -15 );
    4753                 :          1 :   QCOMPARE( l37.boundingBox(), QgsRectangle( -6, -15, -4, -9 ) );
    4754                 :            :   //append
    4755                 :          1 :   toAppend.reset( new QgsLineString() );
    4756                 :          1 :   toAppend->setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 4, 0 ) );
    4757                 :          1 :   l37.append( toAppend.get() );
    4758                 :          1 :   QCOMPARE( l37.boundingBox(), QgsRectangle( -6, -15, 4, 2 ) );
    4759                 :          1 :   l37.addVertex( QgsPoint( 6, 3 ) );
    4760                 :          1 :   QCOMPARE( l37.boundingBox(), QgsRectangle( -6, -15, 6, 3 ) );
    4761                 :          1 :   l37.clear();
    4762                 :          1 :   QVERIFY( l37.boundingBox().isNull() );
    4763                 :          1 :   l37.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) << QgsPoint( 10, 15 ) );
    4764                 :          1 :   QByteArray wkbToAppend = toAppend->asWkb();
    4765                 :          1 :   QgsConstWkbPtr wkbToAppendPtr( wkbToAppend );
    4766                 :          1 :   l37.fromWkb( wkbToAppendPtr );
    4767                 :          1 :   QCOMPARE( l37.boundingBox(), QgsRectangle( 1, 0, 4, 2 ) );
    4768                 :          2 :   l37.fromWkt( QStringLiteral( "LineString( 1 5, 3 4, 6 3 )" ) );
    4769                 :          1 :   QCOMPARE( l37.boundingBox(), QgsRectangle( 1, 3, 6, 5 ) );
    4770                 :          1 :   l37.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( -1, 7 ) );
    4771                 :          1 :   QCOMPARE( l37.boundingBox(), QgsRectangle( -1, 3, 6, 7 ) );
    4772                 :          1 :   l37.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( -3, 10 ) );
    4773                 :          1 :   QCOMPARE( l37.boundingBox(), QgsRectangle( -3, 3, 6, 10 ) );
    4774                 :          1 :   l37.deleteVertex( QgsVertexId( 0, 0, 1 ) );
    4775                 :          1 :   QCOMPARE( l37.boundingBox(), QgsRectangle( 1, 3, 6, 5 ) );
    4776                 :            : 
    4777                 :            :   //angle
    4778                 :          1 :   QgsLineString l38;
    4779                 :          1 :   ( void )l38.vertexAngle( QgsVertexId() ); //just want no crash
    4780                 :          1 :   ( void )l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ); //just want no crash
    4781                 :          1 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) );
    4782                 :          1 :   ( void )l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ); //just want no crash, any answer is meaningless
    4783                 :          1 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) );
    4784                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 1.5708, 0.0001 );
    4785                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 1.5708, 0.0001 );
    4786                 :          1 :   ( void )l38.vertexAngle( QgsVertexId( 0, 0, 2 ) ); //no crash
    4787                 :          1 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 1 ) );
    4788                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 0.0, 4 * std::numeric_limits<double>::epsilon() );
    4789                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 0.0, 4 * std::numeric_limits<double>::epsilon() );
    4790                 :          1 :   l38.setPoints( QgsPointSequence() << QgsPoint( 1, 0 ) << QgsPoint( 0, 0 ) );
    4791                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 4.71239, 0.0001 );
    4792                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 4.71239, 0.0001 );
    4793                 :          1 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 1 ) << QgsPoint( 0, 0 ) );
    4794                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 3.1416, 0.0001 );
    4795                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 3.1416, 0.0001 );
    4796                 :          1 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 ) );
    4797                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 1.5708, 0.0001 );
    4798                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 0.7854, 0.0001 );
    4799                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 2 ) ), 0.0, 0.0001 );
    4800                 :          2 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0.5, 0 ) << QgsPoint( 1, 0 )
    4801                 :          1 :                  << QgsPoint( 2, 1 ) << QgsPoint( 1, 2 ) << QgsPoint( 0, 2 ) );
    4802                 :          1 :   ( void )l38.vertexAngle( QgsVertexId( 0, 0, 20 ) );
    4803                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 1.5708, 0.0001 );
    4804                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 1.5708, 0.0001 );
    4805                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 2 ) ), 1.17809, 0.00001 );
    4806                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 3 ) ), 0.0, 0.00001 );
    4807                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 4 ) ), 5.10509, 0.00001 );
    4808                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 5 ) ), 4.71239, 0.00001 );
    4809                 :            :   //closed line string
    4810                 :          1 :   l38.close();
    4811                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 5 ) ), 3.92699, 0.00001 );
    4812                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 2.35619, 0.00001 );
    4813                 :          1 :   QGSCOMPARENEAR( l38.vertexAngle( QgsVertexId( 0, 0, 6 ) ), 2.35619, 0.00001 );
    4814                 :            : 
    4815                 :            :   //removing the second to last vertex should remove the whole line
    4816                 :          1 :   QgsLineString l39;
    4817                 :          1 :   l39.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 1 ) );
    4818                 :          1 :   QVERIFY( l39.numPoints() == 2 );
    4819                 :          1 :   l39.deleteVertex( QgsVertexId( 0, 0, 1 ) );
    4820                 :          1 :   QVERIFY( l39.numPoints() == 0 );
    4821                 :            : 
    4822                 :            :   //boundary
    4823                 :          1 :   QgsLineString boundary1;
    4824                 :          1 :   QVERIFY( !boundary1.boundary() );
    4825                 :          1 :   boundary1.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 ) );
    4826                 :          1 :   QgsAbstractGeometry *boundary = boundary1.boundary();
    4827                 :          1 :   QgsMultiPoint *mpBoundary = dynamic_cast< QgsMultiPoint * >( boundary );
    4828                 :          1 :   QVERIFY( mpBoundary );
    4829                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->x(), 0.0 );
    4830                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->y(), 0.0 );
    4831                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->x(), 1.0 );
    4832                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->y(), 1.0 );
    4833                 :          1 :   delete boundary;
    4834                 :            : 
    4835                 :            :   // closed string = no boundary
    4836                 :          1 :   boundary1.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 ) << QgsPoint( 0, 0 ) );
    4837                 :          1 :   QVERIFY( !boundary1.boundary() );
    4838                 :            :   \
    4839                 :            : 
    4840                 :            :   //boundary with z
    4841                 :          1 :   boundary1.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 10 ) << QgsPoint( QgsWkbTypes::PointZ, 1, 0, 15 ) << QgsPoint( QgsWkbTypes::PointZ, 1, 1, 20 ) );
    4842                 :          1 :   boundary = boundary1.boundary();
    4843                 :          1 :   mpBoundary = dynamic_cast< QgsMultiPoint * >( boundary );
    4844                 :          1 :   QVERIFY( mpBoundary );
    4845                 :          1 :   QCOMPARE( mpBoundary->geometryN( 0 )->wkbType(), QgsWkbTypes::PointZ );
    4846                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->x(), 0.0 );
    4847                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->y(), 0.0 );
    4848                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->z(), 10.0 );
    4849                 :          1 :   QCOMPARE( mpBoundary->geometryN( 1 )->wkbType(), QgsWkbTypes::PointZ );
    4850                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->x(), 1.0 );
    4851                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->y(), 1.0 );
    4852                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->z(), 20.0 );
    4853                 :          1 :   delete boundary;
    4854                 :            : 
    4855                 :            :   //extend
    4856                 :          1 :   QgsLineString extend1;
    4857                 :          1 :   extend1.extend( 10, 10 ); //test no crash
    4858                 :          1 :   extend1.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 ) );
    4859                 :          1 :   extend1.extend( 1, 2 );
    4860                 :          1 :   QCOMPARE( extend1.pointN( 0 ), QgsPoint( QgsWkbTypes::Point, -1, 0 ) );
    4861                 :          1 :   QCOMPARE( extend1.pointN( 1 ), QgsPoint( QgsWkbTypes::Point, 1, 0 ) );
    4862                 :          1 :   QCOMPARE( extend1.pointN( 2 ), QgsPoint( QgsWkbTypes::Point, 1, 3 ) );
    4863                 :            : 
    4864                 :            :   // addToPainterPath (note most tests are in test_qgsgeometry.py)
    4865                 :          1 :   QgsLineString path;
    4866                 :          1 :   QPainterPath pPath;
    4867                 :          1 :   path.addToPainterPath( pPath );
    4868                 :          1 :   QVERIFY( pPath.isEmpty() );
    4869                 :          1 :   path.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 ) );
    4870                 :          1 :   path.addToPainterPath( pPath );
    4871                 :          1 :   QVERIFY( !pPath.isEmpty() );
    4872                 :            : 
    4873                 :            :   // toCurveType
    4874                 :          1 :   QgsLineString curveLine1;
    4875                 :          1 :   curveLine1.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
    4876                 :          1 :   std::unique_ptr< QgsCompoundCurve > curveType( curveLine1.toCurveType() );
    4877                 :          1 :   QCOMPARE( curveType->wkbType(), QgsWkbTypes::CompoundCurve );
    4878                 :          1 :   QCOMPARE( curveType->numPoints(), 2 );
    4879                 :          1 :   QCOMPARE( curveType->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( 1, 2 ) );
    4880                 :          1 :   QCOMPARE( curveType->vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( 11, 12 ) );
    4881                 :            : 
    4882                 :            :   //adjacent vertices
    4883                 :          1 :   QgsLineString vertexLine1;
    4884                 :          1 :   vertexLine1.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 111, 112 ) );
    4885                 :          1 :   QgsVertexId prev( 1, 2, 3 ); // start with something
    4886                 :          1 :   QgsVertexId next( 4, 5, 6 );
    4887                 :          1 :   vertexLine1.adjacentVertices( QgsVertexId( 0, 0, -1 ), prev, next );
    4888                 :          1 :   QCOMPARE( prev, QgsVertexId() );
    4889                 :          1 :   QCOMPARE( next, QgsVertexId() );
    4890                 :          1 :   vertexLine1.adjacentVertices( QgsVertexId( 0, 0, 3 ), prev, next );
    4891                 :          1 :   QCOMPARE( prev, QgsVertexId() );
    4892                 :          1 :   QCOMPARE( next, QgsVertexId() );
    4893                 :          1 :   vertexLine1.adjacentVertices( QgsVertexId( 0, 0, 0 ), prev, next );
    4894                 :          1 :   QCOMPARE( prev, QgsVertexId() );
    4895                 :          1 :   QCOMPARE( next, QgsVertexId( 0, 0, 1 ) );
    4896                 :          1 :   vertexLine1.adjacentVertices( QgsVertexId( 0, 0, 1 ), prev, next );
    4897                 :          1 :   QCOMPARE( prev, QgsVertexId( 0, 0, 0 ) );
    4898                 :          1 :   QCOMPARE( next, QgsVertexId( 0, 0, 2 ) );
    4899                 :          1 :   vertexLine1.adjacentVertices( QgsVertexId( 0, 0, 2 ), prev, next );
    4900                 :          1 :   QCOMPARE( prev, QgsVertexId( 0, 0, 1 ) );
    4901                 :          1 :   QCOMPARE( next, QgsVertexId() );
    4902                 :            :   // ring, part should be maintained
    4903                 :          1 :   vertexLine1.adjacentVertices( QgsVertexId( 1, 0, 1 ), prev, next );
    4904                 :          1 :   QCOMPARE( prev, QgsVertexId( 1, 0, 0 ) );
    4905                 :          1 :   QCOMPARE( next, QgsVertexId( 1, 0, 2 ) );
    4906                 :          1 :   vertexLine1.adjacentVertices( QgsVertexId( 1, 2, 1 ), prev, next );
    4907                 :          1 :   QCOMPARE( prev, QgsVertexId( 1, 2, 0 ) );
    4908                 :          1 :   QCOMPARE( next, QgsVertexId( 1, 2, 2 ) );
    4909                 :            :   // closed ring
    4910                 :          1 :   vertexLine1.close();
    4911                 :          1 :   vertexLine1.adjacentVertices( QgsVertexId( 0, 0, 0 ), prev, next );
    4912                 :          1 :   QCOMPARE( prev, QgsVertexId() );
    4913                 :          1 :   QCOMPARE( next, QgsVertexId( 0, 0, 1 ) );
    4914                 :          1 :   vertexLine1.adjacentVertices( QgsVertexId( 0, 0, 3 ), prev, next );
    4915                 :          1 :   QCOMPARE( prev, QgsVertexId( 0, 0, 2 ) );
    4916                 :          1 :   QCOMPARE( next, QgsVertexId() );
    4917                 :            : 
    4918                 :            :   // vertex number
    4919                 :          1 :   QgsLineString vertexLine2;
    4920                 :          1 :   QCOMPARE( vertexLine2.vertexNumberFromVertexId( QgsVertexId( -1, 0, 0 ) ), -1 );
    4921                 :          1 :   QCOMPARE( vertexLine2.vertexNumberFromVertexId( QgsVertexId( 0, 0, 0 ) ), -1 );
    4922                 :          1 :   QCOMPARE( vertexLine2.vertexNumberFromVertexId( QgsVertexId( 1, 0, 0 ) ), -1 );
    4923                 :          1 :   vertexLine2.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 111, 112 ) );
    4924                 :          1 :   QCOMPARE( vertexLine2.vertexNumberFromVertexId( QgsVertexId( -1, 0, 0 ) ), -1 );
    4925                 :          1 :   QCOMPARE( vertexLine2.vertexNumberFromVertexId( QgsVertexId( 1, 0, 0 ) ), -1 );
    4926                 :          1 :   QCOMPARE( vertexLine2.vertexNumberFromVertexId( QgsVertexId( 0, -1, 0 ) ), -1 );
    4927                 :          1 :   QCOMPARE( vertexLine2.vertexNumberFromVertexId( QgsVertexId( 0, 1, 0 ) ), -1 );
    4928                 :          1 :   QCOMPARE( vertexLine2.vertexNumberFromVertexId( QgsVertexId( 0, 0, -1 ) ), -1 );
    4929                 :          1 :   QCOMPARE( vertexLine2.vertexNumberFromVertexId( QgsVertexId( 0, 0, 0 ) ), 0 );
    4930                 :          1 :   QCOMPARE( vertexLine2.vertexNumberFromVertexId( QgsVertexId( 0, 0, 1 ) ), 1 );
    4931                 :          1 :   QCOMPARE( vertexLine2.vertexNumberFromVertexId( QgsVertexId( 0, 0, 2 ) ), 2 );
    4932                 :          1 :   QCOMPARE( vertexLine2.vertexNumberFromVertexId( QgsVertexId( 0, 0, 3 ) ), -1 );
    4933                 :            : 
    4934                 :            :   //segmentLength
    4935                 :          1 :   QgsLineString vertexLine3;
    4936                 :          1 :   QCOMPARE( vertexLine3.segmentLength( QgsVertexId( -1, 0, 0 ) ), 0.0 );
    4937                 :          1 :   QCOMPARE( vertexLine3.segmentLength( QgsVertexId( 0, 0, 0 ) ), 0.0 );
    4938                 :          1 :   QCOMPARE( vertexLine3.segmentLength( QgsVertexId( 1, 0, 0 ) ), 0.0 );
    4939                 :          1 :   vertexLine3.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 111, 12 ) );
    4940                 :          1 :   QCOMPARE( vertexLine3.segmentLength( QgsVertexId() ), 0.0 );
    4941                 :          1 :   QCOMPARE( vertexLine3.segmentLength( QgsVertexId( 0, 0, -1 ) ), 0.0 );
    4942                 :          1 :   QCOMPARE( vertexLine3.segmentLength( QgsVertexId( 0, 0, 0 ) ), 10.0 );
    4943                 :          1 :   QCOMPARE( vertexLine3.segmentLength( QgsVertexId( 0, 0, 1 ) ), 100.0 );
    4944                 :          1 :   QCOMPARE( vertexLine3.segmentLength( QgsVertexId( 0, 0, 2 ) ), 0.0 );
    4945                 :          1 :   QCOMPARE( vertexLine3.segmentLength( QgsVertexId( -1, 0, -1 ) ), 0.0 );
    4946                 :          1 :   QCOMPARE( vertexLine3.segmentLength( QgsVertexId( -1, 0, 0 ) ), 10.0 );
    4947                 :          1 :   QCOMPARE( vertexLine3.segmentLength( QgsVertexId( 1, 0, 1 ) ), 100.0 );
    4948                 :          1 :   QCOMPARE( vertexLine3.segmentLength( QgsVertexId( 1, 1, 1 ) ), 100.0 );
    4949                 :            : 
    4950                 :            :   //removeDuplicateNodes
    4951                 :          1 :   QgsLineString nodeLine;
    4952                 :          1 :   QVERIFY( !nodeLine.removeDuplicateNodes() );
    4953                 :          1 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 111, 12 ) );
    4954                 :          1 :   QVERIFY( !nodeLine.removeDuplicateNodes() );
    4955                 :          2 :   QCOMPARE( nodeLine.asWkt(), QStringLiteral( "LineString (11 2, 11 12, 111 12)" ) );
    4956                 :          2 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11.01, 1.99 ) << QgsPoint( 11.02, 2.01 )
    4957                 :          1 :                       << QgsPoint( 11, 12 ) << QgsPoint( 111, 12 ) << QgsPoint( 111.01, 11.99 ) );
    4958                 :          1 :   QVERIFY( nodeLine.removeDuplicateNodes( 0.02 ) );
    4959                 :          1 :   QVERIFY( !nodeLine.removeDuplicateNodes( 0.02 ) );
    4960                 :          2 :   QCOMPARE( nodeLine.asWkt(), QStringLiteral( "LineString (11 2, 11 12, 111 12)" ) );
    4961                 :          2 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11.01, 1.99 ) << QgsPoint( 11.02, 2.01 )
    4962                 :          1 :                       << QgsPoint( 11, 12 ) << QgsPoint( 111, 12 ) << QgsPoint( 111.01, 11.99 ) );
    4963                 :          1 :   QVERIFY( !nodeLine.removeDuplicateNodes() );
    4964                 :          2 :   QCOMPARE( nodeLine.asWkt( 2 ), QStringLiteral( "LineString (11 2, 11.01 1.99, 11.02 2.01, 11 12, 111 12, 111.01 11.99)" ) );
    4965                 :            :   // don't create degenerate lines
    4966                 :          1 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) );
    4967                 :          1 :   QVERIFY( !nodeLine.removeDuplicateNodes( 0.02 ) );
    4968                 :          2 :   QCOMPARE( nodeLine.asWkt( 2 ), QStringLiteral( "LineString (11 2)" ) );
    4969                 :          1 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11.01, 1.99 ) );
    4970                 :          1 :   QVERIFY( !nodeLine.removeDuplicateNodes( 0.02 ) );
    4971                 :          2 :   QCOMPARE( nodeLine.asWkt( 2 ), QStringLiteral( "LineString (11 2, 11.01 1.99)" ) );
    4972                 :            :   // with z
    4973                 :          2 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 1 ) << QgsPoint( 11.01, 1.99, 2 ) << QgsPoint( 11.02, 2.01, 3 )
    4974                 :          1 :                       << QgsPoint( 11, 12, 4 ) << QgsPoint( 111, 12, 5 ) << QgsPoint( 111.01, 11.99, 6 ) );
    4975                 :          1 :   QVERIFY( nodeLine.removeDuplicateNodes( 0.02 ) );
    4976                 :          2 :   QCOMPARE( nodeLine.asWkt(), QStringLiteral( "LineStringZ (11 2 1, 11 12 4, 111 12 5)" ) );
    4977                 :          2 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 1 ) << QgsPoint( 11.01, 1.99, 2 ) << QgsPoint( 11.02, 2.01, 3 )
    4978                 :          1 :                       << QgsPoint( 11, 12, 4 ) << QgsPoint( 111, 12, 5 ) << QgsPoint( 111.01, 11.99, 6 ) );
    4979                 :          1 :   QVERIFY( !nodeLine.removeDuplicateNodes( 0.02, true ) );
    4980                 :          2 :   QCOMPARE( nodeLine.asWkt( 2 ), QStringLiteral( "LineStringZ (11 2 1, 11.01 1.99 2, 11.02 2.01 3, 11 12 4, 111 12 5, 111.01 11.99 6)" ) );
    4981                 :            : 
    4982                 :            :   // swap xy
    4983                 :          1 :   QgsLineString swapLine;
    4984                 :          1 :   swapLine.swapXy(); // no crash
    4985                 :          1 :   swapLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 11, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 111, 12, 23, 24, QgsWkbTypes::PointZM ) );
    4986                 :          1 :   swapLine.swapXy();
    4987                 :          2 :   QCOMPARE( swapLine.asWkt( 2 ), QStringLiteral( "LineStringZM (2 11 3 4, 12 11 13 14, 12 111 23 24)" ) );
    4988                 :            : 
    4989                 :            :   // filter vertex
    4990                 :          1 :   QgsLineString filterLine;
    4991                 :          4 :   auto filter = []( const QgsPoint & point )-> bool
    4992                 :            :   {
    4993                 :          4 :     return point.x() < 5;
    4994                 :            :   };
    4995                 :          1 :   filterLine.filterVertices( filter ); // no crash
    4996                 :          1 :   filterLine.setPoints( QgsPointSequence()  << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 1, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 4, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 111, 12, 23, 24, QgsWkbTypes::PointZM ) );
    4997                 :          1 :   filterLine.filterVertices( filter );
    4998                 :          2 :   QCOMPARE( filterLine.asWkt( 2 ), QStringLiteral( "LineStringZM (1 2 3 4, 4 12 13 14)" ) );
    4999                 :            : 
    5000                 :            :   // transform vertex
    5001                 :          1 :   QgsLineString transformLine;
    5002                 :          4 :   auto transform = []( const QgsPoint & point )-> QgsPoint
    5003                 :            :   {
    5004                 :          4 :     return QgsPoint( point.x() + 5, point.y() + 6, point.z() + 7, point.m() + 8 );
    5005                 :            :   };
    5006                 :          1 :   transformLine.transformVertices( transform ); // no crash
    5007                 :          1 :   transformLine.setPoints( QgsPointSequence()  << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 1, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 4, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 111, 12, 23, 24, QgsWkbTypes::PointZM ) );
    5008                 :          1 :   transformLine.transformVertices( transform );
    5009                 :          2 :   QCOMPARE( transformLine.asWkt( 2 ), QStringLiteral( "LineStringZM (16 8 10 12, 6 8 10 12, 9 18 20 22, 116 18 30 32)" ) );
    5010                 :            : 
    5011                 :            :   // transform using class
    5012                 :          1 :   QgsLineString transformLine2;
    5013                 :          1 :   TestTransformer transformer;
    5014                 :            :   // no crash
    5015                 :          1 :   QVERIFY( transformLine2.transform( &transformer ) );
    5016                 :          1 :   transformLine2.setPoints( QgsPointSequence()  << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 1, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 4, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 111, 12, 23, 24, QgsWkbTypes::PointZM ) );
    5017                 :          1 :   QVERIFY( transformLine2.transform( &transformer ) );
    5018                 :          2 :   QCOMPARE( transformLine2.asWkt( 2 ), QStringLiteral( "LineStringZM (33 16 8 3, 3 16 8 3, 12 26 18 13, 333 26 28 23)" ) );
    5019                 :            : 
    5020                 :          1 :   TestFailTransformer failTransformer;
    5021                 :          1 :   QVERIFY( !transformLine2.transform( &failTransformer ) );
    5022                 :            : 
    5023                 :            :   // substring
    5024                 :          1 :   QgsLineString substring;
    5025                 :          1 :   std::unique_ptr< QgsLineString > substringResult( substring.curveSubstring( 1, 2 ) ); // no crash
    5026                 :          1 :   QVERIFY( substringResult.get() );
    5027                 :          1 :   QVERIFY( substringResult->isEmpty() );
    5028                 :          1 :   substring.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 11, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 111, 12, 23, 24, QgsWkbTypes::PointZM ) );
    5029                 :          1 :   substringResult.reset( substring.curveSubstring( 0, 0 ) );
    5030                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "LineStringZM (11 2 3 4, 11 2 3 4)" ) );
    5031                 :          1 :   substringResult.reset( substring.curveSubstring( -1, -0.1 ) );
    5032                 :          1 :   QVERIFY( substringResult->isEmpty() );
    5033                 :          1 :   substringResult.reset( substring.curveSubstring( 100000, 10000 ) );
    5034                 :          1 :   QVERIFY( substringResult->isEmpty() );
    5035                 :          1 :   substringResult.reset( substring.curveSubstring( -1, 1 ) );
    5036                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "LineStringZM (11 2 3 4, 11 3 4 5)" ) );
    5037                 :          1 :   substringResult.reset( substring.curveSubstring( 1, -1 ) );
    5038                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "LineStringZM (11 3 4 5, 11 3 4 5)" ) );
    5039                 :          1 :   substringResult.reset( substring.curveSubstring( -1, 10000 ) );
    5040                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "LineStringZM (11 2 3 4, 11 12 13 14, 111 12 23 24)" ) );
    5041                 :          1 :   substringResult.reset( substring.curveSubstring( 1, 10000 ) );
    5042                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "LineStringZM (11 3 4 5, 11 12 13 14, 111 12 23 24)" ) );
    5043                 :          1 :   substringResult.reset( substring.curveSubstring( 1, 20 ) );
    5044                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "LineStringZM (11 3 4 5, 11 12 13 14, 21 12 14 15)" ) );
    5045                 :          1 :   substringResult.reset( substring.curveSubstring( QgsGeometryUtils::distanceToVertex( substring, QgsVertexId( 0, 0, 1 ) ), QgsGeometryUtils::distanceToVertex( substring, QgsVertexId( 0, 0, 2 ) ) ) );
    5046                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "LineStringZM (11 12 13 14, 111 12 23 24)" ) );
    5047                 :          1 :   substring.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 3, 0, QgsWkbTypes::PointZ ) << QgsPoint( 11, 12, 13, 0, QgsWkbTypes::PointZ ) << QgsPoint( 111, 12, 23, 0, QgsWkbTypes::PointZ ) );
    5048                 :          1 :   substringResult.reset( substring.curveSubstring( 1, 20 ) );
    5049                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "LineStringZ (11 3 4, 11 12 13, 21 12 14)" ) );
    5050                 :          1 :   substring.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 0, 3, QgsWkbTypes::PointM ) << QgsPoint( 11, 12, 0, 13, QgsWkbTypes::PointM ) << QgsPoint( 111, 12, 0, 23, QgsWkbTypes::PointM ) );
    5051                 :          1 :   substringResult.reset( substring.curveSubstring( 1, 20 ) );
    5052                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "LineStringM (11 3 4, 11 12 13, 21 12 14)" ) );
    5053                 :          1 :   substring.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 111, 12 ) );
    5054                 :          1 :   substringResult.reset( substring.curveSubstring( 1, 20 ) );
    5055                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "LineString (11 3, 11 12, 21 12)" ) );
    5056                 :            : 
    5057                 :            :   //interpolate point
    5058                 :          1 :   QgsLineString interpolate;
    5059                 :          1 :   std::unique_ptr< QgsPoint > interpolateResult( interpolate.interpolatePoint( 1 ) ); // no crash
    5060                 :          1 :   QVERIFY( !interpolateResult.get() );
    5061                 :          1 :   interpolate.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 11, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 111, 12, 23, 24, QgsWkbTypes::PointZM ) );
    5062                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 0 ) );
    5063                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointZM (11 2 3 4)" ) );
    5064                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( -1 ) );
    5065                 :          1 :   QVERIFY( !interpolateResult.get() );
    5066                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 100000 ) );
    5067                 :          1 :   QVERIFY( !interpolateResult.get() );
    5068                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 1 ) );
    5069                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointZM (11 3 4 5)" ) );
    5070                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 20 ) );
    5071                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointZM (21 12 14 15)" ) );
    5072                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 110 ) );
    5073                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointZM (111 12 23 24)" ) );
    5074                 :          1 :   interpolate.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 3, 0, QgsWkbTypes::PointZ ) << QgsPoint( 11, 12, 13, 0, QgsWkbTypes::PointZ ) << QgsPoint( 111, 12, 23, 0, QgsWkbTypes::PointZ ) );
    5075                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 1 ) );
    5076                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointZ (11 3 4)" ) );
    5077                 :          1 :   interpolate.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 0, 3, QgsWkbTypes::PointM ) << QgsPoint( 11, 12, 0, 13, QgsWkbTypes::PointM ) << QgsPoint( 111, 12, 0, 23, QgsWkbTypes::PointM ) );
    5078                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 1 ) );
    5079                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointM (11 3 4)" ) );
    5080                 :          1 :   interpolate.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 111, 12 ) );
    5081                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 1 ) );
    5082                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "Point (11 3)" ) );
    5083                 :            : 
    5084                 :            :   // visit points
    5085                 :          1 :   QgsLineString visitLine;
    5086                 :          1 :   visitLine.visitPointsByRegularDistance( 1, [ = ]( double, double, double, double, double, double, double, double, double, double, double, double )->bool
    5087                 :            :   {
    5088                 :          0 :     return true;
    5089                 :            :   } ); // no crash
    5090                 :          1 :   visitLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 11, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 111, 12, 23, 24, QgsWkbTypes::PointZM ) );
    5091                 :          1 :   int visitCount = 0;
    5092                 :          1 :   xx.clear();
    5093                 :          1 :   yy.clear();
    5094                 :          1 :   zz.clear();
    5095                 :          1 :   mm.clear();
    5096                 :          1 :   QVector<double> pX, pY, pZ, pM, nX, nY, nZ, nM;
    5097                 :          5 :   auto visitor = [ & ]( double x, double y, double z, double m, double ppx, double ppy, double ppz, double ppm, double nnx, double nny, double nnz, double nnm )->bool
    5098                 :            :   {
    5099                 :          4 :     xx << x;
    5100                 :          4 :     yy << y;
    5101                 :          4 :     zz << z;
    5102                 :          4 :     mm << m;
    5103                 :          4 :     pX << ppx;
    5104                 :          4 :     pY << ppy;
    5105                 :          4 :     pZ << ppz;
    5106                 :          4 :     pM << ppm;
    5107                 :          4 :     nX << nnx;
    5108                 :          4 :     nY << nny;
    5109                 :          4 :     nZ << nnz;
    5110                 :          4 :     nM << nnm;
    5111                 :          4 :     visitCount++;
    5112                 :          4 :     return true;
    5113                 :            :   };
    5114                 :          1 :   visitLine.visitPointsByRegularDistance( 0, visitor );
    5115                 :          1 :   QCOMPARE( visitCount, 1 );
    5116                 :          1 :   QCOMPARE( xx.at( 0 ), 11.0 );
    5117                 :          1 :   QCOMPARE( yy.at( 0 ), 2.0 );
    5118                 :          1 :   QCOMPARE( zz.at( 0 ), 3.0 );
    5119                 :          1 :   QCOMPARE( mm.at( 0 ), 4.0 );
    5120                 :          1 :   xx.clear();
    5121                 :          1 :   yy.clear();
    5122                 :          1 :   zz.clear();
    5123                 :          1 :   mm.clear();
    5124                 :          1 :   pX.clear();
    5125                 :          1 :   pY.clear();
    5126                 :          1 :   pZ.clear();
    5127                 :          1 :   pM.clear();
    5128                 :          1 :   nX.clear();
    5129                 :          1 :   nY.clear();
    5130                 :          1 :   nZ.clear();
    5131                 :          1 :   nM.clear();
    5132                 :          1 :   visitCount = 0;
    5133                 :          1 :   visitLine.visitPointsByRegularDistance( -1, visitor );
    5134                 :          1 :   QCOMPARE( visitCount, 0 );
    5135                 :          1 :   visitLine.visitPointsByRegularDistance( 10000, visitor );
    5136                 :          1 :   QCOMPARE( visitCount, 0 );
    5137                 :          1 :   visitLine.visitPointsByRegularDistance( 30, visitor );
    5138                 :          1 :   QCOMPARE( visitCount, 3 );
    5139                 :          1 :   QCOMPARE( xx.at( 0 ), 31.0 );
    5140                 :          1 :   QCOMPARE( yy.at( 0 ), 12.0 );
    5141                 :          1 :   QCOMPARE( zz.at( 0 ), 15.0 );
    5142                 :          1 :   QCOMPARE( mm.at( 0 ), 16.0 );
    5143                 :          1 :   QCOMPARE( pX.at( 0 ), 11.0 );
    5144                 :          1 :   QCOMPARE( pY.at( 0 ), 12.0 );
    5145                 :          1 :   QCOMPARE( pZ.at( 0 ), 13.0 );
    5146                 :          1 :   QCOMPARE( pM.at( 0 ), 14.0 );
    5147                 :          1 :   QCOMPARE( nX.at( 0 ), 111.0 );
    5148                 :          1 :   QCOMPARE( nY.at( 0 ), 12.0 );
    5149                 :          1 :   QCOMPARE( nZ.at( 0 ), 23.0 );
    5150                 :          1 :   QCOMPARE( nM.at( 0 ), 24.0 );
    5151                 :          1 :   QCOMPARE( xx.at( 1 ), 61.0 );
    5152                 :          1 :   QCOMPARE( yy.at( 1 ), 12.0 );
    5153                 :          1 :   QCOMPARE( zz.at( 1 ), 18.0 );
    5154                 :          1 :   QCOMPARE( mm.at( 1 ), 19.0 );
    5155                 :          1 :   QCOMPARE( pX.at( 1 ), 11.0 );
    5156                 :          1 :   QCOMPARE( pY.at( 1 ), 12.0 );
    5157                 :          1 :   QCOMPARE( pZ.at( 1 ), 13.0 );
    5158                 :          1 :   QCOMPARE( pM.at( 1 ), 14.0 );
    5159                 :          1 :   QCOMPARE( nX.at( 1 ), 111.0 );
    5160                 :          1 :   QCOMPARE( nY.at( 1 ), 12.0 );
    5161                 :          1 :   QCOMPARE( nZ.at( 1 ), 23.0 );
    5162                 :          1 :   QCOMPARE( nM.at( 1 ), 24.0 );
    5163                 :          1 :   QCOMPARE( xx.at( 2 ), 91.0 );
    5164                 :          1 :   QCOMPARE( yy.at( 2 ), 12.0 );
    5165                 :          1 :   QCOMPARE( zz.at( 2 ), 21.0 );
    5166                 :          1 :   QCOMPARE( mm.at( 2 ), 22.0 );
    5167                 :          1 :   QCOMPARE( pX.at( 2 ), 11.0 );
    5168                 :          1 :   QCOMPARE( pY.at( 2 ), 12.0 );
    5169                 :          1 :   QCOMPARE( pZ.at( 2 ), 13.0 );
    5170                 :          1 :   QCOMPARE( pM.at( 2 ), 14.0 );
    5171                 :          1 :   QCOMPARE( nX.at( 2 ), 111.0 );
    5172                 :          1 :   QCOMPARE( nY.at( 2 ), 12.0 );
    5173                 :          1 :   QCOMPARE( nZ.at( 2 ), 23.0 );
    5174                 :          1 :   QCOMPARE( nM.at( 2 ), 24.0 );
    5175                 :            : 
    5176                 :            :   // orientation
    5177                 :          1 :   QgsLineString orientation;
    5178                 :          1 :   ( void )orientation.orientation(); // no crash
    5179                 :          1 :   orientation.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 1 ) << QgsPoint( 1, 1 ) << QgsPoint( 1, 0 ) << QgsPoint( 0, 0 ) );
    5180                 :          1 :   QCOMPARE( orientation.orientation(), QgsCurve::Clockwise );
    5181                 :          1 :   orientation.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 ) << QgsPoint( 0, 1 ) << QgsPoint( 0, 0 ) );
    5182                 :          1 :   QCOMPARE( orientation.orientation(), QgsCurve::CounterClockwise );
    5183                 :            : 
    5184                 :            :   // test bounding box intersects
    5185                 :          1 :   QgsLineString bb;
    5186                 :          1 :   QVERIFY( !bb.boundingBoxIntersects( QgsRectangle( 1, 3, 6, 9 ) ) );
    5187                 :          1 :   bb.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 13, -10 ) );
    5188                 :          1 :   QVERIFY( bb.boundingBoxIntersects( QgsRectangle( 12, 3, 16, 9 ) ) );
    5189                 :            :   // double test because of cache
    5190                 :          1 :   QVERIFY( bb.boundingBoxIntersects( QgsRectangle( 12, 3, 16, 9 ) ) );
    5191                 :          1 :   QVERIFY( !bb.boundingBoxIntersects( QgsRectangle( 1, 3, 6, 9 ) ) );
    5192                 :          1 :   QVERIFY( !bb.boundingBoxIntersects( QgsRectangle( 1, 3, 6, 9 ) ) );
    5193                 :          1 :   QCOMPARE( bb.boundingBox(), QgsRectangle( 11, -10, 13, 12 ) );
    5194                 :            :   // clear cache
    5195                 :          1 :   bb.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 13, -10 ) );
    5196                 :          1 :   QVERIFY( !bb.boundingBoxIntersects( QgsRectangle( 1, 3, 6, 9 ) ) );
    5197                 :          1 :   QVERIFY( !bb.boundingBoxIntersects( QgsRectangle( 1, 3, 6, 9 ) ) );
    5198                 :          1 :   QCOMPARE( bb.boundingBox(), QgsRectangle( 11, -10, 13, 12 ) );
    5199                 :          1 :   QVERIFY( bb.boundingBoxIntersects( QgsRectangle( 12, 3, 16, 9 ) ) );
    5200                 :          1 : }
    5201                 :            : 
    5202                 :          1 : void TestQgsGeometry::polygon()
    5203                 :            : {
    5204                 :            :   //test constructor
    5205                 :          1 :   QgsPolygon p1;
    5206                 :          1 :   QVERIFY( p1.isEmpty() );
    5207                 :          1 :   QCOMPARE( p1.numInteriorRings(), 0 );
    5208                 :          1 :   QCOMPARE( p1.nCoordinates(), 0 );
    5209                 :          1 :   QCOMPARE( p1.ringCount(), 0 );
    5210                 :          1 :   QCOMPARE( p1.partCount(), 0 );
    5211                 :          1 :   QVERIFY( !p1.is3D() );
    5212                 :          1 :   QVERIFY( !p1.isMeasure() );
    5213                 :          1 :   QCOMPARE( p1.wkbType(), QgsWkbTypes::Polygon );
    5214                 :          1 :   QCOMPARE( p1.wktTypeStr(), QString( "Polygon" ) );
    5215                 :          1 :   QCOMPARE( p1.geometryType(), QString( "Polygon" ) );
    5216                 :          1 :   QCOMPARE( p1.dimension(), 2 );
    5217                 :          1 :   QVERIFY( !p1.hasCurvedSegments() );
    5218                 :          1 :   QCOMPARE( p1.area(), 0.0 );
    5219                 :          1 :   QCOMPARE( p1.perimeter(), 0.0 );
    5220                 :          1 :   QVERIFY( !p1.exteriorRing() );
    5221                 :          1 :   QVERIFY( !p1.interiorRing( 0 ) );
    5222                 :            : 
    5223                 :            :   //set exterior ring
    5224                 :            : 
    5225                 :            :   //try with no ring
    5226                 :          1 :   QgsLineString *ext = nullptr;
    5227                 :          1 :   p1.setExteriorRing( ext );
    5228                 :          1 :   QVERIFY( p1.isEmpty() );
    5229                 :          1 :   QCOMPARE( p1.numInteriorRings(), 0 );
    5230                 :          1 :   QCOMPARE( p1.nCoordinates(), 0 );
    5231                 :          1 :   QCOMPARE( p1.ringCount(), 0 );
    5232                 :          1 :   QCOMPARE( p1.partCount(), 0 );
    5233                 :          1 :   QVERIFY( !p1.exteriorRing() );
    5234                 :          1 :   QVERIFY( !p1.interiorRing( 0 ) );
    5235                 :          1 :   QCOMPARE( p1.wkbType(), QgsWkbTypes::Polygon );
    5236                 :            : 
    5237                 :            :   // empty exterior ring
    5238                 :          1 :   ext = new QgsLineString();
    5239                 :          1 :   p1.setExteriorRing( ext );
    5240                 :          1 :   QVERIFY( p1.isEmpty() );
    5241                 :          1 :   QCOMPARE( p1.numInteriorRings(), 0 );
    5242                 :          1 :   QCOMPARE( p1.nCoordinates(), 0 );
    5243                 :          1 :   QCOMPARE( p1.ringCount(), 1 );
    5244                 :          1 :   QCOMPARE( p1.partCount(), 1 );
    5245                 :          1 :   QVERIFY( p1.exteriorRing() );
    5246                 :          1 :   QVERIFY( !p1.interiorRing( 0 ) );
    5247                 :          1 :   QCOMPARE( p1.wkbType(), QgsWkbTypes::Polygon );
    5248                 :            : 
    5249                 :            :   //valid exterior ring
    5250                 :          1 :   ext = new QgsLineString();
    5251                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
    5252                 :          1 :                   << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) );
    5253                 :          1 :   p1.setExteriorRing( ext );
    5254                 :          1 :   QVERIFY( !p1.isEmpty() );
    5255                 :          1 :   QCOMPARE( p1.numInteriorRings(), 0 );
    5256                 :          1 :   QCOMPARE( p1.nCoordinates(), 5 );
    5257                 :          1 :   QCOMPARE( p1.ringCount(), 1 );
    5258                 :          1 :   QCOMPARE( p1.partCount(), 1 );
    5259                 :          1 :   QVERIFY( !p1.is3D() );
    5260                 :          1 :   QVERIFY( !p1.isMeasure() );
    5261                 :          1 :   QCOMPARE( p1.wkbType(), QgsWkbTypes::Polygon );
    5262                 :          1 :   QCOMPARE( p1.wktTypeStr(), QString( "Polygon" ) );
    5263                 :          1 :   QCOMPARE( p1.geometryType(), QString( "Polygon" ) );
    5264                 :          1 :   QCOMPARE( p1.dimension(), 2 );
    5265                 :          1 :   QVERIFY( !p1.hasCurvedSegments() );
    5266                 :          1 :   QCOMPARE( p1.area(), 100.0 );
    5267                 :          1 :   QCOMPARE( p1.perimeter(), 40.0 );
    5268                 :          1 :   QVERIFY( p1.exteriorRing() );
    5269                 :          1 :   QVERIFY( !p1.interiorRing( 0 ) );
    5270                 :            : 
    5271                 :            :   //retrieve exterior ring and check
    5272                 :          1 :   QCOMPARE( *( static_cast< const QgsLineString * >( p1.exteriorRing() ) ), *ext );
    5273                 :            : 
    5274                 :            :   //test that a non closed exterior ring will be automatically closed
    5275                 :          1 :   ext = new QgsLineString();
    5276                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
    5277                 :          1 :                   << QgsPoint( 10, 0 ) );
    5278                 :          1 :   QVERIFY( !ext->isClosed() );
    5279                 :          1 :   p1.setExteriorRing( ext );
    5280                 :          1 :   QVERIFY( !p1.isEmpty() );
    5281                 :          1 :   QVERIFY( p1.exteriorRing()->isClosed() );
    5282                 :          1 :   QCOMPARE( p1.nCoordinates(), 5 );
    5283                 :            : 
    5284                 :            :   //initial setting of exterior ring should set z/m type
    5285                 :          1 :   QgsPolygon p2;
    5286                 :          1 :   ext = new QgsLineString();
    5287                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 )
    5288                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 0, 10, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 10, 10, 3 )
    5289                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 10, 0, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 ) );
    5290                 :          1 :   p2.setExteriorRing( ext );
    5291                 :          1 :   QVERIFY( p2.is3D() );
    5292                 :          1 :   QVERIFY( !p2.isMeasure() );
    5293                 :          1 :   QCOMPARE( p2.wkbType(), QgsWkbTypes::PolygonZ );
    5294                 :          1 :   QCOMPARE( p2.wktTypeStr(), QString( "PolygonZ" ) );
    5295                 :          1 :   QCOMPARE( p2.geometryType(), QString( "Polygon" ) );
    5296                 :          1 :   QCOMPARE( *( static_cast< const QgsLineString * >( p2.exteriorRing() ) ), *ext );
    5297                 :          1 :   QgsPolygon p3;
    5298                 :          1 :   ext = new QgsLineString();
    5299                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 0, 0, 0, 1 )
    5300                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 0, 10, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 10, 10, 0, 3 )
    5301                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 10, 0, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 0, 0, 0, 1 ) );
    5302                 :          1 :   p3.setExteriorRing( ext );
    5303                 :          1 :   QVERIFY( !p3.is3D() );
    5304                 :          1 :   QVERIFY( p3.isMeasure() );
    5305                 :          1 :   QCOMPARE( p3.wkbType(), QgsWkbTypes::PolygonM );
    5306                 :          1 :   QCOMPARE( p3.wktTypeStr(), QString( "PolygonM" ) );
    5307                 :          1 :   QCOMPARE( *( static_cast< const QgsLineString * >( p3.exteriorRing() ) ), *ext );
    5308                 :          1 :   QgsPolygon p4;
    5309                 :          1 :   ext = new QgsLineString();
    5310                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 2, 1 )
    5311                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 0, 10, 3, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 10, 10, 5, 3 )
    5312                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 10, 0, 0, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 2, 1 ) );
    5313                 :          1 :   p4.setExteriorRing( ext );
    5314                 :          1 :   QVERIFY( p4.is3D() );
    5315                 :          1 :   QVERIFY( p4.isMeasure() );
    5316                 :          1 :   QCOMPARE( p4.wkbType(), QgsWkbTypes::PolygonZM );
    5317                 :          1 :   QCOMPARE( p4.wktTypeStr(), QString( "PolygonZM" ) );
    5318                 :          1 :   QCOMPARE( *( static_cast< const QgsLineString * >( p4.exteriorRing() ) ), *ext );
    5319                 :          1 :   QgsPolygon p5;
    5320                 :          1 :   ext = new QgsLineString();
    5321                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point25D, 0, 0, 1 )
    5322                 :          1 :                   << QgsPoint( QgsWkbTypes::Point25D, 0, 10, 2 ) << QgsPoint( QgsWkbTypes::Point25D, 10, 10, 3 )
    5323                 :          1 :                   << QgsPoint( QgsWkbTypes::Point25D, 10, 0, 4 ) << QgsPoint( QgsWkbTypes::Point25D, 0, 0, 1 ) );
    5324                 :          1 :   p5.setExteriorRing( ext );
    5325                 :          1 :   QVERIFY( p5.is3D() );
    5326                 :          1 :   QVERIFY( !p5.isMeasure() );
    5327                 :          1 :   QCOMPARE( p5.wkbType(), QgsWkbTypes::Polygon25D );
    5328                 :          1 :   QCOMPARE( p5.wktTypeStr(), QString( "PolygonZ" ) );
    5329                 :          1 :   QCOMPARE( *( static_cast< const QgsLineString * >( p5.exteriorRing() ) ), *ext );
    5330                 :            : 
    5331                 :            :   //setting curved exterior ring should be segmentized
    5332                 :          1 :   QgsCircularString *circularRing = new QgsCircularString();
    5333                 :          2 :   circularRing->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
    5334                 :          1 :                            << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) );
    5335                 :          1 :   QVERIFY( circularRing->hasCurvedSegments() );
    5336                 :          1 :   p5.setExteriorRing( circularRing );
    5337                 :          1 :   QVERIFY( !p5.exteriorRing()->hasCurvedSegments() );
    5338                 :          1 :   QCOMPARE( p5.exteriorRing()->wkbType(), QgsWkbTypes::LineString );
    5339                 :            : 
    5340                 :            :   //addInteriorRing
    5341                 :          1 :   QgsPolygon p6;
    5342                 :          1 :   ext = new QgsLineString();
    5343                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
    5344                 :          1 :                   << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) );
    5345                 :          1 :   p6.setExteriorRing( ext );
    5346                 :            :   //empty ring
    5347                 :          1 :   QCOMPARE( p6.numInteriorRings(), 0 );
    5348                 :          1 :   QVERIFY( !p6.interiorRing( -1 ) );
    5349                 :          1 :   QVERIFY( !p6.interiorRing( 0 ) );
    5350                 :          1 :   p6.addInteriorRing( nullptr );
    5351                 :          1 :   QCOMPARE( p6.numInteriorRings(), 0 );
    5352                 :          1 :   QgsLineString *ring = new QgsLineString();
    5353                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( 1, 1 ) << QgsPoint( 1, 9 ) << QgsPoint( 9, 9 )
    5354                 :          1 :                    << QgsPoint( 9, 1 ) << QgsPoint( 1, 1 ) );
    5355                 :          1 :   p6.addInteriorRing( ring );
    5356                 :          1 :   QCOMPARE( p6.numInteriorRings(), 1 );
    5357                 :          1 :   QCOMPARE( p6.interiorRing( 0 ), ring );
    5358                 :          1 :   QVERIFY( !p6.interiorRing( 1 ) );
    5359                 :            : 
    5360                 :          1 :   QgsCoordinateSequence seq = p6.coordinateSequence();
    5361                 :          1 :   QCOMPARE( seq, QgsCoordinateSequence() << ( QgsRingSequence() << ( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
    5362                 :            :             << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) )
    5363                 :            :             << ( QgsPointSequence() << QgsPoint( 1, 1 ) << QgsPoint( 1, 9 ) << QgsPoint( 9, 9 )
    5364                 :            :                  << QgsPoint( 9, 1 ) << QgsPoint( 1, 1 ) ) ) );
    5365                 :          1 :   QCOMPARE( p6.nCoordinates(), 10 );
    5366                 :            : 
    5367                 :            :   //add non-closed interior ring, should be closed automatically
    5368                 :          1 :   ring = new QgsLineString();
    5369                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( 0.1, 0.1 ) << QgsPoint( 0.1, 0.9 ) << QgsPoint( 0.9, 0.9 )
    5370                 :          1 :                    << QgsPoint( 0.9, 0.1 ) );
    5371                 :          1 :   QVERIFY( !ring->isClosed() );
    5372                 :          1 :   p6.addInteriorRing( ring );
    5373                 :          1 :   QCOMPARE( p6.numInteriorRings(), 2 );
    5374                 :          1 :   QVERIFY( p6.interiorRing( 1 )->isClosed() );
    5375                 :            : 
    5376                 :            :   //try adding an interior ring with z to a 2d polygon, z should be dropped
    5377                 :          1 :   ring = new QgsLineString();
    5378                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.1, 1 )
    5379                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.2, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 0.2, 0.2, 3 )
    5380                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZ, 0.2, 0.1, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.1, 1 ) );
    5381                 :          1 :   p6.addInteriorRing( ring );
    5382                 :          1 :   QCOMPARE( p6.numInteriorRings(), 3 );
    5383                 :          1 :   QVERIFY( !p6.is3D() );
    5384                 :          1 :   QVERIFY( !p6.isMeasure() );
    5385                 :          1 :   QCOMPARE( p6.wkbType(), QgsWkbTypes::Polygon );
    5386                 :          1 :   QVERIFY( p6.interiorRing( 2 ) );
    5387                 :          1 :   QVERIFY( !p6.interiorRing( 2 )->is3D() );
    5388                 :          1 :   QVERIFY( !p6.interiorRing( 2 )->isMeasure() );
    5389                 :          1 :   QCOMPARE( p6.interiorRing( 2 )->wkbType(), QgsWkbTypes::LineString );
    5390                 :            : 
    5391                 :            :   //try adding an interior ring with m to a 2d polygon, m should be dropped
    5392                 :          1 :   ring = new QgsLineString();
    5393                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 0.1, 0.1, 0, 1 )
    5394                 :          1 :                    << QgsPoint( QgsWkbTypes::PointM, 0.1, 0.2, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 0.2, 0.2, 0, 3 )
    5395                 :          1 :                    << QgsPoint( QgsWkbTypes::PointM, 0.2, 0.1, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 0.1, 0.1, 0, 1 ) );
    5396                 :          1 :   p6.addInteriorRing( ring );
    5397                 :          1 :   QCOMPARE( p6.numInteriorRings(), 4 );
    5398                 :          1 :   QVERIFY( !p6.is3D() );
    5399                 :          1 :   QVERIFY( !p6.isMeasure() );
    5400                 :          1 :   QCOMPARE( p6.wkbType(), QgsWkbTypes::Polygon );
    5401                 :          1 :   QVERIFY( p6.interiorRing( 3 ) );
    5402                 :          1 :   QVERIFY( !p6.interiorRing( 3 )->is3D() );
    5403                 :          1 :   QVERIFY( !p6.interiorRing( 3 )->isMeasure() );
    5404                 :          1 :   QCOMPARE( p6.interiorRing( 3 )->wkbType(), QgsWkbTypes::LineString );
    5405                 :            : 
    5406                 :            :   //addInteriorRing without z/m to PolygonZM
    5407                 :          1 :   QgsPolygon p6b;
    5408                 :          1 :   ext = new QgsLineString();
    5409                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1 )
    5410                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 0, 10, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 10, 10, 3 )
    5411                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1 ) );
    5412                 :          1 :   p6b.setExteriorRing( ext );
    5413                 :          1 :   QVERIFY( p6b.is3D() );
    5414                 :          1 :   QVERIFY( p6b.isMeasure() );
    5415                 :          1 :   QCOMPARE( p6b.wkbType(), QgsWkbTypes::PolygonZM );
    5416                 :            :   //ring has no z
    5417                 :          1 :   ring = new QgsLineString();
    5418                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 1, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 1, 9 ) << QgsPoint( QgsWkbTypes::PointM, 9, 9 )
    5419                 :          1 :                    << QgsPoint( QgsWkbTypes::PointM, 9, 1 ) << QgsPoint( QgsWkbTypes::PointM, 1, 1 ) );
    5420                 :          1 :   p6b.addInteriorRing( ring );
    5421                 :          1 :   QVERIFY( p6b.interiorRing( 0 ) );
    5422                 :          1 :   QVERIFY( p6b.interiorRing( 0 )->is3D() );
    5423                 :          1 :   QVERIFY( p6b.interiorRing( 0 )->isMeasure() );
    5424                 :          1 :   QCOMPARE( p6b.interiorRing( 0 )->wkbType(), QgsWkbTypes::LineStringZM );
    5425                 :          1 :   QCOMPARE( p6b.interiorRing( 0 )->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::PointZM, 1, 1, 0, 2 ) );
    5426                 :            :   //ring has no m
    5427                 :          1 :   ring = new QgsLineString();
    5428                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.1, 1 )
    5429                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.2, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 0.2, 0.2, 3 )
    5430                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZ, 0.2, 0.1, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.1, 1 ) );
    5431                 :          1 :   p6b.addInteriorRing( ring );
    5432                 :          1 :   QVERIFY( p6b.interiorRing( 1 ) );
    5433                 :          1 :   QVERIFY( p6b.interiorRing( 1 )->is3D() );
    5434                 :          1 :   QVERIFY( p6b.interiorRing( 1 )->isMeasure() );
    5435                 :          1 :   QCOMPARE( p6b.interiorRing( 1 )->wkbType(), QgsWkbTypes::LineStringZM );
    5436                 :          1 :   QCOMPARE( p6b.interiorRing( 1 )->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::PointZM, 0.1, 0.1, 1, 0 ) );
    5437                 :            :   //test handling of 25D rings/polygons
    5438                 :          1 :   QgsPolygon p6c;
    5439                 :          1 :   ext = new QgsLineString();
    5440                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point25D, 0, 0, 1 )
    5441                 :          1 :                   << QgsPoint( QgsWkbTypes::Point25D, 0, 10, 2 ) << QgsPoint( QgsWkbTypes::Point25D, 10, 10, 3 )
    5442                 :          1 :                   << QgsPoint( QgsWkbTypes::Point25D, 10, 0, 4 ) << QgsPoint( QgsWkbTypes::Point25D, 0, 0, 1 ) );
    5443                 :          1 :   p6c.setExteriorRing( ext );
    5444                 :          1 :   QVERIFY( p6c.is3D() );
    5445                 :          1 :   QVERIFY( !p6c.isMeasure() );
    5446                 :          1 :   QCOMPARE( p6c.wkbType(), QgsWkbTypes::Polygon25D );
    5447                 :            :   //adding a LineStringZ, should become LineString25D
    5448                 :          1 :   ring = new QgsLineString();
    5449                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.1, 1 )
    5450                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.2, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 0.2, 0.2, 3 )
    5451                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZ, 0.2, 0.1, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.1, 1 ) );
    5452                 :          1 :   QCOMPARE( ring->wkbType(), QgsWkbTypes::LineStringZ );
    5453                 :          1 :   p6c.addInteriorRing( ring );
    5454                 :          1 :   QVERIFY( p6c.interiorRing( 0 ) );
    5455                 :          1 :   QVERIFY( p6c.interiorRing( 0 )->is3D() );
    5456                 :          1 :   QVERIFY( !p6c.interiorRing( 0 )->isMeasure() );
    5457                 :          1 :   QCOMPARE( p6c.interiorRing( 0 )->wkbType(), QgsWkbTypes::LineString25D );
    5458                 :          1 :   QCOMPARE( p6c.interiorRing( 0 )->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::Point25D, 0.1, 0.1, 1 ) );
    5459                 :            :   //add a LineStringM, should become LineString25D
    5460                 :          1 :   ring = new QgsLineString();
    5461                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 0.1, 0.1, 0, 1 )
    5462                 :          1 :                    << QgsPoint( QgsWkbTypes::PointM, 0.1, 0.2, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 0.2, 0.2, 0, 3 )
    5463                 :          1 :                    << QgsPoint( QgsWkbTypes::PointM, 0.2, 0.1, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 0.1, 0.1, 0, 1 ) );
    5464                 :          1 :   QCOMPARE( ring->wkbType(), QgsWkbTypes::LineStringM );
    5465                 :          1 :   p6c.addInteriorRing( ring );
    5466                 :          1 :   QVERIFY( p6c.interiorRing( 1 ) );
    5467                 :          1 :   QVERIFY( p6c.interiorRing( 1 )->is3D() );
    5468                 :          1 :   QVERIFY( !p6c.interiorRing( 1 )->isMeasure() );
    5469                 :          1 :   QCOMPARE( p6c.interiorRing( 1 )->wkbType(), QgsWkbTypes::LineString25D );
    5470                 :          1 :   QCOMPARE( p6c.interiorRing( 1 )->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::Point25D, 0.1, 0.1 ) );
    5471                 :            : 
    5472                 :            :   //add curved ring to polygon
    5473                 :          1 :   circularRing = new QgsCircularString();
    5474                 :          2 :   circularRing->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
    5475                 :          1 :                            << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) );
    5476                 :          1 :   QVERIFY( circularRing->hasCurvedSegments() );
    5477                 :          1 :   p6c.addInteriorRing( circularRing );
    5478                 :          1 :   QVERIFY( p6c.interiorRing( 2 ) );
    5479                 :          1 :   QVERIFY( !p6c.interiorRing( 2 )->hasCurvedSegments() );
    5480                 :          1 :   QVERIFY( p6c.interiorRing( 2 )->is3D() );
    5481                 :          1 :   QVERIFY( !p6c.interiorRing( 2 )->isMeasure() );
    5482                 :          1 :   QCOMPARE( p6c.interiorRing( 2 )->wkbType(), QgsWkbTypes::LineString25D );
    5483                 :            : 
    5484                 :            :   // alternate constructor
    5485                 :          2 :   QgsPolygon pc6( new QgsLineString( QVector<QgsPoint>() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 ) << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) ),
    5486                 :          1 :                   QList< QgsLineString *>() << new QgsLineString( QVector< QgsPoint >() << QgsPoint( 1, 1 ) << QgsPoint( 2, 1 ) << QgsPoint( 2, 2 ) << QgsPoint( 1, 2 ) << QgsPoint( 1, 1 ) )
    5487                 :          1 :                   << new QgsLineString( QVector< QgsPoint >() << QgsPoint( 3, 1 ) << QgsPoint( 4, 1 ) << QgsPoint( 4, 2 ) << QgsPoint( 3, 2 ) << QgsPoint( 3, 1 ) ) );
    5488                 :          2 :   QCOMPARE( pc6.asWkt(), QStringLiteral( "Polygon ((0 0, 0 10, 10 10, 10 0, 0 0),(1 1, 2 1, 2 2, 1 2, 1 1),(3 1, 4 1, 4 2, 3 2, 3 1))" ) );
    5489                 :            : 
    5490                 :            :   //set interior rings
    5491                 :          1 :   QgsPolygon p7;
    5492                 :          1 :   ext = new QgsLineString();
    5493                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
    5494                 :          1 :                   << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) );
    5495                 :          1 :   p7.setExteriorRing( ext );
    5496                 :            :   //add a list of rings with mixed types
    5497                 :          1 :   QVector< QgsCurve * > rings;
    5498                 :          1 :   rings << new QgsLineString();
    5499                 :          2 :   static_cast< QgsLineString *>( rings[0] )->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.1, 1 )
    5500                 :          1 :       << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.2, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 0.2, 0.2, 3 )
    5501                 :          1 :       << QgsPoint( QgsWkbTypes::PointZ, 0.2, 0.1, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.1, 1 ) );
    5502                 :          1 :   rings << new QgsLineString();
    5503                 :          2 :   static_cast< QgsLineString *>( rings[1] )->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 0.3, 0.3, 0, 1 )
    5504                 :          1 :       << QgsPoint( QgsWkbTypes::PointM, 0.3, 0.4, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 0.4, 0.4, 0, 3 )
    5505                 :          1 :       << QgsPoint( QgsWkbTypes::PointM, 0.4, 0.3, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 0.3, 0.3, 0, 1 ) );
    5506                 :            :   //throw an empty ring in too
    5507                 :          1 :   rings << 0;
    5508                 :          1 :   rings << new QgsCircularString();
    5509                 :          2 :   static_cast< QgsCircularString *>( rings[3] )->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
    5510                 :          1 :       << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) );
    5511                 :          1 :   p7.setInteriorRings( rings );
    5512                 :          1 :   QCOMPARE( p7.numInteriorRings(), 3 );
    5513                 :          1 :   QVERIFY( p7.interiorRing( 0 ) );
    5514                 :          1 :   QVERIFY( !p7.interiorRing( 0 )->is3D() );
    5515                 :          1 :   QVERIFY( !p7.interiorRing( 0 )->isMeasure() );
    5516                 :          1 :   QCOMPARE( p7.interiorRing( 0 )->wkbType(), QgsWkbTypes::LineString );
    5517                 :          1 :   QCOMPARE( p7.interiorRing( 0 )->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::Point, 0.1, 0.1 ) );
    5518                 :          1 :   QVERIFY( p7.interiorRing( 1 ) );
    5519                 :          1 :   QVERIFY( !p7.interiorRing( 1 )->is3D() );
    5520                 :          1 :   QVERIFY( !p7.interiorRing( 1 )->isMeasure() );
    5521                 :          1 :   QCOMPARE( p7.interiorRing( 1 )->wkbType(), QgsWkbTypes::LineString );
    5522                 :          1 :   QCOMPARE( p7.interiorRing( 1 )->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::Point, 0.3, 0.3 ) );
    5523                 :          1 :   QVERIFY( p7.interiorRing( 2 ) );
    5524                 :          1 :   QVERIFY( !p7.interiorRing( 2 )->is3D() );
    5525                 :          1 :   QVERIFY( !p7.interiorRing( 2 )->isMeasure() );
    5526                 :          1 :   QCOMPARE( p7.interiorRing( 2 )->wkbType(), QgsWkbTypes::LineString );
    5527                 :            : 
    5528                 :            :   //set rings with existing
    5529                 :          1 :   rings.clear();
    5530                 :          1 :   rings << new QgsLineString();
    5531                 :          2 :   static_cast< QgsLineString *>( rings[0] )->setPoints( QgsPointSequence() << QgsPoint( 0.8, 0.8 )
    5532                 :          1 :       << QgsPoint( 0.8, 0.9 ) << QgsPoint( 0.9, 0.9 )
    5533                 :          1 :       << QgsPoint( 0.9, 0.8 ) << QgsPoint( 0.8, 0.8 ) );
    5534                 :          1 :   p7.setInteriorRings( rings );
    5535                 :          1 :   QCOMPARE( p7.numInteriorRings(), 1 );
    5536                 :          1 :   QVERIFY( p7.interiorRing( 0 ) );
    5537                 :          1 :   QVERIFY( !p7.interiorRing( 0 )->is3D() );
    5538                 :          1 :   QVERIFY( !p7.interiorRing( 0 )->isMeasure() );
    5539                 :          1 :   QCOMPARE( p7.interiorRing( 0 )->wkbType(), QgsWkbTypes::LineString );
    5540                 :          1 :   QCOMPARE( p7.interiorRing( 0 )->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::Point, 0.8, 0.8 ) );
    5541                 :          1 :   rings.clear();
    5542                 :          1 :   p7.setInteriorRings( rings );
    5543                 :          1 :   QCOMPARE( p7.numInteriorRings(), 0 );
    5544                 :            : 
    5545                 :            :   //change dimensionality of interior rings using setExteriorRing
    5546                 :          1 :   QgsPolygon p7a;
    5547                 :          1 :   ext = new QgsLineString();
    5548                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 ) << QgsPoint( QgsWkbTypes::PointZ, 0, 10, 2 )
    5549                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 10, 10, 1 ) << QgsPoint( QgsWkbTypes::PointZ, 10, 0, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 ) );
    5550                 :          1 :   p7a.setExteriorRing( ext );
    5551                 :          1 :   rings.clear();
    5552                 :          1 :   rings << new QgsLineString();
    5553                 :          2 :   static_cast< QgsLineString *>( rings[0] )->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.1, 1 )
    5554                 :          1 :       << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.2, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 0.2, 0.2, 3 )
    5555                 :          1 :       << QgsPoint( QgsWkbTypes::PointZ, 0.2, 0.1, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.1, 1 ) );
    5556                 :          1 :   rings << new QgsLineString();
    5557                 :          2 :   static_cast< QgsLineString *>( rings[1] )->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0.3, 0.3, 1 )
    5558                 :          1 :       << QgsPoint( QgsWkbTypes::PointZ, 0.3, 0.4, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 0.4, 0.4, 3 )
    5559                 :          1 :       << QgsPoint( QgsWkbTypes::PointZ, 0.4, 0.3, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0.3, 0.3,  1 ) );
    5560                 :          1 :   p7a.setInteriorRings( rings );
    5561                 :          1 :   QVERIFY( p7a.is3D() );
    5562                 :          1 :   QVERIFY( !p7a.isMeasure() );
    5563                 :          1 :   QVERIFY( p7a.interiorRing( 0 )->is3D() );
    5564                 :          1 :   QVERIFY( !p7a.interiorRing( 0 )->isMeasure() );
    5565                 :          1 :   QVERIFY( p7a.interiorRing( 1 )->is3D() );
    5566                 :          1 :   QVERIFY( !p7a.interiorRing( 1 )->isMeasure() );
    5567                 :            :   //reset exterior ring to 2d
    5568                 :          1 :   ext = new QgsLineString();
    5569                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 )
    5570                 :          1 :                   << QgsPoint( 10, 10 ) << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) );
    5571                 :          1 :   p7a.setExteriorRing( ext );
    5572                 :          1 :   QVERIFY( !p7a.is3D() );
    5573                 :          1 :   QVERIFY( !p7a.interiorRing( 0 )->is3D() ); //rings should also be made 2D
    5574                 :          1 :   QVERIFY( !p7a.interiorRing( 1 )->is3D() );
    5575                 :            :   //reset exterior ring to LineStringM
    5576                 :          1 :   ext = new QgsLineString();
    5577                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 0, 0 ) << QgsPoint( QgsWkbTypes::PointM, 0, 10 )
    5578                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 10, 10 ) << QgsPoint( QgsWkbTypes::PointM, 10, 0 ) << QgsPoint( QgsWkbTypes::PointM, 0, 0 ) );
    5579                 :          1 :   p7a.setExteriorRing( ext );
    5580                 :          1 :   QVERIFY( p7a.isMeasure() );
    5581                 :          1 :   QVERIFY( p7a.interiorRing( 0 )->isMeasure() ); //rings should also gain measure
    5582                 :          1 :   QVERIFY( p7a.interiorRing( 1 )->isMeasure() );
    5583                 :            :   //25D exterior ring
    5584                 :          1 :   ext = new QgsLineString();
    5585                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point25D, 0, 0 ) << QgsPoint( QgsWkbTypes::Point25D, 0, 10 )
    5586                 :          1 :                   << QgsPoint( QgsWkbTypes::Point25D, 10, 10 ) << QgsPoint( QgsWkbTypes::Point25D, 10, 0 ) << QgsPoint( QgsWkbTypes::Point25D, 0, 0 ) );
    5587                 :          1 :   p7a.setExteriorRing( ext );
    5588                 :          1 :   QVERIFY( p7a.is3D() );
    5589                 :          1 :   QVERIFY( !p7a.isMeasure() );
    5590                 :          1 :   QVERIFY( p7a.interiorRing( 0 )->is3D() ); //rings should also be made 25D
    5591                 :          1 :   QVERIFY( !p7a.interiorRing( 0 )->isMeasure() );
    5592                 :          1 :   QVERIFY( p7a.interiorRing( 1 )->is3D() );
    5593                 :          1 :   QVERIFY( !p7a.interiorRing( 1 )->isMeasure() );
    5594                 :          1 :   QCOMPARE( p7a.interiorRing( 0 )->wkbType(), QgsWkbTypes::LineString25D );
    5595                 :          1 :   QCOMPARE( p7a.interiorRing( 1 )->wkbType(), QgsWkbTypes::LineString25D );
    5596                 :            : 
    5597                 :            : 
    5598                 :            :   //removeInteriorRing
    5599                 :          1 :   QgsPolygon p8;
    5600                 :          1 :   ext = new QgsLineString();
    5601                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
    5602                 :          1 :                   << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) );
    5603                 :          1 :   p8.setExteriorRing( ext );
    5604                 :          1 :   QVERIFY( !p8.removeInteriorRing( -1 ) );
    5605                 :          1 :   QVERIFY( !p8.removeInteriorRing( 0 ) );
    5606                 :          1 :   rings.clear();
    5607                 :          1 :   rings << new QgsLineString();
    5608                 :          2 :   static_cast< QgsLineString *>( rings[0] )->setPoints( QgsPointSequence() << QgsPoint( 0.1, 0.1 )
    5609                 :          1 :       << QgsPoint( 0.1, 0.2 ) << QgsPoint( 0.2, 0.2 )
    5610                 :          1 :       << QgsPoint( 0.2, 0.1 ) << QgsPoint( 0.1, 0.1 ) );
    5611                 :          1 :   rings << new QgsLineString();
    5612                 :          2 :   static_cast< QgsLineString *>( rings[1] )->setPoints( QgsPointSequence() << QgsPoint( 0.3, 0.3 )
    5613                 :          1 :       << QgsPoint( 0.3, 0.4 ) << QgsPoint( 0.4, 0.4 )
    5614                 :          1 :       << QgsPoint( 0.4, 0.3 ) << QgsPoint( 0.3, 0.3 ) );
    5615                 :          1 :   rings << new QgsLineString();
    5616                 :          2 :   static_cast< QgsLineString *>( rings[2] )->setPoints( QgsPointSequence() << QgsPoint( 0.8, 0.8 )
    5617                 :          1 :       << QgsPoint( 0.8, 0.9 ) << QgsPoint( 0.9, 0.9 )
    5618                 :          1 :       << QgsPoint( 0.9, 0.8 ) << QgsPoint( 0.8, 0.8 ) );
    5619                 :          1 :   p8.setInteriorRings( rings );
    5620                 :          1 :   QCOMPARE( p8.numInteriorRings(), 3 );
    5621                 :          1 :   QVERIFY( p8.removeInteriorRing( 0 ) );
    5622                 :          1 :   QCOMPARE( p8.numInteriorRings(), 2 );
    5623                 :          1 :   QCOMPARE( p8.interiorRing( 0 )->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( 0.3, 0.3 ) );
    5624                 :          1 :   QCOMPARE( p8.interiorRing( 1 )->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( 0.8, 0.8 ) );
    5625                 :          1 :   QVERIFY( p8.removeInteriorRing( 1 ) );
    5626                 :          1 :   QCOMPARE( p8.numInteriorRings(), 1 );
    5627                 :          1 :   QCOMPARE( p8.interiorRing( 0 )->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( 0.3, 0.3 ) );
    5628                 :          1 :   QVERIFY( p8.removeInteriorRing( 0 ) );
    5629                 :          1 :   QCOMPARE( p8.numInteriorRings(), 0 );
    5630                 :          1 :   QVERIFY( !p8.removeInteriorRing( 0 ) );
    5631                 :            : 
    5632                 :            :   //clear
    5633                 :          1 :   QgsPolygon p9;
    5634                 :          1 :   ext = new QgsLineString();
    5635                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 )
    5636                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 0, 10, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 10, 10, 3 )
    5637                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 10, 0, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 ) );
    5638                 :          1 :   p9.setExteriorRing( ext );
    5639                 :          1 :   ring = new QgsLineString();
    5640                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 1, 1 )
    5641                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZ, 1, 9, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 9, 9, 3 )
    5642                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZ, 9, 1, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 1, 1, 1 ) );
    5643                 :          1 :   p9.addInteriorRing( ring );
    5644                 :          1 :   QCOMPARE( p9.numInteriorRings(), 1 );
    5645                 :          1 :   p9.clear();
    5646                 :          1 :   QVERIFY( p9.isEmpty() );
    5647                 :          1 :   QCOMPARE( p9.numInteriorRings(), 0 );
    5648                 :          1 :   QCOMPARE( p9.nCoordinates(), 0 );
    5649                 :          1 :   QCOMPARE( p9.ringCount(), 0 );
    5650                 :          1 :   QCOMPARE( p9.partCount(), 0 );
    5651                 :          1 :   QVERIFY( !p9.is3D() );
    5652                 :          1 :   QVERIFY( !p9.isMeasure() );
    5653                 :          1 :   QCOMPARE( p9.wkbType(), QgsWkbTypes::Polygon );
    5654                 :            : 
    5655                 :            :   //equality operator
    5656                 :          1 :   QgsPolygon p10;
    5657                 :          1 :   QgsPolygon p10b;
    5658                 :          1 :   QVERIFY( p10 == p10b );
    5659                 :          1 :   QVERIFY( !( p10 != p10b ) );
    5660                 :          1 :   ext = new QgsLineString();
    5661                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
    5662                 :          1 :                   << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) );
    5663                 :          1 :   p10.setExteriorRing( ext );
    5664                 :          1 :   QVERIFY( !( p10 == p10b ) );
    5665                 :          1 :   QVERIFY( p10 != p10b );
    5666                 :          1 :   ext = new QgsLineString();
    5667                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
    5668                 :          1 :                   << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) );
    5669                 :          1 :   p10b.setExteriorRing( ext );
    5670                 :          1 :   QVERIFY( p10 == p10b );
    5671                 :          1 :   QVERIFY( !( p10 != p10b ) );
    5672                 :          1 :   ext = new QgsLineString();
    5673                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 9 ) << QgsPoint( 9, 9 )
    5674                 :          1 :                   << QgsPoint( 9, 0 ) << QgsPoint( 0, 0 ) );
    5675                 :          1 :   p10b.setExteriorRing( ext );
    5676                 :          1 :   QVERIFY( !( p10 == p10b ) );
    5677                 :          1 :   QVERIFY( p10 != p10b );
    5678                 :          1 :   ext = new QgsLineString();
    5679                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 ) << QgsPoint( QgsWkbTypes::PointZ, 0, 10, 2 )
    5680                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 10, 10, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 10, 0, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 ) );
    5681                 :          1 :   p10b.setExteriorRing( ext );
    5682                 :          1 :   QVERIFY( !( p10 == p10b ) );
    5683                 :          1 :   QVERIFY( p10 != p10b );
    5684                 :          1 :   p10b.setExteriorRing( p10.exteriorRing()->clone() );
    5685                 :          1 :   QVERIFY( p10 == p10b );
    5686                 :          1 :   QVERIFY( !( p10 != p10b ) );
    5687                 :          1 :   ring = new QgsLineString();
    5688                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( 1, 1 )
    5689                 :          1 :                    << QgsPoint( 1, 9 ) << QgsPoint( 9, 9 )
    5690                 :          1 :                    << QgsPoint( 9, 1 ) << QgsPoint( 1, 1 ) );
    5691                 :          1 :   p10.addInteriorRing( ring );
    5692                 :          1 :   QVERIFY( !( p10 == p10b ) );
    5693                 :          1 :   QVERIFY( p10 != p10b );
    5694                 :            : 
    5695                 :          1 :   ring = new QgsLineString();
    5696                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( 2, 1 )
    5697                 :          1 :                    << QgsPoint( 2, 9 ) << QgsPoint( 9, 9 )
    5698                 :          1 :                    << QgsPoint( 9, 1 ) << QgsPoint( 2, 1 ) );
    5699                 :          1 :   p10b.addInteriorRing( ring );
    5700                 :          1 :   QVERIFY( !( p10 == p10b ) );
    5701                 :          1 :   QVERIFY( p10 != p10b );
    5702                 :          1 :   p10b.removeInteriorRing( 0 );
    5703                 :          1 :   p10b.addInteriorRing( p10.interiorRing( 0 )->clone() );
    5704                 :          1 :   QVERIFY( p10 == p10b );
    5705                 :          1 :   QVERIFY( !( p10 != p10b ) );
    5706                 :            : 
    5707                 :          1 :   QgsLineString nonPolygon;
    5708                 :          1 :   QVERIFY( p10 != nonPolygon );
    5709                 :          1 :   QVERIFY( !( p10 == nonPolygon ) );
    5710                 :            : 
    5711                 :            :   //clone
    5712                 :            : 
    5713                 :          1 :   QgsPolygon p11;
    5714                 :          1 :   std::unique_ptr< QgsPolygon >cloned( p11.clone() );
    5715                 :          1 :   QCOMPARE( p11, *cloned );
    5716                 :          1 :   ext = new QgsLineString();
    5717                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 5 )
    5718                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 0, 10, 2, 6 ) << QgsPoint( QgsWkbTypes::PointZM, 10, 10, 3, 7 )
    5719                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 9 ) );
    5720                 :          1 :   p11.setExteriorRing( ext );
    5721                 :          1 :   ring = new QgsLineString();
    5722                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 2 )
    5723                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 1, 9, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZM, 9, 9, 3, 6 )
    5724                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 9, 1, 4, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 7 ) );
    5725                 :          1 :   p11.addInteriorRing( ring );
    5726                 :          1 :   cloned.reset( p11.clone() );
    5727                 :          1 :   QCOMPARE( p11, *cloned );
    5728                 :            : 
    5729                 :            :   //copy constructor
    5730                 :          1 :   QgsPolygon p12;
    5731                 :          1 :   QgsPolygon p13( p12 );
    5732                 :          1 :   QCOMPARE( p12, p13 );
    5733                 :          1 :   ext = new QgsLineString();
    5734                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 5 )
    5735                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 0, 10, 2, 6 ) << QgsPoint( QgsWkbTypes::PointZM, 10, 10, 3, 7 )
    5736                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 9 ) );
    5737                 :          1 :   p12.setExteriorRing( ext );
    5738                 :          1 :   ring = new QgsLineString();
    5739                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 2 )
    5740                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 1, 9, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZM, 9, 9, 3, 6 )
    5741                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 9, 1, 4, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 7 ) );
    5742                 :          1 :   p12.addInteriorRing( ring );
    5743                 :          1 :   QgsPolygon p14( p12 );
    5744                 :          1 :   QCOMPARE( p12, p14 );
    5745                 :            : 
    5746                 :            :   //assignment operator
    5747                 :          1 :   QgsPolygon p15;
    5748                 :          1 :   p15 = p13;
    5749                 :          1 :   QCOMPARE( p13, p15 );
    5750                 :          1 :   p15 = p12;
    5751                 :          1 :   QCOMPARE( p12, p15 );
    5752                 :            : 
    5753                 :            :   //surfaceToPolygon - should be identical given polygon has no curves
    5754                 :          1 :   std::unique_ptr< QgsPolygon > surface( p12.surfaceToPolygon() );
    5755                 :          1 :   QCOMPARE( *surface, p12 );
    5756                 :            :   //toPolygon - should be identical given polygon has no curves
    5757                 :          1 :   std::unique_ptr< QgsPolygon > toP( p12.toPolygon() );
    5758                 :          1 :   QCOMPARE( *toP, p12 );
    5759                 :            : 
    5760                 :            :   //toCurveType
    5761                 :          1 :   std::unique_ptr< QgsCurvePolygon > curveType( p12.toCurveType() );
    5762                 :          1 :   QCOMPARE( curveType->wkbType(), QgsWkbTypes::CurvePolygonZM );
    5763                 :          1 :   QCOMPARE( curveType->exteriorRing()->numPoints(), 5 );
    5764                 :          1 :   QCOMPARE( curveType->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 5 ) );
    5765                 :          1 :   QCOMPARE( curveType->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( QgsWkbTypes::PointZM, 0, 10, 2, 6 ) );
    5766                 :          1 :   QCOMPARE( curveType->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( QgsWkbTypes::PointZM, 10, 10, 3, 7 ) );
    5767                 :          1 :   QCOMPARE( curveType->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 3 ) ), QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) );
    5768                 :          1 :   QCOMPARE( curveType->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 4 ) ), QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 9 ) );
    5769                 :          1 :   QCOMPARE( curveType->numInteriorRings(), 1 );
    5770                 :          1 :   QCOMPARE( curveType->interiorRing( 0 )->numPoints(), 5 );
    5771                 :          1 :   QCOMPARE( curveType->interiorRing( 0 )->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 2 ) );
    5772                 :          1 :   QCOMPARE( curveType->interiorRing( 0 )->vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( QgsWkbTypes::PointZM, 1, 9, 2, 3 ) );
    5773                 :          1 :   QCOMPARE( curveType->interiorRing( 0 )->vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( QgsWkbTypes::PointZM, 9, 9, 3, 6 ) );
    5774                 :          1 :   QCOMPARE( curveType->interiorRing( 0 )->vertexAt( QgsVertexId( 0, 0, 3 ) ), QgsPoint( QgsWkbTypes::PointZM, 9, 1, 4, 4 ) );
    5775                 :          1 :   QCOMPARE( curveType->interiorRing( 0 )->vertexAt( QgsVertexId( 0, 0, 4 ) ), QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 7 ) );
    5776                 :            : 
    5777                 :            :   //to/fromWKB
    5778                 :          1 :   QgsPolygon p16;
    5779                 :          1 :   ext = new QgsLineString();
    5780                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 0, 0 )
    5781                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 0, 10 ) << QgsPoint( QgsWkbTypes::Point, 10, 10 )
    5782                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 10, 0 ) << QgsPoint( QgsWkbTypes::Point, 0, 0 ) );
    5783                 :          1 :   p16.setExteriorRing( ext );
    5784                 :          1 :   ring = new QgsLineString();
    5785                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 1, 1 )
    5786                 :          1 :                    << QgsPoint( QgsWkbTypes::Point, 1, 9 ) << QgsPoint( QgsWkbTypes::Point, 9, 9 )
    5787                 :          1 :                    << QgsPoint( QgsWkbTypes::Point, 9, 1 ) << QgsPoint( QgsWkbTypes::Point, 1, 1 ) );
    5788                 :          1 :   p16.addInteriorRing( ring );
    5789                 :          1 :   QByteArray wkb16 = p16.asWkb();
    5790                 :          1 :   QCOMPARE( wkb16.size(), p16.wkbSize() );
    5791                 :          1 :   QgsPolygon p17;
    5792                 :          1 :   QgsConstWkbPtr wkb16ptr( wkb16 );
    5793                 :          1 :   p17.fromWkb( wkb16ptr );
    5794                 :          1 :   QCOMPARE( p16, p17 );
    5795                 :            :   //PolygonZ
    5796                 :          1 :   p16.clear();
    5797                 :          1 :   p17.clear();
    5798                 :          1 :   ext = new QgsLineString();
    5799                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 )
    5800                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 0, 10, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 10, 10, 3 )
    5801                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 10, 0, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 ) );
    5802                 :          1 :   p16.setExteriorRing( ext );
    5803                 :          1 :   ring = new QgsLineString();
    5804                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 1, 1 )
    5805                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZ, 1, 9, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 9, 9, 3 )
    5806                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZ, 9, 1, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 1, 1, 1 ) );
    5807                 :          1 :   p16.addInteriorRing( ring );
    5808                 :          1 :   wkb16 = p16.asWkb();
    5809                 :          1 :   QCOMPARE( wkb16.size(), p16.wkbSize() );
    5810                 :          1 :   QgsConstWkbPtr wkb16ptr2( wkb16 );
    5811                 :          1 :   p17.fromWkb( wkb16ptr2 );
    5812                 :          1 :   QCOMPARE( p16, p17 );
    5813                 :            :   //PolygonM
    5814                 :          1 :   p16.clear();
    5815                 :          1 :   p17.clear();
    5816                 :          1 :   ext = new QgsLineString();
    5817                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 0, 0, 0, 1 )
    5818                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 0, 10,  0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 10, 10, 0, 3 )
    5819                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 10, 0,  0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 0, 0, 0, 1 ) );
    5820                 :          1 :   p16.setExteriorRing( ext );
    5821                 :          1 :   ring = new QgsLineString();
    5822                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 1, 0, 1 )
    5823                 :          1 :                    << QgsPoint( QgsWkbTypes::PointM, 1, 9, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 9, 9, 0, 3 )
    5824                 :          1 :                    << QgsPoint( QgsWkbTypes::PointM, 9, 1, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 1, 1, 0, 1 ) );
    5825                 :          1 :   p16.addInteriorRing( ring );
    5826                 :          1 :   wkb16 = p16.asWkb();
    5827                 :          1 :   QgsConstWkbPtr wkb16ptr3( wkb16 );
    5828                 :          1 :   p17.fromWkb( wkb16ptr3 );
    5829                 :          1 :   QCOMPARE( p16, p17 );
    5830                 :            :   //PolygonZM
    5831                 :          1 :   p16.clear();
    5832                 :          1 :   p17.clear();
    5833                 :          1 :   ext = new QgsLineString();
    5834                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 5 )
    5835                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 0, 10, 2, 6 ) << QgsPoint( QgsWkbTypes::PointZM, 10, 10, 3, 7 )
    5836                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 9 ) );
    5837                 :          1 :   p16.setExteriorRing( ext );
    5838                 :          1 :   ring = new QgsLineString();
    5839                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 2 )
    5840                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 1, 9, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZM, 9, 9, 3, 6 )
    5841                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 9, 1, 4, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 7 ) );
    5842                 :          1 :   p16.addInteriorRing( ring );
    5843                 :          1 :   wkb16 = p16.asWkb();
    5844                 :          1 :   QgsConstWkbPtr wkb16ptr4( wkb16 );
    5845                 :          1 :   p17.fromWkb( wkb16ptr4 );
    5846                 :          1 :   QCOMPARE( p16, p17 );
    5847                 :            :   //Polygon25D
    5848                 :          1 :   p16.clear();
    5849                 :          1 :   p17.clear();
    5850                 :          1 :   ext = new QgsLineString();
    5851                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point25D, 0, 0, 1 )
    5852                 :          1 :                   << QgsPoint( QgsWkbTypes::Point25D, 0, 10, 2 ) << QgsPoint( QgsWkbTypes::Point25D, 10, 10, 3 )
    5853                 :          1 :                   << QgsPoint( QgsWkbTypes::Point25D, 10, 0, 4 ) << QgsPoint( QgsWkbTypes::Point25D, 0, 0, 1 ) );
    5854                 :          1 :   p16.setExteriorRing( ext );
    5855                 :          1 :   ring = new QgsLineString();
    5856                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point25D, 1, 1, 1 )
    5857                 :          1 :                    << QgsPoint( QgsWkbTypes::Point25D, 1, 9, 2 ) << QgsPoint( QgsWkbTypes::Point25D, 9, 9, 3 )
    5858                 :          1 :                    << QgsPoint( QgsWkbTypes::Point25D, 9, 1, 4 ) << QgsPoint( QgsWkbTypes::Point25D, 1, 1, 1 ) );
    5859                 :          1 :   p16.addInteriorRing( ring );
    5860                 :          1 :   wkb16 = p16.asWkb();
    5861                 :          1 :   p17.clear();
    5862                 :          1 :   QgsConstWkbPtr wkb16ptr5( wkb16 );
    5863                 :          1 :   p17.fromWkb( wkb16ptr5 );
    5864                 :          1 :   QCOMPARE( p16, p17 );
    5865                 :            : 
    5866                 :            :   //bad WKB - check for no crash
    5867                 :          1 :   p17.clear();
    5868                 :          1 :   QgsConstWkbPtr nullPtr( nullptr, 0 );
    5869                 :          1 :   QVERIFY( !p17.fromWkb( nullPtr ) );
    5870                 :          1 :   QCOMPARE( p17.wkbType(), QgsWkbTypes::Polygon );
    5871                 :          1 :   QgsPoint point( 1, 2 );
    5872                 :          1 :   QByteArray wkbPoint = point.asWkb();
    5873                 :          1 :   QgsConstWkbPtr wkbPointPtr( wkbPoint );
    5874                 :          1 :   QVERIFY( !p17.fromWkb( wkbPointPtr ) );
    5875                 :          1 :   QCOMPARE( p17.wkbType(), QgsWkbTypes::Polygon );
    5876                 :            : 
    5877                 :            :   //to/from WKT
    5878                 :          1 :   QgsPolygon p18;
    5879                 :          1 :   ext = new QgsLineString();
    5880                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 5 )
    5881                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 0, 10, 2, 6 ) << QgsPoint( QgsWkbTypes::PointZM, 10, 10, 3, 7 )
    5882                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 9 ) );
    5883                 :          1 :   p18.setExteriorRing( ext );
    5884                 :          1 :   ring = new QgsLineString();
    5885                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 2 )
    5886                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 1, 9, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZM, 9, 9, 3, 6 )
    5887                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 9, 1, 4, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 7 ) );
    5888                 :          1 :   p18.addInteriorRing( ring );
    5889                 :            : 
    5890                 :          1 :   QString wkt = p18.asWkt();
    5891                 :          1 :   QVERIFY( !wkt.isEmpty() );
    5892                 :          1 :   QgsPolygon p19;
    5893                 :          1 :   QVERIFY( p19.fromWkt( wkt ) );
    5894                 :          1 :   QCOMPARE( p18, p19 );
    5895                 :            : 
    5896                 :            :   //bad WKT
    5897                 :          1 :   QVERIFY( !p19.fromWkt( "Point()" ) );
    5898                 :          1 :   QVERIFY( p19.isEmpty() );
    5899                 :          1 :   QVERIFY( !p19.exteriorRing() );
    5900                 :          1 :   QCOMPARE( p19.numInteriorRings(), 0 );
    5901                 :          1 :   QVERIFY( !p19.is3D() );
    5902                 :          1 :   QVERIFY( !p19.isMeasure() );
    5903                 :          1 :   QCOMPARE( p19.wkbType(), QgsWkbTypes::Polygon );
    5904                 :            : 
    5905                 :            :   //as JSON
    5906                 :          1 :   QgsPolygon exportPolygon;
    5907                 :          1 :   ext = new QgsLineString();
    5908                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 0, 0 )
    5909                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 0, 10 ) << QgsPoint( QgsWkbTypes::Point, 10, 10 )
    5910                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 10, 0 ) << QgsPoint( QgsWkbTypes::Point, 0, 0 ) );
    5911                 :          1 :   exportPolygon.setExteriorRing( ext );
    5912                 :            : 
    5913                 :            :   // GML document for compare
    5914                 :          2 :   QDomDocument doc( QStringLiteral( "gml" ) );
    5915                 :            : 
    5916                 :            :   // as GML2
    5917                 :          2 :   QString expectedSimpleGML2( QStringLiteral( "<Polygon xmlns=\"gml\"><outerBoundaryIs xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">0,0 0,10 10,10 10,0 0,0</coordinates></LinearRing></outerBoundaryIs></Polygon>" ) );
    5918                 :          3 :   QGSCOMPAREGML( elemToString( exportPolygon.asGml2( doc ) ), expectedSimpleGML2 );
    5919                 :          2 :   QString expectedGML2empty( QStringLiteral( "<Polygon xmlns=\"gml\"/>" ) );
    5920                 :          3 :   QGSCOMPAREGML( elemToString( QgsPolygon().asGml2( doc ) ), expectedGML2empty );
    5921                 :            : 
    5922                 :            :   //as GML3
    5923                 :          2 :   QString expectedSimpleGML3( QStringLiteral( "<Polygon xmlns=\"gml\"><exterior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">0 0 0 10 10 10 10 0 0 0</posList></LinearRing></exterior></Polygon>" ) );
    5924                 :          1 :   QCOMPARE( elemToString( exportPolygon.asGml3( doc ) ), expectedSimpleGML3 );
    5925                 :          2 :   QString expectedGML3empty( QStringLiteral( "<Polygon xmlns=\"gml\"/>" ) );
    5926                 :          3 :   QGSCOMPAREGML( elemToString( QgsPolygon().asGml3( doc ) ), expectedGML3empty );
    5927                 :            : 
    5928                 :            :   // as JSON
    5929                 :          2 :   QString expectedSimpleJson( QStringLiteral( "{\"coordinates\":[[[0.0,0.0],[0.0,10.0],[10.0,10.0],[10.0,0.0],[0.0,0.0]]],\"type\":\"Polygon\"}" ) );
    5930                 :          1 :   QCOMPARE( exportPolygon.asJson(), expectedSimpleJson );
    5931                 :            : 
    5932                 :          1 :   ring = new QgsLineString();
    5933                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 1, 1 )
    5934                 :          1 :                    << QgsPoint( QgsWkbTypes::Point, 1, 9 ) << QgsPoint( QgsWkbTypes::Point, 9, 9 )
    5935                 :          1 :                    << QgsPoint( QgsWkbTypes::Point, 9, 1 ) << QgsPoint( QgsWkbTypes::Point, 1, 1 ) );
    5936                 :          1 :   exportPolygon.addInteriorRing( ring );
    5937                 :            : 
    5938                 :          2 :   QString expectedJson( QStringLiteral( "{\"coordinates\":[[[0.0,0.0],[0.0,10.0],[10.0,10.0],[10.0,0.0],[0.0,0.0]],[[1.0,1.0],[1.0,9.0],[9.0,9.0],[9.0,1.0],[1.0,1.0]]],\"type\":\"Polygon\"}" ) );
    5939                 :          1 :   QCOMPARE( exportPolygon.asJson(), expectedJson );
    5940                 :            : 
    5941                 :          1 :   QgsPolygon exportPolygonFloat;
    5942                 :          1 :   ext = new QgsLineString();
    5943                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 10 / 9.0, 10 / 9.0 )
    5944                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 10 / 9.0, 100 / 9.0 ) << QgsPoint( QgsWkbTypes::Point, 100 / 9.0, 100 / 9.0 )
    5945                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 100 / 9.0, 10 / 9.0 ) << QgsPoint( QgsWkbTypes::Point, 10 / 9.0, 10 / 9.0 ) );
    5946                 :          1 :   exportPolygonFloat.setExteriorRing( ext );
    5947                 :          1 :   ring = new QgsLineString();
    5948                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 2 / 3.0, 2 / 3.0 )
    5949                 :          1 :                    << QgsPoint( QgsWkbTypes::Point, 2 / 3.0, 4 / 3.0 ) << QgsPoint( QgsWkbTypes::Point, 4 / 3.0, 4 / 3.0 )
    5950                 :          1 :                    << QgsPoint( QgsWkbTypes::Point, 4 / 3.0, 2 / 3.0 ) << QgsPoint( QgsWkbTypes::Point, 2 / 3.0, 2 / 3.0 ) );
    5951                 :          1 :   exportPolygonFloat.addInteriorRing( ring );
    5952                 :            : 
    5953                 :          2 :   QString expectedJsonPrec3( QStringLiteral( "{\"coordinates\":[[[1.111,1.111],[1.111,11.111],[11.111,11.111],[11.111,1.111],[1.111,1.111]],[[0.667,0.667],[0.667,1.333],[1.333,1.333],[1.333,0.667],[0.667,0.667]]],\"type\":\"Polygon\"}" ) );
    5954                 :          1 :   QCOMPARE( exportPolygonFloat.asJson( 3 ), expectedJsonPrec3 );
    5955                 :            : 
    5956                 :            :   // as GML2
    5957                 :          2 :   QString expectedGML2( QStringLiteral( "<Polygon xmlns=\"gml\"><outerBoundaryIs xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">0,0 0,10 10,10 10,0 0,0</coordinates></LinearRing></outerBoundaryIs>" ) );
    5958                 :          1 :   expectedGML2 += QLatin1String( "<innerBoundaryIs xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">1,1 1,9 9,9 9,1 1,1</coordinates></LinearRing></innerBoundaryIs></Polygon>" );
    5959                 :          3 :   QGSCOMPAREGML( elemToString( exportPolygon.asGml2( doc ) ), expectedGML2 );
    5960                 :          2 :   QString expectedGML2prec3( QStringLiteral( "<Polygon xmlns=\"gml\"><outerBoundaryIs xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">1.111,1.111 1.111,11.111 11.111,11.111 11.111,1.111 1.111,1.111</coordinates></LinearRing></outerBoundaryIs>" ) );
    5961                 :          1 :   expectedGML2prec3 += QLatin1String( "<innerBoundaryIs xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">0.667,0.667 0.667,1.333 1.333,1.333 1.333,0.667 0.667,0.667</coordinates></LinearRing></innerBoundaryIs></Polygon>" );
    5962                 :          3 :   QGSCOMPAREGML( elemToString( exportPolygonFloat.asGml2( doc, 3 ) ), expectedGML2prec3 );
    5963                 :            : 
    5964                 :            :   //as GML3
    5965                 :          2 :   QString expectedGML3( QStringLiteral( "<Polygon xmlns=\"gml\"><exterior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">0 0 0 10 10 10 10 0 0 0</posList></LinearRing></exterior>" ) );
    5966                 :          1 :   expectedGML3 += QLatin1String( "<interior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">1 1 1 9 9 9 9 1 1 1</posList></LinearRing></interior></Polygon>" );
    5967                 :            : 
    5968                 :          1 :   QCOMPARE( elemToString( exportPolygon.asGml3( doc ) ), expectedGML3 );
    5969                 :          2 :   QString expectedGML3prec3( QStringLiteral( "<Polygon xmlns=\"gml\"><exterior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">1.111 1.111 1.111 11.111 11.111 11.111 11.111 1.111 1.111 1.111</posList></LinearRing></exterior>" ) );
    5970                 :          1 :   expectedGML3prec3 += QLatin1String( "<interior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">0.667 0.667 0.667 1.333 1.333 1.333 1.333 0.667 0.667 0.667</posList></LinearRing></interior></Polygon>" );
    5971                 :          1 :   QCOMPARE( elemToString( exportPolygonFloat.asGml3( doc, 3 ) ), expectedGML3prec3 );
    5972                 :            : 
    5973                 :            :   //asKML
    5974                 :          2 :   QString expectedKml( QStringLiteral( "<Polygon><outerBoundaryIs><LinearRing><altitudeMode>clampToGround</altitudeMode><coordinates>0,0,0 0,10,0 10,10,0 10,0,0 0,0,0</coordinates></LinearRing></outerBoundaryIs><innerBoundaryIs><LinearRing><altitudeMode>clampToGround</altitudeMode><coordinates>1,1,0 1,9,0 9,9,0 9,1,0 1,1,0</coordinates></LinearRing></innerBoundaryIs></Polygon>" ) );
    5975                 :          1 :   QCOMPARE( exportPolygon.asKml(), expectedKml );
    5976                 :          2 :   QString expectedKmlPrec3( QStringLiteral( "<Polygon><outerBoundaryIs><LinearRing><altitudeMode>clampToGround</altitudeMode><coordinates>1.111,1.111,0 1.111,11.111,0 11.111,11.111,0 11.111,1.111,0 1.111,1.111,0</coordinates></LinearRing></outerBoundaryIs><innerBoundaryIs><LinearRing><altitudeMode>clampToGround</altitudeMode><coordinates>0.667,0.667,0 0.667,1.333,0 1.333,1.333,0 1.333,0.667,0 0.667,0.667,0</coordinates></LinearRing></innerBoundaryIs></Polygon>" ) );
    5977                 :          1 :   QCOMPARE( exportPolygonFloat.asKml( 3 ), expectedKmlPrec3 );
    5978                 :            : 
    5979                 :            :   //removing the fourth to last vertex removes the whole ring
    5980                 :          1 :   QgsPolygon p20;
    5981                 :          1 :   QgsLineString *p20ExteriorRing = new QgsLineString();
    5982                 :          1 :   p20ExteriorRing->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 ) << QgsPoint( 0, 0 ) );
    5983                 :          1 :   p20.setExteriorRing( p20ExteriorRing );
    5984                 :          1 :   QVERIFY( p20.exteriorRing() );
    5985                 :          1 :   p20.deleteVertex( QgsVertexId( 0, 0, 2 ) );
    5986                 :          1 :   QVERIFY( !p20.exteriorRing() );
    5987                 :            : 
    5988                 :            :   //boundary
    5989                 :          1 :   QgsLineString boundary1;
    5990                 :          1 :   boundary1.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 )  << QgsPoint( 0, 0 ) );
    5991                 :          1 :   QgsPolygon boundaryPolygon;
    5992                 :          1 :   QVERIFY( !boundaryPolygon.boundary() );
    5993                 :            : 
    5994                 :          1 :   boundaryPolygon.setExteriorRing( boundary1.clone() );
    5995                 :          1 :   QgsAbstractGeometry *boundary = boundaryPolygon.boundary();
    5996                 :          1 :   QgsLineString *lineBoundary = dynamic_cast< QgsLineString * >( boundary );
    5997                 :          1 :   QVERIFY( lineBoundary );
    5998                 :          1 :   QCOMPARE( lineBoundary->numPoints(), 4 );
    5999                 :          1 :   QCOMPARE( lineBoundary->xAt( 0 ), 0.0 );
    6000                 :          1 :   QCOMPARE( lineBoundary->xAt( 1 ), 1.0 );
    6001                 :          1 :   QCOMPARE( lineBoundary->xAt( 2 ), 1.0 );
    6002                 :          1 :   QCOMPARE( lineBoundary->xAt( 3 ), 0.0 );
    6003                 :          1 :   QCOMPARE( lineBoundary->yAt( 0 ), 0.0 );
    6004                 :          1 :   QCOMPARE( lineBoundary->yAt( 1 ), 0.0 );
    6005                 :          1 :   QCOMPARE( lineBoundary->yAt( 2 ), 1.0 );
    6006                 :          1 :   QCOMPARE( lineBoundary->yAt( 3 ), 0.0 );
    6007                 :          1 :   delete boundary;
    6008                 :            : 
    6009                 :            :   // add interior rings
    6010                 :          1 :   QgsLineString boundaryRing1;
    6011                 :          1 :   boundaryRing1.setPoints( QgsPointSequence() << QgsPoint( 0.1, 0.1 ) << QgsPoint( 0.2, 0.1 ) << QgsPoint( 0.2, 0.2 )  << QgsPoint( 0.1, 0.1 ) );
    6012                 :          1 :   QgsLineString boundaryRing2;
    6013                 :          1 :   boundaryRing2.setPoints( QgsPointSequence() << QgsPoint( 0.8, 0.8 ) << QgsPoint( 0.9, 0.8 ) << QgsPoint( 0.9, 0.9 )  << QgsPoint( 0.8, 0.8 ) );
    6014                 :          1 :   boundaryPolygon.setInteriorRings( QVector< QgsCurve * >() << boundaryRing1.clone() << boundaryRing2.clone() );
    6015                 :          1 :   boundary = boundaryPolygon.boundary();
    6016                 :          1 :   QgsMultiLineString *multiLineBoundary = dynamic_cast< QgsMultiLineString * >( boundary );
    6017                 :          1 :   QVERIFY( multiLineBoundary );
    6018                 :          1 :   QCOMPARE( multiLineBoundary->numGeometries(), 3 );
    6019                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 0 ) )->numPoints(), 4 );
    6020                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 0 ) )->xAt( 0 ), 0.0 );
    6021                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 0 ) )->xAt( 1 ), 1.0 );
    6022                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 0 ) )->xAt( 2 ), 1.0 );
    6023                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 0 ) )->xAt( 3 ), 0.0 );
    6024                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 0 ) )->yAt( 0 ), 0.0 );
    6025                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 0 ) )->yAt( 1 ), 0.0 );
    6026                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 0 ) )->yAt( 2 ), 1.0 );
    6027                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 0 ) )->yAt( 3 ), 0.0 );
    6028                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 1 ) )->numPoints(), 4 );
    6029                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 1 ) )->xAt( 0 ), 0.1 );
    6030                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 1 ) )->xAt( 1 ), 0.2 );
    6031                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 1 ) )->xAt( 2 ), 0.2 );
    6032                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 1 ) )->xAt( 3 ), 0.1 );
    6033                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 1 ) )->yAt( 0 ), 0.1 );
    6034                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 1 ) )->yAt( 1 ), 0.1 );
    6035                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 1 ) )->yAt( 2 ), 0.2 );
    6036                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 1 ) )->yAt( 3 ), 0.1 );
    6037                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 2 ) )->numPoints(), 4 );
    6038                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 2 ) )->xAt( 0 ), 0.8 );
    6039                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 2 ) )->xAt( 1 ), 0.9 );
    6040                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 2 ) )->xAt( 2 ), 0.9 );
    6041                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 2 ) )->xAt( 3 ), 0.8 );
    6042                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 2 ) )->yAt( 0 ), 0.8 );
    6043                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 2 ) )->yAt( 1 ), 0.8 );
    6044                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 2 ) )->yAt( 2 ), 0.9 );
    6045                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 2 ) )->yAt( 3 ), 0.8 );
    6046                 :          1 :   boundaryPolygon.setInteriorRings( QVector< QgsCurve * >() );
    6047                 :          1 :   delete boundary;
    6048                 :            : 
    6049                 :            :   //test boundary with z
    6050                 :          2 :   boundary1.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 10 ) << QgsPoint( QgsWkbTypes::PointZ, 1, 0, 15 )
    6051                 :          1 :                        << QgsPoint( QgsWkbTypes::PointZ, 1, 1, 20 )  << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 10 ) );
    6052                 :          1 :   boundaryPolygon.setExteriorRing( boundary1.clone() );
    6053                 :          1 :   boundary = boundaryPolygon.boundary();
    6054                 :          1 :   lineBoundary = dynamic_cast< QgsLineString * >( boundary );
    6055                 :          1 :   QVERIFY( lineBoundary );
    6056                 :          1 :   QCOMPARE( lineBoundary->numPoints(), 4 );
    6057                 :          1 :   QCOMPARE( lineBoundary->wkbType(), QgsWkbTypes::LineStringZ );
    6058                 :          1 :   QCOMPARE( lineBoundary->zAt( 0 ), 10.0 );
    6059                 :          1 :   QCOMPARE( lineBoundary->zAt( 1 ), 15.0 );
    6060                 :          1 :   QCOMPARE( lineBoundary->zAt( 2 ), 20.0 );
    6061                 :          1 :   QCOMPARE( lineBoundary->zAt( 3 ), 10.0 );
    6062                 :          1 :   delete boundary;
    6063                 :            : 
    6064                 :            :   // point distance to boundary
    6065                 :            : 
    6066                 :          1 :   QgsLineString pd1;
    6067                 :          1 :   pd1.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 ) << QgsPoint( 0, 1 ) << QgsPoint( 0, 0 ) );
    6068                 :          1 :   QgsPolygon pd;
    6069                 :            :   // no meaning, but let's not crash
    6070                 :          1 :   ( void )pd.pointDistanceToBoundary( 0, 0 );
    6071                 :            : 
    6072                 :          1 :   pd.setExteriorRing( pd1.clone() );
    6073                 :          1 :   QGSCOMPARENEAR( pd.pointDistanceToBoundary( 0, 0.5 ), 0.0, 0.0000000001 );
    6074                 :          1 :   QGSCOMPARENEAR( pd.pointDistanceToBoundary( 0.1, 0.5 ), 0.1, 0.0000000001 );
    6075                 :          1 :   QGSCOMPARENEAR( pd.pointDistanceToBoundary( -0.1, 0.5 ), -0.1, 0.0000000001 );
    6076                 :            :   // with a ring
    6077                 :          1 :   QgsLineString pdRing1;
    6078                 :          1 :   pdRing1.setPoints( QgsPointSequence() << QgsPoint( 0.1, 0.1 ) << QgsPoint( 0.2, 0.1 ) << QgsPoint( 0.2, 0.6 )  << QgsPoint( 0.1, 0.6 ) << QgsPoint( 0.1, 0.1 ) );
    6079                 :          1 :   pd.setInteriorRings( QVector< QgsCurve * >() << pdRing1.clone() );
    6080                 :          1 :   QGSCOMPARENEAR( pd.pointDistanceToBoundary( 0, 0.5 ), 0.0, 0.0000000001 );
    6081                 :          1 :   QGSCOMPARENEAR( pd.pointDistanceToBoundary( 0.1, 0.5 ), 0.0, 0.0000000001 );
    6082                 :          1 :   QGSCOMPARENEAR( pd.pointDistanceToBoundary( 0.01, 0.5 ), 0.01, 0.0000000001 );
    6083                 :          1 :   QGSCOMPARENEAR( pd.pointDistanceToBoundary( 0.08, 0.5 ), 0.02, 0.0000000001 );
    6084                 :          1 :   QGSCOMPARENEAR( pd.pointDistanceToBoundary( 0.12, 0.5 ), -0.02, 0.0000000001 );
    6085                 :          1 :   QGSCOMPARENEAR( pd.pointDistanceToBoundary( -0.1, 0.5 ), -0.1, 0.0000000001 );
    6086                 :            : 
    6087                 :            :   // remove interior rings
    6088                 :          1 :   QgsLineString removeRingsExt;
    6089                 :          1 :   removeRingsExt.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 )  << QgsPoint( 0, 0 ) );
    6090                 :          1 :   QgsPolygon removeRings1;
    6091                 :          1 :   removeRings1.removeInteriorRings();
    6092                 :            : 
    6093                 :          1 :   removeRings1.setExteriorRing( boundary1.clone() );
    6094                 :          1 :   removeRings1.removeInteriorRings();
    6095                 :          1 :   QCOMPARE( removeRings1.numInteriorRings(), 0 );
    6096                 :            : 
    6097                 :            :   // add interior rings
    6098                 :          1 :   QgsLineString removeRingsRing1;
    6099                 :          1 :   removeRingsRing1.setPoints( QgsPointSequence() << QgsPoint( 0.1, 0.1 ) << QgsPoint( 0.2, 0.1 ) << QgsPoint( 0.2, 0.2 )  << QgsPoint( 0.1, 0.1 ) );
    6100                 :          1 :   QgsLineString removeRingsRing2;
    6101                 :          1 :   removeRingsRing2.setPoints( QgsPointSequence() << QgsPoint( 0.6, 0.8 ) << QgsPoint( 0.9, 0.8 ) << QgsPoint( 0.9, 0.9 )  << QgsPoint( 0.6, 0.8 ) );
    6102                 :          1 :   removeRings1.setInteriorRings( QVector< QgsCurve * >() << removeRingsRing1.clone() << removeRingsRing2.clone() );
    6103                 :            : 
    6104                 :            :   // remove ring with size filter
    6105                 :          1 :   removeRings1.removeInteriorRings( 0.0075 );
    6106                 :          1 :   QCOMPARE( removeRings1.numInteriorRings(), 1 );
    6107                 :            : 
    6108                 :            :   // remove ring with no size filter
    6109                 :          1 :   removeRings1.removeInteriorRings();
    6110                 :          1 :   QCOMPARE( removeRings1.numInteriorRings(), 0 );
    6111                 :            : 
    6112                 :            :   // cast
    6113                 :          1 :   QVERIFY( !QgsPolygon().cast( nullptr ) );
    6114                 :          1 :   QgsPolygon pCast;
    6115                 :          1 :   QVERIFY( QgsPolygon().cast( &pCast ) );
    6116                 :          1 :   QgsPolygon pCast2;
    6117                 :          2 :   pCast2.fromWkt( QStringLiteral( "PolygonZ((0 0 0, 0 1 1, 1 0 2, 0 0 0))" ) );
    6118                 :          1 :   QVERIFY( QgsPolygon().cast( &pCast2 ) );
    6119                 :          2 :   pCast2.fromWkt( QStringLiteral( "PolygonM((0 0 1, 0 1 2, 1 0 3, 0 0 1))" ) );
    6120                 :          1 :   QVERIFY( QgsPolygon().cast( &pCast2 ) );
    6121                 :          2 :   pCast2.fromWkt( QStringLiteral( "PolygonZM((0 0 0 1, 0 1 1 2, 1 0 2 3, 0 0 0 1))" ) );
    6122                 :          1 :   QVERIFY( QgsPolygon().cast( &pCast2 ) );
    6123                 :            : 
    6124                 :            :   //transform
    6125                 :            :   //CRS transform
    6126                 :          2 :   QgsCoordinateReferenceSystem sourceSrs( QStringLiteral( "EPSG:3994" ) );
    6127                 :          2 :   QgsCoordinateReferenceSystem destSrs( QStringLiteral( "EPSG:4202" ) ); // want a transform with ellipsoid change
    6128                 :          1 :   QgsCoordinateTransform tr( sourceSrs, destSrs, QgsProject::instance() );
    6129                 :            : 
    6130                 :            :   // 2d CRS transform
    6131                 :          1 :   QgsPolygon pTransform;
    6132                 :          1 :   QgsLineString l21;
    6133                 :          2 :   l21.setPoints( QgsPointSequence() << QgsPoint( 6374985, -3626584 )
    6134                 :          1 :                  << QgsPoint( 6274985, -3526584 )
    6135                 :          1 :                  << QgsPoint( 6474985, -3526584 )
    6136                 :          1 :                  << QgsPoint( 6374985, -3626584 ) );
    6137                 :          1 :   pTransform.setExteriorRing( l21.clone() );
    6138                 :          1 :   pTransform.addInteriorRing( l21.clone() );
    6139                 :          1 :   pTransform.transform( tr, QgsCoordinateTransform::ForwardTransform );
    6140                 :          1 :   const QgsLineString *extR = static_cast< const QgsLineString * >( pTransform.exteriorRing() );
    6141                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).x(), 175.771, 0.001 );
    6142                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).y(), -39.724, 0.001 );
    6143                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).x(),  174.581448, 0.001 );
    6144                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).y(), -38.7999, 0.001 );
    6145                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).x(),  176.958633, 0.001 );
    6146                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).y(), -38.7999, 0.001 );
    6147                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).x(),  175.771, 0.001 );
    6148                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).y(), -39.724, 0.001 );
    6149                 :          1 :   QGSCOMPARENEAR( pTransform.exteriorRing()->boundingBox().xMinimum(), 174.581448, 0.001 );
    6150                 :          1 :   QGSCOMPARENEAR( pTransform.exteriorRing()->boundingBox().yMinimum(), -39.724, 0.001 );
    6151                 :          1 :   QGSCOMPARENEAR( pTransform.exteriorRing()->boundingBox().xMaximum(), 176.959, 0.001 );
    6152                 :          1 :   QGSCOMPARENEAR( pTransform.exteriorRing()->boundingBox().yMaximum(), -38.7999, 0.001 );
    6153                 :          1 :   const QgsLineString *intR = static_cast< const QgsLineString * >( pTransform.interiorRing( 0 ) );
    6154                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).x(), 175.771, 0.001 );
    6155                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).y(), -39.724, 0.001 );
    6156                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).x(),  174.581448, 0.001 );
    6157                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).y(), -38.7999, 0.001 );
    6158                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).x(),  176.958633, 0.001 );
    6159                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).y(), -38.7999, 0.001 );
    6160                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).x(),  175.771, 0.001 );
    6161                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).y(), -39.724, 0.001 );
    6162                 :          1 :   QGSCOMPARENEAR( pTransform.interiorRing( 0 )->boundingBox().xMinimum(), 174.581448, 0.001 );
    6163                 :          1 :   QGSCOMPARENEAR( pTransform.interiorRing( 0 )->boundingBox().yMinimum(), -39.724, 0.001 );
    6164                 :          1 :   QGSCOMPARENEAR( pTransform.interiorRing( 0 )->boundingBox().xMaximum(), 176.959, 0.001 );
    6165                 :          1 :   QGSCOMPARENEAR( pTransform.interiorRing( 0 )->boundingBox().yMaximum(), -38.7999, 0.001 );
    6166                 :            : 
    6167                 :            :   //3d CRS transform
    6168                 :          1 :   QgsLineString l22;
    6169                 :          2 :   l22.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 6374985, -3626584, 1, 2 )
    6170                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 6274985, -3526584, 3, 4 )
    6171                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 6474985, -3526584, 5, 6 )
    6172                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 6374985, -3626584, 1, 2 ) );
    6173                 :          1 :   pTransform.clear();
    6174                 :          1 :   pTransform.setExteriorRing( l22.clone() );
    6175                 :          1 :   pTransform.addInteriorRing( l22.clone() );
    6176                 :          1 :   pTransform.transform( tr, QgsCoordinateTransform::ForwardTransform );
    6177                 :          1 :   extR = static_cast< const QgsLineString * >( pTransform.exteriorRing() );
    6178                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).x(), 175.771, 0.001 );
    6179                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).y(), -39.724, 0.001 );
    6180                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).z(), 1.0, 0.001 );
    6181                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).m(), 2.0, 0.001 );
    6182                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).x(),  174.581448, 0.001 );
    6183                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).y(), -38.7999, 0.001 );
    6184                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).z(), 3.0, 0.001 );
    6185                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).m(), 4.0, 0.001 );
    6186                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).x(),  176.958633, 0.001 );
    6187                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).y(), -38.7999, 0.001 );
    6188                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).z(), 5.0, 0.001 );
    6189                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).m(), 6.0, 0.001 );
    6190                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).x(),  175.771, 0.001 );
    6191                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).y(), -39.724, 0.001 );
    6192                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).z(), 1.0, 0.001 );
    6193                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).m(), 2.0, 0.001 );
    6194                 :          1 :   QGSCOMPARENEAR( pTransform.exteriorRing()->boundingBox().xMinimum(), 174.581448, 0.001 );
    6195                 :          1 :   QGSCOMPARENEAR( pTransform.exteriorRing()->boundingBox().yMinimum(), -39.724, 0.001 );
    6196                 :          1 :   QGSCOMPARENEAR( pTransform.exteriorRing()->boundingBox().xMaximum(), 176.959, 0.001 );
    6197                 :          1 :   QGSCOMPARENEAR( pTransform.exteriorRing()->boundingBox().yMaximum(), -38.7999, 0.001 );
    6198                 :          1 :   intR = static_cast< const QgsLineString * >( pTransform.interiorRing( 0 ) );
    6199                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).x(), 175.771, 0.001 );
    6200                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).y(), -39.724, 0.001 );
    6201                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).z(), 1.0, 0.001 );
    6202                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).m(), 2.0, 0.001 );
    6203                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).x(),  174.581448, 0.001 );
    6204                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).y(), -38.7999, 0.001 );
    6205                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).z(), 3.0, 0.001 );
    6206                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).m(), 4.0, 0.001 );
    6207                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).x(),  176.958633, 0.001 );
    6208                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).y(), -38.7999, 0.001 );
    6209                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).z(), 5.0, 0.001 );
    6210                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).m(), 6.0, 0.001 );
    6211                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).x(),  175.771, 0.001 );
    6212                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).y(), -39.724, 0.001 );
    6213                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).z(), 1.0, 0.001 );
    6214                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).m(), 2.0, 0.001 );
    6215                 :          1 :   QGSCOMPARENEAR( pTransform.interiorRing( 0 )->boundingBox().xMinimum(), 174.581448, 0.001 );
    6216                 :          1 :   QGSCOMPARENEAR( pTransform.interiorRing( 0 )->boundingBox().yMinimum(), -39.724, 0.001 );
    6217                 :          1 :   QGSCOMPARENEAR( pTransform.interiorRing( 0 )->boundingBox().xMaximum(), 176.959, 0.001 );
    6218                 :          1 :   QGSCOMPARENEAR( pTransform.interiorRing( 0 )->boundingBox().yMaximum(), -38.7999, 0.001 );
    6219                 :            : 
    6220                 :            :   //reverse transform
    6221                 :          1 :   pTransform.transform( tr, QgsCoordinateTransform::ReverseTransform );
    6222                 :          1 :   extR = static_cast< const QgsLineString * >( pTransform.exteriorRing() );
    6223                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).x(), 6374984, 100 );
    6224                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).y(), -3626584, 100 );
    6225                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).z(), 1.0, 0.001 );
    6226                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).m(), 2.0, 0.001 );
    6227                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).x(), 6274984, 100 );
    6228                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).y(), -3526584, 100 );
    6229                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).z(), 3.0, 0.001 );
    6230                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).m(), 4.0, 0.001 );
    6231                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).x(),  6474984, 100 );
    6232                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).y(), -3526584, 100 );
    6233                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).z(), 5.0, 0.001 );
    6234                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).m(), 6.0, 0.001 );
    6235                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).x(),  6374984, 100 );
    6236                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).y(), -3626584, 100 );
    6237                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).z(), 1.0, 0.001 );
    6238                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).m(), 2.0, 0.001 );
    6239                 :          1 :   QGSCOMPARENEAR( pTransform.exteriorRing()->boundingBox().xMinimum(), 6274984, 100 );
    6240                 :          1 :   QGSCOMPARENEAR( pTransform.exteriorRing()->boundingBox().yMinimum(), -3626584, 100 );
    6241                 :          1 :   QGSCOMPARENEAR( pTransform.exteriorRing()->boundingBox().xMaximum(), 6474984, 100 );
    6242                 :          1 :   QGSCOMPARENEAR( pTransform.exteriorRing()->boundingBox().yMaximum(), -3526584, 100 );
    6243                 :          1 :   intR = static_cast< const QgsLineString * >( pTransform.interiorRing( 0 ) );
    6244                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).x(), 6374984, 100 );
    6245                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).y(), -3626584, 100 );
    6246                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).z(), 1.0, 0.001 );
    6247                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).m(), 2.0, 0.001 );
    6248                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).x(), 6274984, 100 );
    6249                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).y(), -3526584, 100 );
    6250                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).z(), 3.0, 0.001 );
    6251                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).m(), 4.0, 0.001 );
    6252                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).x(),  6474984, 100 );
    6253                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).y(), -3526584, 100 );
    6254                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).z(), 5.0, 0.001 );
    6255                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).m(), 6.0, 0.001 );
    6256                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).x(),  6374984, 100 );
    6257                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).y(), -3626584, 100 );
    6258                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).z(), 1.0, 0.001 );
    6259                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).m(), 2.0, 0.001 );
    6260                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().xMinimum(), 6274984, 100 );
    6261                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().yMinimum(), -3626584, 100 );
    6262                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().xMaximum(), 6474984, 100 );
    6263                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().yMaximum(), -3526584, 100 );
    6264                 :            : 
    6265                 :            : #if PROJ_VERSION_MAJOR<6 // note - z value transform doesn't currently work with proj 6+, because we don't yet support compound CRS definitions
    6266                 :            :   //z value transform
    6267                 :            :   pTransform.transform( tr, QgsCoordinateTransform::ForwardTransform, true );
    6268                 :            :   extR = static_cast< const QgsLineString * >( pTransform.exteriorRing() );
    6269                 :            :   QGSCOMPARENEAR( extR->pointN( 0 ).z(), -19.249066, 0.001 );
    6270                 :            :   QGSCOMPARENEAR( extR->pointN( 1 ).z(), -19.148357, 0.001 );
    6271                 :            :   QGSCOMPARENEAR( extR->pointN( 2 ).z(), -19.092128, 0.001 );
    6272                 :            :   QGSCOMPARENEAR( extR->pointN( 3 ).z(), -19.249066, 0.001 );
    6273                 :            :   intR = static_cast< const QgsLineString * >( pTransform.interiorRing( 0 ) );
    6274                 :            :   QGSCOMPARENEAR( intR->pointN( 0 ).z(), -19.249066, 0.001 );
    6275                 :            :   QGSCOMPARENEAR( intR->pointN( 1 ).z(), -19.148357, 0.001 );
    6276                 :            :   QGSCOMPARENEAR( intR->pointN( 2 ).z(), -19.092128, 0.001 );
    6277                 :            :   QGSCOMPARENEAR( intR->pointN( 3 ).z(), -19.249066, 0.001 );
    6278                 :            :   pTransform.transform( tr, QgsCoordinateTransform::ReverseTransform, true );
    6279                 :            :   extR = static_cast< const QgsLineString * >( pTransform.exteriorRing() );
    6280                 :            :   QGSCOMPARENEAR( extR->pointN( 0 ).z(), 1, 0.001 );
    6281                 :            :   QGSCOMPARENEAR( extR->pointN( 1 ).z(), 3, 0.001 );
    6282                 :            :   QGSCOMPARENEAR( extR->pointN( 2 ).z(), 5, 0.001 );
    6283                 :            :   QGSCOMPARENEAR( extR->pointN( 3 ).z(), 1, 0.001 );
    6284                 :            :   intR = static_cast< const QgsLineString * >( pTransform.interiorRing( 0 ) );
    6285                 :            :   QGSCOMPARENEAR( intR->pointN( 0 ).z(), 1, 0.001 );
    6286                 :            :   QGSCOMPARENEAR( intR->pointN( 1 ).z(), 3, 0.001 );
    6287                 :            :   QGSCOMPARENEAR( intR->pointN( 2 ).z(), 5, 0.001 );
    6288                 :            :   QGSCOMPARENEAR( intR->pointN( 3 ).z(), 1, 0.001 );
    6289                 :            : #endif
    6290                 :            : 
    6291                 :            :   //QTransform transform
    6292                 :          1 :   QTransform qtr = QTransform::fromScale( 2, 3 );
    6293                 :          1 :   QgsLineString l23;
    6294                 :          2 :   l23.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
    6295                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 )
    6296                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 12, 23, 24 )
    6297                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) );
    6298                 :          1 :   QgsPolygon pTransform2;
    6299                 :          1 :   pTransform2.setExteriorRing( l23.clone() );
    6300                 :          1 :   pTransform2.addInteriorRing( l23.clone() );
    6301                 :          1 :   pTransform2.transform( qtr, 2, 3, 4, 5 );
    6302                 :            : 
    6303                 :          1 :   extR = static_cast< const QgsLineString * >( pTransform2.exteriorRing() );
    6304                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).x(), 2, 100 );
    6305                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).y(), 6, 100 );
    6306                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).z(), 11.0, 0.001 );
    6307                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).m(), 24.0, 0.001 );
    6308                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).x(), 22, 100 );
    6309                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).y(), 36, 100 );
    6310                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).z(), 41.0, 0.001 );
    6311                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).m(), 74.0, 0.001 );
    6312                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).x(),  2, 100 );
    6313                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).y(), 36, 100 );
    6314                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).z(), 71.0, 0.001 );
    6315                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).m(), 124.0, 0.001 );
    6316                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).x(), 2, 100 );
    6317                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).y(), 6, 100 );
    6318                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).z(), 11.0, 0.001 );
    6319                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).m(), 24.0, 0.001 );
    6320                 :          1 :   QGSCOMPARENEAR( pTransform2.exteriorRing()->boundingBox().xMinimum(), 2, 0.001 );
    6321                 :          1 :   QGSCOMPARENEAR( pTransform2.exteriorRing()->boundingBox().yMinimum(), 6, 0.001 );
    6322                 :          1 :   QGSCOMPARENEAR( pTransform2.exteriorRing()->boundingBox().xMaximum(), 22, 0.001 );
    6323                 :          1 :   QGSCOMPARENEAR( pTransform2.exteriorRing()->boundingBox().yMaximum(), 36, 0.001 );
    6324                 :          1 :   intR = static_cast< const QgsLineString * >( pTransform2.interiorRing( 0 ) );
    6325                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).x(), 2, 100 );
    6326                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).y(), 6, 100 );
    6327                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).z(), 11.0, 0.001 );
    6328                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).m(), 24.0, 0.001 );
    6329                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).x(), 22, 100 );
    6330                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).y(), 36, 100 );
    6331                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).z(), 41.0, 0.001 );
    6332                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).m(), 74.0, 0.001 );
    6333                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).x(),  2, 100 );
    6334                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).y(), 36, 100 );
    6335                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).z(), 71.0, 0.001 );
    6336                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).m(), 124.0, 0.001 );
    6337                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).x(), 2, 100 );
    6338                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).y(), 6, 100 );
    6339                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).z(), 11.0, 0.001 );
    6340                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).m(), 24.0, 0.001 );
    6341                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().xMinimum(), 2, 0.001 );
    6342                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().yMinimum(), 6, 0.001 );
    6343                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().xMaximum(), 22, 0.001 );
    6344                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().yMaximum(), 36, 0.001 );
    6345                 :            : 
    6346                 :            :   // closestSegment
    6347                 :          1 :   QgsPoint pt;
    6348                 :          1 :   QgsVertexId v;
    6349                 :          1 :   int leftOf = 0;
    6350                 :          1 :   QgsPolygon empty;
    6351                 :          1 :   ( void )empty.closestSegment( QgsPoint( 1, 2 ), pt, v ); // empty polygon, just want no crash
    6352                 :            : 
    6353                 :          1 :   QgsPolygon p21;
    6354                 :          1 :   QgsLineString p21ls;
    6355                 :          1 :   p21ls.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) << QgsPoint( 7, 12 ) << QgsPoint( 5, 15 ) << QgsPoint( 5, 10 ) );
    6356                 :          1 :   p21.setExteriorRing( p21ls.clone() );
    6357                 :          1 :   QGSCOMPARENEAR( p21.closestSegment( QgsPoint( 4, 11 ), pt, v, &leftOf ), 1.0, 0.0001 );
    6358                 :          1 :   QGSCOMPARENEAR( pt.x(), 5, 0.01 );
    6359                 :          1 :   QGSCOMPARENEAR( pt.y(), 11, 0.01 );
    6360                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 3 ) );
    6361                 :          1 :   QCOMPARE( leftOf, 1 );
    6362                 :          1 :   QGSCOMPARENEAR( p21.closestSegment( QgsPoint( 8, 11 ), pt, v, &leftOf ),  2.0, 0.0001 );
    6363                 :          1 :   QGSCOMPARENEAR( pt.x(), 7, 0.01 );
    6364                 :          1 :   QGSCOMPARENEAR( pt.y(), 12, 0.01 );
    6365                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    6366                 :          1 :   QCOMPARE( leftOf, 1 );
    6367                 :          1 :   QGSCOMPARENEAR( p21.closestSegment( QgsPoint( 6, 11.5 ), pt, v, &leftOf ), 0.125000, 0.0001 );
    6368                 :          1 :   QGSCOMPARENEAR( pt.x(), 6.25, 0.01 );
    6369                 :          1 :   QGSCOMPARENEAR( pt.y(), 11.25, 0.01 );
    6370                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    6371                 :          1 :   QCOMPARE( leftOf, -1 );
    6372                 :          1 :   QGSCOMPARENEAR( p21.closestSegment( QgsPoint( 7, 16 ), pt, v, &leftOf ), 4.923077, 0.0001 );
    6373                 :          1 :   QGSCOMPARENEAR( pt.x(), 5.153846, 0.01 );
    6374                 :          1 :   QGSCOMPARENEAR( pt.y(), 14.769231, 0.01 );
    6375                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    6376                 :          1 :   QCOMPARE( leftOf, 1 );
    6377                 :          1 :   QGSCOMPARENEAR( p21.closestSegment( QgsPoint( 5.5, 13.5 ), pt, v, &leftOf ), 0.173077, 0.0001 );
    6378                 :          1 :   QGSCOMPARENEAR( pt.x(), 5.846154, 0.01 );
    6379                 :          1 :   QGSCOMPARENEAR( pt.y(), 13.730769, 0.01 );
    6380                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    6381                 :          1 :   QCOMPARE( leftOf, -1 );
    6382                 :            :   // point directly on segment
    6383                 :          1 :   QCOMPARE( p21.closestSegment( QgsPoint( 5, 15 ), pt, v, &leftOf ), 0.0 );
    6384                 :          1 :   QCOMPARE( pt, QgsPoint( 5, 15 ) );
    6385                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    6386                 :            :   // with interior ring
    6387                 :          1 :   p21ls.setPoints( QgsPointSequence() << QgsPoint( 6, 11.5 ) << QgsPoint( 6.5, 12 ) << QgsPoint( 6, 13 ) << QgsPoint( 6, 11.5 ) );
    6388                 :          1 :   p21.addInteriorRing( p21ls.clone() );
    6389                 :          1 :   QGSCOMPARENEAR( p21.closestSegment( QgsPoint( 4, 11 ), pt, v, &leftOf ), 1.0, 0.0001 );
    6390                 :          1 :   QGSCOMPARENEAR( pt.x(), 5, 0.01 );
    6391                 :          1 :   QGSCOMPARENEAR( pt.y(), 11, 0.01 );
    6392                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 3 ) );
    6393                 :          1 :   QCOMPARE( leftOf, 1 );
    6394                 :          1 :   QGSCOMPARENEAR( p21.closestSegment( QgsPoint( 8, 11 ), pt, v, &leftOf ),  2.0, 0.0001 );
    6395                 :          1 :   QGSCOMPARENEAR( pt.x(), 7, 0.01 );
    6396                 :          1 :   QGSCOMPARENEAR( pt.y(), 12, 0.01 );
    6397                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    6398                 :          1 :   QCOMPARE( leftOf, 1 );
    6399                 :          1 :   QGSCOMPARENEAR( p21.closestSegment( QgsPoint( 6, 11.4 ), pt, v, &leftOf ), 0.01, 0.0001 );
    6400                 :          1 :   QGSCOMPARENEAR( pt.x(), 6.0, 0.01 );
    6401                 :          1 :   QGSCOMPARENEAR( pt.y(), 11.5, 0.01 );
    6402                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 1, 1 ) );
    6403                 :          1 :   QCOMPARE( leftOf, 1 );
    6404                 :          1 :   QGSCOMPARENEAR( p21.closestSegment( QgsPoint( 7, 16 ), pt, v, &leftOf ), 4.923077, 0.0001 );
    6405                 :          1 :   QGSCOMPARENEAR( pt.x(), 5.153846, 0.01 );
    6406                 :          1 :   QGSCOMPARENEAR( pt.y(), 14.769231, 0.01 );
    6407                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    6408                 :          1 :   QCOMPARE( leftOf, 1 );
    6409                 :          1 :   QGSCOMPARENEAR( p21.closestSegment( QgsPoint( 5.5, 13.5 ), pt, v, &leftOf ), 0.173077, 0.0001 );
    6410                 :          1 :   QGSCOMPARENEAR( pt.x(), 5.846154, 0.01 );
    6411                 :          1 :   QGSCOMPARENEAR( pt.y(), 13.730769, 0.01 );
    6412                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    6413                 :          1 :   QCOMPARE( leftOf, -1 );
    6414                 :            :   // point directly on segment
    6415                 :          1 :   QCOMPARE( p21.closestSegment( QgsPoint( 6, 13 ), pt, v, &leftOf ), 0.0 );
    6416                 :          1 :   QCOMPARE( pt, QgsPoint( 6, 13 ) );
    6417                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 1, 2 ) );
    6418                 :          1 :   QCOMPARE( leftOf, 0 );
    6419                 :            : 
    6420                 :            :   //nextVertex
    6421                 :          1 :   QgsPolygon p22;
    6422                 :          1 :   QVERIFY( !p22.nextVertex( v, pt ) );
    6423                 :          1 :   v = QgsVertexId( 0, 0, -2 );
    6424                 :          1 :   QVERIFY( !p22.nextVertex( v, pt ) );
    6425                 :          1 :   v = QgsVertexId( 0, 0, 10 );
    6426                 :          1 :   QVERIFY( !p22.nextVertex( v, pt ) );
    6427                 :          1 :   QgsLineString lp22;
    6428                 :          1 :   lp22.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 12 ) << QgsPoint( 1, 2 ) );
    6429                 :          1 :   p22.setExteriorRing( lp22.clone() );
    6430                 :          1 :   v = QgsVertexId( 0, 0, 4 ); //out of range
    6431                 :          1 :   QVERIFY( !p22.nextVertex( v, pt ) );
    6432                 :          1 :   v = QgsVertexId( 0, 0, -5 );
    6433                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
    6434                 :          1 :   v = QgsVertexId( 0, 0, -1 );
    6435                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
    6436                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 0 ) );
    6437                 :          1 :   QCOMPARE( pt, QgsPoint( 1, 2 ) );
    6438                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
    6439                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    6440                 :          1 :   QCOMPARE( pt, QgsPoint( 11, 12 ) );
    6441                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
    6442                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    6443                 :          1 :   QCOMPARE( pt, QgsPoint( 1, 12 ) );
    6444                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
    6445                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 3 ) );
    6446                 :          1 :   QCOMPARE( pt, QgsPoint( 1, 2 ) );
    6447                 :          1 :   v = QgsVertexId( 0, 1, 0 );
    6448                 :          1 :   QVERIFY( !p22.nextVertex( v, pt ) );
    6449                 :          1 :   v = QgsVertexId( 1, 0, 0 );
    6450                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
    6451                 :          1 :   QCOMPARE( v, QgsVertexId( 1, 0, 1 ) ); //test that part number is maintained
    6452                 :          1 :   QCOMPARE( pt, QgsPoint( 11, 12 ) );
    6453                 :            :   // add interior ring
    6454                 :          1 :   lp22.setPoints( QgsPointSequence() << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) << QgsPoint( 11, 22 ) << QgsPoint( 11, 12 ) );
    6455                 :          1 :   p22.addInteriorRing( lp22.clone() );
    6456                 :          1 :   v = QgsVertexId( 0, 1, 4 ); //out of range
    6457                 :          1 :   QVERIFY( !p22.nextVertex( v, pt ) );
    6458                 :          1 :   v = QgsVertexId( 0, 1, -5 );
    6459                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
    6460                 :          1 :   v = QgsVertexId( 0, 1, -1 );
    6461                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
    6462                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 1, 0 ) );
    6463                 :          1 :   QCOMPARE( pt, QgsPoint( 11, 12 ) );
    6464                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
    6465                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 1, 1 ) );
    6466                 :          1 :   QCOMPARE( pt, QgsPoint( 21, 22 ) );
    6467                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
    6468                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 1, 2 ) );
    6469                 :          1 :   QCOMPARE( pt, QgsPoint( 11, 22 ) );
    6470                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
    6471                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 1, 3 ) );
    6472                 :          1 :   QCOMPARE( pt, QgsPoint( 11, 12 ) );
    6473                 :          1 :   v = QgsVertexId( 0, 2, 0 );
    6474                 :          1 :   QVERIFY( !p22.nextVertex( v, pt ) );
    6475                 :          1 :   v = QgsVertexId( 1, 1, 0 );
    6476                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
    6477                 :          1 :   QCOMPARE( v, QgsVertexId( 1, 1, 1 ) ); //test that part number is maintained
    6478                 :          1 :   QCOMPARE( pt, QgsPoint( 21, 22 ) );
    6479                 :            : 
    6480                 :            :   // dropZValue
    6481                 :          1 :   QgsPolygon p23;
    6482                 :          1 :   p23.dropZValue();
    6483                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::Polygon );
    6484                 :          1 :   QgsLineString lp23;
    6485                 :          1 :   lp23.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 12 ) << QgsPoint( 1, 2 ) );
    6486                 :          1 :   p23.setExteriorRing( lp23.clone() );
    6487                 :          1 :   p23.addInteriorRing( lp23.clone() );
    6488                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::Polygon );
    6489                 :          1 :   p23.dropZValue(); // not z
    6490                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::Polygon );
    6491                 :          1 :   QCOMPARE( p23.exteriorRing()->wkbType(), QgsWkbTypes::LineString );
    6492                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.exteriorRing() )->pointN( 0 ), QgsPoint( 1, 2 ) );
    6493                 :          1 :   QCOMPARE( p23.interiorRing( 0 )->wkbType(), QgsWkbTypes::LineString );
    6494                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 1, 2 ) );
    6495                 :            :   // with z
    6496                 :          1 :   lp23.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 3 ) << QgsPoint( 11, 12, 13 ) << QgsPoint( 1, 12, 23 ) << QgsPoint( 1, 2, 3 ) );
    6497                 :          1 :   p23.clear();
    6498                 :          1 :   p23.setExteriorRing( lp23.clone() );
    6499                 :          1 :   p23.addInteriorRing( lp23.clone() );
    6500                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::PolygonZ );
    6501                 :          1 :   p23.dropZValue();
    6502                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::Polygon );
    6503                 :          1 :   QCOMPARE( p23.exteriorRing()->wkbType(), QgsWkbTypes::LineString );
    6504                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.exteriorRing() )->pointN( 0 ), QgsPoint( 1, 2 ) );
    6505                 :          1 :   QCOMPARE( p23.interiorRing( 0 )->wkbType(), QgsWkbTypes::LineString );
    6506                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 1, 2 ) );
    6507                 :            :   // with zm
    6508                 :          1 :   lp23.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 3, 4 ) << QgsPoint( 11, 12, 13, 14 ) << QgsPoint( 1, 12, 23, 24 ) << QgsPoint( 1, 2, 3, 4 ) );
    6509                 :          1 :   p23.clear();
    6510                 :          1 :   p23.setExteriorRing( lp23.clone() );
    6511                 :          1 :   p23.addInteriorRing( lp23.clone() );
    6512                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::PolygonZM );
    6513                 :          1 :   p23.dropZValue();
    6514                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::PolygonM );
    6515                 :          1 :   QCOMPARE( p23.exteriorRing()->wkbType(), QgsWkbTypes::LineStringM );
    6516                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.exteriorRing() )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) );
    6517                 :          1 :   QCOMPARE( p23.interiorRing( 0 )->wkbType(), QgsWkbTypes::LineStringM );
    6518                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) );
    6519                 :            : 
    6520                 :            :   // dropMValue
    6521                 :          1 :   p23.clear();
    6522                 :          1 :   p23.dropMValue();
    6523                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::Polygon );
    6524                 :          1 :   lp23.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 12 ) << QgsPoint( 1, 2 ) );
    6525                 :          1 :   p23.setExteriorRing( lp23.clone() );
    6526                 :          1 :   p23.addInteriorRing( lp23.clone() );
    6527                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::Polygon );
    6528                 :          1 :   p23.dropMValue(); // not zm
    6529                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::Polygon );
    6530                 :          1 :   QCOMPARE( p23.exteriorRing()->wkbType(), QgsWkbTypes::LineString );
    6531                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.exteriorRing() )->pointN( 0 ), QgsPoint( 1, 2 ) );
    6532                 :          1 :   QCOMPARE( p23.interiorRing( 0 )->wkbType(), QgsWkbTypes::LineString );
    6533                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 1, 2 ) );
    6534                 :            :   // with m
    6535                 :          1 :   lp23.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM,  1, 2, 0, 3 ) << QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 13 ) << QgsPoint( QgsWkbTypes::PointM, 1, 12, 0, 23 ) << QgsPoint( QgsWkbTypes::PointM,  1, 2, 0, 3 ) );
    6536                 :          1 :   p23.clear();
    6537                 :          1 :   p23.setExteriorRing( lp23.clone() );
    6538                 :          1 :   p23.addInteriorRing( lp23.clone() );
    6539                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::PolygonM );
    6540                 :          1 :   p23.dropMValue();
    6541                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::Polygon );
    6542                 :          1 :   QCOMPARE( p23.exteriorRing()->wkbType(), QgsWkbTypes::LineString );
    6543                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.exteriorRing() )->pointN( 0 ), QgsPoint( 1, 2 ) );
    6544                 :          1 :   QCOMPARE( p23.interiorRing( 0 )->wkbType(), QgsWkbTypes::LineString );
    6545                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 1, 2 ) );
    6546                 :            :   // with zm
    6547                 :          1 :   lp23.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 3, 4 ) << QgsPoint( 11, 12, 13, 14 ) << QgsPoint( 1, 12, 23, 24 ) << QgsPoint( 1, 2, 3, 4 ) );
    6548                 :          1 :   p23.clear();
    6549                 :          1 :   p23.setExteriorRing( lp23.clone() );
    6550                 :          1 :   p23.addInteriorRing( lp23.clone() );
    6551                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::PolygonZM );
    6552                 :          1 :   p23.dropMValue();
    6553                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::PolygonZ );
    6554                 :          1 :   QCOMPARE( p23.exteriorRing()->wkbType(), QgsWkbTypes::LineStringZ );
    6555                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.exteriorRing() )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) );
    6556                 :          1 :   QCOMPARE( p23.interiorRing( 0 )->wkbType(), QgsWkbTypes::LineStringZ );
    6557                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) );
    6558                 :            : 
    6559                 :            :   //vertexAngle
    6560                 :          1 :   QgsPolygon p24;
    6561                 :          1 :   ( void )p24.vertexAngle( QgsVertexId() ); //just want no crash
    6562                 :          1 :   ( void )p24.vertexAngle( QgsVertexId( 0, 0, 0 ) ); //just want no crash
    6563                 :          1 :   ( void )p24.vertexAngle( QgsVertexId( 0, 1, 0 ) ); //just want no crash
    6564                 :          1 :   QgsLineString l38;
    6565                 :          2 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0.5, 0 ) << QgsPoint( 1, 0 )
    6566                 :          1 :                  << QgsPoint( 2, 1 ) << QgsPoint( 1, 2 ) << QgsPoint( 0, 2 ) << QgsPoint( 0, 0 ) );
    6567                 :          1 :   p24.setExteriorRing( l38.clone() );
    6568                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 2.35619, 0.00001 );
    6569                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 1.5708, 0.0001 );
    6570                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 0, 2 ) ), 1.17809, 0.00001 );
    6571                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 0, 3 ) ), 0.0, 0.00001 );
    6572                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 0, 4 ) ), 5.10509, 0.00001 );
    6573                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 0, 5 ) ), 3.92699, 0.00001 );
    6574                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 0, 6 ) ), 2.35619, 0.00001 );
    6575                 :          1 :   p24.addInteriorRing( l38.clone() );
    6576                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 1, 0 ) ), 2.35619, 0.00001 );
    6577                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 1, 1 ) ), 1.5708, 0.0001 );
    6578                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 1, 2 ) ), 1.17809, 0.00001 );
    6579                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 1, 3 ) ), 0.0, 0.00001 );
    6580                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 1, 4 ) ), 5.10509, 0.00001 );
    6581                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 1, 5 ) ), 3.92699, 0.00001 );
    6582                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 1, 6 ) ), 2.35619, 0.00001 );
    6583                 :            : 
    6584                 :            :   //insert vertex
    6585                 :            : 
    6586                 :            :   //insert vertex in empty polygon
    6587                 :          1 :   QgsPolygon p25;
    6588                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    6589                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 6.0, 7.0 ) ) );
    6590                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 1, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    6591                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 1, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    6592                 :          1 :   QVERIFY( p25.isEmpty() );
    6593                 :          2 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0.5, 0 ) << QgsPoint( 1, 0 )
    6594                 :          1 :                  << QgsPoint( 2, 1 ) << QgsPoint( 1, 2 ) << QgsPoint( 0, 2 ) << QgsPoint( 0, 0 ) );
    6595                 :          1 :   p25.setExteriorRing( l38.clone() );
    6596                 :          1 :   QVERIFY( p25.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 0.3, 0 ) ) );
    6597                 :          1 :   QCOMPARE( p25.nCoordinates(), 8 );
    6598                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 0 ), QgsPoint( 0, 0 ) );
    6599                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 1 ), QgsPoint( 0.3, 0 ) );
    6600                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 2 ), QgsPoint( 0.5, 0 ) );
    6601                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 0, -1 ), QgsPoint( 6.0, 7.0 ) ) );
    6602                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 0, 100 ), QgsPoint( 6.0, 7.0 ) ) );
    6603                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 1, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    6604                 :            :   // first vertex
    6605                 :          1 :   QVERIFY( p25.insertVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 0, 0.1 ) ) );
    6606                 :          1 :   QCOMPARE( p25.nCoordinates(), 9 );
    6607                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 0 ), QgsPoint( 0, 0.1 ) );
    6608                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 1 ), QgsPoint( 0, 0 ) );
    6609                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 2 ), QgsPoint( 0.3, 0 ) );
    6610                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 3 ), QgsPoint( 0.5, 0 ) );
    6611                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 7 ), QgsPoint( 0, 2 ) );
    6612                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 8 ), QgsPoint( 0, 0.1 ) );
    6613                 :            :   // last vertex
    6614                 :          1 :   QVERIFY( p25.insertVertex( QgsVertexId( 0, 0, 9 ), QgsPoint( 0.1, 0.1 ) ) );
    6615                 :          1 :   QCOMPARE( p25.nCoordinates(), 10 );
    6616                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 0 ), QgsPoint( 0.1, 0.1 ) );
    6617                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 1 ), QgsPoint( 0, 0 ) );
    6618                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 2 ), QgsPoint( 0.3, 0 ) );
    6619                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 3 ), QgsPoint( 0.5, 0 ) );
    6620                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 8 ), QgsPoint( 0, 0.1 ) );
    6621                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 9 ), QgsPoint( 0.1, 0.1 ) );
    6622                 :            :   // with interior ring
    6623                 :          1 :   p25.addInteriorRing( l38.clone() );
    6624                 :          1 :   QCOMPARE( p25.nCoordinates(), 17 );
    6625                 :          1 :   QVERIFY( p25.insertVertex( QgsVertexId( 0, 1, 1 ), QgsPoint( 0.3, 0 ) ) );
    6626                 :          1 :   QCOMPARE( p25.nCoordinates(), 18 );
    6627                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 0, 0 ) );
    6628                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 1 ), QgsPoint( 0.3, 0 ) );
    6629                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 2 ), QgsPoint( 0.5, 0 ) );
    6630                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 1, -1 ), QgsPoint( 6.0, 7.0 ) ) );
    6631                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 1, 100 ), QgsPoint( 6.0, 7.0 ) ) );
    6632                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 2, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    6633                 :            :   // first vertex in interior ring
    6634                 :          1 :   QVERIFY( p25.insertVertex( QgsVertexId( 0, 1, 0 ), QgsPoint( 0, 0.1 ) ) );
    6635                 :          1 :   QCOMPARE( p25.nCoordinates(), 19 );
    6636                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 0, 0.1 ) );
    6637                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 1 ), QgsPoint( 0, 0 ) );
    6638                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 2 ), QgsPoint( 0.3, 0 ) );
    6639                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 3 ), QgsPoint( 0.5, 0 ) );
    6640                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 7 ), QgsPoint( 0, 2 ) );
    6641                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 8 ), QgsPoint( 0, 0.1 ) );
    6642                 :            :   // last vertex in interior ring
    6643                 :          1 :   QVERIFY( p25.insertVertex( QgsVertexId( 0, 1, 9 ), QgsPoint( 0.1, 0.1 ) ) );
    6644                 :          1 :   QCOMPARE( p25.nCoordinates(), 20 );
    6645                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 0.1, 0.1 ) );
    6646                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 1 ), QgsPoint( 0, 0 ) );
    6647                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 2 ), QgsPoint( 0.3, 0 ) );
    6648                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 3 ), QgsPoint( 0.5, 0 ) );
    6649                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 8 ), QgsPoint( 0, 0.1 ) );
    6650                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 9 ), QgsPoint( 0.1, 0.1 ) );
    6651                 :            : 
    6652                 :            :   //move vertex
    6653                 :            : 
    6654                 :            :   //empty polygon
    6655                 :          1 :   QgsPolygon p26;
    6656                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    6657                 :          1 :   QVERIFY( p26.isEmpty() );
    6658                 :            : 
    6659                 :            :   //valid polygon
    6660                 :          2 :   l38.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
    6661                 :          1 :                  << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) << QgsPoint( 1, 2 ) );
    6662                 :          1 :   p26.setExteriorRing( l38.clone() );
    6663                 :          1 :   QVERIFY( p26.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    6664                 :          1 :   QVERIFY( p26.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 16.0, 17.0 ) ) );
    6665                 :          1 :   QVERIFY( p26.moveVertex( QgsVertexId( 0, 0, 2 ), QgsPoint( 26.0, 27.0 ) ) );
    6666                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.exteriorRing() )->pointN( 0 ), QgsPoint( 6.0, 7.0 ) );
    6667                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.exteriorRing() )->pointN( 1 ), QgsPoint( 16.0, 17.0 ) );
    6668                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.exteriorRing() )->pointN( 2 ), QgsPoint( 26.0, 27.0 ) );
    6669                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.exteriorRing() )->pointN( 3 ), QgsPoint( 6.0, 7.0 ) );
    6670                 :            : 
    6671                 :            :   //out of range
    6672                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 0, 0, -1 ), QgsPoint( 3.0, 4.0 ) ) );
    6673                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 0, 0, 10 ), QgsPoint( 3.0, 4.0 ) ) );
    6674                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 0, 1, 0 ), QgsPoint( 3.0, 4.0 ) ) );
    6675                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.exteriorRing() )->pointN( 0 ), QgsPoint( 6.0, 7.0 ) );
    6676                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.exteriorRing() )->pointN( 1 ), QgsPoint( 16.0, 17.0 ) );
    6677                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.exteriorRing() )->pointN( 2 ), QgsPoint( 26.0, 27.0 ) );
    6678                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.exteriorRing() )->pointN( 3 ), QgsPoint( 6.0, 7.0 ) );
    6679                 :            : 
    6680                 :            :   // with interior ring
    6681                 :          1 :   p26.addInteriorRing( l38.clone() );
    6682                 :          1 :   QVERIFY( p26.moveVertex( QgsVertexId( 0, 1, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    6683                 :          1 :   QVERIFY( p26.moveVertex( QgsVertexId( 0, 1, 1 ), QgsPoint( 16.0, 17.0 ) ) );
    6684                 :          1 :   QVERIFY( p26.moveVertex( QgsVertexId( 0, 1, 2 ), QgsPoint( 26.0, 27.0 ) ) );
    6685                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 6.0, 7.0 ) );
    6686                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.interiorRing( 0 ) )->pointN( 1 ), QgsPoint( 16.0, 17.0 ) );
    6687                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.interiorRing( 0 ) )->pointN( 2 ), QgsPoint( 26.0, 27.0 ) );
    6688                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.interiorRing( 0 ) )->pointN( 3 ), QgsPoint( 6.0, 7.0 ) );
    6689                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 0, 1, -1 ), QgsPoint( 3.0, 4.0 ) ) );
    6690                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 0, 1, 10 ), QgsPoint( 3.0, 4.0 ) ) );
    6691                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 0, 2, 0 ), QgsPoint( 3.0, 4.0 ) ) );
    6692                 :            : 
    6693                 :            :   //delete vertex
    6694                 :            : 
    6695                 :            :   //empty polygon
    6696                 :          1 :   QgsPolygon p27;
    6697                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
    6698                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 0, 1, 0 ) ) );
    6699                 :          1 :   QVERIFY( p27.isEmpty() );
    6700                 :            : 
    6701                 :            :   //valid polygon
    6702                 :          2 :   l38.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 5, 2 ) << QgsPoint( 6, 2 ) << QgsPoint( 7, 2 )
    6703                 :          1 :                  << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) << QgsPoint( 1, 2 ) );
    6704                 :            : 
    6705                 :          1 :   p27.setExteriorRing( l38.clone() );
    6706                 :            :   //out of range vertices
    6707                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 0, 0, -1 ) ) );
    6708                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 0, 0, 100 ) ) );
    6709                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 0, 1, 1 ) ) );
    6710                 :            : 
    6711                 :            :   //valid vertices
    6712                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 1 ) ) );
    6713                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 0 ), QgsPoint( 1.0, 2.0 ) );
    6714                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 1 ), QgsPoint( 6.0, 2.0 ) );
    6715                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 2 ), QgsPoint( 7.0, 2.0 ) );
    6716                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 3 ), QgsPoint( 11.0, 12.0 ) );
    6717                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 5 ), QgsPoint( 1.0, 2.0 ) );
    6718                 :            : 
    6719                 :            :   // delete first vertex
    6720                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
    6721                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 0 ), QgsPoint( 6.0, 2.0 ) );
    6722                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 1 ), QgsPoint( 7.0, 2.0 ) );
    6723                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 2 ), QgsPoint( 11.0, 12.0 ) );
    6724                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 3 ), QgsPoint( 21.0, 22.0 ) );
    6725                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 4 ), QgsPoint( 6.0, 2.0 ) );
    6726                 :            : 
    6727                 :            :   // delete last vertex
    6728                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 4 ) ) );
    6729                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 0 ), QgsPoint( 21.0, 22.0 ) );
    6730                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 1 ), QgsPoint( 7.0, 2.0 ) );
    6731                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 2 ), QgsPoint( 11.0, 12.0 ) );
    6732                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 3 ), QgsPoint( 21.0, 22.0 ) );
    6733                 :            : 
    6734                 :            :   // delete another vertex - should remove ring
    6735                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 1 ) ) );
    6736                 :          1 :   QVERIFY( !p27.exteriorRing() );
    6737                 :            : 
    6738                 :            :   // with interior ring
    6739                 :          1 :   p27.setExteriorRing( l38.clone() );
    6740                 :          1 :   p27.addInteriorRing( l38.clone() );
    6741                 :            : 
    6742                 :            :   //out of range vertices
    6743                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 0, 1, -1 ) ) );
    6744                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 0, 1, 100 ) ) );
    6745                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 0, 2, 1 ) ) );
    6746                 :            : 
    6747                 :            :   //valid vertices
    6748                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 1, 1 ) ) );
    6749                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 1.0, 2.0 ) );
    6750                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 1 ), QgsPoint( 6.0, 2.0 ) );
    6751                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 2 ), QgsPoint( 7.0, 2.0 ) );
    6752                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 3 ), QgsPoint( 11.0, 12.0 ) );
    6753                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 5 ), QgsPoint( 1.0, 2.0 ) );
    6754                 :            : 
    6755                 :            :   // delete first vertex
    6756                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 1, 0 ) ) );
    6757                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 6.0, 2.0 ) );
    6758                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 1 ), QgsPoint( 7.0, 2.0 ) );
    6759                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 2 ), QgsPoint( 11.0, 12.0 ) );
    6760                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 3 ), QgsPoint( 21.0, 22.0 ) );
    6761                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 4 ), QgsPoint( 6.0, 2.0 ) );
    6762                 :            : 
    6763                 :            :   // delete last vertex
    6764                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 1, 4 ) ) );
    6765                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 21.0, 22.0 ) );
    6766                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 1 ), QgsPoint( 7.0, 2.0 ) );
    6767                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 2 ), QgsPoint( 11.0, 12.0 ) );
    6768                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 3 ), QgsPoint( 21.0, 22.0 ) );
    6769                 :            : 
    6770                 :            :   // delete another vertex - should remove ring
    6771                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 1, 1 ) ) );
    6772                 :          1 :   QCOMPARE( p27.numInteriorRings(), 0 );
    6773                 :          1 :   QVERIFY( p27.exteriorRing() );
    6774                 :            : 
    6775                 :            :   // test that interior ring is "promoted" when exterior is removed
    6776                 :          1 :   p27.addInteriorRing( l38.clone() );
    6777                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
    6778                 :          1 :   QCOMPARE( p27.numInteriorRings(), 1 );
    6779                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
    6780                 :          1 :   QCOMPARE( p27.numInteriorRings(), 1 );
    6781                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
    6782                 :          1 :   QCOMPARE( p27.numInteriorRings(), 1 );
    6783                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
    6784                 :          1 :   QCOMPARE( p27.numInteriorRings(), 0 );
    6785                 :          1 :   QVERIFY( p27.exteriorRing() );
    6786                 :            : 
    6787                 :            :   // test adjacent vertices - should wrap around!
    6788                 :          1 :   QgsLineString *closedRing1 = new QgsLineString();
    6789                 :          1 :   closedRing1->setPoints( QgsPointSequence() << QgsPoint( 1, 1 ) << QgsPoint( 1, 2 ) << QgsPoint( 2, 2 ) << QgsPoint( 2, 1 ) << QgsPoint( 1, 1 ) );
    6790                 :          1 :   QgsPolygon p28;
    6791                 :          1 :   QgsVertexId previous( 1, 2, 3 );
    6792                 :          1 :   QgsVertexId next( 4, 5, 6 );
    6793                 :          1 :   p28.adjacentVertices( QgsVertexId( 0, 0, 0 ), previous, next );
    6794                 :          1 :   QCOMPARE( previous, QgsVertexId( ) );
    6795                 :          1 :   QCOMPARE( next, QgsVertexId( ) );
    6796                 :          1 :   p28.adjacentVertices( QgsVertexId( 0, 1, 0 ), previous, next );
    6797                 :          1 :   QCOMPARE( previous, QgsVertexId( ) );
    6798                 :          1 :   QCOMPARE( next, QgsVertexId( ) );
    6799                 :          1 :   p28.adjacentVertices( QgsVertexId( 0, 0, 1 ), previous, next );
    6800                 :          1 :   QCOMPARE( previous, QgsVertexId( ) );
    6801                 :          1 :   QCOMPARE( next, QgsVertexId( ) );
    6802                 :            : 
    6803                 :          1 :   p28.setExteriorRing( closedRing1 );
    6804                 :          1 :   p28.adjacentVertices( QgsVertexId( 0, 0, 0 ), previous, next );
    6805                 :          1 :   QCOMPARE( previous, QgsVertexId( 0, 0, 3 ) );
    6806                 :          1 :   QCOMPARE( next, QgsVertexId( 0, 0, 1 ) );
    6807                 :          1 :   p28.adjacentVertices( QgsVertexId( 0, 0, 1 ), previous, next );
    6808                 :          1 :   QCOMPARE( previous, QgsVertexId( 0, 0, 0 ) );
    6809                 :          1 :   QCOMPARE( next, QgsVertexId( 0, 0, 2 ) );
    6810                 :          1 :   p28.adjacentVertices( QgsVertexId( 0, 0, 2 ), previous, next );
    6811                 :          1 :   QCOMPARE( previous, QgsVertexId( 0, 0, 1 ) );
    6812                 :          1 :   QCOMPARE( next, QgsVertexId( 0, 0, 3 ) );
    6813                 :          1 :   p28.adjacentVertices( QgsVertexId( 0, 0, 3 ), previous, next );
    6814                 :          1 :   QCOMPARE( previous, QgsVertexId( 0, 0, 2 ) );
    6815                 :          1 :   QCOMPARE( next, QgsVertexId( 0, 0, 4 ) );
    6816                 :          1 :   p28.adjacentVertices( QgsVertexId( 0, 0, 4 ), previous, next );
    6817                 :          1 :   QCOMPARE( previous, QgsVertexId( 0, 0, 3 ) );
    6818                 :          1 :   QCOMPARE( next, QgsVertexId( 0, 0, 1 ) );
    6819                 :          1 :   p28.adjacentVertices( QgsVertexId( 0, 1, 0 ), previous, next );
    6820                 :          1 :   QCOMPARE( previous, QgsVertexId( ) );
    6821                 :          1 :   QCOMPARE( next, QgsVertexId( ) );
    6822                 :            :   // part number should be retained
    6823                 :          1 :   p28.adjacentVertices( QgsVertexId( 1, 0, 0 ), previous, next );
    6824                 :          1 :   QCOMPARE( previous, QgsVertexId( 1, 0, 3 ) );
    6825                 :          1 :   QCOMPARE( next, QgsVertexId( 1, 0, 1 ) );
    6826                 :            : 
    6827                 :            :   // interior ring
    6828                 :          1 :   p28.addInteriorRing( closedRing1->clone() );
    6829                 :          1 :   p28.adjacentVertices( QgsVertexId( 0, 1, 0 ), previous, next );
    6830                 :          1 :   QCOMPARE( previous, QgsVertexId( 0, 1, 3 ) );
    6831                 :          1 :   QCOMPARE( next, QgsVertexId( 0, 1, 1 ) );
    6832                 :          1 :   p28.adjacentVertices( QgsVertexId( 0, 1, 1 ), previous, next );
    6833                 :          1 :   QCOMPARE( previous, QgsVertexId( 0, 1, 0 ) );
    6834                 :          1 :   QCOMPARE( next, QgsVertexId( 0, 1, 2 ) );
    6835                 :          1 :   p28.adjacentVertices( QgsVertexId( 0, 1, 2 ), previous, next );
    6836                 :          1 :   QCOMPARE( previous, QgsVertexId( 0, 1, 1 ) );
    6837                 :          1 :   QCOMPARE( next, QgsVertexId( 0, 1, 3 ) );
    6838                 :          1 :   p28.adjacentVertices( QgsVertexId( 0, 1, 3 ), previous, next );
    6839                 :          1 :   QCOMPARE( previous, QgsVertexId( 0, 1, 2 ) );
    6840                 :          1 :   QCOMPARE( next, QgsVertexId( 0, 1, 4 ) );
    6841                 :          1 :   p28.adjacentVertices( QgsVertexId( 0, 1, 4 ), previous, next );
    6842                 :          1 :   QCOMPARE( previous, QgsVertexId( 0, 1, 3 ) );
    6843                 :          1 :   QCOMPARE( next, QgsVertexId( 0, 1, 1 ) );
    6844                 :          1 :   p28.adjacentVertices( QgsVertexId( 0, 2, 0 ), previous, next );
    6845                 :          1 :   QCOMPARE( previous, QgsVertexId( ) );
    6846                 :          1 :   QCOMPARE( next, QgsVertexId( ) );
    6847                 :            : 
    6848                 :            :   // vertex number
    6849                 :          1 :   QgsLineString vertexLine2;
    6850                 :          1 :   QCOMPARE( vertexLine2.vertexNumberFromVertexId( QgsVertexId( -1, 0, 0 ) ), -1 );
    6851                 :            : 
    6852                 :          1 :   QgsLineString *closedRing2 = new QgsLineString();
    6853                 :          1 :   closedRing2->setPoints( QgsPointSequence() << QgsPoint( 1, 1 ) << QgsPoint( 1, 2 ) << QgsPoint( 2, 2 ) << QgsPoint( 2, 1 ) << QgsPoint( 1, 1 ) );
    6854                 :          1 :   QgsPolygon p29;
    6855                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( -1, 0, 0 ) ), -1 );
    6856                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 1, 0, 0 ) ), -1 );
    6857                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, -1, 0 ) ), -1 );
    6858                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 1, 0 ) ), -1 );
    6859                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 0, -1 ) ), -1 );
    6860                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 0, 0 ) ), -1 );
    6861                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 0, 1 ) ), -1 );
    6862                 :          1 :   p29.setExteriorRing( closedRing2 );
    6863                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( -1, 0, 0 ) ), -1 );
    6864                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 1, 0, 0 ) ), -1 );
    6865                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, -1, 0 ) ), -1 );
    6866                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 1, 0 ) ), -1 );
    6867                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 0, -1 ) ), -1 );
    6868                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 0, 0 ) ), 0 );
    6869                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 0, 1 ) ), 1 );
    6870                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 0, 2 ) ), 2 );
    6871                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 0, 3 ) ), 3 );
    6872                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 0, 4 ) ), 4 );
    6873                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 0, 5 ) ), -1 );
    6874                 :          1 :   p29.addInteriorRing( closedRing2->clone() );
    6875                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 0, 0 ) ), 0 );
    6876                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 0, 1 ) ), 1 );
    6877                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 0, 2 ) ), 2 );
    6878                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 0, 3 ) ), 3 );
    6879                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 0, 4 ) ), 4 );
    6880                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 0, 5 ) ), -1 );
    6881                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 1, 0 ) ), 5 );
    6882                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 1, 1 ) ), 6 );
    6883                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 1, 2 ) ), 7 );
    6884                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 1, 3 ) ), 8 );
    6885                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 1, 4 ) ), 9 );
    6886                 :          1 :   QCOMPARE( p29.vertexNumberFromVertexId( QgsVertexId( 0, 1, 5 ) ), -1 );
    6887                 :            : 
    6888                 :            : 
    6889                 :            :   //segmentLength
    6890                 :          1 :   QgsPolygon p30;
    6891                 :          1 :   QgsLineString vertexLine3;
    6892                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( -1, 0, 0 ) ), 0.0 );
    6893                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 0, 0 ) ), 0.0 );
    6894                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 1, 0, 0 ) ), 0.0 );
    6895                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, -1, 0 ) ), 0.0 );
    6896                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 1, 0 ) ), 0.0 );
    6897                 :          2 :   vertexLine3.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 111, 12 )
    6898                 :          1 :                          << QgsPoint( 111, 2 ) << QgsPoint( 11, 2 ) );
    6899                 :          1 :   p30.setExteriorRing( vertexLine3.clone() );
    6900                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId() ), 0.0 );
    6901                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 0, -1 ) ), 0.0 );
    6902                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 0, 0 ) ), 10.0 );
    6903                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 0, 1 ) ), 100.0 );
    6904                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 0, 2 ) ), 10.0 );
    6905                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 0, 3 ) ), 100.0 );
    6906                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 0, 4 ) ), 0.0 );
    6907                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( -1, 0, -1 ) ), 0.0 );
    6908                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( -1, 0, 0 ) ), 10.0 );
    6909                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, -1, 0 ) ), 0.0 );
    6910                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 1, 0 ) ), 0.0 );
    6911                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 1, 1 ) ), 0.0 );
    6912                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 1, 0, 1 ) ), 100.0 );
    6913                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 1, 1, 1 ) ), 0.0 );
    6914                 :            : 
    6915                 :            :   // add interior ring
    6916                 :          2 :   vertexLine3.setPoints( QgsPointSequence() << QgsPoint( 30, 6 ) << QgsPoint( 34, 6 ) << QgsPoint( 34, 8 )
    6917                 :          1 :                          << QgsPoint( 30, 8 ) << QgsPoint( 30, 6 ) );
    6918                 :          1 :   p30.addInteriorRing( vertexLine3.clone() );
    6919                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId() ), 0.0 );
    6920                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 0, -1 ) ), 0.0 );
    6921                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 0, 0 ) ), 10.0 );
    6922                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 0, 1 ) ), 100.0 );
    6923                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 0, 2 ) ), 10.0 );
    6924                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 0, 3 ) ), 100.0 );
    6925                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 0, 4 ) ), 0.0 );
    6926                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( -1, 0, -1 ) ), 0.0 );
    6927                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( -1, 0, 0 ) ), 10.0 );
    6928                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, -1, 0 ) ), 0.0 );
    6929                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 1, -1 ) ), 0.0 );
    6930                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 1, 0 ) ), 4.0 );
    6931                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 1, 1 ) ), 2.0 );
    6932                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 1, 2 ) ), 4.0 );
    6933                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 1, 3 ) ), 2.0 );
    6934                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 0, 1, 4 ) ), 0.0 );
    6935                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 1, 0, 1 ) ), 100.0 );
    6936                 :          1 :   QCOMPARE( p30.segmentLength( QgsVertexId( 1, 1, 1 ) ), 2.0 );
    6937                 :            : 
    6938                 :            :   //removeDuplicateNodes
    6939                 :          1 :   QgsPolygon nodePolygon;
    6940                 :          1 :   QgsLineString nodeLine;
    6941                 :          1 :   QVERIFY( !nodePolygon.removeDuplicateNodes() );
    6942                 :          1 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 11, 22 ) << QgsPoint( 11, 2 ) );
    6943                 :          1 :   nodePolygon.setExteriorRing( nodeLine.clone() );
    6944                 :          1 :   QVERIFY( !nodePolygon.removeDuplicateNodes() );
    6945                 :          2 :   QCOMPARE( nodePolygon.asWkt(), QStringLiteral( "Polygon ((11 2, 11 12, 11 22, 11 2))" ) );
    6946                 :          2 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11.01, 1.99 ) << QgsPoint( 11.02, 2.01 )
    6947                 :          1 :                       << QgsPoint( 11, 12 ) << QgsPoint( 11, 22 ) << QgsPoint( 11.01, 21.99 ) << QgsPoint( 10.99, 1.99 ) << QgsPoint( 11, 2 ) );
    6948                 :          1 :   nodePolygon.setExteriorRing( nodeLine.clone() );
    6949                 :          1 :   QVERIFY( nodePolygon.removeDuplicateNodes( 0.02 ) );
    6950                 :          1 :   QVERIFY( !nodePolygon.removeDuplicateNodes( 0.02 ) );
    6951                 :          2 :   QCOMPARE( nodePolygon.asWkt( 2 ), QStringLiteral( "Polygon ((11 2, 11 12, 11 22, 11 2))" ) );
    6952                 :          2 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11.01, 1.99 ) << QgsPoint( 11.02, 2.01 )
    6953                 :          1 :                       << QgsPoint( 11, 12 ) << QgsPoint( 11, 22 ) << QgsPoint( 11.01, 21.99 ) << QgsPoint( 10.99, 1.99 ) << QgsPoint( 11, 2 ) );
    6954                 :          1 :   nodePolygon.setExteriorRing( nodeLine.clone() );
    6955                 :          1 :   QVERIFY( !nodePolygon.removeDuplicateNodes() );
    6956                 :          2 :   QCOMPARE( nodePolygon.asWkt( 2 ), QStringLiteral( "Polygon ((11 2, 11.01 1.99, 11.02 2.01, 11 12, 11 22, 11.01 21.99, 10.99 1.99, 11 2))" ) );
    6957                 :            :   // don't create degenerate rings
    6958                 :          1 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11.01, 2.01 ) << QgsPoint( 11, 2.01 ) << QgsPoint( 11, 2 ) );
    6959                 :          1 :   nodePolygon.addInteriorRing( nodeLine.clone() );
    6960                 :          1 :   QVERIFY( nodePolygon.removeDuplicateNodes( 0.02 ) );
    6961                 :          2 :   QCOMPARE( nodePolygon.asWkt( 2 ), QStringLiteral( "Polygon ((11 2, 11 12, 11 22, 11 2),(11 2, 11.01 2.01, 11 2.01, 11 2))" ) );
    6962                 :            : 
    6963                 :            :   // swap XY
    6964                 :          1 :   QgsPolygon swapPolygon;
    6965                 :          1 :   swapPolygon.swapXy(); //no crash
    6966                 :          1 :   QgsLineString swapLine;
    6967                 :          1 :   swapLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 11, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 11, 22, 23, 24, QgsWkbTypes::PointZM ) << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) );
    6968                 :          1 :   swapPolygon.setExteriorRing( swapLine.clone() );
    6969                 :          1 :   swapPolygon.swapXy();
    6970                 :          2 :   QCOMPARE( swapPolygon.asWkt(), QStringLiteral( "PolygonZM ((2 11 3 4, 12 11 13 14, 22 11 23 24, 2 11 3 4))" ) );
    6971                 :          1 :   swapLine.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 5, 6, QgsWkbTypes::PointZM ) << QgsPoint( 11.01, 2.01, 15, 16, QgsWkbTypes::PointZM ) << QgsPoint( 11, 2.01, 25, 26, QgsWkbTypes::PointZM ) << QgsPoint( 11, 2, 5, 6, QgsWkbTypes::PointZM ) );
    6972                 :          1 :   swapPolygon.addInteriorRing( swapLine.clone() );
    6973                 :          1 :   swapPolygon.swapXy();
    6974                 :          2 :   QCOMPARE( swapPolygon.asWkt( 2 ), QStringLiteral( "PolygonZM ((11 2 3 4, 11 12 13 14, 11 22 23 24, 11 2 3 4),(2 1 5 6, 2.01 11.01 15 16, 2.01 11 25 26, 2 11 5 6, 2 1 5 6))" ) );
    6975                 :            : 
    6976                 :            :   // filter vertex
    6977                 :          1 :   QgsPolygon filterPolygon;
    6978                 :         19 :   auto filter = []( const QgsPoint & point )-> bool
    6979                 :            :   {
    6980                 :         19 :     return point.x() > 5;
    6981                 :            :   };
    6982                 :          1 :   filterPolygon.filterVertices( filter ); // no crash
    6983                 :          1 :   QgsLineString filterPolygonRing;
    6984                 :          1 :   filterPolygonRing.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 4, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 11, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 11, 22, 23, 24, QgsWkbTypes::PointZM ) << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) );
    6985                 :          1 :   filterPolygon.setExteriorRing( filterPolygonRing.clone() );
    6986                 :          1 :   filterPolygon.filterVertices( filter );
    6987                 :          2 :   QCOMPARE( filterPolygon.asWkt(), QStringLiteral( "PolygonZM ((11 2 3 4, 11 12 13 14, 11 22 23 24, 11 2 3 4))" ) );
    6988                 :          1 :   filterPolygonRing.setPoints( QgsPointSequence() << QgsPoint( 10, 2, 5, 6, QgsWkbTypes::PointZM ) << QgsPoint( 4, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 11.01, 2.01, 15, 16, QgsWkbTypes::PointZM ) << QgsPoint( 11, 2.01, 25, 26, QgsWkbTypes::PointZM ) << QgsPoint( 11, 2, 5, 6, QgsWkbTypes::PointZM ) << QgsPoint( 10, 2, 5, 6, QgsWkbTypes::PointZM ) );
    6989                 :          1 :   filterPolygon.addInteriorRing( filterPolygonRing.clone() );
    6990                 :          1 :   filterPolygonRing.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 5, 6, QgsWkbTypes::PointZM ) << QgsPoint( 11.01, 2.01, 15, 16, QgsWkbTypes::PointZM ) << QgsPoint( 11, 2.01, 25, 26, QgsWkbTypes::PointZM ) << QgsPoint( 1, 2, 5, 6, QgsWkbTypes::PointZM ) );
    6991                 :          1 :   filterPolygon.addInteriorRing( filterPolygonRing.clone() );
    6992                 :          1 :   filterPolygon.filterVertices( filter );
    6993                 :          2 :   QCOMPARE( filterPolygon.asWkt( 2 ), QStringLiteral( "PolygonZM ((11 2 3 4, 11 12 13 14, 11 22 23 24, 11 2 3 4),(10 2 5 6, 11.01 2.01 15 16, 11 2.01 25 26, 11 2 5 6, 10 2 5 6),(11.01 2.01 15 16, 11 2.01 25 26))" ) );
    6994                 :            : 
    6995                 :            :   // transform vertex
    6996                 :          1 :   QgsPolygon transformPolygon;
    6997                 :         20 :   auto transform = []( const QgsPoint & point )-> QgsPoint
    6998                 :            :   {
    6999                 :         20 :     return QgsPoint( point.x() + 2, point.y() + 3, point.z() + 4, point.m() + 5 );
    7000                 :            :   };
    7001                 :          1 :   transformPolygon.transformVertices( transform ); // no crash
    7002                 :          1 :   QgsLineString transformPolygonRing;
    7003                 :          1 :   transformPolygonRing.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 4, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 11, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 11, 22, 23, 24, QgsWkbTypes::PointZM ) << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) );
    7004                 :          1 :   transformPolygon.setExteriorRing( transformPolygonRing.clone() );
    7005                 :          1 :   transformPolygon.transformVertices( transform );
    7006                 :          2 :   QCOMPARE( transformPolygon.asWkt(), QStringLiteral( "PolygonZM ((13 5 7 9, 6 15 17 19, 13 15 17 19, 13 25 27 29, 13 5 7 9))" ) );
    7007                 :          1 :   transformPolygonRing.setPoints( QgsPointSequence() << QgsPoint( 10, 2, 5, 6, QgsWkbTypes::PointZM ) << QgsPoint( 4, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 11.01, 2.01, 15, 16, QgsWkbTypes::PointZM ) << QgsPoint( 11, 2.01, 25, 26, QgsWkbTypes::PointZM ) << QgsPoint( 11, 2, 5, 6, QgsWkbTypes::PointZM ) << QgsPoint( 10, 2, 5, 6, QgsWkbTypes::PointZM ) );
    7008                 :          1 :   transformPolygon.addInteriorRing( transformPolygonRing.clone() );
    7009                 :          1 :   transformPolygonRing.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 5, 6, QgsWkbTypes::PointZM ) << QgsPoint( 11.01, 2.01, 15, 16, QgsWkbTypes::PointZM ) << QgsPoint( 11, 2.01, 25, 26, QgsWkbTypes::PointZM ) << QgsPoint( 1, 2, 5, 6, QgsWkbTypes::PointZM ) );
    7010                 :          1 :   transformPolygon.addInteriorRing( transformPolygonRing.clone() );
    7011                 :          1 :   transformPolygon.transformVertices( transform );
    7012                 :          2 :   QCOMPARE( transformPolygon.asWkt( 2 ), QStringLiteral( "PolygonZM ((15 8 11 14, 8 18 21 24, 15 18 21 24, 15 28 31 34, 15 8 11 14),(12 5 9 11, 6 15 17 19, 13.01 5.01 19 21, 13 5.01 29 31, 13 5 9 11, 12 5 9 11),(3 5 9 11, 13.01 5.01 19 21, 13 5.01 29 31, 3 5 9 11))" ) );
    7013                 :            : 
    7014                 :            :   // transform using class
    7015                 :          1 :   QgsPolygon transformPolygon2;
    7016                 :          1 :   TestTransformer transformer;
    7017                 :            :   // no crash
    7018                 :          1 :   QVERIFY( transformPolygon2.transform( &transformer ) );
    7019                 :          1 :   transformPolygonRing.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 4, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 11, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 11, 22, 23, 24, QgsWkbTypes::PointZM ) << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) );
    7020                 :          1 :   transformPolygon2.setExteriorRing( transformPolygonRing.clone() );
    7021                 :          1 :   QVERIFY( transformPolygon2.transform( &transformer ) );
    7022                 :          2 :   QCOMPARE( transformPolygon2.asWkt( 2 ), QStringLiteral( "PolygonZM ((33 16 8 3, 12 26 18 13, 33 26 18 13, 33 36 28 23, 33 16 8 3))" ) );
    7023                 :          1 :   transformPolygonRing.setPoints( QgsPointSequence() << QgsPoint( 10, 2, 5, 6, QgsWkbTypes::PointZM ) << QgsPoint( 4, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 11.01, 2.01, 15, 16, QgsWkbTypes::PointZM ) << QgsPoint( 11, 2.01, 25, 26, QgsWkbTypes::PointZM ) << QgsPoint( 11, 2, 5, 6, QgsWkbTypes::PointZM ) << QgsPoint( 10, 2, 5, 6, QgsWkbTypes::PointZM ) );
    7024                 :          1 :   transformPolygon2.addInteriorRing( transformPolygonRing.clone() );
    7025                 :          1 :   transformPolygonRing.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 5, 6, QgsWkbTypes::PointZM ) << QgsPoint( 11.01, 2.01, 15, 16, QgsWkbTypes::PointZM ) << QgsPoint( 11, 2.01, 25, 26, QgsWkbTypes::PointZM ) << QgsPoint( 1, 2, 5, 6, QgsWkbTypes::PointZM ) );
    7026                 :          1 :   transformPolygon2.addInteriorRing( transformPolygonRing.clone() );
    7027                 :          1 :   QVERIFY( transformPolygon2.transform( &transformer ) );
    7028                 :          2 :   QCOMPARE( transformPolygon2.asWkt( 2 ), QStringLiteral( "PolygonZM ((99 30 13 2, 36 40 23 12, 99 40 23 12, 99 50 33 22, 99 30 13 2),(30 16 10 5, 12 26 18 13, 33.03 16.01 20 15, 33 16.01 30 25, 33 16 10 5, 30 16 10 5),(3 16 10 5, 33.03 16.01 20 15, 33 16.01 30 25, 3 16 10 5))" ) );
    7029                 :            : 
    7030                 :          1 :   TestFailTransformer failTransformer;
    7031                 :          1 :   QVERIFY( !transformPolygon2.transform( &failTransformer ) );
    7032                 :            : 
    7033                 :            :   // remove invalid rings
    7034                 :          1 :   QgsPolygon invalidRingPolygon;
    7035                 :          1 :   invalidRingPolygon.removeInvalidRings(); // no crash
    7036                 :          1 :   QgsLineString removeInvalidPolygonRing;
    7037                 :          1 :   removeInvalidPolygonRing.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 4, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 11, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 11, 22, 23, 24, QgsWkbTypes::PointZM ) << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) );
    7038                 :          1 :   invalidRingPolygon.setExteriorRing( removeInvalidPolygonRing.clone() );
    7039                 :          1 :   invalidRingPolygon.removeInvalidRings();
    7040                 :          2 :   QCOMPARE( invalidRingPolygon.asWkt(), QStringLiteral( "PolygonZM ((11 2 3 4, 4 12 13 14, 11 12 13 14, 11 22 23 24, 11 2 3 4))" ) );
    7041                 :          1 :   removeInvalidPolygonRing.setPoints( QgsPointSequence() << QgsPoint( 10, 2, 5, 6, QgsWkbTypes::PointZM )  << QgsPoint( 11, 2, 5, 6, QgsWkbTypes::PointZM ) << QgsPoint( 10, 2, 5, 6, QgsWkbTypes::PointZM ) );
    7042                 :          1 :   invalidRingPolygon.addInteriorRing( removeInvalidPolygonRing.clone() );
    7043                 :          1 :   removeInvalidPolygonRing.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 5, 6, QgsWkbTypes::PointZM ) << QgsPoint( 11.01, 2.01, 15, 16, QgsWkbTypes::PointZM ) << QgsPoint( 11, 2.01, 25, 26, QgsWkbTypes::PointZM ) << QgsPoint( 1, 2, 5, 6, QgsWkbTypes::PointZM ) );
    7044                 :          1 :   invalidRingPolygon.addInteriorRing( removeInvalidPolygonRing.clone() );
    7045                 :          1 :   invalidRingPolygon.removeInvalidRings();
    7046                 :          2 :   QCOMPARE( invalidRingPolygon.asWkt( 2 ), QStringLiteral( "PolygonZM ((11 2 3 4, 4 12 13 14, 11 12 13 14, 11 22 23 24, 11 2 3 4),(1 2 5 6, 11.01 2.01 15 16, 11 2.01 25 26, 1 2 5 6))" ) );
    7047                 :            : 
    7048                 :            :   // force RHR
    7049                 :          1 :   QgsPolygon rhr;
    7050                 :          1 :   rhr.forceRHR(); // no crash
    7051                 :          2 :   rhr.fromWkt( QStringLiteral( "PolygonZM ((0 0 3 4, 0 100 13 14, 100 100 13 14, 100 0 23 24, 0 0 3 4))" ) );
    7052                 :          1 :   rhr.forceRHR();
    7053                 :          2 :   QCOMPARE( rhr.asWkt( 2 ), QStringLiteral( "PolygonZM ((0 0 3 4, 0 100 13 14, 100 100 13 14, 100 0 23 24, 0 0 3 4))" ) );
    7054                 :          2 :   rhr.fromWkt( QStringLiteral( "PolygonZM ((0 0 3 4, 100 0 13 14, 100 100 23 24, 0 100 23 24, 0 0 3 4))" ) );
    7055                 :          1 :   rhr.forceRHR();
    7056                 :          2 :   QCOMPARE( rhr.asWkt( 2 ), QStringLiteral( "PolygonZM ((0 0 3 4, 0 100 23 24, 100 100 23 24, 100 0 13 14, 0 0 3 4))" ) );
    7057                 :          2 :   rhr.fromWkt( QStringLiteral( "PolygonZM ((0 0 3 4, 0 100 13 14, 100 100 13 14, 100 0 23 24, 0 0 3 4),(10 10 1 2, 20 10 3 4, 20 20 4, 5, 10 20 6 8, 10 10 1 2))" ) );
    7058                 :          1 :   rhr.forceRHR();
    7059                 :          2 :   QCOMPARE( rhr.asWkt( 2 ), QStringLiteral( "PolygonZM ((0 0 3 4, 0 100 13 14, 100 100 13 14, 100 0 23 24, 0 0 3 4),(10 10 1 2, 20 10 3 4, 10 20 6 8, 10 10 1 2))" ) );
    7060                 :          2 :   rhr.fromWkt( QStringLiteral( "PolygonZM ((0 0 3 4, 100 0 13 14, 100 100 13 14, 0 100 23 24, 0 0 3 4),(10 10 1 2, 20 10 3 4, 20 20 4, 5, 10 20 6 8, 10 10 1 2))" ) );
    7061                 :          1 :   rhr.forceRHR();
    7062                 :          2 :   QCOMPARE( rhr.asWkt( 2 ), QStringLiteral( "PolygonZM ((0 0 3 4, 0 100 23 24, 100 100 13 14, 100 0 13 14, 0 0 3 4),(10 10 1 2, 20 10 3 4, 10 20 6 8, 10 10 1 2))" ) );
    7063                 :          2 :   rhr.fromWkt( QStringLiteral( "PolygonZM ((0 0 3 4, 0 100 13 14, 100 100 13 14, 100 0 23 24, 0 0 3 4),(10 10 1 2, 10 20 3 4, 20 10 6 8, 10 10 1 2))" ) );
    7064                 :          1 :   rhr.forceRHR();
    7065                 :          2 :   QCOMPARE( rhr.asWkt( 2 ), QStringLiteral( "PolygonZM ((0 0 3 4, 0 100 13 14, 100 100 13 14, 100 0 23 24, 0 0 3 4),(10 10 1 2, 20 10 6 8, 10 20 3 4, 10 10 1 2))" ) );
    7066                 :            : 
    7067                 :            :   // test bounding box intersects
    7068                 :          1 :   QgsPolygon bb;
    7069                 :          1 :   QVERIFY( !bb.boundingBoxIntersects( QgsRectangle( 1, 3, 6, 9 ) ) );
    7070                 :          1 :   QgsLineString bbR;
    7071                 :          1 :   bbR.setPoints( QgsPointSequence() << QgsPoint( 0, 2 ) << QgsPoint( 4, 2 ) << QgsPoint( 4, 4 ) << QgsPoint( 0, 2 ) );
    7072                 :          1 :   bb.setExteriorRing( bbR.clone() );
    7073                 :          1 :   QVERIFY( bb.boundingBoxIntersects( QgsRectangle( 1, 3, 6, 9 ) ) );
    7074                 :            :   // double test because of cache
    7075                 :          1 :   QVERIFY( bb.boundingBoxIntersects( QgsRectangle( 1, 3, 6, 9 ) ) );
    7076                 :          1 :   QVERIFY( !bb.boundingBoxIntersects( QgsRectangle( 11, 3, 6, 9 ) ) );
    7077                 :          1 :   QVERIFY( !bb.boundingBoxIntersects( QgsRectangle( 11, 3, 6, 9 ) ) );
    7078                 :          1 :   QCOMPARE( bb.boundingBox(), QgsRectangle( 0, 2, 4, 4 ) );
    7079                 :            :   // clear cache
    7080                 :          1 :   bbR.setPoints( QgsPointSequence() << QgsPoint( 10, 2 ) << QgsPoint( 14, 2 ) << QgsPoint( 15, 4 ) << QgsPoint( 10, 2 ) );
    7081                 :          1 :   bb.setExteriorRing( bbR.clone() );
    7082                 :          1 :   QVERIFY( !bb.boundingBoxIntersects( QgsRectangle( 1, 3, 6, 9 ) ) );
    7083                 :          1 :   QVERIFY( !bb.boundingBoxIntersects( QgsRectangle( 1, 3, 6, 9 ) ) );
    7084                 :          1 :   QCOMPARE( bb.boundingBox(), QgsRectangle( 10, 2, 15, 4 ) );
    7085                 :          1 :   QVERIFY( bb.boundingBoxIntersects( QgsRectangle( 11, 3, 16, 9 ) ) );
    7086                 :            :   // technically invalid -- the interior ring is outside the exterior, but we want boundingBoxIntersects to be tolerant to
    7087                 :            :   // cases like this!
    7088                 :          1 :   bbR.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 4, 2 ) << QgsPoint( 5, 4 ) << QgsPoint( 1, 2 ) );
    7089                 :          1 :   bb.addInteriorRing( bbR.clone() );
    7090                 :          1 :   QVERIFY( bb.boundingBoxIntersects( QgsRectangle( 1, 3, 6, 9 ) ) );
    7091                 :          1 :   QVERIFY( bb.boundingBoxIntersects( QgsRectangle( 1, 3, 6, 9 ) ) );
    7092                 :          1 :   QVERIFY( bb.boundingBoxIntersects( QgsRectangle( 11, 3, 16, 9 ) ) );
    7093                 :          1 :   QVERIFY( !bb.boundingBoxIntersects( QgsRectangle( 21, 3, 26, 9 ) ) );
    7094                 :          1 :   QCOMPARE( bb.boundingBox(), QgsRectangle( 10, 2, 15, 4 ) );
    7095                 :          1 : }
    7096                 :            : 
    7097                 :          1 : void TestQgsGeometry::triangle()
    7098                 :            : {
    7099                 :            :   //test constructor
    7100                 :          1 :   QgsTriangle t1;
    7101                 :          1 :   QVERIFY( t1.isEmpty() );
    7102                 :          1 :   QCOMPARE( t1.numInteriorRings(), 0 );
    7103                 :          1 :   QCOMPARE( t1.nCoordinates(), 0 );
    7104                 :          1 :   QCOMPARE( t1.ringCount(), 0 );
    7105                 :          1 :   QCOMPARE( t1.partCount(), 0 );
    7106                 :          1 :   QVERIFY( !t1.is3D() );
    7107                 :          1 :   QVERIFY( !t1.isMeasure() );
    7108                 :          1 :   QCOMPARE( t1.wkbType(), QgsWkbTypes::Triangle );
    7109                 :          1 :   QCOMPARE( t1.wktTypeStr(), QString( "Triangle" ) );
    7110                 :          1 :   QCOMPARE( t1.geometryType(), QString( "Triangle" ) );
    7111                 :          1 :   QCOMPARE( t1.dimension(), 2 );
    7112                 :          1 :   QVERIFY( !t1.hasCurvedSegments() );
    7113                 :          1 :   QCOMPARE( t1.area(), 0.0 );
    7114                 :          1 :   QCOMPARE( t1.perimeter(), 0.0 );
    7115                 :          1 :   QVERIFY( !t1.exteriorRing() );
    7116                 :          1 :   QVERIFY( !t1.interiorRing( 0 ) );
    7117                 :            : 
    7118                 :            :   // degenerate triangles
    7119                 :          1 :   QgsTriangle invalid( QgsPointXY( 0, 0 ), QgsPointXY( 0, 0 ), QgsPointXY( 10, 10 ) );
    7120                 :          1 :   QVERIFY( !invalid.isEmpty() );
    7121                 :          1 :   invalid = QgsTriangle( QPointF( 0, 0 ), QPointF( 0, 0 ), QPointF( 10, 10 ) );
    7122                 :          1 :   QVERIFY( !invalid.isEmpty() );
    7123                 :            :   //set exterior ring
    7124                 :            : 
    7125                 :            :   //try with no ring
    7126                 :          1 :   std::unique_ptr< QgsLineString > ext;
    7127                 :          1 :   t1.setExteriorRing( nullptr );
    7128                 :          1 :   QVERIFY( t1.isEmpty() );
    7129                 :          1 :   QCOMPARE( t1.numInteriorRings(), 0 );
    7130                 :          1 :   QCOMPARE( t1.nCoordinates(), 0 );
    7131                 :          1 :   QCOMPARE( t1.ringCount(), 0 );
    7132                 :          1 :   QCOMPARE( t1.partCount(), 0 );
    7133                 :          1 :   QVERIFY( !t1.exteriorRing() );
    7134                 :          1 :   QVERIFY( !t1.interiorRing( 0 ) );
    7135                 :          1 :   QCOMPARE( t1.wkbType(), QgsWkbTypes::Triangle );
    7136                 :            : 
    7137                 :            :   //valid exterior ring
    7138                 :          1 :   ext.reset( new QgsLineString() );
    7139                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
    7140                 :          1 :                   << QgsPoint( 0, 0 ) );
    7141                 :          1 :   QVERIFY( ext->isClosed() );
    7142                 :          1 :   t1.setExteriorRing( ext->clone() );
    7143                 :          1 :   QVERIFY( !t1.isEmpty() );
    7144                 :          1 :   QCOMPARE( t1.numInteriorRings(), 0 );
    7145                 :          1 :   QCOMPARE( t1.nCoordinates(), 4 );
    7146                 :          1 :   QCOMPARE( t1.ringCount(), 1 );
    7147                 :          1 :   QCOMPARE( t1.partCount(), 1 );
    7148                 :          1 :   QVERIFY( !t1.is3D() );
    7149                 :          1 :   QVERIFY( !t1.isMeasure() );
    7150                 :          1 :   QCOMPARE( t1.wkbType(), QgsWkbTypes::Triangle );
    7151                 :          1 :   QCOMPARE( t1.wktTypeStr(), QString( "Triangle" ) );
    7152                 :          1 :   QCOMPARE( t1.geometryType(), QString( "Triangle" ) );
    7153                 :          1 :   QCOMPARE( t1.dimension(), 2 );
    7154                 :          1 :   QVERIFY( !t1.hasCurvedSegments() );
    7155                 :          1 :   QCOMPARE( t1.area(), 50.0 );
    7156                 :          1 :   QGSCOMPARENEAR( t1.perimeter(), 34.1421, 0.001 );
    7157                 :          1 :   QVERIFY( t1.exteriorRing() );
    7158                 :          1 :   QVERIFY( !t1.interiorRing( 0 ) );
    7159                 :            : 
    7160                 :            :   //retrieve exterior ring and check
    7161                 :          1 :   QCOMPARE( *( static_cast< const QgsLineString * >( t1.exteriorRing() ) ), *ext );
    7162                 :            : 
    7163                 :            :   //set new ExteriorRing
    7164                 :          1 :   ext.reset( new QgsLineString() );
    7165                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 10 ) << QgsPoint( 5, 5 ) << QgsPoint( 10, 10 )
    7166                 :          1 :                   << QgsPoint( 0, 10 ) );
    7167                 :          1 :   QVERIFY( ext->isClosed() );
    7168                 :          1 :   t1.setExteriorRing( ext->clone() );
    7169                 :          1 :   QVERIFY( !t1.isEmpty() );
    7170                 :          1 :   QCOMPARE( t1.numInteriorRings(), 0 );
    7171                 :          1 :   QCOMPARE( t1.nCoordinates(), 4 );
    7172                 :          1 :   QCOMPARE( t1.ringCount(), 1 );
    7173                 :          1 :   QCOMPARE( t1.partCount(), 1 );
    7174                 :          1 :   QVERIFY( !t1.is3D() );
    7175                 :          1 :   QVERIFY( !t1.isMeasure() );
    7176                 :          1 :   QCOMPARE( t1.wkbType(), QgsWkbTypes::Triangle );
    7177                 :          1 :   QCOMPARE( t1.wktTypeStr(), QString( "Triangle" ) );
    7178                 :          1 :   QCOMPARE( t1.geometryType(), QString( "Triangle" ) );
    7179                 :          1 :   QCOMPARE( t1.dimension(), 2 );
    7180                 :          1 :   QVERIFY( !t1.hasCurvedSegments() );
    7181                 :          1 :   QCOMPARE( t1.area(), 25.0 );
    7182                 :          1 :   QGSCOMPARENEAR( t1.perimeter(), 24.1421, 0.001 );
    7183                 :          1 :   QVERIFY( t1.exteriorRing() );
    7184                 :          1 :   QVERIFY( !t1.interiorRing( 0 ) );
    7185                 :          1 :   QCOMPARE( *( static_cast< const QgsLineString * >( t1.exteriorRing() ) ), *ext );
    7186                 :            : 
    7187                 :            :   // AddZ
    7188                 :          1 :   QgsLineString lz;
    7189                 :          1 :   lz.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 3 ) << QgsPoint( 11, 12, 13 ) << QgsPoint( 1, 12, 23 ) << QgsPoint( 1, 2, 3 ) );
    7190                 :          1 :   t1.setExteriorRing( lz.clone() );
    7191                 :          1 :   QVERIFY( t1.is3D() );
    7192                 :          1 :   QVERIFY( !t1.isMeasure() );
    7193                 :          1 :   QCOMPARE( t1.wkbType(), QgsWkbTypes::TriangleZ );
    7194                 :          1 :   QCOMPARE( t1.wktTypeStr(), QString( "TriangleZ" ) );
    7195                 :          1 :   QCOMPARE( t1.geometryType(), QString( "Triangle" ) );
    7196                 :          1 :   QCOMPARE( t1.dimension(), 2 );
    7197                 :          1 :   QCOMPARE( t1.vertexAt( 0 ).z(),  3.0 );
    7198                 :          1 :   QCOMPARE( t1.vertexAt( 1 ).z(), 13.0 );
    7199                 :          1 :   QCOMPARE( t1.vertexAt( 2 ).z(), 23.0 );
    7200                 :            :   // AddM
    7201                 :          1 :   QgsLineString lzm;
    7202                 :          1 :   lzm.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 3, 4 ) << QgsPoint( 11, 12, 13, 14 ) << QgsPoint( 1, 12, 23, 24 ) << QgsPoint( 1, 2, 3, 4 ) );
    7203                 :          1 :   t1.setExteriorRing( lzm.clone() );
    7204                 :          1 :   QVERIFY( t1.is3D() );
    7205                 :          1 :   QVERIFY( t1.isMeasure() );
    7206                 :          1 :   QCOMPARE( t1.wkbType(), QgsWkbTypes::TriangleZM );
    7207                 :          1 :   QCOMPARE( t1.wktTypeStr(), QString( "TriangleZM" ) );
    7208                 :          1 :   QCOMPARE( t1.geometryType(), QString( "Triangle" ) );
    7209                 :          1 :   QCOMPARE( t1.dimension(), 2 );
    7210                 :          1 :   QCOMPARE( t1.vertexAt( 0 ).m(),  4.0 );
    7211                 :          1 :   QCOMPARE( t1.vertexAt( 1 ).m(), 14.0 );
    7212                 :          1 :   QCOMPARE( t1.vertexAt( 2 ).m(), 24.0 );
    7213                 :            :   // dropZ
    7214                 :          1 :   t1.dropZValue();
    7215                 :          1 :   QVERIFY( !t1.is3D() );
    7216                 :          1 :   QVERIFY( t1.isMeasure() );
    7217                 :          1 :   QCOMPARE( t1.wkbType(), QgsWkbTypes::TriangleM );
    7218                 :          1 :   QCOMPARE( t1.wktTypeStr(), QString( "TriangleM" ) );
    7219                 :          1 :   QCOMPARE( t1.geometryType(), QString( "Triangle" ) );
    7220                 :          1 :   QCOMPARE( t1.dimension(), 2 );
    7221                 :          1 :   QVERIFY( std::isnan( t1.vertexAt( 0 ).z() ) );
    7222                 :          1 :   QVERIFY( std::isnan( t1.vertexAt( 1 ).z() ) );
    7223                 :          1 :   QVERIFY( std::isnan( t1.vertexAt( 2 ).z() ) );
    7224                 :            :   // dropM
    7225                 :          1 :   t1.dropMValue();
    7226                 :          1 :   QVERIFY( !t1.is3D() );
    7227                 :          1 :   QVERIFY( !t1.isMeasure() );
    7228                 :          1 :   QCOMPARE( t1.wkbType(), QgsWkbTypes::Triangle );
    7229                 :          1 :   QCOMPARE( t1.wktTypeStr(), QString( "Triangle" ) );
    7230                 :          1 :   QCOMPARE( t1.geometryType(), QString( "Triangle" ) );
    7231                 :          1 :   QCOMPARE( t1.dimension(), 2 );
    7232                 :          1 :   QVERIFY( std::isnan( t1.vertexAt( 0 ).m() ) );
    7233                 :          1 :   QVERIFY( std::isnan( t1.vertexAt( 1 ).m() ) );
    7234                 :          1 :   QVERIFY( std::isnan( t1.vertexAt( 2 ).m() ) );
    7235                 :            : 
    7236                 :            :   //test that a non closed exterior ring will be automatically closed
    7237                 :          1 :   QgsTriangle t2;
    7238                 :          1 :   ext.reset( new QgsLineString() );
    7239                 :          1 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 ) );
    7240                 :          1 :   QVERIFY( !ext->isClosed() );
    7241                 :          1 :   t2.setExteriorRing( ext.release() );
    7242                 :          1 :   QVERIFY( !t2.isEmpty() );
    7243                 :          1 :   QVERIFY( t2.exteriorRing()->isClosed() );
    7244                 :          1 :   QCOMPARE( t2.nCoordinates(), 4 );
    7245                 :            : 
    7246                 :            :   // invalid number of points
    7247                 :          1 :   ext.reset( new QgsLineString() );
    7248                 :          1 :   t2.clear();
    7249                 :          1 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) );
    7250                 :          1 :   t2.setExteriorRing( ext.release() );
    7251                 :          1 :   QVERIFY( t2.isEmpty() );
    7252                 :            : 
    7253                 :          1 :   ext.reset( new QgsLineString() );
    7254                 :          1 :   t2.clear();
    7255                 :          1 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 ) << QgsPoint( 5, 10 ) << QgsPoint( 8, 10 ) );
    7256                 :          1 :   t2.setExteriorRing( ext.release() );
    7257                 :          1 :   QVERIFY( t2.isEmpty() );
    7258                 :            : 
    7259                 :            :   // invalid exterior ring
    7260                 :          1 :   ext.reset( new QgsLineString() );
    7261                 :          1 :   t2.clear();
    7262                 :          1 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 ) << QgsPoint( 5, 10 ) );
    7263                 :          1 :   t2.setExteriorRing( ext.release() );
    7264                 :          1 :   QVERIFY( t2.isEmpty() );
    7265                 :            : 
    7266                 :          1 :   ext.reset( new QgsLineString() );
    7267                 :          1 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 0, 0 ) );
    7268                 :          1 :   t2.setExteriorRing( ext.release() );
    7269                 :          1 :   QVERIFY( t2.isEmpty() );
    7270                 :            : 
    7271                 :            :   // degenerate case
    7272                 :          1 :   ext.reset( new QgsLineString() );
    7273                 :          1 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 0, 0 ) );
    7274                 :          1 :   t2.setExteriorRing( ext.release() );
    7275                 :          1 :   QVERIFY( !t2.isEmpty() );
    7276                 :            : 
    7277                 :            :   // circular ring
    7278                 :          1 :   QgsCircularString *circularRing = new QgsCircularString();
    7279                 :          1 :   t2.clear();
    7280                 :          1 :   circularRing->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 ) );
    7281                 :          1 :   QVERIFY( circularRing->hasCurvedSegments() );
    7282                 :          1 :   t2.setExteriorRing( circularRing );
    7283                 :          1 :   QVERIFY( t2.isEmpty() );
    7284                 :            : 
    7285                 :            :   //constructor with 3 points
    7286                 :            :   // double points
    7287                 :          1 :   QgsTriangle t3( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ), QgsPoint( 10, 10 ) );
    7288                 :          1 :   QVERIFY( !t3.isEmpty() );
    7289                 :          1 :   QCOMPARE( t3.numInteriorRings(), 0 );
    7290                 :          1 :   QCOMPARE( t3.nCoordinates(), 4 );
    7291                 :          1 :   QCOMPARE( t3.ringCount(), 1 );
    7292                 :          1 :   QCOMPARE( t3.partCount(), 1 );
    7293                 :          1 :   QVERIFY( !t3.is3D() );
    7294                 :          1 :   QVERIFY( !t3.isMeasure() );
    7295                 :          1 :   QCOMPARE( t3.wkbType(), QgsWkbTypes::Triangle );
    7296                 :          1 :   QCOMPARE( t3.wktTypeStr(), QString( "Triangle" ) );
    7297                 :          1 :   QCOMPARE( t3.geometryType(), QString( "Triangle" ) );
    7298                 :          1 :   QCOMPARE( t3.dimension(), 2 );
    7299                 :          1 :   QVERIFY( !t3.hasCurvedSegments() );
    7300                 :          1 :   QCOMPARE( t3.area(), 0.0 );
    7301                 :          1 :   QGSCOMPARENEAR( t3.perimeter(), 28.284271, 0.001 );
    7302                 :          1 :   QVERIFY( t3.exteriorRing() );
    7303                 :          1 :   QVERIFY( !t3.interiorRing( 0 ) );
    7304                 :            : 
    7305                 :            :   // colinear
    7306                 :          1 :   t3 = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 10 ) );
    7307                 :          1 :   QVERIFY( !t3.isEmpty() );
    7308                 :          1 :   QCOMPARE( t3.numInteriorRings(), 0 );
    7309                 :          1 :   QCOMPARE( t3.nCoordinates(), 4 );
    7310                 :          1 :   QCOMPARE( t3.ringCount(), 1 );
    7311                 :          1 :   QCOMPARE( t3.partCount(), 1 );
    7312                 :          1 :   QVERIFY( !t3.is3D() );
    7313                 :          1 :   QVERIFY( !t3.isMeasure() );
    7314                 :          1 :   QCOMPARE( t3.wkbType(), QgsWkbTypes::Triangle );
    7315                 :          1 :   QCOMPARE( t3.wktTypeStr(), QString( "Triangle" ) );
    7316                 :          1 :   QCOMPARE( t3.geometryType(), QString( "Triangle" ) );
    7317                 :          1 :   QCOMPARE( t3.dimension(), 2 );
    7318                 :          1 :   QVERIFY( !t3.hasCurvedSegments() );
    7319                 :          1 :   QCOMPARE( t3.area(), 0.0 );
    7320                 :          1 :   QGSCOMPARENEAR( t3.perimeter(), 10.0 * 2, 0.001 );
    7321                 :          1 :   QVERIFY( t3.exteriorRing() );
    7322                 :          1 :   QVERIFY( !t3.interiorRing( 0 ) );
    7323                 :            : 
    7324                 :          1 :   t3 = QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 10 ), QgsPoint( 10, 10 ) );
    7325                 :          1 :   QVERIFY( !t3.isEmpty() );
    7326                 :          1 :   QCOMPARE( t3.numInteriorRings(), 0 );
    7327                 :          1 :   QCOMPARE( t3.nCoordinates(), 4 );
    7328                 :          1 :   QCOMPARE( t3.ringCount(), 1 );
    7329                 :          1 :   QCOMPARE( t3.partCount(), 1 );
    7330                 :          1 :   QVERIFY( !t3.is3D() );
    7331                 :          1 :   QVERIFY( !t3.isMeasure() );
    7332                 :          1 :   QCOMPARE( t3.wkbType(), QgsWkbTypes::Triangle );
    7333                 :          1 :   QCOMPARE( t3.wktTypeStr(), QString( "Triangle" ) );
    7334                 :          1 :   QCOMPARE( t3.geometryType(), QString( "Triangle" ) );
    7335                 :          1 :   QCOMPARE( t3.dimension(), 2 );
    7336                 :          1 :   QVERIFY( !t3.hasCurvedSegments() );
    7337                 :          1 :   QCOMPARE( t3.area(), 50.0 );
    7338                 :          1 :   QGSCOMPARENEAR( t3.perimeter(), 34.1421, 0.001 );
    7339                 :          1 :   QVERIFY( t3.exteriorRing() );
    7340                 :          1 :   QVERIFY( !t3.interiorRing( 0 ) );
    7341                 :            : 
    7342                 :            :   // equality
    7343                 :          1 :   QVERIFY( QgsTriangle() == QgsTriangle() ); // empty
    7344                 :          1 :   QVERIFY( QgsTriangle() != QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 10 ) ) ); // empty
    7345                 :          1 :   QVERIFY( QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 10 ) ) != QgsTriangle() ); // empty
    7346                 :          1 :   QVERIFY( QgsTriangle() != QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 0, 10 ) ) );
    7347                 :          1 :   QVERIFY( QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 0, 10 ) ) != QgsTriangle() );
    7348                 :          1 :   QVERIFY( QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 0, 10 ) ) != QgsTriangle( QgsPoint( 0, 10 ), QgsPoint( 5, 5 ), QgsPoint( 0, 0 ) ) );
    7349                 :            : 
    7350                 :            :   // clone
    7351                 :          1 :   QgsTriangle *t4 = t3.clone();
    7352                 :          1 :   QCOMPARE( t3, *t4 );
    7353                 :          1 :   delete t4;
    7354                 :            : 
    7355                 :            :   // constructor from QgsPointXY and QPointF
    7356                 :          1 :   QgsTriangle t_qgspoint = QgsTriangle( QgsPointXY( 0, 0 ), QgsPointXY( 0, 10 ), QgsPointXY( 10, 10 ) );
    7357                 :          1 :   QVERIFY( t3 == t_qgspoint );
    7358                 :          1 :   QgsTriangle t_pointf = QgsTriangle( QPointF( 0, 0 ), QPointF( 0, 10 ), QPointF( 10, 10 ) );
    7359                 :          1 :   QVERIFY( t3 == t_pointf );
    7360                 :            : 
    7361                 :            :   // Z
    7362                 :          1 :   t3 = QgsTriangle( QgsPoint( QgsWkbTypes::PointZ, 0, 5, 1 ), QgsPoint( QgsWkbTypes::PointZ, 0, 0, 2 ), QgsPoint( QgsWkbTypes::PointZ, 10, 10, 3 ) );
    7363                 :          1 :   QVERIFY( !t3.isEmpty() );
    7364                 :          1 :   QVERIFY( t3.is3D() );
    7365                 :          1 :   QVERIFY( !t3.isMeasure() );
    7366                 :          1 :   QCOMPARE( t3.wkbType(), QgsWkbTypes::TriangleZ );
    7367                 :          1 :   QCOMPARE( t3.wktTypeStr(), QString( "TriangleZ" ) );
    7368                 :          1 :   QCOMPARE( t3.geometryType(), QString( "Triangle" ) );
    7369                 :            :   // M
    7370                 :          1 :   t3 = QgsTriangle( QgsPoint( QgsWkbTypes::PointM, 0, 5, 0, 1 ), QgsPoint( QgsWkbTypes::PointM, 0, 0, 0, 2 ), QgsPoint( QgsWkbTypes::PointM, 10, 10, 0, 3 ) );
    7371                 :          1 :   QVERIFY( !t3.isEmpty() );
    7372                 :          1 :   QVERIFY( !t3.is3D() );
    7373                 :          1 :   QVERIFY( t3.isMeasure() );
    7374                 :          1 :   QCOMPARE( t3.wkbType(), QgsWkbTypes::TriangleM );
    7375                 :          1 :   QCOMPARE( t3.wktTypeStr(), QString( "TriangleM" ) );
    7376                 :          1 :   QCOMPARE( t3.geometryType(), QString( "Triangle" ) );
    7377                 :            :   // ZM
    7378                 :          1 :   t3 = QgsTriangle( QgsPoint( QgsWkbTypes::PointZM, 0, 5, 8, 1 ), QgsPoint( QgsWkbTypes::PointZM, 0, 0, 5, 2 ), QgsPoint( QgsWkbTypes::PointZM, 10, 10, 2, 3 ) );
    7379                 :          1 :   QVERIFY( !t3.isEmpty() );
    7380                 :          1 :   QVERIFY( t3.is3D() );
    7381                 :          1 :   QVERIFY( t3.isMeasure() );
    7382                 :          1 :   QCOMPARE( t3.wkbType(), QgsWkbTypes::TriangleZM );
    7383                 :          1 :   QCOMPARE( t3.wktTypeStr(), QString( "TriangleZM" ) );
    7384                 :          1 :   QCOMPARE( t3.geometryType(), QString( "Triangle" ) );
    7385                 :            : 
    7386                 :            :   // fromWkt
    7387                 :          1 :   QgsTriangle t5;
    7388                 :          1 :   ext.reset( new QgsLineString() );
    7389                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 5 )
    7390                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 0, 10, 2, 6 ) << QgsPoint( QgsWkbTypes::PointZM, 10, 10, 3, 7 ) );
    7391                 :          1 :   t5.setExteriorRing( ext.release() );
    7392                 :          1 :   QString wkt = t5.asWkt();
    7393                 :          1 :   QVERIFY( !wkt.isEmpty() );
    7394                 :          1 :   QgsTriangle t6;
    7395                 :          1 :   QVERIFY( t6.fromWkt( wkt ) );
    7396                 :          1 :   QCOMPARE( t5, t6 );
    7397                 :            : 
    7398                 :            :   // conversion
    7399                 :          1 :   QgsPolygon p1;
    7400                 :          1 :   ext.reset( new QgsLineString() );
    7401                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 5 )
    7402                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 0, 10, 2, 6 ) << QgsPoint( QgsWkbTypes::PointZM, 10, 10, 3, 7 ) );
    7403                 :          1 :   p1.setExteriorRing( ext.release() );
    7404                 :            :   //toPolygon
    7405                 :          1 :   std::unique_ptr< QgsPolygon > poly( t5.toPolygon() );
    7406                 :          1 :   QCOMPARE( *poly, p1 );
    7407                 :            :   //surfaceToPolygon
    7408                 :          1 :   std::unique_ptr< QgsPolygon > surface( t5.surfaceToPolygon() );
    7409                 :          1 :   QCOMPARE( *surface, p1 );
    7410                 :            : 
    7411                 :            :   //bad WKT
    7412                 :          1 :   QVERIFY( !t6.fromWkt( "Point()" ) );
    7413                 :          1 :   QVERIFY( t6.isEmpty() );
    7414                 :          1 :   QVERIFY( !t6.exteriorRing() );
    7415                 :          1 :   QCOMPARE( t6.numInteriorRings(), 0 );
    7416                 :          1 :   QVERIFY( !t6.is3D() );
    7417                 :          1 :   QVERIFY( !t6.isMeasure() );
    7418                 :          1 :   QCOMPARE( t6.wkbType(), QgsWkbTypes::Triangle );
    7419                 :            : 
    7420                 :            :   // WKB
    7421                 :          1 :   QByteArray wkb = t5.asWkb();
    7422                 :          1 :   QCOMPARE( wkb.size(), t5.wkbSize() );
    7423                 :          1 :   t6.clear();
    7424                 :          1 :   QgsConstWkbPtr wkb16ptr5( wkb );
    7425                 :          1 :   t6.fromWkb( wkb16ptr5 );
    7426                 :          1 :   QCOMPARE( t5.wkbType(), QgsWkbTypes::TriangleZM );
    7427                 :          1 :   QCOMPARE( t5, t6 );
    7428                 :            : 
    7429                 :            :   //bad WKB - check for no crash
    7430                 :          1 :   t6.clear();
    7431                 :          1 :   QgsConstWkbPtr nullPtr( nullptr, 0 );
    7432                 :          1 :   QVERIFY( !t6.fromWkb( nullPtr ) );
    7433                 :          1 :   QCOMPARE( t6.wkbType(), QgsWkbTypes::Triangle );
    7434                 :          1 :   QgsPoint point( 1, 2 );
    7435                 :          1 :   QByteArray wkbPoint = point.asWkb();
    7436                 :          1 :   QgsConstWkbPtr wkbPointPtr( wkbPoint );
    7437                 :          1 :   QVERIFY( !t6.fromWkb( wkbPointPtr ) );
    7438                 :          1 :   QCOMPARE( t6.wkbType(), QgsWkbTypes::Triangle );
    7439                 :            : 
    7440                 :            :   //asGML2
    7441                 :          2 :   QgsTriangle exportTriangle( QgsPoint( 1, 2 ),
    7442                 :          1 :                               QgsPoint( 3, 4 ),
    7443                 :          1 :                               QgsPoint( 6, 5 ) );
    7444                 :          2 :   QgsTriangle exportTriangleZ( QgsPoint( 1, 2, 3 ),
    7445                 :          1 :                                QgsPoint( 11, 12, 13 ),
    7446                 :          1 :                                QgsPoint( 1, 12, 23 ) );
    7447                 :          2 :   QgsTriangle exportTriangleFloat( QgsPoint( 1 + 1 / 3.0, 2 + 2 / 3.0 ),
    7448                 :          1 :                                    QgsPoint( 3 + 1 / 3.0, 4 + 2 / 3.0 ),
    7449                 :          1 :                                    QgsPoint( 6 + 1 / 3.0, 5 + 2 / 3.0 ) );
    7450                 :          2 :   QDomDocument doc( QStringLiteral( "gml" ) );
    7451                 :          2 :   QString expectedGML2( QStringLiteral( "<Polygon xmlns=\"gml\"><outerBoundaryIs xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">1,2 3,4 6,5 1,2</coordinates></LinearRing></outerBoundaryIs></Polygon>" ) );
    7452                 :          3 :   QGSCOMPAREGML( elemToString( exportTriangle.asGml2( doc ) ), expectedGML2 );
    7453                 :          2 :   QString expectedGML2prec3( QStringLiteral( "<Polygon xmlns=\"gml\"><outerBoundaryIs xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">1.333,2.667 3.333,4.667 6.333,5.667 1.333,2.667</coordinates></LinearRing></outerBoundaryIs></Polygon>" ) );
    7454                 :          3 :   QGSCOMPAREGML( elemToString( exportTriangleFloat.asGml2( doc, 3 ) ), expectedGML2prec3 );
    7455                 :          2 :   QString expectedGML2empty( QStringLiteral( "<Polygon xmlns=\"gml\"/>" ) );
    7456                 :          3 :   QGSCOMPAREGML( elemToString( QgsTriangle().asGml2( doc ) ), expectedGML2empty );
    7457                 :            : 
    7458                 :            :   //asGML3
    7459                 :          2 :   QString expectedGML3( QStringLiteral( "<Triangle xmlns=\"gml\"><exterior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">1 2 3 4 6 5 1 2</posList></LinearRing></exterior></Triangle>" ) );
    7460                 :          1 :   QCOMPARE( elemToString( exportTriangle.asGml3( doc ) ), expectedGML3 );
    7461                 :          2 :   QString expectedGML3prec3( QStringLiteral( "<Triangle xmlns=\"gml\"><exterior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">1.333 2.667 3.333 4.667 6.333 5.667 1.333 2.667</posList></LinearRing></exterior></Triangle>" ) );
    7462                 :          1 :   QCOMPARE( elemToString( exportTriangleFloat.asGml3( doc, 3 ) ), expectedGML3prec3 );
    7463                 :          2 :   QString expectedGML3empty( QStringLiteral( "<Triangle xmlns=\"gml\"/>" ) );
    7464                 :          3 :   QGSCOMPAREGML( elemToString( QgsTriangle().asGml3( doc ) ), expectedGML3empty );
    7465                 :          2 :   QString expectedGML3Z( QStringLiteral( "<Triangle xmlns=\"gml\"><exterior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"3\">1 2 3 11 12 13 1 12 23 1 2 3</posList></LinearRing></exterior></Triangle>" ) );
    7466                 :          1 :   QCOMPARE( elemToString( exportTriangleZ.asGml3( doc ) ), expectedGML3Z );
    7467                 :            : 
    7468                 :            : 
    7469                 :            :   // lengths and angles
    7470                 :          1 :   QgsTriangle t7( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ) );
    7471                 :            : 
    7472                 :          1 :   QVector<double> a_tested, a_t7 = t7.angles();
    7473                 :          1 :   a_tested.append( M_PI / 4.0 );
    7474                 :          1 :   a_tested.append( M_PI / 2.0 );
    7475                 :          1 :   a_tested.append( M_PI / 4.0 );
    7476                 :          1 :   QGSCOMPARENEAR( a_tested.at( 0 ), a_t7.at( 0 ), 0.0001 );
    7477                 :          1 :   QGSCOMPARENEAR( a_tested.at( 1 ), a_t7.at( 1 ), 0.0001 );
    7478                 :          1 :   QGSCOMPARENEAR( a_tested.at( 2 ), a_t7.at( 2 ), 0.0001 );
    7479                 :          1 :   QVector<double> a_empty = QgsTriangle().angles();
    7480                 :          1 :   QVERIFY( a_empty.isEmpty() );
    7481                 :            : 
    7482                 :          1 :   QVector<double> l_tested, l_t7 = t7.lengths();
    7483                 :          1 :   l_tested.append( 5 );
    7484                 :          1 :   l_tested.append( 5 );
    7485                 :          1 :   l_tested.append( std::sqrt( 5 * 5 + 5 * 5 ) );
    7486                 :          1 :   QGSCOMPARENEAR( l_tested.at( 0 ), l_t7.at( 0 ), 0.0001 );
    7487                 :          1 :   QGSCOMPARENEAR( l_tested.at( 1 ), l_t7.at( 1 ), 0.0001 );
    7488                 :          1 :   QGSCOMPARENEAR( l_tested.at( 2 ), l_t7.at( 2 ), 0.0001 );
    7489                 :          1 :   QVector<double> l_empty = QgsTriangle().lengths();
    7490                 :          1 :   QVERIFY( l_empty.isEmpty() );
    7491                 :            : 
    7492                 :            :   // type of triangle
    7493                 :            :   // Empty triangle returns always false for the types, except isDegenerate
    7494                 :          1 :   QVERIFY( QgsTriangle().isDegenerate() );
    7495                 :          1 :   QVERIFY( !QgsTriangle().isRight() );
    7496                 :          1 :   QVERIFY( !QgsTriangle().isIsocele() );
    7497                 :          1 :   QVERIFY( !QgsTriangle().isScalene() );
    7498                 :          1 :   QVERIFY( !QgsTriangle().isEquilateral() );
    7499                 :            : 
    7500                 :            :   // type of triangle
    7501                 :          1 :   QVERIFY( !t7.isDegenerate() );
    7502                 :          1 :   QVERIFY( t7.isRight() );
    7503                 :          1 :   QVERIFY( t7.isIsocele() );
    7504                 :          1 :   QVERIFY( !t7.isScalene() );
    7505                 :          1 :   QVERIFY( !t7.isEquilateral() );
    7506                 :            : 
    7507                 :          1 :   QgsTriangle t8( QgsPoint( 7.2825, 4.2368 ), QgsPoint( 13.0058, 3.3218 ), QgsPoint( 9.2145, 6.5242 ) );
    7508                 :            :   // angles in radians 58.8978;31.1036;89.9985
    7509                 :            :   // length 5.79598;4.96279;2.99413
    7510                 :          1 :   QVERIFY( !t8.isDegenerate() );
    7511                 :          1 :   QVERIFY( t8.isRight() );
    7512                 :          1 :   QVERIFY( !t8.isIsocele() );
    7513                 :          1 :   QVERIFY( t8.isScalene() );
    7514                 :          1 :   QVERIFY( !t8.isEquilateral() );
    7515                 :            : 
    7516                 :          1 :   QgsTriangle t9( QgsPoint( 10, 10 ), QgsPoint( 16, 10 ), QgsPoint( 13, 15.1962 ) );
    7517                 :          1 :   QVERIFY( !t9.isDegenerate() );
    7518                 :          1 :   QVERIFY( !t9.isRight() );
    7519                 :          1 :   QVERIFY( t9.isIsocele() );
    7520                 :          1 :   QVERIFY( !t9.isScalene() );
    7521                 :          1 :   QVERIFY( t9.isEquilateral() );
    7522                 :            : 
    7523                 :            :   // vertex
    7524                 :          1 :   QVERIFY( t9.vertexAt( -1 ).isEmpty() );
    7525                 :          1 :   QCOMPARE( t9.vertexAt( 0 ), QgsPoint( 10, 10 ) );
    7526                 :          1 :   QCOMPARE( t9.vertexAt( 1 ), QgsPoint( 16, 10 ) );
    7527                 :          1 :   QCOMPARE( t9.vertexAt( 2 ), QgsPoint( 13, 15.1962 ) );
    7528                 :          1 :   QCOMPARE( t9.vertexAt( 3 ), QgsPoint( 10, 10 ) );
    7529                 :          1 :   QVERIFY( t9.vertexAt( 4 ).isEmpty() );
    7530                 :            : 
    7531                 :            :   // altitudes
    7532                 :          1 :   QgsTriangle t10( QgsPoint( 20, 2 ), QgsPoint( 16, 6 ), QgsPoint( 26, 2 ) );
    7533                 :          1 :   QVector<QgsLineString> alt = QgsTriangle().altitudes();
    7534                 :          1 :   QVERIFY( alt.isEmpty() );
    7535                 :          1 :   alt = t10.altitudes();
    7536                 :          1 :   QGSCOMPARENEARPOINT( alt.at( 0 ).pointN( 1 ), QgsPoint( 20.8276, 4.0690 ), 0.0001 );
    7537                 :          1 :   QGSCOMPARENEARPOINT( alt.at( 1 ).pointN( 1 ), QgsPoint( 16, 2 ), 0.0001 );
    7538                 :          1 :   QGSCOMPARENEARPOINT( alt.at( 2 ).pointN( 1 ), QgsPoint( 23, -1 ), 0.0001 );
    7539                 :            : 
    7540                 :            :   // orthocenter
    7541                 :            : 
    7542                 :          1 :   QVERIFY( QgsTriangle().orthocenter().isEmpty() );
    7543                 :          1 :   QCOMPARE( QgsPoint( 16, -8 ), t10.orthocenter() );
    7544                 :          1 :   QCOMPARE( QgsPoint( 0, 5 ), t7.orthocenter() );
    7545                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( 13, 11.7321 ), t9.orthocenter(), 0.0001 );
    7546                 :            : 
    7547                 :            :   // circumscribed circle
    7548                 :          1 :   QVERIFY( QgsTriangle().circumscribedCenter().isEmpty() );
    7549                 :          1 :   QCOMPARE( 0.0, QgsTriangle().circumscribedRadius() );
    7550                 :          1 :   QCOMPARE( QgsPoint( 2.5, 2.5 ), t7.circumscribedCenter() );
    7551                 :          1 :   QGSCOMPARENEAR( 3.5355, t7.circumscribedRadius(), 0.0001 );
    7552                 :          1 :   QCOMPARE( QgsPoint( 23, 9 ), t10.circumscribedCenter() );
    7553                 :          1 :   QGSCOMPARENEAR( 7.6158, t10.circumscribedRadius(), 0.0001 );
    7554                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( 13, 11.7321 ), t9.circumscribedCenter(), 0.0001 );
    7555                 :          1 :   QGSCOMPARENEAR( 3.4641, t9.circumscribedRadius(), 0.0001 );
    7556                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( 13, 11.7321 ), t9.circumscribedCircle().center(), 0.0001 );
    7557                 :          1 :   QGSCOMPARENEAR( 3.4641, t9.circumscribedCircle().radius(), 0.0001 );
    7558                 :            : 
    7559                 :            :   // inscribed circle
    7560                 :          1 :   QVERIFY( QgsTriangle().inscribedCenter().isEmpty() );
    7561                 :          1 :   QCOMPARE( 0.0, QgsTriangle().inscribedRadius() );
    7562                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( 1.4645, 3.5355 ), t7.inscribedCenter(), 0.001 );
    7563                 :          1 :   QGSCOMPARENEAR( 1.4645, t7.inscribedRadius(), 0.0001 );
    7564                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( 20.4433, 3.0701 ), t10.inscribedCenter(), 0.001 );
    7565                 :          1 :   QGSCOMPARENEAR( 1.0701, t10.inscribedRadius(), 0.0001 );
    7566                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( 13, 11.7321 ), t9.inscribedCenter(), 0.0001 );
    7567                 :          1 :   QGSCOMPARENEAR( 1.7321, t9.inscribedRadius(), 0.0001 );
    7568                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( 13, 11.7321 ), t9.inscribedCircle().center(), 0.0001 );
    7569                 :          1 :   QGSCOMPARENEAR( 1.7321, t9.inscribedCircle().radius(), 0.0001 );
    7570                 :            : 
    7571                 :            :   // medians
    7572                 :          1 :   QVector<QgsLineString> med = QgsTriangle().medians();
    7573                 :          1 :   QVERIFY( med.isEmpty() );
    7574                 :          1 :   med = t7.medians();
    7575                 :          1 :   QCOMPARE( med.at( 0 ).pointN( 0 ), t7.vertexAt( 0 ) );
    7576                 :          1 :   QGSCOMPARENEARPOINT( med.at( 0 ).pointN( 1 ), QgsPoint( 2.5, 5 ), 0.0001 );
    7577                 :          1 :   QCOMPARE( med.at( 1 ).pointN( 0 ), t7.vertexAt( 1 ) );
    7578                 :          1 :   QGSCOMPARENEARPOINT( med.at( 1 ).pointN( 1 ), QgsPoint( 2.5, 2.5 ), 0.0001 );
    7579                 :          1 :   QCOMPARE( med.at( 2 ).pointN( 0 ), t7.vertexAt( 2 ) );
    7580                 :          1 :   QGSCOMPARENEARPOINT( med.at( 2 ).pointN( 1 ), QgsPoint( 0, 2.5 ), 0.0001 );
    7581                 :          1 :   med.clear();
    7582                 :            : 
    7583                 :          1 :   med = t10.medians();
    7584                 :          1 :   QCOMPARE( med.at( 0 ).pointN( 0 ), t10.vertexAt( 0 ) );
    7585                 :          1 :   QGSCOMPARENEARPOINT( med.at( 0 ).pointN( 1 ), QgsPoint( 21, 4 ), 0.0001 );
    7586                 :          1 :   QCOMPARE( med.at( 1 ).pointN( 0 ), t10.vertexAt( 1 ) );
    7587                 :          1 :   QGSCOMPARENEARPOINT( med.at( 1 ).pointN( 1 ), QgsPoint( 23, 2 ), 0.0001 );
    7588                 :          1 :   QCOMPARE( med.at( 2 ).pointN( 0 ), t10.vertexAt( 2 ) );
    7589                 :          1 :   QGSCOMPARENEARPOINT( med.at( 2 ).pointN( 1 ), QgsPoint( 18, 4 ), 0.0001 );
    7590                 :          1 :   med.clear();
    7591                 :          1 :   alt.clear();
    7592                 :            : 
    7593                 :          1 :   med = t9.medians();
    7594                 :          1 :   alt = t9.altitudes();
    7595                 :          1 :   QGSCOMPARENEARPOINT( med.at( 0 ).pointN( 0 ), alt.at( 0 ).pointN( 0 ), 0.0001 );
    7596                 :          1 :   QGSCOMPARENEARPOINT( med.at( 0 ).pointN( 1 ), alt.at( 0 ).pointN( 1 ), 0.0001 );
    7597                 :          1 :   QGSCOMPARENEARPOINT( med.at( 1 ).pointN( 0 ), alt.at( 1 ).pointN( 0 ), 0.0001 );
    7598                 :          1 :   QGSCOMPARENEARPOINT( med.at( 1 ).pointN( 1 ), alt.at( 1 ).pointN( 1 ), 0.0001 );
    7599                 :          1 :   QGSCOMPARENEARPOINT( med.at( 2 ).pointN( 0 ), alt.at( 2 ).pointN( 0 ), 0.0001 );
    7600                 :          1 :   QGSCOMPARENEARPOINT( med.at( 2 ).pointN( 1 ), alt.at( 2 ).pointN( 1 ), 0.0001 );
    7601                 :            : 
    7602                 :            :   // medial
    7603                 :          1 :   QCOMPARE( QgsTriangle().medial(), QgsTriangle() );
    7604                 :          1 :   QCOMPARE( t7.medial(), QgsTriangle( QgsPoint( 0, 2.5 ), QgsPoint( 2.5, 5 ), QgsPoint( 2.5, 2.5 ) ) );
    7605                 :          1 :   QCOMPARE( t9.medial(), QgsTriangle( QgsGeometryUtils::midpoint( t9.vertexAt( 0 ), t9.vertexAt( 1 ) ),
    7606                 :            :                                       QgsGeometryUtils::midpoint( t9.vertexAt( 1 ), t9.vertexAt( 2 ) ),
    7607                 :            :                                       QgsGeometryUtils::midpoint( t9.vertexAt( 2 ), t9.vertexAt( 0 ) ) ) );
    7608                 :            : 
    7609                 :            :   // bisectors
    7610                 :          1 :   QVector<QgsLineString> bis = QgsTriangle().bisectors();
    7611                 :          1 :   QVERIFY( bis.isEmpty() );
    7612                 :          1 :   bis = t7.bisectors();
    7613                 :          1 :   QCOMPARE( bis.at( 0 ).pointN( 0 ), t7.vertexAt( 0 ) );
    7614                 :          1 :   QGSCOMPARENEARPOINT( bis.at( 0 ).pointN( 1 ), QgsPoint( 2.0711, 5 ), 0.0001 );
    7615                 :          1 :   QCOMPARE( bis.at( 1 ).pointN( 0 ), t7.vertexAt( 1 ) );
    7616                 :          1 :   QGSCOMPARENEARPOINT( bis.at( 1 ).pointN( 1 ), QgsPoint( 2.5, 2.5 ), 0.0001 );
    7617                 :          1 :   QCOMPARE( bis.at( 2 ).pointN( 0 ), t7.vertexAt( 2 ) );
    7618                 :          1 :   QGSCOMPARENEARPOINT( bis.at( 2 ).pointN( 1 ), QgsPoint( 0, 2.9289 ), 0.0001 );
    7619                 :            : 
    7620                 :            :   // "deleted" method
    7621                 :          1 :   ext.reset( new QgsLineString() );
    7622                 :          1 :   QgsTriangle t11( QgsPoint( 0, 0 ), QgsPoint( 100, 100 ), QgsPoint( 0, 200 ) );
    7623                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 5, 5 )
    7624                 :          1 :                   << QgsPoint( 50, 50 ) << QgsPoint( 0, 25 )
    7625                 :          1 :                   << QgsPoint( 5, 5 ) );
    7626                 :          1 :   t11.addInteriorRing( ext.release() );
    7627                 :          1 :   QCOMPARE( t11.asWkt(), QString( "Triangle ((0 0, 100 100, 0 200, 0 0))" ) );
    7628                 :            : 
    7629                 :            :   /* QList<QgsCurve *> lc;
    7630                 :            :    lc.append(ext);
    7631                 :            :    t11.setInteriorRings( lc );
    7632                 :            :    QCOMPARE( t11.asWkt(), QString( "Triangle ((0 0, 100 100, 0 200, 0 0))" ) );*/
    7633                 :            : 
    7634                 :          1 :   QgsVertexId id( 0, 0, 1 );
    7635                 :          1 :   QVERIFY( !t11.deleteVertex( id ) );
    7636                 :          1 :   QCOMPARE( t11.asWkt(), QString( "Triangle ((0 0, 100 100, 0 200, 0 0))" ) );
    7637                 :          1 :   QVERIFY( !t11.insertVertex( id, QgsPoint( 5, 5 ) ) );
    7638                 :          1 :   QCOMPARE( t11.asWkt(), QString( "Triangle ((0 0, 100 100, 0 200, 0 0))" ) );
    7639                 :            : 
    7640                 :            :   //move vertex
    7641                 :          1 :   QgsPoint pt1( 5, 5 );
    7642                 :            :   // invalid part
    7643                 :          1 :   id.part = -1;
    7644                 :          1 :   QVERIFY( !t11.moveVertex( id, pt1 ) );
    7645                 :          1 :   id.part = 1;
    7646                 :          1 :   QVERIFY( !t11.moveVertex( id, pt1 ) );
    7647                 :            :   // invalid ring
    7648                 :          1 :   id.part = 0;
    7649                 :          1 :   id.ring = -1;
    7650                 :          1 :   QVERIFY( !t11.moveVertex( id, pt1 ) );
    7651                 :          1 :   id.ring = 1;
    7652                 :          1 :   QVERIFY( !t11.moveVertex( id, pt1 ) );
    7653                 :          1 :   id.ring = 0;
    7654                 :          1 :   id.vertex = -1;
    7655                 :          1 :   QVERIFY( !t11.moveVertex( id, pt1 ) );
    7656                 :          1 :   id.vertex = 5;
    7657                 :          1 :   QVERIFY( !t11.moveVertex( id, pt1 ) );
    7658                 :            : 
    7659                 :            :   // valid vertex
    7660                 :          1 :   id.vertex = 0;
    7661                 :          1 :   QVERIFY( t11.moveVertex( id, pt1 ) );
    7662                 :          1 :   QCOMPARE( t11.asWkt(), QString( "Triangle ((5 5, 100 100, 0 200, 5 5))" ) );
    7663                 :          1 :   pt1 = QgsPoint( 0, 0 );
    7664                 :          1 :   QVERIFY( t11.moveVertex( id, pt1 ) );
    7665                 :          1 :   QCOMPARE( t11.asWkt(), QString( "Triangle ((0 0, 100 100, 0 200, 0 0))" ) );
    7666                 :          1 :   id.vertex = 4;
    7667                 :          1 :   pt1 = QgsPoint( 5, 5 );
    7668                 :          1 :   QVERIFY( t11.moveVertex( id, pt1 ) );
    7669                 :          1 :   QCOMPARE( t11.asWkt(), QString( "Triangle ((5 5, 100 100, 0 200, 5 5))" ) );
    7670                 :          1 :   pt1 = QgsPoint( 0, 0 );
    7671                 :          1 :   QVERIFY( t11.moveVertex( id, pt1 ) );
    7672                 :          1 :   QCOMPARE( t11.asWkt(), QString( "Triangle ((0 0, 100 100, 0 200, 0 0))" ) );
    7673                 :          1 :   id.vertex = 1;
    7674                 :          1 :   pt1 = QgsPoint( 5, 5 );
    7675                 :          1 :   QVERIFY( t11.moveVertex( id, pt1 ) );
    7676                 :          1 :   QCOMPARE( t11.asWkt(), QString( "Triangle ((0 0, 5 5, 0 200, 0 0))" ) );
    7677                 :            :   // colinear
    7678                 :          1 :   pt1 = QgsPoint( 0, 100 );
    7679                 :          1 :   QVERIFY( t11.moveVertex( id, pt1 ) );
    7680                 :          1 :   pt1 = QgsPoint( 5, 5 );
    7681                 :          1 :   QVERIFY( t11.moveVertex( id, pt1 ) );
    7682                 :            :   // duplicate point
    7683                 :          1 :   pt1 = QgsPoint( 0, 0 );
    7684                 :          1 :   QVERIFY( t11.moveVertex( id, pt1 ) );
    7685                 :          1 :   pt1 = QgsPoint( 5, 5 );
    7686                 :          1 :   QVERIFY( t11.moveVertex( id, pt1 ) );
    7687                 :            : 
    7688                 :            :   //toCurveType
    7689                 :          1 :   QgsTriangle t12( QgsPoint( 7, 4 ), QgsPoint( 13, 3 ), QgsPoint( 9, 6 ) );
    7690                 :          1 :   std::unique_ptr< QgsCurvePolygon > curveType( t12.toCurveType() );
    7691                 :          1 :   QCOMPARE( curveType->wkbType(), QgsWkbTypes::CurvePolygon );
    7692                 :          1 :   QCOMPARE( curveType->exteriorRing()->numPoints(), 4 );
    7693                 :          1 :   QCOMPARE( curveType->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( 7, 4 ) );
    7694                 :          1 :   QCOMPARE( curveType->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( 13, 3 ) );
    7695                 :          1 :   QCOMPARE( curveType->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( 9, 6 ) );
    7696                 :          1 :   QCOMPARE( curveType->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 3 ) ), QgsPoint( 7, 4 ) );
    7697                 :          1 :   QCOMPARE( curveType->numInteriorRings(), 0 );
    7698                 :            : 
    7699                 :            :   // boundary
    7700                 :          1 :   QVERIFY( !QgsTriangle().boundary() );
    7701                 :          1 :   std::unique_ptr< QgsCurve > boundary( QgsTriangle( QgsPoint( 7, 4 ), QgsPoint( 13, 3 ), QgsPoint( 9, 6 ) ).boundary() );
    7702                 :          1 :   QCOMPARE( boundary->wkbType(), QgsWkbTypes::LineString );
    7703                 :          1 :   QCOMPARE( boundary->numPoints(), 4 );
    7704                 :          1 :   QCOMPARE( boundary->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( 7, 4 ) );
    7705                 :          1 :   QCOMPARE( boundary->vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( 13, 3 ) );
    7706                 :          1 :   QCOMPARE( boundary->vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( 9, 6 ) );
    7707                 :          1 :   QCOMPARE( boundary->vertexAt( QgsVertexId( 0, 0, 3 ) ), QgsPoint( 7, 4 ) );
    7708                 :            : 
    7709                 :            :   // cast
    7710                 :          1 :   QgsTriangle pCast;
    7711                 :          1 :   QVERIFY( QgsPolygon().cast( &pCast ) );
    7712                 :          1 :   QgsTriangle pCast2( QgsPoint( 7, 4 ), QgsPoint( 13, 3 ), QgsPoint( 9, 6 ) );
    7713                 :          1 :   QVERIFY( QgsPolygon().cast( &pCast2 ) );
    7714                 :          1 : }
    7715                 :            : 
    7716                 :          1 : void TestQgsGeometry::ellipse()
    7717                 :            : {
    7718                 :            :   //test constructors
    7719                 :          1 :   QgsEllipse elp1;
    7720                 :          1 :   QVERIFY( elp1.center().isEmpty() );
    7721                 :          1 :   QCOMPARE( elp1.semiMajorAxis(), 0.0 );
    7722                 :          1 :   QCOMPARE( elp1.semiMinorAxis(), 0.0 );
    7723                 :          1 :   QCOMPARE( elp1.azimuth(), 90.0 );
    7724                 :          1 :   QVERIFY( elp1.isEmpty() );
    7725                 :            : 
    7726                 :          1 :   QgsEllipse elp2( QgsPoint( 5, 10 ), 3, 2 );
    7727                 :          1 :   QVERIFY( elp2.center() == QgsPoint( 5, 10 ) );
    7728                 :          1 :   QCOMPARE( elp2.semiMajorAxis(), 3.0 );
    7729                 :          1 :   QCOMPARE( elp2.semiMinorAxis(), 2.0 );
    7730                 :          1 :   QCOMPARE( elp2.azimuth(), 90.0 );
    7731                 :          1 :   QVERIFY( !elp2.isEmpty() );
    7732                 :            : 
    7733                 :          1 :   QgsEllipse elp3( QgsPoint( 5, 10 ), 3, 2, 45 );
    7734                 :          1 :   QVERIFY( elp3.center() == QgsPoint( 5, 10 ) );
    7735                 :          1 :   QCOMPARE( elp3.semiMajorAxis(), 3.0 );
    7736                 :          1 :   QCOMPARE( elp3.semiMinorAxis(), 2.0 );
    7737                 :          1 :   QCOMPARE( elp3.azimuth(), 45.0 );
    7738                 :          1 :   QVERIFY( !elp3.isEmpty() );
    7739                 :            : 
    7740                 :          1 :   QgsEllipse elp4( QgsPoint( 5, 10 ), 2, 3, 45 );
    7741                 :          1 :   QVERIFY( elp4.center() == QgsPoint( 5, 10 ) );
    7742                 :          1 :   QCOMPARE( elp4.semiMajorAxis(), 3.0 );
    7743                 :          1 :   QCOMPARE( elp4.semiMinorAxis(), 2.0 );
    7744                 :          1 :   QCOMPARE( elp4.azimuth(), 135.0 );
    7745                 :          1 :   QVERIFY( !elp4.isEmpty() );
    7746                 :            : 
    7747                 :            :   //test toString
    7748                 :          1 :   QCOMPARE( elp1.toString(), QString( "Empty" ) );
    7749                 :          1 :   QCOMPARE( elp2.toString(), QString( "Ellipse (Center: Point (5 10), Semi-Major Axis: 3, Semi-Minor Axis: 2, Azimuth: 90)" ) );
    7750                 :          1 :   QCOMPARE( elp3.toString(), QString( "Ellipse (Center: Point (5 10), Semi-Major Axis: 3, Semi-Minor Axis: 2, Azimuth: 45)" ) );
    7751                 :          1 :   QCOMPARE( elp4.toString(), QString( "Ellipse (Center: Point (5 10), Semi-Major Axis: 3, Semi-Minor Axis: 2, Azimuth: 135)" ) );
    7752                 :            : 
    7753                 :            :   //test equality operator
    7754                 :          1 :   QCOMPARE( QgsEllipse().isEmpty(), QgsEllipse( QgsPoint(), 0, 0, 90 ).isEmpty() );
    7755                 :          1 :   QVERIFY( !( QgsEllipse() == QgsEllipse( QgsPoint( 0, 0 ), 0, 0, 0.0005 ) ) );
    7756                 :          1 :   QVERIFY( elp2 == QgsEllipse( QgsPoint( 5, 10 ), 2, 3, 0 ) );
    7757                 :          1 :   QVERIFY( elp2 != elp3 );
    7758                 :          1 :   QVERIFY( elp3 != elp4 );
    7759                 :          1 :   QVERIFY( elp4 == QgsEllipse( QgsPoint( 5, 10 ), 3, 2, 90 + 45 ) );
    7760                 :            : 
    7761                 :            :   //test setter and getter
    7762                 :          1 :   elp1.setAzimuth( 45 );
    7763                 :          1 :   QCOMPARE( elp1.azimuth(), 45.0 );
    7764                 :            : 
    7765                 :          1 :   elp1.setSemiMajorAxis( 50 );
    7766                 :          1 :   QCOMPARE( elp1.semiMajorAxis(), 50.0 );
    7767                 :            : 
    7768                 :            :   // axis_b > axis_a
    7769                 :          1 :   elp1.setSemiMinorAxis( 70 );
    7770                 :          1 :   QCOMPARE( elp1.semiMajorAxis(), 70.0 );
    7771                 :          1 :   QCOMPARE( elp1.semiMinorAxis(), 50.0 );
    7772                 :            :   // axis_b < axis_a
    7773                 :          1 :   elp1.setSemiMinorAxis( 3 );
    7774                 :          1 :   QCOMPARE( elp1.semiMinorAxis(), 3.0 );
    7775                 :          1 :   QCOMPARE( elp1.semiMajorAxis(), 70.0 );
    7776                 :            : 
    7777                 :          1 :   elp1.setSemiMajorAxis( 2 );
    7778                 :          1 :   QCOMPARE( elp1.semiMinorAxis(), 2.0 );
    7779                 :          1 :   QCOMPARE( elp1.semiMajorAxis(), 3.0 );
    7780                 :            : 
    7781                 :          1 :   elp1.setCenter( QgsPoint( 5, 10 ) );
    7782                 :          1 :   QVERIFY( elp1.center() == QgsPoint( 5, 10 ) );
    7783                 :          1 :   QVERIFY( elp1.rcenter() == QgsPoint( 5, 10 ) );
    7784                 :          1 :   elp1.rcenter() = QgsPoint( 25, 310 );
    7785                 :          1 :   QVERIFY( elp1.center() == QgsPoint( 25, 310 ) );
    7786                 :            : 
    7787                 :            :   //test "alt" constructors
    7788                 :            :   // fromExtent
    7789                 :          1 :   QgsEllipse elp_alt = QgsEllipse( QgsPoint( 2.5, 5 ), 2.5, 5 );
    7790                 :          1 :   QVERIFY( QgsEllipse().fromExtent( QgsPoint( 0, 0 ), QgsPoint( 5, 10 ) ) == elp_alt );
    7791                 :          1 :   QVERIFY( QgsEllipse().fromExtent( QgsPoint( 5, 10 ), QgsPoint( 0, 0 ) ) == elp_alt );
    7792                 :          1 :   QVERIFY( QgsEllipse().fromExtent( QgsPoint( 5, 0 ), QgsPoint( 0, 10 ) ) == elp_alt );
    7793                 :          1 :   QVERIFY( QgsEllipse().fromExtent( QgsPoint( -5, 0 ), QgsPoint( 0, 10 ) ) != elp_alt );
    7794                 :            :   // fromCenterPoint
    7795                 :          1 :   QVERIFY( QgsEllipse().fromCenterPoint( QgsPoint( 2.5, 5 ), QgsPoint( 5, 10 ) ) == elp_alt );
    7796                 :          1 :   QVERIFY( QgsEllipse().fromCenterPoint( QgsPoint( 2.5, 5 ), QgsPoint( -0, 0 ) ) == elp_alt );
    7797                 :          1 :   QVERIFY( QgsEllipse().fromCenterPoint( QgsPoint( 2.5, 5 ), QgsPoint( 0, -10 ) ) != elp_alt );
    7798                 :            :   // fromCenter2Points
    7799                 :          1 :   QVERIFY( QgsEllipse().fromCenter2Points( QgsPoint( 2.5, 5 ), QgsPoint( 2.5, 0 ), QgsPoint( 7.5, 5 ) ) ==
    7800                 :            :            QgsEllipse( QgsPoint( 2.5, 5 ), 5, 5, 180 ) );
    7801                 :          1 :   QVERIFY( QgsEllipse().fromCenter2Points( QgsPoint( 2.5, 5 ), QgsPoint( 2.5, 7.5 ), QgsPoint( 7.5, 5 ) ) != elp_alt ); //same ellipse with different azimuth
    7802                 :          1 :   QVERIFY( QgsEllipse().fromCenter2Points( QgsPoint( 2.5, 5 ), QgsPoint( 2.5, 2.5 ), QgsPoint( 7.5, 5 ) ) != elp_alt ); //same ellipse with different azimuth
    7803                 :          1 :   QVERIFY( QgsEllipse().fromCenter2Points( QgsPoint( 2.5, 5 ), QgsPoint( 2.5, 0 ), QgsPoint( 5, 5 ) ) == elp_alt );
    7804                 :          1 :   QVERIFY( QgsEllipse().fromCenter2Points( QgsPoint( 5, 10 ), QgsPoint( 5, 10 ).project( 3, 45 ), QgsPoint( 5, 10 ).project( 2, 90 + 45 ) ) ==
    7805                 :            :            QgsEllipse( QgsPoint( 5, 10 ), 3, 2, 45 ) );
    7806                 :            : 
    7807                 :            :   // fromFoci
    7808                 :            :   // horizontal
    7809                 :          1 :   QgsEllipse elp_hor = QgsEllipse().fromFoci( QgsPoint( -4, 0 ), QgsPoint( 4, 0 ), QgsPoint( 0, 4 ) );
    7810                 :          1 :   QVERIFY( QgsEllipse( QgsPoint( 0, 0 ), std::sqrt( 32.0 ), std::sqrt( 16.0 ), 90.0 ) == elp_hor );
    7811                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( 4, 0 ), elp_hor.foci().at( 0 ), 1e-8 );
    7812                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( -4, 0 ), elp_hor.foci().at( 1 ), 1e-8 );
    7813                 :          1 :   elp_hor = QgsEllipse().fromFoci( QgsPoint( 4, 0 ), QgsPoint( -4, 0 ), QgsPoint( 0, 4 ) );
    7814                 :          1 :   QVERIFY( QgsEllipse( QgsPoint( 0, 0 ), std::sqrt( 32.0 ), std::sqrt( 16.0 ), 270.0 ) == elp_hor );
    7815                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( -4, 0 ), elp_hor.foci().at( 0 ), 1e-8 );
    7816                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( 4, 0 ), elp_hor.foci().at( 1 ), 1e-8 );
    7817                 :            : 
    7818                 :            :   // vertical
    7819                 :          1 :   QgsEllipse elp_ver = QgsEllipse().fromFoci( QgsPoint( 45, -15 ), QgsPoint( 45, 10 ), QgsPoint( 55, 0 ) );
    7820                 :          1 :   QVERIFY( QgsEllipse( QgsPoint( 45, -2.5 ), 16.084946, 10.123017725, 0.0 ) == elp_ver );
    7821                 :          1 :   elp_ver = QgsEllipse().fromFoci( QgsPoint( 45, 10 ), QgsPoint( 45, -15 ), QgsPoint( 55, 0 ) );
    7822                 :          1 :   QVERIFY( QgsEllipse( QgsPoint( 45, -2.5 ), 16.084946, 10.123017725, 180.0 ) == elp_ver );
    7823                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( 45, -15 ), elp_ver.foci().at( 0 ), 1e-8 );
    7824                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( 45, 10 ), elp_ver.foci().at( 1 ), 1e-8 );
    7825                 :            :   // oriented
    7826                 :            :   // first quadrant
    7827                 :          1 :   QgsEllipse elp_ori = QgsEllipse().fromFoci( QgsPoint( 10, 10 ), QgsPoint( 25, 20 ), QgsPoint( 15, 20 ) );
    7828                 :          1 :   QVERIFY( QgsEllipse( QgsPoint( 17.5, 15.0 ), 10.5901699437, 5.55892970251, 90.0 - 33.690067526 ) == elp_ori );
    7829                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( 25, 20 ), elp_ori.foci().at( 0 ), 1e-8 );
    7830                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( 10, 10 ), elp_ori.foci().at( 1 ), 1e-8 );
    7831                 :            :   // second quadrant
    7832                 :          1 :   elp_ori = QgsEllipse().fromFoci( QgsPoint( 10, 10 ), QgsPoint( 5, 20 ), QgsPoint( 15, 20 ) );
    7833                 :          1 :   QVERIFY( QgsEllipse( QgsPoint( 7.5, 15.0 ), 10.5901699437, 8.99453719974, 360 - 26.56505117 ) == elp_ori );
    7834                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( 5, 20 ), elp_ori.foci().at( 0 ), 1e-8 );
    7835                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( 10, 10 ), elp_ori.foci().at( 1 ), 1e-8 );
    7836                 :            :   // third quadrant
    7837                 :          1 :   elp_ori = QgsEllipse().fromFoci( QgsPoint( 10, 10 ), QgsPoint( 5, -5 ), QgsPoint( 15, 20 ) );
    7838                 :          1 :   QVERIFY( QgsEllipse( QgsPoint( 7.5, 2.5 ), 19.0530819616, 17.3355107289893, 198.434948822922 ) == elp_ori );
    7839                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( 10, 10 ), elp_ori.foci().at( 1 ), 1e-8 );
    7840                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( 5, -5 ), elp_ori.foci().at( 0 ), 1e-8 );
    7841                 :            :   // fourth quadrant
    7842                 :          1 :   elp_ori = QgsEllipse().fromFoci( QgsPoint( 10, 10 ), QgsPoint( 25, -5 ), QgsPoint( 15, 20 ) );
    7843                 :          1 :   QVERIFY( QgsEllipse( QgsPoint( 17.5, 2.5 ), 19.0530819616, 15.82782146, 135 ) == elp_ori );
    7844                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( 25, -5 ), elp_ori.foci().at( 0 ), 1e-8 );
    7845                 :          1 :   QGSCOMPARENEARPOINT( QgsPoint( 10, 10 ), elp_ori.foci().at( 1 ), 1e-8 );
    7846                 :            : 
    7847                 :            :   // test quadrant
    7848                 :          1 :   QgsEllipse elpq( QgsPoint( 5, 10 ), 3, 2, 45 );
    7849                 :          1 :   QgsPointSequence q = elpq.quadrant();
    7850                 :          1 :   QGSCOMPARENEARPOINT( q.at( 0 ), QgsPoint( 7.1213, 12.1213 ), 0.001 );
    7851                 :          1 :   QGSCOMPARENEARPOINT( q.at( 3 ), QgsPoint( 3.5858, 11.4142 ), 0.001 );
    7852                 :          1 :   QGSCOMPARENEARPOINT( q.at( 2 ), QgsPoint( 2.8787, 7.8787 ), 0.001 );
    7853                 :          1 :   QGSCOMPARENEARPOINT( q.at( 1 ), QgsPoint( 6.4142, 8.5858 ), 0.001 );
    7854                 :            : 
    7855                 :          1 :   elpq = QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 90 );
    7856                 :          1 :   q.clear();
    7857                 :          1 :   q = elpq.quadrant();
    7858                 :          1 :   QCOMPARE( q.at( 3 ), QgsPoint( 0, 2 ) );
    7859                 :          1 :   QCOMPARE( q.at( 0 ), QgsPoint( 5, 0 ) );
    7860                 :          1 :   QCOMPARE( q.at( 1 ), QgsPoint( 0, -2 ) );
    7861                 :          1 :   QCOMPARE( q.at( 2 ), QgsPoint( -5, 0 ) );
    7862                 :            : 
    7863                 :          1 :   elpq = QgsEllipse( QgsPoint( QgsWkbTypes::PointZM, 0, 0, 123, 321 ), 5, 2, 0 );
    7864                 :          1 :   q.clear();
    7865                 :          1 :   q = elpq.quadrant();
    7866                 :          1 :   QCOMPARE( q.at( 0 ), QgsPoint( QgsWkbTypes::PointZM, 0, 5, 123, 321 ) );
    7867                 :          1 :   QCOMPARE( q.at( 3 ), QgsPoint( QgsWkbTypes::PointZM, -2, 0, 123, 321 ) );
    7868                 :          1 :   QCOMPARE( q.at( 2 ), QgsPoint( QgsWkbTypes::PointZM, 0, -5, 123, 321 ) );
    7869                 :          1 :   QCOMPARE( q.at( 1 ), QgsPoint( QgsWkbTypes::PointZM, 2, 0, 123, 321 ) );
    7870                 :            : 
    7871                 :          1 :   elpq = QgsEllipse( QgsPoint( 0, 0 ), 2.5, 2, 315 );
    7872                 :          1 :   q.clear();
    7873                 :          1 :   q = elpq.quadrant();
    7874                 :          1 :   QGSCOMPARENEARPOINT( q.at( 1 ), QgsPoint( 1.4142, 1.4142 ), 0.001 );
    7875                 :          1 :   QGSCOMPARENEARPOINT( q.at( 2 ), QgsPoint( 1.7678, -1.7678 ), 0.001 );
    7876                 :          1 :   QGSCOMPARENEARPOINT( q.at( 3 ), QgsPoint( -1.4142, -1.4142 ), 0.001 );
    7877                 :          1 :   QGSCOMPARENEARPOINT( q.at( 0 ), QgsPoint( -1.7678, 1.7678 ), 0.001 );
    7878                 :            : 
    7879                 :          1 :   elpq = QgsEllipse( QgsPoint( 0, 0 ), 5, 2.5, 45 );
    7880                 :          1 :   q.clear();
    7881                 :          1 :   q = elpq.quadrant();
    7882                 :          1 :   QGSCOMPARENEARPOINT( q.at( 3 ), QgsPoint( -1.7678, 1.7678 ), 0.001 );
    7883                 :          1 :   QGSCOMPARENEARPOINT( q.at( 0 ), QgsPoint( 3.5355, 3.5355 ), 0.001 );
    7884                 :          1 :   QGSCOMPARENEARPOINT( q.at( 1 ), QgsPoint( 1.7678, -1.7678 ), 0.001 );
    7885                 :          1 :   QGSCOMPARENEARPOINT( q.at( 2 ), QgsPoint( -3.5355, -3.5355 ), 0.001 );
    7886                 :            : 
    7887                 :            :   //test conversion
    7888                 :            :   // points
    7889                 :          1 :   QgsPointSequence pts;
    7890                 :          1 :   pts = QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 0 ).points( 4 );
    7891                 :          1 :   q = QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 0 ).quadrant();
    7892                 :          1 :   QCOMPARE( pts.length(), 4 );
    7893                 :          1 :   QGSCOMPARENEARPOINT( q.at( 0 ), pts.at( 0 ), 2 );
    7894                 :          1 :   QGSCOMPARENEARPOINT( q.at( 1 ), pts.at( 1 ), 2 );
    7895                 :          1 :   QGSCOMPARENEARPOINT( q.at( 2 ), pts.at( 2 ), 2 );
    7896                 :          1 :   QGSCOMPARENEARPOINT( q.at( 3 ), pts.at( 3 ), 2 );
    7897                 :            : 
    7898                 :          1 :   QVERIFY( QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 0 ).points( 2 ).isEmpty() ); // segments too low
    7899                 :            : 
    7900                 :            :   // linestring
    7901                 :          1 :   std::unique_ptr< QgsLineString > l( new QgsLineString() );
    7902                 :            : 
    7903                 :          1 :   l.reset( QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 0 ).toLineString( 2 ) );
    7904                 :          1 :   QVERIFY( l->isEmpty() ); // segments too low
    7905                 :            : 
    7906                 :          1 :   l.reset( QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 0 ).toLineString( 4 ) );
    7907                 :          1 :   QCOMPARE( l->numPoints(), 5 ); // closed linestring
    7908                 :          1 :   QgsPointSequence pts_l;
    7909                 :          1 :   l->points( pts_l );
    7910                 :          1 :   pts_l.pop_back();
    7911                 :          1 :   QCOMPARE( pts, pts_l );
    7912                 :            : 
    7913                 :            :   // polygon
    7914                 :          1 :   std::unique_ptr< QgsPolygon > p1( new QgsPolygon() );
    7915                 :            : 
    7916                 :          1 :   p1.reset( QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 0 ).toPolygon( 2 ) );
    7917                 :          1 :   QVERIFY( p1->isEmpty() ); // segments too low
    7918                 :            : 
    7919                 :          1 :   p1.reset( QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 0 ).toPolygon( 4 ) );
    7920                 :          1 :   q = QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 0 ).quadrant();
    7921                 :          1 :   QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 0 ) ), q.at( 0 ) );
    7922                 :          1 :   QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 1 ) ), q.at( 1 ) );
    7923                 :          1 :   QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 2 ) ), q.at( 2 ) );
    7924                 :          1 :   QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 3 ) ), q.at( 3 ) );
    7925                 :          1 :   QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 4 ) ), q.at( 0 ) );
    7926                 :          1 :   QCOMPARE( 0, p1->numInteriorRings() );
    7927                 :          1 :   QCOMPARE( 5, p1->exteriorRing()->numPoints() );
    7928                 :            : 
    7929                 :          1 :   p1.reset( QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 90 ).toPolygon( 4 ) );
    7930                 :          1 :   q = QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 90 ).quadrant();
    7931                 :          1 :   QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 0 ) ), q.at( 0 ) );
    7932                 :          1 :   QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 1 ) ), q.at( 1 ) );
    7933                 :          1 :   QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 2 ) ), q.at( 2 ) );
    7934                 :          1 :   QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 3 ) ), q.at( 3 ) );
    7935                 :          1 :   QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 4 ) ), q.at( 0 ) );
    7936                 :          1 :   QCOMPARE( 0, p1->numInteriorRings() );
    7937                 :          1 :   QCOMPARE( 5, p1->exteriorRing()->numPoints() );
    7938                 :            : 
    7939                 :          1 :   p1.reset( elpq.toPolygon( 4 ) );
    7940                 :          1 :   q = elpq.quadrant();
    7941                 :          1 :   QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 0 ) ), q.at( 0 ) );
    7942                 :          1 :   QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 1 ) ), q.at( 1 ) );
    7943                 :          1 :   QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 2 ) ), q.at( 2 ) );
    7944                 :          1 :   QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 3 ) ), q.at( 3 ) );
    7945                 :          1 :   QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 4 ) ), q.at( 0 ) );
    7946                 :          1 :   QCOMPARE( 0, p1->numInteriorRings() );
    7947                 :          1 :   QCOMPARE( 5, p1->exteriorRing()->numPoints() );
    7948                 :            : 
    7949                 :            :   // oriented bounding box
    7950                 :          1 :   std::unique_ptr< QgsPolygon > ombb( QgsEllipse().orientedBoundingBox() );
    7951                 :          1 :   QVERIFY( ombb->isEmpty() );
    7952                 :            : 
    7953                 :          1 :   elpq = QgsEllipse( QgsPoint( 0, 0 ), 5, 2 );
    7954                 :          1 :   ombb.reset( new QgsPolygon() );
    7955                 :          1 :   QgsLineString *ext = new QgsLineString();
    7956                 :          1 :   ext->setPoints( QgsPointSequence() << QgsPoint( 5, 2 ) << QgsPoint( 5, -2 ) << QgsPoint( -5, -2 ) << QgsPoint( -5, 2 ) );
    7957                 :          1 :   ombb->setExteriorRing( ext );
    7958                 :          1 :   std::unique_ptr< QgsPolygon >ombb2( elpq.orientedBoundingBox() );
    7959                 :          1 :   QCOMPARE( ombb->asWkt( 2 ), ombb2->asWkt( 2 ) );
    7960                 :            : 
    7961                 :          1 :   elpq = QgsEllipse( QgsPoint( 0, 0 ), 5, 2.5, 45 );
    7962                 :          1 :   ombb.reset( elpq.orientedBoundingBox() );
    7963                 :          1 :   QGSCOMPARENEARPOINT( ombb->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( 1.7678, 5.3033 ), 0.0001 );
    7964                 :          1 :   QGSCOMPARENEARPOINT( ombb->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( 5.3033, 1.7678 ), 0.0001 );
    7965                 :          1 :   QGSCOMPARENEARPOINT( ombb->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( -1.7678, -5.3033 ), 0.0001 );
    7966                 :          1 :   QGSCOMPARENEARPOINT( ombb->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 3 ) ), QgsPoint( -5.3033, -1.7678 ), 0.0001 );
    7967                 :            : 
    7968                 :          1 :   elpq = QgsEllipse( QgsPoint( 0, 0 ), 5, 2.5, 315 );
    7969                 :          1 :   ombb.reset( elpq.orientedBoundingBox() );
    7970                 :          1 :   QGSCOMPARENEARPOINT( ombb->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( -5.3033, 1.7678 ), 0.0001 );
    7971                 :          1 :   QGSCOMPARENEARPOINT( ombb->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( -1.7678, 5.3033 ), 0.0001 );
    7972                 :          1 :   QGSCOMPARENEARPOINT( ombb->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( 5.3033, -1.7678 ), 0.0001 );
    7973                 :          1 :   QGSCOMPARENEARPOINT( ombb->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 3 ) ), QgsPoint( 1.7678, -5.3033 ), 0.0001 );
    7974                 :            : 
    7975                 :            :   // bounding box
    7976                 :          1 :   QCOMPARE( QgsEllipse().boundingBox(), QgsRectangle() );
    7977                 :          1 :   ombb.reset( QgsEllipse( QgsPoint( 0, 0 ), 5, 2 ).orientedBoundingBox() );
    7978                 :          1 :   QCOMPARE( QgsEllipse( QgsPoint( 0, 0 ), 5, 2 ).boundingBox(), ombb->boundingBox() );
    7979                 :          1 :   QCOMPARE( QgsEllipse( QgsPoint( 0, 0 ), 5, 5 ).boundingBox(), QgsRectangle( QgsPointXY( -5, -5 ), QgsPointXY( 5, 5 ) ) );
    7980                 :          1 :   QCOMPARE( QgsEllipse( QgsPoint( 0, 0 ), 5, 5, 60 ).boundingBox(), QgsRectangle( QgsPointXY( -5, -5 ), QgsPointXY( 5, 5 ) ) );
    7981                 :          1 :   QCOMPARE( QgsEllipse( QgsPoint( 0, 0 ), 13, 9, 45 ).boundingBox().toString( 4 ).toStdString(), QgsRectangle( QgsPointXY( -11.1803, -11.1803 ), QgsPointXY( 11.1803, 11.1803 ) ).toString( 4 ).toStdString() );
    7982                 :          1 :   QCOMPARE( QgsEllipse( QgsPoint( 0, 0 ), 13, 9, 60 ).boundingBox().toString( 4 ).toStdString(), QgsRectangle( QgsPointXY( -12.12436, -10.14889 ), QgsPointXY( 12.12436, 10.14889 ) ).toString( 4 ).toStdString() );
    7983                 :          1 :   QCOMPARE( QgsEllipse( QgsPoint( 0, 0 ), 13, 9, 60 + 90 ).boundingBox().toString( 4 ).toStdString(), QgsRectangle( QgsPointXY( -10.14889, -12.12436 ), QgsPointXY( 10.14889, 12.12436 ) ).toString( 4 ).toStdString() );
    7984                 :          1 :   QCOMPARE( QgsEllipse( QgsPoint( 0, 0 ), 13, 9, 300 ).boundingBox().toString( 4 ).toStdString(), QgsRectangle( QgsPointXY( -12.12436, -10.14889 ), QgsPointXY( 12.12436, 10.14889 ) ).toString( 4 ).toStdString() );
    7985                 :          1 :   QCOMPARE( QgsEllipse( QgsPoint( 0, 0 ), 13, 9, 300 - 90 ).boundingBox().toString( 4 ).toStdString(), QgsRectangle( QgsPointXY( -10.14889, -12.12436 ), QgsPointXY( 10.14889, 12.12436 ) ).toString( 4 ).toStdString() );
    7986                 :            : 
    7987                 :            :   // focus
    7988                 :          1 :   QCOMPARE( QgsEllipse().fromFoci( QgsPoint( -4, 0 ), QgsPoint( 4, 0 ), QgsPoint( 0, 4 ) ).focusDistance(), 4.0 );
    7989                 :          1 :   QGSCOMPARENEAR( QgsEllipse().fromFoci( QgsPoint( 10, 10 ), QgsPoint( 25, 20 ), QgsPoint( 15, 20 ) ).focusDistance(), 9.01388, 0.0001 );
    7990                 :            : 
    7991                 :            :   // eccentricity
    7992                 :          1 :   QCOMPARE( QgsEllipse().fromFoci( QgsPoint( -4, 0 ), QgsPoint( 4, 0 ), QgsPoint( 0, 4 ) ).eccentricity(), 0.7071067811865475 );
    7993                 :          1 :   QCOMPARE( QgsEllipse( QgsPoint( 0, 0 ), 3, 3 ).eccentricity(), 0.0 );
    7994                 :          1 :   QVERIFY( std::isnan( QgsEllipse().eccentricity() ) );
    7995                 :            : 
    7996                 :            :   // area
    7997                 :          1 :   QGSCOMPARENEAR( 31.4159, QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 0 ).area(), 0.0001 );
    7998                 :            :   // perimeter
    7999                 :          1 :   p1.reset( QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 45 ).toPolygon( 10000 ) );
    8000                 :          1 :   QGSCOMPARENEAR( QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 45 ).perimeter(), p1->perimeter(), 0.001 );
    8001                 :            : 
    8002                 :          1 : }
    8003                 :            : 
    8004                 :          1 : void TestQgsGeometry::circle()
    8005                 :            : {
    8006                 :            :   //test constructors
    8007                 :          1 :   QgsCircle circ1;
    8008                 :          1 :   QVERIFY( circ1.center().isEmpty() );
    8009                 :          1 :   QCOMPARE( circ1.radius(), 0.0 );
    8010                 :          1 :   QCOMPARE( circ1.azimuth(), 0.0 );
    8011                 :          1 :   QVERIFY( circ1.isEmpty() );
    8012                 :            : 
    8013                 :          1 :   QgsCircle circ2( QgsPoint( 5, 10 ), 3 );
    8014                 :          1 :   QVERIFY( circ2.center() == QgsPoint( 5, 10 ) );
    8015                 :          1 :   QCOMPARE( circ2.radius(), 3.0 );
    8016                 :          1 :   QCOMPARE( circ2.azimuth(), 0.0 );
    8017                 :          1 :   QVERIFY( !circ2.isEmpty() );
    8018                 :            : 
    8019                 :          1 :   QgsCircle circ3( QgsPoint( 5, 10 ), 3, 45 );
    8020                 :          1 :   QVERIFY( circ3.center() == QgsPoint( 5, 10 ) );
    8021                 :          1 :   QCOMPARE( circ3.radius(), 3.0 );
    8022                 :          1 :   QCOMPARE( circ3.azimuth(), 45.0 );
    8023                 :          1 :   QVERIFY( !circ3.isEmpty() );
    8024                 :            : 
    8025                 :            :   //test toString
    8026                 :          1 :   QCOMPARE( circ1.toString(), QString( "Empty" ) );
    8027                 :          1 :   QCOMPARE( circ2.toString(), QString( "Circle (Center: Point (5 10), Radius: 3, Azimuth: 0)" ) );
    8028                 :          1 :   QCOMPARE( circ3.toString(), QString( "Circle (Center: Point (5 10), Radius: 3, Azimuth: 45)" ) );
    8029                 :            : 
    8030                 :            : //test equality operator
    8031                 :          1 :   QCOMPARE( QgsCircle().isEmpty(), QgsCircle( QgsPoint(), 0, 0 ).isEmpty() );
    8032                 :          1 :   QVERIFY( !( QgsCircle() == QgsCircle( QgsPoint( 0, 0 ), 0, 0.0005 ) ) );
    8033                 :          1 :   QVERIFY( circ2 == QgsCircle( QgsPoint( 5, 10 ), 3, 0 ) );
    8034                 :          1 :   QVERIFY( circ2 != circ3 );
    8035                 :            : 
    8036                 :            : //test setter and getter
    8037                 :          1 :   circ1.setAzimuth( 45 );
    8038                 :          1 :   QCOMPARE( circ1.azimuth(), 45.0 );
    8039                 :            : 
    8040                 :          1 :   circ1.setRadius( 50 );
    8041                 :          1 :   QCOMPARE( circ1.radius(), 50.0 );
    8042                 :          1 :   QCOMPARE( circ1.semiMajorAxis(), 50.0 );
    8043                 :          1 :   QCOMPARE( circ1.semiMinorAxis(), 50.0 );
    8044                 :            : 
    8045                 :          1 :   circ1.setSemiMajorAxis( 250 );
    8046                 :          1 :   QCOMPARE( circ1.radius(), 250.0 );
    8047                 :          1 :   QCOMPARE( circ1.semiMajorAxis(), 250.0 );
    8048                 :          1 :   QCOMPARE( circ1.semiMinorAxis(), 250.0 );
    8049                 :            : 
    8050                 :          1 :   circ1.setSemiMinorAxis( 8250 );
    8051                 :          1 :   QCOMPARE( circ1.radius(), 8250.0 );
    8052                 :          1 :   QCOMPARE( circ1.semiMajorAxis(), 8250.0 );
    8053                 :          1 :   QCOMPARE( circ1.semiMinorAxis(), 8250.0 );
    8054                 :            : 
    8055                 :          1 :   circ1.setCenter( QgsPoint( 5, 10 ) );
    8056                 :          1 :   QVERIFY( circ1.center() == QgsPoint( 5, 10 ) );
    8057                 :          1 :   QVERIFY( circ1.rcenter() == QgsPoint( 5, 10 ) );
    8058                 :          1 :   circ1.rcenter() = QgsPoint( 25, 310 );
    8059                 :          1 :   QVERIFY( circ1.center() == QgsPoint( 25, 310 ) );
    8060                 :            : 
    8061                 :            : //test "alt" constructors
    8062                 :            : // by2Points
    8063                 :          1 :   QVERIFY( QgsCircle().from2Points( QgsPoint( -5, 0 ), QgsPoint( 5, 0 ) ) == QgsCircle( QgsPoint( 0, 0 ), 5, 90 ) );
    8064                 :          1 :   QVERIFY( QgsCircle().from2Points( QgsPoint( 0, -5 ), QgsPoint( 0, 5 ) ) == QgsCircle( QgsPoint( 0, 0 ), 5, 0 ) );
    8065                 :            : // byExtent
    8066                 :          1 :   QVERIFY( QgsCircle().fromExtent( QgsPoint( -5, -5 ), QgsPoint( 5, 5 ) ) == QgsCircle( QgsPoint( 0, 0 ), 5, 0 ) );
    8067                 :          1 :   QVERIFY( QgsCircle().fromExtent( QgsPoint( -7.5, -2.5 ), QgsPoint( 2.5, 200.5 ) ).isEmpty() );
    8068                 :            : // by3Points
    8069                 :          1 :   QVERIFY( QgsCircle().from3Points( QgsPoint( -5, 0 ), QgsPoint( 5, 0 ), QgsPoint( 0, 5 ) ) == QgsCircle( QgsPoint( 0, 0 ), 5 ) );
    8070                 :          1 :   QVERIFY( QgsCircle().from3Points( QgsPoint( 5, 0 ), QgsPoint( 6, 0 ), QgsPoint( 7, 0 ) ).isEmpty() );
    8071                 :            : // byCenterDiameter
    8072                 :          1 :   QVERIFY( QgsCircle().fromCenterDiameter( QgsPoint( 0, 0 ), 10 ) == QgsCircle( QgsPoint( 0, 0 ), 5, 0 ) );
    8073                 :          1 :   QVERIFY( QgsCircle().fromCenterDiameter( QgsPoint( 2, 100 ), -10 ) == QgsCircle( QgsPoint( 2, 100 ), 5, 0 ) );
    8074                 :          1 :   QVERIFY( QgsCircle().fromCenterDiameter( QgsPoint( 2, 100 ), -10, 45 ) == QgsCircle( QgsPoint( 2, 100 ), 5, 45 ) );
    8075                 :            : // byCenterPoint
    8076                 :          1 :   QVERIFY( QgsCircle().fromCenterPoint( QgsPoint( 0, 0 ), QgsPoint( 5, 0 ) ) == QgsCircle( QgsPoint( 0, 0 ), 5, 90 ) );
    8077                 :          1 :   QVERIFY( QgsCircle().fromCenterPoint( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ) ) == QgsCircle( QgsPoint( 0, 0 ), 5, 0 ) );
    8078                 :          1 :   QVERIFY( QgsCircle().fromCenterPoint( QgsPoint( 0, 0 ), QgsPoint( 5 * std::cos( 45 * M_PI / 180.0 ), 5 * std::sin( 45 * M_PI / 180.0 ) ) ) == QgsCircle( QgsPoint( 0, 0 ), 5, 45 ) );
    8079                 :            : // by3Tangents
    8080                 :            : // Tangents from triangle tri1( 0,0 ; 0,5 ), tri2( 0,0 ; 5,0 ), tri3( 5,0 ; 0,5 )
    8081                 :          1 :   QgsCircle circ_tgt = QgsCircle().from3Tangents( QgsPoint( 0, 0 ), QgsPoint( 0, 1 ), QgsPoint( 2, 0 ), QgsPoint( 3, 0 ), QgsPoint( 5, 0 ), QgsPoint( 0, 5 ) );
    8082                 :          1 :   QGSCOMPARENEARPOINT( circ_tgt.center(), QgsPoint( 1.4645, 1.4645 ), 0.0001 );
    8083                 :          1 :   QGSCOMPARENEAR( circ_tgt.radius(), 1.4645, 0.0001 );
    8084                 :            :   // with parallels
    8085                 :          1 :   circ_tgt = QgsCircle().from3Tangents( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 1, 0 ), QgsPoint( 1, 5 ), QgsPoint( 5, 0 ), QgsPoint( 0, 5 ) );
    8086                 :          1 :   QVERIFY( circ_tgt.isEmpty() );
    8087                 :          1 :   circ_tgt = QgsCircle().from3Tangents( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 0 ), QgsPoint( 0, 5 ), QgsPoint( 1, 0 ), QgsPoint( 1, 5 ) );
    8088                 :          1 :   QVERIFY( circ_tgt.isEmpty() );
    8089                 :          1 :   circ_tgt = QgsCircle().from3Tangents( QgsPoint( 5, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 1, 0 ), QgsPoint( 1, 5 ) );
    8090                 :          1 :   QVERIFY( circ_tgt.isEmpty() );
    8091                 :            :   // with 2 parallels
    8092                 :          1 :   const double epsilon = 1e-8;
    8093                 :          1 :   circ_tgt = QgsCircle().from3Tangents( QgsPoint( 0, 0 ), QgsPoint( 5, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 5 ), QgsPoint( 2.5, 0 ), QgsPoint( 7.5, 5 ) );
    8094                 :          1 :   QVERIFY( circ_tgt.isEmpty() );
    8095                 :          1 :   circ_tgt = QgsCircle().from3Tangents( QgsPoint( 0, 0 ), QgsPoint( 5, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 5 ), QgsPoint( 2.5, 0 ), QgsPoint( 7.5, 5 ), epsilon, QgsPoint( 2, 0 ) );
    8096                 :          1 :   QGSCOMPARENEARPOINT( circ_tgt.center(), QgsPoint( 1.4645, 2.5000 ), 0.0001 );
    8097                 :          1 :   QGSCOMPARENEAR( circ_tgt.radius(), 2.5, 0.0001 );
    8098                 :          1 :   circ_tgt = QgsCircle().from3Tangents( QgsPoint( 0, 0 ), QgsPoint( 5, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 5 ), QgsPoint( 2.5, 0 ), QgsPoint( 7.5, 5 ), epsilon, QgsPoint( 3, 0 ) );
    8099                 :          1 :   QGSCOMPARENEARPOINT( circ_tgt.center(), QgsPoint( 8.5355, 2.5000 ), 0.0001 );
    8100                 :          1 :   QGSCOMPARENEAR( circ_tgt.radius(), 2.5, 0.0001 );
    8101                 :            : // from3tangentsMulti
    8102                 :          1 :   QVector<QgsCircle> circles_tgt;
    8103                 :          1 :   circles_tgt = QgsCircle().from3TangentsMulti( QgsPoint( 0, 0 ), QgsPoint( 5, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 5 ), QgsPoint( 2.5, 0 ), QgsPoint( 7.5, 5 ) );
    8104                 :          1 :   QCOMPARE( circles_tgt.count(), 2 );
    8105                 :          1 :   circ_tgt = circles_tgt.at( 0 );
    8106                 :          1 :   QGSCOMPARENEARPOINT( circ_tgt.center(), QgsPoint( 8.5355, 2.5000 ), 0.0001 );
    8107                 :          1 :   QGSCOMPARENEAR( circ_tgt.radius(), 2.5, 0.0001 );
    8108                 :          1 :   circ_tgt = circles_tgt.at( 1 );
    8109                 :          1 :   QGSCOMPARENEARPOINT( circ_tgt.center(), QgsPoint( 1.4645, 2.5000 ), 0.0001 );
    8110                 :          1 :   QGSCOMPARENEAR( circ_tgt.radius(), 2.5, 0.0001 );
    8111                 :          1 :   circles_tgt = QgsCircle().from3TangentsMulti( QgsPoint( 0, 0 ), QgsPoint( 5, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 5 ), QgsPoint( 2.5, 0 ), QgsPoint( 7.5, 5 ), epsilon, QgsPoint( 2, 0 ) );
    8112                 :          1 :   QCOMPARE( circles_tgt.count(), 1 );
    8113                 :          1 :   circ_tgt = circles_tgt.at( 0 );
    8114                 :          1 :   QGSCOMPARENEARPOINT( circ_tgt.center(), QgsPoint( 1.4645, 2.5000 ), 0.0001 );
    8115                 :          1 :   QGSCOMPARENEAR( circ_tgt.radius(), 2.5, 0.0001 );
    8116                 :          1 :   circles_tgt = QgsCircle().from3TangentsMulti( QgsPoint( 0, 0 ), QgsPoint( 5, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 5 ), QgsPoint( 2.5, 0 ), QgsPoint( 7.5, 5 ), epsilon, QgsPoint( 3, 0 ) );
    8117                 :          1 :   QCOMPARE( circles_tgt.count(), 1 );
    8118                 :          1 :   circles_tgt = QgsCircle().from3TangentsMulti( QgsPoint( 0, 0 ), QgsPoint( 5, 0 ), QgsPoint( 5, 5 ), QgsPoint( 10, 5 ), QgsPoint( 15, 5 ), QgsPoint( 20, 5 ) );
    8119                 :          1 :   QVERIFY( circles_tgt.isEmpty() );
    8120                 :            :   // check that Z dimension is ignored in case of using tangents
    8121                 :          1 :   QgsCircle circ_tgt_z = QgsCircle().from3Tangents( QgsPoint( 0, 0, 333 ), QgsPoint( 0, 1, 1 ), QgsPoint( 2, 0, 2 ), QgsPoint( 3, 0, 3 ), QgsPoint( 5, 0, 4 ), QgsPoint( 0, 5, 5 ) );
    8122                 :          1 :   QCOMPARE( circ_tgt_z.center().is3D(), false );
    8123                 :            : 
    8124                 :            :   // minimalCircleFrom3points
    8125                 :          1 :   QgsCircle minCircle3Points = QgsCircle().minimalCircleFrom3Points( QgsPoint( 0, 5 ), QgsPoint( 0, -5 ), QgsPoint( 1, 2 ) );
    8126                 :          1 :   QGSCOMPARENEARPOINT( minCircle3Points.center(), QgsPoint( 0, 0 ), 0.0001 );
    8127                 :          1 :   QGSCOMPARENEAR( minCircle3Points.radius(), 5.0, 0.0001 );
    8128                 :          1 :   minCircle3Points = QgsCircle().minimalCircleFrom3Points( QgsPoint( 0, 5 ), QgsPoint( 5, 0 ), QgsPoint( -5, 0 ) );
    8129                 :          1 :   QGSCOMPARENEARPOINT( minCircle3Points.center(), QgsPoint( 0, 0 ), 0.0001 );
    8130                 :          1 :   QGSCOMPARENEAR( minCircle3Points.radius(), 5.0, 0.0001 );
    8131                 :            : 
    8132                 :            : 
    8133                 :            : 
    8134                 :            : // test quadrant
    8135                 :          1 :   QgsPointSequence quad = QgsCircle( QgsPoint( 0, 0 ), 5 ).northQuadrant();
    8136                 :          1 :   QVERIFY( quad.at( 0 ) == QgsPoint( 0, 5 ) );
    8137                 :          1 :   QVERIFY( quad.at( 1 ) == QgsPoint( 5, 0 ) );
    8138                 :          1 :   QVERIFY( quad.at( 2 ) == QgsPoint( 0, -5 ) );
    8139                 :          1 :   QVERIFY( quad.at( 3 ) == QgsPoint( -5, 0 ) );
    8140                 :            : 
    8141                 :          1 :   quad = QgsCircle( QgsPoint( 0, 0 ), 5, 123 ).northQuadrant();
    8142                 :          1 :   QVERIFY( quad.at( 0 ) == QgsPoint( 0, 5 ) );
    8143                 :          1 :   QVERIFY( quad.at( 1 ) == QgsPoint( 5, 0 ) );
    8144                 :          1 :   QVERIFY( quad.at( 2 ) == QgsPoint( 0, -5 ) );
    8145                 :          1 :   QVERIFY( quad.at( 3 ) == QgsPoint( -5, 0 ) );
    8146                 :            : 
    8147                 :          1 :   quad = QgsCircle( QgsPoint( 0, 0 ), 5, 456 ).northQuadrant();
    8148                 :          1 :   QVERIFY( quad.at( 0 ) == QgsPoint( 0, 5 ) );
    8149                 :          1 :   QVERIFY( quad.at( 1 ) == QgsPoint( 5, 0 ) );
    8150                 :          1 :   QVERIFY( quad.at( 2 ) == QgsPoint( 0, -5 ) );
    8151                 :          1 :   QVERIFY( quad.at( 3 ) == QgsPoint( -5, 0 ) );
    8152                 :            : 
    8153                 :          1 :   quad = QgsCircle( QgsPoint( 0, 0 ), 5, -789l ).northQuadrant();
    8154                 :          1 :   QVERIFY( quad.at( 0 ) == QgsPoint( 0, 5 ) );
    8155                 :          1 :   QVERIFY( quad.at( 1 ) == QgsPoint( 5, 0 ) );
    8156                 :          1 :   QVERIFY( quad.at( 2 ) == QgsPoint( 0, -5 ) );
    8157                 :          1 :   QVERIFY( quad.at( 3 ) == QgsPoint( -5, 0 ) );
    8158                 :            : 
    8159                 :            : 
    8160                 :            : //test conversion
    8161                 :          1 :   QgsPointSequence ptsPol;
    8162                 :          1 :   std::unique_ptr< QgsPolygon > pol( new QgsPolygon() );
    8163                 :            : // polygon
    8164                 :          1 :   pol.reset( QgsCircle( QgsPoint( 0, 0 ), 5 ).toPolygon( 4 ) );
    8165                 :          1 :   QCOMPARE( pol->numInteriorRings(), 0 );
    8166                 :          1 :   QCOMPARE( pol->exteriorRing()->numPoints(), 5 );
    8167                 :            : 
    8168                 :          1 :   pol->exteriorRing()->points( ptsPol );
    8169                 :          1 :   QCOMPARE( ptsPol.length(), 5 );
    8170                 :          1 :   QVERIFY( ptsPol.at( 0 ) == QgsPoint( 0, 5 ) );
    8171                 :          1 :   QVERIFY( ptsPol.at( 1 ) == QgsPoint( 5, 0 ) );
    8172                 :          1 :   QVERIFY( ptsPol.at( 2 ) == QgsPoint( 0, -5 ) );
    8173                 :          1 :   QVERIFY( ptsPol.at( 3 ) == QgsPoint( -5, 0 ) );
    8174                 :          1 :   QVERIFY( ptsPol.at( 4 ) == QgsPoint( 0, 5 ) );
    8175                 :            : 
    8176                 :            : // oriented
    8177                 :            : //45
    8178                 :          1 :   double val = 5 * std::sin( M_PI / 4 );
    8179                 :          1 :   pol.reset( QgsCircle( QgsPoint( 0, 0 ), 5, 45 ).toPolygon( 4 ) );
    8180                 :          1 :   QCOMPARE( pol->numInteriorRings(), 0 );
    8181                 :          1 :   QCOMPARE( pol->exteriorRing()->numPoints(), 5 );
    8182                 :          1 :   pol->exteriorRing()->points( ptsPol );
    8183                 :          1 :   QCOMPARE( ptsPol.length(), 5 );
    8184                 :          1 :   QVERIFY( ptsPol.at( 0 ) == QgsPoint( val, val ) );
    8185                 :          1 :   QVERIFY( ptsPol.at( 1 ) == QgsPoint( val, -val ) );
    8186                 :          1 :   QVERIFY( ptsPol.at( 2 ) == QgsPoint( -val, -val ) );
    8187                 :          1 :   QVERIFY( ptsPol.at( 3 ) == QgsPoint( -val, val ) );
    8188                 :          1 :   QVERIFY( ptsPol.at( 4 ) == QgsPoint( val, val ) );
    8189                 :            : //135
    8190                 :          1 :   pol.reset( QgsCircle( QgsPoint( 0, 0 ), 5, 135 ).toPolygon( 4 ) );
    8191                 :          1 :   QCOMPARE( pol->numInteriorRings(), 0 );
    8192                 :          1 :   QCOMPARE( pol->exteriorRing()->numPoints(), 5 );
    8193                 :          1 :   pol->exteriorRing()->points( ptsPol );
    8194                 :          1 :   QCOMPARE( ptsPol.length(), 5 );
    8195                 :          1 :   QVERIFY( ptsPol.at( 0 ) == QgsPoint( val, -val ) );
    8196                 :          1 :   QVERIFY( ptsPol.at( 1 ) == QgsPoint( -val, -val ) );
    8197                 :          1 :   QVERIFY( ptsPol.at( 2 ) == QgsPoint( -val, val ) );
    8198                 :          1 :   QVERIFY( ptsPol.at( 3 ) == QgsPoint( val, val ) );
    8199                 :          1 :   QVERIFY( ptsPol.at( 4 ) == QgsPoint( val, -val ) );
    8200                 :            : //225
    8201                 :          1 :   pol.reset( QgsCircle( QgsPoint( 0, 0 ), 5, 225 ).toPolygon( 4 ) );
    8202                 :          1 :   QCOMPARE( pol->numInteriorRings(), 0 );
    8203                 :          1 :   QCOMPARE( pol->exteriorRing()->numPoints(), 5 );
    8204                 :          1 :   pol->exteriorRing()->points( ptsPol );
    8205                 :          1 :   QCOMPARE( ptsPol.length(), 5 );
    8206                 :          1 :   QVERIFY( ptsPol.at( 0 ) == QgsPoint( -val, -val ) );
    8207                 :          1 :   QVERIFY( ptsPol.at( 1 ) == QgsPoint( -val, val ) );
    8208                 :          1 :   QVERIFY( ptsPol.at( 2 ) == QgsPoint( val, val ) );
    8209                 :          1 :   QVERIFY( ptsPol.at( 3 ) == QgsPoint( val, -val ) );
    8210                 :          1 :   QVERIFY( ptsPol.at( 4 ) == QgsPoint( -val, -val ) );
    8211                 :            : //315
    8212                 :          1 :   pol.reset( QgsCircle( QgsPoint( 0, 0 ), 5, 315 ).toPolygon( 4 ) );
    8213                 :          1 :   QCOMPARE( pol->numInteriorRings(), 0 );
    8214                 :          1 :   QCOMPARE( pol->exteriorRing()->numPoints(), 5 );
    8215                 :          1 :   pol->exteriorRing()->points( ptsPol );
    8216                 :          1 :   QCOMPARE( ptsPol.length(), 5 );
    8217                 :          1 :   QVERIFY( ptsPol.at( 0 ) == QgsPoint( -val, val ) );
    8218                 :          1 :   QVERIFY( ptsPol.at( 1 ) == QgsPoint( val, val ) );
    8219                 :          1 :   QVERIFY( ptsPol.at( 2 ) == QgsPoint( val, -val ) );
    8220                 :          1 :   QVERIFY( ptsPol.at( 3 ) == QgsPoint( -val, -val ) );
    8221                 :          1 :   QVERIFY( ptsPol.at( 4 ) == QgsPoint( -val, val ) );
    8222                 :            : 
    8223                 :            : // circular arc
    8224                 :          1 :   std::unique_ptr< QgsCircularString > cs( QgsCircle( QgsPoint( 0, 0 ), 5 ).toCircularString() );
    8225                 :          1 :   QCOMPARE( cs->asWkt( 2 ), QString( "CircularString (0 5, 5 0, 0 -5, -5 0, 0 5)" ) );
    8226                 :          1 :   cs.reset( QgsCircle( QgsPoint( 0, 0 ), 5 ).toCircularString( true ) );
    8227                 :          1 :   QCOMPARE( cs->asWkt( 2 ), QString( "CircularString (0 5, 5 0, 0 -5, -5 0, 0 5)" ) );
    8228                 :          1 :   cs.reset( QgsCircle( QgsPoint( 0, 0 ), 5, 315 ).toCircularString() );
    8229                 :          1 :   QCOMPARE( cs->asWkt( 2 ), QString( "CircularString (0 5, 5 0, 0 -5, -5 0, 0 5)" ) );
    8230                 :          1 :   cs.reset( QgsCircle( QgsPoint( 0, 0 ), 5, 315 ).toCircularString( true ) );
    8231                 :          1 :   QCOMPARE( cs->asWkt( 2 ), QString( "CircularString (-3.54 3.54, 3.54 3.54, 3.54 -3.54, -3.54 -3.54, -3.54 3.54)" ) );
    8232                 :            : 
    8233                 :            : // bounding box
    8234                 :          1 :   QVERIFY( QgsRectangle( QgsPointXY( -2.5, -2.5 ), QgsPointXY( 2.5, 2.5 ) ) == QgsCircle( QgsPoint( 0, 0 ), 2.5, 0 ).boundingBox() );
    8235                 :          1 :   QVERIFY( QgsRectangle( QgsPointXY( -2.5, -2.5 ), QgsPointXY( 2.5, 2.5 ) ) == QgsCircle( QgsPoint( 0, 0 ), 2.5, 45 ).boundingBox() );
    8236                 :            : 
    8237                 :            :   // area
    8238                 :          1 :   QGSCOMPARENEAR( 314.1593, QgsCircle( QgsPoint( 0, 0 ), 10 ).area(), 0.0001 );
    8239                 :            :   // perimeter
    8240                 :          1 :   QGSCOMPARENEAR( 31.4159, QgsCircle( QgsPoint( 0, 0 ), 5 ).perimeter(), 0.0001 );
    8241                 :            : 
    8242                 :            :   // contains
    8243                 :          1 :   QgsPoint pc;
    8244                 :          1 :   pc = QgsPoint( 1, 1 );
    8245                 :          1 :   QVERIFY( QgsCircle( QgsPoint( 0, 0 ), 5 ).contains( pc ) );
    8246                 :          1 :   pc = QgsPoint( 0, 5 );
    8247                 :          1 :   QVERIFY( QgsCircle( QgsPoint( 0, 0 ), 5 ).contains( pc ) );
    8248                 :          1 :   pc = QgsPoint( 6, 1 );
    8249                 :          1 :   QVERIFY( !QgsCircle( QgsPoint( 0, 0 ), 5 ).contains( pc ) );
    8250                 :            : 
    8251                 :            :   // intersections
    8252                 :          1 :   QgsCircle ci1( QgsPoint( 0, 0 ), 1 );
    8253                 :          1 :   QgsPoint int1;
    8254                 :          1 :   QgsPoint int2;
    8255                 :          1 :   QCOMPARE( ci1.intersections( QgsCircle( QgsPoint( 2, 0 ), 0.5 ), int1, int2 ), 0 );
    8256                 :          1 :   QCOMPARE( ci1.intersections( QgsCircle( QgsPoint( 0.5, 0.1 ), 0.2 ), int1, int2 ), 0 );
    8257                 :            :   // one intersection
    8258                 :          1 :   QCOMPARE( ci1.intersections( QgsCircle( QgsPoint( 3, 0 ), 2 ), int1, int2 ), 1 );
    8259                 :          1 :   QCOMPARE( int1, QgsPoint( 1, 0 ) );
    8260                 :          1 :   QCOMPARE( int2, QgsPoint( 1, 0 ) );
    8261                 :            :   // two intersections
    8262                 :          1 :   ci1 = QgsCircle( QgsPoint( 5, 3 ), 2 );
    8263                 :          1 :   QCOMPARE( ci1.intersections( QgsCircle( QgsPoint( 7, -1 ), 4 ), int1, int2 ), 2 );
    8264                 :          1 :   QCOMPARE( int1.wkbType(), QgsWkbTypes::Point );
    8265                 :          1 :   QGSCOMPARENEAR( int1.x(), 3.8, 0.001 );
    8266                 :          1 :   QGSCOMPARENEAR( int1.y(), 1.4, 0.001 );
    8267                 :          1 :   QCOMPARE( int2.wkbType(), QgsWkbTypes::Point );
    8268                 :          1 :   QGSCOMPARENEAR( int2.x(), 7.0, 0.001 );
    8269                 :          1 :   QGSCOMPARENEAR( int2.y(), 3.0, 0.001 );
    8270                 :            :   // with z
    8271                 :          1 :   ci1 = QgsCircle( QgsPoint( 5, 3, 11 ), 2 );
    8272                 :          1 :   QCOMPARE( ci1.intersections( QgsCircle( QgsPoint( 7, -1, 5 ), 4 ), int1, int2, true ), 0 );
    8273                 :          1 :   QCOMPARE( ci1.intersections( QgsCircle( QgsPoint( 7, -1, 11 ), 4 ), int1, int2, true ), 2 );
    8274                 :          1 :   QCOMPARE( int1.wkbType(), QgsWkbTypes::PointZ );
    8275                 :          1 :   QGSCOMPARENEAR( int1.x(), 3.8, 0.001 );
    8276                 :          1 :   QGSCOMPARENEAR( int1.y(), 1.4, 0.001 );
    8277                 :          1 :   QGSCOMPARENEAR( int1.z(), 11.0, 0.001 );
    8278                 :          1 :   QCOMPARE( int2.wkbType(), QgsWkbTypes::PointZ );
    8279                 :          1 :   QGSCOMPARENEAR( int2.x(), 7.0, 0.001 );
    8280                 :          1 :   QGSCOMPARENEAR( int2.y(), 3.0, 0.001 );
    8281                 :          1 :   QGSCOMPARENEAR( int2.z(), 11.0, 0.001 );
    8282                 :            : 
    8283                 :            :   // tangent to point
    8284                 :          1 :   QgsPointXY t1;
    8285                 :          1 :   QgsPointXY t2;
    8286                 :          1 :   QVERIFY( !QgsCircle( QgsPoint( 1, 2 ), 4 ).tangentToPoint( QgsPointXY( 1, 2 ), t1, t2 ) );
    8287                 :          1 :   QVERIFY( QgsCircle( QgsPoint( 1, 2 ), 4 ).tangentToPoint( QgsPointXY( 8, 4 ), t1, t2 ) );
    8288                 :          1 :   QGSCOMPARENEAR( t1.x(), 4.03, 0.01 );
    8289                 :          1 :   QGSCOMPARENEAR( t1.y(), -0.61, 0.01 );
    8290                 :          1 :   QGSCOMPARENEAR( t2.x(), 2.2, 0.01 );
    8291                 :          1 :   QGSCOMPARENEAR( t2.y(), 5.82, 0.01 );
    8292                 :            : 
    8293                 :            :   // two outer circle tangents
    8294                 :          1 :   QgsPointXY l1p1, l1p2, l2p1, l2p2;
    8295                 :          1 :   QCOMPARE( QgsCircle( QgsPoint( 1, 2 ), 4 ).outerTangents( QgsCircle( QgsPoint( 2, 3 ), 1 ), l1p1, l1p2, l2p1, l2p2 ), 0 );
    8296                 :          1 :   QCOMPARE( QgsCircle( QgsPoint( 1, 2 ), 1 ).outerTangents( QgsCircle( QgsPoint( 10, 3 ), 4 ), l1p1, l1p2, l2p1, l2p2 ), 2 );
    8297                 :          1 :   QGSCOMPARENEAR( l1p1.x(), 0.566, 0.01 );
    8298                 :          1 :   QGSCOMPARENEAR( l1p1.y(), 2.901, 0.01 );
    8299                 :          1 :   QGSCOMPARENEAR( l1p2.x(), 8.266, 0.01 );
    8300                 :          1 :   QGSCOMPARENEAR( l1p2.y(), 6.604, 0.01 );
    8301                 :          1 :   QGSCOMPARENEAR( l2p1.x(), 0.7749, 0.01 );
    8302                 :          1 :   QGSCOMPARENEAR( l2p1.y(), 1.025, 0.01 );
    8303                 :          1 :   QGSCOMPARENEAR( l2p2.x(), 9.099, 0.01 );
    8304                 :          1 :   QGSCOMPARENEAR( l2p2.y(), -0.897, 0.01 );
    8305                 :            : 
    8306                 :            :   // two inner circle tangents
    8307                 :          1 :   QCOMPARE( QgsCircle( QgsPoint( 1, 2 ), 4 ).innerTangents( QgsCircle( QgsPoint( 2, 3 ), 1 ), l1p1, l1p2, l2p1, l2p2 ), 0 );
    8308                 :          1 :   QCOMPARE( QgsCircle( QgsPoint( 0, 0 ), 4 ).innerTangents( QgsCircle( QgsPoint( 8, 0 ), 5 ), l1p1, l1p2, l2p1, l2p2 ), 0 );
    8309                 :          1 :   QCOMPARE( QgsCircle( QgsPoint( 0, 0 ), 4 ).innerTangents( QgsCircle( QgsPoint( 8, 0 ), 4 ), l1p1, l1p2, l2p1, l2p2 ), 0 );
    8310                 :          1 :   QCOMPARE( QgsCircle( QgsPoint( 1, 2 ), 1 ).innerTangents( QgsCircle( QgsPoint( 10, 3 ), 4 ), l1p1, l1p2, l2p1, l2p2 ), 2 );
    8311                 :          1 :   QGSCOMPARENEAR( l1p1.x(), 7.437, 0.01 );
    8312                 :          1 :   QGSCOMPARENEAR( l1p1.y(), 6.071, 0.01 );
    8313                 :          1 :   QGSCOMPARENEAR( l1p2.x(), 1.641, 0.01 );
    8314                 :          1 :   QGSCOMPARENEAR( l1p2.y(), 1.232, 0.01 );
    8315                 :          1 :   QGSCOMPARENEAR( l2p1.x(), 8.173, 0.01 );
    8316                 :          1 :   QGSCOMPARENEAR( l2p1.y(), -0.558, 0.01 );
    8317                 :          1 :   QGSCOMPARENEAR( l2p2.x(), 1.457, 0.01 );
    8318                 :          1 :   QGSCOMPARENEAR( l2p2.y(), 2.89, 0.01 );
    8319                 :            : 
    8320                 :            :   // asGML3
    8321                 :          1 :   QgsCircle exportCircle( QgsPoint( 1, 1 ), 3 );
    8322                 :          1 :   QDomDocument doc( "gml" );
    8323                 :          2 :   QString expectedGML3( QStringLiteral( "<Circle xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">1 4 4 1 1 -2</posList></Circle>" ) );
    8324                 :          3 :   QGSCOMPAREGML( elemToString( exportCircle.asGml3( doc ) ), expectedGML3 );
    8325                 :            :   // asGML2
    8326                 :          2 :   QString expectedGML2( QStringLiteral( "<LineString xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">1,4 1.05,4 1.1,4 1.16,4 1.21,3.99 1.26,3.99 1.31,3.98 1.37,3.98 1.42,3.97 1.47,3.96 1.52,3.95 1.57,3.94 1.62,3.93 1.67,3.92 1.73,3.91 1.78,3.9 1.83,3.88 1.88,3.87 1.93,3.85 1.98,3.84 2.03,3.82 2.08,3.8 2.12,3.78 2.17,3.76 2.22,3.74 2.27,3.72 2.32,3.7 2.36,3.67 2.41,3.65 2.45,3.62 2.5,3.6 2.55,3.57 2.59,3.54 2.63,3.52 2.68,3.49 2.72,3.46 2.76,3.43 2.81,3.4 2.85,3.36 2.89,3.33 2.93,3.3 2.97,3.26 3.01,3.23 3.05,3.19 3.08,3.16 3.12,3.12 3.16,3.08 3.19,3.05 3.23,3.01 3.26,2.97 3.3,2.93 3.33,2.89 3.36,2.85 3.4,2.81 3.43,2.76 3.46,2.72 3.49,2.68 3.52,2.63 3.54,2.59 3.57,2.55 3.6,2.5 3.62,2.45 3.65,2.41 3.67,2.36 3.7,2.32 3.72,2.27 3.74,2.22 3.76,2.17 3.78,2.12 3.8,2.08 3.82,2.03 3.84,1.98 3.85,1.93 3.87,1.88 3.88,1.83 3.9,1.78 3.91,1.73 3.92,1.67 3.93,1.62 3.94,1.57 3.95,1.52 3.96,1.47 3.97,1.42 3.98,1.37 3.98,1.31 3.99,1.26 3.99,1.21 4,1.16 4,1.1 4,1.05 4,1 4,0.95 4,0.9 4,0.84 3.99,0.79 3.99,0.74 3.98,0.69 3.98,0.63 3.97,0.58 3.96,0.53 3.95,0.48 3.94,0.43 3.93,0.38 3.92,0.33 3.91,0.27 3.9,0.22 3.88,0.17 3.87,0.12 3.85,0.07 3.84,0.02 3.82,-0.03 3.8,-0.08 3.78,-0.12 3.76,-0.17 3.74,-0.22 3.72,-0.27 3.7,-0.32 3.67,-0.36 3.65,-0.41 3.62,-0.45 3.6,-0.5 3.57,-0.55 3.54,-0.59 3.52,-0.63 3.49,-0.68 3.46,-0.72 3.43,-0.76 3.4,-0.81 3.36,-0.85 3.33,-0.89 3.3,-0.93 3.26,-0.97 3.23,-1.01 3.19,-1.05 3.16,-1.08 3.12,-1.12 3.08,-1.16 3.05,-1.19 3.01,-1.23 2.97,-1.26 2.93,-1.3 2.89,-1.33 2.85,-1.36 2.81,-1.4 2.76,-1.43 2.72,-1.46 2.68,-1.49 2.63,-1.52 2.59,-1.54 2.55,-1.57 2.5,-1.6 2.45,-1.62 2.41,-1.65 2.36,-1.67 2.32,-1.7 2.27,-1.72 2.22,-1.74 2.17,-1.76 2.12,-1.78 2.08,-1.8 2.03,-1.82 1.98,-1.84 1.93,-1.85 1.88,-1.87 1.83,-1.88 1.78,-1.9 1.73,-1.91 1.67,-1.92 1.62,-1.93 1.57,-1.94 1.52,-1.95 1.47,-1.96 1.42,-1.97 1.37,-1.98 1.31,-1.98 1.26,-1.99 1.21,-1.99 1.16,-2 1.1,-2 1.05,-2 1,-2 0.95,-2 0.9,-2 0.84,-2 0.79,-1.99 0.74,-1.99 0.69,-1.98 0.63,-1.98 0.58,-1.97 0.53,-1.96 0.48,-1.95 0.43,-1.94 0.38,-1.93 0.33,-1.92 0.27,-1.91 0.22,-1.9 0.17,-1.88 0.12,-1.87 0.07,-1.85 0.02,-1.84 -0.03,-1.82 -0.08,-1.8 -0.12,-1.78 -0.17,-1.76 -0.22,-1.74 -0.27,-1.72 -0.32,-1.7 -0.36,-1.67 -0.41,-1.65 -0.45,-1.62 -0.5,-1.6 -0.55,-1.57 -0.59,-1.54 -0.63,-1.52 -0.68,-1.49 -0.72,-1.46 -0.76,-1.43 -0.81,-1.4 -0.85,-1.36 -0.89,-1.33 -0.93,-1.3 -0.97,-1.26 -1.01,-1.23 -1.05,-1.19 -1.08,-1.16 -1.12,-1.12 -1.16,-1.08 -1.19,-1.05 -1.23,-1.01 -1.26,-0.97 -1.3,-0.93 -1.33,-0.89 -1.36,-0.85 -1.4,-0.81 -1.43,-0.76 -1.46,-0.72 -1.49,-0.68 -1.52,-0.63 -1.54,-0.59 -1.57,-0.55 -1.6,-0.5 -1.62,-0.45 -1.65,-0.41 -1.67,-0.36 -1.7,-0.32 -1.72,-0.27 -1.74,-0.22 -1.76,-0.17 -1.78,-0.12 -1.8,-0.08 -1.82,-0.03 -1.84,0.02 -1.85,0.07 -1.87,0.12 -1.88,0.17 -1.9,0.22 -1.91,0.27 -1.92,0.33 -1.93,0.38 -1.94,0.43 -1.95,0.48 -1.96,0.53 -1.97,0.58 -1.98,0.63 -1.98,0.69 -1.99,0.74 -1.99,0.79 -2,0.84 -2,0.9 -2,0.95 -2,1 -2,1.05 -2,1.1 -2,1.16 -1.99,1.21 -1.99,1.26 -1.98,1.31 -1.98,1.37 -1.97,1.42 -1.96,1.47 -1.95,1.52 -1.94,1.57 -1.93,1.62 -1.92,1.67 -1.91,1.73 -1.9,1.78 -1.88,1.83 -1.87,1.88 -1.85,1.93 -1.84,1.98 -1.82,2.03 -1.8,2.08 -1.78,2.12 -1.76,2.17 -1.74,2.22 -1.72,2.27 -1.7,2.32 -1.67,2.36 -1.65,2.41 -1.62,2.45 -1.6,2.5 -1.57,2.55 -1.54,2.59 -1.52,2.63 -1.49,2.68 -1.46,2.72 -1.43,2.76 -1.4,2.81 -1.36,2.85 -1.33,2.89 -1.3,2.93 -1.26,2.97 -1.23,3.01 -1.19,3.05 -1.16,3.08 -1.12,3.12 -1.08,3.16 -1.05,3.19 -1.01,3.23 -0.97,3.26 -0.93,3.3 -0.89,3.33 -0.85,3.36 -0.81,3.4 -0.76,3.43 -0.72,3.46 -0.68,3.49 -0.63,3.52 -0.59,3.54 -0.55,3.57 -0.5,3.6 -0.45,3.62 -0.41,3.65 -0.36,3.67 -0.32,3.7 -0.27,3.72 -0.22,3.74 -0.17,3.76 -0.12,3.78 -0.08,3.8 -0.03,3.82 0.02,3.84 0.07,3.85 0.12,3.87 0.17,3.88 0.22,3.9 0.27,3.91 0.33,3.92 0.38,3.93 0.43,3.94 0.48,3.95 0.53,3.96 0.58,3.97 0.63,3.98 0.69,3.98 0.74,3.99 0.79,3.99 0.84,4 0.9,4 0.95,4 1,4</coordinates></LineString>" ) );
    8327                 :          3 :   QGSCOMPAREGML( elemToString( exportCircle.asGml2( doc, 2 ) ), expectedGML2 );
    8328                 :          1 : }
    8329                 :            : 
    8330                 :          1 : void TestQgsGeometry::quadrilateral()
    8331                 :            : {
    8332                 :            : 
    8333                 :            :   // default
    8334                 :          1 :   QgsQuadrilateral quad_init;
    8335                 :          1 :   QgsPointSequence pts = quad_init.points();
    8336                 :          1 :   QVERIFY( pts.at( 0 ).isEmpty() );
    8337                 :          1 :   QVERIFY( pts.at( 1 ).isEmpty() );
    8338                 :          1 :   QVERIFY( pts.at( 2 ).isEmpty() );
    8339                 :          1 :   QVERIFY( pts.at( 3 ).isEmpty() );
    8340                 :          1 :   QVERIFY( !quad_init.isValid() );
    8341                 :            : 
    8342                 :            :   // colinear
    8343                 :          1 :   QgsQuadrilateral quad4points_col( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 10 ), QgsPoint( 10, 10 ) );
    8344                 :          1 :   QVERIFY( !quad4points_col.isValid() );
    8345                 :          1 :   pts = quad4points_col.points();
    8346                 :          1 :   QVERIFY( pts.at( 0 ).isEmpty() );
    8347                 :          1 :   QVERIFY( pts.at( 1 ).isEmpty() );
    8348                 :          1 :   QVERIFY( pts.at( 2 ).isEmpty() );
    8349                 :          1 :   QVERIFY( pts.at( 3 ).isEmpty() );
    8350                 :            : 
    8351                 :            : 
    8352                 :          1 :   QgsQuadrilateral quad4pointsXY_col( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 10 ), QgsPoint( 10, 10 ) );
    8353                 :          1 :   QVERIFY( !quad4pointsXY_col.isValid() );
    8354                 :          1 :   pts = quad4pointsXY_col.points();
    8355                 :          1 :   QVERIFY( pts.at( 0 ).isEmpty() );
    8356                 :          1 :   QVERIFY( pts.at( 1 ).isEmpty() );
    8357                 :          1 :   QVERIFY( pts.at( 2 ).isEmpty() );
    8358                 :          1 :   QVERIFY( pts.at( 3 ).isEmpty() );
    8359                 :            : 
    8360                 :            : 
    8361                 :            :   // anti parallelogram
    8362                 :          1 :   QgsQuadrilateral quad4points_anti( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 5, 0 ), QgsPoint( 0, 5 ) );
    8363                 :          1 :   QVERIFY( !quad4points_anti.isValid() );
    8364                 :          1 :   pts = quad4points_anti.points();
    8365                 :          1 :   QVERIFY( pts.at( 0 ).isEmpty() );
    8366                 :          1 :   QVERIFY( pts.at( 1 ).isEmpty() );
    8367                 :          1 :   QVERIFY( pts.at( 2 ).isEmpty() );
    8368                 :          1 :   QVERIFY( pts.at( 3 ).isEmpty() );
    8369                 :            : 
    8370                 :            : 
    8371                 :          1 :   QgsQuadrilateral quad4pointsXY_anti( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ), QgsPoint( 5, 0 ), QgsPoint( 0, 5 ) );
    8372                 :          1 :   QVERIFY( !quad4pointsXY_anti.isValid() );
    8373                 :          1 :   pts = quad4pointsXY_anti.points();
    8374                 :          1 :   QVERIFY( pts.at( 0 ).isEmpty() );
    8375                 :          1 :   QVERIFY( pts.at( 1 ).isEmpty() );
    8376                 :          1 :   QVERIFY( pts.at( 2 ).isEmpty() );
    8377                 :          1 :   QVERIFY( pts.at( 3 ).isEmpty() );
    8378                 :            : 
    8379                 :            :   // valid
    8380                 :          1 :   QgsQuadrilateral quad4points_valid( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ), QgsPoint( 5, 0 ) );
    8381                 :          1 :   QVERIFY( quad4points_valid.isValid() );
    8382                 :          1 :   pts = quad4points_valid.points();
    8383                 :          1 :   QCOMPARE( pts.at( 0 ), QgsPoint( 0, 0 ) );
    8384                 :          1 :   QCOMPARE( pts.at( 1 ), QgsPoint( 0, 5 ) );
    8385                 :          1 :   QCOMPARE( pts.at( 2 ), QgsPoint( 5, 5 ) );
    8386                 :          1 :   QCOMPARE( pts.at( 3 ), QgsPoint( 5, 0 ) );
    8387                 :            : 
    8388                 :            :   // setPoint
    8389                 :          1 :   QVERIFY( quad4points_valid.setPoint( QgsPoint( -1, -1 ), QgsQuadrilateral::Point1 ) );
    8390                 :          1 :   QVERIFY( quad4points_valid.setPoint( QgsPoint( -1, 6 ), QgsQuadrilateral::Point2 ) );
    8391                 :          1 :   QVERIFY( quad4points_valid.setPoint( QgsPoint( 6, 6 ), QgsQuadrilateral::Point3 ) );
    8392                 :          1 :   QVERIFY( quad4points_valid.setPoint( QgsPoint( 6, -1 ), QgsQuadrilateral::Point4 ) );
    8393                 :          1 :   QVERIFY( quad4points_valid.isValid() );
    8394                 :          1 :   pts = quad4points_valid.points();
    8395                 :          1 :   QCOMPARE( pts.at( 0 ), QgsPoint( -1, -1 ) );
    8396                 :          1 :   QCOMPARE( pts.at( 1 ), QgsPoint( -1, 6 ) );
    8397                 :          1 :   QCOMPARE( pts.at( 2 ), QgsPoint( 6, 6 ) );
    8398                 :          1 :   QCOMPARE( pts.at( 3 ), QgsPoint( 6, -1 ) );
    8399                 :            : 
    8400                 :            :   // invalid: must have same type
    8401                 :          1 :   QVERIFY( !quad4points_valid.setPoint( QgsPoint( -1, -1, 10 ), QgsQuadrilateral::Point1 ) );
    8402                 :          1 :   QVERIFY( !quad4points_valid.setPoint( QgsPoint( -1, 6, 10 ), QgsQuadrilateral::Point2 ) );
    8403                 :          1 :   QVERIFY( !quad4points_valid.setPoint( QgsPoint( 6, 6, 10 ), QgsQuadrilateral::Point3 ) );
    8404                 :          1 :   QVERIFY( !quad4points_valid.setPoint( QgsPoint( 6, -1, 10 ), QgsQuadrilateral::Point4 ) );
    8405                 :            : 
    8406                 :            :   // invalid self-intersection
    8407                 :          1 :   QVERIFY( !quad4points_valid.setPoint( QgsPoint( 7, 3 ), QgsQuadrilateral::Point1 ) );
    8408                 :          1 :   QVERIFY( !quad4points_valid.setPoint( QgsPoint( 3, 7 ), QgsQuadrilateral::Point1 ) );
    8409                 :          1 :   QVERIFY( !quad4points_valid.setPoint( QgsPoint( 3, -7 ), QgsQuadrilateral::Point2 ) );
    8410                 :          1 :   QVERIFY( !quad4points_valid.setPoint( QgsPoint( 7, 3 ), QgsQuadrilateral::Point2 ) );
    8411                 :          1 :   QVERIFY( !quad4points_valid.setPoint( QgsPoint( 3, -7 ), QgsQuadrilateral::Point3 ) );
    8412                 :          1 :   QVERIFY( !quad4points_valid.setPoint( QgsPoint( -7, 3 ), QgsQuadrilateral::Point3 ) );
    8413                 :          1 :   QVERIFY( !quad4points_valid.setPoint( QgsPoint( 3, 7 ), QgsQuadrilateral::Point4 ) );
    8414                 :          1 :   QVERIFY( !quad4points_valid.setPoint( QgsPoint( -7, 3 ), QgsQuadrilateral::Point4 ) );
    8415                 :            : 
    8416                 :            :   // invalid colinear
    8417                 :          1 :   QVERIFY( !quad4points_valid.setPoint( QgsPoint( 6, -2 ), QgsQuadrilateral::Point1 ) );
    8418                 :          1 :   QVERIFY( !quad4points_valid.setPoint( QgsPoint( -2, 6 ), QgsQuadrilateral::Point1 ) );
    8419                 :          1 :   QVERIFY( !quad4points_valid.setPoint( QgsPoint( 6, 7 ), QgsQuadrilateral::Point2 ) );
    8420                 :          1 :   QVERIFY( !quad4points_valid.setPoint( QgsPoint( -2, -1 ), QgsQuadrilateral::Point2 ) );
    8421                 :          1 :   QVERIFY( !quad4points_valid.setPoint( QgsPoint( 7, -1 ), QgsQuadrilateral::Point3 ) );
    8422                 :          1 :   QVERIFY( !quad4points_valid.setPoint( QgsPoint( -1, 7 ), QgsQuadrilateral::Point3 ) );
    8423                 :          1 :   QVERIFY( !quad4points_valid.setPoint( QgsPoint( -1, -2 ), QgsQuadrilateral::Point4 ) );
    8424                 :          1 :   QVERIFY( !quad4points_valid.setPoint( QgsPoint( 7, 6 ), QgsQuadrilateral::Point4 ) );
    8425                 :            : 
    8426                 :            : //equals
    8427                 :          1 :   QVERIFY( QgsQuadrilateral( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ), QgsPoint( 5, 0 ) ) !=
    8428                 :            :            QgsQuadrilateral( QgsPoint( 0.01, 0.01 ), QgsPoint( 0.01, 5.01 ), QgsPoint( 5.01, 5.01 ), QgsPoint( 5.01, 0.01 ) ) );
    8429                 :          1 :   QVERIFY( QgsQuadrilateral( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ), QgsPoint( 5, 0 ) ).equals(
    8430                 :            :              QgsQuadrilateral( QgsPoint( 0.01, 0.01 ), QgsPoint( 0.01, 5.01 ), QgsPoint( 5.01, 5.01 ), QgsPoint( 5.01, 0.01 ) ), 1e-1 ) );
    8431                 :          1 :   QVERIFY( QgsQuadrilateral( QgsPoint( 0, 0, 0 ), QgsPoint( 0, 5, -0.02 ), QgsPoint( 5, 5, 0 ), QgsPoint( 5, 0, -0.02 ) ).equals(
    8432                 :            :              QgsQuadrilateral( QgsPoint( 0.01, 0.01, 0.01 ), QgsPoint( 0.01, 5.01, 0 ), QgsPoint( 5.01, 5.01, -0.01 ), QgsPoint( 5.01, 0.01, 0.04 ) ), 1e-1 ) );
    8433                 :            : 
    8434                 :            : // rectangleFromExtent
    8435                 :          1 :   QgsQuadrilateral rectangleFromExtent( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ), QgsPoint( 5, 0 ) );
    8436                 :          1 :   QgsQuadrilateral rectangleFromExtentZ( QgsPoint( 0, 0, 10 ), QgsPoint( 0, 5, 10 ), QgsPoint( 5, 5, 10 ), QgsPoint( 5, 0, 10 ) );
    8437                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFromExtent( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ) ), QgsQuadrilateral() );
    8438                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFromExtent( QgsPoint( 0, 0 ), QgsPoint( 0, 10 ) ), QgsQuadrilateral() );
    8439                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFromExtent( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ) ), rectangleFromExtent );
    8440                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFromExtent( QgsPoint( 5, 5 ), QgsPoint( 0, 0 ) ), rectangleFromExtent );
    8441                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFromExtent( QgsPoint( 0, 0, 10 ), QgsPoint( 5, 5 ) ), rectangleFromExtentZ );
    8442                 :          1 :   QVERIFY( QgsQuadrilateral::rectangleFromExtent( QgsPoint( 0, 0 ), QgsPoint( 5, 5, 10 ) ) != rectangleFromExtentZ );
    8443                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFromExtent( QgsPoint( 0, 0 ), QgsPoint( 5, 5, 10 ) ), rectangleFromExtent );
    8444                 :            : 
    8445                 :            : // squareFromDiagonal
    8446                 :          1 :   QgsQuadrilateral squareFromDiagonal( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ), QgsPoint( 5, 0 ) );
    8447                 :          1 :   QgsQuadrilateral squareFromDiagonalZ( QgsPoint( 0, 0, 10 ), QgsPoint( 0, 5, 10 ), QgsPoint( 5, 5, 10 ), QgsPoint( 5, 0, 10 ) );
    8448                 :          1 :   QgsQuadrilateral squareFromDiagonalInv( QgsPoint( 5, 5 ), QgsPoint( 5, 0 ), QgsPoint( 0, 0 ), QgsPoint( 0, 5 ) );
    8449                 :          1 :   QCOMPARE( QgsQuadrilateral::squareFromDiagonal( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ) ), QgsQuadrilateral() );
    8450                 :          1 :   QCOMPARE( QgsQuadrilateral::squareFromDiagonal( QgsPoint( 0, 0 ), QgsPoint( 5, 5 ) ), squareFromDiagonal );
    8451                 :          1 :   QVERIFY( QgsQuadrilateral::squareFromDiagonal( QgsPoint( 5, 5 ), QgsPoint( 0, 0 ) ) != squareFromDiagonal );
    8452                 :          1 :   QVERIFY( QgsQuadrilateral::squareFromDiagonal( QgsPoint( 5, 5 ), QgsPoint( 0, 0 ) ).equals( squareFromDiagonalInv, 1E-8 ) );
    8453                 :          1 :   QCOMPARE( QgsQuadrilateral::squareFromDiagonal( QgsPoint( 0, 0, 10 ), QgsPoint( 5, 5 ) ), squareFromDiagonalZ );
    8454                 :          1 :   QVERIFY( QgsQuadrilateral::squareFromDiagonal( QgsPoint( 0, 0 ), QgsPoint( 5, 5, 10 ) ) != squareFromDiagonalZ );
    8455                 :          1 :   QCOMPARE( QgsQuadrilateral::squareFromDiagonal( QgsPoint( 0, 0 ), QgsPoint( 5, 5, 10 ) ), squareFromDiagonal );
    8456                 :            : 
    8457                 :            : // rectangleFromCenterPoint
    8458                 :          1 :   QgsQuadrilateral rectangleFromCenterPoint( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ), QgsPoint( 5, 0 ) );
    8459                 :          1 :   QgsQuadrilateral rectangleFromCenterPointZ( QgsPoint( 0, 0, 10 ), QgsPoint( 0, 5, 10 ), QgsPoint( 5, 5, 10 ), QgsPoint( 5, 0, 10 ) );
    8460                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFromCenterPoint( QgsPoint( 2.5, 2.5 ), QgsPoint( 2.5, 2.5 ) ), QgsQuadrilateral() ) ;
    8461                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFromCenterPoint( QgsPoint( 2.5, 2.5 ), QgsPoint( 5, 5 ) ), rectangleFromCenterPoint ) ;
    8462                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFromCenterPoint( QgsPoint( 2.5, 2.5 ), QgsPoint( 5, 0 ) ), rectangleFromCenterPoint ) ;
    8463                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFromCenterPoint( QgsPoint( 2.5, 2.5 ), QgsPoint( 0, 5 ) ), rectangleFromCenterPoint ) ;
    8464                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFromCenterPoint( QgsPoint( 2.5, 2.5 ), QgsPoint( 0, 0 ) ), rectangleFromCenterPoint ) ;
    8465                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFromCenterPoint( QgsPoint( 2.5, 2.5, 10 ), QgsPoint( 5, 5 ) ), rectangleFromCenterPointZ ) ;
    8466                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFromCenterPoint( QgsPoint( 2.5, 2.5, 10 ), QgsPoint( 5, 0 ) ), rectangleFromCenterPointZ ) ;
    8467                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFromCenterPoint( QgsPoint( 2.5, 2.5, 10 ), QgsPoint( 0, 5 ) ), rectangleFromCenterPointZ ) ;
    8468                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFromCenterPoint( QgsPoint( 2.5, 2.5, 10 ), QgsPoint( 0, 0 ) ), rectangleFromCenterPointZ ) ;
    8469                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFromCenterPoint( QgsPoint( 2.5, 2.5 ), QgsPoint( 0, 0, 10 ) ), rectangleFromCenterPoint ) ;
    8470                 :            : 
    8471                 :            : // fromRectangle
    8472                 :          1 :   QgsQuadrilateral fromRectangle( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ), QgsPoint( 5, 0 ) );
    8473                 :          1 :   QCOMPARE( QgsQuadrilateral::fromRectangle( QgsRectangle( QgsPointXY( 0, 0 ), QgsPointXY( 0, 0 ) ) ), QgsQuadrilateral() );
    8474                 :          1 :   QCOMPARE( QgsQuadrilateral::fromRectangle( QgsRectangle( QgsPointXY( 0, 0 ), QgsPointXY( 5, 5 ) ) ), fromRectangle ) ;
    8475                 :          1 :   QCOMPARE( QgsQuadrilateral::fromRectangle( QgsRectangle( QgsPointXY( 5, 5 ), QgsPointXY( 0, 0 ) ) ), fromRectangle ) ;
    8476                 :            : // rectangleFrom3points
    8477                 :          1 :   QgsQuadrilateral rectangleFrom3Points( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ), QgsPoint( 5, 0 ) );
    8478                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFrom3Points( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 5 ), QgsQuadrilateral::Distance ), QgsQuadrilateral() );
    8479                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFrom3Points( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 0, 5 ), QgsQuadrilateral::Projected ), QgsQuadrilateral() );
    8480                 :            : 
    8481                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFrom3Points( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ), QgsQuadrilateral::Distance ).toLineString()->asWkt( 0 ),
    8482                 :            :             QString( "LineString (0 0, 0 5, 5 5, 5 0, 0 0)" ) );
    8483                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFrom3Points( QgsPoint( 0, 0, 10 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ), QgsQuadrilateral::Distance ).toLineString()->asWkt( 0 ),
    8484                 :            :             QString( "LineStringZ (0 0 10, 0 5 10, 5 5 10, 5 0 10, 0 0 10)" ) );
    8485                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFrom3Points( QgsPoint( 0, 0 ), QgsPoint( 0, 5, 10 ), QgsPoint( 5, 5 ), QgsQuadrilateral::Distance ).toLineString()->asWkt( 0 ),
    8486                 :            :             QString( "LineStringZ (0 0 10, 0 5 10, 5 5 10, 5 0 10, 0 0 10)" ) );
    8487                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFrom3Points( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5, 10 ), QgsQuadrilateral::Distance ).toLineString()->asWkt( 0 ),
    8488                 :            :             QString( "LineStringZ (0 0 10, 0 5 10, 5 5 10, 5 0 10, 0 0 10)" ) );
    8489                 :            : 
    8490                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFrom3Points( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 4 ), QgsQuadrilateral::Projected ).toLineString()->asWkt( 0 ),
    8491                 :            :             QString( "LineString (0 0, 0 5, 5 5, 5 0, 0 0)" ) );
    8492                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFrom3Points( QgsPoint( 0, 0, 10 ), QgsPoint( 0, 5 ), QgsPoint( 5, 4 ), QgsQuadrilateral::Projected ).toLineString()->asWkt( 0 ),
    8493                 :            :             QString( "LineStringZ (0 0 10, 0 5 10, 5 5 10, 5 0 10, 0 0 10)" ) );
    8494                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFrom3Points( QgsPoint( 0, 0 ), QgsPoint( 0, 5, 10 ), QgsPoint( 5, 4 ), QgsQuadrilateral::Projected ).toLineString()->asWkt( 0 ),
    8495                 :            :             QString( "LineStringZ (0 0 10, 0 5 10, 5 5 10, 5 0 10, 0 0 10)" ) );
    8496                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFrom3Points( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 4, 10 ), QgsQuadrilateral::Projected ).toLineString()->asWkt( 0 ),
    8497                 :            :             QString( "LineStringZ (0 0 10, 0 5 10, 5 5 10, 5 0 10, 0 0 10)" ) );
    8498                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFrom3Points( QgsPoint( 0, 0, 10 ), QgsPoint( 0, 5, 10 ), QgsPoint( 5, 4, 10 ), QgsQuadrilateral::Projected ).toLineString()->asWkt( 0 ),
    8499                 :            :             QString( "LineStringZ (0 0 10, 0 5 10, 5 5 10, 5 0 10, 0 0 10)" ) );
    8500                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFrom3Points( QgsPoint( 0, 0, 5 ), QgsPoint( 0, 5, 5 ), QgsPoint( 5, 5, 0 ), QgsQuadrilateral::Projected ).toString( 2 ),
    8501                 :            :             QString( "Quadrilateral (Point 1: PointZ (0 0 5), Point 2: PointZ (0 5 5), Point 3: PointZ (5 5 0), Point 4: PointZ (5 0 0))" ) );
    8502                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFrom3Points( QgsPoint( 0, 0, 5 ), QgsPoint( 0, 5, 5 ), QgsPoint( 5, 5, 10 ), QgsQuadrilateral::Projected ).toString( 2 ),
    8503                 :            :             QString( "Quadrilateral (Point 1: PointZ (0 0 5), Point 2: PointZ (0 5 5), Point 3: PointZ (5 5 10), Point 4: PointZ (5 0 10))" ) );
    8504                 :            : // toString
    8505                 :          1 :   QCOMPARE( QgsQuadrilateral( ).toString(), QString( "Empty" ) );
    8506                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFromCenterPoint( QgsPoint( 2.5, 2.5 ), QgsPoint( 2.5, 2.5 ) ).toString(), QString( "Empty" ) );
    8507                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFromCenterPoint( QgsPoint( 2.5, 2.5 ), QgsPoint( 5, 0 ) ).toString(), QString( "Quadrilateral (Point 1: Point (0 0), Point 2: Point (0 5), Point 3: Point (5 5), Point 4: Point (5 0))" ) );
    8508                 :          1 :   QCOMPARE( QgsQuadrilateral::rectangleFromCenterPoint( QgsPoint( 2.5, 2.5, 10 ), QgsPoint( 5, 0 ) ).toString(), QString( "Quadrilateral (Point 1: PointZ (0 0 10), Point 2: PointZ (0 5 10), Point 3: PointZ (5 5 10), Point 4: PointZ (5 0 10))" ) );
    8509                 :            : 
    8510                 :            : // toPolygon / toLineString
    8511                 :          1 :   QCOMPARE( quad_init.toPolygon()->asWkt(), QgsPolygon().asWkt() );
    8512                 :          1 :   QCOMPARE( quad_init.toLineString()->asWkt(), QgsLineString().asWkt() );
    8513                 :          1 :   QgsLineString ext, extZ;
    8514                 :          1 :   QgsPolygon polyg, polygZ;
    8515                 :          1 :   QgsQuadrilateral quad( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), QgsPoint( 5, 5 ), QgsPoint( 5, 0 ) );
    8516                 :          1 :   QgsQuadrilateral quadZ( QgsPoint( 0, 0, 10 ), QgsPoint( 0, 5, 10 ), QgsPoint( 5, 5, 10 ), QgsPoint( 5, 0, 10 ) );
    8517                 :          1 :   ext.fromWkt( "LineString (0 0, 0 5, 5 5, 5 0, 0 0)" );
    8518                 :          1 :   QCOMPARE( quad.toLineString()->asWkt(), ext.asWkt() );
    8519                 :          1 :   polyg.fromWkt( "Polygon ((0 0, 0 5, 5 5, 5 0, 0 0))" );
    8520                 :          1 :   QCOMPARE( quad.toPolygon()->asWkt(), polyg.asWkt() );
    8521                 :            : 
    8522                 :          1 :   extZ.fromWkt( "LineStringZ (0 0 10, 0 5 10, 5 5 10, 5 0 10, 0 0 10)" );
    8523                 :          1 :   QCOMPARE( quadZ.toLineString()->asWkt(), extZ.asWkt() );
    8524                 :          1 :   QCOMPARE( quadZ.toLineString( true )->asWkt(), ext.asWkt() );
    8525                 :          1 :   polygZ.fromWkt( "PolygonZ ((0 0 10, 0 5 10, 5 5 10, 5 0 10, 0 0 10))" );
    8526                 :          1 :   QCOMPARE( quadZ.toPolygon()->asWkt(), polygZ.asWkt() );
    8527                 :          1 :   QCOMPARE( quadZ.toPolygon( true )->asWkt(), polyg.asWkt() );
    8528                 :            : 
    8529                 :            : 
    8530                 :            : // area / perimeter
    8531                 :            : 
    8532                 :          1 :   QCOMPARE( QgsQuadrilateral().area(), 0.0 );
    8533                 :          1 :   QCOMPARE( QgsQuadrilateral().perimeter(), 0.0 );
    8534                 :            : 
    8535                 :          1 :   QVERIFY( qgsDoubleNear( QgsQuadrilateral::rectangleFrom3Points( QgsPoint( 0, 0, 10 ), QgsPoint( 0, 5 ), QgsPoint( 5, 4 ), QgsQuadrilateral::Projected ).area(), 25.0 ) );
    8536                 :          1 :   QVERIFY( qgsDoubleNear( QgsQuadrilateral::rectangleFrom3Points( QgsPoint( 0, 0, 10 ), QgsPoint( 0, 5 ), QgsPoint( 5, 4 ), QgsQuadrilateral::Projected ).perimeter(), 20 ) );
    8537                 :          1 : }
    8538                 :            : 
    8539                 :          1 : void TestQgsGeometry::regularPolygon()
    8540                 :            : {
    8541                 :            :   // constructors
    8542                 :          1 :   QgsRegularPolygon rp1 = QgsRegularPolygon();
    8543                 :          1 :   QVERIFY( rp1.center().isEmpty() );
    8544                 :          1 :   QVERIFY( rp1.firstVertex().isEmpty() );
    8545                 :          1 :   QCOMPARE( rp1.numberSides(), static_cast< unsigned int >( 0 ) );
    8546                 :          1 :   QCOMPARE( rp1.radius(), 0.0 );
    8547                 :          1 :   QVERIFY( rp1.isEmpty() );
    8548                 :            : 
    8549                 :          1 :   QgsRegularPolygon rp2;
    8550                 :          1 :   QgsRegularPolygon( QgsPoint( 0, 0 ), 5, 0, 2, QgsRegularPolygon::InscribedCircle );
    8551                 :          1 :   QVERIFY( rp2.isEmpty() );
    8552                 :          1 :   QgsRegularPolygon( QgsPoint( 0, 0 ), 5, 0, 5, static_cast< QgsRegularPolygon::ConstructionOption >( 4 ) );
    8553                 :          1 :   QVERIFY( rp2.isEmpty() );
    8554                 :            : 
    8555                 :          1 :   rp2 = QgsRegularPolygon( QgsPoint( 0, 0 ), 5, 0, 5, QgsRegularPolygon::InscribedCircle );
    8556                 :          1 :   QVERIFY( !rp2.isEmpty() );
    8557                 :          1 :   QCOMPARE( rp2.center(), QgsPoint( 0, 0 ) );
    8558                 :          1 :   QCOMPARE( rp2.firstVertex(), QgsPoint( 0, 5 ) );
    8559                 :          1 :   QCOMPARE( rp2.numberSides(), static_cast< unsigned int>( 5 ) );
    8560                 :          1 :   QCOMPARE( rp2.radius(), 5.0 );
    8561                 :          1 :   QGSCOMPARENEAR( rp2.apothem(), 4.0451, 10E-4 );
    8562                 :          1 :   QVERIFY( rp2 ==  QgsRegularPolygon( QgsPoint( 0, 0 ), -5, 0, 5, QgsRegularPolygon::InscribedCircle ) );
    8563                 :            : 
    8564                 :          1 :   QgsRegularPolygon rp3 = QgsRegularPolygon( QgsPoint( 0, 0 ), rp2.apothem(), 36.0, 5, QgsRegularPolygon::CircumscribedCircle );
    8565                 :          1 :   QVERIFY( rp2 == rp3 );
    8566                 :          1 :   QVERIFY( rp2 == QgsRegularPolygon( QgsPoint( 0, 0 ), -rp2.apothem(), 36.0, 5, QgsRegularPolygon::CircumscribedCircle ) );
    8567                 :          1 :   QVERIFY( rp1 != rp3 );
    8568                 :          1 :   QVERIFY( rp1 != QgsRegularPolygon( QgsPoint( 5, 5 ), rp2.apothem(), 36.0, 5, QgsRegularPolygon::CircumscribedCircle ) );
    8569                 :          1 :   QVERIFY( rp1 != QgsRegularPolygon( QgsPoint( 0, 0 ), 5, 36.0, 5, QgsRegularPolygon::CircumscribedCircle ) );
    8570                 :          1 :   QVERIFY( rp1 != QgsRegularPolygon( QgsPoint( 0, 0 ), 5, 36.0, 5, QgsRegularPolygon::InscribedCircle ) );
    8571                 :            : 
    8572                 :          1 :   QgsRegularPolygon rp4 = QgsRegularPolygon( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), 2, QgsRegularPolygon::InscribedCircle );
    8573                 :          1 :   QVERIFY( rp4.isEmpty() );
    8574                 :          1 :   rp4 = QgsRegularPolygon( QgsPoint(), QgsPoint( 0, 5 ), 5, static_cast< QgsRegularPolygon::ConstructionOption >( 4 ) );
    8575                 :          1 :   QVERIFY( rp4.isEmpty() );
    8576                 :          1 :   rp4 = QgsRegularPolygon( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), 5, QgsRegularPolygon::InscribedCircle );
    8577                 :          1 :   QVERIFY( rp4 == rp2 );
    8578                 :            : 
    8579                 :          1 :   QgsRegularPolygon rp5 = QgsRegularPolygon( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ).project( rp2.apothem(), 36.0 ), 2, QgsRegularPolygon::CircumscribedCircle );
    8580                 :          1 :   QVERIFY( rp5.isEmpty() );
    8581                 :          1 :   rp5 = QgsRegularPolygon( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ).project( rp2.apothem(), 36.0 ), 5, static_cast< QgsRegularPolygon::ConstructionOption >( 4 ) );
    8582                 :          1 :   QVERIFY( rp5.isEmpty() );
    8583                 :          1 :   rp5 = QgsRegularPolygon( QgsPoint( 0, 0 ), QgsPoint( 0, 0 ).project( rp2.apothem(), 36.0 ), 5, QgsRegularPolygon::CircumscribedCircle );
    8584                 :          1 :   QVERIFY( rp5 == rp2 );
    8585                 :            : 
    8586                 :          1 :   QgsRegularPolygon rp6 = QgsRegularPolygon( QgsPoint( 0, 5 ), QgsPoint( 0, 0 ).project( 5.0, 72 ), 5 );
    8587                 :          1 :   QVERIFY( rp6 == rp2 );
    8588                 :            : 
    8589                 :            : 
    8590                 :            :   // setters and getters
    8591                 :          1 :   QgsRegularPolygon rp7 = QgsRegularPolygon();
    8592                 :            : 
    8593                 :          1 :   rp7.setCenter( QgsPoint( 5, 5 ) );
    8594                 :          1 :   QVERIFY( rp7.isEmpty() );
    8595                 :          1 :   QCOMPARE( rp7.center(), QgsPoint( 5, 5 ) );
    8596                 :            : 
    8597                 :          1 :   rp7.setNumberSides( 2 );
    8598                 :          1 :   QVERIFY( rp7.isEmpty() );
    8599                 :          1 :   QCOMPARE( rp7.numberSides(), static_cast< unsigned int >( 0 ) );
    8600                 :          1 :   rp7.setNumberSides( 5 );
    8601                 :          1 :   QVERIFY( rp7.isEmpty() );
    8602                 :          1 :   QCOMPARE( rp7.numberSides(), static_cast< unsigned int >( 5 ) );
    8603                 :          1 :   rp7.setNumberSides( 2 );
    8604                 :          1 :   QVERIFY( rp7.isEmpty() );
    8605                 :          1 :   QCOMPARE( rp7.numberSides(), static_cast< unsigned int >( 5 ) );
    8606                 :          1 :   rp7.setNumberSides( 3 );
    8607                 :          1 :   QVERIFY( rp7.isEmpty() );
    8608                 :          1 :   QCOMPARE( rp7.numberSides(), static_cast< unsigned int >( 3 ) );
    8609                 :            : 
    8610                 :          1 :   rp7.setRadius( -6 );
    8611                 :          1 :   QVERIFY( !rp7.isEmpty() );
    8612                 :          1 :   QCOMPARE( rp7.radius(), 6.0 );
    8613                 :          1 :   QCOMPARE( rp7.firstVertex(), rp7.center().project( 6, 0 ) );
    8614                 :            : 
    8615                 :          1 :   rp7.setFirstVertex( QgsPoint( 4, 4 ) );
    8616                 :          1 :   QCOMPARE( rp7.firstVertex(), QgsPoint( 4, 4 ) );
    8617                 :          1 :   QCOMPARE( rp7.radius(), rp7.center().distance3D( QgsPoint( 4, 4 ) ) );
    8618                 :            : 
    8619                 :          1 :   rp7 = QgsRegularPolygon( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), 5, QgsRegularPolygon::InscribedCircle );
    8620                 :          1 :   rp7.setCenter( QgsPoint( 5, 5 ) );
    8621                 :          1 :   QCOMPARE( rp7.radius(), 5.0 );
    8622                 :          1 :   QCOMPARE( rp7.firstVertex(), QgsPoint( 5, 10 ) );
    8623                 :          1 :   rp7.setNumberSides( 3 );
    8624                 :          1 :   QCOMPARE( rp7.radius(), 5.0 );
    8625                 :          1 :   QCOMPARE( rp7.firstVertex(), QgsPoint( 5, 10 ) );
    8626                 :          1 :   rp7.setNumberSides( 2 );
    8627                 :          1 :   QCOMPARE( rp7.radius(), 5.0 );
    8628                 :          1 :   QCOMPARE( rp7.firstVertex(), QgsPoint( 5, 10 ) );
    8629                 :            : 
    8630                 :            :   // measures
    8631                 :          1 :   QGSCOMPARENEAR( rp1.length(), 0.0, 10e-4 );
    8632                 :          1 :   QGSCOMPARENEAR( rp1.area(), 0.0, 10e-4 );
    8633                 :          1 :   QGSCOMPARENEAR( rp1.perimeter(), 0.0, 10e-4 );
    8634                 :          1 :   QGSCOMPARENEAR( rp2.length(), 5.8779, 10e-4 );
    8635                 :          1 :   QGSCOMPARENEAR( rp2.area(), 59.4410, 10e-4 );
    8636                 :          1 :   QGSCOMPARENEAR( rp2.perimeter(), 29.3893, 10e-4 );
    8637                 :          1 :   QCOMPARE( rp2.interiorAngle(), 108.0 );
    8638                 :          1 :   QCOMPARE( rp2.centralAngle(), 72.0 );
    8639                 :          1 :   QgsRegularPolygon rp8 = QgsRegularPolygon( QgsPoint( 0, 0 ), QgsPoint( 5, 0 ), 5 );
    8640                 :          1 :   QGSCOMPARENEAR( rp8.area(), 43.0119, 10e-4 );
    8641                 :          1 :   QCOMPARE( rp8.perimeter(), 25.0 );
    8642                 :          1 :   QCOMPARE( rp8.length(), 5.0 );
    8643                 :          1 :   QCOMPARE( rp8.interiorAngle(), 108.0 );
    8644                 :          1 :   QCOMPARE( rp8.centralAngle(), 72.0 );
    8645                 :          1 :   rp8.setNumberSides( 4 );
    8646                 :          1 :   QCOMPARE( rp8.interiorAngle(), 90.0 );
    8647                 :          1 :   QCOMPARE( rp8.centralAngle(), 90.0 );
    8648                 :          1 :   rp8.setNumberSides( 3 );
    8649                 :          1 :   QCOMPARE( rp8.interiorAngle(), 60.0 );
    8650                 :          1 :   QCOMPARE( rp8.centralAngle(), 120.0 );
    8651                 :            : 
    8652                 :            :   //points
    8653                 :          1 :   rp8 = QgsRegularPolygon(); // empty
    8654                 :          1 :   QgsPointSequence points = rp8.points();
    8655                 :          1 :   QVERIFY( points.isEmpty() );
    8656                 :          1 :   rp8 = QgsRegularPolygon( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), 3, QgsRegularPolygon::InscribedCircle );
    8657                 :          1 :   points = rp8.points();
    8658                 :          1 :   QCOMPARE( points.count(), 3 );
    8659                 :          1 :   QCOMPARE( points.at( 0 ), QgsPoint( 0, 5 ) );
    8660                 :          1 :   QGSCOMPARENEAR( points.at( 1 ).x(), 4.33, 0.01 );
    8661                 :          1 :   QGSCOMPARENEAR( points.at( 1 ).y(), -2.4999, 0.01 );
    8662                 :          1 :   QGSCOMPARENEAR( points.at( 2 ).x(), -4.33, 0.01 );
    8663                 :          1 :   QGSCOMPARENEAR( points.at( 2 ).y(), -2.4999, 0.01 );
    8664                 :            : 
    8665                 :            :   //test conversions
    8666                 :            :   // circle
    8667                 :          1 :   QVERIFY( QgsCircle( QgsPoint( 0, 0 ), 5 ) == rp2.circumscribedCircle() );
    8668                 :          1 :   QVERIFY( rp2.inscribedCircle() == QgsRegularPolygon( QgsPoint( 0, 0 ), rp2.apothem(), 36.0, 5, QgsRegularPolygon::InscribedCircle ).circumscribedCircle() );
    8669                 :            : 
    8670                 :            :   // triangle
    8671                 :          1 :   QCOMPARE( QgsTriangle(), rp2.toTriangle() );
    8672                 :          1 :   QCOMPARE( QgsTriangle(), QgsRegularPolygon().toTriangle() );
    8673                 :          1 :   QgsRegularPolygon rp9 = QgsRegularPolygon( QgsPoint( 0, 0 ), 5, 0, 3, QgsRegularPolygon::InscribedCircle );
    8674                 :            : 
    8675                 :          1 :   QVERIFY( QgsCircle( QgsPoint( 0, 0 ), 5 ) == rp9.toTriangle().circumscribedCircle() );
    8676                 :            : 
    8677                 :          1 :   QgsRegularPolygon rp10 = QgsRegularPolygon( QgsPoint( 0, 0 ), QgsPoint( 0, 4 ), 4 );
    8678                 :          1 :   QVector<QgsTriangle> rp10_tri = rp10.triangulate();
    8679                 :          1 :   QCOMPARE( rp10_tri.length(), static_cast< int >( rp10.numberSides() ) );
    8680                 :          1 :   QVERIFY( rp10_tri.at( 0 ) == QgsTriangle( QgsPoint( 0, 0 ), QgsPoint( 0, 4 ), rp10.center() ) );
    8681                 :          1 :   QVERIFY( rp10_tri.at( 1 ) == QgsTriangle( QgsPoint( 0, 4 ), QgsPoint( 4, 4 ), rp10.center() ) );
    8682                 :          1 :   QVERIFY( rp10_tri.at( 2 ) == QgsTriangle( QgsPoint( 4, 4 ), QgsPoint( 4, 0 ), rp10.center() ) );
    8683                 :          1 :   QVERIFY( rp10_tri.at( 3 ) == QgsTriangle( QgsPoint( 4, 0 ), QgsPoint( 0, 0 ), rp10.center() ) );
    8684                 :            : 
    8685                 :          1 :   QVERIFY( QgsRegularPolygon().triangulate().isEmpty() );
    8686                 :            : 
    8687                 :            :   // polygon
    8688                 :          1 :   std::unique_ptr< QgsPolygon > toP( QgsRegularPolygon().toPolygon() );
    8689                 :          1 :   QVERIFY( toP->isEmpty() );
    8690                 :            : 
    8691                 :          1 :   QgsPointSequence ptsPol;
    8692                 :          1 :   std::unique_ptr< QgsPolygon > pol( new QgsPolygon() );
    8693                 :          1 :   pol.reset( rp10.toPolygon() );
    8694                 :          1 :   QCOMPARE( pol->numInteriorRings(), 0 );
    8695                 :          1 :   QCOMPARE( pol->exteriorRing()->numPoints(), 5 );
    8696                 :            : 
    8697                 :          1 :   pol->exteriorRing()->points( ptsPol );
    8698                 :          1 :   QCOMPARE( ptsPol.length(), 5 );
    8699                 :          1 :   QVERIFY( ptsPol.at( 0 ) == QgsPoint( 0, 0 ) );
    8700                 :          1 :   QVERIFY( ptsPol.at( 1 ) == QgsPoint( 0, 4 ) );
    8701                 :          1 :   QVERIFY( ptsPol.at( 2 ) == QgsPoint( 4, 4 ) );
    8702                 :          1 :   QVERIFY( ptsPol.at( 3 ) == QgsPoint( 4, 0 ) );
    8703                 :          1 :   QVERIFY( ptsPol.at( 4 ) == QgsPoint( 0, 0 ) );
    8704                 :          1 :   ptsPol.pop_back();
    8705                 :            : 
    8706                 :          1 :   std::unique_ptr< QgsLineString > l( QgsRegularPolygon( QgsPoint( 0, 0 ), QgsPoint( 0, 5 ), 1, QgsRegularPolygon::InscribedCircle ).toLineString() );
    8707                 :          1 :   QVERIFY( l->isEmpty() );
    8708                 :          1 :   l.reset( rp10.toLineString( ) );
    8709                 :          1 :   QCOMPARE( l->numPoints(), 5 );
    8710                 :          1 :   QCOMPARE( l->pointN( 0 ), l->pointN( 4 ) );
    8711                 :          1 :   QgsPointSequence pts_l;
    8712                 :          1 :   l->points( pts_l );
    8713                 :          1 :   pts_l.pop_back();
    8714                 :          1 :   QCOMPARE( ptsPol, pts_l );
    8715                 :            : 
    8716                 :            :   //test toString
    8717                 :          1 :   QCOMPARE( rp1.toString(), QString( "Empty" ) );
    8718                 :          1 :   QCOMPARE( rp2.toString(), QString( "RegularPolygon (Center: Point (0 0), First Vertex: Point (0 5), Radius: 5, Azimuth: 0)" ) );
    8719                 :            : 
    8720                 :          1 : }
    8721                 :            : 
    8722                 :            : 
    8723                 :          1 : void TestQgsGeometry::curvePolygon()
    8724                 :            : {
    8725                 :            :   //test constructor
    8726                 :          1 :   QgsCurvePolygon p1;
    8727                 :          1 :   QVERIFY( p1.isEmpty() );
    8728                 :          1 :   QCOMPARE( p1.numInteriorRings(), 0 );
    8729                 :          1 :   QCOMPARE( p1.nCoordinates(), 0 );
    8730                 :          1 :   QCOMPARE( p1.ringCount(), 0 );
    8731                 :          1 :   QCOMPARE( p1.partCount(), 0 );
    8732                 :          1 :   QVERIFY( !p1.is3D() );
    8733                 :          1 :   QVERIFY( !p1.isMeasure() );
    8734                 :          1 :   QCOMPARE( p1.wkbType(), QgsWkbTypes::CurvePolygon );
    8735                 :          1 :   QCOMPARE( p1.wktTypeStr(), QString( "CurvePolygon" ) );
    8736                 :          1 :   QCOMPARE( p1.geometryType(), QString( "CurvePolygon" ) );
    8737                 :          1 :   QCOMPARE( p1.dimension(), 2 );
    8738                 :          1 :   QVERIFY( !p1.hasCurvedSegments() );
    8739                 :          1 :   QCOMPARE( p1.area(), 0.0 );
    8740                 :          1 :   QCOMPARE( p1.perimeter(), 0.0 );
    8741                 :          1 :   QVERIFY( !p1.exteriorRing() );
    8742                 :          1 :   QVERIFY( !p1.interiorRing( 0 ) );
    8743                 :            : 
    8744                 :            :   //set exterior ring
    8745                 :            : 
    8746                 :            :   //try with no ring
    8747                 :          1 :   QgsCircularString *ext = nullptr;
    8748                 :          1 :   p1.setExteriorRing( ext );
    8749                 :          1 :   QVERIFY( p1.isEmpty() );
    8750                 :          1 :   QCOMPARE( p1.numInteriorRings(), 0 );
    8751                 :          1 :   QCOMPARE( p1.nCoordinates(), 0 );
    8752                 :          1 :   QCOMPARE( p1.ringCount(), 0 );
    8753                 :          1 :   QCOMPARE( p1.partCount(), 0 );
    8754                 :          1 :   QVERIFY( !p1.exteriorRing() );
    8755                 :          1 :   QVERIFY( !p1.interiorRing( 0 ) );
    8756                 :          1 :   QCOMPARE( p1.wkbType(), QgsWkbTypes::CurvePolygon );
    8757                 :            : 
    8758                 :            :   // empty exterior ring
    8759                 :          1 :   ext = new QgsCircularString();
    8760                 :          1 :   p1.setExteriorRing( ext );
    8761                 :          1 :   QVERIFY( p1.isEmpty() );
    8762                 :          1 :   QCOMPARE( p1.numInteriorRings(), 0 );
    8763                 :          1 :   QCOMPARE( p1.nCoordinates(), 0 );
    8764                 :          1 :   QCOMPARE( p1.ringCount(), 1 );
    8765                 :          1 :   QCOMPARE( p1.partCount(), 1 );
    8766                 :          1 :   QVERIFY( p1.exteriorRing() );
    8767                 :          1 :   QVERIFY( !p1.interiorRing( 0 ) );
    8768                 :          1 :   QCOMPARE( p1.wkbType(), QgsWkbTypes::CurvePolygon );
    8769                 :            : 
    8770                 :            :   //valid exterior ring
    8771                 :          1 :   ext = new QgsCircularString();
    8772                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
    8773                 :          1 :                   << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) );
    8774                 :          1 :   p1.setExteriorRing( ext );
    8775                 :          1 :   QVERIFY( !p1.isEmpty() );
    8776                 :          1 :   QCOMPARE( p1.numInteriorRings(), 0 );
    8777                 :          1 :   QCOMPARE( p1.nCoordinates(), 5 );
    8778                 :          1 :   QCOMPARE( p1.ringCount(), 1 );
    8779                 :          1 :   QCOMPARE( p1.partCount(), 1 );
    8780                 :          1 :   QVERIFY( !p1.is3D() );
    8781                 :          1 :   QVERIFY( !p1.isMeasure() );
    8782                 :          1 :   QCOMPARE( p1.wkbType(), QgsWkbTypes::CurvePolygon );
    8783                 :          1 :   QCOMPARE( p1.wktTypeStr(), QString( "CurvePolygon" ) );
    8784                 :          1 :   QCOMPARE( p1.geometryType(), QString( "CurvePolygon" ) );
    8785                 :          1 :   QCOMPARE( p1.dimension(), 2 );
    8786                 :          1 :   QVERIFY( p1.hasCurvedSegments() );
    8787                 :          1 :   QGSCOMPARENEAR( p1.area(), 157.08, 0.01 );
    8788                 :          1 :   QGSCOMPARENEAR( p1.perimeter(), 44.4288, 0.01 );
    8789                 :          1 :   QVERIFY( p1.exteriorRing() );
    8790                 :          1 :   QVERIFY( !p1.interiorRing( 0 ) );
    8791                 :            : 
    8792                 :            :   //retrieve exterior ring and check
    8793                 :          1 :   QCOMPARE( *( static_cast< const QgsCircularString * >( p1.exteriorRing() ) ), *ext );
    8794                 :            : 
    8795                 :            :   //initial setting of exterior ring should set z/m type
    8796                 :          1 :   QgsCurvePolygon p2;
    8797                 :          1 :   ext = new QgsCircularString();
    8798                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 )
    8799                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 0, 10, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 10, 10, 3 )
    8800                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 10, 0, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 ) );
    8801                 :          1 :   p2.setExteriorRing( ext );
    8802                 :          1 :   QVERIFY( p2.is3D() );
    8803                 :          1 :   QVERIFY( !p2.isMeasure() );
    8804                 :          1 :   QCOMPARE( p2.wkbType(), QgsWkbTypes::CurvePolygonZ );
    8805                 :          1 :   QCOMPARE( p2.wktTypeStr(), QString( "CurvePolygonZ" ) );
    8806                 :          1 :   QCOMPARE( p2.geometryType(), QString( "CurvePolygon" ) );
    8807                 :          1 :   QCOMPARE( *( static_cast< const QgsCircularString * >( p2.exteriorRing() ) ), *ext );
    8808                 :          1 :   QgsCurvePolygon p3;
    8809                 :          1 :   ext = new QgsCircularString();
    8810                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 0, 0, 0, 1 )
    8811                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 0, 10, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 10, 10, 0, 3 )
    8812                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 10, 0, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 0, 0, 0, 1 ) );
    8813                 :          1 :   p3.setExteriorRing( ext );
    8814                 :          1 :   QVERIFY( !p3.is3D() );
    8815                 :          1 :   QVERIFY( p3.isMeasure() );
    8816                 :          1 :   QCOMPARE( p3.wkbType(), QgsWkbTypes::CurvePolygonM );
    8817                 :          1 :   QCOMPARE( p3.wktTypeStr(), QString( "CurvePolygonM" ) );
    8818                 :          1 :   QCOMPARE( *( static_cast< const QgsCircularString * >( p3.exteriorRing() ) ), *ext );
    8819                 :          1 :   QgsCurvePolygon p4;
    8820                 :          1 :   ext = new QgsCircularString();
    8821                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 2, 1 )
    8822                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 0, 10, 3, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 10, 10, 5, 3 )
    8823                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 10, 0, 0, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 2, 1 ) );
    8824                 :          1 :   p4.setExteriorRing( ext );
    8825                 :          1 :   QVERIFY( p4.is3D() );
    8826                 :          1 :   QVERIFY( p4.isMeasure() );
    8827                 :          1 :   QCOMPARE( p4.wkbType(), QgsWkbTypes::CurvePolygonZM );
    8828                 :          1 :   QCOMPARE( p4.wktTypeStr(), QString( "CurvePolygonZM" ) );
    8829                 :          1 :   QCOMPARE( *( static_cast< const QgsCircularString * >( p4.exteriorRing() ) ), *ext );
    8830                 :            : 
    8831                 :            :   //addInteriorRing
    8832                 :          1 :   QgsCurvePolygon p6;
    8833                 :          1 :   ext = new QgsCircularString();
    8834                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
    8835                 :          1 :                   << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) );
    8836                 :          1 :   p6.setExteriorRing( ext );
    8837                 :            :   //empty ring
    8838                 :          1 :   QCOMPARE( p6.numInteriorRings(), 0 );
    8839                 :          1 :   QVERIFY( !p6.interiorRing( -1 ) );
    8840                 :          1 :   QVERIFY( !p6.interiorRing( 0 ) );
    8841                 :          1 :   p6.addInteriorRing( nullptr );
    8842                 :          1 :   QCOMPARE( p6.numInteriorRings(), 0 );
    8843                 :          1 :   QgsCircularString *ring = new QgsCircularString();
    8844                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( 1, 1 ) << QgsPoint( 1, 9 ) << QgsPoint( 9, 9 )
    8845                 :          1 :                    << QgsPoint( 9, 1 ) << QgsPoint( 1, 1 ) );
    8846                 :          1 :   p6.addInteriorRing( ring );
    8847                 :          1 :   QCOMPARE( p6.numInteriorRings(), 1 );
    8848                 :          1 :   QCOMPARE( p6.interiorRing( 0 ), ring );
    8849                 :          1 :   QVERIFY( !p6.interiorRing( 1 ) );
    8850                 :            : 
    8851                 :          1 :   QgsCoordinateSequence seq = p6.coordinateSequence();
    8852                 :          1 :   QCOMPARE( seq, QgsCoordinateSequence() << ( QgsRingSequence() << ( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
    8853                 :            :             << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) )
    8854                 :            :             << ( QgsPointSequence() << QgsPoint( 1, 1 ) << QgsPoint( 1, 9 ) << QgsPoint( 9, 9 )
    8855                 :            :                  << QgsPoint( 9, 1 ) << QgsPoint( 1, 1 ) ) ) );
    8856                 :          1 :   QCOMPARE( p6.nCoordinates(), 10 );
    8857                 :            : 
    8858                 :            :   //try adding an interior ring with z to a 2d polygon, z should be dropped
    8859                 :          1 :   ring = new QgsCircularString();
    8860                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.1, 1 )
    8861                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.2, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 0.2, 0.2, 3 )
    8862                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZ, 0.2, 0.1, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.1, 1 ) );
    8863                 :          1 :   p6.addInteriorRing( ring );
    8864                 :          1 :   QCOMPARE( p6.numInteriorRings(), 2 );
    8865                 :          1 :   QVERIFY( !p6.is3D() );
    8866                 :          1 :   QVERIFY( !p6.isMeasure() );
    8867                 :          1 :   QCOMPARE( p6.wkbType(), QgsWkbTypes::CurvePolygon );
    8868                 :          1 :   QVERIFY( p6.interiorRing( 1 ) );
    8869                 :          1 :   QVERIFY( !p6.interiorRing( 1 )->is3D() );
    8870                 :          1 :   QVERIFY( !p6.interiorRing( 1 )->isMeasure() );
    8871                 :          1 :   QCOMPARE( p6.interiorRing( 1 )->wkbType(), QgsWkbTypes::CircularString );
    8872                 :            : 
    8873                 :            :   //try adding an interior ring with m to a 2d polygon, m should be dropped
    8874                 :          1 :   ring = new QgsCircularString();
    8875                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 0.1, 0.1, 0, 1 )
    8876                 :          1 :                    << QgsPoint( QgsWkbTypes::PointM, 0.1, 0.2, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 0.2, 0.2, 0, 3 )
    8877                 :          1 :                    << QgsPoint( QgsWkbTypes::PointM, 0.2, 0.1, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 0.1, 0.1, 0, 1 ) );
    8878                 :          1 :   p6.addInteriorRing( ring );
    8879                 :          1 :   QCOMPARE( p6.numInteriorRings(), 3 );
    8880                 :          1 :   QVERIFY( !p6.is3D() );
    8881                 :          1 :   QVERIFY( !p6.isMeasure() );
    8882                 :          1 :   QCOMPARE( p6.wkbType(), QgsWkbTypes::CurvePolygon );
    8883                 :          1 :   QVERIFY( p6.interiorRing( 2 ) );
    8884                 :          1 :   QVERIFY( !p6.interiorRing( 2 )->is3D() );
    8885                 :          1 :   QVERIFY( !p6.interiorRing( 2 )->isMeasure() );
    8886                 :          1 :   QCOMPARE( p6.interiorRing( 2 )->wkbType(), QgsWkbTypes::CircularString );
    8887                 :            : 
    8888                 :            : 
    8889                 :            :   //addInteriorRing without z/m to PolygonZM
    8890                 :          1 :   QgsCurvePolygon p6b;
    8891                 :          1 :   ext = new QgsCircularString();
    8892                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1 )
    8893                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 0, 10, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 10, 10, 3 )
    8894                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1 ) );
    8895                 :          1 :   p6b.setExteriorRing( ext );
    8896                 :          1 :   QVERIFY( p6b.is3D() );
    8897                 :          1 :   QVERIFY( p6b.isMeasure() );
    8898                 :          1 :   QCOMPARE( p6b.wkbType(), QgsWkbTypes::CurvePolygonZM );
    8899                 :            :   //ring has no z
    8900                 :          1 :   ring = new QgsCircularString();
    8901                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 1, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 1, 9 ) << QgsPoint( QgsWkbTypes::PointM, 9, 9 )
    8902                 :          1 :                    << QgsPoint( QgsWkbTypes::PointM, 9, 1 ) << QgsPoint( QgsWkbTypes::PointM, 1, 1 ) );
    8903                 :          1 :   p6b.addInteriorRing( ring );
    8904                 :          1 :   QVERIFY( p6b.interiorRing( 0 ) );
    8905                 :          1 :   QVERIFY( p6b.interiorRing( 0 )->is3D() );
    8906                 :          1 :   QVERIFY( p6b.interiorRing( 0 )->isMeasure() );
    8907                 :          1 :   QCOMPARE( p6b.interiorRing( 0 )->wkbType(), QgsWkbTypes::CircularStringZM );
    8908                 :          1 :   QCOMPARE( p6b.interiorRing( 0 )->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::PointZM, 1, 1, 0, 2 ) );
    8909                 :            :   //ring has no m
    8910                 :          1 :   ring = new QgsCircularString();
    8911                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.1, 1 )
    8912                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.2, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 0.2, 0.2, 3 )
    8913                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZ, 0.2, 0.1, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.1, 1 ) );
    8914                 :          1 :   p6b.addInteriorRing( ring );
    8915                 :          1 :   QVERIFY( p6b.interiorRing( 1 ) );
    8916                 :          1 :   QVERIFY( p6b.interiorRing( 1 )->is3D() );
    8917                 :          1 :   QVERIFY( p6b.interiorRing( 1 )->isMeasure() );
    8918                 :          1 :   QCOMPARE( p6b.interiorRing( 1 )->wkbType(), QgsWkbTypes::CircularStringZM );
    8919                 :          1 :   QCOMPARE( p6b.interiorRing( 1 )->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::PointZM, 0.1, 0.1, 1, 0 ) );
    8920                 :            : 
    8921                 :            :   //set interior rings
    8922                 :          1 :   QgsCurvePolygon p7;
    8923                 :          1 :   ext = new QgsCircularString();
    8924                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
    8925                 :          1 :                   << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) );
    8926                 :          1 :   p7.setExteriorRing( ext );
    8927                 :            :   //add a list of rings with mixed types
    8928                 :          1 :   QVector< QgsCurve * > rings;
    8929                 :          1 :   rings << new QgsCircularString();
    8930                 :          2 :   static_cast< QgsCircularString *>( rings[0] )->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.1, 1 )
    8931                 :          1 :       << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.2, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 0.2, 0.2, 3 )
    8932                 :          1 :       << QgsPoint( QgsWkbTypes::PointZ, 0.2, 0.1, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.1, 1 ) );
    8933                 :          1 :   rings << new QgsCircularString();
    8934                 :          2 :   static_cast< QgsCircularString *>( rings[1] )->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 0.3, 0.3, 0, 1 )
    8935                 :          1 :       << QgsPoint( QgsWkbTypes::PointM, 0.3, 0.4, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 0.4, 0.4, 0, 3 )
    8936                 :          1 :       << QgsPoint( QgsWkbTypes::PointM, 0.4, 0.3, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 0.3, 0.3, 0, 1 ) );
    8937                 :            :   //throw an empty ring in too
    8938                 :          1 :   rings << 0;
    8939                 :          1 :   rings << new QgsCircularString();
    8940                 :          2 :   static_cast< QgsCircularString *>( rings[3] )->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
    8941                 :          1 :       << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) );
    8942                 :          1 :   p7.setInteriorRings( rings );
    8943                 :          1 :   QCOMPARE( p7.numInteriorRings(), 3 );
    8944                 :          1 :   QVERIFY( p7.interiorRing( 0 ) );
    8945                 :          1 :   QVERIFY( !p7.interiorRing( 0 )->is3D() );
    8946                 :          1 :   QVERIFY( !p7.interiorRing( 0 )->isMeasure() );
    8947                 :          1 :   QCOMPARE( p7.interiorRing( 0 )->wkbType(), QgsWkbTypes::CircularString );
    8948                 :          1 :   QCOMPARE( p7.interiorRing( 0 )->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::Point, 0.1, 0.1 ) );
    8949                 :          1 :   QVERIFY( p7.interiorRing( 1 ) );
    8950                 :          1 :   QVERIFY( !p7.interiorRing( 1 )->is3D() );
    8951                 :          1 :   QVERIFY( !p7.interiorRing( 1 )->isMeasure() );
    8952                 :          1 :   QCOMPARE( p7.interiorRing( 1 )->wkbType(), QgsWkbTypes::CircularString );
    8953                 :          1 :   QCOMPARE( p7.interiorRing( 1 )->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::Point, 0.3, 0.3 ) );
    8954                 :          1 :   QVERIFY( p7.interiorRing( 2 ) );
    8955                 :          1 :   QVERIFY( !p7.interiorRing( 2 )->is3D() );
    8956                 :          1 :   QVERIFY( !p7.interiorRing( 2 )->isMeasure() );
    8957                 :          1 :   QCOMPARE( p7.interiorRing( 2 )->wkbType(), QgsWkbTypes::CircularString );
    8958                 :            : 
    8959                 :            :   //set rings with existing
    8960                 :          1 :   rings.clear();
    8961                 :          1 :   rings << new QgsCircularString();
    8962                 :          2 :   static_cast< QgsCircularString *>( rings[0] )->setPoints( QgsPointSequence() << QgsPoint( 0.8, 0.8 )
    8963                 :          1 :       << QgsPoint( 0.8, 0.9 ) << QgsPoint( 0.9, 0.9 )
    8964                 :          1 :       << QgsPoint( 0.9, 0.8 ) << QgsPoint( 0.8, 0.8 ) );
    8965                 :          1 :   p7.setInteriorRings( rings );
    8966                 :          1 :   QCOMPARE( p7.numInteriorRings(), 1 );
    8967                 :          1 :   QVERIFY( p7.interiorRing( 0 ) );
    8968                 :          1 :   QVERIFY( !p7.interiorRing( 0 )->is3D() );
    8969                 :          1 :   QVERIFY( !p7.interiorRing( 0 )->isMeasure() );
    8970                 :          1 :   QCOMPARE( p7.interiorRing( 0 )->wkbType(), QgsWkbTypes::CircularString );
    8971                 :          1 :   QCOMPARE( p7.interiorRing( 0 )->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::Point, 0.8, 0.8 ) );
    8972                 :          1 :   rings.clear();
    8973                 :          1 :   p7.setInteriorRings( rings );
    8974                 :          1 :   QCOMPARE( p7.numInteriorRings(), 0 );
    8975                 :            : 
    8976                 :            :   //change dimensionality of interior rings using setExteriorRing
    8977                 :          1 :   QgsCurvePolygon p7a;
    8978                 :          1 :   ext = new QgsCircularString();
    8979                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 ) << QgsPoint( QgsWkbTypes::PointZ, 0, 10, 2 )
    8980                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 10, 10, 1 ) << QgsPoint( QgsWkbTypes::PointZ, 10, 0, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 ) );
    8981                 :          1 :   p7a.setExteriorRing( ext );
    8982                 :          1 :   rings.clear();
    8983                 :          1 :   rings << new QgsCircularString();
    8984                 :          2 :   static_cast< QgsCircularString *>( rings[0] )->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.1, 1 )
    8985                 :          1 :       << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.2, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 0.2, 0.2, 3 )
    8986                 :          1 :       << QgsPoint( QgsWkbTypes::PointZ, 0.2, 0.1, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0.1, 0.1, 1 ) );
    8987                 :          1 :   rings << new QgsCircularString();
    8988                 :          2 :   static_cast< QgsCircularString *>( rings[1] )->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0.3, 0.3, 1 )
    8989                 :          1 :       << QgsPoint( QgsWkbTypes::PointZ, 0.3, 0.4, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 0.4, 0.4, 3 )
    8990                 :          1 :       << QgsPoint( QgsWkbTypes::PointZ, 0.4, 0.3, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0.3, 0.3,  1 ) );
    8991                 :          1 :   p7a.setInteriorRings( rings );
    8992                 :          1 :   QVERIFY( p7a.is3D() );
    8993                 :          1 :   QVERIFY( !p7a.isMeasure() );
    8994                 :          1 :   QVERIFY( p7a.interiorRing( 0 )->is3D() );
    8995                 :          1 :   QVERIFY( !p7a.interiorRing( 0 )->isMeasure() );
    8996                 :          1 :   QVERIFY( p7a.interiorRing( 1 )->is3D() );
    8997                 :          1 :   QVERIFY( !p7a.interiorRing( 1 )->isMeasure() );
    8998                 :            :   //reset exterior ring to 2d
    8999                 :          1 :   ext = new QgsCircularString();
    9000                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 )
    9001                 :          1 :                   << QgsPoint( 10, 10 ) << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) );
    9002                 :          1 :   p7a.setExteriorRing( ext );
    9003                 :          1 :   QVERIFY( !p7a.is3D() );
    9004                 :          1 :   QVERIFY( !p7a.interiorRing( 0 )->is3D() ); //rings should also be made 2D
    9005                 :          1 :   QVERIFY( !p7a.interiorRing( 1 )->is3D() );
    9006                 :            :   //reset exterior ring to LineStringM
    9007                 :          1 :   ext = new QgsCircularString();
    9008                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 0, 0 ) << QgsPoint( QgsWkbTypes::PointM, 0, 10 )
    9009                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 10, 10 ) << QgsPoint( QgsWkbTypes::PointM, 10, 0 ) << QgsPoint( QgsWkbTypes::PointM, 0, 0 ) );
    9010                 :          1 :   p7a.setExteriorRing( ext );
    9011                 :          1 :   QVERIFY( p7a.isMeasure() );
    9012                 :          1 :   QVERIFY( p7a.interiorRing( 0 )->isMeasure() ); //rings should also gain measure
    9013                 :          1 :   QVERIFY( p7a.interiorRing( 1 )->isMeasure() );
    9014                 :            : 
    9015                 :            :   //removeInteriorRing
    9016                 :          1 :   QgsCurvePolygon p8;
    9017                 :          1 :   ext = new QgsCircularString();
    9018                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
    9019                 :          1 :                   << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) );
    9020                 :          1 :   p8.setExteriorRing( ext );
    9021                 :          1 :   QVERIFY( !p8.removeInteriorRing( -1 ) );
    9022                 :          1 :   QVERIFY( !p8.removeInteriorRing( 0 ) );
    9023                 :          1 :   rings.clear();
    9024                 :          1 :   rings << new QgsCircularString();
    9025                 :          2 :   static_cast< QgsCircularString *>( rings[0] )->setPoints( QgsPointSequence() << QgsPoint( 0.1, 0.1 )
    9026                 :          1 :       << QgsPoint( 0.1, 0.2 ) << QgsPoint( 0.2, 0.2 )
    9027                 :          1 :       << QgsPoint( 0.2, 0.1 ) << QgsPoint( 0.1, 0.1 ) );
    9028                 :          1 :   rings << new QgsCircularString();
    9029                 :          2 :   static_cast< QgsCircularString *>( rings[1] )->setPoints( QgsPointSequence() << QgsPoint( 0.3, 0.3 )
    9030                 :          1 :       << QgsPoint( 0.3, 0.4 ) << QgsPoint( 0.4, 0.4 )
    9031                 :          1 :       << QgsPoint( 0.4, 0.3 ) << QgsPoint( 0.3, 0.3 ) );
    9032                 :          1 :   rings << new QgsCircularString();
    9033                 :          2 :   static_cast< QgsCircularString *>( rings[2] )->setPoints( QgsPointSequence() << QgsPoint( 0.8, 0.8 )
    9034                 :          1 :       << QgsPoint( 0.8, 0.9 ) << QgsPoint( 0.9, 0.9 )
    9035                 :          1 :       << QgsPoint( 0.9, 0.8 ) << QgsPoint( 0.8, 0.8 ) );
    9036                 :          1 :   p8.setInteriorRings( rings );
    9037                 :          1 :   QCOMPARE( p8.numInteriorRings(), 3 );
    9038                 :          1 :   QVERIFY( p8.removeInteriorRing( 0 ) );
    9039                 :          1 :   QCOMPARE( p8.numInteriorRings(), 2 );
    9040                 :          1 :   QCOMPARE( p8.interiorRing( 0 )->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( 0.3, 0.3 ) );
    9041                 :          1 :   QCOMPARE( p8.interiorRing( 1 )->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( 0.8, 0.8 ) );
    9042                 :          1 :   QVERIFY( p8.removeInteriorRing( 1 ) );
    9043                 :          1 :   QCOMPARE( p8.numInteriorRings(), 1 );
    9044                 :          1 :   QCOMPARE( p8.interiorRing( 0 )->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( 0.3, 0.3 ) );
    9045                 :          1 :   QVERIFY( p8.removeInteriorRing( 0 ) );
    9046                 :          1 :   QCOMPARE( p8.numInteriorRings(), 0 );
    9047                 :          1 :   QVERIFY( !p8.removeInteriorRing( 0 ) );
    9048                 :            : 
    9049                 :            :   //clear
    9050                 :          1 :   QgsCurvePolygon p9;
    9051                 :          1 :   ext = new QgsCircularString();
    9052                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 )
    9053                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 0, 10, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 10, 10, 3 )
    9054                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 10, 0, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 ) );
    9055                 :          1 :   p9.setExteriorRing( ext );
    9056                 :          1 :   ring = new QgsCircularString();
    9057                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 1, 1 )
    9058                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZ, 1, 9, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 9, 9, 3 )
    9059                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZ, 9, 1, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 1, 1, 1 ) );
    9060                 :          1 :   p9.addInteriorRing( ring );
    9061                 :          1 :   QCOMPARE( p9.numInteriorRings(), 1 );
    9062                 :          1 :   p9.clear();
    9063                 :          1 :   QVERIFY( p9.isEmpty() );
    9064                 :          1 :   QCOMPARE( p9.numInteriorRings(), 0 );
    9065                 :          1 :   QCOMPARE( p9.nCoordinates(), 0 );
    9066                 :          1 :   QCOMPARE( p9.ringCount(), 0 );
    9067                 :          1 :   QCOMPARE( p9.partCount(), 0 );
    9068                 :          1 :   QVERIFY( !p9.is3D() );
    9069                 :          1 :   QVERIFY( !p9.isMeasure() );
    9070                 :          1 :   QCOMPARE( p9.wkbType(), QgsWkbTypes::CurvePolygon );
    9071                 :            : 
    9072                 :            :   //equality operator
    9073                 :          1 :   QgsCurvePolygon p10;
    9074                 :          1 :   QgsCurvePolygon p10b;
    9075                 :          1 :   QVERIFY( p10 == p10b );
    9076                 :          1 :   QVERIFY( !( p10 != p10b ) );
    9077                 :          1 :   ext = new QgsCircularString();
    9078                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
    9079                 :          1 :                   << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) );
    9080                 :          1 :   p10.setExteriorRing( ext );
    9081                 :          1 :   QVERIFY( !( p10 == p10b ) );
    9082                 :          1 :   QVERIFY( p10 != p10b );
    9083                 :          1 :   ext = new QgsCircularString();
    9084                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
    9085                 :          1 :                   << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) );
    9086                 :          1 :   p10b.setExteriorRing( ext );
    9087                 :          1 :   QVERIFY( p10 == p10b );
    9088                 :          1 :   QVERIFY( !( p10 != p10b ) );
    9089                 :          1 :   ext = new QgsCircularString();
    9090                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 9 ) << QgsPoint( 9, 9 )
    9091                 :          1 :                   << QgsPoint( 9, 0 ) << QgsPoint( 0, 0 ) );
    9092                 :          1 :   p10b.setExteriorRing( ext );
    9093                 :          1 :   QVERIFY( !( p10 == p10b ) );
    9094                 :          1 :   QVERIFY( p10 != p10b );
    9095                 :          1 :   ext = new QgsCircularString();
    9096                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 ) << QgsPoint( QgsWkbTypes::PointZ, 0, 10, 2 )
    9097                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 10, 10, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 10, 0, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 ) );
    9098                 :          1 :   p10b.setExteriorRing( ext );
    9099                 :          1 :   QVERIFY( !( p10 == p10b ) );
    9100                 :          1 :   QVERIFY( p10 != p10b );
    9101                 :          1 :   p10b.setExteriorRing( p10.exteriorRing()->clone() );
    9102                 :          1 :   QVERIFY( p10 == p10b );
    9103                 :          1 :   QVERIFY( !( p10 != p10b ) );
    9104                 :          1 :   ring = new QgsCircularString();
    9105                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( 1, 1 )
    9106                 :          1 :                    << QgsPoint( 1, 9 ) << QgsPoint( 9, 9 )
    9107                 :          1 :                    << QgsPoint( 9, 1 ) << QgsPoint( 1, 1 ) );
    9108                 :          1 :   p10.addInteriorRing( ring );
    9109                 :          1 :   QVERIFY( !( p10 == p10b ) );
    9110                 :          1 :   QVERIFY( p10 != p10b );
    9111                 :            : 
    9112                 :          1 :   ring = new QgsCircularString();
    9113                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( 2, 1 )
    9114                 :          1 :                    << QgsPoint( 2, 9 ) << QgsPoint( 9, 9 )
    9115                 :          1 :                    << QgsPoint( 9, 1 ) << QgsPoint( 2, 1 ) );
    9116                 :          1 :   p10b.addInteriorRing( ring );
    9117                 :          1 :   QVERIFY( !( p10 == p10b ) );
    9118                 :          1 :   QVERIFY( p10 != p10b );
    9119                 :          1 :   p10b.removeInteriorRing( 0 );
    9120                 :          1 :   p10b.addInteriorRing( p10.interiorRing( 0 )->clone() );
    9121                 :          1 :   QVERIFY( p10 == p10b );
    9122                 :          1 :   QVERIFY( !( p10 != p10b ) );
    9123                 :            : 
    9124                 :            :   //clone
    9125                 :            : 
    9126                 :          1 :   QgsCurvePolygon p11;
    9127                 :          1 :   std::unique_ptr< QgsCurvePolygon >cloned( p11.clone() );
    9128                 :          1 :   QCOMPARE( p11, *cloned );
    9129                 :          1 :   ext = new QgsCircularString();
    9130                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 5 )
    9131                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 0, 10, 2, 6 ) << QgsPoint( QgsWkbTypes::PointZM, 10, 10, 3, 7 )
    9132                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 9 ) );
    9133                 :          1 :   p11.setExteriorRing( ext );
    9134                 :          1 :   ring = new QgsCircularString();
    9135                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 2 )
    9136                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 1, 9, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZM, 9, 9, 3, 6 )
    9137                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 9, 1, 4, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 7 ) );
    9138                 :          1 :   p11.addInteriorRing( ring );
    9139                 :          1 :   cloned.reset( p11.clone() );
    9140                 :          1 :   QCOMPARE( p11, *cloned );
    9141                 :            : 
    9142                 :            :   //copy constructor
    9143                 :          1 :   QgsCurvePolygon p12;
    9144                 :          1 :   QgsCurvePolygon p13( p12 );
    9145                 :          1 :   QCOMPARE( p12, p13 );
    9146                 :          1 :   ext = new QgsCircularString();
    9147                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 5 )
    9148                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 0, 10, 2, 6 ) << QgsPoint( QgsWkbTypes::PointZM, 10, 10, 3, 7 )
    9149                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 9 ) );
    9150                 :          1 :   p12.setExteriorRing( ext );
    9151                 :          1 :   ring = new QgsCircularString();
    9152                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 2 )
    9153                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 1, 9, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZM, 9, 9, 3, 6 )
    9154                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 9, 1, 4, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 7 ) );
    9155                 :          1 :   p12.addInteriorRing( ring );
    9156                 :          1 :   QgsCurvePolygon p14( p12 );
    9157                 :          1 :   QCOMPARE( p12, p14 );
    9158                 :            : 
    9159                 :            :   //assignment operator
    9160                 :          1 :   QgsCurvePolygon p15;
    9161                 :          1 :   p15 = p13;
    9162                 :          1 :   QCOMPARE( p13, p15 );
    9163                 :          1 :   p15 = p12;
    9164                 :          1 :   QCOMPARE( p12, p15 );
    9165                 :            : 
    9166                 :            :   // bounding box
    9167                 :          1 :   QgsCurvePolygon boundingBoxPoly;
    9168                 :          1 :   QgsRectangle bBox = boundingBoxPoly.boundingBox(); //no crash!
    9169                 :            : 
    9170                 :          1 :   ext = new QgsCircularString();
    9171                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0, 1 ) << QgsPoint( 1, 10, 2 ) << QgsPoint( 0, 18, 3 )
    9172                 :          1 :                   << QgsPoint( -1, 4, 4 ) << QgsPoint( 0, 0, 1 ) );
    9173                 :          1 :   boundingBoxPoly.setExteriorRing( ext );
    9174                 :          1 :   bBox = boundingBoxPoly.boundingBox();
    9175                 :          1 :   QGSCOMPARENEAR( bBox.xMinimum(), -1.435273, 0.001 );
    9176                 :          1 :   QGSCOMPARENEAR( bBox.xMaximum(), 1.012344, 0.001 );
    9177                 :          1 :   QGSCOMPARENEAR( bBox.yMinimum(), 0.000000, 0.001 );
    9178                 :          1 :   QGSCOMPARENEAR( bBox.yMaximum(), 18, 0.001 );
    9179                 :            : 
    9180                 :            :   //surfaceToPolygon
    9181                 :          1 :   QgsCurvePolygon p12a;
    9182                 :          1 :   std::unique_ptr< QgsPolygon > surface( p12a.surfaceToPolygon() );
    9183                 :          1 :   QVERIFY( surface->isEmpty() );
    9184                 :            : 
    9185                 :          1 :   ext = new QgsCircularString();
    9186                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 3 ) << QgsPoint( 2, 4 )
    9187                 :          1 :                   << QgsPoint( -1, 5 ) << QgsPoint( 0, 6 ) );
    9188                 :          1 :   p12a.setExteriorRing( ext );
    9189                 :          1 :   surface.reset( p12a.surfaceToPolygon() );
    9190                 :          1 :   QCOMPARE( surface->wkbType(), QgsWkbTypes::Polygon );
    9191                 :          1 :   QCOMPARE( surface->exteriorRing()->nCoordinates(), 290 );
    9192                 :          1 :   QCOMPARE( surface->exteriorRing()->nCoordinates(), 290 ); // nCoordinates is cached, so check twice
    9193                 :          1 :   QVERIFY( surface->exteriorRing()->isClosed() );
    9194                 :            :   // too many vertices to actually check the result, let's just make sure the bounding boxes are similar
    9195                 :          1 :   QgsRectangle r1 = ext->boundingBox();
    9196                 :          1 :   QgsRectangle r2 = surface->exteriorRing()->boundingBox();
    9197                 :          1 :   QGSCOMPARENEAR( r1.xMinimum(), r2.xMinimum(), 0.0001 );
    9198                 :          1 :   QGSCOMPARENEAR( r1.xMaximum(), r2.xMaximum(), 0.0001 );
    9199                 :          1 :   QGSCOMPARENEAR( r1.yMinimum(), r2.yMinimum(), 0.0001 );
    9200                 :          1 :   QGSCOMPARENEAR( r1.yMaximum(), r2.yMaximum(), 0.0001 );
    9201                 :          1 :   ring = new QgsCircularString();
    9202                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 2 )
    9203                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 1, 9, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZM, 9, 9, 3, 6 )
    9204                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 9, 1, 4, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 7 ) );
    9205                 :          1 :   p12a.addInteriorRing( ring );
    9206                 :          1 :   surface.reset( p12a.surfaceToPolygon() );
    9207                 :          1 :   QCOMPARE( surface->wkbType(), QgsWkbTypes::Polygon );
    9208                 :          1 :   QCOMPARE( surface->exteriorRing()->nCoordinates(), 290 );
    9209                 :          1 :   QCOMPARE( surface->exteriorRing()->nCoordinates(), 290 ); // nCoordinates is cached, so check twice
    9210                 :          1 :   QVERIFY( surface->exteriorRing()->isClosed() );
    9211                 :          1 :   QCOMPARE( surface->numInteriorRings(), 1 );
    9212                 :            :   // too many vertices to actually check the result, let's just make sure the bounding boxes are similar
    9213                 :          1 :   r1 = ring->boundingBox();
    9214                 :          1 :   r2 = surface->interiorRing( 0 )->boundingBox();
    9215                 :          1 :   QGSCOMPARENEAR( r1.xMinimum(), r2.xMinimum(), 0.0001 );
    9216                 :          1 :   QGSCOMPARENEAR( r1.xMaximum(), r2.xMaximum(), 0.0001 );
    9217                 :          1 :   QGSCOMPARENEAR( r1.yMinimum(), r2.yMinimum(), 0.0001 );
    9218                 :          1 :   QGSCOMPARENEAR( r1.yMaximum(), r2.yMaximum(), 0.0001 );
    9219                 :            : 
    9220                 :            :   //toPolygon
    9221                 :          1 :   p12a = QgsCurvePolygon();
    9222                 :          1 :   surface.reset( p12a.toPolygon() );
    9223                 :          1 :   QVERIFY( surface->isEmpty() );
    9224                 :            : 
    9225                 :          1 :   ext = new QgsCircularString();
    9226                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 10 ) << QgsPoint( 0, 18 )
    9227                 :          1 :                   << QgsPoint( -1, 4 ) << QgsPoint( 0, 0 ) );
    9228                 :          1 :   p12a.setExteriorRing( ext );
    9229                 :          1 :   surface.reset( p12a.toPolygon() );
    9230                 :          1 :   QCOMPARE( surface->wkbType(), QgsWkbTypes::Polygon );
    9231                 :          1 :   QCOMPARE( surface->exteriorRing()->nCoordinates(), 64 );
    9232                 :          1 :   QCOMPARE( surface->exteriorRing()->nCoordinates(), 64 ); // ncoordinates is cached, so check twice
    9233                 :          1 :   QVERIFY( surface->exteriorRing()->isClosed() );
    9234                 :            :   // too many vertices to actually check the result, let's just make sure the bounding boxes are similar
    9235                 :          1 :   r1 = ext->boundingBox();
    9236                 :          1 :   r2 = surface->exteriorRing()->boundingBox();
    9237                 :          1 :   QGSCOMPARENEAR( r1.xMinimum(), r2.xMinimum(), 0.01 );
    9238                 :          1 :   QGSCOMPARENEAR( r1.xMaximum(), r2.xMaximum(), 0.01 );
    9239                 :          1 :   QGSCOMPARENEAR( r1.yMinimum(), r2.yMinimum(), 0.01 );
    9240                 :          1 :   QGSCOMPARENEAR( r1.yMaximum(), r2.yMaximum(), 0.01 );
    9241                 :          1 :   ring = new QgsCircularString();
    9242                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 2 )
    9243                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 1, 9, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZM, 9, 9, 3, 6 )
    9244                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 9, 1, 4, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 7 ) );
    9245                 :          1 :   p12a.addInteriorRing( ring );
    9246                 :          1 :   surface.reset( p12a.toPolygon() );
    9247                 :          1 :   QCOMPARE( surface->wkbType(), QgsWkbTypes::Polygon );
    9248                 :          1 :   QCOMPARE( surface->exteriorRing()->nCoordinates(), 64 );
    9249                 :          1 :   QCOMPARE( surface->exteriorRing()->nCoordinates(), 64 ); //ncoordinates is cached, so check twice
    9250                 :          1 :   QVERIFY( surface->exteriorRing()->isClosed() );
    9251                 :          1 :   QCOMPARE( surface->numInteriorRings(), 1 );
    9252                 :            :   // too many vertices to actually check the result, let's just make sure the bounding boxes are similar
    9253                 :          1 :   r1 = ring->boundingBox();
    9254                 :          1 :   r2 = surface->interiorRing( 0 )->boundingBox();
    9255                 :          1 :   QGSCOMPARENEAR( r1.xMinimum(), r2.xMinimum(), 0.0001 );
    9256                 :          1 :   QGSCOMPARENEAR( r1.xMaximum(), r2.xMaximum(), 0.0001 );
    9257                 :          1 :   QGSCOMPARENEAR( r1.yMinimum(), r2.yMinimum(), 0.0001 );
    9258                 :          1 :   QGSCOMPARENEAR( r1.yMaximum(), r2.yMaximum(), 0.0001 );
    9259                 :            : 
    9260                 :            :   //toCurveType - should be identical since it's already a curve
    9261                 :          1 :   std::unique_ptr< QgsCurvePolygon > curveType( p12a.toCurveType() );
    9262                 :          1 :   QCOMPARE( *curveType, p12a );
    9263                 :            : 
    9264                 :            :   //to/fromWKB
    9265                 :          1 :   QgsCurvePolygon p16;
    9266                 :          1 :   ext = new QgsCircularString();
    9267                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 2, 0 )
    9268                 :          1 :                   << QgsPoint( 1, 0.5 ) << QgsPoint( 0, 0 ) );
    9269                 :          1 :   p16.setExteriorRing( ext );
    9270                 :          1 :   ring = new QgsCircularString();
    9271                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0.1, 0 ) << QgsPoint( 0.2, 0 )
    9272                 :          1 :                    << QgsPoint( 0.1, 0.05 ) << QgsPoint( 0, 0 ) );
    9273                 :          1 :   p16.addInteriorRing( ring );
    9274                 :          1 :   QByteArray wkb16 = p16.asWkb();
    9275                 :          1 :   QCOMPARE( wkb16.size(), p16.wkbSize() );
    9276                 :          1 :   QgsCurvePolygon p17;
    9277                 :          1 :   QgsConstWkbPtr wkb16ptr( wkb16 );
    9278                 :          1 :   p17.fromWkb( wkb16ptr );
    9279                 :          1 :   QCOMPARE( p16, p17 );
    9280                 :            :   //CurvePolygonZ
    9281                 :          1 :   p16.clear();
    9282                 :          1 :   p17.clear();
    9283                 :            : 
    9284                 :          1 :   ext = new QgsCircularString();
    9285                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0, 1 ) << QgsPoint( 1, 0, 2 ) << QgsPoint( 2, 0, 3 )
    9286                 :          1 :                   << QgsPoint( 1, 0.5, 4 ) << QgsPoint( 0, 0, 1 ) );
    9287                 :          1 :   p16.setExteriorRing( ext );
    9288                 :          1 :   ring = new QgsCircularString();
    9289                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( 0, 0, 1 ) << QgsPoint( 0.1, 0, 2 ) << QgsPoint( 0.2, 0, 3 )
    9290                 :          1 :                    << QgsPoint( 0.1, 0.05, 4 ) << QgsPoint( 0, 0, 1 ) );
    9291                 :          1 :   p16.addInteriorRing( ring );
    9292                 :          1 :   wkb16 = p16.asWkb();
    9293                 :          1 :   QgsConstWkbPtr wkb16ptr2( wkb16 );
    9294                 :          1 :   p17.fromWkb( wkb16ptr2 );
    9295                 :          1 :   QCOMPARE( p16, p17 );
    9296                 :            : 
    9297                 :            :   // compound curve
    9298                 :          1 :   QgsCompoundCurve *cCurve = new QgsCompoundCurve();
    9299                 :          1 :   ext = new QgsCircularString();
    9300                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( 0, 0, 1 ) << QgsPoint( 1, 0, 2 ) << QgsPoint( 2, 0, 3 )
    9301                 :          1 :                   << QgsPoint( 1, 0.5, 4 ) << QgsPoint( 0, 0, 1 ) );
    9302                 :          1 :   cCurve->addCurve( ext );
    9303                 :          1 :   p16.addInteriorRing( cCurve );
    9304                 :          1 :   wkb16 = p16.asWkb();
    9305                 :          1 :   QCOMPARE( wkb16.size(), p16.wkbSize() );
    9306                 :          1 :   QgsConstWkbPtr wkb16ptr3( wkb16 );
    9307                 :          1 :   p17.fromWkb( wkb16ptr3 );
    9308                 :          1 :   QCOMPARE( p16, p17 );
    9309                 :            : 
    9310                 :            :   //CurvePolygonM
    9311                 :          1 :   p16.clear();
    9312                 :          1 :   p17.clear();
    9313                 :          1 :   ext = new QgsCircularString();
    9314                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 0, 0, 0, 1 ) << QgsPoint( QgsWkbTypes::PointM, 1, 0, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 2, 0, 0, 3 )
    9315                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 1, 0.5, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 0, 0, 0, 1 ) );
    9316                 :          1 :   p16.setExteriorRing( ext );
    9317                 :          1 :   ring = new QgsCircularString();
    9318                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 0, 0, 0, 1 ) << QgsPoint( QgsWkbTypes::PointM, 0.1, 0, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 0.2, 0, 0, 3 )
    9319                 :          1 :                    << QgsPoint( QgsWkbTypes::PointM, 0.1, 0.05, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 0, 0, 0, 1 ) );
    9320                 :          1 :   p16.addInteriorRing( ring );
    9321                 :          1 :   wkb16 = p16.asWkb();
    9322                 :          1 :   QgsConstWkbPtr wkb16ptr8( wkb16 );
    9323                 :          1 :   p17.fromWkb( wkb16ptr8 );
    9324                 :          1 :   QCOMPARE( p16, p17 );
    9325                 :            : 
    9326                 :            :   //CurvePolygonZM
    9327                 :          1 :   p16.clear();
    9328                 :          1 :   p17.clear();
    9329                 :          1 :   ext = new QgsCircularString();
    9330                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 10, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 1, 0, 11, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 2, 0, 12, 3 )
    9331                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 1, 0.5, 13, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 10, 1 ) );
    9332                 :          1 :   p16.setExteriorRing( ext );
    9333                 :          1 :   ring = new QgsCircularString();
    9334                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 10, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 0.1, 0, 11, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 0.2, 0, 12, 3 )
    9335                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 0.1, 0.05, 13, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 10, 1 ) );
    9336                 :          1 :   p16.addInteriorRing( ring );
    9337                 :          1 :   wkb16 = p16.asWkb();
    9338                 :          1 :   QgsConstWkbPtr wkb16ptr4( wkb16 );
    9339                 :          1 :   p17.fromWkb( wkb16ptr4 );
    9340                 :          1 :   QCOMPARE( p16, p17 );
    9341                 :            : 
    9342                 :            :   //bad WKB - check for no crash
    9343                 :          1 :   p17.clear();
    9344                 :          1 :   QgsConstWkbPtr nullPtr( nullptr, 0 );
    9345                 :          1 :   QVERIFY( !p17.fromWkb( nullPtr ) );
    9346                 :          1 :   QCOMPARE( p17.wkbType(), QgsWkbTypes::CurvePolygon );
    9347                 :          1 :   QgsPoint point( 1, 2 );
    9348                 :          1 :   QByteArray wkbPoint = point.asWkb();
    9349                 :          1 :   QgsConstWkbPtr wkbPointPtr( wkbPoint );
    9350                 :          1 :   QVERIFY( !p17.fromWkb( wkbPointPtr ) );
    9351                 :          1 :   QCOMPARE( p17.wkbType(), QgsWkbTypes::CurvePolygon );
    9352                 :            : 
    9353                 :            :   //to/from WKT
    9354                 :          1 :   QgsCurvePolygon p18;
    9355                 :          1 :   ext = new QgsCircularString();
    9356                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 10, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 1, 0, 11, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 2, 0, 12, 3 )
    9357                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 1, 0.5, 13, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 10, 1 ) );
    9358                 :          1 :   p18.setExteriorRing( ext );
    9359                 :          1 :   ring = new QgsCircularString();
    9360                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 10, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 0.1, 0, 11, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 0.2, 0, 12, 3 )
    9361                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 0.1, 0.05, 13, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 10, 1 ) );
    9362                 :          1 :   p18.addInteriorRing( ring );
    9363                 :            : 
    9364                 :          1 :   QString wkt = p18.asWkt();
    9365                 :          1 :   QVERIFY( !wkt.isEmpty() );
    9366                 :          1 :   QgsCurvePolygon p19;
    9367                 :          1 :   QVERIFY( p19.fromWkt( wkt ) );
    9368                 :          1 :   QCOMPARE( p18, p19 );
    9369                 :            : 
    9370                 :            :   //bad WKT
    9371                 :          1 :   QVERIFY( !p19.fromWkt( "Point()" ) );
    9372                 :          1 :   QVERIFY( p19.isEmpty() );
    9373                 :          1 :   QVERIFY( !p19.exteriorRing() );
    9374                 :          1 :   QCOMPARE( p19.numInteriorRings(), 0 );
    9375                 :          1 :   QVERIFY( !p19.is3D() );
    9376                 :          1 :   QVERIFY( !p19.isMeasure() );
    9377                 :          1 :   QCOMPARE( p19.wkbType(), QgsWkbTypes::CurvePolygon );
    9378                 :            : 
    9379                 :            : 
    9380                 :            :   //as JSON
    9381                 :          1 :   QgsCurvePolygon exportPolygon;
    9382                 :          1 :   ext = new QgsCircularString();
    9383                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 10, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 1, 0, 11, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 2, 0, 12, 3 )
    9384                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 1, 0.5, 13, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 10, 1 ) );
    9385                 :          1 :   exportPolygon.setExteriorRing( ext );
    9386                 :            : 
    9387                 :            : 
    9388                 :            :   // GML document for compare
    9389                 :          2 :   QDomDocument doc( QStringLiteral( "gml" ) );
    9390                 :            : 
    9391                 :            :   // as GML2
    9392                 :          2 :   QString expectedSimpleGML2( QStringLiteral( "<Polygon xmlns=\"gml\"><outerBoundaryIs xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">0,0 1,0 2,0 2,0 2,0 2,0.1 1.9,0.1 1.9,0.1 1.9,0.1 1.9,0.1 1.9,0.1 1.9,0.1 1.9,0.2 1.8,0.2 1.8,0.2 1.8,0.2 1.8,0.2 1.8,0.2 1.8,0.2 1.7,0.3 1.7,0.3 1.7,0.3 1.7,0.3 1.7,0.3 1.6,0.3 1.6,0.3 1.6,0.3 1.6,0.4 1.6,0.4 1.6,0.4 1.5,0.4 1.5,0.4 1.5,0.4 1.5,0.4 1.5,0.4 1.4,0.4 1.4,0.4 1.4,0.4 1.4,0.4 1.4,0.4 1.3,0.5 1.3,0.5 1.3,0.5 1.3,0.5 1.2,0.5 1.2,0.5 1.2,0.5 1.2,0.5 1.2,0.5 1.1,0.5 1.1,0.5 1.1,0.5 1.1,0.5 1.1,0.5 1,0.5 1,0.5 1,0.5 1,0.5 0.9,0.5 0.9,0.5 0.9,0.5 0.9,0.5 0.9,0.5 0.8,0.5 0.8,0.5 0.8,0.5 0.8,0.5 0.8,0.5 0.7,0.5 0.7,0.5 0.7,0.5 0.7,0.5 0.6,0.4 0.6,0.4 0.6,0.4 0.6,0.4 0.6,0.4 0.5,0.4 0.5,0.4 0.5,0.4 0.5,0.4 0.5,0.4 0.4,0.4 0.4,0.4 0.4,0.4 0.4,0.3 0.4,0.3 0.4,0.3 0.3,0.3 0.3,0.3 0.3,0.3 0.3,0.3 0.3,0.3 0.2,0.2 0.2,0.2 0.2,0.2 0.2,0.2 0.2,0.2 0.2,0.2 0.1,0.2 0.1,0.1 0.1,0.1 0.1,0.1 0.1,0.1 0.1,0.1 0.1,0.1 0,0.1 0,0 0,0 0,0</coordinates></LinearRing></outerBoundaryIs></Polygon>" ) );
    9393                 :          1 :   QString res = elemToString( exportPolygon.asGml2( doc, 1 ) );
    9394                 :          3 :   QGSCOMPAREGML( res, expectedSimpleGML2 );
    9395                 :          2 :   QString expectedGML2empty( QStringLiteral( "<Polygon xmlns=\"gml\"/>" ) );
    9396                 :          3 :   QGSCOMPAREGML( elemToString( QgsCurvePolygon().asGml2( doc ) ), expectedGML2empty );
    9397                 :            : 
    9398                 :            :   //as GML3
    9399                 :          2 :   QString expectedSimpleGML3( QStringLiteral( "<Polygon xmlns=\"gml\"><exterior xmlns=\"gml\"><Curve xmlns=\"gml\"><segments xmlns=\"gml\"><ArcString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"3\">0 0 10 1 0 11 2 0 12 1 0.5 13 0 0 10</posList></ArcString></segments></Curve></exterior></Polygon>" ) );
    9400                 :          1 :   res = elemToString( exportPolygon.asGml3( doc, 2 ) );
    9401                 :          1 :   QCOMPARE( elemToString( exportPolygon.asGml3( doc ) ), expectedSimpleGML3 );
    9402                 :          2 :   QString expectedGML3empty( QStringLiteral( "<Polygon xmlns=\"gml\"/>" ) );
    9403                 :          3 :   QGSCOMPAREGML( elemToString( QgsCurvePolygon().asGml3( doc ) ), expectedGML3empty );
    9404                 :            : 
    9405                 :            :   // as JSON
    9406                 :          1 :   QString expectedSimpleJson( "{\"coordinates\":[[[0.0,0.0,10.0],[1.0,0.0,11.0],[2.0,0.0,12.0],[2.0,0.0,12.0],[2.0,0.0,12.0],[2.0,0.1,12.1],[1.9,0.1,12.1],[1.9,0.1,12.1],[1.9,0.1,12.1],[1.9,0.1,12.1],[1.9,0.1,12.1],[1.9,0.1,12.2],[1.9,0.2,12.2],[1.8,0.2,12.2],[1.8,0.2,12.2],[1.8,0.2,12.2],[1.8,0.2,12.3],[1.8,0.2,12.3],[1.8,0.2,12.3],[1.7,0.3,12.3],[1.7,0.3,12.3],[1.7,0.3,12.4],[1.7,0.3,12.4],[1.7,0.3,12.4],[1.6,0.3,12.4],[1.6,0.3,12.4],[1.6,0.3,12.4],[1.6,0.4,12.5],[1.6,0.4,12.5],[1.6,0.4,12.5],[1.5,0.4,12.5],[1.5,0.4,12.5],[1.5,0.4,12.6],[1.5,0.4,12.6],[1.5,0.4,12.6],[1.4,0.4,12.6],[1.4,0.4,12.6],[1.4,0.4,12.7],[1.4,0.4,12.7],[1.4,0.4,12.7],[1.3,0.5,12.7],[1.3,0.5,12.7],[1.3,0.5,12.7],[1.3,0.5,12.8],[1.2,0.5,12.8],[1.2,0.5,12.8],[1.2,0.5,12.8],[1.2,0.5,12.8],[1.2,0.5,12.9],[1.1,0.5,12.9],[1.1,0.5,12.9],[1.1,0.5,12.9],[1.1,0.5,12.9],[1.1,0.5,13.0],[1.0,0.5,13.0],[1.0,0.5,13.0],[1.0,0.5,13.0],[1.0,0.5,12.9],[0.9,0.5,12.9],[0.9,0.5,12.8],[0.9,0.5,12.7],[0.9,0.5,12.7],[0.9,0.5,12.6],[0.8,0.5,12.6],[0.8,0.5,12.5],[0.8,0.5,12.5],[0.8,0.5,12.4],[0.8,0.5,12.4],[0.7,0.5,12.3],[0.7,0.5,12.2],[0.7,0.5,12.2],[0.7,0.5,12.1],[0.6,0.4,12.1],[0.6,0.4,12.0],[0.6,0.4,12.0],[0.6,0.4,11.9],[0.6,0.4,11.9],[0.5,0.4,11.8],[0.5,0.4,11.7],[0.5,0.4,11.7],[0.5,0.4,11.6],[0.5,0.4,11.6],[0.4,0.4,11.5],[0.4,0.4,11.5],[0.4,0.4,11.4],[0.4,0.3,11.3],[0.4,0.3,11.3],[0.4,0.3,11.2],[0.3,0.3,11.2],[0.3,0.3,11.1],[0.3,0.3,11.1],[0.3,0.3,11.0],[0.3,0.3,11.0],[0.2,0.2,10.9],[0.2,0.2,10.8],[0.2,0.2,10.8],[0.2,0.2,10.7],[0.2,0.2,10.7],[0.2,0.2,10.6],[0.1,0.2,10.6],[0.1,0.1,10.5],[0.1,0.1,10.4],[0.1,0.1,10.4],[0.1,0.1,10.3],[0.1,0.1,10.3],[0.1,0.1,10.2],[0.0,0.1,10.2],[0.0,0.0,10.1],[0.0,0.0,10.1],[0.0,0.0,10.0]]],\"type\":\"Polygon\"}" );
    9407                 :          1 :   res = exportPolygon.asJson( 1 );
    9408                 :          1 :   QCOMPARE( res, expectedSimpleJson );
    9409                 :            : 
    9410                 :          1 :   ring = new QgsCircularString();
    9411                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 10, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 0.1, 0, 11, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 0.2, 0, 12, 3 )
    9412                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 0.1, 0.05, 13, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 10, 1 ) );
    9413                 :          1 :   exportPolygon.addInteriorRing( ring );
    9414                 :            : 
    9415                 :          1 :   QString expectedJson( "{\"coordinates\":[[[0.0,0.0,10.0],[1.0,0.0,11.0],[2.0,0.0,12.0],[2.0,0.0,12.0],[2.0,0.0,12.0],[2.0,0.1,12.1],[1.9,0.1,12.1],[1.9,0.1,12.1],[1.9,0.1,12.1],[1.9,0.1,12.1],[1.9,0.1,12.1],[1.9,0.1,12.2],[1.9,0.2,12.2],[1.8,0.2,12.2],[1.8,0.2,12.2],[1.8,0.2,12.2],[1.8,0.2,12.3],[1.8,0.2,12.3],[1.8,0.2,12.3],[1.7,0.3,12.3],[1.7,0.3,12.3],[1.7,0.3,12.4],[1.7,0.3,12.4],[1.7,0.3,12.4],[1.6,0.3,12.4],[1.6,0.3,12.4],[1.6,0.3,12.4],[1.6,0.4,12.5],[1.6,0.4,12.5],[1.6,0.4,12.5],[1.5,0.4,12.5],[1.5,0.4,12.5],[1.5,0.4,12.6],[1.5,0.4,12.6],[1.5,0.4,12.6],[1.4,0.4,12.6],[1.4,0.4,12.6],[1.4,0.4,12.7],[1.4,0.4,12.7],[1.4,0.4,12.7],[1.3,0.5,12.7],[1.3,0.5,12.7],[1.3,0.5,12.7],[1.3,0.5,12.8],[1.2,0.5,12.8],[1.2,0.5,12.8],[1.2,0.5,12.8],[1.2,0.5,12.8],[1.2,0.5,12.9],[1.1,0.5,12.9],[1.1,0.5,12.9],[1.1,0.5,12.9],[1.1,0.5,12.9],[1.1,0.5,13.0],[1.0,0.5,13.0],[1.0,0.5,13.0],[1.0,0.5,13.0],[1.0,0.5,12.9],[0.9,0.5,12.9],[0.9,0.5,12.8],[0.9,0.5,12.7],[0.9,0.5,12.7],[0.9,0.5,12.6],[0.8,0.5,12.6],[0.8,0.5,12.5],[0.8,0.5,12.5],[0.8,0.5,12.4],[0.8,0.5,12.4],[0.7,0.5,12.3],[0.7,0.5,12.2],[0.7,0.5,12.2],[0.7,0.5,12.1],[0.6,0.4,12.1],[0.6,0.4,12.0],[0.6,0.4,12.0],[0.6,0.4,11.9],[0.6,0.4,11.9],[0.5,0.4,11.8],[0.5,0.4,11.7],[0.5,0.4,11.7],[0.5,0.4,11.6],[0.5,0.4,11.6],[0.4,0.4,11.5],[0.4,0.4,11.5],[0.4,0.4,11.4],[0.4,0.3,11.3],[0.4,0.3,11.3],[0.4,0.3,11.2],[0.3,0.3,11.2],[0.3,0.3,11.1],[0.3,0.3,11.1],[0.3,0.3,11.0],[0.3,0.3,11.0],[0.2,0.2,10.9],[0.2,0.2,10.8],[0.2,0.2,10.8],[0.2,0.2,10.7],[0.2,0.2,10.7],[0.2,0.2,10.6],[0.1,0.2,10.6],[0.1,0.1,10.5],[0.1,0.1,10.4],[0.1,0.1,10.4],[0.1,0.1,10.3],[0.1,0.1,10.3],[0.1,0.1,10.2],[0.0,0.1,10.2],[0.0,0.0,10.1],[0.0,0.0,10.1],[0.0,0.0,10.0]],[[0.0,0.0,10.0],[0.1,0.0,11.0],[0.2,0.0,12.0],[0.2,0.0,12.0],[0.2,0.0,12.0],[0.2,0.0,12.1],[0.2,0.0,12.1],[0.2,0.0,12.1],[0.2,0.0,12.1],[0.2,0.0,12.1],[0.2,0.0,12.1],[0.2,0.0,12.2],[0.2,0.0,12.2],[0.2,0.0,12.2],[0.2,0.0,12.2],[0.2,0.0,12.2],[0.2,0.0,12.3],[0.2,0.0,12.3],[0.2,0.0,12.3],[0.2,0.0,12.3],[0.2,0.0,12.3],[0.2,0.0,12.4],[0.2,0.0,12.4],[0.2,0.0,12.4],[0.2,0.0,12.4],[0.2,0.0,12.4],[0.2,0.0,12.4],[0.2,0.0,12.5],[0.2,0.0,12.5],[0.2,0.0,12.5],[0.2,0.0,12.5],[0.2,0.0,12.5],[0.1,0.0,12.6],[0.1,0.0,12.6],[0.1,0.0,12.6],[0.1,0.0,12.6],[0.1,0.0,12.6],[0.1,0.0,12.7],[0.1,0.0,12.7],[0.1,0.0,12.7],[0.1,0.0,12.7],[0.1,0.0,12.7],[0.1,0.0,12.7],[0.1,0.0,12.8],[0.1,0.0,12.8],[0.1,0.0,12.8],[0.1,0.0,12.8],[0.1,0.0,12.8],[0.1,0.0,12.9],[0.1,0.0,12.9],[0.1,0.0,12.9],[0.1,0.0,12.9],[0.1,0.0,12.9],[0.1,0.0,13.0],[0.1,0.0,13.0],[0.1,0.0,13.0],[0.1,0.0,13.0],[0.1,0.0,12.9],[0.1,0.0,12.9],[0.1,0.0,12.8],[0.1,0.0,12.7],[0.1,0.0,12.7],[0.1,0.0,12.6],[0.1,0.0,12.6],[0.1,0.0,12.5],[0.1,0.0,12.5],[0.1,0.0,12.4],[0.1,0.0,12.4],[0.1,0.0,12.3],[0.1,0.0,12.2],[0.1,0.0,12.2],[0.1,0.0,12.1],[0.1,0.0,12.1],[0.1,0.0,12.0],[0.1,0.0,12.0],[0.1,0.0,11.9],[0.1,0.0,11.9],[0.1,0.0,11.8],[0.1,0.0,11.7],[0.1,0.0,11.7],[0.0,0.0,11.6],[0.0,0.0,11.6],[0.0,0.0,11.5],[0.0,0.0,11.5],[0.0,0.0,11.4],[0.0,0.0,11.3],[0.0,0.0,11.3],[0.0,0.0,11.2],[0.0,0.0,11.2],[0.0,0.0,11.1],[0.0,0.0,11.1],[0.0,0.0,11.0],[0.0,0.0,11.0],[0.0,0.0,10.9],[0.0,0.0,10.8],[0.0,0.0,10.8],[0.0,0.0,10.7],[0.0,0.0,10.7],[0.0,0.0,10.6],[0.0,0.0,10.6],[0.0,0.0,10.5],[0.0,0.0,10.4],[0.0,0.0,10.4],[0.0,0.0,10.3],[0.0,0.0,10.3],[0.0,0.0,10.2],[0.0,0.0,10.2],[0.0,0.0,10.1],[0.0,0.0,10.1],[0.0,0.0,10.0]]],\"type\":\"Polygon\"}" );
    9416                 :          1 :   res = exportPolygon.asJson( 1 );
    9417                 :          1 :   QCOMPARE( res, expectedJson );
    9418                 :            : 
    9419                 :            :   //asKML
    9420                 :          2 :   QString expectedKml( QStringLiteral( "<Polygon><outerBoundaryIs><LinearRing><altitudeMode>absolute</altitudeMode><coordinates>0,0,10 1,0,11 2,0,12 2,0,12 2,0,12 2,0.1,12.1 1.9,0.1,12.1 1.9,0.1,12.1 1.9,0.1,12.1 1.9,0.1,12.1 1.9,0.1,12.1 1.9,0.1,12.2 1.9,0.2,12.2 1.8,0.2,12.2 1.8,0.2,12.2 1.8,0.2,12.2 1.8,0.2,12.3 1.8,0.2,12.3 1.8,0.2,12.3 1.7,0.3,12.3 1.7,0.3,12.3 1.7,0.3,12.4 1.7,0.3,12.4 1.7,0.3,12.4 1.6,0.3,12.4 1.6,0.3,12.4 1.6,0.3,12.4 1.6,0.4,12.5 1.6,0.4,12.5 1.6,0.4,12.5 1.5,0.4,12.5 1.5,0.4,12.5 1.5,0.4,12.6 1.5,0.4,12.6 1.5,0.4,12.6 1.4,0.4,12.6 1.4,0.4,12.6 1.4,0.4,12.7 1.4,0.4,12.7 1.4,0.4,12.7 1.3,0.5,12.7 1.3,0.5,12.7 1.3,0.5,12.7 1.3,0.5,12.8 1.2,0.5,12.8 1.2,0.5,12.8 1.2,0.5,12.8 1.2,0.5,12.8 1.2,0.5,12.9 1.1,0.5,12.9 1.1,0.5,12.9 1.1,0.5,12.9 1.1,0.5,12.9 1.1,0.5,13 1,0.5,13 1,0.5,13 1,0.5,13 1,0.5,12.9 0.9,0.5,12.9 0.9,0.5,12.8 0.9,0.5,12.7 0.9,0.5,12.7 0.9,0.5,12.6 0.8,0.5,12.6 0.8,0.5,12.5 0.8,0.5,12.5 0.8,0.5,12.4 0.8,0.5,12.4 0.7,0.5,12.3 0.7,0.5,12.2 0.7,0.5,12.2 0.7,0.5,12.1 0.6,0.4,12.1 0.6,0.4,12 0.6,0.4,12 0.6,0.4,11.9 0.6,0.4,11.9 0.5,0.4,11.8 0.5,0.4,11.7 0.5,0.4,11.7 0.5,0.4,11.6 0.5,0.4,11.6 0.4,0.4,11.5 0.4,0.4,11.5 0.4,0.4,11.4 0.4,0.3,11.3 0.4,0.3,11.3 0.4,0.3,11.2 0.3,0.3,11.2 0.3,0.3,11.1 0.3,0.3,11.1 0.3,0.3,11 0.3,0.3,11 0.2,0.2,10.9 0.2,0.2,10.8 0.2,0.2,10.8 0.2,0.2,10.7 0.2,0.2,10.7 0.2,0.2,10.6 0.1,0.2,10.6 0.1,0.1,10.5 0.1,0.1,10.4 0.1,0.1,10.4 0.1,0.1,10.3 0.1,0.1,10.3 0.1,0.1,10.2 0,0.1,10.2 0,0,10.1 0,0,10.1 0,0,10</coordinates></LinearRing></outerBoundaryIs><innerBoundaryIs><LinearRing><altitudeMode>absolute</altitudeMode><coordinates>0,0,10 0.1,0,11 0.2,0,12 0.2,0,12 0.2,0,12 0.2,0,12.1 0.2,0,12.1 0.2,0,12.1 0.2,0,12.1 0.2,0,12.1 0.2,0,12.1 0.2,0,12.2 0.2,0,12.2 0.2,0,12.2 0.2,0,12.2 0.2,0,12.2 0.2,0,12.3 0.2,0,12.3 0.2,0,12.3 0.2,0,12.3 0.2,0,12.3 0.2,0,12.4 0.2,0,12.4 0.2,0,12.4 0.2,0,12.4 0.2,0,12.4 0.2,0,12.4 0.2,0,12.5 0.2,0,12.5 0.2,0,12.5 0.2,0,12.5 0.2,0,12.5 0.1,0,12.6 0.1,0,12.6 0.1,0,12.6 0.1,0,12.6 0.1,0,12.6 0.1,0,12.7 0.1,0,12.7 0.1,0,12.7 0.1,0,12.7 0.1,0,12.7 0.1,0,12.7 0.1,0,12.8 0.1,0,12.8 0.1,0,12.8 0.1,0,12.8 0.1,0,12.8 0.1,0,12.9 0.1,0,12.9 0.1,0,12.9 0.1,0,12.9 0.1,0,12.9 0.1,0,13 0.1,0,13 0.1,0,13 0.1,0,13 0.1,0,12.9 0.1,0,12.9 0.1,0,12.8 0.1,0,12.7 0.1,0,12.7 0.1,0,12.6 0.1,0,12.6 0.1,0,12.5 0.1,0,12.5 0.1,0,12.4 0.1,0,12.4 0.1,0,12.3 0.1,0,12.2 0.1,0,12.2 0.1,0,12.1 0.1,0,12.1 0.1,0,12 0.1,0,12 0.1,0,11.9 0.1,0,11.9 0.1,0,11.8 0.1,0,11.7 0.1,0,11.7 0,0,11.6 0,0,11.6 0,0,11.5 0,0,11.5 0,0,11.4 0,0,11.3 0,0,11.3 0,0,11.2 0,0,11.2 0,0,11.1 0,0,11.1 0,0,11 0,0,11 0,0,10.9 0,0,10.8 0,0,10.8 0,0,10.7 0,0,10.7 0,0,10.6 0,0,10.6 0,0,10.5 0,0,10.4 0,0,10.4 0,0,10.3 0,0,10.3 0,0,10.2 0,0,10.2 0,0,10.1 0,0,10.1 0,0,10</coordinates></LinearRing></innerBoundaryIs></Polygon>" ) );
    9421                 :          1 :   QCOMPARE( exportPolygon.asKml( 1 ), expectedKml );
    9422                 :            : 
    9423                 :            : 
    9424                 :          1 :   QgsCurvePolygon exportPolygonFloat;
    9425                 :          1 :   ext = new QgsCircularString();
    9426                 :          2 :   ext->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 10, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 1 / 3.0, 0, 11, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 2 / 3.0, 0, 12, 3 )
    9427                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 1 / 3.0, 0.5, 13, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 10, 1 ) );
    9428                 :          1 :   exportPolygonFloat.setExteriorRing( ext );
    9429                 :          1 :   ring = new QgsCircularString();
    9430                 :          2 :   ring->setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 10, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 0.1 / 3.0, 0, 11, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 0.2 / 3.0, 0, 12, 3 )
    9431                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 0.1 / 3.0, 0.05 / 3.0, 13, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 10, 1 ) );
    9432                 :          1 :   exportPolygonFloat.addInteriorRing( ring );
    9433                 :            : 
    9434                 :          1 :   QString expectedJsonPrec3( "{\"coordinates\":[[[0.0,0.0,10.0],[0.333,0.0,11.0],[0.667,0.0,12.0],[0.669,0.006,12.009],[0.671,0.012,12.018],[0.673,0.018,12.027],[0.676,0.024,12.035],[0.677,0.029,12.044],[0.679,0.035,12.053],[0.681,0.042,12.062],[0.683,0.048,12.071],[0.684,0.054,12.08],[0.686,0.06,12.088],[0.687,0.066,12.097],[0.688,0.072,12.106],[0.689,0.078,12.115],[0.69,0.084,12.124],[0.691,0.091,12.133],[0.692,0.097,12.142],[0.693,0.103,12.15],[0.693,0.109,12.159],[0.694,0.116,12.168],[0.694,0.122,12.177],[0.694,0.128,12.186],[0.694,0.135,12.195],[0.694,0.141,12.204],[0.694,0.147,12.212],[0.694,0.153,12.221],[0.694,0.16,12.23],[0.693,0.166,12.239],[0.693,0.172,12.248],[0.692,0.178,12.257],[0.692,0.185,12.265],[0.691,0.191,12.274],[0.69,0.197,12.283],[0.689,0.203,12.292],[0.687,0.209,12.301],[0.686,0.216,12.31],[0.685,0.222,12.319],[0.683,0.228,12.327],[0.682,0.234,12.336],[0.68,0.24,12.345],[0.678,0.246,12.354],[0.676,0.252,12.363],[0.674,0.258,12.372],[0.672,0.264,12.381],[0.67,0.27,12.389],[0.668,0.275,12.398],[0.665,0.281,12.407],[0.663,0.287,12.416],[0.66,0.293,12.425],[0.657,0.298,12.434],[0.654,0.304,12.442],[0.652,0.31,12.451],[0.649,0.315,12.46],[0.645,0.321,12.469],[0.642,0.326,12.478],[0.639,0.331,12.487],[0.636,0.337,12.496],[0.632,0.342,12.504],[0.628,0.347,12.513],[0.625,0.352,12.522],[0.621,0.357,12.531],[0.617,0.362,12.54],[0.613,0.367,12.549],[0.609,0.372,12.558],[0.605,0.377,12.566],[0.601,0.381,12.575],[0.597,0.386,12.584],[0.592,0.39,12.593],[0.588,0.395,12.602],[0.584,0.399,12.611],[0.579,0.404,12.619],[0.574,0.408,12.628],[0.57,0.412,12.637],[0.565,0.416,12.646],[0.56,0.42,12.655],[0.555,0.424,12.664],[0.55,0.428,12.673],[0.545,0.431,12.681],[0.54,0.435,12.69],[0.535,0.439,12.699],[0.529,0.442,12.708],[0.524,0.445,12.717],[0.519,0.449,12.726],[0.513,0.452,12.735],[0.508,0.455,12.743],[0.502,0.458,12.752],[0.497,0.461,12.761],[0.491,0.464,12.77],[0.485,0.466,12.779],[0.48,0.469,12.788],[0.474,0.471,12.796],[0.468,0.474,12.805],[0.462,0.476,12.814],[0.456,0.478,12.823],[0.451,0.48,12.832],[0.445,0.482,12.841],[0.439,0.484,12.85],[0.433,0.486,12.858],[0.426,0.488,12.867],[0.42,0.489,12.876],[0.414,0.491,12.885],[0.408,0.492,12.894],[0.402,0.493,12.903],[0.396,0.495,12.912],[0.39,0.496,12.92],[0.383,0.497,12.929],[0.377,0.497,12.938],[0.371,0.498,12.947],[0.365,0.499,12.956],[0.358,0.499,12.965],[0.352,0.5,12.973],[0.346,0.5,12.982],[0.34,0.5,12.991],[0.333,0.5,13.0],[0.327,0.5,12.973],[0.321,0.5,12.947],[0.314,0.5,12.92],[0.308,0.499,12.894],[0.302,0.499,12.867],[0.296,0.498,12.841],[0.289,0.497,12.814],[0.283,0.497,12.788],[0.277,0.496,12.761],[0.271,0.495,12.735],[0.265,0.493,12.708],[0.259,0.492,12.681],[0.252,0.491,12.655],[0.246,0.489,12.628],[0.24,0.488,12.602],[0.234,0.486,12.575],[0.228,0.484,12.549],[0.222,0.482,12.522],[0.216,0.48,12.496],[0.21,0.478,12.469],[0.204,0.476,12.442],[0.198,0.474,12.416],[0.193,0.471,12.389],[0.187,0.469,12.363],[0.181,0.466,12.336],[0.176,0.464,12.31],[0.17,0.461,12.283],[0.164,0.458,12.257],[0.159,0.455,12.23],[0.153,0.452,12.204],[0.148,0.449,12.177],[0.143,0.445,12.15],[0.137,0.442,12.124],[0.132,0.439,12.097],[0.127,0.435,12.071],[0.122,0.431,12.044],[0.117,0.428,12.018],[0.112,0.424,11.991],[0.107,0.42,11.965],[0.102,0.416,11.938],[0.097,0.412,11.912],[0.092,0.408,11.885],[0.088,0.404,11.858],[0.083,0.399,11.832],[0.079,0.395,11.805],[0.074,0.39,11.779],[0.07,0.386,11.752],[0.066,0.381,11.726],[0.061,0.377,11.699],[0.057,0.372,11.673],[0.053,0.367,11.646],[0.049,0.362,11.619],[0.046,0.357,11.593],[0.042,0.352,11.566],[0.038,0.347,11.54],[0.035,0.342,11.513],[0.031,0.337,11.487],[0.028,0.331,11.46],[0.024,0.326,11.434],[0.021,0.321,11.407],[0.018,0.315,11.381],[0.015,0.31,11.354],[0.012,0.304,11.327],[0.009,0.298,11.301],[0.007,0.293,11.274],[0.004,0.287,11.248],[0.001,0.281,11.221],[-0.001,0.275,11.195],[-0.003,0.27,11.168],[-0.005,0.264,11.142],[-0.008,0.258,11.115],[-0.01,0.252,11.088],[-0.012,0.246,11.062],[-0.013,0.24,11.035],[-0.015,0.234,11.009],[-0.017,0.228,10.982],[-0.018,0.222,10.956],[-0.02,0.216,10.929],[-0.021,0.209,10.903],[-0.022,0.203,10.876],[-0.023,0.197,10.85],[-0.024,0.191,10.823],[-0.025,0.185,10.796],[-0.026,0.178,10.77],[-0.026,0.172,10.743],[-0.027,0.166,10.717],[-0.027,0.16,10.69],[-0.027,0.153,10.664],[-0.028,0.147,10.637],[-0.028,0.141,10.611],[-0.028,0.135,10.584],[-0.028,0.128,10.558],[-0.027,0.122,10.531],[-0.027,0.116,10.504],[-0.027,0.109,10.478],[-0.026,0.103,10.451],[-0.025,0.097,10.425],[-0.025,0.091,10.398],[-0.024,0.084,10.372],[-0.023,0.078,10.345],[-0.022,0.072,10.319],[-0.02,0.066,10.292],[-0.019,0.06,10.265],[-0.018,0.054,10.239],[-0.016,0.048,10.212],[-0.014,0.042,10.186],[-0.013,0.035,10.159],[-0.011,0.029,10.133],[-0.009,0.024,10.106],[-0.007,0.018,10.08],[-0.005,0.012,10.053],[-0.002,0.006,10.027],[0.0,0.0,10.0]],[[0.0,0.0,10.0],[0.033,0.0,11.0],[0.067,0.0,12.0],[0.066,0.001,12.019],[0.066,0.001,12.037],[0.065,0.002,12.056],[0.065,0.002,12.075],[0.064,0.003,12.093],[0.064,0.003,12.112],[0.063,0.004,12.131],[0.063,0.004,12.15],[0.062,0.005,12.168],[0.062,0.005,12.187],[0.061,0.006,12.206],[0.061,0.006,12.224],[0.06,0.007,12.243],[0.06,0.007,12.262],[0.059,0.008,12.28],[0.059,0.008,12.299],[0.058,0.009,12.318],[0.057,0.009,12.336],[0.057,0.009,12.355],[0.056,0.01,12.374],[0.056,0.01,12.393],[0.055,0.011,12.411],[0.054,0.011,12.43],[0.054,0.011,12.449],[0.053,0.012,12.467],[0.052,0.012,12.486],[0.052,0.012,12.505],[0.051,0.013,12.523],[0.051,0.013,12.542],[0.05,0.013,12.561],[0.049,0.014,12.579],[0.049,0.014,12.598],[0.048,0.014,12.617],[0.047,0.014,12.636],[0.046,0.015,12.654],[0.046,0.015,12.673],[0.045,0.015,12.692],[0.044,0.015,12.71],[0.044,0.015,12.729],[0.043,0.016,12.748],[0.042,0.016,12.766],[0.042,0.016,12.785],[0.041,0.016,12.804],[0.04,0.016,12.822],[0.039,0.016,12.841],[0.039,0.016,12.86],[0.038,0.016,12.879],[0.037,0.016,12.897],[0.037,0.017,12.916],[0.036,0.017,12.935],[0.035,0.017,12.953],[0.034,0.017,12.972],[0.034,0.017,12.991],[0.033,0.017,12.972],[0.032,0.017,12.916],[0.032,0.017,12.86],[0.031,0.017,12.804],[0.03,0.017,12.748],[0.029,0.016,12.692],[0.029,0.016,12.636],[0.028,0.016,12.579],[0.027,0.016,12.523],[0.027,0.016,12.467],[0.026,0.016,12.411],[0.025,0.016,12.355],[0.024,0.016,12.299],[0.024,0.016,12.243],[0.023,0.015,12.187],[0.022,0.015,12.131],[0.022,0.015,12.075],[0.021,0.015,12.019],[0.02,0.015,11.963],[0.02,0.014,11.907],[0.019,0.014,11.85],[0.018,0.014,11.794],[0.017,0.014,11.738],[0.017,0.013,11.682],[0.016,0.013,11.626],[0.016,0.013,11.57],[0.015,0.012,11.514],[0.014,0.012,11.458],[0.014,0.012,11.402],[0.013,0.011,11.346],[0.012,0.011,11.29],[0.012,0.011,11.234],[0.011,0.01,11.178],[0.01,0.01,11.121],[0.01,0.009,11.065],[0.009,0.009,11.009],[0.009,0.009,10.953],[0.008,0.008,10.897],[0.008,0.008,10.841],[0.007,0.007,10.785],[0.006,0.007,10.729],[0.006,0.006,10.673],[0.005,0.006,10.617],[0.005,0.005,10.561],[0.004,0.005,10.505],[0.004,0.004,10.449],[0.003,0.004,10.393],[0.003,0.003,10.336],[0.002,0.003,10.28],[0.002,0.002,10.224],[0.001,0.002,10.168],[0.001,0.001,10.112],[0.0,0.001,10.056],[0.0,0.0,10.0]]],\"type\":\"Polygon\"}" );
    9435                 :          1 :   res = exportPolygonFloat.asJson( 3 );
    9436                 :          1 :   QCOMPARE( exportPolygonFloat.asJson( 3 ), expectedJsonPrec3 );
    9437                 :            : 
    9438                 :            :   // as GML2
    9439                 :          2 :   QString expectedGML2( QStringLiteral( "<Polygon xmlns=\"gml\"><outerBoundaryIs xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">0,0 1,0 2,0 1.98685,0.01722 1.97341,0.03421 1.95967,0.05096 1.94564,0.06747 1.93133,0.08374 1.91674,0.09976 1.90188,0.11552 1.88674,0.13102 1.87134,0.14625 1.85567,0.16122 1.83975,0.17592 1.82358,0.19033 1.80716,0.20446 1.79049,0.21831 1.77359,0.23186 1.75646,0.24512 1.7391,0.25809 1.72151,0.27074 1.70371,0.2831 1.6857,0.29514 1.66748,0.30687 1.64907,0.31828 1.63045,0.32936 1.61165,0.34013 1.59267,0.35057 1.5735,0.36067 1.55417,0.37045 1.53466,0.37988 1.515,0.38898 1.49518,0.39773 1.47522,0.40614 1.45511,0.41421 1.43486,0.42192 1.41448,0.42928 1.39398,0.43629 1.37336,0.44294 1.35263,0.44923 1.33179,0.45516 1.31086,0.46073 1.28983,0.46594 1.26871,0.47078 1.24751,0.47525 1.22624,0.47936 1.2049,0.48309 1.18349,0.48646 1.16204,0.48945 1.14053,0.49208 1.11898,0.49432 1.0974,0.4962 1.07578,0.4977 1.05415,0.49883 1.0325,0.49958 1.01083,0.49995 0.98917,0.49995 0.9675,0.49958 0.94585,0.49883 0.92422,0.4977 0.9026,0.4962 0.88102,0.49432 0.85947,0.49208 0.83796,0.48945 0.81651,0.48646 0.7951,0.48309 0.77376,0.47936 0.75249,0.47525 0.73129,0.47078 0.71017,0.46594 0.68914,0.46073 0.66821,0.45516 0.64737,0.44923 0.62664,0.44294 0.60602,0.43629 0.58552,0.42928 0.56514,0.42192 0.54489,0.41421 0.52478,0.40614 0.50482,0.39773 0.485,0.38898 0.46534,0.37988 0.44583,0.37045 0.4265,0.36067 0.40733,0.35057 0.38835,0.34013 0.36955,0.32936 0.35093,0.31828 0.33252,0.30687 0.3143,0.29514 0.29629,0.2831 0.27849,0.27074 0.2609,0.25809 0.24354,0.24512 0.22641,0.23186 0.20951,0.21831 0.19284,0.20446 0.17642,0.19033 0.16025,0.17592 0.14433,0.16122 0.12866,0.14625 0.11326,0.13102 0.09812,0.11552 0.08326,0.09976 0.06867,0.08374 0.05436,0.06747 0.04033,0.05096 0.02659,0.03421 0.01315,0.01722 0,0</coordinates></LinearRing></outerBoundaryIs><innerBoundaryIs xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">0,0 0.1,0 0.2,0 0.19869,0.00172 0.19734,0.00342 0.19597,0.0051 0.19456,0.00675 0.19313,0.00837 0.19167,0.00998 0.19019,0.01155 0.18867,0.0131 0.18713,0.01463 0.18557,0.01612 0.18398,0.01759 0.18236,0.01903 0.18072,0.02045 0.17905,0.02183 0.17736,0.02319 0.17565,0.02451 0.17391,0.02581 0.17215,0.02707 0.17037,0.02831 0.16857,0.02951 0.16675,0.03069 0.16491,0.03183 0.16305,0.03294 0.16117,0.03401 0.15927,0.03506 0.15735,0.03607 0.15542,0.03704 0.15347,0.03799 0.1515,0.0389 0.14952,0.03977 0.14752,0.04061 0.14551,0.04142 0.14349,0.04219 0.14145,0.04293 0.1394,0.04363 0.13734,0.04429 0.13526,0.04492 0.13318,0.04552 0.13109,0.04607 0.12898,0.04659 0.12687,0.04708 0.12475,0.04753 0.12262,0.04794 0.12049,0.04831 0.11835,0.04865 0.1162,0.04895 0.11405,0.04921 0.1119,0.04943 0.10974,0.04962 0.10758,0.04977 0.10541,0.04988 0.10325,0.04996 0.10108,0.05 0.09892,0.05 0.09675,0.04996 0.09459,0.04988 0.09242,0.04977 0.09026,0.04962 0.0881,0.04943 0.08595,0.04921 0.0838,0.04895 0.08165,0.04865 0.07951,0.04831 0.07738,0.04794 0.07525,0.04753 0.07313,0.04708 0.07102,0.04659 0.06891,0.04607 0.06682,0.04552 0.06474,0.04492 0.06266,0.04429 0.0606,0.04363 0.05855,0.04293 0.05651,0.04219 0.05449,0.04142 0.05248,0.04061 0.05048,0.03977 0.0485,0.0389 0.04653,0.03799 0.04458,0.03704 0.04265,0.03607 0.04073,0.03506 0.03883,0.03401 0.03695,0.03294 0.03509,0.03183 0.03325,0.03069 0.03143,0.02951 0.02963,0.02831 0.02785,0.02707 0.02609,0.02581 0.02435,0.02451 0.02264,0.02319 0.02095,0.02183 0.01928,0.02045 0.01764,0.01903 0.01602,0.01759 0.01443,0.01612 0.01287,0.01463 0.01133,0.0131 0.00981,0.01155 0.00833,0.00998 0.00687,0.00837 0.00544,0.00675 0.00403,0.0051 0.00266,0.00342 0.00131,0.00172 0,0</coordinates></LinearRing></innerBoundaryIs></Polygon>" ) );
    9440                 :          1 :   res = elemToString( exportPolygon.asGml2( doc, 5 ) );
    9441                 :          3 :   QGSCOMPAREGML( res, expectedGML2 );
    9442                 :            : 
    9443                 :          2 :   QString expectedGML2prec2( QStringLiteral( "<Polygon xmlns=\"gml\"><outerBoundaryIs xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">0,0 1,0 2,0 1.99,0.02 1.97,0.03 1.96,0.05 1.95,0.07 1.93,0.08 1.92,0.1 1.9,0.12 1.89,0.13 1.87,0.15 1.86,0.16 1.84,0.18 1.82,0.19 1.81,0.2 1.79,0.22 1.77,0.23 1.76,0.25 1.74,0.26 1.72,0.27 1.7,0.28 1.69,0.3 1.67,0.31 1.65,0.32 1.63,0.33 1.61,0.34 1.59,0.35 1.57,0.36 1.55,0.37 1.53,0.38 1.52,0.39 1.5,0.4 1.48,0.41 1.46,0.41 1.43,0.42 1.41,0.43 1.39,0.44 1.37,0.44 1.35,0.45 1.33,0.46 1.31,0.46 1.29,0.47 1.27,0.47 1.25,0.48 1.23,0.48 1.2,0.48 1.18,0.49 1.16,0.49 1.14,0.49 1.12,0.49 1.1,0.5 1.08,0.5 1.05,0.5 1.03,0.5 1.01,0.5 0.99,0.5 0.97,0.5 0.95,0.5 0.92,0.5 0.9,0.5 0.88,0.49 0.86,0.49 0.84,0.49 0.82,0.49 0.8,0.48 0.77,0.48 0.75,0.48 0.73,0.47 0.71,0.47 0.69,0.46 0.67,0.46 0.65,0.45 0.63,0.44 0.61,0.44 0.59,0.43 0.57,0.42 0.54,0.41 0.52,0.41 0.5,0.4 0.48,0.39 0.47,0.38 0.45,0.37 0.43,0.36 0.41,0.35 0.39,0.34 0.37,0.33 0.35,0.32 0.33,0.31 0.31,0.3 0.3,0.28 0.28,0.27 0.26,0.26 0.24,0.25 0.23,0.23 0.21,0.22 0.19,0.2 0.18,0.19 0.16,0.18 0.14,0.16 0.13,0.15 0.11,0.13 0.1,0.12 0.08,0.1 0.07,0.08 0.05,0.07 0.04,0.05 0.03,0.03 0.01,0.02 0,0</coordinates></LinearRing></outerBoundaryIs><innerBoundaryIs xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">0,0 0.1,0 0.2,0 0.2,0 0.2,0 0.2,0.01 0.19,0.01 0.19,0.01 0.19,0.01 0.19,0.01 0.19,0.01 0.19,0.01 0.19,0.02 0.18,0.02 0.18,0.02 0.18,0.02 0.18,0.02 0.18,0.02 0.18,0.02 0.17,0.03 0.17,0.03 0.17,0.03 0.17,0.03 0.17,0.03 0.16,0.03 0.16,0.03 0.16,0.03 0.16,0.04 0.16,0.04 0.16,0.04 0.15,0.04 0.15,0.04 0.15,0.04 0.15,0.04 0.15,0.04 0.14,0.04 0.14,0.04 0.14,0.04 0.14,0.04 0.14,0.04 0.13,0.05 0.13,0.05 0.13,0.05 0.13,0.05 0.12,0.05 0.12,0.05 0.12,0.05 0.12,0.05 0.12,0.05 0.11,0.05 0.11,0.05 0.11,0.05 0.11,0.05 0.11,0.05 0.1,0.05 0.1,0.05 0.1,0.05 0.1,0.05 0.09,0.05 0.09,0.05 0.09,0.05 0.09,0.05 0.09,0.05 0.08,0.05 0.08,0.05 0.08,0.05 0.08,0.05 0.08,0.05 0.07,0.05 0.07,0.05 0.07,0.05 0.07,0.05 0.06,0.04 0.06,0.04 0.06,0.04 0.06,0.04 0.06,0.04 0.05,0.04 0.05,0.04 0.05,0.04 0.05,0.04 0.05,0.04 0.04,0.04 0.04,0.04 0.04,0.04 0.04,0.03 0.04,0.03 0.04,0.03 0.03,0.03 0.03,0.03 0.03,0.03 0.03,0.03 0.03,0.03 0.02,0.02 0.02,0.02 0.02,0.02 0.02,0.02 0.02,0.02 0.02,0.02 0.01,0.02 0.01,0.01 0.01,0.01 0.01,0.01 0.01,0.01 0.01,0.01 0.01,0.01 0,0.01 0,0 0,0 0,0</coordinates></LinearRing></innerBoundaryIs></Polygon>" ) );
    9444                 :          1 :   res = elemToString( exportPolygon.asGml2( doc, 2 ) );
    9445                 :          3 :   QGSCOMPAREGML( res, expectedGML2prec2 );
    9446                 :            : 
    9447                 :            :   //as GML3
    9448                 :          2 :   QString expectedGML3( QStringLiteral( "<Polygon xmlns=\"gml\"><exterior xmlns=\"gml\"><Curve xmlns=\"gml\"><segments xmlns=\"gml\"><ArcString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"3\">0 0 10 1 0 11 2 0 12 1 0.5 13 0 0 10</posList></ArcString></segments></Curve></exterior><interior xmlns=\"gml\"><Curve xmlns=\"gml\"><segments xmlns=\"gml\"><ArcString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"3\">0 0 10 0.10000000000000001 0 11 0.20000000000000001 0 12 0.10000000000000001 0.05 13 0 0 10</posList></ArcString></segments></Curve></interior></Polygon>" ) );
    9449                 :          1 :   res = elemToString( exportPolygon.asGml3( doc ) );
    9450                 :          1 :   QCOMPARE( res, expectedGML3 );
    9451                 :            : 
    9452                 :          2 :   QString expectedGML3prec3( QStringLiteral( "<Polygon xmlns=\"gml\"><exterior xmlns=\"gml\"><Curve xmlns=\"gml\"><segments xmlns=\"gml\"><ArcString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"3\">0 0 10 1 0 11 2 0 12 1 0.5 13 0 0 10</posList></ArcString></segments></Curve></exterior><interior xmlns=\"gml\"><Curve xmlns=\"gml\"><segments xmlns=\"gml\"><ArcString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"3\">0 0 10 0.1 0 11 0.2 0 12 0.1 0.05 13 0 0 10</posList></ArcString></segments></Curve></interior></Polygon>" ) );
    9453                 :          1 :   res = elemToString( exportPolygon.asGml3( doc, 3 ) );
    9454                 :          1 :   QCOMPARE( res, expectedGML3prec3 );
    9455                 :            : 
    9456                 :            :   //removing the fourth to last vertex removes the whole ring
    9457                 :          1 :   QgsCurvePolygon p20;
    9458                 :          1 :   QgsCircularString *p20ExteriorRing = new QgsCircularString();
    9459                 :          1 :   p20ExteriorRing->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 ) << QgsPoint( 0, 0 ) );
    9460                 :          1 :   p20.setExteriorRing( p20ExteriorRing );
    9461                 :          1 :   QVERIFY( p20.exteriorRing() );
    9462                 :          1 :   p20.deleteVertex( QgsVertexId( 0, 0, 2 ) );
    9463                 :          1 :   QVERIFY( !p20.exteriorRing() );
    9464                 :            : 
    9465                 :            :   //boundary
    9466                 :          1 :   QgsCircularString boundary1;
    9467                 :          2 :   boundary1.setPoints( QgsPointSequence() << QgsPoint( 0, 0, 1 ) << QgsPoint( 1, 0, 2 ) << QgsPoint( 2, 0, 3 )
    9468                 :          1 :                        << QgsPoint( 1, 0.5, 4 ) << QgsPoint( 0, 0, 1 ) );
    9469                 :          1 :   QgsCurvePolygon boundaryPolygon;
    9470                 :          1 :   QVERIFY( !boundaryPolygon.boundary() );
    9471                 :            : 
    9472                 :          1 :   boundaryPolygon.setExteriorRing( boundary1.clone() );
    9473                 :          1 :   QgsAbstractGeometry *boundary = boundaryPolygon.boundary();
    9474                 :          1 :   QgsCircularString *lineBoundary = dynamic_cast< QgsCircularString * >( boundary );
    9475                 :          1 :   QVERIFY( lineBoundary );
    9476                 :          1 :   QCOMPARE( lineBoundary->numPoints(), 5 );
    9477                 :          1 :   QCOMPARE( lineBoundary->xAt( 0 ), 0.0 );
    9478                 :          1 :   QCOMPARE( lineBoundary->xAt( 1 ), 1.0 );
    9479                 :          1 :   QCOMPARE( lineBoundary->xAt( 2 ), 2.0 );
    9480                 :          1 :   QCOMPARE( lineBoundary->xAt( 3 ), 1.0 );
    9481                 :          1 :   QCOMPARE( lineBoundary->xAt( 4 ), 0.0 );
    9482                 :          1 :   QCOMPARE( lineBoundary->yAt( 0 ), 0.0 );
    9483                 :          1 :   QCOMPARE( lineBoundary->yAt( 1 ), 0.0 );
    9484                 :          1 :   QCOMPARE( lineBoundary->yAt( 2 ), 0.0 );
    9485                 :          1 :   QCOMPARE( lineBoundary->yAt( 3 ), 0.5 );
    9486                 :          1 :   QCOMPARE( lineBoundary->yAt( 4 ), 0.0 );
    9487                 :          1 :   delete boundary;
    9488                 :            : 
    9489                 :            :   // add interior rings
    9490                 :          1 :   QgsCircularString boundaryRing1;
    9491                 :          1 :   boundaryRing1.setPoints( QgsPointSequence() << QgsPoint( 0.1, 0.1 ) << QgsPoint( 0.2, 0.1 ) << QgsPoint( 0.2, 0.2 ) );
    9492                 :          1 :   QgsCircularString boundaryRing2;
    9493                 :          1 :   boundaryRing2.setPoints( QgsPointSequence() << QgsPoint( 0.8, 0.8 ) << QgsPoint( 0.9, 0.8 ) << QgsPoint( 0.9, 0.9 ) );
    9494                 :          1 :   boundaryPolygon.setInteriorRings( QVector< QgsCurve * >() << boundaryRing1.clone() << boundaryRing2.clone() );
    9495                 :          1 :   boundary = boundaryPolygon.boundary();
    9496                 :          1 :   QgsMultiCurve *multiLineBoundary = dynamic_cast< QgsMultiCurve * >( boundary );
    9497                 :          1 :   QVERIFY( multiLineBoundary );
    9498                 :          1 :   QCOMPARE( multiLineBoundary->numGeometries(), 3 );
    9499                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 0 ) )->numPoints(), 5 );
    9500                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 0 ) )->xAt( 0 ), 0.0 );
    9501                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 0 ) )->xAt( 1 ), 1.0 );
    9502                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 0 ) )->xAt( 2 ), 2.0 );
    9503                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 0 ) )->xAt( 3 ), 1.0 );
    9504                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 0 ) )->xAt( 4 ), 0.0 );
    9505                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 0 ) )->yAt( 0 ), 0.0 );
    9506                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 0 ) )->yAt( 1 ), 0.0 );
    9507                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 0 ) )->yAt( 2 ), 0.0 );
    9508                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 0 ) )->yAt( 3 ), 0.5 );
    9509                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 0 ) )->yAt( 4 ), 0.0 );
    9510                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 1 ) )->numPoints(), 3 );
    9511                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 1 ) )->xAt( 0 ), 0.1 );
    9512                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 1 ) )->xAt( 1 ), 0.2 );
    9513                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 1 ) )->xAt( 2 ), 0.2 );
    9514                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 1 ) )->yAt( 0 ), 0.1 );
    9515                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 1 ) )->yAt( 1 ), 0.1 );
    9516                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 1 ) )->yAt( 2 ), 0.2 );
    9517                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 2 ) )->numPoints(), 3 );
    9518                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 2 ) )->xAt( 0 ), 0.8 );
    9519                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 2 ) )->xAt( 1 ), 0.9 );
    9520                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 2 ) )->xAt( 2 ), 0.9 );
    9521                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 2 ) )->yAt( 0 ), 0.8 );
    9522                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 2 ) )->yAt( 1 ), 0.8 );
    9523                 :          1 :   QCOMPARE( dynamic_cast< QgsCircularString * >( multiLineBoundary->geometryN( 2 ) )->yAt( 2 ), 0.9 );
    9524                 :          1 :   boundaryPolygon.setInteriorRings( QVector< QgsCurve * >() );
    9525                 :          1 :   delete boundary;
    9526                 :            : 
    9527                 :            :   //test boundary with z
    9528                 :          2 :   boundary1.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 10 ) << QgsPoint( QgsWkbTypes::PointZ, 1, 0, 15 )
    9529                 :          1 :                        << QgsPoint( QgsWkbTypes::PointZ, 1, 1, 20 ) );
    9530                 :          1 :   boundaryPolygon.setExteriorRing( boundary1.clone() );
    9531                 :          1 :   boundary = boundaryPolygon.boundary();
    9532                 :          1 :   lineBoundary = dynamic_cast< QgsCircularString * >( boundary );
    9533                 :          1 :   QVERIFY( lineBoundary );
    9534                 :          1 :   QCOMPARE( lineBoundary->numPoints(), 3 );
    9535                 :          1 :   QCOMPARE( lineBoundary->wkbType(), QgsWkbTypes::CircularStringZ );
    9536                 :          1 :   QCOMPARE( lineBoundary->pointN( 0 ).z(), 10.0 );
    9537                 :          1 :   QCOMPARE( lineBoundary->pointN( 1 ).z(), 15.0 );
    9538                 :          1 :   QCOMPARE( lineBoundary->pointN( 2 ).z(), 20.0 );
    9539                 :          1 :   delete boundary;
    9540                 :            : 
    9541                 :            :   // remove interior rings
    9542                 :          1 :   QgsCircularString removeRingsExt;
    9543                 :          1 :   removeRingsExt.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 )  << QgsPoint( 0, 0 ) );
    9544                 :          1 :   QgsCurvePolygon removeRings1;
    9545                 :          1 :   removeRings1.removeInteriorRings();
    9546                 :            : 
    9547                 :          1 :   removeRings1.setExteriorRing( boundary1.clone() );
    9548                 :          1 :   removeRings1.removeInteriorRings();
    9549                 :          1 :   QCOMPARE( removeRings1.numInteriorRings(), 0 );
    9550                 :            : 
    9551                 :            :   // add interior rings
    9552                 :          1 :   QgsCircularString removeRingsRing1;
    9553                 :          2 :   removeRingsRing1.setPoints( QgsPointSequence() << QgsPoint( 0, 0, 1 ) << QgsPoint( 0.1, 1, 2 ) << QgsPoint( 0, 2, 3 )
    9554                 :          1 :                               << QgsPoint( -0.1, 1.2, 4 ) << QgsPoint( 0, 0, 1 ) );
    9555                 :          1 :   QgsCircularString removeRingsRing2;
    9556                 :          2 :   removeRingsRing2.setPoints( QgsPointSequence() << QgsPoint( 0, 0, 1 ) << QgsPoint( 0.01, 0.1, 2 ) << QgsPoint( 0, 0.2, 3 )
    9557                 :          1 :                               << QgsPoint( -0.01, 0.12, 4 ) << QgsPoint( 0, 0, 1 ) );
    9558                 :          1 :   removeRings1.setInteriorRings( QVector< QgsCurve * >() << removeRingsRing1.clone() << removeRingsRing2.clone() );
    9559                 :            : 
    9560                 :            :   // remove ring with size filter
    9561                 :          1 :   removeRings1.removeInteriorRings( 0.05 );
    9562                 :          1 :   QCOMPARE( removeRings1.numInteriorRings(), 1 );
    9563                 :            : 
    9564                 :            :   // remove ring with no size filter
    9565                 :          1 :   removeRings1.removeInteriorRings();
    9566                 :          1 :   QCOMPARE( removeRings1.numInteriorRings(), 0 );
    9567                 :            : 
    9568                 :            :   // cast
    9569                 :          1 :   QVERIFY( !QgsCurvePolygon().cast( nullptr ) );
    9570                 :          1 :   QgsCurvePolygon pCast;
    9571                 :          1 :   QVERIFY( QgsCurvePolygon().cast( &pCast ) );
    9572                 :          1 :   QgsCurvePolygon pCast2;
    9573                 :          2 :   pCast2.fromWkt( QStringLiteral( "CurvePolygonZ((0 0 0, 0 1 1, 1 0 2, 0 0 0))" ) );
    9574                 :          1 :   QVERIFY( QgsCurvePolygon().cast( &pCast2 ) );
    9575                 :          2 :   pCast2.fromWkt( QStringLiteral( "CurvePolygonM((0 0 1, 0 1 2, 1 0 3, 0 0 1))" ) );
    9576                 :          1 :   QVERIFY( QgsCurvePolygon().cast( &pCast2 ) );
    9577                 :          2 :   pCast2.fromWkt( QStringLiteral( "CurvePolygonZM((0 0 0 1, 0 1 1 2, 1 0 2 3, 0 0 0 1))" ) );
    9578                 :          1 :   QVERIFY( QgsCurvePolygon().cast( &pCast2 ) );
    9579                 :            : 
    9580                 :            :   // draw - most tests are in test_qgsgeometry.py
    9581                 :          1 :   QgsCurvePolygon empty;
    9582                 :          1 :   QPainter p;
    9583                 :          1 :   empty.draw( p ); //no crash!
    9584                 :            : 
    9585                 :            : 
    9586                 :            :   // closestSegment
    9587                 :          1 :   QgsPoint pt;
    9588                 :          1 :   QgsVertexId v;
    9589                 :          1 :   int leftOf = 0;
    9590                 :          1 :   ( void )empty.closestSegment( QgsPoint( 1, 2 ), pt, v ); // empty curve, just want no crash
    9591                 :            : 
    9592                 :          1 :   QgsCurvePolygon cp12;
    9593                 :          1 :   QgsLineString cp12ls;
    9594                 :          1 :   cp12ls.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) << QgsPoint( 7, 12 ) << QgsPoint( 5, 15 ) << QgsPoint( 5, 10 ) );
    9595                 :          1 :   cp12.setExteriorRing( cp12ls.clone() );
    9596                 :          1 :   QGSCOMPARENEAR( cp12.closestSegment( QgsPoint( 4, 11 ), pt, v, &leftOf ), 1.0, 0.0001 );
    9597                 :          1 :   QGSCOMPARENEAR( pt.x(), 5, 0.01 );
    9598                 :          1 :   QGSCOMPARENEAR( pt.y(), 11, 0.01 );
    9599                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 3 ) );
    9600                 :          1 :   QCOMPARE( leftOf, 1 );
    9601                 :          1 :   QGSCOMPARENEAR( cp12.closestSegment( QgsPoint( 8, 11 ), pt, v, &leftOf ),  2.0, 0.0001 );
    9602                 :          1 :   QGSCOMPARENEAR( pt.x(), 7, 0.01 );
    9603                 :          1 :   QGSCOMPARENEAR( pt.y(), 12, 0.01 );
    9604                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    9605                 :          1 :   QCOMPARE( leftOf, 1 );
    9606                 :          1 :   QGSCOMPARENEAR( cp12.closestSegment( QgsPoint( 6, 11.5 ), pt, v, &leftOf ), 0.125000, 0.0001 );
    9607                 :          1 :   QGSCOMPARENEAR( pt.x(), 6.25, 0.01 );
    9608                 :          1 :   QGSCOMPARENEAR( pt.y(), 11.25, 0.01 );
    9609                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    9610                 :          1 :   QCOMPARE( leftOf, -1 );
    9611                 :          1 :   QGSCOMPARENEAR( cp12.closestSegment( QgsPoint( 7, 16 ), pt, v, &leftOf ), 4.923077, 0.0001 );
    9612                 :          1 :   QGSCOMPARENEAR( pt.x(), 5.153846, 0.01 );
    9613                 :          1 :   QGSCOMPARENEAR( pt.y(), 14.769231, 0.01 );
    9614                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    9615                 :          1 :   QCOMPARE( leftOf, 1 );
    9616                 :          1 :   QGSCOMPARENEAR( cp12.closestSegment( QgsPoint( 5.5, 13.5 ), pt, v, &leftOf ), 0.173077, 0.0001 );
    9617                 :          1 :   QGSCOMPARENEAR( pt.x(), 5.846154, 0.01 );
    9618                 :          1 :   QGSCOMPARENEAR( pt.y(), 13.730769, 0.01 );
    9619                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    9620                 :          1 :   QCOMPARE( leftOf, -1 );
    9621                 :            :   // point directly on segment
    9622                 :          1 :   QCOMPARE( cp12.closestSegment( QgsPoint( 5, 15 ), pt, v, &leftOf ), 0.0 );
    9623                 :          1 :   QCOMPARE( pt, QgsPoint( 5, 15 ) );
    9624                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    9625                 :          1 :   QCOMPARE( leftOf, 0 );
    9626                 :            : 
    9627                 :            :   // with interior ring
    9628                 :          1 :   cp12ls.setPoints( QgsPointSequence() << QgsPoint( 6, 11.5 ) << QgsPoint( 6.5, 12 ) << QgsPoint( 6, 13 ) << QgsPoint( 6, 11.5 ) );
    9629                 :          1 :   cp12.addInteriorRing( cp12ls.clone() );
    9630                 :          1 :   QGSCOMPARENEAR( cp12.closestSegment( QgsPoint( 4, 11 ), pt, v, &leftOf ), 1.0, 0.0001 );
    9631                 :          1 :   QGSCOMPARENEAR( pt.x(), 5, 0.01 );
    9632                 :          1 :   QGSCOMPARENEAR( pt.y(), 11, 0.01 );
    9633                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 3 ) );
    9634                 :          1 :   QCOMPARE( leftOf, 1 );
    9635                 :          1 :   QGSCOMPARENEAR( cp12.closestSegment( QgsPoint( 8, 11 ), pt, v, &leftOf ),  2.0, 0.0001 );
    9636                 :          1 :   QGSCOMPARENEAR( pt.x(), 7, 0.01 );
    9637                 :          1 :   QGSCOMPARENEAR( pt.y(), 12, 0.01 );
    9638                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    9639                 :          1 :   QCOMPARE( leftOf, 1 );
    9640                 :          1 :   QGSCOMPARENEAR( cp12.closestSegment( QgsPoint( 6, 11.4 ), pt, v, &leftOf ), 0.01, 0.0001 );
    9641                 :          1 :   QGSCOMPARENEAR( pt.x(), 6.0, 0.01 );
    9642                 :          1 :   QGSCOMPARENEAR( pt.y(), 11.5, 0.01 );
    9643                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 1, 1 ) );
    9644                 :          1 :   QCOMPARE( leftOf, 1 );
    9645                 :          1 :   QGSCOMPARENEAR( cp12.closestSegment( QgsPoint( 7, 16 ), pt, v, &leftOf ), 4.923077, 0.0001 );
    9646                 :          1 :   QGSCOMPARENEAR( pt.x(), 5.153846, 0.01 );
    9647                 :          1 :   QGSCOMPARENEAR( pt.y(), 14.769231, 0.01 );
    9648                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    9649                 :          1 :   QCOMPARE( leftOf, 1 );
    9650                 :          1 :   QGSCOMPARENEAR( cp12.closestSegment( QgsPoint( 5.5, 13.5 ), pt, v, &leftOf ), 0.173077, 0.0001 );
    9651                 :          1 :   QGSCOMPARENEAR( pt.x(), 5.846154, 0.01 );
    9652                 :          1 :   QGSCOMPARENEAR( pt.y(), 13.730769, 0.01 );
    9653                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    9654                 :          1 :   QCOMPARE( leftOf, -1 );
    9655                 :            :   // point directly on segment
    9656                 :          1 :   QCOMPARE( cp12.closestSegment( QgsPoint( 6, 13 ), pt, v, &leftOf ), 0.0 );
    9657                 :          1 :   QCOMPARE( pt, QgsPoint( 6, 13 ) );
    9658                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 1, 2 ) );
    9659                 :          1 :   QCOMPARE( leftOf, 0 );
    9660                 :            : 
    9661                 :            :   //nextVertex
    9662                 :          1 :   QgsCurvePolygon cp13;
    9663                 :          1 :   QVERIFY( !cp13.nextVertex( v, pt ) );
    9664                 :          1 :   v = QgsVertexId( 0, 0, -2 );
    9665                 :          1 :   QVERIFY( !cp13.nextVertex( v, pt ) );
    9666                 :          1 :   v = QgsVertexId( 0, 0, 10 );
    9667                 :          1 :   QVERIFY( !cp13.nextVertex( v, pt ) );
    9668                 :          1 :   QgsLineString lp22;
    9669                 :          1 :   lp22.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 12 ) << QgsPoint( 1, 2 ) );
    9670                 :          1 :   cp13.setExteriorRing( lp22.clone() );
    9671                 :          1 :   v = QgsVertexId( 0, 0, 4 ); //out of range
    9672                 :          1 :   QVERIFY( !cp13.nextVertex( v, pt ) );
    9673                 :          1 :   v = QgsVertexId( 0, 0, -5 );
    9674                 :          1 :   QVERIFY( cp13.nextVertex( v, pt ) );
    9675                 :          1 :   v = QgsVertexId( 0, 0, -1 );
    9676                 :          1 :   QVERIFY( cp13.nextVertex( v, pt ) );
    9677                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 0 ) );
    9678                 :          1 :   QCOMPARE( pt, QgsPoint( 1, 2 ) );
    9679                 :          1 :   QVERIFY( cp13.nextVertex( v, pt ) );
    9680                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
    9681                 :          1 :   QCOMPARE( pt, QgsPoint( 11, 12 ) );
    9682                 :          1 :   QVERIFY( cp13.nextVertex( v, pt ) );
    9683                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
    9684                 :          1 :   QCOMPARE( pt, QgsPoint( 1, 12 ) );
    9685                 :          1 :   QVERIFY( cp13.nextVertex( v, pt ) );
    9686                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 3 ) );
    9687                 :          1 :   QCOMPARE( pt, QgsPoint( 1, 2 ) );
    9688                 :          1 :   v = QgsVertexId( 0, 1, 0 );
    9689                 :          1 :   QVERIFY( !cp13.nextVertex( v, pt ) );
    9690                 :          1 :   v = QgsVertexId( 1, 0, 0 );
    9691                 :          1 :   QVERIFY( cp13.nextVertex( v, pt ) );
    9692                 :          1 :   QCOMPARE( v, QgsVertexId( 1, 0, 1 ) ); //test that part number is maintained
    9693                 :          1 :   QCOMPARE( pt, QgsPoint( 11, 12 ) );
    9694                 :            :   // add interior ring
    9695                 :          1 :   lp22.setPoints( QgsPointSequence() << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) << QgsPoint( 11, 22 ) << QgsPoint( 11, 12 ) );
    9696                 :          1 :   cp13.addInteriorRing( lp22.clone() );
    9697                 :          1 :   v = QgsVertexId( 0, 1, 4 ); //out of range
    9698                 :          1 :   QVERIFY( !cp13.nextVertex( v, pt ) );
    9699                 :          1 :   v = QgsVertexId( 0, 1, -5 );
    9700                 :          1 :   QVERIFY( cp13.nextVertex( v, pt ) );
    9701                 :          1 :   v = QgsVertexId( 0, 1, -1 );
    9702                 :          1 :   QVERIFY( cp13.nextVertex( v, pt ) );
    9703                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 1, 0 ) );
    9704                 :          1 :   QCOMPARE( pt, QgsPoint( 11, 12 ) );
    9705                 :          1 :   QVERIFY( cp13.nextVertex( v, pt ) );
    9706                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 1, 1 ) );
    9707                 :          1 :   QCOMPARE( pt, QgsPoint( 21, 22 ) );
    9708                 :          1 :   QVERIFY( cp13.nextVertex( v, pt ) );
    9709                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 1, 2 ) );
    9710                 :          1 :   QCOMPARE( pt, QgsPoint( 11, 22 ) );
    9711                 :          1 :   QVERIFY( cp13.nextVertex( v, pt ) );
    9712                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 1, 3 ) );
    9713                 :          1 :   QCOMPARE( pt, QgsPoint( 11, 12 ) );
    9714                 :          1 :   v = QgsVertexId( 0, 2, 0 );
    9715                 :          1 :   QVERIFY( !cp13.nextVertex( v, pt ) );
    9716                 :          1 :   v = QgsVertexId( 1, 1, 0 );
    9717                 :          1 :   QVERIFY( cp13.nextVertex( v, pt ) );
    9718                 :          1 :   QCOMPARE( v, QgsVertexId( 1, 1, 1 ) ); //test that part number is maintained
    9719                 :          1 :   QCOMPARE( pt, QgsPoint( 21, 22 ) );
    9720                 :            : 
    9721                 :            :   // dropZValue
    9722                 :          1 :   QgsCurvePolygon p23;
    9723                 :          1 :   p23.dropZValue();
    9724                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::CurvePolygon );
    9725                 :          1 :   QgsLineString lp23;
    9726                 :          1 :   lp23.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 12 ) << QgsPoint( 1, 2 ) );
    9727                 :          1 :   p23.setExteriorRing( lp23.clone() );
    9728                 :          1 :   p23.addInteriorRing( lp23.clone() );
    9729                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::CurvePolygon );
    9730                 :          1 :   p23.dropZValue(); // not z
    9731                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::CurvePolygon );
    9732                 :          1 :   QCOMPARE( p23.exteriorRing()->wkbType(), QgsWkbTypes::LineString );
    9733                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.exteriorRing() )->pointN( 0 ), QgsPoint( 1, 2 ) );
    9734                 :          1 :   QCOMPARE( p23.interiorRing( 0 )->wkbType(), QgsWkbTypes::LineString );
    9735                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 1, 2 ) );
    9736                 :            :   // with z
    9737                 :          1 :   lp23.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 3 ) << QgsPoint( 11, 12, 13 ) << QgsPoint( 1, 12, 23 ) << QgsPoint( 1, 2, 3 ) );
    9738                 :          1 :   p23.clear();
    9739                 :          1 :   p23.setExteriorRing( lp23.clone() );
    9740                 :          1 :   p23.addInteriorRing( lp23.clone() );
    9741                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::CurvePolygonZ );
    9742                 :          1 :   p23.dropZValue();
    9743                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::CurvePolygon );
    9744                 :          1 :   QCOMPARE( p23.exteriorRing()->wkbType(), QgsWkbTypes::LineString );
    9745                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.exteriorRing() )->pointN( 0 ), QgsPoint( 1, 2 ) );
    9746                 :          1 :   QCOMPARE( p23.interiorRing( 0 )->wkbType(), QgsWkbTypes::LineString );
    9747                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 1, 2 ) );
    9748                 :            :   // with zm
    9749                 :          1 :   lp23.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 3, 4 ) << QgsPoint( 11, 12, 13, 14 ) << QgsPoint( 1, 12, 23, 24 ) << QgsPoint( 1, 2, 3, 4 ) );
    9750                 :          1 :   p23.clear();
    9751                 :          1 :   p23.setExteriorRing( lp23.clone() );
    9752                 :          1 :   p23.addInteriorRing( lp23.clone() );
    9753                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::CurvePolygonZM );
    9754                 :          1 :   p23.dropZValue();
    9755                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::CurvePolygonM );
    9756                 :          1 :   QCOMPARE( p23.exteriorRing()->wkbType(), QgsWkbTypes::LineStringM );
    9757                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.exteriorRing() )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) );
    9758                 :          1 :   QCOMPARE( p23.interiorRing( 0 )->wkbType(), QgsWkbTypes::LineStringM );
    9759                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) );
    9760                 :            : 
    9761                 :            :   // dropMValue
    9762                 :          1 :   p23.clear();
    9763                 :          1 :   p23.dropMValue();
    9764                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::CurvePolygon );
    9765                 :          1 :   lp23.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 12 ) << QgsPoint( 1, 2 ) );
    9766                 :          1 :   p23.setExteriorRing( lp23.clone() );
    9767                 :          1 :   p23.addInteriorRing( lp23.clone() );
    9768                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::CurvePolygon );
    9769                 :          1 :   p23.dropMValue(); // not zm
    9770                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::CurvePolygon );
    9771                 :          1 :   QCOMPARE( p23.exteriorRing()->wkbType(), QgsWkbTypes::LineString );
    9772                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.exteriorRing() )->pointN( 0 ), QgsPoint( 1, 2 ) );
    9773                 :          1 :   QCOMPARE( p23.interiorRing( 0 )->wkbType(), QgsWkbTypes::LineString );
    9774                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 1, 2 ) );
    9775                 :            :   // with m
    9776                 :          1 :   lp23.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM,  1, 2, 0, 3 ) << QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 13 ) << QgsPoint( QgsWkbTypes::PointM, 1, 12, 0, 23 ) << QgsPoint( QgsWkbTypes::PointM,  1, 2, 0, 3 ) );
    9777                 :          1 :   p23.clear();
    9778                 :          1 :   p23.setExteriorRing( lp23.clone() );
    9779                 :          1 :   p23.addInteriorRing( lp23.clone() );
    9780                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::CurvePolygonM );
    9781                 :          1 :   p23.dropMValue();
    9782                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::CurvePolygon );
    9783                 :          1 :   QCOMPARE( p23.exteriorRing()->wkbType(), QgsWkbTypes::LineString );
    9784                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.exteriorRing() )->pointN( 0 ), QgsPoint( 1, 2 ) );
    9785                 :          1 :   QCOMPARE( p23.interiorRing( 0 )->wkbType(), QgsWkbTypes::LineString );
    9786                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 1, 2 ) );
    9787                 :            :   // with zm
    9788                 :          1 :   lp23.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 3, 4 ) << QgsPoint( 11, 12, 13, 14 ) << QgsPoint( 1, 12, 23, 24 ) << QgsPoint( 1, 2, 3, 4 ) );
    9789                 :          1 :   p23.clear();
    9790                 :          1 :   p23.setExteriorRing( lp23.clone() );
    9791                 :          1 :   p23.addInteriorRing( lp23.clone() );
    9792                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::CurvePolygonZM );
    9793                 :          1 :   p23.dropMValue();
    9794                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::CurvePolygonZ );
    9795                 :          1 :   QCOMPARE( p23.exteriorRing()->wkbType(), QgsWkbTypes::LineStringZ );
    9796                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.exteriorRing() )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) );
    9797                 :          1 :   QCOMPARE( p23.interiorRing( 0 )->wkbType(), QgsWkbTypes::LineStringZ );
    9798                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) );
    9799                 :            : 
    9800                 :            : 
    9801                 :            :   // hasCurvedSegments
    9802                 :          1 :   QgsCurvePolygon p24;
    9803                 :          1 :   QVERIFY( !p24.hasCurvedSegments() );
    9804                 :          1 :   QgsLineString lp24;
    9805                 :          1 :   lp24.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 12 ) << QgsPoint( 1, 2 ) );
    9806                 :          1 :   p24.setExteriorRing( lp23.clone() );
    9807                 :          1 :   QVERIFY( !p24.hasCurvedSegments() );
    9808                 :          1 :   QgsCircularString cs24;
    9809                 :          1 :   cs24.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 12 ) << QgsPoint( 1, 2 ) );
    9810                 :          1 :   p24.addInteriorRing( cs24.clone() );
    9811                 :          1 :   QVERIFY( p24.hasCurvedSegments() );
    9812                 :            : 
    9813                 :            :   //vertexAngle
    9814                 :          1 :   QgsCurvePolygon p25;
    9815                 :          1 :   ( void )p25.vertexAngle( QgsVertexId() ); //just want no crash
    9816                 :          1 :   ( void )p25.vertexAngle( QgsVertexId( 0, 0, 0 ) ); //just want no crash
    9817                 :          1 :   ( void )p25.vertexAngle( QgsVertexId( 0, 1, 0 ) ); //just want no crash
    9818                 :          1 :   QgsLineString l38;
    9819                 :          2 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0.5, 0 ) << QgsPoint( 1, 0 )
    9820                 :          1 :                  << QgsPoint( 2, 1 ) << QgsPoint( 1, 2 ) << QgsPoint( 0, 2 ) << QgsPoint( 0, 0 ) );
    9821                 :          1 :   p25.setExteriorRing( l38.clone() );
    9822                 :          1 :   QGSCOMPARENEAR( p25.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 2.35619, 0.00001 );
    9823                 :          1 :   QGSCOMPARENEAR( p25.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 1.5708, 0.0001 );
    9824                 :          1 :   QGSCOMPARENEAR( p25.vertexAngle( QgsVertexId( 0, 0, 2 ) ), 1.17809, 0.00001 );
    9825                 :          1 :   QGSCOMPARENEAR( p25.vertexAngle( QgsVertexId( 0, 0, 3 ) ), 0.0, 0.00001 );
    9826                 :          1 :   QGSCOMPARENEAR( p25.vertexAngle( QgsVertexId( 0, 0, 4 ) ), 5.10509, 0.00001 );
    9827                 :          1 :   QGSCOMPARENEAR( p25.vertexAngle( QgsVertexId( 0, 0, 5 ) ), 3.92699, 0.00001 );
    9828                 :          1 :   QGSCOMPARENEAR( p25.vertexAngle( QgsVertexId( 0, 0, 6 ) ), 2.35619, 0.00001 );
    9829                 :          1 :   p25.addInteriorRing( l38.clone() );
    9830                 :          1 :   QGSCOMPARENEAR( p25.vertexAngle( QgsVertexId( 0, 1, 0 ) ), 2.35619, 0.00001 );
    9831                 :          1 :   QGSCOMPARENEAR( p25.vertexAngle( QgsVertexId( 0, 1, 1 ) ), 1.5708, 0.0001 );
    9832                 :          1 :   QGSCOMPARENEAR( p25.vertexAngle( QgsVertexId( 0, 1, 2 ) ), 1.17809, 0.00001 );
    9833                 :          1 :   QGSCOMPARENEAR( p25.vertexAngle( QgsVertexId( 0, 1, 3 ) ), 0.0, 0.00001 );
    9834                 :          1 :   QGSCOMPARENEAR( p25.vertexAngle( QgsVertexId( 0, 1, 4 ) ), 5.10509, 0.00001 );
    9835                 :          1 :   QGSCOMPARENEAR( p25.vertexAngle( QgsVertexId( 0, 1, 5 ) ), 3.92699, 0.00001 );
    9836                 :          1 :   QGSCOMPARENEAR( p25.vertexAngle( QgsVertexId( 0, 1, 6 ) ), 2.35619, 0.00001 );
    9837                 :            : 
    9838                 :            : 
    9839                 :            :   //insert vertex
    9840                 :            : 
    9841                 :            :   //insert vertex in empty polygon
    9842                 :          1 :   p25.clear();
    9843                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    9844                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 6.0, 7.0 ) ) );
    9845                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 1, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    9846                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 1, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    9847                 :          1 :   QVERIFY( p25.isEmpty() );
    9848                 :          2 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0.5, 0 ) << QgsPoint( 1, 0 )
    9849                 :          1 :                  << QgsPoint( 2, 1 ) << QgsPoint( 1, 2 ) << QgsPoint( 0, 2 ) << QgsPoint( 0, 0 ) );
    9850                 :          1 :   p25.setExteriorRing( l38.clone() );
    9851                 :          1 :   QVERIFY( p25.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 0.3, 0 ) ) );
    9852                 :          1 :   QCOMPARE( p25.nCoordinates(), 8 );
    9853                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 0 ), QgsPoint( 0, 0 ) );
    9854                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 1 ), QgsPoint( 0.3, 0 ) );
    9855                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 2 ), QgsPoint( 0.5, 0 ) );
    9856                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 0, -1 ), QgsPoint( 6.0, 7.0 ) ) );
    9857                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 0, 100 ), QgsPoint( 6.0, 7.0 ) ) );
    9858                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 1, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    9859                 :            :   // first vertex
    9860                 :          1 :   QVERIFY( p25.insertVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 0, 0.1 ) ) );
    9861                 :          1 :   QCOMPARE( p25.nCoordinates(), 9 );
    9862                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 0 ), QgsPoint( 0, 0.1 ) );
    9863                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 1 ), QgsPoint( 0, 0 ) );
    9864                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 2 ), QgsPoint( 0.3, 0 ) );
    9865                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 3 ), QgsPoint( 0.5, 0 ) );
    9866                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 7 ), QgsPoint( 0, 2 ) );
    9867                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 8 ), QgsPoint( 0, 0.1 ) );
    9868                 :            :   // last vertex
    9869                 :          1 :   QVERIFY( p25.insertVertex( QgsVertexId( 0, 0, 9 ), QgsPoint( 0.1, 0.1 ) ) );
    9870                 :          1 :   QCOMPARE( p25.nCoordinates(), 10 );
    9871                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 0 ), QgsPoint( 0.1, 0.1 ) );
    9872                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 1 ), QgsPoint( 0, 0 ) );
    9873                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 2 ), QgsPoint( 0.3, 0 ) );
    9874                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 3 ), QgsPoint( 0.5, 0 ) );
    9875                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 8 ), QgsPoint( 0, 0.1 ) );
    9876                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.exteriorRing() )->pointN( 9 ), QgsPoint( 0.1, 0.1 ) );
    9877                 :            :   // with interior ring
    9878                 :          1 :   p25.addInteriorRing( l38.clone() );
    9879                 :          1 :   QCOMPARE( p25.nCoordinates(), 17 );
    9880                 :          1 :   QVERIFY( p25.insertVertex( QgsVertexId( 0, 1, 1 ), QgsPoint( 0.3, 0 ) ) );
    9881                 :          1 :   QCOMPARE( p25.nCoordinates(), 18 );
    9882                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 0, 0 ) );
    9883                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 1 ), QgsPoint( 0.3, 0 ) );
    9884                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 2 ), QgsPoint( 0.5, 0 ) );
    9885                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 1, -1 ), QgsPoint( 6.0, 7.0 ) ) );
    9886                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 1, 100 ), QgsPoint( 6.0, 7.0 ) ) );
    9887                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 2, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    9888                 :            :   // first vertex in interior ring
    9889                 :          1 :   QVERIFY( p25.insertVertex( QgsVertexId( 0, 1, 0 ), QgsPoint( 0, 0.1 ) ) );
    9890                 :          1 :   QCOMPARE( p25.nCoordinates(), 19 );
    9891                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 0, 0.1 ) );
    9892                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 1 ), QgsPoint( 0, 0 ) );
    9893                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 2 ), QgsPoint( 0.3, 0 ) );
    9894                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 3 ), QgsPoint( 0.5, 0 ) );
    9895                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 7 ), QgsPoint( 0, 2 ) );
    9896                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 8 ), QgsPoint( 0, 0.1 ) );
    9897                 :            :   // last vertex in interior ring
    9898                 :          1 :   QVERIFY( p25.insertVertex( QgsVertexId( 0, 1, 9 ), QgsPoint( 0.1, 0.1 ) ) );
    9899                 :          1 :   QCOMPARE( p25.nCoordinates(), 20 );
    9900                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 0.1, 0.1 ) );
    9901                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 1 ), QgsPoint( 0, 0 ) );
    9902                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 2 ), QgsPoint( 0.3, 0 ) );
    9903                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 3 ), QgsPoint( 0.5, 0 ) );
    9904                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 8 ), QgsPoint( 0, 0.1 ) );
    9905                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.interiorRing( 0 ) )->pointN( 9 ), QgsPoint( 0.1, 0.1 ) );
    9906                 :            : 
    9907                 :            :   //move vertex
    9908                 :            : 
    9909                 :            :   //empty polygon
    9910                 :          1 :   QgsCurvePolygon p26;
    9911                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    9912                 :          1 :   QVERIFY( p26.isEmpty() );
    9913                 :            : 
    9914                 :            :   //valid polygon
    9915                 :          2 :   l38.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
    9916                 :          1 :                  << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) << QgsPoint( 1, 2 ) );
    9917                 :          1 :   p26.setExteriorRing( l38.clone() );
    9918                 :          1 :   QVERIFY( p26.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    9919                 :          1 :   QVERIFY( p26.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 16.0, 17.0 ) ) );
    9920                 :          1 :   QVERIFY( p26.moveVertex( QgsVertexId( 0, 0, 2 ), QgsPoint( 26.0, 27.0 ) ) );
    9921                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.exteriorRing() )->pointN( 0 ), QgsPoint( 6.0, 7.0 ) );
    9922                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.exteriorRing() )->pointN( 1 ), QgsPoint( 16.0, 17.0 ) );
    9923                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.exteriorRing() )->pointN( 2 ), QgsPoint( 26.0, 27.0 ) );
    9924                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.exteriorRing() )->pointN( 3 ), QgsPoint( 6.0, 7.0 ) );
    9925                 :            : 
    9926                 :            :   //out of range
    9927                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 0, 0, -1 ), QgsPoint( 3.0, 4.0 ) ) );
    9928                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 0, 0, 10 ), QgsPoint( 3.0, 4.0 ) ) );
    9929                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 0, 1, 0 ), QgsPoint( 3.0, 4.0 ) ) );
    9930                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.exteriorRing() )->pointN( 0 ), QgsPoint( 6.0, 7.0 ) );
    9931                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.exteriorRing() )->pointN( 1 ), QgsPoint( 16.0, 17.0 ) );
    9932                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.exteriorRing() )->pointN( 2 ), QgsPoint( 26.0, 27.0 ) );
    9933                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.exteriorRing() )->pointN( 3 ), QgsPoint( 6.0, 7.0 ) );
    9934                 :            : 
    9935                 :            :   // with interior ring
    9936                 :          1 :   p26.addInteriorRing( l38.clone() );
    9937                 :          1 :   QVERIFY( p26.moveVertex( QgsVertexId( 0, 1, 0 ), QgsPoint( 6.0, 7.0 ) ) );
    9938                 :          1 :   QVERIFY( p26.moveVertex( QgsVertexId( 0, 1, 1 ), QgsPoint( 16.0, 17.0 ) ) );
    9939                 :          1 :   QVERIFY( p26.moveVertex( QgsVertexId( 0, 1, 2 ), QgsPoint( 26.0, 27.0 ) ) );
    9940                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 6.0, 7.0 ) );
    9941                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.interiorRing( 0 ) )->pointN( 1 ), QgsPoint( 16.0, 17.0 ) );
    9942                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.interiorRing( 0 ) )->pointN( 2 ), QgsPoint( 26.0, 27.0 ) );
    9943                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.interiorRing( 0 ) )->pointN( 3 ), QgsPoint( 6.0, 7.0 ) );
    9944                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 0, 1, -1 ), QgsPoint( 3.0, 4.0 ) ) );
    9945                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 0, 1, 10 ), QgsPoint( 3.0, 4.0 ) ) );
    9946                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 0, 2, 0 ), QgsPoint( 3.0, 4.0 ) ) );
    9947                 :            : 
    9948                 :            :   //delete vertex
    9949                 :            : 
    9950                 :            :   //empty polygon
    9951                 :          1 :   QgsCurvePolygon p27;
    9952                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
    9953                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 0, 1, 0 ) ) );
    9954                 :          1 :   QVERIFY( p27.isEmpty() );
    9955                 :            : 
    9956                 :            :   //valid polygon
    9957                 :          2 :   l38.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 5, 2 ) << QgsPoint( 6, 2 ) << QgsPoint( 7, 2 )
    9958                 :          1 :                  << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) << QgsPoint( 1, 2 ) );
    9959                 :            : 
    9960                 :          1 :   p27.setExteriorRing( l38.clone() );
    9961                 :            :   //out of range vertices
    9962                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 0, 0, -1 ) ) );
    9963                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 0, 0, 100 ) ) );
    9964                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 0, 1, 1 ) ) );
    9965                 :            : 
    9966                 :            :   //valid vertices
    9967                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 1 ) ) );
    9968                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 0 ), QgsPoint( 1.0, 2.0 ) );
    9969                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 1 ), QgsPoint( 6.0, 2.0 ) );
    9970                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 2 ), QgsPoint( 7.0, 2.0 ) );
    9971                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 3 ), QgsPoint( 11.0, 12.0 ) );
    9972                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 5 ), QgsPoint( 1.0, 2.0 ) );
    9973                 :            : 
    9974                 :            :   // delete first vertex
    9975                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
    9976                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 0 ), QgsPoint( 6.0, 2.0 ) );
    9977                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 1 ), QgsPoint( 7.0, 2.0 ) );
    9978                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 2 ), QgsPoint( 11.0, 12.0 ) );
    9979                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 3 ), QgsPoint( 21.0, 22.0 ) );
    9980                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 4 ), QgsPoint( 6.0, 2.0 ) );
    9981                 :            : 
    9982                 :            :   // delete last vertex
    9983                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 4 ) ) );
    9984                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 0 ), QgsPoint( 21.0, 22.0 ) );
    9985                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 1 ), QgsPoint( 7.0, 2.0 ) );
    9986                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 2 ), QgsPoint( 11.0, 12.0 ) );
    9987                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.exteriorRing() )->pointN( 3 ), QgsPoint( 21.0, 22.0 ) );
    9988                 :            : 
    9989                 :            :   // delete another vertex - should remove ring
    9990                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 1 ) ) );
    9991                 :          1 :   QVERIFY( !p27.exteriorRing() );
    9992                 :            : 
    9993                 :            :   // with interior ring
    9994                 :          1 :   p27.setExteriorRing( l38.clone() );
    9995                 :          1 :   p27.addInteriorRing( l38.clone() );
    9996                 :            : 
    9997                 :            :   //out of range vertices
    9998                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 0, 1, -1 ) ) );
    9999                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 0, 1, 100 ) ) );
   10000                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 0, 2, 1 ) ) );
   10001                 :            : 
   10002                 :            :   //valid vertices
   10003                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 1, 1 ) ) );
   10004                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 1.0, 2.0 ) );
   10005                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 1 ), QgsPoint( 6.0, 2.0 ) );
   10006                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 2 ), QgsPoint( 7.0, 2.0 ) );
   10007                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 3 ), QgsPoint( 11.0, 12.0 ) );
   10008                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 5 ), QgsPoint( 1.0, 2.0 ) );
   10009                 :            : 
   10010                 :            :   // delete first vertex
   10011                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 1, 0 ) ) );
   10012                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 6.0, 2.0 ) );
   10013                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 1 ), QgsPoint( 7.0, 2.0 ) );
   10014                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 2 ), QgsPoint( 11.0, 12.0 ) );
   10015                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 3 ), QgsPoint( 21.0, 22.0 ) );
   10016                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 4 ), QgsPoint( 6.0, 2.0 ) );
   10017                 :            : 
   10018                 :            :   // delete last vertex
   10019                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 1, 4 ) ) );
   10020                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 0 ), QgsPoint( 21.0, 22.0 ) );
   10021                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 1 ), QgsPoint( 7.0, 2.0 ) );
   10022                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 2 ), QgsPoint( 11.0, 12.0 ) );
   10023                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.interiorRing( 0 ) )->pointN( 3 ), QgsPoint( 21.0, 22.0 ) );
   10024                 :            : 
   10025                 :            :   // delete another vertex - should remove ring
   10026                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 1, 1 ) ) );
   10027                 :          1 :   QCOMPARE( p27.numInteriorRings(), 0 );
   10028                 :          1 :   QVERIFY( p27.exteriorRing() );
   10029                 :            : 
   10030                 :            :   // test that interior ring is "promoted" when exterior is removed
   10031                 :          1 :   p27.addInteriorRing( l38.clone() );
   10032                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
   10033                 :          1 :   QCOMPARE( p27.numInteriorRings(), 1 );
   10034                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
   10035                 :          1 :   QCOMPARE( p27.numInteriorRings(), 1 );
   10036                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
   10037                 :          1 :   QCOMPARE( p27.numInteriorRings(), 1 );
   10038                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
   10039                 :          1 :   QCOMPARE( p27.numInteriorRings(), 0 );
   10040                 :          1 :   QVERIFY( p27.exteriorRing() );
   10041                 :          1 : }
   10042                 :            : 
   10043                 :          1 : void TestQgsGeometry::compoundCurve()
   10044                 :            : {
   10045                 :            :   //test constructors
   10046                 :          1 :   QgsCompoundCurve l1;
   10047                 :          1 :   QVERIFY( l1.isEmpty() );
   10048                 :          1 :   QCOMPARE( l1.numPoints(), 0 );
   10049                 :          1 :   QCOMPARE( l1.vertexCount(), 0 );
   10050                 :          1 :   QCOMPARE( l1.nCoordinates(), 0 );
   10051                 :          1 :   QCOMPARE( l1.ringCount(), 0 );
   10052                 :          1 :   QCOMPARE( l1.partCount(), 0 );
   10053                 :          1 :   QVERIFY( !l1.is3D() );
   10054                 :          1 :   QVERIFY( !l1.isMeasure() );
   10055                 :          1 :   QCOMPARE( l1.wkbType(), QgsWkbTypes::CompoundCurve );
   10056                 :          1 :   QCOMPARE( l1.wktTypeStr(), QString( "CompoundCurve" ) );
   10057                 :          1 :   QCOMPARE( l1.geometryType(), QString( "CompoundCurve" ) );
   10058                 :          1 :   QCOMPARE( l1.dimension(), 1 );
   10059                 :          1 :   QVERIFY( !l1.hasCurvedSegments() );
   10060                 :          1 :   QCOMPARE( l1.area(), 0.0 );
   10061                 :          1 :   QCOMPARE( l1.perimeter(), 0.0 );
   10062                 :          1 :   QgsPointSequence pts;
   10063                 :          1 :   l1.points( pts );
   10064                 :          1 :   QVERIFY( pts.empty() );
   10065                 :            : 
   10066                 :            :   // empty, test some methods to make sure they don't crash
   10067                 :          1 :   QCOMPARE( l1.nCurves(), 0 );
   10068                 :          1 :   QVERIFY( !l1.curveAt( -1 ) );
   10069                 :          1 :   QVERIFY( !l1.curveAt( 0 ) );
   10070                 :          1 :   QVERIFY( !l1.curveAt( 100 ) );
   10071                 :          1 :   l1.removeCurve( -1 );
   10072                 :          1 :   l1.removeCurve( 0 );
   10073                 :          1 :   l1.removeCurve( 100 );
   10074                 :            : 
   10075                 :            :   //addCurve
   10076                 :          1 :   QgsCompoundCurve c1;
   10077                 :            :   //try to add null curve
   10078                 :          1 :   c1.addCurve( nullptr );
   10079                 :          1 :   QCOMPARE( c1.nCurves(), 0 );
   10080                 :          1 :   QVERIFY( !c1.curveAt( 0 ) );
   10081                 :            : 
   10082                 :          1 :   QgsCircularString l2;
   10083                 :          1 :   l2.setPoints( QgsPointSequence() << QgsPoint( 1.0, 2.0 ) );
   10084                 :          1 :   c1.addCurve( l2.clone() );
   10085                 :          1 :   QVERIFY( !c1.isEmpty() );
   10086                 :          1 :   QCOMPARE( c1.numPoints(), 1 );
   10087                 :          1 :   QCOMPARE( c1.vertexCount(), 1 );
   10088                 :          1 :   QCOMPARE( c1.nCoordinates(), 1 );
   10089                 :          1 :   QCOMPARE( c1.ringCount(), 1 );
   10090                 :          1 :   QCOMPARE( c1.partCount(), 1 );
   10091                 :          1 :   QVERIFY( !c1.is3D() );
   10092                 :          1 :   QVERIFY( !c1.isMeasure() );
   10093                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::CompoundCurve );
   10094                 :          1 :   QVERIFY( c1.hasCurvedSegments() );
   10095                 :          1 :   QCOMPARE( c1.area(), 0.0 );
   10096                 :          1 :   QCOMPARE( c1.perimeter(), 0.0 );
   10097                 :          1 :   c1.points( pts );
   10098                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( 1.0, 2.0 ) );
   10099                 :            : 
   10100                 :            :   //adding first curve should set linestring z/m type
   10101                 :          1 :   QgsCircularString l3;
   10102                 :          1 :   l3.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1.0, 2.0, 3.0 ) );
   10103                 :          1 :   QgsCompoundCurve c2;
   10104                 :          1 :   c2.addCurve( l3.clone() );
   10105                 :          1 :   QVERIFY( !c2.isEmpty() );
   10106                 :          1 :   QVERIFY( c2.is3D() );
   10107                 :          1 :   QVERIFY( !c2.isMeasure() );
   10108                 :          1 :   QCOMPARE( c2.wkbType(), QgsWkbTypes::CompoundCurveZ );
   10109                 :          1 :   QCOMPARE( c2.wktTypeStr(), QString( "CompoundCurveZ" ) );
   10110                 :          1 :   c2.points( pts );
   10111                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1.0, 2.0, 3.0 ) );
   10112                 :            : 
   10113                 :          1 :   QgsCircularString l4;
   10114                 :          1 :   l4.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1.0, 2.0, 0.0, 3.0 ) );
   10115                 :          1 :   QgsCompoundCurve c4;
   10116                 :          1 :   c4.addCurve( l4.clone() );
   10117                 :          1 :   QVERIFY( !c4.isEmpty() );
   10118                 :          1 :   QVERIFY( !c4.is3D() );
   10119                 :          1 :   QVERIFY( c4.isMeasure() );
   10120                 :          1 :   QCOMPARE( c4.wkbType(), QgsWkbTypes::CompoundCurveM );
   10121                 :          1 :   QCOMPARE( c4.wktTypeStr(), QString( "CompoundCurveM" ) );
   10122                 :          1 :   c4.points( pts );
   10123                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1.0, 2.0, 0.0, 3.0 ) );
   10124                 :            : 
   10125                 :          1 :   QgsCircularString l5;
   10126                 :          1 :   l5.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1.0, 2.0, 3.0, 4.0 ) );
   10127                 :          1 :   QgsCompoundCurve c5;
   10128                 :          1 :   c5.addCurve( l5.clone() );
   10129                 :          1 :   QVERIFY( !c5.isEmpty() );
   10130                 :          1 :   QVERIFY( c5.is3D() );
   10131                 :          1 :   QVERIFY( c5.isMeasure() );
   10132                 :          1 :   QCOMPARE( c5.wkbType(), QgsWkbTypes::CompoundCurveZM );
   10133                 :          1 :   QCOMPARE( c5.wktTypeStr(), QString( "CompoundCurveZM" ) );
   10134                 :          1 :   c5.points( pts );
   10135                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1.0, 2.0, 3.0, 4.0 ) );
   10136                 :            : 
   10137                 :            :   //clear
   10138                 :          1 :   c5.clear();
   10139                 :          1 :   QVERIFY( c5.isEmpty() );
   10140                 :          1 :   QCOMPARE( c5.nCurves(), 0 );
   10141                 :          1 :   QCOMPARE( c5.numPoints(), 0 );
   10142                 :          1 :   QCOMPARE( c5.vertexCount(), 0 );
   10143                 :          1 :   QCOMPARE( c5.nCoordinates(), 0 );
   10144                 :          1 :   QCOMPARE( c5.ringCount(), 0 );
   10145                 :          1 :   QCOMPARE( c5.partCount(), 0 );
   10146                 :          1 :   QVERIFY( !c5.is3D() );
   10147                 :          1 :   QVERIFY( !c5.isMeasure() );
   10148                 :          1 :   QCOMPARE( c5.wkbType(), QgsWkbTypes::CompoundCurve );
   10149                 :            : 
   10150                 :            :   //addCurve
   10151                 :          1 :   QgsCircularString l8;
   10152                 :          1 :   QgsCompoundCurve c8;
   10153                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 2, 3 ) << QgsPoint( 3, 4 ) );
   10154                 :          1 :   c8.addCurve( l8.clone() );
   10155                 :          1 :   QVERIFY( !c8.isEmpty() );
   10156                 :          1 :   QCOMPARE( c8.numPoints(), 3 );
   10157                 :          1 :   QCOMPARE( c8.vertexCount(), 3 );
   10158                 :          1 :   QCOMPARE( c8.nCoordinates(), 3 );
   10159                 :          1 :   QCOMPARE( c8.ringCount(), 1 );
   10160                 :          1 :   QCOMPARE( c8.partCount(), 1 );
   10161                 :          1 :   QCOMPARE( c8.nCurves(), 1 );
   10162                 :          1 :   QVERIFY( !c8.is3D() );
   10163                 :          1 :   QVERIFY( !c8.isMeasure() );
   10164                 :          1 :   QCOMPARE( c8.wkbType(), QgsWkbTypes::CompoundCurve );
   10165                 :          1 :   QVERIFY( c8.hasCurvedSegments() );
   10166                 :          1 :   c8.points( pts );
   10167                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 2, 3 ) << QgsPoint( 3, 4 ) );
   10168                 :          1 :   QCOMPARE( *dynamic_cast< const QgsCircularString *>( c8.curveAt( 0 ) ), l8 );
   10169                 :          1 :   QVERIFY( ! c8.curveAt( -1 ) );
   10170                 :          1 :   QVERIFY( ! c8.curveAt( 1 ) );
   10171                 :            : 
   10172                 :          1 :   QgsCircularString l8a;
   10173                 :          1 :   l8a.setPoints( QgsPointSequence() << QgsPoint( 3, 4 ) << QgsPoint( 4, 5 ) << QgsPoint( 3, 6 ) );
   10174                 :          1 :   c8.addCurve( l8a.clone() );
   10175                 :          1 :   QCOMPARE( c8.numPoints(), 5 );
   10176                 :          1 :   QCOMPARE( c8.vertexCount(), 5 );
   10177                 :          1 :   QCOMPARE( c8.nCoordinates(), 5 );
   10178                 :          1 :   QCOMPARE( c8.ringCount(), 1 );
   10179                 :          1 :   QCOMPARE( c8.partCount(), 1 );
   10180                 :          1 :   QCOMPARE( c8.nCurves(), 2 );
   10181                 :          1 :   pts.clear();
   10182                 :          1 :   c8.points( pts );
   10183                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 2, 3 ) << QgsPoint( 3, 4 )
   10184                 :            :             << QgsPoint( 4, 5 ) << QgsPoint( 3, 6 ) );
   10185                 :          1 :   QCOMPARE( *dynamic_cast< const QgsCircularString *>( c8.curveAt( 0 ) ), l8 );
   10186                 :          1 :   QCOMPARE( *dynamic_cast< const QgsCircularString *>( c8.curveAt( 1 ) ), l8a );
   10187                 :          1 :   QVERIFY( ! c8.curveAt( -1 ) );
   10188                 :          1 :   QVERIFY( ! c8.curveAt( 2 ) );
   10189                 :            : 
   10190                 :          1 :   QgsLineString l8b;
   10191                 :          1 :   l8b.setPoints( QgsPointSequence() << QgsPoint( 3, 6 ) << QgsPoint( 4, 6 ) );
   10192                 :          1 :   c8.addCurve( l8b.clone() );
   10193                 :          1 :   QCOMPARE( c8.numPoints(), 6 );
   10194                 :          1 :   QCOMPARE( c8.vertexCount(), 6 );
   10195                 :          1 :   QCOMPARE( c8.nCoordinates(), 6 );
   10196                 :          1 :   QCOMPARE( c8.ringCount(), 1 );
   10197                 :          1 :   QCOMPARE( c8.partCount(), 1 );
   10198                 :          1 :   QCOMPARE( c8.nCurves(), 3 );
   10199                 :          1 :   pts.clear();
   10200                 :          1 :   c8.points( pts );
   10201                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 2, 3 ) << QgsPoint( 3, 4 )
   10202                 :            :             << QgsPoint( 4, 5 ) << QgsPoint( 3, 6 )
   10203                 :            :             << QgsPoint( 4, 6 ) );
   10204                 :          1 :   QCOMPARE( *dynamic_cast< const QgsCircularString *>( c8.curveAt( 0 ) ), l8 );
   10205                 :          1 :   QCOMPARE( *dynamic_cast< const QgsCircularString *>( c8.curveAt( 1 ) ), l8a );
   10206                 :          1 :   QCOMPARE( *dynamic_cast< const QgsLineString *>( c8.curveAt( 2 ) ), l8b );
   10207                 :          1 :   QVERIFY( ! c8.curveAt( -1 ) );
   10208                 :          1 :   QVERIFY( ! c8.curveAt( 3 ) );
   10209                 :            : 
   10210                 :            :   //removeCurve
   10211                 :          1 :   c8.removeCurve( -1 );
   10212                 :          1 :   c8.removeCurve( 3 );
   10213                 :          1 :   QCOMPARE( c8.nCurves(), 3 );
   10214                 :          1 :   QCOMPARE( *dynamic_cast< const QgsCircularString *>( c8.curveAt( 0 ) ), l8 );
   10215                 :          1 :   QCOMPARE( *dynamic_cast< const QgsCircularString *>( c8.curveAt( 1 ) ), l8a );
   10216                 :          1 :   QCOMPARE( *dynamic_cast< const QgsLineString *>( c8.curveAt( 2 ) ), l8b );
   10217                 :          1 :   c8.removeCurve( 1 );
   10218                 :          1 :   QCOMPARE( c8.nCurves(), 2 );
   10219                 :          1 :   QCOMPARE( *dynamic_cast< const QgsCircularString *>( c8.curveAt( 0 ) ), l8 );
   10220                 :          1 :   QCOMPARE( *dynamic_cast< const QgsLineString *>( c8.curveAt( 1 ) ), l8b );
   10221                 :          1 :   c8.removeCurve( 0 );
   10222                 :          1 :   QCOMPARE( c8.nCurves(), 1 );
   10223                 :          1 :   QCOMPARE( *dynamic_cast< const QgsLineString *>( c8.curveAt( 0 ) ), l8b );
   10224                 :          1 :   c8.removeCurve( 0 );
   10225                 :          1 :   QCOMPARE( c8.nCurves(), 0 );
   10226                 :          1 :   QVERIFY( c8.isEmpty() );
   10227                 :            : 
   10228                 :            :   //addCurve with z
   10229                 :          1 :   c8.clear();
   10230                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 2, 3, 4 ) );
   10231                 :          1 :   c8.addCurve( l8.clone() );
   10232                 :          1 :   QCOMPARE( c8.numPoints(), 2 );
   10233                 :          1 :   QVERIFY( c8.is3D() );
   10234                 :          1 :   QVERIFY( !c8.isMeasure() );
   10235                 :          1 :   QCOMPARE( c8.wkbType(), QgsWkbTypes::CompoundCurveZ );
   10236                 :          1 :   pts.clear();
   10237                 :          1 :   c8.points( pts );
   10238                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 2, 3, 4 ) );
   10239                 :            : 
   10240                 :            :   //addCurve with m
   10241                 :          1 :   c8.clear();
   10242                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 3 ) << QgsPoint( QgsWkbTypes::PointM, 2, 3, 0, 4 ) );
   10243                 :          1 :   c8.addCurve( l8.clone() );
   10244                 :          1 :   QCOMPARE( c8.numPoints(), 2 );
   10245                 :          1 :   QVERIFY( !c8.is3D() );
   10246                 :          1 :   QVERIFY( c8.isMeasure() );
   10247                 :          1 :   QCOMPARE( c8.wkbType(), QgsWkbTypes::CompoundCurveM );
   10248                 :          1 :   c8.points( pts );
   10249                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 3 ) << QgsPoint( QgsWkbTypes::PointM, 2, 3, 0, 4 ) );
   10250                 :            : 
   10251                 :            :   //addCurve with zm
   10252                 :          1 :   c8.clear();
   10253                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 4, 5 ) << QgsPoint( QgsWkbTypes::PointZM, 2, 3, 4, 5 ) );
   10254                 :          1 :   c8.addCurve( l8.clone() );
   10255                 :          1 :   QCOMPARE( c8.numPoints(), 2 );
   10256                 :          1 :   QVERIFY( c8.is3D() );
   10257                 :          1 :   QVERIFY( c8.isMeasure() );
   10258                 :          1 :   QCOMPARE( c8.wkbType(), QgsWkbTypes::CompoundCurveZM );
   10259                 :          1 :   c8.points( pts );
   10260                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 4, 5 ) << QgsPoint( QgsWkbTypes::PointZM, 2, 3, 4, 5 ) );
   10261                 :            : 
   10262                 :            :   //addCurve with z to non z compound curve
   10263                 :          1 :   c8.clear();
   10264                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 1, 2 ) << QgsPoint( QgsWkbTypes::Point, 2, 3 ) );
   10265                 :          1 :   c8.addCurve( l8.clone() );
   10266                 :          1 :   QCOMPARE( c8.wkbType(), QgsWkbTypes::CompoundCurve );
   10267                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 2, 3, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 3, 3, 5 ) );
   10268                 :          1 :   c8.addCurve( l8.clone() );
   10269                 :          1 :   QVERIFY( !c8.is3D() );
   10270                 :          1 :   QVERIFY( !c8.isMeasure() );
   10271                 :          1 :   QCOMPARE( c8.wkbType(), QgsWkbTypes::CompoundCurve );
   10272                 :          1 :   c8.points( pts );
   10273                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 1, 2 ) << QgsPoint( QgsWkbTypes::Point, 2, 3 )
   10274                 :            :             << QgsPoint( QgsWkbTypes::Point, 3, 3 ) );
   10275                 :          1 :   c8.removeCurve( 1 );
   10276                 :            : 
   10277                 :            :   //addCurve with m to non m compound curve
   10278                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 2, 3, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 3, 3, 0, 5 ) );
   10279                 :          1 :   c8.addCurve( l8.clone() );
   10280                 :          1 :   QVERIFY( !c8.is3D() );
   10281                 :          1 :   QVERIFY( !c8.isMeasure() );
   10282                 :          1 :   QCOMPARE( c8.wkbType(), QgsWkbTypes::CompoundCurve );
   10283                 :          1 :   c8.points( pts );
   10284                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 1, 2 ) << QgsPoint( QgsWkbTypes::Point, 2, 3 )
   10285                 :            :             << QgsPoint( QgsWkbTypes::Point, 3, 3 ) );
   10286                 :          1 :   c8.removeCurve( 1 );
   10287                 :            : 
   10288                 :            :   //addCurve with zm to non m compound curve
   10289                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 2, 3, 6, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 3, 3, 1, 5 ) );
   10290                 :          1 :   c8.addCurve( l8.clone() );
   10291                 :          1 :   QVERIFY( !c8.is3D() );
   10292                 :          1 :   QVERIFY( !c8.isMeasure() );
   10293                 :          1 :   QCOMPARE( c8.wkbType(), QgsWkbTypes::CompoundCurve );
   10294                 :          1 :   c8.points( pts );
   10295                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 1, 2 ) << QgsPoint( QgsWkbTypes::Point, 2, 3 )
   10296                 :            :             << QgsPoint( QgsWkbTypes::Point, 3, 3 ) );
   10297                 :          1 :   c8.removeCurve( 1 );
   10298                 :            : 
   10299                 :            :   //addCurve with no z to z compound curve
   10300                 :          1 :   c8.clear();
   10301                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 2, 3, 5 ) );
   10302                 :          1 :   c8.addCurve( l8.clone() );
   10303                 :          1 :   QCOMPARE( c8.wkbType(), QgsWkbTypes::CompoundCurveZ );
   10304                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 2, 3 ) << QgsPoint( QgsWkbTypes::Point, 3, 4 ) );
   10305                 :          1 :   c8.addCurve( l8.clone() );
   10306                 :          1 :   QVERIFY( c8.is3D() );
   10307                 :          1 :   QVERIFY( !c8.isMeasure() );
   10308                 :          1 :   QCOMPARE( c8.wkbType(), QgsWkbTypes::CompoundCurveZ );
   10309                 :          1 :   c8.points( pts );
   10310                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 2, 3, 5 )
   10311                 :            :             << QgsPoint( QgsWkbTypes::PointZ, 3, 4, 0 ) );
   10312                 :          1 :   c8.removeCurve( 1 );
   10313                 :            : 
   10314                 :            :   //add curve with m, no z to z compound curve
   10315                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 2, 3, 0, 8 ) << QgsPoint( QgsWkbTypes::PointM, 3, 4, 0, 9 ) );
   10316                 :          1 :   c8.addCurve( l8.clone() );
   10317                 :          1 :   QVERIFY( c8.is3D() );
   10318                 :          1 :   QVERIFY( !c8.isMeasure() );
   10319                 :          1 :   QCOMPARE( c8.wkbType(), QgsWkbTypes::CompoundCurveZ );
   10320                 :          1 :   c8.points( pts );
   10321                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 2, 3, 5 )
   10322                 :            :             << QgsPoint( QgsWkbTypes::PointZ, 3, 4, 0 ) );
   10323                 :          1 :   c8.removeCurve( 1 );
   10324                 :            : 
   10325                 :            :   //add curve with zm to z compound curve
   10326                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 2, 3, 6, 8 ) << QgsPoint( QgsWkbTypes::PointZM, 3, 4, 7, 9 ) );
   10327                 :          1 :   c8.addCurve( l8.clone() );
   10328                 :          1 :   QVERIFY( c8.is3D() );
   10329                 :          1 :   QVERIFY( !c8.isMeasure() );
   10330                 :          1 :   QCOMPARE( c8.wkbType(), QgsWkbTypes::CompoundCurveZ );
   10331                 :          1 :   c8.points( pts );
   10332                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 2, 3, 5 )
   10333                 :            :             << QgsPoint( QgsWkbTypes::PointZ, 3, 4, 7 ) );
   10334                 :          1 :   c8.removeCurve( 1 );
   10335                 :            : 
   10336                 :            :   //addCurve with no m to m compound curve
   10337                 :          1 :   c8.clear();
   10338                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 2, 3, 0, 5 ) );
   10339                 :          1 :   c8.addCurve( l8.clone() );
   10340                 :          1 :   QCOMPARE( c8.wkbType(), QgsWkbTypes::CompoundCurveM );
   10341                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 2, 3 ) << QgsPoint( QgsWkbTypes::Point, 3, 4 ) );
   10342                 :          1 :   c8.addCurve( l8.clone() );
   10343                 :          1 :   QVERIFY( !c8.is3D() );
   10344                 :          1 :   QVERIFY( c8.isMeasure() );
   10345                 :          1 :   QCOMPARE( c8.wkbType(), QgsWkbTypes::CompoundCurveM );
   10346                 :          1 :   c8.points( pts );
   10347                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 2, 3, 0, 5 )
   10348                 :            :             << QgsPoint( QgsWkbTypes::PointM, 3, 4, 0, 0 ) );
   10349                 :          1 :   c8.removeCurve( 1 );
   10350                 :            : 
   10351                 :            :   //add curve with z, no m to m compound curve
   10352                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 2, 3, 8 ) << QgsPoint( QgsWkbTypes::PointZ, 3, 4, 9 ) );
   10353                 :          1 :   c8.addCurve( l8.clone() );
   10354                 :          1 :   QVERIFY( !c8.is3D() );
   10355                 :          1 :   QVERIFY( c8.isMeasure() );
   10356                 :          1 :   QCOMPARE( c8.wkbType(), QgsWkbTypes::CompoundCurveM );
   10357                 :          1 :   c8.points( pts );
   10358                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 2, 3, 0, 5 )
   10359                 :            :             << QgsPoint( QgsWkbTypes::PointM, 3, 4, 0, 0 ) );
   10360                 :          1 :   c8.removeCurve( 1 );
   10361                 :            : 
   10362                 :            :   //add curve with zm to m compound curve
   10363                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 2, 3, 6, 8 ) << QgsPoint( QgsWkbTypes::PointZM, 3, 4, 7, 9 ) );
   10364                 :          1 :   c8.addCurve( l8.clone() );
   10365                 :          1 :   QVERIFY( !c8.is3D() );
   10366                 :          1 :   QVERIFY( c8.isMeasure() );
   10367                 :          1 :   QCOMPARE( c8.wkbType(), QgsWkbTypes::CompoundCurveM );
   10368                 :          1 :   c8.points( pts );
   10369                 :          1 :   QCOMPARE( pts, QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 2, 3, 0, 5 )
   10370                 :            :             << QgsPoint( QgsWkbTypes::PointM, 3, 4, 0, 9 ) );
   10371                 :          1 :   c8.removeCurve( 1 );
   10372                 :            : 
   10373                 :            :   // add curve and extend existing
   10374                 :          1 :   QgsCompoundCurve c8j;
   10375                 :            :   // try to extend empty compound curve
   10376                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 2, 3 ) << QgsPoint( 3, 4 ) );
   10377                 :          1 :   c8j.addCurve( l8.clone(), true );
   10378                 :          2 :   QCOMPARE( c8j.asWkt(), QStringLiteral( "CompoundCurve (CircularString (1 2, 2 3, 3 4))" ) );
   10379                 :            :   // try to add another curve with extend existing as true - should be ignored.
   10380                 :          1 :   l8.setPoints( QgsPointSequence() << QgsPoint( 6, 6 ) << QgsPoint( 7, 8 ) );
   10381                 :          1 :   c8j.addCurve( l8.clone(), true );
   10382                 :          2 :   QCOMPARE( c8j.asWkt(), QStringLiteral( "CompoundCurve (CircularString (1 2, 2 3, 3 4),CircularString (6 6, 7 8))" ) );
   10383                 :            :   // try to add a linestring with extend existing as true - should be ignored because the last curve isn't a linestring
   10384                 :          1 :   QgsLineString l8j;
   10385                 :          1 :   l8j.setPoints( QgsPointSequence() << QgsPoint( 10, 8 ) << QgsPoint( 10, 12 ) );
   10386                 :          1 :   c8j.addCurve( l8j.clone(), true );
   10387                 :          2 :   QCOMPARE( c8j.asWkt(), QStringLiteral( "CompoundCurve (CircularString (1 2, 2 3, 3 4),CircularString (6 6, 7 8),(10 8, 10 12))" ) );
   10388                 :            :   // try to extend with another linestring -- should add to final part
   10389                 :          1 :   l8j.setPoints( QgsPointSequence() << QgsPoint( 11, 13 ) << QgsPoint( 12, 12 ) );
   10390                 :          1 :   c8j.addCurve( l8j.clone(), true );
   10391                 :          2 :   QCOMPARE( c8j.asWkt(), QStringLiteral( "CompoundCurve (CircularString (1 2, 2 3, 3 4),CircularString (6 6, 7 8),(10 8, 10 12, 11 13, 12 12))" ) );
   10392                 :            :   // try to extend with another linestring -- should add to final part, with no duplicate points
   10393                 :          1 :   l8j.setPoints( QgsPointSequence() << QgsPoint( 12, 12 ) << QgsPoint( 13, 12 ) << QgsPoint( 14, 15 ) );
   10394                 :          1 :   c8j.addCurve( l8j.clone(), true );
   10395                 :          2 :   QCOMPARE( c8j.asWkt(), QStringLiteral( "CompoundCurve (CircularString (1 2, 2 3, 3 4),CircularString (6 6, 7 8),(10 8, 10 12, 11 13, 12 12, 13 12, 14 15))" ) );
   10396                 :            :   // not extending, should be added as new curve
   10397                 :          1 :   l8j.setPoints( QgsPointSequence() << QgsPoint( 15, 16 ) << QgsPoint( 17, 12 ) );
   10398                 :          1 :   c8j.addCurve( l8j.clone(), false );
   10399                 :          2 :   QCOMPARE( c8j.asWkt(), QStringLiteral( "CompoundCurve (CircularString (1 2, 2 3, 3 4),CircularString (6 6, 7 8),(10 8, 10 12, 11 13, 12 12, 13 12, 14 15),(15 16, 17 12))" ) );
   10400                 :          1 :   c8j.clear();
   10401                 :            :   // adding a linestring as first part, with extend as true
   10402                 :          1 :   c8j.addCurve( l8j.clone(), true );
   10403                 :          2 :   QCOMPARE( c8j.asWkt(), QStringLiteral( "CompoundCurve ((15 16, 17 12))" ) );
   10404                 :            : 
   10405                 :            :   //test getters/setters
   10406                 :          1 :   QgsCompoundCurve c9;
   10407                 :            : 
   10408                 :            :   // no crash!
   10409                 :          1 :   ( void )c9.xAt( -1 );
   10410                 :          1 :   ( void )c9.xAt( 1 );
   10411                 :          1 :   ( void )c9.yAt( -1 );
   10412                 :          1 :   ( void )c9.yAt( 1 );
   10413                 :            : 
   10414                 :          1 :   QgsCircularString l9;
   10415                 :          2 :   l9.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
   10416                 :          1 :                 << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 )
   10417                 :          1 :                 << QgsPoint( QgsWkbTypes::PointZM, 21, 22, 23, 24 ) );
   10418                 :          1 :   c9.addCurve( l9.clone() );
   10419                 :          1 :   QCOMPARE( c9.xAt( 0 ), 1.0 );
   10420                 :          1 :   QCOMPARE( c9.xAt( 1 ), 11.0 );
   10421                 :          1 :   QCOMPARE( c9.xAt( 2 ), 21.0 );
   10422                 :          1 :   ( void ) c9.xAt( -1 ); //out of range
   10423                 :          1 :   ( void ) c9.xAt( 11 ); //out of range
   10424                 :          1 :   QCOMPARE( c9.yAt( 0 ), 2.0 );
   10425                 :          1 :   QCOMPARE( c9.yAt( 1 ), 12.0 );
   10426                 :          1 :   QCOMPARE( c9.yAt( 2 ), 22.0 );
   10427                 :          1 :   ( void ) c9.yAt( -1 ); //out of range
   10428                 :          1 :   ( void ) c9.yAt( 11 ); //out of range
   10429                 :            : 
   10430                 :          1 :   QgsLineString l9a;
   10431                 :          2 :   l9a.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 21, 22, 23, 24 )
   10432                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 31, 22, 13, 14 ) );
   10433                 :          1 :   c9.addCurve( l9a.clone() );
   10434                 :          1 :   QCOMPARE( c9.xAt( 0 ), 1.0 );
   10435                 :          1 :   QCOMPARE( c9.xAt( 1 ), 11.0 );
   10436                 :          1 :   QCOMPARE( c9.xAt( 2 ), 21.0 );
   10437                 :          1 :   QCOMPARE( c9.xAt( 3 ), 31.0 );
   10438                 :          1 :   QCOMPARE( c9.xAt( 4 ), 0.0 );
   10439                 :          1 :   ( void ) c9.xAt( -1 ); //out of range
   10440                 :          1 :   ( void ) c9.xAt( 11 ); //out of range
   10441                 :          1 :   QCOMPARE( c9.yAt( 0 ), 2.0 );
   10442                 :          1 :   QCOMPARE( c9.yAt( 1 ), 12.0 );
   10443                 :          1 :   QCOMPARE( c9.yAt( 2 ), 22.0 );
   10444                 :          1 :   QCOMPARE( c9.yAt( 3 ), 22.0 );
   10445                 :          1 :   QCOMPARE( c9.yAt( 4 ), 0.0 );
   10446                 :          1 :   ( void ) c9.yAt( -1 ); //out of range
   10447                 :          1 :   ( void ) c9.yAt( 11 ); //out of range
   10448                 :            : 
   10449                 :          1 :   c9.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 51.0, 52.0 ) );
   10450                 :          1 :   QCOMPARE( c9.xAt( 0 ), 51.0 );
   10451                 :          1 :   QCOMPARE( c9.yAt( 0 ), 52.0 );
   10452                 :          1 :   c9.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 61.0, 62 ) );
   10453                 :          1 :   QCOMPARE( c9.xAt( 1 ), 61.0 );
   10454                 :          1 :   QCOMPARE( c9.yAt( 1 ), 62.0 );
   10455                 :          1 :   c9.moveVertex( QgsVertexId( 0, 0, -1 ), QgsPoint( 71.0, 2 ) ); //out of range
   10456                 :          1 :   c9.moveVertex( QgsVertexId( 0, 0, 11 ), QgsPoint( 71.0, 2 ) ); //out of range
   10457                 :            : 
   10458                 :          1 :   QgsPoint p;
   10459                 :            :   QgsVertexId::VertexType type;
   10460                 :          1 :   QVERIFY( !c9.pointAt( -1, p, type ) );
   10461                 :          1 :   QVERIFY( !c9.pointAt( 11, p, type ) );
   10462                 :          1 :   QVERIFY( c9.pointAt( 0, p, type ) );
   10463                 :          1 :   QCOMPARE( p.z(), 3.0 );
   10464                 :          1 :   QCOMPARE( p.m(), 4.0 );
   10465                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
   10466                 :          1 :   QVERIFY( c9.pointAt( 1, p, type ) );
   10467                 :          1 :   QCOMPARE( p.z(), 13.0 );
   10468                 :          1 :   QCOMPARE( p.m(), 14.0 );
   10469                 :          1 :   QCOMPARE( type, QgsVertexId::CurveVertex );
   10470                 :          1 :   QVERIFY( c9.pointAt( 2, p, type ) );
   10471                 :          1 :   QCOMPARE( p.z(), 23.0 );
   10472                 :          1 :   QCOMPARE( p.m(), 24.0 );
   10473                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
   10474                 :          1 :   QVERIFY( c9.pointAt( 3, p, type ) );
   10475                 :          1 :   QCOMPARE( p.z(), 13.0 );
   10476                 :          1 :   QCOMPARE( p.m(), 14.0 );
   10477                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
   10478                 :            : 
   10479                 :            :   //equality
   10480                 :          1 :   QgsCompoundCurve e1;
   10481                 :          1 :   QgsCompoundCurve e2;
   10482                 :          1 :   QVERIFY( e1 == e2 );
   10483                 :          1 :   QVERIFY( !( e1 != e2 ) );
   10484                 :          1 :   QgsLineString le1;
   10485                 :          1 :   QgsLineString le2;
   10486                 :          1 :   le1.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) );
   10487                 :          1 :   e1.addCurve( le1.clone() );
   10488                 :          1 :   QVERIFY( !( e1 == e2 ) ); //different number of curves
   10489                 :          1 :   QVERIFY( e1 != e2 );
   10490                 :          1 :   e2.addCurve( le1.clone() );
   10491                 :          1 :   QVERIFY( e1 == e2 );
   10492                 :          1 :   QVERIFY( !( e1 != e2 ) );
   10493                 :          1 :   le1.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 1 / 3.0, 4 / 3.0 ) );
   10494                 :          1 :   e1.addCurve( le1.clone() );
   10495                 :          1 :   QVERIFY( !( e1 == e2 ) ); //different number of curves
   10496                 :          1 :   QVERIFY( e1 != e2 );
   10497                 :          1 :   le2.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 2 / 6.0, 8 / 6.0 ) );
   10498                 :          1 :   e2.addCurve( le2.clone() );
   10499                 :          1 :   QVERIFY( e1 == e2 ); //check non-integer equality
   10500                 :          1 :   QVERIFY( !( e1 != e2 ) );
   10501                 :          1 :   le1.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 1 / 3.0, 4 / 3.0 ) << QgsPoint( 7, 8 ) );
   10502                 :          1 :   e1.addCurve( le1.clone() );
   10503                 :          1 :   le2.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 2 / 6.0, 8 / 6.0 ) << QgsPoint( 6, 9 ) );
   10504                 :          1 :   e2.addCurve( le2.clone() );
   10505                 :          1 :   QVERIFY( !( e1 == e2 ) ); //different coordinates
   10506                 :          1 :   QVERIFY( e1 != e2 );
   10507                 :            : 
   10508                 :            :   // different dimensions
   10509                 :          1 :   QgsCompoundCurve e3;
   10510                 :          1 :   e1.clear();
   10511                 :          1 :   e1.addCurve( le1.clone() );
   10512                 :          1 :   QgsLineString le3;
   10513                 :          2 :   le3.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 0 )
   10514                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZ, 1 / 3.0, 4 / 3.0, 0 )
   10515                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZ, 7, 8, 0 ) );
   10516                 :          1 :   e3.addCurve( le3.clone() );
   10517                 :          1 :   QVERIFY( !( e1 == e3 ) ); //different dimension
   10518                 :          1 :   QVERIFY( e1 != e3 );
   10519                 :          1 :   QgsCompoundCurve e4;
   10520                 :          1 :   QgsLineString le4;
   10521                 :          2 :   le4.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 )
   10522                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZ, 1 / 3.0, 4 / 3.0, 3 )
   10523                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZ, 7, 8, 4 ) );
   10524                 :          1 :   e4.addCurve( le4.clone() );
   10525                 :          1 :   QVERIFY( !( e3 == e4 ) ); //different z coordinates
   10526                 :          1 :   QVERIFY( e3 != e4 );
   10527                 :          1 :   QgsCompoundCurve e5;
   10528                 :          1 :   QgsLineString le5;
   10529                 :          2 :   le5.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 1 )
   10530                 :          1 :                  << QgsPoint( QgsWkbTypes::PointM, 1 / 3.0, 4 / 3.0, 0, 2 )
   10531                 :          1 :                  << QgsPoint( QgsWkbTypes::PointM, 7, 8, 0, 3 ) );
   10532                 :          1 :   e5.addCurve( le5.clone() );
   10533                 :          1 :   QgsCompoundCurve e6;
   10534                 :          1 :   QgsLineString le6;
   10535                 :          2 :   le6.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 11 )
   10536                 :          1 :                  << QgsPoint( QgsWkbTypes::PointM, 1 / 3.0, 4 / 3.0, 0, 12 )
   10537                 :          1 :                  << QgsPoint( QgsWkbTypes::PointM, 7, 8, 0, 13 ) );
   10538                 :          1 :   e6.addCurve( le6.clone() );
   10539                 :          1 :   QVERIFY( !( e5 == e6 ) ); //different m values
   10540                 :          1 :   QVERIFY( e5 != e6 );
   10541                 :            : 
   10542                 :          1 :   QVERIFY( e6 != QgsLineString() );
   10543                 :            : 
   10544                 :            :   // assignment operator
   10545                 :          1 :   e5.addCurve( le5.clone() );
   10546                 :          1 :   QVERIFY( e5 != e6 );
   10547                 :          1 :   e6 = e5;
   10548                 :          1 :   QCOMPARE( e5, e6 );
   10549                 :            : 
   10550                 :            :   //isClosed
   10551                 :          1 :   QgsCompoundCurve c11;
   10552                 :          1 :   QgsCircularString l11;
   10553                 :          1 :   QVERIFY( !c11.isClosed() );
   10554                 :          2 :   l11.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
   10555                 :          1 :                  << QgsPoint( 11, 2 )
   10556                 :          1 :                  << QgsPoint( 11, 22 )
   10557                 :          1 :                  << QgsPoint( 1, 22 ) );
   10558                 :          1 :   c11.addCurve( l11.clone() );
   10559                 :          1 :   QVERIFY( !c11.isClosed() );
   10560                 :          1 :   QgsLineString ls11;
   10561                 :          2 :   ls11.setPoints( QgsPointSequence() << QgsPoint( 1, 22 )
   10562                 :          1 :                   << QgsPoint( 1, 2 ) );
   10563                 :          1 :   c11.addCurve( ls11.clone() );
   10564                 :          1 :   QVERIFY( c11.isClosed() );
   10565                 :            : 
   10566                 :            :   //test that m values aren't considered when testing for closedness
   10567                 :          1 :   c11.clear();
   10568                 :          2 :   l11.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 3 )
   10569                 :          1 :                  << QgsPoint( QgsWkbTypes::PointM, 11, 2, 0, 4 )
   10570                 :          1 :                  << QgsPoint( QgsWkbTypes::PointM, 11, 22, 0, 5 )
   10571                 :          1 :                  << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 6 ) );
   10572                 :          1 :   c11.addCurve( l11.clone() );
   10573                 :          1 :   QVERIFY( c11.isClosed() );
   10574                 :            : 
   10575                 :            :   //polygonf
   10576                 :          1 :   QgsCircularString lc13;
   10577                 :          1 :   QgsCompoundCurve c13;
   10578                 :          2 :   lc13.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
   10579                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 11, 2, 11, 14 )
   10580                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 11, 22, 21, 24 )
   10581                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 1, 22, 31, 34 ) );
   10582                 :          1 :   c13.addCurve( lc13.clone() );
   10583                 :          1 :   QgsLineString ls13;
   10584                 :          1 :   ls13.setPoints( QgsPointSequence() << QgsPoint( 1, 22 ) << QgsPoint( 23, 22 ) );
   10585                 :          1 :   c13.addCurve( ls13.clone() );
   10586                 :          1 :   QPolygonF poly = c13.asQPolygonF();
   10587                 :          1 :   QCOMPARE( poly.count(), 183 );
   10588                 :          1 :   QCOMPARE( poly.at( 0 ).x(), 1.0 );
   10589                 :          1 :   QCOMPARE( poly.at( 0 ).y(), 2.0 );
   10590                 :          1 :   QCOMPARE( poly.at( 182 ).x(), 23.0 );
   10591                 :          1 :   QCOMPARE( poly.at( 182 ).y(), 22.0 );
   10592                 :            : 
   10593                 :            :   // clone tests
   10594                 :          1 :   QgsCircularString lc14;
   10595                 :          2 :   lc14.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
   10596                 :          1 :                   << QgsPoint( 11, 2 )
   10597                 :          1 :                   << QgsPoint( 11, 22 )
   10598                 :          1 :                   << QgsPoint( 1, 22 ) );
   10599                 :          1 :   QgsCompoundCurve c14;
   10600                 :          1 :   c14.addCurve( lc14.clone() );
   10601                 :          1 :   QgsLineString ls14;
   10602                 :          1 :   ls14.setPoints( QgsPointSequence() << QgsPoint( 1, 22 ) << QgsPoint( 23, 22 ) );
   10603                 :          1 :   c14.addCurve( ls14.clone() );
   10604                 :          1 :   std::unique_ptr<QgsCompoundCurve> cloned( c14.clone() );
   10605                 :          1 :   QCOMPARE( *cloned, c14 );
   10606                 :            : 
   10607                 :            :   //clone with Z/M
   10608                 :          2 :   lc14.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
   10609                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 11, 2, 11, 14 )
   10610                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 11, 22, 21, 24 )
   10611                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 1, 22, 31, 34 ) );
   10612                 :          1 :   ls14.setPoints( QgsPointSequence() << QgsPoint( 1, 22, 31, 34 ) << QgsPoint( 23, 22, 42, 43 ) );
   10613                 :          1 :   c14.clear();
   10614                 :          1 :   c14.addCurve( lc14.clone() );
   10615                 :          1 :   c14.addCurve( ls14.clone() );
   10616                 :          1 :   cloned.reset( c14.clone() );
   10617                 :          1 :   QCOMPARE( *cloned, c14 );
   10618                 :            : 
   10619                 :            :   //clone an empty line
   10620                 :          1 :   c14.clear();
   10621                 :          1 :   cloned.reset( c14.clone() );
   10622                 :          1 :   QVERIFY( cloned->isEmpty() );
   10623                 :          1 :   QCOMPARE( cloned->numPoints(), 0 );
   10624                 :          1 :   QVERIFY( !cloned->is3D() );
   10625                 :          1 :   QVERIFY( !cloned->isMeasure() );
   10626                 :          1 :   QCOMPARE( cloned->wkbType(), QgsWkbTypes::CompoundCurve );
   10627                 :            : 
   10628                 :            :   //segmentize tests
   10629                 :          1 :   QgsCompoundCurve toSegment;
   10630                 :          1 :   QgsCircularString lcSegment;
   10631                 :          2 :   lcSegment.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
   10632                 :          1 :                        << QgsPoint( 11, 10 ) << QgsPoint( 21, 2 ) );
   10633                 :          1 :   toSegment.addCurve( lcSegment.clone() );
   10634                 :          1 :   std::unique_ptr<QgsLineString> segmentized( static_cast< QgsLineString * >( toSegment.segmentize() ) );
   10635                 :          1 :   QCOMPARE( segmentized->numPoints(), 156 );
   10636                 :          1 :   QCOMPARE( segmentized->vertexCount(), 156 );
   10637                 :          1 :   QCOMPARE( segmentized->ringCount(), 1 );
   10638                 :          1 :   QCOMPARE( segmentized->partCount(), 1 );
   10639                 :          1 :   QCOMPARE( segmentized->wkbType(), QgsWkbTypes::LineString );
   10640                 :          1 :   QVERIFY( !segmentized->is3D() );
   10641                 :          1 :   QVERIFY( !segmentized->isMeasure() );
   10642                 :            : 
   10643                 :          1 :   QCOMPARE( segmentized->pointN( 0 ), lcSegment.pointN( 0 ) );
   10644                 :          1 :   QCOMPARE( segmentized->pointN( segmentized->numPoints() - 1 ), lcSegment.pointN( toSegment.numPoints() - 1 ) );
   10645                 :            : 
   10646                 :            :   //segmentize with Z/M
   10647                 :          2 :   lcSegment.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
   10648                 :          1 :                        << QgsPoint( QgsWkbTypes::PointZM, 11, 10, 11, 14 )
   10649                 :          1 :                        << QgsPoint( QgsWkbTypes::PointZM, 21, 2, 21, 24 ) );
   10650                 :          1 :   toSegment.clear();
   10651                 :          1 :   toSegment.addCurve( lcSegment.clone() );
   10652                 :          1 :   segmentized.reset( static_cast< QgsLineString * >( toSegment.segmentize() ) );
   10653                 :          1 :   QCOMPARE( segmentized->numPoints(), 156 );
   10654                 :          1 :   QCOMPARE( segmentized->vertexCount(), 156 );
   10655                 :          1 :   QCOMPARE( segmentized->ringCount(), 1 );
   10656                 :          1 :   QCOMPARE( segmentized->partCount(), 1 );
   10657                 :          1 :   QCOMPARE( segmentized->wkbType(), QgsWkbTypes::LineStringZM );
   10658                 :          1 :   QVERIFY( segmentized->is3D() );
   10659                 :          1 :   QVERIFY( segmentized->isMeasure() );
   10660                 :          1 :   QCOMPARE( segmentized->pointN( 0 ), lcSegment.pointN( 0 ) );
   10661                 :          1 :   QCOMPARE( segmentized->pointN( segmentized->numPoints() - 1 ), lcSegment.pointN( toSegment.numPoints() - 1 ) );
   10662                 :            : 
   10663                 :            :   //segmentize an empty line
   10664                 :          1 :   toSegment.clear();
   10665                 :          1 :   segmentized.reset( static_cast< QgsLineString * >( toSegment.segmentize() ) );
   10666                 :          1 :   QVERIFY( segmentized->isEmpty() );
   10667                 :          1 :   QCOMPARE( segmentized->numPoints(), 0 );
   10668                 :          1 :   QVERIFY( !segmentized->is3D() );
   10669                 :          1 :   QVERIFY( !segmentized->isMeasure() );
   10670                 :          1 :   QCOMPARE( segmentized->wkbType(), QgsWkbTypes::LineString );
   10671                 :            : 
   10672                 :            :   //to/from WKB
   10673                 :          1 :   QgsCompoundCurve c15;
   10674                 :          1 :   QgsCircularString l15;
   10675                 :          2 :   l15.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
   10676                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 2, 11, 14 )
   10677                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 22, 21, 24 )
   10678                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 22, 31, 34 ) );
   10679                 :          1 :   c15.addCurve( l15.clone() );
   10680                 :          1 :   QByteArray wkb15 = c15.asWkb();
   10681                 :          1 :   QCOMPARE( wkb15.size(), c15.wkbSize() );
   10682                 :          1 :   QgsCompoundCurve c16;
   10683                 :          1 :   QgsConstWkbPtr wkb15ptr( wkb15 );
   10684                 :          1 :   c16.fromWkb( wkb15ptr );
   10685                 :          1 :   QCOMPARE( c16.numPoints(), 4 );
   10686                 :          1 :   QCOMPARE( c16.vertexCount(), 4 );
   10687                 :          1 :   QCOMPARE( c16.nCoordinates(), 4 );
   10688                 :          1 :   QCOMPARE( c16.ringCount(), 1 );
   10689                 :          1 :   QCOMPARE( c16.partCount(), 1 );
   10690                 :          1 :   QCOMPARE( c16.wkbType(), QgsWkbTypes::CompoundCurveZM );
   10691                 :          1 :   QVERIFY( c16.is3D() );
   10692                 :          1 :   QVERIFY( c16.isMeasure() );
   10693                 :          1 :   QCOMPARE( c16.nCurves(), 1 );
   10694                 :          1 :   QCOMPARE( dynamic_cast< const QgsCircularString *>( c16.curveAt( 0 ) )->pointN( 0 ), l15.pointN( 0 ) );
   10695                 :          1 :   QCOMPARE( dynamic_cast< const QgsCircularString *>( c16.curveAt( 0 ) )->pointN( 1 ), l15.pointN( 1 ) );
   10696                 :          1 :   QCOMPARE( dynamic_cast< const QgsCircularString *>( c16.curveAt( 0 ) )->pointN( 2 ), l15.pointN( 2 ) );
   10697                 :          1 :   QCOMPARE( dynamic_cast< const QgsCircularString *>( c16.curveAt( 0 ) )->pointN( 3 ), l15.pointN( 3 ) );
   10698                 :            : 
   10699                 :            :   //bad WKB - check for no crash
   10700                 :          1 :   c16.clear();
   10701                 :          1 :   QgsConstWkbPtr nullPtr( nullptr, 0 );
   10702                 :          1 :   QVERIFY( !c16.fromWkb( nullPtr ) );
   10703                 :          1 :   QCOMPARE( c16.wkbType(), QgsWkbTypes::CompoundCurve );
   10704                 :          1 :   QgsPoint point( 1, 2 );
   10705                 :          1 :   QByteArray wkb16 = point.asWkb();
   10706                 :          1 :   QgsConstWkbPtr wkb16ptr( wkb16 );
   10707                 :          1 :   QVERIFY( !c16.fromWkb( wkb16ptr ) );
   10708                 :          1 :   QCOMPARE( c16.wkbType(), QgsWkbTypes::CompoundCurve );
   10709                 :            : 
   10710                 :            :   //to/from WKT
   10711                 :          1 :   QgsCompoundCurve c17;
   10712                 :          1 :   QgsCircularString l17;
   10713                 :          2 :   l17.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
   10714                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 2, 11, 14 )
   10715                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 22, 21, 24 )
   10716                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 22, 31, 34 ) );
   10717                 :          1 :   c17.addCurve( l17.clone() );
   10718                 :            : 
   10719                 :          1 :   QString wkt = c17.asWkt();
   10720                 :          1 :   QVERIFY( !wkt.isEmpty() );
   10721                 :          1 :   QgsCompoundCurve c18;
   10722                 :          1 :   QVERIFY( c18.fromWkt( wkt ) );
   10723                 :          1 :   QCOMPARE( c18.numPoints(), 4 );
   10724                 :          1 :   QCOMPARE( c18.wkbType(), QgsWkbTypes::CompoundCurveZM );
   10725                 :          1 :   QVERIFY( c18.is3D() );
   10726                 :          1 :   QVERIFY( c18.isMeasure() );
   10727                 :          1 :   QCOMPARE( dynamic_cast< const QgsCircularString *>( c18.curveAt( 0 ) )->pointN( 0 ), l17.pointN( 0 ) );
   10728                 :          1 :   QCOMPARE( dynamic_cast< const QgsCircularString *>( c18.curveAt( 0 ) )->pointN( 1 ), l17.pointN( 1 ) );
   10729                 :          1 :   QCOMPARE( dynamic_cast< const QgsCircularString *>( c18.curveAt( 0 ) )->pointN( 2 ), l17.pointN( 2 ) );
   10730                 :          1 :   QCOMPARE( dynamic_cast< const QgsCircularString *>( c18.curveAt( 0 ) )->pointN( 3 ), l17.pointN( 3 ) );
   10731                 :            : 
   10732                 :            :   //bad WKT
   10733                 :          1 :   QVERIFY( !c18.fromWkt( "Polygon()" ) );
   10734                 :          1 :   QVERIFY( c18.isEmpty() );
   10735                 :          1 :   QCOMPARE( c18.numPoints(), 0 );
   10736                 :          1 :   QVERIFY( !c18.is3D() );
   10737                 :          1 :   QVERIFY( !c18.isMeasure() );
   10738                 :          1 :   QCOMPARE( c18.wkbType(), QgsWkbTypes::CompoundCurve );
   10739                 :          1 :   QVERIFY( !c18.fromWkt( "CompoundCurve(LineString(0 0, 1 1),Point( 2 2 ))" ) );
   10740                 :            : 
   10741                 :            :   //asGML2
   10742                 :          1 :   QgsCompoundCurve exportCurve;
   10743                 :          1 :   QgsCircularString exportLine;
   10744                 :          2 :   exportLine.setPoints( QgsPointSequence() << QgsPoint( 31, 32 )
   10745                 :          1 :                         << QgsPoint( 41, 42 )
   10746                 :          1 :                         << QgsPoint( 51, 52 ) );
   10747                 :          1 :   exportCurve.addCurve( exportLine.clone() );
   10748                 :          1 :   QgsLineString exportLineString;
   10749                 :          2 :   exportLineString.setPoints( QgsPointSequence() << QgsPoint( 51, 52 )
   10750                 :          1 :                               << QgsPoint( 61, 62 ) );
   10751                 :          1 :   exportCurve.addCurve( exportLineString.clone() );
   10752                 :            : 
   10753                 :          1 :   QgsCircularString exportLineFloat;
   10754                 :          2 :   exportLineFloat.setPoints( QgsPointSequence() << QgsPoint( 1 / 3.0, 2 / 3.0 )
   10755                 :          1 :                              << QgsPoint( 1 + 1 / 3.0, 1 + 2 / 3.0 )
   10756                 :          1 :                              << QgsPoint( 2 + 1 / 3.0, 2 + 2 / 3.0 ) );
   10757                 :          1 :   QgsCompoundCurve exportCurveFloat;
   10758                 :          1 :   exportCurveFloat.addCurve( exportLineFloat.clone() );
   10759                 :          1 :   QgsLineString exportLineStringFloat;
   10760                 :          2 :   exportLineStringFloat.setPoints( QgsPointSequence() << QgsPoint( 2 + 1 / 3.0, 2 + 2 / 3.0 )
   10761                 :          1 :                                    << QgsPoint( 3 + 1 / 3.0, 3 + 2 / 3.0 ) );
   10762                 :          1 :   exportCurveFloat.addCurve( exportLineStringFloat.clone() );
   10763                 :            : 
   10764                 :          2 :   QDomDocument doc( QStringLiteral( "gml" ) );
   10765                 :          2 :   QString expectedGML2( QStringLiteral( "<LineString xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">31,32 41,42 51,52 61,62</coordinates></LineString>" ) );
   10766                 :          1 :   QString result = elemToString( exportCurve.asGml2( doc ) );
   10767                 :          3 :   QGSCOMPAREGML( result, expectedGML2 );
   10768                 :          2 :   QString expectedGML2prec3( QStringLiteral( "<LineString xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">0.333,0.667 1.333,1.667 2.333,2.667 3.333,3.667</coordinates></LineString>" ) );
   10769                 :          1 :   result = elemToString( exportCurveFloat.asGml2( doc, 3 ) );
   10770                 :          3 :   QGSCOMPAREGML( result, expectedGML2prec3 );
   10771                 :          2 :   QString expectedGML2empty( QStringLiteral( "<LineString xmlns=\"gml\"/>" ) );
   10772                 :          3 :   QGSCOMPAREGML( elemToString( QgsCompoundCurve().asGml2( doc ) ), expectedGML2empty );
   10773                 :            : 
   10774                 :            : 
   10775                 :            :   //asGML3
   10776                 :          2 :   QString expectedGML3( QStringLiteral( "<CompositeCurve xmlns=\"gml\"><curveMember xmlns=\"gml\"><Curve xmlns=\"gml\"><segments xmlns=\"gml\"><ArcString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">31 32 41 42 51 52</posList></ArcString></segments></Curve></curveMember><curveMember xmlns=\"gml\"><LineString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">51 52 61 62</posList></LineString></curveMember></CompositeCurve>" ) );
   10777                 :          1 :   result = elemToString( exportCurve.asGml3( doc ) );
   10778                 :          1 :   QCOMPARE( result, expectedGML3 );
   10779                 :          2 :   QString expectedGML3prec3( QStringLiteral( "<CompositeCurve xmlns=\"gml\"><curveMember xmlns=\"gml\"><Curve xmlns=\"gml\"><segments xmlns=\"gml\"><ArcString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">0.333 0.667 1.333 1.667 2.333 2.667</posList></ArcString></segments></Curve></curveMember><curveMember xmlns=\"gml\"><LineString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">2.333 2.667 3.333 3.667</posList></LineString></curveMember></CompositeCurve>" ) );
   10780                 :          1 :   result = elemToString( exportCurveFloat.asGml3( doc, 3 ) );
   10781                 :          1 :   QCOMPARE( result, expectedGML3prec3 );
   10782                 :          2 :   QString expectedGML3empty( QStringLiteral( "<CompositeCurve xmlns=\"gml\"/>" ) );
   10783                 :          3 :   QGSCOMPAREGML( elemToString( QgsCompoundCurve().asGml3( doc ) ), expectedGML3empty );
   10784                 :            : 
   10785                 :            :   //asJSON
   10786                 :          1 :   QString expectedJson( "{\"coordinates\":[[31.0,32.0],[41.0,42.0],[51.0,52.0],[61.0,62.0]],\"type\":\"LineString\"}" );
   10787                 :          1 :   result = exportCurve.asJson();
   10788                 :          1 :   QCOMPARE( result, expectedJson );
   10789                 :          1 :   QString expectedJsonPrec3( "{\"coordinates\":[[0.333,0.667],[1.333,1.667],[2.333,2.667],[3.333,3.667]],\"type\":\"LineString\"}" );
   10790                 :          1 :   result = exportCurveFloat.asJson( 3 );
   10791                 :          1 :   QCOMPARE( result, expectedJsonPrec3 );
   10792                 :            : 
   10793                 :            :   //asKML
   10794                 :          2 :   QString expectedKml( QStringLiteral( "<LineString><altitudeMode>clampToGround</altitudeMode><coordinates>31,32,0 41,42,0 51,52,0 61,62,0</coordinates></LineString>" ) );
   10795                 :          1 :   QCOMPARE( exportCurve.asKml(), expectedKml );
   10796                 :          2 :   QString expectedKmlPrec3( QStringLiteral( "<LineString><altitudeMode>clampToGround</altitudeMode><coordinates>0.333,0.667,0 1.333,1.667,0 2.333,2.667,0 3.333,3.667,0</coordinates></LineString>" ) );
   10797                 :          1 :   QCOMPARE( exportCurveFloat.asKml( 3 ), expectedKmlPrec3 );
   10798                 :            : 
   10799                 :            :   //length
   10800                 :          1 :   QgsCompoundCurve c19;
   10801                 :          1 :   QCOMPARE( c19.length(), 0.0 );
   10802                 :          1 :   QgsCircularString l19;
   10803                 :          2 :   l19.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 )
   10804                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 10, 4, 5 )
   10805                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 ) );
   10806                 :          1 :   c19.addCurve( l19.clone() );
   10807                 :          1 :   QgsLineString l19a;
   10808                 :          2 :   l19a.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 )
   10809                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 25, 10, 6, 7 ) );
   10810                 :          1 :   c19.addCurve( l19a.clone() );
   10811                 :          1 :   QGSCOMPARENEAR( c19.length(), 36.1433, 0.001 );
   10812                 :            : 
   10813                 :            :   //startPoint
   10814                 :          1 :   QCOMPARE( c19.startPoint(), QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 ) );
   10815                 :            : 
   10816                 :            :   //endPoint
   10817                 :          1 :   QCOMPARE( c19.endPoint(), QgsPoint( QgsWkbTypes::PointZM, 25, 10, 6, 7 ) );
   10818                 :            : 
   10819                 :            :   //bad start/end points. Test that this doesn't crash.
   10820                 :          1 :   c19.clear();
   10821                 :          1 :   QVERIFY( c19.startPoint().isEmpty() );
   10822                 :          1 :   QVERIFY( c19.endPoint().isEmpty() );
   10823                 :            : 
   10824                 :            :   //curveToLine
   10825                 :          1 :   c19.clear();
   10826                 :          2 :   l19.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 )
   10827                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 10, 4, 5 )
   10828                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 ) );
   10829                 :          1 :   c19.addCurve( l19.clone() );
   10830                 :          2 :   l19a.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 )
   10831                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 25, 10, 6, 7 ) );
   10832                 :          1 :   c19.addCurve( l19a.clone() );
   10833                 :          1 :   segmentized.reset( c19.curveToLine() );
   10834                 :          1 :   QCOMPARE( segmentized->numPoints(), 182 );
   10835                 :          1 :   QCOMPARE( segmentized->wkbType(), QgsWkbTypes::LineStringZM );
   10836                 :          1 :   QVERIFY( segmentized->is3D() );
   10837                 :          1 :   QVERIFY( segmentized->isMeasure() );
   10838                 :          1 :   QCOMPARE( segmentized->pointN( 0 ), l19.pointN( 0 ) );
   10839                 :          1 :   QCOMPARE( segmentized->pointN( segmentized->numPoints() - 1 ), l19a.pointN( l19a.numPoints() - 1 ) );
   10840                 :            : 
   10841                 :            :   // points
   10842                 :          1 :   QgsCompoundCurve c20;
   10843                 :          1 :   QgsCircularString l20;
   10844                 :          1 :   QgsPointSequence points;
   10845                 :          1 :   c20.points( points );
   10846                 :          1 :   QVERIFY( points.isEmpty() );
   10847                 :          2 :   l20.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 )
   10848                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 10, 4, 5 )
   10849                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 ) );
   10850                 :          1 :   c20.addCurve( l20.clone() );
   10851                 :          1 :   QgsLineString ls20;
   10852                 :          2 :   ls20.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 )
   10853                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 25, 10, 6, 7 ) );
   10854                 :          1 :   c20.addCurve( ls20.clone() );
   10855                 :          1 :   c20.points( points );
   10856                 :          1 :   QCOMPARE( points.count(), 4 );
   10857                 :          1 :   QCOMPARE( points.at( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 ) );
   10858                 :          1 :   QCOMPARE( points.at( 1 ), QgsPoint( QgsWkbTypes::PointZM, 1, 10, 4, 5 ) );
   10859                 :          1 :   QCOMPARE( points.at( 2 ), QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 ) );
   10860                 :          1 :   QCOMPARE( points.at( 3 ), QgsPoint( QgsWkbTypes::PointZM, 25, 10, 6, 7 ) );
   10861                 :            : 
   10862                 :            :   //CRS transform
   10863                 :          2 :   QgsCoordinateReferenceSystem sourceSrs( QStringLiteral( "EPSG:3994" ) );
   10864                 :          2 :   QgsCoordinateReferenceSystem destSrs( QStringLiteral( "EPSG:4202" ) ); // want a transform with ellipsoid change
   10865                 :          1 :   QgsCoordinateTransform tr( sourceSrs, destSrs, QgsProject::instance() );
   10866                 :            : 
   10867                 :            :   // 2d CRS transform
   10868                 :          1 :   QgsCompoundCurve c21;
   10869                 :          1 :   QgsCircularString l21;
   10870                 :          2 :   l21.setPoints( QgsPointSequence() << QgsPoint( 6374985, -3626584 )
   10871                 :          1 :                  << QgsPoint( 6474985, -3526584 ) );
   10872                 :          1 :   c21.addCurve( l21.clone() );
   10873                 :          1 :   QgsLineString ls21;
   10874                 :          2 :   ls21.setPoints( QgsPointSequence() << QgsPoint( 6474985, -3526584 )
   10875                 :          1 :                   << QgsPoint( 6504985, -3526584 ) );
   10876                 :          1 :   c21.addCurve( ls21.clone() );
   10877                 :          1 :   c21.transform( tr, QgsCoordinateTransform::ForwardTransform );
   10878                 :          1 :   QGSCOMPARENEAR( c21.xAt( 0 ), 175.771, 0.001 );
   10879                 :          1 :   QGSCOMPARENEAR( c21.yAt( 0 ), -39.724, 0.001 );
   10880                 :          1 :   QGSCOMPARENEAR( c21.xAt( 1 ), 176.959, 0.001 );
   10881                 :          1 :   QGSCOMPARENEAR( c21.yAt( 1 ), -38.7999, 0.001 );
   10882                 :          1 :   QGSCOMPARENEAR( c21.xAt( 2 ), 177.315211, 0.001 );
   10883                 :          1 :   QGSCOMPARENEAR( c21.yAt( 2 ), -38.799974, 0.001 );
   10884                 :          1 :   QGSCOMPARENEAR( c21.boundingBox().xMinimum(), 175.770033, 0.001 );
   10885                 :          1 :   QGSCOMPARENEAR( c21.boundingBox().yMinimum(), -39.724, 0.001 );
   10886                 :          1 :   QGSCOMPARENEAR( c21.boundingBox().xMaximum(), 177.315211, 0.001 );
   10887                 :          1 :   QGSCOMPARENEAR( c21.boundingBox().yMaximum(), -38.7999, 0.001 );
   10888                 :            : 
   10889                 :            :   //3d CRS transform
   10890                 :          1 :   QgsCompoundCurve c22;
   10891                 :          2 :   l21.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 6374985, -3626584, 1, 2 )
   10892                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 6474985, -3526584, 3, 4 ) );
   10893                 :          1 :   c22.addCurve( l21.clone() );
   10894                 :          2 :   ls21.setPoints( QgsPointSequence() << QgsPoint( 6474985, -3526584, 3, 4 )
   10895                 :          1 :                   << QgsPoint( 6504985, -3526584, 5, 6 ) );
   10896                 :          1 :   c22.addCurve( ls21.clone() );
   10897                 :          1 :   c22.transform( tr, QgsCoordinateTransform::ForwardTransform );
   10898                 :          1 :   QgsPoint pt;
   10899                 :            :   QgsVertexId::VertexType v;
   10900                 :          1 :   c22.pointAt( 0, pt, v );
   10901                 :          1 :   QGSCOMPARENEAR( pt.x(), 175.771, 0.001 );
   10902                 :          1 :   QGSCOMPARENEAR( pt.y(), -39.724, 0.001 );
   10903                 :          1 :   QGSCOMPARENEAR( pt.z(), 1.0, 0.001 );
   10904                 :          1 :   QCOMPARE( pt.m(), 2.0 );
   10905                 :          1 :   c22.pointAt( 1, pt, v );
   10906                 :          1 :   QGSCOMPARENEAR( pt.x(), 176.959, 0.001 );
   10907                 :          1 :   QGSCOMPARENEAR( pt.y(), -38.7999, 0.001 );
   10908                 :          1 :   QGSCOMPARENEAR( pt.z(), 3.0, 0.001 );
   10909                 :          1 :   QCOMPARE( pt.m(), 4.0 );
   10910                 :          1 :   c22.pointAt( 2, pt, v );
   10911                 :          1 :   QGSCOMPARENEAR( pt.x(), 177.315211, 0.001 );
   10912                 :          1 :   QGSCOMPARENEAR( pt.y(), -38.7999, 0.001 );
   10913                 :          1 :   QGSCOMPARENEAR( pt.z(), 5.0, 0.001 );
   10914                 :          1 :   QCOMPARE( pt.m(), 6.0 );
   10915                 :            : 
   10916                 :            :   //reverse transform
   10917                 :          1 :   c22.transform( tr, QgsCoordinateTransform::ReverseTransform );
   10918                 :          1 :   c22.pointAt( 0, pt, v );
   10919                 :          1 :   QGSCOMPARENEAR( pt.x(), 6374985, 100 );
   10920                 :          1 :   QGSCOMPARENEAR( pt.y(), -3626584, 100 );
   10921                 :          1 :   QGSCOMPARENEAR( pt.z(), 1.0, 0.001 );
   10922                 :          1 :   QCOMPARE( pt.m(), 2.0 );
   10923                 :          1 :   c22.pointAt( 1, pt, v );
   10924                 :          1 :   QGSCOMPARENEAR( pt.x(), 6474985, 100 );
   10925                 :          1 :   QGSCOMPARENEAR( pt.y(), -3526584, 100 );
   10926                 :          1 :   QGSCOMPARENEAR( pt.z(), 3.0, 0.001 );
   10927                 :          1 :   QCOMPARE( pt.m(), 4.0 );
   10928                 :          1 :   c22.pointAt( 2, pt, v );
   10929                 :          1 :   QGSCOMPARENEAR( pt.x(), 6504985, 100 );
   10930                 :          1 :   QGSCOMPARENEAR( pt.y(), -3526584, 100 );
   10931                 :          1 :   QGSCOMPARENEAR( pt.z(), 5.0, 0.001 );
   10932                 :          1 :   QCOMPARE( pt.m(), 6.0 );
   10933                 :            : 
   10934                 :            : #if PROJ_VERSION_MAJOR<6 // note - z value transform doesn't currently work with proj 6+, because we don't yet support compound CRS definitions
   10935                 :            :   //z value transform
   10936                 :            :   c22.transform( tr, QgsCoordinateTransform::ForwardTransform, true );
   10937                 :            :   c22.pointAt( 0, pt, v );
   10938                 :            :   QGSCOMPARENEAR( pt.z(), -19.249066, 0.001 );
   10939                 :            :   c22.pointAt( 1, pt, v );
   10940                 :            :   QGSCOMPARENEAR( pt.z(), -21.092128, 0.001 );
   10941                 :            :   c22.pointAt( 2, pt, v );
   10942                 :            :   QGSCOMPARENEAR( pt.z(), -19.370485, 0.001 );
   10943                 :            : 
   10944                 :            :   c22.transform( tr, QgsCoordinateTransform::ReverseTransform, true );
   10945                 :            :   c22.pointAt( 0, pt, v );
   10946                 :            :   QGSCOMPARENEAR( pt.z(), 1, 0.001 );
   10947                 :            :   c22.pointAt( 1, pt, v );
   10948                 :            :   QGSCOMPARENEAR( pt.z(), 3, 0.001 );
   10949                 :            :   c22.pointAt( 2, pt, v );
   10950                 :            :   QGSCOMPARENEAR( pt.z(), 5, 0.001 );
   10951                 :            : #endif
   10952                 :            : 
   10953                 :            :   //QTransform transform
   10954                 :          1 :   QTransform qtr = QTransform::fromScale( 2, 3 );
   10955                 :          1 :   QgsCompoundCurve c23;
   10956                 :          1 :   QgsCircularString l23;
   10957                 :          2 :   l23.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
   10958                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
   10959                 :          1 :   c23.addCurve( l23.clone() );
   10960                 :          1 :   QgsLineString ls23;
   10961                 :          1 :   ls23.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) << QgsPoint( QgsWkbTypes::PointZM, 21, 13, 13, 14 ) );
   10962                 :          1 :   c23.addCurve( ls23.clone() );
   10963                 :          1 :   c23.transform( qtr, 5, 2, 4, 3 );
   10964                 :          1 :   c23.pointAt( 0, pt, v );
   10965                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZM, 2, 6, 11, 16 ) );
   10966                 :          1 :   c23.pointAt( 1, pt, v );
   10967                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZM, 22, 36, 31, 46 ) );
   10968                 :          1 :   c23.pointAt( 2, pt, v );
   10969                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZM, 42, 39, 31, 46 ) );
   10970                 :          1 :   QCOMPARE( c23.boundingBox(), QgsRectangle( 2, 6, 42, 39 ) );
   10971                 :            : 
   10972                 :            :   //insert vertex
   10973                 :            :   //cannot insert vertex in empty line
   10974                 :          1 :   QgsCompoundCurve c24;
   10975                 :          1 :   QVERIFY( !c24.insertVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
   10976                 :          1 :   QCOMPARE( c24.numPoints(), 0 );
   10977                 :            : 
   10978                 :            :   //2d line
   10979                 :          1 :   QgsCircularString l24;
   10980                 :          2 :   l24.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
   10981                 :          1 :                  << QgsPoint( 11, 12 ) << QgsPoint( 1, 22 ) );
   10982                 :          1 :   c24.addCurve( l24.clone() );
   10983                 :          1 :   QVERIFY( c24.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 4.0, 7.0 ) ) );
   10984                 :          1 :   QCOMPARE( c24.numPoints(), 5 );
   10985                 :          1 :   QVERIFY( !c24.is3D() );
   10986                 :          1 :   QVERIFY( !c24.isMeasure() );
   10987                 :          1 :   QCOMPARE( c24.wkbType(), QgsWkbTypes::CompoundCurve );
   10988                 :          1 :   c24.pointAt( 0, pt, v );
   10989                 :          1 :   QCOMPARE( pt, QgsPoint( 1.0, 2.0 ) );
   10990                 :          1 :   c24.pointAt( 1, pt, v );
   10991                 :          1 :   QCOMPARE( pt, QgsPoint( 4.0, 7.0 ) );
   10992                 :          1 :   c24.pointAt( 2, pt, v );
   10993                 :          1 :   QGSCOMPARENEAR( pt.x(), 7.192236, 0.01 );
   10994                 :          1 :   QGSCOMPARENEAR( pt.y(), 9.930870, 0.01 );
   10995                 :          1 :   c24.pointAt( 3, pt, v );
   10996                 :          1 :   QCOMPARE( pt, QgsPoint( 11.0, 12.0 ) );
   10997                 :          1 :   c24.pointAt( 4, pt, v );
   10998                 :          1 :   QCOMPARE( pt, QgsPoint( 1.0, 22.0 ) );
   10999                 :            : 
   11000                 :          1 :   QVERIFY( c24.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 8.0, 9.0 ) ) );
   11001                 :          1 :   QVERIFY( c24.insertVertex( QgsVertexId( 0, 0, 2 ), QgsPoint( 18.0, 16.0 ) ) );
   11002                 :          1 :   QCOMPARE( c24.numPoints(), 9 );
   11003                 :          1 :   c24.pointAt( 0, pt, v );
   11004                 :          1 :   QCOMPARE( pt, QgsPoint( 1.0, 2.0 ) );
   11005                 :          1 :   c24.pointAt( 1, pt, v );
   11006                 :          1 :   QGSCOMPARENEAR( pt.x(), 4.363083, 0.01 );
   11007                 :          1 :   QGSCOMPARENEAR( pt.y(), 5.636917, 0.01 );
   11008                 :          1 :   c24.pointAt( 2, pt, v );
   11009                 :          1 :   QCOMPARE( pt, QgsPoint( 8.0, 9.0 ) );
   11010                 :          1 :   c24.pointAt( 3, pt, v );
   11011                 :          1 :   QCOMPARE( pt, QgsPoint( 18.0, 16.0 ) );
   11012                 :          1 :   c24.pointAt( 4, pt, v );
   11013                 :          1 :   QGSCOMPARENEAR( pt.x(), 5.876894, 0.01 );
   11014                 :          1 :   QGSCOMPARENEAR( pt.y(), 8.246211, 0.01 );
   11015                 :          1 :   c24.pointAt( 5, pt, v );
   11016                 :          1 :   QCOMPARE( pt, QgsPoint( 4.0, 7.0 ) );
   11017                 :          1 :   c24.pointAt( 6, pt, v );
   11018                 :          1 :   QGSCOMPARENEAR( pt.x(), 7.192236, 0.01 );
   11019                 :          1 :   QGSCOMPARENEAR( pt.y(), 9.930870, 0.01 );
   11020                 :          1 :   c24.pointAt( 7, pt, v );
   11021                 :          1 :   QCOMPARE( pt, QgsPoint( 11.0, 12.0 ) );
   11022                 :          1 :   c24.pointAt( 8, pt, v );
   11023                 :          1 :   QCOMPARE( pt, QgsPoint( 1.0, 22.0 ) );
   11024                 :            : 
   11025                 :            :   //insert vertex at end
   11026                 :          1 :   QVERIFY( !c24.insertVertex( QgsVertexId( 0, 0, 9 ), QgsPoint( 31.0, 32.0 ) ) );
   11027                 :            : 
   11028                 :            :   //insert vertex past end
   11029                 :          1 :   QVERIFY( !c24.insertVertex( QgsVertexId( 0, 0, 10 ), QgsPoint( 41.0, 42.0 ) ) );
   11030                 :          1 :   QCOMPARE( c24.numPoints(), 9 );
   11031                 :            : 
   11032                 :            :   //insert vertex before start
   11033                 :          1 :   QVERIFY( !c24.insertVertex( QgsVertexId( 0, 0, -18 ), QgsPoint( 41.0, 42.0 ) ) );
   11034                 :          1 :   QCOMPARE( c24.numPoints(), 9 );
   11035                 :            : 
   11036                 :            :   //insert 4d vertex in 4d line
   11037                 :          1 :   c24.clear();
   11038                 :          2 :   l24.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 )
   11039                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 10, 4, 5 )
   11040                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 ) );
   11041                 :          1 :   c24.addCurve( l24.clone( ) );
   11042                 :          1 :   QVERIFY( c24.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) ) );
   11043                 :          1 :   QCOMPARE( c24.numPoints(), 5 );
   11044                 :          1 :   c24.pointAt( 1, pt, v );
   11045                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
   11046                 :            : 
   11047                 :            :   //insert 2d vertex in 4d line
   11048                 :          1 :   QVERIFY( c24.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 101, 102 ) ) );
   11049                 :          1 :   QCOMPARE( c24.numPoints(), 7 );
   11050                 :          1 :   QCOMPARE( c24.wkbType(), QgsWkbTypes::CompoundCurveZM );
   11051                 :          1 :   c24.pointAt( 1, pt, v );
   11052                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZM, 101, 102 ) );
   11053                 :            : 
   11054                 :            :   //insert 4d vertex in 2d line
   11055                 :          1 :   c24.clear();
   11056                 :          2 :   l24.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
   11057                 :          1 :                  << QgsPoint( 11, 12 ) << QgsPoint( 1, 22 ) );
   11058                 :          1 :   c24.addCurve( l24.clone() );
   11059                 :          1 :   QVERIFY( c24.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( QgsWkbTypes::PointZM, 2, 4, 103, 104 ) ) );
   11060                 :          1 :   QCOMPARE( c24.numPoints(), 5 );
   11061                 :          1 :   QCOMPARE( c24.wkbType(), QgsWkbTypes::CompoundCurve );
   11062                 :          1 :   c24.pointAt( 1, pt, v );
   11063                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::Point, 2, 4 ) );
   11064                 :            : 
   11065                 :            :   // invalid
   11066                 :          1 :   QVERIFY( !c24.insertVertex( QgsVertexId( 0, 1, 0 ), QgsPoint( 1, 2 ) ) );
   11067                 :            : 
   11068                 :            :   //move vertex
   11069                 :            : 
   11070                 :            :   //empty line
   11071                 :          1 :   QgsCompoundCurve c25;
   11072                 :          1 :   QgsCircularString l25;
   11073                 :          1 :   QVERIFY( !c25.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
   11074                 :          1 :   QVERIFY( c25.isEmpty() );
   11075                 :            : 
   11076                 :            :   //valid line
   11077                 :          2 :   l25.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
   11078                 :          1 :                  << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) );
   11079                 :          1 :   c25.addCurve( l25.clone() );
   11080                 :          1 :   QVERIFY( c25.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
   11081                 :          1 :   QVERIFY( c25.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 16.0, 17.0 ) ) );
   11082                 :          1 :   QVERIFY( c25.moveVertex( QgsVertexId( 0, 0, 2 ), QgsPoint( 26.0, 27.0 ) ) );
   11083                 :          1 :   c25.pointAt( 0, pt, v );
   11084                 :          1 :   QCOMPARE( pt, QgsPoint( 6.0, 7.0 ) );
   11085                 :          1 :   c25.pointAt( 1, pt, v );
   11086                 :          1 :   QCOMPARE( pt, QgsPoint( 16.0, 17.0 ) );
   11087                 :          1 :   c25.pointAt( 2, pt, v );
   11088                 :          1 :   QCOMPARE( pt, QgsPoint( 26.0, 27.0 ) );
   11089                 :            : 
   11090                 :            :   //out of range
   11091                 :          1 :   QVERIFY( !c25.moveVertex( QgsVertexId( 0, 0, -1 ), QgsPoint( 3.0, 4.0 ) ) );
   11092                 :          1 :   QVERIFY( !c25.moveVertex( QgsVertexId( 0, 0, 10 ), QgsPoint( 3.0, 4.0 ) ) );
   11093                 :          1 :   QVERIFY( !c25.moveVertex( QgsVertexId( 0, 1, 10 ), QgsPoint( 3.0, 4.0 ) ) );
   11094                 :          1 :   c25.pointAt( 0, pt, v );
   11095                 :          1 :   QCOMPARE( pt, QgsPoint( 6.0, 7.0 ) );
   11096                 :          1 :   c25.pointAt( 1, pt, v );
   11097                 :          1 :   QCOMPARE( pt, QgsPoint( 16.0, 17.0 ) );
   11098                 :          1 :   c25.pointAt( 2, pt, v );
   11099                 :          1 :   QCOMPARE( pt, QgsPoint( 26.0, 27.0 ) );
   11100                 :            : 
   11101                 :            :   //move 4d point in 4d line
   11102                 :          2 :   l25.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 2, 3 )
   11103                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 10, 4, 5 )
   11104                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 15, 10, 6, 7 ) );
   11105                 :          1 :   c25.clear();
   11106                 :          1 :   c25.addCurve( l25.clone() );
   11107                 :          1 :   QVERIFY( c25.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( QgsWkbTypes::PointZM, 6, 7, 12, 13 ) ) );
   11108                 :          1 :   c25.pointAt( 1, pt, v );
   11109                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZM, 6, 7, 12, 13 ) );
   11110                 :            : 
   11111                 :            :   //move 2d point in 4d line, existing z/m should be maintained
   11112                 :          1 :   QVERIFY( c25.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 34, 35 ) ) );
   11113                 :          1 :   c25.pointAt( 1, pt, v );
   11114                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZM, 34, 35, 12, 13 ) );
   11115                 :            : 
   11116                 :            :   //move 4d point in 2d line
   11117                 :          2 :   l25.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
   11118                 :          1 :                  << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) );
   11119                 :          1 :   c25.clear();
   11120                 :          1 :   c25.addCurve( l25.clone() );
   11121                 :          1 :   QVERIFY( c25.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( QgsWkbTypes::PointZM, 3, 4, 2, 3 ) ) );
   11122                 :          1 :   c25.pointAt( 0, pt, v );
   11123                 :          1 :   QCOMPARE( pt, QgsPoint( 3, 4 ) );
   11124                 :            : 
   11125                 :            :   //delete vertex
   11126                 :            : 
   11127                 :            :   //empty line
   11128                 :          1 :   QgsCompoundCurve c26;
   11129                 :          1 :   QgsCircularString l26;
   11130                 :          1 :   QVERIFY( !c26.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
   11131                 :          1 :   QVERIFY( c26.isEmpty() );
   11132                 :            : 
   11133                 :            :   //valid line
   11134                 :          2 :   l26.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 )
   11135                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 )
   11136                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 21, 22, 6, 7 )
   11137                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 31, 32, 6, 7 ) );
   11138                 :          1 :   c26.addCurve( l26.clone() );
   11139                 :            :   //out of range vertices
   11140                 :          1 :   QVERIFY( !c26.deleteVertex( QgsVertexId( 0, 0, -1 ) ) );
   11141                 :          1 :   QVERIFY( !c26.deleteVertex( QgsVertexId( 0, 0, 100 ) ) );
   11142                 :            : 
   11143                 :            :   //valid vertices
   11144                 :          1 :   QVERIFY( c26.deleteVertex( QgsVertexId( 0, 0, 1 ) ) );
   11145                 :          1 :   QCOMPARE( c26.numPoints(), 2 );
   11146                 :          1 :   c26.pointAt( 0, pt, v );
   11147                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 ) );
   11148                 :          1 :   c26.pointAt( 1, pt, v );
   11149                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZM, 31, 32, 6, 7 ) );
   11150                 :            : 
   11151                 :            :   //removing the next vertex removes all remaining vertices
   11152                 :          1 :   QVERIFY( c26.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
   11153                 :          1 :   QCOMPARE( c26.numPoints(), 0 );
   11154                 :          1 :   QVERIFY( c26.isEmpty() );
   11155                 :            : 
   11156                 :            :   // two lines
   11157                 :          1 :   QgsLineString ls26;
   11158                 :          1 :   c26.clear();
   11159                 :          2 :   ls26.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 )
   11160                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 ) );
   11161                 :          1 :   c26.addCurve( ls26.clone() );
   11162                 :          2 :   ls26.setPoints( QgsPointSequence()
   11163                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 )
   11164                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 21, 32, 4, 5 )
   11165                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 31, 42, 4, 5 ) );
   11166                 :          1 :   c26.addCurve( ls26.clone() );
   11167                 :          1 :   QVERIFY( c26.deleteVertex( QgsVertexId( 0, 0, 1 ) ) );
   11168                 :          1 :   QCOMPARE( c26.nCurves(), 1 );
   11169                 :          1 :   const QgsLineString *ls26r = dynamic_cast< const QgsLineString * >( c26.curveAt( 0 ) );
   11170                 :          1 :   QCOMPARE( ls26r->numPoints(), 2 );
   11171                 :          1 :   QCOMPARE( ls26r->startPoint(), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 ) );
   11172                 :          1 :   QCOMPARE( ls26r->endPoint(), QgsPoint( QgsWkbTypes::PointZM, 31, 42, 4, 5 ) );
   11173                 :            : 
   11174                 :            :   //add vertex at the end of linestring
   11175                 :          1 :   QVERIFY( c26.insertVertex( QgsVertexId( 0, 0, 2 ), QgsPoint( QgsWkbTypes::PointZM, 35, 43, 4, 5 ) ) );
   11176                 :          1 :   ls26r = dynamic_cast< const QgsLineString * >( c26.curveAt( 0 ) );
   11177                 :          1 :   QCOMPARE( ls26r->numPoints(), 3 );
   11178                 :          1 :   QCOMPARE( ls26r->startPoint(), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 ) );
   11179                 :          1 :   QCOMPARE( ls26r->endPoint(), QgsPoint( QgsWkbTypes::PointZM, 35, 43, 4, 5 ) );
   11180                 :            : 
   11181                 :          1 :   c26.clear();
   11182                 :          2 :   ls26.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 )
   11183                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 )
   11184                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 21, 32, 4, 5 ) );
   11185                 :          1 :   c26.addCurve( ls26.clone() );
   11186                 :          2 :   ls26.setPoints( QgsPointSequence()
   11187                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 21, 32, 4, 5 )
   11188                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 31, 42, 4, 5 ) );
   11189                 :          1 :   c26.addCurve( ls26.clone() );
   11190                 :          1 :   QVERIFY( c26.deleteVertex( QgsVertexId( 0, 0, 2 ) ) );
   11191                 :          1 :   QCOMPARE( c26.nCurves(), 1 );
   11192                 :          1 :   ls26r = dynamic_cast< const QgsLineString * >( c26.curveAt( 0 ) );
   11193                 :          1 :   QCOMPARE( ls26r->numPoints(), 2 );
   11194                 :          1 :   QCOMPARE( ls26r->startPoint(), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 ) );
   11195                 :          1 :   QCOMPARE( ls26r->endPoint(), QgsPoint( QgsWkbTypes::PointZM, 31, 42, 4, 5 ) );
   11196                 :            : 
   11197                 :            :   //reversed
   11198                 :          1 :   QgsCompoundCurve c27;
   11199                 :          1 :   QgsCircularString l27;
   11200                 :          1 :   std::unique_ptr< QgsCompoundCurve > reversed( c27.reversed() );
   11201                 :          1 :   QVERIFY( reversed->isEmpty() );
   11202                 :          2 :   l27.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 )
   11203                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 )
   11204                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 21, 22, 6, 7 ) );
   11205                 :          1 :   c27.addCurve( l27.clone() );
   11206                 :          1 :   QgsLineString ls27;
   11207                 :          2 :   ls27.setPoints( QgsPointSequence()
   11208                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 21, 22, 6, 7 )
   11209                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 23, 32, 7, 8 ) );
   11210                 :          1 :   c27.addCurve( ls27.clone() );
   11211                 :            : 
   11212                 :          1 :   reversed.reset( c27.reversed() );
   11213                 :          1 :   QCOMPARE( reversed->numPoints(), 4 );
   11214                 :          1 :   QVERIFY( dynamic_cast< const QgsLineString * >( reversed->curveAt( 0 ) ) );
   11215                 :          1 :   QVERIFY( dynamic_cast< const QgsCircularString * >( reversed->curveAt( 1 ) ) );
   11216                 :          1 :   QCOMPARE( reversed->wkbType(), QgsWkbTypes::CompoundCurveZM );
   11217                 :          1 :   QVERIFY( reversed->is3D() );
   11218                 :          1 :   QVERIFY( reversed->isMeasure() );
   11219                 :          1 :   reversed->pointAt( 0, pt, v );
   11220                 :          1 :   reversed->pointAt( 1, pt, v );
   11221                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZM, 21, 22, 6, 7 ) );
   11222                 :          1 :   reversed->pointAt( 2, pt, v );
   11223                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 ) );
   11224                 :          1 :   reversed->pointAt( 3, pt, v );
   11225                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 ) );
   11226                 :            : 
   11227                 :            :   //addZValue
   11228                 :          1 :   QgsCompoundCurve c28;
   11229                 :          1 :   QgsCircularString l28;
   11230                 :          1 :   QCOMPARE( c28.wkbType(), QgsWkbTypes::CompoundCurve );
   11231                 :          1 :   QVERIFY( c28.addZValue() );
   11232                 :          1 :   QCOMPARE( c28.wkbType(), QgsWkbTypes::CompoundCurveZ );
   11233                 :          1 :   c28.clear();
   11234                 :            :   //2d line
   11235                 :          1 :   l28.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
   11236                 :          1 :   c28.addCurve( l28.clone() );
   11237                 :          1 :   l28.setPoints( QgsPointSequence() << QgsPoint( 11, 12 ) << QgsPoint( 3, 4 ) );
   11238                 :          1 :   c28.addCurve( l28.clone() );
   11239                 :          1 :   QVERIFY( c28.addZValue( 2 ) );
   11240                 :          1 :   QVERIFY( c28.is3D() );
   11241                 :          1 :   QCOMPARE( c28.wkbType(), QgsWkbTypes::CompoundCurveZ );
   11242                 :          1 :   c28.pointAt( 0, pt, v );
   11243                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ) );
   11244                 :          1 :   c28.pointAt( 1, pt, v );
   11245                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZ, 11, 12, 2 ) );
   11246                 :          1 :   c28.pointAt( 2, pt, v );
   11247                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZ, 3, 4, 2 ) );
   11248                 :            : 
   11249                 :          1 :   QVERIFY( !c28.addZValue( 4 ) ); //already has z value, test that existing z is unchanged
   11250                 :          1 :   c28.pointAt( 0, pt, v );
   11251                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZ, 1, 2, 2 ) );
   11252                 :          1 :   c28.pointAt( 1, pt, v );
   11253                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZ, 11, 12, 2 ) );
   11254                 :          1 :   c28.pointAt( 2, pt, v );
   11255                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZ, 3, 4, 2 ) );
   11256                 :            : 
   11257                 :            :   //linestring with m
   11258                 :          1 :   l28.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 3 ) << QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 4 ) );
   11259                 :          1 :   c28.clear();
   11260                 :          1 :   c28.addCurve( l28.clone() );
   11261                 :          1 :   l28.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 21, 32, 0, 4 ) );
   11262                 :          1 :   c28.addCurve( l28.clone() );
   11263                 :          1 :   QVERIFY( c28.addZValue( 5 ) );
   11264                 :          1 :   QVERIFY( c28.is3D() );
   11265                 :          1 :   QVERIFY( c28.isMeasure() );
   11266                 :          1 :   QCOMPARE( c28.wkbType(), QgsWkbTypes::CompoundCurveZM );
   11267                 :          1 :   c28.pointAt( 0, pt, v );
   11268                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZM, 1, 2, 5, 3 ) );
   11269                 :          1 :   c28.pointAt( 1, pt, v );
   11270                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZM, 11, 12, 5, 4 ) );
   11271                 :          1 :   c28.pointAt( 2, pt, v );
   11272                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZM, 21, 32, 5, 4 ) );
   11273                 :            : 
   11274                 :            :   //addMValue
   11275                 :          1 :   c28.clear();
   11276                 :            :   //2d line
   11277                 :          1 :   l28.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
   11278                 :          1 :   c28.addCurve( l28.clone() );
   11279                 :          1 :   l28.setPoints( QgsPointSequence() << QgsPoint( 11, 12 ) << QgsPoint( 3, 4 ) );
   11280                 :          1 :   c28.addCurve( l28.clone() );
   11281                 :          1 :   QVERIFY( c28.addMValue( 2 ) );
   11282                 :          1 :   QVERIFY( c28.isMeasure() );
   11283                 :          1 :   QCOMPARE( c28.wkbType(), QgsWkbTypes::CompoundCurveM );
   11284                 :          1 :   c28.pointAt( 0, pt, v );
   11285                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 2 ) );
   11286                 :          1 :   c28.pointAt( 1, pt, v );
   11287                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 2 ) );
   11288                 :          1 :   c28.pointAt( 2, pt, v );
   11289                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointM, 3, 4, 0, 2 ) );
   11290                 :            : 
   11291                 :          1 :   QVERIFY( !c28.addMValue( 4 ) ); //already has z value, test that existing z is unchanged
   11292                 :          1 :   c28.pointAt( 0, pt, v );
   11293                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 2 ) );
   11294                 :          1 :   c28.pointAt( 1, pt, v );
   11295                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 2 ) );
   11296                 :          1 :   c28.pointAt( 2, pt, v );
   11297                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointM, 3, 4, 0, 2 ) );
   11298                 :            : 
   11299                 :            :   //linestring with z
   11300                 :          1 :   l28.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 11, 12, 4 ) );
   11301                 :          1 :   c28.clear();
   11302                 :          1 :   c28.addCurve( l28.clone() );
   11303                 :          1 :   l28.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 11, 12, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 21, 32, 4 ) );
   11304                 :          1 :   c28.addCurve( l28.clone() );
   11305                 :          1 :   QVERIFY( c28.addMValue( 5 ) );
   11306                 :          1 :   QVERIFY( c28.is3D() );
   11307                 :          1 :   QVERIFY( c28.isMeasure() );
   11308                 :          1 :   QCOMPARE( c28.wkbType(), QgsWkbTypes::CompoundCurveZM );
   11309                 :          1 :   c28.pointAt( 0, pt, v );
   11310                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 5 ) );
   11311                 :          1 :   c28.pointAt( 1, pt, v );
   11312                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 ) );
   11313                 :          1 :   c28.pointAt( 2, pt, v );
   11314                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZM, 21, 32, 4, 5 ) );
   11315                 :            : 
   11316                 :            :   //dropZValue
   11317                 :          1 :   QgsCompoundCurve c28d;
   11318                 :          1 :   QgsCircularString l28d;
   11319                 :          1 :   QVERIFY( !c28d.dropZValue() );
   11320                 :          1 :   l28d.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
   11321                 :          1 :   c28d.addCurve( l28d.clone() );
   11322                 :          1 :   l28d.setPoints( QgsPointSequence() << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) );
   11323                 :          1 :   c28d.addCurve( l28d.clone() );
   11324                 :          1 :   QVERIFY( !c28d.dropZValue() );
   11325                 :          1 :   c28d.addZValue( 1.0 );
   11326                 :          1 :   QCOMPARE( c28d.wkbType(), QgsWkbTypes::CompoundCurveZ );
   11327                 :          1 :   QVERIFY( c28d.is3D() );
   11328                 :          1 :   QVERIFY( c28d.dropZValue() );
   11329                 :          1 :   QVERIFY( !c28d.is3D() );
   11330                 :          1 :   QCOMPARE( c28d.wkbType(), QgsWkbTypes::CompoundCurve );
   11331                 :          1 :   c28d.pointAt( 0, pt, v );
   11332                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::Point, 1, 2 ) );
   11333                 :          1 :   c28d.pointAt( 1, pt, v );
   11334                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::Point, 11, 12 ) );
   11335                 :          1 :   c28d.pointAt( 2, pt, v );
   11336                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::Point, 21, 22 ) );
   11337                 :            : 
   11338                 :          1 :   QVERIFY( !c28d.dropZValue() ); //already dropped
   11339                 :            :   //linestring with m
   11340                 :          1 :   l28d.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 3, 4 ) );
   11341                 :          1 :   c28d.clear();
   11342                 :          1 :   c28d.addCurve( l28d.clone() );
   11343                 :          1 :   l28d.setPoints( QgsPointSequence() <<  QgsPoint( QgsWkbTypes::PointZM, 11, 12, 3, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 21, 22, 3, 4 ) );
   11344                 :          1 :   c28d.addCurve( l28d.clone() );
   11345                 :          1 :   QVERIFY( c28d.dropZValue() );
   11346                 :          1 :   QVERIFY( !c28d.is3D() );
   11347                 :          1 :   QVERIFY( c28d.isMeasure() );
   11348                 :          1 :   QCOMPARE( c28d.wkbType(), QgsWkbTypes::CompoundCurveM );
   11349                 :          1 :   c28d.pointAt( 0, pt, v );
   11350                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) );
   11351                 :          1 :   c28d.pointAt( 1, pt, v );
   11352                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 4 ) );
   11353                 :          1 :   c28d.pointAt( 2, pt, v );
   11354                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointM, 21, 22, 0, 4 ) );
   11355                 :            : 
   11356                 :            :   //dropMValue
   11357                 :          1 :   c28d.clear();
   11358                 :          1 :   QVERIFY( !c28d.dropMValue() );
   11359                 :          1 :   l28d.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
   11360                 :          1 :   c28d.addCurve( l28d.clone() );
   11361                 :          1 :   l28d.setPoints( QgsPointSequence() << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) );
   11362                 :          1 :   c28d.addCurve( l28d.clone() );
   11363                 :          1 :   QVERIFY( !c28d.dropMValue() );
   11364                 :          1 :   c28d.addMValue( 1.0 );
   11365                 :          1 :   QCOMPARE( c28d.wkbType(), QgsWkbTypes::CompoundCurveM );
   11366                 :          1 :   QVERIFY( c28d.isMeasure() );
   11367                 :          1 :   QVERIFY( c28d.dropMValue() );
   11368                 :          1 :   QVERIFY( !c28d.isMeasure() );
   11369                 :          1 :   QCOMPARE( c28d.wkbType(), QgsWkbTypes::CompoundCurve );
   11370                 :          1 :   c28d.pointAt( 0, pt, v );
   11371                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::Point, 1, 2 ) );
   11372                 :          1 :   c28d.pointAt( 1, pt, v );
   11373                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::Point, 11, 12 ) );
   11374                 :          1 :   c28d.pointAt( 2, pt, v );
   11375                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::Point, 21, 22 ) );
   11376                 :            : 
   11377                 :          1 :   QVERIFY( !c28d.dropMValue() ); //already dropped
   11378                 :            :   //linestring with z
   11379                 :          1 :   l28d.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 3, 4 ) );
   11380                 :          1 :   c28d.clear();
   11381                 :          1 :   c28d.addCurve( l28d.clone() );
   11382                 :          1 :   l28d.setPoints( QgsPointSequence() <<  QgsPoint( QgsWkbTypes::PointZM, 11, 12, 3, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 21, 22, 3, 4 ) );
   11383                 :          1 :   c28d.addCurve( l28d.clone() );
   11384                 :          1 :   QVERIFY( c28d.dropMValue() );
   11385                 :          1 :   QVERIFY( !c28d.isMeasure() );
   11386                 :          1 :   QVERIFY( c28d.is3D() );
   11387                 :          1 :   QCOMPARE( c28d.wkbType(), QgsWkbTypes::CompoundCurveZ );
   11388                 :          1 :   c28d.pointAt( 0, pt, v );
   11389                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) );
   11390                 :          1 :   c28d.pointAt( 1, pt, v );
   11391                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZ, 11, 12, 3 ) );
   11392                 :          1 :   c28d.pointAt( 2, pt, v );
   11393                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZ, 21, 22, 3 ) );
   11394                 :            : 
   11395                 :            :   //convertTo
   11396                 :          1 :   l28d.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
   11397                 :          1 :   c28d.clear();
   11398                 :          1 :   c28d.addCurve( l28d.clone() );
   11399                 :          1 :   QVERIFY( c28d.convertTo( QgsWkbTypes::CompoundCurve ) );
   11400                 :          1 :   QCOMPARE( c28d.wkbType(), QgsWkbTypes::CompoundCurve );
   11401                 :          1 :   QVERIFY( c28d.convertTo( QgsWkbTypes::CompoundCurveZ ) );
   11402                 :          1 :   QCOMPARE( c28d.wkbType(), QgsWkbTypes::CompoundCurveZ );
   11403                 :          1 :   c28d.pointAt( 0, pt, v );
   11404                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZ, 1, 2 ) );
   11405                 :            : 
   11406                 :          1 :   QVERIFY( c28d.convertTo( QgsWkbTypes::CompoundCurveZM ) );
   11407                 :          1 :   QCOMPARE( c28d.wkbType(), QgsWkbTypes::CompoundCurveZM );
   11408                 :          1 :   c28d.pointAt( 0, pt, v );
   11409                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZM, 1, 2 ) );
   11410                 :          1 :   c28d.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 1, 2, 5 ) );
   11411                 :          1 :   c28d.pointAt( 0, pt, v );
   11412                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZM, 1, 2, 5.0 ) );
   11413                 :          1 :   QVERIFY( c28d.convertTo( QgsWkbTypes::CompoundCurveM ) );
   11414                 :          1 :   QCOMPARE( c28d.wkbType(), QgsWkbTypes::CompoundCurveM );
   11415                 :          1 :   c28d.pointAt( 0, pt, v );
   11416                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointM, 1, 2 ) );
   11417                 :          1 :   c28d.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 1, 2, 0, 6 ) );
   11418                 :          1 :   c28d.pointAt( 0, pt, v );
   11419                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointM, 1, 2, 0.0, 6.0 ) );
   11420                 :          1 :   QVERIFY( c28d.convertTo( QgsWkbTypes::CompoundCurve ) );
   11421                 :          1 :   QCOMPARE( c28d.wkbType(), QgsWkbTypes::CompoundCurve );
   11422                 :          1 :   c28d.pointAt( 0, pt, v );
   11423                 :          1 :   QCOMPARE( pt, QgsPoint( 1, 2 ) );
   11424                 :          1 :   QVERIFY( !c28d.convertTo( QgsWkbTypes::Polygon ) );
   11425                 :            : 
   11426                 :            :   //isRing
   11427                 :          1 :   QgsCircularString l30;
   11428                 :          1 :   QgsCompoundCurve c30;
   11429                 :          1 :   QVERIFY( !c30.isRing() );
   11430                 :          1 :   l30.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 2 ) );
   11431                 :          1 :   c30.addCurve( l30.clone() );
   11432                 :          1 :   QVERIFY( !c30.isRing() ); //<4 points
   11433                 :          1 :   l30.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) << QgsPoint( 31, 32 ) );
   11434                 :          1 :   c30.clear();
   11435                 :          1 :   c30.addCurve( l30.clone() );
   11436                 :          1 :   QVERIFY( !c30.isRing() ); //not closed
   11437                 :          1 :   l30.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) << QgsPoint( 1, 2 ) );
   11438                 :          1 :   c30.clear();
   11439                 :          1 :   c30.addCurve( l30.clone() );
   11440                 :          1 :   QVERIFY( c30.isRing() );
   11441                 :          1 :   l30.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
   11442                 :          1 :   c30.clear();
   11443                 :          1 :   c30.addCurve( l30.clone() );
   11444                 :          1 :   QVERIFY( !c30.isRing() );
   11445                 :          1 :   l30.setPoints( QgsPointSequence() << QgsPoint( 11, 12 )  << QgsPoint( 21, 22 ) );
   11446                 :          1 :   c30.addCurve( l30.clone() );
   11447                 :          1 :   QVERIFY( !c30.isRing() );
   11448                 :          1 :   l30.setPoints( QgsPointSequence() << QgsPoint( 21, 22 )  << QgsPoint( 1, 2 ) );
   11449                 :          1 :   c30.addCurve( l30.clone() );
   11450                 :          1 :   QVERIFY( c30.isRing() );
   11451                 :            : 
   11452                 :            :   //coordinateSequence
   11453                 :          1 :   QgsCompoundCurve c31;
   11454                 :          1 :   QgsCircularString l31;
   11455                 :          1 :   QgsCoordinateSequence coords = c31.coordinateSequence();
   11456                 :          1 :   QCOMPARE( coords.count(), 1 );
   11457                 :          1 :   QCOMPARE( coords.at( 0 ).count(), 1 );
   11458                 :          1 :   QVERIFY( coords.at( 0 ).at( 0 ).isEmpty() );
   11459                 :          2 :   l31.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 )
   11460                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 )
   11461                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 21, 22, 6, 7 ) );
   11462                 :          1 :   c31.addCurve( l31.clone() );
   11463                 :          1 :   QgsLineString ls31;
   11464                 :          2 :   ls31.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 21, 22, 6, 7 ) <<
   11465                 :          1 :                   QgsPoint( QgsWkbTypes::PointZM, 31, 32, 16, 17 ) );
   11466                 :          1 :   c31.addCurve( ls31.clone() );
   11467                 :          1 :   coords = c31.coordinateSequence();
   11468                 :          1 :   QCOMPARE( coords.count(), 1 );
   11469                 :          1 :   QCOMPARE( coords.at( 0 ).count(), 1 );
   11470                 :          1 :   QCOMPARE( coords.at( 0 ).at( 0 ).count(), 4 );
   11471                 :          1 :   QCOMPARE( coords.at( 0 ).at( 0 ).at( 0 ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 2, 3 ) );
   11472                 :          1 :   QCOMPARE( coords.at( 0 ).at( 0 ).at( 1 ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 4, 5 ) );
   11473                 :          1 :   QCOMPARE( coords.at( 0 ).at( 0 ).at( 2 ), QgsPoint( QgsWkbTypes::PointZM, 21, 22, 6, 7 ) );
   11474                 :          1 :   QCOMPARE( coords.at( 0 ).at( 0 ).at( 3 ), QgsPoint( QgsWkbTypes::PointZM, 31, 32, 16, 17 ) );
   11475                 :            : 
   11476                 :            :   //nextVertex
   11477                 :          1 :   QgsCompoundCurve c32;
   11478                 :          1 :   QgsCircularString l32;
   11479                 :          1 :   QgsVertexId vId;
   11480                 :          1 :   QVERIFY( !c32.nextVertex( vId, p ) );
   11481                 :          1 :   vId = QgsVertexId( 0, 0, -2 );
   11482                 :          1 :   QVERIFY( !c32.nextVertex( vId, p ) );
   11483                 :          1 :   vId = QgsVertexId( 0, 0, 10 );
   11484                 :          1 :   QVERIFY( !c32.nextVertex( vId, p ) );
   11485                 :            :   //CircularString
   11486                 :          1 :   l32.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
   11487                 :          1 :   c32.addCurve( l32.clone() );
   11488                 :          1 :   vId = QgsVertexId( 0, 0, 2 ); //out of range
   11489                 :          1 :   QVERIFY( !c32.nextVertex( vId, p ) );
   11490                 :          1 :   vId = QgsVertexId( 0, 0, -5 );
   11491                 :          1 :   QVERIFY( c32.nextVertex( vId, p ) );
   11492                 :          1 :   vId = QgsVertexId( 0, 0, -1 );
   11493                 :          1 :   QVERIFY( c32.nextVertex( vId, p ) );
   11494                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 0, 0 ) );
   11495                 :          1 :   QCOMPARE( p, QgsPoint( 1, 2 ) );
   11496                 :          1 :   QVERIFY( c32.nextVertex( vId, p ) );
   11497                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 0, 1 ) );
   11498                 :          1 :   QCOMPARE( p, QgsPoint( 11, 12 ) );
   11499                 :          1 :   QVERIFY( !c32.nextVertex( vId, p ) );
   11500                 :          1 :   vId = QgsVertexId( 0, 1, 0 );
   11501                 :          1 :   QVERIFY( c32.nextVertex( vId, p ) );
   11502                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 1, 1 ) ); //test that ring number is maintained
   11503                 :          1 :   QCOMPARE( p, QgsPoint( 11, 12 ) );
   11504                 :          1 :   vId = QgsVertexId( 1, 0, 0 );
   11505                 :          1 :   QVERIFY( c32.nextVertex( vId, p ) );
   11506                 :          1 :   QCOMPARE( vId, QgsVertexId( 1, 0, 1 ) ); //test that part number is maintained
   11507                 :          1 :   QCOMPARE( p, QgsPoint( 11, 12 ) );
   11508                 :          1 :   QgsLineString ls32;
   11509                 :          1 :   ls32.setPoints( QgsPointSequence() << QgsPoint( 11, 12 ) << QgsPoint( 13, 14 ) );
   11510                 :          1 :   c32.addCurve( ls32.clone() );
   11511                 :          1 :   vId = QgsVertexId( 0, 0, 1 );
   11512                 :          1 :   QVERIFY( c32.nextVertex( vId, p ) );
   11513                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 0, 2 ) );
   11514                 :          1 :   QCOMPARE( p, QgsPoint( 13, 14 ) );
   11515                 :          1 :   QVERIFY( !c32.nextVertex( vId, p ) );
   11516                 :            : 
   11517                 :            :   //CircularStringZ
   11518                 :          1 :   l32.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 ) );
   11519                 :          1 :   c32.clear();
   11520                 :          1 :   c32.addCurve( l32.clone() );
   11521                 :          1 :   vId = QgsVertexId( 0, 0, -1 );
   11522                 :          1 :   QVERIFY( c32.nextVertex( vId, p ) );
   11523                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 0, 0 ) );
   11524                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) );
   11525                 :          1 :   QVERIFY( c32.nextVertex( vId, p ) );
   11526                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 0, 1 ) );
   11527                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 ) );
   11528                 :          1 :   QVERIFY( !c32.nextVertex( vId, p ) );
   11529                 :            :   //CircularStringM
   11530                 :          1 :   l32.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 14 ) );
   11531                 :          1 :   c32.clear();
   11532                 :          1 :   c32.addCurve( l32.clone() );
   11533                 :          1 :   vId = QgsVertexId( 0, 0, -1 );
   11534                 :          1 :   QVERIFY( c32.nextVertex( vId, p ) );
   11535                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 0, 0 ) );
   11536                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) );
   11537                 :          1 :   QVERIFY( c32.nextVertex( vId, p ) );
   11538                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 0, 1 ) );
   11539                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 14 ) );
   11540                 :          1 :   QVERIFY( !c32.nextVertex( vId, p ) );
   11541                 :            :   //CircularStringZM
   11542                 :          1 :   l32.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
   11543                 :          1 :   c32.clear();
   11544                 :          1 :   c32.addCurve( l32.clone() );
   11545                 :          1 :   vId = QgsVertexId( 0, 0, -1 );
   11546                 :          1 :   QVERIFY( c32.nextVertex( vId, p ) );
   11547                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 0, 0 ) );
   11548                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) );
   11549                 :          1 :   QVERIFY( c32.nextVertex( vId, p ) );
   11550                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 0, 1 ) );
   11551                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
   11552                 :          1 :   QVERIFY( !c32.nextVertex( vId, p ) );
   11553                 :            : 
   11554                 :            :   //vertexAt and pointAt
   11555                 :          1 :   QgsCompoundCurve c33;
   11556                 :          1 :   QgsCircularString l33;
   11557                 :          1 :   c33.vertexAt( QgsVertexId( 0, 0, -10 ) ); //out of bounds, check for no crash
   11558                 :          1 :   c33.vertexAt( QgsVertexId( 0, 0, 10 ) ); //out of bounds, check for no crash
   11559                 :          1 :   QVERIFY( !c33.pointAt( -10, p, type ) );
   11560                 :          1 :   QVERIFY( !c33.pointAt( 10, p, type ) );
   11561                 :            :   //CircularString
   11562                 :          1 :   l33.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 22 ) );
   11563                 :          1 :   c33.addCurve( l33.clone() );
   11564                 :          1 :   c33.vertexAt( QgsVertexId( 0, 0, -10 ) );
   11565                 :          1 :   c33.vertexAt( QgsVertexId( 0, 0, 10 ) ); //out of bounds, check for no crash
   11566                 :          1 :   QCOMPARE( c33.vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( 1, 2 ) );
   11567                 :          1 :   QCOMPARE( c33.vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( 11, 12 ) );
   11568                 :          1 :   QCOMPARE( c33.vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( 1, 22 ) );
   11569                 :          1 :   QVERIFY( !c33.pointAt( -10, p, type ) );
   11570                 :          1 :   QVERIFY( !c33.pointAt( 10, p, type ) );
   11571                 :          1 :   QVERIFY( c33.pointAt( 0, p, type ) );
   11572                 :          1 :   QCOMPARE( p, QgsPoint( 1, 2 ) );
   11573                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
   11574                 :          1 :   QVERIFY( c33.pointAt( 1, p, type ) );
   11575                 :          1 :   QCOMPARE( p, QgsPoint( 11, 12 ) );
   11576                 :          1 :   QCOMPARE( type, QgsVertexId::CurveVertex );
   11577                 :          1 :   QVERIFY( c33.pointAt( 2, p, type ) );
   11578                 :          1 :   QCOMPARE( p, QgsPoint( 1, 22 ) );
   11579                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
   11580                 :          1 :   QgsLineString ls33;
   11581                 :          1 :   ls33.setPoints( QgsPointSequence() << QgsPoint( 1, 22 ) << QgsPoint( 3, 34 ) );
   11582                 :          1 :   c33.addCurve( ls33.clone() );
   11583                 :          1 :   QVERIFY( c33.pointAt( 3, p, type ) );
   11584                 :          1 :   QCOMPARE( p, QgsPoint( 3, 34 ) );
   11585                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
   11586                 :            : 
   11587                 :          1 :   c33.clear();
   11588                 :            :   //CircularStringZ
   11589                 :          1 :   l33.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 )  << QgsPoint( QgsWkbTypes::PointZ, 1, 22, 23 ) );
   11590                 :          1 :   c33.addCurve( l33.clone() );
   11591                 :          1 :   QCOMPARE( c33.vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) );
   11592                 :          1 :   QCOMPARE( c33.vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 ) );
   11593                 :          1 :   QCOMPARE( c33.vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( QgsWkbTypes::PointZ, 1, 22, 23 ) );
   11594                 :          1 :   QVERIFY( c33.pointAt( 0, p, type ) );
   11595                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) );
   11596                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
   11597                 :          1 :   QVERIFY( c33.pointAt( 1, p, type ) );
   11598                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 ) );
   11599                 :          1 :   QCOMPARE( type, QgsVertexId::CurveVertex );
   11600                 :          1 :   QVERIFY( c33.pointAt( 2, p, type ) );
   11601                 :          1 :   QCOMPARE( p, QgsPoint( 1, 22, 23 ) );
   11602                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
   11603                 :            : 
   11604                 :            :   //CircularStringM
   11605                 :          1 :   c33.clear();
   11606                 :          1 :   l33.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 14 ) << QgsPoint( QgsWkbTypes::PointM, 1, 22, 0, 24 ) );
   11607                 :          1 :   c33.addCurve( l33.clone() );
   11608                 :          1 :   QCOMPARE( c33.vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) );
   11609                 :          1 :   QCOMPARE( c33.vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 14 ) );
   11610                 :          1 :   QCOMPARE( c33.vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( QgsWkbTypes::PointM, 1, 22, 0, 24 ) );
   11611                 :          1 :   QVERIFY( c33.pointAt( 0, p, type ) );
   11612                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) );
   11613                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
   11614                 :          1 :   QVERIFY( c33.pointAt( 1, p, type ) );
   11615                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 14 ) );
   11616                 :          1 :   QCOMPARE( type, QgsVertexId::CurveVertex );
   11617                 :          1 :   QVERIFY( c33.pointAt( 2, p, type ) );
   11618                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointM, 1, 22, 0, 24 ) );
   11619                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
   11620                 :            :   //CircularStringZM
   11621                 :          1 :   l33.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) << QgsPoint( QgsWkbTypes::PointZM, 1, 22, 23, 24 ) );
   11622                 :          1 :   c33.clear();
   11623                 :          1 :   c33.addCurve( l33.clone() );
   11624                 :          1 :   QCOMPARE( c33.vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) );
   11625                 :          1 :   QCOMPARE( c33.vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
   11626                 :          1 :   QCOMPARE( c33.vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( QgsWkbTypes::PointZM, 1, 22, 23, 24 ) );
   11627                 :          1 :   QVERIFY( c33.pointAt( 0, p, type ) );
   11628                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) );
   11629                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
   11630                 :          1 :   QVERIFY( c33.pointAt( 1, p, type ) );
   11631                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 ) );
   11632                 :          1 :   QCOMPARE( type, QgsVertexId::CurveVertex );
   11633                 :          1 :   QVERIFY( c33.pointAt( 2, p, type ) );
   11634                 :          1 :   QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZM, 1, 22, 23, 24 ) );
   11635                 :          1 :   QCOMPARE( type, QgsVertexId::SegmentVertex );
   11636                 :            : 
   11637                 :            :   //centroid
   11638                 :          1 :   QgsCircularString l34;
   11639                 :          1 :   QgsCompoundCurve c34;
   11640                 :          1 :   QCOMPARE( c34.centroid(), QgsPoint( 0, 0 ) );
   11641                 :          1 :   l34.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) );
   11642                 :          1 :   c34.addCurve( l34.clone() );
   11643                 :          1 :   QCOMPARE( c34.centroid(), QgsPoint( 5, 10 ) );
   11644                 :          1 :   l34.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 20, 10 ) << QgsPoint( 2, 9 ) );
   11645                 :          1 :   c34.clear();
   11646                 :          1 :   c34.addCurve( l34.clone() );
   11647                 :          1 :   QgsPoint centroid = c34.centroid();
   11648                 :          1 :   QGSCOMPARENEAR( centroid.x(), 7.333, 0.001 );
   11649                 :          1 :   QGSCOMPARENEAR( centroid.y(), 6.333, 0.001 );
   11650                 :          1 :   l34.setPoints( QgsPointSequence() << QgsPoint( 2, 9 ) << QgsPoint( 12, 9 ) << QgsPoint( 15, 19 ) );
   11651                 :          1 :   c34.addCurve( l34.clone() );
   11652                 :          1 :   centroid = c34.centroid();
   11653                 :          1 :   QGSCOMPARENEAR( centroid.x(), 9.756646, 0.001 );
   11654                 :          1 :   QGSCOMPARENEAR( centroid.y(), 8.229039, 0.001 );
   11655                 :            : 
   11656                 :            :   //closest segment
   11657                 :          1 :   QgsCompoundCurve c35;
   11658                 :          1 :   QgsCircularString l35;
   11659                 :          1 :   int leftOf = 0;
   11660                 :          1 :   p = QgsPoint( 0, 0 ); // reset all coords to zero
   11661                 :          1 :   ( void )c35.closestSegment( QgsPoint( 1, 2 ), p, vId ); //empty line, just want no crash
   11662                 :          1 :   l35.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) );
   11663                 :          1 :   c35.addCurve( l35.clone() );
   11664                 :          1 :   QVERIFY( c35.closestSegment( QgsPoint( 5, 10 ), p, vId ) < 0 );
   11665                 :          1 :   l35.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) << QgsPoint( 7, 12 ) << QgsPoint( 5, 15 ) );
   11666                 :          1 :   c35.clear();
   11667                 :          1 :   c35.addCurve( l35.clone() );
   11668                 :          1 :   QGSCOMPARENEAR( c35.closestSegment( QgsPoint( 4, 11 ), p, vId, &leftOf ), 2.0, 0.0001 );
   11669                 :          1 :   QCOMPARE( p, QgsPoint( 5, 10 ) );
   11670                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 0, 1 ) );
   11671                 :          1 :   QCOMPARE( leftOf, -1 );
   11672                 :          1 :   QGSCOMPARENEAR( c35.closestSegment( QgsPoint( 8, 11 ), p, vId, &leftOf ),  1.583512, 0.0001 );
   11673                 :          1 :   QGSCOMPARENEAR( p.x(), 6.84, 0.01 );
   11674                 :          1 :   QGSCOMPARENEAR( p.y(), 11.49, 0.01 );
   11675                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 0, 1 ) );
   11676                 :          1 :   QCOMPARE( leftOf, 1 );
   11677                 :          1 :   QGSCOMPARENEAR( c35.closestSegment( QgsPoint( 5.5, 11.5 ), p, vId, &leftOf ), 1.288897, 0.0001 );
   11678                 :          1 :   QGSCOMPARENEAR( p.x(), 6.302776, 0.01 );
   11679                 :          1 :   QGSCOMPARENEAR( p.y(), 10.7, 0.01 );
   11680                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 0, 1 ) );
   11681                 :          1 :   QCOMPARE( leftOf, -1 );
   11682                 :          1 :   QGSCOMPARENEAR( c35.closestSegment( QgsPoint( 7, 16 ), p, vId, &leftOf ), 3.068288, 0.0001 );
   11683                 :          1 :   QGSCOMPARENEAR( p.x(), 5.981872, 0.01 );
   11684                 :          1 :   QGSCOMPARENEAR( p.y(), 14.574621, 0.01 );
   11685                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 0, 2 ) );
   11686                 :          1 :   QCOMPARE( leftOf, 1 );
   11687                 :          1 :   QGSCOMPARENEAR( c35.closestSegment( QgsPoint( 5.5, 13.5 ), p, vId, &leftOf ), 1.288897, 0.0001 );
   11688                 :          1 :   QGSCOMPARENEAR( p.x(), 6.302776, 0.01 );
   11689                 :          1 :   QGSCOMPARENEAR( p.y(), 14.3, 0.01 );
   11690                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 0, 2 ) );
   11691                 :          1 :   QCOMPARE( leftOf, -1 );
   11692                 :            :   // point directly on segment
   11693                 :          1 :   QCOMPARE( c35.closestSegment( QgsPoint( 5, 15 ), p, vId, &leftOf ), 0.0 );
   11694                 :          1 :   QCOMPARE( p, QgsPoint( 5, 15 ) );
   11695                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 0, 2 ) );
   11696                 :          1 :   QCOMPARE( leftOf, 0 );
   11697                 :            : 
   11698                 :          1 :   QgsLineString ls35;
   11699                 :          1 :   ls35.setPoints( QgsPointSequence() << QgsPoint( 5, 15 ) << QgsPoint( 5, 20 ) );
   11700                 :          1 :   c35.addCurve( ls35.clone() );
   11701                 :          1 :   QGSCOMPARENEAR( c35.closestSegment( QgsPoint( 5.5, 16.5 ), p, vId, &leftOf ), 0.25, 0.0001 );
   11702                 :          1 :   QGSCOMPARENEAR( p.x(), 5.0, 0.01 );
   11703                 :          1 :   QGSCOMPARENEAR( p.y(), 16.5, 0.01 );
   11704                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 0, 3 ) );
   11705                 :          1 :   QCOMPARE( leftOf, 1 );
   11706                 :          1 :   QGSCOMPARENEAR( c35.closestSegment( QgsPoint( 4.5, 16.5 ), p, vId, &leftOf ), 0.25, 0.0001 );
   11707                 :          1 :   QGSCOMPARENEAR( p.x(), 5.0, 0.01 );
   11708                 :          1 :   QGSCOMPARENEAR( p.y(), 16.5, 0.01 );
   11709                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 0, 3 ) );
   11710                 :          1 :   QCOMPARE( leftOf, -1 );
   11711                 :          1 :   QGSCOMPARENEAR( c35.closestSegment( QgsPoint( 4.5, 21.5 ), p, vId, &leftOf ), 2.500000, 0.0001 );
   11712                 :          1 :   QGSCOMPARENEAR( p.x(), 5.0, 0.01 );
   11713                 :          1 :   QGSCOMPARENEAR( p.y(), 20.0, 0.01 );
   11714                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 0, 3 ) );
   11715                 :          1 :   QCOMPARE( leftOf, -1 );
   11716                 :          1 :   QGSCOMPARENEAR( c35.closestSegment( QgsPoint( 5.5, 21.5 ), p, vId, &leftOf ), 2.500000, 0.0001 );
   11717                 :          1 :   QGSCOMPARENEAR( p.x(), 5.0, 0.01 );
   11718                 :          1 :   QGSCOMPARENEAR( p.y(), 20.0, 0.01 );
   11719                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 0, 3 ) );
   11720                 :          1 :   QCOMPARE( leftOf, 1 );
   11721                 :          1 :   QGSCOMPARENEAR( c35.closestSegment( QgsPoint( 5, 20 ), p, vId, &leftOf ), 0.0000, 0.0001 );
   11722                 :          1 :   QGSCOMPARENEAR( p.x(), 5.0, 0.01 );
   11723                 :          1 :   QGSCOMPARENEAR( p.y(), 20.0, 0.01 );
   11724                 :          1 :   QCOMPARE( vId, QgsVertexId( 0, 0, 3 ) );
   11725                 :          1 :   QCOMPARE( leftOf, 0 );
   11726                 :            : 
   11727                 :            :   //sumUpArea
   11728                 :          1 :   QgsCompoundCurve c36;
   11729                 :          1 :   QgsCircularString l36;
   11730                 :          1 :   double area = 1.0; //sumUpArea adds to area, so start with non-zero value
   11731                 :          1 :   c36.sumUpArea( area );
   11732                 :          1 :   QCOMPARE( area, 1.0 );
   11733                 :          1 :   l36.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) );
   11734                 :          1 :   c36.addCurve( l36.clone() );
   11735                 :          1 :   c36.sumUpArea( area );
   11736                 :          1 :   QCOMPARE( area, 1.0 );
   11737                 :          1 :   l36.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) << QgsPoint( 10, 10 ) );
   11738                 :          1 :   c36.clear();
   11739                 :          1 :   c36.addCurve( l36.clone() );
   11740                 :          1 :   c36.sumUpArea( area );
   11741                 :          1 :   QCOMPARE( area, 1.0 );
   11742                 :          1 :   l36.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 2, 0 ) << QgsPoint( 2, 2 ) );
   11743                 :          1 :   c36.clear();
   11744                 :          1 :   c36.addCurve( l36.clone() );
   11745                 :          1 :   c36.sumUpArea( area );
   11746                 :          1 :   QGSCOMPARENEAR( area, 4.141593, 0.0001 );
   11747                 :          1 :   l36.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 2, 0 ) << QgsPoint( 2, 2 ) << QgsPoint( 0, 2 ) );
   11748                 :          1 :   c36.clear();
   11749                 :          1 :   c36.addCurve( l36.clone() );
   11750                 :          1 :   c36.sumUpArea( area );
   11751                 :          1 :   QGSCOMPARENEAR( area, 7.283185, 0.0001 );
   11752                 :            :   // full circle
   11753                 :          1 :   l36.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 4, 0 ) << QgsPoint( 0, 0 ) );
   11754                 :          1 :   c36.clear();
   11755                 :          1 :   c36.addCurve( l36.clone() );
   11756                 :          1 :   area = 0.0;
   11757                 :          1 :   c36.sumUpArea( area );
   11758                 :          1 :   QGSCOMPARENEAR( area, 12.566370614359172, 0.0001 );
   11759                 :            : 
   11760                 :            :   //boundingBox - test that bounding box is updated after every modification to the circular string
   11761                 :          1 :   QgsCompoundCurve c37;
   11762                 :          1 :   QgsCircularString l37;
   11763                 :          1 :   QVERIFY( c37.boundingBox().isNull() );
   11764                 :          1 :   l37.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) << QgsPoint( 10, 15 ) );
   11765                 :          1 :   c37.addCurve( l37.clone() );
   11766                 :          1 :   QCOMPARE( c37.boundingBox(), QgsRectangle( 5, 10, 10, 15 ) );
   11767                 :          1 :   l37.setPoints( QgsPointSequence() << QgsPoint( -5, -10 ) << QgsPoint( -6, -10 ) << QgsPoint( -5.5, -9 ) );
   11768                 :          1 :   c37.clear();
   11769                 :          1 :   c37.addCurve( l37.clone() );
   11770                 :          1 :   QCOMPARE( c37.boundingBox(), QgsRectangle( -6.125, -10.25, -5, -9 ) );
   11771                 :          1 :   QByteArray wkbToAppend = c37.asWkb();
   11772                 :          1 :   c37.clear();
   11773                 :          1 :   QVERIFY( c37.boundingBox().isNull() );
   11774                 :          1 :   QgsConstWkbPtr wkbToAppendPtr( wkbToAppend );
   11775                 :          1 :   l37.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) << QgsPoint( 10, 15 ) );
   11776                 :          1 :   c37.clear();
   11777                 :          1 :   c37.addCurve( l37.clone() );
   11778                 :          1 :   QCOMPARE( c37.boundingBox(), QgsRectangle( 5, 10, 10, 15 ) );
   11779                 :          1 :   c37.fromWkb( wkbToAppendPtr );
   11780                 :          1 :   QCOMPARE( c37.boundingBox(), QgsRectangle( -6.125, -10.25, -5, -9 ) );
   11781                 :          2 :   c37.fromWkt( QStringLiteral( "CompoundCurve(CircularString( 5 10, 6 10, 5.5 9 ))" ) );
   11782                 :          1 :   QCOMPARE( c37.boundingBox(), QgsRectangle( 5, 9, 6.125, 10.25 ) );
   11783                 :          1 :   c37.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( -1, 7 ) );
   11784                 :          1 :   QgsRectangle r = c37.boundingBox();
   11785                 :          1 :   QGSCOMPARENEAR( r.xMinimum(), -3.014, 0.01 );
   11786                 :          1 :   QGSCOMPARENEAR( r.xMaximum(), 14.014, 0.01 );
   11787                 :          1 :   QGSCOMPARENEAR( r.yMinimum(), -7.0146, 0.01 );
   11788                 :          1 :   QGSCOMPARENEAR( r.yMaximum(), 12.4988, 0.01 );
   11789                 :          1 :   c37.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( -3, 10 ) );
   11790                 :          1 :   r = c37.boundingBox();
   11791                 :          1 :   QGSCOMPARENEAR( r.xMinimum(), -10.294, 0.01 );
   11792                 :          1 :   QGSCOMPARENEAR( r.xMaximum(), 12.294, 0.01 );
   11793                 :          1 :   QGSCOMPARENEAR( r.yMinimum(), 9, 0.01 );
   11794                 :          1 :   QGSCOMPARENEAR( r.yMaximum(), 31.856, 0.01 );
   11795                 :          1 :   c37.deleteVertex( QgsVertexId( 0, 0, 1 ) );
   11796                 :          1 :   r = c37.boundingBox();
   11797                 :          1 :   QGSCOMPARENEAR( r.xMinimum(), 5, 0.01 );
   11798                 :          1 :   QGSCOMPARENEAR( r.xMaximum(), 6.125, 0.01 );
   11799                 :          1 :   QGSCOMPARENEAR( r.yMinimum(), 9, 0.01 );
   11800                 :          1 :   QGSCOMPARENEAR( r.yMaximum(), 10.25, 0.01 );
   11801                 :            : 
   11802                 :            :   //angle
   11803                 :          1 :   QgsCompoundCurve c38;
   11804                 :          1 :   QgsCircularString l38;
   11805                 :          1 :   ( void )c38.vertexAngle( QgsVertexId() ); //just want no crash
   11806                 :          1 :   ( void )c38.vertexAngle( QgsVertexId( 0, 0, 0 ) ); //just want no crash
   11807                 :          1 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) );
   11808                 :          1 :   c38.addCurve( l38.clone() );
   11809                 :          1 :   ( void )c38.vertexAngle( QgsVertexId( 0, 0, 0 ) ); //just want no crash, any answer is meaningless
   11810                 :          1 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) );
   11811                 :          1 :   c38.clear();
   11812                 :          1 :   c38.addCurve( l38.clone() );
   11813                 :          1 :   ( void )c38.vertexAngle( QgsVertexId( 0, 0, 0 ) ); //just want no crash, any answer is meaningless
   11814                 :          1 :   ( void )c38.vertexAngle( QgsVertexId( 0, 0, 1 ) ); //just want no crash, any answer is meaningless
   11815                 :          1 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 1 ) << QgsPoint( 0, 2 ) );
   11816                 :          1 :   c38.clear();
   11817                 :          1 :   c38.addCurve( l38.clone() );
   11818                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 1.5708, 0.0001 );
   11819                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 0, 0.0001 );
   11820                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 2 ) ), 4.712389, 0.0001 );
   11821                 :          1 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 2 ) << QgsPoint( 1, 1 ) << QgsPoint( 0, 0 ) );
   11822                 :          1 :   c38.clear();
   11823                 :          1 :   c38.addCurve( l38.clone() );
   11824                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 1.5708, 0.0001 );
   11825                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 3.141593, 0.0001 );
   11826                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 2 ) ), 4.712389, 0.0001 );
   11827                 :          1 :   ( void )c38.vertexAngle( QgsVertexId( 0, 0, 20 ) ); // no crash
   11828                 :          2 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 1 ) << QgsPoint( 0, 2 )
   11829                 :          1 :                  << QgsPoint( -1, 3 ) << QgsPoint( 0, 4 ) );
   11830                 :          1 :   c38.clear();
   11831                 :          1 :   c38.addCurve( l38.clone() );
   11832                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 1.5708, 0.0001 );
   11833                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 0, 0.0001 );
   11834                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 2 ) ), 4.712389, 0.0001 );
   11835                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 3 ) ), 0, 0.0001 );
   11836                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 4 ) ), 1.5708, 0.0001 );
   11837                 :          2 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 4 ) << QgsPoint( -1, 3 ) << QgsPoint( 0, 2 )
   11838                 :          1 :                  << QgsPoint( 1, 1 ) << QgsPoint( 0, 0 ) );
   11839                 :          1 :   c38.clear();
   11840                 :          1 :   c38.addCurve( l38.clone() );
   11841                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 4.712389, 0.0001 );
   11842                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 3.141592, 0.0001 );
   11843                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 2 ) ), 1.5708, 0.0001 );
   11844                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 3 ) ), 3.141592, 0.0001 );
   11845                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 4 ) ), 4.712389, 0.0001 );
   11846                 :            : 
   11847                 :            :   // with second curve
   11848                 :          1 :   QgsLineString ls38;
   11849                 :          1 :   ls38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, -1 ) );
   11850                 :          1 :   c38.addCurve( ls38.clone() );
   11851                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 4 ) ), 3.926991, 0.0001 );
   11852                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 5 ) ), 3.141593, 0.0001 );
   11853                 :            : 
   11854                 :            :   //closed circular string
   11855                 :          1 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 0, 0 ) );
   11856                 :          1 :   c38.clear();
   11857                 :          1 :   c38.addCurve( l38.clone() );
   11858                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 0, 0.00001 );
   11859                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 3.141592, 0.00001 );
   11860                 :          1 :   QGSCOMPARENEAR( c38.vertexAngle( QgsVertexId( 0, 0, 2 ) ), 0, 0.00001 );
   11861                 :            : 
   11862                 :            :   //removing a vertex from a 3 point comound curveshould remove the whole line
   11863                 :          1 :   QgsCircularString l39;
   11864                 :          1 :   QgsCompoundCurve c39;
   11865                 :          1 :   l39.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 1 ) << QgsPoint( 0, 2 ) );
   11866                 :          1 :   c39.addCurve( l39.clone() );
   11867                 :          1 :   QCOMPARE( c39.numPoints(), 3 );
   11868                 :          1 :   c39.deleteVertex( QgsVertexId( 0, 0, 2 ) );
   11869                 :          1 :   QCOMPARE( c39.numPoints(), 0 );
   11870                 :            : 
   11871                 :            :   //boundary
   11872                 :          1 :   QgsCompoundCurve cBoundary1;
   11873                 :          1 :   QgsCircularString boundary1;
   11874                 :          1 :   QVERIFY( !cBoundary1.boundary() );
   11875                 :          1 :   boundary1.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 ) );
   11876                 :          1 :   cBoundary1.addCurve( boundary1.clone() );
   11877                 :          1 :   QgsAbstractGeometry *boundary = cBoundary1.boundary();
   11878                 :          1 :   QgsMultiPoint *mpBoundary = dynamic_cast< QgsMultiPoint * >( boundary );
   11879                 :          1 :   QVERIFY( mpBoundary );
   11880                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->x(), 0.0 );
   11881                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->y(), 0.0 );
   11882                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->x(), 1.0 );
   11883                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->y(), 1.0 );
   11884                 :          1 :   delete boundary;
   11885                 :            : 
   11886                 :            :   // closed string = no boundary
   11887                 :          1 :   boundary1.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 ) << QgsPoint( 0, 0 ) );
   11888                 :          1 :   cBoundary1.clear();
   11889                 :          1 :   cBoundary1.addCurve( boundary1.clone() );
   11890                 :          1 :   QVERIFY( !cBoundary1.boundary() );
   11891                 :            : 
   11892                 :            :   //boundary with z
   11893                 :          1 :   boundary1.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 10 ) << QgsPoint( QgsWkbTypes::PointZ, 1, 0, 15 ) << QgsPoint( QgsWkbTypes::PointZ, 1, 1, 20 ) );
   11894                 :          1 :   cBoundary1.clear();
   11895                 :          1 :   cBoundary1.addCurve( boundary1.clone() );
   11896                 :          1 :   boundary = cBoundary1.boundary();
   11897                 :          1 :   mpBoundary = dynamic_cast< QgsMultiPoint * >( boundary );
   11898                 :          1 :   QVERIFY( mpBoundary );
   11899                 :          1 :   QCOMPARE( mpBoundary->geometryN( 0 )->wkbType(), QgsWkbTypes::PointZ );
   11900                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->x(), 0.0 );
   11901                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->y(), 0.0 );
   11902                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->z(), 10.0 );
   11903                 :          1 :   QCOMPARE( mpBoundary->geometryN( 1 )->wkbType(), QgsWkbTypes::PointZ );
   11904                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->x(), 1.0 );
   11905                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->y(), 1.0 );
   11906                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->z(), 20.0 );
   11907                 :          1 :   delete boundary;
   11908                 :            : 
   11909                 :            :   // addToPainterPath (note most tests are in test_qgsgeometry.py)
   11910                 :          1 :   QgsCompoundCurve ccPath;
   11911                 :          1 :   QgsCircularString path;
   11912                 :          1 :   QPainterPath pPath;
   11913                 :          1 :   ccPath.addToPainterPath( pPath );
   11914                 :          1 :   QVERIFY( pPath.isEmpty() );
   11915                 :          2 :   path.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 )
   11916                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 21, 2, 3 ) );
   11917                 :          1 :   ccPath.addCurve( path.clone() );
   11918                 :          1 :   ccPath.addToPainterPath( pPath );
   11919                 :          1 :   QGSCOMPARENEAR( pPath.currentPosition().x(), 21.0, 0.01 );
   11920                 :          1 :   QGSCOMPARENEAR( pPath.currentPosition().y(), 2.0, 0.01 );
   11921                 :          1 :   QVERIFY( !pPath.isEmpty() );
   11922                 :          1 :   QgsLineString lsPath;
   11923                 :          2 :   lsPath.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 21, 2, 3 )
   11924                 :          1 :                     << QgsPoint( QgsWkbTypes::PointZ, 31, 12, 3 ) );
   11925                 :          1 :   ccPath.addCurve( lsPath.clone() );
   11926                 :          1 :   pPath = QPainterPath();
   11927                 :          1 :   ccPath.addToPainterPath( pPath );
   11928                 :          1 :   QGSCOMPARENEAR( pPath.currentPosition().x(), 31.0, 0.01 );
   11929                 :          1 :   QGSCOMPARENEAR( pPath.currentPosition().y(), 12.0, 0.01 );
   11930                 :            : 
   11931                 :            :   // even number of points - should still work
   11932                 :          1 :   pPath = QPainterPath();
   11933                 :          1 :   path.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 ) );
   11934                 :          1 :   ccPath.clear();
   11935                 :          1 :   ccPath.addCurve( path.clone() );
   11936                 :          1 :   ccPath.addToPainterPath( pPath );
   11937                 :          1 :   QGSCOMPARENEAR( pPath.currentPosition().x(), 11.0, 0.01 );
   11938                 :          1 :   QGSCOMPARENEAR( pPath.currentPosition().y(), 12.0, 0.01 );
   11939                 :          1 :   QVERIFY( !pPath.isEmpty() );
   11940                 :            : 
   11941                 :            :   // toCurveType
   11942                 :          1 :   QgsCircularString curveLine1;
   11943                 :          1 :   QgsCompoundCurve cc1;
   11944                 :          1 :   curveLine1.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 22 ) );
   11945                 :          1 :   cc1.addCurve( curveLine1.clone() );
   11946                 :          1 :   std::unique_ptr< QgsCurve > curveType( cc1.toCurveType() );
   11947                 :          1 :   QCOMPARE( curveType->wkbType(), QgsWkbTypes::CompoundCurve );
   11948                 :          1 :   QCOMPARE( curveType->numPoints(), 3 );
   11949                 :          1 :   QCOMPARE( curveType->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( 1, 2 ) );
   11950                 :          1 :   QCOMPARE( curveType->vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( 11, 12 ) );
   11951                 :          1 :   QCOMPARE( curveType->vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( 1, 22 ) );
   11952                 :          1 :   QgsLineString ccls1;
   11953                 :          1 :   ccls1.setPoints( QgsPointSequence() << QgsPoint( 1, 22 ) << QgsPoint( 1, 25 ) );
   11954                 :          1 :   cc1.addCurve( ccls1.clone() );
   11955                 :          1 :   curveType.reset( cc1.toCurveType() );
   11956                 :          1 :   QCOMPARE( curveType->wkbType(), QgsWkbTypes::CompoundCurve );
   11957                 :          1 :   QCOMPARE( curveType->numPoints(), 4 );
   11958                 :          1 :   QCOMPARE( curveType->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( 1, 2 ) );
   11959                 :          1 :   QCOMPARE( curveType->vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( 11, 12 ) );
   11960                 :          1 :   QCOMPARE( curveType->vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( 1, 22 ) );
   11961                 :          1 :   QCOMPARE( curveType->vertexAt( QgsVertexId( 0, 0, 3 ) ), QgsPoint( 1, 25 ) );
   11962                 :            : 
   11963                 :            :   //test that area of a compound curve ring is equal to a closed linestring with the same vertices
   11964                 :          1 :   QgsCompoundCurve cc;
   11965                 :          1 :   QgsLineString *ll1 = new QgsLineString();
   11966                 :          1 :   ll1->setPoints( QgsPointSequence() << QgsPoint( 1, 1 ) << QgsPoint( 0, 2 ) );
   11967                 :          1 :   cc.addCurve( ll1 );
   11968                 :          1 :   QgsLineString *ll2 = new QgsLineString();
   11969                 :          1 :   ll2->setPoints( QgsPointSequence() << QgsPoint( 0, 2 ) << QgsPoint( -1, 0 ) << QgsPoint( 0, -1 ) );
   11970                 :          1 :   cc.addCurve( ll2 );
   11971                 :          1 :   QgsLineString *ll3 = new QgsLineString();
   11972                 :          1 :   ll3->setPoints( QgsPointSequence() << QgsPoint( 0, -1 ) << QgsPoint( 1, 1 ) );
   11973                 :          1 :   cc.addCurve( ll3 );
   11974                 :            : 
   11975                 :          1 :   double ccArea = 0.0;
   11976                 :          1 :   cc.sumUpArea( ccArea );
   11977                 :            : 
   11978                 :          1 :   QgsLineString ls;
   11979                 :          2 :   ls.setPoints( QgsPointSequence() << QgsPoint( 1, 1 ) << QgsPoint( 0, 2 ) <<  QgsPoint( -1, 0 ) << QgsPoint( 0, -1 )
   11980                 :          1 :                 << QgsPoint( 1, 1 ) );
   11981                 :          1 :   double lsArea = 0.0;
   11982                 :          1 :   ls.sumUpArea( lsArea );
   11983                 :          1 :   QGSCOMPARENEAR( ccArea, lsArea, 4 * std::numeric_limits<double>::epsilon() );
   11984                 :            : 
   11985                 :            : 
   11986                 :            :   //addVertex
   11987                 :          1 :   QgsCompoundCurve ac1;
   11988                 :          1 :   ac1.addVertex( QgsPoint( 1.0, 2.0 ) );
   11989                 :          1 :   QVERIFY( !ac1.isEmpty() );
   11990                 :          1 :   QCOMPARE( ac1.numPoints(), 1 );
   11991                 :          1 :   QCOMPARE( ac1.vertexCount(), 1 );
   11992                 :          1 :   QCOMPARE( ac1.nCoordinates(), 1 );
   11993                 :          1 :   QCOMPARE( ac1.ringCount(), 1 );
   11994                 :          1 :   QCOMPARE( ac1.partCount(), 1 );
   11995                 :          1 :   QVERIFY( !ac1.is3D() );
   11996                 :          1 :   QVERIFY( !ac1.isMeasure() );
   11997                 :          1 :   QCOMPARE( ac1.wkbType(), QgsWkbTypes::CompoundCurve );
   11998                 :          1 :   QVERIFY( !ac1.hasCurvedSegments() );
   11999                 :          1 :   QCOMPARE( ac1.area(), 0.0 );
   12000                 :          1 :   QCOMPARE( ac1.perimeter(), 0.0 );
   12001                 :            : 
   12002                 :            :   //adding first vertex should set linestring z/m type
   12003                 :          1 :   QgsCompoundCurve ac2;
   12004                 :          1 :   ac2.addVertex( QgsPoint( QgsWkbTypes::PointZ, 1.0, 2.0, 3.0 ) );
   12005                 :          1 :   QVERIFY( !ac2.isEmpty() );
   12006                 :          1 :   QVERIFY( ac2.is3D() );
   12007                 :          1 :   QVERIFY( !ac2.isMeasure() );
   12008                 :          1 :   QCOMPARE( ac2.wkbType(), QgsWkbTypes::CompoundCurveZ );
   12009                 :          1 :   QCOMPARE( ac2.wktTypeStr(), QString( "CompoundCurveZ" ) );
   12010                 :            : 
   12011                 :          1 :   QgsCompoundCurve ac3;
   12012                 :          1 :   ac3.addVertex( QgsPoint( QgsWkbTypes::PointM, 1.0, 2.0, 0.0, 3.0 ) );
   12013                 :          1 :   QVERIFY( !ac3.isEmpty() );
   12014                 :          1 :   QVERIFY( !ac3.is3D() );
   12015                 :          1 :   QVERIFY( ac3.isMeasure() );
   12016                 :          1 :   QCOMPARE( ac3.wkbType(), QgsWkbTypes::CompoundCurveM );
   12017                 :          1 :   QCOMPARE( ac3.wktTypeStr(), QString( "CompoundCurveM" ) );
   12018                 :            : 
   12019                 :          1 :   QgsCompoundCurve ac4;
   12020                 :          1 :   ac4.addVertex( QgsPoint( QgsWkbTypes::PointZM, 1.0, 2.0, 3.0, 4.0 ) );
   12021                 :          1 :   QVERIFY( !ac4.isEmpty() );
   12022                 :          1 :   QVERIFY( ac4.is3D() );
   12023                 :          1 :   QVERIFY( ac4.isMeasure() );
   12024                 :          1 :   QCOMPARE( ac4.wkbType(), QgsWkbTypes::CompoundCurveZM );
   12025                 :          1 :   QCOMPARE( ac4.wktTypeStr(), QString( "CompoundCurveZM" ) );
   12026                 :            : 
   12027                 :            :   //adding subsequent vertices should not alter z/m type, regardless of points type
   12028                 :          1 :   QgsCompoundCurve ac5;
   12029                 :          1 :   ac5.addVertex( QgsPoint( QgsWkbTypes::Point, 1.0, 2.0 ) ); //2d type
   12030                 :          1 :   QCOMPARE( ac5.wkbType(), QgsWkbTypes::CompoundCurve );
   12031                 :          1 :   ac5.addVertex( QgsPoint( QgsWkbTypes::PointZ, 11.0, 12.0, 13.0 ) ); // add 3d point
   12032                 :          1 :   QCOMPARE( ac5.numPoints(), 2 );
   12033                 :          1 :   QCOMPARE( ac5.vertexCount(), 2 );
   12034                 :          1 :   QCOMPARE( ac5.nCoordinates(), 2 );
   12035                 :          1 :   QCOMPARE( ac5.ringCount(), 1 );
   12036                 :          1 :   QCOMPARE( ac5.partCount(), 1 );
   12037                 :          1 :   QCOMPARE( ac5.wkbType(), QgsWkbTypes::CompoundCurve ); //should still be 2d
   12038                 :          1 :   QVERIFY( !ac5.is3D() );
   12039                 :          1 :   QCOMPARE( ac5.area(), 0.0 );
   12040                 :          1 :   QCOMPARE( ac5.perimeter(), 0.0 );
   12041                 :            : 
   12042                 :          1 :   QgsCompoundCurve ac6;
   12043                 :          1 :   ac6.addVertex( QgsPoint( QgsWkbTypes::PointZ, 1.0, 2.0, 3.0 ) ); //3d type
   12044                 :          1 :   QCOMPARE( ac6.wkbType(), QgsWkbTypes::CompoundCurveZ );
   12045                 :          1 :   ac6.addVertex( QgsPoint( QgsWkbTypes::Point, 11.0, 12.0 ) ); //add 2d point
   12046                 :          1 :   QCOMPARE( ac6.wkbType(), QgsWkbTypes::CompoundCurveZ ); //should still be 3d
   12047                 :          1 :   ac6.pointAt( 1, pt, v );
   12048                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::PointZ, 11.0, 12.0 ) );
   12049                 :          1 :   QVERIFY( ac6.is3D() );
   12050                 :          1 :   QCOMPARE( ac6.numPoints(), 2 );
   12051                 :          1 :   QCOMPARE( ac6.vertexCount(), 2 );
   12052                 :          1 :   QCOMPARE( ac6.nCoordinates(), 2 );
   12053                 :          1 :   QCOMPARE( ac6.ringCount(), 1 );
   12054                 :          1 :   QCOMPARE( ac6.partCount(), 1 );
   12055                 :            : 
   12056                 :            :   //close
   12057                 :          1 :   QgsLineString closeC1;
   12058                 :          1 :   QgsCompoundCurve closeCc1;
   12059                 :          1 :   closeCc1.close();
   12060                 :          1 :   QVERIFY( closeCc1.isEmpty() );
   12061                 :          1 :   closeC1.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 22 ) );
   12062                 :          1 :   closeCc1.addCurve( closeC1.clone() );
   12063                 :          1 :   QCOMPARE( closeCc1.numPoints(), 3 );
   12064                 :          1 :   QVERIFY( !closeCc1.isClosed() );
   12065                 :          1 :   closeCc1.close();
   12066                 :          1 :   QCOMPARE( closeCc1.numPoints(), 4 );
   12067                 :          1 :   QVERIFY( closeCc1.isClosed() );
   12068                 :          1 :   closeCc1.pointAt( 3, pt, v );
   12069                 :          1 :   QCOMPARE( pt, QgsPoint( QgsWkbTypes::Point, 1, 2 ) );
   12070                 :          1 :   closeCc1.close();
   12071                 :          1 :   QCOMPARE( closeCc1.numPoints(), 4 );
   12072                 :          1 :   QVERIFY( closeCc1.isClosed() );
   12073                 :            : 
   12074                 :            :   //segmentLength
   12075                 :          1 :   QgsCircularString curveLine2;
   12076                 :          1 :   QgsCompoundCurve slc1;
   12077                 :          1 :   QCOMPARE( slc1.segmentLength( QgsVertexId( -1, 0, 0 ) ), 0.0 );
   12078                 :          1 :   QCOMPARE( slc1.segmentLength( QgsVertexId( 0, 0, 0 ) ), 0.0 );
   12079                 :          1 :   QCOMPARE( slc1.segmentLength( QgsVertexId( 1, 0, 0 ) ), 0.0 );
   12080                 :          1 :   curveLine2.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 22 ) );
   12081                 :          1 :   slc1.addCurve( curveLine2.clone() );
   12082                 :          1 :   QCOMPARE( slc1.segmentLength( QgsVertexId() ), 0.0 );
   12083                 :          1 :   QCOMPARE( slc1.segmentLength( QgsVertexId( 0, 0, -1 ) ), 0.0 );
   12084                 :          1 :   QGSCOMPARENEAR( slc1.segmentLength( QgsVertexId( 0, 0, 0 ) ), 31.4159, 0.001 );
   12085                 :          1 :   QCOMPARE( slc1.segmentLength( QgsVertexId( 0, 0, 1 ) ), 0.0 );
   12086                 :          1 :   QCOMPARE( slc1.segmentLength( QgsVertexId( 0, 0, 2 ) ), 0.0 );
   12087                 :          1 :   QCOMPARE( slc1.segmentLength( QgsVertexId( -1, 0, -1 ) ), 0.0 );
   12088                 :          1 :   QGSCOMPARENEAR( slc1.segmentLength( QgsVertexId( -1, 0, 0 ) ), 31.4159, 0.001 );
   12089                 :          1 :   QCOMPARE( slc1.segmentLength( QgsVertexId( 1, 0, 1 ) ), 0.0 );
   12090                 :          1 :   QGSCOMPARENEAR( slc1.segmentLength( QgsVertexId( 1, 1, 0 ) ), 31.4159, 0.001 );
   12091                 :          1 :   curveLine2.setPoints( QgsPointSequence() << QgsPoint( 1, 22 ) << QgsPoint( -9, 32 ) << QgsPoint( 1, 42 ) );
   12092                 :          1 :   slc1.addCurve( curveLine2.clone() );
   12093                 :          1 :   QCOMPARE( slc1.segmentLength( QgsVertexId() ), 0.0 );
   12094                 :          1 :   QCOMPARE( slc1.segmentLength( QgsVertexId( 0, 0, -1 ) ), 0.0 );
   12095                 :          1 :   QGSCOMPARENEAR( slc1.segmentLength( QgsVertexId( 0, 0, 0 ) ), 31.4159, 0.001 );
   12096                 :          1 :   QCOMPARE( slc1.segmentLength( QgsVertexId( 0, 0, 1 ) ), 0.0 );
   12097                 :          1 :   QGSCOMPARENEAR( slc1.segmentLength( QgsVertexId( 0, 0, 2 ) ), 31.4159, 0.001 );
   12098                 :          1 :   QCOMPARE( slc1.segmentLength( QgsVertexId( 0, 0, 3 ) ), 0.0 );
   12099                 :          1 :   QCOMPARE( slc1.segmentLength( QgsVertexId( 0, 0, 4 ) ), 0.0 );
   12100                 :          1 :   QgsLineString curveLine3;
   12101                 :          1 :   curveLine3.setPoints( QgsPointSequence() << QgsPoint( 1, 42 ) << QgsPoint( 10, 42 ) );
   12102                 :          1 :   slc1.addCurve( curveLine3.clone() );
   12103                 :          1 :   QCOMPARE( slc1.segmentLength( QgsVertexId() ), 0.0 );
   12104                 :          1 :   QCOMPARE( slc1.segmentLength( QgsVertexId( 0, 0, -1 ) ), 0.0 );
   12105                 :          1 :   QGSCOMPARENEAR( slc1.segmentLength( QgsVertexId( 0, 0, 0 ) ), 31.4159, 0.001 );
   12106                 :          1 :   QCOMPARE( slc1.segmentLength( QgsVertexId( 0, 0, 1 ) ), 0.0 );
   12107                 :          1 :   QGSCOMPARENEAR( slc1.segmentLength( QgsVertexId( 0, 0, 2 ) ), 31.4159, 0.001 );
   12108                 :          1 :   QCOMPARE( slc1.segmentLength( QgsVertexId( 0, 0, 3 ) ), 0.0 );
   12109                 :          1 :   QCOMPARE( slc1.segmentLength( QgsVertexId( 0, 0, 4 ) ), 9.0 );
   12110                 :          1 :   QCOMPARE( slc1.segmentLength( QgsVertexId( 0, 0, 5 ) ), 0.0 );
   12111                 :            : 
   12112                 :            :   //removeDuplicateNodes
   12113                 :          1 :   QgsCompoundCurve nodeCurve;
   12114                 :          1 :   QgsCircularString nodeLine;
   12115                 :          1 :   QVERIFY( !nodeCurve.removeDuplicateNodes() );
   12116                 :          1 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 111, 12 ) );
   12117                 :          1 :   nodeCurve.addCurve( nodeLine.clone() );
   12118                 :          1 :   QVERIFY( !nodeCurve.removeDuplicateNodes() );
   12119                 :          2 :   QCOMPARE( nodeCurve.asWkt(), QStringLiteral( "CompoundCurve (CircularString (11 2, 11 12, 111 12))" ) );
   12120                 :          1 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 11, 2 ) );
   12121                 :          1 :   nodeCurve.clear();
   12122                 :          1 :   nodeCurve.addCurve( nodeLine.clone() );
   12123                 :          1 :   QVERIFY( !nodeCurve.removeDuplicateNodes() );
   12124                 :          2 :   QCOMPARE( nodeCurve.asWkt(), QStringLiteral( "CompoundCurve (CircularString (11 2, 11 12, 11 2))" ) );
   12125                 :          2 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 10, 3 ) << QgsPoint( 11.01, 1.99 ) << QgsPoint( 9, 3 )
   12126                 :          1 :                       << QgsPoint( 11, 2 ) );
   12127                 :          1 :   nodeCurve.clear();
   12128                 :          1 :   nodeCurve.addCurve( nodeLine.clone() );
   12129                 :          1 :   QVERIFY( !nodeCurve.removeDuplicateNodes( 0.02 ) );
   12130                 :          2 :   QCOMPARE( nodeCurve.asWkt( 2 ), QStringLiteral( "CompoundCurve (CircularString (11 2, 10 3, 11.01 1.99, 9 3, 11 2))" ) );
   12131                 :          2 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11.01, 1.99 ) << QgsPoint( 11.02, 2.01 )
   12132                 :          1 :                       << QgsPoint( 11, 12 ) << QgsPoint( 111, 12 ) << QgsPoint( 111.01, 11.99 ) );
   12133                 :          1 :   nodeCurve.clear();
   12134                 :          1 :   nodeCurve.addCurve( nodeLine.clone() );
   12135                 :          1 :   QVERIFY( !nodeCurve.removeDuplicateNodes() );
   12136                 :          2 :   QCOMPARE( nodeCurve.asWkt( 2 ), QStringLiteral( "CompoundCurve (CircularString (11 2, 11.01 1.99, 11.02 2.01, 11 12, 111 12, 111.01 11.99))" ) );
   12137                 :          1 :   QVERIFY( nodeCurve.removeDuplicateNodes( 0.02 ) );
   12138                 :          1 :   QVERIFY( !nodeCurve.removeDuplicateNodes( 0.02 ) );
   12139                 :          2 :   QCOMPARE( nodeCurve.asWkt( 2 ), QStringLiteral( "CompoundCurve (CircularString (11 2, 11 12, 111 12, 111.01 11.99))" ) );
   12140                 :            : 
   12141                 :            :   // with tiny segment
   12142                 :          1 :   QgsLineString linePart;
   12143                 :          1 :   linePart.setPoints( QgsPointSequence() << QgsPoint( 111.01, 11.99 ) << QgsPoint( 111, 12 ) );
   12144                 :          1 :   nodeCurve.addCurve( linePart.clone() );
   12145                 :          1 :   QVERIFY( !nodeCurve.removeDuplicateNodes() );
   12146                 :          2 :   QCOMPARE( nodeCurve.asWkt( 2 ), QStringLiteral( "CompoundCurve (CircularString (11 2, 11 12, 111 12, 111.01 11.99),(111.01 11.99, 111 12))" ) );
   12147                 :          1 :   QVERIFY( nodeCurve.removeDuplicateNodes( 0.02 ) );
   12148                 :          2 :   QCOMPARE( nodeCurve.asWkt( 2 ), QStringLiteral( "CompoundCurve (CircularString (11 2, 11 12, 111 12, 111.01 11.99))" ) );
   12149                 :            : 
   12150                 :            :   // with multiple duplicate nodes
   12151                 :          2 :   nodeCurve.fromWkt( QStringLiteral( "CompoundCurve ((11 1, 11 2, 11 2),CircularString(11 2, 10 3, 10 2),(10 2, 10 2, 11 1))" ) );
   12152                 :          1 :   QVERIFY( nodeCurve.removeDuplicateNodes( 0.02 ) );
   12153                 :          2 :   QCOMPARE( nodeCurve.asWkt( 0 ), QStringLiteral( "CompoundCurve ((11 1, 11 2),CircularString (11 2, 10 3, 10 2),(10 2, 11 1))" ) );
   12154                 :            : 
   12155                 :            :   // ensure continuity
   12156                 :          1 :   nodeCurve.clear();
   12157                 :          1 :   linePart.setPoints( QgsPointSequence() << QgsPoint( 1, 1 ) << QgsPoint( 111.01, 11.99 ) << QgsPoint( 111, 12 ) );
   12158                 :          1 :   nodeCurve.addCurve( linePart.clone() );
   12159                 :          1 :   linePart.setPoints( QgsPointSequence() << QgsPoint( 111, 12 ) << QgsPoint( 31, 33 ) );
   12160                 :          1 :   nodeCurve.addCurve( linePart.clone() );
   12161                 :          1 :   QVERIFY( nodeCurve.removeDuplicateNodes( 0.02 ) );
   12162                 :          2 :   QCOMPARE( nodeCurve.asWkt( 2 ), QStringLiteral( "CompoundCurve ((1 1, 111.01 11.99),(111.01 11.99, 31 33))" ) );
   12163                 :            : 
   12164                 :            :   // swap xy
   12165                 :          1 :   QgsCompoundCurve swapCurve;
   12166                 :          1 :   swapCurve.swapXy(); //no crash
   12167                 :          1 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 11, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 111, 12, 23, 24, QgsWkbTypes::PointZM ) );
   12168                 :          1 :   swapCurve.addCurve( nodeLine.clone() );
   12169                 :          1 :   swapCurve.swapXy();
   12170                 :          2 :   QCOMPARE( swapCurve.asWkt(), QStringLiteral( "CompoundCurveZM (CircularStringZM (2 11 3 4, 12 11 13 14, 12 111 23 24))" ) );
   12171                 :          1 :   QgsLineString lsSwap;
   12172                 :          1 :   lsSwap.setPoints( QgsPointSequence() << QgsPoint( 12, 111, 23, 24, QgsWkbTypes::PointZM ) << QgsPoint( 22, 122, 33, 34, QgsWkbTypes::PointZM ) );
   12173                 :          1 :   swapCurve.addCurve( lsSwap.clone() );
   12174                 :          1 :   swapCurve.swapXy();
   12175                 :          2 :   QCOMPARE( swapCurve.asWkt(), QStringLiteral( "CompoundCurveZM (CircularStringZM (11 2 3 4, 11 12 13 14, 111 12 23 24),(111 12 23 24, 122 22 33 34))" ) );
   12176                 :            : 
   12177                 :            :   // filter vertices
   12178                 :         11 :   auto filter = []( const QgsPoint & point )-> bool
   12179                 :            :   {
   12180                 :         11 :     return point.x() > 5;
   12181                 :            :   };
   12182                 :          1 :   QgsCompoundCurve filterCurve;
   12183                 :          1 :   filterCurve.filterVertices( filter ); //no crash
   12184                 :          1 :   nodeLine.setPoints( QgsPointSequence()   << QgsPoint( 1, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 11, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 111, 12, 23, 24, QgsWkbTypes::PointZM )   << QgsPoint( 1, 2, 3, 4, QgsWkbTypes::PointZM ) );
   12185                 :          1 :   filterCurve.addCurve( nodeLine.clone() );
   12186                 :          1 :   filterCurve.filterVertices( filter );
   12187                 :          2 :   QCOMPARE( filterCurve.asWkt(), QStringLiteral( "CompoundCurveZM (CircularStringZM (11 2 3 4, 11 12 13 14, 111 12 23 24))" ) );
   12188                 :          1 :   QgsLineString lsFilter;
   12189                 :          1 :   lsFilter.setPoints( QgsPointSequence() << QgsPoint( 12, 111, 23, 24, QgsWkbTypes::PointZM ) << QgsPoint( 22, 122, 33, 34, QgsWkbTypes::PointZM ) << QgsPoint( 1, 111, 23, 24, QgsWkbTypes::PointZM ) );
   12190                 :          1 :   filterCurve.addCurve( lsFilter.clone() );
   12191                 :          1 :   filterCurve.filterVertices( filter );
   12192                 :          2 :   QCOMPARE( filterCurve.asWkt(), QStringLiteral( "CompoundCurveZM (CircularStringZM (11 2 3 4, 11 12 13 14, 111 12 23 24),(12 111 23 24, 22 122 33 34))" ) );
   12193                 :            : 
   12194                 :            :   // transform vertices
   12195                 :         13 :   auto transform = []( const QgsPoint & point )-> QgsPoint
   12196                 :            :   {
   12197                 :         13 :     return QgsPoint( point.x() + 2, point.y() + 3, point.z() + 4, point.m() + 5 );
   12198                 :            :   };
   12199                 :          1 :   QgsCompoundCurve transformCurve;
   12200                 :          1 :   transformCurve.transformVertices( transform ); //no crash
   12201                 :          1 :   nodeLine.setPoints( QgsPointSequence()   << QgsPoint( 1, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 11, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 111, 12, 23, 24, QgsWkbTypes::PointZM )   << QgsPoint( 1, 2, 3, 4, QgsWkbTypes::PointZM ) );
   12202                 :          1 :   transformCurve.addCurve( nodeLine.clone() );
   12203                 :          1 :   transformCurve.transformVertices( transform );
   12204                 :          2 :   QCOMPARE( transformCurve.asWkt(), QStringLiteral( "CompoundCurveZM (CircularStringZM (3 5 7 9, 13 5 7 9, 13 15 17 19, 113 15 27 29, 3 5 7 9))" ) );
   12205                 :          1 :   QgsLineString lsTransform;
   12206                 :          1 :   lsTransform.setPoints( QgsPointSequence() << QgsPoint( 12, 111, 23, 24, QgsWkbTypes::PointZM ) << QgsPoint( 22, 122, 33, 34, QgsWkbTypes::PointZM ) << QgsPoint( 1, 111, 23, 24, QgsWkbTypes::PointZM ) );
   12207                 :          1 :   transformCurve.addCurve( lsTransform.clone() );
   12208                 :          1 :   transformCurve.transformVertices( transform );
   12209                 :          2 :   QCOMPARE( transformCurve.asWkt(), QStringLiteral( "CompoundCurveZM (CircularStringZM (5 8 11 14, 15 8 11 14, 15 18 21 24, 115 18 31 34, 5 8 11 14),(14 114 27 29, 24 125 37 39, 3 114 27 29))" ) );
   12210                 :            : 
   12211                 :            :   // transform using class
   12212                 :          1 :   QgsCompoundCurve transformCurve2;
   12213                 :          1 :   TestTransformer transformer;
   12214                 :            :   // no crash
   12215                 :          1 :   QVERIFY( transformCurve2.transform( &transformer ) );
   12216                 :          1 :   nodeLine.setPoints( QgsPointSequence()   << QgsPoint( 1, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 11, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 111, 12, 23, 24, QgsWkbTypes::PointZM )   << QgsPoint( 1, 2, 3, 4, QgsWkbTypes::PointZM ) );
   12217                 :          1 :   transformCurve2.addCurve( nodeLine.clone() );
   12218                 :          1 :   QVERIFY( transformCurve2.transform( &transformer ) );
   12219                 :          2 :   QCOMPARE( transformCurve2.asWkt(), QStringLiteral( "CompoundCurveZM (CircularStringZM (3 16 8 3, 33 16 8 3, 33 26 18 13, 333 26 28 23, 3 16 8 3))" ) );
   12220                 :          1 :   transformCurve2.addCurve( lsTransform.clone() );
   12221                 :          1 :   QVERIFY( transformCurve2.transform( &transformer ) );
   12222                 :          2 :   QCOMPARE( transformCurve2.asWkt(), QStringLiteral( "CompoundCurveZM (CircularStringZM (9 30 13 2, 99 30 13 2, 99 40 23 12, 999 40 33 22, 9 30 13 2),(36 125 28 23, 66 136 38 33, 3 125 28 23))" ) );
   12223                 :            : 
   12224                 :          1 :   TestFailTransformer failTransformer;
   12225                 :          1 :   QVERIFY( !transformCurve2.transform( &failTransformer ) );
   12226                 :            : 
   12227                 :            :   // substring
   12228                 :          1 :   QgsCompoundCurve substring;
   12229                 :          1 :   std::unique_ptr< QgsCompoundCurve > substringResult( substring.curveSubstring( 1, 2 ) ); // no crash
   12230                 :          1 :   QVERIFY( substringResult.get() );
   12231                 :          1 :   QVERIFY( substringResult->isEmpty() );
   12232                 :          2 :   substring.fromWkt( QStringLiteral( "CompoundCurveZM( ( 5 0 -1 -2, 10 0 1 2 ), CircularStringZM (10 0 1 2, 11 1 3 4, 12 0 13 14))" ) );
   12233                 :          1 :   substringResult.reset( substring.curveSubstring( 0, 0 ) );
   12234                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CompoundCurveZM ((5 0 -1 -2, 5 0 -1 -2))" ) );
   12235                 :          1 :   substringResult.reset( substring.curveSubstring( -1, -0.1 ) );
   12236                 :          1 :   QVERIFY( substringResult->isEmpty() );
   12237                 :          1 :   substringResult.reset( substring.curveSubstring( 100000, 10000 ) );
   12238                 :          1 :   QVERIFY( substringResult->isEmpty() );
   12239                 :          1 :   substringResult.reset( substring.curveSubstring( -1, 1 ) );
   12240                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CompoundCurveZM ((5 0 -1 -2, 6 0 -0.6 -1.2))" ) );
   12241                 :          1 :   substringResult.reset( substring.curveSubstring( 1, -1 ) );
   12242                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CompoundCurveZM ((6 0 -0.6 -1.2, 6 0 -0.6 -1.2))" ) );
   12243                 :          1 :   substringResult.reset( substring.curveSubstring( -1, 10000 ) );
   12244                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CompoundCurveZM ((5 0 -1 -2, 10 0 1 2),CircularStringZM (10 0 1 2, 11 1 3 4, 12 0 13 14))" ) );
   12245                 :          1 :   substringResult.reset( substring.curveSubstring( 1, 10000 ) );
   12246                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CompoundCurveZM ((6 0 -0.6 -1.2, 10 0 1 2),CircularStringZM (10 0 1 2, 11 1 3 4, 12 0 13 14))" ) );
   12247                 :          1 :   substringResult.reset( substring.curveSubstring( 1, 7 ) );
   12248                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CompoundCurveZM ((6 0 -0.6 -1.2, 10 0 1 2),CircularStringZM (10 0 1 2, 10.46 0.84 2.27 3.27, 11.42 0.91 5.73 6.73))" ) );
   12249                 :          1 :   substringResult.reset( substring.curveSubstring( 1, 1.5 ) );
   12250                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CompoundCurveZM ((6 0 -0.6 -1.2, 6.5 0 -0.4 -0.8))" ) );
   12251                 :            : 
   12252                 :          2 :   substring.fromWkt( QStringLiteral( "CompoundCurveZ( ( 5 0 -1, 10 0 1 ), CircularStringZ (10 0 1, 11 1 3, 12 0 13))" ) );
   12253                 :          1 :   substringResult.reset( substring.curveSubstring( 1, 7 ) );
   12254                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CompoundCurveZ ((6 0 -0.6, 10 0 1),CircularStringZ (10 0 1, 10.46 0.84 2.27, 11.42 0.91 5.73))" ) );
   12255                 :          2 :   substring.fromWkt( QStringLiteral( "CompoundCurveM( ( 5 0 -1, 10 0 1 ), CircularStringM (10 0 1, 11 1 3, 12 0 13))" ) );
   12256                 :          1 :   substringResult.reset( substring.curveSubstring( 1, 7 ) );
   12257                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CompoundCurveM ((6 0 -0.6, 10 0 1),CircularStringM (10 0 1, 10.46 0.84 2.27, 11.42 0.91 5.73))" ) );
   12258                 :          2 :   substring.fromWkt( QStringLiteral( "CompoundCurve( ( 5 0, 10 0 ), CircularString (10 0, 11 1, 12 0))" ) );
   12259                 :          1 :   substringResult.reset( substring.curveSubstring( 1, 7 ) );
   12260                 :          2 :   QCOMPARE( substringResult->asWkt( 2 ), QStringLiteral( "CompoundCurve ((6 0, 10 0),CircularString (10 0, 10.46 0.84, 11.42 0.91))" ) );
   12261                 :            : 
   12262                 :            :   // substring
   12263                 :          1 :   QgsCompoundCurve interpolate;
   12264                 :          1 :   std::unique_ptr< QgsPoint > interpolateResult( interpolate.interpolatePoint( 1 ) ); // no crash
   12265                 :          1 :   QVERIFY( !interpolateResult.get() );
   12266                 :          2 :   interpolate.fromWkt( QStringLiteral( "CompoundCurveZM( ( 5 0 -1 -2, 10 0 1 2 ), CircularStringZM (10 0 1 2, 11 1 3 4, 12 0 13 14))" ) );
   12267                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 0 ) );
   12268                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointZM (5 0 -1 -2)" ) );
   12269                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( -1 ) );
   12270                 :          1 :   QVERIFY( !interpolateResult.get() );
   12271                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 100000 ) );
   12272                 :          1 :   QVERIFY( !interpolateResult.get() );
   12273                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 1 ) );
   12274                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointZM (6 0 -0.6 -1.2)" ) );
   12275                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 7 ) );
   12276                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointZM (11.42 0.91 5.73 6.73)" ) );
   12277                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 1.5 ) );
   12278                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointZM (6.5 0 -0.4 -0.8)" ) );
   12279                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( interpolate.length() ) );
   12280                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointZM (12 0 13 14)" ) );
   12281                 :            : 
   12282                 :          2 :   interpolate.fromWkt( QStringLiteral( "CompoundCurveZ( ( 5 0 -1, 10 0 1 ), CircularStringZ (10 0 1, 11 1 3, 12 0 13))" ) );
   12283                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 1 ) );
   12284                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointZ (6 0 -0.6)" ) );
   12285                 :          2 :   interpolate.fromWkt( QStringLiteral( "CompoundCurveM( ( 5 0 -1, 10 0 1 ), CircularStringM (10 0 1, 11 1 3, 12 0 13))" ) );
   12286                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 1 ) );
   12287                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "PointM (6 0 -0.6)" ) );
   12288                 :          2 :   interpolate.fromWkt( QStringLiteral( "CompoundCurve( ( 5 0, 10 0 ), CircularString (10 0, 11 1, 12 0))" ) );
   12289                 :          1 :   interpolateResult.reset( interpolate.interpolatePoint( 1 ) );
   12290                 :          2 :   QCOMPARE( interpolateResult->asWkt( 2 ), QStringLiteral( "Point (6 0)" ) );
   12291                 :            : 
   12292                 :            :   // orientation
   12293                 :          1 :   QgsCompoundCurve orientation;
   12294                 :          1 :   ( void )orientation.orientation(); // no crash
   12295                 :          2 :   orientation.fromWkt( QStringLiteral( "CompoundCurve( ( 0 0, 0 1), CircularString (0 1, 1 1, 1 0), (1 0, 0 0))" ) );
   12296                 :          1 :   QCOMPARE( orientation.orientation(), QgsCurve::Clockwise );
   12297                 :          2 :   orientation.fromWkt( QStringLiteral( "CompoundCurve( ( 0 0, 1 0), CircularString (1 0, 1 1, 0 1), (0 1, 0 0))" ) );
   12298                 :          1 :   QCOMPARE( orientation.orientation(), QgsCurve::CounterClockwise );
   12299                 :          1 : }
   12300                 :            : 
   12301                 :          1 : void TestQgsGeometry::multiPoint()
   12302                 :            : {
   12303                 :            :   //test constructor
   12304                 :          1 :   QgsMultiPoint c1;
   12305                 :          1 :   QVERIFY( c1.isEmpty() );
   12306                 :          1 :   QCOMPARE( c1.nCoordinates(), 0 );
   12307                 :          1 :   QCOMPARE( c1.ringCount(), 0 );
   12308                 :          1 :   QCOMPARE( c1.partCount(), 0 );
   12309                 :          1 :   QVERIFY( !c1.is3D() );
   12310                 :          1 :   QVERIFY( !c1.isMeasure() );
   12311                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::MultiPoint );
   12312                 :          1 :   QCOMPARE( c1.wktTypeStr(), QString( "MultiPoint" ) );
   12313                 :          1 :   QCOMPARE( c1.geometryType(), QString( "MultiPoint" ) );
   12314                 :          1 :   QCOMPARE( c1.dimension(), 0 );
   12315                 :          1 :   QVERIFY( !c1.hasCurvedSegments() );
   12316                 :          1 :   QCOMPARE( c1.area(), 0.0 );
   12317                 :          1 :   QCOMPARE( c1.perimeter(), 0.0 );
   12318                 :          1 :   QCOMPARE( c1.numGeometries(), 0 );
   12319                 :          1 :   QVERIFY( !c1.geometryN( 0 ) );
   12320                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   12321                 :          1 :   QCOMPARE( c1.vertexCount( 0, 0 ), 0 );
   12322                 :          1 :   QCOMPARE( c1.vertexCount( 0, 1 ), 0 );
   12323                 :          1 :   QCOMPARE( c1.vertexCount( 1, 0 ), 0 );
   12324                 :            : 
   12325                 :            :   //addGeometry
   12326                 :            : 
   12327                 :            :   //try with nullptr
   12328                 :          1 :   c1.addGeometry( nullptr );
   12329                 :          1 :   QVERIFY( c1.isEmpty() );
   12330                 :          1 :   QCOMPARE( c1.nCoordinates(), 0 );
   12331                 :          1 :   QCOMPARE( c1.ringCount(), 0 );
   12332                 :          1 :   QCOMPARE( c1.partCount(), 0 );
   12333                 :          1 :   QCOMPARE( c1.numGeometries(), 0 );
   12334                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::MultiPoint );
   12335                 :          1 :   QVERIFY( !c1.geometryN( 0 ) );
   12336                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   12337                 :            : 
   12338                 :            :   // not a point
   12339                 :          1 :   QVERIFY( !c1.addGeometry( new QgsLineString() ) );
   12340                 :          1 :   QVERIFY( c1.isEmpty() );
   12341                 :          1 :   QCOMPARE( c1.nCoordinates(), 0 );
   12342                 :          1 :   QCOMPARE( c1.ringCount(), 0 );
   12343                 :          1 :   QCOMPARE( c1.partCount(), 0 );
   12344                 :          1 :   QCOMPARE( c1.numGeometries(), 0 );
   12345                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::MultiPoint );
   12346                 :          1 :   QVERIFY( !c1.geometryN( 0 ) );
   12347                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   12348                 :            : 
   12349                 :            :   //valid geometry
   12350                 :          1 :   QgsPoint part( 1, 10 );
   12351                 :          1 :   c1.addGeometry( part.clone() );
   12352                 :          1 :   QVERIFY( !c1.isEmpty() );
   12353                 :          1 :   QCOMPARE( c1.numGeometries(), 1 );
   12354                 :          1 :   QCOMPARE( c1.nCoordinates(), 1 );
   12355                 :          1 :   QCOMPARE( c1.ringCount(), 1 );
   12356                 :          1 :   QCOMPARE( c1.partCount(), 1 );
   12357                 :          1 :   QVERIFY( !c1.is3D() );
   12358                 :          1 :   QVERIFY( !c1.isMeasure() );
   12359                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::MultiPoint );
   12360                 :          1 :   QCOMPARE( c1.wktTypeStr(), QString( "MultiPoint" ) );
   12361                 :          1 :   QCOMPARE( c1.geometryType(), QString( "MultiPoint" ) );
   12362                 :          1 :   QCOMPARE( c1.dimension(), 0 );
   12363                 :          1 :   QVERIFY( !c1.hasCurvedSegments() );
   12364                 :          1 :   QCOMPARE( c1.area(), 0.0 );
   12365                 :          1 :   QCOMPARE( c1.perimeter(), 0.0 );
   12366                 :          1 :   QVERIFY( c1.geometryN( 0 ) );
   12367                 :          1 :   QCOMPARE( *static_cast< const QgsPoint * >( c1.geometryN( 0 ) ), part );
   12368                 :          1 :   QVERIFY( !c1.geometryN( 100 ) );
   12369                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   12370                 :          1 :   QCOMPARE( c1.vertexCount( 0, 0 ), 1 );
   12371                 :          1 :   QCOMPARE( c1.vertexCount( 1, 0 ), 0 );
   12372                 :            : 
   12373                 :            :   //initial adding of geometry should set z/m type
   12374                 :          1 :   part = QgsPoint( QgsWkbTypes::PointZ, 10, 11, 1 );
   12375                 :          1 :   QgsMultiPoint c2;
   12376                 :          1 :   c2.addGeometry( part.clone() );
   12377                 :          1 :   QVERIFY( c2.is3D() );
   12378                 :          1 :   QVERIFY( !c2.isMeasure() );
   12379                 :          1 :   QCOMPARE( c2.wkbType(), QgsWkbTypes::MultiPointZ );
   12380                 :          1 :   QCOMPARE( c2.wktTypeStr(), QString( "MultiPointZ" ) );
   12381                 :          1 :   QCOMPARE( c2.geometryType(), QString( "MultiPoint" ) );
   12382                 :          1 :   QCOMPARE( *( static_cast< const QgsPoint * >( c2.geometryN( 0 ) ) ), part );
   12383                 :          1 :   QgsMultiPoint c3;
   12384                 :          1 :   part = QgsPoint( QgsWkbTypes::PointM, 10, 10, 0, 3 );
   12385                 :          1 :   c3.addGeometry( part.clone() );
   12386                 :          1 :   QVERIFY( !c3.is3D() );
   12387                 :          1 :   QVERIFY( c3.isMeasure() );
   12388                 :          1 :   QCOMPARE( c3.wkbType(), QgsWkbTypes::MultiPointM );
   12389                 :          1 :   QCOMPARE( c3.wktTypeStr(), QString( "MultiPointM" ) );
   12390                 :          1 :   QCOMPARE( *( static_cast< const QgsPoint * >( c3.geometryN( 0 ) ) ), part );
   12391                 :          1 :   QgsMultiPoint c4;
   12392                 :          1 :   part = QgsPoint( QgsWkbTypes::PointZM, 10, 10, 5, 3 );
   12393                 :          1 :   c4.addGeometry( part.clone() );
   12394                 :          1 :   QVERIFY( c4.is3D() );
   12395                 :          1 :   QVERIFY( c4.isMeasure() );
   12396                 :          1 :   QCOMPARE( c4.wkbType(), QgsWkbTypes::MultiPointZM );
   12397                 :          1 :   QCOMPARE( c4.wktTypeStr(), QString( "MultiPointZM" ) );
   12398                 :          1 :   QCOMPARE( *( static_cast< const QgsPoint * >( c4.geometryN( 0 ) ) ), part );
   12399                 :            : 
   12400                 :            :   //add another part
   12401                 :          1 :   QgsMultiPoint c6;
   12402                 :          1 :   part = QgsPoint( 10, 11 );
   12403                 :          1 :   c6.addGeometry( part.clone() );
   12404                 :          1 :   QCOMPARE( c6.vertexCount( 0, 0 ), 1 );
   12405                 :          1 :   part = QgsPoint( 9, 1 );
   12406                 :          1 :   c6.addGeometry( part.clone() );
   12407                 :          1 :   QCOMPARE( c6.vertexCount( 1, 0 ), 1 );
   12408                 :          1 :   QCOMPARE( c6.numGeometries(), 2 );
   12409                 :          1 :   QVERIFY( c6.geometryN( 0 ) );
   12410                 :          1 :   QCOMPARE( *static_cast< const QgsPoint * >( c6.geometryN( 1 ) ), part );
   12411                 :            : 
   12412                 :          1 :   QgsCoordinateSequence seq = c6.coordinateSequence();
   12413                 :          1 :   QCOMPARE( seq, QgsCoordinateSequence() << ( QgsRingSequence() << ( QgsPointSequence() << QgsPoint( 10, 11 ) ) )
   12414                 :            :             << ( QgsRingSequence() << ( QgsPointSequence() << QgsPoint( 9, 1 ) ) ) );
   12415                 :          1 :   QCOMPARE( c6.nCoordinates(), 2 );
   12416                 :            : 
   12417                 :            :   //adding subsequent points should not alter z/m type, regardless of points type
   12418                 :          1 :   c6.clear();
   12419                 :          1 :   c6.addGeometry( part.clone() );
   12420                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPoint );
   12421                 :          1 :   c6.addGeometry( new QgsPoint( QgsWkbTypes::PointZ, 1.0, 2.0, 3 ) );
   12422                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPoint );
   12423                 :          1 :   QCOMPARE( c6.vertexCount( 0, 0 ), 1 );
   12424                 :          1 :   QCOMPARE( c6.vertexCount( 1, 0 ), 1 );
   12425                 :          1 :   QCOMPARE( c6.vertexCount( 2, 0 ), 0 );
   12426                 :          1 :   QCOMPARE( c6.vertexCount( -1, 0 ), 0 );
   12427                 :          1 :   QCOMPARE( c6.nCoordinates(), 2 );
   12428                 :          1 :   QCOMPARE( c6.ringCount(), 1 );
   12429                 :          1 :   QCOMPARE( c6.partCount(), 2 );
   12430                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPoint ); //should still be 2d
   12431                 :          1 :   QVERIFY( !c6.is3D() );
   12432                 :          1 :   QCOMPARE( *( static_cast< const QgsPoint * >( c6.geometryN( 1 ) ) ), QgsPoint( 1, 2 ) );
   12433                 :          1 :   c6.addGeometry( new QgsPoint( QgsWkbTypes::PointM, 11.0, 12.0, 0, 3 ) );
   12434                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPoint );
   12435                 :          1 :   QCOMPARE( c6.vertexCount( 0, 0 ), 1 );
   12436                 :          1 :   QCOMPARE( c6.vertexCount( 1, 0 ), 1 );
   12437                 :          1 :   QCOMPARE( c6.vertexCount( 2, 0 ), 1 );
   12438                 :          1 :   QCOMPARE( c6.nCoordinates(), 3 );
   12439                 :          1 :   QCOMPARE( c6.ringCount(), 1 );
   12440                 :          1 :   QCOMPARE( c6.partCount(), 3 );
   12441                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPoint ); //should still be 2d
   12442                 :          1 :   QVERIFY( !c6.is3D() );
   12443                 :          1 :   QVERIFY( !c6.isMeasure() );
   12444                 :          1 :   QCOMPARE( *( static_cast< const QgsPoint * >( c6.geometryN( 2 ) ) ), QgsPoint( 11, 12 ) );
   12445                 :            : 
   12446                 :          1 :   c6.clear();
   12447                 :          1 :   c6.addGeometry( new QgsPoint( QgsWkbTypes::PointZ, 1.0, 2.0, 3 ) );
   12448                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPointZ );
   12449                 :          1 :   c6.addGeometry( new QgsPoint( QgsWkbTypes::Point, 11.0, 12.0 ) );
   12450                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPointZ );
   12451                 :          1 :   QVERIFY( c6.is3D() );
   12452                 :          1 :   QCOMPARE( *( static_cast< const QgsPoint * >( c6.geometryN( 0 ) ) ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) );
   12453                 :          1 :   QCOMPARE( *( static_cast< const QgsPoint * >( c6.geometryN( 1 ) ) ), QgsPoint( QgsWkbTypes::PointZ, 11, 12, 0 ) );
   12454                 :          1 :   c6.addGeometry( new QgsPoint( QgsWkbTypes::PointM, 21.0, 22.0, 0, 3 ) );
   12455                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPointZ );
   12456                 :          1 :   QVERIFY( c6.is3D() );
   12457                 :          1 :   QVERIFY( !c6.isMeasure() );
   12458                 :          1 :   QCOMPARE( *( static_cast< const QgsPoint * >( c6.geometryN( 2 ) ) ), QgsPoint( QgsWkbTypes::PointZ, 21, 22, 0 ) );
   12459                 :            : 
   12460                 :          1 :   c6.clear();
   12461                 :          1 :   c6.addGeometry( new QgsPoint( QgsWkbTypes::PointM, 1.0, 2.0, 0, 3 ) );
   12462                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPointM );
   12463                 :          1 :   c6.addGeometry( new QgsPoint( QgsWkbTypes::Point, 11.0, 12.0 ) );
   12464                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPointM );
   12465                 :          1 :   QVERIFY( c6.isMeasure() );
   12466                 :          1 :   QCOMPARE( *( static_cast< const QgsPoint * >( c6.geometryN( 0 ) ) ), QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 3 ) );
   12467                 :          1 :   QCOMPARE( *( static_cast< const QgsPoint * >( c6.geometryN( 1 ) ) ), QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 0 ) );
   12468                 :          1 :   c6.addGeometry( new QgsPoint( QgsWkbTypes::PointZ, 21.0, 22.0, 3 ) );
   12469                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPointM );
   12470                 :          1 :   QVERIFY( !c6.is3D() );
   12471                 :          1 :   QVERIFY( c6.isMeasure() );
   12472                 :          1 :   QCOMPARE( *( static_cast< const QgsPoint * >( c6.geometryN( 2 ) ) ), QgsPoint( QgsWkbTypes::PointM, 21, 22, 0, 0 ) );
   12473                 :            : 
   12474                 :          1 :   c6.clear();
   12475                 :          1 :   c6.addGeometry( new QgsPoint( QgsWkbTypes::PointZM, 1.0, 2.0, 4, 3 ) );
   12476                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPointZM );
   12477                 :          1 :   c6.addGeometry( new QgsPoint( QgsWkbTypes::Point, 11.0, 12.0 ) );
   12478                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPointZM );
   12479                 :          1 :   QVERIFY( c6.isMeasure() );
   12480                 :          1 :   QVERIFY( c6.is3D() );
   12481                 :          1 :   QCOMPARE( *( static_cast< const QgsPoint * >( c6.geometryN( 0 ) ) ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 4, 3 ) );
   12482                 :          1 :   QCOMPARE( *( static_cast< const QgsPoint * >( c6.geometryN( 1 ) ) ), QgsPoint( QgsWkbTypes::PointZM, 11, 12, 0, 0 ) );
   12483                 :          1 :   c6.addGeometry( new QgsPoint( QgsWkbTypes::PointZ, 21.0, 22.0, 3 ) );
   12484                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPointZM );
   12485                 :          1 :   QVERIFY( c6.is3D() );
   12486                 :          1 :   QVERIFY( c6.isMeasure() );
   12487                 :          1 :   QCOMPARE( *( static_cast< const QgsPoint * >( c6.geometryN( 2 ) ) ), QgsPoint( QgsWkbTypes::PointZM, 21, 22, 3, 0 ) );
   12488                 :          1 :   c6.addGeometry( new QgsPoint( QgsWkbTypes::PointM, 31.0, 32.0, 0, 4 ) );
   12489                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPointZM );
   12490                 :          1 :   QVERIFY( c6.is3D() );
   12491                 :          1 :   QVERIFY( c6.isMeasure() );
   12492                 :          1 :   QCOMPARE( *( static_cast< const QgsPoint * >( c6.geometryN( 3 ) ) ), QgsPoint( QgsWkbTypes::PointZM, 31, 32, 0, 4 ) );
   12493                 :            : 
   12494                 :            :   //clear
   12495                 :          1 :   QgsMultiPoint c7;
   12496                 :          1 :   c7.addGeometry( new  QgsPoint( QgsWkbTypes::PointZ, 0, 10, 2 ) );
   12497                 :          1 :   c7.addGeometry( new  QgsPoint( QgsWkbTypes::PointZ, 11, 12, 3 ) );
   12498                 :          1 :   QCOMPARE( c7.numGeometries(), 2 );
   12499                 :          1 :   c7.clear();
   12500                 :          1 :   QVERIFY( c7.isEmpty() );
   12501                 :          1 :   QCOMPARE( c7.numGeometries(), 0 );
   12502                 :          1 :   QCOMPARE( c7.nCoordinates(), 0 );
   12503                 :          1 :   QCOMPARE( c7.ringCount(), 0 );
   12504                 :          1 :   QCOMPARE( c7.partCount(), 0 );
   12505                 :          1 :   QVERIFY( !c7.is3D() );
   12506                 :          1 :   QVERIFY( !c7.isMeasure() );
   12507                 :          1 :   QCOMPARE( c7.wkbType(), QgsWkbTypes::MultiPoint );
   12508                 :            : 
   12509                 :            :   //clone
   12510                 :          1 :   QgsMultiPoint c11;
   12511                 :          1 :   std::unique_ptr< QgsMultiPoint >cloned( c11.clone() );
   12512                 :          1 :   QVERIFY( cloned->isEmpty() );
   12513                 :          1 :   c11.addGeometry( new QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 5 ) );
   12514                 :          1 :   c11.addGeometry( new QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) );
   12515                 :          1 :   cloned.reset( c11.clone() );
   12516                 :          1 :   QCOMPARE( cloned->numGeometries(), 2 );
   12517                 :          1 :   QCOMPARE( *static_cast< const QgsPoint * >( cloned->geometryN( 0 ) ), QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 5 ) );
   12518                 :          1 :   QCOMPARE( *static_cast< const QgsPoint * >( cloned->geometryN( 1 ) ), QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) );
   12519                 :            : 
   12520                 :            :   //copy constructor
   12521                 :          1 :   QgsMultiPoint c12;
   12522                 :          1 :   QgsMultiPoint c13( c12 );
   12523                 :          1 :   QVERIFY( c13.isEmpty() );
   12524                 :          1 :   c12.addGeometry( new QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) );
   12525                 :          1 :   c12.addGeometry( new QgsPoint( QgsWkbTypes::PointZM, 20, 10, 14, 18 ) );
   12526                 :          1 :   QgsMultiPoint c14( c12 );
   12527                 :          1 :   QCOMPARE( c14.numGeometries(), 2 );
   12528                 :          1 :   QCOMPARE( c14.wkbType(), QgsWkbTypes::MultiPointZM );
   12529                 :          1 :   QCOMPARE( *static_cast< const QgsPoint * >( c14.geometryN( 0 ) ), QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) );
   12530                 :          1 :   QCOMPARE( *static_cast< const QgsPoint * >( c14.geometryN( 1 ) ), QgsPoint( QgsWkbTypes::PointZM, 20, 10, 14, 18 ) );
   12531                 :            : 
   12532                 :            :   //assignment operator
   12533                 :          1 :   QgsMultiPoint c15;
   12534                 :          1 :   c15 = c13;
   12535                 :          1 :   QCOMPARE( c15.numGeometries(), 0 );
   12536                 :          1 :   c15 = c14;
   12537                 :          1 :   QCOMPARE( c15.numGeometries(), 2 );
   12538                 :          1 :   QCOMPARE( *static_cast< const QgsPoint * >( c15.geometryN( 0 ) ), QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) );
   12539                 :          1 :   QCOMPARE( *static_cast< const QgsPoint * >( c15.geometryN( 1 ) ), QgsPoint( QgsWkbTypes::PointZM, 20, 10, 14, 18 ) );
   12540                 :            : 
   12541                 :            :   //toCurveType
   12542                 :          1 :   std::unique_ptr< QgsMultiPoint > curveType( c12.toCurveType() );
   12543                 :          1 :   QCOMPARE( curveType->wkbType(), QgsWkbTypes::MultiPointZM );
   12544                 :          1 :   QCOMPARE( curveType->numGeometries(), 2 );
   12545                 :          1 :   const QgsPoint *curve = static_cast< const QgsPoint * >( curveType->geometryN( 0 ) );
   12546                 :          1 :   QCOMPARE( *curve, QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) );
   12547                 :          1 :   curve = static_cast< const QgsPoint * >( curveType->geometryN( 1 ) );
   12548                 :          1 :   QCOMPARE( *curve, QgsPoint( QgsWkbTypes::PointZM, 20, 10, 14, 18 ) );
   12549                 :            : 
   12550                 :            :   //to/fromWKB
   12551                 :          1 :   QgsMultiPoint c16;
   12552                 :          1 :   c16.addGeometry( new QgsPoint( QgsWkbTypes::Point, 10, 11 ) );
   12553                 :          1 :   c16.addGeometry( new QgsPoint( QgsWkbTypes::Point, 20, 21 ) );
   12554                 :          1 :   QByteArray wkb16 = c16.asWkb();
   12555                 :          1 :   QgsMultiPoint c17;
   12556                 :          1 :   QgsConstWkbPtr wkb16ptr( wkb16 );
   12557                 :          1 :   c17.fromWkb( wkb16ptr );
   12558                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   12559                 :          1 :   QCOMPARE( *static_cast< const QgsPoint * >( c17.geometryN( 0 ) ), QgsPoint( QgsWkbTypes::Point, 10, 11 ) );
   12560                 :          1 :   QCOMPARE( *static_cast< const QgsPoint * >( c17.geometryN( 1 ) ), QgsPoint( QgsWkbTypes::Point, 20, 21 ) );
   12561                 :            : 
   12562                 :            :   //parts with Z
   12563                 :          1 :   c16.clear();
   12564                 :          1 :   c17.clear();
   12565                 :          1 :   c16.addGeometry( new QgsPoint( QgsWkbTypes::PointZ, 10, 0, 4 ) );
   12566                 :          1 :   c16.addGeometry( new QgsPoint( QgsWkbTypes::PointZ, 9, 1, 4 ) );
   12567                 :          1 :   wkb16 = c16.asWkb();
   12568                 :          1 :   QgsConstWkbPtr wkb16ptr2( wkb16 );
   12569                 :          1 :   c17.fromWkb( wkb16ptr2 );
   12570                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   12571                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiPointZ );
   12572                 :          1 :   QCOMPARE( *static_cast< const QgsPoint * >( c17.geometryN( 0 ) ), QgsPoint( QgsWkbTypes::PointZ, 10, 0, 4 ) );
   12573                 :          1 :   QCOMPARE( *static_cast< const QgsPoint * >( c17.geometryN( 1 ) ), QgsPoint( QgsWkbTypes::PointZ, 9, 1, 4 ) );
   12574                 :            : 
   12575                 :            :   //parts with m
   12576                 :          1 :   c16.clear();
   12577                 :          1 :   c17.clear();
   12578                 :          1 :   c16.addGeometry( new QgsPoint( QgsWkbTypes::PointM, 10, 0, 0, 4 ) );
   12579                 :          1 :   c16.addGeometry( new QgsPoint( QgsWkbTypes::PointM, 9, 1, 0, 4 ) );
   12580                 :          1 :   wkb16 = c16.asWkb();
   12581                 :          1 :   QgsConstWkbPtr wkb16ptr3( wkb16 );
   12582                 :          1 :   c17.fromWkb( wkb16ptr3 );
   12583                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   12584                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiPointM );
   12585                 :          1 :   QCOMPARE( *static_cast< const QgsPoint * >( c17.geometryN( 0 ) ), QgsPoint( QgsWkbTypes::PointM, 10, 0, 0, 4 ) );
   12586                 :          1 :   QCOMPARE( *static_cast< const QgsPoint * >( c17.geometryN( 1 ) ), QgsPoint( QgsWkbTypes::PointM, 9, 1, 0, 4 ) );
   12587                 :            : 
   12588                 :            :   // parts with ZM
   12589                 :          1 :   c16.clear();
   12590                 :          1 :   c17.clear();
   12591                 :          1 :   c16.addGeometry( new QgsPoint( QgsWkbTypes::PointZM, 10, 0, 70, 4 ) );
   12592                 :          1 :   c16.addGeometry( new QgsPoint( QgsWkbTypes::PointZM, 9, 1, 3, 4 ) );
   12593                 :          1 :   wkb16 = c16.asWkb();
   12594                 :          1 :   QgsConstWkbPtr wkb16ptr4( wkb16 );
   12595                 :          1 :   c17.fromWkb( wkb16ptr4 );
   12596                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   12597                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiPointZM );
   12598                 :          1 :   QCOMPARE( *static_cast< const QgsPoint * >( c17.geometryN( 0 ) ), QgsPoint( QgsWkbTypes::PointZM, 10, 0, 70, 4 ) );
   12599                 :          1 :   QCOMPARE( *static_cast< const QgsPoint * >( c17.geometryN( 1 ) ), QgsPoint( QgsWkbTypes::PointZM, 9, 1, 3, 4 ) );
   12600                 :            : 
   12601                 :            :   //bad WKB - check for no crash
   12602                 :          1 :   c17.clear();
   12603                 :          1 :   QgsConstWkbPtr nullPtr( nullptr, 0 );
   12604                 :          1 :   QVERIFY( !c17.fromWkb( nullPtr ) );
   12605                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiPoint );
   12606                 :          1 :   QgsPoint point( 1, 2 );
   12607                 :          1 :   QByteArray wkbPoint = point.asWkb();
   12608                 :          1 :   QgsConstWkbPtr wkbPointPtr( wkbPoint );
   12609                 :          1 :   QVERIFY( !c17.fromWkb( wkbPointPtr ) );
   12610                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiPoint );
   12611                 :            : 
   12612                 :            :   //to/from WKT
   12613                 :          1 :   QgsMultiPoint c18;
   12614                 :          1 :   c18.addGeometry( new QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) );
   12615                 :          1 :   c18.addGeometry( new QgsPoint( QgsWkbTypes::PointZM, 9, 1, 4, 4 ) );
   12616                 :            : 
   12617                 :          1 :   QString wkt = c18.asWkt();
   12618                 :          1 :   QVERIFY( !wkt.isEmpty() );
   12619                 :          1 :   QgsMultiPoint c19;
   12620                 :          1 :   QVERIFY( c19.fromWkt( wkt ) );
   12621                 :          1 :   QCOMPARE( c19.numGeometries(), 2 );
   12622                 :          1 :   QCOMPARE( *static_cast< const QgsPoint * >( c19.geometryN( 0 ) ), QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) );
   12623                 :          1 :   QCOMPARE( *static_cast< const QgsPoint * >( c19.geometryN( 1 ) ), QgsPoint( QgsWkbTypes::PointZM, 9, 1, 4, 4 ) );
   12624                 :            : 
   12625                 :            :   //bad WKT
   12626                 :          1 :   QgsMultiPoint c20;
   12627                 :          1 :   QVERIFY( !c20.fromWkt( "Point()" ) );
   12628                 :          1 :   QVERIFY( c20.isEmpty() );
   12629                 :          1 :   QCOMPARE( c20.numGeometries(), 0 );
   12630                 :          1 :   QCOMPARE( c20.wkbType(), QgsWkbTypes::MultiPoint );
   12631                 :            : 
   12632                 :            :   //as JSON
   12633                 :          1 :   QgsMultiPoint exportC;
   12634                 :          1 :   exportC.addGeometry( new QgsPoint( QgsWkbTypes::Point, 0, 10 ) );
   12635                 :          1 :   exportC.addGeometry( new QgsPoint( QgsWkbTypes::Point, 10, 0 ) );
   12636                 :            : 
   12637                 :            :   // GML document for compare
   12638                 :          1 :   QDomDocument doc( "gml" );
   12639                 :            : 
   12640                 :            :   // as GML2
   12641                 :          2 :   QString expectedSimpleGML2( QStringLiteral( "<MultiPoint xmlns=\"gml\"><pointMember xmlns=\"gml\"><Point xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">0,10</coordinates></Point></pointMember><pointMember xmlns=\"gml\"><Point xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">10,0</coordinates></Point></pointMember></MultiPoint>" ) );
   12642                 :          1 :   QString res = elemToString( exportC.asGml2( doc ) );
   12643                 :          3 :   QGSCOMPAREGML( res, expectedSimpleGML2 );
   12644                 :          2 :   QString expectedGML2empty( QStringLiteral( "<MultiPoint xmlns=\"gml\"/>" ) );
   12645                 :          3 :   QGSCOMPAREGML( elemToString( QgsMultiPoint().asGml2( doc ) ), expectedGML2empty );
   12646                 :            : 
   12647                 :            :   //as GML3
   12648                 :          2 :   QString expectedSimpleGML3( QStringLiteral( "<MultiPoint xmlns=\"gml\"><pointMember xmlns=\"gml\"><Point xmlns=\"gml\"><pos xmlns=\"gml\" srsDimension=\"2\">0 10</pos></Point></pointMember><pointMember xmlns=\"gml\"><Point xmlns=\"gml\"><pos xmlns=\"gml\" srsDimension=\"2\">10 0</pos></Point></pointMember></MultiPoint>" ) );
   12649                 :          1 :   res = elemToString( exportC.asGml3( doc ) );
   12650                 :          1 :   QCOMPARE( res, expectedSimpleGML3 );
   12651                 :          2 :   QString expectedGML3empty( QStringLiteral( "<MultiPoint xmlns=\"gml\"/>" ) );
   12652                 :          3 :   QGSCOMPAREGML( elemToString( QgsMultiPoint().asGml3( doc ) ), expectedGML3empty );
   12653                 :            : 
   12654                 :            :   // as JSON
   12655                 :          1 :   QString expectedSimpleJson( "{\"coordinates\":[[0.0,10.0],[10.0,0.0]],\"type\":\"MultiPoint\"}" );
   12656                 :          1 :   res = exportC.asJson();
   12657                 :          1 :   QCOMPARE( res, expectedSimpleJson );
   12658                 :            : 
   12659                 :          1 :   QgsMultiPoint exportFloat;
   12660                 :          1 :   exportFloat.addGeometry( new QgsPoint( QgsWkbTypes::Point, 10 / 9.0, 100 / 9.0 ) );
   12661                 :          1 :   exportFloat.addGeometry( new QgsPoint( QgsWkbTypes::Point, 4 / 3.0, 2 / 3.0 ) );
   12662                 :            : 
   12663                 :            : 
   12664                 :          1 :   QString expectedJsonPrec3( "{\"coordinates\":[[1.111,11.111],[1.333,0.667]],\"type\":\"MultiPoint\"}" );
   12665                 :          1 :   res = exportFloat.asJson( 3 );
   12666                 :          1 :   QCOMPARE( res, expectedJsonPrec3 );
   12667                 :            : 
   12668                 :            :   // as GML2
   12669                 :          2 :   QString expectedGML2prec3( QStringLiteral( "<MultiPoint xmlns=\"gml\"><pointMember xmlns=\"gml\"><Point xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">1.111,11.111</coordinates></Point></pointMember><pointMember xmlns=\"gml\"><Point xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">1.333,0.667</coordinates></Point></pointMember></MultiPoint>" ) );
   12670                 :          1 :   res = elemToString( exportFloat.asGml2( doc, 3 ) );
   12671                 :          3 :   QGSCOMPAREGML( res, expectedGML2prec3 );
   12672                 :            : 
   12673                 :            :   //as GML3
   12674                 :          2 :   QString expectedGML3prec3( QStringLiteral( "<MultiPoint xmlns=\"gml\"><pointMember xmlns=\"gml\"><Point xmlns=\"gml\"><pos xmlns=\"gml\" srsDimension=\"2\">1.111 11.111</pos></Point></pointMember><pointMember xmlns=\"gml\"><Point xmlns=\"gml\"><pos xmlns=\"gml\" srsDimension=\"2\">1.333 0.667</pos></Point></pointMember></MultiPoint>" ) );
   12675                 :          1 :   res = elemToString( exportFloat.asGml3( doc, 3 ) );
   12676                 :          1 :   QCOMPARE( res, expectedGML3prec3 );
   12677                 :            : 
   12678                 :            :   //asKML
   12679                 :          2 :   QString expectedKml( QStringLiteral( "<MultiGeometry><Point><coordinates>0,10</coordinates></Point><Point><coordinates>10,0</coordinates></Point></MultiGeometry>" ) );
   12680                 :          1 :   QCOMPARE( exportC.asKml(), expectedKml );
   12681                 :          2 :   QString expectedKmlPrec3( QStringLiteral( "<MultiGeometry><Point><coordinates>1.111,11.111</coordinates></Point><Point><coordinates>1.333,0.667</coordinates></Point></MultiGeometry>" ) );
   12682                 :          1 :   QCOMPARE( exportFloat.asKml( 3 ), expectedKmlPrec3 );
   12683                 :            : 
   12684                 :            : 
   12685                 :            :   // insert geometry
   12686                 :          1 :   QgsMultiPoint rc;
   12687                 :          1 :   rc.clear();
   12688                 :          1 :   rc.insertGeometry( nullptr, 0 );
   12689                 :          1 :   QVERIFY( rc.isEmpty() );
   12690                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   12691                 :          1 :   rc.insertGeometry( nullptr, -1 );
   12692                 :          1 :   QVERIFY( rc.isEmpty() );
   12693                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   12694                 :          1 :   rc.insertGeometry( nullptr, 100 );
   12695                 :          1 :   QVERIFY( rc.isEmpty() );
   12696                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   12697                 :            : 
   12698                 :          1 :   rc.insertGeometry( new QgsLineString(), 0 );
   12699                 :          1 :   QVERIFY( rc.isEmpty() );
   12700                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   12701                 :            : 
   12702                 :            :   // cast
   12703                 :          1 :   QVERIFY( !QgsMultiPoint().cast( nullptr ) );
   12704                 :          1 :   QgsMultiPoint pCast;
   12705                 :          1 :   QVERIFY( QgsMultiPoint().cast( &pCast ) );
   12706                 :          1 :   QgsMultiPoint pCast2;
   12707                 :          2 :   pCast2.fromWkt( QStringLiteral( "MultiPointZ(PointZ(0 1 1))" ) );
   12708                 :          1 :   QVERIFY( QgsMultiPoint().cast( &pCast2 ) );
   12709                 :          2 :   pCast2.fromWkt( QStringLiteral( "MultiPointM(PointM(0 1 1))" ) );
   12710                 :          1 :   QVERIFY( QgsMultiPoint().cast( &pCast2 ) );
   12711                 :          2 :   pCast2.fromWkt( QStringLiteral( "MultiPointZM(PointZM(0 1 1 2))" ) );
   12712                 :          1 :   QVERIFY( QgsMultiPoint().cast( &pCast2 ) );
   12713                 :            : 
   12714                 :            :   // bounding box
   12715                 :          1 :   QgsMultiPoint boundingBox;
   12716                 :          1 :   boundingBox.addGeometry( new QgsPoint( 0, 0 ) );
   12717                 :          1 :   QCOMPARE( boundingBox.boundingBox(), QgsRectangle( 0, 0, 0, 0 ) );
   12718                 :          1 :   boundingBox.addGeometry( new QgsPoint( 1, 2 ) );
   12719                 :          1 :   QCOMPARE( boundingBox.boundingBox(), QgsRectangle( 0, 0, 1, 2 ) );
   12720                 :          1 :   QgsMultiPoint boundingBox2;
   12721                 :          1 :   QCOMPARE( boundingBox2.boundingBox(), QgsRectangle( 0, 0, 0, 0 ) );
   12722                 :          1 :   boundingBox2.addGeometry( new QgsPoint( 1, 2 ) );
   12723                 :          1 :   QCOMPARE( boundingBox2.boundingBox(), QgsRectangle( 1, 2, 1, 2 ) );
   12724                 :          1 :   boundingBox2.addGeometry( new QgsPoint( 10, 3 ) );
   12725                 :          1 :   QCOMPARE( boundingBox2.boundingBox(), QgsRectangle( 1, 2, 10, 3 ) );
   12726                 :          1 :   boundingBox2.addGeometry( new QgsPoint( 0, 0 ) );
   12727                 :          1 :   QCOMPARE( boundingBox2.boundingBox(), QgsRectangle( 0, 0, 10, 3 ) );
   12728                 :            : 
   12729                 :            :   //boundary
   12730                 :            : 
   12731                 :            :   //multipoints have no boundary defined
   12732                 :          1 :   QgsMultiPoint boundaryMP;
   12733                 :          1 :   QVERIFY( !boundaryMP.boundary() );
   12734                 :            :   // add some points and retest, should still be undefined
   12735                 :          1 :   boundaryMP.addGeometry( new QgsPoint( 0, 0 ) );
   12736                 :          1 :   boundaryMP.addGeometry( new QgsPoint( 1, 1 ) );
   12737                 :          1 :   QVERIFY( !boundaryMP.boundary() );
   12738                 :            : 
   12739                 :            :   // closestSegment
   12740                 :          1 :   QgsPoint closest;
   12741                 :          1 :   QgsVertexId after;
   12742                 :            :   // return error - points have no segments
   12743                 :          1 :   QVERIFY( boundaryMP.closestSegment( QgsPoint( 0.5, 0.5 ), closest, after ) < 0 );
   12744                 :            : 
   12745                 :            :   // vertex iterator
   12746                 :          1 :   QgsAbstractGeometry::vertex_iterator it = boundaryMP.vertices_begin();
   12747                 :          1 :   QgsAbstractGeometry::vertex_iterator itEnd = boundaryMP.vertices_end();
   12748                 :          1 :   QCOMPARE( *it, QgsPoint( 0, 0 ) );
   12749                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 0, 0, 0 ) );
   12750                 :          1 :   ++it;
   12751                 :          1 :   QCOMPARE( *it, QgsPoint( 1, 1 ) );
   12752                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 1, 0, 0 ) );
   12753                 :          1 :   ++it;
   12754                 :          1 :   QCOMPARE( it, itEnd );
   12755                 :            : 
   12756                 :            :   // Java-style iterator
   12757                 :          1 :   QgsVertexIterator it2( &boundaryMP );
   12758                 :          1 :   QVERIFY( it2.hasNext() );
   12759                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 0, 0 ) );
   12760                 :          1 :   QVERIFY( it2.hasNext() );
   12761                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 1, 1 ) );
   12762                 :          1 :   QVERIFY( !it2.hasNext() );
   12763                 :            : 
   12764                 :            :   //adjacent vertices - both should be invalid
   12765                 :          1 :   QgsMultiPoint c21;
   12766                 :          1 :   c21.addGeometry( new QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) );
   12767                 :          1 :   c21.addGeometry( new QgsPoint( QgsWkbTypes::PointZM, 9, 1, 4, 4 ) );
   12768                 :          1 :   QgsVertexId prev( 1, 2, 3 ); // start with something
   12769                 :          1 :   QgsVertexId next( 4, 5, 6 );
   12770                 :          1 :   c21.adjacentVertices( QgsVertexId( 0, 0, 0 ), prev, next );
   12771                 :          1 :   QCOMPARE( prev, QgsVertexId() );
   12772                 :          1 :   QCOMPARE( next, QgsVertexId() );
   12773                 :          1 :   c21.adjacentVertices( QgsVertexId( 1, 0, 0 ), prev, next );
   12774                 :          1 :   QCOMPARE( prev, QgsVertexId() );
   12775                 :          1 :   QCOMPARE( next, QgsVertexId() );
   12776                 :            : 
   12777                 :            :   // vertex number
   12778                 :          1 :   QgsMultiPoint c22;
   12779                 :          1 :   QCOMPARE( c22.vertexNumberFromVertexId( QgsVertexId( -1, 0, 0 ) ), -1 );
   12780                 :          1 :   QCOMPARE( c22.vertexNumberFromVertexId( QgsVertexId( 0, 0, 0 ) ), -1 );
   12781                 :          1 :   QCOMPARE( c22.vertexNumberFromVertexId( QgsVertexId( 1, 0, 0 ) ), -1 );
   12782                 :          1 :   c22.addGeometry( new QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) );
   12783                 :          1 :   c22.addGeometry( new QgsPoint( QgsWkbTypes::PointZM, 9, 1, 4, 4 ) );
   12784                 :          1 :   QCOMPARE( c22.vertexNumberFromVertexId( QgsVertexId( -1, 0, 0 ) ), -1 );
   12785                 :          1 :   QCOMPARE( c22.vertexNumberFromVertexId( QgsVertexId( 2, 0, 0 ) ), -1 );
   12786                 :          1 :   QCOMPARE( c22.vertexNumberFromVertexId( QgsVertexId( 0, 0, 0 ) ), 0 );
   12787                 :          1 :   QCOMPARE( c22.vertexNumberFromVertexId( QgsVertexId( 0, 0, 1 ) ), -1 );
   12788                 :          1 :   QCOMPARE( c22.vertexNumberFromVertexId( QgsVertexId( 0, 1, 0 ) ), -1 );
   12789                 :          1 :   QCOMPARE( c22.vertexNumberFromVertexId( QgsVertexId( 1, 0, 0 ) ), 1 );
   12790                 :          1 :   QCOMPARE( c22.vertexNumberFromVertexId( QgsVertexId( 1, 0, 1 ) ), -1 );
   12791                 :          1 :   QCOMPARE( c22.vertexNumberFromVertexId( QgsVertexId( -1, 0, 0 ) ), -1 );
   12792                 :            : 
   12793                 :          1 :   QgsMultiPoint mp;
   12794                 :            :   // multipoints should not be affected by removeDuplicatePoints
   12795                 :          1 :   QVERIFY( !mp.removeDuplicateNodes() );
   12796                 :          1 :   mp.addGeometry( new QgsPoint( QgsWkbTypes::PointZM, 10, 1, 4, 8 ) );
   12797                 :          1 :   mp.addGeometry( new QgsPoint( QgsWkbTypes::PointZM, 10, 1, 4, 8 ) );
   12798                 :          1 :   QVERIFY( !mp.removeDuplicateNodes() );
   12799                 :          1 :   QCOMPARE( mp.numGeometries(), 2 );
   12800                 :            : 
   12801                 :            :   // filter vertex
   12802                 :          1 :   QgsMultiPoint filterPoint;
   12803                 :          4 :   auto filter = []( const QgsPoint & point )-> bool
   12804                 :            :   {
   12805                 :          4 :     return point.x() < 5;
   12806                 :            :   };
   12807                 :          1 :   filterPoint.filterVertices( filter ); // no crash
   12808                 :          1 :   filterPoint.addGeometry( new QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) );
   12809                 :          1 :   filterPoint.addGeometry( new QgsPoint( QgsWkbTypes::PointZM, 3, 0, 4, 8 ) );
   12810                 :          1 :   filterPoint.addGeometry( new QgsPoint( QgsWkbTypes::PointZM, 1, 0, 4, 8 ) );
   12811                 :          1 :   filterPoint.addGeometry( new QgsPoint( QgsWkbTypes::PointZM, 11, 0, 4, 8 ) );
   12812                 :          1 :   filterPoint.filterVertices( filter );
   12813                 :          2 :   QCOMPARE( filterPoint.asWkt( 2 ), QStringLiteral( "MultiPointZM ((3 0 4 8),(1 0 4 8))" ) );
   12814                 :          1 : }
   12815                 :            : 
   12816                 :          1 : void TestQgsGeometry::multiLineString()
   12817                 :            : {
   12818                 :            :   //test constructor
   12819                 :          1 :   QgsMultiLineString c1;
   12820                 :          1 :   QVERIFY( c1.isEmpty() );
   12821                 :          1 :   QCOMPARE( c1.nCoordinates(), 0 );
   12822                 :          1 :   QCOMPARE( c1.ringCount(), 0 );
   12823                 :          1 :   QCOMPARE( c1.partCount(), 0 );
   12824                 :          1 :   QVERIFY( !c1.is3D() );
   12825                 :          1 :   QVERIFY( !c1.isMeasure() );
   12826                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::MultiLineString );
   12827                 :          1 :   QCOMPARE( c1.wktTypeStr(), QString( "MultiLineString" ) );
   12828                 :          1 :   QCOMPARE( c1.geometryType(), QString( "MultiLineString" ) );
   12829                 :          1 :   QCOMPARE( c1.dimension(), 0 );
   12830                 :          1 :   QVERIFY( !c1.hasCurvedSegments() );
   12831                 :          1 :   QCOMPARE( c1.area(), 0.0 );
   12832                 :          1 :   QCOMPARE( c1.perimeter(), 0.0 );
   12833                 :          1 :   QCOMPARE( c1.numGeometries(), 0 );
   12834                 :          1 :   QVERIFY( !c1.geometryN( 0 ) );
   12835                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   12836                 :          1 :   QCOMPARE( c1.vertexCount( 0, 0 ), 0 );
   12837                 :          1 :   QCOMPARE( c1.vertexCount( 0, 1 ), 0 );
   12838                 :          1 :   QCOMPARE( c1.vertexCount( 1, 0 ), 0 );
   12839                 :            : 
   12840                 :            :   //addGeometry
   12841                 :            : 
   12842                 :            :   //try with nullptr
   12843                 :          1 :   c1.addGeometry( nullptr );
   12844                 :          1 :   QVERIFY( c1.isEmpty() );
   12845                 :          1 :   QCOMPARE( c1.nCoordinates(), 0 );
   12846                 :          1 :   QCOMPARE( c1.ringCount(), 0 );
   12847                 :          1 :   QCOMPARE( c1.partCount(), 0 );
   12848                 :          1 :   QCOMPARE( c1.numGeometries(), 0 );
   12849                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::MultiLineString );
   12850                 :          1 :   QVERIFY( !c1.geometryN( 0 ) );
   12851                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   12852                 :            : 
   12853                 :            :   // not a linestring
   12854                 :          1 :   QVERIFY( !c1.addGeometry( new QgsPoint() ) );
   12855                 :          1 :   QVERIFY( c1.isEmpty() );
   12856                 :          1 :   QCOMPARE( c1.nCoordinates(), 0 );
   12857                 :          1 :   QCOMPARE( c1.ringCount(), 0 );
   12858                 :          1 :   QCOMPARE( c1.partCount(), 0 );
   12859                 :          1 :   QCOMPARE( c1.numGeometries(), 0 );
   12860                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::MultiLineString );
   12861                 :          1 :   QVERIFY( !c1.geometryN( 0 ) );
   12862                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   12863                 :            : 
   12864                 :            :   //valid geometry
   12865                 :          1 :   QgsLineString part;
   12866                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( 1, 10 ) << QgsPoint( 2, 11 ) );
   12867                 :          1 :   c1.addGeometry( part.clone() );
   12868                 :          1 :   QVERIFY( !c1.isEmpty() );
   12869                 :          1 :   QCOMPARE( c1.numGeometries(), 1 );
   12870                 :          1 :   QCOMPARE( c1.nCoordinates(), 2 );
   12871                 :          1 :   QCOMPARE( c1.ringCount(), 1 );
   12872                 :          1 :   QCOMPARE( c1.partCount(), 1 );
   12873                 :          1 :   QVERIFY( !c1.is3D() );
   12874                 :          1 :   QVERIFY( !c1.isMeasure() );
   12875                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::MultiLineString );
   12876                 :          1 :   QCOMPARE( c1.wktTypeStr(), QString( "MultiLineString" ) );
   12877                 :          1 :   QCOMPARE( c1.geometryType(), QString( "MultiLineString" ) );
   12878                 :          1 :   QCOMPARE( c1.dimension(), 1 );
   12879                 :          1 :   QVERIFY( !c1.hasCurvedSegments() );
   12880                 :          1 :   QCOMPARE( c1.area(), 0.0 );
   12881                 :          1 :   QCOMPARE( c1.perimeter(), 0.0 );
   12882                 :          1 :   QVERIFY( c1.geometryN( 0 ) );
   12883                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c1.geometryN( 0 ) ), part );
   12884                 :          1 :   QVERIFY( !c1.geometryN( 100 ) );
   12885                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   12886                 :          1 :   QCOMPARE( c1.vertexCount( 0, 0 ), 2 );
   12887                 :          1 :   QCOMPARE( c1.vertexCount( 1, 0 ), 0 );
   12888                 :            : 
   12889                 :            :   //initial adding of geometry should set z/m type
   12890                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 10, 11, 1 ) << QgsPoint( QgsWkbTypes::PointZ, 20, 21, 2 ) );
   12891                 :          1 :   QgsMultiLineString c2;
   12892                 :          1 :   c2.addGeometry( part.clone() );
   12893                 :          1 :   QVERIFY( c2.is3D() );
   12894                 :          1 :   QVERIFY( !c2.isMeasure() );
   12895                 :          1 :   QCOMPARE( c2.wkbType(), QgsWkbTypes::MultiLineStringZ );
   12896                 :          1 :   QCOMPARE( c2.wktTypeStr(), QString( "MultiLineStringZ" ) );
   12897                 :          1 :   QCOMPARE( c2.geometryType(), QString( "MultiLineString" ) );
   12898                 :          1 :   QCOMPARE( *( static_cast< const QgsLineString * >( c2.geometryN( 0 ) ) ), part );
   12899                 :          1 :   QgsMultiLineString c3;
   12900                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 10, 11, 0, 1 ) << QgsPoint( QgsWkbTypes::PointM, 20, 21, 0, 2 ) );
   12901                 :          1 :   c3.addGeometry( part.clone() );
   12902                 :          1 :   QVERIFY( !c3.is3D() );
   12903                 :          1 :   QVERIFY( c3.isMeasure() );
   12904                 :          1 :   QCOMPARE( c3.wkbType(), QgsWkbTypes::MultiLineStringM );
   12905                 :          1 :   QCOMPARE( c3.wktTypeStr(), QString( "MultiLineStringM" ) );
   12906                 :          1 :   QCOMPARE( *( static_cast< const QgsLineString * >( c3.geometryN( 0 ) ) ), part );
   12907                 :          1 :   QgsMultiLineString c4;
   12908                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 10, 11, 2, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 20, 21, 3, 2 ) );
   12909                 :          1 :   c4.addGeometry( part.clone() );
   12910                 :          1 :   QVERIFY( c4.is3D() );
   12911                 :          1 :   QVERIFY( c4.isMeasure() );
   12912                 :          1 :   QCOMPARE( c4.wkbType(), QgsWkbTypes::MultiLineStringZM );
   12913                 :          1 :   QCOMPARE( c4.wktTypeStr(), QString( "MultiLineStringZM" ) );
   12914                 :          1 :   QCOMPARE( *( static_cast< const QgsLineString * >( c4.geometryN( 0 ) ) ), part );
   12915                 :            : 
   12916                 :            :   //add another part
   12917                 :          1 :   QgsMultiLineString c6;
   12918                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( 1, 10 ) << QgsPoint( 2, 11 ) );
   12919                 :          1 :   c6.addGeometry( part.clone() );
   12920                 :          1 :   QCOMPARE( c6.vertexCount( 0, 0 ), 2 );
   12921                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( 9, 12 ) << QgsPoint( 3, 13 ) );
   12922                 :          1 :   c6.addGeometry( part.clone() );
   12923                 :          1 :   QCOMPARE( c6.vertexCount( 1, 0 ), 2 );
   12924                 :          1 :   QCOMPARE( c6.numGeometries(), 2 );
   12925                 :          1 :   QVERIFY( c6.geometryN( 0 ) );
   12926                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c6.geometryN( 1 ) ), part );
   12927                 :            : 
   12928                 :            :   //adding subsequent points should not alter z/m type, regardless of points type
   12929                 :          1 :   c6.clear();
   12930                 :          1 :   c6.addGeometry( part.clone() );
   12931                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiLineString );
   12932                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( 1, 10, 2 ) << QgsPoint( 2, 11, 3 ) ) ;
   12933                 :          1 :   c6.addGeometry( part.clone() );
   12934                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiLineString );
   12935                 :          1 :   QCOMPARE( c6.vertexCount( 0, 0 ), 2 );
   12936                 :          1 :   QCOMPARE( c6.vertexCount( 1, 0 ), 2 );
   12937                 :          1 :   QCOMPARE( c6.vertexCount( 2, 0 ), 0 );
   12938                 :          1 :   QCOMPARE( c6.vertexCount( -1, 0 ), 0 );
   12939                 :          1 :   QCOMPARE( c6.nCoordinates(), 4 );
   12940                 :          1 :   QCOMPARE( c6.ringCount(), 1 );
   12941                 :          1 :   QCOMPARE( c6.partCount(), 2 );
   12942                 :          1 :   QVERIFY( !c6.is3D() );
   12943                 :          1 :   const QgsLineString *ls = static_cast< const QgsLineString * >( c6.geometryN( 0 ) );
   12944                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( 9, 12 ) );
   12945                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( 3, 13 ) );
   12946                 :          1 :   ls = static_cast< const QgsLineString * >( c6.geometryN( 1 ) );
   12947                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( 1, 10 ) );
   12948                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( 2, 11 ) );
   12949                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 21, 30, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 32, 41, 0, 3 ) ) ;
   12950                 :          1 :   c6.addGeometry( part.clone() );
   12951                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiLineString );
   12952                 :          1 :   QCOMPARE( c6.vertexCount( 0, 0 ), 2 );
   12953                 :          1 :   QCOMPARE( c6.vertexCount( 1, 0 ), 2 );
   12954                 :          1 :   QCOMPARE( c6.vertexCount( 2, 0 ), 2 );
   12955                 :          1 :   QCOMPARE( c6.nCoordinates(), 6 );
   12956                 :          1 :   QCOMPARE( c6.ringCount(), 1 );
   12957                 :          1 :   QCOMPARE( c6.partCount(), 3 );
   12958                 :          1 :   QVERIFY( !c6.is3D() );
   12959                 :          1 :   QVERIFY( !c6.isMeasure() );
   12960                 :          1 :   ls = static_cast< const QgsLineString * >( c6.geometryN( 2 ) );
   12961                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( 21, 30 ) );
   12962                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( 32, 41 ) );
   12963                 :            : 
   12964                 :          1 :   c6.clear();
   12965                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( 1, 10, 2 ) << QgsPoint( 2, 11, 3 ) ) ;
   12966                 :          1 :   c6.addGeometry( part.clone() );
   12967                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiLineStringZ );
   12968                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( 2, 20 ) << QgsPoint( 3, 31 ) ) ;
   12969                 :          1 :   c6.addGeometry( part.clone() );
   12970                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiLineStringZ );
   12971                 :          1 :   QVERIFY( c6.is3D() );
   12972                 :          1 :   ls = static_cast< const QgsLineString * >( c6.geometryN( 0 ) );
   12973                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( 1, 10, 2 ) );
   12974                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( 2, 11, 3 ) );
   12975                 :          1 :   ls = static_cast< const QgsLineString * >( c6.geometryN( 1 ) );
   12976                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( 2, 20, 0 ) );
   12977                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( 3, 31, 0 ) );
   12978                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 5, 50, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 6, 61, 0, 5 ) ) ;
   12979                 :          1 :   c6.addGeometry( part.clone() );
   12980                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiLineStringZ );
   12981                 :          1 :   QVERIFY( c6.is3D() );
   12982                 :          1 :   QVERIFY( !c6.isMeasure() );
   12983                 :          1 :   ls = static_cast< const QgsLineString * >( c6.geometryN( 2 ) );
   12984                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( 5, 50, 0 ) );
   12985                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( 6, 61, 0 ) );
   12986                 :            : 
   12987                 :          1 :   c6.clear();
   12988                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiLineString );
   12989                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 5, 50, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 6, 61, 0, 5 ) ) ;
   12990                 :          1 :   c6.addGeometry( part.clone() );
   12991                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiLineStringM );
   12992                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( 2, 20 ) << QgsPoint( 3, 31 ) ) ;
   12993                 :          1 :   c6.addGeometry( part.clone() );
   12994                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiLineStringM );
   12995                 :          1 :   QVERIFY( c6.isMeasure() );
   12996                 :          1 :   ls = static_cast< const QgsLineString * >( c6.geometryN( 0 ) );
   12997                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 5, 50, 0, 4 ) );
   12998                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( QgsWkbTypes::PointM, 6, 61, 0, 5 ) );
   12999                 :          1 :   ls = static_cast< const QgsLineString * >( c6.geometryN( 1 ) );
   13000                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 2, 20, 0, 0 ) );
   13001                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( QgsWkbTypes::PointM, 3, 31, 0, 0 ) );
   13002                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( 11, 12, 13 ) << QgsPoint( 14, 15, 16 ) ) ;
   13003                 :          1 :   c6.addGeometry( part.clone() );
   13004                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiLineStringM );
   13005                 :          1 :   QVERIFY( !c6.is3D() );
   13006                 :          1 :   QVERIFY( c6.isMeasure() );
   13007                 :          1 :   ls = static_cast< const QgsLineString * >( c6.geometryN( 2 ) );
   13008                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 0 ) );
   13009                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( QgsWkbTypes::PointM, 14, 15, 0, 0 ) );
   13010                 :            : 
   13011                 :          1 :   c6.clear();
   13012                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 5, 50, 1, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 6, 61, 3, 5 ) ) ;
   13013                 :          1 :   c6.addGeometry( part.clone() );
   13014                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiLineStringZM );
   13015                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 7, 17 ) << QgsPoint( QgsWkbTypes::Point, 3, 13 ) ) ;
   13016                 :          1 :   c6.addGeometry( part.clone() );
   13017                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiLineStringZM );
   13018                 :          1 :   QVERIFY( c6.isMeasure() );
   13019                 :          1 :   QVERIFY( c6.is3D() );
   13020                 :          1 :   ls = static_cast< const QgsLineString * >( c6.geometryN( 0 ) );
   13021                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 5, 50, 1, 4 ) );
   13022                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 6, 61, 3, 5 ) );
   13023                 :          1 :   ls = static_cast< const QgsLineString * >( c6.geometryN( 1 ) );
   13024                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 7, 17, 0, 0 ) );
   13025                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 3, 13, 0, 0 ) );
   13026                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 77, 87, 7 ) << QgsPoint( QgsWkbTypes::PointZ, 83, 83, 8 ) ) ;
   13027                 :          1 :   c6.addGeometry( part.clone() );
   13028                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiLineStringZM );
   13029                 :          1 :   QVERIFY( c6.is3D() );
   13030                 :          1 :   QVERIFY( c6.isMeasure() );
   13031                 :          1 :   ls = static_cast< const QgsLineString * >( c6.geometryN( 2 ) );
   13032                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 77, 87, 7, 0 ) );
   13033                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 83, 83, 8, 0 ) );
   13034                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 177, 187, 0, 9 ) << QgsPoint( QgsWkbTypes::PointM, 183, 183, 0, 11 ) ) ;
   13035                 :          1 :   c6.addGeometry( part.clone() );
   13036                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiLineStringZM );
   13037                 :          1 :   QVERIFY( c6.is3D() );
   13038                 :          1 :   QVERIFY( c6.isMeasure() );
   13039                 :          1 :   ls = static_cast< const QgsLineString * >( c6.geometryN( 3 ) );
   13040                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 177, 187, 0, 9 ) );
   13041                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 183, 183, 0, 11 ) );
   13042                 :            : 
   13043                 :            :   //clear
   13044                 :          1 :   QgsMultiLineString c7;
   13045                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 5, 50, 1, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 6, 61, 3, 5 ) ) ;
   13046                 :          1 :   c7.addGeometry( part.clone() );
   13047                 :          1 :   c7.addGeometry( part.clone() );
   13048                 :          1 :   QCOMPARE( c7.numGeometries(), 2 );
   13049                 :          1 :   c7.clear();
   13050                 :          1 :   QVERIFY( c7.isEmpty() );
   13051                 :          1 :   QCOMPARE( c7.numGeometries(), 0 );
   13052                 :          1 :   QCOMPARE( c7.nCoordinates(), 0 );
   13053                 :          1 :   QCOMPARE( c7.ringCount(), 0 );
   13054                 :          1 :   QCOMPARE( c7.partCount(), 0 );
   13055                 :          1 :   QVERIFY( !c7.is3D() );
   13056                 :          1 :   QVERIFY( !c7.isMeasure() );
   13057                 :          1 :   QCOMPARE( c7.wkbType(), QgsWkbTypes::MultiLineString );
   13058                 :            : 
   13059                 :            :   //clone
   13060                 :          1 :   QgsMultiLineString c11;
   13061                 :          1 :   std::unique_ptr< QgsMultiLineString >cloned( c11.clone() );
   13062                 :          1 :   QVERIFY( cloned->isEmpty() );
   13063                 :          1 :   c11.addGeometry( part.clone() );
   13064                 :          1 :   c11.addGeometry( part.clone() );
   13065                 :          1 :   cloned.reset( c11.clone() );
   13066                 :          1 :   QCOMPARE( cloned->numGeometries(), 2 );
   13067                 :          1 :   ls = static_cast< const QgsLineString * >( cloned->geometryN( 0 ) );
   13068                 :          1 :   QCOMPARE( *ls, part );
   13069                 :          1 :   ls = static_cast< const QgsLineString * >( cloned->geometryN( 1 ) );
   13070                 :          1 :   QCOMPARE( *ls, part );
   13071                 :            : 
   13072                 :            :   //copy constructor
   13073                 :          1 :   QgsMultiLineString c12;
   13074                 :          1 :   QgsMultiLineString c13( c12 );
   13075                 :          1 :   QVERIFY( c13.isEmpty() );
   13076                 :          1 :   c12.addGeometry( part.clone() );
   13077                 :          1 :   c12.addGeometry( part.clone() );
   13078                 :          1 :   QgsMultiLineString c14( c12 );
   13079                 :          1 :   QCOMPARE( c14.numGeometries(), 2 );
   13080                 :          1 :   QCOMPARE( c14.wkbType(), QgsWkbTypes::MultiLineStringZM );
   13081                 :          1 :   ls = static_cast< const QgsLineString * >( c14.geometryN( 0 ) );
   13082                 :          1 :   QCOMPARE( *ls, part );
   13083                 :          1 :   ls = static_cast< const QgsLineString * >( c14.geometryN( 1 ) );
   13084                 :          1 :   QCOMPARE( *ls, part );
   13085                 :            : 
   13086                 :            :   //assignment operator
   13087                 :          1 :   QgsMultiLineString c15;
   13088                 :          1 :   c15 = c13;
   13089                 :          1 :   QCOMPARE( c15.numGeometries(), 0 );
   13090                 :          1 :   c15 = c14;
   13091                 :          1 :   QCOMPARE( c15.numGeometries(), 2 );
   13092                 :          1 :   ls = static_cast< const QgsLineString * >( c15.geometryN( 0 ) );
   13093                 :          1 :   QCOMPARE( *ls, part );
   13094                 :          1 :   ls = static_cast< const QgsLineString * >( c15.geometryN( 1 ) );
   13095                 :          1 :   QCOMPARE( *ls, part );
   13096                 :            : 
   13097                 :            :   //toCurveType
   13098                 :          1 :   std::unique_ptr< QgsMultiCurve > curveType( c12.toCurveType() );
   13099                 :          1 :   QCOMPARE( curveType->wkbType(), QgsWkbTypes::MultiCurveZM );
   13100                 :          1 :   QCOMPARE( curveType->numGeometries(), 2 );
   13101                 :          1 :   const QgsCompoundCurve *curve = static_cast< const QgsCompoundCurve * >( curveType->geometryN( 0 ) );
   13102                 :          2 :   QCOMPARE( curve->asWkt(), QStringLiteral( "CompoundCurveZM ((5 50 1 4, 6 61 3 5))" ) );
   13103                 :          1 :   curve = static_cast< const QgsCompoundCurve * >( curveType->geometryN( 1 ) );
   13104                 :          2 :   QCOMPARE( curve->asWkt(), QStringLiteral( "CompoundCurveZM ((5 50 1 4, 6 61 3 5))" ) );
   13105                 :            : 
   13106                 :            :   //to/fromWKB
   13107                 :          1 :   QgsMultiLineString c16;
   13108                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 7, 17 ) << QgsPoint( QgsWkbTypes::Point, 3, 13 ) ) ;
   13109                 :          1 :   c16.addGeometry( part.clone() );
   13110                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 27, 37 ) << QgsPoint( QgsWkbTypes::Point, 43, 43 ) ) ;
   13111                 :          1 :   c16.addGeometry( part.clone() );
   13112                 :          1 :   QByteArray wkb16 = c16.asWkb();
   13113                 :          1 :   QgsMultiLineString c17;
   13114                 :          1 :   QgsConstWkbPtr wkb16ptr( wkb16 );
   13115                 :          1 :   c17.fromWkb( wkb16ptr );
   13116                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   13117                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c17.geometryN( 0 ) ), *static_cast< const QgsLineString * >( c16.geometryN( 0 ) ) );
   13118                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c17.geometryN( 1 ) ), *static_cast< const QgsLineString * >( c16.geometryN( 1 ) ) );
   13119                 :            : 
   13120                 :            :   //parts with Z
   13121                 :          1 :   c16.clear();
   13122                 :          1 :   c17.clear();
   13123                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 7, 17, 1 ) << QgsPoint( QgsWkbTypes::PointZ, 3, 13, 4 ) ) ;
   13124                 :          1 :   c16.addGeometry( part.clone() );
   13125                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 27, 37, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 43, 43, 5 ) ) ;
   13126                 :          1 :   c16.addGeometry( part.clone() );
   13127                 :          1 :   wkb16 = c16.asWkb();
   13128                 :          1 :   QgsConstWkbPtr wkb16ptr2( wkb16 );
   13129                 :          1 :   c17.fromWkb( wkb16ptr2 );
   13130                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   13131                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiLineStringZ );
   13132                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c17.geometryN( 0 ) ), *static_cast< const QgsLineString * >( c16.geometryN( 0 ) ) );
   13133                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c17.geometryN( 1 ) ), *static_cast< const QgsLineString * >( c16.geometryN( 1 ) ) );
   13134                 :            : 
   13135                 :            :   //parts with m
   13136                 :          1 :   c16.clear();
   13137                 :          1 :   c17.clear();
   13138                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 7, 17, 0, 1 ) << QgsPoint( QgsWkbTypes::PointM, 3, 13, 0, 4 ) ) ;
   13139                 :          1 :   c16.addGeometry( part.clone() );
   13140                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 27, 37, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 43, 43, 0, 5 ) ) ;
   13141                 :          1 :   c16.addGeometry( part.clone() );
   13142                 :          1 :   wkb16 = c16.asWkb();
   13143                 :          1 :   QgsConstWkbPtr wkb16ptr3( wkb16 );
   13144                 :          1 :   c17.fromWkb( wkb16ptr3 );
   13145                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   13146                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiLineStringM );
   13147                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c17.geometryN( 0 ) ), *static_cast< const QgsLineString * >( c16.geometryN( 0 ) ) );
   13148                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c17.geometryN( 1 ) ), *static_cast< const QgsLineString * >( c16.geometryN( 1 ) ) );
   13149                 :            : 
   13150                 :            :   // parts with ZM
   13151                 :          1 :   c16.clear();
   13152                 :          1 :   c17.clear();
   13153                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 7, 17, 4, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 3, 13, 1, 4 ) ) ;
   13154                 :          1 :   c16.addGeometry( part.clone() );
   13155                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 27, 37, 6, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 43, 43, 11, 5 ) ) ;
   13156                 :          1 :   c16.addGeometry( part.clone() );
   13157                 :          1 :   wkb16 = c16.asWkb();
   13158                 :          1 :   QgsConstWkbPtr wkb16ptr4( wkb16 );
   13159                 :          1 :   c17.fromWkb( wkb16ptr4 );
   13160                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   13161                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiLineStringZM );
   13162                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c17.geometryN( 0 ) ), *static_cast< const QgsLineString * >( c16.geometryN( 0 ) ) );
   13163                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c17.geometryN( 1 ) ), *static_cast< const QgsLineString * >( c16.geometryN( 1 ) ) );
   13164                 :            : 
   13165                 :            :   //bad WKB - check for no crash
   13166                 :          1 :   c17.clear();
   13167                 :          1 :   QgsConstWkbPtr nullPtr( nullptr, 0 );
   13168                 :          1 :   QVERIFY( !c17.fromWkb( nullPtr ) );
   13169                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiLineString );
   13170                 :          1 :   QgsPoint point( 1, 2 );
   13171                 :          1 :   QByteArray wkbPoint = point.asWkb();
   13172                 :          1 :   QgsConstWkbPtr wkbPointPtr( wkbPoint );
   13173                 :          1 :   QVERIFY( !c17.fromWkb( wkbPointPtr ) );
   13174                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiLineString );
   13175                 :            : 
   13176                 :            :   //to/from WKT
   13177                 :          1 :   QgsMultiLineString c18;
   13178                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 7, 17, 4, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 3, 13, 1, 4 ) ) ;
   13179                 :          1 :   c18.addGeometry( part.clone() );
   13180                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 27, 37, 6, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 43, 43, 11, 5 ) ) ;
   13181                 :          1 :   c18.addGeometry( part.clone() );
   13182                 :            : 
   13183                 :          1 :   QString wkt = c18.asWkt();
   13184                 :          1 :   QVERIFY( !wkt.isEmpty() );
   13185                 :          1 :   QgsMultiLineString c19;
   13186                 :          1 :   QVERIFY( c19.fromWkt( wkt ) );
   13187                 :          1 :   QCOMPARE( c19.numGeometries(), 2 );
   13188                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c19.geometryN( 0 ) ), *static_cast< const QgsLineString * >( c18.geometryN( 0 ) ) );
   13189                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c19.geometryN( 1 ) ), *static_cast< const QgsLineString * >( c18.geometryN( 1 ) ) );
   13190                 :            : 
   13191                 :            :   //bad WKT
   13192                 :          1 :   QgsMultiLineString c20;
   13193                 :          1 :   QVERIFY( !c20.fromWkt( "Point()" ) );
   13194                 :          1 :   QVERIFY( c20.isEmpty() );
   13195                 :          1 :   QCOMPARE( c20.numGeometries(), 0 );
   13196                 :          1 :   QCOMPARE( c20.wkbType(), QgsWkbTypes::MultiLineString );
   13197                 :            : 
   13198                 :            :   //as JSON
   13199                 :          1 :   QgsMultiLineString exportC;
   13200                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 7, 17 ) << QgsPoint( QgsWkbTypes::Point, 3, 13 ) ) ;
   13201                 :          1 :   exportC.addGeometry( part.clone() );
   13202                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 27, 37 ) << QgsPoint( QgsWkbTypes::Point, 43, 43 ) ) ;
   13203                 :          1 :   exportC.addGeometry( part.clone() );
   13204                 :            : 
   13205                 :            :   // GML document for compare
   13206                 :          1 :   QDomDocument doc( "gml" );
   13207                 :            : 
   13208                 :            :   // as GML2
   13209                 :          2 :   QString expectedSimpleGML2( QStringLiteral( "<MultiLineString xmlns=\"gml\"><lineStringMember xmlns=\"gml\"><LineString xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">7,17 3,13</coordinates></LineString></lineStringMember><lineStringMember xmlns=\"gml\"><LineString xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">27,37 43,43</coordinates></LineString></lineStringMember></MultiLineString>" ) );
   13210                 :          1 :   QString res = elemToString( exportC.asGml2( doc ) );
   13211                 :          3 :   QGSCOMPAREGML( res, expectedSimpleGML2 );
   13212                 :          2 :   QString expectedGML2empty( QStringLiteral( "<MultiLineString xmlns=\"gml\"/>" ) );
   13213                 :          3 :   QGSCOMPAREGML( elemToString( QgsMultiLineString().asGml2( doc ) ), expectedGML2empty );
   13214                 :            : 
   13215                 :            :   //as GML3
   13216                 :          2 :   QString expectedSimpleGML3( QStringLiteral( "<MultiCurve xmlns=\"gml\"><curveMember xmlns=\"gml\"><LineString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">7 17 3 13</posList></LineString></curveMember><curveMember xmlns=\"gml\"><LineString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">27 37 43 43</posList></LineString></curveMember></MultiCurve>" ) );
   13217                 :          1 :   res = elemToString( exportC.asGml3( doc ) );
   13218                 :          1 :   QCOMPARE( res, expectedSimpleGML3 );
   13219                 :          2 :   QString expectedGML3empty( QStringLiteral( "<MultiCurve xmlns=\"gml\"/>" ) );
   13220                 :          3 :   QGSCOMPAREGML( elemToString( QgsMultiLineString().asGml3( doc ) ), expectedGML3empty );
   13221                 :            : 
   13222                 :            :   // as JSON
   13223                 :          1 :   QString expectedSimpleJson( "{\"coordinates\":[[[7.0,17.0],[3.0,13.0]],[[27.0,37.0],[43.0,43.0]]],\"type\":\"MultiLineString\"}" );
   13224                 :          1 :   res = exportC.asJson();
   13225                 :          1 :   QCOMPARE( res, expectedSimpleJson );
   13226                 :            : 
   13227                 :          1 :   QgsMultiLineString exportFloat;
   13228                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 7 / 3.0, 17 / 3.0 ) << QgsPoint( QgsWkbTypes::Point, 3 / 5.0, 13 / 3.0 ) ) ;
   13229                 :          1 :   exportFloat.addGeometry( part.clone() );
   13230                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 27 / 3.0, 37 / 9.0 ) << QgsPoint( QgsWkbTypes::Point, 43 / 41.0, 43 / 42.0 ) ) ;
   13231                 :          1 :   exportFloat.addGeometry( part.clone() );
   13232                 :            : 
   13233                 :          1 :   QString expectedJsonPrec3( "{\"coordinates\":[[[2.333,5.667],[0.6,4.333]],[[9.0,4.111],[1.049,1.024]]],\"type\":\"MultiLineString\"}" );
   13234                 :          1 :   res = exportFloat.asJson( 3 );
   13235                 :          1 :   QCOMPARE( res, expectedJsonPrec3 );
   13236                 :            : 
   13237                 :            :   // as GML2
   13238                 :          2 :   QString expectedGML2prec3( QStringLiteral( "<MultiLineString xmlns=\"gml\"><lineStringMember xmlns=\"gml\"><LineString xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">2.333,5.667 0.6,4.333</coordinates></LineString></lineStringMember><lineStringMember xmlns=\"gml\"><LineString xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">9,4.111 1.049,1.024</coordinates></LineString></lineStringMember></MultiLineString>" ) );
   13239                 :          1 :   res = elemToString( exportFloat.asGml2( doc, 3 ) );
   13240                 :          3 :   QGSCOMPAREGML( res, expectedGML2prec3 );
   13241                 :            : 
   13242                 :            :   //as GML3
   13243                 :          2 :   QString expectedGML3prec3( QStringLiteral( "<MultiCurve xmlns=\"gml\"><curveMember xmlns=\"gml\"><LineString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">2.333 5.667 0.6 4.333</posList></LineString></curveMember><curveMember xmlns=\"gml\"><LineString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">9 4.111 1.049 1.024</posList></LineString></curveMember></MultiCurve>" ) );
   13244                 :          1 :   res = elemToString( exportFloat.asGml3( doc, 3 ) );
   13245                 :          1 :   QCOMPARE( res, expectedGML3prec3 );
   13246                 :            : 
   13247                 :            :   //asKML
   13248                 :          2 :   QString expectedKml( QStringLiteral( "<MultiGeometry><LineString><altitudeMode>clampToGround</altitudeMode><coordinates>7,17,0 3,13,0</coordinates></LineString><LineString><altitudeMode>clampToGround</altitudeMode><coordinates>27,37,0 43,43,0</coordinates></LineString></MultiGeometry>" ) );
   13249                 :          1 :   QCOMPARE( exportC.asKml(), expectedKml );
   13250                 :          2 :   QString expectedKmlPrec3( QStringLiteral( "<MultiGeometry><LineString><altitudeMode>clampToGround</altitudeMode><coordinates>2.333,5.667,0 0.6,4.333,0</coordinates></LineString><LineString><altitudeMode>clampToGround</altitudeMode><coordinates>9,4.111,0 1.049,1.024,0</coordinates></LineString></MultiGeometry>" ) );
   13251                 :          1 :   QCOMPARE( exportFloat.asKml( 3 ), expectedKmlPrec3 );
   13252                 :            : 
   13253                 :            :   // insert geometry
   13254                 :          1 :   QgsMultiLineString rc;
   13255                 :          1 :   rc.clear();
   13256                 :          1 :   rc.insertGeometry( nullptr, 0 );
   13257                 :          1 :   QVERIFY( rc.isEmpty() );
   13258                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   13259                 :          1 :   rc.insertGeometry( nullptr, -1 );
   13260                 :          1 :   QVERIFY( rc.isEmpty() );
   13261                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   13262                 :          1 :   rc.insertGeometry( nullptr, 100 );
   13263                 :          1 :   QVERIFY( rc.isEmpty() );
   13264                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   13265                 :            : 
   13266                 :          1 :   rc.insertGeometry( new QgsPoint(), 0 );
   13267                 :          1 :   QVERIFY( rc.isEmpty() );
   13268                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   13269                 :            : 
   13270                 :          1 :   rc.insertGeometry( part.clone(), 0 );
   13271                 :          1 :   QVERIFY( !rc.isEmpty() );
   13272                 :          1 :   QCOMPARE( rc.numGeometries(), 1 );
   13273                 :            : 
   13274                 :            :   // cast
   13275                 :          1 :   QVERIFY( !QgsMultiLineString().cast( nullptr ) );
   13276                 :          1 :   QgsMultiLineString pCast;
   13277                 :          1 :   QVERIFY( QgsMultiLineString().cast( &pCast ) );
   13278                 :          1 :   QgsMultiLineString pCast2;
   13279                 :          2 :   pCast2.fromWkt( QStringLiteral( "MultiLineStringZ()" ) );
   13280                 :          1 :   QVERIFY( QgsMultiLineString().cast( &pCast2 ) );
   13281                 :          2 :   pCast2.fromWkt( QStringLiteral( "MultiLineStringM()" ) );
   13282                 :          1 :   QVERIFY( QgsMultiLineString().cast( &pCast2 ) );
   13283                 :          2 :   pCast2.fromWkt( QStringLiteral( "MultiLineStringZM()" ) );
   13284                 :          1 :   QVERIFY( QgsMultiLineString().cast( &pCast2 ) );
   13285                 :            : 
   13286                 :            :   //boundary
   13287                 :          1 :   QgsMultiLineString multiLine1;
   13288                 :          1 :   QVERIFY( !multiLine1.boundary() );
   13289                 :          1 :   QgsLineString boundaryLine1;
   13290                 :          1 :   boundaryLine1.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 ) );
   13291                 :          1 :   multiLine1.addGeometry( boundaryLine1.clone() );
   13292                 :          1 :   QgsAbstractGeometry *boundary = multiLine1.boundary();
   13293                 :          1 :   QgsMultiPoint *mpBoundary = dynamic_cast< QgsMultiPoint * >( boundary );
   13294                 :          1 :   QVERIFY( mpBoundary );
   13295                 :          1 :   QCOMPARE( mpBoundary->numGeometries(), 2 );
   13296                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->x(), 0.0 );
   13297                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->y(), 0.0 );
   13298                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->x(), 1.0 );
   13299                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->y(), 1.0 );
   13300                 :          1 :   delete boundary;
   13301                 :            :   // add another linestring
   13302                 :          1 :   QgsLineString boundaryLine2;
   13303                 :          1 :   boundaryLine2.setPoints( QgsPointSequence() << QgsPoint( 10, 10 ) << QgsPoint( 11, 10 ) << QgsPoint( 11, 11 ) );
   13304                 :          1 :   multiLine1.addGeometry( boundaryLine2.clone() );
   13305                 :          1 :   boundary = multiLine1.boundary();
   13306                 :          1 :   mpBoundary = dynamic_cast< QgsMultiPoint * >( boundary );
   13307                 :          1 :   QVERIFY( mpBoundary );
   13308                 :          1 :   QCOMPARE( mpBoundary->numGeometries(), 4 );
   13309                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->x(), 0.0 );
   13310                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->y(), 0.0 );
   13311                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->x(), 1.0 );
   13312                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->y(), 1.0 );
   13313                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 2 ) )->x(), 10.0 );
   13314                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 2 ) )->y(), 10.0 );
   13315                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 3 ) )->x(), 11.0 );
   13316                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 3 ) )->y(), 11.0 );
   13317                 :          1 :   delete boundary;
   13318                 :            : 
   13319                 :            :   // vertex iterator: 2 linestrings with 3 points each
   13320                 :          1 :   QgsAbstractGeometry::vertex_iterator it = multiLine1.vertices_begin();
   13321                 :          1 :   QgsAbstractGeometry::vertex_iterator itEnd = multiLine1.vertices_end();
   13322                 :          1 :   QCOMPARE( *it, QgsPoint( 0, 0 ) );
   13323                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 0, 0, 0 ) );
   13324                 :          1 :   ++it;
   13325                 :          1 :   QCOMPARE( *it, QgsPoint( 1, 0 ) );
   13326                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 0, 0, 1 ) );
   13327                 :          1 :   ++it;
   13328                 :          1 :   QCOMPARE( *it, QgsPoint( 1, 1 ) );
   13329                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 0, 0, 2 ) );
   13330                 :          1 :   ++it;
   13331                 :          1 :   QCOMPARE( *it, QgsPoint( 10, 10 ) );
   13332                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 1, 0, 0 ) );
   13333                 :          1 :   ++it;
   13334                 :          1 :   QCOMPARE( *it, QgsPoint( 11, 10 ) );
   13335                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 1, 0, 1 ) );
   13336                 :          1 :   ++it;
   13337                 :          1 :   QCOMPARE( *it, QgsPoint( 11, 11 ) );
   13338                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 1, 0, 2 ) );
   13339                 :          1 :   ++it;
   13340                 :          1 :   QCOMPARE( it, itEnd );
   13341                 :            : 
   13342                 :            :   // Java-style iterator
   13343                 :          1 :   QgsVertexIterator it2( &multiLine1 );
   13344                 :          1 :   QVERIFY( it2.hasNext() );
   13345                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 0, 0 ) );
   13346                 :          1 :   QVERIFY( it2.hasNext() );
   13347                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 1, 0 ) );
   13348                 :          1 :   QVERIFY( it2.hasNext() );
   13349                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 1, 1 ) );
   13350                 :          1 :   QVERIFY( it2.hasNext() );
   13351                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 10, 10 ) );
   13352                 :          1 :   QVERIFY( it2.hasNext() );
   13353                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 11, 10 ) );
   13354                 :          1 :   QVERIFY( it2.hasNext() );
   13355                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 11, 11 ) );
   13356                 :          1 :   QVERIFY( !it2.hasNext() );
   13357                 :            : 
   13358                 :            :   // add a closed string = no boundary
   13359                 :          1 :   QgsLineString boundaryLine3;
   13360                 :          1 :   boundaryLine3.setPoints( QgsPointSequence() << QgsPoint( 20, 20 ) << QgsPoint( 21, 20 ) << QgsPoint( 21, 21 ) << QgsPoint( 20, 20 ) );
   13361                 :          1 :   multiLine1.addGeometry( boundaryLine3.clone() );
   13362                 :          1 :   boundary = multiLine1.boundary();
   13363                 :          1 :   mpBoundary = dynamic_cast< QgsMultiPoint * >( boundary );
   13364                 :          1 :   QVERIFY( mpBoundary );
   13365                 :          1 :   QCOMPARE( mpBoundary->numGeometries(), 4 );
   13366                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->x(), 0.0 );
   13367                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->y(), 0.0 );
   13368                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->x(), 1.0 );
   13369                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->y(), 1.0 );
   13370                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 2 ) )->x(), 10.0 );
   13371                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 2 ) )->y(), 10.0 );
   13372                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 3 ) )->x(), 11.0 );
   13373                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 3 ) )->y(), 11.0 );
   13374                 :          1 :   delete boundary;
   13375                 :            : 
   13376                 :            :   //boundary with z
   13377                 :          1 :   QgsLineString boundaryLine4;
   13378                 :          1 :   boundaryLine4.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 10 ) << QgsPoint( QgsWkbTypes::PointZ, 1, 0, 15 ) << QgsPoint( QgsWkbTypes::PointZ, 1, 1, 20 ) );
   13379                 :          1 :   QgsLineString boundaryLine5;
   13380                 :          1 :   boundaryLine5.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 10, 10, 100 ) << QgsPoint( QgsWkbTypes::PointZ, 10, 20, 150 ) << QgsPoint( QgsWkbTypes::PointZ, 20, 20, 200 ) );
   13381                 :          1 :   QgsMultiLineString multiLine2;
   13382                 :          1 :   multiLine2.addGeometry( boundaryLine4.clone() );
   13383                 :          1 :   multiLine2.addGeometry( boundaryLine5.clone() );
   13384                 :            : 
   13385                 :          1 :   boundary = multiLine2.boundary();
   13386                 :          1 :   mpBoundary = dynamic_cast< QgsMultiPoint * >( boundary );
   13387                 :          1 :   QVERIFY( mpBoundary );
   13388                 :          1 :   QCOMPARE( mpBoundary->numGeometries(), 4 );
   13389                 :          1 :   QCOMPARE( mpBoundary->geometryN( 0 )->wkbType(), QgsWkbTypes::PointZ );
   13390                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->x(), 0.0 );
   13391                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->y(), 0.0 );
   13392                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->z(), 10.0 );
   13393                 :          1 :   QCOMPARE( mpBoundary->geometryN( 1 )->wkbType(), QgsWkbTypes::PointZ );
   13394                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->x(), 1.0 );
   13395                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->y(), 1.0 );
   13396                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->z(), 20.0 );
   13397                 :          1 :   QCOMPARE( mpBoundary->geometryN( 2 )->wkbType(), QgsWkbTypes::PointZ );
   13398                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 2 ) )->x(), 10.0 );
   13399                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 2 ) )->y(), 10.0 );
   13400                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 2 ) )->z(), 100.0 );
   13401                 :          1 :   QCOMPARE( mpBoundary->geometryN( 3 )->wkbType(), QgsWkbTypes::PointZ );
   13402                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 3 ) )->x(), 20.0 );
   13403                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 3 ) )->y(), 20.0 );
   13404                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 3 ) )->z(), 200.0 );
   13405                 :          1 :   delete boundary;
   13406                 :            : 
   13407                 :            :   //segmentLength
   13408                 :          1 :   QgsMultiLineString multiLine3;
   13409                 :          1 :   QgsLineString vertexLine3;
   13410                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( -1, 0, 0 ) ), 0.0 );
   13411                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 0, 0, 0 ) ), 0.0 );
   13412                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 1, 0, 0 ) ), 0.0 );
   13413                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 0, -1, 0 ) ), 0.0 );
   13414                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 0, 1, 0 ) ), 0.0 );
   13415                 :          2 :   vertexLine3.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 111, 12 )
   13416                 :          1 :                          << QgsPoint( 111, 2 ) << QgsPoint( 11, 2 ) );
   13417                 :          1 :   multiLine3.addGeometry( vertexLine3.clone() );
   13418                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId() ), 0.0 );
   13419                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 0, 0, -1 ) ), 0.0 );
   13420                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 0, 0, 0 ) ), 10.0 );
   13421                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 0, 0, 1 ) ), 100.0 );
   13422                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 0, 0, 2 ) ), 10.0 );
   13423                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 0, 0, 3 ) ), 100.0 );
   13424                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 0, 0, 4 ) ), 0.0 );
   13425                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( -1, 0, -1 ) ), 0.0 );
   13426                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( -1, 0, 0 ) ), 0.0 );
   13427                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 0, -1, 0 ) ), 10.0 );
   13428                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 1, 1, 0 ) ), 0.0 );
   13429                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 1, 1, 1 ) ), 0.0 );
   13430                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 1, 0, 1 ) ), 0.0 );
   13431                 :            : 
   13432                 :            :   // add another line
   13433                 :          2 :   vertexLine3.setPoints( QgsPointSequence() << QgsPoint( 30, 6 ) << QgsPoint( 34, 6 ) << QgsPoint( 34, 8 )
   13434                 :          1 :                          << QgsPoint( 30, 8 ) << QgsPoint( 30, 6 ) );
   13435                 :          1 :   multiLine3.addGeometry( vertexLine3.clone() );
   13436                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId() ), 0.0 );
   13437                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 0, 0, -1 ) ), 0.0 );
   13438                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 0, 0, 0 ) ), 10.0 );
   13439                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 0, 0, 1 ) ), 100.0 );
   13440                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 0, 0, 2 ) ), 10.0 );
   13441                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 0, 0, 3 ) ), 100.0 );
   13442                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 0, 0, 4 ) ), 0.0 );
   13443                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( -1, 0, -1 ) ), 0.0 );
   13444                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( -1, 0, 0 ) ), 0.0 );
   13445                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 0, -1, 0 ) ), 10.0 );
   13446                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 1, 0, -1 ) ), 0.0 );
   13447                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 1, 0, 0 ) ), 4.0 );
   13448                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 1, 0, 1 ) ), 2.0 );
   13449                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 1, 0, 2 ) ), 4.0 );
   13450                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 1, 0, 3 ) ), 2.0 );
   13451                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 1, 0, 4 ) ), 0.0 );
   13452                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 1, 1, 1 ) ), 2.0 );
   13453                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 1, 1, 2 ) ), 4.0 );
   13454                 :          1 :   QCOMPARE( multiLine3.segmentLength( QgsVertexId( 2, 0, 0 ) ), 0.0 );
   13455                 :          1 : }
   13456                 :            : 
   13457                 :          1 : void TestQgsGeometry::multiCurve()
   13458                 :            : {
   13459                 :            :   //test constructor
   13460                 :          1 :   QgsMultiCurve c1;
   13461                 :          1 :   QVERIFY( c1.isEmpty() );
   13462                 :          1 :   QCOMPARE( c1.nCoordinates(), 0 );
   13463                 :          1 :   QCOMPARE( c1.ringCount(), 0 );
   13464                 :          1 :   QCOMPARE( c1.partCount(), 0 );
   13465                 :          1 :   QVERIFY( !c1.is3D() );
   13466                 :          1 :   QVERIFY( !c1.isMeasure() );
   13467                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::MultiCurve );
   13468                 :          1 :   QCOMPARE( c1.wktTypeStr(), QString( "MultiCurve" ) );
   13469                 :          1 :   QCOMPARE( c1.geometryType(), QString( "MultiCurve" ) );
   13470                 :          1 :   QCOMPARE( c1.dimension(), 0 );
   13471                 :          1 :   QVERIFY( !c1.hasCurvedSegments() );
   13472                 :          1 :   QCOMPARE( c1.area(), 0.0 );
   13473                 :          1 :   QCOMPARE( c1.perimeter(), 0.0 );
   13474                 :          1 :   QCOMPARE( c1.numGeometries(), 0 );
   13475                 :          1 :   QVERIFY( !c1.geometryN( 0 ) );
   13476                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   13477                 :          1 :   QCOMPARE( c1.vertexCount( 0, 0 ), 0 );
   13478                 :          1 :   QCOMPARE( c1.vertexCount( 0, 1 ), 0 );
   13479                 :          1 :   QCOMPARE( c1.vertexCount( 1, 0 ), 0 );
   13480                 :            : 
   13481                 :            :   //addGeometry
   13482                 :            :   //try with nullptr
   13483                 :          1 :   c1.addGeometry( nullptr );
   13484                 :          1 :   QVERIFY( c1.isEmpty() );
   13485                 :          1 :   QCOMPARE( c1.nCoordinates(), 0 );
   13486                 :          1 :   QCOMPARE( c1.ringCount(), 0 );
   13487                 :          1 :   QCOMPARE( c1.partCount(), 0 );
   13488                 :          1 :   QCOMPARE( c1.numGeometries(), 0 );
   13489                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::MultiCurve );
   13490                 :          1 :   QVERIFY( !c1.geometryN( 0 ) );
   13491                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   13492                 :            : 
   13493                 :            :   // not a curve
   13494                 :          1 :   QVERIFY( !c1.addGeometry( new QgsPoint() ) );
   13495                 :          1 :   QVERIFY( c1.isEmpty() );
   13496                 :          1 :   QCOMPARE( c1.nCoordinates(), 0 );
   13497                 :          1 :   QCOMPARE( c1.ringCount(), 0 );
   13498                 :          1 :   QCOMPARE( c1.partCount(), 0 );
   13499                 :          1 :   QCOMPARE( c1.numGeometries(), 0 );
   13500                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::MultiCurve );
   13501                 :          1 :   QVERIFY( !c1.geometryN( 0 ) );
   13502                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   13503                 :            : 
   13504                 :            :   //valid geometry
   13505                 :          1 :   QgsCircularString part;
   13506                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( 1, 10 ) << QgsPoint( 2, 11 ) << QgsPoint( 1, 12 ) );
   13507                 :          1 :   c1.addGeometry( part.clone() );
   13508                 :          1 :   QVERIFY( !c1.isEmpty() );
   13509                 :          1 :   QCOMPARE( c1.numGeometries(), 1 );
   13510                 :          1 :   QCOMPARE( c1.nCoordinates(), 3 );
   13511                 :          1 :   QCOMPARE( c1.ringCount(), 1 );
   13512                 :          1 :   QCOMPARE( c1.partCount(), 1 );
   13513                 :          1 :   QVERIFY( !c1.is3D() );
   13514                 :          1 :   QVERIFY( !c1.isMeasure() );
   13515                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::MultiCurve );
   13516                 :          1 :   QCOMPARE( c1.wktTypeStr(), QString( "MultiCurve" ) );
   13517                 :          1 :   QCOMPARE( c1.geometryType(), QString( "MultiCurve" ) );
   13518                 :          1 :   QCOMPARE( c1.dimension(), 1 );
   13519                 :          1 :   QVERIFY( c1.hasCurvedSegments() );
   13520                 :          1 :   QCOMPARE( c1.area(), 0.0 );
   13521                 :          1 :   QCOMPARE( c1.perimeter(), 0.0 );
   13522                 :          1 :   QVERIFY( c1.geometryN( 0 ) );
   13523                 :          1 :   QCOMPARE( *static_cast< const QgsCircularString * >( c1.geometryN( 0 ) ), part );
   13524                 :          1 :   QVERIFY( !c1.geometryN( 100 ) );
   13525                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   13526                 :          1 :   QCOMPARE( c1.vertexCount( 0, 0 ), 3 );
   13527                 :          1 :   QCOMPARE( c1.vertexCount( 1, 0 ), 0 );
   13528                 :            : 
   13529                 :            :   //initial adding of geometry should set z/m type
   13530                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 10, 11, 1 ) << QgsPoint( QgsWkbTypes::PointZ, 20, 21, 2 )
   13531                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 10, 31, 3 ) );
   13532                 :          1 :   QgsMultiCurve c2;
   13533                 :          1 :   c2.addGeometry( part.clone() );
   13534                 :          1 :   QVERIFY( c2.is3D() );
   13535                 :          1 :   QVERIFY( !c2.isMeasure() );
   13536                 :          1 :   QCOMPARE( c2.wkbType(), QgsWkbTypes::MultiCurveZ );
   13537                 :          1 :   QCOMPARE( c2.wktTypeStr(), QString( "MultiCurveZ" ) );
   13538                 :          1 :   QCOMPARE( c2.geometryType(), QString( "MultiCurve" ) );
   13539                 :          1 :   QCOMPARE( *( static_cast< const QgsCircularString * >( c2.geometryN( 0 ) ) ), part );
   13540                 :          1 :   QgsMultiCurve c3;
   13541                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 10, 11, 0, 1 ) << QgsPoint( QgsWkbTypes::PointM, 20, 21, 0, 2 )
   13542                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 10, 31, 0, 3 ) );
   13543                 :          1 :   c3.addGeometry( part.clone() );
   13544                 :          1 :   QVERIFY( !c3.is3D() );
   13545                 :          1 :   QVERIFY( c3.isMeasure() );
   13546                 :          1 :   QCOMPARE( c3.wkbType(), QgsWkbTypes::MultiCurveM );
   13547                 :          1 :   QCOMPARE( c3.wktTypeStr(), QString( "MultiCurveM" ) );
   13548                 :          1 :   QCOMPARE( *( static_cast< const QgsCircularString * >( c3.geometryN( 0 ) ) ), part );
   13549                 :          1 :   QgsMultiCurve c4;
   13550                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 10, 11, 2, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 20, 21, 3, 2 )
   13551                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 10, 31, 4, 5 ) );
   13552                 :          1 :   c4.addGeometry( part.clone() );
   13553                 :          1 :   QVERIFY( c4.is3D() );
   13554                 :          1 :   QVERIFY( c4.isMeasure() );
   13555                 :          1 :   QCOMPARE( c4.wkbType(), QgsWkbTypes::MultiCurveZM );
   13556                 :          1 :   QCOMPARE( c4.wktTypeStr(), QString( "MultiCurveZM" ) );
   13557                 :          1 :   QCOMPARE( *( static_cast< const QgsCircularString * >( c4.geometryN( 0 ) ) ), part );
   13558                 :            : 
   13559                 :            :   //add another part
   13560                 :          1 :   QgsMultiCurve c6;
   13561                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( 1, 10 ) << QgsPoint( 2, 11 ) << QgsPoint( 1, 20 ) );
   13562                 :          1 :   c6.addGeometry( part.clone() );
   13563                 :          1 :   QCOMPARE( c6.vertexCount( 0, 0 ), 3 );
   13564                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( 9, 12 ) << QgsPoint( 3, 13 )  << QgsPoint( 9, 20 ) );
   13565                 :          1 :   c6.addGeometry( part.clone() );
   13566                 :          1 :   QCOMPARE( c6.vertexCount( 1, 0 ), 3 );
   13567                 :          1 :   QCOMPARE( c6.numGeometries(), 2 );
   13568                 :          1 :   QVERIFY( c6.geometryN( 0 ) );
   13569                 :          1 :   QCOMPARE( *static_cast< const QgsCircularString * >( c6.geometryN( 1 ) ), part );
   13570                 :            : 
   13571                 :            :   //adding subsequent points should not alter z/m type, regardless of parts type
   13572                 :          1 :   c6.clear();
   13573                 :          1 :   c6.addGeometry( part.clone() );
   13574                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiCurve );
   13575                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( 1, 10, 2 ) << QgsPoint( 2, 11, 3 ) << QgsPoint( 1, 20, 4 ) ) ;
   13576                 :          1 :   c6.addGeometry( part.clone() );
   13577                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiCurve );
   13578                 :          1 :   QCOMPARE( c6.vertexCount( 0, 0 ), 3 );
   13579                 :          1 :   QCOMPARE( c6.vertexCount( 1, 0 ), 3 );
   13580                 :          1 :   QCOMPARE( c6.vertexCount( 2, 0 ), 0 );
   13581                 :          1 :   QCOMPARE( c6.vertexCount( -1, 0 ), 0 );
   13582                 :          1 :   QCOMPARE( c6.nCoordinates(), 6 );
   13583                 :          1 :   QCOMPARE( c6.ringCount(), 1 );
   13584                 :          1 :   QCOMPARE( c6.partCount(), 2 );
   13585                 :          1 :   QVERIFY( !c6.is3D() );
   13586                 :          1 :   const QgsCircularString *ls = static_cast< const QgsCircularString * >( c6.geometryN( 0 ) );
   13587                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( 9, 12 ) );
   13588                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( 3, 13 ) );
   13589                 :          1 :   QCOMPARE( ls->pointN( 2 ), QgsPoint( 9, 20 ) );
   13590                 :          1 :   ls = static_cast< const QgsCircularString * >( c6.geometryN( 1 ) );
   13591                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( 1, 10 ) );
   13592                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( 2, 11 ) );
   13593                 :          1 :   QCOMPARE( ls->pointN( 2 ), QgsPoint( 1, 20 ) );
   13594                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 21, 30, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 32, 41, 0, 3 )
   13595                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 21, 51, 0, 4 ) ) ;
   13596                 :          1 :   c6.addGeometry( part.clone() );
   13597                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiCurve );
   13598                 :          1 :   QCOMPARE( c6.vertexCount( 0, 0 ), 3 );
   13599                 :          1 :   QCOMPARE( c6.vertexCount( 1, 0 ), 3 );
   13600                 :          1 :   QCOMPARE( c6.vertexCount( 2, 0 ), 3 );
   13601                 :          1 :   QCOMPARE( c6.nCoordinates(), 9 );
   13602                 :          1 :   QCOMPARE( c6.ringCount(), 1 );
   13603                 :          1 :   QCOMPARE( c6.partCount(), 3 );
   13604                 :          1 :   QVERIFY( !c6.is3D() );
   13605                 :          1 :   QVERIFY( !c6.isMeasure() );
   13606                 :          1 :   ls = static_cast< const QgsCircularString * >( c6.geometryN( 2 ) );
   13607                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( 21, 30 ) );
   13608                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( 32, 41 ) );
   13609                 :          1 :   QCOMPARE( ls->pointN( 2 ), QgsPoint( 21, 51 ) );
   13610                 :            : 
   13611                 :          1 :   c6.clear();
   13612                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( 1, 10, 2 ) << QgsPoint( 2, 11, 3 ) << QgsPoint( 1, 21, 4 ) ) ;
   13613                 :          1 :   c6.addGeometry( part.clone() );
   13614                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiCurveZ );
   13615                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( 2, 20 ) << QgsPoint( 3, 31 ) << QgsPoint( 2, 41 ) ) ;
   13616                 :          1 :   c6.addGeometry( part.clone() );
   13617                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiCurveZ );
   13618                 :          1 :   QVERIFY( c6.is3D() );
   13619                 :          1 :   ls = static_cast< const QgsCircularString * >( c6.geometryN( 0 ) );
   13620                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( 1, 10, 2 ) );
   13621                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( 2, 11, 3 ) );
   13622                 :          1 :   QCOMPARE( ls->pointN( 2 ), QgsPoint( 1, 21, 4 ) );
   13623                 :          1 :   ls = static_cast< const QgsCircularString * >( c6.geometryN( 1 ) );
   13624                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( 2, 20, 0 ) );
   13625                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( 3, 31, 0 ) );
   13626                 :          1 :   QCOMPARE( ls->pointN( 2 ), QgsPoint( 2, 41, 0 ) );
   13627                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 5, 50, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 6, 61, 0, 5 )
   13628                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 5, 71, 0, 6 ) ) ;
   13629                 :          1 :   c6.addGeometry( part.clone() );
   13630                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiCurveZ );
   13631                 :          1 :   QVERIFY( c6.is3D() );
   13632                 :          1 :   QVERIFY( !c6.isMeasure() );
   13633                 :          1 :   ls = static_cast< const QgsCircularString * >( c6.geometryN( 2 ) );
   13634                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( 5, 50, 0 ) );
   13635                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( 6, 61, 0 ) );
   13636                 :          1 :   QCOMPARE( ls->pointN( 2 ), QgsPoint( 5, 71, 0 ) );
   13637                 :            : 
   13638                 :          1 :   c6.clear();
   13639                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiCurve );
   13640                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 5, 50, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 6, 61, 0, 5 )
   13641                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 5, 71, 0, 5 ) ) ;
   13642                 :          1 :   c6.addGeometry( part.clone() );
   13643                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiCurveM );
   13644                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( 2, 20 ) << QgsPoint( 3, 31 )   << QgsPoint( 2, 41 ) ) ;
   13645                 :          1 :   c6.addGeometry( part.clone() );
   13646                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiCurveM );
   13647                 :          1 :   QVERIFY( c6.isMeasure() );
   13648                 :          1 :   ls = static_cast< const QgsCircularString * >( c6.geometryN( 0 ) );
   13649                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 5, 50, 0, 4 ) );
   13650                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( QgsWkbTypes::PointM, 6, 61, 0, 5 ) );
   13651                 :          1 :   QCOMPARE( ls->pointN( 2 ), QgsPoint( QgsWkbTypes::PointM, 5, 71, 0, 5 ) );
   13652                 :          1 :   ls = static_cast< const QgsCircularString * >( c6.geometryN( 1 ) );
   13653                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 2, 20, 0, 0 ) );
   13654                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( QgsWkbTypes::PointM, 3, 31, 0, 0 ) );
   13655                 :          1 :   QCOMPARE( ls->pointN( 2 ), QgsPoint( QgsWkbTypes::PointM, 2, 41, 0, 0 ) );
   13656                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( 11, 12, 13 ) << QgsPoint( 14, 15, 16 ) << QgsPoint( 11, 25, 17 ) ) ;
   13657                 :          1 :   c6.addGeometry( part.clone() );
   13658                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiCurveM );
   13659                 :          1 :   QVERIFY( !c6.is3D() );
   13660                 :          1 :   QVERIFY( c6.isMeasure() );
   13661                 :          1 :   ls = static_cast< const QgsCircularString * >( c6.geometryN( 2 ) );
   13662                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 0 ) );
   13663                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( QgsWkbTypes::PointM, 14, 15, 0, 0 ) );
   13664                 :          1 :   QCOMPARE( ls->pointN( 2 ), QgsPoint( QgsWkbTypes::PointM, 11, 25, 0, 0 ) );
   13665                 :            : 
   13666                 :          1 :   c6.clear();
   13667                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 5, 50, 1, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 6, 61, 3, 5 )
   13668                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 5, 71, 4, 6 ) ) ;
   13669                 :          1 :   c6.addGeometry( part.clone() );
   13670                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiCurveZM );
   13671                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 7, 17 ) << QgsPoint( QgsWkbTypes::Point, 3, 13 )
   13672                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 7, 11 ) ) ;
   13673                 :          1 :   c6.addGeometry( part.clone() );
   13674                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiCurveZM );
   13675                 :          1 :   QVERIFY( c6.isMeasure() );
   13676                 :          1 :   QVERIFY( c6.is3D() );
   13677                 :          1 :   ls = static_cast< const QgsCircularString * >( c6.geometryN( 0 ) );
   13678                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 5, 50, 1, 4 ) );
   13679                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 6, 61, 3, 5 ) );
   13680                 :          1 :   QCOMPARE( ls->pointN( 2 ), QgsPoint( QgsWkbTypes::PointZM, 5, 71, 4, 6 ) );
   13681                 :          1 :   ls = static_cast< const QgsCircularString * >( c6.geometryN( 1 ) );
   13682                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 7, 17, 0, 0 ) );
   13683                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 3, 13, 0, 0 ) );
   13684                 :          1 :   QCOMPARE( ls->pointN( 2 ), QgsPoint( QgsWkbTypes::PointZM, 7, 11, 0, 0 ) );
   13685                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 77, 87, 7 ) << QgsPoint( QgsWkbTypes::PointZ, 83, 83, 8 )
   13686                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 77, 81, 9 ) ) ;
   13687                 :          1 :   c6.addGeometry( part.clone() );
   13688                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiCurveZM );
   13689                 :          1 :   QVERIFY( c6.is3D() );
   13690                 :          1 :   QVERIFY( c6.isMeasure() );
   13691                 :          1 :   ls = static_cast< const QgsCircularString * >( c6.geometryN( 2 ) );
   13692                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 77, 87, 7, 0 ) );
   13693                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 83, 83, 8, 0 ) );
   13694                 :          1 :   QCOMPARE( ls->pointN( 2 ), QgsPoint( QgsWkbTypes::PointZM, 77, 81, 9, 0 ) );
   13695                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 177, 187, 0, 9 ) << QgsPoint( QgsWkbTypes::PointM, 183, 183, 0, 11 )
   13696                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 177, 181, 0, 13 ) ) ;
   13697                 :          1 :   c6.addGeometry( part.clone() );
   13698                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiCurveZM );
   13699                 :          1 :   QVERIFY( c6.is3D() );
   13700                 :          1 :   QVERIFY( c6.isMeasure() );
   13701                 :          1 :   ls = static_cast< const QgsCircularString * >( c6.geometryN( 3 ) );
   13702                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 177, 187, 0, 9 ) );
   13703                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 183, 183, 0, 11 ) );
   13704                 :          1 :   QCOMPARE( ls->pointN( 2 ), QgsPoint( QgsWkbTypes::PointZM, 177, 181, 0, 13 ) );
   13705                 :            : 
   13706                 :            :   //clear
   13707                 :          1 :   QgsMultiCurve c7;
   13708                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 5, 50, 1, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 6, 61, 3, 5 )
   13709                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 5, 71, 4, 6 ) ) ;
   13710                 :          1 :   c7.addGeometry( part.clone() );
   13711                 :          1 :   c7.addGeometry( part.clone() );
   13712                 :          1 :   QCOMPARE( c7.numGeometries(), 2 );
   13713                 :          1 :   c7.clear();
   13714                 :          1 :   QVERIFY( c7.isEmpty() );
   13715                 :          1 :   QCOMPARE( c7.numGeometries(), 0 );
   13716                 :          1 :   QCOMPARE( c7.nCoordinates(), 0 );
   13717                 :          1 :   QCOMPARE( c7.ringCount(), 0 );
   13718                 :          1 :   QCOMPARE( c7.partCount(), 0 );
   13719                 :          1 :   QVERIFY( !c7.is3D() );
   13720                 :          1 :   QVERIFY( !c7.isMeasure() );
   13721                 :          1 :   QCOMPARE( c7.wkbType(), QgsWkbTypes::MultiCurve );
   13722                 :            : 
   13723                 :            :   //clone
   13724                 :          1 :   QgsMultiCurve c11;
   13725                 :          1 :   std::unique_ptr< QgsMultiCurve >cloned( c11.clone() );
   13726                 :          1 :   QVERIFY( cloned->isEmpty() );
   13727                 :          1 :   c11.addGeometry( part.clone() );
   13728                 :          1 :   c11.addGeometry( part.clone() );
   13729                 :          1 :   cloned.reset( c11.clone() );
   13730                 :          1 :   QCOMPARE( cloned->numGeometries(), 2 );
   13731                 :          1 :   ls = static_cast< const QgsCircularString * >( cloned->geometryN( 0 ) );
   13732                 :          1 :   QCOMPARE( *ls, part );
   13733                 :          1 :   ls = static_cast< const QgsCircularString * >( cloned->geometryN( 1 ) );
   13734                 :          1 :   QCOMPARE( *ls, part );
   13735                 :            : 
   13736                 :            :   //copy constructor
   13737                 :          1 :   QgsMultiCurve c12;
   13738                 :          1 :   QgsMultiCurve c13( c12 );
   13739                 :          1 :   QVERIFY( c13.isEmpty() );
   13740                 :          1 :   c12.addGeometry( part.clone() );
   13741                 :          1 :   c12.addGeometry( part.clone() );
   13742                 :          1 :   QgsMultiCurve c14( c12 );
   13743                 :          1 :   QCOMPARE( c14.numGeometries(), 2 );
   13744                 :          1 :   QCOMPARE( c14.wkbType(), QgsWkbTypes::MultiCurveZM );
   13745                 :          1 :   ls = static_cast< const QgsCircularString * >( c14.geometryN( 0 ) );
   13746                 :          1 :   QCOMPARE( *ls, part );
   13747                 :          1 :   ls = static_cast< const QgsCircularString * >( c14.geometryN( 1 ) );
   13748                 :          1 :   QCOMPARE( *ls, part );
   13749                 :            : 
   13750                 :            :   //assignment operator
   13751                 :          1 :   QgsMultiCurve c15;
   13752                 :          1 :   c15 = c13;
   13753                 :          1 :   QCOMPARE( c15.numGeometries(), 0 );
   13754                 :          1 :   c15 = c14;
   13755                 :          1 :   QCOMPARE( c15.numGeometries(), 2 );
   13756                 :          1 :   ls = static_cast< const QgsCircularString * >( c15.geometryN( 0 ) );
   13757                 :          1 :   QCOMPARE( *ls, part );
   13758                 :          1 :   ls = static_cast< const QgsCircularString * >( c15.geometryN( 1 ) );
   13759                 :          1 :   QCOMPARE( *ls, part );
   13760                 :            : 
   13761                 :            :   //toCurveType
   13762                 :          1 :   std::unique_ptr< QgsMultiCurve > curveType( c12.toCurveType() );
   13763                 :          1 :   QCOMPARE( curveType->wkbType(), QgsWkbTypes::MultiCurveZM );
   13764                 :          1 :   QCOMPARE( curveType->numGeometries(), 2 );
   13765                 :          1 :   const QgsCircularString *curve = static_cast< const QgsCircularString * >( curveType->geometryN( 0 ) );
   13766                 :          1 :   QCOMPARE( *curve, *static_cast< const QgsCircularString * >( c12.geometryN( 0 ) ) );
   13767                 :          1 :   curve = static_cast< const QgsCircularString * >( curveType->geometryN( 1 ) );
   13768                 :          1 :   QCOMPARE( *curve, *static_cast< const QgsCircularString * >( c12.geometryN( 1 ) ) );
   13769                 :            : 
   13770                 :            :   //to/fromWKB
   13771                 :          1 :   QgsMultiCurve c16;
   13772                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 7, 17 ) << QgsPoint( QgsWkbTypes::Point, 3, 13 ) << QgsPoint( QgsWkbTypes::Point, 7, 11 ) ) ;
   13773                 :          1 :   c16.addGeometry( part.clone() );
   13774                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 27, 37 ) << QgsPoint( QgsWkbTypes::Point, 43, 43 )  << QgsPoint( QgsWkbTypes::Point, 27, 54 ) ) ;
   13775                 :          1 :   c16.addGeometry( part.clone() );
   13776                 :          1 :   QByteArray wkb16 = c16.asWkb();
   13777                 :          1 :   QgsMultiCurve c17;
   13778                 :          1 :   QgsConstWkbPtr wkb16ptr( wkb16 );
   13779                 :          1 :   c17.fromWkb( wkb16ptr );
   13780                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   13781                 :          1 :   QCOMPARE( *static_cast< const QgsCircularString * >( c17.geometryN( 0 ) ), *static_cast< const QgsCircularString * >( c16.geometryN( 0 ) ) );
   13782                 :          1 :   QCOMPARE( *static_cast< const QgsCircularString * >( c17.geometryN( 1 ) ), *static_cast< const QgsCircularString * >( c16.geometryN( 1 ) ) );
   13783                 :            : 
   13784                 :            :   //parts with Z
   13785                 :          1 :   c16.clear();
   13786                 :          1 :   c17.clear();
   13787                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 7, 17, 1 ) << QgsPoint( QgsWkbTypes::PointZ, 3, 13, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 7, 11, 3 ) ) ;
   13788                 :          1 :   c16.addGeometry( part.clone() );
   13789                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 27, 37, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 43, 43, 5 ) << QgsPoint( QgsWkbTypes::PointZ, 27, 53, 6 ) ) ;
   13790                 :          1 :   c16.addGeometry( part.clone() );
   13791                 :          1 :   wkb16 = c16.asWkb();
   13792                 :          1 :   QgsConstWkbPtr wkb16ptr2( wkb16 );
   13793                 :          1 :   c17.fromWkb( wkb16ptr2 );
   13794                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   13795                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiCurveZ );
   13796                 :          1 :   QCOMPARE( *static_cast< const QgsCircularString * >( c17.geometryN( 0 ) ), *static_cast< const QgsCircularString * >( c16.geometryN( 0 ) ) );
   13797                 :          1 :   QCOMPARE( *static_cast< const QgsCircularString * >( c17.geometryN( 1 ) ), *static_cast< const QgsCircularString * >( c16.geometryN( 1 ) ) );
   13798                 :            : 
   13799                 :            :   //parts with m
   13800                 :          1 :   c16.clear();
   13801                 :          1 :   c17.clear();
   13802                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 7, 17, 0, 1 ) << QgsPoint( QgsWkbTypes::PointM, 3, 13, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 7, 11, 0, 5 ) ) ;
   13803                 :          1 :   c16.addGeometry( part.clone() );
   13804                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 27, 37, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 43, 43, 0, 5 ) << QgsPoint( QgsWkbTypes::PointM, 27, 53, 0, 7 ) ) ;
   13805                 :          1 :   c16.addGeometry( part.clone() );
   13806                 :          1 :   wkb16 = c16.asWkb();
   13807                 :          1 :   QgsConstWkbPtr wkb16ptr3( wkb16 );
   13808                 :          1 :   c17.fromWkb( wkb16ptr3 );
   13809                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   13810                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiCurveM );
   13811                 :          1 :   QCOMPARE( *static_cast< const QgsCircularString * >( c17.geometryN( 0 ) ), *static_cast< const QgsCircularString * >( c16.geometryN( 0 ) ) );
   13812                 :          1 :   QCOMPARE( *static_cast< const QgsCircularString * >( c17.geometryN( 1 ) ), *static_cast< const QgsCircularString * >( c16.geometryN( 1 ) ) );
   13813                 :            : 
   13814                 :            :   // parts with ZM
   13815                 :          1 :   c16.clear();
   13816                 :          1 :   c17.clear();
   13817                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 7, 17, 4, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 3, 13, 1, 4 )  << QgsPoint( QgsWkbTypes::PointZM, 7, 11, 2, 5 ) ) ;
   13818                 :          1 :   c16.addGeometry( part.clone() );
   13819                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 27, 37, 6, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 43, 43, 11, 5 ) << QgsPoint( QgsWkbTypes::PointZM, 27, 47, 12, 15 ) ) ;
   13820                 :          1 :   c16.addGeometry( part.clone() );
   13821                 :          1 :   wkb16 = c16.asWkb();
   13822                 :          1 :   QgsConstWkbPtr wkb16ptr4( wkb16 );
   13823                 :          1 :   c17.fromWkb( wkb16ptr4 );
   13824                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   13825                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiCurveZM );
   13826                 :          1 :   QCOMPARE( *static_cast< const QgsCircularString * >( c17.geometryN( 0 ) ), *static_cast< const QgsCircularString * >( c16.geometryN( 0 ) ) );
   13827                 :          1 :   QCOMPARE( *static_cast< const QgsCircularString * >( c17.geometryN( 1 ) ), *static_cast< const QgsCircularString * >( c16.geometryN( 1 ) ) );
   13828                 :            : 
   13829                 :            :   //bad WKB - check for no crash
   13830                 :          1 :   c17.clear();
   13831                 :          1 :   QgsConstWkbPtr nullPtr( nullptr, 0 );
   13832                 :          1 :   QVERIFY( !c17.fromWkb( nullPtr ) );
   13833                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiCurve );
   13834                 :          1 :   QgsPoint point( 1, 2 );
   13835                 :          1 :   QByteArray wkbPoint = point.asWkb();
   13836                 :          1 :   QgsConstWkbPtr wkbPointPtr( wkbPoint );
   13837                 :          1 :   QVERIFY( !c17.fromWkb( wkbPointPtr ) );
   13838                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiCurve );
   13839                 :            : 
   13840                 :            :   //to/from WKT
   13841                 :          1 :   QgsMultiCurve c18;
   13842                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 7, 17, 4, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 3, 13, 1, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 7, 11, 2, 8 ) ) ;
   13843                 :          1 :   c18.addGeometry( part.clone() );
   13844                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 27, 37, 6, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 43, 43, 11, 5 )  << QgsPoint( QgsWkbTypes::PointZM, 27, 53, 21, 52 ) ) ;
   13845                 :          1 :   c18.addGeometry( part.clone() );
   13846                 :            : 
   13847                 :          1 :   QString wkt = c18.asWkt();
   13848                 :          1 :   QVERIFY( !wkt.isEmpty() );
   13849                 :          1 :   QgsMultiCurve c19;
   13850                 :          1 :   QVERIFY( c19.fromWkt( wkt ) );
   13851                 :          1 :   QCOMPARE( c19.numGeometries(), 2 );
   13852                 :          1 :   QCOMPARE( *static_cast< const QgsCircularString * >( c19.geometryN( 0 ) ), *static_cast< const QgsCircularString * >( c18.geometryN( 0 ) ) );
   13853                 :          1 :   QCOMPARE( *static_cast< const QgsCircularString * >( c19.geometryN( 1 ) ), *static_cast< const QgsCircularString * >( c18.geometryN( 1 ) ) );
   13854                 :            : 
   13855                 :            :   //bad WKT
   13856                 :          1 :   QgsMultiCurve c20;
   13857                 :          1 :   QVERIFY( !c20.fromWkt( "Point()" ) );
   13858                 :          1 :   QVERIFY( c20.isEmpty() );
   13859                 :          1 :   QCOMPARE( c20.numGeometries(), 0 );
   13860                 :          1 :   QCOMPARE( c20.wkbType(), QgsWkbTypes::MultiCurve );
   13861                 :            : 
   13862                 :            :   //as JSON
   13863                 :          1 :   QgsMultiCurve exportC;
   13864                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 7, 17 ) << QgsPoint( QgsWkbTypes::Point, 3, 13 ) << QgsPoint( QgsWkbTypes::Point, 7, 11 ) ) ;
   13865                 :          1 :   exportC.addGeometry( part.clone() );
   13866                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 27, 37 ) << QgsPoint( QgsWkbTypes::Point, 43, 43 )  << QgsPoint( QgsWkbTypes::Point, 27, 47 ) ) ;
   13867                 :          1 :   exportC.addGeometry( part.clone() );
   13868                 :            : 
   13869                 :            :   // GML document for compare
   13870                 :          1 :   QDomDocument doc( "gml" );
   13871                 :            : 
   13872                 :            :   // as GML2
   13873                 :          2 :   QString expectedSimpleGML2( QStringLiteral( "<MultiLineString xmlns=\"gml\"><lineStringMember xmlns=\"gml\"><LineString xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">7,17 6.9,17 6.9,17 6.8,17 6.8,17.1 6.7,17.1 6.7,17.1 6.6,17.1 6.6,17.1 6.5,17.1 6.5,17.1 6.4,17.1 6.4,17.1 6.3,17.1 6.2,17.2 6.2,17.2 6.1,17.2 6.1,17.2 6,17.2 6,17.2 5.9,17.2 5.9,17.2 5.8,17.2 5.7,17.2 5.7,17.1 5.6,17.1 5.6,17.1 5.5,17.1 5.5,17.1 5.4,17.1 5.4,17.1 5.3,17.1 5.3,17.1 5.2,17.1 5.2,17 5.1,17 5,17 5,17 4.9,17 4.9,17 4.8,16.9 4.8,16.9 4.7,16.9 4.7,16.9 4.6,16.9 4.6,16.8 4.5,16.8 4.5,16.8 4.4,16.8 4.4,16.7 4.3,16.7 4.3,16.7 4.3,16.6 4.2,16.6 4.2,16.6 4.1,16.5 4.1,16.5 4,16.5 4,16.4 3.9,16.4 3.9,16.4 3.9,16.3 3.8,16.3 3.8,16.3 3.7,16.2 3.7,16.2 3.7,16.1 3.6,16.1 3.6,16.1 3.6,16 3.5,16 3.5,15.9 3.5,15.9 3.4,15.8 3.4,15.8 3.4,15.7 3.3,15.7 3.3,15.7 3.3,15.6 3.2,15.6 3.2,15.5 3.2,15.5 3.2,15.4 3.1,15.4 3.1,15.3 3.1,15.3 3.1,15.2 3.1,15.2 3,15.1 3,15.1 3,15 3,15 3,14.9 3,14.8 2.9,14.8 2.9,14.7 2.9,14.7 2.9,14.6 2.9,14.6 2.9,14.5 2.9,14.5 2.9,14.4 2.9,14.4 2.9,14.3 2.8,14.2 2.8,14.2 2.8,14.1 2.8,14.1 2.8,14 2.8,14 2.8,13.9 2.8,13.9 2.8,13.8 2.8,13.8 2.9,13.7 2.9,13.6 2.9,13.6 2.9,13.5 2.9,13.5 2.9,13.4 2.9,13.4 2.9,13.3 2.9,13.3 2.9,13.2 3,13.2 3,13.1 3,13 3,13 3,12.9 3,12.9 3.1,12.8 3.1,12.8 3.1,12.7 3.1,12.7 3.1,12.6 3.2,12.6 3.2,12.5 3.2,12.5 3.2,12.4 3.3,12.4 3.3,12.3 3.3,12.3 3.4,12.3 3.4,12.2 3.4,12.2 3.5,12.1 3.5,12.1 3.5,12 3.6,12 3.6,11.9 3.6,11.9 3.7,11.9 3.7,11.8 3.7,11.8 3.8,11.7 3.8,11.7 3.9,11.7 3.9,11.6 3.9,11.6 4,11.6 4,11.5 4.1,11.5 4.1,11.5 4.2,11.4 4.2,11.4 4.3,11.4 4.3,11.3 4.3,11.3 4.4,11.3 4.4,11.2 4.5,11.2 4.5,11.2 4.6,11.2 4.6,11.1 4.7,11.1 4.7,11.1 4.8,11.1 4.8,11.1 4.9,11 4.9,11 5,11 5,11 5.1,11 5.2,11 5.2,10.9 5.3,10.9 5.3,10.9 5.4,10.9 5.4,10.9 5.5,10.9 5.5,10.9 5.6,10.9 5.6,10.9 5.7,10.9 5.7,10.8 5.8,10.8 5.9,10.8 5.9,10.8 6,10.8 6,10.8 6.1,10.8 6.1,10.8 6.2,10.8 6.2,10.8 6.3,10.9 6.4,10.9 6.4,10.9 6.5,10.9 6.5,10.9 6.6,10.9 6.6,10.9 6.7,10.9 6.7,10.9 6.8,10.9 6.8,11 6.9,11 6.9,11 7,11</coordinates></LineString></lineStringMember><lineStringMember xmlns=\"gml\"><LineString xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">27,37 27.1,36.9 27.2,36.8 27.3,36.6 27.4,36.5 27.5,36.4 27.6,36.3 27.7,36.2 27.8,36 27.9,35.9 28,35.8 28.1,35.7 28.2,35.6 28.3,35.5 28.4,35.4 28.5,35.3 28.7,35.2 28.8,35.1 28.9,35 29,34.9 29.1,34.8 29.3,34.7 29.4,34.6 29.5,34.6 29.7,34.5 29.8,34.4 29.9,34.3 30.1,34.3 30.2,34.2 30.3,34.1 30.5,34 30.6,34 30.7,33.9 30.9,33.9 31,33.8 31.2,33.7 31.3,33.7 31.5,33.6 31.6,33.6 31.8,33.6 31.9,33.5 32.1,33.5 32.2,33.4 32.4,33.4 32.5,33.4 32.7,33.3 32.8,33.3 33,33.3 33.1,33.3 33.3,33.2 33.4,33.2 33.6,33.2 33.7,33.2 33.9,33.2 34,33.2 34.2,33.2 34.3,33.2 34.5,33.2 34.6,33.2 34.8,33.2 34.9,33.2 35.1,33.2 35.3,33.3 35.4,33.3 35.6,33.3 35.7,33.3 35.9,33.3 36,33.4 36.2,33.4 36.3,33.4 36.5,33.5 36.6,33.5 36.8,33.6 36.9,33.6 37.1,33.7 37.2,33.7 37.3,33.8 37.5,33.8 37.6,33.9 37.8,33.9 37.9,34 38,34.1 38.2,34.1 38.3,34.2 38.5,34.3 38.6,34.3 38.7,34.4 38.9,34.5 39,34.6 39.1,34.7 39.2,34.7 39.4,34.8 39.5,34.9 39.6,35 39.7,35.1 39.9,35.2 40,35.3 40.1,35.4 40.2,35.5 40.3,35.6 40.4,35.7 40.5,35.8 40.6,35.9 40.7,36.1 40.8,36.2 40.9,36.3 41,36.4 41.1,36.5 41.2,36.6 41.3,36.8 41.4,36.9 41.5,37 41.6,37.1 41.7,37.3 41.8,37.4 41.8,37.5 41.9,37.7 42,37.8 42.1,37.9 42.1,38.1 42.2,38.2 42.3,38.3 42.3,38.5 42.4,38.6 42.4,38.8 42.5,38.9 42.6,39.1 42.6,39.2 42.6,39.4 42.7,39.5 42.7,39.6 42.8,39.8 42.8,39.9 42.8,40.1 42.9,40.2 42.9,40.4 42.9,40.5 43,40.7 43,40.9 43,41 43,41.2 43,41.3 43,41.5 43,41.6 43.1,41.8 43.1,41.9 43.1,42.1 43.1,42.2 43,42.4 43,42.5 43,42.7 43,42.8 43,43 43,43.1 43,43.3 42.9,43.5 42.9,43.6 42.9,43.8 42.8,43.9 42.8,44.1 42.8,44.2 42.7,44.4 42.7,44.5 42.6,44.6 42.6,44.8 42.6,44.9 42.5,45.1 42.4,45.2 42.4,45.4 42.3,45.5 42.3,45.7 42.2,45.8 42.1,45.9 42.1,46.1 42,46.2 41.9,46.3 41.8,46.5 41.8,46.6 41.7,46.7 41.6,46.9 41.5,47 41.4,47.1 41.3,47.2 41.2,47.4 41.1,47.5 41,47.6 40.9,47.7 40.8,47.8 40.7,47.9 40.6,48.1 40.5,48.2 40.4,48.3 40.3,48.4 40.2,48.5 40.1,48.6 40,48.7 39.9,48.8 39.7,48.9 39.6,49 39.5,49.1 39.4,49.2 39.2,49.3 39.1,49.3 39,49.4 38.9,49.5 38.7,49.6 38.6,49.7 38.5,49.7 38.3,49.8 38.2,49.9 38,49.9 37.9,50 37.8,50.1 37.6,50.1 37.5,50.2 37.3,50.2 37.2,50.3 37.1,50.3 36.9,50.4 36.8,50.4 36.6,50.5 36.5,50.5 36.3,50.6 36.2,50.6 36,50.6 35.9,50.7 35.7,50.7 35.6,50.7 35.4,50.7 35.3,50.7 35.1,50.8 34.9,50.8 34.8,50.8 34.6,50.8 34.5,50.8 34.3,50.8 34.2,50.8 34,50.8 33.9,50.8 33.7,50.8 33.6,50.8 33.4,50.8 33.3,50.8 33.1,50.7 33,50.7 32.8,50.7 32.7,50.7 32.5,50.6 32.4,50.6 32.2,50.6 32.1,50.5 31.9,50.5 31.8,50.4 31.6,50.4 31.5,50.4 31.3,50.3 31.2,50.3 31,50.2 30.9,50.1 30.7,50.1 30.6,50 30.5,50 30.3,49.9 30.2,49.8 30.1,49.7 29.9,49.7 29.8,49.6 29.7,49.5 29.5,49.4 29.4,49.4 29.3,49.3 29.1,49.2 29,49.1 28.9,49 28.8,48.9 28.7,48.8 28.5,48.7 28.4,48.6 28.3,48.5 28.2,48.4 28.1,48.3 28,48.2 27.9,48.1 27.8,48 27.7,47.8 27.6,47.7 27.5,47.6 27.4,47.5 27.3,47.4 27.2,47.2 27.1,47.1 27,47</coordinates></LineString></lineStringMember></MultiLineString>" ) );
   13874                 :          1 :   QString res = elemToString( exportC.asGml2( doc, 1 ) );
   13875                 :          3 :   QGSCOMPAREGML( res, expectedSimpleGML2 );
   13876                 :          2 :   QString expectedGML2empty( QStringLiteral( "<MultiLineString xmlns=\"gml\"/>" ) );
   13877                 :          3 :   QGSCOMPAREGML( elemToString( QgsMultiCurve().asGml2( doc ) ), expectedGML2empty );
   13878                 :            : 
   13879                 :            :   //as GML3
   13880                 :          2 :   QString expectedSimpleGML3( QStringLiteral( "<MultiCurve xmlns=\"gml\"><curveMember xmlns=\"gml\"><Curve xmlns=\"gml\"><segments xmlns=\"gml\"><ArcString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">7 17 3 13 7 11</posList></ArcString></segments></Curve></curveMember><curveMember xmlns=\"gml\"><Curve xmlns=\"gml\"><segments xmlns=\"gml\"><ArcString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">27 37 43 43 27 47</posList></ArcString></segments></Curve></curveMember></MultiCurve>" ) );
   13881                 :          1 :   res = elemToString( exportC.asGml3( doc ) );
   13882                 :          1 :   QCOMPARE( res, expectedSimpleGML3 );
   13883                 :          2 :   QString expectedGML3empty( QStringLiteral( "<MultiCurve xmlns=\"gml\"/>" ) );
   13884                 :          3 :   QGSCOMPAREGML( elemToString( QgsMultiCurve().asGml3( doc ) ), expectedGML3empty );
   13885                 :            : 
   13886                 :            :   // as JSON
   13887                 :          1 :   QString expectedSimpleJson( "{\"coordinates\":[[[7.0,17.0],[6.9,17.0],[6.9,17.0],[6.8,17.0],[6.8,17.1],[6.7,17.1],[6.7,17.1],[6.6,17.1],[6.6,17.1],[6.5,17.1],[6.5,17.1],[6.4,17.1],[6.4,17.1],[6.3,17.1],[6.2,17.2],[6.2,17.2],[6.1,17.2],[6.1,17.2],[6.0,17.2],[6.0,17.2],[5.9,17.2],[5.9,17.2],[5.8,17.2],[5.7,17.2],[5.7,17.1],[5.6,17.1],[5.6,17.1],[5.5,17.1],[5.5,17.1],[5.4,17.1],[5.4,17.1],[5.3,17.1],[5.3,17.1],[5.2,17.1],[5.2,17.0],[5.1,17.0],[5.0,17.0],[5.0,17.0],[4.9,17.0],[4.9,17.0],[4.8,16.9],[4.8,16.9],[4.7,16.9],[4.7,16.9],[4.6,16.9],[4.6,16.8],[4.5,16.8],[4.5,16.8],[4.4,16.8],[4.4,16.7],[4.3,16.7],[4.3,16.7],[4.3,16.6],[4.2,16.6],[4.2,16.6],[4.1,16.5],[4.1,16.5],[4.0,16.5],[4.0,16.4],[3.9,16.4],[3.9,16.4],[3.9,16.3],[3.8,16.3],[3.8,16.3],[3.7,16.2],[3.7,16.2],[3.7,16.1],[3.6,16.1],[3.6,16.1],[3.6,16.0],[3.5,16.0],[3.5,15.9],[3.5,15.9],[3.4,15.8],[3.4,15.8],[3.4,15.7],[3.3,15.7],[3.3,15.7],[3.3,15.6],[3.2,15.6],[3.2,15.5],[3.2,15.5],[3.2,15.4],[3.1,15.4],[3.1,15.3],[3.1,15.3],[3.1,15.2],[3.1,15.2],[3.0,15.1],[3.0,15.1],[3.0,15.0],[3.0,15.0],[3.0,14.9],[3.0,14.8],[2.9,14.8],[2.9,14.7],[2.9,14.7],[2.9,14.6],[2.9,14.6],[2.9,14.5],[2.9,14.5],[2.9,14.4],[2.9,14.4],[2.9,14.3],[2.8,14.2],[2.8,14.2],[2.8,14.1],[2.8,14.1],[2.8,14.0],[2.8,14.0],[2.8,13.9],[2.8,13.9],[2.8,13.8],[2.8,13.8],[2.9,13.7],[2.9,13.6],[2.9,13.6],[2.9,13.5],[2.9,13.5],[2.9,13.4],[2.9,13.4],[2.9,13.3],[2.9,13.3],[2.9,13.2],[3.0,13.2],[3.0,13.1],[3.0,13.0],[3.0,13.0],[3.0,12.9],[3.0,12.9],[3.1,12.8],[3.1,12.8],[3.1,12.7],[3.1,12.7],[3.1,12.6],[3.2,12.6],[3.2,12.5],[3.2,12.5],[3.2,12.4],[3.3,12.4],[3.3,12.3],[3.3,12.3],[3.4,12.3],[3.4,12.2],[3.4,12.2],[3.5,12.1],[3.5,12.1],[3.5,12.0],[3.6,12.0],[3.6,11.9],[3.6,11.9],[3.7,11.9],[3.7,11.8],[3.7,11.8],[3.8,11.7],[3.8,11.7],[3.9,11.7],[3.9,11.6],[3.9,11.6],[4.0,11.6],[4.0,11.5],[4.1,11.5],[4.1,11.5],[4.2,11.4],[4.2,11.4],[4.3,11.4],[4.3,11.3],[4.3,11.3],[4.4,11.3],[4.4,11.2],[4.5,11.2],[4.5,11.2],[4.6,11.2],[4.6,11.1],[4.7,11.1],[4.7,11.1],[4.8,11.1],[4.8,11.1],[4.9,11.0],[4.9,11.0],[5.0,11.0],[5.0,11.0],[5.1,11.0],[5.2,11.0],[5.2,10.9],[5.3,10.9],[5.3,10.9],[5.4,10.9],[5.4,10.9],[5.5,10.9],[5.5,10.9],[5.6,10.9],[5.6,10.9],[5.7,10.9],[5.7,10.8],[5.8,10.8],[5.9,10.8],[5.9,10.8],[6.0,10.8],[6.0,10.8],[6.1,10.8],[6.1,10.8],[6.2,10.8],[6.2,10.8],[6.3,10.9],[6.4,10.9],[6.4,10.9],[6.5,10.9],[6.5,10.9],[6.6,10.9],[6.6,10.9],[6.7,10.9],[6.7,10.9],[6.8,10.9],[6.8,11.0],[6.9,11.0],[6.9,11.0],[7.0,11.0]],[[27.0,37.0],[27.1,36.9],[27.2,36.8],[27.3,36.6],[27.4,36.5],[27.5,36.4],[27.6,36.3],[27.7,36.2],[27.8,36.0],[27.9,35.9],[28.0,35.8],[28.1,35.7],[28.2,35.6],[28.3,35.5],[28.4,35.4],[28.5,35.3],[28.7,35.2],[28.8,35.1],[28.9,35.0],[29.0,34.9],[29.1,34.8],[29.3,34.7],[29.4,34.6],[29.5,34.6],[29.7,34.5],[29.8,34.4],[29.9,34.3],[30.1,34.3],[30.2,34.2],[30.3,34.1],[30.5,34.0],[30.6,34.0],[30.7,33.9],[30.9,33.9],[31.0,33.8],[31.2,33.7],[31.3,33.7],[31.5,33.6],[31.6,33.6],[31.8,33.6],[31.9,33.5],[32.1,33.5],[32.2,33.4],[32.4,33.4],[32.5,33.4],[32.7,33.3],[32.8,33.3],[33.0,33.3],[33.1,33.3],[33.3,33.2],[33.4,33.2],[33.6,33.2],[33.7,33.2],[33.9,33.2],[34.0,33.2],[34.2,33.2],[34.3,33.2],[34.5,33.2],[34.6,33.2],[34.8,33.2],[34.9,33.2],[35.1,33.2],[35.3,33.3],[35.4,33.3],[35.6,33.3],[35.7,33.3],[35.9,33.3],[36.0,33.4],[36.2,33.4],[36.3,33.4],[36.5,33.5],[36.6,33.5],[36.8,33.6],[36.9,33.6],[37.1,33.7],[37.2,33.7],[37.3,33.8],[37.5,33.8],[37.6,33.9],[37.8,33.9],[37.9,34.0],[38.0,34.1],[38.2,34.1],[38.3,34.2],[38.5,34.3],[38.6,34.3],[38.7,34.4],[38.9,34.5],[39.0,34.6],[39.1,34.7],[39.2,34.7],[39.4,34.8],[39.5,34.9],[39.6,35.0],[39.7,35.1],[39.9,35.2],[40.0,35.3],[40.1,35.4],[40.2,35.5],[40.3,35.6],[40.4,35.7],[40.5,35.8],[40.6,35.9],[40.7,36.1],[40.8,36.2],[40.9,36.3],[41.0,36.4],[41.1,36.5],[41.2,36.6],[41.3,36.8],[41.4,36.9],[41.5,37.0],[41.6,37.1],[41.7,37.3],[41.8,37.4],[41.8,37.5],[41.9,37.7],[42.0,37.8],[42.1,37.9],[42.1,38.1],[42.2,38.2],[42.3,38.3],[42.3,38.5],[42.4,38.6],[42.4,38.8],[42.5,38.9],[42.6,39.1],[42.6,39.2],[42.6,39.4],[42.7,39.5],[42.7,39.6],[42.8,39.8],[42.8,39.9],[42.8,40.1],[42.9,40.2],[42.9,40.4],[42.9,40.5],[43.0,40.7],[43.0,40.9],[43.0,41.0],[43.0,41.2],[43.0,41.3],[43.0,41.5],[43.0,41.6],[43.1,41.8],[43.1,41.9],[43.1,42.1],[43.1,42.2],[43.0,42.4],[43.0,42.5],[43.0,42.7],[43.0,42.8],[43.0,43.0],[43.0,43.1],[43.0,43.3],[42.9,43.5],[42.9,43.6],[42.9,43.8],[42.8,43.9],[42.8,44.1],[42.8,44.2],[42.7,44.4],[42.7,44.5],[42.6,44.6],[42.6,44.8],[42.6,44.9],[42.5,45.1],[42.4,45.2],[42.4,45.4],[42.3,45.5],[42.3,45.7],[42.2,45.8],[42.1,45.9],[42.1,46.1],[42.0,46.2],[41.9,46.3],[41.8,46.5],[41.8,46.6],[41.7,46.7],[41.6,46.9],[41.5,47.0],[41.4,47.1],[41.3,47.2],[41.2,47.4],[41.1,47.5],[41.0,47.6],[40.9,47.7],[40.8,47.8],[40.7,47.9],[40.6,48.1],[40.5,48.2],[40.4,48.3],[40.3,48.4],[40.2,48.5],[40.1,48.6],[40.0,48.7],[39.9,48.8],[39.7,48.9],[39.6,49.0],[39.5,49.1],[39.4,49.2],[39.2,49.3],[39.1,49.3],[39.0,49.4],[38.9,49.5],[38.7,49.6],[38.6,49.7],[38.5,49.7],[38.3,49.8],[38.2,49.9],[38.0,49.9],[37.9,50.0],[37.8,50.1],[37.6,50.1],[37.5,50.2],[37.3,50.2],[37.2,50.3],[37.1,50.3],[36.9,50.4],[36.8,50.4],[36.6,50.5],[36.5,50.5],[36.3,50.6],[36.2,50.6],[36.0,50.6],[35.9,50.7],[35.7,50.7],[35.6,50.7],[35.4,50.7],[35.3,50.7],[35.1,50.8],[34.9,50.8],[34.8,50.8],[34.6,50.8],[34.5,50.8],[34.3,50.8],[34.2,50.8],[34.0,50.8],[33.9,50.8],[33.7,50.8],[33.6,50.8],[33.4,50.8],[33.3,50.8],[33.1,50.7],[33.0,50.7],[32.8,50.7],[32.7,50.7],[32.5,50.6],[32.4,50.6],[32.2,50.6],[32.1,50.5],[31.9,50.5],[31.8,50.4],[31.6,50.4],[31.5,50.4],[31.3,50.3],[31.2,50.3],[31.0,50.2],[30.9,50.1],[30.7,50.1],[30.6,50.0],[30.5,50.0],[30.3,49.9],[30.2,49.8],[30.1,49.7],[29.9,49.7],[29.8,49.6],[29.7,49.5],[29.5,49.4],[29.4,49.4],[29.3,49.3],[29.1,49.2],[29.0,49.1],[28.9,49.0],[28.8,48.9],[28.7,48.8],[28.5,48.7],[28.4,48.6],[28.3,48.5],[28.2,48.4],[28.1,48.3],[28.0,48.2],[27.9,48.1],[27.8,48.0],[27.7,47.8],[27.6,47.7],[27.5,47.6],[27.4,47.5],[27.3,47.4],[27.2,47.2],[27.1,47.1],[27.0,47.0]]],\"type\":\"MultiLineString\"}" );
   13888                 :          1 :   res = exportC.asJson( 1 );
   13889                 :          1 :   QCOMPARE( res, expectedSimpleJson );
   13890                 :            : 
   13891                 :          1 :   QgsMultiCurve exportFloat;
   13892                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 7 / 3.0, 17 / 3.0 ) << QgsPoint( QgsWkbTypes::Point, 3 / 5.0, 13 / 3.0 ) << QgsPoint( QgsWkbTypes::Point, 7 / 3.0, 11 / 3.0 ) ) ;
   13893                 :          1 :   exportFloat.addGeometry( part.clone() );
   13894                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 27 / 3.0, 37 / 9.0 ) << QgsPoint( QgsWkbTypes::Point, 43 / 41.0, 43 / 42.0 ) << QgsPoint( QgsWkbTypes::Point, 27 / 3.0, 1 / 3.0 ) ) ;
   13895                 :          1 :   exportFloat.addGeometry( part.clone() );
   13896                 :            : 
   13897                 :          2 :   QString expectedJsonPrec3( QStringLiteral( "{\"coordinates\":[[[2.333,5.667],[2.316,5.677],[2.298,5.687],[2.28,5.697],[2.262,5.707],[2.244,5.716],[2.226,5.725],[2.207,5.734],[2.188,5.742],[2.17,5.75],[2.151,5.757],[2.131,5.765],[2.112,5.772],[2.093,5.778],[2.074,5.785],[2.054,5.79],[2.034,5.796],[2.015,5.801],[1.995,5.806],[1.975,5.811],[1.955,5.815],[1.935,5.819],[1.915,5.822],[1.894,5.826],[1.874,5.828],[1.854,5.831],[1.834,5.833],[1.813,5.835],[1.793,5.836],[1.773,5.837],[1.752,5.838],[1.732,5.838],[1.711,5.838],[1.691,5.838],[1.67,5.837],[1.65,5.836],[1.63,5.834],[1.609,5.833],[1.589,5.83],[1.569,5.828],[1.548,5.825],[1.528,5.822],[1.508,5.818],[1.488,5.814],[1.468,5.81],[1.448,5.805],[1.428,5.801],[1.409,5.795],[1.389,5.79],[1.37,5.784],[1.35,5.777],[1.331,5.771],[1.312,5.764],[1.293,5.756],[1.274,5.749],[1.255,5.741],[1.236,5.732],[1.218,5.724],[1.199,5.715],[1.181,5.705],[1.163,5.696],[1.145,5.686],[1.128,5.676],[1.11,5.665],[1.093,5.654],[1.076,5.643],[1.059,5.632],[1.042,5.62],[1.025,5.608],[1.009,5.596],[0.993,5.583],[0.977,5.57],[0.962,5.557],[0.946,5.543],[0.931,5.53],[0.916,5.516],[0.901,5.502],[0.887,5.487],[0.873,5.473],[0.859,5.458],[0.845,5.442],[0.832,5.427],[0.819,5.411],[0.806,5.395],[0.793,5.379],[0.781,5.363],[0.769,5.346],[0.757,5.33],[0.746,5.313],[0.735,5.296],[0.724,5.278],[0.713,5.261],[0.703,5.243],[0.693,5.225],[0.684,5.207],[0.674,5.189],[0.666,5.171],[0.657,5.152],[0.649,5.133],[0.641,5.115],[0.633,5.096],[0.626,5.077],[0.619,5.057],[0.612,5.038],[0.606,5.019],[0.6,4.999],[0.594,4.979],[0.589,4.96],[0.584,4.94],[0.579,4.92],[0.575,4.9],[0.571,4.88],[0.568,4.86],[0.564,4.84],[0.562,4.819],[0.559,4.799],[0.557,4.779],[0.555,4.759],[0.554,4.738],[0.553,4.718],[0.552,4.697],[0.552,4.677],[0.552,4.656],[0.552,4.636],[0.553,4.616],[0.554,4.595],[0.555,4.575],[0.557,4.554],[0.559,4.534],[0.562,4.514],[0.564,4.494],[0.568,4.473],[0.571,4.453],[0.575,4.433],[0.579,4.413],[0.584,4.393],[0.589,4.374],[0.594,4.354],[0.6,4.334],[0.606,4.315],[0.612,4.295],[0.619,4.276],[0.626,4.257],[0.633,4.238],[0.641,4.219],[0.649,4.2],[0.657,4.181],[0.666,4.163],[0.674,4.144],[0.684,4.126],[0.693,4.108],[0.703,4.09],[0.713,4.073],[0.724,4.055],[0.735,4.038],[0.746,4.021],[0.757,4.004],[0.769,3.987],[0.781,3.97],[0.793,3.954],[0.806,3.938],[0.819,3.922],[0.832,3.906],[0.845,3.891],[0.859,3.876],[0.873,3.861],[0.887,3.846],[0.901,3.832],[0.916,3.817],[0.931,3.804],[0.946,3.79],[0.962,3.776],[0.977,3.763],[0.993,3.75],[1.009,3.738],[1.025,3.726],[1.042,3.713],[1.059,3.702],[1.076,3.69],[1.093,3.679],[1.11,3.668],[1.128,3.658],[1.145,3.648],[1.163,3.638],[1.181,3.628],[1.199,3.619],[1.218,3.61],[1.236,3.601],[1.255,3.593],[1.274,3.585],[1.293,3.577],[1.312,3.57],[1.331,3.563],[1.35,3.556],[1.37,3.55],[1.389,3.544],[1.409,3.538],[1.428,3.533],[1.448,3.528],[1.468,3.523],[1.488,3.519],[1.508,3.515],[1.528,3.511],[1.548,3.508],[1.569,3.505],[1.589,3.503],[1.609,3.501],[1.63,3.499],[1.65,3.497],[1.67,3.496],[1.691,3.496],[1.711,3.495],[1.732,3.495],[1.752,3.496],[1.773,3.496],[1.793,3.497],[1.813,3.499],[1.834,3.5],[1.854,3.503],[1.874,3.505],[1.894,3.508],[1.915,3.511],[1.935,3.514],[1.955,3.518],[1.975,3.523],[1.995,3.527],[2.015,3.532],[2.034,3.537],[2.054,3.543],[2.074,3.549],[2.093,3.555],[2.112,3.562],[2.131,3.569],[2.151,3.576],[2.17,3.584],[2.188,3.592],[2.207,3.6],[2.226,3.608],[2.244,3.617],[2.262,3.627],[2.28,3.636],[2.298,3.646],[2.316,3.656],[2.333,3.667]],[[9.0,4.111],[8.966,4.178],[8.932,4.244],[8.896,4.309],[8.859,4.374],[8.821,4.438],[8.782,4.502],[8.742,4.565],[8.7,4.627],[8.658,4.688],[8.614,4.749],[8.57,4.809],[8.524,4.868],[8.477,4.926],[8.43,4.983],[8.381,5.04],[8.331,5.096],[8.281,5.151],[8.229,5.205],[8.177,5.258],[8.124,5.31],[8.069,5.361],[8.014,5.411],[7.958,5.461],[7.901,5.509],[7.844,5.556],[7.785,5.603],[7.726,5.648],[7.666,5.692],[7.605,5.735],[7.543,5.777],[7.481,5.818],[7.418,5.858],[7.354,5.897],[7.29,5.935],[7.225,5.971],[7.159,6.007],[7.093,6.041],[7.026,6.074],[6.958,6.106],[6.89,6.137],[6.822,6.167],[6.753,6.195],[6.683,6.222],[6.613,6.248],[6.543,6.273],[6.472,6.296],[6.401,6.319],[6.329,6.34],[6.257,6.36],[6.185,6.378],[6.112,6.395],[6.04,6.411],[5.966,6.426],[5.893,6.44],[5.819,6.452],[5.746,6.463],[5.672,6.472],[5.597,6.48],[5.523,6.487],[5.449,6.493],[5.374,6.498],[5.3,6.501],[5.225,6.503],[5.15,6.503],[5.076,6.502],[5.001,6.5],[4.927,6.497],[4.852,6.492],[4.778,6.486],[4.704,6.479],[4.629,6.47],[4.555,6.46],[4.482,6.449],[4.408,6.437],[4.335,6.423],[4.262,6.408],[4.189,6.392],[4.116,6.374],[4.044,6.355],[3.972,6.335],[3.901,6.314],[3.83,6.292],[3.759,6.268],[3.688,6.243],[3.619,6.217],[3.549,6.189],[3.48,6.16],[3.412,6.131],[3.344,6.1],[3.277,6.067],[3.21,6.034],[3.144,5.999],[3.078,5.964],[3.013,5.927],[2.949,5.889],[2.886,5.85],[2.823,5.81],[2.761,5.768],[2.699,5.726],[2.638,5.683],[2.578,5.638],[2.519,5.593],[2.461,5.546],[2.403,5.499],[2.347,5.45],[2.291,5.401],[2.236,5.35],[2.182,5.299],[2.129,5.246],[2.076,5.193],[2.025,5.139],[1.975,5.084],[1.925,5.028],[1.877,4.971],[1.829,4.914],[1.783,4.855],[1.738,4.796],[1.693,4.736],[1.65,4.675],[1.608,4.614],[1.567,4.551],[1.527,4.488],[1.488,4.425],[1.45,4.36],[1.413,4.295],[1.378,4.23],[1.343,4.164],[1.31,4.097],[1.278,4.029],[1.247,3.961],[1.217,3.893],[1.189,3.824],[1.161,3.755],[1.135,3.685],[1.11,3.614],[1.087,3.544],[1.064,3.472],[1.043,3.401],[1.023,3.329],[1.004,3.257],[0.987,3.184],[0.971,3.111],[0.956,3.038],[0.942,2.965],[0.93,2.891],[0.919,2.817],[0.909,2.743],[0.901,2.669],[0.894,2.595],[0.888,2.52],[0.883,2.446],[0.88,2.371],[0.878,2.297],[0.878,2.222],[0.878,2.148],[0.88,2.073],[0.883,1.998],[0.888,1.924],[0.894,1.85],[0.901,1.775],[0.909,1.701],[0.919,1.627],[0.93,1.553],[0.942,1.48],[0.956,1.406],[0.971,1.333],[0.987,1.26],[1.004,1.188],[1.023,1.116],[1.043,1.044],[1.064,0.972],[1.087,0.901],[1.11,0.83],[1.135,0.76],[1.161,0.69],[1.189,0.62],[1.217,0.551],[1.247,0.483],[1.278,0.415],[1.31,0.348],[1.343,0.281],[1.378,0.215],[1.413,0.149],[1.45,0.084],[1.488,0.02],[1.527,-0.044],[1.567,-0.107],[1.608,-0.169],[1.65,-0.231],[1.693,-0.291],[1.738,-0.351],[1.783,-0.411],[1.829,-0.469],[1.877,-0.527],[1.925,-0.584],[1.975,-0.639],[2.025,-0.694],[2.076,-0.749],[2.129,-0.802],[2.182,-0.854],[2.236,-0.906],[2.291,-0.956],[2.347,-1.006],[2.403,-1.054],[2.461,-1.102],[2.519,-1.148],[2.578,-1.194],[2.638,-1.238],[2.699,-1.282],[2.761,-1.324],[2.823,-1.365],[2.886,-1.405],[2.949,-1.444],[3.013,-1.482],[3.078,-1.519],[3.144,-1.555],[3.21,-1.589],[3.277,-1.623],[3.344,-1.655],[3.412,-1.686],[3.48,-1.716],[3.549,-1.745],[3.619,-1.772],[3.688,-1.798],[3.759,-1.823],[3.83,-1.847],[3.901,-1.87],[3.972,-1.891],[4.044,-1.911],[4.116,-1.93],[4.189,-1.947],[4.262,-1.964],[4.335,-1.979],[4.408,-1.992],[4.482,-2.005],[4.555,-2.016],[4.629,-2.026],[4.704,-2.034],[4.778,-2.042],[4.852,-2.048],[4.927,-2.052],[5.001,-2.056],[5.076,-2.058],[5.15,-2.059],[5.225,-2.058],[5.3,-2.056],[5.374,-2.053],[5.449,-2.049],[5.523,-2.043],[5.597,-2.036],[5.672,-2.028],[5.746,-2.018],[5.819,-2.007],[5.893,-1.995],[5.966,-1.982],[6.04,-1.967],[6.112,-1.951],[6.185,-1.934],[6.257,-1.915],[6.329,-1.895],[6.401,-1.874],[6.472,-1.852],[6.543,-1.829],[6.613,-1.804],[6.683,-1.778],[6.753,-1.751],[6.822,-1.722],[6.89,-1.693],[6.958,-1.662],[7.026,-1.63],[7.093,-1.597],[7.159,-1.562],[7.225,-1.527],[7.29,-1.49],[7.354,-1.453],[7.418,-1.414],[7.481,-1.374],[7.543,-1.333],[7.605,-1.291],[7.666,-1.248],[7.726,-1.203],[7.785,-1.158],[7.844,-1.112],[7.901,-1.065],[7.958,-1.016],[8.014,-0.967],[8.069,-0.917],[8.124,-0.865],[8.177,-0.813],[8.229,-0.76],[8.281,-0.706],[8.331,-0.651],[8.381,-0.596],[8.43,-0.539],[8.477,-0.482],[8.524,-0.423],[8.57,-0.364],[8.614,-0.304],[8.658,-0.244],[8.7,-0.182],[8.742,-0.12],[8.782,-0.057],[8.821,0.006],[8.859,0.07],[8.896,0.135],[8.932,0.201],[8.966,0.267],[9.0,0.333]]],\"type\":\"MultiLineString\"}" ) );
   13898                 :          1 :   res = exportFloat.asJson( 3 );
   13899                 :          1 :   QCOMPARE( res, expectedJsonPrec3 );
   13900                 :            : 
   13901                 :            :   // as GML2
   13902                 :          2 :   QString expectedGML2prec3( QStringLiteral( "<MultiLineString xmlns=\"gml\"><lineStringMember xmlns=\"gml\"><LineString xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">2.333,5.667 2.316,5.677 2.298,5.687 2.28,5.697 2.262,5.707 2.244,5.716 2.226,5.725 2.207,5.734 2.188,5.742 2.17,5.75 2.151,5.757 2.131,5.765 2.112,5.772 2.093,5.778 2.074,5.785 2.054,5.79 2.034,5.796 2.015,5.801 1.995,5.806 1.975,5.811 1.955,5.815 1.935,5.819 1.915,5.822 1.894,5.826 1.874,5.828 1.854,5.831 1.834,5.833 1.813,5.835 1.793,5.836 1.773,5.837 1.752,5.838 1.732,5.838 1.711,5.838 1.691,5.838 1.67,5.837 1.65,5.836 1.63,5.834 1.609,5.833 1.589,5.83 1.569,5.828 1.548,5.825 1.528,5.822 1.508,5.818 1.488,5.814 1.468,5.81 1.448,5.805 1.428,5.801 1.409,5.795 1.389,5.79 1.37,5.784 1.35,5.777 1.331,5.771 1.312,5.764 1.293,5.756 1.274,5.749 1.255,5.741 1.236,5.732 1.218,5.724 1.199,5.715 1.181,5.705 1.163,5.696 1.145,5.686 1.128,5.676 1.11,5.665 1.093,5.654 1.076,5.643 1.059,5.632 1.042,5.62 1.025,5.608 1.009,5.596 0.993,5.583 0.977,5.57 0.962,5.557 0.946,5.543 0.931,5.53 0.916,5.516 0.901,5.502 0.887,5.487 0.873,5.473 0.859,5.458 0.845,5.442 0.832,5.427 0.819,5.411 0.806,5.395 0.793,5.379 0.781,5.363 0.769,5.346 0.757,5.33 0.746,5.313 0.735,5.296 0.724,5.278 0.713,5.261 0.703,5.243 0.693,5.225 0.684,5.207 0.674,5.189 0.666,5.171 0.657,5.152 0.649,5.133 0.641,5.115 0.633,5.096 0.626,5.077 0.619,5.057 0.612,5.038 0.606,5.019 0.6,4.999 0.594,4.979 0.589,4.96 0.584,4.94 0.579,4.92 0.575,4.9 0.571,4.88 0.568,4.86 0.564,4.84 0.562,4.819 0.559,4.799 0.557,4.779 0.555,4.759 0.554,4.738 0.553,4.718 0.552,4.697 0.552,4.677 0.552,4.656 0.552,4.636 0.553,4.616 0.554,4.595 0.555,4.575 0.557,4.554 0.559,4.534 0.562,4.514 0.564,4.494 0.568,4.473 0.571,4.453 0.575,4.433 0.579,4.413 0.584,4.393 0.589,4.374 0.594,4.354 0.6,4.334 0.606,4.315 0.612,4.295 0.619,4.276 0.626,4.257 0.633,4.238 0.641,4.219 0.649,4.2 0.657,4.181 0.666,4.163 0.674,4.144 0.684,4.126 0.693,4.108 0.703,4.09 0.713,4.073 0.724,4.055 0.735,4.038 0.746,4.021 0.757,4.004 0.769,3.987 0.781,3.97 0.793,3.954 0.806,3.938 0.819,3.922 0.832,3.906 0.845,3.891 0.859,3.876 0.873,3.861 0.887,3.846 0.901,3.832 0.916,3.817 0.931,3.804 0.946,3.79 0.962,3.776 0.977,3.763 0.993,3.75 1.009,3.738 1.025,3.726 1.042,3.713 1.059,3.702 1.076,3.69 1.093,3.679 1.11,3.668 1.128,3.658 1.145,3.648 1.163,3.638 1.181,3.628 1.199,3.619 1.218,3.61 1.236,3.601 1.255,3.593 1.274,3.585 1.293,3.577 1.312,3.57 1.331,3.563 1.35,3.556 1.37,3.55 1.389,3.544 1.409,3.538 1.428,3.533 1.448,3.528 1.468,3.523 1.488,3.519 1.508,3.515 1.528,3.511 1.548,3.508 1.569,3.505 1.589,3.503 1.609,3.501 1.63,3.499 1.65,3.497 1.67,3.496 1.691,3.496 1.711,3.495 1.732,3.495 1.752,3.496 1.773,3.496 1.793,3.497 1.813,3.499 1.834,3.5 1.854,3.503 1.874,3.505 1.894,3.508 1.915,3.511 1.935,3.514 1.955,3.518 1.975,3.523 1.995,3.527 2.015,3.532 2.034,3.537 2.054,3.543 2.074,3.549 2.093,3.555 2.112,3.562 2.131,3.569 2.151,3.576 2.17,3.584 2.188,3.592 2.207,3.6 2.226,3.608 2.244,3.617 2.262,3.627 2.28,3.636 2.298,3.646 2.316,3.656 2.333,3.667</coordinates></LineString></lineStringMember><lineStringMember xmlns=\"gml\"><LineString xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">9,4.111 8.966,4.178 8.932,4.244 8.896,4.309 8.859,4.374 8.821,4.438 8.782,4.502 8.742,4.565 8.7,4.627 8.658,4.688 8.614,4.749 8.57,4.809 8.524,4.868 8.477,4.926 8.43,4.983 8.381,5.04 8.331,5.096 8.281,5.151 8.229,5.205 8.177,5.258 8.124,5.31 8.069,5.361 8.014,5.411 7.958,5.461 7.901,5.509 7.844,5.556 7.785,5.603 7.726,5.648 7.666,5.692 7.605,5.735 7.543,5.777 7.481,5.818 7.418,5.858 7.354,5.897 7.29,5.935 7.225,5.971 7.159,6.007 7.093,6.041 7.026,6.074 6.958,6.106 6.89,6.137 6.822,6.167 6.753,6.195 6.683,6.222 6.613,6.248 6.543,6.273 6.472,6.296 6.401,6.319 6.329,6.34 6.257,6.36 6.185,6.378 6.112,6.395 6.04,6.411 5.966,6.426 5.893,6.44 5.819,6.452 5.746,6.463 5.672,6.472 5.597,6.48 5.523,6.487 5.449,6.493 5.374,6.498 5.3,6.501 5.225,6.503 5.15,6.503 5.076,6.502 5.001,6.5 4.927,6.497 4.852,6.492 4.778,6.486 4.704,6.479 4.629,6.47 4.555,6.46 4.482,6.449 4.408,6.437 4.335,6.423 4.262,6.408 4.189,6.392 4.116,6.374 4.044,6.355 3.972,6.335 3.901,6.314 3.83,6.292 3.759,6.268 3.688,6.243 3.619,6.217 3.549,6.189 3.48,6.16 3.412,6.131 3.344,6.1 3.277,6.067 3.21,6.034 3.144,5.999 3.078,5.964 3.013,5.927 2.949,5.889 2.886,5.85 2.823,5.81 2.761,5.768 2.699,5.726 2.638,5.683 2.578,5.638 2.519,5.593 2.461,5.546 2.403,5.499 2.347,5.45 2.291,5.401 2.236,5.35 2.182,5.299 2.129,5.246 2.076,5.193 2.025,5.139 1.975,5.084 1.925,5.028 1.877,4.971 1.829,4.914 1.783,4.855 1.738,4.796 1.693,4.736 1.65,4.675 1.608,4.614 1.567,4.551 1.527,4.488 1.488,4.425 1.45,4.36 1.413,4.295 1.378,4.23 1.343,4.164 1.31,4.097 1.278,4.029 1.247,3.961 1.217,3.893 1.189,3.824 1.161,3.755 1.135,3.685 1.11,3.614 1.087,3.544 1.064,3.472 1.043,3.401 1.023,3.329 1.004,3.257 0.987,3.184 0.971,3.111 0.956,3.038 0.942,2.965 0.93,2.891 0.919,2.817 0.909,2.743 0.901,2.669 0.894,2.595 0.888,2.52 0.883,2.446 0.88,2.371 0.878,2.297 0.878,2.222 0.878,2.148 0.88,2.073 0.883,1.998 0.888,1.924 0.894,1.85 0.901,1.775 0.909,1.701 0.919,1.627 0.93,1.553 0.942,1.48 0.956,1.406 0.971,1.333 0.987,1.26 1.004,1.188 1.023,1.116 1.043,1.044 1.064,0.972 1.087,0.901 1.11,0.83 1.135,0.76 1.161,0.69 1.189,0.62 1.217,0.551 1.247,0.483 1.278,0.415 1.31,0.348 1.343,0.281 1.378,0.215 1.413,0.149 1.45,0.084 1.488,0.02 1.527,-0.044 1.567,-0.107 1.608,-0.169 1.65,-0.231 1.693,-0.291 1.738,-0.351 1.783,-0.411 1.829,-0.469 1.877,-0.527 1.925,-0.584 1.975,-0.639 2.025,-0.694 2.076,-0.749 2.129,-0.802 2.182,-0.854 2.236,-0.906 2.291,-0.956 2.347,-1.006 2.403,-1.054 2.461,-1.102 2.519,-1.148 2.578,-1.194 2.638,-1.238 2.699,-1.282 2.761,-1.324 2.823,-1.365 2.886,-1.405 2.949,-1.444 3.013,-1.482 3.078,-1.519 3.144,-1.555 3.21,-1.589 3.277,-1.623 3.344,-1.655 3.412,-1.686 3.48,-1.716 3.549,-1.745 3.619,-1.772 3.688,-1.798 3.759,-1.823 3.83,-1.847 3.901,-1.87 3.972,-1.891 4.044,-1.911 4.116,-1.93 4.189,-1.947 4.262,-1.964 4.335,-1.979 4.408,-1.992 4.482,-2.005 4.555,-2.016 4.629,-2.026 4.704,-2.034 4.778,-2.042 4.852,-2.048 4.927,-2.052 5.001,-2.056 5.076,-2.058 5.15,-2.059 5.225,-2.058 5.3,-2.056 5.374,-2.053 5.449,-2.049 5.523,-2.043 5.597,-2.036 5.672,-2.028 5.746,-2.018 5.819,-2.007 5.893,-1.995 5.966,-1.982 6.04,-1.967 6.112,-1.951 6.185,-1.934 6.257,-1.915 6.329,-1.895 6.401,-1.874 6.472,-1.852 6.543,-1.829 6.613,-1.804 6.683,-1.778 6.753,-1.751 6.822,-1.722 6.89,-1.693 6.958,-1.662 7.026,-1.63 7.093,-1.597 7.159,-1.562 7.225,-1.527 7.29,-1.49 7.354,-1.453 7.418,-1.414 7.481,-1.374 7.543,-1.333 7.605,-1.291 7.666,-1.248 7.726,-1.203 7.785,-1.158 7.844,-1.112 7.901,-1.065 7.958,-1.016 8.014,-0.967 8.069,-0.917 8.124,-0.865 8.177,-0.813 8.229,-0.76 8.281,-0.706 8.331,-0.651 8.381,-0.596 8.43,-0.539 8.477,-0.482 8.524,-0.423 8.57,-0.364 8.614,-0.304 8.658,-0.244 8.7,-0.182 8.742,-0.12 8.782,-0.057 8.821,0.006 8.859,0.07 8.896,0.135 8.932,0.201 8.966,0.267 9,0.333</coordinates></LineString></lineStringMember></MultiLineString>" ) );
   13903                 :          1 :   res = elemToString( exportFloat.asGml2( doc, 3 ) );
   13904                 :          3 :   QGSCOMPAREGML( res, expectedGML2prec3 );
   13905                 :            : 
   13906                 :            :   //as GML3
   13907                 :          2 :   QString expectedGML3prec3( QStringLiteral( "<MultiCurve xmlns=\"gml\"><curveMember xmlns=\"gml\"><Curve xmlns=\"gml\"><segments xmlns=\"gml\"><ArcString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">2.333 5.667 0.6 4.333 2.333 3.667</posList></ArcString></segments></Curve></curveMember><curveMember xmlns=\"gml\"><Curve xmlns=\"gml\"><segments xmlns=\"gml\"><ArcString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">9 4.111 1.049 1.024 9 0.333</posList></ArcString></segments></Curve></curveMember></MultiCurve>" ) );
   13908                 :          1 :   res = elemToString( exportFloat.asGml3( doc, 3 ) );
   13909                 :          1 :   QCOMPARE( res, expectedGML3prec3 );
   13910                 :            : 
   13911                 :            :   //asKML
   13912                 :          2 :   QString expectedKml( QStringLiteral( "<MultiGeometry><LineString><altitudeMode>clampToGround</altitudeMode><coordinates>7,17,0 6.9,17,0 6.9,17,0 6.8,17,0 6.8,17.1,0 6.7,17.1,0 6.7,17.1,0 6.6,17.1,0 6.6,17.1,0 6.5,17.1,0 6.5,17.1,0 6.4,17.1,0 6.4,17.1,0 6.3,17.1,0 6.2,17.2,0 6.2,17.2,0 6.1,17.2,0 6.1,17.2,0 6,17.2,0 6,17.2,0 5.9,17.2,0 5.9,17.2,0 5.8,17.2,0 5.7,17.2,0 5.7,17.1,0 5.6,17.1,0 5.6,17.1,0 5.5,17.1,0 5.5,17.1,0 5.4,17.1,0 5.4,17.1,0 5.3,17.1,0 5.3,17.1,0 5.2,17.1,0 5.2,17,0 5.1,17,0 5,17,0 5,17,0 4.9,17,0 4.9,17,0 4.8,16.9,0 4.8,16.9,0 4.7,16.9,0 4.7,16.9,0 4.6,16.9,0 4.6,16.8,0 4.5,16.8,0 4.5,16.8,0 4.4,16.8,0 4.4,16.7,0 4.3,16.7,0 4.3,16.7,0 4.3,16.6,0 4.2,16.6,0 4.2,16.6,0 4.1,16.5,0 4.1,16.5,0 4,16.5,0 4,16.4,0 3.9,16.4,0 3.9,16.4,0 3.9,16.3,0 3.8,16.3,0 3.8,16.3,0 3.7,16.2,0 3.7,16.2,0 3.7,16.1,0 3.6,16.1,0 3.6,16.1,0 3.6,16,0 3.5,16,0 3.5,15.9,0 3.5,15.9,0 3.4,15.8,0 3.4,15.8,0 3.4,15.7,0 3.3,15.7,0 3.3,15.7,0 3.3,15.6,0 3.2,15.6,0 3.2,15.5,0 3.2,15.5,0 3.2,15.4,0 3.1,15.4,0 3.1,15.3,0 3.1,15.3,0 3.1,15.2,0 3.1,15.2,0 3,15.1,0 3,15.1,0 3,15,0 3,15,0 3,14.9,0 3,14.8,0 2.9,14.8,0 2.9,14.7,0 2.9,14.7,0 2.9,14.6,0 2.9,14.6,0 2.9,14.5,0 2.9,14.5,0 2.9,14.4,0 2.9,14.4,0 2.9,14.3,0 2.8,14.2,0 2.8,14.2,0 2.8,14.1,0 2.8,14.1,0 2.8,14,0 2.8,14,0 2.8,13.9,0 2.8,13.9,0 2.8,13.8,0 2.8,13.8,0 2.9,13.7,0 2.9,13.6,0 2.9,13.6,0 2.9,13.5,0 2.9,13.5,0 2.9,13.4,0 2.9,13.4,0 2.9,13.3,0 2.9,13.3,0 2.9,13.2,0 3,13.2,0 3,13.1,0 3,13,0 3,13,0 3,12.9,0 3,12.9,0 3.1,12.8,0 3.1,12.8,0 3.1,12.7,0 3.1,12.7,0 3.1,12.6,0 3.2,12.6,0 3.2,12.5,0 3.2,12.5,0 3.2,12.4,0 3.3,12.4,0 3.3,12.3,0 3.3,12.3,0 3.4,12.3,0 3.4,12.2,0 3.4,12.2,0 3.5,12.1,0 3.5,12.1,0 3.5,12,0 3.6,12,0 3.6,11.9,0 3.6,11.9,0 3.7,11.9,0 3.7,11.8,0 3.7,11.8,0 3.8,11.7,0 3.8,11.7,0 3.9,11.7,0 3.9,11.6,0 3.9,11.6,0 4,11.6,0 4,11.5,0 4.1,11.5,0 4.1,11.5,0 4.2,11.4,0 4.2,11.4,0 4.3,11.4,0 4.3,11.3,0 4.3,11.3,0 4.4,11.3,0 4.4,11.2,0 4.5,11.2,0 4.5,11.2,0 4.6,11.2,0 4.6,11.1,0 4.7,11.1,0 4.7,11.1,0 4.8,11.1,0 4.8,11.1,0 4.9,11,0 4.9,11,0 5,11,0 5,11,0 5.1,11,0 5.2,11,0 5.2,10.9,0 5.3,10.9,0 5.3,10.9,0 5.4,10.9,0 5.4,10.9,0 5.5,10.9,0 5.5,10.9,0 5.6,10.9,0 5.6,10.9,0 5.7,10.9,0 5.7,10.8,0 5.8,10.8,0 5.9,10.8,0 5.9,10.8,0 6,10.8,0 6,10.8,0 6.1,10.8,0 6.1,10.8,0 6.2,10.8,0 6.2,10.8,0 6.3,10.9,0 6.4,10.9,0 6.4,10.9,0 6.5,10.9,0 6.5,10.9,0 6.6,10.9,0 6.6,10.9,0 6.7,10.9,0 6.7,10.9,0 6.8,10.9,0 6.8,11,0 6.9,11,0 6.9,11,0 7,11,0</coordinates></LineString><LineString><altitudeMode>clampToGround</altitudeMode><coordinates>27,37,0 27.1,36.9,0 27.2,36.8,0 27.3,36.6,0 27.4,36.5,0 27.5,36.4,0 27.6,36.3,0 27.7,36.2,0 27.8,36,0 27.9,35.9,0 28,35.8,0 28.1,35.7,0 28.2,35.6,0 28.3,35.5,0 28.4,35.4,0 28.5,35.3,0 28.7,35.2,0 28.8,35.1,0 28.9,35,0 29,34.9,0 29.1,34.8,0 29.3,34.7,0 29.4,34.6,0 29.5,34.6,0 29.7,34.5,0 29.8,34.4,0 29.9,34.3,0 30.1,34.3,0 30.2,34.2,0 30.3,34.1,0 30.5,34,0 30.6,34,0 30.7,33.9,0 30.9,33.9,0 31,33.8,0 31.2,33.7,0 31.3,33.7,0 31.5,33.6,0 31.6,33.6,0 31.8,33.6,0 31.9,33.5,0 32.1,33.5,0 32.2,33.4,0 32.4,33.4,0 32.5,33.4,0 32.7,33.3,0 32.8,33.3,0 33,33.3,0 33.1,33.3,0 33.3,33.2,0 33.4,33.2,0 33.6,33.2,0 33.7,33.2,0 33.9,33.2,0 34,33.2,0 34.2,33.2,0 34.3,33.2,0 34.5,33.2,0 34.6,33.2,0 34.8,33.2,0 34.9,33.2,0 35.1,33.2,0 35.3,33.3,0 35.4,33.3,0 35.6,33.3,0 35.7,33.3,0 35.9,33.3,0 36,33.4,0 36.2,33.4,0 36.3,33.4,0 36.5,33.5,0 36.6,33.5,0 36.8,33.6,0 36.9,33.6,0 37.1,33.7,0 37.2,33.7,0 37.3,33.8,0 37.5,33.8,0 37.6,33.9,0 37.8,33.9,0 37.9,34,0 38,34.1,0 38.2,34.1,0 38.3,34.2,0 38.5,34.3,0 38.6,34.3,0 38.7,34.4,0 38.9,34.5,0 39,34.6,0 39.1,34.7,0 39.2,34.7,0 39.4,34.8,0 39.5,34.9,0 39.6,35,0 39.7,35.1,0 39.9,35.2,0 40,35.3,0 40.1,35.4,0 40.2,35.5,0 40.3,35.6,0 40.4,35.7,0 40.5,35.8,0 40.6,35.9,0 40.7,36.1,0 40.8,36.2,0 40.9,36.3,0 41,36.4,0 41.1,36.5,0 41.2,36.6,0 41.3,36.8,0 41.4,36.9,0 41.5,37,0 41.6,37.1,0 41.7,37.3,0 41.8,37.4,0 41.8,37.5,0 41.9,37.7,0 42,37.8,0 42.1,37.9,0 42.1,38.1,0 42.2,38.2,0 42.3,38.3,0 42.3,38.5,0 42.4,38.6,0 42.4,38.8,0 42.5,38.9,0 42.6,39.1,0 42.6,39.2,0 42.6,39.4,0 42.7,39.5,0 42.7,39.6,0 42.8,39.8,0 42.8,39.9,0 42.8,40.1,0 42.9,40.2,0 42.9,40.4,0 42.9,40.5,0 43,40.7,0 43,40.9,0 43,41,0 43,41.2,0 43,41.3,0 43,41.5,0 43,41.6,0 43.1,41.8,0 43.1,41.9,0 43.1,42.1,0 43.1,42.2,0 43,42.4,0 43,42.5,0 43,42.7,0 43,42.8,0 43,43,0 43,43.1,0 43,43.3,0 42.9,43.5,0 42.9,43.6,0 42.9,43.8,0 42.8,43.9,0 42.8,44.1,0 42.8,44.2,0 42.7,44.4,0 42.7,44.5,0 42.6,44.6,0 42.6,44.8,0 42.6,44.9,0 42.5,45.1,0 42.4,45.2,0 42.4,45.4,0 42.3,45.5,0 42.3,45.7,0 42.2,45.8,0 42.1,45.9,0 42.1,46.1,0 42,46.2,0 41.9,46.3,0 41.8,46.5,0 41.8,46.6,0 41.7,46.7,0 41.6,46.9,0 41.5,47,0 41.4,47.1,0 41.3,47.2,0 41.2,47.4,0 41.1,47.5,0 41,47.6,0 40.9,47.7,0 40.8,47.8,0 40.7,47.9,0 40.6,48.1,0 40.5,48.2,0 40.4,48.3,0 40.3,48.4,0 40.2,48.5,0 40.1,48.6,0 40,48.7,0 39.9,48.8,0 39.7,48.9,0 39.6,49,0 39.5,49.1,0 39.4,49.2,0 39.2,49.3,0 39.1,49.3,0 39,49.4,0 38.9,49.5,0 38.7,49.6,0 38.6,49.7,0 38.5,49.7,0 38.3,49.8,0 38.2,49.9,0 38,49.9,0 37.9,50,0 37.8,50.1,0 37.6,50.1,0 37.5,50.2,0 37.3,50.2,0 37.2,50.3,0 37.1,50.3,0 36.9,50.4,0 36.8,50.4,0 36.6,50.5,0 36.5,50.5,0 36.3,50.6,0 36.2,50.6,0 36,50.6,0 35.9,50.7,0 35.7,50.7,0 35.6,50.7,0 35.4,50.7,0 35.3,50.7,0 35.1,50.8,0 34.9,50.8,0 34.8,50.8,0 34.6,50.8,0 34.5,50.8,0 34.3,50.8,0 34.2,50.8,0 34,50.8,0 33.9,50.8,0 33.7,50.8,0 33.6,50.8,0 33.4,50.8,0 33.3,50.8,0 33.1,50.7,0 33,50.7,0 32.8,50.7,0 32.7,50.7,0 32.5,50.6,0 32.4,50.6,0 32.2,50.6,0 32.1,50.5,0 31.9,50.5,0 31.8,50.4,0 31.6,50.4,0 31.5,50.4,0 31.3,50.3,0 31.2,50.3,0 31,50.2,0 30.9,50.1,0 30.7,50.1,0 30.6,50,0 30.5,50,0 30.3,49.9,0 30.2,49.8,0 30.1,49.7,0 29.9,49.7,0 29.8,49.6,0 29.7,49.5,0 29.5,49.4,0 29.4,49.4,0 29.3,49.3,0 29.1,49.2,0 29,49.1,0 28.9,49,0 28.8,48.9,0 28.7,48.8,0 28.5,48.7,0 28.4,48.6,0 28.3,48.5,0 28.2,48.4,0 28.1,48.3,0 28,48.2,0 27.9,48.1,0 27.8,48,0 27.7,47.8,0 27.6,47.7,0 27.5,47.6,0 27.4,47.5,0 27.3,47.4,0 27.2,47.2,0 27.1,47.1,0 27,47,0</coordinates></LineString></MultiGeometry>" ) );
   13913                 :          1 :   QCOMPARE( exportC.asKml( 1 ), expectedKml );
   13914                 :          2 :   QString expectedKmlPrec3( QStringLiteral( "<MultiGeometry><LineString><altitudeMode>clampToGround</altitudeMode><coordinates>2.333,5.667,0 2.316,5.677,0 2.298,5.687,0 2.28,5.697,0 2.262,5.707,0 2.244,5.716,0 2.226,5.725,0 2.207,5.734,0 2.188,5.742,0 2.17,5.75,0 2.151,5.757,0 2.131,5.765,0 2.112,5.772,0 2.093,5.778,0 2.074,5.785,0 2.054,5.79,0 2.034,5.796,0 2.015,5.801,0 1.995,5.806,0 1.975,5.811,0 1.955,5.815,0 1.935,5.819,0 1.915,5.822,0 1.894,5.826,0 1.874,5.828,0 1.854,5.831,0 1.834,5.833,0 1.813,5.835,0 1.793,5.836,0 1.773,5.837,0 1.752,5.838,0 1.732,5.838,0 1.711,5.838,0 1.691,5.838,0 1.67,5.837,0 1.65,5.836,0 1.63,5.834,0 1.609,5.833,0 1.589,5.83,0 1.569,5.828,0 1.548,5.825,0 1.528,5.822,0 1.508,5.818,0 1.488,5.814,0 1.468,5.81,0 1.448,5.805,0 1.428,5.801,0 1.409,5.795,0 1.389,5.79,0 1.37,5.784,0 1.35,5.777,0 1.331,5.771,0 1.312,5.764,0 1.293,5.756,0 1.274,5.749,0 1.255,5.741,0 1.236,5.732,0 1.218,5.724,0 1.199,5.715,0 1.181,5.705,0 1.163,5.696,0 1.145,5.686,0 1.128,5.676,0 1.11,5.665,0 1.093,5.654,0 1.076,5.643,0 1.059,5.632,0 1.042,5.62,0 1.025,5.608,0 1.009,5.596,0 0.993,5.583,0 0.977,5.57,0 0.962,5.557,0 0.946,5.543,0 0.931,5.53,0 0.916,5.516,0 0.901,5.502,0 0.887,5.487,0 0.873,5.473,0 0.859,5.458,0 0.845,5.442,0 0.832,5.427,0 0.819,5.411,0 0.806,5.395,0 0.793,5.379,0 0.781,5.363,0 0.769,5.346,0 0.757,5.33,0 0.746,5.313,0 0.735,5.296,0 0.724,5.278,0 0.713,5.261,0 0.703,5.243,0 0.693,5.225,0 0.684,5.207,0 0.674,5.189,0 0.666,5.171,0 0.657,5.152,0 0.649,5.133,0 0.641,5.115,0 0.633,5.096,0 0.626,5.077,0 0.619,5.057,0 0.612,5.038,0 0.606,5.019,0 0.6,4.999,0 0.594,4.979,0 0.589,4.96,0 0.584,4.94,0 0.579,4.92,0 0.575,4.9,0 0.571,4.88,0 0.568,4.86,0 0.564,4.84,0 0.562,4.819,0 0.559,4.799,0 0.557,4.779,0 0.555,4.759,0 0.554,4.738,0 0.553,4.718,0 0.552,4.697,0 0.552,4.677,0 0.552,4.656,0 0.552,4.636,0 0.553,4.616,0 0.554,4.595,0 0.555,4.575,0 0.557,4.554,0 0.559,4.534,0 0.562,4.514,0 0.564,4.494,0 0.568,4.473,0 0.571,4.453,0 0.575,4.433,0 0.579,4.413,0 0.584,4.393,0 0.589,4.374,0 0.594,4.354,0 0.6,4.334,0 0.606,4.315,0 0.612,4.295,0 0.619,4.276,0 0.626,4.257,0 0.633,4.238,0 0.641,4.219,0 0.649,4.2,0 0.657,4.181,0 0.666,4.163,0 0.674,4.144,0 0.684,4.126,0 0.693,4.108,0 0.703,4.09,0 0.713,4.073,0 0.724,4.055,0 0.735,4.038,0 0.746,4.021,0 0.757,4.004,0 0.769,3.987,0 0.781,3.97,0 0.793,3.954,0 0.806,3.938,0 0.819,3.922,0 0.832,3.906,0 0.845,3.891,0 0.859,3.876,0 0.873,3.861,0 0.887,3.846,0 0.901,3.832,0 0.916,3.817,0 0.931,3.804,0 0.946,3.79,0 0.962,3.776,0 0.977,3.763,0 0.993,3.75,0 1.009,3.738,0 1.025,3.726,0 1.042,3.713,0 1.059,3.702,0 1.076,3.69,0 1.093,3.679,0 1.11,3.668,0 1.128,3.658,0 1.145,3.648,0 1.163,3.638,0 1.181,3.628,0 1.199,3.619,0 1.218,3.61,0 1.236,3.601,0 1.255,3.593,0 1.274,3.585,0 1.293,3.577,0 1.312,3.57,0 1.331,3.563,0 1.35,3.556,0 1.37,3.55,0 1.389,3.544,0 1.409,3.538,0 1.428,3.533,0 1.448,3.528,0 1.468,3.523,0 1.488,3.519,0 1.508,3.515,0 1.528,3.511,0 1.548,3.508,0 1.569,3.505,0 1.589,3.503,0 1.609,3.501,0 1.63,3.499,0 1.65,3.497,0 1.67,3.496,0 1.691,3.496,0 1.711,3.495,0 1.732,3.495,0 1.752,3.496,0 1.773,3.496,0 1.793,3.497,0 1.813,3.499,0 1.834,3.5,0 1.854,3.503,0 1.874,3.505,0 1.894,3.508,0 1.915,3.511,0 1.935,3.514,0 1.955,3.518,0 1.975,3.523,0 1.995,3.527,0 2.015,3.532,0 2.034,3.537,0 2.054,3.543,0 2.074,3.549,0 2.093,3.555,0 2.112,3.562,0 2.131,3.569,0 2.151,3.576,0 2.17,3.584,0 2.188,3.592,0 2.207,3.6,0 2.226,3.608,0 2.244,3.617,0 2.262,3.627,0 2.28,3.636,0 2.298,3.646,0 2.316,3.656,0 2.333,3.667,0</coordinates></LineString><LineString><altitudeMode>clampToGround</altitudeMode><coordinates>9,4.111,0 8.966,4.178,0 8.932,4.244,0 8.896,4.309,0 8.859,4.374,0 8.821,4.438,0 8.782,4.502,0 8.742,4.565,0 8.7,4.627,0 8.658,4.688,0 8.614,4.749,0 8.57,4.809,0 8.524,4.868,0 8.477,4.926,0 8.43,4.983,0 8.381,5.04,0 8.331,5.096,0 8.281,5.151,0 8.229,5.205,0 8.177,5.258,0 8.124,5.31,0 8.069,5.361,0 8.014,5.411,0 7.958,5.461,0 7.901,5.509,0 7.844,5.556,0 7.785,5.603,0 7.726,5.648,0 7.666,5.692,0 7.605,5.735,0 7.543,5.777,0 7.481,5.818,0 7.418,5.858,0 7.354,5.897,0 7.29,5.935,0 7.225,5.971,0 7.159,6.007,0 7.093,6.041,0 7.026,6.074,0 6.958,6.106,0 6.89,6.137,0 6.822,6.167,0 6.753,6.195,0 6.683,6.222,0 6.613,6.248,0 6.543,6.273,0 6.472,6.296,0 6.401,6.319,0 6.329,6.34,0 6.257,6.36,0 6.185,6.378,0 6.112,6.395,0 6.04,6.411,0 5.966,6.426,0 5.893,6.44,0 5.819,6.452,0 5.746,6.463,0 5.672,6.472,0 5.597,6.48,0 5.523,6.487,0 5.449,6.493,0 5.374,6.498,0 5.3,6.501,0 5.225,6.503,0 5.15,6.503,0 5.076,6.502,0 5.001,6.5,0 4.927,6.497,0 4.852,6.492,0 4.778,6.486,0 4.704,6.479,0 4.629,6.47,0 4.555,6.46,0 4.482,6.449,0 4.408,6.437,0 4.335,6.423,0 4.262,6.408,0 4.189,6.392,0 4.116,6.374,0 4.044,6.355,0 3.972,6.335,0 3.901,6.314,0 3.83,6.292,0 3.759,6.268,0 3.688,6.243,0 3.619,6.217,0 3.549,6.189,0 3.48,6.16,0 3.412,6.131,0 3.344,6.1,0 3.277,6.067,0 3.21,6.034,0 3.144,5.999,0 3.078,5.964,0 3.013,5.927,0 2.949,5.889,0 2.886,5.85,0 2.823,5.81,0 2.761,5.768,0 2.699,5.726,0 2.638,5.683,0 2.578,5.638,0 2.519,5.593,0 2.461,5.546,0 2.403,5.499,0 2.347,5.45,0 2.291,5.401,0 2.236,5.35,0 2.182,5.299,0 2.129,5.246,0 2.076,5.193,0 2.025,5.139,0 1.975,5.084,0 1.925,5.028,0 1.877,4.971,0 1.829,4.914,0 1.783,4.855,0 1.738,4.796,0 1.693,4.736,0 1.65,4.675,0 1.608,4.614,0 1.567,4.551,0 1.527,4.488,0 1.488,4.425,0 1.45,4.36,0 1.413,4.295,0 1.378,4.23,0 1.343,4.164,0 1.31,4.097,0 1.278,4.029,0 1.247,3.961,0 1.217,3.893,0 1.189,3.824,0 1.161,3.755,0 1.135,3.685,0 1.11,3.614,0 1.087,3.544,0 1.064,3.472,0 1.043,3.401,0 1.023,3.329,0 1.004,3.257,0 0.987,3.184,0 0.971,3.111,0 0.956,3.038,0 0.942,2.965,0 0.93,2.891,0 0.919,2.817,0 0.909,2.743,0 0.901,2.669,0 0.894,2.595,0 0.888,2.52,0 0.883,2.446,0 0.88,2.371,0 0.878,2.297,0 0.878,2.222,0 0.878,2.148,0 0.88,2.073,0 0.883,1.998,0 0.888,1.924,0 0.894,1.85,0 0.901,1.775,0 0.909,1.701,0 0.919,1.627,0 0.93,1.553,0 0.942,1.48,0 0.956,1.406,0 0.971,1.333,0 0.987,1.26,0 1.004,1.188,0 1.023,1.116,0 1.043,1.044,0 1.064,0.972,0 1.087,0.901,0 1.11,0.83,0 1.135,0.76,0 1.161,0.69,0 1.189,0.62,0 1.217,0.551,0 1.247,0.483,0 1.278,0.415,0 1.31,0.348,0 1.343,0.281,0 1.378,0.215,0 1.413,0.149,0 1.45,0.084,0 1.488,0.02,0 1.527,-0.044,0 1.567,-0.107,0 1.608,-0.169,0 1.65,-0.231,0 1.693,-0.291,0 1.738,-0.351,0 1.783,-0.411,0 1.829,-0.469,0 1.877,-0.527,0 1.925,-0.584,0 1.975,-0.639,0 2.025,-0.694,0 2.076,-0.749,0 2.129,-0.802,0 2.182,-0.854,0 2.236,-0.906,0 2.291,-0.956,0 2.347,-1.006,0 2.403,-1.054,0 2.461,-1.102,0 2.519,-1.148,0 2.578,-1.194,0 2.638,-1.238,0 2.699,-1.282,0 2.761,-1.324,0 2.823,-1.365,0 2.886,-1.405,0 2.949,-1.444,0 3.013,-1.482,0 3.078,-1.519,0 3.144,-1.555,0 3.21,-1.589,0 3.277,-1.623,0 3.344,-1.655,0 3.412,-1.686,0 3.48,-1.716,0 3.549,-1.745,0 3.619,-1.772,0 3.688,-1.798,0 3.759,-1.823,0 3.83,-1.847,0 3.901,-1.87,0 3.972,-1.891,0 4.044,-1.911,0 4.116,-1.93,0 4.189,-1.947,0 4.262,-1.964,0 4.335,-1.979,0 4.408,-1.992,0 4.482,-2.005,0 4.555,-2.016,0 4.629,-2.026,0 4.704,-2.034,0 4.778,-2.042,0 4.852,-2.048,0 4.927,-2.052,0 5.001,-2.056,0 5.076,-2.058,0 5.15,-2.059,0 5.225,-2.058,0 5.3,-2.056,0 5.374,-2.053,0 5.449,-2.049,0 5.523,-2.043,0 5.597,-2.036,0 5.672,-2.028,0 5.746,-2.018,0 5.819,-2.007,0 5.893,-1.995,0 5.966,-1.982,0 6.04,-1.967,0 6.112,-1.951,0 6.185,-1.934,0 6.257,-1.915,0 6.329,-1.895,0 6.401,-1.874,0 6.472,-1.852,0 6.543,-1.829,0 6.613,-1.804,0 6.683,-1.778,0 6.753,-1.751,0 6.822,-1.722,0 6.89,-1.693,0 6.958,-1.662,0 7.026,-1.63,0 7.093,-1.597,0 7.159,-1.562,0 7.225,-1.527,0 7.29,-1.49,0 7.354,-1.453,0 7.418,-1.414,0 7.481,-1.374,0 7.543,-1.333,0 7.605,-1.291,0 7.666,-1.248,0 7.726,-1.203,0 7.785,-1.158,0 7.844,-1.112,0 7.901,-1.065,0 7.958,-1.016,0 8.014,-0.967,0 8.069,-0.917,0 8.124,-0.865,0 8.177,-0.813,0 8.229,-0.76,0 8.281,-0.706,0 8.331,-0.651,0 8.381,-0.596,0 8.43,-0.539,0 8.477,-0.482,0 8.524,-0.423,0 8.57,-0.364,0 8.614,-0.304,0 8.658,-0.244,0 8.7,-0.182,0 8.742,-0.12,0 8.782,-0.057,0 8.821,0.006,0 8.859,0.07,0 8.896,0.135,0 8.932,0.201,0 8.966,0.267,0 9,0.333,0</coordinates></LineString></MultiGeometry>" ) );
   13915                 :          1 :   QCOMPARE( exportFloat.asKml( 3 ), expectedKmlPrec3 );
   13916                 :            : 
   13917                 :            :   // insert geometry
   13918                 :          1 :   QgsMultiCurve rc;
   13919                 :          1 :   rc.clear();
   13920                 :          1 :   rc.insertGeometry( nullptr, 0 );
   13921                 :          1 :   QVERIFY( rc.isEmpty() );
   13922                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   13923                 :          1 :   rc.insertGeometry( nullptr, -1 );
   13924                 :          1 :   QVERIFY( rc.isEmpty() );
   13925                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   13926                 :          1 :   rc.insertGeometry( nullptr, 100 );
   13927                 :          1 :   QVERIFY( rc.isEmpty() );
   13928                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   13929                 :            : 
   13930                 :          1 :   rc.insertGeometry( new QgsPoint(), 0 );
   13931                 :          1 :   QVERIFY( rc.isEmpty() );
   13932                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   13933                 :            : 
   13934                 :          1 :   rc.insertGeometry( part.clone(), 0 );
   13935                 :          1 :   QVERIFY( !rc.isEmpty() );
   13936                 :          1 :   QCOMPARE( rc.numGeometries(), 1 );
   13937                 :            : 
   13938                 :            :   // cast
   13939                 :          1 :   QVERIFY( !QgsMultiCurve().cast( nullptr ) );
   13940                 :          1 :   QgsMultiCurve pCast;
   13941                 :          1 :   QVERIFY( QgsMultiCurve().cast( &pCast ) );
   13942                 :          1 :   QgsMultiCurve pCast2;
   13943                 :          2 :   pCast2.fromWkt( QStringLiteral( "MultiCurveZ()" ) );
   13944                 :          1 :   QVERIFY( QgsMultiCurve().cast( &pCast2 ) );
   13945                 :          2 :   pCast2.fromWkt( QStringLiteral( "MultiCurveM()" ) );
   13946                 :          1 :   QVERIFY( QgsMultiCurve().cast( &pCast2 ) );
   13947                 :          2 :   pCast2.fromWkt( QStringLiteral( "MultiCurveZM()" ) );
   13948                 :          1 :   QVERIFY( QgsMultiCurve().cast( &pCast2 ) );
   13949                 :            : 
   13950                 :            :   //boundary
   13951                 :          1 :   QgsMultiCurve multiLine1;
   13952                 :          1 :   QVERIFY( !multiLine1.boundary() );
   13953                 :          1 :   QgsCircularString boundaryLine1;
   13954                 :          1 :   boundaryLine1.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 ) );
   13955                 :          1 :   multiLine1.addGeometry( boundaryLine1.clone() );
   13956                 :          1 :   QgsAbstractGeometry *boundary = multiLine1.boundary();
   13957                 :          1 :   QgsMultiPoint *mpBoundary = dynamic_cast< QgsMultiPoint * >( boundary );
   13958                 :          1 :   QVERIFY( mpBoundary );
   13959                 :          1 :   QCOMPARE( mpBoundary->numGeometries(), 2 );
   13960                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->x(), 0.0 );
   13961                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->y(), 0.0 );
   13962                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->x(), 1.0 );
   13963                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->y(), 1.0 );
   13964                 :          1 :   delete boundary;
   13965                 :            :   // add another QgsCircularString
   13966                 :          1 :   QgsCircularString boundaryLine2;
   13967                 :          1 :   boundaryLine2.setPoints( QgsPointSequence() << QgsPoint( 10, 10 ) << QgsPoint( 11, 10 ) << QgsPoint( 11, 11 ) );
   13968                 :          1 :   multiLine1.addGeometry( boundaryLine2.clone() );
   13969                 :          1 :   boundary = multiLine1.boundary();
   13970                 :          1 :   mpBoundary = dynamic_cast< QgsMultiPoint * >( boundary );
   13971                 :          1 :   QVERIFY( mpBoundary );
   13972                 :          1 :   QCOMPARE( mpBoundary->numGeometries(), 4 );
   13973                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->x(), 0.0 );
   13974                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->y(), 0.0 );
   13975                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->x(), 1.0 );
   13976                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->y(), 1.0 );
   13977                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 2 ) )->x(), 10.0 );
   13978                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 2 ) )->y(), 10.0 );
   13979                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 3 ) )->x(), 11.0 );
   13980                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 3 ) )->y(), 11.0 );
   13981                 :          1 :   delete boundary;
   13982                 :            : 
   13983                 :            :   // add a closed string = no boundary
   13984                 :          1 :   QgsCircularString boundaryLine3;
   13985                 :          1 :   boundaryLine3.setPoints( QgsPointSequence() << QgsPoint( 20, 20 ) << QgsPoint( 21, 20 ) <<  QgsPoint( 20, 20 ) );
   13986                 :          1 :   multiLine1.addGeometry( boundaryLine3.clone() );
   13987                 :          1 :   boundary = multiLine1.boundary();
   13988                 :          1 :   mpBoundary = dynamic_cast< QgsMultiPoint * >( boundary );
   13989                 :          1 :   QVERIFY( mpBoundary );
   13990                 :          1 :   QCOMPARE( mpBoundary->numGeometries(), 4 );
   13991                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->x(), 0.0 );
   13992                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->y(), 0.0 );
   13993                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->x(), 1.0 );
   13994                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->y(), 1.0 );
   13995                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 2 ) )->x(), 10.0 );
   13996                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 2 ) )->y(), 10.0 );
   13997                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 3 ) )->x(), 11.0 );
   13998                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 3 ) )->y(), 11.0 );
   13999                 :          1 :   delete boundary;
   14000                 :            : 
   14001                 :            :   //boundary with z
   14002                 :          1 :   QgsCircularString boundaryLine4;
   14003                 :          1 :   boundaryLine4.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 10 ) << QgsPoint( QgsWkbTypes::PointZ, 1, 0, 15 ) << QgsPoint( QgsWkbTypes::PointZ, 1, 1, 20 ) );
   14004                 :          1 :   QgsCircularString boundaryLine5;
   14005                 :          1 :   boundaryLine5.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 10, 10, 100 ) << QgsPoint( QgsWkbTypes::PointZ, 10, 20, 150 ) << QgsPoint( QgsWkbTypes::PointZ, 20, 20, 200 ) );
   14006                 :          1 :   QgsMultiCurve multiLine2;
   14007                 :          1 :   multiLine2.addGeometry( boundaryLine4.clone() );
   14008                 :          1 :   multiLine2.addGeometry( boundaryLine5.clone() );
   14009                 :            : 
   14010                 :          1 :   boundary = multiLine2.boundary();
   14011                 :          1 :   mpBoundary = dynamic_cast< QgsMultiPoint * >( boundary );
   14012                 :          1 :   QVERIFY( mpBoundary );
   14013                 :          1 :   QCOMPARE( mpBoundary->numGeometries(), 4 );
   14014                 :          1 :   QCOMPARE( mpBoundary->geometryN( 0 )->wkbType(), QgsWkbTypes::PointZ );
   14015                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->x(), 0.0 );
   14016                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->y(), 0.0 );
   14017                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 0 ) )->z(), 10.0 );
   14018                 :          1 :   QCOMPARE( mpBoundary->geometryN( 1 )->wkbType(), QgsWkbTypes::PointZ );
   14019                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->x(), 1.0 );
   14020                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->y(), 1.0 );
   14021                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 1 ) )->z(), 20.0 );
   14022                 :          1 :   QCOMPARE( mpBoundary->geometryN( 2 )->wkbType(), QgsWkbTypes::PointZ );
   14023                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 2 ) )->x(), 10.0 );
   14024                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 2 ) )->y(), 10.0 );
   14025                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 2 ) )->z(), 100.0 );
   14026                 :          1 :   QCOMPARE( mpBoundary->geometryN( 3 )->wkbType(), QgsWkbTypes::PointZ );
   14027                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 3 ) )->x(), 20.0 );
   14028                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 3 ) )->y(), 20.0 );
   14029                 :          1 :   QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 3 ) )->z(), 200.0 );
   14030                 :          1 :   delete boundary;
   14031                 :            : 
   14032                 :            :   //reversed
   14033                 :          1 :   QgsMultiCurve cR;
   14034                 :          1 :   std::unique_ptr< QgsMultiCurve > reversed( cR.reversed() );
   14035                 :          1 :   QVERIFY( reversed->isEmpty() );
   14036                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 7, 17, 4, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 3, 13, 1, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 7, 11, 2, 8 ) ) ;
   14037                 :          1 :   cR.addGeometry( part.clone() );
   14038                 :          1 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 27, 37, 6, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 43, 43, 11, 5 )  << QgsPoint( QgsWkbTypes::PointZM, 27, 53, 21, 52 ) ) ;
   14039                 :          1 :   cR.addGeometry( part.clone() );
   14040                 :          1 :   reversed.reset( cR.reversed() );
   14041                 :          1 :   QVERIFY( !reversed->isEmpty() );
   14042                 :          1 :   ls = static_cast< const QgsCircularString * >( reversed->geometryN( 0 ) );
   14043                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 7, 11, 2, 8 ) );
   14044                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 3, 13, 1, 4 ) );
   14045                 :          1 :   QCOMPARE( ls->pointN( 2 ), QgsPoint( QgsWkbTypes::PointZM, 7, 17, 4, 1 ) );
   14046                 :          1 :   ls = static_cast< const QgsCircularString * >( reversed->geometryN( 1 ) );
   14047                 :          1 :   QCOMPARE( ls->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 27, 53, 21, 52 ) );
   14048                 :          1 :   QCOMPARE( ls->pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 43, 43, 11, 5 ) );
   14049                 :          1 :   QCOMPARE( ls->pointN( 2 ), QgsPoint( QgsWkbTypes::PointZM, 27, 37, 6, 2 ) );
   14050                 :            : 
   14051                 :            :   // segmentize
   14052                 :          1 :   QgsMultiCurve multiCurve2;
   14053                 :          1 :   QgsCompoundCurve compoundCurve2;
   14054                 :          1 :   QgsCircularString circularString2;
   14055                 :          1 :   circularString2.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 10 ) << QgsPoint( 21, 2 ) );
   14056                 :          1 :   compoundCurve2.addCurve( circularString2.clone() );
   14057                 :          1 :   multiCurve2.addGeometry( compoundCurve2.clone() );
   14058                 :          1 :   QgsMultiLineString *segmentized2 = static_cast<QgsMultiLineString *>( multiCurve2.segmentize() );
   14059                 :          1 :   QCOMPARE( segmentized2->vertexCount(), 156 );
   14060                 :          1 :   QCOMPARE( segmentized2->partCount(), 1 );
   14061                 :          1 :   QVERIFY( !segmentized2->is3D() );
   14062                 :          1 :   QVERIFY( !segmentized2->isMeasure() );
   14063                 :          1 :   QCOMPARE( segmentized2->wkbType(),  QgsWkbTypes::Type::MultiLineString );
   14064                 :          1 : }
   14065                 :            : 
   14066                 :          1 : void TestQgsGeometry::multiSurface()
   14067                 :            : {
   14068                 :            :   //test constructor
   14069                 :          1 :   QgsMultiSurface c1;
   14070                 :          1 :   QVERIFY( c1.isEmpty() );
   14071                 :          1 :   QCOMPARE( c1.nCoordinates(), 0 );
   14072                 :          1 :   QCOMPARE( c1.ringCount(), 0 );
   14073                 :          1 :   QCOMPARE( c1.partCount(), 0 );
   14074                 :          1 :   QVERIFY( !c1.is3D() );
   14075                 :          1 :   QVERIFY( !c1.isMeasure() );
   14076                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::MultiSurface );
   14077                 :          1 :   QCOMPARE( c1.wktTypeStr(), QString( "MultiSurface" ) );
   14078                 :          1 :   QCOMPARE( c1.geometryType(), QString( "MultiSurface" ) );
   14079                 :          1 :   QCOMPARE( c1.dimension(), 0 );
   14080                 :          1 :   QVERIFY( !c1.hasCurvedSegments() );
   14081                 :          1 :   QCOMPARE( c1.area(), 0.0 );
   14082                 :          1 :   QCOMPARE( c1.perimeter(), 0.0 );
   14083                 :          1 :   QCOMPARE( c1.numGeometries(), 0 );
   14084                 :          1 :   QVERIFY( !c1.geometryN( 0 ) );
   14085                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   14086                 :          1 :   QCOMPARE( c1.vertexCount( 0, 0 ), 0 );
   14087                 :          1 :   QCOMPARE( c1.vertexCount( 0, 1 ), 0 );
   14088                 :          1 :   QCOMPARE( c1.vertexCount( 1, 0 ), 0 );
   14089                 :            : 
   14090                 :            :   //addGeometry
   14091                 :            :   //try with nullptr
   14092                 :          1 :   c1.addGeometry( nullptr );
   14093                 :          1 :   QVERIFY( c1.isEmpty() );
   14094                 :          1 :   QCOMPARE( c1.nCoordinates(), 0 );
   14095                 :          1 :   QCOMPARE( c1.ringCount(), 0 );
   14096                 :          1 :   QCOMPARE( c1.partCount(), 0 );
   14097                 :          1 :   QCOMPARE( c1.numGeometries(), 0 );
   14098                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::MultiSurface );
   14099                 :          1 :   QVERIFY( !c1.geometryN( 0 ) );
   14100                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   14101                 :            : 
   14102                 :            :   // not a surface
   14103                 :          1 :   QVERIFY( !c1.addGeometry( new QgsPoint() ) );
   14104                 :          1 :   QVERIFY( c1.isEmpty() );
   14105                 :          1 :   QCOMPARE( c1.nCoordinates(), 0 );
   14106                 :          1 :   QCOMPARE( c1.ringCount(), 0 );
   14107                 :          1 :   QCOMPARE( c1.partCount(), 0 );
   14108                 :          1 :   QCOMPARE( c1.numGeometries(), 0 );
   14109                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::MultiSurface );
   14110                 :          1 :   QVERIFY( !c1.geometryN( 0 ) );
   14111                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   14112                 :            : 
   14113                 :            :   //valid geometry
   14114                 :          1 :   QgsCurvePolygon part;
   14115                 :          1 :   QgsCircularString ring;
   14116                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( 1, 10 ) << QgsPoint( 2, 11 ) << QgsPoint( 1, 10 ) );
   14117                 :          1 :   part.setExteriorRing( ring.clone() );
   14118                 :          1 :   c1.addGeometry( part.clone() );
   14119                 :          1 :   QVERIFY( !c1.isEmpty() );
   14120                 :          1 :   QCOMPARE( c1.numGeometries(), 1 );
   14121                 :          1 :   QCOMPARE( c1.nCoordinates(), 3 );
   14122                 :          1 :   QCOMPARE( c1.ringCount(), 1 );
   14123                 :          1 :   QCOMPARE( c1.partCount(), 1 );
   14124                 :          1 :   QVERIFY( !c1.is3D() );
   14125                 :          1 :   QVERIFY( !c1.isMeasure() );
   14126                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::MultiSurface );
   14127                 :          1 :   QCOMPARE( c1.wktTypeStr(), QString( "MultiSurface" ) );
   14128                 :          1 :   QCOMPARE( c1.geometryType(), QString( "MultiSurface" ) );
   14129                 :          1 :   QCOMPARE( c1.dimension(), 2 );
   14130                 :          1 :   QVERIFY( c1.hasCurvedSegments() );
   14131                 :          1 :   QVERIFY( c1.geometryN( 0 ) );
   14132                 :          1 :   QCOMPARE( *static_cast< const QgsCurvePolygon * >( c1.geometryN( 0 ) ), part );
   14133                 :          1 :   QVERIFY( !c1.geometryN( 100 ) );
   14134                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   14135                 :          1 :   QCOMPARE( c1.vertexCount( 0, 0 ), 3 );
   14136                 :          1 :   QCOMPARE( c1.vertexCount( 1, 0 ), 0 );
   14137                 :            : 
   14138                 :            :   //initial adding of geometry should set z/m type
   14139                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 10, 11, 1 ) << QgsPoint( QgsWkbTypes::PointZ, 20, 21, 2 )
   14140                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 10, 11, 1 ) );
   14141                 :          1 :   part.clear();
   14142                 :          1 :   part.setExteriorRing( ring.clone() );
   14143                 :          1 :   QgsMultiSurface c2;
   14144                 :          1 :   c2.addGeometry( part.clone() );
   14145                 :          1 :   QVERIFY( c2.is3D() );
   14146                 :          1 :   QVERIFY( !c2.isMeasure() );
   14147                 :          1 :   QCOMPARE( c2.wkbType(), QgsWkbTypes::MultiSurfaceZ );
   14148                 :          1 :   QCOMPARE( c2.wktTypeStr(), QString( "MultiSurfaceZ" ) );
   14149                 :          1 :   QCOMPARE( c2.geometryType(), QString( "MultiSurface" ) );
   14150                 :          1 :   QCOMPARE( *( static_cast< const QgsCurvePolygon * >( c2.geometryN( 0 ) ) ), part );
   14151                 :          1 :   QgsMultiSurface c3;
   14152                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 10, 11, 0, 1 ) << QgsPoint( QgsWkbTypes::PointM, 20, 21, 0, 2 )
   14153                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 10, 11, 0, 1 ) );
   14154                 :          1 :   part.clear();
   14155                 :          1 :   part.setExteriorRing( ring.clone() );
   14156                 :          1 :   c3.addGeometry( part.clone() );
   14157                 :          1 :   QVERIFY( !c3.is3D() );
   14158                 :          1 :   QVERIFY( c3.isMeasure() );
   14159                 :          1 :   QCOMPARE( c3.wkbType(), QgsWkbTypes::MultiSurfaceM );
   14160                 :          1 :   QCOMPARE( c3.wktTypeStr(), QString( "MultiSurfaceM" ) );
   14161                 :          1 :   QCOMPARE( *( static_cast< const QgsCurvePolygon * >( c3.geometryN( 0 ) ) ), part );
   14162                 :          1 :   QgsMultiSurface c4;
   14163                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 10, 11, 2, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 20, 21, 3, 2 )
   14164                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 10, 11, 2, 1 ) );
   14165                 :          1 :   part.clear();
   14166                 :          1 :   part.setExteriorRing( ring.clone() );
   14167                 :          1 :   c4.addGeometry( part.clone() );
   14168                 :          1 :   QVERIFY( c4.is3D() );
   14169                 :          1 :   QVERIFY( c4.isMeasure() );
   14170                 :          1 :   QCOMPARE( c4.wkbType(), QgsWkbTypes::MultiSurfaceZM );
   14171                 :          1 :   QCOMPARE( c4.wktTypeStr(), QString( "MultiSurfaceZM" ) );
   14172                 :          1 :   QCOMPARE( *( static_cast< const QgsCurvePolygon * >( c4.geometryN( 0 ) ) ), part );
   14173                 :            : 
   14174                 :            :   //add another part
   14175                 :          1 :   QgsMultiSurface c6;
   14176                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( 1, 10 ) << QgsPoint( 2, 11 ) << QgsPoint( 1, 10 ) );
   14177                 :          1 :   part.clear();
   14178                 :          1 :   part.setExteriorRing( ring.clone() );
   14179                 :          1 :   c6.addGeometry( part.clone() );
   14180                 :          1 :   QCOMPARE( c6.vertexCount( 0, 0 ), 3 );
   14181                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( 9, 12 ) << QgsPoint( 3, 13 )  << QgsPoint( 9, 12 ) );
   14182                 :          1 :   part.clear();
   14183                 :          1 :   part.setExteriorRing( ring.clone() );
   14184                 :          1 :   c6.addGeometry( part.clone() );
   14185                 :          1 :   QCOMPARE( c6.vertexCount( 1, 0 ), 3 );
   14186                 :          1 :   QCOMPARE( c6.numGeometries(), 2 );
   14187                 :          1 :   QVERIFY( c6.geometryN( 0 ) );
   14188                 :          1 :   QCOMPARE( *static_cast< const QgsCurvePolygon * >( c6.geometryN( 1 ) ), part );
   14189                 :            : 
   14190                 :            :   //adding subsequent points should not alter z/m type, regardless of parts type
   14191                 :          1 :   c6.clear();
   14192                 :          1 :   c6.addGeometry( part.clone() );
   14193                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiSurface );
   14194                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( 1, 10, 2 ) << QgsPoint( 2, 11, 3 ) << QgsPoint( 1, 10, 2 ) ) ;
   14195                 :          1 :   part.clear();
   14196                 :          1 :   part.setExteriorRing( ring.clone() );
   14197                 :          1 :   c6.addGeometry( part.clone() );
   14198                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiSurface );
   14199                 :          1 :   QCOMPARE( c6.vertexCount( 0, 0 ), 3 );
   14200                 :          1 :   QCOMPARE( c6.vertexCount( 1, 0 ), 3 );
   14201                 :          1 :   QCOMPARE( c6.vertexCount( 2, 0 ), 0 );
   14202                 :          1 :   QCOMPARE( c6.vertexCount( -1, 0 ), 0 );
   14203                 :          1 :   QCOMPARE( c6.nCoordinates(), 6 );
   14204                 :          1 :   QCOMPARE( c6.ringCount(), 1 );
   14205                 :          1 :   QCOMPARE( c6.partCount(), 2 );
   14206                 :          1 :   QVERIFY( !c6.is3D() );
   14207                 :          1 :   const QgsCurvePolygon *ls = static_cast< const QgsCurvePolygon * >( c6.geometryN( 0 ) );
   14208                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( 9, 12 ) );
   14209                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( 3, 13 ) );
   14210                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( 9, 12 ) );
   14211                 :          1 :   ls = static_cast< const QgsCurvePolygon * >( c6.geometryN( 1 ) );
   14212                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( 1, 10 ) );
   14213                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( 2, 11 ) );
   14214                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( 1, 10 ) );
   14215                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 21, 30, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 32, 41, 0, 3 )
   14216                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 21, 30, 0, 2 ) ) ;
   14217                 :          1 :   part.clear();
   14218                 :          1 :   part.setExteriorRing( ring.clone() );
   14219                 :          1 :   c6.addGeometry( part.clone() );
   14220                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiSurface );
   14221                 :          1 :   QCOMPARE( c6.vertexCount( 0, 0 ), 3 );
   14222                 :          1 :   QCOMPARE( c6.vertexCount( 1, 0 ), 3 );
   14223                 :          1 :   QCOMPARE( c6.vertexCount( 2, 0 ), 3 );
   14224                 :          1 :   QCOMPARE( c6.nCoordinates(), 9 );
   14225                 :          1 :   QCOMPARE( c6.ringCount(), 1 );
   14226                 :          1 :   QCOMPARE( c6.partCount(), 3 );
   14227                 :          1 :   QVERIFY( !c6.is3D() );
   14228                 :          1 :   QVERIFY( !c6.isMeasure() );
   14229                 :          1 :   ls = static_cast< const QgsCurvePolygon * >( c6.geometryN( 2 ) );
   14230                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( 21, 30 ) );
   14231                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( 32, 41 ) );
   14232                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( 21, 30 ) );
   14233                 :            : 
   14234                 :          1 :   c6.clear();
   14235                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( 1, 10, 2 ) << QgsPoint( 2, 11, 3 ) << QgsPoint( 1, 10, 2 ) ) ;
   14236                 :          1 :   part.clear();
   14237                 :          1 :   part.setExteriorRing( ring.clone() );
   14238                 :          1 :   c6.addGeometry( part.clone() );
   14239                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiSurfaceZ );
   14240                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( 2, 20 ) << QgsPoint( 3, 31 ) << QgsPoint( 2, 20 ) ) ;
   14241                 :          1 :   part.clear();
   14242                 :          1 :   part.setExteriorRing( ring.clone() );
   14243                 :          1 :   c6.addGeometry( part.clone() );
   14244                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiSurfaceZ );
   14245                 :          1 :   QVERIFY( c6.is3D() );
   14246                 :          1 :   ls = static_cast< const QgsCurvePolygon * >( c6.geometryN( 0 ) );
   14247                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( 1, 10, 2 ) );
   14248                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( 2, 11, 3 ) );
   14249                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( 1, 10, 2 ) );
   14250                 :          1 :   ls = static_cast< const QgsCurvePolygon * >( c6.geometryN( 1 ) );
   14251                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( 2, 20, 0 ) );
   14252                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( 3, 31, 0 ) );
   14253                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( 2, 20, 0 ) );
   14254                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 5, 50, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 6, 61, 0, 5 )
   14255                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 5, 50, 0, 4 ) ) ;
   14256                 :          1 :   part.clear();
   14257                 :          1 :   part.setExteriorRing( ring.clone() );
   14258                 :          1 :   c6.addGeometry( part.clone() );
   14259                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiSurfaceZ );
   14260                 :          1 :   QVERIFY( c6.is3D() );
   14261                 :          1 :   QVERIFY( !c6.isMeasure() );
   14262                 :          1 :   ls = static_cast< const QgsCurvePolygon * >( c6.geometryN( 2 ) );
   14263                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( 5, 50, 0 ) );
   14264                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( 6, 61, 0 ) );
   14265                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( 5, 50, 0 ) );
   14266                 :            : 
   14267                 :          1 :   c6.clear();
   14268                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiSurface );
   14269                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 5, 50, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 6, 61, 0, 5 )
   14270                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 5, 50, 0, 4 ) ) ;
   14271                 :          1 :   part.clear();
   14272                 :          1 :   part.setExteriorRing( ring.clone() );
   14273                 :          1 :   c6.addGeometry( part.clone() );
   14274                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiSurfaceM );
   14275                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( 2, 20 ) << QgsPoint( 3, 31 )   << QgsPoint( 2, 20 ) ) ;
   14276                 :          1 :   part.clear();
   14277                 :          1 :   part.setExteriorRing( ring.clone() );
   14278                 :          1 :   c6.addGeometry( part.clone() );
   14279                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiSurfaceM );
   14280                 :          1 :   QVERIFY( c6.isMeasure() );
   14281                 :          1 :   ls = static_cast< const QgsCurvePolygon * >( c6.geometryN( 0 ) );
   14282                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 5, 50, 0, 4 ) );
   14283                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( QgsWkbTypes::PointM, 6, 61, 0, 5 ) );
   14284                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( QgsWkbTypes::PointM, 5, 50, 0, 4 ) );
   14285                 :          1 :   ls = static_cast< const QgsCurvePolygon * >( c6.geometryN( 1 ) );
   14286                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 2, 20, 0, 0 ) );
   14287                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( QgsWkbTypes::PointM, 3, 31, 0, 0 ) );
   14288                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( QgsWkbTypes::PointM, 2, 20, 0, 0 ) );
   14289                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( 11, 12, 13 ) << QgsPoint( 14, 15, 16 ) << QgsPoint( 11, 12, 13 ) ) ;
   14290                 :          1 :   part.clear();
   14291                 :          1 :   part.setExteriorRing( ring.clone() );
   14292                 :          1 :   c6.addGeometry( part.clone() );
   14293                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiSurfaceM );
   14294                 :          1 :   QVERIFY( !c6.is3D() );
   14295                 :          1 :   QVERIFY( c6.isMeasure() );
   14296                 :          1 :   ls = static_cast< const QgsCurvePolygon * >( c6.geometryN( 2 ) );
   14297                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 0 ) );
   14298                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( QgsWkbTypes::PointM, 14, 15, 0, 0 ) );
   14299                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 0 ) );
   14300                 :            : 
   14301                 :          1 :   c6.clear();
   14302                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 5, 50, 1, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 6, 61, 3, 5 )
   14303                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 5, 50, 1, 4 ) ) ;
   14304                 :          1 :   part.clear();
   14305                 :          1 :   part.setExteriorRing( ring.clone() );
   14306                 :          1 :   c6.addGeometry( part.clone() );
   14307                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiSurfaceZM );
   14308                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 7, 17 ) << QgsPoint( QgsWkbTypes::Point, 3, 13 )
   14309                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 7, 17 ) ) ;
   14310                 :          1 :   part.clear();
   14311                 :          1 :   part.setExteriorRing( ring.clone() );
   14312                 :          1 :   c6.addGeometry( part.clone() );
   14313                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiSurfaceZM );
   14314                 :          1 :   QVERIFY( c6.isMeasure() );
   14315                 :          1 :   QVERIFY( c6.is3D() );
   14316                 :          1 :   ls = static_cast< const QgsCurvePolygon * >( c6.geometryN( 0 ) );
   14317                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 5, 50, 1, 4 ) );
   14318                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 6, 61, 3, 5 ) );
   14319                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( QgsWkbTypes::PointZM, 5, 50, 1, 4 ) );
   14320                 :          1 :   ls = static_cast< const QgsCurvePolygon * >( c6.geometryN( 1 ) );
   14321                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 7, 17, 0, 0 ) );
   14322                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 3, 13, 0, 0 ) );
   14323                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( QgsWkbTypes::PointZM, 7, 17, 0, 0 ) );
   14324                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 77, 87, 7 ) << QgsPoint( QgsWkbTypes::PointZ, 83, 83, 8 )
   14325                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 77, 87, 7 ) ) ;
   14326                 :          1 :   part.clear();
   14327                 :          1 :   part.setExteriorRing( ring.clone() );
   14328                 :          1 :   c6.addGeometry( part.clone() );
   14329                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiSurfaceZM );
   14330                 :          1 :   QVERIFY( c6.is3D() );
   14331                 :          1 :   QVERIFY( c6.isMeasure() );
   14332                 :          1 :   ls = static_cast< const QgsCurvePolygon * >( c6.geometryN( 2 ) );
   14333                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 77, 87, 7, 0 ) );
   14334                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 83, 83, 8, 0 ) );
   14335                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( QgsWkbTypes::PointZM, 77, 87, 7, 0 ) );
   14336                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 177, 187, 0, 9 ) << QgsPoint( QgsWkbTypes::PointM, 183, 183, 0, 11 )
   14337                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 177, 187, 0, 9 ) ) ;
   14338                 :          1 :   part.clear();
   14339                 :          1 :   part.setExteriorRing( ring.clone() );
   14340                 :          1 :   c6.addGeometry( part.clone() );
   14341                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiSurfaceZM );
   14342                 :          1 :   QVERIFY( c6.is3D() );
   14343                 :          1 :   QVERIFY( c6.isMeasure() );
   14344                 :          1 :   ls = static_cast< const QgsCurvePolygon * >( c6.geometryN( 3 ) );
   14345                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 177, 187, 0, 9 ) );
   14346                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 183, 183, 0, 11 ) );
   14347                 :          1 :   QCOMPARE( static_cast< const QgsCircularString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( QgsWkbTypes::PointZM, 177, 187, 0, 9 ) );
   14348                 :            : 
   14349                 :            :   //clear
   14350                 :          1 :   QgsMultiSurface c7;
   14351                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 5, 50, 1, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 6, 61, 3, 5 )
   14352                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 5, 71, 4, 6 ) ) ;
   14353                 :          1 :   part.clear();
   14354                 :          1 :   part.setExteriorRing( ring.clone() );
   14355                 :          1 :   c7.addGeometry( part.clone() );
   14356                 :          1 :   c7.addGeometry( part.clone() );
   14357                 :          1 :   QCOMPARE( c7.numGeometries(), 2 );
   14358                 :          1 :   c7.clear();
   14359                 :          1 :   QVERIFY( c7.isEmpty() );
   14360                 :          1 :   QCOMPARE( c7.numGeometries(), 0 );
   14361                 :          1 :   QCOMPARE( c7.nCoordinates(), 0 );
   14362                 :          1 :   QCOMPARE( c7.ringCount(), 0 );
   14363                 :          1 :   QCOMPARE( c7.partCount(), 0 );
   14364                 :          1 :   QVERIFY( !c7.is3D() );
   14365                 :          1 :   QVERIFY( !c7.isMeasure() );
   14366                 :          1 :   QCOMPARE( c7.wkbType(), QgsWkbTypes::MultiSurface );
   14367                 :            : 
   14368                 :            :   //clone
   14369                 :          1 :   QgsMultiSurface c11;
   14370                 :          1 :   std::unique_ptr< QgsMultiSurface >cloned( c11.clone() );
   14371                 :          1 :   QVERIFY( cloned->isEmpty() );
   14372                 :          1 :   c11.addGeometry( part.clone() );
   14373                 :          1 :   c11.addGeometry( part.clone() );
   14374                 :          1 :   cloned.reset( c11.clone() );
   14375                 :          1 :   QCOMPARE( cloned->numGeometries(), 2 );
   14376                 :          1 :   ls = static_cast< const QgsCurvePolygon * >( cloned->geometryN( 0 ) );
   14377                 :          1 :   QCOMPARE( *ls, part );
   14378                 :          1 :   ls = static_cast< const QgsCurvePolygon * >( cloned->geometryN( 1 ) );
   14379                 :          1 :   QCOMPARE( *ls, part );
   14380                 :            : 
   14381                 :            :   //copy constructor
   14382                 :          1 :   QgsMultiSurface c12;
   14383                 :          1 :   QgsMultiSurface c13( c12 );
   14384                 :          1 :   QVERIFY( c13.isEmpty() );
   14385                 :          1 :   c12.addGeometry( part.clone() );
   14386                 :          1 :   c12.addGeometry( part.clone() );
   14387                 :          1 :   QgsMultiSurface c14( c12 );
   14388                 :          1 :   QCOMPARE( c14.numGeometries(), 2 );
   14389                 :          1 :   QCOMPARE( c14.wkbType(), QgsWkbTypes::MultiSurfaceZM );
   14390                 :          1 :   ls = static_cast< const QgsCurvePolygon * >( c14.geometryN( 0 ) );
   14391                 :          1 :   QCOMPARE( *ls, part );
   14392                 :          1 :   ls = static_cast< const QgsCurvePolygon * >( c14.geometryN( 1 ) );
   14393                 :          1 :   QCOMPARE( *ls, part );
   14394                 :            : 
   14395                 :            :   //assignment operator
   14396                 :          1 :   QgsMultiSurface c15;
   14397                 :          1 :   c15 = c13;
   14398                 :          1 :   QCOMPARE( c15.numGeometries(), 0 );
   14399                 :          1 :   c15 = c14;
   14400                 :          1 :   QCOMPARE( c15.numGeometries(), 2 );
   14401                 :          1 :   ls = static_cast< const QgsCurvePolygon * >( c15.geometryN( 0 ) );
   14402                 :          1 :   QCOMPARE( *ls, part );
   14403                 :          1 :   ls = static_cast< const QgsCurvePolygon * >( c15.geometryN( 1 ) );
   14404                 :          1 :   QCOMPARE( *ls, part );
   14405                 :            : 
   14406                 :            :   //toCurveType
   14407                 :          1 :   std::unique_ptr< QgsMultiSurface > curveType( c12.toCurveType() );
   14408                 :          1 :   QCOMPARE( curveType->wkbType(), QgsWkbTypes::MultiSurfaceZM );
   14409                 :          1 :   QCOMPARE( curveType->numGeometries(), 2 );
   14410                 :          1 :   const QgsCurvePolygon *curve = static_cast< const QgsCurvePolygon * >( curveType->geometryN( 0 ) );
   14411                 :          1 :   QCOMPARE( *curve, *static_cast< const QgsCurvePolygon * >( c12.geometryN( 0 ) ) );
   14412                 :          1 :   curve = static_cast< const QgsCurvePolygon * >( curveType->geometryN( 1 ) );
   14413                 :          1 :   QCOMPARE( *curve, *static_cast< const QgsCurvePolygon * >( c12.geometryN( 1 ) ) );
   14414                 :            : 
   14415                 :            :   //to/fromWKB
   14416                 :          1 :   QgsMultiSurface c16;
   14417                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 7, 17 ) << QgsPoint( QgsWkbTypes::Point, 3, 13 ) << QgsPoint( QgsWkbTypes::Point, 7, 17 ) ) ;
   14418                 :          1 :   part.clear();
   14419                 :          1 :   part.setExteriorRing( ring.clone() );
   14420                 :          1 :   c16.addGeometry( part.clone() );
   14421                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 27, 37 ) << QgsPoint( QgsWkbTypes::Point, 43, 43 )  << QgsPoint( QgsWkbTypes::Point, 27, 37 ) ) ;
   14422                 :          1 :   part.clear();
   14423                 :          1 :   part.setExteriorRing( ring.clone() );
   14424                 :          1 :   c16.addGeometry( part.clone() );
   14425                 :          1 :   QByteArray wkb16 = c16.asWkb();
   14426                 :          1 :   QgsMultiSurface c17;
   14427                 :          1 :   QgsConstWkbPtr wkb16ptr( wkb16 );
   14428                 :          1 :   c17.fromWkb( wkb16ptr );
   14429                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   14430                 :          1 :   QCOMPARE( *static_cast< const QgsCurvePolygon * >( c17.geometryN( 0 ) ), *static_cast< const QgsCurvePolygon * >( c16.geometryN( 0 ) ) );
   14431                 :          1 :   QCOMPARE( *static_cast< const QgsCurvePolygon * >( c17.geometryN( 1 ) ), *static_cast< const QgsCurvePolygon * >( c16.geometryN( 1 ) ) );
   14432                 :            : 
   14433                 :            :   //parts with Z
   14434                 :          1 :   c16.clear();
   14435                 :          1 :   c17.clear();
   14436                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 7, 17, 1 ) << QgsPoint( QgsWkbTypes::PointZ, 3, 13, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 7, 17, 1 ) ) ;
   14437                 :          1 :   part.clear();
   14438                 :          1 :   part.setExteriorRing( ring.clone() );
   14439                 :          1 :   c16.addGeometry( part.clone() );
   14440                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 27, 37, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 43, 43, 5 ) << QgsPoint( QgsWkbTypes::PointZ, 27, 37, 2 ) ) ;
   14441                 :          1 :   part.clear();
   14442                 :          1 :   part.setExteriorRing( ring.clone() );
   14443                 :          1 :   c16.addGeometry( part.clone() );
   14444                 :          1 :   wkb16 = c16.asWkb();
   14445                 :          1 :   QgsConstWkbPtr wkb16ptr2( wkb16 );
   14446                 :          1 :   c17.fromWkb( wkb16ptr2 );
   14447                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   14448                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiSurfaceZ );
   14449                 :          1 :   QCOMPARE( *static_cast< const QgsCurvePolygon * >( c17.geometryN( 0 ) ), *static_cast< const QgsCurvePolygon * >( c16.geometryN( 0 ) ) );
   14450                 :          1 :   QCOMPARE( *static_cast< const QgsCurvePolygon * >( c17.geometryN( 1 ) ), *static_cast< const QgsCurvePolygon * >( c16.geometryN( 1 ) ) );
   14451                 :            : 
   14452                 :            :   //parts with m
   14453                 :          1 :   c16.clear();
   14454                 :          1 :   c17.clear();
   14455                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 7, 17, 0, 1 ) << QgsPoint( QgsWkbTypes::PointM, 3, 13, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 7, 17, 0, 1 ) ) ;
   14456                 :          1 :   part.clear();
   14457                 :          1 :   part.setExteriorRing( ring.clone() );
   14458                 :          1 :   c16.addGeometry( part.clone() );
   14459                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 27, 37, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 43, 43, 0, 5 ) << QgsPoint( QgsWkbTypes::PointM, 27, 37, 0, 2 ) ) ;
   14460                 :          1 :   part.clear();
   14461                 :          1 :   part.setExteriorRing( ring.clone() );
   14462                 :          1 :   c16.addGeometry( part.clone() );
   14463                 :          1 :   wkb16 = c16.asWkb();
   14464                 :          1 :   QgsConstWkbPtr wkb16ptr3( wkb16 );
   14465                 :          1 :   c17.fromWkb( wkb16ptr3 );
   14466                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   14467                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiSurfaceM );
   14468                 :          1 :   QCOMPARE( *static_cast< const QgsCurvePolygon * >( c17.geometryN( 0 ) ), *static_cast< const QgsCurvePolygon * >( c16.geometryN( 0 ) ) );
   14469                 :          1 :   QCOMPARE( *static_cast< const QgsCurvePolygon * >( c17.geometryN( 1 ) ), *static_cast< const QgsCurvePolygon * >( c16.geometryN( 1 ) ) );
   14470                 :            : 
   14471                 :            :   // parts with ZM
   14472                 :          1 :   c16.clear();
   14473                 :          1 :   c17.clear();
   14474                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 7, 17, 4, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 3, 13, 1, 4 )  << QgsPoint( QgsWkbTypes::PointZM, 7, 17, 4, 1 ) ) ;
   14475                 :          1 :   part.clear();
   14476                 :          1 :   part.setExteriorRing( ring.clone() );
   14477                 :          1 :   c16.addGeometry( part.clone() );
   14478                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 27, 37, 6, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 43, 43, 11, 5 ) << QgsPoint( QgsWkbTypes::PointZM, 27, 37, 6, 2 ) ) ;
   14479                 :          1 :   part.clear();
   14480                 :          1 :   part.setExteriorRing( ring.clone() );
   14481                 :          1 :   c16.addGeometry( part.clone() );
   14482                 :          1 :   wkb16 = c16.asWkb();
   14483                 :          1 :   QgsConstWkbPtr wkb16ptr4( wkb16 );
   14484                 :          1 :   c17.fromWkb( wkb16ptr4 );
   14485                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   14486                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiSurfaceZM );
   14487                 :          1 :   QCOMPARE( *static_cast< const QgsCurvePolygon * >( c17.geometryN( 0 ) ), *static_cast< const QgsCurvePolygon * >( c16.geometryN( 0 ) ) );
   14488                 :          1 :   QCOMPARE( *static_cast< const QgsCurvePolygon * >( c17.geometryN( 1 ) ), *static_cast< const QgsCurvePolygon * >( c16.geometryN( 1 ) ) );
   14489                 :            : 
   14490                 :            :   //bad WKB - check for no crash
   14491                 :          1 :   c17.clear();
   14492                 :          1 :   QgsConstWkbPtr nullPtr( nullptr, 0 );
   14493                 :          1 :   QVERIFY( !c17.fromWkb( nullPtr ) );
   14494                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiSurface );
   14495                 :          1 :   QgsPoint point( 1, 2 );
   14496                 :          1 :   QByteArray wkbPoint = point.asWkb();
   14497                 :          1 :   QgsConstWkbPtr wkbPointPtr( wkbPoint );
   14498                 :          1 :   QVERIFY( !c17.fromWkb( wkbPointPtr ) );
   14499                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiSurface );
   14500                 :            : 
   14501                 :            :   //to/from WKT
   14502                 :          1 :   QgsMultiSurface c18;
   14503                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 7, 17, 4, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 3, 13, 1, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 7, 11, 2, 8 ) ) ;
   14504                 :          1 :   part.clear();
   14505                 :          1 :   part.setExteriorRing( ring.clone() );
   14506                 :          1 :   c18.addGeometry( part.clone() );
   14507                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 27, 37, 6, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 43, 43, 11, 5 )  << QgsPoint( QgsWkbTypes::PointZM, 27, 53, 21, 52 ) ) ;
   14508                 :          1 :   part.clear();
   14509                 :          1 :   part.setExteriorRing( ring.clone() );
   14510                 :          1 :   c18.addGeometry( part.clone() );
   14511                 :            : 
   14512                 :          1 :   QString wkt = c18.asWkt();
   14513                 :          1 :   QVERIFY( !wkt.isEmpty() );
   14514                 :          1 :   QgsMultiSurface c19;
   14515                 :          1 :   QVERIFY( c19.fromWkt( wkt ) );
   14516                 :          1 :   QCOMPARE( c19.numGeometries(), 2 );
   14517                 :          1 :   QCOMPARE( *static_cast< const QgsCurvePolygon * >( c19.geometryN( 0 ) ), *static_cast< const QgsCurvePolygon * >( c18.geometryN( 0 ) ) );
   14518                 :          1 :   QCOMPARE( *static_cast< const QgsCurvePolygon * >( c19.geometryN( 1 ) ), *static_cast< const QgsCurvePolygon * >( c18.geometryN( 1 ) ) );
   14519                 :            : 
   14520                 :            :   //bad WKT
   14521                 :          1 :   QgsMultiSurface c20;
   14522                 :          1 :   QVERIFY( !c20.fromWkt( "Point()" ) );
   14523                 :          1 :   QVERIFY( c20.isEmpty() );
   14524                 :          1 :   QCOMPARE( c20.numGeometries(), 0 );
   14525                 :          1 :   QCOMPARE( c20.wkbType(), QgsWkbTypes::MultiSurface );
   14526                 :            : 
   14527                 :            :   //as JSON
   14528                 :          1 :   QgsMultiSurface exportC;
   14529                 :          1 :   QgsLineString lineRing;
   14530                 :          1 :   lineRing.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 7, 17 ) << QgsPoint( QgsWkbTypes::Point, 7, 13 )  << QgsPoint( QgsWkbTypes::Point, 3, 13 ) << QgsPoint( QgsWkbTypes::Point, 7, 17 ) ) ;
   14531                 :          1 :   part.clear();
   14532                 :          1 :   part.setExteriorRing( lineRing.clone() );
   14533                 :          1 :   exportC.addGeometry( part.clone() );
   14534                 :          1 :   lineRing.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 27, 37 ) << QgsPoint( QgsWkbTypes::Point, 27, 43 ) << QgsPoint( QgsWkbTypes::Point, 43, 43 )  << QgsPoint( QgsWkbTypes::Point, 27, 37 ) ) ;
   14535                 :          1 :   part.clear();
   14536                 :          1 :   part.setExteriorRing( lineRing.clone() );
   14537                 :          1 :   exportC.addGeometry( part.clone() );
   14538                 :            : 
   14539                 :            :   // GML document for compare
   14540                 :          1 :   QDomDocument doc( "gml" );
   14541                 :            : 
   14542                 :            :   // as GML2
   14543                 :          2 :   QString expectedSimpleGML2( QStringLiteral( "<MultiPolygon xmlns=\"gml\"><polygonMember xmlns=\"gml\"><Polygon xmlns=\"gml\"><outerBoundaryIs xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">7,17 7,13 3,13 7,17</coordinates></LinearRing></outerBoundaryIs></Polygon></polygonMember><polygonMember xmlns=\"gml\"><Polygon xmlns=\"gml\"><outerBoundaryIs xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">27,37 27,43 43,43 27,37</coordinates></LinearRing></outerBoundaryIs></Polygon></polygonMember></MultiPolygon>" ) );
   14544                 :          1 :   QString res = elemToString( exportC.asGml2( doc, 1 ) );
   14545                 :          3 :   QGSCOMPAREGML( res, expectedSimpleGML2 );
   14546                 :          2 :   QString expectedGML2empty( QStringLiteral( "<MultiPolygon xmlns=\"gml\"/>" ) );
   14547                 :          3 :   QGSCOMPAREGML( elemToString( QgsMultiSurface().asGml2( doc ) ), expectedGML2empty );
   14548                 :            : 
   14549                 :            :   //as GML3
   14550                 :            : 
   14551                 :          2 :   QString expectedSimpleGML3( QStringLiteral( "<MultiSurface xmlns=\"gml\"><surfaceMember xmlns=\"gml\"><Polygon xmlns=\"gml\"><exterior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">7 17 7 13 3 13 7 17</posList></LinearRing></exterior></Polygon></surfaceMember><surfaceMember xmlns=\"gml\"><Polygon xmlns=\"gml\"><exterior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">27 37 27 43 43 43 27 37</posList></LinearRing></exterior></Polygon></surfaceMember></MultiSurface>" ) );
   14552                 :          1 :   res = elemToString( exportC.asGml3( doc ) );
   14553                 :          1 :   QCOMPARE( res, expectedSimpleGML3 );
   14554                 :          2 :   QString expectedGML3empty( QStringLiteral( "<MultiSurface xmlns=\"gml\"/>" ) );
   14555                 :          3 :   QGSCOMPAREGML( elemToString( QgsMultiSurface().asGml3( doc ) ), expectedGML3empty );
   14556                 :            : 
   14557                 :            :   // as JSON
   14558                 :          1 :   QString expectedSimpleJson( "{\"coordinates\":[[[[7.0,17.0],[7.0,13.0],[3.0,13.0],[7.0,17.0]]],[[[27.0,37.0],[27.0,43.0],[43.0,43.0],[27.0,37.0]]]],\"type\":\"MultiPolygon\"}" );
   14559                 :          1 :   res = exportC.asJson( 1 );
   14560                 :          1 :   QCOMPARE( res, expectedSimpleJson );
   14561                 :            : 
   14562                 :          1 :   lineRing.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 17, 27 ) << QgsPoint( QgsWkbTypes::Point, 17, 28 ) << QgsPoint( QgsWkbTypes::Point, 18, 28 )  << QgsPoint( QgsWkbTypes::Point, 17, 27 ) ) ;
   14563                 :          1 :   part.addInteriorRing( lineRing.clone() );
   14564                 :          1 :   exportC.addGeometry( part.clone() );
   14565                 :            : 
   14566                 :          1 :   QString expectedJsonWithRings( "{\"coordinates\":[[[[7.0,17.0],[7.0,13.0],[3.0,13.0],[7.0,17.0]]],[[[27.0,37.0],[27.0,43.0],[43.0,43.0],[27.0,37.0]]],[[[27.0,37.0],[27.0,43.0],[43.0,43.0],[27.0,37.0]],[[17.0,27.0],[17.0,28.0],[18.0,28.0],[17.0,27.0]]]],\"type\":\"MultiPolygon\"}" );
   14567                 :          1 :   res = exportC.asJson( 1 );
   14568                 :          1 :   QCOMPARE( res, expectedJsonWithRings );
   14569                 :            : 
   14570                 :          1 :   QgsMultiSurface exportFloat;
   14571                 :          1 :   lineRing.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 0.1234, 0.1234 ) << QgsPoint( QgsWkbTypes::Point, 0.1234, 1.2344 ) << QgsPoint( QgsWkbTypes::Point, 1.2344, 1.2344 ) << QgsPoint( QgsWkbTypes::Point, 0.1234, 0.1234 ) ) ;
   14572                 :          1 :   part.clear();
   14573                 :          1 :   part.setExteriorRing( lineRing.clone() );
   14574                 :          1 :   exportFloat.addGeometry( part.clone() );
   14575                 :            : 
   14576                 :          2 :   QString expectedJsonPrec3( QStringLiteral( "{\"coordinates\":[[[[0.123,0.123],[0.123,1.234],[1.234,1.234],[0.123,0.123]]]],\"type\":\"MultiPolygon\"}" ) );
   14577                 :          1 :   res = exportFloat.asJson( 3 );
   14578                 :          1 :   QCOMPARE( res, expectedJsonPrec3 );
   14579                 :            : 
   14580                 :            :   // as GML2
   14581                 :          2 :   QString expectedGML2prec3( QStringLiteral( "<MultiPolygon xmlns=\"gml\"><polygonMember xmlns=\"gml\"><Polygon xmlns=\"gml\"><outerBoundaryIs xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">0.123,0.123 0.123,1.234 1.234,1.234 0.123,0.123</coordinates></LinearRing></outerBoundaryIs></Polygon></polygonMember></MultiPolygon>" ) );
   14582                 :          1 :   res = elemToString( exportFloat.asGml2( doc, 3 ) );
   14583                 :          3 :   QGSCOMPAREGML( res, expectedGML2prec3 );
   14584                 :            : 
   14585                 :            :   //as GML3
   14586                 :          2 :   QString expectedGML3prec3( QStringLiteral( "<MultiSurface xmlns=\"gml\"><surfaceMember xmlns=\"gml\"><Polygon xmlns=\"gml\"><exterior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">0.123 0.123 0.123 1.234 1.234 1.234 0.123 0.123</posList></LinearRing></exterior></Polygon></surfaceMember></MultiSurface>" ) );
   14587                 :          1 :   res = elemToString( exportFloat.asGml3( doc, 3 ) );
   14588                 :          1 :   QCOMPARE( res, expectedGML3prec3 );
   14589                 :            : 
   14590                 :            :   //asKML
   14591                 :          2 :   QString expectedKmlPrec3( QStringLiteral( "<MultiGeometry><Polygon><outerBoundaryIs><LinearRing><altitudeMode>clampToGround</altitudeMode><coordinates>0.123,0.123,0 0.123,1.234,0 1.234,1.234,0 0.123,0.123,0</coordinates></LinearRing></outerBoundaryIs></Polygon></MultiGeometry>" ) );
   14592                 :          1 :   QCOMPARE( exportFloat.asKml( 3 ), expectedKmlPrec3 );
   14593                 :            : 
   14594                 :            :   // insert geometry
   14595                 :          1 :   QgsMultiSurface rc;
   14596                 :          1 :   rc.clear();
   14597                 :          1 :   rc.insertGeometry( nullptr, 0 );
   14598                 :          1 :   QVERIFY( rc.isEmpty() );
   14599                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   14600                 :          1 :   rc.insertGeometry( nullptr, -1 );
   14601                 :          1 :   QVERIFY( rc.isEmpty() );
   14602                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   14603                 :          1 :   rc.insertGeometry( nullptr, 100 );
   14604                 :          1 :   QVERIFY( rc.isEmpty() );
   14605                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   14606                 :            : 
   14607                 :          1 :   rc.insertGeometry( new QgsPoint(), 0 );
   14608                 :          1 :   QVERIFY( rc.isEmpty() );
   14609                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   14610                 :            : 
   14611                 :          1 :   rc.insertGeometry( part.clone(), 0 );
   14612                 :          1 :   QVERIFY( !rc.isEmpty() );
   14613                 :          1 :   QCOMPARE( rc.numGeometries(), 1 );
   14614                 :            : 
   14615                 :            :   // cast
   14616                 :          1 :   QVERIFY( !QgsMultiSurface().cast( nullptr ) );
   14617                 :          1 :   QgsMultiSurface pCast;
   14618                 :          1 :   QVERIFY( QgsMultiSurface().cast( &pCast ) );
   14619                 :          1 :   QgsMultiSurface pCast2;
   14620                 :          2 :   pCast2.fromWkt( QStringLiteral( "MultiSurfaceZ()" ) );
   14621                 :          1 :   QVERIFY( QgsMultiSurface().cast( &pCast2 ) );
   14622                 :          2 :   pCast2.fromWkt( QStringLiteral( "MultiSurfaceM()" ) );
   14623                 :          1 :   QVERIFY( QgsMultiSurface().cast( &pCast2 ) );
   14624                 :          2 :   pCast2.fromWkt( QStringLiteral( "MultiSurfaceZM()" ) );
   14625                 :          1 :   QVERIFY( QgsMultiSurface().cast( &pCast2 ) );
   14626                 :            : 
   14627                 :            :   //boundary
   14628                 :          1 :   QgsMultiSurface multiSurface;
   14629                 :          1 :   QVERIFY( !multiSurface.boundary() );
   14630                 :          1 :   QgsCircularString boundaryLine1;
   14631                 :          1 :   boundaryLine1.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 0, 0 ) );
   14632                 :          1 :   part.clear();
   14633                 :          1 :   part.setExteriorRing( boundaryLine1.clone() );
   14634                 :          1 :   multiSurface.addGeometry( part.clone() );
   14635                 :          1 :   QgsAbstractGeometry *boundary = multiSurface.boundary();
   14636                 :          1 :   QgsMultiCurve *mpBoundary = dynamic_cast< QgsMultiCurve * >( boundary );
   14637                 :          1 :   QVERIFY( mpBoundary );
   14638                 :          1 :   QCOMPARE( mpBoundary->numGeometries(), 1 );
   14639                 :          1 :   QCOMPARE( *static_cast< const QgsCurve *>( mpBoundary->geometryN( 0 ) ), *part.exteriorRing() );
   14640                 :          1 :   delete boundary;
   14641                 :            :   // add another QgsCircularString
   14642                 :          1 :   QgsCircularString boundaryLine2;
   14643                 :          1 :   boundaryLine2.setPoints( QgsPointSequence() << QgsPoint( 10, 10 ) << QgsPoint( 11, 10 ) << QgsPoint( 10, 10 ) );
   14644                 :          1 :   QgsCurvePolygon part2;
   14645                 :          1 :   part2.setExteriorRing( boundaryLine2.clone() );
   14646                 :          1 :   multiSurface.addGeometry( part2.clone() );
   14647                 :          1 :   boundary = multiSurface.boundary();
   14648                 :          1 :   mpBoundary = dynamic_cast< QgsMultiCurve * >( boundary );
   14649                 :          1 :   QVERIFY( mpBoundary );
   14650                 :          1 :   QCOMPARE( mpBoundary->numGeometries(), 2 );
   14651                 :          1 :   QCOMPARE( *static_cast< const QgsCurve *>( mpBoundary->geometryN( 0 ) ), *part.exteriorRing() );
   14652                 :          1 :   QCOMPARE( *static_cast< const QgsCurve *>( mpBoundary->geometryN( 1 ) ), *part2.exteriorRing() );
   14653                 :          1 :   delete boundary;
   14654                 :            : 
   14655                 :            :   //boundary with z
   14656                 :          1 :   QgsCircularString boundaryLine4;
   14657                 :          1 :   boundaryLine4.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 10 ) << QgsPoint( QgsWkbTypes::PointZ, 1, 0, 15 ) << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 10 ) );
   14658                 :          1 :   part.clear();
   14659                 :          1 :   part.setExteriorRing( boundaryLine4.clone() );
   14660                 :          1 :   QgsCircularString boundaryLine5;
   14661                 :          1 :   boundaryLine5.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 10, 10, 100 ) << QgsPoint( QgsWkbTypes::PointZ, 10, 20, 150 ) << QgsPoint( QgsWkbTypes::PointZ, 10, 10, 100 ) );
   14662                 :          1 :   part2.clear();
   14663                 :          1 :   part2.setExteriorRing( boundaryLine5.clone() );
   14664                 :          1 :   QgsMultiSurface multiSurface2;
   14665                 :          1 :   multiSurface2.addGeometry( part.clone() );
   14666                 :          1 :   multiSurface2.addGeometry( part2.clone() );
   14667                 :            : 
   14668                 :          1 :   boundary = multiSurface2.boundary();
   14669                 :          1 :   mpBoundary = dynamic_cast< QgsMultiCurve * >( boundary );
   14670                 :          1 :   QVERIFY( mpBoundary );
   14671                 :          1 :   QCOMPARE( mpBoundary->numGeometries(), 2 );
   14672                 :          1 :   QCOMPARE( *static_cast< const QgsCurve *>( mpBoundary->geometryN( 0 ) ), *part.exteriorRing() );
   14673                 :          1 :   QCOMPARE( *static_cast< const QgsCurve *>( mpBoundary->geometryN( 1 ) ), *part2.exteriorRing() );
   14674                 :          1 :   delete boundary;
   14675                 :          1 : }
   14676                 :            : 
   14677                 :          1 : void TestQgsGeometry::multiPolygon()
   14678                 :            : {
   14679                 :            :   //test constructor
   14680                 :          1 :   QgsMultiPolygon c1;
   14681                 :          1 :   QVERIFY( c1.isEmpty() );
   14682                 :          1 :   QCOMPARE( c1.nCoordinates(), 0 );
   14683                 :          1 :   QCOMPARE( c1.ringCount(), 0 );
   14684                 :          1 :   QCOMPARE( c1.partCount(), 0 );
   14685                 :          1 :   QVERIFY( !c1.is3D() );
   14686                 :          1 :   QVERIFY( !c1.isMeasure() );
   14687                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::MultiPolygon );
   14688                 :          1 :   QCOMPARE( c1.wktTypeStr(), QString( "MultiPolygon" ) );
   14689                 :          1 :   QCOMPARE( c1.geometryType(), QString( "MultiPolygon" ) );
   14690                 :          1 :   QCOMPARE( c1.dimension(), 0 );
   14691                 :          1 :   QVERIFY( !c1.hasCurvedSegments() );
   14692                 :          1 :   QCOMPARE( c1.area(), 0.0 );
   14693                 :          1 :   QCOMPARE( c1.perimeter(), 0.0 );
   14694                 :          1 :   QCOMPARE( c1.numGeometries(), 0 );
   14695                 :          1 :   QVERIFY( !c1.geometryN( 0 ) );
   14696                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   14697                 :          1 :   QCOMPARE( c1.vertexCount( 0, 0 ), 0 );
   14698                 :          1 :   QCOMPARE( c1.vertexCount( 0, 1 ), 0 );
   14699                 :          1 :   QCOMPARE( c1.vertexCount( 1, 0 ), 0 );
   14700                 :            : 
   14701                 :            :   //addGeometry
   14702                 :            :   //try with nullptr
   14703                 :          1 :   c1.addGeometry( nullptr );
   14704                 :          1 :   QVERIFY( c1.isEmpty() );
   14705                 :          1 :   QCOMPARE( c1.nCoordinates(), 0 );
   14706                 :          1 :   QCOMPARE( c1.ringCount(), 0 );
   14707                 :          1 :   QCOMPARE( c1.partCount(), 0 );
   14708                 :          1 :   QCOMPARE( c1.numGeometries(), 0 );
   14709                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::MultiPolygon );
   14710                 :          1 :   QVERIFY( !c1.geometryN( 0 ) );
   14711                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   14712                 :            : 
   14713                 :            :   // not a surface
   14714                 :          1 :   QVERIFY( !c1.addGeometry( new QgsPoint() ) );
   14715                 :          1 :   QVERIFY( c1.isEmpty() );
   14716                 :          1 :   QCOMPARE( c1.nCoordinates(), 0 );
   14717                 :          1 :   QCOMPARE( c1.ringCount(), 0 );
   14718                 :          1 :   QCOMPARE( c1.partCount(), 0 );
   14719                 :          1 :   QCOMPARE( c1.numGeometries(), 0 );
   14720                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::MultiPolygon );
   14721                 :          1 :   QVERIFY( !c1.geometryN( 0 ) );
   14722                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   14723                 :            : 
   14724                 :            :   //valid geometry
   14725                 :          1 :   QgsPolygon part;
   14726                 :          1 :   QgsLineString ring;
   14727                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( 1, 10 ) << QgsPoint( 2, 11 ) << QgsPoint( 2, 21 ) << QgsPoint( 1, 10 ) );
   14728                 :          1 :   part.setExteriorRing( ring.clone() );
   14729                 :          1 :   c1.addGeometry( part.clone() );
   14730                 :          1 :   QVERIFY( !c1.isEmpty() );
   14731                 :          1 :   QCOMPARE( c1.numGeometries(), 1 );
   14732                 :          1 :   QCOMPARE( c1.nCoordinates(), 4 );
   14733                 :          1 :   QCOMPARE( c1.ringCount(), 1 );
   14734                 :          1 :   QCOMPARE( c1.partCount(), 1 );
   14735                 :          1 :   QVERIFY( !c1.is3D() );
   14736                 :          1 :   QVERIFY( !c1.isMeasure() );
   14737                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::MultiPolygon );
   14738                 :          1 :   QCOMPARE( c1.wktTypeStr(), QString( "MultiPolygon" ) );
   14739                 :          1 :   QCOMPARE( c1.geometryType(), QString( "MultiPolygon" ) );
   14740                 :          1 :   QCOMPARE( c1.dimension(), 2 );
   14741                 :          1 :   QVERIFY( !c1.hasCurvedSegments() );
   14742                 :          1 :   QVERIFY( c1.geometryN( 0 ) );
   14743                 :          1 :   QCOMPARE( *static_cast< const QgsPolygon * >( c1.geometryN( 0 ) ), part );
   14744                 :          1 :   QVERIFY( !c1.geometryN( 100 ) );
   14745                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   14746                 :          1 :   QCOMPARE( c1.vertexCount( 0, 0 ), 4 );
   14747                 :          1 :   QCOMPARE( c1.vertexCount( 1, 0 ), 0 );
   14748                 :            : 
   14749                 :            :   //initial adding of geometry should set z/m type
   14750                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 10, 11, 1 ) << QgsPoint( QgsWkbTypes::PointZ, 20, 21, 2 )  << QgsPoint( QgsWkbTypes::PointZ, 30, 31, 2 )
   14751                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 10, 11, 1 ) );
   14752                 :          1 :   part.clear();
   14753                 :          1 :   part.setExteriorRing( ring.clone() );
   14754                 :          1 :   QgsMultiPolygon c2;
   14755                 :          1 :   c2.addGeometry( part.clone() );
   14756                 :          1 :   QVERIFY( c2.is3D() );
   14757                 :          1 :   QVERIFY( !c2.isMeasure() );
   14758                 :          1 :   QCOMPARE( c2.wkbType(), QgsWkbTypes::MultiPolygonZ );
   14759                 :          1 :   QCOMPARE( c2.wktTypeStr(), QString( "MultiPolygonZ" ) );
   14760                 :          1 :   QCOMPARE( c2.geometryType(), QString( "MultiPolygon" ) );
   14761                 :          1 :   QCOMPARE( *( static_cast< const QgsPolygon * >( c2.geometryN( 0 ) ) ), part );
   14762                 :          1 :   QgsMultiPolygon c3;
   14763                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 10, 11, 0, 1 ) << QgsPoint( QgsWkbTypes::PointM, 20, 21, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 30, 31, 0, 2 )
   14764                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 10, 11, 0, 1 ) );
   14765                 :          1 :   part.clear();
   14766                 :          1 :   part.setExteriorRing( ring.clone() );
   14767                 :          1 :   c3.addGeometry( part.clone() );
   14768                 :          1 :   QVERIFY( !c3.is3D() );
   14769                 :          1 :   QVERIFY( c3.isMeasure() );
   14770                 :          1 :   QCOMPARE( c3.wkbType(), QgsWkbTypes::MultiPolygonM );
   14771                 :          1 :   QCOMPARE( c3.wktTypeStr(), QString( "MultiPolygonM" ) );
   14772                 :          1 :   QCOMPARE( *( static_cast< const QgsPolygon * >( c3.geometryN( 0 ) ) ), part );
   14773                 :          1 :   QgsMultiPolygon c4;
   14774                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 10, 11, 2, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 20, 21, 3, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 30, 31, 3, 2 )
   14775                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 10, 11, 2, 1 ) );
   14776                 :          1 :   part.clear();
   14777                 :          1 :   part.setExteriorRing( ring.clone() );
   14778                 :          1 :   c4.addGeometry( part.clone() );
   14779                 :          1 :   QVERIFY( c4.is3D() );
   14780                 :          1 :   QVERIFY( c4.isMeasure() );
   14781                 :          1 :   QCOMPARE( c4.wkbType(), QgsWkbTypes::MultiPolygonZM );
   14782                 :          1 :   QCOMPARE( c4.wktTypeStr(), QString( "MultiPolygonZM" ) );
   14783                 :          1 :   QCOMPARE( *( static_cast< const QgsPolygon * >( c4.geometryN( 0 ) ) ), part );
   14784                 :            : 
   14785                 :            :   //add another part
   14786                 :          1 :   QgsMultiPolygon c6;
   14787                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( 1, 10 ) << QgsPoint( 2, 11 ) << QgsPoint( 10, 21 ) << QgsPoint( 1, 10 ) );
   14788                 :          1 :   part.clear();
   14789                 :          1 :   part.setExteriorRing( ring.clone() );
   14790                 :          1 :   c6.addGeometry( part.clone() );
   14791                 :          1 :   QCOMPARE( c6.vertexCount( 0, 0 ), 4 );
   14792                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( 9, 12 ) << QgsPoint( 3, 13 )  << QgsPoint( 4, 17 ) << QgsPoint( 9, 12 ) );
   14793                 :          1 :   part.clear();
   14794                 :          1 :   part.setExteriorRing( ring.clone() );
   14795                 :          1 :   c6.addGeometry( part.clone() );
   14796                 :          1 :   QCOMPARE( c6.vertexCount( 1, 0 ), 4 );
   14797                 :          1 :   QCOMPARE( c6.numGeometries(), 2 );
   14798                 :          1 :   QVERIFY( c6.geometryN( 0 ) );
   14799                 :          1 :   QCOMPARE( *static_cast< const QgsPolygon * >( c6.geometryN( 1 ) ), part );
   14800                 :            : 
   14801                 :            :   //adding subsequent points should not alter z/m type, regardless of parts type
   14802                 :          1 :   c6.clear();
   14803                 :          1 :   c6.addGeometry( part.clone() );
   14804                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPolygon );
   14805                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( 1, 10, 2 ) << QgsPoint( 2, 11, 3 ) << QgsPoint( 10, 13, 3 ) << QgsPoint( 1, 10, 2 ) ) ;
   14806                 :          1 :   part.clear();
   14807                 :          1 :   part.setExteriorRing( ring.clone() );
   14808                 :          1 :   c6.addGeometry( part.clone() );
   14809                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPolygon );
   14810                 :          1 :   QCOMPARE( c6.vertexCount( 0, 0 ), 4 );
   14811                 :          1 :   QCOMPARE( c6.vertexCount( 1, 0 ), 4 );
   14812                 :          1 :   QCOMPARE( c6.vertexCount( 2, 0 ), 0 );
   14813                 :          1 :   QCOMPARE( c6.vertexCount( -1, 0 ), 0 );
   14814                 :          1 :   QCOMPARE( c6.nCoordinates(), 8 );
   14815                 :          1 :   QCOMPARE( c6.ringCount(), 1 );
   14816                 :          1 :   QCOMPARE( c6.partCount(), 2 );
   14817                 :          1 :   QVERIFY( !c6.is3D() );
   14818                 :          1 :   const QgsPolygon *ls = static_cast< const QgsPolygon * >( c6.geometryN( 0 ) );
   14819                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( 9, 12 ) );
   14820                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( 3, 13 ) );
   14821                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( 4, 17 ) );
   14822                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 3 ), QgsPoint( 9, 12 ) );
   14823                 :          1 :   ls = static_cast< const QgsPolygon * >( c6.geometryN( 1 ) );
   14824                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( 1, 10 ) );
   14825                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( 2, 11 ) );
   14826                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( 10, 13 ) );
   14827                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 3 ), QgsPoint( 1, 10 ) );
   14828                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 21, 30, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 32, 41, 0, 3 )
   14829                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 42, 61, 0, 4 )
   14830                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 21, 30, 0, 2 ) ) ;
   14831                 :          1 :   part.clear();
   14832                 :          1 :   part.setExteriorRing( ring.clone() );
   14833                 :          1 :   c6.addGeometry( part.clone() );
   14834                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPolygon );
   14835                 :          1 :   QCOMPARE( c6.vertexCount( 0, 0 ), 4 );
   14836                 :          1 :   QCOMPARE( c6.vertexCount( 1, 0 ), 4 );
   14837                 :          1 :   QCOMPARE( c6.vertexCount( 2, 0 ), 4 );
   14838                 :          1 :   QCOMPARE( c6.nCoordinates(), 12 );
   14839                 :          1 :   QCOMPARE( c6.ringCount(), 1 );
   14840                 :          1 :   QCOMPARE( c6.partCount(), 3 );
   14841                 :          1 :   QVERIFY( !c6.is3D() );
   14842                 :          1 :   QVERIFY( !c6.isMeasure() );
   14843                 :          1 :   ls = static_cast< const QgsPolygon * >( c6.geometryN( 2 ) );
   14844                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( 21, 30 ) );
   14845                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( 32, 41 ) );
   14846                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( 42, 61 ) );
   14847                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 3 ), QgsPoint( 21, 30 ) );
   14848                 :            : 
   14849                 :          1 :   c6.clear();
   14850                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( 1, 10, 2 ) << QgsPoint( 2, 11, 3 ) << QgsPoint( 9, 15, 3 ) << QgsPoint( 1, 10, 2 ) ) ;
   14851                 :          1 :   part.clear();
   14852                 :          1 :   part.setExteriorRing( ring.clone() );
   14853                 :          1 :   c6.addGeometry( part.clone() );
   14854                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPolygonZ );
   14855                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( 2, 20 ) << QgsPoint( 3, 31 )  << QgsPoint( 7, 34 ) << QgsPoint( 2, 20 ) ) ;
   14856                 :          1 :   part.clear();
   14857                 :          1 :   part.setExteriorRing( ring.clone() );
   14858                 :          1 :   c6.addGeometry( part.clone() );
   14859                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPolygonZ );
   14860                 :          1 :   QVERIFY( c6.is3D() );
   14861                 :          1 :   ls = static_cast< const QgsPolygon * >( c6.geometryN( 0 ) );
   14862                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( 1, 10, 2 ) );
   14863                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( 2, 11, 3 ) );
   14864                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( 9, 15, 3 ) );
   14865                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 3 ), QgsPoint( 1, 10, 2 ) );
   14866                 :          1 :   ls = static_cast< const QgsPolygon * >( c6.geometryN( 1 ) );
   14867                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( 2, 20, 0 ) );
   14868                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( 3, 31, 0 ) );
   14869                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( 7, 34, 0 ) );
   14870                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 3 ), QgsPoint( 2, 20, 0 ) );
   14871                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 5, 50, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 6, 61, 0, 5 )
   14872                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 9, 65, 0, 7 ) << QgsPoint( QgsWkbTypes::PointM, 5, 50, 0, 4 ) ) ;
   14873                 :          1 :   part.clear();
   14874                 :          1 :   part.setExteriorRing( ring.clone() );
   14875                 :          1 :   c6.addGeometry( part.clone() );
   14876                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPolygonZ );
   14877                 :          1 :   QVERIFY( c6.is3D() );
   14878                 :          1 :   QVERIFY( !c6.isMeasure() );
   14879                 :          1 :   ls = static_cast< const QgsPolygon * >( c6.geometryN( 2 ) );
   14880                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( 5, 50, 0 ) );
   14881                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( 6, 61, 0 ) );
   14882                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( 9, 65, 0 ) );
   14883                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 3 ), QgsPoint( 5, 50, 0 ) );
   14884                 :            : 
   14885                 :          1 :   c6.clear();
   14886                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPolygon );
   14887                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 5, 50, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 6, 61, 0, 5 )
   14888                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 9, 76, 0, 8 ) << QgsPoint( QgsWkbTypes::PointM, 5, 50, 0, 4 ) ) ;
   14889                 :          1 :   part.clear();
   14890                 :          1 :   part.setExteriorRing( ring.clone() );
   14891                 :          1 :   c6.addGeometry( part.clone() );
   14892                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPolygonM );
   14893                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( 2, 20 ) << QgsPoint( 3, 31 ) << QgsPoint( 7, 39 ) << QgsPoint( 2, 20 ) ) ;
   14894                 :          1 :   part.clear();
   14895                 :          1 :   part.setExteriorRing( ring.clone() );
   14896                 :          1 :   c6.addGeometry( part.clone() );
   14897                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPolygonM );
   14898                 :          1 :   QVERIFY( c6.isMeasure() );
   14899                 :          1 :   ls = static_cast< const QgsPolygon * >( c6.geometryN( 0 ) );
   14900                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 5, 50, 0, 4 ) );
   14901                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( QgsWkbTypes::PointM, 6, 61, 0, 5 ) );
   14902                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( QgsWkbTypes::PointM, 9, 76, 0, 8 ) );
   14903                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 3 ), QgsPoint( QgsWkbTypes::PointM, 5, 50, 0, 4 ) );
   14904                 :          1 :   ls = static_cast< const QgsPolygon * >( c6.geometryN( 1 ) );
   14905                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 2, 20, 0, 0 ) );
   14906                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( QgsWkbTypes::PointM, 3, 31, 0, 0 ) );
   14907                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( QgsWkbTypes::PointM, 7, 39, 0, 0 ) );
   14908                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 3 ), QgsPoint( QgsWkbTypes::PointM, 2, 20, 0, 0 ) );
   14909                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( 11, 12, 13 ) << QgsPoint( 14, 15, 16 ) << QgsPoint( 24, 21, 5 ) << QgsPoint( 11, 12, 13 ) ) ;
   14910                 :          1 :   part.clear();
   14911                 :          1 :   part.setExteriorRing( ring.clone() );
   14912                 :          1 :   c6.addGeometry( part.clone() );
   14913                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPolygonM );
   14914                 :          1 :   QVERIFY( !c6.is3D() );
   14915                 :          1 :   QVERIFY( c6.isMeasure() );
   14916                 :          1 :   ls = static_cast< const QgsPolygon * >( c6.geometryN( 2 ) );
   14917                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 0 ) );
   14918                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( QgsWkbTypes::PointM, 14, 15, 0, 0 ) );
   14919                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( QgsWkbTypes::PointM, 24, 21, 0, 0 ) );
   14920                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 3 ), QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 0 ) );
   14921                 :            : 
   14922                 :          1 :   c6.clear();
   14923                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 5, 50, 1, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 6, 61, 3, 5 )
   14924                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 9, 71, 4, 9 ) << QgsPoint( QgsWkbTypes::PointZM, 5, 50, 1, 4 ) ) ;
   14925                 :          1 :   part.clear();
   14926                 :          1 :   part.setExteriorRing( ring.clone() );
   14927                 :          1 :   c6.addGeometry( part.clone() );
   14928                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPolygonZM );
   14929                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 7, 17 ) << QgsPoint( QgsWkbTypes::Point, 3, 13 )
   14930                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 13, 27 ) << QgsPoint( QgsWkbTypes::Point, 7, 17 ) ) ;
   14931                 :          1 :   part.clear();
   14932                 :          1 :   part.setExteriorRing( ring.clone() );
   14933                 :          1 :   c6.addGeometry( part.clone() );
   14934                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPolygonZM );
   14935                 :          1 :   QVERIFY( c6.isMeasure() );
   14936                 :          1 :   QVERIFY( c6.is3D() );
   14937                 :          1 :   ls = static_cast< const QgsPolygon * >( c6.geometryN( 0 ) );
   14938                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 5, 50, 1, 4 ) );
   14939                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 6, 61, 3, 5 ) );
   14940                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( QgsWkbTypes::PointZM, 9, 71, 4, 9 ) );
   14941                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 3 ), QgsPoint( QgsWkbTypes::PointZM, 5, 50, 1, 4 ) );
   14942                 :          1 :   ls = static_cast< const QgsPolygon * >( c6.geometryN( 1 ) );
   14943                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 7, 17, 0, 0 ) );
   14944                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 3, 13, 0, 0 ) );
   14945                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( QgsWkbTypes::PointZM, 13, 27, 0, 0 ) );
   14946                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 3 ), QgsPoint( QgsWkbTypes::PointZM, 7, 17, 0, 0 ) );
   14947                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 77, 87, 7 ) << QgsPoint( QgsWkbTypes::PointZ, 83, 83, 8 )
   14948                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 93, 85, 10 ) << QgsPoint( QgsWkbTypes::PointZ, 77, 87, 7 ) ) ;
   14949                 :          1 :   part.clear();
   14950                 :          1 :   part.setExteriorRing( ring.clone() );
   14951                 :          1 :   c6.addGeometry( part.clone() );
   14952                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPolygonZM );
   14953                 :          1 :   QVERIFY( c6.is3D() );
   14954                 :          1 :   QVERIFY( c6.isMeasure() );
   14955                 :          1 :   ls = static_cast< const QgsPolygon * >( c6.geometryN( 2 ) );
   14956                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 77, 87, 7, 0 ) );
   14957                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 83, 83, 8, 0 ) );
   14958                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( QgsWkbTypes::PointZM, 93, 85, 10, 0 ) );
   14959                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 3 ), QgsPoint( QgsWkbTypes::PointZM, 77, 87, 7, 0 ) );
   14960                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 177, 187, 0, 9 ) << QgsPoint( QgsWkbTypes::PointM, 183, 183, 0, 11 )
   14961                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 185, 193, 0, 13 ) << QgsPoint( QgsWkbTypes::PointM, 177, 187, 0, 9 ) ) ;
   14962                 :          1 :   part.clear();
   14963                 :          1 :   part.setExteriorRing( ring.clone() );
   14964                 :          1 :   c6.addGeometry( part.clone() );
   14965                 :          1 :   QCOMPARE( c6.wkbType(), QgsWkbTypes::MultiPolygonZM );
   14966                 :          1 :   QVERIFY( c6.is3D() );
   14967                 :          1 :   QVERIFY( c6.isMeasure() );
   14968                 :          1 :   ls = static_cast< const QgsPolygon * >( c6.geometryN( 3 ) );
   14969                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZM, 177, 187, 0, 9 ) );
   14970                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 1 ), QgsPoint( QgsWkbTypes::PointZM, 183, 183, 0, 11 ) );
   14971                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 2 ), QgsPoint( QgsWkbTypes::PointZM, 185, 193, 0, 13 ) );
   14972                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( ls->exteriorRing() )->pointN( 3 ), QgsPoint( QgsWkbTypes::PointZM, 177, 187, 0, 9 ) );
   14973                 :            : 
   14974                 :            :   //clear
   14975                 :          1 :   QgsMultiPolygon c7;
   14976                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 5, 50, 1, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 6, 61, 3, 5 )
   14977                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 9, 71, 4, 15 ) << QgsPoint( QgsWkbTypes::PointZM, 5, 71, 4, 6 ) ) ;
   14978                 :          1 :   part.clear();
   14979                 :          1 :   part.setExteriorRing( ring.clone() );
   14980                 :          1 :   c7.addGeometry( part.clone() );
   14981                 :          1 :   c7.addGeometry( part.clone() );
   14982                 :          1 :   QCOMPARE( c7.numGeometries(), 2 );
   14983                 :          1 :   c7.clear();
   14984                 :          1 :   QVERIFY( c7.isEmpty() );
   14985                 :          1 :   QCOMPARE( c7.numGeometries(), 0 );
   14986                 :          1 :   QCOMPARE( c7.nCoordinates(), 0 );
   14987                 :          1 :   QCOMPARE( c7.ringCount(), 0 );
   14988                 :          1 :   QCOMPARE( c7.partCount(), 0 );
   14989                 :          1 :   QVERIFY( !c7.is3D() );
   14990                 :          1 :   QVERIFY( !c7.isMeasure() );
   14991                 :          1 :   QCOMPARE( c7.wkbType(), QgsWkbTypes::MultiPolygon );
   14992                 :            : 
   14993                 :            :   //clone
   14994                 :          1 :   QgsMultiPolygon c11;
   14995                 :          1 :   std::unique_ptr< QgsMultiPolygon >cloned( c11.clone() );
   14996                 :          1 :   QVERIFY( cloned->isEmpty() );
   14997                 :          1 :   c11.addGeometry( part.clone() );
   14998                 :          1 :   c11.addGeometry( part.clone() );
   14999                 :          1 :   cloned.reset( c11.clone() );
   15000                 :          1 :   QCOMPARE( cloned->numGeometries(), 2 );
   15001                 :          1 :   ls = static_cast< const QgsPolygon * >( cloned->geometryN( 0 ) );
   15002                 :          1 :   QCOMPARE( *ls, part );
   15003                 :          1 :   ls = static_cast< const QgsPolygon * >( cloned->geometryN( 1 ) );
   15004                 :          1 :   QCOMPARE( *ls, part );
   15005                 :            : 
   15006                 :            :   //copy constructor
   15007                 :          1 :   QgsMultiPolygon c12;
   15008                 :          1 :   QgsMultiPolygon c13( c12 );
   15009                 :          1 :   QVERIFY( c13.isEmpty() );
   15010                 :          1 :   c12.addGeometry( part.clone() );
   15011                 :          1 :   c12.addGeometry( part.clone() );
   15012                 :          1 :   QgsMultiPolygon c14( c12 );
   15013                 :          1 :   QCOMPARE( c14.numGeometries(), 2 );
   15014                 :          1 :   QCOMPARE( c14.wkbType(), QgsWkbTypes::MultiPolygonZM );
   15015                 :          1 :   ls = static_cast< const QgsPolygon * >( c14.geometryN( 0 ) );
   15016                 :          1 :   QCOMPARE( *ls, part );
   15017                 :          1 :   ls = static_cast< const QgsPolygon * >( c14.geometryN( 1 ) );
   15018                 :          1 :   QCOMPARE( *ls, part );
   15019                 :            : 
   15020                 :            :   //assignment operator
   15021                 :          1 :   QgsMultiPolygon c15;
   15022                 :          1 :   c15 = c13;
   15023                 :          1 :   QCOMPARE( c15.numGeometries(), 0 );
   15024                 :          1 :   c15 = c14;
   15025                 :          1 :   QCOMPARE( c15.numGeometries(), 2 );
   15026                 :          1 :   ls = static_cast< const QgsPolygon * >( c15.geometryN( 0 ) );
   15027                 :          1 :   QCOMPARE( *ls, part );
   15028                 :          1 :   ls = static_cast< const QgsPolygon * >( c15.geometryN( 1 ) );
   15029                 :          1 :   QCOMPARE( *ls, part );
   15030                 :            : 
   15031                 :            :   //toCurveType
   15032                 :          1 :   std::unique_ptr< QgsMultiSurface > curveType( c12.toCurveType() );
   15033                 :          1 :   QCOMPARE( curveType->wkbType(), QgsWkbTypes::MultiSurfaceZM );
   15034                 :          1 :   QCOMPARE( curveType->numGeometries(), 2 );
   15035                 :          1 :   const QgsPolygon *curve = static_cast< const QgsPolygon * >( curveType->geometryN( 0 ) );
   15036                 :          1 :   QCOMPARE( *curve, *static_cast< const QgsPolygon * >( c12.geometryN( 0 ) ) );
   15037                 :          1 :   curve = static_cast< const QgsPolygon * >( curveType->geometryN( 1 ) );
   15038                 :          1 :   QCOMPARE( *curve, *static_cast< const QgsPolygon * >( c12.geometryN( 1 ) ) );
   15039                 :            : 
   15040                 :            :   //to/fromWKB
   15041                 :          1 :   QgsMultiPolygon c16;
   15042                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 7, 17 ) << QgsPoint( QgsWkbTypes::Point, 3, 13 ) << QgsPoint( QgsWkbTypes::Point, 9, 27 ) << QgsPoint( QgsWkbTypes::Point, 7, 17 ) ) ;
   15043                 :          1 :   part.clear();
   15044                 :          1 :   part.setExteriorRing( ring.clone() );
   15045                 :          1 :   c16.addGeometry( part.clone() );
   15046                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 27, 37 ) << QgsPoint( QgsWkbTypes::Point, 43, 43 ) << QgsPoint( QgsWkbTypes::Point, 29, 39 ) << QgsPoint( QgsWkbTypes::Point, 27, 37 ) ) ;
   15047                 :          1 :   part.clear();
   15048                 :          1 :   part.setExteriorRing( ring.clone() );
   15049                 :          1 :   c16.addGeometry( part.clone() );
   15050                 :          1 :   QByteArray wkb16 = c16.asWkb();
   15051                 :          1 :   QCOMPARE( wkb16.size(), c16.wkbSize() );
   15052                 :          1 :   QgsMultiPolygon c17;
   15053                 :          1 :   QgsConstWkbPtr wkb16ptr( wkb16 );
   15054                 :          1 :   c17.fromWkb( wkb16ptr );
   15055                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   15056                 :          1 :   QCOMPARE( *static_cast< const QgsPolygon * >( c17.geometryN( 0 ) ), *static_cast< const QgsPolygon * >( c16.geometryN( 0 ) ) );
   15057                 :          1 :   QCOMPARE( *static_cast< const QgsPolygon * >( c17.geometryN( 1 ) ), *static_cast< const QgsPolygon * >( c16.geometryN( 1 ) ) );
   15058                 :            : 
   15059                 :            :   //parts with Z
   15060                 :          1 :   c16.clear();
   15061                 :          1 :   c17.clear();
   15062                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 7, 17, 1 ) << QgsPoint( QgsWkbTypes::PointZ, 3, 13, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 9, 27, 5 )  << QgsPoint( QgsWkbTypes::PointZ, 7, 17, 1 ) ) ;
   15063                 :          1 :   part.clear();
   15064                 :          1 :   part.setExteriorRing( ring.clone() );
   15065                 :          1 :   c16.addGeometry( part.clone() );
   15066                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 27, 37, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 43, 43, 5 ) << QgsPoint( QgsWkbTypes::PointZ, 87, 54, 7 ) << QgsPoint( QgsWkbTypes::PointZ, 27, 37, 2 ) ) ;
   15067                 :          1 :   part.clear();
   15068                 :          1 :   part.setExteriorRing( ring.clone() );
   15069                 :          1 :   c16.addGeometry( part.clone() );
   15070                 :          1 :   wkb16 = c16.asWkb();
   15071                 :          1 :   QgsConstWkbPtr wkb16ptr2( wkb16 );
   15072                 :          1 :   c17.fromWkb( wkb16ptr2 );
   15073                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   15074                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiPolygonZ );
   15075                 :          1 :   QCOMPARE( *static_cast< const QgsPolygon * >( c17.geometryN( 0 ) ), *static_cast< const QgsPolygon * >( c16.geometryN( 0 ) ) );
   15076                 :          1 :   QCOMPARE( *static_cast< const QgsPolygon * >( c17.geometryN( 1 ) ), *static_cast< const QgsPolygon * >( c16.geometryN( 1 ) ) );
   15077                 :            : 
   15078                 :            :   //parts with m
   15079                 :          1 :   c16.clear();
   15080                 :          1 :   c17.clear();
   15081                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 7, 17, 0, 1 ) << QgsPoint( QgsWkbTypes::PointM, 3, 13, 0, 4 )
   15082                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 9, 21, 0, 3 ) << QgsPoint( QgsWkbTypes::PointM, 7, 17, 0, 1 ) ) ;
   15083                 :          1 :   part.clear();
   15084                 :          1 :   part.setExteriorRing( ring.clone() );
   15085                 :          1 :   c16.addGeometry( part.clone() );
   15086                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 27, 37, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 43, 43, 0, 5 )
   15087                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 37, 31, 0, 3 ) << QgsPoint( QgsWkbTypes::PointM, 27, 37, 0, 2 ) ) ;
   15088                 :          1 :   part.clear();
   15089                 :          1 :   part.setExteriorRing( ring.clone() );
   15090                 :          1 :   c16.addGeometry( part.clone() );
   15091                 :          1 :   wkb16 = c16.asWkb();
   15092                 :          1 :   QgsConstWkbPtr wkb16ptr3( wkb16 );
   15093                 :          1 :   c17.fromWkb( wkb16ptr3 );
   15094                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   15095                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiPolygonM );
   15096                 :          1 :   QCOMPARE( *static_cast< const QgsPolygon * >( c17.geometryN( 0 ) ), *static_cast< const QgsPolygon * >( c16.geometryN( 0 ) ) );
   15097                 :          1 :   QCOMPARE( *static_cast< const QgsPolygon * >( c17.geometryN( 1 ) ), *static_cast< const QgsPolygon * >( c16.geometryN( 1 ) ) );
   15098                 :            : 
   15099                 :            :   // parts with ZM
   15100                 :          1 :   c16.clear();
   15101                 :          1 :   c17.clear();
   15102                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 7, 17, 4, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 3, 13, 1, 4 )
   15103                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 19, 13, 5, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 7, 17, 4, 1 ) ) ;
   15104                 :          1 :   part.clear();
   15105                 :          1 :   part.setExteriorRing( ring.clone() );
   15106                 :          1 :   c16.addGeometry( part.clone() );
   15107                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 27, 37, 6, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 43, 43, 11, 5 )
   15108                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 7, 17, 4, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 27, 37, 6, 2 ) ) ;
   15109                 :          1 :   part.clear();
   15110                 :          1 :   part.setExteriorRing( ring.clone() );
   15111                 :          1 :   c16.addGeometry( part.clone() );
   15112                 :          1 :   wkb16 = c16.asWkb();
   15113                 :          1 :   QgsConstWkbPtr wkb16ptr4( wkb16 );
   15114                 :          1 :   c17.fromWkb( wkb16ptr4 );
   15115                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   15116                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiPolygonZM );
   15117                 :          1 :   QCOMPARE( *static_cast< const QgsPolygon * >( c17.geometryN( 0 ) ), *static_cast< const QgsPolygon * >( c16.geometryN( 0 ) ) );
   15118                 :          1 :   QCOMPARE( *static_cast< const QgsPolygon * >( c17.geometryN( 1 ) ), *static_cast< const QgsPolygon * >( c16.geometryN( 1 ) ) );
   15119                 :            : 
   15120                 :            :   //bad WKB - check for no crash
   15121                 :          1 :   c17.clear();
   15122                 :          1 :   QgsConstWkbPtr nullPtr( nullptr, 0 );
   15123                 :          1 :   QVERIFY( !c17.fromWkb( nullPtr ) );
   15124                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiPolygon );
   15125                 :          1 :   QgsPoint point( 1, 2 );
   15126                 :          1 :   QByteArray wkbPoint = point.asWkb();
   15127                 :          1 :   QgsConstWkbPtr wkbPointPtr( wkbPoint );
   15128                 :          1 :   QVERIFY( !c17.fromWkb( wkbPointPtr ) );
   15129                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::MultiPolygon );
   15130                 :            : 
   15131                 :            :   //to/from WKT
   15132                 :          1 :   QgsMultiPolygon c18;
   15133                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 7, 17, 4, 1 ) << QgsPoint( QgsWkbTypes::PointZM, 3, 13, 1, 4 )
   15134                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 13, 19, 3, 10 ) << QgsPoint( QgsWkbTypes::PointZM, 7, 11, 2, 8 ) ) ;
   15135                 :          1 :   part.clear();
   15136                 :          1 :   part.setExteriorRing( ring.clone() );
   15137                 :          1 :   c18.addGeometry( part.clone() );
   15138                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 27, 37, 6, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 43, 43, 11, 5 )
   15139                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 17, 49, 31, 53 ) << QgsPoint( QgsWkbTypes::PointZM, 27, 53, 21, 52 ) ) ;
   15140                 :          1 :   part.clear();
   15141                 :          1 :   part.setExteriorRing( ring.clone() );
   15142                 :          1 :   c18.addGeometry( part.clone() );
   15143                 :            : 
   15144                 :          1 :   QString wkt = c18.asWkt();
   15145                 :          1 :   QVERIFY( !wkt.isEmpty() );
   15146                 :          1 :   QgsMultiPolygon c19;
   15147                 :          1 :   QVERIFY( c19.fromWkt( wkt ) );
   15148                 :          1 :   QCOMPARE( c19.numGeometries(), 2 );
   15149                 :          1 :   QCOMPARE( *static_cast< const QgsPolygon * >( c19.geometryN( 0 ) ), *static_cast< const QgsPolygon * >( c18.geometryN( 0 ) ) );
   15150                 :          1 :   QCOMPARE( *static_cast< const QgsPolygon * >( c19.geometryN( 1 ) ), *static_cast< const QgsPolygon * >( c18.geometryN( 1 ) ) );
   15151                 :            : 
   15152                 :            :   //bad WKT
   15153                 :          1 :   QgsMultiPolygon c20;
   15154                 :          1 :   QVERIFY( !c20.fromWkt( "Point()" ) );
   15155                 :          1 :   QVERIFY( c20.isEmpty() );
   15156                 :          1 :   QCOMPARE( c20.numGeometries(), 0 );
   15157                 :          1 :   QCOMPARE( c20.wkbType(), QgsWkbTypes::MultiPolygon );
   15158                 :            : 
   15159                 :            :   //as JSON
   15160                 :          1 :   QgsMultiPolygon exportC;
   15161                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 7, 17 ) << QgsPoint( QgsWkbTypes::Point, 3, 13 )
   15162                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 7, 21 ) << QgsPoint( QgsWkbTypes::Point, 7, 17 ) ) ;
   15163                 :          1 :   part.clear();
   15164                 :          1 :   part.setExteriorRing( ring.clone() );
   15165                 :          1 :   exportC.addGeometry( part.clone() );
   15166                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 27, 37 ) << QgsPoint( QgsWkbTypes::Point, 43, 43 )
   15167                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 41, 39 ) << QgsPoint( QgsWkbTypes::Point, 27, 37 ) ) ;
   15168                 :          1 :   part.clear();
   15169                 :          1 :   part.setExteriorRing( ring.clone() );
   15170                 :          1 :   exportC.addGeometry( part.clone() );
   15171                 :            : 
   15172                 :            :   // GML document for compare
   15173                 :          1 :   QDomDocument doc( "gml" );
   15174                 :            : 
   15175                 :            :   // as GML2
   15176                 :          2 :   QString expectedSimpleGML2( QStringLiteral( "<MultiPolygon xmlns=\"gml\"><polygonMember xmlns=\"gml\"><Polygon xmlns=\"gml\"><outerBoundaryIs xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">7,17 3,13 7,21 7,17</coordinates></LinearRing></outerBoundaryIs></Polygon></polygonMember><polygonMember xmlns=\"gml\"><Polygon xmlns=\"gml\"><outerBoundaryIs xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">27,37 43,43 41,39 27,37</coordinates></LinearRing></outerBoundaryIs></Polygon></polygonMember></MultiPolygon>" ) );
   15177                 :          1 :   QString res = elemToString( exportC.asGml2( doc, 1 ) );
   15178                 :          3 :   QGSCOMPAREGML( res, expectedSimpleGML2 );
   15179                 :          2 :   QString expectedGML2empty( QStringLiteral( "<MultiPolygon xmlns=\"gml\"/>" ) );
   15180                 :          3 :   QGSCOMPAREGML( elemToString( QgsMultiPolygon().asGml2( doc ) ), expectedGML2empty );
   15181                 :            : 
   15182                 :            :   //as GML3
   15183                 :          2 :   QString expectedSimpleGML3( QStringLiteral( "<MultiPolygon xmlns=\"gml\"><polygonMember xmlns=\"gml\"><Polygon xmlns=\"gml\"><exterior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">7 17 3 13 7 21 7 17</posList></LinearRing></exterior></Polygon></polygonMember><polygonMember xmlns=\"gml\"><Polygon xmlns=\"gml\"><exterior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">27 37 43 43 41 39 27 37</posList></LinearRing></exterior></Polygon></polygonMember></MultiPolygon>" ) );
   15184                 :          1 :   res = elemToString( exportC.asGml3( doc ) );
   15185                 :          1 :   QCOMPARE( res, expectedSimpleGML3 );
   15186                 :          2 :   QString expectedGML3empty( QStringLiteral( "<MultiPolygon xmlns=\"gml\"/>" ) );
   15187                 :          3 :   QGSCOMPAREGML( elemToString( QgsMultiPolygon().asGml3( doc ) ), expectedGML3empty );
   15188                 :            : 
   15189                 :            :   // as JSON
   15190                 :          1 :   QString expectedSimpleJson( "{\"coordinates\":[[[[7.0,17.0],[3.0,13.0],[7.0,21.0],[7.0,17.0]]],[[[27.0,37.0],[43.0,43.0],[41.0,39.0],[27.0,37.0]]]],\"type\":\"MultiPolygon\"}" );
   15191                 :          1 :   res = exportC.asJson( 1 );
   15192                 :          1 :   QCOMPARE( res, expectedSimpleJson );
   15193                 :            : 
   15194                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 17, 27 ) << QgsPoint( QgsWkbTypes::Point, 18, 28 ) << QgsPoint( QgsWkbTypes::Point, 19, 37 ) << QgsPoint( QgsWkbTypes::Point, 17, 27 ) ) ;
   15195                 :          1 :   part.addInteriorRing( ring.clone() );
   15196                 :          1 :   exportC.addGeometry( part.clone() );
   15197                 :            : 
   15198                 :          1 :   QString expectedJsonWithRings( "{\"coordinates\":[[[[7.0,17.0],[3.0,13.0],[7.0,21.0],[7.0,17.0]]],[[[27.0,37.0],[43.0,43.0],[41.0,39.0],[27.0,37.0]]],[[[27.0,37.0],[43.0,43.0],[41.0,39.0],[27.0,37.0]],[[17.0,27.0],[18.0,28.0],[19.0,37.0],[17.0,27.0]]]],\"type\":\"MultiPolygon\"}" );
   15199                 :          1 :   res = exportC.asJson( 1 );
   15200                 :          1 :   QCOMPARE( res, expectedJsonWithRings );
   15201                 :            : 
   15202                 :          1 :   QgsMultiPolygon exportFloat;
   15203                 :          2 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 7 / 3.0, 17 / 3.0 ) << QgsPoint( QgsWkbTypes::Point, 3 / 5.0, 13 / 3.0 )
   15204                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 8 / 3.0, 27 / 3.0 ) << QgsPoint( QgsWkbTypes::Point, 7 / 3.0, 17 / 3.0 ) ) ;
   15205                 :          1 :   part.clear();
   15206                 :          1 :   part.setExteriorRing( ring.clone() );
   15207                 :          1 :   exportFloat.addGeometry( part.clone() );
   15208                 :          1 :   ring.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 27 / 3.0, 37 / 9.0 ) << QgsPoint( QgsWkbTypes::Point, 43 / 41.0, 43 / 42.0 ) << QgsPoint( QgsWkbTypes::Point, 27 / 3.0, 37 / 9.0 ) ) ;
   15209                 :          1 :   part.clear();
   15210                 :          1 :   part.setExteriorRing( ring.clone() );
   15211                 :          1 :   exportFloat.addGeometry( part.clone() );
   15212                 :            : 
   15213                 :          1 :   QString expectedJsonPrec3( "{\"coordinates\":[[[[2.333,5.667],[0.6,4.333],[2.667,9.0],[2.333,5.667]]],[[[9.0,4.111],[1.049,1.024],[9.0,4.111]]]],\"type\":\"MultiPolygon\"}" );
   15214                 :          1 :   res = exportFloat.asJson( 3 );
   15215                 :          1 :   QCOMPARE( res, expectedJsonPrec3 );
   15216                 :            : 
   15217                 :            :   // as GML2
   15218                 :          1 :   QString expectedGML2prec3( "<MultiPolygon xmlns=\"gml\"><polygonMember xmlns=\"gml\"><Polygon xmlns=\"gml\"><outerBoundaryIs xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">2.333,5.667 0.6,4.333 2.667,9 2.333,5.667</coordinates></LinearRing></outerBoundaryIs></Polygon></polygonMember><polygonMember xmlns=\"gml\"><Polygon xmlns=\"gml\"><outerBoundaryIs xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">9,4.111 1.049,1.024 9,4.111</coordinates></LinearRing></outerBoundaryIs></Polygon></polygonMember></MultiPolygon>" );
   15219                 :          1 :   res = elemToString( exportFloat.asGml2( doc, 3 ) );
   15220                 :          3 :   QGSCOMPAREGML( res, expectedGML2prec3 );
   15221                 :            : 
   15222                 :            :   //as GML3
   15223                 :          1 :   QString expectedGML3prec3( "<MultiPolygon xmlns=\"gml\"><polygonMember xmlns=\"gml\"><Polygon xmlns=\"gml\"><exterior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">2.333 5.667 0.6 4.333 2.667 9 2.333 5.667</posList></LinearRing></exterior></Polygon></polygonMember><polygonMember xmlns=\"gml\"><Polygon xmlns=\"gml\"><exterior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">9 4.111 1.049 1.024 9 4.111</posList></LinearRing></exterior></Polygon></polygonMember></MultiPolygon>" );
   15224                 :          1 :   res = elemToString( exportFloat.asGml3( doc, 3 ) );
   15225                 :          1 :   QCOMPARE( res, expectedGML3prec3 );
   15226                 :            : 
   15227                 :            :   //asKML
   15228                 :          1 :   QString expectedKmlPrec3( "<MultiGeometry><Polygon><outerBoundaryIs><LinearRing><altitudeMode>clampToGround</altitudeMode><coordinates>2.333,5.667,0 0.6,4.333,0 2.667,9,0 2.333,5.667,0</coordinates></LinearRing></outerBoundaryIs></Polygon><Polygon><outerBoundaryIs><LineString><altitudeMode>clampToGround</altitudeMode><coordinates>9,4.111,0 1.049,1.024,0 9,4.111,0</coordinates></LineString></outerBoundaryIs></Polygon></MultiGeometry>" );
   15229                 :          1 :   QCOMPARE( exportFloat.asKml( 3 ), expectedKmlPrec3 );
   15230                 :            : 
   15231                 :            : 
   15232                 :            :   // insert geometry
   15233                 :          1 :   QgsMultiPolygon rc;
   15234                 :          1 :   rc.clear();
   15235                 :          1 :   rc.insertGeometry( nullptr, 0 );
   15236                 :          1 :   QVERIFY( rc.isEmpty() );
   15237                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   15238                 :          1 :   rc.insertGeometry( nullptr, -1 );
   15239                 :          1 :   QVERIFY( rc.isEmpty() );
   15240                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   15241                 :          1 :   rc.insertGeometry( nullptr, 100 );
   15242                 :          1 :   QVERIFY( rc.isEmpty() );
   15243                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   15244                 :            : 
   15245                 :          1 :   rc.insertGeometry( new QgsPoint(), 0 );
   15246                 :          1 :   QVERIFY( rc.isEmpty() );
   15247                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   15248                 :            : 
   15249                 :          1 :   rc.insertGeometry( part.clone(), 0 );
   15250                 :          1 :   QVERIFY( !rc.isEmpty() );
   15251                 :          1 :   QCOMPARE( rc.numGeometries(), 1 );
   15252                 :            : 
   15253                 :            :   // cast
   15254                 :          1 :   QVERIFY( !QgsMultiPolygon().cast( nullptr ) );
   15255                 :          1 :   QgsMultiPolygon pCast;
   15256                 :          1 :   QVERIFY( QgsMultiPolygon().cast( &pCast ) );
   15257                 :          1 :   QgsMultiPolygon pCast2;
   15258                 :          2 :   pCast2.fromWkt( QStringLiteral( "MultiPolygonZ()" ) );
   15259                 :          1 :   QVERIFY( QgsMultiPolygon().cast( &pCast2 ) );
   15260                 :          2 :   pCast2.fromWkt( QStringLiteral( "MultiPolygonM()" ) );
   15261                 :          1 :   QVERIFY( QgsMultiPolygon().cast( &pCast2 ) );
   15262                 :          2 :   pCast2.fromWkt( QStringLiteral( "MultiPolygonZM()" ) );
   15263                 :          1 :   QVERIFY( QgsMultiPolygon().cast( &pCast2 ) );
   15264                 :            : 
   15265                 :            : 
   15266                 :            :   //boundary
   15267                 :          1 :   QgsMultiPolygon multiPolygon1;
   15268                 :          1 :   QVERIFY( !multiPolygon1.boundary() );
   15269                 :            : 
   15270                 :          1 :   QgsLineString ring1;
   15271                 :          1 :   ring1.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 )  << QgsPoint( 0, 0 ) );
   15272                 :          1 :   QgsPolygon polygon1;
   15273                 :          1 :   polygon1.setExteriorRing( ring1.clone() );
   15274                 :          1 :   multiPolygon1.addGeometry( polygon1.clone() );
   15275                 :            : 
   15276                 :          1 :   std::unique_ptr< QgsAbstractGeometry > boundary( multiPolygon1.boundary() );
   15277                 :          1 :   QgsMultiLineString *lineBoundary = dynamic_cast< QgsMultiLineString * >( boundary.get() );
   15278                 :          1 :   QVERIFY( lineBoundary );
   15279                 :          1 :   QCOMPARE( lineBoundary->numGeometries(), 1 );
   15280                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( lineBoundary->geometryN( 0 ) )->numPoints(), 4 );
   15281                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( lineBoundary->geometryN( 0 ) )->xAt( 0 ), 0.0 );
   15282                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( lineBoundary->geometryN( 0 ) )->xAt( 1 ), 1.0 );
   15283                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( lineBoundary->geometryN( 0 ) )->xAt( 2 ), 1.0 );
   15284                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( lineBoundary->geometryN( 0 ) )->xAt( 3 ), 0.0 );
   15285                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( lineBoundary->geometryN( 0 ) )->yAt( 0 ), 0.0 );
   15286                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( lineBoundary->geometryN( 0 ) )->yAt( 1 ), 0.0 );
   15287                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( lineBoundary->geometryN( 0 ) )->yAt( 2 ), 1.0 );
   15288                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( lineBoundary->geometryN( 0 ) )->yAt( 3 ), 0.0 );
   15289                 :            : 
   15290                 :            :   // add polygon with interior rings
   15291                 :          1 :   QgsLineString ring2;
   15292                 :          1 :   ring2.setPoints( QgsPointSequence() << QgsPoint( 10, 10 ) << QgsPoint( 11, 10 ) << QgsPoint( 11, 11 )  << QgsPoint( 10, 10 ) );
   15293                 :          1 :   QgsPolygon polygon2;
   15294                 :          1 :   polygon2.setExteriorRing( ring2.clone() );
   15295                 :          1 :   QgsLineString boundaryRing1;
   15296                 :          1 :   boundaryRing1.setPoints( QgsPointSequence() << QgsPoint( 10.1, 10.1 ) << QgsPoint( 10.2, 10.1 ) << QgsPoint( 10.2, 10.2 )  << QgsPoint( 10.1, 10.1 ) );
   15297                 :          1 :   QgsLineString boundaryRing2;
   15298                 :          1 :   boundaryRing2.setPoints( QgsPointSequence() << QgsPoint( 10.8, 10.8 ) << QgsPoint( 10.9, 10.8 ) << QgsPoint( 10.9, 10.9 )  << QgsPoint( 10.8, 10.8 ) );
   15299                 :          1 :   polygon2.setInteriorRings( QVector< QgsCurve * >() << boundaryRing1.clone() << boundaryRing2.clone() );
   15300                 :          1 :   multiPolygon1.addGeometry( polygon2.clone() );
   15301                 :            : 
   15302                 :          1 :   boundary.reset( multiPolygon1.boundary() );
   15303                 :          1 :   QgsMultiLineString *multiLineBoundary( static_cast< QgsMultiLineString * >( boundary.get() ) );
   15304                 :          1 :   QVERIFY( multiLineBoundary );
   15305                 :          1 :   QCOMPARE( multiLineBoundary->numGeometries(), 4 );
   15306                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 0 ) )->numPoints(), 4 );
   15307                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 0 ) )->xAt( 0 ), 0.0 );
   15308                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 0 ) )->xAt( 1 ), 1.0 );
   15309                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 0 ) )->xAt( 2 ), 1.0 );
   15310                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 0 ) )->xAt( 3 ), 0.0 );
   15311                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 0 ) )->yAt( 0 ), 0.0 );
   15312                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 0 ) )->yAt( 1 ), 0.0 );
   15313                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 0 ) )->yAt( 2 ), 1.0 );
   15314                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 0 ) )->yAt( 3 ), 0.0 );
   15315                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 1 ) )->numPoints(), 4 );
   15316                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 1 ) )->xAt( 0 ), 10.0 );
   15317                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 1 ) )->xAt( 1 ), 11.0 );
   15318                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 1 ) )->xAt( 2 ), 11.0 );
   15319                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 1 ) )->xAt( 3 ), 10.0 );
   15320                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 1 ) )->yAt( 0 ), 10.0 );
   15321                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 1 ) )->yAt( 1 ), 10.0 );
   15322                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 1 ) )->yAt( 2 ), 11.0 );
   15323                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 1 ) )->yAt( 3 ), 10.0 );
   15324                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 2 ) )->numPoints(), 4 );
   15325                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 2 ) )->xAt( 0 ), 10.1 );
   15326                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 2 ) )->xAt( 1 ), 10.2 );
   15327                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 2 ) )->xAt( 2 ), 10.2 );
   15328                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 2 ) )->xAt( 3 ), 10.1 );
   15329                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 2 ) )->yAt( 0 ), 10.1 );
   15330                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 2 ) )->yAt( 1 ), 10.1 );
   15331                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 2 ) )->yAt( 2 ), 10.2 );
   15332                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 2 ) )->yAt( 3 ), 10.1 );
   15333                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 3 ) )->numPoints(), 4 );
   15334                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 3 ) )->xAt( 0 ), 10.8 );
   15335                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 3 ) )->xAt( 1 ), 10.9 );
   15336                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 3 ) )->xAt( 2 ), 10.9 );
   15337                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 3 ) )->xAt( 3 ), 10.8 );
   15338                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 3 ) )->yAt( 0 ), 10.8 );
   15339                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 3 ) )->yAt( 1 ), 10.8 );
   15340                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 3 ) )->yAt( 2 ), 10.9 );
   15341                 :          1 :   QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 3 ) )->yAt( 3 ), 10.8 );
   15342                 :            : 
   15343                 :            :   // vertex iterator: 2 polygons (one with just exterior ring, other with two interior rings)
   15344                 :          1 :   QgsAbstractGeometry::vertex_iterator it = multiPolygon1.vertices_begin();
   15345                 :          1 :   QgsAbstractGeometry::vertex_iterator itEnd = multiPolygon1.vertices_end();
   15346                 :          1 :   QCOMPARE( *it, QgsPoint( 0, 0 ) );
   15347                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 0, 0, 0 ) );
   15348                 :          1 :   ++it;
   15349                 :          1 :   QCOMPARE( *it, QgsPoint( 1, 0 ) );
   15350                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 0, 0, 1 ) );
   15351                 :          1 :   ++it;
   15352                 :          1 :   QCOMPARE( *it, QgsPoint( 1, 1 ) );
   15353                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 0, 0, 2 ) );
   15354                 :          1 :   ++it;
   15355                 :          1 :   QCOMPARE( *it, QgsPoint( 0, 0 ) );
   15356                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 0, 0, 3 ) );
   15357                 :          1 :   ++it;
   15358                 :            :   // 2nd polygon - exterior ring
   15359                 :          1 :   QCOMPARE( *it, QgsPoint( 10, 10 ) );
   15360                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 1, 0, 0 ) );
   15361                 :          1 :   ++it;
   15362                 :          1 :   QCOMPARE( *it, QgsPoint( 11, 10 ) );
   15363                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 1, 0, 1 ) );
   15364                 :          1 :   ++it;
   15365                 :          1 :   QCOMPARE( *it, QgsPoint( 11, 11 ) );
   15366                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 1, 0, 2 ) );
   15367                 :          1 :   ++it;
   15368                 :          1 :   QCOMPARE( *it, QgsPoint( 10, 10 ) );
   15369                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 1, 0, 3 ) );
   15370                 :          1 :   ++it;
   15371                 :            :   // 2nd polygon - 1st interior ring
   15372                 :          1 :   QCOMPARE( *it, QgsPoint( 10.1, 10.1 ) );
   15373                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 1, 1, 0 ) );
   15374                 :          1 :   ++it;
   15375                 :          1 :   QCOMPARE( *it, QgsPoint( 10.2, 10.1 ) );
   15376                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 1, 1, 1 ) );
   15377                 :          1 :   ++it;
   15378                 :          1 :   QCOMPARE( *it, QgsPoint( 10.2, 10.2 ) );
   15379                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 1, 1, 2 ) );
   15380                 :          1 :   ++it;
   15381                 :          1 :   QCOMPARE( *it, QgsPoint( 10.1, 10.1 ) );
   15382                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 1, 1, 3 ) );
   15383                 :          1 :   ++it;
   15384                 :            :   // 2nd polygon - 2nd interior ring
   15385                 :          1 :   QCOMPARE( *it, QgsPoint( 10.8, 10.8 ) );
   15386                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 1, 2, 0 ) );
   15387                 :          1 :   ++it;
   15388                 :          1 :   QCOMPARE( *it, QgsPoint( 10.9, 10.8 ) );
   15389                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 1, 2, 1 ) );
   15390                 :          1 :   ++it;
   15391                 :          1 :   QCOMPARE( *it, QgsPoint( 10.9, 10.9 ) );
   15392                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 1, 2, 2 ) );
   15393                 :          1 :   ++it;
   15394                 :          1 :   QCOMPARE( *it, QgsPoint( 10.8, 10.8 ) );
   15395                 :          1 :   QCOMPARE( it.vertexId(), QgsVertexId( 1, 2, 3 ) );
   15396                 :          1 :   ++it;
   15397                 :            :   // done!
   15398                 :          1 :   QCOMPARE( it, itEnd );
   15399                 :            : 
   15400                 :            :   // Java-style iterator
   15401                 :          1 :   QgsVertexIterator it2( &multiPolygon1 );
   15402                 :          1 :   QVERIFY( it2.hasNext() );
   15403                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 0, 0 ) );
   15404                 :          1 :   QVERIFY( it2.hasNext() );
   15405                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 1, 0 ) );
   15406                 :          1 :   QVERIFY( it2.hasNext() );
   15407                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 1, 1 ) );
   15408                 :          1 :   QVERIFY( it2.hasNext() );
   15409                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 0, 0 ) );
   15410                 :          1 :   QVERIFY( it2.hasNext() );
   15411                 :            :   // 2nd polygon - exterior ring
   15412                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 10, 10 ) );
   15413                 :          1 :   QVERIFY( it2.hasNext() );
   15414                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 11, 10 ) );
   15415                 :          1 :   QVERIFY( it2.hasNext() );
   15416                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 11, 11 ) );
   15417                 :          1 :   QVERIFY( it2.hasNext() );
   15418                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 10, 10 ) );
   15419                 :          1 :   QVERIFY( it2.hasNext() );
   15420                 :            :   // 2nd polygon - 1st interior ring
   15421                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 10.1, 10.1 ) );
   15422                 :          1 :   QVERIFY( it2.hasNext() );
   15423                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 10.2, 10.1 ) );
   15424                 :          1 :   QVERIFY( it2.hasNext() );
   15425                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 10.2, 10.2 ) );
   15426                 :          1 :   QVERIFY( it2.hasNext() );
   15427                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 10.1, 10.1 ) );
   15428                 :          1 :   QVERIFY( it2.hasNext() );
   15429                 :            :   // 2nd polygon - 2nd interior ring
   15430                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 10.8, 10.8 ) );
   15431                 :          1 :   QVERIFY( it2.hasNext() );
   15432                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 10.9, 10.8 ) );
   15433                 :          1 :   QVERIFY( it2.hasNext() );
   15434                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 10.9, 10.9 ) );
   15435                 :          1 :   QVERIFY( it2.hasNext() );
   15436                 :          1 :   QCOMPARE( it2.next(), QgsPoint( 10.8, 10.8 ) );
   15437                 :          1 :   QVERIFY( !it2.hasNext() );
   15438                 :            : 
   15439                 :            :   //removeDuplicateNodes
   15440                 :          1 :   QgsMultiPolygon dn1;
   15441                 :          2 :   QVERIFY( dn1.fromWkt( QStringLiteral( "MultiPolygonZ (((0 0 0, 10 10 0, 11 9 0, 9 8 0, 9 8 0, 1 -1 0, 0 0 0)),((7 -1 0, 12 7 0, 13 6 0, 13 6 0, 8 -3 0, 7 -1 0)))" ) ) );
   15442                 :          1 :   QCOMPARE( dn1.numGeometries(), 2 );
   15443                 :            :   // First call should remove all duplicate nodes (one per part)
   15444                 :          1 :   QVERIFY( dn1.removeDuplicateNodes( 0.001, false ) );
   15445                 :          1 :   QVERIFY( !dn1.removeDuplicateNodes( 0.001, false ) );
   15446                 :          2 :   QCOMPARE( dn1.asWkt(), QStringLiteral( "MultiPolygonZ (((0 0 0, 10 10 0, 11 9 0, 9 8 0, 1 -1 0, 0 0 0)),((7 -1 0, 12 7 0, 13 6 0, 8 -3 0, 7 -1 0)))" ) );
   15447                 :          1 : }
   15448                 :            : 
   15449                 :          1 : void TestQgsGeometry::geometryCollection()
   15450                 :            : {
   15451                 :            :   //test constructor
   15452                 :          1 :   QgsGeometryCollection c1;
   15453                 :          1 :   QVERIFY( c1.isEmpty() );
   15454                 :          1 :   QCOMPARE( c1.nCoordinates(), 0 );
   15455                 :          1 :   QCOMPARE( c1.ringCount(), 0 );
   15456                 :          1 :   QCOMPARE( c1.partCount(), 0 );
   15457                 :          1 :   QVERIFY( !c1.is3D() );
   15458                 :          1 :   QVERIFY( !c1.isMeasure() );
   15459                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::GeometryCollection );
   15460                 :          1 :   QCOMPARE( c1.wktTypeStr(), QString( "GeometryCollection" ) );
   15461                 :          1 :   QCOMPARE( c1.geometryType(), QString( "GeometryCollection" ) );
   15462                 :          1 :   QCOMPARE( c1.dimension(), 0 );
   15463                 :          1 :   QVERIFY( !c1.hasCurvedSegments() );
   15464                 :          1 :   QCOMPARE( c1.area(), 0.0 );
   15465                 :          1 :   QCOMPARE( c1.perimeter(), 0.0 );
   15466                 :          1 :   QCOMPARE( c1.numGeometries(), 0 );
   15467                 :          1 :   QVERIFY( !c1.geometryN( 0 ) );
   15468                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   15469                 :          1 :   QCOMPARE( c1.vertexCount( 0, 0 ), 0 );
   15470                 :          1 :   QCOMPARE( c1.vertexCount( 0, 1 ), 0 );
   15471                 :          1 :   QCOMPARE( c1.vertexCount( 1, 0 ), 0 );
   15472                 :            : 
   15473                 :            :   //addGeometry
   15474                 :            : 
   15475                 :            :   //try with nullptr
   15476                 :          1 :   c1.addGeometry( nullptr );
   15477                 :          1 :   QVERIFY( c1.isEmpty() );
   15478                 :          1 :   QCOMPARE( c1.nCoordinates(), 0 );
   15479                 :          1 :   QCOMPARE( c1.ringCount(), 0 );
   15480                 :          1 :   QCOMPARE( c1.partCount(), 0 );
   15481                 :          1 :   QCOMPARE( c1.numGeometries(), 0 );
   15482                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::GeometryCollection );
   15483                 :          1 :   QVERIFY( !c1.geometryN( 0 ) );
   15484                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   15485                 :            : 
   15486                 :            :   //valid geometry
   15487                 :          1 :   QgsLineString part;
   15488                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
   15489                 :          1 :                   << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) );
   15490                 :          1 :   c1.addGeometry( part.clone() );
   15491                 :          1 :   QVERIFY( !c1.isEmpty() );
   15492                 :          1 :   QCOMPARE( c1.numGeometries(), 1 );
   15493                 :          1 :   QCOMPARE( c1.nCoordinates(), 5 );
   15494                 :          1 :   QCOMPARE( c1.ringCount(), 1 );
   15495                 :          1 :   QCOMPARE( c1.partCount(), 1 );
   15496                 :          1 :   QVERIFY( !c1.is3D() );
   15497                 :          1 :   QVERIFY( !c1.isMeasure() );
   15498                 :          1 :   QCOMPARE( c1.wkbType(), QgsWkbTypes::GeometryCollection );
   15499                 :          1 :   QCOMPARE( c1.wktTypeStr(), QString( "GeometryCollection" ) );
   15500                 :          1 :   QCOMPARE( c1.geometryType(), QString( "GeometryCollection" ) );
   15501                 :          1 :   QCOMPARE( c1.dimension(), 1 );
   15502                 :          1 :   QVERIFY( !c1.hasCurvedSegments() );
   15503                 :          1 :   QCOMPARE( c1.area(), 0.0 );
   15504                 :          1 :   QCOMPARE( c1.perimeter(), 0.0 );
   15505                 :          1 :   QVERIFY( c1.geometryN( 0 ) );
   15506                 :          1 :   QVERIFY( !c1.geometryN( 100 ) );
   15507                 :          1 :   QVERIFY( !c1.geometryN( -1 ) );
   15508                 :          1 :   QCOMPARE( c1.vertexCount( 0, 0 ), 5 );
   15509                 :          1 :   QCOMPARE( c1.vertexCount( 1, 0 ), 0 );
   15510                 :            : 
   15511                 :            :   //retrieve geometry and check
   15512                 :          1 :   QCOMPARE( *( static_cast< const QgsLineString * >( c1.geometryN( 0 ) ) ), part );
   15513                 :            : 
   15514                 :            :   //initial adding of geometry should set z/m type
   15515                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 )
   15516                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 0, 10, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 10, 10, 3 )
   15517                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 10, 0, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 ) );
   15518                 :          1 :   QgsGeometryCollection c2;
   15519                 :          1 :   c2.addGeometry( part.clone() );
   15520                 :            :   //QVERIFY( c2.is3D() ); //no meaning for collections?
   15521                 :            :   //QVERIFY( !c2.isMeasure() ); //no meaning for collections?
   15522                 :          1 :   QCOMPARE( c2.wkbType(), QgsWkbTypes::GeometryCollection );
   15523                 :          1 :   QCOMPARE( c2.wktTypeStr(), QString( "GeometryCollection" ) );
   15524                 :          1 :   QCOMPARE( c2.geometryType(), QString( "GeometryCollection" ) );
   15525                 :          1 :   QCOMPARE( *( static_cast< const QgsLineString * >( c2.geometryN( 0 ) ) ), part );
   15526                 :          1 :   QgsGeometryCollection c3;
   15527                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 0, 0, 0, 1 )
   15528                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 0, 10, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 10, 10, 0, 3 )
   15529                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 10, 0, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 0, 0, 0, 1 ) );
   15530                 :          1 :   c3.addGeometry( part.clone() );
   15531                 :            :   //QVERIFY( !c3.is3D() ); //no meaning for collections?
   15532                 :            :   //QVERIFY( c3.isMeasure() ); //no meaning for collections?
   15533                 :          1 :   QCOMPARE( c3.wkbType(), QgsWkbTypes::GeometryCollection );
   15534                 :          1 :   QCOMPARE( c3.wktTypeStr(), QString( "GeometryCollection" ) );
   15535                 :          1 :   QCOMPARE( *( static_cast< const QgsLineString * >( c3.geometryN( 0 ) ) ), part );
   15536                 :          1 :   QgsGeometryCollection c4;
   15537                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 2, 1 )
   15538                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 0, 10, 3, 2 ) << QgsPoint( QgsWkbTypes::PointZM, 10, 10, 5, 3 )
   15539                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 10, 0, 0, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 2, 1 ) );
   15540                 :          1 :   c4.addGeometry( part.clone() );
   15541                 :            :   //QVERIFY( c4.is3D() ); //no meaning for collections?
   15542                 :            :   //QVERIFY( c4.isMeasure() ); //no meaning for collections?
   15543                 :          1 :   QCOMPARE( c4.wkbType(), QgsWkbTypes::GeometryCollection );
   15544                 :          1 :   QCOMPARE( c4.wktTypeStr(), QString( "GeometryCollection" ) );
   15545                 :          1 :   QCOMPARE( *( static_cast< const QgsLineString * >( c4.geometryN( 0 ) ) ), part );
   15546                 :            : 
   15547                 :            :   //add another part
   15548                 :          1 :   QgsGeometryCollection c6;
   15549                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
   15550                 :          1 :                   << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) );
   15551                 :          1 :   c6.addGeometry( part.clone() );
   15552                 :          1 :   QCOMPARE( c6.vertexCount( 0, 0 ), 5 );
   15553                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( 1, 1 ) << QgsPoint( 1, 9 ) << QgsPoint( 9, 9 )
   15554                 :          1 :                   << QgsPoint( 9, 1 ) << QgsPoint( 1, 1 ) );
   15555                 :          1 :   c6.addGeometry( part.clone() );
   15556                 :          1 :   QCOMPARE( c6.vertexCount( 1, 0 ), 5 );
   15557                 :          1 :   QCOMPARE( c6.numGeometries(), 2 );
   15558                 :          1 :   QVERIFY( c6.geometryN( 0 ) );
   15559                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c6.geometryN( 1 ) ), part );
   15560                 :            : 
   15561                 :          1 :   QgsCoordinateSequence seq = c6.coordinateSequence();
   15562                 :          1 :   QCOMPARE( seq, QgsCoordinateSequence() << ( QgsRingSequence() << ( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0, 10 ) << QgsPoint( 10, 10 )
   15563                 :            :             << QgsPoint( 10, 0 ) << QgsPoint( 0, 0 ) ) )
   15564                 :            :             << ( QgsRingSequence() << ( QgsPointSequence() << QgsPoint( 1, 1 ) << QgsPoint( 1, 9 ) << QgsPoint( 9, 9 )
   15565                 :            :                                         << QgsPoint( 9, 1 ) << QgsPoint( 1, 1 ) ) ) );
   15566                 :          1 :   QCOMPARE( c6.nCoordinates(), 10 );
   15567                 :            : 
   15568                 :            : 
   15569                 :            :   //clear
   15570                 :          1 :   QgsGeometryCollection c7;
   15571                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 )
   15572                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 0, 10, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 10, 10, 3 )
   15573                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 10, 0, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 ) );
   15574                 :          1 :   c7.addGeometry( part.clone() );
   15575                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 1, 1 )
   15576                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 1, 9, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 9, 9, 3 )
   15577                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 9, 1, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 1, 1, 1 ) );
   15578                 :          1 :   c7.addGeometry( part.clone() );
   15579                 :          1 :   QCOMPARE( c7.numGeometries(), 2 );
   15580                 :          1 :   c7.clear();
   15581                 :          1 :   QVERIFY( c7.isEmpty() );
   15582                 :          1 :   QCOMPARE( c7.numGeometries(), 0 );
   15583                 :          1 :   QCOMPARE( c7.nCoordinates(), 0 );
   15584                 :          1 :   QCOMPARE( c7.ringCount(), 0 );
   15585                 :          1 :   QCOMPARE( c7.partCount(), 0 );
   15586                 :          1 :   QVERIFY( !c7.is3D() );
   15587                 :          1 :   QVERIFY( !c7.isMeasure() );
   15588                 :          1 :   QCOMPARE( c7.wkbType(), QgsWkbTypes::GeometryCollection );
   15589                 :            : 
   15590                 :            :   //clone
   15591                 :          1 :   QgsGeometryCollection c11;
   15592                 :          1 :   std::unique_ptr< QgsGeometryCollection >cloned( c11.clone() );
   15593                 :          1 :   QVERIFY( cloned->isEmpty() );
   15594                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 5 )
   15595                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 0, 10, 2, 6 ) << QgsPoint( QgsWkbTypes::PointZM, 10, 10, 3, 7 )
   15596                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 9 ) );
   15597                 :          1 :   c11.addGeometry( part.clone() );
   15598                 :          1 :   QgsLineString part2;
   15599                 :          2 :   part2.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 2 )
   15600                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 1, 9, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZM, 9, 9, 3, 6 )
   15601                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 9, 1, 4, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 7 ) );
   15602                 :          1 :   c11.addGeometry( part2.clone() );
   15603                 :          1 :   cloned.reset( c11.clone() );
   15604                 :          1 :   QCOMPARE( cloned->numGeometries(), 2 );
   15605                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( cloned->geometryN( 0 ) ), part );
   15606                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( cloned->geometryN( 1 ) ), part2 );
   15607                 :            : 
   15608                 :            :   //copy constructor
   15609                 :          1 :   QgsGeometryCollection c12;
   15610                 :          1 :   QgsGeometryCollection c13( c12 );
   15611                 :          1 :   QVERIFY( c13.isEmpty() );
   15612                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 5 )
   15613                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 0, 10, 2, 6 ) << QgsPoint( QgsWkbTypes::PointZM, 10, 10, 3, 7 )
   15614                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 9 ) );
   15615                 :          1 :   c12.addGeometry( part.clone() );
   15616                 :          2 :   part2.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 2 )
   15617                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 1, 9, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZM, 9, 9, 3, 6 )
   15618                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 9, 1, 4, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 7 ) );
   15619                 :          1 :   c12.addGeometry( part2.clone() );
   15620                 :          1 :   QgsGeometryCollection c14( c12 );
   15621                 :          1 :   QCOMPARE( c14.numGeometries(), 2 );
   15622                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c14.geometryN( 0 ) ), part );
   15623                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c14.geometryN( 1 ) ), part2 );
   15624                 :            : 
   15625                 :            :   //assignment operator
   15626                 :          1 :   QgsGeometryCollection c15;
   15627                 :          1 :   c15 = c13;
   15628                 :          1 :   QCOMPARE( c15.numGeometries(), 0 );
   15629                 :          1 :   c15 = c14;
   15630                 :          1 :   QCOMPARE( c15.numGeometries(), 2 );
   15631                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c15.geometryN( 0 ) ), part );
   15632                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c15.geometryN( 1 ) ), part2 );
   15633                 :            : 
   15634                 :            :   //equality
   15635                 :          1 :   QgsGeometryCollection emptyCollection;
   15636                 :          1 :   QVERIFY( !( emptyCollection == c15 ) );
   15637                 :          1 :   QVERIFY( emptyCollection != c15 );
   15638                 :          1 :   QgsPoint notCollection;
   15639                 :          1 :   QVERIFY( !( emptyCollection == notCollection ) );
   15640                 :          1 :   QVERIFY( emptyCollection != notCollection );
   15641                 :          1 :   QgsMultiPoint mp;
   15642                 :          1 :   QgsMultiLineString ml;
   15643                 :          1 :   QVERIFY( mp != ml );
   15644                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 )
   15645                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 0, 10, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 10, 10, 3 )
   15646                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 10, 0, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 ) );
   15647                 :          1 :   ml.addGeometry( part.clone() );
   15648                 :          1 :   QgsMultiLineString ml2;
   15649                 :          1 :   QVERIFY( ml != ml2 );
   15650                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 1, 1 )
   15651                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 0, 10, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 10, 10, 3 )
   15652                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 10, 0, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 ) );
   15653                 :          1 :   ml2.addGeometry( part.clone() );
   15654                 :          1 :   QVERIFY( ml != ml2 );
   15655                 :            : 
   15656                 :          1 :   QgsMultiLineString ml3;
   15657                 :          1 :   ml3.addGeometry( part.clone() );
   15658                 :          1 :   QVERIFY( ml2 == ml3 );
   15659                 :            : 
   15660                 :            :   //toCurveType
   15661                 :          1 :   std::unique_ptr< QgsGeometryCollection > curveType( c12.toCurveType() );
   15662                 :          1 :   QCOMPARE( curveType->wkbType(), QgsWkbTypes::GeometryCollection );
   15663                 :          1 :   QCOMPARE( curveType->numGeometries(), 2 );
   15664                 :          1 :   const QgsCompoundCurve *curve = static_cast< const QgsCompoundCurve * >( curveType->geometryN( 0 ) );
   15665                 :          1 :   QCOMPARE( curve->numPoints(), 5 );
   15666                 :          1 :   QCOMPARE( curve->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 5 ) );
   15667                 :          1 :   QCOMPARE( curve->vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( QgsWkbTypes::PointZM, 0, 10, 2, 6 ) );
   15668                 :          1 :   QCOMPARE( curve->vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( QgsWkbTypes::PointZM, 10, 10, 3, 7 ) );
   15669                 :          1 :   QCOMPARE( curve->vertexAt( QgsVertexId( 0, 0, 3 ) ), QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) );
   15670                 :          1 :   QCOMPARE( curve->vertexAt( QgsVertexId( 0, 0, 4 ) ), QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 9 ) );
   15671                 :          1 :   curve = static_cast< const QgsCompoundCurve * >( curveType->geometryN( 1 ) );
   15672                 :          1 :   QCOMPARE( curve->numPoints(), 5 );
   15673                 :          1 :   QCOMPARE( curve->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 2 ) );
   15674                 :          1 :   QCOMPARE( curve->vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( QgsWkbTypes::PointZM, 1, 9, 2, 3 ) );
   15675                 :          1 :   QCOMPARE( curve->vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( QgsWkbTypes::PointZM, 9, 9, 3, 6 ) );
   15676                 :          1 :   QCOMPARE( curve->vertexAt( QgsVertexId( 0, 0, 3 ) ), QgsPoint( QgsWkbTypes::PointZM, 9, 1, 4, 4 ) );
   15677                 :          1 :   QCOMPARE( curve->vertexAt( QgsVertexId( 0, 0, 4 ) ), QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 7 ) );
   15678                 :            : 
   15679                 :            :   //to/fromWKB
   15680                 :          1 :   QgsGeometryCollection c16;
   15681                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 0, 0 )
   15682                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 0, 10 ) << QgsPoint( QgsWkbTypes::Point, 10, 10 )
   15683                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 10, 0 ) << QgsPoint( QgsWkbTypes::Point, 0, 0 ) );
   15684                 :          1 :   c16.addGeometry( part.clone() );
   15685                 :          2 :   part2.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 1, 1 )
   15686                 :          1 :                    << QgsPoint( QgsWkbTypes::Point, 1, 9 ) << QgsPoint( QgsWkbTypes::Point, 9, 9 )
   15687                 :          1 :                    << QgsPoint( QgsWkbTypes::Point, 9, 1 ) << QgsPoint( QgsWkbTypes::Point, 1, 1 ) );
   15688                 :          1 :   c16.addGeometry( part2.clone() );
   15689                 :          1 :   QByteArray wkb16 = c16.asWkb();
   15690                 :          1 :   QCOMPARE( wkb16.size(), c16.wkbSize() );
   15691                 :          1 :   QgsGeometryCollection c17;
   15692                 :          1 :   QgsConstWkbPtr wkb16ptr( wkb16 );
   15693                 :          1 :   c17.fromWkb( wkb16ptr );
   15694                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   15695                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c17.geometryN( 0 ) ), part );
   15696                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c17.geometryN( 1 ) ), part2 );
   15697                 :            : 
   15698                 :            :   //parts with Z
   15699                 :          1 :   c16.clear();
   15700                 :          1 :   c17.clear();
   15701                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 )
   15702                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 0, 10, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 10, 10, 3 )
   15703                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZ, 10, 0, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 0, 0, 1 ) );
   15704                 :          1 :   c16.addGeometry( part.clone() );
   15705                 :          2 :   part2.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 1, 1 )
   15706                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZ, 1, 9, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 9, 9, 3 )
   15707                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZ, 9, 1, 4 ) << QgsPoint( QgsWkbTypes::PointZ, 1, 1, 1 ) );
   15708                 :          1 :   c16.addGeometry( part2.clone() );
   15709                 :          1 :   wkb16 = c16.asWkb();
   15710                 :          1 :   QgsConstWkbPtr wkb16ptr2( wkb16 );
   15711                 :          1 :   c17.fromWkb( wkb16ptr2 );
   15712                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   15713                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c17.geometryN( 0 ) ), part );
   15714                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c17.geometryN( 1 ) ), part2 );
   15715                 :            : 
   15716                 :            : 
   15717                 :            :   //parts with m
   15718                 :          1 :   c16.clear();
   15719                 :          1 :   c17.clear();
   15720                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 0, 0, 0, 1 )
   15721                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 0, 10,  0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 10, 10, 0, 3 )
   15722                 :          1 :                   << QgsPoint( QgsWkbTypes::PointM, 10, 0,  0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 0, 0, 0, 1 ) );
   15723                 :          1 :   c16.addGeometry( part.clone() );
   15724                 :          2 :   part2.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 1, 0, 1 )
   15725                 :          1 :                    << QgsPoint( QgsWkbTypes::PointM, 1, 9, 0, 2 ) << QgsPoint( QgsWkbTypes::PointM, 9, 9, 0, 3 )
   15726                 :          1 :                    << QgsPoint( QgsWkbTypes::PointM, 9, 1, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 1, 1, 0, 1 ) );
   15727                 :          1 :   c16.addGeometry( part2.clone() );
   15728                 :          1 :   wkb16 = c16.asWkb();
   15729                 :          1 :   QgsConstWkbPtr wkb16ptr3( wkb16 );
   15730                 :          1 :   c17.fromWkb( wkb16ptr3 );
   15731                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   15732                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c17.geometryN( 0 ) ), part );
   15733                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c17.geometryN( 1 ) ), part2 );
   15734                 :            : 
   15735                 :            :   // parts with ZM
   15736                 :          1 :   c16.clear();
   15737                 :          1 :   c17.clear();
   15738                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 5 )
   15739                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 0, 10, 2, 6 ) << QgsPoint( QgsWkbTypes::PointZM, 10, 10, 3, 7 )
   15740                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 9 ) );
   15741                 :          1 :   c16.addGeometry( part.clone() );
   15742                 :          2 :   part2.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 2 )
   15743                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 1, 9, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZM, 9, 9, 3, 6 )
   15744                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 9, 1, 4, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 7 ) );
   15745                 :          1 :   c16.addGeometry( part2.clone() );
   15746                 :          1 :   wkb16 = c16.asWkb();
   15747                 :          1 :   QgsConstWkbPtr wkb16ptr4( wkb16 );
   15748                 :          1 :   c17.fromWkb( wkb16ptr4 );
   15749                 :          1 :   QCOMPARE( c17.numGeometries(), 2 );
   15750                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c17.geometryN( 0 ) ), part );
   15751                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c17.geometryN( 1 ) ), part2 );
   15752                 :            : 
   15753                 :            : 
   15754                 :            :   //bad WKB - check for no crash
   15755                 :          1 :   c17.clear();
   15756                 :          1 :   QgsConstWkbPtr nullPtr( nullptr, 0 );
   15757                 :          1 :   QVERIFY( !c17.fromWkb( nullPtr ) );
   15758                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::GeometryCollection );
   15759                 :          1 :   QgsPoint point( 1, 2 );
   15760                 :          1 :   QByteArray wkbPoint = point.asWkb();
   15761                 :          1 :   QgsConstWkbPtr wkbPointPtr( wkbPoint );
   15762                 :          1 :   QVERIFY( !c17.fromWkb( wkbPointPtr ) );
   15763                 :          1 :   QCOMPARE( c17.wkbType(), QgsWkbTypes::GeometryCollection );
   15764                 :            : 
   15765                 :            :   //to/from WKT
   15766                 :          1 :   QgsGeometryCollection c18;
   15767                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 5 )
   15768                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 0, 10, 2, 6 ) << QgsPoint( QgsWkbTypes::PointZM, 10, 10, 3, 7 )
   15769                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 9 ) );
   15770                 :          1 :   c18.addGeometry( part.clone() );
   15771                 :          2 :   part2.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 2 )
   15772                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 1, 9, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZM, 9, 9, 3, 6 )
   15773                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 9, 1, 4, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 7 ) );
   15774                 :          1 :   c18.addGeometry( part2.clone() );
   15775                 :            : 
   15776                 :          1 :   QString wkt = c18.asWkt();
   15777                 :          1 :   QVERIFY( !wkt.isEmpty() );
   15778                 :          1 :   QgsGeometryCollection c19;
   15779                 :          1 :   QVERIFY( c19.fromWkt( wkt ) );
   15780                 :          1 :   QCOMPARE( c19.numGeometries(), 2 );
   15781                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c19.geometryN( 0 ) ), part );
   15782                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( c19.geometryN( 1 ) ), part2 );
   15783                 :            : 
   15784                 :            :   //bad WKT
   15785                 :          1 :   QgsGeometryCollection c20;
   15786                 :          1 :   QVERIFY( !c20.fromWkt( "Point()" ) );
   15787                 :          1 :   QVERIFY( c20.isEmpty() );
   15788                 :          1 :   QCOMPARE( c20.numGeometries(), 0 );
   15789                 :          1 :   QCOMPARE( c20.wkbType(), QgsWkbTypes::GeometryCollection );
   15790                 :            : 
   15791                 :            :   //as JSON
   15792                 :          1 :   QgsGeometryCollection exportC;
   15793                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 0, 0 )
   15794                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 0, 10 ) << QgsPoint( QgsWkbTypes::Point, 10, 10 )
   15795                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 10, 0 ) << QgsPoint( QgsWkbTypes::Point, 0, 0 ) );
   15796                 :          1 :   exportC.addGeometry( part.clone() );
   15797                 :            : 
   15798                 :            :   // GML document for compare
   15799                 :          1 :   QDomDocument doc( "gml" );
   15800                 :            : 
   15801                 :            : 
   15802                 :            :   // as GML2
   15803                 :          2 :   QString expectedSimpleGML2( QStringLiteral( "<MultiGeometry xmlns=\"gml\"><geometryMember xmlns=\"gml\"><LineString xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">0,0 0,10 10,10 10,0 0,0</coordinates></LineString></geometryMember></MultiGeometry>" ) );
   15804                 :          1 :   QString res = elemToString( exportC.asGml2( doc ) );
   15805                 :          3 :   QGSCOMPAREGML( res, expectedSimpleGML2 );
   15806                 :          2 :   QString expectedGML2empty( QStringLiteral( "<MultiGeometry xmlns=\"gml\"/>" ) );
   15807                 :          3 :   QGSCOMPAREGML( elemToString( QgsGeometryCollection().asGml2( doc ) ), expectedGML2empty );
   15808                 :            : 
   15809                 :            :   //as GML3
   15810                 :          2 :   QString expectedSimpleGML3( QStringLiteral( "<MultiGeometry xmlns=\"gml\"><geometryMember xmlns=\"gml\"><LineString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">0 0 0 10 10 10 10 0 0 0</posList></LineString></geometryMember></MultiGeometry>" ) );
   15811                 :          1 :   res = elemToString( exportC.asGml3( doc ) );
   15812                 :          1 :   QCOMPARE( res, expectedSimpleGML3 );
   15813                 :          2 :   QString expectedGML3empty( QStringLiteral( "<MultiGeometry xmlns=\"gml\"/>" ) );
   15814                 :          3 :   QGSCOMPAREGML( elemToString( QgsGeometryCollection().asGml3( doc ) ), expectedGML3empty );
   15815                 :            : 
   15816                 :            :   // as JSON
   15817                 :          1 :   QString expectedSimpleJson( "{\"geometries\":[{\"coordinates\":[[0.0,0.0],[0.0,10.0],[10.0,10.0],[10.0,0.0],[0.0,0.0]],\"type\":\"LineString\"}],\"type\":\"GeometryCollection\"}" );
   15818                 :          1 :   res = exportC.asJson();
   15819                 :          1 :   QCOMPARE( res, expectedSimpleJson );
   15820                 :            : 
   15821                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 1, 1 )
   15822                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 1, 9 ) << QgsPoint( QgsWkbTypes::Point, 9, 9 )
   15823                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 9, 1 ) << QgsPoint( QgsWkbTypes::Point, 1, 1 ) );
   15824                 :          1 :   exportC.addGeometry( part.clone() );
   15825                 :            : 
   15826                 :          1 :   QString expectedJson( "{\"geometries\":[{\"coordinates\":[[0.0,0.0],[0.0,10.0],[10.0,10.0],[10.0,0.0],[0.0,0.0]],\"type\":\"LineString\"},{\"coordinates\":[[1.0,1.0],[1.0,9.0],[9.0,9.0],[9.0,1.0],[1.0,1.0]],\"type\":\"LineString\"}],\"type\":\"GeometryCollection\"}" );
   15827                 :          1 :   res = exportC.asJson();
   15828                 :          1 :   QCOMPARE( res, expectedJson );
   15829                 :            : 
   15830                 :          1 :   QgsGeometryCollection exportFloat;
   15831                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 10 / 9.0, 10 / 9.0 )
   15832                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 10 / 9.0, 100 / 9.0 ) << QgsPoint( QgsWkbTypes::Point, 100 / 9.0, 100 / 9.0 )
   15833                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 100 / 9.0, 10 / 9.0 ) << QgsPoint( QgsWkbTypes::Point, 10 / 9.0, 10 / 9.0 ) );
   15834                 :          1 :   exportFloat.addGeometry( part.clone() );
   15835                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::Point, 2 / 3.0, 2 / 3.0 )
   15836                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 2 / 3.0, 4 / 3.0 ) << QgsPoint( QgsWkbTypes::Point, 4 / 3.0, 4 / 3.0 )
   15837                 :          1 :                   << QgsPoint( QgsWkbTypes::Point, 4 / 3.0, 2 / 3.0 ) << QgsPoint( QgsWkbTypes::Point, 2 / 3.0, 2 / 3.0 ) );
   15838                 :          1 :   exportFloat.addGeometry( part.clone() );
   15839                 :            : 
   15840                 :          1 :   QString expectedJsonPrec3( "{\"geometries\":[{\"coordinates\":[[1.111,1.111],[1.111,11.111],[11.111,11.111],[11.111,1.111],[1.111,1.111]],\"type\":\"LineString\"},{\"coordinates\":[[0.667,0.667],[0.667,1.333],[1.333,1.333],[1.333,0.667],[0.667,0.667]],\"type\":\"LineString\"}],\"type\":\"GeometryCollection\"}" );
   15841                 :          1 :   res = exportFloat.asJson( 3 );
   15842                 :          1 :   QCOMPARE( res, expectedJsonPrec3 );
   15843                 :            : 
   15844                 :            :   // as GML2
   15845                 :          2 :   QString expectedGML2( QStringLiteral( "<MultiGeometry xmlns=\"gml\"><geometryMember xmlns=\"gml\"><LineString xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">0,0 0,10 10,10 10,0 0,0</coordinates></LineString></geometryMember><geometryMember xmlns=\"gml\"><LineString xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">1,1 1,9 9,9 9,1 1,1</coordinates></LineString></geometryMember></MultiGeometry>" ) );
   15846                 :          1 :   res = elemToString( exportC.asGml2( doc ) );
   15847                 :          3 :   QGSCOMPAREGML( res, expectedGML2 );
   15848                 :          2 :   QString expectedGML2prec3( QStringLiteral( "<MultiGeometry xmlns=\"gml\"><geometryMember xmlns=\"gml\"><LineString xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">1.111,1.111 1.111,11.111 11.111,11.111 11.111,1.111 1.111,1.111</coordinates></LineString></geometryMember><geometryMember xmlns=\"gml\"><LineString xmlns=\"gml\"><coordinates xmlns=\"gml\" cs=\",\" ts=\" \">0.667,0.667 0.667,1.333 1.333,1.333 1.333,0.667 0.667,0.667</coordinates></LineString></geometryMember></MultiGeometry>" ) );
   15849                 :          1 :   res = elemToString( exportFloat.asGml2( doc, 3 ) );
   15850                 :          3 :   QGSCOMPAREGML( res, expectedGML2prec3 );
   15851                 :            : 
   15852                 :            :   //as GML3
   15853                 :          2 :   QString expectedGML3( QStringLiteral( "<MultiGeometry xmlns=\"gml\"><geometryMember xmlns=\"gml\"><LineString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">0 0 0 10 10 10 10 0 0 0</posList></LineString></geometryMember><geometryMember xmlns=\"gml\"><LineString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">1 1 1 9 9 9 9 1 1 1</posList></LineString></geometryMember></MultiGeometry>" ) );
   15854                 :          1 :   res = elemToString( exportC.asGml3( doc ) );
   15855                 :          1 :   QCOMPARE( res, expectedGML3 );
   15856                 :          2 :   QString expectedGML3prec3( QStringLiteral( "<MultiGeometry xmlns=\"gml\"><geometryMember xmlns=\"gml\"><LineString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">1.111 1.111 1.111 11.111 11.111 11.111 11.111 1.111 1.111 1.111</posList></LineString></geometryMember><geometryMember xmlns=\"gml\"><LineString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">0.667 0.667 0.667 1.333 1.333 1.333 1.333 0.667 0.667 0.667</posList></LineString></geometryMember></MultiGeometry>" ) );
   15857                 :          1 :   res = elemToString( exportFloat.asGml3( doc, 3 ) );
   15858                 :          1 :   QCOMPARE( res, expectedGML3prec3 );
   15859                 :            : 
   15860                 :            :   //asKML
   15861                 :          2 :   QString expectedKml( QStringLiteral( "<MultiGeometry><LinearRing><altitudeMode>clampToGround</altitudeMode><coordinates>0,0,0 0,10,0 10,10,0 10,0,0 0,0,0</coordinates></LinearRing><LinearRing><altitudeMode>clampToGround</altitudeMode><coordinates>1,1,0 1,9,0 9,9,0 9,1,0 1,1,0</coordinates></LinearRing></MultiGeometry>" ) );
   15862                 :          1 :   QCOMPARE( exportC.asKml(), expectedKml );
   15863                 :          2 :   QString expectedKmlPrec3( QStringLiteral( "<MultiGeometry><LinearRing><altitudeMode>clampToGround</altitudeMode><coordinates>1.111,1.111,0 1.111,11.111,0 11.111,11.111,0 11.111,1.111,0 1.111,1.111,0</coordinates></LinearRing><LinearRing><altitudeMode>clampToGround</altitudeMode><coordinates>0.667,0.667,0 0.667,1.333,0 1.333,1.333,0 1.333,0.667,0 0.667,0.667,0</coordinates></LinearRing></MultiGeometry>" ) );
   15864                 :          1 :   QCOMPARE( exportFloat.asKml( 3 ), expectedKmlPrec3 );
   15865                 :            : 
   15866                 :            : 
   15867                 :            :   // remove geometry
   15868                 :          1 :   QgsGeometryCollection rc;
   15869                 :            :   // no crash!
   15870                 :          1 :   rc.removeGeometry( -1 );
   15871                 :          1 :   rc.removeGeometry( 0 );
   15872                 :          1 :   rc.removeGeometry( 100 );
   15873                 :          2 :   part.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 5 )
   15874                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 0, 10, 2, 6 ) << QgsPoint( QgsWkbTypes::PointZM, 10, 10, 3, 7 )
   15875                 :          1 :                   << QgsPoint( QgsWkbTypes::PointZM, 10, 0, 4, 8 ) << QgsPoint( QgsWkbTypes::PointZM, 0, 0, 1, 9 ) );
   15876                 :          1 :   rc.addGeometry( part.clone() );
   15877                 :          2 :   part2.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 2 )
   15878                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 1, 9, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZM, 9, 9, 3, 6 )
   15879                 :          1 :                    << QgsPoint( QgsWkbTypes::PointZM, 9, 1, 4, 4 ) << QgsPoint( QgsWkbTypes::PointZM, 1, 1, 1, 7 ) );
   15880                 :          1 :   rc.addGeometry( part2.clone() );
   15881                 :            :   // no crash
   15882                 :          1 :   rc.removeGeometry( -1 );
   15883                 :          1 :   rc.removeGeometry( 100 );
   15884                 :            : 
   15885                 :          1 :   rc.removeGeometry( 0 );
   15886                 :          1 :   QCOMPARE( rc.numGeometries(), 1 );
   15887                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( rc.geometryN( 0 ) ), part2 );
   15888                 :            : 
   15889                 :          1 :   rc.addGeometry( part.clone() );
   15890                 :          1 :   rc.removeGeometry( 1 );
   15891                 :          1 :   QCOMPARE( rc.numGeometries(), 1 );
   15892                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( rc.geometryN( 0 ) ), part2 );
   15893                 :          1 :   rc.removeGeometry( 0 );
   15894                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   15895                 :            : 
   15896                 :            : 
   15897                 :            :   // insert geometry
   15898                 :          1 :   rc.clear();
   15899                 :          1 :   rc.insertGeometry( nullptr, 0 );
   15900                 :          1 :   QVERIFY( rc.isEmpty() );
   15901                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   15902                 :          1 :   rc.insertGeometry( nullptr, -1 );
   15903                 :          1 :   QVERIFY( rc.isEmpty() );
   15904                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   15905                 :          1 :   rc.insertGeometry( nullptr, 100 );
   15906                 :          1 :   QVERIFY( rc.isEmpty() );
   15907                 :          1 :   QCOMPARE( rc.numGeometries(), 0 );
   15908                 :            : 
   15909                 :          1 :   rc.insertGeometry( part.clone(), 0 );
   15910                 :          1 :   QCOMPARE( rc.numGeometries(), 1 );
   15911                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( rc.geometryN( 0 ) ), part );
   15912                 :          1 :   rc.insertGeometry( part2.clone(), 0 );
   15913                 :          1 :   QCOMPARE( rc.numGeometries(), 2 );
   15914                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( rc.geometryN( 0 ) ), part2 );
   15915                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( rc.geometryN( 1 ) ), part );
   15916                 :          1 :   rc.removeGeometry( 0 );
   15917                 :          1 :   rc.insertGeometry( part2.clone(), 1 );
   15918                 :          1 :   QCOMPARE( rc.numGeometries(), 2 );
   15919                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( rc.geometryN( 0 ) ), part );
   15920                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( rc.geometryN( 1 ) ), part2 );
   15921                 :          1 :   rc.removeGeometry( 1 );
   15922                 :          1 :   rc.insertGeometry( part2.clone(), 2 );
   15923                 :          1 :   QCOMPARE( rc.numGeometries(), 2 );
   15924                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( rc.geometryN( 0 ) ), part );
   15925                 :          1 :   QCOMPARE( *static_cast< const QgsLineString * >( rc.geometryN( 1 ) ), part2 );
   15926                 :            : 
   15927                 :            :   // cast
   15928                 :          1 :   QVERIFY( !QgsGeometryCollection().cast( nullptr ) );
   15929                 :          1 :   QgsGeometryCollection pCast;
   15930                 :          1 :   QVERIFY( QgsGeometryCollection().cast( &pCast ) );
   15931                 :          1 :   QgsGeometryCollection pCast2;
   15932                 :          2 :   pCast2.fromWkt( QStringLiteral( "GeometryCollectionZ(PolygonZ((0 0 0, 0 1 1, 1 0 2, 0 0 0)))" ) );
   15933                 :          1 :   QVERIFY( QgsGeometryCollection().cast( &pCast2 ) );
   15934                 :          2 :   pCast2.fromWkt( QStringLiteral( "GeometryCollectionM(PolygonM((0 0 1, 0 1 2, 1 0 3, 0 0 1)))" ) );
   15935                 :          1 :   QVERIFY( QgsGeometryCollection().cast( &pCast2 ) );
   15936                 :          2 :   pCast2.fromWkt( QStringLiteral( "GeometryCollectionZM(PolygonZM((0 0 0 1, 0 1 1 2, 1 0 2 3, 0 0 0 1)))" ) );
   15937                 :          1 :   QVERIFY( QgsGeometryCollection().cast( &pCast2 ) );
   15938                 :            : 
   15939                 :            :   //transform
   15940                 :            :   //CRS transform
   15941                 :          2 :   QgsCoordinateReferenceSystem sourceSrs( QStringLiteral( "EPSG:3994" ) );
   15942                 :          2 :   QgsCoordinateReferenceSystem destSrs( QStringLiteral( "EPSG:4202" ) ); // want a transform with ellipsoid change
   15943                 :          1 :   QgsCoordinateTransform tr( sourceSrs, destSrs, QgsProject::instance() );
   15944                 :            : 
   15945                 :            :   // 2d CRS transform
   15946                 :          1 :   QgsGeometryCollection pTransform;
   15947                 :          1 :   QgsLineString l21;
   15948                 :          2 :   l21.setPoints( QgsPointSequence() << QgsPoint( 6374985, -3626584 )
   15949                 :          1 :                  << QgsPoint( 6274985, -3526584 )
   15950                 :          1 :                  << QgsPoint( 6474985, -3526584 )
   15951                 :          1 :                  << QgsPoint( 6374985, -3626584 ) );
   15952                 :          1 :   pTransform.addGeometry( l21.clone() );
   15953                 :          1 :   pTransform.addGeometry( l21.clone() );
   15954                 :          1 :   pTransform.transform( tr, QgsCoordinateTransform::ForwardTransform );
   15955                 :          1 :   const QgsLineString *extR = static_cast< const QgsLineString * >( pTransform.geometryN( 0 ) );
   15956                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).x(), 175.771, 0.001 );
   15957                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).y(), -39.724, 0.001 );
   15958                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).x(),  174.581448, 0.001 );
   15959                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).y(), -38.7999, 0.001 );
   15960                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).x(),  176.958633, 0.001 );
   15961                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).y(), -38.7999, 0.001 );
   15962                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).x(),  175.771, 0.001 );
   15963                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).y(), -39.724, 0.001 );
   15964                 :          1 :   QGSCOMPARENEAR( extR->boundingBox().xMinimum(), 174.581448, 0.001 );
   15965                 :          1 :   QGSCOMPARENEAR( extR->boundingBox().yMinimum(), -39.724, 0.001 );
   15966                 :          1 :   QGSCOMPARENEAR( extR->boundingBox().xMaximum(), 176.959, 0.001 );
   15967                 :          1 :   QGSCOMPARENEAR( extR->boundingBox().yMaximum(), -38.7999, 0.001 );
   15968                 :          1 :   const QgsLineString *intR = static_cast< const QgsLineString * >( pTransform.geometryN( 1 ) );
   15969                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).x(), 175.771, 0.001 );
   15970                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).y(), -39.724, 0.001 );
   15971                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).x(),  174.581448, 0.001 );
   15972                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).y(), -38.7999, 0.001 );
   15973                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).x(),  176.958633, 0.001 );
   15974                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).y(), -38.7999, 0.001 );
   15975                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).x(),  175.771, 0.001 );
   15976                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).y(), -39.724, 0.001 );
   15977                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().xMinimum(), 174.581448, 0.001 );
   15978                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().yMinimum(), -39.724, 0.001 );
   15979                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().xMaximum(), 176.959, 0.001 );
   15980                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().yMaximum(), -38.7999, 0.001 );
   15981                 :            : 
   15982                 :            :   //3d CRS transform
   15983                 :          1 :   QgsLineString l22;
   15984                 :          2 :   l22.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 6374985, -3626584, 1, 2 )
   15985                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 6274985, -3526584, 3, 4 )
   15986                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 6474985, -3526584, 5, 6 )
   15987                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 6374985, -3626584, 1, 2 ) );
   15988                 :          1 :   pTransform.clear();
   15989                 :          1 :   pTransform.addGeometry( l22.clone() );
   15990                 :          1 :   pTransform.addGeometry( l22.clone() );
   15991                 :          1 :   pTransform.transform( tr, QgsCoordinateTransform::ForwardTransform );
   15992                 :          1 :   extR = static_cast< const QgsLineString * >( pTransform.geometryN( 0 ) );
   15993                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).x(), 175.771, 0.001 );
   15994                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).y(), -39.724, 0.001 );
   15995                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).z(), 1.0, 0.001 );
   15996                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).m(), 2.0, 0.001 );
   15997                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).x(),  174.581448, 0.001 );
   15998                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).y(), -38.7999, 0.001 );
   15999                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).z(), 3.0, 0.001 );
   16000                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).m(), 4.0, 0.001 );
   16001                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).x(),  176.958633, 0.001 );
   16002                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).y(), -38.7999, 0.001 );
   16003                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).z(), 5.0, 0.001 );
   16004                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).m(), 6.0, 0.001 );
   16005                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).x(),  175.771, 0.001 );
   16006                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).y(), -39.724, 0.001 );
   16007                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).z(), 1.0, 0.001 );
   16008                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).m(), 2.0, 0.001 );
   16009                 :          1 :   QGSCOMPARENEAR( extR->boundingBox().xMinimum(), 174.581448, 0.001 );
   16010                 :          1 :   QGSCOMPARENEAR( extR->boundingBox().yMinimum(), -39.724, 0.001 );
   16011                 :          1 :   QGSCOMPARENEAR( extR->boundingBox().xMaximum(), 176.959, 0.001 );
   16012                 :          1 :   QGSCOMPARENEAR( extR->boundingBox().yMaximum(), -38.7999, 0.001 );
   16013                 :          1 :   intR = static_cast< const QgsLineString * >( pTransform.geometryN( 1 ) );
   16014                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).x(), 175.771, 0.001 );
   16015                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).y(), -39.724, 0.001 );
   16016                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).z(), 1.0, 0.001 );
   16017                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).m(), 2.0, 0.001 );
   16018                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).x(),  174.581448, 0.001 );
   16019                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).y(), -38.7999, 0.001 );
   16020                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).z(), 3.0, 0.001 );
   16021                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).m(), 4.0, 0.001 );
   16022                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).x(),  176.958633, 0.001 );
   16023                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).y(), -38.7999, 0.001 );
   16024                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).z(), 5.0, 0.001 );
   16025                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).m(), 6.0, 0.001 );
   16026                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).x(),  175.771, 0.001 );
   16027                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).y(), -39.724, 0.001 );
   16028                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).z(), 1.0, 0.001 );
   16029                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).m(), 2.0, 0.001 );
   16030                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().xMinimum(), 174.581448, 0.001 );
   16031                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().yMinimum(), -39.724, 0.001 );
   16032                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().xMaximum(), 176.959, 0.001 );
   16033                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().yMaximum(), -38.7999, 0.001 );
   16034                 :            : 
   16035                 :            :   //reverse transform
   16036                 :          1 :   pTransform.transform( tr, QgsCoordinateTransform::ReverseTransform );
   16037                 :          1 :   extR = static_cast< const QgsLineString * >( pTransform.geometryN( 0 ) );
   16038                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).x(), 6374984, 100 );
   16039                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).y(), -3626584, 100 );
   16040                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).z(), 1.0, 0.001 );
   16041                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).m(), 2.0, 0.001 );
   16042                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).x(), 6274984, 100 );
   16043                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).y(), -3526584, 100 );
   16044                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).z(), 3.0, 0.001 );
   16045                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).m(), 4.0, 0.001 );
   16046                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).x(),  6474984, 100 );
   16047                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).y(), -3526584, 100 );
   16048                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).z(), 5.0, 0.001 );
   16049                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).m(), 6.0, 0.001 );
   16050                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).x(),  6374984, 100 );
   16051                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).y(), -3626584, 100 );
   16052                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).z(), 1.0, 0.001 );
   16053                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).m(), 2.0, 0.001 );
   16054                 :          1 :   QGSCOMPARENEAR( extR->boundingBox().xMinimum(), 6274984, 100 );
   16055                 :          1 :   QGSCOMPARENEAR( extR->boundingBox().yMinimum(), -3626584, 100 );
   16056                 :          1 :   QGSCOMPARENEAR( extR->boundingBox().xMaximum(), 6474984, 100 );
   16057                 :          1 :   QGSCOMPARENEAR( extR->boundingBox().yMaximum(), -3526584, 100 );
   16058                 :          1 :   intR = static_cast< const QgsLineString * >( pTransform.geometryN( 1 ) );
   16059                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).x(), 6374984, 100 );
   16060                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).y(), -3626584, 100 );
   16061                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).z(), 1.0, 0.001 );
   16062                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).m(), 2.0, 0.001 );
   16063                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).x(), 6274984, 100 );
   16064                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).y(), -3526584, 100 );
   16065                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).z(), 3.0, 0.001 );
   16066                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).m(), 4.0, 0.001 );
   16067                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).x(),  6474984, 100 );
   16068                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).y(), -3526584, 100 );
   16069                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).z(), 5.0, 0.001 );
   16070                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).m(), 6.0, 0.001 );
   16071                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).x(),  6374984, 100 );
   16072                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).y(), -3626584, 100 );
   16073                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).z(), 1.0, 0.001 );
   16074                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).m(), 2.0, 0.001 );
   16075                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().xMinimum(), 6274984, 100 );
   16076                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().yMinimum(), -3626584, 100 );
   16077                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().xMaximum(), 6474984, 100 );
   16078                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().yMaximum(), -3526584, 100 );
   16079                 :            : 
   16080                 :            : #if PROJ_VERSION_MAJOR<6 // note - z value transform doesn't currently work with proj 6+, because we don't yet support compound CRS definitions
   16081                 :            :   //z value transform
   16082                 :            :   pTransform.transform( tr, QgsCoordinateTransform::ForwardTransform, true );
   16083                 :            :   extR = static_cast< const QgsLineString * >( pTransform.geometryN( 0 ) );
   16084                 :            :   QGSCOMPARENEAR( extR->pointN( 0 ).z(), -19.249066, 0.001 );
   16085                 :            :   QGSCOMPARENEAR( extR->pointN( 1 ).z(), -19.148357, 0.001 );
   16086                 :            :   QGSCOMPARENEAR( extR->pointN( 2 ).z(), -19.092128, 0.001 );
   16087                 :            :   QGSCOMPARENEAR( extR->pointN( 3 ).z(), -19.249066, 0.001 );
   16088                 :            :   intR = static_cast< const QgsLineString * >( pTransform.geometryN( 1 ) );
   16089                 :            :   QGSCOMPARENEAR( intR->pointN( 0 ).z(), -19.249066, 0.001 );
   16090                 :            :   QGSCOMPARENEAR( intR->pointN( 1 ).z(), -19.148357, 0.001 );
   16091                 :            :   QGSCOMPARENEAR( intR->pointN( 2 ).z(), -19.092128, 0.001 );
   16092                 :            :   QGSCOMPARENEAR( intR->pointN( 3 ).z(), -19.249066, 0.001 );
   16093                 :            :   pTransform.transform( tr, QgsCoordinateTransform::ReverseTransform, true );
   16094                 :            :   extR = static_cast< const QgsLineString * >( pTransform.geometryN( 0 ) );
   16095                 :            :   QGSCOMPARENEAR( extR->pointN( 0 ).z(), 1, 0.001 );
   16096                 :            :   QGSCOMPARENEAR( extR->pointN( 1 ).z(), 3, 0.001 );
   16097                 :            :   QGSCOMPARENEAR( extR->pointN( 2 ).z(), 5, 0.001 );
   16098                 :            :   QGSCOMPARENEAR( extR->pointN( 3 ).z(), 1, 0.001 );
   16099                 :            :   intR = static_cast< const QgsLineString * >( pTransform.geometryN( 1 ) );
   16100                 :            :   QGSCOMPARENEAR( intR->pointN( 0 ).z(), 1, 0.001 );
   16101                 :            :   QGSCOMPARENEAR( intR->pointN( 1 ).z(), 3, 0.001 );
   16102                 :            :   QGSCOMPARENEAR( intR->pointN( 2 ).z(), 5, 0.001 );
   16103                 :            :   QGSCOMPARENEAR( intR->pointN( 3 ).z(), 1, 0.001 );
   16104                 :            : #endif
   16105                 :            : 
   16106                 :            :   //QTransform transform
   16107                 :          1 :   QTransform qtr = QTransform::fromScale( 2, 3 );
   16108                 :          1 :   QgsLineString l23;
   16109                 :          2 :   l23.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 )
   16110                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 11, 12, 13, 14 )
   16111                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 12, 23, 24 )
   16112                 :          1 :                  << QgsPoint( QgsWkbTypes::PointZM, 1, 2, 3, 4 ) );
   16113                 :          1 :   QgsGeometryCollection pTransform2;
   16114                 :          1 :   pTransform2.addGeometry( l23.clone() );
   16115                 :          1 :   pTransform2.addGeometry( l23.clone() );
   16116                 :          1 :   pTransform2.transform( qtr, 3, 2, 6, 3 );
   16117                 :            : 
   16118                 :          1 :   extR = static_cast< const QgsLineString * >( pTransform2.geometryN( 0 ) );
   16119                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).x(), 2, 100 );
   16120                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).y(), 6, 100 );
   16121                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).z(), 9.0, 0.001 );
   16122                 :          1 :   QGSCOMPARENEAR( extR->pointN( 0 ).m(), 18.0, 0.001 );
   16123                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).x(), 22, 100 );
   16124                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).y(), 36, 100 );
   16125                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).z(), 29.0, 0.001 );
   16126                 :          1 :   QGSCOMPARENEAR( extR->pointN( 1 ).m(), 48.0, 0.001 );
   16127                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).x(),  2, 100 );
   16128                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).y(), 36, 100 );
   16129                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).z(), 49.0, 0.001 );
   16130                 :          1 :   QGSCOMPARENEAR( extR->pointN( 2 ).m(), 78.0, 0.001 );
   16131                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).x(), 2, 100 );
   16132                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).y(), 6, 100 );
   16133                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).z(), 9.0, 0.001 );
   16134                 :          1 :   QGSCOMPARENEAR( extR->pointN( 3 ).m(), 18.0, 0.001 );
   16135                 :          1 :   QGSCOMPARENEAR( extR->boundingBox().xMinimum(), 2, 0.001 );
   16136                 :          1 :   QGSCOMPARENEAR( extR->boundingBox().yMinimum(), 6, 0.001 );
   16137                 :          1 :   QGSCOMPARENEAR( extR->boundingBox().xMaximum(), 22, 0.001 );
   16138                 :          1 :   QGSCOMPARENEAR( extR->boundingBox().yMaximum(), 36, 0.001 );
   16139                 :          1 :   intR = static_cast< const QgsLineString * >( pTransform2.geometryN( 1 ) );
   16140                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).x(), 2, 100 );
   16141                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).y(), 6, 100 );
   16142                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).z(), 9.0, 0.001 );
   16143                 :          1 :   QGSCOMPARENEAR( intR->pointN( 0 ).m(), 18.0, 0.001 );
   16144                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).x(), 22, 100 );
   16145                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).y(), 36, 100 );
   16146                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).z(), 29.0, 0.001 );
   16147                 :          1 :   QGSCOMPARENEAR( intR->pointN( 1 ).m(), 48.0, 0.001 );
   16148                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).x(),  2, 100 );
   16149                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).y(), 36, 100 );
   16150                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).z(), 49.0, 0.001 );
   16151                 :          1 :   QGSCOMPARENEAR( intR->pointN( 2 ).m(), 78.0, 0.001 );
   16152                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).x(), 2, 100 );
   16153                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).y(), 6, 100 );
   16154                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).z(), 9.0, 0.001 );
   16155                 :          1 :   QGSCOMPARENEAR( intR->pointN( 3 ).m(), 18.0, 0.001 );
   16156                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().xMinimum(), 2, 0.001 );
   16157                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().yMinimum(), 6, 0.001 );
   16158                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().xMaximum(), 22, 0.001 );
   16159                 :          1 :   QGSCOMPARENEAR( intR->boundingBox().yMaximum(), 36, 0.001 );
   16160                 :            : 
   16161                 :            : 
   16162                 :            :   // closestSegment
   16163                 :          1 :   QgsPoint pt;
   16164                 :          1 :   QgsVertexId v;
   16165                 :          1 :   int leftOf = 0;
   16166                 :          1 :   QgsGeometryCollection empty;
   16167                 :          1 :   ( void )empty.closestSegment( QgsPoint( 1, 2 ), pt, v ); // empty collection, just want no crash
   16168                 :            : 
   16169                 :          1 :   QgsGeometryCollection p21;
   16170                 :          1 :   QgsLineString p21ls;
   16171                 :          1 :   p21ls.setPoints( QgsPointSequence() << QgsPoint( 5, 10 ) << QgsPoint( 7, 12 ) << QgsPoint( 5, 15 ) << QgsPoint( 5, 10 ) );
   16172                 :          1 :   p21.addGeometry( p21ls.clone() );
   16173                 :          1 :   QGSCOMPARENEAR( p21.closestSegment( QgsPoint( 4, 11 ), pt, v, &leftOf ), 1.0, 0.0001 );
   16174                 :          1 :   QGSCOMPARENEAR( pt.x(), 5, 0.01 );
   16175                 :          1 :   QGSCOMPARENEAR( pt.y(), 11, 0.01 );
   16176                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 3 ) );
   16177                 :          1 :   QCOMPARE( leftOf, 1 );
   16178                 :          1 :   QGSCOMPARENEAR( p21.closestSegment( QgsPoint( 8, 11 ), pt, v, &leftOf ),  2.0, 0.0001 );
   16179                 :          1 :   QGSCOMPARENEAR( pt.x(), 7, 0.01 );
   16180                 :          1 :   QGSCOMPARENEAR( pt.y(), 12, 0.01 );
   16181                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
   16182                 :          1 :   QCOMPARE( leftOf, 1 );
   16183                 :          1 :   QGSCOMPARENEAR( p21.closestSegment( QgsPoint( 6, 11.5 ), pt, v, &leftOf ), 0.125000, 0.0001 );
   16184                 :          1 :   QGSCOMPARENEAR( pt.x(), 6.25, 0.01 );
   16185                 :          1 :   QGSCOMPARENEAR( pt.y(), 11.25, 0.01 );
   16186                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
   16187                 :          1 :   QCOMPARE( leftOf, -1 );
   16188                 :          1 :   QGSCOMPARENEAR( p21.closestSegment( QgsPoint( 7, 16 ), pt, v, &leftOf ), 4.923077, 0.0001 );
   16189                 :          1 :   QGSCOMPARENEAR( pt.x(), 5.153846, 0.01 );
   16190                 :          1 :   QGSCOMPARENEAR( pt.y(), 14.769231, 0.01 );
   16191                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
   16192                 :          1 :   QCOMPARE( leftOf, 1 );
   16193                 :          1 :   QGSCOMPARENEAR( p21.closestSegment( QgsPoint( 5.5, 13.5 ), pt, v, &leftOf ), 0.173077, 0.0001 );
   16194                 :          1 :   QGSCOMPARENEAR( pt.x(), 5.846154, 0.01 );
   16195                 :          1 :   QGSCOMPARENEAR( pt.y(), 13.730769, 0.01 );
   16196                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
   16197                 :          1 :   QCOMPARE( leftOf, -1 );
   16198                 :            :   // point directly on segment
   16199                 :          1 :   QCOMPARE( p21.closestSegment( QgsPoint( 5, 15 ), pt, v, &leftOf ), 0.0 );
   16200                 :          1 :   QCOMPARE( pt, QgsPoint( 5, 15 ) );
   16201                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
   16202                 :            :   // with interior ring
   16203                 :          1 :   p21ls.setPoints( QgsPointSequence() << QgsPoint( 6, 11.5 ) << QgsPoint( 6.5, 12 ) << QgsPoint( 6, 13 ) << QgsPoint( 6, 11.5 ) );
   16204                 :          1 :   p21.addGeometry( p21ls.clone() );
   16205                 :          1 :   QGSCOMPARENEAR( p21.closestSegment( QgsPoint( 4, 11 ), pt, v, &leftOf ), 1.0, 0.0001 );
   16206                 :          1 :   QGSCOMPARENEAR( pt.x(), 5, 0.01 );
   16207                 :          1 :   QGSCOMPARENEAR( pt.y(), 11, 0.01 );
   16208                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 3 ) );
   16209                 :          1 :   QCOMPARE( leftOf, 1 );
   16210                 :          1 :   QGSCOMPARENEAR( p21.closestSegment( QgsPoint( 8, 11 ), pt, v, &leftOf ),  2.0, 0.0001 );
   16211                 :          1 :   QGSCOMPARENEAR( pt.x(), 7, 0.01 );
   16212                 :          1 :   QGSCOMPARENEAR( pt.y(), 12, 0.01 );
   16213                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
   16214                 :          1 :   QCOMPARE( leftOf, 1 );
   16215                 :          1 :   QGSCOMPARENEAR( p21.closestSegment( QgsPoint( 6, 11.4 ), pt, v, &leftOf ), 0.01, 0.0001 );
   16216                 :          1 :   QGSCOMPARENEAR( pt.x(), 6.0, 0.01 );
   16217                 :          1 :   QGSCOMPARENEAR( pt.y(), 11.5, 0.01 );
   16218                 :          1 :   QCOMPARE( v, QgsVertexId( 1, 0, 1 ) );
   16219                 :          1 :   QCOMPARE( leftOf, 1 );
   16220                 :          1 :   QGSCOMPARENEAR( p21.closestSegment( QgsPoint( 7, 16 ), pt, v, &leftOf ), 4.923077, 0.0001 );
   16221                 :          1 :   QGSCOMPARENEAR( pt.x(), 5.153846, 0.01 );
   16222                 :          1 :   QGSCOMPARENEAR( pt.y(), 14.769231, 0.01 );
   16223                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
   16224                 :          1 :   QCOMPARE( leftOf, 1 );
   16225                 :          1 :   QGSCOMPARENEAR( p21.closestSegment( QgsPoint( 5.5, 13.5 ), pt, v, &leftOf ), 0.173077, 0.0001 );
   16226                 :          1 :   QGSCOMPARENEAR( pt.x(), 5.846154, 0.01 );
   16227                 :          1 :   QGSCOMPARENEAR( pt.y(), 13.730769, 0.01 );
   16228                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
   16229                 :          1 :   QCOMPARE( leftOf, -1 );
   16230                 :            :   // point directly on segment
   16231                 :          1 :   QCOMPARE( p21.closestSegment( QgsPoint( 6, 13 ), pt, v, &leftOf ), 0.0 );
   16232                 :          1 :   QCOMPARE( pt, QgsPoint( 6, 13 ) );
   16233                 :          1 :   QCOMPARE( v, QgsVertexId( 1, 0, 2 ) );
   16234                 :          1 :   QCOMPARE( leftOf, 0 );
   16235                 :            : 
   16236                 :            :   //nextVertex
   16237                 :          1 :   QgsGeometryCollection p22;
   16238                 :          1 :   QVERIFY( !p22.nextVertex( v, pt ) );
   16239                 :          1 :   v = QgsVertexId( 0, 0, -2 );
   16240                 :          1 :   QVERIFY( !p22.nextVertex( v, pt ) );
   16241                 :          1 :   v = QgsVertexId( 0, 0, 10 );
   16242                 :          1 :   QVERIFY( !p22.nextVertex( v, pt ) );
   16243                 :          1 :   QgsLineString lp22;
   16244                 :          1 :   lp22.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 12 ) << QgsPoint( 1, 2 ) );
   16245                 :          1 :   p22.addGeometry( lp22.clone() );
   16246                 :          1 :   v = QgsVertexId( 0, 0, 4 ); //out of range
   16247                 :          1 :   QVERIFY( !p22.nextVertex( v, pt ) );
   16248                 :          1 :   v = QgsVertexId( 0, 0, -5 );
   16249                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
   16250                 :          1 :   v = QgsVertexId( 0, 0, -1 );
   16251                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
   16252                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 0 ) );
   16253                 :          1 :   QCOMPARE( pt, QgsPoint( 1, 2 ) );
   16254                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
   16255                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
   16256                 :          1 :   QCOMPARE( pt, QgsPoint( 11, 12 ) );
   16257                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
   16258                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 2 ) );
   16259                 :          1 :   QCOMPARE( pt, QgsPoint( 1, 12 ) );
   16260                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
   16261                 :          1 :   QCOMPARE( v, QgsVertexId( 0, 0, 3 ) );
   16262                 :          1 :   QCOMPARE( pt, QgsPoint( 1, 2 ) );
   16263                 :          1 :   v = QgsVertexId( 1, 0, 0 );
   16264                 :          1 :   QVERIFY( !p22.nextVertex( v, pt ) );
   16265                 :          1 :   v = QgsVertexId( 1, 0, 0 );
   16266                 :            :   // add another part
   16267                 :          1 :   lp22.setPoints( QgsPointSequence() << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) << QgsPoint( 11, 22 ) << QgsPoint( 11, 12 ) );
   16268                 :          1 :   p22.addGeometry( lp22.clone() );
   16269                 :          1 :   v = QgsVertexId( 1, 0, 4 ); //out of range
   16270                 :          1 :   QVERIFY( !p22.nextVertex( v, pt ) );
   16271                 :          1 :   v = QgsVertexId( 1, 0, -5 );
   16272                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
   16273                 :          1 :   v = QgsVertexId( 1, 0, -1 );
   16274                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
   16275                 :          1 :   QCOMPARE( v, QgsVertexId( 1, 0, 0 ) );
   16276                 :          1 :   QCOMPARE( pt, QgsPoint( 11, 12 ) );
   16277                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
   16278                 :          1 :   QCOMPARE( v, QgsVertexId( 1, 0, 1 ) );
   16279                 :          1 :   QCOMPARE( pt, QgsPoint( 21, 22 ) );
   16280                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
   16281                 :          1 :   QCOMPARE( v, QgsVertexId( 1, 0, 2 ) );
   16282                 :          1 :   QCOMPARE( pt, QgsPoint( 11, 22 ) );
   16283                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
   16284                 :          1 :   QCOMPARE( v, QgsVertexId( 1, 0, 3 ) );
   16285                 :          1 :   QCOMPARE( pt, QgsPoint( 11, 12 ) );
   16286                 :          1 :   v = QgsVertexId( 2, 0, 0 );
   16287                 :          1 :   QVERIFY( !p22.nextVertex( v, pt ) );
   16288                 :          1 :   v = QgsVertexId( 1, 1, 0 );
   16289                 :          1 :   QVERIFY( p22.nextVertex( v, pt ) );
   16290                 :          1 :   QCOMPARE( v, QgsVertexId( 1, 1, 1 ) ); //test that part number is maintained
   16291                 :          1 :   QCOMPARE( pt, QgsPoint( 21, 22 ) );
   16292                 :            : 
   16293                 :            : 
   16294                 :            :   // dropZValue
   16295                 :          1 :   QgsGeometryCollection p23;
   16296                 :          1 :   p23.dropZValue();
   16297                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::GeometryCollection );
   16298                 :          1 :   QgsLineString lp23;
   16299                 :          1 :   lp23.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 12 ) << QgsPoint( 1, 2 ) );
   16300                 :          1 :   p23.addGeometry( lp23.clone() );
   16301                 :          1 :   p23.addGeometry( lp23.clone() );
   16302                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::GeometryCollection );
   16303                 :          1 :   p23.dropZValue(); // not z
   16304                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::GeometryCollection );
   16305                 :          1 :   QCOMPARE( p23.geometryN( 0 )->wkbType(), QgsWkbTypes::LineString );
   16306                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.geometryN( 0 ) )->pointN( 0 ), QgsPoint( 1, 2 ) );
   16307                 :          1 :   QCOMPARE( p23.geometryN( 1 )->wkbType(), QgsWkbTypes::LineString );
   16308                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.geometryN( 1 ) )->pointN( 0 ), QgsPoint( 1, 2 ) );
   16309                 :            :   // with z
   16310                 :          1 :   lp23.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 3 ) << QgsPoint( 11, 12, 13 ) << QgsPoint( 1, 12, 23 ) << QgsPoint( 1, 2, 3 ) );
   16311                 :          1 :   p23.clear();
   16312                 :          1 :   p23.addGeometry( lp23.clone() );
   16313                 :          1 :   p23.addGeometry( lp23.clone() );
   16314                 :          1 :   p23.dropZValue();
   16315                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::GeometryCollection );
   16316                 :          1 :   QCOMPARE( p23.geometryN( 0 )->wkbType(), QgsWkbTypes::LineString );
   16317                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.geometryN( 0 ) )->pointN( 0 ), QgsPoint( 1, 2 ) );
   16318                 :          1 :   QCOMPARE( p23.geometryN( 1 )->wkbType(), QgsWkbTypes::LineString );
   16319                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.geometryN( 1 ) )->pointN( 0 ), QgsPoint( 1, 2 ) );
   16320                 :            :   // with zm
   16321                 :          1 :   lp23.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 3, 4 ) << QgsPoint( 11, 12, 13, 14 ) << QgsPoint( 1, 12, 23, 24 ) << QgsPoint( 1, 2, 3, 4 ) );
   16322                 :          1 :   p23.clear();
   16323                 :          1 :   p23.addGeometry( lp23.clone() );
   16324                 :          1 :   p23.addGeometry( lp23.clone() );
   16325                 :          1 :   p23.dropZValue();
   16326                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::GeometryCollection );
   16327                 :          1 :   QCOMPARE( p23.geometryN( 0 )->wkbType(), QgsWkbTypes::LineStringM );
   16328                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.geometryN( 0 ) )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) );
   16329                 :          1 :   QCOMPARE( p23.geometryN( 1 )->wkbType(), QgsWkbTypes::LineStringM );
   16330                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.geometryN( 1 ) )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) );
   16331                 :            : 
   16332                 :            : 
   16333                 :            :   // dropMValue
   16334                 :          1 :   p23.clear();
   16335                 :          1 :   p23.dropMValue();
   16336                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::GeometryCollection );
   16337                 :          1 :   lp23.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 1, 12 ) << QgsPoint( 1, 2 ) );
   16338                 :          1 :   p23.addGeometry( lp23.clone() );
   16339                 :          1 :   p23.addGeometry( lp23.clone() );
   16340                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::GeometryCollection );
   16341                 :          1 :   p23.dropMValue(); // not zm
   16342                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::GeometryCollection );
   16343                 :          1 :   QCOMPARE( p23.geometryN( 0 )->wkbType(), QgsWkbTypes::LineString );
   16344                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.geometryN( 0 ) )->pointN( 0 ), QgsPoint( 1, 2 ) );
   16345                 :          1 :   QCOMPARE( p23.geometryN( 1 )->wkbType(), QgsWkbTypes::LineString );
   16346                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.geometryN( 1 ) )->pointN( 0 ), QgsPoint( 1, 2 ) );
   16347                 :            :   // with m
   16348                 :          1 :   lp23.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM,  1, 2, 0, 3 ) << QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 13 ) << QgsPoint( QgsWkbTypes::PointM, 1, 12, 0, 23 ) << QgsPoint( QgsWkbTypes::PointM,  1, 2, 0, 3 ) );
   16349                 :          1 :   p23.clear();
   16350                 :          1 :   p23.addGeometry( lp23.clone() );
   16351                 :          1 :   p23.addGeometry( lp23.clone() );
   16352                 :          1 :   p23.dropMValue();
   16353                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::GeometryCollection );
   16354                 :          1 :   QCOMPARE( p23.geometryN( 0 )->wkbType(), QgsWkbTypes::LineString );
   16355                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.geometryN( 0 ) )->pointN( 0 ), QgsPoint( 1, 2 ) );
   16356                 :          1 :   QCOMPARE( p23.geometryN( 1 )->wkbType(), QgsWkbTypes::LineString );
   16357                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.geometryN( 1 ) )->pointN( 0 ), QgsPoint( 1, 2 ) );
   16358                 :            :   // with zm
   16359                 :          1 :   lp23.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 3, 4 ) << QgsPoint( 11, 12, 13, 14 ) << QgsPoint( 1, 12, 23, 24 ) << QgsPoint( 1, 2, 3, 4 ) );
   16360                 :          1 :   p23.clear();
   16361                 :          1 :   p23.addGeometry( lp23.clone() );
   16362                 :          1 :   p23.addGeometry( lp23.clone() );
   16363                 :          1 :   p23.dropMValue();
   16364                 :          1 :   QCOMPARE( p23.wkbType(), QgsWkbTypes::GeometryCollection );
   16365                 :          1 :   QCOMPARE( p23.geometryN( 0 )->wkbType(), QgsWkbTypes::LineStringZ );
   16366                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.geometryN( 0 ) )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) );
   16367                 :          1 :   QCOMPARE( p23.geometryN( 1 )->wkbType(), QgsWkbTypes::LineStringZ );
   16368                 :          1 :   QCOMPARE( static_cast< const QgsLineString *>( p23.geometryN( 1 ) )->pointN( 0 ), QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) );
   16369                 :            : 
   16370                 :            :   //vertexAngle
   16371                 :          1 :   QgsGeometryCollection p24;
   16372                 :          1 :   ( void )p24.vertexAngle( QgsVertexId() ); //just want no crash
   16373                 :          1 :   ( void )p24.vertexAngle( QgsVertexId( 0, 0, 0 ) ); //just want no crash
   16374                 :          1 :   ( void )p24.vertexAngle( QgsVertexId( 0, 1, 0 ) ); //just want no crash
   16375                 :          1 :   ( void )p24.vertexAngle( QgsVertexId( 1, 0, 0 ) ); //just want no crash
   16376                 :          1 :   ( void )p24.vertexAngle( QgsVertexId( -1, 0, 0 ) ); //just want no crash
   16377                 :          1 :   QgsLineString l38;
   16378                 :          2 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0.5, 0 ) << QgsPoint( 1, 0 )
   16379                 :          1 :                  << QgsPoint( 2, 1 ) << QgsPoint( 1, 2 ) << QgsPoint( 0, 2 ) << QgsPoint( 0, 0 ) );
   16380                 :          1 :   p24.addGeometry( l38.clone() );
   16381                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 2.35619, 0.00001 );
   16382                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 1.5708, 0.0001 );
   16383                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 0, 2 ) ), 1.17809, 0.00001 );
   16384                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 0, 3 ) ), 0.0, 0.00001 );
   16385                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 0, 4 ) ), 5.10509, 0.00001 );
   16386                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 0, 5 ) ), 3.92699, 0.00001 );
   16387                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 0, 0, 6 ) ), 2.35619, 0.00001 );
   16388                 :          1 :   p24.addGeometry( l38.clone() );
   16389                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 1, 0, 0 ) ), 2.35619, 0.00001 );
   16390                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 1, 0, 1 ) ), 1.5708, 0.0001 );
   16391                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 1, 0, 2 ) ), 1.17809, 0.00001 );
   16392                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 1, 0, 3 ) ), 0.0, 0.00001 );
   16393                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 1, 0, 4 ) ), 5.10509, 0.00001 );
   16394                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 1, 0, 5 ) ), 3.92699, 0.00001 );
   16395                 :          1 :   QGSCOMPARENEAR( p24.vertexAngle( QgsVertexId( 1, 0, 6 ) ), 2.35619, 0.00001 );
   16396                 :            : 
   16397                 :            :   //insert vertex
   16398                 :            : 
   16399                 :            :   //insert vertex in empty collection
   16400                 :          1 :   QgsGeometryCollection p25;
   16401                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
   16402                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 6.0, 7.0 ) ) );
   16403                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 1, 0 ), QgsPoint( 6.0, 7.0 ) ) );
   16404                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 1, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
   16405                 :          1 :   QVERIFY( p25.isEmpty() );
   16406                 :          2 :   l38.setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 0.5, 0 ) << QgsPoint( 1, 0 )
   16407                 :          1 :                  << QgsPoint( 2, 1 ) << QgsPoint( 1, 2 ) << QgsPoint( 0, 2 ) << QgsPoint( 0, 0 ) );
   16408                 :          1 :   p25.addGeometry( l38.clone() );
   16409                 :          1 :   QVERIFY( p25.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 0.3, 0 ) ) );
   16410                 :          1 :   QCOMPARE( p25.nCoordinates(), 8 );
   16411                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 0 ) )->pointN( 0 ), QgsPoint( 0, 0 ) );
   16412                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 0 ) )->pointN( 1 ), QgsPoint( 0.3, 0 ) );
   16413                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 0 ) )->pointN( 2 ), QgsPoint( 0.5, 0 ) );
   16414                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 0, -1 ), QgsPoint( 6.0, 7.0 ) ) );
   16415                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 0, 0, 100 ), QgsPoint( 6.0, 7.0 ) ) );
   16416                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 1, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
   16417                 :            :   // first vertex
   16418                 :          1 :   QVERIFY( p25.insertVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 0, 0.1 ) ) );
   16419                 :          1 :   QCOMPARE( p25.nCoordinates(), 9 );
   16420                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 0 ) )->pointN( 0 ), QgsPoint( 0, 0.1 ) );
   16421                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 0 ) )->pointN( 1 ), QgsPoint( 0, 0 ) );
   16422                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 0 ) )->pointN( 2 ), QgsPoint( 0.3, 0 ) );
   16423                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 0 ) )->pointN( 3 ), QgsPoint( 0.5, 0 ) );
   16424                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 0 ) )->pointN( 7 ), QgsPoint( 0, 2 ) );
   16425                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 0 ) )->pointN( 8 ), QgsPoint( 0, 0 ) );
   16426                 :            :   // last vertex
   16427                 :          1 :   QVERIFY( p25.insertVertex( QgsVertexId( 0, 0, 9 ), QgsPoint( 0.1, 0.1 ) ) );
   16428                 :          1 :   QCOMPARE( p25.nCoordinates(), 10 );
   16429                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 0 ) )->pointN( 0 ), QgsPoint( 0, 0.1 ) );
   16430                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 0 ) )->pointN( 1 ), QgsPoint( 0, 0 ) );
   16431                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 0 ) )->pointN( 2 ), QgsPoint( 0.3, 0 ) );
   16432                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 0 ) )->pointN( 3 ), QgsPoint( 0.5, 0 ) );
   16433                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 0 ) )->pointN( 8 ), QgsPoint( 0, 0 ) );
   16434                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 0 ) )->pointN( 9 ), QgsPoint( 0.1, 0.1 ) );
   16435                 :            :   // with second part
   16436                 :          1 :   p25.addGeometry( l38.clone() );
   16437                 :          1 :   QCOMPARE( p25.nCoordinates(), 17 );
   16438                 :          1 :   QVERIFY( p25.insertVertex( QgsVertexId( 1, 0, 1 ), QgsPoint( 0.3, 0 ) ) );
   16439                 :          1 :   QCOMPARE( p25.nCoordinates(), 18 );
   16440                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 1 ) )->pointN( 0 ), QgsPoint( 0, 0 ) );
   16441                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 1 ) )->pointN( 1 ), QgsPoint( 0.3, 0 ) );
   16442                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 1 ) )->pointN( 2 ), QgsPoint( 0.5, 0 ) );
   16443                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 1, 0, -1 ), QgsPoint( 6.0, 7.0 ) ) );
   16444                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 1, 0, 100 ), QgsPoint( 6.0, 7.0 ) ) );
   16445                 :          1 :   QVERIFY( !p25.insertVertex( QgsVertexId( 2, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
   16446                 :            :   // first vertex in second part
   16447                 :          1 :   QVERIFY( p25.insertVertex( QgsVertexId( 1, 0, 0 ), QgsPoint( 0, 0.1 ) ) );
   16448                 :          1 :   QCOMPARE( p25.nCoordinates(), 19 );
   16449                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 1 ) )->pointN( 0 ), QgsPoint( 0, 0.1 ) );
   16450                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 1 ) )->pointN( 1 ), QgsPoint( 0, 0 ) );
   16451                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 1 ) )->pointN( 2 ), QgsPoint( 0.3, 0 ) );
   16452                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 1 ) )->pointN( 3 ), QgsPoint( 0.5, 0 ) );
   16453                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 1 ) )->pointN( 7 ), QgsPoint( 0, 2 ) );
   16454                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 1 ) )->pointN( 8 ), QgsPoint( 0, 0 ) );
   16455                 :            :   // last vertex in second part
   16456                 :          1 :   QVERIFY( p25.insertVertex( QgsVertexId( 1, 0, 9 ), QgsPoint( 0.1, 0.1 ) ) );
   16457                 :          1 :   QCOMPARE( p25.nCoordinates(), 20 );
   16458                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 1 ) )->pointN( 0 ), QgsPoint( 0, 0.1 ) );
   16459                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 1 ) )->pointN( 1 ), QgsPoint( 0, 0 ) );
   16460                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 1 ) )->pointN( 2 ), QgsPoint( 0.3, 0 ) );
   16461                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 1 ) )->pointN( 3 ), QgsPoint( 0.5, 0 ) );
   16462                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 1 ) )->pointN( 8 ), QgsPoint( 0, 0 ) );
   16463                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p25.geometryN( 1 ) )->pointN( 9 ), QgsPoint( 0.1, 0.1 ) );
   16464                 :            : 
   16465                 :            :   //move vertex
   16466                 :            : 
   16467                 :            :   //empty collection
   16468                 :          1 :   QgsGeometryCollection p26;
   16469                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
   16470                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( -1, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
   16471                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 1, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
   16472                 :          1 :   QVERIFY( p26.isEmpty() );
   16473                 :            : 
   16474                 :            :   //valid collection
   16475                 :          2 :   l38.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
   16476                 :          1 :                  << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) << QgsPoint( 1, 2 ) );
   16477                 :          1 :   p26.addGeometry( l38.clone() );
   16478                 :          1 :   QVERIFY( p26.moveVertex( QgsVertexId( 0, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
   16479                 :          1 :   QVERIFY( p26.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPoint( 16.0, 17.0 ) ) );
   16480                 :          1 :   QVERIFY( p26.moveVertex( QgsVertexId( 0, 0, 2 ), QgsPoint( 26.0, 27.0 ) ) );
   16481                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.geometryN( 0 ) )->pointN( 0 ), QgsPoint( 6.0, 7.0 ) );
   16482                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.geometryN( 0 ) )->pointN( 1 ), QgsPoint( 16.0, 17.0 ) );
   16483                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.geometryN( 0 ) )->pointN( 2 ), QgsPoint( 26.0, 27.0 ) );
   16484                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.geometryN( 0 ) )->pointN( 3 ), QgsPoint( 1, 2 ) );
   16485                 :            : 
   16486                 :            :   //out of range
   16487                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 0, 0, -1 ), QgsPoint( 3.0, 4.0 ) ) );
   16488                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 0, 0, 10 ), QgsPoint( 3.0, 4.0 ) ) );
   16489                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 1, 0, 0 ), QgsPoint( 3.0, 4.0 ) ) );
   16490                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.geometryN( 0 ) )->pointN( 0 ), QgsPoint( 6.0, 7.0 ) );
   16491                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.geometryN( 0 ) )->pointN( 1 ), QgsPoint( 16.0, 17.0 ) );
   16492                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.geometryN( 0 ) )->pointN( 2 ), QgsPoint( 26.0, 27.0 ) );
   16493                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.geometryN( 0 ) )->pointN( 3 ), QgsPoint( 1.0, 2.0 ) );
   16494                 :            : 
   16495                 :            :   // with second part
   16496                 :          1 :   p26.addGeometry( l38.clone() );
   16497                 :          1 :   QVERIFY( p26.moveVertex( QgsVertexId( 1, 0, 0 ), QgsPoint( 6.0, 7.0 ) ) );
   16498                 :          1 :   QVERIFY( p26.moveVertex( QgsVertexId( 1, 0, 1 ), QgsPoint( 16.0, 17.0 ) ) );
   16499                 :          1 :   QVERIFY( p26.moveVertex( QgsVertexId( 1, 0, 2 ), QgsPoint( 26.0, 27.0 ) ) );
   16500                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.geometryN( 1 ) )->pointN( 0 ), QgsPoint( 6.0, 7.0 ) );
   16501                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.geometryN( 1 ) )->pointN( 1 ), QgsPoint( 16.0, 17.0 ) );
   16502                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.geometryN( 1 ) )->pointN( 2 ), QgsPoint( 26.0, 27.0 ) );
   16503                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p26.geometryN( 1 ) )->pointN( 3 ), QgsPoint( 1.0, 2.0 ) );
   16504                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 1, 0, -1 ), QgsPoint( 3.0, 4.0 ) ) );
   16505                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 1, 0, 10 ), QgsPoint( 3.0, 4.0 ) ) );
   16506                 :          1 :   QVERIFY( !p26.moveVertex( QgsVertexId( 2, 0, 0 ), QgsPoint( 3.0, 4.0 ) ) );
   16507                 :            : 
   16508                 :            :   //delete vertex
   16509                 :            : 
   16510                 :            :   //empty collection
   16511                 :          1 :   QgsGeometryCollection p27;
   16512                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
   16513                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 0, 1, 0 ) ) );
   16514                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 1, 1, 0 ) ) );
   16515                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( -1, 1, 0 ) ) );
   16516                 :          1 :   QVERIFY( p27.isEmpty() );
   16517                 :            : 
   16518                 :            :   //valid collection
   16519                 :          2 :   l38.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 5, 2 ) << QgsPoint( 6, 2 ) << QgsPoint( 7, 2 )
   16520                 :          1 :                  << QgsPoint( 11, 12 ) << QgsPoint( 21, 22 ) << QgsPoint( 1, 2 ) );
   16521                 :            : 
   16522                 :          1 :   p27.addGeometry( l38.clone() );
   16523                 :            :   //out of range vertices
   16524                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 0, 0, -1 ) ) );
   16525                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 0, 0, 100 ) ) );
   16526                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 1, 0, 1 ) ) );
   16527                 :            : 
   16528                 :            :   //valid vertices
   16529                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 1 ) ) );
   16530                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 0 ) )->pointN( 0 ), QgsPoint( 1.0, 2.0 ) );
   16531                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 0 ) )->pointN( 1 ), QgsPoint( 6.0, 2.0 ) );
   16532                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 0 ) )->pointN( 2 ), QgsPoint( 7.0, 2.0 ) );
   16533                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 0 ) )->pointN( 3 ), QgsPoint( 11.0, 12.0 ) );
   16534                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 0 ) )->pointN( 5 ), QgsPoint( 1.0, 2.0 ) );
   16535                 :            : 
   16536                 :            :   // delete first vertex
   16537                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
   16538                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 0 ) )->pointN( 0 ), QgsPoint( 6.0, 2.0 ) );
   16539                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 0 ) )->pointN( 1 ), QgsPoint( 7.0, 2.0 ) );
   16540                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 0 ) )->pointN( 2 ), QgsPoint( 11.0, 12.0 ) );
   16541                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 0 ) )->pointN( 3 ), QgsPoint( 21.0, 22.0 ) );
   16542                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 0 ) )->pointN( 4 ), QgsPoint( 1.0, 2.0 ) );
   16543                 :            : 
   16544                 :            :   // delete last vertex
   16545                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 4 ) ) );
   16546                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 0 ) )->pointN( 0 ), QgsPoint( 6.0, 2.0 ) );
   16547                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 0 ) )->pointN( 1 ), QgsPoint( 7.0, 2.0 ) );
   16548                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 0 ) )->pointN( 2 ), QgsPoint( 11.0, 12.0 ) );
   16549                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 0 ) )->pointN( 3 ), QgsPoint( 21.0, 22.0 ) );
   16550                 :            : 
   16551                 :            :   // delete some more vertices - should remove part
   16552                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
   16553                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
   16554                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
   16555                 :          1 :   QVERIFY( !p27.geometryN( 0 ) );
   16556                 :            : 
   16557                 :            :   // with two parts
   16558                 :          1 :   p27.addGeometry( l38.clone() );
   16559                 :          1 :   p27.addGeometry( l38.clone() );
   16560                 :            : 
   16561                 :            :   //out of range vertices
   16562                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 1, 0, -1 ) ) );
   16563                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 1, 0, 100 ) ) );
   16564                 :          1 :   QVERIFY( !p27.deleteVertex( QgsVertexId( 2, 0, 1 ) ) );
   16565                 :            : 
   16566                 :            :   //valid vertices
   16567                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 1, 0, 1 ) ) );
   16568                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 1 ) )->pointN( 0 ), QgsPoint( 1.0, 2.0 ) );
   16569                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 1 ) )->pointN( 1 ), QgsPoint( 6.0, 2.0 ) );
   16570                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 1 ) )->pointN( 2 ), QgsPoint( 7.0, 2.0 ) );
   16571                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 1 ) )->pointN( 3 ), QgsPoint( 11.0, 12.0 ) );
   16572                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 1 ) )->pointN( 5 ), QgsPoint( 1.0, 2.0 ) );
   16573                 :            : 
   16574                 :            :   // delete first vertex
   16575                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 1, 0, 0 ) ) );
   16576                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 1 ) )->pointN( 0 ), QgsPoint( 6.0, 2.0 ) );
   16577                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 1 ) )->pointN( 1 ), QgsPoint( 7.0, 2.0 ) );
   16578                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 1 ) )->pointN( 2 ), QgsPoint( 11.0, 12.0 ) );
   16579                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 1 ) )->pointN( 3 ), QgsPoint( 21.0, 22.0 ) );
   16580                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 1 ) )->pointN( 4 ), QgsPoint( 1.0, 2.0 ) );
   16581                 :            : 
   16582                 :            :   // delete last vertex
   16583                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 1, 0, 4 ) ) );
   16584                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 1 ) )->pointN( 0 ), QgsPoint( 6.0, 2.0 ) );
   16585                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 1 ) )->pointN( 1 ), QgsPoint( 7.0, 2.0 ) );
   16586                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 1 ) )->pointN( 2 ), QgsPoint( 11.0, 12.0 ) );
   16587                 :          1 :   QCOMPARE( static_cast< const QgsLineString * >( p27.geometryN( 1 ) )->pointN( 3 ), QgsPoint( 21.0, 22.0 ) );
   16588                 :            : 
   16589                 :            :   // delete some more vertices - should remove part
   16590                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 1, 0, 1 ) ) );
   16591                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 1, 0, 1 ) ) );
   16592                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 1, 0, 1 ) ) );
   16593                 :          1 :   QCOMPARE( p27.numGeometries(), 1 );
   16594                 :          1 :   QVERIFY( p27.geometryN( 0 ) );
   16595                 :            : 
   16596                 :            :   // test that second geometry is "promoted" when first is removed
   16597                 :          1 :   p27.addGeometry( l38.clone() );
   16598                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
   16599                 :          1 :   QCOMPARE( p27.numGeometries(), 2 );
   16600                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
   16601                 :          1 :   QCOMPARE( p27.numGeometries(), 2 );
   16602                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
   16603                 :          1 :   QCOMPARE( p27.numGeometries(), 2 );
   16604                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
   16605                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
   16606                 :          1 :   QVERIFY( p27.deleteVertex( QgsVertexId( 0, 0, 0 ) ) );
   16607                 :          1 :   QCOMPARE( p27.numGeometries(), 1 );
   16608                 :          1 :   QVERIFY( p27.geometryN( 0 ) );
   16609                 :            : 
   16610                 :            :   //boundary
   16611                 :            : 
   16612                 :            :   // collections have no boundary defined
   16613                 :          1 :   QgsGeometryCollection boundaryCollection;
   16614                 :          1 :   QVERIFY( !boundaryCollection.boundary() );
   16615                 :            :   // add a geometry and retest, should still be undefined
   16616                 :          1 :   QgsLineString *lineBoundary = new QgsLineString();
   16617                 :          1 :   lineBoundary->setPoints( QgsPointSequence() << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) );
   16618                 :          1 :   boundaryCollection.addGeometry( lineBoundary );
   16619                 :          1 :   QVERIFY( !boundaryCollection.boundary() );
   16620                 :            : 
   16621                 :            :   // segmentize
   16622                 :          1 :   QgsGeometryCollection segmentC;
   16623                 :          1 :   QgsCircularString toSegment;
   16624                 :          2 :   toSegment.setPoints( QgsPointSequence() << QgsPoint( 1, 2 )
   16625                 :          1 :                        << QgsPoint( 11, 10 ) << QgsPoint( 21, 2 ) );
   16626                 :          1 :   segmentC.addGeometry( toSegment.clone() );
   16627                 :          1 :   std::unique_ptr<QgsGeometryCollection> segmentized( static_cast< QgsGeometryCollection * >( segmentC.segmentize() ) );
   16628                 :          1 :   const QgsLineString *segmentizedLine = static_cast< const QgsLineString * >( segmentized->geometryN( 0 ) );
   16629                 :          1 :   QCOMPARE( segmentizedLine->numPoints(), 156 );
   16630                 :          1 :   QCOMPARE( segmentizedLine->vertexCount(), 156 );
   16631                 :          1 :   QCOMPARE( segmentizedLine->ringCount(), 1 );
   16632                 :          1 :   QCOMPARE( segmentizedLine->partCount(), 1 );
   16633                 :          1 :   QCOMPARE( segmentizedLine->wkbType(), QgsWkbTypes::LineString );
   16634                 :          1 :   QVERIFY( !segmentizedLine->is3D() );
   16635                 :          1 :   QVERIFY( !segmentizedLine->isMeasure() );
   16636                 :          1 :   QCOMPARE( segmentizedLine->pointN( 0 ), toSegment.pointN( 0 ) );
   16637                 :          1 :   QCOMPARE( segmentizedLine->pointN( segmentizedLine->numPoints() - 1 ), toSegment.pointN( toSegment.numPoints() - 1 ) );
   16638                 :            : 
   16639                 :            :   // hasCurvedSegments
   16640                 :          1 :   QgsGeometryCollection c30;
   16641                 :          1 :   QVERIFY( !c30.hasCurvedSegments() );
   16642                 :          1 :   c30.addGeometry( part.clone() );
   16643                 :          1 :   QVERIFY( !c30.hasCurvedSegments() );
   16644                 :          1 :   c30.addGeometry( toSegment.clone() );
   16645                 :          1 :   QVERIFY( c30.hasCurvedSegments() );
   16646                 :            : 
   16647                 :            : 
   16648                 :            :   //adjacent vertices
   16649                 :          1 :   QgsGeometryCollection c31;
   16650                 :          1 :   QgsLineString vertexLine1;
   16651                 :          1 :   QgsVertexId prev( 1, 2, 3 ); // start with something
   16652                 :          1 :   QgsVertexId next( 4, 5, 6 );
   16653                 :          1 :   c31.adjacentVertices( QgsVertexId( 0, 0, -1 ), prev, next );
   16654                 :          1 :   QCOMPARE( prev, QgsVertexId() );
   16655                 :          1 :   QCOMPARE( next, QgsVertexId() );
   16656                 :          1 :   c31.adjacentVertices( QgsVertexId( -1, 0, -1 ), prev, next );
   16657                 :          1 :   QCOMPARE( prev, QgsVertexId() );
   16658                 :          1 :   QCOMPARE( next, QgsVertexId() );
   16659                 :          1 :   c31.adjacentVertices( QgsVertexId( 10, 0, -1 ), prev, next );
   16660                 :          1 :   QCOMPARE( prev, QgsVertexId() );
   16661                 :          1 :   QCOMPARE( next, QgsVertexId() );
   16662                 :          1 :   vertexLine1.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 111, 112 ) );
   16663                 :          1 :   c31.addGeometry( vertexLine1.clone() );
   16664                 :          1 :   c31.addGeometry( vertexLine1.clone() );
   16665                 :          1 :   c31.adjacentVertices( QgsVertexId( -1, 0, -1 ), prev, next );
   16666                 :          1 :   QCOMPARE( prev, QgsVertexId() );
   16667                 :          1 :   QCOMPARE( next, QgsVertexId() );
   16668                 :          1 :   c31.adjacentVertices( QgsVertexId( 10, 0, -1 ), prev, next );
   16669                 :          1 :   QCOMPARE( prev, QgsVertexId() );
   16670                 :          1 :   QCOMPARE( next, QgsVertexId() );
   16671                 :          1 :   c31.adjacentVertices( QgsVertexId( 0, 0, 0 ), prev, next );
   16672                 :          1 :   QCOMPARE( prev, QgsVertexId() );
   16673                 :          1 :   QCOMPARE( next, QgsVertexId( 0, 0, 1 ) );
   16674                 :          1 :   c31.adjacentVertices( QgsVertexId( 0, 0, 1 ), prev, next );
   16675                 :          1 :   QCOMPARE( prev, QgsVertexId( 0, 0, 0 ) );
   16676                 :          1 :   QCOMPARE( next, QgsVertexId( 0, 0, 2 ) );
   16677                 :          1 :   c31.adjacentVertices( QgsVertexId( 1, 0, 1 ), prev, next );
   16678                 :          1 :   QCOMPARE( prev, QgsVertexId( 1, 0, 0 ) );
   16679                 :          1 :   QCOMPARE( next, QgsVertexId( 1, 0, 2 ) );
   16680                 :            : 
   16681                 :            : 
   16682                 :            :   // vertex number
   16683                 :          1 :   QgsGeometryCollection c32;
   16684                 :          1 :   QgsLineString vertexLine2;
   16685                 :          1 :   vertexLine2.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 111, 112 ) );
   16686                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( -1, 0, 0 ) ), -1 );
   16687                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 1, 0, 0 ) ), -1 );
   16688                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 0, -1, 0 ) ), -1 );
   16689                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 0, 1, 0 ) ), -1 );
   16690                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 0, 0, -1 ) ), -1 );
   16691                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 0, 0, 0 ) ), -1 );
   16692                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 0, 0, 1 ) ), -1 );
   16693                 :          1 :   c32.addGeometry( vertexLine2.clone() );
   16694                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( -1, 0, 0 ) ), -1 );
   16695                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 1, 0, 0 ) ), -1 );
   16696                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 0, -1, 0 ) ), -1 );
   16697                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 0, 1, 0 ) ), -1 );
   16698                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 0, 0, -1 ) ), -1 );
   16699                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 0, 0, 0 ) ), 0 );
   16700                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 0, 0, 1 ) ), 1 );
   16701                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 0, 0, 2 ) ), 2 );
   16702                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 0, 0, 3 ) ), -1 );
   16703                 :          1 :   c32.addGeometry( vertexLine2.clone() );
   16704                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 0, 0, 0 ) ), 0 );
   16705                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 0, 0, 1 ) ), 1 );
   16706                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 0, 0, 2 ) ), 2 );
   16707                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 0, 0, 3 ) ), -1 );
   16708                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 1, 0, 0 ) ), 3 );
   16709                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 1, 0, 1 ) ), 4 );
   16710                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 1, 0, 2 ) ), 5 );
   16711                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 1, 0, 3 ) ), -1 );
   16712                 :          1 :   QgsPolygon polyPart;
   16713                 :          1 :   vertexLine2.close();
   16714                 :          1 :   polyPart.setExteriorRing( vertexLine2.clone() );
   16715                 :          1 :   c32.addGeometry( polyPart.clone() );
   16716                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 0, 0, 0 ) ), 0 );
   16717                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 0, 0, 1 ) ), 1 );
   16718                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 0, 0, 2 ) ), 2 );
   16719                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 0, 0, 3 ) ), -1 );
   16720                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 1, 0, 0 ) ), 3 );
   16721                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 1, 0, 1 ) ), 4 );
   16722                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 1, 0, 2 ) ), 5 );
   16723                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 1, 0, 3 ) ), -1 );
   16724                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 2, -1, 0 ) ), -1 );
   16725                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 2, 1, 0 ) ), -1 );
   16726                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 2, 0, -1 ) ), -1 );
   16727                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 2, 0, 0 ) ), 6 );
   16728                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 2, 0, 1 ) ), 7 );
   16729                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 2, 0, 2 ) ), 8 );
   16730                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 2, 0, 3 ) ), 9 );
   16731                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 2, 0, 4 ) ), -1 );
   16732                 :          1 :   polyPart.addInteriorRing( vertexLine2.clone() );
   16733                 :          1 :   c32.addGeometry( polyPart.clone() );
   16734                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 2, 0, 0 ) ), 6 );
   16735                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 2, 0, 1 ) ), 7 );
   16736                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 2, 0, 2 ) ), 8 );
   16737                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 2, 0, 3 ) ), 9 );
   16738                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 2, 0, 4 ) ), -1 );
   16739                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 3, -1, 0 ) ), -1 );
   16740                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 3, 2, 0 ) ), -1 );
   16741                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 3, 0, 0 ) ), 10 );
   16742                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 3, 0, 1 ) ), 11 );
   16743                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 3, 0, 2 ) ), 12 );
   16744                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 3, 0, 3 ) ), 13 );
   16745                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 3, 0, 4 ) ), -1 );
   16746                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 3, 1, 0 ) ), 14 );
   16747                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 3, 1, 1 ) ), 15 );
   16748                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 3, 1, 2 ) ), 16 );
   16749                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 3, 1, 3 ) ), 17 );
   16750                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 3, 1, 4 ) ), -1 );
   16751                 :          1 :   QCOMPARE( c32.vertexNumberFromVertexId( QgsVertexId( 3, 2, 0 ) ), -1 );
   16752                 :            : 
   16753                 :            : 
   16754                 :            :   //removeDuplicateNodes
   16755                 :          1 :   QgsGeometryCollection gcNodes;
   16756                 :          1 :   QgsLineString nodeLine;
   16757                 :          1 :   QVERIFY( !gcNodes.removeDuplicateNodes() );
   16758                 :          1 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11, 12 ) << QgsPoint( 111, 12 ) );
   16759                 :          1 :   gcNodes.addGeometry( nodeLine.clone() );
   16760                 :          1 :   QVERIFY( !gcNodes.removeDuplicateNodes( 0.02 ) );
   16761                 :          2 :   QCOMPARE( gcNodes.asWkt(), QStringLiteral( "GeometryCollection (LineString (11 2, 11 12, 111 12))" ) );
   16762                 :          2 :   nodeLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2 ) << QgsPoint( 11.01, 1.99 ) << QgsPoint( 11.02, 2.01 )
   16763                 :          1 :                       << QgsPoint( 11, 12 ) << QgsPoint( 111, 12 ) << QgsPoint( 111.01, 11.99 ) );
   16764                 :          1 :   gcNodes.addGeometry( nodeLine.clone() );
   16765                 :          1 :   QVERIFY( gcNodes.removeDuplicateNodes( 0.02 ) );
   16766                 :          1 :   QVERIFY( !gcNodes.removeDuplicateNodes( 0.02 ) );
   16767                 :          2 :   QCOMPARE( gcNodes.asWkt( 2 ), QStringLiteral( "GeometryCollection (LineString (11 2, 11 12, 111 12),LineString (11 2, 11 12, 111 12))" ) );
   16768                 :            : 
   16769                 :            :   //swapXy
   16770                 :          1 :   QgsGeometryCollection swapCollect;
   16771                 :          1 :   QgsLineString swapLine;
   16772                 :          1 :   swapCollect.swapXy(); // no crash
   16773                 :          1 :   swapLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 11, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 111, 12, 23, 24, QgsWkbTypes::PointZM ) );
   16774                 :          1 :   swapCollect.addGeometry( swapLine.clone() );
   16775                 :          1 :   swapCollect.swapXy();
   16776                 :          2 :   QCOMPARE( swapCollect.asWkt(), QStringLiteral( "GeometryCollection (LineStringZM (2 11 3 4, 12 11 13 14, 12 111 23 24))" ) );
   16777                 :          1 :   swapLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 5, 6, QgsWkbTypes::PointZM ) << QgsPoint( 11.01, 1.99, 15, 16, QgsWkbTypes::PointZM ) << QgsPoint( 11.02, 2.01, 25, 26, QgsWkbTypes::PointZM ) );
   16778                 :          1 :   swapCollect.addGeometry( swapLine.clone() );
   16779                 :          1 :   swapCollect.swapXy();
   16780                 :          2 :   QCOMPARE( swapCollect.asWkt( 2 ), QStringLiteral( "GeometryCollection (LineStringZM (11 2 3 4, 11 12 13 14, 111 12 23 24),LineStringZM (2 11 5 6, 1.99 11.01 15 16, 2.01 11.02 25 26))" ) );
   16781                 :            : 
   16782                 :            :   // filter vertices
   16783                 :          1 :   QgsGeometryCollection filterCollect;
   16784                 :          8 :   auto filter = []( const QgsPoint & point )-> bool
   16785                 :            :   {
   16786                 :          8 :     return point.x() > 5;
   16787                 :            :   };
   16788                 :          1 :   QgsLineString filterLine;
   16789                 :          1 :   filterCollect.filterVertices( filter ); // no crash
   16790                 :          1 :   filterLine.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 11, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 111, 12, 23, 24, QgsWkbTypes::PointZM ) );
   16791                 :          1 :   filterCollect.addGeometry( filterLine.clone() );
   16792                 :          1 :   filterCollect.filterVertices( filter );
   16793                 :          2 :   QCOMPARE( filterCollect.asWkt(), QStringLiteral( "GeometryCollection (LineStringZM (11 12 13 14, 111 12 23 24))" ) );
   16794                 :          1 :   filterLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 5, 6, QgsWkbTypes::PointZM ) << QgsPoint( 1.01, 1.99, 15, 16, QgsWkbTypes::PointZM ) << QgsPoint( 11.02, 2.01, 25, 26, QgsWkbTypes::PointZM ) );
   16795                 :          1 :   filterCollect.addGeometry( filterLine.clone() );
   16796                 :          1 :   filterCollect.filterVertices( filter );
   16797                 :          2 :   QCOMPARE( filterCollect.asWkt( 2 ), QStringLiteral( "GeometryCollection (LineStringZM (11 12 13 14, 111 12 23 24),LineStringZM (11 2 5 6, 11.02 2.01 25 26))" ) );
   16798                 :            : 
   16799                 :            :   // transform vertices
   16800                 :          1 :   QgsGeometryCollection transformCollect;
   16801                 :          9 :   auto transform = []( const QgsPoint & point )-> QgsPoint
   16802                 :            :   {
   16803                 :          9 :     return QgsPoint( point.x() + 2, point.y() + 3, point.z() + 4, point.m() + 5 );
   16804                 :            :   };
   16805                 :          1 :   QgsLineString transformLine;
   16806                 :          1 :   transformCollect.transformVertices( transform ); // no crash
   16807                 :          1 :   transformLine.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 11, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 111, 12, 23, 24, QgsWkbTypes::PointZM ) );
   16808                 :          1 :   transformCollect.addGeometry( transformLine.clone() );
   16809                 :          1 :   transformCollect.transformVertices( transform );
   16810                 :          2 :   QCOMPARE( transformCollect.asWkt(), QStringLiteral( "GeometryCollection (LineStringZM (3 5 7 9, 13 15 17 19, 113 15 27 29))" ) );
   16811                 :          1 :   transformLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 5, 6, QgsWkbTypes::PointZM ) << QgsPoint( 1.01, 1.99, 15, 16, QgsWkbTypes::PointZM ) << QgsPoint( 11.02, 2.01, 25, 26, QgsWkbTypes::PointZM ) );
   16812                 :          1 :   transformCollect.addGeometry( transformLine.clone() );
   16813                 :          1 :   transformCollect.transformVertices( transform );
   16814                 :          2 :   QCOMPARE( transformCollect.asWkt( 2 ), QStringLiteral( "GeometryCollection (LineStringZM (5 8 11 14, 15 18 21 24, 115 18 31 34),LineStringZM (13 5 9 11, 3.01 4.99 19 21, 13.02 5.01 29 31))" ) );
   16815                 :            : 
   16816                 :            :   // transform using class
   16817                 :          1 :   TestTransformer transformer;
   16818                 :          1 :   QgsGeometryCollection transformCollect2;
   16819                 :          1 :   transformCollect2.transform( &transformer ); // no crash
   16820                 :          1 :   transformLine.setPoints( QgsPointSequence() << QgsPoint( 1, 2, 3, 4, QgsWkbTypes::PointZM ) << QgsPoint( 11, 12, 13, 14, QgsWkbTypes::PointZM ) << QgsPoint( 111, 12, 23, 24, QgsWkbTypes::PointZM ) );
   16821                 :          1 :   transformCollect2.addGeometry( transformLine.clone() );
   16822                 :          1 :   QVERIFY( transformCollect2.transform( &transformer ) );
   16823                 :          2 :   QCOMPARE( transformCollect2.asWkt(), QStringLiteral( "GeometryCollection (LineStringZM (3 16 8 3, 33 26 18 13, 333 26 28 23))" ) );
   16824                 :          1 :   transformLine.setPoints( QgsPointSequence() << QgsPoint( 11, 2, 5, 6, QgsWkbTypes::PointZM ) << QgsPoint( 1.01, 1.99, 15, 16, QgsWkbTypes::PointZM ) << QgsPoint( 11.02, 2.01, 25, 26, QgsWkbTypes::PointZM ) );
   16825                 :          1 :   transformCollect2.addGeometry( transformLine.clone() );
   16826                 :          1 :   QVERIFY( transformCollect2.transform( &transformer ) );
   16827                 :          2 :   QCOMPARE( transformCollect2.asWkt( 2 ), QStringLiteral( "GeometryCollection (LineStringZM (9 30 13 2, 99 40 23 12, 999 40 33 22),LineStringZM (33 16 10 5, 3.03 15.99 20 15, 33.06 16.01 30 25))" ) );
   16828                 :            : 
   16829                 :          1 :   TestFailTransformer failTransformer;
   16830                 :          1 :   QVERIFY( !transformCollect2.transform( &failTransformer ) );
   16831                 :          1 : }
   16832                 :            : 
   16833                 :          1 : void TestQgsGeometry::fromQgsPointXY()
   16834                 :            : {
   16835                 :          1 :   QgsPointXY point( 1.0, 2.0 );
   16836                 :          1 :   QgsGeometry result( QgsGeometry::fromPointXY( point ) );
   16837                 :          1 :   QCOMPARE( result.wkbType(), QgsWkbTypes::Point );
   16838                 :          1 :   QgsPointXY resultPoint = result.asPoint();
   16839                 :          1 :   QCOMPARE( resultPoint, point );
   16840                 :          1 : }
   16841                 :            : 
   16842                 :          1 : void TestQgsGeometry::fromQPoint()
   16843                 :            : {
   16844                 :          1 :   QPointF point( 1.0, 2.0 );
   16845                 :          1 :   QgsGeometry result( QgsGeometry::fromQPointF( point ) );
   16846                 :          1 :   QCOMPARE( result.wkbType(), QgsWkbTypes::Point );
   16847                 :          1 :   QgsPointXY resultPoint = result.asPoint();
   16848                 :          1 :   QCOMPARE( resultPoint.x(), 1.0 );
   16849                 :          1 :   QCOMPARE( resultPoint.y(), 2.0 );
   16850                 :          1 : }
   16851                 :            : 
   16852                 :          1 : void TestQgsGeometry::fromQPolygonF()
   16853                 :            : {
   16854                 :            :   //test with a polyline
   16855                 :          1 :   QPolygonF polyline;
   16856                 :          1 :   polyline << QPointF( 1.0, 2.0 ) << QPointF( 4.0, 6.0 ) << QPointF( 4.0, 3.0 ) << QPointF( 2.0, 2.0 );
   16857                 :          1 :   QgsGeometry result( QgsGeometry::fromQPolygonF( polyline ) );
   16858                 :          1 :   QCOMPARE( result.wkbType(), QgsWkbTypes::LineString );
   16859                 :          1 :   QgsPolylineXY resultLine = result.asPolyline();
   16860                 :          1 :   QCOMPARE( resultLine.size(), 4 );
   16861                 :          1 :   QCOMPARE( resultLine.at( 0 ), QgsPointXY( 1.0, 2.0 ) );
   16862                 :          1 :   QCOMPARE( resultLine.at( 1 ), QgsPointXY( 4.0, 6.0 ) );
   16863                 :          1 :   QCOMPARE( resultLine.at( 2 ), QgsPointXY( 4.0, 3.0 ) );
   16864                 :          1 :   QCOMPARE( resultLine.at( 3 ), QgsPointXY( 2.0, 2.0 ) );
   16865                 :            : 
   16866                 :            :   //test with a closed polygon
   16867                 :          1 :   QPolygonF polygon;
   16868                 :          1 :   polygon << QPointF( 1.0, 2.0 ) << QPointF( 4.0, 6.0 ) << QPointF( 4.0, 3.0 ) << QPointF( 2.0, 2.0 ) << QPointF( 1.0, 2.0 );
   16869                 :          1 :   QgsGeometry result2( QgsGeometry::fromQPolygonF( polygon ) );
   16870                 :          1 :   QCOMPARE( result2.wkbType(), QgsWkbTypes::Polygon );
   16871                 :          1 :   QgsPolygonXY resultPolygon = result2.asPolygon();
   16872                 :          1 :   QCOMPARE( resultPolygon.size(), 1 );
   16873                 :          1 :   QCOMPARE( resultPolygon.at( 0 ).at( 0 ), QgsPointXY( 1.0, 2.0 ) );
   16874                 :          1 :   QCOMPARE( resultPolygon.at( 0 ).at( 1 ), QgsPointXY( 4.0, 6.0 ) );
   16875                 :          1 :   QCOMPARE( resultPolygon.at( 0 ).at( 2 ), QgsPointXY( 4.0, 3.0 ) );
   16876                 :          1 :   QCOMPARE( resultPolygon.at( 0 ).at( 3 ), QgsPointXY( 2.0, 2.0 ) );
   16877                 :          1 :   QCOMPARE( resultPolygon.at( 0 ).at( 4 ), QgsPointXY( 1.0, 2.0 ) );
   16878                 :          1 : }
   16879                 :            : 
   16880                 :          1 : void TestQgsGeometry::fromPolyline()
   16881                 :            : {
   16882                 :          1 :   QgsPolyline polyline;
   16883                 :          1 :   QgsGeometry fromPolyline = QgsGeometry::fromPolyline( polyline );
   16884                 :          1 :   QVERIFY( fromPolyline.isEmpty() );
   16885                 :          1 :   QCOMPARE( fromPolyline.wkbType(), QgsWkbTypes::LineString );
   16886                 :          1 :   polyline << QgsPoint( 10, 20 ) << QgsPoint( 30, 40 );
   16887                 :          1 :   fromPolyline = QgsGeometry::fromPolyline( polyline );
   16888                 :          2 :   QCOMPARE( fromPolyline.asWkt(), QStringLiteral( "LineString (10 20, 30 40)" ) );
   16889                 :          1 :   QgsPolyline polyline3d;
   16890                 :          1 :   polyline3d << QgsPoint( QgsWkbTypes::PointZ, 10, 20, 100 ) << QgsPoint( QgsWkbTypes::PointZ, 30, 40, 200 );
   16891                 :          1 :   fromPolyline = QgsGeometry::fromPolyline( polyline3d );
   16892                 :          2 :   QCOMPARE( fromPolyline.asWkt(), QStringLiteral( "LineStringZ (10 20 100, 30 40 200)" ) );
   16893                 :          1 :   QgsPolyline polylineM;
   16894                 :          1 :   polylineM << QgsPoint( QgsWkbTypes::PointM, 10, 20, 0, 100 ) << QgsPoint( QgsWkbTypes::PointM, 30, 40, 0, 200 );
   16895                 :          1 :   fromPolyline = QgsGeometry::fromPolyline( polylineM );
   16896                 :          2 :   QCOMPARE( fromPolyline.asWkt(), QStringLiteral( "LineStringM (10 20 100, 30 40 200)" ) );
   16897                 :          1 :   QgsPolyline polylineZM;
   16898                 :          1 :   polylineZM << QgsPoint( QgsWkbTypes::PointZM, 10, 20, 4, 100 ) << QgsPoint( QgsWkbTypes::PointZM, 30, 40, 5, 200 );
   16899                 :          1 :   fromPolyline = QgsGeometry::fromPolyline( polylineZM );
   16900                 :          2 :   QCOMPARE( fromPolyline.asWkt(), QStringLiteral( "LineStringZM (10 20 4 100, 30 40 5 200)" ) );
   16901                 :          1 : }
   16902                 :            : 
   16903                 :          1 : void TestQgsGeometry::asQPointF()
   16904                 :            : {
   16905                 :          1 :   QPointF point( 1.0, 2.0 );
   16906                 :          1 :   QgsGeometry geom( QgsGeometry::fromQPointF( point ) );
   16907                 :          1 :   QPointF resultPoint = geom.asQPointF();
   16908                 :          1 :   QCOMPARE( resultPoint, point );
   16909                 :            : 
   16910                 :            :   //non point geom
   16911                 :          1 :   QPointF badPoint = mpPolygonGeometryA.asQPointF();
   16912                 :          1 :   QVERIFY( badPoint.isNull() );
   16913                 :          1 : }
   16914                 :            : 
   16915                 :          1 : void TestQgsGeometry::asQPolygonF()
   16916                 :            : {
   16917                 :          1 :   QgsPointXY point1 = QgsPointXY( 20.0, 20.0 );
   16918                 :          1 :   QgsPointXY point2 = QgsPointXY( 80.0, 20.0 );
   16919                 :          1 :   QgsPointXY point3 = QgsPointXY( 80.0, 80.0 );
   16920                 :          1 :   QgsPointXY point4 = QgsPointXY( 20.0, 80.0 );
   16921                 :            : 
   16922                 :          1 :   QgsGeometry polygonGeometryA = QgsGeometry::fromPolygonXY( QgsPolygonXY() << ( QgsPolylineXY() << point1 << point2 << point3 << point4 << point1 ) );
   16923                 :            : 
   16924                 :            :   //test polygon
   16925                 :          1 :   QPolygonF fromPoly = polygonGeometryA.asQPolygonF();
   16926                 :          1 :   QVERIFY( fromPoly.isClosed() );
   16927                 :          1 :   QCOMPARE( fromPoly.size(), 5 );
   16928                 :          1 :   QCOMPARE( fromPoly.at( 0 ).x(), point1.x() );
   16929                 :          1 :   QCOMPARE( fromPoly.at( 0 ).y(), point1.y() );
   16930                 :          1 :   QCOMPARE( fromPoly.at( 1 ).x(), point2.x() );
   16931                 :          1 :   QCOMPARE( fromPoly.at( 1 ).y(), point2.y() );
   16932                 :          1 :   QCOMPARE( fromPoly.at( 2 ).x(), point3.x() );
   16933                 :          1 :   QCOMPARE( fromPoly.at( 2 ).y(), point3.y() );
   16934                 :          1 :   QCOMPARE( fromPoly.at( 3 ).x(), point4.x() );
   16935                 :          1 :   QCOMPARE( fromPoly.at( 3 ).y(), point4.y() );
   16936                 :          1 :   QCOMPARE( fromPoly.at( 4 ).x(), point1.x() );
   16937                 :          1 :   QCOMPARE( fromPoly.at( 4 ).y(), point1.y() );
   16938                 :            : 
   16939                 :            :   //test polyline
   16940                 :          1 :   QgsPolylineXY testline;
   16941                 :          1 :   testline << point1 << point2 << point3;
   16942                 :          1 :   QgsGeometry lineGeom( QgsGeometry::fromPolylineXY( testline ) );
   16943                 :          1 :   QPolygonF fromLine = lineGeom.asQPolygonF();
   16944                 :          1 :   QVERIFY( !fromLine.isClosed() );
   16945                 :          1 :   QCOMPARE( fromLine.size(), 3 );
   16946                 :          1 :   QCOMPARE( fromLine.at( 0 ).x(), point1.x() );
   16947                 :          1 :   QCOMPARE( fromLine.at( 0 ).y(), point1.y() );
   16948                 :          1 :   QCOMPARE( fromLine.at( 1 ).x(), point2.x() );
   16949                 :          1 :   QCOMPARE( fromLine.at( 1 ).y(), point2.y() );
   16950                 :          1 :   QCOMPARE( fromLine.at( 2 ).x(), point3.x() );
   16951                 :          1 :   QCOMPARE( fromLine.at( 2 ).y(), point3.y() );
   16952                 :            : 
   16953                 :            :   //test a bad geometry
   16954                 :          1 :   QgsGeometry badGeom( QgsGeometry::fromPointXY( point1 ) );
   16955                 :          1 :   QPolygonF fromBad = badGeom.asQPolygonF();
   16956                 :          1 :   QVERIFY( fromBad.isEmpty() );
   16957                 :            : 
   16958                 :            :   // test a multipolygon
   16959                 :          2 :   QPolygonF res = QgsGeometry::fromWkt( QStringLiteral( "MultiPolygon (((0 0, 10 0, 10 10, 0 10, 0 0 )),((2 2, 4 2, 4 4, 2 4, 2 2)))" ) ).asQPolygonF();
   16960                 :          1 :   QVERIFY( res.isClosed() );
   16961                 :          1 :   QCOMPARE( res.size(), 5 );
   16962                 :          1 :   QCOMPARE( res.at( 0 ).x(), 0.0 );
   16963                 :          1 :   QCOMPARE( res.at( 0 ).y(), 0.0 );
   16964                 :          1 :   QCOMPARE( res.at( 1 ).x(), 10.0 );
   16965                 :          1 :   QCOMPARE( res.at( 1 ).y(), 0.0 );
   16966                 :          1 :   QCOMPARE( res.at( 2 ).x(), 10.0 );
   16967                 :          1 :   QCOMPARE( res.at( 2 ).y(), 10.0 );
   16968                 :          1 :   QCOMPARE( res.at( 3 ).x(), 0.0 );
   16969                 :          1 :   QCOMPARE( res.at( 3 ).y(), 10.0 );
   16970                 :          1 :   QCOMPARE( res.at( 4 ).x(), 0.0 );
   16971                 :          1 :   QCOMPARE( res.at( 4 ).y(), 0.0 );
   16972                 :            : 
   16973                 :            :   // test a multilinestring
   16974                 :          2 :   res = QgsGeometry::fromWkt( QStringLiteral( "MultiLineString((0 0, 10 0, 10 10, 0 10 ),(2 2, 4 2, 4 4, 2 4))" ) ).asQPolygonF();
   16975                 :          1 :   QVERIFY( !res.isClosed() );
   16976                 :          1 :   QCOMPARE( res.size(), 4 );
   16977                 :          1 :   QCOMPARE( res.at( 0 ).x(), 0.0 );
   16978                 :          1 :   QCOMPARE( res.at( 0 ).y(), 0.0 );
   16979                 :          1 :   QCOMPARE( res.at( 1 ).x(), 10.0 );
   16980                 :          1 :   QCOMPARE( res.at( 1 ).y(), 0.0 );
   16981                 :          1 :   QCOMPARE( res.at( 2 ).x(), 10.0 );
   16982                 :          1 :   QCOMPARE( res.at( 2 ).y(), 10.0 );
   16983                 :          1 :   QCOMPARE( res.at( 3 ).x(), 0.0 );
   16984                 :          1 :   QCOMPARE( res.at( 3 ).y(), 10.0 );
   16985                 :          1 : }
   16986                 :            : 
   16987                 :          1 : void TestQgsGeometry::comparePolylines()
   16988                 :            : {
   16989                 :          1 :   QgsPointXY point1 = QgsPointXY( 20.0, 20.0 );
   16990                 :          1 :   QgsPointXY point2 = QgsPointXY( 80.0, 20.0 );
   16991                 :          1 :   QgsPointXY point3 = QgsPointXY( 80.0, 80.0 );
   16992                 :          1 :   QgsPointXY point4 = QgsPointXY( 20.0, 80.0 );
   16993                 :          1 :   QgsPointXY pointA = QgsPointXY( 40.0, 40.0 );
   16994                 :            : 
   16995                 :          1 :   QgsPolylineXY line1;
   16996                 :          1 :   line1 << point1 << point2 << point3;
   16997                 :          1 :   QgsPolylineXY line2;
   16998                 :          1 :   line2 << point1 << point2 << point3;
   16999                 :          1 :   QVERIFY( QgsGeometry::compare( line1, line2 ) );
   17000                 :            : 
   17001                 :            :   //different number of nodes
   17002                 :          1 :   QgsPolylineXY line3;
   17003                 :          1 :   line3 << point1 << point2 << point3 << point4;
   17004                 :          1 :   QVERIFY( !QgsGeometry::compare( line1, line3 ) );
   17005                 :            : 
   17006                 :            :   //different nodes
   17007                 :          1 :   QgsPolylineXY line4;
   17008                 :          1 :   line3 << point1 << pointA << point3 << point4;
   17009                 :          1 :   QVERIFY( !QgsGeometry::compare( line3, line4 ) );
   17010                 :          1 : }
   17011                 :            : 
   17012                 :          1 : void TestQgsGeometry::comparePolygons()
   17013                 :            : {
   17014                 :          1 :   QgsPointXY point1 = QgsPointXY( 20.0, 20.0 );
   17015                 :          1 :   QgsPointXY point2 = QgsPointXY( 80.0, 20.0 );
   17016                 :          1 :   QgsPointXY point3 = QgsPointXY( 80.0, 80.0 );
   17017                 :          1 :   QgsPointXY point4 = QgsPointXY( 20.0, 80.0 );
   17018                 :          1 :   QgsPointXY pointA = QgsPointXY( 40.0, 40.0 );
   17019                 :          1 :   QgsPointXY pointB = QgsPointXY( 100.0, 40.0 );
   17020                 :            : 
   17021                 :          1 :   QgsPolylineXY ring1;
   17022                 :          1 :   ring1 << point1 << point2 << point3 << point1;
   17023                 :          1 :   QgsPolylineXY ring2;
   17024                 :          1 :   ring2 << point4 << pointA << pointB << point4;
   17025                 :          1 :   QgsPolygonXY poly1;
   17026                 :          1 :   poly1 << ring1 << ring2;
   17027                 :          1 :   QgsPolygonXY poly2;
   17028                 :          1 :   poly2 << ring1 << ring2;
   17029                 :          1 :   QVERIFY( QgsGeometry::compare( poly1, poly2 ) );
   17030                 :            : 
   17031                 :            :   //different number of rings
   17032                 :          1 :   QgsPolygonXY poly3;
   17033                 :          1 :   poly3 << ring1;
   17034                 :          1 :   QVERIFY( !QgsGeometry::compare( poly1, poly3 ) );
   17035                 :            : 
   17036                 :            :   //different rings
   17037                 :          1 :   QgsPolygonXY poly4;
   17038                 :          1 :   poly4 << ring2;
   17039                 :          1 :   QVERIFY( !QgsGeometry::compare( poly3, poly4 ) );
   17040                 :          1 : }
   17041                 :            : 
   17042                 :            : #if defined(__clang__) || defined(__GNUG__)
   17043                 :            : #include <cxxabi.h>
   17044                 :            : #include <ctime>
   17045                 :            : 
   17046                 :       1392 : QString generateSpacesString( int numberOfSpace )
   17047                 :            : {
   17048                 :       1392 :   QStringList spaces;
   17049                 :       1392 :   spaces << QString( " " ) << QString( "\t" ) << QString( "\n" ) << QString( "\r" );
   17050                 :            : 
   17051                 :       1392 :   QString ret;
   17052                 :       7872 :   for ( int i = 0; i < numberOfSpace; ++i )
   17053                 :            :   {
   17054                 :       6480 :     int r = rand() % ( spaces.count() );
   17055                 :       6480 :     ret += spaces.at( r );
   17056                 :       6480 :   }
   17057                 :       1392 :   return ret;
   17058                 :       1392 : }
   17059                 :            : 
   17060                 :            : #endif
   17061                 :            : // Helper function (in anonymous namespace to prevent possible link with the extirior)
   17062                 :            : namespace
   17063                 :            : {
   17064                 :            :   template<typename T>
   17065                 :         12 :   inline void testCreateEmptyWithSameType()
   17066                 :            :   {
   17067                 :         12 :     std::unique_ptr<QgsAbstractGeometry> geom { new T() };
   17068                 :         12 :     std::unique_ptr<QgsAbstractGeometry> created { TestQgsGeometry::createEmpty( geom.get() ) };
   17069                 :         12 :     QVERIFY( created->isEmpty() );
   17070                 :            : #if defined(__clang__) || defined(__GNUG__)
   17071                 :         12 :     srand( ( unsigned )time( NULL ) );
   17072                 :            : 
   17073                 :         12 :     const std::type_info  &ti = typeid( T );
   17074                 :            :     int status;
   17075                 :         12 :     char *realname = abi::__cxa_demangle( ti.name(), 0, 0, &status );
   17076                 :            : 
   17077                 :         12 :     QString type = realname;
   17078                 :            : // remove Qgs prefix
   17079                 :         12 :     type = type.right( type.count() - 3 );
   17080                 :         12 :     QStringList extensionZM;
   17081                 :         12 :     extensionZM << QString() << QString( "Z" ) << QString( "M" ) << QString( "ZM" );
   17082                 :         60 :     for ( QString ext : extensionZM )
   17083                 :            :     {
   17084                 :         48 :       QString wkt = type + ext;
   17085                 :         48 :       QString result = wkt + QLatin1String( " EMPTY" );
   17086                 :            : 
   17087                 :         48 :       QStringList emptyStringList;
   17088                 :         48 :       emptyStringList << QString( "EMPTY" ) << QString( "Empty" ) << QString( "empty" ) << QString( "EmptY" ) << QString( "EmPtY" );
   17089                 :        528 :       for ( int i = 0 ; i < 10 ; ++i )
   17090                 :            :       {
   17091                 :        480 :         QString spacesBefore = generateSpacesString( i );
   17092                 :        528 :         QString spacesMiddle = i == 0 ? QStringLiteral( " " ) : generateSpacesString( i );
   17093                 :        480 :         QString spacesAfter = generateSpacesString( i );
   17094                 :       2880 :         for ( int j = 0; j < emptyStringList.count() ; ++j )
   17095                 :            :         {
   17096                 :       2400 :           QString generatedWkt = spacesBefore + wkt + spacesMiddle + emptyStringList.at( j ) + spacesAfter;
   17097                 :            : 
   17098                 :       2400 :           QgsGeometry gWkt = QgsGeometry().fromWkt( generatedWkt );
   17099                 :       2400 :           QVERIFY( gWkt.asWkt().compare( result, Qt::CaseInsensitive ) == 0 );
   17100                 :            : 
   17101                 :       2400 :           QVERIFY( geom->fromWkt( generatedWkt ) );
   17102                 :       2400 :           QVERIFY( geom->asWkt().compare( result, Qt::CaseInsensitive ) == 0 );
   17103                 :       2400 :         }
   17104                 :        480 :       }
   17105                 :         48 :     }
   17106                 :         12 :     free( realname );
   17107                 :            : #endif
   17108                 :            : 
   17109                 :            : 
   17110                 :            :     // Check that it is the correct type
   17111                 :         12 :     QVERIFY( static_cast<T *>( created.get() ) != nullptr );
   17112                 :         12 :   }
   17113                 :            : }
   17114                 :            : 
   17115                 :          1 : void TestQgsGeometry::createEmptyWithSameType()
   17116                 :            : {
   17117                 :          1 :   testCreateEmptyWithSameType<QgsCircularString>();
   17118                 :          1 :   testCreateEmptyWithSameType<QgsCompoundCurve>();
   17119                 :          1 :   testCreateEmptyWithSameType<QgsLineString>();
   17120                 :          1 :   testCreateEmptyWithSameType<QgsGeometryCollection>();
   17121                 :          1 :   testCreateEmptyWithSameType<QgsMultiCurve>();
   17122                 :          1 :   testCreateEmptyWithSameType<QgsMultiLineString>();
   17123                 :          1 :   testCreateEmptyWithSameType<QgsMultiPoint>();
   17124                 :          1 :   testCreateEmptyWithSameType<QgsMultiSurface>();
   17125                 :          1 :   testCreateEmptyWithSameType<QgsPoint>();
   17126                 :          1 :   testCreateEmptyWithSameType<QgsCurvePolygon>();
   17127                 :          1 :   testCreateEmptyWithSameType<QgsPolygon>();
   17128                 :          1 :   testCreateEmptyWithSameType<QgsTriangle>();
   17129                 :          1 : }
   17130                 :            : 
   17131                 :            : 
   17132                 :            : // MK, Disabled 14.11.2014
   17133                 :            : // Too unclear what exactly should be tested and which variations are allowed for the line
   17134                 :            : #if 0
   17135                 :            : void TestQgsGeometry::simplifyCheck1()
   17136                 :            : {
   17137                 :            :   initPainterTest();
   17138                 :            :   QVERIFY( mpPolylineGeometryD->simplify( 0.5 ) );
   17139                 :            :   // should be a single polygon as A intersect B
   17140                 :            :   QgsGeometry *mypSimplifyGeometry  =  mpPolylineGeometryD->simplify( 0.5 );
   17141                 :            :   qDebug( "Geometry Type: %s", QgsWkbTypes::displayString( mypSimplifyGeometry->wkbType() ) );
   17142                 :            :   QVERIFY( mypSimplifyGeometry->wkbType() == QgsWkbTypes::LineString );
   17143                 :            :   QgsPolyline myLine = mypSimplifyGeometry->asPolyline();
   17144                 :            :   QVERIFY( myLine.size() > 0 ); //check that the union created a feature
   17145                 :            :   dumpPolyline( myLine );
   17146                 :            :   delete mypSimplifyGeometry;
   17147                 :            :   QVERIFY( renderCheck( "geometry_simplifyCheck1", "Checking simplify of line" ) );
   17148                 :            : }
   17149                 :            : #endif
   17150                 :            : 
   17151                 :          1 : void TestQgsGeometry::intersectionCheck1()
   17152                 :            : {
   17153                 :          1 :   initPainterTest();
   17154                 :          1 :   QVERIFY( mpPolygonGeometryA.intersects( mpPolygonGeometryB ) );
   17155                 :            : 
   17156                 :          1 :   std::unique_ptr< QgsGeometryEngine > engine( QgsGeometry::createGeometryEngine( mpPolygonGeometryA.constGet() ) );
   17157                 :          1 :   QVERIFY( engine->intersects( mpPolygonGeometryB.constGet() ) );
   17158                 :          1 :   engine->prepareGeometry();
   17159                 :          1 :   QVERIFY( engine->intersects( mpPolygonGeometryB.constGet() ) );
   17160                 :            : 
   17161                 :            :   // should be a single polygon as A intersect B
   17162                 :          1 :   QgsGeometry mypIntersectionGeometry  =  mpPolygonGeometryA.intersection( mpPolygonGeometryB );
   17163                 :          1 :   QVERIFY( mypIntersectionGeometry.wkbType() == QgsWkbTypes::Polygon );
   17164                 :          1 :   QgsPolygonXY myPolygon = mypIntersectionGeometry.asPolygon();
   17165                 :          1 :   QVERIFY( myPolygon.size() > 0 ); //check that the union created a feature
   17166                 :          1 :   paintPolygon( myPolygon );
   17167                 :          1 :   QVERIFY( renderCheck( "geometry_intersectionCheck1", "Checking if A intersects B" ) );
   17168                 :          1 : }
   17169                 :          1 : void TestQgsGeometry::intersectionCheck2()
   17170                 :            : {
   17171                 :          1 :   QVERIFY( !mpPolygonGeometryA.intersects( mpPolygonGeometryC ) );
   17172                 :          1 : }
   17173                 :            : 
   17174                 :          1 : void TestQgsGeometry::translateCheck1()
   17175                 :            : {
   17176                 :          2 :   QString wkt = QStringLiteral( "LineString (0 0, 10 0, 10 10)" );
   17177                 :          1 :   QgsGeometry geom( QgsGeometry::fromWkt( wkt ) );
   17178                 :          1 :   geom.translate( 10, -5 );
   17179                 :          1 :   QString obtained = geom.asWkt();
   17180                 :          2 :   QString expected = QStringLiteral( "LineString (10 -5, 20 -5, 20 5)" );
   17181                 :          1 :   QCOMPARE( obtained, expected );
   17182                 :          1 :   geom.translate( -10, 5 );
   17183                 :          1 :   obtained = geom.asWkt();
   17184                 :          1 :   QCOMPARE( obtained, wkt );
   17185                 :            : 
   17186                 :          2 :   wkt = QStringLiteral( "Polygon ((-2 4, -2 -10, 2 3, -2 4),(1 1, -1 1, -1 -1, 1 1))" );
   17187                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17188                 :          1 :   geom.translate( -2, 10 );
   17189                 :          1 :   obtained = geom.asWkt();
   17190                 :          2 :   expected = QStringLiteral( "Polygon ((-4 14, -4 0, 0 13, -4 14),(-1 11, -3 11, -3 9, -1 11))" );
   17191                 :          1 :   QCOMPARE( obtained, expected );
   17192                 :          1 :   geom.translate( 2, -10 );
   17193                 :          1 :   obtained = geom.asWkt();
   17194                 :          1 :   QCOMPARE( obtained, wkt );
   17195                 :            : 
   17196                 :          2 :   wkt = QStringLiteral( "Point (40 50)" );
   17197                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17198                 :          1 :   geom.translate( -2, 10 );
   17199                 :          1 :   obtained = geom.asWkt();
   17200                 :          2 :   expected = QStringLiteral( "Point (38 60)" );
   17201                 :          1 :   QCOMPARE( obtained, expected );
   17202                 :          1 :   geom.translate( 2, -10 );
   17203                 :          1 :   obtained = geom.asWkt();
   17204                 :          1 :   QCOMPARE( obtained, wkt );
   17205                 :            : 
   17206                 :          1 : }
   17207                 :            : 
   17208                 :          1 : void TestQgsGeometry::rotateCheck1()
   17209                 :            : {
   17210                 :          2 :   QString wkt = QStringLiteral( "LineString (0 0, 10 0, 10 10)" );
   17211                 :          1 :   QgsGeometry geom( QgsGeometry::fromWkt( wkt ) );
   17212                 :          1 :   geom.rotate( 90, QgsPointXY( 0, 0 ) );
   17213                 :          1 :   QString obtained = geom.asWkt();
   17214                 :          2 :   QString expected = QStringLiteral( "LineString (0 0, 0 -10, 10 -10)" );
   17215                 :          1 :   QCOMPARE( obtained, expected );
   17216                 :          1 :   geom.rotate( -90, QgsPointXY( 0, 0 ) );
   17217                 :          1 :   obtained = geom.asWkt();
   17218                 :          1 :   QCOMPARE( obtained, wkt );
   17219                 :            : 
   17220                 :          2 :   wkt = QStringLiteral( "Polygon ((-2 4, -2 -10, 2 3, -2 4),(1 1, -1 1, -1 -1, 1 1))" );
   17221                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17222                 :          1 :   geom.rotate( 90, QgsPointXY( 0, 0 ) );
   17223                 :          1 :   obtained = geom.asWkt();
   17224                 :          2 :   expected = QStringLiteral( "Polygon ((4 2, -10 2, 3 -2, 4 2),(1 -1, 1 1, -1 1, 1 -1))" );
   17225                 :          1 :   QCOMPARE( obtained, expected );
   17226                 :          1 :   geom.rotate( -90, QgsPointXY( 0, 0 ) );
   17227                 :          1 :   obtained = geom.asWkt();
   17228                 :          1 :   QCOMPARE( obtained, wkt );
   17229                 :            : 
   17230                 :          2 :   wkt = QStringLiteral( "Point (40 50)" );
   17231                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17232                 :          1 :   geom.rotate( 90, QgsPointXY( 0, 0 ) );
   17233                 :          1 :   obtained = geom.asWkt();
   17234                 :          2 :   expected = QStringLiteral( "Point (50 -40)" );
   17235                 :          1 :   QCOMPARE( obtained, expected );
   17236                 :          1 :   geom.rotate( -90, QgsPointXY( 0, 0 ) );
   17237                 :          1 :   obtained = geom.asWkt();
   17238                 :          1 :   QCOMPARE( obtained, wkt );
   17239                 :          1 :   geom.rotate( 180, QgsPointXY( 40, 0 ) );
   17240                 :          2 :   expected = QStringLiteral( "Point (40 -50)" );
   17241                 :          1 :   obtained = geom.asWkt();
   17242                 :          1 :   QCOMPARE( obtained, expected );
   17243                 :          1 :   geom.rotate( 180, QgsPointXY( 40, 0 ) ); // round-trip
   17244                 :          1 :   obtained = geom.asWkt();
   17245                 :          1 :   QCOMPARE( obtained, wkt );
   17246                 :            : 
   17247                 :          1 : }
   17248                 :            : 
   17249                 :          1 : void TestQgsGeometry::unionCheck1()
   17250                 :            : {
   17251                 :          1 :   initPainterTest();
   17252                 :            :   // should be a multipolygon with 2 parts as A does not intersect C
   17253                 :          1 :   QgsGeometry mypUnionGeometry  =  mpPolygonGeometryA.combine( mpPolygonGeometryC );
   17254                 :          1 :   QVERIFY( mypUnionGeometry.wkbType() == QgsWkbTypes::MultiPolygon );
   17255                 :          1 :   QgsMultiPolygonXY myMultiPolygon = mypUnionGeometry.asMultiPolygon();
   17256                 :          1 :   QVERIFY( myMultiPolygon.size() > 0 ); //check that the union did not fail
   17257                 :          1 :   paintMultiPolygon( myMultiPolygon );
   17258                 :          1 :   QVERIFY( renderCheck( "geometry_unionCheck1", "Checking A union C produces 2 polys" ) );
   17259                 :          1 : }
   17260                 :            : 
   17261                 :          1 : void TestQgsGeometry::unionCheck2()
   17262                 :            : {
   17263                 :          1 :   initPainterTest();
   17264                 :            :   // should be a single polygon as A intersect B
   17265                 :          1 :   QgsGeometry mypUnionGeometry  =  mpPolygonGeometryA.combine( mpPolygonGeometryB );
   17266                 :          1 :   QVERIFY( mypUnionGeometry.wkbType() == QgsWkbTypes::Polygon );
   17267                 :          1 :   QgsPolygonXY myPolygon = mypUnionGeometry.asPolygon();
   17268                 :          1 :   QVERIFY( myPolygon.size() > 0 ); //check that the union created a feature
   17269                 :          1 :   paintPolygon( myPolygon );
   17270                 :          1 :   QVERIFY( renderCheck( "geometry_unionCheck2", "Checking A union B produces single union poly" ) );
   17271                 :          1 : }
   17272                 :            : 
   17273                 :          1 : void TestQgsGeometry::differenceCheck1()
   17274                 :            : {
   17275                 :          1 :   initPainterTest();
   17276                 :            :   // should be same as A since A does not intersect C so diff is 100% of A
   17277                 :          1 :   QgsGeometry mypDifferenceGeometry( mpPolygonGeometryA.difference( mpPolygonGeometryC ) );
   17278                 :          1 :   QVERIFY( mypDifferenceGeometry.wkbType() == QgsWkbTypes::Polygon );
   17279                 :          1 :   QgsPolygonXY myPolygon = mypDifferenceGeometry.asPolygon();
   17280                 :          1 :   QVERIFY( myPolygon.size() > 0 ); //check that the union did not fail
   17281                 :          1 :   paintPolygon( myPolygon );
   17282                 :          1 :   QVERIFY( renderCheck( "geometry_differenceCheck1", "Checking (A - C) = A" ) );
   17283                 :          1 : }
   17284                 :            : 
   17285                 :          1 : void TestQgsGeometry::differenceCheck2()
   17286                 :            : {
   17287                 :          1 :   initPainterTest();
   17288                 :            :   // should be a single polygon as (A - B) = subset of A
   17289                 :          1 :   QgsGeometry mypDifferenceGeometry( mpPolygonGeometryA.difference( mpPolygonGeometryB ) );
   17290                 :          1 :   QVERIFY( mypDifferenceGeometry.wkbType() == QgsWkbTypes::Polygon );
   17291                 :          1 :   QgsPolygonXY myPolygon = mypDifferenceGeometry.asPolygon();
   17292                 :          1 :   QVERIFY( myPolygon.size() > 0 ); //check that the union created a feature
   17293                 :          1 :   paintPolygon( myPolygon );
   17294                 :          1 :   QVERIFY( renderCheck( "geometry_differenceCheck2", "Checking (A - B) = subset of A" ) );
   17295                 :          1 : }
   17296                 :          1 : void TestQgsGeometry::bufferCheck()
   17297                 :            : {
   17298                 :          1 :   initPainterTest();
   17299                 :            :   // should be a single polygon
   17300                 :          1 :   QgsGeometry mypBufferGeometry( mpPolygonGeometryB.buffer( 10, 10 ) );
   17301                 :          1 :   QVERIFY( mypBufferGeometry.wkbType() == QgsWkbTypes::Polygon );
   17302                 :          1 :   QgsPolygonXY myPolygon = mypBufferGeometry.asPolygon();
   17303                 :          1 :   QVERIFY( myPolygon.size() > 0 ); //check that the buffer created a feature
   17304                 :          1 :   paintPolygon( myPolygon );
   17305                 :          1 :   QVERIFY( renderCheck( "geometry_bufferCheck", "Checking buffer(10,10) of B", 10 ) );
   17306                 :          1 : }
   17307                 :            : 
   17308                 :          1 : void TestQgsGeometry::smoothCheck()
   17309                 :            : {
   17310                 :            :   //can't smooth a point
   17311                 :          2 :   QString wkt = QStringLiteral( "Point (40 50)" );
   17312                 :          1 :   QgsGeometry geom( QgsGeometry::fromWkt( wkt ) );
   17313                 :          1 :   QgsGeometry result = geom.smooth( 1, 0.25 );
   17314                 :          1 :   QString obtained = result.asWkt();
   17315                 :          1 :   QCOMPARE( obtained, wkt );
   17316                 :            : 
   17317                 :            :   //linestring
   17318                 :          2 :   wkt = QStringLiteral( "LineString(0 0, 10 0, 10 10, 20 10)" );
   17319                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17320                 :          1 :   result = geom.smooth( 1, 0.25 );
   17321                 :          1 :   QgsPolylineXY line = result.asPolyline();
   17322                 :          1 :   QgsPolylineXY expectedLine;
   17323                 :          1 :   expectedLine << QgsPointXY( 0, 0 ) << QgsPointXY( 7.5, 0 ) << QgsPointXY( 10.0, 2.5 )
   17324                 :          1 :                << QgsPointXY( 10.0, 7.5 ) << QgsPointXY( 12.5, 10.0 ) << QgsPointXY( 20.0, 10.0 );
   17325                 :          1 :   QVERIFY( QgsGeometry::compare( line, expectedLine ) );
   17326                 :            : 
   17327                 :            :   //linestringM
   17328                 :          2 :   wkt = QStringLiteral( "LineStringM(0 0 1, 10 0 2, 10 10 6, 20 10 4)" );
   17329                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17330                 :          1 :   result = geom.smooth( 1, 0.25 );
   17331                 :          2 :   QCOMPARE( result.asWkt(), QStringLiteral( "LineStringM (0 0 1, 7.5 0 1.75, 10 2.5 3, 10 7.5 5, 12.5 10 5.5, 20 10 4)" ) );
   17332                 :            : 
   17333                 :            :   //linestringZ
   17334                 :          2 :   wkt = QStringLiteral( "LineStringZ(0 0 1, 10 0 2, 10 10 6, 20 10 4)" );
   17335                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17336                 :          1 :   result = geom.smooth( 1, 0.25 );
   17337                 :          2 :   QCOMPARE( result.asWkt(), QStringLiteral( "LineStringZ (0 0 1, 7.5 0 1.75, 10 2.5 3, 10 7.5 5, 12.5 10 5.5, 20 10 4)" ) );
   17338                 :            : 
   17339                 :            :   //linestringZM
   17340                 :          2 :   wkt = QStringLiteral( "LineStringZM(0 0 1 4, 10 0 2 8, 10 10 6 2, 20 10 4 0)" );
   17341                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17342                 :          1 :   result = geom.smooth( 1, 0.25 );
   17343                 :          2 :   QCOMPARE( result.asWkt(), QStringLiteral( "LineStringZM (0 0 1 4, 7.5 0 1.75 7, 10 2.5 3 6.5, 10 7.5 5 3.5, 12.5 10 5.5 1.5, 20 10 4 0)" ) );
   17344                 :            : 
   17345                 :            :   //linestring, with min distance
   17346                 :          2 :   wkt = QStringLiteral( "LineString(0 0, 10 0, 10 10, 15 10, 15 20)" );
   17347                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17348                 :          1 :   result = geom.smooth( 1, 0.25, 6 );
   17349                 :          1 :   line = result.asPolyline();
   17350                 :          1 :   expectedLine.clear();
   17351                 :          1 :   expectedLine << QgsPointXY( 0, 0 ) << QgsPointXY( 7.5, 0 ) << QgsPointXY( 10.0, 2.5 )
   17352                 :          1 :                << QgsPointXY( 10.0, 7.5 ) << QgsPointXY( 15, 12.5 ) << QgsPointXY( 15.0, 20.0 );
   17353                 :          1 :   QVERIFY( QgsGeometry::compare( line, expectedLine ) );
   17354                 :            : 
   17355                 :            :   //linestring, with max angle
   17356                 :          2 :   wkt = QStringLiteral( "LineString(0 0, 10 0, 15 5, 25 -5, 30 -5 )" );
   17357                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17358                 :          1 :   result = geom.smooth( 1, 0.25, 0, 50 );
   17359                 :          1 :   line = result.asPolyline();
   17360                 :          1 :   expectedLine.clear();
   17361                 :          1 :   expectedLine << QgsPointXY( 0, 0 ) << QgsPointXY( 7.5, 0 ) << QgsPointXY( 11.25, 1.25 )
   17362                 :          1 :                << QgsPointXY( 15.0, 5.0 ) << QgsPointXY( 22.5, -2.5 ) << QgsPointXY( 26.25, -5 ) << QgsPointXY( 30, -5 );
   17363                 :          1 :   QVERIFY( QgsGeometry::compare( line, expectedLine ) );
   17364                 :            : 
   17365                 :            :   //linestring, with max angle, other direction
   17366                 :          2 :   wkt = QStringLiteral( "LineString( 30 -5, 25 -5, 15 5, 10 0, 0 0 )" );
   17367                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17368                 :          1 :   result = geom.smooth( 1, 0.25, 0, 50 );
   17369                 :          1 :   line = result.asPolyline();
   17370                 :          1 :   expectedLine.clear();
   17371                 :          1 :   expectedLine << QgsPointXY( 30, -5 ) << QgsPointXY( 26.25, -5 ) << QgsPointXY( 22.5, -2.5 )
   17372                 :          1 :                << QgsPointXY( 15.0, 5.0 ) << QgsPointXY( 11.25, 1.25 ) << QgsPointXY( 7.5, 0 ) << QgsPointXY( 0, 0 );
   17373                 :          1 :   QVERIFY( QgsGeometry::compare( line, expectedLine ) );
   17374                 :            : 
   17375                 :            :   //linestring, max angle, first corner sharp
   17376                 :          2 :   wkt = QStringLiteral( "LineString(0 0, 10 0, 10 10 )" );
   17377                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17378                 :          1 :   result = geom.smooth( 1, 0.25, 0, 50 );
   17379                 :          1 :   line = result.asPolyline();
   17380                 :          1 :   expectedLine.clear();
   17381                 :          1 :   expectedLine << QgsPointXY( 0, 0 ) << QgsPointXY( 10, 0 ) << QgsPointXY( 10, 10 );
   17382                 :          1 :   QVERIFY( QgsGeometry::compare( line, expectedLine ) );
   17383                 :            : 
   17384                 :          2 :   wkt = QStringLiteral( "MultiLineString ((0 0, 10 0, 10 10, 20 10),(30 30, 40 30, 40 40, 50 40))" );
   17385                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17386                 :          1 :   result = geom.smooth( 1, 0.25 );
   17387                 :          1 :   QgsMultiPolylineXY multiLine = result.asMultiPolyline();
   17388                 :          1 :   QgsMultiPolylineXY expectedMultiline;
   17389                 :          3 :   expectedMultiline << ( QgsPolylineXY() << QgsPointXY( 0, 0 ) << QgsPointXY( 7.5, 0 ) << QgsPointXY( 10.0, 2.5 )
   17390                 :          1 :                          <<  QgsPointXY( 10.0, 7.5 ) << QgsPointXY( 12.5, 10.0 ) << QgsPointXY( 20.0, 10.0 ) )
   17391                 :          2 :                     << ( QgsPolylineXY() << QgsPointXY( 30.0, 30.0 ) << QgsPointXY( 37.5, 30.0 ) << QgsPointXY( 40.0, 32.5 )
   17392                 :          1 :                          << QgsPointXY( 40.0, 37.5 ) << QgsPointXY( 42.5, 40.0 ) << QgsPointXY( 50.0, 40.0 ) );
   17393                 :          1 :   QVERIFY( QgsGeometry::compare( multiLine, expectedMultiline ) );
   17394                 :            : 
   17395                 :            :   //polygon
   17396                 :          2 :   wkt = QStringLiteral( "Polygon ((0 0, 10 0, 10 10, 0 10, 0 0 ),(2 2, 4 2, 4 4, 2 4, 2 2))" );
   17397                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17398                 :          1 :   result = geom.smooth( 1, 0.25 );
   17399                 :          1 :   QgsPolygonXY poly = result.asPolygon();
   17400                 :          1 :   QgsPolygonXY expectedPolygon;
   17401                 :          3 :   expectedPolygon << ( QgsPolylineXY() << QgsPointXY( 2.5, 0 ) << QgsPointXY( 7.5, 0 ) << QgsPointXY( 10.0, 2.5 )
   17402                 :          1 :                        <<  QgsPointXY( 10.0, 7.5 ) << QgsPointXY( 7.5, 10.0 ) << QgsPointXY( 2.5, 10.0 ) << QgsPointXY( 0, 7.5 )
   17403                 :          1 :                        << QgsPointXY( 0, 2.5 ) << QgsPointXY( 2.5, 0 ) )
   17404                 :          2 :                   << ( QgsPolylineXY() << QgsPointXY( 2.5, 2.0 ) << QgsPointXY( 3.5, 2.0 ) << QgsPointXY( 4.0, 2.5 )
   17405                 :          1 :                        << QgsPointXY( 4.0, 3.5 ) << QgsPointXY( 3.5, 4.0 ) << QgsPointXY( 2.5, 4.0 )
   17406                 :          1 :                        << QgsPointXY( 2.0, 3.5 ) << QgsPointXY( 2.0, 2.5 ) << QgsPointXY( 2.5, 2.0 ) );
   17407                 :          1 :   QVERIFY( QgsGeometry::compare( poly, expectedPolygon ) );
   17408                 :            : 
   17409                 :            :   //polygonM
   17410                 :          2 :   wkt = QStringLiteral( "PolygonM ((0 0 1, 10 0 4, 10 10 6, 0 10 8, 0 0 1 ),(2 2 3, 4 2 5, 4 4 7, 2 4 9, 2 2 3))" );
   17411                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17412                 :          1 :   result = geom.smooth( 1, 0.25 );
   17413                 :          2 :   QCOMPARE( result.asWkt(), QStringLiteral( "PolygonM ((2.5 0 1.75, 7.5 0 3.25, 10 2.5 4.5, 10 7.5 5.5, 7.5 10 6.5, 2.5 10 7.5, 0 7.5 6.25, 0 2.5 2.75, 2.5 0 1.75),(2.5 2 3.5, 3.5 2 4.5, 4 2.5 5.5, 4 3.5 6.5, 3.5 4 7.5, 2.5 4 8.5, 2 3.5 7.5, 2 2.5 4.5, 2.5 2 3.5))" ) );
   17414                 :            : 
   17415                 :            :   //polygonZ
   17416                 :          2 :   wkt = QStringLiteral( "PolygonZ ((0 0 1, 10 0 4, 10 10 6, 0 10 8, 0 0 1 ),(2 2 3, 4 2 5, 4 4 7, 2 4 9, 2 2 3))" );
   17417                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17418                 :          1 :   result = geom.smooth( 1, 0.25 );
   17419                 :          2 :   QCOMPARE( result.asWkt(), QStringLiteral( "PolygonZ ((2.5 0 1.75, 7.5 0 3.25, 10 2.5 4.5, 10 7.5 5.5, 7.5 10 6.5, 2.5 10 7.5, 0 7.5 6.25, 0 2.5 2.75, 2.5 0 1.75),(2.5 2 3.5, 3.5 2 4.5, 4 2.5 5.5, 4 3.5 6.5, 3.5 4 7.5, 2.5 4 8.5, 2 3.5 7.5, 2 2.5 4.5, 2.5 2 3.5))" ) );
   17420                 :            : 
   17421                 :            :   //polygonZM
   17422                 :          2 :   wkt = QStringLiteral( "PolygonZ ((0 0 1 6, 10 0 4 2, 10 10 6 0, 0 10 8 4, 0 0 1 6 ))" );
   17423                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17424                 :          1 :   result = geom.smooth( 1, 0.25 );
   17425                 :          2 :   QCOMPARE( result.asWkt(), QStringLiteral( "PolygonZM ((2.5 0 1.75 5, 7.5 0 3.25 3, 10 2.5 4.5 1.5, 10 7.5 5.5 0.5, 7.5 10 6.5 1, 2.5 10 7.5 3, 0 7.5 6.25 4.5, 0 2.5 2.75 5.5, 2.5 0 1.75 5))" ) );
   17426                 :            : 
   17427                 :            :   //polygon with max angle - should be unchanged
   17428                 :          2 :   wkt = QStringLiteral( "Polygon ((0 0, 10 0, 10 10, 0 10, 0 0))" );
   17429                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17430                 :          1 :   result = geom.smooth( 1, 0.25, -1, 50 );
   17431                 :          1 :   poly = result.asPolygon();
   17432                 :          1 :   expectedPolygon.clear();
   17433                 :          2 :   expectedPolygon << ( QgsPolylineXY() << QgsPointXY( 0, 0 ) << QgsPointXY( 10, 0 ) << QgsPointXY( 10.0, 10 )
   17434                 :          1 :                        <<  QgsPointXY( 0, 10 ) << QgsPointXY( 0, 0 ) );
   17435                 :          1 :   QVERIFY( QgsGeometry::compare( poly, expectedPolygon ) );
   17436                 :            : 
   17437                 :            :   //multipolygon)
   17438                 :          2 :   wkt = QStringLiteral( "MultiPolygon (((0 0, 10 0, 10 10, 0 10, 0 0 )),((2 2, 4 2, 4 4, 2 4, 2 2)))" );
   17439                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17440                 :          1 :   result = geom.smooth( 1, 0.1 );
   17441                 :          1 :   QgsMultiPolygonXY multipoly = result.asMultiPolygon();
   17442                 :          1 :   QgsMultiPolygonXY expectedMultiPoly;
   17443                 :          1 :   expectedMultiPoly
   17444                 :          2 :       << ( QgsPolygonXY() << ( QgsPolylineXY() << QgsPointXY( 1.0, 0 ) << QgsPointXY( 9, 0 ) << QgsPointXY( 10.0, 1 )
   17445                 :          1 :                                <<  QgsPointXY( 10.0, 9 ) << QgsPointXY( 9, 10.0 ) << QgsPointXY( 1, 10.0 ) << QgsPointXY( 0, 9 )
   17446                 :          1 :                                << QgsPointXY( 0, 1 ) << QgsPointXY( 1, 0 ) ) )
   17447                 :          2 :       << ( QgsPolygonXY() << ( QgsPolylineXY() << QgsPointXY( 2.2, 2.0 ) << QgsPointXY( 3.8, 2.0 ) << QgsPointXY( 4.0, 2.2 )
   17448                 :          1 :                                <<  QgsPointXY( 4.0, 3.8 ) << QgsPointXY( 3.8, 4.0 ) << QgsPointXY( 2.2, 4.0 ) << QgsPointXY( 2.0, 3.8 )
   17449                 :          1 :                                << QgsPointXY( 2, 2.2 ) << QgsPointXY( 2.2, 2 ) ) );
   17450                 :          1 :   QVERIFY( QgsGeometry::compare( multipoly, expectedMultiPoly ) );
   17451                 :            : 
   17452                 :            :   // curved geometry
   17453                 :          2 :   wkt = QStringLiteral( "CurvePolygon (CompoundCurve (CircularString (-70.75639028391421448 42.11076979194393743, -70.75300889449444242 42.10738840252416537, -70.75639028391421448 42.10400701310439331, -70.75977167333398654 42.10738840252416537, -70.75639028391421448 42.11076979194393743)))        1" );
   17454                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17455                 :          1 :   result = geom.smooth( 3 );
   17456                 :          1 :   QCOMPARE( result.wkbType(), QgsWkbTypes::Polygon );
   17457                 :          1 : }
   17458                 :            : 
   17459                 :          1 : void TestQgsGeometry::shortestLineEmptyGeometry()
   17460                 :            : {
   17461                 :            :   // test calculating distance to an empty geometry
   17462                 :            :   // refs https://github.com/qgis/QGIS/issues/41968
   17463                 :          2 :   QgsGeometry geom1( QgsGeometry::fromWkt( QStringLiteral( "Polygon ((0 0, 10 0, 10 10, 0 10, 0 0 ))" ) ) );
   17464                 :          1 :   QgsGeometry geom2( new QgsPoint() );
   17465                 :          1 :   QgsGeos geos( geom1.constGet() );
   17466                 :          1 :   QVERIFY( geos.shortestLine( geom2.constGet() ).isNull() );
   17467                 :          1 : }
   17468                 :            : 
   17469                 :          1 : void TestQgsGeometry::unaryUnion()
   17470                 :            : {
   17471                 :            :   //test QgsGeometry::unaryUnion with null geometry
   17472                 :          2 :   QString wkt1 = QStringLiteral( "Polygon ((0 0, 10 0, 10 10, 0 10, 0 0 ))" );
   17473                 :          2 :   QString wkt2 = QStringLiteral( "Polygon ((2 2, 4 2, 4 4, 2 4, 2 2))" );
   17474                 :          1 :   QgsGeometry geom1( QgsGeometry::fromWkt( wkt1 ) );
   17475                 :          1 :   QgsGeometry geom2( QgsGeometry::fromWkt( wkt2 ) );
   17476                 :          1 :   QgsGeometry empty;
   17477                 :          1 :   QVector< QgsGeometry > list;
   17478                 :          1 :   list << geom1 << empty << geom2;
   17479                 :            : 
   17480                 :          1 :   QgsGeometry result( QgsGeometry::unaryUnion( list ) );
   17481                 :            :   Q_UNUSED( result );
   17482                 :          1 : }
   17483                 :            : 
   17484                 :          1 : void TestQgsGeometry::dataStream()
   17485                 :            : {
   17486                 :          2 :   QString wkt = QStringLiteral( "Point (40 50)" );
   17487                 :          1 :   QgsGeometry geom( QgsGeometry::fromWkt( wkt ) );
   17488                 :            : 
   17489                 :          1 :   QByteArray ba;
   17490                 :          1 :   QDataStream ds( &ba, QIODevice::ReadWrite );
   17491                 :          1 :   ds << geom;
   17492                 :            : 
   17493                 :          1 :   QgsGeometry resultGeometry;
   17494                 :          1 :   ds.device()->seek( 0 );
   17495                 :          1 :   ds >> resultGeometry;
   17496                 :            : 
   17497                 :          1 :   QCOMPARE( geom.constGet()->asWkt(), resultGeometry.constGet()->asWkt() );
   17498                 :            : 
   17499                 :            :   //also test with geometry without data
   17500                 :          1 :   std::unique_ptr<QgsGeometry> emptyGeom( new QgsGeometry() );
   17501                 :            : 
   17502                 :          1 :   QByteArray ba2;
   17503                 :          1 :   QDataStream ds2( &ba2, QIODevice::ReadWrite );
   17504                 :          1 :   ds2 << emptyGeom.get();
   17505                 :            : 
   17506                 :          1 :   ds2.device()->seek( 0 );
   17507                 :          1 :   ds2 >> resultGeometry;
   17508                 :            : 
   17509                 :          1 :   QVERIFY( resultGeometry.isNull() );
   17510                 :          1 : }
   17511                 :            : 
   17512                 :          1 : void TestQgsGeometry::exportToGeoJSON()
   17513                 :            : {
   17514                 :            :   //Point
   17515                 :          2 :   QString wkt = QStringLiteral( "Point (40 50)" );
   17516                 :          1 :   QgsGeometry geom( QgsGeometry::fromWkt( wkt ) );
   17517                 :          1 :   QString obtained = geom.asJson();
   17518                 :          2 :   QString geojson = QStringLiteral( "{\"coordinates\":[40.0,50.0],\"type\":\"Point\"}" );
   17519                 :          1 :   QCOMPARE( obtained, geojson );
   17520                 :            : 
   17521                 :            :   //MultiPoint
   17522                 :          2 :   wkt = QStringLiteral( "MultiPoint (0 0, 10 0, 10 10, 20 10)" );
   17523                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17524                 :          1 :   obtained = geom.asJson();
   17525                 :          2 :   geojson = QStringLiteral( "{\"coordinates\":[[0.0,0.0],[10.0,0.0],[10.0,10.0],[20.0,10.0]],\"type\":\"MultiPoint\"}" );
   17526                 :          1 :   QCOMPARE( obtained, geojson );
   17527                 :            : 
   17528                 :            :   //Linestring
   17529                 :          2 :   wkt = QStringLiteral( "LineString(0 0, 10 0, 10 10, 20 10)" );
   17530                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17531                 :          1 :   obtained = geom.asJson();
   17532                 :          2 :   geojson = QStringLiteral( "{\"coordinates\":[[0.0,0.0],[10.0,0.0],[10.0,10.0],[20.0,10.0]],\"type\":\"LineString\"}" );
   17533                 :          1 :   QCOMPARE( obtained, geojson );
   17534                 :            : 
   17535                 :            :   //MultiLineString
   17536                 :          2 :   wkt = QStringLiteral( "MultiLineString ((0 0, 10 0, 10 10, 20 10),(30 30, 40 30, 40 40, 50 40))" );
   17537                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17538                 :          1 :   obtained = geom.asJson();
   17539                 :          2 :   geojson = QStringLiteral( "{\"coordinates\":[[[0.0,0.0],[10.0,0.0],[10.0,10.0],[20.0,10.0]],[[30.0,30.0],[40.0,30.0],[40.0,40.0],[50.0,40.0]]],\"type\":\"MultiLineString\"}" );
   17540                 :          1 :   QCOMPARE( obtained, geojson );
   17541                 :            : 
   17542                 :            :   //Polygon
   17543                 :          2 :   wkt = QStringLiteral( "Polygon ((0 0, 10 0, 10 10, 0 10, 0 0 ),(2 2, 4 2, 4 4, 2 4, 2 2))" );
   17544                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17545                 :          1 :   obtained = geom.asJson();
   17546                 :          2 :   geojson = QStringLiteral( "{\"coordinates\":[[[0.0,0.0],[10.0,0.0],[10.0,10.0],[0.0,10.0],[0.0,0.0]],[[2.0,2.0],[4.0,2.0],[4.0,4.0],[2.0,4.0],[2.0,2.0]]],\"type\":\"Polygon\"}" );
   17547                 :          1 :   QCOMPARE( obtained, geojson );
   17548                 :            : 
   17549                 :            :   //MultiPolygon
   17550                 :          2 :   wkt = QStringLiteral( "MultiPolygon (((0 0, 10 0, 10 10, 0 10, 0 0 )),((2 2, 4 2, 4 4, 2 4, 2 2)))" );
   17551                 :          1 :   geom = QgsGeometry::fromWkt( wkt );
   17552                 :          1 :   obtained = geom.asJson();
   17553                 :          2 :   geojson = QStringLiteral( "{\"coordinates\":[[[[0.0,0.0],[10.0,0.0],[10.0,10.0],[0.0,10.0],[0.0,0.0]]],[[[2.0,2.0],[4.0,2.0],[4.0,4.0],[2.0,4.0],[2.0,2.0]]]],\"type\":\"MultiPolygon\"}" );
   17554                 :          1 :   QCOMPARE( obtained, geojson );
   17555                 :            : 
   17556                 :            :   // no geometry
   17557                 :          1 :   QgsGeometry nullGeom( nullptr );
   17558                 :          1 :   obtained = nullGeom.asJson();
   17559                 :          2 :   geojson = QStringLiteral( "null" );
   17560                 :          1 :   QCOMPARE( obtained, geojson );
   17561                 :          1 : }
   17562                 :            : 
   17563                 :          6 : bool TestQgsGeometry::renderCheck( const QString &testName, const QString &comment, int mismatchCount )
   17564                 :            : {
   17565                 :          6 :   mReport += "<h2>" + testName + "</h2>\n";
   17566                 :          6 :   mReport += "<h3>" + comment + "</h3>\n";
   17567                 :          6 :   QString myTmpDir = QDir::tempPath() + '/';
   17568                 :          6 :   QString myFileName = myTmpDir + testName + ".png";
   17569                 :          6 :   mImage.save( myFileName, "PNG" );
   17570                 :          6 :   QgsRenderChecker myChecker;
   17571                 :          6 :   myChecker.setControlName( "expected_" + testName );
   17572                 :          6 :   myChecker.setRenderedImage( myFileName );
   17573                 :          6 :   bool myResultFlag = myChecker.compareImages( testName, mismatchCount );
   17574                 :          6 :   mReport += myChecker.report();
   17575                 :          6 :   return myResultFlag;
   17576                 :          6 : }
   17577                 :            : 
   17578                 :          0 : void TestQgsGeometry::dumpMultiPolygon( QgsMultiPolygonXY &multiPolygon )
   17579                 :            : {
   17580                 :          0 :   qDebug( "Multipolygon Geometry Dump" );
   17581                 :          0 :   for ( int i = 0; i < multiPolygon.size(); i++ )
   17582                 :            :   {
   17583                 :          0 :     QgsPolygonXY myPolygon = multiPolygon.at( i );
   17584                 :          0 :     qDebug( "\tPolygon in multipolygon: %d", i );
   17585                 :          0 :     dumpPolygon( myPolygon );
   17586                 :          0 :   }
   17587                 :          0 : }
   17588                 :            : 
   17589                 :          1 : void TestQgsGeometry::paintMultiPolygon( QgsMultiPolygonXY &multiPolygon )
   17590                 :            : {
   17591                 :          3 :   for ( int i = 0; i < multiPolygon.size(); i++ )
   17592                 :            :   {
   17593                 :          2 :     QgsPolygonXY myPolygon = multiPolygon.at( i );
   17594                 :          2 :     paintPolygon( myPolygon );
   17595                 :          2 :   }
   17596                 :          1 : }
   17597                 :            : 
   17598                 :          0 : void TestQgsGeometry::dumpPolygon( QgsPolygonXY &polygon )
   17599                 :            : {
   17600                 :          0 :   for ( int j = 0; j < polygon.size(); j++ )
   17601                 :            :   {
   17602                 :          0 :     QgsPolylineXY myPolyline = polygon.at( j ); //rings of polygon
   17603                 :          0 :     qDebug( "\t\tRing in polygon: %d", j );
   17604                 :            : 
   17605                 :          0 :     for ( int k = 0; k < myPolyline.size(); k++ )
   17606                 :            :     {
   17607                 :          0 :       QgsPointXY myPoint = myPolyline.at( k );
   17608                 :          0 :       qDebug( "\t\t\tPoint in ring %d : %s", k, myPoint.toString().toLocal8Bit().constData() );
   17609                 :          0 :     }
   17610                 :          0 :   }
   17611                 :          0 : }
   17612                 :            : 
   17613                 :         25 : void TestQgsGeometry::paintPolygon( QgsPolygonXY &polygon )
   17614                 :            : {
   17615                 :         25 :   QVector<QPointF> myPoints;
   17616                 :         50 :   for ( int j = 0; j < polygon.size(); j++ )
   17617                 :            :   {
   17618                 :         25 :     QgsPolylineXY myPolyline = polygon.at( j ); //rings of polygon
   17619                 :        196 :     for ( int k = 0; k < myPolyline.size(); k++ )
   17620                 :            :     {
   17621                 :        171 :       QgsPointXY myPoint = myPolyline.at( k );
   17622                 :        171 :       myPoints << QPointF( myPoint.x(), myPoint.y() );
   17623                 :        171 :     }
   17624                 :         25 :   }
   17625                 :         25 :   mpPainter->drawPolygon( myPoints );
   17626                 :         25 : }
   17627                 :            : 
   17628                 :          0 : void TestQgsGeometry::dumpPolyline( QgsPolylineXY &polyline )
   17629                 :            : {
   17630                 :          0 :   QVector<QPointF> myPoints;
   17631                 :            : //  QgsPolyline myPolyline = polyline.at( j ); //rings of polygon
   17632                 :          0 :   for ( int j = 0; j < polyline.size(); j++ )
   17633                 :            :   {
   17634                 :          0 :     QgsPointXY myPoint = polyline.at( j );
   17635                 :            : //    QgsPolyline myPolyline = polygon.at( j ); //rings of polygon
   17636                 :          0 :     myPoints << QPointF( myPoint.x(), myPoint.y() );
   17637                 :          0 :     qDebug( "\t\tPoint in line: %d", j );
   17638                 :            : 
   17639                 :            : //    for ( int k = 0; k < myPolyline.size(); k++ )
   17640                 :            : //    {
   17641                 :            : //      QgsPointXY myPoint = myPolyline.at( k );
   17642                 :            : //      qDebug( "\t\t\tPoint in ring %d : %s", k, myPoint.toString().toLocal8Bit().constData() );
   17643                 :            : //      myPoints << QPointF( myPoint.x(), myPoint.y() );
   17644                 :            : //    }
   17645                 :          0 :   }
   17646                 :          0 :   mpPainter->drawPolyline( myPoints );
   17647                 :          0 : }
   17648                 :            : 
   17649                 :         92 : QString TestQgsGeometry::elemToString( const QDomElement &elem ) const
   17650                 :            : {
   17651                 :         92 :   QString s;
   17652                 :         92 :   QTextStream stream( &s );
   17653                 :         92 :   elem.save( stream, -1 );
   17654                 :            : 
   17655                 :         92 :   return s;
   17656                 :         92 : }
   17657                 :            : 
   17658                 :          1 : void TestQgsGeometry::wkbInOut()
   17659                 :            : {
   17660                 :            :   // Premature end of WKB
   17661                 :            :   // See https://github.com/qgis/QGIS/issues/22184
   17662                 :          1 :   const char *hexwkb = "0102000000EF0000000000000000000000000000000000000000000000000000000000000000000000";
   17663                 :            :   int size;
   17664                 :          1 :   unsigned char *wkb = hex2bytes( hexwkb, &size );
   17665                 :          1 :   QgsGeometry g14182;
   17666                 :            :   // NOTE: wkb onwership transferred to QgsGeometry
   17667                 :          1 :   g14182.fromWkb( wkb, size );
   17668                 :            :   //QList<QgsGeometry::Error> errors;
   17669                 :            :   //g14182.validateGeometry(errors);
   17670                 :            :   // Check with valgrind !
   17671                 :          1 :   QString wkt = g14182.asWkt();
   17672                 :          1 :   QCOMPARE( wkt, QString() );
   17673                 :            : 
   17674                 :            :   //WKB with a truncated header
   17675                 :          1 :   const char *badHeaderHexwkb = "0102";
   17676                 :          1 :   wkb = hex2bytes( badHeaderHexwkb, &size );
   17677                 :          1 :   QgsGeometry badHeader;
   17678                 :            :   // NOTE: wkb onwership transferred to QgsGeometry
   17679                 :          1 :   badHeader.fromWkb( wkb, size );
   17680                 :          1 :   QVERIFY( badHeader.isNull() );
   17681                 :          1 :   QCOMPARE( badHeader.wkbType(), QgsWkbTypes::Unknown );
   17682                 :          1 : }
   17683                 :            : 
   17684                 :          1 : void TestQgsGeometry::directionNeutralSegmentation()
   17685                 :            : {
   17686                 :            :   //Tests, if segmentation of a circularstring is the same in both directions
   17687                 :          2 :   QString CWCircularStringWkt( QStringLiteral( "CIRCULARSTRING( 0 0, 0.5 0.5, 0.83 7.33 )" ) );
   17688                 :          1 :   QgsCircularString *CWCircularString = static_cast<QgsCircularString *>( QgsGeometryFactory::geomFromWkt( CWCircularStringWkt ).release() );
   17689                 :          1 :   QgsLineString *CWLineString = CWCircularString->curveToLine();
   17690                 :            : 
   17691                 :          2 :   QString CCWCircularStringWkt( QStringLiteral( "CIRCULARSTRING( 0.83 7.33, 0.5 0.5, 0 0 )" ) );
   17692                 :          1 :   QgsCircularString *CCWCircularString = static_cast<QgsCircularString *>( QgsGeometryFactory::geomFromWkt( CCWCircularStringWkt ).release() );
   17693                 :          1 :   QgsLineString *CCWLineString = CCWCircularString->curveToLine();
   17694                 :          1 :   QgsLineString *reversedCCWLineString = CCWLineString->reversed();
   17695                 :            : 
   17696                 :          1 :   QCOMPARE( CWLineString->asWkt(), reversedCCWLineString->asWkt() );
   17697                 :          1 :   bool equal = ( *CWLineString == *reversedCCWLineString );
   17698                 :            : 
   17699                 :          1 :   delete CWCircularString;
   17700                 :          1 :   delete CCWCircularString;
   17701                 :          1 :   delete CWLineString;
   17702                 :          1 :   delete CCWLineString;
   17703                 :          1 :   delete reversedCCWLineString;
   17704                 :            : 
   17705                 :          1 :   QVERIFY( equal );
   17706                 :          1 : }
   17707                 :            : 
   17708                 :          1 : void TestQgsGeometry::poleOfInaccessibility()
   17709                 :            : {
   17710                 :          1 :   QString poly1Wkt( "Polygon ((3116 3071, 3394 3431, 3563 3362, 3611 3205, 3599 3181, 3477 3281, 3449 3160, 3570 3127, 3354 3116,"
   17711                 :            :                     " 3436 3008, 3158 2907, 2831 2438, 3269 2916, 3438 2885, 3295 2799, 3407 2772, 3278 2629, 3411 2689, 3329 2611,"
   17712                 :            :                     " 3360 2531, 3603 2800, 3598 2501, 3317 2429, 3329 2401, 3170 2340, 3142 2291, 3524 2403, 3598 2233, 3460 2117,"
   17713                 :            :                     " 3590 1931, 3364 1753, 3597 1875, 3639 1835, 3660 1733, 3600 1771, 3538 1694, 3661 1732, 3359 1554, 3334 1554,"
   17714                 :            :                     " 3341 1588, 3317 1588, 3305 1644, 3286 1656, 3115 1255, 3072 1252, 3078 1335, 3046 1355, 2984 1234, 2983 1409,"
   17715                 :            :                     " 2876 1222, 2525 1161, 2488 787, 2162 913, 2079 661, 2270 380, 2188 823, 2510 592, 2659 992, 2911 1118, 2943 938,"
   17716                 :            :                     " 2957 1097, 3092 1002, 3006 1097, 3233 1282, 3325 1291, 3296 1116, 3333 1115, 3391 1333, 3434 1274, 3413 1326,"
   17717                 :            :                     " 3449 1327, 3473 1408, 3490 1430, 3526 1434, 3198 -112, 3263 -87, 3289 -128, 4224 -128, 4224 -128, 3474 -128,"
   17718                 :            :                     " 3475 -116, 3486 -120, 3458 -49, 3523 -78, 3513 -128, 3509 -119, 3509 -128, 3717 -128, 3705 -60, 3735 -16,"
   17719                 :            :                     " 3714 38, 3758 88, 3825 47, 3812 -11, 3859 -51, 3871 49, 3760 149, 3636 -74, 3510 126, 3501 245, 3504 270,"
   17720                 :            :                     " 3511 284, 3582 16, 3631 19, 3569 125, 3570 193, 3610 212, 3583 119, 3655 29, 3738 170, 3561 466, 3826 549,"
   17721                 :            :                     " 3527 604, 3609 833, 3681 798, 3956 1127, 3917 964, 4043 850, 4049 1096, 4193 1052, 4191 1078, 4208 1106,"
   17722                 :            :                     " 4222 1110, 4224 1109, 4224 1144, 4202 1158, 4177 1161, 4182 1181, 4075 1201, 4141 1275, 4215 1215, 4221 1223,"
   17723                 :            :                     " 4219 1231, 4224 1243, 4224 1257, 4224 1262, 4224 1345, 4224 1339, 4224 1328, 4215 1335, 4203 1355, 4215 1369,"
   17724                 :            :                     " 4224 1363, 4215 1377, 4208 1387, 4217 1401, 4224 1403, 4224 1520, 4219 1535, 4221 1544, 4199 1593, 4223 1595,"
   17725                 :            :                     " 4206 1626, 4214 1648, 4224 1645, 4224 1640, 4224 2108, 4220 2125, 4224 2125, 4224 2143, 4205 2141, 4180 2159,"
   17726                 :            :                     " 4201 2182, 4163 2189, 4176 2229, 4199 2211, 4210 2218, 4212 2210, 4223 2214, 4224 2207, 4224 2216, 4217 2225,"
   17727                 :            :                     " 4221 2233, 4203 2227, 4209 2248, 4185 2240, 4198 2276, 4144 2218, 4091 2343, 4119 2332, 4121 2347, 4155 2337,"
   17728                 :            :                     " 4180 2355, 4200 2342, 4201 2354, 4213 2352, 4224 2348, 4224 2356, 4207 2361, 4184 2358, 4176 2367, 4106 2355,"
   17729                 :            :                     " 3983 2765, 4050 3151, 4139 2720, 4209 2589, 4211 2600, 4219 2599, 4224 2592, 4224 2574, 4223 2566, 4224 2562,"
   17730                 :            :                     " 4224 2553, 4224 2552, 4224 -128, 4224 4224, 4205 4224, 4015 3513, 3993 3494, 3873 3533, 3887 3539, 3923 3524,"
   17731                 :            :                     " 3950 3529, 4018 3572, 3987 3633, 3983 3571, 3955 3583, 3936 3547, 3882 3539, 3913 3557, 3920 3598, 3901 3596,"
   17732                 :            :                     " 3923 3631, 3914 3628, 3919 3647, 3922 3656, 3917 3666, 3523 3438, 3631 3564, 3527 3597, 3718 3655, 3578 3672,"
   17733                 :            :                     " 3660 3867, 3543 3628, 3416 3725, 3487 3503, 3274 3583, 3271 3644, 3197 3671, 3210 3775, 3184 3788, 3181 3672,"
   17734                 :            :                     " 3306 3521, 3292 3508, 3229 3565, 3219 3564, 3216 3574, 3192 3578, 3297 3444, 3089 3395, 3029 3028, 2973 3133,"
   17735                 :            :                     " 2529 2945, 2538 2811, 2461 2901, 2170 2839, 2121 2797, 2156 2733, 2105 2709, 2096 2695, 2114 2621, 2102 2693,"
   17736                 :            :                     " 2168 2738, 2167 2778, 2447 2765, 2441 2866, 2527 2793, 2670 2938, 2626 2651, 2688 2623, 2740 2922, 3084 2960,"
   17737                 :            :                     " 3116 3071),(4016 1878, 4029 1859, 4008 1839, 4006 1863, 4016 1878),(3315 1339, 3331 1324, 3290 1293, 3305 1315,"
   17738                 :            :                     " 3315 1339),(4136 3071, 4136 3080, 4143 3020, 4137 3036, 4136 3071),(4218 3073, 4183 3114, 4117 3157, 4159 3147,"
   17739                 :            :                     " 4218 3073),(3912 3542, 3934 3536, 3955 3536, 3937 3527, 3900 3540, 3912 3542),(4050 3172, 4043 3210, 4085 3209,"
   17740                 :            :                     " 4090 3179, 4050 3172),(4151 2998, 4158 2977, 4159 2946, 4147 2988, 4151 2998),(2920 3005, 2935 2994, 2864 2973,"
   17741                 :            :                     " 2905 3016, 2920 3005),(3571 2424, 3545 2469, 3608 2480, 3596 2434, 3571 2424),(4095 1229, 4073 1234, 4076 1293,"
   17742                 :            :                     " 4121 1285, 4095 1229),(4173 1536, 4153 1576, 4166 1585, 4198 1571, 4188 1532, 4213 1535, 4224 1512, 4224 1511,"
   17743                 :            :                     " 4209 1511, 4198 1506, 4190 1517, 4194 1509, 4192 1499, 4200 1496, 4202 1504, 4224 1510, 4224 1488, 4215 1486,"
   17744                 :            :                     " 4216 1478, 4224 1472, 4224 1464, 4207 1458, 4193 1464, 4173 1536),(3934 1537, 3968 1630, 3960 1666, 3968 1673,"
   17745                 :            :                     " 3975 1562, 3934 1537),(4182 1653, 4196 1624, 4166 1614, 4157 1674, 4216 1671, 4182 1653),(4200 1619, 4196 1620,"
   17746                 :            :                     " 4200 1632, 4195 1642, 4207 1648, 4200 1619),(4026 1835, 4025 1830, 4016 1808, 4007 1836, 4026 1835),(4199 1384,"
   17747                 :            :                     " 4182 1389, 4206 1412, 4216 1401, 4199 1384),(3926 1251, 3969 1206, 3913 1149, 3878 1173, 3876 1229, 3926 1251),"
   17748                 :            :                     " (3926 1354, 3958 1389, 3997 1384, 3991 1352, 3960 1322, 3955 1299, 3926 1354),(3964 1319, 3974 1329, 3984 1285,"
   17749                 :            :                     " 3963 1301, 3964 1319),(3687 959, 3696 903, 3678 885, 3665 930, 3687 959),(3452 79, 3437 124, 3456 149, 3476 141,"
   17750                 :            :                     " 3452 79),(3751 927, 3738 906, 3719 942, 3739 929, 3751 927))" );
   17751                 :            : 
   17752                 :          1 :   QString poly2Wkt( "Polygon ((-128 4224, -128 2734, -11 2643, -101 2919, 120 2654, 19 2846, 217 2897, -13 2873, -79 2998, -106 2989,"
   17753                 :            :                     " -128 3002, -128 4224, -128 4224, 1249 4224, 1247 4199, 1231 4132, 909 3902, 775 3278, 509 2903, 470 2603, 663 2311,"
   17754                 :            :                     " 889 2134, 989 2146, 534 2585, 575 2880, 833 3112, 833 3037, 1025 2977, 834 3096, 946 3217, 923 3153, 971 3094,"
   17755                 :            :                     " 997 3103, 1166 3423, 1198 3329, 1233 3367, 1270 3327, 1274 3354, 1290 3360, 1321 3322, 1331 3318, 1343 3325,"
   17756                 :            :                     " 1310 3073, 1363 3093, 1413 3186, 1325 3398, 1458 3364, 1493 3426, 1526 3394, 1588 3465, 1417 3824, 1458 3825,"
   17757                 :            :                     " 1522 3849, 1729 3488, 2018 3223, 1908 3291, 1924 3238, 1899 3187, 1913 3150, 2070 3041, 2102 3063, 2112 3053,"
   17758                 :            :                     " 2168 3085, 2101 2994, 2265 2863, 1890 2593, 2106 2713, 2130 2706, 2108 2678, 2117 2647, 2105 2636, 2099 2604,"
   17759                 :            :                     " 2094 2591, 2088 2575, 2088 2564, 2249 2751, 2441 2618, 2689 1728, 2681 2323, 2776 1685, 2711 1708, 2673 1680,"
   17760                 :            :                     " 2675 1639, 2810 1522, 2765 1535, 2734 1510, 2850 1332, 2863 1186, 2847 1025, 2832 985, 2739 1025, 2850 1090,"
   17761                 :            :                     " 2859 1174, 2853 1235, 2827 1235, 2839 1279, 2811 1286, 2751 1272, 2851 1160, 2788 1159, 2724 1204, 2713 1198,"
   17762                 :            :                     " 2708 1213, 2699 1221, 2724 1179, 2797 1145, 2785 1123, 2848 1143, 2821 1092, 2284 980, 2288 963, 2264 962,"
   17763                 :            :                     " 2261 948, 2247 958, 2194 947, 2120 900, 2047 809, 2434 923, 2450 817, 2528 737, 2527 667, 2641 544, 2641 460,"
   17764                 :            :                     " 2710 452, 2687 447, 2681 435, 2693 330, 2772 327, 2766 291, 2779 245, 2769 219, 2771 198, 2816 219, 2781 342,"
   17765                 :            :                     " 2612 647, 2903 188, 2803 539, 2950 206, 2927 342, 3123 339, 3092 300, 3073 175, 3082 160, 3412 -103, 4224 -128,"
   17766                 :            :                     " 4032 167, 3572 63, 3554 109, 3606 211, 3604 232, 3454 124, 3332 345, 3237 212, 3181 415, 2953 364, 2761 692,"
   17767                 :            :                     " 2819 788, 2997 769, 2997 626, 3199 659, 3155 730, 2929 805, 2908 841, 3218 717, 3276 744, 3246 723, 3270 658,"
   17768                 :            :                     " 4223 473, 4224 589, 3906 681, 3818 677, 3915 686, 4224 592, 4224 4224, -128 4224, -128 4224),(2049 3181,"
   17769                 :            :                     " 2224 3084, 2204 3040, 2169 3036, 2174 3084, 2155 3102, 2126 3123, 2109 3127, 2103 3102, 2049 3181),(1578 3811,"
   17770                 :            :                     " 1567 3883, 1675 3768, 1658 3712, 1659 3751, 1578 3811),(2304 2930, 2335 2918, 2287 2880, 2279 2926, 2304 2930),"
   17771                 :            :                     " (2316 2895, 2317 2895, 2316 2901, 2331 2901, 2332 2889, 2316 2895),(2304 2850, 2335 2861, 2344 2910, 2357 2828,"
   17772                 :            :                     " 2304 2850),(1714 3583, 1725 3638, 1682 3717, 1797 3564, 1714 3583),(1537 3873, 1456 3827, 1405 3876, 1461 3898,"
   17773                 :            :                     " 1537 3873),(2547 2560, 2375 2815, 2384 2825, 2470 2722, 2685 2336, 2648 2310, 2547 2560),(2107 3073, 2107 3098,"
   17774                 :            :                     " 2144 3086, 2122 3073, 2113 3059, 2107 3073),(2117 3120, 2156 3099, 2164 3083, 2106 3103, 2117 3120),(2303 2981,"
   17775                 :            :                     " 2226 3010, 2232 3064, 2286 3012, 2344 2928, 2303 2981),(2304 2858, 2291 2864, 2303 2885, 2324 2870, 2304 2858),"
   17776                 :            :                     " (2175 3002, 2179 2983, 2152 2991, 2175 3002, 2175 3002),(2175 3022, 2150 3017, 2144 3048, 2159 3031, 2184 3030,"
   17777                 :            :                     " 2175 3022),(2265 2953, 2270 2950, 2262 2950, 2254 2963, 2253 2979, 2265 2953),(2229 2928, 2250 2928, 2241 2922,"
   17778                 :            :                     " 2239 2914, 2224 2900, 2237 2914, 2229 2928),(2531 2473, 2520 2466, 2521 2474, 2511 2503, 2531 2473),(2547 2526,"
   17779                 :            :                     " 2529 2519, 2528 2541, 2544 2538, 2547 2526),(2559 646, 2513 810, 2463 835, 2462 930, 2746 731, 2559 646),(3840 653,"
   17780                 :            :                     " 3809 641, 3718 689, 3547 733, 3553 712, 3440 780, 3840 653),(3327 741, 3242 750, 3195 745, 3180 758, 3326 764,"
   17781                 :            :                     " 3440 742, 3327 741),(3282 702, 3265 699, 3273 721, 3290 714, 3282 702),(3762 662, 3783 654, 3786 638, 3742 653,"
   17782                 :            :                     " 3762 662),(3071 703, 3082 741, 3079 655, 3064 657, 3071 703),(3881 637, 3904 647, 3914 626, 3861 638, 3881 637))" );
   17783                 :            : 
   17784                 :          1 :   QgsGeometry poly1 = QgsGeometry::fromWkt( poly1Wkt );
   17785                 :          1 :   QgsGeometry poly2 = QgsGeometry::fromWkt( poly2Wkt );
   17786                 :            : 
   17787                 :            :   double distance;
   17788                 :          1 :   QgsPointXY point = poly1.poleOfInaccessibility( 1, &distance ).asPoint();
   17789                 :          1 :   QGSCOMPARENEAR( point.x(), 3867.37, 0.01 );
   17790                 :          1 :   QGSCOMPARENEAR( point.y(), 2126.45, 0.01 );
   17791                 :          1 :   QGSCOMPARENEAR( distance, 289.51, 0.01 );
   17792                 :            : 
   17793                 :          1 :   point = poly1.poleOfInaccessibility( 50 ).asPoint();
   17794                 :          1 :   QGSCOMPARENEAR( point.x(), 3855.33, 0.01 );
   17795                 :          1 :   QGSCOMPARENEAR( point.y(), 2117.55, 0.01 );
   17796                 :            : 
   17797                 :          1 :   point = poly2.poleOfInaccessibility( 1 ).asPoint();
   17798                 :          1 :   QGSCOMPARENEAR( point.x(), 3263.50, 0.01 );
   17799                 :          1 :   QGSCOMPARENEAR( point.y(), 3263.50, 0.01 );
   17800                 :            : 
   17801                 :            :   //test degenerate polygons
   17802                 :          2 :   QgsGeometry degen1 = QgsGeometry::fromWkt( QStringLiteral( "Polygon(( 0 0, 1 0, 2 0, 0 0 ))" ) );
   17803                 :          1 :   point = degen1.poleOfInaccessibility( 1 ).asPoint();
   17804                 :          1 :   QGSCOMPARENEAR( point.x(), 0, 0.01 );
   17805                 :          1 :   QGSCOMPARENEAR( point.y(), 0, 0.01 );
   17806                 :            : 
   17807                 :          2 :   QgsGeometry degen2 = QgsGeometry::fromWkt( QStringLiteral( "Polygon(( 0 0, 1 0, 1 1 , 1 0, 0 0 ))" ) );
   17808                 :          1 :   point = degen2.poleOfInaccessibility( 1 ).asPoint();
   17809                 :          1 :   QGSCOMPARENEAR( point.x(), 0, 0.01 );
   17810                 :          1 :   QGSCOMPARENEAR( point.y(), 0, 0.01 );
   17811                 :            : 
   17812                 :            :   //empty geometry
   17813                 :          1 :   QVERIFY( QgsGeometry().poleOfInaccessibility( 1 ).isNull() );
   17814                 :            : 
   17815                 :            :   // not a polygon
   17816                 :          2 :   QgsGeometry lineString = QgsGeometry::fromWkt( QStringLiteral( "LineString(1 0, 2 2 )" ) );
   17817                 :          1 :   QVERIFY( lineString.poleOfInaccessibility( 1 ).isNull() );
   17818                 :            : 
   17819                 :            :   // invalid threshold
   17820                 :          1 :   QVERIFY( poly1.poleOfInaccessibility( -1 ).isNull() );
   17821                 :          1 :   QVERIFY( poly1.poleOfInaccessibility( 0 ).isNull() );
   17822                 :            : 
   17823                 :            :   // curved geometry
   17824                 :          1 :   QgsGeometry curved = QgsGeometry::fromWkt( "CurvePolygon( CompoundCurve( CircularString(-0.44 0.35, 0.51 0.34, 0.56 0.21, 0.11 -0.33, 0.15 -0.35,"
   17825                 :            :                        "-0.93 -0.30, -1.02 -0.22, -0.49 0.01, -0.23 -0.04),(-0.23 -0.04, -0.44, 0.35)))" );
   17826                 :          1 :   point = curved.poleOfInaccessibility( 0.01 ).asPoint();
   17827                 :          1 :   QGSCOMPARENEAR( point.x(), -0.4324, 0.0001 );
   17828                 :          1 :   QGSCOMPARENEAR( point.y(), -0.2434, 0.0001 );
   17829                 :            : 
   17830                 :            :   // multipolygon
   17831                 :          2 :   QgsGeometry multiPoly = QgsGeometry::fromWkt( QStringLiteral( "MultiPolygon (((0 0, 10 0, 10 10, 0 10, 0 0)),((30 30, 50 30, 50 60, 30 60, 30 30)))" ) );
   17832                 :          1 :   point = multiPoly.poleOfInaccessibility( 0.01, &distance ).asPoint();
   17833                 :          1 :   QGSCOMPARENEAR( point.x(), 40, 0.0001 );
   17834                 :          1 :   QGSCOMPARENEAR( point.y(), 45, 0.0001 );
   17835                 :          1 :   QGSCOMPARENEAR( distance, 10.0, 0.00001 );
   17836                 :          1 : }
   17837                 :            : 
   17838                 :          1 : void TestQgsGeometry::makeValid()
   17839                 :            : {
   17840                 :            :   typedef QPair<QString, QString> InputAndExpectedWktPair;
   17841                 :          1 :   QList<InputAndExpectedWktPair> geoms;
   17842                 :            :   // dimension collapse
   17843                 :          3 :   geoms << qMakePair( QStringLiteral( "LINESTRING(0 0)" ),
   17844                 :          2 :                       QStringLiteral( "POINT(0 0)" ) );
   17845                 :            :   // unclosed ring
   17846                 :          3 :   geoms << qMakePair( QStringLiteral( "POLYGON((10 22,10 32,20 32,20 22))" ),
   17847                 :          2 :                       QStringLiteral( "POLYGON((10 22,10 32,20 32,20 22,10 22))" ) );
   17848                 :            :   // butterfly polygon (self-intersecting ring)
   17849                 :          3 :   geoms << qMakePair( QStringLiteral( "POLYGON((0 0, 10 10, 10 0, 0 10, 0 0))" ),
   17850                 :          2 :                       QStringLiteral( "MULTIPOLYGON(((5 5, 0 0, 0 10, 5 5)),((5 5, 10 10, 10 0, 5 5)))" ) );
   17851                 :            :   // polygon with extra tail (a part of the ring does not form any area)
   17852                 :          3 :   geoms << qMakePair( QStringLiteral( "POLYGON((0 0, 1 0, 1 1, 0 1, 0 0, -1 0, 0 0))" ),
   17853                 :          2 :                       QStringLiteral( "GEOMETRYCOLLECTION(POLYGON((0 0, 0 1, 1 1, 1 0, 0 0)), LINESTRING(0 0, -1 0))" ) );
   17854                 :            :   // collection with invalid geometries
   17855                 :          3 :   geoms << qMakePair( QStringLiteral( "GEOMETRYCOLLECTION(LINESTRING(0 0, 0 0), POLYGON((0 0, 10 10, 10 0, 0 10, 0 0)), LINESTRING(10 0, 10 10))" ),
   17856                 :          2 :                       QStringLiteral( "GEOMETRYCOLLECTION(POINT(0 0), MULTIPOLYGON(((5 5, 0 0, 0 10, 5 5)),((5 5, 10 10, 10 0, 5 5))), LINESTRING(10 0, 10 10))" ) );
   17857                 :            :   // null line (#18077)
   17858                 :          3 :   geoms << qMakePair( QStringLiteral( "MultiLineString ((356984.0625 6300089, 356984.0625 6300089))" ),
   17859                 :          2 :                       QStringLiteral( "MultiPoint ((356984.0625 6300089))" ) );
   17860                 :            : 
   17861                 :          7 :   for ( const InputAndExpectedWktPair &pair : geoms )
   17862                 :            :   {
   17863                 :          6 :     QgsGeometry gInput = QgsGeometry::fromWkt( pair.first );
   17864                 :          6 :     QgsGeometry gExp = QgsGeometry::fromWkt( pair.second );
   17865                 :          6 :     QVERIFY( !gInput.isNull() );
   17866                 :          6 :     QVERIFY( !gExp.isNull() );
   17867                 :            : 
   17868                 :          6 :     QgsGeometry gValid = gInput.makeValid();
   17869                 :          6 :     QVERIFY( gValid.isGeosValid() );
   17870                 :          6 :     QVERIFY( gValid.isGeosEqual( gExp ) );
   17871                 :          6 :   }
   17872                 :          1 : }
   17873                 :            : 
   17874                 :          1 : void TestQgsGeometry::isSimple_data()
   17875                 :            : {
   17876                 :          1 :   QTest::addColumn<QString>( "wkt" );
   17877                 :          1 :   QTest::addColumn<bool>( "simple" );
   17878                 :            : 
   17879                 :          2 :   QTest::newRow( "linestring" ) << QStringLiteral( "LINESTRING(0 0, 1 0, 1 1)" ) << true;
   17880                 :          2 :   QTest::newRow( "may be closed (linear ring)" ) << QStringLiteral( "LINESTRING(0 0, 1 0, 1 1, 0 0)" ) << true;
   17881                 :          2 :   QTest::newRow( "self-intersection" ) << QStringLiteral( "LINESTRING(0 0, 1 0, 1 1, 0 -1)" ) << false;
   17882                 :          2 :   QTest::newRow( "self-tangency" ) << QStringLiteral( "LINESTRING(0 0, 1 0, 1 1, 0.5 0, 0 1)" ) << false;
   17883                 :          2 :   QTest::newRow( "points are simple" ) << QStringLiteral( "POINT(1 1)" ) << true;
   17884                 :          2 :   QTest::newRow( "multipoint" ) << QStringLiteral( "MULTIPOINT((1 1), (2 2))" ) << true;
   17885                 :          2 :   QTest::newRow( "must not contain the same point twice" ) << QStringLiteral( "MULTIPOINT((1 1), (1 1))" ) << false;
   17886                 :          2 :   QTest::newRow( "multiline string simple" ) << QStringLiteral( "MULTILINESTRING((0 0, 1 0), (0 1, 1 1))" ) << true;
   17887                 :          2 :   QTest::newRow( "may be touching at endpoints" ) << QStringLiteral( "MULTILINESTRING((0 0, 1 0), (0 0, 1 0))" ) << true;
   17888                 :          2 :   QTest::newRow( "must not intersect each other" ) << QStringLiteral( "MULTILINESTRING((0 0, 1 1), (0 1, 1 0))" ) << false;
   17889                 :          1 : }
   17890                 :            : 
   17891                 :         10 : void TestQgsGeometry::isSimple()
   17892                 :            : {
   17893                 :         10 :   QFETCH( QString, wkt );
   17894                 :         10 :   QFETCH( bool, simple );
   17895                 :            : 
   17896                 :         10 :   QgsGeometry gInput = QgsGeometry::fromWkt( wkt );
   17897                 :         10 :   QVERIFY( !gInput.isNull() );
   17898                 :            : 
   17899                 :         10 :   bool res = gInput.isSimple();
   17900                 :         10 :   QCOMPARE( res, simple );
   17901                 :         10 : }
   17902                 :            : 
   17903                 :          1 : void TestQgsGeometry::reshapeGeometryLineMerge()
   17904                 :            : {
   17905                 :            :   int res;
   17906                 :          2 :   QgsGeometry g2D = QgsGeometry::fromWkt( QStringLiteral( "LINESTRING(10 10, 20 20)" ) );
   17907                 :          2 :   QgsGeometry g3D = QgsGeometry::fromWkt( QStringLiteral( "LINESTRINGZ(10 10 1, 20 20 2)" ) );
   17908                 :            : 
   17909                 :            :   // prepare 2D reshaping line
   17910                 :          1 :   QgsPointSequence v2D_1, v2D_2;
   17911                 :          1 :   v2D_1 << QgsPoint( 20, 20 ) << QgsPoint( 30, 30 );
   17912                 :          1 :   v2D_2 << QgsPoint( 10, 10 ) << QgsPoint( -10, -10 );
   17913                 :          1 :   QgsLineString line2D_1( v2D_1 ), line2D_2( v2D_2 );
   17914                 :            : 
   17915                 :            :   // prepare 3D reshaping line
   17916                 :          1 :   QgsPointSequence v3D_1, v3D_2;
   17917                 :          1 :   v3D_1 << QgsPoint( QgsWkbTypes::PointZ, 20, 20, 2 ) << QgsPoint( QgsWkbTypes::PointZ, 30, 30, 3 );
   17918                 :          1 :   v3D_2 << QgsPoint( QgsWkbTypes::PointZ, 10, 10, 1 ) << QgsPoint( QgsWkbTypes::PointZ, -10, -10, -1 );
   17919                 :          1 :   QgsLineString line3D_1( v3D_1 ), line3D_2( v3D_2 );
   17920                 :            : 
   17921                 :            :   // append with 2D line
   17922                 :          1 :   QgsGeometry g2D_1 = g2D;
   17923                 :          1 :   res = g2D_1.reshapeGeometry( line2D_1 );
   17924                 :          1 :   QCOMPARE( res, 0 );
   17925                 :          1 :   QCOMPARE( g2D_1.asWkt(), QString( "LineString (10 10, 20 20, 30 30)" ) );
   17926                 :            : 
   17927                 :            :   // prepend with 2D line
   17928                 :          1 :   QgsGeometry g2D_2 = g2D;
   17929                 :          1 :   res = g2D_2.reshapeGeometry( line2D_2 );
   17930                 :          1 :   QCOMPARE( res, 0 );
   17931                 :          1 :   QCOMPARE( g2D_2.asWkt(), QString( "LineString (-10 -10, 10 10, 20 20)" ) );
   17932                 :            : 
   17933                 :            :   // append with 3D line
   17934                 :          1 :   QgsGeometry g3D_1 = g3D;
   17935                 :          1 :   res = g3D_1.reshapeGeometry( line3D_1 );
   17936                 :          1 :   QCOMPARE( res, 0 );
   17937                 :          1 :   QCOMPARE( g3D_1.asWkt(), QString( "LineStringZ (10 10 1, 20 20 2, 30 30 3)" ) );
   17938                 :            : 
   17939                 :            :   // prepend with 3D line
   17940                 :          1 :   QgsGeometry g3D_2 = g3D;
   17941                 :          1 :   res = g3D_2.reshapeGeometry( line3D_2 );
   17942                 :          1 :   QCOMPARE( res, 0 );
   17943                 :          1 :   QCOMPARE( g3D_2.asWkt(), QString( "LineStringZ (-10 -10 -1, 10 10 1, 20 20 2)" ) );
   17944                 :          1 : }
   17945                 :            : 
   17946                 :          1 : void TestQgsGeometry::createCollectionOfType()
   17947                 :            : {
   17948                 :          1 :   std::unique_ptr< QgsGeometryCollection > collect( QgsGeometryFactory::createCollectionOfType( QgsWkbTypes::Unknown ) );
   17949                 :          1 :   QVERIFY( !collect );
   17950                 :          1 :   collect = QgsGeometryFactory::createCollectionOfType( QgsWkbTypes::Point );
   17951                 :          1 :   QCOMPARE( collect->wkbType(), QgsWkbTypes::MultiPoint );
   17952                 :          1 :   QVERIFY( dynamic_cast< QgsMultiPoint *>( collect.get() ) );
   17953                 :          1 :   collect = QgsGeometryFactory::createCollectionOfType( QgsWkbTypes::PointM );
   17954                 :          1 :   QCOMPARE( collect->wkbType(), QgsWkbTypes::MultiPointM );
   17955                 :          1 :   QVERIFY( dynamic_cast< QgsMultiPoint *>( collect.get() ) );
   17956                 :          1 :   collect = QgsGeometryFactory::createCollectionOfType( QgsWkbTypes::PointZM );
   17957                 :          1 :   QCOMPARE( collect->wkbType(), QgsWkbTypes::MultiPointZM );
   17958                 :          1 :   QVERIFY( dynamic_cast< QgsMultiPoint *>( collect.get() ) );
   17959                 :          1 :   collect = QgsGeometryFactory::createCollectionOfType( QgsWkbTypes::PointZ );
   17960                 :          1 :   QCOMPARE( collect->wkbType(), QgsWkbTypes::MultiPointZ );
   17961                 :          1 :   QVERIFY( dynamic_cast< QgsMultiPoint *>( collect.get() ) );
   17962                 :          1 :   collect = QgsGeometryFactory::createCollectionOfType( QgsWkbTypes::MultiPoint );
   17963                 :          1 :   QCOMPARE( collect->wkbType(), QgsWkbTypes::MultiPoint );
   17964                 :          1 :   QVERIFY( dynamic_cast< QgsMultiPoint *>( collect.get() ) );
   17965                 :          1 :   collect = QgsGeometryFactory::createCollectionOfType( QgsWkbTypes::LineStringZ );
   17966                 :          1 :   QCOMPARE( collect->wkbType(), QgsWkbTypes::MultiLineStringZ );
   17967                 :          1 :   QVERIFY( dynamic_cast< QgsMultiLineString *>( collect.get() ) );
   17968                 :          1 :   collect = QgsGeometryFactory::createCollectionOfType( QgsWkbTypes::PolygonM );
   17969                 :          1 :   QCOMPARE( collect->wkbType(), QgsWkbTypes::MultiPolygonM );
   17970                 :          1 :   QVERIFY( dynamic_cast< QgsMultiPolygon *>( collect.get() ) );
   17971                 :          1 :   collect = QgsGeometryFactory::createCollectionOfType( QgsWkbTypes::GeometryCollectionZ );
   17972                 :          1 :   QCOMPARE( collect->wkbType(), QgsWkbTypes::GeometryCollectionZ );
   17973                 :          1 :   QVERIFY( dynamic_cast< QgsGeometryCollection *>( collect.get() ) );
   17974                 :          1 :   collect = QgsGeometryFactory::createCollectionOfType( QgsWkbTypes::CurvePolygonM );
   17975                 :          1 :   QCOMPARE( collect->wkbType(), QgsWkbTypes::MultiSurfaceM );
   17976                 :          1 :   QVERIFY( dynamic_cast< QgsMultiSurface *>( collect.get() ) );
   17977                 :          1 : }
   17978                 :            : 
   17979                 :          1 : void TestQgsGeometry::orientedMinimumBoundingBox()
   17980                 :            : {
   17981                 :          1 :   QgsGeometry geomTest;
   17982                 :          1 :   QgsGeometry result, resultTest;
   17983                 :            :   // empty
   17984                 :          1 :   result = geomTest.orientedMinimumBoundingBox( );
   17985                 :          1 :   QVERIFY( result.isEmpty() );
   17986                 :            : 
   17987                 :            :   // oriented rectangle
   17988                 :          2 :   geomTest = QgsGeometry::fromWkt( QStringLiteral( " Polygon(0 0, 5 5, -2.07106781186547462 12.07106781186547551, -7.07106781186547462 7.07106781186547551, 0 0) " ) );
   17989                 :          1 :   result = geomTest.orientedMinimumBoundingBox( );
   17990                 :          1 :   QgsPolygonXY geomXY, resultXY;
   17991                 :          1 :   geomXY = geomTest.asPolygon();
   17992                 :          1 :   resultXY = result.asPolygon();
   17993                 :            : 
   17994                 :          1 :   QCOMPARE( geomXY.count(), resultXY.count() );
   17995                 :            :   // can't strictly compare, use tolerance
   17996                 :          1 :   for ( int i = 0 ; i < geomXY.count() ; ++i )
   17997                 :            :   {
   17998                 :          0 :     QVERIFY( geomXY.at( 0 ).at( i ).compare( resultXY.at( 0 ).at( i ), 1E-8 ) );
   17999                 :          0 :   }
   18000                 :            : 
   18001                 :            :   // Issue https://github.com/qgis/QGIS/issues/33532
   18002                 :          2 :   geomTest = QgsGeometry::fromWkt( QStringLiteral( " Polygon ((264 -525, 248 -521, 244 -519, 233 -508, 231 -504, 210 -445, 196 -396, 180 -332, 178 -322, 176 -310, 174 -296, 174 -261, 176 -257, 178 -255, 183 -251, 193 -245, 197 -243, 413 -176, 439 -168, 447 -166, 465 -164, 548 -164, 552 -166, 561 -175, 567 -187, 602 -304, 618 -379, 618 -400, 616 -406, 612 -414, 606 -420, 587 -430, 575 -436, 547 -446, 451 -474, 437 -478, 321 -511, 283 -521, 275 -523, 266 -525, 264 -525)) " ) );
   18003                 :          1 :   result = geomTest.orientedMinimumBoundingBox( );
   18004                 :          2 :   QString resultTestWKT = QStringLiteral( "Polygon ((635.86 -420.08, 552.66 -134.85, 153.5 -251.27, 236.69 -536.51, 635.86 -420.08))" );
   18005                 :          1 :   QCOMPARE( result.asWkt( 2 ), resultTestWKT );
   18006                 :            : 
   18007                 :          1 : }
   18008                 :          1 : void TestQgsGeometry::minimalEnclosingCircle()
   18009                 :            : {
   18010                 :          1 :   QgsGeometry geomTest;
   18011                 :          1 :   QgsGeometry result, resultTest;
   18012                 :          1 :   QgsPointXY center;
   18013                 :            :   double radius;
   18014                 :            : 
   18015                 :            :   // empty
   18016                 :          1 :   result = geomTest.minimalEnclosingCircle( center, radius );
   18017                 :          1 :   QCOMPARE( center, QgsPointXY() );
   18018                 :          1 :   QCOMPARE( radius, 0.0 );
   18019                 :          1 :   QVERIFY( result.isNull() );
   18020                 :            : 
   18021                 :            :   // case 1
   18022                 :          1 :   geomTest = QgsGeometry::fromPointXY( QgsPointXY( 5, 5 ) );
   18023                 :          1 :   result = geomTest.minimalEnclosingCircle( center, radius );
   18024                 :          1 :   QCOMPARE( center, QgsPointXY( 5, 5 ) );
   18025                 :          1 :   QCOMPARE( radius, 0.0 );
   18026                 :          1 :   resultTest.set( QgsCircle( QgsPoint( center ), radius ).toPolygon( 36 ) );
   18027                 :          1 :   QCOMPARE( result.asWkt(), resultTest.asWkt() );
   18028                 :            : 
   18029                 :            :   // case 2
   18030                 :          2 :   geomTest = QgsGeometry::fromWkt( QStringLiteral( "MULTIPOINT( 3 8, 7 4 )" ) );
   18031                 :          1 :   result = geomTest.minimalEnclosingCircle( center, radius, 6 );
   18032                 :          1 :   QGSCOMPARENEARPOINT( center, QgsPointXY( 5, 6 ), 0.0001 );
   18033                 :          1 :   QGSCOMPARENEAR( radius, sqrt( 2 ) * 2, 0.0001 );
   18034                 :          2 :   QCOMPARE( result.asWkt( 1 ), QStringLiteral( "Polygon ((7 4, 4.3 3.3, 2.3 5.3, 3 8, 5.7 8.7, 7.7 6.7, 7 4))" ) );
   18035                 :            : 
   18036                 :          2 :   geomTest = QgsGeometry::fromWkt( QStringLiteral( "LINESTRING( 0 5, 2 2, 0 -5, -1 -1 )" ) );
   18037                 :          1 :   result = geomTest.minimalEnclosingCircle( center, radius, 6 );
   18038                 :          1 :   QGSCOMPARENEARPOINT( center, QgsPointXY( 0, 0 ), 0.0001 );
   18039                 :          1 :   QGSCOMPARENEAR( radius, 5, 0.0001 );
   18040                 :          2 :   QCOMPARE( result.asWkt( 1 ), QStringLiteral( "Polygon ((0 5, 4.3 2.5, 4.3 -2.5, 0 -5, -4.3 -2.5, -4.3 2.5, 0 5))" ) );
   18041                 :            : 
   18042                 :          2 :   geomTest = QgsGeometry::fromWkt( QStringLiteral( "MULTIPOINT( 0 5, 2 2, 0 -5, -1 -1 )" ) );
   18043                 :          1 :   result = geomTest.minimalEnclosingCircle( center, radius, 6 );
   18044                 :          1 :   QGSCOMPARENEARPOINT( center, QgsPointXY( 0, 0 ), 0.0001 );
   18045                 :          1 :   QGSCOMPARENEAR( radius, 5, 0.0001 );
   18046                 :          2 :   QCOMPARE( result.asWkt( 1 ), QStringLiteral( "Polygon ((0 5, 4.3 2.5, 4.3 -2.5, 0 -5, -4.3 -2.5, -4.3 2.5, 0 5))" ) );
   18047                 :            : 
   18048                 :          2 :   geomTest = QgsGeometry::fromWkt( QStringLiteral( "POLYGON(( 0 5, 2 2, 0 -5, -1 -1 ))" ) );
   18049                 :          1 :   result = geomTest.minimalEnclosingCircle( center, radius, 6 );
   18050                 :          1 :   QGSCOMPARENEARPOINT( center, QgsPointXY( 0, 0 ), 0.0001 );
   18051                 :          1 :   QGSCOMPARENEAR( radius, 5, 0.0001 );
   18052                 :          1 :   resultTest.set( QgsCircle( QgsPoint( center ), radius ).toPolygon( 36 ) );
   18053                 :          2 :   QCOMPARE( result.asWkt( 1 ), QStringLiteral( "Polygon ((0 5, 4.3 2.5, 4.3 -2.5, 0 -5, -4.3 -2.5, -4.3 2.5, 0 5))" ) );
   18054                 :            : 
   18055                 :          2 :   geomTest = QgsGeometry::fromWkt( QStringLiteral( "MULTIPOINT( 0 5, 0 -5, 0 0 )" ) );
   18056                 :          1 :   result = geomTest.minimalEnclosingCircle( center, radius, 6 );
   18057                 :          1 :   QGSCOMPARENEARPOINT( center, QgsPointXY( 0, 0 ), 0.0001 );
   18058                 :          1 :   QGSCOMPARENEAR( radius, 5, 0.0001 );
   18059                 :          1 :   resultTest.set( QgsCircle( QgsPoint( center ), radius ).toPolygon( 36 ) );
   18060                 :          2 :   QCOMPARE( result.asWkt( 1 ), QStringLiteral( "Polygon ((0 5, 4.3 2.5, 4.3 -2.5, 0 -5, -4.3 -2.5, -4.3 2.5, 0 5))" ) );
   18061                 :            : 
   18062                 :            :   // case 3
   18063                 :          2 :   geomTest = QgsGeometry::fromWkt( QStringLiteral( "MULTIPOINT((0 0), (5 5), (0 -5), (0 5), (-5 0))" ) );
   18064                 :          1 :   result = geomTest.minimalEnclosingCircle( center, radius, 6 );
   18065                 :          1 :   QGSCOMPARENEARPOINT( center, QgsPointXY( 0.8333, 0.8333 ), 0.0001 );
   18066                 :          1 :   QGSCOMPARENEAR( radius, 5.8926, 0.0001 );
   18067                 :          1 :   resultTest.set( QgsCircle( QgsPoint( center ), radius ).toPolygon( 36 ) );
   18068                 :          2 :   QCOMPARE( result.asWkt( 1 ), QStringLiteral( "Polygon ((0.8 6.7, 5.9 3.8, 5.9 -2.1, 0.8 -5.1, -4.3 -2.1, -4.3 3.8, 0.8 6.7))" ) );
   18069                 :            : 
   18070                 :          1 : }
   18071                 :            : 
   18072                 :          1 : void TestQgsGeometry::splitGeometry()
   18073                 :            : {
   18074                 :          1 :   QVector<QgsGeometry> newGeoms;
   18075                 :          1 :   QgsPointSequence testPoints;
   18076                 :          1 :   qDebug() << GEOSversion() << "\n";
   18077                 :          2 :   QgsGeometry g1 = QgsGeometry::fromWkt( QStringLiteral( "Polygon ((492980.38648063864093274 7082334.45244149677455425, 493082.65415841294452548 7082319.87918917648494244, 492980.38648063858272508 7082334.45244149677455425, 492980.38648063864093274 7082334.45244149677455425))" ) );
   18078                 :            :   if ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR < 9 )
   18079                 :            :   {
   18080                 :            :     QCOMPARE( g1.splitGeometry( QgsPointSequence() << QgsPoint( 493825.46541286131832749, 7082214.02779923938214779 ) << QgsPoint( 492955.04876351181883365, 7082338.06309300474822521 ),
   18081                 :            :                                 newGeoms, false, testPoints ), QgsGeometry::NothingHappened );
   18082                 :            :   }
   18083                 :            :   else
   18084                 :            :   {
   18085                 :          1 :     QCOMPARE( g1.splitGeometry( QgsPointSequence() << QgsPoint( 493825.46541286131832749, 7082214.02779923938214779 ) << QgsPoint( 492955.04876351181883365, 7082338.06309300474822521 ),
   18086                 :            :                                 newGeoms, false, testPoints ), QgsGeometry::InvalidBaseGeometry );
   18087                 :            :   }
   18088                 :          1 :   QVERIFY( newGeoms.isEmpty() );
   18089                 :            : 
   18090                 :            :   // Bug https://github.com/qgis/QGIS/issues/33489
   18091                 :          1 :   QgsGeometry g2 = QgsGeometry::fromWkt( "CompoundCurveZ ((2749546.2003820720128715 1262904.45356595050543547 100, 2749557.82053794478997588 1262920.05570670193992555 200))" );
   18092                 :          1 :   testPoints.clear();
   18093                 :          1 :   newGeoms.clear();
   18094                 :          1 :   QCOMPARE( g2.splitGeometry( QgsPointSequence() << QgsPoint( 2749544.19, 1262914.79, 0 ) << QgsPoint( 2749557.64, 1262897.30, 0 ), newGeoms, false, testPoints ), QgsGeometry::Success );
   18095                 :          1 :   QVERIFY( newGeoms.count() == 1 );
   18096                 :          2 :   QCOMPARE( newGeoms[0].asWkt( 2 ), QStringLiteral( "LineStringZ (2749549.12 1262908.38 125.14, 2749557.82 1262920.06 200)" ) );
   18097                 :            : 
   18098                 :            :   // Test split geometry with topological editing
   18099                 :          1 :   QVector<QgsPointXY> testPointsXY;
   18100                 :          1 :   testPoints.clear();
   18101                 :          1 :   newGeoms.clear();
   18102                 :          2 :   g1 = QgsGeometry::fromWkt( QStringLiteral( "Polygon ((1.0 1.0, 1.0 100.0, 100.0 100.0, 100.0 1.0, 1.0 1.0))" ) );
   18103                 :          1 :   QCOMPARE( g1.splitGeometry( QgsPointSequence() << QgsPoint( 0.0, 42.0 ) << QgsPoint( 101.0, 42.0 ), newGeoms, true, testPoints ), QgsGeometry::Success );
   18104                 :          1 :   QCOMPARE( newGeoms.count(), 1 );
   18105                 :          1 :   QCOMPARE( testPoints.count(), 2 );
   18106                 :          1 :   QgsGeometry::convertPointList( testPoints, testPointsXY );
   18107                 :          2 :   QVERIFY( QgsGeometry::fromWkt( QStringLiteral( "Linestring (1.0 42.0, 100.0 42.0)" ) ).touches( QgsGeometry::fromPointXY( testPointsXY.at( 0 ) ) ) );
   18108                 :          2 :   QVERIFY( QgsGeometry::fromWkt( QStringLiteral( "Linestring (1.0 42.0, 100.0 42.0)" ) ).touches( QgsGeometry::fromPointXY( testPointsXY.at( 1 ) ) ) );
   18109                 :            : 
   18110                 :          1 :   testPointsXY.clear();
   18111                 :          1 :   testPoints.clear();
   18112                 :          1 :   newGeoms.clear();
   18113                 :          2 :   g1 = QgsGeometry::fromWkt( QStringLiteral( "Linestring (1.0 1.0, 1.0 100.0, 100.0 100.0, 100.0 1.0, 1.0 1.0)" ) );
   18114                 :          1 :   QCOMPARE( g1.splitGeometry( QgsPointSequence() << QgsPoint( 0.0, 42.0 ) << QgsPoint( 101.0, 42.0 ), newGeoms, true, testPoints ), QgsGeometry::Success );
   18115                 :          1 :   QCOMPARE( newGeoms.count(), 2 );
   18116                 :          1 :   QCOMPARE( testPoints.count(), 2 );
   18117                 :          1 :   QgsGeometry::convertPointList( testPoints, testPointsXY );
   18118                 :          2 :   QVERIFY( QgsGeometry::fromWkt( QStringLiteral( "Linestring (1.0 42.0, 100.0 42.0)" ) ).touches( QgsGeometry::fromPointXY( testPointsXY.at( 0 ) ) ) );
   18119                 :          2 :   QVERIFY( QgsGeometry::fromWkt( QStringLiteral( "Linestring (1.0 42.0, 100.0 42.0)" ) ).touches( QgsGeometry::fromPointXY( testPointsXY.at( 1 ) ) ) );
   18120                 :            : 
   18121                 :            :   // Test split parts with topological editing
   18122                 :          1 :   testPointsXY.clear();
   18123                 :          1 :   testPoints.clear();
   18124                 :          1 :   newGeoms.clear();
   18125                 :          2 :   g1 = QgsGeometry::fromWkt( QStringLiteral( "Polygon ((1.0 1.0, 1.0 100.0, 100.0 100.0, 100.0 1.0, 1.0 1.0))" ) );
   18126                 :          1 :   QCOMPARE( g1.splitGeometry( QgsPointSequence() << QgsPoint( 0.0, 42.0 ) << QgsPoint( 101.0, 42.0 ), newGeoms, true, testPoints, false ), QgsGeometry::Success );
   18127                 :          1 :   QCOMPARE( newGeoms.count(), 2 );
   18128                 :          1 :   QCOMPARE( testPoints.count(), 2 );
   18129                 :          1 :   QgsGeometry::convertPointList( testPoints, testPointsXY );
   18130                 :          2 :   QVERIFY( QgsGeometry::fromWkt( QStringLiteral( "Linestring (1.0 42.0, 100.0 42.0)" ) ).touches( QgsGeometry::fromPointXY( testPointsXY.at( 0 ) ) ) );
   18131                 :          2 :   QVERIFY( QgsGeometry::fromWkt( QStringLiteral( "Linestring (1.0 42.0, 100.0 42.0)" ) ).touches( QgsGeometry::fromPointXY( testPointsXY.at( 1 ) ) ) );
   18132                 :            : 
   18133                 :          1 :   testPointsXY.clear();
   18134                 :          1 :   testPoints.clear();
   18135                 :          1 :   newGeoms.clear();
   18136                 :          2 :   g1 = QgsGeometry::fromWkt( QStringLiteral( "Linestring (1.0 1.0, 1.0 100.0, 100.0 100.0, 100.0 1.0, 1.0 1.0)" ) );
   18137                 :          1 :   QCOMPARE( g1.splitGeometry( QgsPointSequence() << QgsPoint( 0.0, 42.0 ) << QgsPoint( 101.0, 42.0 ), newGeoms, true, testPoints, false ), QgsGeometry::Success );
   18138                 :          1 :   QCOMPARE( newGeoms.count(), 3 );
   18139                 :          1 :   QCOMPARE( testPoints.count(), 2 );
   18140                 :          1 :   QgsGeometry::convertPointList( testPoints, testPointsXY );
   18141                 :          2 :   QVERIFY( QgsGeometry::fromWkt( QStringLiteral( "Linestring (1.0 42.0, 100.0 42.0)" ) ).touches( QgsGeometry::fromPointXY( testPointsXY.at( 0 ) ) ) );
   18142                 :          2 :   QVERIFY( QgsGeometry::fromWkt( QStringLiteral( "Linestring (1.0 42.0, 100.0 42.0)" ) ).touches( QgsGeometry::fromPointXY( testPointsXY.at( 1 ) ) ) );
   18143                 :            : 
   18144                 :            :   // Repeat previous tests with QVector<QgsPointXY> instead of QgsPointSequence
   18145                 :            :   // Those tests are for the deprecated QgsGeometry::splitGeometry() variant and should be removed in QGIS 4.0
   18146                 :            :   Q_NOWARN_DEPRECATED_PUSH
   18147                 :          1 :   testPointsXY.clear();
   18148                 :          1 :   newGeoms.clear();
   18149                 :          2 :   g1 = QgsGeometry::fromWkt( QStringLiteral( "Polygon ((1.0 1.0, 1.0 100.0, 100.0 100.0, 100.0 1.0, 1.0 1.0))" ) );
   18150                 :          1 :   QCOMPARE( g1.splitGeometry( QgsPolylineXY() << QgsPointXY( 0.0, 42.0 ) << QgsPointXY( 101.0, 42.0 ), newGeoms, true, testPointsXY ), QgsGeometry::Success );
   18151                 :          1 :   QCOMPARE( newGeoms.count(), 1 );
   18152                 :          1 :   QCOMPARE( testPointsXY.count(), 2 );
   18153                 :          2 :   QVERIFY( QgsGeometry::fromWkt( QStringLiteral( "Linestring (1.0 42.0, 100.0 42.0)" ) ).touches( QgsGeometry::fromPointXY( testPointsXY.at( 0 ) ) ) );
   18154                 :          2 :   QVERIFY( QgsGeometry::fromWkt( QStringLiteral( "Linestring (1.0 42.0, 100.0 42.0)" ) ).touches( QgsGeometry::fromPointXY( testPointsXY.at( 1 ) ) ) );
   18155                 :            : 
   18156                 :          1 :   testPointsXY.clear();
   18157                 :          1 :   newGeoms.clear();
   18158                 :          2 :   g1 = QgsGeometry::fromWkt( QStringLiteral( "Linestring (1.0 1.0, 1.0 100.0, 100.0 100.0, 100.0 1.0, 1.0 1.0)" ) );
   18159                 :          1 :   QCOMPARE( g1.splitGeometry( QgsPolylineXY() << QgsPointXY( 0.0, 42.0 ) << QgsPointXY( 101.0, 42.0 ), newGeoms, true, testPointsXY ), QgsGeometry::Success );
   18160                 :          1 :   QCOMPARE( newGeoms.count(), 2 );
   18161                 :          1 :   QCOMPARE( testPointsXY.count(), 2 );
   18162                 :          2 :   QVERIFY( QgsGeometry::fromWkt( QStringLiteral( "Linestring (1.0 42.0, 100.0 42.0)" ) ).touches( QgsGeometry::fromPointXY( testPointsXY.at( 0 ) ) ) );
   18163                 :          2 :   QVERIFY( QgsGeometry::fromWkt( QStringLiteral( "Linestring (1.0 42.0, 100.0 42.0)" ) ).touches( QgsGeometry::fromPointXY( testPointsXY.at( 1 ) ) ) );
   18164                 :            : 
   18165                 :            :   // Test split parts with topological editing
   18166                 :          1 :   testPointsXY.clear();
   18167                 :          1 :   newGeoms.clear();
   18168                 :          2 :   g1 = QgsGeometry::fromWkt( QStringLiteral( "Polygon ((1.0 1.0, 1.0 100.0, 100.0 100.0, 100.0 1.0, 1.0 1.0))" ) );
   18169                 :          1 :   QCOMPARE( g1.splitGeometry( QgsPolylineXY() << QgsPointXY( 0.0, 42.0 ) << QgsPointXY( 101.0, 42.0 ), newGeoms, true, testPointsXY, false ), QgsGeometry::Success );
   18170                 :          1 :   QCOMPARE( newGeoms.count(), 2 );
   18171                 :          1 :   QCOMPARE( testPointsXY.count(), 2 );
   18172                 :          2 :   QVERIFY( QgsGeometry::fromWkt( QStringLiteral( "Linestring (1.0 42.0, 100.0 42.0)" ) ).touches( QgsGeometry::fromPointXY( testPointsXY.at( 0 ) ) ) );
   18173                 :          2 :   QVERIFY( QgsGeometry::fromWkt( QStringLiteral( "Linestring (1.0 42.0, 100.0 42.0)" ) ).touches( QgsGeometry::fromPointXY( testPointsXY.at( 1 ) ) ) );
   18174                 :            : 
   18175                 :          1 :   testPointsXY.clear();
   18176                 :          1 :   newGeoms.clear();
   18177                 :          2 :   g1 = QgsGeometry::fromWkt( QStringLiteral( "Linestring (1.0 1.0, 1.0 100.0, 100.0 100.0, 100.0 1.0, 1.0 1.0)" ) );
   18178                 :          1 :   QCOMPARE( g1.splitGeometry( QgsPolylineXY() << QgsPointXY( 0.0, 42.0 ) << QgsPointXY( 101.0, 42.0 ), newGeoms, true, testPointsXY, false ), QgsGeometry::Success );
   18179                 :          1 :   QCOMPARE( newGeoms.count(), 3 );
   18180                 :          1 :   QCOMPARE( testPointsXY.count(), 2 );
   18181                 :          2 :   QVERIFY( QgsGeometry::fromWkt( QStringLiteral( "Linestring (1.0 42.0, 100.0 42.0)" ) ).touches( QgsGeometry::fromPointXY( testPointsXY.at( 0 ) ) ) );
   18182                 :          2 :   QVERIFY( QgsGeometry::fromWkt( QStringLiteral( "Linestring (1.0 42.0, 100.0 42.0)" ) ).touches( QgsGeometry::fromPointXY( testPointsXY.at( 1 ) ) ) );
   18183                 :            :   Q_NOWARN_DEPRECATED_POP
   18184                 :          1 : }
   18185                 :            : 
   18186                 :          1 : void TestQgsGeometry::snappedToGrid()
   18187                 :            : {
   18188                 :            :   // points
   18189                 :            :   {
   18190                 :         10 :     auto check = []( QgsPoint * _a, QgsPoint const & b )
   18191                 :            :     {
   18192                 :         10 :       std::unique_ptr<QgsPoint> a {_a};
   18193                 :            :       // because it is to check after snapping, there shouldn't be small precision errors
   18194                 :            : 
   18195                 :         10 :       if ( !std::isnan( b.x() ) )
   18196                 :         10 :         QVERIFY( ( float )a->x() == ( float )b.x() );
   18197                 :            : 
   18198                 :         10 :       if ( !std::isnan( b.y() ) )
   18199                 :         10 :         QVERIFY( ( float )a->y() == ( float )b.y() );
   18200                 :            : 
   18201                 :         10 :       if ( !std::isnan( b.z() ) )
   18202                 :          3 :         QVERIFY( ( float )a->z() == ( float )b.z() );
   18203                 :            : 
   18204                 :         10 :       if ( !std::isnan( b.m() ) )
   18205                 :          3 :         QVERIFY( ( float )a->m() == ( float )b.m() );
   18206                 :         10 :     };
   18207                 :            : 
   18208                 :            : 
   18209                 :          2 :     check( QgsPoint( 0, 0 ).snappedToGrid( 1, 1 ),
   18210                 :          1 :            QgsPoint( 0, 0 ) );
   18211                 :            : 
   18212                 :          2 :     check( QgsPoint( 1, 2.732 ).snappedToGrid( 1, 1 ),
   18213                 :          1 :            QgsPoint( 1, 3 ) );
   18214                 :            : 
   18215                 :          2 :     check( QgsPoint( 1.3, 6.4 ).snappedToGrid( 1, 1 ),
   18216                 :          1 :            QgsPoint( 1, 6 ) );
   18217                 :            : 
   18218                 :          2 :     check( QgsPoint( 1.3, 6.4 ).snappedToGrid( 1, 0 ),
   18219                 :          1 :            QgsPoint( 1, 6.4 ) );
   18220                 :            : 
   18221                 :            : 
   18222                 :            :     // multiple checks with the same point
   18223                 :          1 :     auto p1 = QgsPoint( 1.38, 2.4432 );
   18224                 :            : 
   18225                 :          2 :     check( p1.snappedToGrid( 1, 1 ),
   18226                 :          1 :            QgsPoint( 1, 2 ) );
   18227                 :            : 
   18228                 :          2 :     check( p1.snappedToGrid( 1, 0.1 ),
   18229                 :          1 :            QgsPoint( 1, 2.4 ) );
   18230                 :            : 
   18231                 :          2 :     check( p1.snappedToGrid( 1, 0.01 ),
   18232                 :          1 :            QgsPoint( 1, 2.44 ) );
   18233                 :            : 
   18234                 :            :     // Let's test more dimensions
   18235                 :          1 :     auto p2 = QgsPoint( 4.2134212, 543.1231, 0.123, 12.944145 );
   18236                 :            : 
   18237                 :          1 :     check( p2.snappedToGrid( 0, 0, 0, 0 ),
   18238                 :            :            p2 );
   18239                 :            : 
   18240                 :          2 :     check( p2.snappedToGrid( 0, 0, 1, 1 ),
   18241                 :          1 :            QgsPoint( 4.2134212, 543.1231, 0, 13 ) );
   18242                 :            : 
   18243                 :          2 :     check( p2.snappedToGrid( 1, 0.1, 0.01, 0.001 ),
   18244                 :          1 :            QgsPoint( 4, 543.1, 0.12, 12.944 ) );
   18245                 :            : 
   18246                 :          1 :   }
   18247                 :            : 
   18248                 :            :   // MultiPolygon (testing QgsCollection, QgsCurvePolygon and QgsLineString)
   18249                 :            :   {
   18250                 :            :     /*
   18251                 :            :      * List of tested edge cases:
   18252                 :            :      *
   18253                 :            :      * - QgsLineString becoming a point
   18254                 :            :      * - QgsLineString losing enough points so it is no longer closed
   18255                 :            :      * - QgsCurvePolygon losing its external ring
   18256                 :            :      * - QgsCurvePolygon losing an internal ring
   18257                 :            :      * - QgsCurvePolygon losing all internal rings
   18258                 :            :      * - QgsCollection losing one of its members
   18259                 :            :      * - QgsCollection losing all its members
   18260                 :            :      */
   18261                 :            : 
   18262                 :          1 :     auto in = QString( "MultiPolygon (((-1.2 -0.87, -0.943 0.8, 0.82 1.4, 1.2 0.9, 0.9 -0.6, -1.2 -0.87),(0.4 0, -0.4 0, 0 0.2, 0.4 0)),((2 0, 2.2 0.2, 2.2 -0.2)),((3 0, 4 0.2, 4 -0.2, 3 0)),((4 8, 3.6 4.1, 0.3 4.9, -0.2 7.8, 4 8),(6.7 7.3, 7 6.4, 5.6 5.9, 6.2 6.8, 6.7 7.3),(6 5.2, 4.9 5.3, 4.8 6.2, 6 5.2)))" );
   18263                 :          1 :     auto out = QString( "MultiPolygon (((-1 -1, -1 1, 1 1, 1 -1, -1 -1)),((4 8, 4 4, 0 5, 0 8, 4 8),(7 7, 7 6, 6 6, 6 7, 7 7),(6 5, 5 5, 5 6, 6 5)))" );
   18264                 :            : 
   18265                 :          1 :     auto inGeom = QgsGeometryFactory::geomFromWkt( in );
   18266                 :            : 
   18267                 :          1 :     std::unique_ptr<QgsAbstractGeometry> snapped { inGeom->snappedToGrid( 1, 1 ) };
   18268                 :          1 :     QCOMPARE( snapped->asWkt( 5 ), out );
   18269                 :          1 :   }
   18270                 :            : 
   18271                 :            :   {
   18272                 :            :     // Curves
   18273                 :          1 :     QgsGeometry curve = QgsGeometry::fromWkt( "CircularString( 68.1 415.2, 27.1 505.2, 27.1 406.2 )" );
   18274                 :          1 :     std::unique_ptr<QgsAbstractGeometry> snapped { curve.constGet()->snappedToGrid( 1, 1 ) };
   18275                 :          2 :     QCOMPARE( snapped->asWkt( 5 ), QStringLiteral( "CircularString (68 415, 27 505, 27 406)" ) );
   18276                 :          1 :     snapped.reset( curve.constGet()->snappedToGrid( 10, 1 ) );
   18277                 :          2 :     QCOMPARE( snapped->asWkt( 5 ), QStringLiteral( "CircularString (70 415, 30 505, 30 406)" ) );
   18278                 :          1 :     snapped.reset( curve.constGet()->snappedToGrid( 1, 10 ) );
   18279                 :          2 :     QCOMPARE( snapped->asWkt( 5 ), QStringLiteral( "CircularString (68 420, 27 510, 27 410)" ) );
   18280                 :          1 :     snapped.reset( curve.constGet()->snappedToGrid( 0, 0 ) );
   18281                 :          2 :     QCOMPARE( snapped->asWkt( 5 ), QStringLiteral( "CircularString (68.1 415.2, 27.1 505.2, 27.1 406.2)" ) );
   18282                 :            : 
   18283                 :          1 :     curve = QgsGeometry::fromWkt( "CircularString (68.1 415.2, 27.1 505.2, 27.1 406.2, 35.1 410.1, 39.2 403.2)" );
   18284                 :          1 :     snapped.reset( curve.constGet()->snappedToGrid( 1, 1 ) );
   18285                 :          2 :     QCOMPARE( snapped->asWkt( 5 ), QStringLiteral( "CircularString (68 415, 27 505, 27 406, 35 410, 39 403)" ) );
   18286                 :          1 :   }
   18287                 :            : 
   18288                 :            :   {
   18289                 :            :     // Lines
   18290                 :          1 :     QgsGeometry curve = QgsGeometry::fromWkt( "LineString( 68.1 415.2, 27.1 505.2, 27.1 406.2 )" );
   18291                 :          1 :     std::unique_ptr<QgsAbstractGeometry> snapped { curve.constGet()->snappedToGrid( 1, 1 ) };
   18292                 :          2 :     QCOMPARE( snapped->asWkt( 5 ), QStringLiteral( "LineString (68 415, 27 505, 27 406)" ) );
   18293                 :          1 :     snapped.reset( curve.constGet()->snappedToGrid( 10, 1 ) );
   18294                 :          2 :     QCOMPARE( snapped->asWkt( 5 ), QStringLiteral( "LineString (70 415, 30 505, 30 406)" ) );
   18295                 :          1 :     snapped.reset( curve.constGet()->snappedToGrid( 1, 10 ) );
   18296                 :          2 :     QCOMPARE( snapped->asWkt( 5 ), QStringLiteral( "LineString (68 420, 27 510, 27 410)" ) );
   18297                 :            : 
   18298                 :          1 :     snapped.reset( curve.constGet()->snappedToGrid( 0, 1 ) );
   18299                 :          2 :     QCOMPARE( snapped->asWkt( 5 ), QStringLiteral( "LineString (68.1 415, 27.1 505, 27.1 406)" ) );
   18300                 :          1 :     snapped.reset( curve.constGet()->snappedToGrid( 1, 0 ) );
   18301                 :          2 :     QCOMPARE( snapped->asWkt( 5 ), QStringLiteral( "LineString (68 415.2, 27 505.2, 27 406.2)" ) );
   18302                 :            : 
   18303                 :          1 :     curve = QgsGeometry::fromWkt( "LineStringZ (68.1 415.2 11.2, 27.1 505.2 23.6, 27.1 406.2 39.9)" );
   18304                 :          1 :     snapped.reset( curve.constGet()->snappedToGrid( 1, 1 ) );
   18305                 :          2 :     QCOMPARE( snapped->asWkt( 5 ), QStringLiteral( "LineStringZ (68 415 11.2, 27 505 23.6, 27 406 39.9)" ) );
   18306                 :          1 :     snapped.reset( curve.constGet()->snappedToGrid( 1, 1, 1 ) );
   18307                 :          2 :     QCOMPARE( snapped->asWkt( 5 ), QStringLiteral( "LineStringZ (68 415 11, 27 505 24, 27 406 40)" ) );
   18308                 :          1 :     snapped.reset( curve.constGet()->snappedToGrid( 1, 1, 10 ) );
   18309                 :          2 :     QCOMPARE( snapped->asWkt( 5 ), QStringLiteral( "LineStringZ (68 415 10, 27 505 20, 27 406 40)" ) );
   18310                 :            : 
   18311                 :          1 :     curve = QgsGeometry::fromWkt( "LineStringM (68.1 415.2 11.2, 27.1 505.2 23.6, 27.1 406.2 39.9)" );
   18312                 :          1 :     snapped.reset( curve.constGet()->snappedToGrid( 1, 1 ) );
   18313                 :          2 :     QCOMPARE( snapped->asWkt( 5 ), QStringLiteral( "LineStringM (68 415 11.2, 27 505 23.6, 27 406 39.9)" ) );
   18314                 :          1 :     snapped.reset( curve.constGet()->snappedToGrid( 1, 1, 0, 1 ) );
   18315                 :          2 :     QCOMPARE( snapped->asWkt( 5 ), QStringLiteral( "LineStringM (68 415 11, 27 505 24, 27 406 40)" ) );
   18316                 :          1 :     snapped.reset( curve.constGet()->snappedToGrid( 1, 1, 0, 10 ) );
   18317                 :          2 :     QCOMPARE( snapped->asWkt( 5 ), QStringLiteral( "LineStringM (68 415 10, 27 505 20, 27 406 40)" ) );
   18318                 :            : 
   18319                 :          1 :     curve = QgsGeometry::fromWkt( "LineStringZM (68.1 415.2 11.2 56.7, 27.1 505.2 23.6 49.1, 27.1 406.2 39.9 32.4)" );
   18320                 :          1 :     snapped.reset( curve.constGet()->snappedToGrid( 1, 1 ) );
   18321                 :          2 :     QCOMPARE( snapped->asWkt( 5 ), QStringLiteral( "LineStringZM (68 415 11.2 56.7, 27 505 23.6 49.1, 27 406 39.9 32.4)" ) );
   18322                 :          1 :     snapped.reset( curve.constGet()->snappedToGrid( 1, 1, 1, 1 ) );
   18323                 :          2 :     QCOMPARE( snapped->asWkt( 5 ), QStringLiteral( "LineStringZM (68 415 11 57, 27 505 24 49, 27 406 40 32)" ) );
   18324                 :          1 :     snapped.reset( curve.constGet()->snappedToGrid( 1, 1, 10, 10 ) );
   18325                 :          2 :     QCOMPARE( snapped->asWkt( 5 ), QStringLiteral( "LineStringZM (68 415 10 60, 27 505 20 50, 27 406 40 30)" ) );
   18326                 :          1 :   }
   18327                 :            : 
   18328                 :            :   //compound curve
   18329                 :            :   {
   18330                 :            :     // Curves
   18331                 :          1 :     QgsGeometry curve = QgsGeometry::fromWkt( "CompoundCurve(LineString(59.1 402.1, 68.1 415.2),CircularString( 68.1 415.2, 27.1 505.2, 27.1 406.2))" );
   18332                 :          1 :     std::unique_ptr<QgsAbstractGeometry> snapped { curve.constGet()->snappedToGrid( 1, 1 ) };
   18333                 :          2 :     QCOMPARE( snapped->asWkt(), QStringLiteral( "CompoundCurve ((59 402, 68 415),CircularString (68 415, 27 505, 27 406))" ) );
   18334                 :          1 :   }
   18335                 :          1 : }
   18336                 :            : 
   18337                 :          1 : void TestQgsGeometry::convertGeometryCollectionToSubclass()
   18338                 :            : {
   18339                 :          2 :   QgsGeometry gc0 = QgsGeometry::fromWkt( QStringLiteral( "GeometryCollection(Point(1 1), Polygon((2 2, 3 3, 2 3, 2 2)))" ) );
   18340                 :            : 
   18341                 :          1 :   QgsGeometry gc1 = gc0;
   18342                 :          1 :   QVERIFY( gc1.convertGeometryCollectionToSubclass( QgsWkbTypes::PointGeometry ) );
   18343                 :          2 :   QCOMPARE( gc1.asWkt(), QStringLiteral( "MultiPoint ((1 1))" ) );
   18344                 :            : 
   18345                 :          1 :   QgsGeometry gc2 = gc0;
   18346                 :          1 :   QVERIFY( gc2.convertGeometryCollectionToSubclass( QgsWkbTypes::PolygonGeometry ) );
   18347                 :          2 :   QCOMPARE( gc2.asWkt(), QStringLiteral( "MultiPolygon (((2 2, 3 3, 2 3, 2 2)))" ) );
   18348                 :            : 
   18349                 :          1 :   QgsGeometry gc3 = gc0;
   18350                 :          1 :   QVERIFY( gc3.convertGeometryCollectionToSubclass( QgsWkbTypes::LineGeometry ) );
   18351                 :          2 :   QCOMPARE( gc3.asWkt(), QStringLiteral( "MultiLineString EMPTY" ) );
   18352                 :          1 :   QVERIFY( gc3.isEmpty() );
   18353                 :            : 
   18354                 :            :   // trying to convert a geometry that is not a geometry collection
   18355                 :          2 :   QgsGeometry wrong = QgsGeometry::fromWkt( QStringLiteral( "Point(1 2)" ) );
   18356                 :          1 :   QVERIFY( !wrong.convertGeometryCollectionToSubclass( QgsWkbTypes::PolygonGeometry ) );
   18357                 :          1 : }
   18358                 :            : 
   18359                 :          1 : void TestQgsGeometry::emptyJson()
   18360                 :            : {
   18361                 :          1 :   QString expected;
   18362                 :          2 :   expected = QStringLiteral( "{\"coordinates\":[],\"type\":\"LineString\"}" );
   18363                 :          1 :   QCOMPARE( QgsCircularString().asJson(), expected );
   18364                 :          1 :   QCOMPARE( QgsCompoundCurve().asJson(), expected );
   18365                 :          1 :   QCOMPARE( QgsLineString().asJson(), expected );
   18366                 :            : 
   18367                 :          2 :   expected = QStringLiteral( "{\"geometries\":[],\"type\":\"GeometryCollection\"}" );
   18368                 :          1 :   QCOMPARE( QgsGeometryCollection().asJson(), expected );
   18369                 :            : 
   18370                 :          2 :   expected = QStringLiteral( "{\"coordinates\":[],\"type\":\"MultiLineString\"}" );
   18371                 :          1 :   QCOMPARE( QgsMultiCurve().asJson(), expected );
   18372                 :          1 :   QCOMPARE( QgsMultiLineString().asJson(), expected );
   18373                 :            : 
   18374                 :          2 :   expected = QStringLiteral( "{\"coordinates\":[],\"type\":\"MultiPoint\"}" );
   18375                 :          1 :   QCOMPARE( QgsMultiPoint().asJson(), expected );
   18376                 :            : 
   18377                 :          2 :   expected = QStringLiteral( "{\"coordinates\":[],\"type\":\"MultiPolygon\"}" );
   18378                 :          1 :   QCOMPARE( QgsMultiSurface().asJson(), expected );
   18379                 :            : 
   18380                 :          2 :   expected = QStringLiteral( "{\"coordinates\":[],\"type\":\"Point\"}" );
   18381                 :          1 :   QCOMPARE( QgsPoint().asJson(), expected );
   18382                 :            : 
   18383                 :          2 :   expected = QStringLiteral( "{\"coordinates\":[],\"type\":\"Polygon\"}" );
   18384                 :          1 :   QCOMPARE( QgsCurvePolygon().asJson(), expected );
   18385                 :          1 :   QCOMPARE( QgsPolygon().asJson(), expected );
   18386                 :          1 :   QCOMPARE( QgsTriangle().asJson(), expected );
   18387                 :          1 : }
   18388                 :            : 
   18389                 :          1 : void TestQgsGeometry::testRandomPointsInPolygon()
   18390                 :            : {
   18391                 :            :   // null geometry
   18392                 :          1 :   QVector< QgsPointXY > points = QgsGeometry().randomPointsInPolygon( 100 );
   18393                 :          1 :   QVERIFY( points.empty() );
   18394                 :            : 
   18395                 :            :   // not polygon geometry
   18396                 :          2 :   points = QgsGeometry::fromWkt( QStringLiteral( "Point( 4 5 )" ) ).randomPointsInPolygon( 100 );
   18397                 :          1 :   QVERIFY( points.empty() );
   18398                 :          2 :   points = QgsGeometry::fromWkt( QStringLiteral( "LineString( 4 5, 6 7 )" ) ).randomPointsInPolygon( 100 );
   18399                 :          1 :   QVERIFY( points.empty() );
   18400                 :            : 
   18401                 :            :   // zero point count
   18402                 :          2 :   points = QgsGeometry::fromWkt( QStringLiteral( "Polygon(( 5 15, 10 15, 10 20, 5 20, 5 15 ))" ) ).randomPointsInPolygon( 0 );
   18403                 :          1 :   QVERIFY( points.empty() );
   18404                 :            : 
   18405                 :            :   // valid polygon
   18406                 :          2 :   QgsGeometry g = QgsGeometry::fromWkt( QStringLiteral( "Polygon(( 5 15, 10 15, 10 20, 5 20, 5 15 ), (6 16, 8 16, 8 18, 6 16 ))" ) );
   18407                 :          1 :   points = g.randomPointsInPolygon( 10000 );
   18408                 :          1 :   QCOMPARE( points.count(), 10000 );
   18409                 :      10001 :   for ( const QgsPointXY &p : std::as_const( points ) )
   18410                 :      10000 :     QVERIFY( g.intersects( QgsGeometry::fromPointXY( p ) ) );
   18411                 :            : 
   18412                 :            :   // valid multipolygon
   18413                 :          2 :   g = QgsGeometry::fromWkt( QStringLiteral( "MultiPolygon((( 5 15, 10 15, 10 20, 5 20, 5 15 ), (6 16, 8 16, 8 18, 6 16 )), (( 105 115, 110 115, 110 120, 105 120, 105 115 ), (106 116, 108 116, 108 118, 106 116 )))" ) );
   18414                 :          1 :   points = g.randomPointsInPolygon( 10000 );
   18415                 :          1 :   QCOMPARE( points.count(), 10000 );
   18416                 :          1 :   bool foundp1Point = false;
   18417                 :          1 :   bool foundp2Point = false;
   18418                 :      10001 :   for ( const QgsPointXY &p : std::as_const( points ) )
   18419                 :            :   {
   18420                 :      10000 :     QVERIFY( g.intersects( QgsGeometry::fromPointXY( p ) ) );
   18421                 :      10000 :     foundp1Point |= p.x() < 100;
   18422                 :      10000 :     foundp2Point |= p.x() > 100;
   18423                 :            :   }
   18424                 :          1 :   QVERIFY( foundp1Point );
   18425                 :          1 :   QVERIFY( foundp2Point );
   18426                 :            : 
   18427                 :            :   // with seed
   18428                 :          2 :   g = QgsGeometry::fromWkt( QStringLiteral( "MultiPolygon((( 5 15, 10 15, 10 20, 5 20, 5 15 ), (6 16, 8 16, 8 18, 6 16 )), (( 105 115, 110 115, 110 120, 105 120, 105 115 ), (106 116, 108 116, 108 118, 106 116 )))" ) );
   18429                 :          1 :   QVector< QgsPointXY > points1 = g.randomPointsInPolygon( 100, 200 );
   18430                 :          1 :   QCOMPARE( points1.count(), 100 );
   18431                 :          1 :   QVector< QgsPointXY > points2 = g.randomPointsInPolygon( 100, 200 );
   18432                 :          1 :   QCOMPARE( points2.count(), 100 );
   18433                 :          1 :   QCOMPARE( points1, points2 );
   18434                 :            : 
   18435                 :            :   // no seed
   18436                 :          1 :   points1 = g.randomPointsInPolygon( 100 );
   18437                 :          1 :   QCOMPARE( points1.count(), 100 );
   18438                 :          1 :   points2 = g.randomPointsInPolygon( 100 );
   18439                 :          1 :   QCOMPARE( points2.count(), 100 );
   18440                 :          1 :   QVERIFY( points1 != points2 );
   18441                 :            : 
   18442                 :            :   // with filter
   18443                 :      20147 :   points = g.randomPointsInPolygon( 10000, []( const QgsPointXY & p )->bool
   18444                 :            :   {
   18445                 :      20146 :     return p.x() > 100;
   18446                 :            :   } );
   18447                 :          1 :   QCOMPARE( points.count(), 10000 );
   18448                 :          1 :   foundp1Point = false;
   18449                 :          1 :   foundp2Point = false;
   18450                 :      10001 :   for ( const QgsPointXY &p : std::as_const( points ) )
   18451                 :            :   {
   18452                 :      10000 :     QVERIFY( g.intersects( QgsGeometry::fromPointXY( p ) ) );
   18453                 :      10000 :     foundp1Point |= p.x() < 100;
   18454                 :      10000 :     foundp2Point |= p.x() > 100;
   18455                 :            :   }
   18456                 :          1 :   QVERIFY( !foundp1Point );
   18457                 :          1 :   QVERIFY( foundp2Point );
   18458                 :          1 : }
   18459                 :            : 
   18460                 :          1 : void TestQgsGeometry::wktParser()
   18461                 :            : {
   18462                 :            :   // POINT
   18463                 :            :   // unbalanced parentheses
   18464                 :          1 :   QVERIFY( QgsPoint().fromWkt( "POINT((0 1)" ) );
   18465                 :          1 :   QVERIFY( QgsPoint().fromWkt( "POINT(0 1) )" ) );
   18466                 :          1 :   QVERIFY( QgsPoint().fromWkt( "POINT ((0 1)" ) );
   18467                 :          1 :   QVERIFY( QgsPoint().fromWkt( "POINT (0 1) )" ) );
   18468                 :            :   // extra parentheses
   18469                 :          1 :   QVERIFY( QgsPoint().fromWkt( "POINT ( (5 1) )" ) );
   18470                 :            :   // not a number
   18471                 :          1 :   QVERIFY( ! QgsPoint().fromWkt( "POINT (a, b)" ) );
   18472                 :          1 :   QVERIFY( ! QgsPoint().fromWkt( "POINT (a b)" ) );
   18473                 :          1 :   QVERIFY( ! QgsPoint().fromWkt( "POINT((0, 1)" ) );
   18474                 :          1 :   QVERIFY( ! QgsPoint().fromWkt( "POINT(0, 1) )" ) );
   18475                 :          1 :   QVERIFY( ! QgsPoint().fromWkt( "POINT ((0, 1)" ) );
   18476                 :          1 :   QVERIFY( ! QgsPoint().fromWkt( "POINT (0, 1) )" ) );
   18477                 :          1 :   QVERIFY( ! QgsPoint().fromWkt( "POINT ( (5, 1) )" ) );
   18478                 :            : 
   18479                 :            :   // valid
   18480                 :          1 :   QgsPoint p;
   18481                 :          1 :   QVERIFY( p.fromWkt( "POINT (5 1)" ) );
   18482                 :          2 :   QCOMPARE( p.asWkt(), QStringLiteral( "Point (5 1)" ) );
   18483                 :            :   // extra parentheses
   18484                 :          1 :   QVERIFY( p.fromWkt( "POINT ( (5 1) )" ) );
   18485                 :            :   // unbalanced parentheses
   18486                 :          1 :   QVERIFY( p.fromWkt( "POINT ( (5 1)" ) );
   18487                 :          2 :   QCOMPARE( p.asWkt(), QStringLiteral( "Point (5 1)" ) );
   18488                 :          1 :   QVERIFY( p.fromWkt( "POINT (5 1) )" ) );
   18489                 :          2 :   QCOMPARE( p.asWkt(), QStringLiteral( "Point (5 1)" ) );
   18490                 :            : 
   18491                 :          1 :   QVERIFY( p.fromWkt( "POINT (5.1234 1.4321)" ) );
   18492                 :          2 :   QCOMPARE( p.asWkt( 4 ), QStringLiteral( "Point (5.1234 1.4321)" ) );
   18493                 :          1 :   QVERIFY( p.fromWkt( "POINT (-5.1234 -1.4321)" ) );
   18494                 :          2 :   QCOMPARE( p.asWkt( 4 ), QStringLiteral( "Point (-5.1234 -1.4321)" ) );
   18495                 :          1 :   QVERIFY( p.fromWkt( "POINT (-12e4 -1.4e-1)" ) );
   18496                 :          2 :   QCOMPARE( p.asWkt( 2 ), QStringLiteral( "Point (-120000 -0.14)" ) );
   18497                 :            : 
   18498                 :          1 :   QVERIFY( p.fromWkt( "POINT ( )" ) );
   18499                 :          2 :   QCOMPARE( p.asWkt(), QStringLiteral( "Point EMPTY" ) );
   18500                 :          1 :   QVERIFY( ! p.fromWkt( "POINT (a, b)" ) );
   18501                 :          2 :   QCOMPARE( p.asWkt(), QStringLiteral( "Point EMPTY" ) );
   18502                 :            :   // LINESTRING
   18503                 :          1 :   QVERIFY( QgsLineString().fromWkt( "LineString(0 1, 1 2) )" ) );
   18504                 :          1 :   QVERIFY( QgsLineString().fromWkt( "LineString (0 1, 1 2) )" ) );
   18505                 :          1 :   QVERIFY( QgsLineString().fromWkt( "LineString ( (0 1) )" ) );
   18506                 :          1 :   QVERIFY( QgsLineString().fromWkt( "LineString ( ( 0 1, 2 3 ) )" ) );
   18507                 :          1 :   QVERIFY( QgsMultiLineString().fromWkt( "MULTILINESTRING ((((1 2, 2 4, 4 5))" ) );
   18508                 :          1 :   QVERIFY( QgsMultiLineString().fromWkt( "MULTILINESTRING((((1 2, 2 4, 4 5))" ) );
   18509                 :            :   // not a number
   18510                 :          1 :   QVERIFY( ! QgsLineString().fromWkt( "LineString(0, 1) )" ) );
   18511                 :          1 :   QVERIFY( ! QgsLineString().fromWkt( "LineString (0, 1) )" ) );
   18512                 :          1 :   QVERIFY( ! QgsLineString().fromWkt( "LineString (a b, 3 4)" ) );
   18513                 :          1 :   QVERIFY( ! QgsMultiLineString().fromWkt( "MULTILINESTRING ((1 2, 2 a, 4 b))" ) );
   18514                 :            :   // valid
   18515                 :          1 :   QgsLineString l;
   18516                 :          1 :   QVERIFY( l.fromWkt( "LINESTRING ( 1 2, 3 4 )" ) );
   18517                 :          2 :   QCOMPARE( l.asWkt(), QStringLiteral( "LineString (1 2, 3 4)" ) );
   18518                 :            :   // unbalanced parentheses
   18519                 :          1 :   QVERIFY( l.fromWkt( "LINESTRING ( ( 1 2, 3 4 )" ) );
   18520                 :          2 :   QCOMPARE( l.asWkt(), QStringLiteral( "LineString (1 2, 3 4)" ) );
   18521                 :          1 :   QVERIFY( l.fromWkt( "LINESTRING ( 1 2, 3 4 ) )" ) );
   18522                 :          2 :   QCOMPARE( l.asWkt(), QStringLiteral( "LineString (1 2, 3 4)" ) );
   18523                 :            :   // extra parentheses
   18524                 :          1 :   QVERIFY( l.fromWkt( "LINESTRING( ( 1 2, 3 4 ) )" ) );
   18525                 :          2 :   QCOMPARE( l.asWkt(), QStringLiteral( "LineString (1 2, 3 4)" ) );
   18526                 :            :   // empty
   18527                 :          1 :   QVERIFY( l.fromWkt( "LINESTRING (  )" ) );
   18528                 :          2 :   QCOMPARE( l.asWkt(), QStringLiteral( "LineString EMPTY" ) );
   18529                 :          1 :   QVERIFY( ! l.fromWkt( "LINESTRING ( a b, 2 3  )" ) );
   18530                 :          2 :   QCOMPARE( l.asWkt(), QStringLiteral( "LineString EMPTY" ) );
   18531                 :          1 :   QVERIFY( l.fromWkt( "LINESTRING ( 1e4 -2, 3 +4.5 )" ) );
   18532                 :          2 :   QCOMPARE( l.asWkt( 1 ), QStringLiteral( "LineString (10000 -2, 3 4.5)" ) );
   18533                 :          1 :   QgsMultiLineString m;
   18534                 :          1 :   m.fromWkt( "MULTILINESTRING ((1 2, 2 3, 4 5))" ) ;
   18535                 :          1 :   QVERIFY( m.fromWkt( "MULTILINESTRING ((1 2, 2 3, 4 5))" ) );
   18536                 :          2 :   QCOMPARE( m.asWkt( 1 ), QStringLiteral( "MultiLineString ((1 2, 2 3, 4 5))" ) );
   18537                 :            : 
   18538                 :            :   // TRIANGLE
   18539                 :            :   // unbalanced parenthesis
   18540                 :          1 :   QVERIFY( QgsTriangle().fromWkt( "Triangle( (0 1, 1 2, 3 3) )) " ) );
   18541                 :          1 :   QVERIFY( QgsTriangle().fromWkt( "Triangle ( (0 1, 1 2, 3 3) )) " ) );
   18542                 :          1 :   QVERIFY( ! QgsTriangle().fromWkt( "Triangle(0 1, 1 2, 3 3) )" ) );
   18543                 :          1 :   QVERIFY( ! QgsTriangle().fromWkt( "Triangle (0 1, 1 2, 3 3) )" ) );
   18544                 :            :   // not a number
   18545                 :          1 :   QVERIFY( ! QgsTriangle().fromWkt( "Triangle ( (0 a, b 2, 3 3 )) " ) );
   18546                 :          1 :   QVERIFY( ! QgsTriangle().fromWkt( "Triangle ( (0 a, b 2, 3 3, 0 a )) " ) );
   18547                 :            :   // incorrect number of points
   18548                 :          1 :   QVERIFY( ! QgsTriangle().fromWkt( "Triangle (( 0 0, 1 1))" ) );
   18549                 :          1 :   QVERIFY( ! QgsTriangle().fromWkt( "Triangle (( 0 0, 1 1, 1 0, 2 3, 4 5))" ) );
   18550                 :          1 :   QVERIFY( ! QgsTriangle().fromWkt( "Triangle (( 0 1, 2 3, 3 4, 1 0))" ) ); // four points but start and last points are different
   18551                 :            :   // valid
   18552                 :          1 :   QgsTriangle t;
   18553                 :          1 :   QVERIFY( t.fromWkt( "TRIANGLE(( 0 1, 2 3, 3 4))" ) );
   18554                 :          2 :   QCOMPARE( t.asWkt(), QStringLiteral( "Triangle ((0 1, 2 3, 3 4))" ) );
   18555                 :          1 :   QVERIFY( t.fromWkt( "TRIANGLE(( 0 1, 2 3, 3 4, 0 1))" ) );
   18556                 :          2 :   QCOMPARE( t.asWkt(), QStringLiteral( "Triangle ((0 1, 2 3, 3 4, 0 1))" ) );
   18557                 :          1 :   QVERIFY( t.fromWkt( "TRIANGLE(( 0 1, 2 3, 3 4, 0 1))" ) );
   18558                 :          2 :   QCOMPARE( t.asWkt(), QStringLiteral( "Triangle ((0 1, 2 3, 3 4, 0 1))" ) );
   18559                 :          1 :   QVERIFY( ! t.fromWkt( "TRIANGLE(( 0 1, 2 3, 3 4, 0 3))" ) );
   18560                 :          2 :   QCOMPARE( t.asWkt(), QStringLiteral( "Triangle EMPTY" ) );
   18561                 :          1 :   QVERIFY( ! t.fromWkt( "TRIANGLE(( 0 1, 2 3, 3 4, 0 3, 4 5))" ) );
   18562                 :          2 :   QCOMPARE( t.asWkt(), QStringLiteral( "Triangle EMPTY" ) );
   18563                 :          1 :   QVERIFY( ! t.fromWkt( "TRIANGLE(( 0 1, 2 3 ))" ) );
   18564                 :          2 :   QCOMPARE( t.asWkt(), QStringLiteral( "Triangle EMPTY" ) );
   18565                 :          1 :   QVERIFY( t.fromWkt( "TRIANGLE((0 1e3, -2 3, +3 4, 0 1e3))" ) );
   18566                 :          2 :   QCOMPARE( t.asWkt(), QStringLiteral( "Triangle ((0 1000, -2 3, 3 4, 0 1000))" ) );
   18567                 :            : 
   18568                 :            :   // POLYGON
   18569                 :            :   // unbalanced parenthesis
   18570                 :          1 :   QVERIFY( QgsPolygon().fromWkt( "Polygon( (0 1, 1 2, 3 3) )) " ) );
   18571                 :          1 :   QVERIFY( QgsPolygon().fromWkt( "Polygon ( (0 1, 1 2, 3 3) )) " ) );
   18572                 :          1 :   QVERIFY( ! QgsPolygon().fromWkt( "Polygon(0 1, 1 2, 3 3) )" ) );
   18573                 :          1 :   QVERIFY( ! QgsPolygon().fromWkt( "Polygon (0 1, 1 2, 3 3) )" ) );
   18574                 :            :   // not a number
   18575                 :          1 :   QVERIFY( ! QgsPolygon().fromWkt( "Polygon ( (0 a, b 2, 3 3 )) " ) );
   18576                 :          1 :   QVERIFY( ! QgsPolygon().fromWkt( "Polygon ( (0 a, b 2, 3 3, 0 a )) " ) );
   18577                 :            :   // valid
   18578                 :          1 :   QgsPolygon poly;
   18579                 :          1 :   QVERIFY( poly.fromWkt( "Polygon(( 0 1, 2 3, 3 4))" ) );
   18580                 :          2 :   QCOMPARE( poly.asWkt(), QStringLiteral( "Polygon ((0 1, 2 3, 3 4))" ) ); // TODO: A polygon must be closed
   18581                 :          1 :   QVERIFY( poly.fromWkt( "Polygon(( 0 1, 2 3, 3 4, 0 1))" ) );
   18582                 :          2 :   QCOMPARE( poly.asWkt(), QStringLiteral( "Polygon ((0 1, 2 3, 3 4, 0 1))" ) );
   18583                 :          1 :   QVERIFY( poly.fromWkt( "Polygon((0 1e3, -2 3, +3 4, 0 1))" ) );
   18584                 :          2 :   QCOMPARE( poly.asWkt(), QStringLiteral( "Polygon ((0 1000, -2 3, 3 4, 0 1))" ) );
   18585                 :            : 
   18586                 :            :   // Circular string
   18587                 :            :   // unbalanced parenthesis
   18588                 :          1 :   QVERIFY( QgsCircularString().fromWkt( "CircularString(0 1, 1 2, 3 3) )" ) );
   18589                 :          1 :   QVERIFY( QgsCircularString().fromWkt( "CircularString (0 1, 1 2, 3 3) )" ) );
   18590                 :          1 :   QVERIFY( QgsCircularString().fromWkt( "CircularString( (0 1, 1 2, 3 3) )) " ) );
   18591                 :          1 :   QVERIFY( QgsCircularString().fromWkt( "CircularString ( (0 1, 1 2, 3 3) )) " ) );
   18592                 :            :   // not a number
   18593                 :          1 :   QVERIFY( ! QgsCircularString().fromWkt( "CircularString (0 a, b 2, 3 3) " ) );
   18594                 :          1 :   QVERIFY( ! QgsCircularString().fromWkt( "CircularString (0 a, b 2, 3 3, 0 a) " ) );
   18595                 :            :   // valid
   18596                 :          1 :   QgsCircularString c;
   18597                 :          1 :   QVERIFY( c.fromWkt( "CircularString( 0 1, 2 3, 3 4)" ) );
   18598                 :          2 :   QCOMPARE( c.asWkt(), QStringLiteral( "CircularString (0 1, 2 3, 3 4)" ) );
   18599                 :          1 :   QVERIFY( c.fromWkt( "CircularString(0 1e3, -2 3, +3 4)" ) );
   18600                 :          2 :   QCOMPARE( c.asWkt(), QStringLiteral( "CircularString (0 1000, -2 3, 3 4)" ) );
   18601                 :            : 
   18602                 :          1 :   QVERIFY( c.fromWkt( "CircularString ((0 0,1 1,2 0))" ) ); // Added from an old test with an invalid wkt, but allowed in QGIS https://github.com/qgis/QGIS/pull/38439/files/59aab9dc9cc58bdc98e6d8091840bc129564ed2f#diff-fe3aa1328ee04f0eb00a1b1d59c0ea71L4247
   18603                 :          2 :   QCOMPARE( c.asWkt(), QStringLiteral( "CircularString (0 0, 1 1, 2 0)" ) );
   18604                 :            : 
   18605                 :            :   // multipoint
   18606                 :          1 :   QgsMultiPoint mp;
   18607                 :          1 :   QVERIFY( ! mp.fromWkt( "MULTIPOINT (((10 40), (40 30), (20 20), (30 10))" ) );
   18608                 :          1 :   QVERIFY( ! mp.fromWkt( "MULTIPOINT (((10 40), (40 30), (xx20 20), (30 10))" ) );
   18609                 :          1 :   QVERIFY( ! mp.fromWkt( "MULTIPOINT ((10 40, 40 30, 20 20, 30 10)" ) );
   18610                 :          1 :   QVERIFY( mp.fromWkt( "MULTIPOINT ((10 40), (40 30), (20 20), (30 10))))" ) );
   18611                 :          1 :   QVERIFY( mp.fromWkt( "MULTIPOINT ( )" ) );
   18612                 :          1 :   QVERIFY( mp.fromWkt( "MULTIPOINT EMPTY" ) );
   18613                 :          1 :   QVERIFY( mp.fromWkt( "MULTIPOINT ((10 40), (40 30), (20 20), (30 10))" ) );
   18614                 :          2 :   QCOMPARE( mp.asWkt(), QStringLiteral( "MultiPoint ((10 40),(40 30),(20 20),(30 10))" ) );
   18615                 :          1 :   QVERIFY( mp.fromWkt( "MULTIPOINT (10 40, 40 30, 20 20, 30 10)" ) );
   18616                 :          2 :   QCOMPARE( mp.asWkt(), QStringLiteral( "MultiPoint ((10 40),(40 30),(20 20),(30 10))" ) );
   18617                 :          1 :   QVERIFY( mp.fromWkt( "MULTIPOINT ((10 40), (40 30), (20 20), (30 10))))" ) );
   18618                 :          2 :   QCOMPARE( mp.asWkt(), QStringLiteral( "MultiPoint ((10 40),(40 30),(20 20),(30 10))" ) );
   18619                 :          1 :   QVERIFY( mp.fromWkt( "MULTIPOINT ( )" ) );
   18620                 :          2 :   QCOMPARE( mp.asWkt(), QStringLiteral( "MultiPoint EMPTY" ) );
   18621                 :          1 :   QVERIFY( mp.fromWkt( "MULTIPOINT EMPTY" ) );
   18622                 :          2 :   QCOMPARE( mp.asWkt(), QStringLiteral( "MultiPoint EMPTY" ) );
   18623                 :            :   // Added from an old test with an invalid wkt, but allowed in QGIS https://github.com/qgis/QGIS/pull/38439/files/59aab9dc9cc58bdc98e6d8091840bc129564ed2f#diff-4444b5a772b35be43721b71a4b95d785R50
   18624                 :          1 :   QVERIFY( mp.fromWkt( "MULTIPOINT(0 20,20 20))" ) );
   18625                 :          2 :   QCOMPARE( mp.asWkt(), QStringLiteral( "MultiPoint ((0 20),(20 20))" ) );
   18626                 :            : 
   18627                 :            :   // compoundcurve
   18628                 :          1 :   QgsCompoundCurve cc;
   18629                 :          1 :   QVERIFY( ! cc.fromWkt( "COMPOUNDCURVE((CIRCULARSTRING( 0 0, 1 1, 2 2))" ) );
   18630                 :          1 :   QVERIFY( cc.fromWkt( "COMPOUNDCURVE(CIRCULARSTRING( 0 0, 1 1, 2 2)))" ) );
   18631                 :          2 :   QCOMPARE( cc.asWkt(), QStringLiteral( "CompoundCurve (CircularString (0 0, 1 1, 2 2))" ) );
   18632                 :          1 :   QVERIFY( cc.fromWkt( "COMPOUNDCURVE(CIRCULARSTRING( 0 0, 1 1, 2 2))" ) );
   18633                 :          2 :   QCOMPARE( cc.asWkt(), QStringLiteral( "CompoundCurve (CircularString (0 0, 1 1, 2 2))" ) );
   18634                 :          1 :   QVERIFY( cc.fromWkt( "COMPOUNDCURVE(CIRCULARSTRING( 0 0, 1 1, 2 2), LINESTRING((2 2, 3 3)))" ) );
   18635                 :          2 :   QCOMPARE( cc.asWkt(), QStringLiteral( "CompoundCurve (CircularString (0 0, 1 1, 2 2),(2 2, 3 3))" ) );
   18636                 :          1 :   QVERIFY( cc.fromWkt( "COMPOUNDCURVE ( )" ) );
   18637                 :          2 :   QCOMPARE( cc.asWkt(), QStringLiteral( "CompoundCurve EMPTY" ) );
   18638                 :          1 :   QVERIFY( cc.fromWkt( "COMPOUNDCURVE EMPTY" ) );
   18639                 :          2 :   QCOMPARE( cc.asWkt(), QStringLiteral( "CompoundCurve EMPTY" ) );
   18640                 :            :   // geometrycollection
   18641                 :          1 :   QgsGeometryCollection gc;
   18642                 :          1 :   QVERIFY( gc.fromWkt( "GeometryCollection((CIRCULARSTRING( 0 0, 1 1, 2 2))" ) );
   18643                 :          2 :   QCOMPARE( gc.asWkt(), QStringLiteral( "GeometryCollection (GeometryCollection (CircularString (0 0, 1 1, 2 2)))" ) );
   18644                 :          1 :   QVERIFY( gc.fromWkt( "GeometryCollection(CIRCULARSTRING( 0 0, 1 1, 2 2)))" ) );
   18645                 :          2 :   QCOMPARE( gc.asWkt(), QStringLiteral( "GeometryCollection (CircularString (0 0, 1 1, 2 2))" ) );
   18646                 :          1 :   QVERIFY( gc.fromWkt( "GeometryCollection(CIRCULARSTRING( 0 0, 1 1, 2 2))" ) );
   18647                 :          2 :   QCOMPARE( gc.asWkt(), QStringLiteral( "GeometryCollection (CircularString (0 0, 1 1, 2 2))" ) );
   18648                 :          1 :   QVERIFY( gc.fromWkt( "GeometryCollection(CIRCULARSTRING( 0 0, 1 1, 2 2), LINESTRING((2 2, 3 3)))" ) );
   18649                 :          2 :   QCOMPARE( gc.asWkt(), QStringLiteral( "GeometryCollection (CircularString (0 0, 1 1, 2 2),LineString (2 2, 3 3))" ) );
   18650                 :          1 :   QVERIFY( gc.fromWkt( "GeometryCollection ( )" ) );
   18651                 :          2 :   QCOMPARE( gc.asWkt(), QStringLiteral( "GeometryCollection EMPTY" ) );
   18652                 :          1 :   QVERIFY( gc.fromWkt( "GeometryCollection EMPTY" ) );
   18653                 :          2 :   QCOMPARE( gc.asWkt(), QStringLiteral( "GeometryCollection EMPTY" ) );
   18654                 :            :   // curvepolygon
   18655                 :          1 :   QgsCurvePolygon cp;
   18656                 :          1 :   QVERIFY( ! cp.fromWkt( "CurvePolygon((CIRCULARSTRING( 0 0, 1 1, 2 2))" ) );
   18657                 :          1 :   QVERIFY( cp.fromWkt( "CurvePolygon(CIRCULARSTRING( 0 0, 1 1, 2 2)))" ) );
   18658                 :          2 :   QCOMPARE( cp.asWkt(), QStringLiteral( "CurvePolygon (CircularString (0 0, 1 1, 2 2))" ) );
   18659                 :          1 :   QVERIFY( cp.fromWkt( "CurvePolygon(CIRCULARSTRING( 0 0, 1 1, 2 2))" ) );
   18660                 :          2 :   QCOMPARE( cp.asWkt(), QStringLiteral( "CurvePolygon (CircularString (0 0, 1 1, 2 2))" ) );
   18661                 :          1 :   QVERIFY( cp.fromWkt( "CurvePolygon(CIRCULARSTRING( 0 0, 1 1, 2 2), LINESTRING((2 2, 3 3)))" ) );
   18662                 :          2 :   QCOMPARE( cp.asWkt(), QStringLiteral( "CurvePolygon (CircularString (0 0, 1 1, 2 2),(2 2, 3 3))" ) );
   18663                 :          1 :   QVERIFY( cp.fromWkt( "CurvePolygon ( )" ) );
   18664                 :          2 :   QCOMPARE( cp.asWkt(), QStringLiteral( "CurvePolygon EMPTY" ) );
   18665                 :          1 :   QVERIFY( cp.fromWkt( "CurvePolygon EMPTY" ) );
   18666                 :          2 :   QCOMPARE( cp.asWkt(), QStringLiteral( "CurvePolygon EMPTY" ) );
   18667                 :            :   // multicurve
   18668                 :          1 :   QgsMultiCurve mc;
   18669                 :          1 :   QVERIFY( ! mc.fromWkt( "MultiCurve((CIRCULARSTRING( 0 0, 1 1, 2 2))" ) );
   18670                 :          1 :   QVERIFY( mc.fromWkt( "MultiCurve(CIRCULARSTRING( 0 0, 1 1, 2 2)))" ) );
   18671                 :          2 :   QCOMPARE( mc.asWkt(), QStringLiteral( "MultiCurve (CircularString (0 0, 1 1, 2 2))" ) );
   18672                 :          1 :   QVERIFY( mc.fromWkt( "MultiCurve(CIRCULARSTRING( 0 0, 1 1, 2 2))" ) );
   18673                 :          2 :   QCOMPARE( mc.asWkt(), QStringLiteral( "MultiCurve (CircularString (0 0, 1 1, 2 2))" ) );
   18674                 :          1 :   QVERIFY( mc.fromWkt( "MultiCurve(CIRCULARSTRING( 0 0, 1 1, 2 2), LINESTRING((2 2, 3 3)))" ) );
   18675                 :          2 :   QCOMPARE( mc.asWkt(), QStringLiteral( "MultiCurve (CircularString (0 0, 1 1, 2 2),LineString (2 2, 3 3))" ) );
   18676                 :          1 :   QVERIFY( mc.fromWkt( "MultiCurve ( )" ) );
   18677                 :          2 :   QCOMPARE( mc.asWkt(), QStringLiteral( "MultiCurve EMPTY" ) );
   18678                 :          1 :   QVERIFY( mc.fromWkt( "MultiCurve EMPTY" ) );
   18679                 :          2 :   QCOMPARE( mc.asWkt(), QStringLiteral( "MultiCurve EMPTY" ) );
   18680                 :            :   // multisurface
   18681                 :          1 :   QgsMultiSurface ms;
   18682                 :          1 :   QVERIFY( ! ms.fromWkt( "MultiSurface((Polygon( 0 0, 1 1, 2 2))" ) );
   18683                 :          1 :   QVERIFY( ms.fromWkt( "MultiSurface(Polygon(( 0 0, 1 1, 2 2)))" ) );
   18684                 :          2 :   QCOMPARE( ms.asWkt(), QStringLiteral( "MultiSurface (Polygon ((0 0, 1 1, 2 2)))" ) );
   18685                 :          1 :   QVERIFY( ms.fromWkt( "MultiSurface(Polygon(( 0 0, 1 1, 2 2)))" ) );
   18686                 :          2 :   QCOMPARE( ms.asWkt(), QStringLiteral( "MultiSurface (Polygon ((0 0, 1 1, 2 2)))" ) );
   18687                 :          1 :   QVERIFY( ms.fromWkt( "MultiSurface(Polygon(( 0 0, 1 1, 2 2)), Polygon((2 2, 3 3, 3 2)))" ) );
   18688                 :          2 :   QCOMPARE( ms.asWkt(), QStringLiteral( "MultiSurface (Polygon ((0 0, 1 1, 2 2)),Polygon ((2 2, 3 3, 3 2)))" ) );
   18689                 :          1 :   QVERIFY( ms.fromWkt( "MultiSurface ( )" ) );
   18690                 :          2 :   QCOMPARE( ms.asWkt(), QStringLiteral( "MultiSurface EMPTY" ) );
   18691                 :          1 :   QVERIFY( ms.fromWkt( "MultiSurface EMPTY" ) );
   18692                 :          2 :   QCOMPARE( ms.asWkt(), QStringLiteral( "MultiSurface EMPTY" ) );
   18693                 :            :   // multipolygon
   18694                 :          1 :   QgsMultiPolygon mpoly;
   18695                 :          1 :   QVERIFY( ! mpoly.fromWkt( "MultiPolygon((Polygon( 0 0, 1 1, 2 2))" ) );
   18696                 :          1 :   QVERIFY( mpoly.fromWkt( "MultiPolygon(Polygon(( 0 0, 1 1, 2 2)))" ) );
   18697                 :          2 :   QCOMPARE( mpoly.asWkt(), QStringLiteral( "MultiPolygon (((0 0, 1 1, 2 2)))" ) );
   18698                 :          1 :   QVERIFY( mpoly.fromWkt( "MultiPolygon(Polygon(( 0 0, 1 1, 2 2)))" ) );
   18699                 :          2 :   QCOMPARE( mpoly.asWkt(), QStringLiteral( "MultiPolygon (((0 0, 1 1, 2 2)))" ) );
   18700                 :          1 :   QVERIFY( mpoly.fromWkt( "MultiPolygon(Polygon(( 0 0, 1 1, 2 2)), Polygon((2 2, 3 3, 3 2)))" ) );
   18701                 :          2 :   QCOMPARE( mpoly.asWkt(), QStringLiteral( "MultiPolygon (((0 0, 1 1, 2 2)),((2 2, 3 3, 3 2)))" ) );
   18702                 :          1 :   QVERIFY( mpoly.fromWkt( "MultiPolygon ( )" ) );
   18703                 :          2 :   QCOMPARE( mpoly.asWkt(), QStringLiteral( "MultiPolygon EMPTY" ) );
   18704                 :          1 :   QVERIFY( mpoly.fromWkt( "MultiPolygon EMPTY" ) );
   18705                 :          2 :   QCOMPARE( mpoly.asWkt(), QStringLiteral( "MultiPolygon EMPTY" ) );
   18706                 :            : 
   18707                 :            :   // multilinestring
   18708                 :          1 :   QgsMultiLineString mline;
   18709                 :          1 :   QVERIFY( ! mline.fromWkt( "MultiLineString((LineString( 0 0, 1 1, 2 2))" ) );
   18710                 :          1 :   QVERIFY( mline.fromWkt( "MultiLineString(LineString(( 0 0, 1 1, 2 2)))" ) );
   18711                 :          2 :   QCOMPARE( mline.asWkt(), QStringLiteral( "MultiLineString ((0 0, 1 1, 2 2))" ) );
   18712                 :          1 :   QVERIFY( mline.fromWkt( "MultiLineString(LineString(( 0 0, 1 1, 2 2)))" ) );
   18713                 :          2 :   QCOMPARE( mline.asWkt(), QStringLiteral( "MultiLineString ((0 0, 1 1, 2 2))" ) );
   18714                 :          1 :   QVERIFY( mline.fromWkt( "MultiLineString(LineString(( 0 0, 1 1, 2 2)), LineString((2 2, 3 3, 3 2)))" ) );
   18715                 :          2 :   QCOMPARE( mline.asWkt(), QStringLiteral( "MultiLineString ((0 0, 1 1, 2 2),(2 2, 3 3, 3 2))" ) );
   18716                 :          1 :   QVERIFY( mline.fromWkt( "MultiLineString ( )" ) );
   18717                 :          2 :   QCOMPARE( mline.asWkt(), QStringLiteral( "MultiLineString EMPTY" ) );
   18718                 :          1 :   QVERIFY( mline.fromWkt( "MultiLineString EMPTY" ) );
   18719                 :          2 :   QCOMPARE( mline.asWkt(), QStringLiteral( "MultiLineString EMPTY" ) );
   18720                 :          1 : }
   18721                 :          1 : QGSTEST_MAIN( TestQgsGeometry )
   18722                 :            : #include "testqgsgeometry.moc"

Generated by: LCOV version 1.14