Navigation Menu

Skip to content

Commit

Permalink
fix layer extent and vertical extent of dataset group when editing
Browse files Browse the repository at this point in the history
  • Loading branch information
vcloarec committed Sep 15, 2021
1 parent 1fcf40b commit a82b8d4
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 27 deletions.
5 changes: 5 additions & 0 deletions python/core/auto_generated/mesh/qgsmeshdataset.sip.in
Expand Up @@ -737,6 +737,11 @@ Returns whether all the datasets contain ``count`` values
void calculateStatistic();
%Docstring
Calculates the statistics (minimum and maximum)
%End

void setStatisticObsolete();
%Docstring
Sets statistic obsolete, that means statistic will be recalculated when requested
%End

virtual QStringList datasetGroupNamesDependentOn() const;
Expand Down
6 changes: 6 additions & 0 deletions python/core/auto_generated/mesh/qgsmesheditor.sip.in
Expand Up @@ -62,6 +62,12 @@ Constructor with a specified layer ``meshLayer``
%End


QgsMeshDatasetGroup *createZValueDatasetGroup() /TransferBack/;
%Docstring
Creates and returns a scalar dataset group with value on vertex that is can be used to access the Z value of the edited mesh.
The caller takes ownership.
%End

QgsMeshEditingError initialize();
%Docstring
Initialize the mesh editor and return errors if the internal native mesh have topologic errors
Expand Down
39 changes: 28 additions & 11 deletions src/core/mesh/qgsmeshdataset.cpp
Expand Up @@ -975,18 +975,12 @@ QDomElement QgsMeshMemoryDatasetGroup::writeXml( QDomDocument &doc, const QgsRea

void QgsMeshDatasetGroup::calculateStatistic()
{
double min = std::numeric_limits<double>::max();
double max = std::numeric_limits<double>::min();
updateStatictic();
}

const int count = datasetCount();
for ( int i = 0; i < count; ++i )
{
const QgsMeshDatasetMetadata &meta = datasetMetadata( i );
min = std::min( min, meta.minimum() );
max = std::max( max, meta.maximum() );
}
mMinimum = min;
mMaximum = max;
void QgsMeshDatasetGroup::setStatisticObsolete()
{
mIsStatisticObsolete = true;
}

QStringList QgsMeshDatasetGroup::datasetGroupNamesDependentOn() const
Expand All @@ -1004,6 +998,27 @@ void QgsMeshDatasetGroup::setReferenceTime( const QDateTime &referenceTime )
mReferenceTime = referenceTime;
}

void QgsMeshDatasetGroup::updateStatictic() const
{
if ( !mIsStatisticObsolete )
return;

double min = std::numeric_limits<double>::max();
double max = std::numeric_limits<double>::min();

const int count = datasetCount();
for ( int i = 0; i < count; ++i )
{
const QgsMeshDatasetMetadata &meta = datasetMetadata( i );
min = std::min( min, meta.minimum() );
max = std::max( max, meta.maximum() );
}
mMinimum = min;
mMaximum = max;

mIsStatisticObsolete = false;
}

