Skip to content

Commit ff36573

Browse files
committedNov 24, 2015
Fix crash in QgsLineStringV2::append if non z/m line appended
to a LineString with z/m Add a bunch of unit tests for QgsLineStringV2 and fix some other minor issues which they identified.
1 parent 7443431 commit ff36573

File tree

3 files changed

+577
-11
lines changed

3 files changed

+577
-11
lines changed
 

‎src/core/geometry/qgslinestringv2.cpp

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ QDomElement QgsLineStringV2::asGML3( QDomDocument& doc, int precision, const QSt
132132

133133
QDomElement elemCurve = doc.createElementNS( ns, "Curve" );
134134
QDomElement elemSegments = doc.createElementNS( ns, "segments" );
135-
QDomElement elemArcString = doc.createElementNS( ns, "LineString" );
135+
QDomElement elemArcString = doc.createElementNS( ns, "LineStringSegment" );
136136
elemArcString.appendChild( QgsGeometryUtils::pointsToGML3( pts, doc, precision, ns, is3D() ) );
137137
elemSegments.appendChild( elemArcString );
138138
elemCurve.appendChild( elemSegments );
@@ -303,11 +303,7 @@ void QgsLineStringV2::setPoints( const QList<QgsPointV2>& points )
303303

304304
if ( points.isEmpty() )
305305
{
306-
mWkbType = QgsWKBTypes::Unknown;
307-
mX.clear();
308-
mY.clear();
309-
mZ.clear();
310-
mM.clear();
306+
clear();
311307
return;
312308
}
313309

@@ -366,8 +362,26 @@ void QgsLineStringV2::append( const QgsLineStringV2* line )
366362

367363
mX += line->mX;
368364
mY += line->mY;
369-
mZ += line->mZ;
370-
mM += line->mM;
365+
366+
if ( line->is3D() )
367+
{
368+
mZ += line->mZ;
369+
}
370+
else
371+
{
372+
// if append line does not have z coordinates, fill with 0 to match number of points in final line
373+
mZ.insert( mZ.count(), mX.size() - mZ.size(), 0 );
374+
}
375+
376+
if ( line->is3D() )
377+
{
378+
mM += line->mM;
379+
}
380+
else
381+
{
382+
// if append line does not have m values, fill with 0 to match number of points in final line
383+
mM.insert( mM.count(), mX.size() - mM.size(), 0 );
384+
}
371385

372386
mBoundingBox = QgsRectangle(); //set bounding box invalid
373387
}
@@ -524,7 +538,7 @@ bool QgsLineStringV2::deleteVertex( const QgsVertexId& position )
524538

525539
void QgsLineStringV2::addVertex( const QgsPointV2& pt )
526540
{
527-
if ( mWkbType == QgsWKBTypes::Unknown )
541+
if ( mWkbType == QgsWKBTypes::Unknown || mX.isEmpty() )
528542
{
529543
setZMTypeFromSubGeometry( &pt, QgsWKBTypes::LineString );
530544
}

‎src/core/geometry/qgslinestringv2.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ class CORE_EXPORT QgsLineStringV2: public QgsCurveV2
107107
*/
108108
void setMAt( int index, double m );
109109

110-
/** Resets the line string to match the specified list of points.
110+
/** Resets the line string to match the specified list of points. The line string will
111+
* inherit the dimensionality of the first point in the list.
111112
* @param points new points for line string. If empty, line string will be cleared.
112113
*/
113114
void setPoints( const QList<QgsPointV2>& points );

‎tests/src/core/testqgsgeometry.cpp

Lines changed: 552 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class TestQgsGeometry : public QObject
5555
void asVariant(); //test conversion to and from a QVariant
5656
void isEmpty();
5757
void pointV2(); //test QgsPointV2
58+
void lineStringV2(); //test QgsLineStringV2
5859

5960
void fromQgsPoint();
6061
void fromQPoint();
@@ -83,7 +84,7 @@ class TestQgsGeometry : public QObject
8384
void smoothCheck();
8485

8586
void dataStream();
86-
87+
8788
void exportToGeoJSON();
8889

8990
private:
@@ -96,6 +97,8 @@ class TestQgsGeometry : public QObject
9697
/** A helper method to dump to qdebug the geometry of a polyline */
9798
void dumpPolyline( QgsPolyline &thePolyline );
9899

100+
QString elemToString( const QDomElement& elem ) const;
101+
99102
QgsPoint mPoint1;
100103
QgsPoint mPoint2;
101104
QgsPoint mPoint3;
@@ -667,6 +670,554 @@ void TestQgsGeometry::pointV2()
667670

668671
}
669672

