Skip to content

Commit

Permalink
Add method to collate all used time ranges for layers in project
Browse files Browse the repository at this point in the history
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 cae8aae
Show file tree
Hide file tree
Showing 10 changed files with 133 additions and 7 deletions.
11 changes: 11 additions & 0 deletions python/core/auto_generated/qgsmaplayertemporalproperties.sip.in
Expand Up @@ -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

};

/************************************************************************
Expand Down
13 changes: 13 additions & 0 deletions python/core/auto_generated/qgstemporalutils.sip.in
Expand Up @@ -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
Expand Down
Expand Up @@ -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
{
Expand Down
5 changes: 5 additions & 0 deletions src/core/qgsmaplayertemporalproperties.cpp
Expand Up @@ -31,3 +31,8 @@ QgsDateTimeRange QgsMapLayerTemporalProperties::calculateTemporalExtent( QgsMapL
{
return QgsDateTimeRange();
}

QList<QgsDateTimeRange> QgsMapLayerTemporalProperties::allTemporalRanges( QgsMapLayer *layer ) const
{
return { calculateTemporalExtent( layer ) };
}
11 changes: 11 additions & 0 deletions src/core/qgsmaplayertemporalproperties.h
Expand Up @@ -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
26 changes: 21 additions & 5 deletions src/core/qgstemporalutils.cpp
Expand Up @@ -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;
Expand All @@ -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() )
Expand Down
13 changes: 13 additions & 0 deletions src/core/qgstemporalutils.h
Expand Up @@ -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
{
Expand Down
21 changes: 21 additions & 0 deletions src/core/raster/qgsrasterlayertemporalproperties.cpp
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/core/raster/qgsrasterlayertemporalproperties.h
Expand Up @@ -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
Expand Down
37 changes: 35 additions & 2 deletions tests/src/python/test_qgstemporalutils.py
Expand Up @@ -16,9 +16,9 @@
QgsTemporalUtils,
QgsRasterLayer,
QgsDateTimeRange,
QgsDateTimeRange,
QgsInterval,
QgsUnitTypes)
QgsUnitTypes,
QgsRasterLayerTemporalProperties)

from qgis.PyQt.QtCore import (QDate,
QTime,
Expand Down Expand Up @@ -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),
Expand Down

0 comments on commit cae8aae

Please sign in to comment.