Skip to content
Permalink
Browse files

[tracer] Fix reprojection, limit tracing graph to visible extent

  • Loading branch information
wonder-sk committed Jan 11, 2016
1 parent bf8571d commit 33ea60d7417394602f426e21921279c28dfc3b8f
@@ -250,14 +250,14 @@ QVector<QgsPoint> shortest_path( const QgsTracerGraph& g, int v1, int v2 )
}


int point2vertex( const QgsTracerGraph& g, const QgsPoint& pt )
int point2vertex( const QgsTracerGraph& g, const QgsPoint& pt, double epsilon = 1e-6 )
{
// TODO: use spatial index

for ( int i = 0; i < g.v.count(); ++i )
{
const QgsTracerGraph::V& v = g.v.at( i );
if ( v.pt == pt )
if ( v.pt == pt || ( fabs( v.pt.x() - pt.x() ) < epsilon && fabs( v.pt.y() - pt.y() ) < epsilon ) )
return i;
}

@@ -472,7 +472,12 @@ void QgsTracer::initGraph()
{
QgsCoordinateTransform ct( vl->crs(), mCRS );

QgsFeatureIterator fi = vl->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) );
QgsFeatureRequest request;
request.setSubsetOfAttributes( QgsAttributeList() );
if ( !mExtent.isEmpty() )
request.setFilterRect( ct.transformBoundingBox( mExtent, QgsCoordinateTransform::ReverseTransform ) );

QgsFeatureIterator fi = vl->getFeatures( request );
while ( fi.nextFeature( f ) )
{
if ( !f.geometry() )
@@ -567,6 +572,15 @@ void QgsTracer::setDestinationCrs( const QgsCoordinateReferenceSystem& crs )
invalidateGraph();
}

void QgsTracer::setExtent( const QgsRectangle& extent )
{
if ( mExtent == extent )
return;

mExtent = extent;
invalidateGraph();
}

void QgsTracer::init()
{
if ( mGraph )
@@ -24,6 +24,7 @@ class QgsVectorLayer;
#include "qgscoordinatereferencesystem.h"
#include "qgsfeature.h"
#include "qgspoint.h"
#include "qgsrectangle.h"

struct QgsTracerGraph;

@@ -51,6 +52,11 @@ class CORE_EXPORT QgsTracer : public QObject
//! Set CRS used for tracing
void setDestinationCrs( const QgsCoordinateReferenceSystem& crs );

//! Get extent to which graph's features will be limited (empty extent means no limit)
QgsRectangle extent() const { return mExtent; }
//! Set extent to which graph's features will be limited (empty extent means no limit)
void setExtent( const QgsRectangle& extent );

//! Build the internal data structures. This may take some time
//! depending on how big the input layers are. It is not necessary
//! to call this method explicitly - it will be called by findShortestPath()
@@ -82,6 +88,8 @@ class CORE_EXPORT QgsTracer : public QObject
QList<QgsVectorLayer*> mLayers;
//! Destination CRS in which graph is built and tracing done
QgsCoordinateReferenceSystem mCRS;
//! Extent for graph building (empty extent means no limit)
QgsRectangle mExtent;
};


@@ -17,6 +17,7 @@ QgsMapCanvasTracer::QgsMapCanvasTracer( QgsMapCanvas* canvas )

connect( canvas, SIGNAL( destinationCrsChanged() ), this, SLOT( updateSettings() ) );
connect( canvas, SIGNAL( layersChanged() ), this, SLOT( updateSettings() ) );
connect( canvas, SIGNAL( extentsChanged() ), this, SLOT( updateSettings() ) );
// TODO: watch for snapping changes

mActionEnableTracing = new QAction( QIcon( QgsApplication::getThemeIcon( "/mActionTracing.png" ) ), tr( "Enable Tracing" ), this );
@@ -48,4 +49,5 @@ void QgsMapCanvasTracer::updateSettings()
setLayers( layers );

setDestinationCrs( mCanvas->mapSettings().destinationCrs() );
setExtent( mCanvas->extent() );
}
@@ -143,20 +143,40 @@ bool QgsMapToolCapture::tracingEnabled()
}


QgsPoint QgsMapToolCapture::tracingStartPoint()
{
try
{
QgsMapLayer* layer = mCanvas->currentLayer();
if ( !layer )
return QgsPoint();
QgsPointV2 v = mCaptureCurve.endPoint();
return toMapCoordinates( layer, QgsPoint( v.x(), v.y() ) );
}
catch ( QgsCsException & )
{
QgsDebugMsg( "transformation to layer coordinate failed" );
return QgsPoint();
}
}


