QGIS API Documentation  3.14.0-Pi (9f7028fd23)
qgstemporalnavigationobject.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgstemporalnavigationobject.cpp
3  ---------------
4  begin : March 2020
5  copyright : (C) 2020 by Samweli Mwakisambwe
6  email : samweli at kartoza dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
19 #include "qgis.h"
20 
22  : QgsTemporalController( parent )
23 {
24  mNewFrameTimer = new QTimer( this );
25 
26  connect( mNewFrameTimer, &QTimer::timeout,
27  this, &QgsTemporalNavigationObject::timerTimeout );
28 }
29 
30 void QgsTemporalNavigationObject::timerTimeout()
31 {
32  switch ( mPlayBackMode )
33  {
34  case AnimationState::Forward:
35  next();
36  if ( mCurrentFrameNumber >= totalFrameCount() - 1 )
37  {
38  if ( mLoopAnimation )
39  mCurrentFrameNumber = -1; // we don't jump immediately to frame 0, instead we delay that till the next timeout
40  else
41  pause();
42  }
43  break;
44 
45  case AnimationState::Reverse:
46  previous();
47  if ( mCurrentFrameNumber <= 0 )
48  {
49  if ( mLoopAnimation )
50  mCurrentFrameNumber = totalFrameCount(); // we don't jump immediately to real last frame..., instead we delay that till the next timeout
51  else
52  pause();
53  }
54  break;
55 
56  case AnimationState::Idle:
57  // should not happen - in an idle state the timeout won't occur
58  break;
59  }
60 }
61 
63 {
64  return mLoopAnimation;
65 }
66 
67 void QgsTemporalNavigationObject::setLooping( bool loopAnimation )
68 {
69  mLoopAnimation = loopAnimation;
70 }
71 
73 {
74  std::unique_ptr< QgsExpressionContextScope > scope = qgis::make_unique< QgsExpressionContextScope >( QStringLiteral( "temporal" ) );
75  scope->setVariable( QStringLiteral( "frame_rate" ), mFramesPerSecond, true );
76  scope->setVariable( QStringLiteral( "frame_number" ), mCurrentFrameNumber, true );
77  scope->setVariable( QStringLiteral( "frame_duration" ), mFrameDuration, true );
78  scope->setVariable( QStringLiteral( "animation_start_time" ), mTemporalExtents.begin(), true );
79  scope->setVariable( QStringLiteral( "animation_end_time" ), mTemporalExtents.end(), true );
80  scope->setVariable( QStringLiteral( "animation_interval" ), mTemporalExtents.end() - mTemporalExtents.begin(), true );
81  return scope.release();
82 }
83 
84 QgsDateTimeRange QgsTemporalNavigationObject::dateTimeRangeForFrameNumber( long long frame ) const
85 {
86  const QDateTime start = mTemporalExtents.begin();
87 
88  if ( frame < 0 )
89  frame = 0;
90 
91  const long long nextFrame = frame + 1;
92 
93  const QDateTime begin = start.addSecs( frame * mFrameDuration.seconds() );
94  const QDateTime end = start.addSecs( nextFrame * mFrameDuration.seconds() );
95 
96  QDateTime frameStart = begin;
97 
98  if ( mCumulativeTemporalRange )
99  frameStart = start;
100 
101  if ( end <= mTemporalExtents.end() )
102  return QgsDateTimeRange( frameStart, end, true, false );
103 
104  return QgsDateTimeRange( frameStart, mTemporalExtents.end(), true, false );
105 }
106 
108 {
109  if ( mNavigationMode == mode )
110  return;
111 
112  mNavigationMode = mode;
113  emit navigationModeChanged( mode );
114 
115  switch ( mNavigationMode )
116  {
117  case Animated:
118  emit updateTemporalRange( dateTimeRangeForFrameNumber( mCurrentFrameNumber ) );
119  break;
120  case FixedRange:
121  emit updateTemporalRange( mTemporalExtents );
122  break;
123  case NavigationOff:
124  emit updateTemporalRange( QgsDateTimeRange() );
125  break;
126  }
127 }
128 
129 void QgsTemporalNavigationObject::setTemporalExtents( const QgsDateTimeRange &temporalExtents )
130 {
131  mTemporalExtents = temporalExtents;
132 
133  switch ( mNavigationMode )
134  {
135  case Animated:
136  {
137  int currentFrameNmber = mCurrentFrameNumber;
139 
140  //Force to emit signal if the current frame number doesn't change
141  if ( currentFrameNmber == mCurrentFrameNumber )
143  break;
144  }
145  case FixedRange:
146  emit updateTemporalRange( mTemporalExtents );
147  break;
148  case NavigationOff:
149  break;
150  }
151 }
152 
154 {
155  return mTemporalExtents;
156 }
157 
159 {
160  if ( mCurrentFrameNumber != frameNumber )
161  {
162  mCurrentFrameNumber = std::max( 0LL, std::min( frameNumber, totalFrameCount() - 1 ) );
163  QgsDateTimeRange range = dateTimeRangeForFrameNumber( mCurrentFrameNumber );
164  emit updateTemporalRange( range );
165  }
166 }
167 
169 {
170  return mCurrentFrameNumber;
171 }
172 
174 {
175  mFrameDuration = frameDuration;
177 }
178 
180 {
181  return mFrameDuration;
182 }
183 
184 void QgsTemporalNavigationObject::setFramesPerSecond( double framesPerSeconds )
185 {
186  if ( framesPerSeconds > 0 )
187  {
188  mFramesPerSecond = framesPerSeconds;
189  mNewFrameTimer->setInterval( ( 1.0 / mFramesPerSecond ) * 1000 );
190  }
191 }
192 
194 {
195  return mFramesPerSecond;
196 }
197 
199 {
200  mCumulativeTemporalRange = state;
201 }
202 
204 {
205  return mCumulativeTemporalRange;
206 }
207 
209 {
210  mNewFrameTimer->start( ( 1.0 / mFramesPerSecond ) * 1000 );
211 }
212 
214 {
215  mNewFrameTimer->stop();
216  setAnimationState( AnimationState::Idle );
217 }
218 
220 {
221  if ( mPlayBackMode == Idle && mCurrentFrameNumber >= totalFrameCount() - 1 )
222  {
223  // if we are paused at the end of the video, and the user hits play, we automatically rewind and play again
224  rewindToStart();
225  }
226 
227  setAnimationState( AnimationState::Forward );
228  play();
229 }
230 
232 {
233  if ( mPlayBackMode == Idle && mCurrentFrameNumber <= 0 )
234  {
235  // if we are paused at the start of the video, and the user hits play, we automatically skip to end and play in reverse again
236  skipToEnd();
237  }
238 
239  setAnimationState( AnimationState::Reverse );
240  play();
241 }
242 
244 {
245  setCurrentFrameNumber( mCurrentFrameNumber + 1 );
246 }
247 
249 {
250  setCurrentFrameNumber( mCurrentFrameNumber - 1 );
251 }
252 
254 {
256 }
257 
259 {
260  const long long frame = totalFrameCount() - 1;
261  setCurrentFrameNumber( frame );
262 }
263 
265 {
266  QgsInterval totalAnimationLength = mTemporalExtents.end() - mTemporalExtents.begin();
267  return std::floor( totalAnimationLength.seconds() / mFrameDuration.seconds() ) + 1;
268 }
269 
271 {
272  if ( mode != mPlayBackMode )
273  {
274  mPlayBackMode = mode;
275  emit stateChanged( mPlayBackMode );
276  }
277 }
278 
280 {
281  return mPlayBackMode;
282 }
QgsTemporalNavigationObject::rewindToStart
void rewindToStart()
Rewinds the temporal navigation to start of the temporal extent.
Definition: qgstemporalnavigationobject.cpp:253
QgsTemporalNavigationObject::Animated
@ Animated
Temporal navigation relies on frames within a datetime range.
Definition: qgstemporalnavigationobject.h:54
QgsInterval::seconds
double seconds() const
Returns the interval duration in seconds.
Definition: qgsinterval.h:168
QgsTemporalNavigationObject::setTemporalRangeCumulative
void setTemporalRangeCumulative(bool state)
Sets the animation temporal range as cumulative.
Definition: qgstemporalnavigationobject.cpp:198
qgstemporalnavigationobject.h
qgis.h
QgsTemporalNavigationObject::dateTimeRangeForFrameNumber
QgsDateTimeRange dateTimeRangeForFrameNumber(long long frame) const
Calculates the temporal range associated with a particular animation frame.
Definition: qgstemporalnavigationobject.cpp:84
QgsTemporalNavigationObject::playForward
void playForward()
Starts the animation playing in a forward direction up till the end of all frames.
Definition: qgstemporalnavigationobject.cpp:219
QgsTemporalNavigationObject::navigationModeChanged
void navigationModeChanged(NavigationMode mode)
Emitted whenever the navigation mode changes.
QgsTemporalNavigationObject::setFrameDuration
void setFrameDuration(QgsInterval duration)
Sets the frame duration, which dictates the temporal length of each frame in the animation.
Definition: qgstemporalnavigationobject.cpp:173
QgsTemporalNavigationObject::NavigationMode
NavigationMode
Represents the current temporal navigation mode.
Definition: qgstemporalnavigationobject.h:51
QgsTemporalNavigationObject::frameDuration
QgsInterval frameDuration() const
Returns the current set frame duration, which dictates the temporal length of each frame in the anima...
Definition: qgstemporalnavigationobject.cpp:179
QgsTemporalNavigationObject::QgsTemporalNavigationObject
QgsTemporalNavigationObject(QObject *parent=nullptr)
Constructor for QgsTemporalNavigationObject, with the specified parent object.
Definition: qgstemporalnavigationobject.cpp:21
QgsTemporalNavigationObject::setLooping
void setLooping(bool loop)
Sets whether the animation should loop after hitting the end or start frame.
Definition: qgstemporalnavigationobject.cpp:67
QgsTemporalNavigationObject::playBackward
void playBackward()
Starts the animation playing in a reverse direction until the beginning of the time range.
Definition: qgstemporalnavigationobject.cpp:231
QgsTemporalNavigationObject::skipToEnd
void skipToEnd()
Skips the temporal navigation to end of the temporal extent.
Definition: qgstemporalnavigationobject.cpp:258
QgsTemporalNavigationObject::stateChanged
void stateChanged(AnimationState state)
Emitted whenever the animation state changes.
QgsTemporalNavigationObject::setCurrentFrameNumber
void setCurrentFrameNumber(long long frame)
Sets the current animation frame number.
Definition: qgstemporalnavigationobject.cpp:158
QgsTemporalNavigationObject::setAnimationState
void setAnimationState(AnimationState state)
Sets the current animation state.
Definition: qgstemporalnavigationobject.cpp:270
QgsTemporalNavigationObject::setTemporalExtents
void setTemporalExtents(const QgsDateTimeRange &extents)
Sets the navigation temporal extents, which dictate the earliest and latest date time possible in the...
Definition: qgstemporalnavigationobject.cpp:129
QgsTemporalNavigationObject::setFramesPerSecond
void setFramesPerSecond(double rate)
Sets the animation frame rate, in frames per second.
Definition: qgstemporalnavigationobject.cpp:184
QgsTemporalController
Definition: qgstemporalcontroller.h:35
QgsTemporalNavigationObject::createExpressionContextScope
QgsExpressionContextScope * createExpressionContextScope() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Definition: qgstemporalnavigationobject.cpp:72
QgsTemporalNavigationObject::Idle
@ Idle
Animation is paused.
Definition: qgstemporalnavigationobject.h:63
QgsTemporalNavigationObject::totalFrameCount
long long totalFrameCount()
Returns the total number of frames for the navigation.
Definition: qgstemporalnavigationobject.cpp:264
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext....
Definition: qgsexpressioncontext.h:111
QgsTemporalNavigationObject::isLooping
bool isLooping() const
Returns true if the animation should loop after hitting the end or start frame.
Definition: qgstemporalnavigationobject.cpp:62
QgsTemporalController::updateTemporalRange
void updateTemporalRange(const QgsDateTimeRange &range)
Signals that a temporal range has changed and needs to be updated in all connected objects.
QgsTemporalNavigationObject::pause
void pause()
Pauses the temporal navigation.
Definition: qgstemporalnavigationobject.cpp:213
QgsTemporalNavigationObject::next
void next()
Advances to the next frame.
Definition: qgstemporalnavigationobject.cpp:243
QgsTemporalNavigationObject::temporalRangeCumulative
bool temporalRangeCumulative() const
Returns the animation temporal range cumulative settings.
Definition: qgstemporalnavigationobject.cpp:203
QgsInterval
A representation of the interval between two datetime values.
Definition: qgsinterval.h:40
QgsTemporalNavigationObject::previous
void previous()
Jumps back to the previous frame.
Definition: qgstemporalnavigationobject.cpp:248
QgsTemporalNavigationObject::NavigationOff
@ NavigationOff
Temporal navigation is disabled.
Definition: qgstemporalnavigationobject.h:53
QgsTemporalNavigationObject::AnimationState
AnimationState
Represents the current animation state.
Definition: qgstemporalnavigationobject.h:59
QgsTemporalNavigationObject::play
void play()
Starts playing the temporal navigation from its current frame, using the direction specified by anima...
Definition: qgstemporalnavigationobject.cpp:208
QgsTemporalNavigationObject::currentFrameNumber
long long currentFrameNumber() const
Returns the current frame number.
Definition: qgstemporalnavigationobject.cpp:168
QgsTemporalNavigationObject::setNavigationMode
void setNavigationMode(const NavigationMode mode)
Sets the temporal navigation mode.
Definition: qgstemporalnavigationobject.cpp:107
QgsTemporalNavigationObject::FixedRange
@ FixedRange
Temporal navigation relies on a fixed datetime range.
Definition: qgstemporalnavigationobject.h:55
QgsTemporalNavigationObject::framesPerSecond
double framesPerSecond() const
Returns the animation frame rate, in frames per second.
Definition: qgstemporalnavigationobject.cpp:193
QgsTemporalNavigationObject::animationState
AnimationState animationState() const
Returns the current animation state.
Definition: qgstemporalnavigationobject.cpp:279
QgsTemporalNavigationObject::temporalExtents
QgsDateTimeRange temporalExtents() const
Returns the navigation temporal extents, which dictate the earliest and latest date time possible in ...
Definition: qgstemporalnavigationobject.cpp:153