31 if ( faceIndex < 0 || faceIndex >=
mesh.faceCount() )
40 double ux1 = v1.
x() - vc.
x();
41 double uy1 = v1.
y() - vc.
y();
42 double vx1 = v2.
x() - vc.
x();
43 double vy1 = v2.
y() - vc.
y();
45 return ux1 * vy1 - uy1 * vx1;
48static double crossProduct(
int centralVertex,
int vertex1,
int vertex2,
const QgsMesh &mesh )
54 return crossProduct( vc, v1, v2 );
59 : mFaces( topologicalMesh.mMesh->faces )
60 , mFacesNeighborhood( topologicalMesh.mFacesNeighborhood )
61 , mVertexIndex( vertexIndex )
63 if ( vertexIndex >= 0 && vertexIndex < topologicalMesh.mMesh->vertexCount() )
65 mCurrentFace = topologicalMesh.mVertexToFace[vertexIndex];
74 mLastValidFace = mCurrentFace;
78 : mFaces( topologicalFaces.mFaces )
79 , mFacesNeighborhood( topologicalFaces.mFacesNeighborhood )
80 , mVertexIndex( vertexIndex )
82 const QgsMeshFace &face = topologicalFaces.mFaces.at( faceIndex );
85 mCurrentFace = faceIndex;
86 mLastValidFace = mCurrentFace;
90 : mFaces( topologicalFaces.mFaces )
91 , mFacesNeighborhood( topologicalFaces.mFacesNeighborhood )
92 , mVertexIndex( vertexIndex )
94 if ( topologicalFaces.mVerticesToFace.contains( vertexIndex ) )
95 mCurrentFace = topologicalFaces.mVerticesToFace.values( vertexIndex ).first();
96 mLastValidFace = mCurrentFace;
97 mIsValid = mCurrentFace != -1;
102 if ( mCurrentFace == -1 )
103 mCurrentFace = mLastValidFace;
106 int currentPos = positionInCurrentFace();
107 Q_ASSERT( currentPos != -1 );
111 mLastValidFace = mCurrentFace;
112 mCurrentFace = mFacesNeighborhood.at( mCurrentFace ).at( ( currentPos + faceSize - 1 ) %
currentFace.count() );
120 if ( mCurrentFace == -1 )
121 mCurrentFace = mLastValidFace;
124 int currentPos = positionInCurrentFace();
125 Q_ASSERT( currentPos != -1 );
129 mLastValidFace = mCurrentFace;
130 mCurrentFace = mFacesNeighborhood.at( mCurrentFace ).at( ( currentPos ) % faceSize );
143 if ( mCurrentFace != -1 )
144 return mFaces.at( mCurrentFace );
154 if ( mCurrentFace == -1 )
155 mCurrentFace = mLastValidFace;
157 int firstFace = mCurrentFace;
162 if ( mCurrentFace == firstFace )
173 if ( mCurrentFace == -1 )
174 mCurrentFace = mLastValidFace;
176 int firstFace = mCurrentFace;
181 if ( mCurrentFace == firstFace )
189 if ( mCurrentFace == -1 )
194 if ( face.isEmpty() )
199 if ( vertexPosition == -1 )
202 return face.at( ( vertexPosition + 1 ) % face.count() );
207 if ( mCurrentFace == -1 )
212 if ( face.isEmpty() )
217 if ( vertexPosition == -1 )
220 return face.at( ( vertexPosition - 1 + face.count() ) % face.count() );
234 if ( mCurrentFace != -1 )
235 ret.append( mCurrentFace );
280int QgsMeshVertexCirculator::positionInCurrentFace()
const
282 if ( mCurrentFace < 0 || mCurrentFace >= mFaces.count() )
295 for (
int i = 0; i < changes.
mFacesToAdd.count(); ++i )
298 for (
int boundary : topologicalFaces.mBoundaries )
301 if ( mVertexToFace.at( boundary ) == -1 )
304 const QList<int> &linkedFaces = topologicalFaces.mVerticesToFace.values( boundary );
305 for (
int linkedFace : linkedFaces )
311 if ( mVertexToFace.at( oppositeVertexForNewFace ) == -1 )
321 if ( oppositeVertexForMeshFace != oppositeVertexForNewFace )
331 std::array<int, 4>( { meshCirculator.
currentFaceIndex(), boundaryPositionInMeshFace, -1, changes.addedFaceIndexInMesh( newFacesCirculator.
currentFaceIndex() ) } )
339 for (
int f = 0; f < changes.
mFacesToAdd.count(); ++f )
340 for (
int n = 0; n < changes.
mFacesToAdd.at( f ).count(); ++n )
342 changes.
mFacesNeighborhoodToAdd[f][n] = changes.addedFaceIndexInMesh( topologicalFaces.mFacesNeighborhood.at( f ).at( n ) );
344 const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
345 for (
const int vtc : verticesToFaceToChange )
346 if ( mVertexToFace.at( vtc ) == -1 )
347 changes.
mVerticesToFaceChanges.append( { vtc, mVertexToFace.at( vtc ), changes.addedFaceIndexInMesh( topologicalFaces.mVerticesToFace.values( vtc ).first() ) } );
356 int initialVerticesCount = mMesh->vertices.count();
359 int newSize = mMesh->vertices.count() + changes.
mVerticesToAdd.count();
360 mMesh->vertices.resize( newSize );
361 mVertexToFace.resize( newSize );
366 int newSize = mMesh->faceCount() + changes.
mFacesToAdd.count();
367 mMesh->faces.resize( newSize );
368 mFacesNeighborhood.resize( newSize );
373 mMesh->faces[changes.removedFaceIndexInMesh( i )] =
QgsMeshFace();
374 mFacesNeighborhood[changes.removedFaceIndexInMesh( i )] =
FaceNeighbors();
380 if ( mVertexToFace.at( vertexIndex ) == -1 )
381 dereferenceAsFreeVertex( vertexIndex );
383 mVertexToFace[vertexIndex] = -1;
388 mMesh->vertices[initialVerticesCount + i] = changes.
mVerticesToAdd.at( i );
391 referenceAsFreeVertex( initialVerticesCount + i );
394 for (
int i = 0; i < changes.
mFacesToAdd.count(); ++i )
396 mMesh->faces[changes.addedFaceIndexInMesh( i )] = changes.
mFacesToAdd.at( i );
402 const int faceIndex = neighborChange.at( 0 );
403 const int positionInFace = neighborChange.at( 1 );
404 const int valueToApply = neighborChange.at( 3 );
405 mFacesNeighborhood[faceIndex][positionInFace] = valueToApply;
410 int vertexIndex = vertexToFaceChange.at( 0 );
411 mVertexToFace[vertexToFaceChange.at( 0 )] = vertexToFaceChange.at( 2 );
413 if ( vertexToFaceChange.at( 2 ) == -1 && vertexToFaceChange.at( 1 ) != -1 && !mMesh->vertices.at( vertexIndex ).isEmpty() )
414 referenceAsFreeVertex( vertexIndex );
416 if ( vertexToFaceChange.at( 1 ) == -1 && vertexToFaceChange.at( 2 ) != -1 )
417 dereferenceAsFreeVertex( vertexIndex );
424 mMesh->vertices[vertexIndex].setZ( changes.
mNewZValues.at( i ) );
428 mMesh->vertices[vertexIndex].setX( pt.
x() );
429 mMesh->vertices[vertexIndex].setY( pt.
y() );
438 const int faceIndex = neighborChange.at( 0 );
439 const int positionInFace = neighborChange.at( 1 );
440 const int valueToApply = neighborChange.at( 2 );
441 mFacesNeighborhood[faceIndex][positionInFace] = valueToApply;
446 mMesh->faces[changes.removedFaceIndexInMesh( i )] = changes.
mFacesToRemove.at( i );
455 if ( mVertexToFace.at( vertexIndex ) == -1 )
456 referenceAsFreeVertex( vertexIndex );
460 for (
int i = 0; i < verticesToFaceChangesCount; ++i )
462 const std::array<int, 3> vertexToFaceChange = changes.
mVerticesToFaceChanges.at( verticesToFaceChangesCount - i - 1 );
463 int vertexIndex = vertexToFaceChange.at( 0 );
464 mVertexToFace[vertexIndex] = vertexToFaceChange.at( 1 );
466 if ( vertexToFaceChange.at( 2 ) == -1 && vertexToFaceChange.at( 1 ) != -1 )
467 dereferenceAsFreeVertex( vertexIndex );
469 if ( vertexToFaceChange.at( 1 ) == -1 && vertexToFaceChange.at( 2 ) != -1 && !mMesh->vertex( vertexIndex ).isEmpty() )
470 referenceAsFreeVertex( vertexIndex );
475 int newSize = mMesh->faceCount() - changes.
mFacesToAdd.count();
476 mMesh->faces.resize( newSize );
477 mFacesNeighborhood.resize( newSize );
482 int newSize = mMesh->vertexCount() - changes.
mVerticesToAdd.count();
484 for (
int i = newSize; i < mMesh->vertexCount(); ++i )
485 if ( mVertexToFace.at( i ) == -1 )
486 dereferenceAsFreeVertex( i );
488 mMesh->vertices.resize( newSize );
489 mVertexToFace.resize( newSize );
496 mMesh->vertices[vertexIndex].setZ( changes.
mOldZValues.at( i ) );
500 mMesh->vertices[vertexIndex].setX( pt.
x() );
501 mMesh->vertices[vertexIndex].setY( pt.
y() );
511QSet<int> QgsTopologicalMesh::concernedFacesBy(
const QList<int> &faceIndexes )
const
514 for (
const int faceIndex : faceIndexes )
517 for (
int i = 0; i < face.count(); ++i )
520 faces.unite( QSet< int >( around.begin(), around.end() ) );
526void QgsTopologicalMesh::dereferenceAsFreeVertex(
int vertexIndex )
528 mFreeVertices.remove( vertexIndex );
531void QgsTopologicalMesh::referenceAsFreeVertex(
int vertexIndex )
535 mFreeVertices.insert( vertexIndex );
540 for (
int faceIndex = 0; faceIndex < mMesh->faces.count(); ++faceIndex )
542 const QgsMeshFace &face = mMesh->faces.at( faceIndex );
543 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( faceIndex );
544 if ( face.count() != neighborhood.count() )
546 for (
int i = 0; i < face.count(); ++i )
548 int vertexIndex = face.at( i );
550 if ( mVertexToFace.at( vertexIndex ) == -1 )
553 int neighborIndex = neighborhood.at( i );
554 if ( neighborIndex != -1 )
556 const QgsMeshFace &neighborFace = mMesh->faces.at( neighborIndex );
557 if ( neighborFace.isEmpty() )
559 int neighborSize = neighborFace.size();
560 const FaceNeighbors &neighborhoodOfNeighbor = mFacesNeighborhood.at( neighborIndex );
562 if ( neighborhoodOfNeighbor.isEmpty() || neighborhoodOfNeighbor.at( ( posInNeighbor + neighborSize - 1 ) % neighborSize ) != faceIndex )
568 for (
int vertexIndex = 0; vertexIndex < mMesh->vertexCount(); ++vertexIndex )
570 if ( mVertexToFace.at( vertexIndex ) != -1 )
572 if ( !mMesh->face( mVertexToFace.at( vertexIndex ) ).contains( vertexIndex ) )
598 if ( vertexIndex < 0 || vertexIndex >= mMesh->vertexCount() )
600 return mVertexToFace.at( vertexIndex );
615 if ( vertexIndex < 0 || vertexIndex >= mMesh->vertexCount() )
618 if ( mMesh->vertices.at( vertexIndex ).isEmpty() )
621 return mVertexToFace.at( vertexIndex ) == -1;
626 return QList<int>( mFreeVertices.begin(), mFreeVertices.end() );
631 int size = vertices.size();
633 for (
int i = 0; i < size; ++i )
636 int iv1 = ( i + 1 ) % size;
637 int iv2 = ( i + 2 ) % size;
652 double crossProd = crossProduct( v1, v0, v2 );
653 if ( direction != 0 && crossProd * direction < 0 )
655 clockwise = direction > 0;
658 else if ( crossProd == 0 )
660 clockwise = direction > 0;
663 else if ( direction == 0 )
664 direction = crossProd / std::fabs( crossProd );
667 clockwise = direction > 0;
676 int faceSize = face.count();
680 QVector<QgsMeshVertex> vertices( face.size() );
682 for (
int i = 0; i < faceSize; ++i )
685 if ( iv < 0 || iv >=
mesh->vertexCount() )
688 vertices[i] =
mesh->vertices.at( face[i] );
691 bool clockwise =
false;
698 for (
int i = 0; i < faceSize / 2; ++i )
701 face[i] = face.at( faceSize - i - 1 );
702 face[faceSize - i - 1] = temp;
711 QVector<int> oldToNewIndex( mMesh->vertices.count(), -1 );
712 int verticesTotalCount = mMesh->vertexCount();
715 while ( oldIndex < verticesTotalCount )
717 if ( mMesh->vertex( oldIndex ).isEmpty() )
723 oldToNewIndex[oldIndex] = newIndex;
724 if ( oldIndex != newIndex )
725 mMesh->vertices[newIndex] = mMesh->vertices[oldIndex];
726 oldToNewIndex[oldIndex] = newIndex;
732 mMesh->vertices.resize( newIndex );
736 int facesTotalCount = mMesh->faceCount();
737 while ( oldIndex < facesTotalCount )
739 if ( mMesh->face( oldIndex ).isEmpty() )
743 if ( oldIndex != newIndex )
744 mMesh->faces[newIndex] = mMesh->faces[oldIndex];
746 for (
int i = 0; i < face.count(); ++i )
747 face[i] = oldToNewIndex[face.at( i )];
753 mMesh->faces.resize( newIndex );
755 mVertexToFace.clear();
756 mFacesNeighborhood.clear();
761 QVector<int> oldToNewVerticesIndexes;
762 if ( !renumberVertices( oldToNewVerticesIndexes ) )
766 QVector<int> oldToNewFacesIndexes;
768 if ( !renumberFaces( oldToNewFacesIndexes ) )
773 QVector<QgsMeshVertex> tempVertices( mMesh->vertices.count() );
774 for (
int i = 0; i < oldToNewVerticesIndexes.count(); ++i )
776 tempVertices[oldToNewVerticesIndexes.at( i )] = mMesh->vertex( i );
778 mMesh->vertices = tempVertices;
780 QVector<QgsMeshFace> tempFaces( mMesh->faces.count() );
781 for (
int i = 0; i < oldToNewFacesIndexes.count(); ++i )
783 tempFaces[oldToNewFacesIndexes.at( i )] = mMesh->face( i );
785 QgsMeshFace &face = tempFaces[oldToNewFacesIndexes.at( i )];
787 for (
int fi = 0; fi < face.count(); ++fi )
789 face[fi] = oldToNewVerticesIndexes.at( face.at( fi ) );
793 mMesh->faces = tempFaces;
798bool QgsTopologicalMesh::renumberVertices( QVector<int> &oldToNewIndex )
const
800 std::vector<QgsMeshVertexCirculator> circulators;
801 circulators.reserve( mMesh->
vertices.count() );
802 int minDegree = std::numeric_limits<int>::max();
803 int minDegreeVertex = -1;
806 QSet<int> nonThreadedVertex;
807 oldToNewIndex = QVector<int>( mMesh->
vertexCount(), -1 );
810 circulators.emplace_back( *
this, i );
812 if ( circulators.back().degree() < minDegree )
814 minDegreeVertex = circulators.size() - 1;
815 minDegree = circulator.
degree();
817 nonThreadedVertex.insert( i );
820 auto sortedNeighbor = [circulators]( QList<int> &neighbors,
int index ) {
833 int degree = circulators.at( neighborIndex ).degree();
834 QList<int>::Iterator it = neighbors.begin();
835 while ( it != neighbors.end() )
837 if ( degree <= circulators.at( *it ).degree() )
839 neighbors.insert( it, neighborIndex );
844 if ( it == neighbors.end() )
845 neighbors.append( neighborIndex );
850 int currentVertex = minDegreeVertex;
851 nonThreadedVertex.remove( minDegreeVertex );
853 while ( newIndex < mMesh->vertexCount() )
855 if ( oldToNewIndex[currentVertex] == -1 )
856 oldToNewIndex[currentVertex] = newIndex++;
858 if ( circulators.at( currentVertex ).isValid() )
860 QList<int> neighbors;
861 sortedNeighbor( neighbors, currentVertex );
863 for (
const int i : std::as_const( neighbors ) )
864 if ( oldToNewIndex.at( i ) == -1 && nonThreadedVertex.contains( i ) )
867 nonThreadedVertex.remove( i );
871 if ( queue.isEmpty() )
873 if ( nonThreadedVertex.isEmpty() && newIndex < mMesh->vertexCount() )
876 const QList<int> remainingVertex( nonThreadedVertex.constBegin(), nonThreadedVertex.constEnd() );
877 int minRemainingDegree = std::numeric_limits<int>::max();
878 int minRemainingVertex = -1;
879 for (
const int i : remainingVertex )
881 int degree = circulators.at( i ).degree();
882 if ( degree < minRemainingDegree )
884 minRemainingDegree = degree;
885 minRemainingVertex = i;
888 currentVertex = minRemainingVertex;
889 nonThreadedVertex.remove( currentVertex );
893 currentVertex = queue.dequeue();
900bool QgsTopologicalMesh::renumberFaces( QVector<int> &oldToNewIndex )
const
903 QSet<int> nonThreadedFaces;
905 oldToNewIndex = QVector<int>( mMesh->faceCount(), -1 );
907 QVector<int> faceDegrees( mMesh->faceCount(), 0 );
909 int minDegree = std::numeric_limits<int>::max();
910 int minDegreeFace = -1;
911 for (
int faceIndex = 0; faceIndex < mMesh->faceCount(); ++faceIndex )
913 const FaceNeighbors &neighbors = mFacesNeighborhood.at( faceIndex );
916 for (
int n = 0; n < neighbors.size(); ++n )
918 if ( neighbors.at( n ) != -1 )
922 if ( degree < minDegree )
925 minDegreeFace = faceIndex;
928 faceDegrees[faceIndex] = degree;
929 nonThreadedFaces.insert( faceIndex );
933 int currentFace = minDegreeFace;
934 nonThreadedFaces.remove( minDegreeFace );
936 auto sortedNeighbor = [
this, faceDegrees]( QList<int> &neighbors,
int index ) {
937 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( index );
939 for (
int i = 0; i < neighborhood.count(); ++i )
941 int neighborIndex = neighborhood.at( i );
942 if ( neighborIndex == -1 )
945 int degree = faceDegrees.at( neighborIndex );
946 if ( neighbors.isEmpty() )
947 neighbors.append( neighborIndex );
950 QList<int>::Iterator it = neighbors.begin();
951 while ( it != neighbors.end() )
953 if ( degree <= faceDegrees.at( *it ) )
955 neighbors.insert( it, neighborIndex );
960 if ( it == neighbors.end() )
961 neighbors.append( neighborIndex );
966 while ( newIndex < mMesh->faceCount() )
968 if ( oldToNewIndex[currentFace] == -1 )
969 oldToNewIndex[currentFace] = newIndex++;
971 QList<int> neighbors;
972 sortedNeighbor( neighbors, currentFace );
974 for (
const int i : std::as_const( neighbors ) )
975 if ( oldToNewIndex.at( i ) == -1 && nonThreadedFaces.contains( i ) )
978 nonThreadedFaces.remove( i );
981 if ( queue.isEmpty() )
983 if ( nonThreadedFaces.isEmpty() && newIndex < mMesh->faceCount() )
986 const QList<int> remainingFace( nonThreadedFaces.constBegin(), nonThreadedFaces.constEnd() );
987 int minRemainingDegree = std::numeric_limits<int>::max();
988 int minRemainingFace = -1;
989 for (
const int i : remainingFace )
991 int degree = faceDegrees.at( i );
992 if ( degree < minRemainingDegree )
994 minRemainingDegree = degree;
995 minRemainingFace = i;
998 currentFace = minRemainingFace;
999 nonThreadedFaces.remove( currentFace );
1003 currentFace = queue.dequeue();
1084int QgsTopologicalMesh::Changes::addedFaceIndexInMesh(
int internalIndex )
const
1086 if ( internalIndex == -1 )
1089 return internalIndex + mAddedFacesFirstIndex;
1092int QgsTopologicalMesh::Changes::removedFaceIndexInMesh(
int internalIndex )
const
1094 if ( internalIndex == -1 )
1097 return mFaceIndexesToRemove.at( internalIndex );
1131 mMesh->vertices.append( vertex );
1132 mVertexToFace.append( -1 );
1133 referenceAsFreeVertex( mMesh->vertices.count() - 1 );
1139static double vertexPolygonOrientation(
const QgsMesh &
mesh,
const QList<int> &vertexIndexes )
1141 if ( vertexIndexes.count() < 3 )
1144 int hullDomainVertexPos = -1;
1145 double xMin = std::numeric_limits<double>::max();
1146 double yMin = std::numeric_limits<double>::max();
1147 for (
int i = 0; i < vertexIndexes.count(); ++i )
1150 if ( xMin >= vertex.
x() && yMin > vertex.
y() )
1152 hullDomainVertexPos = i;
1158 if ( hullDomainVertexPos >= 0 )
1160 int iv1 = vertexIndexes.at( ( hullDomainVertexPos - 1 + vertexIndexes.count() ) % vertexIndexes.count() );
1161 int iv2 = vertexIndexes.at( ( hullDomainVertexPos + 1 ) % vertexIndexes.count() );
1162 int ivc = vertexIndexes.at( ( hullDomainVertexPos ) );
1163 double cp = crossProduct( ivc, iv1, iv2,
mesh );
1172 if ( vertexIndex >= mVertexToFace.count() )
1175 if ( mVertexToFace.at( vertexIndex ) == -1 )
1181 dereferenceAsFreeVertex( vertexIndex );
1189 QList<int> boundariesVertexIndex;
1190 QList<int> associateFaceToBoundaries;
1191 QList<int> removedFacesIndexes;
1192 QSet<int> boundaryInGlobalMesh;
1198 Q_ASSERT( !mMesh->vertices.at( boundariesVertexIndex.last() ).isEmpty() );
1202 if ( currentFace.count() > 3 )
1205 for (
int i = 2; i < currentFace.count() - 1; ++i )
1207 boundariesVertexIndex.append( currentFace.at( ( posInface + i ) % currentFace.count() ) );
1208 Q_ASSERT( !mMesh->vertices.at( boundariesVertexIndex.last() ).isEmpty() );
1214 bool boundaryFill =
false;
1217 boundaryFill =
true;
1221 boundariesVertexIndex.append( lastVertexIndex );
1230 boundaryFill =
false;
1233 associateFaceToBoundaries.append( -1 );
1235 for (
const int index : std::as_const( boundariesVertexIndex ) )
1238 boundaryInGlobalMesh.insert( index );
1242 int currentVertexToFace = mVertexToFace.at( vertexIndex );
1246 QList<QList<int>> holes;
1247 QList<QList<int>> associateMeshFacesToHoles;
1249 bool cancelOperation =
false;
1257 int finalPos = boundariesVertexIndex.count() - 1;
1258 QList<int> uncoveredVertex;
1260 QList<int> partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1261 QList<int> associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1262 while ( startPos < finalPos && !partToCheck.isEmpty() )
1265 int secondPos = partToCheck.count() - 1;
1266 const QgsPoint &closingSegmentExtremety1 = mMesh->vertex( partToCheck.at( 0 ) );
1267 const QgsPoint &closingSegmentExtremety2 = mMesh->vertex( partToCheck.last() );
1268 bool isEdgeIntersect =
false;
1269 for (
int i = 1; i < secondPos - 1; ++i )
1271 const QgsPoint &p1 = mMesh->vertex( partToCheck.at( i ) );
1272 const QgsPoint &p2 = mMesh->vertex( partToCheck.at( i + 1 ) );
1273 bool isLineIntersection;
1276 if ( isEdgeIntersect )
1280 int index = partToCheck.at( 0 );
1281 if ( boundaryInGlobalMesh.contains( index ) && index != boundariesVertexIndex.at( 0 ) )
1283 cancelOperation =
true;
1289 if ( isEdgeIntersect || vertexPolygonOrientation( *mMesh, partToCheck ) >= 0 )
1291 partToCheck.removeLast();
1292 associateFacePart.removeAt( associateFacePart.count() - 2 );
1293 if ( partToCheck.count() == 1 )
1295 uncoveredVertex.append( index );
1296 startPos = startPos + 1;
1297 partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1298 associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1304 holes.append( partToCheck );
1305 associateMeshFacesToHoles.append( associateFacePart );
1307 startPos = startPos + partToCheck.count() - 1;
1308 uncoveredVertex.append( partToCheck.at( 0 ) );
1309 partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1310 associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1316 holes.append( boundariesVertexIndex );
1317 associateMeshFacesToHoles.append( associateFaceToBoundaries );
1320 if ( cancelOperation )
1326 Q_ASSERT( holes.count() == associateMeshFacesToHoles.count() );
1332 dereferenceAsFreeVertex( vertexIndex );
1334 mVertexToFace[vertexIndex] = -1;
1336 int oldFacesCount = mMesh->faceCount();
1337 for (
int h = 0; h < holes.count(); ++h )
1339 const QList<int> &holeVertices = holes.at( h );
1340 const QList<int> &associateMeshFacesToHole = associateMeshFacesToHoles.at( h );
1341 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
1342 std::vector<p2t::Point *> holeToFill( holeVertices.count() );
1345 for (
int i = 0; i < holeVertices.count(); ++i )
1347 const QgsMeshVertex &vertex = mMesh->vertex( holeVertices.at( i ) );
1348 holeToFill[i] =
new p2t::Point( vertex.
x(), vertex.
y() );
1349 mapPoly2TriPointToVertex.insert( holeToFill[i], holeVertices.at( i ) );
1352 auto cdt = std::make_unique<p2t::CDT>( holeToFill );
1355 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
1356 QVector<QgsMeshFace> newFaces( triangles.size() );
1357 for (
size_t i = 0; i < triangles.size(); ++i )
1361 for (
int j = 0; j < 3; j++ )
1363 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
1364 if ( vertInd == -1 )
1365 throw std::exception();
1366 Q_ASSERT( !mMesh->vertices.at( vertInd ).isEmpty() );
1374 throw std::exception();
1375 int newFaceIndexStartIndex = mMesh->faceCount();
1382 const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
1383 for (
const int vtc : verticesToFaceToChange )
1384 if ( mVertexToFace.at( vtc ) == -1 )
1385 addChanges.
mVerticesToFaceChanges.append( { vtc, mVertexToFace.at( vtc ), addChanges.addedFaceIndexInMesh( topologicalFaces.mVerticesToFace.values( vtc ).first() ) } );
1389 for (
int i = 0; i < topologicalFaces.mFaces.count(); ++i )
1392 faceNeighbors = topologicalFaces.mFacesNeighborhood.at( i );
1393 for (
int n = 0; n < faceNeighbors.count(); ++n )
1395 if ( faceNeighbors.at( n ) != -1 )
1396 faceNeighbors[n] += newFaceIndexStartIndex;
1401 for (
int i = 0; i < holeVertices.count(); ++i )
1403 int vertexHoleIndex = holeVertices.at( i );
1404 int meshFaceBoundaryIndex = associateMeshFacesToHole.at( i );
1409 int newFaceBoundaryIndexInMesh = circulator.
currentFaceIndex() + newFaceIndexStartIndex;
1413 if ( meshFaceBoundaryIndex != -1 )
1415 const QgsMeshFace meshFace = mMesh->face( meshFaceBoundaryIndex );
1416 int positionInMeshFaceBoundary =
vertexPositionInFace( *mMesh, vertexHoleIndex, meshFaceBoundaryIndex );
1417 positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.count() ) % meshFace.count();
1419 addChanges.
mNeighborhoodChanges.append( { meshFaceBoundaryIndex, positionInMeshFaceBoundary, -1, newFaceBoundaryIndexInMesh } );
1430 for (
const std::array<int, 4> &neighborChangeToAdd : std::as_const( addChanges.
mNeighborhoodChanges ) )
1432 bool merged =
false;
1435 if ( existingNeighborChange.at( 0 ) == neighborChangeToAdd.at( 0 ) && existingNeighborChange.at( 1 ) == neighborChangeToAdd.at( 1 ) )
1438 Q_ASSERT( existingNeighborChange.at( 3 ) == neighborChangeToAdd.at( 2 ) );
1439 existingNeighborChange[3] = neighborChangeToAdd.at( 3 );
1446 for (
const std::array<int, 3> &verticesToFaceToAdd : std::as_const( addChanges.
mVerticesToFaceChanges ) )
1448 bool merged =
false;
1451 if ( existingVerticesToFace.at( 0 ) == verticesToFaceToAdd.at( 0 ) )
1454 Q_ASSERT( existingVerticesToFace.at( 2 ) == verticesToFaceToAdd.at( 1 ) );
1455 existingVerticesToFace[2] = verticesToFaceToAdd.at( 2 );
1462 qDeleteAll( holeToFill );
1466 qDeleteAll( holeToFill );
1480 QSet<int> facesIndex;
1482 for (
int vertexIndex : vertices )
1485 facesIndex.unite( QSet< int >( faces.begin(), faces.end() ) );
1492 for (
int vertexIndex : vertices )
1494 int currentVertexToFace = mVertexToFace.at( vertexIndex );
1500 dereferenceAsFreeVertex( vertexIndex );
1502 mVertexToFace[vertexIndex] = -1;
1510 QList<int> boundariesToCheckClockwiseInNewFaces = topologicFaces.mBoundaries;
1511 QList<std::array<int, 2>> boundariesToCheckCounterClockwiseInNewFaces;
1512 QList<int> uniqueSharedVertexBoundary;
1520 while ( !boundariesToCheckClockwiseInNewFaces.isEmpty() )
1522 int boundary = boundariesToCheckClockwiseInNewFaces.takeLast();
1524 const QList<int> &linkedFaces = topologicFaces.mVerticesToFace.values( boundary );
1526 for (
int const linkedFace : linkedFaces )
1529 if ( mVertexToFace.at( boundary ) == -1 )
1535 if ( !newFacescirculator.
isValid() )
1549 if ( oppositeVertexCCWInMesh == oppositeVertexInNewFaces )
1555 int faceSize = newFaceOnBoundary.size();
1557 int previousVertexIndex = ( posInNewFace + faceSize - 1 ) % faceSize;
1558 if ( newFaceOnBoundary.at( previousVertexIndex ) == oppositeVertexCCWInMesh )
1566 if ( oppositeVertexCWInMesh == oppositeVertexInNewFaces )
1570 boundariesToCheckCounterClockwiseInNewFaces.append( { boundary, linkedFace } );
1575 while ( !boundariesToCheckCounterClockwiseInNewFaces.isEmpty() )
1577 std::array<int, 2> boundaryLinkedface = boundariesToCheckCounterClockwiseInNewFaces.takeLast();
1578 int boundary = boundaryLinkedface.at( 0 );
1579 int linkedFace = boundaryLinkedface.at( 1 );
1594 if ( oppositeVertexCWInMesh == oppositeVertexInNewFaces )
1601 if ( oppositeVertexCCWInMesh == oppositeVertexInNewFaces )
1604 uniqueSharedVertexBoundary.append( boundary );
1607 if ( !uniqueSharedVertexBoundary.isEmpty() )
1611 QSet<int> boundaryVertices( topologicFaces.mBoundaries.constBegin(), topologicFaces.mBoundaries.constEnd() );
1612 for (
const QgsMeshFace &newFace : std::as_const( topologicFaces.mFaces ) )
1614 for (
const int vertexIndex : newFace )
1616 if ( boundaryVertices.contains( vertexIndex ) )
1618 if ( mVertexToFace.at( vertexIndex ) != -1 )
1629 mFacesNeighborhood.clear();
1630 mVerticesToFace.clear();
1631 mBoundaries.clear();
1636 return mFacesNeighborhood;
1641 if ( mVerticesToFace.contains( vertexIndex ) )
1642 return mVerticesToFace.values( vertexIndex ).at( 0 );
1650 topologicMesh.mMesh =
mesh;
1651 topologicMesh.mVertexToFace = QVector<int>(
mesh->vertexCount(), -1 );
1652 topologicMesh.mMaximumVerticesPerFace = maxVerticesPerFace;
1655 for (
int i = 0; i <
mesh->faceCount(); ++i )
1657 if (
mesh->face( i ).isEmpty() )
1659 if ( maxVerticesPerFace != 0 &&
mesh->face( i ).count() > maxVerticesPerFace )
1676 TopologicalFaces subMesh = createTopologicalFaces(
mesh->faces, &topologicMesh.mVertexToFace, error,
false );
1677 topologicMesh.mFacesNeighborhood = subMesh.mFacesNeighborhood;
1679 for (
int i = 0; i < topologicMesh.mMesh->
vertexCount(); ++i )
1681 if ( topologicMesh.mVertexToFace.at( i ) == -1 )
1682 topologicMesh.mFreeVertices.insert( i );
1686 return topologicMesh;
1691 return createTopologicalFaces( faces,
nullptr, error, uniqueSharedVertexAllowed );
1697 int facesCount = faces.count();
1698 QVector<FaceNeighbors> faceTopologies;
1699 QMultiHash<int, int> verticesToFace;
1702 TopologicalFaces ret;
1706 QMap<int, QMap<int, int>> verticesToNeighbor;
1708 for (
int faceIndex = 0; faceIndex < facesCount; ++faceIndex )
1711 int faceSize = face.count();
1713 for (
int i = 0; i < faceSize; ++i )
1715 int v1 = face[i % faceSize];
1716 int v2 = face[( i + 1 ) % faceSize];
1717 if ( verticesToNeighbor[v2].contains( v1 ) )
1723 verticesToNeighbor[v2].insert( v1, faceIndex );
1727 faceTopologies = QVector<FaceNeighbors>( faces.count() );
1729 QSet<int> boundaryVertices;
1731 for (
int faceIndex = 0; faceIndex < facesCount; ++faceIndex )
1734 int faceSize = face.size();
1736 faceTopology.resize( faceSize );
1738 for (
int i = 0; i < faceSize; ++i )
1740 int v1 = face.at( i );
1741 int v2 = face.at( ( i + 1 ) % faceSize );
1743 if ( globalVertexToFace )
1745 if ( ( *globalVertexToFace )[v1] == -1 )
1746 ( *globalVertexToFace )[v1] = faceIndex;
1750 if ( allowUniqueSharedVertex || !verticesToFace.contains( v1 ) )
1751 verticesToFace.insert( v1, faceIndex );
1754 QMap<int, int> &edges = verticesToNeighbor[v1];
1755 if ( edges.contains( v2 ) )
1756 faceTopology[i] = edges.value( v2 );
1759 faceTopology[i] = -1;
1761 if ( !allowUniqueSharedVertex )
1763 if ( boundaryVertices.contains( v1 ) )
1769 boundaryVertices.insert( v1 );
1775 ret.mFacesNeighborhood = faceTopologies;
1776 ret.mBoundaries = boundaryVertices.values();
1777 ret.mVerticesToFace = verticesToFace;
1783 return mFacesNeighborhood.at( faceIndex );
1795 QSet<int> removedFaces( facesIndexes.begin(), facesIndexes.end() );
1796 QSet<int> concernedFaces = concernedFacesBy( facesIndexes );
1798 for (
const int f : std::as_const( removedFaces ) )
1799 concernedFaces.remove( f );
1801 QVector<QgsMeshFace> remainingFaces;
1802 remainingFaces.reserve( concernedFaces.count() );
1803 for (
const int f : std::as_const( concernedFaces ) )
1804 remainingFaces.append( mMesh->face( f ) );
1807 createTopologicalFaces( remainingFaces,
nullptr, error,
false );
1819 QSet<int> indexSet( facesIndexesToRemove.begin(), facesIndexesToRemove.end() );
1820 QSet<int> threatedVertex;
1822 for (
int i = 0; i < facesIndexesToRemove.count(); ++i )
1824 const int faceIndex = facesIndexesToRemove.at( i );
1825 const QgsMeshFace &face = mMesh->face( faceIndex );
1827 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( faceIndex );
1829 for (
int j = 0; j < face.count(); ++j )
1832 int neighborIndex = neighborhood.at( j );
1833 if ( neighborIndex != -1 && !indexSet.contains( neighborIndex ) )
1835 int positionInNeighbor = mFacesNeighborhood.at( neighborIndex ).indexOf( faceIndex );
1840 int vertexIndex = face.at( j );
1841 if ( !threatedVertex.contains( vertexIndex ) && indexSet.contains( mVertexToFace.at( vertexIndex ) ) )
1843 int oldValue = mVertexToFace.at( vertexIndex );
1846 if ( neighborIndex != -1 && !indexSet.contains( neighborIndex ) )
1847 refValue = neighborIndex;
1851 aroundFaces.removeOne( faceIndex );
1852 if ( !aroundFaces.isEmpty() )
1854 while ( !aroundFaces.isEmpty() && refValue == -1 )
1856 if ( !indexSet.contains( aroundFaces.first() ) )
1857 refValue = aroundFaces.first();
1859 aroundFaces.removeFirst();
1864 threatedVertex.insert( vertexIndex );
1874bool QgsTopologicalMesh::eitherSideFacesAndVertices(
1875 int vertexIndex1,
int vertexIndex2,
int &face1,
int &face2,
int &neighborVertex1InFace1,
int &neighborVertex1InFace2,
int &neighborVertex2inFace1,
int &neighborVertex2inFace2
1917 int oppositeVertexFace1;
1918 int oppositeVertexFace2;
1919 int supposedOppositeVertexFace1;
1920 int supposedoppositeVertexFace2;
1922 bool result = eitherSideFacesAndVertices( vertexIndex1, vertexIndex2, faceIndex1, faceIndex2, oppositeVertexFace1, supposedoppositeVertexFace2, supposedOppositeVertexFace1, oppositeVertexFace2 );
1924 if ( !result || faceIndex1 < 0 || faceIndex2 < 0 || oppositeVertexFace1 < 0 || oppositeVertexFace2 < 0 || supposedOppositeVertexFace1 != oppositeVertexFace1 || supposedoppositeVertexFace2 != oppositeVertexFace2 )
1927 const QgsMeshFace &face1 = mMesh->face( faceIndex1 );
1928 const QgsMeshFace &face2 = mMesh->face( faceIndex2 );
1931 if ( face1.count() != 3 || face2.count() != 3 )
1934 double crossProduct1 = crossProduct( vertexIndex1, oppositeVertexFace1, oppositeVertexFace2, *mMesh );
1935 double crossProduct2 = crossProduct( vertexIndex2, oppositeVertexFace1, oppositeVertexFace2, *mMesh );
1937 return crossProduct1 * crossProduct2 < 0;
1944 int oppositeVertexFace1;
1945 int oppositeVertexFace2;
1946 int supposedOppositeVertexFace1;
1947 int supposedoppositeVertexFace2;
1949 bool result = eitherSideFacesAndVertices( vertexIndex1, vertexIndex2, faceIndex1, faceIndex2, oppositeVertexFace1, supposedoppositeVertexFace2, supposedOppositeVertexFace1, oppositeVertexFace2 );
1951 if ( !result || faceIndex1 < 0 || faceIndex2 < 0 || oppositeVertexFace1 < 0 || oppositeVertexFace2 < 0 || supposedOppositeVertexFace1 != oppositeVertexFace1 || supposedoppositeVertexFace2 != oppositeVertexFace2 )
1957 const QgsMeshFace &face1 = mMesh->face( faceIndex1 );
1958 const QgsMeshFace &face2 = mMesh->face( faceIndex2 );
1960 Q_ASSERT( face1.count() == 3 );
1961 Q_ASSERT( face2.count() == 3 );
1966 int neighborFace1 = mFacesNeighborhood.at( faceIndex1 ).at( pos1 );
1968 int neighborFace2 = mFacesNeighborhood.at( faceIndex1 ).at( ( pos1 + 1 ) % 3 );
1970 int neighborFace3 = mFacesNeighborhood.at( faceIndex2 ).at( pos2 );
1972 int neighborFace4 = mFacesNeighborhood.at( faceIndex2 ).at( ( pos2 + 1 ) % 3 );
1981 int startIndex = mMesh->faceCount();
1983 changes.
mFacesToAdd.append( { oppositeVertexFace1, oppositeVertexFace2, vertexIndex1 } );
1984 changes.
mFacesToAdd.append( { oppositeVertexFace2, oppositeVertexFace1, vertexIndex2 } );
1985 changes.
mFacesNeighborhoodToAdd.append( { startIndex + 1, mFacesNeighborhood.at( faceIndex2 ).at( ( pos2 + 1 ) % 3 ), mFacesNeighborhood.at( faceIndex1 ).at( pos1 ) } );
1986 changes.
mFacesNeighborhoodToAdd.append( { startIndex, mFacesNeighborhood.at( faceIndex1 ).at( ( pos1 + 1 ) % 3 ), mFacesNeighborhood.at( faceIndex2 ).at( pos2 ) } );
1988 if ( neighborFace1 >= 0 )
1989 changes.
mNeighborhoodChanges.append( { neighborFace1, posInNeighbor1, faceIndex1, startIndex } );
1990 if ( neighborFace2 >= 0 )
1991 changes.
mNeighborhoodChanges.append( { neighborFace2, posInNeighbor2, faceIndex1, startIndex + 1 } );
1992 if ( neighborFace3 >= 0 )
1993 changes.
mNeighborhoodChanges.append( { neighborFace3, posInNeighbor3, faceIndex2, startIndex + 1 } );
1994 if ( neighborFace4 >= 0 )
1995 changes.
mNeighborhoodChanges.append( { neighborFace4, posInNeighbor4, faceIndex2, startIndex } );
1998 if ( mVertexToFace.at( vertexIndex1 ) == faceIndex1 || mVertexToFace.at( vertexIndex1 ) == faceIndex2 )
2000 if ( mVertexToFace.at( vertexIndex2 ) == faceIndex1 || mVertexToFace.at( vertexIndex2 ) == faceIndex2 )
2001 changes.
mVerticesToFaceChanges.append( { vertexIndex2, mVertexToFace.at( vertexIndex2 ), startIndex + 1 } );
2003 if ( mVertexToFace.at( oppositeVertexFace1 ) == faceIndex1 )
2006 if ( mVertexToFace.at( oppositeVertexFace2 ) == faceIndex2 )
2018 int neighborVertex1InFace1;
2019 int neighborVertex1InFace2;
2020 int neighborVertex2inFace1;
2021 int neighborVertex2inFace2;
2023 bool result = eitherSideFacesAndVertices( vertexIndex1, vertexIndex2, faceIndex1, faceIndex2, neighborVertex1InFace1, neighborVertex1InFace2, neighborVertex2inFace1, neighborVertex2inFace2 );
2025 if ( !result || faceIndex1 < 0 || faceIndex2 < 0 )
2028 const QgsMeshFace &face1 = mMesh->face( faceIndex1 );
2029 const QgsMeshFace &face2 = mMesh->face( faceIndex2 );
2031 if ( face1.count() + face2.count() - 2 > mMaximumVerticesPerFace )
2036 QgsMeshVertex nv11 = mMesh->vertices.at( neighborVertex1InFace1 );
2037 QgsMeshVertex nv12 = mMesh->vertices.at( neighborVertex1InFace2 );
2038 QgsMeshVertex nv21 = mMesh->vertices.at( neighborVertex2inFace1 );
2039 QgsMeshVertex nv22 = mMesh->vertices.at( neighborVertex2inFace2 );
2041 double crossProduct1 = crossProduct( vertexIndex1, neighborVertex1InFace1, neighborVertex1InFace2, *mMesh );
2042 double crossProduct2 = crossProduct( vertexIndex2, neighborVertex2inFace1, neighborVertex2inFace2, *mMesh );
2044 return crossProduct1 * crossProduct2 < 0;
2051 int neighborVertex1InFace1;
2052 int neighborVertex1InFace2;
2053 int neighborVertex2inFace1;
2054 int neighborVertex2inFace2;
2056 bool result = eitherSideFacesAndVertices( vertexIndex1, vertexIndex2, faceIndex1, faceIndex2, neighborVertex1InFace1, neighborVertex1InFace2, neighborVertex2inFace1, neighborVertex2inFace2 );
2058 if ( !result || faceIndex1 < 0 || faceIndex2 < 0 )
2063 const QgsMeshFace &face1 = mMesh->face( faceIndex1 );
2064 const QgsMeshFace &face2 = mMesh->face( faceIndex2 );
2065 int faceSize1 = face1.count();
2066 int faceSize2 = face2.count();
2077 int startIndex = mMesh->faceCount();
2082 for (
int i = 0; i < faceSize1 - 1; ++i )
2084 int currentPos = ( pos1 + i ) % faceSize1;
2085 newface.append( face1.at( currentPos ) );
2087 int currentNeighbor = mFacesNeighborhood.at( faceIndex1 ).at( currentPos );
2088 newNeighborhood.append( currentNeighbor );
2090 if ( currentNeighbor != -1 )
2093 changes.
mNeighborhoodChanges.append( { currentNeighbor, currentPosInNeighbor, faceIndex1, startIndex } );
2096 for (
int i = 0; i < faceSize2 - 1; ++i )
2098 int currentPos = ( pos2 + i ) % faceSize2;
2099 newface.append( face2.at( currentPos ) );
2101 int currentNeighbor = mFacesNeighborhood.at( faceIndex2 ).at( currentPos );
2102 newNeighborhood.append( currentNeighbor );
2104 if ( currentNeighbor != -1 )
2107 changes.
mNeighborhoodChanges.append( { currentNeighbor, currentPosInNeighbor, faceIndex2, startIndex } );
2111 for (
int i = 0; i < faceSize1; ++i )
2112 if ( mVertexToFace.at( face1.at( i ) ) == faceIndex1 )
2115 for (
int i = 0; i < faceSize2; ++i )
2116 if ( mVertexToFace.at( face2.at( i ) ) == faceIndex2 )
2129 const QgsMeshFace face = mMesh->face( faceIndex );
2131 return face.count() == 4;
2137 const QgsMeshFace &face = mMesh->face( faceIndex );
2138 int faceSize = face.count();
2140 Q_ASSERT( faceSize == 4 );
2142 double maxAngle = 0;
2143 int splitVertexPos = -1;
2144 for (
int i = 0; i < faceSize; ++i )
2146 QgsVector vect1( mMesh->vertex( face.at( i ) ) - mMesh->vertex( face.at( ( i + 1 ) % faceSize ) ) );
2147 QgsVector vect2( mMesh->vertex( face.at( ( i + 2 ) % faceSize ) ) - mMesh->vertex( face.at( ( i + 1 ) % faceSize ) ) );
2149 double angle = std::abs( vect1.
angle( vect2 ) );
2150 angle = std::min( angle, 2.0 * M_PI - angle );
2151 if ( angle > maxAngle )
2154 splitVertexPos = ( i + 1 ) % faceSize;
2159 if ( splitVertexPos == -1 )
2162 const QgsMeshFace newFace1 = { face.at( splitVertexPos ), face.at( ( splitVertexPos + 1 ) % faceSize ), face.at( ( splitVertexPos + 2 ) % faceSize ) };
2164 const QgsMeshFace newFace2 = { face.at( splitVertexPos ), face.at( ( splitVertexPos + 2 ) % faceSize ), face.at( ( splitVertexPos + 3 ) % faceSize ) };
2166 QVector<int> neighborIndex( faceSize );
2167 QVector<int> posInNeighbor( faceSize );
2169 for (
int i = 0; i < faceSize; ++i )
2171 neighborIndex[i] = mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + i ) % faceSize );
2178 int startIndex = mMesh->faceCount();
2183 changes.
mFacesNeighborhoodToAdd.append( { mFacesNeighborhood.at( faceIndex ).at( splitVertexPos ), mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 1 ) % faceSize ), startIndex + 1 } );
2185 { startIndex, mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 2 ) % faceSize ), mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 3 ) % faceSize ) }
2188 for (
int i = 0; i < faceSize; ++i )
2190 if ( neighborIndex[i] >= 0 )
2191 changes.
mNeighborhoodChanges.append( { neighborIndex[i], posInNeighbor[i], faceIndex, startIndex + int( i / 2 ) } );
2193 int vertexIndex = face.at( ( splitVertexPos + i ) % faceSize );
2194 if ( mVertexToFace.at( vertexIndex ) == faceIndex )
2210 mMesh->vertices.append( vertex );
2211 mVertexToFace.append( -1 );
2214 const QgsMeshFace includingFace = mMesh->face( includingFaceIndex );
2215 const FaceNeighbors includingFaceNeighborhood = mFacesNeighborhood.at( includingFaceIndex );
2216 int includingFaceSize = includingFace.count();
2218 for (
int i = 0; i < includingFaceSize; ++i )
2222 face[0] = mMesh->vertexCount() - 1;
2223 face[1] = includingFace.at( i );
2224 face[2] = includingFace.at( ( i + 1 ) % includingFaceSize );
2225 mMesh->faces.append( face );
2228 int currentVertexIndex = includingFace.at( i );
2229 if ( mVertexToFace.at( currentVertexIndex ) == includingFaceIndex )
2231 int newFaceIndex = mMesh->faceCount() - 1;
2232 mVertexToFace[currentVertexIndex] = newFaceIndex;
2236 int includingFaceNeighbor = includingFaceNeighborhood.at( i );
2240 mFacesNeighborhood.append( neighbors );
2243 if ( includingFaceNeighbor != -1 )
2246 int oldValue = mFacesNeighborhood[includingFaceNeighbor][indexInNeighbor];
2258 mVertexToFace[mVertexToFace.count() - 1] = mMesh->faceCount() - 1;
2266 const QgsMeshFace face1 = mMesh->face( faceIndex );
2273 int newVertexPositionInFace1 = position + 1;
2275 auto triangulate = [
this, &changes](
int removedFaceIndex,
const QgsMeshVertex &newVertex,
int newVertexPosition, QVector<int> &edgeFacesIndexes ) ->
bool {
2276 const QgsMeshFace &initialFace = mMesh->face( removedFaceIndex );
2280 const int addedVertexIndex = mMesh->vertexCount();
2282 int faceStartGlobalIndex = mMesh->faceCount() + changes.
mFacesToAdd.count();
2283 int localStartIndex = changes.
mFacesToAdd.count();
2285 QVector<int> newBoundary = initialFace;
2286 newBoundary.insert( newVertexPosition, addedVertexIndex );
2290 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
2291 std::vector<p2t::Point *> faceToFill( newBoundary.count() );
2292 for (
int i = 0; i < newBoundary.count(); ++i )
2296 if ( newBoundary.at( i ) == addedVertexIndex )
2299 vert = mMesh->vertex( newBoundary.at( i ) );
2301 faceToFill[i] =
new p2t::Point( vert.
x(), vert.
y() );
2302 mapPoly2TriPointToVertex.insert( faceToFill[i], newBoundary.at( i ) );
2305 auto cdt = std::make_unique<p2t::CDT>( faceToFill );
2307 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
2308 QVector<QgsMeshFace> newFaces( triangles.size() );
2309 for (
size_t i = 0; i < triangles.size(); ++i )
2313 for (
int j = 0; j < 3; j++ )
2315 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
2316 if ( vertInd == -1 )
2317 throw std::exception();
2325 throw std::exception();
2331 const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
2332 for (
const int vtc : verticesToFaceToChange )
2333 if ( vtc != addedVertexIndex && mVertexToFace.at( vtc ) == removedFaceIndex )
2337 for (
int i = 0; i < topologicalFaces.mFaces.count(); ++i )
2340 for (
int n = 0; n < faceNeighbors.count(); ++n )
2342 if ( faceNeighbors.at( n ) != -1 )
2343 faceNeighbors[n] += faceStartGlobalIndex;
2347 edgeFacesIndexes.resize( 2 );
2349 for (
int i = 0; i < newBoundary.count(); ++i )
2351 int vertexIndex = newBoundary.at( i );
2354 int newFaceBoundaryLocalIndex = localStartIndex + circulator.
currentFaceIndex();
2356 int newFaceBoundaryIndexInMesh = faceStartGlobalIndex;
2358 int meshFaceBoundaryIndex;
2359 if ( i == newVertexPosition )
2361 meshFaceBoundaryIndex = -1;
2362 edgeFacesIndexes[0] = newFaceBoundaryLocalIndex;
2364 else if ( i == ( newVertexPosition + newBoundary.count() - 1 ) % newBoundary.count() )
2366 meshFaceBoundaryIndex = -1;
2367 edgeFacesIndexes[1] = newFaceBoundaryLocalIndex;
2375 if ( meshFaceBoundaryIndex != -1 )
2377 const QgsMeshFace meshFace = mMesh->face( meshFaceBoundaryIndex );
2379 positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.count() ) % meshFace.count();
2387 qDeleteAll( faceToFill );
2397 QVector<int> edgeFacesIndexes;
2398 if ( !triangulate( faceIndex, vertexToInsert, newVertexPositionInFace1, edgeFacesIndexes ) )
2403 int addedVertexIndex = mMesh->vertexCount();
2406 int face2Index = mFacesNeighborhood.at( faceIndex ).at( position );
2407 if ( face2Index != -1 )
2409 const QgsMeshFace &face2 = mMesh->face( face2Index );
2411 QVector<int> edgeFacesIndexesFace2;
2412 if ( !triangulate( face2Index, vertexToInsert, vertexPositionInFace2, edgeFacesIndexesFace2 ) )
2421 pos2InFaceSide1 = ( pos2InFaceSide1 + secondFaceSide1.size() - 1 ) % secondFaceSide1.size();
2428 pos2InFaceSide2 = ( pos2InFaceSide2 + secondFaceSide1.size() - 1 ) % secondFaceSide1.size();
2442 Q_ASSERT( verticesIndexes.count() == newValues.count() );
2445 changes.
mNewZValues.reserve( verticesIndexes.count() );
2446 changes.
mOldZValues.reserve( verticesIndexes.count() );
2447 for (
int i = 0; i < verticesIndexes.count(); ++i )
2450 changes.
mOldZValues.append( mMesh->vertices.at( verticesIndexes.at( i ) ).z() );
2461 Q_ASSERT( verticesIndexes.count() == newValues.count() );
2464 changes.
mNewXYValues.reserve( verticesIndexes.count() );
2465 changes.
mOldXYValues.reserve( verticesIndexes.count() );
2466 QSet<int> concernedFace;
2467 for (
int i = 0; i < verticesIndexes.count(); ++i )
2470 changes.
mOldXYValues.append( mMesh->vertices.at( verticesIndexes.at( i ) ) );
2473 concernedFace.unite( QSet< int>( faces.begin(), faces.end() ) );
2487 int oppositeVertexFace1;
2488 int oppositeVertexFace2;
2489 int supposedOppositeVertexFace1;
2490 int supposedoppositeVertexFace2;
2492 bool result = eitherSideFacesAndVertices( vertexIndex1, vertexIndex2, faceIndex1, faceIndex2, oppositeVertexFace1, supposedoppositeVertexFace2, supposedOppositeVertexFace1, oppositeVertexFace2 );
2497 const QgsMeshFace face1 = mMesh->face( faceIndex1 );
2498 const QgsMeshFace face2 = mMesh->face( faceIndex2 );
2501 bool circle1ContainsPoint = circle.
contains( mMesh->vertex( supposedoppositeVertexFace2 ) );
2503 circle =
QgsCircle::from3Points( mMesh->vertex( face2.at( 0 ) ), mMesh->vertex( face2.at( 1 ) ), mMesh->vertex( face2.at( 2 ) ) );
2504 bool circle2ContainsPoint = circle.
contains( mMesh->vertex( supposedOppositeVertexFace1 ) );
2506 return !( circle1ContainsPoint || circle2ContainsPoint );
@ 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.
bool contains(const QgsPoint &point, double epsilon=1E-8) const
Returns true if the circle contains the point.
static QgsCircle from3Points(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double epsilon=1E-8)
Constructs a circle by 3 points on the circle.
static bool segmentIntersection(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q1, const QgsPoint &q2, QgsPoint &intersectionPoint, bool &isIntersection, double tolerance=1e-8, bool acceptImproperIntersection=false)
Compute the intersection between two segments.
Represents an error which occurred during mesh editing.
Qgis::MeshEditingErrorType errorType
Convenience class that turns around a vertex and provides 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, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
Point geometry type, with support for z-dimension and m-values.
bool isEmpty() const override
Returns true if the geometry is empty.
Contains topological differences between two states of a topological mesh, only accessible from the Q...
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.
Contains independent faces and topological information about these 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.
Wraps a QgsMesh to ensure the consistency of the mesh during editing and helps to access elements fro...
static QgsMeshEditingError checkTopologyOfVerticesAsFace(const QVector< QgsMeshVertex > &vertices, bool &clockwise)
Checks the topology of the vertices as they are contained in a face and returns indication on directi...
Changes changeZValue(const QList< int > &verticesIndexes, const QList< double > &newValues)
Changes the Z values of the vertices with indexes in vertices indexes with the values in newValues.
static QgsTopologicalMesh createTopologicalMesh(QgsMesh *mesh, int maxVerticesPerFace, QgsMeshEditingError &error)
Creates a topologicaly consistent mesh with mesh, this static method modifies mesh to be topological ...
bool isVertexFree(int vertexIndex) const
Returns whether the vertex is a free vertex.
static QgsMeshEditingError counterClockwiseFaces(QgsMeshFace &face, QgsMesh *mesh)
Checks the topology of the face and sets it counter clockwise if necessary.
Changes removeVertexFillHole(int vertexIndex)
Removes the vertex with index vertexIndex.
static int vertexPositionInFace(int vertexIndex, const QgsMeshFace &face)
Returns vertex position in face.
static QgsMeshEditingError checkTopology(const QgsMesh &mesh, int maxVerticesPerFace)
Checks the topology of the mesh mesh, if error occurs, this mesh can't be edited.
friend class QgsMeshVertexCirculator
void applyChanges(const Changes &changes)
Applies the changes.
int firstFaceLinked(int vertexIndex) const
Returns the index of the first face linked, returns -1 if it is a free vertex or out of range index.
QgsMeshEditingError checkConsistency() const
Checks the consistency of the topological mesh and return false if there is a consistency issue.
Changes removeVertices(const QList< int > &vertices)
Removes all the vertices with index in the list vertices If vertices in linked with faces,...
Changes changeXYValue(const QList< int > &verticesIndexes, const QList< QgsPointXY > &newValues)
Changes the (X,Y) values of the vertices with indexes in vertices indexes with the values in newValue...
void reindex()
Reindexes faces and vertices, after this operation, the topological mesh can't be edited anymore and ...
QVector< int > neighborsOfFace(int faceIndex) const
Returns the indexes of neighbor faces of the face with index faceIndex.
QgsMeshEditingError facesCanBeAdded(const TopologicalFaces &topologicalFaces) const
Returns whether the faces can be added to the mesh.
bool renumber()
Renumbers the indexes of vertices and faces using the Reverse CutHill McKee Algorithm.
Changes flipEdge(int vertexIndex1, int vertexIndex2)
Flips edge (vertexIndex1, vertexIndex2) The method returns a instance of the class QgsTopologicalMesh...
QgsMeshEditingError facesCanBeRemoved(const QList< int > &facesIndexes)
Returns whether faces with index in faceIndexes can be removed/ The method an error object with type ...
QVector< int > FaceNeighbors
void reverseChanges(const Changes &changes)
Reverses the changes.
Changes addFaces(const TopologicalFaces &topologicFaces)
Adds faces topologicFaces to the topologic mesh.
Changes merge(int vertexIndex1, int vertexIndex2)
Merges faces separated by vertices with indexes vertexIndex1 and vertexIndex2 The method returns a in...
Changes removeFaces(const QList< int > &facesIndexes)
Removes faces with index in faceIndexes.
QList< int > freeVerticesIndexes() const
Returns a list of vertices are not linked to any faces.
bool edgeCanBeFlipped(int vertexIndex1, int vertexIndex2) const
Returns true if the edge can be flipped (only available for edge shared by two faces with 3 vertices)...
Changes addVertexInFace(int faceIndex, const QgsMeshVertex &vertex)
Adds a vertex in the face with index faceIndex.
bool canBeMerged(int vertexIndex1, int vertexIndex2) const
Returns true if faces separated by vertices with indexes vertexIndex1 and vertexIndex2 can be merged.
QList< int > facesAroundVertex(int vertexIndex) const
Returns the indexes of faces that are around the vertex with index vertexIndex.
bool canBeSplit(int faceIndex) const
Returns true if face with index faceIndex can be split.
Changes addFreeVertex(const QgsMeshVertex &vertex)
Adds a free vertex in the face, that is a vertex that is not included or linked with any faces.
Changes insertVertexInFacesEdge(int faceIndex, int position, const QgsMeshVertex &vertex)
Inserts a vertex in the edge of face with index faceIndex at position .
QgsMesh * mesh() const
Returns a pointer to the wrapped mesh.
bool isVertexOnBoundary(int vertexIndex) const
Returns whether the vertex is on a boundary.
Changes splitFace(int faceIndex)
Splits face with index faceIndex The method returns a instance of the class QgsTopologicalMesh::Chang...
static TopologicalFaces createNewTopologicalFaces(const QVector< QgsMeshFace > &faces, bool uniqueSharedVertexAllowed, QgsMeshEditingError &error)
Creates new topological faces that are not yet included in the mesh.
QgsMeshVertexCirculator vertexCirculator(int vertexIndex) const
Returns a vertex circulator linked to this mesh around the vertex with index vertexIndex.
bool delaunayConditionForEdge(int vertexIndex1, int vertexIndex2)
Check if Delaunay condition holds for given edge returns true if delaunay condition holds false other...
Represent a 2-dimensional vector.
double angle() const
Returns the angle of the vector in radians.
QVector< int > QgsMeshFace
List of vertex indexes.
QgsPoint QgsMeshVertex
xyz coords of vertex
Mesh - vertices, edges and faces.
int vertexCount() const
Returns number of vertices.
QVector< QgsMeshVertex > vertices
QgsMeshFace face(int index) const
Returns a face at the index.