70 QSet<int> facesToRefine = qgis::listToSet(
mInputFaces );
71 QHash<int, FaceRefinement> facesRefinement;
72 QHash<int, BorderFace> borderFaces;
74 createNewVerticesAndRefinedFaces( meshEditor, facesToRefine, facesRefinement );
75 if ( !createNewBorderFaces( meshEditor, facesToRefine, facesRefinement, borderFaces ) )
100void QgsMeshEditRefineFaces::createNewVerticesAndRefinedFaces(
QgsMeshEditor *meshEditor,
101 QSet<int> &facesToRefine,
102 QHash<int, FaceRefinement> &facesRefinement )
108 int startingGlobalFaceIndex = mesh.
faceCount();
110 auto canBeRefined = [ & ](
int fi )->
bool
114 int fs = mesh.
face( fi ).size();
115 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() );
170 ( vertex1.
y() + vertex2.
y() ) / 2,
171 ( vertex1.
z() + vertex2.
z() ) / 2 ) );
179 int faceStartIndex = startingGlobalFaceIndex +
mFacesToAdd.count();
183 for (
int i = 0; i < faceSize; ++i )
186 refinement.newVerticesLocalIndex.at( i ) + startingVertexIndex,
187 refinement.newVerticesLocalIndex.at( ( i + faceSize - 1 ) % faceSize ) + startingVertexIndex} );
188 refinement.newFacesChangesIndex.append(
mFacesToAdd.count() );
193 QgsMeshFace newFace( {refinement.newVerticesLocalIndex.at( 0 ) + startingVertexIndex,
194 refinement.newVerticesLocalIndex.at( 1 ) + startingVertexIndex,
195 refinement.newVerticesLocalIndex.at( ( 2 ) % faceSize ) + startingVertexIndex} );
196 refinement.newFacesChangesIndex.append(
mFacesToAdd.count() );
203 int centerVertexIndex =
mVerticesToAdd.count() + startingVertexIndex;
208 for (
int i = 0; i < faceSize; ++i )
211 refinement.newVerticesLocalIndex.at( i ) + startingVertexIndex,
213 refinement.newVerticesLocalIndex.at( ( i + faceSize - 1 ) % faceSize ) + startingVertexIndex} );
214 refinement.newFacesChangesIndex.append(
mFacesToAdd.count() );
222 refinement.newCenterVertexIndex = -1;
224 facesRefinement.insert( faceIndex, refinement );
227 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
229 if ( addedVerticesIndex.at( positionInFace ) != -1 )
232 refinement.newFacesChangesIndex.at( positionInFace ) + startingGlobalFaceIndex;
235 int vertexIndex = face.at( positionInFace );
237 mVerticesToFaceChanges.append( {vertexIndex, faceIndex, refinement.newFacesChangesIndex.at( positionInFace ) + startingGlobalFaceIndex} );
243 facesToRefine.remove( faceIndex );
248 for ( QHash<int, FaceRefinement>::iterator it = facesRefinement.begin(); it != facesRefinement.end(); ++it )
250 int faceIndex = it.key();
251 FaceRefinement &faceRefinement = it.value();
253 int faceSize = face.size();
257 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
259 if ( faceRefinement.refinedFaceNeighbor.at( positionInFace ) )
261 int neighborIndex = neighbors.at( positionInFace );
262 int firstVertexIndex = face.at( positionInFace );
263 int secondVertexIndex = faceRefinement.newVerticesLocalIndex.at( positionInFace ) + startingVertexIndex;
265 const FaceRefinement &otherRefinement = facesRefinement.value( neighborIndex );
267 int otherFaceSize = otherFace.size();
270 int newFace1ChangesIndex = faceRefinement.newFacesChangesIndex.at( ( positionInFace ) );
274 int newFace2ChangesIndex = faceRefinement.newFacesChangesIndex.at( ( positionInFace + 1 ) % faceSize );
278 int otherNewFace1ChangesIndex = otherRefinement.newFacesChangesIndex.at( ( otherPositionInface ) % otherFaceSize );
279 int otherNewFace2ChangesIndex = otherRefinement.newFacesChangesIndex.at( ( otherPositionInface + 1 ) % otherFaceSize );
281 mFacesNeighborhoodToAdd[newFace1ChangesIndex][positionInNewface1Index] = otherNewFace2ChangesIndex + startingGlobalFaceIndex;
282 mFacesNeighborhoodToAdd[newFace2ChangesIndex][positionInNewface2Index] = otherNewFace1ChangesIndex + startingGlobalFaceIndex;
288bool QgsMeshEditRefineFaces::createNewBorderFaces(
QgsMeshEditor *meshEditor,
289 const QSet<int> &facesToRefine,
290 QHash<int, FaceRefinement> &facesRefinement,
291 QHash<int, BorderFace> &borderFaces )
297 int startingFaceChangesGlobalIndex = mesh.
faceCount();
300 for (
int faceIndexToRefine : facesToRefine )
303 int faceToRefineSize = faceToRefine.size();
305 const QVector<int> &neighbors = topology.
neighborsOfFace( faceIndexToRefine );
307 QHash<int, FaceRefinement>::iterator itFace = facesRefinement.find( faceIndexToRefine );
309 if ( itFace == facesRefinement.end() )
312 FaceRefinement &refinement = itFace.value();
314 for (
int posInFaceToRefine = 0; posInFaceToRefine < faceToRefineSize; ++posInFaceToRefine )
316 int neighborFaceIndex = neighbors.at( posInFaceToRefine );
317 if ( neighborFaceIndex != -1 && !facesToRefine.contains( neighborFaceIndex ) )
320 int neighborFaceSize = neighborFace.size();
322 positionInNeighbor = ( positionInNeighbor + neighborFaceSize - 1 ) % neighborFaceSize;
324 QHash<int, BorderFace>::iterator it = borderFaces.find( neighborFaceIndex );
325 if ( it == borderFaces.end() )
327 BorderFace borderFace;
328 for (
int i = 0; i < neighborFaceSize; ++i )
330 borderFace.unchangeFacesNeighbor.append(
false );
331 borderFace.borderFacesNeighbor.append(
false );
332 if ( i == positionInNeighbor )
334 borderFace.refinedFacesNeighbor.append(
true );
335 borderFace.newVerticesLocalIndex.append( refinement.newVerticesLocalIndex.at( posInFaceToRefine ) );
339 borderFace.refinedFacesNeighbor.append(
false );
340 borderFace.newVerticesLocalIndex.append( -1 );
343 borderFaces.insert( neighborFaceIndex, borderFace );
347 BorderFace &borderFace = it.value();
348 for (
int i = 0; i < neighborFaceSize; ++i )
350 if ( i == positionInNeighbor )
352 borderFace.unchangeFacesNeighbor[i] =
false;
353 borderFace.borderFacesNeighbor[i] =
false;
354 borderFace.refinedFacesNeighbor[i] =
true;
355 borderFace.newVerticesLocalIndex[i] = refinement.newVerticesLocalIndex.at( posInFaceToRefine );
364 for ( QHash<int, BorderFace>::iterator it = borderFaces.begin(); it != borderFaces.end(); ++it )
366 int faceIndex = it.key();
367 BorderFace &borderFace = it.value();
370 int faceSize = face.size();
373 for (
int posInFace = 0; posInFace < faceSize; ++posInFace )
375 int neighborIndex = neighbors.at( posInFace );
377 if ( neighborIndex != -1 )
380 int neighborFaceSize = neighborFace.size();
382 posInNeighbor = ( posInNeighbor - 1 + neighborFaceSize ) % neighborFaceSize;
384 QHash<int, FaceRefinement>::iterator itRefinement = facesRefinement.find( neighborIndex );
385 if ( itRefinement != facesRefinement.end() )
387 FaceRefinement &neighborRefinement = itRefinement.value();
388 neighborRefinement.borderFaceNeighbor[posInNeighbor] =
true;
389 borderFace.refinedFacesNeighbor[posInFace] =
true;
393 QHash<int, BorderFace>::iterator itNeighborBorder = borderFaces.find( neighborIndex );
394 if ( itNeighborBorder == borderFaces.end() )
395 borderFace.unchangeFacesNeighbor[posInFace] =
true;
398 BorderFace &neighborBorderFace = itNeighborBorder.value();
399 neighborBorderFace.borderFacesNeighbor[posInNeighbor] =
true;
400 borderFace.borderFacesNeighbor[posInFace] =
true;
405 borderFace.unchangeFacesNeighbor[posInFace] =
true;
411 for ( QHash<int, BorderFace>::iterator it = borderFaces.begin(); it != borderFaces.end(); ++it )
413 int faceIndex = it.key();
414 BorderFace &borderFace = it.value();
417 int faceSize = face.size();
419 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
420 std::vector<p2t::Point *> points;
421 for (
int i = 0; i < faceSize; ++i )
424 points.push_back(
new p2t::Point( vert.
x(), vert.
y() ) );
425 mapPoly2TriPointToVertex.insert( points.back(), face.at( i ) );
426 if ( borderFace.refinedFacesNeighbor.at( i ) )
428 int localVertexIndex = borderFace.newVerticesLocalIndex.at( i );
430 points.push_back(
new p2t::Point( newVert.
x(), newVert.
y() ) );
431 mapPoly2TriPointToVertex.insert( points.back(), localVertexIndex + startingVertexIndex );
437 auto cdt = std::make_unique<p2t::CDT>( points );
439 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
440 QVector<QgsMeshFace> faces( triangles.size() );
441 for (
size_t i = 0; i < triangles.size(); ++i )
444 triangle.resize( 3 );
445 QVector<QgsMeshVertex> vertices( 3 );
446 for (
int j = 0; j < 3; j++ )
448 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
450 throw std::exception();;
451 triangle[j] = vertInd;
452 if ( vertInd >= startingVertexIndex )
455 vertices[j] = mesh.
vertex( vertInd );
462 QgsMeshEditingError error;
464 QVector<QgsTopologicalMesh::FaceNeighbors> neighborhood = topologicalFaces.
facesNeighborhood();
467 for (
int i = 0; i < neighborhood.count(); ++i )
470 for (
int j = 0; j < neighbors.count(); ++j )
472 if ( neighbors[j] != -1 )
473 neighbors[j] = neighbors[j] + startingFaceIndex;
480 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
482 if ( borderFace.refinedFacesNeighbor.at( positionInFace ) )
485 QVector<int> vertexIndexes( 2 );
486 QVector<int> localFaceIndex( 2 );
487 vertexIndexes[0] = face.at( positionInFace );
488 vertexIndexes[1] = borderFace.newVerticesLocalIndex.at( positionInFace ) + startingVertexIndex;
490 int refinedFaceIndex = neighborOfFace.at( positionInFace );
491 const FaceRefinement &faceRefinement = facesRefinement.value( refinedFaceIndex );
493 int refinedFaceSize = refinedFace.size();
496 for (
int i = 0; i < 2; ++i )
498 QgsMeshVertexCirculator circulator( topologicalFaces, vertexIndexes.at( i ) );
499 circulator.goBoundaryClockwise();
500 localFaceIndex[i] = circulator.currentFaceIndex();
504 const QgsMeshFace newFace = faces.at( localFaceIndex.at( i ) );
506 int newFaceRefinedIndexInChanges = faceRefinement.newFacesChangesIndex.at( ( positionInRefinedFace + ( 1 - i ) ) % refinedFaceSize ) ;
507 neighborsNewFace[positionInNewFace] = newFaceRefinedIndexInChanges + startingFaceChangesGlobalIndex;
511 int newRefinedFaceSize = newRefinedFace.size();
513 neighborsRefinedFace[positionInNewRefinedChange] = localFaceIndex.at( i ) + startingFaceIndex;
516 borderFace.edgeFace.append( localFaceIndex.at( 0 ) + startingFaceIndex );
519 if ( borderFace.borderFacesNeighbor.at( positionInFace ) )
521 int vertexIndex = face.at( positionInFace );
522 QgsMeshVertexCirculator circulator( topologicalFaces, vertexIndex );
523 circulator.goBoundaryClockwise();
524 int localFaceIndex = circulator.currentFaceIndex();
527 borderFace.edgeFace.append( localFaceIndex + startingFaceIndex );
530 if ( borderFace.unchangeFacesNeighbor.at( positionInFace ) )
532 int vertexIndex = face.at( positionInFace );
533 QgsMeshVertexCirculator circulator( topologicalFaces, vertexIndex );
534 circulator.goBoundaryClockwise();
535 int localFaceIndex = circulator.currentFaceIndex();
537 const QgsMeshFace &newFace = faces.at( localFaceIndex );
540 int unchangedFaceIndex = neighborOfFace.at( positionInFace );
541 neighborsNewFace[positionInNewface] = unchangedFaceIndex;
543 if ( unchangedFaceIndex != -1 )
546 int unchangedFaceSize = unchangedFace.size();
548 mNeighborhoodChanges.append( {unchangedFaceIndex, positionInUnchangedFace, faceIndex, localFaceIndex + startingFaceIndex} );
551 borderFace.edgeFace.append( localFaceIndex + startingFaceIndex );
558 for ( p2t::Point *pt : points )
569 for ( QHash<int, BorderFace>::iterator it = borderFaces.begin(); it != borderFaces.end(); ++it )
571 int faceIndex = it.key();
572 BorderFace &borderFace = it.value();
574 int faceSize = face.size();
578 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
580 if ( borderFace.borderFacesNeighbor.at( positionInFace ) )
582 int otherIndex = neighbors.at( positionInFace );
584 int otherFaceSize = otherFace.size();
586 const BorderFace &otherBorderFace = borderFaces.value( otherIndex );
587 int otherNewFaceIndex = otherBorderFace.edgeFace.at( otherPositionInface );
589 int newFaceChangesIndex = borderFace.edgeFace.at( positionInFace ) - startingFaceChangesGlobalIndex;
597 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
599 int vertexIndex = face.at( positionInFace );
611 return QObject::tr(
"Refine %n face(s)",
nullptr,
mInputFaces.count() );
623 QSet<int> concernedFaces;
624 mChangingVertexMap = QHash<int, int>();
629 context.
lastScope()->
setVariable( QStringLiteral(
"_native_mesh" ), QVariant::fromValue( mesh ) );
631 QVector<QgsMeshVertex> newVertices;
637 bool calcX = !mExpressionX.isEmpty();
638 bool calcY = !mExpressionY.isEmpty();
639 bool calcZ = !mExpressionZ.isEmpty();
644 expressionX.
prepare( &context );
651 expressionY.
prepare( &context );
654 if ( calcX || calcY )
661 if ( calcZ || mZFromTerrain )
664 expressionZ.
prepare( &context );
672 if ( mZFromTerrain && project )
675 if ( terrainProvider )
687 mChangingVertexMap[vertexIndex] = i;
688 const QVariant xvar = expressionX.
evaluate( &context );
689 const QVariant yvar = expressionY.
evaluate( &context );
690 const QVariant zvar = expressionZ.
evaluate( &context );
694 if ( calcX || calcY )
700 concernedFaces.unite( qgis::listToSet( facesAround ) );
706 if ( xvar.isValid() )
708 double x = xvar.toDouble( &ok );
724 if ( yvar.isValid() )
726 double y = yvar.toDouble( &ok );
738 if ( calcZ && !mZFromTerrain )
740 double z = std::numeric_limits<double>::quiet_NaN();
741 if ( zvar.isValid() )
743 z = zvar.toDouble( &ok );
745 z = std::numeric_limits<double>::quiet_NaN();
752 if ( mZFromTerrain && terrainProvider )
755 bool vertexTransformed;
760 if ( calcX || calcY )
766 point = transformation.
transform( vert.
x(), vert.
y() );
768 vertexTransformed =
true;
772 vertexTransformed =
false;
776 elevation = vert.
z();
778 if ( vertexTransformed )
780 double terrainElevation = terrainProvider->
heightAt( point.
x(), point.
y() );
782 if ( ! std::isnan( terrainElevation ) )
784 elevation = terrainElevation;
793 auto transformFunction = [
this, layer ](
int vi )->
const QgsMeshVertex
804 return QObject::tr(
"Transform %n vertices by expression",
nullptr,
mInputVertices.count() );
809 mExpressionX = expressionX;
810 mExpressionY = expressionY;
811 mExpressionZ = expressionZ;
813 mChangingVertexMap.clear();
825 int pos = mChangingVertexMap.value( vertexIndex, -1 );
849 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.