Skip to content
Permalink
Browse files

Add method to collate all used time ranges for layers in project

Unlike the existing methods, this new method does not return
a single overall time range, but rather (possibly with gaps)
containing all time ranges were we know data actually exists
in the project.
  • Loading branch information
nyalldawson committed Mar 25, 2021
1 parent b7c1c3a commit cae8aae8491bf412129a89cabafcc11d1498d189
@@ -81,6 +81,17 @@ Sets the layers temporal settings to appropriate defaults based on
a provider's temporal ``capabilities``.
%End


virtual QList< QgsDateTimeRange > allTemporalRanges( QgsMapLayer *layer ) const;
%Docstring
Attempts to calculate the overall list of all temporal extents which are contained in the specified ``layer``, using
the settings defined by the temporal properties object.

May return an empty list if the ranges could not be calculated.

.. versionadded:: 3.20
%End

};

/************************************************************************
@@ -29,6 +29,19 @@ Calculates the temporal range for a ``project``.

This method considers the temporal range available from layers contained within the project and
returns the maximal combined temporal extent of these layers.
%End

static QList< QgsDateTimeRange > usedTemporalRangesForProject( QgsProject *project );
%Docstring
Calculates all temporal ranges which are in use for a ``project``.

This method considers the temporal range available from layers contained within the project and
returns a list of ranges which cover only the temporal ranges which are actually in use by layers
in the project.

The returned list may be non-contiguous and have gaps in the ranges. The ranges are sorted in ascending order.

.. versionadded:: 3.20
%End

struct AnimationExportSettings
@@ -32,6 +32,8 @@ The ``enabled`` argument specifies whether the temporal properties are initially

virtual bool isVisibleInTemporalRange( const QgsDateTimeRange &range ) const;

virtual QList< QgsDateTimeRange > allTemporalRanges( QgsMapLayer *layer ) const;


enum TemporalMode
{
@@ -31,3 +31,8 @@ QgsDateTimeRange QgsMapLayerTemporalProperties::calculateTemporalExtent( QgsMapL
{
return QgsDateTimeRange();
}

QList<QgsDateTimeRange> QgsMapLayerTemporalProperties::allTemporalRanges( QgsMapLayer *layer ) const
{
return { calculateTemporalExtent( layer ) };
}
@@ -117,6 +117,17 @@ class CORE_EXPORT QgsMapLayerTemporalProperties : public QgsTemporalProperty
*/
virtual QgsDateTimeRange calculateTemporalExtent( QgsMapLayer *layer ) const;
#endif

/**
* Attempts to calculate the overall list of all temporal extents which are contained in the specified \a layer, using
* the settings defined by the temporal properties object.
*
* May return an empty list if the ranges could not be calculated.
*
* \since QGIS 3.20
*/
virtual QList< QgsDateTimeRange > allTemporalRanges( QgsMapLayer *layer ) const;

};

#endif // QGSMAPLAYERTEMPORALPROPERTIES_H
@@ -30,15 +30,13 @@

