24#include "qgsogrprovider.h"
35using namespace Qt::StringLiterals;
38std::once_flag usageInformationLoaderFlag;
39QHash<Qgis::RasterAttributeTableFieldUsage, QgsRasterAttributeTable::UsageInformation> QgsRasterAttributeTable::sUsageInformation;
51 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
62 for (
int idx = 0; idx < mFields.count(); ++idx )
64 const Field f { mFields.at( idx ) };
95 for (
Field &f : mFields )
133 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
140 QList<Qgis::RasterAttributeTableFieldUsage>
usages;
143 usages.push_back( field.usage );
149QList<int> QgsRasterAttributeTable::intUsages( )
const
154 usages.push_back(
static_cast<int>( field.usage ) );
162 QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
169 const QVariantList rowData = mData.at(
row );
188 QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
189 const QVariantList rowData = mData.at(
row );
226 for (
const QVariantList &
row : std::as_const( mData ) )
229 for (
const auto &cell : std::as_const(
row ) )
231 attributes.append( cell );
235 features.append( feature );
253 const int realPos { std::clamp( position, 0,
static_cast<int>( mFields.count() ) ) };
255 if ( field.
name.isEmpty() )
259 *errorMessage = tr(
"Field name must not be empty." );
272 *errorMessage = tr(
"A field with name '%1' already exists." ).arg( field.
name );
278 static const QList<Qgis::RasterAttributeTableFieldUsage> uniqueUsages {{
302 *errorMessage = tr(
"A field with unique usage '%1' already exists." ).arg(
usageName( field.
usage ) );
307 mFields.insert( realPos, field );
309 for (
auto it = mData.begin(); it != mData.end(); ++it )
313 switch ( field.
type )
315 case QMetaType::Type::QChar:
316 case QMetaType::Type::Int:
317 case QMetaType::Type::UInt:
318 case QMetaType::Type::LongLong:
319 case QMetaType::Type::ULongLong:
320 case QMetaType::Type::Double:
324 defaultValue = QString();
326 it->insert( realPos, defaultValue );
358 int idx { position };
372 if ( fieldIndex < 0 || fieldIndex >=
fields().count( ) )
383 mFields[ fieldIndex ].
usage = usage;
395 *errorMessage = tr(
"A color ramp can only be added to an athematic attribute table." );
399 int idx { position };
413 return insertField( mFields.count(), name, usage,
type, errorMessage );
423 return insertField( mFields.count(), field, errorMessage );
428 const auto toRemove { std::find_if( mFields.begin(), mFields.end(), [ &name ](
Field & f ) ->
bool {
429 return f.name == name;
432 if ( toRemove != mFields.end() )
434 const int idx {
static_cast<int>( std::distance( mFields.begin(), toRemove ) ) };
435 mFields.erase( toRemove );
436 for (
auto it = mData.begin(); it != mData.end(); ++it )
447 *errorMessage = tr(
"A field with name '%1' was not found." ).arg( name );
455 const int realPos { std::clamp( position, 0,
static_cast<int>( mData.count() ) ) };
457 if ( rowData.size() != mFields.size() )
461 *errorMessage = tr(
"Row element count differs from field count (%1)." ).arg( mFields.size() );
466 QVariantList dataValid;
468 for (
int idx = 0; idx < mFields.count(); ++idx )
470 QVariant cell( rowData[ idx ] );
471 if ( ! cell.canConvert( mFields.at( idx ).type ) || ! cell.convert( mFields.at( idx ).type ) )
475 *errorMessage = tr(
"Row data at column %1 cannot be converted to field type (%2)." ).arg( idx ).arg( QVariant::typeToName( mFields.at( idx ).type ) );
481 dataValid.append( cell );
485 mData.insert( realPos, dataValid );
492 if ( position >= mData.count() || position < 0 || mData.isEmpty() )
496 *errorMessage = tr(
"Position is not valid or the table is empty." );
500 mData.removeAt( position );
518 std::unique_ptr<QgsVectorFileWriter> writer;
521 QString cleanedPath { path };
522 if ( path.endsWith( u
".dbf"_s, Qt::CaseSensitivity::CaseInsensitive ) )
524 cleanedPath.chop( 4 );
531 cleanedPath.append( u
".dbf"_s );
538 *errorMessage = tr(
"Error creating Raster Attribute Table table: %1." ).arg( writer->errorMessage() );
544 bool result { writer->addFeatures( features ) };
550 *errorMessage = tr(
"Error creating Raster Attribute Table table: could not add rows." );
555 result = writer->flushBuffer();
559 mFilePath = cleanedPath;
569 if ( ! ratDbfSource.isValid() )
573 *errorMessage = tr(
"Error reading Raster Attribute Table table from file: invalid layer." );
578 QList<Field> oldFields = mFields;
579 QList<QVariantList> oldData = mData;
584 bool hasValueField {
false };
585 for (
const QgsField &field : ratDbfSource.fields() )
588 QMetaType::Type
type { field.type() };
590 if (
type == QMetaType::Type::LongLong &&
596 type = QMetaType::Type::Int;
601 hasValueField =
true;
614 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 ) )
619 const int fieldCount {
static_cast<int>( ratDbfSource.fields().count( ) ) };
628 *errorMessage = tr(
"Error reading Raster Attribute Table table from file: number of fields and number of attributes do not match." );
648 if ( mFields.isEmpty() )
650 errors.push_back( tr(
"The attribute table has no fields." ) );
653 if ( mData.isEmpty() )
655 errors.push_back( tr(
"The attribute table has no rows." ) );
658 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
661 if ( ! isMinMax && ! isValueRamp )
663 errors.push_back( tr(
"The attribute table has no MinMax nor a pair of Min and Max fields." ) );
671 errors.push_back( tr(
"The attribute table has some but not all the fields required for color definition (Red, Green, Blue)." ) );
680 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)." ) );
682 else if ( ! isValueRamp )
684 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." ) );
688 if ( errorMessage && ! errors.isEmpty() )
690 *errorMessage = errors.join( QChar(
'\n' ) );
693 return errors.isEmpty();
703 for (
const Field &f : std::as_const( mFields ) )
705 if ( f.name == name )
723 QList<QgsRasterAttributeTable::Field> result;
724 for (
const Field &f : std::as_const( mFields ) )
726 if ( f.usage == fieldUsage )
728 result.push_back( f );
741 QVariant newVal =
value;
742 if ( column >= mFields.length() || !
value.canConvert( mFields.at( column ).type ) || ! newVal.convert( mFields.at( column ).type ) )
747 const QVariant oldVal = mData[
row ][ column ];
749 if ( newVal != oldVal )
751 mData[
row ][ column ] = newVal;
764 return mData[
row ][ column ];
769 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
782 double min { std::numeric_limits<double>::max() };
783 for (
int rowIdx = 0; rowIdx < mData.count(); ++rowIdx )
785 min = std::min( min,
value( rowIdx, fieldIdx ).toDouble( &ok ) );
788 return std::numeric_limits<double>::quiet_NaN();
792 if ( fieldIdx == -1 || ! ok )
794 return std::numeric_limits<double>::quiet_NaN();
804 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
817 double max { std::numeric_limits<double>::lowest() };
818 for (
int rowIdx = 0; rowIdx < mData.count(); ++rowIdx )
820 max = std::max( max,
value( rowIdx, fieldIdx ).toDouble( &ok ) );
823 return std::numeric_limits<double>::quiet_NaN();
827 if ( fieldIdx == -1 || ! ok )
829 return std::numeric_limits<double>::quiet_NaN();
841 return QVariantList();
844 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
849 for (
int rowIdx = 0; rowIdx < mData.count(); ++rowIdx )
852 if ( matchValue ==
value( rowIdx, colIdx ).toDouble( &ok ) && ok )
854 return mData.at( rowIdx );
862 for (
int rowIdx = 0; rowIdx < mData.count(); ++rowIdx )
865 if ( matchValue >=
value( rowIdx, minColIdx ).toDouble( &ok ) && ok )
867 if ( matchValue <
value( rowIdx, maxColIdx ).toDouble( &ok ) && ok )
869 return mData.at( rowIdx );
874 return QVariantList();
879 static const QStringList minValueNames { {
887 static const QStringList maxValueNames { {
895 const QString fieldLower { name.toLower() };
897 if (
type == QMetaType::Type::Double ||
type == QMetaType::Type::Int ||
type == QMetaType::Type::UInt ||
type == QMetaType::Type::LongLong ||
type == QMetaType::Type::ULongLong )
899 if ( minValueNames.contains( fieldLower ) )
903 else if ( maxValueNames.contains( fieldLower ) )
907 else if ( fieldLower ==
"value"_L1 )
911 else if ( fieldLower ==
"count"_L1 )
917 else if (
type != QMetaType::Type::Double )
919 if ( fieldLower.contains(
"red" ) || fieldLower ==
"r"_L1 )
921 if ( fieldLower.contains(
"min" ) )
925 else if ( fieldLower.contains(
"max" ) )
934 else if ( fieldLower.contains(
"green" ) || fieldLower ==
"g"_L1 )
936 if ( fieldLower.contains(
"min" ) )
940 else if ( fieldLower.contains(
"max" ) )
949 else if ( fieldLower.contains(
"blue" ) || fieldLower ==
"b"_L1 )
951 if ( fieldLower.contains(
"min" ) )
955 else if ( fieldLower.contains(
"max" ) )
964 else if ( fieldLower.contains(
"alpha" ) || fieldLower ==
"a"_L1 )
966 if ( fieldLower.contains(
"min" ) )
970 else if ( fieldLower.contains(
"max" ) )
983 if (
type == QMetaType::Type::QString )
1005 return tr(
"Green" );
1007 return tr(
"Blue" );
1009 return tr(
"Alpha" );
1011 return tr(
"Red Minimum" );
1013 return tr(
"Green Minimum" );
1015 return tr(
"Blue Minimum" );
1017 return tr(
"Alpha Minimum" );
1019 return tr(
"Red Maximum" );
1021 return tr(
"Green Maximum" );
1023 return tr(
"Blue Maximum" );
1025 return tr(
"Alpha Maximum" );
1027 return tr(
"Generic" );
1029 return tr(
"Name" );
1031 return tr(
"Pixel Count" );
1033 return tr(
"Maximum Count" );
1035 return tr(
"Value" );
1037 return tr(
"Minimum Value" );
1039 return tr(
"Maximum Value" );
1046 static const QList<Qgis::RasterAttributeTableFieldUsage> valueColorUsages {{
1063 return valueColorUsages;
1095 rat->
appendRow( QVariantList() << klass.value << klass.label << 0 << 0 << 0 << 255 );
1096 rat->
setColor( rat->
data().length() - 1, klass.color );
1101 *bandNumber = palettedRenderer->inputBand();
1112 switch ( shaderFunction->colorRampType() )
1128 const QList<QgsColorRampShader::ColorRampItem> rampItems { shaderFunction->colorRampItemList() };
1129 if ( rampItems.size() > 1 )
1131 QColor color1 { rampItems.at( 0 ).color };
1132 QString label1 { rampItems.at( 0 ).label };
1133 QVariant value1( rampItems.at( 0 ).value );
1134 const int rampItemSize = rampItems.size();
1135 for (
int i = 1; i < rampItemSize; ++i )
1138 rat->
appendRow( QVariantList() << value1 << rampItem.
value << u
"%1 - %2"_s.arg( label1, rampItem.
label ) << 0 << 0 << 0 << 255 << 0 << 0 << 0 << 255 );
1140 label1 = rampItem.
label;
1141 value1 = rampItem.
value;
1142 color1 = rampItem.
color;
1157 const QList<QgsColorRampShader::ColorRampItem> rampItems { shaderFunction->colorRampItemList() };
1158 if ( rampItems.size( ) > 1 )
1160 QColor color1 { rampItems.at( 0 ).color };
1161 QString label1 { rampItems.at( 0 ).label };
1162 QVariant value1( rampItems.at( 0 ).value );
1163 const int rampItemSize = rampItems.size();
1164 for (
int i = 1; i < rampItemSize; ++i )
1167 rat->
appendRow( QVariantList() << value1 << rampItem.
value << u
"%1 - %2"_s.arg( label1, rampItem.
label ) << 0 << 0 << 0 << 255 << 0 << 0 << 0 << 255 );
1169 label1 = rampItem.
label;
1170 value1 = rampItem.
value;
1171 color1 = rampItem.
color;
1185 const QList<QgsColorRampShader::ColorRampItem> rampItems { shaderFunction->colorRampItemList() };
1188 rat->
appendRow( QVariantList() << rampItem.value << rampItem.label << 0 << 0 << 0 << 255 );
1189 rat->
setColor( rat->
data().length() - 1, rampItem.color );
1197 *bandNumber = pseudoColorRenderer->inputBand();
1220 std::call_once( usageInformationLoaderFlag, [ ]
1222 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 } );
1224 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Name, { tr(
"Class Name" ),
false,
false,
false,
false,
true,
true, QList<QMetaType::Type>() << QMetaType::Type::QString } );
1225 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 } );
1226 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 } );
1227 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 } );
1228 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Red, { tr(
"Red Color Value (0-255)" ),
true,
false,
true,
false,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1229 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Green, { tr(
"Green Color Value (0-255)" ),
true,
false,
true,
false,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1230 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Blue, { tr(
"Blue Color Value (0-255)" ),
true,
false,
true,
false,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1231 QgsRasterAttributeTable::sUsageInformation.insert(
Qgis::RasterAttributeTableFieldUsage::Alpha, { tr(
"Alpha Color Value (0-255)" ),
true,
false,
true,
false,
true,
false, QList<QMetaType::Type>() << QMetaType::Type::Int } );
1232 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 } );
1233 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 } );
1234 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 } );
1235 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 } );
1236 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 } );
1237 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 } );
1238 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 } );
1239 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 } );
1241 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 } );
1243 return QgsRasterAttributeTable::sUsageInformation;
1246void QgsRasterAttributeTable::setType()
1248 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1254QHash<int, QgsRasterAttributeTable::UsageInformation> QgsRasterAttributeTable::usageInformationInt()
1256 QHash<int, QgsRasterAttributeTable::UsageInformation> usageInfoInt;
1258 for (
auto it = usageInfo.cbegin(); it != usageInfo.cend(); ++it )
1260 usageInfoInt.insert(
static_cast<int>( it.key() ), it.value() );
1262 return usageInfoInt;
1273 QList<QgsRasterAttributeTable::MinMaxClass> classes;
1276 QgsDebugError(
"minMaxClasses was called on an invalid RAT" );
1280 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1284 QgsDebugError(
"minMaxClasses was called on a ramp raster" );
1290 Q_ASSERT( minMaxIndex >= 0 );
1292 int classificationIndex = classificationColumn;
1293 if ( classificationIndex >= 0 && classificationIndex < mFields.count( ) )
1295 const Field classificationField { mFields.at( classificationIndex ) };
1298 QgsDebugError(
"minMaxClasses was called with a classification column which is not suitable for classification" );
1302 else if ( classificationIndex == -1 )
1315 classificationIndex = minMaxIndex;
1318 else if ( classificationIndex >= mFields.count( ) )
1320 QgsDebugError(
"minMaxClasses was called with a classification column out of range" );
1324 if ( classificationIndex >= 0 )
1328 for (
const QVariantList &
row : std::as_const( mData ) )
1330 const QString label {
row.at( classificationIndex ).toString() };
1332 const double value {
row.at( minMaxIndex ).toDouble( &ok ) };
1336 QgsDebugError(
"minMaxClasses could not convert a MinMax value to double" );
1339 if ( labels.contains( label ) )
1341 classes[ labels.indexOf( label ) ].minMaxValues.push_back(
value );
1345 labels.push_back( label );
1346 classes.push_back( { label, {
value },
color( rowIdx ) } );
1357 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1360 const bool isRange { minIdx >= 0 && maxIdx >= 0 };
1362 int labelIdx { labelColumn };
1363 if ( labelColumn < 0 || labelColumn >=
fields().count( ) ||
1369 if ( ! mData.isEmpty() && ( minIdx >= 0 && maxIdx >= 0 ) )
1377 const double range { max - min };
1382 if ( ! std::isnan( min ) && ! std::isnan( max ) )
1384 const QList<QVariantList> dataCopy(
orderedRows() );
1387 for (
const Field &f : std::as_const( mFields ) )
1391 for (
const QVariantList &r : std::as_const( dataCopy ) )
1396 QColor lastColor {
ramp.color1() };
1398 if ( hasColorOrRamp )
1405 auto labelFromField = [ & ](
int rowIdx ) -> QString
1409 return u
"%L1 - %L2"_s.arg( orderedRat.
value( rowIdx, minIdx ).toDouble() ).arg( orderedRat.
value( rowIdx, maxIdx ).toDouble() );
1411 const QVariant val( orderedRat.
value( rowIdx, labelIdx ) );
1414 switch ( val.userType() )
1416 case QMetaType::Type::QChar:
1417 return QString( val.toChar() );
1418 case QMetaType::Type::Int:
1419 res = QLocale().toString( val.toInt( &ok ) );
1421 case QMetaType::Type::LongLong:
1422 res = QLocale().toString( val.toLongLong( &ok ) );
1424 case QMetaType::Type::UInt:
1425 res = QLocale().toString( val.toUInt( &ok ) );
1427 case QMetaType::Type::ULongLong:
1428 res = QLocale().toString( val.toULongLong( &ok ) );
1430 case QMetaType::Type::Double:
1431 res = QLocale().toString( val.toDouble( &ok ),
'g' );
1433 case QMetaType::Type::QString:
1435 return val.toString( );
1437 return ok ? res : val.toString();
1443 if ( orderedRat.
hasColor() && isRange )
1445 labels.push_back( labelFromField( 0 ) );
1447 for (
int rowIdx = 1; rowIdx < orderedRat.
data().count(); ++rowIdx )
1449 const double offset { ( orderedRat.
value( rowIdx, minIdx ).toDouble( ) - min ) / range };
1450 const QColor
color { orderedRat.
color( rowIdx - 1 ) };
1452 labels.push_back( labelFromField( rowIdx ) );
1461 else if ( orderedRat.
hasRamp() && isRange )
1463 double prevOffset { 0 };
1464 labels.push_back( labelFromField( 0 ) );
1465 for (
int rowIdx = 1; rowIdx < orderedRat.
data().count(); ++rowIdx )
1467 labels.push_back( labelFromField( rowIdx ) );
1468 const int prevRowIdx { rowIdx - 1 };
1469 const double offset { ( ( orderedRat.
value( rowIdx, minIdx ).toDouble( ) + orderedRat.
value( prevRowIdx, maxIdx ).toDouble( ) ) / 2.0 - min ) / range };
1477 stops.append(
QgsGradientStop( offset + std::numeric_limits<double>::epsilon(), currentRamp.
color1() ) );
1479 prevOffset = offset;
1487 labels.push_back( labelFromField( 0 ) );
1489 for (
int rowIdx = 1; rowIdx < orderedRat.
data().count(); ++rowIdx )
1491 const int prevRowIdx { rowIdx - 1 };
1492 const double offset { ( ( orderedRat.
value( rowIdx, minIdx ).toDouble( ) + orderedRat.
value( prevRowIdx, maxIdx ).toDouble( ) ) / 2.0 - min ) / range };
1494 labels.push_back( labelFromField( rowIdx ) );
1501 ramp.setStops( stops );
1516 std::unique_ptr<QgsRasterRenderer> renderer;
1520 std::unique_ptr<QgsColorRamp>
ramp;
1523 ramp = std::make_unique<QgsRandomColorRamp>( );
1526 if ( classes.isEmpty() )
1529 renderer = std::make_unique<QgsPalettedRasterRenderer>( provider,
1535 auto pseudoColorRenderer = std::make_unique<QgsSingleBandPseudoColorRenderer>( provider, bandNumber );
1539 int labelColumn { classificationColumn };
1540 if ( labelColumn < 0 )
1542 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1544 if ( labelColumn < 0 )
1550 pseudoColorRenderer->setClassificationMin(
minimumValue() );
1551 pseudoColorRenderer->setClassificationMax(
maximumValue() );
1554 if ( pseudoColorRenderer->shader() )
1556 pseudoColorRenderer->shader()->setMaximumValue(
maximumValue() );
1557 pseudoColorRenderer->shader()->setMinimumValue(
minimumValue() );
1563 const bool labelsAreUsable {
ramp->count() > 2 && labels.count() ==
ramp->count() - 1 };
1565 if ( labelsAreUsable )
1567 QList<QgsColorRampShader::ColorRampItem> newItemList;
1570 for (
const QString &label : std::as_const( labels ) )
1572 if ( stopIdx >=
ramp->count() - 2 )
1578 newItemList.push_back( item );
1583 newItemList.push_back( item );
1584 shaderFunction->setColorRampItemList( newItemList );
1588 renderer = std::move( pseudoColorRenderer );
1591 return renderer.release();
1596 const QList<Qgis::RasterAttributeTableFieldUsage> fieldUsages {
usages() };
1599 const bool isRange { minIdx >= 0 && maxIdx >= 0 };
1600 QList<QVariantList> dataCopy( mData );
1604 std::sort( dataCopy.begin(), dataCopy.end(), [ & ](
const QVariantList & first,
const QVariantList & second ) ->
bool
1606 return ( first.at( maxIdx ).toDouble() + first.at( minIdx ).toDouble() ) < ( second.at( maxIdx ).toDouble() + second.at( minIdx ).toDouble() );
1612 if ( minMaxIdx < 0 )
1618 std::sort( dataCopy.begin(), dataCopy.end(), [ & ](
const QVariantList & first,
const QVariantList & second ) ->
bool
1620 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.