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 ) );
 
   40bool QgsMeshEditForceByLine::edgeIntersection(
 
   43  int &closestSnappedVertex,
 
   50  closestSnappedVertex = -1;
 
   57  double epsilon = std::numeric_limits<double>::epsilon() * mTolerance * mTolerance;
 
   60  bool snapV1 = sqrt( v1.sqrDistToSegment( pt1.x(), pt1.y(), pt2.x(), pt2.y(), minDistPoint, epsilon ) ) < mTolerance;
 
   61  bool snapV2 = sqrt( v2.sqrDistToSegment( pt1.x(), pt1.y(), pt2.x(), pt2.y(), minDistPoint, epsilon ) ) < mTolerance;
 
   63  bool intersectLine = 
false;
 
   65                       mCurrentPointPosition,
 
   67                       triangularMesh->
vertices().at( vertex1 ),
 
   68                       triangularMesh->
vertices().at( vertex2 ),
 
   71                       outAllowed ? mTolerance : 0, true );
 
   73  if ( snapV1 == snapV2 ) 
 
   75    double distance1FromIntersection = v1.
distance( intersectionPoint );
 
   76    double distance2FromIntersection = v2.distance( intersectionPoint );
 
   77    if ( distance1FromIntersection <= distance2FromIntersection )
 
   89  if ( isIntersect && snapV1 )
 
   91    closestSnappedVertex = vertex1;
 
   92    intersectionPoint = triangularMesh->
vertices().at( vertex1 );
 
   95  else if ( isIntersect && snapV2 )
 
   97    closestSnappedVertex = vertex2;
 
   98    intersectionPoint = triangularMesh->
vertices().at( vertex2 );
 
  110                                   QList<int> &holeOnLeft,
 
  111                                   QList<int> &neighborsOnLeft,
 
  112                                   QList<int> &holeOnRight,
 
  113                                   QList<int> &neighborsOnRight )
 
  117  const int faceSize = face.size();
 
  119  int beginPos = vertexPositionInFace( firstVertex, face );
 
  120  int endPos = vertexPositionInFace( secondVertex, face );
 
  123  for ( 
int i = 0; i < faceSize; ++i )
 
  125    int currentPos = ( beginPos + i ) % faceSize;
 
  126    holeOnRight.append( face.at( currentPos ) );
 
  127    if ( currentPos == endPos )
 
  129    neighborsOnRight.append( neighbors.at( currentPos ) );
 
  133  for ( 
int i = 0; i < faceSize; ++i )
 
  135    int currentPos = ( beginPos + faceSize - i ) % faceSize;
 
  136    holeOnLeft.append( face.at( currentPos ) );
 
  137    if ( currentPos == endPos )
 
  139    int neighborPos = ( currentPos + faceSize - 1 ) % faceSize;
 
  140    neighborsOnLeft.append( neighbors.at( neighborPos ) );
 
  146static int cutEdgeFromSnappedVertex( 
QgsMeshEditor *meshEditor,
 
  148                                     int startingSnappedVertex,
 
  150                                     QList<int> &newVerticesOnLeftHole,
 
  151                                     QList<int> &newNeighborsOnLeftHole,
 
  152                                     QList<int> &newVerticesOnRightHole,
 
  153                                     QList<int> &newNeighborsOnRightHole )
 
  157  const int faceSize = face.size();
 
  159  const int beginPos = vertexPositionInFace( startingSnappedVertex, face );
 
  161  const int endPosOnLeft = ( edgePosition + 1 ) % faceSize;
 
  162  const int endPosOnRight = edgePosition;
 
  165  for ( 
int i = 0; i < faceSize; ++i )
 
  167    int currentPos = ( beginPos + faceSize - i ) % faceSize;
 
  168    newVerticesOnLeftHole.append( face.at( currentPos ) );
 
  169    if ( currentPos == endPosOnLeft )
 
  171    int neighborPos = ( currentPos + faceSize - 1 ) % faceSize;
 
  172    newNeighborsOnLeftHole.append( neighbors.at( neighborPos ) );
 
  176  for ( 
int i = 0; i < faceSize; ++i )
 
  178    int currentPos = ( beginPos + i ) % faceSize;
 
  179    newVerticesOnRightHole.append( face.at( currentPos ) );
 
  180    if ( currentPos == endPosOnRight )
 
  182    newNeighborsOnRightHole.append( neighbors.at( currentPos ) );
 
  185  return neighbors.at( edgePosition );
 
  194  mTolerance = tolerance;
 
  195  mNewVertexOnIntersection = newVertexOnIntersection;
 
  196  mFirstPointChecked = 
false;
 
  197  mSecondPointChecked = 
