28 static int vertexPositionInFace( 
int vertexIndex, 
const QgsMeshFace &face )
 
   30   return face.indexOf( vertexIndex );
 
   33 static int vertexPositionInFace( 
const QgsMesh &mesh, 
int vertexIndex, 
int faceIndex )
 
   35   if ( faceIndex < 0 || faceIndex >= mesh.
faceCount() )
 
   38   return vertexPositionInFace( vertexIndex, mesh.
face( faceIndex ) );
 
   41 static double crossProduct( 
int centralVertex, 
int vertex1, 
int vertex2, 
const QgsMesh &mesh )
 
   47   double ux1 = v1.
x() - vc.
x();
 
   48   double uy1 = v1.
y() - vc.
y();
 
   49   double vx1 = v2.
x() - vc.
x();
 
   50   double vy1 = v2.
y() - vc.
y();
 
   52   return ux1 * vy1 - uy1 * vx1;
 
   57   : mFaces( topologicalMesh.mMesh->faces )
 
   58   , mFacesNeighborhood( topologicalMesh.mFacesNeighborhood )
 
   59   ,  mVertexIndex( vertexIndex )
 
   61   if ( vertexIndex >= 0 && vertexIndex < topologicalMesh.mMesh->vertexCount() )
 
   63     mCurrentFace = topologicalMesh.mVertexToFace[vertexIndex];
 
   64     mIsValid = vertexPositionInFace( *topologicalMesh.
mesh(), vertexIndex, mCurrentFace ) != -1;
 
   72     mLastValidFace = mCurrentFace;
 
   76   : mFaces( topologicalFaces.mFaces )
 
   77   , mFacesNeighborhood( topologicalFaces.mFacesNeighborhood )
 
   78   , mVertexIndex( vertexIndex )
 
   80   const QgsMeshFace &face = topologicalFaces.mFaces.at( faceIndex );
 
   81   mIsValid = vertexPositionInFace( vertexIndex, face ) != -1;
 
   83   mCurrentFace = faceIndex;
 
   84   mLastValidFace = mCurrentFace;
 
   88   : mFaces( topologicalFaces.mFaces )
 
   89   , mFacesNeighborhood( topologicalFaces.mFacesNeighborhood )
 
   90   , mVertexIndex( vertexIndex )
 
   92   if ( topologicalFaces.mVerticesToFace.contains( vertexIndex ) )
 
   93     mCurrentFace = topologicalFaces.mVerticesToFace.values( vertexIndex ).first();
 
   94   mLastValidFace = mCurrentFace;
 
   95   mIsValid = mCurrentFace != -1;
 
  100   if ( mCurrentFace == -1 )
 
  101     mCurrentFace = mLastValidFace;
 
  104     int currentPos = positionInCurrentFace();
 
  105     Q_ASSERT( currentPos != -1 );
 
  109     mLastValidFace = mCurrentFace;
 
  110     mCurrentFace = mFacesNeighborhood.at( mCurrentFace ).at( ( currentPos + faceSize - 1 ) % 
currentFace.count() );
 
  118   if ( mCurrentFace == -1 )
 
  119     mCurrentFace = mLastValidFace;
 
  122     int currentPos = positionInCurrentFace();
 
  123     Q_ASSERT( currentPos != -1 );
 
  127     mLastValidFace = mCurrentFace;
 
  128     mCurrentFace = mFacesNeighborhood.at( mCurrentFace ).at( ( currentPos ) % faceSize );
 
  141   if ( mCurrentFace != -1 )
 
  142     return mFaces.at( mCurrentFace );
 
  152   if ( mCurrentFace == -1 )
 
  153     mCurrentFace = mLastValidFace;
 
  155   int firstFace = mCurrentFace;
 
  158   if ( mCurrentFace == firstFace )
 
  169   if ( mCurrentFace == -1 )
 
  170     mCurrentFace = mLastValidFace;
 
  172   int firstFace = mCurrentFace;
 
  175   if ( mCurrentFace == firstFace )
 
  183   if ( mCurrentFace == -1 )
 
  188   if ( face.isEmpty() )
 
  191   int vertexPosition = vertexPositionInFace( mVertexIndex, 
currentFace() );
 
  193   if ( vertexPosition == -1 )
 
  196   return face.at( ( vertexPosition + 1 ) % face.count() );
 
  201   if ( mCurrentFace == -1 )
 
  206   if ( face.isEmpty() )
 
  209   int vertexPosition = vertexPositionInFace( mVertexIndex, 
currentFace() );
 
  211   if ( vertexPosition == -1 )
 
  214   return face.at( ( vertexPosition - 1 + face.count() ) % face.count() );
 
  228   if ( mCurrentFace != -1 )
 
  229     ret.append( mCurrentFace );
 
  274 int QgsMeshVertexCirculator::positionInCurrentFace()
 const 
  276   if ( mCurrentFace < 0 || mCurrentFace > mFaces.count() )
 
  279   return vertexPositionInFace( mVertexIndex, mFaces.at( mCurrentFace ) );
 
  289   for ( 
int i = 0; i < changes.
mFacesToAdd.count(); ++i )
 
  292   for ( 
int boundary : topologicalFaces.mBoundaries )
 
  295     if ( mVertexToFace.at( boundary ) == -1 )
 
  298     const QList<int> &linkedFaces = topologicalFaces.mVerticesToFace.values( boundary );
 
  299     for ( 
int linkedFace : linkedFaces )
 
  305       if ( mVertexToFace.at( oppositeVertexForNewFace ) == -1 )
 
  313       int boundaryPositionInNewFace = vertexPositionInFace( boundary, newFaceBoundary );
 
  315       if ( oppositeVertexForMeshFace != oppositeVertexForNewFace )
 
  327           boundaryPositionInMeshFace,
 
  337   for ( 
int f = 0; f < changes.
mFacesToAdd.count(); ++f )
 
  338     for ( 
int n = 0; n < changes.
mFacesToAdd.at( f ).count(); ++n )
 
  340         changes.
mFacesNeighborhoodToAdd[f][n] = changes.addedFaceIndexInMesh( topologicalFaces.mFacesNeighborhood.at( f ).at( n ) );
 
  342   const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
 
  343   for ( 
const int vtc : verticesToFaceToChange )
 
  344     if ( mVertexToFace.at( vtc ) == -1 )
 
  346                                               mVertexToFace.at( vtc ),
 
  347                                               changes.addedFaceIndexInMesh( topologicalFaces.mVerticesToFace.values( vtc ).first() ) } );
 
  356   int initialVerticesCount = mMesh->
vertices.count();
 
  361     mVertexToFace.resize( newSize );
 
  367     mMesh->
faces.resize( newSize );
 
  368     mFacesNeighborhood.resize( newSize );
 
  374     mFacesNeighborhood[changes.removedFaceIndexInMesh( i )] = 
FaceNeighbors();
 
  380     if ( mVertexToFace.at( vertexIndex ) == -1 )
 
  381       dereferenceAsFreeVertex( vertexIndex );
 
  383     mVertexToFace[vertexIndex] = -1;
 
  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 = neigborChange.at( 0 );
 
  403     const int positionInFace = neigborChange.at( 1 );
 
  404     const int valueToApply = neigborChange.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 &&
 
  414          vertexToFaceChange.at( 1 ) != -1 &&
 
  415          !mMesh->
vertices.at( vertexIndex ).isEmpty() )
 
  416       referenceAsFreeVertex( vertexIndex );
 
  418     if ( vertexToFaceChange.at( 1 ) == -1 && vertexToFaceChange.at( 2 ) != -1 )
 
  419       dereferenceAsFreeVertex( vertexIndex );
 
  430       mMesh->
vertices[vertexIndex].setX( pt.
x() );
 
  431       mMesh->
vertices[vertexIndex].setY( pt.
y() );
 
  440     const int faceIndex = neigborChange.at( 0 );
 
  441     const int positionInFace = neigborChange.at( 1 );
 
  442     const int valueToApply = neigborChange.at( 2 );
 
  443     mFacesNeighborhood[faceIndex][positionInFace] = valueToApply;
 
  457     if ( mVertexToFace.at( vertexIndex ) == -1 )
 
  458       referenceAsFreeVertex( vertexIndex );
 
  462   for ( 
int i = 0; i < verticesToFaceChangesCount; ++i )
 
  464     const std::array<int, 3> vertexToFaceChange = changes.
