CYD-UI
A C++ library for building native graphic user interfaces
Loading...
Searching...
No Matches
interpolation.cppm
Go to the documentation of this file.
1//
2// Created by castle on 2/21/25.
3//
4
5export module cydui.interpolation;
6
7import std;
8import fabric.logging;
9
10export import cydui.easing_functions;
11
12export import :mappings;
13
14#define FLOAT_TOLERANCE 0.0001
15
16bool fuzzy_eq(const float a, const float b) {
17 return std::abs(a - b) < FLOAT_TOLERANCE;
18}
19
20bool is_zero(float a) {
21 return fuzzy_eq(a, 0.0f);
22}
23
24std::optional<float> find_root(std::function<float(float)> fun, float x0, float x1) {
25 static constexpr int N_MAX = 1000;
26 int n = N_MAX;
27
28 if (is_zero(fun(x0))) {
29 // LOG::print{INFO}("OK: {} iterations", N_MAX - n);
30 return x0;
31 }
32 if (is_zero(fun(x1))) {
33 // LOG::print{INFO}("OK: {} iterations", N_MAX - n);
34 return x1;
35 }
36
37 while (n-- > 0) {
38 float x = (x0 + x1) / 2;
39 float y = fun(x);
40 // LOG::print{INFO}("[ITER: {}] error: {}", N_MAX - n, y);
41 if (is_zero(y)) {
42 // LOG::print{INFO}("OK: {} iterations", N_MAX - n);
43 return x;
44 }
45
46 if (y < 0.0f) {
47 x0 = x;
48 } else {
49 x1 = x;
50 }
51 }
52
53 LOG::print{ERROR}("FAILED to find root");
54 return std::nullopt;
55}
56
57namespace cydui {
58 export class interpolator_base {
59 public:
60 using sptr = std::shared_ptr<interpolator_base>;
61
62 virtual ~interpolator_base() = default;
64 };
65
66 namespace interp {
67 export class lerp final: public interpolator_base {
68 public:
69 lerp() = default;
71 return (1 - t) * x0 + t * x1;
72 }
73 };
74
75 export class easing final: public interpolator_base {
76 public:
78 explicit easing(function_type fun): fun_(fun) {}
80 const float_type s = normalize(t, fun_);
81 return (1 - s) * x0 + s * x1;
82 }
83 private:
84 static float_type normalize(float_type t, const function_type& fun) {
85 return (fun(t) - fun(0)) / (fun(1) - fun(0));
86 }
87
88 private:
89 function_type fun_;
90 };
91
92 export class bezier final: public interpolator_base {
93 public:
99 : c0(c0_),
100 c1(c1_) {
101 // Clamp control points within time domain [0, 1]
102 c0.t = std::clamp(c0.t, 0.0f, 1.0f);
103 c1.t = std::clamp(c1.t, 0.0f, 1.0f);
104
105 // Cache values used in the cubic bezier polynomial
106 As = 3 * c0.t;
107 Bs = 3 * (-2 * c0.t + c1.t);
108 // Cs = (-3 * c0.t + c1.t + 3);
109 Cs = (3 * c0.t - 3 * c1.t + 1);
110 }
112 const auto s_opt = find_root([&](const float_type s) {
113 return s * As //
114 + s * s * Bs //
115 + s * s * s * Cs //
116 - t;
117 }, 0.0f, 1.0f);
118
119 if (s_opt.has_value()) {
120 const float_type s = s_opt.value();
121 // I'm translating the curve so that x0 = 0 and the control points
122 // are specified relative to their respective end points:
123 // c0 relative to x0, and c1 relative to x1
124 const float_type xd = x1 - x0;
125 return x0 + (s * 3 * (c0.x - x0) //
126 + s * s * 3 * (x0 - 2 * c0.x + (x1 + c1.x)) //
127 + s * s * s * (-x0 + 3 * c0.x - 3 * (x1 + c1.x) + x1));
128
129 // Generic curve
130 // return x0 //
131 // + s * 3 * (x1 - x0) //
132 // + s * s * 3 * (x0 - 2 * x1 + c0.x) //
133 // + s * s * s * (-x0 + 3 * x1 - 3 * c0.x + c1.x);
134 }
135 return x0;
136 }
137 private:
138 control_point c0{};
139 control_point c1{};
140
141 float_type As, Bs, Cs;
142 };
143 }
144} // namespace cydui
bezier(control_point c0_, control_point c1_)
float_type interpolate(float_type x0, float_type x1, float_type t) const override
float_type interpolate(float_type x0, float_type x1, float_type t) const override
easing(function_type fun)
cydui::easing::function_type function_type
float_type interpolate(float_type x0, float_type x1, float_type t) const override
std::shared_ptr< interpolator_base > sptr
virtual ~interpolator_base()=default
virtual float_type interpolate(float_type x0, float_type x1, float_type t) const =0
std::optional< float > find_root(std::function< float(float)> fun, float x0, float x1)
bool fuzzy_eq(const float a, const float b)
#define FLOAT_TOLERANCE
bool is_zero(float a)
std::function< float_type(const float_type &)> function_type