27static int vertexPositionInFace( 
int vertexIndex, 
const QgsMeshFace &face )
 
   29  return face.indexOf( vertexIndex );
 
   32static int vertexPositionInFace( 
const QgsMesh &mesh, 
int vertexIndex, 
int faceIndex )
 
   34  if ( faceIndex < 0 || faceIndex >= mesh.
faceCount() )
 
   37  return vertexPositionInFace( vertexIndex, mesh.
face( faceIndex ) );
 
   40static double crossProduct( 
int centralVertex, 
int vertex1, 
int vertex2, 
const QgsMesh &mesh )
 
   46  double ux1 = v1.
x() - vc.
x();
 
   47  double uy1 = v1.
y() - vc.
y();
 
   48  double vx1 = v2.
x() - vc.
x();
 
   49  double vy1 = v2.
y() - vc.
y();
 
   51  return ux1 * vy1 - uy1 * vx1;
 
   56  : mFaces( topologicalMesh.mMesh->faces )
 
   57  , mFacesNeighborhood( topologicalMesh.mFacesNeighborhood )
 
   58  ,  mVertexIndex( vertexIndex )
 
   60  if ( vertexIndex >= 0 && vertexIndex < topologicalMesh.mMesh->vertexCount() )
 
   62    mCurrentFace = topologicalMesh.mVertexToFace[vertexIndex];
 
   63    mIsValid = vertexPositionInFace( *topologicalMesh.
mesh(), vertexIndex, mCurrentFace ) != -1;
 
   71    mLastValidFace = mCurrentFace;
 
   75  : mFaces( topologicalFaces.mFaces )
 
   76  , mFacesNeighborhood( topologicalFaces.mFacesNeighborhood )
 
   77  , mVertexIndex( vertexIndex )
 
   79  const QgsMeshFace &face = topologicalFaces.mFaces.at( faceIndex );
 
   80  mIsValid = vertexPositionInFace( vertexIndex, face ) != -1;
 
   82  mCurrentFace = faceIndex;
 
   83  mLastValidFace = mCurrentFace;
 
   87  : mFaces( topologicalFaces.mFaces )
 
   88  , mFacesNeighborhood( topologicalFaces.mFacesNeighborhood )
 
   89  , mVertexIndex( vertexIndex )
 
   91  if ( topologicalFaces.mVerticesToFace.contains( vertexIndex ) )
 
   92    mCurrentFace = topologicalFaces.mVerticesToFace.values( vertexIndex ).first();
 
   93  mLastValidFace = mCurrentFace;
 
   94  mIsValid = mCurrentFace != -1;
 
   99  if ( mCurrentFace == -1 )
 
  100    mCurrentFace = mLastValidFace;
 
  103    int currentPos = positionInCurrentFace();
 
  104    Q_ASSERT( currentPos != -1 );
 
  108    mLastValidFace = mCurrentFace;
 
  109    mCurrentFace = mFacesNeighborhood.at( mCurrentFace ).at( ( currentPos + faceSize - 1 ) % 
currentFace.count() );
 
  117  if ( mCurrentFace == -1 )
 
  118    mCurrentFace = mLastValidFace;
 
  121    int currentPos = positionInCurrentFace();
 
  122    Q_ASSERT( currentPos != -1 );
 
  126    mLastValidFace = mCurrentFace;
 
  127    mCurrentFace = mFacesNeighborhood.at( mCurrentFace ).at( ( currentPos ) % faceSize );
 
  140  if ( mCurrentFace != -1 )
 
  141    return mFaces.at( mCurrentFace );
 
  151  if ( mCurrentFace == -1 )
 
  152    mCurrentFace = mLastValidFace;
 
  154  int firstFace = mCurrentFace;
 
  157  if ( mCurrentFace == firstFace )
 
  168  if ( mCurrentFace == -1 )
 
  169    mCurrentFace = mLastValidFace;
 
  171  int firstFace = mCurrentFace;
 
  174  if ( mCurrentFace == firstFace )
 
  182  if ( mCurrentFace == -1 )
 
  187  if ( face.isEmpty() )
 
  190  int vertexPosition = vertexPositionInFace( mVertexIndex, 
currentFace() );
 
  192  if ( vertexPosition == -1 )
 
  195  return face.at( ( vertexPosition + 1 ) % face.count() );
 
  200  if ( mCurrentFace == -1 )
 
  205  if ( face.isEmpty() )
 
  208  int vertexPosition = vertexPositionInFace( mVertexIndex, 
currentFace() );
 
  210  if ( vertexPosition == -1 )
 
  213  return face.at( ( vertexPosition - 1 + face.count() ) % face.count() );
 
  227  if ( mCurrentFace != -1 )
 
  228    ret.append( mCurrentFace );
 
  273int QgsMeshVertexCirculator::positionInCurrentFace()
 const 
  275  if ( mCurrentFace < 0 || mCurrentFace > mFaces.count() )
 
  278  return vertexPositionInFace( mVertexIndex, mFaces.at( mCurrentFace ) );
 
  288  for ( 
int i = 0; i < changes.
mFacesToAdd.count(); ++i )
 
  291  for ( 
int boundary : topologicalFaces.mBoundaries )
 
  294    if ( mVertexToFace.at( boundary ) == -1 )
 
  297    const QList<int> &linkedFaces = topologicalFaces.mVerticesToFace.values( boundary );
 
  298    for ( 
int linkedFace : linkedFaces )
 
  304      if ( mVertexToFace.at( oppositeVertexForNewFace ) == -1 )
 
  312      int boundaryPositionInNewFace = vertexPositionInFace( boundary, newFaceBoundary );
 
  314      if ( oppositeVertexForMeshFace != oppositeVertexForNewFace )
 
  326          boundaryPositionInMeshFace,
 
  336  for ( 
int f = 0; f < changes.
mFacesToAdd.count(); ++f )
 
  337    for ( 
int n = 0; n < changes.
mFacesToAdd.at( f ).count(); ++n )
 
  339        changes.
mFacesNeighborhoodToAdd[f][n] = changes.addedFaceIndexInMesh( topologicalFaces.mFacesNeighborhood.at( f ).at( n ) );
 
  341  const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
 
  342  for ( 
const int vtc : verticesToFaceToChange )
 
  343    if ( mVertexToFace.at( vtc ) == -1 )
 
  345                                              mVertexToFace.at( vtc ),
 
  346                                              changes.addedFaceIndexInMesh( topologicalFaces.mVerticesToFace.values( vtc ).first() ) } );
 
  355  int initialVerticesCount = mMesh->
vertices.count();
 
  360    mVertexToFace.resize( newSize );
 
  366    mMesh->
faces.resize( newSize );
 
  367    mFacesNeighborhood.resize( newSize );
 
  373    mFacesNeighborhood[changes.removedFaceIndexInMesh( i )] = 
FaceNeighbors();
 
  379    if ( mVertexToFace.at( vertexIndex ) == -1 )
 
  380      dereferenceAsFreeVertex( vertexIndex );
 
  382    mVertexToFace[vertexIndex] = -1;
 
  390      referenceAsFreeVertex( initialVerticesCount + i );
 
  393  for ( 
int i = 0; i < changes.
mFacesToAdd.count(); ++i )
 
  395    mMesh->
faces[changes.addedFaceIndexInMesh( i )] = changes.
mFacesToAdd.at( i );
 
  401    const int faceIndex = neigborChange.at( 0 );
 
  402    const int positionInFace = neigborChange.at( 1 );
 
  403    const int valueToApply = neigborChange.at( 3 );
 
  404    mFacesNeighborhood[faceIndex][positionInFace] = valueToApply;
 
  409    int vertexIndex = vertexToFaceChange.at( 0 );
 
  410    mVertexToFace[vertexToFaceChange.at( 0 )] = vertexToFaceChange.at( 2 );
 
  412    if ( vertexToFaceChange.at( 2 ) == -1 &&
 
  413         vertexToFaceChange.at( 1 ) != -1 &&
 
  414         !mMesh->
vertices.at( vertexIndex ).isEmpty() )
 
  415      referenceAsFreeVertex( vertexIndex );
 
  417    if ( vertexToFaceChange.at( 1 ) == -1 && vertexToFaceChange.at( 2 ) != -1 )
 
  418      dereferenceAsFreeVertex( vertexIndex );
 
  429      mMesh->
vertices[vertexIndex].setX( pt.
x() );
 
  430      mMesh->
