Navigation Menu

Skip to content

Commit

Permalink
Mesh layer style following dataset group name (#52312)
Browse files Browse the repository at this point in the history
* copy mesh layer style following dataset group name

* fix typo and sipify

* fix const

* fix version in doc

* fix version in doc
  • Loading branch information
vcloarec committed Apr 26, 2023
1 parent bce3f8b commit 004f6d3
Show file tree
Hide file tree
Showing 7 changed files with 240 additions and 4 deletions.
29 changes: 29 additions & 0 deletions python/core/auto_generated/mesh/qgsmeshrenderersettings.sip.in
Expand Up @@ -682,9 +682,24 @@ Sets new edge mesh renderer settings
%Docstring
Returns renderer settings
%End

void setScalarSettings( int groupIndex, const QgsMeshRendererScalarSettings &settings );
%Docstring
Sets new renderer settings
%End

bool hasScalarSettings( int groupIndex ) const;
%Docstring
Returns whether ``groupIndex`` has existing scalar settings

.. versionadded:: 3.30.2
%End

bool removeScalarSettings( int groupIndex );
%Docstring
Removes scalar settings with ``groupIndex``

.. versionadded:: 3.30.2
%End

QgsMeshRendererVectorSettings vectorSettings( int groupIndex ) const;
Expand All @@ -694,6 +709,20 @@ Returns renderer settings
void setVectorSettings( int groupIndex, const QgsMeshRendererVectorSettings &settings );
%Docstring
Sets new renderer settings
%End

bool hasVectorSettings( int groupIndex ) const;
%Docstring
Returns whether ``groupIndex`` has existing vector settings

.. versionadded:: 3.30.2
%End

bool removeVectorSettings( int groupIndex );
%Docstring
Removes vector settings for ``groupIndex``

.. versionadded:: 3.30.2
%End

QgsMesh3dAveragingMethod *averagingMethod() const;
Expand Down
10 changes: 10 additions & 0 deletions src/core/mesh/qgsmeshdatasetgroupstore.cpp
Expand Up @@ -392,6 +392,16 @@ int QgsMeshDatasetGroupStore::globalDatasetGroupIndexInSource( QgsMeshDatasetSou
return -1;
}

int QgsMeshDatasetGroupStore::indexFromGroupName( const QString &groupName ) const
{
return mGroupNameToGlobalIndex.value( groupName, -1 );
}

QString QgsMeshDatasetGroupStore::groupName( int groupIndex ) const
{
return datasetGroupMetadata( groupIndex ).name();
}

bool QgsMeshDatasetGroupStore::saveDatasetGroup( QString filePath, int groupIndex, QString driver )
{
DatasetGroup group = datasetGroup( groupIndex );
Expand Down
20 changes: 17 additions & 3 deletions src/core/mesh/qgsmeshdatasetgroupstore.h
Expand Up @@ -125,7 +125,7 @@ class QgsMeshDatasetGroupStore: public QObject

public:
//! Constructor
QgsMeshDatasetGroupStore( QgsMeshLayer *layer );
explicit QgsMeshDatasetGroupStore( QgsMeshLayer *layer );

//! Sets the persistent mesh data provider with the path of its extra dataset to be loaded by the provider
void setPersistentProvider( QgsMeshDataProvider *provider, const QStringList &extraDatasetUri );
Expand Down Expand Up @@ -203,7 +203,7 @@ class QgsMeshDatasetGroupStore: public QObject
/**
* Returns the global dataset index of the dataset int the dataset group with \a groupIndex, that is between relative times \a time1 and \a time2
*
* Since QGIS 3.22
* \since QGIS 3.22
*/
QList<QgsMeshDatasetIndex> datasetIndexInTimeInterval( qint64 time1, qint64 time2, int groupIndex ) const;

Expand All @@ -223,10 +223,24 @@ class QgsMeshDatasetGroupStore: public QObject
* Returns the global dataset group index of the dataset group with native index \a nativeGroupIndex in the \a source
* Returns -1 if the group or the source is not registered
*
* Since QGIS 3.22
* \since QGIS 3.22
*/
int globalDatasetGroupIndexInSource( QgsMeshDatasetSourceInterface *source, int nativeGroupIndex ) const;

/**
* Returns the global dataset group index of the dataset with name \a groupName
*
* \since QGIS 3.30.2
*/
int indexFromGroupName( const QString &groupName ) const;

/**
* Returns the name of the dataset group with global index \a groupIndex
*
* \since QGIS 3.30.2
*/
QString groupName( int groupIndex ) const;

signals:
//! Emitted after dataset groups are added
void datasetGroupsAdded( QList<int> indexes );
Expand Down
83 changes: 82 additions & 1 deletion src/core/mesh/qgsmeshlayer.cpp
Expand Up @@ -1382,6 +1382,64 @@ void QgsMeshLayer::updateActiveDatasetGroups()
emit activeVectorDatasetGroupChanged( settings.activeVectorDatasetGroup() );
}

QgsMeshRendererSettings QgsMeshLayer::accordSymbologyWithGroupName( const QgsMeshRendererSettings &settings, const QMap<QString, int> &nameToIndex )
{
QString activeScalarName;
QString activeVectorName;
QgsMeshRendererSettings consistentSettings = settings;
int activeScalar = consistentSettings.activeScalarDatasetGroup();
int activeVector = consistentSettings.activeScalarDatasetGroup();

for ( auto it = nameToIndex.constBegin(); it != nameToIndex.constEnd(); ++it )
{
int index = it.value();
const QString name = it.key() ;
int globalIndex = mDatasetGroupStore->indexFromGroupName( name );
if ( globalIndex >= 0 )
{
QgsMeshRendererScalarSettings scalarSettings = settings.scalarSettings( index );
consistentSettings.setScalarSettings( globalIndex, scalarSettings );
if ( settings.hasVectorSettings( it.value() ) && mDatasetGroupStore->datasetGroupMetadata( globalIndex ).isVector() )
{
QgsMeshRendererVectorSettings vectorSettings = settings.vectorSettings( index );
consistentSettings.setVectorSettings( globalIndex, vectorSettings );
}
}
else
{
consistentSettings.removeScalarSettings( index );
if ( settings.hasVectorSettings( it.value() ) )
consistentSettings.removeVectorSettings( index );
}

if ( index == activeScalar )
activeScalarName = name;
if ( index == activeVector )
activeVectorName = name;
}

const QList<int> globalIndexes = datasetGroupsIndexes();
for ( int globalIndex : globalIndexes )
{
const QString name = mDatasetGroupStore->groupName( globalIndex );
if ( !nameToIndex.contains( name ) )
{
consistentSettings.setScalarSettings( globalIndex, mRendererSettings.scalarSettings( globalIndex ) );
if ( mDatasetGroupStore->datasetGroupMetadata( globalIndex ).isVector() )
{
consistentSettings.setVectorSettings( globalIndex, mRendererSettings.vectorSettings( globalIndex ) );
}
}
}

if ( !activeScalarName.isEmpty() )
consistentSettings.setActiveScalarDatasetGroup( mDatasetGroupStore->indexFromGroupName( activeScalarName ) );
if ( activeVectorName.isEmpty() )
consistentSettings.setActiveVectorDatasetGroup( mDatasetGroupStore->indexFromGroupName( activeVectorName ) );

return consistentSettings;
}

void QgsMeshLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
{
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
Expand Down Expand Up @@ -1634,9 +1692,22 @@ bool QgsMeshLayer::readSymbology( const QDomNode &node, QString &errorMessage,

readCommonStyle( elem, context, categories );

QgsMeshRendererSettings rendererSettings;
const QDomElement elemRendererSettings = elem.firstChildElement( "mesh-renderer-settings" );
if ( !elemRendererSettings.isNull() )
mRendererSettings.readXml( elemRendererSettings, context );
rendererSettings.readXml( elemRendererSettings, context );

QMap<QString, int> groupNameToGlobalIndex;
QDomElement nameToIndexElem = elem.firstChildElement( "name-to-global-index" );
while ( !nameToIndexElem.isNull() )
{
const QString name = nameToIndexElem.attribute( QStringLiteral( "name" ) );
int globalIndex = nameToIndexElem.attribute( QStringLiteral( "global-index" ) ).toInt();
groupNameToGlobalIndex.insert( name, globalIndex );
nameToIndexElem = nameToIndexElem.nextSiblingElement( QStringLiteral( "name-to-global-index" ) );
}

mRendererSettings = accordSymbologyWithGroupName( rendererSettings, groupNameToGlobalIndex );

checkSymbologyConsistency();

Expand Down Expand Up @@ -1681,6 +1752,16 @@ bool QgsMeshLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &e
const QDomElement elemRendererSettings = mRendererSettings.writeXml( doc, context );
elem.appendChild( elemRendererSettings );

const QList<int> groupIndexes = datasetGroupsIndexes();
// we store the relation between name and indexes to be able to retrieve the consistency between name and symbology
for ( int index : groupIndexes )
{
QDomElement elemNameToIndex = doc.createElement( QStringLiteral( "name-to-global-index" ) );
elemNameToIndex.setAttribute( QStringLiteral( "name" ), mDatasetGroupStore->groupName( index ) );
elemNameToIndex.setAttribute( QStringLiteral( "global-index" ), index );
elem.appendChild( elemNameToIndex );
}

const QDomElement elemSimplifySettings = mSimplificationSettings.writeXml( doc, context );
elem.appendChild( elemSimplifySettings );

Expand Down
1 change: 1 addition & 0 deletions src/core/mesh/qgsmeshlayer.h
Expand Up @@ -1004,6 +1004,7 @@ class CORE_EXPORT QgsMeshLayer : public QgsMapLayer, public QgsAbstractProfileSo

void updateActiveDatasetGroups();

QgsMeshRendererSettings accordSymbologyWithGroupName( const QgsMeshRendererSettings &settings, const QMap<QString, int> &nameToIndex );
void checkSymbologyConsistency();

void setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider,
Expand Down
25 changes: 25 additions & 0 deletions src/core/mesh/qgsmeshrenderersettings.h
Expand Up @@ -619,14 +619,39 @@ class CORE_EXPORT QgsMeshRendererSettings

//! Returns renderer settings
QgsMeshRendererScalarSettings scalarSettings( int groupIndex ) const { return mRendererScalarSettings.value( groupIndex ); }

//! Sets new renderer settings
void setScalarSettings( int groupIndex, const QgsMeshRendererScalarSettings &settings ) { mRendererScalarSettings[groupIndex] = settings; }

/**
* Returns whether \a groupIndex has existing scalar settings
* \since QGIS 3.30.2
*/
bool hasScalarSettings( int groupIndex ) const {return mRendererScalarSettings.contains( groupIndex );}

/**
* Removes scalar settings with \a groupIndex
* \since QGIS 3.30.2
*/
bool removeScalarSettings( int groupIndex ) {return mRendererScalarSettings.remove( groupIndex );}

//! Returns renderer settings
QgsMeshRendererVectorSettings vectorSettings( int groupIndex ) const { return mRendererVectorSettings.value( groupIndex ); }
//! Sets new renderer settings
void setVectorSettings( int groupIndex, const QgsMeshRendererVectorSettings &settings ) { mRendererVectorSettings[groupIndex] = settings; }

/**
* Returns whether \a groupIndex has existing vector settings
* \since QGIS 3.30.2
*/
bool hasVectorSettings( int groupIndex ) const {return mRendererVectorSettings.contains( groupIndex );}

/**
* Removes vector settings for \a groupIndex
* \since QGIS 3.30.2
*/
bool removeVectorSettings( int groupIndex ) {return mRendererVectorSettings.remove( groupIndex );}

/**
* Returns averaging method for conversion of 3d stacked mesh data to 2d data
*
Expand Down
76 changes: 76 additions & 0 deletions tests/src/core/testqgsmeshlayer.cpp
Expand Up @@ -106,6 +106,7 @@ class TestQgsMeshLayer : public QObject
void testSetDataSourceRetainStyle();

void keepDatasetIndexConsistency();
void symbologyConsistencyWithName();
void updateTimePropertiesWhenReloading();
};

Expand Down Expand Up @@ -2104,6 +2105,81 @@ void TestQgsMeshLayer::keepDatasetIndexConsistency()

}

void TestQgsMeshLayer::symbologyConsistencyWithName()
{
const QString uri_1( mDataDir + QStringLiteral( "/mesh_z_ws_d_vel.nc" ) ); //mesh with dataset group "Bed Elevation", "Water level", "Depth" and "Velocity"
const QString uri_2( mDataDir + QStringLiteral( "/mesh_z_ws_d.nc" ) ); //exactly the same mesh except without "Velocity"

std::unique_ptr< QgsMeshLayer > layer_1 = std::make_unique< QgsMeshLayer >( uri_1, QStringLiteral( "mesh" ), QStringLiteral( "mdal" ) );
std::unique_ptr< QgsMeshLayer > layer_2 = std::make_unique< QgsMeshLayer >( uri_2, QStringLiteral( "mesh" ), QStringLiteral( "mdal" ) );

QMap<QString, int> nameToindex_1;
QList<int> indexes = layer_1->datasetGroupsIndexes();
for ( int index : indexes )
nameToindex_1.insert( layer_1->datasetGroupMetadata( index ).name(), index );

QMap<QString, int> nameToindex_2;
indexes = layer_2->datasetGroupsIndexes();
for ( int index : std::as_const( indexes ) )
nameToindex_2.insert( layer_2->datasetGroupMetadata( index ).name(), index );

QStringList names_1 = nameToindex_1.keys();
QgsMeshRendererSettings settings_1 = layer_1->rendererSettings();
for ( int i = 0; i < names_1.count(); ++i )
{
const QString name = names_1.at( i );
int index = nameToindex_1.value( name );
QgsMeshRendererScalarSettings scalSettings = settings_1.scalarSettings( index );
QgsColorRampShader cl = scalSettings.colorRampShader();
cl.setClassificationMode( QgsColorRampShader::EqualInterval );
cl.classifyColorRamp( 10 + i, -1 );
QCOMPARE( cl.colorRampItemList().count(), 10 + i );
scalSettings.setColorRampShader( cl );
settings_1.setScalarSettings( index, scalSettings );
}
layer_1->setRendererSettings( settings_1 );

QStringList names_2 = nameToindex_2.keys();
QgsMeshRendererSettings settings_2 = layer_2->rendererSettings();
for ( int i = 0; i < names_2.count(); ++i )
{
const QString name = names_2.at( i );
int index = nameToindex_2.value( name );
QgsMeshRendererScalarSettings scalSettings = settings_2.scalarSettings( index );
QgsColorRampShader cl = scalSettings.colorRampShader();
cl.setClassificationMode( QgsColorRampShader::EqualInterval );
cl.classifyColorRamp( 30 + i, -1 );
QCOMPARE( cl.colorRampItemList().count(), 30 + i );
scalSettings.setColorRampShader( cl );
settings_2.setScalarSettings( index, scalSettings );
}
layer_2->setRendererSettings( settings_2 );

QDomDocument doc( QStringLiteral( "dataset-symbology" ) );
QDomElement elem_1 = doc.createElement( "dataset-symbology" );
QString err;
QgsReadWriteContext rwContext;
QVERIFY( layer_1->writeStyle( elem_1, doc, err, rwContext ) );

QDomElement elem_2 = doc.createElement( "dataset-symbology" );
QVERIFY( layer_2->writeStyle( elem_2, doc, err, rwContext ) );

QVERIFY( layer_2->readStyle( elem_1, err, rwContext ) );
QVERIFY( layer_1->readStyle( elem_2, err, rwContext ) );

settings_1 = layer_1->rendererSettings();
QCOMPARE( 30, settings_1.scalarSettings( nameToindex_1.value( names_1.at( 0 ) ) ).colorRampShader().colorRampItemList().count() );
// following group is not present in layer_2, so symbology is unchanged
QCOMPARE( 11, settings_1.scalarSettings( nameToindex_1.value( names_1.at( 1 ) ) ).colorRampShader().colorRampItemList().count() );
QCOMPARE( 31, settings_1.scalarSettings( nameToindex_1.value( names_1.at( 2 ) ) ).colorRampShader().colorRampItemList().count() );
QCOMPARE( 32, settings_1.scalarSettings( nameToindex_1.value( names_1.at( 3 ) ) ).colorRampShader().colorRampItemList().count() );

settings_2 = layer_2->rendererSettings();
QCOMPARE( 10, settings_2.scalarSettings( nameToindex_2.value( names_2.at( 0 ) ) ).colorRampShader().colorRampItemList().count() );
QCOMPARE( 12, settings_2.scalarSettings( nameToindex_2.value( names_2.at( 1 ) ) ).colorRampShader().colorRampItemList().count() );
QCOMPARE( 13, settings_2.scalarSettings( nameToindex_2.value( names_2.at( 2 ) ) ).colorRampShader().colorRampItemList().count() );
}

void TestQgsMeshLayer::test_temporal()
{
const qint64 relativeTime_0 = -1000;
Expand Down

0 comments on commit 004f6d3

Please sign in to comment.