• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/gestures/velocity_tracker.h"
17 
18 namespace OHOS::Ace {
19 namespace {
20 static constexpr int32_t MAX_INDEX = 4;
21 
CheckExtremePoint(const LeastSquareImpl & axis,double extremX,uint32_t valSize)22 void CheckExtremePoint(const LeastSquareImpl& axis, double extremX, uint32_t valSize)
23 {
24     const auto& x = axis.GetXVals();
25     const auto& y = axis.GetYVals();
26     auto count = axis.GetTrackNum();
27 
28     // filter quiver
29     if (LessNotEqual(std::fabs(y[count - 1] - y[count - 2]), 100)) { // 2: const, 100: quiver threshold
30         return;
31     }
32     // check if extrem point exists between axis's points.
33     if (GreatNotEqual(extremX, x[x.size() - valSize]) && LessNotEqual(extremX, x.back())) {
34         LOGI("Extrem point %{public}f exists between tracker points.", extremX);
35     }
36     // dump points
37     int32_t i = static_cast<int32_t>(x.size());
38     for (int32_t cnt = VelocityTracker::POINT_NUMBER; i > 0 && cnt > 0; --cnt) {
39         --i;
40         LOGI("Last tracker points[%{public}d] x=%{public}f y=%{public}f", cnt, x[i], y[i]);
41     }
42 }
43 
44 // true for increasing, false for decreasing, nullopt for nonmonotonic
GetMononicity(const std::vector<double> & vals,uint32_t valSize)45 std::optional<bool> GetMononicity(const std::vector<double>& vals, uint32_t valSize)
46 {
47     std::optional<bool> compareResult;
48     for (uint32_t i = vals.size() - valSize + 1; i < vals.size(); ++i) {
49         double delta = vals[i] - vals[i - 1];
50         if (NearZero(delta)) {
51             continue;
52         }
53         bool isIncreasing = Positive(delta);
54         if (compareResult.value_or(isIncreasing) != isIncreasing) {
55             return std::nullopt;
56         }
57         compareResult = isIncreasing;
58     }
59     return compareResult;
60 }
61 
GetLinearSlope(const LeastSquareImpl & axis)62 double GetLinearSlope(const LeastSquareImpl& axis)
63 {
64     const auto& x = axis.GetXVals();
65     const auto& y = axis.GetYVals();
66     auto count = axis.GetTrackNum();
67     int32_t index = 2;
68     while (index <= MAX_INDEX && count >= index) {
69         if (!NearEqual(x[count - 1], x[count - index])) {
70             break;
71         }
72         auto previousIndex = count - index;
73         auto lastIndex = count - 1;
74         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW,
75             "GetLinearSlope points time is same y[%{public}d]: %{public}f y[%{public}d]: %{public}f x[%{public}d]: "
76             "%{public}f x[%{public}d]: "
77             "%{public}f",
78             previousIndex, y[previousIndex], lastIndex, y[lastIndex], previousIndex, x[previousIndex], lastIndex,
79             x[lastIndex]);
80         index++;
81     }
82     if (index > MAX_INDEX || index > count) {
83         return 0.0;
84     }
85     return (y[count - 1] - y[count - index]) / (x[count - 1] - x[count - index]); // 2: const
86 }
87 
CorrectMonotonicAxisVelocity(const LeastSquareImpl & axis,double & v,double extremX)88 void CorrectMonotonicAxisVelocity(const LeastSquareImpl& axis, double& v, double extremX)
89 {
90     const auto& yVals = axis.GetYVals();
91     uint32_t valSize = std::min(static_cast<int32_t>(yVals.size()), VelocityTracker::POINT_NUMBER);
92     auto mononicity = GetMononicity(yVals, valSize);
93     if (!mononicity.has_value()) {
94         return;
95     }
96 
97     // velocity is still, no need to do correction
98     if (mononicity.value() ? GreatOrEqual(v, 0) : LessOrEqual(v, 0)) {
99         return;
100     }
101 
102     // Do correction
103     v = GetLinearSlope(axis);
104     CheckExtremePoint(axis, extremX, valSize);
105 }
106 
UpdateAxisVelocity(LeastSquareImpl & axis)107 double UpdateAxisVelocity(LeastSquareImpl& axis)
108 {
109     std::vector<double> param(VelocityTracker::LEAST_SQUARE_PARAM_NUM, 0);
110     auto x = axis.GetXVals().back();
111     // curve is param[0] * x^2 + param[1] * x + param[2]
112     // the velocity is 2 * param[0] * x + param[1];
113     double velocity = 0.0;
114     if (axis.GetLeastSquareParams(param)) {
115         velocity = 2 * param[0] * x + param[1];      // 2: const of formula
116         double extremX = -0.5 * param[1] / param[0]; // 0.5: const of formula
117         CorrectMonotonicAxisVelocity(axis, velocity, extremX);
118     } else { // Use linear velocity instead
119         velocity = GetLinearSlope(axis);
120     }
121     return velocity;
122 }
123 } // namespace
124 
UpdateTouchPoint(const TouchEvent & event,bool end)125 void VelocityTracker::UpdateTouchPoint(const TouchEvent& event, bool end)
126 {
127     if (isFirstPoint_) {
128         firstTrackPoint_ = event;
129         isFirstPoint_ = false;
130     } else {
131         delta_ = event.GetOffset() - lastPosition_;
132         lastPosition_ = event.GetOffset();
133     }
134     TouchEvent lastTrackPoint(currentTrackPoint_);
135     currentTrackPoint_ = event;
136     isVelocityDone_ = false;
137     std::chrono::duration<double> diffTime = event.time - lastTimePoint_;
138     lastTimePoint_ = event.time;
139     lastPosition_ = event.GetOffset();
140     // judge duration is 500ms.
141     static const double range = 0.5;
142     if (end) {
143         Offset oriDelta;
144         if (isFirstPoint_) {
145             oriDelta = delta_;
146         } else {
147             Offset lastMoveEvent = lastTrackPoint.GetOffset();
148             Offset upEvent = event.GetOffset();
149             oriDelta = upEvent - lastMoveEvent;
150         }
151         if (oriDelta.IsZero() && (diffTime.count() < range)) {
152             return;
153         }
154     }
155     // nanoseconds duration to seconds.
156     std::chrono::duration<double> duration = event.time - firstTrackPoint_.time;
157     auto seconds = duration.count();
158     xAxis_.UpdatePoint(seconds, event.x);
159     yAxis_.UpdatePoint(seconds, event.y);
160 }
161 
UpdateTrackerPoint(double x,double y,const TimeStamp & time,bool end)162 void VelocityTracker::UpdateTrackerPoint(double x, double y, const TimeStamp& time, bool end)
163 {
164     Offset trackerPoint(x, y);
165     isVelocityDone_ = false;
166     if (isFirstPoint_) {
167         firstPointTime_ = time;
168         isFirstPoint_ = false;
169     } else {
170         delta_ = trackerPoint - lastPosition_;
171         lastPosition_ = trackerPoint;
172     }
173     std::chrono::duration<double> diffTime = time - lastTimePoint_;
174     lastTimePoint_ = time;
175     lastPosition_ = trackerPoint;
176     // judge duration is 500ms.
177     static const double range = 0.5;
178     if (delta_.IsZero() && end && (diffTime.count() < range)) {
179         return;
180     }
181     // nanoseconds duration to seconds.
182     std::chrono::duration<double> duration = time - firstPointTime_;
183     auto seconds = duration.count();
184     xAxis_.UpdatePoint(seconds, x);
185     yAxis_.UpdatePoint(seconds, y);
186 }
187 
UpdateVelocity()188 void VelocityTracker::UpdateVelocity()
189 {
190     if (isVelocityDone_) {
191         return;
192     }
193     if (xAxis_.GetTrackNum() < 2) { // Velocity is calculated from at least 2 points.
194         return;
195     }
196 
197     double xVelocity = UpdateAxisVelocity(xAxis_);
198     double yVelocity = UpdateAxisVelocity(yAxis_);
199     velocity_.SetOffsetPerSecond({ xVelocity, yVelocity });
200     isVelocityDone_ = true;
201 }
202 
DumpVelocityPoints() const203 void VelocityTracker::DumpVelocityPoints() const
204 {
205     auto func = [](const LeastSquareImpl &axis, const char* str) {
206         const auto& xVal = axis.GetXVals();
207         const auto& yVal = axis.GetYVals();
208         int32_t i = static_cast<int32_t>(xVal.size());
209         for (int32_t cnt = VelocityTracker::POINT_NUMBER; i > 0 && cnt > 0; --cnt) {
210             --i;
211             LOGI("%{public}s last tracker points[%{public}d] x=%{public}f y=%{public}f", str, cnt, xVal[i], yVal[i]);
212         }
213     };
214     func(xAxis_, "xAxis");
215     func(yAxis_, "yAxis");
216 }
217 } // namespace OHOS::Ace
218