bool QgsMeshDatasetGroup::checkValueCountPerDataset( int count ) const
{
for ( int i = 0; i < datasetCount(); ++i )
Expand All @@ -1021,11 +1036,13 @@ QgsMeshDatasetGroup::QgsMeshDatasetGroup( const QString &name ): mName( name ) {

double QgsMeshDatasetGroup::minimum() const
{
updateStatictic();
return mMinimum;
}

double QgsMeshDatasetGroup::maximum() const
{
updateStatictic();
return mMaximum;
}

Expand Down
10 changes: 8 additions & 2 deletions src/core/mesh/qgsmeshdataset.h
Expand Up @@ -658,6 +658,9 @@ class CORE_EXPORT QgsMeshDatasetGroup
//! Calculates the statistics (minimum and maximum)
void calculateStatistic();

//! Sets statistic obsolete, that means statistic will be recalculated when requested
void setStatisticObsolete();

//! Returns the dataset group variable name which this dataset group depends on
virtual QStringList datasetGroupNamesDependentOn() const;

Expand All @@ -678,8 +681,11 @@ class CORE_EXPORT QgsMeshDatasetGroup
bool mIsScalar = true;

private:
double mMinimum = std::numeric_limits<double>::quiet_NaN();
double mMaximum = std::numeric_limits<double>::quiet_NaN();
mutable double mMinimum = std::numeric_limits<double>::quiet_NaN();
mutable double mMaximum = std::numeric_limits<double>::quiet_NaN();
mutable bool mIsStatisticObsolete = true;

void updateStatictic() const;

QDateTime mReferenceTime;
};
Expand Down
40 changes: 38 additions & 2 deletions src/core/mesh/qgsmesheditor.cpp
Expand Up @@ -52,6 +52,13 @@ QgsMeshEditor::QgsMeshEditor( QgsMesh *nativeMesh, QgsTriangularMesh *triangular
connect( mUndoStack, &QUndoStack::indexChanged, this, &QgsMeshEditor::meshEdited );
}

QgsMeshDatasetGroup *QgsMeshEditor::createZValueDatasetGroup()
{
std::unique_ptr<QgsMeshDatasetGroup> zValueDatasetGroup = std::make_unique<QgsMeshVerticesElevationDatasetGroup>( tr( "vertices Z value" ), mMesh );
mZValueDatasetGroup = zValueDatasetGroup.get();
return zValueDatasetGroup.release();
}

QgsMeshEditor::~QgsMeshEditor() = default;

QgsMeshEditingError QgsMeshEditor::initialize()
Expand Down Expand Up @@ -184,12 +191,24 @@ void QgsMeshEditor::applyEdit( QgsMeshEditor::Edit &edit )
{
mTopologicalMesh.applyChanges( edit.topologicalChanges );
mTriangularMesh->applyChanges( edit.triangularMeshChanges );

if ( mZValueDatasetGroup &&
( !edit.topologicalChanges.newVerticesZValues().isEmpty() ||
!edit.topologicalChanges.verticesToRemoveIndexes().isEmpty() ||
!edit.topologicalChanges.addedVertices().isEmpty() ) )
mZValueDatasetGroup->setStatisticObsolete();
}

void QgsMeshEditor::reverseEdit( QgsMeshEditor::Edit &edit )
{
mTopologicalMesh.reverseChanges( edit.topologicalChanges );
mTriangularMesh->reverseChanges( edit.triangularMeshChanges, *mMesh );

if ( mZValueDatasetGroup &&
( !edit.topologicalChanges.newVerticesZValues().isEmpty() ||
!edit.topologicalChanges.verticesToRemoveIndexes().isEmpty() ||
!edit.topologicalChanges.addedVertices().isEmpty() ) )
mZValueDatasetGroup->setStatisticObsolete();
}

void QgsMeshEditor::applyAddVertex( QgsMeshEditor::Edit &edit, const QgsMeshVertex &vertex, double tolerance )
Expand Down Expand Up @@ -217,16 +236,25 @@ void QgsMeshEditor::applyAddVertex( QgsMeshEditor::Edit &edit, const QgsMeshVert
}

applyEditOnTriangularMesh( edit, topologicChanges );

if ( mZValueDatasetGroup )
mZValueDatasetGroup->setStatisticObsolete();
}

void QgsMeshEditor::applyRemoveVertexFillHole( QgsMeshEditor::Edit &edit, int vertexIndex )
{
applyEditOnTriangularMesh( edit, mTopologicalMesh.removeVertexFillHole( vertexIndex ) );

if ( mZValueDatasetGroup )
mZValueDatasetGroup->setStatisticObsolete();
}

void QgsMeshEditor::applyRemoveVerticesWithoutFillHole( QgsMeshEditor::Edit &edit, const QList<int> &verticesIndexes )
{
applyEditOnTriangularMesh( edit, mTopologicalMesh.removeVertices( verticesIndexes ) );

if ( mZValueDatasetGroup )
mZValueDatasetGroup->setStatisticObsolete();
}