false;
 
  198  mCurrentSnappedVertex = -1;
 
  200  mCurrentPointPosition = mPoint1;
 
  201  mRemovedFaces.clear();
 
  203  mNeighborOnLeft.clear();
 
  204  mHoleOnRight.clear();
 
  205  mNeighborOnRight.clear();
 
  206  mNewVerticesIndexesOnLine.clear();
 
  207  mEndOnPoint2 = 
false;
 
  208  mPoint2VertexIndex = -1;
 
 
  214  mEditor = meshEditor;
 
  216  if ( ! mFirstPointChecked )
 
  218    mFirstPointChecked = 
true;
 
  220    if ( mInterpolateZValueOnMesh )
 
  221      interpolateZValueOnMesh( mPoint1 );
 
  225    int faceCloseEdge = -1;
 
  226    if ( meshEditor->
edgeIsClose( mPoint1, mTolerance, faceCloseEdge, closeEdge ) )
 
  230      int vertexIndex1 = face.at( closeEdge );
 
  231      int vertexIndex2 = face.at( ( closeEdge + 1 ) % face.size() );
 
  240      if ( includdingFace != -1 )
 
  247  if ( ! mSecondPointChecked )
 
  249    mSecondPointChecked = 
true;
 
  250    if ( mInterpolateZValueOnMesh )
 
  251      interpolateZValueOnMesh( mPoint2 );
 
  255    int faceCloseEdge = -1;
 
  256    if ( meshEditor->
edgeIsClose( mPoint2, mTolerance, faceCloseEdge, closeEdge ) )
 
  260      int vertexIndex1 = face.at( closeEdge );
 
  261      int vertexIndex2 = face.at( ( closeEdge + 1 ) % face.size() );
 
  263      bool snap1 = meshEditor->
triangularMesh()->
vertices().at( vertexIndex1 ).distance( mPoint2 ) <= mTolerance ;
 
  264      bool snap2 = meshEditor->
triangularMesh()->
vertices().at( vertexIndex2 ).distance( mPoint2 ) <= mTolerance ;
 
  269        mPoint2VertexIndex = vertexIndex1;
 
  275        mPoint2VertexIndex = vertexIndex2;
 
  293      if ( includdingFace != -1 )
 
  307  if ( buildForcedElements() )
 
  316void QgsMeshEditForceByLine::finish()
 
  321void QgsMeshEditForceByLine::interpolateZValueOnMesh( 
QgsPoint &point )
 const 
  326  if ( includdingFace != -1 )
 
  329    if ( triangleFaceIndex != -1 )
 
  335      double z = QgsMeshLayerUtils::interpolateFromVerticesData( tv1, tv2, tv3, tv1.
z(), tv2.
z(), tv3.
z(), point );
 
  343  double distPoint = point.
distance( otherPoint1 );
 
  344  double totalDistance = otherPoint1.
distance( otherPoint2 );
 
  346  point.
setZ( otherPoint1.
z() + ( otherPoint2.
z() - otherPoint1.
z() )*distPoint / totalDistance );
 
  349bool QgsMeshEditForceByLine::buildForcedElements()
 
  354  QSet<int> treatedFaces;
 
  356  int startingVertexIndex = mesh->
vertices.count();
 
  358  int currentFaceIndex = -1;
 
  359  bool searchOutside = 
