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 )
306 QVariant defaultValue( field.
type );
308 switch ( field.
type )
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 );
408 return insertField( mFields.count(), field, 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 );
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" ) );
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 };
570 for (
const QgsField &field : ratDbfSource.fields() )
573 QVariant::Type
type { field.type() };
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() )
1108 const QList<QgsColorRampShader::ColorRampItem> rampItems { shaderFunction->colorRampItemList() };
1109 if ( rampItems.size() > 1 )
1111 QColor color1 { rampItems.at( 0 ).color };
1112 QString label1 { rampItems.at( 0 ).label };
1113 QVariant value1( rampItems.at( 0 ).value );
1114 const int rampItemSize = rampItems.size();
1115 for (
int i = 1; i < rampItemSize; ++i )
1118 rat->
appendRow( QVariantList() << value1 << rampItem.value << QStringLiteral(
"%1 - %2" ).arg( label1, rampItem.label ) << 0 << 0 << 0 << 255 << 0 << 0 << 0 << 255 );
1119 rat->
setRamp( rat->
data().length() - 1, color1, rampItem.color );
1120 label1 = rampItem.label;
1121 value1 = rampItem.value;
1122 color1 = rampItem.color;
1137 const QList<QgsColorRampShader::ColorRampItem> rampItems { shaderFunction->colorRampItemList() };
1138 if ( rampItems.size( ) > 1 )
1140 QColor color1 { rampItems.at( 0 ).color };
1141 QString label1 { rampItems.at( 0 ).label };
1142 QVariant value1( rampItems.at( 0 ).value );
1143 const int rampItemSize = rampItems.size();
1144 for (
int i = 1; i < rampItemSize; ++i )
1147 rat->
appendRow( QVariantList() << value1 << rampItem.value << QStringLiteral(
"%1 - %2" ).arg( label1, rampItem.label ) << 0 << 0 << 0 << 255 << 0 << 0 << 0 << 255 );
1148 rat->
setRamp( rat->
data().length() - 1, color1, rampItem.color );
1149 label1 = rampItem.label;
1150 value1 = rampItem.value;
1151 color1 = rampItem.color;
1165 const QList<QgsColorRampShader::ColorRampItem> rampItems { shaderFunction->colorRampItemList() };
1168 rat->
appendRow( QVariantList() << rampItem.value << rampItem.label << 0 << 0 << 0 << 255 );
1169 rat->
setColor( rat->
data().length() - 1, rampItem.color );
1177 *bandNumber = pseudoColorRenderer->band();
1200 std::call_once( usageInformationLoaderFlag, [ ]
1202 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 } );
1204 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Name, { tr(
"Class Name" ),
false,
false,
false,
false,
true,
true, QList<QVariant::Type>() << QVariant::String } );
1205 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 } );
1206 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 } );
1207 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 } );
1208 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Red, { tr(
"Red Color Value (0-255)" ),
true,
false,
true,
false,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1209 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Green, { tr(
"Green Color Value (0-255)" ),
true,
false,
true,
false,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1210 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Blue, { tr(
"Blue Color Value (0-255)" ),
true,
false,
true,
false,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1211 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Alpha, { tr(
"Alpha Color Value (0-255)" ),
true,
false,
true,
false,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1212 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::RedMin, { tr(
"Red Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1213 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::GreenMin, { tr(
"Green Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1214 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::BlueMin, { tr(
"Blue Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1215 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::AlphaMin, { tr(
"Alpha Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1216 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::RedMax, { tr(
"Red Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1217 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::GreenMax, { tr(
"Green Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1218 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::BlueMax, { tr(
"Blue Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1219 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::AlphaMax, { tr(
"Alpha Color Minimum Value (0-255)" ),
true,
false,
false,
true,
true,
false, QList<QVariant::Type>() << QVariant::Int } );
1221 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 } );
1223 return QgsRasterAttributeTable::sUsageInformation;
1226void QgsRasterAttributeTable::setType()
1228 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1234QHash<int, QgsRasterAttributeTable::UsageInformation> QgsRasterAttributeTable::usageInformationInt()
1236 QHash<int, QgsRasterAttributeTable::UsageInformation> usageInfoInt;
1238 for (
auto it = usageInfo.cbegin(); it != usageInfo.cend(); ++it )
1240 usageInfoInt.insert(
static_cast<int>( it.key() ), it.value() );
1242 return usageInfoInt;
1253 QList<QgsRasterAttributeTable::MinMaxClass> classes;
1256 QgsDebugError(
"minMaxClasses was called on an invalid RAT" );
1260 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1264 QgsDebugError(
"minMaxClasses was called on a ramp raster" );
1270 Q_ASSERT( minMaxIndex >= 0 );
1272 int classificationIndex = classificationColumn;
1273 if ( classificationIndex >= 0 && classificationIndex < mFields.count( ) )
1275 const Field classificationField { mFields.at( classificationIndex ) };
1278 QgsDebugError(
"minMaxClasses was called with a classification column which is not suitable for classification" );
1282 else if ( classificationIndex == -1 )
1295 classificationIndex = minMaxIndex;
1298 else if ( classificationIndex >= mFields.count( ) )
1300 QgsDebugError(
"minMaxClasses was called with a classification column out of range" );
1304 if ( classificationIndex >= 0 )
1308 for (
const QVariantList &
row : std::as_const( mData ) )
1310 const QString label {
row.at( classificationIndex ).toString() };
1312 const double value {
row.at( minMaxIndex ).toDouble( &ok ) };
1316 QgsDebugError(
"minMaxClasses could not convert a MinMax value to double" );
1319 if ( labels.contains( label ) )
1321 classes[ labels.indexOf( label ) ].minMaxValues.push_back(
value );
1325 labels.push_back( label );
1326 classes.push_back( { label, {
value },
color( rowIdx ) } );
1337 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1340 const bool isRange { minIdx >= 0 && maxIdx >= 0 };
1342 int labelIdx { labelColumn };
1343 if ( labelColumn < 0 || labelColumn >=
fields().count( ) ||
1349 if ( ! mData.isEmpty() && ( minIdx >= 0 && maxIdx >= 0 ) )
1357 const double range { max - min };
1362 if ( ! isnan( min ) && ! isnan( max ) )
1364 const QList<QVariantList> dataCopy(
orderedRows() );
1367 for (
const Field &f : std::as_const( mFields ) )
1371 for (
const QVariantList &r : std::as_const( dataCopy ) )
1378 if ( hasColorOrRamp )
1385 auto labelFromField = [ & ](
int rowIdx ) -> QString
1389 return QStringLiteral(
"%L1 - %L2" ).arg( orderedRat.
value( rowIdx, minIdx ).toDouble() ).arg( orderedRat.
value( rowIdx, maxIdx ).toDouble() );
1391 const QVariant val( orderedRat.
value( rowIdx, labelIdx ) );
1394 switch ( val.type() )
1396 case QVariant::Type::Char:
1397 return QString( val.toChar() );
1398 case QVariant::Type::Int:
1399 res = QLocale().toString( val.toInt( &ok ) );
1401 case QVariant::Type::LongLong:
1402 res = QLocale().toString( val.toLongLong( &ok ) );
1404 case QVariant::Type::UInt:
1405 res = QLocale().toString( val.toUInt( &ok ) );
1407 case QVariant::Type::ULongLong:
1408 res = QLocale().toString( val.toULongLong( &ok ) );
1410 case QVariant::Type::Double:
1411 res = QLocale().toString( val.toDouble( &ok ),
'g' );
1413 case QVariant::Type::String:
1415 return val.toString( );
1417 return ok ? res : val.toString();
1423 if ( orderedRat.
hasColor() && isRange )
1425 labels.push_back( labelFromField( 0 ) );
1427 for (
int rowIdx = 1; rowIdx < orderedRat.
data().count(); ++rowIdx )
1429 const double offset { ( orderedRat.
value( rowIdx, minIdx ).toDouble( ) - min ) / range };
1430 const QColor
color { orderedRat.
color( rowIdx - 1 ) };
1432 labels.push_back( labelFromField( rowIdx ) );
1441 else if ( orderedRat.
hasRamp() && isRange )
1443 double prevOffset { 0 };
1444 labels.push_back( labelFromField( 0 ) );
1445 for (
int rowIdx = 1; rowIdx < orderedRat.
data().count(); ++rowIdx )
1447 labels.push_back( labelFromField( rowIdx ) );
1448 const int prevRowIdx { rowIdx - 1 };
1449 const double offset { ( ( orderedRat.
value( rowIdx, minIdx ).toDouble( ) + orderedRat.
value( prevRowIdx, maxIdx ).toDouble( ) ) / 2.0 - min ) / range };
1455 if ( currentRamp.color1() != previousRamp.color2() &&
qgsDoubleNear( offset, prevOffset, 1e-6 ) )
1457 stops.append(
QgsGradientStop( offset + std::numeric_limits<double>::epsilon(), currentRamp.color1() ) );
1459 prevOffset = offset;
1467 labels.push_back( labelFromField( 0 ) );
1469 for (
int rowIdx = 1; rowIdx < orderedRat.
data().count(); ++rowIdx )
1471 const int prevRowIdx { rowIdx - 1 };
1472 const double offset { ( ( orderedRat.
value( rowIdx, minIdx ).toDouble( ) + orderedRat.
value( prevRowIdx, maxIdx ).toDouble( ) ) / 2.0 - min ) / range };
1474 labels.push_back( labelFromField( rowIdx ) );
1496 std::unique_ptr<QgsRasterRenderer> renderer;
1500 std::unique_ptr<QgsColorRamp>
ramp;
1506 if ( classes.isEmpty() )
1509 renderer = std::make_unique<QgsPalettedRasterRenderer>( provider,
1515 std::unique_ptr<QgsSingleBandPseudoColorRenderer> pseudoColorRenderer = std::make_unique<QgsSingleBandPseudoColorRenderer>( provider, bandNumber );
1519 int labelColumn { classificationColumn };
1520 if ( labelColumn < 0 )
1522 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1524 if ( labelColumn < 0 )
1530 pseudoColorRenderer->setClassificationMin(
minimumValue() );
1531 pseudoColorRenderer->setClassificationMax(
maximumValue() );
1534 if ( pseudoColorRenderer->shader() )
1536 pseudoColorRenderer->shader()->setMaximumValue(
maximumValue() );
1537 pseudoColorRenderer->shader()->setMinimumValue(
minimumValue() );
1543 const bool labelsAreUsable {
ramp->
count() > 2 && labels.count() ==
ramp->
count() - 1 };
1545 if ( labelsAreUsable )
1547 QList<QgsColorRampShader::ColorRampItem> newItemList;
1550 for (
const QString &label : std::as_const( labels ) )
1558 newItemList.push_back( item );
1563 newItemList.push_back( item );
1564 shaderFunction->setColorRampItemList( newItemList );
1568 renderer.reset( pseudoColorRenderer.release() );
1571 return renderer.release();
1576 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1579 const bool isRange { minIdx >= 0 && maxIdx >= 0 };
1580 QList<QVariantList> dataCopy( mData );
1584 std::sort( dataCopy.begin(), dataCopy.end(), [ & ](
const QVariantList & first,
const QVariantList & second ) ->
bool
1586 return ( first.at( maxIdx ).toDouble() + first.at( minIdx ).toDouble() ) < ( second.at( maxIdx ).toDouble() + second.at( minIdx ).toDouble() );
1592 if ( minMaxIdx < 0 )
1598 std::sort( dataCopy.begin(), dataCopy.end(), [ & ](
const QVariantList & first,
const QVariantList & second ) ->
bool
1600 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.
@ Continuous
Uses breaks from color palette.
@ Interpolated
Interpolates the color between two class breaks linearly.
@ Discrete
Assigns the color of the higher class for every pixel between two class breaks.
@ Exact
Assigns the color of the exact matching value in the color ramp item list.
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.
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 ...
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.
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...
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.
@ 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.