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;
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() ) ) };
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 )
310 case QVariant::Type::Char:
311 case QVariant::Type::Int:
312 case QVariant::Type::UInt:
313 case QVariant::Type::LongLong:
314 case QVariant::Type::ULongLong:
315 case QVariant::Type::Double:
319 defaultValue = QString();
321 it->insert( realPos, defaultValue );
348 int idx { position };
362 if ( fieldIndex < 0 || fieldIndex >=
fields().count( ) )
373 mFields[ fieldIndex ].usage = usage;
385 *errorMessage = tr(
"A color ramp can only be added to an athematic attribute table." );
389 int idx { position };
403 return insertField( mFields.count(), name, usage,
type, errorMessage );
413 const auto toRemove { std::find_if( mFields.begin(), mFields.end(), [ &name ](
Field & f ) ->
bool {
414 return f.name == name;
417 if ( toRemove != mFields.end() )
419 const int idx {
static_cast<int>( std::distance( mFields.begin(), toRemove ) ) };
420 mFields.erase( toRemove );
421 for (
auto it = mData.begin(); it != mData.end(); ++it )
432 *errorMessage = tr(
"A field with name '%1' was not found." ).arg( name );
440 const int realPos { std::clamp( position, 0,
static_cast<int>( mData.count() ) ) };
442 if ( rowData.size() != mFields.size() )
446 *errorMessage = tr(
"Row element count differs from field count (%1)." ).arg( mFields.size() );
451 QVariantList dataValid;
453 for (
int idx = 0; idx < mFields.count(); ++idx )
455 QVariant cell( rowData[ idx ] );
456 if ( ! cell.canConvert( mFields.at( idx ).type ) || ! cell.convert( mFields.at( idx ).type ) )
460 *errorMessage = tr(
"Row data at column %1 cannot be converted to field type (%2)." ).arg( idx ).arg( QVariant::typeToName( mFields.at( idx ).type ) );
466 dataValid.append( cell );
470 mData.insert( realPos, dataValid );
477 if ( position >= mData.count() || position < 0 || mData.isEmpty() )
481 *errorMessage = tr(
"Position is not valid or the table is empty." );
485 mData.removeAt( position );
498 options.
actionOnExistingFile = QgsVectorFileWriter::ActionOnExistingFile::CreateOrOverwriteFile;
499 options.
driverName = QStringLiteral(
"ESRI Shapefile" );
501 options.
layerOptions = QStringList() << QStringLiteral(
"SHPT=NULL" );
503 std::unique_ptr<QgsVectorFileWriter> writer;
506 QString cleanedPath { path };
507 if ( path.endsWith( QStringLiteral(
".dbf" ), Qt::CaseSensitivity::CaseInsensitive ) )
509 cleanedPath.chop( 4 );
516 cleanedPath.append( QStringLiteral(
".dbf" ) );
519 if ( error != QgsVectorFileWriter::WriterError::NoError )
523 *errorMessage = tr(
"Error creating Raster Attribute Table table: %1." ).arg( writer->errorMessage() );
529 bool result { writer->addFeatures( features ) };
535 *errorMessage = tr(
"Error creating Raster Attribute Table table: could not add rows." );
540 result = writer->flushBuffer();
544 mFilePath = cleanedPath;
554 if ( ! ratDbfSource.isValid() )
558 *errorMessage = tr(
"Error reading Raster Attribute Table table from file: invalid layer." );
563 QList<Field> oldFields = mFields;
564 QList<QVariantList> oldData = mData;
569 bool hasValueField {
false };
575 if (
type == QVariant::Type::LongLong &&
581 type = QVariant::Int;
586 hasValueField =
true;
599 if ( ! hasValueField && mFields.count() > 1 && ( mFields.at( 0 ).type == QVariant::Int || mFields.at( 0 ).type == QVariant::Char || mFields.at( 0 ).type == QVariant::UInt || mFields.at( 0 ).type == QVariant::LongLong || mFields.at( 0 ).type == QVariant::ULongLong ) )
604 const int fieldCount {
static_cast<int>( ratDbfSource.fields().count( ) ) };
607 while ( fit.nextFeature( f ) )
613 *errorMessage = tr(
"Error reading Raster Attribute Table table from file: number of fields and number of attributes do not match." );
633 if ( mFields.isEmpty() )
635 errors.push_back( tr(
"The attribute table has no fields." ) );
638 if ( mData.isEmpty() )
640 errors.push_back( tr(
"The attribute table has no rows." ) );
643 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
646 if ( ! isMinMax && ! isValueRamp )
648 errors.push_back( tr(
"The attribute table has no MinMax nor a pair of Min and Max fields." ) );
656 errors.push_back( tr(
"The attribute table has some but not all the fields required for color definition (Red, Green, Blue)." ) );
665 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)." ) );
667 else if ( ! isValueRamp )
669 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." ) );
673 if ( errorMessage && ! errors.isEmpty() )
675 *errorMessage = errors.join( QChar(
'\n' ) );
678 return errors.isEmpty();
688 for (
const Field &f : std::as_const( mFields ) )
690 if ( f.name == name )
708 QList<QgsRasterAttributeTable::Field> result;
709 for (
const Field &f : std::as_const( mFields ) )
711 if ( f.usage == fieldUsage )
713 result.push_back( f );
721 if ( row < 0 || row >= mData.count( ) || column < 0 || column >= mData[
row ].count( ) )
726 QVariant newVal =
value;
727 if ( column >= mFields.length() || !
value.canConvert( mFields.at( column ).type ) || ! newVal.convert( mFields.at( column ).type ) )
732 const QVariant oldVal = mData[
row ][ column ];
734 if ( newVal != oldVal )
736 mData[
row ][ column ] = newVal;
745 if ( row < 0 || row >= mData.count( ) || column < 0 || column >= mData[
row ].count( ) )
749 return mData[
row ][ column ];
754 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
767 double min { std::numeric_limits<double>::max() };
768 for (
int rowIdx = 0; rowIdx < mData.count(); ++rowIdx )
770 min = std::min( min,
value( rowIdx, fieldIdx ).toDouble( &ok ) );
773 return std::numeric_limits<double>::quiet_NaN();
777 if ( fieldIdx == -1 || ! ok )
779 return std::numeric_limits<double>::quiet_NaN();
789 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
802 double max { std::numeric_limits<double>::lowest() };
803 for (
int rowIdx = 0; rowIdx < mData.count(); ++rowIdx )
805 max = std::max( max,
value( rowIdx, fieldIdx ).toDouble( &ok ) );
808 return std::numeric_limits<double>::quiet_NaN();
812 if ( fieldIdx == -1 || ! ok )
814 return std::numeric_limits<double>::quiet_NaN();
826 return QVariantList();
829 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
834 for (
int rowIdx = 0; rowIdx < mData.count(); ++rowIdx )
837 if ( matchValue ==
value( rowIdx, colIdx ).toDouble( &ok ) && ok )
839 return mData.at( rowIdx );
847 for (
int rowIdx = 0; rowIdx < mData.count(); ++rowIdx )
850 if ( matchValue >=
value( rowIdx, minColIdx ).toDouble( &ok ) && ok )
852 if ( matchValue <
value( rowIdx, maxColIdx ).toDouble( &ok ) && ok )
854 return mData.at( rowIdx );
859 return QVariantList();
864 static const QStringList minValueNames { {
865 QStringLiteral(
"min" ),
866 QStringLiteral(
"min_value" ),
867 QStringLiteral(
"min value" ),
868 QStringLiteral(
"value min" ),
869 QStringLiteral(
"value_min" ),
872 static const QStringList maxValueNames { {
873 QStringLiteral(
"max" ),
874 QStringLiteral(
"max_value" ),
875 QStringLiteral(
"max value" ),
876 QStringLiteral(
"value max" ),
877 QStringLiteral(
"value_max" ),
880 const QString fieldLower { name.toLower() };
882 if (
type == QVariant::Double ||
type == QVariant::Int ||
type == QVariant::UInt ||
type == QVariant::LongLong ||
type == QVariant::ULongLong )
884 if ( minValueNames.contains( fieldLower ) )
888 else if ( maxValueNames.contains( fieldLower ) )
892 else if ( fieldLower == QLatin1String(
"value" ) )
896 else if ( fieldLower == QLatin1String(
"count" ) )
902 else if (
type != QVariant::Double )
904 if ( fieldLower.contains(
"red" ) || fieldLower == QLatin1String(
"r" ) )
906 if ( fieldLower.contains(
"min" ) )
910 else if ( fieldLower.contains(
"max" ) )
919 else if ( fieldLower.contains(
"green" ) || fieldLower == QLatin1String(
"g" ) )
921 if ( fieldLower.contains(
"min" ) )
925 else if ( fieldLower.contains(
"max" ) )
934 else if ( fieldLower.contains(
"blue" ) || fieldLower == QLatin1String(
"b" ) )
936 if ( fieldLower.contains(
"min" ) )
940 else if ( fieldLower.contains(
"max" ) )
949 else if ( fieldLower.contains(
"alpha" ) || fieldLower == QLatin1String(
"a" ) )
951 if ( fieldLower.contains(
"min" ) )
955 else if ( fieldLower.contains(
"max" ) )
968 if (
type == QVariant::String )
985 return tr(
"Green" );
989 return tr(
"Alpha" );
991 return tr(
"Red Minimum" );
993 return tr(
"Green Minimum" );
995 return tr(
"Blue Minimum" );
997 return tr(
"Alpha Minimum" );
999 return tr(
"Red Maximum" );
1001 return tr(
"Green Maximum" );
1003 return tr(
"Blue Maximum" );
1005 return tr(
"Alpha Maximum" );
1007 return tr(
"Generic" );
1009 return tr(
"Name" );
1011 return tr(
"Pixel Count" );
1013 return tr(
"Maximum Count" );
1015 return tr(
"Value" );
1017 return tr(
"Minimum Value" );
1019 return tr(
"Maximum Value" );
1026 static const QList<Qgis::RasterAttributeTableFieldUsage> valueColorUsages {{
1043 return valueColorUsages;
1075 rat->
appendRow( QVariantList() << klass.value << klass.label << 0 << 0 << 0 << 255 );
1076 rat->
setColor( rat->
data().length() - 1, klass.color );
1081 *bandNumber = palettedRenderer->band();
1092 switch ( shaderFunction->colorRampType() )
1095 case QgsColorRampShader::Type::Interpolated:
1108 const QList<QgsColorRampShader::ColorRampItem> rampItems { shaderFunction->colorRampItemList() };
1109 if ( rampItems.count( ) > 1 )
1111 QColor color1 { rampItems.at( 0 ).color };
1112 QString label1 { rampItems.at( 0 ).label };
1113 QVariant value1( rampItems.at( 0 ).value );
1114 for (
int i = 1; i < rampItems.count( ); ++i )
1117 rat->
appendRow( QVariantList() << value1 << rampItem.value << QStringLiteral(
"%1 - %2" ).arg( label1, rampItem.label ) << 0 << 0 << 0 << 255 << 0 << 0 << 0 << 255 );
1118 rat->
setRamp( rat->
data().length() - 1, color1, rampItem.color );
1119 label1 = rampItem.label;
1120 value1 = rampItem.value;
1121 color1 = rampItem.color;
1127 case QgsColorRampShader::Type::Discrete:
1136 const QList<QgsColorRampShader::ColorRampItem> rampItems { shaderFunction->colorRampItemList() };
1137 if ( rampItems.count( ) > 1 )
1139 QColor color1 { rampItems.at( 0 ).color };
1140 QString label1 { rampItems.at( 0 ).label };
1141 QVariant value1( rampItems.at( 0 ).value );
1142 for (
int i = 1; i < rampItems.count( ); ++i )
1145 rat->
appendRow( QVariantList() << value1 << rampItem.value << QStringLiteral(
"%1 - %2" ).arg( label1, rampItem.label ) << 0 << 0 << 0 << 255 << 0 << 0 << 0 << 255 );
1146 rat->
setRamp( rat->
data().length() - 1, color1, rampItem.color );
1147 label1 = rampItem.label;
1148 value1 = rampItem.value;
1149 color1 = rampItem.color;
1155 case QgsColorRampShader::Type::Exact:
1163 const QList<QgsColorRampShader::ColorRampItem> rampItems { shaderFunction->colorRampItemList() };
1166 rat->
appendRow( QVariantList() << rampItem.value << rampItem.label << 0 << 0 << 0 << 255 );
1167 rat->
setColor( rat->
data().length() - 1, rampItem.color );
1175 *bandNumber = pseudoColorRenderer->band();
1198 std::call_once( usageInformationLoaderFlag, [ ]
1200 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Generic, { tr(
"General Purpose Field" ),
false,
false,
false,
false,
true,
true, QList<QVariant::Type>() << QVariant::String << QVariant::Int << QVariant::LongLong << QVariant::Double } );
1202 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Name, { tr(
"Class Name" ),
false,
false,
false,
false,
true,
true, QList<QVariant::Type>() << QVariant::String } );
1203 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::MinMax, { tr(
"Class Value (min=max)" ),
true,
true,
false,
false,
true,
false, QList<QVariant::Type>() << QVariant::Int << QVariant::LongLong << QVariant::Double } );
1204 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Min, { tr(
"Class Minimum Value" ),
true,
true,
false,
false,
true,
false, QList<QVariant::Type>() << QVariant::Int << QVariant::LongLong << QVariant::Double } );
1205 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Max, { tr(
"Class Maximum Value" ),
true,
true,
false,
false,
true,
false, QList<QVariant::Type>() << QVariant::Int << QVariant::LongLong << QVariant::Double } );
1206 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Red, { tr(
"Red Color Value (0-255)" ),
true,
false,
true,
false,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1207 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Green, { tr(
"Green Color Value (0-255)" ),
true,
false,
true,
false,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1208 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Blue, { tr(
"Blue Color Value (0-255)" ),
true,
false,
true,
false,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1209 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Alpha, { tr(
"Alpha Color Value (0-255)" ),
true,
false,
true,
false,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1210 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::RedMin, { tr(
"Red Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1211 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::GreenMin, { tr(
"Green Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1212 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::BlueMin, { tr(
"Blue Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1213 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::AlphaMin, { tr(
"Alpha Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1214 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::RedMax, { tr(
"Red Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1215 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::GreenMax, { tr(
"Green Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1216 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::BlueMax, { tr(
"Blue Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1217 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::AlphaMax, { tr(
"Alpha Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1219 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::MaxCount, { tr(
"Maximum GFU value(equals to GFU_AlphaMax+1 currently)" ),
true,
false,
false,
true,
false,
false, QList<QVariant::Type>() << QVariant::Int } );
1221 return QgsRasterAttributeTable::sUsageInformation;
1224void QgsRasterAttributeTable::setType()
1226 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1232QHash<int, QgsRasterAttributeTable::UsageInformation> QgsRasterAttributeTable::usageInformationInt()
1234 QHash<int, QgsRasterAttributeTable::UsageInformation> usageInfoInt;
1236 for (
auto it = usageInfo.cbegin(); it != usageInfo.cend(); ++it )
1238 usageInfoInt.insert(
static_cast<int>( it.key() ), it.value() );
1240 return usageInfoInt;
1251 QList<QgsRasterAttributeTable::MinMaxClass> classes;
1254 QgsDebugMsg(
"minMaxClasses was called on an invalid RAT" );
1258 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1262 QgsDebugMsg(
"minMaxClasses was called on a ramp raster" );
1268 Q_ASSERT( minMaxIndex >= 0 );
1270 int classificationIndex = classificationColumn;
1271 if ( classificationIndex >= 0 && classificationIndex < mFields.count( ) )
1273 const Field classificationField { mFields.at( classificationIndex ) };
1276 QgsDebugMsg(
"minMaxClasses was called with a classification column which is not suitable for classification" );
1280 else if ( classificationIndex == -1 )
1293 classificationIndex = minMaxIndex;
1296 else if ( classificationIndex >= mFields.count( ) )
1298 QgsDebugMsg(
"minMaxClasses was called with a classification column out of range" );
1302 if ( classificationIndex >= 0 )
1306 for (
const QVariantList &
row : std::as_const( mData ) )
1308 const QString label {
row.at( classificationIndex ).toString() };
1310 const double value {
row.at( minMaxIndex ).toDouble( &ok ) };
1314 QgsDebugMsg(
"minMaxClasses could not convert a MinMax value to double" );
1317 if ( labels.contains( label ) )
1319 classes[ labels.indexOf( label ) ].minMaxValues.push_back(
value );
1323 labels.push_back( label );
1324 classes.push_back( { label, {
value },
color( rowIdx ) } );
1335 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1338 const bool isRange { minIdx >= 0 && maxIdx >= 0 };
1340 int labelIdx { labelColumn };
1341 if ( labelColumn < 0 || labelColumn >=
fields().count( ) ||
1347 if ( ! mData.isEmpty() && ( minIdx >= 0 && maxIdx >= 0 ) )
1355 const double range { max - min };
1360 if ( ! isnan( min ) && ! isnan( max ) )
1362 const QList<QVariantList> dataCopy(
orderedRows() );
1365 for (
const Field &f : std::as_const( mFields ) )
1369 for (
const QVariantList &r : std::as_const( dataCopy ) )
1376 if ( hasColorOrRamp )
1383 auto labelFromField = [ & ](
int rowIdx ) -> QString
1387 return QStringLiteral(
"%L1 - %L2" ).arg( orderedRat.
value( rowIdx, minIdx ).toDouble() ).arg( orderedRat.
value( rowIdx, maxIdx ).toDouble() );
1389 const QVariant val( orderedRat.
value( rowIdx, labelIdx ) );
1392 switch ( val.type() )
1394 case QVariant::Type::Char:
1395 return QString( val.toChar() );
1396 case QVariant::Type::Int:
1397 res = QLocale().toString( val.toInt( &ok ) );
1399 case QVariant::Type::LongLong:
1400 res = QLocale().toString( val.toLongLong( &ok ) );
1402 case QVariant::Type::UInt:
1403 res = QLocale().toString( val.toUInt( &ok ) );
1405 case QVariant::Type::ULongLong:
1406 res = QLocale().toString( val.toULongLong( &ok ) );
1408 case QVariant::Type::Double:
1409 res = QLocale().toString( val.toDouble( &ok ),
'g' );
1411 case QVariant::Type::String:
1413 return val.toString( );
1415 return ok ? res : val.toString();
1421 if ( orderedRat.
hasColor() && isRange )
1423 labels.push_back( labelFromField( 0 ) );
1425 for (
int rowIdx = 1; rowIdx < orderedRat.
data().count(); ++rowIdx )
1427 const double offset { ( orderedRat.
value( rowIdx, minIdx ).toDouble( ) - min ) / range };
1428 const QColor
color { orderedRat.
color( rowIdx - 1 ) };
1430 labels.push_back( labelFromField( rowIdx ) );
1439 else if ( orderedRat.
hasRamp() && isRange )
1441 double prevOffset { 0 };
1442 labels.push_back( labelFromField( 0 ) );
1443 for (
int rowIdx = 1; rowIdx < orderedRat.
data().count(); ++rowIdx )
1445 labels.push_back( labelFromField( rowIdx ) );
1446 const int prevRowIdx { rowIdx - 1 };
1447 const double offset { ( ( orderedRat.
value( rowIdx, minIdx ).toDouble( ) + orderedRat.
value( prevRowIdx, maxIdx ).toDouble( ) ) / 2.0 - min ) / range };
1453 if ( currentRamp.color1() != previousRamp.color2() &&
qgsDoubleNear( offset, prevOffset, 1e-6 ) )
1455 stops.append(
QgsGradientStop( offset + std::numeric_limits<double>::epsilon(), currentRamp.color1() ) );
1457 prevOffset = offset;
1465 labels.push_back( labelFromField( 0 ) );
1467 for (
int rowIdx = 1; rowIdx < orderedRat.
data().count(); ++rowIdx )
1469 const int prevRowIdx { rowIdx - 1 };
1470 const double offset { ( ( orderedRat.
value( rowIdx, minIdx ).toDouble( ) + orderedRat.
value( prevRowIdx, maxIdx ).toDouble( ) ) / 2.0 - min ) / range };
1472 labels.push_back( labelFromField( rowIdx ) );
1494 std::unique_ptr<QgsRasterRenderer> renderer;
1498 std::unique_ptr<QgsColorRamp>
ramp;
1504 if ( classes.isEmpty() )
1507 renderer = std::make_unique<QgsPalettedRasterRenderer>( provider,
1513 std::unique_ptr<QgsSingleBandPseudoColorRenderer> pseudoColorRenderer = std::make_unique<QgsSingleBandPseudoColorRenderer>( provider, bandNumber );
1517 int labelColumn { classificationColumn };
1518 if ( labelColumn < 0 )
1520 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1522 if ( labelColumn < 0 )
1528 pseudoColorRenderer->setClassificationMin(
minimumValue() );
1529 pseudoColorRenderer->setClassificationMax(
maximumValue() );
1531 pseudoColorRenderer->createShader(
ramp,
hasRamp() ? QgsColorRampShader::Type::Interpolated : QgsColorRampShader::Type::Discrete, QgsColorRampShader::ClassificationMode::Continuous,
ramp->
stops().count() + 2,
true );
1532 pseudoColorRenderer->shader()->setMaximumValue(
maximumValue() );
1533 pseudoColorRenderer->shader()->setMinimumValue(
minimumValue() );
1539 const bool labelsAreUsable {
ramp->
count() > 2 && labels.count() ==
ramp->
count() - 1 };
1541 if ( labelsAreUsable )
1543 QList<QgsColorRampShader::ColorRampItem> newItemList;
1546 for (
const QString &label : std::as_const( labels ) )
1554 newItemList.push_back( item );
1559 newItemList.push_back( item );
1560 shaderFunction->setColorRampItemList( newItemList );
1563 renderer.reset( pseudoColorRenderer.release() );
1566 return renderer.release();
1571 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1574 const bool isRange { minIdx >= 0 && maxIdx >= 0 };
1575 QList<QVariantList> dataCopy( mData );
1579 std::sort( dataCopy.begin(), dataCopy.end(), [ & ](
const QVariantList & first,
const QVariantList & second ) ->
bool
1581 return ( first.at( maxIdx ).toDouble() + first.at( minIdx ).toDouble() ) < ( second.at( maxIdx ).toDouble() + second.at( minIdx ).toDouble() );
1587 if ( minMaxIdx < 0 )
1593 std::sort( dataCopy.begin(), dataCopy.end(), [ & ](
const QVariantList & first,
const QVariantList & second ) ->
bool
1595 return first.at( minMaxIdx ).toDouble() < second.at( minMaxIdx ).toDouble();
RasterAttributeTableType
The RasterAttributeTableType enum represents the type of RAT.
RasterAttributeTableFieldUsage
Flags which control behavior of raster renderers.
@ 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, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
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 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.
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...
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.
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 ...
static Qgis::RasterAttributeTableFieldUsage guessFieldUsage(const QString &name, const QVariant::Type type)
Try to determine the field usage from its name and type.
const QList< QList< QVariant > > data() const
Returns the Raster Attribute Table rows.
Qgis::RasterAttributeTableType type() const
Returns the Raster Attribute Table type.
bool setRamp(const int row, const QColor &colorMin, const QColor &colorMax)
Sets the color ramp for the row at rowIndex to colorMin and colorMax.
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...
bool appendField(const QString &name, const Qgis::RasterAttributeTableFieldUsage usage, const QVariant::Type type, QString *errorMessage=nullptr)
Creates a new field from name, usage and type and appends it to the fields, optionally reporting any ...
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.
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.
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.
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
Setting options for creating vector data providers.
Properties of a single value class.