diff options
author | 2023-03-02 21:08:14 -0800 | |
---|---|---|
committer | 2023-03-06 22:13:06 +0000 | |
commit | a0e573c3ad544689381a4e555c02515a45d86a57 (patch) | |
tree | 0389462867492a28b41d6459f0dbb2d1adfac30a | |
parent | 274435cf3840f2a1a7c2e5a1789ddfcbd6395800 (diff) |
Create AccumulatingVelocityTrackerStrategy
This is a partial implementation of VelocityTrackerStrategy, that stores
data points during "add" operations. Extracting this logic into a common
class helps avoid duplicated logic across several strategies that do the
exact same thing when adding new movements. It also helps ease future
updates/optimizations.
Bug: 267211645
Test: atest libinput_tests
Change-Id: I116e978b070aa451813fefa384ccc65e10ea45a0
-rw-r--r-- | include/input/VelocityTracker.h | 68 | ||||
-rw-r--r-- | libs/input/VelocityTracker.cpp | 87 |
2 files changed, 36 insertions, 119 deletions
diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h index 5a23e8dca5..6d51515cb3 100644 --- a/include/input/VelocityTracker.h +++ b/include/input/VelocityTracker.h @@ -152,11 +152,34 @@ public: virtual std::optional<float> getVelocity(int32_t pointerId) const = 0; }; +/** + * A `VelocityTrackerStrategy` that accumulates added data points and processes the accumulated data + * points when getting velocity. + */ +class AccumulatingVelocityTrackerStrategy : public VelocityTrackerStrategy { +public: + void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override; + void clearPointer(int32_t pointerId) override; + +protected: + struct Movement { + nsecs_t eventTime; + float position; + }; + + // Number of samples to keep. + // If different strategies would like to maintain different history size, we can make this a + // protected const field. + static constexpr uint32_t HISTORY_SIZE = 20; + + std::map<int32_t /*pointerId*/, size_t /*positionInArray*/> mIndex; + std::map<int32_t /*pointerId*/, std::array<Movement, HISTORY_SIZE>> mMovements; +}; /* * Velocity tracker algorithm based on least-squares linear regression. */ -class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy { +class LeastSquaresVelocityTrackerStrategy : public AccumulatingVelocityTrackerStrategy { public: enum class Weighting { // No weights applied. All data points are equally reliable. @@ -177,8 +200,6 @@ public: LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting = Weighting::NONE); ~LeastSquaresVelocityTrackerStrategy() override; - void clearPointer(int32_t pointerId) override; - void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override; std::optional<float> getVelocity(int32_t pointerId) const override; private: @@ -187,23 +208,12 @@ private: // changes in direction. static const nsecs_t HORIZON = 100 * 1000000; // 100 ms - // Number of samples to keep. - static const uint32_t HISTORY_SIZE = 20; - - struct Movement { - nsecs_t eventTime; - float position; - }; - float chooseWeight(int32_t pointerId, uint32_t index) const; const uint32_t mDegree; const Weighting mWeighting; - std::map<int32_t /*pointerId*/, size_t /*positionInArray*/> mIndex; - std::map<int32_t /*pointerId*/, std::array<Movement, HISTORY_SIZE>> mMovements; }; - /* * Velocity tracker algorithm that uses an IIR filter. */ @@ -238,41 +248,26 @@ private: /* * Velocity tracker strategy used prior to ICS. */ -class LegacyVelocityTrackerStrategy : public VelocityTrackerStrategy { +class LegacyVelocityTrackerStrategy : public AccumulatingVelocityTrackerStrategy { public: LegacyVelocityTrackerStrategy(); ~LegacyVelocityTrackerStrategy() override; - void clearPointer(int32_t pointerId) override; - void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override; std::optional<float> getVelocity(int32_t pointerId) const override; private: // Oldest sample to consider when calculating the velocity. static const nsecs_t HORIZON = 200 * 1000000; // 100 ms - // Number of samples to keep. - static const uint32_t HISTORY_SIZE = 20; - // The minimum duration between samples when estimating velocity. static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms - - struct Movement { - nsecs_t eventTime; - float position; - }; - - std::map<int32_t /*pointerId*/, size_t /*positionInArray*/> mIndex; - std::map<int32_t /*pointerId*/, std::array<Movement, HISTORY_SIZE>> mMovements; }; -class ImpulseVelocityTrackerStrategy : public VelocityTrackerStrategy { +class ImpulseVelocityTrackerStrategy : public AccumulatingVelocityTrackerStrategy { public: ImpulseVelocityTrackerStrategy(bool deltaValues); ~ImpulseVelocityTrackerStrategy() override; - void clearPointer(int32_t pointerId) override; - void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override; std::optional<float> getVelocity(int32_t pointerId) const override; private: @@ -281,21 +276,10 @@ private: // changes in direction. static constexpr nsecs_t HORIZON = 100 * 1000000; // 100 ms - // Number of samples to keep. - static constexpr size_t HISTORY_SIZE = 20; - - struct Movement { - nsecs_t eventTime; - float position; - }; - // Whether or not the input movement values for the strategy come in the form of delta values. // If the input values are not deltas, the strategy needs to calculate deltas as part of its // velocity calculation. const bool mDeltaValues; - - std::map<int32_t /*pointerId*/, size_t /*positionInArray*/> mIndex; - std::map<int32_t /*pointerId*/, std::array<Movement, HISTORY_SIZE>> mMovements; }; } // namespace android diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp index a88aa485fc..ac042c5790 100644 --- a/libs/input/VelocityTracker.cpp +++ b/libs/input/VelocityTracker.cpp @@ -370,21 +370,12 @@ VelocityTracker::ComputedVelocity VelocityTracker::getComputedVelocity(int32_t u return computedVelocity; } -// --- LeastSquaresVelocityTrackerStrategy --- - -LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(uint32_t degree, - Weighting weighting) - : mDegree(degree), mWeighting(weighting) {} - -LeastSquaresVelocityTrackerStrategy::~LeastSquaresVelocityTrackerStrategy() { -} - -void LeastSquaresVelocityTrackerStrategy::clearPointer(int32_t pointerId) { +void AccumulatingVelocityTrackerStrategy::clearPointer(int32_t pointerId) { mIndex.erase(pointerId); mMovements.erase(pointerId); } -void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t pointerId, +void AccumulatingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t pointerId, float position) { // If data for this pointer already exists, we have a valid entry at the position of // mIndex[pointerId] and mMovements[pointerId]. In that case, we need to advance the index @@ -412,6 +403,14 @@ void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t movement.position = position; } +// --- LeastSquaresVelocityTrackerStrategy --- + +LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(uint32_t degree, + Weighting weighting) + : mDegree(degree), mWeighting(weighting) {} + +LeastSquaresVelocityTrackerStrategy::~LeastSquaresVelocityTrackerStrategy() {} + /** * Solves a linear least squares problem to obtain a N degree polynomial that fits * the specified input data as nearly as possible. @@ -834,39 +833,6 @@ LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() {} LegacyVelocityTrackerStrategy::~LegacyVelocityTrackerStrategy() { } -void LegacyVelocityTrackerStrategy::clearPointer(int32_t pointerId) { - mIndex.erase(pointerId); - mMovements.erase(pointerId); -} - -void LegacyVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t pointerId, - float position) { - // If data for this pointer already exists, we have a valid entry at the position of - // mIndex[pointerId] and mMovements[pointerId]. In that case, we need to advance the index - // to the next position in the circular buffer and write the new Movement there. Otherwise, - // if this is a first movement for this pointer, we initialize the maps mIndex and mMovements - // for this pointer and write to the first position. - auto [movementIt, inserted] = mMovements.insert({pointerId, {}}); - auto [indexIt, _] = mIndex.insert({pointerId, 0}); - size_t& index = indexIt->second; - if (!inserted && movementIt->second[index].eventTime != eventTime) { - // When ACTION_POINTER_DOWN happens, we will first receive ACTION_MOVE with the coordinates - // of the existing pointers, and then ACTION_POINTER_DOWN with the coordinates that include - // the new pointer. If the eventtimes for both events are identical, just update the data - // for this time. - // We only compare against the last value, as it is likely that addMovement is called - // in chronological order as events occur. - index++; - } - if (index == HISTORY_SIZE) { - index = 0; - } - - Movement& movement = movementIt->second[index]; - movement.eventTime = eventTime; - movement.position = position; -} - std::optional<float> LegacyVelocityTrackerStrategy::getVelocity(int32_t pointerId) const { const auto movementIt = mMovements.find(pointerId); if (movementIt == mMovements.end()) { @@ -939,39 +905,6 @@ ImpulseVelocityTrackerStrategy::ImpulseVelocityTrackerStrategy(bool deltaValues) ImpulseVelocityTrackerStrategy::~ImpulseVelocityTrackerStrategy() { } -void ImpulseVelocityTrackerStrategy::clearPointer(int32_t pointerId) { - mIndex.erase(pointerId); - mMovements.erase(pointerId); -} - -void ImpulseVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t pointerId, - float position) { - // If data for this pointer already exists, we have a valid entry at the position of - // mIndex[pointerId] and mMovements[pointerId]. In that case, we need to advance the index - // to the next position in the circular buffer and write the new Movement there. Otherwise, - // if this is a first movement for this pointer, we initialize the maps mIndex and mMovements - // for this pointer and write to the first position. - auto [movementIt, inserted] = mMovements.insert({pointerId, {}}); - auto [indexIt, _] = mIndex.insert({pointerId, 0}); - size_t& index = indexIt->second; - if (!inserted && movementIt->second[index].eventTime != eventTime) { - // When ACTION_POINTER_DOWN happens, we will first receive ACTION_MOVE with the coordinates - // of the existing pointers, and then ACTION_POINTER_DOWN with the coordinates that include - // the new pointer. If the eventtimes for both events are identical, just update the data - // for this time. - // We only compare against the last value, as it is likely that addMovement is called - // in chronological order as events occur. - index++; - } - if (index == HISTORY_SIZE) { - index = 0; - } - - Movement& movement = movementIt->second[index]; - movement.eventTime = eventTime; - movement.position = position; -} - /** * Calculate the total impulse provided to the screen and the resulting velocity. * |