27static int vertexPositionInFace(
int vertexIndex,
const QgsMeshFace &face )
29 return face.indexOf( vertexIndex );
32static int vertexPositionInFace(
const QgsMesh &mesh,
int vertexIndex,
int faceIndex )
34 if ( faceIndex < 0 || faceIndex >= mesh.
faceCount() )
37 return vertexPositionInFace( vertexIndex, mesh.
face( faceIndex ) );
40static double crossProduct(
int centralVertex,
int vertex1,
int vertex2,
const QgsMesh &mesh )
46 double ux1 = v1.
x() - vc.
x();
47 double uy1 = v1.
y() - vc.
y();
48 double vx1 = v2.
x() - vc.
x();
49 double vy1 = v2.
y() - vc.
y();
51 return ux1 * vy1 - uy1 * vx1;
56 : mFaces( topologicalMesh.mMesh->faces )
57 , mFacesNeighborhood( topologicalMesh.mFacesNeighborhood )
58 , mVertexIndex( vertexIndex )
60 if ( vertexIndex >= 0 && vertexIndex < topologicalMesh.mMesh->vertexCount() )
62 mCurrentFace = topologicalMesh.mVertexToFace[vertexIndex];
63 mIsValid = vertexPositionInFace( *topologicalMesh.
mesh(), vertexIndex, mCurrentFace ) != -1;
71 mLastValidFace = mCurrentFace;
75 : mFaces( topologicalFaces.mFaces )
76 , mFacesNeighborhood( topologicalFaces.mFacesNeighborhood )
77 , mVertexIndex( vertexIndex )
79 const QgsMeshFace &face = topologicalFaces.mFaces.at( faceIndex );
80 mIsValid = vertexPositionInFace( vertexIndex, face ) != -1;
82 mCurrentFace = faceIndex;
83 mLastValidFace = mCurrentFace;
87 : mFaces( topologicalFaces.mFaces )
88 , mFacesNeighborhood( topologicalFaces.mFacesNeighborhood )
89 , mVertexIndex( vertexIndex )
91 if ( topologicalFaces.mVerticesToFace.contains( vertexIndex ) )
92 mCurrentFace = topologicalFaces.mVerticesToFace.values( vertexIndex ).first();
93 mLastValidFace = mCurrentFace;
94 mIsValid = mCurrentFace != -1;
99 if ( mCurrentFace == -1 )
100 mCurrentFace = mLastValidFace;
103 int currentPos = positionInCurrentFace();
104 Q_ASSERT( currentPos != -1 );
108 mLastValidFace = mCurrentFace;
109 mCurrentFace = mFacesNeighborhood.at( mCurrentFace ).at( ( currentPos + faceSize - 1 ) %
currentFace.count() );
117 if ( mCurrentFace == -1 )
118 mCurrentFace = mLastValidFace;
121 int currentPos = positionInCurrentFace();
122 Q_ASSERT( currentPos != -1 );
126 mLastValidFace = mCurrentFace;
127 mCurrentFace = mFacesNeighborhood.at( mCurrentFace ).at( ( currentPos ) % faceSize );
140 if ( mCurrentFace != -1 )
141 return mFaces.at( mCurrentFace );
151 if ( mCurrentFace == -1 )
152 mCurrentFace = mLastValidFace;
154 int firstFace = mCurrentFace;
157 if ( mCurrentFace == firstFace )
168 if ( mCurrentFace == -1 )
169 mCurrentFace = mLastValidFace;
171 int firstFace = mCurrentFace;
174 if ( mCurrentFace == firstFace )
182 if ( mCurrentFace == -1 )
187 if ( face.isEmpty() )
190 int vertexPosition = vertexPositionInFace( mVertexIndex,
currentFace() );
192 if ( vertexPosition == -1 )
195 return face.at( ( vertexPosition + 1 ) % face.count() );
200 if ( mCurrentFace == -1 )
205 if ( face.isEmpty() )
208 int vertexPosition = vertexPositionInFace( mVertexIndex,
currentFace() );
210 if ( vertexPosition == -1 )
213 return face.at( ( vertexPosition - 1 + face.count() ) % face.count() );
227 if ( mCurrentFace != -1 )
228 ret.append( mCurrentFace );
273int QgsMeshVertexCirculator::positionInCurrentFace()
const
275 if ( mCurrentFace < 0 || mCurrentFace > mFaces.count() )
278 return vertexPositionInFace( mVertexIndex, mFaces.at( mCurrentFace ) );
288 for (
int i = 0; i < changes.
mFacesToAdd.count(); ++i )
291 for (
int boundary : topologicalFaces.mBoundaries )
294 if ( mVertexToFace.at( boundary ) == -1 )
297 const QList<int> &linkedFaces = topologicalFaces.mVerticesToFace.values( boundary );
298 for (
int linkedFace : linkedFaces )
304 if ( mVertexToFace.at( oppositeVertexForNewFace ) == -1 )
312 int boundaryPositionInNewFace = vertexPositionInFace( boundary, newFaceBoundary );
314 if ( oppositeVertexForMeshFace != oppositeVertexForNewFace )
326 boundaryPositionInMeshFace,
336 for (
int f = 0; f < changes.
mFacesToAdd.count(); ++f )
337 for (
int n = 0; n < changes.
mFacesToAdd.at( f ).count(); ++n )
339 changes.
mFacesNeighborhoodToAdd[f][n] = changes.addedFaceIndexInMesh( topologicalFaces.mFacesNeighborhood.at( f ).at( n ) );
341 const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
342 for (
const int vtc : verticesToFaceToChange )
343 if ( mVertexToFace.at( vtc ) == -1 )
345 mVertexToFace.at( vtc ),
346 changes.addedFaceIndexInMesh( topologicalFaces.mVerticesToFace.values( vtc ).first() ) } );
355 int initialVerticesCount = mMesh->
vertices.count();
360 mVertexToFace.resize( newSize );
366 mMesh->
faces.resize( newSize );
367 mFacesNeighborhood.resize( newSize );
373 mFacesNeighborhood[changes.removedFaceIndexInMesh( i )] =
FaceNeighbors();
379 if ( mVertexToFace.at( vertexIndex ) == -1 )
380 dereferenceAsFreeVertex( vertexIndex );
382 mVertexToFace[vertexIndex] = -1;
390 referenceAsFreeVertex( initialVerticesCount + i );
393 for (
int i = 0; i < changes.
mFacesToAdd.count(); ++i )
395 mMesh->
faces[changes.addedFaceIndexInMesh( i )] = changes.
mFacesToAdd.at( i );
401 const int faceIndex = neigborChange.at( 0 );
402 const int positionInFace = neigborChange.at( 1 );
403 const int valueToApply = neigborChange.at( 3 );
404 mFacesNeighborhood[faceIndex][positionInFace] = valueToApply;
409 int vertexIndex = vertexToFaceChange.at( 0 );
410 mVertexToFace[vertexToFaceChange.at( 0 )] = vertexToFaceChange.at( 2 );
412 if ( vertexToFaceChange.at( 2 ) == -1 &&
413 vertexToFaceChange.at( 1 ) != -1 &&
414 !mMesh->
vertices.at( vertexIndex ).isEmpty() )
415 referenceAsFreeVertex( vertexIndex );
417 if ( vertexToFaceChange.at( 1 ) == -1 && vertexToFaceChange.at( 2 ) != -1 )
418 dereferenceAsFreeVertex( vertexIndex );
429 mMesh->
vertices[vertexIndex].setX( pt.
x() );
430 mMesh->
vertices[vertexIndex].setY( pt.
y() );
439 const int faceIndex = neigborChange.at( 0 );
440 const int positionInFace = neigborChange.at( 1 );
441 const int valueToApply = neigborChange.at( 2 );
442 mFacesNeighborhood[faceIndex][positionInFace] = valueToApply;
456 if ( mVertexToFace.at( vertexIndex ) == -1 )
457 referenceAsFreeVertex( vertexIndex );
461 for (
int i = 0; i < verticesToFaceChangesCount; ++i )
463 const std::array<int, 3> vertexToFaceChange = changes.
mVerticesToFaceChanges.at( verticesToFaceChangesCount - i - 1 );
464 int vertexIndex = vertexToFaceChange.at( 0 );
465 mVertexToFace[vertexIndex] = vertexToFaceChange.at( 1 );
467 if ( vertexToFaceChange.at( 2 ) == -1 && vertexToFaceChange.at( 1 ) != -1 )
468 dereferenceAsFreeVertex( vertexIndex );
470 if ( vertexToFaceChange.at( 1 ) == -1 &&
471 vertexToFaceChange.at( 2 ) != -1 &&
473 referenceAsFreeVertex( vertexIndex );
479 mMesh->
faces.resize( newSize );
480 mFacesNeighborhood.resize( newSize );
487 for (
int i = newSize; i < mMesh->
vertexCount(); ++i )
488 if ( mVertexToFace.at( i ) == -1 )
489 dereferenceAsFreeVertex( i );
492 mVertexToFace.resize( newSize );
503 mMesh->
vertices[vertexIndex].setX( pt.
x() );
504 mMesh->
vertices[vertexIndex].setY( pt.
y() );
514QSet<int> QgsTopologicalMesh::concernedFacesBy(
const QList<int> faceIndexes )
const
517 for (
const int faceIndex : faceIndexes )
520 for (
int i = 0; i < face.count(); ++i )
523 faces.unite( QSet< int >( around.begin(), around.end() ) );
529void QgsTopologicalMesh::dereferenceAsFreeVertex(
int vertexIndex )
531 mFreeVertices.remove( vertexIndex );
534void QgsTopologicalMesh::referenceAsFreeVertex(
int vertexIndex )
538 mFreeVertices.insert( vertexIndex );
543 for (
int faceIndex = 0 ; faceIndex < mMesh->
faces.count( ); ++faceIndex )
546 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( faceIndex );
547 if ( face.count() != neighborhood.count() )
549 for (
int i = 0; i < face.count(); ++i )
551 int vertexIndex = face.at( i );
553 if ( mVertexToFace.at( vertexIndex ) == -1 )
556 int neighborIndex = neighborhood.at( i );
557 if ( neighborIndex != -1 )
560 if ( neighborFace.isEmpty() )
562 int neighborSize = neighborFace.size();
563 const FaceNeighbors &neighborhoodOfNeighbor = mFacesNeighborhood.at( neighborIndex );
564 int posInNeighbor = vertexPositionInFace( *mMesh, vertexIndex, neighborIndex );
565 if ( neighborhoodOfNeighbor.isEmpty() || neighborhoodOfNeighbor.at( ( posInNeighbor + neighborSize - 1 ) % neighborSize ) != faceIndex )
571 for (
int vertexIndex = 0; vertexIndex < mMesh->
vertexCount(); ++vertexIndex )
573 if ( mVertexToFace.at( vertexIndex ) != -1 )
575 if ( !mMesh->
face( mVertexToFace.at( vertexIndex ) ).contains( vertexIndex ) )
601 if ( vertexIndex < 0 || vertexIndex >= mMesh->
vertexCount() )
603 return mVertexToFace.at( vertexIndex );
618 if ( vertexIndex < 0 || vertexIndex >= mMesh->
vertexCount() )
621 if ( mMesh->
vertices.at( vertexIndex ).isEmpty() )
624 return mVertexToFace.at( vertexIndex ) == -1;
629 return QList<int>( mFreeVertices.begin(), mFreeVertices.end() );
636 int faceSize = face.count();
641 for (
int i = 0; i < faceSize; ++i )
644 int iv1 = face[( i + 1 ) % faceSize];
645 int iv2 = face[( i + 2 ) % faceSize];
669 double crossProd = crossProduct( iv1, iv0, iv2, *
mesh );
670 if ( direction != 0 && crossProd * direction < 0 )
672 else if ( crossProd == 0 )
674 else if ( direction == 0 && crossProd != 0 )
675 direction = crossProd / std::fabs( crossProd );
680 for (
int i = 0; i < faceSize / 2; ++i )
683 face[i] = face.at( faceSize - i - 1 );
684 face[faceSize - i - 1] = temp;
693 QVector<int> oldToNewIndex( mMesh->
vertices.count(), -1 );
697 while ( oldIndex < verticesTotalCount )
705 oldToNewIndex[oldIndex] = newIndex;
706 if ( oldIndex != newIndex )
708 oldToNewIndex[oldIndex] = newIndex;
718 int facesTotalCount = mMesh->
faceCount();
719 while ( oldIndex < facesTotalCount )
721 if ( mMesh->
face( oldIndex ).isEmpty() )
725 if ( oldIndex != newIndex )
726 mMesh->
faces[newIndex] = mMesh->
faces[oldIndex];
728 for (
int i = 0; i < face.count(); ++i )
729 face[i] = oldToNewIndex[face.at( i )];
735 mMesh->
faces.resize( newIndex );
737 mVertexToFace.clear();
738 mFacesNeighborhood.clear();
743 QVector<int> oldToNewVerticesIndexes;
744 if ( !renumberVertices( oldToNewVerticesIndexes ) )
748 QVector<int> oldToNewFacesIndexes;
750 if ( !renumberFaces( oldToNewFacesIndexes ) )
755 QVector<QgsMeshVertex> tempVertices( mMesh->
vertices.count() );
756 for (
int i = 0; i < oldToNewVerticesIndexes.count(); ++i )
758 tempVertices[oldToNewVerticesIndexes.at( i )] = mMesh->
vertex( i );
762 QVector<QgsMeshFace> tempFaces( mMesh->
faces.count() );
763 for (
int i = 0; i < oldToNewFacesIndexes.count(); ++i )
765 tempFaces[oldToNewFacesIndexes.at( i )] = mMesh->
face( i );
767 QgsMeshFace &face = tempFaces[oldToNewFacesIndexes.at( i )];
769 for (
int fi = 0; fi < face.count(); ++fi )
771 face[fi] = oldToNewVerticesIndexes.at( face.at( fi ) );
775 mMesh->
faces = tempFaces;
781bool QgsTopologicalMesh::renumberVertices( QVector<int> &oldToNewIndex )
const
783 std::vector<QgsMeshVertexCirculator> circulators;
784 circulators.reserve( mMesh->
vertices.count() );
785 int minDegree = std::numeric_limits<int>::max();
786 int minDegreeVertex = -1;
789 QSet<int> nonThreadedVertex;
790 oldToNewIndex = QVector<int> ( mMesh->
vertexCount(), -1 );
793 circulators.emplace_back( *
this, i );
795 if ( circulators.back().degree() < minDegree )
797 minDegreeVertex = circulators.size() - 1;
798 minDegree = circulator.
degree();
800 nonThreadedVertex.insert( i );
803 auto sortedNeighbor = [ = ]( QList<int> &neighbors,
int index )
817 int degree = circulators.at( neighborIndex ).degree();
818 QList<int>::Iterator it = neighbors.begin();
819 while ( it != neighbors.end() )
821 if ( degree <= circulators.at( *it ).degree() )
823 neighbors.insert( it, neighborIndex );
828 if ( it == neighbors.end() )
829 neighbors.append( neighborIndex );
835 int currentVertex = minDegreeVertex;
836 nonThreadedVertex.remove( minDegreeVertex );
838 while ( newIndex < mMesh->vertexCount() )
840 if ( oldToNewIndex[currentVertex] == -1 )
841 oldToNewIndex[currentVertex] = newIndex++;
843 if ( circulators.at( currentVertex ).isValid() )
845 QList<int> neighbors;
846 sortedNeighbor( neighbors, currentVertex );
848 for (
const int i : std::as_const( neighbors ) )
849 if ( oldToNewIndex.at( i ) == -1 && nonThreadedVertex.contains( i ) )
852 nonThreadedVertex.remove( i );
856 if ( queue.isEmpty() )
858 if ( nonThreadedVertex.isEmpty() && newIndex < mMesh->vertexCount() )
861 const QList<int> remainingVertex( nonThreadedVertex.constBegin(), nonThreadedVertex.constEnd() );
862 int minRemainingDegree = std::numeric_limits<int>::max();
863 int minRemainingVertex = -1;
864 for (
const int i : remainingVertex )
866 int degree = circulators.at( i ).degree();
867 if ( degree < minRemainingDegree )
869 minRemainingDegree = degree;
870 minRemainingVertex = i;
873 currentVertex = minRemainingVertex;
874 nonThreadedVertex.remove( currentVertex );
878 currentVertex = queue.dequeue();
885bool QgsTopologicalMesh::renumberFaces( QVector<int> &oldToNewIndex )
const
888 QSet<int> nonThreadedFaces;
890 oldToNewIndex = QVector<int>( mMesh->
faceCount(), -1 );
892 QVector<int> faceDegrees( mMesh->
faceCount(), 0 );
894 int minDegree = std::numeric_limits<int>::max();
895 int minDegreeFace = -1;
896 for (
int faceIndex = 0; faceIndex < mMesh->
faceCount(); ++faceIndex )
898 const FaceNeighbors &neighbors = mFacesNeighborhood.at( faceIndex );
901 for (
int n = 0; n < neighbors.size(); ++n )
903 if ( neighbors.at( n ) != -1 )
907 if ( degree < minDegree )
910 minDegreeFace = faceIndex;
913 faceDegrees[faceIndex] = degree;
914 nonThreadedFaces.insert( faceIndex );
918 int currentFace = minDegreeFace;
919 nonThreadedFaces.remove( minDegreeFace );
921 auto sortedNeighbor = [ = ]( QList<int> &neighbors,
int index )
923 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( index );
925 for (
int i = 0; i < neighborhood.count(); ++i )
927 int neighborIndex = neighborhood.at( i );
928 if ( neighborIndex == -1 )
931 int degree = faceDegrees.at( neighborIndex );
932 if ( neighbors.isEmpty() )
933 neighbors.append( neighborIndex );
936 QList<int>::Iterator it = neighbors.begin();
937 while ( it != neighbors.end() )
939 if ( degree <= faceDegrees.at( *it ) )
941 neighbors.insert( it, neighborIndex );
946 if ( it == neighbors.end() )
947 neighbors.append( neighborIndex );
952 while ( newIndex < mMesh->faceCount() )
954 if ( oldToNewIndex[currentFace] == -1 )
955 oldToNewIndex[currentFace] = newIndex++;
957 QList<int> neighbors;
958 sortedNeighbor( neighbors, currentFace );
960 for (
const int i : std::as_const( neighbors ) )
961 if ( oldToNewIndex.at( i ) == -1 && nonThreadedFaces.contains( i ) )
964 nonThreadedFaces.remove( i );
967 if ( queue.isEmpty() )
969 if ( nonThreadedFaces.isEmpty() && newIndex < mMesh->faceCount() )
972 const QList<int> remainingFace( nonThreadedFaces.constBegin(), nonThreadedFaces.constEnd() );
973 int minRemainingDegree = std::numeric_limits<int>::max();
974 int minRemainingFace = -1;
975 for (
const int i : remainingFace )
977 int degree = faceDegrees.at( i );
978 if ( degree < minRemainingDegree )
980 minRemainingDegree = degree;
981 minRemainingFace = i;
984 currentFace = minRemainingFace;
985 nonThreadedFaces.remove( currentFace );
989 currentFace = queue.dequeue();
1004 return mFacesToRemove;
1009 return mFaceIndexesToRemove;
1014 return mVerticesToAdd;
1019 return mChangeCoordinateVerticesIndexes;
1029 return mNewXYValues;
1034 return mOldXYValues;
1039 return mNativeFacesIndexesGeometryChanged;
1044 return ( mFaceIndexesToRemove.isEmpty() &&
1045 mFacesToAdd.isEmpty() &&
1046 mFacesNeighborhoodToAdd.isEmpty() &&
1047 mFacesToRemove.isEmpty() &&
1048 mFacesNeighborhoodToRemove.isEmpty() &&
1049 mNeighborhoodChanges.isEmpty() &&
1050 mVerticesToAdd.isEmpty() &&
1051 mVertexToFaceToAdd.isEmpty() &&
1052 mVerticesToRemoveIndexes.isEmpty() &&
1053 mRemovedVertices.isEmpty() &&
1054 mVerticesToFaceRemoved.isEmpty() &&
1055 mVerticesToFaceChanges.isEmpty() &&
1056 mChangeCoordinateVerticesIndexes.isEmpty() &&
1057 mNewZValues.isEmpty() &&
1058 mOldZValues.isEmpty() &&
1059 mNewXYValues.isEmpty() &&
1060 mOldXYValues.isEmpty() &&
1061 mNativeFacesIndexesGeometryChanged.isEmpty() );
1066 return mVerticesToRemoveIndexes;
1069int QgsTopologicalMesh::Changes::addedFaceIndexInMesh(
int internalIndex )
const
1071 if ( internalIndex == -1 )
1074 return internalIndex + mAddedFacesFirstIndex;
1077int QgsTopologicalMesh::Changes::removedFaceIndexInMesh(
int internalIndex )
const
1079 if ( internalIndex == -1 )
1082 return mFaceIndexesToRemove.at( internalIndex );
1087 mAddedFacesFirstIndex = 0;
1088 mFaceIndexesToRemove.clear();
1089 mFacesToAdd.clear();
1090 mFacesNeighborhoodToAdd.clear();
1091 mFacesToRemove.clear();
1092 mFacesNeighborhoodToRemove.clear();
1093 mNeighborhoodChanges.clear();
1095 mVerticesToAdd.clear();
1096 mVertexToFaceToAdd.clear();
1097 mVerticesToRemoveIndexes.clear();
1098 mRemovedVertices.clear();
1099 mVerticesToFaceRemoved.clear();
1100 mVerticesToFaceChanges.clear();
1102 mChangeCoordinateVerticesIndexes.clear();
1103 mNewZValues.clear();
1104 mOldZValues.clear();
1105 mNewXYValues.clear();
1106 mOldXYValues.clear();
1107 mNativeFacesIndexesGeometryChanged.clear();
1117 mVertexToFace.append( -1 );
1118 referenceAsFreeVertex( mMesh->
vertices.count() - 1 );
1124static double vertexPolygonOrientation(
const QgsMesh &
mesh,
const QList<int> &vertexIndexes )
1126 if ( vertexIndexes.count() < 3 )
1129 int hullDomainVertexPos = -1;
1130 double xMin = std::numeric_limits<double>::max();
1131 double yMin = std::numeric_limits<double>::max();
1132 for (
int i = 0; i < vertexIndexes.count(); ++i )
1135 if ( xMin >= vertex.
x() && yMin > vertex.
y() )
1137 hullDomainVertexPos = i;
1143 if ( hullDomainVertexPos >= 0 )
1145 int iv1 = vertexIndexes.at( ( hullDomainVertexPos - 1 + vertexIndexes.count() ) % vertexIndexes.count() );
1146 int iv2 = vertexIndexes.at( ( hullDomainVertexPos + 1 ) % vertexIndexes.count() );
1147 int ivc = vertexIndexes.at( ( hullDomainVertexPos ) );
1148 double cp = crossProduct( ivc, iv1, iv2,
mesh );
1157 if ( vertexIndex >= mVertexToFace.count() )
1160 if ( mVertexToFace.at( vertexIndex ) == -1 )
1166 dereferenceAsFreeVertex( vertexIndex );
1174 QList<int> boundariesVertexIndex;
1175 QList<int> associateFaceToBoundaries;
1176 QList<int> removedFacesIndexes;
1177 QSet<int> boundaryInGlobalMesh;
1183 Q_ASSERT( !mMesh->
vertices.at( boundariesVertexIndex.last() ).isEmpty() );
1185 associateFaceToBoundaries.append( mFacesNeighborhood.at( circulator.
currentFaceIndex() ).at(
1186 vertexPositionInFace( boundariesVertexIndex.last(), currentFace ) ) );
1188 if ( currentFace.count() > 3 )
1190 int posInface = vertexPositionInFace( vertexIndex, currentFace );
1191 for (
int i = 2; i < currentFace.count() - 1; ++i )
1193 boundariesVertexIndex.append( currentFace.at( ( posInface + i ) % currentFace.count() ) );
1194 Q_ASSERT( !mMesh->
vertices.at( boundariesVertexIndex.last() ).isEmpty() );
1195 associateFaceToBoundaries.append( mFacesNeighborhood.at( circulator.
currentFaceIndex() ).at(
1196 vertexPositionInFace( boundariesVertexIndex.last(), currentFace ) ) );
1202 bool boundaryFill =
false;
1205 boundaryFill =
true;
1209 boundariesVertexIndex.append( lastVertexIndex );
1218 boundaryFill =
false;
1221 associateFaceToBoundaries.append( -1 );
1223 for (
const int index : std::as_const( boundariesVertexIndex ) )
1226 boundaryInGlobalMesh.insert( index );
1230 int currentVertexToFace = mVertexToFace.at( vertexIndex );
1234 QList<QList<int>> holes;
1235 QList<QList<int>> associateMeshFacesToHoles;
1237 bool cancelOperation =
false;
1245 int finalPos = boundariesVertexIndex.count() - 1;
1246 QList<int> uncoveredVertex;
1248 QList<int> partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1249 QList<int> associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1250 while ( startPos < finalPos && !partToCheck.isEmpty() )
1253 int secondPos = partToCheck.count() - 1;
1254 const QgsPoint &closingSegmentExtremety1 = mMesh->
vertex( partToCheck.at( 0 ) );
1255 const QgsPoint &closingSegmentExtremety2 = mMesh->
vertex( partToCheck.last() );
1256 bool isEdgeIntersect =
false;
1257 for (
int i = 1; i < secondPos - 1; ++i )
1261 bool isLineIntersection;
1264 if ( isEdgeIntersect )
1268 int index = partToCheck.at( 0 );
1269 if ( boundaryInGlobalMesh.contains( index ) && index != boundariesVertexIndex.at( 0 ) )
1271 cancelOperation =
true;
1277 if ( isEdgeIntersect || vertexPolygonOrientation( *mMesh, partToCheck ) >= 0 )
1279 partToCheck.removeLast();
1280 associateFacePart.removeAt( associateFacePart.count() - 2 );
1281 if ( partToCheck.count() == 1 )
1283 uncoveredVertex.append( index );
1284 startPos = startPos + 1;
1285 partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1286 associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1292 holes.append( partToCheck );
1293 associateMeshFacesToHoles.append( associateFacePart );
1295 startPos = startPos + partToCheck.count() - 1;
1296 uncoveredVertex.append( partToCheck.at( 0 ) );
1297 partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1298 associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1304 holes.append( boundariesVertexIndex );
1305 associateMeshFacesToHoles.append( associateFaceToBoundaries );
1308 if ( cancelOperation )
1314 Q_ASSERT( holes.count() == associateMeshFacesToHoles.count() );
1320 dereferenceAsFreeVertex( vertexIndex );
1322 mVertexToFace[vertexIndex] = -1;
1325 for (
int h = 0; h < holes.count(); ++h )
1327 const QList<int> &holeVertices = holes.at( h );
1328 const QList<int> &associateMeshFacesToHole = associateMeshFacesToHoles.at( h );
1329 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
1330 std::vector<p2t::Point *> holeToFill( holeVertices.count() );
1333 for (
int i = 0; i < holeVertices.count(); ++i )
1336 holeToFill[i] =
new p2t::Point( vertex.
x(), vertex.
y() );
1337 mapPoly2TriPointToVertex.insert( holeToFill[i], holeVertices.at( i ) );
1340 std::unique_ptr<p2t::CDT> cdt(
new p2t::CDT( holeToFill ) );
1343 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
1344 QVector<QgsMeshFace> newFaces( triangles.size() );
1345 for (
size_t i = 0; i < triangles.size(); ++i )
1349 for (
int j = 0; j < 3; j++ )
1351 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
1352 if ( vertInd == -1 )
1353 throw std::exception();
1354 Q_ASSERT( !mMesh->
vertices.at( vertInd ).isEmpty() );
1362 throw std::exception();
1363 int newFaceIndexStartIndex = mMesh->
faceCount();
1370 const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
1371 for (
const int vtc : verticesToFaceToChange )
1372 if ( mVertexToFace.at( vtc ) == -1 )
1374 mVertexToFace.at( vtc ),
1375 addChanges.addedFaceIndexInMesh( topologicalFaces.mVerticesToFace.values( vtc ).first() ) } );
1379 for (
int i = 0; i < topologicalFaces.mFaces.count(); ++i )
1382 faceNeighbors = topologicalFaces.mFacesNeighborhood.at( i );
1383 for (
int n = 0; n < faceNeighbors.count(); ++n )
1385 if ( faceNeighbors.at( n ) != -1 )
1386 faceNeighbors[n] += newFaceIndexStartIndex;
1391 for (
int i = 0 ; i < holeVertices.count(); ++i )
1393 int vertexHoleIndex = holeVertices.at( i );
1394 int meshFaceBoundaryIndex = associateMeshFacesToHole.at( i );
1399 int newFaceBoundaryIndexInMesh = circulator.
currentFaceIndex() + newFaceIndexStartIndex;
1401 int positionInNewFaces = vertexPositionInFace( vertexHoleIndex, newFace );
1403 if ( meshFaceBoundaryIndex != -1 )
1406 int positionInMeshFaceBoundary = vertexPositionInFace( *mMesh, vertexHoleIndex, meshFaceBoundaryIndex );
1407 positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.count() ) % meshFace.count();
1409 addChanges.
mNeighborhoodChanges.append( {meshFaceBoundaryIndex, positionInMeshFaceBoundary, -1, newFaceBoundaryIndexInMesh} );
1420 for (
const std::array<int, 4> &neighborChangeToAdd : std::as_const( addChanges.
mNeighborhoodChanges ) )
1422 bool merged =
false;
1425 if ( existingNeighborChange.at( 0 ) == neighborChangeToAdd.at( 0 ) &&
1426 existingNeighborChange.at( 1 ) == neighborChangeToAdd.at( 1 ) )
1429 Q_ASSERT( existingNeighborChange.at( 3 ) == neighborChangeToAdd.at( 2 ) );
1430 existingNeighborChange[3] = neighborChangeToAdd.at( 3 );
1437 for (
const std::array<int, 3> &verticesToFaceToAdd : std::as_const( addChanges.
mVerticesToFaceChanges ) )
1439 bool merged =
false;
1442 if ( existingVerticesToFace.at( 0 ) == verticesToFaceToAdd.at( 0 ) )
1445 Q_ASSERT( existingVerticesToFace.at( 2 ) == verticesToFaceToAdd.at( 1 ) );
1446 existingVerticesToFace[2] = verticesToFaceToAdd.at( 2 );
1453 qDeleteAll( holeToFill );
1457 qDeleteAll( holeToFill );
1472 QSet<int> facesIndex;
1474 for (
int vertexIndex : vertices )
1477 facesIndex.unite( QSet< int >( faces.begin(), faces.end() ) );
1484 for (
int vertexIndex : vertices )
1486 int currentVertexToFace = mVertexToFace.at( vertexIndex );
1492 dereferenceAsFreeVertex( vertexIndex );
1494 mVertexToFace[vertexIndex] = -1;
1502 QList<int> boundariesToCheckClockwiseInNewFaces = topologicFaces.mBoundaries;
1503 QList<std::array<int, 2>> boundariesToCheckCounterClockwiseInNewFaces;
1504 QList<int> uniqueSharedVertexBoundary;
1512 while ( !boundariesToCheckClockwiseInNewFaces.isEmpty() )
1514 int boundary = boundariesToCheckClockwiseInNewFaces.takeLast();
1516 const QList<int> &linkedFaces = topologicFaces.mVerticesToFace.values( boundary );
1518 for (
int const linkedFace : linkedFaces )
1522 if ( mVertexToFace.at( boundary ) == -1 )
1528 if ( !newFacescirculator.
isValid() )
1542 if ( oppositeVertexCCWInMesh == oppositeVertexInNewFaces )
1548 int faceSize = newFaceOnBoundary.size();
1549 int posInNewFace = vertexPositionInFace( boundary, newFaceOnBoundary );
1550 int previousVertexIndex = ( posInNewFace + faceSize - 1 ) % faceSize;
1551 if ( newFaceOnBoundary.at( previousVertexIndex ) == oppositeVertexCCWInMesh )
1559 if ( oppositeVertexCWInMesh == oppositeVertexInNewFaces )
1563 boundariesToCheckCounterClockwiseInNewFaces.append( {boundary, linkedFace} );
1568 while ( !boundariesToCheckCounterClockwiseInNewFaces.isEmpty() )
1570 std::array<int, 2> boundaryLinkedface = boundariesToCheckCounterClockwiseInNewFaces.takeLast();
1571 int boundary = boundaryLinkedface.at( 0 );
1572 int linkedFace = boundaryLinkedface.at( 1 );
1587 if ( oppositeVertexCWInMesh == oppositeVertexInNewFaces )
1594 if ( oppositeVertexCCWInMesh == oppositeVertexInNewFaces )
1597 uniqueSharedVertexBoundary.append( boundary );
1600 if ( !uniqueSharedVertexBoundary.isEmpty() )
1604 QSet<int> boundaryVertices( topologicFaces.mBoundaries.constBegin(), topologicFaces.mBoundaries.constEnd() );
1605 for (
const QgsMeshFace &newFace : std::as_const( topologicFaces.mFaces ) )
1607 for (
const int vertexIndex : newFace )
1609 if ( boundaryVertices.contains( vertexIndex ) )
1611 if ( mVertexToFace.at( vertexIndex ) != -1 )
1622 mFacesNeighborhood.clear();
1623 mVerticesToFace.clear();
1624 mBoundaries.clear();
1629 return mFacesNeighborhood;
1634 if ( mVerticesToFace.contains( vertexIndex ) )
1635 return mVerticesToFace.values( vertexIndex ).at( 0 );
1643 topologicMesh.mMesh =
mesh;
1644 topologicMesh.mVertexToFace = QVector<int>(
mesh->
vertexCount(), -1 );
1645 topologicMesh.mMaximumVerticesPerFace = maxVerticesPerFace;
1652 if ( maxVerticesPerFace != 0 &&
mesh->
face( i ).count() > maxVerticesPerFace )
1670 topologicMesh.mFacesNeighborhood = subMesh.mFacesNeighborhood;
1672 for (
int i = 0; i < topologicMesh.mMesh->
vertexCount(); ++i )
1674 if ( topologicMesh.mVertexToFace.at( i ) == -1 )
1675 topologicMesh.mFreeVertices.insert( i );
1679 return topologicMesh;
1684 return createTopologicalFaces( faces,
nullptr, error, uniqueSharedVertexAllowed );
1689 const QVector<QgsMeshFace> &faces,
1690 QVector<int> *globalVertexToFace,
1692 bool allowUniqueSharedVertex )
1694 int facesCount = faces.count();
1695 QVector<FaceNeighbors> faceTopologies;
1696 QMultiHash<int, int> verticesToFace;
1699 TopologicalFaces ret;
1703 QMap<int, QMap<int, int>> verticesToNeighbor;
1705 for (
int faceIndex = 0; faceIndex < facesCount; ++faceIndex )
1708 int faceSize = face.count();
1710 for (
int i = 0; i < faceSize; ++i )
1712 int v1 = face[i % faceSize];
1713 int v2 = face[( i + 1 ) % faceSize];
1714 if ( verticesToNeighbor[v2].contains( v1 ) )
1720 verticesToNeighbor[v2].insert( v1, faceIndex );
1724 faceTopologies = QVector<FaceNeighbors>( faces.count() );
1726 QSet<int> boundaryVertices;
1728 for (
int faceIndex = 0; faceIndex < facesCount; ++faceIndex )
1731 int faceSize = face.size();
1733 faceTopology.resize( faceSize );
1735 for (
int i = 0; i < faceSize; ++i )
1737 int v1 = face.at( i );
1738 int v2 = face.at( ( i + 1 ) % faceSize );
1740 if ( globalVertexToFace )
1742 if ( ( *globalVertexToFace )[v1] == -1 )
1743 ( *globalVertexToFace )[v1] = faceIndex ;
1747 if ( allowUniqueSharedVertex || !verticesToFace.contains( v1 ) )
1748 verticesToFace.insert( v1, faceIndex ) ;
1751 QMap<int, int> &edges = verticesToNeighbor[v1];
1752 if ( edges.contains( v2 ) )
1753 faceTopology[i] = edges.value( v2 );
1756 faceTopology[i] = -1;
1758 if ( !allowUniqueSharedVertex )
1760 if ( boundaryVertices.contains( v1 ) )
1766 boundaryVertices.insert( v1 );
1772 ret.mFacesNeighborhood = faceTopologies;
1773 ret.mBoundaries = boundaryVertices.values();
1774 ret.mVerticesToFace = verticesToFace;
1780 return mFacesNeighborhood.at( faceIndex );
1792 QSet<int> removedFaces( facesIndexes.begin(), facesIndexes.end() );
1793 QSet<int> concernedFaces = concernedFacesBy( facesIndexes );
1795 for (
const int f : std::as_const( removedFaces ) )
1796 concernedFaces.remove( f );
1798 QVector<QgsMeshFace> remainingFaces;
1799 remainingFaces.reserve( concernedFaces.count() );
1800 for (
const int f : std::as_const( concernedFaces ) )
1801 remainingFaces.append( mMesh->
face( f ) );
1804 createTopologicalFaces( remainingFaces,
nullptr, error,
false );
1816 QSet<int> indexSet( facesIndexesToRemove.begin(), facesIndexesToRemove.end() );
1817 QSet<int> threatedVertex;
1819 for (
int i = 0; i < facesIndexesToRemove.count(); ++i )
1821 const int faceIndex = facesIndexesToRemove.at( i );
1824 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( faceIndex );
1826 for (
int j = 0; j < face.count(); ++j )
1829 int neighborIndex = neighborhood.at( j );
1830 if ( neighborIndex != -1 && !indexSet.contains( neighborIndex ) )
1832 int positionInNeighbor = mFacesNeighborhood.at( neighborIndex ).indexOf( faceIndex );
1837 int vertexIndex = face.at( j );
1838 if ( !threatedVertex.contains( vertexIndex ) && indexSet.contains( mVertexToFace.at( vertexIndex ) ) )
1840 int oldValue = mVertexToFace.at( vertexIndex );
1843 if ( neighborIndex != -1 && !indexSet.contains( neighborIndex ) )
1844 refValue = neighborIndex;
1848 aroundFaces.removeOne( faceIndex );
1849 if ( !aroundFaces.isEmpty() )
1851 while ( !aroundFaces.isEmpty() && refValue == -1 )
1853 if ( !indexSet.contains( aroundFaces.first() ) )
1854 refValue = aroundFaces.first();
1856 aroundFaces.removeFirst();
1861 threatedVertex.insert( vertexIndex );
1871bool QgsTopologicalMesh::eitherSideFacesAndVertices(
int vertexIndex1,
1875 int &neighborVertex1InFace1,
1876 int &neighborVertex1InFace2,
1877 int &neighborVertex2inFace1,
1878 int &neighborVertex2inFace2 )
const
1920 int oppositeVertexFace1;
1921 int oppositeVertexFace2;
1922 int supposedOppositeVertexFace1;
1923 int supposedoppositeVertexFace2;
1925 bool result = eitherSideFacesAndVertices(
1930 oppositeVertexFace1,
1931 supposedoppositeVertexFace2,
1932 supposedOppositeVertexFace1,
1933 oppositeVertexFace2 );
1938 oppositeVertexFace1 < 0 ||
1939 oppositeVertexFace2 < 0 ||
1940 supposedOppositeVertexFace1 != oppositeVertexFace1 ||
1941 supposedoppositeVertexFace2 != oppositeVertexFace2 )
1948 if ( face1.count() != 3 || face2.count() != 3 )
1951 double crossProduct1 = crossProduct( vertexIndex1, oppositeVertexFace1, oppositeVertexFace2, *mMesh );
1952 double crossProduct2 = crossProduct( vertexIndex2, oppositeVertexFace1, oppositeVertexFace2, *mMesh );
1954 return crossProduct1 * crossProduct2 < 0;
1961 int oppositeVertexFace1;
1962 int oppositeVertexFace2;
1963 int supposedOppositeVertexFace1;
1964 int supposedoppositeVertexFace2;
1966 bool result = eitherSideFacesAndVertices(
1971 oppositeVertexFace1,
1972 supposedoppositeVertexFace2,
1973 supposedOppositeVertexFace1,
1974 oppositeVertexFace2 );
1979 oppositeVertexFace1 < 0 ||
1980 oppositeVertexFace2 < 0 ||
1981 supposedOppositeVertexFace1 != oppositeVertexFace1 ||
1982 supposedoppositeVertexFace2 != oppositeVertexFace2 )
1991 Q_ASSERT( face1.count() == 3 );
1992 Q_ASSERT( face2.count() == 3 );
1994 int pos1 = vertexPositionInFace( vertexIndex1, face1 );
1995 int pos2 = vertexPositionInFace( vertexIndex2, face2 );
1997 int neighborFace1 = mFacesNeighborhood.at( faceIndex1 ).at( pos1 );
1998 int posInNeighbor1 = vertexPositionInFace( *mMesh, oppositeVertexFace1, neighborFace1 );
1999 int neighborFace2 = mFacesNeighborhood.at( faceIndex1 ).at( ( pos1 + 1 ) % 3 );
2000 int posInNeighbor2 = vertexPositionInFace( *mMesh, vertexIndex2, neighborFace2 );
2001 int neighborFace3 = mFacesNeighborhood.at( faceIndex2 ).at( pos2 );
2002 int posInNeighbor3 = vertexPositionInFace( *mMesh, oppositeVertexFace2, neighborFace3 );
2003 int neighborFace4 = mFacesNeighborhood.at( faceIndex2 ).at( ( pos2 + 1 ) % 3 );
2004 int posInNeighbor4 = vertexPositionInFace( *mMesh, vertexIndex1, neighborFace4 );
2014 changes.
mFacesToAdd.append( {oppositeVertexFace1, oppositeVertexFace2, vertexIndex1} );
2015 changes.
mFacesToAdd.append( {oppositeVertexFace2, oppositeVertexFace1, vertexIndex2} );
2017 mFacesNeighborhood.at( faceIndex2 ).at( ( pos2 + 1 ) % 3 ),
2018 mFacesNeighborhood.at( faceIndex1 ).at( pos1 )} );
2020 mFacesNeighborhood.at( faceIndex1 ).at( ( pos1 + 1 ) % 3 ),
2021 mFacesNeighborhood.at( faceIndex2 ).at( pos2 )} );
2023 if ( neighborFace1 >= 0 )
2024 changes.
mNeighborhoodChanges.append( {neighborFace1, posInNeighbor1, faceIndex1, startIndex} );
2025 if ( neighborFace2 >= 0 )
2026 changes.
mNeighborhoodChanges.append( {neighborFace2, posInNeighbor2, faceIndex1, startIndex + 1} );
2027 if ( neighborFace3 >= 0 )
2028 changes.
mNeighborhoodChanges.append( {neighborFace3, posInNeighbor3, faceIndex2, startIndex + 1} );
2029 if ( neighborFace4 >= 0 )
2030 changes.
mNeighborhoodChanges.append( {neighborFace4, posInNeighbor4, faceIndex2, startIndex} );
2033 if ( mVertexToFace.at( vertexIndex1 ) == faceIndex1 || mVertexToFace.at( vertexIndex1 ) == faceIndex2 )
2035 if ( mVertexToFace.at( vertexIndex2 ) == faceIndex1 || mVertexToFace.at( vertexIndex2 ) == faceIndex2 )
2036 changes.
mVerticesToFaceChanges.append( {vertexIndex2, mVertexToFace.at( vertexIndex2 ), startIndex + 1} );
2038 if ( mVertexToFace.at( oppositeVertexFace1 ) == faceIndex1 )
2041 if ( mVertexToFace.at( oppositeVertexFace2 ) == faceIndex2 )
2053 int neighborVertex1InFace1;
2054 int neighborVertex1InFace2;
2055 int neighborVertex2inFace1;
2056 int neighborVertex2inFace2;
2058 bool result = eitherSideFacesAndVertices(
2063 neighborVertex1InFace1,
2064 neighborVertex1InFace2,
2065 neighborVertex2inFace1,
2066 neighborVertex2inFace2 );
2076 if ( face1.count() + face2.count() - 2 > mMaximumVerticesPerFace )
2086 double crossProduct1 = crossProduct( vertexIndex1, neighborVertex1InFace1, neighborVertex1InFace2, *mMesh );
2087 double crossProduct2 = crossProduct( vertexIndex2, neighborVertex2inFace1, neighborVertex2inFace2, *mMesh );
2089 return crossProduct1 * crossProduct2 < 0;
2096 int neighborVertex1InFace1;
2097 int neighborVertex1InFace2;
2098 int neighborVertex2inFace1;
2099 int neighborVertex2inFace2;
2101 bool result = eitherSideFacesAndVertices(
2106 neighborVertex1InFace1,
2107 neighborVertex1InFace2,
2108 neighborVertex2inFace1,
2109 neighborVertex2inFace2 );
2120 int faceSize1 = face1.count();
2121 int faceSize2 = face2.count();
2123 int pos1 = vertexPositionInFace( vertexIndex1, face1 );
2124 int pos2 = vertexPositionInFace( vertexIndex2, face2 );
2137 for (
int i = 0; i < faceSize1 - 1; ++i )
2139 int currentPos = ( pos1 + i ) % faceSize1;
2140 newface.append( face1.at( currentPos ) );
2142 int currentNeighbor = mFacesNeighborhood.at( faceIndex1 ).at( currentPos );
2143 newNeighborhood.append( currentNeighbor );
2145 if ( currentNeighbor != -1 )
2147 int currentPosInNeighbor = vertexPositionInFace( *mMesh, face1.at( ( currentPos + 1 ) % faceSize1 ), currentNeighbor );
2148 changes.
mNeighborhoodChanges.append( {currentNeighbor, currentPosInNeighbor, faceIndex1, startIndex} );
2151 for (
int i = 0; i < faceSize2 - 1; ++i )
2153 int currentPos = ( pos2 + i ) % faceSize2;
2154 newface.append( face2.at( currentPos ) );
2156 int currentNeighbor = mFacesNeighborhood.at( faceIndex2 ).at( currentPos );
2157 newNeighborhood.append( currentNeighbor );
2159 if ( currentNeighbor != -1 )
2161 int currentPosInNeighbor = vertexPositionInFace( *mMesh, face2.at( ( currentPos + 1 ) % faceSize2 ), currentNeighbor );
2162 changes.
mNeighborhoodChanges.append( {currentNeighbor, currentPosInNeighbor, faceIndex2, startIndex} );
2166 for (
int i = 0; i < faceSize1; ++i )
2167 if ( mVertexToFace.at( face1.at( i ) ) == faceIndex1 )
2170 for (
int i = 0; i < faceSize2; ++i )
2171 if ( mVertexToFace.at( face2.at( i ) ) == faceIndex2 )
2186 return face.count() == 4;
2193 int faceSize = face.count();
2195 Q_ASSERT( faceSize == 4 );
2197 double maxAngle = 0;
2198 int splitVertexPos = -1;
2199 for (
int i = 0; i < faceSize; ++i )
2201 QgsVector vect1( mMesh->
vertex( face.at( i ) ) - mMesh->
vertex( face.at( ( i + 1 ) % faceSize ) ) );
2202 QgsVector vect2( mMesh->
vertex( face.at( ( i + 2 ) % faceSize ) ) - mMesh->
vertex( face.at( ( i + 1 ) % faceSize ) ) );
2204 double angle = std::abs( vect1.
angle( vect2 ) );
2206 if (
angle > maxAngle )
2209 splitVertexPos = ( i + 1 ) % faceSize;
2215 const QgsMeshFace newFace1 = {face.at( splitVertexPos ),
2216 face.at( ( splitVertexPos + 1 ) % faceSize ),
2217 face.at( ( splitVertexPos + 2 ) % faceSize )
2220 const QgsMeshFace newFace2 = {face.at( splitVertexPos ),
2221 face.at( ( splitVertexPos + 2 ) % faceSize ),
2222 face.at( ( splitVertexPos + 3 ) % faceSize )
2225 QVector<int> neighborIndex( faceSize );
2226 QVector<int> posInNeighbor( faceSize );
2228 for (
int i = 0; i < faceSize; ++i )
2230 neighborIndex[i] = mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + i ) % faceSize );
2231 posInNeighbor[i] = vertexPositionInFace( *mMesh, face.at( ( splitVertexPos + i + 1 ) % faceSize ), neighborIndex[i] );
2243 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 1 ) % faceSize ),
2246 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 2 ) % faceSize ),
2247 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 3 ) % faceSize )} );
2249 for (
int i = 0; i < faceSize; ++i )
2251 if ( neighborIndex[i] >= 0 )
2252 changes.
mNeighborhoodChanges.append( {neighborIndex[i], posInNeighbor[i], faceIndex, startIndex + int( i / 2 )} );
2254 int vertexIndex = face.at( ( splitVertexPos + i ) % faceSize );
2255 if ( mVertexToFace.at( vertexIndex ) == faceIndex )
2272 mVertexToFace.append( -1 );
2276 const FaceNeighbors includingFaceNeighborhood = mFacesNeighborhood.at( includingFaceIndex );
2277 int includingFaceSize = includingFace.count();
2279 for (
int i = 0; i < includingFaceSize; ++i )
2284 face[1] = includingFace.at( i );
2285 face[2] = includingFace.at( ( i + 1 ) % includingFaceSize );
2286 mMesh->
faces.append( face );
2289 int currentVertexIndex = includingFace.at( i );
2290 if ( mVertexToFace.at( currentVertexIndex ) == includingFaceIndex )
2292 int newFaceIndex = mMesh->
faceCount() - 1;
2293 mVertexToFace[currentVertexIndex] = newFaceIndex;
2297 int includingFaceNeighbor = includingFaceNeighborhood.at( i );
2301 includingFaceNeighbor,
2304 mFacesNeighborhood.append( neighbors );
2307 if ( includingFaceNeighbor != -1 )
2309 int indexInNeighbor = vertexPositionInFace( *mMesh, includingFace.at( ( i + 1 ) % includingFaceSize ), includingFaceNeighbor );
2310 int oldValue = mFacesNeighborhood[includingFaceNeighbor][indexInNeighbor];
2322 mVertexToFace[mVertexToFace.count() - 1] = mMesh->
faceCount() - 1;
2337 int newVertexPositionInFace1 = position + 1;
2339 auto triangulate = [
this, &changes](
int removedFaceIndex,
const QgsMeshVertex & newVertex,
int newVertexPosition, QVector<int> &edgeFacesIndexes )->
bool
2345 const int addedVertexIndex = mMesh->
vertexCount();
2348 int localStartIndex = changes.
mFacesToAdd.count();
2350 QVector<int> newBoundary = initialFace;
2351 newBoundary.insert( newVertexPosition, addedVertexIndex );
2355 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
2356 std::vector<p2t::Point *> faceToFill( newBoundary.count() );
2357 for (
int i = 0; i < newBoundary.count(); ++i )
2361 if ( newBoundary.at( i ) == addedVertexIndex )
2364 vert = mMesh->
vertex( newBoundary.at( i ) );
2366 faceToFill[i] =
new p2t::Point( vert.
x(), vert.
y() );
2367 mapPoly2TriPointToVertex.insert( faceToFill[i], newBoundary.at( i ) );
2370 std::unique_ptr<p2t::CDT> cdt(
new p2t::CDT( faceToFill ) );
2372 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
2373 QVector<QgsMeshFace> newFaces( triangles.size() );
2374 for (
size_t i = 0; i < triangles.size(); ++i )
2378 for (
int j = 0; j < 3; j++ )
2380 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
2381 if ( vertInd == -1 )
2382 throw std::exception();
2390 throw std::exception();
2396 const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
2397 for (
const int vtc : verticesToFaceToChange )
2398 if ( vtc != addedVertexIndex && mVertexToFace.at( vtc ) == removedFaceIndex )
2403 topologicalFaces.
vertexToFace( vtc ) + faceStartGlobalIndex
2407 for (
int i = 0; i < topologicalFaces.mFaces.count(); ++i )
2410 for (
int n = 0; n < faceNeighbors.count(); ++n )
2412 if ( faceNeighbors.at( n ) != -1 )
2413 faceNeighbors[n] += faceStartGlobalIndex;
2417 edgeFacesIndexes.resize( 2 );
2419 for (
int i = 0 ; i < newBoundary.count(); ++i )
2421 int vertexIndex = newBoundary.at( i );
2424 int newFaceBoundaryLocalIndex = localStartIndex + circulator.
currentFaceIndex();
2426 int newFaceBoundaryIndexInMesh = faceStartGlobalIndex;
2428 int meshFaceBoundaryIndex;
2429 if ( i == newVertexPosition )
2431 meshFaceBoundaryIndex = -1;
2432 edgeFacesIndexes[0] = newFaceBoundaryLocalIndex;
2434 else if ( i == ( newVertexPosition + newBoundary.count() - 1 ) % newBoundary.count() )
2436 meshFaceBoundaryIndex = -1;
2437 edgeFacesIndexes[1] = newFaceBoundaryLocalIndex;
2440 meshFaceBoundaryIndex = mFacesNeighborhood.at( removedFaceIndex ).at( vertexPositionInFace( vertexIndex, initialFace ) );
2443 int positionInNewFaces = vertexPositionInFace( vertexIndex, newFace );
2445 if ( meshFaceBoundaryIndex != -1 )
2448 int positionInMeshFaceBoundary = vertexPositionInFace( *mMesh, vertexIndex, meshFaceBoundaryIndex );
2449 positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.count() ) % meshFace.count();
2452 positionInMeshFaceBoundary,
2454 newFaceBoundaryIndexInMesh +
2461 qDeleteAll( faceToFill );
2471 QVector<int> edgeFacesIndexes;
2472 if ( !triangulate( faceIndex, vertexToInsert, newVertexPositionInFace1, edgeFacesIndexes ) )
2480 int face2Index = mFacesNeighborhood.at( faceIndex ).at( position );
2481 if ( face2Index != -1 )
2484 int vertexPositionInFace2 = vertexPositionInFace( face1.at( position ), face2 );
2485 QVector<int> edgeFacesIndexesFace2;
2486 if ( !triangulate( face2Index, vertexToInsert, vertexPositionInFace2, edgeFacesIndexesFace2 ) )
2491 int pos1InFaceSide1 = vertexPositionInFace( addedVertexIndex, firstFaceSide1 );
2494 int pos2InFaceSide1 = vertexPositionInFace( addedVertexIndex, secondFaceSide1 );
2495 pos2InFaceSide1 = ( pos2InFaceSide1 + secondFaceSide1.size() - 1 ) % secondFaceSide1.size();
2498 int pos1InFaceSide2 = vertexPositionInFace( addedVertexIndex, firstFaceSide2 );
2501 int pos2InFaceSide2 = vertexPositionInFace( addedVertexIndex, secondFaceSide2 );
2502 pos2InFaceSide2 = ( pos2InFaceSide2 + secondFaceSide1.size() - 1 ) % secondFaceSide1.size();
2516 Q_ASSERT( verticesIndexes.count() == newValues.count() );
2519 changes.
mNewZValues.reserve( verticesIndexes.count() );
2520 changes.
mOldZValues.reserve( verticesIndexes.count() );
2521 for (
int i = 0; i < verticesIndexes.count(); ++i )
2535 Q_ASSERT( verticesIndexes.count() == newValues.count() );
2538 changes.
mNewXYValues.reserve( verticesIndexes.count() );
2539 changes.
mOldXYValues.reserve( verticesIndexes.count() );
2540 QSet<int> concernedFace;
2541 for (
int i = 0; i < verticesIndexes.count(); ++i )
2547 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) 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.