24#include "qgsogrprovider.h"
35std::once_flag usageInformationLoaderFlag;
36QHash<Qgis::RasterAttributeTableFieldUsage, QgsRasterAttributeTable::UsageInformation> QgsRasterAttributeTable::sUsageInformation;
48 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
59 for (
int idx = 0; idx < mFields.count(); ++idx )
61 const Field f { mFields.at( idx ) };
92 for (
Field &f : mFields )
130 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
137 QList<Qgis::RasterAttributeTableFieldUsage>
usages;
140 usages.push_back( field.usage );
146QList<int> QgsRasterAttributeTable::intUsages( )
const
151 usages.push_back(
static_cast<int>( field.usage ) );
159 QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
166 const QVariantList rowData = mData.at(
row );
185 QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
186 const QVariantList rowData = mData.at(
row );
223 for (
const QVariantList &
row : std::as_const( mData ) )
226 for (
const auto &cell : std::as_const(
row ) )
228 attributes.append( cell );
232 features.append( feature );
250 const int realPos { std::clamp( position, 0,
static_cast<int>( mFields.count() ) ) };
252 if ( field.
name.isEmpty() )
256 *errorMessage = tr(
"Field name must not be empty." );
269 *errorMessage = tr(
"A field with name '%1' already exists." ).arg( field.
name );
275 static const QList<Qgis::RasterAttributeTableFieldUsage> uniqueUsages {{
299 *errorMessage = tr(
"A field with unique usage '%1' already exists." ).arg(
usageName( field.
usage ) );
304 mFields.insert( realPos, field );
306 for (
auto it = mData.begin(); it != mData.end(); ++it )
310 switch ( field.
type )
312 case QMetaType::Type::QChar:
313 case QMetaType::Type::Int:
314 case QMetaType::Type::UInt:
315 case QMetaType::Type::LongLong:
316 case QMetaType::Type::ULongLong:
317 case QMetaType::Type::Double:
321 defaultValue = QString();
323 it->insert( realPos, defaultValue );
355 int idx { position };
369 if ( fieldIndex < 0 || fieldIndex >=
fields().count( ) )
380 mFields[ fieldIndex ].
usage = usage;
392 *errorMessage = tr(
"A color ramp can only be added to an athematic attribute table." );
396 int idx { position };
410 return insertField( mFields.count(), name, usage,
type, errorMessage );
420 return insertField( mFields.count(), field, errorMessage );
425 const auto toRemove { std::find_if( mFields.begin(), mFields.end(), [ &name ](
Field & f ) ->
bool {
426 return f.name == name;
429 if ( toRemove != mFields.end() )
431 const int idx {
static_cast<int>( std::distance( mFields.begin(), toRemove ) ) };
432 mFields.erase( toRemove );
433 for (
auto it = mData.begin(); it != mData.end(); ++it )
444 *errorMessage = tr(
"A field with name '%1' was not found." ).arg( name );
452 const int realPos { std::clamp( position, 0,
static_cast<int>( mData.count() ) ) };
454 if ( rowData.size() != mFields.size() )
458 *errorMessage = tr(
"Row element count differs from field count (%1)." ).arg( mFields.size() );
463 QVariantList dataValid;
465 for (
int idx = 0; idx < mFields.count(); ++idx )
467 QVariant cell( rowData[ idx ] );
468 if ( ! cell.canConvert( mFields.at( idx ).type ) || ! cell.convert( mFields.at( idx ).type ) )
472 *errorMessage = tr(
"Row data at column %1 cannot be converted to field type (%2)." ).arg( idx ).arg( QVariant::typeToName( mFields.at( idx ).type ) );
478 dataValid.append( cell );
482 mData.insert( realPos, dataValid );
489 if ( position >= mData.count() || position < 0 || mData.isEmpty() )
493 *errorMessage = tr(
"Position is not valid or the table is empty." );
497 mData.removeAt( position );
511 options.
driverName = QStringLiteral(
"ESRI Shapefile" );
513 options.
layerOptions = QStringList() << QStringLiteral(
"SHPT=NULL" );
515 std::unique_ptr<QgsVectorFileWriter> writer;
518 QString cleanedPath { path };
519 if ( path.endsWith( QStringLiteral(
".dbf" ), Qt::CaseSensitivity::CaseInsensitive ) )
521 cleanedPath.chop( 4 );
528 cleanedPath.append( QStringLiteral(
".dbf" ) );
535 *errorMessage = tr(
"Error creating Raster Attribute Table table: %1." ).arg( writer->errorMessage() );
541 bool result { writer->addFeatures( features ) };
547 *errorMessage = tr(
"Error creating Raster Attribute Table table: could not add rows." );
552 result = writer->flushBuffer();
556 mFilePath = cleanedPath;
566 if ( ! ratDbfSource.isValid() )
570 *errorMessage = tr(
"Error reading Raster Attribute Table table from file: invalid layer." );
575 QList<Field> oldFields = mFields;
576 QList<QVariantList> oldData = mData;
581 bool hasValueField {
false };
582 for (
const QgsField &field : ratDbfSource.fields() )
585 QMetaType::Type
type { field.type() };
587 if (
type == QMetaType::Type::LongLong &&
593 type = QMetaType::Type::Int;
598 hasValueField =
true;
611 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 ) )
616 const int fieldCount {
static_cast<int>( ratDbfSource.fields().count( ) ) };
625 *errorMessage = tr(
"Error reading Raster Attribute Table table from file: number of fields and number of attributes do not match." );
645 if ( mFields.isEmpty() )
647 errors.push_back( tr(
"The attribute table has no fields." ) );
650 if ( mData.isEmpty() )
652 errors.push_back( tr(
"The attribute table has no rows." ) );
655 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
658 if ( ! isMinMax && ! isValueRamp )
660 errors.push_back( tr(
"The attribute table has no MinMax nor a pair of Min and Max fields." ) );
668 errors.push_back( tr(
"The attribute table has some but not all the fields required for color definition (Red, Green, Blue)." ) );
677 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)." ) );
679 else if ( ! isValueRamp )
681 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." ) );
685 if ( errorMessage && ! errors.isEmpty() )
687 *errorMessage = errors.join( QChar(
'\n' ) );
690 return errors.isEmpty();
700 for (
const Field &f : std::as_const( mFields ) )
702 if ( f.name == name )
720 QList<QgsRasterAttributeTable::Field> result;
721 for (
const Field &f : std::as_const( mFields ) )
723 if ( f.usage == fieldUsage )
725 result.push_back( f );
738 QVariant newVal =
value;
739 if ( column >= mFields.length() || !
value.canConvert( mFields.at( column ).type ) || ! newVal.convert( mFields.at( column ).type ) )
744 const QVariant oldVal = mData[
row ][ column ];
746 if ( newVal != oldVal )
748 mData[
row ][ column ] = newVal;
761 return mData[
row ][ column ];
766 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
779 double min { std::numeric_limits<double>::max() };
780 for (
int rowIdx = 0; rowIdx < mData.count(); ++rowIdx )
782 min = std::min( min,
value( rowIdx, fieldIdx ).toDouble( &ok ) );
785 return std::numeric_limits<double>::quiet_NaN();
789 if ( fieldIdx == -1 || ! ok )
791 return std::numeric_limits<double>::quiet_NaN();
801 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
814 double max { std::numeric_limits<double>::lowest() };
815 for (
int rowIdx = 0; rowIdx < mData.count(); ++rowIdx )
817 max = std::max( max,
value( rowIdx, fieldIdx ).toDouble( &ok ) );
820 return std::numeric_limits<double>::quiet_NaN();
824 if ( fieldIdx == -1 || ! ok )
826 return std::numeric_limits<double>::quiet_NaN();
838 return QVariantList();
841 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
846 for (
int rowIdx = 0; rowIdx < mData.count(); ++rowIdx )
849 if ( matchValue ==
value( rowIdx, colIdx ).toDouble( &ok ) && ok )
851 return mData.at( rowIdx );
859 for (
int rowIdx = 0; rowIdx < mData.count(); ++rowIdx )
862 if ( matchValue >=
value( rowIdx, minColIdx ).toDouble( &ok ) && ok )
864 if ( matchValue <
value( rowIdx, maxColIdx ).toDouble( &ok ) && ok )
866 return mData.at( rowIdx );
871 return QVariantList();
876 static const QStringList minValueNames { {
877 QStringLiteral(
"min" ),
878 QStringLiteral(
"min_value" ),
879 QStringLiteral(
"min value" ),
880 QStringLiteral(
"value min" ),
881 QStringLiteral(
"value_min" ),
884 static const QStringList maxValueNames { {
885 QStringLiteral(
"max" ),
886 QStringLiteral(
"max_value" ),
887 QStringLiteral(
"max value" ),
888 QStringLiteral(
"value max" ),
889 QStringLiteral(
"value_max" ),
892 const QString fieldLower { name.toLower() };
894 if (
type == QMetaType::Type::Double ||
type == QMetaType::Type::Int ||
type == QMetaType::Type::UInt ||
type == QMetaType::Type::LongLong ||
type == QMetaType::Type::ULongLong )
896 if ( minValueNames.contains( fieldLower ) )
900 else if ( maxValueNames.contains( fieldLower ) )
904 else if ( fieldLower == QLatin1String(
"value" ) )
908 else if ( fieldLower == QLatin1String(
"count" ) )
914 else if (
type != QMetaType::Type::Double )
916 if ( fieldLower.contains(
"red" ) || fieldLower == QLatin1String(
"r" ) )
918 if ( fieldLower.contains(
"min" ) )
922 else if ( fieldLower.contains(
"max" ) )
931 else if ( fieldLower.contains(
"green" ) || fieldLower == QLatin1String(
"g" ) )
933 if ( fieldLower.contains(
"min" ) )
937 else if ( fieldLower.contains(
"max" ) )
946 else if ( fieldLower.contains(
"blue" ) || fieldLower == QLatin1String(
"b" ) )
948 if ( fieldLower.contains(
"min" ) )
952 else if ( fieldLower.contains(
"max" ) )
961 else if ( fieldLower.contains(
"alpha" ) || fieldLower == QLatin1String(
"a" ) )
963 if ( fieldLower.contains(
"min" ) )
967 else if ( fieldLower.contains(
"max" ) )
980 if (
type == QMetaType::Type::QString )
1002 return tr(
"Green" );
1004 return tr(
"Blue" );
1006 return tr(
"Alpha" );
1008 return tr(
"Red Minimum" );
1010 return tr(
"Green Minimum" );
1012 return tr(
"Blue Minimum" );
1014 return tr(
"Alpha Minimum" );
1016 return tr(
"Red Maximum" );
1018 return tr(
"Green Maximum" );
1020 return tr(
"Blue Maximum" );
1022 return tr(
"Alpha Maximum" );
1024 return tr(
"Generic" );
1026 return tr(
"Name" );
1028 return tr(
"Pixel Count" );
1030 return tr(
"Maximum Count" );
1032 return tr(
"Value" );
1034 return tr(
"Minimum Value" );
1036 return tr(
"Maximum Value" );
1043 static const QList<Qgis::RasterAttributeTableFieldUsage> valueColorUsages {{
1060 return valueColorUsages;
1092 rat->
appendRow( QVariantList() << klass.value << klass.label << 0 << 0 << 0 << 255 );
1093 rat->
setColor( rat->
data().length() - 1, klass.color );
1098 *bandNumber = palettedRenderer->inputBand();
1109 switch ( shaderFunction->colorRampType() )
1125 const QList<QgsColorRampShader::ColorRampItem> rampItems { shaderFunction->colorRampItemList() };
1126 if ( rampItems.size() > 1 )
1128 QColor color1 { rampItems.at( 0 ).color };
1129 QString label1 { rampItems.at( 0 ).label };
1130 QVariant value1( rampItems.at( 0 ).value );
1131 const int rampItemSize = rampItems.size();
1132 for (
int i = 1; i < rampItemSize; ++i )
1135 rat->
appendRow( QVariantList() << value1 << rampItem.
value << QStringLiteral(
"%1 - %2" ).arg( label1, rampItem.
label ) << 0 << 0 << 0 << 255 << 0 << 0 << 0 << 255 );
1137 label1 = rampItem.
label;
1138 value1 = rampItem.
value;
1139 color1 = rampItem.
color;
1154 const QList<QgsColorRampShader::ColorRampItem> rampItems { shaderFunction->colorRampItemList() };
1155 if ( rampItems.size( ) > 1 )
1157 QColor color1 { rampItems.at( 0 ).color };
1158 QString label1 { rampItems.at( 0 ).label };
1159 QVariant value1( rampItems.at( 0 ).value );
1160 const int rampItemSize = rampItems.size();
1161 for (
int i = 1; i < rampItemSize; ++i )
1164 rat->
appendRow( QVariantList() << value1 << rampItem.
value << QStringLiteral(
"%1 - %2" ).arg( label1, rampItem.
label ) << 0 << 0 << 0 << 255 << 0 << 0 << 0 << 255 );
1166 label1 = rampItem.
label;
1167 value1 = rampItem.
value;
1168 color1 = rampItem.
color;
1182 const QList<QgsColorRampShader::ColorRampItem> rampItems { shaderFunction->colorRampItemList() };
1185 rat->
appendRow( QVariantList() << rampItem.value << rampItem.label << 0 << 0 << 0 << 255 );
1186 rat->
setColor( rat->
data().length() - 1, rampItem.color );
1194 *bandNumber = pseudoColorRenderer->inputBand();
1217 std::call_once( usageInformationLoaderFlag, [ ]
1219 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 } );
1221 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Name, { tr(
"Class Name" ),
false,
false,
false,
false,
true,
true, QList<QMetaType::Type>() << QMetaType::Type::QString } );
1222 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 } );
1223 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 } );
1224 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 } );
1225 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Red, { tr(
"Red Color Value (0-255)" ),
true,
false,
true,
false,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1226 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Green, { tr(
"Green Color Value (0-255)" ),
true,
false,
true,
false,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1227 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Blue, { tr(
"Blue Color Value (0-255)" ),
true,
false,
true,
false,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1228 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Alpha, { tr(
"Alpha Color Value (0-255)" ),
true,
false,
true,
false,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1229 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 } );
1230 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 } );
1231 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 } );
1232 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 } );
1233 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 } );
1234 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 } );
1235 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 } );
1236 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 } );
1238 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 } );
1240 return QgsRasterAttributeTable::sUsageInformation;
1243void QgsRasterAttributeTable::setType()
1245 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1251QHash<int, QgsRasterAttributeTable::UsageInformation> QgsRasterAttributeTable::usageInformationInt()
1253 QHash<int, QgsRasterAttributeTable::UsageInformation> usageInfoInt;
1255 for (
auto it = usageInfo.cbegin(); it != usageInfo.cend(); ++it )
1257 usageInfoInt.insert(
static_cast<int>( it.key() ), it.value() );
1259 return usageInfoInt;
1270 QList<QgsRasterAttributeTable::MinMaxClass> classes;
1273 QgsDebugError(
"minMaxClasses was called on an invalid RAT" );
1277 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1281 QgsDebugError(
"minMaxClasses was called on a ramp raster" );
1287 Q_ASSERT( minMaxIndex >= 0 );
1289 int classificationIndex = classificationColumn;
1290 if ( classificationIndex >= 0 && classificationIndex < mFields.count( ) )
1292 const Field classificationField { mFields.at( classificationIndex ) };
1295 QgsDebugError(
"minMaxClasses was called with a classification column which is not suitable for classification" );
1299 else if ( classificationIndex == -1 )
1312 classificationIndex = minMaxIndex;
1315 else if ( classificationIndex >= mFields.count( ) )
1317 QgsDebugError(
"minMaxClasses was called with a classification column out of range" );
1321 if ( classificationIndex >= 0 )
1325 for (
const QVariantList &
row : std::as_const( mData ) )
1327 const QString label {
row.at( classificationIndex ).toString() };
1329 const double value {
row.at( minMaxIndex ).toDouble( &ok ) };
1333 QgsDebugError(
"minMaxClasses could not convert a MinMax value to double" );
1336 if ( labels.contains( label ) )
1338 classes[ labels.indexOf( label ) ].minMaxValues.push_back(
value );
1342 labels.push_back( label );
1343 classes.push_back( { label, {
value },
color( rowIdx ) } );
1354 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1357 const bool isRange { minIdx >= 0 && maxIdx >= 0 };
1359 int labelIdx { labelColumn };
1360 if ( labelColumn < 0 || labelColumn >=
fields().count( ) ||
1366 if ( ! mData.isEmpty() && ( minIdx >= 0 && maxIdx >= 0 ) )
1374 const double range { max - min };
1379 if ( ! std::isnan( min ) && ! std::isnan( max ) )
1381 const QList<QVariantList> dataCopy(
orderedRows() );
1384 for (
const Field &f : std::as_const( mFields ) )
1388 for (
const QVariantList &r : std::as_const( dataCopy ) )
1393 QColor lastColor {
ramp.color1() };
1395 if ( hasColorOrRamp )
1402 auto labelFromField = [ & ](
int rowIdx ) -> QString
1406 return QStringLiteral(
"%L1 - %L2" ).arg( orderedRat.
value( rowIdx, minIdx ).toDouble() ).arg( orderedRat.
value( rowIdx, maxIdx ).toDouble() );
1408 const QVariant val( orderedRat.
value( rowIdx, labelIdx ) );
1411 switch ( val.userType() )
1413 case QMetaType::Type::QChar:
1414 return QString( val.toChar() );
1415 case QMetaType::Type::Int:
1416 res = QLocale().toString( val.toInt( &ok ) );
1418 case QMetaType::Type::LongLong:
1419 res = QLocale().toString( val.toLongLong( &ok ) );
1421 case QMetaType::Type::UInt:
1422 res = QLocale().toString( val.toUInt( &ok ) );
1424 case QMetaType::Type::ULongLong:
1425 res = QLocale().toString( val.toULongLong( &ok ) );
1427 case QMetaType::Type::Double:
1428 res = QLocale().toString( val.toDouble( &ok ),
'g' );
1430 case QMetaType::Type::QString:
1432 return val.toString( );
1434 return ok ? res : val.toString();
1440 if ( orderedRat.
hasColor() && isRange )
1442 labels.push_back( labelFromField( 0 ) );
1444 for (
int rowIdx = 1; rowIdx < orderedRat.
data().count(); ++rowIdx )
1446 const double offset { ( orderedRat.
value( rowIdx, minIdx ).toDouble( ) - min ) / range };
1447 const QColor
color { orderedRat.
color( rowIdx - 1 ) };
1449 labels.push_back( labelFromField( rowIdx ) );
1458 else if ( orderedRat.
hasRamp() && isRange )
1460 double prevOffset { 0 };
1461 labels.push_back( labelFromField( 0 ) );
1462 for (
int rowIdx = 1; rowIdx < orderedRat.
data().count(); ++rowIdx )
1464 labels.push_back( labelFromField( rowIdx ) );
1465 const int prevRowIdx { rowIdx - 1 };
1466 const double offset { ( ( orderedRat.
value( rowIdx, minIdx ).toDouble( ) + orderedRat.
value( prevRowIdx, maxIdx ).toDouble( ) ) / 2.0 - min ) / range };
1474 stops.append(
QgsGradientStop( offset + std::numeric_limits<double>::epsilon(), currentRamp.
color1() ) );
1476 prevOffset = offset;
1484 labels.push_back( labelFromField( 0 ) );
1486 for (
int rowIdx = 1; rowIdx < orderedRat.
data().count(); ++rowIdx )
1488 const int prevRowIdx { rowIdx - 1 };
1489 const double offset { ( ( orderedRat.
value( rowIdx, minIdx ).toDouble( ) + orderedRat.
value( prevRowIdx, maxIdx ).toDouble( ) ) / 2.0 - min ) / range };
1491 labels.push_back( labelFromField( rowIdx ) );
1498 ramp.setStops( stops );
1513 std::unique_ptr<QgsRasterRenderer> renderer;
1517 std::unique_ptr<QgsColorRamp>
ramp;
1520 ramp = std::make_unique<QgsRandomColorRamp>( );
1523 if ( classes.isEmpty() )
1526 renderer = std::make_unique<QgsPalettedRasterRenderer>( provider,
1532 auto pseudoColorRenderer = std::make_unique<QgsSingleBandPseudoColorRenderer>( provider, bandNumber );
1536 int labelColumn { classificationColumn };
1537 if ( labelColumn < 0 )
1539 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1541 if ( labelColumn < 0 )
1547 pseudoColorRenderer->setClassificationMin(
minimumValue() );
1548 pseudoColorRenderer->setClassificationMax(
maximumValue() );
1551 if ( pseudoColorRenderer->shader() )
1553 pseudoColorRenderer->shader()->setMaximumValue(
maximumValue() );
1554 pseudoColorRenderer->shader()->setMinimumValue(
minimumValue() );
1560 const bool labelsAreUsable {
ramp->count() > 2 && labels.count() ==
ramp->count() - 1 };
1562 if ( labelsAreUsable )
1564 QList<QgsColorRampShader::ColorRampItem> newItemList;
1567 for (
const QString &label : std::as_const( labels ) )
1569 if ( stopIdx >=
ramp->count() - 2 )
1575 newItemList.push_back( item );
1580 newItemList.push_back( item );
1581 shaderFunction->setColorRampItemList( newItemList );
1585 renderer = std::move( pseudoColorRenderer );
1588 return renderer.release();
1593 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1596 const bool isRange { minIdx >= 0 && maxIdx >= 0 };
1597 QList<QVariantList> dataCopy( mData );
1601 std::sort( dataCopy.begin(), dataCopy.end(), [ & ](
const QVariantList & first,
const QVariantList & second ) ->
bool
1603 return ( first.at( maxIdx ).toDouble() + first.at( minIdx ).toDouble() ) < ( second.at( maxIdx ).toDouble() + second.at( minIdx ).toDouble() );
1609 if ( minMaxIdx < 0 )
1615 std::sort( dataCopy.begin(), dataCopy.end(), [ & ](
const QVariantList & first,
const QVariantList & second ) ->
bool
1617 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.
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.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
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...
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
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 ...
QColor color1() const
Returns the gradient start color.
QgsGradientColorRamp * clone() const override
Creates a clone of the color ramp.
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.
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...
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 QgsVectorFileWriter::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.