32#include "moc_qgsrasterlayerelevationproperties.cpp"
34using namespace Qt::StringLiterals;
40 setDefaultProfileLineSymbol( color );
41 setDefaultProfileFillSymbol( color );
53 QDomElement element = document.createElement( u
"elevation"_s );
54 element.setAttribute( u
"enabled"_s, mEnabled ? u
"1"_s : u
"0"_s );
57 if ( !std::isnan( mElevationLimit ) )
58 element.setAttribute( u
"elevationLimit"_s,
qgsDoubleToString( mElevationLimit ) );
67 element.setAttribute( u
"includeLower"_s, mFixedRange.includeLower() ?
"1" :
"0" );
68 element.setAttribute( u
"includeUpper"_s, mFixedRange.includeUpper() ?
"1" :
"0" );
73 QDomElement ranges = document.createElement( u
"ranges"_s );
74 for (
auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
76 QDomElement range = document.createElement( u
"range"_s );
77 range.setAttribute( u
"band"_s, it.key() );
80 range.setAttribute( u
"includeLower"_s, it.value().includeLower() ?
"1" :
"0" );
81 range.setAttribute( u
"includeUpper"_s, it.value().includeUpper() ?
"1" :
"0" );
82 ranges.appendChild( range );
84 element.appendChild( ranges );
92 element.setAttribute( u
"band"_s, mBandNumber );
96 QDomElement profileLineSymbolElement = document.createElement( u
"profileLineSymbol"_s );
98 element.appendChild( profileLineSymbolElement );
100 QDomElement profileFillSymbolElement = document.createElement( u
"profileFillSymbol"_s );
102 element.appendChild( profileFillSymbolElement );
104 parentElement.appendChild( element );
110 const QDomElement elevationElement = element.firstChildElement( u
"elevation"_s ).toElement();
111 mEnabled = elevationElement.attribute( u
"enabled"_s, u
"0"_s ).toInt();
114 if ( elevationElement.hasAttribute( u
"elevationLimit"_s ) )
115 mElevationLimit = elevationElement.attribute( u
"elevationLimit"_s ).toDouble();
117 mElevationLimit = std::numeric_limits< double >::quiet_NaN();
125 const double lower = elevationElement.attribute( u
"lower"_s ).toDouble();
126 const double upper = elevationElement.attribute( u
"upper"_s ).toDouble();
127 const bool includeLower = elevationElement.attribute( u
"includeLower"_s ).toInt();
128 const bool includeUpper = elevationElement.attribute( u
"includeUpper"_s ).toInt();
129 mFixedRange =
QgsDoubleRange( lower, upper, includeLower, includeUpper );
135 mRangePerBand.clear();
137 const QDomNodeList ranges = elevationElement.firstChildElement( u
"ranges"_s ).childNodes();
138 for (
int i = 0; i < ranges.size(); ++i )
140 const QDomElement rangeElement = ranges.at( i ).toElement();
141 const int band = rangeElement.attribute( u
"band"_s ).toInt();
142 const double lower = rangeElement.attribute( u
"lower"_s ).toDouble();
143 const double upper = rangeElement.attribute( u
"upper"_s ).toDouble();
144 const bool includeLower = rangeElement.attribute( u
"includeLower"_s ).toInt();
145 const bool includeUpper = rangeElement.attribute( u
"includeUpper"_s ).toInt();
146 mRangePerBand.insert( band,
QgsDoubleRange( lower, upper, includeLower, includeUpper ) );
155 mBandNumber = elevationElement.attribute( u
"band"_s, u
"1"_s ).toInt();
161 const QDomElement profileLineSymbolElement = elevationElement.firstChildElement( u
"profileLineSymbol"_s ).firstChildElement( u
"symbol"_s );
163 if ( !mProfileLineSymbol )
164 setDefaultProfileLineSymbol( defaultColor );
166 const QDomElement profileFillSymbolElement = elevationElement.firstChildElement( u
"profileFillSymbol"_s ).firstChildElement( u
"symbol"_s );
168 if ( !mProfileFillSymbol )
169 setDefaultProfileFillSymbol( defaultColor );
176 auto res = std::make_unique< QgsRasterLayerElevationProperties >(
nullptr );
177 res->setEnabled( mEnabled );
178 res->setMode( mMode );
179 res->setProfileLineSymbol( mProfileLineSymbol->clone() );
180 res->setProfileFillSymbol( mProfileFillSymbol->clone() );
181 res->setProfileSymbology( mSymbology );
182 res->setElevationLimit( mElevationLimit );
183 res->setBandNumber( mBandNumber );
184 res->setFixedRange( mFixedRange );
185 res->setFixedRangePerBand( mRangePerBand );
186 res->copyCommonProperties(
this );
187 return res.release();
192 QStringList properties;
196 properties << tr(
"Elevation range: %1 to %2" ).arg( mFixedRange.lower() ).arg( mFixedRange.upper() );
201 for (
auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
203 properties << tr(
"Elevation for band %1: %2 to %3" ).arg( it.key() ).arg( it.value().lower() ).arg( it.value().upper() );
212 properties << tr(
"Elevation band: %1" ).arg( mBandNumber );
213 properties << tr(
"Scale: %1" ).arg(
mZScale );
214 properties << tr(
"Offset: %1" ).arg(
mZOffset );
218 return u
"<li>%1</li>"_s.arg( properties.join(
"</li><li>"_L1 ) );
226 return mFixedRange.overlaps( range );
230 for (
auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
232 if ( it.value().overlaps( range ) )
240 if (
QgsRasterLayer *rl = qobject_cast< QgsRasterLayer * >( layer ) )
252 lowerProperty.
prepare( context );
253 upperProperty.
prepare( context );
254 for (
int band = 1; band <= rl->bandCount(); ++band )
257 bandScope->
setVariable( u
"band_name"_s, rl->dataProvider()->displayBandName( band ) );
258 bandScope->
setVariable( u
"band_description"_s, rl->dataProvider()->bandDescription( band ) );
261 const double lower = lowerProperty.
valueAsDouble( context, 0, &ok );
264 const double upper = upperProperty.
valueAsDouble( context, 0, &ok );
291 double lower = std::numeric_limits< double >::max();
292 double upper = std::numeric_limits< double >::min();
293 bool includeLower =
true;
294 bool includeUpper =
true;
295 for (
auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
297 if ( it.value().lower() < lower )
299 lower = it.value().lower();
300 includeLower = it.value().includeLower();
302 else if ( !includeLower && it.value().lower() == lower && it.value().includeLower() )
306 if ( it.value().upper() > upper )
308 upper = it.value().upper();
309 includeUpper = it.value().includeUpper();
311 else if ( !includeUpper && it.value().upper() == upper && it.value().includeUpper() )
316 return QgsDoubleRange( lower, upper, includeLower, includeUpper );
321 if (
QgsRasterLayer *rl = qobject_cast< QgsRasterLayer * >( layer ) )
333 lowerProperty.
prepare( context );
334 upperProperty.
prepare( context );
335 double minLower = std::numeric_limits<double>::max();
336 double maxUpper = std::numeric_limits<double>::lowest();
337 for (
int band = 1; band <= rl->bandCount(); ++band )
340 bandScope->
setVariable( u
"band_name"_s, rl->dataProvider()->displayBandName( band ) );
341 bandScope->
setVariable( u
"band_description"_s, rl->dataProvider()->bandDescription( band ) );
344 const double lower = lowerProperty.
valueAsDouble( context, 0, &ok );
347 const double upper = upperProperty.
valueAsDouble( context, 0, &ok );
351 minLower = std::min( minLower, lower );
352 maxUpper = std::max( maxUpper, upper );
354 return ( minLower == std::numeric_limits<double>::max() && maxUpper == std::numeric_limits<double>::lowest() ) ?
QgsDoubleRange() :
QgsDoubleRange( minLower, maxUpper );
372 if ( !mFixedRange.isInfinite() && mFixedRange.lower() != mFixedRange.upper() )
373 return { mFixedRange.lower(), mFixedRange.upper() };
374 else if ( !mFixedRange.isInfinite() )
375 return { mFixedRange.lower() };
383 for (
auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
385 if ( it.value().isInfinite() )
388 if ( !res.contains( it.value().lower( ) ) )
389 res.append( it.value().lower() );
390 if ( !res.contains( it.value().upper( ) ) )
391 res.append( it.value().upper() );
393 std::sort( res.begin(), res.end() );
400 if (
QgsRasterLayer *rl = qobject_cast< QgsRasterLayer * >( layer ) )
412 lowerProperty.
prepare( context );
413 upperProperty.
prepare( context );
414 for (
int band = 1; band <= rl->bandCount(); ++band )
417 bandScope->
setVariable( u
"band_name"_s, rl->dataProvider()->displayBandName( band ) );
418 bandScope->
setVariable( u
"band_description"_s, rl->dataProvider()->bandDescription( band ) );
421 const double lower = lowerProperty.
valueAsDouble( context, 0, &ok );
422 if ( ok && !res.contains( lower ) )
424 const double upper = upperProperty.
valueAsDouble( context, 0, &ok );
425 if ( ok && !res.contains( upper ) )
463 if ( enabled == mEnabled )
487 if ( mBandNumber == band )
497 if ( !mEnabled || std::isnan( pixelValue ) )
507 auto it = mRangePerBand.constFind( band );
508 if ( it != mRangePerBand.constEnd() )
515 if ( layer && band > 0 && band <= layer->bandCount() )
527 lowerProperty.
prepare( context );
528 upperProperty.
prepare( context );
531 const double lower = lowerProperty.
valueAsDouble( context, 0, &ok );
534 const double upper = upperProperty.
valueAsDouble( context, 0, &ok );
546 if ( band != mBandNumber )
567 int currentMatchingBand = -1;
569 for (
auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
571 if ( it.value().overlaps( range ) )
574 || ( it.value().includeUpper() && it.value().upper() >= currentMatchingRange.
upper() )
575 || ( !currentMatchingRange.
includeUpper() && it.value().upper() >= currentMatchingRange.
upper() ) )
577 currentMatchingBand = it.key();
578 currentMatchingRange = it.value();
582 return currentMatchingBand;
596 lowerProperty.
prepare( context );
597 upperProperty.
prepare( context );
599 int currentMatchingBand = -1;
602 for (
int band = 1; band <= layer->
bandCount(); ++band )
609 const double lower = lowerProperty.
valueAsDouble( context, 0, &ok );
612 const double upper = upperProperty.
valueAsDouble( context, 0, &ok );
623 currentMatchingBand = band;
624 currentMatchingRange = bandRange;
628 return currentMatchingBand;
638 return mProfileLineSymbol.get();
643 mProfileLineSymbol.reset( symbol );
650 return mProfileFillSymbol.get();
655 mProfileFillSymbol.reset( symbol );
662 if ( mSymbology == symbology )
665 mSymbology = symbology;
672 return mElevationLimit;
680 mElevationLimit = limit;
698 switch ( dataProvider->dataType( 1 ) )
724 static const QStringList sPartialCandidates{ u
"dem"_s,
743 const QString layerName = layer->
name();
744 for (
const QString &candidate : sPartialCandidates )
746 if ( layerName.contains( candidate, Qt::CaseInsensitive ) )
751 static const QStringList sWordCandidates{ u
"aster"_s };
752 for (
const QString &candidate : sWordCandidates )
754 const thread_local QRegularExpression re( u
"\\b%1\\b"_s.arg( candidate ) );
755 if ( re.match( layerName, Qt::CaseInsensitive ).hasMatch() )
762void QgsRasterLayerElevationProperties::setDefaultProfileLineSymbol(
const QColor &color )
764 auto profileLineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( color, 0.6 );
765 mProfileLineSymbol = std::make_unique< QgsLineSymbol>(
QgsSymbolLayerList( { profileLineLayer.release() } ) );
768void QgsRasterLayerElevationProperties::setDefaultProfileFillSymbol(
const QColor &color )
770 auto profileFillLayer = std::make_unique< QgsSimpleFillSymbolLayer >( color );
771 profileFillLayer->setStrokeStyle( Qt::NoPen );
772 mProfileFillSymbol = std::make_unique< QgsFillSymbol>(
QgsSymbolLayerList( { profileFillLayer.release() } ) );
777 return mRangePerBand;
782 if ( ranges == mRangePerBand )
785 mRangePerBand = ranges;
796 if ( range == mFixedRange )
RasterElevationMode
Raster layer elevation modes.
@ FixedRangePerBand
Layer has a fixed (manually specified) elevation range per band.
@ FixedElevationRange
Layer has a fixed elevation range.
@ RepresentsElevationSurface
Pixel values represent an elevation surface.
@ DynamicRangePerBand
Layer has a elevation range per band, calculated dynamically from an expression.
@ Float32
Thirty two bit floating point (float).
@ CFloat64
Complex Float64.
@ Int16
Sixteen bit signed integer (qint16).
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
@ Int8
Eight bit signed integer (qint8) (added in QGIS 3.30).
@ UInt16
Sixteen bit unsigned integer (quint16).
@ Byte
Eight bit unsigned integer (quint8).
@ UnknownDataType
Unknown or unspecified type.
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
@ Int32
Thirty two bit signed integer (qint32).
@ Float64
Sixty four bit floating point (double).
@ CFloat32
Complex Float32.
@ UInt32
Thirty two bit unsigned integer (quint32).
ProfileSurfaceSymbology
Surface symbology type for elevation profile plots.
@ Line
The elevation surface will be rendered using a line symbol.
static QgsColorSchemeRegistry * colorSchemeRegistry()
Returns the application's color scheme registry, used for managing color schemes.
QColor fetchRandomStyleColor() const
Returns a random color for use with a new symbol style (e.g.
QgsRange which stores a range of double values.
bool isInfinite() const
Returns true if the range consists of all possible values.
Single scope for storing variables and functions for use within a QgsExpressionContext.
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
void setVariable(const QString &name, const QVariant &value, bool isStatic=false)
Convenience method for setting a variable in the context scope by name name and value.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
A line symbol type, for rendering LineString and MultiLineString geometries.
QgsPropertyCollection mDataDefinedProperties
Property collection for data defined elevation settings.
void writeCommonProperties(QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context)
Writes common class properties to a DOM element, to be used later with readXml().
void profileGenerationPropertyChanged()
Emitted when any of the elevation properties which relate solely to generation of elevation profiles ...
QgsMapLayerElevationProperties(QObject *parent)
Constructor for QgsMapLayerElevationProperties, with the specified parent object.
void readCommonProperties(const QDomElement &element, const QgsReadWriteContext &context)
Reads common class properties from a DOM element previously written by writeXml().
void changed()
Emitted when any of the elevation properties have changed.
void profileRenderingPropertyChanged()
Emitted when any of the elevation properties which relate solely to presentation of elevation results...
@ RasterPerBandUpperElevation
Upper elevation for each raster band.
@ RasterPerBandLowerElevation
Lower elevation for each raster band.
@ FlagDontInvalidateCachedRendersWhenRangeChanges
Any cached rendering will not be invalidated when z range context is modified.
Base class for all map layer types.
A store for object properties.
double valueAsDouble(const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property and interprets it as a double.
bool prepare(const QgsExpressionContext &context=QgsExpressionContext()) const
Prepares the property against a specified expression context.
bool includeUpper() const
Returns true if the upper bound is inclusive, or false if the upper bound is exclusive.
bool overlaps(const QgsRange< T > &other) const
Returns true if this range overlaps another range.
T upper() const
Returns the upper bound of the range.
Base class for raster data providers.
virtual QString bandDescription(int bandNumber)
Returns the description for band bandNumber, or an empty string if the band is not valid or has not d...
QString displayBandName(int bandNumber) const
Generates a friendly, descriptive name for the specified bandNumber.
QgsDoubleRange fixedRange() const
Returns the fixed elevation range for the raster.
void setProfileFillSymbol(QgsFillSymbol *symbol)
Sets the fill symbol used to render the raster profile in elevation profile plots.
void setFixedRange(const QgsDoubleRange &range)
Sets the fixed elevation range for the raster.
~QgsRasterLayerElevationProperties() override
QgsDoubleRange elevationRangeForPixelValue(QgsRasterLayer *layer, int band, double pixelValue) const
Returns the elevation range corresponding to a raw pixel value from the specified band.
QList< double > significantZValues(QgsMapLayer *layer) const override
Returns a list of significant elevation/z-values for the specified layer, using the settings defined ...
Qgis::RasterElevationMode mode() const
Returns the elevation mode.
QgsLineSymbol * profileLineSymbol() const
Returns the line symbol used to render the raster profile in elevation profile plots.
bool hasElevation() const override
Returns true if the layer has an elevation or z component.
QgsRasterLayerElevationProperties * clone() const override
Creates a clone of the properties.
QgsDoubleRange calculateZRange(QgsMapLayer *layer) const override
Attempts to calculate the overall elevation or z range for the specified layer, using the settings de...
QgsMapLayerElevationProperties::Flags flags() const override
Returns flags associated to the elevation properties.
void setBandNumber(int band)
Sets the band number from which the elevation should be taken.
int bandForElevationRange(QgsRasterLayer *layer, const QgsDoubleRange &range) const
Returns the band corresponding to the specified range.
QString htmlSummary() const override
Returns a HTML formatted summary of the properties.
void setElevationLimit(double limit)
Sets the elevation limit, which is used when profileSymbology() is Qgis::ProfileSurfaceSymbology::Fil...
void setFixedRangePerBand(const QMap< int, QgsDoubleRange > &ranges)
Sets the fixed elevation range for each band.
bool isVisibleInZRange(const QgsDoubleRange &range, QgsMapLayer *layer=nullptr) const override
Returns true if the layer should be visible and rendered for the specified z range.
void setProfileSymbology(Qgis::ProfileSurfaceSymbology symbology)
Sets the symbology option used to render the raster profile in elevation profile plots.
QMap< int, QgsDoubleRange > fixedRangePerBand() const
Returns the fixed elevation range for each band.
static bool layerLooksLikeDem(QgsRasterLayer *layer)
Returns true if a raster layer looks like a DEM.
QDomElement writeXml(QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context) override
Writes the properties to a DOM element, to be used later with readXml().
QgsFillSymbol * profileFillSymbol() const
Returns the fill symbol used to render the raster profile in elevation profile plots.
double elevationLimit() const
Returns the elevation limit, which is used when profileSymbology() is Qgis::ProfileSurfaceSymbology::...
void setProfileLineSymbol(QgsLineSymbol *symbol)
Sets the line symbol used to render the raster profile in elevation profile plots.
void setMode(Qgis::RasterElevationMode mode)
Sets the elevation mode.
void setEnabled(bool enabled)
Sets whether the elevation properties are enabled, i.e.
QgsRasterLayerElevationProperties(QObject *parent)
Constructor for QgsRasterLayerElevationProperties, with the specified parent object.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context) override
Reads the elevation properties from a DOM element previously written by writeXml().
bool showByDefaultInElevationProfilePlots() const override
Returns true if the layer should be visible by default in newly created elevation profile plots.
Represents a raster layer.
QgsRasterAttributeTable * attributeTable(int bandNumber) const
Returns the (possibly NULL) raster attribute table for the given band bandNumber.
int bandCount() const
Returns the number of bands in this layer.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
A container for the context for various read/write operations on objects.
static std::unique_ptr< QgsSymbol > loadSymbol(const QDomElement &element, const QgsReadWriteContext &context)
Attempts to load a symbol from a DOM element.
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
#define BUILTIN_UNREACHABLE
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
QList< QgsSymbolLayer * > QgsSymbolLayerList
Single variable definition for use within a QgsExpressionContextScope.