32 : QObject( meshLayer )
33 , mMesh( meshLayer ? meshLayer->nativeMesh() : nullptr )
34 , mTriangularMesh( meshLayer ? meshLayer->triangularMeshByLodIndex( 0 ) : nullptr )
35 , mUndoStack( meshLayer ? meshLayer->undoStack() : nullptr )
47 , mTriangularMesh( triangularMesh )
49 mUndoStack =
new QUndoStack(
this );
55 std::unique_ptr<QgsMeshDatasetGroup> zValueDatasetGroup = std::make_unique<QgsMeshVerticesElevationDatasetGroup>( tr(
"vertices Z value" ), mMesh );
56 mZValueDatasetGroup = zValueDatasetGroup.get();
57 return zValueDatasetGroup.release();
72 for (
int vi : freeVertices )
100 mTriangularMesh->
update( mMesh );
127 auto faceIt = mMesh->
faces.begin();
128 while ( faceIt != mMesh->
faces.end() )
131 faceIt = mMesh->
faces.erase( faceIt );
157 Q_ASSERT( vertexIndexes.count() == vertices.count() );
159 QVector<QgsPoint> ring;
160 for (
int i = 0; i < vertices.size(); ++i )
162 const QgsPoint &vertex = vertices[i];
163 ring.append( vertex );
165 std::unique_ptr< QgsPolygon > polygon = std::make_unique< QgsPolygon >();
167 const QgsGeometry newFaceGeom( polygon.release() );
169 geomEngine->prepareGeometry();
171 const QgsRectangle boundingBox = newFaceGeom.boundingBox();
172 int newFaceSize = vertexIndexes.count();
174 if ( !concernedFaceIndex.isEmpty() )
178 for (
const int faceIndex : concernedFaceIndex )
181 int existingFaceSize = existingFace.count();
182 bool shareVertex =
false;
183 for (
int i = 0; i < existingFaceSize; ++i )
185 if ( vertexIndexes.contains( existingFace.at( i ) ) )
194 for (
int i = 0; i < existingFaceSize; ++i )
196 int index1 = existingFace.at( i );
197 int index2 = existingFace.at( ( i + 1 ) % existingFaceSize );
202 if ( ! vertexIndexes.contains( index1 ) && !vertexIndexes.contains( index2 ) )
205 if ( geomEngine->intersects( edgeGeom.
constGet() ) )
210 for (
int vi = 0; vi < vertexIndexes.count(); ++vi )
212 int vertInNewFace1 = vertexIndexes.at( vi );
213 int vertInNewFace2 = vertexIndexes.at( ( vi + 1 ) % newFaceSize );
214 bool hasToBeTest =
false;
216 if ( vertInNewFace1 != -1 && vertInNewFace2 != -1 )
218 hasToBeTest = vertInNewFace1 != index1 &&
219 vertInNewFace2 != index2 &&
220 vertInNewFace1 != index2 &&
221 vertInNewFace2 != index1;
225 if ( vertInNewFace1 == -1 )
226 hasToBeTest &= vertInNewFace2 != index1 && vertInNewFace2 != index2;
229 if ( vertInNewFace2 == -1 )
230 hasToBeTest &= vertInNewFace1 != index1 && vertInNewFace1 != index2;
236 const QgsMeshVertex &nv2 = vertices.at( ( vi + 1 ) % newFaceSize );
249 if ( geomEngine->intersects( existingFaceGeom.
constGet() ) )
257 for (
const int freeVertexIndex : freeVertices )
259 if ( vertexIndexes.contains( freeVertexIndex ) )
263 if ( geomEngine->contains( &vertex ) )
272 const QList<int> newFaceVerticesIndexes( face.toList() );
273 QList<QgsMeshVertex> allVertices;
274 allVertices.reserve( face.count() );
276 allVertices.append( mTriangularMesh->
vertices().at( i ) );
288 QVector<QgsMeshFace> facesToAdd = prepareFaces( {face}, error );
311 const QList<int> face = prepareFaceWithNewVertices( verticesIndex, newVertices, error );
313 if ( face.isEmpty() )
322 int size = face.size();
323 QList<QgsMeshVertex> allVertices;
324 allVertices.reserve( verticesIndex.size() );
326 for (
int i = 0; i < size; ++i )
328 int index = face.at( i );
331 if ( newVertPos >= newVertices.count() )
333 allVertices.append( newVertices.at( newVertPos++ ) );
337 allVertices.append( mTriangularMesh->
vertices().at( index ) );
342 int prevIndex = face.at( ( i - 1 + size ) % size );
343 int nextIndex = face.at( ( i + 1 ) % size );
350 if ( prevOppVertex == nextIndex )
357 if ( nextOppVertex == prevIndex )
360 if ( nextIndex != nextOppVertex && prevIndex != prevOppVertex )
367void QgsMeshEditor::applyEdit( QgsMeshEditor::Edit &edit )
369 mTopologicalMesh.
applyChanges( edit.topologicalChanges );
370 mTriangularMesh->
applyChanges( edit.triangularMeshChanges );
372 if ( mZValueDatasetGroup &&
373 ( !edit.topologicalChanges.newVerticesZValues().isEmpty() ||
374 !edit.topologicalChanges.verticesToRemoveIndexes().isEmpty() ||
375 !edit.topologicalChanges.addedVertices().isEmpty() ) )
378 updateElementsCount( edit.topologicalChanges );
381void QgsMeshEditor::reverseEdit( QgsMeshEditor::Edit &edit )
384 mTriangularMesh->
reverseChanges( edit.triangularMeshChanges, *mMesh );
386 if ( mZValueDatasetGroup &&
387 ( !edit.topologicalChanges.newVerticesZValues().isEmpty() ||
388 !edit.topologicalChanges.verticesToRemoveIndexes().isEmpty() ||
389 !edit.topologicalChanges.addedVertices().isEmpty() ) )
392 updateElementsCount( edit.topologicalChanges,
false );
395void QgsMeshEditor::applyAddVertex( QgsMeshEditor::Edit &edit,
const QgsMeshVertex &vertex,
double tolerance )
400 int faceEdgeIntersect = -1;
401 int edgePosition = -1;
405 if (
edgeIsClose( vertexInTriangularCoordinate, tolerance, faceEdgeIntersect, edgePosition ) )
413 if ( includingFaceIndex != -1 )
414 topologicChanges = mTopologicalMesh.
addVertexInFace( includingFaceIndex, vertex );
419 applyEditOnTriangularMesh( edit, topologicChanges );
421 if ( mZValueDatasetGroup )
424 updateElementsCount( edit.topologicalChanges );
427bool QgsMeshEditor::applyRemoveVertexFillHole( QgsMeshEditor::Edit &edit,
int vertexIndex )
433 applyEditOnTriangularMesh( edit, changes );
435 if ( mZValueDatasetGroup )
438 updateElementsCount( edit.topologicalChanges );
445void QgsMeshEditor::applyRemoveVerticesWithoutFillHole( QgsMeshEditor::Edit &edit,
const QList<int> &verticesIndexes )
447 applyEditOnTriangularMesh( edit, mTopologicalMesh.
removeVertices( verticesIndexes ) );
449 if ( mZValueDatasetGroup )
452 updateElementsCount( edit.topologicalChanges );
457 applyEditOnTriangularMesh( edit, mTopologicalMesh.
addFaces( faces ) );
459 updateElementsCount( edit.topologicalChanges );
462void QgsMeshEditor::applyRemoveFaces( QgsMeshEditor::Edit &edit,
const QList<int> &faceToRemoveIndex )
464 applyEditOnTriangularMesh( edit, mTopologicalMesh.
removeFaces( faceToRemoveIndex ) );
466 updateElementsCount( edit.topologicalChanges );
469void QgsMeshEditor::applyChangeZValue( QgsMeshEditor::Edit &edit,
const QList<int> &verticesIndexes,
const QList<double> &newValues )
471 applyEditOnTriangularMesh( edit, mTopologicalMesh.
changeZValue( verticesIndexes, newValues ) );
473 if ( mZValueDatasetGroup )
477void QgsMeshEditor::applyChangeXYValue( QgsMeshEditor::Edit &edit,
const QList<int> &verticesIndexes,
const QList<QgsPointXY> &newValues )
479 applyEditOnTriangularMesh( edit, mTopologicalMesh.
changeXYValue( verticesIndexes, newValues ) );
482void QgsMeshEditor::applyFlipEdge( QgsMeshEditor::Edit &edit,
int vertexIndex1,
int vertexIndex2 )
484 applyEditOnTriangularMesh( edit, mTopologicalMesh.
flipEdge( vertexIndex1, vertexIndex2 ) );
486 updateElementsCount( edit.topologicalChanges );
489void QgsMeshEditor::applyMerge( QgsMeshEditor::Edit &edit,
int vertexIndex1,
int vertexIndex2 )
491 applyEditOnTriangularMesh( edit, mTopologicalMesh.
merge( vertexIndex1, vertexIndex2 ) );
493 updateElementsCount( edit.topologicalChanges );
496void QgsMeshEditor::applySplit( QgsMeshEditor::Edit &edit,
int faceIndex )
498 applyEditOnTriangularMesh( edit, mTopologicalMesh.
splitFace( faceIndex ) );
500 updateElementsCount( edit.topologicalChanges );
505 applyEditOnTriangularMesh( edit, editing->
apply(
this ) );
507 updateElementsCount( edit.topologicalChanges );
509 if ( mZValueDatasetGroup )
518 edit.topologicalChanges = topologicChanges;
519 edit.triangularMeshChanges = triangularChanges;
565 point.
y() - tolerance,
566 point.
x() + tolerance,
567 point.
y() + tolerance );
570 double minDist = std::numeric_limits<double>::max();
572 double epsilon = std::numeric_limits<double>::epsilon() * tolerance;
573 for (
const int nativeFaceIndex : nativeFaces )
576 const int faceSize = face.size();
577 for (
int i = 0; i < faceSize; ++i )
593 if ( dist < tolerance && dist < minDist )
595 faceIndex = nativeFaceIndex;
602 if ( edgePosition != -1 )
611 return mValidFacesCount;
616 return mValidVerticesCount;
621 return mMaximumVerticesPerFace;
650 return mTopologicalMesh.
canBeMerged( vertexIndex1, vertexIndex2 );
663 return mTopologicalMesh.
canBeSplit( faceIndex );
668 QList<int> faceIndexesSplittable;
670 for (
const int faceIndex : faceIndexes )
672 faceIndexesSplittable.append( faceIndex );
674 if ( faceIndexesSplittable.isEmpty() )
679 return faceIndexesSplittable.count();
682QVector<QgsMeshFace> QgsMeshEditor::prepareFaces(
const QVector<QgsMeshFace> &faces,
QgsMeshEditingError &error )
const
684 QVector<QgsMeshFace> treatedFaces = faces;
688 for (
int i = 0; i < treatedFaces.count(); ++i )
691 if ( mMaximumVerticesPerFace != 0 && face.count() > mMaximumVerticesPerFace )
705QList<int> QgsMeshEditor::prepareFaceWithNewVertices(
const QList<int> &face,
const QList<QgsMeshVertex> &newVertices,
QgsMeshEditingError &error )
const
707 if ( mMaximumVerticesPerFace != 0 && face.count() > mMaximumVerticesPerFace )
713 int faceSize = face.count();
714 QVector<QgsMeshVertex> vertices( faceSize );
715 int newVertexPos = 0;
716 for (
int i = 0; i < faceSize; ++i )
718 if ( face.at( i ) == -1 )
720 if ( newVertexPos >= newVertices.count() )
722 vertices[i] = newVertices.at( newVertexPos++ );
724 else if ( face.at( i ) >= 0 )
726 if ( face.at( i ) >= mTriangularMesh->
vertices().count() )
731 vertices[i] = mTriangularMesh->
vertices().at( face.at( i ) );
743 bool clockwise =
false;
749 QList<int> newFace = face;
750 for (
int i = 0; i < faceSize / 2; ++i )
752 int temp = newFace[i];
753 newFace[i] = face.at( faceSize - i - 1 );
754 newFace[faceSize - i - 1] = temp;
766 QVector<QgsMeshFace> facesToAdd = prepareFaces( faces, error );
790 mUndoStack->beginMacro( tr(
"Add a face with new %n vertices",
nullptr, newVertices.count() ) );
794 for (
int i = 0; i < vertexIndexes.count(); ++i )
796 int index = vertexIndexes.at( i );
798 face[i] = newVertexIndex++;
804 mUndoStack->endMacro();
811 QVector<QgsMeshVertex> verticesInLayerCoordinate( vertices.count() );
812 int ignoredVertex = 0;
813 for (
int i = 0; i < vertices.count(); ++i )
815 const QgsPointXY &pointInTriangularMesh = vertices.at( i );
816 bool isTooClose =
false;
818 if ( triangleIndex != -1 )
821 for (
int j = 0; j < 3; ++j )
824 double dist = pointInTriangularMesh.
distance( facePoint );
825 if ( dist < tolerance )
838 if ( verticesInLayerCoordinate.at( i ).isEmpty() )
842 if ( ignoredVertex < vertices.count() )
847 int effectivlyAddedVertex = vertices.count() - ignoredVertex;
849 return effectivlyAddedVertex;
861 QList<int> verticesIndexes = verticesToRemoveIndexes;
863 QSet<int> concernedNativeFaces;
864 for (
const int vi : std::as_const( verticesIndexes ) )
867 concernedNativeFaces.unite( QSet< int >( faces.begin(), faces.end() ) );
881 QList<int> remainingVertices;
884 return remainingVertices;
895 for (
const int faceIndex : facesToCheck )
898 int faceSize = face.count();
899 QVector<QgsPointXY> pointsInTriangularMeshCoordinate( faceSize );
900 QVector<QgsPointXY> points( faceSize );
901 for (
int i = 0; i < faceSize; ++i )
904 int ip1 = face[( i + 1 ) % faceSize];
905 int ip2 = face[( i + 2 ) % faceSize];
911 double ux = p0.x() - p1.
x();
912 double uy = p0.y() - p1.
y();
913 double vx = p2.
x() - p1.
x();
914 double vy = p2.
y() - p1.
y();
916 double crossProduct = ux * vy - uy * vx;
917 if ( crossProduct >= 0 )
926 QList<int> otherFaceIndexes =
929 for (
const int otherFaceIndex : otherFaceIndexes )
932 int existingFaceSize = otherFace.count();
933 bool shareVertex =
false;
934 for (
int i = 0; i < existingFaceSize; ++i )
936 if ( face.contains( otherFace.at( i ) ) )
945 for (
int i = 0; i < existingFaceSize; ++i )
947 int index1 = otherFace.at( i );
948 int index2 = otherFace.at( ( i + 1 ) % existingFaceSize );
949 if ( ! face.contains( index1 ) && !face.contains( index2 ) )
951 const QgsPointXY &v1 = transformFunction( index1 );
952 const QgsPointXY &v2 = transformFunction( index2 );
961 QVector<QgsPointXY> otherPoints( existingFaceSize );
962 for (
int i = 0; i < existingFaceSize; ++i )
963 otherPoints[i] = transformFunction( otherFace.at( i ) );
965 if ( deformedFace.
intersects( existingFaceGeom ) )
971 for (
const int vertexIndex : freeVerticesIndex )
973 const QgsPointXY &mapPoint = transformFunction( vertexIndex );
974 if ( deformedFace.
contains( &mapPoint ) )
981 for (
const int vertexIndex : freeVerticesIndex )
983 const QgsMeshVertex &newFreeVertexPosition = transformFunction( vertexIndex );
987 if ( originalIncludingFace != -1 )
992 int faceSize = face.count();
993 QVector<QgsPointXY> points( faceSize );
994 for (
int i = 0; i < faceSize; ++i )
995 points[i] = transformFunction( face.at( i ) );
998 const QgsPointXY ptXY( newFreeVertexPosition );
999 if ( deformedFace.
contains( &ptXY ) )
1026 mUndoStack->clear();
1030 : mMeshEditor( meshEditor )
1039 for (
int i =
mEdits.count() - 1; i >= 0; --i )
1048 for ( QgsMeshEditor::Edit &edit :
mEdits )
1054 , mVertices( vertices )
1055 , mTolerance( tolerance )
1057 setText( QObject::tr(
"Add %n vertices",
nullptr, mVertices.count() ) );
1062 if ( !mVertices.isEmpty() )
1064 for (
int i = 0; i < mVertices.count(); ++i )
1069 QgsMeshEditor::Edit edit;
1070 mMeshEditor->applyAddVertex( edit, vertex, mTolerance );
1077 for ( QgsMeshEditor::Edit &edit :
mEdits )
1084 const QList<int> &verticesToRemoveIndexes,
1085 QList<int> *remainingVerticesPointer )
1087 , mVerticesToRemoveIndexes( verticesToRemoveIndexes )
1088 , mRemainingVerticesPointer( remainingVerticesPointer )
1090 setText( QObject::tr(
"Remove %n vertices filling holes",
nullptr, verticesToRemoveIndexes.count() ) );
1095 int initialVertexCount = mVerticesToRemoveIndexes.count();
1096 if ( !mVerticesToRemoveIndexes.isEmpty() )
1098 QgsMeshEditor::Edit edit;
1099 QList<int> vertexToRetry;
1100 while ( !mVerticesToRemoveIndexes.isEmpty() )
1103 for (
const int &vertex : std::as_const( mVerticesToRemoveIndexes ) )
1105 if (
mMeshEditor->applyRemoveVertexFillHole( edit, vertex ) )
1108 vertexToRetry.append( vertex );
1111 if ( vertexToRetry.count() == mVerticesToRemoveIndexes.count() )
1114 mVerticesToRemoveIndexes = vertexToRetry;
1117 if ( initialVertexCount == mVerticesToRemoveIndexes.count() )
1118 setObsolete(
true );
1120 if ( mRemainingVerticesPointer !=
nullptr )
1121 *mRemainingVerticesPointer = mVerticesToRemoveIndexes;
1123 mRemainingVerticesPointer =
nullptr;
1125 mVerticesToRemoveIndexes.clear();
1129 for ( QgsMeshEditor::Edit &edit :
mEdits )
1137 const QList<int> &verticesToRemoveIndexes )
1139 , mVerticesToRemoveIndexes( verticesToRemoveIndexes )
1141 setText( QObject::tr(
"Remove %n vertices without filling holes",
nullptr, verticesToRemoveIndexes.count() ) ) ;
1146 if ( !mVerticesToRemoveIndexes.isEmpty() )
1148 QgsMeshEditor::Edit edit;
1150 mMeshEditor->applyRemoveVerticesWithoutFillHole( edit, mVerticesToRemoveIndexes );
1153 mVerticesToRemoveIndexes.clear();
1157 for ( QgsMeshEditor::Edit &edit :
mEdits )
1166 setText( QObject::tr(
"Add %n face(s)",
nullptr, faces.
meshFaces().count() ) );
1173 QgsMeshEditor::Edit edit;
1181 for ( QgsMeshEditor::Edit &edit :
mEdits )
1188 , mfacesToRemoveIndexes( facesToRemoveIndexes )
1190 setText( QObject::tr(
"Remove %n face(s)",
nullptr, facesToRemoveIndexes.count() ) );
1195 if ( !mfacesToRemoveIndexes.isEmpty() )
1197 QgsMeshEditor::Edit edit;
1198 mMeshEditor->applyRemoveFaces( edit, mfacesToRemoveIndexes );
1201 mfacesToRemoveIndexes.clear();
1205 for ( QgsMeshEditor::Edit &edit :
mEdits )
1222 return !mUndoStack->isClean();
1230 mUndoStack->clear();
1240 if ( !mTopologicalMesh.
renumber() )
1275 return mTopologicalMesh;
1280 return mTriangularMesh;
1285 , mVerticesIndexes( verticesIndexes )
1286 , mNewValues( newValues )
1288 setText( QObject::tr(
"Change %n vertices Z Value",
nullptr, verticesIndexes.count() ) );
1293 if ( !mVerticesIndexes.isEmpty() )
1295 QgsMeshEditor::Edit edit;
1296 mMeshEditor->applyChangeZValue( edit, mVerticesIndexes, mNewValues );
1298 mVerticesIndexes.clear();
1303 for ( QgsMeshEditor::Edit &edit :
mEdits )
1310 , mVerticesIndexes( verticesIndexes )
1311 , mNewValues( newValues )
1313 setText( QObject::tr(
"Move %n vertices",
nullptr, verticesIndexes.count() ) );
1318 if ( !mVerticesIndexes.isEmpty() )
1320 QgsMeshEditor::Edit edit;
1321 mMeshEditor->applyChangeXYValue( edit, mVerticesIndexes, mNewValues );
1323 mVerticesIndexes.clear();
1328 for ( QgsMeshEditor::Edit &edit :
mEdits )
1336 , mVerticesIndexes( verticesIndexes )
1337 , mNewCoordinates( newCoordinates )
1339 setText( QObject::tr(
"Transform %n vertices coordinates",
nullptr, verticesIndexes.count() ) );
1344 if ( !mVerticesIndexes.isEmpty() )
1346 QgsMeshEditor::Edit editXY;
1347 QList<QgsPointXY> newXY;
1348 newXY.reserve( mNewCoordinates.count() );
1349 QgsMeshEditor::Edit editZ;
1351 newZ.reserve( mNewCoordinates.count() );
1353 for (
const QgsPoint &pt : std::as_const( mNewCoordinates ) )
1356 newZ.append( pt.z() );
1359 mMeshEditor->applyChangeXYValue( editXY, mVerticesIndexes, newXY );
1361 mMeshEditor->applyChangeZValue( editZ, mVerticesIndexes, newZ );
1363 mVerticesIndexes.clear();
1364 mNewCoordinates.clear();
1368 for ( QgsMeshEditor::Edit &edit :
mEdits )
1377 , mVertexIndex1( vertexIndex1 )
1378 , mVertexIndex2( vertexIndex2 )
1380 setText( QObject::tr(
"Flip edge" ) );
1385 if ( mVertexIndex1 >= 0 && mVertexIndex2 >= 0 )
1387 QgsMeshEditor::Edit edit;
1388 mMeshEditor->applyFlipEdge( edit, mVertexIndex1, mVertexIndex2 );
1395 for ( QgsMeshEditor::Edit &edit :
mEdits )
1402 , mVertexIndex1( vertexIndex1 )
1403 , mVertexIndex2( vertexIndex2 )
1405 setText( QObject::tr(
"Merge faces" ) );
1410 if ( mVertexIndex1 >= 0 && mVertexIndex2 >= 0 )
1412 QgsMeshEditor::Edit edit;
1413 mMeshEditor->applyMerge( edit, mVertexIndex1, mVertexIndex2 );
1420 for ( QgsMeshEditor::Edit &edit :
mEdits )
1427 , mFaceIndexes( faceIndexes )
1429 setText( QObject::tr(
"Split %n face(s)",
nullptr, faceIndexes.count() ) );
1434 if ( !mFaceIndexes.isEmpty() )
1436 for (
int faceIndex : std::as_const( mFaceIndexes ) )
1438 QgsMeshEditor::Edit edit;
1442 mFaceIndexes.clear();
1446 for ( QgsMeshEditor::Edit &edit :
mEdits )
1453 , mAdvancedEditing( advancdEdit )
1455 setText( advancdEdit->
text() );
1460 if ( mAdvancedEditing )
1462 QgsMeshEditor::Edit edit;
1465 mMeshEditor->applyAdvancedEdit( edit, mAdvancedEditing );
1469 mAdvancedEditing =
nullptr;
1473 for ( QgsMeshEditor::Edit &edit :
mEdits )
The Qgis class provides global constants for use throughout the application.
MeshEditingErrorType
Type of error that can occur during mesh frame editing.
@ TooManyVerticesInFace
A face has more vertices than the maximum number supported per face.
@ InvalidFace
An error occurs due to an invalid face (for example, vertex indexes are unordered)
@ UniqueSharedVertex
A least two faces share only one vertices.
@ ManifoldFace
ManifoldFace.
@ InvalidVertex
An error occurs due to an invalid vertex (for example, vertex index is out of range the available ver...
@ FlatFace
A flat face is present.
static double sqrDistToLine(double ptX, double ptY, double x1, double y1, double x2, double y2, double &minDistX, double &minDistY, double epsilon) SIP_HOLDGIL
Returns the squared distance between a point and a line.
A geometry is the spatial representation of a feature.
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
static QgsGeometry fromPolylineXY(const QgsPolylineXY &polyline)
Creates a new LineString geometry from a list of QgsPointXY points.
bool contains(const QgsPointXY *p) const
Returns true if the geometry contains the point p.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine representing the specified geometry.
static QgsGeometry fromPolygonXY(const QgsPolygonXY &polygon)
Creates a new geometry from a QgsPolygonXY.
bool intersects(const QgsRectangle &rectangle) const
Returns true if this geometry exactly intersects with a rectangle.
Line string geometry type, with support for z-dimension and m-values.
Abstract class that can be derived to implement advanced editing on mesh.
virtual QgsTopologicalMesh::Changes apply(QgsMeshEditor *meshEditor)=0
Apply a change to mesh Editor.
virtual bool isFinished() const
Returns whether the advanced edit is finished, if not, this edit has to be applied again with QgsMesh...
virtual QString text() const
Returns a short text string describing what this advanced edit does. Default implementation return a ...
virtual int maximumVerticesCountPerFace() const
Returns the maximum number of vertices per face supported by the current mesh, if returns 0,...
Abstract class that represents a dataset group.
void setStatisticObsolete() const
Sets statistic obsolete, that means statistic will be recalculated when requested.
Class that represents an error during mesh editing.
Qgis::MeshEditingErrorType errorType
QgsMeshEditingError()
Constructor of the default error, that is NoError.
Class that makes edit operation on a mesh.
friend class QgsMeshLayerUndoCommandSplitFaces
QgsMeshEditingError initialize()
Initializes the mesh editor and returns first error if the internal native mesh has topological error...
friend class QgsMeshLayerUndoCommandMerge
void changeXYValues(const QList< int > &verticesIndexes, const QList< QgsPointXY > &newValues)
Changes the (X,Y) coordinates values of the vertices with indexes in verticesIndexes with the values ...
int validFacesCount() const
Returns the count of valid faces, that is non void faces in the mesh.
friend class QgsMeshLayerUndoCommandRemoveVerticesWithoutFillHoles
QgsMeshEditingError removeFaces(const QList< int > &facesToRemove)
Removes faces faces to the mesh, returns topological errors if this operation fails (operation is not...
QgsMeshEditingError addFaces(const QVector< QgsMeshFace > &faces)
Adds faces faces to the mesh, returns topological errors if this operation fails (operation is not re...
bool checkConsistency(QgsMeshEditingError &error) const
Return true if the edited mesh is consistent.
QList< int > removeVerticesFillHoles(const QList< int > &verticesToRemoveIndexes)
Removes vertices with indexes in the list verticesToRemoveIndexes in the mesh the surrounding faces A...
void flipEdge(int vertexIndex1, int vertexIndex2)
Flips edge (vertexIndex1, vertexIndex2)
QgsRectangle extent() const
Returns the extent of the edited mesh.
friend class QgsMeshLayerUndoCommandAddVertices
bool faceCanBeSplit(int faceIndex) const
Returns true if face with index faceIndex can be split.
QgsMeshEditingError initializeWithErrorsFix()
Initializes the mesh editor.
int maximumVerticesPerFace() const
Returns the maximum count of vertices per face that the mesh can support.
QgsMeshEditingError addFace(const QVector< int > &vertexIndexes)
Adds a face face to the mesh with vertex indexes vertexIndexes, returns topological errors if this op...
QgsMeshEditor(QgsMeshLayer *meshLayer)
Constructor with a specified layer meshLayer.
void merge(int vertexIndex1, int vertexIndex2)
Merges faces separated by vertices with indexes vertexIndex1 and vertexIndex2.
bool edgeIsClose(QgsPointXY point, double tolerance, int &faceIndex, int &edgePosition)
Returns true if an edge of face is closest than the tolerance from the point in triangular mesh coord...
QgsMeshEditingError removeVerticesWithoutFillHoles(const QList< int > &verticesToRemoveIndexes)
Removes vertices with indexes in the list verticesToRemoveIndexes in the mesh removing the surroundin...
bool isFaceGeometricallyCompatible(const QgsMeshFace &face) const
Returns true if the face does not intersect or contains any other elements (faces or vertices) The to...
QList< int > freeVerticesIndexes() const
Returns all the free vertices indexes.
friend class QgsMeshLayerUndoCommandChangeXYValue
bool isVertexOnBoundary(int vertexIndex) const
Returns whether the vertex with index vertexIndex is on a boundary.
friend class QgsMeshLayerUndoCommandFlipEdge
bool faceCanBeAdded(const QgsMeshFace &face) const
Returns true if a face can be added to the mesh.
void changeCoordinates(const QList< int > &verticesIndexes, const QList< QgsPoint > &newCoordinates)
Changes the (X,Y,Z) coordinates values of the vertices with indexes in vertices indexes with the valu...
void stopEditing()
Stops editing.
friend class QgsMeshLayerUndoCommandAdvancedEditing
bool canBeMerged(int vertexIndex1, int vertexIndex2) const
Returns true if faces separated by vertices with indexes vertexIndex1 and vertexIndex2 can be merged.
friend class QgsMeshLayerUndoCommandAddFaces
QgsMeshEditingError addFaceWithNewVertices(const QList< int > &vertexIndexes, const QList< QgsMeshVertex > &newVertices)
Adds a face formed by some vertices vertexIndexes to the mesh, returns topological errors if this ope...
friend class QgsMeshLayerUndoCommandChangeCoordinates
bool edgeCanBeFlipped(int vertexIndex1, int vertexIndex2) const
Returns true if the edge can be flipped (only available for edge shared by two faces with 3 vertices)
int splitFaces(const QList< int > &faceIndexes)
Splits faces with index faceIndexes.
QgsMeshVertexCirculator vertexCirculator(int vertexIndex) const
Returns a vertex circulator linked to this mesh around the vertex with index vertexIndex.
bool faceCanBeAddedWithNewVertices(const QList< int > &verticesIndex, const QList< QgsMeshVertex > &newVertices) const
Returns true if a face formed by some vertices can be added to the mesh.
void meshEdited()
Emitted when the mesh is edited.
void changeZValues(const QList< int > &verticesIndexes, const QList< double > &newValues)
Changes the Z values of the vertices with indexes in vertices indexes with the values in newValues.
void resetTriangularMesh(QgsTriangularMesh *triangularMesh)
Resets the triangular mesh.
bool isModified() const
Returns whether the mesh has been modified.
void advancedEdit(QgsMeshAdvancedEditing *editing)
Applies an advance editing on the edited mesh, see QgsMeshAdvancedEditing.
bool canBeTransformed(const QList< int > &facesToCheck, const std::function< const QgsMeshVertex(int)> &transformFunction) const
Returns true if faces with index in transformedFaces can be transformed without obtaining topologic o...
int addVertices(const QVector< QgsMeshVertex > &vertices, double tolerance)
Adds vertices in triangular mesh coordinate in the mesh.
int validVerticesCount() const
Returns the count of valid vertices, that is non void vertices in the mesh.
friend class QgsMeshLayerUndoCommandRemoveVerticesFillHoles
bool isVertexFree(int vertexIndex) const
Returns whether the vertex with index vertexIndex is a free vertex.
bool reindex(bool renumbering)
Reindexes the mesh, that is remove unusued index of face and vertices, this operation void the undo/r...
friend class QgsMeshLayerUndoCommandChangeZValue
QgsTriangularMesh * triangularMesh()
Returns a pointer to the triangular mesh.
bool fixError(const QgsMeshEditingError &error)
Tries to fix the topological error in the mesh.
QgsMeshDatasetGroup * createZValueDatasetGroup()
Creates and returns a scalar dataset group with value on vertex that is can be used to access the Z v...
friend class QgsMeshLayerUndoCommandRemoveFaces
QgsTopologicalMesh & topologicalMesh()
Returns a reference to the topological mesh.
int addPointsAsVertices(const QVector< QgsPoint > &point, double tolerance)
Adds points as vertices in triangular mesh coordinate in the mesh.
QgsMeshLayerUndoCommandAddFaces(QgsMeshEditor *meshEditor, QgsTopologicalMesh::TopologicalFaces &faces)
Constructor with the associated meshEditor and faces that will be added.
QgsMeshLayerUndoCommandAddVertices(QgsMeshEditor *meshEditor, const QVector< QgsMeshVertex > &vertices, double tolerance)
Constructor with the associated meshEditor and vertices that will be added.
QgsMeshLayerUndoCommandAdvancedEditing(QgsMeshEditor *meshEditor, QgsMeshAdvancedEditing *advancdEdit)
Constructor with the associated meshEditor.
QgsMeshLayerUndoCommandChangeCoordinates(QgsMeshEditor *meshEditor, const QList< int > &verticesIndexes, const QList< QgsPoint > &newCoordinates)
Constructor with the associated meshEditor and indexes verticesIndexes of the vertices that will have...
QgsMeshLayerUndoCommandChangeXYValue(QgsMeshEditor *meshEditor, const QList< int > &verticesIndexes, const QList< QgsPointXY > &newValues)
Constructor with the associated meshEditor and indexes verticesIndexes of the vertices that will have...
QgsMeshLayerUndoCommandChangeZValue(QgsMeshEditor *meshEditor, const QList< int > &verticesIndexes, const QList< double > &newValues)
Constructor with the associated meshEditor and indexes verticesIndexes of the vertices that will have...
QgsMeshLayerUndoCommandFlipEdge(QgsMeshEditor *meshEditor, int vertexIndex1, int vertexIndex2)
Constructor with the associated meshEditor and the vertex indexes of the edge (vertexIndex1,...
QgsMeshLayerUndoCommandMerge(QgsMeshEditor *meshEditor, int vertexIndex1, int vertexIndex2)
Constructor with the associated meshEditor and the vertex indexes of the edge (vertexIndex1,...
Base class for undo/redo command for mesh editing.
QList< QgsMeshEditor::Edit > mEdits
QgsMeshLayerUndoCommandMeshEdit(QgsMeshEditor *meshEditor)
Constructor for the base class.
QPointer< QgsMeshEditor > mMeshEditor
QgsMeshLayerUndoCommandRemoveFaces(QgsMeshEditor *meshEditor, const QList< int > &facesToRemoveIndexes)
Constructor with the associated meshEditor and indexes facesToRemoveIndexes of the faces that will be...
QgsMeshLayerUndoCommandRemoveVerticesFillHoles(QgsMeshEditor *meshEditor, const QList< int > &verticesToRemoveIndexes, QList< int > *remainingVerticesPointer=nullptr)
Constructor with the associated meshEditor and vertices that will be removed.
QgsMeshLayerUndoCommandRemoveVerticesWithoutFillHoles(QgsMeshEditor *meshEditor, const QList< int > &verticesToRemoveIndexes)
Constructor with the associated meshEditor and vertices that will be removed.
QgsMeshLayerUndoCommandSplitFaces(QgsMeshEditor *meshEditor, const QList< int > &faceIndexes)
Constructor with the associated meshEditor and indexes faceIndexes of the faces to split.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
QgsMeshDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
Convenient class that turn around a vertex and provide information about faces and vertices.
bool goBoundaryCounterClockwise() const
Sets the circulator on the boundary face turning counter clockwise, return false is there isn't bound...
int oppositeVertexCounterClockwise() const
Returns the opposite vertex of the current face and on the edge on the side turning counter clockwise...
bool goBoundaryClockwise() const
Sets the circulator on the boundary face turning clockwise, return false is there isn't boundary face...
int oppositeVertexClockwise() const
Returns the opposite vertex of the current face and on the edge on the side turning clockwise.
A class to represent a 2D point.
double distance(double x, double y) const SIP_HOLDGIL
Returns the distance between this point and a specified x, y coordinate.
Point geometry type, with support for z-dimension and m-values.
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
A rectangle specified with double values.
Class that contains topological differences between two states of a topological mesh,...
QVector< QgsMeshFace > removedFaces() const
Returns the faces that are removed with this changes.
QVector< QgsMeshVertex > addedVertices() const
Returns the added vertices with this changes.
bool isEmpty() const
Returns whether changes are empty, that there is nothing to change.
QVector< QgsMeshFace > addedFaces() const
Returns the face that are added with this changes.
QList< int > verticesToRemoveIndexes() const
Returns the indexes of vertices to remove.
Class that contains independent faces an topological information about this faces.
void clear()
Clears all data contained in the instance.
QVector< QgsMeshFace > meshFaces() const
Returns faces.
Class that wraps a QgsMesh to ensure the consistency of the mesh during editing and help to access to...
static QgsMeshEditingError checkTopologyOfVerticesAsFace(const QVector< QgsMeshVertex > &vertices, bool &clockwise)
Checks the topology of the vertices as they are contained in a face and returns indication on directi...
Changes changeZValue(const QList< int > &verticesIndexes, const QList< double > &newValues)
Changes the Z values of the vertices with indexes in vertices indexes with the values in newValues.
static QgsTopologicalMesh createTopologicalMesh(QgsMesh *mesh, int maxVerticesPerFace, QgsMeshEditingError &error)
Creates a topologicaly consistent mesh with mesh, this static method modifies mesh to be topological ...
bool isVertexFree(int vertexIndex) const
Returns whether the vertex is a free vertex.
static QgsMeshEditingError counterClockwiseFaces(QgsMeshFace &face, QgsMesh *mesh)
Checks the topology of the face and sets it counter clockwise if necessary.
Changes removeVertexFillHole(int vertexIndex)
Removes the vertex with index vertexIndex.
void applyChanges(const Changes &changes)
Applies the changes.
QgsMeshEditingError checkConsistency() const
Checks the consistency of the topological mesh and return false if there is a consistency issue.
Changes removeVertices(const QList< int > &vertices)
Removes all the vertices with index in the list vertices If vertices in linked with faces,...
Changes changeXYValue(const QList< int > &verticesIndexes, const QList< QgsPointXY > &newValues)
Changes the (X,Y) values of the vertices with indexes in vertices indexes with the values in newValue...
void reindex()
Reindexes faces and vertices, after this operation, the topological mesh can't be edited anymore and ...
QgsMeshEditingError facesCanBeAdded(const TopologicalFaces &topologicalFaces) const
Returns whether the faces can be added to the mesh.
bool renumber()
Renumbers the indexes of vertices and faces using the Reverse CutHill McKee Algorithm.
Changes flipEdge(int vertexIndex1, int vertexIndex2)
Flips edge (vertexIndex1, vertexIndex2) The method returns a instance of the class QgsTopologicalMesh...
QgsMeshEditingError facesCanBeRemoved(const QList< int > &facesIndexes)
Returns whether faces with index in faceIndexes can be removed/ The method an error object with type ...
void reverseChanges(const Changes &changes)
Reverses the changes.
Changes addFaces(const TopologicalFaces &topologicFaces)
Adds faces topologicFaces to the topologic mesh.
Changes merge(int vertexIndex1, int vertexIndex2)
Merges faces separated by vertices with indexes vertexIndex1 and vertexIndex2 The method returns a in...
Changes removeFaces(const QList< int > &facesIndexes)
Removes faces with index in faceIndexes.
QList< int > freeVerticesIndexes() const
Returns a list of vertices are not linked to any faces.
bool edgeCanBeFlipped(int vertexIndex1, int vertexIndex2) const
Returns true if the edge can be flipped (only available for edge shared by two faces with 3 vertices)
Changes addVertexInFace(int faceIndex, const QgsMeshVertex &vertex)
Adds a vertex in the face with index faceIndex.
bool canBeMerged(int vertexIndex1, int vertexIndex2) const
Returns true if faces separated by vertices with indexes vertexIndex1 and vertexIndex2 can be merged.
QList< int > facesAroundVertex(int vertexIndex) const
Returns the indexes of faces that are around the vertex with index vertexIndex.
bool canBeSplit(int faceIndex) const
Returns true if face with index faceIndex can be split.
Changes addFreeVertex(const QgsMeshVertex &vertex)
Adds a free vertex in the face, that is a vertex tha tis not included or linked with any faces.
Changes insertVertexInFacesEdge(int faceIndex, int position, const QgsMeshVertex &vertex)
Inserts a vertex in the edge of face with index faceIndex at position .
bool isVertexOnBoundary(int vertexIndex) const
Returns whether the vertex is on a boundary.
Changes splitFace(int faceIndex)
Splits face with index faceIndex The method returns a instance of the class QgsTopologicalMesh::Chang...
static TopologicalFaces createNewTopologicalFaces(const QVector< QgsMeshFace > &faces, bool uniqueSharedVertexAllowed, QgsMeshEditingError &error)
Creates new topological faces that are not yet included in the mesh.
QgsMeshVertexCirculator vertexCirculator(int vertexIndex) const
Returns a vertex circulator linked to this mesh around the vertex with index vertexIndex.
The Changes class is used to make changes of the triangular and to keep traces of this changes If a C...
Triangular/Derived Mesh is mesh with vertices in map coordinates.
const QVector< QgsMeshFace > & triangles() const
Returns triangles.
QgsRectangle nativeExtent()
Returns the extent of the mesh in the native mesh coordinates system, returns empty extent if the tra...
int nativeFaceIndexForPoint(const QgsPointXY &point) const
Finds index of native face at given point It uses spatial indexing.
void reverseChanges(const Changes &changes, const QgsMesh &nativeMesh)
Reverses the changes on the triangular mesh (see Changes)
void applyChanges(const Changes &changes)
Applies the changes on the triangular mesh (see Changes)
const QVector< QgsMeshVertex > & vertices() const
Returns vertices in map coordinate system.
QgsMeshVertex triangularToNativeCoordinates(const QgsMeshVertex &vertex) const
Transforms the vertex from triangular mesh coordinates system to native coordinates system.
QgsMeshVertex nativeToTriangularCoordinates(const QgsMeshVertex &vertex) const
Transforms the vertex from native coordinates system to triangular mesh coordinates system.
bool update(QgsMesh *nativeMesh, const QgsCoordinateTransform &transform)
Constructs triangular mesh from layer's native mesh and transform to destination CRS.
const QVector< QgsMeshVertex > & faceCentroids() const
Returns centroids of the native faces in map CRS.
QList< int > nativeFaceIndexForRectangle(const QgsRectangle &rectangle) const
Finds indexes of native faces which bounding boxes intersect given bounding box It uses spatial index...
int faceIndexForPoint_v2(const QgsPointXY &point) const
Finds index of triangle at given point It uses spatial indexing and don't use geos to be faster.
CORE_EXPORT QgsGeometry toGeometry(const QgsMeshFace &face, const QVector< QgsMeshVertex > &vertices)
Returns face as polygon geometry.
QVector< int > QgsMeshFace
List of vertex indexes.
QgsPoint QgsMeshVertex
xyz coords of vertex
Mesh - vertices, edges and faces.
int vertexCount() const
Returns number of vertices.
QVector< QgsMeshVertex > vertices
QgsMeshFace face(int index) const
Returns a face at the index.
QVector< QgsMeshFace > faces
int faceCount() const
Returns number of faces.