vertices[vertexIndex].setY( pt.
y() );
 
  439    const int faceIndex = neigborChange.at( 0 );
 
  440    const int positionInFace = neigborChange.at( 1 );
 
  441    const int valueToApply = neigborChange.at( 2 );
 
  442    mFacesNeighborhood[faceIndex][positionInFace] = valueToApply;
 
  456    if ( mVertexToFace.at( vertexIndex ) == -1 )
 
  457      referenceAsFreeVertex( vertexIndex );
 
  461  for ( 
int i = 0; i < verticesToFaceChangesCount; ++i )
 
  463    const std::array<int, 3> vertexToFaceChange = changes.
mVerticesToFaceChanges.at( verticesToFaceChangesCount - i - 1 );
 
  464    int vertexIndex = vertexToFaceChange.at( 0 );
 
  465    mVertexToFace[vertexIndex] = vertexToFaceChange.at( 1 );
 
  467    if ( vertexToFaceChange.at( 2 ) == -1 && vertexToFaceChange.at( 1 ) != -1 )
 
  468      dereferenceAsFreeVertex( vertexIndex );
 
  470    if ( vertexToFaceChange.at( 1 ) == -1 &&
 
  471         vertexToFaceChange.at( 2 ) != -1 &&
 
  473      referenceAsFreeVertex( vertexIndex );
 
  479    mMesh->
faces.resize( newSize );
 
  480    mFacesNeighborhood.resize( newSize );
 
  487    for ( 
int i = newSize; i < mMesh->
vertexCount(); ++i )
 
  488      if ( mVertexToFace.at( i ) == -1 )
 
  489        dereferenceAsFreeVertex( i );
 
  492    mVertexToFace.resize( newSize );
 
  503      mMesh->
vertices[vertexIndex].setX( pt.
x() );
 
  504      mMesh->
vertices[vertexIndex].setY( pt.
y() );
 
  514QSet<int> QgsTopologicalMesh::concernedFacesBy( 
const QList<int> faceIndexes )
 const 
  517  for ( 
const int faceIndex : faceIndexes )
 
  520    for ( 
int i = 0; i < face.count(); ++i )
 
  523      faces.unite( QSet< int >( around.begin(), around.end() ) );
 
  529void QgsTopologicalMesh::dereferenceAsFreeVertex( 
int vertexIndex )
 
  531  mFreeVertices.remove( vertexIndex );
 
  534void QgsTopologicalMesh::referenceAsFreeVertex( 
int vertexIndex )
 
  538  mFreeVertices.insert( vertexIndex );
 
  543  for ( 
int faceIndex = 0 ; faceIndex < mMesh->
faces.count( ); ++faceIndex )
 
  546    const FaceNeighbors &neighborhood = mFacesNeighborhood.at( faceIndex );
 
  547    if ( face.count() != neighborhood.count() )
 
  549    for ( 
int i = 0; i < face.count(); ++i )
 
  551      int vertexIndex = face.at( i );
 
  553      if ( mVertexToFace.at( vertexIndex ) == -1 )
 
  556      int neighborIndex = neighborhood.at( i );
 
  557      if ( neighborIndex != -1 )
 
  560        if ( neighborFace.isEmpty() )
 
  562        int neighborSize = neighborFace.size();
 
  563        const FaceNeighbors &neighborhoodOfNeighbor = mFacesNeighborhood.at( neighborIndex );
 
  564        int posInNeighbor = vertexPositionInFace( *mMesh, vertexIndex, neighborIndex );
 
  565        if ( neighborhoodOfNeighbor.isEmpty() || neighborhoodOfNeighbor.at( ( posInNeighbor + neighborSize - 1 ) % neighborSize ) != faceIndex )
 
  571  for ( 
int vertexIndex = 0; vertexIndex < mMesh->
vertexCount(); ++vertexIndex )
 
  573    if ( mVertexToFace.at( vertexIndex ) != -1 )
 
  575      if ( !mMesh->
face( mVertexToFace.at( vertexIndex ) ).contains( vertexIndex ) )
 
  601  if ( vertexIndex < 0 || vertexIndex >= mMesh->
vertexCount() )
 
  603  return mVertexToFace.at( vertexIndex );
 
  618  if ( vertexIndex < 0 || vertexIndex >= mMesh->
vertexCount() )
 
  621  if ( mMesh->
vertices.at( vertexIndex ).isEmpty() )
 
  624  return mVertexToFace.at( vertexIndex ) == -1;
 
  629  return QList<int>( mFreeVertices.begin(), mFreeVertices.end() );
 
  636  int faceSize = face.count();
 
  641  for ( 
int i = 0; i < faceSize; ++i )
 
  644    int iv1 = face[( i + 1 ) % faceSize];
 
  645    int iv2 = face[( i + 2 ) % faceSize];
 
  669    double crossProd = crossProduct( iv1, iv0, iv2, *
mesh ); 
 
  670    if ( direction != 0 && crossProd * direction < 0 )   
 
  672    else if ( crossProd == 0 )
 
  674    else if ( direction == 0 && crossProd != 0 )
 
  675      direction = crossProd / std::fabs( crossProd );
 
  680    for ( 
int i = 0; i < faceSize / 2; ++i )
 
  683      face[i] = face.at( faceSize - i - 1 );
 
  684      face[faceSize - i - 1] = temp;
 
  693  QVector<int> oldToNewIndex( mMesh->
vertices.count(), -1 );
 
  697  while ( oldIndex < verticesTotalCount )
 
  705      oldToNewIndex[oldIndex] = newIndex;
 
  706      if ( oldIndex != newIndex )
 
  708      oldToNewIndex[oldIndex] = newIndex;
 
  718  int facesTotalCount = mMesh->
faceCount();
 
  719  while ( oldIndex < facesTotalCount )
 
  721    if ( mMesh->
face( oldIndex ).isEmpty() )
 
  725      if ( oldIndex != newIndex )
 
  726        mMesh->
faces[newIndex] = mMesh->
faces[oldIndex];
 
  728      for ( 
int i = 0; i < face.count(); ++i )
 
  729        face[i] = oldToNewIndex[face.at( i )];
 
  735  mMesh->
faces.resize( newIndex );
 
  737  mVertexToFace.clear();
 
  738  mFacesNeighborhood.clear();
 
  743  QVector<int> oldToNewVerticesIndexes;
 
  744  if ( !renumberVertices( oldToNewVerticesIndexes ) )
 
  748  QVector<int> oldToNewFacesIndexes;
 
  750  if ( !renumberFaces( oldToNewFacesIndexes ) )
 
  755  QVector<QgsMeshVertex> tempVertices( mMesh->
vertices.count() );
 
  756  for ( 
int i = 0; i < oldToNewVerticesIndexes.count(); ++i )
 
  758    tempVertices[oldToNewVerticesIndexes.at( i )] = mMesh->
vertex( i );
 
  762  QVector<QgsMeshFace> tempFaces( mMesh->
faces.count() );
 
  763  for ( 
int i = 0; i < oldToNewFacesIndexes.count(); ++i )
 
  765    tempFaces[oldToNewFacesIndexes.at( i )] = mMesh->
face( i );
 
  767    QgsMeshFace &face = tempFaces[oldToNewFacesIndexes.at( i )];
 
  769    for ( 
int fi = 0; fi < face.count(); ++fi )
 
  771      face[fi] = oldToNewVerticesIndexes.at( face.at( fi ) );
 
  775  mMesh->
faces = tempFaces;
 
  781bool QgsTopologicalMesh::renumberVertices( QVector<int> &oldToNewIndex )
 const 
  783  std::vector<QgsMeshVertexCirculator> circulators;
 
  784  circulators.reserve( mMesh->
vertices.count() );
 
  785  int minDegree = std::numeric_limits<int>::max();
 
  786  int minDegreeVertex = -1;
 
  789  QSet<int> nonThreadedVertex;
 
  790  oldToNewIndex = QVector<int> ( mMesh->
vertexCount(), -1 );
 
  793    circulators.emplace_back( *
this, i );
 
  795    if ( circulators.back().degree() < minDegree )
 
  797      minDegreeVertex = circulators.size() - 1;
 
  798      minDegree = circulator.
degree();
 
  800    nonThreadedVertex.insert( i );
 
  803  auto sortedNeighbor = [ = ]( QList<int> &neighbors, 
int index )
 
  817      int degree = circulators.at( neighborIndex ).degree();
 
  818      QList<int>::Iterator it = neighbors.begin();
 
  819      while ( it != neighbors.end() )
 
  821        if ( degree <= circulators.at( *it ).degree() )
 
  823          neighbors.insert( it, neighborIndex );
 
  828      if ( it == neighbors.end() )
 
  829        neighbors.append( neighborIndex );
 
  835  int currentVertex = minDegreeVertex;
 
  836  nonThreadedVertex.remove( minDegreeVertex );
 
  838  while ( newIndex < mMesh->vertexCount() )
 
  840    if ( oldToNewIndex[currentVertex] == -1 )
 
  841      oldToNewIndex[currentVertex] = newIndex++;
 
  843    if ( circulators.at( currentVertex ).isValid() )
 
  845      QList<int> neighbors;
 
  846      sortedNeighbor( neighbors, currentVertex );
 
  848      for ( 
const int i : std::as_const( neighbors ) )
 
  849        if ( oldToNewIndex.at( i ) == -1 && nonThreadedVertex.contains( i ) )
 
  852          nonThreadedVertex.remove( i );
 
  856    if ( queue.isEmpty() )
 
  858      if ( nonThreadedVertex.isEmpty() && newIndex < mMesh->vertexCount() )
 
  861      const QList<int> remainingVertex( nonThreadedVertex.constBegin(), nonThreadedVertex.constEnd() );
 
  862      int minRemainingDegree = std::numeric_limits<int>::max();
 
  863      int minRemainingVertex = -1;
 
  864      for ( 
const int i : remainingVertex )
 
  866        int degree = circulators.at( i ).degree();
 
  867        if ( degree < minRemainingDegree )
 
  869          minRemainingDegree = degree;
 
  870          minRemainingVertex = i;
 
  873      currentVertex = minRemainingVertex;
 
  874      nonThreadedVertex.remove( currentVertex );
 
  878      currentVertex = queue.dequeue();
 
  885bool QgsTopologicalMesh::renumberFaces( QVector<int> &oldToNewIndex )
 const 
  888  QSet<int> nonThreadedFaces;
 
  890  oldToNewIndex = QVector<int>( mMesh->
faceCount(), -1 );
 
  892  QVector<int> faceDegrees( mMesh->
faceCount(), 0 );
 
  894  int minDegree = std::numeric_limits<int>::max();
 
  895  int minDegreeFace = -1;
 
  896  for ( 
int faceIndex = 0; faceIndex < mMesh->
faceCount(); ++faceIndex )
 
  898    const FaceNeighbors &neighbors = mFacesNeighborhood.at( faceIndex );
 
  901    for ( 
int n = 0; n < neighbors.size(); ++n )
 
  903      if ( neighbors.at( n ) != -1 )
 
  907    if ( degree < minDegree )
 
  910      minDegreeFace = faceIndex;
 
  913    faceDegrees[faceIndex] = degree;
 
  914    nonThreadedFaces.insert( faceIndex );
 
  918  int currentFace = minDegreeFace;
 
  919  nonThreadedFaces.remove( minDegreeFace );
 
  921  auto sortedNeighbor = [ = ]( QList<int> &neighbors, 
int index )
 
  923    const FaceNeighbors &neighborhood = mFacesNeighborhood.at( index );
 
  925    for ( 
int i = 0; i < neighborhood.count(); ++i )
 
  927      int neighborIndex = neighborhood.at( i );
 
  928      if ( neighborIndex == -1 )
 
  931      int degree = faceDegrees.at( neighborIndex );
 
  932      if ( neighbors.isEmpty() )
 
  933        neighbors.append( neighborIndex );
 
  936        QList<int>::Iterator it = neighbors.begin();
 
  937        while ( it != neighbors.end() )
 
  939          if ( degree <= faceDegrees.at( *it ) )
 
  941            neighbors.insert( it, neighborIndex );
 
  946        if ( it == neighbors.end() )
 
  947          neighbors.append( neighborIndex );
 
  952  while ( newIndex < mMesh->faceCount() )
 
  954    if ( oldToNewIndex[currentFace] == -1 )
 
  955      oldToNewIndex[currentFace] = newIndex++;
 
  957    QList<int> neighbors;
 
  958    sortedNeighbor( neighbors, currentFace );
 
  960    for ( 
const int i : std::as_const( neighbors ) )
 
  961      if ( oldToNewIndex.at( i ) == -1 && nonThreadedFaces.contains( i ) )
 
  964        nonThreadedFaces.remove( i );
 
  967    if ( queue.isEmpty() )
 
  969      if ( nonThreadedFaces.isEmpty() && newIndex < mMesh->faceCount() )
 
  972      const QList<int> remainingFace( nonThreadedFaces.constBegin(), nonThreadedFaces.constEnd() );
 
  973      int minRemainingDegree = std::numeric_limits<int>::max();
 
  974      int minRemainingFace = -1;
 
  975      for ( 
const int i : remainingFace )
 
  977        int degree = faceDegrees.at( i );
 
  978        if ( degree < minRemainingDegree )
 
  980          minRemainingDegree = degree;
 
  981          minRemainingFace = i;
 
  984      currentFace = minRemainingFace;
 
  985      nonThreadedFaces.remove( currentFace );
 
  989      currentFace = queue.dequeue();
 
 1004  return mFacesToRemove;
 
 1009  return mFaceIndexesToRemove;
 
 1014  return mVerticesToAdd;
 
 1019  return mChangeCoordinateVerticesIndexes;
 
 1029  return mNewXYValues;
 
 1034  return mOldXYValues;
 
 1039  return mNativeFacesIndexesGeometryChanged;
 
 1044  return ( mFaceIndexesToRemove.isEmpty() &&
 
 1045           mFacesToAdd.isEmpty() &&
 
 1046           mFacesNeighborhoodToAdd.isEmpty() &&
 
 1047           mFacesToRemove.isEmpty() &&
 
 1048           mFacesNeighborhoodToRemove.isEmpty() &&
 
 1049           mNeighborhoodChanges.isEmpty() &&
 
 1050           mVerticesToAdd.isEmpty() &&
 
 1051           mVertexToFaceToAdd.isEmpty() &&
 
 1052           mVerticesToRemoveIndexes.isEmpty() &&
 
 1053           mRemovedVertices.isEmpty() &&
 
 1054           mVerticesToFaceRemoved.isEmpty() &&
 
 1055           mVerticesToFaceChanges.isEmpty() &&
 
 1056           mChangeCoordinateVerticesIndexes.isEmpty() &&
 
 1057           mNewZValues.isEmpty() &&
 
 1058           mOldZValues.isEmpty() &&
 
 1059           mNewXYValues.isEmpty() &&
 
 1060           mOldXYValues.isEmpty() &&
 
 1061           mNativeFacesIndexesGeometryChanged.isEmpty() );
 
 1066  return mVerticesToRemoveIndexes;
 
 1069int QgsTopologicalMesh::Changes::addedFaceIndexInMesh( 
int internalIndex )
 const 
 1071  if ( internalIndex == -1 )
 
 1074  return internalIndex + mAddedFacesFirstIndex;
 
 1077int QgsTopologicalMesh::Changes::removedFaceIndexInMesh( 
int internalIndex )
 const 
 1079  if ( internalIndex == -1 )
 
 1082  return mFaceIndexesToRemove.at( internalIndex );
 
 1087  mAddedFacesFirstIndex = 0;
 
 1088  mFaceIndexesToRemove.clear();
 
 1089  mFacesToAdd.clear();
 
 1090  mFacesNeighborhoodToAdd.clear();
 
 1091  mFacesToRemove.clear();
 
 1092  mFacesNeighborhoodToRemove.clear();
 
 1093  mNeighborhoodChanges.clear();
 
 1095  mVerticesToAdd.clear();
 
 1096  mVertexToFaceToAdd.clear();
 
 1097  mVerticesToRemoveIndexes.clear();
 
 1098  mRemovedVertices.clear();
 
 1099  mVerticesToFaceRemoved.clear();
 
 1100  mVerticesToFaceChanges.clear();
 
 1102  mChangeCoordinateVerticesIndexes.clear();
 
 1103  mNewZValues.clear();
 
 1104  mOldZValues.clear();
 
 1105  mNewXYValues.clear();
 
 1106  mOldXYValues.clear();
 
 1107  mNativeFacesIndexesGeometryChanged.clear();
 
 1117  mVertexToFace.append( -1 );
 
 1118  referenceAsFreeVertex( mMesh->
vertices.count() - 1 );
 
 1124static double vertexPolygonOrientation( 
const QgsMesh &
mesh, 
const QList<int> &vertexIndexes )
 
 1126  if ( vertexIndexes.count() < 3 )
 
 1129  int hullDomainVertexPos = -1;
 
 1130  double xMin = std::numeric_limits<double>::max();
 
 1131  double yMin = std::numeric_limits<double>::max();
 
 1132  for ( 
int i = 0; i < vertexIndexes.count(); ++i )
 
 1135    if ( xMin >= vertex.
x() && yMin > vertex.
y() )
 
 1137      hullDomainVertexPos = i;
 
 1143  if ( hullDomainVertexPos >= 0 )
 
 1145    int iv1 = vertexIndexes.at( ( hullDomainVertexPos - 1 + vertexIndexes.count() ) % vertexIndexes.count() );
 
 1146    int iv2 = vertexIndexes.at( ( hullDomainVertexPos + 1 ) % vertexIndexes.count() );
 
 1147    int ivc = vertexIndexes.at( ( hullDomainVertexPos ) );
 
 1148    double cp = crossProduct( ivc, iv1, iv2, 
mesh );
 
 1157  if ( vertexIndex >= mVertexToFace.count() )
 
 1160  if ( mVertexToFace.at( vertexIndex ) == -1 ) 
 
 1166    dereferenceAsFreeVertex( vertexIndex );
 
 1174  QList<int> boundariesVertexIndex;
 
 1175  QList<int> associateFaceToBoundaries;
 
 1176  QList<int> removedFacesIndexes;
 
 1177  QSet<int> boundaryInGlobalMesh;
 
 1183    Q_ASSERT( !mMesh->
vertices.at( boundariesVertexIndex.last() ).isEmpty() );
 
 1185    associateFaceToBoundaries.append( mFacesNeighborhood.at( circulator.
currentFaceIndex() ).at(
 
 1186                                        vertexPositionInFace( boundariesVertexIndex.last(), currentFace ) ) );
 
 1188    if ( currentFace.count() > 3 ) 
 
 1190      int posInface = vertexPositionInFace( vertexIndex, currentFace );
 
 1191      for ( 
int i = 2; i < currentFace.count() - 1; ++i )
 
 1193        boundariesVertexIndex.append( currentFace.at( ( posInface + i ) % currentFace.count() ) );
 
 1194        Q_ASSERT( !mMesh->
vertices.at( boundariesVertexIndex.last() ).isEmpty() );
 
 1195        associateFaceToBoundaries.append( mFacesNeighborhood.at( circulator.
currentFaceIndex() ).at(
 
 1196                                            vertexPositionInFace( boundariesVertexIndex.last(), currentFace ) ) );
 
 1202  bool boundaryFill = 
false;
 
 1205    boundaryFill = 
true;
 
 1209    boundariesVertexIndex.append( lastVertexIndex );
 
 1218      boundaryFill = 
false; 
 
 1221      associateFaceToBoundaries.append( -1 );
 
 1223    for ( 
const int index : std::as_const( boundariesVertexIndex ) )
 
 1226        boundaryInGlobalMesh.insert( index );
 
 1230  int currentVertexToFace = mVertexToFace.at( vertexIndex );
 
 1234  QList<QList<int>> holes;
 
 1235  QList<QList<int>> associateMeshFacesToHoles;
 
 1237  bool cancelOperation = 
false;
 
 1245    int finalPos = boundariesVertexIndex.count() - 1;
 
 1246    QList<int> uncoveredVertex;
 
 1248    QList<int> partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
 
 1249    QList<int> associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
 
 1250    while ( startPos < finalPos && !partToCheck.isEmpty() )
 
 1253      int secondPos = partToCheck.count() - 1;
 
 1254      const QgsPoint &closingSegmentExtremety1 = mMesh->
vertex( partToCheck.at( 0 ) );
 
 1255      const QgsPoint &closingSegmentExtremety2 = mMesh->
vertex( partToCheck.last() );
 
 1256      bool isEdgeIntersect = 
false;
 
 1257      for ( 
int i = 1; i < secondPos - 1; ++i )
 
 1261        bool isLineIntersection;
 
 1264        if ( isEdgeIntersect )
 
 1268      int index = partToCheck.at( 0 );
 
 1269      if ( boundaryInGlobalMesh.contains( index ) && index != boundariesVertexIndex.at( 0 ) )
 
 1271        cancelOperation = 
true;
 
 1277      if ( isEdgeIntersect || vertexPolygonOrientation( *mMesh, partToCheck ) >= 0 )
 
 1279        partToCheck.removeLast();
 
 1280        associateFacePart.removeAt( associateFacePart.count() - 2 );
 
 1281        if ( partToCheck.count() == 1 )
 
 1283          uncoveredVertex.append( index );
 
 1284          startPos = startPos + 1;
 
 1285          partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
 
 1286          associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
 
 1292        holes.append( partToCheck );
 
 1293        associateMeshFacesToHoles.append( associateFacePart );
 
 1295        startPos = startPos + partToCheck.count() - 1;
 
 1296        uncoveredVertex.append( partToCheck.at( 0 ) );
 
 1297        partToCheck = boundariesVertexIndex.mid( startPos, finalPos - startPos + 1 );
 
 1298        associateFacePart = associateFaceToBoundaries.mid( startPos, finalPos - startPos + 1 );
 
 1304    holes.append( boundariesVertexIndex );
 
 1305    associateMeshFacesToHoles.append( associateFaceToBoundaries );
 
 1308  if ( cancelOperation )
 
 1314  Q_ASSERT( holes.count() == associateMeshFacesToHoles.count() );
 
 1320  dereferenceAsFreeVertex( vertexIndex );
 
 1322  mVertexToFace[vertexIndex] = -1;
 
 1325  for ( 
int h = 0; h < holes.count(); ++h )
 
 1327    const QList<int> &holeVertices = holes.at( h );
 
 1328    const QList<int> &associateMeshFacesToHole = associateMeshFacesToHoles.at( h );
 
 1329    QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
 
 1330    std::vector<p2t::Point *> holeToFill( holeVertices.count() );
 
 1333      for ( 
int i = 0; i < holeVertices.count(); ++i )
 
 1336        holeToFill[i] = 
new p2t::Point( vertex.
x(), vertex.
y() );
 
 1337        mapPoly2TriPointToVertex.insert( holeToFill[i], holeVertices.at( i ) );
 
 1340      std::unique_ptr<p2t::CDT> cdt( 
new p2t::CDT( holeToFill ) );
 
 1343      std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
 
 1344      QVector<QgsMeshFace> newFaces( triangles.size() );
 
 1345      for ( 
size_t i = 0; i < triangles.size(); ++i )
 
 1349        for ( 
int j = 0; j < 3; j++ )
 
 1351          int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
 
 1352          if ( vertInd == -1 )
 
 1353            throw std::exception();
 
 1354          Q_ASSERT( !mMesh->
vertices.at( vertInd ).isEmpty() );
 
 1362        throw std::exception();
 
 1363      int newFaceIndexStartIndex = mMesh->
faceCount();
 
 1370      const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
 
 1371      for ( 
const int vtc : verticesToFaceToChange )
 
 1372        if ( mVertexToFace.at( vtc ) == -1 )
 
 1374              mVertexToFace.at( vtc ),
 
 1375              addChanges.addedFaceIndexInMesh( topologicalFaces.mVerticesToFace.values( vtc ).first() ) } );
 
 1379      for ( 
int i = 0; i < topologicalFaces.mFaces.count(); ++i )
 
 1382        faceNeighbors = topologicalFaces.mFacesNeighborhood.at( i );
 
 1383        for ( 
int n = 0; n < faceNeighbors.count(); ++n )
 
 1385          if ( faceNeighbors.at( n ) != -1 )
 
 1386            faceNeighbors[n] += newFaceIndexStartIndex; 
 
 1391      for ( 
int i = 0 ; i < holeVertices.count(); ++i )
 
 1393        int vertexHoleIndex = holeVertices.at( i );
 
 1394        int meshFaceBoundaryIndex = associateMeshFacesToHole.at( i );
 
 1399        int newFaceBoundaryIndexInMesh = circulator.
