Skip to content

Commit

Permalink
Mesh editing: Select mesh element by polygon (#44739)
Browse files Browse the repository at this point in the history
[feature] [mesh] Select mesh elements by polygon

Default behavior: all touched (partially included element) will be selected (green rubber band) (default)
Alt Modifier: only totally included elements will be selected (blue rubber band) (alt + drag)
  • Loading branch information
vcloarec committed Aug 18, 2021
1 parent ad8991f commit 781f484
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 34 deletions.
1 change: 1 addition & 0 deletions images/images.qrc
Expand Up @@ -923,6 +923,7 @@
<file>themes/default/mIconFolderHomeParams.svg</file>
<file>themes/default/mActionMeasureBearing.svg</file>
<file>themes/default/mActionMeshDigitizing.svg</file>
<file>themes/default/mActionMeshSelectPolygon.svg</file>
<file>themes/default/mActionNewMeshLayer.svg</file>
<file>themes/default/mIconGeometryCollectionLayer.svg</file>
<file>themes/default/mIconGps.svg</file>
Expand Down
1 change: 1 addition & 0 deletions images/themes/default/mActionMeshSelectPolygon.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
89 changes: 62 additions & 27 deletions src/app/mesh/qgsmaptooleditmeshframe.cpp
Expand Up @@ -92,6 +92,8 @@ QgsMapToolEditMeshFrame::QgsMapToolEditMeshFrame( QgsMapCanvas *canvas )
{
mActionDigitizing = new QAction( QgsApplication::getThemePixmap( QStringLiteral( "/mActionMeshDigitizing.svg" ) ), tr( "Digitize mesh elements" ) );
mActionDigitizing->setCheckable( true );
mActionSelectByPolygon = new QAction( QgsApplication::getThemePixmap( QStringLiteral( "/mActionMeshSelectPolygon.svg" ) ), tr( "Select mesh element by polygon" ) );
mActionSelectByPolygon->setCheckable( true );

mActionRemoveVerticesFillingHole = new QAction( this );
mActionDelaunayTriangulation = new QAction( tr( "Delaunay triangulation with selected vertices" ), this );
Expand All @@ -111,6 +113,14 @@ QgsMapToolEditMeshFrame::QgsMapToolEditMeshFrame( QgsMapCanvas *canvas )
activateWithState( Digitizing );
} );

connect( mActionSelectByPolygon, &QAction::toggled, this, [this]( bool checked )
{
if ( checked )
activateWithState( SelectingByPolygon );
else
mSelectionBand->reset( QgsWkbTypes::PolygonGeometry );
} );

