libalmath  2.8.7.4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
qianim.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 Softbank Robotics. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the COPYING file.
5  */
6 
7 #ifndef LIBALMATH_ALMATH_SCENEGRAPH_QIANIM_H
8 #define LIBALMATH_ALMATH_SCENEGRAPH_QIANIM_H
9 
10 #include <almath/api.h>
12 #include <iterator>
13 #include <type_traits>
14 #include <boost/property_tree/ptree.hpp>
15 #include <boost/range/adaptor/map.hpp>
16 #include <boost/range/adaptor/filtered.hpp>
17 #include <functional>
18 
19 namespace AL {
20 namespace qianim {
21 
23 
24 template<class T>
25 using optional = boost::optional<T>;
26 
27 enum struct Side : bool {
28  left,
29  right
30 };
31 
32 namespace V2 {
33 
34 // Apply binary functor on each pair of adjacent iterators in the range
35 // [first, last).
36 template <typename InputIt, typename BinaryOperation>
37 BinaryOperation adjacent_for_each(InputIt first, InputIt last,
38  BinaryOperation binary_op) {
39  if (first == last)
40  return binary_op;
41  auto next = std::next(first);
42  while (next != last) {
43  binary_op(*first, *next);
44  first = next;
45  ++next;
46  }
47  return binary_op;
48 }
49 
50 namespace Tangent {
51 
52 // homogeneous to Key::frame()
53 // Note: this function does *not* check that the abscissa sign is consistent
54 // with the tangent side
55 template <typename T>
56 typename std::enable_if<std::is_floating_point<T>::value, T>::type
57 get_abscissa(const ptree &pt) {
58  return pt.get<T>("<xmlattr>.abscissaParam");
59 }
60 
61 // Note: this function does *not* check that the abscissa sign is consistent
62 // with the tangent side
63 template <typename T>
64 typename std::enable_if<std::is_floating_point<T>::value>::type
65 put_abscissa(ptree &pt, T abscissa) {
66  pt.put<T>("<xmlattr>.abscissaParam", abscissa);
67 }
68 
69 // homogeneous to Key::value()
70 template <typename T>
71 typename std::enable_if<std::is_floating_point<T>::value, T>::type
72 get_ordinate(const ptree &pt) {
73  return pt.get<T>("<xmlattr>.ordinateParam");
74 }
75 
76 template <typename T>
77 typename std::enable_if<std::is_floating_point<T>::value>::type
78 put_ordinate(ptree &pt, T ordinate) {
79  pt.put<T>("<xmlattr>.ordinateParam", ordinate);
80 }
81 
82 ALMATH_API Side get_side(const ptree &pt);
83 ALMATH_API void put_side(ptree &pt, Side side);
84 }
85 
86 namespace Key {
87 // return true if the argument is a Key element
88 ALMATH_API bool is_key(const ptree::value_type &val);
89 
90 // return key frame, which is non-negative
91 ALMATH_API int get_frame(const ptree &pt);
92 ALMATH_API void put_frame(ptree &pt, int frame);
93 
94 ALMATH_API ptree::size_type erase_tangent(ptree &pt, Side side);
95 
97  Side side);
98 ALMATH_API optional<ptree &> get_tangent_optional(ptree &pt, Side side);
99 
100 inline const ptree &get_tangent(const ptree &pt, Side side) {
101  return get_tangent_optional(pt, side).value();
102 }
103 
104 inline ptree &get_tangent(ptree &pt, Side side) {
105  return get_tangent_optional(pt, side).value();
106 }
107 
108 ALMATH_API ptree &require_tangent(ptree &pt, Side side);
109 
110 // Note: this function does *not* check that the abscissa sign is consistent
111 // with the tangent side
112 template <typename T>
113 typename std::enable_if<std::is_floating_point<T>::value, ptree &>::type
114 put_tangent(ptree &pt, Side side, T abscissa, T ordinate) {
115  ptree &tangent = require_tangent(pt, side);
116  Tangent::put_abscissa<T>(tangent, abscissa);
117  Tangent::put_ordinate<T>(tangent, ordinate);
118  return tangent;
119 }
120 
121 template <typename T>
122 typename std::enable_if<std::is_floating_point<T>::value, T>::type
123 get_value(const ptree &pt) {
124  return pt.get<T>("<xmlattr>.value");
125 }
126 
127 template <typename T>
128 typename std::enable_if<std::is_floating_point<T>::value>::type
129 put_value(ptree &pt, T value){
130  pt.put("<xmlattr>.value", value);
131 }
132 
133 
134 // throw if:
135 // an interval has non-positive duration
136 // an interval has a tangent with out of bounds abscissa
137 template <typename T>
138 typename std::enable_if<std::is_floating_point<T>::value>::type
139 check_cubic_bezier(int p0_frame, T, T p1_dframe, T,
140  T p2_dframe, T, int p3_frame, T) {
141  // interval duration, in frames
142  auto dframe = p3_frame - p0_frame;
143  if (dframe <= 0) {
144  throw std::invalid_argument(
145  "successive Key elements shall have increasing frame attributes");
146  }
147  if (p1_dframe < 0 || p1_dframe > dframe) {
148  throw std::invalid_argument(
149  "Key has right Tangent with out of bound abscissa attribute");
150  }
151  if (p2_dframe > 0 || p2_dframe < -dframe) {
152  throw std::invalid_argument(
153  "Key has left Tangent with out of bound abscissa attribute");
154  }
155 }
156 
157 // Apply functor to cubic Bezier curve parameters
158 //
159 // The Bezier curve is defined by the four points read from two adjacent
160 // keys
161 //
162 // p0: (p0_frame , p0_value)
163 // p1: (p0_frame + p1_dframe, p0_value + p1_dvalue)
164 // p2: (p3_frame + p2_dframe, p3_value + p2_dvalue)
165 // p3: (p3_frame, p3_value)
166 //
167 // The functor has the following signature:
168 // void op(int p0_frame, Scalar p0_value,
169 // Scalar p1_dframe, Scalar p1_dvalue,
170 // Scalar p2_dframe, Scalar p2_dvalue,
171 // int p3_frame, Scalar p3_value)
172 //
173 template <typename Scalar, typename Functor>
174 typename std::enable_if<std::is_floating_point<Scalar>::value>::type
175 apply_cubic_bezier(const ptree &p0_key, const ptree &p3_key, Functor op) {
176  const ptree &p1_tangent = Key::get_tangent(p0_key, Side::right);
177  const ptree &p2_tangent = Key::get_tangent(p3_key, Side::left);
178  op(Key::get_frame(p0_key),
179  Key::get_value<Scalar>(p0_key),
180  Tangent::get_abscissa<Scalar>(p1_tangent),
181  Tangent::get_ordinate<Scalar>(p1_tangent),
182  Tangent::get_abscissa<Scalar>(p2_tangent),
183  Tangent::get_ordinate<Scalar>(p2_tangent),
184  Key::get_frame(p3_key),
185  Key::get_value<Scalar>(p3_key));
186 }
187 }
188 
189 namespace ActuatorCurve {
190 // return true if the argument is an ActuatorCurve element
191 ALMATH_API bool is_actuatorcurve(const ptree::value_type &val);
192 
193 // return actuator name
194 ALMATH_API std::string get_actuator(const ptree &pt);
195 ALMATH_API void put_actuator(ptree &pt, const std::string &name);
196 
197 // return fps, which is positive
198 ALMATH_API int get_fps(const ptree &pt);
199 ALMATH_API void put_fps(ptree &pt, int fps);
200 
201 ALMATH_API bool get_mute(const ptree &pt);
202 ALMATH_API void put_mute(ptree &pt, bool mute);
203 
204 // return unit, which is not UNIT_UNKNOWN
205 ALMATH_API Unit get_unit(const ptree &pt);
206 ALMATH_API void put_unit(ptree &pt, Unit unit);
207 
208 // Search for a Key element with the given frame.
209 // If found, return it, otherwise return an invalid optional.
210 // This function assumes the Key elements are sorted by increasing frame,
211 // which should be the case if the document is conforming.
212 ALMATH_API optional<const ptree &> get_key_optional(const ptree &pt,
213  int frame);
214 ALMATH_API optional<ptree &> get_key_optional(ptree &pt, int frame);
215 
216 // Search for a Key element with the given frame.
217 // Throw if not found, otherwise return an invalid optional.
218 // This function assumes the Key elements are sorted by increasing frame,
219 // which should be the case if the document is conforming.
220 inline const ptree &get_key(const ptree &pt, int frame) {
221  return get_key_optional(pt, frame).value();
222 }
223 inline ptree &get_key(ptree &pt, int frame) {
224  return get_key_optional(pt, frame).value();
225 }
226 
227 // Search for a Key element with the given frame.
228 // If found, return it, otherwise insert a new Key.
229 // This function assumes the Key elements are sorted by increasing frame,
230 // which should be the case if the document is conforming.
231 ALMATH_API ptree &require_key(ptree &pt, int frame);
232 
233 // return the range of child Key elements, in document order.
234 // If the document is conforming, the keys are sorted by increasing frame.
235 inline auto get_keys(const ptree &pt)
236 -> boost::select_second_const_range<
237  decltype(boost::adaptors::filter(pt, Key::is_key))>
238 {
239  return boost::adaptors::values(boost::adaptors::filter(pt, Key::is_key));
240 }
241 
242 inline auto get_keys(ptree &pt)
243 -> boost::select_second_mutable_range<
244  decltype(boost::adaptors::filter(pt, Key::is_key))> {
245  auto kv = boost::adaptors::filter(pt, Key::is_key);
246  return boost::adaptors::values(kv);
247 }
248 
249 // throw if the curve does not describe a mathematical function as a
250 // sequence of cubic Bezier curves of positive duration
251 template <typename Scalar>
252 typename std::enable_if<std::is_floating_point<Scalar>::value>::type
254  auto keys = get_keys(pt);
256  keys.begin(), keys.end(),
257  [](const ptree &p0_key, const ptree &p3_key) {
258  Key::apply_cubic_bezier<Scalar>(p0_key, p3_key,
259  Key::check_cubic_bezier<Scalar>);
260  });
261 }
262 }
263 
264 namespace Label {
265 // return true if the argument is a Label element
266 ALMATH_API bool is_label(const ptree::value_type &val);
267 
268 using Key::get_frame;
269 using Key::put_frame;
270 
271 ALMATH_API std::string get_value(const ptree &pt);
272 }
273 
274 namespace Labels {
275 // return true if the argument is a Labels element
276 ALMATH_API bool is_labels(const ptree::value_type &val);
277 
280 
281 // Add a Label at the given frame, with the given value.
282 // Note that the specification requires the value to be UTF-8 encoded.
283 ALMATH_API ptree &add_label(ptree &pt, int frame, const std::string value);
284 
285 // return the range of child Label elements, in document order.
286 // If the document is conforming, the Label elements are sorted by increasing
287 // frame.
288 inline auto get_labels(const ptree &pt)
289 -> boost::select_second_const_range<
290  decltype(boost::adaptors::filter(pt, Label::is_label))>
291 {
292  return boost::adaptors::values(boost::adaptors::filter(pt, Label::is_label));
293 }
294 
295 // return the range of child Label elements, in document order.
296 inline auto get_labels(ptree &pt)
297 -> boost::select_second_mutable_range<
298  decltype(boost::adaptors::filter(pt, Label::is_label))> {
299  auto kv = boost::adaptors::filter(pt, Label::is_label);
300  return boost::adaptors::values(kv);
301 }
302 }
303 
304 namespace Animation {
305 // return the range of child ActuatorCurve elements, in document order.
306 inline auto get_actuatorcurves(const ptree &pt)
307 -> boost::select_second_const_range<
308  decltype(boost::adaptors::filter(pt, ActuatorCurve::is_actuatorcurve))> {
309  return boost::adaptors::values(
310  boost::adaptors::filter(pt, ActuatorCurve::is_actuatorcurve));
311 }
312 
313 inline auto get_actuatorcurves(ptree &pt)
314 -> boost::select_second_mutable_range<
315  decltype(boost::adaptors::filter(pt, ActuatorCurve::is_actuatorcurve))> {
316  auto kv = boost::adaptors::filter(pt, ActuatorCurve::is_actuatorcurve);
317  return boost::adaptors::values(kv);
318 }
319 
320 // throw if version is not 2.0
321 ALMATH_API void check_version(const ptree &pt);
322 
323 // throw if animation or one of its children is invalid
324 ALMATH_API void check_all(const ptree &pt);
325 
326 ALMATH_API ptree &require_actuatorcurve(ptree &pt,
327  const std::string &actuator);
328 
329 // return the range of child Labels elements, in document order.
330 inline auto get_labels(const ptree &pt)
331 -> boost::select_second_const_range<
332  decltype(boost::adaptors::filter(pt, Labels::is_labels))> {
333  return boost::adaptors::values(
334  boost::adaptors::filter(pt, Labels::is_labels));
335 }
336 
337 ALMATH_API ptree &add_labels(ptree &pt);
338 
339 }
340 
341 // return the Animation element, checking its version
342 ALMATH_API ptree &get_animation(ptree &root);
343 ALMATH_API const ptree &get_animation(const ptree &root);
344 ALMATH_API ptree &require_animation(ptree &root);
345 }
346 }
347 }
348 
349 #endif
ALMATH_API std::string get_actuator(const ptree &pt)
std::enable_if< std::is_floating_point< Scalar >::value >::type apply_cubic_bezier(const ptree &p0_key, const ptree &p3_key, Functor op)
Definition: qianim.h:175
ALMATH_API bool get_mute(const ptree &pt)
boost::optional< T > optional
Definition: qianim.h:25
std::enable_if< std::is_floating_point< T >::value, ptree & >::type put_tangent(ptree &pt, Side side, T abscissa, T ordinate)
Definition: qianim.h:114
auto get_labels(const ptree &pt) -> boost::select_second_const_range< decltype(boost::adaptors::filter(pt, Labels::is_labels))>
Definition: qianim.h:330
ALMATH_API std::string name(const ptree &pt)
ALMATH_API ptree::size_type erase_tangent(ptree &pt, Side side)
ALMATH_API bool is_label(const ptree::value_type &val)
ALMATH_API ptree & add_label(ptree &pt, int frame, const std::string value)
std::enable_if< std::is_floating_point< T >::value >::type put_value(ptree &pt, T value)
Definition: qianim.h:129
ALMATH_API void check_version(const ptree &pt)
ALMATH_API ptree & require_actuatorcurve(ptree &pt, const std::string &actuator)
ALMATH_API int get_fps(const ptree &pt)
std::enable_if< std::is_floating_point< T >::value >::type check_cubic_bezier(int p0_frame, T, T p1_dframe, T, T p2_dframe, T, int p3_frame, T)
Definition: qianim.h:139
ALMATH_API ptree & require_key(ptree &pt, int frame)
std::enable_if< std::is_floating_point< T >::value >::type put_abscissa(ptree &pt, T abscissa)
Definition: qianim.h:65
BinaryOperation adjacent_for_each(InputIt first, InputIt last, BinaryOperation binary_op)
Definition: qianim.h:37
ALMATH_API void check_all(const ptree &pt)
ALMATH_API std::string get_value(const ptree &pt)
Definition: qianim.h:123
std::enable_if< std::is_floating_point< T >::value, T >::type get_ordinate(const ptree &pt)
Definition: qianim.h:72
ALMATH_API bool is_actuatorcurve(const ptree::value_type &val)
ALMATH_API void put_side(ptree &pt, Side side)
ALMATH_API void put_unit(ptree &pt, Unit unit)
auto get_labels(const ptree &pt) -> boost::select_second_const_range< decltype(boost::adaptors::filter(pt, Label::is_label))>
Definition: qianim.h:288
std::enable_if< std::is_floating_point< Scalar >::value >::type check_cubic_bezier(const ptree &pt)
Definition: qianim.h:253
ALMATH_API optional< const ptree & > get_tangent_optional(const ptree &pt, Side side)
ALMATH_API ptree & require_animation(ptree &root)
ALMATH_API void put_fps(ptree &pt, int fps)
std::enable_if< std::is_floating_point< T >::value, T >::type get_value(const ptree &pt)
Definition: qianim.h:123
ALMATH_API ptree & get_animation(ptree &root)
ALMATH_API bool is_key(const ptree::value_type &val)
auto get_actuatorcurves(const ptree &pt) -> boost::select_second_const_range< decltype(boost::adaptors::filter(pt, ActuatorCurve::is_actuatorcurve))>
Definition: qianim.h:306
ALMATH_API void put_actuator(ptree &pt, const std::string &name)
ALMATH_API void put_frame(ptree &pt, int frame)
const ptree & get_tangent(const ptree &pt, Side side)
Definition: qianim.h:100
boost::property_tree::ptree ptree
Definition: qianim.h:22
const ptree & get_key(const ptree &pt, int frame)
Definition: qianim.h:220
ALMATH_API Side get_side(const ptree &pt)
std::enable_if< std::is_floating_point< T >::value >::type put_ordinate(ptree &pt, T ordinate)
Definition: qianim.h:78
ALMATH_API void put_mute(ptree &pt, bool mute)
ALMATH_API int get_frame(const ptree &pt)
ALMATH_API ptree & require_tangent(ptree &pt, Side side)
ALMATH_API bool is_labels(const ptree::value_type &val)
ALMATH_API Unit get_unit(const ptree &pt)
std::enable_if< std::is_floating_point< T >::value, T >::type get_abscissa(const ptree &pt)
Definition: qianim.h:57
ALMATH_API ptree & add_labels(ptree &pt)
ALMATH_API optional< const ptree & > get_key_optional(const ptree &pt, int frame)
auto get_keys(const ptree &pt) -> boost::select_second_const_range< decltype(boost::adaptors::filter(pt, Key::is_key))>
Definition: qianim.h:235