Improved pan gesture prediction 70/34470/4 tizen_3.0.2014.q4_common tizen_3.0.2015.q1_common accepted/tizen/common/20150205.080851 accepted/tizen/common/20150205.165930 accepted/tizen/common/20150209.121019 accepted/tizen/mobile/20150211.014650 accepted/tizen/tv/20150210.012938 accepted/tizen/wearable/20150210.014755 submit/tizen/20150205.011244 submit/tizen/20150205.132622 submit/tizen/20150205.132635 submit/tizen/20150206.044231
authorRichard Huang <r.huang@samsung.com>
Tue, 27 Jan 2015 16:31:39 +0000 (16:31 +0000)
committerRichard Huang <r.huang@samsung.com>
Wed, 4 Feb 2015 16:02:46 +0000 (16:02 +0000)
[problem]  A bigger prediction interpolation makes the prediction result less usable.
[cause]    The changing velocity of pan gesture could cause overshoot for the prediction
           (and sometimes in the wrong direction), which makes the scrolling jerky.
[solution] Dynamically adpat the prediction interpolation to the change of pan velocity.
           When overshoot is detected, alter any prediction in the wrong direction and
           decrease the prediction interpolation so that it doesn't overshoot as easily
           in the next frame.

Change-Id: I71afc4d601c865785a1629a2c186d45547e6117c

automated-tests/src/dali/utc-Dali-PanGestureDetector.cpp
dali/integration-api/input-options.cpp
dali/integration-api/input-options.h
dali/internal/event/events/gesture-event-processor.cpp
dali/internal/event/events/gesture-event-processor.h
dali/internal/event/events/pan-gesture-processor.cpp
dali/internal/event/events/pan-gesture-processor.h
dali/internal/update/gestures/pan-gesture-profiling.cpp
dali/internal/update/gestures/pan-gesture-profiling.h
dali/internal/update/gestures/scene-graph-pan-gesture.cpp
dali/internal/update/gestures/scene-graph-pan-gesture.h

index a850887f149e9db980f2ca3b8a5c19af01459f55..a902e9fdbe0a11cddf0014edd18a6cec8be5a9ff 100644 (file)
@@ -2188,7 +2188,7 @@ int UtcDaliPanGesturePredictionNoSmoothing(void)
   application.SendNotification();
   application.Render();
 
-  Vector2 direction(Vector2::XAXIS * -5.0f);
+  Vector2 direction(Vector2::XAXIS * -1.0f);
   Vector2 previousPosition( 20.0f, 20.0f );
   Vector2 currentPosition( 20.0f, 10.0f );
   PerformSwipeGestureSwipe(application, Vector2(1.0f, 1.0f), direction, PAN_GESTURE_UPDATE_COUNT, true);
@@ -2234,7 +2234,7 @@ int UtcDaliPanGesturePredictionSmoothing(void)
   application.SendNotification();
   application.Render();
 
-  Vector2 direction(Vector2::XAXIS * -5.0f);
+  Vector2 direction(Vector2::XAXIS * -1.0f);
   Vector2 previousPosition( 20.0f, 20.0f );
   Vector2 currentPosition( 20.0f, 10.0f );
   PerformSwipeGestureSwipe(application, Vector2(1.0f, 1.0f), direction, PAN_GESTURE_UPDATE_COUNT, true);
index 2efe516e1f45f3676ed856eaf046942a7e23907c..41e3ab076c035886e284b7c46d59c502aeb65537 100644 (file)
@@ -24,6 +24,24 @@ void SetPanGesturePredictionAmount(unsigned int amount)
   eventProcessor.SetPanGesturePredictionAmount(amount);
 }
 
