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