28static int vertexPositionInFace( 
int vertexIndex, 
const QgsMeshFace &face )
 
   30  return face.indexOf( vertexIndex );
 
   33static int vertexPositionInFace( 
const QgsMesh &mesh, 
int vertexIndex, 
int faceIndex )
 
   35  if ( faceIndex < 0 || faceIndex >= mesh.
faceCount() )
 
   38  return vertexPositionInFace( vertexIndex, mesh.
face( faceIndex ) );
 
   41bool QgsMeshEditForceByLine::edgeIntersection(
 
   44  int &closestSnappedVertex,
 
   51  closestSnappedVertex = -1;
 
   58  double epsilon = std::numeric_limits<double>::epsilon() * mTolerance * mTolerance;
 
   61  bool snapV1 = sqrt( v1.sqrDistToSegment( pt1.x(), pt1.y(), pt2.x(), pt2.y(), minDistPoint, epsilon ) ) < mTolerance;
 
   62  bool snapV2 = sqrt( v2.sqrDistToSegment( pt1.x(), pt1.y(), pt2.x(), pt2.y(), minDistPoint, epsilon ) ) < mTolerance;
 
   64  bool intersectLine = 
false;
 
   66                       mCurrentPointPosition,
 
   68                       triangularMesh->
vertices().at( vertex1 ),
 
   69                       triangularMesh->
vertices().at( vertex2 ),
 
   72                       outAllowed ? mTolerance : 0, 
true );
 
   74  if ( snapV1 == snapV2 ) 
 
   76    double distance1FromIntersection = v1.distance( intersectionPoint );
 
   77    double distance2FromIntersection = v2.distance( intersectionPoint );
 
   78    if ( distance1FromIntersection <= distance2FromIntersection )
 
   90  if ( isIntersect && snapV1 )
 
   92    closestSnappedVertex = vertex1;
 
   93    intersectionPoint = triangularMesh->
vertices().at( vertex1 );
 
   96  else if ( isIntersect && snapV2 )
 
   98    closestSnappedVertex = vertex2;
 
   99    intersectionPoint = triangularMesh->
vertices().at( vertex2 );
 
  111                                   QList<int> &holeOnLeft,
 
  112                                   QList<int> &neighborsOnLeft,
 
  113                                   QList<int> &holeOnRight,
 
  114                                   QList<int> &neighborsOnRight )
 
  118  const int faceSize = face.size();
 
  120  int beginPos = vertexPositionInFace( firstVertex, face );
 
  121  int endPos = vertexPositionInFace( secondVertex, face );
 
  124  for ( 
int i = 0; i < faceSize; ++i )
 
  126    int currentPos = ( beginPos + i ) % faceSize;
 
  127    holeOnRight.append( face.at( currentPos ) );
 
  128    if ( currentPos == endPos )
 
  130    neighborsOnRight.append( neighbors.at( currentPos ) );
 
  134  for ( 
int i = 0; i < faceSize; ++i )
 
  136    int currentPos = ( beginPos + faceSize - i ) % faceSize;
 
  137    holeOnLeft.append( face.at( currentPos ) );
 
  138    if ( currentPos == endPos )
 
  140    int neighborPos = ( currentPos + faceSize - 1 ) % faceSize;
 
  141    neighborsOnLeft.append( neighbors.at( neighborPos ) );
 
  147static int cutEdgeFromSnappedVertex( 
QgsMeshEditor *meshEditor,
 
  149                                     int startingSnappedVertex,
 
  151                                     QList<int> &newVerticesOnLeftHole,
 
  152                                     QList<int> &newNeighborsOnLeftHole,
 
  153                                     QList<int> &newVerticesOnRightHole,
 
  154                                     QList<int> &newNeighborsOnRightHole )
 
  158  const int faceSize = face.size();
 
  160  const int beginPos = vertexPositionInFace( startingSnappedVertex, face );
 
  162  const int endPosOnLeft = ( edgePosition + 1 ) % faceSize;
 
  163  const int endPosOnRight = edgePosition;
 
  166  for ( 
int i = 0; i < faceSize; ++i )
 
  168    int currentPos = ( beginPos + faceSize - i ) % faceSize;
 
  169    newVerticesOnLeftHole.append( face.at( currentPos ) );
 
  170    if ( currentPos == endPosOnLeft )
 
  172    int neighborPos = ( currentPos + faceSize - 1 ) % faceSize;
 
  173    newNeighborsOnLeftHole.append( neighbors.at( neighborPos ) );
 
  177  for ( 
int i = 0; i < faceSize; ++i )
 
  179    int currentPos = ( beginPos + i ) % faceSize;
 
  180    newVerticesOnRightHole.append( face.at( currentPos ) );
 
  181    if ( currentPos == endPosOnRight )
 
  183    newNeighborsOnRightHole.append( neighbors.at( currentPos ) );
 
  186  return neighbors.at( edgePosition );
 
  195  mTolerance = tolerance;
 
  196  mNewVertexOnIntersection = newVertexOnIntersection;
 
  197  mFirstPointChecked = 