void QgsMeshEditor::applyAddFaces( QgsMeshEditor::Edit &edit, const QgsTopologicalMesh::TopologicalFaces &faces )
Expand All @@ -242,6 +270,9 @@ void QgsMeshEditor::applyRemoveFaces( QgsMeshEditor::Edit &edit, const QList<int
void QgsMeshEditor::applyChangeZValue( QgsMeshEditor::Edit &edit, const QList<int> &verticesIndexes, const QList<double> &newValues )
{
applyEditOnTriangularMesh( edit, mTopologicalMesh.changeZValue( verticesIndexes, newValues ) );

if ( mZValueDatasetGroup )
mZValueDatasetGroup->setStatisticObsolete();
}

void QgsMeshEditor::applyChangeXYValue( QgsMeshEditor::Edit &edit, const QList<int> &verticesIndexes, const QList<QgsPointXY> &newValues )
Expand Down Expand Up @@ -493,7 +524,9 @@ int QgsMeshEditor::addVertices( const QVector<QgsMeshVertex> &vertices, double t
mUndoStack->push( new QgsMeshLayerUndoCommandAddVertices( this, verticesInLayerCoordinate, tolerance ) );
}

return vertices.count() - ignoredVertex;
int effectivlyAddedVertex = vertices.count() - ignoredVertex;

return effectivlyAddedVertex;
}

int QgsMeshEditor::addPointsAsVertices( const QVector<QgsPoint> &point, double tolerance )
Expand All @@ -518,7 +551,10 @@ QgsMeshEditingError QgsMeshEditor::removeVertices( const QList<int> &verticesToR
return error;
}

mUndoStack->push( new QgsMeshLayerUndoCommandRemoveVertices( this, verticesIndexes, fillHoles ) );
if ( error.errorType == Qgis::MeshEditingErrorType::NoError )
{
mUndoStack->push( new QgsMeshLayerUndoCommandRemoveVertices( this, verticesIndexes, fillHoles ) );
}

return error;
}
Expand Down
7 changes: 7 additions & 0 deletions src/core/mesh/qgsmesheditor.h
Expand Up @@ -73,6 +73,12 @@ class CORE_EXPORT QgsMeshEditor : public QObject
QgsMeshEditor( QgsMesh *nativeMesh, QgsTriangularMesh *triangularMesh, QObject *parent = nullptr ); SIP_SKIP
~QgsMeshEditor();

/**
* Creates and returns a scalar dataset group with value on vertex that is can be used to access the Z value of the edited mesh.
* The caller takes ownership.
*/
QgsMeshDatasetGroup *createZValueDatasetGroup() SIP_TRANSFERBACK;

//! Initialize the mesh editor and return errors if the internal native mesh have topologic errors
QgsMeshEditingError initialize();

Expand Down Expand Up @@ -241,6 +247,7 @@ class CORE_EXPORT QgsMeshEditor : public QObject
QgsTopologicalMesh mTopologicalMesh;
QgsTriangularMesh *mTriangularMesh = nullptr;
int mMaximumVerticesPerFace = 0;
QgsMeshDatasetGroup *mZValueDatasetGroup = nullptr;

QVector<QgsMeshFace> prepareFaces( const QVector<QgsMeshFace> &faces, QgsMeshEditingError &error );

Expand Down
2 changes: 1 addition & 1 deletion src/core/mesh/qgsmeshlayer.cpp
Expand Up @@ -925,7 +925,7 @@ bool QgsMeshLayer::startFrameEditing( const QgsCoordinateTransform &transform )
// All dataset group are removed and replace by a unique virtual dataset group that provide vertices elevation value.
mExtraDatasetUri.clear();
mDatasetGroupStore.reset( new QgsMeshDatasetGroupStore( this ) );
mDatasetGroupStore->addDatasetGroup( new QgsMeshVerticesElevationDatasetGroup( tr( "vertices Z value" ), mNativeMesh.get() ) );
mDatasetGroupStore->addDatasetGroup( mMeshEditor->createZValueDatasetGroup() );
resetDatasetGroupTreeItem();

