QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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  if ( !mBlockUpdateTemporalRangeSignal )
116  {
117  switch ( mNavigationMode )
118  {
119  case Animated:
120  emit updateTemporalRange( dateTimeRangeForFrameNumber( mCurrentFrameNumber ) );
121  break;
122  case FixedRange:
123  emit updateTemporalRange( mTemporalExtents );
124  break;
125  case NavigationOff:
126  emit updateTemporalRange( QgsDateTimeRange() );
127  break;
128  }
129  }
130 }
131 
132 void QgsTemporalNavigationObject::setTemporalExtents( const QgsDateTimeRange &temporalExtents )
133 {
134  if ( mTemporalExtents == temporalExtents )
135  {
136  return;
137  }
138  mTemporalExtents = temporalExtents;
139  emit temporalExtentsChanged( mTemporalExtents );
140 
141  switch ( mNavigationMode )
142  {
143  case Animated:
144  {
145  int currentFrameNumber = mCurrentFrameNumber;
147 
148  //Force to emit signal if the current frame number doesn't change
149  if ( currentFrameNumber == mCurrentFrameNumber && !mBlockUpdateTemporalRangeSignal )
151  break;
152  }
153  case FixedRange:
154  if ( !mBlockUpdateTemporalRangeSignal )
155  emit updateTemporalRange( mTemporalExtents );
156  break;
157  case NavigationOff:
158  break;
159  }
160 
161 }
162 
164 {
165  return mTemporalExtents;
166 }
167 
169 {
170  if ( mCurrentFrameNumber != frameNumber )
171  {
172  mCurrentFrameNumber = std::max( 0LL, std::min( frameNumber, totalFrameCount() - 1 ) );
173  QgsDateTimeRange range = dateTimeRangeForFrameNumber( mCurrentFrameNumber );
174 
175  if ( !mBlockUpdateTemporalRangeSignal )
176  emit updateTemporalRange( range );
177  }
178 }
179 
181 {
182  return mCurrentFrameNumber;
183 }
184 
186 {
187  if ( mFrameDuration == frameDuration )
188  {
189  return;
190  }
191  mFrameDuration = frameDuration;
192  emit temporalFrameDurationChanged( mFrameDuration );
193 
194  // temporarily disable the updateTemporalRange signal, as we'll emit it ourselves at the end of this function...
195  mBlockUpdateTemporalRangeSignal++;
197  mBlockUpdateTemporalRangeSignal--;
198 
199  // forcing an update of our views
200  QgsDateTimeRange range = dateTimeRangeForFrameNumber( mCurrentFrameNumber );
201 
202  if ( !mBlockUpdateTemporalRangeSignal )
203  emit updateTemporalRange( range );
204 }
205 
207 {
208  return mFrameDuration;
209 }
210 
211 void QgsTemporalNavigationObject::setFramesPerSecond( double framesPerSeconds )
212 {
213  if ( framesPerSeconds > 0 )
214  {
215  mFramesPerSecond = framesPerSeconds;
216  mNewFrameTimer->setInterval( ( 1.0 / mFramesPerSecond ) * 1000 );
217  }
218 }
219 
221 {
222  return mFramesPerSecond;
223 }
224 
226 {
227  mCumulativeTemporalRange = state;
228 }
229 
231 {
232  return mCumulativeTemporalRange;
233 }
234 
236 {
237  mNewFrameTimer->start( ( 1.0 / mFramesPerSecond ) * 1000 );
238 }
239 
241 {
242  mNewFrameTimer->stop();
243  setAnimationState( AnimationState::Idle );
244 }
245 
247 {
248  if ( mPlayBackMode == Idle && mCurrentFrameNumber >= totalFrameCount() - 1 )
249  {
250  // if we are paused at the end of the video, and the user hits play, we automatically rewind and play again
251  rewindToStart();
252  }
253 
254  setAnimationState( AnimationState::Forward );
255  play();
256 }
257 
259 {
260  if ( mPlayBackMode == Idle && mCurrentFrameNumber <= 0 )
261  {
262  // 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
263  skipToEnd();
264  }
265 
266  setAnimationState( AnimationState::Reverse );
267  play();
268 }
269 
271 {
272  setCurrentFrameNumber( mCurrentFrameNumber + 1 );
273 }
274 
276 {
277  setCurrentFrameNumber( mCurrentFrameNumber - 1 );
278 }
279 
281 {
283 }
284 
286 {
287  const long long frame = totalFrameCount() - 1;
288  setCurrentFrameNumber( frame );
289 }
290 
292 {
293  QgsInterval totalAnimationLength = mTemporalExtents.end() - mTemporalExtents.begin();
294  return std::floor( totalAnimationLength.seconds() / mFrameDuration.seconds() ) + 1;
295 }
296 
298 {
299  if ( mode != mPlayBackMode )
300  {
301  mPlayBackMode = mode;
302  emit stateChanged( mPlayBackMode );
303  }
304 }
305 
307 {
308  return mPlayBackMode;
309 }
QgsTemporalNavigationObject::rewindToStart
void rewindToStart()
Rewinds the temporal navigation to start of the temporal extent.
Definition: qgstemporalnavigationobject.cpp:280
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:225
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:246
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:185
QgsTemporalNavigationObject::NavigationMode
NavigationMode
Represents the current temporal navigation mode.
Definition: qgstemporalnavigationobject.h:52
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:206
QgsTemporalNavigationObject::temporalExtentsChanged
void temporalExtentsChanged(const QgsDateTimeRange &extent)
Emitted whenever the temporalExtent extent changes.
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:258
QgsTemporalNavigationObject::skipToEnd
void skipToEnd()
Skips the temporal navigation to end of the temporal extent.
Definition: qgstemporalnavigationobject.cpp:285
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:168
QgsTemporalNavigationObject::setAnimationState
void setAnimationState(AnimationState state)
Sets the current animation state.
Definition: qgstemporalnavigationobject.cpp:297
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:132
QgsTemporalNavigationObject::setFramesPerSecond
void setFramesPerSecond(double rate)
Sets the animation frame rate, in frames per second.
Definition: qgstemporalnavigationobject.cpp:211
QgsTemporalController
A controller base class for temporal objects, contains a signal for notifying updates of the objects ...
Definition: qgstemporalcontroller.h:42
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:291
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext.
Definition: qgsexpressioncontext.h:112
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:240
QgsTemporalNavigationObject::next
void next()
Advances to the next frame.
Definition: qgstemporalnavigationobject.cpp:270
QgsTemporalNavigationObject::temporalFrameDurationChanged
void temporalFrameDurationChanged(const QgsInterval &interval)
Emitted whenever the frameDuration interval of the controller changes.
QgsTemporalNavigationObject::temporalRangeCumulative
bool temporalRangeCumulative() const
Returns the animation temporal range cumulative settings.
Definition: qgstemporalnavigationobject.cpp:230
QgsInterval
A representation of the interval between two datetime values.
Definition: qgsinterval.h:41
QgsTemporalNavigationObject::previous
void previous()
Jumps back to the previous frame.
Definition: qgstemporalnavigationobject.cpp:275
QgsTemporalNavigationObject::NavigationOff
@ NavigationOff
Temporal navigation is disabled.
Definition: qgstemporalnavigationobject.h:53
QgsTemporalNavigationObject::AnimationState
AnimationState
Represents the current animation state.
Definition: qgstemporalnavigationobject.h:60
QgsTemporalNavigationObject::play
void play()
Starts playing the temporal navigation from its current frame, using the direction specified by anima...
Definition: qgstemporalnavigationobject.cpp:235
QgsTemporalNavigationObject::currentFrameNumber
long long currentFrameNumber() const
Returns the current frame number.
Definition: qgstemporalnavigationobject.cpp:180
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:220
QgsTemporalNavigationObject::animationState
AnimationState animationState() const
Returns the current animation state.
Definition: qgstemporalnavigationobject.cpp:306
QgsTemporalNavigationObject::temporalExtents
QgsDateTimeRange temporalExtents() const
Returns the navigation temporal extents, which dictate the earliest and latest date time possible in ...
Definition: qgstemporalnavigationobject.cpp:163