34 : QObject( meshLayer )
35 , mMesh( meshLayer ? meshLayer->nativeMesh() : nullptr )
36 , mTriangularMesh( meshLayer ? meshLayer->triangularMeshByLodIndex( 0 ) : nullptr )
37 , mUndoStack( meshLayer ? meshLayer->undoStack() : nullptr )
49 , mTriangularMesh( triangularMesh )
51 mUndoStack =
new QUndoStack(
this );
57 std::unique_ptr<QgsMeshDatasetGroup> zValueDatasetGroup = std::make_unique<QgsMeshVerticesElevationDatasetGroup>( tr(
"vertices Z value" ), mMesh );
58 mZValueDatasetGroup = zValueDatasetGroup.get();
59 return zValueDatasetGroup.release();
82 geomEngine->prepareGeometry();
85 QList<int> newFaceVerticesIndexes( face.toList() );
86 int newFaceSize = face.count();
88 if ( !concernedFaceIndex.isEmpty() )
92 for (
const int faceIndex : concernedFaceIndex )
95 int existingFaceSize = existingFace.count();
96 bool shareVertex =
false;
97 for (
int i = 0; i < existingFaceSize; ++i )
99 if ( newFaceVerticesIndexes.contains( existingFace.at( i ) ) )
108 for (
int i = 0; i < existingFaceSize; ++i )
110 int index1 = existingFace.at( i );
111 int index2 = existingFace.at( ( i + 1 ) % existingFaceSize );
116 if ( ! newFaceVerticesIndexes.contains( index1 ) && !newFaceVerticesIndexes.contains( index2 ) )
119 if ( geomEngine->intersects( edgeGeom.
constGet() ) )
124 for (
int vi = 0; vi < newFaceVerticesIndexes.count(); ++vi )
126 int vertInNewFace1 = newFaceVerticesIndexes.at( vi );
127 int vertInNewFace2 = newFaceVerticesIndexes.at( ( vi + 1 ) % newFaceSize );
128 if ( vertInNewFace1 != index1 && vertInNewFace2 != index2 && vertInNewFace1 != index2 && vertInNewFace2 != index1 )
144 if ( geomEngine->intersects( existingFaceGeom.
constGet() ) )
153 for (
const int freeVertexIndex : freeVertices )
155 if ( newFaceVerticesIndexes.contains( freeVertexIndex ) )
159 if ( geomEngine->contains( &vertex ) )
172 QVector<QgsMeshFace> facesToAdd = prepareFaces( {face}, error );
192 void QgsMeshEditor::applyEdit( QgsMeshEditor::Edit &edit )
194 mTopologicalMesh.
applyChanges( edit.topologicalChanges );
195 mTriangularMesh->
applyChanges( edit.triangularMeshChanges );
197 if ( mZValueDatasetGroup &&
198 ( !edit.topologicalChanges.newVerticesZValues().isEmpty() ||
199 !edit.topologicalChanges.verticesToRemoveIndexes().isEmpty() ||
200 !edit.topologicalChanges.addedVertices().isEmpty() ) )
203 updateElementsCount( edit.topologicalChanges );
206 void QgsMeshEditor::reverseEdit( QgsMeshEditor::Edit &edit )
209 mTriangularMesh->
reverseChanges( edit.triangularMeshChanges, *mMesh );
211 if ( mZValueDatasetGroup &&
212 ( !edit.topologicalChanges.newVerticesZValues().isEmpty() ||
213 !edit.topologicalChanges.verticesToRemoveIndexes().isEmpty() ||
214 !edit.topologicalChanges.addedVertices().isEmpty() ) )
217 updateElementsCount( edit.topologicalChanges,
false );
220 void QgsMeshEditor::applyAddVertex( QgsMeshEditor::Edit &edit,
const QgsMeshVertex &vertex,
double tolerance )
225 int faceEdgeIntersect = -1;
226 int edgePosition = -1;
230 if (
edgeIsClose( vertexInTriangularCoordinate, tolerance, faceEdgeIntersect, edgePosition ) )
238 if ( includingFaceIndex != -1 )
239 topologicChanges = mTopologicalMesh.
addVertexInFace( includingFaceIndex, vertex );
244 applyEditOnTriangularMesh( edit, topologicChanges );
246 if ( mZValueDatasetGroup )
249 updateElementsCount( edit.topologicalChanges );
252 bool QgsMeshEditor::applyRemoveVertexFillHole( QgsMeshEditor::Edit &edit,
int vertexIndex )
258 applyEditOnTriangularMesh( edit, changes );
260 if ( mZValueDatasetGroup )
263 updateElementsCount( edit.topologicalChanges );
270 void QgsMeshEditor::applyRemoveVerticesWithoutFillHole( QgsMeshEditor::Edit &edit,
const QList<int> &verticesIndexes )
272 applyEditOnTriangularMesh( edit, mTopologicalMesh.
removeVertices( verticesIndexes ) );
274 if ( mZValueDatasetGroup )
277 updateElementsCount( edit.topologicalChanges );
282 applyEditOnTriangularMesh( edit, mTopologicalMesh.
addFaces( faces ) );
284 updateElementsCount( edit.topologicalChanges );
287 void QgsMeshEditor::applyRemoveFaces( QgsMeshEditor::Edit &edit,
const QList<int> &faceToRemoveIndex )
289 applyEditOnTriangularMesh( edit, mTopologicalMesh.
removeFaces( faceToRemoveIndex ) );
291 updateElementsCount( edit.topologicalChanges );
294 void QgsMeshEditor::applyChangeZValue( QgsMeshEditor::Edit &edit,
const QList<int> &verticesIndexes,
const QList<double> &newValues )
296 applyEditOnTriangularMesh( edit, mTopologicalMesh.
changeZValue( verticesIndexes, newValues ) );
298 if ( mZValueDatasetGroup )
302 void QgsMeshEditor::applyChangeXYValue( QgsMeshEditor::Edit &edit,
const QList<int> &verticesIndexes,
const QList<QgsPointXY> &newValues )
304 applyEditOnTriangularMesh( edit, mTopologicalMesh.
changeXYValue( verticesIndexes, newValues ) );
307 void QgsMeshEditor::applyFlipEdge( QgsMeshEditor::Edit &edit,
int vertexIndex1,
int vertexIndex2 )
309 applyEditOnTriangularMesh( edit, mTopologicalMesh.
flipEdge( vertexIndex1, vertexIndex2 ) );
311 updateElementsCount( edit.topologicalChanges );
314 void QgsMeshEditor::applyMerge( QgsMeshEditor::Edit &edit,
int vertexIndex1,
int vertexIndex2 )
316 applyEditOnTriangularMesh( edit, mTopologicalMesh.
merge( vertexIndex1, vertexIndex2 ) );
318 updateElementsCount( edit.topologicalChanges );
321 void QgsMeshEditor::applySplit( QgsMeshEditor::Edit &edit,
int faceIndex )
323 applyEditOnTriangularMesh( edit, mTopologicalMesh.
splitFace( faceIndex ) );
325 updateElementsCount( edit.topologicalChanges );
330 applyEditOnTriangularMesh( edit, editing->
apply(
this ) );
332 updateElementsCount( edit.topologicalChanges );
334 if ( mZValueDatasetGroup )
343 edit.topologicalChanges = topologicChanges;
344 edit.triangularMeshChanges = triangularChanges;
390 point.
y() - tolerance,
391 point.
x() + tolerance,
392 point.
y() + tolerance );
395 double minDist = std::numeric_limits<double>::max();
397 double epsilon = std::numeric_limits<double>::epsilon() * tolerance;
398 for (
const int nativeFaceIndex : nativeFaces )
401 const int faceSize = face.size();
402 for (
int i = 0; i < faceSize; ++i )
418 if ( dist < tolerance && dist < minDist )
420 faceIndex = nativeFaceIndex;
427 if ( edgePosition != -1 )
436 return mValidFacesCount;
441 return mValidVerticesCount;
446 return mMaximumVerticesPerFace;
475 return mTopologicalMesh.
canBeMerged( vertexIndex1, vertexIndex2 );
488 return mTopologicalMesh.
canBeSplit( faceIndex );
493 QList<int> faceIndexesSplittable;
495 for (
const int faceIndex : faceIndexes )
497 faceIndexesSplittable.append( faceIndex );
499 if ( faceIndexesSplittable.isEmpty() )
504 return faceIndexesSplittable.count();
507 QVector<QgsMeshFace> QgsMeshEditor::prepareFaces(
const QVector<QgsMeshFace> &faces,
QgsMeshEditingError &error )
509 QVector<QgsMeshFace> treatedFaces = faces;
513 for (
int i = 0; i < treatedFaces.count(); ++i )
516 if ( mMaximumVerticesPerFace != 0 && face.count() > mMaximumVerticesPerFace )
533 QVector<QgsMeshFace> facesToAdd = prepareFaces( faces, error );
557 QVector<QgsMeshVertex> verticesInLayerCoordinate( vertices.count() );
558 int ignoredVertex = 0;
559 for (
int i = 0; i < vertices.count(); ++i )
561 const QgsPointXY &pointInTriangularMesh = vertices.at( i );
562 bool isTooClose =
false;
564 if ( triangleIndex != -1 )
567 for (
int j = 0; j < 3; ++j )
570 double dist = pointInTriangularMesh.
distance( facePoint );
571 if ( dist < tolerance )
584 if ( verticesInLayerCoordinate.at( i ).isEmpty() )
588 if ( ignoredVertex < vertices.count() )
593 int effectivlyAddedVertex = vertices.count() - ignoredVertex;
595 return effectivlyAddedVertex;
607 QList<int> verticesIndexes = verticesToRemoveIndexes;
609 QSet<int> concernedNativeFaces;
610 for (
const int vi : std::as_const( verticesIndexes ) )
611 concernedNativeFaces.unite( qgis::listToSet( mTopologicalMesh.
facesAroundVertex( vi ) ) );
624 QList<int> remainingVertices;
627 return remainingVertices;
638 for (
const int faceIndex : facesToCheck )
641 int faceSize = face.count();
642 QVector<QgsPointXY> pointsInTriangularMeshCoordinate( faceSize );
643 QVector<QgsPointXY> points( faceSize );
644 for (
int i = 0; i < faceSize; ++i )
647 int ip1 = face[( i + 1 ) % faceSize];
648 int ip2 = face[( i + 2 ) % faceSize];
654 double ux = p0.x() - p1.
x();
655 double uy = p0.y() - p1.
y();
656 double vx = p2.
x() - p1.
x();
657 double vy = p2.
y() - p1.
y();
659 double crossProduct = ux * vy - uy * vx;
660 if ( crossProduct >= 0 )
669 QList<int> otherFaceIndexes =
672 for (
const int otherFaceIndex : otherFaceIndexes )
675 int existingFaceSize = otherFace.count();
676 bool shareVertex =
false;
677 for (
int i = 0; i < existingFaceSize; ++i )
679 if ( face.contains( otherFace.at( i ) ) )
688 for (
int i = 0; i < existingFaceSize; ++i )
690 int index1 = otherFace.at( i );
691 int index2 = otherFace.at( ( i + 1 ) % existingFaceSize );
692 if ( ! face.contains( index1 ) && !face.contains( index2 ) )
694 const QgsPointXY &v1 = transformFunction( index1 );
695 const QgsPointXY &v2 = transformFunction( index2 );
704 QVector<QgsPointXY> otherPoints( existingFaceSize );
705 for (
int i = 0; i < existingFaceSize; ++i )
706 otherPoints[i] = transformFunction( otherFace.at( i ) );
708 if ( deformedFace.
intersects( existingFaceGeom ) )
714 for (
const int vertexIndex : freeVerticesIndex )
716 const QgsPointXY &mapPoint = transformFunction( vertexIndex );
717 if ( deformedFace.
contains( &mapPoint ) )
724 for (
const int vertexIndex : freeVerticesIndex )
726 const QgsMeshVertex &newFreeVertexPosition = transformFunction( vertexIndex );
730 if ( originalIncludingFace != -1 )
735 int faceSize = face.count();
736 QVector<QgsPointXY> points( faceSize );
737 for (
int i = 0; i < faceSize; ++i )
738 points[i] = transformFunction( face.at( i ) );
741 const QgsPointXY ptXY( newFreeVertexPosition );
742 if ( deformedFace.
contains( &ptXY ) )
773 : mMeshEditor( meshEditor )
782 for (
int i =
mEdits.count() - 1; i >= 0; --i )
791 for ( QgsMeshEditor::Edit &edit :
mEdits )
797 , mVertices( vertices )
798 , mTolerance( tolerance )
800 setText( QObject::tr(
"Add %n vertices",
nullptr, mVertices.count() ) );
805 if ( !mVertices.isEmpty() )
807 for (
int i = 0; i < mVertices.count(); ++i )
812 QgsMeshEditor::Edit edit;
813 mMeshEditor->applyAddVertex( edit, vertex, mTolerance );
820 for ( QgsMeshEditor::Edit &edit :
mEdits )
827 const QList<int> &verticesToRemoveIndexes,
828 QList<int> *remainingVerticesPointer )
830 , mVerticesToRemoveIndexes( verticesToRemoveIndexes )
831 , mRemainingVerticesPointer( remainingVerticesPointer )
833 setText( QObject::tr(
"Remove %n vertices filling holes",
nullptr, verticesToRemoveIndexes.count() ) );
838 int initialVertexCount = mVerticesToRemoveIndexes.count();
839 if ( !mVerticesToRemoveIndexes.isEmpty() )
841 QgsMeshEditor::Edit edit;
842 QList<int> vertexToRetry;
843 while ( !mVerticesToRemoveIndexes.isEmpty() )
846 for (
const int &vertex : std::as_const( mVerticesToRemoveIndexes ) )
848 if (
mMeshEditor->applyRemoveVertexFillHole( edit, vertex ) )
851 vertexToRetry.append( vertex );
854 if ( vertexToRetry.count() == mVerticesToRemoveIndexes.count() )
857 mVerticesToRemoveIndexes = vertexToRetry;
860 if ( initialVertexCount == mVerticesToRemoveIndexes.count() )
863 if ( mRemainingVerticesPointer !=
nullptr )
864 *mRemainingVerticesPointer = mVerticesToRemoveIndexes;
866 mRemainingVerticesPointer =
nullptr;
868 mVerticesToRemoveIndexes.clear();
872 for ( QgsMeshEditor::Edit &edit :
mEdits )
880 const QList<int> &verticesToRemoveIndexes )
882 , mVerticesToRemoveIndexes( verticesToRemoveIndexes )
884 setText( QObject::tr(
"Remove %n vertices without filling holes",
nullptr, verticesToRemoveIndexes.count() ) ) ;
889 if ( !mVerticesToRemoveIndexes.isEmpty() )
891 QgsMeshEditor::Edit edit;
893 mMeshEditor->applyRemoveVerticesWithoutFillHole( edit, mVerticesToRemoveIndexes );
896 mVerticesToRemoveIndexes.clear();
900 for ( QgsMeshEditor::Edit &edit :
mEdits )
909 setText( QObject::tr(
"Add %n face(s)",
nullptr, faces.
meshFaces().count() ) );
916 QgsMeshEditor::Edit edit;
924 for ( QgsMeshEditor::Edit &edit :
mEdits )
931 , mfacesToRemoveIndexes( facesToRemoveIndexes )
933 setText( QObject::tr(
"Remove %n face(s)",
nullptr, facesToRemoveIndexes.count() ) );
938 if ( !mfacesToRemoveIndexes.isEmpty() )
940 QgsMeshEditor::Edit edit;
941 mMeshEditor->applyRemoveFaces( edit, mfacesToRemoveIndexes );
944 mfacesToRemoveIndexes.clear();
948 for ( QgsMeshEditor::Edit &edit :
mEdits )
965 return !mUndoStack->isClean();
1016 return mTopologicalMesh;
1021 return mTriangularMesh;
1026 , mVerticesIndexes( verticesIndexes )
1027 , mNewValues( newValues )
1029 setText( QObject::tr(
"Change %n vertices Z Value",
nullptr, verticesIndexes.count() ) );
1034 if ( !mVerticesIndexes.isEmpty() )
1036 QgsMeshEditor::Edit edit;
1037 mMeshEditor->applyChangeZValue( edit, mVerticesIndexes, mNewValues );
1039 mVerticesIndexes.clear();
1044 for ( QgsMeshEditor::Edit &edit :
mEdits )
1051 , mVerticesIndexes( verticesIndexes )
1052 , mNewValues( newValues )
1054 setText( QObject::tr(
"Move %n vertices",
nullptr, verticesIndexes.count() ) );
1059 if ( !mVerticesIndexes.isEmpty() )
1061 QgsMeshEditor::Edit edit;
1062 mMeshEditor->applyChangeXYValue( edit, mVerticesIndexes, mNewValues );
1064 mVerticesIndexes.clear();
1069 for ( QgsMeshEditor::Edit &edit :
mEdits )
1077 , mVerticesIndexes( verticesIndexes )
1078 , mNewCoordinates( newCoordinates )
1080 setText( QObject::tr(
"Transform %n vertices coordinates",
nullptr, verticesIndexes.count() ) );
1085 if ( !mVerticesIndexes.isEmpty() )
1087 QgsMeshEditor::Edit editXY;
1088 QList<QgsPointXY> newXY;
1089 newXY.reserve( mNewCoordinates.count() );
1090 QgsMeshEditor::Edit editZ;
1092 newZ.reserve( mNewCoordinates.count() );
1094 for (
const QgsPoint &pt : std::as_const( mNewCoordinates ) )
1097 newZ.append( pt.z() );
1100 mMeshEditor->applyChangeXYValue( editXY, mVerticesIndexes, newXY );
1102 mMeshEditor->applyChangeZValue( editZ, mVerticesIndexes, newZ );
1104 mVerticesIndexes.clear();
1105 mNewCoordinates.clear();
1109 for ( QgsMeshEditor::Edit &edit :
mEdits )
1118 , mVertexIndex1( vertexIndex1 )
1119 , mVertexIndex2( vertexIndex2 )
1121 setText( QObject::tr(
"Flip edge" ) );
1126 if ( mVertexIndex1 >= 0 && mVertexIndex2 >= 0 )
1128 QgsMeshEditor::Edit edit;
1129 mMeshEditor->applyFlipEdge( edit, mVertexIndex1, mVertexIndex2 );
1136 for ( QgsMeshEditor::Edit &edit :
mEdits )
1143 , mVertexIndex1( vertexIndex1 )
1144 , mVertexIndex2( vertexIndex2 )
1146 setText( QObject::tr(
"Merge faces" ) );
1151 if ( mVertexIndex1 >= 0 && mVertexIndex2 >= 0 )
1153 QgsMeshEditor::Edit edit;
1154 mMeshEditor->applyMerge( edit, mVertexIndex1, mVertexIndex2 );
1161 for ( QgsMeshEditor::Edit &edit :
mEdits )
1168 , mFaceIndexes( faceIndexes )
1170 setText( QObject::tr(
"Split %n face(s)",
nullptr, faceIndexes.count() ) );
1175 if ( !mFaceIndexes.isEmpty() )
1177 for (
int faceIndex : std::as_const( mFaceIndexes ) )
1179 QgsMeshEditor::Edit edit;
1183 mFaceIndexes.clear();
1187 for ( QgsMeshEditor::Edit &edit :
mEdits )
1194 , mAdvancedEditing( advancdEdit )
1196 setText( advancdEdit->
text() );
1201 if ( mAdvancedEditing )
1203 QgsMeshEditor::Edit edit;
1206 mMeshEditor->applyAdvancedEdit( edit, mAdvancedEditing );
1210 mAdvancedEditing =
nullptr;
1214 for ( QgsMeshEditor::Edit &edit :
mEdits )