mVerticesToFaceChanges.at( verticesToFaceChangesCount - i - 1 );
 
  465     int vertexIndex = vertexToFaceChange.at( 0 );
 
  466     mVertexToFace[vertexIndex] = vertexToFaceChange.at( 1 );
 
  468     if ( vertexToFaceChange.at( 2 ) == -1 && vertexToFaceChange.at( 1 ) != -1 )
 
  469       dereferenceAsFreeVertex( vertexIndex );
 
  471     if ( vertexToFaceChange.at( 1 ) == -1 &&
 
  472          vertexToFaceChange.at( 2 ) != -1 &&
 
  474       referenceAsFreeVertex( vertexIndex );
 
  480     mMesh->
faces.resize( newSize );
 
  481     mFacesNeighborhood.resize( newSize );
 
  488     for ( 
int i = newSize; i < mMesh->
vertexCount(); ++i )
 
  489       if ( mVertexToFace.at( i ) == -1 )
 
  490         dereferenceAsFreeVertex( i );
 
  493     mVertexToFace.resize( newSize );
 
  504       mMesh->
vertices[vertexIndex].setX( pt.
x() );
 
  505       mMesh->
vertices[vertexIndex].setY( pt.
y() );
 
  515 QSet<int> QgsTopologicalMesh::concernedFacesBy( 
const QList<int> faceIndexes )
 const 
  518   for ( 
const int faceIndex : faceIndexes )
 
  521     for ( 
int i = 0; i < face.count(); ++i )
 
  527 void QgsTopologicalMesh::dereferenceAsFreeVertex( 
int vertexIndex )
 
  529   mFreeVertices.remove( vertexIndex );
 
  532 void QgsTopologicalMesh::referenceAsFreeVertex( 
int vertexIndex )
 
  536   mFreeVertices.insert( vertexIndex );
 
  541   for ( 
int faceIndex = 0 ; faceIndex < mMesh->
faces.count( ); ++faceIndex )
 
  544     const FaceNeighbors &neighborhood = mFacesNeighborhood.at( faceIndex );
 
  545     if ( face.count() != neighborhood.count() )
 
  547     for ( 
int i = 0; i < face.count(); ++i )
 
  549       int vertexIndex = face.at( i );
 
  551       if ( mVertexToFace.at( vertexIndex ) == -1 )
 
  554       int neighborIndex = neighborhood.at( i );
 
  555       if ( neighborIndex != -1 )
 
  558         if ( neighborFace.isEmpty() )
 
  560         int neighborSize = neighborFace.size();
 
  561         const FaceNeighbors &neighborhoodOfNeighbor = mFacesNeighborhood.at( neighborIndex );
 
  562         int posInNeighbor = vertexPositionInFace( *mMesh, vertexIndex, neighborIndex );
 
  563         if ( neighborhoodOfNeighbor.isEmpty() || neighborhoodOfNeighbor.at( ( posInNeighbor + neighborSize - 1 ) % neighborSize ) != faceIndex )
 
  569   for ( 
int vertexIndex = 0; vertexIndex < mMesh->
vertexCount(); ++vertexIndex )
 
  571     if ( mVertexToFace.at( vertexIndex ) != -1 )
 
  573       if ( !mMesh->
face( mVertexToFace.at( vertexIndex ) ).contains( vertexIndex ) )
 
  599   if ( vertexIndex < 0 || vertexIndex >= mMesh->
vertexCount() )
 
  601   return mVertexToFace.at( vertexIndex );
 
  616   if ( vertexIndex < 0 || vertexIndex >= mMesh->
vertexCount() )
 
  619   if ( mMesh->
vertices.at( vertexIndex ).isEmpty() )
 
  622   return mVertexToFace.at( vertexIndex ) == -1;
 
  627 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) 
  628   return mFreeVertices.values();
 
  630   return QList<int>( mFreeVertices.begin(), mFreeVertices.end() );
 
  638   int faceSize = face.count();
 
  643   for ( 
int i = 0; i < faceSize; ++i )
 
  646     int iv1 = face[( i + 1 ) % faceSize];
 
  647     int iv2 = face[( i + 2 ) % faceSize];
 
  671     double crossProd = crossProduct( iv1, iv0, iv2, *
mesh ); 
 
  672     if ( direction != 0 && crossProd * direction < 0 )   
 
  674     else if ( crossProd == 0 )
 
  676     else if ( direction == 0 && crossProd != 0 )
 
  677       direction = crossProd / std::fabs( crossProd );
 
  682     for ( 
int i = 0; i < faceSize / 2; ++i )
 
  685       face[i] = face.at( faceSize - i - 1 );
 
  686       face[faceSize - i - 1] = temp;
 
  695   QVector<int> oldToNewIndex( mMesh->
vertices.count(), -1 );
 
  699   while ( oldIndex < verticesTotalCount )
 
  707       oldToNewIndex[oldIndex] = newIndex;
 
  708       if ( oldIndex != newIndex )
 
  710       oldToNewIndex[oldIndex] = newIndex;
 
  720   int facesTotalCount = mMesh->
faceCount();
 
  721   while ( oldIndex < facesTotalCount )
 
  723     if ( mMesh->
face( oldIndex ).isEmpty() )
 
  727       if ( oldIndex != newIndex )
 
  728         mMesh->
faces[newIndex] = mMesh->
faces[oldIndex];
 
  730       for ( 
int i = 0; i < face.count(); ++i )
 
  731         face[i] = oldToNewIndex[face.at( i )];
 
  737   mMesh->
faces.resize( newIndex );
 
  739   mVertexToFace.clear();
 
  740   mFacesNeighborhood.clear();
 
  745   QVector<int> oldToNewVerticesIndexes;
 
  746   if ( !renumberVertices( oldToNewVerticesIndexes ) )
 
  750   QVector<int> oldToNewFacesIndexes;
 
  752   if ( !renumberFaces( oldToNewFacesIndexes ) )
 
  757   QVector<QgsMeshVertex> tempVertices( mMesh->
vertices.count() );
 
  758   for ( 
int i = 0; i < oldToNewVerticesIndexes.count(); ++i )
 
  760     tempVertices[oldToNewVerticesIndexes.at( i )] = mMesh->
vertex( i );
 
  764   QVector<QgsMeshFace> tempFaces( mMesh->
faces.count() );
 
  765   for ( 
int i = 0; i < oldToNewFacesIndexes.count(); ++i )
 
  767     tempFaces[oldToNewFacesIndexes.at( i )] = mMesh->
face( i );
 
  769     QgsMeshFace &face = tempFaces[oldToNewFacesIndexes.at( i )];
 
  771     for ( 
int fi = 0; fi < face.count(); ++fi )
 
  773       face[fi] = oldToNewVerticesIndexes.at( face.at( fi ) );
 
  777   mMesh->
faces = tempFaces;
 
  783 bool QgsTopologicalMesh::renumberVertices( QVector<int> &oldToNewIndex )
 const 
  785   std::vector<QgsMeshVertexCirculator> circulators;
 
  786   circulators.reserve( mMesh->
vertices.count() );
 
  787   int minDegree = std::numeric_limits<int>::max();
 
  788   int minDegreeVertex = -1;
 
  791   QSet<int> nonThreadedVertex;
 
  792   oldToNewIndex = QVector<int> ( mMesh->
vertexCount(), -1 );
 
  795     circulators.emplace_back( *
this, i );
 
  797     if ( circulators.back().degree() < minDegree )
 
  799       minDegreeVertex = circulators.size() - 1;
 
  800       minDegree = circulator.