currentFaceIndex() + newFaceIndexStartIndex;
 
 1401        int positionInNewFaces = vertexPositionInFace( vertexHoleIndex, newFace );
 
 1403        if ( meshFaceBoundaryIndex != -1 )
 
 1406          int positionInMeshFaceBoundary = vertexPositionInFace( *mMesh, vertexHoleIndex, meshFaceBoundaryIndex );
 
 1407          positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.count() ) % meshFace.count(); 
 
 1409          addChanges.
mNeighborhoodChanges.append( {meshFaceBoundaryIndex, positionInMeshFaceBoundary, -1, newFaceBoundaryIndexInMesh} );
 
 1420      for ( 
const std::array<int, 4> &neighborChangeToAdd : std::as_const( addChanges.
mNeighborhoodChanges ) )
 
 1422        bool merged = 
false;
 
 1425          if ( existingNeighborChange.at( 0 ) == neighborChangeToAdd.at( 0 ) &&
 
 1426               existingNeighborChange.at( 1 ) == neighborChangeToAdd.at( 1 ) )
 
 1429            Q_ASSERT( existingNeighborChange.at( 3 ) == neighborChangeToAdd.at( 2 ) );
 
 1430            existingNeighborChange[3] = neighborChangeToAdd.at( 3 );
 
 1437      for ( 
const std::array<int, 3> &verticesToFaceToAdd : std::as_const( addChanges.
mVerticesToFaceChanges ) )
 
 1439        bool merged = 