false; 
 
  360  QPair<int, int> currentEdge{-1, -1};
 
  362  int currentAddedVertex = -1; 
 
  363  int nextCutFace = -1; 
 
  368    if ( mCurrentSnappedVertex == -1 )
 
  371    if ( currentFaceIndex == leftFace )
 
  372      currentFaceIndex = -1;
 
  374    if ( mCurrentSnappedVertex != -1 && !searchOutside )
 
  377      currentFaceIndex = -1;
 
  378      int previousSnappedVertex = -1;
 
  379      int intersectionFaceIndex = -1;
 
  380      QgsPoint intersectionPoint( 0, 0, 0 );
 
  381      int edgePosition = -1;
 
  383      bool result = searchIntersectionEdgeFromSnappedVertex(
 
  384                      intersectionFaceIndex,
 
  385                      previousSnappedVertex,
 
  386                      mCurrentSnappedVertex,
 
  394        if ( mCurrentSnappedVertex != -1 &&
 
  395             mPoint2.
distance( triangularMesh->
vertices().at( mCurrentSnappedVertex ) ) < mTolerance )
 
  399        searchOutside = 
true;
 
  403        if ( mEndOnPoint2 && mCurrentSnappedVertex == mPoint2VertexIndex )
 
  409        if ( mCurrentSnappedVertex != -1 )
 
  413          buildHolesWithOneFace( mEditor,
 
  414                                 intersectionFaceIndex,
 
  415                                 previousSnappedVertex,
 
  416                                 mCurrentSnappedVertex,
 
  422          mRemovedFaces.append( intersectionFaceIndex );
 
  424          if ( finishForcingLine() )
 
  433          nextCutFace = cutEdgeFromSnappedVertex( mEditor,
 
  434                                                  intersectionFaceIndex,
 
  435                                                  previousSnappedVertex,
 
  442          mRemovedFaces.append( intersectionFaceIndex );
 
  444          int iv1 = mHoleOnLeft.last();
 
  445          int iv2 = mHoleOnRight.last();
 
  447          if ( mNewVertexOnIntersection )
 
  449            currentAddedVertex = startingVertexIndex + 
mVerticesToAdd.count();
 
  451            if ( mInterpolateZValueOnMesh )
 
  452              interpolateZValue( intersectionPoint,
 
  453                                 triangularMesh->
vertices().at( iv1 ),
 
  454                                 triangularMesh->
vertices().at( iv2 ) );
 
  456              interpolateZValue( intersectionPoint, mPoint1, mPoint2 );
 
  460          if ( nextCutFace != -1 )
 
  462            mCurrentSnappedVertex = -1;
 
  463            currentFaceIndex = nextCutFace;
 
  464            currentEdge = {mHoleOnLeft.last(), mHoleOnRight.last()};
 
  469            if ( !mNewVertexOnIntersection )
 
  471              currentAddedVertex = startingVertexIndex + 
mVerticesToAdd.count();
 
  472              if ( mInterpolateZValueOnMesh )
 
  473                interpolateZValue( intersectionPoint,
 
  474                                   triangularMesh->
vertices().at( iv1 ),
 
  475                                   triangularMesh->
vertices().at( iv2 ) );
 
  477                interpolateZValue( intersectionPoint, mPoint1, mPoint2 );
 
  481              mNewVerticesIndexesOnLine.removeLast();
 
  483            mHoleOnLeft.append( currentAddedVertex );
 
  484            mNeighborOnLeft.append( -1 );
 
  485            mHoleOnRight.append( currentAddedVertex );
 
  486            mNeighborOnRight.append( -1 );
 
  488            if ( finishForcingLine() )
 
  493            leftFace = intersectionFaceIndex;
 
  496          mCurrentPointPosition = intersectionPoint;
 
  500    else if ( nextCutFace != -1 )
 
  504      int faceSize = face.size();
 
  506      currentFaceIndex = nextCutFace;
 
  508      mRemovedFaces.append( nextCutFace );
 
  510      int edgePositionOnLeft =  vertexPositionInFace( currentEdge.first, face );
 
  511      int edgePositionOnRight = vertexPositionInFace( currentEdge.second, face );
 
  512      int firstEdgeToTest = vertexPositionInFace( currentEdge.second, face );
 
  514      bool foundSomething = 
false;
 
  516      for ( 
int fi = 0; fi < faceSize; ++fi )
 
  518        int iv1 = face.at( ( firstEdgeToTest + fi ) % faceSize );
 
  519        int iv2 = face.at( ( firstEdgeToTest + fi + 1 ) % faceSize );
 
  521        if ( iv1 == currentEdge.first && iv2 == currentEdge.second )
 
  526        if ( edgeIntersection( iv1, iv2, snapVertex, intersection, 
false ) ||
 
  529          foundSomething = 
true;
 
  531          int endPositionOnRight;
 
  532          int endPositionOnLeft;
 
  534          if ( snapVertex != -1 )
 
  537            endPositionOnRight = vertexPositionInFace( snapVertex, face );
 
  538            endPositionOnLeft = vertexPositionInFace( snapVertex, face );
 
  541            currentEdge = {-1, -1};
 
  542            mCurrentSnappedVertex = snapVertex;
 
  547            endPositionOnLeft = vertexPositionInFace( iv2, face );
 
  548            endPositionOnRight = vertexPositionInFace( iv1, face );
 
  550            nextCutFace = neighbors.at( endPositionOnRight );
 
  552            if ( mNewVertexOnIntersection )
 
  554              currentAddedVertex = startingVertexIndex + 
mVerticesToAdd.count();
 
  556              if ( mInterpolateZValueOnMesh )
 
  557                interpolateZValue( intersection,
 
  558                                   triangularMesh->
vertices().at( iv1 ),
 
  559                                   triangularMesh->
vertices().at( iv2 ) );
 
  561                interpolateZValue( intersection, mPoint1, mPoint2 );
 
  566          int currentPos = edgePositionOnLeft;
 
  567          while ( currentPos != endPositionOnLeft )
 
  569            int nextPos = ( currentPos - 1 + faceSize ) % faceSize;
 
  570            mHoleOnLeft.append( face.at( nextPos ) );
 
  571            int neighborPos = nextPos;
 
  572            mNeighborOnLeft.append( neighbors.at( neighborPos ) );
 
  573            currentPos = nextPos;
 
  576          currentPos = edgePositionOnRight;
 
  577          while ( currentPos != endPositionOnRight )
 
  579            int nextPos = ( currentPos + 1 ) % faceSize;
 
  580            mHoleOnRight.append( face.at( nextPos ) );
 
  581            int neighborPos = ( nextPos + faceSize - 1 ) % faceSize;
 
  582            mNeighborOnRight.append( neighbors.at( neighborPos ) );
 
  583            currentPos = nextPos;
 
  586          mCurrentPointPosition = intersection;
 
  588          if ( snapVertex != -1 )
 
  590            currentEdge = {-1, -1};
 
  592            if ( finishForcingLine() )
 
  594              mIsFinished = mEndOnPoint2 && mPoint2VertexIndex == snapVertex;
 
  603          else if ( nextCutFace == -1 )
 
  606            if ( !mNewVertexOnIntersection )
 
  608              currentAddedVertex = startingVertexIndex + 
mVerticesToAdd.count();
 
  609              if ( mInterpolateZValueOnMesh )
 
  610                interpolateZValue( intersection,
 
  611                                   triangularMesh->
vertices().at( iv1 ),
 
  612                                   triangularMesh->
vertices().at( iv2 ) );
 
  614                interpolateZValue( intersection, mPoint1, mPoint2 );
 
  618              mNewVerticesIndexesOnLine.removeLast();
 
  620            mHoleOnLeft.append( currentAddedVertex );
 
  621            mNeighborOnLeft.append( -1 );
 
  622            mHoleOnRight.append( currentAddedVertex );
 
  623            mNeighborOnRight.append( -1 );
 
  625            if ( finishForcingLine() )
 
  634            currentEdge = {mHoleOnLeft.last(), mHoleOnRight.last()};
 
  640      if ( ! foundSomething )
 
  646    else if ( currentFaceIndex == -1 || searchOutside )
 
  649      const QgsRectangle bbox( mCurrentPointPosition, mPoint2 );
 
  651      int closestFaceIndex = -1;
 
  652      int closestEdge = -1; 
 
  653      int closestSnapVertex = -1;
 
  654      double minimalDistance = std::numeric_limits<double>::max();
 
  655      QgsPoint closestIntersectionPoint( 0, 0, 0 );
 
  656      for ( 
const int candidateFaceIndex : candidateFacesIndexes )
 
  658        if ( candidateFaceIndex == leftFace )
 
  661        if ( treatedFaces.contains( candidateFaceIndex ) ) 
 
  665        const int faceSize = candidateFace.size();
 
  667        for ( 
int i = 0; i < faceSize; ++i )
 
  669          int iv1 = candidateFace.at( i );
 
  670          int iv2 = candidateFace.at( ( i + 1 ) % faceSize );
 
  672          if ( iv1 == mCurrentSnappedVertex || iv2 == mCurrentSnappedVertex )
 
  677          bool isIntersect = edgeIntersection( iv1, iv2, snapVertex, intersectionPoint, 
true );
 
  681            double distance = intersectionPoint.
distance( mCurrentPointPosition );
 
  682            if ( distance < minimalDistance )
 
  684              closestFaceIndex = candidateFaceIndex;
 
  685              closestEdge = candidateFace.at( i );
 
  686              closestSnapVertex = snapVertex;
 
  687              closestIntersectionPoint = intersectionPoint;
 
  688              minimalDistance = distance;
 
  694      if ( closestFaceIndex < 0 || closestEdge < 0 ) 
 
  701        mCurrentSnappedVertex = closestSnapVertex;
 
  702        treatedFaces.insert( closestFaceIndex );
 
  703        searchOutside = 
false;
 
  704        if ( mCurrentSnappedVertex == -1 )
 
  708          currentAddedVertex = startingVertexIndex + 
mVerticesToAdd.count();
 
  710          nextCutFace = closestFaceIndex;
 
  712          mHoleOnRight.append( currentAddedVertex );
 
  713          mHoleOnRight.append( face.at( ( vertexPositionInFace( closestEdge, face ) + 1 ) % face.size() ) );
 
  714          mNeighborOnRight.append( -1 );
 
  717          mHoleOnLeft.append( currentAddedVertex );
 
  718          mHoleOnLeft.append( closestEdge ) ;
 
  719          mNeighborOnLeft.append( -1 );
 
  721          currentEdge = {mHoleOnLeft.last(), mHoleOnRight.last()};
 
  723          if ( mInterpolateZValueOnMesh )
 
  724            interpolateZValue( closestIntersectionPoint,
 
  725                               triangularMesh->
vertices().at( mHoleOnLeft.last() ),
 
  726                               triangularMesh->
vertices().at( mHoleOnRight.last() ) );
 
  728            interpolateZValue( closestIntersectionPoint, mPoint1, mPoint2 );
 
  735    else if ( mCurrentSnappedVertex == -1 ) 
 
  738      double minimalDistance = std::numeric_limits<double>::max();
 
  740      for ( 
int i = 0; i < face.size(); ++i )
 
  743        const double distance = mCurrentPointPosition.
distance( vertex );
 
  744        if ( distance < mTolerance && distance < minimalDistance )
 
  746          minimalDistance = distance;
 
  747          mCurrentSnappedVertex = face.at( i );
 
  750      searchOutside = 
false;
 
  752      if ( mCurrentSnappedVertex == -1 )
 
  758    if ( mCurrentSnappedVertex != -1 )
 
  760      if ( mCurrentSnappedVertex == mPoint2VertexIndex )
 
  765      mCurrentPointPosition = triangularMesh->
vertices().at( mCurrentSnappedVertex );
 
  774bool QgsMeshEditForceByLine::searchIntersectionEdgeFromSnappedVertex
 
  775( 
int &intersectionFaceIndex,
 
  776  int &previousSnappedVertex,
 
  777  int ¤tSnappedVertexIndex,
 
  780  QSet<int> &treatedFaces )
 
  782  previousSnappedVertex = currentSnappedVertexIndex;
 
  783  QSet<int> treatedVertices;
 
  787    treatedVertices.insert( currentSnappedVertexIndex );
 
  790    bool foundSomething = 
false;
 
  791    for ( 
const int faceIndex : std::as_const( facesAround ) )
 
  794      int faceSize = face.size();
 
  795      int vertexPos = vertexPositionInFace( currentSnappedVertexIndex, face );
 
  797      int newSnapVertex = -1;
 
  798      for ( 
int i = 1; i < faceSize - 1; ++i )
 
  800        edgePosition = ( vertexPos + i ) % faceSize ;
 
  801        foundSomething = edgeIntersection( face.at( edgePosition ),
 
  802                                           face.at( ( edgePosition + 1 ) % faceSize ),
 
  807        if ( mEndOnPoint2 && newSnapVertex == mPoint2VertexIndex )
 
  809          mCurrentSnappedVertex = newSnapVertex;
 
  813        if ( newSnapVertex != -1 )
 
  814          foundSomething = ( newSnapVertex != previousSnappedVertex &&
 
  815                             !treatedVertices.contains( newSnapVertex ) );
 
  817        if ( foundSomething )
 
  821      if ( foundSomething )
 
  823        treatedFaces.insert( faceIndex );
 
  824        if ( newSnapVertex != -1 )
 
  826          previousSnappedVertex = currentSnappedVertexIndex;
 
  827          currentSnappedVertexIndex = newSnapVertex;
 
  828          if ( newSnapVertex == face.at( ( vertexPos + 1 ) % faceSize ) || newSnapVertex == face.at( ( vertexPos - 1 + faceSize ) % faceSize ) )
 
  836            intersectionFaceIndex = faceIndex;
 
  842          intersectionFaceIndex = faceIndex;
 
  843          previousSnappedVertex = currentSnappedVertexIndex;
 
  844          currentSnappedVertexIndex = -1;
 
  850    if ( !foundSomething )
 
  857bool QgsMeshEditForceByLine::triangulateHoles(
 
  858  const QList<int> &hole,
 
  859  const QList<int> &neighbors,
 
  861  QList<std::array<int, 2>> &newFacesOnLine,
 
  862  std::array<int, 2> &extremeFaces )
 
  867  for ( 
int i = 0; i < hole.count(); ++i )
 
  869    for ( 
int j = i + 1; j < hole.count(); ++j )
 
  871      if ( hole.at( i ) == hole.at( j ) )
 
  882  std::vector<p2t::Point *> holeToFill;
 
  885    QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
 
  886    holeToFill.resize( hole.count() + mNewVerticesIndexesOnLine.count() );
 
  887    for ( 
int i = 0; i < hole.count(); ++i )
 
  889      int vertexIndex = hole.at( i );
 
  891      if ( vertexIndex < mesh->vertexCount() )
 
  892        vertex = mesh->
vertex( vertexIndex );
 
  896      holeToFill[i] = 
new p2t::Point( vertex.
x(), vertex.
y() );
 
  897      mapPoly2TriPointToVertex.insert( holeToFill[i], vertexIndex );
 
  900    const int verticesOnLineCount = mNewVerticesIndexesOnLine.count();
 
  901    for ( 
int i = 0; i < verticesOnLineCount; ++i )
 
  903      int vertexLocalIndex = mNewVerticesIndexesOnLine.at( verticesOnLineCount - i - 1 );
 
  905      holeToFill[i + hole.count()] = 
new p2t::Point( vertex.
x(), vertex.
y() );
 
  906      mapPoly2TriPointToVertex.insert( holeToFill[i + hole.count()], vertexLocalIndex + mesh->
vertexCount() );
 
  909    std::unique_ptr<p2t::CDT> cdt( 
new p2t::CDT( holeToFill ) );
 
  911    std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
 
  912    QVector<QgsMeshFace> newFaces( triangles.size() );
 
  913    for ( 
size_t i = 0; i < triangles.size(); ++i )
 
  917      for ( 
int j = 0; j < 3; j++ )
 
  919        int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
 
  921          throw std::exception();
 
  929      throw std::exception();
 
  931    const QVector<QgsMeshFace> &facesToAdd = topologicalFaces.
meshFaces();
 
  935    for ( 
const int vtc : hole )
 
  938      if ( mRemovedFaces.contains( firstLinkedFace ) )
 
  943    for ( 
int i = 0; i < facesToAdd.count(); ++i )
 
  947      for ( 
int n = 0; n < faceNeighbors.count(); ++n )
 
  949        if ( faceNeighbors.at( n ) != -1 )
 
  950          faceNeighbors[n] += startingFaceGlobalIndex; 
 
  955    for ( 
int i = 0 ; i < hole.count() - 1; ++i )
 
  957      int vertexHoleIndex = hole.at( i );
 
  958      int meshFaceBoundaryIndex = neighbors.at( i );
 
  962        throw std::exception();
 
  970      int newFaceBoundaryIndexInMesh = circulator.
currentFaceIndex() + startingFaceGlobalIndex;
 
  972      int positionInNewFaces = vertexPositionInFace( vertexHoleIndex, newFace );
 
  974        positionInNewFaces = ( positionInNewFaces - 1 + newFace.size() ) % newFace.size(); 
 
  976      if ( meshFaceBoundaryIndex != -1 )
 
  980        int positionInMeshFaceBoundary = vertexPositionInFace( *mesh, vertexHoleIndex, meshFaceBoundaryIndex );
 
  982          positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.size() ) % meshFace.size(); 
 
  985        mNeighborhoodChanges.append( {meshFaceBoundaryIndex, positionInMeshFaceBoundary, oldNeighbor, newFaceBoundaryIndexInMesh} );
 
  988      mFacesNeighborhoodToAdd[newFaceBoundaryLocalIndex + startingFaceLocalIndex][positionInNewFaces] = meshFaceBoundaryIndex;
 
  992    int vertexOnLine = hole.at( 0 );
 
  993    while ( vertexOnLine != hole.last() )
 
  999        circulatorOnLine.goBoundaryClockwise();
 
 1000        nextVertex = circulatorOnLine.oppositeVertexClockwise();
 
 1004        circulatorOnLine.goBoundaryCounterClockwise();
 
 1005        nextVertex = circulatorOnLine.oppositeVertexCounterClockwise();
 
 1007      const QgsMeshFace &faceOnLine = circulatorOnLine.currentFace();
 
 1008      int positionOnFaceOnTheLine = vertexPositionInFace( vertexOnLine, faceOnLine );
 
 1010        positionOnFaceOnTheLine = ( positionOnFaceOnTheLine - 1 + faceOnLine.size() ) % faceOnLine.size();
 
 1012      newFacesOnLine.append( {circulatorOnLine.currentFaceIndex() + startingFaceLocalIndex, positionOnFaceOnTheLine} );
 
 1013      vertexOnLine = nextVertex;
 
 1018      circulatorOnStart.goBoundaryCounterClockwise();
 
 1020      circulatorOnStart.goBoundaryClockwise();
 
 1024      circulatorOnEnd.goBoundaryClockwise();
 
 1026      circulatorOnEnd.goBoundaryCounterClockwise();
 
 1029    extremeFaces = {circulatorOnStart.currentFaceIndex() + startingFaceLocalIndex,
 
 1030                    circulatorOnEnd.currentFaceIndex() + startingFaceLocalIndex
 
 1032    qDeleteAll( holeToFill );
 
 1036    qDeleteAll( holeToFill );
 
 1045bool QgsMeshEditForceByLine::finishForcingLine()
 
 1049  QList<std::array<int, 2>> newLeftFacesOnLine;
 
 1050  QList<std::array<int, 2>> newRightFacesOnLine;
 
 1052  std::array<int, 2> extremeFacesOnLeft;
 
 1053  std::array<int, 2> extremeFacesOnRight;
 
 1055  if ( !triangulateHoles( mHoleOnLeft, mNeighborOnLeft, 
true, newLeftFacesOnLine, extremeFacesOnLeft ) )
 
 1057  if ( !triangulateHoles( mHoleOnRight, mNeighborOnRight, 
false, newRightFacesOnLine, extremeFacesOnRight ) )
 
 1061  if ( newLeftFacesOnLine.count() != newRightFacesOnLine.count() )
 
 1064  for ( 
int i = 0; i < newLeftFacesOnLine.count(); ++i )
 
 1066    int leftFaceLocalIndex = newLeftFacesOnLine.at( i ).at( 0 );
 
 1067    int leftPositionInFace = newLeftFacesOnLine.at( i ).at( 1 );
 
 1068    int rightFaceLocalIndex = newRightFacesOnLine.at( i ).at( 0 );
 
 1069    int rightPositionInFace = newRightFacesOnLine.at( i ).at( 1 );
 
 1077  const int firstVertexIndex = mHoleOnLeft.first();
 
 1080    const int firstVertexLocalIndex = firstVertexIndex - mesh->
vertexCount();
 
 1084  const int lastVertexIndex = mHoleOnLeft.last();
 
 1087    const int lastVertexLocalIndex = lastVertexIndex - mesh->
vertexCount();
 
 1091  for ( 
int i = 0; i < mNewVerticesIndexesOnLine.count(); ++i )
 
 1096  for ( 
const int fi : std::as_const( mRemovedFaces ) )
 
 1103  mRemovedFaces.clear();
 
 1104  mHoleOnLeft.clear();
 
 1105  mNeighborOnLeft.clear();
 
 1106  mHoleOnRight.clear();
 
 1107  mNeighborOnRight.clear();
 
 1108  mNewVerticesIndexesOnLine.clear();
 
 1115  return QObject::tr( 
"Force mesh by polyline" );
 
 
 1125  if ( mPolylines.isEmpty() )
 
 1131  if ( mCurrentPolyline == 0 && mCurrentSegment == 0 )
 
 1133    setInputLine( mPolylines.at( 0 ).at( 0 ),
 
 1134                  mPolylines.at( 0 ).at( 1 ),
 
 1135                  mTolerance, mNewVertexOnIntersection );
 
 1138    return QgsMeshEditForceByLine::apply( meshEditor );
 
 1143    setInputLine( mPolylines.at( mCurrentPolyline ).at( mCurrentSegment ),
 
 1144                  mPolylines.at( mCurrentPolyline ).at( mCurrentSegment + 1 ),
 
 1145                  mTolerance, mNewVertexOnIntersection );
 
 1149  return QgsMeshEditForceByLine::apply( meshEditor );
 
 1154  std::vector<const QgsCurve *> curves;
 
 1157    std::vector< const QgsCurvePolygon * > polygons;
 
 1162        polygons.emplace_back( qgsgeometry_cast< const QgsCurvePolygon * >( ms->
geometryN( i ) ) );
 
 1165      polygons.emplace_back( qgsgeometry_cast< const QgsCurvePolygon * >( geom.
constGet() ) );
 
 1172      if ( polygon->exteriorRing() )
 
 1173        curves.emplace_back( polygon->exteriorRing() );
 
 1175      for ( 
int i = 0; i < polygon->numInteriorRings(); ++i )
 
 1176        curves.emplace_back( polygon->interiorRing( i ) );
 
 1185        curves.emplace_back( qgsgeometry_cast< const QgsCurve * >( mc->
geometryN( i ) ) );
 
 1188      curves.emplace_back( qgsgeometry_cast< const QgsCurve * >( geom.
constGet() ) );
 
 1191  for ( 
const QgsCurve *curve : curves )
 
 1197    curve->points( linePoints );
 
 1198    if ( linePoints.count() < 2 )
 
 1200    if ( !curve->is3D() )
 
 1202      for ( 
int i = 0; i < linePoints.count(); ++i )
 
 1204        const QgsPoint &point = linePoints.at( i );
 
 1205        linePoints[i] = 
QgsPoint( point.
x(), point.
y(), mDefaultZValue );
 
 1208    mPolylines.append( linePoints );
 
 
 1220  mTolerance = tolerance;
 
 
 1225  mNewVertexOnIntersection = addVertex;
 
 
 1230  mDefaultZValue = defaultZValue;
 
 
 1235  mInterpolateZValueOnMesh = interpolateZValueOnMesh;
 
 
 1238void QgsMeshEditForceByPolylines::incrementSegment()
 
 1241  if ( mCurrentSegment >= mPolylines.at( mCurrentPolyline ).count() - 1 )
 
 1243    mCurrentSegment = 0;
 
Curve polygon geometry type.
 
Abstract base class for curved geometry type.
 
int numGeometries() const
Returns the number of geometries within the collection.
 
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
 
static bool segmentIntersection(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q1, const QgsPoint &q2, QgsPoint &intersectionPoint, bool &isIntersection, double tolerance=1e-8, bool acceptImproperIntersection=false)
Compute the intersection between two segments.
 
A geometry is the spatial representation of a feature.
 
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
 
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
 
Qgis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
 
void clear()
Removes all data provided to the editing or created by the editing.
 
virtual bool isFinished() const
Returns whether the advanced edit is finished, if not, this edit has to be applied again with QgsMesh...
 
void setAddVertexOnIntersection(bool addVertex)
Sets whether vertices will be added when the lines will intersect internal edges of faces,...
 
void setInputLine(const QgsPoint &pt1, const QgsPoint &pt2, double tolerance, bool newVertexOnIntersection)
Sets the input forcing line in rendering coordinates.
 
void setDefaultZValue(double defaultZValue)
Sets the default value of Z coordinate to use for new vertices, this value will be used if the Z valu...
 
void setTolerance(double tolerance)
Sets the tolerance in redering coordinate system unit.
 
void setInterpolateZValueOnMesh(bool interpolateZValueOnMesh)
Sets whether the new created vertices will have their value interpolated from the existing mesh.
 
QString text() const override
Returns a short text string describing what this advanced edit does. Default implementation return a ...
 
void addLinesFromGeometries(const QList< QgsGeometry > geometries)
Adds a list of input forcing lines geometry in rendering coordinates.
 
bool isFinished() const override
Returns whether the advanced edit is finished, if not, this edit has to be applied again with QgsMesh...
 
void addLineFromGeometry(const QgsGeometry &geom)
Adds a input forcing line geometry in rendering coordinates.
 
Class that represents an error during mesh editing.
 
Qgis::MeshEditingErrorType errorType
 
Class that makes edit operation on a mesh.
 
bool edgeIsClose(QgsPointXY point, double tolerance, int &faceIndex, int &edgePosition)
Returns true if an edge of face is closest than the tolerance from the point in triangular mesh coord...
 
QgsTriangularMesh * triangularMesh()
Returns a pointer to the triangular mesh.
 
QgsTopologicalMesh & topologicalMesh()
Returns a reference to the topological mesh.
 
Convenient class that turn around a vertex and provide information about faces and vertices.
 
bool isValid() const
Returns whether the vertex circulator is valid.
 
bool goBoundaryCounterClockwise() const
Sets the circulator on the boundary face turning counter clockwise, return false is there isn't bound...
 
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.
 
Multi curve geometry collection.
 
Multi surface geometry collection.
 
A class to represent a 2D point.
 
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
 
Point geometry type, with support for z-dimension and m-values.
 
double distance(double x, double y) const
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
 
void setZ(double z)
Sets the point's z-coordinate.
 
A rectangle specified with double values.
 
Class that contains topological differences between two states of a topological mesh,...
 
QVector< FaceNeighbors > mFacesNeighborhoodToRemove
 
QVector< QgsMeshVertex > addedVertices() const
Returns the added vertices with this changes.
 
QList< std::array< int, 4 > > mNeighborhoodChanges
 
QVector< QgsMeshFace > mFacesToAdd
 
QVector< FaceNeighbors > mFacesNeighborhoodToAdd
 
QList< std::array< int, 3 > > mVerticesToFaceChanges
 
QVector< QgsMeshVertex > mVerticesToAdd
 
int mAddedFacesFirstIndex
 
QVector< int > mVertexToFaceToAdd
 
QList< int > mFaceIndexesToRemove
 
QVector< QgsMeshFace > mFacesToRemove
 
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.
 
QVector< QgsMeshFace > meshFaces() const
Returns faces.
 
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.
 
QVector< int > neighborsOfFace(int faceIndex) const
Returns the indexes of neighbor faces of the face with index faceIndex.
 
QVector< int > FaceNeighbors
 
Changes addVertexInFace(int faceIndex, const QgsMeshVertex &vertex)
Adds a vertex in the face with index faceIndex.
 
QList< int > facesAroundVertex(int vertexIndex) const
Returns the indexes of faces that are around the vertex with index vertexIndex.
 
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.
 
static TopologicalFaces createNewTopologicalFaces(const QVector< QgsMeshFace > &faces, bool uniqueSharedVertexAllowed, QgsMeshEditingError &error)
Creates new topological faces that are not yet included in the mesh.
 
Triangular/Derived Mesh is mesh with vertices in map coordinates.
 
const QVector< QgsMeshFace > & triangles() const
Returns triangles.
 
int nativeFaceIndexForPoint(const QgsPointXY &point) const
Finds index of native face at given point It uses spatial indexing.
 
const QVector< QgsMeshVertex > & vertices() const
Returns vertices in map coordinate system.
 
QgsMeshVertex triangularToNativeCoordinates(const QgsMeshVertex &vertex) const
Transforms the vertex from triangular mesh coordinates system to native coordinates system.
 
QList< int > nativeFaceIndexForRectangle(const QgsRectangle &rectangle) const
Finds indexes of native faces which bounding boxes intersect given bounding box It uses spatial index...
 
int faceIndexForPoint_v2(const QgsPointXY &point) const
Finds index of triangle at given point It uses spatial indexing and don't use geos to be faster.
 
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
 
QVector< QgsPoint > QgsPointSequence
 
QVector< int > QgsMeshFace
List of vertex indexes.
 
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.
 
int faceCount() const
Returns number of faces.
 
QgsMeshVertex vertex(int index) const
Returns a vertex at the index.