Skip to content

Commit 1f33011

Browse files
committedNov 27, 2015
Add more tests to QgsLineStringV2, fix vertexAngle calculation
1 parent 6ab718d commit 1f33011

File tree

4 files changed

+105
-13
lines changed

4 files changed

+105
-13
lines changed
 

‎python/core/geometry/qgsabstractgeometryv2.sip

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,12 @@ class QgsAbstractGeometryV2
157157
/** Returns a geometry without curves. Caller takes ownership*/
158158
virtual QgsAbstractGeometryV2* segmentize() const /Factory/;
159159

160-
/** Returns approximate rotation angle for a vertex. Usually average angle between adjacent segments.
161-
@return rotation in radians, clockwise from north*/
160+
/** Returns approximate angle at a vertex. This is usually the average angle between adjacent
161+
* segments, and can be pictured as the orientation of a line following the curvature of the
162+
* geometry at the specified vertex.
163+
* @param vertex the vertex id
164+
* @return rotation in radians, clockwise from north
165+
*/
162166
virtual double vertexAngle( const QgsVertexId& vertex ) const = 0;
163167

164168
virtual int vertexCount(int part = 0, int ring = 0) const = 0;

‎src/core/geometry/qgsabstractgeometryv2.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -294,9 +294,12 @@ class CORE_EXPORT QgsAbstractGeometryV2
294294
*/
295295
virtual QgsAbstractGeometryV2* segmentize() const { return clone(); }
296296

297-
/** Returns approximate rotation angle for a vertex. Usually average angle between adjacent segments.
298-
@param vertex the vertex id
299-
@return rotation in radians, clockwise from north*/
297+
/** Returns approximate angle at a vertex. This is usually the average angle between adjacent
298+
* segments, and can be pictured as the orientation of a line following the curvature of the
299+
* geometry at the specified vertex.
300+
* @param vertex the vertex id
301+
* @return rotation in radians, clockwise from north
302+
*/
300303
virtual double vertexAngle( const QgsVertexId& vertex ) const = 0;
301304

302305
virtual int vertexCount( int part = 0, int ring = 0 ) const = 0;

‎src/core/geometry/qgslinestringv2.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -705,12 +705,18 @@ void QgsLineStringV2::close()
705705