false;
 
 1442          if ( existingVerticesToFace.at( 0 ) == verticesToFaceToAdd.at( 0 ) )
 
 1445            Q_ASSERT( existingVerticesToFace.at( 2 ) == verticesToFaceToAdd.at( 1 ) );
 
 1446            existingVerticesToFace[2] = verticesToFaceToAdd.at( 2 );
 
 1453      qDeleteAll( holeToFill );
 
 1457      qDeleteAll( holeToFill );
 
 1472  QSet<int> facesIndex;
 
 1474  for ( 
int vertexIndex : vertices )
 
 1477    facesIndex.unite( QSet< int >( faces.begin(), faces.end() ) );
 
 1484  for ( 
int vertexIndex : vertices )
 
 1486    int currentVertexToFace = mVertexToFace.at( vertexIndex );
 
 1492    dereferenceAsFreeVertex( vertexIndex );
 
 1494    mVertexToFace[vertexIndex] = -1;
 
 1502  QList<int> boundariesToCheckClockwiseInNewFaces = topologicFaces.mBoundaries;
 
 1503  QList<std::array<int, 2>> boundariesToCheckCounterClockwiseInNewFaces; 
 
 1504  QList<int> uniqueSharedVertexBoundary;
 
 1512  while ( !boundariesToCheckClockwiseInNewFaces.isEmpty() )
 
 1514    int boundary = boundariesToCheckClockwiseInNewFaces.takeLast();
 
 1516    const QList<int> &linkedFaces = topologicFaces.mVerticesToFace.values( boundary );
 
 1518    for ( 
int const linkedFace : linkedFaces )
 
 1522      if ( mVertexToFace.at( boundary ) == -1 )
 
 1528      if ( !newFacescirculator.
isValid() )
 
 1542      if ( oppositeVertexCCWInMesh == oppositeVertexInNewFaces ) 
 
 1548        int faceSize = newFaceOnBoundary.size();
 
 1549        int posInNewFace = vertexPositionInFace( boundary, newFaceOnBoundary );
 
 1550        int previousVertexIndex = ( posInNewFace + faceSize - 1 ) % faceSize;
 
 1551        if ( newFaceOnBoundary.at( previousVertexIndex ) == oppositeVertexCCWInMesh )
 
 1559      if ( oppositeVertexCWInMesh == oppositeVertexInNewFaces )
 
 1563      boundariesToCheckCounterClockwiseInNewFaces.append( {boundary, linkedFace} );
 
 1568  while ( !boundariesToCheckCounterClockwiseInNewFaces.isEmpty() )
 
 1570    std::array<int, 2> boundaryLinkedface = boundariesToCheckCounterClockwiseInNewFaces.takeLast();
 
 1571    int boundary = boundaryLinkedface.at( 0 );
 
 1572    int linkedFace = boundaryLinkedface.at( 1 );
 
 1587    if ( oppositeVertexCWInMesh == oppositeVertexInNewFaces ) 
 
 1594    if ( oppositeVertexCCWInMesh == oppositeVertexInNewFaces )
 
 1597    uniqueSharedVertexBoundary.append( boundary );
 
 1600  if ( !uniqueSharedVertexBoundary.isEmpty() )
 
 1604  QSet<int> boundaryVertices( topologicFaces.mBoundaries.constBegin(), topologicFaces.mBoundaries.constEnd() );
 
 1605  for ( 
const QgsMeshFace &newFace : std::as_const( topologicFaces.mFaces ) )
 
 1607    for ( 
const int vertexIndex : newFace )
 
 1609      if ( boundaryVertices.contains( vertexIndex ) )
 
 1611      if ( mVertexToFace.at( vertexIndex ) != -1 )
 
 1622  mFacesNeighborhood.clear();
 
 1623  mVerticesToFace.clear();
 
 1624  mBoundaries.clear();
 
 1629  return mFacesNeighborhood;
 
 1634  if ( mVerticesToFace.contains( vertexIndex ) )
 
 1635    return mVerticesToFace.values( vertexIndex ).at( 0 );
 
 1643  topologicMesh.mMesh = 
