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(
int vertex1,
int vertex2,
int &closestSnappedVertex,
QgsPoint &intersectionPoint,
bool outAllowed )
42 const QgsPointXY pt1( mCurrentPointPosition );
43 const QgsPointXY pt2( mPoint2 );
45 closestSnappedVertex = -1;
47 QgsTriangularMesh *triangularMesh = mEditor->triangularMesh();
49 const QgsPointXY v1( triangularMesh->
vertices().at( vertex1 ) );
50 const QgsPointXY v2( triangularMesh->
vertices().at( vertex2 ) );
52 double epsilon = std::numeric_limits<double>::epsilon() * mTolerance * mTolerance;
54 QgsPointXY minDistPoint;
55 bool snapV1 = sqrt( v1.sqrDistToSegment( pt1.x(), pt1.y(), pt2.x(), pt2.y(), minDistPoint, epsilon ) ) < mTolerance;
56 bool snapV2 = sqrt( v2.sqrDistToSegment( pt1.x(), pt1.y(), pt2.x(), pt2.y(), minDistPoint, epsilon ) ) < mTolerance;
58 bool intersectLine =
false;
60 segmentIntersection( mCurrentPointPosition, mPoint2, triangularMesh->
vertices().at( vertex1 ), triangularMesh->
vertices().at( vertex2 ), intersectionPoint, intersectLine, outAllowed ? mTolerance : 0,
true );
62 if ( snapV1 == snapV2 )
64 double distance1FromIntersection = v1.distance( intersectionPoint );
65 double distance2FromIntersection = v2.distance( intersectionPoint );
66 if ( distance1FromIntersection <= distance2FromIntersection )
78 if ( isIntersect && snapV1 )
80 closestSnappedVertex = vertex1;
81 intersectionPoint = triangularMesh->
vertices().at( vertex1 );
84 else if ( isIntersect && snapV2 )
86 closestSnappedVertex = vertex2;
87 intersectionPoint = triangularMesh->
vertices().at( vertex2 );
95static void buildHolesWithOneFace(
96 QgsMeshEditor *meshEditor,
int faceIndex,
int firstVertex,
int secondVertex, QList<int> &holeOnLeft, QList<int> &neighborsOnLeft, QList<int> &holeOnRight, QList<int> &neighborsOnRight
101 const int faceSize = face.size();
103 int beginPos = vertexPositionInFace( firstVertex, face );
104 int endPos = vertexPositionInFace( secondVertex, face );
107 for (
int i = 0; i < faceSize; ++i )
109 int currentPos = ( beginPos + i ) % faceSize;
110 holeOnRight.append( face.at( currentPos ) );
111 if ( currentPos == endPos )
113 neighborsOnRight.append( neighbors.at( currentPos ) );
117 for (
int i = 0; i < faceSize; ++i )
119 int currentPos = ( beginPos + faceSize - i ) % faceSize;
120 holeOnLeft.append( face.at( currentPos ) );
121 if ( currentPos == endPos )
123 int neighborPos = ( currentPos + faceSize - 1 ) % faceSize;
124 neighborsOnLeft.append( neighbors.at( neighborPos ) );
130static int cutEdgeFromSnappedVertex(
133 int startingSnappedVertex,
135 QList<int> &newVerticesOnLeftHole,
136 QList<int> &newNeighborsOnLeftHole,
137 QList<int> &newVerticesOnRightHole,
138 QList<int> &newNeighborsOnRightHole
143 const int faceSize = face.size();
145 const int beginPos = vertexPositionInFace( startingSnappedVertex, face );
147 const int endPosOnLeft = ( edgePosition + 1 ) % faceSize;
148 const int endPosOnRight = edgePosition;
151 for (
int i = 0; i < faceSize; ++i )
153 int currentPos = ( beginPos + faceSize - i ) % faceSize;
154 newVerticesOnLeftHole.append( face.at( currentPos ) );
155 if ( currentPos == endPosOnLeft )
157 int neighborPos = ( currentPos + faceSize - 1 ) % faceSize;
158 newNeighborsOnLeftHole.append( neighbors.at( neighborPos ) );
162 for (
int i = 0; i < faceSize; ++i )
164 int currentPos = ( beginPos + i ) % faceSize;
165 newVerticesOnRightHole.append( face.at( currentPos ) );
166 if ( currentPos == endPosOnRight )
168 newNeighborsOnRightHole.append( neighbors.at( currentPos ) );
171 return neighbors.at( edgePosition );
180 mTolerance = tolerance;
181 mNewVertexOnIntersection = newVertexOnIntersection;
182 mFirstPointChecked =
false;
183 mSecondPointChecked =
false;
184 mCurrentSnappedVertex = -1;
186 mCurrentPointPosition = mPoint1;
187 mRemovedFaces.clear();
189 mNeighborOnLeft.clear();
190 mHoleOnRight.clear();
191 mNeighborOnRight.clear();
192 mNewVerticesIndexesOnLine.clear();
193 mEndOnPoint2 =
false;
194 mPoint2VertexIndex = -1;
200 mEditor = meshEditor;
202 if ( !mFirstPointChecked )
204 mFirstPointChecked =
true;
206 if ( mInterpolateZValueOnMesh )
207 interpolateZValueOnMesh( mPoint1 );
211 int faceCloseEdge = -1;
212 if ( meshEditor->
edgeIsClose( mPoint1, mTolerance, faceCloseEdge, closeEdge ) )
216 int vertexIndex1 = face.at( closeEdge );
217 int vertexIndex2 = face.at( ( closeEdge + 1 ) % face.size() );
226 if ( includdingFace != -1 )
233 if ( !mSecondPointChecked )
235 mSecondPointChecked =
true;
236 if ( mInterpolateZValueOnMesh )
237 interpolateZValueOnMesh( mPoint2 );
241 int faceCloseEdge = -1;
242 if ( meshEditor->
edgeIsClose( mPoint2, mTolerance, faceCloseEdge, closeEdge ) )
246 int vertexIndex1 = face.at( closeEdge );
247 int vertexIndex2 = face.at( ( closeEdge + 1 ) % face.size() );
249 bool snap1 = meshEditor->
triangularMesh()->
vertices().at( vertexIndex1 ).distance( mPoint2 ) <= mTolerance;
250 bool snap2 = meshEditor->
triangularMesh()->
vertices().at( vertexIndex2 ).distance( mPoint2 ) <= mTolerance;
255 mPoint2VertexIndex = vertexIndex1;
261 mPoint2VertexIndex = vertexIndex2;
279 if ( includdingFace != -1 )
293 if ( buildForcedElements() )
299 return QgsTopologicalMesh::Changes();
302void QgsMeshEditForceByLine::finish()
307void QgsMeshEditForceByLine::interpolateZValueOnMesh(
QgsPoint &point )
const
309 QgsTriangularMesh *triangularMesh = mEditor->triangularMesh();
312 if ( includdingFace != -1 )
315 if ( triangleFaceIndex != -1 )
321 double z = QgsMeshLayerUtils::interpolateFromVerticesData( tv1, tv2, tv3, tv1.
z(), tv2.
z(), tv3.
z(), point );
329 double distPoint = point.
distance( otherPoint1 );
330 double totalDistance = otherPoint1.
distance( otherPoint2 );
332 point.
setZ( otherPoint1.
z() + ( otherPoint2.
z() - otherPoint1.
z() ) * distPoint / totalDistance );
335bool QgsMeshEditForceByLine::buildForcedElements()
337 QgsTriangularMesh *triangularMesh = mEditor->triangularMesh();
338 QgsMesh *mesh = mEditor->topologicalMesh().mesh();
340 QSet<int> treatedFaces;
342 int startingVertexIndex = mesh->
vertices.count();
344 int currentFaceIndex = -1;
345 bool searchOutside =
false;
346 QPair<int, int> currentEdge { -1, -1 };
348 int currentAddedVertex = -1;
349 int nextCutFace = -1;
354 if ( mCurrentSnappedVertex == -1 )
357 if ( currentFaceIndex == leftFace )
358 currentFaceIndex = -1;
360 if ( mCurrentSnappedVertex != -1 && !searchOutside )
363 currentFaceIndex = -1;
364 int previousSnappedVertex = -1;
365 int intersectionFaceIndex = -1;
366 QgsPoint intersectionPoint( 0, 0, 0 );
367 int edgePosition = -1;
369 bool result = searchIntersectionEdgeFromSnappedVertex( intersectionFaceIndex, previousSnappedVertex, mCurrentSnappedVertex, intersectionPoint, edgePosition, treatedFaces );
374 if ( mCurrentSnappedVertex != -1 && mPoint2.distance( triangularMesh->
vertices().at( mCurrentSnappedVertex ) ) < mTolerance )
378 searchOutside =
true;
382 if ( mEndOnPoint2 && mCurrentSnappedVertex == mPoint2VertexIndex )
388 if ( mCurrentSnappedVertex != -1 )
392 buildHolesWithOneFace( mEditor, intersectionFaceIndex, previousSnappedVertex, mCurrentSnappedVertex, mHoleOnLeft, mNeighborOnLeft, mHoleOnRight, mNeighborOnRight );
394 mRemovedFaces.append( intersectionFaceIndex );
396 if ( finishForcingLine() )
405 nextCutFace = cutEdgeFromSnappedVertex( mEditor, intersectionFaceIndex, previousSnappedVertex, edgePosition, mHoleOnLeft, mNeighborOnLeft, mHoleOnRight, mNeighborOnRight );
407 mRemovedFaces.append( intersectionFaceIndex );
409 int iv1 = mHoleOnLeft.last();
410 int iv2 = mHoleOnRight.last();
412 if ( mNewVertexOnIntersection )
414 currentAddedVertex = startingVertexIndex +
mVerticesToAdd.count();
416 if ( mInterpolateZValueOnMesh )
417 interpolateZValue( intersectionPoint, triangularMesh->
vertices().at( iv1 ), triangularMesh->
vertices().at( iv2 ) );
419 interpolateZValue( intersectionPoint, mPoint1, mPoint2 );
423 if ( nextCutFace != -1 )
425 mCurrentSnappedVertex = -1;
426 currentFaceIndex = nextCutFace;
427 currentEdge = { mHoleOnLeft.last(), mHoleOnRight.last() };
432 if ( !mNewVertexOnIntersection )
434 currentAddedVertex = startingVertexIndex +
mVerticesToAdd.count();
435 if ( mInterpolateZValueOnMesh )
436 interpolateZValue( intersectionPoint, triangularMesh->
vertices().at( iv1 ), triangularMesh->
vertices().at( iv2 ) );
438 interpolateZValue( intersectionPoint, mPoint1, mPoint2 );
442 mNewVerticesIndexesOnLine.removeLast();
444 mHoleOnLeft.append( currentAddedVertex );
445 mNeighborOnLeft.append( -1 );
446 mHoleOnRight.append( currentAddedVertex );
447 mNeighborOnRight.append( -1 );
449 if ( finishForcingLine() )
454 leftFace = intersectionFaceIndex;
457 mCurrentPointPosition = intersectionPoint;
461 else if ( nextCutFace != -1 )
464 const QVector<int> &neighbors = mEditor->topologicalMesh().neighborsOfFace( nextCutFace );
465 int faceSize = face.size();
467 currentFaceIndex = nextCutFace;
469 mRemovedFaces.append( nextCutFace );
471 int edgePositionOnLeft = vertexPositionInFace( currentEdge.first, face );
472 int edgePositionOnRight = vertexPositionInFace( currentEdge.second, face );
473 int firstEdgeToTest = vertexPositionInFace( currentEdge.second, face );
475 bool foundSomething =
false;
477 for (
int fi = 0; fi < faceSize; ++fi )
479 int iv1 = face.at( ( firstEdgeToTest + fi ) % faceSize );
480 int iv2 = face.at( ( firstEdgeToTest + fi + 1 ) % faceSize );
482 if ( iv1 == currentEdge.first && iv2 == currentEdge.second )
486 QgsPoint intersection( 0, 0, 0 );
487 if ( edgeIntersection( iv1, iv2, snapVertex, intersection,
false ) || snapVertex != -1 )
489 foundSomething =
true;
491 int endPositionOnRight;
492 int endPositionOnLeft;
494 if ( snapVertex != -1 )
497 endPositionOnRight = vertexPositionInFace( snapVertex, face );
498 endPositionOnLeft = vertexPositionInFace( snapVertex, face );
501 currentEdge = { -1, -1 };
502 mCurrentSnappedVertex = snapVertex;
507 endPositionOnLeft = vertexPositionInFace( iv2, face );
508 endPositionOnRight = vertexPositionInFace( iv1, face );
510 nextCutFace = neighbors.at( endPositionOnRight );
512 if ( mNewVertexOnIntersection )
514 currentAddedVertex = startingVertexIndex +
mVerticesToAdd.count();
516 if ( mInterpolateZValueOnMesh )
517 interpolateZValue( intersection, triangularMesh->
vertices().at( iv1 ), triangularMesh->
vertices().at( iv2 ) );
519 interpolateZValue( intersection, mPoint1, mPoint2 );
524 int currentPos = edgePositionOnLeft;
525 while ( currentPos != endPositionOnLeft )
527 int nextPos = ( currentPos - 1 + faceSize ) % faceSize;
528 mHoleOnLeft.append( face.at( nextPos ) );
529 int neighborPos = nextPos;
530 mNeighborOnLeft.append( neighbors.at( neighborPos ) );
531 currentPos = nextPos;
534 currentPos = edgePositionOnRight;
535 while ( currentPos != endPositionOnRight )
537 int nextPos = ( currentPos + 1 ) % faceSize;
538 mHoleOnRight.append( face.at( nextPos ) );
539 int neighborPos = ( nextPos + faceSize - 1 ) % faceSize;
540 mNeighborOnRight.append( neighbors.at( neighborPos ) );
541 currentPos = nextPos;
544 mCurrentPointPosition = intersection;
546 if ( snapVertex != -1 )
548 currentEdge = { -1, -1 };
550 if ( finishForcingLine() )
552 mIsFinished = mEndOnPoint2 && mPoint2VertexIndex == snapVertex;
561 else if ( nextCutFace == -1 )
564 if ( !mNewVertexOnIntersection )
566 currentAddedVertex = startingVertexIndex +
mVerticesToAdd.count();
567 if ( mInterpolateZValueOnMesh )
568 interpolateZValue( intersection, triangularMesh->
vertices().at( iv1 ), triangularMesh->
vertices().at( iv2 ) );
570 interpolateZValue( intersection, mPoint1, mPoint2 );
574 mNewVerticesIndexesOnLine.removeLast();
576 mHoleOnLeft.append( currentAddedVertex );
577 mNeighborOnLeft.append( -1 );
578 mHoleOnRight.append( currentAddedVertex );
579 mNeighborOnRight.append( -1 );
581 if ( finishForcingLine() )
590 currentEdge = { mHoleOnLeft.last(), mHoleOnRight.last() };
596 if ( !foundSomething )
602 else if ( currentFaceIndex == -1 || searchOutside )
605 const QgsRectangle bbox( mCurrentPointPosition, mPoint2 );
607 int closestFaceIndex = -1;
608 int closestEdge = -1;
609 int closestSnapVertex = -1;
610 double minimalDistance = std::numeric_limits<double>::max();
611 QgsPoint closestIntersectionPoint( 0, 0, 0 );
612 for (
const int candidateFaceIndex : candidateFacesIndexes )
614 if ( candidateFaceIndex == leftFace )
617 if ( treatedFaces.contains( candidateFaceIndex ) )
621 const int faceSize = candidateFace.size();
623 for (
int i = 0; i < faceSize; ++i )
625 int iv1 = candidateFace.at( i );
626 int iv2 = candidateFace.at( ( i + 1 ) % faceSize );
628 if ( iv1 == mCurrentSnappedVertex || iv2 == mCurrentSnappedVertex )
632 QgsPoint intersectionPoint;
633 bool isIntersect = edgeIntersection( iv1, iv2, snapVertex, intersectionPoint,
true );
637 double distance = intersectionPoint.
distance( mCurrentPointPosition );
638 if ( distance < minimalDistance )
640 closestFaceIndex = candidateFaceIndex;
641 closestEdge = candidateFace.at( i );
642 closestSnapVertex = snapVertex;
643 closestIntersectionPoint = intersectionPoint;
644 minimalDistance = distance;
650 if ( closestFaceIndex < 0 || closestEdge < 0 )
657 mCurrentSnappedVertex = closestSnapVertex;
658 treatedFaces.insert( closestFaceIndex );
659 searchOutside =
false;
660 if ( mCurrentSnappedVertex == -1 )
664 currentAddedVertex = startingVertexIndex +
mVerticesToAdd.count();
666 nextCutFace = closestFaceIndex;
668 mHoleOnRight.append( currentAddedVertex );
669 mHoleOnRight.append( face.at( ( vertexPositionInFace( closestEdge, face ) + 1 ) % face.size() ) );
670 mNeighborOnRight.append( -1 );
673 mHoleOnLeft.append( currentAddedVertex );
674 mHoleOnLeft.append( closestEdge );
675 mNeighborOnLeft.append( -1 );
677 currentEdge = { mHoleOnLeft.last(), mHoleOnRight.last() };
679 if ( mInterpolateZValueOnMesh )
680 interpolateZValue( closestIntersectionPoint, triangularMesh->
vertices().at( mHoleOnLeft.last() ), triangularMesh->
vertices().at( mHoleOnRight.last() ) );
682 interpolateZValue( closestIntersectionPoint, mPoint1, mPoint2 );
688 else if ( mCurrentSnappedVertex == -1 )
691 double minimalDistance = std::numeric_limits<double>::max();
693 for (
int i = 0; i < face.size(); ++i )
696 const double distance = mCurrentPointPosition.distance( vertex );
697 if ( distance < mTolerance && distance < minimalDistance )
699 minimalDistance = distance;
700 mCurrentSnappedVertex = face.at( i );
703 searchOutside =
false;
705 if ( mCurrentSnappedVertex == -1 )
711 if ( mCurrentSnappedVertex != -1 )
713 if ( mCurrentSnappedVertex == mPoint2VertexIndex )
718 mCurrentPointPosition = triangularMesh->
vertices().at( mCurrentSnappedVertex );
727bool QgsMeshEditForceByLine::searchIntersectionEdgeFromSnappedVertex(
728 int &intersectionFaceIndex,
int &previousSnappedVertex,
int ¤tSnappedVertexIndex,
QgsPoint &intersectionPoint,
int &edgePosition, QSet<int> &treatedFaces
731 previousSnappedVertex = currentSnappedVertexIndex;
732 QSet<int> treatedVertices;
736 treatedVertices.insert( currentSnappedVertexIndex );
737 const QList<int> facesAround = mEditor->topologicalMesh().facesAroundVertex( currentSnappedVertexIndex );
739 bool foundSomething =
false;
740 for (
const int faceIndex : std::as_const( facesAround ) )
742 const QgsMeshFace &face = mEditor->topologicalMesh().mesh()->face( faceIndex );
743 int faceSize = face.size();
744 int vertexPos = vertexPositionInFace( currentSnappedVertexIndex, face );
745 QgsPoint oppositeIntersectionPoint;
746 int newSnapVertex = -1;
747 for (
int i = 1; i < faceSize - 1; ++i )
749 edgePosition = ( vertexPos + i ) % faceSize;
750 foundSomething = edgeIntersection( face.at( edgePosition ), face.at( ( edgePosition + 1 ) % faceSize ), newSnapVertex, intersectionPoint,
false );
752 if ( mEndOnPoint2 && newSnapVertex == mPoint2VertexIndex )
754 mCurrentSnappedVertex = newSnapVertex;
758 if ( newSnapVertex != -1 )
759 foundSomething = ( newSnapVertex != previousSnappedVertex && !treatedVertices.contains( newSnapVertex ) );
761 if ( foundSomething )
765 if ( foundSomething )
767 treatedFaces.insert( faceIndex );
768 if ( newSnapVertex != -1 )
770 previousSnappedVertex = currentSnappedVertexIndex;
771 currentSnappedVertexIndex = newSnapVertex;
772 if ( newSnapVertex == face.at( ( vertexPos + 1 ) % faceSize ) || newSnapVertex == face.at( ( vertexPos - 1 + faceSize ) % faceSize ) )
775 mCurrentPointPosition = mEditor->triangularMesh()->vertices().at( newSnapVertex );
780 intersectionFaceIndex = faceIndex;
786 intersectionFaceIndex = faceIndex;
787 previousSnappedVertex = currentSnappedVertexIndex;
788 currentSnappedVertexIndex = -1;
794 if ( !foundSomething )
801bool QgsMeshEditForceByLine::triangulateHoles(
const QList<int> &hole,
const QList<int> &neighbors,
bool isLeftHole, QList<std::array<int, 2>> &newFacesOnLine, std::array<int, 2> &extremeFaces )
803 QgsMesh *mesh = mEditor->topologicalMesh().mesh();
806 for (
int i = 0; i < hole.count(); ++i )
808 for (
int j = i + 1; j < hole.count(); ++j )
810 if ( hole.at( i ) == hole.at( j ) )
821 std::vector<p2t::Point *> holeToFill;
824 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
825 holeToFill.resize( hole.count() + mNewVerticesIndexesOnLine.count() );
826 for (
int i = 0; i < hole.count(); ++i )
828 int vertexIndex = hole.at( i );
830 if ( vertexIndex < mesh->vertexCount() )
831 vertex = mesh->
vertex( vertexIndex );
835 holeToFill[i] =
new p2t::Point( vertex.
x(), vertex.
y() );
836 mapPoly2TriPointToVertex.insert( holeToFill[i], vertexIndex );
839 const int verticesOnLineCount = mNewVerticesIndexesOnLine.count();
840 for (
int i = 0; i < verticesOnLineCount; ++i )
842 int vertexLocalIndex = mNewVerticesIndexesOnLine.at( verticesOnLineCount - i - 1 );
844 holeToFill[i + hole.count()] =
new p2t::Point( vertex.
x(), vertex.
y() );
845 mapPoly2TriPointToVertex.insert( holeToFill[i + hole.count()], vertexLocalIndex + mesh->
vertexCount() );
848 auto cdt = std::make_unique<p2t::CDT>( holeToFill );
850 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
851 QVector<QgsMeshFace> newFaces( triangles.size() );
852 for (
size_t i = 0; i < triangles.size(); ++i )
856 for (
int j = 0; j < 3; j++ )
858 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
860 throw std::exception();
865 QgsMeshEditingError error;
868 throw std::exception();
870 const QVector<QgsMeshFace> &facesToAdd = topologicalFaces.
meshFaces();
874 for (
const int vtc : hole )
876 int firstLinkedFace = mEditor->topologicalMesh().firstFaceLinked( vtc );
877 if ( mRemovedFaces.contains( firstLinkedFace ) )
882 for (
int i = 0; i < facesToAdd.count(); ++i )
886 for (
int n = 0; n < faceNeighbors.count(); ++n )
888 if ( faceNeighbors.at( n ) != -1 )
889 faceNeighbors[n] += startingFaceGlobalIndex;
894 for (
int i = 0; i < hole.count() - 1; ++i )
896 int vertexHoleIndex = hole.at( i );
897 int meshFaceBoundaryIndex = neighbors.at( i );
899 QgsMeshVertexCirculator circulator = QgsMeshVertexCirculator( topologicalFaces, vertexHoleIndex );
901 throw std::exception();
909 int newFaceBoundaryIndexInMesh = circulator.
currentFaceIndex() + startingFaceGlobalIndex;
911 int positionInNewFaces = vertexPositionInFace( vertexHoleIndex, newFace );
913 positionInNewFaces = ( positionInNewFaces - 1 + newFace.size() ) % newFace.size();
915 if ( meshFaceBoundaryIndex != -1 )
919 int positionInMeshFaceBoundary = vertexPositionInFace( *mesh, vertexHoleIndex, meshFaceBoundaryIndex );
921 positionInMeshFaceBoundary = ( positionInMeshFaceBoundary - 1 + meshFace.size() ) % meshFace.size();
923 int oldNeighbor = mEditor->topologicalMesh().neighborsOfFace( meshFaceBoundaryIndex ).at( positionInMeshFaceBoundary );
924 mNeighborhoodChanges.append( { meshFaceBoundaryIndex, positionInMeshFaceBoundary, oldNeighbor, newFaceBoundaryIndexInMesh } );
927 mFacesNeighborhoodToAdd[newFaceBoundaryLocalIndex + startingFaceLocalIndex][positionInNewFaces] = meshFaceBoundaryIndex;
931 int vertexOnLine = hole.at( 0 );
932 while ( vertexOnLine != hole.last() )
934 QgsMeshVertexCirculator circulatorOnLine( topologicalFaces, vertexOnLine );
938 circulatorOnLine.goBoundaryClockwise();
939 nextVertex = circulatorOnLine.oppositeVertexClockwise();
943 circulatorOnLine.goBoundaryCounterClockwise();
944 nextVertex = circulatorOnLine.oppositeVertexCounterClockwise();
946 const QgsMeshFace &faceOnLine = circulatorOnLine.currentFace();
947 int positionOnFaceOnTheLine = vertexPositionInFace( vertexOnLine, faceOnLine );
949 positionOnFaceOnTheLine = ( positionOnFaceOnTheLine - 1 + faceOnLine.size() ) % faceOnLine.size();
951 newFacesOnLine.append( { circulatorOnLine.currentFaceIndex() + startingFaceLocalIndex, positionOnFaceOnTheLine } );
952 vertexOnLine = nextVertex;
955 QgsMeshVertexCirculator circulatorOnStart( topologicalFaces, hole.first() );
957 circulatorOnStart.goBoundaryCounterClockwise();
959 circulatorOnStart.goBoundaryClockwise();
961 QgsMeshVertexCirculator circulatorOnEnd( topologicalFaces, hole.last() );
963 circulatorOnEnd.goBoundaryClockwise();
965 circulatorOnEnd.goBoundaryCounterClockwise();
968 extremeFaces = { circulatorOnStart.currentFaceIndex() + startingFaceLocalIndex, circulatorOnEnd.currentFaceIndex() + startingFaceLocalIndex };
969 qDeleteAll( holeToFill );
973 qDeleteAll( holeToFill );
981bool QgsMeshEditForceByLine::finishForcingLine()
983 QgsMesh *mesh = mEditor->topologicalMesh().mesh();
985 QList<std::array<int, 2>> newLeftFacesOnLine;
986 QList<std::array<int, 2>> newRightFacesOnLine;
988 std::array<int, 2> extremeFacesOnLeft;
989 std::array<int, 2> extremeFacesOnRight;
991 if ( !triangulateHoles( mHoleOnLeft, mNeighborOnLeft,
true, newLeftFacesOnLine, extremeFacesOnLeft ) )
993 if ( !triangulateHoles( mHoleOnRight, mNeighborOnRight,
false, newRightFacesOnLine, extremeFacesOnRight ) )
997 if ( newLeftFacesOnLine.count() != newRightFacesOnLine.count() )
1000 for (
int i = 0; i < newLeftFacesOnLine.count(); ++i )
1002 int leftFaceLocalIndex = newLeftFacesOnLine.at( i ).at( 0 );
1003 int leftPositionInFace = newLeftFacesOnLine.at( i ).at( 1 );
1004 int rightFaceLocalIndex = newRightFacesOnLine.at( i ).at( 0 );
1005 int rightPositionInFace = newRightFacesOnLine.at( i ).at( 1 );
1013 const int firstVertexIndex = mHoleOnLeft.first();
1016 const int firstVertexLocalIndex = firstVertexIndex - mesh->
vertexCount();
1020 const int lastVertexIndex = mHoleOnLeft.last();
1023 const int lastVertexLocalIndex = lastVertexIndex - mesh->
vertexCount();
1027 for (
int i = 0; i < mNewVerticesIndexesOnLine.count(); ++i )
1032 for (
const int fi : std::as_const( mRemovedFaces ) )
1039 mRemovedFaces.clear();
1040 mHoleOnLeft.clear();
1041 mNeighborOnLeft.clear();
1042 mHoleOnRight.clear();
1043 mNeighborOnRight.clear();
1044 mNewVerticesIndexesOnLine.clear();
1051 return QObject::tr(
"Force mesh by polyline" );
1061 if ( mPolylines.isEmpty() )
1067 if ( mCurrentPolyline == 0 && mCurrentSegment == 0 )
1069 setInputLine( mPolylines.at( 0 ).at( 0 ), mPolylines.at( 0 ).at( 1 ), mTolerance, mNewVertexOnIntersection );
1072 return QgsMeshEditForceByLine::apply( meshEditor );
1077 setInputLine( mPolylines.at( mCurrentPolyline ).at( mCurrentSegment ), mPolylines.at( mCurrentPolyline ).at( mCurrentSegment + 1 ), mTolerance, mNewVertexOnIntersection );
1081 return QgsMeshEditForceByLine::apply( meshEditor );
1086 std::vector<const QgsCurve *> curves;
1089 std::vector< const QgsCurvePolygon * > polygons;
1104 if ( polygon->exteriorRing() )
1105 curves.emplace_back( polygon->exteriorRing() );
1107 for (
int i = 0; i < polygon->numInteriorRings(); ++i )
1108 curves.emplace_back( polygon->interiorRing( i ) );
1123 for (
const QgsCurve *curve : curves )
1129 curve->points( linePoints );
1130 if ( linePoints.count() < 2 )
1132 if ( !curve->is3D() )
1134 for (
int i = 0; i < linePoints.count(); ++i )
1136 const QgsPoint &point = linePoints.at( i );
1137 linePoints[i] =
QgsPoint( point.
x(), point.
y(), mDefaultZValue );
1140 mPolylines.append( linePoints );
1152 mTolerance = tolerance;
1157 mNewVertexOnIntersection = addVertex;
1162 mDefaultZValue = defaultZValue;
1167 mInterpolateZValueOnMesh = interpolateZValueOnMesh;
1170void QgsMeshEditForceByPolylines::incrementSegment()
1173 if ( mCurrentSegment >= mPolylines.at( mCurrentPolyline ).count() - 1 )
1175 mCurrentSegment = 0;
Curve polygon geometry type.
Abstract base class for curved geometry type.
int numGeometries() const
Returns the number of geometries within the collection.
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
static bool segmentIntersection(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q1, const QgsPoint &q2, QgsPoint &intersectionPoint, bool &isIntersection, double tolerance=1e-8, bool acceptImproperIntersection=false)
Compute the intersection between two segments.
A geometry is the spatial representation of a feature.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
Qgis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.).
void clear()
Removes all data provided to the editing or created by the editing.
virtual bool isFinished() const
Returns whether the advanced edit is finished, if not, this edit has to be applied again with QgsMesh...
void setAddVertexOnIntersection(bool addVertex)
Sets whether vertices will be added when the lines will intersect internal edges of faces,...
void setInputLine(const QgsPoint &pt1, const QgsPoint &pt2, double tolerance, bool newVertexOnIntersection)
Sets the input forcing line in rendering coordinates.
void setDefaultZValue(double defaultZValue)
Sets the default value of Z coordinate to use for new vertices, this value will be used if the Z valu...
void setTolerance(double tolerance)
Sets the tolerance in redering coordinate system unit.
void setInterpolateZValueOnMesh(bool interpolateZValueOnMesh)
Sets whether the new created vertices will have their value interpolated from the existing mesh.
QString text() const override
Returns a short text string describing what this advanced edit does. Default implementation return a ...
void addLinesFromGeometries(const QList< QgsGeometry > geometries)
Adds a list of input forcing lines geometry in rendering coordinates.
bool isFinished() const override
Returns whether the advanced edit is finished, if not, this edit has to be applied again with QgsMesh...
void addLineFromGeometry(const QgsGeometry &geom)
Adds a input forcing line geometry in rendering coordinates.
Qgis::MeshEditingErrorType errorType
Handles edit operations on a mesh layer.
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.
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.
Point geometry type, with support for z-dimension and m-values.
double distance(double x, double y) const
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
void setZ(double z)
Sets the point's z-coordinate.
Contains topological differences between two states of a topological mesh, only accessible from the Q...
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
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.
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.
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.
const QVector< QgsMeshFace > & triangles() const
Returns triangles.
int nativeFaceIndexForPoint(const QgsPointXY &point) const
Finds index of native face at given point It uses spatial indexing.
const QVector< QgsMeshVertex > & vertices() const
Returns vertices in map coordinate system.
QgsMeshVertex triangularToNativeCoordinates(const QgsMeshVertex &vertex) const
Transforms the vertex from triangular mesh coordinates system to native coordinates system.
QList< int > nativeFaceIndexForRectangle(const QgsRectangle &rectangle) const
Finds indexes of native faces which bounding boxes intersect given bounding box It uses spatial index...
int faceIndexForPoint_v2(const QgsPointXY &point) const
Finds index of triangle at given point It uses spatial indexing and don't use geos to be faster.
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
T qgsgeometry_cast(QgsAbstractGeometry *geom)
QVector< QgsPoint > QgsPointSequence
QVector< int > QgsMeshFace
List of vertex indexes.
QgsPoint QgsMeshVertex
xyz coords of vertex
Mesh - vertices, edges and faces.
int vertexCount() const
Returns number of vertices.
QVector< QgsMeshVertex > vertices
QgsMeshFace face(int index) const
Returns a face at the index.
int faceCount() const
Returns number of faces.
QgsMeshVertex vertex(int index) const
Returns a vertex at the index.