39 double ux1 = v1.
x() - vc.
x();
40 double uy1 = v1.
y() - vc.
y();
41 double vx1 = v2.
x() - vc.
x();
42 double vy1 = v2.
y() - vc.
y();
44 return ux1 * vy1 - uy1 * vx1;
47static double crossProduct(
int centralVertex,
int vertex1,
int vertex2,
const QgsMesh &mesh )
53 return crossProduct( vc, v1, v2 );
58 : mFaces( topologicalMesh.mMesh->faces )
59 , mFacesNeighborhood( topologicalMesh.mFacesNeighborhood )
60 , mVertexIndex( vertexIndex )
62 if ( vertexIndex >= 0 && vertexIndex < topologicalMesh.mMesh->vertexCount() )
64 mCurrentFace = topologicalMesh.mVertexToFace[vertexIndex];
73 mLastValidFace = mCurrentFace;
77 : mFaces( topologicalFaces.mFaces )
78 , mFacesNeighborhood( topologicalFaces.mFacesNeighborhood )
79 , mVertexIndex( vertexIndex )
81 const QgsMeshFace &face = topologicalFaces.mFaces.at( faceIndex );
84 mCurrentFace = faceIndex;
85 mLastValidFace = mCurrentFace;
89 : mFaces( topologicalFaces.mFaces )
90 , mFacesNeighborhood( topologicalFaces.mFacesNeighborhood )
91 , mVertexIndex( vertexIndex )
93 if ( topologicalFaces.mVerticesToFace.contains( vertexIndex ) )
94 mCurrentFace = topologicalFaces.mVerticesToFace.values( vertexIndex ).first();
95 mLastValidFace = mCurrentFace;
96 mIsValid = mCurrentFace != -1;
101 if ( mCurrentFace == -1 )
102 mCurrentFace = mLastValidFace;
105 int currentPos = positionInCurrentFace();
106 Q_ASSERT( currentPos != -1 );
110 mLastValidFace = mCurrentFace;
111 mCurrentFace = mFacesNeighborhood.at( mCurrentFace ).at( ( currentPos + faceSize - 1 ) %
currentFace.count() );
119 if ( mCurrentFace == -1 )
120 mCurrentFace = mLastValidFace;
123 int currentPos = positionInCurrentFace();
124 Q_ASSERT( currentPos != -1 );
128 mLastValidFace = mCurrentFace;
129 mCurrentFace = mFacesNeighborhood.at( mCurrentFace ).at( ( currentPos ) % faceSize );
142 if ( mCurrentFace != -1 )
143 return mFaces.at( mCurrentFace );
153 if ( mCurrentFace == -1 )
154 mCurrentFace = mLastValidFace;
156 int firstFace = mCurrentFace;
159 if ( mCurrentFace == firstFace )
170 if ( mCurrentFace == -1 )
171 mCurrentFace = mLastValidFace;
173 int firstFace = mCurrentFace;
176 if ( mCurrentFace == firstFace )
184 if ( mCurrentFace == -1 )
189 if ( face.isEmpty() )
194 if ( vertexPosition == -1 )
197 return face.at( ( vertexPosition + 1 ) % face.count() );
202 if ( mCurrentFace == -1 )
207 if ( face.isEmpty() )
212 if ( vertexPosition == -1 )
215 return face.at( ( vertexPosition - 1 + face.count() ) % face.count() );
229 if ( mCurrentFace != -1 )
230 ret.append( mCurrentFace );
275int QgsMeshVertexCirculator::positionInCurrentFace()
const
277 if ( mCurrentFace < 0 || mCurrentFace >= mFaces.count() )
290 for (
int i = 0; i < changes.
mFacesToAdd.count(); ++i )
293 for (
int boundary : topologicalFaces.mBoundaries )
296 if ( mVertexToFace.at( boundary ) == -1 )
299 const QList<int> &linkedFaces = topologicalFaces.mVerticesToFace.values( boundary );
300 for (
int linkedFace : linkedFaces )
306 if ( mVertexToFace.at( oppositeVertexForNewFace ) == -1 )
316 if ( oppositeVertexForMeshFace != oppositeVertexForNewFace )
328 boundaryPositionInMeshFace,
338 for (
int f = 0; f < changes.
mFacesToAdd.count(); ++f )
339 for (
int n = 0; n < changes.
mFacesToAdd.at( f ).count(); ++n )
341 changes.
mFacesNeighborhoodToAdd[f][n] = changes.addedFaceIndexInMesh( topologicalFaces.mFacesNeighborhood.at( f ).at( n ) );
343 const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
344 for (
const int vtc : verticesToFaceToChange )
345 if ( mVertexToFace.at( vtc ) == -1 )
347 mVertexToFace.at( vtc ),
348 changes.addedFaceIndexInMesh( topologicalFaces.mVerticesToFace.values( vtc ).first() )
351 applyChanges( changes );
358 int initialVerticesCount = mMesh->
vertices.count();
363 mVertexToFace.resize( newSize );
369 mMesh->
faces.resize( newSize );
370 mFacesNeighborhood.resize( newSize );
376 mFacesNeighborhood[changes.removedFaceIndexInMesh( i )] =
FaceNeighbors();
382 if ( mVertexToFace.at( vertexIndex ) == -1 )
383 dereferenceAsFreeVertex( vertexIndex );
385 mVertexToFace[vertexIndex] = -1;
393 referenceAsFreeVertex( initialVerticesCount + i );
396 for (
int i = 0; i < changes.
mFacesToAdd.count(); ++i )
398 mMesh->
faces[changes.addedFaceIndexInMesh( i )] = changes.
mFacesToAdd.at( i );
404 const int faceIndex = neighborChange.at( 0 );
405 const int positionInFace = neighborChange.at( 1 );
406 const int valueToApply = neighborChange.at( 3 );
407 mFacesNeighborhood[faceIndex][positionInFace] = valueToApply;
412 int vertexIndex = vertexToFaceChange.at( 0 );
413 mVertexToFace[vertexToFaceChange.at( 0 )] = vertexToFaceChange.at( 2 );
415 if ( vertexToFaceChange.at( 2 ) == -1 &&
416 vertexToFaceChange.at( 1 ) != -1 &&
417 !mMesh->
vertices.at( vertexIndex ).isEmpty() )
418 referenceAsFreeVertex( vertexIndex );
420 if ( vertexToFaceChange.at( 1 ) == -1 && vertexToFaceChange.at( 2 ) != -1 )
421 dereferenceAsFreeVertex( vertexIndex );
432 mMesh->
vertices[vertexIndex].setX( pt.
x() );
433 mMesh->
vertices[vertexIndex].setY( pt.
y() );
442 const int faceIndex = neighborChange.at( 0 );
443 const int positionInFace = neighborChange.at( 1 );
444 const int valueToApply = neighborChange.at( 2 );
445 mFacesNeighborhood[faceIndex][positionInFace] = valueToApply;
459 if ( mVertexToFace.at( vertexIndex ) == -1 )
460 referenceAsFreeVertex( vertexIndex );
464 for (
int i = 0; i < verticesToFaceChangesCount; ++i )
466 const std::array<int, 3> vertexToFaceChange = changes.
mVerticesToFaceChanges.at( verticesToFaceChangesCount - i - 1 );
467 int vertexIndex = vertexToFaceChange.at( 0 );
468 mVertexToFace[vertexIndex] = vertexToFaceChange.at( 1 );
470 if ( vertexToFaceChange.at( 2 ) == -1 && vertexToFaceChange.at( 1 ) != -1 )
471 dereferenceAsFreeVertex( vertexIndex );
473 if ( vertexToFaceChange.at( 1 ) == -1 &&
474 vertexToFaceChange.at( 2 ) != -1 &&
476 referenceAsFreeVertex( vertexIndex );
482 mMesh->
faces.resize( newSize );
483 mFacesNeighborhood.resize( newSize );
490 for (
int i = newSize; i < mMesh->
vertexCount(); ++i )
491 if ( mVertexToFace.at( i ) == -1 )
492 dereferenceAsFreeVertex( i );
495 mVertexToFace.resize( newSize );
506 mMesh->
vertices[vertexIndex].setX( pt.
x() );
507 mMesh->
vertices[vertexIndex].setY( pt.
y() );
517QSet<int> QgsTopologicalMesh::concernedFacesBy(
const QList<int> &faceIndexes )
const
520 for (
const int faceIndex : faceIndexes )
523 for (
int i = 0; i < face.count(); ++i )
526 faces.unite( QSet< int >( around.begin(), around.end() ) );
532void QgsTopologicalMesh::dereferenceAsFreeVertex(
int vertexIndex )
534 mFreeVertices.remove( vertexIndex );
537void QgsTopologicalMesh::referenceAsFreeVertex(
int vertexIndex )
541 mFreeVertices.insert( vertexIndex );
546 for (
int faceIndex = 0 ; faceIndex < mMesh->
faces.count( ); ++faceIndex )
549 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( faceIndex );
550 if ( face.count() != neighborhood.count() )
552 for (
int i = 0; i < face.count(); ++i )
554 int vertexIndex = face.at( i );
556 if ( mVertexToFace.at( vertexIndex ) == -1 )
559 int neighborIndex = neighborhood.at( i );
560 if ( neighborIndex != -1 )
563 if ( neighborFace.isEmpty() )
565 int neighborSize = neighborFace.size();
566 const FaceNeighbors &neighborhoodOfNeighbor = mFacesNeighborhood.at( neighborIndex );
568 if ( neighborhoodOfNeighbor.isEmpty() || neighborhoodOfNeighbor.at( ( posInNeighbor + neighborSize - 1 ) % neighborSize ) != faceIndex )
574 for (
int vertexIndex = 0; vertexIndex < mMesh->
vertexCount(); ++vertexIndex )
576 if ( mVertexToFace.at( vertexIndex ) != -1 )
578 if ( !mMesh->
face( mVertexToFace.at( vertexIndex ) ).contains( vertexIndex ) )
604 if ( vertexIndex < 0 || vertexIndex >= mMesh->
vertexCount() )
606 return mVertexToFace.at( vertexIndex );
621 if ( vertexIndex < 0 || vertexIndex >= mMesh->
vertexCount() )
624 if ( mMesh->
vertices.at( vertexIndex ).isEmpty() )
627 return mVertexToFace.at( vertexIndex ) == -1;
632 return QList<int>( mFreeVertices.begin(), mFreeVertices.end() );
637 int size = vertices.size();
639 for (
int i = 0; i < size; ++i )
642 int iv1 = ( i + 1 ) % size;
643 int iv2 = ( i + 2 ) % size;
658 double crossProd = crossProduct( v1, v0, v2 );
659 if ( direction != 0 && crossProd * direction < 0 )
661 clockwise = direction > 0;
664 else if ( crossProd == 0 )
666 clockwise = direction > 0;
669 else if ( direction == 0 )
670 direction = crossProd / std::fabs( crossProd );
673 clockwise = direction > 0;
682 int faceSize = face.count();
686 QVector<QgsMeshVertex> vertices( face.size() );
688 for (
int i = 0; i < faceSize; ++i )
697 bool clockwise =
false;
704 for (
int i = 0; i < faceSize / 2; ++i )
707 face[i] = face.at( faceSize - i - 1 );
708 face[faceSize - i - 1] = temp;
717 QVector<int> oldToNewIndex( mMesh->
vertices.count(), -1 );
721 while ( oldIndex < verticesTotalCount )
729 oldToNewIndex[oldIndex] = newIndex;
730 if ( oldIndex != newIndex )
732 oldToNewIndex[oldIndex] = newIndex;
742 int facesTotalCount = mMesh->
faceCount();
743 while ( oldIndex < facesTotalCount )
745 if ( mMesh->
face( oldIndex ).isEmpty() )
749 if ( oldIndex != newIndex )
750 mMesh->
faces[newIndex] = mMesh->
faces[oldIndex];
752 for (
int i = 0; i < face.count(); ++i )
753 face[i] = oldToNewIndex[face.at( i )];
759 mMesh->
faces.resize( newIndex );
761 mVertexToFace.clear();
762 mFacesNeighborhood.clear();
767 QVector<int> oldToNewVerticesIndexes;
768 if ( !renumberVertices( oldToNewVerticesIndexes ) )
772 QVector<int> oldToNewFacesIndexes;
774 if ( !renumberFaces( oldToNewFacesIndexes ) )
779 QVector<QgsMeshVertex> tempVertices( mMesh->
vertices.count() );
780 for (
int i = 0; i < oldToNewVerticesIndexes.count(); ++i )
782 tempVertices[oldToNewVerticesIndexes.at( i )] = mMesh->
vertex( i );
786 QVector<QgsMeshFace> tempFaces( mMesh->
faces.count() );
787 for (
int i = 0; i < oldToNewFacesIndexes.count(); ++i )
789 tempFaces[oldToNewFacesIndexes.at( i )] = mMesh->
face( i );
791 QgsMeshFace &face = tempFaces[oldToNewFacesIndexes.at( i )];
793 for (
int fi = 0; fi < face.count(); ++fi )
795 face[fi] = oldToNewVerticesIndexes.at( face.at( fi ) );
799 mMesh->
faces = tempFaces;
805bool QgsTopologicalMesh::renumberVertices( QVector<int> &oldToNewIndex )
const
807 std::vector<QgsMeshVertexCirculator> circulators;
808 circulators.reserve( mMesh->
vertices.count() );
809 int minDegree = std::numeric_limits<int>::max();
810 int minDegreeVertex = -1;
813 QSet<int> nonThreadedVertex;
814 oldToNewIndex = QVector<int> ( mMesh->
vertexCount(), -1 );
817 circulators.emplace_back( *
this, i );
819 if ( circulators.back().degree() < minDegree )
821 minDegreeVertex = circulators.size() - 1;
822 minDegree = circulator.
degree();
824 nonThreadedVertex.insert( i );
827 auto sortedNeighbor = [ = ]( QList<int> &neighbors,
int index )
841 int degree = circulators.at( neighborIndex ).degree();
842 QList<int>::Iterator it = neighbors.begin();
843 while ( it != neighbors.end() )
845 if ( degree <= circulators.at( *it ).degree() )
847 neighbors.insert( it, neighborIndex );
852 if ( it == neighbors.end() )
853 neighbors.append( neighborIndex );
859 int currentVertex = minDegreeVertex;
860 nonThreadedVertex.remove( minDegreeVertex );
862 while ( newIndex < mMesh->vertexCount() )
864 if ( oldToNewIndex[currentVertex] == -1 )
865 oldToNewIndex[currentVertex] = newIndex++;
867 if ( circulators.at( currentVertex ).isValid() )
869 QList<int> neighbors;
870 sortedNeighbor( neighbors, currentVertex );
872 for (
const int i : std::as_const( neighbors ) )
873 if ( oldToNewIndex.at( i ) == -1 && nonThreadedVertex.contains( i ) )
876 nonThreadedVertex.remove( i );
880 if ( queue.isEmpty() )
882 if ( nonThreadedVertex.isEmpty() && newIndex < mMesh->vertexCount() )
885 const QList<int> remainingVertex( nonThreadedVertex.constBegin(), nonThreadedVertex.constEnd() );
886 int minRemainingDegree = std::numeric_limits<int>::max();
887 int minRemainingVertex = -1;
888 for (
const int i : remainingVertex )
890 int degree = circulators.at( i ).degree();
891 if ( degree < minRemainingDegree )
893 minRemainingDegree = degree;
894 minRemainingVertex = i;
897 currentVertex = minRemainingVertex;
898 nonThreadedVertex.remove( currentVertex );
902 currentVertex = queue.dequeue();
909bool QgsTopologicalMesh::renumberFaces( QVector<int> &oldToNewIndex )
const
912 QSet<int> nonThreadedFaces;
914 oldToNewIndex = QVector<int>( mMesh->
faceCount(), -1 );
916 QVector<int> faceDegrees( mMesh->
faceCount(), 0 );
918 int minDegree = std::numeric_limits<int>::max();
919 int minDegreeFace = -1;
920 for (
int faceIndex = 0; faceIndex < mMesh->
faceCount(); ++faceIndex )
922 const FaceNeighbors &neighbors = mFacesNeighborhood.at( faceIndex );
925 for (
int n = 0; n < neighbors.size(); ++n )
927 if ( neighbors.at( n ) != -1 )
931 if ( degree < minDegree )
934 minDegreeFace = faceIndex;
937 faceDegrees[faceIndex] = degree;
938 nonThreadedFaces.insert( faceIndex );
942 int currentFace = minDegreeFace;
943 nonThreadedFaces.remove( minDegreeFace );
945 auto sortedNeighbor = [
this, faceDegrees]( QList<int> &neighbors,
int index )
947 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( index );
949 for (
int i = 0; i < neighborhood.count(); ++i )
951 int neighborIndex = neighborhood.at( i );
952 if ( neighborIndex == -1 )
955 int degree = faceDegrees.at( neighborIndex );
956 if ( neighbors.isEmpty() )
957 neighbors.append( neighborIndex );
960 QList<int>::Iterator it = neighbors.begin();
961 while ( it != neighbors.end() )
963 if ( degree <= faceDegrees.at( *it ) )
965 neighbors.insert( it, neighborIndex );
970 if ( it == neighbors.end() )
971 neighbors.append( neighborIndex );
976 while ( newIndex < mMesh->faceCount() )
978 if ( oldToNewIndex[currentFace] == -1 )
979 oldToNewIndex[currentFace] = newIndex++;
981 QList<int> neighbors;
982 sortedNeighbor( neighbors, currentFace );
984 for (
const int i : std::as_const( neighbors ) )
985 if ( oldToNewIndex.at( i ) == -1 && nonThreadedFaces.contains( i ) )
988 nonThreadedFaces.remove( i );
991 if ( queue.isEmpty() )
993 if ( nonThreadedFaces.isEmpty() && newIndex < mMesh->faceCount() )
996 const QList<int> remainingFace( nonThreadedFaces.constBegin(), nonThreadedFaces.constEnd() );
997 int minRemainingDegree = std::numeric_limits<int>::max();
998 int minRemainingFace = -1;
999 for (
const int i : remainingFace )
1001 int degree = faceDegrees.at( i );
1002 if ( degree < minRemainingDegree )
1004 minRemainingDegree = degree;
1005 minRemainingFace = i;
1008 currentFace = minRemainingFace;
1009 nonThreadedFaces.remove( currentFace );
1013 currentFace = queue.dequeue();
1028 return mFacesToRemove;
1033 return mFaceIndexesToRemove;
1038 return mVerticesToAdd;
1043 return mChangeCoordinateVerticesIndexes;
1053 return mNewXYValues;
1058 return mOldXYValues;
1063 return mNativeFacesIndexesGeometryChanged;
1068 return ( mFaceIndexesToRemove.isEmpty() &&
1069 mFacesToAdd.isEmpty() &&
1070 mFacesNeighborhoodToAdd.isEmpty() &&
1071 mFacesToRemove.isEmpty() &&
1072 mFacesNeighborhoodToRemove.isEmpty() &&
1073 mNeighborhoodChanges.isEmpty() &&
1074 mVerticesToAdd.isEmpty() &&
1075 mVertexToFaceToAdd.isEmpty() &&
1076 mVerticesToRemoveIndexes.isEmpty() &&
1077 mRemovedVertices.isEmpty() &&
1078 mVerticesToFaceRemoved.isEmpty() &&
1079 mVerticesToFaceChanges.isEmpty() &&
1080 mChangeCoordinateVerticesIndexes.isEmpty() &&
1081 mNewZValues.isEmpty() &&
1082 mOldZValues.isEmpty() &&
1083 mNewXYValues.isEmpty() &&
1084 mOldXYValues.isEmpty() &&
1085 mNativeFacesIndexesGeometryChanged.isEmpty() );
1090 return mVerticesToRemoveIndexes;
1093int QgsTopologicalMesh::Changes::addedFaceIndexInMesh(
int internalIndex )
const
1095 if ( internalIndex == -1 )
1098 return internalIndex + mAddedFacesFirstIndex;
1101int QgsTopologicalMesh::Changes::removedFaceIndexInMesh(
int internalIndex )
const
1103 if ( internalIndex == -1 )
1106 return mFaceIndexesToRemove.at( internalIndex );
1111 mAddedFacesFirstIndex = 0;
1112 mFaceIndexesToRemove.clear();
1113 mFacesToAdd.clear();
1114 mFacesNeighborhoodToAdd.clear();
1115 mFacesToRemove.clear();
1116 mFacesNeighborhoodToRemove.clear();
1117 mNeighborhoodChanges.clear();
1119 mVerticesToAdd.clear();
1120 mVertexToFaceToAdd.clear();
1121 mVerticesToRemoveIndexes.clear();
1122 mRemovedVertices.clear();
1123 mVerticesToFaceRemoved.clear();
1124 mVerticesToFaceChanges.clear();
1126 mChangeCoordinateVerticesIndexes.clear();
1127 mNewZValues.clear();
1128 mOldZValues.clear();
1129 mNewXYValues.clear();
1130 mOldXYValues.clear();
1131 mNativeFacesIndexesGeometryChanged.clear();
1141 mVertexToFace.append( -1 );
1142 referenceAsFreeVertex( mMesh->
vertices.count() - 1 );
1148static double vertexPolygonOrientation(
const QgsMesh &
mesh,
const QList<int> &vertexIndexes )
1150 if ( vertexIndexes.count() < 3 )
1153 int hullDomainVertexPos = -1;
1154 double xMin = std::numeric_limits<double>::max();
1155 double yMin = std::numeric_limits<double>::max();
1156 for (
int i = 0; i < vertexIndexes.count(); ++i )
1159 if ( xMin >= vertex.
x() && yMin > vertex.
y() )
1161 hullDomainVertexPos = i;
1167 if ( hullDomainVertexPos >= 0 )
1169 int iv1 = vertexIndexes.at( ( hullDomainVertexPos - 1 + vertexIndexes.count() ) % vertexIndexes.count() );
1170 int iv2 = vertexIndexes.at( ( hullDomainVertexPos + 1 ) % vertexIndexes.count() );
1171 int ivc = vertexIndexes.at( ( hullDomainVertexPos ) );
1172 double cp = crossProduct( ivc, iv1, iv2,
mesh );
1181 if ( vertexIndex >= mVertexToFace.count() )
1184 if ( mVertexToFace.at( vertexIndex ) == -1 )
1190 dereferenceAsFreeVertex( vertexIndex );
1198 QList<int> boundariesVertexIndex;
1199 QList<int> associateFaceToBoundaries;
1200 QList<int> removedFacesIndexes;
1201 QSet<int> boundaryInGlobalMesh;
1207 Q_ASSERT( !mMesh->
vertices.at( boundariesVertexIndex.last() ).isEmpty() );
1209 associateFaceToBoundaries.append( mFacesNeighborhood.at( circulator.
currentFaceIndex() ).at(
1212 if ( currentFace.count() > 3 )
1215 for (
int i = 2; i < currentFace.count() - 1; ++i )
1217 boundariesVertexIndex.append( currentFace.at( ( posInface + i ) % currentFace.count() ) );
1218 Q_ASSERT( !mMesh->
vertices.at( boundariesVertexIndex.last() ).isEmpty() );
1219 associateFaceToBoundaries.append( mFacesNeighborhood.at( circulator.
currentFaceIndex() ).at(
1226 bool boundaryFill =
false;
1229 boundaryFill =
true;
1233 boundariesVertexIndex.append( lastVertexIndex );
1242 boundaryFill =
false;
1245 associateFaceToBoundaries.append( -1 );
1247 for (
const int index : std::as_const( boundariesVertexIndex ) )
1250 boundaryInGlobalMesh.insert( index );
1254 int currentVertexToFace = mVertexToFace.at( vertexIndex );
1258 QList<QList<int>> holes;
1259 QList<QList<int>> associateMeshFacesToHoles;
1261 bool cancelOperation =
false;
1269 int finalPos = boundariesVertexIndex.count() - 1;
1270 QList<int> uncoveredVertex;
1272 QList<int> partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1273 QList<int> associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1274 while ( startPos < finalPos && !partToCheck.isEmpty() )
1277 int secondPos = partToCheck.count() - 1;
1278 const QgsPoint &closingSegmentExtremety1 = mMesh->
vertex( partToCheck.at( 0 ) );
1279 const QgsPoint &closingSegmentExtremety2 = mMesh->
vertex( partToCheck.last() );
1280 bool isEdgeIntersect =
false;
1281 for (
int i = 1; i < secondPos - 1; ++i )
1285 bool isLineIntersection;
1288 if ( isEdgeIntersect )
1292 int index = partToCheck.at( 0 );
1293 if ( boundaryInGlobalMesh.contains( index ) && index != boundariesVertexIndex.at( 0 ) )
1295 cancelOperation =
true;
1301 if ( isEdgeIntersect || vertexPolygonOrientation( *mMesh, partToCheck ) >= 0 )
1303 partToCheck.removeLast();
1304 associateFacePart.removeAt( associateFacePart.count() - 2 );
1305 if ( partToCheck.count() == 1 )
1307 uncoveredVertex.append( index );
1308 startPos = startPos + 1;
1309 partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1310 associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1316 holes.append( partToCheck );
1317 associateMeshFacesToHoles.append( associateFacePart );
1319 startPos = startPos + partToCheck.count() - 1;
1320 uncoveredVertex.append( partToCheck.at( 0 ) );
1321 partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1322 associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1328 holes.append( boundariesVertexIndex );
1329 associateMeshFacesToHoles.append( associateFaceToBoundaries );
1332 if ( cancelOperation )
1338 Q_ASSERT( holes.count() == associateMeshFacesToHoles.count() );
1344 dereferenceAsFreeVertex( vertexIndex );
1346 mVertexToFace[vertexIndex] = -1;
1349 for (
int h = 0; h < holes.count(); ++h )
1351 const QList<int> &holeVertices = holes.at( h );
1352 const QList<int> &associateMeshFacesToHole = associateMeshFacesToHoles.at( h );
1353 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
1354 std::vector<p2t::Point *> holeToFill( holeVertices.count() );
1357 for (
int i = 0; i < holeVertices.count(); ++i )
1360 holeToFill[i] =
new p2t::Point( vertex.
x(), vertex.
y() );
1361 mapPoly2TriPointToVertex.insert( holeToFill[i], holeVertices.at( i ) );
1364 std::unique_ptr<p2t::CDT> cdt(
new p2t::CDT( holeToFill ) );
1367 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
1368 QVector<QgsMeshFace> newFaces( triangles.size() );
1369 for (
size_t i = 0; i < triangles.size(); ++i )
1373 for (
int j = 0; j < 3; j++ )
1375 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
1376 if ( vertInd == -1 )
1377 throw std::exception();
1378 Q_ASSERT( !mMesh->
vertices.at( vertInd ).isEmpty() );
1386 throw std::exception();
1387 int newFaceIndexStartIndex = mMesh->
faceCount();
1394 const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
1395 for (
const int vtc : verticesToFaceToChange )
1396 if ( mVertexToFace.at( vtc ) == -1 )
1398 mVertexToFace.at( vtc ),
1399 addChanges.addedFaceIndexInMesh( topologicalFaces.mVerticesToFace.values( vtc ).first() )
1404 for (
int i = 0; i < topologicalFaces.mFaces.count(); ++i )
1406 FaceNeighbors &faceNeighbors = addChanges.mFacesNeighborhoodToAdd[i];
1407 faceNeighbors = topologicalFaces.mFacesNeighborhood.at( i );
1408 for (
int n = 0; n < faceNeighbors.count(); ++n )
1410 if ( faceNeighbors.at( n ) != -1 )
1411 faceNeighbors[n] += newFaceIndexStartIndex;
1416 for (
int i = 0 ; i < holeVertices.count(); ++i )
1418 int vertexHoleIndex = holeVertices.at( i );
1419 int meshFaceBoundaryIndex = associateMeshFacesToHole.at( i );
1424 int newFaceBoundaryIndexInMesh = circulator.
currentFaceIndex() + newFaceIndexStartIndex;
1428 if ( meshFaceBoundaryIndex != -1 )
1431 int positionInMeshFaceBoundary =
vertexPositionInFace( *mMesh, vertexHoleIndex, meshFaceBoundaryIndex );
1432 positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.count() ) % meshFace.count();
1434 addChanges.mNeighborhoodChanges.append( {meshFaceBoundaryIndex, positionInMeshFaceBoundary, -1, newFaceBoundaryIndexInMesh} );
1437 addChanges.mFacesNeighborhoodToAdd[newFaceBoundaryLocalIndex][positionInNewFaces] = meshFaceBoundaryIndex;
1442 changes.
mFacesToAdd.append( addChanges.mFacesToAdd );
1445 for (
const std::array<int, 4> &neighborChangeToAdd : std::as_const( addChanges.mNeighborhoodChanges ) )
1447 bool merged =
false;
1450 if ( existingNeighborChange.at( 0 ) == neighborChangeToAdd.at( 0 ) &&
1451 existingNeighborChange.at( 1 ) == neighborChangeToAdd.at( 1 ) )
1454 Q_ASSERT( existingNeighborChange.at( 3 ) == neighborChangeToAdd.at( 2 ) );
1455 existingNeighborChange[3] = neighborChangeToAdd.at( 3 );
1462 for (
const std::array<int, 3> &verticesToFaceToAdd : std::as_const( addChanges.mVerticesToFaceChanges ) )
1464 bool merged =
false;
1467 if ( existingVerticesToFace.at( 0 ) == verticesToFaceToAdd.at( 0 ) )
1470 Q_ASSERT( existingVerticesToFace.at( 2 ) == verticesToFaceToAdd.at( 1 ) );
1471 existingVerticesToFace[2] = verticesToFaceToAdd.at( 2 );
1478 qDeleteAll( holeToFill );
1482 qDeleteAll( holeToFill );
1486 changes.mAddedFacesFirstIndex = oldFacesCount;
1490 changes.mAddedFacesFirstIndex = oldFacesCount;
1497 QSet<int> facesIndex;
1499 for (
int vertexIndex : vertices )
1502 facesIndex.unite( QSet< int >( faces.begin(), faces.end() ) );
1509 for (
int vertexIndex : vertices )
1511 int currentVertexToFace = mVertexToFace.at( vertexIndex );
1517 dereferenceAsFreeVertex( vertexIndex );
1519 mVertexToFace[vertexIndex] = -1;
1527 QList<int> boundariesToCheckClockwiseInNewFaces = topologicFaces.mBoundaries;
1528 QList<std::array<int, 2>> boundariesToCheckCounterClockwiseInNewFaces;
1529 QList<int> uniqueSharedVertexBoundary;
1537 while ( !boundariesToCheckClockwiseInNewFaces.isEmpty() )
1539 int boundary = boundariesToCheckClockwiseInNewFaces.takeLast();
1541 const QList<int> &linkedFaces = topologicFaces.mVerticesToFace.values( boundary );
1543 for (
int const linkedFace : linkedFaces )
1547 if ( mVertexToFace.at( boundary ) == -1 )
1553 if ( !newFacescirculator.
isValid() )
1567 if ( oppositeVertexCCWInMesh == oppositeVertexInNewFaces )
1573 int faceSize = newFaceOnBoundary.size();
1575 int previousVertexIndex = ( posInNewFace + faceSize - 1 ) % faceSize;
1576 if ( newFaceOnBoundary.at( previousVertexIndex ) == oppositeVertexCCWInMesh )
1584 if ( oppositeVertexCWInMesh == oppositeVertexInNewFaces )
1588 boundariesToCheckCounterClockwiseInNewFaces.append( {boundary, linkedFace} );
1593 while ( !boundariesToCheckCounterClockwiseInNewFaces.isEmpty() )
1595 std::array<int, 2> boundaryLinkedface = boundariesToCheckCounterClockwiseInNewFaces.takeLast();
1596 int boundary = boundaryLinkedface.at( 0 );
1597 int linkedFace = boundaryLinkedface.at( 1 );
1612 if ( oppositeVertexCWInMesh == oppositeVertexInNewFaces )
1619 if ( oppositeVertexCCWInMesh == oppositeVertexInNewFaces )
1622 uniqueSharedVertexBoundary.append( boundary );
1625 if ( !uniqueSharedVertexBoundary.isEmpty() )
1629 QSet<int> boundaryVertices( topologicFaces.mBoundaries.constBegin(), topologicFaces.mBoundaries.constEnd() );
1630 for (
const QgsMeshFace &newFace : std::as_const( topologicFaces.mFaces ) )
1632 for (
const int vertexIndex : newFace )
1634 if ( boundaryVertices.contains( vertexIndex ) )
1636 if ( mVertexToFace.at( vertexIndex ) != -1 )
1647 mFacesNeighborhood.clear();
1648 mVerticesToFace.clear();
1649 mBoundaries.clear();
1654 return mFacesNeighborhood;
1659 if ( mVerticesToFace.contains( vertexIndex ) )
1660 return mVerticesToFace.values( vertexIndex ).at( 0 );
1668 topologicMesh.mMesh =
mesh;
1669 topologicMesh.mVertexToFace = QVector<int>(
mesh->
vertexCount(), -1 );
1670 topologicMesh.mMaximumVerticesPerFace = maxVerticesPerFace;
1677 if ( maxVerticesPerFace != 0 &&
mesh->
face( i ).count() > maxVerticesPerFace )
1695 topologicMesh.mFacesNeighborhood = subMesh.mFacesNeighborhood;
1697 for (
int i = 0; i < topologicMesh.mMesh->
vertexCount(); ++i )
1699 if ( topologicMesh.mVertexToFace.at( i ) == -1 )
1700 topologicMesh.mFreeVertices.insert( i );
1704 return topologicMesh;
1709 return createTopologicalFaces( faces,
nullptr, error, uniqueSharedVertexAllowed );
1714 const QVector<QgsMeshFace> &faces,
1715 QVector<int> *globalVertexToFace,
1717 bool allowUniqueSharedVertex )
1719 int facesCount = faces.count();
1720 QVector<FaceNeighbors> faceTopologies;
1721 QMultiHash<int, int> verticesToFace;
1724 TopologicalFaces ret;
1728 QMap<int, QMap<int, int>> verticesToNeighbor;
1730 for (
int faceIndex = 0; faceIndex < facesCount; ++faceIndex )
1733 int faceSize = face.count();
1735 for (
int i = 0; i < faceSize; ++i )
1737 int v1 = face[i % faceSize];
1738 int v2 = face[( i + 1 ) % faceSize];
1739 if ( verticesToNeighbor[v2].contains( v1 ) )
1745 verticesToNeighbor[v2].insert( v1, faceIndex );
1749 faceTopologies = QVector<FaceNeighbors>( faces.count() );
1751 QSet<int> boundaryVertices;
1753 for (
int faceIndex = 0; faceIndex < facesCount; ++faceIndex )
1756 int faceSize = face.size();
1758 faceTopology.resize( faceSize );
1760 for (
int i = 0; i < faceSize; ++i )
1762 int v1 = face.at( i );
1763 int v2 = face.at( ( i + 1 ) % faceSize );
1765 if ( globalVertexToFace )
1767 if ( ( *globalVertexToFace )[v1] == -1 )
1768 ( *globalVertexToFace )[v1] = faceIndex ;
1772 if ( allowUniqueSharedVertex || !verticesToFace.contains( v1 ) )
1773 verticesToFace.insert( v1, faceIndex ) ;
1776 QMap<int, int> &edges = verticesToNeighbor[v1];
1777 if ( edges.contains( v2 ) )
1778 faceTopology[i] = edges.value( v2 );
1781 faceTopology[i] = -1;
1783 if ( !allowUniqueSharedVertex )
1785 if ( boundaryVertices.contains( v1 ) )
1791 boundaryVertices.insert( v1 );
1797 ret.mFacesNeighborhood = faceTopologies;
1798 ret.mBoundaries = boundaryVertices.values();
1799 ret.mVerticesToFace = verticesToFace;
1805 return mFacesNeighborhood.at( faceIndex );
1817 QSet<int> removedFaces( facesIndexes.begin(), facesIndexes.end() );
1818 QSet<int> concernedFaces = concernedFacesBy( facesIndexes );
1820 for (
const int f : std::as_const( removedFaces ) )
1821 concernedFaces.remove( f );
1823 QVector<QgsMeshFace> remainingFaces;
1824 remainingFaces.reserve( concernedFaces.count() );
1825 for (
const int f : std::as_const( concernedFaces ) )
1826 remainingFaces.append( mMesh->
face( f ) );
1829 createTopologicalFaces( remainingFaces,
nullptr, error,
false );
1841 QSet<int> indexSet( facesIndexesToRemove.begin(), facesIndexesToRemove.end() );
1842 QSet<int> threatedVertex;
1844 for (
int i = 0; i < facesIndexesToRemove.count(); ++i )
1846 const int faceIndex = facesIndexesToRemove.at( i );
1849 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( faceIndex );
1851 for (
int j = 0; j < face.count(); ++j )
1854 int neighborIndex = neighborhood.at( j );
1855 if ( neighborIndex != -1 && !indexSet.contains( neighborIndex ) )
1857 int positionInNeighbor = mFacesNeighborhood.at( neighborIndex ).indexOf( faceIndex );
1862 int vertexIndex = face.at( j );
1863 if ( !threatedVertex.contains( vertexIndex ) && indexSet.contains( mVertexToFace.at( vertexIndex ) ) )
1865 int oldValue = mVertexToFace.at( vertexIndex );
1868 if ( neighborIndex != -1 && !indexSet.contains( neighborIndex ) )
1869 refValue = neighborIndex;
1873 aroundFaces.removeOne( faceIndex );
1874 if ( !aroundFaces.isEmpty() )
1876 while ( !aroundFaces.isEmpty() && refValue == -1 )
1878 if ( !indexSet.contains( aroundFaces.first() ) )
1879 refValue = aroundFaces.first();
1881 aroundFaces.removeFirst();
1886 threatedVertex.insert( vertexIndex );
1896bool QgsTopologicalMesh::eitherSideFacesAndVertices(
int vertexIndex1,
1900 int &neighborVertex1InFace1,
1901 int &neighborVertex1InFace2,
1902 int &neighborVertex2inFace1,
1903 int &neighborVertex2inFace2 )
const
1945 int oppositeVertexFace1;
1946 int oppositeVertexFace2;
1947 int supposedOppositeVertexFace1;
1948 int supposedoppositeVertexFace2;
1950 bool result = eitherSideFacesAndVertices(
1955 oppositeVertexFace1,
1956 supposedoppositeVertexFace2,
1957 supposedOppositeVertexFace1,
1958 oppositeVertexFace2 );
1963 oppositeVertexFace1 < 0 ||
1964 oppositeVertexFace2 < 0 ||
1965 supposedOppositeVertexFace1 != oppositeVertexFace1 ||
1966 supposedoppositeVertexFace2 != oppositeVertexFace2 )
1973 if ( face1.count() != 3 || face2.count() != 3 )
1976 double crossProduct1 = crossProduct( vertexIndex1, oppositeVertexFace1, oppositeVertexFace2, *mMesh );
1977 double crossProduct2 = crossProduct( vertexIndex2, oppositeVertexFace1, oppositeVertexFace2, *mMesh );
1979 return crossProduct1 * crossProduct2 < 0;
1986 int oppositeVertexFace1;
1987 int oppositeVertexFace2;
1988 int supposedOppositeVertexFace1;
1989 int supposedoppositeVertexFace2;
1991 bool result = eitherSideFacesAndVertices(
1996 oppositeVertexFace1,
1997 supposedoppositeVertexFace2,
1998 supposedOppositeVertexFace1,
1999 oppositeVertexFace2 );
2004 oppositeVertexFace1 < 0 ||
2005 oppositeVertexFace2 < 0 ||
2006 supposedOppositeVertexFace1 != oppositeVertexFace1 ||
2007 supposedoppositeVertexFace2 != oppositeVertexFace2 )
2016 Q_ASSERT( face1.count() == 3 );
2017 Q_ASSERT( face2.count() == 3 );
2022 int neighborFace1 = mFacesNeighborhood.at( faceIndex1 ).at( pos1 );
2024 int neighborFace2 = mFacesNeighborhood.at( faceIndex1 ).at( ( pos1 + 1 ) % 3 );
2026 int neighborFace3 = mFacesNeighborhood.at( faceIndex2 ).at( pos2 );
2028 int neighborFace4 = mFacesNeighborhood.at( faceIndex2 ).at( ( pos2 + 1 ) % 3 );
2039 changes.
mFacesToAdd.append( {oppositeVertexFace1, oppositeVertexFace2, vertexIndex1} );
2040 changes.
mFacesToAdd.append( {oppositeVertexFace2, oppositeVertexFace1, vertexIndex2} );
2042 mFacesNeighborhood.at( faceIndex2 ).at( ( pos2 + 1 ) % 3 ),
2043 mFacesNeighborhood.at( faceIndex1 ).at( pos1 )
2046 mFacesNeighborhood.at( faceIndex1 ).at( ( pos1 + 1 ) % 3 ),
2047 mFacesNeighborhood.at( faceIndex2 ).at( pos2 )
2050 if ( neighborFace1 >= 0 )
2051 changes.
mNeighborhoodChanges.append( {neighborFace1, posInNeighbor1, faceIndex1, startIndex} );
2052 if ( neighborFace2 >= 0 )
2053 changes.
mNeighborhoodChanges.append( {neighborFace2, posInNeighbor2, faceIndex1, startIndex + 1} );
2054 if ( neighborFace3 >= 0 )
2055 changes.
mNeighborhoodChanges.append( {neighborFace3, posInNeighbor3, faceIndex2, startIndex + 1} );
2056 if ( neighborFace4 >= 0 )
2057 changes.
mNeighborhoodChanges.append( {neighborFace4, posInNeighbor4, faceIndex2, startIndex} );
2060 if ( mVertexToFace.at( vertexIndex1 ) == faceIndex1 || mVertexToFace.at( vertexIndex1 ) == faceIndex2 )
2062 if ( mVertexToFace.at( vertexIndex2 ) == faceIndex1 || mVertexToFace.at( vertexIndex2 ) == faceIndex2 )
2063 changes.
mVerticesToFaceChanges.append( {vertexIndex2, mVertexToFace.at( vertexIndex2 ), startIndex + 1} );
2065 if ( mVertexToFace.at( oppositeVertexFace1 ) == faceIndex1 )
2068 if ( mVertexToFace.at( oppositeVertexFace2 ) == faceIndex2 )
2080 int neighborVertex1InFace1;
2081 int neighborVertex1InFace2;
2082 int neighborVertex2inFace1;
2083 int neighborVertex2inFace2;
2085 bool result = eitherSideFacesAndVertices(
2090 neighborVertex1InFace1,
2091 neighborVertex1InFace2,
2092 neighborVertex2inFace1,
2093 neighborVertex2inFace2 );
2103 if ( face1.count() + face2.count() - 2 > mMaximumVerticesPerFace )
2113 double crossProduct1 = crossProduct( vertexIndex1, neighborVertex1InFace1, neighborVertex1InFace2, *mMesh );
2114 double crossProduct2 = crossProduct( vertexIndex2, neighborVertex2inFace1, neighborVertex2inFace2, *mMesh );
2116 return crossProduct1 * crossProduct2 < 0;
2123 int neighborVertex1InFace1;
2124 int neighborVertex1InFace2;
2125 int neighborVertex2inFace1;
2126 int neighborVertex2inFace2;
2128 bool result = eitherSideFacesAndVertices(
2133 neighborVertex1InFace1,
2134 neighborVertex1InFace2,
2135 neighborVertex2inFace1,
2136 neighborVertex2inFace2 );
2147 int faceSize1 = face1.count();
2148 int faceSize2 = face2.count();
2164 for (
int i = 0; i < faceSize1 - 1; ++i )
2166 int currentPos = ( pos1 + i ) % faceSize1;
2167 newface.append( face1.at( currentPos ) );
2169 int currentNeighbor = mFacesNeighborhood.at( faceIndex1 ).at( currentPos );
2170 newNeighborhood.append( currentNeighbor );
2172 if ( currentNeighbor != -1 )
2175 changes.
mNeighborhoodChanges.append( {currentNeighbor, currentPosInNeighbor, faceIndex1, startIndex} );
2178 for (
int i = 0; i < faceSize2 - 1; ++i )
2180 int currentPos = ( pos2 + i ) % faceSize2;
2181 newface.append( face2.at( currentPos ) );
2183 int currentNeighbor = mFacesNeighborhood.at( faceIndex2 ).at( currentPos );
2184 newNeighborhood.append( currentNeighbor );
2186 if ( currentNeighbor != -1 )
2189 changes.
mNeighborhoodChanges.append( {currentNeighbor, currentPosInNeighbor, faceIndex2, startIndex} );
2193 for (
int i = 0; i < faceSize1; ++i )
2194 if ( mVertexToFace.at( face1.at( i ) ) == faceIndex1 )
2197 for (
int i = 0; i < faceSize2; ++i )
2198 if ( mVertexToFace.at( face2.at( i ) ) == faceIndex2 )
2213 return face.count() == 4;
2220 int faceSize = face.count();
2222 Q_ASSERT( faceSize == 4 );
2224 double maxAngle = 0;
2225 int splitVertexPos = -1;
2226 for (
int i = 0; i < faceSize; ++i )
2228 QgsVector vect1( mMesh->
vertex( face.at( i ) ) - mMesh->
vertex( face.at( ( i + 1 ) % faceSize ) ) );
2229 QgsVector vect2( mMesh->
vertex( face.at( ( i + 2 ) % faceSize ) ) - mMesh->
vertex( face.at( ( i + 1 ) % faceSize ) ) );
2231 double angle = std::abs( vect1.
angle( vect2 ) );
2232 angle = std::min( angle, 2.0 * M_PI - angle );
2233 if ( angle > maxAngle )
2236 splitVertexPos = ( i + 1 ) % faceSize;
2241 if ( splitVertexPos == -1 )
2244 const QgsMeshFace newFace1 = {face.at( splitVertexPos ),
2245 face.at( ( splitVertexPos + 1 ) % faceSize ),
2246 face.at( ( splitVertexPos + 2 ) % faceSize )
2249 const QgsMeshFace newFace2 = {face.at( splitVertexPos ),
2250 face.at( ( splitVertexPos + 2 ) % faceSize ),
2251 face.at( ( splitVertexPos + 3 ) % faceSize )
2254 QVector<int> neighborIndex( faceSize );
2255 QVector<int> posInNeighbor( faceSize );
2257 for (
int i = 0; i < faceSize; ++i )
2259 neighborIndex[i] = mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + i ) % faceSize );
2272 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 1 ) % faceSize ),
2276 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 2 ) % faceSize ),
2277 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 3 ) % faceSize )
2280 for (
int i = 0; i < faceSize; ++i )
2282 if ( neighborIndex[i] >= 0 )
2283 changes.
mNeighborhoodChanges.append( {neighborIndex[i], posInNeighbor[i], faceIndex, startIndex + int( i / 2 )} );
2285 int vertexIndex = face.at( ( splitVertexPos + i ) % faceSize );
2286 if ( mVertexToFace.at( vertexIndex ) == faceIndex )
2303 mVertexToFace.append( -1 );
2307 const FaceNeighbors includingFaceNeighborhood = mFacesNeighborhood.at( includingFaceIndex );
2308 int includingFaceSize = includingFace.count();
2310 for (
int i = 0; i < includingFaceSize; ++i )
2315 face[1] = includingFace.at( i );
2316 face[2] = includingFace.at( ( i + 1 ) % includingFaceSize );
2317 mMesh->
faces.append( face );
2320 int currentVertexIndex = includingFace.at( i );
2321 if ( mVertexToFace.at( currentVertexIndex ) == includingFaceIndex )
2323 int newFaceIndex = mMesh->
faceCount() - 1;
2324 mVertexToFace[currentVertexIndex] = newFaceIndex;
2328 int includingFaceNeighbor = includingFaceNeighborhood.at( i );
2332 includingFaceNeighbor,
2335 mFacesNeighborhood.append( neighbors );
2338 if ( includingFaceNeighbor != -1 )
2341 int oldValue = mFacesNeighborhood[includingFaceNeighbor][indexInNeighbor];
2353 mVertexToFace[mVertexToFace.count() - 1] = mMesh->
faceCount() - 1;
2368 int newVertexPositionInFace1 = position + 1;
2370 auto triangulate = [
this, &changes](
int removedFaceIndex,
const QgsMeshVertex & newVertex,
int newVertexPosition, QVector<int> &edgeFacesIndexes )->
bool
2376 const int addedVertexIndex = mMesh->
vertexCount();
2379 int localStartIndex = changes.
mFacesToAdd.count();
2381 QVector<int> newBoundary = initialFace;
2382 newBoundary.insert( newVertexPosition, addedVertexIndex );
2386 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
2387 std::vector<p2t::Point *> faceToFill( newBoundary.count() );
2388 for (
int i = 0; i < newBoundary.count(); ++i )
2392 if ( newBoundary.at( i ) == addedVertexIndex )
2395 vert = mMesh->
vertex( newBoundary.at( i ) );
2397 faceToFill[i] =
new p2t::Point( vert.
x(), vert.
y() );
2398 mapPoly2TriPointToVertex.insert( faceToFill[i], newBoundary.at( i ) );
2401 std::unique_ptr<p2t::CDT> cdt(
new p2t::CDT( faceToFill ) );
2403 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
2404 QVector<QgsMeshFace> newFaces( triangles.size() );
2405 for (
size_t i = 0; i < triangles.size(); ++i )
2409 for (
int j = 0; j < 3; j++ )
2411 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
2412 if ( vertInd == -1 )
2413 throw std::exception();
2421 throw std::exception();
2427 const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
2428 for (
const int vtc : verticesToFaceToChange )
2429 if ( vtc != addedVertexIndex && mVertexToFace.at( vtc ) == removedFaceIndex )
2434 topologicalFaces.
vertexToFace( vtc ) + faceStartGlobalIndex
2438 for (
int i = 0; i < topologicalFaces.mFaces.count(); ++i )
2441 for (
int n = 0; n < faceNeighbors.count(); ++n )
2443 if ( faceNeighbors.at( n ) != -1 )
2444 faceNeighbors[n] += faceStartGlobalIndex;
2448 edgeFacesIndexes.resize( 2 );
2450 for (
int i = 0 ; i < newBoundary.count(); ++i )
2452 int vertexIndex = newBoundary.at( i );
2455 int newFaceBoundaryLocalIndex = localStartIndex + circulator.
currentFaceIndex();
2457 int newFaceBoundaryIndexInMesh = faceStartGlobalIndex;
2459 int meshFaceBoundaryIndex;
2460 if ( i == newVertexPosition )
2462 meshFaceBoundaryIndex = -1;
2463 edgeFacesIndexes[0] = newFaceBoundaryLocalIndex;
2465 else if ( i == ( newVertexPosition + newBoundary.count() - 1 ) % newBoundary.count() )
2467 meshFaceBoundaryIndex = -1;
2468 edgeFacesIndexes[1] = newFaceBoundaryLocalIndex;
2476 if ( meshFaceBoundaryIndex != -1 )
2480 positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.count() ) % meshFace.count();
2483 positionInMeshFaceBoundary,
2485 newFaceBoundaryIndexInMesh +
2493 qDeleteAll( faceToFill );
2503 QVector<int> edgeFacesIndexes;
2504 if ( !triangulate( faceIndex, vertexToInsert, newVertexPositionInFace1, edgeFacesIndexes ) )
2507 changes.mVertexToFaceToAdd.append( edgeFacesIndexes.at( 0 ) + changes.mAddedFacesFirstIndex );
2512 int face2Index = mFacesNeighborhood.at( faceIndex ).at( position );
2513 if ( face2Index != -1 )
2517 QVector<int> edgeFacesIndexesFace2;
2518 if ( !triangulate( face2Index, vertexToInsert, vertexPositionInFace2, edgeFacesIndexesFace2 ) )
2522 const QgsMeshFace &firstFaceSide1 = changes.mFacesToAdd.at( edgeFacesIndexes.at( 0 ) );
2525 const QgsMeshFace &secondFaceSide1 = changes.mFacesToAdd.at( edgeFacesIndexes.at( 1 ) );
2527 pos2InFaceSide1 = ( pos2InFaceSide1 + secondFaceSide1.size() - 1 ) % secondFaceSide1.size();
2529 const QgsMeshFace &firstFaceSide2 = changes.mFacesToAdd.at( edgeFacesIndexesFace2.at( 0 ) );
2532 const QgsMeshFace &secondFaceSide2 = changes.mFacesToAdd.at( edgeFacesIndexesFace2.at( 1 ) );
2534 pos2InFaceSide2 = ( pos2InFaceSide2 + secondFaceSide1.size() - 1 ) % secondFaceSide1.size();
2536 changes.mFacesNeighborhoodToAdd[edgeFacesIndexes.at( 0 )][pos1InFaceSide1] = edgeFacesIndexesFace2.at( 1 ) + changes.mAddedFacesFirstIndex;
2537 changes.mFacesNeighborhoodToAdd[edgeFacesIndexes.at( 1 )][pos2InFaceSide1] = edgeFacesIndexesFace2.at( 0 ) + changes.mAddedFacesFirstIndex;
2538 changes.mFacesNeighborhoodToAdd[edgeFacesIndexesFace2.at( 0 )][pos1InFaceSide2] = edgeFacesIndexes.at( 1 ) + changes.mAddedFacesFirstIndex;
2539 changes.mFacesNeighborhoodToAdd[edgeFacesIndexesFace2.at( 1 )][pos2InFaceSide2] = edgeFacesIndexes.at( 0 ) + changes.mAddedFacesFirstIndex;
2548 Q_ASSERT( verticesIndexes.count() == newValues.count() );
2551 changes.
mNewZValues.reserve( verticesIndexes.count() );
2552 changes.
mOldZValues.reserve( verticesIndexes.count() );
2553 for (
int i = 0; i < verticesIndexes.count(); ++i )
2567 Q_ASSERT( verticesIndexes.count() == newValues.count() );
2570 changes.
mNewXYValues.reserve( verticesIndexes.count() );
2571 changes.
mOldXYValues.reserve( verticesIndexes.count() );
2572 QSet<int> concernedFace;
2573 for (
int i = 0; i < verticesIndexes.count(); ++i )
2579 concernedFace.unite( QSet< int>( faces.begin(), faces.end() ) );
2593 int oppositeVertexFace1;
2594 int oppositeVertexFace2;
2595 int supposedOppositeVertexFace1;
2596 int supposedoppositeVertexFace2;
2598 bool result = eitherSideFacesAndVertices(
2603 oppositeVertexFace1,
2604 supposedoppositeVertexFace2,
2605 supposedOppositeVertexFace1,
2606 oppositeVertexFace2 );
2615 mMesh->
vertex( face1.at( 1 ) ),
2616 mMesh->
vertex( face1.at( 2 ) ) );
2617 bool circle1ContainsPoint = circle.
contains( mMesh->
vertex( supposedoppositeVertexFace2 ) );
2620 mMesh->
vertex( face2.at( 1 ) ),
2621 mMesh->
vertex( face2.at( 2 ) ) );
2622 bool circle2ContainsPoint = circle.
contains( mMesh->
vertex( supposedOppositeVertexFace1 ) );
2624 return !( circle1ContainsPoint || circle2ContainsPoint );
@ 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.
bool contains(const QgsPoint &point, double epsilon=1E-8) const
Returns true if the circle contains the point.
static QgsCircle from3Points(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double epsilon=1E-8)
Constructs a circle by 3 points on the circle.
static bool segmentIntersection(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q1, const QgsPoint &q2, QgsPoint &intersectionPoint, bool &isIntersection, double tolerance=1e-8, bool acceptImproperIntersection=false)
Compute the intersection between two segments.
Class that represents an error during mesh editing.
Qgis::MeshEditingErrorType errorType
Convenient class that turn around a vertex and provide information about faces and vertices.
bool isValid() const
Returns whether the vertex circulator is valid.
int turnClockwise() const
Turns counter clockwise around the vertex and returns the new current face, -1 if the circulator pass...
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...
int turnCounterClockwise() const
Turns counter clockwise around the vertex and returns the new current face, -1 if the circulator pass...
int currentFaceIndex() const
Returns the current face index, -1 if the circulator has passed a boundary or circulator is invalid.
bool goBoundaryClockwise() const
Sets the circulator on the boundary face turning clockwise, return false is there isn't boundary face...
QgsMeshFace currentFace() const
Returns the current face, empty face if the circulator pass a boundary or circulator is invalid.
QgsMeshVertexCirculator(const QgsTopologicalMesh &topologicalMesh, int vertexIndex)
Constructor with topologicalMesh and vertexIndex.
int oppositeVertexClockwise() const
Returns the opposite vertex of the current face and on the edge on the side turning clockwise.
int degree() const
Returns the degree of the vertex, that is the count of other vertices linked.
QList< int > facesAround() const
Returns all the faces indexes around the vertex.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
A class to represent a 2D point.
Point geometry type, with support for z-dimension and m-values.
bool isEmpty() const override
Returns true if the geometry is empty.
Class that contains topological differences between two states of a topological mesh,...
QList< int > mChangeCoordinateVerticesIndexes
QList< int > mVerticesToFaceRemoved
void clearChanges()
Clears all changes.
QVector< FaceNeighbors > mFacesNeighborhoodToRemove
QVector< QgsMeshFace > removedFaces() const
Returns the faces that are removed with this changes.
QList< QgsPointXY > mNewXYValues
QList< QgsMeshVertex > mRemovedVertices
QVector< QgsMeshVertex > addedVertices() const
Returns the added vertices with this changes.
QList< std::array< int, 4 > > mNeighborhoodChanges
bool isEmpty() const
Returns whether changes are empty, that there is nothing to change.
QList< int > mVerticesToRemoveIndexes
QList< int > changedCoordinatesVerticesIndexes() const
Returns the indexes of vertices that have changed coordinates.
QList< int > mNativeFacesIndexesGeometryChanged
QVector< QgsMeshFace > mFacesToAdd
QList< int > removedFaceIndexes() const
Returns the indexes of the faces that are removed with this changes.
QVector< FaceNeighbors > mFacesNeighborhoodToAdd
QList< std::array< int, 3 > > mVerticesToFaceChanges
QList< QgsPointXY > mOldXYValues
QList< double > newVerticesZValues() const
Returns the new Z values of vertices that have changed their coordinates.
QList< double > mNewZValues
QVector< QgsMeshVertex > mVerticesToAdd
QVector< QgsMeshFace > addedFaces() const
Returns the face that are added with this changes.
QList< QgsPointXY > oldVerticesXYValues() const
Returns the old (X,Y) values of vertices that have changed their coordinates.
int mAddedFacesFirstIndex
QVector< int > mVertexToFaceToAdd
QList< int > mFaceIndexesToRemove
QList< QgsPointXY > newVerticesXYValues() const
Returns the new (X,Y) values of vertices that have changed their coordinates.
QVector< QgsMeshFace > mFacesToRemove
QList< double > mOldZValues
QList< int > nativeFacesIndexesGeometryChanged() const
Returns a list of the native face indexes that have a geometry changed.
QList< int > verticesToRemoveIndexes() const
Returns the indexes of vertices to remove.
Class that contains independent faces an topological information about this faces.
int vertexToFace(int vertexIndex) const
Returns a face linked to the vertices with index vertexIndex.
QVector< FaceNeighbors > facesNeighborhood() const
Returns the face neighborhood of the faces, indexing is local.
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.
static int vertexPositionInFace(int vertexIndex, const QgsMeshFace &face)
Returns vertex position in face.
static QgsMeshEditingError checkTopology(const QgsMesh &mesh, int maxVerticesPerFace)
Checks the topology of the mesh mesh, if error occurs, this mesh can't be edited.
friend class QgsMeshVertexCirculator
void applyChanges(const Changes &changes)
Applies the changes.
int firstFaceLinked(int vertexIndex) const
Returns the index of the first face linked, returns -1 if it is a free vertex or out of range index.
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 ...
QVector< int > neighborsOfFace(int faceIndex) const
Returns the indexes of neighbor faces of the face with index faceIndex.
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 ...
QVector< int > FaceNeighbors
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 that is 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 .
QgsMesh * mesh() const
Returns a pointer to the wrapped mesh.
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.
bool delaunayConditionForEdge(int vertexIndex1, int vertexIndex2)
Check if Delaunay condition holds for given edge returns true if delaunay condition holds false other...
A class to represent a vector.
double angle() const
Returns the angle of the vector in radians.
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.
QgsMeshVertex vertex(int index) const
Returns a vertex at the index.