[ATSPI] Add CalculateScreenExtents function
[platform/core/uifw/dali-core.git] / dali / internal / update / gestures / scene-graph-pan-gesture.cpp
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/update/gestures/scene-graph-pan-gesture.h>
20
21 // EXTERNAL INCLUDES
22 #include <cmath>
23
24 // INTERNAL INCLUDES
25 #include <dali/internal/update/gestures/pan-gesture-profiling.h>
26 #include <dali/integration-api/debug.h>
27
28 namespace Dali
29 {
30
31 namespace Internal
32 {
33
34 namespace SceneGraph
35 {
36
37 namespace
38 {
39
40 // TODO: Experimental - for changing in code only:
41 const bool         TEST_TUNE_ENABLE_OVERSHOOT_PROTECTION   = false;
42
43 // Internal defaults:
44 const int          MAX_GESTURE_AGE                         = 200;    ///< maximum age of a gesture before disallowing its use in algorithm TODO: Possibly make this configurable.
45 const float        ACCELERATION_THRESHOLD                  = 0.1f;   ///< minimum pan velocity change to trigger dynamic change of prediction amount.
46 const float        OUTPUT_TIME_DIFFERENCE                  = ( 1000.0f / 60.0f ); ///< This is used to optionally override actual times if they make results worse.
47 const float        ACCELERATION_SMOOTHING                  = 0.44f;  ///< Smoothes acceleration changes from one frame to another.
48 const float        ACCELERATION_CAP                        = 0.0004f;///< Limits acceleration changes from one frame to another.
49
50 // Defaults for Environment Variables:
51
52 // Prediction Mode 1:
53 const unsigned int DEFAULT_MAX_PREDICTION_AMOUNT           = 32;     ///< the upper bound of the range to clamp the prediction interpolation.
54 const unsigned int DEFAULT_MIN_PREDICTION_AMOUNT           = 0;      ///< the lower bound of the range to clamp the prediction interpolation.
55 const unsigned int DEFAULT_PREDICTION_AMOUNT_ADJUSTMENT    = 2;      ///< the amount of prediction interpolation to adjust (in milliseconds) each time when pan velocity changes.
56
57 // Prediction Mode 2:
58 const bool         DEFAULT_USE_ACTUAL_TIMES                = false;  ///< Disable to optionally override actual times if they make results worse.
59 const int          DEFAULT_INTERPOLATION_TIME_RANGE        = 255;    ///< Time into past history (ms) to use points to interpolate the first point.
60 const bool         DEFAULT_SCALAR_ONLY_PREDICTION_ENABLED  = false;  ///< If enabled, prediction is done using velocity alone (no integration or acceleration).
61 const bool         DEFAULT_TWO_POINT_PREDICTION_ENABLED    = true;   ///< If enabled, a second interpolated point is predicted and combined with the first to get more stable values.
62 const int          DEFAULT_TWO_POINT_PAST_INTERPOLATE_TIME = 42;     ///< The target time in the past to generate the second interpolated point.
63 const float        DEFAULT_TWO_POINT_VELOCITY_BIAS         = 0.35f;  ///< The ratio of first and second interpolated points to use for velocity. 0.0f = 100% of first point. 1.0f = 100% of second point.
64 const float        DEFAULT_TWO_POINT_ACCELERATION_BIAS     = 0.10f;  ///< The ratio of first and second interpolated points to use for acceleration. 0.0f = 100% of first point. 1.0f = 100% of second point.
65 const int          DEFAULT_MULTITAP_SMOOTHING_RANGE        = 34;     ///< The range in time (ms) of points in the history to smooth the final output against.
66
67 // Prediction Modes 1 & 2.
68 const unsigned int DEFAULT_PREDICTION_AMOUNT[2]            = {     5,    57 }; ///< how much to interpolate pan position and displacement from last vsync time (in milliseconds)
69 const float        DEFAULT_SMOOTHING_AMOUNT[2]             = { 0.25f, 0.23f }; ///< how much to smooth final result from last vsync time
70
71 } // unnamed namespace
72
73 const PanGesture::PredictionMode PanGesture::DEFAULT_PREDICTION_MODE = PanGesture::PREDICTION_NONE;
74 const int PanGesture::NUM_PREDICTION_MODES = PanGesture::PREDICTION_2 + 1;
75
76 const PanGesture::SmoothingMode PanGesture::DEFAULT_SMOOTHING_MODE = PanGesture::SMOOTHING_LAST_VALUE;
77 const int PanGesture::NUM_SMOOTHING_MODES = PanGesture::SMOOTHING_MULTI_TAP + 1;
78
79 PanGesture* PanGesture::New()
80 {
81   return new PanGesture();
82 }
83
84 PanGesture::~PanGesture()
85 {
86   delete mProfiling;
87 }
88
89 void PanGesture::AddGesture( const Dali::PanGesture& gesture )
90 {
91   Dali::Mutex::ScopedLock lock( mMutex );
92   mGestures[ mWritePosition ] = gesture;
93
94   // Update our write position.
95   ++mWritePosition;
96   mWritePosition %= PAN_GESTURE_HISTORY;
97 }
98
99 void PanGesture::RemoveOldHistory(PanInfoHistory& panHistory, unsigned int currentTime, unsigned int maxAge, unsigned int minEvents)
100 {
101   PanInfoHistoryConstIter endIter = panHistory.end();
102   PanInfoHistoryIter iter = panHistory.begin();
103   while( iter != endIter && panHistory.size() > minEvents)
104   {
105     PanInfo currentGesture = *iter;
106     if( currentTime < currentGesture.time + maxAge )
107     {
108       break;
109     }
110     iter = panHistory.erase(iter);
111     endIter = panHistory.end();
112   }
113
114   // dont want more than 5 previous predictions for smoothing
115   iter = mPredictionHistory.begin();
116   while( mPredictionHistory.size() > 1 && iter != mPredictionHistory.end() )
117   {
118     iter = mPredictionHistory.erase(iter);
119   }
120 }
121
122 void PanGesture::PredictionMode1(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime)
123 {
124   RemoveOldHistory(panHistory, lastVSyncTime, MAX_GESTURE_AGE, 0);
125   size_t panHistorySize = panHistory.size();
126   if( panHistorySize == 0 )
127   {
128     // cant do any prediction without a history
129     return;
130   }
131
132   PanInfoHistoryConstIter endIter = panHistory.end();
133   PanInfoHistoryIter iter = panHistory.begin();
134   Vector2 screenVelocity = gestureOut.screen.velocity;
135   Vector2 localVelocity = gestureOut.local.velocity;
136   Vector2 screenDisplacement = gestureOut.screen.displacement;
137   Vector2 localDisplacement = gestureOut.local.displacement;
138
139   bool havePreviousAcceleration = false;
140   bool previousVelocity = false;
141   float previousAccel = 0.0f;
142   unsigned int lastTime(0);
143
144   unsigned int interpolationTime = lastVSyncTime + mCurrentPredictionAmount;
145
146   if( interpolationTime > gestureOut.time ) // Guard against the rare case when gestureOut.time > (lastVSyncTime + mCurrentPredictionAmount)
147   {
148     interpolationTime -= gestureOut.time;
149   }
150   else
151   {
152     interpolationTime = 0u;
153   }
154
155   while( iter != endIter )
156   {
157     PanInfo currentGesture = *iter;
158     if( !previousVelocity )
159     {
160       // not yet set a previous velocity
161       screenVelocity = currentGesture.screen.velocity;
162       previousVelocity = true;
163       lastTime = currentGesture.time;
164       ++iter;
165       continue;
166     }
167     float previousValueWeight = ( static_cast<float>( MAX_GESTURE_AGE ) - static_cast<float>(lastVSyncTime - lastTime) ) / static_cast<float>( MAX_GESTURE_AGE );
168     float velMag = currentGesture.screen.velocity.Length();
169     float velDiff = velMag - screenVelocity.Length();
170     float acceleration = 0.0f;
171
172     float time(0.f);
173     if (currentGesture.time > lastTime) // Guard against invalid timestamps
174     {
175       time = static_cast<float>( currentGesture.time - lastTime );
176     }
177     if( time > Math::MACHINE_EPSILON_1 )
178     {
179       acceleration = velDiff / time;
180     }
181
182     float newVelMag = 0.0f;
183     int currentInterpolation = interpolationTime;
184     if( !havePreviousAcceleration )
185     {
186       newVelMag =  velMag;
187       havePreviousAcceleration = true;
188     }
189     else
190     {
191       newVelMag = velMag + (((acceleration * (1.0f - previousValueWeight)) + (previousAccel * previousValueWeight)) * static_cast<float>( currentInterpolation ) );
192     }
193     float velMod = 1.0f;
194     if( velMag > Math::MACHINE_EPSILON_1 )
195     {
196       velMod = newVelMag / velMag;
197     }
198     gestureOut.screen.velocity = currentGesture.screen.velocity * velMod;
199     gestureOut.local.velocity = currentGesture.local.velocity * velMod;
200     screenDisplacement = gestureOut.screen.displacement + (gestureOut.screen.velocity * static_cast<float>( interpolationTime ) );
201     localDisplacement = gestureOut.local.displacement + (gestureOut.local.velocity * static_cast<float>( interpolationTime ) );
202     screenVelocity = currentGesture.screen.velocity;
203     localVelocity = currentGesture.local.velocity;
204     previousAccel = acceleration;
205     ++iter;
206   }
207   // gestureOut's position is currently equal to the last event's position and its displacement is equal to last frame's total displacement
208   // add interpolated distance and position to current
209   // work out interpolated velocity
210   gestureOut.screen.position = (gestureOut.screen.position - gestureOut.screen.displacement) + screenDisplacement;
211   gestureOut.local.position = (gestureOut.local.position - gestureOut.local.displacement) + localDisplacement;
212   gestureOut.screen.displacement = screenDisplacement;
213   gestureOut.local.displacement = localDisplacement;
214   gestureOut.time += interpolationTime;
215 }
216
217 void PanGesture::BlendPoints( PanInfo& gesture, PanInfo& lastGesture, float blendValue )
218 {
219   gesture.screen.position -= ( gesture.screen.position - lastGesture.screen.position ) * 0.5f * ( 1.0f - blendValue );
220   gesture.local.position -= ( gesture.local.position - lastGesture.local.position ) * 0.5f * ( 1.0f - blendValue );
221   // Make current displacement relative to previous update-frame now.
222   gesture.screen.displacement = gesture.screen.position - lastGesture.screen.position;
223   gesture.local.displacement = gesture.local.position - lastGesture.local.position;
224   // Calculate velocity relative to previous update-frame
225   float timeDifference = static_cast<float>( gesture.time - lastGesture.time );
226   gesture.screen.velocity = gesture.screen.displacement / timeDifference;
227   gesture.local.velocity = gesture.local.displacement / timeDifference;
228 }
229
230 bool PanGesture::ReadGestures( FrameGestureInfo& info, unsigned int currentTimestamp )
231 {
232   unsigned int previousReadPosition = 0;
233   bool eventFound = false;
234   info.frameGesture = mLastUnmodifiedGesture;
235
236   while( mReadPosition != mWritePosition )
237   {
238     // Copy the gesture first
239     PanInfo currentGesture( mGestures[mReadPosition] );
240
241     if( mProfiling )
242     {
243       mProfiling->mRawData.push_back( PanGestureProfiling::Position( currentGesture.time, currentGesture.screen.position, currentGesture.screen.displacement, currentGesture.screen.velocity, currentGesture.state ) );
244     }
245     info.frameGesture.local.position = currentGesture.local.position;
246     info.frameGesture.local.velocity = currentGesture.local.velocity;
247     info.frameGesture.screen.position = currentGesture.screen.position;
248     info.frameGesture.screen.velocity = currentGesture.screen.velocity;
249
250     if( info.eventsThisFrame > 0 )
251     {
252       info.acceleration = currentGesture.screen.velocity.Length() - mGestures[previousReadPosition].screen.velocity.Length();
253     }
254
255     if( !eventFound )
256     {
257       info.frameGesture.local.displacement = currentGesture.local.displacement;
258       info.frameGesture.screen.displacement = currentGesture.screen.displacement;
259       eventFound = true;
260     }
261     else
262     {
263       info.frameGesture.local.displacement += currentGesture.local.displacement;
264       info.frameGesture.screen.displacement += currentGesture.screen.displacement;
265     }
266     info.frameGesture.time = currentGesture.time;
267
268     // add event to history
269     mPanHistory.push_back( currentGesture );
270     if( currentGesture.state == Gesture::Started )
271     {
272       info.justStarted = true;
273       // clear just finished as we have started new pan
274       info.justFinished = false;
275     }
276     info.justFinished |= ( currentGesture.state == Gesture::Finished || currentGesture.state == Gesture::Cancelled );
277
278     // Update our read position.
279     previousReadPosition = mReadPosition;
280     ++info.eventsThisFrame;
281     ++mReadPosition;
282     mReadPosition %= PAN_GESTURE_HISTORY;
283   }
284   // This code does not determine if the data will be used.
285   return false;
286 }
287
288 bool PanGesture::ReadAndResampleGestures( FrameGestureInfo& info, unsigned int currentTimestamp )
289 {
290   PanInfo lastReadGesture;
291   Dali::Mutex::ScopedLock lock( mMutex );
292   while( mReadPosition != mWritePosition )
293   {
294     // Copy the gesture first
295     lastReadGesture = mGestures[mReadPosition];
296     if( mProfiling )
297     {
298       mProfiling->mRawData.push_back( PanGestureProfiling::Position( lastReadGesture.time, lastReadGesture.screen.position,
299           lastReadGesture.screen.displacement, lastReadGesture.screen.velocity, lastReadGesture.state ) );
300     }
301
302     info.frameGesture.screen.position += lastReadGesture.screen.position;
303     info.frameGesture.local.position += lastReadGesture.local.position;
304     info.frameGesture.screen.velocity += lastReadGesture.screen.velocity;
305     info.frameGesture.local.velocity += lastReadGesture.local.velocity;
306
307     if( lastReadGesture.state == Gesture::Started )
308     {
309       // Clear just finished as we have started new pan.
310       info.justFinished = false;
311       info.justStarted = true;
312     }
313     else
314     {
315       info.justFinished |= ( lastReadGesture.state == Gesture::Finished || lastReadGesture.state == Gesture::Cancelled );
316     }
317
318     // Add event to history
319     mPanHistory.push_back( lastReadGesture );
320
321     // Update our read position.
322     ++info.eventsThisFrame;
323     ++mReadPosition;
324     mReadPosition %= PAN_GESTURE_HISTORY;
325   }
326
327   bool updateProperties = false;
328   if( info.eventsThisFrame > 0 )
329   {
330     // Some events were read this frame.
331     mTargetGesture = lastReadGesture;
332
333     if( info.eventsThisFrame > 1 )
334     {
335       const float eventsThisFrame = static_cast<float>( info.eventsThisFrame );
336       info.frameGesture.screen.position /= eventsThisFrame;
337       info.frameGesture.local.position /= eventsThisFrame;
338       info.frameGesture.screen.velocity /= eventsThisFrame;
339       info.frameGesture.local.velocity /= eventsThisFrame;
340
341       info.frameGesture.screen.displacement = info.frameGesture.screen.position - mLastGesture.screen.position;
342       info.frameGesture.local.displacement = info.frameGesture.local.position - mLastGesture.local.position;
343
344       mNotAtTarget = true;
345     }
346     else
347     {
348       info.frameGesture.screen.displacement = lastReadGesture.screen.displacement;
349       info.frameGesture.local.displacement = lastReadGesture.local.displacement;
350     }
351
352     info.frameGesture.time = currentTimestamp;
353
354     updateProperties = true;
355   }
356   else
357   {
358     // 0 Events this frame.
359     if( mNotAtTarget )
360     {
361       mNotAtTarget = false;
362       info.frameGesture = mTargetGesture;
363       updateProperties = true;
364     }
365     else
366     {
367       info.frameGesture = mLastGesture;
368     }
369   }
370
371   return updateProperties;
372 }
373
374 bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int nextVSyncTime )
375 {
376   if( mPredictionMode == PREDICTION_2 )
377   {
378     // TODO: Have the two prediction modes share more behavior so some parts of mode 2 can
379     // be used with mode 1 etc. Needs code moving and more importantly testing.
380     return NewAlgorithm( lastVSyncTime, nextVSyncTime );
381   }
382
383   if( !mInGesture )
384   {
385     // clear current pan history
386     mPanHistory.clear();
387     mPredictionHistory.clear();
388   }
389
390   FrameGestureInfo frameInfo;
391   bool updateProperties = false;
392
393   // Read input data.
394   // If we are using a form of prediction, read all the input as-is.
395   if( mPredictionMode != PREDICTION_NONE )
396   {
397     // Read input required for prediction algorithms.
398     updateProperties = ReadGestures( frameInfo, lastVSyncTime );
399   }
400   else
401   {
402     // Read and resample input.
403     updateProperties = ReadAndResampleGestures( frameInfo, lastVSyncTime );
404   }
405
406   PanInfo frameGesture = frameInfo.frameGesture;
407   PanInfo unmodifiedGesture = frameGesture;
408
409   // Process input data.
410   mInGesture |= frameInfo.justStarted;
411   if( mInGesture )
412   {
413     // Profiling.
414     if( mProfiling )
415     {
416       mProfiling->mLatestData.push_back( PanGestureProfiling::Position( lastVSyncTime, frameGesture.screen.position,
417           frameGesture.screen.displacement, frameGesture.screen.velocity, frameGesture.state ) );
418     }
419
420     // Perform prediction.
421     if( mPredictionMode == PREDICTION_1 )
422     {
423       // Dynamically change the prediction amount according to the pan velocity acceleration.
424       if( !frameInfo.justStarted )
425       {
426         if( frameInfo.eventsThisFrame <= 1 )
427         {
428           frameInfo.acceleration = frameGesture.screen.velocity.Length() - mLastUnmodifiedGesture.screen.velocity.Length();
429         }
430
431         // Ignore tiny velocity fluctuation to avoid unnecessary prediction amount change
432         if( fabsf( frameInfo.acceleration ) > ACCELERATION_THRESHOLD )
433         {
434           mCurrentPredictionAmount += static_cast<unsigned int>( static_cast<float>( mPredictionAmountAdjustment ) * ( frameInfo.acceleration > Math::MACHINE_EPSILON_0 ? 1.0f : -1.0f ) );
435           if( mCurrentPredictionAmount > mMaxPredictionAmount + mPredictionAmountAdjustment ) // Guard against unsigned int overflow
436           {
437             mCurrentPredictionAmount = 0;
438           }
439         }
440       }
441       else
442       {
443         if( !mPredictionAmountOverridden )
444         {
445           // If the prediction amount has not been modified, default to the correct amount for this algorithm.
446           mPredictionAmount = DEFAULT_PREDICTION_AMOUNT[0];
447         }
448         mCurrentPredictionAmount = mPredictionAmount; // Reset the prediction amount for each new gesture
449       }
450
451       mCurrentPredictionAmount = std::max( mMinPredictionAmount, std::min( mCurrentPredictionAmount, mMaxPredictionAmount ) );
452
453       // Calculate the delta of positions before the prediction
454       Vector2 deltaPosition = frameGesture.screen.position - mLastUnmodifiedGesture.screen.position;
455
456       // Make latest gesture equal to current gesture before interpolation
457       PredictionMode1( frameInfo.eventsThisFrame, frameGesture, mPanHistory, lastVSyncTime, nextVSyncTime );
458
459       // Calculate the delta of positions after the prediction.
460       Vector2 deltaPredictedPosition = frameGesture.screen.position - mLastGesture.screen.position;
461
462       // If the change in the prediction has a different sign than the change in the actual position,
463       // there is overshot (i.e. the current prediction is too large). Return the previous prediction
464       // to give the user's finger a chance to catch up with where we have panned to.
465       bool overshotXAxis = false;
466       bool overshotYAxis = false;
467       if( (deltaPosition.x > Math::MACHINE_EPSILON_0 && deltaPredictedPosition.x < Math::MACHINE_EPSILON_0 )
468        || (deltaPosition.x < Math::MACHINE_EPSILON_0 && deltaPredictedPosition.x > Math::MACHINE_EPSILON_0 ) )
469       {
470         overshotXAxis = true;
471         frameGesture.screen.position.x = mLastGesture.screen.position.x;
472       }
473
474       if( (deltaPosition.y > Math::MACHINE_EPSILON_0 && deltaPredictedPosition.y < Math::MACHINE_EPSILON_0 )
475        || (deltaPosition.y < Math::MACHINE_EPSILON_0 && deltaPredictedPosition.y > Math::MACHINE_EPSILON_0 ) )
476       {
477         overshotYAxis = true;
478         frameGesture.screen.position.y = mLastGesture.screen.position.y;
479       }
480
481       // If there is overshot in one axis, reduce the possible overshot in the other axis,
482       // and reduce the prediction amount so that it doesn't overshoot as easily next time.
483       if(overshotXAxis || overshotYAxis)
484       {
485         mCurrentPredictionAmount -= mPredictionAmountAdjustment;
486         if( mCurrentPredictionAmount > mMaxPredictionAmount + mPredictionAmountAdjustment ) // Guard against unsigned int overflow
487         {
488           mCurrentPredictionAmount = 0;
489         }
490         mCurrentPredictionAmount = std::max( mMinPredictionAmount, std::min( mCurrentPredictionAmount, mMaxPredictionAmount ) );
491
492         if( overshotXAxis && !overshotYAxis )
493         {
494           frameGesture.screen.position.y = ( mLastGesture.screen.position.y + frameGesture.screen.position.y ) * 0.5f;
495         }
496
497         if( overshotYAxis && !overshotXAxis )
498         {
499           frameGesture.screen.position.x = ( mLastGesture.screen.position.x + frameGesture.screen.position.x ) * 0.5f;
500         }
501       }
502
503       updateProperties = true;
504     }
505
506     // Perform smoothing.
507     switch( mSmoothingMode )
508     {
509       case SMOOTHING_NONE:
510       case SMOOTHING_MULTI_TAP:
511       {
512         // No smoothing
513         // TODO: Old algorithm to be able to use multitap smoothing.
514         break;
515       }
516       case SMOOTHING_LAST_VALUE:
517       {
518         if( !frameInfo.justStarted )
519         {
520           if( !mSmoothingAmountOverridden )
521           {
522             // If the smoothing amount has not been modified, default to the correct amount for this algorithm.
523             mSmoothingAmount = DEFAULT_SMOOTHING_AMOUNT[0];
524           }
525           BlendPoints( frameGesture, mLastGesture, mSmoothingAmount );
526         }
527         break;
528       }
529     }
530
531     if( updateProperties )
532     {
533       // only update properties if event received
534       // set latest gesture to raw pan info with unchanged time
535       mPanning.Set( mInGesture & !frameInfo.justFinished );
536       mScreenPosition.Set( frameGesture.screen.position );
537       mScreenDisplacement.Set( frameGesture.screen.displacement );
538       mScreenVelocity.Set( frameGesture.screen.velocity );
539       mLocalPosition.Set( frameGesture.local.position );
540       mLocalDisplacement.Set( frameGesture.local.displacement );
541       mLocalVelocity.Set( frameGesture.local.velocity );
542     }
543
544     if( mProfiling )
545     {
546       mProfiling->mAveragedData.push_back( PanGestureProfiling::Position( frameGesture.time, frameGesture.screen.position,
547           frameGesture.screen.displacement, frameGesture.screen.velocity, frameGesture.state ) );
548     }
549   }
550
551   mLastGesture = frameGesture;
552   mLastUnmodifiedGesture = unmodifiedGesture;
553
554   mInGesture = mInGesture && !frameInfo.justFinished;
555   if( mProfiling && frameInfo.justFinished )
556   {
557     mProfiling->PrintData();
558     mProfiling->ClearData();
559   }
560
561   return updateProperties;
562 }
563
564 const GesturePropertyBool& PanGesture::GetPanningProperty() const
565 {
566   return mPanning;
567 }
568
569 const GesturePropertyVector2& PanGesture::GetScreenPositionProperty() const
570 {
571   return mScreenPosition;
572 }
573
574 const GesturePropertyVector2& PanGesture::GetScreenVelocityProperty() const
575 {
576   return mScreenVelocity;
577 }
578
579 const GesturePropertyVector2& PanGesture::GetScreenDisplacementProperty() const
580 {
581   return mScreenDisplacement;
582 }
583
584 const GesturePropertyVector2& PanGesture::GetLocalPositionProperty() const
585 {
586   return mLocalPosition;
587 }
588
589 const GesturePropertyVector2& PanGesture::GetLocalDisplacementProperty() const
590 {
591   return mLocalDisplacement;
592 }
593
594 const GesturePropertyVector2& PanGesture::GetLocalVelocityProperty() const
595 {
596   return mLocalVelocity;
597 }
598
599 void PanGesture::SetPredictionMode(PredictionMode mode)
600 {
601   mPredictionMode = mode;
602 }
603
604 void PanGesture::SetPredictionAmount(unsigned int amount)
605 {
606   mPredictionAmount = amount;
607   mPredictionAmountOverridden = true;
608 }
609
610 void PanGesture::SetMaximumPredictionAmount(unsigned int amount)
611 {
612   mMaxPredictionAmount = amount;
613 }
614
615 void PanGesture::SetMinimumPredictionAmount(unsigned int amount)
616 {
617   mMinPredictionAmount = amount;
618 }
619
620 void PanGesture::SetPredictionAmountAdjustment(unsigned int amount)
621 {
622   mPredictionAmountAdjustment = amount;
623 }
624
625 void PanGesture::SetSmoothingMode(SmoothingMode mode)
626 {
627   mSmoothingMode = mode;
628 }
629
630 void PanGesture::SetSmoothingAmount(float amount)
631 {
632   mSmoothingAmount = amount;
633   mSmoothingAmountOverridden = true;
634 }
635
636 void PanGesture::SetUseActualTimes( bool value )
637 {
638   mUseActualTimes = value;
639 }
640
641 void PanGesture::SetInterpolationTimeRange( int value )
642 {
643   mInterpolationTimeRange = value;
644 }
645
646 void PanGesture::SetScalarOnlyPredictionEnabled( bool value )
647 {
648   mScalarOnlyPredictionEnabled = value;
649 }
650
651 void PanGesture::SetTwoPointPredictionEnabled( bool value )
652 {
653   mTwoPointPredictionEnabled = value;
654 }
655
656 void PanGesture::SetTwoPointInterpolatePastTime( int value )
657 {
658   mTwoPointPastInterpolateTime = value;
659 }
660
661 void PanGesture::SetTwoPointVelocityBias( float value )
662 {
663   mTwoPointVelocityBias = value;
664 }
665
666 void PanGesture::SetTwoPointAccelerationBias( float value )
667 {
668   mTwoPointAccelerationBias = value;
669 }
670
671 void PanGesture::SetMultitapSmoothingRange( int value )
672 {
673   mMultiTapSmoothingRange = value;
674 }
675
676 void PanGesture::EnableProfiling()
677 {
678   if( !mProfiling )
679   {
680     mProfiling = new PanGestureProfiling();
681   }
682 }
683
684 void PanGesture::ResetDefaultProperties( BufferIndex updateBufferIndex )
685 {
686   mScreenPosition.Reset();
687   mScreenDisplacement.Reset();
688   mLocalPosition.Reset();
689   mLocalDisplacement.Reset();
690   mPanning.Reset();
691 }
692
693 PanGesture::PanGesture()
694 : mPanning(),
695   mGestures(),
696   mWritePosition( 0 ),
697   mReadPosition( 0 ),
698   mNotAtTarget( false ),
699   mInGesture( false ),
700   mPredictionAmountOverridden( false ),
701   mSmoothingAmountOverridden( false ),
702   mProfiling( NULL ),
703
704   // Set environment variable defaults:
705   mPredictionMode( DEFAULT_PREDICTION_MODE ),
706   mPredictionAmount( DEFAULT_PREDICTION_AMOUNT[0] ),
707   mCurrentPredictionAmount( DEFAULT_PREDICTION_AMOUNT[0] ),
708   mMaxPredictionAmount( DEFAULT_MAX_PREDICTION_AMOUNT ),
709   mMinPredictionAmount( DEFAULT_MIN_PREDICTION_AMOUNT ),
710   mPredictionAmountAdjustment( DEFAULT_PREDICTION_AMOUNT_ADJUSTMENT ),
711   mSmoothingMode( DEFAULT_SMOOTHING_MODE ),
712   mSmoothingAmount( DEFAULT_SMOOTHING_AMOUNT[0] ),
713   mUseActualTimes( DEFAULT_USE_ACTUAL_TIMES ),
714   mInterpolationTimeRange( DEFAULT_INTERPOLATION_TIME_RANGE ),
715   mScalarOnlyPredictionEnabled( DEFAULT_SCALAR_ONLY_PREDICTION_ENABLED ),
716   mTwoPointPredictionEnabled( DEFAULT_TWO_POINT_PREDICTION_ENABLED ),
717   mTwoPointPastInterpolateTime( DEFAULT_TWO_POINT_PAST_INTERPOLATE_TIME ),
718   mTwoPointVelocityBias( DEFAULT_TWO_POINT_VELOCITY_BIAS ),
719   mTwoPointAccelerationBias( DEFAULT_TWO_POINT_ACCELERATION_BIAS ),
720   mMultiTapSmoothingRange( DEFAULT_MULTITAP_SMOOTHING_RANGE )
721 {
722
723 }
724
725 // Prediction mode 2 related code and functions follow:
726
727 unsigned int PanGesture::ReadFrameEvents()
728 {
729   unsigned int eventsThisFrame;
730   // Copy the events into a linear buffer while holding the mutex.
731   // This is so the lock is not held while any processing is done.
732   Dali::Mutex::ScopedLock lock( mMutex );
733   for( eventsThisFrame = 0; mReadPosition != mWritePosition; ++eventsThisFrame )
734   {
735     mReadGestures[ eventsThisFrame ] = mGestures[ mReadPosition ];
736     ++mReadPosition;
737     mReadPosition %= PAN_GESTURE_HISTORY;
738   }
739   return eventsThisFrame;
740 }
741
742 // TODO: eventsThisFrame parameter can be removed if we use a smarter container.
743 bool PanGesture::InputRateConversion( PanInfo& rateConvertedGesture, unsigned int eventsThisFrame,
744     unsigned int currentFrameTime, unsigned int lastFrameTime, bool& justStarted, bool& justFinished )
745 {
746   // TODO: Lots of variables on the stack. Needs optimizing.
747   PanInfo readGesture;
748   PanInfo firstReadGesture;
749   unsigned int eventsKeptThisFrame = 0;
750
751   for( unsigned int readPosition = 0; readPosition < eventsThisFrame; ++readPosition )
752   {
753     // Copy the gesture first
754     readGesture = mReadGestures[ readPosition ];
755
756     if( mProfiling )
757     {
758       mProfiling->mRawData.push_back( PanGestureProfiling::Position( readGesture.time, readGesture.screen.position,
759           readGesture.screen.displacement, readGesture.screen.velocity, readGesture.state ) );
760     }
761
762     if( readGesture.state == Gesture::Started )
763     {
764       // Clear pan data.
765       mPanHistory.clear();
766       mPredictionHistory.clear();
767       mLastAcceleration.local = Vector2::ZERO;
768       mLastAcceleration.screen = Vector2::ZERO;
769       mLastInterpolatedAcceleration.local = Vector2::ZERO;
770       mLastInterpolatedAcceleration.screen = Vector2::ZERO;
771       mLastInitialAcceleration.local = Vector2::ZERO;
772       mLastInitialAcceleration.screen = Vector2::ZERO;
773       PanInfo startInfo;
774       mLastGesture = startInfo;
775       mLastSecondInterpolatedPoint = startInfo;
776       mLastPredictedPoint = startInfo;
777       mLastFrameReadGesture = startInfo;
778       rateConvertedGesture = startInfo;
779       firstReadGesture = readGesture;
780       eventsKeptThisFrame = 0;
781       mNotAtTarget = false;
782       justFinished = false;
783       justStarted = true;
784       mInGesture = true;
785
786       if( !mPredictionAmountOverridden )
787       {
788         // If the prediction amount has not been modified, default to the correct amount for this algorithm.
789         mPredictionAmount = DEFAULT_PREDICTION_AMOUNT[1];
790       }
791       mCurrentPredictionAmount = mPredictionAmount;
792     }
793     else
794     {
795       justFinished |= ( readGesture.state == Gesture::Finished || readGesture.state == Gesture::Cancelled );
796     }
797
798     rateConvertedGesture.screen.position += readGesture.screen.position;
799     rateConvertedGesture.local.position += readGesture.local.position;
800     rateConvertedGesture.screen.velocity += readGesture.screen.velocity;
801     rateConvertedGesture.local.velocity += readGesture.local.velocity;
802     rateConvertedGesture.screen.displacement += readGesture.screen.displacement;
803     rateConvertedGesture.local.displacement += readGesture.local.displacement;
804
805     ++eventsKeptThisFrame;
806   }
807
808   bool storeGesture = false;
809   if( eventsKeptThisFrame > 0 )
810   {
811     // Some events were read this frame.
812     if( eventsKeptThisFrame > 1 )
813     {
814       const float eventDivisor = static_cast<float>( eventsKeptThisFrame );
815       rateConvertedGesture.screen.position /= eventDivisor;
816       rateConvertedGesture.local.position /= eventDivisor;
817       rateConvertedGesture.screen.velocity /= eventDivisor;
818       rateConvertedGesture.local.velocity /= eventDivisor;
819       rateConvertedGesture.screen.displacement /= eventDivisor;
820       rateConvertedGesture.local.displacement /= eventDivisor;
821
822       mTargetGesture = readGesture;
823       mNotAtTarget = true;
824     }
825     else
826     {
827       mNotAtTarget = false;
828     }
829
830     rateConvertedGesture.time = currentFrameTime;
831     storeGesture = true;
832   }
833   else
834   {
835     // We did not get any event this frame.
836     // If we just started (or aren't in a gesture), exit.
837     if( !mInGesture || justStarted )
838     {
839       // We cannot guess what the event could be as we have no other events to base the guess from.
840       return false;
841     }
842
843     // As we are currently in a gesture, we can estimate an event.
844     readGesture = mLastFrameReadGesture;
845     readGesture.time = currentFrameTime;
846
847     // Take the last event, halve the acceleration, and use that.
848     const float accelerationDegrade = 2.0f;
849     Vector2 degradedAccelerationLocal( mLastAcceleration.local /= accelerationDegrade );
850     Vector2 degradedAccelerationScreen( mLastAcceleration.screen /= accelerationDegrade );
851
852     float outputTimeGranularity( GetDivisibleTimeDifference( currentFrameTime, lastFrameTime, 1.0f, OUTPUT_TIME_DIFFERENCE ) );
853
854     readGesture.local.velocity = degradedAccelerationLocal * outputTimeGranularity;
855     readGesture.local.displacement = readGesture.local.velocity * outputTimeGranularity;
856     readGesture.local.position = mLastFrameReadGesture.local.position + readGesture.local.displacement;
857     readGesture.screen.velocity = degradedAccelerationScreen * outputTimeGranularity;
858     readGesture.screen.displacement = readGesture.screen.velocity * outputTimeGranularity;
859     readGesture.screen.position = mLastFrameReadGesture.screen.position + readGesture.screen.displacement;
860
861     rateConvertedGesture = readGesture;
862     eventsKeptThisFrame = 1;
863     storeGesture = true;
864   }
865
866   if( eventsKeptThisFrame > 0 )
867   {
868     // Store last read gesture.
869     readGesture.time = currentFrameTime;
870     mLastFrameReadGesture = readGesture;
871
872     if( eventsKeptThisFrame > 2 )
873     {
874       DALI_LOG_WARNING( "Got events this frame:%d (more than 2 will compromise result)\n", eventsKeptThisFrame );
875     }
876   }
877
878   if( storeGesture )
879   {
880     // Store final converted result.
881     mPanHistory.push_back( rateConvertedGesture );
882   }
883   return true;
884 }
885
886 bool PanGesture::InterpolatePoint( PanInfoHistory& history, unsigned int currentTime, unsigned int targetTime, unsigned int range,
887       PanInfo& outPoint, RelativeVectors& acceleration, int outputTimeGranularity, bool eraseUnused )
888 {
889   unsigned int maxHistoryTime = targetTime - range;
890   unsigned int tapsUsed = 0;
891   outPoint.time = targetTime;
892   float divisor = 0.0f;
893   float accelerationDivisor = 0.0f;
894   PanInfoHistoryIter historyBegin = history.begin();
895   PanInfoHistoryIter lastIt = history.end();
896   bool pointGenerated = false;
897   bool havePreviousPoint = false;
898   RelativeVectors newAcceleration;
899
900   // Iterate through point history to perform interpolation.
901   for( PanInfoHistoryIter it = historyBegin; it != history.end(); )
902   {
903     unsigned int gestureTime = it->time;
904
905     if( gestureTime < maxHistoryTime )
906     {
907       // Too far in the past, discard.
908       // Clean history as we go (if requested).
909       if( eraseUnused )
910       {
911         it = history.erase( it );
912       }
913       else
914       {
915         ++it;
916         continue;
917       }
918     }
919     else
920     {
921       float timeDelta( static_cast<float>( abs( int( targetTime - gestureTime ) ) ) );
922       // Handle low time deltas.
923       if( timeDelta < 1.0f )
924       {
925         timeDelta = 1.0f;
926       }
927
928       outPoint.local.position += it->local.position / timeDelta;
929       outPoint.screen.position += it->screen.position / timeDelta;
930       outPoint.local.velocity += it->local.velocity / timeDelta;
931       outPoint.screen.velocity += it->screen.velocity / timeDelta;
932       outPoint.local.displacement += it->local.displacement / timeDelta;
933       outPoint.screen.displacement += it->screen.displacement / timeDelta;
934
935       divisor += 1.0f / timeDelta;
936
937       // Acceleration requires a previous point.
938       if( havePreviousPoint )
939       {
940         // Time delta of input.
941         float timeDifference( GetDivisibleTimeDifference( it->time, lastIt->time, 1.0f, OUTPUT_TIME_DIFFERENCE ) );
942
943         newAcceleration.local += ( ( it->local.velocity - lastIt->local.velocity ) / timeDifference ) / timeDelta;
944         newAcceleration.screen += ( ( it->screen.velocity - lastIt->screen.velocity ) / timeDifference ) / timeDelta;
945
946         accelerationDivisor += 1.0f / timeDelta;
947       }
948       else
949       {
950         havePreviousPoint = true;
951       }
952
953       tapsUsed++;
954       lastIt = it;
955       ++it;
956     }
957   }
958
959   // Divide results by their respective divisors.
960   if( tapsUsed > 0 )
961   {
962     if( divisor > 0.0f )
963     {
964       outPoint.local.position /= divisor;
965       outPoint.screen.position /= divisor;
966       outPoint.local.velocity /= divisor;
967       outPoint.screen.velocity /= divisor;
968       outPoint.local.displacement /= divisor;
969       outPoint.screen.displacement /= divisor;
970     }
971
972     if( tapsUsed > 1 )
973     {
974       if( accelerationDivisor > 0.0f )
975       {
976         newAcceleration.local /= accelerationDivisor;
977         newAcceleration.screen /= accelerationDivisor;
978       }
979
980       float accelerationSmoothing( ACCELERATION_SMOOTHING );
981       newAcceleration.local = ( acceleration.local * accelerationSmoothing ) + ( newAcceleration.local * ( 1.0f - accelerationSmoothing ) );
982       newAcceleration.screen = ( acceleration.screen * accelerationSmoothing ) + ( newAcceleration.screen * ( 1.0f - accelerationSmoothing ) );
983     }
984     else
985     {
986       // If we just started, last velocity was 0. So difference of zero to current velocity over time gives acceleration of the first point.
987       newAcceleration.local = outPoint.local.velocity / static_cast<float>( outputTimeGranularity );
988       newAcceleration.screen = outPoint.screen.velocity / static_cast<float>( outputTimeGranularity );
989     }
990     pointGenerated = true;
991   }
992
993   acceleration.local = newAcceleration.local;
994   acceleration.screen = newAcceleration.screen;
995   return pointGenerated;
996 }
997
998 float PanGesture::GetDivisibleTimeDifference( int timeA, int timeB, float minimumDelta, float overrideDifference )
999 {
1000   float timeDifference( overrideDifference );
1001   if( mUseActualTimes )
1002   {
1003     timeDifference = static_cast<float>( abs( timeA - timeB ) );
1004     if( timeDifference < minimumDelta )
1005     {
1006       timeDifference = minimumDelta;
1007     }
1008   }
1009   return timeDifference;
1010 }
1011
1012 void PanGesture::LimitAccelerationChange( RelativeVectors& currentAcceleration, RelativeVectors& lastAcceleration, float changeLimit )
1013 {
1014   // We don't use the float parameter version of clamp here, as that will create the capping vectors twice in total.
1015   Vector2 capMinimum( -changeLimit, -changeLimit );
1016   Vector2 capMaximum( changeLimit, changeLimit );
1017   Vector2 accelerationDeltaLocal( currentAcceleration.local - lastAcceleration.local );
1018   Vector2 accelerationDeltaScreen( currentAcceleration.screen - lastAcceleration.screen );
1019   accelerationDeltaLocal.Clamp( capMinimum, capMaximum );
1020   accelerationDeltaScreen.Clamp( capMinimum, capMaximum );
1021   currentAcceleration.local = lastAcceleration.local + accelerationDeltaLocal;
1022   currentAcceleration.screen = lastAcceleration.screen + accelerationDeltaScreen;
1023 }
1024
1025 void PanGesture::PredictionMode2( PanInfo& startPoint, RelativeVectors& accelerationToUse,
1026     PanInfo& predictedPoint, unsigned int currentFrameTime, unsigned int previousFrameTime, bool noPreviousData )
1027 {
1028   // Do the prediction (based on mode).
1029   if( mScalarOnlyPredictionEnabled )
1030   {
1031     // We are doing scalar based prediction.
1032     // This divisor is to help tuning by giving the scalar only result
1033     // a similar prediction amount to the integrated result.
1034     float scalarVelocityMultiplier = static_cast<float>( mCurrentPredictionAmount ) / 1.364f;
1035     predictedPoint.local.position = startPoint.local.position + ( startPoint.local.velocity * scalarVelocityMultiplier );
1036     predictedPoint.screen.position = startPoint.screen.position + ( startPoint.screen.velocity * scalarVelocityMultiplier );
1037   }
1038   else
1039   {
1040     // We are doing integration based prediction.
1041     float predictionDelta = static_cast<float>( mCurrentPredictionAmount );
1042
1043     predictedPoint.local.position = startPoint.local.position + ( startPoint.local.velocity * predictionDelta ) +
1044         ( accelerationToUse.local * ( predictionDelta * predictionDelta * 0.5f ) );
1045     predictedPoint.screen.position = startPoint.screen.position + ( startPoint.screen.velocity * predictionDelta ) +
1046         ( accelerationToUse.screen * ( predictionDelta * predictionDelta * 0.5f ) );
1047   }
1048
1049   // Calculate remaining gesture data from the result.
1050   float timeDifference( GetDivisibleTimeDifference( currentFrameTime, previousFrameTime, 1.0f, OUTPUT_TIME_DIFFERENCE ) );
1051   if( noPreviousData )
1052   {
1053     predictedPoint.local.displacement = predictedPoint.local.position - startPoint.local.position;
1054     predictedPoint.screen.displacement = predictedPoint.screen.position - startPoint.screen.position;
1055   }
1056   else
1057   {
1058     predictedPoint.local.displacement = predictedPoint.local.position - mLastPredictedPoint.local.position;
1059     predictedPoint.screen.displacement = predictedPoint.screen.position - mLastPredictedPoint.screen.position;
1060   }
1061   predictedPoint.local.velocity = predictedPoint.local.displacement / timeDifference;
1062   predictedPoint.screen.velocity = predictedPoint.screen.displacement / timeDifference;
1063
1064   // TODO: Experimental - not used at run time. Left in code for reference only.
1065   if( TEST_TUNE_ENABLE_OVERSHOOT_PROTECTION )
1066   {
1067     // Overshoot protection
1068     if( !noPreviousData )
1069     {
1070       if( ( mLastPredictedPoint.local.velocity.x > Math::MACHINE_EPSILON_0 && predictedPoint.local.velocity.x < Math::MACHINE_EPSILON_0 )
1071         || ( mLastPredictedPoint.local.velocity.x < Math::MACHINE_EPSILON_0 && predictedPoint.local.velocity.x > Math::MACHINE_EPSILON_0 ) )
1072       {
1073         predictedPoint.local.position.x = mLastPredictedPoint.local.position.x;
1074         predictedPoint.screen.position.x = mLastPredictedPoint.screen.position.x;
1075         mPredictionHistory.clear();
1076       }
1077       if( ( mLastPredictedPoint.local.velocity.y > Math::MACHINE_EPSILON_0 && predictedPoint.local.velocity.y < Math::MACHINE_EPSILON_0 )
1078         || ( mLastPredictedPoint.local.velocity.y < Math::MACHINE_EPSILON_0 && predictedPoint.local.velocity.y > Math::MACHINE_EPSILON_0 ) )
1079       {
1080         predictedPoint.local.position.y = mLastPredictedPoint.local.position.y;
1081         predictedPoint.screen.position.y = mLastPredictedPoint.screen.position.y;
1082         mPredictionHistory.clear();
1083       }
1084     }
1085   }
1086
1087   predictedPoint.time = currentFrameTime;
1088   mLastPredictedPoint = predictedPoint;
1089 }
1090
1091 // TODO: This needs a better name! It is called this instead of prediction mode 2 because:
1092 // 1) It is the entire workflow, not just prediction.
1093 // 2) To make it less confusing as there is a function that does prediction alone called PerformPredictionMode2.
1094 // Ultimately we need to combine the old and new code modularly so there is one code path that can optionally run different functions based on configuration.
1095 // At the moment, the differences between the inputs & outputs of these different functions prevent that, but this can be resolved.
1096 bool PanGesture::NewAlgorithm( unsigned int lastVSyncTime, unsigned int nextVSyncTime )
1097 {
1098   if( !mInGesture )
1099   {
1100     // clear current pan history
1101     mPanHistory.clear();
1102     mPredictionHistory.clear();
1103   }
1104
1105   /*#########################################################################################
1106     #### Read in all gestures received this frame first (holding a lock for a short time)
1107     #########################################################################################*/
1108
1109   unsigned int eventsThisFrame = ReadFrameEvents();
1110
1111   /*#########################################################################################
1112     #### Perform input rate-conversion on all gestures received this frame.
1113     #### This also populates the pan history.
1114     #########################################################################################*/
1115
1116   bool justStarted = false;
1117   bool justFinished = false;
1118   PanInfo rateConvertedGesture;
1119   if( !InputRateConversion( rateConvertedGesture, eventsThisFrame, nextVSyncTime, lastVSyncTime, justStarted, justFinished ) )
1120   {
1121     // There's nothing we can do with the input, exit.
1122     return false;
1123   }
1124
1125   /*#########################################################################################
1126     #### If we are in gesture, Get first interpolated point with: target time = current time
1127     #########################################################################################*/
1128
1129   bool performUpdate = false;
1130   RelativeVectors currentAcceleration;
1131   currentAcceleration.local = mLastInitialAcceleration.local;
1132   currentAcceleration.screen = mLastInitialAcceleration.screen;
1133
1134   if( mInGesture || justStarted )
1135   {
1136     // Get first interpolated point.
1137     // TODO: Erase time should be maximum of both interpolated point ranges in past.
1138     PanInfo targetPoint;
1139     float outputTimeGranularity( GetDivisibleTimeDifference( nextVSyncTime, lastVSyncTime, 1.0f, OUTPUT_TIME_DIFFERENCE ) );
1140     bool pointGenerated = InterpolatePoint( mPanHistory, nextVSyncTime, nextVSyncTime, mInterpolationTimeRange,
1141         targetPoint, currentAcceleration, static_cast<int>( outputTimeGranularity ), true ); // truncated
1142     if( pointGenerated )
1143     {
1144       mLastInitialAcceleration.local = currentAcceleration.local;
1145       mLastInitialAcceleration.screen = currentAcceleration.screen;
1146       performUpdate = true;
1147     }
1148     else
1149     {
1150       targetPoint = rateConvertedGesture;
1151       currentAcceleration.local = mLastInitialAcceleration.local;
1152       currentAcceleration.screen = mLastInitialAcceleration.screen;
1153       // TODO: Potentially do something to substitute lack of generated point (and perform update).
1154     }
1155
1156     /*#########################################################################################
1157       #### Limit the change of acceleration of the first interpolated point since last time
1158       #########################################################################################*/
1159
1160     if( !justStarted )
1161     {
1162       LimitAccelerationChange( currentAcceleration, mLastAcceleration, ACCELERATION_CAP );
1163     }
1164     mLastAcceleration.local = currentAcceleration.local;
1165     mLastAcceleration.screen = currentAcceleration.screen;
1166
1167     /*#########################################################################################
1168       #### Get second interpolated point, and blend the resultant velocity and acceleration (optional)
1169       #########################################################################################*/
1170
1171     PanInfo outPoint;
1172     RelativeVectors interpolatedAcceleration;
1173     if( mTwoPointPredictionEnabled )
1174     {
1175       // Get second interpolated point with target time = current time - past interpolate time.
1176       unsigned int pastInterpolateTime = nextVSyncTime - mTwoPointPastInterpolateTime;
1177       PanInfo outPoint;
1178       RelativeVectors interpolatedAcceleration;
1179       interpolatedAcceleration.local = mLastInterpolatedAcceleration.local;
1180       interpolatedAcceleration.screen = mLastInterpolatedAcceleration.screen;
1181       if( !InterpolatePoint( mPanHistory, nextVSyncTime, pastInterpolateTime, mTwoPointPastInterpolateTime,
1182           outPoint, interpolatedAcceleration, static_cast<int>( outputTimeGranularity ), false ) ) // truncated
1183       {
1184         if( justStarted )
1185         {
1186           outPoint = targetPoint;
1187         }
1188         else
1189         {
1190           outPoint = mLastSecondInterpolatedPoint;
1191         }
1192       }
1193       mLastInterpolatedAcceleration.local = interpolatedAcceleration.local;
1194       mLastInterpolatedAcceleration.screen = interpolatedAcceleration.screen;
1195       mLastSecondInterpolatedPoint = outPoint;
1196
1197       // Combine the first interpolated point and the second interpolated point.
1198       // by mixing them with the configured amount. This is done for acceleration and velocity.
1199       // It could be optionally done for position too, but this typically is worse as it means we have to predict further ahead.
1200       float currentVelocityMultiplier( 1.0f - mTwoPointVelocityBias );
1201       float lastVelocityMultiplier( mTwoPointVelocityBias );
1202       targetPoint.local.velocity = ( outPoint.local.velocity * lastVelocityMultiplier ) + ( targetPoint.local.velocity * currentVelocityMultiplier );
1203       targetPoint.screen.velocity = ( outPoint.screen.velocity * lastVelocityMultiplier ) + ( targetPoint.screen.velocity * currentVelocityMultiplier );
1204       float currentAccelerationMultiplier( 1.0f - mTwoPointAccelerationBias );
1205       float lastAccelerationMultiplier( mTwoPointAccelerationBias );
1206       currentAcceleration.local = ( interpolatedAcceleration.local * lastAccelerationMultiplier ) + ( currentAcceleration.local * currentAccelerationMultiplier );
1207       currentAcceleration.screen = ( interpolatedAcceleration.screen * lastAccelerationMultiplier ) + ( currentAcceleration.screen * currentAccelerationMultiplier );
1208     }
1209
1210     /*#########################################################################################
1211       #### Perform prediction
1212       #########################################################################################*/
1213
1214     PanInfo predictedPoint;
1215     PredictionMode2( targetPoint, currentAcceleration, predictedPoint, nextVSyncTime, lastVSyncTime, justStarted );
1216     targetPoint = predictedPoint;
1217
1218     /*#########################################################################################
1219       #### Smoothing
1220       #########################################################################################*/
1221
1222     // If we are using multi-tap smoothing, keep a history of predicted results.
1223     if( mSmoothingMode == SMOOTHING_MULTI_TAP )
1224     {
1225       mPredictionHistory.push_back( targetPoint );
1226     }
1227
1228     if( !justStarted )
1229     {
1230       float outputTimeGranularity( GetDivisibleTimeDifference( nextVSyncTime, lastVSyncTime, 1.0f, OUTPUT_TIME_DIFFERENCE ) );
1231       if( mSmoothingMode == SMOOTHING_MULTI_TAP )
1232       {
1233         // Perform Multi-tap Smoothing.
1234         RelativeVectors blank;
1235         InterpolatePoint( mPredictionHistory, nextVSyncTime, nextVSyncTime, mMultiTapSmoothingRange,
1236             targetPoint, blank, static_cast<int>( outputTimeGranularity ), true ); // truncated
1237       }
1238       else
1239       {
1240         // Perform Single-tap Smoothing.
1241         if( !mSmoothingAmountOverridden )
1242         {
1243           // If the smoothing amount has not been modified, default to the correct amount for this algorithm.
1244           mSmoothingAmount = DEFAULT_SMOOTHING_AMOUNT[1];
1245         }
1246         BlendPoints( targetPoint, mLastGesture, mSmoothingAmount );
1247       }
1248
1249       /*#########################################################################################
1250         #### Finalize other point data (from position)
1251         #########################################################################################*/
1252
1253       targetPoint.local.displacement = targetPoint.local.position - mLastGesture.local.position;
1254       targetPoint.local.velocity = targetPoint.local.displacement / outputTimeGranularity;
1255       targetPoint.screen.displacement = targetPoint.screen.position - mLastGesture.screen.position;
1256       targetPoint.screen.velocity = targetPoint.screen.displacement / outputTimeGranularity;
1257     }
1258
1259     /*#########################################################################################
1260       #### Send out the new point, by setting the properties
1261       #### (Constraints will automatically react to this)
1262       #########################################################################################*/
1263
1264     if( performUpdate )
1265     {
1266       mPanning.Set( mInGesture & !justFinished );
1267       mScreenPosition.Set( targetPoint.screen.position );
1268       mScreenDisplacement.Set( targetPoint.screen.displacement );
1269       mScreenVelocity.Set( targetPoint.screen.velocity );
1270       mLocalPosition.Set( targetPoint.local.position );
1271       mLocalDisplacement.Set( targetPoint.local.displacement );
1272       mLocalVelocity.Set( targetPoint.local.velocity );
1273
1274       mLastGesture = targetPoint;
1275
1276       if( mProfiling )
1277       {
1278         mProfiling->mAveragedData.push_back( PanGestureProfiling::Position( targetPoint.time, targetPoint.screen.position,
1279             targetPoint.screen.displacement, targetPoint.screen.velocity, targetPoint.state ) );
1280       }
1281     }
1282   }
1283
1284   mInGesture = mInGesture && !justFinished;
1285
1286   return performUpdate;
1287 }
1288
1289
1290 } // namespace SceneGraph
1291
1292 } // namespace Internal
1293
1294 } // namespace Dali