OSSIA
Open Scenario System for Interactive Application
curve.hpp
1 #pragma once
2 
3 #include <ossia/detail/config.hpp>
4 
5 #if defined(__cpp_exceptions)
6 #include <ossia/detail/flat_map.hpp>
7 #include <ossia/detail/optional.hpp>
12 #include <ossia/network/base/node.hpp>
13 #include <ossia/network/base/parameter.hpp>
15 #include <ossia/network/value/value.hpp>
16 
17 #include <functional>
18 #include <memory>
19 #include <utility>
20 #include <vector>
21 
26 namespace ossia
27 {
28 class destination;
29 
30 // TODO still broken in clang-11...
31 #if defined(__clang__)
32 #define CLANG_BUGGY_STATIC_VARIABLE_TEMPLATE static
33 #else
34 #define CLANG_BUGGY_STATIC_VARIABLE_TEMPLATE
35 #endif
36 template <typename T>
37 static const constexpr std::nullptr_t curve_segment_type_map = nullptr;
38 template <>
39 CLANG_BUGGY_STATIC_VARIABLE_TEMPLATE const constexpr ossia::curve_segment_type
40  curve_segment_type_map<int>
41  = ossia::curve_segment_type::INT;
42 template <>
43 CLANG_BUGGY_STATIC_VARIABLE_TEMPLATE const constexpr ossia::curve_segment_type
44  curve_segment_type_map<int64_t>
45  = ossia::curve_segment_type::INT64;
46 template <>
47 CLANG_BUGGY_STATIC_VARIABLE_TEMPLATE const constexpr ossia::curve_segment_type
48  curve_segment_type_map<float>
49  = ossia::curve_segment_type::FLOAT;
50 template <>
51 CLANG_BUGGY_STATIC_VARIABLE_TEMPLATE const constexpr ossia::curve_segment_type
52  curve_segment_type_map<double>
53  = ossia::curve_segment_type::DOUBLE;
54 template <>
55 CLANG_BUGGY_STATIC_VARIABLE_TEMPLATE const constexpr ossia::curve_segment_type
56  curve_segment_type_map<bool>
57  = ossia::curve_segment_type::BOOL;
58 template <>
59 CLANG_BUGGY_STATIC_VARIABLE_TEMPLATE const constexpr ossia::curve_segment_type
60  curve_segment_type_map<ossia::value>
61  = ossia::curve_segment_type::ANY;
62 
63 template <typename K, typename V>
64 using curve_map = ossia::flat_map<K, V>;
65 
66 template <typename X, typename Y>
73 class curve final : public curve_abstract
74 {
75 public:
76  using abscissa_type = X;
77  using ordinate_type = Y;
78  using curve_type = curve<X, Y>;
79  using map_type = curve_map<X, std::pair<Y, ossia::curve_segment<Y>>>;
80 
81  curve() = default;
82  curve(const curve& other)
83  {
84  m_x0 = other.m_x0;
85  m_y0 = other.m_y0;
86  m_y0_destination = other.m_y0_destination;
87 
88  m_points = other.m_points;
89 
90  m_y0_cacheUsed = false;
91  }
92 
93  curve(curve&& other) noexcept
94  {
95  m_x0 = other.m_x0;
96  m_y0 = other.m_y0;
97  m_y0_destination = std::move(other.m_y0_destination);
98 
99  m_points = std::move(other.m_points);
100 
101  m_y0_cacheUsed = false;
102  }
103 
104  curve& operator=(const curve& other)
105  {
106  m_x0 = other.m_x0;
107  m_y0 = other.m_y0;
108  m_y0_destination = other.m_y0_destination;
109 
110  m_points = other.m_points;
111 
112  m_y0_cacheUsed = false;
113  return *this;
114  }
115  curve& operator=(curve&& other) noexcept
116  {
117  m_x0 = other.m_x0;
118  m_y0 = other.m_y0;
119  m_y0_destination = std::move(other.m_y0_destination);
120 
121  m_points = std::move(other.m_points);
122 
123  m_y0_cacheUsed = false;
124  return *this;
125  }
127  virtual ~curve() = default;
128 
129  void reset() override;
130 
136  bool add_point(ossia::curve_segment<Y>&& segment, X abscissa, Y value);
137 
141  bool remove_point(X abscissa);
142 
146  Y value_at(X abscissa) const;
147 
148  ossia::curve_type get_type() const override;
149 
154  X get_x0() const;
155 
160  Y get_y0() const;
161 
165  void set_x0(X value);
166 
170  void set_y0(Y value);
171 
174  std::optional<destination> get_y0_destination() const;
175 
178  void set_y0_destination(const ossia::destination& destination);
179 
184  map_type get_points() const;
185 
186  static Y convert_to_template_type_value(
187  const ossia::value& value, ossia::destination_index::const_iterator idx);
188 
189  void reserve(std::size_t count) { m_points.reserve(count); }
190 
191 private:
192  mutable X m_x0;
193  mutable Y m_y0;
194  mutable std::optional<ossia::destination> m_y0_destination;
195 
196  mutable map_type m_points;
197 
198  mutable Y m_y0_cache;
199 
200  mutable bool m_y0_cacheUsed = false;
201 };
202 
203 template <typename X, typename Y>
204 inline void curve<X, Y>::reset()
205 {
206  m_y0_cacheUsed = false;
207 }
208 
209 template <typename X, typename Y>
210 inline bool
211 curve<X, Y>::add_point(ossia::curve_segment<Y>&& segment, X abscissa, Y value)
212 {
213  m_points.emplace(abscissa, std::make_pair(value, std::move(segment)));
214 
215  return true;
216 }
217 
218 template <typename X, typename Y>
219 inline bool curve<X, Y>::remove_point(X abscissa)
220 {
221  return m_points.erase(abscissa) > 0;
222 }
223 
224 template <typename X, typename Y>
225 inline Y curve<X, Y>::value_at(X abscissa) const
226 {
227  X lastAbscissa = get_x0();
228  Y lastValue = get_y0();
229 
230  auto end = m_points.end();
231  for(auto it = m_points.begin(); it != end; ++it)
232  {
233  if(abscissa > lastAbscissa && abscissa <= it->first)
234  {
235  lastValue = it->second.second(
236  ((double)abscissa - (double)lastAbscissa)
237  / ((double)it->first - (double)lastAbscissa),
238  lastValue, it->second.first);
239  break;
240  }
241  else if(abscissa > it->first)
242  {
243  lastAbscissa = it->first;
244  lastValue = it->second.first;
245  }
246  else
247  break;
248  }
249 
250  return lastValue;
251 }
252 
253 template <typename X, typename Y>
254 inline curve_type curve<X, Y>::get_type() const
255 {
256  return std::make_pair(curve_segment_type_map<X>, curve_segment_type_map<Y>);
257 }
258 
259 template <typename X, typename Y>
260 inline X curve<X, Y>::get_x0() const
261 {
262  return m_x0;
263 }
264 
265 template <typename X, typename Y>
266 inline Y curve<X, Y>::get_y0() const
267 {
268  if(!m_y0_destination)
269  return m_y0;
270  else
271  {
272  if(m_y0_cacheUsed)
273  return m_y0_cache;
274 
275  const destination& dest = *m_y0_destination;
276  m_y0_cacheUsed = true;
277  m_y0_cache = convert_to_template_type_value(
278  dest.address().fetch_value(), dest.index.begin());
279 
280  return m_y0_cache;
281  }
282 }
283 
284 template <typename X, typename Y>
285 inline void curve<X, Y>::set_x0(X value)
286 {
287  m_x0 = value;
288 }
289 
290 template <typename X, typename Y>
291 inline void curve<X, Y>::set_y0(Y value)
292 {
293  m_y0 = value;
294 }
295 
296 template <typename X, typename Y>
297 inline std::optional<destination> curve<X, Y>::get_y0_destination() const
298 {
299  return m_y0_destination;
300 }
301 
302 template <typename X, typename Y>
303 inline void curve<X, Y>::set_y0_destination(const destination& destination)
304 {
305  m_y0_destination = destination;
306 }
307 
308 template <typename X, typename Y>
309 inline typename curve<X, Y>::map_type curve<X, Y>::get_points() const
310 {
311  return m_points;
312 }
313 
314 template <typename X, typename Y>
315 inline Y curve<X, Y>::convert_to_template_type_value(
316  const value& v, ossia::destination_index::const_iterator idx)
317 {
318  using namespace ossia;
319  using namespace std;
320  struct visitor
321  {
322  destination_index::const_iterator index;
323  Y operator()(int32_t i) const { return i; }
324  Y operator()(float f) const { return f; }
325  Y operator()(bool b) const { return b; }
326  Y operator()(char c) const { return c; }
327  Y operator()(vec2f vec) const { return vec[*index]; }
328  Y operator()(vec3f vec) const { return vec[*index]; }
329  Y operator()(vec4f vec) const { return vec[*index]; }
330  Y operator()(const std::vector<ossia::value>& t) const
331  {
332  auto& val = t[*index];
333  return convert_to_template_type_value(val, index + 1);
334  }
335  Y operator()(const value_map_type& t) const
336  {
338  "curve_impl::convertToTemplateTypeValue: "
339  "Cannot convert Map to a numeric type");
340  return {};
341  }
342 
343  Y operator()(impulse) const
344  {
346  "curve_impl::convertToTemplateTypeValue: "
347  "Cannot convert Impulse to a numeric type");
348  return {};
349  }
350  Y operator()(const std::string& str) const
351  {
353  "curve_impl::convertToTemplateTypeValue: "
354  "Cannot convert String to a numeric type");
355  return {};
356  }
357  Y operator()() const
358  {
360  "curve_impl::convertToTemplateTypeValue: "
361  "No type provided");
362  return {};
363  }
364  } vis{idx};
365 
366  return v.apply(vis);
367 }
368 
380 class OSSIA_EXPORT constant_curve final : public curve_abstract
381 {
382 public:
383  constant_curve(ossia::value v)
384  : mValue{std::move(v)}
385  {
386  }
387  ~constant_curve() override;
388  constant_curve() = default;
389  constant_curve(const constant_curve&) = delete;
390  constant_curve(constant_curve&&) = delete;
391  constant_curve& operator=(const constant_curve&) = delete;
392  constant_curve& operator=(constant_curve&&) = delete;
393 
394  [[nodiscard]] ossia::value value() const { return mValue; }
395 
396  [[nodiscard]] curve_type get_type() const override
397  {
398  return std::make_pair(
399  ossia::curve_segment_type::DOUBLE, ossia::curve_segment_type::ANY);
400  }
401 
402  void reset() override { }
403 
404 private:
405  const ossia::value mValue;
406 };
407 }
408 
409 #endif
The curve_abstract class.
Definition: curve_abstract.hpp:42
The value class.
Definition: value.hpp:173
Definition: git_info.h:7
curve_segment_type
The curve_segment_type enum.
Definition: curve_abstract.hpp:18
The invalid_value_type_error class.
Definition: network/exceptions.hpp:87