degree();
 
  802     nonThreadedVertex.insert( i );
 
  805   auto sortedNeighbor = [ = ]( QList<int> &neighbors, 
int index )
 
  819       int degree = circulators.at( neighborIndex ).degree();
 
  820       QList<int>::Iterator it = neighbors.begin();
 
  821       while ( it != neighbors.end() )
 
  823         if ( degree <= circulators.at( *it ).degree() )
 
  825           neighbors.insert( it, neighborIndex );
 
  830       if ( it == neighbors.end() )
 
  831         neighbors.append( neighborIndex );
 
  837   int currentVertex = minDegreeVertex;
 
  838   nonThreadedVertex.remove( minDegreeVertex );
 
  840   while ( newIndex < mMesh->vertexCount() )
 
  842     if ( oldToNewIndex[currentVertex] == -1 )
 
  843       oldToNewIndex[currentVertex] = newIndex++;
 
  845     if ( circulators.at( currentVertex ).isValid() )
 
  847       QList<int> neighbors;
 
  848       sortedNeighbor( neighbors, currentVertex );
 
  850       for ( 
const int i : std::as_const( neighbors ) )
 
  851         if ( oldToNewIndex.at( i ) == -1 && nonThreadedVertex.contains( i ) )
 
  854           nonThreadedVertex.remove( i );
 
  858     if ( queue.isEmpty() )
 
  860       if ( nonThreadedVertex.isEmpty() && newIndex < mMesh->vertexCount() )
 
  863       const QList<int> remainingVertex = qgis::setToList( nonThreadedVertex );
 
  864       int minRemainingDegree = std::numeric_limits<int>::max();
 
  865       int minRemainingVertex = -1;
 
  866       for ( 
const int i : remainingVertex )
 
  868         int degree = circulators.at( i ).degree();
 
  869         if ( degree < minRemainingDegree )
 
  871           minRemainingDegree = degree;
 
  872           minRemainingVertex = i;
 
  875       currentVertex = minRemainingVertex;
 
  876       nonThreadedVertex.remove( currentVertex );
 
  880       currentVertex = queue.dequeue();
 
  887 bool QgsTopologicalMesh::renumberFaces( QVector<int> &oldToNewIndex )
 const 
  890   QSet<int> nonThreadedFaces;
 
  892   oldToNewIndex = QVector<int>( mMesh->
faceCount(), -1 );
 
  894   QVector<int> faceDegrees( mMesh->
faceCount(), 0 );
 
  896   int minDegree = std::numeric_limits<int>::max();
 
  897   int minDegreeFace = -1;
 
  898   for ( 
int faceIndex = 0; faceIndex < mMesh->
faceCount(); ++faceIndex )
 
  900     const FaceNeighbors &neighbors = mFacesNeighborhood.at( faceIndex );
 
  903     for ( 
int n = 0; n < neighbors.size(); ++n )
 
  905       if ( neighbors.at( n ) != -1 )
 
  909     if ( degree < minDegree )
 
  912       minDegreeFace = faceIndex;
 
  915     faceDegrees[faceIndex] = degree;
 
  916     nonThreadedFaces.insert( faceIndex );
 
  920   int currentFace = minDegreeFace;
 
  921   nonThreadedFaces.remove( minDegreeFace );
 
  923   auto sortedNeighbor = [ = ]( QList<int> &neighbors, 
int index )
 
  925     const FaceNeighbors &neighborhood = mFacesNeighborhood.at( index );
 
  927     for ( 
int i = 0; i < neighborhood.count(); ++i )
 
  929       int neighborIndex = neighborhood.at( i );
 
  930       if ( neighborIndex == -1 )
 
  933       int degree = faceDegrees.at( neighborIndex );
 
  934       if ( neighbors.isEmpty() )
 
  935         neighbors.append( neighborIndex );
 
  938         QList<int>::Iterator it = neighbors.begin();
 
  939         while ( it != neighbors.end() )
 
  941           if ( degree <= faceDegrees.at( *it ) )
 
  943             neighbors.insert( it, neighborIndex );
 
  948         if ( it == neighbors.end() )
 
  949           neighbors.append( neighborIndex );
 
  954   while ( newIndex < mMesh->faceCount() )
 
  956     if ( oldToNewIndex[currentFace] == -1 )
 
  957       oldToNewIndex[currentFace] = newIndex++;
 
  959     QList<int> neighbors;
 
  960     sortedNeighbor( neighbors, currentFace );
 
  962     for ( 
const int i : std::as_const( neighbors ) )
 
  963       if ( oldToNewIndex.at( i ) == -1 && nonThreadedFaces.contains( i ) )
 
  966         nonThreadedFaces.remove( i );
 
  969     if ( queue.isEmpty() )
 
  971       if ( nonThreadedFaces.isEmpty() && newIndex < mMesh->faceCount() )
 
  974       const QList<int> remainingFace = qgis::setToList( nonThreadedFaces );
 
  975       int minRemainingDegree = std::numeric_limits<int>::max();
 
  976       int minRemainingFace = -1;
 
  977       for ( 
const int i : remainingFace )
 
  979         int degree = faceDegrees.at( i );
 
  980         if ( degree < minRemainingDegree )
 
  982           minRemainingDegree = degree;
 
  983           minRemainingFace = i;
 
  986       currentFace = minRemainingFace;
 
  987       nonThreadedFaces.remove( currentFace );
 
  991       currentFace = queue.dequeue();
 
 1006   return mFacesToRemove;
 
 1011   return mFaceIndexesToRemove;
 
 1016   return mVerticesToAdd;
 
 1021   return mChangeCoordinateVerticesIndexes;
 
 1031   return mNewXYValues;
 
 1036   return mOldXYValues;
 
 1041   return mNativeFacesIndexesGeometryChanged;
 
 1046   return ( mFaceIndexesToRemove.isEmpty() &&
 
 1047            mFacesToAdd.isEmpty() &&
 
 1048            mFacesNeighborhoodToAdd.isEmpty() &&
 
 1049            mFacesToRemove.isEmpty() &&
 
 1050            mFacesNeighborhoodToRemove.isEmpty() &&
 
 1051            mNeighborhoodChanges.isEmpty() &&
 
 1052            mVerticesToAdd.isEmpty() &&
 
 1053            mVertexToFaceToAdd.isEmpty() &&
 
 1054            mVerticesToRemoveIndexes.isEmpty() &&
 
 1055            mRemovedVertices.isEmpty() &&
 
 1056            mVerticesToFaceRemoved.isEmpty() &&
 
 1057            mVerticesToFaceChanges.isEmpty() &&
 
 1058            mChangeCoordinateVerticesIndexes.isEmpty() &&
 
 1059            mNewZValues.isEmpty() &&
 
 1060            mOldZValues.isEmpty() &&
 
 1061            mNewXYValues.isEmpty() &&
 
 1062            mOldXYValues.isEmpty() &&
 
 1063            mNativeFacesIndexesGeometryChanged.isEmpty() );
 
 1068   return mVerticesToRemoveIndexes;
 
 1071 int QgsTopologicalMesh::Changes::addedFaceIndexInMesh( 
int internalIndex )
 const 
 1073   if ( internalIndex == -1 )
 
 1076   return internalIndex + mAddedFacesFirstIndex;
 
 1079 int QgsTopologicalMesh::Changes::removedFaceIndexInMesh( 
int internalIndex )
 const 
 1081   if ( internalIndex == -1 )
 
 1084   return mFaceIndexesToRemove.at( internalIndex );
 
 1089   mAddedFacesFirstIndex = 0;
 
 1090   mFaceIndexesToRemove.clear();
 
 1091   mFacesToAdd.clear();
 
 1092   mFacesNeighborhoodToAdd.clear();
 
 1093   mFacesToRemove.clear();
 
 1094   mFacesNeighborhoodToRemove.clear();
 
 1095   mNeighborhoodChanges.clear();
 
 1097   mVerticesToAdd.clear();
 
 1098   mVertexToFaceToAdd.clear();
 
 1099   mVerticesToRemoveIndexes.clear();
 
 1100   mRemovedVertices.clear();
 
 1101   mVerticesToFaceRemoved.clear();
 
 1102   mVerticesToFaceChanges.clear();
 
 1104   mChangeCoordinateVerticesIndexes.clear();
 
 1105   mNewZValues.clear();
 
 1106   mOldZValues.clear();
 
 1107   mNewXYValues.clear();
 
 1108   mOldXYValues.clear();
 
 1109   mNativeFacesIndexesGeometryChanged.clear();
 
 1119   mVertexToFace.append( -1 );
 
 1120   referenceAsFreeVertex( mMesh->
vertices.count() - 1 );
 
 1126 static double vertexPolygonOrientation( 
const QgsMesh &
mesh, 
const QList<int> &vertexIndexes )
 
 1128   if ( vertexIndexes.count() < 3 )
 
 1131   int hullDomainVertexPos = -1;
 
 1132   double xMin = std::numeric_limits<double>::max();
 
 1133   double yMin = std::numeric_limits<double>::max();
 
 1134   for ( 
int i = 0; i < vertexIndexes.count(); ++i )
 
 1137     if ( xMin >= vertex.
x() && yMin > vertex.
y() )
 
 1139       hullDomainVertexPos = i;
 
 1145   if ( hullDomainVertexPos >= 0 )
 
 1147     int iv1 = vertexIndexes.at( ( hullDomainVertexPos - 1 + vertexIndexes.count() ) % vertexIndexes.count() );
 
 1148     int iv2 = vertexIndexes.at( ( hullDomainVertexPos + 1 ) % vertexIndexes.count() );
 
 1149     int ivc = vertexIndexes.at( ( hullDomainVertexPos ) );
 
 1150     double cp = crossProduct( ivc, iv1, iv2, 
mesh );
 
 1159   if ( vertexIndex >= mVertexToFace.count() )
 
 1162   if ( mVertexToFace.at( vertexIndex ) == -1 ) 
 
 1168     dereferenceAsFreeVertex( vertexIndex );
 
 1176   QList<int> boundariesVertexIndex;
 
 1177   QList<int> associateFaceToBoundaries;
 
 1178   QList<int> removedFacesIndexes;
 
 1179   QSet<int> boundaryInGlobalMesh;
 
 1185     Q_ASSERT( !mMesh->
vertices.at( boundariesVertexIndex.last() ).isEmpty() );
 
 1187     associateFaceToBoundaries.append( mFacesNeighborhood.at( circulator.
currentFaceIndex() ).at(
 
 1188                                         vertexPositionInFace( boundariesVertexIndex.last(), currentFace ) ) );
 
 1190     if ( currentFace.count() > 3 ) 
 
 1192       int posInface = vertexPositionInFace( vertexIndex, currentFace );
 
 1193       for ( 
int i = 2; i < currentFace.count() - 1; ++i )
 
 1195         boundariesVertexIndex.append( currentFace.at( ( posInface + i ) % currentFace.count() ) );
 
 1196         Q_ASSERT( !mMesh->
vertices.at( boundariesVertexIndex.last() ).isEmpty() );
 
 1197         associateFaceToBoundaries.append( mFacesNeighborhood.at( circulator.
currentFaceIndex() ).at(
 
 1198                                             vertexPositionInFace( boundariesVertexIndex.last(), currentFace ) ) );
 
 1204   bool boundaryFill = 
false;
 
 1207     boundaryFill = 
true;
 
 1211     boundariesVertexIndex.append( lastVertexIndex );
 
 1220       boundaryFill = 
false; 
 
 1223       associateFaceToBoundaries.append( -1 );
 
 1225     for ( 
const int index : std::as_const( boundariesVertexIndex ) )
 
 1228         boundaryInGlobalMesh.insert( index );
 
 1232   int currentVertexToFace = mVertexToFace.at( vertexIndex );
 
 1236   QList<QList<int>> holes;
 
 1237   QList<QList<int>> associateMeshFacesToHoles;
 
 1239   bool cancelOperation = 
