QGIS API Documentation 3.99.0-Master (752b475928d)
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 "moc_qgsrasterlayertemporalproperties.cpp"
24
26 : QgsMapLayerTemporalProperties( parent, enabled )
27{
28 mTemporalRepresentationScale.setDays( 1.0 );
29}
30
32{
33 if ( !isActive() )
34 return true;
35
36 switch ( mMode )
37 {
40 return range.isInfinite() || mFixedRange.isInfinite() || mFixedRange.overlaps( range );
41
43 {
44 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
45 {
46 if ( it.value().overlaps( range ) )
47 return true;
48 }
49 return false;
50 }
51
55 return true;
56 }
57 return true;
58}
59
61{
62 QgsRasterLayer *rasterLayer = qobject_cast< QgsRasterLayer *>( layer );
63 if ( !rasterLayer )
64 return QgsDateTimeRange();
65
66 switch ( mMode )
67 {
70 return mFixedRange;
71
74
76 {
77 QDateTime begin;
78 QDateTime end;
79 bool includeBeginning = true;
80 bool includeEnd = true;
81 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
82 {
83 if ( it.value().begin() < begin || !begin.isValid() )
84 {
85 begin = it.value().begin();
86 includeBeginning = it.value().includeBeginning();
87 }
88 else if ( !includeBeginning && it.value().begin() == begin && it.value().includeBeginning() )
89 {
90 includeBeginning = true;
91 }
92 if ( it.value().end() > end || !end.isValid() )
93 {
94 end = it.value().end();
95 includeEnd = it.value().includeEnd();
96 }
97 else if ( !includeEnd && it.value().end() == end && it.value().includeEnd() )
98 {
99 includeEnd = true;
100 }
101 }
102 return QgsDateTimeRange( begin, end, includeBeginning, includeEnd );
103 }
104
107 break;
108 }
109
110 return QgsDateTimeRange();
111}
112
114{
115 QgsRasterLayer *rasterLayer = qobject_cast< QgsRasterLayer *>( layer );
116
117 switch ( mMode )
118 {
121 return { mFixedRange };
122
124 {
125 QList<QgsDateTimeRange> results;
126 results.reserve( mRangePerBand.size() );
127 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
128 {
129 results.append( it.value() );
130 }
131 return results;
132 }
133
135 {
136 if ( !rasterLayer || !rasterLayer->dataProvider() )
137 return {};
138
139 const QList< QgsDateTimeRange > ranges = rasterLayer->dataProvider()->temporalCapabilities()->allAvailableTemporalRanges();
140 return ranges.empty() ? QList< QgsDateTimeRange > { rasterLayer->dataProvider()->temporalCapabilities()->availableTemporalRange() } : ranges;
141 }
142
145 break;
146 }
147
148 return {};
149}
150
155
157{
158 if ( mMode == mode )
159 return;
160 mMode = mode;
161}
162
179
184
186{
187 if ( mIntervalHandlingMethod == method )
188 return;
189 mIntervalHandlingMethod = method;
190}
191
193{
194 mFixedRange = range;
195}
196
198{
199 return mFixedRange;
200}
201
203{
204 return mRangePerBand;
205}
206
207void QgsRasterLayerTemporalProperties::setFixedRangePerBand( const QMap<int, QgsDateTimeRange> &ranges )
208{
209 if ( mRangePerBand == ranges )
210 return;
211
212 mRangePerBand = ranges;
213 emit changed();
214}
215
217{
218 switch ( mMode )
219 {
224 return -1;
225
227 {
228 // find the latest-most band which matches the map range
229 int currentMatchingBand = -1;
230 QgsDateTimeRange currentMatchingRange;
231 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
232 {
233 if ( it.value().overlaps( range ) )
234 {
235 if ( currentMatchingRange.isInfinite()
236 || ( it.value().includeEnd() && it.value().end() >= currentMatchingRange.end() ) // cppcheck-suppress mismatchingContainerExpression
237 || ( !currentMatchingRange.includeEnd() && it.value().end() >= currentMatchingRange.end() ) ) // cppcheck-suppress mismatchingContainerExpression
238 {
239 currentMatchingBand = it.key();
240 currentMatchingRange = it.value();
241 }
242 }
243 }
244 return currentMatchingBand;
245 }
246
248 return mBandNumber;
249 }
251}
252
254{
255 switch ( mMode )
256 {
261 {
262 const int bandCount = layer->bandCount();
263 QList< int > res;
264 res.reserve( bandCount );
265 for ( int i = 1; i <= bandCount; ++i )
266 res.append( i );
267 return res;
268 }
269
271 {
272 QList<int> res;
273 res.reserve( mRangePerBand.size() );
274 // find the latest-most band which matches the map range
275 QgsDateTimeRange currentMatchingRange;
276 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
277 {
278 if ( it.value().overlaps( range ) )
279 {
280 res.append( it.key() );
281 }
282 }
283 return res;
284 }
285
287 return QList<int>() << mBandNumber;
288 }
290}
291
293{
294 return mBandNumber;
295}
296
298{
299 if ( mBandNumber == number )
300 return;
301
302 mBandNumber = number;
303}
304
306{
307 return mTemporalRepresentationOffset;
308}
309
311{
312 if ( mTemporalRepresentationOffset == offset )
313 return;
314
315 mTemporalRepresentationOffset = offset;
316}
317
319{
320 return mAccumulatePixels;
321}
322
324{
325 mAccumulatePixels = accumulate;
326}
327
329{
330 return mTemporalRepresentationScale;
331}
332
334{
335 if ( mTemporalRepresentationScale == scale )
336 return;
337
338 mTemporalRepresentationScale = scale;
339}
340
341bool QgsRasterLayerTemporalProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context )
342{
343 Q_UNUSED( context )
344 // TODO add support for raster layers with multi-temporal properties.
345
346 const QDomElement temporalNode = element.firstChildElement( QStringLiteral( "temporal" ) );
347
348 setIsActive( temporalNode.attribute( QStringLiteral( "enabled" ), QStringLiteral( "0" ) ).toInt() );
349
350 mMode = static_cast< Qgis::RasterTemporalMode >( temporalNode.attribute( QStringLiteral( "mode" ), QStringLiteral( "0" ) ). toInt() );
351 mBandNumber = temporalNode.attribute( QStringLiteral( "bandNumber" ), QStringLiteral( "1" ) ).toInt();
352 mIntervalHandlingMethod = static_cast< Qgis::TemporalIntervalMatchMethod >( temporalNode.attribute( QStringLiteral( "fetchMode" ), QStringLiteral( "0" ) ). toInt() );
353
354 switch ( mMode )
355 {
357 {
358 const QDomNode instantElement = temporalNode.namedItem( QStringLiteral( "fixedInstant" ) );
359 const QDateTime date = QDateTime::fromString( instantElement.toElement().text(), Qt::ISODate );
360
361 const QgsDateTimeRange range = QgsDateTimeRange( date, date );
362 setFixedTemporalRange( range );
363 break;
364 }
365
367 {
368 const QDomNode rangeElement = temporalNode.namedItem( QStringLiteral( "fixedRange" ) );
369
370 const QDomNode begin = rangeElement.namedItem( QStringLiteral( "start" ) );
371 const QDomNode end = rangeElement.namedItem( QStringLiteral( "end" ) );
372
373 const QDateTime beginDate = QDateTime::fromString( begin.toElement().text(), Qt::ISODate );
374 const QDateTime endDate = QDateTime::fromString( end.toElement().text(), Qt::ISODate );
375
376 const QgsDateTimeRange range = QgsDateTimeRange( beginDate, endDate );
377 setFixedTemporalRange( range );
378 break;
379 }
380
382 {
383 mRangePerBand.clear();
384
385 const QDomNodeList ranges = temporalNode.firstChildElement( QStringLiteral( "ranges" ) ).childNodes();
386 for ( int i = 0; i < ranges.size(); ++i )
387 {
388 const QDomElement rangeElement = ranges.at( i ).toElement();
389 const int band = rangeElement.attribute( QStringLiteral( "band" ) ).toInt();
390 const QDateTime begin = QDateTime::fromString( rangeElement.attribute( QStringLiteral( "begin" ) ), Qt::ISODate );
391 const QDateTime end = QDateTime::fromString( rangeElement.attribute( QStringLiteral( "end" ) ), Qt::ISODate );
392 const bool includeBeginning = rangeElement.attribute( QStringLiteral( "includeBeginning" ) ).toInt();
393 const bool includeEnd = rangeElement.attribute( QStringLiteral( "includeEnd" ) ).toInt();
394 mRangePerBand.insert( band, QgsDateTimeRange( begin, end, includeBeginning, includeEnd ) );
395 }
396 break;
397 }
398
400 {
401 mTemporalRepresentationOffset = QDateTime::fromString( temporalNode.attribute( QStringLiteral( "temporalRepresentationOffset" ) ), Qt::ISODate );
402 mAccumulatePixels = temporalNode.attribute( QStringLiteral( "accumulate" ), QStringLiteral( "0" ) ).toInt();
403 mTemporalRepresentationScale = QgsInterval( temporalNode.attribute( QStringLiteral( "temporalRepresentationScale" ), QStringLiteral( "1" ) ).toDouble(),
404 static_cast< Qgis::TemporalUnit >( temporalNode.attribute( QStringLiteral( "temporalRepresentationScaleUnit" ), QStringLiteral( "4" ) ).toInt() ) );
405 break;
406 }
407
410 break;
411 }
412
413 return true;
414}
415
416QDomElement QgsRasterLayerTemporalProperties::writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context )
417{
418 Q_UNUSED( context )
419 if ( element.isNull() )
420 return QDomElement();
421
422 QDomElement temporalElement = document.createElement( QStringLiteral( "temporal" ) );
423 temporalElement.setAttribute( QStringLiteral( "enabled" ), isActive() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
424 temporalElement.setAttribute( QStringLiteral( "mode" ), QString::number( static_cast< int >( mMode ) ) );
425 temporalElement.setAttribute( QStringLiteral( "bandNumber" ), QString::number( mBandNumber ) );
426 temporalElement.setAttribute( QStringLiteral( "fetchMode" ), QString::number( static_cast< int >( mIntervalHandlingMethod ) ) );
427
428 switch ( mMode )
429 {
431 {
432 QDomElement instantElement = document.createElement( QStringLiteral( "fixedInstant" ) );
433 const QDomText instantText = document.createTextNode( mFixedRange.begin().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODate ) );
434 instantElement.appendChild( instantText );
435
436 temporalElement.appendChild( instantElement );
437 break;
438 }
439
441 {
442
443 QDomElement rangeElement = document.createElement( QStringLiteral( "fixedRange" ) );
444
445 QDomElement startElement = document.createElement( QStringLiteral( "start" ) );
446 QDomElement endElement = document.createElement( QStringLiteral( "end" ) );
447
448 const QDomText startText = document.createTextNode( mFixedRange.begin().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODate ) );
449 const QDomText endText = document.createTextNode( mFixedRange.end().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODate ) );
450 startElement.appendChild( startText );
451 endElement.appendChild( endText );
452 rangeElement.appendChild( startElement );
453 rangeElement.appendChild( endElement );
454
455 temporalElement.appendChild( rangeElement );
456 break;
457 }
458
460 {
461 QDomElement ranges = document.createElement( QStringLiteral( "ranges" ) );
462 for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
463 {
464 QDomElement range = document.createElement( QStringLiteral( "range" ) );
465 range.setAttribute( QStringLiteral( "band" ), it.key() );
466 range.setAttribute( QStringLiteral( "begin" ), it.value().begin().toString( Qt::ISODate ) );
467 range.setAttribute( QStringLiteral( "end" ), it.value().end().toString( Qt::ISODate ) );
468 range.setAttribute( QStringLiteral( "includeBeginning" ), it.value().includeBeginning() ? "1" : "0" );
469 range.setAttribute( QStringLiteral( "includeEnd" ), it.value().includeEnd() ? "1" : "0" );
470 ranges.appendChild( range );
471 }
472 temporalElement.appendChild( ranges );
473 break;
474 }
475
477 {
478 temporalElement.setAttribute( QStringLiteral( "temporalRepresentationOffset" ), mTemporalRepresentationOffset.toString( Qt::ISODate ) );
479 temporalElement.setAttribute( QStringLiteral( "accumulate" ), mAccumulatePixels ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
480 temporalElement.setAttribute( QStringLiteral( "temporalRepresentationScale" ), QString::number( mTemporalRepresentationScale.originalDuration() ) );
481 temporalElement.setAttribute( QStringLiteral( "temporalRepresentationScaleUnit" ), QString::number( static_cast< int >( mTemporalRepresentationScale.originalUnit() ) ) );
482 break;
483 }
484
487 break;
488 }
489
490 element.appendChild( temporalElement );
491
492 return element;
493}
494
496{
497 if ( const QgsRasterDataProviderTemporalCapabilities *rasterCaps = dynamic_cast< const QgsRasterDataProviderTemporalCapabilities *>( capabilities ) )
498 {
499 setIsActive( rasterCaps->hasTemporalCapabilities() );
500 setFixedTemporalRange( rasterCaps->availableTemporalRange() );
501
502 if ( rasterCaps->hasTemporalCapabilities() )
503 {
505 }
506
507 mIntervalHandlingMethod = rasterCaps->intervalHandlingMethod();
508 }
509}
TemporalIntervalMatchMethod
Method to use when resolving a temporal range to a data provider layer or band.
Definition qgis.h:2637
TemporalUnit
Temporal units.
Definition qgis.h:5159
RasterTemporalMode
Raster layer temporal modes.
Definition qgis.h:2621
@ RepresentsTemporalValues
Pixel values represent an datetime.
Definition qgis.h:2626
@ RedrawLayerOnly
Redraw the layer when temporal range changes, but don't apply any filtering. Useful when raster symbo...
Definition qgis.h:2624
@ FixedRangePerBand
Layer has a fixed temporal range per band.
Definition qgis.h:2625
@ TemporalRangeFromDataProvider
Mode when raster layer delegates temporal range handling to the dataprovider.
Definition qgis.h:2623
@ FixedTemporalRange
Mode when temporal properties have fixed start and end datetimes.
Definition qgis.h:2622
@ FixedDateTime
Layer has a fixed date time instant.
Definition qgis.h:2627
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:47
QgsMapLayerTemporalProperties(QObject *parent, bool enabled=false)
Constructor for QgsMapLayerTemporalProperties, with the specified parent object.
Base class for all map layer types.
Definition qgsmaplayer.h:80
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:453
bool includeEnd() const
Returns true if the end is inclusive, or false if the end is exclusive.
Definition qgsrange.h:468
bool isInfinite() const
Returns true if the range consists of all possible values.
Definition qgsrange.h:482
#define BUILTIN_UNREACHABLE
Definition qgis.h:7208
QgsTemporalRange< QDateTime > QgsDateTimeRange
QgsRange which stores a range of date times.
Definition qgsrange.h:761