sandbox
Loading...
Searching...
No Matches
smooth_value.hpp
1#ifndef LIBSBX_MATH_SMOOTH_VALUE_HPP_
2#define LIBSBX_MATH_SMOOTH_VALUE_HPP_
3
4#include <cmath>
5#include <concepts>
6#include <type_traits>
7
8#include <libsbx/units/time.hpp>
9
10#include <libsbx/utility/logger.hpp>
11
12#include <libsbx/math/concepts.hpp>
13#include <libsbx/math/constants.hpp>
14#include <libsbx/math/traits.hpp>
15#include <libsbx/math/algorithm.hpp>
16
17namespace sbx::math {
18
19enum class smoothing_mode : std::uint8_t {
20 linear,
21 proportional
22}; // enum class smoothing_mode
23
24template<typename Type>
25struct is_smoothable : std::false_type { };
26
27template<typename Type>
28inline constexpr auto is_smoothable_v = is_smoothable<Type>::value;
29
30template<floating_point Type>
31struct is_smoothable<Type> : std::true_type { };
32
33template<typename Type>
34concept smoothable = is_smoothable_v<Type>;
35
36template<smoothable Type, smoothing_mode Mode>
38
39public:
40
41 using value_type = Type;
42
43 inline static constexpr auto mode = Mode;
44
45 basic_smooth_value(const value_type value)
46 : _current{value},
47 _target{value} { }
48
49 static constexpr auto clamp(const basic_smooth_value& value, const value_type min, const value_type max) -> basic_smooth_value {
50 return basic_smooth_value{value._current, std::clamp(value._target, min, max)};
51 }
52
53 template<floating_point Ratio>
54 static constexpr auto lerp(const basic_smooth_value& x, const basic_smooth_value& y, const Ratio ratio) -> basic_smooth_value {
55 return basic_smooth_value{x._current, mix(x._target, y._target, ratio)};
56 }
57
58 constexpr auto operator=(const value_type value) -> basic_smooth_value& {
59 _target = value;
60
61 return *this;
62 }
63
64 constexpr auto operator+=(const value_type value) -> basic_smooth_value& {
65 _target += value;
66
67 return *this;
68 }
69
70 constexpr auto operator-=(const value_type value) -> basic_smooth_value& {
71 _target -= value;
72
73 return *this;
74 }
75
76 constexpr auto operator*=(const value_type value) -> basic_smooth_value& {
77 _target *= value;
78
79 return *this;
80 }
81
82 constexpr auto operator/=(const value_type value) -> basic_smooth_value& {
83 _target /= value;
84
85 return *this;
86 }
87
88 constexpr auto operator+(const value_type value) -> basic_smooth_value {
89 auto copy = basic_smooth_value{*this};
90 copy += value;
91 return copy;
92 }
93
94 constexpr auto operator-(const value_type value) -> basic_smooth_value {
95 auto copy = basic_smooth_value{*this};
96 copy -= value;
97 return copy;
98 }
99
100 constexpr auto operator*(const value_type value) -> basic_smooth_value {
101 auto copy = basic_smooth_value{*this};
102 copy *= value;
103 return copy;
104 }
105
106 constexpr auto operator/(const value_type value) -> basic_smooth_value {
107 auto copy = basic_smooth_value{*this};
108 copy /= value;
109 return copy;
110 }
111
112 constexpr auto value() const noexcept -> value_type {
113 return _current;
114 }
115
116 constexpr operator value_type() const noexcept {
117 return value();
118 }
119
120 constexpr void update(const units::second& delta_time, const value_type base_speed) {
121 const auto difference = _target - _current;
122
123 if (comparision_traits<value_type>::equal(difference, static_cast<value_type>(0))) {
124 _current = _target;
125 return;
126 }
127
128 const auto step = _compute_step(difference, base_speed, delta_time);
129
130 // Clamp step to not overshoot
131 if (std::abs(step) >= std::abs(difference)) {
132 _current = _target;
133 } else {
134 _current += step;
135 }
136 }
137
138
139private:
140
141 basic_smooth_value(const value_type current, const value_type target)
142 : _current{current},
143 _target{target} { }
144
145 constexpr auto _compute_step(const value_type difference, const value_type base_speed, const units::second& delta_time) const -> value_type {
146 switch (mode) {
147 case smoothing_mode::linear: {
148 return (difference > 0 ? 1 : -1) * base_speed * delta_time;
149 }
150 case smoothing_mode::proportional: {
151 return difference * base_speed * delta_time;
152 }
153 default: {
154 return {};
155 }
156 }
157 }
158
159 value_type _current;
160 value_type _target;
161
162}; // class basic_smooth_value
163
164template<smoothable Type>
166
168
170
171template<smoothable Type>
173
175
177
178} // namespace sbx::math
179
180#endif // LIBSBX_MATH_SMOOTH_VALUE_HPP_
Definition: smooth_value.hpp:37
Definition: quantity.hpp:65
Definition: traits.hpp:10
Definition: smooth_value.hpp:25