void QgsMapToolCapture::tracingMouseMove( QgsMapMouseEvent* e )
{
if ( !e->isSnapped() )
return;

QgsPointV2 v = mCaptureCurve.endPoint();
QgsPoint pt0 = tracingStartPoint();
if ( pt0 == QgsPoint() )
return;

QgsMapCanvasTracer* tracer = QgsMapCanvasTracer::tracerForCanvas( mCanvas );
if ( !tracer )
return; // this should not happen!

mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QGis::Polygon : QGis::Line );

QVector<QgsPoint> points = tracer->findShortestPath( QgsPoint( v.x(), v.y() ), e->mapPoint() );
QVector<QgsPoint> points = tracer->findShortestPath( pt0, e->mapPoint() );
if ( points.isEmpty() )
return;

@@ -190,9 +210,11 @@ bool QgsMapToolCapture::tracingAddVertex( const QgsPoint& point )
return res;
}

QgsPointV2 v = mCaptureCurve.endPoint();
QgsPoint pt0 = tracingStartPoint();
if ( pt0 == QgsPoint() )
return false;

QVector<QgsPoint> points = tracer->findShortestPath( QgsPoint( v.x(), v.y() ), point );
QVector<QgsPoint> points = tracer->findShortestPath( pt0, point );
if ( points.isEmpty() )
return false; // ignore the vertex - can't find path to the end point!

@@ -143,6 +143,8 @@ class GUI_EXPORT QgsMapToolCapture : public QgsMapToolAdvancedDigitizing
private:
//! whether tracing has been requested by the user
bool tracingEnabled();
//! first point that will be used as a start of the trace
QgsPoint tracingStartPoint();
//! handle of mouse movement when tracing enabled and capturing has started
void tracingMouseMove( QgsMapMouseEvent* e );
//! handle of addition of clicked point (with the rest of the trace) when tracing enabled
@@ -32,6 +32,8 @@ class TestQgsTracer : public QObject
void testPolygon();
void testButterfly();
void testLayerUpdates();
void testExtent();
void testReprojection();

private:

@@ -268,6 +270,54 @@ void TestQgsTracer::testLayerUpdates()
delete vl;
}

void TestQgsTracer::testExtent()
{
// check whether the tracer correctly handles the extent limitation

// same shape as in testSimple()
QStringList wkts;
wkts << "LINESTRING(0 0, 0 10)"
<< "LINESTRING(0 0, 10 0)"
<< "LINESTRING(0 10, 20 10)"
<< "LINESTRING(10 0, 20 10)";

QgsVectorLayer* vl = make_layer( wkts );

QgsTracer tracer;
tracer.setLayers( QList<QgsVectorLayer*>() << vl );
tracer.setExtent( QgsRectangle( 0, 0, 5, 5 ) );
tracer.init();

QgsPolyline points1 = tracer.findShortestPath( QgsPoint( 0, 0 ), QgsPoint( 10, 0 ) );
QCOMPARE( points1.count(), 2 );
QCOMPARE( points1[0], QgsPoint( 0, 0 ) );
QCOMPARE( points1[1], QgsPoint( 10, 0 ) );

QgsPolyline points2 = tracer.findShortestPath( QgsPoint( 0, 0 ), QgsPoint( 20, 10 ) );
QCOMPARE( points2.count(), 0 );
}

void TestQgsTracer::testReprojection()
{
QStringList wkts;
wkts << "LINESTRING(1 0, 2 0)";

QgsVectorLayer* vl = make_layer( wkts );

QgsCoordinateReferenceSystem dstCrs( "EPSG:3857" );
QgsCoordinateTransform ct( QgsCoordinateReferenceSystem( "EPSG:4326" ), dstCrs );
QgsPoint p1 = ct.transform( QgsPoint( 1, 0 ) );
QgsPoint p2 = ct.transform( QgsPoint( 2, 0 ) );

QgsTracer tracer;
tracer.setLayers( QList<QgsVectorLayer*>() << vl );
tracer.setDestinationCrs( dstCrs );
tracer.init();

QgsPolyline points1 = tracer.findShortestPath( p1, p2 );
QCOMPARE( points1.count(), 2 );
}


QTEST_MAIN( TestQgsTracer )
#include "testqgstracer.moc"

0 comments on commit 33ea60d

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