+void SetPanGestureMaximumPredictionAmount( unsigned int amount )
+{
+  GestureEventProcessor& eventProcessor = ThreadLocalStorage::Get().GetGestureEventProcessor();
+  eventProcessor.SetPanGestureMaximumPredictionAmount(amount);
+}
+
+void SetPanGestureMinimumPredictionAmount( unsigned int amount )
+{
+  GestureEventProcessor& eventProcessor = ThreadLocalStorage::Get().GetGestureEventProcessor();
+  eventProcessor.SetPanGestureMinimumPredictionAmount(amount);
+}
+
+void SetPanGesturePredictionAmountAdjustment( unsigned int amount )
+{
+  GestureEventProcessor& eventProcessor = ThreadLocalStorage::Get().GetGestureEventProcessor();
+  eventProcessor.SetPanGesturePredictionAmountAdjustment(amount);
+}
+
 void SetPanGestureSmoothingMode(int mode)
 {
   GestureEventProcessor& eventProcessor = ThreadLocalStorage::Get().GetGestureEventProcessor();
index 9b8458e906164302ca5e8482688ebad0fc2e4625..3c630a41b494fee5e89518ce752aec2ac8465568 100644 (file)
@@ -39,12 +39,40 @@ namespace Integration
 DALI_IMPORT_API void SetPanGesturePredictionMode( int mode );
 
 /**
- * @brief Called by adaptor to set the prediction amount of the pan gesture from an environment variable
+ * @brief Called by adaptor to set the prediction amount of the pan gesture
+ * from an environment variable
  *
  * @param[in] amount The prediction amount in milliseconds
  */
 DALI_IMPORT_API void SetPanGesturePredictionAmount(unsigned int amount);
 
+/**
+ * @brief Sets the upper bound of the prediction amount for clamping
+ * from an environment variable
+ *
+ * @param[in] amount The prediction amount in milliseconds
+ */
+DALI_IMPORT_API void SetPanGestureMaximumPredictionAmount( unsigned int amount );
+
+/**
+ * @brief Sets the lower bound of the prediction amount for clamping
+ * from an environment variable
+ *
+ * @param[in] amount The prediction amount in milliseconds
+ */
+DALI_IMPORT_API void SetPanGestureMinimumPredictionAmount( unsigned int amount );
+
+/**
+ * @brief Sets the prediction amount to adjust when the pan velocity is changed
+ * from an environment variable. If the pan velocity is accelerating, the prediction
+ * amount will be increased by the specified amount until it reaches the upper bound.
+ * If the pan velocity is decelerating, the prediction amount will be decreased by
+ * the specified amount until it reaches the lower bound.
+ *
+ * @param[in] amount The prediction amount in milliseconds
+ */
+DALI_IMPORT_API void SetPanGesturePredictionAmountAdjustment( unsigned int amount );
+
 /**
  * @brief Called to set how pan gestures smooth input
  *
@@ -53,7 +81,7 @@ DALI_IMPORT_API void SetPanGesturePredictionAmount(unsigned int amount);
 DALI_IMPORT_API void SetPanGestureSmoothingMode( int mode );
 
 /**
- * @brief Sets the prediction amount of the pan gesture
+ * @brief Sets the smoothing amount of the pan gesture
  *
  * @param[in] amount The smoothing amount [0.0f,1.0f] - 0.0f would be no smoothing, 1.0f maximum smoothing
  */
index 4a13feb3246ba7d4a2a8e33ddd133a808eab18a9..0482b19e7d1267329299209030975edf813aa6e4 100644 (file)
@@ -240,6 +240,21 @@ void GestureEventProcessor::SetPanGesturePredictionAmount( unsigned int amount )
   mPanGestureProcessor.SetPredictionAmount(amount);
 }
 
