From 3341f0589035eaf700a9768408829285bca7ba83 Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Fri, 22 Nov 2024 09:51:48 +0100 Subject: [PATCH 01/18] add function delaunayConditionForEdge() --- src/core/mesh/qgstopologicalmesh.cpp | 39 ++++++++++++++++++++++++++++ src/core/mesh/qgstopologicalmesh.h | 8 ++++++ 2 files changed, 47 insertions(+) diff --git a/src/core/mesh/qgstopologicalmesh.cpp b/src/core/mesh/qgstopologicalmesh.cpp index e6b040f7e067..993c01f39b17 100644 --- a/src/core/mesh/qgstopologicalmesh.cpp +++ b/src/core/mesh/qgstopologicalmesh.cpp @@ -19,6 +19,7 @@ #include "qgsmesheditor.h" #include "qgsmessagelog.h" #include "qgsgeometryutils.h" +#include "qgscircle.h" #include #include @@ -2589,3 +2590,41 @@ QgsTopologicalMesh::Changes QgsTopologicalMesh::changeXYValue( const QList return changes; } + +bool QgsTopologicalMesh::delaunayConditionForEdge( int vertexIndex1, int vertexIndex2 ) +{ + int faceIndex1; + int faceIndex2; + int oppositeVertexFace1; + int oppositeVertexFace2; + int supposedOppositeVertexFace1; + int supposedoppositeVertexFace2; + + bool result = eitherSideFacesAndVertices( + vertexIndex1, + vertexIndex2, + faceIndex1, + faceIndex2, + oppositeVertexFace1, + supposedoppositeVertexFace2, + supposedOppositeVertexFace1, + oppositeVertexFace2 ); + + if ( ! result ) + return false; + + const QgsMeshFace face1 = mMesh->face( faceIndex1 ); + const QgsMeshFace face2 = mMesh->face( faceIndex2 ); + + QgsCircle circle = QgsCircle::from3Points( mMesh->vertex( face1.at( 0 ) ), + mMesh->vertex( face1.at( 1 ) ), + mMesh->vertex( face1.at( 2 ) ) ); + bool circle1ContainsPoint = circle.contains( mMesh->vertex( supposedoppositeVertexFace2 ) ); + + circle = QgsCircle::from3Points( mMesh->vertex( face2.at( 0 ) ), + mMesh->vertex( face2.at( 1 ) ), + mMesh->vertex( face2.at( 2 ) ) ); + bool circle2ContainsPoint = circle.contains( mMesh->vertex( supposedOppositeVertexFace1 ) ); + + return !( circle1ContainsPoint || circle2ContainsPoint ); +} diff --git a/src/core/mesh/qgstopologicalmesh.h b/src/core/mesh/qgstopologicalmesh.h index 6b91e48b2267..1eeb6e853818 100644 --- a/src/core/mesh/qgstopologicalmesh.h +++ b/src/core/mesh/qgstopologicalmesh.h @@ -232,6 +232,14 @@ class CORE_EXPORT QgsTopologicalMesh */ Changes flipEdge( int vertexIndex1, int vertexIndex2 ); + /** + * Check if Delaunay condition holds for given edge + * returns TRUE if delaunay condition holds FALSE otherwise + * + * \since QGIS 3.42 + */ + bool delaunayConditionForEdge( int vertexIndex1, int vertexIndex2 ); + /** * Returns TRUE if faces separated by vertices with indexes \a vertexIndex1 and \a vertexIndex2 can be merged */ From 1248d785a6c6e21b5dba3d7c5c690bdafd14dafa Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Fri, 22 Nov 2024 09:52:45 +0100 Subject: [PATCH 02/18] undo command with delaunay refinement --- src/core/mesh/qgsmesheditor.cpp | 158 ++++++++++++++++++++++++++++++++ src/core/mesh/qgsmesheditor.h | 30 ++++++ 2 files changed, 188 insertions(+) diff --git a/src/core/mesh/qgsmesheditor.cpp b/src/core/mesh/qgsmesheditor.cpp index 770242fa7062..cf4a3f083ae0 100644 --- a/src/core/mesh/qgsmesheditor.cpp +++ b/src/core/mesh/qgsmesheditor.cpp @@ -640,6 +640,15 @@ QgsMeshEditingError QgsMeshEditor::removeFaces( const QList &facesToRemove return error; } +void QgsMeshEditor::addVertexWithDelaunayRefinement( const QgsMeshVertex vertex, const double tolerance ) +{ + int triangleIndex = mTriangularMesh->faceIndexForPoint_v2( vertex ); + if ( triangleIndex == -1 ) + return; + + mUndoStack->push( new QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement( this, vertex, tolerance ) ); +} + bool QgsMeshEditor::edgeCanBeFlipped( int vertexIndex1, int vertexIndex2 ) const { return mTopologicalMesh.edgeCanBeFlipped( vertexIndex1, vertexIndex2 ); @@ -1482,3 +1491,152 @@ void QgsMeshLayerUndoCommandAdvancedEditing::redo() mMeshEditor->applyEdit( edit ); } } + +QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement::QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement( + QgsMeshEditor *meshEditor, + const QgsMeshVertex vertex, + double tolerance ) + : QgsMeshLayerUndoCommandMeshEdit( meshEditor ) + , mVertex( vertex ) + , mTolerance( tolerance ) +{ + setText( QObject::tr( "Add vertex inside face with Delaunay refinement" ) ); +} + +void QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement::redo() +{ + if ( !mVertex.isEmpty() ) + { + QgsMeshEditor::Edit edit; + + mMeshEditor->applyAddVertex( edit, mVertex, mTolerance ); + mEdits.append( edit ); + + QList> sharedEdges = innerEdges( triangularFaces( facesContainingVertex( mMeshEditor->topologicalMesh().mesh()->vertexCount() - 1 ) ) ); + + for ( std::pair edge : sharedEdges ) + { + if ( mMeshEditor->edgeCanBeFlipped( edge.first, edge.second ) && !mMeshEditor->topologicalMesh().delaunayConditionForEdge( edge.first, edge.second ) ) + { + mMeshEditor->applyFlipEdge( edit, edge.first, edge.second ); + mEdits.append( edit ); + } + } + + mVertex = QgsMeshVertex(); + } + else + { + for ( QgsMeshEditor::Edit &edit : mEdits ) + mMeshEditor->applyEdit( edit ); + } +} + +QSet QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement::facesContainingVertex( const int vertexId ) +{ + QList facesAroundVertex; + + for ( int i = 0; i < mMeshEditor->topologicalMesh().mesh()->faceCount(); i++ ) + { + QgsMeshFace face = mMeshEditor->topologicalMesh().mesh()->face( i ); + + if ( face.contains( vertexId ) ) + { + facesAroundVertex.push_back( i ); + } + } + + QSet vertexIndexes; + + for ( int faceIndex : facesAroundVertex ) + { + QgsMeshFace face = mMeshEditor->topologicalMesh().mesh()->face( faceIndex ); + + for ( int i = 0; i < face.count(); i++ ) + { + vertexIndexes.insert( face.at( i ) ); + } + } + + // faces that have at least one common vertex with newly added faces + QSet selectedFaces; + + for ( int i = 0; i < mMeshEditor->topologicalMesh().mesh()->faceCount(); i++ ) + { + const QgsMeshFace face = mMeshEditor->topologicalMesh().mesh()->face( i ); + + for ( int j = 0; j < face.count(); j++ ) + { + for ( int vertex : vertexIndexes ) + { + if ( face.contains( vertex ) ) + { + selectedFaces.insert( i ); + break; + } + } + } + } + return selectedFaces; +} + + +QSet QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement::triangularFaces( const QSet &faces ) +{ + QSet triangularFaces; + + for ( int faceIndex : faces ) + { + if ( mMeshEditor->topologicalMesh().mesh()->face( faceIndex ).count() == 3 ) + { + triangularFaces.insert( faceIndex ); + } + } + + return triangularFaces; +} + +QList> QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement::innerEdges( const QSet &faces ) +{ + // edges and number of their occurrence in triangular faces + QMap, int> edges; + + for ( int faceIndex : faces ) + { + const QgsMeshFace face = mMeshEditor->topologicalMesh().mesh()->face( faceIndex ); + + for ( int i = 0; i < face.size(); i++ ) + { + int next = i + 1; + if ( next == face.size() ) + { + next = 0; + } + + int minIndex = std::min( face.at( i ), face.at( next ) ); + int maxIndex = std::max( face.at( i ), face.at( next ) ); + std::pair edge = std::pair( minIndex, maxIndex ); + + int count = 1; + if ( edges.contains( edge ) ) + { + count = edges.take( edge ); + count++; + } + + edges.insert( edge, count ); + } + } + + QList> sharedEdges; + + for ( auto it = edges.begin(); it != edges.end(); it++ ) + { + if ( it.value() == 2 ) + { + sharedEdges.push_back( it.key() ); + } + } + + return sharedEdges; +} diff --git a/src/core/mesh/qgsmesheditor.h b/src/core/mesh/qgsmesheditor.h index ea0f127101db..92a4e137be7d 100644 --- a/src/core/mesh/qgsmesheditor.h +++ b/src/core/mesh/qgsmesheditor.h @@ -305,6 +305,13 @@ class CORE_EXPORT QgsMeshEditor : public QObject //! Returns the maximum count of vertices per face that the mesh can support int maximumVerticesPerFace() const; + /** + * Add a vertex in a face with Delaunay refinement of neighboring faces + * + * \since QGIS 3.42 + */ + void addVertexWithDelaunayRefinement( const QgsMeshVertex vertex, const double tolerance ); + signals: //! Emitted when the mesh is edited void meshEdited(); @@ -363,6 +370,7 @@ class CORE_EXPORT QgsMeshEditor : public QObject friend class QgsMeshLayerUndoCommandFlipEdge; friend class QgsMeshLayerUndoCommandMerge; friend class QgsMeshLayerUndoCommandSplitFaces; + friend class QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement; friend class QgsMeshLayerUndoCommandAdvancedEditing; }; @@ -652,7 +660,29 @@ class QgsMeshLayerUndoCommandAdvancedEditing : public QgsMeshLayerUndoCommandMes }; +/** + * \ingroup core + * + * \brief Class for undo/redo command for adding vertex to face with Delaunay Refiment of faces surrounding + * + * \since QGIS 3.42 + */ +class QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement: public QgsMeshLayerUndoCommandMeshEdit +{ + public: + + //! Constructor with the associated \a meshEditor and indexes \a vertex and \a tolerance + QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement( QgsMeshEditor *meshEditor, const QgsMeshVertex vertex, double tolerance ); + + void redo() override; + private: + QSet facesContainingVertex( const int vertexId ); + QSet triangularFaces( const QSet &faces ); + QList> innerEdges( const QSet &faces ); + QgsMeshVertex mVertex; + double mTolerance; +}; #endif //SIP_RUN From 1c04a69acce686c1e0141e2dff3e36e246098550 Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Fri, 22 Nov 2024 09:58:25 +0100 Subject: [PATCH 03/18] add delaunay refinement action --- src/app/mesh/qgsmaptooleditmeshframe.cpp | 54 +++++++++++++++++++++++- src/app/mesh/qgsmaptooleditmeshframe.h | 20 +++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/app/mesh/qgsmaptooleditmeshframe.cpp b/src/app/mesh/qgsmaptooleditmeshframe.cpp index 1d16b32713a0..fe22e111112a 100644 --- a/src/app/mesh/qgsmaptooleditmeshframe.cpp +++ b/src/app/mesh/qgsmaptooleditmeshframe.cpp @@ -203,6 +203,42 @@ void QgsMeshEditForceByLineAction::updateSettings() settings.setEnumValue( QStringLiteral( "UI/Mesh/ForceByLineToleranceUnit" ), mUnitSelecionWidget->unit() ); } +// +// QgsMeshEditDelaunayRefinementAction +// + +QgsMeshEditDelaunayRefinementAction::QgsMeshEditDelaunayRefinementAction( QObject *parent ) + : QWidgetAction( parent ) +{ + QVBoxLayout *layout = new QVBoxLayout(); + + QgsSettings settings; + + mCheckBoxRefineNeighboringFaces = new QCheckBox( tr( "On add vertex in face refine neighboring faces" ) ); + + bool refineNeighboringFaces = settings.value( QStringLiteral( "UI/Mesh/RefineNeighboringFaces" ) ).toBool(); + mCheckBoxRefineNeighboringFaces->setChecked( refineNeighboringFaces ); + layout->addWidget( mCheckBoxRefineNeighboringFaces ); + + QWidget *w = new QWidget(); + w->setLayout( layout ); + setDefaultWidget( w ); + + connect( mCheckBoxRefineNeighboringFaces, &QCheckBox::toggled, this, &QgsMeshEditDelaunayRefinementAction::updateSettings ); +} + +void QgsMeshEditDelaunayRefinementAction::updateSettings() +{ + QgsSettings settings; + + settings.setValue( QStringLiteral( "UI/Mesh/RefineNeighboringFaces" ), mCheckBoxRefineNeighboringFaces->isChecked() ); +} + +bool QgsMeshEditDelaunayRefinementAction::refineNeighboringFaces() const +{ + return mCheckBoxRefineNeighboringFaces->isChecked(); +} + // // QgsMapToolEditMeshFrame // @@ -234,6 +270,8 @@ QgsMapToolEditMeshFrame::QgsMapToolEditMeshFrame( QgsMapCanvas *canvas ) mWidgetActionForceByLine = new QgsMeshEditForceByLineAction( this ); mWidgetActionForceByLine->setMapCanvas( canvas ); + mWidgetActionDelaunayRefinementAction = new QgsMeshEditDelaunayRefinementAction( this ); + mActionReindexMesh = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionMeshReindex.svg" ) ), tr( "Reindex Faces and Vertices" ), this ); mActionRemoveVerticesFillingHole = new QAction( this ); @@ -429,6 +467,12 @@ QWidgetAction *QgsMapToolEditMeshFrame::forceByLineWidgetActionSettings() const return mWidgetActionForceByLine; } +QWidgetAction *QgsMapToolEditMeshFrame::delaunayRefinementWidgetActionSettings() const +{ + return mWidgetActionDelaunayRefinementAction; +} + + QAction *QgsMapToolEditMeshFrame::reindexAction() const { return mActionReindexMesh; @@ -2726,10 +2770,18 @@ void QgsMapToolEditMeshFrame::addVertex( zValue = currentZValue(); const QVector points( 1, QgsMeshVertex( effectivePoint.x(), effectivePoint.y(), zValue ) ); + if ( mCurrentEditor ) { double tolerance = QgsTolerance::vertexSearchRadius( canvas()->mapSettings() ); - mCurrentEditor->addVertices( points, tolerance ); + if ( mWidgetActionDelaunayRefinementAction->refineNeighboringFaces() && mCurrentFaceIndex != -1 ) + { + mCurrentEditor->addVertexWithDelaunayRefinement( points.first(), tolerance ); + } + else + { + mCurrentEditor->addVertices( points, tolerance ); + } } } diff --git a/src/app/mesh/qgsmaptooleditmeshframe.h b/src/app/mesh/qgsmaptooleditmeshframe.h index 7e6a66a77b25..a7254a09ff0c 100644 --- a/src/app/mesh/qgsmaptooleditmeshframe.h +++ b/src/app/mesh/qgsmaptooleditmeshframe.h @@ -111,6 +111,24 @@ class QgsMeshEditForceByLineAction : public QWidgetAction QgsDoubleSpinBox *mToleranceSpinBox = nullptr; }; +class QgsMeshEditDelaunayRefinementAction : public QWidgetAction +{ + Q_OBJECT + public: + + //! Constructor + QgsMeshEditDelaunayRefinementAction( QObject *parent = nullptr ); + + //! Returns + bool refineNeighboringFaces() const; + + private slots: + void updateSettings(); + + private: + QCheckBox *mCheckBoxRefineNeighboringFaces = nullptr; +}; + class APP_EXPORT QgsMapToolEditMeshFrame : public QgsMapToolAdvancedDigitizing { Q_OBJECT @@ -128,6 +146,7 @@ class APP_EXPORT QgsMapToolEditMeshFrame : public QgsMapToolAdvancedDigitizing QList forceByLinesActions() const; QAction *defaultForceAction() const; QWidgetAction *forceByLineWidgetActionSettings() const; + QWidgetAction *delaunayRefinementWidgetActionSettings() const; QAction *reindexAction() const; void setActionsEnable( bool enable ); @@ -352,6 +371,7 @@ class APP_EXPORT QgsMapToolEditMeshFrame : public QgsMapToolAdvancedDigitizing QAction *mActionForceByLines = nullptr; QgsMeshEditForceByLineAction *mWidgetActionForceByLine = nullptr; + QgsMeshEditDelaunayRefinementAction *mWidgetActionDelaunayRefinementAction = nullptr; QAction *mActionReindexMesh = nullptr; friend class TestQgsMapToolEditMesh; From f6009b875e3c6b9414c58da7cfc748090de6a4b0 Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Fri, 22 Nov 2024 10:00:08 +0100 Subject: [PATCH 04/18] add menu to button --- src/app/qgisapp.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index a4a5d942c682..e53c324615f0 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -3930,7 +3930,15 @@ void QgisApp::createToolBars() QgsMapToolEditMeshFrame *editMeshMapTool = qobject_cast( mMapTools->mapTool( QgsAppMapTools::EditMeshFrame ) ); if ( editMeshMapTool ) { - mMeshToolBar->addAction( editMeshMapTool->digitizeAction() ); + QToolButton *meshEditToolButton = new QToolButton(); + meshEditToolButton->setPopupMode( QToolButton::MenuButtonPopup ); + QMenu *meshEditMenu = new QMenu( meshEditToolButton ); + + meshEditToolButton->setDefaultAction( editMeshMapTool->digitizeAction() ); + meshEditMenu->addSeparator(); + meshEditMenu->addAction( editMeshMapTool->delaunayRefinementWidgetActionSettings() ); + meshEditToolButton->setMenu( meshEditMenu ); + mMeshToolBar->addWidget( meshEditToolButton ); QToolButton *meshSelectToolButton = new QToolButton(); meshSelectToolButton->setPopupMode( QToolButton::MenuButtonPopup ); From 99df7a6f4a00fae5b4ba73d936b0c4b2a20df097 Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Fri, 22 Nov 2024 10:00:39 +0100 Subject: [PATCH 05/18] sipify --- python/PyQt6/core/auto_generated/mesh/qgsmesheditor.sip.in | 7 +++++++ python/core/auto_generated/mesh/qgsmesheditor.sip.in | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/python/PyQt6/core/auto_generated/mesh/qgsmesheditor.sip.in b/python/PyQt6/core/auto_generated/mesh/qgsmesheditor.sip.in index 6482b89e7de9..40724d000529 100644 --- a/python/PyQt6/core/auto_generated/mesh/qgsmesheditor.sip.in +++ b/python/PyQt6/core/auto_generated/mesh/qgsmesheditor.sip.in @@ -260,6 +260,13 @@ Returns the count of valid vertices, that is non void vertices in the mesh int maximumVerticesPerFace() const; %Docstring Returns the maximum count of vertices per face that the mesh can support +%End + + void addVertexWithDelaunayRefinement( const QgsMeshVertex vertex, const double tolerance ); +%Docstring +Add a vertex in a face with Delaunay refinement of neighboring faces + +.. versionadded:: 3.42 %End signals: diff --git a/python/core/auto_generated/mesh/qgsmesheditor.sip.in b/python/core/auto_generated/mesh/qgsmesheditor.sip.in index 6482b89e7de9..40724d000529 100644 --- a/python/core/auto_generated/mesh/qgsmesheditor.sip.in +++ b/python/core/auto_generated/mesh/qgsmesheditor.sip.in @@ -260,6 +260,13 @@ Returns the count of valid vertices, that is non void vertices in the mesh int maximumVerticesPerFace() const; %Docstring Returns the maximum count of vertices per face that the mesh can support +%End + + void addVertexWithDelaunayRefinement( const QgsMeshVertex vertex, const double tolerance ); +%Docstring +Add a vertex in a face with Delaunay refinement of neighboring faces + +.. versionadded:: 3.42 %End signals: From 2e72d7bf5bf20fdadf749a23b2a1de740949e0b0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 12:31:20 +0000 Subject: [PATCH 06/18] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/app/mesh/qgsmaptooleditmeshframe.cpp | 12 ++++++------ src/app/mesh/qgsmaptooleditmeshframe.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/app/mesh/qgsmaptooleditmeshframe.cpp b/src/app/mesh/qgsmaptooleditmeshframe.cpp index ea3076a27335..a2bd2bbe876b 100644 --- a/src/app/mesh/qgsmaptooleditmeshframe.cpp +++ b/src/app/mesh/qgsmaptooleditmeshframe.cpp @@ -237,13 +237,13 @@ QgsMeshEditDigitizingAction::QgsMeshEditDigitizingAction( QObject *parent ) int interpolateFromValue = settings.enumValue( QStringLiteral( "UI/Mesh/zValueFrom" ), PreferMeshThenZWidget ); mComboZValueType->setCurrentIndex( interpolateFromValue ); - + mCheckBoxRefineNeighboringFaces = new QCheckBox( tr( "On add vertex in face refine neighboring faces" ) ); bool refineNeighboringFaces = settings.value( QStringLiteral( "UI/Mesh/refineNeighboringFaces" ) ).toBool(); mCheckBoxRefineNeighboringFaces->setChecked( refineNeighboringFaces ); layout->addWidget( mCheckBoxRefineNeighboringFaces ); - + gLayout->addWidget( labelZValueType, 1, 0, 1, 1 ); gLayout->addWidget( mComboZValueType, 1, 1, 1, 1 ); gLayout->addWidget( mCheckBoxRefineNeighboringFaces, 2, 0, 1, 2 ); @@ -251,8 +251,8 @@ QgsMeshEditDigitizingAction::QgsMeshEditDigitizingAction( QObject *parent ) QWidget *w = new QWidget(); w->setLayout( gLayout ); setDefaultWidget( w ); - - connect( mCheckBoxRefineNeighboringFaces, &QCheckBox::toggled, this, &QgsMeshEditDelaunayRefinementAction::updateSettings ); + + connect( mCheckBoxRefineNeighboringFaces, &QCheckBox::toggled, this, &QgsMeshEditDelaunayRefinementAction::updateSettings ); } void QgsMeshEditDigitizingAction::updateSettings() @@ -272,10 +272,10 @@ void QgsMeshEditDigitizingAction::setZValueType( QgsMeshEditDigitizingAction::ZV { mComboZValueType->setCurrentIndex( mComboZValueType->findData( zValueSource ) ); } - + bool QgsMeshEditDigitizingAction::refineNeighboringFaces() const { - return mCheckBoxRefineNeighboringFaces->isChecked(); + return mCheckBoxRefineNeighboringFaces->isChecked(); } // diff --git a/src/app/mesh/qgsmaptooleditmeshframe.h b/src/app/mesh/qgsmaptooleditmeshframe.h index 0377b1f29d85..f2d9921edf1e 100644 --- a/src/app/mesh/qgsmaptooleditmeshframe.h +++ b/src/app/mesh/qgsmaptooleditmeshframe.h @@ -140,7 +140,7 @@ class QgsMeshEditDigitizingAction : public QWidgetAction //! Returns type of z value obtaining QgsMeshEditDigitizingAction::ZValueSource zValueSourceType() const; - + //! Returns if neighboring faces should be refined when adding vertex inside mesh bool refineNeighboringFaces() const; From 463aa3acd6bd591201e14c5bb0cb48637deb12c6 Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Thu, 12 Dec 2024 13:32:21 +0100 Subject: [PATCH 07/18] fix merge issues --- src/app/mesh/qgsmaptooleditmeshframe.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/app/mesh/qgsmaptooleditmeshframe.cpp b/src/app/mesh/qgsmaptooleditmeshframe.cpp index a2bd2bbe876b..22f75fb91b70 100644 --- a/src/app/mesh/qgsmaptooleditmeshframe.cpp +++ b/src/app/mesh/qgsmaptooleditmeshframe.cpp @@ -242,8 +242,7 @@ QgsMeshEditDigitizingAction::QgsMeshEditDigitizingAction( QObject *parent ) bool refineNeighboringFaces = settings.value( QStringLiteral( "UI/Mesh/refineNeighboringFaces" ) ).toBool(); mCheckBoxRefineNeighboringFaces->setChecked( refineNeighboringFaces ); - layout->addWidget( mCheckBoxRefineNeighboringFaces ); - + gLayout->addWidget( labelZValueType, 1, 0, 1, 1 ); gLayout->addWidget( mComboZValueType, 1, 1, 1, 1 ); gLayout->addWidget( mCheckBoxRefineNeighboringFaces, 2, 0, 1, 2 ); @@ -251,8 +250,8 @@ QgsMeshEditDigitizingAction::QgsMeshEditDigitizingAction( QObject *parent ) QWidget *w = new QWidget(); w->setLayout( gLayout ); setDefaultWidget( w ); - - connect( mCheckBoxRefineNeighboringFaces, &QCheckBox::toggled, this, &QgsMeshEditDelaunayRefinementAction::updateSettings ); + + connect( mCheckBoxRefineNeighboringFaces, &QCheckBox::toggled, this, &QgsMeshEditDigitizingAction::updateSettings ); } void QgsMeshEditDigitizingAction::updateSettings() From 4cff3c60daa0ce024ce302799bdd765da429ce74 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 12:37:33 +0000 Subject: [PATCH 08/18] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/app/mesh/qgsmaptooleditmeshframe.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/mesh/qgsmaptooleditmeshframe.cpp b/src/app/mesh/qgsmaptooleditmeshframe.cpp index 22f75fb91b70..84569cb64dc1 100644 --- a/src/app/mesh/qgsmaptooleditmeshframe.cpp +++ b/src/app/mesh/qgsmaptooleditmeshframe.cpp @@ -242,7 +242,7 @@ QgsMeshEditDigitizingAction::QgsMeshEditDigitizingAction( QObject *parent ) bool refineNeighboringFaces = settings.value( QStringLiteral( "UI/Mesh/refineNeighboringFaces" ) ).toBool(); mCheckBoxRefineNeighboringFaces->setChecked( refineNeighboringFaces ); - + gLayout->addWidget( labelZValueType, 1, 0, 1, 1 ); gLayout->addWidget( mComboZValueType, 1, 1, 1, 1 ); gLayout->addWidget( mCheckBoxRefineNeighboringFaces, 2, 0, 1, 2 ); @@ -250,8 +250,8 @@ QgsMeshEditDigitizingAction::QgsMeshEditDigitizingAction( QObject *parent ) QWidget *w = new QWidget(); w->setLayout( gLayout ); setDefaultWidget( w ); - - connect( mCheckBoxRefineNeighboringFaces, &QCheckBox::toggled, this, &QgsMeshEditDigitizingAction::updateSettings ); + + connect( mCheckBoxRefineNeighboringFaces, &QCheckBox::toggled, this, &QgsMeshEditDigitizingAction::updateSettings ); } void QgsMeshEditDigitizingAction::updateSettings() From 37eb0e707c99504949865a61365a23520d49abad Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Thu, 19 Dec 2024 16:22:40 +0100 Subject: [PATCH 09/18] access widget in test to directly change selected value --- src/app/mesh/qgsmaptooleditmeshframe.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/mesh/qgsmaptooleditmeshframe.h b/src/app/mesh/qgsmaptooleditmeshframe.h index f2d9921edf1e..792869bf848c 100644 --- a/src/app/mesh/qgsmaptooleditmeshframe.h +++ b/src/app/mesh/qgsmaptooleditmeshframe.h @@ -152,6 +152,8 @@ class QgsMeshEditDigitizingAction : public QWidgetAction private: QComboBox *mComboZValueType = nullptr; QCheckBox *mCheckBoxRefineNeighboringFaces = nullptr; + + friend class TestQgsMapToolEditMesh; }; class APP_EXPORT QgsMapToolEditMeshFrame : public QgsMapToolAdvancedDigitizing From 56bb4176648c1f1c06c368fbfa0c0b4604609952 Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Thu, 19 Dec 2024 16:30:07 +0100 Subject: [PATCH 10/18] add tests --- tests/src/app/testqgsmaptooleditmesh.cpp | 103 +++++++++++++++++- .../expected_delaunay.2dm | 21 ++++ .../expected_not_delaunay.2dm | 21 ++++ tests/testdata/mesh/not_delaunay.2dm | 18 +++ 4 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 tests/testdata/control_files/app/expected_edit_delaunay_refinement/expected_delaunay.2dm create mode 100644 tests/testdata/control_files/app/expected_edit_no_delaunay_refinement/expected_not_delaunay.2dm create mode 100644 tests/testdata/mesh/not_delaunay.2dm diff --git a/tests/src/app/testqgsmaptooleditmesh.cpp b/tests/src/app/testqgsmaptooleditmesh.cpp index 7a7ea9201a1d..7f1455c774e7 100644 --- a/tests/src/app/testqgsmaptooleditmesh.cpp +++ b/tests/src/app/testqgsmaptooleditmesh.cpp @@ -14,6 +14,8 @@ * * ***************************************************************************/ +#include + #include "qgstest.h" #include "qgisapp.h" #include "testqgsmaptoolutils.h" @@ -25,11 +27,13 @@ #include "qgsterrainprovider.h" #include "qgsmeshtransformcoordinatesdockwidget.h" -class TestQgsMapToolEditMesh : public QObject +class TestQgsMapToolEditMesh : public QgsTest { Q_OBJECT public: - TestQgsMapToolEditMesh() = default; + TestQgsMapToolEditMesh() + : QgsTest( QStringLiteral( "Map Tool Edit Mesh Tests" ), QStringLiteral( "app" ) ) + {} private slots: void initTestCase(); // will be called before the first testfunction is executed. @@ -44,8 +48,11 @@ class TestQgsMapToolEditMesh : public QObject void selectElements(); void testAssignVertexZValueFromTerrainOnCreation(); void testAssignVertexZValueFromTerrainOnButtonClick(); + void testDelaunayRefinement(); private: + static QString read2DMFileContent( const QString &filePath ); + QgisApp *mQgisApp = nullptr; std::unique_ptr meshLayerQuadFlower; QString mDataDir; @@ -730,5 +737,97 @@ void TestQgsMapToolEditMesh::selectElements() QCOMPARE( mEditMeshMapTool->mSelectedVertices.count(), 3 ); } +void TestQgsMapToolEditMesh::testDelaunayRefinement() +{ + QgsCoordinateReferenceSystem crs3857; + crs3857.createFromString( "EPSG:3857" ); + + const QgsCoordinateTransform transform; + QgsMeshEditingError error; + QgsPointXY point; + + QString originalDataPath = QString( "/mesh/not_delaunay.2dm" ); + + // editing with normal setting - without delaunay refinement + mEditMeshMapTool->mWidgetActionDigitizing->mCheckBoxRefineNeighboringFaces->setChecked( false ); + + const QString copyDataPath1 = copyTestData( originalDataPath ); // copy of data to be edited + + std::unique_ptr layer = std::make_unique( copyDataPath1, "not delaunay", "mdal" ); + layer->setCrs( crs3857 ); + QVERIFY( layer->isValid() ); + + layer->startFrameEditing( transform, error, false ); + QVERIFY( error == QgsMeshEditingError() ); + + mCanvas->setLayers( QList() << layer.get() ); + mCanvas->setDestinationCrs( crs3857 ); + mCanvas->setExtent( layer->extent() ); + + QVERIFY( layer->meshEditor() ); + + TestQgsMapToolAdvancedDigitizingUtils tool( mEditMeshMapTool ); + mCanvas->setCurrentLayer( layer.get() ); + mEditMeshMapTool->mActionDigitizing->trigger(); + + point = QgsPointXY( 4.5, 3.5 ); + QCOMPARE( layer->meshEditor()->validFacesCount(), 8 ); + tool.mouseMove( point.x(), point.y() ); + tool.mouseDoubleClick( point.x(), point.y(), Qt::LeftButton ); + QCOMPARE( layer->meshEditor()->validFacesCount(), 10 ); + QCOMPARE( layer->undoStack()->command( 0 )->text(), "Add 1 vertices" ); + + QVERIFY( layer->commitFrameEditing( transform, false ) ); + + QGSCOMPARELONGSTR( "edit_no_delaunay_refinement", "not_delaunay.2dm", TestQgsMapToolEditMesh::read2DMFileContent( copyDataPath1 ).toUtf8() ); + + // editing with delaunay refinement + mEditMeshMapTool->mWidgetActionDigitizing->mCheckBoxRefineNeighboringFaces->setChecked( true ); + + const QString copyDataPath2 = copyTestData( originalDataPath ); // copy of data to be edited + + layer = std::make_unique( copyDataPath2, "not delaunay", "mdal" ); + layer->setCrs( crs3857 ); + QVERIFY( layer->isValid() ); + + layer->startFrameEditing( transform, error, false ); + QVERIFY( error == QgsMeshEditingError() ); + + mCanvas->setLayers( QList() << layer.get() ); + mCanvas->setDestinationCrs( crs3857 ); + mCanvas->setExtent( layer->extent() ); + + QVERIFY( layer->meshEditor() ); + + mCanvas->setCurrentLayer( layer.get() ); + mEditMeshMapTool->mActionDigitizing->trigger(); + + point = QgsPointXY( 4.5, 3.5 ); + QCOMPARE( layer->meshEditor()->validFacesCount(), 8 ); + tool.mouseMove( point.x(), point.y() ); + tool.mouseDoubleClick( point.x(), point.y(), Qt::LeftButton ); + QCOMPARE( layer->meshEditor()->validFacesCount(), 10 ); + QCOMPARE( layer->undoStack()->command( 0 )->text(), "Add vertex inside face with Delaunay refinement" ); + + QVERIFY( layer->commitFrameEditing( transform, false ) ); + + QGSCOMPARELONGSTR( "edit_delaunay_refinement", "delaunay.2dm", TestQgsMapToolEditMesh::read2DMFileContent( copyDataPath2 ).toUtf8() ); +} + +QString TestQgsMapToolEditMesh::read2DMFileContent( const QString &filePath ) +{ + QFile file( filePath ); + if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) + { + return QString(); // Return empty string if file can't be opened + } + + QTextStream in( &file ); + + QString content = in.readAll(); + file.close(); + return content; +} + QGSTEST_MAIN( TestQgsMapToolEditMesh ) #include "testqgsmaptooleditmesh.moc" diff --git a/tests/testdata/control_files/app/expected_edit_delaunay_refinement/expected_delaunay.2dm b/tests/testdata/control_files/app/expected_edit_delaunay_refinement/expected_delaunay.2dm new file mode 100644 index 000000000000..bee99533d8ac --- /dev/null +++ b/tests/testdata/control_files/app/expected_edit_delaunay_refinement/expected_delaunay.2dm @@ -0,0 +1,21 @@ +MESH2D +ND 1 2.50000000e+00 2.00000000e+00 0 +ND 2 3.00000000e+00 7.50000000e+00 0 +ND 3 8.00000000e+00 2.50000000e+00 0 +ND 4 1.50000000e+00 2.50000000e+00 0 +ND 5 1.50000000e+00 0.00000000e+00 0 +ND 6 8.00000000e+00 0.00000000e+00 0 +ND 7 7.50000000e+00 7.50000000e+00 0 +ND 8 1.00000000e+01 0.00000000e+00 0 +ND 9 9.50000000e+00 3.50000000e+00 0 +ND 10 4.49476987e+00 3.49895397e+00 0 +E4Q 1 6 3 1 5 +E3T 2 6 8 3 +E3T 3 7 3 8 +E3T 4 8 9 7 +E3T 5 10 1 3 +E3T 6 10 2 1 +E3T 7 10 7 2 +E3T 8 7 10 3 +E3T 9 4 1 2 +E3T 10 1 4 5 diff --git a/tests/testdata/control_files/app/expected_edit_no_delaunay_refinement/expected_not_delaunay.2dm b/tests/testdata/control_files/app/expected_edit_no_delaunay_refinement/expected_not_delaunay.2dm new file mode 100644 index 000000000000..bfd241f3dc3a --- /dev/null +++ b/tests/testdata/control_files/app/expected_edit_no_delaunay_refinement/expected_not_delaunay.2dm @@ -0,0 +1,21 @@ +MESH2D +ND 1 2.50000000e+00 2.00000000e+00 0 +ND 2 3.00000000e+00 7.50000000e+00 0 +ND 3 8.00000000e+00 2.50000000e+00 0 +ND 4 1.50000000e+00 2.50000000e+00 0 +ND 5 1.50000000e+00 0.00000000e+00 0 +ND 6 8.00000000e+00 0.00000000e+00 0 +ND 7 7.50000000e+00 7.50000000e+00 0 +ND 8 1.00000000e+01 0.00000000e+00 0 +ND 9 9.50000000e+00 3.50000000e+00 0 +ND 10 4.49476987e+00 3.49895397e+00 0 +E3T 1 2 5 1 +E3T 2 2 4 5 +E4Q 3 6 3 1 5 +E3T 4 3 7 2 +E3T 5 6 8 3 +E3T 6 7 3 8 +E3T 7 8 9 7 +E3T 8 10 1 3 +E3T 9 10 3 2 +E3T 10 10 2 1 diff --git a/tests/testdata/mesh/not_delaunay.2dm b/tests/testdata/mesh/not_delaunay.2dm new file mode 100644 index 000000000000..71a95ea43144 --- /dev/null +++ b/tests/testdata/mesh/not_delaunay.2dm @@ -0,0 +1,18 @@ +MESH2D +ND 1 2.5 2 0 +ND 2 3 7.5 0 +ND 3 8 2.5 0 +ND 4 1.5 2.5 0 +ND 5 1.5 0 0 +ND 6 8 0 0 +ND 7 7.5 7.5 0 +ND 8 10 0 0 +ND 9 9.5 3.5 0 +E3T 1 1 3 2 +E3T 2 2 5 1 +E3T 3 2 4 5 +E4Q 4 6 3 1 5 +E3T 5 3 7 2 +E3T 6 6 8 3 +E3T 7 7 3 8 +E3T 8 8 9 7 From d5849ab756c0b7f7a20b73075ad3ef95c49168a7 Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Mon, 23 Dec 2024 16:12:36 +0100 Subject: [PATCH 11/18] fix docstring Co-authored-by: Stefanos Natsis --- src/core/mesh/qgsmesheditor.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/mesh/qgsmesheditor.h b/src/core/mesh/qgsmesheditor.h index 92a4e137be7d..258ec9556678 100644 --- a/src/core/mesh/qgsmesheditor.h +++ b/src/core/mesh/qgsmesheditor.h @@ -307,6 +307,7 @@ class CORE_EXPORT QgsMeshEditor : public QObject /** * Add a vertex in a face with Delaunay refinement of neighboring faces + * All neighboring faces sharing a vertex will be refined to satisfy the Delaunay condition * * \since QGIS 3.42 */ From 9aacd8306494b76ccfe066c62bbf76aabdeba47c Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Mon, 23 Dec 2024 16:13:20 +0100 Subject: [PATCH 12/18] remove pass by reference Co-authored-by: Stefanos Natsis --- src/core/mesh/qgsmesheditor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/mesh/qgsmesheditor.h b/src/core/mesh/qgsmesheditor.h index 258ec9556678..975243eeb5db 100644 --- a/src/core/mesh/qgsmesheditor.h +++ b/src/core/mesh/qgsmesheditor.h @@ -311,7 +311,7 @@ class CORE_EXPORT QgsMeshEditor : public QObject * * \since QGIS 3.42 */ - void addVertexWithDelaunayRefinement( const QgsMeshVertex vertex, const double tolerance ); + void addVertexWithDelaunayRefinement( const QgsMeshVertex &vertex, const double tolerance ); signals: //! Emitted when the mesh is edited From 988fe45cc92dce838a5c1d0af86e61443f4ffff6 Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Mon, 23 Dec 2024 16:13:40 +0100 Subject: [PATCH 13/18] pass by reference Co-authored-by: Stefanos Natsis --- src/core/mesh/qgsmesheditor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/mesh/qgsmesheditor.h b/src/core/mesh/qgsmesheditor.h index 975243eeb5db..e3cce8605983 100644 --- a/src/core/mesh/qgsmesheditor.h +++ b/src/core/mesh/qgsmesheditor.h @@ -673,7 +673,7 @@ class QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement: public QgsMe public: //! Constructor with the associated \a meshEditor and indexes \a vertex and \a tolerance - QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement( QgsMeshEditor *meshEditor, const QgsMeshVertex vertex, double tolerance ); + QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement( QgsMeshEditor *meshEditor, const QgsMeshVertex &vertex, double tolerance ); void redo() override; private: From 0fd2e872d70e2753166e2e85f7c029c021a7a604 Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Mon, 23 Dec 2024 15:24:33 +0100 Subject: [PATCH 14/18] fix label, add tooltip --- src/app/mesh/qgsmaptooleditmeshframe.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/mesh/qgsmaptooleditmeshframe.cpp b/src/app/mesh/qgsmaptooleditmeshframe.cpp index 84569cb64dc1..58eb72c4e5a8 100644 --- a/src/app/mesh/qgsmaptooleditmeshframe.cpp +++ b/src/app/mesh/qgsmaptooleditmeshframe.cpp @@ -238,7 +238,8 @@ QgsMeshEditDigitizingAction::QgsMeshEditDigitizingAction( QObject *parent ) int interpolateFromValue = settings.enumValue( QStringLiteral( "UI/Mesh/zValueFrom" ), PreferMeshThenZWidget ); mComboZValueType->setCurrentIndex( interpolateFromValue ); - mCheckBoxRefineNeighboringFaces = new QCheckBox( tr( "On add vertex in face refine neighboring faces" ) ); + mCheckBoxRefineNeighboringFaces = new QCheckBox( tr( "Refine neighboring faces when adding vertices" ) ); + mCheckBoxRefineNeighboringFaces->setToolTip( "Flip edges that do not fulfil delaunay rule on triangular faces that share at least one vertex with the face that new vertex was added to." ); bool refineNeighboringFaces = settings.value( QStringLiteral( "UI/Mesh/refineNeighboringFaces" ) ).toBool(); mCheckBoxRefineNeighboringFaces->setChecked( refineNeighboringFaces ); From 173752acc61c071a7e500211414bdc9b25e8bfb8 Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Mon, 23 Dec 2024 16:38:17 +0100 Subject: [PATCH 15/18] avoid brute forcing through faces, use review suggestion instead --- src/core/mesh/qgsmesheditor.cpp | 69 ++++++++------------------------- src/core/mesh/qgsmesheditor.h | 3 +- 2 files changed, 17 insertions(+), 55 deletions(-) diff --git a/src/core/mesh/qgsmesheditor.cpp b/src/core/mesh/qgsmesheditor.cpp index cf4a3f083ae0..e798f3a36168 100644 --- a/src/core/mesh/qgsmesheditor.cpp +++ b/src/core/mesh/qgsmesheditor.cpp @@ -1512,7 +1512,7 @@ void QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement::redo() mMeshEditor->applyAddVertex( edit, mVertex, mTolerance ); mEdits.append( edit ); - QList> sharedEdges = innerEdges( triangularFaces( facesContainingVertex( mMeshEditor->topologicalMesh().mesh()->vertexCount() - 1 ) ) ); + QList> sharedEdges = innerEdges( secondNeighboringTriangularFaces() ); //innerEdges( triangularFaces( candidateFacesForRefinement( mMeshEditor->topologicalMesh().mesh()->vertexCount() - 1 ) ) ); for ( std::pair edge : sharedEdges ) { @@ -1532,68 +1532,31 @@ void QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement::redo() } } -QSet QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement::facesContainingVertex( const int vertexId ) +QSet QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement::secondNeighboringTriangularFaces() { - QList facesAroundVertex; - - for ( int i = 0; i < mMeshEditor->topologicalMesh().mesh()->faceCount(); i++ ) + const int vIndex = mMeshEditor->topologicalMesh().mesh()->vertexCount() - 1; + const QList firstNeighborFaces = mMeshEditor->topologicalMesh().facesAroundVertex( vIndex ); + QSet firstNeighborVertices; + for ( int face : firstNeighborFaces ) { - QgsMeshFace face = mMeshEditor->topologicalMesh().mesh()->face( i ); - - if ( face.contains( vertexId ) ) + const QgsMeshFace meshFace = mMeshEditor->topologicalMesh().mesh()->face( face ); + for ( int vertex : meshFace ) { - facesAroundVertex.push_back( i ); + firstNeighborVertices.insert( vertex ); } } - QSet vertexIndexes; - - for ( int faceIndex : facesAroundVertex ) + QSet secondNeighboringFaces; + for ( int vertex : firstNeighborVertices ) { - QgsMeshFace face = mMeshEditor->topologicalMesh().mesh()->face( faceIndex ); - - for ( int i = 0; i < face.count(); i++ ) + const QList faces = mMeshEditor->topologicalMesh().facesAroundVertex( vertex ); + for ( int face : faces ) { - vertexIndexes.insert( face.at( i ) ); + if ( mMeshEditor->topologicalMesh().mesh()->face( face ).count() == 3 ) + secondNeighboringFaces.insert( face ); } } - - // faces that have at least one common vertex with newly added faces - QSet selectedFaces; - - for ( int i = 0; i < mMeshEditor->topologicalMesh().mesh()->faceCount(); i++ ) - { - const QgsMeshFace face = mMeshEditor->topologicalMesh().mesh()->face( i ); - - for ( int j = 0; j < face.count(); j++ ) - { - for ( int vertex : vertexIndexes ) - { - if ( face.contains( vertex ) ) - { - selectedFaces.insert( i ); - break; - } - } - } - } - return selectedFaces; -} - - -QSet QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement::triangularFaces( const QSet &faces ) -{ - QSet triangularFaces; - - for ( int faceIndex : faces ) - { - if ( mMeshEditor->topologicalMesh().mesh()->face( faceIndex ).count() == 3 ) - { - triangularFaces.insert( faceIndex ); - } - } - - return triangularFaces; + return secondNeighboringFaces; } QList> QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement::innerEdges( const QSet &faces ) diff --git a/src/core/mesh/qgsmesheditor.h b/src/core/mesh/qgsmesheditor.h index e3cce8605983..72cfd9edd12d 100644 --- a/src/core/mesh/qgsmesheditor.h +++ b/src/core/mesh/qgsmesheditor.h @@ -677,9 +677,8 @@ class QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement: public QgsMe void redo() override; private: - QSet facesContainingVertex( const int vertexId ); - QSet triangularFaces( const QSet &faces ); QList> innerEdges( const QSet &faces ); + QSet secondNeighboringTriangularFaces(); QgsMeshVertex mVertex; double mTolerance; From 564fcfec96bdef7a38ea4160b9fb55853685cba7 Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Mon, 23 Dec 2024 16:40:11 +0100 Subject: [PATCH 16/18] add pass by reference --- src/core/mesh/qgsmesheditor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/mesh/qgsmesheditor.cpp b/src/core/mesh/qgsmesheditor.cpp index e798f3a36168..5849d7e26603 100644 --- a/src/core/mesh/qgsmesheditor.cpp +++ b/src/core/mesh/qgsmesheditor.cpp @@ -640,7 +640,7 @@ QgsMeshEditingError QgsMeshEditor::removeFaces( const QList &facesToRemove return error; } -void QgsMeshEditor::addVertexWithDelaunayRefinement( const QgsMeshVertex vertex, const double tolerance ) +void QgsMeshEditor::addVertexWithDelaunayRefinement( const QgsMeshVertex &vertex, const double tolerance ) { int triangleIndex = mTriangularMesh->faceIndexForPoint_v2( vertex ); if ( triangleIndex == -1 ) @@ -1494,7 +1494,7 @@ void QgsMeshLayerUndoCommandAdvancedEditing::redo() QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement::QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement( QgsMeshEditor *meshEditor, - const QgsMeshVertex vertex, + const QgsMeshVertex &vertex, double tolerance ) : QgsMeshLayerUndoCommandMeshEdit( meshEditor ) , mVertex( vertex ) From be13eef46ca8430f86ad2f5708be645f73599f5c Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Mon, 23 Dec 2024 17:01:48 +0100 Subject: [PATCH 17/18] sipify --- python/PyQt6/core/auto_generated/mesh/qgsmesheditor.sip.in | 3 ++- python/core/auto_generated/mesh/qgsmesheditor.sip.in | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/python/PyQt6/core/auto_generated/mesh/qgsmesheditor.sip.in b/python/PyQt6/core/auto_generated/mesh/qgsmesheditor.sip.in index 40724d000529..c01dbfcb8acc 100644 --- a/python/PyQt6/core/auto_generated/mesh/qgsmesheditor.sip.in +++ b/python/PyQt6/core/auto_generated/mesh/qgsmesheditor.sip.in @@ -262,9 +262,10 @@ Returns the count of valid vertices, that is non void vertices in the mesh Returns the maximum count of vertices per face that the mesh can support %End - void addVertexWithDelaunayRefinement( const QgsMeshVertex vertex, const double tolerance ); + void addVertexWithDelaunayRefinement( const QgsMeshVertex &vertex, const double tolerance ); %Docstring Add a vertex in a face with Delaunay refinement of neighboring faces +All neighboring faces sharing a vertex will be refined to satisfy the Delaunay condition .. versionadded:: 3.42 %End diff --git a/python/core/auto_generated/mesh/qgsmesheditor.sip.in b/python/core/auto_generated/mesh/qgsmesheditor.sip.in index 40724d000529..c01dbfcb8acc 100644 --- a/python/core/auto_generated/mesh/qgsmesheditor.sip.in +++ b/python/core/auto_generated/mesh/qgsmesheditor.sip.in @@ -262,9 +262,10 @@ Returns the count of valid vertices, that is non void vertices in the mesh Returns the maximum count of vertices per face that the mesh can support %End - void addVertexWithDelaunayRefinement( const QgsMeshVertex vertex, const double tolerance ); + void addVertexWithDelaunayRefinement( const QgsMeshVertex &vertex, const double tolerance ); %Docstring Add a vertex in a face with Delaunay refinement of neighboring faces +All neighboring faces sharing a vertex will be refined to satisfy the Delaunay condition .. versionadded:: 3.42 %End From a7ec33dcc9b2c00fdfe45780c2d88878ee1e68af Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Tue, 24 Dec 2024 09:50:10 +0100 Subject: [PATCH 18/18] remove leftover --- src/core/mesh/qgsmesheditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/mesh/qgsmesheditor.cpp b/src/core/mesh/qgsmesheditor.cpp index 5849d7e26603..79d520d27519 100644 --- a/src/core/mesh/qgsmesheditor.cpp +++ b/src/core/mesh/qgsmesheditor.cpp @@ -1512,7 +1512,7 @@ void QgsMeshLayerUndoCommandAddVertexInFaceWithDelaunayRefinement::redo() mMeshEditor->applyAddVertex( edit, mVertex, mTolerance ); mEdits.append( edit ); - QList> sharedEdges = innerEdges( secondNeighboringTriangularFaces() ); //innerEdges( triangularFaces( candidateFacesForRefinement( mMeshEditor->topologicalMesh().mesh()->vertexCount() - 1 ) ) ); + QList> sharedEdges = innerEdges( secondNeighboringTriangularFaces() ); for ( std::pair edge : sharedEdges ) {