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 "core/animation/bilateral_spring_node.h"
17
18 namespace OHOS::Ace {
19 namespace {
20
21 constexpr int64_t NANOS_TO_MILLS = 1000000;
22
23 } // namespace
24
NotifyNext(double endValue,double initVelocity)25 void BilateralSpringNode::NotifyNext(double endValue, double initVelocity)
26 {
27 if (!adapter_) {
28 LOGE("Notify next failed. adapter is null.");
29 return;
30 }
31 if (Claim(this) != adapter_->GetControlNode() || adapter_->GetSize() < 2) {
32 return;
33 }
34
35 int32_t controlIndex = adapter_->GetSize() / 2;
36 RefPtr<SpringNode> node;
37 for (int32_t index = 1; index <= controlIndex; index++) {
38 if (controlIndex + index < adapter_->GetSize()) {
39 node = adapter_->GetNode(controlIndex + index);
40 if (node) {
41 node->EndToValue(endValue, initVelocity);
42 }
43 }
44 if (controlIndex - index >= 0) {
45 node = adapter_->GetNode(controlIndex - index);
46 if (node) {
47 node->EndToValue(endValue, initVelocity);
48 }
49 }
50 }
51 }
52
OnAnimation()53 void BilateralSpringNode::OnAnimation()
54 {
55 auto context = context_.Upgrade();
56 if (!context) {
57 LOGE("Animate failed, context is null. index: %{public}d", index_);
58 return;
59 }
60 if (!spring_) {
61 LOGE("Animate failed, spring is null. index: %{public}d", index_);
62 return;
63 }
64 int64_t delta = static_cast<int64_t>(context->GetTimeFromExternalTimer()) - static_cast<int64_t>(startTime_);
65 spring_->OnTimestampChanged(static_cast<double>(delta * 1.0) / static_cast<double>(NANOS_TO_MILLS), 0.0f, false);
66 double simpleValue = spring_->GetCurrentPosition();
67 FixValue(simpleValue);
68 DoCollision();
69 velocity_ = spring_->GetCurrentVelocity();
70 if (spring_->IsCompleted() || spring_->IsCompleted(simpleValue, velocity_)) {
71 isRunning_ = false;
72 value_ = spring_->GetEndValue();
73 velocity_ = 0.0;
74 // Node's animation update callback
75 OnUpdate(value_, velocity_);
76 NotifyUpdateListener(value_, velocity_);
77 OnEnd(value_);
78 if (scheduler_->IsActive()) {
79 scheduler_->Stop();
80 }
81 } else {
82 OnUpdate(value_, velocity_);
83 NotifyUpdateListener(value_, velocity_);
84 if (!scheduler_->IsActive()) {
85 scheduler_->Start();
86 }
87 }
88 }
89
DoCollision()90 void BilateralSpringNode::DoCollision()
91 {
92 if (!switchCollision_ || !adapter_) {
93 return;
94 }
95 if (adapter_->GetControlIndex() > GetIndex()) {
96 // up / left node
97 auto next = adapter_->GetNode(GetIndex() + 1);
98 if (next) {
99 double nextBasePosition = next->GetValue() + decoration_;
100 value_ = std::clamp(value_, nextBasePosition - maxDecoration_, nextBasePosition - minDecoration_);
101 }
102 }
103 if (adapter_->GetControlIndex() < GetIndex()) {
104 // down / right node
105 auto prev = adapter_->GetNode(GetIndex() - 1);
106 if (prev) {
107 double prevBasePosition = prev->GetValue() - decoration_;
108 value_ = std::clamp(value_, prevBasePosition + minDecoration_, prevBasePosition + maxDecoration_);
109 }
110 }
111 }
112
FixValue(double springValue)113 void BilateralSpringNode::FixValue(double springValue)
114 {
115 if (fixMode_) {
116 SimpleFixedValue(springValue);
117 } else {
118 value_ = springValue;
119 }
120 }
121
SimpleFixedValue(double springValue)122 void BilateralSpringNode::SimpleFixedValue(double springValue)
123 {
124 if (!fixMode_) {
125 value_ = springValue;
126 return;
127 }
128 double delta = springValue - lastTheoryValue_;
129 lastTheoryValue_ = springValue;
130
131 if (GreatOrEqual(std::abs(delta), 1.0)) {
132 // The displacement between two frames is greater than 1 pixel, using engine data
133 value_ = springValue;
134 } else {
135 // The displacement between two frames is less than 1 pixel, and +1 processing is performed
136 if (delta > 0.0) {
137 value_++;
138 } else {
139 value_--;
140 }
141 }
142 }
143
SetDeltaValue(double delta)144 void BilateralSpringNode::SetDeltaValue(double delta)
145 {
146 SimpleSpringNode::SetDeltaValue(delta);
147 DoCollision();
148 }
149
150 } // namespace OHOS::Ace