false;
 
  198  mSecondPointChecked = 
false;
 
  199  mCurrentSnappedVertex = -1;
 
  201  mCurrentPointPosition = mPoint1;
 
  202  mRemovedFaces.clear();
 
  204  mNeighborOnLeft.clear();
 
  205  mHoleOnRight.clear();
 
  206  mNeighborOnRight.clear();
 
  207  mNewVerticesIndexesOnLine.clear();
 
  208  mEndOnPoint2 = 
false;
 
  209  mPoint2VertexIndex = -1;
 
  215  mEditor = meshEditor;
 
  217  if ( ! mFirstPointChecked )
 
  219    mFirstPointChecked = 
true;
 
  221    if ( mInterpolateZValueOnMesh )
 
  222      interpolateZValueOnMesh( mPoint1 );
 
  226    int faceCloseEdge = -1;
 
  227    if ( meshEditor->
edgeIsClose( mPoint1, mTolerance, faceCloseEdge, closeEdge ) )
 
  231      int vertexIndex1 = face.at( closeEdge );
 
  232      int vertexIndex2 = face.at( ( closeEdge + 1 ) % face.size() );
 
  241      if ( includdingFace != -1 )
 
  248  if ( ! mSecondPointChecked )
 
  250    mSecondPointChecked = 
true;
 
  251    if ( mInterpolateZValueOnMesh )
 
  252      interpolateZValueOnMesh( mPoint2 );
 
  256    int faceCloseEdge = -1;
 
  257    if ( meshEditor->
edgeIsClose( mPoint2, mTolerance, faceCloseEdge, closeEdge ) )
 
  261      int vertexIndex1 = face.at( closeEdge );
 
  262      int vertexIndex2 = face.at( ( closeEdge + 1 ) % face.size() );
 
  264      bool snap1 = meshEditor->
triangularMesh()->
vertices().at( vertexIndex1 ).distance( mPoint2 ) <= mTolerance ;
 
  265      bool snap2 = meshEditor->
triangularMesh()->
vertices().at( vertexIndex2 ).distance( mPoint2 ) <= mTolerance ;
 
  270        mPoint2VertexIndex = vertexIndex1;
 
  276        mPoint2VertexIndex = vertexIndex2;
 
  294      if ( includdingFace != -1 )
 
  308  if ( buildForcedElements() )
 
  317void QgsMeshEditForceByLine::finish()
 
  322void QgsMeshEditForceByLine::interpolateZValueOnMesh( 
QgsPoint &point )
 const 
  327  if ( includdingFace != -1 )
 
  330    if ( triangleFaceIndex != -1 )
 
  336      double z = QgsMeshLayerUtils::interpolateFromVerticesData( tv1, tv2, tv3, tv1.
z(), tv2.
z(), tv3.
z(), point );
 
  344  double distPoint = point.
distance( otherPoint1 );
 
  345  double totalDistance = otherPoint1.
distance( otherPoint2 );
 
  347  point.
setZ( otherPoint1.
z() + ( otherPoint2.
z() - otherPoint1.
z() )*distPoint / totalDistance );
 
  350bool QgsMeshEditForceByLine::buildForcedElements()
 
  355  QSet<int> treatedFaces;
 
  357  int startingVertexIndex = mesh->
vertices.count();
 
  359  int currentFaceIndex = -1;
 
  360  bool searchOutside = 
