Skip to content

Commit

Permalink
Node tool: give priority to the current layer when selecting vertex
Browse files Browse the repository at this point in the history
  • Loading branch information
wonder-sk committed Sep 8, 2017
1 parent 7a62746 commit 31b6b58
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 10 deletions.
47 changes: 37 additions & 10 deletions src/app/nodetool/qgsnodetool.cpp
Expand Up @@ -596,6 +596,10 @@ void QgsNodeTool::removeTemporaryRubberBands()

QgsPointLocator::Match QgsNodeTool::snapToEditableLayer( QgsMapMouseEvent *e )
{
QgsSnappingUtils *snapUtils = canvas()->snappingUtils();
QgsSnappingConfig oldConfig = snapUtils->config();
QgsPointLocator::Match m;

QgsPointXY mapPoint = toMapCoordinates( e->pos() );
double tol = QgsTolerance::vertexSearchRadius( canvas()->mapSettings() );

Expand All @@ -604,21 +608,44 @@ QgsPointLocator::Match QgsNodeTool::snapToEditableLayer( QgsMapMouseEvent *e )
config.setMode( QgsSnappingConfig::AdvancedConfiguration );
config.setIntersectionSnapping( false ); // only snap to layers

Q_FOREACH ( QgsMapLayer *layer, canvas()->layers() )
// if there is a current layer, it should have priority over other layers
// because sometimes there may be match from multiple layers at one location
// and selecting current layer is an easy way for the user to prioritize a layer
if ( QgsVectorLayer *currentVlayer = currentVectorLayer() )
{
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
if ( !vlayer )
continue;
if ( currentVlayer->isEditable() )
{
Q_FOREACH ( QgsMapLayer *layer, canvas()->layers() )
{
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
if ( !vlayer )
continue;

config.setIndividualLayerSettings( vlayer, QgsSnappingConfig::IndividualLayerSettings(
vlayer == currentVlayer, QgsSnappingConfig::VertexAndSegment, tol, QgsTolerance::ProjectUnits ) );
}

config.setIndividualLayerSettings( vlayer, QgsSnappingConfig::IndividualLayerSettings(
vlayer->isEditable(), QgsSnappingConfig::VertexAndSegment, tol, QgsTolerance::ProjectUnits ) );
snapUtils->setConfig( config );
m = snapUtils->snapToMap( mapPoint );
}
}

QgsSnappingUtils *snapUtils = canvas()->snappingUtils();
QgsSnappingConfig oldConfig = snapUtils->config();
snapUtils->setConfig( config );
// if there is no match from the current layer, try to use any editable vector layer
if ( !m.isValid() )
{
Q_FOREACH ( QgsMapLayer *layer, canvas()->layers() )
{
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
if ( !vlayer )
continue;

QgsPointLocator::Match m = snapUtils->snapToMap( mapPoint );
config.setIndividualLayerSettings( vlayer, QgsSnappingConfig::IndividualLayerSettings(
vlayer->isEditable(), QgsSnappingConfig::VertexAndSegment, tol, QgsTolerance::ProjectUnits ) );
}

snapUtils->setConfig( config );
m = snapUtils->snapToMap( mapPoint );
}

// try to stay snapped to previously used feature
// so the highlight does not jump around at nodes where features are joined
Expand Down
46 changes: 46 additions & 0 deletions tests/src/app/testqgsnodetool.cpp
Expand Up @@ -63,6 +63,7 @@ class TestQgsNodeTool : public QObject
void testMoveMultipleVertices();
void testMoveVertexTopo();
void testDeleteVertexTopo();
void testActiveLayerPriority();

private:
QPoint mapToScreen( double mapX, double mapY )
Expand Down Expand Up @@ -532,5 +533,50 @@ void TestQgsNodeTool::testDeleteVertexTopo()
QgsProject::instance()->setTopologicalEditing( false );
}

void TestQgsNodeTool::testActiveLayerPriority()
{
// check that features from current layer get priority when picking points

// create a temporary line layer that has a common vertex with existing line layer at (1, 1)
QgsVectorLayer *layerLine2 = new QgsVectorLayer( "LineString?crs=EPSG:27700", "layer line 2", "memory" );
QVERIFY( layerLine2->isValid() );
QgsPolyline line1;
line1 << QgsPointXY( 0, 1 ) << QgsPointXY( 1, 1 ) << QgsPointXY( 1, 0 );
QgsFeature lineF1;
lineF1.setGeometry( QgsGeometry::fromPolyline( line1 ) );
layerLine2->startEditing();
layerLine2->addFeature( lineF1 );
QgsFeatureId fidLineF1 = lineF1.id();
QCOMPARE( layerLine2->featureCount(), ( long )1 );
QgsProject::instance()->addMapLayer( layerLine2 );
mCanvas->setLayers( QList<QgsMapLayer *>() << mLayerLine << mLayerPolygon << mLayerPoint << layerLine2 );

// make one layer active and check its vertex is used

mCanvas->setCurrentLayer( mLayerLine );

mouseClick( 1, 1, Qt::LeftButton );
mouseClick( 0, 0, Qt::LeftButton );

QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 0 0, 1 3)" ) );
QCOMPARE( layerLine2->getFeature( fidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(0 1, 1 1, 1 0)" ) );
mLayerLine->undoStack()->undo();

// make the other layer active and check its vertex is used

mCanvas->setCurrentLayer( layerLine2 );

mouseClick( 1, 1, Qt::LeftButton );
mouseClick( 0, 0, Qt::LeftButton );

QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) );
QCOMPARE( layerLine2->getFeature( fidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(0 1, 0 0, 1 0)" ) );
layerLine2->undoStack()->undo();

// get rid of the temporary layer
mCanvas->setLayers( QList<QgsMapLayer *>() << mLayerLine << mLayerPolygon << mLayerPoint );
QgsProject::instance()->removeMapLayer( layerLine2 );
}

QGSTEST_MAIN( TestQgsNodeTool )
#include "testqgsnodetool.moc"

0 comments on commit 31b6b58

Please sign in to comment.