Skip to content

Commit

Permalink
Gracefully handle topology errors when tracing (fixes #14447)
Browse files Browse the repository at this point in the history
(cherry picked from commit 11e7140)
  • Loading branch information
wonder-sk committed Apr 29, 2016
1 parent 8244947 commit 80102b1
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 9 deletions.
5 changes: 5 additions & 0 deletions python/core/qgstracer.sip
Expand Up @@ -49,6 +49,11 @@ class QgsTracer : QObject
//! Whether the internal data structures have been initialized
bool isInitialized() const;

//! Whether there was an error during graph creation due to noding exception,
//! indicating some input data topology problems
//! @note added in QGIS 2.14.2
bool hasTopologyProblem() const;

//! Possible errors that may happen when calling findShortestPath()
enum PathError
{
Expand Down
36 changes: 27 additions & 9 deletions src/core/qgstracer.cpp
Expand Up @@ -17,6 +17,7 @@

#include "qgsgeometry.h"
#include "qgsgeometryutils.h"
#include "qgsgeos.h"
#include "qgslogger.h"
#include "qgsvectorlayer.h"

Expand Down Expand Up @@ -439,6 +440,7 @@ QgsTracer::QgsTracer()
: mGraph( 0 )
, mReprojectionEnabled( false )
, mMaxFeatureCount( 0 )
, mHasTopologyProblem( false )
{
}

Expand All @@ -448,6 +450,8 @@ bool QgsTracer::initGraph()
if ( mGraph )
return true; // already initialized

mHasTopologyProblem = false;

QgsFeature f;
QgsMultiPolyline mpl;

Expand Down Expand Up @@ -499,23 +503,37 @@ bool QgsTracer::initGraph()

t2.start();

int timeNodingCall = 0;

#if 0
// without noding - if data are known to be noded beforehand
int timeNodingCall = 0;
#else
QgsGeometry* allGeom = QgsGeometry::fromMultiPolyline( mpl );

t2a.start();
GEOSGeometry* allNoded = GEOSNode_r( QgsGeometry::getGEOSHandler(), allGeom->asGeos() );
int timeNodingCall = t2a.elapsed();
try
{
t2a.start();
// GEOSNode_r may throw an exception
GEOSGeometry* allNoded = GEOSNode_r( QgsGeometry::getGEOSHandler(), allGeom->asGeos() );
timeNodingCall = t2a.elapsed();

QgsGeometry* noded = new QgsGeometry;
noded->fromGeos( allNoded );
delete allGeom;

QgsGeometry* noded = new QgsGeometry;
noded->fromGeos( allNoded );
delete allGeom;
mpl = noded->asMultiPolyline();

mpl = noded->asMultiPolyline();
delete noded;
}
catch ( GEOSException &e )
{
// no big deal... we will just not have nicely noded linework, potentially
// missing some intersections

delete noded;
mHasTopologyProblem = true;

QgsDebugMsg( "Tracer Noding Exception: " + e.what() );
}
#endif

int timeNoding = t2.elapsed();
Expand Down
8 changes: 8 additions & 0 deletions src/core/qgstracer.h
Expand Up @@ -76,6 +76,11 @@ class CORE_EXPORT QgsTracer : public QObject
//! Whether the internal data structures have been initialized
bool isInitialized() const { return mGraph != nullptr; }

//! Whether there was an error during graph creation due to noding exception,
//! indicating some input data topology problems
//! @note added in QGIS 2.14.2
bool hasTopologyProblem() const { return mHasTopologyProblem; }

//! Possible errors that may happen when calling findShortestPath()
enum PathError
{
Expand Down Expand Up @@ -127,6 +132,9 @@ class CORE_EXPORT QgsTracer : public QObject
//! Limit of how many features can be in the graph (0 means no limit).
//! This is to avoid possibly long graph preparation for complicated layers
int mMaxFeatureCount;
//! A flag indicating that there was an error during graph creation
//! due to noding exception, indicating some input data topology problems
bool mHasTopologyProblem;
};


Expand Down
5 changes: 5 additions & 0 deletions src/gui/qgsmapcanvastracer.cpp
Expand Up @@ -65,6 +65,11 @@ void QgsMapCanvasTracer::reportError( QgsTracer::PathError err, bool addingVerte
break;
}

if ( message.isEmpty() && hasTopologyProblem() )
{
message = tr( "Tracing may not work correctly. Please check topology of the input layers." );
}

if ( message.isEmpty() )
return;

Expand Down

0 comments on commit 80102b1

Please sign in to comment.