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