1 /* -*- C++ -*- ------------------------------------------------------------
3 Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
5 The Configurable Math Library (CML) is distributed under the terms of the
6 Boost Software License, v1.0 (see cml/LICENSE for details).
8 *-----------------------------------------------------------------------*/
13 #ifndef quaternion_expr_h
14 #define quaternion_expr_h
16 #include <cml/et/size_checking.h>
17 #include <cml/mathlib/epsilon.h>
18 #include <cml/quaternion/quaternion_traits.h>
19 #include <cml/quaternion/quaternion_promotions.h>
22 #define QUATXPR_ARG_TYPE const et::QuaternionXpr<XprT>&
23 #define QUATXPR_ARG_TYPE_N(_N_) const et::QuaternionXpr<XprT##_N_>&
28 /** A placeholder for a quaternion expression in an expression tree. */
34 typedef QuaternionXpr
<ExprT
> expr_type
;
36 /* Record ary-ness of the expression: */
37 typedef typename
ExprT::expr_ary expr_ary
;
39 /* Copy the expression by value into higher-up expressions: */
40 typedef expr_type expr_const_reference
;
42 typedef typename
ExprT::value_type value_type
;
43 typedef quaternion_result_tag result_tag
;
44 typedef typename
ExprT::size_tag size_tag
;
46 /* Store the expression traits: */
47 typedef ExprTraits
<ExprT
> expr_traits
;
49 /* Get the reference type: */
50 typedef typename
expr_traits::const_reference expr_reference
;
52 /* Get the result type: */
53 typedef typename
expr_traits::result_type result_type
;
55 /* Get the vector type: */
56 typedef typename
result_type::vector_type vector_type
;
58 /* Get the imaginary part type: */
59 typedef typename
vector_type::subvector_type imaginary_type
;
61 /* For matching by assignability: */
62 typedef cml::et::not_assignable_tag assignable_tag
;
64 /* Get the temporary type: */
65 typedef typename
result_type::temporary_type temporary_type
;
67 /* Record the order type: */
68 typedef typename
result_type::order_type order_type
;
70 /* Record the cross type: */
71 typedef typename
result_type::cross_type cross_type
;
76 /** Record result size as an enum. */
77 enum { array_size
= ExprT::array_size
};
82 /** Return the real part of the expression. */
83 value_type
real() const {
87 /** Return the vector part of the expression. */
88 imaginary_type
imaginary() const {
89 return m_expr
.imaginary();
92 /** Return the Cayley norm of the expression. */
93 value_type
norm() const {
94 return m_expr
.length_squared();
97 /** Return square of the quaternion length. */
98 value_type
length_squared() const {
99 return m_expr
.length_squared();
102 /** Return the quaternion length. */
103 value_type
length() const {
104 return m_expr
.length();
107 /** Return the result as a normalized quaternion. */
108 temporary_type
normalize() const {
109 return m_expr
.normalize();
112 /** Return the log of the expression. */
114 value_type tolerance
= epsilon
<value_type
>::placeholder()) const
116 return m_expr
.log(tolerance
);
120 * Return the result of the exponential function as applied to
124 value_type tolerance
= epsilon
<value_type
>::placeholder()) const
126 return m_expr
.exp(tolerance
);
129 /** Compute value at index i of the result quaternion. */
130 value_type
operator[](size_t i
) const {
137 /** Return size of this expression (same as subexpression's size). */
138 size_t size() const {
139 return m_expr
.size();
142 /** Return reference to contained expression. */
143 expr_reference
expression() const { return m_expr
; }
148 /** Construct from the subexpression to store. */
149 explicit QuaternionXpr(expr_reference expr
) : m_expr(expr
) {}
151 /** Copy constructor. */
152 QuaternionXpr(const expr_type
& e
) : m_expr(e
.m_expr
) {}
157 expr_reference m_expr
;
162 /* Cannot be assigned to: */
163 expr_type
& operator=(const expr_type
&);
166 /** Expression traits class for QuaternionXpr<>. */
167 template<class ExprT
>
168 struct ExprTraits
< QuaternionXpr
<ExprT
> >
170 typedef QuaternionXpr
<ExprT
> expr_type
;
171 typedef ExprT arg_type
;
172 typedef typename
expr_type::value_type value_type
;
173 typedef typename
expr_type::expr_const_reference const_reference
;
174 typedef typename
expr_type::result_tag result_tag
;
175 typedef typename
expr_type::size_tag size_tag
;
176 typedef typename
expr_type::result_type result_type
;
177 typedef typename
expr_type::assignable_tag not_assignable_tag
;
178 typedef expr_node_tag node_tag
;
180 value_type
get(const expr_type
& v
, size_t i
) const { return v
[i
]; }
181 size_t size(const expr_type
& e
) const { return e
.size(); }
185 /** A unary quaternion expression.
187 * The operator's operator() method must take exactly one argument.
189 template<class ExprT
, class OpT
>
190 class UnaryQuaternionOp
194 typedef UnaryQuaternionOp
<ExprT
,OpT
> expr_type
;
196 /* Record ary-ness of the expression: */
197 typedef unary_expression expr_ary
;
199 /* Copy the expression by value into higher-up expressions: */
200 typedef expr_type expr_const_reference
;
202 typedef typename
OpT::value_type value_type
;
203 typedef quaternion_result_tag result_tag
;
204 typedef typename
ExprT::size_tag size_tag
;
206 /* Store the expression traits for the subexpression: */
207 typedef ExprTraits
<ExprT
> expr_traits
;
209 /* Reference type for the subexpression: */
210 typedef typename
expr_traits::const_reference expr_reference
;
212 /* Get the result type (same as for subexpression): */
213 typedef typename
expr_traits::result_type result_type
;
215 /* For matching by assignability: */
216 typedef cml::et::not_assignable_tag assignable_tag
;
218 /* Get the temporary type: */
219 typedef typename
result_type::temporary_type temporary_type
;
221 /* Get the vector type: */
222 typedef typename
result_type::vector_type vector_type
;
224 /* Get the imaginary part type: */
225 typedef typename
vector_type::subvector_type imaginary_type
;
227 /* Record the order type: */
228 typedef typename
result_type::order_type order_type
;
233 /** Record result size as an enum. */
234 enum { array_size
= ExprT::array_size
};
236 /** Localize the ordering as an enum. */
247 /** Return the real part of the expression. */
248 value_type
real() const {
252 /** Return the vector part of the expression. */
253 imaginary_type
imaginary() const {
255 v
[0] = (*this)[X
]; v
[1] = (*this)[Y
]; v
[2] = (*this)[Z
];
259 /** Return the Cayley norm of the expression. */
260 value_type
norm() const {
261 return length_squared();
264 /** Return square of the quaternion length. */
265 value_type
length_squared() const {
267 QuaternionXpr
<expr_type
>(*this),
268 QuaternionXpr
<expr_type
>(*this));
271 /** Return the quaternion length. */
272 value_type
length() const {
273 return std::sqrt(length_squared());
276 /** Return the result as a normalized quaternion. */
277 temporary_type
normalize() const {
278 temporary_type
q(QuaternionXpr
<expr_type
>(*this));
279 return q
.normalize();
282 /** Return the log of this expression. */
284 value_type tolerance
= epsilon
<value_type
>::placeholder()) const
286 value_type a
= acos_safe(real());
287 value_type s
= std::sin(a
);
290 return temporary_type(value_type(0), imaginary() * (a
/ s
));
292 return temporary_type(value_type(0), imaginary());
297 * Return the result of the exponential function as applied to
301 value_type tolerance
= epsilon
<value_type
>::placeholder()) const
303 imaginary_type v
= imaginary();
304 value_type a
= cml::length(v
);
307 return temporary_type(std::cos(a
), v
* (std::sin(a
) / a
));
309 return temporary_type(std::cos(a
), v
);
313 /** Compute value at index i of the result quaternion. */
314 value_type
operator[](size_t i
) const {
316 /* This uses the expression traits to figure out how to access the
317 * i'th index of the subexpression:
319 return OpT().apply(expr_traits().get(m_expr
,i
));
325 /** Return size of this expression (same as argument's size). */
326 size_t size() const {
327 return m_expr
.size();
330 /** Return reference to contained expression. */
331 expr_reference
expression() const { return m_expr
; }
336 /** Construct from the subexpression. */
337 explicit UnaryQuaternionOp(expr_reference expr
) : m_expr(expr
) {}
339 /** Copy constructor. */
340 UnaryQuaternionOp(const expr_type
& e
) : m_expr(e
.m_expr
) {}
345 expr_reference m_expr
;
350 /* Cannot be assigned to: */
351 expr_type
& operator=(const expr_type
&);
354 /** Expression traits class for UnaryQuaternionOp<>. */
355 template<class ExprT
, class OpT
>
356 struct ExprTraits
< UnaryQuaternionOp
<ExprT
,OpT
> >
358 typedef UnaryQuaternionOp
<ExprT
,OpT
> expr_type
;
359 typedef ExprT arg_type
;
361 typedef typename
expr_type::value_type value_type
;
362 typedef typename
expr_type::expr_const_reference const_reference
;
363 typedef typename
expr_type::result_tag result_tag
;
364 typedef typename
expr_type::size_tag size_tag
;
365 typedef typename
expr_type::result_type result_type
;
366 typedef typename
expr_type::assignable_tag not_assignable_tag
;
367 typedef expr_node_tag node_tag
;
369 value_type
get(const expr_type
& v
, size_t i
) const { return v
[i
]; }
370 size_t size(const expr_type
& e
) const { return e
.size(); }
374 /** A binary quaternion expression.
376 * The operator's operator() method must take exactly two arguments.
378 template<class LeftT
, class RightT
, class OpT
>
379 class BinaryQuaternionOp
383 typedef BinaryQuaternionOp
<LeftT
,RightT
,OpT
> expr_type
;
385 /* Record ary-ness of the expression: */
386 typedef binary_expression expr_ary
;
388 /* Copy the expression by value into higher-up expressions: */
389 typedef expr_type expr_const_reference
;
391 typedef typename
OpT::value_type value_type
;
392 typedef quaternion_result_tag result_tag
;
394 /* Store the expression traits types for the two subexpressions: */
395 typedef ExprTraits
<LeftT
> left_traits
;
396 typedef ExprTraits
<RightT
> right_traits
;
398 /* Reference types for the two subexpressions: */
399 typedef typename
left_traits::const_reference left_reference
;
400 typedef typename
right_traits::const_reference right_reference
;
402 /* Figure out the expression's resulting (quaternion) type: */
403 typedef typename
left_traits::result_type left_result
;
404 typedef typename
right_traits::result_type right_result
;
405 typedef typename QuaternionPromote
<left_result
,right_result
>::type
407 typedef typename
result_type::size_tag size_tag
;
409 /* For matching by assignability: */
410 typedef cml::et::not_assignable_tag assignable_tag
;
412 /* Get the temporary type: */
413 typedef typename
result_type::temporary_type temporary_type
;
415 /* Get the vector type: */
416 typedef typename
result_type::vector_type vector_type
;
418 /* Get the imaginary part type: */
419 typedef typename
vector_type::subvector_type imaginary_type
;
421 /* Record the order type: */
422 typedef typename
result_type::order_type order_type
;
424 /* Define a size checker: */
425 typedef GetCheckedSize
<LeftT
,RightT
,size_tag
> checked_size
;
430 /** Record result size as an enum. */
431 enum { array_size
= 4 };
433 /** Localize the ordering as an enum. */
444 /** Return the real part of the expression. */
445 value_type
real() const {
449 /** Return the vector part of the expression. */
450 imaginary_type
imaginary() const {
452 v
[0] = (*this)[X
]; v
[1] = (*this)[Y
]; v
[2] = (*this)[Z
];
456 /** Return the Cayley norm of the expression. */
457 value_type
norm() const {
458 return length_squared();
461 /** Return square of the quaternion length. */
462 value_type
length_squared() const {
464 QuaternionXpr
<expr_type
>(*this),
465 QuaternionXpr
<expr_type
>(*this));
468 /** Return the quaternion length. */
469 value_type
length() const {
470 return std::sqrt(length_squared());
473 /** Return the result as a normalized quaternion. */
474 temporary_type
normalize() const {
475 temporary_type
q(QuaternionXpr
<expr_type
>(*this));
476 return q
.normalize();
479 /** Return the log of this expression. */
481 value_type tolerance
= epsilon
<value_type
>::placeholder()) const
483 value_type a
= acos_safe(real());
484 value_type s
= std::sin(a
);
487 return temporary_type(value_type(0), imaginary() * (a
/ s
));
489 return temporary_type(value_type(0), imaginary());
494 * Return the result of the exponential function as applied to
498 value_type tolerance
= epsilon
<value_type
>::placeholder()) const
500 imaginary_type v
= imaginary();
501 value_type a
= cml::length(v
);
504 return temporary_type(std::cos(a
), v
* (std::sin(a
) / a
));
506 return temporary_type(std::cos(a
), v
);
510 /** Compute value at index i of the result quaternion. */
511 value_type
operator[](size_t i
) const {
513 /* This uses the expression traits to figure out how to access the
514 * i'th index of the two subexpressions:
517 left_traits().get(m_left
,i
),
518 right_traits().get(m_right
,i
));
524 /** Return the size of the quaternion result.
526 * @throws std::invalid_argument if the expressions do not have the same
529 size_t size() const {
530 /* Note: This actually does a check only if
531 * CML_CHECK_VECTOR_EXPR_SIZES is set:
533 CheckedSize(m_left
,m_right
,size_tag());
535 /* The size is always 4: */
539 /** Return reference to left expression. */
540 left_reference
left_expression() const { return m_left
; }
542 /** Return reference to right expression. */
543 right_reference
right_expression() const { return m_right
; }
548 /** Construct from the two subexpressions. */
549 explicit BinaryQuaternionOp(left_reference left
, right_reference right
)
550 : m_left(left
), m_right(right
) {}
552 /** Copy constructor. */
553 BinaryQuaternionOp(const expr_type
& e
)
554 : m_left(e
.m_left
), m_right(e
.m_right
) {}
559 left_reference m_left
;
560 right_reference m_right
;
565 /* This ensures that a compile-time size check is executed: */
566 typename
checked_size::check_type _dummy
;
571 /* Cannot be assigned to: */
572 expr_type
& operator=(const expr_type
&);
575 /** Expression traits class for BinaryQuaternionOp<>. */
576 template<class LeftT
, class RightT
, class OpT
>
577 struct ExprTraits
< BinaryQuaternionOp
<LeftT
,RightT
,OpT
> >
579 typedef BinaryQuaternionOp
<LeftT
,RightT
,OpT
> expr_type
;
580 typedef LeftT left_type
;
581 typedef RightT right_type
;
583 typedef typename
expr_type::value_type value_type
;
584 typedef typename
expr_type::expr_const_reference const_reference
;
585 typedef typename
expr_type::result_tag result_tag
;
586 typedef typename
expr_type::size_tag size_tag
;
587 typedef typename
expr_type::result_type result_type
;
588 typedef typename
expr_type::imaginary_type imaginary_type
;
589 typedef typename
expr_type::assignable_tag not_assignable_tag
;
590 typedef expr_node_tag node_tag
;
592 value_type
get(const expr_type
& v
, size_t i
) const { return v
[i
]; }
593 size_t size(const expr_type
& e
) const { return e
.size(); }
597 /* Helper struct to verify that both arguments are quaternion expressions: */
598 template<class LeftTraits
, class RightTraits
>
599 struct QuaternionExpressions
601 /* Require that both arguments are quaternion expressions: */
602 typedef typename
LeftTraits::result_tag left_result
;
603 typedef typename
RightTraits::result_tag right_result
;
604 enum { is_true
= (same_type
<left_result
,et::quaternion_result_tag
>::is_true
605 && same_type
<right_result
,et::quaternion_result_tag
>::is_true
) };
613 // -------------------------------------------------------------------------