38 double ux1 = v1.
x() - vc.
x();
39 double uy1 = v1.
y() - vc.
y();
40 double vx1 = v2.
x() - vc.
x();
41 double vy1 = v2.
y() - vc.
y();
43 return ux1 * vy1 - uy1 * vx1;
46static double crossProduct(
int centralVertex,
int vertex1,
int vertex2,
const QgsMesh &mesh )
52 return crossProduct( vc, v1, v2 );
57 : mFaces( topologicalMesh.mMesh->faces )
58 , mFacesNeighborhood( topologicalMesh.mFacesNeighborhood )
59 , mVertexIndex( vertexIndex )
61 if ( vertexIndex >= 0 && vertexIndex < topologicalMesh.mMesh->vertexCount() )
63 mCurrentFace = topologicalMesh.mVertexToFace[vertexIndex];
72 mLastValidFace = mCurrentFace;
76 : mFaces( topologicalFaces.mFaces )
77 , mFacesNeighborhood( topologicalFaces.mFacesNeighborhood )
78 , mVertexIndex( vertexIndex )
80 const QgsMeshFace &face = topologicalFaces.mFaces.at( faceIndex );
83 mCurrentFace = faceIndex;
84 mLastValidFace = mCurrentFace;
88 : mFaces( topologicalFaces.mFaces )
89 , mFacesNeighborhood( topologicalFaces.mFacesNeighborhood )
90 , mVertexIndex( vertexIndex )
92 if ( topologicalFaces.mVerticesToFace.contains( vertexIndex ) )
93 mCurrentFace = topologicalFaces.mVerticesToFace.values( vertexIndex ).first();
94 mLastValidFace = mCurrentFace;
95 mIsValid = mCurrentFace != -1;
100 if ( mCurrentFace == -1 )
101 mCurrentFace = mLastValidFace;
104 int currentPos = positionInCurrentFace();
105 Q_ASSERT( currentPos != -1 );
109 mLastValidFace = mCurrentFace;
110 mCurrentFace = mFacesNeighborhood.at( mCurrentFace ).at( ( currentPos + faceSize - 1 ) %
currentFace.count() );
118 if ( mCurrentFace == -1 )
119 mCurrentFace = mLastValidFace;
122 int currentPos = positionInCurrentFace();
123 Q_ASSERT( currentPos != -1 );
127 mLastValidFace = mCurrentFace;
128 mCurrentFace = mFacesNeighborhood.at( mCurrentFace ).at( ( currentPos ) % faceSize );
141 if ( mCurrentFace != -1 )
142 return mFaces.at( mCurrentFace );
152 if ( mCurrentFace == -1 )
153 mCurrentFace = mLastValidFace;
155 int firstFace = mCurrentFace;
158 if ( mCurrentFace == firstFace )
169 if ( mCurrentFace == -1 )
170 mCurrentFace = mLastValidFace;
172 int firstFace = mCurrentFace;
175 if ( mCurrentFace == firstFace )
183 if ( mCurrentFace == -1 )
188 if ( face.isEmpty() )
193 if ( vertexPosition == -1 )
196 return face.at( ( vertexPosition + 1 ) % face.count() );
201 if ( mCurrentFace == -1 )
206 if ( face.isEmpty() )
211 if ( vertexPosition == -1 )
214 return face.at( ( vertexPosition - 1 + face.count() ) % face.count() );
228 if ( mCurrentFace != -1 )
229 ret.append( mCurrentFace );
274int QgsMeshVertexCirculator::positionInCurrentFace()
const
276 if ( mCurrentFace < 0 || mCurrentFace >= mFaces.count() )
289 for (
int i = 0; i < changes.
mFacesToAdd.count(); ++i )
292 for (
int boundary : topologicalFaces.mBoundaries )
295 if ( mVertexToFace.at( boundary ) == -1 )
298 const QList<int> &linkedFaces = topologicalFaces.mVerticesToFace.values( boundary );
299 for (
int linkedFace : linkedFaces )
305 if ( mVertexToFace.at( oppositeVertexForNewFace ) == -1 )
315 if ( oppositeVertexForMeshFace != oppositeVertexForNewFace )
327 boundaryPositionInMeshFace,
337 for (
int f = 0; f < changes.
mFacesToAdd.count(); ++f )
338 for (
int n = 0; n < changes.
mFacesToAdd.at( f ).count(); ++n )
340 changes.
mFacesNeighborhoodToAdd[f][n] = changes.addedFaceIndexInMesh( topologicalFaces.mFacesNeighborhood.at( f ).at( n ) );
342 const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
343 for (
const int vtc : verticesToFaceToChange )
344 if ( mVertexToFace.at( vtc ) == -1 )
346 mVertexToFace.at( vtc ),
347 changes.addedFaceIndexInMesh( topologicalFaces.mVerticesToFace.values( vtc ).first() )
350 applyChanges( changes );
357 int initialVerticesCount = mMesh->
vertices.count();
362 mVertexToFace.resize( newSize );
368 mMesh->
faces.resize( newSize );
369 mFacesNeighborhood.resize( newSize );
375 mFacesNeighborhood[changes.removedFaceIndexInMesh( i )] =
FaceNeighbors();
381 if ( mVertexToFace.at( vertexIndex ) == -1 )
382 dereferenceAsFreeVertex( vertexIndex );
384 mVertexToFace[vertexIndex] = -1;
392 referenceAsFreeVertex( initialVerticesCount + i );
395 for (
int i = 0; i < changes.
mFacesToAdd.count(); ++i )
397 mMesh->
faces[changes.addedFaceIndexInMesh( i )] = changes.
mFacesToAdd.at( i );
403 const int faceIndex = neighborChange.at( 0 );
404 const int positionInFace = neighborChange.at( 1 );
405 const int valueToApply = neighborChange.at( 3 );
406 mFacesNeighborhood[faceIndex][positionInFace] = valueToApply;
411 int vertexIndex = vertexToFaceChange.at( 0 );
412 mVertexToFace[vertexToFaceChange.at( 0 )] = vertexToFaceChange.at( 2 );
414 if ( vertexToFaceChange.at( 2 ) == -1 &&
415 vertexToFaceChange.at( 1 ) != -1 &&
416 !mMesh->
vertices.at( vertexIndex ).isEmpty() )
417 referenceAsFreeVertex( vertexIndex );
419 if ( vertexToFaceChange.at( 1 ) == -1 && vertexToFaceChange.at( 2 ) != -1 )
420 dereferenceAsFreeVertex( vertexIndex );
431 mMesh->
vertices[vertexIndex].setX( pt.
x() );
432 mMesh->
vertices[vertexIndex].setY( pt.
y() );
441 const int faceIndex = neighborChange.at( 0 );
442 const int positionInFace = neighborChange.at( 1 );
443 const int valueToApply = neighborChange.at( 2 );
444 mFacesNeighborhood[faceIndex][positionInFace] = valueToApply;
458 if ( mVertexToFace.at( vertexIndex ) == -1 )
459 referenceAsFreeVertex( vertexIndex );
463 for (
int i = 0; i < verticesToFaceChangesCount; ++i )
465 const std::array<int, 3> vertexToFaceChange = changes.
mVerticesToFaceChanges.at( verticesToFaceChangesCount - i - 1 );
466 int vertexIndex = vertexToFaceChange.at( 0 );
467 mVertexToFace[vertexIndex] = vertexToFaceChange.at( 1 );
469 if ( vertexToFaceChange.at( 2 ) == -1 && vertexToFaceChange.at( 1 ) != -1 )
470 dereferenceAsFreeVertex( vertexIndex );
472 if ( vertexToFaceChange.at( 1 ) == -1 &&
473 vertexToFaceChange.at( 2 ) != -1 &&
475 referenceAsFreeVertex( vertexIndex );
481 mMesh->
faces.resize( newSize );
482 mFacesNeighborhood.resize( newSize );
489 for (
int i = newSize; i < mMesh->
vertexCount(); ++i )
490 if ( mVertexToFace.at( i ) == -1 )
491 dereferenceAsFreeVertex( i );
494 mVertexToFace.resize( newSize );
505 mMesh->
vertices[vertexIndex].setX( pt.
x() );
506 mMesh->
vertices[vertexIndex].setY( pt.
y() );
516QSet<int> QgsTopologicalMesh::concernedFacesBy(
const QList<int> &faceIndexes )
const
519 for (
const int faceIndex : faceIndexes )
522 for (
int i = 0; i < face.count(); ++i )
525 faces.unite( QSet< int >( around.begin(), around.end() ) );
531void QgsTopologicalMesh::dereferenceAsFreeVertex(
int vertexIndex )
533 mFreeVertices.remove( vertexIndex );
536void QgsTopologicalMesh::referenceAsFreeVertex(
int vertexIndex )
540 mFreeVertices.insert( vertexIndex );
545 for (
int faceIndex = 0 ; faceIndex < mMesh->
faces.count( ); ++faceIndex )
548 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( faceIndex );
549 if ( face.count() != neighborhood.count() )
551 for (
int i = 0; i < face.count(); ++i )
553 int vertexIndex = face.at( i );
555 if ( mVertexToFace.at( vertexIndex ) == -1 )
558 int neighborIndex = neighborhood.at( i );
559 if ( neighborIndex != -1 )
562 if ( neighborFace.isEmpty() )
564 int neighborSize = neighborFace.size();
565 const FaceNeighbors &neighborhoodOfNeighbor = mFacesNeighborhood.at( neighborIndex );
567 if ( neighborhoodOfNeighbor.isEmpty() || neighborhoodOfNeighbor.at( ( posInNeighbor + neighborSize - 1 ) % neighborSize ) != faceIndex )
573 for (
int vertexIndex = 0; vertexIndex < mMesh->
vertexCount(); ++vertexIndex )
575 if ( mVertexToFace.at( vertexIndex ) != -1 )
577 if ( !mMesh->
face( mVertexToFace.at( vertexIndex ) ).contains( vertexIndex ) )
603 if ( vertexIndex < 0 || vertexIndex >= mMesh->
vertexCount() )
605 return mVertexToFace.at( vertexIndex );
620 if ( vertexIndex < 0 || vertexIndex >= mMesh->
vertexCount() )
623 if ( mMesh->
vertices.at( vertexIndex ).isEmpty() )
626 return mVertexToFace.at( vertexIndex ) == -1;
631 return QList<int>( mFreeVertices.begin(), mFreeVertices.end() );
636 int size = vertices.size();
638 for (
int i = 0; i < size; ++i )
641 int iv1 = ( i + 1 ) % size;
642 int iv2 = ( i + 2 ) % size;
657 double crossProd = crossProduct( v1, v0, v2 );
658 if ( direction != 0 && crossProd * direction < 0 )
660 clockwise = direction > 0;
663 else if ( crossProd == 0 )
665 clockwise = direction > 0;
668 else if ( direction == 0 )
669 direction = crossProd / std::fabs( crossProd );
672 clockwise = direction > 0;
681 int faceSize = face.count();
685 QVector<QgsMeshVertex> vertices( face.size() );
687 for (
int i = 0; i < faceSize; ++i )
696 bool clockwise =
false;
703 for (
int i = 0; i < faceSize / 2; ++i )
706 face[i] = face.at( faceSize - i - 1 );
707 face[faceSize - i - 1] = temp;
716 QVector<int> oldToNewIndex( mMesh->
vertices.count(), -1 );
720 while ( oldIndex < verticesTotalCount )
728 oldToNewIndex[oldIndex] = newIndex;
729 if ( oldIndex != newIndex )
731 oldToNewIndex[oldIndex] = newIndex;
741 int facesTotalCount = mMesh->
faceCount();
742 while ( oldIndex < facesTotalCount )
744 if ( mMesh->
face( oldIndex ).isEmpty() )
748 if ( oldIndex != newIndex )
749 mMesh->
faces[newIndex] = mMesh->
faces[oldIndex];
751 for (
int i = 0; i < face.count(); ++i )
752 face[i] = oldToNewIndex[face.at( i )];
758 mMesh->
faces.resize( newIndex );
760 mVertexToFace.clear();
761 mFacesNeighborhood.clear();
766 QVector<int> oldToNewVerticesIndexes;
767 if ( !renumberVertices( oldToNewVerticesIndexes ) )
771 QVector<int> oldToNewFacesIndexes;
773 if ( !renumberFaces( oldToNewFacesIndexes ) )
778 QVector<QgsMeshVertex> tempVertices( mMesh->
vertices.count() );
779 for (
int i = 0; i < oldToNewVerticesIndexes.count(); ++i )
781 tempVertices[oldToNewVerticesIndexes.at( i )] = mMesh->
vertex( i );
785 QVector<QgsMeshFace> tempFaces( mMesh->
faces.count() );
786 for (
int i = 0; i < oldToNewFacesIndexes.count(); ++i )
788 tempFaces[oldToNewFacesIndexes.at( i )] = mMesh->
face( i );
790 QgsMeshFace &face = tempFaces[oldToNewFacesIndexes.at( i )];
792 for (
int fi = 0; fi < face.count(); ++fi )
794 face[fi] = oldToNewVerticesIndexes.at( face.at( fi ) );
798 mMesh->
faces = tempFaces;
804bool QgsTopologicalMesh::renumberVertices( QVector<int> &oldToNewIndex )
const
806 std::vector<QgsMeshVertexCirculator> circulators;
807 circulators.reserve( mMesh->
vertices.count() );
808 int minDegree = std::numeric_limits<int>::max();
809 int minDegreeVertex = -1;
812 QSet<int> nonThreadedVertex;
813 oldToNewIndex = QVector<int> ( mMesh->
vertexCount(), -1 );
816 circulators.emplace_back( *
this, i );
818 if ( circulators.back().degree() < minDegree )
820 minDegreeVertex = circulators.size() - 1;
821 minDegree = circulator.
degree();
823 nonThreadedVertex.insert( i );
826 auto sortedNeighbor = [ = ]( QList<int> &neighbors,
int index )
840 int degree = circulators.at( neighborIndex ).degree();
841 QList<int>::Iterator it = neighbors.begin();
842 while ( it != neighbors.end() )
844 if ( degree <= circulators.at( *it ).degree() )
846 neighbors.insert( it, neighborIndex );
851 if ( it == neighbors.end() )
852 neighbors.append( neighborIndex );
858 int currentVertex = minDegreeVertex;
859 nonThreadedVertex.remove( minDegreeVertex );
861 while ( newIndex < mMesh->vertexCount() )
863 if ( oldToNewIndex[currentVertex] == -1 )
864 oldToNewIndex[currentVertex] = newIndex++;
866 if ( circulators.at( currentVertex ).isValid() )
868 QList<int> neighbors;
869 sortedNeighbor( neighbors, currentVertex );
871 for (
const int i : std::as_const( neighbors ) )
872 if ( oldToNewIndex.at( i ) == -1 && nonThreadedVertex.contains( i ) )
875 nonThreadedVertex.remove( i );
879 if ( queue.isEmpty() )
881 if ( nonThreadedVertex.isEmpty() && newIndex < mMesh->vertexCount() )
884 const QList<int> remainingVertex( nonThreadedVertex.constBegin(), nonThreadedVertex.constEnd() );
885 int minRemainingDegree = std::numeric_limits<int>::max();
886 int minRemainingVertex = -1;
887 for (
const int i : remainingVertex )
889 int degree = circulators.at( i ).degree();
890 if ( degree < minRemainingDegree )
892 minRemainingDegree = degree;
893 minRemainingVertex = i;
896 currentVertex = minRemainingVertex;
897 nonThreadedVertex.remove( currentVertex );
901 currentVertex = queue.dequeue();
908bool QgsTopologicalMesh::renumberFaces( QVector<int> &oldToNewIndex )
const
911 QSet<int> nonThreadedFaces;
913 oldToNewIndex = QVector<int>( mMesh->
faceCount(), -1 );
915 QVector<int> faceDegrees( mMesh->
faceCount(), 0 );
917 int minDegree = std::numeric_limits<int>::max();
918 int minDegreeFace = -1;
919 for (
int faceIndex = 0; faceIndex < mMesh->
faceCount(); ++faceIndex )
921 const FaceNeighbors &neighbors = mFacesNeighborhood.at( faceIndex );
924 for (
int n = 0; n < neighbors.size(); ++n )
926 if ( neighbors.at( n ) != -1 )
930 if ( degree < minDegree )
933 minDegreeFace = faceIndex;
936 faceDegrees[faceIndex] = degree;
937 nonThreadedFaces.insert( faceIndex );
941 int currentFace = minDegreeFace;
942 nonThreadedFaces.remove( minDegreeFace );
944 auto sortedNeighbor = [
this, faceDegrees]( QList<int> &neighbors,
int index )
946 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( index );
948 for (
int i = 0; i < neighborhood.count(); ++i )
950 int neighborIndex = neighborhood.at( i );
951 if ( neighborIndex == -1 )
954 int degree = faceDegrees.at( neighborIndex );
955 if ( neighbors.isEmpty() )
956 neighbors.append( neighborIndex );
959 QList<int>::Iterator it = neighbors.begin();
960 while ( it != neighbors.end() )
962 if ( degree <= faceDegrees.at( *it ) )
964 neighbors.insert( it, neighborIndex );
969 if ( it == neighbors.end() )
970 neighbors.append( neighborIndex );
975 while ( newIndex < mMesh->faceCount() )
977 if ( oldToNewIndex[currentFace] == -1 )
978 oldToNewIndex[currentFace] = newIndex++;
980 QList<int> neighbors;
981 sortedNeighbor( neighbors, currentFace );
983 for (
const int i : std::as_const( neighbors ) )
984 if ( oldToNewIndex.at( i ) == -1 && nonThreadedFaces.contains( i ) )
987 nonThreadedFaces.remove( i );
990 if ( queue.isEmpty() )
992 if ( nonThreadedFaces.isEmpty() && newIndex < mMesh->faceCount() )
995 const QList<int> remainingFace( nonThreadedFaces.constBegin(), nonThreadedFaces.constEnd() );
996 int minRemainingDegree = std::numeric_limits<int>::max();
997 int minRemainingFace = -1;
998 for (
const int i : remainingFace )
1000 int degree = faceDegrees.at( i );
1001 if ( degree < minRemainingDegree )
1003 minRemainingDegree = degree;
1004 minRemainingFace = i;
1007 currentFace = minRemainingFace;
1008 nonThreadedFaces.remove( currentFace );
1012 currentFace = queue.dequeue();
1027 return mFacesToRemove;
1032 return mFaceIndexesToRemove;
1037 return mVerticesToAdd;
1042 return mChangeCoordinateVerticesIndexes;
1052 return mNewXYValues;
1057 return mOldXYValues;
1062 return mNativeFacesIndexesGeometryChanged;
1067 return ( mFaceIndexesToRemove.isEmpty() &&
1068 mFacesToAdd.isEmpty() &&
1069 mFacesNeighborhoodToAdd.isEmpty() &&
1070 mFacesToRemove.isEmpty() &&
1071 mFacesNeighborhoodToRemove.isEmpty() &&
1072 mNeighborhoodChanges.isEmpty() &&
1073 mVerticesToAdd.isEmpty() &&
1074 mVertexToFaceToAdd.isEmpty() &&
1075 mVerticesToRemoveIndexes.isEmpty() &&
1076 mRemovedVertices.isEmpty() &&
1077 mVerticesToFaceRemoved.isEmpty() &&
1078 mVerticesToFaceChanges.isEmpty() &&
1079 mChangeCoordinateVerticesIndexes.isEmpty() &&
1080 mNewZValues.isEmpty() &&
1081 mOldZValues.isEmpty() &&
1082 mNewXYValues.isEmpty() &&
1083 mOldXYValues.isEmpty() &&
1084 mNativeFacesIndexesGeometryChanged.isEmpty() );
1089 return mVerticesToRemoveIndexes;
1092int QgsTopologicalMesh::Changes::addedFaceIndexInMesh(
int internalIndex )
const
1094 if ( internalIndex == -1 )
1097 return internalIndex + mAddedFacesFirstIndex;
1100int QgsTopologicalMesh::Changes::removedFaceIndexInMesh(
int internalIndex )
const
1102 if ( internalIndex == -1 )
1105 return mFaceIndexesToRemove.at( internalIndex );
1110 mAddedFacesFirstIndex = 0;
1111 mFaceIndexesToRemove.clear();
1112 mFacesToAdd.clear();
1113 mFacesNeighborhoodToAdd.clear();
1114 mFacesToRemove.clear();
1115 mFacesNeighborhoodToRemove.clear();
1116 mNeighborhoodChanges.clear();
1118 mVerticesToAdd.clear();
1119 mVertexToFaceToAdd.clear();
1120 mVerticesToRemoveIndexes.clear();
1121 mRemovedVertices.clear();
1122 mVerticesToFaceRemoved.clear();
1123 mVerticesToFaceChanges.clear();
1125 mChangeCoordinateVerticesIndexes.clear();
1126 mNewZValues.clear();
1127 mOldZValues.clear();
1128 mNewXYValues.clear();
1129 mOldXYValues.clear();
1130 mNativeFacesIndexesGeometryChanged.clear();
1140 mVertexToFace.append( -1 );
1141 referenceAsFreeVertex( mMesh->
vertices.count() - 1 );
1147static double vertexPolygonOrientation(
const QgsMesh &
mesh,
const QList<int> &vertexIndexes )
1149 if ( vertexIndexes.count() < 3 )
1152 int hullDomainVertexPos = -1;
1153 double xMin = std::numeric_limits<double>::max();
1154 double yMin = std::numeric_limits<double>::max();
1155 for (
int i = 0; i < vertexIndexes.count(); ++i )
1158 if ( xMin >= vertex.
x() && yMin > vertex.
y() )
1160 hullDomainVertexPos = i;
1166 if ( hullDomainVertexPos >= 0 )
1168 int iv1 = vertexIndexes.at( ( hullDomainVertexPos - 1 + vertexIndexes.count() ) % vertexIndexes.count() );
1169 int iv2 = vertexIndexes.at( ( hullDomainVertexPos + 1 ) % vertexIndexes.count() );
1170 int ivc = vertexIndexes.at( ( hullDomainVertexPos ) );
1171 double cp = crossProduct( ivc, iv1, iv2,
mesh );
1180 if ( vertexIndex >= mVertexToFace.count() )
1183 if ( mVertexToFace.at( vertexIndex ) == -1 )
1189 dereferenceAsFreeVertex( vertexIndex );
1197 QList<int> boundariesVertexIndex;
1198 QList<int> associateFaceToBoundaries;
1199 QList<int> removedFacesIndexes;
1200 QSet<int> boundaryInGlobalMesh;
1206 Q_ASSERT( !mMesh->
vertices.at( boundariesVertexIndex.last() ).isEmpty() );
1208 associateFaceToBoundaries.append( mFacesNeighborhood.at( circulator.
currentFaceIndex() ).at(
1211 if ( currentFace.count() > 3 )
1214 for (
int i = 2; i < currentFace.count() - 1; ++i )
1216 boundariesVertexIndex.append( currentFace.at( ( posInface + i ) % currentFace.count() ) );
1217 Q_ASSERT( !mMesh->
vertices.at( boundariesVertexIndex.last() ).isEmpty() );
1218 associateFaceToBoundaries.append( mFacesNeighborhood.at( circulator.
currentFaceIndex() ).at(
1225 bool boundaryFill =
false;
1228 boundaryFill =
true;
1232 boundariesVertexIndex.append( lastVertexIndex );
1241 boundaryFill =
false;
1244 associateFaceToBoundaries.append( -1 );
1246 for (
const int index : std::as_const( boundariesVertexIndex ) )
1249 boundaryInGlobalMesh.insert( index );
1253 int currentVertexToFace = mVertexToFace.at( vertexIndex );
1257 QList<QList<int>> holes;
1258 QList<QList<int>> associateMeshFacesToHoles;
1260 bool cancelOperation =
false;
1268 int finalPos = boundariesVertexIndex.count() - 1;
1269 QList<int> uncoveredVertex;
1271 QList<int> partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1272 QList<int> associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1273 while ( startPos < finalPos && !partToCheck.isEmpty() )
1276 int secondPos = partToCheck.count() - 1;
1277 const QgsPoint &closingSegmentExtremety1 = mMesh->
vertex( partToCheck.at( 0 ) );
1278 const QgsPoint &closingSegmentExtremety2 = mMesh->
vertex( partToCheck.last() );
1279 bool isEdgeIntersect =
false;
1280 for (
int i = 1; i < secondPos - 1; ++i )
1284 bool isLineIntersection;
1287 if ( isEdgeIntersect )
1291 int index = partToCheck.at( 0 );
1292 if ( boundaryInGlobalMesh.contains( index ) && index != boundariesVertexIndex.at( 0 ) )
1294 cancelOperation =
true;
1300 if ( isEdgeIntersect || vertexPolygonOrientation( *mMesh, partToCheck ) >= 0 )
1302 partToCheck.removeLast();
1303 associateFacePart.removeAt( associateFacePart.count() - 2 );
1304 if ( partToCheck.count() == 1 )
1306 uncoveredVertex.append( index );
1307 startPos = startPos + 1;
1308 partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1309 associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1315 holes.append( partToCheck );
1316 associateMeshFacesToHoles.append( associateFacePart );
1318 startPos = startPos + partToCheck.count() - 1;
1319 uncoveredVertex.append( partToCheck.at( 0 ) );
1320 partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1321 associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1327 holes.append( boundariesVertexIndex );
1328 associateMeshFacesToHoles.append( associateFaceToBoundaries );
1331 if ( cancelOperation )
1337 Q_ASSERT( holes.count() == associateMeshFacesToHoles.count() );
1343 dereferenceAsFreeVertex( vertexIndex );
1345 mVertexToFace[vertexIndex] = -1;
1348 for (
int h = 0; h < holes.count(); ++h )
1350 const QList<int> &holeVertices = holes.at( h );
1351 const QList<int> &associateMeshFacesToHole = associateMeshFacesToHoles.at( h );
1352 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
1353 std::vector<p2t::Point *> holeToFill( holeVertices.count() );
1356 for (
int i = 0; i < holeVertices.count(); ++i )
1359 holeToFill[i] =
new p2t::Point( vertex.
x(), vertex.
y() );
1360 mapPoly2TriPointToVertex.insert( holeToFill[i], holeVertices.at( i ) );
1363 std::unique_ptr<p2t::CDT> cdt(
new p2t::CDT( holeToFill ) );
1366 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
1367 QVector<QgsMeshFace> newFaces( triangles.size() );
1368 for (
size_t i = 0; i < triangles.size(); ++i )
1372 for (
int j = 0; j < 3; j++ )
1374 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
1375 if ( vertInd == -1 )
1376 throw std::exception();
1377 Q_ASSERT( !mMesh->
vertices.at( vertInd ).isEmpty() );
1385 throw std::exception();
1386 int newFaceIndexStartIndex = mMesh->
faceCount();
1393 const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
1394 for (
const int vtc : verticesToFaceToChange )
1395 if ( mVertexToFace.at( vtc ) == -1 )
1397 mVertexToFace.at( vtc ),
1398 addChanges.addedFaceIndexInMesh( topologicalFaces.mVerticesToFace.values( vtc ).first() )
1403 for (
int i = 0; i < topologicalFaces.mFaces.count(); ++i )
1405 FaceNeighbors &faceNeighbors = addChanges.mFacesNeighborhoodToAdd[i];
1406 faceNeighbors = topologicalFaces.mFacesNeighborhood.at( i );
1407 for (
int n = 0; n < faceNeighbors.count(); ++n )
1409 if ( faceNeighbors.at( n ) != -1 )
1410 faceNeighbors[n] += newFaceIndexStartIndex;
1415 for (
int i = 0 ; i < holeVertices.count(); ++i )
1417 int vertexHoleIndex = holeVertices.at( i );
1418 int meshFaceBoundaryIndex = associateMeshFacesToHole.at( i );
1423 int newFaceBoundaryIndexInMesh = circulator.
currentFaceIndex() + newFaceIndexStartIndex;
1427 if ( meshFaceBoundaryIndex != -1 )
1430 int positionInMeshFaceBoundary =
vertexPositionInFace( *mMesh, vertexHoleIndex, meshFaceBoundaryIndex );
1431 positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.count() ) % meshFace.count();
1433 addChanges.mNeighborhoodChanges.append( {meshFaceBoundaryIndex, positionInMeshFaceBoundary, -1, newFaceBoundaryIndexInMesh} );
1436 addChanges.mFacesNeighborhoodToAdd[newFaceBoundaryLocalIndex][positionInNewFaces] = meshFaceBoundaryIndex;
1441 changes.
mFacesToAdd.append( addChanges.mFacesToAdd );
1444 for (
const std::array<int, 4> &neighborChangeToAdd : std::as_const( addChanges.mNeighborhoodChanges ) )
1446 bool merged =
false;
1449 if ( existingNeighborChange.at( 0 ) == neighborChangeToAdd.at( 0 ) &&
1450 existingNeighborChange.at( 1 ) == neighborChangeToAdd.at( 1 ) )
1453 Q_ASSERT( existingNeighborChange.at( 3 ) == neighborChangeToAdd.at( 2 ) );
1454 existingNeighborChange[3] = neighborChangeToAdd.at( 3 );
1461 for (
const std::array<int, 3> &verticesToFaceToAdd : std::as_const( addChanges.mVerticesToFaceChanges ) )
1463 bool merged =
false;
1466 if ( existingVerticesToFace.at( 0 ) == verticesToFaceToAdd.at( 0 ) )
1469 Q_ASSERT( existingVerticesToFace.at( 2 ) == verticesToFaceToAdd.at( 1 ) );
1470 existingVerticesToFace[2] = verticesToFaceToAdd.at( 2 );
1477 qDeleteAll( holeToFill );
1481 qDeleteAll( holeToFill );
1485 changes.mAddedFacesFirstIndex = oldFacesCount;
1489 changes.mAddedFacesFirstIndex = oldFacesCount;
1496 QSet<int> facesIndex;
1498 for (
int vertexIndex : vertices )
1501 facesIndex.unite( QSet< int >( faces.begin(), faces.end() ) );
1508 for (
int vertexIndex : vertices )
1510 int currentVertexToFace = mVertexToFace.at( vertexIndex );
1516 dereferenceAsFreeVertex( vertexIndex );
1518 mVertexToFace[vertexIndex] = -1;
1526 QList<int> boundariesToCheckClockwiseInNewFaces = topologicFaces.mBoundaries;
1527 QList<std::array<int, 2>> boundariesToCheckCounterClockwiseInNewFaces;
1528 QList<int> uniqueSharedVertexBoundary;
1536 while ( !boundariesToCheckClockwiseInNewFaces.isEmpty() )
1538 int boundary = boundariesToCheckClockwiseInNewFaces.takeLast();
1540 const QList<int> &linkedFaces = topologicFaces.mVerticesToFace.values( boundary );
1542 for (
int const linkedFace : linkedFaces )
1546 if ( mVertexToFace.at( boundary ) == -1 )
1552 if ( !newFacescirculator.
isValid() )
1566 if ( oppositeVertexCCWInMesh == oppositeVertexInNewFaces )
1572 int faceSize = newFaceOnBoundary.size();
1574 int previousVertexIndex = ( posInNewFace + faceSize - 1 ) % faceSize;
1575 if ( newFaceOnBoundary.at( previousVertexIndex ) == oppositeVertexCCWInMesh )
1583 if ( oppositeVertexCWInMesh == oppositeVertexInNewFaces )
1587 boundariesToCheckCounterClockwiseInNewFaces.append( {boundary, linkedFace} );
1592 while ( !boundariesToCheckCounterClockwiseInNewFaces.isEmpty() )
1594 std::array<int, 2> boundaryLinkedface = boundariesToCheckCounterClockwiseInNewFaces.takeLast();
1595 int boundary = boundaryLinkedface.at( 0 );
1596 int linkedFace = boundaryLinkedface.at( 1 );
1611 if ( oppositeVertexCWInMesh == oppositeVertexInNewFaces )
1618 if ( oppositeVertexCCWInMesh == oppositeVertexInNewFaces )
1621 uniqueSharedVertexBoundary.append( boundary );
1624 if ( !uniqueSharedVertexBoundary.isEmpty() )
1628 QSet<int> boundaryVertices( topologicFaces.mBoundaries.constBegin(), topologicFaces.mBoundaries.constEnd() );
1629 for (
const QgsMeshFace &newFace : std::as_const( topologicFaces.mFaces ) )
1631 for (
const int vertexIndex : newFace )
1633 if ( boundaryVertices.contains( vertexIndex ) )
1635 if ( mVertexToFace.at( vertexIndex ) != -1 )
1646 mFacesNeighborhood.clear();
1647 mVerticesToFace.clear();
1648 mBoundaries.clear();
1653 return mFacesNeighborhood;
1658 if ( mVerticesToFace.contains( vertexIndex ) )
1659 return mVerticesToFace.values( vertexIndex ).at( 0 );
1667 topologicMesh.mMesh =
mesh;
1668 topologicMesh.mVertexToFace = QVector<int>(
mesh->
vertexCount(), -1 );
1669 topologicMesh.mMaximumVerticesPerFace = maxVerticesPerFace;
1676 if ( maxVerticesPerFace != 0 &&
mesh->
face( i ).count() > maxVerticesPerFace )
1694 topologicMesh.mFacesNeighborhood = subMesh.mFacesNeighborhood;
1696 for (
int i = 0; i < topologicMesh.mMesh->
vertexCount(); ++i )
1698 if ( topologicMesh.mVertexToFace.at( i ) == -1 )
1699 topologicMesh.mFreeVertices.insert( i );
1703 return topologicMesh;
1708 return createTopologicalFaces( faces,
nullptr, error, uniqueSharedVertexAllowed );
1713 const QVector<QgsMeshFace> &faces,
1714 QVector<int> *globalVertexToFace,
1716 bool allowUniqueSharedVertex )
1718 int facesCount = faces.count();
1719 QVector<FaceNeighbors> faceTopologies;
1720 QMultiHash<int, int> verticesToFace;
1723 TopologicalFaces ret;
1727 QMap<int, QMap<int, int>> verticesToNeighbor;
1729 for (
int faceIndex = 0; faceIndex < facesCount; ++faceIndex )
1732 int faceSize = face.count();
1734 for (
int i = 0; i < faceSize; ++i )
1736 int v1 = face[i % faceSize];
1737 int v2 = face[( i + 1 ) % faceSize];
1738 if ( verticesToNeighbor[v2].contains( v1 ) )
1744 verticesToNeighbor[v2].insert( v1, faceIndex );
1748 faceTopologies = QVector<FaceNeighbors>( faces.count() );
1750 QSet<int> boundaryVertices;
1752 for (
int faceIndex = 0; faceIndex < facesCount; ++faceIndex )
1755 int faceSize = face.size();
1757 faceTopology.resize( faceSize );
1759 for (
int i = 0; i < faceSize; ++i )
1761 int v1 = face.at( i );
1762 int v2 = face.at( ( i + 1 ) % faceSize );
1764 if ( globalVertexToFace )
1766 if ( ( *globalVertexToFace )[v1] == -1 )
1767 ( *globalVertexToFace )[v1] = faceIndex ;
1771 if ( allowUniqueSharedVertex || !verticesToFace.contains( v1 ) )
1772 verticesToFace.insert( v1, faceIndex ) ;
1775 QMap<int, int> &edges = verticesToNeighbor[v1];
1776 if ( edges.contains( v2 ) )
1777 faceTopology[i] = edges.value( v2 );
1780 faceTopology[i] = -1;
1782 if ( !allowUniqueSharedVertex )
1784 if ( boundaryVertices.contains( v1 ) )
1790 boundaryVertices.insert( v1 );
1796 ret.mFacesNeighborhood = faceTopologies;
1797 ret.mBoundaries = boundaryVertices.values();
1798 ret.mVerticesToFace = verticesToFace;
1804 return mFacesNeighborhood.at( faceIndex );
1816 QSet<int> removedFaces( facesIndexes.begin(), facesIndexes.end() );
1817 QSet<int> concernedFaces = concernedFacesBy( facesIndexes );
1819 for (
const int f : std::as_const( removedFaces ) )
1820 concernedFaces.remove( f );
1822 QVector<QgsMeshFace> remainingFaces;
1823 remainingFaces.reserve( concernedFaces.count() );
1824 for (
const int f : std::as_const( concernedFaces ) )
1825 remainingFaces.append( mMesh->
face( f ) );
1828 createTopologicalFaces( remainingFaces,
nullptr, error,
false );
1840 QSet<int> indexSet( facesIndexesToRemove.begin(), facesIndexesToRemove.end() );
1841 QSet<int> threatedVertex;
1843 for (
int i = 0; i < facesIndexesToRemove.count(); ++i )
1845 const int faceIndex = facesIndexesToRemove.at( i );
1848 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( faceIndex );
1850 for (
int j = 0; j < face.count(); ++j )
1853 int neighborIndex = neighborhood.at( j );
1854 if ( neighborIndex != -1 && !indexSet.contains( neighborIndex ) )
1856 int positionInNeighbor = mFacesNeighborhood.at( neighborIndex ).indexOf( faceIndex );
1861 int vertexIndex = face.at( j );
1862 if ( !threatedVertex.contains( vertexIndex ) && indexSet.contains( mVertexToFace.at( vertexIndex ) ) )
1864 int oldValue = mVertexToFace.at( vertexIndex );
1867 if ( neighborIndex != -1 && !indexSet.contains( neighborIndex ) )
1868 refValue = neighborIndex;
1872 aroundFaces.removeOne( faceIndex );
1873 if ( !aroundFaces.isEmpty() )
1875 while ( !aroundFaces.isEmpty() && refValue == -1 )
1877 if ( !indexSet.contains( aroundFaces.first() ) )
1878 refValue = aroundFaces.first();
1880 aroundFaces.removeFirst();
1885 threatedVertex.insert( vertexIndex );
1895bool QgsTopologicalMesh::eitherSideFacesAndVertices(
int vertexIndex1,
1899 int &neighborVertex1InFace1,
1900 int &neighborVertex1InFace2,
1901 int &neighborVertex2inFace1,
1902 int &neighborVertex2inFace2 )
const
1944 int oppositeVertexFace1;
1945 int oppositeVertexFace2;
1946 int supposedOppositeVertexFace1;
1947 int supposedoppositeVertexFace2;
1949 bool result = eitherSideFacesAndVertices(
1954 oppositeVertexFace1,
1955 supposedoppositeVertexFace2,
1956 supposedOppositeVertexFace1,
1957 oppositeVertexFace2 );
1962 oppositeVertexFace1 < 0 ||
1963 oppositeVertexFace2 < 0 ||
1964 supposedOppositeVertexFace1 != oppositeVertexFace1 ||
1965 supposedoppositeVertexFace2 != oppositeVertexFace2 )
1972 if ( face1.count() != 3 || face2.count() != 3 )
1975 double crossProduct1 = crossProduct( vertexIndex1, oppositeVertexFace1, oppositeVertexFace2, *mMesh );
1976 double crossProduct2 = crossProduct( vertexIndex2, oppositeVertexFace1, oppositeVertexFace2, *mMesh );
1978 return crossProduct1 * crossProduct2 < 0;
1985 int oppositeVertexFace1;
1986 int oppositeVertexFace2;
1987 int supposedOppositeVertexFace1;
1988 int supposedoppositeVertexFace2;
1990 bool result = eitherSideFacesAndVertices(
1995 oppositeVertexFace1,
1996 supposedoppositeVertexFace2,
1997 supposedOppositeVertexFace1,
1998 oppositeVertexFace2 );
2003 oppositeVertexFace1 < 0 ||
2004 oppositeVertexFace2 < 0 ||
2005 supposedOppositeVertexFace1 != oppositeVertexFace1 ||
2006 supposedoppositeVertexFace2 != oppositeVertexFace2 )
2015 Q_ASSERT( face1.count() == 3 );
2016 Q_ASSERT( face2.count() == 3 );
2021 int neighborFace1 = mFacesNeighborhood.at( faceIndex1 ).at( pos1 );
2023 int neighborFace2 = mFacesNeighborhood.at( faceIndex1 ).at( ( pos1 + 1 ) % 3 );
2025 int neighborFace3 = mFacesNeighborhood.at( faceIndex2 ).at( pos2 );
2027 int neighborFace4 = mFacesNeighborhood.at( faceIndex2 ).at( ( pos2 + 1 ) % 3 );
2038 changes.
mFacesToAdd.append( {oppositeVertexFace1, oppositeVertexFace2, vertexIndex1} );
2039 changes.
mFacesToAdd.append( {oppositeVertexFace2, oppositeVertexFace1, vertexIndex2} );
2041 mFacesNeighborhood.at( faceIndex2 ).at( ( pos2 + 1 ) % 3 ),
2042 mFacesNeighborhood.at( faceIndex1 ).at( pos1 )
2045 mFacesNeighborhood.at( faceIndex1 ).at( ( pos1 + 1 ) % 3 ),
2046 mFacesNeighborhood.at( faceIndex2 ).at( pos2 )
2049 if ( neighborFace1 >= 0 )
2050 changes.
mNeighborhoodChanges.append( {neighborFace1, posInNeighbor1, faceIndex1, startIndex} );
2051 if ( neighborFace2 >= 0 )
2052 changes.
mNeighborhoodChanges.append( {neighborFace2, posInNeighbor2, faceIndex1, startIndex + 1} );
2053 if ( neighborFace3 >= 0 )
2054 changes.
mNeighborhoodChanges.append( {neighborFace3, posInNeighbor3, faceIndex2, startIndex + 1} );
2055 if ( neighborFace4 >= 0 )
2056 changes.
mNeighborhoodChanges.append( {neighborFace4, posInNeighbor4, faceIndex2, startIndex} );
2059 if ( mVertexToFace.at( vertexIndex1 ) == faceIndex1 || mVertexToFace.at( vertexIndex1 ) == faceIndex2 )
2061 if ( mVertexToFace.at( vertexIndex2 ) == faceIndex1 || mVertexToFace.at( vertexIndex2 ) == faceIndex2 )
2062 changes.
mVerticesToFaceChanges.append( {vertexIndex2, mVertexToFace.at( vertexIndex2 ), startIndex + 1} );
2064 if ( mVertexToFace.at( oppositeVertexFace1 ) == faceIndex1 )
2067 if ( mVertexToFace.at( oppositeVertexFace2 ) == faceIndex2 )
2079 int neighborVertex1InFace1;
2080 int neighborVertex1InFace2;
2081 int neighborVertex2inFace1;
2082 int neighborVertex2inFace2;
2084 bool result = eitherSideFacesAndVertices(
2089 neighborVertex1InFace1,
2090 neighborVertex1InFace2,
2091 neighborVertex2inFace1,
2092 neighborVertex2inFace2 );
2102 if ( face1.count() + face2.count() - 2 > mMaximumVerticesPerFace )
2112 double crossProduct1 = crossProduct( vertexIndex1, neighborVertex1InFace1, neighborVertex1InFace2, *mMesh );
2113 double crossProduct2 = crossProduct( vertexIndex2, neighborVertex2inFace1, neighborVertex2inFace2, *mMesh );
2115 return crossProduct1 * crossProduct2 < 0;
2122 int neighborVertex1InFace1;
2123 int neighborVertex1InFace2;
2124 int neighborVertex2inFace1;
2125 int neighborVertex2inFace2;
2127 bool result = eitherSideFacesAndVertices(
2132 neighborVertex1InFace1,
2133 neighborVertex1InFace2,
2134 neighborVertex2inFace1,
2135 neighborVertex2inFace2 );
2146 int faceSize1 = face1.count();
2147 int faceSize2 = face2.count();
2163 for (
int i = 0; i < faceSize1 - 1; ++i )
2165 int currentPos = ( pos1 + i ) % faceSize1;
2166 newface.append( face1.at( currentPos ) );
2168 int currentNeighbor = mFacesNeighborhood.at( faceIndex1 ).at( currentPos );
2169 newNeighborhood.append( currentNeighbor );
2171 if ( currentNeighbor != -1 )
2174 changes.
mNeighborhoodChanges.append( {currentNeighbor, currentPosInNeighbor, faceIndex1, startIndex} );
2177 for (
int i = 0; i < faceSize2 - 1; ++i )
2179 int currentPos = ( pos2 + i ) % faceSize2;
2180 newface.append( face2.at( currentPos ) );
2182 int currentNeighbor = mFacesNeighborhood.at( faceIndex2 ).at( currentPos );
2183 newNeighborhood.append( currentNeighbor );
2185 if ( currentNeighbor != -1 )
2188 changes.
mNeighborhoodChanges.append( {currentNeighbor, currentPosInNeighbor, faceIndex2, startIndex} );
2192 for (
int i = 0; i < faceSize1; ++i )
2193 if ( mVertexToFace.at( face1.at( i ) ) == faceIndex1 )
2196 for (
int i = 0; i < faceSize2; ++i )
2197 if ( mVertexToFace.at( face2.at( i ) ) == faceIndex2 )
2212 return face.count() == 4;
2219 int faceSize = face.count();
2221 Q_ASSERT( faceSize == 4 );
2223 double maxAngle = 0;
2224 int splitVertexPos = -1;
2225 for (
int i = 0; i < faceSize; ++i )
2227 QgsVector vect1( mMesh->
vertex( face.at( i ) ) - mMesh->
vertex( face.at( ( i + 1 ) % faceSize ) ) );
2228 QgsVector vect2( mMesh->
vertex( face.at( ( i + 2 ) % faceSize ) ) - mMesh->
vertex( face.at( ( i + 1 ) % faceSize ) ) );
2230 double angle = std::abs( vect1.
angle( vect2 ) );
2231 angle = std::min( angle, 2.0 * M_PI - angle );
2232 if ( angle > maxAngle )
2235 splitVertexPos = ( i + 1 ) % faceSize;
2240 if ( splitVertexPos == -1 )
2243 const QgsMeshFace newFace1 = {face.at( splitVertexPos ),
2244 face.at( ( splitVertexPos + 1 ) % faceSize ),
2245 face.at( ( splitVertexPos + 2 ) % faceSize )
2248 const QgsMeshFace newFace2 = {face.at( splitVertexPos ),
2249 face.at( ( splitVertexPos + 2 ) % faceSize ),
2250 face.at( ( splitVertexPos + 3 ) % faceSize )
2253 QVector<int> neighborIndex( faceSize );
2254 QVector<int> posInNeighbor( faceSize );
2256 for (
int i = 0; i < faceSize; ++i )
2258 neighborIndex[i] = mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + i ) % faceSize );
2271 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 1 ) % faceSize ),
2275 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 2 ) % faceSize ),
2276 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 3 ) % faceSize )
2279 for (
int i = 0; i < faceSize; ++i )
2281 if ( neighborIndex[i] >= 0 )
2282 changes.
mNeighborhoodChanges.append( {neighborIndex[i], posInNeighbor[i], faceIndex, startIndex + int( i / 2 )} );
2284 int vertexIndex = face.at( ( splitVertexPos + i ) % faceSize );
2285 if ( mVertexToFace.at( vertexIndex ) == faceIndex )
2302 mVertexToFace.append( -1 );
2306 const FaceNeighbors includingFaceNeighborhood = mFacesNeighborhood.at( includingFaceIndex );
2307 int includingFaceSize = includingFace.count();
2309 for (
int i = 0; i < includingFaceSize; ++i )
2314 face[1] = includingFace.at( i );
2315 face[2] = includingFace.at( ( i + 1 ) % includingFaceSize );
2316 mMesh->
faces.append( face );
2319 int currentVertexIndex = includingFace.at( i );
2320 if ( mVertexToFace.at( currentVertexIndex ) == includingFaceIndex )
2322 int newFaceIndex = mMesh->
faceCount() - 1;
2323 mVertexToFace[currentVertexIndex] = newFaceIndex;
2327 int includingFaceNeighbor = includingFaceNeighborhood.at( i );
2331 includingFaceNeighbor,
2334 mFacesNeighborhood.append( neighbors );
2337 if ( includingFaceNeighbor != -1 )
2340 int oldValue = mFacesNeighborhood[includingFaceNeighbor][indexInNeighbor];
2352 mVertexToFace[mVertexToFace.count() - 1] = mMesh->
faceCount() - 1;
2367 int newVertexPositionInFace1 = position + 1;
2369 auto triangulate = [
this, &changes](
int removedFaceIndex,
const QgsMeshVertex & newVertex,
int newVertexPosition, QVector<int> &edgeFacesIndexes )->
bool
2375 const int addedVertexIndex = mMesh->
vertexCount();
2378 int localStartIndex = changes.
mFacesToAdd.count();
2380 QVector<int> newBoundary = initialFace;
2381 newBoundary.insert( newVertexPosition, addedVertexIndex );
2385 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
2386 std::vector<p2t::Point *> faceToFill( newBoundary.count() );
2387 for (
int i = 0; i < newBoundary.count(); ++i )
2391 if ( newBoundary.at( i ) == addedVertexIndex )
2394 vert = mMesh->
vertex( newBoundary.at( i ) );
2396 faceToFill[i] =
new p2t::Point( vert.
x(), vert.
y() );
2397 mapPoly2TriPointToVertex.insert( faceToFill[i], newBoundary.at( i ) );
2400 std::unique_ptr<p2t::CDT> cdt(
new p2t::CDT( faceToFill ) );
2402 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
2403 QVector<QgsMeshFace> newFaces( triangles.size() );
2404 for (
size_t i = 0; i < triangles.size(); ++i )
2408 for (
int j = 0; j < 3; j++ )
2410 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
2411 if ( vertInd == -1 )
2412 throw std::exception();
2420 throw std::exception();
2426 const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
2427 for (
const int vtc : verticesToFaceToChange )
2428 if ( vtc != addedVertexIndex && mVertexToFace.at( vtc ) == removedFaceIndex )
2433 topologicalFaces.
vertexToFace( vtc ) + faceStartGlobalIndex
2437 for (
int i = 0; i < topologicalFaces.mFaces.count(); ++i )
2440 for (
int n = 0; n < faceNeighbors.count(); ++n )
2442 if ( faceNeighbors.at( n ) != -1 )
2443 faceNeighbors[n] += faceStartGlobalIndex;
2447 edgeFacesIndexes.resize( 2 );
2449 for (
int i = 0 ; i < newBoundary.count(); ++i )
2451 int vertexIndex = newBoundary.at( i );
2454 int newFaceBoundaryLocalIndex = localStartIndex + circulator.
currentFaceIndex();
2456 int newFaceBoundaryIndexInMesh = faceStartGlobalIndex;
2458 int meshFaceBoundaryIndex;
2459 if ( i == newVertexPosition )
2461 meshFaceBoundaryIndex = -1;
2462 edgeFacesIndexes[0] = newFaceBoundaryLocalIndex;
2464 else if ( i == ( newVertexPosition + newBoundary.count() - 1 ) % newBoundary.count() )
2466 meshFaceBoundaryIndex = -1;
2467 edgeFacesIndexes[1] = newFaceBoundaryLocalIndex;
2475 if ( meshFaceBoundaryIndex != -1 )
2479 positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.count() ) % meshFace.count();
2482 positionInMeshFaceBoundary,
2484 newFaceBoundaryIndexInMesh +
2492 qDeleteAll( faceToFill );
2502 QVector<int> edgeFacesIndexes;
2503 if ( !triangulate( faceIndex, vertexToInsert, newVertexPositionInFace1, edgeFacesIndexes ) )
2506 changes.mVertexToFaceToAdd.append( edgeFacesIndexes.at( 0 ) + changes.mAddedFacesFirstIndex );
2511 int face2Index = mFacesNeighborhood.at( faceIndex ).at( position );
2512 if ( face2Index != -1 )
2516 QVector<int> edgeFacesIndexesFace2;
2517 if ( !triangulate( face2Index, vertexToInsert, vertexPositionInFace2, edgeFacesIndexesFace2 ) )
2521 const QgsMeshFace &firstFaceSide1 = changes.mFacesToAdd.at( edgeFacesIndexes.at( 0 ) );
2524 const QgsMeshFace &secondFaceSide1 = changes.mFacesToAdd.at( edgeFacesIndexes.at( 1 ) );
2526 pos2InFaceSide1 = ( pos2InFaceSide1 + secondFaceSide1.size() - 1 ) % secondFaceSide1.size();
2528 const QgsMeshFace &firstFaceSide2 = changes.mFacesToAdd.at( edgeFacesIndexesFace2.at( 0 ) );
2531 const QgsMeshFace &secondFaceSide2 = changes.mFacesToAdd.at( edgeFacesIndexesFace2.at( 1 ) );
2533 pos2InFaceSide2 = ( pos2InFaceSide2 + secondFaceSide1.size() - 1 ) % secondFaceSide1.size();
2535 changes.mFacesNeighborhoodToAdd[edgeFacesIndexes.at( 0 )][pos1InFaceSide1] = edgeFacesIndexesFace2.at( 1 ) + changes.mAddedFacesFirstIndex;
2536 changes.mFacesNeighborhoodToAdd[edgeFacesIndexes.at( 1 )][pos2InFaceSide1] = edgeFacesIndexesFace2.at( 0 ) + changes.mAddedFacesFirstIndex;
2537 changes.mFacesNeighborhoodToAdd[edgeFacesIndexesFace2.at( 0 )][pos1InFaceSide2] = edgeFacesIndexes.at( 1 ) + changes.mAddedFacesFirstIndex;
2538 changes.mFacesNeighborhoodToAdd[edgeFacesIndexesFace2.at( 1 )][pos2InFaceSide2] = edgeFacesIndexes.at( 0 ) + changes.mAddedFacesFirstIndex;
2547 Q_ASSERT( verticesIndexes.count() == newValues.count() );
2550 changes.
mNewZValues.reserve( verticesIndexes.count() );
2551 changes.
mOldZValues.reserve( verticesIndexes.count() );
2552 for (
int i = 0; i < verticesIndexes.count(); ++i )
2566 Q_ASSERT( verticesIndexes.count() == newValues.count() );
2569 changes.
mNewXYValues.reserve( verticesIndexes.count() );
2570 changes.
mOldXYValues.reserve( verticesIndexes.count() );
2571 QSet<int> concernedFace;
2572 for (
int i = 0; i < verticesIndexes.count(); ++i )
2578 concernedFace.unite( QSet< int>( faces.begin(), faces.end() ) );
@ 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 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)
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.
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.