false;
 
 1247     int finalPos = boundariesVertexIndex.count() - 1;
 
 1248     QList<int> uncoveredVertex;
 
 1250     QList<int> partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
 
 1251     QList<int> associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
 
 1252     while ( startPos < finalPos && !partToCheck.isEmpty() )
 
 1255       int secondPos = partToCheck.count() - 1;
 
 1256       const QgsPoint &closingSegmentExtremety1 = mMesh->
vertex( partToCheck.at( 0 ) );
 
 1257       const QgsPoint &closingSegmentExtremety2 = mMesh->
vertex( partToCheck.last() );
 
 1258       bool isEdgeIntersect = 
false;
 
 1259       for ( 
int i = 1; i < secondPos - 1; ++i )
 
 1263         bool isLineIntersection;
 
 1266         if ( isEdgeIntersect )
 
 1270       int index = partToCheck.at( 0 );
 
 1271       if ( boundaryInGlobalMesh.contains( index ) && index != boundariesVertexIndex.at( 0 ) )
 
 1273         cancelOperation = 
true;
 
 1279       if ( isEdgeIntersect || vertexPolygonOrientation( *mMesh, partToCheck ) >= 0 )
 
 1281         partToCheck.removeLast();
 
 1282         associateFacePart.removeAt( associateFacePart.count() - 2 );
 
 1283         if ( partToCheck.count() == 1 )
 
 1285           uncoveredVertex.append( index );
 
 1286           startPos = startPos + 1;
 
 1287           partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
 
 1288           associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
 
 1294         holes.append( partToCheck );
 
 1295         associateMeshFacesToHoles.append( associateFacePart );
 
 1297         startPos = startPos + partToCheck.count() - 1;
 
 1298         uncoveredVertex.append( partToCheck.at( 0 ) );
 
 1299         partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
 
 1300         associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
 
 1306     holes.append( boundariesVertexIndex );
 
 1307     associateMeshFacesToHoles.append( associateFaceToBoundaries );
 
 1310   if ( cancelOperation )
 
 1316   Q_ASSERT( holes.count() == associateMeshFacesToHoles.count() );
 
 1322   dereferenceAsFreeVertex( vertexIndex );
 
 1324   mVertexToFace[vertexIndex] = -1;
 
 1327   for ( 
int h = 0; h < holes.count(); ++h )
 
 1329     const QList<int> &holeVertices = holes.at( h );
 
 1330     const QList<int> &associateMeshFacesToHole = associateMeshFacesToHoles.at( h );
 
 1331     QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
 
 1332     std::vector<p2t::Point *> holeToFill( holeVertices.count() );
 
 1335       for ( 
int i = 0; i < holeVertices.count(); ++i )
 
 1338         holeToFill[i] = 
new p2t::Point( vertex.
x(), vertex.
y() );
 
 1339         mapPoly2TriPointToVertex.insert( holeToFill[i], holeVertices.at( i ) );
 
 1342       std::unique_ptr<p2t::CDT> cdt( 
new p2t::CDT( holeToFill ) );
 
 1345       std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
 
 1346       QVector<QgsMeshFace> newFaces( triangles.size() );
 
 1347       for ( 
size_t i = 0; i < triangles.size(); ++i )
 
 1351         for ( 
int j = 0; j < 3; j++ )
 
 1353           int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
 
 1354           if ( vertInd == -1 )
 
 1355             throw std::exception();
 
 1356           Q_ASSERT( !mMesh->
vertices.at( vertInd ).isEmpty() );
 
 1364         throw std::exception();
 
 1365       int newFaceIndexStartIndex = mMesh->
faceCount();
 
 1372       const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
 
 1373       for ( 
const int vtc : verticesToFaceToChange )
 
 1374         if ( mVertexToFace.at( vtc ) == -1 )
 
 1376               mVertexToFace.at( vtc ),
 
 1377               addChanges.addedFaceIndexInMesh( topologicalFaces.mVerticesToFace.values( vtc ).first() ) } );
 
 1381       for ( 
int i = 0; i < topologicalFaces.mFaces.count(); ++i )
 
 1384         faceNeighbors = topologicalFaces.mFacesNeighborhood.at( i );
 
 1385         for ( 
int n = 0; n < faceNeighbors.count(); ++n )
 
 1387           if ( faceNeighbors.at( n ) != -1 )
 
 1388             faceNeighbors[n] += newFaceIndexStartIndex; 
 
 1393       for ( 
int i = 0 ; i < holeVertices.count(); ++i )
 
 1395         int vertexHoleIndex = holeVertices.at( i );
 
 1396         int meshFaceBoundaryIndex = associateMeshFacesToHole.at( i );
 
 1401         int newFaceBoundaryIndexInMesh = circulator.
currentFaceIndex() + newFaceIndexStartIndex;
 
 1403         int positionInNewFaces = vertexPositionInFace( vertexHoleIndex, newFace );
 
 1405         if ( meshFaceBoundaryIndex != -1 )
 
 1408           int positionInMeshFaceBoundary = vertexPositionInFace( *mMesh, vertexHoleIndex, meshFaceBoundaryIndex );
 
 1409           positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.count() ) % meshFace.count(); 
 
 1411           addChanges.
mNeighborhoodChanges.append( {meshFaceBoundaryIndex, positionInMeshFaceBoundary, -1, newFaceBoundaryIndexInMesh} );
 
 1422       for ( 
const std::array<int, 4> &neighborChangeToAdd : std::as_const( addChanges.
mNeighborhoodChanges ) )
 
 1424         bool merged = 
false;
 
 1427           if ( existingNeighborChange.at( 0 ) == neighborChangeToAdd.at( 0 ) &&
 
 1428                existingNeighborChange.at( 1 ) == neighborChangeToAdd.at( 1 ) )
 
 1431             Q_ASSERT( existingNeighborChange.at( 3 ) == neighborChangeToAdd.at( 2 ) );
 
 1432             existingNeighborChange[3] = neighborChangeToAdd.at( 3 );
 
 1439       for ( 
const std::array<int, 3> &verticesToFaceToAdd : std::as_const( addChanges.
mVerticesToFaceChanges ) )
 
 1441         bool merged = 
false;
 
 1444           if ( existingVerticesToFace.at( 0 ) == verticesToFaceToAdd.at( 0 ) )
 
 1447             Q_ASSERT( existingVerticesToFace.at( 2 ) == verticesToFaceToAdd.at( 1 ) );
 
 1448             existingVerticesToFace[2] = verticesToFaceToAdd.at( 2 );
 
 1455       qDeleteAll( holeToFill );
 
 1459       qDeleteAll( holeToFill );
 
 1474   QSet<int> facesIndex;
 
 1476   for ( 
int vertexIndex : vertices )
 
 1483   for ( 
int vertexIndex : vertices )
 
 1485     int currentVertexToFace = mVertexToFace.at( vertexIndex );
 
 1491     dereferenceAsFreeVertex( vertexIndex );
 
 1493     mVertexToFace[vertexIndex] = -1;
 
 1501   QList<int> boundariesToCheckClockwiseInNewFaces = topologicFaces.mBoundaries;
 
 1502   QList<std::array<int, 2>> boundariesToCheckCounterClockwiseInNewFaces; 
 
 1503   QList<int> uniqueSharedVertexBoundary;
 
 1511   while ( !boundariesToCheckClockwiseInNewFaces.isEmpty() )
 
 1513     int boundary = boundariesToCheckClockwiseInNewFaces.takeLast();
 
 1515     const QList<int> &linkedFaces = topologicFaces.mVerticesToFace.values( boundary );
 
 1517     for ( 
int const linkedFace : linkedFaces )
 
 1521       if ( mVertexToFace.at( boundary ) == -1 )
 
 1527       if ( !newFacescirculator.
isValid() )
 
 1541       if ( oppositeVertexCCWInMesh == oppositeVertexInNewFaces ) 
 
 1547         int faceSize = newFaceOnBoundary.size();
 
 1548         int posInNewFace = vertexPositionInFace( boundary, newFaceOnBoundary );
 
 1549         int previousVertexIndex = ( posInNewFace + faceSize - 1 ) % faceSize;
 
 1550         if ( newFaceOnBoundary.at( previousVertexIndex ) == oppositeVertexCCWInMesh )
 
 1558       if ( oppositeVertexCWInMesh == oppositeVertexInNewFaces )
 
 1562       boundariesToCheckCounterClockwiseInNewFaces.append( {boundary, linkedFace} );
 
 1567   while ( !boundariesToCheckCounterClockwiseInNewFaces.isEmpty() )
 
 1569     std::array<int, 2> boundaryLinkedface = boundariesToCheckCounterClockwiseInNewFaces.takeLast();
 
 1570     int boundary = boundaryLinkedface.at( 0 );
 
 1571     int linkedFace = boundaryLinkedface.at( 1 );
 
 1586     if ( oppositeVertexCWInMesh == oppositeVertexInNewFaces ) 
 
 1593     if ( oppositeVertexCCWInMesh == oppositeVertexInNewFaces )
 
 1596     uniqueSharedVertexBoundary.append( boundary );
 
 1599   if ( !uniqueSharedVertexBoundary.isEmpty() )
 
 1603   QSet<int> boundaryVertices = qgis::listToSet( topologicFaces.mBoundaries );
 
 1604   for ( 
const QgsMeshFace &newFace : std::as_const( topologicFaces.mFaces ) )
 
 1606     for ( 
const int vertexIndex : newFace )
 
 1608       if ( boundaryVertices.contains( vertexIndex ) )
 
 1610       if ( mVertexToFace.at( vertexIndex ) != -1 )
 
 1621   mFacesNeighborhood.clear();
 
 1622   mVerticesToFace.clear();
 
 1623   mBoundaries.clear();
 
 1628   return mFacesNeighborhood;
 
 1633   if ( mVerticesToFace.contains( vertexIndex ) )
 
 1634     return mVerticesToFace.values( vertexIndex ).at( 0 );
 
 1642   topologicMesh.mMesh = 
