Skip to content
Permalink
Browse files
Make mesh edit tools more consistent with vector layers tools (#45040)
[mesh] UX fixes:
* move mesh elements click->move->click instead press-> drag->release
* allow to select by drawing a polygon and select an existing polygon in the same map tool like for vector layer)
  • Loading branch information
vcloarec committed Sep 14, 2021
1 parent 6f1deb6 commit 176ab296587b015dab98efea54a593856d0ead6b
@@ -928,8 +928,6 @@
<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>

This file was deleted.

This file was deleted.

@@ -55,7 +55,7 @@ Removes all data provided to the editing or created by the editing
virtual bool isFinished() const;
%Docstring
Returns whether the advanced edit is finished,
if not, tis edit has to be applied again with :py:func:`QgsMeshEditor.advancedEdit()` until is finished returns ``True``
if not, this edit has to be applied again with :py:func:`QgsMeshEditor.advancedEdit()` until is finished returns ``True``
%End

protected:

Large diffs are not rendered by default.

@@ -37,7 +37,7 @@ class QgsMeshTransformCoordinatesDockWidget;
class QComboBox;
class QCheckBox;
class QgsUnitSelectionWidget;

class QgsMapToolSelectionHandler;


class QgsExpressionBuilderWidget;
@@ -109,8 +109,6 @@ class QgsMeshEditForceByLineAction : public QWidgetAction
QCheckBox *mCheckBoxNewVertex = nullptr;
QgsUnitSelectionWidget *mUnitSelecionWidget = nullptr;
QgsDoubleSpinBox *mToleranceSpinBox = nullptr;


};

class APP_EXPORT QgsMapToolEditMeshFrame : public QgsMapToolAdvancedDigitizing
@@ -164,8 +162,6 @@ 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();
@@ -177,7 +173,7 @@ 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
MovingSelection, //!< Moving vertex or vertices is processing
SelectingByPolygon, //!< Selection elements by polygon is in progress
};

@@ -234,9 +230,11 @@ class APP_EXPORT QgsMapToolEditMeshFrame : public QgsMapToolAdvancedDigitizing
void applyZValueOnSelectedVertices();
void prepareSelection();
void updateSelectecVerticesMarker();
void moveSelection( const QgsPointXY &destinationPoint );
void clearSelection();

void setMovingRubberBandValidity( bool valid );
bool isSelectionGrapped( QgsPointXY &grappedPoint );

QList<QgsGeometry> selectedGeometriesInVectorLayers() const;
bool areGeometriesSelectedInVectorLayer() const;
@@ -262,7 +260,7 @@ class APP_EXPORT QgsMapToolEditMeshFrame : public QgsMapToolAdvancedDigitizing
int mCurrentVertexIndex = -1;
QList<int> mNewFaceCandidate;
bool mDoubleClicks = false;
QgsPointXY mLastClickPoint;
QgsPointXY mFirstClickPoint; //the first click point when double clicks, we need it when the point is constraint by the cad tool, second click could not be constraint
double mOrdinaryZValue = 0;
bool mIsSelectedZValue = false;
double mSelectedZValue = 0;
@@ -295,10 +293,6 @@ class APP_EXPORT QgsMapToolEditMeshFrame : public QgsMapToolAdvancedDigitizing
QgsVertexMarker *mSelectEdgeMarker = nullptr; //own by map canvas
QgsRubberBand *mSelectionBand = nullptr; //own by map canvas
QPoint mStartSelectionPos;
QColor mSelectionBandPartiallyFillColor = QColor( 0, 215, 120, 63 );
QColor mSelectionBandPartiallyStrokeColor = QColor( 0, 204, 102, 100 );
QColor mSelectionBandTotalFillColor = QColor( 0, 120, 215, 63 );
QColor mSelectionBandTotalStrokeColor = QColor( 0, 102, 204, 100 );
QgsRubberBand *mSelectedFacesRubberband = nullptr; //own by map canvas
QMap< int, QgsVertexMarker * > mSelectedVerticesMarker;

@@ -307,6 +301,7 @@ class APP_EXPORT QgsMapToolEditMeshFrame : public QgsMapToolAdvancedDigitizing
bool mCanMovingStart = false;
QgsRubberBand *mMovingEdgesRubberband = nullptr; //own by map canvas
QgsRubberBand *mMovingFacesRubberband = nullptr; //own by map canvas
QgsRubberBand *mMovingFreeVertexRubberband = nullptr; //own by map canvas
bool mIsMovingAllowed = false;

//! members for edge flip
@@ -332,14 +327,14 @@ class APP_EXPORT QgsMapToolEditMeshFrame : public QgsMapToolAdvancedDigitizing
QAction *mActionFacesRefinement = nullptr;

QAction *mActionDigitizing = nullptr;

QAction *mActionSelectByPolygon = nullptr;
std::unique_ptr<QgsMapToolSelectionHandler> mSelectionHandler;

QAction *mActionTransformCoordinates = nullptr;