mesh;
 
 1644  topologicMesh.mVertexToFace = QVector<int>( 
mesh->
vertexCount(), -1 );
 
 1645  topologicMesh.mMaximumVerticesPerFace = maxVerticesPerFace;
 
 1652    if ( maxVerticesPerFace != 0 && 
mesh->
face( i ).count() > maxVerticesPerFace )
 
 1670    topologicMesh.mFacesNeighborhood = subMesh.mFacesNeighborhood;
 
 1672    for ( 
int i = 0; i < topologicMesh.mMesh->
vertexCount(); ++i )
 
 1674      if ( topologicMesh.mVertexToFace.at( i ) == -1 )
 
 1675        topologicMesh.mFreeVertices.insert( i );
 
 1679  return topologicMesh;
 
 1684  return createTopologicalFaces( faces, 
nullptr, error, uniqueSharedVertexAllowed );
 
 1689  const QVector<QgsMeshFace> &faces,
 
 1690  QVector<int> *globalVertexToFace,
 
 1692  bool allowUniqueSharedVertex )
 
 1694  int facesCount = faces.count();
 
 1695  QVector<FaceNeighbors> faceTopologies;
 
 1696  QMultiHash<int, int> verticesToFace;
 
 1699  TopologicalFaces ret;
 
 1703  QMap<int, QMap<int, int>> verticesToNeighbor;
 
 1705  for ( 
int faceIndex = 0; faceIndex < facesCount; ++faceIndex )
 
 1708    int faceSize = face.count();
 
 1710    for ( 
int i = 0; i < faceSize; ++i )
 
 1712      int v1 = face[i % faceSize];
 
 1713      int v2 = face[( i + 1 ) % faceSize];
 
 1714      if ( verticesToNeighbor[v2].contains( v1 ) )
 
 1720        verticesToNeighbor[v2].insert( v1, faceIndex );
 
 1724  faceTopologies = QVector<FaceNeighbors>( faces.count() );
 
 1726  QSet<int> boundaryVertices;
 
 1728  for ( 
int faceIndex = 0; faceIndex < facesCount; ++faceIndex )
 
 1731    int faceSize = face.size();
 
 1733    faceTopology.resize( faceSize );
 
 1735    for ( 
int i = 0; i < faceSize; ++i )
 
 1737      int v1 = face.at( i );
 
 1738      int v2 = face.at( ( i + 1 ) % faceSize );
 
 1740      if ( globalVertexToFace )
 
 1742        if ( ( *globalVertexToFace )[v1] == -1 )
 
 1743          ( *globalVertexToFace )[v1] = faceIndex ;
 
 1747        if ( allowUniqueSharedVertex || !verticesToFace.contains( v1 ) )
 
 1748          verticesToFace.insert( v1, faceIndex ) ;
 
 1751      QMap<int, int> &edges = verticesToNeighbor[v1];
 
 1752      if ( edges.contains( v2 ) )
 
 1753        faceTopology[i] = edges.value( v2 );
 
 1756        faceTopology[i] = -1;
 
 1758        if ( !allowUniqueSharedVertex )
 
 1760          if ( boundaryVertices.contains( v1 ) )
 
 1766        boundaryVertices.insert( v1 );
 
 1772  ret.mFacesNeighborhood = faceTopologies;
 
 1773  ret.mBoundaries = boundaryVertices.values();
 
 1774  ret.mVerticesToFace = verticesToFace;
 
 1780  return mFacesNeighborhood.at( faceIndex );
 
 1792  QSet<int> removedFaces( facesIndexes.begin(), facesIndexes.end() );
 
 1793  QSet<int> concernedFaces = concernedFacesBy( facesIndexes );
 
 1795  for ( 
const int f : std::as_const( removedFaces ) )
 
 1796    concernedFaces.remove( f );
 
 1798  QVector<QgsMeshFace> remainingFaces;
 
 1799  remainingFaces.reserve( concernedFaces.count() );
 
 1800  for ( 
const int f : std::as_const( concernedFaces ) )
 
 1801    remainingFaces.append( mMesh->
face( f ) );
 
 1804  createTopologicalFaces( remainingFaces, 
nullptr, error, 
false );
 
 1816  QSet<int> indexSet( facesIndexesToRemove.begin(), facesIndexesToRemove.end() );
 
 1817  QSet<int> threatedVertex;
 
 1819  for ( 
int i = 0; i < facesIndexesToRemove.count(); ++i )
 
 1821    const int faceIndex = facesIndexesToRemove.at( i );
 
 1824    const FaceNeighbors &neighborhood = mFacesNeighborhood.at( faceIndex );
 
 1826    for ( 
int j = 0; j < face.count(); ++j )
 
 1829      int neighborIndex = neighborhood.at( j );
 
 1830      if ( neighborIndex != -1 && !indexSet.contains( neighborIndex ) )
 
 1832        int positionInNeighbor = mFacesNeighborhood.at( neighborIndex ).indexOf( faceIndex );
 
 1837      int vertexIndex = face.at( j );
 
 1838      if ( !threatedVertex.contains( vertexIndex ) && indexSet.contains( mVertexToFace.at( vertexIndex ) ) )
 
 1840        int oldValue = mVertexToFace.at( vertexIndex );
 
 1843        if ( neighborIndex != -1 && !indexSet.contains( neighborIndex ) ) 
 
 1844          refValue = neighborIndex;
 
 1848          aroundFaces.removeOne( faceIndex );
 
 1849          if ( !aroundFaces.isEmpty() )
 
 1851            while ( !aroundFaces.isEmpty() && refValue == -1 )
 
 1853              if ( !indexSet.contains( aroundFaces.first() ) )
 
 1854                refValue = aroundFaces.first();
 
 1856                aroundFaces.removeFirst();
 
 1861        threatedVertex.insert( vertexIndex );
 
 1871bool QgsTopologicalMesh::eitherSideFacesAndVertices( 
int vertexIndex1,
 
 1875    int &neighborVertex1InFace1,
 
 1876    int &neighborVertex1InFace2,
 
 1877    int &neighborVertex2inFace1,
 
 1878    int &neighborVertex2inFace2 )
 const 
 1920  int oppositeVertexFace1;
 
 1921  int oppositeVertexFace2;
 
 1922  int supposedOppositeVertexFace1;
 
 1923  int supposedoppositeVertexFace2;
 
 1925  bool result = eitherSideFacesAndVertices(
 
 1930                  oppositeVertexFace1,
 
 1931                  supposedoppositeVertexFace2,
 
 1932                  supposedOppositeVertexFace1,
 
 1933                  oppositeVertexFace2 );
 
 1938       oppositeVertexFace1 < 0 ||
 
 1939       oppositeVertexFace2 < 0 ||
 
 1940       supposedOppositeVertexFace1 != oppositeVertexFace1 ||
 
 1941       supposedoppositeVertexFace2 != oppositeVertexFace2 )
 
 1948  if ( face1.count() != 3 || face2.count() != 3 )
 
 1951  double crossProduct1 = crossProduct( vertexIndex1, oppositeVertexFace1, oppositeVertexFace2, *mMesh );
 
 1952  double crossProduct2 = crossProduct( vertexIndex2, oppositeVertexFace1, oppositeVertexFace2, *mMesh );
 
 1954  return crossProduct1 * crossProduct2 < 0;
 
 1961  int oppositeVertexFace1;
 
 1962  int oppositeVertexFace2;
 
 1963  int supposedOppositeVertexFace1;
 
 1964  int supposedoppositeVertexFace2;
 
 1966  bool result = eitherSideFacesAndVertices(
 
 1971                  oppositeVertexFace1,
 
 1972                  supposedoppositeVertexFace2,
 
 1973                  supposedOppositeVertexFace1,
 
 1974                  oppositeVertexFace2 );
 
 1979       oppositeVertexFace1 < 0 ||
 
 1980       oppositeVertexFace2 < 0 ||
 
 1981       supposedOppositeVertexFace1 != oppositeVertexFace1 ||
 
 1982       supposedoppositeVertexFace2 != oppositeVertexFace2 )
 
 1991  Q_ASSERT( face1.count() == 3 );
 
 1992  Q_ASSERT( face2.count() == 3 );
 
 1994  int pos1 = vertexPositionInFace( vertexIndex1, face1 );
 
 1995  int pos2 = vertexPositionInFace( vertexIndex2, face2 );
 
 1997  int neighborFace1 = mFacesNeighborhood.at( faceIndex1 ).at( pos1 );
 
 1998  int posInNeighbor1 = vertexPositionInFace( *mMesh, oppositeVertexFace1, neighborFace1 );
 
 1999  int neighborFace2 = mFacesNeighborhood.at( faceIndex1 ).at( ( pos1 + 1 ) % 3 );
 
 2000  int posInNeighbor2 = vertexPositionInFace( *mMesh, vertexIndex2, neighborFace2 );
 
 2001  int neighborFace3 = mFacesNeighborhood.at( faceIndex2 ).at( pos2 );
 
 2002  int posInNeighbor3 = vertexPositionInFace( *mMesh, oppositeVertexFace2, neighborFace3 );
 
 2003  int neighborFace4 = mFacesNeighborhood.at( faceIndex2 ).at( ( pos2 + 1 ) % 3 );
 
 2004  int posInNeighbor4 = vertexPositionInFace( *mMesh, vertexIndex1, neighborFace4 );
 
 2014  changes.
