• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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