connect( mMeshEditor, &QgsMeshEditor::meshEdited, this, &QgsMeshLayer::onMeshEdited );
Expand Down
35 changes: 25 additions & 10 deletions src/core/mesh/qgstriangularmesh.cpp
Expand Up @@ -291,7 +291,7 @@ QgsRectangle QgsTriangularMesh::nativeExtent()
{
try
{
nativeExtent = mCoordinateTransform.transform( mExtent, QgsCoordinateTransform::ReverseTransform );
nativeExtent = mCoordinateTransform.transform( extent(), QgsCoordinateTransform::ReverseTransform );
}
catch ( QgsCsException &cse )
{
Expand All @@ -300,13 +300,22 @@ QgsRectangle QgsTriangularMesh::nativeExtent()
}
}
else
nativeExtent = mExtent;
nativeExtent = extent();

return nativeExtent;
}

QgsRectangle QgsTriangularMesh::extent() const
{
if ( !mIsExtentValid )
{
mExtent.setMinimal();
for ( int i = 0; i < mTriangularMesh.vertices.size(); ++i )
if ( !mTriangularMesh.vertices.at( i ).isEmpty() )
mExtent.include( mTriangularMesh.vertices.at( i ) );

mIsExtentValid = true;
}
return mExtent;
}

Expand Down Expand Up @@ -795,11 +804,14 @@ void QgsTriangularMesh::applyChanges( const QgsTriangularMesh::Changes &changes
}

for ( int i = 0; i < changes.mNativeFaceIndexesToRemove.count(); ++i )
mNativeMeshFaceCentroids[changes.mNativeFaceIndexesToRemove.at( i )] = QgsPoint();
mNativeMeshFaceCentroids[changes.mNativeFaceIndexesToRemove.at( i )] = QgsMeshVertex();

// remove vertices
// for now, let's try to not remove the vertices, because if the vertex is not referenced in faces,
// there is no access anymore to the vertex. If we do not remove it, not need to store (x,y,z) in the changes instance
for ( int i = 0; i < changes.mVerticesIndexesToRemove.count(); ++i )
mTriangularMesh.vertices[changes.mVerticesIndexesToRemove.at( i )] = QgsMeshVertex();

if ( !changes.mVerticesIndexesToRemove.isEmpty() )
mIsExtentValid = false;

// change Z value
for ( int i = 0; i < changes.mNewZValue.count(); ++i )
Expand Down Expand Up @@ -850,12 +862,15 @@ void QgsTriangularMesh::reverseChanges( const QgsTriangularMesh::Changes &change
int initialVerticesCount = mTriangularMesh.vertices.count() - changes.mAddedVertices.count();
mTriangularMesh.vertices.resize( initialVerticesCount );

// for each vertex to remove, check if the triangular vertex is empty,
// that means vertices had to be updated from the native mesh but faces was empty
// we need to update the vertices with the reverse native face
if ( !changes.mAddedVertices.isEmpty() )
mIsExtentValid = false;

// for each vertex to remove we need to update the vertices with the native vertex
for ( const int i : std::as_const( changes.mVerticesIndexesToRemove ) )
if ( mTriangularMesh.vertex( i ).isEmpty() )
mTriangularMesh.vertices[i] = nativeToTriangularCoordinates( nativeMesh.vertex( i ) );
mTriangularMesh.vertices[i] = nativeToTriangularCoordinates( nativeMesh.vertex( i ) );

if ( !changes.mVerticesIndexesToRemove.isEmpty() )
mIsExtentValid = false;

// reverse removed faces
QVector<QgsMeshFace> restoredTriangles;
Expand Down
3 changes: 2 additions & 1 deletion src/core/mesh/qgstriangularmesh.h
Expand Up @@ -361,7 +361,8 @@ class CORE_EXPORT QgsTriangularMesh // TODO rename to QgsRendererMesh in QGIS 4
QgsMeshSpatialIndex mSpatialEdgeIndex;
QgsCoordinateTransform mCoordinateTransform; //coordinate transform used to convert native mesh vertices to map vertices

QgsRectangle mExtent;
mutable QgsRectangle mExtent;
mutable bool mIsExtentValid = false;

// average size of the triangles
double mAverageTriangleSize = 0;
Expand Down

0 comments on commit a82b8d4

Please sign in to comment.