mFacesToAdd.append( {oppositeVertexFace1, oppositeVertexFace2, vertexIndex1} );
 
 2015  changes.
mFacesToAdd.append( {oppositeVertexFace2, oppositeVertexFace1, vertexIndex2} );
 
 2017                                          mFacesNeighborhood.at( faceIndex2 ).at( ( pos2 + 1 ) % 3 ),
 
 2018                                          mFacesNeighborhood.at( faceIndex1 ).at( pos1 )} );
 
 2020                                          mFacesNeighborhood.at( faceIndex1 ).at( ( pos1 + 1 ) % 3 ),
 
 2021                                          mFacesNeighborhood.at( faceIndex2 ).at( pos2 )} );
 
 2023  if ( neighborFace1 >= 0 )
 
 2024    changes.
mNeighborhoodChanges.append( {neighborFace1, posInNeighbor1, faceIndex1, startIndex} );
 
 2025  if ( neighborFace2 >= 0 )
 
 2026    changes.
mNeighborhoodChanges.append( {neighborFace2, posInNeighbor2, faceIndex1, startIndex + 1} );
 
 2027  if ( neighborFace3 >= 0 )
 
 2028    changes.
mNeighborhoodChanges.append( {neighborFace3, posInNeighbor3, faceIndex2, startIndex + 1} );
 
 2029  if ( neighborFace4 >= 0 )
 
 2030    changes.
mNeighborhoodChanges.append( {neighborFace4, posInNeighbor4, faceIndex2, startIndex} );
 
 2033  if ( mVertexToFace.at( vertexIndex1 ) == faceIndex1 || mVertexToFace.at( vertexIndex1 ) == faceIndex2 )
 
 2035  if ( mVertexToFace.at( vertexIndex2 ) == faceIndex1 || mVertexToFace.at( vertexIndex2 ) == faceIndex2 )
 
 2036    changes.
mVerticesToFaceChanges.append( {vertexIndex2,  mVertexToFace.at( vertexIndex2 ), startIndex + 1} );
 
 2038  if ( mVertexToFace.at( oppositeVertexFace1 ) == faceIndex1 )
 
 2041  if ( mVertexToFace.at( oppositeVertexFace2 ) == faceIndex2 )
 
 2053  int neighborVertex1InFace1;
 
 2054  int neighborVertex1InFace2;
 
 2055  int neighborVertex2inFace1;
 
 2056  int neighborVertex2inFace2;
 
 2058  bool result = eitherSideFacesAndVertices(
 
 2063                  neighborVertex1InFace1,
 
 2064                  neighborVertex1InFace2,
 
 2065                  neighborVertex2inFace1,
 
 2066                  neighborVertex2inFace2 );
 
 2076  if ( face1.count() + face2.count() - 2 > mMaximumVerticesPerFace )
 
 2086  double crossProduct1 = crossProduct( vertexIndex1, neighborVertex1InFace1, neighborVertex1InFace2, *mMesh );
 
 2087  double crossProduct2 = crossProduct( vertexIndex2, neighborVertex2inFace1, neighborVertex2inFace2, *mMesh );
 
 2089  return crossProduct1 * crossProduct2 < 0;
 
 2096  int neighborVertex1InFace1;
 
 2097  int neighborVertex1InFace2;
 
 2098  int neighborVertex2inFace1;
 
 2099  int neighborVertex2inFace2;
 
 2101  bool result = eitherSideFacesAndVertices(
 
 2106                  neighborVertex1InFace1,
 
 2107                  neighborVertex1InFace2,
 
 2108                  neighborVertex2inFace1,
 
 2109                  neighborVertex2inFace2 );
 
 2120  int faceSize1 = face1.count();
 
 2121  int faceSize2 = face2.count();
 
 2123  int pos1 = vertexPositionInFace( vertexIndex1, face1 );
 
 2124  int pos2 = vertexPositionInFace( vertexIndex2, face2 );
 
 2137  for ( 
int i = 0; i < faceSize1 - 1; ++i )
 
 2139    int currentPos = ( pos1 + i ) % faceSize1;
 
 2140    newface.append( face1.at( currentPos ) ); 
 
 2142    int currentNeighbor = mFacesNeighborhood.at( faceIndex1 ).at( currentPos );
 
 2143    newNeighborhood.append( currentNeighbor );
 
 2145    if ( currentNeighbor != -1 )
 
 2147      int currentPosInNeighbor = vertexPositionInFace( *mMesh, face1.at( ( currentPos + 1 ) % faceSize1 ), currentNeighbor );
 
 2148      changes.
