71 QSet<int> facesToRefine = qgis::listToSet(
mInputFaces );
72 QHash<int, FaceRefinement> facesRefinement;
73 QHash<int, BorderFace> borderFaces;
75 createNewVerticesAndRefinedFaces( meshEditor, facesToRefine, facesRefinement );
76 if ( !createNewBorderFaces( meshEditor, facesToRefine, facesRefinement, borderFaces ) )
101void QgsMeshEditRefineFaces::createNewVerticesAndRefinedFaces(
QgsMeshEditor *meshEditor,
102 QSet<int> &facesToRefine,
103 QHash<int, FaceRefinement> &facesRefinement )
109 int startingGlobalFaceIndex = mesh.
faceCount();
111 auto canBeRefined = [ & ](
int fi )->
bool
115 int fs = mesh.
face( fi ).size();
116 return fs == 3 || fs == 4;
120 for (
const int faceIndex : std::as_const(
mInputFaces ) )
122 FaceRefinement refinement;
125 int faceSize = face.size();
127 QVector<int> addedVerticesIndex( faceSize, -1 );
129 if ( canBeRefined( faceIndex ) )
131 refinement.newVerticesLocalIndex.reserve( faceSize );
132 refinement.refinedFaceNeighbor.reserve( faceSize );
133 refinement.borderFaceNeighbor.reserve( faceSize );
136 double zValueSum = 0;
138 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
140 refinement.refinedFaceNeighbor.append(
false );
141 refinement.borderFaceNeighbor.append(
false );
143 int neighborFaceIndex = neighbors.at( positionInFace );
144 bool needCreateVertex =
true;
145 if ( neighborFaceIndex != -1 && facesToRefine.contains( neighborFaceIndex ) && canBeRefined( neighborFaceIndex ) )
147 int neighborFaceSize = mesh.
face( neighborFaceIndex ).size();
149 positionVertexInNeighbor = ( positionVertexInNeighbor + neighborFaceSize - 1 ) % neighborFaceSize;
150 refinement.refinedFaceNeighbor[positionInFace] =
true;
151 QHash<int, FaceRefinement>::iterator it = facesRefinement.find( neighborFaceIndex );
152 if ( it != facesRefinement.end() )
154 FaceRefinement &neighborRefinement = it.value();
155 int existingVertexLocalIndex = neighborRefinement.newVerticesLocalIndex.at( positionVertexInNeighbor );
156 refinement.newVerticesLocalIndex.append( existingVertexLocalIndex );
157 needCreateVertex =
false;
162 if ( needCreateVertex )
165 const QgsMeshVertex &vertex2 = mesh.
vertex( face.at( ( positionInFace + 1 ) % faceSize ) );
167 refinement.newVerticesLocalIndex.append(
mVerticesToAdd.count() );
171 ( vertex1.
y() + vertex2.
y() ) / 2,
172 ( vertex1.
z() + vertex2.
z() ) / 2 ) );
180 int faceStartIndex = startingGlobalFaceIndex +
mFacesToAdd.count();
184 for (
int i = 0; i < faceSize; ++i )
187 refinement.newVerticesLocalIndex.at( i ) + startingVertexIndex,
188 refinement.newVerticesLocalIndex.at( ( i + faceSize - 1 ) % faceSize ) + startingVertexIndex} );
189 refinement.newFacesChangesIndex.append(
mFacesToAdd.count() );
194 QgsMeshFace newFace( {refinement.newVerticesLocalIndex.at( 0 ) + startingVertexIndex,
195 refinement.newVerticesLocalIndex.at( 1 ) + startingVertexIndex,
196 refinement.newVerticesLocalIndex.at( ( 2 ) % faceSize ) + startingVertexIndex} );
197 refinement.newFacesChangesIndex.append(
mFacesToAdd.count() );
204 int centerVertexIndex =
mVerticesToAdd.count() + startingVertexIndex;
209 for (
int i = 0; i < faceSize; ++i )
212 refinement.newVerticesLocalIndex.at( i ) + startingVertexIndex,
214 refinement.newVerticesLocalIndex.at( ( i + faceSize - 1 ) % faceSize ) + startingVertexIndex} );
215 refinement.newFacesChangesIndex.append(
mFacesToAdd.count() );
223 refinement.newCenterVertexIndex = -1;
225 facesRefinement.insert( faceIndex, refinement );
228 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
230 if ( addedVerticesIndex.at( positionInFace ) != -1 )
233 refinement.newFacesChangesIndex.at( positionInFace ) + startingGlobalFaceIndex;
236 int vertexIndex = face.at( positionInFace );
238 mVerticesToFaceChanges.append( {vertexIndex, faceIndex, refinement.newFacesChangesIndex.at( positionInFace ) + startingGlobalFaceIndex} );
244 facesToRefine.remove( faceIndex );
249 for ( QHash<int, FaceRefinement>::iterator it = facesRefinement.begin(); it != facesRefinement.end(); ++it )
251 int faceIndex = it.key();
252 FaceRefinement &faceRefinement = it.value();
254 int faceSize = face.size();
258 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
260 if ( faceRefinement.refinedFaceNeighbor.at( positionInFace ) )
262 int neighborIndex = neighbors.at( positionInFace );
263 int firstVertexIndex = face.at( positionInFace );
264 int secondVertexIndex = faceRefinement.newVerticesLocalIndex.at( positionInFace ) + startingVertexIndex;
266 const FaceRefinement &otherRefinement = facesRefinement.value( neighborIndex );
268 int otherFaceSize = otherFace.size();
271 int newFace1ChangesIndex = faceRefinement.newFacesChangesIndex.at( ( positionInFace ) );
272 const QgsMeshFace &newFace1 = mFacesToAdd.at( newFace1ChangesIndex );
275 int newFace2ChangesIndex = faceRefinement.newFacesChangesIndex.at( ( positionInFace + 1 ) % faceSize );
276 const QgsMeshFace &newFace2 = mFacesToAdd.at( newFace2ChangesIndex );
279 int otherNewFace1ChangesIndex = otherRefinement.newFacesChangesIndex.at( ( otherPositionInface ) % otherFaceSize );
280 int otherNewFace2ChangesIndex = otherRefinement.newFacesChangesIndex.at( ( otherPositionInface + 1 ) % otherFaceSize );
282 mFacesNeighborhoodToAdd[newFace1ChangesIndex][positionInNewface1Index] = otherNewFace2ChangesIndex + startingGlobalFaceIndex;
283 mFacesNeighborhoodToAdd[newFace2ChangesIndex][positionInNewface2Index] = otherNewFace1ChangesIndex + startingGlobalFaceIndex;
289bool QgsMeshEditRefineFaces::createNewBorderFaces(
QgsMeshEditor *meshEditor,
290 const QSet<int> &facesToRefine,
291 QHash<int, FaceRefinement> &facesRefinement,
292 QHash<int, BorderFace> &borderFaces )
298 int startingFaceChangesGlobalIndex = mesh.
faceCount();
301 for (
int faceIndexToRefine : facesToRefine )
304 int faceToRefineSize = faceToRefine.size();
306 const QVector<int> &neighbors = topology.
neighborsOfFace( faceIndexToRefine );
308 QHash<int, FaceRefinement>::iterator itFace = facesRefinement.find( faceIndexToRefine );
310 if ( itFace == facesRefinement.end() )
313 FaceRefinement &refinement = itFace.value();
315 for (
int posInFaceToRefine = 0; posInFaceToRefine < faceToRefineSize; ++posInFaceToRefine )
317 int neighborFaceIndex = neighbors.at( posInFaceToRefine );
318 if ( neighborFaceIndex != -1 && !facesToRefine.contains( neighborFaceIndex ) )
321 int neighborFaceSize = neighborFace.size();
323 positionInNeighbor = ( positionInNeighbor + neighborFaceSize - 1 ) % neighborFaceSize;
325 QHash<int, BorderFace>::iterator it = borderFaces.find( neighborFaceIndex );
326 if ( it == borderFaces.end() )
328 BorderFace borderFace;
329 for (
int i = 0; i < neighborFaceSize; ++i )
331 borderFace.unchangeFacesNeighbor.append(
false );
332 borderFace.borderFacesNeighbor.append(
false );
333 if ( i == positionInNeighbor )
335 borderFace.refinedFacesNeighbor.append(
true );
336 borderFace.newVerticesLocalIndex.append( refinement.newVerticesLocalIndex.at( posInFaceToRefine ) );
340 borderFace.refinedFacesNeighbor.append(
false );
341 borderFace.newVerticesLocalIndex.append( -1 );
344 borderFaces.insert( neighborFaceIndex, borderFace );
348 BorderFace &borderFace = it.value();
349 for (
int i = 0; i < neighborFaceSize; ++i )
351 if ( i == positionInNeighbor )
353 borderFace.unchangeFacesNeighbor[i] =
false;
354 borderFace.borderFacesNeighbor[i] =
false;
355 borderFace.refinedFacesNeighbor[i] =
true;
356 borderFace.newVerticesLocalIndex[i] = refinement.newVerticesLocalIndex.at( posInFaceToRefine );
365 for ( QHash<int, BorderFace>::iterator it = borderFaces.begin(); it != borderFaces.end(); ++it )
367 int faceIndex = it.key();
368 BorderFace &borderFace = it.value();
371 int faceSize = face.size();
374 for (
int posInFace = 0; posInFace < faceSize; ++posInFace )
376 int neighborIndex = neighbors.at( posInFace );
378 if ( neighborIndex != -1 )
381 int neighborFaceSize = neighborFace.size();
383 posInNeighbor = ( posInNeighbor - 1 + neighborFaceSize ) % neighborFaceSize;
385 QHash<int, FaceRefinement>::iterator itRefinement = facesRefinement.find( neighborIndex );
386 if ( itRefinement != facesRefinement.end() )
388 FaceRefinement &neighborRefinement = itRefinement.value();
389 neighborRefinement.borderFaceNeighbor[posInNeighbor] =
true;
390 borderFace.refinedFacesNeighbor[posInFace] =
true;
394 QHash<int, BorderFace>::iterator itNeighborBorder = borderFaces.find( neighborIndex );
395 if ( itNeighborBorder == borderFaces.end() )
396 borderFace.unchangeFacesNeighbor[posInFace] =
true;
399 BorderFace &neighborBorderFace = itNeighborBorder.value();
400 neighborBorderFace.borderFacesNeighbor[posInNeighbor] =
true;
401 borderFace.borderFacesNeighbor[posInFace] =
true;
406 borderFace.unchangeFacesNeighbor[posInFace] =
true;
412 for ( QHash<int, BorderFace>::iterator it = borderFaces.begin(); it != borderFaces.end(); ++it )
414 int faceIndex = it.key();
415 BorderFace &borderFace = it.value();
418 int faceSize = face.size();
420 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
421 std::vector<p2t::Point *> points;
422 for (
int i = 0; i < faceSize; ++i )
425 points.push_back(
new p2t::Point( vert.
x(), vert.
y() ) );
426 mapPoly2TriPointToVertex.insert( points.back(), face.at( i ) );
427 if ( borderFace.refinedFacesNeighbor.at( i ) )
429 int localVertexIndex = borderFace.newVerticesLocalIndex.at( i );
431 points.push_back(
new p2t::Point( newVert.
x(), newVert.
y() ) );
432 mapPoly2TriPointToVertex.insert( points.back(), localVertexIndex + startingVertexIndex );
438 auto cdt = std::make_unique<p2t::CDT>( points );
440 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
441 QVector<QgsMeshFace> faces( triangles.size() );
442 for (
size_t i = 0; i < triangles.size(); ++i )
445 triangle.resize( 3 );
446 QVector<QgsMeshVertex> vertices( 3 );
447 for (
int j = 0; j < 3; j++ )
449 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
451 throw std::exception();;
452 triangle[j] = vertInd;
453 if ( vertInd >= startingVertexIndex )
456 vertices[j] = mesh.
vertex( vertInd );
465 QVector<QgsTopologicalMesh::FaceNeighbors> neighborhood = topologicalFaces.
facesNeighborhood();
468 for (
int i = 0; i < neighborhood.count(); ++i )
471 for (
int j = 0; j < neighbors.count(); ++j )
473 if ( neighbors[j] != -1 )
474 neighbors[j] = neighbors[j] + startingFaceIndex;
481 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
483 if ( borderFace.refinedFacesNeighbor.at( positionInFace ) )
486 QVector<int> vertexIndexes( 2 );
487 QVector<int> localFaceIndex( 2 );
488 vertexIndexes[0] = face.at( positionInFace );
489 vertexIndexes[1] = borderFace.newVerticesLocalIndex.at( positionInFace ) + startingVertexIndex;
491 int refinedFaceIndex = neighborOfFace.at( positionInFace );
492 const FaceRefinement &faceRefinement = facesRefinement.value( refinedFaceIndex );
494 int refinedFaceSize = refinedFace.size();
497 for (
int i = 0; i < 2; ++i )
500 circulator.goBoundaryClockwise();
501 localFaceIndex[i] = circulator.currentFaceIndex();
505 const QgsMeshFace newFace = faces.at( localFaceIndex.at( i ) );
507 int newFaceRefinedIndexInChanges = faceRefinement.newFacesChangesIndex.at( ( positionInRefinedFace + ( 1 - i ) ) % refinedFaceSize ) ;
508 neighborsNewFace[positionInNewFace] = newFaceRefinedIndexInChanges + startingFaceChangesGlobalIndex;
512 int newRefinedFaceSize = newRefinedFace.size();
514 neighborsRefinedFace[positionInNewRefinedChange] = localFaceIndex.at( i ) + startingFaceIndex;
517 borderFace.edgeFace.append( localFaceIndex.at( 0 ) + startingFaceIndex );
520 if ( borderFace.borderFacesNeighbor.at( positionInFace ) )
522 int vertexIndex = face.at( positionInFace );
524 circulator.goBoundaryClockwise();
525 int localFaceIndex = circulator.currentFaceIndex();
528 borderFace.edgeFace.append( localFaceIndex + startingFaceIndex );
531 if ( borderFace.unchangeFacesNeighbor.at( positionInFace ) )
533 int vertexIndex = face.at( positionInFace );
535 circulator.goBoundaryClockwise();
536 int localFaceIndex = circulator.currentFaceIndex();
538 const QgsMeshFace &newFace = faces.at( localFaceIndex );
541 int unchangedFaceIndex = neighborOfFace.at( positionInFace );
542 neighborsNewFace[positionInNewface] = unchangedFaceIndex;
544 if ( unchangedFaceIndex != -1 )
547 int unchangedFaceSize = unchangedFace.size();
549 mNeighborhoodChanges.append( {unchangedFaceIndex, positionInUnchangedFace, faceIndex, localFaceIndex + startingFaceIndex} );
552 borderFace.edgeFace.append( localFaceIndex + startingFaceIndex );
559 for ( p2t::Point *pt : points )
570 for ( QHash<int, BorderFace>::iterator it = borderFaces.begin(); it != borderFaces.end(); ++it )
572 int faceIndex = it.key();
573 BorderFace &borderFace = it.value();
575 int faceSize = face.size();
579 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
581 if ( borderFace.borderFacesNeighbor.at( positionInFace ) )
583 int otherIndex = neighbors.at( positionInFace );
585 int otherFaceSize = otherFace.size();
587 const BorderFace &otherBorderFace = borderFaces.value( otherIndex );
588 int otherNewFaceIndex = otherBorderFace.edgeFace.at( otherPositionInface );
590 int newFaceChangesIndex = borderFace.edgeFace.at( positionInFace ) - startingFaceChangesGlobalIndex;
598 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
600 int vertexIndex = face.at( positionInFace );
612 return QObject::tr(
"Refine %n face(s)",
nullptr,
mInputFaces.count() );
624 QSet<int> concernedFaces;
625 mChangingVertexMap = QHash<int, int>();
630 context.
lastScope()->
setVariable( QStringLiteral(
"_native_mesh" ), QVariant::fromValue( mesh ) );
632 QVector<QgsMeshVertex> newVertices;
638 bool calcX = !mExpressionX.isEmpty();
639 bool calcY = !mExpressionY.isEmpty();
640 bool calcZ = !mExpressionZ.isEmpty();
645 expressionX.
prepare( &context );
652 expressionY.
prepare( &context );
655 if ( calcX || calcY )
662 if ( calcZ || mZFromTerrain )
665 expressionZ.
prepare( &context );
673 if ( mZFromTerrain && project )
676 if ( terrainProvider )
688 mChangingVertexMap[vertexIndex] = i;
689 const QVariant xvar = expressionX.
evaluate( &context );
690 const QVariant yvar = expressionY.
evaluate( &context );
691 const QVariant zvar = expressionZ.
evaluate( &context );
695 if ( calcX || calcY )
701 concernedFaces.unite( qgis::listToSet( facesAround ) );
707 if ( xvar.isValid() )
709 double x = xvar.toDouble( &ok );
725 if ( yvar.isValid() )
727 double y = yvar.toDouble( &ok );
739 if ( calcZ && !mZFromTerrain )
741 double z = std::numeric_limits<double>::quiet_NaN();
742 if ( zvar.isValid() )
744 z = zvar.toDouble( &ok );
746 z = std::numeric_limits<double>::quiet_NaN();
753 if ( mZFromTerrain && terrainProvider )
756 bool vertexTransformed;
761 if ( calcX || calcY )
767 point = transformation.
transform( vert.
x(), vert.
y() );
769 vertexTransformed =
true;
773 vertexTransformed =
false;
777 elevation = vert.
z();
779 if ( vertexTransformed )
781 double terrainElevation = terrainProvider->
heightAt( point.
x(), point.
y() );
783 if ( ! std::isnan( terrainElevation ) )
785 elevation = terrainElevation;
794 auto transformFunction = [
this, layer ](
int vi )->
const QgsMeshVertex
805 return QObject::tr(
"Transform %n vertices by expression",
nullptr,
mInputVertices.count() );
810 mExpressionX = expressionX;
811 mExpressionY = expressionY;
812 mExpressionZ = expressionZ;
814 mChangingVertexMap.clear();
826 int pos = mChangingVertexMap.value( vertexIndex, -1 );
850 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 ...
Represents an error which occurred during mesh editing.
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.
Convenience class that turns around a vertex and provides information about faces and vertices.
Point geometry type, with support for z-dimension and m-values.
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
QList< double > mNewZValues
QVector< QgsMeshVertex > mVerticesToAdd
int mAddedFacesFirstIndex
QVector< int > mVertexToFaceToAdd
QList< int > mFaceIndexesToRemove
QVector< QgsMeshFace > mFacesToRemove
QList< double > mOldZValues
Contains independent faces and topological information about these faces.
QVector< FaceNeighbors > facesNeighborhood() const
Returns the face neighborhood of the faces, indexing is local.
Wraps a QgsMesh to ensure the consistency of the mesh during editing and helps to access elements fro...
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.