+void GestureEventProcessor::SetPanGestureMaximumPredictionAmount( unsigned int amount )
+{
+  mPanGestureProcessor.SetMaximumPredictionAmount(amount);
+}
+
+void GestureEventProcessor::SetPanGestureMinimumPredictionAmount( unsigned int amount )
+{
+  mPanGestureProcessor.SetMinimumPredictionAmount(amount);
+}
+
+void GestureEventProcessor::SetPanGesturePredictionAmountAdjustment( unsigned int amount )
+{
+  mPanGestureProcessor.SetPredictionAmountAdjustment(amount);
+}
+
 void GestureEventProcessor::SetPanGestureSmoothingMode(int mode)
 {
   mPanGestureProcessor.SetSmoothingMode(mode);
index 2522e4862d0e152eb25607e3dfa001aa298b9a01..285a59741795a5aa190b0a38c304bca3d1d7f163 100644 (file)
@@ -136,6 +136,31 @@ public: // Called by Core
    */
   void SetPanGesturePredictionAmount( unsigned int amount );
 
+  /**
+   * @brief Sets the upper bound of the prediction amount for clamping
+   *
+   * @param[in] amount The prediction amount in milliseconds
+   */
+  void SetPanGestureMaximumPredictionAmount( unsigned int amount );
+
+  /**
+   * @brief Sets the lower bound of the prediction amount for clamping
+   *
+   * @param[in] amount The prediction amount in milliseconds
+   */
+  void SetPanGestureMinimumPredictionAmount( unsigned int amount );
+
+  /**
+   * @brief Sets the prediction amount to adjust when the pan velocity is changed.
+   * If the pan velocity is accelerating, the prediction amount will be increased
+   * by the specified amount until it reaches the upper bound. If the pan velocity
+   * is decelerating, the prediction amount will be decreased by the specified amount
+   * until it reaches the lower bound.
+   *
+   * @param[in] amount The prediction amount in milliseconds
+   */
+  void SetPanGesturePredictionAmountAdjustment( unsigned int amount );
+
   /**
    * @brief Called to set how pan gestures smooth input
    *
index dd908c71afa31bd59742f33143d6114f28df2d41..441fb7df58735ff22c46e8b7d20cc0d48b15863b 100644 (file)
@@ -331,6 +331,21 @@ void PanGestureProcessor::SetPredictionAmount(unsigned int amount)
   mSceneObject->SetPredictionAmount(amount);
 }
 
+void PanGestureProcessor::SetMaximumPredictionAmount(unsigned int amount)
+{
+  mSceneObject->SetMaximumPredictionAmount(amount);
+}
+
+void PanGestureProcessor::SetMinimumPredictionAmount(unsigned int amount)
+{
+  mSceneObject->SetMinimumPredictionAmount(amount);
+}
+
+void PanGestureProcessor::SetPredictionAmountAdjustment(unsigned int amount)
+{
+  mSceneObject->SetPredictionAmountAdjustment(amount);
+}
+
 void PanGestureProcessor::SetSmoothingMode(int mode)
 {
   if( (mode < 0)
index 9cd2de043755df6264915b748b75ffa10a157dcd..f09bda32d48fddb7dc2b089c83ffa3ab49ee9318 100644 (file)
@@ -129,6 +129,27 @@ public: // To be called by GestureEventProcessor
    */
   void SetPredictionAmount(unsigned int amount);
 
+  /**
+   * @brief Sets the upper bound of the prediction amount for clamping
+   *
+   * @param[in] amount The prediction amount in milliseconds
+   */
+  void SetMaximumPredictionAmount(unsigned int amount);
+
+  /**
+   * @brief Sets the lower bound of the prediction amount for clamping
+   *
+   * @param[in] amount The prediction amount in milliseconds
+   */
+  void SetMinimumPredictionAmount(unsigned int amount);
+
+  /**
+   * @brief Sets the amount of prediction interpolation to adjust when the pan velocity is changed
+   *
+   * @param[in] amount The prediction amount in milliseconds
+   */
+  void SetPredictionAmountAdjustment(unsigned int amount);
+
   /**
    * Called to set the prediction mode for pan gestures
    *
index 4acfedf168026add66e02f407aadd28e15d1baef..02044fd1672ba153d6a65a56c13dc2b048b90d61 100644 (file)
@@ -39,7 +39,7 @@ void PanGestureProfiling::PrintData( const PanPositionContainer& dataContainer,
   const PanPositionContainer::const_iterator endIter = dataContainer.end();
   for ( PanPositionContainer::const_iterator iter = dataContainer.begin(); iter != endIter; ++iter )
   {
-    DALI_LOG_UPDATE_STATUS( "%s, %u, %.2f, %.2f\n", prefix, iter->time, iter->position.x, iter->position.y );
+    DALI_LOG_UPDATE_STATUS( "%s, %u, %.2f, %.2f, displacement: %.2f, %.2f, velocity: %.2f, %.2f, state: %d\n", prefix, iter->time, iter->position.x, iter->position.y, iter->displacement.x, iter->displacement.y, iter->velocity.x, iter->velocity.y, iter->state );
   }
 }
 
index 2ded72a1677a26ff58ea6c6a53d80fcbddbfa95e..0ab89b1bdf012dff2f52f44e798bf529e4ab117e 100644 (file)
@@ -32,13 +32,16 @@ struct PanGestureProfiling
 {
   struct Position
   {
-    Position( unsigned int time, Vector2 position )
-    : time( time ), position( position )
+    Position( unsigned int time, Vector2 position, Vector2 displacement, Vector2 velocity, int state )
+    : time( time ), position( position ), displacement( displacement ), velocity( velocity ), state( state )
     {
     }
 
     unsigned int time;
     Vector2 position;
+    Vector2 displacement;
+    Vector2 velocity;
+    int state;
   };
 
   typedef std::vector< PanGestureProfiling::Position > PanPositionContainer;
index 8a070c6998df4d3dfc913a664e1f2e314aca4c5e..4a47a8c1121d9cc5944fe3735630437cb7c5db24 100644 (file)
@@ -19,6 +19,7 @@
 #include <dali/internal/update/gestures/scene-graph-pan-gesture.h>
 
 // EXTERNAL INCLUDES
+#include <cmath>
 
 // INTERNAL INCLUDES
 #include <dali/internal/update/gestures/pan-gesture-profiling.h>
@@ -34,7 +35,11 @@ namespace SceneGraph
 namespace
 {
 const int MAX_GESTURE_AGE = 50; ///< maximum age of a gesture before disallowing its use in algorithm
-const unsigned int DEFAULT_PREDICTION_INTERPOLATION = 0; ///< how much to interpolate pan position and displacement from last vsync time
+const float ACCELERATION_THRESHOLD = 0.1f; ///< minimum pan velocity change to trigger dynamic change of prediction amount
+const unsigned int DEFAULT_PREDICTION_INTERPOLATION = 0; ///< how much to interpolate pan position and displacement from last vsync time (in milliseconds)
+const unsigned int DEFAULT_MAX_PREDICTION_INTERPOLATION = 32; ///< the upper bound of the range to clamp the prediction interpolation
+const unsigned int DEFAULT_MIN_PREDICTION_INTERPOLATION = 0; ///< the lower bound of the range to clamp the prediction interpolation
+const unsigned int DEFAULT_PREDICTION_INTERPOLATION_ADJUSTMENT = 4; ///< the amount of prediction interpolation to adjust (in milliseconds) each time when pan velocity changes
 const float DEFAULT_SMOOTHING_AMOUNT = 1.0f; ///< how much to interpolate pan position and displacement from last vsync time
 } // unnamed namespace
 
@@ -108,8 +113,8 @@ void PanGesture::PredictiveAlgorithm1(int eventsThisFrame, PanInfo& gestureOut,
   float previousAccel = 0.0f;
   unsigned int lastTime(0);
 
-  unsigned int interpolationTime = lastVSyncTime + mPredictionAmount;
-  if( interpolationTime > gestureOut.time ) // Guard against the rare case when gestureOut.time > (lastVSyncTime + mPredictionAmount)
+  unsigned int interpolationTime = lastVSyncTime + mCurrentPredictionAmount;
+  if( interpolationTime > gestureOut.time ) // Guard against the rare case when gestureOut.time > (lastVSyncTime + mCurrentPredictionAmount)
   {
     interpolationTime -= gestureOut.time;
   }
@@ -237,6 +242,8 @@ bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int next
   bool justFinished ( false );
   bool eventFound( false );
 
+  float acceleration = 0.0f;
+
   // Not going through array from the beginning, using it as a circular buffer and only using unread
   // values.
   int eventsThisFrame = 0;
@@ -245,6 +252,7 @@ bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int next
   mLastEventGesture = mEventGesture;
   mLastGesture = mLatestGesture;
   // add new gestures and work out one full gesture for the frame
+  unsigned int previousReadPosition = 0;
   while(mReadPosition != mWritePosition)
   {
     // Copy the gesture first
@@ -252,12 +260,18 @@ bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int next
 
     if( mProfiling )
     {
-      mProfiling->mRawData.push_back( PanGestureProfiling::Position( currentGesture.time, currentGesture.screen.position ) );
+      mProfiling->mRawData.push_back( PanGestureProfiling::Position( currentGesture.time, currentGesture.screen.position, currentGesture.screen.displacement, currentGesture.screen.velocity, currentGesture.state ) );
     }
     mEventGesture.local.position = currentGesture.local.position;
     mEventGesture.local.velocity = currentGesture.local.velocity;
     mEventGesture.screen.position = currentGesture.screen.position;
     mEventGesture.screen.velocity = currentGesture.screen.velocity;
+
+    if(eventsThisFrame > 0)
+    {
+      acceleration = currentGesture.screen.velocity.Length() - mGestures[previousReadPosition].screen.velocity.Length();
+    }
+
     if( !eventFound )
     {
       mEventGesture.local.displacement = currentGesture.local.displacement;
@@ -282,6 +296,7 @@ bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int next
     justFinished |= (currentGesture.state == Gesture::Finished || currentGesture.state == Gesture::Cancelled);
 
     // Update our read position.
+    previousReadPosition = mReadPosition;
     ++eventsThisFrame;
     ++mReadPosition;
     mReadPosition %= PAN_GESTURE_HISTORY;
@@ -296,7 +311,7 @@ bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int next
   {
     if( mProfiling )
     {
-      mProfiling->mLatestData.push_back( PanGestureProfiling::Position( lastVSyncTime, mEventGesture.screen.position ) );
+      mProfiling->mLatestData.push_back( PanGestureProfiling::Position( lastVSyncTime, mEventGesture.screen.position, mEventGesture.screen.displacement, mEventGesture.screen.velocity, mEventGesture.state ) );
     }
 
     switch( mPredictionMode )
@@ -313,8 +328,81 @@ bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int next
       }
       case PREDICTION_1:
       {
-        // make latest gesture equal to current gesture before interpolation
+        // Dynamically change the prediction amount according to the pan velocity acceleration.
+        if(!justStarted)
+        {
+          if(eventsThisFrame <= 1)
+          {
+            acceleration = mEventGesture.screen.velocity.Length() - mLastEventGesture.screen.velocity.Length();
+          }
+
+          // Ignore tiny velocity fluctuation to avoid unnecessary prediction amount change
+          if(fabsf(acceleration) > ACCELERATION_THRESHOLD)
+          {
+            mCurrentPredictionAmount += mPredictionAmountAdjustment * (acceleration > Math::MACHINE_EPSILON_0 ? 1.0f : -1.0f);
+            if(mCurrentPredictionAmount > mMaxPredictionAmount + mPredictionAmountAdjustment) // Guard against unsigned int overflow
+            {
+              mCurrentPredictionAmount = 0;
+            }
+          }
+        }
+        else
+        {
+          mCurrentPredictionAmount = mPredictionAmount; // Reset the prediction amount for each new gesture
+        }
+
+        mCurrentPredictionAmount = std::max(mMinPredictionAmount, std::min(mCurrentPredictionAmount, mMaxPredictionAmount));
+
+        // Calculate the delta of positions before the prediction
+        Vector2 deltaPosition = mLatestGesture.screen.position - mLastEventGesture.screen.position;
+
+        // Make latest gesture equal to current gesture before interpolation
         PredictiveAlgorithm1(eventsThisFrame, mLatestGesture, mPanHistory, lastVSyncTime, nextVSyncTime);
+
+        // Calculate the delta of positions after the prediction.
+        Vector2 deltaPredictedPosition = mLatestGesture.screen.position - mLastGesture.screen.position;
+
+        // If the change in the prediction has a different sign than the change in the actual position,
+        // there is overshot (i.e. the current prediction is too large). Return the previous prediction
+        // to give the user's finger a chance to catch up with where we have panned to.
+        bool overshotXAxis = false;
+        bool overshotYAxis = false;
+        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 ) )
+        {
+          overshotXAxis = true;
+          mLatestGesture.screen.position.x = mLastGesture.screen.position.x;
+        }
+
+        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 ) )
+        {
+          overshotYAxis = true;
+          mLatestGesture.screen.position.y = mLastGesture.screen.position.y;
+        }
+
+        // If there is overshot in one axis, reduce the possible overshot in the other axis,
+        // and reduce the prediction amount so that it doesn't overshoot as easily next time.
+        if(overshotXAxis || overshotYAxis)
+        {
+          mCurrentPredictionAmount -= mPredictionAmountAdjustment;
+          if(mCurrentPredictionAmount > mMaxPredictionAmount + mPredictionAmountAdjustment) // Guard against unsigned int overflow
+          {
+            mCurrentPredictionAmount = 0;
+          }
+          mCurrentPredictionAmount = std::max(mMinPredictionAmount, std::min(mCurrentPredictionAmount, mMaxPredictionAmount));
+
+          if(overshotXAxis && !overshotYAxis)
+          {
+            mLatestGesture.screen.position.y = (mLastGesture.screen.position.y + mLatestGesture.screen.position.y) * 0.5f;
+          }
+
+          if(overshotYAxis && !overshotXAxis)
+          {
+            mLatestGesture.screen.position.x = (mLastGesture.screen.position.x + mLatestGesture.screen.position.x) * 0.5f;
+          }
+        }
+
         updateProperties = true;
         break;
       }
@@ -349,7 +437,7 @@ bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int next
 
     if( mProfiling )
     {
-      mProfiling->mAveragedData.push_back( PanGestureProfiling::Position( mLatestGesture.time, mLatestGesture.screen.position ) );
+      mProfiling->mAveragedData.push_back( PanGestureProfiling::Position( mLatestGesture.time, mLatestGesture.screen.position, mLatestGesture.screen.displacement, mLatestGesture.screen.velocity, mLatestGesture.state ) );
     }
   }
 
@@ -409,6 +497,21 @@ void PanGesture::SetPredictionAmount(unsigned int amount)
   mPredictionAmount = amount;
 }
 
+void PanGesture::SetMaximumPredictionAmount(unsigned int amount)
+{
+  mMaxPredictionAmount = amount;
+}
+
+void PanGesture::SetMinimumPredictionAmount(unsigned int amount)
+{
+  mMinPredictionAmount = amount;
+}
+
+void PanGesture::SetPredictionAmountAdjustment(unsigned int amount)
+{
+  mPredictionAmountAdjustment = amount;
+}
+
 void PanGesture::SetSmoothingMode(SmoothingMode mode)
 {
   mSmoothingMode = mode;
@@ -443,6 +546,10 @@ PanGesture::PanGesture()
   mInGesture( false ),
   mPredictionMode(DEFAULT_PREDICTION_MODE),
   mPredictionAmount(DEFAULT_PREDICTION_INTERPOLATION),
+  mCurrentPredictionAmount(DEFAULT_PREDICTION_INTERPOLATION),
+  mMaxPredictionAmount(DEFAULT_MAX_PREDICTION_INTERPOLATION),
+  mMinPredictionAmount(DEFAULT_MIN_PREDICTION_INTERPOLATION),
+  mPredictionAmountAdjustment(DEFAULT_PREDICTION_INTERPOLATION_ADJUSTMENT),
   mSmoothingMode(DEFAULT_SMOOTHING_MODE),
   mSmoothingAmount(DEFAULT_SMOOTHING_AMOUNT),
   mProfiling( NULL )
index 99d86882fab54f314e6b611628faacac00cde390..e696c76b5ac636d69d51220cc7486a098931a87a 100644 (file)
@@ -287,6 +287,27 @@ public:
    */
   void SetPredictionAmount(unsigned int amount);
 
+  /**
+   * @brief Sets the upper bound of the prediction amount for clamping
+   *
+   * @param[in] amount The prediction amount in milliseconds
+   */
+  void SetMaximumPredictionAmount(unsigned int amount);
+
+  /**
+   * @brief Sets the lower bound of the prediction amount for clamping
+   *
+   * @param[in] amount The prediction amount in milliseconds
+   */
+  void SetMinimumPredictionAmount(unsigned int amount);
+
+  /**
+   * @brief Sets the amount of prediction interpolation to adjust when the pan velocity is changed
+   *
+   * @param[in] amount The prediction amount in milliseconds
+   */
+  void SetPredictionAmountAdjustment(unsigned int amount);
+
   /**
    * @brief Sets the prediction mode of the pan gesture
    *
@@ -347,6 +368,10 @@ private:
 
   PredictionMode mPredictionMode;  ///< The pan gesture prediction mode
   unsigned int mPredictionAmount;  ///< how far into future to predict in milliseconds
+  unsigned int mCurrentPredictionAmount;  ///< the current prediction amount used by the prediction algorithm
+  unsigned int mMaxPredictionAmount;  ///< the maximum prediction amount used by the prediction algorithm
+  unsigned int mMinPredictionAmount;  ///< the minimum prediction amount used by the prediction algorithm
+  unsigned int mPredictionAmountAdjustment;  ///< the prediction amount to adjust in milliseconds when pan velocity changes
   SmoothingMode mSmoothingMode;    ///< The pan gesture prediction mode
   float         mSmoothingAmount;  ///< How much smoothing to apply [0.0f,1.0f]
   PanGestureProfiling* mProfiling; ///< NULL unless pan-gesture profiling information is required.