mesh;
 
 1643   topologicMesh.mVertexToFace = QVector<int>( 
mesh->
vertexCount(), -1 );
 
 1644   topologicMesh.mMaximumVerticesPerFace = maxVerticesPerFace;
 
 1651     if ( maxVerticesPerFace != 0 && 
mesh->
face( i ).count() > maxVerticesPerFace )
 
 1669     topologicMesh.mFacesNeighborhood = subMesh.mFacesNeighborhood;
 
 1671     for ( 
int i = 0; i < topologicMesh.mMesh->
vertexCount(); ++i )
 
 1673       if ( topologicMesh.mVertexToFace.at( i ) == -1 )
 
 1674         topologicMesh.mFreeVertices.insert( i );
 
 1678   return topologicMesh;
 
 1683   return createTopologicalFaces( faces, 
nullptr, error, uniqueSharedVertexAllowed );
 
 1688   const QVector<QgsMeshFace> &faces,
 
 1689   QVector<int> *globalVertexToFace,
 
 1691   bool allowUniqueSharedVertex )
 
 1693   int facesCount = faces.count();
 
 1694   QVector<FaceNeighbors> faceTopologies;
 
 1695   QMultiHash<int, int> verticesToFace;
 
 1698   TopologicalFaces ret;
 
 1702   QMap<int, QMap<int, int>> verticesToNeighbor;
 
 1704   for ( 
int faceIndex = 0; faceIndex < facesCount; ++faceIndex )
 
 1707     int faceSize = face.count();
 
 1709     for ( 
int i = 0; i < faceSize; ++i )
 
 1711       int v1 = face[i % faceSize];
 
 1712       int v2 = face[( i + 1 ) % faceSize];
 
 1713       if ( verticesToNeighbor[v2].contains( v1 ) )
 
 1719         verticesToNeighbor[v2].insert( v1, faceIndex );
 
 1723   faceTopologies = QVector<FaceNeighbors>( faces.count() );
 
 1725   QSet<int> boundaryVertices;
 
 1727   for ( 
int faceIndex = 0; faceIndex < facesCount; ++faceIndex )
 
 1730     int faceSize = face.size();
 
 1732     faceTopology.resize( faceSize );
 
 1734     for ( 
int i = 0; i < faceSize; ++i )
 
 1736       int v1 = face.at( i );
 
 1737       int v2 = face.at( ( i + 1 ) % faceSize );
 
 1739       if ( globalVertexToFace )
 
 1741         if ( ( *globalVertexToFace )[v1] == -1 )
 
 1742           ( *globalVertexToFace )[v1] = faceIndex ;
 
 1746         if ( allowUniqueSharedVertex || !verticesToFace.contains( v1 ) )
 
 1747           verticesToFace.insert( v1, faceIndex ) ;
 
 1750       QMap<int, int> &edges = verticesToNeighbor[v1];
 
 1751       if ( edges.contains( v2 ) )
 
 1752         faceTopology[i] = edges.value( v2 );
 
 1755         faceTopology[i] = -1;
 
 1757         if ( !allowUniqueSharedVertex )
 
 1759           if ( boundaryVertices.contains( v1 ) )
 
 1765         boundaryVertices.insert( v1 );
 
 1771   ret.mFacesNeighborhood = faceTopologies;
 
 1772   ret.mBoundaries = boundaryVertices.values();
 
 1773   ret.mVerticesToFace = verticesToFace;
 
 1779   return mFacesNeighborhood.at( faceIndex );
 
 1791   QSet<int> removedFaces = qgis::listToSet( facesIndexes );
 
 1792   QSet<int> concernedFaces = concernedFacesBy( facesIndexes );
 
 1794   for ( 
const int f : std::as_const( removedFaces ) )
 
 1795     concernedFaces.remove( f );
 
 1797   QVector<QgsMeshFace> remainingFaces;
 
 1798   remainingFaces.reserve( concernedFaces.count() );
 
 1799   for ( 
const int f : std::as_const( concernedFaces ) )
 
 1800     remainingFaces.append( mMesh->
face( f ) );
 
 1803   createTopologicalFaces( remainingFaces, 
nullptr, error, 
false );
 
 1815   QSet<int> indexSet = qgis::listToSet( facesIndexesToRemove );
 
 1816   QSet<int> threatedVertex;
 
 1818   for ( 
int i = 0; i < facesIndexesToRemove.count(); ++i )
 
 1820     const int faceIndex = facesIndexesToRemove.at( i );
 
 1823     const FaceNeighbors &neighborhood = mFacesNeighborhood.at( faceIndex );
 
 1825     for ( 
int j = 0; j < face.count(); ++j )
 
 1828       int neighborIndex = neighborhood.at( j );
 
 1829       if ( neighborIndex != -1 && !indexSet.contains( neighborIndex ) )
 
 1831         int positionInNeighbor = mFacesNeighborhood.at( neighborIndex ).indexOf( faceIndex );
 
 1836       int vertexIndex = face.at( j );
 
 1837       if ( !threatedVertex.contains( vertexIndex ) && indexSet.contains( mVertexToFace.at( vertexIndex ) ) )
 
 1839         int oldValue = mVertexToFace.at( vertexIndex );
 
 1842         if ( neighborIndex != -1 && !indexSet.contains( neighborIndex ) ) 
 
 1843           refValue = neighborIndex;
 
 1847           aroundFaces.removeOne( faceIndex );
 
 1848           if ( !aroundFaces.isEmpty() )
 
 1850             while ( !aroundFaces.isEmpty() && refValue == -1 )
 
 1852               if ( !indexSet.contains( aroundFaces.first() ) )
 
 1853                 refValue = aroundFaces.first();
 
 1855                 aroundFaces.removeFirst();
 
 1860         threatedVertex.insert( vertexIndex );
 
 1870 bool QgsTopologicalMesh::eitherSideFacesAndVertices( 
int vertexIndex1,
 
 1874     int &neighborVertex1InFace1,
 
 1875     int &neighborVertex1InFace2,
 
 1876     int &neighborVertex2inFace1,
 
 1877     int &neighborVertex2inFace2 )
 const 
 1919   int oppositeVertexFace1;
 
 1920   int oppositeVertexFace2;
 
 1921   int supposedOppositeVertexFace1;
 
 1922   int supposedoppositeVertexFace2;
 
 1924   bool result = eitherSideFacesAndVertices(
 
 1929                   oppositeVertexFace1,
 
 1930                   supposedoppositeVertexFace2,
 
 1931                   supposedOppositeVertexFace1,
 
 1932                   oppositeVertexFace2 );
 
 1937        oppositeVertexFace1 < 0 ||
 
 1938        oppositeVertexFace2 < 0 ||
 
 1939        supposedOppositeVertexFace1 != oppositeVertexFace1 ||
 
 1940        supposedoppositeVertexFace2 != oppositeVertexFace2 )
 
 1947   if ( face1.count() != 3 || face2.count() != 3 )
 
 1950   double crossProduct1 = crossProduct( vertexIndex1, oppositeVertexFace1, oppositeVertexFace2, *mMesh );
 
 1951   double crossProduct2 = crossProduct( vertexIndex2, oppositeVertexFace1, oppositeVertexFace2, *mMesh );
 
 1953   return crossProduct1 * crossProduct2 < 0;
 
 1960   int oppositeVertexFace1;
 
 1961   int oppositeVertexFace2;
 
 1962   int supposedOppositeVertexFace1;
 
 1963   int supposedoppositeVertexFace2;
 
 1965   bool result = eitherSideFacesAndVertices(
 
 1970                   oppositeVertexFace1,
 
 1971                   supposedoppositeVertexFace2,
 
 1972                   supposedOppositeVertexFace1,
 
 1973                   oppositeVertexFace2 );
 
 1978        oppositeVertexFace1 < 0 ||
 
 1979        oppositeVertexFace2 < 0 ||
 
 1980        supposedOppositeVertexFace1 != oppositeVertexFace1 ||
 
 1981        supposedoppositeVertexFace2 != oppositeVertexFace2 )
 
 1990   Q_ASSERT( face1.count() == 3 );
 
 1991   Q_ASSERT( face2.count() == 3 );
 
 1993   int pos1 = vertexPositionInFace( vertexIndex1, face1 );
 
 1994   int pos2 = vertexPositionInFace( vertexIndex2, face2 );
 
 1996   int neighborFace1 = mFacesNeighborhood.at( faceIndex1 ).at( pos1 );
 
 1997   int posInNeighbor1 = vertexPositionInFace( *mMesh, oppositeVertexFace1, neighborFace1 );
 
 1998   int neighborFace2 = mFacesNeighborhood.at( faceIndex1 ).at( ( pos1 + 1 ) % 3 );
 
 1999   int posInNeighbor2 = vertexPositionInFace( *mMesh, vertexIndex2, neighborFace2 );
 
 2000   int neighborFace3 = mFacesNeighborhood.at( faceIndex2 ).at( pos2 );
 
 2001   int posInNeighbor3 = vertexPositionInFace( *mMesh, oppositeVertexFace2, neighborFace3 );
 
 2002   int neighborFace4 = mFacesNeighborhood.at( faceIndex2 ).at( ( pos2 + 1 ) % 3 );
 
 2003   int posInNeighbor4 = vertexPositionInFace( *mMesh, vertexIndex1, neighborFace4 );
 
 2013   changes.
