QGIS API Documentation 3.99.0-Master (09f76ad7019)
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
19
21#include "qgsrasterlayer.h"
22
23#include <QString>
24
25#include "moc_qgsrasterlayertemporalproperties.cpp"
26
27using namespace Qt::StringLiterals;
28
30 : QgsMapLayerTemporalProperties( parent, enabled )
31{
32 mTemporalRepresentationScale.setDays( 1.0 );
33}
34
36{
37 if ( !isActive() )
38 return true;
39
40 switch ( mMode )
41 {
44 return range.isInfinite() || mFixedRange.isInfinite() || mFixedRange.overlaps( range );
45
47 {
48 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
49 {
50 if ( it.value().overlaps( range ) )
51 return true;
52 }
53 return false;
54 }
55
59 return true;
60 }
61 return true;
62}
63
65{
66 QgsRasterLayer *rasterLayer = qobject_cast< QgsRasterLayer *>( layer );
67 if ( !rasterLayer )
68 return QgsDateTimeRange();
69
70 switch ( mMode )
71 {
74 return mFixedRange;
75
78
80 {
81 QDateTime begin;
82 QDateTime end;
83 bool includeBeginning = true;
84 bool includeEnd = true;
85 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
86 {
87 if ( it.value().begin() < begin || !begin.isValid() )
88 {
89 begin = it.value().begin();
90 includeBeginning = it.value().includeBeginning();
91 }
92 else if ( !includeBeginning && it.value().begin() == begin && it.value().includeBeginning() )
93 {
94 includeBeginning = true;
95 }
96 if ( it.value().end() > end || !end.isValid() )
97 {
98 end = it.value().end();
99 includeEnd = it.value().includeEnd();
100 }
101 else if ( !includeEnd && it.value().end() == end && it.value().includeEnd() )
102 {
103 includeEnd = true;
104 }
105 }
106 return QgsDateTimeRange( begin, end, includeBeginning, includeEnd );
107 }
108
111 break;
112 }
113
114 return QgsDateTimeRange();
115}
116
118{
119 QgsRasterLayer *rasterLayer = qobject_cast< QgsRasterLayer *>( layer );
120
121 switch ( mMode )
122 {
125 return { mFixedRange };
126
128 {
129 QList<QgsDateTimeRange> results;
130 results.reserve( mRangePerBand.size() );
131 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
132 {
133 results.append( it.value() );
134 }
135 return results;
136 }
137
139 {
140 if ( !rasterLayer || !rasterLayer->dataProvider() )
141 return {};
142
143 const QList< QgsDateTimeRange > ranges = rasterLayer->dataProvider()->temporalCapabilities()->allAvailableTemporalRanges();
144 return ranges.empty() ? QList< QgsDateTimeRange > { rasterLayer->dataProvider()->temporalCapabilities()->availableTemporalRange() } : ranges;
145 }
146
149 break;
150 }
151
152 return {};
153}
154
159
161{
162 if ( mMode == mode )
163 return;
164 mMode = mode;
165}
166
183
188
190{
191 if ( mIntervalHandlingMethod == method )
192 return;
193 mIntervalHandlingMethod = method;
194}
195
197{
198 mFixedRange = range;
199}
200
202{
203 return mFixedRange;
204}
205
207{
208 return mRangePerBand;
209}
210
211void QgsRasterLayerTemporalProperties::setFixedRangePerBand( const QMap<int, QgsDateTimeRange> &ranges )
212{
213 if ( mRangePerBand == ranges )
214 return;
215
216 mRangePerBand = ranges;
217 emit changed();
218}
219
221{
222 switch ( mMode )
223 {
228 return -1;
229
231 {
232 // find the latest-most band which matches the map range
233 int currentMatchingBand = -1;
234 QgsDateTimeRange currentMatchingRange;
235 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
236 {
237 if ( it.value().overlaps( range ) )
238 {
239 if ( currentMatchingRange.isInfinite()
240 || ( it.value().includeEnd() && it.value().end() >= currentMatchingRange.end() ) // cppcheck-suppress mismatchingContainerExpression
241 || ( !currentMatchingRange.includeEnd() && it.value().end() >= currentMatchingRange.end() ) ) // cppcheck-suppress mismatchingContainerExpression
242 {
243 currentMatchingBand = it.key();
244 currentMatchingRange = it.value();
245 }
246 }
247 }
248 return currentMatchingBand;
249 }
250
252 return mBandNumber;
253 }
255}
256
258{
259 switch ( mMode )
260 {
265 {
266 const int bandCount = layer->bandCount();
267 QList< int > res;
268 res.reserve( bandCount );
269 for ( int i = 1; i <= bandCount; ++i )
270 res.append( i );
271 return res;
272 }
273
275 {
276 QList<int> res;
277 res.reserve( mRangePerBand.size() );
278 // find the latest-most band which matches the map range
279 QgsDateTimeRange currentMatchingRange;
280 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
281 {
282 if ( it.value().overlaps( range ) )
283 {
284 res.append( it.key() );
285 }
286 }
287 return res;
288 }
289
291 return QList<int>() << mBandNumber;
292 }
294}
295
297{
298 return mBandNumber;
299}
300
302{
303 if ( mBandNumber == number )
304 return;
305
306 mBandNumber = number;
307}
308
310{
311 return mTemporalRepresentationOffset;
312}
313
315{
316 if ( mTemporalRepresentationOffset == offset )
317 return;
318
319 mTemporalRepresentationOffset = offset;
320}
321
323{
324 return mAccumulatePixels;
325}
326
328{
329 mAccumulatePixels = accumulate;
330}
331
333{
334 return mTemporalRepresentationScale;
335}
336
338{
339 if ( mTemporalRepresentationScale == scale )
340 return;
341
342 mTemporalRepresentationScale = scale;
343}
344
345bool QgsRasterLayerTemporalProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context )
346{
347 Q_UNUSED( context )
348 // TODO add support for raster layers with multi-temporal properties.
349
350 const QDomElement temporalNode = element.firstChildElement( u"temporal"_s );
351
352 setIsActive( temporalNode.attribute( u"enabled"_s, u"0"_s ).toInt() );
353
354 mMode = static_cast< Qgis::RasterTemporalMode >( temporalNode.attribute( u"mode"_s, u"0"_s ). toInt() );
355 mBandNumber = temporalNode.attribute( u"bandNumber"_s, u"1"_s ).toInt();
356 mIntervalHandlingMethod = static_cast< Qgis::TemporalIntervalMatchMethod >( temporalNode.attribute( u"fetchMode"_s, u"0"_s ). toInt() );
357
358 switch ( mMode )
359 {
361 {
362 const QDomNode instantElement = temporalNode.namedItem( u"fixedInstant"_s );
363 const QDateTime date = QDateTime::fromString( instantElement.toElement().text(), Qt::ISODate );
364
365 const QgsDateTimeRange range = QgsDateTimeRange( date, date );
366 setFixedTemporalRange( range );
367 break;
368 }
369
371 {
372 const QDomNode rangeElement = temporalNode.namedItem( u"fixedRange"_s );
373
374 const QDomNode begin = rangeElement.namedItem( u"start"_s );
375 const QDomNode end = rangeElement.namedItem( u"end"_s );
376
377 const QDateTime beginDate = QDateTime::fromString( begin.toElement().text(), Qt::ISODate );
378 const QDateTime endDate = QDateTime::fromString( end.toElement().text(), Qt::ISODate );
379
380 const QgsDateTimeRange range = QgsDateTimeRange( beginDate, endDate );
381 setFixedTemporalRange( range );
382 break;
383 }
384
386 {
387 mRangePerBand.clear();
388
389 const QDomNodeList ranges = temporalNode.firstChildElement( u"ranges"_s ).childNodes();
390 for ( int i = 0; i < ranges.size(); ++i )
391 {
392 const QDomElement rangeElement = ranges.at( i ).toElement();
393 const int band = rangeElement.attribute( u"band"_s ).toInt();
394 const QDateTime begin = QDateTime::fromString( rangeElement.attribute( u"begin"_s ), Qt::ISODate );
395 const QDateTime end = QDateTime::fromString( rangeElement.attribute( u"end"_s ), Qt::ISODate );
396 const bool includeBeginning = rangeElement.attribute( u"includeBeginning"_s ).toInt();
397 const bool includeEnd = rangeElement.attribute( u"includeEnd"_s ).toInt();
398 mRangePerBand.insert( band, QgsDateTimeRange( begin, end, includeBeginning, includeEnd ) );
399 }
400 break;
401 }
402
404 {
405 mTemporalRepresentationOffset = QDateTime::fromString( temporalNode.attribute( u"temporalRepresentationOffset"_s ), Qt::ISODate );
406 mAccumulatePixels = temporalNode.attribute( u"accumulate"_s, u"0"_s ).toInt();
407 mTemporalRepresentationScale = QgsInterval( temporalNode.attribute( u"temporalRepresentationScale"_s, u"1"_s ).toDouble(),
408 static_cast< Qgis::TemporalUnit >( temporalNode.attribute( u"temporalRepresentationScaleUnit"_s, u"4"_s ).toInt() ) );
409 break;
410 }
411
414 break;
415 }
416
417 return true;
418}
419
420QDomElement QgsRasterLayerTemporalProperties::writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context )
421{
422 Q_UNUSED( context )
423 if ( element.isNull() )
424 return QDomElement();
425
426 QDomElement temporalElement = document.createElement( u"temporal"_s );
427 temporalElement.setAttribute( u"enabled"_s, isActive() ? u"1"_s : u"0"_s );
428 temporalElement.setAttribute( u"mode"_s, QString::number( static_cast< int >( mMode ) ) );
429 temporalElement.setAttribute( u"bandNumber"_s, QString::number( mBandNumber ) );
430 temporalElement.setAttribute( u"fetchMode"_s, QString::number( static_cast< int >( mIntervalHandlingMethod ) ) );
431
432 switch ( mMode )
433 {
435 {
436 QDomElement instantElement = document.createElement( u"fixedInstant"_s );
437 const QDomText instantText = document.createTextNode( mFixedRange.begin().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODate ) );
438 instantElement.appendChild( instantText );
439
440 temporalElement.appendChild( instantElement );
441 break;
442 }
443
445 {
446
447 QDomElement rangeElement = document.createElement( u"fixedRange"_s );
448
449 QDomElement startElement = document.createElement( u"start"_s );
450 QDomElement endElement = document.createElement( u"end"_s );
451
452 const QDomText startText = document.createTextNode( mFixedRange.begin().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODate ) );
453 const QDomText endText = document.createTextNode( mFixedRange.end().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODate ) );
454 startElement.appendChild( startText );
455 endElement.appendChild( endText );
456 rangeElement.appendChild( startElement );
457 rangeElement.appendChild( endElement );
458
459 temporalElement.appendChild( rangeElement );
460 break;
461 }
462
464 {
465 QDomElement ranges = document.createElement( u"ranges"_s );
466 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
467 {
468 QDomElement range = document.createElement( u"range"_s );
469 range.setAttribute( u"band"_s, it.key() );
470 range.setAttribute( u"begin"_s, it.value().begin().toString( Qt::ISODate ) );
471 range.setAttribute( u"end"_s, it.value().end().toString( Qt::ISODate ) );
472 range.setAttribute( u"includeBeginning"_s, it.value().includeBeginning() ? "1" : "0" );
473 range.setAttribute( u"includeEnd"_s, it.value().includeEnd() ? "1" : "0" );
474 ranges.appendChild( range );
475 }
476 temporalElement.appendChild( ranges );
477 break;
478 }
479
481 {
482 temporalElement.setAttribute( u"temporalRepresentationOffset"_s, mTemporalRepresentationOffset.toString( Qt::ISODate ) );
483 temporalElement.setAttribute( u"accumulate"_s, mAccumulatePixels ? u"1"_s : u"0"_s );
484 temporalElement.setAttribute( u"temporalRepresentationScale"_s, QString::number( mTemporalRepresentationScale.originalDuration() ) );
485 temporalElement.setAttribute( u"temporalRepresentationScaleUnit"_s, QString::number( static_cast< int >( mTemporalRepresentationScale.originalUnit() ) ) );
486 break;
487 }
488
491 break;
492 }
493
494 element.appendChild( temporalElement );
495
496 return element;
497}
498
500{
501 if ( const QgsRasterDataProviderTemporalCapabilities *rasterCaps = dynamic_cast< const QgsRasterDataProviderTemporalCapabilities *>( capabilities ) )
502 {
503 setIsActive( rasterCaps->hasTemporalCapabilities() );
504 setFixedTemporalRange( rasterCaps->availableTemporalRange() );
505
506 if ( rasterCaps->hasTemporalCapabilities() )
507 {
509 }
510
511 mIntervalHandlingMethod = rasterCaps->intervalHandlingMethod();
512 }
513}
TemporalIntervalMatchMethod
Method to use when resolving a temporal range to a data provider layer or band.
Definition qgis.h:2695
TemporalUnit
Temporal units.
Definition qgis.h:5266
RasterTemporalMode
Raster layer temporal modes.
Definition qgis.h:2679
@ RepresentsTemporalValues
Pixel values represent an datetime.
Definition qgis.h:2684
@ RedrawLayerOnly
Redraw the layer when temporal range changes, but don't apply any filtering. Useful when raster symbo...
Definition qgis.h:2682
@ FixedRangePerBand
Layer has a fixed temporal range per band.
Definition qgis.h:2683
@ TemporalRangeFromDataProvider
Mode when raster layer delegates temporal range handling to the dataprovider.
Definition qgis.h:2681
@ FixedTemporalRange
Mode when temporal properties have fixed start and end datetimes.
Definition qgis.h:2680
@ FixedDateTime
Layer has a fixed date time instant.
Definition qgis.h:2685
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:50
QgsMapLayerTemporalProperties(QObject *parent, bool enabled=false)
Constructor for QgsMapLayerTemporalProperties, with the specified parent object.
Base class for all map layer types.
Definition qgsmaplayer.h:83
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 setAccumulatePixels(bool accumulate)
Sets whether pixels will be accumulated over time (i.e.
void setTemporalRepresentationScale(const QgsInterval &scale)
Sets the scale, which is an interval factor which should be applied to individual pixel values from t...
bool accumulatePixels() const
Returns true if pixels will be accumulated over time (i.e.
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.
A container for the context for various read/write operations on 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 end() const
Returns the upper bound of the range.
Definition qgsrange.h:456
bool includeEnd() const
Returns true if the end is inclusive, or false if the end is exclusive.
Definition qgsrange.h:471
bool isInfinite() const
Returns true if the range consists of all possible values.
Definition qgsrange.h:485
#define BUILTIN_UNREACHABLE
Definition qgis.h:7524
QgsTemporalRange< QDateTime > QgsDateTimeRange
QgsRange which stores a range of date times.
Definition qgsrange.h:764