connect( mActionDelaunayTriangulation, &QAction::triggered, this, [this]
{
if ( mCurrentEditor && mSelectedVertices.count() > 3 )
Expand Down Expand Up @@ -152,6 +162,12 @@ void QgsMapToolEditMeshFrame::activateWithState( State state )
mCurrentState = state;
}

void QgsMapToolEditMeshFrame::backToDigitizing()
{
activateWithState( Digitizing );
mActionDigitizing->setChecked( true );
}

QgsMapToolEditMeshFrame::~QgsMapToolEditMeshFrame()
{
deleteZvalueWidget();
Expand All @@ -160,13 +176,15 @@ QgsMapToolEditMeshFrame::~QgsMapToolEditMeshFrame()
QList<QAction *> QgsMapToolEditMeshFrame::actions() const
{
return QList<QAction *>()
<< mActionDigitizing;
<< mActionDigitizing
<< mActionSelectByPolygon;
}

QList<QAction *> QgsMapToolEditMeshFrame::mapToolActions()
{
return QList<QAction *>()
<< mActionDigitizing;
<< mActionDigitizing
<< mActionSelectByPolygon;
}

void QgsMapToolEditMeshFrame::initialize()
Expand Down Expand Up @@ -215,12 +233,8 @@ void QgsMapToolEditMeshFrame::initialize()

if ( !mSelectionBand )
mSelectionBand = new QgsRubberBand( mCanvas, QgsWkbTypes::PolygonGeometry );
mSelectionBandPartiallyFillColor = QColor( 0, 215, 120, 63 );
mSelectionBandPartiallyStrokeColor = QColor( 0, 204, 102, 100 );
mSelectionBandTotalFillColor = QColor( 0, 120, 215, 63 );
mSelectionBandTotalStrokeColor = QColor( 0, 102, 204, 100 );
mSelectionBand->setFillColor( mSelectionBandTotalFillColor );
mSelectionBand->setStrokeColor( mSelectionBandTotalStrokeColor );
mSelectionBand->setFillColor( QColor( 254, 178, 76, 63 ) );
mSelectionBand->setStrokeColor( QColor( 254, 58, 29, 100 ) );
mSelectionBand->setZValue( 10 );

if ( !mSelectedFacesRubberband )
Expand Down Expand Up @@ -407,6 +421,7 @@ bool QgsMapToolEditMeshFrame::populateContextMenuWithEvent( QMenu *menu, QgsMapM
case AddingNewFace:
case Selecting:
case MovingVertex:
case SelectingByPolygon:
return false;
}

Expand All @@ -422,6 +437,7 @@ QgsMapTool::Flags QgsMapToolEditMeshFrame::flags() const
case AddingNewFace:
case Selecting:
case MovingVertex:
case SelectingByPolygon:
return QgsMapTool::Flags();
}

Expand All @@ -442,7 +458,8 @@ void QgsMapToolEditMeshFrame::cadCanvasPressEvent( QgsMapMouseEvent *e )
if ( e->button() == Qt::LeftButton )
{
mStartSelectionPos = e->pos();
mSelectionBand->reset( QgsWkbTypes::PolygonGeometry );
if ( mCurrentState != SelectingByPolygon )
mSelectionBand->reset( QgsWkbTypes::PolygonGeometry );
switch ( mCurrentState )
{
case Digitizing:
Expand Down Expand Up @@ -476,11 +493,11 @@ void QgsMapToolEditMeshFrame::cadCanvasPressEvent( QgsMapMouseEvent *e )
mStartMovingPoint = mapVertexXY( mCurrentVertexIndex );
mCanMovingStart = true;
}
mPreviousState = mCurrentState;
break;
case AddingNewFace:
case Selecting:
case MovingVertex:
case SelectingByPolygon:
break;
}
}
Expand All @@ -499,7 +516,8 @@ void QgsMapToolEditMeshFrame::cadCanvasMoveEvent( QgsMapMouseEvent *e )

if ( mLeftButtonPressed &&
mCurrentState != MovingVertex &&
mCurrentState != AddingNewFace )
mCurrentState != AddingNewFace &&
mCurrentState != SelectingByPolygon )
{
if ( mCanMovingStart )
{
Expand All @@ -526,18 +544,6 @@ void QgsMapToolEditMeshFrame::cadCanvasMoveEvent( QgsMapMouseEvent *e )
case Selecting:
{
const QRect &rect = QRect( e->pos(), mStartSelectionPos );
mSelectPartiallyContainedFace = e->pos().x() < mStartSelectionPos.x();
if ( mSelectPartiallyContainedFace )
{
mSelectionBand->setFillColor( mSelectionBandPartiallyFillColor );
mSelectionBand->setColor( mSelectionBandPartiallyStrokeColor );
}
else
{
mSelectionBand->setFillColor( mSelectionBandTotalFillColor );
mSelectionBand->setColor( mSelectionBandTotalStrokeColor );
}

mSelectionBand->setToCanvasRectangle( rect );
}
break;
Expand Down Expand Up @@ -616,6 +622,9 @@ void QgsMapToolEditMeshFrame::cadCanvasMoveEvent( QgsMapMouseEvent *e )
}
}
break;
case SelectingByPolygon:
mSelectionBand->movePoint( mapPoint );
break;
}

QgsMapToolAdvancedDigitizing::cadCanvasMoveEvent( e );
Expand Down Expand Up @@ -729,10 +738,10 @@ void QgsMapToolEditMeshFrame::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
break;
case Selecting:
{
mCurrentState = mPreviousState;
QgsGeometry selectionGeom = mSelectionBand->asGeometry();
selectInGeometry( selectionGeom, e->modifiers() );
mSelectionBand->reset( QgsWkbTypes::PolygonGeometry );
mCurrentState = Digitizing;
}
break;
case MovingVertex:
Expand All @@ -757,6 +766,19 @@ void QgsMapToolEditMeshFrame::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
mMovingVerticesRubberband->reset();
mCurrentState = Digitizing;
break;
case SelectingByPolygon:
if ( e->button() == Qt::LeftButton )
{
mSelectionBand->movePoint( mapPoint );
mSelectionBand->addPoint( mapPoint );
}
else if ( e->button() == Qt::RightButton )
{
QgsGeometry selectionGeom = mSelectionBand->asGeometry();
selectInGeometry( selectionGeom, e->modifiers() );
mSelectionBand->reset( QgsWkbTypes::PolygonGeometry );
}
break;
}
mDoubleClicks = false;