mFacesToAdd.append( {oppositeVertexFace1, oppositeVertexFace2, vertexIndex1} );
 
 2014   changes.
mFacesToAdd.append( {oppositeVertexFace2, oppositeVertexFace1, vertexIndex2} );
 
 2016                                           mFacesNeighborhood.at( faceIndex2 ).at( ( pos2 + 1 ) % 3 ),
 
 2017                                           mFacesNeighborhood.at( faceIndex1 ).at( pos1 )} );
 
 2019                                           mFacesNeighborhood.at( faceIndex1 ).at( ( pos1 + 1 ) % 3 ),
 
 2020                                           mFacesNeighborhood.at( faceIndex2 ).at( pos2 )} );
 
 2022   if ( neighborFace1 >= 0 )
 
 2023     changes.
mNeighborhoodChanges.append( {neighborFace1, posInNeighbor1, faceIndex1, startIndex} );
 
 2024   if ( neighborFace2 >= 0 )
 
 2025     changes.
mNeighborhoodChanges.append( {neighborFace2, posInNeighbor2, faceIndex1, startIndex + 1} );
 
 2026   if ( neighborFace3 >= 0 )
 
 2027     changes.
mNeighborhoodChanges.append( {neighborFace3, posInNeighbor3, faceIndex2, startIndex + 1} );
 
 2028   if ( neighborFace4 >= 0 )
 
 2029     changes.
mNeighborhoodChanges.append( {neighborFace4, posInNeighbor4, faceIndex2, startIndex} );
 
 2032   if ( mVertexToFace.at( vertexIndex1 ) == faceIndex1 || mVertexToFace.at( vertexIndex1 ) == faceIndex2 )
 
 2034   if ( mVertexToFace.at( vertexIndex2 ) == faceIndex1 || mVertexToFace.at( vertexIndex2 ) == faceIndex2 )
 
 2035     changes.
mVerticesToFaceChanges.append( {vertexIndex2,  mVertexToFace.at( vertexIndex2 ), startIndex + 1} );
 
 2037   if ( mVertexToFace.at( oppositeVertexFace1 ) == faceIndex1 )
 
 2040   if ( mVertexToFace.at( oppositeVertexFace2 ) == faceIndex2 )
 
 2052   int neighborVertex1InFace1;
 
 2053   int neighborVertex1InFace2;
 
 2054   int neighborVertex2inFace1;
 
 2055   int neighborVertex2inFace2;
 
 2057   bool result = eitherSideFacesAndVertices(
 
 2062                   neighborVertex1InFace1,
 
 2063                   neighborVertex1InFace2,
 
 2064                   neighborVertex2inFace1,
 
 2065                   neighborVertex2inFace2 );
 
 2075   if ( face1.count() + face2.count() - 2 > mMaximumVerticesPerFace )
 
 2085   double crossProduct1 = crossProduct( vertexIndex1, neighborVertex1InFace1, neighborVertex1InFace2, *mMesh );
 
 2086   double crossProduct2 = crossProduct( vertexIndex2, neighborVertex2inFace1, neighborVertex2inFace2, *mMesh );
 
 2088   return crossProduct1 * crossProduct2 < 0;
 
 2095   int neighborVertex1InFace1;
 
 2096   int neighborVertex1InFace2;
 
 2097   int neighborVertex2inFace1;
 
 2098   int neighborVertex2inFace2;
 
 2100   bool result = eitherSideFacesAndVertices(
 
 2105                   neighborVertex1InFace1,
 
 2106                   neighborVertex1InFace2,
 
 2107                   neighborVertex2inFace1,
 
 2108                   neighborVertex2inFace2 );
 
 2119   int faceSize1 = face1.count();
 
 2120   int faceSize2 = face2.count();
 
 2122   int pos1 = vertexPositionInFace( vertexIndex1, face1 );
 
 2123   int pos2 = vertexPositionInFace( vertexIndex2, face2 );
 
 2136   for ( 
int i = 0; i < faceSize1 - 1; ++i )
 
 2138     int currentPos = ( pos1 + i ) % faceSize1;
 
 2139     newface.append( face1.at( currentPos ) ); 
 
 2141     int currentNeighbor = mFacesNeighborhood.at( faceIndex1 ).at( currentPos );
 
 2142     newNeighborhood.append( currentNeighbor );
 
 2144     if ( currentNeighbor != -1 )
 
 2146       int currentPosInNeighbor = vertexPositionInFace( *mMesh, face1.at( ( currentPos + 1 ) % faceSize1 ), currentNeighbor );
 
 2147       changes.
mNeighborhoodChanges.append( {currentNeighbor, currentPosInNeighbor, faceIndex1, startIndex} );
 
 2150   for ( 
int i = 0; i < faceSize2 - 1; ++i )
 
 2152     int currentPos = ( pos2 + i ) % faceSize2;
 
 2153     newface.append( face2.at( currentPos ) ); 
 
 2155     int currentNeighbor = mFacesNeighborhood.at( faceIndex2 ).at( currentPos );
 
 2156     newNeighborhood.append( currentNeighbor );
 
 2158     if ( currentNeighbor != -1 )
 
 2160       int currentPosInNeighbor = vertexPositionInFace( *mMesh, face2.at( ( currentPos + 1 ) % faceSize2 ), currentNeighbor );
 
 2161       changes.
mNeighborhoodChanges.append( {currentNeighbor, currentPosInNeighbor, faceIndex2, startIndex} );
 
 2165   for ( 
int i = 0; i < faceSize1; ++i )
 
 2166     if ( mVertexToFace.at( face1.at( i ) ) == faceIndex1 )
 
 2169   for ( 
int i = 0; i < faceSize2; ++i )
 
 2170     if ( mVertexToFace.at( face2.at( i ) ) == faceIndex2 )
 
 2185   return face.count() == 4;
 
 2192   int faceSize = face.count();
 
 2194   Q_ASSERT( faceSize == 4 );
 
 2196   double maxAngle = 0;
 
 2197   int splitVertexPos = -1;
 
 2198   for ( 
int i = 0; i < faceSize; ++i )
 
 2200     QgsVector vect1( mMesh->
vertex( face.at( i ) ) - mMesh->
vertex( face.at( ( i + 1 ) % faceSize ) ) );
 
 2201     QgsVector vect2( mMesh->
vertex( face.at( ( i + 2 ) % faceSize ) ) - mMesh->
vertex( face.at( ( i + 1 ) % faceSize ) ) );
 
 2203     double angle = std::abs( vect1.
angle( vect2 ) );
 
 2205     if ( 
angle > maxAngle )
 
 2208       splitVertexPos = ( i + 1 ) % faceSize;
 
 2214   const QgsMeshFace newFace1 = {face.at( splitVertexPos ),
 
 2215                                 face.at( ( splitVertexPos + 1 ) % faceSize ),
 
 2216                                 face.at( ( splitVertexPos + 2 ) % faceSize )
 
 2219   const QgsMeshFace newFace2 = {face.at( splitVertexPos ),
 
 2220                                 face.at( ( splitVertexPos + 2 ) % faceSize ),
 
 2221                                 face.at( ( splitVertexPos + 3 ) % faceSize )
 
 2224   QVector<int> neighborIndex( faceSize );
 
 2225   QVector<int> posInNeighbor( faceSize );
 
 2227   for ( 
int i = 0; i < faceSize; ++i )
 
 2229     neighborIndex[i] = mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + i ) % faceSize );
 
 2230     posInNeighbor[i] = vertexPositionInFace( *mMesh,  face.at( ( splitVertexPos + i + 1 ) % faceSize ), neighborIndex[i] );
 
 2242                                           mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 1 ) % faceSize ),
 
 2245                                           mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 2 ) % faceSize ),
 
 2246                                           mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 3 ) % faceSize )} );
 
 2248   for ( 
int i = 0; i < faceSize; ++i )
 
 2250     if ( neighborIndex[i] >= 0 )
 
 2251       changes.
