1 /*
2 * Copyright (c) 2022-2023 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 #ifndef ROSEN_ENGINE_CORE_ANIMATION_RS_SPRING_MODEL_H
17 #define ROSEN_ENGINE_CORE_ANIMATION_RS_SPRING_MODEL_H
18
19 #include "common/rs_macros.h"
20 #include "common/rs_vector2.h"
21 #include "common/rs_vector4.h"
22 #include <vector>
23
24 namespace OHOS {
25 namespace Rosen {
26 class RSRenderPropertyBase;
27 namespace {
28 constexpr float SPRING_MIN_DAMPING_RATIO = 1e-4f;
29 constexpr float SPRING_MAX_DAMPING_RATIO = 1e4f;
30 constexpr float SPRING_MIN_DURATION = 1e-3f;
31 constexpr float SPRING_MAX_DURATION = 300.0f;
32 constexpr float SPRING_MIN_RESPONSE = 1e-8;
33 constexpr float SPRING_MIN_AMPLITUDE_RATIO = 1e-3f;
34 constexpr float SPRING_MIN_AMPLITUDE = 1e-5f;
35 constexpr float FLOAT_PI = 3.14159265f;
36
37 // helper function to simplify estimation of spring duration
38 template<typename RSAnimatableType>
toFloat(RSAnimatableType value)39 float toFloat(RSAnimatableType value)
40 {
41 return 1.f;
42 }
43 template<>
toFloat(Vector4f value)44 float toFloat(Vector4f value)
45 {
46 return value.GetLength();
47 }
48 template<>
toFloat(Quaternion value)49 float toFloat(Quaternion value)
50 {
51 return value.GetLength();
52 }
53 template<>
toFloat(Vector2f value)54 float toFloat(Vector2f value)
55 {
56 return value.GetLength();
57 }
58 } // namespace
59
Add(const std::vector<float> & first,const std::vector<float> & second)60 inline std::vector<float> Add(const std::vector<float> &first, const std::vector<float> &second)
61 {
62 std::vector<float> result;
63 if (first.size() == second.size()) {
64 result.reserve(first.size());
65 for (auto i = 0u; i < first.size(); i++) {
66 result.push_back(first.at(i) + second.at(i));
67 }
68 } else {
69 result = second;
70 }
71 return result;
72 }
73 inline std::vector<float> operator-(const std::vector<float> &first, const std::vector<float> &second)
74 {
75 std::vector<float> result;
76 if (first.size() == second.size()) {
77 result.reserve(first.size());
78 for (auto i = 0u; i < first.size(); i++) {
79 result.push_back(first.at(i) - second.at(i));
80 }
81 } else {
82 result = second;
83 }
84 return result;
85 }
86 inline std::vector<float> operator+(const std::vector<float> &first, const std::vector<float> &second)
87 {
88 return Add(first, second);
89 }
90 inline std::vector<float> operator*(const std::vector<float> &first, float scale)
91 {
92 std::vector<float> result;
93 result.reserve(first.size());
94 for (auto i = 0u; i < first.size(); i++) {
95 result.push_back(first.at(i) * scale);
96 }
97 return result;
98 }
99 inline std::vector<float> operator/(const std::vector<float> &first, float scale)
100 {
101 std::vector<float> result;
102 result.reserve(first.size());
103 if (ROSEN_EQ(scale, 0.0f)) {
104 return first;
105 }
106 for (auto i = 0u; i < first.size(); i++) {
107 result.push_back(first.at(i) / scale);
108 }
109 return result;
110 }
111
112 // RSAnimatableType should have following operators: + - *float ==
113 template<typename RSAnimatableType>
114 class RSB_EXPORT RSSpringModel {
115 public:
RSSpringModel()116 RSSpringModel() {};
117
RSSpringModel(float response,float dampingRatio,const RSAnimatableType & initialOffset,const RSAnimatableType & initialVelocity,float minimumAmplitude)118 explicit RSSpringModel(float response, float dampingRatio, const RSAnimatableType& initialOffset,
119 const RSAnimatableType& initialVelocity, float minimumAmplitude)
120 : response_(response), dampingRatio_(dampingRatio), initialOffset_(initialOffset),
121 initialVelocity_(initialVelocity), minimumAmplitudeRatio_(minimumAmplitude)
122 {
123 CalculateSpringParameters();
124 }
125
~RSSpringModel()126 ~RSSpringModel() {};
127
CalculateDisplacement(double time)128 RSAnimatableType CalculateDisplacement(double time) const
129 {
130 if (dampingRatio_ <= 0.0f) {
131 return {};
132 }
133 double coeffDecay = exp(coeffDecay_ * time);
134 if (dampingRatio_ < 1) {
135 // under-damped
136 double rad = dampedAngularVelocity_ * time;
137 RSAnimatableType coeffPeriod = initialOffset_ * cos(rad) + coeffScale_ * sin(rad);
138 return coeffPeriod * coeffDecay;
139 } else if (ROSEN_EQ(dampingRatio_, 1.0f)) {
140 // critical-damped
141 return (initialOffset_ + coeffScale_ * time) * coeffDecay;
142 } else {
143 // over-damped
144 double coeffDecayAlt = exp(coeffDecayAlt_ * time);
145 return coeffScale_ * coeffDecay + coeffScaleAlt_ * coeffDecayAlt;
146 }
147 }
148
EstimateDuration()149 float EstimateDuration() const
150 {
151 if (dampingRatio_ <= 0.0f || response_ <= 0.0f) {
152 return 0.0f;
153 }
154
155 // convert templated type to float, simplify estimation of spring duration
156 float coeffScale = toFloat(coeffScale_);
157 float initialOffset = toFloat(initialOffset_);
158 float estimatedDuration = 0.0f;
159 float minimumAmplitude = std::max(initialOffset * minimumAmplitudeRatio_, SPRING_MIN_AMPLITUDE);
160
161 if (dampingRatio_ < 1) { // Under-damped
162 if (ROSEN_EQ(coeffDecay_, 0.0f)) {
163 return 0.0f;
164 }
165 estimatedDuration = log(fmax(coeffScale, initialOffset) / minimumAmplitude) / -coeffDecay_;
166 } else if (ROSEN_EQ(dampingRatio_, 1.0f)) { // Critically-damped
167 // critical damping spring use dampingRatio = 0.999 to esimate duration approximately
168 constexpr float dampingRatio = 0.999f;
169 double naturalAngularVelocity = 2 * FLOAT_PI / response_;
170 double dampedAngularVelocity = naturalAngularVelocity * sqrt(1.0f - dampingRatio * dampingRatio);
171 if (ROSEN_EQ(dampedAngularVelocity, 0.0)) {
172 return 0.0f;
173 }
174 double tempCoeffA = 1.0 / (dampingRatio * naturalAngularVelocity);
175 double tempCoeffB = toFloat((initialVelocity_ + initialOffset_ * dampingRatio * naturalAngularVelocity) *
176 (1 / dampedAngularVelocity));
177 double tempCoeffC = sqrt(initialOffset * initialOffset + tempCoeffB * tempCoeffB);
178 if (ROSEN_EQ(tempCoeffC, 0.0)) {
179 return 0.0f;
180 }
181 estimatedDuration = log(tempCoeffC / minimumAmplitude) * tempCoeffA;
182 } else { // Over-damped
183 if (ROSEN_EQ(coeffDecay_, 0.0f) || ROSEN_EQ(coeffDecayAlt_, 0.0f)) {
184 return 0.0f;
185 }
186 float coeffScaleAlt = toFloat(coeffScaleAlt_);
187 double durationMain =
188 (coeffScale <= minimumAmplitude) ? 0 : (log(coeffScale / minimumAmplitude) / -coeffDecay_);
189 double durationAlt =
190 (coeffScaleAlt <= minimumAmplitude) ? 0 : (log(coeffScaleAlt / minimumAmplitude) / -coeffDecayAlt_);
191 estimatedDuration = fmax(durationMain, durationAlt);
192 }
193 return std::clamp(estimatedDuration, SPRING_MIN_DURATION, SPRING_MAX_DURATION);
194 }
195
196 protected:
CalculateSpringParameters()197 void CalculateSpringParameters()
198 {
199 // sanity check
200 dampingRatio_ = std::clamp(dampingRatio_, SPRING_MIN_DAMPING_RATIO, SPRING_MAX_DAMPING_RATIO);
201 if (response_ <= 0) {
202 response_ = SPRING_MIN_RESPONSE;
203 }
204 if (minimumAmplitudeRatio_ <= 0) {
205 minimumAmplitudeRatio_ = SPRING_MIN_AMPLITUDE_RATIO;
206 }
207
208 // calculate internal parameters
209 double naturalAngularVelocity = 2 * FLOAT_PI / response_;
210 if (dampingRatio_ < 1) { // Under-damped Systems
211 dampedAngularVelocity_ = naturalAngularVelocity * sqrt(1.0f - dampingRatio_ * dampingRatio_);
212 if (ROSEN_EQ(dampedAngularVelocity_, 0.0f)) {
213 return;
214 }
215 coeffDecay_ = -dampingRatio_ * naturalAngularVelocity;
216 coeffScale_ = (initialVelocity_ + initialOffset_ * dampingRatio_ * naturalAngularVelocity) *
217 (1 / dampedAngularVelocity_);
218 } else if (ROSEN_EQ(dampingRatio_, 1.0f)) { // Critically-Damped Systems
219 coeffDecay_ = -naturalAngularVelocity;
220 coeffScale_ = initialVelocity_ + initialOffset_ * naturalAngularVelocity;
221 } else { // Over-damped Systems
222 double coeffTmp = sqrt(dampingRatio_ * dampingRatio_ - 1);
223 if (ROSEN_EQ(naturalAngularVelocity * coeffTmp, 0.0)) {
224 return;
225 }
226 coeffDecay_ = (-dampingRatio_ + coeffTmp) * naturalAngularVelocity;
227 coeffScale_ = (initialOffset_ * ((dampingRatio_ + coeffTmp) * naturalAngularVelocity) + initialVelocity_) *
228 (0.5f / (naturalAngularVelocity * coeffTmp));
229 coeffScaleAlt_ =
230 (initialOffset_ * ((coeffTmp - dampingRatio_) * naturalAngularVelocity) - initialVelocity_) *
231 (0.5f / (naturalAngularVelocity * coeffTmp));
232 coeffDecayAlt_ = (-dampingRatio_ - coeffTmp) * naturalAngularVelocity;
233 }
234 }
235
236 // physical parameters of spring-damper model
237 float response_ { 0.0f };
238 float dampingRatio_ { 0.0f };
239 RSAnimatableType initialOffset_ {};
240 RSAnimatableType initialVelocity_ {};
241
242 // estimated duration until the spring is at rest
243 float minimumAmplitudeRatio_ { SPRING_MIN_AMPLITUDE_RATIO };
244
245 private:
EstimateDurationForUnderDampedModel()246 float EstimateDurationForUnderDampedModel() const
247 {
248 return 0.0f;
249 }
EstimateDurationForCriticalDampedModel()250 float EstimateDurationForCriticalDampedModel() const
251 {
252 return 0.0f;
253 }
EstimateDurationForOverDampedModel()254 float EstimateDurationForOverDampedModel() const
255 {
256 return 0.0f;
257 }
BinarySearchTime(float left,float right,RSAnimatableType target)258 float BinarySearchTime(float left, float right, RSAnimatableType target) const
259 {
260 return 0.0f;
261 }
262 // calculated intermediate coefficient
263 float coeffDecay_ { 0.0f };
264 RSAnimatableType coeffScale_ {};
265 float dampedAngularVelocity_ { 0.0f };
266 RSAnimatableType coeffScaleAlt_ {};
267 float coeffDecayAlt_ { 0.0f };
268
269 template<typename T>
270 friend class RSSpringValueEstimator;
271 };
272
273 template class RSSpringModel<Vector2f>;
274 template class RSSpringModel<Vector4f>;
275 template class RSSpringModel<Quaternion>;
276
277 // only used for property of which type is float
278 template<>
279 RSB_EXPORT float RSSpringModel<float>::EstimateDuration() const;
280 template<>
281 float RSSpringModel<std::shared_ptr<RSRenderPropertyBase>>::EstimateDuration() const;
282 template<>
283 RSB_EXPORT float RSSpringModel<float>::BinarySearchTime(float left, float right, float target) const;
284 template<>
285 RSB_EXPORT float RSSpringModel<float>::EstimateDurationForUnderDampedModel() const;
286 template<>
287 RSB_EXPORT float RSSpringModel<float>::EstimateDurationForCriticalDampedModel() const;
288 template<>
289 RSB_EXPORT float RSSpringModel<float>::EstimateDurationForOverDampedModel() const;
290
291 template<>
292 void RSSpringModel<std::shared_ptr<RSRenderPropertyBase>>::CalculateSpringParameters();
293 template<>
294 std::shared_ptr<RSRenderPropertyBase> RSSpringModel<std::shared_ptr<RSRenderPropertyBase>>::CalculateDisplacement(
295 double time) const;
296 } // namespace Rosen
297 } // namespace OHOS
298
299 #endif // ROSEN_ENGINE_CORE_ANIMATION_RS_SPRING_MODEL_H
300