Expand Down Expand Up @@ -878,8 +900,6 @@ bool QgsMapToolEditMeshFrame::testBorderMovingFace( const QgsMeshFace &borderMov
return true;
}



void QgsMapToolEditMeshFrame::keyPressEvent( QKeyEvent *e )
{
bool consumned = false;
Expand Down Expand Up @@ -932,6 +952,20 @@ void QgsMapToolEditMeshFrame::keyPressEvent( QKeyEvent *e )
}
}
break;
case SelectingByPolygon:
if ( e->key() == Qt::Key_Escape )
{
mSelectionBand->reset( QgsWkbTypes::PolygonGeometry );
backToDigitizing();
consumned = true;
}

if ( e->key() == Qt::Key_Backspace )
{
mSelectionBand->removePoint( -2, true );
consumned = true;
}
break;
case Selecting:
case MovingVertex:
break;
Expand All @@ -956,6 +990,7 @@ void QgsMapToolEditMeshFrame::keyReleaseEvent( QKeyEvent *e )
case Digitizing:
break;
case AddingNewFace:
case SelectingByPolygon:
if ( e->key() == Qt::Key_Backspace )
consumned = true; //to avoid removing the value of the ZvalueWidget
break;
Expand Down Expand Up @@ -1270,7 +1305,7 @@ void QgsMapToolEditMeshFrame::selectInGeometry( const QgsGeometry &geometry, Qt:
for ( const int faceIndex : nativeFaceIndexes )
{
const QgsMeshFace &face = nativeFace( faceIndex );
if ( mSelectPartiallyContainedFace )
if ( !( modifiers & Qt::AltModifier ) )
{
std::unique_ptr<QgsPolygon> faceGeom( new QgsPolygon( new QgsLineString( nativeFaceGeometry( faceIndex ) ) ) );
if ( engine->intersects( faceGeom.get() ) )
Expand Down
7 changes: 4 additions & 3 deletions src/app/mesh/qgsmaptooleditmeshframe.h
Expand Up @@ -102,14 +102,16 @@ class APP_EXPORT QgsMapToolEditMeshFrame : public QgsMapToolAdvancedDigitizing
Digitizing, //!< Digitizing action can be start (add/remove vertices, selection, add/remove faces, move vertices)
AddingNewFace, //!< Adding a face has been start and the user have to choose or digitize vertices
Selecting, //!< Selection is in process
MovingVertex //!< Moving vertex or vertices is processing
MovingVertex, //!< Moving vertex or vertices is processing
SelectingByPolygon, //!< Selection elements by polygon is in progress
};

typedef QPair<int, int> Edge; //first face index, second the vertex index corresponding to the end extremity (ccw)

// methods
void initialize();
void activateWithState( State state );
void backToDigitizing();
const QgsMeshVertex mapVertex( int index ) const;
const QgsPointXY mapVertexXY( int index ) const;
const QgsMeshFace nativeFace( int index ) const;
Expand Down Expand Up @@ -166,7 +168,6 @@ class APP_EXPORT QgsMapToolEditMeshFrame : public QgsMapToolAdvancedDigitizing

bool mIsInitialized = false;
State mCurrentState = Digitizing;
State mPreviousState = Digitizing; //used to store a state and restore it after a particular action as selecting
bool mLeftButtonPressed = false;
bool mKeepSelectionOnEdit = false;

Expand Down Expand Up @@ -216,7 +217,6 @@ class APP_EXPORT QgsMapToolEditMeshFrame : public QgsMapToolAdvancedDigitizing
QColor mSelectionBandTotalStrokeColor = QColor( 0, 102, 204, 100 );
QgsRubberBand *mSelectedFacesRubberband = nullptr; //own by map canvas
QMap< int, QgsVertexMarker * > mSelectedVerticesMarker;
bool mSelectPartiallyContainedFace = false;

//! members for moving vertices
QgsPointXY mStartMovingPoint;
Expand Down Expand Up @@ -246,6 +246,7 @@ class APP_EXPORT QgsMapToolEditMeshFrame : public QgsMapToolAdvancedDigitizing
QAction *mActionFacesRefinement = nullptr;

QAction *mActionDigitizing = nullptr;
QAction *mActionSelectByPolygon = nullptr;

friend class TestQgsMapToolEditMesh;
};
Expand Down
42 changes: 38 additions & 4 deletions tests/src/app/testqgsmaptooleditmesh.cpp
Expand Up @@ -191,15 +191,15 @@ void TestQgsMapToolEditMesh::editMesh()
QCOMPARE( meshLayerQuadFlower->datasetValue( QgsMeshDatasetIndex( 0, 0 ), QgsPointXY( 2500, 3250 ) ).x(), 1500 );

//Selection
// from left to right
// completely included
tool.mouseMove( 1200, 3600 );
tool.mousePress( 1200, 3600, Qt::LeftButton );
tool.mouseMove( 2700, 2250 );
tool.mouseRelease( 2700, 2250, Qt::LeftButton );
tool.mouseRelease( 2700, 2250, Qt::LeftButton, Qt::AltModifier );
QCOMPARE( editMeshMapTool->mSelectedVertices.count(), 5 );
QCOMPARE( editMeshMapTool->mSelectedFaces.count(), 1 );

// from left to right
// touched
tool.mouseMove( 2700, 2250 );
tool.mousePress( 2700, 2250, Qt::LeftButton );
tool.mouseMove( 1200, 3600 );
Expand Down Expand Up @@ -280,9 +280,43 @@ void TestQgsMapToolEditMesh::editMesh()
tool.mouseClick( 1500, 3324, Qt::LeftButton );
centroid = meshLayerQuadFlower->snapOnElement( QgsMesh::Face, QgsPointXY( 1100, 3050 ), 10 );
QVERIFY( centroid.compare( QgsPointXY( 1500, 3100 ), 1e-2 ) );
}

