69 QSet<int> facesToRefine = qgis::listToSet(
mInputFaces );
70 QHash<int, FaceRefinement> facesRefinement;
71 QHash<int, BorderFace> borderFaces;
73 createNewVerticesAndRefinedFaces( meshEditor, facesToRefine, facesRefinement );
74 if ( !createNewBorderFaces( meshEditor, facesToRefine, facesRefinement, borderFaces ) )
99void QgsMeshEditRefineFaces::createNewVerticesAndRefinedFaces(
QgsMeshEditor *meshEditor,
100 QSet<int> &facesToRefine,
101 QHash<int, FaceRefinement> &facesRefinement )
107 int startingGlobalFaceIndex = mesh.
faceCount();
109 auto canBeRefined = [ & ](
int fi )->
bool
113 int fs = mesh.
face( fi ).size();
114 return fs == 3 || fs == 4;
118 for (
const int faceIndex : std::as_const(
mInputFaces ) )
120 FaceRefinement refinement;
123 int faceSize = face.size();
125 QVector<int> addedVerticesIndex( faceSize, -1 );
127 if ( canBeRefined( faceIndex ) )
129 refinement.newVerticesLocalIndex.reserve( faceSize );
130 refinement.refinedFaceNeighbor.reserve( faceSize );
131 refinement.borderFaceNeighbor.reserve( faceSize );
134 double zValueSum = 0;
136 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
138 refinement.refinedFaceNeighbor.append(
false );
139 refinement.borderFaceNeighbor.append(
false );
141 int neighborFaceIndex = neighbors.at( positionInFace );
142 bool needCreateVertex =
true;
143 if ( neighborFaceIndex != -1 && facesToRefine.contains( neighborFaceIndex ) && canBeRefined( neighborFaceIndex ) )
145 int neighborFaceSize = mesh.
face( neighborFaceIndex ).size();
147 positionVertexInNeighbor = ( positionVertexInNeighbor + neighborFaceSize - 1 ) % neighborFaceSize;
148 refinement.refinedFaceNeighbor[positionInFace] =
true;
149 QHash<int, FaceRefinement>::iterator it = facesRefinement.find( neighborFaceIndex );
150 if ( it != facesRefinement.end() )
152 FaceRefinement &neighborRefinement = it.value();
153 int existingVertexLocalIndex = neighborRefinement.newVerticesLocalIndex.at( positionVertexInNeighbor );
154 refinement.newVerticesLocalIndex.append( existingVertexLocalIndex );
155 needCreateVertex =
false;
160 if ( needCreateVertex )
163 const QgsMeshVertex &vertex2 = mesh.
vertex( face.at( ( positionInFace + 1 ) % faceSize ) );
165 refinement.newVerticesLocalIndex.append(
mVerticesToAdd.count() );
169 ( vertex1.
y() + vertex2.
y() ) / 2,
170 ( vertex1.
z() + vertex2.
z() ) / 2 ) );
178 int faceStartIndex = startingGlobalFaceIndex +
mFacesToAdd.count();
182 for (
int i = 0; i < faceSize; ++i )
185 refinement.newVerticesLocalIndex.at( i ) + startingVertexIndex,
186 refinement.newVerticesLocalIndex.at( ( i + faceSize - 1 ) % faceSize ) + startingVertexIndex} );
187 refinement.newFacesChangesIndex.append(
mFacesToAdd.count() );
192 QgsMeshFace newFace( {refinement.newVerticesLocalIndex.at( 0 ) + startingVertexIndex,
193 refinement.newVerticesLocalIndex.at( 1 ) + startingVertexIndex,
194 refinement.newVerticesLocalIndex.at( ( 2 ) % faceSize ) + startingVertexIndex} );
195 refinement.newFacesChangesIndex.append(
mFacesToAdd.count() );
202 int centerVertexIndex =
mVerticesToAdd.count() + startingVertexIndex;
207 for (
int i = 0; i < faceSize; ++i )
210 refinement.newVerticesLocalIndex.at( i ) + startingVertexIndex,
212 refinement.newVerticesLocalIndex.at( ( i + faceSize - 1 ) % faceSize ) + startingVertexIndex} );
213 refinement.newFacesChangesIndex.append(
mFacesToAdd.count() );
221 refinement.newCenterVertexIndex = -1;
223 facesRefinement.insert( faceIndex, refinement );
226 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
228 if ( addedVerticesIndex.at( positionInFace ) != -1 )
231 refinement.newFacesChangesIndex.at( positionInFace ) + startingGlobalFaceIndex;
234 int vertexIndex = face.at( positionInFace );
236 mVerticesToFaceChanges.append( {vertexIndex, faceIndex, refinement.newFacesChangesIndex.at( positionInFace ) + startingGlobalFaceIndex} );
242 facesToRefine.remove( faceIndex );
247 for ( QHash<int, FaceRefinement>::iterator it = facesRefinement.begin(); it != facesRefinement.end(); ++it )
249 int faceIndex = it.key();
250 FaceRefinement &faceRefinement = it.value();
252 int faceSize = face.size();
256 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
258 if ( faceRefinement.refinedFaceNeighbor.at( positionInFace ) )
260 int neighborIndex = neighbors.at( positionInFace );
261 int firstVertexIndex = face.at( positionInFace );
262 int secondVertexIndex = faceRefinement.newVerticesLocalIndex.at( positionInFace ) + startingVertexIndex;
264 const FaceRefinement &otherRefinement = facesRefinement.value( neighborIndex );
266 int otherFaceSize = otherFace.size();
269 int newFace1ChangesIndex = faceRefinement.newFacesChangesIndex.at( ( positionInFace ) );
270 const QgsMeshFace &newFace1 = mFacesToAdd.at( newFace1ChangesIndex );
273 int newFace2ChangesIndex = faceRefinement.newFacesChangesIndex.at( ( positionInFace + 1 ) % faceSize );
274 const QgsMeshFace &newFace2 = mFacesToAdd.at( newFace2ChangesIndex );
277 int otherNewFace1ChangesIndex = otherRefinement.newFacesChangesIndex.at( ( otherPositionInface ) % otherFaceSize );
278 int otherNewFace2ChangesIndex = otherRefinement.newFacesChangesIndex.at( ( otherPositionInface + 1 ) % otherFaceSize );
280 mFacesNeighborhoodToAdd[newFace1ChangesIndex][positionInNewface1Index] = otherNewFace2ChangesIndex + startingGlobalFaceIndex;
281 mFacesNeighborhoodToAdd[newFace2ChangesIndex][positionInNewface2Index] = otherNewFace1ChangesIndex + startingGlobalFaceIndex;
287bool QgsMeshEditRefineFaces::createNewBorderFaces(
QgsMeshEditor *meshEditor,
288 const QSet<int> &facesToRefine,
289 QHash<int, FaceRefinement> &facesRefinement,
290 QHash<int, BorderFace> &borderFaces )
296 int startingFaceChangesGlobalIndex = mesh.
faceCount();
299 for (
int faceIndexToRefine : facesToRefine )
302 int faceToRefineSize = faceToRefine.size();
304 const QVector<int> &neighbors = topology.
neighborsOfFace( faceIndexToRefine );
306 QHash<int, FaceRefinement>::iterator itFace = facesRefinement.find( faceIndexToRefine );
308 if ( itFace == facesRefinement.end() )
311 FaceRefinement &refinement = itFace.value();
313 for (
int posInFaceToRefine = 0; posInFaceToRefine < faceToRefineSize; ++posInFaceToRefine )
315 int neighborFaceIndex = neighbors.at( posInFaceToRefine );
316 if ( neighborFaceIndex != -1 && !facesToRefine.contains( neighborFaceIndex ) )
319 int neighborFaceSize = neighborFace.size();
321 positionInNeighbor = ( positionInNeighbor + neighborFaceSize - 1 ) % neighborFaceSize;
323 QHash<int, BorderFace>::iterator it = borderFaces.find( neighborFaceIndex );
324 if ( it == borderFaces.end() )
326 BorderFace borderFace;
327 for (
int i = 0; i < neighborFaceSize; ++i )
329 borderFace.unchangeFacesNeighbor.append(
false );
330 borderFace.borderFacesNeighbor.append(
false );
331 if ( i == positionInNeighbor )
333 borderFace.refinedFacesNeighbor.append(
true );
334 borderFace.newVerticesLocalIndex.append( refinement.newVerticesLocalIndex.at( posInFaceToRefine ) );
338 borderFace.refinedFacesNeighbor.append(
false );
339 borderFace.newVerticesLocalIndex.append( -1 );
342 borderFaces.insert( neighborFaceIndex, borderFace );
346 BorderFace &borderFace = it.value();
347 for (
int i = 0; i < neighborFaceSize; ++i )
349 if ( i == positionInNeighbor )
351 borderFace.unchangeFacesNeighbor[i] =
false;
352 borderFace.borderFacesNeighbor[i] =
false;
353 borderFace.refinedFacesNeighbor[i] =
true;
354 borderFace.newVerticesLocalIndex[i] = refinement.newVerticesLocalIndex.at( posInFaceToRefine );
363 for ( QHash<int, BorderFace>::iterator it = borderFaces.begin(); it != borderFaces.end(); ++it )
365 int faceIndex = it.key();
366 BorderFace &borderFace = it.value();
369 int faceSize = face.size();
372 for (
int posInFace = 0; posInFace < faceSize; ++posInFace )
374 int neighborIndex = neighbors.at( posInFace );
376 if ( neighborIndex != -1 )
379 int neighborFaceSize = neighborFace.size();
381 posInNeighbor = ( posInNeighbor - 1 + neighborFaceSize ) % neighborFaceSize;
383 QHash<int, FaceRefinement>::iterator itRefinement = facesRefinement.find( neighborIndex );
384 if ( itRefinement != facesRefinement.end() )
386 FaceRefinement &neighborRefinement = itRefinement.value();
387 neighborRefinement.borderFaceNeighbor[posInNeighbor] =
true;
388 borderFace.refinedFacesNeighbor[posInFace] =
true;
392 QHash<int, BorderFace>::iterator itNeighborBorder = borderFaces.find( neighborIndex );
393 if ( itNeighborBorder == borderFaces.end() )
394 borderFace.unchangeFacesNeighbor[posInFace] =
true;
397 BorderFace &neighborBorderFace = itNeighborBorder.value();
398 neighborBorderFace.borderFacesNeighbor[posInNeighbor] =
true;
399 borderFace.borderFacesNeighbor[posInFace] =
true;
404 borderFace.unchangeFacesNeighbor[posInFace] =
true;
410 for ( QHash<int, BorderFace>::iterator it = borderFaces.begin(); it != borderFaces.end(); ++it )
412 int faceIndex = it.key();
413 BorderFace &borderFace = it.value();
416 int faceSize = face.size();
418 QHash<p2t::Point *, int> mapPoly2TriPointToVertex;
419 std::vector<p2t::Point *> points;
420 for (
int i = 0; i < faceSize; ++i )
423 points.push_back(
new p2t::Point( vert.
x(), vert.
y() ) );
424 mapPoly2TriPointToVertex.insert( points.back(), face.at( i ) );
425 if ( borderFace.refinedFacesNeighbor.at( i ) )
427 int localVertexIndex = borderFace.newVerticesLocalIndex.at( i );
429 points.push_back(
new p2t::Point( newVert.
x(), newVert.
y() ) );
430 mapPoly2TriPointToVertex.insert( points.back(), localVertexIndex + startingVertexIndex );
436 std::unique_ptr<p2t::CDT> cdt(
new p2t::CDT( points ) );
438 std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();
439 QVector<QgsMeshFace> faces( triangles.size() );
440 for (
size_t i = 0; i < triangles.size(); ++i )
443 triangle.resize( 3 );
444 QVector<QgsMeshVertex> vertices( 3 );
445 for (
int j = 0; j < 3; j++ )
447 int vertInd = mapPoly2TriPointToVertex.value( triangles.at( i )->GetPoint( j ), -1 );
449 throw std::exception();;
450 triangle[j] = vertInd;
451 if ( vertInd >= startingVertexIndex )
454 vertices[j] = mesh.
vertex( vertInd );
456 QgsMeshUtils::setCounterClockwise( triangle, vertices[0], vertices[1], vertices[2] );
463 QVector<QgsTopologicalMesh::FaceNeighbors> neighborhood = topologicalFaces.
facesNeighborhood();
466 for (
int i = 0; i < neighborhood.count(); ++i )
469 for (
int j = 0; j < neighbors.count(); ++j )
471 if ( neighbors[j] != -1 )
472 neighbors[j] = neighbors[j] + startingFaceIndex;
479 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
481 if ( borderFace.refinedFacesNeighbor.at( positionInFace ) )
484 QVector<int> vertexIndexes( 2 );
485 QVector<int> localFaceIndex( 2 );
486 vertexIndexes[0] = face.at( positionInFace );
487 vertexIndexes[1] = borderFace.newVerticesLocalIndex.at( positionInFace ) + startingVertexIndex;
489 int refinedFaceIndex = neighborOfFace.at( positionInFace );
490 const FaceRefinement &faceRefinement = facesRefinement.value( refinedFaceIndex );
492 int refinedFaceSize = refinedFace.size();
495 for (
int i = 0; i < 2; ++i )
498 circulator.goBoundaryClockwise();
499 localFaceIndex[i] = circulator.currentFaceIndex();
503 const QgsMeshFace newFace = faces.at( localFaceIndex.at( i ) );
505 int newFaceRefinedIndexInChanges = faceRefinement.newFacesChangesIndex.at( ( positionInRefinedFace + ( 1 - i ) ) % refinedFaceSize ) ;
506 neighborsNewFace[positionInNewFace] = newFaceRefinedIndexInChanges + startingFaceChangesGlobalIndex;
510 int newRefinedFaceSize = newRefinedFace.size();
512 neighborsRefinedFace[positionInNewRefinedChange] = localFaceIndex.at( i ) + startingFaceIndex;
515 borderFace.edgeFace.append( localFaceIndex.at( 0 ) + startingFaceIndex );
518 if ( borderFace.borderFacesNeighbor.at( positionInFace ) )
520 int vertexIndex = face.at( positionInFace );
522 circulator.goBoundaryClockwise();
523 int localFaceIndex = circulator.currentFaceIndex();
526 borderFace.edgeFace.append( localFaceIndex + startingFaceIndex );
529 if ( borderFace.unchangeFacesNeighbor.at( positionInFace ) )
531 int vertexIndex = face.at( positionInFace );
533 circulator.goBoundaryClockwise();
534 int localFaceIndex = circulator.currentFaceIndex();
536 const QgsMeshFace &newFace = faces.at( localFaceIndex );
539 int unchangedFaceIndex = neighborOfFace.at( positionInFace );
540 neighborsNewFace[positionInNewface] = unchangedFaceIndex;
542 if ( unchangedFaceIndex != -1 )
545 int unchangedFaceSize = unchangedFace.size();
547 mNeighborhoodChanges.append( {unchangedFaceIndex, positionInUnchangedFace, faceIndex, localFaceIndex + startingFaceIndex} );
550 borderFace.edgeFace.append( localFaceIndex + startingFaceIndex );
557 for ( p2t::Point *pt : points )
568 for ( QHash<int, BorderFace>::iterator it = borderFaces.begin(); it != borderFaces.end(); ++it )
570 int faceIndex = it.key();
571 BorderFace &borderFace = it.value();
573 int faceSize = face.size();
577 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
579 if ( borderFace.borderFacesNeighbor.at( positionInFace ) )
581 int otherIndex = neighbors.at( positionInFace );
583 int otherFaceSize = otherFace.size();
585 const BorderFace &otherBorderFace = borderFaces.value( otherIndex );
586 int otherNewFaceIndex = otherBorderFace.edgeFace.at( otherPositionInface );
588 int newFaceChangesIndex = borderFace.edgeFace.at( positionInFace ) - startingFaceChangesGlobalIndex;
596 for (
int positionInFace = 0; positionInFace < faceSize; ++positionInFace )
598 int vertexIndex = face.at( positionInFace );
610 return QObject::tr(
"Refine %n face(s)",
nullptr,
mInputFaces.count() );
622 QSet<int> concernedFaces;
623 mChangingVertexMap = QHash<int, int>();
628 context.
lastScope()->
setVariable( QStringLiteral(
"_native_mesh" ), QVariant::fromValue( mesh ) );
630 QVector<QgsMeshVertex> newVertices;
636 bool calcX = !mExpressionX.isEmpty();
637 bool calcY = !mExpressionY.isEmpty();
638 bool calcZ = !mExpressionZ.isEmpty();
643 expressionX.
prepare( &context );
650 expressionY.
prepare( &context );
653 if ( calcX || calcY )
663 expressionZ.
prepare( &context );
673 mChangingVertexMap[vertexIndex] = i;
674 const QVariant xvar = expressionX.
evaluate( &context );
675 const QVariant yvar = expressionY.
evaluate( &context );
676 const QVariant zvar = expressionZ.
evaluate( &context );
680 if ( calcX || calcY )
686 concernedFaces.unite( qgis::listToSet( facesAround ) );
692 if ( xvar.isValid() )
694 double x = xvar.toDouble( &ok );
710 if ( yvar.isValid() )
712 double y = yvar.toDouble( &ok );
726 double z = std::numeric_limits<double>::quiet_NaN();
727 if ( zvar.isValid() )
729 z = zvar.toDouble( &ok );
731 z = std::numeric_limits<double>::quiet_NaN();
739 auto transformFunction = [
this, layer ](
int vi )->
const QgsMeshVertex
750 return QObject::tr(
"Transform %n vertices by expression",
nullptr,
mInputVertices.count() );
755 mExpressionX = expressionX;
756 mExpressionY = expressionY;
757 mExpressionZ = expressionZ;
759 mChangingVertexMap.clear();
771 int pos = mChangingVertexMap.value( vertexIndex, -1 );
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.
Class for 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.
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 ...
Class that represents an error during mesh editing.
Class that makes edit operation on a mesh.
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)
Convenient class that turn around a vertex and provide information about faces and vertices.
A class to represent a 2D point.
Point geometry type, with support for z-dimension and m-values.
Class that contains topological differences between two states of a topological mesh,...
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
Class that contains independent faces an topological information about this faces.
QVector< FaceNeighbors > facesNeighborhood() const
Returns the face neighborhood of the faces, indexing is local.
Class that wraps a QgsMesh to ensure the consistency of the mesh during editing and help to access to...
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.