OSSIA
Open Scenario System for Interactive Application
curve_value_visitor.hpp
1 #pragma once
2 #include <ossia/detail/small_vector.hpp>
4 #include <ossia/editor/curve/curve.hpp>
5 #include <ossia/network/value/value.hpp>
6 namespace ossia::detail
7 {
8 
9 using vec_behavior = ossia::static_vector<curve<double, float>*, 4>;
10 static vec_behavior list_convertible_to_vec(const std::vector<ossia::behavior>& t)
11 {
12  const auto n = t.size();
13 
14  vec_behavior arr;
15  bool ok = false;
16  if(n >= 2 && n <= 4)
17  {
18  for(const ossia::behavior& v : t)
19  {
20  auto target = v.target<std::shared_ptr<ossia::curve_abstract>>();
21  if(!target)
22  return {};
23 
24  ossia::curve_abstract* c = target->get();
25  if(!c)
26  return {};
27 
28  auto t = c->get_type();
29  if(t.first == ossia::curve_segment_type::DOUBLE
30  && t.second == ossia::curve_segment_type::FLOAT)
31  {
32  arr.push_back(static_cast<ossia::curve<double, float>*>(c));
33  ok = true;
34  continue;
35  }
36  else
37  {
38  ok = false;
39  break;
40  }
41  }
42 
43  if(ok)
44  return arr;
45  else
46  return {};
47  }
48  return {};
49 }
50 
51 template <int N>
52 ossia::value make_filled_vec(
53  ossia::curve_abstract* base_curve, ossia::curve_segment_type t, double position)
54 {
55  switch(t)
56  {
57  case ossia::curve_segment_type::FLOAT: {
58  auto c = static_cast<curve<double, float>*>(base_curve);
59  return fill_vec<N>(float(c->value_at(position)));
60  }
61  case ossia::curve_segment_type::INT: {
62  auto c = static_cast<curve<double, int>*>(base_curve);
63  return fill_vec<N>(int(c->value_at(position)));
64  }
65  case ossia::curve_segment_type::BOOL: {
66  auto c = static_cast<curve<double, bool>*>(base_curve);
67  return fill_vec<N>(bool(c->value_at(position)));
68  }
69  case ossia::curve_segment_type::DOUBLE:
70  case ossia::curve_segment_type::INT64:
71  case ossia::curve_segment_type::ANY:
72  break;
73  }
74 
75  return {};
76 }
77 
78 struct compute_value_uninformed_visitor
79 {
80  double position;
81 
82  [[nodiscard]] ossia::value error() const
83  {
84  throw invalid_value_type_error(
85  "computeValue_visitor: "
86  "Unhandled drive value type.");
87  return {};
88  }
89 
90  template <typename T>
91  ossia::value operator()(const T&) const
92  {
93  return error();
94  }
95 
96  ossia::value operator()() const { return error(); }
97 
98  ossia::value operator()(const curve_ptr& c) const
99  {
100  auto base_curve = c.get();
101  if(!base_curve)
102  {
103  throw invalid_value_type_error(
104  "computeValue_visitor: "
105  "invalid Behavior");
106  return {};
107  }
108 
109  auto t = base_curve->get_type();
110  switch(t.second)
111  {
112  case ossia::curve_segment_type::FLOAT:
113  return float{static_cast<curve<double, float>*>(base_curve)->value_at(position)};
114  case ossia::curve_segment_type::INT:
115  return int32_t{static_cast<curve<double, int>*>(base_curve)->value_at(position)};
116  case ossia::curve_segment_type::BOOL:
117  return bool{static_cast<curve<double, bool>*>(base_curve)->value_at(position)};
118  case ossia::curve_segment_type::DOUBLE:
119  break;
120  case ossia::curve_segment_type::INT64:
121  break;
122  case ossia::curve_segment_type::ANY:
123  // TODO we need a specific handling for destination.
124  return static_cast<constant_curve*>(base_curve)->value();
125  }
126 
127  throw invalid_value_type_error(
128  "computeValue_visitor: "
129  "drive curve type is not DOUBLE");
130  return {};
131  }
132 
133  ossia::value operator()(const std::vector<ossia::behavior>& b)
134  {
135  vec_behavior arr = list_convertible_to_vec(b);
136 
137  // VecNf case.
138  switch(arr.size())
139  {
140  case 2:
141  return ossia::make_vec(arr[0]->value_at(position), arr[1]->value_at(position));
142  case 3:
143  return ossia::make_vec(
144  arr[0]->value_at(position), arr[1]->value_at(position),
145  arr[2]->value_at(position));
146  case 4:
147  return ossia::make_vec(
148  arr[0]->value_at(position), arr[1]->value_at(position),
149  arr[2]->value_at(position), arr[3]->value_at(position));
150  default:
151  break;
152  }
153 
154  // General list case
155  std::vector<ossia::value> t;
156  t.reserve(b.size());
157 
158  for(const auto& e : b)
159  {
160  if(e)
161  t.push_back(ossia::apply_nonnull(*this, e));
162  else
163  return {};
164  }
165 
166  return t;
167  }
168 };
169 
170 struct compute_value_visitor
171 {
172  double position;
173  ossia::val_type driven_type;
174 
175  [[nodiscard]] ossia::value error() const
176  {
177  throw invalid_value_type_error(
178  "computeValue_visitor: "
179  "Unhandled drive value type.");
180  return {};
181  }
182 
183  template <typename T>
184  ossia::value operator()(const T&) const
185  {
186  return error();
187  }
188 
189  ossia::value operator()() const { return error(); }
190 
191  ossia::value operator()(const curve_ptr& c) const
192  {
193  auto base_curve = c.get();
194  if(!base_curve)
195  {
196  throw invalid_value_type_error(
197  "computeValue_visitor: "
198  "invalid Behavior");
199  return {};
200  }
201 
202  auto t = base_curve->get_type();
203  if(t.first == ossia::curve_segment_type::DOUBLE)
204  {
205  switch(driven_type)
206  {
207  case ossia::val_type::FLOAT:
209  case ossia::val_type::BOOL: {
210  switch(t.second)
211  {
212  case ossia::curve_segment_type::FLOAT:
213  return float{
214  static_cast<curve<double, float>*>(base_curve)->value_at(position)};
215  case ossia::curve_segment_type::INT:
216  return int32_t{
217  static_cast<curve<double, int>*>(base_curve)->value_at(position)};
218  case ossia::curve_segment_type::BOOL:
219  return bool{
220  static_cast<curve<double, bool>*>(base_curve)->value_at(position)};
221  case ossia::curve_segment_type::DOUBLE:
222  break;
223  case ossia::curve_segment_type::INT64:
224  break;
225  case ossia::curve_segment_type::ANY:
226  // TODO we need a specific handling for destination.
227  return static_cast<constant_curve*>(base_curve)->value();
228  }
229  break;
230  }
232  return make_filled_vec<2>(base_curve, t.second, position);
234  return make_filled_vec<3>(base_curve, t.second, position);
236  return make_filled_vec<4>(base_curve, t.second, position);
237  case ossia::val_type::LIST: {
238  return {}; // TODO
239  }
240 
241  default:
242  break;
243  }
244  }
245 
246  throw invalid_value_type_error(
247  "computeValue_visitor: "
248  "drive curve type is not DOUBLE");
249  return {};
250  }
251 
252  ossia::value operator()(const std::vector<ossia::behavior>& b)
253  {
254  vec_behavior arr = list_convertible_to_vec(b);
255 
256  // VecNf case.
257  switch(arr.size())
258  {
259  case 2:
260  return ossia::make_vec(arr[0]->value_at(position), arr[1]->value_at(position));
261  case 3:
262  return ossia::make_vec(
263  arr[0]->value_at(position), arr[1]->value_at(position),
264  arr[2]->value_at(position));
265  case 4:
266  return ossia::make_vec(
267  arr[0]->value_at(position), arr[1]->value_at(position),
268  arr[2]->value_at(position), arr[3]->value_at(position));
269  default:
270  break;
271  }
272 
273  // General list case
274  std::vector<ossia::value> t;
275  t.reserve(b.size());
276 
277  for(const auto& e : b)
278  {
279  if(e)
280  t.push_back(ossia::apply_nonnull(compute_value_uninformed_visitor{position}, e));
281  else
282  return {};
283  }
284 
285  return t;
286  }
287 };
288 }
The curve_abstract class.
Definition: curve_abstract.hpp:42
virtual curve_type get_type() const =0
get the type of both coordinates
The value class.
Definition: value.hpp:173
Definition: transitive_closure.hpp:27
val_type
Enum to represent the types that a value can take.
Definition: parameter_properties.hpp:16
@ VEC3F
array<float, 2>
@ LIST
std::string
@ VEC4F
array<float, 3>
@ BOOL
ossia::impulse
curve_segment_type
The curve_segment_type enum.
Definition: curve_abstract.hpp:18