From ac5806397905dcb1b7c4c456a3f10bbe7d934a61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B0=B8=E7=95=85?= Date: Fri, 26 Jan 2024 09:46:56 +0000 Subject: [PATCH] fixed 936a244 from https://gitee.com/benb365/ace_ace_engine/pulls/26495 When encounting extrem point using 2nd order least square algorithm, using 1st order algorithm instead. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 刘永畅 Change-Id: I956941efde7d54fe7f8888be847a9f35d81dea81 --- frameworks/core/gestures/velocity_tracker.cpp | 133 ++++++++++++------ frameworks/core/gestures/velocity_tracker.h | 7 +- 2 files changed, 96 insertions(+), 44 deletions(-) diff --git a/frameworks/core/gestures/velocity_tracker.cpp b/frameworks/core/gestures/velocity_tracker.cpp index 98f889cc4a2..aeab6349c99 100644 --- a/frameworks/core/gestures/velocity_tracker.cpp +++ b/frameworks/core/gestures/velocity_tracker.cpp @@ -15,9 +15,96 @@ #include "core/gestures/velocity_tracker.h" -#include +#include +#include namespace OHOS::Ace { +namespace { +void CheckExtremePoint(const LeastSquareImpl& axis, double extremX, uint32_t valSize) +{ + const auto& x = axis.GetXVals(); + const auto& y = axis.GetYVals(); + auto count = axis.GetTrackNum(); + + // filter quiver + if (LessNotEqual(std::fabs(y[count - 1] - y[count - 2]), 100)) { // 2: const, 100: quiver threshold + return; + } + // check if extrem point exists between axis's points. + if (GreatNotEqual(extremX, x[x.size() - valSize]) && LessNotEqual(extremX, x.back())) { + LOGI("Extrem point %{public}f exists between tracker points.", extremX); + } + // dump points + int32_t i = static_cast(x.size() - 1); + for (int32_t cnt = VelocityTracker::POINT_NUMBER; i >= 0 && cnt > 0; --cnt) { + --i; + LOGI("Last tracker points[%{public}d] x=%{public}f y=%{public}f", cnt, x[i], y[i]); + } + +} + +// true for increasing, false for decreasing, nullopt for nonmonotonic +std::optional GetMononicity(const std::vector& vals, uint32_t valSize) +{ + std::optional compareResult; + for (uint32_t i = vals.size() - valSize + 1; i < vals.size(); ++i) { + double delta = vals[i] - vals[i - 1]; + if (NearZero(delta)) { + continue; + } + bool isIncreasing = Positive(delta); + if (compareResult.value_or(isIncreasing) != isIncreasing) { + return std::nullopt; + } + compareResult = isIncreasing; + } + return compareResult; +} + +inline double GetLinearSlope(const LeastSquareImpl& axis) +{ + const auto& x = axis.GetXVals(); + const auto& y = axis.GetYVals(); + auto count = axis.GetTrackNum(); + return (y[count - 1] - y[count - 2]) / (x[count - 1] - x[count - 2]); // 2: const +} + +void CorrectMonotonicAxisVelocity(const LeastSquareImpl& axis, double& v, double extremX) +{ + const auto& yVals = axis.GetYVals(); + uint32_t valSize = std::min(static_cast(yVals.size()), VelocityTracker::POINT_NUMBER); + auto mononicity = GetMononicity(yVals, valSize); + if (!mononicity.has_value()) { + return; + } + + // velocity is still, no need to do correction + if (mononicity.value() ? GreatOrEqual(v, 0) : LessOrEqual(v, 0)) { + return; + } + + // Do correction + v = GetLinearSlope(axis); + CheckExtremePoint(axis, extremX, valSize); +} + +double UpdateAxisVelocity(LeastSquareImpl& axis) +{ + std::vector param(VelocityTracker::LEAST_SQUARE_PARAM_NUM, 0); + auto x = axis.GetXVals().back(); + // curve is param[0] * x^2 + param[1] * x + param[2] + // the velocity is 2 * param[0] * x + param[1]; + double velocity = 0.0; + if (axis.GetLeastSquareParams(param)) { + velocity = 2 * param[0] * x + param[1]; // 2: const of formula + double extremX = -0.5 * param[1] / param[0]; // 0.5: const of formula + CorrectMonotonicAxisVelocity(axis, velocity, extremX); + } else { // Use linear velocity instead + velocity = GetLinearSlope(axis); + } + return velocity; +} +} // namespace void VelocityTracker::UpdateTouchPoint(const TouchEvent& event, bool end) { @@ -76,50 +163,12 @@ void VelocityTracker::UpdateVelocity() if (isVelocityDone_) { return; } - if (xAxis_.GetXVals().empty() || yAxis_.GetXVals().empty()) { + if (xAxis_.GetTrackNum() < 2) { // Velocity is calculated from at least 2 points. return; } - // the least square method three params curve is 0 * x^3 + a2 * x^2 + a1 * x + a0 - // the velocity is 2 * a2 * x + a1; - static const int32_t linearParam = 2; - std::vector xAxis { 3, 0 }; - auto xValue = xAxis_.GetXVals().back(); - double xVelocity = 0.0; - if (xAxis_.GetLeastSquareParams(xAxis)) { - xVelocity = linearParam * xAxis[0] * xValue + xAxis[1]; - } - std::vector yAxis { 3, 0 }; - auto yValue = yAxis_.GetXVals().back(); - double yVelocity = 0.0; - if (yAxis_.GetLeastSquareParams(yAxis)) { - yVelocity = linearParam * yAxis[0] * yValue + yAxis[1]; - } - if (currentTrackPoint_.type == TouchType::UP) { - static const int32_t minSize = 2; - if (yAxis_.GetYVals().size() >= minSize) { - auto yAxisDelta = yAxis_.GetYVals()[yAxis_.GetYVals().size() - 1] - - yAxis_.GetYVals()[yAxis_.GetYVals().size() - 2]; - if (yAxisDelta > 0 && yVelocity < 0) { - yVelocity = 0; - } else if (yAxisDelta < 0 && yVelocity > 0) { - yVelocity = 0; - } else if (yAxisDelta == 0) { - yVelocity = 0; - } - } - if (xAxis_.GetYVals().size() >= minSize) { - auto xAxisDelta = xAxis_.GetYVals()[xAxis_.GetYVals().size() - 1] - - xAxis_.GetYVals()[xAxis_.GetYVals().size() - 2]; - if (xAxisDelta > 0 && xVelocity < 0) { - xVelocity = 0; - } else if (xAxisDelta < 0 && xVelocity > 0) { - xVelocity = 0; - } else if (xAxisDelta == 0) { - xVelocity = 0; - } - } - } + double xVelocity = UpdateAxisVelocity(xAxis_); + double yVelocity = UpdateAxisVelocity(yAxis_); velocity_.SetOffsetPerSecond({ xVelocity, yVelocity }); isVelocityDone_ = true; } diff --git a/frameworks/core/gestures/velocity_tracker.h b/frameworks/core/gestures/velocity_tracker.h index 7b74b161977..2dd9abd4d68 100644 --- a/frameworks/core/gestures/velocity_tracker.h +++ b/frameworks/core/gestures/velocity_tracker.h @@ -30,6 +30,9 @@ public: explicit VelocityTracker(Axis mainAxis) : mainAxis_(mainAxis) {} ~VelocityTracker() = default; + static constexpr int32_t LEAST_SQUARE_PARAM_NUM = 3; + static constexpr int32_t POINT_NUMBER = 5; + void Reset() { lastPosition_.Reset(); @@ -131,8 +134,8 @@ private: bool isFirstPoint_ = true; TimeStamp lastTimePoint_; TimeStamp firstPointTime_; - LeastSquareImpl xAxis_ { 3, 5 }; - LeastSquareImpl yAxis_ { 3, 5 }; + LeastSquareImpl xAxis_ { LEAST_SQUARE_PARAM_NUM, POINT_NUMBER }; + LeastSquareImpl yAxis_ { LEAST_SQUARE_PARAM_NUM, POINT_NUMBER }; bool isVelocityDone_ = false; }; -- Gitee