19#include "qgsogrprovider.h"
33std::once_flag usageInformationLoaderFlag;
34QHash<Qgis::RasterAttributeTableFieldUsage, QgsRasterAttributeTable::UsageInformation> QgsRasterAttributeTable::sUsageInformation;
46 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
52 if ( !
hasColor() || row < 0 || row >= mData.count() )
57 for (
int idx = 0; idx < mFields.count(); ++idx )
59 const Field f { mFields.at( idx ) };
84 if ( !
hasRamp() || row < 0 || row >= mData.count() )
90 for (
Field &f : mFields )
128 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
135 QList<Qgis::RasterAttributeTableFieldUsage>
usages;
138 usages.push_back( field.usage );
144QList<int> QgsRasterAttributeTable::intUsages( )
const
149 usages.push_back(
static_cast<int>( field.usage ) );
157 QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
164 const QVariantList rowData = mData.at(
row );
179 if ( !
hasRamp() || row < 0 || row >= mData.count() )
183 QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
184 const QVariantList rowData = mData.at(
row );
221 for (
const QVariantList &
row : std::as_const( mData ) )
224 for (
const auto &cell : std::as_const(
row ) )
226 attributes.append( cell );
229 feature.setAttributes( attributes );
230 features.
append( feature );
248 const int realPos { std::clamp( position, 0,
static_cast<int>( mFields.count() ) ) };
250 if ( field.
name.isEmpty() )
254 *errorMessage = tr(
"Field name must not be empty." );
267 *errorMessage = tr(
"A field with name '%1' already exists." ).arg( field.
name );
273 static const QList<Qgis::RasterAttributeTableFieldUsage> uniqueUsages {{
297 *errorMessage = tr(
"A field with unique usage '%1' already exists." ).arg(
usageName( field.
usage ) );
302 mFields.insert( realPos, field );
304 for (
auto it = mData.begin(); it != mData.end(); ++it )
308 switch ( field.
type )
310 case QMetaType::Type::QChar:
311 case QMetaType::Type::Int:
312 case QMetaType::Type::UInt:
313 case QMetaType::Type::LongLong:
314 case QMetaType::Type::ULongLong:
315 case QMetaType::Type::Double:
319 defaultValue = QString();
321 it->insert( realPos, defaultValue );
353 int idx { position };
367 if ( fieldIndex < 0 || fieldIndex >=
fields().count( ) )
378 mFields[ fieldIndex ].usage = usage;
390 *errorMessage = tr(
"A color ramp can only be added to an athematic attribute table." );
394 int idx { position };
408 return insertField( mFields.count(), name, usage,
type, errorMessage );
418 return insertField( mFields.count(), field, errorMessage );
423 const auto toRemove { std::find_if( mFields.begin(), mFields.end(), [ &name ](
Field & f ) ->
bool {
424 return f.name == name;
427 if ( toRemove != mFields.end() )
429 const int idx {
static_cast<int>( std::distance( mFields.begin(), toRemove ) ) };
430 mFields.erase( toRemove );
431 for (
auto it = mData.begin(); it != mData.end(); ++it )
442 *errorMessage = tr(
"A field with name '%1' was not found." ).arg( name );
450 const int realPos { std::clamp( position, 0,
static_cast<int>( mData.count() ) ) };
452 if ( rowData.size() != mFields.size() )
456 *errorMessage = tr(
"Row element count differs from field count (%1)." ).arg( mFields.size() );
461 QVariantList dataValid;
463 for (
int idx = 0; idx < mFields.count(); ++idx )
465 QVariant cell( rowData[ idx ] );
466 if ( ! cell.canConvert( mFields.at( idx ).type ) || ! cell.convert( mFields.at( idx ).type ) )
470 *errorMessage = tr(
"Row data at column %1 cannot be converted to field type (%2)." ).arg( idx ).arg( QVariant::typeToName( mFields.at( idx ).type ) );
476 dataValid.append( cell );
480 mData.insert( realPos, dataValid );
487 if ( position >= mData.count() || position < 0 || mData.isEmpty() )
491 *errorMessage = tr(
"Position is not valid or the table is empty." );
495 mData.removeAt( position );
509 options.
driverName = QStringLiteral(
"ESRI Shapefile" );
511 options.
layerOptions = QStringList() << QStringLiteral(
"SHPT=NULL" );
513 std::unique_ptr<QgsVectorFileWriter> writer;
516 QString cleanedPath { path };
517 if ( path.endsWith( QStringLiteral(
".dbf" ), Qt::CaseSensitivity::CaseInsensitive ) )
519 cleanedPath.chop( 4 );
526 cleanedPath.append( QStringLiteral(
".dbf" ) );
533 *errorMessage = tr(
"Error creating Raster Attribute Table table: %1." ).arg( writer->errorMessage() );
539 bool result { writer->addFeatures( features ) };
545 *errorMessage = tr(
"Error creating Raster Attribute Table table: could not add rows." );
550 result = writer->flushBuffer();
554 mFilePath = cleanedPath;
564 if ( ! ratDbfSource.isValid() )
568 *errorMessage = tr(
"Error reading Raster Attribute Table table from file: invalid layer." );
573 QList<Field> oldFields = mFields;
574 QList<QVariantList> oldData = mData;
579 bool hasValueField {
false };
580 for (
const QgsField &field : ratDbfSource.fields() )
583 QMetaType::Type
type { field.type() };
585 if (
type == QMetaType::Type::LongLong &&
591 type = QMetaType::Type::Int;
596 hasValueField =
true;
609 if ( ! hasValueField && mFields.count() > 1 && ( mFields.at( 0 ).type == QMetaType::Type::Int || mFields.at( 0 ).type == QMetaType::Type::QChar || mFields.at( 0 ).type == QMetaType::Type::UInt || mFields.at( 0 ).type == QMetaType::Type::LongLong || mFields.at( 0 ).type == QMetaType::Type::ULongLong ) )
614 const int fieldCount {
static_cast<int>( ratDbfSource.fields().count( ) ) };
617 while ( fit.nextFeature( f ) )
623 *errorMessage = tr(
"Error reading Raster Attribute Table table from file: number of fields and number of attributes do not match." );
643 if ( mFields.isEmpty() )
645 errors.push_back( tr(
"The attribute table has no fields." ) );
648 if ( mData.isEmpty() )
650 errors.push_back( tr(
"The attribute table has no rows." ) );
653 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
656 if ( ! isMinMax && ! isValueRamp )
658 errors.push_back( tr(
"The attribute table has no MinMax nor a pair of Min and Max fields." ) );
666 errors.push_back( tr(
"The attribute table has some but not all the fields required for color definition (Red, Green, Blue)." ) );
675 errors.push_back( tr(
"The attribute table has some but not all the fields required for color ramp definition (RedMin, GreenMin, BlueMin, RedMax, GreenMax, BlueMax)." ) );
677 else if ( ! isValueRamp )
679 errors.push_back( tr(
"The attribute table has all the fields required for color ramp definition (RedMin, GreenMin, BlueMin, RedMax, GreenMax, BlueMax) but no Min and Max field." ) );
683 if ( errorMessage && ! errors.isEmpty() )
685 *errorMessage = errors.join( QChar(
'\n' ) );
688 return errors.isEmpty();
698 for (
const Field &f : std::as_const( mFields ) )
700 if ( f.name == name )
718 QList<QgsRasterAttributeTable::Field> result;
719 for (
const Field &f : std::as_const( mFields ) )
721 if ( f.usage == fieldUsage )
723 result.push_back( f );
731 if ( row < 0 || row >= mData.count( ) || column < 0 || column >= mData[
row ].count( ) )
736 QVariant newVal =
value;
737 if ( column >= mFields.length() || !
value.canConvert( mFields.at( column ).type ) || ! newVal.convert( mFields.at( column ).type ) )
742 const QVariant oldVal = mData[
row ][ column ];
744 if ( newVal != oldVal )
746 mData[
row ][ column ] = newVal;
755 if ( row < 0 || row >= mData.count( ) || column < 0 || column >= mData[
row ].count( ) )
759 return mData[
row ][ column ];
764 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
777 double min { std::numeric_limits<double>::max() };
778 for (
int rowIdx = 0; rowIdx < mData.count(); ++rowIdx )
780 min = std::min( min,
value( rowIdx, fieldIdx ).toDouble( &ok ) );
783 return std::numeric_limits<double>::quiet_NaN();
787 if ( fieldIdx == -1 || ! ok )
789 return std::numeric_limits<double>::quiet_NaN();
799 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
812 double max { std::numeric_limits<double>::lowest() };
813 for (
int rowIdx = 0; rowIdx < mData.count(); ++rowIdx )
815 max = std::max( max,
value( rowIdx, fieldIdx ).toDouble( &ok ) );
818 return std::numeric_limits<double>::quiet_NaN();
822 if ( fieldIdx == -1 || ! ok )
824 return std::numeric_limits<double>::quiet_NaN();
836 return QVariantList();
839 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
844 for (
int rowIdx = 0; rowIdx < mData.count(); ++rowIdx )
847 if ( matchValue ==
value( rowIdx, colIdx ).toDouble( &ok ) && ok )
849 return mData.at( rowIdx );
857 for (
int rowIdx = 0; rowIdx < mData.count(); ++rowIdx )
860 if ( matchValue >=
value( rowIdx, minColIdx ).toDouble( &ok ) && ok )
862 if ( matchValue <
value( rowIdx, maxColIdx ).toDouble( &ok ) && ok )
864 return mData.at( rowIdx );
869 return QVariantList();
874 static const QStringList minValueNames { {
875 QStringLiteral(
"min" ),
876 QStringLiteral(
"min_value" ),
877 QStringLiteral(
"min value" ),
878 QStringLiteral(
"value min" ),
879 QStringLiteral(
"value_min" ),
882 static const QStringList maxValueNames { {
883 QStringLiteral(
"max" ),
884 QStringLiteral(
"max_value" ),
885 QStringLiteral(
"max value" ),
886 QStringLiteral(
"value max" ),
887 QStringLiteral(
"value_max" ),
890 const QString fieldLower { name.toLower() };
892 if (
type == QMetaType::Type::Double ||
type == QMetaType::Type::Int ||
type == QMetaType::Type::UInt ||
type == QMetaType::Type::LongLong ||
type == QMetaType::Type::ULongLong )
894 if ( minValueNames.contains( fieldLower ) )
898 else if ( maxValueNames.contains( fieldLower ) )
902 else if ( fieldLower == QLatin1String(
"value" ) )
906 else if ( fieldLower == QLatin1String(
"count" ) )
912 else if (
type != QMetaType::Type::Double )
914 if ( fieldLower.contains(
"red" ) || fieldLower == QLatin1String(
"r" ) )
916 if ( fieldLower.contains(
"min" ) )
920 else if ( fieldLower.contains(
"max" ) )
929 else if ( fieldLower.contains(
"green" ) || fieldLower == QLatin1String(
"g" ) )
931 if ( fieldLower.contains(
"min" ) )
935 else if ( fieldLower.contains(
"max" ) )
944 else if ( fieldLower.contains(
"blue" ) || fieldLower == QLatin1String(
"b" ) )
946 if ( fieldLower.contains(
"min" ) )
950 else if ( fieldLower.contains(
"max" ) )
959 else if ( fieldLower.contains(
"alpha" ) || fieldLower == QLatin1String(
"a" ) )
961 if ( fieldLower.contains(
"min" ) )
965 else if ( fieldLower.contains(
"max" ) )
978 if (
type == QMetaType::Type::QString )
1000 return tr(
"Green" );
1002 return tr(
"Blue" );
1004 return tr(
"Alpha" );
1006 return tr(
"Red Minimum" );
1008 return tr(
"Green Minimum" );
1010 return tr(
"Blue Minimum" );
1012 return tr(
"Alpha Minimum" );
1014 return tr(
"Red Maximum" );
1016 return tr(
"Green Maximum" );
1018 return tr(
"Blue Maximum" );
1020 return tr(
"Alpha Maximum" );
1022 return tr(
"Generic" );
1024 return tr(
"Name" );
1026 return tr(
"Pixel Count" );
1028 return tr(
"Maximum Count" );
1030 return tr(
"Value" );
1032 return tr(
"Minimum Value" );
1034 return tr(
"Maximum Value" );
1041 static const QList<Qgis::RasterAttributeTableFieldUsage> valueColorUsages {{
1058 return valueColorUsages;
1090 rat->
appendRow( QVariantList() << klass.value << klass.label << 0 << 0 << 0 << 255 );
1091 rat->
setColor( rat->
data().length() - 1, klass.color );
1096 *bandNumber = palettedRenderer->inputBand();
1107 switch ( shaderFunction->colorRampType() )
1123 const QList<QgsColorRampShader::ColorRampItem> rampItems { shaderFunction->colorRampItemList() };
1124 if ( rampItems.size() > 1 )
1126 QColor color1 { rampItems.at( 0 ).color };
1127 QString label1 { rampItems.at( 0 ).label };
1128 QVariant value1( rampItems.at( 0 ).value );
1129 const int rampItemSize = rampItems.size();
1130 for (
int i = 1; i < rampItemSize; ++i )
1133 rat->
appendRow( QVariantList() << value1 << rampItem.value << QStringLiteral(
"%1 - %2" ).arg( label1, rampItem.label ) << 0 << 0 << 0 << 255 << 0 << 0 << 0 << 255 );
1134 rat->
setRamp( rat->
data().length() - 1, color1, rampItem.color );
1135 label1 = rampItem.label;
1136 value1 = rampItem.value;
1137 color1 = rampItem.color;
1152 const QList<QgsColorRampShader::ColorRampItem> rampItems { shaderFunction->colorRampItemList() };
1153 if ( rampItems.size( ) > 1 )
1155 QColor color1 { rampItems.at( 0 ).color };
1156 QString label1 { rampItems.at( 0 ).label };
1157 QVariant value1( rampItems.at( 0 ).value );
1158 const int rampItemSize = rampItems.size();
1159 for (
int i = 1; i < rampItemSize; ++i )
1162 rat->
appendRow( QVariantList() << value1 << rampItem.value << QStringLiteral(
"%1 - %2" ).arg( label1, rampItem.label ) << 0 << 0 << 0 << 255 << 0 << 0 << 0 << 255 );
1163 rat->
setRamp( rat->
data().length() - 1, color1, rampItem.color );
1164 label1 = rampItem.label;
1165 value1 = rampItem.value;
1166 color1 = rampItem.color;
1180 const QList<QgsColorRampShader::ColorRampItem> rampItems { shaderFunction->colorRampItemList() };
1183 rat->
appendRow( QVariantList() << rampItem.value << rampItem.label << 0 << 0 << 0 << 255 );
1184 rat->
setColor( rat->
data().length() - 1, rampItem.color );
1192 *bandNumber = pseudoColorRenderer->inputBand();
1215 std::call_once( usageInformationLoaderFlag, [ ]
1217 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Generic, { tr(
"General Purpose Field" ),
false,
false,
false,
false,
true,
true, QList<QMetaType::Type>() << QMetaType::Type::QString << QMetaType::Type::Int << QMetaType::Type::LongLong << QMetaType::Type::Double } );
1219 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Name, { tr(
"Class Name" ),
false,
false,
false,
false,
true,
true, QList<QMetaType::Type>() << QMetaType::Type::QString } );
1220 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::MinMax, { tr(
"Class Value (min=max)" ),
true,
true,
false,
false,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int << QMetaType::Type::LongLong << QMetaType::Type::Double } );
1221 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Min, { tr(
"Class Minimum Value" ),
true,
true,
false,
false,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int << QMetaType::Type::LongLong << QMetaType::Type::Double } );
1222 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Max, { tr(
"Class Maximum Value" ),
true,
true,
false,
false,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int << QMetaType::Type::LongLong << QMetaType::Type::Double } );
1223 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Red, { tr(
"Red Color Value (0-255)" ),
true,
false,
true,
false,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1224 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Green, { tr(
"Green Color Value (0-255)" ),
true,
false,
true,
false,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1225 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Blue, { tr(
"Blue Color Value (0-255)" ),
true,
false,
true,
false,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1226 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Alpha, { tr(
"Alpha Color Value (0-255)" ),
true,
false,
true,
false,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1227 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::RedMin, { tr(
"Red Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1228 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::GreenMin, { tr(
"Green Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1229 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::BlueMin, { tr(
"Blue Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1230 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::AlphaMin, { tr(
"Alpha Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1231 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::RedMax, { tr(
"Red Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1232 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::GreenMax, { tr(
"Green Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1233 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::BlueMax, { tr(
"Blue Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1234 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::AlphaMax, { tr(
"Alpha Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1236 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::MaxCount, { tr(
"Maximum GFU value(equals to GFU_AlphaMax+1 currently)" ),
true,
false,
false,
true,
false,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1238 return QgsRasterAttributeTable::sUsageInformation;
1241void QgsRasterAttributeTable::setType()
1243 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1249QHash<int, QgsRasterAttributeTable::UsageInformation> QgsRasterAttributeTable::usageInformationInt()
1251 QHash<int, QgsRasterAttributeTable::UsageInformation> usageInfoInt;
1253 for (
auto it = usageInfo.cbegin(); it != usageInfo.cend(); ++it )
1255 usageInfoInt.insert(
static_cast<int>( it.key() ), it.value() );
1257 return usageInfoInt;
1268 QList<QgsRasterAttributeTable::MinMaxClass> classes;
1271 QgsDebugError(
"minMaxClasses was called on an invalid RAT" );
1275 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1279 QgsDebugError(
"minMaxClasses was called on a ramp raster" );
1285 Q_ASSERT( minMaxIndex >= 0 );
1287 int classificationIndex = classificationColumn;
1288 if ( classificationIndex >= 0 && classificationIndex < mFields.count( ) )
1290 const Field classificationField { mFields.at( classificationIndex ) };
1293 QgsDebugError(
"minMaxClasses was called with a classification column which is not suitable for classification" );
1297 else if ( classificationIndex == -1 )
1310 classificationIndex = minMaxIndex;
1313 else if ( classificationIndex >= mFields.count( ) )
1315 QgsDebugError(
"minMaxClasses was called with a classification column out of range" );
1319 if ( classificationIndex >= 0 )
1323 for (
const QVariantList &
row : std::as_const( mData ) )
1325 const QString label {
row.at( classificationIndex ).toString() };
1327 const double value {
row.at( minMaxIndex ).toDouble( &ok ) };
1331 QgsDebugError(
"minMaxClasses could not convert a MinMax value to double" );
1334 if ( labels.contains( label ) )
1336 classes[ labels.indexOf( label ) ].minMaxValues.push_back(
value );
1340 labels.push_back( label );
1341 classes.push_back( { label, {
value },
color( rowIdx ) } );
1352 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1355 const bool isRange { minIdx >= 0 && maxIdx >= 0 };
1357 int labelIdx { labelColumn };
1358 if ( labelColumn < 0 || labelColumn >=
fields().count( ) ||
1364 if ( ! mData.isEmpty() && ( minIdx >= 0 && maxIdx >= 0 ) )
1372 const double range { max - min };
1377 if ( ! isnan( min ) && ! isnan( max ) )
1379 const QList<QVariantList> dataCopy(
orderedRows() );
1382 for (
const Field &f : std::as_const( mFields ) )
1386 for (
const QVariantList &r : std::as_const( dataCopy ) )
1393 if ( hasColorOrRamp )
1400 auto labelFromField = [ & ](
int rowIdx ) -> QString
1404 return QStringLiteral(
"%L1 - %L2" ).arg( orderedRat.
value( rowIdx, minIdx ).toDouble() ).arg( orderedRat.
value( rowIdx, maxIdx ).toDouble() );
1406 const QVariant val( orderedRat.
value( rowIdx, labelIdx ) );
1409 switch ( val.userType() )
1411 case QMetaType::Type::QChar:
1412 return QString( val.toChar() );
1413 case QMetaType::Type::Int:
1414 res = QLocale().toString( val.toInt( &ok ) );
1416 case QMetaType::Type::LongLong:
1417 res = QLocale().toString( val.toLongLong( &ok ) );
1419 case QMetaType::Type::UInt:
1420 res = QLocale().toString( val.toUInt( &ok ) );
1422 case QMetaType::Type::ULongLong:
1423 res = QLocale().toString( val.toULongLong( &ok ) );
1425 case QMetaType::Type::Double:
1426 res = QLocale().toString( val.toDouble( &ok ),
'g' );
1428 case QMetaType::Type::QString:
1430 return val.toString( );
1432 return ok ? res : val.toString();
1438 if ( orderedRat.
hasColor() && isRange )
1440 labels.push_back( labelFromField( 0 ) );
1442 for (
int rowIdx = 1; rowIdx < orderedRat.
data().count(); ++rowIdx )
1444 const double offset { ( orderedRat.
value( rowIdx, minIdx ).toDouble( ) - min ) / range };
1445 const QColor
color { orderedRat.
color( rowIdx - 1 ) };
1447 labels.push_back( labelFromField( rowIdx ) );
1456 else if ( orderedRat.
hasRamp() && isRange )
1458 double prevOffset { 0 };
1459 labels.push_back( labelFromField( 0 ) );
1460 for (
int rowIdx = 1; rowIdx < orderedRat.
data().count(); ++rowIdx )
1462 labels.push_back( labelFromField( rowIdx ) );
1463 const int prevRowIdx { rowIdx - 1 };
1464 const double offset { ( ( orderedRat.
value( rowIdx, minIdx ).toDouble( ) + orderedRat.
value( prevRowIdx, maxIdx ).toDouble( ) ) / 2.0 - min ) / range };
1470 if ( currentRamp.color1() != previousRamp.color2() &&
qgsDoubleNear( offset, prevOffset, 1e-6 ) )
1472 stops.append(
QgsGradientStop( offset + std::numeric_limits<double>::epsilon(), currentRamp.color1() ) );
1474 prevOffset = offset;
1482 labels.push_back( labelFromField( 0 ) );
1484 for (
int rowIdx = 1; rowIdx < orderedRat.
data().count(); ++rowIdx )
1486 const int prevRowIdx { rowIdx - 1 };
1487 const double offset { ( ( orderedRat.
value( rowIdx, minIdx ).toDouble( ) + orderedRat.
value( prevRowIdx, maxIdx ).toDouble( ) ) / 2.0 - min ) / range };
1489 labels.push_back( labelFromField( rowIdx ) );
1511 std::unique_ptr<QgsRasterRenderer> renderer;
1515 std::unique_ptr<QgsColorRamp>
ramp;
1521 if ( classes.isEmpty() )
1524 renderer = std::make_unique<QgsPalettedRasterRenderer>( provider,
1530 std::unique_ptr<QgsSingleBandPseudoColorRenderer> pseudoColorRenderer = std::make_unique<QgsSingleBandPseudoColorRenderer>( provider, bandNumber );
1534 int labelColumn { classificationColumn };
1535 if ( labelColumn < 0 )
1537 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1539 if ( labelColumn < 0 )
1545 pseudoColorRenderer->setClassificationMin(
minimumValue() );
1546 pseudoColorRenderer->setClassificationMax(
maximumValue() );
1549 if ( pseudoColorRenderer->shader() )
1551 pseudoColorRenderer->shader()->setMaximumValue(
maximumValue() );
1552 pseudoColorRenderer->shader()->setMinimumValue(
minimumValue() );
1558 const bool labelsAreUsable {
ramp->
count() > 2 && labels.count() ==
ramp->
count() - 1 };
1560 if ( labelsAreUsable )
1562 QList<QgsColorRampShader::ColorRampItem> newItemList;
1565 for (
const QString &label : std::as_const( labels ) )
1573 newItemList.push_back( item );
1578 newItemList.push_back( item );
1579 shaderFunction->setColorRampItemList( newItemList );
1583 renderer.reset( pseudoColorRenderer.release() );
1586 return renderer.release();
1591 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1594 const bool isRange { minIdx >= 0 && maxIdx >= 0 };
1595 QList<QVariantList> dataCopy( mData );
1599 std::sort( dataCopy.begin(), dataCopy.end(), [ & ](
const QVariantList & first,
const QVariantList & second ) ->
bool
1601 return ( first.at( maxIdx ).toDouble() + first.at( minIdx ).toDouble() ) < ( second.at( maxIdx ).toDouble() + second.at( minIdx ).toDouble() );
1607 if ( minMaxIdx < 0 )
1613 std::sort( dataCopy.begin(), dataCopy.end(), [ & ](
const QVariantList & first,
const QVariantList & second ) ->
bool
1615 return first.at( minMaxIdx ).toDouble() < second.at( minMaxIdx ).toDouble();
@ Exact
Assigns the color of the exact matching value in the color ramp item list.
@ Linear
Interpolates the color between two class breaks linearly.
@ Discrete
Assigns the color of the higher class for every pixel between two class breaks.
RasterAttributeTableType
The RasterAttributeTableType enum represents the type of RAT.
@ Continuous
Uses breaks from color palette.
RasterAttributeTableFieldUsage
The RasterAttributeTableFieldUsage enum represents the usage of a Raster Attribute Table field.
@ RedMax
Field usage RedMax.
@ PixelCount
Field usage PixelCount.
@ AlphaMax
Field usage AlphaMax.
@ BlueMin
Field usage BlueMin.
@ Alpha
Field usage Alpha.
@ Generic
Field usage Generic.
@ GreenMax
Field usage GreenMax.
@ RedMin
Field usage RedMin.
@ MinMax
Field usage MinMax.
@ BlueMax
Field usage BlueMax.
@ AlphaMin
Field usage AlphaMin.
@ Green
Field usage Green.
@ MaxCount
Not used by QGIS: GDAL Maximum GFU value (equals to GFU_AlphaMax+1 currently)
@ GreenMin
Field usage GreenMin.
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
This class represents a coordinate reference system (CRS).
Contains information about the context in which a coordinate transform is executed.
Wrapper for iterator of features from vector data provider or vector layer.
This class wraps a request for features to a vector layer (or directly its vector data provider).
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
int attributeCount() const
Returns the number of attributes attached to the feature.
Encapsulate a field in an attribute table or data source.
Container of fields for a vector layer.
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
static QString ensureFileNameHasExtension(const QString &fileName, const QStringList &extensions)
Ensures that a fileName ends with an extension from the provided list of extensions.
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
void setColor1(const QColor &color)
Sets the gradient start color.
void setColor2(const QColor &color)
Sets the gradient end color.
int count() const override
Returns number of defined colors, or -1 if undefined.
QColor color(double value) const override
Returns the color corresponding to a specified value.
void setStops(const QgsGradientStopsList &stops)
Sets the list of intermediate gradient stops for the ramp.
QColor color1() const
Returns the gradient start color.
QgsGradientStopsList stops() const
Returns the list of intermediate gradient stops for the ramp.
QgsGradientColorRamp * clone() const override
Creates a clone of the color ramp.
void setDiscrete(bool discrete)
Sets whether the gradient should use discrete interpolation, rather than smoothly interpolating betwe...
QColor color2() const
Returns the gradient end color.
Represents a color stop within a QgsGradientColorRamp color ramp.
Renderer for paletted raster images.
static QgsPalettedRasterRenderer::MultiValueClassData rasterAttributeTableToClassData(const QgsRasterAttributeTable *attributeTable, int classificationColumn=-1, QgsColorRamp *ramp=nullptr)
Reads and returns classes from the Raster Attribute Table attributeTable, optionally classifying the ...
QList< QgsPalettedRasterRenderer::Class > ClassData
Map of value to class properties.
QList< QgsPalettedRasterRenderer::MultiValueClass > MultiValueClassData
Map of multi value to class properties.
Totally random color ramp.
The Field class represents a Raster Attribute Table field, including its name, usage and type.
Qgis::RasterAttributeTableFieldUsage usage
bool isRamp() const
Returns true if the field carries a color ramp component information (RedMin/RedMax,...
bool isColor() const
Returns true if the field carries a color component (Red, Green, Blue and optionally Alpha) informati...
The QgsRasterAttributeTable class represents a Raster Attribute Table (RAT).
const QgsRasterAttributeTable::Field fieldByName(const QString name, bool *ok=nullptr) const
Returns a field by name or a default constructed field with empty name if the field is not found.
bool isDirty() const
Returns true if the Raster Attribute Table was modified from its last reading from the storage.
bool setColor(const int row, const QColor &color)
Sets the color for the row at rowIndex to color.
QList< QgsRasterAttributeTable::MinMaxClass > minMaxClasses(const int classificationColumn=-1) const
Returns the classes for a thematic Raster Attribute Table, classified by classificationColumn,...
QgsGradientColorRamp ramp(int row) const
Returns the gradient color ramp of the rat row or a default constructed gradient if row does not exis...
QgsRasterRenderer * createRenderer(QgsRasterDataProvider *provider, const int bandNumber, const int classificationColumn=-1)
Creates and returns a (possibly nullptr) raster renderer for the specified provider and bandNumber an...
bool readFromFile(const QString &path, QString *errorMessage=nullptr)
Reads the Raster Attribute Table from a DBF file specified by path, optionally reporting any error in...
QgsGradientColorRamp colorRamp(QStringList &labels, const int labelColumn=-1) const
Returns the color ramp for an athematic Raster Attribute Table setting the labels in labels,...
bool appendField(const QString &name, const Qgis::RasterAttributeTableFieldUsage usage, const QMetaType::Type type, QString *errorMessage=nullptr)
Creates a new field from name, usage and type and appends it to the fields, optionally reporting any ...
bool insertField(int position, const QgsRasterAttributeTable::Field &field, QString *errorMessage=nullptr)
Inserts a new field at position, optionally reporting any error in errorMessage, returns true on succ...
bool hasColor() const
Returns true if the Raster Attribute Table has color RGBA information.
bool setValue(const int row, const int column, const QVariant &value)
Sets the value for row and column.
static QList< Qgis::RasterAttributeTableFieldUsage > valueAndColorFieldUsages()
Returns the list of field usages for colors and values.
QList< QgsRasterAttributeTable::Field > fields() const
Returns the Raster Attribute Table fields.
static QgsRasterAttributeTable * createFromRaster(QgsRasterLayer *rasterLayer, int *bandNumber=nullptr)
Creates a new Raster Attribute Table from a raster layer, the renderer must be Paletted or SingleBand...
bool removeRow(int position=0, QString *errorMessage=nullptr)
Removes the row in the Raster Attribute Table at position, optionally reporting any error in errorMes...
bool appendRow(const QVariantList &data, QString *errorMessage=nullptr)
Appends a row of data to the RAT, optionally reporting any error in errorMessage, returns true on suc...
static QHash< Qgis::RasterAttributeTableFieldUsage, QgsRasterAttributeTable::UsageInformation > usageInformation()
Returns information about supported Raster Attribute Table usages.
Qgis::RasterAttributeTableType type() const
Returns the Raster Attribute Table type.
QList< Qgis::RasterAttributeTableFieldUsage > usages() const
Returns the list of field usages.
QVariantList row(const double matchValue) const
Returns a row of data for the given matchValue or and empty row if there is not match.
bool insertRow(int position, const QVariantList &rowData, QString *errorMessage=nullptr)
Inserts a row of rowData in the Raster Attribute Table at position, optionally reporting any error in...
bool writeToFile(const QString &path, QString *errorMessage=nullptr)
Writes the Raster Attribute Table to a DBF file specified by path, optionally reporting any error in ...
double minimumValue() const
Returns the minimum value of the MinMax (thematic) or Min (athematic) column, returns NaN on errors.
double maximumValue() const
Returns the maximum value of the MinMax (thematic) or Max (athematic) column, returns NaN on errors.
const QList< QgsRasterAttributeTable::Field > fieldsByUsage(const Qgis::RasterAttributeTableFieldUsage fieldUsage) const
Returns the list of fields matching fieldUsage.
void setDirty(bool isDirty)
Sets the Raster Attribute Table dirty state to isDirty;.
bool insertColor(int position, QString *errorMessage=nullptr)
Create RGBA fields and inserts them at position, optionally reporting any error in errorMessage,...
bool isValid(QString *errorMessage=nullptr) const
Returns true if the Raster Attribute Table is valid, optionally reporting validity checks results in ...
const QList< QList< QVariant > > data() const
Returns the Raster Attribute Table rows.
bool setRamp(const int row, const QColor &colorMin, const QColor &colorMax)
Sets the color ramp for the row at rowIndex to colorMin and colorMax.
PRIVATE QColor color(int row) const
Returns the color of the rat row or an invalid color if row does not exist or if there is no color de...
QList< QList< QVariant > > orderedRows() const
Returns the data rows ordered by the value column(s) in ascending order, if the attribute table type ...
static QString usageName(const Qgis::RasterAttributeTableFieldUsage fieldusage)
Returns the translated human readable name of fieldUsage.
bool hasRamp() const
Returns true if the Raster Attribute Table has ramp RGBA information.
QgsFeatureList qgisFeatures() const
Returns the Raster Attribute Table rows as a list of QgsFeature.
bool setFieldUsage(int fieldIndex, const Qgis::RasterAttributeTableFieldUsage usage)
Change the usage of the field at index fieldIndex to usage with checks for allowed types.
QString filePath() const
Returns the (possibly empty) path of the file-based RAT, the path is set when a RAT is read or writte...
bool insertRamp(int position, QString *errorMessage=nullptr)
Create RGBA minimum and maximum fields and inserts them at position, optionally reporting any error i...
QVariant value(const int row, const int column) const
Returns the value for row and column.
QgsFields qgisFields() const
Returns the Raster Attribute Table fields as QgsFields.
static Qgis::RasterAttributeTableFieldUsage guessFieldUsage(const QString &name, const QMetaType::Type type)
Try to determine the field usage from its name and type.
bool removeField(const QString &name, QString *errorMessage=nullptr)
Removes the field with name, optionally reporting any error in errorMessage, returns true on success.
Base class for raster data providers.
Represents a raster layer.
QgsRasterRenderer * renderer() const
Returns the raster's renderer.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
Raster renderer pipe that applies colors to a raster.
Interface for all raster shaders.
Raster renderer pipe for single band pseudocolor.
static QMetaType::Type variantTypeToMetaType(QVariant::Type variantType)
Converts a QVariant::Type to a QMetaType::Type.
static QVariant createNullVariant(QMetaType::Type metaType)
Helper method to properly create a null QVariant from a metaType Returns the created QVariant.
Options to pass to writeAsVectorFormat()
QString fileEncoding
Encoding to use.
QString driverName
OGR driver to use.
QStringList layerOptions
List of OGR layer creation options.
QgsVectorFileWriter::ActionOnExistingFile actionOnExistingFile
Action on existing file.
static QgsVectorFileWriter * create(const QString &fileName, const QgsFields &fields, Qgis::WkbType geometryType, const QgsCoordinateReferenceSystem &srs, const QgsCoordinateTransformContext &transformContext, const QgsVectorFileWriter::SaveVectorOptions &options, QgsFeatureSink::SinkFlags sinkFlags=QgsFeatureSink::SinkFlags(), QString *newFilename=nullptr, QString *newLayer=nullptr)
Create a new vector file writer.
@ CreateOrOverwriteFile
Create or overwrite file.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QList< QgsGradientStop > QgsGradientStopsList
List of gradient stops.
QList< QgsFeature > QgsFeatureList
#define QgsDebugError(str)
Setting options for creating vector data providers.
Properties of a single value class.