673+
void TestQgsGeometry::lineStringV2()
674+
{
675+
//test constructors
676+
QgsLineStringV2 l1;
677+
QVERIFY( l1.isEmpty() );
678+
QCOMPARE( l1.numPoints(), 0 );
679+
QVERIFY( !l1.is3D() );
680+
QVERIFY( !l1.isMeasure() );
681+
QCOMPARE( l1.wkbType(), QgsWKBTypes::LineString );
682+
QCOMPARE( l1.wktTypeStr(), QString( "LineString" ) );
683+
QCOMPARE( l1.geometryType(), QString( "LineString" ) );
684+
QCOMPARE( l1.dimension(), 1 );
685+
686+
//addVertex
687+
QgsLineStringV2 l2;
688+
l2.addVertex( QgsPointV2( 1.0, 2.0 ) );
689+
QVERIFY( !l2.isEmpty() );
690+
QCOMPARE( l2.numPoints(), 1 );
691+
QVERIFY( !l2.is3D() );
692+
QVERIFY( !l2.isMeasure() );
693+
QCOMPARE( l2.wkbType(), QgsWKBTypes::LineString );
694+
695+
//adding first vertex should set linestring z/m type
696+
QgsLineStringV2 l3;
697+
l3.addVertex( QgsPointV2( QgsWKBTypes::PointZ, 1.0, 2.0, 3.0 ) );
698+
QVERIFY( !l3.isEmpty() );
699+
QVERIFY( l3.is3D() );
700+
QVERIFY( !l3.isMeasure() );
701+
QCOMPARE( l3.wkbType(), QgsWKBTypes::LineStringZ );
702+
QCOMPARE( l3.wktTypeStr(), QString( "LineStringZ" ) );
703+
704+
QgsLineStringV2 l4;
705+
l4.addVertex( QgsPointV2( QgsWKBTypes::PointM, 1.0, 2.0, 0.0, 3.0 ) );
706+
QVERIFY( !l4.isEmpty() );
707+
QVERIFY( !l4.is3D() );
708+
QVERIFY( l4.isMeasure() );
709+
QCOMPARE( l4.wkbType(), QgsWKBTypes::LineStringM );
710+
QCOMPARE( l4.wktTypeStr(), QString( "LineStringM" ) );
711+
712+
QgsLineStringV2 l5;
713+
l5.addVertex( QgsPointV2( QgsWKBTypes::PointZM, 1.0, 2.0, 3.0, 4.0 ) );
714+
QVERIFY( !l5.isEmpty() );
715+
QVERIFY( l5.is3D() );
716+
QVERIFY( l5.isMeasure() );
717+
QCOMPARE( l5.wkbType(), QgsWKBTypes::LineStringZM );
718+
QCOMPARE( l5.wktTypeStr(), QString( "LineStringZM" ) );
719+
720+
//adding subsequent vertices should not alter z/m type, regardless of points type
721+
QgsLineStringV2 l6;
722+
l6.addVertex( QgsPointV2( QgsWKBTypes::Point, 1.0, 2.0 ) ); //2d type
723+
QCOMPARE( l6.wkbType(), QgsWKBTypes::LineString );
724+
l6.addVertex( QgsPointV2( QgsWKBTypes::PointZ, 11.0, 12.0, 13.0 ) ); // add 3d point
725+
QCOMPARE( l6.numPoints(), 2 );
726+
QCOMPARE( l6.wkbType(), QgsWKBTypes::LineString ); //should still be 2d
727+
QVERIFY( !l6.is3D() );
728+
729+
QgsLineStringV2 l7;
730+
l7.addVertex( QgsPointV2( QgsWKBTypes::PointZ, 1.0, 2.0, 3.0 ) ); //3d type
731+
QCOMPARE( l7.wkbType(), QgsWKBTypes::LineStringZ );
732+
l7.addVertex( QgsPointV2( QgsWKBTypes::Point, 11.0, 12.0 ) ); //add 2d point
733+
QCOMPARE( l7.wkbType(), QgsWKBTypes::LineStringZ ); //should still be 3d
734+
QCOMPARE( l7.pointN( 1 ), QgsPointV2( QgsWKBTypes::PointZ, 11.0, 12.0, 0.0 ) );
735+
QVERIFY( l7.is3D() );
736+
QCOMPARE( l7.numPoints(), 2 );
737+
738+
//clear
739+
l7.clear();
740+
QVERIFY( l7.isEmpty() );
741+
QCOMPARE( l7.numPoints(), 0 );
742+
QVERIFY( !l7.is3D() );
743+
QVERIFY( !l7.isMeasure() );
744+
QCOMPARE( l7.wkbType(), QgsWKBTypes::Unknown );
745+
746+
//setPoints
747+
QgsLineStringV2 l8;
748+
l8.setPoints( QList< QgsPointV2 >() << QgsPointV2( 1, 2 ) << QgsPointV2( 2, 3 ) << QgsPointV2( 3, 4 ) );
749+
QVERIFY( !l8.isEmpty() );
750+
QCOMPARE( l8.numPoints(), 3 );
751+
QVERIFY( !l8.is3D() );
752+
QVERIFY( !l8.isMeasure() );
753+
QCOMPARE( l8.wkbType(), QgsWKBTypes::LineString );
754+
755+
//setPoints with empty list, should clear linestring
756+
l8.setPoints( QList< QgsPointV2 >() );
757+
QVERIFY( l8.isEmpty() );
758+
QCOMPARE( l8.numPoints(), 0 );
759+
QCOMPARE( l8.wkbType(), QgsWKBTypes::Unknown );
760+
761+
//setPoints with z
762+
l8.setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::PointZ, 1, 2, 3 ) << QgsPointV2( QgsWKBTypes::PointZ, 2, 3, 4 ) );
763+
QCOMPARE( l8.numPoints(), 2 );
764+
QVERIFY( l8.is3D() );
765+
QVERIFY( !l8.isMeasure() );
766+
QCOMPARE( l8.wkbType(), QgsWKBTypes::LineStringZ );
767+
768+
//setPoints with m
769+
l8.setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::PointM, 1, 2, 0, 3 ) << QgsPointV2( QgsWKBTypes::PointM, 2, 3, 0, 4 ) );
770+
QCOMPARE( l8.numPoints(), 2 );
771+
QVERIFY( !l8.is3D() );
772+
QVERIFY( l8.isMeasure() );
773+
QCOMPARE( l8.wkbType(), QgsWKBTypes::LineStringM );
774+
775+
//setPoints with zm
776+
l8.setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::PointZM, 1, 2, 4, 5 ) << QgsPointV2( QgsWKBTypes::PointZM, 2, 3, 4, 5 ) );
777+
QCOMPARE( l8.numPoints(), 2 );
778+
QVERIFY( l8.is3D() );
779+
QVERIFY( l8.isMeasure() );
780+
QCOMPARE( l8.wkbType(), QgsWKBTypes::LineStringZM );
781+
782+
//setPoints with MIXED dimensionality of points
783+
l8.setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::PointZM, 1, 2, 4, 5 ) << QgsPointV2( QgsWKBTypes::PointM, 2, 3, 0, 5 ) );
784+
QCOMPARE( l8.numPoints(), 2 );
785+
QVERIFY( l8.is3D() );
786+
QVERIFY( l8.isMeasure() );
787+
QCOMPARE( l8.wkbType(), QgsWKBTypes::LineStringZM );
788+
789+
//test point
790+
QCOMPARE( l8.pointN( 0 ), QgsPointV2( QgsWKBTypes::PointZM, 1, 2, 4, 5 ) );
791+
QCOMPARE( l8.pointN( 1 ), QgsPointV2( QgsWKBTypes::PointZM, 2, 3, 0, 5 ) );
792+
793+
//out of range - just want no crash here
794+
QgsPointV2 bad = l8.pointN( -1 );
795+
bad = l8.pointN( 100 );
796+
797+
//test getters/setters
798+
QgsLineStringV2 l9;
799+
l9.setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::PointZM, 1, 2, 3, 4 )
800+
<< QgsPointV2( QgsWKBTypes::PointZM, 11, 12, 13, 14 )
801+
<< QgsPointV2( QgsWKBTypes::PointZM, 21, 22, 23, 24 ) );
802+
QCOMPARE( l9.xAt( 0 ), 1.0 );
803+
QCOMPARE( l9.xAt( 1 ), 11.0 );
804+
QCOMPARE( l9.xAt( 2 ), 21.0 );
805+
QCOMPARE( l9.xAt( -1 ), 0.0 ); //out of range
806+
QCOMPARE( l9.xAt( 11 ), 0.0 ); //out of range
807+
808+
l9.setXAt( 0, 51.0 );
809+
QCOMPARE( l9.xAt( 0 ), 51.0 );
810+
l9.setXAt( 1, 61.0 );
811+
QCOMPARE( l9.xAt( 1 ), 61.0 );
812+
l9.setXAt( -1, 51.0 ); //out of range
813+
l9.setXAt( 11, 51.0 ); //out of range
814+
815+
QCOMPARE( l9.yAt( 0 ), 2.0 );
816+
QCOMPARE( l9.yAt( 1 ), 12.0 );
817+
QCOMPARE( l9.yAt( 2 ), 22.0 );
818+
QCOMPARE( l9.yAt( -1 ), 0.0 ); //out of range
819+
QCOMPARE( l9.yAt( 11 ), 0.0 ); //out of range
820+
821+
l9.setYAt( 0, 52.0 );
822+
QCOMPARE( l9.yAt( 0 ), 52.0 );
823+
l9.setYAt( 1, 62.0 );
824+
QCOMPARE( l9.yAt( 1 ), 62.0 );
825+
l9.setYAt( -1, 52.0 ); //out of range
826+
l9.setYAt( 11, 52.0 ); //out of range
827+
828+
QCOMPARE( l9.zAt( 0 ), 3.0 );
829+
QCOMPARE( l9.zAt( 1 ), 13.0 );
830+
QCOMPARE( l9.zAt( 2 ), 23.0 );
831+
QCOMPARE( l9.zAt( -1 ), 0.0 ); //out of range
832+
QCOMPARE( l9.zAt( 11 ), 0.0 ); //out of range
833+
834+
l9.setZAt( 0, 53.0 );
835+
QCOMPARE( l9.zAt( 0 ), 53.0 );
836+
l9.setZAt( 1, 63.0 );
837+
QCOMPARE( l9.zAt( 1 ), 63.0 );
838+
l9.setZAt( -1, 53.0 ); //out of range
839+
l9.setZAt( 11, 53.0 ); //out of range
840+
841+
QCOMPARE( l9.mAt( 0 ), 4.0 );
842+
QCOMPARE( l9.mAt( 1 ), 14.0 );
843+
QCOMPARE( l9.mAt( 2 ), 24.0 );
844+
QCOMPARE( l9.mAt( -1 ), 0.0 ); //out of range
845+
QCOMPARE( l9.mAt( 11 ), 0.0 ); //out of range
846+
847+
l9.setMAt( 0, 54.0 );
848+
QCOMPARE( l9.mAt( 0 ), 54.0 );
849+
l9.setMAt( 1, 64.0 );
850+
QCOMPARE( l9.mAt( 1 ), 64.0 );
851+
l9.setMAt( -1, 54.0 ); //out of range
852+
l9.setMAt( 11, 54.0 ); //out of range
853+
854+
//check zAt/setZAt with non-3d linestring
855+
l9.setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::PointM, 1, 2, 0, 4 )
856+
<< QgsPointV2( QgsWKBTypes::PointM, 11, 12, 0, 14 )
857+
<< QgsPointV2( QgsWKBTypes::PointM, 21, 22, 0, 24 ) );
858+
859+
//basically we just don't want these to crash
860+
QCOMPARE( l9.zAt( 0 ), 0.0 );
861+
QCOMPARE( l9.zAt( 1 ), 0.0 );
862+
l9.setZAt( 0, 53.0 );
863+
l9.setZAt( 1, 63.0 );
864+
865+
//check mAt/setMAt with non-measure linestring
866+
l9.setPoints( QList< QgsPointV2 >() << QgsPointV2( 1, 2 )
867+
<< QgsPointV2( 11, 12 )
868+
<< QgsPointV2( 21, 22 ) );
869+
870+
//basically we just don't want these to crash
871+
QCOMPARE( l9.mAt( 0 ), 0.0 );
872+
QCOMPARE( l9.mAt( 1 ), 0.0 );
873+
l9.setMAt( 0, 53.0 );
874+
l9.setMAt( 1, 63.0 );
875+
876+
//append linestring
877+
878+
//append to empty
879+
QgsLineStringV2 l10;
880+
l10.append( 0 );
881+
QVERIFY( l10.isEmpty() );
882+
QCOMPARE( l10.numPoints(), 0 );
883+
884+
QScopedPointer<QgsLineStringV2> toAppend( new QgsLineStringV2() );
885+
toAppend->setPoints( QList< QgsPointV2 >() << QgsPointV2( 1, 2 )
886+
<< QgsPointV2( 11, 12 )
887+
<< QgsPointV2( 21, 22 ) );
888+
l10.append( toAppend.data() );
889+
QVERIFY( !l10.is3D() );
890+
QVERIFY( !l10.isMeasure() );
891+
QCOMPARE( l10.numPoints(), 3 );
892+
QCOMPARE( l10.wkbType(), QgsWKBTypes::LineString );
893+
QCOMPARE( l10.pointN( 0 ), toAppend->pointN( 0 ) );
894+
QCOMPARE( l10.pointN( 1 ), toAppend->pointN( 1 ) );
895+
QCOMPARE( l10.pointN( 2 ), toAppend->pointN( 2 ) );
896+
897+
//add more points
898+
toAppend.reset( new QgsLineStringV2() );
899+
toAppend->setPoints( QList< QgsPointV2 >() << QgsPointV2( 31, 32 )
900+
<< QgsPointV2( 41, 42 )
901+
<< QgsPointV2( 51, 52 ) );
902+
l10.append( toAppend.data() );
903+
QCOMPARE( l10.numPoints(), 6 );
904+
QCOMPARE( l10.pointN( 3 ), toAppend->pointN( 0 ) );
905+
QCOMPARE( l10.pointN( 4 ), toAppend->pointN( 1 ) );
906+
QCOMPARE( l10.pointN( 5 ), toAppend->pointN( 2 ) );
907+
908+
//check dimensionality is inherited from append line if initially empty
909+
l10.clear();
910+
toAppend.reset( new QgsLineStringV2() );
911+
toAppend->setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::PointZM, 31, 32, 33, 34 )
912+
<< QgsPointV2( QgsWKBTypes::PointZM, 41, 42, 43 , 44 )
913+
<< QgsPointV2( QgsWKBTypes::PointZM, 51, 52, 53, 54 ) );
914+
l10.append( toAppend.data() );
915+
QVERIFY( l10.is3D() );
916+
QVERIFY( l10.isMeasure() );
917+
QCOMPARE( l10.numPoints(), 3 );
918+
QCOMPARE( l10.wkbType(), QgsWKBTypes::LineStringZM );
919+
QCOMPARE( l10.pointN( 0 ), toAppend->pointN( 0 ) );
920+
QCOMPARE( l10.pointN( 1 ), toAppend->pointN( 1 ) );
921+
QCOMPARE( l10.pointN( 2 ), toAppend->pointN( 2 ) );
922+
923+
//append points with z to non z linestring
924+
l10.clear();
925+
l10.addVertex( QgsPointV2( 1.0, 2.0 ) );
926+
QVERIFY( !l10.is3D() );
927+
QCOMPARE( l10.wkbType(), QgsWKBTypes::LineString );
928+
toAppend.reset( new QgsLineStringV2() );
929+
toAppend->setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::PointZM, 31, 32, 33, 34 )
930+
<< QgsPointV2( QgsWKBTypes::PointZM, 41, 42, 43 , 44 )
931+
<< QgsPointV2( QgsWKBTypes::PointZM, 51, 52, 53, 54 ) );
932+
l10.append( toAppend.data() );
933+
QCOMPARE( l10.wkbType(), QgsWKBTypes::LineString );
934+
QCOMPARE( l10.pointN( 0 ), QgsPointV2( 1, 2 ) );
935+
QCOMPARE( l10.pointN( 1 ), QgsPointV2( 31, 32 ) );
936+
QCOMPARE( l10.pointN( 2 ), QgsPointV2( 41, 42 ) );
937+
QCOMPARE( l10.pointN( 3 ), QgsPointV2( 51, 52 ) );
938+
939+
//append points without z/m to linestring with z & m
940+
l10.clear();
941+
l10.addVertex( QgsPointV2( QgsWKBTypes::PointZM, 1.0, 2.0, 3.0, 4.0 ) );
942+
QVERIFY( l10.is3D() );
943+
QVERIFY( l10.isMeasure() );
944+
QCOMPARE( l10.wkbType(), QgsWKBTypes::LineStringZM );
945+
toAppend.reset( new QgsLineStringV2() );
946+
toAppend->setPoints( QList< QgsPointV2 >() << QgsPointV2( 31, 32 )
947+
<< QgsPointV2( 41, 42 )
948+
<< QgsPointV2( 51, 52 ) );
949+
l10.append( toAppend.data() );
950+
QCOMPARE( l10.wkbType(), QgsWKBTypes::LineStringZM );
951+
QCOMPARE( l10.pointN( 0 ), QgsPointV2( QgsWKBTypes::PointZM, 1, 2, 3, 4 ) );
952+
QCOMPARE( l10.pointN( 1 ), QgsPointV2( QgsWKBTypes::PointZM, 31, 32 ) );
953+
QCOMPARE( l10.pointN( 2 ), QgsPointV2( QgsWKBTypes::PointZM, 41, 42 ) );
954+
QCOMPARE( l10.pointN( 3 ), QgsPointV2( QgsWKBTypes::PointZM, 51, 52 ) );
955+
956+
//close
957+
QgsLineStringV2 l11;
958+
l11.setPoints( QList< QgsPointV2 >() << QgsPointV2( 1, 2 )
959+
<< QgsPointV2( 11, 2 )
960+
<< QgsPointV2( 11, 22 )
961+
<< QgsPointV2( 1, 22 ) );
962+
QVERIFY( !l11.isClosed() );
963+
QCOMPARE( l11.numPoints(), 4 );
964+
l11.close();
965+
QVERIFY( l11.isClosed() );
966+
QCOMPARE( l11.numPoints(), 5 );
967+
QCOMPARE( l11.pointN( 4 ), QgsPointV2( 1, 2 ) );
968+
969+
//close with z and m
970+
QgsLineStringV2 l12;
971+
l12.setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::PointZM, 1, 2, 3, 4 )
972+
<< QgsPointV2( QgsWKBTypes::PointZM, 11, 2, 11, 14 )
973+
<< QgsPointV2( QgsWKBTypes::PointZM, 11, 22, 21, 24 )
974+
<< QgsPointV2( QgsWKBTypes::PointZM, 1, 22, 31, 34 ) );
975+
l12.close();
976+
QCOMPARE( l12.pointN( 4 ), QgsPointV2( QgsWKBTypes::PointZM, 1, 2, 3, 4 ) );
977+
978+
979+
//polygonf
980+
QgsLineStringV2 l13;
981+
l13.setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::PointZM, 1, 2, 3, 4 )
982+
<< QgsPointV2( QgsWKBTypes::PointZM, 11, 2, 11, 14 )
983+
<< QgsPointV2( QgsWKBTypes::PointZM, 11, 22, 21, 24 )
984+
<< QgsPointV2( QgsWKBTypes::PointZM, 1, 22, 31, 34 ) );
985+
986+
QPolygonF poly = l13.asQPolygonF();
987+
QCOMPARE( poly.count(), 4 );
988+
QCOMPARE( poly.at( 0 ).x(), 1.0 );
989+
QCOMPARE( poly.at( 0 ).y(), 2.0 );
990+
QCOMPARE( poly.at( 1 ).x(), 11.0 );
991+
QCOMPARE( poly.at( 1 ).y(), 2.0 );
992+
QCOMPARE( poly.at( 2 ).x(), 11.0 );
993+
QCOMPARE( poly.at( 2 ).y(), 22.0 );
994+
QCOMPARE( poly.at( 3 ).x(), 1.0 );
995+
QCOMPARE( poly.at( 3 ).y(), 22.0 );
996+
997+
// clone
998+
QgsLineStringV2 l14;
999+
l14.setPoints( QList< QgsPointV2 >() << QgsPointV2( 1, 2 )
1000+
<< QgsPointV2( 11, 2 )
1001+
<< QgsPointV2( 11, 22 )
1002+
<< QgsPointV2( 1, 22 ) );
1003+
QScopedPointer<QgsLineStringV2> cloned( l14.clone() );
1004+
QCOMPARE( cloned->numPoints(), 4 );
1005+
QCOMPARE( cloned->wkbType(), QgsWKBTypes::LineString );
1006+
QVERIFY( !cloned->is3D() );
1007+
QVERIFY( !cloned->isMeasure() );
1008+
QCOMPARE( cloned->pointN( 0 ), l14.pointN( 0 ) );
1009+
QCOMPARE( cloned->pointN( 1 ), l14.pointN( 1 ) );
1010+
QCOMPARE( cloned->pointN( 2 ), l14.pointN( 2 ) );
1011+
QCOMPARE( cloned->pointN( 3 ), l14.pointN( 3 ) );
1012+
1013+
//clone with Z/M
1014+
l14.setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::PointZM, 1, 2, 3, 4 )
1015+
<< QgsPointV2( QgsWKBTypes::PointZM, 11, 2, 11, 14 )
1016+
<< QgsPointV2( QgsWKBTypes::PointZM, 11, 22, 21, 24 )
1017+
<< QgsPointV2( QgsWKBTypes::PointZM, 1, 22, 31, 34 ) );
1018+
cloned.reset( l14.clone() );
1019+
QCOMPARE( cloned->numPoints(), 4 );
1020+
QCOMPARE( cloned->wkbType(), QgsWKBTypes::LineStringZM );
1021+
QVERIFY( cloned->is3D() );
1022+
QVERIFY( cloned->isMeasure() );
1023+
QCOMPARE( cloned->pointN( 0 ), l14.pointN( 0 ) );
1024+
QCOMPARE( cloned->pointN( 1 ), l14.pointN( 1 ) );
1025+
QCOMPARE( cloned->pointN( 2 ), l14.pointN( 2 ) );
1026+
QCOMPARE( cloned->pointN( 3 ), l14.pointN( 3 ) );
1027+
1028+
//clone an empty line
1029+
l14.clear();
1030+
cloned.reset( l14.clone() );
1031+
QVERIFY( cloned->isEmpty() );
1032+
QCOMPARE( cloned->numPoints(), 0 );
1033+
QVERIFY( !cloned->is3D() );
1034+
QVERIFY( !cloned->isMeasure() );
1035+
QCOMPARE( cloned->wkbType(), QgsWKBTypes::Unknown );
1036+
1037+
//to/from WKB
1038+
QgsLineStringV2 l15;
1039+
l15.setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::PointZM, 1, 2, 3, 4 )
1040+
<< QgsPointV2( QgsWKBTypes::PointZM, 11, 2, 11, 14 )
1041+
<< QgsPointV2( QgsWKBTypes::PointZM, 11, 22, 21, 24 )
1042+
<< QgsPointV2( QgsWKBTypes::PointZM, 1, 22, 31, 34 ) );
1043+
int size = 0;
1044+
unsigned char* wkb = l15.asWkb( size );
1045+
QCOMPARE( size, l15.wkbSize() );
1046+
QgsLineStringV2 l16;
1047+
l16.fromWkb( wkb );
1048+
QCOMPARE( l16.numPoints(), 4 );
1049+
QCOMPARE( l16.wkbType(), QgsWKBTypes::LineStringZM );
1050+
QVERIFY( l16.is3D() );
1051+
QVERIFY( l16.isMeasure() );
1052+
QCOMPARE( l16.pointN( 0 ), l15.pointN( 0 ) );
1053+
QCOMPARE( l16.pointN( 1 ), l15.pointN( 1 ) );
1054+
QCOMPARE( l16.pointN( 2 ), l15.pointN( 2 ) );
1055+
QCOMPARE( l16.pointN( 3 ), l15.pointN( 3 ) );
1056+
1057+
//bad WKB - check for no crash
1058+
l16.clear();
1059+
QVERIFY( !l16.fromWkb( 0 ) );
1060+
QCOMPARE( l16.wkbType(), QgsWKBTypes::Unknown );
1061+
QgsPointV2 point( 1, 2 );
1062+
QVERIFY( !l16.fromWkb( point.asWkb( size ) ) );
1063+
QCOMPARE( l16.wkbType(), QgsWKBTypes::Unknown );
1064+
1065+
//TODO - from WKB points
1066+
1067+
//to/from WKT
1068+
QgsLineStringV2 l17;
1069+
l17.setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::PointZM, 1, 2, 3, 4 )
1070+
<< QgsPointV2( QgsWKBTypes::PointZM, 11, 2, 11, 14 )
1071+
<< QgsPointV2( QgsWKBTypes::PointZM, 11, 22, 21, 24 )
1072+
<< QgsPointV2( QgsWKBTypes::PointZM, 1, 22, 31, 34 ) );
1073+
1074+
QString wkt = l17.asWkt();
1075+
QVERIFY( !wkt.isEmpty() );
1076+
QgsLineStringV2 l18;
1077+
QVERIFY( l18.fromWkt( wkt ) );
1078+
QCOMPARE( l18.numPoints(), 4 );
1079+
QCOMPARE( l18.wkbType(), QgsWKBTypes::LineStringZM );
1080+
QVERIFY( l18.is3D() );
1081+
QVERIFY( l18.isMeasure() );
1082+
QCOMPARE( l18.pointN( 0 ), l17.pointN( 0 ) );
1083+
QCOMPARE( l18.pointN( 1 ), l17.pointN( 1 ) );
1084+
QCOMPARE( l18.pointN( 2 ), l17.pointN( 2 ) );
1085+
QCOMPARE( l18.pointN( 3 ), l17.pointN( 3 ) );
1086+
1087+
//bad WKT
1088+
QVERIFY( !l18.fromWkt( "Polygon()" ) );
1089+
QVERIFY( l18.isEmpty() );
1090+
QCOMPARE( l18.numPoints(), 0 );
1091+
QVERIFY( !l18.is3D() );
1092+
QVERIFY( !l18.isMeasure() );
1093+
QCOMPARE( l18.wkbType(), QgsWKBTypes::Unknown );
1094+
1095+
//asGML2
1096+
QgsLineStringV2 exportLine;
1097+
exportLine.setPoints( QList< QgsPointV2 >() << QgsPointV2( 31, 32 )
1098+
<< QgsPointV2( 41, 42 )
1099+
<< QgsPointV2( 51, 52 ) );
1100+
QgsLineStringV2 exportLineFloat;
1101+
exportLineFloat.setPoints( QList< QgsPointV2 >() << QgsPointV2( 1 / 3.0, 2 / 3.0 )
1102+
<< QgsPointV2( 1 + 1 / 3.0, 1 + 2 / 3.0 )
1103+
<< QgsPointV2( 2 + 1 / 3.0, 2 + 2 / 3.0 ) );
1104+
QDomDocument doc( "gml" );
1105+
QString expectedGML2( "<LineString xmlns=\"gml\"><coordinates xmlns=\"gml\">31,32 41,42 51,52</coordinates></LineString>" );
1106+
QCOMPARE( elemToString( exportLine.asGML2( doc ) ), expectedGML2 );
1107+
QString expectedGML2prec3( "<LineString xmlns=\"gml\"><coordinates xmlns=\"gml\">0.333,0.667 1.333,1.667 2.333,2.667</coordinates></LineString>" );
1108+
QCOMPARE( elemToString( exportLineFloat.asGML2( doc, 3 ) ), expectedGML2prec3 );
1109+
1110+
//asGML3
1111+
QString expectedGML3( "<Curve xmlns=\"gml\"><segments xmlns=\"gml\"><LineStringSegment xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">31 32 41 42 51 52</posList></LineStringSegment></segments></Curve>" );
1112+
QCOMPARE( elemToString( exportLine.asGML3( doc ) ), expectedGML3 );
1113+
QString expectedGML3prec3( "<Curve xmlns=\"gml\"><segments xmlns=\"gml\"><LineStringSegment xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">0.333 0.667 1.333 1.667 2.333 2.667</posList></LineStringSegment></segments></Curve>" );
1114+
QCOMPARE( elemToString( exportLineFloat.asGML3( doc, 3 ) ), expectedGML3prec3 );
1115+
1116+
//asJSON
1117+
QString expectedJson( "{\"type\": \"LineString\", \"coordinates\": [ [31, 32], [41, 42], [51, 52]]}" );
1118+
QCOMPARE( exportLine.asJSON(), expectedJson );
1119+
QString expectedJsonPrec3( "{\"type\": \"LineString\", \"coordinates\": [ [0.333, 0.667], [1.333, 1.667], [2.333, 2.667]]}" );
1120+
QCOMPARE( exportLineFloat.asJSON( 3 ), expectedJsonPrec3 );
1121+
1122+
//length
1123+
QgsLineStringV2 l19;
1124+
QCOMPARE( l19.length(), 0.0 );
1125+
l19.setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::PointZM, 1, 1, 2, 3 )
1126+
<< QgsPointV2( QgsWKBTypes::PointZM, 1, 10, 4, 5 )
1127+
<< QgsPointV2( QgsWKBTypes::PointZM, 15, 10, 6, 7 ) );
1128+
QCOMPARE( l19.length(), 23.0 );
1129+
1130+
//startPoint
1131+
QCOMPARE( l19.startPoint(), QgsPointV2( QgsWKBTypes::PointZM, 1, 1, 2, 3 ) );
1132+
1133+
//endPoint
1134+
QCOMPARE( l19.endPoint(), QgsPointV2( QgsWKBTypes::PointZM, 15, 10, 6, 7 ) );
1135+
1136+
//bad start/end points. Test that this doesn't crash.
1137+
l19.clear();
1138+
QCOMPARE( l19.startPoint(), QgsPointV2() );
1139+
QCOMPARE( l19.endPoint(), QgsPointV2() );
1140+
1141+
//curveToLine - no segmentation required, so should return a clone
1142+
l19.setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::PointZM, 1, 1, 2, 3 )
1143+
<< QgsPointV2( QgsWKBTypes::PointZM, 1, 10, 4, 5 )
1144+
<< QgsPointV2( QgsWKBTypes::PointZM, 15, 10, 6, 7 ) );
1145+
QScopedPointer< QgsLineStringV2 > segmentized( l19.curveToLine() );
1146+
QCOMPARE( segmentized->numPoints(), 3 );
1147+
QCOMPARE( segmentized->wkbType(), QgsWKBTypes::LineStringZM );
1148+
QVERIFY( segmentized->is3D() );
1149+
QVERIFY( segmentized->isMeasure() );
1150+
QCOMPARE( segmentized->pointN( 0 ), l19.pointN( 0 ) );
1151+
QCOMPARE( segmentized->pointN( 1 ), l19.pointN( 1 ) );
1152+
QCOMPARE( segmentized->pointN( 2 ), l19.pointN( 2 ) );
1153+
1154+
// points
1155+
QgsLineStringV2 l20;
1156+
QList< QgsPointV2 > points;
1157+
l20.points( points );
1158+
QVERIFY( l20.isEmpty() );
1159+
l20.setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::PointZM, 1, 1, 2, 3 )
1160+
<< QgsPointV2( QgsWKBTypes::PointZM, 1, 10, 4, 5 )
1161+
<< QgsPointV2( QgsWKBTypes::PointZM, 15, 10, 6, 7 ) );
1162+
l20.points( points );
1163+
QCOMPARE( points.count(), 3 );
1164+
QCOMPARE( points.at( 0 ), QgsPointV2( QgsWKBTypes::PointZM, 1, 1, 2, 3 ) );
1165+
QCOMPARE( points.at( 1 ), QgsPointV2( QgsWKBTypes::PointZM, 1, 10, 4, 5 ) );
1166+
QCOMPARE( points.at( 2 ), QgsPointV2( QgsWKBTypes::PointZM, 15, 10, 6, 7 ) );
1167+
1168+
//CRS transform
1169+
QgsCoordinateReferenceSystem sourceSrs;
1170+
sourceSrs.createFromSrid( 3994 );
1171+
QgsCoordinateReferenceSystem destSrs;
1172+
destSrs.createFromSrid( 4326 );
1173+
QgsCoordinateTransform tr( sourceSrs, destSrs );
1174+
1175+
// 2d CRS transform
1176+
QgsLineStringV2 l21;
1177+
l21.setPoints( QList< QgsPointV2 >() << QgsPointV2( 6374985, -3626584 )
1178+
<< QgsPointV2( 6474985, -3526584 ) );
1179+
l21.transform( tr, QgsCoordinateTransform::ForwardTransform );
1180+
QVERIFY( qgsDoubleNear( l21.pointN( 0 ).x(), 175.771, 0.001 ) );
1181+
QVERIFY( qgsDoubleNear( l21.pointN( 0 ).y(), -39.722, 0.001 ) );
1182+
QVERIFY( qgsDoubleNear( l21.pointN( 1 ).x(), 176.959, 0.001 ) );
1183+
QVERIFY( qgsDoubleNear( l21.pointN( 1 ).y(), -38.798, 0.001 ) );
1184+
1185+
//3d CRS transform
1186+
QgsLineStringV2 l22;
1187+
l22.setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::PointZM, 6374985, -3626584, 1, 2 )
1188+
<< QgsPointV2( QgsWKBTypes::PointZM, 6474985, -3526584, 3, 4 ) );
1189+
l22.transform( tr, QgsCoordinateTransform::ForwardTransform );
1190+
QVERIFY( qgsDoubleNear( l22.pointN( 0 ).x(), 175.771, 0.001 ) );
1191+
QVERIFY( qgsDoubleNear( l22.pointN( 0 ).y(), -39.722, 0.001 ) );
1192+
QVERIFY( qgsDoubleNear( l22.pointN( 0 ).z(), 57.2958, 0.001 ) );
1193+
QCOMPARE( l22.pointN( 0 ).m(), 2.0 );
1194+
QVERIFY( qgsDoubleNear( l22.pointN( 1 ).x(), 176.959, 0.001 ) );
1195+
QVERIFY( qgsDoubleNear( l22.pointN( 1 ).y(), -38.798, 0.001 ) );
1196+
QVERIFY( qgsDoubleNear( l22.pointN( 1 ).z(), 171.887, 0.001 ) );
1197+
QCOMPARE( l22.pointN( 1 ).m(), 4.0 );
1198+
1199+
//reverse transform
1200+
l22.transform( tr, QgsCoordinateTransform::ReverseTransform );
1201+
QVERIFY( qgsDoubleNear( l22.pointN( 0 ).x(), 6374985, 0.01 ) );
1202+
QVERIFY( qgsDoubleNear( l22.pointN( 0 ).y(), -3626584, 0.01 ) );
1203+
QVERIFY( qgsDoubleNear( l22.pointN( 0 ).z(), 1, 0.001 ) );
1204+
QCOMPARE( l22.pointN( 0 ).m(), 2.0 );
1205+
QVERIFY( qgsDoubleNear( l22.pointN( 1 ).x(), 6474985, 0.01 ) );
1206+
QVERIFY( qgsDoubleNear( l22.pointN( 1 ).y(), -3526584, 0.01 ) );
1207+
QVERIFY( qgsDoubleNear( l22.pointN( 1 ).z(), 3, 0.001 ) );
1208+
QCOMPARE( l22.pointN( 1 ).m(), 4.0 );
1209+
1210+
//QTransform transform
1211+
QTransform qtr = QTransform::fromScale( 2, 3 );
1212+
QgsLineStringV2 l23;
1213+
l23.setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::PointZM, 1, 2, 3, 4 )
1214+
<< QgsPointV2( QgsWKBTypes::PointZM, 11, 12, 13, 14 ) );
1215+
l23.transform( qtr );
1216+
QCOMPARE( l23.pointN( 0 ), QgsPointV2( QgsWKBTypes::PointZM, 2, 6, 3, 4 ) );
1217+
QCOMPARE( l23.pointN( 1 ), QgsPointV2( QgsWKBTypes::PointZM, 22, 36, 13, 14 ) );
1218+
}
1219+
1220+
6701221
void TestQgsGeometry::fromQgsPoint()
6711222
{
6721223
QgsPoint point( 1.0, 2.0 );

0 commit comments

Comments
 (0)
Please sign in to comment.