Skip to content
Permalink
Browse files

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
  • Loading branch information
rduivenvoorde committed Nov 19, 2020
1 parent fb48bc9 commit 6797118e2f57b8a8d724d03632190ec457329982
@@ -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
@@ -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/;
@@ -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:
@@ -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 );
@@ -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;
}
@@ -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()
*/
@@ -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:
@@ -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()
@@ -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 );
}

@@ -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()

0 comments on commit 6797118

Please sign in to comment.
You can’t perform that action at this time.