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/spring_model.h"
17
18 #include "base/log/log.h"
19 #include "base/utils/utils.h"
20
21 namespace OHOS::Ace {
22 namespace {
23
24 constexpr double HIGH_RATIO = 4.0;
25 constexpr double LOW_RATIO = 2.0;
26
27 } // namespace
28
IsValid() const29 bool SpringProperty::IsValid() const
30 {
31 if (LessOrEqual(mass_, 0.0) || LessOrEqual(stiffness_, 0.0) || LessOrEqual(damping_, 0.0)) {
32 return false;
33 }
34 return true;
35 }
36
SetMass(double mass)37 void SpringProperty::SetMass(double mass)
38 {
39 if (mass > 0.0) {
40 mass_ = mass;
41 }
42 }
43
Mass() const44 double SpringProperty::Mass() const
45 {
46 return mass_;
47 }
48
SetStiffness(double stiffness)49 void SpringProperty::SetStiffness(double stiffness)
50 {
51 if (stiffness > 0.0) {
52 stiffness_ = stiffness;
53 }
54 }
55
Stiffness() const56 double SpringProperty::Stiffness() const
57 {
58 return stiffness_;
59 }
60
SetDamping(double damping)61 void SpringProperty::SetDamping(double damping)
62 {
63 if (damping > 0.0) {
64 damping_ = damping;
65 }
66 }
67
Damping() const68 double SpringProperty::Damping() const
69 {
70 return damping_;
71 }
72
Build(double distance,double velocity,const RefPtr<SpringProperty> & spring)73 RefPtr<SpringModel> SpringModel::Build(double distance, double velocity, const RefPtr<SpringProperty>& spring)
74 {
75 if (!spring || !spring->IsValid()) {
76 LOGE("SpringProperty can not be nullptr.");
77 return nullptr;
78 } else {
79 double cmk = spring->Damping() * spring->Damping() - HIGH_RATIO * spring->Mass() * spring->Stiffness();
80 if (NearZero(cmk)) {
81 if (NearZero(distance)) {
82 LOGE("create CriticalDamped failed, distance can not be zero.");
83 return nullptr;
84 }
85 return AceType::MakeRefPtr<CriticalDampedModel>(distance, velocity, spring);
86 } else if (cmk > 0.0) {
87 return AceType::MakeRefPtr<OverdampedModel>(distance, velocity, spring);
88 } else {
89 return AceType::MakeRefPtr<UnderdampedModel>(distance, velocity, spring);
90 }
91 }
92 }
93
94 // Overdamping calculation model.
CriticalDampedModel(double distance,double velocity,const RefPtr<SpringProperty> & spring)95 CriticalDampedModel::CriticalDampedModel(double distance, double velocity, const RefPtr<SpringProperty>& spring)
96 {
97 if (spring && spring->IsValid() && !NearZero(distance)) {
98 r_ = -spring->Damping() / (LOW_RATIO * spring->Mass());
99 c1_ = distance;
100 c2_ = velocity / (r_ * distance);
101 }
102 }
103
Position(double time) const104 double CriticalDampedModel::Position(double time) const
105 {
106 return (c1_ + c2_ * time) * exp(r_ * time);
107 }
108
Velocity(double time) const109 double CriticalDampedModel::Velocity(double time) const
110 {
111 const double power = exp(r_ * time);
112 return r_ * (c1_ + c2_ * time) * power + c2_ * power;
113 }
114
GetType() const115 SpringModelType CriticalDampedModel::GetType() const
116 {
117 return SpringModelType::CRITICAL_DAMPED;
118 }
119
120 // Overdamping calculation model.
OverdampedModel(double distance,double velocity,const RefPtr<SpringProperty> & spring)121 OverdampedModel::OverdampedModel(double distance, double velocity, const RefPtr<SpringProperty>& spring)
122 {
123 if (spring && spring->IsValid()) {
124 double cmk = spring->Damping() * spring->Damping() - HIGH_RATIO * spring->Mass() * spring->Stiffness();
125 r1_ = (-spring->Damping() - sqrt(cmk)) / (LOW_RATIO * spring->Mass());
126 r2_ = (-spring->Damping() + sqrt(cmk)) / (LOW_RATIO * spring->Mass());
127 if (!NearEqual(r2_, r1_)) {
128 c2_ = (velocity - r1_ * distance) / (r2_ - r1_);
129 c1_ = distance - c2_;
130 }
131 }
132 }
133
Position(double time) const134 double OverdampedModel::Position(double time) const
135 {
136 return c1_ * exp(r1_ * time) + c2_ * exp(r2_ * time);
137 }
138
Velocity(double time) const139 double OverdampedModel::Velocity(double time) const
140 {
141 return c1_ * r1_ * exp(r1_ * time) + c2_ * r2_ * exp(r2_ * time);
142 }
143
GetType() const144 SpringModelType OverdampedModel::GetType() const
145 {
146 return SpringModelType::OVER_DAMPED;
147 }
148
149 // Underdamped calculation model
UnderdampedModel(double distance,double velocity,const RefPtr<SpringProperty> & spring)150 UnderdampedModel::UnderdampedModel(double distance, double velocity, const RefPtr<SpringProperty>& spring)
151 {
152 if (spring && spring->IsValid()) {
153 w_ = sqrt(HIGH_RATIO * spring->Mass() * spring->Stiffness() - spring->Damping() * spring->Damping()) /
154 (LOW_RATIO * spring->Mass());
155 r_ = -(spring->Damping() / LOW_RATIO * spring->Mass());
156 c1_ = distance;
157 if (!NearEqual(w_, 0.0)) {
158 c2_ = (velocity - r_ * distance) / w_;
159 }
160 }
161 }
162
Position(double time) const163 double UnderdampedModel::Position(double time) const
164 {
165 return exp(r_ * time) * (c1_ * cos(w_ * time) + c2_ * sin(w_ * time));
166 }
167
Velocity(double time) const168 double UnderdampedModel::Velocity(double time) const
169 {
170 double power = exp(r_ * time);
171 double cosine = cos(w_ * time);
172 double sine = sin(w_ * time);
173 return power * (c2_ * w_ * cosine - c1_ * w_ * sine) + r_ * power * (c2_ * sine + c1_ * cosine);
174 }
175
GetType() const176 SpringModelType UnderdampedModel::GetType() const
177 {
178 return SpringModelType::UNDER_DAMPED;
179 }
180
181 } // namespace OHOS::Ace