Skip to content
Permalink
Browse files
[temporal] Fix broken animations when a non-integer interval value
is used (e.g. 1.5 hours)

The frame number was not being considered, making it impossible
to advance the animation
  • Loading branch information
nyalldawson committed Jun 3, 2021
1 parent 191e9f9 commit 81ec79c0e5d31f0e56413fdb01af320fbc00c564
@@ -79,7 +79,7 @@ support.
- error: will be set to a descriptive error message if the export fails
%End

static QDateTime calculateFrameTime( const QDateTime &start, const long long frame, const QgsInterval interval );
static QDateTime calculateFrameTime( const QDateTime &start, const long long frame, const QgsInterval &interval );
%Docstring
Calculates the frame time for an animation.

@@ -162,54 +162,50 @@ bool QgsTemporalUtils::exportAnimation( const QgsMapSettings &mapSettings, const
}


QDateTime QgsTemporalUtils::calculateFrameTime( const QDateTime &start, const long long frame, const QgsInterval interval )
QDateTime QgsTemporalUtils::calculateFrameTime( const QDateTime &start, const long long frame, const QgsInterval &interval )
{

double unused;
const bool isFractional = !qgsDoubleNear( fabs( modf( interval.originalDuration(), &unused ) ), 0.0 );

if ( isFractional || interval.originalUnit() == QgsUnitTypes::TemporalUnit::TemporalUnknownUnit )
{
return start + interval;
const double duration = interval.seconds();
return start.addMSecs( frame * duration * 1000 );
}
else
{
switch ( interval.originalUnit() )
{
case QgsUnitTypes::TemporalUnit::TemporalMilliseconds:
return start.addMSecs( frame * interval.originalDuration() );
break;
case QgsUnitTypes::TemporalUnit::TemporalSeconds:
return start.addSecs( frame * interval.originalDuration() );
break;
case QgsUnitTypes::TemporalUnit::TemporalMinutes:
return start.addSecs( 60 * frame * interval.originalDuration() );
break;
case QgsUnitTypes::TemporalUnit::TemporalHours:
return start.addSecs( 3600 * frame * interval.originalDuration() );
break;
case QgsUnitTypes::TemporalUnit::TemporalDays:
return start.addDays( frame * interval.originalDuration() );
break;
case QgsUnitTypes::TemporalUnit::TemporalWeeks:
return start.addDays( 7 * frame * interval.originalDuration() );
break;
case QgsUnitTypes::TemporalUnit::TemporalMonths:
return start.addMonths( frame * interval.originalDuration() );
break;
case QgsUnitTypes::TemporalUnit::TemporalYears:
return start.addYears( frame * interval.originalDuration() );
break;
case QgsUnitTypes::TemporalUnit::TemporalDecades:
return start.addYears( 10 * frame * interval.originalDuration() );
break;
case QgsUnitTypes::TemporalUnit::TemporalCenturies:
return start.addYears( 100 * frame * interval.originalDuration() );
break;
default:
return start;
case QgsUnitTypes::TemporalUnit::TemporalUnknownUnit:
// handled above
return QDateTime();
case QgsUnitTypes::TemporalUnit::TemporalIrregularStep:
// not supported by this method
return QDateTime();
}
}
return QDateTime();
}

QList<QDateTime> QgsTemporalUtils::calculateDateTimesUsingDuration( const QDateTime &start, const QDateTime &end, const QString &duration, bool &ok, bool &maxValuesExceeded, int maxValues )
@@ -208,7 +208,7 @@ class CORE_EXPORT QgsTemporalUtils
*
* \since QGIS 3.18
*/
static QDateTime calculateFrameTime( const QDateTime &start, const long long frame, const QgsInterval interval );
static QDateTime calculateFrameTime( const QDateTime &start, const long long frame, const QgsInterval &interval );