QAction *mActionSelectByExpression = nullptr;
QAction *mActionForceByVectorLayerGeometries = nullptr;
QAction *mActionSelectByContainingSelectedPolygon = nullptr;
QAction *mActionSelectByTouchingSelectedPolygon = nullptr;

QgsMeshEditForceByLineAction *mWidgetActionForceByLine = nullptr;
QAction *mActionReindexMesh = nullptr;
@@ -58,7 +58,7 @@ class CORE_EXPORT QgsMeshAdvancedEditing : protected QgsTopologicalMesh::Changes

/**
* Returns whether the advanced edit is finished,
* if not, tis edit has to be applied again with QgsMeshEditor::advancedEdit() until is finished returns TRUE
* if not, this edit has to be applied again with QgsMeshEditor::advancedEdit() until is finished returns TRUE
*/
virtual bool isFinished() const;

@@ -528,9 +528,9 @@ void QgsMeshEditor::changeZValues( const QList<int> &verticesIndexes, const QLis
mUndoStack->push( new QgsMeshLayerUndoCommandChangeZValue( this, verticesIndexes, newZValues ) );
}

bool QgsMeshEditor::canBeTransformed( const QList<int> &transformedFaces, const std::function<const QgsMeshVertex( int )> &transformFunction ) const
bool QgsMeshEditor::canBeTransformed( const QList<int> &facesToCheck, const std::function<const QgsMeshVertex( int )> &transformFunction ) const
{
for ( const int faceIndex : transformedFaces )
for ( const int faceIndex : facesToCheck )
{
const QgsMeshFace &face = mMesh->face( faceIndex );
int faceSize = face.count();
@@ -560,7 +560,7 @@ bool QgsMeshEditor::canBeTransformed( const QList<int> &transformedFaces, const

const QgsGeometry &deformedFace = QgsGeometry::fromPolygonXY( {points} );

// now test if the deformed face contain something else (search canditate <ith the
// now test if the deformed face contain something else
QList<int> otherFaceIndexes =
mTriangularMesh->nativeFaceIndexForRectangle( QgsGeometry::fromPolygonXY( {pointsInTriangularMeshCoordinate} ).boundingBox() );

@@ -579,7 +579,7 @@ bool QgsMeshEditor::canBeTransformed( const QList<int> &transformedFaces, const
}
if ( shareVertex )
{
//only test the edge that not contain a shared vertex
//only test the edge that not contains a shared vertex
for ( int i = 0; i < existingFaceSize; ++i )
{
int index1 = otherFace.at( i );
@@ -605,7 +605,6 @@ bool QgsMeshEditor::canBeTransformed( const QList<int> &transformedFaces, const
}
}

//finish with free vertices...
const QList<int> freeVerticesIndex = freeVerticesIndexes();
for ( const int vertexIndex : freeVerticesIndex )
{
@@ -615,6 +614,31 @@ bool QgsMeshEditor::canBeTransformed( const QList<int> &transformedFaces, const
}
}

// free vertices
const QList<int> freeVerticesIndex = freeVerticesIndexes();
for ( const int vertexIndex : freeVerticesIndex )
{
const QgsMeshVertex &newFreeVertexPosition = transformFunction( vertexIndex ); // transformed free vertex
const QgsMeshVertex pointInTriangularCoord = mTriangularMesh->nativeToTriangularCoordinates( newFreeVertexPosition );
const int originalIncludingFace = mTriangularMesh->nativeFaceIndexForPoint( pointInTriangularCoord );

if ( originalIncludingFace != -1 )
{
// That means two things: the free vertex is moved AND is included in a face before transform
// Before returning false, we need to check if the vertex is still in the face after transform
const QgsMeshFace &face = mMesh->face( originalIncludingFace );
int faceSize = face.count();
QVector<QgsPointXY> points( faceSize );
for ( int i = 0; i < faceSize; ++i )
points[i] = transformFunction( face.at( i ) );

const QgsGeometry &deformedFace = QgsGeometry::fromPolygonXY( {points} );
const QgsPointXY ptXY( newFreeVertexPosition );
if ( deformedFace.contains( &ptXY ) )
return false;
}
}

return true;
}

@@ -161,8 +161,12 @@ class CORE_EXPORT QgsMeshEditor : public QObject
*
* The transform function takes a vertex index in parameter and return a QgsMeshVertex object with transformed coordinates.
* This transformation is done in layer coordinates
*
* \note Even only the faces with indexes in \a transformdFaces are checked to avoid testing all the mesh,
* all the mesh are supposed to path through this transform function (but it is possible that transform function is not able to transform all vertices).
* Moving free vertices of the mesh are also checked.
*/
bool canBeTransformed( const QList<int> &transformedFaces, const std::function<const QgsMeshVertex( int )> &transformFunction ) const; SIP_SKIP
bool canBeTransformed( const QList<int> &facesToCheck, const std::function<const QgsMeshVertex( int )> &transformFunction ) const; SIP_SKIP

/**
* Changes the (X,Y) coordinates values of the vertices with indexes in \a vertices indexes with the values in \a newValues.

0 comments on commit 176ab29

Please sign in to comment.