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 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.
Qgis::WkbType 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 Qgis::GeometryType geometryType(Qgis::WkbType 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.