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