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