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;
160 if ( mCurrentFace == firstFace )
171 if ( mCurrentFace == -1 )
172 mCurrentFace = mLastValidFace;
174 int firstFace = mCurrentFace;
177 if ( mCurrentFace == firstFace )
185 if ( mCurrentFace == -1 )
190 if ( face.isEmpty() )
195 if ( vertexPosition == -1 )
198 return face.at( ( vertexPosition + 1 ) % face.count() );
203 if ( mCurrentFace == -1 )
208 if ( face.isEmpty() )
213 if ( vertexPosition == -1 )
216 return face.at( ( vertexPosition - 1 + face.count() ) % face.count() );
230 if ( mCurrentFace != -1 )
231 ret.append( mCurrentFace );
276int QgsMeshVertexCirculator::positionInCurrentFace()
const
278 if ( mCurrentFace < 0 || mCurrentFace >= mFaces.count() )
291 for (
int i = 0; i < changes.
mFacesToAdd.count(); ++i )
294 for (
int boundary : topologicalFaces.mBoundaries )
297 if ( mVertexToFace.at( boundary ) == -1 )
300 const QList<int> &linkedFaces = topologicalFaces.mVerticesToFace.values( boundary );
301 for (
int linkedFace : linkedFaces )
307 if ( mVertexToFace.at( oppositeVertexForNewFace ) == -1 )
317 if ( oppositeVertexForMeshFace != oppositeVertexForNewFace )
329 boundaryPositionInMeshFace,
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 )
348 mVertexToFace.at( vtc ),
349 changes.addedFaceIndexInMesh( topologicalFaces.mVerticesToFace.values( vtc ).first() )
359 int initialVerticesCount = mMesh->vertices.count();
362 int newSize = mMesh->vertices.count() + changes.
mVerticesToAdd.count();
363 mMesh->vertices.resize( newSize );
364 mVertexToFace.resize( newSize );
369 int newSize = mMesh->faceCount() + changes.
mFacesToAdd.count();
370 mMesh->faces.resize( newSize );
371 mFacesNeighborhood.resize( newSize );
376 mMesh->faces[changes.removedFaceIndexInMesh( i )] =
QgsMeshFace();
377 mFacesNeighborhood[changes.removedFaceIndexInMesh( i )] =
FaceNeighbors();
383 if ( mVertexToFace.at( vertexIndex ) == -1 )
384 dereferenceAsFreeVertex( vertexIndex );
386 mVertexToFace[vertexIndex] = -1;
391 mMesh->vertices[initialVerticesCount + i] = changes.
mVerticesToAdd.at( i );
394 referenceAsFreeVertex( initialVerticesCount + i );
397 for (
int i = 0; i < changes.
mFacesToAdd.count(); ++i )
399 mMesh->faces[changes.addedFaceIndexInMesh( i )] = changes.
mFacesToAdd.at( i );
405 const int faceIndex = neighborChange.at( 0 );
406 const int positionInFace = neighborChange.at( 1 );
407 const int valueToApply = neighborChange.at( 3 );
408 mFacesNeighborhood[faceIndex][positionInFace] = valueToApply;
413 int vertexIndex = vertexToFaceChange.at( 0 );
414 mVertexToFace[vertexToFaceChange.at( 0 )] = vertexToFaceChange.at( 2 );
416 if ( vertexToFaceChange.at( 2 ) == -1 &&
417 vertexToFaceChange.at( 1 ) != -1 &&
418 !mMesh->vertices.at( vertexIndex ).isEmpty() )
419 referenceAsFreeVertex( vertexIndex );
421 if ( vertexToFaceChange.at( 1 ) == -1 && vertexToFaceChange.at( 2 ) != -1 )
422 dereferenceAsFreeVertex( vertexIndex );
429 mMesh->vertices[vertexIndex].setZ( changes.
mNewZValues.at( i ) );
433 mMesh->vertices[vertexIndex].setX( pt.
x() );
434 mMesh->vertices[vertexIndex].setY( pt.
y() );
443 const int faceIndex = neighborChange.at( 0 );
444 const int positionInFace = neighborChange.at( 1 );
445 const int valueToApply = neighborChange.at( 2 );
446 mFacesNeighborhood[faceIndex][positionInFace] = valueToApply;
451 mMesh->faces[changes.removedFaceIndexInMesh( i )] = changes.
mFacesToRemove.at( i );
460 if ( mVertexToFace.at( vertexIndex ) == -1 )
461 referenceAsFreeVertex( vertexIndex );
465 for (
int i = 0; i < verticesToFaceChangesCount; ++i )
467 const std::array<int, 3> vertexToFaceChange = changes.
mVerticesToFaceChanges.at( verticesToFaceChangesCount - i - 1 );
468 int vertexIndex = vertexToFaceChange.at( 0 );
469 mVertexToFace[vertexIndex] = vertexToFaceChange.at( 1 );
471 if ( vertexToFaceChange.at( 2 ) == -1 && vertexToFaceChange.at( 1 ) != -1 )
472 dereferenceAsFreeVertex( vertexIndex );
474 if ( vertexToFaceChange.at( 1 ) == -1 &&
475 vertexToFaceChange.at( 2 ) != -1 &&
476 !mMesh->vertex( vertexIndex ).isEmpty() )
477 referenceAsFreeVertex( vertexIndex );
482 int newSize = mMesh->faceCount() - changes.
mFacesToAdd.count();
483 mMesh->faces.resize( newSize );
484 mFacesNeighborhood.resize( newSize );
489 int newSize = mMesh->vertexCount() - changes.
mVerticesToAdd.count();
491 for (
int i = newSize; i < mMesh->vertexCount(); ++i )
492 if ( mVertexToFace.at( i ) == -1 )
493 dereferenceAsFreeVertex( i );
495 mMesh->vertices.resize( newSize );
496 mVertexToFace.resize( newSize );
503 mMesh->vertices[vertexIndex].setZ( changes.
mOldZValues.at( i ) );
507 mMesh->vertices[vertexIndex].setX( pt.
x() );
508 mMesh->vertices[vertexIndex].setY( pt.
y() );
518QSet<int> QgsTopologicalMesh::concernedFacesBy(
const QList<int> &faceIndexes )
const
521 for (
const int faceIndex : faceIndexes )
524 for (
int i = 0; i < face.count(); ++i )
527 faces.unite( QSet< int >( around.begin(), around.end() ) );
533void QgsTopologicalMesh::dereferenceAsFreeVertex(
int vertexIndex )
535 mFreeVertices.remove( vertexIndex );
538void QgsTopologicalMesh::referenceAsFreeVertex(
int vertexIndex )
542 mFreeVertices.insert( vertexIndex );
547 for (
int faceIndex = 0 ; faceIndex < mMesh->faces.count( ); ++faceIndex )
549 const QgsMeshFace &face = mMesh->faces.at( faceIndex );
550 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( faceIndex );
551 if ( face.count() != neighborhood.count() )
553 for (
int i = 0; i < face.count(); ++i )
555 int vertexIndex = face.at( i );
557 if ( mVertexToFace.at( vertexIndex ) == -1 )
560 int neighborIndex = neighborhood.at( i );
561 if ( neighborIndex != -1 )
563 const QgsMeshFace &neighborFace = mMesh->faces.at( neighborIndex );
564 if ( neighborFace.isEmpty() )
566 int neighborSize = neighborFace.size();
567 const FaceNeighbors &neighborhoodOfNeighbor = mFacesNeighborhood.at( neighborIndex );
569 if ( neighborhoodOfNeighbor.isEmpty() || neighborhoodOfNeighbor.at( ( posInNeighbor + neighborSize - 1 ) % neighborSize ) != faceIndex )
575 for (
int vertexIndex = 0; vertexIndex < mMesh->vertexCount(); ++vertexIndex )
577 if ( mVertexToFace.at( vertexIndex ) != -1 )
579 if ( !mMesh->face( mVertexToFace.at( vertexIndex ) ).contains( vertexIndex ) )
605 if ( vertexIndex < 0 || vertexIndex >= mMesh->vertexCount() )
607 return mVertexToFace.at( vertexIndex );
622 if ( vertexIndex < 0 || vertexIndex >= mMesh->vertexCount() )
625 if ( mMesh->vertices.at( vertexIndex ).isEmpty() )
628 return mVertexToFace.at( vertexIndex ) == -1;
633 return QList<int>( mFreeVertices.begin(), mFreeVertices.end() );
638 int size = vertices.size();
640 for (
int i = 0; i < size; ++i )
643 int iv1 = ( i + 1 ) % size;
644 int iv2 = ( i + 2 ) % size;
659 double crossProd = crossProduct( v1, v0, v2 );
660 if ( direction != 0 && crossProd * direction < 0 )
662 clockwise = direction > 0;
665 else if ( crossProd == 0 )
667 clockwise = direction > 0;
670 else if ( direction == 0 )
671 direction = crossProd / std::fabs( crossProd );
674 clockwise = direction > 0;
683 int faceSize = face.count();
687 QVector<QgsMeshVertex> vertices( face.size() );
689 for (
int i = 0; i < faceSize; ++i )
692 if ( iv < 0 || iv >=
mesh->vertexCount() )
695 vertices[i] =
mesh->vertices.at( face[i] );
698 bool clockwise =
false;
705 for (
int i = 0; i < faceSize / 2; ++i )
708 face[i] = face.at( faceSize - i - 1 );
709 face[faceSize - i - 1] = temp;
718 QVector<int> oldToNewIndex( mMesh->vertices.count(), -1 );
719 int verticesTotalCount = mMesh->vertexCount();
722 while ( oldIndex < verticesTotalCount )
724 if ( mMesh->vertex( oldIndex ).isEmpty() )
730 oldToNewIndex[oldIndex] = newIndex;
731 if ( oldIndex != newIndex )
732 mMesh->vertices[newIndex] = mMesh->vertices[oldIndex];
733 oldToNewIndex[oldIndex] = newIndex;
739 mMesh->vertices.resize( newIndex );
743 int facesTotalCount = mMesh->faceCount();
744 while ( oldIndex < facesTotalCount )
746 if ( mMesh->face( oldIndex ).isEmpty() )
750 if ( oldIndex != newIndex )
751 mMesh->faces[newIndex] = mMesh->faces[oldIndex];
753 for (
int i = 0; i < face.count(); ++i )
754 face[i] = oldToNewIndex[face.at( i )];
760 mMesh->faces.resize( newIndex );
762 mVertexToFace.clear();
763 mFacesNeighborhood.clear();
768 QVector<int> oldToNewVerticesIndexes;
769 if ( !renumberVertices( oldToNewVerticesIndexes ) )
773 QVector<int> oldToNewFacesIndexes;
775 if ( !renumberFaces( oldToNewFacesIndexes ) )
780 QVector<QgsMeshVertex> tempVertices( mMesh->vertices.count() );
781 for (
int i = 0; i < oldToNewVerticesIndexes.count(); ++i )
783 tempVertices[oldToNewVerticesIndexes.at( i )] = mMesh->vertex( i );
785 mMesh->vertices = tempVertices;
787 QVector<QgsMeshFace> tempFaces( mMesh->faces.count() );
788 for (
int i = 0; i < oldToNewFacesIndexes.count(); ++i )
790 tempFaces[oldToNewFacesIndexes.at( i )] = mMesh->face( i );
792 QgsMeshFace &face = tempFaces[oldToNewFacesIndexes.at( i )];
794 for (
int fi = 0; fi < face.count(); ++fi )
796 face[fi] = oldToNewVerticesIndexes.at( face.at( fi ) );
800 mMesh->faces = tempFaces;
806bool QgsTopologicalMesh::renumberVertices( QVector<int> &oldToNewIndex )
const
808 std::vector<QgsMeshVertexCirculator> circulators;
809 circulators.reserve( mMesh->
vertices.count() );
810 int minDegree = std::numeric_limits<int>::max();
811 int minDegreeVertex = -1;
814 QSet<int> nonThreadedVertex;
815 oldToNewIndex = QVector<int> ( mMesh->
vertexCount(), -1 );
818 circulators.emplace_back( *
this, i );
820 if ( circulators.back().degree() < minDegree )
822 minDegreeVertex = circulators.size() - 1;
823 minDegree = circulator.
degree();
825 nonThreadedVertex.insert( i );
828 auto sortedNeighbor = [circulators]( QList<int> &neighbors,
int index )
842 int degree = circulators.at( neighborIndex ).degree();
843 QList<int>::Iterator it = neighbors.begin();
844 while ( it != neighbors.end() )
846 if ( degree <= circulators.at( *it ).degree() )
848 neighbors.insert( it, neighborIndex );
853 if ( it == neighbors.end() )
854 neighbors.append( neighborIndex );
860 int currentVertex = minDegreeVertex;
861 nonThreadedVertex.remove( minDegreeVertex );
863 while ( newIndex < mMesh->vertexCount() )
865 if ( oldToNewIndex[currentVertex] == -1 )
866 oldToNewIndex[currentVertex] = newIndex++;
868 if ( circulators.at( currentVertex ).isValid() )
870 QList<int> neighbors;
871 sortedNeighbor( neighbors, currentVertex );
873 for (
const int i : std::as_const( neighbors ) )
874 if ( oldToNewIndex.at( i ) == -1 && nonThreadedVertex.contains( i ) )
877 nonThreadedVertex.remove( i );
881 if ( queue.isEmpty() )
883 if ( nonThreadedVertex.isEmpty() && newIndex < mMesh->vertexCount() )
886 const QList<int> remainingVertex( nonThreadedVertex.constBegin(), nonThreadedVertex.constEnd() );
887 int minRemainingDegree = std::numeric_limits<int>::max();
888 int minRemainingVertex = -1;
889 for (
const int i : remainingVertex )
891 int degree = circulators.at( i ).degree();
892 if ( degree < minRemainingDegree )
894 minRemainingDegree = degree;
895 minRemainingVertex = i;
898 currentVertex = minRemainingVertex;
899 nonThreadedVertex.remove( currentVertex );
903 currentVertex = queue.dequeue();
910bool QgsTopologicalMesh::renumberFaces( QVector<int> &oldToNewIndex )
const
913 QSet<int> nonThreadedFaces;
915 oldToNewIndex = QVector<int>( mMesh->faceCount(), -1 );
917 QVector<int> faceDegrees( mMesh->faceCount(), 0 );
919 int minDegree = std::numeric_limits<int>::max();
920 int minDegreeFace = -1;
921 for (
int faceIndex = 0; faceIndex < mMesh->faceCount(); ++faceIndex )
923 const FaceNeighbors &neighbors = mFacesNeighborhood.at( faceIndex );
926 for (
int n = 0; n < neighbors.size(); ++n )
928 if ( neighbors.at( n ) != -1 )
932 if ( degree < minDegree )
935 minDegreeFace = faceIndex;
938 faceDegrees[faceIndex] = degree;
939 nonThreadedFaces.insert( faceIndex );
943 int currentFace = minDegreeFace;
944 nonThreadedFaces.remove( minDegreeFace );
946 auto sortedNeighbor = [
this, faceDegrees]( QList<int> &neighbors,
int index )
948 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( index );
950 for (
int i = 0; i < neighborhood.count(); ++i )
952 int neighborIndex = neighborhood.at( i );
953 if ( neighborIndex == -1 )
956 int degree = faceDegrees.at( neighborIndex );
957 if ( neighbors.isEmpty() )
958 neighbors.append( neighborIndex );
961 QList<int>::Iterator it = neighbors.begin();
962 while ( it != neighbors.end() )
964 if ( degree <= faceDegrees.at( *it ) )
966 neighbors.insert( it, neighborIndex );
971 if ( it == neighbors.end() )
972 neighbors.append( neighborIndex );
977 while ( newIndex < mMesh->faceCount() )
979 if ( oldToNewIndex[currentFace] == -1 )
980 oldToNewIndex[currentFace] = newIndex++;
982 QList<int> neighbors;
983 sortedNeighbor( neighbors, currentFace );
985 for (
const int i : std::as_const( neighbors ) )
986 if ( oldToNewIndex.at( i ) == -1 && nonThreadedFaces.contains( i ) )
989 nonThreadedFaces.remove( i );
992 if ( queue.isEmpty() )
994 if ( nonThreadedFaces.isEmpty() && newIndex < mMesh->faceCount() )
997 const QList<int> remainingFace( nonThreadedFaces.constBegin(), nonThreadedFaces.constEnd() );
998 int minRemainingDegree = std::numeric_limits<int>::max();
999 int minRemainingFace = -1;
1000 for (
const int i : remainingFace )
1002 int degree = faceDegrees.at( i );
1003 if ( degree < minRemainingDegree )
1005 minRemainingDegree = degree;
1006 minRemainingFace = i;
1009 currentFace = minRemainingFace;
1010 nonThreadedFaces.remove( currentFace );
1014 currentFace = queue.dequeue();
1094int QgsTopologicalMesh::Changes::addedFaceIndexInMesh(
int internalIndex )
const
1096 if ( internalIndex == -1 )
1099 return internalIndex + mAddedFacesFirstIndex;
1102int QgsTopologicalMesh::Changes::removedFaceIndexInMesh(
int internalIndex )
const
1104 if ( internalIndex == -1 )
1107 return mFaceIndexesToRemove.at( internalIndex );
1141 mMesh->vertices.append( vertex );
1142 mVertexToFace.append( -1 );
1143 referenceAsFreeVertex( mMesh->vertices.count() - 1 );
1149static double vertexPolygonOrientation(
const QgsMesh &
mesh,
const QList<int> &vertexIndexes )
1151 if ( vertexIndexes.count() < 3 )
1154 int hullDomainVertexPos = -1;
1155 double xMin = std::numeric_limits<double>::max();
1156 double yMin = std::numeric_limits<double>::max();
1157 for (
int i = 0; i < vertexIndexes.count(); ++i )
1160 if ( xMin >= vertex.
x() && yMin > vertex.
y() )
1162 hullDomainVertexPos = i;
1168 if ( hullDomainVertexPos >= 0 )
1170 int iv1 = vertexIndexes.at( ( hullDomainVertexPos - 1 + vertexIndexes.count() ) % vertexIndexes.count() );
1171 int iv2 = vertexIndexes.at( ( hullDomainVertexPos + 1 ) % vertexIndexes.count() );
1172 int ivc = vertexIndexes.at( ( hullDomainVertexPos ) );
1173 double cp = crossProduct( ivc, iv1, iv2,
mesh );
1182 if ( vertexIndex >= mVertexToFace.count() )
1185 if ( mVertexToFace.at( vertexIndex ) == -1 )
1191 dereferenceAsFreeVertex( vertexIndex );
1199 QList<int> boundariesVertexIndex;
1200 QList<int> associateFaceToBoundaries;
1201 QList<int> removedFacesIndexes;
1202 QSet<int> boundaryInGlobalMesh;
1208 Q_ASSERT( !mMesh->vertices.at( boundariesVertexIndex.last() ).isEmpty() );
1210 associateFaceToBoundaries.append( mFacesNeighborhood.at( circulator.
currentFaceIndex() ).at(
1213 if ( currentFace.count() > 3 )
1216 for (
int i = 2; i < currentFace.count() - 1; ++i )
1218 boundariesVertexIndex.append( currentFace.at( ( posInface + i ) % currentFace.count() ) );
1219 Q_ASSERT( !mMesh->vertices.at( boundariesVertexIndex.last() ).isEmpty() );
1220 associateFaceToBoundaries.append( mFacesNeighborhood.at( circulator.
currentFaceIndex() ).at(
1227 bool boundaryFill =
false;
1230 boundaryFill =
true;
1234 boundariesVertexIndex.append( lastVertexIndex );
1243 boundaryFill =
false;
1246 associateFaceToBoundaries.append( -1 );
1248 for (
const int index : std::as_const( boundariesVertexIndex ) )
1251 boundaryInGlobalMesh.insert( index );
1255 int currentVertexToFace = mVertexToFace.at( vertexIndex );
1259 QList<QList<int>> holes;
1260 QList<QList<int>> associateMeshFacesToHoles;
1262 bool cancelOperation =
false;
1270 int finalPos = boundariesVertexIndex.count() - 1;
1271 QList<int> uncoveredVertex;
1273 QList<int> partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1274 QList<int> associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1275 while ( startPos < finalPos && !partToCheck.isEmpty() )
1278 int secondPos = partToCheck.count() - 1;
1279 const QgsPoint &closingSegmentExtremety1 = mMesh->vertex( partToCheck.at( 0 ) );
1280 const QgsPoint &closingSegmentExtremety2 = mMesh->vertex( partToCheck.last() );
1281 bool isEdgeIntersect =
false;
1282 for (
int i = 1; i < secondPos - 1; ++i )
1284 const QgsPoint &p1 = mMesh->vertex( partToCheck.at( i ) );
1285 const QgsPoint &p2 = mMesh->vertex( partToCheck.at( i + 1 ) );
1286 bool isLineIntersection;
1289 if ( isEdgeIntersect )
1293 int index = partToCheck.at( 0 );
1294 if ( boundaryInGlobalMesh.contains( index ) && index != boundariesVertexIndex.at( 0 ) )
1296 cancelOperation =
true;
1302 if ( isEdgeIntersect || vertexPolygonOrientation( *mMesh, partToCheck ) >= 0 )
1304 partToCheck.removeLast();
1305 associateFacePart.removeAt( associateFacePart.count() - 2 );
1306 if ( partToCheck.count() == 1 )
1308 uncoveredVertex.append( index );
1309 startPos = startPos + 1;
1310 partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1311 associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1317 holes.append( partToCheck );
1318 associateMeshFacesToHoles.append( associateFacePart );
1320 startPos = startPos + partToCheck.count() - 1;
1321 uncoveredVertex.append( partToCheck.at( 0 ) );
1322 partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
1323 associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
1329 holes.append( boundariesVertexIndex );
1330 associateMeshFacesToHoles.append( associateFaceToBoundaries );
1333 if ( cancelOperation )
1339 Q_ASSERT( holes.count() == associateMeshFacesToHoles.count() );
1345 dereferenceAsFreeVertex( vertexIndex );
1347 mVertexToFace[vertexIndex] = -1;
1349 int oldFacesCount = mMesh->faceCount();
1350 for (
int h = 0; h < holes.count(); ++h )
1352 const QList<int> &holeVertices = holes.at( h );
1353 const QList<int> &associateMeshFacesToHole = associateMeshFacesToHoles.at( h );
1354 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
1355 std::vector<p2t::Point *> holeToFill( holeVertices.count() );
1358 for (
int i = 0; i < holeVertices.count(); ++i )
1360 const QgsMeshVertex &vertex = mMesh->vertex( holeVertices.at( i ) );
1361 holeToFill[i] =
new p2t::Point( vertex.
x(), vertex.
y() );
1362 mapPoly2TriPointToVertex.insert( holeToFill[i], holeVertices.at( i ) );
1365 auto cdt = std::make_unique<p2t::CDT>( holeToFill );
1368 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
1369 QVector<QgsMeshFace> newFaces( triangles.size() );
1370 for (
size_t i = 0; i < triangles.size(); ++i )
1374 for (
int j = 0; j < 3; j++ )
1376 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
1377 if ( vertInd == -1 )
1378 throw std::exception();
1379 Q_ASSERT( !mMesh->vertices.at( vertInd ).isEmpty() );
1387 throw std::exception();
1388 int newFaceIndexStartIndex = mMesh->faceCount();
1395 const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
1396 for (
const int vtc : verticesToFaceToChange )
1397 if ( mVertexToFace.at( vtc ) == -1 )
1399 mVertexToFace.at( vtc ),
1400 addChanges.addedFaceIndexInMesh( topologicalFaces.mVerticesToFace.values( vtc ).first() )
1405 for (
int i = 0; i < topologicalFaces.mFaces.count(); ++i )
1408 faceNeighbors = topologicalFaces.mFacesNeighborhood.at( i );
1409 for (
int n = 0; n < faceNeighbors.count(); ++n )
1411 if ( faceNeighbors.at( n ) != -1 )
1412 faceNeighbors[n] += newFaceIndexStartIndex;
1417 for (
int i = 0 ; i < holeVertices.count(); ++i )
1419 int vertexHoleIndex = holeVertices.at( i );
1420 int meshFaceBoundaryIndex = associateMeshFacesToHole.at( i );
1425 int newFaceBoundaryIndexInMesh = circulator.
currentFaceIndex() + newFaceIndexStartIndex;
1429 if ( meshFaceBoundaryIndex != -1 )
1431 const QgsMeshFace meshFace = mMesh->face( meshFaceBoundaryIndex );
1432 int positionInMeshFaceBoundary =
vertexPositionInFace( *mMesh, vertexHoleIndex, meshFaceBoundaryIndex );
1433 positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.count() ) % meshFace.count();
1435 addChanges.
mNeighborhoodChanges.append( {meshFaceBoundaryIndex, positionInMeshFaceBoundary, -1, newFaceBoundaryIndexInMesh} );
1446 for (
const std::array<int, 4> &neighborChangeToAdd : std::as_const( addChanges.
mNeighborhoodChanges ) )
1448 bool merged =
false;
1451 if ( existingNeighborChange.at( 0 ) == neighborChangeToAdd.at( 0 ) &&
1452 existingNeighborChange.at( 1 ) == neighborChangeToAdd.at( 1 ) )
1455 Q_ASSERT( existingNeighborChange.at( 3 ) == neighborChangeToAdd.at( 2 ) );
1456 existingNeighborChange[3] = neighborChangeToAdd.at( 3 );
1463 for (
const std::array<int, 3> &verticesToFaceToAdd : std::as_const( addChanges.
mVerticesToFaceChanges ) )
1465 bool merged =
false;
1468 if ( existingVerticesToFace.at( 0 ) == verticesToFaceToAdd.at( 0 ) )
1471 Q_ASSERT( existingVerticesToFace.at( 2 ) == verticesToFaceToAdd.at( 1 ) );
1472 existingVerticesToFace[2] = verticesToFaceToAdd.at( 2 );
1479 qDeleteAll( holeToFill );
1483 qDeleteAll( holeToFill );
1498 QSet<int> facesIndex;
1500 for (
int vertexIndex : vertices )
1503 facesIndex.unite( QSet< int >( faces.begin(), faces.end() ) );
1510 for (
int vertexIndex : vertices )
1512 int currentVertexToFace = mVertexToFace.at( vertexIndex );
1518 dereferenceAsFreeVertex( vertexIndex );
1520 mVertexToFace[vertexIndex] = -1;
1528 QList<int> boundariesToCheckClockwiseInNewFaces = topologicFaces.mBoundaries;
1529 QList<std::array<int, 2>> boundariesToCheckCounterClockwiseInNewFaces;
1530 QList<int> uniqueSharedVertexBoundary;
1538 while ( !boundariesToCheckClockwiseInNewFaces.isEmpty() )
1540 int boundary = boundariesToCheckClockwiseInNewFaces.takeLast();
1542 const QList<int> &linkedFaces = topologicFaces.mVerticesToFace.values( boundary );
1544 for (
int const linkedFace : linkedFaces )
1548 if ( mVertexToFace.at( boundary ) == -1 )
1554 if ( !newFacescirculator.
isValid() )
1568 if ( oppositeVertexCCWInMesh == oppositeVertexInNewFaces )
1574 int faceSize = newFaceOnBoundary.size();
1576 int previousVertexIndex = ( posInNewFace + faceSize - 1 ) % faceSize;
1577 if ( newFaceOnBoundary.at( previousVertexIndex ) == oppositeVertexCCWInMesh )
1585 if ( oppositeVertexCWInMesh == oppositeVertexInNewFaces )
1589 boundariesToCheckCounterClockwiseInNewFaces.append( {boundary, linkedFace} );
1594 while ( !boundariesToCheckCounterClockwiseInNewFaces.isEmpty() )
1596 std::array<int, 2> boundaryLinkedface = boundariesToCheckCounterClockwiseInNewFaces.takeLast();
1597 int boundary = boundaryLinkedface.at( 0 );
1598 int linkedFace = boundaryLinkedface.at( 1 );
1613 if ( oppositeVertexCWInMesh == oppositeVertexInNewFaces )
1620 if ( oppositeVertexCCWInMesh == oppositeVertexInNewFaces )
1623 uniqueSharedVertexBoundary.append( boundary );
1626 if ( !uniqueSharedVertexBoundary.isEmpty() )
1630 QSet<int> boundaryVertices( topologicFaces.mBoundaries.constBegin(), topologicFaces.mBoundaries.constEnd() );
1631 for (
const QgsMeshFace &newFace : std::as_const( topologicFaces.mFaces ) )
1633 for (
const int vertexIndex : newFace )
1635 if ( boundaryVertices.contains( vertexIndex ) )
1637 if ( mVertexToFace.at( vertexIndex ) != -1 )
1648 mFacesNeighborhood.clear();
1649 mVerticesToFace.clear();
1650 mBoundaries.clear();
1655 return mFacesNeighborhood;
1660 if ( mVerticesToFace.contains( vertexIndex ) )
1661 return mVerticesToFace.values( vertexIndex ).at( 0 );
1669 topologicMesh.mMesh =
mesh;
1670 topologicMesh.mVertexToFace = QVector<int>(
mesh->vertexCount(), -1 );
1671 topologicMesh.mMaximumVerticesPerFace = maxVerticesPerFace;
1674 for (
int i = 0; i <
mesh->faceCount(); ++i )
1676 if (
mesh->face( i ).isEmpty() )
1678 if ( maxVerticesPerFace != 0 &&
mesh->face( i ).count() > maxVerticesPerFace )
1695 TopologicalFaces subMesh = createTopologicalFaces(
mesh->faces, &topologicMesh.mVertexToFace, error,
false );
1696 topologicMesh.mFacesNeighborhood = subMesh.mFacesNeighborhood;
1698 for (
int i = 0; i < topologicMesh.mMesh->
vertexCount(); ++i )
1700 if ( topologicMesh.mVertexToFace.at( i ) == -1 )
1701 topologicMesh.mFreeVertices.insert( i );
1705 return topologicMesh;
1710 return createTopologicalFaces( faces,
nullptr, error, uniqueSharedVertexAllowed );
1715 const QVector<QgsMeshFace> &faces,
1716 QVector<int> *globalVertexToFace,
1718 bool allowUniqueSharedVertex )
1720 int facesCount = faces.count();
1721 QVector<FaceNeighbors> faceTopologies;
1722 QMultiHash<int, int> verticesToFace;
1725 TopologicalFaces ret;
1729 QMap<int, QMap<int, int>> verticesToNeighbor;
1731 for (
int faceIndex = 0; faceIndex < facesCount; ++faceIndex )
1734 int faceSize = face.count();
1736 for (
int i = 0; i < faceSize; ++i )
1738 int v1 = face[i % faceSize];
1739 int v2 = face[( i + 1 ) % faceSize];
1740 if ( verticesToNeighbor[v2].contains( v1 ) )
1746 verticesToNeighbor[v2].insert( v1, faceIndex );
1750 faceTopologies = QVector<FaceNeighbors>( faces.count() );
1752 QSet<int> boundaryVertices;
1754 for (
int faceIndex = 0; faceIndex < facesCount; ++faceIndex )
1757 int faceSize = face.size();
1759 faceTopology.resize( faceSize );
1761 for (
int i = 0; i < faceSize; ++i )
1763 int v1 = face.at( i );
1764 int v2 = face.at( ( i + 1 ) % faceSize );
1766 if ( globalVertexToFace )
1768 if ( ( *globalVertexToFace )[v1] == -1 )
1769 ( *globalVertexToFace )[v1] = faceIndex ;
1773 if ( allowUniqueSharedVertex || !verticesToFace.contains( v1 ) )
1774 verticesToFace.insert( v1, faceIndex ) ;
1777 QMap<int, int> &edges = verticesToNeighbor[v1];
1778 if ( edges.contains( v2 ) )
1779 faceTopology[i] = edges.value( v2 );
1782 faceTopology[i] = -1;
1784 if ( !allowUniqueSharedVertex )
1786 if ( boundaryVertices.contains( v1 ) )
1792 boundaryVertices.insert( v1 );
1798 ret.mFacesNeighborhood = faceTopologies;
1799 ret.mBoundaries = boundaryVertices.values();
1800 ret.mVerticesToFace = verticesToFace;
1806 return mFacesNeighborhood.at( faceIndex );
1818 QSet<int> removedFaces( facesIndexes.begin(), facesIndexes.end() );
1819 QSet<int> concernedFaces = concernedFacesBy( facesIndexes );
1821 for (
const int f : std::as_const( removedFaces ) )
1822 concernedFaces.remove( f );
1824 QVector<QgsMeshFace> remainingFaces;
1825 remainingFaces.reserve( concernedFaces.count() );
1826 for (
const int f : std::as_const( concernedFaces ) )
1827 remainingFaces.append( mMesh->face( f ) );
1830 createTopologicalFaces( remainingFaces,
nullptr, error,
false );
1842 QSet<int> indexSet( facesIndexesToRemove.begin(), facesIndexesToRemove.end() );
1843 QSet<int> threatedVertex;
1845 for (
int i = 0; i < facesIndexesToRemove.count(); ++i )
1847 const int faceIndex = facesIndexesToRemove.at( i );
1848 const QgsMeshFace &face = mMesh->face( faceIndex );
1850 const FaceNeighbors &neighborhood = mFacesNeighborhood.at( faceIndex );
1852 for (
int j = 0; j < face.count(); ++j )
1855 int neighborIndex = neighborhood.at( j );
1856 if ( neighborIndex != -1 && !indexSet.contains( neighborIndex ) )
1858 int positionInNeighbor = mFacesNeighborhood.at( neighborIndex ).indexOf( faceIndex );
1863 int vertexIndex = face.at( j );
1864 if ( !threatedVertex.contains( vertexIndex ) && indexSet.contains( mVertexToFace.at( vertexIndex ) ) )
1866 int oldValue = mVertexToFace.at( vertexIndex );
1869 if ( neighborIndex != -1 && !indexSet.contains( neighborIndex ) )
1870 refValue = neighborIndex;
1874 aroundFaces.removeOne( faceIndex );
1875 if ( !aroundFaces.isEmpty() )
1877 while ( !aroundFaces.isEmpty() && refValue == -1 )
1879 if ( !indexSet.contains( aroundFaces.first() ) )
1880 refValue = aroundFaces.first();
1882 aroundFaces.removeFirst();
1887 threatedVertex.insert( vertexIndex );
1897bool QgsTopologicalMesh::eitherSideFacesAndVertices(
int vertexIndex1,
1901 int &neighborVertex1InFace1,
1902 int &neighborVertex1InFace2,
1903 int &neighborVertex2inFace1,
1904 int &neighborVertex2inFace2 )
const
1946 int oppositeVertexFace1;
1947 int oppositeVertexFace2;
1948 int supposedOppositeVertexFace1;
1949 int supposedoppositeVertexFace2;
1951 bool result = eitherSideFacesAndVertices(
1956 oppositeVertexFace1,
1957 supposedoppositeVertexFace2,
1958 supposedOppositeVertexFace1,
1959 oppositeVertexFace2 );
1964 oppositeVertexFace1 < 0 ||
1965 oppositeVertexFace2 < 0 ||
1966 supposedOppositeVertexFace1 != oppositeVertexFace1 ||
1967 supposedoppositeVertexFace2 != oppositeVertexFace2 )
1970 const QgsMeshFace &face1 = mMesh->face( faceIndex1 );
1971 const QgsMeshFace &face2 = mMesh->face( faceIndex2 );
1974 if ( face1.count() != 3 || face2.count() != 3 )
1977 double crossProduct1 = crossProduct( vertexIndex1, oppositeVertexFace1, oppositeVertexFace2, *mMesh );
1978 double crossProduct2 = crossProduct( vertexIndex2, oppositeVertexFace1, oppositeVertexFace2, *mMesh );
1980 return crossProduct1 * crossProduct2 < 0;
1987 int oppositeVertexFace1;
1988 int oppositeVertexFace2;
1989 int supposedOppositeVertexFace1;
1990 int supposedoppositeVertexFace2;
1992 bool result = eitherSideFacesAndVertices(
1997 oppositeVertexFace1,
1998 supposedoppositeVertexFace2,
1999 supposedOppositeVertexFace1,
2000 oppositeVertexFace2 );
2005 oppositeVertexFace1 < 0 ||
2006 oppositeVertexFace2 < 0 ||
2007 supposedOppositeVertexFace1 != oppositeVertexFace1 ||
2008 supposedoppositeVertexFace2 != oppositeVertexFace2 )
2014 const QgsMeshFace &face1 = mMesh->face( faceIndex1 );
2015 const QgsMeshFace &face2 = mMesh->face( faceIndex2 );
2017 Q_ASSERT( face1.count() == 3 );
2018 Q_ASSERT( face2.count() == 3 );
2023 int neighborFace1 = mFacesNeighborhood.at( faceIndex1 ).at( pos1 );
2025 int neighborFace2 = mFacesNeighborhood.at( faceIndex1 ).at( ( pos1 + 1 ) % 3 );
2027 int neighborFace3 = mFacesNeighborhood.at( faceIndex2 ).at( pos2 );
2029 int neighborFace4 = mFacesNeighborhood.at( faceIndex2 ).at( ( pos2 + 1 ) % 3 );
2038 int startIndex = mMesh->faceCount();
2040 changes.
mFacesToAdd.append( {oppositeVertexFace1, oppositeVertexFace2, vertexIndex1} );
2041 changes.
mFacesToAdd.append( {oppositeVertexFace2, oppositeVertexFace1, vertexIndex2} );
2043 mFacesNeighborhood.at( faceIndex2 ).at( ( pos2 + 1 ) % 3 ),
2044 mFacesNeighborhood.at( faceIndex1 ).at( pos1 )
2047 mFacesNeighborhood.at( faceIndex1 ).at( ( pos1 + 1 ) % 3 ),
2048 mFacesNeighborhood.at( faceIndex2 ).at( pos2 )
2051 if ( neighborFace1 >= 0 )
2052 changes.
mNeighborhoodChanges.append( {neighborFace1, posInNeighbor1, faceIndex1, startIndex} );
2053 if ( neighborFace2 >= 0 )
2054 changes.
mNeighborhoodChanges.append( {neighborFace2, posInNeighbor2, faceIndex1, startIndex + 1} );
2055 if ( neighborFace3 >= 0 )
2056 changes.
mNeighborhoodChanges.append( {neighborFace3, posInNeighbor3, faceIndex2, startIndex + 1} );
2057 if ( neighborFace4 >= 0 )
2058 changes.
mNeighborhoodChanges.append( {neighborFace4, posInNeighbor4, faceIndex2, startIndex} );
2061 if ( mVertexToFace.at( vertexIndex1 ) == faceIndex1 || mVertexToFace.at( vertexIndex1 ) == faceIndex2 )
2063 if ( mVertexToFace.at( vertexIndex2 ) == faceIndex1 || mVertexToFace.at( vertexIndex2 ) == faceIndex2 )
2064 changes.
mVerticesToFaceChanges.append( {vertexIndex2, mVertexToFace.at( vertexIndex2 ), startIndex + 1} );
2066 if ( mVertexToFace.at( oppositeVertexFace1 ) == faceIndex1 )
2069 if ( mVertexToFace.at( oppositeVertexFace2 ) == faceIndex2 )
2081 int neighborVertex1InFace1;
2082 int neighborVertex1InFace2;
2083 int neighborVertex2inFace1;
2084 int neighborVertex2inFace2;
2086 bool result = eitherSideFacesAndVertices(
2091 neighborVertex1InFace1,
2092 neighborVertex1InFace2,
2093 neighborVertex2inFace1,
2094 neighborVertex2inFace2 );
2101 const QgsMeshFace &face1 = mMesh->face( faceIndex1 );
2102 const QgsMeshFace &face2 = mMesh->face( faceIndex2 );
2104 if ( face1.count() + face2.count() - 2 > mMaximumVerticesPerFace )
2109 QgsMeshVertex nv11 = mMesh->vertices.at( neighborVertex1InFace1 );
2110 QgsMeshVertex nv12 = mMesh->vertices.at( neighborVertex1InFace2 );
2111 QgsMeshVertex nv21 = mMesh->vertices.at( neighborVertex2inFace1 );
2112 QgsMeshVertex nv22 = mMesh->vertices.at( neighborVertex2inFace2 );
2114 double crossProduct1 = crossProduct( vertexIndex1, neighborVertex1InFace1, neighborVertex1InFace2, *mMesh );
2115 double crossProduct2 = crossProduct( vertexIndex2, neighborVertex2inFace1, neighborVertex2inFace2, *mMesh );
2117 return crossProduct1 * crossProduct2 < 0;
2124 int neighborVertex1InFace1;
2125 int neighborVertex1InFace2;
2126 int neighborVertex2inFace1;
2127 int neighborVertex2inFace2;
2129 bool result = eitherSideFacesAndVertices(
2134 neighborVertex1InFace1,
2135 neighborVertex1InFace2,
2136 neighborVertex2inFace1,
2137 neighborVertex2inFace2 );
2146 const QgsMeshFace &face1 = mMesh->face( faceIndex1 );
2147 const QgsMeshFace &face2 = mMesh->face( faceIndex2 );
2148 int faceSize1 = face1.count();
2149 int faceSize2 = face2.count();
2160 int startIndex = mMesh->faceCount();
2165 for (
int i = 0; i < faceSize1 - 1; ++i )
2167 int currentPos = ( pos1 + i ) % faceSize1;
2168 newface.append( face1.at( currentPos ) );
2170 int currentNeighbor = mFacesNeighborhood.at( faceIndex1 ).at( currentPos );
2171 newNeighborhood.append( currentNeighbor );
2173 if ( currentNeighbor != -1 )
2176 changes.
mNeighborhoodChanges.append( {currentNeighbor, currentPosInNeighbor, faceIndex1, startIndex} );
2179 for (
int i = 0; i < faceSize2 - 1; ++i )
2181 int currentPos = ( pos2 + i ) % faceSize2;
2182 newface.append( face2.at( currentPos ) );
2184 int currentNeighbor = mFacesNeighborhood.at( faceIndex2 ).at( currentPos );
2185 newNeighborhood.append( currentNeighbor );
2187 if ( currentNeighbor != -1 )
2190 changes.
mNeighborhoodChanges.append( {currentNeighbor, currentPosInNeighbor, faceIndex2, startIndex} );
2194 for (
int i = 0; i < faceSize1; ++i )
2195 if ( mVertexToFace.at( face1.at( i ) ) == faceIndex1 )
2198 for (
int i = 0; i < faceSize2; ++i )
2199 if ( mVertexToFace.at( face2.at( i ) ) == faceIndex2 )
2212 const QgsMeshFace face = mMesh->face( faceIndex );
2214 return face.count() == 4;
2220 const QgsMeshFace &face = mMesh->face( faceIndex );
2221 int faceSize = face.count();
2223 Q_ASSERT( faceSize == 4 );
2225 double maxAngle = 0;
2226 int splitVertexPos = -1;
2227 for (
int i = 0; i < faceSize; ++i )
2229 QgsVector vect1( mMesh->vertex( face.at( i ) ) - mMesh->vertex( face.at( ( i + 1 ) % faceSize ) ) );
2230 QgsVector vect2( mMesh->vertex( face.at( ( i + 2 ) % faceSize ) ) - mMesh->vertex( face.at( ( i + 1 ) % faceSize ) ) );
2232 double angle = std::abs( vect1.
angle( vect2 ) );
2233 angle = std::min( angle, 2.0 * M_PI - angle );
2234 if ( angle > maxAngle )
2237 splitVertexPos = ( i + 1 ) % faceSize;
2242 if ( splitVertexPos == -1 )
2245 const QgsMeshFace newFace1 = {face.at( splitVertexPos ),
2246 face.at( ( splitVertexPos + 1 ) % faceSize ),
2247 face.at( ( splitVertexPos + 2 ) % faceSize )
2250 const QgsMeshFace newFace2 = {face.at( splitVertexPos ),
2251 face.at( ( splitVertexPos + 2 ) % faceSize ),
2252 face.at( ( splitVertexPos + 3 ) % faceSize )
2255 QVector<int> neighborIndex( faceSize );
2256 QVector<int> posInNeighbor( faceSize );
2258 for (
int i = 0; i < faceSize; ++i )
2260 neighborIndex[i] = mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + i ) % faceSize );
2267 int startIndex = mMesh->faceCount();
2273 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 1 ) % faceSize ),
2277 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 2 ) % faceSize ),
2278 mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 3 ) % faceSize )
2281 for (
int i = 0; i < faceSize; ++i )
2283 if ( neighborIndex[i] >= 0 )
2284 changes.
mNeighborhoodChanges.append( {neighborIndex[i], posInNeighbor[i], faceIndex, startIndex + int( i / 2 )} );
2286 int vertexIndex = face.at( ( splitVertexPos + i ) % faceSize );
2287 if ( mVertexToFace.at( vertexIndex ) == faceIndex )
2303 mMesh->vertices.append( vertex );
2304 mVertexToFace.append( -1 );
2307 const QgsMeshFace includingFace = mMesh->face( includingFaceIndex );
2308 const FaceNeighbors includingFaceNeighborhood = mFacesNeighborhood.at( includingFaceIndex );
2309 int includingFaceSize = includingFace.count();
2311 for (
int i = 0; i < includingFaceSize; ++i )
2315 face[0] = mMesh->vertexCount() - 1;
2316 face[1] = includingFace.at( i );
2317 face[2] = includingFace.at( ( i + 1 ) % includingFaceSize );
2318 mMesh->faces.append( face );
2321 int currentVertexIndex = includingFace.at( i );
2322 if ( mVertexToFace.at( currentVertexIndex ) == includingFaceIndex )
2324 int newFaceIndex = mMesh->faceCount() - 1;
2325 mVertexToFace[currentVertexIndex] = newFaceIndex;
2329 int includingFaceNeighbor = includingFaceNeighborhood.at( i );
2333 includingFaceNeighbor,
2336 mFacesNeighborhood.append( neighbors );
2339 if ( includingFaceNeighbor != -1 )
2342 int oldValue = mFacesNeighborhood[includingFaceNeighbor][indexInNeighbor];
2354 mVertexToFace[mVertexToFace.count() - 1] = mMesh->faceCount() - 1;
2362 const QgsMeshFace face1 = mMesh->face( faceIndex );
2369 int newVertexPositionInFace1 = position + 1;
2371 auto triangulate = [
this, &changes](
int removedFaceIndex,
const QgsMeshVertex & newVertex,
int newVertexPosition, QVector<int> &edgeFacesIndexes )->
bool
2373 const QgsMeshFace &initialFace = mMesh->face( removedFaceIndex );
2377 const int addedVertexIndex = mMesh->vertexCount();
2379 int faceStartGlobalIndex = mMesh->faceCount() + changes.
mFacesToAdd.count();
2380 int localStartIndex = changes.
mFacesToAdd.count();
2382 QVector<int> newBoundary = initialFace;
2383 newBoundary.insert( newVertexPosition, addedVertexIndex );
2387 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
2388 std::vector<p2t::Point *> faceToFill( newBoundary.count() );
2389 for (
int i = 0; i < newBoundary.count(); ++i )
2393 if ( newBoundary.at( i ) == addedVertexIndex )
2396 vert = mMesh->vertex( newBoundary.at( i ) );
2398 faceToFill[i] =
new p2t::Point( vert.
x(), vert.
y() );
2399 mapPoly2TriPointToVertex.insert( faceToFill[i], newBoundary.at( i ) );
2402 auto cdt = std::make_unique<p2t::CDT>( faceToFill );
2404 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
2405 QVector<QgsMeshFace> newFaces( triangles.size() );
2406 for (
size_t i = 0; i < triangles.size(); ++i )
2410 for (
int j = 0; j < 3; j++ )
2412 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
2413 if ( vertInd == -1 )
2414 throw std::exception();
2422 throw std::exception();
2428 const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
2429 for (
const int vtc : verticesToFaceToChange )
2430 if ( vtc != addedVertexIndex && mVertexToFace.at( vtc ) == removedFaceIndex )
2435 topologicalFaces.
vertexToFace( vtc ) + faceStartGlobalIndex
2439 for (
int i = 0; i < topologicalFaces.mFaces.count(); ++i )
2442 for (
int n = 0; n < faceNeighbors.count(); ++n )
2444 if ( faceNeighbors.at( n ) != -1 )
2445 faceNeighbors[n] += faceStartGlobalIndex;
2449 edgeFacesIndexes.resize( 2 );
2451 for (
int i = 0 ; i < newBoundary.count(); ++i )
2453 int vertexIndex = newBoundary.at( i );
2456 int newFaceBoundaryLocalIndex = localStartIndex + circulator.
currentFaceIndex();
2458 int newFaceBoundaryIndexInMesh = faceStartGlobalIndex;
2460 int meshFaceBoundaryIndex;
2461 if ( i == newVertexPosition )
2463 meshFaceBoundaryIndex = -1;
2464 edgeFacesIndexes[0] = newFaceBoundaryLocalIndex;
2466 else if ( i == ( newVertexPosition + newBoundary.count() - 1 ) % newBoundary.count() )
2468 meshFaceBoundaryIndex = -1;
2469 edgeFacesIndexes[1] = newFaceBoundaryLocalIndex;
2477 if ( meshFaceBoundaryIndex != -1 )
2479 const QgsMeshFace meshFace = mMesh->face( meshFaceBoundaryIndex );
2481 positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.count() ) % meshFace.count();
2484 positionInMeshFaceBoundary,
2486 newFaceBoundaryIndexInMesh +
2494 qDeleteAll( faceToFill );
2504 QVector<int> edgeFacesIndexes;
2505 if ( !triangulate( faceIndex, vertexToInsert, newVertexPositionInFace1, edgeFacesIndexes ) )
2510 int addedVertexIndex = mMesh->vertexCount();
2513 int face2Index = mFacesNeighborhood.at( faceIndex ).at( position );
2514 if ( face2Index != -1 )
2516 const QgsMeshFace &face2 = mMesh->face( face2Index );
2518 QVector<int> edgeFacesIndexesFace2;
2519 if ( !triangulate( face2Index, vertexToInsert, vertexPositionInFace2, edgeFacesIndexesFace2 ) )
2528 pos2InFaceSide1 = ( pos2InFaceSide1 + secondFaceSide1.size() - 1 ) % secondFaceSide1.size();
2535 pos2InFaceSide2 = ( pos2InFaceSide2 + secondFaceSide1.size() - 1 ) % secondFaceSide1.size();
2549 Q_ASSERT( verticesIndexes.count() == newValues.count() );
2552 changes.
mNewZValues.reserve( verticesIndexes.count() );
2553 changes.
mOldZValues.reserve( verticesIndexes.count() );
2554 for (
int i = 0; i < verticesIndexes.count(); ++i )
2557 changes.
mOldZValues.append( mMesh->vertices.at( verticesIndexes.at( i ) ).z() );
2568 Q_ASSERT( verticesIndexes.count() == newValues.count() );
2571 changes.
mNewXYValues.reserve( verticesIndexes.count() );
2572 changes.
mOldXYValues.reserve( verticesIndexes.count() );
2573 QSet<int> concernedFace;
2574 for (
int i = 0; i < verticesIndexes.count(); ++i )
2577 changes.
mOldXYValues.append( mMesh->vertices.at( verticesIndexes.at( i ) ) );
2580 concernedFace.unite( QSet< int>( faces.begin(), faces.end() ) );
2594 int oppositeVertexFace1;
2595 int oppositeVertexFace2;
2596 int supposedOppositeVertexFace1;
2597 int supposedoppositeVertexFace2;
2599 bool result = eitherSideFacesAndVertices(
2604 oppositeVertexFace1,
2605 supposedoppositeVertexFace2,
2606 supposedOppositeVertexFace1,
2607 oppositeVertexFace2 );
2612 const QgsMeshFace face1 = mMesh->face( faceIndex1 );
2613 const QgsMeshFace face2 = mMesh->face( faceIndex2 );
2616 mMesh->vertex( face1.at( 1 ) ),
2617 mMesh->vertex( face1.at( 2 ) ) );
2618 bool circle1ContainsPoint = circle.
contains( mMesh->vertex( supposedoppositeVertexFace2 ) );
2621 mMesh->vertex( face2.at( 1 ) ),
2622 mMesh->vertex( face2.at( 2 ) ) );
2623 bool circle2ContainsPoint = circle.
contains( mMesh->vertex( supposedOppositeVertexFace1 ) );
2625 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())
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.