Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
On timestep-size change, Set timeslider to best possible fit (instead…
… of resetting to start)

Try to remember/set last timeframe (upon timestep- or timeframe-changes).

Setting the stepsize to a different size, did reset the slider to start
(aka timeframe 0).
Same when you changed the range (data time) extent.

This commit tries to set the slider to the same position as before the
step change, if possible). Else it will take the position of the timeframe
in which the start of the old timeframe fits.

fixes #39994

(cherry picked from commit 6797118)
  • Loading branch information
rduivenvoorde authored and nyalldawson committed Nov 20, 2020
1 parent 77b9937 commit f88c48d
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 14 deletions.
Expand Up @@ -115,7 +115,7 @@ Sets the frame ``duration``, which dictates the temporal length of each frame in

.. note::

Calling this will reset the :py:func:`~QgsTemporalNavigationObject.currentFrameNumber` to the first frame.
Calling this will reset the :py:func:`~QgsTemporalNavigationObject.currentFrameNumber` to the closest temporal match for the previous temporal range.

.. seealso:: :py:func:`frameDuration`
%End
Expand Down Expand Up @@ -186,6 +186,11 @@ Returns ``True`` if the animation should loop after hitting the end or start fra
Sets whether the animation should ``loop`` after hitting the end or start frame.

.. seealso:: :py:func:`isLooping`
%End

long findBestFrameNumberForFrameStart( const QDateTime &frameStart ) const;
%Docstring
Returns the best suited frame number for the specified datetime, based on the start of the corresponding temporal range.
%End

virtual QgsExpressionContextScope *createExpressionContextScope() const /Factory/;
Expand Down
28 changes: 22 additions & 6 deletions src/core/qgstemporalnavigationobject.cpp
Expand Up @@ -135,19 +135,20 @@ void QgsTemporalNavigationObject::setTemporalExtents( const QgsDateTimeRange &te
{
return;
}
QgsDateTimeRange oldFrame = dateTimeRangeForFrameNumber( currentFrameNumber() );
mTemporalExtents = temporalExtents;
mCurrentFrameNumber = findBestFrameNumberForFrameStart( oldFrame.begin() );
emit temporalExtentsChanged( mTemporalExtents );

switch ( mNavigationMode )
{
case Animated:
{
int currentFrameNumber = mCurrentFrameNumber;
setCurrentFrameNumber( 0 );

//Force to emit signal if the current frame number doesn't change
// Force to emit signal if the current frame number doesn't change
if ( currentFrameNumber == mCurrentFrameNumber && !mBlockUpdateTemporalRangeSignal )
emit updateTemporalRange( dateTimeRangeForFrameNumber( 0 ) );
emit updateTemporalRange( dateTimeRangeForFrameNumber( mCurrentFrameNumber ) );
break;
}
case FixedRange:
Expand Down Expand Up @@ -188,13 +189,12 @@ void QgsTemporalNavigationObject::setFrameDuration( QgsInterval frameDuration )
{
return;
}
QgsDateTimeRange oldFrame = dateTimeRangeForFrameNumber( currentFrameNumber() );
mFrameDuration = frameDuration;
mCurrentFrameNumber = findBestFrameNumberForFrameStart( oldFrame.begin() );
emit temporalFrameDurationChanged( mFrameDuration );

// temporarily disable the updateTemporalRange signal, as we'll emit it ourselves at the end of this function...
mBlockUpdateTemporalRangeSignal++;
setCurrentFrameNumber( 0 );
mBlockUpdateTemporalRangeSignal--;

// forcing an update of our views
QgsDateTimeRange range = dateTimeRangeForFrameNumber( mCurrentFrameNumber );
Expand Down Expand Up @@ -307,3 +307,19 @@ QgsTemporalNavigationObject::AnimationState QgsTemporalNavigationObject::animati
{
return mPlayBackMode;
}

long QgsTemporalNavigationObject::findBestFrameNumberForFrameStart( const QDateTime &frameStart ) const
{
long bestFrame = 0;
QgsDateTimeRange testFrame = QgsDateTimeRange( frameStart, frameStart ); // creatng an 'instant' Range here
for ( long i = 0; i < totalFrameCount(); ++i )
{
QgsDateTimeRange range = dateTimeRangeForFrameNumber( i );
if ( range.overlaps( testFrame ) )
{
bestFrame = i;
break;
}
}
return bestFrame;
}
7 changes: 6 additions & 1 deletion src/core/qgstemporalnavigationobject.h
Expand Up @@ -129,7 +129,7 @@ class CORE_EXPORT QgsTemporalNavigationObject : public QgsTemporalController, pu
/**
* Sets the frame \a duration, which dictates the temporal length of each frame in the animation.
*
* \note Calling this will reset the currentFrameNumber() to the first frame.
* \note Calling this will reset the currentFrameNumber() to the closest temporal match for the previous temporal range.
*
* \see frameDuration()
*/
Expand Down Expand Up @@ -203,6 +203,11 @@ class CORE_EXPORT QgsTemporalNavigationObject : public QgsTemporalController, pu
*/
void setLooping( bool loop );

/**
* Returns the best suited frame number for the specified datetime, based on the start of the corresponding temporal range.
*/
long findBestFrameNumberForFrameStart( const QDateTime &frameStart ) const;

QgsExpressionContextScope *createExpressionContextScope() const override SIP_FACTORY;

signals:
Expand Down
6 changes: 4 additions & 2 deletions src/gui/qgstemporalcontrollerwidget.cpp
Expand Up @@ -283,7 +283,7 @@ void QgsTemporalControllerWidget::updateTemporalExtent()
mEndDateTime->dateTime() );
mNavigationObject->setTemporalExtents( temporalExtent );
mSlider->setRange( 0, mNavigationObject->totalFrameCount() - 1 );
mSlider->setValue( 0 );
mSlider->setValue( mNavigationObject->currentFrameNumber() );
}

