Select by existing geometries (#45006)

[mesh] [feature] mesh select  element by existing selected polygon
This commit is contained in:
Vincent Cloarec 2021-09-10 02:00:55 -04:00 committed by GitHub
parent 87d42afb31
commit 4e0d0f6692
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 162 additions and 63 deletions

View File

@ -927,6 +927,8 @@
<file>themes/default/mActionMeshSelectExpression.svg</file>
<file>themes/default/mActionNewMeshLayer.svg</file>
<file>themes/default/mActionMeshTransformByExpression.svg</file>
<file>themes/default/mActionMeshSelectByTouchingGeometry.svg</file>
<file>themes/default/mActionMeshSelectByContainingGeometry.svg</file>
<file>themes/default/mIconVertexCoordinates.svg</file>
<file>themes/default/mActionMeshEditForceByVectorLines.svg</file>
<file>themes/default/mActionMeshReindex.svg</file>

View File

@ -0,0 +1 @@
<svg height="24" width="24" xmlns="http://www.w3.org/2000/svg"><g stroke-linecap="round"><path d="m11.985167 1.3595988-10.0115895 17.9748692m0 0h20.0231785m0 0-10.011589-17.9748692" fill="#fce94f" stroke="#5b6775" stroke-linejoin="bevel" stroke-width="1.002"/><g stroke="#c4a000" stroke-linejoin="round" stroke-width=".933968" transform="matrix(1.0707604 0 0 1.0706405 -48.994616 4.657768)"><path d="m50.730049 2.8451652-.18235 12.6360258h10.492628l3.839717-12.8620523z" fill="none"/><path d="m52.311948 2.8451652c0 2.1564332-3.162859 2.1564332-3.162859 0 0-2.15643314 3.162859-2.15643314 3.162859 0zm-.0048 12.6504958c0 2.156432-3.162859 2.156432-3.162859 0 0-2.156433 3.162859-2.156433 3.162859 0zm10.370845-.04968c0 2.156433-3.162857 2.156433-3.162857 0 0-2.156434 3.162857-2.156434 3.162857 0zm3.894613-12.4844338c0 2.1564332-3.162859 2.1564332-3.162859 0 0-2.15643304 3.162859-2.15643304 3.162859 0z" fill="#eeeeec" fill-rule="evenodd"/></g><path d="m16.990961 10.347034h-10.0115888l5.0057948 8.987432z" fill="#fce94f" stroke="#5b6775" stroke-linejoin="bevel" stroke-width="1.001575"/></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1 @@
<svg height="24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m1.9735772 19.334469h20.0231788l-10.011589-17.9748703z" fill="#fce94f"/><g stroke-linecap="round"><path d="m11.985167 1.3595988-10.0115895 17.9748692m0 0h20.0231785m0 0-10.011589-17.9748692" fill="#fce94f" stroke="#5b6775" stroke-linejoin="bevel" stroke-width="1.002"/><g stroke="#c4a000" stroke-linejoin="round" stroke-width=".933968" transform="matrix(1.0707604 0 0 1.0706405 -48.994616 4.657768)"><path d="m50.730049 2.8451652-.18235 12.6360258h10.492628l3.839717-12.8620523z" fill="none"/><path d="m52.311948 2.8451652c0 2.1564332-3.162859 2.1564332-3.162859 0 0-2.15643314 3.162859-2.15643314 3.162859 0zm-.0048 12.6504958c0 2.156432-3.162859 2.156432-3.162859 0 0-2.156433 3.162859-2.156433 3.162859 0zm10.370845-.04968c0 2.156433-3.162857 2.156433-3.162857 0 0-2.156434 3.162857-2.156434 3.162857 0zm3.894613-12.4844338c0 2.1564332-3.162859 2.1564332-3.162859 0 0-2.15643304 3.162859-2.15643304 3.162859 0z" fill="#eeeeec" fill-rule="evenodd"/></g><path d="m16.990961 10.347034h-10.0115888l5.0057948 8.987432z" fill="#fce94f" stroke="#5b6775" stroke-linejoin="bevel" stroke-width="1.001575"/></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -206,30 +206,41 @@ QgsMapToolEditMeshFrame::QgsMapToolEditMeshFrame( QgsMapCanvas *canvas )
: QgsMapToolAdvancedDigitizing( canvas, QgisApp::instance()->cadDockWidget() )
, mSnapIndicator( new QgsSnapIndicator( canvas ) )
{
mActionDigitizing = new QAction( QgsApplication::getThemePixmap( QStringLiteral( "/mActionMeshDigitizing.svg" ) ), tr( "Digitize mesh elements" ), this );
mActionDigitizing = new QAction( QgsApplication::getThemePixmap( QStringLiteral( "/mActionMeshDigitizing.svg" ) ), tr( "Digitize Mesh elements" ), this );
mActionDigitizing->setCheckable( true );
mActionSelectByPolygon = new QAction( QgsApplication::getThemePixmap( QStringLiteral( "/mActionMeshSelectPolygon.svg" ) ), tr( "Select mesh element by polygon" ), this );
mActionSelectByPolygon = new QAction( QgsApplication::getThemePixmap( QStringLiteral( "/mActionMeshSelectPolygon.svg" ) ), tr( "Select mesh elements by polygon" ), this );
mActionSelectByPolygon->setCheckable( true );
mActionSelectByExpression = new QAction( QgsApplication::getThemePixmap( QStringLiteral( "/mActionMeshSelectExpression.svg" ) ), tr( "Select mesh elements by expression" ), this );
mActionTransformCoordinates = new QAction( QgsApplication::getThemePixmap( QStringLiteral( "/mActionMeshTransformByExpression.svg" ) ), tr( "Transform vertices coordinates" ), this );
mActionSelectByPolygon = new QAction( QgsApplication::getThemePixmap( QStringLiteral( "/mActionMeshSelectPolygon.svg" ) ), tr( "Select Mesh Elements by Polygon" ), this );
mActionSelectByPolygon->setCheckable( true );
mActionSelectByPolygon->setObjectName( QStringLiteral( "ActionMeshSelectByPolygon" ) );
mActionSelectByExpression = new QAction( QgsApplication::getThemePixmap( QStringLiteral( "/mActionMeshSelectExpression.svg" ) ), tr( "Select Mesh Elements by Expression" ), this );
mActionSelectByExpression->setObjectName( QStringLiteral( "ActionMeshSelectByExpression" ) );
mActionSelectByContainingSelectedPolygon = new QAction( QgsApplication::getThemePixmap( QStringLiteral( "/mActionMeshSelectByContainingGeometry.svg" ) ), tr( "Select Contained Elements by Selected Polygons" ), this );
mActionSelectByTouchingSelectedPolygon = new QAction( QgsApplication::getThemePixmap( QStringLiteral( "/mActionMeshSelectByTouchingGeometry.svg" ) ), tr( "Select Touched Elements by Selected Polygons" ), this );
mActionSelectByContainingSelectedPolygon->setEnabled( false );
mActionSelectByTouchingSelectedPolygon->setEnabled( false );
mSelectActions << mActionSelectByPolygon
<< mActionSelectByExpression
<< mActionSelectByContainingSelectedPolygon
<< mActionSelectByTouchingSelectedPolygon;
mActionTransformCoordinates = new QAction( QgsApplication::getThemePixmap( QStringLiteral( "/mActionMeshTransformByExpression.svg" ) ), tr( "Transform Vertices Coordinates" ), this );
mActionTransformCoordinates->setCheckable( true );
mActionForceByVectorLayerGeometries = new QAction( QgsApplication::getThemePixmap( QStringLiteral( "/mActionMeshEditForceByVectorLines.svg" ) ), tr( "Force by selected geometries" ), this );
mActionForceByVectorLayerGeometries = new QAction( QgsApplication::getThemePixmap( QStringLiteral( "/mActionMeshEditForceByVectorLines.svg" ) ), tr( "Force by Selected Geometries" ), this );
mActionForceByVectorLayerGeometries->setEnabled( areGeometriesSelectedInVectorLayer() );
mWidgetActionForceByLine = new QgsMeshEditForceByLineAction( this );
mWidgetActionForceByLine->setMapCanvas( canvas );
mActionReindexMesh = new QAction( QgsApplication::getThemePixmap( QStringLiteral( "/mActionMeshReindex.svg" ) ), tr( "Reindex faces and vertices" ), this );
mActionReindexMesh = new QAction( QgsApplication::getThemePixmap( QStringLiteral( "/mActionMeshReindex.svg" ) ), tr( "Reindex Faces and Vertices" ), this );
mActionRemoveVerticesFillingHole = new QAction( this );
mActionDelaunayTriangulation = new QAction( tr( "Delaunay triangulation with selected vertices" ), this );
mActionFacesRefinement = new QAction( tr( "Refine current face" ), this );
mActionDelaunayTriangulation = new QAction( tr( "Delaunay Triangulation with Selected Vertices" ), this );
mActionFacesRefinement = new QAction( tr( "Refine Current Face" ), this );
mActionRemoveVerticesWithoutFillingHole = new QAction( this );
mActionRemoveFaces = new QAction( tr( "Remove current face" ), this );
mActionSplitFaces = new QAction( tr( "Split current face" ), this );
mActionRemoveFaces = new QAction( tr( "Remove Current Face" ), this );
mActionSplitFaces = new QAction( tr( "Split Current Face" ), this );
connect( mActionRemoveVerticesFillingHole, &QAction::triggered, this, [this] {removeSelectedVerticesFromMesh( true );} );
connect( mActionRemoveVerticesWithoutFillingHole, &QAction::triggered, this, [this] {removeSelectedVerticesFromMesh( false );} );
@ -242,14 +253,30 @@ QgsMapToolEditMeshFrame::QgsMapToolEditMeshFrame( QgsMapCanvas *canvas )
activateWithState( Digitizing );
} );
connect( mActionSelectByPolygon, &QAction::toggled, this, [this]( bool checked )
for ( int i = 0; i < mSelectActions.count(); ++i )
{
if ( checked )
connect( mSelectActions.at( i ), &QAction::triggered, this, [i]
{
QgsSettings settings;
settings.setValue( QStringLiteral( "UI/Mesh/defaultSelection" ), i );
} );
}
connect( mActionSelectByPolygon, &QAction::triggered, this, [this]
{
if ( mActionSelectByPolygon->isChecked() )
{
activateWithState( SelectingByPolygon );
}
else
mSelectionBand->reset( QgsWkbTypes::PolygonGeometry );
} );
connect( mActionSelectByExpression, &QAction::triggered, this, &QgsMapToolEditMeshFrame::showSelectByExpressionDialog );
connect( mActionSelectByTouchingSelectedPolygon, &QAction::triggered, this, &QgsMapToolEditMeshFrame::selectByTouchingSelectedPolygons );
connect( mActionSelectByContainingSelectedPolygon, &QAction::triggered, this, &QgsMapToolEditMeshFrame::selectByContainingSelectedPolygons );
connect( mActionDelaunayTriangulation, &QAction::triggered, this, [this]
{
if ( mCurrentEditor && mSelectedVertices.count() >= 3 )
@ -280,11 +307,12 @@ QgsMapToolEditMeshFrame::QgsMapToolEditMeshFrame( QgsMapCanvas *canvas )
connect( mActionTransformCoordinates, &QAction::triggered, this, &QgsMapToolEditMeshFrame::triggerTransformCoordinatesDockWidget );
connect( mActionSelectByExpression, &QAction::triggered, this, &QgsMapToolEditMeshFrame::showSelectByExpressionDialog );
connect( canvas, &QgsMapCanvas::selectionChanged, this, [this]
{
mActionForceByVectorLayerGeometries->setEnabled( areGeometriesSelectedInVectorLayer() &&( mCurrentEditor != nullptr ) );
bool enable = areGeometriesSelectedInVectorLayer() && ( mCurrentEditor != nullptr );
mActionForceByVectorLayerGeometries->setEnabled( enable );
mActionSelectByContainingSelectedPolygon->setEnabled( enable );
mActionSelectByTouchingSelectedPolygon->setEnabled( enable );
} );
connect( mActionForceByVectorLayerGeometries, &QAction::triggered, this, &QgsMapToolEditMeshFrame::forceBySelectedLayerPolyline );
@ -330,7 +358,10 @@ void QgsMapToolEditMeshFrame::setActionsEnable( bool enable )
for ( QAction *action : std::as_const( actions ) )
action->setEnabled( enable );
mActionForceByVectorLayerGeometries->setEnabled( enable && areGeometriesSelectedInVectorLayer() );
bool areGeometriesSelected = areGeometriesSelectedInVectorLayer();
mActionForceByVectorLayerGeometries->setEnabled( enable && areGeometriesSelected );
mActionSelectByContainingSelectedPolygon->setEnabled( enable && areGeometriesSelected );
mActionSelectByTouchingSelectedPolygon->setEnabled( enable && areGeometriesSelected );
}
@ -348,12 +379,18 @@ QAction *QgsMapToolEditMeshFrame::digitizeAction() const
QList<QAction *> QgsMapToolEditMeshFrame::selectActions() const
{
return QList<QAction *>()
<< mActionSelectByPolygon;
return mSelectActions;
}
QAction *QgsMapToolEditMeshFrame::defaultSelectActions() const
{
QgsSettings settings;
bool ok = false;
int defaultIndex = settings.value( QStringLiteral( "UI/Mesh/defaultSelection" ) ).toInt( &ok );
if ( ok && mSelectActions.at( defaultIndex )->isEnabled() )
return mSelectActions.at( defaultIndex );
return mActionSelectByPolygon;
}
@ -926,7 +963,7 @@ void QgsMapToolEditMeshFrame::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
case Selecting:
{
QgsGeometry selectionGeom = mSelectionBand->asGeometry();
selectInGeometry( selectionGeom, e->modifiers() );
selectByGeometry( selectionGeom, e->modifiers() );
mSelectionBand->reset( QgsWkbTypes::PolygonGeometry );
mCurrentState = Digitizing;
}
@ -967,7 +1004,7 @@ void QgsMapToolEditMeshFrame::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
else if ( e->button() == Qt::RightButton )
{
QgsGeometry selectionGeom = mSelectionBand->asGeometry();
selectInGeometry( selectionGeom, e->modifiers() );
selectByGeometry( selectionGeom, e->modifiers() );
mSelectionBand->reset( QgsWkbTypes::PolygonGeometry );
}
break;
@ -1651,48 +1688,11 @@ void QgsMapToolEditMeshFrame::reindexMesh()
mCurrentLayer->reindex( transform, true );
}
void QgsMapToolEditMeshFrame::selectInGeometry( const QgsGeometry &geometry, Qt::KeyboardModifiers modifiers )
void QgsMapToolEditMeshFrame::selectByGeometry( const QgsGeometry &geometry, Qt::KeyboardModifiers modifiers )
{
if ( mCurrentLayer.isNull() || !mCurrentLayer->triangularMesh() || mCurrentEditor.isNull() )
return;
QSet<int> selectedVertices;
const QList<int> nativeFaceIndexes = mCurrentLayer->triangularMesh()->nativeFaceIndexForRectangle( geometry.boundingBox() );
std::unique_ptr<QgsGeometryEngine> engine( QgsGeometry::createGeometryEngine( geometry.constGet() ) );
engine->prepareGeometry();
for ( const int faceIndex : nativeFaceIndexes )
{
const QgsMeshFace &face = nativeFace( faceIndex );
if ( !( modifiers & Qt::AltModifier ) )
{
std::unique_ptr<QgsPolygon> faceGeom( new QgsPolygon( new QgsLineString( nativeFaceGeometry( faceIndex ) ) ) );
if ( engine->intersects( faceGeom.get() ) )
{
QSet<int> faceToAdd = qgis::listToSet( face.toList() );
selectedVertices.unite( faceToAdd );
}
}
else
{
for ( const int vertexIndex : face )
{
const QgsMeshVertex &vertex = mapVertex( vertexIndex );
if ( engine->contains( &vertex ) )
selectedVertices.insert( vertexIndex );
}
}
}
//free vertices
const QList<int> &freeVerticesIndexes = mCurrentEditor->freeVerticesIndexes();
for ( const int freeVertexIndex : freeVerticesIndexes )
{
const QgsMeshVertex &vertex = mapVertex( freeVertexIndex );
if ( engine->contains( &vertex ) )
selectedVertices.insert( freeVertexIndex );
}
Qgis::SelectBehavior behavior;
if ( modifiers & Qt::ShiftModifier )
behavior = Qgis::SelectBehavior::RemoveFromSelection;
@ -1701,9 +1701,87 @@ void QgsMapToolEditMeshFrame::selectInGeometry( const QgsGeometry &geometry, Qt:
else
behavior = Qgis::SelectBehavior::SetSelection;
if ( modifiers & Qt::AltModifier )
selectContainedByGeometry( geometry, behavior );
else
selectTouchedByGeometry( geometry, behavior );
}
void QgsMapToolEditMeshFrame::selectTouchedByGeometry( const QgsGeometry &geometry, Qgis::SelectBehavior behavior )
{
QSet<int> selectedVertices;
const QList<int> nativeFaceIndexes = mCurrentLayer->triangularMesh()->nativeFaceIndexForRectangle( geometry.boundingBox() );
std::unique_ptr<QgsGeometryEngine> engine( QgsGeometry::createGeometryEngine( geometry.constGet() ) );
engine->prepareGeometry();
for ( const int faceIndex : nativeFaceIndexes )
{
const QgsMeshFace &face = nativeFace( faceIndex );
std::unique_ptr<QgsPolygon> faceGeom( new QgsPolygon( new QgsLineString( nativeFaceGeometry( faceIndex ) ) ) );
if ( engine->intersects( faceGeom.get() ) )
{
QSet<int> faceToAdd = qgis::listToSet( face.toList() );
selectedVertices.unite( faceToAdd );
}
}
const QList<int> &freeVerticesIndexes = mCurrentEditor->freeVerticesIndexes();
for ( const int freeVertexIndex : freeVerticesIndexes )
{
const QgsMeshVertex &vertex = mapVertex( freeVertexIndex );
if ( engine->contains( &vertex ) )
selectedVertices.insert( freeVertexIndex );
}
setSelectedVertices( selectedVertices.values(), behavior );
}
void QgsMapToolEditMeshFrame::selectContainedByGeometry( const QgsGeometry &geometry, Qgis::SelectBehavior behavior )
{
QSet<int> selectedVertices;
const QList<int> nativeFaceIndexes = mCurrentLayer->triangularMesh()->nativeFaceIndexForRectangle( geometry.boundingBox() );
std::unique_ptr<QgsGeometryEngine> engine( QgsGeometry::createGeometryEngine( geometry.constGet() ) );
engine->prepareGeometry();
for ( const int faceIndex : nativeFaceIndexes )
{
const QgsMeshFace &face = nativeFace( faceIndex );
for ( const int vertexIndex : face )
{
const QgsMeshVertex &vertex = mapVertex( vertexIndex );
if ( engine->contains( &vertex ) )
selectedVertices.insert( vertexIndex );
}
}
const QList<int> &freeVerticesIndexes = mCurrentEditor->freeVerticesIndexes();
for ( const int freeVertexIndex : freeVerticesIndexes )
{
const QgsMeshVertex &vertex = mapVertex( freeVertexIndex );
if ( engine->contains( &vertex ) )
selectedVertices.insert( freeVertexIndex );
}
setSelectedVertices( selectedVertices.values(), behavior );
}
void QgsMapToolEditMeshFrame::selectByTouchingSelectedPolygons()
{
onEditingStarted();
const QList<QgsGeometry> geometries = selectedGeometriesInVectorLayers();
for ( const QgsGeometry &geom : geometries )
selectTouchedByGeometry( geom, Qgis::SelectBehavior::AddToSelection );
}
void QgsMapToolEditMeshFrame::selectByContainingSelectedPolygons()
{
onEditingStarted();
const QList<QgsGeometry> geometries = selectedGeometriesInVectorLayers();
for ( const QgsGeometry &geom : geometries )
selectContainedByGeometry( geom, Qgis::SelectBehavior::AddToSelection );
}
void QgsMapToolEditMeshFrame::applyZValueOnSelectedVertices()
{
if ( !mZValueWidget )
@ -2412,7 +2490,6 @@ int QgsMapToolEditMeshFrame::closeVertex( const QgsPointXY &mapPoint ) const
return -1;
}
void QgsMapToolEditMeshFrame::selectByExpression( const QString &textExpression, Qgis::SelectBehavior behavior, QgsMesh::ElementType elementType )
{
if ( !mCurrentEditor || !mCurrentLayer )
@ -2440,6 +2517,7 @@ void QgsMapToolEditMeshFrame::selectByExpression( const QString &textExpression,
}
}
void QgsMapToolEditMeshFrame::onZoomToSelected()
{
canvas()->zoomToFeatureExtent( mSelectedMapExtent );

View File

@ -164,6 +164,8 @@ class APP_EXPORT QgsMapToolEditMeshFrame : public QgsMapToolAdvancedDigitizing
void showSelectByExpressionDialog();
void selectByExpression( const QString &textExpression, Qgis::SelectBehavior behavior, QgsMesh::ElementType elementType );
void selectByTouchingSelectedPolygons();
void selectByContainingSelectedPolygons();
void onZoomToSelected();
void forceBySelectedLayerPolyline();
void reindexMesh();
@ -226,7 +228,9 @@ class APP_EXPORT QgsMapToolEditMeshFrame : public QgsMapToolAdvancedDigitizing
bool isFaceSelected( int faceIndex );
void setSelectedVertices( const QList<int> newSelectedVertices, Qgis::SelectBehavior behavior );
void setSelectedFaces( const QList<int> newSelectedFaces, Qgis::SelectBehavior behavior );
void selectInGeometry( const QgsGeometry &geometry, Qt::KeyboardModifiers modifiers );
void selectByGeometry( const QgsGeometry &geometry, Qt::KeyboardModifiers modifiers );
void selectTouchedByGeometry( const QgsGeometry &geometry, Qgis::SelectBehavior behavior );
void selectContainedByGeometry( const QgsGeometry &geometry, Qgis::SelectBehavior behavior );
void applyZValueOnSelectedVertices();
void prepareSelection();
void updateSelectecVerticesMarker();
@ -282,6 +286,7 @@ class APP_EXPORT QgsMapToolEditMeshFrame : public QgsMapToolAdvancedDigitizing
QList<QgsVertexMarker *> mFreeVertexMarker;
//! members for selection of vertices/faces
QList<QAction *> mSelectActions;
QMap<int, SelectedVertexData> mSelectedVertices;
QgsRectangle mSelectedMapExtent;
QSet<int> mSelectedFaces;
@ -333,6 +338,9 @@ class APP_EXPORT QgsMapToolEditMeshFrame : public QgsMapToolAdvancedDigitizing
QAction *mActionSelectByExpression = nullptr;
QAction *mActionForceByVectorLayerGeometries = nullptr;
QAction *mActionSelectByContainingSelectedPolygon = nullptr;
QAction *mActionSelectByTouchingSelectedPolygon = nullptr;
QgsMeshEditForceByLineAction *mWidgetActionForceByLine = nullptr;
QAction *mActionReindexMesh = nullptr;

View File

@ -3866,7 +3866,16 @@ void QgisApp::createToolBars()
QToolButton *meshSelectToolButton = new QToolButton();
meshSelectToolButton->setPopupMode( QToolButton::MenuButtonPopup );
meshSelectToolButton->addActions( editMeshMapTool->selectActions() );
QList<QAction *> selectActions = editMeshMapTool->selectActions();
for ( QAction *selectAction : selectActions )
{
meshSelectToolButton->addAction( selectAction );
connect( selectAction, &QAction::triggered, meshSelectToolButton, [selectAction, meshSelectToolButton]
{
meshSelectToolButton->setDefaultAction( selectAction );
} );
}
meshSelectToolButton->setDefaultAction( editMeshMapTool->defaultSelectActions() );
mMeshToolBar->addWidget( meshSelectToolButton );