Skip to content

Commit

Permalink
Use raster band names in QGIS [FEATURE] [needs-docs]
Browse files Browse the repository at this point in the history
* fixes #16047
* extracts band name info using gdalapi in QgsGdalProvider
* added configuration option to allowing user to select band name behavior
* currently 5 ways including current default behavior: #, name, name (#), # (name), _DIM_EXTRA metadata
  • Loading branch information
AndrewAnnex authored and nyalldawson committed Oct 9, 2018
1 parent b6e6b90 commit b86f84e
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 60 deletions.
15 changes: 15 additions & 0 deletions src/app/qgsoptions.cpp
Expand Up @@ -418,6 +418,20 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WindowFlags fl, const QList<QgsOpti
cmbPromptRasterSublayers->addItem( tr( "Load all" ) );
cmbPromptRasterSublayers->setCurrentIndex( mSettings->value( QStringLiteral( "/qgis/promptForRasterSublayers" ), 0 ).toInt() );

// decide how qgis should use band names (if present) in raster sources
// 0 = Band Number -> Default behavior is to just use band numbers
// 1 = Band Name -> Uses available band name
// 2 = Band Name & Number -> Uses available band name with a band number-> "name (band #)"
// 3 = Band Name & Number -> Uses band number with available band name-> "band # (name)"
// 4 = Use _DIM_EXTRA -> Uses "_DIM_EXTRA" metadata attribute in netCDF and geotiff
cmbUseOfRasterBandNames->clear();
cmbUseOfRasterBandNames->addItem( tr( "Band Number" ) );
cmbUseOfRasterBandNames->addItem( tr( "Band Name" ) );
cmbUseOfRasterBandNames->addItem( tr( "Band Name & Number" ) );
cmbUseOfRasterBandNames->addItem( tr( "Band Number & Name" ) );
cmbUseOfRasterBandNames->addItem( tr( "Use _DIM_EXTRA" ) );
cmbUseOfRasterBandNames->setCurrentIndex( mSettings->value( QStringLiteral( "/qgis/useOfRasterBandNames" ), 0 ).toInt() );