mNeighborhoodChanges.append( {neighborIndex[i], posInNeighbor[i], faceIndex, startIndex + int( i / 2 )} );
 
 2253     int vertexIndex = face.at( ( splitVertexPos + i ) % faceSize );
 
 2254     if ( mVertexToFace.at( vertexIndex ) == faceIndex )
 
 2271   mVertexToFace.append( -1 );
 
 2275   const FaceNeighbors includingFaceNeighborhood = mFacesNeighborhood.at( includingFaceIndex );
 
 2276   int includingFaceSize = includingFace.count();
 
 2278   for ( 
int i = 0; i < includingFaceSize; ++i )
 
 2283     face[1] = includingFace.at( i );
 
 2284     face[2] = includingFace.at( ( i + 1 ) % includingFaceSize );
 
 2285     mMesh->
faces.append( face );
 
 2288     int currentVertexIndex = includingFace.at( i );
 
 2289     if ( mVertexToFace.at( currentVertexIndex ) == includingFaceIndex )
 
 2291       int newFaceIndex = mMesh->
faceCount() - 1;
 
 2292       mVertexToFace[currentVertexIndex] = newFaceIndex;
 
 2296     int includingFaceNeighbor = includingFaceNeighborhood.at( i );
 
 2300       includingFaceNeighbor,
 
 2303     mFacesNeighborhood.append( neighbors );
 
 2306     if ( includingFaceNeighbor != -1 )
 
 2308       int indexInNeighbor = vertexPositionInFace( *mMesh, includingFace.at( ( i + 1 ) % includingFaceSize ), includingFaceNeighbor );
 
 2309       int oldValue = mFacesNeighborhood[includingFaceNeighbor][indexInNeighbor];
 
 2321   mVertexToFace[mVertexToFace.count() - 1] = mMesh->
faceCount() - 1;
 
 2336   int newVertexPositionInFace1 = position + 1;
 
 2338   auto triangulate = [
this, &changes]( 
int removedFaceIndex, 
const QgsMeshVertex & newVertex, 
int newVertexPosition, QVector<int> &edgeFacesIndexes )->
bool 
 2344     const int addedVertexIndex = mMesh->
vertexCount();
 
 2347     int localStartIndex = changes.
mFacesToAdd.count();
 
 2349     QVector<int> newBoundary = initialFace;
 
 2350     newBoundary.insert( newVertexPosition, addedVertexIndex );
 
 2354       QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
 
 2355       std::vector<p2t::Point *> faceToFill( newBoundary.count() );
 
 2356       for ( 
int i = 0; i < newBoundary.count(); ++i )
 
 2360         if ( newBoundary.at( i ) == addedVertexIndex )
 
 2363           vert = mMesh->
vertex( newBoundary.at( i ) );
 
 2365         faceToFill[i] = 
new p2t::Point( vert.
x(), vert.
y() );
 
 2366         mapPoly2TriPointToVertex.insert( faceToFill[i], newBoundary.at( i ) );
 
 2369       std::unique_ptr<p2t::CDT> cdt( 
new p2t::CDT( faceToFill ) );
 
 2371       std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
 
 2372       QVector<QgsMeshFace> newFaces( triangles.size() );
 
 2373       for ( 
size_t i = 0; i < triangles.size(); ++i )
 
 2377         for ( 
int j = 0; j < 3; j++ )
 
 2379           int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
 
 2380           if ( vertInd == -1 )
 
 2381             throw std::exception();
 
 2389         throw std::exception();
 
 2395       const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
 
 2396       for ( 
const int vtc : verticesToFaceToChange )
 
 2397         if ( vtc != addedVertexIndex && mVertexToFace.at( vtc ) == removedFaceIndex )
 
 2402           topologicalFaces.
vertexToFace( vtc ) + faceStartGlobalIndex
 
 2406       for ( 
int i = 0; i < topologicalFaces.mFaces.count(); ++i )
 
 2409         for ( 
int n = 0; n < faceNeighbors.count(); ++n )
 
 2411           if ( faceNeighbors.at( n ) != -1 )
 
 2412             faceNeighbors[n] += faceStartGlobalIndex; 
 
 2416       edgeFacesIndexes.resize( 2 );
 
 2418       for ( 
int i = 0 ; i < newBoundary.count(); ++i )
 
 2420         int vertexIndex = newBoundary.at( i );
 
 2423         int newFaceBoundaryLocalIndex = localStartIndex + circulator.
currentFaceIndex();
 
 2425         int newFaceBoundaryIndexInMesh = faceStartGlobalIndex;
 
 2427         int meshFaceBoundaryIndex;
 
 2428         if ( i == newVertexPosition )
 
 2430           meshFaceBoundaryIndex = -1; 
 
 2431           edgeFacesIndexes[0] =  newFaceBoundaryLocalIndex;
 
 2433         else if ( i == ( newVertexPosition + newBoundary.count() - 1 ) % newBoundary.count() )
 
 2435           meshFaceBoundaryIndex = -1; 
 
 2436           edgeFacesIndexes[1] =  newFaceBoundaryLocalIndex;
 
 2439           meshFaceBoundaryIndex = mFacesNeighborhood.at( removedFaceIndex ).at( vertexPositionInFace( vertexIndex, initialFace ) );
 
 2442         int positionInNewFaces = vertexPositionInFace( vertexIndex, newFace );
 
 2444         if ( meshFaceBoundaryIndex != -1 )
 
 2447           int positionInMeshFaceBoundary = vertexPositionInFace( *mMesh, vertexIndex, meshFaceBoundaryIndex );
 
 2448           positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.count() ) % meshFace.count(); 
 
 2451                                                 positionInMeshFaceBoundary,
 
 2453                                                 newFaceBoundaryIndexInMesh +
 
 2460       qDeleteAll( faceToFill );
 
 2470   QVector<int> edgeFacesIndexes;
 
 2471   if ( !triangulate( faceIndex, vertexToInsert, newVertexPositionInFace1, edgeFacesIndexes ) )
 
 2479   int face2Index = mFacesNeighborhood.at( faceIndex ).at( position );
 
 2480   if ( face2Index != -1 )
 
 2483     int vertexPositionInFace2 = vertexPositionInFace( face1.at( position ), face2 );
 
 2484     QVector<int> edgeFacesIndexesFace2;
 
 2485     if ( !triangulate( face2Index, vertexToInsert, vertexPositionInFace2, edgeFacesIndexesFace2 ) )
 
 2490     int pos1InFaceSide1 = vertexPositionInFace( addedVertexIndex, firstFaceSide1 );
 
 2493     int pos2InFaceSide1 = vertexPositionInFace( addedVertexIndex, secondFaceSide1 );
 
 2494     pos2InFaceSide1 = ( pos2InFaceSide1 + secondFaceSide1.size() - 1 ) % secondFaceSide1.size();
 
 2497     int pos1InFaceSide2 = vertexPositionInFace( addedVertexIndex, firstFaceSide2 );
 
 2500     int pos2InFaceSide2 = vertexPositionInFace( addedVertexIndex, secondFaceSide2 );
 
 2501     pos2InFaceSide2 = ( pos2InFaceSide2 + secondFaceSide1.size() - 1 ) % secondFaceSide1.size();
 
 2515   Q_ASSERT( verticesIndexes.count() == newValues.count() );
 
 2518   changes.
mNewZValues.reserve( verticesIndexes.count() );
 
 2519   changes.
mOldZValues.reserve( verticesIndexes.count() );
 
 2520   for ( 
int i = 0; i < verticesIndexes.count(); ++i )
 
 2534   Q_ASSERT( verticesIndexes.count() == newValues.count() );
 
 2537   changes.
mNewXYValues.reserve( verticesIndexes.count() );
 
 2538   changes.
mOldXYValues.reserve( verticesIndexes.count() );
 
 2539   QSet<int> concernedFace;
 
 2540   for ( 
int i = 0; i < verticesIndexes.count(); ++i )
 
 2545     concernedFace.unite( qgis::listToSet( 
facesAroundVertex( verticesIndexes.at( i ) ) ) );
 
@ InvalidFace
An error occurs due to an invalid face (for example, vertex indexes are unordered)
 
@ UniqueSharedVertex
A least two faces share only one vertices.
 
@ ManifoldFace
ManifoldFace.
 
