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,
105 QSet<int> &facesToRefine,
106 QHash<int, FaceRefinement> &facesRefinement )
112 int startingGlobalFaceIndex = mesh.
faceCount();
114 auto canBeRefined = [ & ](
int fi )->
bool
118 int fs = mesh.
face( fi ).size();
119 return fs == 3 || fs == 4;
123 for (
const int faceIndex : std::as_const(
mInputFaces ) )
125 FaceRefinement refinement;
128 int faceSize = face.size();
130 QVector<int> addedVerticesIndex( faceSize, -1 );
132 if ( canBeRefined( faceIndex ) )
134 refinement.newVerticesLocalIndex.reserve( faceSize );
135 refinement.refinedFaceNeighbor.reserve( faceSize );
136 refinement.borderFaceNeighbor.reserve( faceSize );
139 double zValueSum = 0;
141 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
143 refinement.refinedFaceNeighbor.append(
false );
144 refinement.borderFaceNeighbor.append(
false );
146 int neighborFaceIndex = neighbors.at( positionInFace );
147 bool needCreateVertex =
true;
148 if ( neighborFaceIndex != -1 && facesToRefine.contains( neighborFaceIndex ) && canBeRefined( neighborFaceIndex ) )
150 int neighborFaceSize = mesh.
face( neighborFaceIndex ).size();
152 positionVertexInNeighbor = ( positionVertexInNeighbor + neighborFaceSize - 1 ) % neighborFaceSize;
153 refinement.refinedFaceNeighbor[positionInFace] =
true;
154 QHash<int, FaceRefinement>::iterator it = facesRefinement.find( neighborFaceIndex );
155 if ( it != facesRefinement.end() )
157 FaceRefinement &neighborRefinement = it.value();
158 int existingVertexLocalIndex = neighborRefinement.newVerticesLocalIndex.at( positionVertexInNeighbor );
159 refinement.newVerticesLocalIndex.append( existingVertexLocalIndex );
160 needCreateVertex =
false;
165 if ( needCreateVertex )
168 const QgsMeshVertex &vertex2 = mesh.
vertex( face.at( ( positionInFace + 1 ) % faceSize ) );
170 refinement.newVerticesLocalIndex.append(
mVerticesToAdd.count() );
174 ( vertex1.
y() + vertex2.
y() ) / 2,
175 ( vertex1.
z() + vertex2.
z() ) / 2 ) );
183 int faceStartIndex = startingGlobalFaceIndex +
mFacesToAdd.count();
187 for (
int i = 0; i < faceSize; ++i )
190 refinement.newVerticesLocalIndex.at( i ) + startingVertexIndex,
191 refinement.newVerticesLocalIndex.at( ( i + faceSize - 1 ) % faceSize ) + startingVertexIndex} );
192 refinement.newFacesChangesIndex.append(
mFacesToAdd.count() );
197 QgsMeshFace newFace( {refinement.newVerticesLocalIndex.at( 0 ) + startingVertexIndex,
198 refinement.newVerticesLocalIndex.at( 1 ) + startingVertexIndex,
199 refinement.newVerticesLocalIndex.at( ( 2 ) % faceSize ) + startingVertexIndex} );
200 refinement.newFacesChangesIndex.append(
mFacesToAdd.count() );
207 int centerVertexIndex =
mVerticesToAdd.count() + startingVertexIndex;
212 for (
int i = 0; i < faceSize; ++i )
215 refinement.newVerticesLocalIndex.at( i ) + startingVertexIndex,
217 refinement.newVerticesLocalIndex.at( ( i + faceSize - 1 ) % faceSize ) + startingVertexIndex} );
218 refinement.newFacesChangesIndex.append(
mFacesToAdd.count() );
226 refinement.newCenterVertexIndex = -1;
228 facesRefinement.insert( faceIndex, refinement );
231 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
233 if ( addedVerticesIndex.at( positionInFace ) != -1 )
236 refinement.newFacesChangesIndex.at( positionInFace ) + startingGlobalFaceIndex;
239 int vertexIndex = face.at( positionInFace );
241 mVerticesToFaceChanges.append( {vertexIndex, faceIndex, refinement.newFacesChangesIndex.at( positionInFace ) + startingGlobalFaceIndex} );
247 facesToRefine.remove( faceIndex );
252 for ( QHash<int, FaceRefinement>::iterator it = facesRefinement.begin(); it != facesRefinement.end(); ++it )
254 int faceIndex = it.key();
255 FaceRefinement &faceRefinement = it.value();
257 int faceSize = face.size();
261 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
263 if ( faceRefinement.refinedFaceNeighbor.at( positionInFace ) )
265 int neighborIndex = neighbors.at( positionInFace );
266 int firstVertexIndex = face.at( positionInFace );
267 int secondVertexIndex = faceRefinement.newVerticesLocalIndex.at( positionInFace ) + startingVertexIndex;
269 const FaceRefinement &otherRefinement = facesRefinement.value( neighborIndex );
271 int otherFaceSize = otherFace.size();
274 int newFace1ChangesIndex = faceRefinement.newFacesChangesIndex.at( ( positionInFace ) );
278 int newFace2ChangesIndex = faceRefinement.newFacesChangesIndex.at( ( positionInFace + 1 ) % faceSize );
282 int otherNewFace1ChangesIndex = otherRefinement.newFacesChangesIndex.at( ( otherPositionInface ) % otherFaceSize );
283 int otherNewFace2ChangesIndex = otherRefinement.newFacesChangesIndex.at( ( otherPositionInface + 1 ) % otherFaceSize );
285 mFacesNeighborhoodToAdd[newFace1ChangesIndex][positionInNewface1Index] = otherNewFace2ChangesIndex + startingGlobalFaceIndex;
286 mFacesNeighborhoodToAdd[newFace2ChangesIndex][positionInNewface2Index] = otherNewFace1ChangesIndex + startingGlobalFaceIndex;
292bool QgsMeshEditRefineFaces::createNewBorderFaces(
QgsMeshEditor *meshEditor,
293 const QSet<int> &facesToRefine,
294 QHash<int, FaceRefinement> &facesRefinement,
295 QHash<int, BorderFace> &borderFaces )
301 int startingFaceChangesGlobalIndex = mesh.
faceCount();
304 for (
int faceIndexToRefine : facesToRefine )
307 int faceToRefineSize = faceToRefine.size();
309 const QVector<int> &neighbors = topology.
neighborsOfFace( faceIndexToRefine );
311 QHash<int, FaceRefinement>::iterator itFace = facesRefinement.find( faceIndexToRefine );
313 if ( itFace == facesRefinement.end() )
316 FaceRefinement &refinement = itFace.value();
318 for (
int posInFaceToRefine = 0; posInFaceToRefine < faceToRefineSize; ++posInFaceToRefine )
320 int neighborFaceIndex = neighbors.at( posInFaceToRefine );
321 if ( neighborFaceIndex != -1 && !facesToRefine.contains( neighborFaceIndex ) )
324 int neighborFaceSize = neighborFace.size();
326 positionInNeighbor = ( positionInNeighbor + neighborFaceSize - 1 ) % neighborFaceSize;
328 QHash<int, BorderFace>::iterator it = borderFaces.find( neighborFaceIndex );
329 if ( it == borderFaces.end() )
331 BorderFace borderFace;
332 for (
int i = 0; i < neighborFaceSize; ++i )
334 borderFace.unchangeFacesNeighbor.append(
false );
335 borderFace.borderFacesNeighbor.append(
false );
336 if ( i == positionInNeighbor )
338 borderFace.refinedFacesNeighbor.append(
true );
339 borderFace.newVerticesLocalIndex.append( refinement.newVerticesLocalIndex.at( posInFaceToRefine ) );
343 borderFace.refinedFacesNeighbor.append(
false );
344 borderFace.newVerticesLocalIndex.append( -1 );
347 borderFaces.insert( neighborFaceIndex, borderFace );
351 BorderFace &borderFace = it.value();
352 for (
int i = 0; i < neighborFaceSize; ++i )
354 if ( i == positionInNeighbor )
356 borderFace.unchangeFacesNeighbor[i] =
false;
357 borderFace.borderFacesNeighbor[i] =
false;
358 borderFace.refinedFacesNeighbor[i] =
true;
359 borderFace.newVerticesLocalIndex[i] = refinement.newVerticesLocalIndex.at( posInFaceToRefine );
368 for ( QHash<int, BorderFace>::iterator it = borderFaces.begin(); it != borderFaces.end(); ++it )
370 int faceIndex = it.key();
371 BorderFace &borderFace = it.value();
374 int faceSize = face.size();
377 for (
int posInFace = 0; posInFace < faceSize; ++posInFace )
379 int neighborIndex = neighbors.at( posInFace );
381 if ( neighborIndex != -1 )
384 int neighborFaceSize = neighborFace.size();
386 posInNeighbor = ( posInNeighbor - 1 + neighborFaceSize ) % neighborFaceSize;
388 QHash<int, FaceRefinement>::iterator itRefinement = facesRefinement.find( neighborIndex );
389 if ( itRefinement != facesRefinement.end() )
391 FaceRefinement &neighborRefinement = itRefinement.value();
392 neighborRefinement.borderFaceNeighbor[posInNeighbor] =
true;
393 borderFace.refinedFacesNeighbor[posInFace] =
true;
397 QHash<int, BorderFace>::iterator itNeighborBorder = borderFaces.find( neighborIndex );
398 if ( itNeighborBorder == borderFaces.end() )
399 borderFace.unchangeFacesNeighbor[posInFace] =
true;
402 BorderFace &neighborBorderFace = itNeighborBorder.value();
403 neighborBorderFace.borderFacesNeighbor[posInNeighbor] =
true;
404 borderFace.borderFacesNeighbor[posInFace] =
true;
409 borderFace.unchangeFacesNeighbor[posInFace] =
true;
415 for ( QHash<int, BorderFace>::iterator it = borderFaces.begin(); it != borderFaces.end(); ++it )
417 int faceIndex = it.key();
418 BorderFace &borderFace = it.value();
421 int faceSize = face.size();
423 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
424 std::vector<p2t::Point *> points;
425 for (
int i = 0; i < faceSize; ++i )
428 points.push_back(
new p2t::Point( vert.
x(), vert.
y() ) );
429 mapPoly2TriPointToVertex.insert( points.back(), face.at( i ) );
430 if ( borderFace.refinedFacesNeighbor.at( i ) )
432 int localVertexIndex = borderFace.newVerticesLocalIndex.at( i );
434 points.push_back(
new p2t::Point( newVert.
x(), newVert.
y() ) );
435 mapPoly2TriPointToVertex.insert( points.back(), localVertexIndex + startingVertexIndex );
441 auto cdt = std::make_unique<p2t::CDT>( points );
443 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
444 QVector<QgsMeshFace> faces( triangles.size() );
445 for (
size_t i = 0; i < triangles.size(); ++i )
448 triangle.resize( 3 );
449 QVector<QgsMeshVertex> vertices( 3 );
450 for (
int j = 0; j < 3; j++ )
452 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
454 throw std::exception();;
455 triangle[j] = vertInd;
456 if ( vertInd >= startingVertexIndex )
459 vertices[j] = mesh.
vertex( vertInd );
466 QgsMeshEditingError error;
468 QVector<QgsTopologicalMesh::FaceNeighbors> neighborhood = topologicalFaces.
facesNeighborhood();
471 for (
int i = 0; i < neighborhood.count(); ++i )
474 for (
int j = 0; j < neighbors.count(); ++j )
476 if ( neighbors[j] != -1 )
477 neighbors[j] = neighbors[j] + startingFaceIndex;
484 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
486 if ( borderFace.refinedFacesNeighbor.at( positionInFace ) )
489 QVector<int> vertexIndexes( 2 );
490 QVector<int> localFaceIndex( 2 );
491 vertexIndexes[0] = face.at( positionInFace );
492 vertexIndexes[1] = borderFace.newVerticesLocalIndex.at( positionInFace ) + startingVertexIndex;
494 int refinedFaceIndex = neighborOfFace.at( positionInFace );
495 const FaceRefinement &faceRefinement = facesRefinement.value( refinedFaceIndex );
497 int refinedFaceSize = refinedFace.size();
500 for (
int i = 0; i < 2; ++i )
502 QgsMeshVertexCirculator circulator( topologicalFaces, vertexIndexes.at( i ) );
503 circulator.goBoundaryClockwise();
504 localFaceIndex[i] = circulator.currentFaceIndex();
508 const QgsMeshFace newFace = faces.at( localFaceIndex.at( i ) );
510 int newFaceRefinedIndexInChanges = faceRefinement.newFacesChangesIndex.at( ( positionInRefinedFace + ( 1 - i ) ) % refinedFaceSize ) ;
511 neighborsNewFace[positionInNewFace] = newFaceRefinedIndexInChanges + startingFaceChangesGlobalIndex;
515 int newRefinedFaceSize = newRefinedFace.size();
517 neighborsRefinedFace[positionInNewRefinedChange] = localFaceIndex.at( i ) + startingFaceIndex;
520 borderFace.edgeFace.append( localFaceIndex.at( 0 ) + startingFaceIndex );
523 if ( borderFace.borderFacesNeighbor.at( positionInFace ) )
525 int vertexIndex = face.at( positionInFace );
526 QgsMeshVertexCirculator circulator( topologicalFaces, vertexIndex );
527 circulator.goBoundaryClockwise();
528 int localFaceIndex = circulator.currentFaceIndex();
531 borderFace.edgeFace.append( localFaceIndex + startingFaceIndex );
534 if ( borderFace.unchangeFacesNeighbor.at( positionInFace ) )
536 int vertexIndex = face.at( positionInFace );
537 QgsMeshVertexCirculator circulator( topologicalFaces, vertexIndex );
538 circulator.goBoundaryClockwise();
539 int localFaceIndex = circulator.currentFaceIndex();
541 const QgsMeshFace &newFace = faces.at( localFaceIndex );
544 int unchangedFaceIndex = neighborOfFace.at( positionInFace );
545 neighborsNewFace[positionInNewface] = unchangedFaceIndex;
547 if ( unchangedFaceIndex != -1 )
550 int unchangedFaceSize = unchangedFace.size();
552 mNeighborhoodChanges.append( {unchangedFaceIndex, positionInUnchangedFace, faceIndex, localFaceIndex + startingFaceIndex} );
555 borderFace.edgeFace.append( localFaceIndex + startingFaceIndex );
562 for ( p2t::Point *pt : points )
573 for ( QHash<int, BorderFace>::iterator it = borderFaces.begin(); it != borderFaces.end(); ++it )
575 int faceIndex = it.key();
576 BorderFace &borderFace = it.value();
578 int faceSize = face.size();
582 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
584 if ( borderFace.borderFacesNeighbor.at( positionInFace ) )
586 int otherIndex = neighbors.at( positionInFace );
588 int otherFaceSize = otherFace.size();
590 const BorderFace &otherBorderFace = borderFaces.value( otherIndex );
591 int otherNewFaceIndex = otherBorderFace.edgeFace.at( otherPositionInface );
593 int newFaceChangesIndex = borderFace.edgeFace.at( positionInFace ) - startingFaceChangesGlobalIndex;
601 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
603 int vertexIndex = face.at( positionInFace );
615 return QObject::tr(
"Refine %n face(s)",
nullptr,
mInputFaces.count() );
627 QSet<int> concernedFaces;
628 mChangingVertexMap = QHash<int, int>();
635 QVector<QgsMeshVertex> newVertices;
641 bool calcX = !mExpressionX.isEmpty();
642 bool calcY = !mExpressionY.isEmpty();
643 bool calcZ = !mExpressionZ.isEmpty();
648 expressionX.
prepare( &context );
655 expressionY.
prepare( &context );
658 if ( calcX || calcY )
665 if ( calcZ || mZFromTerrain )
668 expressionZ.
prepare( &context );
676 if ( mZFromTerrain && project )
679 if ( terrainProvider )
691 mChangingVertexMap[vertexIndex] = i;
692 const QVariant xvar = expressionX.
evaluate( &context );
693 const QVariant yvar = expressionY.
evaluate( &context );
694 const QVariant zvar = expressionZ.
evaluate( &context );
698 if ( calcX || calcY )
704 concernedFaces.unite( qgis::listToSet( facesAround ) );
710 if ( xvar.isValid() )
712 double x = xvar.toDouble( &ok );
728 if ( yvar.isValid() )
730 double y = yvar.toDouble( &ok );
742 if ( calcZ && !mZFromTerrain )
744 double z = std::numeric_limits<double>::quiet_NaN();
745 if ( zvar.isValid() )
747 z = zvar.toDouble( &ok );
749 z = std::numeric_limits<double>::quiet_NaN();
756 if ( mZFromTerrain && terrainProvider )
759 bool vertexTransformed;
764 if ( calcX || calcY )
770 point = transformation.
transform( vert.
x(), vert.
y() );
772 vertexTransformed =
true;
776 vertexTransformed =
false;
780 elevation = vert.
z();
782 if ( vertexTransformed )
784 double terrainElevation = terrainProvider->
heightAt( point.
x(), point.
y() );
786 if ( ! std::isnan( terrainElevation ) )
788 elevation = terrainElevation;
797 auto transformFunction = [
this, layer ](
int vi )->
const QgsMeshVertex
808 return QObject::tr(
"Transform %n vertices by expression",
nullptr,
mInputVertices.count() );
813 mExpressionX = expressionX;
814 mExpressionY = expressionY;
815 mExpressionZ = expressionZ;
817 mChangingVertexMap.clear();
829 int pos = mChangingVertexMap.value( vertexIndex, -1 );
853 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.