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