Skip to content
Permalink
Browse files

Move extraction of linestrings out of QgsExpression file + add unit test

  • Loading branch information
wonder-sk committed Jan 27, 2016
1 parent 5210c12 commit 9fd6b246867a9e54c8fa812cc3a7fc1a2a79e9e8
@@ -14,10 +14,52 @@ email : marco.hugentobler at sourcepole dot com
***************************************************************************/

#include "qgsgeometryutils.h"

#include "qgscurvev2.h"
#include "qgscurvepolygonv2.h"
#include "qgsgeometrycollectionv2.h"
#include "qgslinestringv2.h"
#include "qgswkbptr.h"

#include <QStringList>
#include <QVector>

QList<QgsLineStringV2*> QgsGeometryUtils::extractLineStrings(const QgsAbstractGeometryV2* geom)
{
QList< QgsLineStringV2* > linestrings;
if ( !geom )
return linestrings;

QList< const QgsAbstractGeometryV2 * > geometries;
geometries << geom;
while ( ! geometries.isEmpty() )
{
const QgsAbstractGeometryV2* g = geometries.takeFirst();
if ( const QgsCurveV2* curve = dynamic_cast< const QgsCurveV2* >( g ) )
{
linestrings << static_cast< QgsLineStringV2* >( curve->segmentize() );
}
else if ( const QgsGeometryCollectionV2* collection = dynamic_cast< const QgsGeometryCollectionV2* >( g ) )
{
for ( int i = 0; i < collection->numGeometries(); ++i )
{
geometries.append( collection->geometryN( i ) );
}
}
else if ( const QgsCurvePolygonV2* curvePolygon = dynamic_cast< const QgsCurvePolygonV2* >( g ) )
{
if ( curvePolygon->exteriorRing() )
linestrings << static_cast< QgsLineStringV2* >( curvePolygon->exteriorRing()->segmentize() );

for ( int i = 0; i < curvePolygon->numInteriorRings(); ++i )
{
linestrings << static_cast< QgsLineStringV2* >( curvePolygon->interiorRing( i )->segmentize() );
}
}
}
return linestrings;
}

