30using namespace Qt::StringLiterals;
74 QSet<int> facesToRefine = qgis::listToSet(
mInputFaces );
75 QHash<int, FaceRefinement> facesRefinement;
76 QHash<int, BorderFace> borderFaces;
78 createNewVerticesAndRefinedFaces( meshEditor, facesToRefine, facesRefinement );
79 if ( !createNewBorderFaces( meshEditor, facesToRefine, facesRefinement, borderFaces ) )
104void QgsMeshEditRefineFaces::createNewVerticesAndRefinedFaces(
QgsMeshEditor *meshEditor, QSet<int> &facesToRefine, QHash<int, FaceRefinement> &facesRefinement )
110 int startingGlobalFaceIndex = mesh.
faceCount();
112 auto canBeRefined = [&](
int fi ) ->
bool {
115 int fs = mesh.
face( fi ).size();
116 return fs == 3 || fs == 4;
119 for (
const int faceIndex : std::as_const(
mInputFaces ) )
121 FaceRefinement refinement;
124 int faceSize = face.size();
126 QVector<int> addedVerticesIndex( faceSize, -1 );
128 if ( canBeRefined( faceIndex ) )
130 refinement.newVerticesLocalIndex.reserve( faceSize );
131 refinement.refinedFaceNeighbor.reserve( faceSize );
132 refinement.borderFaceNeighbor.reserve( faceSize );
135 double zValueSum = 0;
137 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
139 refinement.refinedFaceNeighbor.append(
false );
140 refinement.borderFaceNeighbor.append(
false );
142 int neighborFaceIndex = neighbors.at( positionInFace );
143 bool needCreateVertex =
true;
144 if ( neighborFaceIndex != -1 && facesToRefine.contains( neighborFaceIndex ) && canBeRefined( neighborFaceIndex ) )
146 int neighborFaceSize = mesh.
face( neighborFaceIndex ).size();
148 positionVertexInNeighbor = ( positionVertexInNeighbor + neighborFaceSize - 1 ) % neighborFaceSize;
149 refinement.refinedFaceNeighbor[positionInFace] =
true;
150 QHash<int, FaceRefinement>::iterator it = facesRefinement.find( neighborFaceIndex );
151 if ( it != facesRefinement.end() )
153 FaceRefinement &neighborRefinement = it.value();
154 int existingVertexLocalIndex = neighborRefinement.newVerticesLocalIndex.at( positionVertexInNeighbor );
155 refinement.newVerticesLocalIndex.append( existingVertexLocalIndex );
156 needCreateVertex =
false;
161 if ( needCreateVertex )
164 const QgsMeshVertex &vertex2 = mesh.
vertex( face.at( ( positionInFace + 1 ) % faceSize ) );
166 refinement.newVerticesLocalIndex.append(
mVerticesToAdd.count() );
176 int faceStartIndex = startingGlobalFaceIndex +
mFacesToAdd.count();
180 for (
int i = 0; i < faceSize; ++i )
183 { face.at( i ), refinement.newVerticesLocalIndex.at( i ) + startingVertexIndex, refinement.newVerticesLocalIndex.at( ( i + faceSize - 1 ) % faceSize ) + startingVertexIndex }
185 refinement.newFacesChangesIndex.append(
mFacesToAdd.count() );
190 { refinement.newVerticesLocalIndex.at( 0 ) + startingVertexIndex,
191 refinement.newVerticesLocalIndex.at( 1 ) + startingVertexIndex,
192 refinement.newVerticesLocalIndex.at( ( 2 ) % faceSize ) + startingVertexIndex }
194 refinement.newFacesChangesIndex.append(
mFacesToAdd.count() );
201 int centerVertexIndex =
mVerticesToAdd.count() + startingVertexIndex;
206 for (
int i = 0; i < faceSize; ++i )
209 { face.at( i ), refinement.newVerticesLocalIndex.at( i ) + startingVertexIndex, centerVertexIndex, refinement.newVerticesLocalIndex.at( ( i + faceSize - 1 ) % faceSize ) + startingVertexIndex }
211 refinement.newFacesChangesIndex.append(
mFacesToAdd.count() );
219 refinement.newCenterVertexIndex = -1;
221 facesRefinement.insert( faceIndex, refinement );
224 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
226 if ( addedVerticesIndex.at( positionInFace ) != -1 )
228 mVertexToFaceToAdd[addedVerticesIndex.at( positionInFace )] = refinement.newFacesChangesIndex.at( positionInFace ) + startingGlobalFaceIndex;
231 int vertexIndex = face.at( positionInFace );
233 mVerticesToFaceChanges.append( { vertexIndex, faceIndex, refinement.newFacesChangesIndex.at( positionInFace ) + startingGlobalFaceIndex } );
239 facesToRefine.remove( faceIndex );
244 for ( QHash<int, FaceRefinement>::iterator it = facesRefinement.begin(); it != facesRefinement.end(); ++it )
246 int faceIndex = it.key();
247 FaceRefinement &faceRefinement = it.value();
249 int faceSize = face.size();
253 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
255 if ( faceRefinement.refinedFaceNeighbor.at( positionInFace ) )
257 int neighborIndex = neighbors.at( positionInFace );
258 int firstVertexIndex = face.at( positionInFace );
259 int secondVertexIndex = faceRefinement.newVerticesLocalIndex.at( positionInFace ) + startingVertexIndex;
261 const FaceRefinement &otherRefinement = facesRefinement.value( neighborIndex );
263 int otherFaceSize = otherFace.size();
266 int newFace1ChangesIndex = faceRefinement.newFacesChangesIndex.at( ( positionInFace ) );
270 int newFace2ChangesIndex = faceRefinement.newFacesChangesIndex.at( ( positionInFace + 1 ) % faceSize );
274 int otherNewFace1ChangesIndex = otherRefinement.newFacesChangesIndex.at( ( otherPositionInface ) % otherFaceSize );
275 int otherNewFace2ChangesIndex = otherRefinement.newFacesChangesIndex.at( ( otherPositionInface + 1 ) % otherFaceSize );
277 mFacesNeighborhoodToAdd[newFace1ChangesIndex][positionInNewface1Index] = otherNewFace2ChangesIndex + startingGlobalFaceIndex;
278 mFacesNeighborhoodToAdd[newFace2ChangesIndex][positionInNewface2Index] = otherNewFace1ChangesIndex + startingGlobalFaceIndex;
284bool QgsMeshEditRefineFaces::createNewBorderFaces(
QgsMeshEditor *meshEditor,
const QSet<int> &facesToRefine, QHash<int, FaceRefinement> &facesRefinement, QHash<int, BorderFace> &borderFaces )
290 int startingFaceChangesGlobalIndex = mesh.
faceCount();
293 for (
int faceIndexToRefine : facesToRefine )
296 int faceToRefineSize = faceToRefine.size();
298 const QVector<int> &neighbors = topology.
neighborsOfFace( faceIndexToRefine );
300 QHash<int, FaceRefinement>::iterator itFace = facesRefinement.find( faceIndexToRefine );
302 if ( itFace == facesRefinement.end() )
305 FaceRefinement &refinement = itFace.value();
307 for (
int posInFaceToRefine = 0; posInFaceToRefine < faceToRefineSize; ++posInFaceToRefine )
309 int neighborFaceIndex = neighbors.at( posInFaceToRefine );
310 if ( neighborFaceIndex != -1 && !facesToRefine.contains( neighborFaceIndex ) )
313 int neighborFaceSize = neighborFace.size();
315 positionInNeighbor = ( positionInNeighbor + neighborFaceSize - 1 ) % neighborFaceSize;
317 QHash<int, BorderFace>::iterator it = borderFaces.find( neighborFaceIndex );
318 if ( it == borderFaces.end() )
320 BorderFace borderFace;
321 for (
int i = 0; i < neighborFaceSize; ++i )
323 borderFace.unchangeFacesNeighbor.append(
false );
324 borderFace.borderFacesNeighbor.append(
false );
325 if ( i == positionInNeighbor )
327 borderFace.refinedFacesNeighbor.append(
true );
328 borderFace.newVerticesLocalIndex.append( refinement.newVerticesLocalIndex.at( posInFaceToRefine ) );
332 borderFace.refinedFacesNeighbor.append(
false );
333 borderFace.newVerticesLocalIndex.append( -1 );
336 borderFaces.insert( neighborFaceIndex, borderFace );
340 BorderFace &borderFace = it.value();
341 for (
int i = 0; i < neighborFaceSize; ++i )
343 if ( i == positionInNeighbor )
345 borderFace.unchangeFacesNeighbor[i] =
false;
346 borderFace.borderFacesNeighbor[i] =
false;
347 borderFace.refinedFacesNeighbor[i] =
true;
348 borderFace.newVerticesLocalIndex[i] = refinement.newVerticesLocalIndex.at( posInFaceToRefine );
357 for ( QHash<int, BorderFace>::iterator it = borderFaces.begin(); it != borderFaces.end(); ++it )
359 int faceIndex = it.key();
360 BorderFace &borderFace = it.value();
363 int faceSize = face.size();
366 for (
int posInFace = 0; posInFace < faceSize; ++posInFace )
368 int neighborIndex = neighbors.at( posInFace );
370 if ( neighborIndex != -1 )
373 int neighborFaceSize = neighborFace.size();
375 posInNeighbor = ( posInNeighbor - 1 + neighborFaceSize ) % neighborFaceSize;
377 QHash<int, FaceRefinement>::iterator itRefinement = facesRefinement.find( neighborIndex );
378 if ( itRefinement != facesRefinement.end() )
380 FaceRefinement &neighborRefinement = itRefinement.value();
381 neighborRefinement.borderFaceNeighbor[posInNeighbor] =
true;
382 borderFace.refinedFacesNeighbor[posInFace] =
true;
386 QHash<int, BorderFace>::iterator itNeighborBorder = borderFaces.find( neighborIndex );
387 if ( itNeighborBorder == borderFaces.end() )
388 borderFace.unchangeFacesNeighbor[posInFace] =
true;
391 BorderFace &neighborBorderFace = itNeighborBorder.value();
392 neighborBorderFace.borderFacesNeighbor[posInNeighbor] =
true;
393 borderFace.borderFacesNeighbor[posInFace] =
true;
398 borderFace.unchangeFacesNeighbor[posInFace] =
true;
403 for ( QHash<int, BorderFace>::iterator it = borderFaces.begin(); it != borderFaces.end(); ++it )
405 int faceIndex = it.key();
406 BorderFace &borderFace = it.value();
409 int faceSize = face.size();
411 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
412 std::vector<p2t::Point *> points;
413 for (
int i = 0; i < faceSize; ++i )
416 points.push_back(
new p2t::Point( vert.
x(), vert.
y() ) );
417 mapPoly2TriPointToVertex.insert( points.back(), face.at( i ) );
418 if ( borderFace.refinedFacesNeighbor.at( i ) )
420 int localVertexIndex = borderFace.newVerticesLocalIndex.at( i );
422 points.push_back(
new p2t::Point( newVert.
x(), newVert.
y() ) );
423 mapPoly2TriPointToVertex.insert( points.back(), localVertexIndex + startingVertexIndex );
429 auto cdt = std::make_unique<p2t::CDT>( points );
431 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
432 QVector<QgsMeshFace> faces( triangles.size() );
433 for (
size_t i = 0; i < triangles.size(); ++i )
436 triangle.resize( 3 );
437 QVector<QgsMeshVertex> vertices( 3 );
438 for (
int j = 0; j < 3; j++ )
440 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
442 throw std::exception();
444 triangle[j] = vertInd;
445 if ( vertInd >= startingVertexIndex )
448 vertices[j] = mesh.
vertex( vertInd );
455 QgsMeshEditingError error;
457 QVector<QgsTopologicalMesh::FaceNeighbors> neighborhood = topologicalFaces.
facesNeighborhood();
460 for (
int i = 0; i < neighborhood.count(); ++i )
463 for (
int j = 0; j < neighbors.count(); ++j )
465 if ( neighbors[j] != -1 )
466 neighbors[j] = neighbors[j] + startingFaceIndex;
473 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
475 if ( borderFace.refinedFacesNeighbor.at( positionInFace ) )
478 QVector<int> vertexIndexes( 2 );
479 QVector<int> localFaceIndex( 2 );
480 vertexIndexes[0] = face.at( positionInFace );
481 vertexIndexes[1] = borderFace.newVerticesLocalIndex.at( positionInFace ) + startingVertexIndex;
483 int refinedFaceIndex = neighborOfFace.at( positionInFace );
484 const FaceRefinement &faceRefinement = facesRefinement.value( refinedFaceIndex );
486 int refinedFaceSize = refinedFace.size();
489 for (
int i = 0; i < 2; ++i )
491 QgsMeshVertexCirculator circulator( topologicalFaces, vertexIndexes.at( i ) );
492 circulator.goBoundaryClockwise();
493 localFaceIndex[i] = circulator.currentFaceIndex();
497 const QgsMeshFace newFace = faces.at( localFaceIndex.at( i ) );
499 int newFaceRefinedIndexInChanges = faceRefinement.newFacesChangesIndex.at( ( positionInRefinedFace + ( 1 - i ) ) % refinedFaceSize );
500 neighborsNewFace[positionInNewFace] = newFaceRefinedIndexInChanges + startingFaceChangesGlobalIndex;
504 int newRefinedFaceSize = newRefinedFace.size();
506 neighborsRefinedFace[positionInNewRefinedChange] = localFaceIndex.at( i ) + startingFaceIndex;
509 borderFace.edgeFace.append( localFaceIndex.at( 0 ) + startingFaceIndex );
512 if ( borderFace.borderFacesNeighbor.at( positionInFace ) )
514 int vertexIndex = face.at( positionInFace );
515 QgsMeshVertexCirculator circulator( topologicalFaces, vertexIndex );
516 circulator.goBoundaryClockwise();
517 int localFaceIndex = circulator.currentFaceIndex();
520 borderFace.edgeFace.append( localFaceIndex + startingFaceIndex );
523 if ( borderFace.unchangeFacesNeighbor.at( positionInFace ) )
525 int vertexIndex = face.at( positionInFace );
526 QgsMeshVertexCirculator circulator( topologicalFaces, vertexIndex );
527 circulator.goBoundaryClockwise();
528 int localFaceIndex = circulator.currentFaceIndex();
530 const QgsMeshFace &newFace = faces.at( localFaceIndex );
533 int unchangedFaceIndex = neighborOfFace.at( positionInFace );
534 neighborsNewFace[positionInNewface] = unchangedFaceIndex;
536 if ( unchangedFaceIndex != -1 )
539 int unchangedFaceSize = unchangedFace.size();
541 mNeighborhoodChanges.append( { unchangedFaceIndex, positionInUnchangedFace, faceIndex, localFaceIndex + startingFaceIndex } );
544 borderFace.edgeFace.append( localFaceIndex + startingFaceIndex );
551 for ( p2t::Point *pt : points )
561 for ( QHash<int, BorderFace>::iterator it = borderFaces.begin(); it != borderFaces.end(); ++it )
563 int faceIndex = it.key();
564 BorderFace &borderFace = it.value();
566 int faceSize = face.size();
570 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
572 if ( borderFace.borderFacesNeighbor.at( positionInFace ) )
574 int otherIndex = neighbors.at( positionInFace );
576 int otherFaceSize = otherFace.size();
578 const BorderFace &otherBorderFace = borderFaces.value( otherIndex );
579 int otherNewFaceIndex = otherBorderFace.edgeFace.at( otherPositionInface );
581 int newFaceChangesIndex = borderFace.edgeFace.at( positionInFace ) - startingFaceChangesGlobalIndex;
589 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
591 int vertexIndex = face.at( positionInFace );
603 return QObject::tr(
"Refine %n face(s)",
nullptr,
mInputFaces.count() );
615 QSet<int> concernedFaces;
616 mChangingVertexMap = QHash<int, int>();
623 QVector<QgsMeshVertex> newVertices;
629 bool calcX = !mExpressionX.isEmpty();
630 bool calcY = !mExpressionY.isEmpty();
631 bool calcZ = !mExpressionZ.isEmpty();
636 expressionX.
prepare( &context );
643 expressionY.
prepare( &context );
646 if ( calcX || calcY )
653 if ( calcZ || mZFromTerrain )
656 expressionZ.
prepare( &context );
664 if ( mZFromTerrain && project )
667 if ( terrainProvider )
679 mChangingVertexMap[vertexIndex] = i;
680 const QVariant xvar = expressionX.
evaluate( &context );
681 const QVariant yvar = expressionY.
evaluate( &context );
682 const QVariant zvar = expressionZ.
evaluate( &context );
686 if ( calcX || calcY )
692 concernedFaces.unite( qgis::listToSet( facesAround ) );
698 if ( xvar.isValid() )
700 double x = xvar.toDouble( &ok );
716 if ( yvar.isValid() )
718 double y = yvar.toDouble( &ok );
730 if ( calcZ && !mZFromTerrain )
732 double z = std::numeric_limits<double>::quiet_NaN();
733 if ( zvar.isValid() )
735 z = zvar.toDouble( &ok );
737 z = std::numeric_limits<double>::quiet_NaN();
744 if ( mZFromTerrain && terrainProvider )
747 bool vertexTransformed;
752 if ( calcX || calcY )
758 point = transformation.
transform( vert.
x(), vert.
y() );
760 vertexTransformed =
true;
764 vertexTransformed =
false;
768 elevation = vert.
z();
770 if ( vertexTransformed )
772 double terrainElevation = terrainProvider->
heightAt( point.
x(), point.
y() );
774 if ( !std::isnan( terrainElevation ) )
776 elevation = terrainElevation;
793 return QObject::tr(
"Transform %n vertices by expression",
nullptr,
mInputVertices.count() );
798 mExpressionX = expressionX;
799 mExpressionY = expressionY;
800 mExpressionZ = expressionZ;
802 mChangingVertexMap.clear();
814 int pos = mChangingVertexMap.value( vertexIndex, -1 );
838 mZFromTerrain = enable;
Abstract base class for terrain providers.
virtual double heightAt(double x, double y) const =0
Returns the height at the point (x,y) in the terrain provider's native crs().
virtual QgsCoordinateReferenceSystem crs() const =0
Returns the native coordinate reference system of the terrain provider.
Custom exception class for Coordinate Reference System related exceptions.
void setVariable(const QString &name, const QVariant &value, bool isStatic=false)
Convenience method for setting a variable in the context scope by name name and value.
static QgsExpressionContextScope * meshExpressionScope(QgsMesh::ElementType elementType)
Creates a new scope which contains functions relating to mesh layer element elementType.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsExpressionContextScope * lastScope()
Returns the last scope added to the context.
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
Handles parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
QVariant evaluate()
Evaluate the feature and return the result.
QgsCoordinateReferenceSystem crs
QString message() const
Returns a message that can be provided by the advanced editing when applying is done.
void setInputVertices(const QList< int > verticesIndexes)
Sets the input vertices indexes that will be used for the editing.
virtual ~QgsMeshAdvancedEditing()
void clear()
Removes all data provided to the editing or created by the editing.
QList< int > mInputVertices
virtual bool isFinished() const
Returns whether the advanced edit is finished, if not, this edit has to be applied again with QgsMesh...
virtual QString text() const
Returns a short text string describing what this advanced edit does. Default implementation return a ...
void setInputFaces(const QList< int > faceIndexes)
Sets the input faces indexes that will be used for the editing.
QString text() const override
Returns a short text string describing what this advanced edit does. Default implementation return a ...
Handles edit operations on a mesh layer.
bool canBeTransformed(const QList< int > &facesToCheck, const std::function< const QgsMeshVertex(int)> &transformFunction) const
Returns true if faces with index in transformedFaces can be transformed without obtaining topologic o...
QgsTopologicalMesh & topologicalMesh()
Returns a reference to the topological mesh.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
QgsMeshEditor * meshEditor()
Returns a pointer to the mesh editor own by the mesh layer.
QgsMesh * nativeMesh()
Returns native mesh (nullptr before rendering or calling to updateMesh).
static void setCounterClockwise(QgsMeshFace &triangle, const QgsMeshVertex &v0, const QgsMeshVertex &v1, const QgsMeshVertex &v2)
Checks if the triangle is counter clockwise, if not sets it counter clockwise.
static QgsMeshVertex centroid(const QgsMeshFace &face, const QVector< QgsMeshVertex > &vertices)
Returns the centroid of the face.
QgsAbstractTerrainProvider * terrainProvider()
Returns the project's terrain provider.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
const QgsProjectElevationProperties * elevationProperties() const
Returns the project's elevation properties, which contains the project's elevation related settings.
Contains topological differences between two states of a topological mesh, only accessible from the Q...
QList< int > mChangeCoordinateVerticesIndexes
void clearChanges()
Clears all changes.
QVector< FaceNeighbors > mFacesNeighborhoodToRemove
QList< QgsPointXY > mNewXYValues
QList< std::array< int, 4 > > mNeighborhoodChanges
QList< int > mNativeFacesIndexesGeometryChanged
QVector< QgsMeshFace > mFacesToAdd
QVector< FaceNeighbors > mFacesNeighborhoodToAdd
QList< std::array< int, 3 > > mVerticesToFaceChanges
QList< QgsPointXY > mOldXYValues
friend class QgsTopologicalMesh
QList< double > mNewZValues
QVector< QgsMeshVertex > mVerticesToAdd
int mAddedFacesFirstIndex
QVector< int > mVertexToFaceToAdd
QList< int > mFaceIndexesToRemove
QVector< QgsMeshFace > mFacesToRemove
QList< double > mOldZValues
QVector< FaceNeighbors > facesNeighborhood() const
Returns the face neighborhood of the faces, indexing is local.
static int vertexPositionInFace(int vertexIndex, const QgsMeshFace &face)
Returns vertex position in face.
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
QList< int > facesAroundVertex(int vertexIndex) const
Returns the indexes of faces that are around the vertex with index vertexIndex.
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.
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.