Vital
Loading...
Searching...
No Matches
line_generator.cpp
Go to the documentation of this file.
1#include "line_generator.h"
2#include "poly_utils.h"
3#include "futils.h"
4
5LineGenerator::LineGenerator(int resolution) : points_(), powers_(), num_points_(2), resolution_(resolution),
6 loop_(false), smooth_(false), linear_(true), render_count_(0) {
7 buffer_ = std::make_unique<vital::mono_float[]>(resolution + kExtraValues);
9}
10
12 points_[0] = { 0.0f, 1.0f };
13 points_[1] = { 1.0f, 0.0f };
14 powers_[0] = 0.0f;
15 powers_[1] = 0.0f;
16 num_points_ = 2;
17 linear_ = true;
18 name_ = "Linear";
19 smooth_ = false;
20 render();
21}
22
24 points_[0] = { 0.0f, 1.0f };
25 points_[1] = { 0.5f, 0.0f };
26 points_[2] = { 1.0f, 1.0f };
27 powers_[0] = 0.0f;
28 powers_[1] = 0.0f;
29 powers_[2] = 0.0f;
30 num_points_ = 3;
31 linear_ = false;
32 name_ = "Triangle";
33 smooth_ = false;
34 render();
35}
36
38 num_points_ = 5;
39 points_[0] = { 0.0f, 1.0f };
40 points_[1] = { 0.0f, 0.0f };
41 points_[2] = { 0.5f, 0.0f };
42 points_[3] = { 0.5f, 1.0f };
43 points_[4] = { 1.0f, 1.0f };
44
45 for (int i = 0; i < num_points_; ++i)
46 powers_[i] = 0.0f;
47
48 linear_ = false;
49 name_ = "Square";
50 smooth_ = false;
51 render();
52}
53
55 points_[0] = { 0.0f, 1.0f };
56 points_[1] = { 0.5f, 0.0f };
57 points_[2] = { 1.0f, 1.0f };
58 powers_[0] = 0.0f;
59 powers_[1] = 0.0f;
60 powers_[2] = 0.0f;
61 num_points_ = 3;
62 linear_ = false;
63 name_ = "Sin";
64 smooth_ = true;
65 render();
66}
67
69 num_points_ = 3;
70 points_[0] = { 0.0f, 1.0f };
71 points_[1] = { 1.0f, 0.0f };
72 points_[2] = { 1.0f, 1.0f };
73 powers_[0] = 0.0f;
74 powers_[1] = 0.0f;
75 powers_[2] = 0.0f;
76 linear_ = false;
77 name_ = "Saw Up";
78 smooth_ = false;
79 render();
80}
81
83 num_points_ = 3;
84 points_[0] = { 0.0f, 0.0f };
85 points_[1] = { 1.0f, 1.0f };
86 points_[2] = { 1.0f, 0.0f };
87 powers_[0] = 0.0f;
88 powers_[1] = 0.0f;
89 powers_[2] = 0.0f;
90 linear_ = false;
91 name_ = "Saw Down";
92 smooth_ = false;
93 render();
94}
95
97 json point_data;
98 json power_data;
99
100 for (int i = 0; i < num_points_; ++i) {
101 std::pair<float, float> point = points_[i];
102 point_data.push_back(point.first);
103 point_data.push_back(point.second);
104 power_data.push_back(powers_[i]);
105 }
106
107 json data;
108 data["num_points"] = num_points_;
109 data["points"] = point_data;
110 data["powers"] = power_data;
111 data["name"] = name_;
112 data["smooth"] = smooth_;
113 return data;
114}
115
117 if (!data.count("num_points") || !data.count("points") || !data.count("powers"))
118 return false;
119
120 json point_data = data["points"];
121 json power_data = data["powers"];
122 return point_data.is_array() && power_data.is_array();
123}
124
126 num_points_ = data["num_points"];
127 json point_data = data["points"];
128 json power_data = data["powers"];
129 name_ = "";
130 if (data.count("name"))
131 name_ = data["name"].get<std::string>();
132
133 smooth_ = false;
134 if (data.count("smooth"))
135 smooth_ = data["smooth"];
136
137 int num_read = kMaxPoints;
138 num_read = std::min(num_read, static_cast<int>(power_data.size()));
139
140 for (int i = 0; i < num_read; ++i) {
141 points_[i] = std::pair<float, float>(point_data[2 * i], point_data[2 * i + 1]);
142 powers_[i] = power_data[i];
143 }
144
146 render();
147}
148
151
152 int point_index = 0;
153 std::pair<float, float> last_point = points_[point_index];
154 float current_power = 0.0f;
155 std::pair<float, float> current_point = points_[point_index];
156 if (loop_) {
157 last_point = points_[num_points_ - 1];
158 last_point.first -= 1.0f;
159 current_power = powers_[num_points_ - 1];
160 }
161 for (int i = 0; i < resolution_; ++i) {
162 float x = i / (resolution_ - 1.0f);
163 float t = 1.0f;
164 if (current_point.first > last_point.first)
165 t = (x - last_point.first) / (current_point.first - last_point.first);
166
167 if (smooth_)
168 t = smoothTransition(t);
169
170 t = vital::utils::clamp(vital::futils::powerScale(t, current_power), 0.0f, 1.0f);
171
172 float y = last_point.second + t * (current_point.second - last_point.second);
173 buffer_[i + 1] = 1.0f - y;
174
175 while (x > current_point.first && point_index < num_points_) {
176 current_power = powers_[point_index % num_points_];
177 point_index++;
178 last_point = current_point;
179 current_point = points_[point_index % num_points_];
180 if (point_index >= num_points_) {
181 current_point.first += 1.0f;
182 break;
183 }
184 }
185 }
186
187 if (loop_) {
189 buffer_[resolution_ + 1] = buffer_[1];
190 buffer_[resolution_ + 2] = buffer_[2];
191 }
192 else {
193 buffer_[0] = buffer_[1];
196 }
197}
198
199float LineGenerator::valueAtPhase(float phase) {
200 float scaled_phase = vital::utils::clamp(phase, 0.0f, 1.0f) * resolution_;
201 int index = scaled_phase;
202 return vital::utils::interpolate(buffer_[index + 1], buffer_[index + 2], scaled_phase - index);
203}
204
206 linear_ = !smooth_ && num_points_ == 2 && powers_[0] == 0.0f &&
207 points_[0] == std::pair<float, float>(0.0f, 1.0f) &&
208 points_[1] == std::pair<float, float>(1.0f, 0.0f);
209}
210
211float LineGenerator::getValueBetweenPoints(float x, int index_from, int index_to) {
212 VITAL_ASSERT(index_from >= 0 && index_to < num_points_);
213
214 std::pair<float, float> first = points_[index_from];
215 std::pair<float, float> second = points_[index_to];
216 float power = powers_[index_from];
217
218 float width = second.first - first.first;
219 if (width <= 0.0f)
220 return second.second;
221
222 float t = (x - first.first) / width;
223 if (smooth_)
224 t = smoothTransition(t);
225
226 t = vital::utils::clamp(vital::futils::powerScale(t, power), 0.0f, 1.0f);
227 return t * (second.second - first.second) + first.second;
228}
229
231 for (int i = 0; i < num_points_ - 1; ++i) {
232 if (points_[i].first <= phase && points_[i + 1].first >= phase)
233 return getValueBetweenPoints(phase, i, i + 1);
234 }
235
236 return lastPoint().second;
237}
238
239void LineGenerator::addPoint(int index, std::pair<float, float> position) {
240 for (int i = num_points_; i > index; --i) {
241 points_[i] = points_[i - 1];
242 powers_[i] = powers_[i - 1];
243 }
244
245 num_points_++;
246 points_[index] = position;
247 powers_[index] = 0.0f;
249}
250
252 VITAL_ASSERT(index > 0);
253
254 float x = (points_[index - 1].first + points_[index].first) * 0.5f;
255 float y = getValueBetweenPoints(x, index - 1, index);
256 addPoint(index, { x, y });
257}
258
260 num_points_--;
261 for (int i = index; i < num_points_; ++i) {
262 points_[i] = points_[i + 1];
263 powers_[i] = powers_[i + 1];
264 }
266}
267
269 for (int i = 0; i < (num_points_ + 1) / 2; ++i) {
270 float tmp_x = 1.0f - points_[i].first;
271 float tmp_y = points_[i].second;
272 points_[i].first = 1.0f - points_[num_points_ - i - 1].first;
273 points_[i].second = points_[num_points_ - i - 1].second;
274 points_[num_points_ - i - 1].first = tmp_x;
275 points_[num_points_ - i - 1].second = tmp_y;
276 }
277 for (int i = 0; i < num_points_ / 2; ++i) {
278 float tmp_power = powers_[i];
279 powers_[i] = -powers_[num_points_ - i - 2];
280 powers_[num_points_ - i - 2] = -tmp_power;
281 }
282 render();
284}
285
287 for (int i = 0; i < num_points_; ++i)
288 points_[i].second = 1.0f - points_[i].second;
289
290 render();
292}
std::string name_
The name of the line shape.
Definition line_generator.h:374
int render_count_
Count of how many times render() was called.
Definition line_generator.h:385
std::pair< float, float > lastPoint() const
Returns the last point in the line.
Definition line_generator.h:252
void initSin()
Initializes the line as a sine-like shape.
Definition line_generator.cpp:54
float valueAtPhase(float phase)
Gets the line value at a given normalized phase.
Definition line_generator.cpp:199
bool loop_
Whether the line loops at the end.
Definition line_generator.h:382
void render()
Renders the line into the internal buffer based on the current points and settings.
Definition line_generator.cpp:149
void checkLineIsLinear()
Checks if the line is the default linear shape.
Definition line_generator.cpp:205
LineGenerator(int resolution=kDefaultResolution)
Constructs a LineGenerator with a given resolution.
Definition line_generator.cpp:5
float powers_[kMaxPoints]
Powers controlling interpolation shape between points.
Definition line_generator.h:377
void addMiddlePoint(int index)
Inserts a point exactly between two existing points.
Definition line_generator.cpp:251
float getValueBetweenPoints(float x, int index_from, int index_to)
Interpolates a value between two points at a given x position.
Definition line_generator.cpp:211
int num_points_
Current number of points.
Definition line_generator.h:378
static bool isValidJson(json data)
Checks if a given JSON object contains valid line data.
Definition line_generator.cpp:116
void removePoint(int index)
Removes the point at a specified index.
Definition line_generator.cpp:259
void flipHorizontal()
Flips the line horizontally around the x=0.5 vertical axis.
Definition line_generator.cpp:268
void initTriangle()
Initializes the line as a triangle shape.
Definition line_generator.cpp:23
force_inline int resolution() const
Gets the resolution of the line's internal buffer.
Definition line_generator.h:266
std::pair< float, float > points_[kMaxPoints]
Array of points defining the line shape.
Definition line_generator.h:376
std::unique_ptr< vital::mono_float[]> buffer_
Internal buffer holding the rendered line values.
Definition line_generator.h:381
static force_inline float smoothTransition(float t)
Smooth transition function for smoothing between points.
Definition line_generator.h:49
float getValueAtPhase(float phase)
Returns the value of the line at a given phase by searching through the points.
Definition line_generator.cpp:230
void jsonToState(json data)
Restores the line state from a given JSON object.
Definition line_generator.cpp:125
void initSawDown()
Initializes the line as a "saw down" shape.
Definition line_generator.cpp:82
static constexpr int kMaxPoints
Maximum number of points that can define the line.
Definition line_generator.h:25
void initSquare()
Initializes the line as a square shape.
Definition line_generator.cpp:37
json stateToJson()
Converts the current state of the line into a JSON object.
Definition line_generator.cpp:96
void initLinear()
Initializes the line to a simple linear shape (from 1.0 at x=0 to 0.0 at x=1).
Definition line_generator.cpp:11
bool linear_
Whether the line is the simple linear shape.
Definition line_generator.h:384
bool smooth_
Whether to apply smoothing between points.
Definition line_generator.h:383
static constexpr int kExtraValues
Extra buffer values used for interpolation outside the main range.
Definition line_generator.h:39
void addPoint(int index, std::pair< float, float > position)
Inserts a new point into the line at a specified index.
Definition line_generator.cpp:239
void flipVertical()
Flips the line vertically around y=0.5.
Definition line_generator.cpp:286
void initSawUp()
Initializes the line as a "saw up" shape.
Definition line_generator.cpp:68
int resolution_
Resolution of the internal buffer.
Definition line_generator.h:379
#define VITAL_ASSERT(x)
Definition common.h:11
Contains faster but less accurate versions of utility math functions, such as exponential,...
nlohmann::json json
Definition line_generator.h:7
force_inline mono_float powerScale(mono_float value, mono_float power)
A power-scaling function to map a linear range to a curved response.
Definition futils.h:455
force_inline poly_float clamp(poly_float value, mono_float min, mono_float max)
Clamps each lane of a vector to [min, max].
Definition poly_utils.h:306
force_inline poly_float interpolate(poly_float from, poly_float to, mono_float t)
Performs a linear interpolation between two poly_floats using a scalar t in [0..1].
Definition poly_utils.h:182