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