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;
2242 const QgsMeshFace newFace1 = {face.at( splitVertexPos ),
2243 face.at( ( splitVertexPos + 1 ) % faceSize ),
2244 face.at( ( splitVertexPos + 2 ) % faceSize )
2247 const QgsMeshFace newFace2 = {face.at( splitVertexPos ),
2248 face.at( ( splitVertexPos + 2 ) % faceSize ),
2249 face.at( ( splitVertexPos + 3 ) % faceSize )
2252 QVector<int> neighborIndex( faceSize );
2253 QVector<int> posInNeighbor( faceSize );
2255 for (
int i = 0; i < faceSize; ++i )
2257 neighborIndex[i] = mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + i ) % faceSize );
2258 posInNeighbor[i] = vertexPositionInFace( *mMesh, face.at( ( splitVertexPos + i + 1 ) % faceSize ), neighborIndex[i] );
2270 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 1 ) % faceSize ),
2273 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 2 ) % faceSize ),
2274 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 3 ) % faceSize )} );
2276 for (
int i = 0; i < faceSize; ++i )
2278 if ( neighborIndex[i] >= 0 )
2279 changes.
mNeighborhoodChanges.append( {neighborIndex[i], posInNeighbor[i], faceIndex, startIndex + int( i / 2 )} );
2281 int vertexIndex = face.at( ( splitVertexPos + i ) % faceSize );
2282 if ( mVertexToFace.at( vertexIndex ) == faceIndex )
2299 mVertexToFace.append( -1 );
2303 const FaceNeighbors includingFaceNeighborhood = mFacesNeighborhood.at( includingFaceIndex );
2304 int includingFaceSize = includingFace.count();
2306 for (
int i = 0; i < includingFaceSize; ++i )
2311 face[1] = includingFace.at( i );
2312 face[2] = includingFace.at( ( i + 1 ) % includingFaceSize );
2313 mMesh->
faces.append( face );
2316 int currentVertexIndex = includingFace.at( i );
2317 if ( mVertexToFace.at( currentVertexIndex ) == includingFaceIndex )
2319 int newFaceIndex = mMesh->
faceCount() - 1;
2320 mVertexToFace[currentVertexIndex] = newFaceIndex;
2324 int includingFaceNeighbor = includingFaceNeighborhood.at( i );
2328 includingFaceNeighbor,
2331 mFacesNeighborhood.append( neighbors );
2334 if ( includingFaceNeighbor != -1 )
2336 int indexInNeighbor = vertexPositionInFace( *mMesh, includingFace.at( ( i + 1 ) % includingFaceSize ), includingFaceNeighbor );
2337 int oldValue = mFacesNeighborhood[includingFaceNeighbor][indexInNeighbor];
2349 mVertexToFace[mVertexToFace.count() - 1] = mMesh->
faceCount() - 1;
2364 int newVertexPositionInFace1 = position + 1;
2366 auto triangulate = [
this, &changes](
int removedFaceIndex,
const QgsMeshVertex & newVertex,
int newVertexPosition, QVector<int> &edgeFacesIndexes )->
bool
2372 const int addedVertexIndex = mMesh->
vertexCount();
2375 int localStartIndex = changes.
mFacesToAdd.count();
2377 QVector<int> newBoundary = initialFace;
2378 newBoundary.insert( newVertexPosition, addedVertexIndex );
2382 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
2383 std::vector<p2t::Point *> faceToFill( newBoundary.count() );
2384 for (
int i = 0; i < newBoundary.count(); ++i )
2388 if ( newBoundary.at( i ) == addedVertexIndex )
2391 vert = mMesh->
vertex( newBoundary.at( i ) );
2393 faceToFill[i] =
new p2t::Point( vert.
x(), vert.
y() );
2394 mapPoly2TriPointToVertex.insert( faceToFill[i], newBoundary.at( i ) );
2397 std::unique_ptr<p2t::CDT> cdt(
new p2t::CDT( faceToFill ) );
2399 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
2400 QVector<QgsMeshFace> newFaces( triangles.size() );
2401 for (
size_t i = 0; i < triangles.size(); ++i )
2405 for (
int j = 0; j < 3; j++ )
2407 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
2408 if ( vertInd == -1 )
2409 throw std::exception();
2417 throw std::exception();
2423 const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
2424 for (
const int vtc : verticesToFaceToChange )
2425 if ( vtc != addedVertexIndex && mVertexToFace.at( vtc ) == removedFaceIndex )
2430 topologicalFaces.
vertexToFace( vtc ) + faceStartGlobalIndex
2434 for (
int i = 0; i < topologicalFaces.mFaces.count(); ++i )
2437 for (
int n = 0; n < faceNeighbors.count(); ++n )
2439 if ( faceNeighbors.at( n ) != -1 )
2440 faceNeighbors[n] += faceStartGlobalIndex;
2444 edgeFacesIndexes.resize( 2 );
2446 for (
int i = 0 ; i < newBoundary.count(); ++i )
2448 int vertexIndex = newBoundary.at( i );
2451 int newFaceBoundaryLocalIndex = localStartIndex + circulator.
currentFaceIndex();
2453 int newFaceBoundaryIndexInMesh = faceStartGlobalIndex;
2455 int meshFaceBoundaryIndex;
2456 if ( i == newVertexPosition )
2458 meshFaceBoundaryIndex = -1;
2459 edgeFacesIndexes[0] = newFaceBoundaryLocalIndex;
2461 else if ( i == ( newVertexPosition + newBoundary.count() - 1 ) % newBoundary.count() )
2463 meshFaceBoundaryIndex = -1;
2464 edgeFacesIndexes[1] = newFaceBoundaryLocalIndex;
2467 meshFaceBoundaryIndex = mFacesNeighborhood.at( removedFaceIndex ).at( vertexPositionInFace( vertexIndex, initialFace ) );
2470 int positionInNewFaces = vertexPositionInFace( vertexIndex, newFace );
2472 if ( meshFaceBoundaryIndex != -1 )
2475 int positionInMeshFaceBoundary = vertexPositionInFace( *mMesh, vertexIndex, meshFaceBoundaryIndex );
2476 positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.count() ) % meshFace.count();
2479 positionInMeshFaceBoundary,
2481 newFaceBoundaryIndexInMesh +
2488 qDeleteAll( faceToFill );
2498 QVector<int> edgeFacesIndexes;
2499 if ( !triangulate( faceIndex, vertexToInsert, newVertexPositionInFace1, edgeFacesIndexes ) )
2507 int face2Index = mFacesNeighborhood.at( faceIndex ).at( position );
2508 if ( face2Index != -1 )
2511 int vertexPositionInFace2 = vertexPositionInFace( face1.at( position ), face2 );
2512 QVector<int> edgeFacesIndexesFace2;
2513 if ( !triangulate( face2Index, vertexToInsert, vertexPositionInFace2, edgeFacesIndexesFace2 ) )
2518 int pos1InFaceSide1 = vertexPositionInFace( addedVertexIndex, firstFaceSide1 );
2521 int pos2InFaceSide1 = vertexPositionInFace( addedVertexIndex, secondFaceSide1 );
2522 pos2InFaceSide1 = ( pos2InFaceSide1 + secondFaceSide1.size() - 1 ) % secondFaceSide1.size();
2525 int pos1InFaceSide2 = vertexPositionInFace( addedVertexIndex, firstFaceSide2 );
2528 int pos2InFaceSide2 = vertexPositionInFace( addedVertexIndex, secondFaceSide2 );
2529 pos2InFaceSide2 = ( pos2InFaceSide2 + secondFaceSide1.size() - 1 ) % secondFaceSide1.size();
2543 Q_ASSERT( verticesIndexes.count() == newValues.count() );
2546 changes.
mNewZValues.reserve( verticesIndexes.count() );
2547 changes.
mOldZValues.reserve( verticesIndexes.count() );
2548 for (
int i = 0; i < verticesIndexes.count(); ++i )
2562 Q_ASSERT( verticesIndexes.count() == newValues.count() );
2565 changes.
mNewXYValues.reserve( verticesIndexes.count() );
2566 changes.
mOldXYValues.reserve( verticesIndexes.count() );
2567 QSet<int> concernedFace;
2568 for (
int i = 0; i < verticesIndexes.count(); ++i )
2574 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.