mNeighborhoodChanges.append( {currentNeighbor, currentPosInNeighbor, faceIndex1, startIndex} );
 
 2151  for ( 
int i = 0; i < faceSize2 - 1; ++i )
 
 2153    int currentPos = ( pos2 + i ) % faceSize2;
 
 2154    newface.append( face2.at( currentPos ) ); 
 
 2156    int currentNeighbor = mFacesNeighborhood.at( faceIndex2 ).at( currentPos );
 
 2157    newNeighborhood.append( currentNeighbor );
 
 2159    if ( currentNeighbor != -1 )
 
 2161      int currentPosInNeighbor = vertexPositionInFace( *mMesh, face2.at( ( currentPos + 1 ) % faceSize2 ), currentNeighbor );
 
 2162      changes.
mNeighborhoodChanges.append( {currentNeighbor, currentPosInNeighbor, faceIndex2, startIndex} );
 
 2166  for ( 
int i = 0; i < faceSize1; ++i )
 
 2167    if ( mVertexToFace.at( face1.at( i ) ) == faceIndex1 )
 
 2170  for ( 
int i = 0; i < faceSize2; ++i )
 
 2171    if ( mVertexToFace.at( face2.at( i ) ) == faceIndex2 )
 
 2186  return face.count() == 4;
 
 2193  int faceSize = face.count();
 
 2195  Q_ASSERT( faceSize == 4 );
 
 2197  double maxAngle = 0;
 
 2198  int splitVertexPos = -1;
 
 2199  for ( 
int i = 0; i < faceSize; ++i )
 
 2201    QgsVector vect1( mMesh->
vertex( face.at( i ) ) - mMesh->
vertex( face.at( ( i + 1 ) % faceSize ) ) );
 
 2202    QgsVector vect2( mMesh->
vertex( face.at( ( i + 2 ) % faceSize ) ) - mMesh->
vertex( face.at( ( i + 1 ) % faceSize ) ) );
 
 2204    double angle = std::abs( vect1.
angle( vect2 ) );
 
 2206    if ( 
angle > maxAngle )
 
 2209      splitVertexPos = ( i + 1 ) % faceSize;
 
 2215  const QgsMeshFace newFace1 = {face.at( splitVertexPos ),
 
 2216                                face.at( ( splitVertexPos + 1 ) % faceSize ),
 
 2217                                face.at( ( splitVertexPos + 2 ) % faceSize )
 
 2220  const QgsMeshFace newFace2 = {face.at( splitVertexPos ),
 
 2221                                face.at( ( splitVertexPos + 2 ) % faceSize ),
 
 2222                                face.at( ( splitVertexPos + 3 ) % faceSize )
 
 2225  QVector<int> neighborIndex( faceSize );
 
 2226  QVector<int> posInNeighbor( faceSize );
 
 2228  for ( 
int i = 0; i < faceSize; ++i )
 
 2230    neighborIndex[i] = mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + i ) % faceSize );
 
 2231    posInNeighbor[i] = vertexPositionInFace( *mMesh,  face.at( ( splitVertexPos + i + 1 ) % faceSize ), neighborIndex[i] );
 
 2243                                          mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 1 ) % faceSize ),
 
 2246                                          mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 2 ) % faceSize ),
 
 2247                                          mFacesNeighborhood.at( faceIndex ).at( ( splitVertexPos + 3 ) % faceSize )} );
 
 2249  for ( 
int i = 0; i < faceSize; ++i )
 
 2251    if ( neighborIndex[i] >= 0 )
 
 2252      changes.
mNeighborhoodChanges.append( {neighborIndex[i], posInNeighbor[i], faceIndex, startIndex + int( i / 2 )} );
 
 2254    int vertexIndex = face.at( ( splitVertexPos + i ) % faceSize );
 
 2255    if ( mVertexToFace.at( vertexIndex ) == faceIndex )
 
 2272  mVertexToFace.append( -1 );
 
 2276  const FaceNeighbors includingFaceNeighborhood = mFacesNeighborhood.at( includingFaceIndex );
 
 2277  int includingFaceSize = includingFace.count();
 
 2279  for ( 
int i = 0; i < includingFaceSize; ++i )
 
 2284    face[1] = includingFace.at( i );
 
 2285    face[2] = includingFace.at( ( i + 1 ) % includingFaceSize );
 
 2286    mMesh->
faces.append( face );
 
 2289    int currentVertexIndex = includingFace.at( i );
 
 2290    if ( mVertexToFace.at( currentVertexIndex ) == includingFaceIndex )
 
 2292      int newFaceIndex = mMesh->
faceCount() - 1;
 
 2293      mVertexToFace[currentVertexIndex] = newFaceIndex;
 
 2297    int includingFaceNeighbor = includingFaceNeighborhood.at( i );
 
 2301      includingFaceNeighbor,
 
 2304    mFacesNeighborhood.append( neighbors );
 
 2307    if ( includingFaceNeighbor != -1 )
 
 2309      int indexInNeighbor = vertexPositionInFace( *mMesh, includingFace.at( ( i + 1 ) % includingFaceSize ), includingFaceNeighbor );
 
 2310      int oldValue = mFacesNeighborhood[includingFaceNeighbor][indexInNeighbor];
 
 2322  mVertexToFace[mVertexToFace.count() - 1] = mMesh->
faceCount() - 1;
 
 2337  int newVertexPositionInFace1 = position + 1;
 
 2339  auto triangulate = [
this, &changes]( 
int removedFaceIndex, 
const QgsMeshVertex & newVertex, 
int newVertexPosition, QVector<int> &edgeFacesIndexes )->
bool 
 2345    const int addedVertexIndex = mMesh->
vertexCount();
 
 2348    int localStartIndex = changes.
mFacesToAdd.count();
 
 2350    QVector<int> newBoundary = initialFace;
 
 2351    newBoundary.insert( newVertexPosition, addedVertexIndex );
 
 2355      QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
 
 2356      std::vector<p2t::Point *> faceToFill( newBoundary.count() );
 
 2357      for ( 
int i = 0; i < newBoundary.count(); ++i )
 
 2361        if ( newBoundary.at( i ) == addedVertexIndex )
 
 2364          vert = mMesh->
vertex( newBoundary.at( i ) );
 
 2366        faceToFill[i] = 
new p2t::Point( vert.
x(), vert.
y() );
 
 2367        mapPoly2TriPointToVertex.insert( faceToFill[i], newBoundary.at( i ) );
 
 2370      std::unique_ptr<p2t::CDT> cdt( 
new p2t::CDT( faceToFill ) );
 
 2372      std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
 
 2373      QVector<QgsMeshFace> newFaces( triangles.size() );
 
 2374      for ( 
size_t i = 0; i < triangles.size(); ++i )
 
 2378        for ( 
int j = 0; j < 3; j++ )
 
 2380          int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
 
 2381          if ( vertInd == -1 )
 
 2382            throw std::exception();
 
 2390        throw std::exception();
 
 2396      const QList<int> &verticesToFaceToChange = topologicalFaces.mVerticesToFace.keys();
 
 2397      for ( 
const int vtc : verticesToFaceToChange )
 
 2398        if ( vtc != addedVertexIndex && mVertexToFace.at( vtc ) == removedFaceIndex )
 
 2403          topologicalFaces.
vertexToFace( vtc ) + faceStartGlobalIndex
 
 2407      for ( 
int i = 0; i < topologicalFaces.mFaces.count(); ++i )
 
 2410        for ( 
int n = 0; n < faceNeighbors.count(); ++n )
 
 2412          if ( faceNeighbors.at( n ) != -1 )
 
 2413            faceNeighbors[n] += faceStartGlobalIndex; 
 
 2417      edgeFacesIndexes.resize( 2 );
 
 2419      for ( 
int i = 0 ; i < newBoundary.count(); ++i )
 
 2421        int vertexIndex = newBoundary.at( i );
 
 2424        int newFaceBoundaryLocalIndex = localStartIndex + circulator.
