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