tool.keyClick( Qt::Key_Escape );

QCOMPARE( editMeshMapTool->mSelectedVertices.count(), 0 );
QCOMPARE( editMeshMapTool->mSelectedFaces.count(), 0 );

// Selection by polygon
editMeshMapTool->mActionSelectByPolygon->trigger();

// touched
tool.mouseClick( 3500, 3250, Qt::LeftButton );
tool.mouseClick( 2750, 3250, Qt::LeftButton );
tool.mouseClick( 1750, 2500, Qt::LeftButton );
tool.mouseClick( 2500, 2000, Qt::LeftButton );
tool.mouseClick( 3000, 2000, Qt::LeftButton );
tool.mouseClick( 3000, 2000, Qt::RightButton );

QCOMPARE( editMeshMapTool->mSelectedVertices.count(), 5 );
QCOMPARE( editMeshMapTool->mSelectedFaces.count(), 3 );

// completely included
tool.mouseClick( 2750, 3250, Qt::LeftButton );
tool.mouseClick( 3500, 3250, Qt::LeftButton );
tool.mouseClick( 3000, 2000, Qt::LeftButton );
tool.mouseClick( 2500, 2000, Qt::LeftButton );
tool.mouseClick( 1750, 2500, Qt::LeftButton );
tool.mouseClick( 1750, 2500, Qt::RightButton, Qt::AltModifier );

QCOMPARE( editMeshMapTool->mSelectedVertices.count(), 1 );
QCOMPARE( editMeshMapTool->mSelectedFaces.count(), 0 );

tool.keyClick( Qt::Key_Escape );
tool.keyClick( Qt::Key_Escape );

QCOMPARE( editMeshMapTool->mSelectedVertices.count(), 0 );
QCOMPARE( editMeshMapTool->mSelectedFaces.count(), 0 );
}

QGSTEST_MAIN( TestQgsMapToolEditMesh )
#include "testqgsmaptooleditmesh.moc"

0 comments on commit 781f484

Please sign in to comment.