OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
curve.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <ossia/detail/config.hpp>
4
5#include <ossia/detail/flat_map.hpp>
6#include <ossia/detail/optional.hpp>
11#include <ossia/network/base/node.hpp>
12#include <ossia/network/base/parameter.hpp>
14#include <ossia/network/value/value.hpp>
15
16#include <functional>
17#include <memory>
18#include <utility>
19#include <vector>
20
24
25namespace ossia
26{
27class destination;
28
29template <typename T>
30static constexpr auto curve_segment_type_map()
31{
32 if constexpr(std::is_same_v<T, int>)
33 return ossia::curve_segment_type::INT;
34 else if constexpr(std::is_same_v<T, int64_t>)
35 return ossia::curve_segment_type::INT64;
36 else if constexpr(std::is_same_v<T, float>)
37 return ossia::curve_segment_type::FLOAT;
38 else if constexpr(std::is_same_v<T, double>)
39 return ossia::curve_segment_type::DOUBLE;
40 else if constexpr(std::is_same_v<T, bool>)
41 return ossia::curve_segment_type::BOOL;
42 else if constexpr(std::is_same_v<T, ossia::value>)
43 return ossia::curve_segment_type::ANY;
44 else
45 return nullptr;
46}
47
48template <typename K, typename V>
49using curve_map = ossia::flat_map<K, V>;
50
51template <typename X, typename Y>
58class OSSIA_TEST_EXPORT curve final : public curve_abstract
59{
60public:
61 using abscissa_type = X;
62 using ordinate_type = Y;
63 using curve_type = curve<X, Y>;
64 using map_type = curve_map<X, std::pair<Y, ossia::curve_segment<Y>>>;
65
66 curve() = default;
67 curve(const curve& other)
68 {
69 m_x0 = other.m_x0;
70 m_y0 = other.m_y0;
71 m_y0_destination = other.m_y0_destination;
72
73 m_points = other.m_points;
74
75 m_y0_cacheUsed = false;
76 }
77
78 curve(curve&& other) noexcept
79 {
80 m_x0 = other.m_x0;
81 m_y0 = other.m_y0;
82 m_y0_destination = std::move(other.m_y0_destination);
83
84 m_points = std::move(other.m_points);
85
86 m_y0_cacheUsed = false;
87 }
88
89 curve& operator=(const curve& other)
90 {
91 m_x0 = other.m_x0;
92 m_y0 = other.m_y0;
93 m_y0_destination = other.m_y0_destination;
94
95 m_points = other.m_points;
96
97 m_y0_cacheUsed = false;
98 return *this;
99 }
100 curve& operator=(curve&& other) noexcept
101 {
102 m_x0 = other.m_x0;
103 m_y0 = other.m_y0;
104 m_y0_destination = std::move(other.m_y0_destination);
105
106 m_points = std::move(other.m_points);
107
108 m_y0_cacheUsed = false;
109 return *this;
110 }
112 virtual ~curve() = default;
113
114 void reset() override;
115
121 bool add_point(ossia::curve_segment<Y>&& segment, X abscissa, Y value);
122
126 bool remove_point(X abscissa);
127
131 Y value_at(X abscissa) const;
132
133 ossia::curve_type get_type() const override;
134
139 X get_x0() const;
140
145 Y get_y0() const;
146
150 void set_x0(X value);
151
155 void set_y0(Y value);
156
159 std::optional<destination> get_y0_destination() const;
160
163 void set_y0_destination(const ossia::destination& destination);
164
169 map_type get_points() const;
170
171 static Y convert_to_template_type_value(
172 const ossia::value& value, ossia::destination_index::const_iterator idx);
173
174 void reserve(std::size_t count) { m_points.reserve(count); }
175
176private:
177 mutable X m_x0;
178 mutable Y m_y0;
179 mutable std::optional<ossia::destination> m_y0_destination;
180
181 mutable map_type m_points;
182
183 mutable Y m_y0_cache;
184
185 mutable bool m_y0_cacheUsed = false;
186};
187
188template <typename X, typename Y>
190{
191 m_y0_cacheUsed = false;
192}
193
194template <typename X, typename Y>
195inline bool
196curve<X, Y>::add_point(ossia::curve_segment<Y>&& segment, X abscissa, Y value)
197{
198 // Curves are built in increasing abscissa: the hint makes that O(1).
199 m_points.emplace_hint(
200 m_points.end(), abscissa, std::make_pair(value, std::move(segment)));
201
202 return true;
203}
204
205template <typename X, typename Y>
206inline bool curve<X, Y>::remove_point(X abscissa)
207{
208 return m_points.erase(abscissa) > 0;
209}
210
211template <typename X, typename Y>
212inline Y curve<X, Y>::value_at(X abscissa) const
213{
214 // Runs on the audio thread on every tick.
215 const X x0 = get_x0();
216 // Always read: with a destination, the first call captures the start value.
217 const Y y0 = get_y0();
218 if(!(abscissa > x0))
219 return y0;
220
221 // The first point at or after abscissa, and the one before it.
222 auto it = m_points.lower_bound(abscissa);
223 if(it == m_points.end())
224 return m_points.empty() ? y0 : std::prev(it)->second.first;
225
226 X lastAbscissa = x0;
227 Y lastValue = y0;
228 if(it != m_points.begin())
229 {
230 auto prev = std::prev(it);
231 if(prev->first >= x0)
232 {
233 lastAbscissa = prev->first;
234 lastValue = prev->second.first;
235 }
236 }
237
238 return it->second.second(
239 ((double)abscissa - (double)lastAbscissa)
240 / ((double)it->first - (double)lastAbscissa),
241 lastValue, it->second.first);
242}
243
244template <typename X, typename Y>
245inline curve_type curve<X, Y>::get_type() const
246{
247 static constexpr auto type
248 = std::make_pair(curve_segment_type_map<X>(), curve_segment_type_map<Y>());
249 return type;
250}
251
252template <typename X, typename Y>
253inline X curve<X, Y>::get_x0() const
254{
255 return m_x0;
256}
257
258template <typename X, typename Y>
259inline Y curve<X, Y>::get_y0() const
260{
261 if(!m_y0_destination)
262 return m_y0;
263 else
264 {
265 if(m_y0_cacheUsed)
266 return m_y0_cache;
267
268 const destination& dest = *m_y0_destination;
269 m_y0_cacheUsed = true;
270 m_y0_cache = convert_to_template_type_value(
271 dest.address().fetch_value(), dest.index.begin());
272
273 return m_y0_cache;
274 }
275}
276
277template <typename X, typename Y>
279{
280 m_x0 = value;
281}
282
283template <typename X, typename Y>
285{
286 m_y0 = value;
287}
288
289template <typename X, typename Y>
290inline std::optional<destination> curve<X, Y>::get_y0_destination() const
291{
292 return m_y0_destination;
293}
294
295template <typename X, typename Y>
296inline void curve<X, Y>::set_y0_destination(const destination& destination)
297{
298 m_y0_destination = destination;
299}
300
301template <typename X, typename Y>
302inline typename curve<X, Y>::map_type curve<X, Y>::get_points() const
303{
304 return m_points;
305}
306
307template <typename X, typename Y>
308inline Y curve<X, Y>::convert_to_template_type_value(
309 const value& v, ossia::destination_index::const_iterator idx)
310{
311 using namespace ossia;
312 using namespace std;
313 struct visitor
314 {
315 destination_index::const_iterator index;
316 Y operator()(int32_t i) const { return i; }
317 Y operator()(float f) const { return f; }
318 Y operator()(bool b) const { return b; }
319 Y operator()(char c) const { return c; }
320 Y operator()(vec2f vec) const { return vec[*index]; }
321 Y operator()(vec3f vec) const { return vec[*index]; }
322 Y operator()(vec4f vec) const { return vec[*index]; }
323 Y operator()(const std::vector<ossia::value>& t) const
324 {
325 auto& val = t[*index];
326 return convert_to_template_type_value(val, index + 1);
327 }
328 Y operator()(const value_map_type& t) const
329 {
330#if defined(__cpp_exceptions)
331 throw invalid_value_type_error(
332 "curve_impl::convertToTemplateTypeValue: "
333 "Cannot convert Map to a numeric type");
334#endif
335 return {};
336 }
337
338 Y operator()(impulse) const
339 {
340#if defined(__cpp_exceptions)
341 throw invalid_value_type_error(
342 "curve_impl::convertToTemplateTypeValue: "
343 "Cannot convert Impulse to a numeric type");
344#endif
345 return {};
346 }
347 Y operator()(const std::string& str) const
348 {
349#if defined(__cpp_exceptions)
350 throw invalid_value_type_error(
351 "curve_impl::convertToTemplateTypeValue: "
352 "Cannot convert String to a numeric type");
353#endif
354 return {};
355 }
356 Y operator()() const
357 {
358#if defined(__cpp_exceptions)
359 throw invalid_value_type_error(
360 "curve_impl::convertToTemplateTypeValue: "
361 "No type provided");
362#endif
363 return {};
364 }
365 } vis{idx};
366
367 return v.apply(vis);
368}
369
381class OSSIA_EXPORT constant_curve final : public curve_abstract
382{
383public:
384 constant_curve(ossia::value v)
385 : mValue{std::move(v)}
386 {
387 }
388 ~constant_curve() override;
389 constant_curve() = default;
390 constant_curve(const constant_curve&) = delete;
391 constant_curve(constant_curve&&) = delete;
392 constant_curve& operator=(const constant_curve&) = delete;
393 constant_curve& operator=(constant_curve&&) = delete;
394
395 [[nodiscard]] ossia::value value() const { return mValue; }
396
397 [[nodiscard]] curve_type get_type() const override
398 {
399 return std::make_pair(
400 ossia::curve_segment_type::DOUBLE, ossia::curve_segment_type::ANY);
401 }
402
403 void reset() override { }
404
405private:
406 const ossia::value mValue;
407};
408}
void reset() override
Clear internal data structures of the curve.
Definition curve.hpp:403
curve_type get_type() const override
get the type of both coordinates
Definition curve.hpp:397
The curve_abstract class.
Definition curve_abstract.hpp:42
X get_x0() const
get initial point abscissa
Definition curve.hpp:253
void reset() override
Clear internal data structures of the curve.
Definition curve.hpp:189
bool remove_point(X abscissa)
remove a point from the curve
Definition curve.hpp:206
void set_x0(X value)
set initial point abscissa
Definition curve.hpp:278
bool add_point(ossia::curve_segment< Y > &&segment, X abscissa, Y value)
add a segment to reach a target point to the curve
Definition curve.hpp:196
std::optional< destination > get_y0_destination() const
get initial point ordinate destination
Definition curve.hpp:290
map_type get_points() const
get points of the curve
Definition curve.hpp:302
Y value_at(X abscissa) const
get value at an abscissa
Definition curve.hpp:212
void set_y0(Y value)
set initial point ordinate
Definition curve.hpp:284
ossia::curve_type get_type() const override
get the type of both coordinates
Definition curve.hpp:245
virtual ~curve()=default
destructor
void set_y0_destination(const ossia::destination &destination)
set initial curve ordinate using a Destination
Definition curve.hpp:296
Y get_y0() const
get initial point ordinate
Definition curve.hpp:259
ossia::value fetch_value()
Pulls and clone the value.
Definition ossia/network/base/parameter.cpp:61
The value class.
Definition value.hpp:173
Definition git_info.h:7