QGIS API Documentation 3.39.0-Master (47f7b3a4989)
Loading...
Searching...
No Matches
qgsrasterlayertemporalproperties.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsrasterlayertemporalproperties.cpp
3 ---------------
4 begin : February 2020
5 copyright : (C) 2020 by Samweli Mwakisambwe
6 email : samweli at kartoza dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
20#include "qgsrasterlayer.h"
21
23 : QgsMapLayerTemporalProperties( parent, enabled )
24{
25 mTemporalRepresentationScale.setDays( 1.0 );
26}
27
29{
30 if ( !isActive() )
31 return true;
32
33 switch ( mMode )
34 {
36 return range.isInfinite() || mFixedRange.isInfinite() || mFixedRange.overlaps( range );
37
39 {
40 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
41 {
42 if ( it.value().overlaps( range ) )
43 return true;
44 }
45 return false;
46 }
47
51 return true;
52 }
53 return true;
54}
55
57{
58 QgsRasterLayer *rasterLayer = qobject_cast< QgsRasterLayer *>( layer );
59 if ( !rasterLayer )
60 return QgsDateTimeRange();
61
62 switch ( mMode )
63 {
65 return mFixedRange;
66
69
71 {
72 QDateTime begin;
73 QDateTime end;
74 bool includeBeginning = true;
75 bool includeEnd = true;
76 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
77 {
78 if ( it.value().begin() < begin || !begin.isValid() )
79 {
80 begin = it.value().begin();
81 includeBeginning = it.value().includeBeginning();
82 }
83 else if ( !includeBeginning && it.value().begin() == begin && it.value().includeBeginning() )
84 {
85 includeBeginning = true;
86 }
87 if ( it.value().end() > end || !end.isValid() )
88 {
89 end = it.value().end();
90 includeEnd = it.value().includeEnd();
91 }
92 else if ( !includeEnd && it.value().end() == end && it.value().includeEnd() )
93 {
94 includeEnd = true;
95 }
96 }
97 return QgsDateTimeRange( begin, end, includeBeginning, includeEnd );
98 }
99
102 break;
103 }
104
105 return QgsDateTimeRange();
106}
107
109{
110 QgsRasterLayer *rasterLayer = qobject_cast< QgsRasterLayer *>( layer );
111
112 switch ( mMode )
113 {
115 return { mFixedRange };
116
118 {
119 QList<QgsDateTimeRange> results;
120 results.reserve( mRangePerBand.size() );
121 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
122 {
123 results.append( it.value() );
124 }
125 return results;
126 }
127
129 {
130 if ( !rasterLayer || !rasterLayer->dataProvider() )
131 return {};
132
133 const QList< QgsDateTimeRange > ranges = rasterLayer->dataProvider()->temporalCapabilities()->allAvailableTemporalRanges();
134 return ranges.empty() ? QList< QgsDateTimeRange > { rasterLayer->dataProvider()->temporalCapabilities()->availableTemporalRange() } : ranges;
135 }
136
139 break;
140 }
141
142 return {};
143}
144
149
151{
152 if ( mMode == mode )
153 return;
154 mMode = mode;
155}
156
172
177
179{
180 if ( mIntervalHandlingMethod == method )
181 return;
182 mIntervalHandlingMethod = method;
183}
184
186{
187 mFixedRange = range;
188}
189
191{
192 return mFixedRange;
193}
194
196{
197 return mRangePerBand;
198}
199
200void QgsRasterLayerTemporalProperties::setFixedRangePerBand( const QMap<int, QgsDateTimeRange> &ranges )
201{
202 if ( mRangePerBand == ranges )
203 return;
204
205 mRangePerBand = ranges;
206 emit changed();
207}
208
210{
211 switch ( mMode )
212 {
216 return -1;
217
219 {
220 // find the latest-most band which matches the map range
221 int currentMatchingBand = -1;
222 QgsDateTimeRange currentMatchingRange;
223 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
224 {
225 if ( it.value().overlaps( range ) )
226 {
227 if ( currentMatchingRange.isInfinite()
228 || ( it.value().includeEnd() && it.value().end() >= currentMatchingRange.end() ) // cppcheck-suppress mismatchingContainerExpression
229 || ( !currentMatchingRange.includeEnd() && it.value().end() >= currentMatchingRange.end() ) ) // cppcheck-suppress mismatchingContainerExpression
230 {
231 currentMatchingBand = it.key();
232 currentMatchingRange = it.value();
233 }
234 }
235 }
236 return currentMatchingBand;
237 }
238
240 return mBandNumber;
241 }
243}
244
246{
247 switch ( mMode )
248 {
252 {
253 const int bandCount = layer->bandCount();
254 QList< int > res;
255 res.reserve( bandCount );
256 for ( int i = 1; i <= bandCount; ++i )
257 res.append( i );
258 return res;
259 }
260
262 {
263 QList<int> res;
264 res.reserve( mRangePerBand.size() );
265 // find the latest-most band which matches the map range
266 QgsDateTimeRange currentMatchingRange;
267 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
268 {
269 if ( it.value().overlaps( range ) )
270 {
271 res.append( it.key() );
272 }
273 }
274 return res;
275 }
276
278 return QList<int>() << mBandNumber;
279 }
281}
282
284{
285 return mBandNumber;
286}
287
289{
290 if ( mBandNumber == number )
291 return;
292
293 mBandNumber = number;
294}
295
297{
298 return mTemporalRepresentationOffset;
299}
300
302{
303 if ( mTemporalRepresentationOffset == offset )
304 return;
305
306 mTemporalRepresentationOffset = offset;
307}
308
310{
311 return mTemporalRepresentationScale;
312}
313
315{
316 if ( mTemporalRepresentationScale == scale )
317 return;
318
319 mTemporalRepresentationScale = scale;
320}
321
322bool QgsRasterLayerTemporalProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context )
323{
324 Q_UNUSED( context )
325 // TODO add support for raster layers with multi-temporal properties.
326
327 const QDomElement temporalNode = element.firstChildElement( QStringLiteral( "temporal" ) );
328
329 setIsActive( temporalNode.attribute( QStringLiteral( "enabled" ), QStringLiteral( "0" ) ).toInt() );
330
331 mMode = static_cast< Qgis::RasterTemporalMode >( temporalNode.attribute( QStringLiteral( "mode" ), QStringLiteral( "0" ) ). toInt() );
332 mBandNumber = temporalNode.attribute( QStringLiteral( "bandNumber" ), QStringLiteral( "1" ) ).toInt();
333 mIntervalHandlingMethod = static_cast< Qgis::TemporalIntervalMatchMethod >( temporalNode.attribute( QStringLiteral( "fetchMode" ), QStringLiteral( "0" ) ). toInt() );
334
335 switch ( mMode )
336 {
338 {
339 const QDomNode rangeElement = temporalNode.namedItem( QStringLiteral( "fixedRange" ) );
340
341 const QDomNode begin = rangeElement.namedItem( QStringLiteral( "start" ) );
342 const QDomNode end = rangeElement.namedItem( QStringLiteral( "end" ) );
343
344 const QDateTime beginDate = QDateTime::fromString( begin.toElement().text(), Qt::ISODate );
345 const QDateTime endDate = QDateTime::fromString( end.toElement().text(), Qt::ISODate );
346
347 const QgsDateTimeRange range = QgsDateTimeRange( beginDate, endDate );
348 setFixedTemporalRange( range );
349 break;
350 }
351
353 {
354 mRangePerBand.clear();
355
356 const QDomNodeList ranges = temporalNode.firstChildElement( QStringLiteral( "ranges" ) ).childNodes();
357 for ( int i = 0; i < ranges.size(); ++i )
358 {
359 const QDomElement rangeElement = ranges.at( i ).toElement();
360 const int band = rangeElement.attribute( QStringLiteral( "band" ) ).toInt();
361 const QDateTime begin = QDateTime::fromString( rangeElement.attribute( QStringLiteral( "begin" ) ), Qt::ISODate );
362 const QDateTime end = QDateTime::fromString( rangeElement.attribute( QStringLiteral( "end" ) ), Qt::ISODate );
363 const bool includeBeginning = rangeElement.attribute( QStringLiteral( "includeBeginning" ) ).toInt();
364 const bool includeEnd = rangeElement.attribute( QStringLiteral( "includeEnd" ) ).toInt();
365 mRangePerBand.insert( band, QgsDateTimeRange( begin, end, includeBeginning, includeEnd ) );
366 }
367 break;
368 }
369
371 {
372 mTemporalRepresentationOffset = QDateTime::fromString( temporalNode.attribute( QStringLiteral( "temporalRepresentationOffset" ) ), Qt::ISODate );
373 mTemporalRepresentationScale = QgsInterval( temporalNode.attribute( QStringLiteral( "temporalRepresentationScale" ), QStringLiteral( "1" ) ).toDouble(),
374 static_cast< Qgis::TemporalUnit >( temporalNode.attribute( QStringLiteral( "temporalRepresentationScaleUnit" ), QStringLiteral( "4" ) ).toInt() ) );
375 break;
376 }
377
380 break;
381 }
382
383 return true;
384}
385
386QDomElement QgsRasterLayerTemporalProperties::writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context )
387{
388 Q_UNUSED( context )
389 if ( element.isNull() )
390 return QDomElement();
391
392 QDomElement temporalElement = document.createElement( QStringLiteral( "temporal" ) );
393 temporalElement.setAttribute( QStringLiteral( "enabled" ), isActive() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
394 temporalElement.setAttribute( QStringLiteral( "mode" ), QString::number( static_cast< int >( mMode ) ) );
395 temporalElement.setAttribute( QStringLiteral( "bandNumber" ), QString::number( mBandNumber ) );
396 temporalElement.setAttribute( QStringLiteral( "fetchMode" ), QString::number( static_cast< int >( mIntervalHandlingMethod ) ) );
397
398 switch ( mMode )
399 {
401 {
402
403 QDomElement rangeElement = document.createElement( QStringLiteral( "fixedRange" ) );
404
405 QDomElement startElement = document.createElement( QStringLiteral( "start" ) );
406 QDomElement endElement = document.createElement( QStringLiteral( "end" ) );
407
408 const QDomText startText = document.createTextNode( mFixedRange.begin().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODate ) );
409 const QDomText endText = document.createTextNode( mFixedRange.end().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODate ) );
410 startElement.appendChild( startText );
411 endElement.appendChild( endText );
412 rangeElement.appendChild( startElement );
413 rangeElement.appendChild( endElement );
414
415 temporalElement.appendChild( rangeElement );
416 break;
417 }
418
420 {
421 QDomElement ranges = document.createElement( QStringLiteral( "ranges" ) );
422 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
423 {
424 QDomElement range = document.createElement( QStringLiteral( "range" ) );
425 range.setAttribute( QStringLiteral( "band" ), it.key() );
426 range.setAttribute( QStringLiteral( "begin" ), it.value().begin().toString( Qt::ISODate ) );
427 range.setAttribute( QStringLiteral( "end" ), it.value().end().toString( Qt::ISODate ) );
428 range.setAttribute( QStringLiteral( "includeBeginning" ), it.value().includeBeginning() ? "1" : "0" );
429 range.setAttribute( QStringLiteral( "includeEnd" ), it.value().includeEnd() ? "1" : "0" );
430 ranges.appendChild( range );
431 }
432 temporalElement.appendChild( ranges );
433 break;
434 }
435
437 {
438 temporalElement.setAttribute( QStringLiteral( "temporalRepresentationOffset" ), mTemporalRepresentationOffset.toString( Qt::ISODate ) );
439 temporalElement.setAttribute( QStringLiteral( "temporalRepresentationScale" ), QString::number( mTemporalRepresentationScale.originalDuration() ) );
440 temporalElement.setAttribute( QStringLiteral( "temporalRepresentationScaleUnit" ), QString::number( static_cast< int >( mTemporalRepresentationScale.originalUnit() ) ) );
441 break;
442 }
443
446 break;
447 }
448
449 element.appendChild( temporalElement );
450
451 return element;
452}
453
455{
456 if ( const QgsRasterDataProviderTemporalCapabilities *rasterCaps = dynamic_cast< const QgsRasterDataProviderTemporalCapabilities *>( capabilities ) )
457 {
458 setIsActive( rasterCaps->hasTemporalCapabilities() );
459 setFixedTemporalRange( rasterCaps->availableTemporalRange() );
460
461 if ( rasterCaps->hasTemporalCapabilities() )
462 {
464 }
465
466 mIntervalHandlingMethod = rasterCaps->intervalHandlingMethod();
467 }
468}
TemporalIntervalMatchMethod
Method to use when resolving a temporal range to a data provider layer or band.
Definition qgis.h:2255
TemporalUnit
Temporal units.
Definition qgis.h:4470
RasterTemporalMode
Raster layer temporal modes.
Definition qgis.h:2240
@ RepresentsTemporalValues
Pixel values represent an datetime.
@ RedrawLayerOnly
Redraw the layer when temporal range changes, but don't apply any filtering. Useful when raster symbo...
@ FixedRangePerBand
Layer has a fixed temporal range per band (since QGIS 3.38)
@ TemporalRangeFromDataProvider
Mode when raster layer delegates temporal range handling to the dataprovider.
@ FixedTemporalRange
Mode when temporal properties have fixed start and end datetimes.
Base class for handling properties relating to a data provider's temporal capabilities.
A representation of the interval between two datetime values.
Definition qgsinterval.h:46
double originalDuration() const
Returns the original interval duration.
Qgis::TemporalUnit originalUnit() const
Returns the original interval temporal unit.
void setDays(double days)
Sets the interval duration in days.
Base class for storage of map layer temporal properties.
Base class for all map layer types.
Definition qgsmaplayer.h:75
Implementation of data provider temporal properties for QgsRasterDataProviders.
QList< QgsDateTimeRange > allAvailableTemporalRanges() const
Returns a list of all valid datetime ranges for which temporal data is available from the provider.
const QgsDateTimeRange & availableTemporalRange() const
Returns the overall datetime range extent from which temporal data is available from the provider.
QgsRasterDataProviderTemporalCapabilities * temporalCapabilities() override
Returns the provider's temporal capabilities.
QDomElement writeXml(QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context) override
Writes the properties to a DOM element, to be used later with readXml().
QDateTime temporalRepresentationOffset() const
Returns the temporal offset, which is a fixed datetime which should be added to individual pixel valu...
void setDefaultsFromDataProviderTemporalCapabilities(const QgsDataProviderTemporalCapabilities *capabilities) override
Sets the layers temporal settings to appropriate defaults based on a provider's temporal capabilities...
bool isVisibleInTemporalRange(const QgsDateTimeRange &range) const override
Returns true if the layer should be visible and rendered for the specified time range.
QgsTemporalProperty::Flags flags() const override
Returns flags associated to the temporal property.
QList< int > filteredBandsForTemporalRange(QgsRasterLayer *layer, const QgsDateTimeRange &range) const
Returns a filtered list of bands which match the specified range.
void setTemporalRepresentationOffset(const QDateTime &offset)
Sets the temporal offset, which is a fixed datetime which should be added to individual pixel values ...
Qgis::TemporalIntervalMatchMethod intervalHandlingMethod() const
Returns the desired method to use when resolving a temporal interval to matching layers or bands in t...
const QgsInterval & temporalRepresentationScale() const
Returns the scale, which is an interval factor which should be applied to individual pixel values fro...
void setIntervalHandlingMethod(Qgis::TemporalIntervalMatchMethod method)
Sets the desired method to use when resolving a temporal interval to matching layers or bands in the ...
Qgis::RasterTemporalMode mode() const
Returns the temporal properties mode.
void setTemporalRepresentationScale(const QgsInterval &scale)
Sets the scale, which is an interval factor which should be applied to individual pixel values from t...
int bandForTemporalRange(QgsRasterLayer *layer, const QgsDateTimeRange &range) const
Returns the band corresponding to the specified range.
QList< QgsDateTimeRange > allTemporalRanges(QgsMapLayer *layer) const override
Attempts to calculate the overall list of all temporal extents which are contained in the specified l...
void setMode(Qgis::RasterTemporalMode mode)
Sets the temporal properties mode.
QgsRasterLayerTemporalProperties(QObject *parent=nullptr, bool enabled=false)
Constructor for QgsRasterLayerTemporalProperties, with the specified parent object.
void setFixedTemporalRange(const QgsDateTimeRange &range)
Sets a temporal range to apply to the whole layer.
void setFixedRangePerBand(const QMap< int, QgsDateTimeRange > &ranges)
Sets the fixed temporal range for each band.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context) override
Reads temporal properties from a DOM element previously written by writeXml().
QMap< int, QgsDateTimeRange > fixedRangePerBand() const
Returns the fixed temporal range for each band.
int bandNumber() const
Returns the band number from which temporal values should be taken.
const QgsDateTimeRange & fixedTemporalRange() const
Returns the fixed temporal range for the layer.
QgsDateTimeRange calculateTemporalExtent(QgsMapLayer *layer) const override
Attempts to calculate the overall temporal extent for the specified layer, using the settings defined...
void setBandNumber(int number)
Sets the band number from which temporal values should be taken.
Represents a raster layer.
int bandCount() const
Returns the number of bands in this layer.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
The class is used as a container of context for various read/write operations on other objects.
void changed()
Emitted when the temporal properties have changed.
bool isActive() const
Returns true if the temporal property is active.
void setIsActive(bool active)
Sets whether the temporal property is active.
@ FlagDontInvalidateCachedRendersWhenRangeChanges
Any cached rendering will not be invalidated when temporal range context is modified.
T begin() const
Returns the beginning of the range.
Definition qgsrange.h:444
T end() const
Returns the upper bound of the range.
Definition qgsrange.h:451
bool overlaps(const QgsTemporalRange< T > &other) const
Returns true if this range overlaps another range.
Definition qgsrange.h:569
bool includeEnd() const
Returns true if the end is inclusive, or false if the end is exclusive.
Definition qgsrange.h:466
bool isInfinite() const
Returns true if the range consists of all possible values.
Definition qgsrange.h:480
#define BUILTIN_UNREACHABLE
Definition qgis.h:6119
QgsTemporalRange< QDateTime > QgsDateTimeRange
QgsRange which stores a range of date times.
Definition qgsrange.h:742