28 static int vertexPositionInFace(
int vertexIndex,
const QgsMeshFace &face )
30 return face.indexOf( vertexIndex );
33 static int vertexPositionInFace(
const QgsMesh &mesh,
int vertexIndex,
int faceIndex )
35 if ( faceIndex < 0 || faceIndex >= mesh.
faceCount() )
38 return vertexPositionInFace( vertexIndex, mesh.
face( faceIndex ) );
41 static double crossProduct(
int centralVertex,
int vertex1,
int vertex2,
const QgsMesh &mesh )
47 double ux1 = v1.
x() - vc.
x();
48 double uy1 = v1.
y() - vc.
y();
49 double vx1 = v2.
x() - vc.
x();
50 double vy1 = v2.
y() - vc.
y();
52 return ux1 * vy1 - uy1 * vx1;
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];
64 mIsValid = vertexPositionInFace( *topologicalMesh.
mesh(), vertexIndex, mCurrentFace ) != -1;
72 mLastValidFace = mCurrentFace;
76 : mFaces( topologicalFaces.mFaces )
77 , mFacesNeighborhood( topologicalFaces.mFacesNeighborhood )
78 , mVertexIndex( vertexIndex )
80 const QgsMeshFace &face = topologicalFaces.mFaces.at( faceIndex );
81 mIsValid = vertexPositionInFace( vertexIndex, face ) != -1;
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() )
191 int vertexPosition = vertexPositionInFace( mVertexIndex,
currentFace() );
193 if ( vertexPosition == -1 )
196 return face.at( ( vertexPosition + 1 ) % face.count() );
201 if ( mCurrentFace == -1 )
206 if ( face.isEmpty() )
209 int vertexPosition = vertexPositionInFace( mVertexIndex,
currentFace() );
211 if ( vertexPosition == -1 )
214 return face.at( ( vertexPosition - 1 + face.count() ) % face.count() );
228 if ( mCurrentFace != -1 )
229 ret.append( mCurrentFace );
274 int QgsMeshVertexCirculator::positionInCurrentFace()
const
276 if ( mCurrentFace < 0 || mCurrentFace > mFaces.count() )
279 return vertexPositionInFace( mVertexIndex, mFaces.at( mCurrentFace ) );
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 )
313 int boundaryPositionInNewFace = vertexPositionInFace( boundary, newFaceBoundary );
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() ) } );
356 int initialVerticesCount = mMesh->
vertices.count();
361 mVertexToFace.resize( newSize );
367 mMesh->
faces.resize( newSize );
368 mFacesNeighborhood.resize( newSize );
374 mFacesNeighborhood[changes.removedFaceIndexInMesh( i )] =
FaceNeighbors();
380 if ( mVertexToFace.at( vertexIndex ) == -1 )
381 dereferenceAsFreeVertex( vertexIndex );
383 mVertexToFace[vertexIndex] = -1;
391 referenceAsFreeVertex( initialVerticesCount + i );
394 for (
int i = 0; i < changes.
mFacesToAdd.count(); ++i )
396 mMesh->
faces[changes.addedFaceIndexInMesh( i )] = changes.
mFacesToAdd.at( i );
402 const int faceIndex = neigborChange.at( 0 );
403 const int positionInFace = neigborChange.at( 1 );
404 const int valueToApply = neigborChange.at( 3 );
405 mFacesNeighborhood[faceIndex][positionInFace] = valueToApply;
410 int vertexIndex = vertexToFaceChange.at( 0 );
411 mVertexToFace[vertexToFaceChange.at( 0 )] = vertexToFaceChange.at( 2 );
413 if ( vertexToFaceChange.at( 2 ) == -1 &&
414 vertexToFaceChange.at( 1 ) != -1 &&
415 !mMesh->
vertices.at( vertexIndex ).isEmpty() )
416 referenceAsFreeVertex( vertexIndex );
418 if ( vertexToFaceChange.at( 1 ) == -1 && vertexToFaceChange.at( 2 ) != -1 )
419 dereferenceAsFreeVertex( vertexIndex );
430 mMesh->
vertices[vertexIndex].setX( pt.
x() );
431 mMesh->
vertices[vertexIndex].setY( pt.
y() );
440 const int faceIndex = neigborChange.at( 0 );
441 const int positionInFace = neigborChange.at( 1 );
442 const int valueToApply = neigborChange.at( 2 );
443 mFacesNeighborhood[faceIndex][positionInFace] = valueToApply;
457 if ( mVertexToFace.at( vertexIndex ) == -1 )
458 referenceAsFreeVertex( vertexIndex );
462 for (
int i = 0; i < verticesToFaceChangesCount; ++i )
464 const std::array<int, 3> vertexToFaceChange = changes.
mVerticesToFaceChanges.at( verticesToFaceChangesCount - i - 1 );
465 int vertexIndex = vertexToFaceChange.at( 0 );
466 mVertexToFace[vertexIndex] = vertexToFaceChange.at( 1 );
468 if ( vertexToFaceChange.at( 2 ) == -1 && vertexToFaceChange.at( 1 ) != -1 )
469 dereferenceAsFreeVertex( vertexIndex );
471 if ( vertexToFaceChange.at( 1 ) == -1 &&
472 vertexToFaceChange.at( 2 ) != -1 &&
474 referenceAsFreeVertex( vertexIndex );
480 mMesh->
faces.resize( newSize );
481 mFacesNeighborhood.resize( newSize );
488 for (
int i = newSize; i < mMesh->
vertexCount(); ++i )
489 if ( mVertexToFace.at( i ) == -1 )
490 dereferenceAsFreeVertex( i );
493 mVertexToFace.resize( newSize );
504 mMesh->
vertices[vertexIndex].setX( pt.
x() );
505 mMesh->
vertices[vertexIndex].setY( pt.
y() );
515 QSet<int> QgsTopologicalMesh::concernedFacesBy(
const QList<int> faceIndexes )
const
518 for (
const int faceIndex : faceIndexes )
521 for (
int i = 0; i < face.count(); ++i )
527 void QgsTopologicalMesh::dereferenceAsFreeVertex(
int vertexIndex )
529 mFreeVertices.remove( vertexIndex );
532 void QgsTopologicalMesh::referenceAsFreeVertex(
int vertexIndex )
536 mFreeVertices.insert( vertexIndex );
541 for (
int faceIndex = 0 ; faceIndex < mMesh->
faces.count( ); ++faceIndex )
544 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( faceIndex );
545 if ( face.count() != neighborhood.count() )
547 for (
int i = 0; i < face.count(); ++i )
549 int vertexIndex = face.at( i );
551 if ( mVertexToFace.at( vertexIndex ) == -1 )
554 int neighborIndex = neighborhood.at( i );
555 if ( neighborIndex != -1 )
558 if ( neighborFace.isEmpty() )
560 int neighborSize = neighborFace.size();
561 const FaceNeighbors &neighborhoodOfNeighbor = mFacesNeighborhood.at( neighborIndex );
562 int posInNeighbor = vertexPositionInFace( *mMesh, vertexIndex, neighborIndex );
563 if ( neighborhoodOfNeighbor.isEmpty() || neighborhoodOfNeighbor.at( ( posInNeighbor + neighborSize - 1 ) % neighborSize ) != faceIndex )
569 for (
int vertexIndex = 0; vertexIndex < mMesh->
vertexCount(); ++vertexIndex )
571 if ( mVertexToFace.at( vertexIndex ) != -1 )
573 if ( !mMesh->
face( mVertexToFace.at( vertexIndex ) ).contains( vertexIndex ) )
599 if ( vertexIndex < 0 || vertexIndex >= mMesh->
vertexCount() )
601 return mVertexToFace.at( vertexIndex );
616 if ( vertexIndex < 0 || vertexIndex >= mMesh->
vertexCount() )
619 if ( mMesh->
vertices.at( vertexIndex ).isEmpty() )
622 return mVertexToFace.at( vertexIndex ) == -1;
627 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
628 return mFreeVertices.values();
630 return QList<int>( mFreeVertices.begin(), mFreeVertices.end() );
638 int faceSize = face.count();
643 for (
int i = 0; i < faceSize; ++i )
646 int iv1 = face[( i + 1 ) % faceSize];
647 int iv2 = face[( i + 2 ) % faceSize];
671 double crossProd = crossProduct( iv1, iv0, iv2, *
mesh );
672 if ( direction != 0 && crossProd * direction < 0 )
674 else if ( crossProd == 0 )
676 else if ( direction == 0 && crossProd != 0 )
677 direction = crossProd / std::fabs( crossProd );
682 for (
int i = 0; i < faceSize / 2; ++i )
685 face[i] = face.at( faceSize - i - 1 );
686 face[faceSize - i - 1] = temp;
695 QVector<int> oldToNewIndex( mMesh->
vertices.count(), -1 );
699 while ( oldIndex < verticesTotalCount )
707 oldToNewIndex[oldIndex] = newIndex;
708 if ( oldIndex != newIndex )
710 oldToNewIndex[oldIndex] = newIndex;
720 int facesTotalCount = mMesh->
faceCount();
721 while ( oldIndex < facesTotalCount )
723 if ( mMesh->
face( oldIndex ).isEmpty() )
727 if ( oldIndex != newIndex )
728 mMesh->
faces[newIndex] = mMesh->
faces[oldIndex];
730 for (
int i = 0; i < face.count(); ++i )
731 face[i] = oldToNewIndex[face.at( i )];
737 mMesh->
faces.resize( newIndex );
739 mVertexToFace.clear();
740 mFacesNeighborhood.clear();
745 QVector<int> oldToNewVerticesIndexes;
746 if ( !renumberVertices( oldToNewVerticesIndexes ) )
750 QVector<int> oldToNewFacesIndexes;
752 if ( !renumberFaces( oldToNewFacesIndexes ) )
757 QVector<QgsMeshVertex> tempVertices( mMesh->
vertices.count() );
758 for (
int i = 0; i < oldToNewVerticesIndexes.count(); ++i )
760 tempVertices[oldToNewVerticesIndexes.at( i )] = mMesh->
vertex( i );
764 QVector<QgsMeshFace> tempFaces( mMesh->
faces.count() );
765 for (
int i = 0; i < oldToNewFacesIndexes.count(); ++i )
767 tempFaces[oldToNewFacesIndexes.at( i )] = mMesh->
face( i );
769 QgsMeshFace &face = tempFaces[oldToNewFacesIndexes.at( i )];
771 for (
int fi = 0; fi < face.count(); ++fi )
773 face[fi] = oldToNewVerticesIndexes.at( face.at( fi ) );
777 mMesh->
faces = tempFaces;
783 bool QgsTopologicalMesh::renumberVertices( QVector<int> &oldToNewIndex )
const
785 std::vector<QgsMeshVertexCirculator> circulators;
786 circulators.reserve( mMesh->
vertices.count() );
787 int minDegree = std::numeric_limits<int>::max();
788 int minDegreeVertex = -1;
791 QSet<int> nonThreadedVertex;
792 oldToNewIndex = QVector<int> ( mMesh->
vertexCount(), -1 );
795 circulators.emplace_back( *
this, i );
797 if ( circulators.back().degree() < minDegree )
799 minDegreeVertex = circulators.size() - 1;
800 minDegree = circulator.
degree();
802 nonThreadedVertex.insert( i );
805 auto sortedNeighbor = [ = ]( QList<int> &neighbors,
int index )
819 int degree = circulators.at( neighborIndex ).degree();
820 QList<int>::Iterator it = neighbors.begin();
821 while ( it != neighbors.end() )
823 if ( degree <= circulators.at( *it ).degree() )
825 neighbors.insert( it, neighborIndex );
830 if ( it == neighbors.end() )
831 neighbors.append( neighborIndex );
837 int currentVertex = minDegreeVertex;
838 nonThreadedVertex.remove( minDegreeVertex );
840 while ( newIndex < mMesh->vertexCount() )
842 if ( oldToNewIndex[currentVertex] == -1 )
843 oldToNewIndex[currentVertex] = newIndex++;
845 if ( circulators.at( currentVertex ).isValid() )
847 QList<int> neighbors;
848 sortedNeighbor( neighbors, currentVertex );
850 for (
const int i : std::as_const( neighbors ) )
851 if ( oldToNewIndex.at( i ) == -1 && nonThreadedVertex.contains( i ) )
854 nonThreadedVertex.remove( i );
858 if ( queue.isEmpty() )
860 if ( nonThreadedVertex.isEmpty() && newIndex < mMesh->vertexCount() )
863 const QList<int> remainingVertex = qgis::setToList( nonThreadedVertex );
864 int minRemainingDegree = std::numeric_limits<int>::max();
865 int minRemainingVertex = -1;
866 for (
const int i : remainingVertex )
868 int degree = circulators.at( i ).degree();
869 if ( degree < minRemainingDegree )
871 minRemainingDegree = degree;
872 minRemainingVertex = i;
875 currentVertex = minRemainingVertex;
876 nonThreadedVertex.remove( currentVertex );
880 currentVertex = queue.dequeue();
887 bool QgsTopologicalMesh::renumberFaces( QVector<int> &oldToNewIndex )
const
890 QSet<int> nonThreadedFaces;
892 oldToNewIndex = QVector<int>( mMesh->
faceCount(), -1 );
894 QVector<int> faceDegrees( mMesh->
faceCount(), 0 );
896 int minDegree = std::numeric_limits<int>::max();
897 int minDegreeFace = -1;
898 for (
int faceIndex = 0; faceIndex < mMesh->
faceCount(); ++faceIndex )
900 const FaceNeighbors &neighbors = mFacesNeighborhood.at( faceIndex );
903 for (
int n = 0; n < neighbors.size(); ++n )
905 if ( neighbors.at( n ) != -1 )
909 if ( degree < minDegree )
912 minDegreeFace = faceIndex;
915 faceDegrees[faceIndex] = degree;
916 nonThreadedFaces.insert( faceIndex );
920 int currentFace = minDegreeFace;
921 nonThreadedFaces.remove( minDegreeFace );
923 auto sortedNeighbor = [ = ]( QList<int> &neighbors,
int index )
925 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( index );
927 for (
int i = 0; i < neighborhood.count(); ++i )
929 int neighborIndex = neighborhood.at( i );
930 if ( neighborIndex == -1 )
933 int degree = faceDegrees.at( neighborIndex );
934 if ( neighbors.isEmpty() )
935 neighbors.append( neighborIndex );
938 QList<int>::Iterator it = neighbors.begin();
939 while ( it != neighbors.end() )
941 if ( degree <= faceDegrees.at( *it ) )
943 neighbors.insert( it, neighborIndex );
948 if ( it == neighbors.end() )
949 neighbors.append( neighborIndex );
954 while ( newIndex < mMesh->faceCount() )
956 if ( oldToNewIndex[currentFace] == -1 )
957 oldToNewIndex[currentFace] = newIndex++;
959 QList<int> neighbors;
960 sortedNeighbor( neighbors, currentFace );
962 for (
const int i : std::as_const( neighbors ) )
963 if ( oldToNewIndex.at( i ) == -1 && nonThreadedFaces.contains( i ) )
966 nonThreadedFaces.remove( i );
969 if ( queue.isEmpty() )
971 if ( nonThreadedFaces.isEmpty() && newIndex < mMesh->faceCount() )
974 const QList<int> remainingFace = qgis::setToList( nonThreadedFaces );
975 int minRemainingDegree = std::numeric_limits<int>::max();
976 int minRemainingFace = -1;
977 for (
const int i : remainingFace )
979 int degree = faceDegrees.at( i );
980 if ( degree < minRemainingDegree )
982 minRemainingDegree = degree;
983 minRemainingFace = i;
986 currentFace = minRemainingFace;
987 nonThreadedFaces.remove( currentFace );
991 currentFace = queue.dequeue();
1006 return mFacesToRemove;
1011 return mFaceIndexesToRemove;
1016 return mVerticesToAdd;
1021 return mChangeCoordinateVerticesIndexes;
1031 return mNewXYValues;
1036 return mOldXYValues;
1041 return mNativeFacesIndexesGeometryChanged;
1046 return ( mFaceIndexesToRemove.isEmpty() &&
1047 mFacesToAdd.isEmpty() &&
1048 mFacesNeighborhoodToAdd.isEmpty() &&
1049 mFacesToRemove.isEmpty() &&
1050 mFacesNeighborhoodToRemove.isEmpty() &&
1051 mNeighborhoodChanges.isEmpty() &&
1052 mVerticesToAdd.isEmpty() &&
1053 mVertexToFaceToAdd.isEmpty() &&
1054 mVerticesToRemoveIndexes.isEmpty() &&
1055 mRemovedVertices.isEmpty() &&
1056 mVerticesToFaceRemoved.isEmpty() &&
1057 mVerticesToFaceChanges.isEmpty() &&
1058 mChangeCoordinateVerticesIndexes.isEmpty() &&
1059 mNewZValues.isEmpty() &&
1060 mOldZValues.isEmpty() &&
1061 mNewXYValues.isEmpty() &&
1062 mOldXYValues.isEmpty() &&
1063 mNativeFacesIndexesGeometryChanged.isEmpty() );
1068 return mVerticesToRemoveIndexes;
1071 int QgsTopologicalMesh::Changes::addedFaceIndexInMesh(
int internalIndex )
const
1073 if ( internalIndex == -1 )
1076 return internalIndex + mAddedFacesFirstIndex;
1079 int QgsTopologicalMesh::Changes::removedFaceIndexInMesh(
int internalIndex )
const
1081 if ( internalIndex == -1 )
1084 return mFaceIndexesToRemove.at( internalIndex );
1089 mAddedFacesFirstIndex = 0;
1090 mFaceIndexesToRemove.clear();
1091 mFacesToAdd.clear();
1092 mFacesNeighborhoodToAdd.clear();
1093 mFacesToRemove.clear();
1094 mFacesNeighborhoodToRemove.clear();
1095 mNeighborhoodChanges.clear();
1097 mVerticesToAdd.clear();
1098 mVertexToFaceToAdd.clear();
1099 mVerticesToRemoveIndexes.clear();
1100 mRemovedVertices.clear();
1101 mVerticesToFaceRemoved.clear();
1102 mVerticesToFaceChanges.clear();
1104 mChangeCoordinateVerticesIndexes.clear();
1105 mNewZValues.clear();
1106 mOldZValues.clear();
1107 mNewXYValues.clear();
1108 mOldXYValues.clear();
1109 mNativeFacesIndexesGeometryChanged.clear();
1119 mVertexToFace.append( -1 );
1120 referenceAsFreeVertex( mMesh->
vertices.count() - 1 );
1126 static double vertexPolygonOrientation(
const QgsMesh &
mesh,
const QList<int> &vertexIndexes )
1128 if ( vertexIndexes.count() < 3 )
1131 int hullDomainVertexPos = -1;
1132 double xMin = std::numeric_limits<double>::max();
1133 double yMin = std::numeric_limits<double>::max();
1134 for (
int i = 0; i < vertexIndexes.count(); ++i )
1137 if ( xMin >= vertex.
x() && yMin > vertex.
y() )
1139 hullDomainVertexPos = i;
1145 if ( hullDomainVertexPos >= 0 )
1147 int iv1 = vertexIndexes.at( ( hullDomainVertexPos - 1 + vertexIndexes.count() ) % vertexIndexes.count() );
1148 int iv2 = vertexIndexes.at( ( hullDomainVertexPos + 1 ) % vertexIndexes.count() );
1149 int ivc = vertexIndexes.at( ( hullDomainVertexPos ) );
1150 double cp = crossProduct( ivc, iv1, iv2,
mesh );
1159 if ( vertexIndex >= mVertexToFace.count() )
1162 if ( mVertexToFace.at( vertexIndex ) == -1 )
1168 dereferenceAsFreeVertex( vertexIndex );
1176 QList<int> boundariesVertexIndex;
1177 QList<int> associateFaceToBoundaries;
1178 QList<int> removedFacesIndexes;
1179 QSet<int> boundaryInGlobalMesh;
1185 Q_ASSERT( !mMesh->
vertices.at( boundariesVertexIndex.last() ).isEmpty() );
1187 associateFaceToBoundaries.append( mFacesNeighborhood.at( circulator.
currentFaceIndex() ).at(
1188 vertexPositionInFace( boundariesVertexIndex.last(), currentFace ) ) );
1190 if ( currentFace.count() > 3 )
1192 int posInface = vertexPositionInFace( vertexIndex, currentFace );
1193 for (
int i = 2; i < currentFace.count() - 1; ++i )
1195 boundariesVertexIndex.append( currentFace.at( ( posInface + i ) % currentFace.count() ) );
1196 Q_ASSERT( !mMesh->
vertices.at( boundariesVertexIndex.last() ).isEmpty() );
1197 associateFaceToBoundaries.append( mFacesNeighborhood.at( circulator.
currentFaceIndex() ).at(
1198 vertexPositionInFace( boundariesVertexIndex.last(), currentFace ) ) );
1204 bool boundaryFill =
false;
1207 boundaryFill =
true;
1211 boundariesVertexIndex.append( lastVertexIndex );
1220 boundaryFill =
false;
1223 associateFaceToBoundaries.append( -1 );
1225 for (
const int index : std::as_const( boundariesVertexIndex ) )
1228 boundaryInGlobalMesh.insert( index );
1232 int currentVertexToFace = mVertexToFace.at( vertexIndex );
1236 QList<QList<int>> holes;
1237 QList<QList<int>> associateMeshFacesToHoles;
1239 bool cancelOperation =
false;
1247 int finalPos = boundariesVertexIndex.count() - 1;
1248 QList<int> uncoveredVertex;
1250 QList<int> partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1251 QList<int> associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1252 while ( startPos < finalPos && !partToCheck.isEmpty() )
1255 int secondPos = partToCheck.count() - 1;
1256 const QgsPoint &closingSegmentExtremety1 = mMesh->
vertex( partToCheck.at( 0 ) );
1257 const QgsPoint &closingSegmentExtremety2 = mMesh->
vertex( partToCheck.last() );
1258 bool isEdgeIntersect =
false;
1259 for (
int i = 1; i < secondPos - 1; ++i )
1263 bool isLineIntersection;
1266 if ( isEdgeIntersect )
1270 int index = partToCheck.at( 0 );
1271 if ( boundaryInGlobalMesh.contains( index ) && index != boundariesVertexIndex.at( 0 ) )
1273 cancelOperation =
true;
1279 if ( isEdgeIntersect || vertexPolygonOrientation( *mMesh, partToCheck ) >= 0 )
1281 partToCheck.removeLast();
1282 associateFacePart.removeAt( associateFacePart.count() - 2 );
1283 if ( partToCheck.count() == 1 )
1285 uncoveredVertex.append( index );
1286 startPos = startPos + 1;
1287 partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1288 associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1294 holes.append( partToCheck );
1295 associateMeshFacesToHoles.append( associateFacePart );
1297 startPos = startPos + partToCheck.count() - 1;
1298 uncoveredVertex.append( partToCheck.at( 0 ) );
1299 partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1300 associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1306 holes.append( boundariesVertexIndex );
1307 associateMeshFacesToHoles.append( associateFaceToBoundaries );
1310 if ( cancelOperation )
1316 Q_ASSERT( holes.count() == associateMeshFacesToHoles.count() );
1322 dereferenceAsFreeVertex( vertexIndex );
1324 mVertexToFace[vertexIndex] = -1;
1327 for (
int h = 0; h < holes.count(); ++h )
1329 const QList<int> &holeVertices = holes.at( h );
1330 const QList<int> &associateMeshFacesToHole = associateMeshFacesToHoles.at( h );
1331 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
1332 std::vector<p2t::Point *> holeToFill( holeVertices.count() );
1335 for (
int i = 0; i < holeVertices.count(); ++i )
1338 holeToFill[i] =
new p2t::Point( vertex.
x(), vertex.
y() );
1339 mapPoly2TriPointToVertex.insert( holeToFill[i], holeVertices.at( i ) );
1342 std::unique_ptr<p2t::CDT> cdt(
new p2t::CDT( holeToFill ) );
1345 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
1346 QVector<QgsMeshFace> newFaces( triangles.size() );
1347 for (
size_t i = 0; i < triangles.size(); ++i )
1351 for (
int j = 0; j < 3; j++ )
1353 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
1354 if ( vertInd == -1 )
1355 throw std::exception();
1356 Q_ASSERT( !mMesh->
vertices.at( vertInd ).isEmpty() );
1364 throw std::exception();
1365 int newFaceIndexStartIndex = mMesh->
faceCount();
1372 const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
1373 for (
const int vtc : verticesToFaceToChange )
1374 if ( mVertexToFace.at( vtc ) == -1 )
1376 mVertexToFace.at( vtc ),
1377 addChanges.addedFaceIndexInMesh( topologicalFaces.mVerticesToFace.values( vtc ).first() ) } );
1381 for (
int i = 0; i < topologicalFaces.mFaces.count(); ++i )
1384 faceNeighbors = topologicalFaces.mFacesNeighborhood.at( i );
1385 for (
int n = 0; n < faceNeighbors.count(); ++n )
1387 if ( faceNeighbors.at( n ) != -1 )
1388 faceNeighbors[n] += newFaceIndexStartIndex;
1393 for (
int i = 0 ; i < holeVertices.count(); ++i )
1395 int vertexHoleIndex = holeVertices.at( i );
1396 int meshFaceBoundaryIndex = associateMeshFacesToHole.at( i );
1401 int newFaceBoundaryIndexInMesh = circulator.
currentFaceIndex() + newFaceIndexStartIndex;
1403 int positionInNewFaces = vertexPositionInFace( vertexHoleIndex, newFace );
1405 if ( meshFaceBoundaryIndex != -1 )
1408 int positionInMeshFaceBoundary = vertexPositionInFace( *mMesh, vertexHoleIndex, meshFaceBoundaryIndex );
1409 positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.count() ) % meshFace.count();
1411 addChanges.
mNeighborhoodChanges.append( {meshFaceBoundaryIndex, positionInMeshFaceBoundary, -1, newFaceBoundaryIndexInMesh} );
1422 for (
const std::array<int, 4> &neighborChangeToAdd : std::as_const( addChanges.
mNeighborhoodChanges ) )
1424 bool merged =
false;
1427 if ( existingNeighborChange.at( 0 ) == neighborChangeToAdd.at( 0 ) &&
1428 existingNeighborChange.at( 1 ) == neighborChangeToAdd.at( 1 ) )
1431 Q_ASSERT( existingNeighborChange.at( 3 ) == neighborChangeToAdd.at( 2 ) );
1432 existingNeighborChange[3] = neighborChangeToAdd.at( 3 );
1439 for (
const std::array<int, 3> &verticesToFaceToAdd : std::as_const( addChanges.
mVerticesToFaceChanges ) )
1441 bool merged =
false;
1444 if ( existingVerticesToFace.at( 0 ) == verticesToFaceToAdd.at( 0 ) )
1447 Q_ASSERT( existingVerticesToFace.at( 2 ) == verticesToFaceToAdd.at( 1 ) );
1448 existingVerticesToFace[2] = verticesToFaceToAdd.at( 2 );
1455 qDeleteAll( holeToFill );
1459 qDeleteAll( holeToFill );
1474 QSet<int> facesIndex;
1476 for (
int vertexIndex : vertices )
1483 for (
int vertexIndex : vertices )
1485 int currentVertexToFace = mVertexToFace.at( vertexIndex );
1491 dereferenceAsFreeVertex( vertexIndex );
1493 mVertexToFace[vertexIndex] = -1;
1501 QList<int> boundariesToCheckClockwiseInNewFaces = topologicFaces.mBoundaries;
1502 QList<std::array<int, 2>> boundariesToCheckCounterClockwiseInNewFaces;
1503 QList<int> uniqueSharedVertexBoundary;
1511 while ( !boundariesToCheckClockwiseInNewFaces.isEmpty() )
1513 int boundary = boundariesToCheckClockwiseInNewFaces.takeLast();
1515 const QList<int> &linkedFaces = topologicFaces.mVerticesToFace.values( boundary );
1517 for (
int const linkedFace : linkedFaces )
1521 if ( mVertexToFace.at( boundary ) == -1 )
1527 if ( !newFacescirculator.
isValid() )
1541 if ( oppositeVertexCCWInMesh == oppositeVertexInNewFaces )
1547 int faceSize = newFaceOnBoundary.size();
1548 int posInNewFace = vertexPositionInFace( boundary, newFaceOnBoundary );
1549 int previousVertexIndex = ( posInNewFace + faceSize - 1 ) % faceSize;
1550 if ( newFaceOnBoundary.at( previousVertexIndex ) == oppositeVertexCCWInMesh )
1558 if ( oppositeVertexCWInMesh == oppositeVertexInNewFaces )
1562 boundariesToCheckCounterClockwiseInNewFaces.append( {boundary, linkedFace} );
1567 while ( !boundariesToCheckCounterClockwiseInNewFaces.isEmpty() )
1569 std::array<int, 2> boundaryLinkedface = boundariesToCheckCounterClockwiseInNewFaces.takeLast();
1570 int boundary = boundaryLinkedface.at( 0 );
1571 int linkedFace = boundaryLinkedface.at( 1 );
1586 if ( oppositeVertexCWInMesh == oppositeVertexInNewFaces )
1593 if ( oppositeVertexCCWInMesh == oppositeVertexInNewFaces )
1596 uniqueSharedVertexBoundary.append( boundary );
1599 if ( !uniqueSharedVertexBoundary.isEmpty() )
1603 QSet<int> boundaryVertices = qgis::listToSet( topologicFaces.mBoundaries );
1604 for (
const QgsMeshFace &newFace : std::as_const( topologicFaces.mFaces ) )
1606 for (
const int vertexIndex : newFace )
1608 if ( boundaryVertices.contains( vertexIndex ) )
1610 if ( mVertexToFace.at( vertexIndex ) != -1 )
1621 mFacesNeighborhood.clear();
1622 mVerticesToFace.clear();
1623 mBoundaries.clear();
1628 return mFacesNeighborhood;
1633 if ( mVerticesToFace.contains( vertexIndex ) )
1634 return mVerticesToFace.values( vertexIndex ).at( 0 );
1642 topologicMesh.mMesh =
mesh;
1643 topologicMesh.mVertexToFace = QVector<int>(
mesh->
vertexCount(), -1 );
1644 topologicMesh.mMaximumVerticesPerFace = maxVerticesPerFace;
1651 if ( maxVerticesPerFace != 0 &&
mesh->
face( i ).count() > maxVerticesPerFace )
1669 topologicMesh.mFacesNeighborhood = subMesh.mFacesNeighborhood;
1671 for (
int i = 0; i < topologicMesh.mMesh->
vertexCount(); ++i )
1673 if ( topologicMesh.mVertexToFace.at( i ) == -1 )
1674 topologicMesh.mFreeVertices.insert( i );
1678 return topologicMesh;
1683 return createTopologicalFaces( faces,
nullptr, error, uniqueSharedVertexAllowed );
1688 const QVector<QgsMeshFace> &faces,
1689 QVector<int> *globalVertexToFace,
1691 bool allowUniqueSharedVertex )
1693 int facesCount = faces.count();
1694 QVector<FaceNeighbors> faceTopologies;
1695 QMultiHash<int, int> verticesToFace;
1698 TopologicalFaces ret;
1702 QMap<int, QMap<int, int>> verticesToNeighbor;
1704 for (
int faceIndex = 0; faceIndex < facesCount; ++faceIndex )
1707 int faceSize = face.count();
1709 for (
int i = 0; i < faceSize; ++i )
1711 int v1 = face[i % faceSize];
1712 int v2 = face[( i + 1 ) % faceSize];
1713 if ( verticesToNeighbor[v2].contains( v1 ) )
1719 verticesToNeighbor[v2].insert( v1, faceIndex );
1723 faceTopologies = QVector<FaceNeighbors>( faces.count() );
1725 QSet<int> boundaryVertices;
1727 for (
int faceIndex = 0; faceIndex < facesCount; ++faceIndex )
1730 int faceSize = face.size();
1732 faceTopology.resize( faceSize );
1734 for (
int i = 0; i < faceSize; ++i )
1736 int v1 = face.at( i );
1737 int v2 = face.at( ( i + 1 ) % faceSize );
1739 if ( globalVertexToFace )
1741 if ( ( *globalVertexToFace )[v1] == -1 )
1742 ( *globalVertexToFace )[v1] = faceIndex ;
1746 if ( allowUniqueSharedVertex || !verticesToFace.contains( v1 ) )
1747 verticesToFace.insert( v1, faceIndex ) ;
1750 QMap<int, int> &edges = verticesToNeighbor[v1];
1751 if ( edges.contains( v2 ) )
1752 faceTopology[i] = edges.value( v2 );
1755 faceTopology[i] = -1;
1757 if ( !allowUniqueSharedVertex )
1759 if ( boundaryVertices.contains( v1 ) )
1765 boundaryVertices.insert( v1 );
1771 ret.mFacesNeighborhood = faceTopologies;
1772 ret.mBoundaries = boundaryVertices.values();
1773 ret.mVerticesToFace = verticesToFace;
1779 return mFacesNeighborhood.at( faceIndex );
1791 QSet<int> removedFaces = qgis::listToSet( facesIndexes );
1792 QSet<int> concernedFaces = concernedFacesBy( facesIndexes );
1794 for (
const int f : std::as_const( removedFaces ) )
1795 concernedFaces.remove( f );
1797 QVector<QgsMeshFace> remainingFaces;
1798 remainingFaces.reserve( concernedFaces.count() );
1799 for (
const int f : std::as_const( concernedFaces ) )
1800 remainingFaces.append( mMesh->
face( f ) );
1803 createTopologicalFaces( remainingFaces,
nullptr, error,
false );
1815 QSet<int> indexSet = qgis::listToSet( facesIndexesToRemove );
1816 QSet<int> threatedVertex;
1818 for (
int i = 0; i < facesIndexesToRemove.count(); ++i )
1820 const int faceIndex = facesIndexesToRemove.at( i );
1823 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( faceIndex );
1825 for (
int j = 0; j < face.count(); ++j )
1828 int neighborIndex = neighborhood.at( j );
1829 if ( neighborIndex != -1 && !indexSet.contains( neighborIndex ) )
1831 int positionInNeighbor = mFacesNeighborhood.at( neighborIndex ).indexOf( faceIndex );
1836 int vertexIndex = face.at( j );
1837 if ( !threatedVertex.contains( vertexIndex ) && indexSet.contains( mVertexToFace.at( vertexIndex ) ) )
1839 int oldValue = mVertexToFace.at( vertexIndex );
1842 if ( neighborIndex != -1 && !indexSet.contains( neighborIndex ) )
1843 refValue = neighborIndex;
1847 aroundFaces.removeOne( faceIndex );
1848 if ( !aroundFaces.isEmpty() )
1850 while ( !aroundFaces.isEmpty() && refValue == -1 )
1852 if ( !indexSet.contains( aroundFaces.first() ) )
1853 refValue = aroundFaces.first();
1855 aroundFaces.removeFirst();
1860 threatedVertex.insert( vertexIndex );
1870 bool QgsTopologicalMesh::eitherSideFacesAndVertices(
int vertexIndex1,
1874 int &neighborVertex1InFace1,
1875 int &neighborVertex1InFace2,
1876 int &neighborVertex2inFace1,
1877 int &neighborVertex2inFace2 )
const
1919 int oppositeVertexFace1;
1920 int oppositeVertexFace2;
1921 int supposedOppositeVertexFace1;
1922 int supposedoppositeVertexFace2;
1924 bool result = eitherSideFacesAndVertices(
1929 oppositeVertexFace1,
1930 supposedoppositeVertexFace2,
1931 supposedOppositeVertexFace1,
1932 oppositeVertexFace2 );
1937 oppositeVertexFace1 < 0 ||
1938 oppositeVertexFace2 < 0 ||
1939 supposedOppositeVertexFace1 != oppositeVertexFace1 ||
1940 supposedoppositeVertexFace2 != oppositeVertexFace2 )
1947 if ( face1.count() != 3 || face2.count() != 3 )
1950 double crossProduct1 = crossProduct( vertexIndex1, oppositeVertexFace1, oppositeVertexFace2, *mMesh );
1951 double crossProduct2 = crossProduct( vertexIndex2, oppositeVertexFace1, oppositeVertexFace2, *mMesh );
1953 return crossProduct1 * crossProduct2 < 0;
1960 int oppositeVertexFace1;
1961 int oppositeVertexFace2;
1962 int supposedOppositeVertexFace1;
1963 int supposedoppositeVertexFace2;
1965 bool result = eitherSideFacesAndVertices(
1970 oppositeVertexFace1,
1971 supposedoppositeVertexFace2,
1972 supposedOppositeVertexFace1,
1973 oppositeVertexFace2 );
1978 oppositeVertexFace1 < 0 ||
1979 oppositeVertexFace2 < 0 ||
1980 supposedOppositeVertexFace1 != oppositeVertexFace1 ||
1981 supposedoppositeVertexFace2 != oppositeVertexFace2 )
1990 Q_ASSERT( face1.count() == 3 );
1991 Q_ASSERT( face2.count() == 3 );
1993 int pos1 = vertexPositionInFace( vertexIndex1, face1 );
1994 int pos2 = vertexPositionInFace( vertexIndex2, face2 );
1996 int neighborFace1 = mFacesNeighborhood.at( faceIndex1 ).at( pos1 );
1997 int posInNeighbor1 = vertexPositionInFace( *mMesh, oppositeVertexFace1, neighborFace1 );
1998 int neighborFace2 = mFacesNeighborhood.at( faceIndex1 ).at( ( pos1 + 1 ) % 3 );
1999 int posInNeighbor2 = vertexPositionInFace( *mMesh, vertexIndex2, neighborFace2 );
2000 int neighborFace3 = mFacesNeighborhood.at( faceIndex2 ).at( pos2 );
2001 int posInNeighbor3 = vertexPositionInFace( *mMesh, oppositeVertexFace2, neighborFace3 );
2002 int neighborFace4 = mFacesNeighborhood.at( faceIndex2 ).at( ( pos2 + 1 ) % 3 );
2003 int posInNeighbor4 = vertexPositionInFace( *mMesh, vertexIndex1, neighborFace4 );
2013 changes.
mFacesToAdd.append( {oppositeVertexFace1, oppositeVertexFace2, vertexIndex1} );
2014 changes.
mFacesToAdd.append( {oppositeVertexFace2, oppositeVertexFace1, vertexIndex2} );
2016 mFacesNeighborhood.at( faceIndex2 ).at( ( pos2 + 1 ) % 3 ),
2017 mFacesNeighborhood.at( faceIndex1 ).at( pos1 )} );
2019 mFacesNeighborhood.at( faceIndex1 ).at( ( pos1 + 1 ) % 3 ),
2020 mFacesNeighborhood.at( faceIndex2 ).at( pos2 )} );
2022 if ( neighborFace1 >= 0 )
2023 changes.
mNeighborhoodChanges.append( {neighborFace1, posInNeighbor1, faceIndex1, startIndex} );
2024 if ( neighborFace2 >= 0 )
2025 changes.
mNeighborhoodChanges.append( {neighborFace2, posInNeighbor2, faceIndex1, startIndex + 1} );
2026 if ( neighborFace3 >= 0 )
2027 changes.
mNeighborhoodChanges.append( {neighborFace3, posInNeighbor3, faceIndex2, startIndex + 1} );
2028 if ( neighborFace4 >= 0 )
2029 changes.
mNeighborhoodChanges.append( {neighborFace4, posInNeighbor4, faceIndex2, startIndex} );
2032 if ( mVertexToFace.at( vertexIndex1 ) == faceIndex1 || mVertexToFace.at( vertexIndex1 ) == faceIndex2 )
2034 if ( mVertexToFace.at( vertexIndex2 ) == faceIndex1 || mVertexToFace.at( vertexIndex2 ) == faceIndex2 )
2035 changes.
mVerticesToFaceChanges.append( {vertexIndex2, mVertexToFace.at( vertexIndex2 ), startIndex + 1} );
2037 if ( mVertexToFace.at( oppositeVertexFace1 ) == faceIndex1 )
2040 if ( mVertexToFace.at( oppositeVertexFace2 ) == faceIndex2 )
2052 int neighborVertex1InFace1;
2053 int neighborVertex1InFace2;
2054 int neighborVertex2inFace1;
2055 int neighborVertex2inFace2;
2057 bool result = eitherSideFacesAndVertices(
2062 neighborVertex1InFace1,
2063 neighborVertex1InFace2,
2064 neighborVertex2inFace1,
2065 neighborVertex2inFace2 );
2075 if ( face1.count() + face2.count() - 2 > mMaximumVerticesPerFace )
2085 double crossProduct1 = crossProduct( vertexIndex1, neighborVertex1InFace1, neighborVertex1InFace2, *mMesh );
2086 double crossProduct2 = crossProduct( vertexIndex2, neighborVertex2inFace1, neighborVertex2inFace2, *mMesh );
2088 return crossProduct1 * crossProduct2 < 0;
2095 int neighborVertex1InFace1;
2096 int neighborVertex1InFace2;
2097 int neighborVertex2inFace1;
2098 int neighborVertex2inFace2;
2100 bool result = eitherSideFacesAndVertices(
2105 neighborVertex1InFace1,
2106 neighborVertex1InFace2,
2107 neighborVertex2inFace1,
2108 neighborVertex2inFace2 );
2119 int faceSize1 = face1.count();
2120 int faceSize2 = face2.count();
2122 int pos1 = vertexPositionInFace( vertexIndex1, face1 );
2123 int pos2 = vertexPositionInFace( vertexIndex2, face2 );
2136 for (
int i = 0; i < faceSize1 - 1; ++i )
2138 int currentPos = ( pos1 + i ) % faceSize1;
2139 newface.append( face1.at( currentPos ) );
2141 int currentNeighbor = mFacesNeighborhood.at( faceIndex1 ).at( currentPos );
2142 newNeighborhood.append( currentNeighbor );
2144 if ( currentNeighbor != -1 )
2146 int currentPosInNeighbor = vertexPositionInFace( *mMesh, face1.at( ( currentPos + 1 ) % faceSize1 ), currentNeighbor );
2147 changes.
mNeighborhoodChanges.append( {currentNeighbor, currentPosInNeighbor, faceIndex1, startIndex} );
2150 for (
int i = 0; i < faceSize2 - 1; ++i )
2152 int currentPos = ( pos2 + i ) % faceSize2;
2153 newface.append( face2.at( currentPos ) );
2155 int currentNeighbor = mFacesNeighborhood.at( faceIndex2 ).at( currentPos );
2156 newNeighborhood.append( currentNeighbor );
2158 if ( currentNeighbor != -1 )
2160 int currentPosInNeighbor = vertexPositionInFace( *mMesh, face2.at( ( currentPos + 1 ) % faceSize2 ), currentNeighbor );
2161 changes.
mNeighborhoodChanges.append( {currentNeighbor, currentPosInNeighbor, faceIndex2, startIndex} );
2165 for (
int i = 0; i < faceSize1; ++i )
2166 if ( mVertexToFace.at( face1.at( i ) ) == faceIndex1 )
2169 for (
int i = 0; i < faceSize2; ++i )
2170 if ( mVertexToFace.at( face2.at( i ) ) == faceIndex2 )
2185 return face.count() == 4;
2192 int faceSize = face.count();
2194 Q_ASSERT( faceSize == 4 );
2196 double maxAngle = 0;
2197 int splitVertexPos = -1;
2198 for (
int i = 0; i < faceSize; ++i )
2200 QgsVector vect1( mMesh->
vertex( face.at( i ) ) - mMesh->
vertex( face.at( ( i + 1 ) % faceSize ) ) );
2201 QgsVector vect2( mMesh->
vertex( face.at( ( i + 2 ) % faceSize ) ) - mMesh->
vertex( face.at( ( i + 1 ) % faceSize ) ) );
2203 double angle = std::abs( vect1.
angle( vect2 ) );
2205 if (
angle > maxAngle )
2208 splitVertexPos = ( i + 1 ) % faceSize;
2214 const QgsMeshFace newFace1 = {face.at( splitVertexPos ),
2215 face.at( ( splitVertexPos + 1 ) % faceSize ),
2216 face.at( ( splitVertexPos + 2 ) % faceSize )
2219 const QgsMeshFace newFace2 = {face.at( splitVertexPos ),
2220 face.at( ( splitVertexPos + 2 ) % faceSize ),
2221 face.at( ( splitVertexPos + 3 ) % faceSize )
2224 QVector<int> neighborIndex( faceSize );
2225 QVector<int> posInNeighbor( faceSize );
2227 for (
int i = 0; i < faceSize; ++i )
2229 neighborIndex[i] = mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + i ) % faceSize );
2230 posInNeighbor[i] = vertexPositionInFace( *mMesh, face.at( ( splitVertexPos + i + 1 ) % faceSize ), neighborIndex[i] );
2242 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 1 ) % faceSize ),
2245 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 2 ) % faceSize ),
2246 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 3 ) % faceSize )} );
2248 for (
int i = 0; i < faceSize; ++i )
2250 if ( neighborIndex[i] >= 0 )
2251 changes.
mNeighborhoodChanges.append( {neighborIndex[i], posInNeighbor[i], faceIndex, startIndex + int( i / 2 )} );
2253 int vertexIndex = face.at( ( splitVertexPos + i ) % faceSize );
2254 if ( mVertexToFace.at( vertexIndex ) == faceIndex )
2271 mVertexToFace.append( -1 );
2275 const FaceNeighbors includingFaceNeighborhood = mFacesNeighborhood.at( includingFaceIndex );
2276 int includingFaceSize = includingFace.count();
2278 for (
int i = 0; i < includingFaceSize; ++i )
2283 face[1] = includingFace.at( i );
2284 face[2] = includingFace.at( ( i + 1 ) % includingFaceSize );
2285 mMesh->
faces.append( face );
2288 int currentVertexIndex = includingFace.at( i );
2289 if ( mVertexToFace.at( currentVertexIndex ) == includingFaceIndex )
2291 int newFaceIndex = mMesh->
faceCount() - 1;
2292 mVertexToFace[currentVertexIndex] = newFaceIndex;
2296 int includingFaceNeighbor = includingFaceNeighborhood.at( i );
2300 includingFaceNeighbor,
2303 mFacesNeighborhood.append( neighbors );
2306 if ( includingFaceNeighbor != -1 )
2308 int indexInNeighbor = vertexPositionInFace( *mMesh, includingFace.at( ( i + 1 ) % includingFaceSize ), includingFaceNeighbor );
2309 int oldValue = mFacesNeighborhood[includingFaceNeighbor][indexInNeighbor];
2321 mVertexToFace[mVertexToFace.count() - 1] = mMesh->
faceCount() - 1;
2336 int newVertexPositionInFace1 = position + 1;
2338 auto triangulate = [
this, &changes](
int removedFaceIndex,
const QgsMeshVertex & newVertex,
int newVertexPosition, QVector<int> &edgeFacesIndexes )->
bool
2344 const int addedVertexIndex = mMesh->
vertexCount();
2347 int localStartIndex = changes.
mFacesToAdd.count();
2349 QVector<int> newBoundary = initialFace;
2350 newBoundary.insert( newVertexPosition, addedVertexIndex );
2354 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
2355 std::vector<p2t::Point *> faceToFill( newBoundary.count() );
2356 for (
int i = 0; i < newBoundary.count(); ++i )
2360 if ( newBoundary.at( i ) == addedVertexIndex )
2363 vert = mMesh->
vertex( newBoundary.at( i ) );
2365 faceToFill[i] =
new p2t::Point( vert.
x(), vert.
y() );
2366 mapPoly2TriPointToVertex.insert( faceToFill[i], newBoundary.at( i ) );
2369 std::unique_ptr<p2t::CDT> cdt(
new p2t::CDT( faceToFill ) );
2371 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
2372 QVector<QgsMeshFace> newFaces( triangles.size() );
2373 for (
size_t i = 0; i < triangles.size(); ++i )
2377 for (
int j = 0; j < 3; j++ )
2379 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
2380 if ( vertInd == -1 )
2381 throw std::exception();
2389 throw std::exception();
2395 const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
2396 for (
const int vtc : verticesToFaceToChange )
2397 if ( vtc != addedVertexIndex && mVertexToFace.at( vtc ) == removedFaceIndex )
2402 topologicalFaces.
vertexToFace( vtc ) + faceStartGlobalIndex
2406 for (
int i = 0; i < topologicalFaces.mFaces.count(); ++i )
2409 for (
int n = 0; n < faceNeighbors.count(); ++n )
2411 if ( faceNeighbors.at( n ) != -1 )
2412 faceNeighbors[n] += faceStartGlobalIndex;
2416 edgeFacesIndexes.resize( 2 );
2418 for (
int i = 0 ; i < newBoundary.count(); ++i )
2420 int vertexIndex = newBoundary.at( i );
2423 int newFaceBoundaryLocalIndex = localStartIndex + circulator.
currentFaceIndex();
2425 int newFaceBoundaryIndexInMesh = faceStartGlobalIndex;
2427 int meshFaceBoundaryIndex;
2428 if ( i == newVertexPosition )
2430 meshFaceBoundaryIndex = -1;
2431 edgeFacesIndexes[0] = newFaceBoundaryLocalIndex;
2433 else if ( i == ( newVertexPosition + newBoundary.count() - 1 ) % newBoundary.count() )
2435 meshFaceBoundaryIndex = -1;
2436 edgeFacesIndexes[1] = newFaceBoundaryLocalIndex;
2439 meshFaceBoundaryIndex = mFacesNeighborhood.at( removedFaceIndex ).at( vertexPositionInFace( vertexIndex, initialFace ) );
2442 int positionInNewFaces = vertexPositionInFace( vertexIndex, newFace );
2444 if ( meshFaceBoundaryIndex != -1 )
2447 int positionInMeshFaceBoundary = vertexPositionInFace( *mMesh, vertexIndex, meshFaceBoundaryIndex );
2448 positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.count() ) % meshFace.count();
2451 positionInMeshFaceBoundary,
2453 newFaceBoundaryIndexInMesh +
2460 qDeleteAll( faceToFill );
2470 QVector<int> edgeFacesIndexes;
2471 if ( !triangulate( faceIndex, vertexToInsert, newVertexPositionInFace1, edgeFacesIndexes ) )
2479 int face2Index = mFacesNeighborhood.at( faceIndex ).at( position );
2480 if ( face2Index != -1 )
2483 int vertexPositionInFace2 = vertexPositionInFace( face1.at( position ), face2 );
2484 QVector<int> edgeFacesIndexesFace2;
2485 if ( !triangulate( face2Index, vertexToInsert, vertexPositionInFace2, edgeFacesIndexesFace2 ) )
2490 int pos1InFaceSide1 = vertexPositionInFace( addedVertexIndex, firstFaceSide1 );
2493 int pos2InFaceSide1 = vertexPositionInFace( addedVertexIndex, secondFaceSide1 );
2494 pos2InFaceSide1 = ( pos2InFaceSide1 + secondFaceSide1.size() - 1 ) % secondFaceSide1.size();
2497 int pos1InFaceSide2 = vertexPositionInFace( addedVertexIndex, firstFaceSide2 );
2500 int pos2InFaceSide2 = vertexPositionInFace( addedVertexIndex, secondFaceSide2 );
2501 pos2InFaceSide2 = ( pos2InFaceSide2 + secondFaceSide1.size() - 1 ) % secondFaceSide1.size();
2515 Q_ASSERT( verticesIndexes.count() == newValues.count() );
2518 changes.
mNewZValues.reserve( verticesIndexes.count() );
2519 changes.
mOldZValues.reserve( verticesIndexes.count() );
2520 for (
int i = 0; i < verticesIndexes.count(); ++i )
2534 Q_ASSERT( verticesIndexes.count() == newValues.count() );
2537 changes.
mNewXYValues.reserve( verticesIndexes.count() );
2538 changes.
mOldXYValues.reserve( verticesIndexes.count() );
2539 QSet<int> concernedFace;
2540 for (
int i = 0; i < verticesIndexes.count(); ++i )
2545 concernedFace.unite( qgis::listToSet(
facesAroundVertex( verticesIndexes.at( i ) ) ) );
@ 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) SIP_HOLDGIL
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 SIP_HOLDGIL
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...
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 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 facesCanBeRemoved(const QList< int > facesIndexes)
Returns whether faces with index in faceIndexes can be removed/ The method an error object with type ...
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...
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...
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.
Changes removeFaces(const QList< int > facesIndexes)
Removes faces with index in faceIndexes.
bool canBeMerged(int vertexIndex1, int vertexIndex2) const
Returns true if faces separated by vertices with indexes vertexIndex1 and vertexIndex2 can be merged.
QList< int > facesAroundVertex(int vertexIndex) const
Returns the indexes of faces that are around the vertex with index vertexIndex.
bool canBeSplit(int faceIndex) const
Returns true if face with index faceIndex can be split.
Changes addFreeVertex(const QgsMeshVertex &vertex)
Adds a free vertex in the face, that is a vertex tha tis not included or linked with any faces.
Changes insertVertexInFacesEdge(int faceIndex, int position, const QgsMeshVertex &vertex)
Inserts a vertex in the edge of face with index faceIndex at position .
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 SIP_HOLDGIL
Returns the angle of the vector in radians.
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
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.