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 "animation/rs_spring_interpolator.h"
17
18 #include <algorithm>
19 #include <cmath>
20
21 #include "platform/common/rs_log.h"
22
23 namespace OHOS {
24 namespace Rosen {
25 constexpr float MIN_DAMPING_RATIO = 0.0f;
26 constexpr float MAX_DAMPING_RATIO = 2.0f;
27 constexpr float MIN_DURATION = 0.02f;
28 constexpr float MAX_DURATION = 300.0f;
29 constexpr float SECONDS_TO_MICROSECONDS = 1e6f;
30 constexpr float MIN_RESPONSE = 1e-8;
31 constexpr float MIN_AMPLITUDE = 0.001f;
32
RSSpringInterpolator(float response,float dampingRatio,float initialOffset,float minimumAmplitude,float initialVelocity,float duration)33 RSSpringInterpolator::RSSpringInterpolator(float response, float dampingRatio, float initialOffset,
34 float minimumAmplitude, float initialVelocity, float duration)
35 : response_(response), dampingRatio_(dampingRatio), initialVelocity_(initialVelocity),
36 initialOffset_(initialOffset), minimumAmplitude_(minimumAmplitude), duration_(duration)
37 {
38 CalculateSpringParameters();
39 ROSEN_LOGD("SAG, %s response = %.2f, dampingRatio = %.2f, initialVelocity "
40 "= %.2f, initialOffset = %.2f minimumAmplitude = %.5f, duration = %.2f",
41 __func__, response_, dampingRatio_, initialVelocity_, initialOffset_, minimumAmplitude_, duration_);
42 }
43
Marshalling(Parcel & parcel) const44 bool RSSpringInterpolator::Marshalling(Parcel& parcel) const
45 {
46 if (!parcel.WriteUint16(InterpolatorType::SPRING)) {
47 ROSEN_LOGE("RSSpringInterpolator::Marshalling, Write type failed");
48 return false;
49 }
50 if (!(parcel.WriteFloat(response_) && parcel.WriteFloat(dampingRatio_) && parcel.WriteFloat(initialVelocity_) &&
51 parcel.WriteFloat(initialOffset_) && parcel.WriteFloat(minimumAmplitude_) &&
52 parcel.WriteFloat(duration_))) {
53 ROSEN_LOGE("RSSpringInterpolator::Marshalling, Write value failed");
54 return false;
55 }
56 return true;
57 }
58
Unmarshalling(Parcel & parcel)59 RSSpringInterpolator* RSSpringInterpolator::Unmarshalling(Parcel& parcel)
60 {
61 float response, dampingRatio, initialVelocity, initialOffset, minimumAmplitude, duration;
62 if (!(parcel.ReadFloat(response) && parcel.ReadFloat(dampingRatio) && parcel.ReadFloat(initialVelocity) &&
63 parcel.ReadFloat(initialOffset) && parcel.ReadFloat(minimumAmplitude) && parcel.ReadFloat(duration))) {
64 ROSEN_LOGE("RSSpringInterpolator::Unmarshalling, SpringInterpolator failed");
65 return nullptr;
66 }
67 auto ret =
68 new RSSpringInterpolator(response, dampingRatio, initialOffset, minimumAmplitude, initialVelocity, duration);
69 return ret;
70 }
71
InterpolateImpl(double seconds) const72 float RSSpringInterpolator::InterpolateImpl(double seconds) const
73 {
74 if (seconds <= 0) {
75 return 0;
76 } else if (seconds >= duration_) {
77 return initialOffset_;
78 }
79
80 double displacement = CalculateDisplacement(seconds);
81 return initialOffset_ - displacement;
82 }
83
CalculateDisplacement(double mappedTime) const84 double RSSpringInterpolator::CalculateDisplacement(double mappedTime) const
85 {
86 double coeffDecay = exp(coeffDecay_ * mappedTime);
87 if (dampingRatio_ < 1) {
88 // under-damped
89 double rad = dampedAngularVelocity_ * mappedTime;
90 double coeffPeriod = initialOffset_ * cos(rad) + coeffScale_ * sin(rad);
91 return coeffDecay * coeffPeriod;
92 } else if (dampingRatio_ == 1) {
93 // critical-damped
94 return coeffDecay * (initialOffset_ + coeffScale_ * mappedTime);
95 } else {
96 // over-damped
97 double coeffDecayMinus = exp(coeffDecayMinus_ * mappedTime);
98 return coeffDecay * coeffScale_ + coeffDecayMinus * coeffScaleMinus_;
99 }
100 }
101
CalculateSpringParameters()102 void RSSpringInterpolator::CalculateSpringParameters()
103 {
104 // handle wrong parameters:
105 // 1. dampingRatio which not in [0, 2]
106 // 2. response/minimumAmplitude which <= 0
107 dampingRatio_ = std::clamp(dampingRatio_, MIN_DAMPING_RATIO, MAX_DAMPING_RATIO);
108 if (response_ <= 0) {
109 response_ = MIN_RESPONSE;
110 }
111
112 float naturalAngularVelocity = 2 * M_PI / response_;
113 float initialVelocity = -initialVelocity_;
114 if (dampingRatio_ < 1) {
115 // Underdamped Systems
116 dampedAngularVelocity_ = naturalAngularVelocity * sqrt(1.0f - dampingRatio_ * dampingRatio_);
117 coeffDecay_ = -dampingRatio_ * naturalAngularVelocity;
118 coeffScale_ =
119 (initialVelocity + dampingRatio_ * naturalAngularVelocity * initialOffset_) / dampedAngularVelocity_;
120 } else if (dampingRatio_ == 1) {
121 // Critically-Damped Systems
122 coeffDecay_ = -naturalAngularVelocity;
123 coeffScale_ = initialVelocity + naturalAngularVelocity * initialOffset_;
124 } else {
125 // Overdamped Systems
126 float coeffTmp = sqrt(dampingRatio_ * dampingRatio_ - 1);
127 coeffDecay_ = (-dampingRatio_ + coeffTmp) * naturalAngularVelocity;
128 coeffScale_ = ((dampingRatio_ + coeffTmp) * naturalAngularVelocity * initialOffset_ + initialVelocity) /
129 (2 * naturalAngularVelocity * coeffTmp);
130 coeffScaleMinus_ = (-(dampingRatio_ - coeffTmp) * naturalAngularVelocity * initialOffset_ - initialVelocity) /
131 (2 * naturalAngularVelocity * coeffTmp);
132 coeffDecayMinus_ = (-dampingRatio_ - coeffTmp) * naturalAngularVelocity;
133 }
134
135 if (duration_ <= 0) {
136 EstimateDuration();
137 }
138 }
139
EstimateDuration()140 void RSSpringInterpolator::EstimateDuration()
141 {
142 if (minimumAmplitude_ <= 0) {
143 minimumAmplitude_ = MIN_AMPLITUDE;
144 }
145 if (dampingRatio_ < 1) {
146 // Underdamped Systems
147 if (coeffScale_ != 0) {
148 duration_ = log(abs(coeffScale_) / minimumAmplitude_) / -coeffDecay_;
149 }
150 } else if (dampingRatio_ == 1) {
151 // Critically-Damped Systems
152 if ((coeffScale_ + initialOffset_) != 0) {
153 duration_ = log(abs(coeffScale_ + initialOffset_) / minimumAmplitude_) / -coeffDecay_;
154 }
155 } else {
156 // Overdamped Systems
157 if (coeffScale_ != 0 && coeffScaleMinus_ != 0) {
158 duration_ = fmax(log(abs(coeffScale_) / minimumAmplitude_ * 2) / -coeffDecay_,
159 log(abs(coeffScaleMinus_) / minimumAmplitude_ * 2) / -coeffDecayMinus_);
160 }
161 }
162 ROSEN_LOGD("SAG, %s estimated duration = %.5f, actual duration = %.5f", __func__, duration_,
163 std::clamp(duration_, MIN_DURATION, MAX_DURATION));
164 duration_ = std::clamp(duration_, MIN_DURATION, MAX_DURATION);
165 }
166
UpdateParameters(float response,float dampingRatio,float initialVelocity,float initialOffset,float minimumAmplitude)167 void RSValueSpringInterpolator::UpdateParameters(
168 float response, float dampingRatio, float initialVelocity, float initialOffset, float minimumAmplitude)
169 {
170 if (response == response_ && dampingRatio == dampingRatio_ && initialVelocity == initialVelocity_ &&
171 initialOffset == initialOffset_ && isReversed_ == false) {
172 return;
173 }
174
175 isReversed_ = false;
176 response_ = response;
177 dampingRatio_ = dampingRatio;
178 initialVelocity_ = initialVelocity;
179 initialOffset_ = initialOffset;
180 minimumAmplitude_ = minimumAmplitude;
181 duration_ = -1; // recalculate spring duration
182
183 CalculateSpringParameters();
184
185 ROSEN_LOGD("SAG, %s response = %.2f, dampingRatio = %.2f, initialOffset = %.2f, initialVelocity "
186 "= %.2f, minimumAmplitude = %.2f, duration = %.2f",
187 __func__, response_, dampingRatio_, initialOffset_, initialVelocity_, minimumAmplitude_, duration_);
188 }
189
GetInstantaneousVelocity(int64_t microseconds) const190 float RSValueSpringInterpolator::GetInstantaneousVelocity(int64_t microseconds) const
191 {
192 if (microseconds <= 0) {
193 return initialVelocity_;
194 } else {
195 return (InterpolateValue(microseconds + 1) - InterpolateValue(microseconds)) * SECONDS_TO_MICROSECONDS;
196 }
197 }
198
InterpolateValue(int64_t microseconds) const199 float RSValueSpringInterpolator::InterpolateValue(int64_t microseconds) const
200 {
201 if (isReversed_) {
202 return initialOffset_ - InterpolateImpl(duration_ - microseconds / SECONDS_TO_MICROSECONDS);
203 } else {
204 return InterpolateImpl(microseconds / SECONDS_TO_MICROSECONDS);
205 }
206 }
207
GetEstimatedDuration() const208 int64_t RSValueSpringInterpolator::GetEstimatedDuration() const
209 {
210 return static_cast<int64_t>(duration_ * SECONDS_TO_MICROSECONDS);
211 }
212
213 } // namespace Rosen
214 } // namespace OHOS
215