void QgsTemporalControllerWidget::updateFrameDuration()
Expand All @@ -296,9 +296,11 @@ void QgsTemporalControllerWidget::updateFrameDuration()
QgsProject::instance()->timeSettings()->setTimeStep( mStepSpinBox->value() );

if ( !mBlockFrameDurationUpdates )
{
mNavigationObject->setFrameDuration( QgsInterval( QgsProject::instance()->timeSettings()->timeStep(),
QgsProject::instance()->timeSettings()->timeStepUnit() ) );

mSlider->setValue( mNavigationObject->currentFrameNumber() );
}
mSlider->setRange( 0, mNavigationObject->totalFrameCount() - 1 );
}

Expand Down
23 changes: 19 additions & 4 deletions tests/src/core/testqgstemporalnavigationobject.cpp
Expand Up @@ -206,17 +206,32 @@ void TestQgsTemporalNavigationObject::frameSettings()
QCOMPARE( navigationObject->currentFrameNumber(), 1 );
QCOMPARE( temporalRangeSignal.count(), 3 );

// Test Overflow
navigationObject->setCurrentFrameNumber( 100 );
QCOMPARE( navigationObject->currentFrameNumber(), navigationObject->totalFrameCount() - 1 );
QCOMPARE( temporalRangeSignal.count(), 4 );

// Test Underflow
navigationObject->setCurrentFrameNumber( -100 );
QCOMPARE( navigationObject->currentFrameNumber(), 0 );
QCOMPARE( temporalRangeSignal.count(), 5 );

navigationObject->setFramesPerSecond( 1 );
QCOMPARE( navigationObject->framesPerSecond(), 1.0 );

QCOMPARE( navigationObject->dateTimeRangeForFrameNumber( 4 ), lastRange );

// Test if changing the frame duration 'keeps' the current frameNumber
navigationObject->setCurrentFrameNumber( 4 ); // 12:00-...
QCOMPARE( navigationObject->currentFrameNumber(), 4 );
navigationObject->setFrameDuration( QgsInterval( 2, QgsUnitTypes::TemporalHours ) );
QCOMPARE( navigationObject->currentFrameNumber(), 2 ); // going from 1 hour to 2 hour frames, but stay on 12:00-...
QCOMPARE( temporalRangeSignal.count(), 7 );

// Test if, when changing to Cumulative mode, the dateTimeRange for frame 4 (with 2 hours frames) is indeed the full range
navigationObject->setTemporalRangeCumulative( true );
QCOMPARE( navigationObject->dateTimeRangeForFrameNumber( 4 ), range );

navigationObject->setFrameDuration( QgsInterval( 2, QgsUnitTypes::TemporalHours ) );
QCOMPARE( navigationObject->currentFrameNumber(), 0 );
QCOMPARE( temporalRangeSignal.count(), 4 );
QCOMPARE( temporalRangeSignal.count(), 7 );
}

void TestQgsTemporalNavigationObject::expressionContext()
Expand Down

0 comments on commit f88c48d

Please sign in to comment.