/**
* Calculates a complete list of datetimes between \a start and \a end, using the specified ISO8601 \a duration string (eg "PT12H").
@@ -120,12 +120,30 @@ def testFrameTimeCalculation(self):
}

for unit in list(expected2.keys()):

f = QgsTemporalUtils.calculateFrameTime(QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 0), Qt.UTC),
1,
QgsInterval(10.5, unit))
self.assertEqual(f, expected2[unit])

# frame number > 1
expected2a = {QgsUnitTypes.TemporalMilliseconds: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 31), Qt.UTC),
QgsUnitTypes.TemporalSeconds: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 31, 500), Qt.UTC),
QgsUnitTypes.TemporalMinutes: QDateTime(QDate(2021, 1, 1), QTime(12, 31, 30, 0), Qt.UTC),
QgsUnitTypes.TemporalHours: QDateTime(QDate(2021, 1, 2), QTime(19, 30, 0, 0), Qt.UTC),
QgsUnitTypes.TemporalDays: QDateTime(QDate(2021, 2, 2), QTime(0, 0, 0), Qt.UTC),
QgsUnitTypes.TemporalWeeks: QDateTime(QDate(2021, 8, 10), QTime(0, 0, 0), Qt.UTC),
QgsUnitTypes.TemporalMonths: QDateTime(QDate(2023, 8, 4), QTime(12, 0, 0, 0), Qt.UTC),
QgsUnitTypes.TemporalYears: QDateTime(QDate(2052, 7, 2), QTime(21, 0, 0, 0), Qt.UTC),
QgsUnitTypes.TemporalDecades: QDateTime(QDate(2336, 1, 5), QTime(6, 0, 0, 0), Qt.UTC),
QgsUnitTypes.TemporalCenturies: QDateTime(QDate(5171, 1, 26), QTime(0, 0, 0, 0), Qt.UTC)
}

for unit in list(expected2.keys()):
f = QgsTemporalUtils.calculateFrameTime(QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 0), Qt.UTC),
3,
QgsInterval(10.5, unit))
self.assertEqual(f, expected2a[unit])

expected3 = {QgsUnitTypes.TemporalMilliseconds: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 0), Qt.UTC),
QgsUnitTypes.TemporalSeconds: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 200), Qt.UTC),
QgsUnitTypes.TemporalMinutes: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 12, 0), Qt.UTC),
@@ -144,6 +162,24 @@ def testFrameTimeCalculation(self):
QgsInterval(0.2, unit))
self.assertEqual(f, expected3[unit])

expected3a = {QgsUnitTypes.TemporalMilliseconds: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 0), Qt.UTC),
QgsUnitTypes.TemporalSeconds: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 600), Qt.UTC),
QgsUnitTypes.TemporalMinutes: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 36, 0), Qt.UTC),
QgsUnitTypes.TemporalHours: QDateTime(QDate(2021, 1, 1), QTime(12, 36, 0, 0), Qt.UTC),
QgsUnitTypes.TemporalDays: QDateTime(QDate(2021, 1, 2), QTime(2, 24, 0), Qt.UTC),
QgsUnitTypes.TemporalWeeks: QDateTime(QDate(2021, 1, 5), QTime(16, 48, 0), Qt.UTC),
QgsUnitTypes.TemporalMonths: QDateTime(QDate(2021, 1, 19), QTime(12, 0, 0, 0), Qt.UTC),
QgsUnitTypes.TemporalYears: QDateTime(QDate(2021, 8, 8), QTime(15, 36, 0, 0), Qt.UTC),
QgsUnitTypes.TemporalDecades: QDateTime(QDate(2027, 1, 2), QTime(0, 0, 0, 0), Qt.UTC),
QgsUnitTypes.TemporalCenturies: QDateTime(QDate(2081, 1, 1), QTime(12, 0, 0, 0), Qt.UTC)
}

for unit in list(expected3.keys()):
f = QgsTemporalUtils.calculateFrameTime(QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 0), Qt.UTC),
3,
QgsInterval(0.2, unit))
self.assertEqual(f, expected3a[unit])

def testCalculateDateTimesUsingDuration(self):
# invalid duration string
vals, ok, exceeded = QgsTemporalUtils.calculateDateTimesUsingDuration(

0 comments on commit 81ec79c

Please sign in to comment.