currentFaceIndex();
 
 2426        int newFaceBoundaryIndexInMesh = faceStartGlobalIndex;
 
 2428        int meshFaceBoundaryIndex;
 
 2429        if ( i == newVertexPosition )
 
 2431          meshFaceBoundaryIndex = -1; 
 
 2432          edgeFacesIndexes[0] =  newFaceBoundaryLocalIndex;
 
 2434        else if ( i == ( newVertexPosition + newBoundary.count() - 1 ) % newBoundary.count() )
 
 2436          meshFaceBoundaryIndex = -1; 
 
 2437          edgeFacesIndexes[1] =  newFaceBoundaryLocalIndex;
 
 2440          meshFaceBoundaryIndex = mFacesNeighborhood.at( removedFaceIndex ).at( vertexPositionInFace( vertexIndex, initialFace ) );
 
 2443        int positionInNewFaces = vertexPositionInFace( vertexIndex, newFace );
 
 2445        if ( meshFaceBoundaryIndex != -1 )
 
 2448          int positionInMeshFaceBoundary = vertexPositionInFace( *mMesh, vertexIndex, meshFaceBoundaryIndex );
 
 2449          positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.count() ) % meshFace.count(); 
 
 2452                                                positionInMeshFaceBoundary,
 
 2454                                                newFaceBoundaryIndexInMesh +
 
 2461      qDeleteAll( faceToFill );
 
 2471  QVector<int> edgeFacesIndexes;
 
 2472  if ( !triangulate( faceIndex, vertexToInsert, newVertexPositionInFace1, edgeFacesIndexes ) )
 
 2480  int face2Index = mFacesNeighborhood.at( faceIndex ).at( position );
 
 2481  if ( face2Index != -1 )
 
 2484    int vertexPositionInFace2 = vertexPositionInFace( face1.at( position ), face2 );
 
 2485    QVector<int> edgeFacesIndexesFace2;
 
 2486    if ( !triangulate( face2Index, vertexToInsert, vertexPositionInFace2, edgeFacesIndexesFace2 ) )
 
 2491    int pos1InFaceSide1 = vertexPositionInFace( addedVertexIndex, firstFaceSide1 );
 
 2494    int pos2InFaceSide1 = vertexPositionInFace( addedVertexIndex, secondFaceSide1 );
 
 2495    pos2InFaceSide1 = ( pos2InFaceSide1 + secondFaceSide1.size() - 1 ) % secondFaceSide1.size();
 
 2498    int pos1InFaceSide2 = vertexPositionInFace( addedVertexIndex, firstFaceSide2 );
 
 2501    int pos2InFaceSide2 = vertexPositionInFace( addedVertexIndex, secondFaceSide2 );
 
 2502    pos2InFaceSide2 = ( pos2InFaceSide2 + secondFaceSide1.size() - 1 ) % secondFaceSide1.size();
 
 2516  Q_ASSERT( verticesIndexes.count() == newValues.count() );
 
 2519  changes.
mNewZValues.reserve( verticesIndexes.count() );
 
 2520  changes.
mOldZValues.reserve( verticesIndexes.count() );
 
 2521  for ( 
int i = 0; i < verticesIndexes.count(); ++i )
 
 2535  Q_ASSERT( verticesIndexes.count() == newValues.count() );
 
 2538  changes.
mNewXYValues.reserve( verticesIndexes.count() );
 
 2539  changes.
mOldXYValues.reserve( verticesIndexes.count() );
 
 2540  QSet<int> concernedFace;
 
 2541  for ( 
int i = 0; i < verticesIndexes.count(); ++i )
 
 2547    concernedFace.unite( QSet< int>( faces.begin(), faces.end() ) );
 
@ InvalidFace
An error occurs due to an invalid face (for example, vertex indexes are unordered)
 
@ UniqueSharedVertex
A least two faces share only one vertices.
 
@ ManifoldFace
ManifoldFace.
 
@ InvalidVertex
An error occurs due to an invalid vertex (for example, vertex index is out of range the available ver...
 
@ FlatFace
A flat face is present.
 
static bool segmentIntersection(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q1, const QgsPoint &q2, QgsPoint &intersectionPoint, bool &isIntersection, double tolerance=1e-8, bool acceptImproperIntersection=false) SIP_HOLDGIL
Compute the intersection between two segments.
 
Class that represents an error during mesh editing.
 
Qgis::MeshEditingErrorType errorType
 
Convenient class that turn around a vertex and provide information about faces and vertices.
 
bool isValid() const
Returns whether the vertex circulator is valid.
 
int turnClockwise() const
Turns counter clockwise around the vertex and returns the new current face, -1 if the circulator pass...
 
bool goBoundaryCounterClockwise() const
Sets the circulator on the boundary face turning counter clockwise, return false is there isn't bound...
 
int oppositeVertexCounterClockwise() const
Returns the opposite vertex of the current face and on the edge on the side turning counter clockwise...
 
int turnCounterClockwise() const
Turns counter clockwise around the vertex and returns the new current face, -1 if the circulator pass...
 
int currentFaceIndex() const
Returns the current face index, -1 if the circulator has passed a boundary or circulator is invalid.
 
bool goBoundaryClockwise() const
Sets the circulator on the boundary face turning clockwise, return false is there isn't boundary face...
 
QgsMeshFace currentFace() const
Returns the current face, empty face if the circulator pass a boundary or circulator is invalid.
 
QgsMeshVertexCirculator(const QgsTopologicalMesh &topologicalMesh, int vertexIndex)
Constructor with topologicalMesh and vertexIndex.
 
int oppositeVertexClockwise() const
Returns the opposite vertex of the current face and on the edge on the side turning clockwise.
 
int degree() const
Returns the degree of the vertex, that is the count of other vertices linked.
 
QList< int > facesAround() const
Returns all the faces indexes around the vertex.
 
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
 
A class to represent a 2D point.
 
Point geometry type, with support for z-dimension and m-values.
 
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
 
Class that contains topological differences between two states of a topological mesh,...
 
QList< int > mChangeCoordinateVerticesIndexes
 
QList< int > mVerticesToFaceRemoved
 
void clearChanges()
Clears all changes.
 
QVector< FaceNeighbors > mFacesNeighborhoodToRemove
 
QVector< QgsMeshFace > removedFaces() const
Returns the faces that are removed with this changes.
 
QList< QgsPointXY > mNewXYValues
 
QList< QgsMeshVertex > mRemovedVertices
 
QVector< QgsMeshVertex > addedVertices() const
Returns the added vertices with this changes.
 
QList< std::array< int, 4 > > mNeighborhoodChanges
 
bool isEmpty() const
Returns whether changes are empty, that there is nothing to change.
 
QList< int > mVerticesToRemoveIndexes
 
QList< int > changedCoordinatesVerticesIndexes() const
Returns the indexes of vertices that have changed coordinates.
 
QList< int > mNativeFacesIndexesGeometryChanged
 
QVector< QgsMeshFace > mFacesToAdd
 
QList< int > removedFaceIndexes() const
Returns the indexes of the faces that are removed with this changes.
 
QVector< FaceNeighbors > mFacesNeighborhoodToAdd
 
QList< std::array< int, 3 > > mVerticesToFaceChanges
 
QList< QgsPointXY > mOldXYValues
 
QList< double > newVerticesZValues() const
Returns the new Z values of vertices that have changed their coordinates.
 
QList< double > mNewZValues
 
QVector< QgsMeshVertex > mVerticesToAdd
 
QVector< QgsMeshFace > addedFaces() const
Returns the face that are added with this changes.
 
QList< QgsPointXY > oldVerticesXYValues() const
Returns the old (X,Y) values of vertices that have changed their coordinates.
 
int mAddedFacesFirstIndex
 
QVector< int > mVertexToFaceToAdd
 
QList< int > mFaceIndexesToRemove
 
QList< QgsPointXY > newVerticesXYValues() const
Returns the new (X,Y) values of vertices that have changed their coordinates.
 
QVector< QgsMeshFace > mFacesToRemove
 
QList< double > mOldZValues
 
QList< int > nativeFacesIndexesGeometryChanged() const
Returns a list of the native face indexes that have a geometry changed.
 
QList< int > verticesToRemoveIndexes() const
Returns the indexes of vertices to remove.
 
Class that contains independent faces an topological information about this faces.
 
int vertexToFace(int vertexIndex) const
Returns a face linked to the vertices with index vertexIndex.
 
QVector< FaceNeighbors > facesNeighborhood() const
Returns the face neighborhood of the faces, indexing is local.
 
void clear()
Clears all data contained in the instance.
 
QVector< QgsMeshFace > meshFaces() const
Returns faces.
 
Class that wraps a QgsMesh to ensure the consistency of the mesh during editing and help to access to...
 
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.