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 ) );
43 double ux1 = v1.
x() - vc.
x();
44 double uy1 = v1.
y() - vc.
y();
45 double vx1 = v2.
x() - vc.
x();
46 double vy1 = v2.
y() - vc.
y();
48 return ux1 * vy1 - uy1 * vx1;
51static double crossProduct(
int centralVertex,
int vertex1,
int vertex2,
const QgsMesh &mesh )
57 return crossProduct( vc, v1, v2 );
62 : mFaces( topologicalMesh.mMesh->faces )
63 , mFacesNeighborhood( topologicalMesh.mFacesNeighborhood )
64 , mVertexIndex( vertexIndex )
66 if ( vertexIndex >= 0 && vertexIndex < topologicalMesh.mMesh->vertexCount() )
68 mCurrentFace = topologicalMesh.mVertexToFace[vertexIndex];
69 mIsValid = vertexPositionInFace( *topologicalMesh.
mesh(), vertexIndex, mCurrentFace ) != -1;
77 mLastValidFace = mCurrentFace;
81 : mFaces( topologicalFaces.mFaces )
82 , mFacesNeighborhood( topologicalFaces.mFacesNeighborhood )
83 , mVertexIndex( vertexIndex )
85 const QgsMeshFace &face = topologicalFaces.mFaces.at( faceIndex );
86 mIsValid = vertexPositionInFace( vertexIndex, face ) != -1;
88 mCurrentFace = faceIndex;
89 mLastValidFace = mCurrentFace;
93 : mFaces( topologicalFaces.mFaces )
94 , mFacesNeighborhood( topologicalFaces.mFacesNeighborhood )
95 , mVertexIndex( vertexIndex )
97 if ( topologicalFaces.mVerticesToFace.contains( vertexIndex ) )
98 mCurrentFace = topologicalFaces.mVerticesToFace.values( vertexIndex ).first();
99 mLastValidFace = mCurrentFace;
100 mIsValid = mCurrentFace != -1;
105 if ( mCurrentFace == -1 )
106 mCurrentFace = mLastValidFace;
109 int currentPos = positionInCurrentFace();
110 Q_ASSERT( currentPos != -1 );
114 mLastValidFace = mCurrentFace;
115 mCurrentFace = mFacesNeighborhood.at( mCurrentFace ).at( ( currentPos + faceSize - 1 ) %
currentFace.count() );
123 if ( mCurrentFace == -1 )
124 mCurrentFace = mLastValidFace;
127 int currentPos = positionInCurrentFace();
128 Q_ASSERT( currentPos != -1 );
132 mLastValidFace = mCurrentFace;
133 mCurrentFace = mFacesNeighborhood.at( mCurrentFace ).at( ( currentPos ) % faceSize );
146 if ( mCurrentFace != -1 )
147 return mFaces.at( mCurrentFace );
157 if ( mCurrentFace == -1 )
158 mCurrentFace = mLastValidFace;
160 int firstFace = mCurrentFace;
163 if ( mCurrentFace == firstFace )
174 if ( mCurrentFace == -1 )
175 mCurrentFace = mLastValidFace;
177 int firstFace = mCurrentFace;
180 if ( mCurrentFace == firstFace )
188 if ( mCurrentFace == -1 )
193 if ( face.isEmpty() )
196 int vertexPosition = vertexPositionInFace( mVertexIndex,
currentFace() );
198 if ( vertexPosition == -1 )
201 return face.at( ( vertexPosition + 1 ) % face.count() );
206 if ( mCurrentFace == -1 )
211 if ( face.isEmpty() )
214 int vertexPosition = vertexPositionInFace( mVertexIndex,
currentFace() );
216 if ( vertexPosition == -1 )
219 return face.at( ( vertexPosition - 1 + face.count() ) % face.count() );
233 if ( mCurrentFace != -1 )
234 ret.append( mCurrentFace );
279int QgsMeshVertexCirculator::positionInCurrentFace()
const
281 if ( mCurrentFace < 0 || mCurrentFace >= mFaces.count() )
284 return vertexPositionInFace( mVertexIndex, mFaces.at( mCurrentFace ) );
294 for (
int i = 0; i < changes.
mFacesToAdd.count(); ++i )
297 for (
int boundary : topologicalFaces.mBoundaries )
300 if ( mVertexToFace.at( boundary ) == -1 )
303 const QList<int> &linkedFaces = topologicalFaces.mVerticesToFace.values( boundary );
304 for (
int linkedFace : linkedFaces )
310 if ( mVertexToFace.at( oppositeVertexForNewFace ) == -1 )
318 int boundaryPositionInNewFace = vertexPositionInFace( boundary, newFaceBoundary );
320 if ( oppositeVertexForMeshFace != oppositeVertexForNewFace )
332 boundaryPositionInMeshFace,
342 for (
int f = 0; f < changes.
mFacesToAdd.count(); ++f )
343 for (
int n = 0; n < changes.
mFacesToAdd.at( f ).count(); ++n )
345 changes.
mFacesNeighborhoodToAdd[f][n] = changes.addedFaceIndexInMesh( topologicalFaces.mFacesNeighborhood.at( f ).at( n ) );
347 const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
348 for (
const int vtc : verticesToFaceToChange )
349 if ( mVertexToFace.at( vtc ) == -1 )
351 mVertexToFace.at( vtc ),
352 changes.addedFaceIndexInMesh( topologicalFaces.mVerticesToFace.values( vtc ).first() ) } );
361 int initialVerticesCount = mMesh->
vertices.count();
366 mVertexToFace.resize( newSize );
372 mMesh->
faces.resize( newSize );
373 mFacesNeighborhood.resize( newSize );
379 mFacesNeighborhood[changes.removedFaceIndexInMesh( i )] =
FaceNeighbors();
385 if ( mVertexToFace.at( vertexIndex ) == -1 )
386 dereferenceAsFreeVertex( vertexIndex );
388 mVertexToFace[vertexIndex] = -1;
396 referenceAsFreeVertex( initialVerticesCount + i );
399 for (
int i = 0; i < changes.
mFacesToAdd.count(); ++i )
401 mMesh->
faces[changes.addedFaceIndexInMesh( i )] = changes.
mFacesToAdd.at( i );
407 const int faceIndex = neigborChange.at( 0 );
408 const int positionInFace = neigborChange.at( 1 );
409 const int valueToApply = neigborChange.at( 3 );
410 mFacesNeighborhood[faceIndex][positionInFace] = valueToApply;
415 int vertexIndex = vertexToFaceChange.at( 0 );
416 mVertexToFace[vertexToFaceChange.at( 0 )] = vertexToFaceChange.at( 2 );
418 if ( vertexToFaceChange.at( 2 ) == -1 &&
419 vertexToFaceChange.at( 1 ) != -1 &&
420 !mMesh->
vertices.at( vertexIndex ).isEmpty() )
421 referenceAsFreeVertex( vertexIndex );
423 if ( vertexToFaceChange.at( 1 ) == -1 && vertexToFaceChange.at( 2 ) != -1 )
424 dereferenceAsFreeVertex( vertexIndex );
435 mMesh->
vertices[vertexIndex].setX( pt.
x() );
436 mMesh->
vertices[vertexIndex].setY( pt.
y() );
445 const int faceIndex = neigborChange.at( 0 );
446 const int positionInFace = neigborChange.at( 1 );
447 const int valueToApply = neigborChange.at( 2 );
448 mFacesNeighborhood[faceIndex][positionInFace] = valueToApply;
462 if ( mVertexToFace.at( vertexIndex ) == -1 )
463 referenceAsFreeVertex( vertexIndex );
467 for (
int i = 0; i < verticesToFaceChangesCount; ++i )
469 const std::array<int, 3> vertexToFaceChange = changes.
mVerticesToFaceChanges.at( verticesToFaceChangesCount - i - 1 );
470 int vertexIndex = vertexToFaceChange.at( 0 );
471 mVertexToFace[vertexIndex] = vertexToFaceChange.at( 1 );
473 if ( vertexToFaceChange.at( 2 ) == -1 && vertexToFaceChange.at( 1 ) != -1 )
474 dereferenceAsFreeVertex( vertexIndex );
476 if ( vertexToFaceChange.at( 1 ) == -1 &&
477 vertexToFaceChange.at( 2 ) != -1 &&
479 referenceAsFreeVertex( vertexIndex );
485 mMesh->
faces.resize( newSize );
486 mFacesNeighborhood.resize( newSize );
493 for (
int i = newSize; i < mMesh->
vertexCount(); ++i )
494 if ( mVertexToFace.at( i ) == -1 )
495 dereferenceAsFreeVertex( i );
498 mVertexToFace.resize( newSize );
509 mMesh->
vertices[vertexIndex].setX( pt.
x() );
510 mMesh->
vertices[vertexIndex].setY( pt.
y() );
520QSet<int> QgsTopologicalMesh::concernedFacesBy(
const QList<int> &faceIndexes )
const
523 for (
const int faceIndex : faceIndexes )
526 for (
int i = 0; i < face.count(); ++i )
529 faces.unite( QSet< int >( around.begin(), around.end() ) );
535void QgsTopologicalMesh::dereferenceAsFreeVertex(
int vertexIndex )
537 mFreeVertices.remove( vertexIndex );
540void QgsTopologicalMesh::referenceAsFreeVertex(
int vertexIndex )
544 mFreeVertices.insert( vertexIndex );
549 for (
int faceIndex = 0 ; faceIndex < mMesh->
faces.count( ); ++faceIndex )
552 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( faceIndex );
553 if ( face.count() != neighborhood.count() )
555 for (
int i = 0; i < face.count(); ++i )
557 int vertexIndex = face.at( i );
559 if ( mVertexToFace.at( vertexIndex ) == -1 )
562 int neighborIndex = neighborhood.at( i );
563 if ( neighborIndex != -1 )
566 if ( neighborFace.isEmpty() )
568 int neighborSize = neighborFace.size();
569 const FaceNeighbors &neighborhoodOfNeighbor = mFacesNeighborhood.at( neighborIndex );
570 int posInNeighbor = vertexPositionInFace( *mMesh, vertexIndex, neighborIndex );
571 if ( neighborhoodOfNeighbor.isEmpty() || neighborhoodOfNeighbor.at( ( posInNeighbor + neighborSize - 1 ) % neighborSize ) != faceIndex )
577 for (
int vertexIndex = 0; vertexIndex < mMesh->
vertexCount(); ++vertexIndex )
579 if ( mVertexToFace.at( vertexIndex ) != -1 )
581 if ( !mMesh->
face( mVertexToFace.at( vertexIndex ) ).contains( vertexIndex ) )
607 if ( vertexIndex < 0 || vertexIndex >= mMesh->
vertexCount() )
609 return mVertexToFace.at( vertexIndex );
624 if ( vertexIndex < 0 || vertexIndex >= mMesh->
vertexCount() )
627 if ( mMesh->
vertices.at( vertexIndex ).isEmpty() )
630 return mVertexToFace.at( vertexIndex ) == -1;
635 return QList<int>( mFreeVertices.begin(), mFreeVertices.end() );
640 int size = vertices.size();
642 for (
int i = 0; i < size; ++i )
645 int iv1 = ( i + 1 ) % size;
646 int iv2 = ( i + 2 ) % size;
661 double crossProd = crossProduct( v1, v0, v2 );
662 if ( direction != 0 && crossProd * direction < 0 )
664 clockwise = direction > 0;
667 else if ( crossProd == 0 )
669 clockwise = direction > 0;
672 else if ( direction == 0 )
673 direction = crossProd / std::fabs( crossProd );
676 clockwise = direction > 0;
685 int faceSize = face.count();
689 QVector<QgsMeshVertex> vertices( face.size() );
691 for (
int i = 0; i < faceSize; ++i )
700 bool clockwise =
false;
707 for (
int i = 0; i < faceSize / 2; ++i )
710 face[i] = face.at( faceSize - i - 1 );
711 face[faceSize - i - 1] = temp;
720 QVector<int> oldToNewIndex( mMesh->
vertices.count(), -1 );
724 while ( oldIndex < verticesTotalCount )
732 oldToNewIndex[oldIndex] = newIndex;
733 if ( oldIndex != newIndex )
735 oldToNewIndex[oldIndex] = newIndex;
745 int facesTotalCount = mMesh->
faceCount();
746 while ( oldIndex < facesTotalCount )
748 if ( mMesh->
face( oldIndex ).isEmpty() )
752 if ( oldIndex != newIndex )
753 mMesh->
faces[newIndex] = mMesh->
faces[oldIndex];
755 for (
int i = 0; i < face.count(); ++i )
756 face[i] = oldToNewIndex[face.at( i )];
762 mMesh->
faces.resize( newIndex );
764 mVertexToFace.clear();
765 mFacesNeighborhood.clear();
770 QVector<int> oldToNewVerticesIndexes;
771 if ( !renumberVertices( oldToNewVerticesIndexes ) )
775 QVector<int> oldToNewFacesIndexes;
777 if ( !renumberFaces( oldToNewFacesIndexes ) )
782 QVector<QgsMeshVertex> tempVertices( mMesh->
vertices.count() );
783 for (
int i = 0; i < oldToNewVerticesIndexes.count(); ++i )
785 tempVertices[oldToNewVerticesIndexes.at( i )] = mMesh->
vertex( i );
789 QVector<QgsMeshFace> tempFaces( mMesh->
faces.count() );
790 for (
int i = 0; i < oldToNewFacesIndexes.count(); ++i )
792 tempFaces[oldToNewFacesIndexes.at( i )] = mMesh->
face( i );
794 QgsMeshFace &face = tempFaces[oldToNewFacesIndexes.at( i )];
796 for (
int fi = 0; fi < face.count(); ++fi )
798 face[fi] = oldToNewVerticesIndexes.at( face.at( fi ) );
802 mMesh->
faces = tempFaces;
808bool QgsTopologicalMesh::renumberVertices( QVector<int> &oldToNewIndex )
const
810 std::vector<QgsMeshVertexCirculator> circulators;
811 circulators.reserve( mMesh->
vertices.count() );
812 int minDegree = std::numeric_limits<int>::max();
813 int minDegreeVertex = -1;
816 QSet<int> nonThreadedVertex;
817 oldToNewIndex = QVector<int> ( mMesh->
vertexCount(), -1 );
820 circulators.emplace_back( *
this, i );
822 if ( circulators.back().degree() < minDegree )
824 minDegreeVertex = circulators.size() - 1;
825 minDegree = circulator.
degree();
827 nonThreadedVertex.insert( i );
830 auto sortedNeighbor = [ = ]( QList<int> &neighbors,
int index )
844 int degree = circulators.at( neighborIndex ).degree();
845 QList<int>::Iterator it = neighbors.begin();
846 while ( it != neighbors.end() )
848 if ( degree <= circulators.at( *it ).degree() )
850 neighbors.insert( it, neighborIndex );
855 if ( it == neighbors.end() )
856 neighbors.append( neighborIndex );
862 int currentVertex = minDegreeVertex;
863 nonThreadedVertex.remove( minDegreeVertex );
865 while ( newIndex < mMesh->vertexCount() )
867 if ( oldToNewIndex[currentVertex] == -1 )
868 oldToNewIndex[currentVertex] = newIndex++;
870 if ( circulators.at( currentVertex ).isValid() )
872 QList<int> neighbors;
873 sortedNeighbor( neighbors, currentVertex );
875 for (
const int i : std::as_const( neighbors ) )
876 if ( oldToNewIndex.at( i ) == -1 && nonThreadedVertex.contains( i ) )
879 nonThreadedVertex.remove( i );
883 if ( queue.isEmpty() )
885 if ( nonThreadedVertex.isEmpty() && newIndex < mMesh->vertexCount() )
888 const QList<int> remainingVertex( nonThreadedVertex.constBegin(), nonThreadedVertex.constEnd() );
889 int minRemainingDegree = std::numeric_limits<int>::max();
890 int minRemainingVertex = -1;
891 for (
const int i : remainingVertex )
893 int degree = circulators.at( i ).degree();
894 if ( degree < minRemainingDegree )
896 minRemainingDegree = degree;
897 minRemainingVertex = i;
900 currentVertex = minRemainingVertex;
901 nonThreadedVertex.remove( currentVertex );
905 currentVertex = queue.dequeue();
912bool QgsTopologicalMesh::renumberFaces( QVector<int> &oldToNewIndex )
const
915 QSet<int> nonThreadedFaces;
917 oldToNewIndex = QVector<int>( mMesh->
faceCount(), -1 );
919 QVector<int> faceDegrees( mMesh->
faceCount(), 0 );
921 int minDegree = std::numeric_limits<int>::max();
922 int minDegreeFace = -1;
923 for (
int faceIndex = 0; faceIndex < mMesh->
faceCount(); ++faceIndex )
925 const FaceNeighbors &neighbors = mFacesNeighborhood.at( faceIndex );
928 for (
int n = 0; n < neighbors.size(); ++n )
930 if ( neighbors.at( n ) != -1 )
934 if ( degree < minDegree )
937 minDegreeFace = faceIndex;
940 faceDegrees[faceIndex] = degree;
941 nonThreadedFaces.insert( faceIndex );
945 int currentFace = minDegreeFace;
946 nonThreadedFaces.remove( minDegreeFace );
948 auto sortedNeighbor = [ = ]( QList<int> &neighbors,
int index )
950 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( index );
952 for (
int i = 0; i < neighborhood.count(); ++i )
954 int neighborIndex = neighborhood.at( i );
955 if ( neighborIndex == -1 )
958 int degree = faceDegrees.at( neighborIndex );
959 if ( neighbors.isEmpty() )
960 neighbors.append( neighborIndex );
963 QList<int>::Iterator it = neighbors.begin();
964 while ( it != neighbors.end() )
966 if ( degree <= faceDegrees.at( *it ) )
968 neighbors.insert( it, neighborIndex );
973 if ( it == neighbors.end() )
974 neighbors.append( neighborIndex );
979 while ( newIndex < mMesh->faceCount() )
981 if ( oldToNewIndex[currentFace] == -1 )
982 oldToNewIndex[currentFace] = newIndex++;
984 QList<int> neighbors;
985 sortedNeighbor( neighbors, currentFace );
987 for (
const int i : std::as_const( neighbors ) )
988 if ( oldToNewIndex.at( i ) == -1 && nonThreadedFaces.contains( i ) )
991 nonThreadedFaces.remove( i );
994 if ( queue.isEmpty() )
996 if ( nonThreadedFaces.isEmpty() && newIndex < mMesh->faceCount() )
999 const QList<int> remainingFace( nonThreadedFaces.constBegin(), nonThreadedFaces.constEnd() );
1000 int minRemainingDegree = std::numeric_limits<int>::max();
1001 int minRemainingFace = -1;
1002 for (
const int i : remainingFace )
1004 int degree = faceDegrees.at( i );
1005 if ( degree < minRemainingDegree )
1007 minRemainingDegree = degree;
1008 minRemainingFace = i;
1011 currentFace = minRemainingFace;
1012 nonThreadedFaces.remove( currentFace );
1016 currentFace = queue.dequeue();
1031 return mFacesToRemove;
1036 return mFaceIndexesToRemove;
1041 return mVerticesToAdd;
1046 return mChangeCoordinateVerticesIndexes;
1056 return mNewXYValues;
1061 return mOldXYValues;
1066 return mNativeFacesIndexesGeometryChanged;
1071 return ( mFaceIndexesToRemove.isEmpty() &&
1072 mFacesToAdd.isEmpty() &&
1073 mFacesNeighborhoodToAdd.isEmpty() &&
1074 mFacesToRemove.isEmpty() &&
1075 mFacesNeighborhoodToRemove.isEmpty() &&
1076 mNeighborhoodChanges.isEmpty() &&
1077 mVerticesToAdd.isEmpty() &&
1078 mVertexToFaceToAdd.isEmpty() &&
1079 mVerticesToRemoveIndexes.isEmpty() &&
1080 mRemovedVertices.isEmpty() &&
1081 mVerticesToFaceRemoved.isEmpty() &&
1082 mVerticesToFaceChanges.isEmpty() &&
1083 mChangeCoordinateVerticesIndexes.isEmpty() &&
1084 mNewZValues.isEmpty() &&
1085 mOldZValues.isEmpty() &&
1086 mNewXYValues.isEmpty() &&
1087 mOldXYValues.isEmpty() &&
1088 mNativeFacesIndexesGeometryChanged.isEmpty() );
1093 return mVerticesToRemoveIndexes;
1096int QgsTopologicalMesh::Changes::addedFaceIndexInMesh(
int internalIndex )
const
1098 if ( internalIndex == -1 )
1101 return internalIndex + mAddedFacesFirstIndex;
1104int QgsTopologicalMesh::Changes::removedFaceIndexInMesh(
int internalIndex )
const
1106 if ( internalIndex == -1 )
1109 return mFaceIndexesToRemove.at( internalIndex );
1114 mAddedFacesFirstIndex = 0;
1115 mFaceIndexesToRemove.clear();
1116 mFacesToAdd.clear();
1117 mFacesNeighborhoodToAdd.clear();
1118 mFacesToRemove.clear();
1119 mFacesNeighborhoodToRemove.clear();
1120 mNeighborhoodChanges.clear();
1122 mVerticesToAdd.clear();
1123 mVertexToFaceToAdd.clear();
1124 mVerticesToRemoveIndexes.clear();
1125 mRemovedVertices.clear();
1126 mVerticesToFaceRemoved.clear();
1127 mVerticesToFaceChanges.clear();
1129 mChangeCoordinateVerticesIndexes.clear();
1130 mNewZValues.clear();
1131 mOldZValues.clear();
1132 mNewXYValues.clear();
1133 mOldXYValues.clear();
1134 mNativeFacesIndexesGeometryChanged.clear();
1144 mVertexToFace.append( -1 );
1145 referenceAsFreeVertex( mMesh->
vertices.count() - 1 );
1151static double vertexPolygonOrientation(
const QgsMesh &
mesh,
const QList<int> &vertexIndexes )
1153 if ( vertexIndexes.count() < 3 )
1156 int hullDomainVertexPos = -1;
1157 double xMin = std::numeric_limits<double>::max();
1158 double yMin = std::numeric_limits<double>::max();
1159 for (
int i = 0; i < vertexIndexes.count(); ++i )
1162 if ( xMin >= vertex.
x() && yMin > vertex.
y() )
1164 hullDomainVertexPos = i;
1170 if ( hullDomainVertexPos >= 0 )
1172 int iv1 = vertexIndexes.at( ( hullDomainVertexPos - 1 + vertexIndexes.count() ) % vertexIndexes.count() );
1173 int iv2 = vertexIndexes.at( ( hullDomainVertexPos + 1 ) % vertexIndexes.count() );
1174 int ivc = vertexIndexes.at( ( hullDomainVertexPos ) );
1175 double cp = crossProduct( ivc, iv1, iv2,
mesh );
1184 if ( vertexIndex >= mVertexToFace.count() )
1187 if ( mVertexToFace.at( vertexIndex ) == -1 )
1193 dereferenceAsFreeVertex( vertexIndex );
1201 QList<int> boundariesVertexIndex;
1202 QList<int> associateFaceToBoundaries;
1203 QList<int> removedFacesIndexes;
1204 QSet<int> boundaryInGlobalMesh;
1210 Q_ASSERT( !mMesh->
vertices.at( boundariesVertexIndex.last() ).isEmpty() );
1212 associateFaceToBoundaries.append( mFacesNeighborhood.at( circulator.
currentFaceIndex() ).at(
1213 vertexPositionInFace( boundariesVertexIndex.last(), currentFace ) ) );
1215 if ( currentFace.count() > 3 )
1217 int posInface = vertexPositionInFace( vertexIndex, currentFace );
1218 for (
int i = 2; i < currentFace.count() - 1; ++i )
1220 boundariesVertexIndex.append( currentFace.at( ( posInface + i ) % currentFace.count() ) );
1221 Q_ASSERT( !mMesh->
vertices.at( boundariesVertexIndex.last() ).isEmpty() );
1222 associateFaceToBoundaries.append( mFacesNeighborhood.at( circulator.
currentFaceIndex() ).at(
1223 vertexPositionInFace( boundariesVertexIndex.last(), currentFace ) ) );
1229 bool boundaryFill =
false;
1232 boundaryFill =
true;
1236 boundariesVertexIndex.append( lastVertexIndex );
1245 boundaryFill =
false;
1248 associateFaceToBoundaries.append( -1 );
1250 for (
const int index : std::as_const( boundariesVertexIndex ) )
1253 boundaryInGlobalMesh.insert( index );
1257 int currentVertexToFace = mVertexToFace.at( vertexIndex );
1261 QList<QList<int>> holes;
1262 QList<QList<int>> associateMeshFacesToHoles;
1264 bool cancelOperation =
false;
1272 int finalPos = boundariesVertexIndex.count() - 1;
1273 QList<int> uncoveredVertex;
1275 QList<int> partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1276 QList<int> associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1277 while ( startPos < finalPos && !partToCheck.isEmpty() )
1280 int secondPos = partToCheck.count() - 1;
1281 const QgsPoint &closingSegmentExtremety1 = mMesh->
vertex( partToCheck.at( 0 ) );
1282 const QgsPoint &closingSegmentExtremety2 = mMesh->
vertex( partToCheck.last() );
1283 bool isEdgeIntersect =
false;
1284 for (
int i = 1; i < secondPos - 1; ++i )
1288 bool isLineIntersection;
1291 if ( isEdgeIntersect )
1295 int index = partToCheck.at( 0 );
1296 if ( boundaryInGlobalMesh.contains( index ) && index != boundariesVertexIndex.at( 0 ) )
1298 cancelOperation =
true;
1304 if ( isEdgeIntersect || vertexPolygonOrientation( *mMesh, partToCheck ) >= 0 )
1306 partToCheck.removeLast();
1307 associateFacePart.removeAt( associateFacePart.count() - 2 );
1308 if ( partToCheck.count() == 1 )
1310 uncoveredVertex.append( index );
1311 startPos = startPos + 1;
1312 partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1313 associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1319 holes.append( partToCheck );
1320 associateMeshFacesToHoles.append( associateFacePart );
1322 startPos = startPos + partToCheck.count() - 1;
1323 uncoveredVertex.append( partToCheck.at( 0 ) );
1324 partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1325 associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1331 holes.append( boundariesVertexIndex );
1332 associateMeshFacesToHoles.append( associateFaceToBoundaries );
1335 if ( cancelOperation )
1341 Q_ASSERT( holes.count() == associateMeshFacesToHoles.count() );
1347 dereferenceAsFreeVertex( vertexIndex );
1349 mVertexToFace[vertexIndex] = -1;
1352 for (
int h = 0; h < holes.count(); ++h )
1354 const QList<int> &holeVertices = holes.at( h );
1355 const QList<int> &associateMeshFacesToHole = associateMeshFacesToHoles.at( h );
1356 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
1357 std::vector<p2t::Point *> holeToFill( holeVertices.count() );
1360 for (
int i = 0; i < holeVertices.count(); ++i )
1363 holeToFill[i] =
new p2t::Point( vertex.
x(), vertex.
y() );
1364 mapPoly2TriPointToVertex.insert( holeToFill[i], holeVertices.at( i ) );
1367 std::unique_ptr<p2t::CDT> cdt(
new p2t::CDT( holeToFill ) );
1370 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
1371 QVector<QgsMeshFace> newFaces( triangles.size() );
1372 for (
size_t i = 0; i < triangles.size(); ++i )
1376 for (
int j = 0; j < 3; j++ )
1378 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
1379 if ( vertInd == -1 )
1380 throw std::exception();
1381 Q_ASSERT( !mMesh->
vertices.at( vertInd ).isEmpty() );
1389 throw std::exception();
1390 int newFaceIndexStartIndex = mMesh->
faceCount();
1397 const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
1398 for (
const int vtc : verticesToFaceToChange )
1399 if ( mVertexToFace.at( vtc ) == -1 )
1401 mVertexToFace.at( vtc ),
1402 addChanges.addedFaceIndexInMesh( topologicalFaces.mVerticesToFace.values( vtc ).first() ) } );
1406 for (
int i = 0; i < topologicalFaces.mFaces.count(); ++i )
1409 faceNeighbors = topologicalFaces.mFacesNeighborhood.at( i );
1410 for (
int n = 0; n < faceNeighbors.count(); ++n )
1412 if ( faceNeighbors.at( n ) != -1 )
1413 faceNeighbors[n] += newFaceIndexStartIndex;
1418 for (
int i = 0 ; i < holeVertices.count(); ++i )
1420 int vertexHoleIndex = holeVertices.at( i );
1421 int meshFaceBoundaryIndex = associateMeshFacesToHole.at( i );
1426 int newFaceBoundaryIndexInMesh = circulator.
currentFaceIndex() + newFaceIndexStartIndex;
1428 int positionInNewFaces = vertexPositionInFace( vertexHoleIndex, newFace );
1430 if ( meshFaceBoundaryIndex != -1 )
1433 int positionInMeshFaceBoundary = vertexPositionInFace( *mMesh, vertexHoleIndex, meshFaceBoundaryIndex );
1434 positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.count() ) % meshFace.count();
1436 addChanges.
mNeighborhoodChanges.append( {meshFaceBoundaryIndex, positionInMeshFaceBoundary, -1, newFaceBoundaryIndexInMesh} );
1447 for (
const std::array<int, 4> &neighborChangeToAdd : std::as_const( addChanges.
mNeighborhoodChanges ) )
1449 bool merged =
false;
1452 if ( existingNeighborChange.at( 0 ) == neighborChangeToAdd.at( 0 ) &&
1453 existingNeighborChange.at( 1 ) == neighborChangeToAdd.at( 1 ) )
1456 Q_ASSERT( existingNeighborChange.at( 3 ) == neighborChangeToAdd.at( 2 ) );
1457 existingNeighborChange[3] = neighborChangeToAdd.at( 3 );
1464 for (
const std::array<int, 3> &verticesToFaceToAdd : std::as_const( addChanges.
mVerticesToFaceChanges ) )
1466 bool merged =
false;
1469 if ( existingVerticesToFace.at( 0 ) == verticesToFaceToAdd.at( 0 ) )
1472 Q_ASSERT( existingVerticesToFace.at( 2 ) == verticesToFaceToAdd.at( 1 ) );
1473 existingVerticesToFace[2] = verticesToFaceToAdd.at( 2 );
1480 qDeleteAll( holeToFill );
1484 qDeleteAll( holeToFill );
1499 QSet<int> facesIndex;
1501 for (
int vertexIndex : vertices )
1504 facesIndex.unite( QSet< int >( faces.begin(), faces.end() ) );
1511 for (
int vertexIndex : vertices )
1513 int currentVertexToFace = mVertexToFace.at( vertexIndex );
1519 dereferenceAsFreeVertex( vertexIndex );
1521 mVertexToFace[vertexIndex] = -1;
1529 QList<int> boundariesToCheckClockwiseInNewFaces = topologicFaces.mBoundaries;
1530 QList<std::array<int, 2>> boundariesToCheckCounterClockwiseInNewFaces;
1531 QList<int> uniqueSharedVertexBoundary;
1539 while ( !boundariesToCheckClockwiseInNewFaces.isEmpty() )
1541 int boundary = boundariesToCheckClockwiseInNewFaces.takeLast();
1543 const QList<int> &linkedFaces = topologicFaces.mVerticesToFace.values( boundary );
1545 for (
int const linkedFace : linkedFaces )
1549 if ( mVertexToFace.at( boundary ) == -1 )
1555 if ( !newFacescirculator.
isValid() )
1569 if ( oppositeVertexCCWInMesh == oppositeVertexInNewFaces )
1575 int faceSize = newFaceOnBoundary.size();
1576 int posInNewFace = vertexPositionInFace( boundary, newFaceOnBoundary );
1577 int previousVertexIndex = ( posInNewFace + faceSize - 1 ) % faceSize;
1578 if ( newFaceOnBoundary.at( previousVertexIndex ) == oppositeVertexCCWInMesh )
1586 if ( oppositeVertexCWInMesh == oppositeVertexInNewFaces )
1590 boundariesToCheckCounterClockwiseInNewFaces.append( {boundary, linkedFace} );
1595 while ( !boundariesToCheckCounterClockwiseInNewFaces.isEmpty() )
1597 std::array<int, 2> boundaryLinkedface = boundariesToCheckCounterClockwiseInNewFaces.takeLast();
1598 int boundary = boundaryLinkedface.at( 0 );
1599 int linkedFace = boundaryLinkedface.at( 1 );
1614 if ( oppositeVertexCWInMesh == oppositeVertexInNewFaces )
1621 if ( oppositeVertexCCWInMesh == oppositeVertexInNewFaces )
1624 uniqueSharedVertexBoundary.append( boundary );
1627 if ( !uniqueSharedVertexBoundary.isEmpty() )
1631 QSet<int> boundaryVertices( topologicFaces.mBoundaries.constBegin(), topologicFaces.mBoundaries.constEnd() );
1632 for (
const QgsMeshFace &newFace : std::as_const( topologicFaces.mFaces ) )
1634 for (
const int vertexIndex : newFace )
1636 if ( boundaryVertices.contains( vertexIndex ) )
1638 if ( mVertexToFace.at( vertexIndex ) != -1 )
1649 mFacesNeighborhood.clear();
1650 mVerticesToFace.clear();
1651 mBoundaries.clear();
1656 return mFacesNeighborhood;
1661 if ( mVerticesToFace.contains( vertexIndex ) )
1662 return mVerticesToFace.values( vertexIndex ).at( 0 );
1670 topologicMesh.mMesh =
mesh;
1671 topologicMesh.mVertexToFace = QVector<int>(
mesh->
vertexCount(), -1 );
1672 topologicMesh.mMaximumVerticesPerFace = maxVerticesPerFace;
1679 if ( maxVerticesPerFace != 0 &&
mesh->
face( i ).count() > maxVerticesPerFace )
1697 topologicMesh.mFacesNeighborhood = subMesh.mFacesNeighborhood;
1699 for (
int i = 0; i < topologicMesh.mMesh->
vertexCount(); ++i )
1701 if ( topologicMesh.mVertexToFace.at( i ) == -1 )
1702 topologicMesh.mFreeVertices.insert( i );
1706 return topologicMesh;
1711 return createTopologicalFaces( faces,
nullptr, error, uniqueSharedVertexAllowed );
1716 const QVector<QgsMeshFace> &faces,
1717 QVector<int> *globalVertexToFace,
1719 bool allowUniqueSharedVertex )
1721 int facesCount = faces.count();
1722 QVector<FaceNeighbors> faceTopologies;
1723 QMultiHash<int, int> verticesToFace;
1726 TopologicalFaces ret;
1730 QMap<int, QMap<int, int>> verticesToNeighbor;
1732 for (
int faceIndex = 0; faceIndex < facesCount; ++faceIndex )
1735 int faceSize = face.count();
1737 for (
int i = 0; i < faceSize; ++i )
1739 int v1 = face[i % faceSize];
1740 int v2 = face[( i + 1 ) % faceSize];
1741 if ( verticesToNeighbor[v2].contains( v1 ) )
1747 verticesToNeighbor[v2].insert( v1, faceIndex );
1751 faceTopologies = QVector<FaceNeighbors>( faces.count() );
1753 QSet<int> boundaryVertices;
1755 for (
int faceIndex = 0; faceIndex < facesCount; ++faceIndex )
1758 int faceSize = face.size();
1760 faceTopology.resize( faceSize );
1762 for (
int i = 0; i < faceSize; ++i )
1764 int v1 = face.at( i );
1765 int v2 = face.at( ( i + 1 ) % faceSize );
1767 if ( globalVertexToFace )
1769 if ( ( *globalVertexToFace )[v1] == -1 )
1770 ( *globalVertexToFace )[v1] = faceIndex ;
1774 if ( allowUniqueSharedVertex || !verticesToFace.contains( v1 ) )
1775 verticesToFace.insert( v1, faceIndex ) ;
1778 QMap<int, int> &edges = verticesToNeighbor[v1];
1779 if ( edges.contains( v2 ) )
1780 faceTopology[i] = edges.value( v2 );
1783 faceTopology[i] = -1;
1785 if ( !allowUniqueSharedVertex )
1787 if ( boundaryVertices.contains( v1 ) )
1793 boundaryVertices.insert( v1 );
1799 ret.mFacesNeighborhood = faceTopologies;
1800 ret.mBoundaries = boundaryVertices.values();
1801 ret.mVerticesToFace = verticesToFace;
1807 return mFacesNeighborhood.at( faceIndex );
1819 QSet<int> removedFaces( facesIndexes.begin(), facesIndexes.end() );
1820 QSet<int> concernedFaces = concernedFacesBy( facesIndexes );
1822 for (
const int f : std::as_const( removedFaces ) )
1823 concernedFaces.remove( f );
1825 QVector<QgsMeshFace> remainingFaces;
1826 remainingFaces.reserve( concernedFaces.count() );
1827 for (
const int f : std::as_const( concernedFaces ) )
1828 remainingFaces.append( mMesh->
face( f ) );
1831 createTopologicalFaces( remainingFaces,
nullptr, error,
false );
1843 QSet<int> indexSet( facesIndexesToRemove.begin(), facesIndexesToRemove.end() );
1844 QSet<int> threatedVertex;
1846 for (
int i = 0; i < facesIndexesToRemove.count(); ++i )
1848 const int faceIndex = facesIndexesToRemove.at( i );
1851 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( faceIndex );
1853 for (
int j = 0; j < face.count(); ++j )
1856 int neighborIndex = neighborhood.at( j );
1857 if ( neighborIndex != -1 && !indexSet.contains( neighborIndex ) )
1859 int positionInNeighbor = mFacesNeighborhood.at( neighborIndex ).indexOf( faceIndex );
1864 int vertexIndex = face.at( j );
1865 if ( !threatedVertex.contains( vertexIndex ) && indexSet.contains( mVertexToFace.at( vertexIndex ) ) )
1867 int oldValue = mVertexToFace.at( vertexIndex );
1870 if ( neighborIndex != -1 && !indexSet.contains( neighborIndex ) )
1871 refValue = neighborIndex;
1875 aroundFaces.removeOne( faceIndex );
1876 if ( !aroundFaces.isEmpty() )
1878 while ( !aroundFaces.isEmpty() && refValue == -1 )
1880 if ( !indexSet.contains( aroundFaces.first() ) )
1881 refValue = aroundFaces.first();
1883 aroundFaces.removeFirst();
1888 threatedVertex.insert( vertexIndex );
1898bool QgsTopologicalMesh::eitherSideFacesAndVertices(
int vertexIndex1,
1902 int &neighborVertex1InFace1,
1903 int &neighborVertex1InFace2,
1904 int &neighborVertex2inFace1,
1905 int &neighborVertex2inFace2 )
const
1947 int oppositeVertexFace1;
1948 int oppositeVertexFace2;
1949 int supposedOppositeVertexFace1;
1950 int supposedoppositeVertexFace2;
1952 bool result = eitherSideFacesAndVertices(
1957 oppositeVertexFace1,
1958 supposedoppositeVertexFace2,
1959 supposedOppositeVertexFace1,
1960 oppositeVertexFace2 );
1965 oppositeVertexFace1 < 0 ||
1966 oppositeVertexFace2 < 0 ||
1967 supposedOppositeVertexFace1 != oppositeVertexFace1 ||
1968 supposedoppositeVertexFace2 != oppositeVertexFace2 )
1975 if ( face1.count() != 3 || face2.count() != 3 )
1978 double crossProduct1 = crossProduct( vertexIndex1, oppositeVertexFace1, oppositeVertexFace2, *mMesh );
1979 double crossProduct2 = crossProduct( vertexIndex2, oppositeVertexFace1, oppositeVertexFace2, *mMesh );
1981 return crossProduct1 * crossProduct2 < 0;
1988 int oppositeVertexFace1;
1989 int oppositeVertexFace2;
1990 int supposedOppositeVertexFace1;
1991 int supposedoppositeVertexFace2;
1993 bool result = eitherSideFacesAndVertices(
1998 oppositeVertexFace1,
1999 supposedoppositeVertexFace2,
2000 supposedOppositeVertexFace1,
2001 oppositeVertexFace2 );
2006 oppositeVertexFace1 < 0 ||
2007 oppositeVertexFace2 < 0 ||
2008 supposedOppositeVertexFace1 != oppositeVertexFace1 ||
2009 supposedoppositeVertexFace2 != oppositeVertexFace2 )
2018 Q_ASSERT( face1.count() == 3 );
2019 Q_ASSERT( face2.count() == 3 );
2021 int pos1 = vertexPositionInFace( vertexIndex1, face1 );
2022 int pos2 = vertexPositionInFace( vertexIndex2, face2 );
2024 int neighborFace1 = mFacesNeighborhood.at( faceIndex1 ).at( pos1 );
2025 int posInNeighbor1 = vertexPositionInFace( *mMesh, oppositeVertexFace1, neighborFace1 );
2026 int neighborFace2 = mFacesNeighborhood.at( faceIndex1 ).at( ( pos1 + 1 ) % 3 );
2027 int posInNeighbor2 = vertexPositionInFace( *mMesh, vertexIndex2, neighborFace2 );
2028 int neighborFace3 = mFacesNeighborhood.at( faceIndex2 ).at( pos2 );
2029 int posInNeighbor3 = vertexPositionInFace( *mMesh, oppositeVertexFace2, neighborFace3 );
2030 int neighborFace4 = mFacesNeighborhood.at( faceIndex2 ).at( ( pos2 + 1 ) % 3 );
2031 int posInNeighbor4 = vertexPositionInFace( *mMesh, vertexIndex1, neighborFace4 );
2041 changes.
mFacesToAdd.append( {oppositeVertexFace1, oppositeVertexFace2, vertexIndex1} );
2042 changes.
mFacesToAdd.append( {oppositeVertexFace2, oppositeVertexFace1, vertexIndex2} );
2044 mFacesNeighborhood.at( faceIndex2 ).at( ( pos2 + 1 ) % 3 ),
2045 mFacesNeighborhood.at( faceIndex1 ).at( pos1 )} );
2047 mFacesNeighborhood.at( faceIndex1 ).at( ( pos1 + 1 ) % 3 ),
2048 mFacesNeighborhood.at( faceIndex2 ).at( pos2 )} );
2050 if ( neighborFace1 >= 0 )
2051 changes.
mNeighborhoodChanges.append( {neighborFace1, posInNeighbor1, faceIndex1, startIndex} );
2052 if ( neighborFace2 >= 0 )
2053 changes.
mNeighborhoodChanges.append( {neighborFace2, posInNeighbor2, faceIndex1, startIndex + 1} );
2054 if ( neighborFace3 >= 0 )
2055 changes.
mNeighborhoodChanges.append( {neighborFace3, posInNeighbor3, faceIndex2, startIndex + 1} );
2056 if ( neighborFace4 >= 0 )
2057 changes.
mNeighborhoodChanges.append( {neighborFace4, posInNeighbor4, faceIndex2, startIndex} );
2060 if ( mVertexToFace.at( vertexIndex1 ) == faceIndex1 || mVertexToFace.at( vertexIndex1 ) == faceIndex2 )
2062 if ( mVertexToFace.at( vertexIndex2 ) == faceIndex1 || mVertexToFace.at( vertexIndex2 ) == faceIndex2 )
2063 changes.
mVerticesToFaceChanges.append( {vertexIndex2, mVertexToFace.at( vertexIndex2 ), startIndex + 1} );
2065 if ( mVertexToFace.at( oppositeVertexFace1 ) == faceIndex1 )
2068 if ( mVertexToFace.at( oppositeVertexFace2 ) == faceIndex2 )
2080 int neighborVertex1InFace1;
2081 int neighborVertex1InFace2;
2082 int neighborVertex2inFace1;
2083 int neighborVertex2inFace2;
2085 bool result = eitherSideFacesAndVertices(
2090 neighborVertex1InFace1,
2091 neighborVertex1InFace2,
2092 neighborVertex2inFace1,
2093 neighborVertex2inFace2 );
2103 if ( face1.count() + face2.count() - 2 > mMaximumVerticesPerFace )
2113 double crossProduct1 = crossProduct( vertexIndex1, neighborVertex1InFace1, neighborVertex1InFace2, *mMesh );
2114 double crossProduct2 = crossProduct( vertexIndex2, neighborVertex2inFace1, neighborVertex2inFace2, *mMesh );
2116 return crossProduct1 * crossProduct2 < 0;
2123 int neighborVertex1InFace1;
2124 int neighborVertex1InFace2;
2125 int neighborVertex2inFace1;
2126 int neighborVertex2inFace2;
2128 bool result = eitherSideFacesAndVertices(
2133 neighborVertex1InFace1,
2134 neighborVertex1InFace2,
2135 neighborVertex2inFace1,
2136 neighborVertex2inFace2 );
2147 int faceSize1 = face1.count();
2148 int faceSize2 = face2.count();
2150 int pos1 = vertexPositionInFace( vertexIndex1, face1 );
2151 int pos2 = vertexPositionInFace( vertexIndex2, face2 );
2164 for (
int i = 0; i < faceSize1 - 1; ++i )
2166 int currentPos = ( pos1 + i ) % faceSize1;
2167 newface.append( face1.at( currentPos ) );
2169 int currentNeighbor = mFacesNeighborhood.at( faceIndex1 ).at( currentPos );
2170 newNeighborhood.append( currentNeighbor );
2172 if ( currentNeighbor != -1 )
2174 int currentPosInNeighbor = vertexPositionInFace( *mMesh, face1.at( ( currentPos + 1 ) % faceSize1 ), currentNeighbor );
2175 changes.
mNeighborhoodChanges.append( {currentNeighbor, currentPosInNeighbor, faceIndex1, startIndex} );
2178 for (
int i = 0; i < faceSize2 - 1; ++i )
2180 int currentPos = ( pos2 + i ) % faceSize2;
2181 newface.append( face2.at( currentPos ) );
2183 int currentNeighbor = mFacesNeighborhood.at( faceIndex2 ).at( currentPos );
2184 newNeighborhood.append( currentNeighbor );
2186 if ( currentNeighbor != -1 )
2188 int currentPosInNeighbor = vertexPositionInFace( *mMesh, face2.at( ( currentPos + 1 ) % faceSize2 ), currentNeighbor );
2189 changes.
mNeighborhoodChanges.append( {currentNeighbor, currentPosInNeighbor, faceIndex2, startIndex} );
2193 for (
int i = 0; i < faceSize1; ++i )
2194 if ( mVertexToFace.at( face1.at( i ) ) == faceIndex1 )
2197 for (
int i = 0; i < faceSize2; ++i )
2198 if ( mVertexToFace.at( face2.at( i ) ) == faceIndex2 )
2213 return face.count() == 4;
2220 int faceSize = face.count();
2222 Q_ASSERT( faceSize == 4 );
2224 double maxAngle = 0;
2225 int splitVertexPos = -1;
2226 for (
int i = 0; i < faceSize; ++i )
2228 QgsVector vect1( mMesh->
vertex( face.at( i ) ) - mMesh->
vertex( face.at( ( i + 1 ) % faceSize ) ) );
2229 QgsVector vect2( mMesh->
vertex( face.at( ( i + 2 ) % faceSize ) ) - mMesh->
vertex( face.at( ( i + 1 ) % faceSize ) ) );
2231 double angle = std::abs( vect1.
angle( vect2 ) );
2233 if (
angle > maxAngle )
2236 splitVertexPos = ( i + 1 ) % faceSize;
2241 if ( splitVertexPos == -1 )
2244 const QgsMeshFace newFace1 = {face.at( splitVertexPos ),
2245 face.at( ( splitVertexPos + 1 ) % faceSize ),
2246 face.at( ( splitVertexPos + 2 ) % faceSize )
2249 const QgsMeshFace newFace2 = {face.at( splitVertexPos ),
2250 face.at( ( splitVertexPos + 2 ) % faceSize ),
2251 face.at( ( splitVertexPos + 3 ) % faceSize )
2254 QVector<int> neighborIndex( faceSize );
2255 QVector<int> posInNeighbor( faceSize );
2257 for (
int i = 0; i < faceSize; ++i )
2259 neighborIndex[i] = mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + i ) % faceSize );
2260 posInNeighbor[i] = vertexPositionInFace( *mMesh, face.at( ( splitVertexPos + i + 1 ) % faceSize ), neighborIndex[i] );
2272 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 1 ) % faceSize ),
2275 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 2 ) % faceSize ),
2276 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 3 ) % faceSize )} );
2278 for (
int i = 0; i < faceSize; ++i )
2280 if ( neighborIndex[i] >= 0 )
2281 changes.
mNeighborhoodChanges.append( {neighborIndex[i], posInNeighbor[i], faceIndex, startIndex + int( i / 2 )} );
2283 int vertexIndex = face.at( ( splitVertexPos + i ) % faceSize );
2284 if ( mVertexToFace.at( vertexIndex ) == faceIndex )
2301 mVertexToFace.append( -1 );
2305 const FaceNeighbors includingFaceNeighborhood = mFacesNeighborhood.at( includingFaceIndex );
2306 int includingFaceSize = includingFace.count();
2308 for (
int i = 0; i < includingFaceSize; ++i )
2313 face[1] = includingFace.at( i );
2314 face[2] = includingFace.at( ( i + 1 ) % includingFaceSize );
2315 mMesh->
faces.append( face );
2318 int currentVertexIndex = includingFace.at( i );
2319 if ( mVertexToFace.at( currentVertexIndex ) == includingFaceIndex )
2321 int newFaceIndex = mMesh->
faceCount() - 1;
2322 mVertexToFace[currentVertexIndex] = newFaceIndex;
2326 int includingFaceNeighbor = includingFaceNeighborhood.at( i );
2330 includingFaceNeighbor,
2333 mFacesNeighborhood.append( neighbors );
2336 if ( includingFaceNeighbor != -1 )
2338 int indexInNeighbor = vertexPositionInFace( *mMesh, includingFace.at( ( i + 1 ) % includingFaceSize ), includingFaceNeighbor );
2339 int oldValue = mFacesNeighborhood[includingFaceNeighbor][indexInNeighbor];
2351 mVertexToFace[mVertexToFace.count() - 1] = mMesh->
faceCount() - 1;
2366 int newVertexPositionInFace1 = position + 1;
2368 auto triangulate = [
this, &changes](
int removedFaceIndex,
const QgsMeshVertex & newVertex,
int newVertexPosition, QVector<int> &edgeFacesIndexes )->
bool
2374 const int addedVertexIndex = mMesh->
vertexCount();
2377 int localStartIndex = changes.
mFacesToAdd.count();
2379 QVector<int> newBoundary = initialFace;
2380 newBoundary.insert( newVertexPosition, addedVertexIndex );
2384 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
2385 std::vector<p2t::Point *> faceToFill( newBoundary.count() );
2386 for (
int i = 0; i < newBoundary.count(); ++i )
2390 if ( newBoundary.at( i ) == addedVertexIndex )
2393 vert = mMesh->
vertex( newBoundary.at( i ) );
2395 faceToFill[i] =
new p2t::Point( vert.
x(), vert.
y() );
2396 mapPoly2TriPointToVertex.insert( faceToFill[i], newBoundary.at( i ) );
2399 std::unique_ptr<p2t::CDT> cdt(
new p2t::CDT( faceToFill ) );
2401 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
2402 QVector<QgsMeshFace> newFaces( triangles.size() );
2403 for (
size_t i = 0; i < triangles.size(); ++i )
2407 for (
int j = 0; j < 3; j++ )
2409 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
2410 if ( vertInd == -1 )
2411 throw std::exception();
2419 throw std::exception();
2425 const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
2426 for (
const int vtc : verticesToFaceToChange )
2427 if ( vtc != addedVertexIndex && mVertexToFace.at( vtc ) == removedFaceIndex )
2432 topologicalFaces.
vertexToFace( vtc ) + faceStartGlobalIndex
2436 for (
int i = 0; i < topologicalFaces.mFaces.count(); ++i )
2439 for (
int n = 0; n < faceNeighbors.count(); ++n )
2441 if ( faceNeighbors.at( n ) != -1 )
2442 faceNeighbors[n] += faceStartGlobalIndex;
2446 edgeFacesIndexes.resize( 2 );
2448 for (
int i = 0 ; i < newBoundary.count(); ++i )
2450 int vertexIndex = newBoundary.at( i );
2453 int newFaceBoundaryLocalIndex = localStartIndex + circulator.
currentFaceIndex();
2455 int newFaceBoundaryIndexInMesh = faceStartGlobalIndex;
2457 int meshFaceBoundaryIndex;
2458 if ( i == newVertexPosition )
2460 meshFaceBoundaryIndex = -1;
2461 edgeFacesIndexes[0] = newFaceBoundaryLocalIndex;
2463 else if ( i == ( newVertexPosition + newBoundary.count() - 1 ) % newBoundary.count() )
2465 meshFaceBoundaryIndex = -1;
2466 edgeFacesIndexes[1] = newFaceBoundaryLocalIndex;
2469 meshFaceBoundaryIndex = mFacesNeighborhood.at( removedFaceIndex ).at( vertexPositionInFace( vertexIndex, initialFace ) );
2472 int positionInNewFaces = vertexPositionInFace( vertexIndex, newFace );
2474 if ( meshFaceBoundaryIndex != -1 )
2477 int positionInMeshFaceBoundary = vertexPositionInFace( *mMesh, vertexIndex, meshFaceBoundaryIndex );
2478 positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.count() ) % meshFace.count();
2481 positionInMeshFaceBoundary,
2483 newFaceBoundaryIndexInMesh +
2490 qDeleteAll( faceToFill );
2500 QVector<int> edgeFacesIndexes;
2501 if ( !triangulate( faceIndex, vertexToInsert, newVertexPositionInFace1, edgeFacesIndexes ) )
2509 int face2Index = mFacesNeighborhood.at( faceIndex ).at( position );
2510 if ( face2Index != -1 )
2513 int vertexPositionInFace2 = vertexPositionInFace( face1.at( position ), face2 );
2514 QVector<int> edgeFacesIndexesFace2;
2515 if ( !triangulate( face2Index, vertexToInsert, vertexPositionInFace2, edgeFacesIndexesFace2 ) )
2520 int pos1InFaceSide1 = vertexPositionInFace( addedVertexIndex, firstFaceSide1 );
2523 int pos2InFaceSide1 = vertexPositionInFace( addedVertexIndex, secondFaceSide1 );
2524 pos2InFaceSide1 = ( pos2InFaceSide1 + secondFaceSide1.size() - 1 ) % secondFaceSide1.size();
2527 int pos1InFaceSide2 = vertexPositionInFace( addedVertexIndex, firstFaceSide2 );
2530 int pos2InFaceSide2 = vertexPositionInFace( addedVertexIndex, secondFaceSide2 );
2531 pos2InFaceSide2 = ( pos2InFaceSide2 + secondFaceSide1.size() - 1 ) % secondFaceSide1.size();
2545 Q_ASSERT( verticesIndexes.count() == newValues.count() );
2548 changes.
mNewZValues.reserve( verticesIndexes.count() );
2549 changes.
mOldZValues.reserve( verticesIndexes.count() );
2550 for (
int i = 0; i < verticesIndexes.count(); ++i )
2564 Q_ASSERT( verticesIndexes.count() == newValues.count() );
2567 changes.
mNewXYValues.reserve( verticesIndexes.count() );
2568 changes.
mOldXYValues.reserve( verticesIndexes.count() );
2569 QSet<int> concernedFace;
2570 for (
int i = 0; i < verticesIndexes.count(); ++i )
2576 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...
static QgsMeshEditingError checkTopologyOfVerticesAsFace(const QVector< QgsMeshVertex > &vertices, bool &clockwise)
Checks the topology of the vertices as they are contained in a face and returns indication on directi...
Changes changeZValue(const QList< int > &verticesIndexes, const QList< double > &newValues)
Changes the Z values of the vertices with indexes in vertices indexes with the values in newValues.
static QgsTopologicalMesh createTopologicalMesh(QgsMesh *mesh, int maxVerticesPerFace, QgsMeshEditingError &error)
Creates a topologicaly consistent mesh with mesh, this static method modifies mesh to be topological ...
bool isVertexFree(int vertexIndex) const
Returns whether the vertex is a free vertex.
static QgsMeshEditingError counterClockwiseFaces(QgsMeshFace &face, QgsMesh *mesh)
Checks the topology of the face and sets it counter clockwise if necessary.
Changes removeVertexFillHole(int vertexIndex)
Removes the vertex with index vertexIndex.
static QgsMeshEditingError checkTopology(const QgsMesh &mesh, int maxVerticesPerFace)
Checks the topology of the mesh mesh, if error occurs, this mesh can't be edited.
friend class QgsMeshVertexCirculator
void applyChanges(const Changes &changes)
Applies the changes.
int firstFaceLinked(int vertexIndex) const
Returns the index of the first face linked, returns -1 if it is a free vertex or out of range index.
QgsMeshEditingError checkConsistency() const
Checks the consistency of the topological mesh and return false if there is a consistency issue.
Changes removeVertices(const QList< int > &vertices)
Removes all the vertices with index in the list vertices If vertices in linked with faces,...
Changes changeXYValue(const QList< int > &verticesIndexes, const QList< QgsPointXY > &newValues)
Changes the (X,Y) values of the vertices with indexes in vertices indexes with the values in newValue...
void reindex()
Reindexes faces and vertices, after this operation, the topological mesh can't be edited anymore and ...
QVector< int > neighborsOfFace(int faceIndex) const
Returns the indexes of neighbor faces of the face with index faceIndex.
QgsMeshEditingError facesCanBeAdded(const TopologicalFaces &topologicalFaces) const
Returns whether the faces can be added to the mesh.
bool renumber()
Renumbers the indexes of vertices and faces using the Reverse CutHill McKee Algorithm.
Changes flipEdge(int vertexIndex1, int vertexIndex2)
Flips edge (vertexIndex1, vertexIndex2) The method returns a instance of the class QgsTopologicalMesh...
QgsMeshEditingError facesCanBeRemoved(const QList< int > &facesIndexes)
Returns whether faces with index in faceIndexes can be removed/ The method an error object with type ...
QVector< int > FaceNeighbors
void reverseChanges(const Changes &changes)
Reverses the changes.
Changes addFaces(const TopologicalFaces &topologicFaces)
Adds faces topologicFaces to the topologic mesh.
Changes merge(int vertexIndex1, int vertexIndex2)
Merges faces separated by vertices with indexes vertexIndex1 and vertexIndex2 The method returns a in...
Changes removeFaces(const QList< int > &facesIndexes)
Removes faces with index in faceIndexes.
QList< int > freeVerticesIndexes() const
Returns a list of vertices are not linked to any faces.
bool edgeCanBeFlipped(int vertexIndex1, int vertexIndex2) const
Returns true if the edge can be flipped (only available for edge shared by two faces with 3 vertices)
Changes addVertexInFace(int faceIndex, const QgsMeshVertex &vertex)
Adds a vertex in the face with index faceIndex.
bool canBeMerged(int vertexIndex1, int vertexIndex2) const
Returns true if faces separated by vertices with indexes vertexIndex1 and vertexIndex2 can be merged.
QList< int > facesAroundVertex(int vertexIndex) const
Returns the indexes of faces that are around the vertex with index vertexIndex.
bool canBeSplit(int faceIndex) const
Returns true if face with index faceIndex can be split.
Changes addFreeVertex(const QgsMeshVertex &vertex)
Adds a free vertex in the face, that is a vertex 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.