1 /*
2 * Copyright (c) 2021 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/animation/friction_motion.h"
17
18 #include "base/log/log.h"
19 #include "base/utils/utils.h"
20
21 namespace OHOS::Ace {
22 namespace {
23
24 constexpr float UNIT_CONVERT = 1000.0f;
25 constexpr float FRICTION_SCALE = -4.2f;
26 constexpr float DEFAULT_THRESHOLD = 0.75f;
27
28 } // namespace
29
FrictionMotion(double friction,double initPosition,double initVelocity)30 FrictionMotion::FrictionMotion(double friction, double initPosition, double initVelocity)
31 {
32 Reset(friction, initPosition, initVelocity);
33 }
34
Reset(double friction,double initPosition,double initVelocity,double threshold)35 void FrictionMotion::Reset(double friction, double initPosition, double initVelocity, double threshold)
36 {
37 if (!IsValid(friction)) {
38 return;
39 }
40 friction_ = friction * FRICTION_SCALE;
41 initVelocity_ = std::abs(initVelocity);
42 currentTime_ = 0.0;
43 initPosition_ = initPosition;
44 valueThreshold_ = DEFAULT_THRESHOLD;
45 velocityThreshold_ = valueThreshold_ * threshold;
46
47 if (NearZero(initVelocity_)) {
48 signum_ = 0.0;
49 finalTime_ = 0.0;
50 } else {
51 signum_ = GreatNotEqual(initVelocity, 0.0) ? 1.0 : -1.0;
52 finalTime_ = UNIT_CONVERT * std::log(velocityThreshold_ / initVelocity_) / friction_;
53 }
54 finalTime_ = std::max(finalTime_, 0.0);
55 finalPosition_ = GetPosition(finalTime_ / UNIT_CONVERT);
56 }
57
IsValid(double friction) const58 bool FrictionMotion::IsValid(double friction) const
59 {
60 if (friction < 0.0 || NearZero(friction)) {
61 LOGE("Invalid friction:%{public}lf.", friction);
62 return false;
63 }
64 return true;
65 }
66
Move(float offsetTime)67 void FrictionMotion::Move(float offsetTime)
68 {
69 // change millisecond to second.
70 currentTime_ = offsetTime / UNIT_CONVERT;
71 }
72
GetPosition(float offsetTime) const73 double FrictionMotion::GetPosition(float offsetTime) const
74 {
75 return initPosition_ + signum_ * (initVelocity_ / friction_) * std::expm1(friction_ * offsetTime);
76 }
77
GetVelocityByFinalPosition(double final,double threshold) const78 double FrictionMotion::GetVelocityByFinalPosition(double final, double threshold) const
79 {
80 return valueThreshold_ * threshold * signum_ - (final - initPosition_) * friction_;
81 }
82
GetVelocity(float offsetTime) const83 double FrictionMotion::GetVelocity(float offsetTime) const
84 {
85 return signum_ * initVelocity_ * std::exp(friction_ * offsetTime);
86 }
87
GetCurrentPosition()88 double FrictionMotion::GetCurrentPosition()
89 {
90 return GetPosition(currentTime_);
91 }
92
GetCurrentVelocity()93 double FrictionMotion::GetCurrentVelocity()
94 {
95 return GetVelocity(currentTime_);
96 }
97
IsCompleted()98 bool FrictionMotion::IsCompleted()
99 {
100 return NearZero(GetCurrentVelocity(), velocityThreshold_) ||
101 NearEqual(finalPosition_, GetCurrentPosition(), 1.0);
102 }
103
GetFinalPosition() const104 double FrictionMotion::GetFinalPosition() const
105 {
106 return finalPosition_;
107 }
108
GetTimeByPosition(double position,double & time) const109 bool FrictionMotion::GetTimeByPosition(double position, double& time) const
110 {
111 time = 0.0;
112 if (NearZero(initVelocity_)) {
113 return false;
114 }
115
116 double rangeStart = 0.0;
117 double rangeEnd = finalPosition_;
118 if (finalPosition_ < 0.0) {
119 rangeStart = finalPosition_;
120 rangeEnd = 0.0;
121 }
122 if (position < rangeStart || position > rangeEnd) {
123 return false;
124 }
125 // Deduced by formula of Func(GetPosition)
126 time = std::log(position * friction_ / initVelocity_ + 1.0) / friction_;
127 return true;
128 }
129
GetMotionType() const130 std::string FrictionMotion::GetMotionType() const
131 {
132 return "friction";
133 }
134
135 } // namespace OHOS::Ace
136