706706
double QgsLineStringV2::vertexAngle( const QgsVertexId& vertex ) const
707707
{
708+
if ( mX.count() < 2 )
709+
{
710+
//undefined
711+
return 0.0;
712+
}
713+
708714
if ( vertex.vertex == 0 || vertex.vertex >= ( numPoints() - 1 ) )
709715
{
710716
if ( isClosed() )
711717
{
712-
double previousX = mX.at( numPoints() - 1 );
713-
double previousY = mY.at( numPoints() - 1 );
718+
double previousX = mX.at( numPoints() - 2 );
719+
double previousY = mY.at( numPoints() - 2 );
714720
double currentX = mX.at( 0 );
715721
double currentY = mY.at( 0 );
716722
double afterX = mX.at( 1 );
@@ -719,13 +725,13 @@ double QgsLineStringV2::vertexAngle( const QgsVertexId& vertex ) const
719725
}
720726
else if ( vertex.vertex == 0 )
721727
{
722-
return QgsGeometryUtils::linePerpendicularAngle( mX.at( 0 ), mY.at( 0 ), mX.at( 1 ), mY.at( 1 ) );
728+
return QgsGeometryUtils::lineAngle( mX.at( 0 ), mY.at( 0 ), mX.at( 1 ), mY.at( 1 ) );
723729
}
724730
else
725731
{
726732
int a = numPoints() - 2;
727733
int b = numPoints() - 1;
728-
return QgsGeometryUtils::linePerpendicularAngle( mX.at( a ), mY.at( a ), mX.at( b ), mY.at( b ) );
734+
return QgsGeometryUtils::lineAngle( mX.at( a ), mY.at( a ), mX.at( b ), mY.at( b ) );
729735
}
730736
}
731737
else

‎tests/src/core/testqgsgeometry.cpp

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,6 +1339,10 @@ void TestQgsGeometry::lineStringV2()
13391339
QVERIFY( qgsDoubleNear( l21.pointN( 0 ).y(), -39.722, 0.001 ) );
13401340
QVERIFY( qgsDoubleNear( l21.pointN( 1 ).x(), 176.959, 0.001 ) );
13411341
QVERIFY( qgsDoubleNear( l21.pointN( 1 ).y(), -38.798, 0.001 ) );
1342+
QVERIFY( qgsDoubleNear( l21.boundingBox().xMinimum(), 175.771, 0.001 ) );
1343+
QVERIFY( qgsDoubleNear( l21.boundingBox().yMinimum(), -39.722, 0.001 ) );
1344+
QVERIFY( qgsDoubleNear( l21.boundingBox().xMaximum(), 176.959, 0.001 ) );
1345+
QVERIFY( qgsDoubleNear( l21.boundingBox().yMaximum(), -38.798, 0.001 ) );
13421346

13431347
//3d CRS transform
13441348
QgsLineStringV2 l22;
@@ -1373,7 +1377,7 @@ void TestQgsGeometry::lineStringV2()
13731377
l23.transform( qtr );
13741378
QCOMPARE( l23.pointN( 0 ), QgsPointV2( QgsWKBTypes::PointZM, 2, 6, 3, 4 ) );
13751379
QCOMPARE( l23.pointN( 1 ), QgsPointV2( QgsWKBTypes::PointZM, 22, 36, 13, 14 ) );
1376-
1380+
QCOMPARE( l23.boundingBox(), QgsRectangle( 2, 6, 22, 36 ) );
13771381

13781382
//insert vertex
13791383

@@ -1784,7 +1788,12 @@ void TestQgsGeometry::lineStringV2()
17841788
QCOMPARE( l34.centroid(), QgsPointV2( 10, 5 ) );
17851789
l34.setPoints( QList< QgsPointV2 >() << QgsPointV2( 0, 0 ) << QgsPointV2( 0, 9 ) << QgsPointV2( 2, 9 ) << QgsPointV2( 2, 0 ) );
17861790
QCOMPARE( l34.centroid(), QgsPointV2( 1, 4.95 ) );
1787-
1791+
//linestring with 0 length segment
1792+
l34.setPoints( QList< QgsPointV2 >() << QgsPointV2( 0, 0 ) << QgsPointV2( 0, 9 ) << QgsPointV2( 2, 9 ) << QgsPointV2( 2, 9 ) << QgsPointV2( 2, 0 ) );
1793+
QCOMPARE( l34.centroid(), QgsPointV2( 1, 4.95 ) );
1794+
//linestring with 0 total length segment
1795+
l34.setPoints( QList< QgsPointV2 >() << QgsPointV2( 5, 4 ) << QgsPointV2( 5, 4 ) << QgsPointV2( 5, 4 ) );
1796+
QCOMPARE( l34.centroid(), QgsPointV2( 5, 4 ) );
17881797

17891798
//closest segment
17901799
QgsLineStringV2 l35;
@@ -1837,10 +1846,80 @@ void TestQgsGeometry::lineStringV2()
18371846
l36.sumUpArea( area );
18381847
QVERIFY( qgsDoubleNear( area, 7.0 ) );
18391848

1840-
//boundingBox
1841-
1849+
//boundingBox - test that bounding box is updated after every modification to the line string
1850+
QgsLineStringV2 l37;
1851+
QVERIFY( l37.boundingBox().isNull() );
1852+
l37.setPoints( QList< QgsPointV2 >() << QgsPointV2( 5, 10 ) << QgsPointV2( 10, 15 ) );
1853+
QCOMPARE( l37.boundingBox(), QgsRectangle( 5, 10, 10, 15 ) );
1854+
l37.setPoints( QList< QgsPointV2 >() << QgsPointV2( -5, -10 ) << QgsPointV2( -6, -10 ) << QgsPointV2( -5.5, -9 ) );
1855+
QCOMPARE( l37.boundingBox(), QgsRectangle( -6, -10, -5, -9 ) );
1856+
//setXAt
1857+
l37.setXAt( 2, -4 );
1858+
QCOMPARE( l37.boundingBox(), QgsRectangle( -6, -10, -4, -9 ) );
1859+
//setYAt
1860+
l37.setYAt( 1, -15 );
1861+
QCOMPARE( l37.boundingBox(), QgsRectangle( -6, -15, -4, -9 ) );
1862+
//append
1863+
toAppend.reset( new QgsLineStringV2() );
1864+
toAppend->setPoints( QList< QgsPointV2 >() << QgsPointV2( 1, 2 ) << QgsPointV2( 4, 0 ) );
1865+
l37.append( toAppend.data() );
1866+
QCOMPARE( l37.boundingBox(), QgsRectangle( -6, -15, 4, 2 ) );
1867+
l37.addVertex( QgsPointV2( 6, 3 ) );
1868+
QCOMPARE( l37.boundingBox(), QgsRectangle( -6, -15, 6, 3 ) );
1869+
l37.clear();
1870+
QVERIFY( l37.boundingBox().isNull() );
1871+
l37.setPoints( QList< QgsPointV2 >() << QgsPointV2( 5, 10 ) << QgsPointV2( 10, 15 ) );
1872+
wkb = toAppend->asWkb( size );
1873+
l37.fromWkb( wkb );
1874+
delete wkb;
1875+
wkb = 0;
1876+
QCOMPARE( l37.boundingBox(), QgsRectangle( 1, 0, 4, 2 ) );
1877+
l37.fromWkt( QString( "LineString( 1 5, 3 4, 6 3 )" ) );
1878+
QCOMPARE( l37.boundingBox(), QgsRectangle( 1, 3, 6, 5 ) );
1879+
l37.insertVertex( QgsVertexId( 0, 0, 1 ), QgsPointV2( -1, 7 ) );
1880+
QCOMPARE( l37.boundingBox(), QgsRectangle( -1, 3, 6, 7 ) );
1881+
l37.moveVertex( QgsVertexId( 0, 0, 1 ), QgsPointV2( -3, 10 ) );
1882+
QCOMPARE( l37.boundingBox(), QgsRectangle( -3, 3, 6, 10 ) );
1883+
l37.deleteVertex( QgsVertexId( 0, 0, 1 ) );
1884+
QCOMPARE( l37.boundingBox(), QgsRectangle( 1, 3, 6, 5 ) );
18421885

18431886
//angle
1887+
QgsLineStringV2 l38;
1888+
( void )l38.vertexAngle( QgsVertexId() ); //just want no crash
1889+
( void )l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ); //just want no crash
1890+
l38.setPoints( QList< QgsPointV2 >() << QgsPointV2( 0, 0 ) );
1891+
( void )l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ); //just want no crash, any answer is meaningless
1892+
l38.setPoints( QList< QgsPointV2 >() << QgsPointV2( 0, 0 ) << QgsPointV2( 1, 0 ) );
1893+
QVERIFY( qgsDoubleNear( l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 1.5708, 0.0001 ) );
1894+
QVERIFY( qgsDoubleNear( l38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 1.5708, 0.0001 ) );
1895+
( void )l38.vertexAngle( QgsVertexId( 0, 0, 2 ) ); //no crash
1896+
l38.setPoints( QList< QgsPointV2 >() << QgsPointV2( 0, 0 ) << QgsPointV2( 0, 1 ) );
1897+
QVERIFY( qgsDoubleNear( l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 0.0 ) );
1898+
QVERIFY( qgsDoubleNear( l38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 0.0 ) );
1899+
l38.setPoints( QList< QgsPointV2 >() << QgsPointV2( 1, 0 ) << QgsPointV2( 0, 0 ) );
1900+
QVERIFY( qgsDoubleNear( l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 4.71239, 0.0001 ) );
1901+
QVERIFY( qgsDoubleNear( l38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 4.71239, 0.0001 ) );
1902+
l38.setPoints( QList< QgsPointV2 >() << QgsPointV2( 0, 1 ) << QgsPointV2( 0, 0 ) );
1903+
QVERIFY( qgsDoubleNear( l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 3.1416, 0.0001 ) );
1904+
QVERIFY( qgsDoubleNear( l38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 3.1416, 0.0001 ) );
1905+
l38.setPoints( QList< QgsPointV2 >() << QgsPointV2( 0, 0 ) << QgsPointV2( 1, 0 ) << QgsPointV2( 1, 1 ) );
1906+
QVERIFY( qgsDoubleNear( l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 1.5708, 0.0001 ) );
1907+
QVERIFY( qgsDoubleNear( l38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 0.7854, 0.0001 ) );
1908+
QVERIFY( qgsDoubleNear( l38.vertexAngle( QgsVertexId( 0, 0, 2 ) ), 0.0, 0.0001 ) );
1909+
l38.setPoints( QList< QgsPointV2 >() << QgsPointV2( 0, 0 ) << QgsPointV2( 0.5, 0 ) << QgsPointV2( 1, 0 )
1910+
<< QgsPointV2( 2, 1 ) << QgsPointV2( 1, 2 ) << QgsPointV2( 0, 2 ) );
1911+
( void )l38.vertexAngle( QgsVertexId( 0, 0, 20 ) );
1912+
QVERIFY( qgsDoubleNear( l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 1.5708, 0.0001 ) );
1913+
QVERIFY( qgsDoubleNear( l38.vertexAngle( QgsVertexId( 0, 0, 1 ) ), 1.5708, 0.0001 ) );
1914+
QVERIFY( qgsDoubleNear( l38.vertexAngle( QgsVertexId( 0, 0, 2 ) ), 1.17809, 0.00001 ) );
1915+
QVERIFY( qgsDoubleNear( l38.vertexAngle( QgsVertexId( 0, 0, 3 ) ), 0.0, 0.00001 ) );
1916+
QVERIFY( qgsDoubleNear( l38.vertexAngle( QgsVertexId( 0, 0, 4 ) ), 5.10509, 0.00001 ) );
1917+
QVERIFY( qgsDoubleNear( l38.vertexAngle( QgsVertexId( 0, 0, 5 ) ), 4.71239, 0.00001 ) );
1918+
//closed line string
1919+
l38.close();
1920+
QVERIFY( qgsDoubleNear( l38.vertexAngle( QgsVertexId( 0, 0, 5 ) ), 3.92699, 0.00001 ) );
1921+
QVERIFY( qgsDoubleNear( l38.vertexAngle( QgsVertexId( 0, 0, 0 ) ), 2.35619, 0.00001 ) );
1922+
QVERIFY( qgsDoubleNear( l38.vertexAngle( QgsVertexId( 0, 0, 6 ) ), 2.35619, 0.00001 ) );
18441923

18451924
}
18461925

0 commit comments

Comments
 (0)
Please sign in to comment.