QgsPointV2 QgsGeometryUtils::closestVertex( const QgsAbstractGeometryV2& geom, const QgsPointV2& pt, QgsVertexId& id )
{
double minDist = std::numeric_limits<double>::max();
@@ -19,6 +19,8 @@ email : marco.hugentobler at sourcepole dot com
#include "qgspointv2.h"
#include <limits>

class QgsLineStringV2;

/** \ingroup core
* \class QgsGeometryUtils
* \brief Contains various geometry utility functions.
@@ -30,6 +32,11 @@ class CORE_EXPORT QgsGeometryUtils
{
public:

/** Returns list of linestrings extracted from the passed geometry. The returned objects
* have to be deleted by the caller.
*/
static QList<QgsLineStringV2*> extractLineStrings( const QgsAbstractGeometryV2* geom );

/** Returns the closest vertex to a geometry for a specified point
*/
static QgsPointV2 closestVertex( const QgsAbstractGeometryV2& geom, const QgsPointV2& pt, QgsVertexId& id );
@@ -29,6 +29,7 @@
#include "qgsfeature.h"
#include "qgsgeometry.h"
#include "qgsgeometryengine.h"
#include "qgsgeometryutils.h"
#include "qgslogger.h"
#include "qgsmaplayerregistry.h"
#include "qgsogcutils.h"
@@ -1432,52 +1433,7 @@ static QVariant fcnSegmentsToLines( const QVariantList& values, const QgsExpress
if ( geom.isEmpty() )
return QVariant();

QList< QgsAbstractGeometryV2 * > geometries;

QgsGeometryCollectionV2* collection = dynamic_cast< QgsGeometryCollectionV2* >( geom.geometry() );
if ( collection )
{
for ( int i = 0; i < collection->numGeometries(); ++i )
{
geometries.append( collection->geometryN( i ) );
}
}
else
{
geometries.append( geom.geometry() );
}

QList< QgsLineStringV2* > linesToProcess;
while ( ! geometries.isEmpty() )
{
QgsAbstractGeometryV2* g = geometries.takeFirst();
QgsCurveV2* curve = dynamic_cast< QgsCurveV2* >( g );
if ( curve )
{
linesToProcess << static_cast< QgsLineStringV2* >( curve->segmentize() );
continue;
}
QgsGeometryCollectionV2* collection = dynamic_cast< QgsGeometryCollectionV2* >( g );
if ( collection )
{
for ( int i = 0; i < collection->numGeometries(); ++i )
{
geometries.append( collection->geometryN( i ) );
}
}
QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( g );
if ( curvePolygon )
{
if ( curvePolygon->exteriorRing() )
linesToProcess << static_cast< QgsLineStringV2* >( curvePolygon->exteriorRing()->segmentize() );

for ( int i = 0; i < curvePolygon->numInteriorRings(); ++i )
{
linesToProcess << static_cast< QgsLineStringV2* >( curvePolygon->interiorRing( i )->segmentize() );
}
continue;
}
}
QList< QgsLineStringV2* > linesToProcess = QgsGeometryUtils::extractLineStrings( geom.geometry() );

//ok, now we have a complete list of segmentized lines from the geometry
QgsMultiLineStringV2* ml = new QgsMultiLineStringV2();
@@ -16,11 +16,15 @@
#include <QtTest/QtTest>
#include <QObject>
#include "qgsgeometryutils.h"
#include "qgslinestringv2.h"
#include "qgspolygonv2.h"
#include "qgsmultipolygonv2.h"

class TestQgsGeometryUtils: public QObject
{
Q_OBJECT
private slots:
void testExtractLinestrings();
void testCircleClockwise_data();
void testCircleClockwise();
void testAngleOnCircle_data();
@@ -41,6 +45,32 @@ class TestQgsGeometryUtils: public QObject
void testAverageAngle();
};


void TestQgsGeometryUtils::testExtractLinestrings()
{
QgsLineStringV2* outerRing1 = new QgsLineStringV2();
outerRing1->setPoints( QList<QgsPointV2>() << QgsPointV2( 1, 1 ) << QgsPointV2( 1, 2 ) << QgsPointV2( 2, 2 ) << QgsPointV2( 2, 1 ) << QgsPointV2( 1, 1 ) );
QgsPolygonV2* polygon1 = new QgsPolygonV2();
polygon1->setExteriorRing( outerRing1 );

QgsLineStringV2* outerRing2 = new QgsLineStringV2();
outerRing2->setPoints( QList<QgsPointV2>() << QgsPointV2( 10, 10 ) << QgsPointV2( 10, 20 ) << QgsPointV2( 20, 20 ) << QgsPointV2( 20, 10 ) << QgsPointV2( 10, 10 ) );
QgsPolygonV2* polygon2 = new QgsPolygonV2();
polygon2->setExteriorRing( outerRing2 );

QgsLineStringV2* innerRing2 = new QgsLineStringV2();
innerRing2->setPoints( QList<QgsPointV2>() << QgsPointV2( 14, 14 ) << QgsPointV2( 14, 16 ) << QgsPointV2( 16, 16 ) << QgsPointV2( 16, 14 ) << QgsPointV2( 14, 14 ) );
polygon2->setInteriorRings( QList<QgsCurveV2*>() << innerRing2 );

QgsMultiPolygonV2 mpg;
mpg.addGeometry( polygon1 );
mpg.addGeometry( polygon2 );

QList<QgsLineStringV2*> linestrings = QgsGeometryUtils::extractLineStrings( &mpg );
QCOMPARE( linestrings.count(), 3 );
qDeleteAll( linestrings );
}

void TestQgsGeometryUtils::testLeftOfLine_data()
{
QTest::addColumn<double>( "x" );

2 comments on commit 9fd6b24

@nyalldawson

This comment has been minimized.

Copy link
Collaborator

@nyalldawson nyalldawson replied Jan 27, 2016

Is QgsGeometryUtils the correct place for this? Or should it be in QgsInternalGeometryEngine and exposed via QgsGeometry?

@wonder-sk

This comment has been minimized.

Copy link
Member Author

@wonder-sk wonder-sk replied Jan 28, 2016

I do not really have a preference where should it go - in theory QgsGeometryUtils and QgsInternalGeometryEngine could be just one class - with assorted geometry functionality.

I would prefer not to expose it via QgsGeometry - that interface is already way too long - but I do not have a strong opinion.

Please sign in to comment.
You can’t perform that action at this time.