28 static int vertexPositionInFace(
int vertexIndex,
const QgsMeshFace &face )
30 return face.indexOf( vertexIndex );
33 static int vertexPositionInFace(
const QgsMesh &mesh,
int vertexIndex,
int faceIndex )
35 if ( faceIndex < 0 || faceIndex >= mesh.
faceCount() )
38 return vertexPositionInFace( vertexIndex, mesh.
face( faceIndex ) );
41 bool 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 );
107 static void buildHolesWithOneFace(
QgsMeshEditor *meshEditor,
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 ) );
147 static 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() )
317 void QgsMeshEditForceByLine::finish()
322 void 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 );
350 bool 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 );
775 bool 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 )
858 bool 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 );
1046 bool 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;
1239 void 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.