@ InvalidVertex
An error occurs due to an invalid vertex (for example, vertex index is out of range the available ver...
 
@ FlatFace
A flat face is present.
 
static bool segmentIntersection(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q1, const QgsPoint &q2, QgsPoint &intersectionPoint, bool &isIntersection, double tolerance=1e-8, bool acceptImproperIntersection=false) SIP_HOLDGIL
Compute the intersection between two segments.
 
Class that represents an error during mesh editing.
 
Qgis::MeshEditingErrorType errorType
 
Convenient class that turn around a vertex and provide information about faces and vertices.
 
bool isValid() const
Returns whether the vertex circulator is valid.
 
int turnClockwise() const
Turns counter clockwise around the vertex and returns the new current face, -1 if the circulator pass...
 
bool goBoundaryCounterClockwise() const
Sets the circulator on the boundary face turning counter clockwise, return false is there isn't bound...
 
int oppositeVertexCounterClockwise() const
Returns the opposite vertex of the current face and on the edge on the side turning counter clockwise...
 
int turnCounterClockwise() const
Turns counter clockwise around the vertex and returns the new current face, -1 if the circulator pass...
 
int currentFaceIndex() const
Returns the current face index, -1 if the circulator has passed a boundary or circulator is invalid.
 
bool goBoundaryClockwise() const
Sets the circulator on the boundary face turning clockwise, return false is there isn't boundary face...
 
QgsMeshFace currentFace() const
Returns the current face, empty face if the circulator pass a boundary or circulator is invalid.
 
QgsMeshVertexCirculator(const QgsTopologicalMesh &topologicalMesh, int vertexIndex)
Constructor with topologicalMesh and vertexIndex.
 
int oppositeVertexClockwise() const
Returns the opposite vertex of the current face and on the edge on the side turning clockwise.
 
int degree() const
Returns the degree of the vertex, that is the count of other vertices linked.
 
QList< int > facesAround() const
Returns all the faces indexes around the vertex.
 
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
 
A class to represent a 2D point.
 
Point geometry type, with support for z-dimension and m-values.
 
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
 
Class that contains topological differences between two states of a topological mesh,...
 
QList< int > mChangeCoordinateVerticesIndexes
 
QList< int > mVerticesToFaceRemoved
 
void clearChanges()
Clears all changes.
 
QVector< FaceNeighbors > mFacesNeighborhoodToRemove
 
QVector< QgsMeshFace > removedFaces() const
Returns the faces that are removed with this changes.
 
QList< QgsPointXY > mNewXYValues
 
QList< QgsMeshVertex > mRemovedVertices
 
QVector< QgsMeshVertex > addedVertices() const
Returns the added vertices with this changes.
 
QList< std::array< int, 4 > > mNeighborhoodChanges
 
bool isEmpty() const
Returns whether changes are empty, that there is nothing to change.
 
QList< int > mVerticesToRemoveIndexes
 
QList< int > changedCoordinatesVerticesIndexes() const
Returns the indexes of vertices that have changed coordinates.
 
QList< int > mNativeFacesIndexesGeometryChanged
 
QVector< QgsMeshFace > mFacesToAdd
 
QList< int > removedFaceIndexes() const
Returns the indexes of the faces that are removed with this changes.
 
QVector< FaceNeighbors > mFacesNeighborhoodToAdd
 
QList< std::array< int, 3 > > mVerticesToFaceChanges
 
QList< QgsPointXY > mOldXYValues
 
QList< double > newVerticesZValues() const
Returns the new Z values of vertices that have changed their coordinates.
 
QList< double > mNewZValues
 
QVector< QgsMeshVertex > mVerticesToAdd
 
QVector< QgsMeshFace > addedFaces() const
Returns the face that are added with this changes.
 
QList< QgsPointXY > oldVerticesXYValues() const
Returns the old (X,Y) values of vertices that have changed their coordinates.
 
int mAddedFacesFirstIndex
 
QVector< int > mVertexToFaceToAdd
 
QList< int > mFaceIndexesToRemove
 
QList< QgsPointXY > newVerticesXYValues() const
Returns the new (X,Y) values of vertices that have changed their coordinates.
 
QVector< QgsMeshFace > mFacesToRemove
 
QList< double > mOldZValues
 
QList< int > nativeFacesIndexesGeometryChanged() const
Returns a list of the native face indexes that have a geometry changed.
 
QList< int > verticesToRemoveIndexes() const
Returns the indexes of vertices to remove.
 
Class that contains independent faces an topological information about this faces.
 
int vertexToFace(int vertexIndex) const
Returns a face linked to the vertices with index vertexIndex.
 
QVector< FaceNeighbors > facesNeighborhood() const
Returns the face neighborhood of the faces, indexing is local.
 
void clear()
Clears all data contained in the instance.
 
QVector< QgsMeshFace > meshFaces() const
Returns faces.
 
Class that wraps a QgsMesh to ensure the consistency of the mesh during editing and help to access to...
 
Changes changeZValue(const QList< int > &verticesIndexes, const QList< double > &newValues)
Changes the Z values of the vertices with indexes in vertices indexes with the values in newValues.
 
static QgsTopologicalMesh createTopologicalMesh(QgsMesh *mesh, int maxVerticesPerFace, QgsMeshEditingError &error)
Creates a topologicaly consistent mesh with mesh, this static method modifies mesh to be topological ...
 
bool isVertexFree(int vertexIndex) const
Returns whether the vertex is a free vertex.
 
static QgsMeshEditingError counterClockwiseFaces(QgsMeshFace &face, QgsMesh *mesh)
Checks the topology of the face and sets it counter clockwise if necessary.
 
Changes removeVertexFillHole(int vertexIndex)
Removes the vertex with index vertexIndex.
 
static QgsMeshEditingError checkTopology(const QgsMesh &mesh, int maxVerticesPerFace)
Checks the topology of the mesh mesh, if error occurs, this mesh can't be edited.
 
friend class QgsMeshVertexCirculator
 
void applyChanges(const Changes &changes)
Applies the changes.
 
int firstFaceLinked(int vertexIndex) const
Returns the index of the first face linked, returns -1 if it is a free vertex or out of range index.
 
QgsMeshEditingError facesCanBeRemoved(const QList< int > facesIndexes)
Returns whether faces with index in faceIndexes can be removed/ The method an error object with type ...
 
QgsMeshEditingError checkConsistency() const
Checks the consistency of the topological mesh and return false if there is a consistency issue.
 
Changes removeVertices(const QList< int > &vertices)
Removes all the vertices with index in the list vertices If vertices in linked with faces,...
 
Changes changeXYValue(const QList< int > &verticesIndexes, const QList< QgsPointXY > &newValues)
Changes the (X,Y) values of the vertices with indexes in vertices indexes with the values in newValue...
 
void reindex()
Reindexes faces and vertices, after this operation, the topological mesh can't be edited anymore and ...
 
QVector< int > neighborsOfFace(int faceIndex) const
Returns the indexes of neighbor faces of the face with index faceIndex.
 
QgsMeshEditingError facesCanBeAdded(const TopologicalFaces &topologicalFaces) const
Returns whether the faces can be added to the mesh.
 
bool renumber()
Renumbers the indexes of vertices and faces using the Reverse CutHill McKee Algorithm.
 
Changes flipEdge(int vertexIndex1, int vertexIndex2)
Flips edge (vertexIndex1, vertexIndex2) The method returns a instance of the class QgsTopologicalMesh...
 
QVector< int > FaceNeighbors
 
void reverseChanges(const Changes &changes)
Reverses the changes.
 
Changes addFaces(const TopologicalFaces &topologicFaces)
Adds faces topologicFaces to the topologic mesh.
 
Changes merge(int vertexIndex1, int vertexIndex2)
Merges faces separated by vertices with indexes vertexIndex1 and vertexIndex2 The method returns a in...
 
QList< int > freeVerticesIndexes() const
Returns a list of vertices are not linked to any faces.
 
bool edgeCanBeFlipped(int vertexIndex1, int vertexIndex2) const
Returns true if the edge can be flipped (only available for edge shared by two faces with 3 vertices)
 
Changes addVertexInFace(int faceIndex, const QgsMeshVertex &vertex)
Adds a vertex in the face with index faceIndex.
 
Changes removeFaces(const QList< int > facesIndexes)
Removes faces with index in faceIndexes.
 
bool canBeMerged(int vertexIndex1, int vertexIndex2) const
Returns true if faces separated by vertices with indexes vertexIndex1 and vertexIndex2 can be merged.
 
QList< int > facesAroundVertex(int vertexIndex) const
Returns the indexes of faces that are around the vertex with index vertexIndex.
 
bool canBeSplit(int faceIndex) const
Returns true if face with index faceIndex can be split.
 
Changes addFreeVertex(const QgsMeshVertex &vertex)
Adds a free vertex in the face, that is a vertex tha tis not included or linked with any faces.
 
Changes insertVertexInFacesEdge(int faceIndex, int position, const QgsMeshVertex &vertex)
Inserts a vertex in the edge of face with index faceIndex at position .
 
QgsMesh * mesh() const
Returns a pointer to the wrapped mesh.
 
bool isVertexOnBoundary(int vertexIndex) const
Returns whether the vertex is on a boundary.
 
Changes splitFace(int faceIndex)
Splits face with index faceIndex The method returns a instance of the class QgsTopologicalMesh::Chang...
 
static TopologicalFaces createNewTopologicalFaces(const QVector< QgsMeshFace > &faces, bool uniqueSharedVertexAllowed, QgsMeshEditingError &error)
Creates new topological faces that are not yet included in the mesh.
 
QgsMeshVertexCirculator vertexCirculator(int vertexIndex) const
Returns a vertex circulator linked to this mesh around the vertex with index vertexIndex.
 
A class to represent a vector.
 
double angle() const SIP_HOLDGIL
Returns the angle of the vector in radians.
 
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
 
QVector< int > QgsMeshFace
List of vertex indexes.
 
QgsPoint QgsMeshVertex
xyz coords of vertex
 
Mesh - vertices, edges and faces.
 
int vertexCount() const
Returns number of vertices.
 
QVector< QgsMeshVertex > vertices
 
QgsMeshFace face(int index) const
Returns a face at the index.
 
QVector< QgsMeshFace > faces
 
int faceCount() const
Returns number of faces.
 
QgsMeshVertex vertex(int index) const
Returns a vertex at the index.