QgsDateTimeRange QgsTemporalUtils::calculateTemporalRangeForProject( QgsProject *project )
{
const QMap<QString, QgsMapLayer *> &mapLayers = project->mapLayers();
QgsMapLayer *currentLayer = nullptr;

QMap<QString, QgsMapLayer *> mapLayers = project->mapLayers();
QDateTime minDate;
QDateTime maxDate;

for ( QMap<QString, QgsMapLayer *>::const_iterator it = mapLayers.constBegin(); it != mapLayers.constEnd(); ++it )
for ( auto it = mapLayers.constBegin(); it != mapLayers.constEnd(); ++it )
{
currentLayer = it.value();
QgsMapLayer *currentLayer = it.value();

if ( !currentLayer->temporalProperties() || !currentLayer->temporalProperties()->isActive() )
continue;
@@ -53,6 +51,24 @@ QgsDateTimeRange QgsTemporalUtils::calculateTemporalRangeForProject( QgsProject
return QgsDateTimeRange( minDate, maxDate );
}

QList< QgsDateTimeRange > QgsTemporalUtils::usedTemporalRangesForProject( QgsProject *project )
{
QMap<QString, QgsMapLayer *> mapLayers = project->mapLayers();

QList< QgsDateTimeRange > ranges;
for ( auto it = mapLayers.constBegin(); it != mapLayers.constEnd(); ++it )
{
QgsMapLayer *currentLayer = it.value();

if ( !currentLayer->temporalProperties() || !currentLayer->temporalProperties()->isActive() )
continue;

ranges.append( currentLayer->temporalProperties()->allTemporalRanges( currentLayer ) );
}

return QgsDateTimeRange::mergeRanges( ranges );
}

bool QgsTemporalUtils::exportAnimation( const QgsMapSettings &mapSettings, const QgsTemporalUtils::AnimationExportSettings &settings, QString &error, QgsFeedback *feedback )
{
if ( settings.fileNameTemplate.isEmpty() )
@@ -45,6 +45,19 @@ class CORE_EXPORT QgsTemporalUtils
*/
static QgsDateTimeRange calculateTemporalRangeForProject( QgsProject *project );

/**
* Calculates all temporal ranges which are in use for a \a project.
*
* This method considers the temporal range available from layers contained within the project and
* returns a list of ranges which cover only the temporal ranges which are actually in use by layers
* in the project.
*
* The returned list may be non-contiguous and have gaps in the ranges. The ranges are sorted in ascending order.
*
* \since QGIS 3.20
*/
static QList< QgsDateTimeRange > usedTemporalRangesForProject( QgsProject *project );

//! Contains settings relating to exporting animations
struct AnimationExportSettings
{
@@ -58,6 +58,27 @@ QgsDateTimeRange QgsRasterLayerTemporalProperties::calculateTemporalExtent( QgsM
return QgsDateTimeRange();
}

QList<QgsDateTimeRange> QgsRasterLayerTemporalProperties::allTemporalRanges( QgsMapLayer *layer ) const
{
QgsRasterLayer *rasterLayer = qobject_cast< QgsRasterLayer *>( layer );
if ( !rasterLayer )
return {};

switch ( mMode )
{
case QgsRasterLayerTemporalProperties::ModeFixedTemporalRange:
return { mFixedRange };

case QgsRasterLayerTemporalProperties::ModeTemporalRangeFromDataProvider:
{
QList< QgsDateTimeRange > ranges = rasterLayer->dataProvider()->temporalCapabilities()->allAvailableTemporalRanges();
return ranges.empty() ? QList< QgsDateTimeRange > { rasterLayer->dataProvider()->temporalCapabilities()->availableTemporalRange() } : ranges;
}
}

return {};
}

QgsRasterLayerTemporalProperties::TemporalMode QgsRasterLayerTemporalProperties::mode() const
{
return mMode;
@@ -47,6 +47,7 @@ class CORE_EXPORT QgsRasterLayerTemporalProperties : public QgsMapLayerTemporalP

bool isVisibleInTemporalRange( const QgsDateTimeRange &range ) const override;
QgsDateTimeRange calculateTemporalExtent( QgsMapLayer *layer ) const override SIP_SKIP;
QList< QgsDateTimeRange > allTemporalRanges( QgsMapLayer *layer ) const override;

/**
* Mode of the raster temporal properties
@@ -16,9 +16,9 @@
QgsTemporalUtils,
QgsRasterLayer,
QgsDateTimeRange,
QgsDateTimeRange,
QgsInterval,
QgsUnitTypes)
QgsUnitTypes,
QgsRasterLayerTemporalProperties)

from qgis.PyQt.QtCore import (QDate,
QTime,
@@ -55,6 +55,39 @@ def testTemporalRangeForProject(self):
self.assertEqual(range.begin(), QDateTime(QDate(2019, 1, 1), QTime(), Qt.UTC))
self.assertEqual(range.end(), QDateTime(QDate(2020, 7, 31), QTime(), Qt.UTC))

def testUsedTemporalRangesForProject(self):
p = QgsProject()
r1 = QgsRasterLayer('', '', 'wms')
r2 = QgsRasterLayer('', '', 'wms')
r3 = QgsRasterLayer('', '', 'wms')
r4 = QgsRasterLayer('', '', 'wms')
r1.temporalProperties().setIsActive(True)
r1.temporalProperties().setMode(QgsRasterLayerTemporalProperties.ModeTemporalRangeFromDataProvider)
r1.dataProvider().temporalCapabilities().setAvailableTemporalRange(QgsDateTimeRange(QDateTime(QDate(2020, 1, 1), QTime(), Qt.UTC),
QDateTime(QDate(2020, 3, 31), QTime(), Qt.UTC)))
r2.temporalProperties().setIsActive(True)
r2.temporalProperties().setMode(QgsRasterLayerTemporalProperties.ModeTemporalRangeFromDataProvider)
r2.dataProvider().temporalCapabilities().setAllAvailableTemporalRanges([QgsDateTimeRange(QDateTime(QDate(2020, 4, 1), QTime(), Qt.UTC),
QDateTime(QDate(2020, 7, 31), QTime(), Qt.UTC))])
r3.temporalProperties().setIsActive(True)
r3.temporalProperties().setMode(QgsRasterLayerTemporalProperties.ModeTemporalRangeFromDataProvider)
r3.dataProvider().temporalCapabilities().setAllAvailableTemporalRanges([QgsDateTimeRange(QDateTime(QDate(2019, 1, 1), QTime(), Qt.UTC),
QDateTime(QDate(2020, 2, 28), QTime(), Qt.UTC))])
r4.temporalProperties().setIsActive(True)
r4.temporalProperties().setMode(QgsRasterLayerTemporalProperties.ModeTemporalRangeFromDataProvider)
r4.dataProvider().temporalCapabilities().setAllAvailableTemporalRanges([QgsDateTimeRange(QDateTime(QDate(2021, 1, 1), QTime(), Qt.UTC),
QDateTime(QDate(2021, 2, 28), QTime(), Qt.UTC))])

p.addMapLayers([r1, r2, r3, r4])

ranges = QgsTemporalUtils.usedTemporalRangesForProject(p)
self.assertEqual(ranges, [QgsDateTimeRange(QDateTime(QDate(2019, 1, 1), QTime(), Qt.UTC),
QDateTime(QDate(2020, 3, 31), QTime(), Qt.UTC)),
QgsDateTimeRange(QDateTime(QDate(2020, 4, 1), QTime(), Qt.UTC),
QDateTime(QDate(2020, 7, 31), QTime(), Qt.UTC)),
QgsDateTimeRange(QDateTime(QDate(2021, 1, 1), QTime(), Qt.UTC),
QDateTime(QDate(2021, 2, 28), QTime(), Qt.UTC))])

def testFrameTimeCalculation(self):
expected = {QgsUnitTypes.TemporalMilliseconds: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 10), Qt.UTC),
QgsUnitTypes.TemporalSeconds: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 10, 0), Qt.UTC),

0 comments on commit cae8aae

Please sign in to comment.