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 a850887..a902e9f 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 2efe516..41e3ab0 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 9b8458e..3c630a4 100644 (file)
@@ -39,13 +39,41 @@ 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
  *
  * @param[in] mode The smoothing mode to use
@@ -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 4a13feb..0482b19 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 2522e48..285a597 100644 (file)
@@ -137,6 +137,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
    *
    * @param[in] mode The smoothing mode to use
index dd908c7..441fb7d 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 9cd2de0..f09bda3 100644 (file)
@@ -130,6 +130,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
    *
    * @param[in] mode The prediction mode
index 4acfedf..02044fd 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 2ded72a..0ab89b1 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 8a070c6..4a47a8c 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 99d8688..e696c76 100644 (file)
@@ -288,6 +288,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
    *
    * @param[in] mode The prediction mode
@@ -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.