// Scan for valid items in the browser dock
cmbScanItemsInBrowser->clear();
cmbScanItemsInBrowser->addItem( tr( "Check file contents" ), "contents" ); // 0
Expand Down Expand Up @@ -1389,6 +1403,7 @@ void QgsOptions::saveOptions()
mSettings->setValue( QStringLiteral( "/qgis/attributeTableView" ), mAttrTableViewComboBox->currentData() );
mSettings->setValue( QStringLiteral( "/qgis/attributeTableRowCache" ), spinBoxAttrTableRowCache->value() );
mSettings->setValue( QStringLiteral( "/qgis/promptForRasterSublayers" ), cmbPromptRasterSublayers->currentIndex() );
mSettings->setValue( QStringLiteral( "/qgis/useOfRasterBandNames" ), cmbUseOfRasterBandNames->currentIndex() );
mSettings->setValue( QStringLiteral( "/qgis/scanItemsInBrowser2" ),
cmbScanItemsInBrowser->currentData().toString() );
mSettings->setValue( QStringLiteral( "/qgis/scanZipInBrowser2" ),
Expand Down
129 changes: 69 additions & 60 deletions src/providers/gdal/qgsgdalprovider.cpp
Expand Up @@ -58,6 +58,7 @@
#include <QDebug>

#include <gdalwarper.h>
#include <gdal.h>
#include <ogr_srs_api.h>
#include <cpl_conv.h>
#include <cpl_string.h>
Expand Down Expand Up @@ -932,70 +933,78 @@ QString QgsGdalProvider::generateBandName( int bandNumber ) const
if ( !const_cast<QgsGdalProvider *>( this )->initIfNeeded() )
return QString();

if ( strcmp( GDALGetDriverShortName( GDALGetDatasetDriver( mGdalDataset ) ), "netCDF" ) == 0 || strcmp( GDALGetDriverShortName( GDALGetDatasetDriver( mGdalDataset ) ), "GTiff" ) == 0 )
{
char **GDALmetadata = GDALGetMetadata( mGdalDataset, nullptr );

if ( GDALmetadata )
{
QStringList metadata = QgsOgrUtils::cStringListToQStringList( GDALmetadata );
QStringList dimExtraValues;
QMap< QString, QString > unitsMap;
for ( QStringList::const_iterator i = metadata.constBegin();
i != metadata.constEnd(); ++i )
{
QString val( *i );
if ( !val.startsWith( QLatin1String( "NETCDF_DIM_EXTRA" ) ) && !val.startsWith( QLatin1String( "GTIFF_DIM_EXTRA" ) ) && !val.contains( QLatin1String( "#units=" ) ) )
continue;
QStringList values = val.split( '=' );
val = values.at( 1 );
if ( values.at( 0 ) == QLatin1String( "NETCDF_DIM_EXTRA" ) || values.at( 0 ) == QLatin1String( "GTIFF_DIM_EXTRA" ) )
{
dimExtraValues = val.replace( '{', QString() ).replace( '}', QString() ).split( ',' );
//http://qt-project.org/doc/qt-4.8/qregexp.html#capturedTexts
}
else
{
unitsMap[ values.at( 0 ).split( '#' ).at( 0 )] = val;
}
}
if ( !dimExtraValues.isEmpty() )
{
QStringList bandNameValues;
GDALRasterBandH gdalBand = GDALGetRasterBand( mGdalDataset, bandNumber );
GDALmetadata = GDALGetMetadata( gdalBand, nullptr );
QString generatedBandName = QgsRasterDataProvider::generateBandName( bandNumber );
GDALRasterBandH myGdalBand = getBand( bandNumber );
QString gdalBandName(GDALGetDescription(myGdalBand));

if ( GDALmetadata )
{
metadata = QgsOgrUtils::cStringListToQStringList( GDALmetadata );
for ( QStringList::const_iterator i = metadata.constBegin();
i != metadata.constEnd(); ++i )
{
QString val( *i );
if ( !val.startsWith( QLatin1String( "NETCDF_DIM_" ) ) && !val.startsWith( QLatin1String( "GTIFF_DIM_" ) ) )
continue;
QStringList values = val.split( '=' );
for ( QStringList::const_iterator j = dimExtraValues.constBegin();
j != dimExtraValues.constEnd(); ++j )
{
QString dim = ( *j );
if ( values.at( 0 ) != "NETCDF_DIM_" + dim && values.at( 0 ) != "GTIFF_DIM_" + dim )
continue;
if ( unitsMap.contains( dim ) && !unitsMap[ dim ].isEmpty() && unitsMap[ dim ] != QLatin1String( "none" ) )
bandNameValues.append( dim + '=' + values.at( 1 ) + " (" + unitsMap[ dim ] + ')' );
else
bandNameValues.append( dim + '=' + values.at( 1 ) );
}
QgsSettings settings;
switch(settings.value(QStringLiteral( "/qgis/useOfRasterBandNames" )).toInt()) {
case 0 :
return generatedBandName;
case 1 :
if ( !gdalBandName.isEmpty() ) {
return gdalBandName;
}
}

if ( !bandNameValues.isEmpty() )
return tr( "Band" ) + QStringLiteral( " %1 / %2" ) .arg( bandNumber, 1 + ( int ) std::log10( ( float ) bandCount() ), 10, QChar( '0' ) ).arg( bandNameValues.join( QStringLiteral( " / " ) ) );
}
}
// if we didn't find a band name use the generated one
break;
case 2 :
return gdalBandName + QStringLiteral(" (") + generatedBandName + QStringLiteral(")");
case 3 :
return generatedBandName + QStringLiteral(" (") + gdalBandName + QStringLiteral(")");
case 4 :
if ( strcmp( GDALGetDriverShortName( GDALGetDatasetDriver( mGdalDataset ) ), "netCDF" ) == 0 || strcmp( GDALGetDriverShortName( GDALGetDatasetDriver( mGdalDataset ) ), "GTiff" ) == 0 ) {
char **GDALmetadata = GDALGetMetadata(mGdalDataset, nullptr);

if (GDALmetadata) {
QStringList metadata = QgsOgrUtils::cStringListToQStringList(GDALmetadata);
QStringList dimExtraValues;
QMap<QString, QString> unitsMap;
for (QStringList::const_iterator i = metadata.constBegin(); i != metadata.constEnd(); ++i) {
QString val(*i);
if (!val.startsWith(QLatin1String("NETCDF_DIM_EXTRA")) && !val.startsWith(QLatin1String("GTIFF_DIM_EXTRA")) && !val.contains(QLatin1String("#units=")))
continue;
QStringList values = val.split('=');
val = values.at(1);
if (values.at(0) == QLatin1String("NETCDF_DIM_EXTRA") || values.at(0) == QLatin1String("GTIFF_DIM_EXTRA")) {
dimExtraValues = val.replace('{', QString()).replace('}', QString()).split(',');
//http://qt-project.org/doc/qt-4.8/qregexp.html#capturedTexts
} else {
unitsMap[values.at(0).split('#').at(0)] = val;
}
}
if (!dimExtraValues.isEmpty()) {
QStringList bandNameValues;
GDALRasterBandH gdalBand = GDALGetRasterBand(mGdalDataset, bandNumber);
GDALmetadata = GDALGetMetadata(gdalBand, nullptr);

if (GDALmetadata) {
metadata = QgsOgrUtils::cStringListToQStringList(GDALmetadata);
for (QStringList::const_iterator i = metadata.constBegin(); i != metadata.constEnd(); ++i) {
QString val(*i);
if (!val.startsWith(QLatin1String("NETCDF_DIM_")) && !val.startsWith(QLatin1String("GTIFF_DIM_")))
continue;
QStringList values = val.split('=');
for (QStringList::const_iterator j = dimExtraValues.constBegin(); j != dimExtraValues.constEnd(); ++j) {
QString dim = (*j);
if (values.at(0) != "NETCDF_DIM_" + dim && values.at(0) != "GTIFF_DIM_" + dim)
continue;
if (unitsMap.contains(dim) && !unitsMap[dim].isEmpty() && unitsMap[dim] != QLatin1String("none"))
bandNameValues.append(dim + '=' + values.at(1) + " (" + unitsMap[dim] + ')');
else
bandNameValues.append(dim + '=' + values.at(1));
}
}
}

if (!bandNameValues.isEmpty())
return tr("Band") + QStringLiteral(" %1 / %2").arg(bandNumber, 1 + (int) std::log10((float) bandCount()), 10, QChar('0')).arg(bandNameValues.join(QStringLiteral(" / ")));
}
}
}
break;
}

return QgsRasterDataProvider::generateBandName( bandNumber );
return generatedBandName;
}

QgsRasterIdentifyResult QgsGdalProvider::identify( const QgsPointXY &point, QgsRaster::IdentifyFormat format, const QgsRectangle &boundingBox, int width, int height, int /*dpi*/ )
Expand Down
40 changes: 40 additions & 0 deletions src/ui/qgsoptionsbase.ui
Expand Up @@ -2007,6 +2007,45 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_38">
<item>
<widget class="QLabel" name="textLabel1_15">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Change raster band name behavior</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_38">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QComboBox" name="cmbUseOfRasterBandNames">
<item>
<property name="text">
<string/>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="cbxIgnoreShapeEncoding">
<property name="toolTip">
Expand Down Expand Up @@ -5606,6 +5645,7 @@ p, li { white-space: pre-wrap; }
<tabstop>cmbScanItemsInBrowser</tabstop>
<tabstop>cmbScanZipInBrowser</tabstop>
<tabstop>cmbPromptRasterSublayers</tabstop>
<tabstop>cmbUseOfRasterBandNames</tabstop>
<tabstop>cbxIgnoreShapeEncoding</tabstop>
<tabstop>cbxAddPostgisDC</tabstop>
<tabstop>cbxAddOracleDC</tabstop>
Expand Down

0 comments on commit b86f84e

Please sign in to comment.