false; 
 
  361  QPair<int, int> currentEdge{-1, -1};
 
  363  int currentAddedVertex = -1; 
 
  364  int nextCutFace = -1; 
 
  369    if ( mCurrentSnappedVertex == -1 )
 
  372    if ( currentFaceIndex == leftFace )
 
  373      currentFaceIndex = -1;
 
  375    if ( mCurrentSnappedVertex != -1 && !searchOutside )
 
  378      currentFaceIndex = -1;
 
  379      int previousSnappedVertex = -1;
 
  380      int intersectionFaceIndex = -1;
 
  381      QgsPoint intersectionPoint( 0, 0, 0 );
 
  382      int edgePosition = -1;
 
  384      bool result = searchIntersectionEdgeFromSnappedVertex(
 
  385                      intersectionFaceIndex,
 
  386                      previousSnappedVertex,
 
  387                      mCurrentSnappedVertex,
 
  395        if ( mCurrentSnappedVertex != -1 &&
 
  396             mPoint2.
distance( triangularMesh->
vertices().at( mCurrentSnappedVertex ) ) < mTolerance )
 
  400        searchOutside = 
true;
 
  404        if ( mEndOnPoint2 && mCurrentSnappedVertex == mPoint2VertexIndex )
 
  410        if ( mCurrentSnappedVertex != -1 )
 
  414          buildHolesWithOneFace( mEditor,
 
  415                                 intersectionFaceIndex,
 
  416                                 previousSnappedVertex,
 
  417                                 mCurrentSnappedVertex,
 
  423          mRemovedFaces.append( intersectionFaceIndex );
 
  425          if ( finishForcingLine() )
 
  434          nextCutFace = cutEdgeFromSnappedVertex( mEditor,
 
  435                                                  intersectionFaceIndex,
 
  436                                                  previousSnappedVertex,
 
  443          mRemovedFaces.append( intersectionFaceIndex );
 
  445          int iv1 = mHoleOnLeft.last();
 
  446          int iv2 = mHoleOnRight.last();
 
  448          if ( mNewVertexOnIntersection )
 
  450            currentAddedVertex = startingVertexIndex + 
mVerticesToAdd.count();
 
  452            if ( mInterpolateZValueOnMesh )
 
  453              interpolateZValue( intersectionPoint,
 
  454                                 triangularMesh->
vertices().at( iv1 ),
 
  455                                 triangularMesh->
vertices().at( iv2 ) );
 
  457              interpolateZValue( intersectionPoint, mPoint1, mPoint2 );
 
  461          if ( nextCutFace != -1 )
 
  463            mCurrentSnappedVertex = -1;
 
  464            currentFaceIndex = nextCutFace;
 
  465            currentEdge = {mHoleOnLeft.last(), mHoleOnRight.last()};
 
  470            if ( !mNewVertexOnIntersection )
 
  472              currentAddedVertex = startingVertexIndex + 
mVerticesToAdd.count();
 
  473              if ( mInterpolateZValueOnMesh )
 
  474                interpolateZValue( intersectionPoint,
 
  475                                   triangularMesh->
vertices().at( iv1 ),
 
  476                                   triangularMesh->
vertices().at( iv2 ) );
 
  478                interpolateZValue( intersectionPoint, mPoint1, mPoint2 );
 
  482              mNewVerticesIndexesOnLine.removeLast();
 
  484            mHoleOnLeft.append( currentAddedVertex );
 
  485            mNeighborOnLeft.append( -1 );
 
  486            mHoleOnRight.append( currentAddedVertex );
 
  487            mNeighborOnRight.append( -1 );
 
  489            if ( finishForcingLine() )
 
  494            leftFace = intersectionFaceIndex;
 
  497          mCurrentPointPosition = intersectionPoint;
 
  501    else if ( nextCutFace != -1 )
 
  505      int faceSize = face.size();
 
  507      currentFaceIndex = nextCutFace;
 
  509      mRemovedFaces.append( nextCutFace );
 
  511      int edgePositionOnLeft =  vertexPositionInFace( currentEdge.first, face );
 
  512      int edgePositionOnRight = vertexPositionInFace( currentEdge.second, face );
 
  513      int firstEdgeToTest = vertexPositionInFace( currentEdge.second, face );
 
  515      bool foundSomething = 
false;
 
  517      for ( 
int fi = 0; fi < faceSize; ++fi )
 
  519        int iv1 = face.at( ( firstEdgeToTest + fi ) % faceSize );
 
  520        int iv2 = face.at( ( firstEdgeToTest + fi + 1 ) % faceSize );
 
  522        if ( iv1 == currentEdge.first && iv2 == currentEdge.second )
 
  527        if ( edgeIntersection( iv1, iv2, snapVertex, intersection, 
false ) ||
 
  530          foundSomething = 
true;
 
  532          int endPositionOnRight;
 
  533          int endPositionOnLeft;
 
  535          if ( snapVertex != -1 )
 
  538            endPositionOnRight = vertexPositionInFace( snapVertex, face );
 
  539            endPositionOnLeft = vertexPositionInFace( snapVertex, face );
 
  542            currentEdge = {-1, -1};
 
  543            mCurrentSnappedVertex = snapVertex;
 
  548            endPositionOnLeft = vertexPositionInFace( iv2, face );
 
  549            endPositionOnRight = vertexPositionInFace( iv1, face );
 
  551            nextCutFace = neighbors.at( endPositionOnRight );
 
  553            if ( mNewVertexOnIntersection )
 
  555              currentAddedVertex = startingVertexIndex + 
mVerticesToAdd.count();
 
  557              if ( mInterpolateZValueOnMesh )
 
  558                interpolateZValue( intersection,
 
  559                                   triangularMesh->
vertices().at( iv1 ),
 
  560                                   triangularMesh->
vertices().at( iv2 ) );
 
  562                interpolateZValue( intersection, mPoint1, mPoint2 );
 
  567          int currentPos = edgePositionOnLeft;
 
  568          while ( currentPos != endPositionOnLeft )
 
  570            int nextPos = ( currentPos - 1 + faceSize ) % faceSize;
 
  571            mHoleOnLeft.append( face.at( nextPos ) );
 
  572            int neighborPos = nextPos;
 
  573            mNeighborOnLeft.append( neighbors.at( neighborPos ) );
 
  574            currentPos = nextPos;
 
  577          currentPos = edgePositionOnRight;
 
  578          while ( currentPos != endPositionOnRight )
 
  580            int nextPos = ( currentPos + 1 ) % faceSize;
 
  581            mHoleOnRight.append( face.at( nextPos ) );
 
  582            int neighborPos = ( nextPos + faceSize - 1 ) % faceSize;
 
  583            mNeighborOnRight.append( neighbors.at( neighborPos ) );
 
  584            currentPos = nextPos;
 
  587          mCurrentPointPosition = intersection;
 
  589          if ( snapVertex != -1 )
 
  591            currentEdge = {-1, -1};
 
  593            if ( finishForcingLine() )
 
  595              mIsFinished = mEndOnPoint2 && mPoint2VertexIndex == snapVertex;
 
  604          else if ( nextCutFace == -1 )
 
  607            if ( !mNewVertexOnIntersection )
 
  609              currentAddedVertex = startingVertexIndex + 
mVerticesToAdd.count();
 
  610              if ( mInterpolateZValueOnMesh )
 
  611                interpolateZValue( intersection,
 
  612                                   triangularMesh->
vertices().at( iv1 ),
 
  613                                   triangularMesh->
vertices().at( iv2 ) );
 
  615                interpolateZValue( intersection, mPoint1, mPoint2 );
 
  619              mNewVerticesIndexesOnLine.removeLast();
 
  621            mHoleOnLeft.append( currentAddedVertex );
 
  622            mNeighborOnLeft.append( -1 );
 
  623            mHoleOnRight.append( currentAddedVertex );
 
  624            mNeighborOnRight.append( -1 );
 
  626            if ( finishForcingLine() )
 
  635            currentEdge = {mHoleOnLeft.last(), mHoleOnRight.last()};
 
  641      if ( ! foundSomething )
 
  647    else if ( currentFaceIndex == -1 || searchOutside )
 
  650      const QgsRectangle bbox( mCurrentPointPosition, mPoint2 );
 
  652      int closestFaceIndex = -1;
 
  653      int closestEdge = -1; 
 
  654      int closestSnapVertex = -1;
 
  655      double minimalDistance = std::numeric_limits<double>::max();
 
  656      QgsPoint closestIntersectionPoint( 0, 0, 0 );
 
  657      for ( 
const int candidateFaceIndex : candidateFacesIndexes )
 
  659        if ( candidateFaceIndex == leftFace )
 
  662        if ( treatedFaces.contains( candidateFaceIndex ) ) 
 
  666        const int faceSize = candidateFace.size();
 
  668        for ( 
int i = 0; i < faceSize; ++i )
 
  670          int iv1 = candidateFace.at( i );
 
  671          int iv2 = candidateFace.at( ( i + 1 ) % faceSize );
 
  673          if ( iv1 == mCurrentSnappedVertex || iv2 == mCurrentSnappedVertex )
 
  678          bool isIntersect = edgeIntersection( iv1, iv2, snapVertex, intersectionPoint, 
true );
 
  682            double distance = intersectionPoint.
distance( mCurrentPointPosition );
 
  683            if ( distance < minimalDistance )
 
  685              closestFaceIndex = candidateFaceIndex;
 
  686              closestEdge = candidateFace.at( i );
 
  687              closestSnapVertex = snapVertex;
 
  688              closestIntersectionPoint = intersectionPoint;
 
  689              minimalDistance = distance;
 
  695      if ( closestFaceIndex < 0 || closestEdge < 0 ) 
 
  702        mCurrentSnappedVertex = closestSnapVertex;
 
  703        treatedFaces.insert( closestFaceIndex );
 
  704        searchOutside = 
false;
 
  705        if ( mCurrentSnappedVertex == -1 )
 
  709          currentAddedVertex = startingVertexIndex + 
mVerticesToAdd.count();
 
  711          nextCutFace = closestFaceIndex;
 
  713          mHoleOnRight.append( currentAddedVertex );
 
  714          mHoleOnRight.append( face.at( ( vertexPositionInFace( closestEdge, face ) + 1 ) % face.size() ) );
 
  715          mNeighborOnRight.append( -1 );
 
  718          mHoleOnLeft.append( currentAddedVertex );
 
  719          mHoleOnLeft.append( closestEdge ) ;
 
  720          mNeighborOnLeft.append( -1 );
 
  722          currentEdge = {mHoleOnLeft.last(), mHoleOnRight.last()};
 
  724          if ( mInterpolateZValueOnMesh )
 
  725            interpolateZValue( closestIntersectionPoint,
 
  726                               triangularMesh->
vertices().at( mHoleOnLeft.last() ),
 
  727                               triangularMesh->
vertices().at( mHoleOnRight.last() ) );
 
  729            interpolateZValue( closestIntersectionPoint, mPoint1, mPoint2 );
 
  736    else if ( mCurrentSnappedVertex == -1 ) 
 
  739      double minimalDistance = std::numeric_limits<double>::max();
 
  741      for ( 
int i = 0; i < face.size(); ++i )
 
  744        const double distance = mCurrentPointPosition.
distance( vertex );
 
  745        if ( distance < mTolerance && distance < minimalDistance )
 
  747          minimalDistance = distance;
 
  748          mCurrentSnappedVertex = face.at( i );
 
  751      searchOutside = 
false;
 
  753      if ( mCurrentSnappedVertex == -1 )
 
  759    if ( mCurrentSnappedVertex != -1 )
 
  761      if ( mCurrentSnappedVertex == mPoint2VertexIndex )
 
  766      mCurrentPointPosition = triangularMesh->
vertices().at( mCurrentSnappedVertex );
 
  775bool QgsMeshEditForceByLine::searchIntersectionEdgeFromSnappedVertex
 
  776( 
int &intersectionFaceIndex,
 
  777  int &previousSnappedVertex,
 
  778  int ¤tSnappedVertexIndex,
 
  781  QSet<int> &treatedFaces )
 
  783  previousSnappedVertex = currentSnappedVertexIndex;
 
  784  QSet<int> treatedVertices;
 
  788    treatedVertices.insert( currentSnappedVertexIndex );
 
  791    bool foundSomething = 
false;
 
  792    for ( 
const int faceIndex : std::as_const( facesAround ) )
 
  795      int faceSize = face.size();
 
  796      int vertexPos = vertexPositionInFace( currentSnappedVertexIndex, face );
 
  798      int newSnapVertex = -1;
 
  799      for ( 
int i = 1; i < faceSize - 1; ++i )
 
  801        edgePosition = ( vertexPos + i ) % faceSize ;
 
  802        foundSomething = edgeIntersection( face.at( edgePosition ),
 
  803                                           face.at( ( edgePosition + 1 ) % faceSize ),
 
  808        if ( mEndOnPoint2 && newSnapVertex == mPoint2VertexIndex )
 
  810          mCurrentSnappedVertex = newSnapVertex;
 
  814        if ( newSnapVertex != -1 )
 
  815          foundSomething = ( newSnapVertex != previousSnappedVertex &&
 
  816                             !treatedVertices.contains( newSnapVertex ) );
 
  818        if ( foundSomething )
 
  822      if ( foundSomething )
 
  824        treatedFaces.insert( faceIndex );
 
  825        if ( newSnapVertex != -1 )
 
  827          previousSnappedVertex = currentSnappedVertexIndex;
 
  828          currentSnappedVertexIndex = newSnapVertex;
 
  829          if ( newSnapVertex == face.at( ( vertexPos + 1 ) % faceSize ) || newSnapVertex == face.at( ( vertexPos - 1 + faceSize ) % faceSize ) )
 
  837            intersectionFaceIndex = faceIndex;
 
  843          intersectionFaceIndex = faceIndex;
 
  844          previousSnappedVertex = currentSnappedVertexIndex;
 
  845          currentSnappedVertexIndex = -1;
 
  851    if ( !foundSomething )
 
  858bool QgsMeshEditForceByLine::triangulateHoles(
 
  859  const QList<int> &hole,
 
  860  const QList<int> &neighbors,
 
  862  QList<std::array<int, 2>> &newFacesOnLine,
 
  863  std::array<int, 2> &extremeFaces )
 
  868  for ( 
int i = 0; i < hole.count(); ++i )
 
  870    for ( 
int j = i + 1; j < hole.count(); ++j )
 
  872      if ( hole.at( i ) == hole.at( j ) )
 
  883  std::vector<p2t::Point *> holeToFill;
 
  886    QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
 
  887    holeToFill.resize( hole.count() + mNewVerticesIndexesOnLine.count() );
 
  888    for ( 
int i = 0; i < hole.count(); ++i )
 
  890      int vertexIndex = hole.at( i );
 
  892      if ( vertexIndex < mesh->vertexCount() )
 
  893        vertex = mesh->
vertex( vertexIndex );
 
  897      holeToFill[i] = 
new p2t::Point( vertex.
x(), vertex.
y() );
 
  898      mapPoly2TriPointToVertex.insert( holeToFill[i], vertexIndex );
 
  901    const int verticesOnLineCount = mNewVerticesIndexesOnLine.count();
 
  902    for ( 
int i = 0; i < verticesOnLineCount; ++i )
 
  904      int vertexLocalIndex = mNewVerticesIndexesOnLine.at( verticesOnLineCount - i - 1 );
 
  906      holeToFill[i + hole.count()] = 
new p2t::Point( vertex.
x(), vertex.
y() );
 
  907      mapPoly2TriPointToVertex.insert( holeToFill[i + hole.count()], vertexLocalIndex + mesh->
vertexCount() );
 
  910    std::unique_ptr<p2t::CDT> cdt( 
new p2t::CDT( holeToFill ) );
 
  912    std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
 
  913    QVector<QgsMeshFace> newFaces( triangles.size() );
 
  914    for ( 
size_t i = 0; i < triangles.size(); ++i )
 
  918      for ( 
int j = 0; j < 3; j++ )
 
  920        int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
 
  922          throw std::exception();
 
  930      throw std::exception();
 
  932    const QVector<QgsMeshFace> &facesToAdd = topologicalFaces.
meshFaces();
 
  936    for ( 
const int vtc : hole )
 
  939      if ( mRemovedFaces.contains( firstLinkedFace ) )
 
  944    for ( 
int i = 0; i < facesToAdd.count(); ++i )
 
  948      for ( 
int n = 0; n < faceNeighbors.count(); ++n )
 
  950        if ( faceNeighbors.at( n ) != -1 )
 
  951          faceNeighbors[n] += startingFaceGlobalIndex; 
 
  956    for ( 
int i = 0 ; i < hole.count() - 1; ++i )
 
  958      int vertexHoleIndex = hole.at( i );
 
  959      int meshFaceBoundaryIndex = neighbors.at( i );
 
  963        throw std::exception();
 
  971      int newFaceBoundaryIndexInMesh = circulator.
currentFaceIndex() + startingFaceGlobalIndex;
 
  973      int positionInNewFaces = vertexPositionInFace( vertexHoleIndex, newFace );
 
  975        positionInNewFaces = ( positionInNewFaces - 1 + newFace.size() ) % newFace.size(); 
 
  977      if ( meshFaceBoundaryIndex != -1 )
 
  981        int positionInMeshFaceBoundary = vertexPositionInFace( *mesh, vertexHoleIndex, meshFaceBoundaryIndex );
 
  983          positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.size() ) % meshFace.size(); 
 
  986        mNeighborhoodChanges.append( {meshFaceBoundaryIndex, positionInMeshFaceBoundary, oldNeighbor, newFaceBoundaryIndexInMesh} );
 
  989      mFacesNeighborhoodToAdd[newFaceBoundaryLocalIndex + startingFaceLocalIndex][positionInNewFaces] = meshFaceBoundaryIndex;
 
  993    int vertexOnLine = hole.at( 0 );
 
  994    while ( vertexOnLine != hole.last() )
 
 1000        circulatorOnLine.goBoundaryClockwise();
 
 1001        nextVertex = circulatorOnLine.oppositeVertexClockwise();
 
 1005        circulatorOnLine.goBoundaryCounterClockwise();
 
 1006        nextVertex = circulatorOnLine.oppositeVertexCounterClockwise();
 
 1008      const QgsMeshFace &faceOnLine = circulatorOnLine.currentFace();
 
 1009      int positionOnFaceOnTheLine = vertexPositionInFace( vertexOnLine, faceOnLine );
 
 1011        positionOnFaceOnTheLine = ( positionOnFaceOnTheLine - 1 + faceOnLine.size() ) % faceOnLine.size();
 
 1013      newFacesOnLine.append( {circulatorOnLine.currentFaceIndex() + startingFaceLocalIndex, positionOnFaceOnTheLine} );
 
 1014      vertexOnLine = nextVertex;
 
 1019      circulatorOnStart.goBoundaryCounterClockwise();
 
 1021      circulatorOnStart.goBoundaryClockwise();
 
 1025      circulatorOnEnd.goBoundaryClockwise();
 
 1027      circulatorOnEnd.goBoundaryCounterClockwise();
 
 1030    extremeFaces = {circulatorOnStart.currentFaceIndex() + startingFaceLocalIndex,
 
 1031                    circulatorOnEnd.currentFaceIndex() + startingFaceLocalIndex
 
 1033    qDeleteAll( holeToFill );
 
 1037    qDeleteAll( holeToFill );
 
 1046bool QgsMeshEditForceByLine::finishForcingLine()
 
 1050  QList<std::array<int, 2>> newLeftFacesOnLine;
 
 1051  QList<std::array<int, 2>> newRightFacesOnLine;
 
 1053  std::array<int, 2> extremeFacesOnLeft;
 
 1054  std::array<int, 2> extremeFacesOnRight;
 
 1056  if ( !triangulateHoles( mHoleOnLeft, mNeighborOnLeft, 
true, newLeftFacesOnLine, extremeFacesOnLeft ) )
 
 1058  if ( !triangulateHoles( mHoleOnRight, mNeighborOnRight, 
false, newRightFacesOnLine, extremeFacesOnRight ) )
 
 1062  if ( newLeftFacesOnLine.count() != newRightFacesOnLine.count() )
 
 1065  for ( 
int i = 0; i < newLeftFacesOnLine.count(); ++i )
 
 1067    int leftFaceLocalIndex = newLeftFacesOnLine.at( i ).at( 0 );
 
 1068    int leftPositionInFace = newLeftFacesOnLine.at( i ).at( 1 );
 
 1069    int rightFaceLocalIndex = newRightFacesOnLine.at( i ).at( 0 );
 
 1070    int rightPositionInFace = newRightFacesOnLine.at( i ).at( 1 );
 
 1078  const int firstVertexIndex = mHoleOnLeft.first();
 
 1081    const int firstVertexLocalIndex = firstVertexIndex - mesh->
vertexCount();
 
 1085  const int lastVertexIndex = mHoleOnLeft.last();
 
 1088    const int lastVertexLocalIndex = lastVertexIndex - mesh->
vertexCount();
 
 1092  for ( 
int i = 0; i < mNewVerticesIndexesOnLine.count(); ++i )
 
 1097  for ( 
const int fi : std::as_const( mRemovedFaces ) )
 
 1104  mRemovedFaces.clear();
 
 1105  mHoleOnLeft.clear();
 
 1106  mNeighborOnLeft.clear();
 
 1107  mHoleOnRight.clear();
 
 1108  mNeighborOnRight.clear();
 
 1109  mNewVerticesIndexesOnLine.clear();
 
 1116  return QObject::tr( 
"Force mesh by polyline" );
 
 1126  if ( mPolylines.isEmpty() )
 
 1132  if ( mCurrentPolyline == 0 && mCurrentSegment == 0 )
 
 1134    setInputLine( mPolylines.at( 0 ).at( 0 ),
 
 1135                  mPolylines.at( 0 ).at( 1 ),
 
 1136                  mTolerance, mNewVertexOnIntersection );
 
 1139    return QgsMeshEditForceByLine::apply( meshEditor );
 
 1144    setInputLine( mPolylines.at( mCurrentPolyline ).at( mCurrentSegment ),
 
 1145                  mPolylines.at( mCurrentPolyline ).at( mCurrentSegment + 1 ),
 
 1146                  mTolerance, mNewVertexOnIntersection );
 
 1150  return QgsMeshEditForceByLine::apply( meshEditor );
 
 1155  std::vector<const QgsCurve *> curves;
 
 1158    std::vector< const QgsCurvePolygon * > polygons;
 
 1163        polygons.emplace_back( qgsgeometry_cast< const QgsCurvePolygon * >( ms->
geometryN( i ) ) );
 
 1166      polygons.emplace_back( qgsgeometry_cast< const QgsCurvePolygon * >( geom.
constGet() ) );
 
 1173      if ( polygon->exteriorRing() )
 
 1174        curves.emplace_back( polygon->exteriorRing() );
 
 1176      for ( 
int i = 0; i < polygon->numInteriorRings(); ++i )
 
 1177        curves.emplace_back( polygon->interiorRing( i ) );
 
 1186        curves.emplace_back( qgsgeometry_cast< const QgsCurve * >( mc->
geometryN( i ) ) );
 
 1189      curves.emplace_back( qgsgeometry_cast< const QgsCurve * >( geom.
constGet() ) );
 
 1192  for ( 
const QgsCurve *curve : curves )
 
 1198    curve->points( linePoints );
 
 1199    if ( linePoints.count() < 2 )
 
 1201    if ( !curve->is3D() )
 
 1203      for ( 
int i = 0; i < linePoints.count(); ++i )
 
 1205        const QgsPoint &point = linePoints.at( i );
 
 1206        linePoints[i] = 
QgsPoint( point.
x(), point.
y(), mDefaultZValue );
 
 1209    mPolylines.append( linePoints );
 
 1221  mTolerance = tolerance;
 
 1226  mNewVertexOnIntersection = addVertex;
 
 1231  mDefaultZValue = defaultZValue;
 
 1236  mInterpolateZValueOnMesh = interpolateZValueOnMesh;
 
 1239void QgsMeshEditForceByPolylines::incrementSegment()
 
 1242  if ( mCurrentSegment >= mPolylines.at( mCurrentPolyline ).count() - 1 )
 
 1244    mCurrentSegment = 0;
 
Curve polygon geometry type.
 
Abstract base class for curved geometry type.
 
int numGeometries() const SIP_HOLDGIL
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) SIP_HOLDGIL
Compute the intersection between two segments.
 
A geometry is the spatial representation of a feature.
 
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
 
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
 
bool isMultipart() const SIP_HOLDGIL
Returns true if WKB of the geometry is of WKBMulti* type.
 
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.
 
Point geometry type, with support for z-dimension and m-values.
 
double distance(double x, double y) const SIP_HOLDGIL
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
 
void setZ(double z) SIP_HOLDGIL
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 GeometryType geometryType(Type type) SIP_HOLDGIL
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.