1:last-update-label!:
2:icons: font
3:prewrap!:
4:source-highlighter: coderay
5:stylesheet: zajo.css
6= QVM
7Generic {CPP} library for working with Quaternions Vectors and Matrices
8:toclevels: 3
9:toc: left
10:sectnumlevels: 2
11:keywords: c++, boost, matrix, vector, quaternion
12
13[abstract]
14== Abstract
15QVM is a generic library for working with Quaternions, Vectors and Matrices of static size. Features:
16
17====
18* Emphasis on 2, 3 and 4-dimensional operations needed in graphics, video games and simulation applications.
19* Free function templates operate on any compatible user-defined quaternion, vector or matrix type.
20* Quaternion, vector and matrix types from different libraries or subsystems can be safely mixed in the same expression.
21* Type-safe mapping between compatible lvalue types with no temporary objects; e.g. transpose remaps the elements, rather than transforming the matrix.
22
23[.text-right]
24https://github.com/boostorg/qvm[GitHub] | <<tutorial>> | <<reference>> | <<rationale>>
25====
26
27[[tutorial]]
28== Tutorial
29
30=== Quaternions, Vectors, Matrices
31
32Out of the box QVM defines generic yet simple <<quat,`quat`>>, <<vec,`vec`>> and <<mat,`mat`>> types. For example, the following snippet creates a quaternion object that rotates around the X axis:
33
34[source,c++]
35----
36quat<float> rx = rotx_quat(3.14159f);
37----
38
39Similarly, a matrix that translates by a given vector can be created as follows:
40
41[source,c++]
42----
43vec<float,3> v = {0,0,7};
44mat<float,4,4> tr = translation_mat(v);
45----
46
47The usual quaternion, vector and matrix operations work on these QVM types, however the operations are decoupled from any specific type: they work on any suitable type that has been registered by specializing the <<quat_traits,`quat_traits`>>, <<vec_traits,`vec_traits`>> and <<mat_traits,`mat_traits`>> templates.
48
49For example, a user-defined 3D vector type `float3` can be introduced to QVM as follows:
50
51[source,c++]
52----
53struct float3 { float a[3]; };
54
55namespace boost { namespace qvm {
56
57  template <>
58  struct vec_traits<float3> {
59
60    static int const dim=3;
61    typedef float scalar_type;
62
63    template <int I>
64    static inline scalar_type & write_element( float3 & v ) {
65      return v.a[I];
66    }
67
68    template <int I>
69    static inline scalar_type read_element( float3 const & v ) {
70      return v.a[I];
71    }
72
73    static inline scalar_type & write_element_idx( int i, float3 & v ) {
74      return v.a[i];
75    } //optional
76
77    static inline scalar_type read_element_idx( int i, float3 const & v ) {
78      return v.a[i];
79    } //optional
80
81  };
82
83} }
84----
85
86Equivalently, using the <<vec_traits_defaults,`vec_traits_defaults`>> template the above can be shortened to:
87
88[source,c++]
89----
90namespace boost { namespace qvm {
91
92  template <>
93  struct vec_traits<float3>: vec_traits_defaults<float3,float,3> {
94
95    template <int I>
96    static inline scalar_type & write_element( float3 & v ) {
97      return v.a[I];
98    }
99
100    static inline scalar_type & write_element_idx( int i, float3 & v ) {
101      return v.a[i];
102    } //optional
103
104  };
105
106} }
107----
108
109After a similar specialization of the <<mat_traits,`mat_traits`>> template for a user-defined 3x3 matrix type `float33`, the full range of vector and matrix operations defined by QVM headers becomes available automatically:
110
111[source,c++]
112----
113float3 v;
114X(v) = 0;
115Y(v) = 0;
116Z(v) = 7;
117float vmag = mag(v);
118float33 m = rotx_mat<3>(3.14159f);
119float3 vrot = m * v;
120----
121
122User-defined quaternion types are similarly introduced to QVM by specializing the <<quat_traits,`quat_traits`>> template.
123
124'''
125
126=== C Arrays
127
128In <<boost/qvm/quat_traits_array.hpp,`boost/qvm/quat_traits_array.hpp`>>, <<boost/qvm/vec_traits_array.hpp,`boost/qvm/vec_traits_array.hpp`>> and <<boost/qvm/mat_traits_array.hpp,`boost/qvm/mat_traits_array.hpp`>> QVM defines appropriate <<quat_traits,`quat_traits`>>, <<vec_traits,`vec_traits`>> and <<mat_traits,`mat_traits`>> specializations that allow QVM functions to operate directly on plain old C arrays:
129
130[source,c++]
131----
132float v[3] = {0,0,7};
133float3 vrot = rotx_mat<3>(3.14159f) * v;
134----
135
136Naturally, operator overloads cannot kick in if all elements of an expression are of built-in types. The following is still illegal:
137
138[source,c++]
139----
140float v[3] = {0,0,7};
141v *= 42;
142----
143
144The <<vref,`vref`>> and <<mref,`mref`>> function templates can be used to work around this issue:
145
146[source,c++]
147----
148float v[3] = {0,0,7};
149vref(v) *= 42;
150----
151
152'''
153
154[[view_proxy]]
155=== View proxies
156
157QVM defines various function templates that provide static mapping between (possibly user-defined) quaternion, vector and matrix types. The example below multiplies column 1 (QVM indexes are always zero-based) of the matrix `m` by a scalar:
158
159[source,c++]
160----
161void multiply_column1( float33 & m, float scalar ) {
162  col<1>(m) *= scalar;
163}
164----
165
166The expression <<col,`col<1>(m)`>> is an lvalue of an unspecified 3D vector type that refers to column 1 of `m`. Note however that this does not create any temporary objects; instead `operator*=` above works directly with a reference to `m`.
167
168Here is another example, multiplying a transposed view of a matrix by a vector of some user-defined type `float3`:
169
170[source,c++]
171----
172float3 v = {0,0,7};
173float3 vrot = transposed(rotx_mat<3>(3.14159f)) * v;
174----
175
176In general, the various view proxy functions return references of unspecified, non-copyable types that refer to the original object. They can be assigned from or converted to any compatible vector or matrix type.
177
178'''
179
180=== Swizzling
181
182QVM allows accessing vector elements by swizzling, exposing vector views of different dimensions, and/or views with reordered elements. The example below rotates `v` around the X axis, and stores the resulting vector back in `v` but with the X and Y elements swapped:
183
184[source,c++]
185----
186float3 v = {0,0,7};
187YXZ(v) = rotx_mat<3>(3.14159f) * v;
188----
189
190A special case of swizzling provides next-dimension-view of a vector object, adding either 0 or 1 as its last component. Assuming `float3` is a 3D vector type, and `float4` is a 4D vector type, the following statements are valid:
191
192[source,c++]
193----
194float3 v = {0,0,7};
195float4 point = XYZ1(v); //{0,0,7,1}
196float4 vector = XYZ0(v); //{0,0,7,0}
197----
198
199It is also valid for swizzling to address vector elements more than once:
200
201[source,c++]
202----
203float3 v = {0,0,7};
204float4 v1 = ZZZZ(v); //{7,7,7,7}
205----
206
207QVM defines all permutations of `X`, `Y`, `Z`, `W` for 1D, 2D, 3D and 4D swizzling, plus each dimension defines variants with 0 or 1 used at any position (if 0 or 1 appear at the first position, the swizzling function name begins with underscore, e.g. `_1XY`).
208
209The swizzling syntax can also be used to bind scalars as vectors. For example:
210
211[source,c++]
212----
213float3 v = _00X(42.0f); //{0,0,42}
214----
215
216'''
217
218[[enable_if]]
219=== SFINAE/enable_if
220
221SFINAE stands for Substitution Failure Is Not An Error. This refers to a situation in {CPP} where an invalid substitution of template parameters (including when those parameters are deduced implicitly as a result of an unqualified call) is not in itself an error.
222
223In absence of concepts support, SFINAE can be used to disable function template overloads that would otherwise present a signature that is too generic. More formally, this is supported by the Boost `enable_if` library.
224
225For example, QVM defines `operator*` overload which works with any user-defined matrix and vector types. The naive approach would be to declare this overload as follows:
226
227[source,c++]
228----
229template <class Matrix,class Vector>
230Vector operator*( Matrix const & m, Vector const & v );
231----
232
233Even if the function definition might contain code that would compile only for `Matrix` and `Vector` types, because the function declaration itself is valid, it will participate in overload rezolutions when multiplying objects of any two types whatsoever. This typically renders overload resolutions ambiguous and the compiler (correctly) issues an error.
234
235Using `enable_if`, QVM declares such overloads in a way that preserves their generic signature but only participate in overload resolutions if the passed parameters make sense depending on the semantics of the operation being defined:
236
237[source,c++]
238----
239template <class A,class B>
240typename enable_if_c<
241  is_mat<A>::value && is_vec<B>::value && mat_traits<A>::cols==vec_traits<B>::dim, //Condition
242  B>::type //Return type
243operator*( A const & a, B const & b );
244----
245
246For brevity, function declarations throughout this documentation specify the condition which controls whether they are enabled or not without specifying exactly what `enable_if` construct is used to achieve this effect.
247
248'''
249
250=== Interoperability
251
252An important design goal of QVM is that it works seamlessly with 3rd-party quaternion, vector and matrix types and libraries. Even when such libraries overload the same {CPP} operators as QVM, it is safe to bring the entire `boost::qvm` namespace in scope by specifying:
253
254[source,c++]
255----
256using namespace boost::qvm;
257----
258
259The above using directive does not introduce ambiguities with function and operator overloads defined by a 3rd-party library because:
260
261- Most `boost::qvm` function overloads and all operator overloads use SFINAE/`enable_if`, which makes them "disappear" unless an expression uses types that have the appropriate QVM-specific type traits defined;
262
263- Whenever such overloads are compatible with a given expression, their signature is extremely generic, which means that any other (user-defined) compatible overload will be a better match in any overload resolution.
264
265NOTE: Bringing the entire boost::qvm namespace in scope may introduce ambiguities when accessing types (as opposed to functions) defined by 3rd-party libraries. In that case, you can safely bring namespace `boost::qvm::sfinae` in scope instead, which contains only function and operator overloads that use SFINAE/`enable_if`.
266
267==== Specifying return types for binary operations
268
269Bringing the `boost::qvm` namespace in scope lets you mix vector and matrix types that come from different APIs into a common, type-safe framework. In this case however, it should be considered what types should be returned by binary operations that return an object by value. For example, if you multiply a 3x3 matrix `m1` of type `user_matrix1` by a 3x3 matrix `m2` of type `user_matrix2`, what type should that operation return?
270
271The answer is that by default, QVM returns some kind of compatible matrix type, so it is always safe to write:
272
273[source,c++]
274----
275auto & m = m1 * m2;
276----
277
278However, the type deduced by default converts implicitly to any compatible matrix type, so the following is also valid, at the cost of a temporary:
279
280[source,c++]
281----
282user_matrix1 m = m1 * m2;
283----
284
285While the temporary object can be optimized away by many compilers, it can be avoided altogether by specializing the <<deduce_mat2,`deduce_mat2`>> template. For example, to specify that multiplying a `user_matrix1` by a `user_matrix2` should always produce a `user_matrix1` object, you could write:
286
287[source,c++]
288----
289namespace boost { namespace qvm {
290
291  template <>
292  struct deduce_mat2<user_matrix1,user_matrix2,3,3> {
293    typedef user_matrix1 type;
294  };
295
296  template <>
297  struct deduce_mat2<user_matrix2,user_matrix1,3,3> {
298    typedef user_matrix1 type;
299  };
300
301} }
302----
303
304[WARNING]
305====
306Be mindful of potential ODR violation when using <<deduce_quat2,`deduce_quat2`>>, <<deduce_vec2,`deduce_vec2`>> and <<deduce_mat2,`deduce_mat2`>> in independent libraries. For example, this could happen if `lib1` defines `deduce_vec2<lib1::vec,lib2::vec>::type` as `lib1::vec` and in the same program `lib2` defines `deduce_vec2<lib1::vec,lib2::vec>::type` as `lib2::vec`.
307
308It is best to keep such specializations out of `lib1` and `lib2`. Of course, it is always safe for `lib1` and `lib2` to use <<convert_to,`convert_to`>> to convert between the `lib1::vec` and `lib2::vec` types as needed.
309====
310
311==== Specifying return types for unary operations
312
313Perhaps surprisingly, unary operations that return an object by value have a similar, though simpler issue. That's because the argument they're called with may not be copyable, as in:
314
315[source,c++]
316----
317float m[3][3];
318auto & inv = inverse(m);
319----
320
321Above, the object returned by <<mat_inverse,`inverse`>> and captured by `inv` can not be of type `float[3][3]`, because that type isn't copyable. By default, QVM "just works", returning an object of suitable matrix type that is copyable. This deduction process can be controlled, by specializing the <<deduce_mat,`deduce_mat`>> template.
322
323==== Converting between different quaternion, vector and matrix types
324
325Any time you need to create a matrix of a particular {CPP} type from any other compatible matrix type, you can use the <<convert_to,`convert_to`>> function:
326
327[source,c++]
328----
329user_matrix2 m=convert_to<user_matrix2>(m1 * m2);
330----
331
332[[reference]]
333== Reference
334
335=== Header Files
336
337QVM is split into multiple headers to allow different compilation units to `#include` only the components they need. Each function in this document specifies the exact header that must be `#included` in order to use it.
338
339The tables below list commonly used components and the headers they're found in. Header names containing a number define functions that only work with objects of that dimension; e.g. `vec_operations2.hpp` contains only functions for working with 2D vectors.
340
341The header `boost/qvm/all.hpp` is provided for convenience. It includes all other QVM headers.
342
343.Quaternion header files
344[cols="1,2l"]
345|====
346| Quaternion traits |#include <boost/qvm/quat_traits.hpp>
347#include <boost/qvm/quat_traits_array.hpp>
348#include <boost/qvm/deduce_quat.hpp>
349| Quaternion element access |#include <boost/qvm/quat_access.hpp>
350| Quaternion operations |#include <boost/qvm/quat_operations.hpp>
351| <<quat,`quat`>> class template |#include <boost/qvm/quat.hpp>
352|====
353
354.Vector header files
355[cols="1,2l"]
356|====
357| Vector traits |#include <boost/qvm/vec_traits.hpp>
358#include <boost/qvm/vec_traits_array.hpp>
359#include <boost/qvm/deduce_vec.hpp>
360| Vector element access |#include <boost/qvm/vec_access.hpp>
361| Vector <<swizzling,swizzling>> |#include <boost/qvm/swizzle.hpp>
362#include <boost/qvm/swizzle2.hpp>
363#include <boost/qvm/swizzle3.hpp>
364#include <boost/qvm/swizzle4.hpp>
365| Vector operations | #include <boost/qvm/vec_operations.hpp>
366#include <boost/qvm/vec_operations2.hpp>
367#include <boost/qvm/vec_operations3.hpp>
368#include <boost/qvm/vec_operations4.hpp>
369| Quaternion-vector operations | #include <boost/qvm/quat_vec_operations.hpp>
370| Vector-matrix operations | #include <boost/qvm/vec_mat_operations.hpp>
371| Vector-matrix <<view_proxy,view proxies>> | #include <boost/qvm/map_vec_mat.hpp>
372| <<vec,`vec`>> class template | #include <boost/qvm/vec.hpp>
373|====
374
375.Matrix header files
376[cols="1,2l"]
377|====
378| Matrix traits |#include <boost/qvm/mat_traits.hpp>
379#include <boost/qvm/mat_traits_array.hpp>
380#include <boost/qvm/deduce_mat.hpp>
381| Matrix element access |#include <boost/qvm/mat_access.hpp>
382| Matrix operations |#include <boost/qvm/mat_operations.hpp>
383#include <boost/qvm/mat_operations2.hpp>
384#include <boost/qvm/mat_operations3.hpp>
385#include <boost/qvm/mat_operations4.hpp>
386| Matrix-matrix <<view_proxy,view proxies>> | #include <boost/qvm/map_mat_mat.hpp>
387| Matrix-vector <<view_proxy,view proxies>> | #include <boost/qvm/map_mat_vec.hpp>
388| <<mat,`mat`>> class template | #include <boost/qvm/mat.hpp>
389|====
390
391[[type_traits]]
392=== Type Traits System
393
394QVM is designed to work with user-defined quaternion, vector and matrix types, as well as user-defined scalar types. This section formally defines the way such types can be integrated.
395
396'''
397
398[[scalar_requirements]]
399==== Scalar Requirements
400
401A valid scalar type `S` must have accessible destructor, default constructor, copy constructor and assignment operator, and must support the following operations:
402
403[source,c++]
404----
405S operator*( S, S );
406S operator/( S, S );
407S operator+( S, S );
408S operator-( S, S );
409
410S & operator*=( S &, S );
411S & operator/=( S &, S );
412S & operator+=( S &, S );
413S & operator-=( S &, S );
414
415bool operator==( S, S );
416bool operator!=( S, S );
417----
418
419In addition, the expression `S(0)` should construct a scalar of value zero, and `S(1)` should construct a scalar of value one, or else the <<scalar_traits,`scalar_traits`>> template must be specialized appropriately.
420
421'''
422
423[[is_scalar]]
424==== `is_scalar`
425
426.#include <boost/qvm/scalar_traits.hpp>
427[source,c++]
428----
429namespace boost { namespace qvm {
430
431  template <class T>
432  struct is_scalar {
433    static bool const value=false;
434  };
435
436  template <> struct is_scalar<char>       { static bool const value=true; };
437  template <> struct is_scalar<signed char>  { static bool const value=true; };
438  template <> struct is_scalar<unsigned char>  { static bool const value=true; };
439  template <> struct is_scalar<signed short>   { static bool const value=true; };
440  template <> struct is_scalar<unsigned short> { static bool const value=true; };
441  template <> struct is_scalar<signed int>   { static bool const value=true; };
442  template <> struct is_scalar<unsigned int>   { static bool const value=true; };
443  template <> struct is_scalar<signed long>  { static bool const value=true; };
444  template <> struct is_scalar<unsigned long>  { static bool const value=true; };
445  template <> struct is_scalar<float>      { static bool const value=true; };
446  template <> struct is_scalar<double>     { static bool const value=true; };
447  template <> struct is_scalar<long double>  { static bool const value=true; };
448
449} }
450----
451
452This template defines a compile-time boolean constant value which can be used to determine whether a type `T` is a valid scalar type. It must be specialized together with the <<scalar_traits,`scalar_traits`>> template in order to introduce a user-defined scalar type to QVM. Such types must satisfy the <<scalar_requirements,scalar requirements>>.
453
454'''
455
456[[scalar_traits]]
457==== `scalar_traits`
458
459.#include <boost/qvm/scalar_traits.hpp>
460[source,c++]
461----
462namespace boost { namespace qvm {
463
464  template <class Scalar>
465  struct scalar_traits {
466
467    BOOST_QVM_INLINE_CRITICAL
468    static Scalar value( int v ) {
469      return Scalar(v);
470    }
471
472  };
473
474} }
475----
476
477This template may be specialized for user-defined scalar types to define the appropriate conversion from `int`; this is primarily used whenever QVM needs to deduce a zero or one value.
478
479'''
480
481[[deduce_scalar]]
482==== `deduce_scalar`
483
484.#include <boost/qvm/deduce_scalar.hpp>
485[source,c++]
486----
487namespace boost { namespace qvm {
488
489  template <class A,class B>
490  struct deduce_scalar
491  {
492    typedef typename impl<A,B>::type type;
493  };
494
495} }
496----
497
498Requirements: :: `A` and `B` satisfy the <<scalar_requirements,scalar requirements>>.
499
500Returns: ::
501
502If `A` and `B` are the same type, `impl<A,B>::type` returns that type. Otherwise, `impl<A,B>::type` is well defined for the following types only: `signed`/`unsigned char`, `signed`/`unsigned short`, `signed`/`unsigned int`, `signed`/`unsigned long`, `float` and `double`. The deduction logic is as follows:
503
504- if either of `A` and `B` is `double`, the result is `double`;
505- else, if one of `A` or `B` is an integer type and the other is `float`, the result is `float`;
506- else, if one of `A` or `B` is a signed integer and the other type is unsigned integer, the signed type is changed to unsigned, and then the lesser of the two integers is promoted to the other.
507
508NOTE: This template is used by generic binary operations that return a scalar, to deduce the return type based on the (possibly different) scalars of their arguments.
509
510'''
511
512[[scalar]]
513==== `scalar`
514
515.#include <boost/qvm/scalar_traits.hpp>
516[source,c++]
517----
518namespace boost { namespace qvm {
519
520  template <class T>
521  struct scalar {
522    typedef /*exact definition unspecified*/ type;
523  };
524
525} }
526----
527
528The expression <<quat_traits,`quat_traits<T>::scalar_type`>> evaluates to the scalar type of the quaternion type `T` (if <<is_quat,`is_quat<T>::value`>> is `true`).
529
530The expression <<vec_traits,`vec_traits<T>::scalar_type`>> evaluates to the scalar type of the vector type `T` (if <<is_vec,`is_vec<T>::value`>> is `true`).
531
532The expression <<mat_traits,`mat_traits<T>::scalar_type`>> evaluates to the scalar type of the matrix type `T` (if <<is_mat,`is_mat<T>::value`>> is `true`).
533
534The expression `scalar<T>::type` is similar, except that it automatically detects whether `T` is a vector or a matrix or a quaternion type.
535
536'''
537
538[[is_quat]]
539==== `is_quat`
540
541.#include <boost/qvm/quat_traits.hpp>
542[source,c++]
543----
544namespace boost { namespace qvm {
545
546  template <class T>
547  struct is_quat {
548
549    static bool const value = false;
550
551  };
552
553} }
554----
555
556This type template defines a compile-time boolean constant value which can be used to determine whether a type `T` is a quaternion type. For quaternion types, the <<quat_traits,`quat_traits`>> template can be used to access their elements generically, or to obtain their `scalar type`.
557
558'''
559
560[[quat_traits]]
561==== `quat_traits`
562
563.#include <boost/qvm/quat_traits.hpp>
564[source,c++]
565----
566namespace boost { namespace qvm {
567
568  template <class Q>
569  struct quat_traits {
570
571    /*main template members unspecified*/
572
573  };
574
575  /*
576  User-defined (possibly partial) specializations:
577
578  template <>
579  struct quat_traits<Q> {
580
581    typedef <<user-defined>> scalar_type;
582
583    template <int I>
584    static inline scalar_type read_element( Quaternion const & q );
585
586    template <int I>
587    static inline scalar_type & write_element( Quaternion & q );
588
589  };
590  */
591
592} }
593----
594
595The `quat_traits` template must be specialized for (user-defined) quaternion types in order to enable quaternion operations defined in QVM headers for objects of those types.
596
597NOTE: QVM quaternion operations do not require that quaternion types are copyable.
598
599The main `quat_traits` template members are not specified. Valid specializations are required to define the following members:
600
601- `scalar_type`: the expression `quat_traits<Quaternion>::scalar_type` must be a value type which satisfies the <<scalar_requirements,`scalar requirements`>>.
602
603In addition, valid specializations of the `quat_traits` template must define at least one of the following access functions as static members, where `q` is an object of type `Quaternion`, and `I` is compile-time integer constant:
604
605- `read_element`: the expression `quat_traits<Quaternion>::read_element<I>(q)` returns either a copy of or a `const` reference to the `I`-th element of `q`.
606
607- `write_element`: the expression `quat_traits<Quaternion>::write_element<I>(q)` returns mutable reference to the `I`-th element of `q`.
608
609NOTE: For the quaternion `a + bi + cj + dk`, the elements are assumed to be in the following order: `a`, `b`, `c`, `d`; that is, `I`=`0`/`1`/`2`/`3` would access `a`/`b`/`c`/`d`.
610
611It is illegal to call any of the above functions unless `is_quat<Quaternion>::value` is true. Even then, quaternion types are allowed to define only a subset of the access functions.
612
613Below is an example of a user-defined quaternion type, and its corresponding specialization of the quat_traits template:
614
615[source,c++]
616----
617#include <boost/qvm/quat_traits.hpp>
618
619struct fquat { float a[4]; };
620
621namespace boost { namespace qvm {
622
623  template <>
624  struct quat_traits<fquat> {
625
626    typedef float scalar_type;
627
628    template <int I>
629    static inline scalar_type & write_element( fquat & q ) {
630      return q.a[I];
631    }
632
633    template <int I>
634    static inline scalar_type read_element( fquat const & q ) {
635      return q.a[I];
636    }
637
638  };
639
640} }
641----
642
643Equivalently, using the <<quat_traits_defaults,`quat_traits_defaults`>> template the above can be shortened to:
644
645[source,c++]
646----
647namespace boost { namespace qvm {
648
649  template <>
650  struct quat_traits<fquat>: quat_traits_defaults<fquat,float> {
651
652    template <int I>
653    static inline scalar_type & write_element( fquat & q ) {
654      return q.a[I];
655    }
656
657  };
658
659} }
660----
661
662'''
663
664[[quat_traits_defaults]]
665==== `quat_traits_defaults`
666
667.#include <boost/qvm/quat_traits_defaults.hpp>
668[source,c++]
669----
670namespace boost { namespace qvm {
671
672  template <class QuatType,class ScalarType>
673  struct quat_traits_defaults {
674
675    typedef QuatType quat_type;
676
677    typedef ScalarType scalar_type;
678
679    template <int I>
680    static BOOST_QVM_INLINE_CRITICAL
681    scalar_type read_element( quat_type const & x ) {
682      return quat_traits<quat_type>::template
683        write_element<I>(const_cast<quat_type &>(x));
684    }
685
686  };
687
688} }
689----
690
691The `quat_traits_defaults` template is designed to be used as a public base for user-defined specializations of the <<quat_traits,`quat_traits`>> template, to easily define the required members. If it is used, the only member that must be defined by the user in a `quat_traits` specialization is `write_element`; the `quat_traits_defaults` base will define `read_element`, as well as `scalar_type` automatically.
692
693'''
694
695[[deduce_quat]]
696==== `deduce_quat`
697
698.#include <boost/qvm/deduce_quat.hpp>
699[source,c++]
700----
701namespace boost { namespace qvm {
702
703  template <class Q>
704  struct deduce_quat {
705    typedef Q type;
706  };
707
708} }
709----
710
711Requirements: ::
712
713- `<<is_quat,is_quat>><Q>::value` is `true`;
714- `<<is_quat,is_quat>><deduce_quat<Q>::type>::value` must be `true`;
715- `deduce_quat<Q>::type` must be copyable.
716
717This template is used by QVM whenever it needs to deduce a copyable quaternion type from a single user-supplied function parameter of quaternion type. Note that `Q` itself may be non-copyable.
718
719The main template definition returns `Q`, which means that it is suitable only for copyable quaternion types. QVM also defines (partial) specializations for the non-copyable quaternion types it produces. Users can define other (partial) specializations for their own types.
720
721A typical use of the `deduce_quat` template is for specifying the preferred quaternion type to be returned by the generic function template overloads in QVM depending on the type of their arguments.
722
723'''
724
725[[deduce_quat2]]
726==== `deduce_quat2`
727
728.#include <boost/qvm/deduce_quat.hpp>
729[source,c++]
730----
731namespace boost { namespace qvm {
732
733  template <class A,class B>
734  struct deduce_quat2 {
735    typedef /*unspecified*/ type;
736  };
737
738} }
739----
740
741Requirements: ::
742
743- Both `<<scalar,scalar>><A>::type` and `scalar<B>::type` are well defined;
744- `<<is_quat,is_quat>><A>::value` || `is_quat<B>::value` is `true`;
745- `is_quat<deduce_quat2<A,B>::type>::value` must be `true`;
746- `deduce_quat2<A,B>::type` must be copyable.
747
748This template is used by QVM whenever it needs to deduce a quaternion type from the types of two user-supplied function parameters. The returned type must have accessible copy constructor (the `A` and `B` types themselves could be non-copyable, and either one of them may not be a quaternion type.)
749
750The main template definition returns an unspecified quaternion type with <<quat_traits,`scalar_type`>> obtained by `<<deduce_scalar,deduce_scalar>><A,B>::type`, except if `A` and `B` are the same quaternion type `Q`, in which case `Q` is returned, which is only suitable for copyable types. QVM also defines (partial) specializations for the non-copyable quaternion types it produces. Users can define other (partial) specializations for their own types.
751
752A typical use of the `deduce_quat2` template is for specifying the preferred quaternion type to be returned by the generic function template overloads in QVM depending on the type of their arguments.
753
754'''
755
756[[is_vec]]
757==== `is_vec`
758
759.#include <boost/qvm/vec_traits.hpp>
760[source,c++]
761----
762namespace boost { namespace qvm {
763
764  template <class T>
765  struct is_vec {
766
767    static bool const value = false;
768
769  };
770
771 } }
772----
773
774This type template defines a compile-time boolean constant value which can be used to determine whether a type `T` is a vector type. For vector types, the <<vec_traits,`vec_traits`>> template can be used to access their elements generically, or to obtain their dimension and `scalar type`.
775
776'''
777
778[[vec_traits]]
779==== `vec_traits`
780
781.#include <boost/qvm/vec_traits.hpp>
782[source,c++]
783----
784namespace boost { namespace qvm {
785
786  template <class V>
787  struct vec_traits {
788
789    /*main template members unspecified*/
790
791  };
792
793  /*
794  User-defined (possibly partial) specializations:
795
796  template <>
797  struct vec_traits<V> {
798
799    static int const dim = <<user-defined>>;
800
801    typedef <<user-defined>> scalar_type;
802
803    template <int I>
804    static inline scalar_type read_element( Vector const & v );
805
806    template <int I>
807    static inline scalar_type & write_element( Vector & v );
808
809    static inline scalar_type read_element_idx( int i, Vector const & v );
810    static inline scalar_type & write_element_idx( int i, Vector & v );
811
812  };
813  */
814
815} }
816----
817
818The `vec_traits` template must be specialized for (user-defined) vector types in order to enable vector and matrix operations defined in QVM headers for objects of those types.
819
820NOTE: QVM vector operations do not require that vector types are copyable.
821
822The main `vec_traits` template members are not specified. Valid specializations are required to define the following members:
823
824- `dim`: the expression `vec_traits<Vector>::dim` must evaluate to a compile-time integer constant greater than 0 that specifies the vector size.
825
826- `scalar_type`: the expression `vec_traits<Vector>::scalar_type` must be a value type which satisfies the <<scalar_requirements,`scalar requirements`>>.
827
828In addition, valid specializations of the `vec_traits` template may define the following access functions as static members, where `v` is an object of type `Vector`, `I` is a compile-time integer constant, and `i` is a variable of type `int`:
829
830- `read_element`: the expression `vec_traits<Vector>::read_element<I>(v)` returns either a copy of or a const reference to the `I`-th element of `v`.
831
832- `write_element`: the expression `vec_traits<Vector>::write_element<I>(v)` returns mutable reference to the `I`-th element of `v`.
833
834- `read_element_idx`: the expression `vec_traits<Vector>::read_element_idx(i,v)` returns either a copy of or a `const` reference to the `i`-th element of `v`.
835
836- `write_element_idx`: the expression `vec_traits<Vector>::write_element_idx(i,v)` returns mutable reference to the `i`-th element of `v`.
837
838It is illegal to call any of the above functions unless `is_vec<Vector>::value` is true. Even then, vector types are allowed to define only a subset of the access functions. The general requirements are:
839
840- At least one of `read_element` or `write_element` must be defined;
841- If `read_element_idx` is defined, `read_element` must also be defined;
842- If `write_element_idx` is defined, `write_element` must also be defined.
843
844Below is an example of a user-defined 3D vector type, and its corresponding specialization of the `vec_traits` template:
845
846[source,c++]
847----
848#include <boost/qvm/vec_traits.hpp>
849
850struct float3 { float a[3]; };
851
852namespace boost { namespace qvm {
853
854  template <>
855  struct vec_traits<float3> {
856
857    static int const dim=3;
858
859    typedef float scalar_type;
860
861    template <int I>
862    static inline scalar_type & write_element( float3 & v ) {
863      return v.a[I];
864    }
865
866    template <int I>
867    static inline scalar_type read_element( float3 const & v ) {
868      return v.a[I];
869    }
870
871    static inline scalar_type & write_element_idx( int i, float3 & v ) {
872      return v.a[i];
873    } //optional
874
875    static inline scalar_type read_element_idx( int i, float3 const & v ) {
876      return v.a[i];
877    } //optional
878
879  };
880
881} }
882----
883
884Equivalently, using the <<vec_traits_defaults,`vec_traits_defaults`>> template the above can be shortened to:
885
886[source,c++]
887----
888namespace boost { namespace qvm {
889
890  template <>
891  struct vec_traits<float3>: vec_traits_defaults<float3,float,3>
892  {
893
894    template <int I>
895    static inline scalar_type & write_element( float3 & v ) {
896      return v.a[I];
897    }
898
899    static inline scalar_type & write_element_idx( int i, float3 & v ) {
900      return v.a[i];
901    } //optional
902
903  };
904
905} }
906----
907
908'''
909
910[[vec_traits_defaults]]
911==== `vec_traits_defaults`
912
913.#include <boost/qvm/vec_traits_defaults.hpp>
914[source,c++]
915----
916namespace boost { namespace qvm {
917
918  template <class VecType,class ScalarType,int Dim>
919  struct vec_traits_defaults {
920
921    typedef VecType vec_type;
922    typedef ScalarType scalar_type;
923    static int const dim=Dim;
924
925    template <int I>
926    static BOOST_QVM_INLINE_CRITICAL
927    scalar_type write_element( vec_type const & x ) {
928      return vec_traits<vec_type>::template write_element<I>(const_cast<vec_type &>(x));
929    }
930
931    static BOOST_QVM_INLINE_CRITICAL
932    scalar_type read_element_idx( int i, vec_type const & x ) {
933      return vec_traits<vec_type>::write_element_idx(i,const_cast<vec_type &>(x));
934    }
935
936    protected:
937
938    static BOOST_QVM_INLINE_TRIVIAL
939    scalar_type & write_element_idx( int i, vec_type & m ) {
940      /* unspecified */
941    }
942  };
943
944} }
945----
946
947The `vec_traits_defaults` template is designed to be used as a public base for user-defined specializations of the <<vec_traits,`vec_traits`>> template, to easily define the required members. If it is used, the only member that must be defined by the user in a `vec_traits` specialization is `write_element`; the `vec_traits_defaults` base will define `read_element`, as well as `scalar_type` and `dim` automatically.
948
949Optionally, the user may also define `write_element_idx`, in which case the `vec_traits_defaults` base will provide a suitable `read_element_idx` definition automatically. If not, `vec_traits_defaults` defines a protected implementation of `write_element_idx` which may be made publicly available by the deriving `vec_traits` specialization in case the vector type for which it is being specialized can not be indexed efficiently. This `write_element_idx` function is less efficient (using meta-programming), implemented in terms of the required user-defined `write_element`.
950
951'''
952
953[[deduce_vec]]
954==== `deduce_vec`
955
956.#include <boost/qvm/deduce_vec.hpp>
957[source,c++]
958----
959namespace boost { namespace qvm {
960
961  template <class V, int Dim=vec_traits<Vector>::dim>
962  struct deduce_vec {
963
964    typedef /*unspecified*/ type;
965
966  };
967
968} }
969----
970
971Requirements: ::
972
973- `<<is_vec,is_vec>><V>::value` is `true`;
974- `is_vec<deduce_vec<V>::type>::value` must be `true`;
975- `deduce_vec<V>::type` must be copyable;
976- `vec_traits<deduce_vec<V>::type>::dim==Dim`.
977
978This template is used by QVM whenever it needs to deduce a copyable vector type of certain dimension from a single user-supplied function parameter of vector type. The returned type must have accessible copy constructor. Note that `V` may be non-copyable.
979
980The main template definition returns an unspecified copyable vector type of size `Dim`, except if `<<vec_traits,vec_traits>><V>::dim==Dim`, in which case it returns `V`, which is suitable only if `V` is a copyable type. QVM also defines (partial) specializations for the non-copyable vector types it produces. Users can define other (partial) specializations for their own types.
981
982A typical use of the `deduce_vec` template is for specifying the preferred vector type to be returned by the generic function template overloads in QVM depending on the type of their arguments.
983
984'''
985
986[[deduce_vec2]]
987==== `deduce_vec2`
988
989.#include <boost/qvm/deduce_vec.hpp>
990[source,c++]
991----
992namespace boost { namespace qvm {
993
994  template <class A,class B,int Dim>
995  struct deduce_vec2 {
996    typedef /*unspecified*/ type;
997  };
998
999} }
1000----
1001
1002Requirements: ::
1003
1004- Both `<<scalar,scalar>><A>::type` and `scalar<B>::type` are well defined;
1005- `<<is_vec,is_vec>><A>::value || is_vec<B>::value` is `true`;
1006- `is_vec<deduce_vec2<A,B>::type>::value` must be `true`;
1007- `deduce_vec2<A,B>::type` must be copyable;
1008- `vec_traits<deduce_vec2<A,B>::type>::dim==Dim`.
1009
1010This template is used by QVM whenever it needs to deduce a vector type of certain dimension from the types of two user-supplied function parameters. The returned type must have accessible copy constructor (the `A` and `B` types themselves could be non-copyable, and either one of them may not be a vector type.)
1011
1012The main template definition returns an unspecified vector type of the requested dimension with <<vec_traits,`scalar_type`>> obtained by `<<deduce_scalar,deduce_scalar>><A,B>::type`, except if `A` and `B` are the same vector type `V` of dimension `Dim`, in which case `V` is returned, which is only suitable for copyable types. QVM also defines (partial) specializations for the non-copyable vector types it produces. Users can define other (partial) specializations for their own types.
1013
1014A typical use of the `deduce_vec2` template is for specifying the preferred vector type to be returned by the generic function template overloads in QVM depending on the type of their arguments.
1015
1016'''
1017
1018[[is_mat]]
1019==== `is_mat`
1020
1021.#include <boost/qvm/mat_traits.hpp>
1022[source,c++]
1023----
1024namespace boost { namespace qvm {
1025
1026  template <class T>
1027  struct is_mat {
1028
1029    static bool const value = false;
1030
1031  };
1032
1033} }
1034----
1035
1036This type template defines a compile-time boolean constant value which can be used to determine whether a type `T` is a matrix type. For matrix types, the <<mat_traits,`mat_traits`>> template can be used to access their elements generically, or to obtain their dimensions and scalar type.
1037
1038'''
1039
1040[[mat_traits]]
1041==== `mat_traits`
1042
1043.#include <boost/qvm/mat_traits.hpp>
1044[source,c++]
1045----
1046namespace boost { namespace qvm {
1047
1048  template <class M>
1049  struct mat_traits {
1050
1051    /*main template members unspecified*/
1052
1053  };
1054
1055  /*
1056  User-defined (possibly partial) specializations:
1057
1058  template <>
1059  struct mat_traits<M> {
1060
1061    static int const rows = <<user-defined>>;
1062    static int const cols = <<user-defined>>;
1063    typedef <<user-defined>> scalar_type;
1064
1065    template <int R,int C>
1066    static inline scalar_type read_element( Matrix const & m );
1067
1068    template <int R,int C>
1069    static inline scalar_type & write_element( Matrix & m );
1070
1071    static inline scalar_typeread_element_idx( int r, int c, Matrix const & m );
1072    static inline scalar_type & write_element_idx( int r, int c, Matrix & m );
1073
1074  };
1075  */
1076
1077} }
1078----
1079
1080The `mat_traits` template must be specialized for (user-defined) matrix types in order to enable vector and matrix operations defined in QVM headers for objects of those types.
1081
1082NOTE: The matrix operations defined by QVM do not require matrix types to be copyable.
1083
1084The main `mat_traits` template members are not specified. Valid specializations are required to define the following members:
1085
1086- `rows`: the expression `mat_traits<Matrix>::rows` must evaluate to a compile-time integer constant greater than 0 that specifies the number of rows in a matrix.
1087- `cols` must evaluate to a compile-time integer constant greater than 0 that specifies the number of columns in a matrix.
1088- `scalar_type`: the expression `mat_traits<Matrix>::scalar_type` must be a value type which satisfies the scalar requirements.
1089
1090In addition, valid specializations of the `mat_traits` template may define the following access functions as static members, where `m` is an object of type `Matrix`, `R` and `C` are compile-time integer constants, and `r` and `c` are variables of type `int`:
1091
1092- `read_element`: the expression `mat_traits<Matrix>::read_element<R,C>(m)` returns either a copy of or a const reference to the element at row `R` and column `C` of `m`.
1093- `write_element`: the expression `mat_traits<Matrix>::write_element<R,C>(m)` returns mutable reference to the element at row `R` and column `C` of `m`.
1094- `read_element_idx`: the expression `mat_traits<Matrix>::read_element_idx(r,c,m)` returns either a copy of or a const reference to the element at row `r` and column `c` of `m`.
1095- `write_element_idx`: the expression `mat_traits<Matrix>::write_element_idx(r,c,m)` returns mutable reference to the element at row `r` and column `c` of `m`.
1096
1097It is illegal to call any of the above functions unless `is_mat<Matrix>::value` is true. Even then, matrix types are allowed to define only a subset of the access functions. The general requirements are:
1098
1099- At least one of `read_element` or `write_element` must be defined;
1100- If `read_element_idx` is defined, `read_element` must also be defined;
1101- If `write_element_idx` is defined, `write_element` must also be defined.
1102
1103Below is an example of a user-defined 3x3 matrix type, and its corresponding specialization of the `mat_traits` template:
1104
1105[source,c++]
1106----
1107#include <boost/qvm/mat_traits.hpp>
1108
1109struct float33 { float a[3][3]; };
1110
1111namespace boost { namespace qvm {
1112
1113  template <>
1114  struct mat_traits<float33> {
1115
1116    static int const rows=3;
1117    static int const cols=3;
1118    typedef float scalar_type;
1119
1120    template <int R,int C>
1121    static inline scalar_type & write_element( float33 & m ) {
1122      return m.a[R][C];
1123    }
1124
1125    template <int R,int C>
1126    static inline scalar_type read_element( float33 const & m ) {
1127      return m.a[R][C];
1128    }
1129
1130    static inline scalar_type & write_element_idx( int r, int c, float33 & m ) {
1131      return m.a[r][c];
1132    }
1133
1134    static inline scalar_type read_element_idx( int r, int c, float33 const & m ) {
1135      return m.a[r][c];
1136    }
1137
1138  };
1139
1140} }
1141----
1142
1143Equivalently, we could use the <<mat_traits_defaults,`mat_traits_defaults` template to shorten the above to:
1144
1145[source,c++]
1146----
1147namespace boost { namespace qvm {
1148
1149  template <>
1150  struct mat_traits<float33>: mat_traits_defaults<float33,float,3,3> {
1151
1152    template <int R,int C> static inline scalar_type & write_element( float33 & m ) { return m.a[R][C]; }
1153
1154    static inline scalar_type & write_element_idx( int r, int c, float33 & m ) {
1155      return m.a[r][c];
1156    }
1157
1158  };
1159
1160} }
1161----
1162
1163'''
1164
1165[[mat_traits_defaults]]
1166==== `mat_traits_defaults`
1167
1168.#include <boost/qvm/mat_traits_defaults.hpp>
1169[source,c++]
1170----
1171namespace boost { namespace qvm {
1172
1173  template <class MatType,class ScalarType,int Rows,int Cols>
1174  struct mat_traits_defaults
1175  {
1176    typedef MatType mat_type;
1177    typedef ScalarType scalar_type;
1178    static int const rows=Rows;
1179    static int const cols=Cols;
1180
1181    template <int Row,int Col>
1182    static BOOST_QVM_INLINE_CRITICAL
1183    scalar_type write_element( mat_type const & x ) {
1184      return mat_traits<mat_type>::template write_element<Row,Col>(const_cast<mat_type &>(x));
1185    }
1186
1187    static BOOST_QVM_INLINE_CRITICAL
1188    scalar_type read_element_idx( int r, int c, mat_type const & x ) {
1189      return mat_traits<mat_type>::write_element_idx(r,c,const_cast<mat_type &>(x));
1190    }
1191
1192    protected:
1193
1194    static BOOST_QVM_INLINE_TRIVIAL
1195    scalar_type & write_element_idx( int r, int c, mat_type & m ) {
1196      /* unspecified */
1197    }
1198  };
1199
1200} }
1201----
1202
1203The `mat_traits_defaults` template is designed to be used as a public base for user-defined specializations of the <<mat_traits,`mat_traits`>> template, to easily define the required members. If it is used, the only member that must be defined by the user in a `mat_traits` specialization is `write_element`; the `mat_traits_defaults` base will define `read_element`, as well as `scalar_type`, `rows` and `cols` automatically.
1204
1205Optionally, the user may also define `write_element_idx`, in which case the `mat_traits_defaults` base will provide a suitable `read_element_idx` definition automatically. Otherwise, `mat_traits_defaults` defines a protected implementation of `write_element_idx` which may be made publicly available by the deriving `mat_traits` specialization in case the matrix type for which it is being specialized can not be indexed efficiently. This `write_element_idx` function is less efficient (using meta-programming), implemented in terms of the required user-defined `write_element`.
1206
1207'''
1208
1209[[deduce_mat]]
1210==== `deduce_mat`
1211
1212.#include <boost/qvm/deduce_mat.hpp>
1213[source,c++]
1214----
1215namespace boost { namespace qvm {
1216
1217  template <
1218    class M,
1219    int Rows=mat_traits<Matrix>::rows,
1220    int Cols=mat_traits<Matrix>::cols>
1221  struct deduce_mat {
1222
1223    typedef /*unspecified*/ type;
1224
1225  };
1226
1227} }
1228----
1229
1230Requirements: ::
1231
1232- `<<is_mat,is_mat>><M>::value` is `true`;
1233- `is_mat<deduce_mat<M>::type>::value` must be `true`;
1234- `deduce_mat<M>::type` must be copyable;
1235- `<<mat_traits,mat_traits>><deduce_mat<M>::type>::rows==Rows`;
1236- `mat_traits<deduce_mat<M>::type>::cols==Cols`.
1237
1238This template is used by QVM whenever it needs to deduce a copyable matrix type of certain dimensions from a single user-supplied function parameter of matrix type. The returned type must have accessible copy constructor. Note that M itself may be non-copyable.
1239
1240The main template definition returns an unspecified copyable matrix type of size `Rows` x `Cols`, except if `<<mat_traits,mat_traits>><M>::rows==Rows && mat_traits<M>::cols==Cols`, in which case it returns `M`, which is suitable only if `M` is a copyable type. QVM also defines (partial) specializations for the non-copyable matrix types it produces. Users can define other (partial) specializations for their own types.
1241
1242A typical use of the deduce_mat template is for specifying the preferred matrix type to be returned by the generic function template overloads in QVM depending on the type of their arguments.
1243
1244'''
1245
1246[[deduce_mat2]]
1247==== `deduce_mat2`
1248
1249.#include <boost/qvm/deduce_mat.hpp>
1250[source,c++]
1251----
1252namespace boost { namespace qvm {
1253
1254  template <class A,class B,int Rows,int Cols>
1255  struct deduce_mat2 {
1256
1257    typedef /*unspecified*/ type;
1258
1259  };
1260
1261} }
1262----
1263
1264Requirements: ::
1265
1266- Both `<<scalar,scalar>><A>::type` and `scalar<B>::type` are well defined;
1267- `<<is_mat,is_mat>><A>::value || is_mat<B>::value` is `true`;
1268- `is_mat<deduce_mat2<A,B>::type>::value` must be `true`;
1269- `deduce_mat2<A,B>::type` must be copyable;
1270- `<<mat_traits,mat_traits>><deduce_mat2<A,B>::type>::rows==Rows`;
1271- `mat_traits<deduce_mat2<A,B>::type>::cols==Cols`.
1272
1273This template is used by QVM whenever it needs to deduce a matrix type of certain dimensions from the types of two user-supplied function parameters. The returned type must have accessible copy constructor (the `A` and `B` types themselves could be non-copyable, and either one of them may be a non-matrix type.)
1274
1275The main template definition returns an unspecified matrix type of the requested dimensions with <<mat_traits,`scalar_type`>> obtained by `<<deduce_scalar,deduce_scalar>><A,B>::type`, except if `A` and `B` are the same matrix type `M` of dimensions `Rows` x `Cols`, in which case `M` is returned, which is only suitable for copyable types. QVM also defines (partial) specializations for the non-copyable matrix types it produces. Users can define other (partial) specializations for their own types.
1276
1277A typical use of the `deduce_mat2` template is for specifying the preferred matrix type to be returned by the generic function template overloads in QVM depending on the type of their arguments.
1278
1279'''
1280
1281=== Built-in Quaternion, Vector and Matrix Types
1282
1283QVM defines several class templates (together with appropriate specializations of <<quat_traits,`quat_traits`>>, <<vec_traits,`vec_traits`>> and <<mat_traits,`mat_traits`>> templates) which can be used as generic quaternion, vector and matrix types. Using these types directly wouldn't be typical though, the main design goal of QVM is to allow users to plug in their own quaternion, vector and matrix types.
1284
1285[[quat]]
1286==== `quat`
1287
1288.#include <boost/qvm/quat.hpp>
1289[source,c++]
1290----
1291namespace boost { namespace qvm {
1292
1293    template <class T>
1294    struct quat {
1295
1296      T a[4];
1297
1298      template <class R>
1299      operator R() const {
1300        R r;
1301        assign(r,*this);
1302        return r;
1303      }
1304
1305    };
1306
1307    template <class Quaternion>
1308    struct quat_traits;
1309
1310    template <class T>
1311    struct quat_traits< quat<T> > {
1312
1313      typedef T scalar_type;
1314
1315      template <int I>
1316      static scalar_type read_element( quat<T> const & x ) {
1317        return x.a[I];
1318      }
1319
1320      template <int I>
1321      static scalar_type & write_element( quat<T> & x ) {
1322        return x.a[I];
1323      }
1324
1325    };
1326
1327} }
1328----
1329
1330This is a simple quaternion type. It converts to any other quaternion type.
1331
1332The partial specialization of the <<quat_traits,`quat_traits`>> template makes the `quat` template compatible with the generic operations defined by QVM.
1333
1334'''
1335
1336[[vec]]
1337==== `vec`
1338
1339.#include <boost/qvm/vec.hpp>
1340[source,c++]
1341----
1342namespace boost { namespace qvm {
1343
1344    template <class T,int Dim>
1345    struct vec {
1346
1347      T a[Dim];
1348
1349      template <class R>
1350      operator R() const {
1351        R r;
1352        assign(r,*this);
1353        return r;
1354      }
1355
1356    };
1357
1358    template <class Vector>
1359    struct vec_traits;
1360
1361    template <class T,int Dim>
1362    struct vec_traits< vec<T,Dim> > {
1363
1364      typedef T scalar_type;
1365      static int const dim=Dim;
1366
1367      template <int I>
1368      static scalar_type read_element( vec<T,Dim> const & x ) {
1369        return x.a[I];
1370      }
1371
1372      template <int I>
1373      static scalar_type & write_element( vec<T,Dim> & x ) {
1374        return x.a[I];
1375      }
1376
1377      static scalar_type read_element_idx( int i, vec<T,Dim> const & x ) {
1378        return x.a[i];
1379      }
1380
1381      static scalar_type & write_element_idx( int i, vec<T,Dim> & x ) {
1382        return x.a[i];
1383      }
1384    };
1385
1386} }
1387----
1388
1389This is a simple vector type. It converts to any other vector type of compatible size.
1390
1391The partial specialization of the <<vec_traits,`vec_traits`>> template makes the `vec` template compatible with the generic operations defined by QVM.
1392
1393'''
1394
1395[[mat]]
1396==== `mat`
1397
1398.#include <boost/qvm/mat.hpp>
1399[source,c++]
1400----
1401namespace boost { namespace qvm {
1402
1403  template <class T,int Rows,int Cols>
1404  struct mat {
1405
1406    T a[Rows][Cols];
1407
1408    template <class R>
1409    operator R() const {
1410      R r;
1411      assign(r,*this);
1412      return r;
1413    }
1414
1415  };
1416
1417  template <class Matrix>
1418  struct mat_traits;
1419
1420  template <class T,int Rows,int Cols>
1421  struct mat_traits< mat<T,Rows,Cols> > {
1422
1423    typedef T scalar_type;
1424    static int const rows=Rows;
1425    static int const cols=Cols;
1426
1427    template <int Row,int Col>
1428    static scalar_type read_element( mat<T,Rows,Cols> const & x ) {
1429      return x.a[Row][Col];
1430    }
1431
1432    template <int Row,int Col>
1433    static scalar_type & write_element( mat<T,Rows,Cols> & x ) {
1434      return x.a[Row][Col];
1435    }
1436
1437    static scalar_type read_element_idx( int row, int col, mat<T,Rows,Cols> const & x ) {
1438      return x.a[row][col];
1439    }
1440
1441    static scalar_type & write_element_idx( int row, int col, mat<T,Rows,Cols> & x ) {
1442      return x.a[row][col];
1443    }
1444
1445  };
1446
1447} }
1448----
1449
1450This is a simple matrix type. It converts to any other matrix type of compatible size.
1451
1452The partial specialization of the <<mat_traits,`mat_traits`>> template makes the `mat` template compatible with the generic operations defined by QVM.
1453
1454'''
1455
1456=== Element Access
1457
1458[[quat_access]]
1459==== Quaternions
1460
1461.#include <boost/qvm/quat_access.hpp>
1462[source,c++]
1463----
1464namespace boost { namespace qvm {
1465
1466  //Only enabled if:
1467  //  is_quat<Q>::value
1468
1469  template <class Q> -unspecified-return-type- S( Q & q );
1470  template <class Q> -unspecified-return-type- V( Q & q );
1471  template <class Q> -unspecified-return-type- X( Q & q );
1472  template <class Q> -unspecified-return-type- Y( Q & q );
1473  template <class Q> -unspecified-return-type- Z( Q & q );
1474
1475} }
1476----
1477
1478An expression of the form `S(q)` can be used to access the scalar component of the quaternion `q`. For example,
1479
1480[source,c++]
1481----
1482S(q) *= 42;
1483----
1484
1485multiplies the scalar component of `q` by the scalar 42.
1486
1487An expression of the form `V(q)` can be used to access the vector component of the quaternion `q`. For example,
1488
1489[source,c++]
1490----
1491V(q) *= 42
1492----
1493
1494multiplies the vector component of `q` by the scalar 42.
1495
1496The `X`, `Y` and `Z` elements of the vector component can also be accessed directly using `X(q)`, `Y(q)` and `Z(q)`.
1497
1498TIP: The return types are lvalues.
1499
1500[[vec_access]]
1501==== Vectors
1502
1503.#include <boost/qvm/vec_access.hpp>
1504[source,c++]
1505----
1506namespace boost { namespace qvm {
1507
1508  //Only enabled if:
1509  //  is_vec<V>::value
1510
1511  template <int I,class V> -unspecified-return-type- A( V & v );
1512  template <class V> -unspecified-return-type- A0( V & v );
1513  template <class V> -unspecified-return-type- A1( V & v );
1514  ...
1515  template <class V> -unspecified-return-type- A9( V & v );
1516
1517  template <class V> -unspecified-return-type- X( V & v );
1518  template <class V> -unspecified-return-type- Y( V & v );
1519  template <class V> -unspecified-return-type- Z( V & v );
1520  template <class V> -unspecified-return-type- W( V & v );
1521
1522} }
1523----
1524
1525An expression of the form of `A<I>(v)` can be used to access the `I`-th element a vector object `v`. For example, the expression:
1526
1527[source,c++]
1528----
1529A<1>(v) *= 42;
1530----
1531
1532can be used to multiply the element at index 1 (indexing in QVM is always zero-based) of a vector `v` by 42.
1533
1534For convenience, there are also non-template overloads for `I` from 0 to 9; an alternative way to write the above expression is:
1535
1536[source,c++]
1537----
1538A1(v) *= 42;
1539----
1540
1541`X`, `Y`, `Z` and `W` act the same as `A0`/`A1`/`A2`/`A3`; yet another alternative way to write the above expression is:
1542
1543[source,c++]
1544----
1545Y(v) *= 42;
1546----
1547
1548TIP: The return types are lvalues.
1549
1550[[swizzling]]
1551==== Vector Element Swizzling
1552
1553.#include <boost/qvm/swizzle.hpp>
1554[source,c++]
1555----
1556namespace boost { namespace qvm {
1557
1558  //*** Accessing vector elements by swizzling ***
1559
1560  //2D view proxies, only enabled if:
1561  //  is_vec<V>::value
1562  template <class V> -unspecified-2D-vector-type- XX( V & v );
1563  template <class V> -unspecified-2D-vector-type- XY( V & v );
1564  template <class V> -unspecified-2D-vector-type- XZ( V & v );
1565  template <class V> -unspecified-2D-vector-type- XW( V & v );
1566  template <class V> -unspecified-2D-vector-type- X0( V & v );
1567  template <class V> -unspecified-2D-vector-type- X1( V & v );
1568  template <class V> -unspecified-2D-vector-type- YX( V & v );
1569  template <class V> -unspecified-2D-vector-type- YY( V & v );
1570  template <class V> -unspecified-2D-vector-type- YZ( V & v );
1571  template <class V> -unspecified-2D-vector-type- YW( V & v );
1572  template <class V> -unspecified-2D-vector-type- Y0( V & v );
1573  template <class V> -unspecified-2D-vector-type- Y1( V & v );
1574  template <class V> -unspecified-2D-vector-type- ZX( V & v );
1575  template <class V> -unspecified-2D-vector-type- ZY( V & v );
1576  template <class V> -unspecified-2D-vector-type- ZZ( V & v );
1577  template <class V> -unspecified-2D-vector-type- ZW( V & v );
1578  template <class V> -unspecified-2D-vector-type- Z0( V & v );
1579  template <class V> -unspecified-2D-vector-type- Z1( V & v );
1580  template <class V> -unspecified-2D-vector-type- WX( V & v );
1581  template <class V> -unspecified-2D-vector-type- WY( V & v );
1582  template <class V> -unspecified-2D-vector-type- WZ( V & v );
1583  template <class V> -unspecified-2D-vector-type- WW( V & v );
1584  template <class V> -unspecified-2D-vector-type- W0( V & v );
1585  template <class V> -unspecified-2D-vector-type- W1( V & v );
1586  ...
1587  //2D view proxies, only enabled if:
1588  //  is_scalar<S>::value
1589  template <class S> -unspecified-2D-vector-type- X0( S & s );
1590  template <class S> -unspecified-2D-vector-type- X1( S & s );
1591  template <class S> -unspecified-2D-vector-type- XX( S & s );
1592  ...
1593  -unspecified-2D-vector-type- _00();
1594  -unspecified-2D-vector-type- _01();
1595  -unspecified-2D-vector-type- _10();
1596  -unspecified-2D-vector-type- _11();
1597
1598  //3D view proxies, only enabled if:
1599  //  is_vec<V>::value
1600  template <class V> -unspecified-3D-vector-type- XXX( V & v );
1601  ...
1602  template <class V> -unspecified-3D-vector-type- XXW( V & v );
1603  template <class V> -unspecified-3D-vector-type- XX0( V & v );
1604  template <class V> -unspecified-3D-vector-type- XX1( V & v );
1605  template <class V> -unspecified-3D-vector-type- XYX( V & v );
1606  ...
1607  template <class V> -unspecified-3D-vector-type- XY1( V & v );
1608  ...
1609  template <class V> -unspecified-3D-vector-type- WW1( V & v );
1610  ...
1611  //3D view proxies, only enabled if:
1612  //  is_scalar<S>::value
1613  template <class S> -unspecified-3D-vector-type- X00( S & s );
1614  template <class S> -unspecified-3D-vector-type- X01( S & s );
1615  ...
1616  template <class S> -unspecified-3D-vector-type- XXX( S & s );
1617  template <class S> -unspecified-3D-vector-type- XX0( S & s );
1618  ...
1619  -unspecified-3D-vector-type- _000();
1620  -unspecified-3D-vector-type- _001();
1621  -unspecified-3D-vector-type- _010();
1622  ...
1623  -unspecified-3D-vector-type- _111();
1624
1625  //4D view proxies, only enabled if:
1626  //  is_vec<V>::value
1627  template <class V> -unspecified-4D-vector-type- XXXX( V & v );
1628  ...
1629  template <class V> -unspecified-4D-vector-type- XXXW( V & v );
1630  template <class V> -unspecified-4D-vector-type- XXX0( V & v );
1631  template <class V> -unspecified-4D-vector-type- XXX1( V & v );
1632  template <class V> -unspecified-4D-vector-type- XXYX( V & v );
1633  ...
1634  template <class V> -unspecified-4D-vector-type- XXY1( V & v );
1635  ...
1636  template <class V> -unspecified-4D-vector-type- WWW1( V & v );
1637  ...
1638  //4D view proxies, only enabled if:
1639  //  is_scalar<S>::value
1640  template <class S> -unspecified-4D-vector-type- X000( S & s );
1641  template <class S> -unspecified-4D-vector-type- X001( S & s );
1642  ...
1643  template <class S> -unspecified-4D-vector-type- XXXX( S & s );
1644  template <class S> -unspecified-4D-vector-type- XX00( S & s );
1645  ...
1646  -unspecified-4D-vector-type- _0000();
1647  -unspecified-4D-vector-type- _0001();
1648  -unspecified-4D-vector-type- _0010();
1649  ...
1650  -unspecified-4D-vector-type- _1111();
1651
1652} }
1653----
1654
1655Swizzling allows zero-overhead direct access to a (possibly rearranged) subset of the elements of 2D, 3D and 4D vectors. For example, if `v` is a 4D vector, the expression `YX(v) is a 2D view proxy whose `X` element refers to the `Y` element of `v`, and whose `Y` element refers to the `X` element of `v`. Like other view proxies `YX` is an lvalue, that is, if `v2` is a 2D vector, one could write:
1656
1657[source,c++]
1658----
1659YX(v) = v2;
1660----
1661
1662The above will leave the `Z` and `W` elements of `v` unchanged but assign the `Y` element of `v2` to the `X` element of `v` and the `X` element of `v2` to the `Y` element of `v`.
1663
1664All permutations of `X`, `Y`, `Z`, `W`, `0`, `1` for 2D, 3D and 4D swizzling are available (if the first character of the swizzle identifier is `0` or `1`, it is preceded by a `_`, for example `_11XY`).
1665
1666It is valid to use the same vector element more than once: the expression `ZZZ(v)` is a 3D vector whose `X`, `Y` and `Z` elements all refer to the `Z` element of `v`.
1667
1668Finally, scalars can be "swizzled" to access them as vectors: the expression `_0X01(42.0f)` is a 4D vector with `X`=0, `Y`=42.0, `Z`=0, `W`=1.
1669
1670[[mat_access]]
1671==== Matrices
1672
1673.#include <boost/qvm/mat_access.hpp>
1674[source,c++]
1675----
1676namespace boost { namespace qvm {
1677
1678  //Only enabled if:
1679  //  is_quat<Q>::value
1680
1681  template <int R,int C,class M> -unspecified-return-type- A( M & m );
1682
1683  template <class M> -unspecified-return-type- A00( M & m );
1684  template <class M> -unspecified-return-type- A01( M & m );
1685  ...
1686  template <class M> -unspecified-return-type- A09( M & m );
1687  template <class M> -unspecified-return-type- A10( M & m );
1688  ...
1689  template <class M> -unspecified-return-type- A99( M & m );
1690
1691} }
1692----
1693
1694An expression of the form `A<R,C>(m)` can be used to access the element at row `R` and column `C` of a matrix object `m`. For example, the expression:
1695
1696[source,c++]
1697----
1698A<4,2>(m) *= 42;
1699----
1700
1701can be used to multiply the element at row 4 and column 2 of a matrix `m` by 42.
1702
1703For convenience, there are also non-template overloads for `R` from `0` to `9` and `C` from `0` to `9`; an alternative way to write the above expression is:
1704
1705[source,c++]
1706----
1707A42(m) *= 42;
1708----
1709
1710TIP: The return types are lvalues.
1711
1712'''
1713
1714=== Quaternion Operations
1715
1716[[quat_assign]]
1717==== `assign`
1718
1719.#include <boost/qvm/quat_operations.hpp>
1720[source,c++]
1721----
1722namespace boost { namespace qvm {
1723
1724  //Only enabled if:
1725  //  is_quat<A>::value && is_quat<B>::value
1726  template <class A,class B>
1727  A & assign( A & a, B const & b );
1728
1729} }
1730----
1731
1732Effects: :: Copies all elements of the quaternion `b` to the quaternion `a`.
1733
1734Returns: :: `a`.
1735
1736'''
1737
1738[[quat_convert_to]]
1739==== `convert_to`
1740
1741.#include <boost/qvm/quat_operations.hpp>
1742[source,c++]
1743----
1744namespace boost { namespace qvm {
1745
1746  //Only enabled if:
1747  //  is_quat<R>::value && is_quat<A>::value
1748  template <class R,class A>
1749  R convert_to( A const & a );
1750
1751  //Only enabled if:
1752  //  is_quat<R>::value && is_mat<A>::value &&
1753  //  mat_traits<A>::rows==3 && mat_traits<A>::cols==3
1754  template <class R,class A>
1755  R convert_to( A const & m );
1756
1757} }
1758----
1759
1760Requirements: :: `R` must be copyable.
1761
1762Effects: ::
1763
1764- The first overload is equivalent to: `R r; assign(r,a); return r;`
1765
1766- The second overload assumes that `m` is an orthonormal rotation matrix and converts it to a quaternion that performs the same rotation.
1767
1768'''
1769
1770[[quat_minus_eq]]
1771==== `operator-=`
1772
1773.#include <boost/qvm/quat_operations.hpp>
1774[source,c++]
1775----
1776namespace boost { namespace qvm {
1777
1778  //Only enabled if:
1779  //  is_quat<A>::value && is_quat<B>::value
1780  template <class A,class B>
1781  A & operator-=( A & a, B const & b );
1782
1783} }
1784----
1785
1786Effects: :: Subtracts the elements of `b` from the corresponding elements of `a`.
1787
1788Returns: :: `a`.
1789
1790'''
1791
1792[[quat_minus_unary]]
1793==== `operator-` (unary)
1794
1795.#include <boost/qvm/quat_operations.hpp>
1796[source,c++]
1797----
1798namespace boost { namespace qvm {
1799
1800   //Only enabled if: is_quat<A>::value
1801  template <class A>
1802  typename deduce_quat<A>::type
1803  operator-( A const & a );
1804
1805} }
1806
1807----
1808
1809Returns: :: A quaternion of the negated elements of `a`.
1810
1811NOTE: The <<deduce_quat,`deduce_quat`>> template can be specialized to deduce the desired return type from the type `A`.
1812
1813'''
1814
1815[[quat_minus]]
1816==== `operator-` (binary)
1817
1818.#include <boost/qvm/quat_operations.hpp>
1819[source,c++]
1820----
1821namespace boost { namespace qvm {
1822
1823  //Only enabled if:
1824  //  is_quat<A>::value && is_quat<B>::value
1825  template <class A,class B>
1826  typename deduce_quat2<A,B>::type
1827  operator-( A const & a, B const & b );
1828
1829} }
1830
1831----
1832
1833Returns: :: A quaternion with elements equal to the elements of `b` subtracted from the corresponding elements of `a`.
1834
1835NOTE: The <<deduce_quat2,`deduce_quat2`>> template can be specialized to deduce the desired return type, given the types `A` and `B`.
1836
1837'''
1838
1839[[quat_plus_eq]]
1840==== `operator+=`
1841
1842.#include <boost/qvm/quat_operations.hpp>
1843[source,c++]
1844----
1845namespace boost { namespace qvm {
1846
1847  //Only enabled if:
1848  //  is_quat<A>::value && is_quat<B>::value
1849  template <class A,class B>
1850  A & operator+=( A & a, B const & b );
1851
1852} }
1853----
1854
1855Effects: :: Adds the elements of `b` to the corresponding elements of `a`.
1856
1857Returns: :: `a`.
1858
1859'''
1860
1861[[quat_plus]]
1862==== `operator+`
1863
1864.#include <boost/qvm/quat_operations.hpp>
1865[source,c++]
1866----
1867namespace boost { namespace qvm {
1868
1869  //Only enabled if:
1870  //  is_quat<A>::value && is_quat<B>::value &&
1871  template <class A,class B>
1872  typename deduce_quat2<A,B>::type
1873  operator+( A const & a, B const & b );
1874
1875} }
1876----
1877
1878Returns: :: A quaternion with elements equal to the elements of `a` added to the corresponding elements of `b`.
1879
1880NOTE: The <<deduce_quat2,`deduce_quat2`>> template can be specialized to deduce the desired return type, given the types `A` and `B`.
1881
1882'''
1883
1884[[quat_div_eq_scalar]]
1885==== `operator/=` (scalar)
1886
1887.#include <boost/qvm/quat_operations.hpp>
1888[source,c++]
1889----
1890namespace boost { namespace qvm {
1891
1892  //Only enabled if: is_quat<A>::value && is_scalar<B>::value
1893  template <class A,class B>
1894  A & operator/=( A & a, B b );
1895
1896} }
1897----
1898
1899Effects: :: This operation divides a quaternion by a scalar.
1900
1901Returns: :: `a`.
1902
1903'''
1904
1905[[quat_div_scalar]]
1906==== `operator/` (scalar)
1907
1908.#include <boost/qvm/quat_operations.hpp>
1909[source,c++]
1910----
1911namespace boost { namespace qvm {
1912
1913  //Only enabled if: is_quat<A>::value && is_scalar<B>::value
1914  template <class A,class B>
1915  typename deduce_quat<A>::type
1916  operator/( A const & a, B b );
1917
1918} }
1919----
1920
1921Returns: :: A quaternion that is the result of dividing the quaternion `a` by the scalar `b`.
1922
1923NOTE: The <<deduce_quat,`deduce_quat`>> template can be specialized to deduce the desired return type from the type `A`.
1924
1925'''
1926
1927[[quat_mul_eq_scalar]]
1928==== `operator*=` (scalar)
1929
1930.#include <boost/qvm/quat_operations.hpp>
1931[source,c++]
1932----
1933namespace boost { namespace qvm {
1934
1935  //Only enabled if: is_quat<A>::value && is_scalar<B>::value
1936  template <class A,class B>
1937  A & operator*=( A & a, B b );
1938
1939} }
1940----
1941
1942Effects: :: This operation multiplies the quaternion `a` by the scalar `b`.
1943
1944Returns: :: `a`.
1945
1946'''
1947
1948[[quat_mul_eq]]
1949==== `operator*=`
1950
1951.#include <boost/qvm/quat_operations.hpp>
1952[source,c++]
1953----
1954namespace boost { namespace qvm {
1955
1956  //Only enabled if:
1957  //  is_quat<A>::value && is_quat<B>::value
1958  template <class A,class B>
1959  A & operator*=( A & a, B const & b );
1960
1961} }
1962----
1963
1964Effects: :: As if:
1965+
1966[source,c++]
1967----
1968A tmp(a);
1969a = tmp * b;
1970return a;
1971----
1972
1973'''
1974
1975[[quat_mul_scalar]]
1976==== `operator*` (scalar)
1977
1978.#include <boost/qvm/quat_operations.hpp>
1979[source,c++]
1980----
1981namespace boost { namespace qvm {
1982
1983  //Only enabled if: is_quat<A>::value && is_scalar<B>::value
1984  template <class A,class B>
1985  typename deduce_quat<A>::type
1986  operator*( A const & a, B b );
1987
1988} }
1989----
1990
1991Returns: :: A quaternion that is the result of multiplying the quaternion `a` by the scalar `b`.
1992
1993NOTE: The <<deduce_quat,`deduce_quat`>> template can be specialized to deduce the desired return type from the type `A`.
1994
1995'''
1996
1997[[quat_mul]]
1998==== `operator*`
1999
2000.#include <boost/qvm/quat_operations.hpp>
2001[source,c++]
2002----
2003namespace boost { namespace qvm {
2004
2005  //Only enabled if:
2006  //  is_quat<A>::value && is_quat<B>::value
2007  template <class A,class B>
2008  typename deduce_quat2<A,B>::type
2009  operator*( A const & a, B const & b );
2010
2011} }
2012----
2013
2014Returns: :: The result of multiplying the quaternions `a` and `b`.
2015
2016NOTE: The <<deduce_quat2,`deduce_quat2`>> template can be specialized to deduce the desired return type, given the types `A` and `B`.
2017
2018'''
2019
2020[[quat_eq]]
2021==== `operator==`
2022
2023.#include <boost/qvm/quat_operations.hpp>
2024[source,c++]
2025----
2026namespace boost { namespace qvm {
2027
2028  //Only enabled if:
2029  //  is_quat<A>::value && is_quat<B>::value
2030  template <class A,class B>
2031  bool operator==( A const & a, B const & b );
2032
2033} }
2034----
2035
2036Returns: :: `true` if each element of `a` compares equal to its corresponding element of `b`, `false` otherwise.
2037
2038'''
2039
2040[[quat_neq]]
2041==== `operator!=`
2042
2043.#include <boost/qvm/quat_operations.hpp>
2044[source,c++]
2045----
2046namespace boost { namespace qvm {
2047
2048  //Only enabled if:
2049  //  is_quat<A>::value && is_quat<B>::value
2050  template <class A,class B>
2051  bool operator!=( A const & a, B const & b );
2052
2053} }
2054----
2055
2056Returns: :: `!(a == b)`.
2057
2058'''
2059
2060[[quat_cmp]]
2061==== `cmp`
2062
2063.#include <boost/qvm/quat_operations.hpp>
2064[source,c++]
2065----
2066namespace boost { namespace qvm {
2067
2068  //Only enabled if:
2069  //  is_quat<A>::value && is_quat<B>::value
2070  template <class A,class B,class Cmp>
2071  bool cmp( A const & a, B const & b, Cmp pred );
2072
2073} }
2074----
2075
2076Returns: :: Similar to <<quat_eq,`operator==`>>, except that it uses the binary predicate `pred` to compare the individual quaternion elements.
2077
2078'''
2079
2080[[quat_mag_sqr]]
2081==== `mag_sqr`
2082
2083.#include <boost/qvm/quat_operations.hpp>
2084[source,c++]
2085----
2086namespace boost { namespace qvm {
2087
2088  //Only enabled if: is_quat<A>::value
2089  template <class A>
2090  typename quat_traits<A>::scalar_type
2091  mag_sqr( A const & a );
2092
2093} }
2094----
2095
2096Returns: :: The squared magnitude of the quaternion `a`.
2097
2098'''
2099
2100[[quat_mag]]
2101==== `mag`
2102
2103.#include <boost/qvm/quat_operations.hpp>
2104[source,c++]
2105----
2106namespace boost { namespace qvm {
2107
2108  //Only enabled if: is_quat<A>::value
2109  template <class A>
2110  typename quat_traits<A>::scalar_type
2111  mag( A const & a );
2112
2113} }
2114----
2115
2116Returns: :: The magnitude of the quaternion `a`.
2117
2118'''
2119
2120[[quat_normalized]]
2121==== `normalized`
2122
2123.#include <boost/qvm/quat_operations.hpp>
2124[source,c++]
2125----
2126namespace boost { namespace qvm {
2127
2128  //Only enabled if: is_quat<A>::value
2129  template <class A>
2130  typename deduce_quat<A>::type
2131  normalized( A const & a );
2132
2133} }
2134----
2135
2136Effects: :: As if:
2137+
2138[source,c++]
2139----
2140typename deduce_quat<A>::type tmp;
2141assign(tmp,a);
2142normalize(tmp);
2143return tmp;
2144----
2145
2146NOTE: The <<deduce_quat,`deduce_quat`>> template can be specialized to deduce the desired return type from the type `A`.
2147
2148'''
2149
2150[[quat_normalize]]
2151==== `normalize`
2152
2153.#include <boost/qvm/quat_operations.hpp>
2154[source,c++]
2155----
2156namespace boost { namespace qvm {
2157
2158  //Only enabled if: is_quat<A>::value
2159  template <class A>
2160  void normalize( A & a );
2161
2162} }
2163----
2164
2165Effects: :: Normalizes `a`.
2166
2167Postcondition: :: `mag(a)==scalar_traits<typename quat_traits<A>::scalar_type>::value(1).`
2168
2169Throws: :: If the magnitude of `a` is zero, throws <<zero_magnitude_error,`zero_magnitude_error`>>.
2170
2171'''
2172
2173[[quat_dot]]
2174==== `dot`
2175
2176.#include <boost/qvm/quat_operations.hpp>
2177[source,c++]
2178----
2179namespace boost { namespace qvm {
2180
2181  //Only enabled if:
2182  //  is_quat<A>::value && is_quat<B>::value
2183  template <class A,class B>
2184  typename deduce_scalar<A,B>::type
2185  dot( A const & a, B const & b );
2186
2187} }
2188----
2189
2190Returns: :: The dot product of the quaternions `a` and `b`.
2191
2192NOTE: The <<deduce_scalar,`deduce_scalar`>> template can be specialized to deduce the desired return type, given the types `A` and `B`.
2193
2194'''
2195
2196[[conjugate]]
2197==== `conjugate`
2198
2199.#include <boost/qvm/quat_operations.hpp>
2200[source,c++]
2201----
2202namespace boost { namespace qvm {
2203
2204  //Only enabled if: is_quat<A>::value
2205  template <class A>
2206  typename deduce_quat<A>::type
2207  conjugate( A const & a );
2208
2209} }
2210----
2211
2212Returns: :: Computes the conjugate of `a`.
2213
2214NOTE: The <<deduce_quat,`deduce_quat`>> template can be specialized to deduce the desired return type from the type `A`.
2215
2216'''
2217
2218[[quat_inverse]]
2219==== `inverse`
2220
2221.#include <boost/qvm/quat_operations.hpp>
2222[source,c++]
2223----
2224namespace boost { namespace qvm {
2225
2226  //Only enabled if: is_quat<A>::value
2227  template <class A>
2228  typename deduce_quat<A>::type
2229  inverse( A const & a );
2230
2231} }
2232----
2233
2234Returns: :: Computes the multiplicative inverse of `a`, or the conjugate-to-norm ratio.
2235
2236Throws: :: If the magnitude of `a` is zero, throws <<zero_magnitude_error,`zero_magnitude_error`>>.
2237
2238TIP: If `a` is known to be unit length, `conjugate` is equivalent to <<quat_inverse,`inverse`>>, yet it is faster to compute.
2239
2240NOTE: The <<deduce_quat,`deduce_quat`>> template can be specialized to deduce the desired return type from the type `A`.
2241
2242'''
2243
2244[[slerp]]
2245==== `slerp`
2246
2247.#include <boost/qvm/quat_operations.hpp>
2248[source,c++]
2249----
2250namespace boost { namespace qvm {
2251
2252  //Only enabled if:
2253  //  is_quat<A>::value && is_quat<B>::value && is_scalar<C>
2254  template <class A,class B,class C>
2255  typename deduce_quat2<A,B> >::type
2256  slerp( A const & a, B const & b, C c );
2257
2258} }
2259----
2260
2261Preconditions: :: `t>=0 && t\<=1`.
2262
2263Returns: :: A quaternion that is the result of Spherical Linear Interpolation of the quaternions `a` and `b` and the interpolation parameter `c`. When `slerp` is applied to unit quaternions, the quaternion path maps to a path through 3D rotations in a standard way. The effect is a rotation with uniform angular velocity around a fixed rotation axis.
2264
2265NOTE: The <<deduce_quat2,`deduce_quat2`>> template can be specialized to deduce the desired return type, given the types `A` and `B`.
2266
2267'''
2268
2269[[zero_quat]]
2270==== `zero_quat`
2271
2272.#include <boost/qvm/quat_operations.hpp>
2273[source,c++]
2274----
2275namespace boost { namespace qvm {
2276
2277  template <class T>
2278  -unspecified-return-type- zero_quat();
2279
2280} }
2281----
2282
2283Returns: :: A read-only quaternion of unspecified type with <<scalar_traits,`scalar_type`>> `T`, with all elements equal to <<scalar_traits,`scalar_traits<T>::value(0)`>>.
2284
2285'''
2286
2287[[quat_set_zero]]
2288==== `set_zero`
2289
2290.#include <boost/qvm/quat_operations.hpp>
2291[source,c++]
2292----
2293namespace boost { namespace qvm {
2294
2295  //Only enabled if: is_quat<A>::value
2296  template <class A>
2297  void set_zero( A & a );
2298
2299} }
2300----
2301
2302Effects: :: As if:
2303+
2304[source,c++]
2305----
2306assign(a,
2307  zero_quat<typename quat_traits<A>::scalar_type>());
2308----
2309
2310'''
2311
2312[[identity_quat]]
2313==== `identity_quat`
2314
2315.#include <boost/qvm/quat_operations.hpp>
2316[source,c++]
2317----
2318namespace boost { namespace qvm {
2319
2320  template <class S>
2321  -unspecified-return-type- identity_quat();
2322
2323} }
2324----
2325
2326Returns: :: An identity quaternion with scalar type `S`.
2327
2328'''
2329
2330[[quat_set_identity]]
2331==== `set_identity`
2332.#include <boost/qvm/quat_operations.hpp>
2333[source,c++]
2334----
2335namespace boost { namespace qvm {
2336
2337  //Only enabled if: is_quat<A>::value
2338  template <class A>
2339  void set_identity( A & a );
2340
2341} }
2342----
2343
2344Effects: :: As if:
2345+
2346[source,c++]
2347----
2348assign(
2349  a,
2350  identity_quat<typename quat_traits<A>::scalar_type>());
2351----
2352
2353'''
2354
2355[[rot_quat]]
2356==== `rot_quat`
2357
2358.#include <boost/qvm/quat_operations.hpp>
2359[source,c++]
2360----
2361namespace boost { namespace qvm {
2362
2363  //Only enabled if:
2364  //  is_vec<A>::value && vec_traits<A>::dim==3
2365  template <class A>
2366  -unspecified-return-type- rot_quat( A const & axis, typename vec_traits<A>::scalar_type angle );
2367
2368} }
2369----
2370
2371Returns: :: A quaternion of unspecified type which performs a rotation around the `axis` at `angle` radians.
2372
2373Throws: :: In case the axis vector has zero magnitude, throws <<zero_magnitude_error,`zero_magnitude_error`>>.
2374
2375NOTE: The `rot_quat` function is not a <<view_proxy,view proxy>>; it returns a temp object.
2376
2377'''
2378
2379[[quat_set_rot]]
2380==== `set_rot`
2381
2382.#include <boost/qvm/quat_operations.hpp>
2383[source,c++]
2384----
2385namespace boost { namespace qvm {
2386
2387  //Only enabled if:
2388  //  is_quat<A>::value &&
2389  //  is_vec<B>::value && vec_traits<B>::dim==3
2390  template <class A>
2391  void set_rot( A & a, B const & axis, typename vec_traits<B>::scalar_type angle );
2392
2393} }
2394----
2395
2396Effects: :: As if:
2397+
2398[source,c++]
2399----
2400assign(
2401  a,
2402  rot_quat(axis,angle));
2403----
2404
2405'''
2406
2407[[quat_rotate]]
2408==== `rotate`
2409
2410.#include <boost/qvm/quat_operations.hpp>
2411[source,c++]
2412----
2413namespace boost { namespace qvm {
2414
2415  //Only enabled if:
2416  //  is_quat<A>::value &&
2417  //  is_vec<B>::value && vec_traits<B>::dim==3
2418  template <class A,class B>
2419  void rotate( A & a, B const & axis, typename quat_traits<A>::scalar_type angle );
2420
2421} }
2422----
2423
2424Effects: :: As if: `a *= <<rot_quat,rot_quat>>(axis,angle)`.
2425
2426'''
2427
2428[[rotx_quat]]
2429==== `rotx_quat`
2430
2431.#include <boost/qvm/quat_operations.hpp>
2432[source,c++]
2433----
2434namespace boost { namespace qvm {
2435
2436  template <class Angle>
2437  -unspecified-return-type- rotx_quat( Angle const & angle );
2438
2439} }
2440----
2441
2442Returns: :: A <<view_proxy,view proxy>> quaternion of unspecified type and scalar type `Angle`, which performs a rotation around the X axis at `angle` radians.
2443
2444'''
2445
2446[[quat_set_rotx]]
2447==== `set_rotx`
2448
2449.#include <boost/qvm/quat_operations.hpp>
2450[source,c++]
2451----
2452namespace boost { namespace qvm {
2453
2454  //Only enabled if: is_quat<A>::value
2455  template <class A>
2456  void set_rotx( A & a, typename quat_traits<A>::scalar_type angle );
2457
2458} }
2459----
2460
2461Effects: :: As if:
2462+
2463[source,c++]
2464----
2465assign(
2466  a,
2467  rotx_quat(angle));
2468----
2469
2470'''
2471
2472[[quat_rotate_x]]
2473==== `rotate_x`
2474
2475.#include <boost/qvm/quat_operations.hpp>
2476[source,c++]
2477----
2478namespace boost { namespace qvm {
2479
2480  //Only enabled if: is_quat<A>::value
2481  template <class A>
2482  void rotate_x( A & a, typename quat_traits<A>::scalar_type angle );
2483
2484} }
2485----
2486
2487Effects: :: As if: `a *= <<rotx_quat,rotx_quat>>(angle)`.
2488
2489'''
2490
2491[[roty_quat]]
2492==== `roty_quat`
2493
2494.#include <boost/qvm/quat_operations.hpp>
2495[source,c++]
2496----
2497namespace boost { namespace qvm {
2498
2499  template <class Angle>
2500  -unspecified-return-type- roty_quat( Angle const & angle );
2501
2502} }
2503----
2504
2505Returns: :: A <<view_proxy,view proxy>> quaternion of unspecified type and scalar type `Angle`, which performs a rotation around the Y axis at `angle` radians.
2506
2507'''
2508
2509[[quat_set_roty]]
2510==== `set_roty`
2511
2512.#include <boost/qvm/quat_operations.hpp>
2513[source,c++]
2514----
2515namespace boost { namespace qvm {
2516
2517  //Only enabled if: is_quat<A>::value
2518  template <class A>
2519  void set_rotz( A & a, typename quat_traits<A>::scalar_type angle );
2520
2521} }
2522----
2523
2524Effects: :: As if:
2525+
2526[source,c++]
2527----
2528assign(
2529  a,
2530  roty_quat(angle));
2531----
2532
2533'''
2534
2535[[quat_rotate_y]]
2536==== `rotate_y`
2537
2538.#include <boost/qvm/quat_operations.hpp>
2539[source,c++]
2540----
2541namespace boost { namespace qvm {
2542
2543  //Only enabled if: is_quat<A>::value
2544  template <class A>
2545  void rotate_y( A & a, typename quat_traits<A>::scalar_type angle );
2546
2547} }
2548----
2549
2550Effects: :: As if: `a *= <<roty_quat,roty_quat>>(angle)`.
2551
2552'''
2553
2554[[rotz_quat]]
2555==== `rotz_quat`
2556
2557.#include <boost/qvm/quat_operations.hpp>
2558[source,c++]
2559----
2560namespace boost { namespace qvm {
2561
2562    template <class Angle>
2563    -unspecified-return-type- rotz_quat( Angle const & angle );
2564
2565} }
2566----
2567
2568Returns: :: A <<view_proxy,view proxy>> quaternion of unspecified type and scalar type `Angle`, which performs a rotation around the Z axis at `angle` radians.
2569
2570'''
2571
2572[[quat_set_rotz]]
2573==== `set_rotz`
2574
2575.#include <boost/qvm/quat_operations.hpp>
2576[source,c++]
2577----
2578namespace boost { namespace qvm {
2579
2580  //Only enabled if: is_quat<A>::value
2581  template <class A>
2582  void set_rotz( A & a, typename quat_traits<A>::scalar_type angle );
2583
2584} }
2585----
2586
2587Effects: :: As if:
2588+
2589[source,c++]
2590----
2591assign(
2592  a,
2593  rotz_quat(angle));
2594----
2595
2596'''
2597
2598[[quat_rotate_z]]
2599==== `rotate_z`
2600
2601.#include <boost/qvm/quat_operations.hpp>
2602[source,c++]
2603----
2604namespace boost { namespace qvm {
2605
2606  //Only enabled if: is_quat<A>::value
2607  template <class A>
2608  void rotate_z( A & a, typename quat_traits<A>::scalar_type angle );
2609
2610} }
2611----
2612
2613Effects: :: As if: `a *= <<rotz_quat,rotz_quat>>(angle)`.
2614
2615'''
2616
2617[[quat_scalar_cast]]
2618==== `scalar_cast`
2619
2620.#include <boost/qvm/quat_operations.hpp>
2621[source,c++]
2622----
2623namespace boost { namespace qvm {
2624
2625  //Only enabled if: is_quat<A>::value
2626  template <class Scalar,class A>
2627  -unspecified-return_type- scalar_cast( A const & a );
2628
2629} }
2630----
2631
2632Returns: :: A read-only <<view_proxy,view proxy>> of `a` that looks like a quaternion of the same dimensions as `a`, but with <<quat_traits,`scalar_type`>> `Scalar` and elements constructed from the corresponding elements of `a`.
2633
2634'''
2635
2636[[qref]]
2637==== `qref`
2638
2639.#include <boost/qvm/quat_operations.hpp>
2640[source,c++]
2641----
2642namespace boost { namespace qvm {
2643
2644  //Only enabled if: is_quat<A>::value
2645  template <class A>
2646  -unspecified-return-type- qref( A & a );
2647
2648} }
2649----
2650
2651Returns: :: An identity view proxy of `a`; that is, it simply accesses the elements of `a`.
2652
2653TIP: `qref` allows calling QVM operations when `a` is of built-in type, for example a plain old C array.
2654
2655'''
2656
2657=== Vector Operations
2658
2659[[vec_assign]]
2660==== `assign`
2661
2662.#include <boost/qvm/vec_operations.hpp>
2663[source,c++]
2664----
2665namespace boost { namespace qvm {
2666
2667    //Only enabled if:
2668    //  is_vec<A>::value && is_vec<B>::value &&
2669    //  vec_traits<A>::dim==vec_traits<B>::dim
2670    template <class A,class B>
2671    A & assign( A & a, B const & b );
2672
2673} }
2674----
2675
2676Effects: :: Copies all elements of the vector `b` to the vector `a`.
2677
2678Returns: :: `a`.
2679
2680'''
2681
2682[[vec_convert_to]]
2683==== `convert_to`
2684
2685.#include <boost/qvm/vec_operations.hpp>
2686[source,c++]
2687----
2688namespace boost { namespace qvm {
2689
2690    //Only enabled if:
2691    //  is_vec<R>::value && is_vec<A>::value &&
2692    //  vec_traits<R>::dim==vec_traits<A>::dim
2693    template <class R,class A>
2694    R convert_to( A const & a );
2695
2696} }
2697----
2698
2699Requirements: :: `R` must be copyable.
2700
2701Effects: :: As if: `R r; assign(r,a); return r;`
2702
2703'''
2704
2705[[vec_minus_eq]]
2706==== `operator-=`
2707
2708.#include <boost/qvm/vec_operations.hpp>
2709[source,c++]
2710----
2711namespace boost { namespace qvm {
2712
2713    //Only enabled if:
2714    //  is_vec<A>::value && is_vec<B>::value &&
2715    //  vec_traits<A>::dim==vec_traits<B>::dim
2716    template <class A,class B>
2717    A & operator-=( A & a, B const & b );
2718
2719} }
2720----
2721
2722Effects: :: Subtracts the elements of `b` from the corresponding elements of `a`.
2723
2724Returns: :: `a`.
2725
2726'''
2727
2728[[vec_minus_unary]]
2729==== `operator-` (unary)
2730
2731operator-(vec)
2732
2733.#include <boost/qvm/vec_operations.hpp>
2734[source,c++]
2735----
2736namespace boost { namespace qvm {
2737
2738    //Only enabled if: is_vec<A>::value
2739    template <class A>
2740    typename deduce_vec<A>::type
2741    operator-( A const & a );
2742
2743} }
2744----
2745
2746Returns: :: A vector of the negated elements of `a`.
2747
2748NOTE: The <<deduce_vec,`deduce_vec`>> template can be specialized to deduce the desired return type from the type `A`.
2749
2750'''
2751
2752[[vec_minus]]
2753==== `operator-` (binary)
2754
2755.#include <boost/qvm/vec_operations.hpp>
2756[source,c++]
2757----
2758namespace boost { namespace qvm {
2759
2760    //Only enabled if:
2761    //  is_vec<A>::value && is_vec<B>::value &&
2762    //  vec_traits<A>::dim==vec_traits<B>::dim
2763    template <class A,class B>
2764    typename deduce_vec2<A,B,vec_traits<A>::dim>::type
2765    operator-( A const & a, B const & b );
2766
2767} }
2768----
2769
2770Returns: :: A vector of the same size as `a` and `b`, with elements the elements of `b` subtracted from the corresponding elements of `a`.
2771
2772NOTE: The <<deduce_vec2,`deduce_vec2`>> template can be specialized to deduce the desired return type, given the types `A` and `B`.
2773
2774'''
2775
2776[[vec_plus_eq]]
2777==== `operator+=`
2778
2779.#include <boost/qvm/vec_operations.hpp>
2780[source,c++]
2781----
2782namespace boost { namespace qvm {
2783
2784    //Only enabled if:
2785    //  is_vec<A>::value && is_vec<B>::value &&
2786    //  vec_traits<A>::dim==vec_traits<B>::dim
2787    template <class A,class B>
2788    A & operator+=( A & a, B const & b );
2789
2790} }
2791----
2792
2793Effects: :: Adds the elements of `b` to the corresponding elements of `a`.
2794
2795Returns: :: `a`.
2796
2797'''
2798
2799[[vec_plus]]
2800==== `operator+`
2801
2802.#include <boost/qvm/vec_operations.hpp>
2803[source,c++]
2804----
2805namespace boost { namespace qvm {
2806
2807    //Only enabled if:
2808    //  is_vec<A>::value && is_vec<B>::value &&
2809    //  vec_traits<A>::dim==vec_traits<B>::dim
2810    template <class A,class B>
2811    typename deduce_vec2<A,B,vec_traits<A>::dim>::type
2812    operator+( A const & a, B const & b );
2813
2814} }
2815----
2816
2817Returns: :: A vector of the same size as `a` and `b`, with elements the elements of `b` added to the corresponding elements of `a`.
2818
2819NOTE: The <<deduce_vec2,`deduce_vec2`>> template can be specialized to deduce the desired return type, given the types `A` and `B`.
2820
2821'''
2822
2823[[vec_div_eq_scalar]]
2824==== `operator/=` (scalar)
2825
2826.#include <boost/qvm/vec_operations.hpp>
2827[source,c++]
2828----
2829namespace boost { namespace qvm {
2830
2831    //Only enabled if: is_vec<A>::value && is_scalar<B>::value
2832    template <class A,class B>
2833    A & operator/=( A & a, B b );
2834
2835} }
2836----
2837
2838Effects: :: This operation divides a vector by a scalar.
2839
2840Returns: :: `a`.
2841
2842'''
2843
2844[[vec_div_scalar]]
2845==== `operator/`
2846
2847.#include <boost/qvm/vec_operations.hpp>
2848[source,c++]
2849----
2850namespace boost { namespace qvm {
2851
2852    //Only enabled if: is_vec<A>::value && is_scalar<B>::value
2853    template <class A,class B>
2854    typename deduce_vec<A>::type
2855    operator/( A const & a, B b );
2856
2857} }
2858----
2859
2860Returns: :: A vector that is the result of dividing the vector `a` by the scalar `b`.
2861
2862NOTE: The <<deduce_vec,`deduce_vec`>> template can be specialized to deduce the desired return type from the type `A`.
2863
2864'''
2865
2866[[vec_mul_eq_scalar]]
2867==== `operator*=`
2868
2869.#include <boost/qvm/vec_operations.hpp>
2870[source,c++]
2871----
2872namespace boost { namespace qvm {
2873
2874    //Only enabled if: is_vec<A>::value && is_scalar<B>::value
2875    template <class A,class B>
2876    A & operator*=( A & a, B b );
2877
2878} }
2879----
2880
2881Effects: :: This operation multiplies the vector `a` by the scalar `b`.
2882
2883Returns: :: `a`.
2884
2885'''
2886
2887[[vec_mul_scalar]]
2888==== `operator*`
2889
2890.#include <boost/qvm/vec_operations.hpp>
2891[source,c++]
2892----
2893namespace boost { namespace qvm {
2894
2895    //Only enabled if: is_vec<A>::value && is_scalar<B>::value
2896    template <class A>
2897    typename deduce_vec<A>::type
2898    operator*( A const & a, B b );
2899
2900} }
2901----
2902
2903Returns: :: A vector that is the result of multiplying the vector `a` by the scalar `b`.
2904
2905NOTE: The <<deduce_vec,`deduce_vec`>> template can be specialized to deduce the desired return type from the type `A`.
2906
2907'''
2908
2909[[vec_eq]]
2910==== `operator==`
2911
2912.#include <boost/qvm/vec_operations.hpp>
2913[source,c++]
2914----
2915namespace boost { namespace qvm {
2916
2917    //Only enabled if:
2918    //  is_vec<A>::value && is_vec<B>::value &&
2919    //  vec_traits<A>::dim==vec_traits<B>::dim
2920    template <class A,class B>
2921    bool operator==( A const & a, B const & b );
2922
2923} }
2924----
2925
2926Returns: :: `true` if each element of `a` compares equal to its corresponding element of `b`, `false` otherwise.
2927
2928'''
2929
2930[[vec_neq]]
2931==== `operator!=`
2932
2933.#include <boost/qvm/vec_operations.hpp>
2934[source,c++]
2935----
2936namespace boost { namespace qvm {
2937
2938    //Only enabled if:
2939    //  is_vec<A>::value && is_vec<B>::value &&
2940    //  vec_traits<A>::dim==vec_traits<B>::dim
2941    template <class A,class B>
2942    bool operator!=( A const & a, B const & b );
2943
2944} }
2945----
2946
2947Returns: :: `!(a == b)`.
2948
2949'''
2950
2951[[vec_cmp]]
2952==== `cmp`
2953
2954----
2955.#include <boost/qvm/mat_operations.hpp>
2956
2957namespace boost
2958{
2959  namespace qvm
2960  {
2961    //Only enabled if:
2962    //  is_mat<A>::value && is_mat<B>::value &&
2963    //  mat_traits<A>::rows==mat_traits<B>::rows &&
2964    //  mat_traits<A>::cols==mat_traits<B>::cols
2965    template <class A,class B,class Cmp>
2966    bool cmp( A const & a, B const & b, Cmp pred );
2967
2968} }
2969----
2970
2971Returns: :: Similar to <<vec_eq,`operator==`>>, except that the individual elements of `a` and `b` are passed to the binary predicate `pred` for comparison.
2972
2973'''
2974
2975[[vec_mag_sqr]]
2976==== `mag_sqr`
2977
2978.#include <boost/qvm/vec_operations.hpp>
2979[source,c++]
2980----
2981namespace boost { namespace qvm {
2982
2983    //Only enabled if:
2984    //  is_vec<A>::value
2985    template <class A>
2986    typename vec_traits<A>::scalar_type
2987    mag_sqr( A const & a );
2988
2989} }
2990----
2991
2992Returns: :: The squared magnitude of the vector `a`.
2993
2994'''
2995
2996[[vec_mag]]
2997==== `mag`
2998
2999.#include <boost/qvm/vec_operations.hpp>
3000[source,c++]
3001----
3002namespace boost { namespace qvm {
3003
3004    //Only enabled if:
3005    //  is_vec<A>::value
3006    template <class A>
3007    typename vec_traits<A>::scalar_type
3008    mag( A const & a );
3009
3010} }
3011----
3012
3013Returns: :: The magnitude of the vector `a`.
3014
3015'''
3016
3017[[vec_normalized]]
3018==== `normalized`
3019
3020.#include <boost/qvm/vec_operations.hpp>
3021[source,c++]
3022----
3023namespace boost { namespace qvm {
3024
3025    //Only enabled if:
3026    //  is_vec<A>::value
3027    template <class A>
3028    typename deduce_vec<A>::type
3029    normalized( A const & a );
3030
3031} }
3032----
3033
3034Effects: :: As if:
3035+
3036[source,c++]
3037----
3038typename deduce_vec<A>::type tmp;
3039assign(tmp,a);
3040normalize(tmp);
3041return tmp;
3042----
3043
3044NOTE: The <<deduce_vec,`deduce_vec`>> template can be specialized to deduce the desired return type from the type `A`.
3045
3046'''
3047
3048[[vec_normalize]]
3049==== `normalize`
3050
3051.#include <boost/qvm/vec_operations.hpp>
3052[source,c++]
3053----
3054namespace boost { namespace qvm {
3055
3056    //Only enabled if:
3057    //  is_vec<A>::value
3058    template <class A>
3059    void normalize( A & a );
3060
3061} }
3062----
3063
3064Effects: :: Normalizes `a`.
3065
3066Postcondition:
3067
3068`mag(a)==<<scalar_traits,scalar_traits>><typename <<vec_traits,vec_traits<A>::scalar_type>>>::value(1)`.
3069
3070Throws: :: If the magnitude of `a` is zero, throws <<zero_magnitude_error,`zero_magnitude_error`>>.
3071
3072'''
3073
3074[[vec_dot]]
3075==== `dot`
3076
3077.#include <boost/qvm/vec_operations.hpp>
3078[source,c++]
3079----
3080namespace boost { namespace qvm {
3081
3082    //Only enabled if:
3083    //  is_vec<A>::value && is_vec<B>::value &&
3084    //  vec_traits<A>::dim==vec_traits<B>::dim
3085    template <class A,class B>
3086    typename deduce_scalar<A,B>::type
3087    dot( A const & a, B const & b );
3088
3089} }
3090----
3091
3092Returns: :: The dot product of the vectors `a` and `b`.
3093
3094NOTE: The <<deduce_scalar,`deduce_scalar`>> template can be specialized to deduce the desired return type, given the types `A` and `B`.
3095
3096'''
3097
3098[[vec_cross]]
3099==== `cross`
3100
3101.#include <boost/qvm/vec_operations.hpp>
3102[source,c++]
3103----
3104namespace boost { namespace qvm {
3105
3106    //Only enabled if:
3107    //  is_vec<A>::value && is_vec<B>::value &&
3108    //  vec_traits<A>::dim==3 && vec_traits<B>::dim==3
3109    template <class A,class B>
3110    typename deduce_vec2<A,B,3>::type
3111    cross( A const & a, B const & b );
3112
3113} }
3114----
3115
3116Returns: :: The cross product of the vectors `a` and `b`.
3117
3118NOTE: The <<deduce_vec2,`deduce_vec2`>> template can be specialized to deduce the desired return type, given the types `A` and `B`.
3119
3120'''
3121
3122[[zero_vec]]
3123==== `zero_vec`
3124
3125.#include <boost/qvm/vec_operations.hpp>
3126[source,c++]
3127----
3128namespace boost { namespace qvm {
3129
3130    template <class T,int S>
3131    -unspecified-return-type- zero_vec();
3132
3133} }
3134----
3135
3136Returns: :: A read-only vector of unspecified type with <<vec_traits,`scalar_type`>> `T` and size `S`, with all elements equal to <<scalar_traits,`scalar_traits<T>::value(0)`>>.
3137
3138'''
3139
3140[[vec_set_zero]]
3141==== `set_zero`
3142
3143.#include <boost/qvm/vec_operations.hpp>
3144[source,c++]
3145----
3146namespace boost { namespace qvm {
3147
3148    //Only enabled if:
3149    //  is_vec<A>::value
3150    template <class A>
3151    void set_zero( A & a );
3152
3153} }
3154----
3155
3156Effects: :: As if:
3157+
3158[source,c++]
3159----
3160assign(a,
3161  zero_vec<
3162    typename vec_traits<A>::scalar_type,
3163    vec_traits<A>::dim>());
3164----
3165
3166'''
3167
3168[[vec_scalar_cast]]
3169==== `scalar_cast`
3170
3171.#include <boost/qvm/vec_operations.hpp>
3172[source,c++]
3173----
3174namespace boost { namespace qvm {
3175
3176    //Only enabled if: is_vec<A>::value
3177    template <class Scalar,class A>
3178    -unspecified-return_type- scalar_cast( A const & a );
3179
3180} }
3181----
3182
3183Returns: :: A read-only <<view_proxy,view proxy>> of `a` that looks like a vector of the same dimensions as `a`, but with <<vec_traits,`scalar_type`>> `Scalar` and elements constructed from the corresponding elements of `a`.
3184
3185'''
3186
3187[[vref]]
3188==== `vref`
3189
3190.#include <boost/qvm/vec_operations.hpp>
3191[source,c++]
3192----
3193namespace boost { namespace qvm {
3194
3195    //Only enabled if: is_vec<A>::value
3196    template <class A>
3197    -unspecified-return-type- vref( A & a );
3198
3199} }
3200----
3201
3202Returns: :: An identity <<view_proxy,view proxy>> of `a`; that is, it simply accesses the elements of `a`.
3203
3204TIP: `vref` allows calling QVM operations when `a` is of built-in type, for example a plain old C array.
3205
3206'''
3207
3208=== Matrix Operations
3209
3210[[mat_assign]]
3211==== `assign`
3212
3213.#include <boost/qvm/mat_operations.hpp>
3214[source,c++]
3215----
3216namespace boost { namespace qvm {
3217
3218  //Only enabled if:
3219  //  is_mat<A>::value && is_mat<B>::value &&
3220  //  mat_traits<A>::rows==mat_traits<B>::rows &&
3221  //  mat_traits<A>::cols==mat_traits<B>::cols
3222  template <class A,class B>
3223  A & assign( A & a, B const & b );
3224
3225} }
3226----
3227
3228Effects: :: Copies all elements of the matrix `b` to the matrix `a`.
3229
3230Returns: :: `a`.
3231
3232'''
3233
3234[[mat_convert_to]]
3235==== `convert_to`
3236
3237.#include <boost/qvm/mat_operations.hpp>
3238[source,c++]
3239----
3240namespace boost { namespace qvm {
3241
3242  //Only enabled if:
3243  //  is_mat<R>::value && is_mat<A>::value &&
3244  //  mat_traits<R>::rows==mat_traits<A>::rows &&
3245  //  mat_traits<R>::cols==mat_traits<A>::cols
3246  template <class R,class A>
3247  R convert_to( A const & a );
3248
3249} }
3250----
3251
3252Requirements: :: `R` must be copyable.
3253
3254Effects:
3255
3256As if: `R r; <<mat_assign,assign>>(r,a); return r;`
3257
3258'''
3259
3260[[mat_minus_eq_scalar]]
3261==== `operator-=`
3262
3263.#include <boost/qvm/mat_operations.hpp>
3264[source,c++]
3265----
3266namespace boost { namespace qvm {
3267
3268  //Only enabled if:
3269  //  is_mat<A>::value && is_mat<B>::value &&
3270  //  mat_traits<A>::rows==mat_traits<B>::rows &&
3271  //  mat_traits<A>::cols==mat_traits<B>::cols
3272  template <class A,class B>
3273  A & operator-=( A & a, B const & b );
3274
3275} }
3276----
3277
3278Effects: :: Subtracts the elements of `b` from the corresponding elements of `a`.
3279
3280Returns: :: `a`.
3281
3282'''
3283
3284[[mat_minus_unary]]
3285==== `operator-` (unary)
3286
3287.#include <boost/qvm/mat_operations.hpp>
3288[source,c++]
3289----
3290namespace boost { namespace qvm {
3291
3292  //Only enabled if: is_mat<A>::value
3293  template <class A>
3294  typename deduce_mat<A>::type
3295  operator-( A const & a );
3296
3297} }
3298----
3299
3300Returns: :: A matrix of the negated elements of `a`.
3301
3302NOTE: The <<deduce_mat,`deduce_mat`>> template can be specialized to deduce the desired return type from the type `A`.
3303
3304'''
3305
3306[[mat_minus]]
3307==== `operator-`
3308
3309.#include <boost/qvm/mat_operations.hpp>
3310[source,c++]
3311----
3312namespace boost { namespace qvm {
3313
3314  //Only enabled if:
3315  //  is_mat<A>::value && is_mat<B>::value &&
3316  //  mat_traits<A>::rows==mat_traits<B>::rows &&
3317  //  mat_traits<A>::cols==mat_traits<B>::cols
3318  template <class A,class B>
3319  typename deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols>::type
3320  operator-( A const & a, B const & b );
3321
3322} }
3323----
3324
3325Returns: :: A matrix of the same size as `a` and `b`, with elements the elements of `b` subtracted from the corresponding elements of `a`.
3326
3327NOTE: The <<deduce_mat2,`deduce_mat2`>> template can be specialized to deduce the desired return type, given the types `A` and `B`.
3328
3329'''
3330
3331[[mat_plus_eq_scalar]]
3332==== `operator+=`
3333
3334.#include <boost/qvm/mat_operations.hpp>
3335[source,c++]
3336----
3337namespace boost { namespace qvm {
3338
3339  //Only enabled if:
3340  //  is_mat<A>::value && is_mat<B>::value &&
3341  //  mat_traits<A>::rows==mat_traits<B>::rows &&
3342  //  mat_traits<A>::cols==mat_traits<B>::cols
3343  template <class A,class B>
3344  A & operator+=( A & a, B const & b );
3345
3346} }
3347----
3348
3349Effects: :: Adds the elements of `b` to the corresponding elements of `a`.
3350
3351Returns: :: `a`.
3352
3353'''
3354
3355[[mat_plus]]
3356==== `operator+`
3357
3358.#include <boost/qvm/mat_operations.hpp>
3359[source,c++]
3360----
3361namespace boost { namespace qvm {
3362
3363  //Only enabled if:
3364  //  is_mat<A>::value && is_mat<B>::value &&
3365  //  mat_traits<A>::rows==mat_traits<B>::rows &&
3366  //  mat_traits<A>::cols==mat_traits<B>::cols
3367  template <class A,class B>
3368  typename deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols>::type
3369  operator+( A const & a, B const & b );
3370
3371} }
3372----
3373
3374Returns: :: A matrix of the same size as `a` and `b`, with elements the elements of `b` added to the corresponding elements of `a`.
3375
3376NOTE: The <<deduce_mat2,`deduce_mat2`>> template can be specialized to deduce the desired return type, given the types `A` and `B`.
3377
3378'''
3379
3380[[mat_div_eq_scalar]]
3381==== `operator/=` (scalar)
3382
3383.#include <boost/qvm/mat_operations.hpp>
3384[source,c++]
3385----
3386namespace boost { namespace qvm {
3387
3388  //Only enabled if: is_mat<A>::value && is_scalar<B>::value
3389  template <class A,class B>
3390  A & operator/=( A & a, B b );
3391
3392} }
3393----
3394
3395Effects: :: This operation divides a matrix by a scalar.
3396
3397Returns: :: `a`.
3398
3399'''
3400
3401[[mat_div_scalar]]
3402==== `operator/` (scalar)
3403
3404.#include <boost/qvm/mat_operations.hpp>
3405[source,c++]
3406----
3407namespace boost { namespace qvm {
3408
3409  //Only enabled if: is_mat<A>::value && is_scalar<B>::value
3410  template <class A,class B>
3411  typename deduce_mat<A>::type
3412  operator/( A const & a, B b );
3413
3414} }
3415----
3416
3417Returns: :: A matrix that is the result of dividing the matrix `a` by the scalar `b`.
3418
3419NOTE: The <<deduce_mat,`deduce_mat`>> template can be specialized to deduce the desired return type from the type `A`.
3420
3421'''
3422
3423[[mat_mul_eq]]
3424==== `operator*=`
3425
3426.#include <boost/qvm/mat_operations.hpp>
3427[source,c++]
3428----
3429namespace boost { namespace qvm {
3430
3431  //Only enabled if:
3432  //  is_mat<A>::value && is_mat<B>::value &&
3433  //  mat_traits<A>::rows==mat_traits<A>::cols &&
3434  //  mat_traits<A>::rows==mat_traits<B>::rows &&
3435  //  mat_traits<A>::cols==mat_traits<B>::cols
3436  template <class A,class B>
3437  A & operator*=( A & a, B const & b );
3438
3439} }
3440----
3441
3442Effects: :: As if:
3443+
3444[source,c++]
3445----
3446A tmp(a);
3447a = tmp * b;
3448return a;
3449----
3450
3451'''
3452
3453[[mat_mul_eq_scalar]]
3454==== `operator*=` (scalar)
3455
3456.#include <boost/qvm/mat_operations.hpp>
3457[source,c++]
3458----
3459namespace boost { namespace qvm {
3460
3461  //Only enabled if: is_mat<A>::value && is_scalar<B>::value
3462  template <class A,class B>
3463  A & operator*=( A & a, B b );
3464
3465} }
3466----
3467
3468Effects: :: This operation multiplies the matrix `a` matrix by the scalar `b`.
3469
3470Returns: :: `a`.
3471
3472'''
3473
3474[[mat_mul]]
3475==== `operator*`
3476
3477.#include <boost/qvm/mat_operations.hpp>
3478[source,c++]
3479----
3480namespace boost { namespace qvm {
3481
3482  //Only enabled if:
3483  //  is_mat<A>::value && is_mat<B>::value &&
3484  //  mat_traits<A>::cols==mat_traits<B>::rows
3485  template <class A,class B>
3486  typename deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<B>::cols>::type
3487  operator*( A const & a, B const & b );
3488
3489} }
3490----
3491
3492Returns: :: The result of https://en.wikipedia.org/wiki/Matrix_multiplication[multiplying] the matrices `a` and `b`.
3493
3494NOTE: The <<deduce_mat2,`deduce_mat2`>> template can be specialized to deduce the desired return type, given the types `A` and `B`.
3495
3496'''
3497
3498[[mat_mul_scalar]]
3499==== `operator*` (scalar)
3500
3501.#include <boost/qvm/mat_operations.hpp>
3502[source,c++]
3503----
3504namespace boost { namespace qvm {
3505
3506  //Only enabled if: is_mat<A>::value && is_scalar<B>::value
3507  template <class A,class B>
3508  typename deduce_mat<A>::type
3509  operator*( A const & a, B b );
3510
3511  //Only enabled if: is_scalar<B>::value && is_mat<A>::value
3512  template <class B,class A>
3513  typename deduce_mat<A>::type
3514  operator*( B b, A const & a );
3515
3516} }
3517----
3518
3519Returns: :: A matrix that is the result of multiplying the matrix `a` by the scalar `b`.
3520
3521NOTE: The <<deduce_mat,`deduce_mat`>> template can be specialized to deduce the desired return type from the type `A`.
3522
3523'''
3524
3525[[mat_eq]]
3526==== `operator==`
3527
3528.#include <boost/qvm/mat_operations.hpp>
3529[source,c++]
3530----
3531namespace boost { namespace qvm {
3532
3533  //Only enabled if:
3534  //  is_mat<A>::value && is_mat<B>::value &&
3535  //  mat_traits<A>::rows==mat_traits<B>::rows &&
3536  //  mat_traits<A>::cols==mat_traits<B>::cols
3537  template <class A,class B>
3538  bool operator==( A const & a, B const & b );
3539
3540} }
3541----
3542
3543Returns: :: `true` if each element of `a` compares equal to its corresponding element of `b`, `false` otherwise.
3544
3545'''
3546
3547[[mat_neq]]
3548==== `operator!=`
3549
3550.#include <boost/qvm/mat_operations.hpp>
3551[source,c++]
3552----
3553namespace boost { namespace qvm {
3554
3555  //Only enabled if:
3556  //  is_mat<A>::value && is_mat<B>::value &&
3557  //  mat_traits<A>::rows==mat_traits<B>::rows &&
3558  //  mat_traits<A>::cols==mat_traits<B>::cols
3559  template <class A,class B>
3560  bool operator!=( A const & a, B const & b );
3561
3562} }
3563----
3564
3565Returns: :: `!( a <<mat_eq,=\=>> b )`.
3566
3567'''
3568
3569[[mat_cmp]]
3570==== `cmp`
3571
3572.#include <boost/qvm/mat_operations.hpp>
3573[source,c++]
3574----
3575namespace boost { namespace qvm {
3576
3577  //Only enabled if:
3578  //  is_mat<A>::value && is_mat<B>::value &&
3579  //  mat_traits<A>::rows==mat_traits<B>::rows &&
3580  //  mat_traits<A>::cols==mat_traits<B>::cols
3581  template <class A,class B,class Cmp>
3582  bool cmp( A const & a, B const & b, Cmp pred );
3583
3584} }
3585----
3586
3587Returns: :: Similar to <<mat_eq,`operator==`>>, except that the individual elements of `a` and `b` are passed to the binary predicate `pred` for comparison.
3588
3589'''
3590
3591[[mat_inverse]]
3592==== `inverse`
3593
3594.#include <boost/qvm/mat_operations.hpp>
3595[source,c++]
3596----
3597namespace boost { namespace qvm {
3598
3599  //Only enabled if:
3600  //  is_mat<A>::value && is_scalar<B>::value
3601  //  mat_traits<A>::rows==mat_traits<A>::cols
3602
3603  template <class A,class B>
3604  typename deduce_mat<A>::type
3605  inverse( A const & a, B det );
3606
3607  template <class A>
3608  typename deduce_mat<A>::type
3609  inverse( A const & a );
3610
3611} }
3612----
3613
3614Preconditions: :: `det!=<<scalar_traits,scalar_traits>><typename <<mat_traits,mat_traits<A>::scalar_type>>>::value(0)`
3615
3616Returns: :: Both overloads compute the inverse of `a`. The first overload takes the pre-computed determinant of `a`.
3617
3618Throws: :: The second overload computes the determinant automatically and throws <<zero_determinant_error,`zero_determinant_error`>> if the computed determinant is zero.
3619
3620NOTE: The <<deduce_mat,`deduce_mat`>> template can be specialized to deduce the desired return type from the type `A`.
3621
3622'''
3623
3624[[zero_mat]]
3625==== `zero_mat`
3626
3627.#include <boost/qvm/mat_operations.hpp>
3628[source,c++]
3629----
3630namespace boost { namespace qvm {
3631
3632  template <class T,int D>
3633  -unspecified-return-type- zero_mat();
3634
3635  template <class T,int R,int C>
3636  -unspecified-return-type- zero_mat();
3637
3638} }
3639----
3640
3641Returns: :: A read-only matrix of unspecified type with <<mat_traits,`scalar_type`>> `T`, `R` rows and `C` columns (or `D` rows and `D` columns), with all elements equal to <<scalar_traits,`scalar_traits<T>::value(0)`>>.
3642
3643'''
3644
3645[[mat_set_zero]]
3646==== `set_zero`
3647
3648.#include <boost/qvm/mat_operations.hpp>
3649[source,c++]
3650----
3651namespace boost { namespace qvm {
3652
3653  //Only enabled if:
3654  //  is_mat<A>::value
3655  template <class A>
3656  void set_zero( A & a );
3657
3658} }
3659----
3660
3661Effects: :: As if:
3662+
3663[source,c++]
3664----
3665assign(a,
3666  zero_mat<
3667    typename mat_traits<A>::scalar_type,
3668    mat_traits<A>::rows,
3669    mat_traits<A>::cols>());
3670----
3671
3672'''
3673
3674[[identity_mat]]
3675==== `identity_mat`
3676
3677.#include <boost/qvm/mat_operations.hpp>
3678----
3679namespace boost { namespace qvm {
3680
3681  template <class S,int D>
3682  -unspecified-return-type- identity_mat();
3683
3684} }
3685----
3686
3687Returns: :: An identity matrix of size `D` x `D` and scalar type `S`.
3688
3689'''
3690
3691[[mat_set_identity]]
3692==== `set_identity`
3693
3694.#include <boost/qvm/mat_operations.hpp>
3695[source,c++]
3696----
3697namespace boost { namespace qvm {
3698
3699  //Only enabled if:
3700  //  is_mat<A>::value &&
3701  //  mat_traits<A>::cols==mat_traits<A>::rows
3702  template <class A>
3703  void set_identity( A & a );
3704
3705} }
3706----
3707
3708Effects: :: As if:
3709+
3710[source,c++]
3711----
3712assign(
3713  a,
3714  identity_mat<
3715    typename mat_traits<A>::scalar_type,
3716    mat_traits<A>::rows,
3717    mat_traits<A>::cols>());
3718----
3719
3720'''
3721
3722[[rot_mat]]
3723==== `rot_mat` / Euler angles
3724
3725.#include <boost/qvm/mat_operations.hpp>
3726[source,c++]
3727----
3728namespace boost { namespace qvm {
3729
3730  //Only enabled if:
3731  //  is_vec<A>::value && vec_traits<A>::dim==3
3732  template <int Dim,class A,class Angle>
3733  -unspecified-return-type-
3734  rot_mat( A const & axis, Angle angle );
3735
3736  template <int Dim,class Angle>
3737  -unspecified-return-type-
3738  rot_mat_xzy( Angle x1, Angle z2, Angle y3 );
3739
3740  template <int Dim,class Angle>
3741  -unspecified-return-type-
3742  rot_mat_xyz( Angle x1, Angle y2, Angle z3 );
3743
3744  template <int Dim,class Angle>
3745  -unspecified-return-type-
3746  rot_mat_yxz( Angle y1, Angle x2, Angle z3 );
3747
3748  template <int Dim,class Angle>
3749  -unspecified-return-type-
3750  rot_mat_yzx( Angle y1, Angle z2, Angle x3 );
3751
3752  template <int Dim,class Angle>
3753  -unspecified-return-type-
3754  rot_mat_zyx( Angle z1, Angle y2, Angle x3 );
3755
3756  template <int Dim,class Angle>
3757  -unspecified-return-type-
3758  rot_mat_zxy( Angle z1, Angle x2, Angle y3 );
3759
3760  template <int Dim,class Angle>
3761  -unspecified-return-type-
3762  rot_mat_xzx( Angle x1, Angle z2, Angle x3 );
3763
3764  template <int Dim,class Angle>
3765  -unspecified-return-type-
3766  rot_mat_xyx( Angle x1, Angle y2, Angle x3 );
3767
3768  template <int Dim,class Angle>
3769  -unspecified-return-type-
3770  rot_mat_yxy( Angle y1, Angle x2, Angle y3 );
3771
3772  template <int Dim,class Angle>
3773  -unspecified-return-type-
3774  rot_mat_yzy( Angle y1, Angle z2, Angle y3 );
3775
3776  template <int Dim,class Angle>
3777  -unspecified-return-type-
3778  rot_mat_zyz( Angle z1, Angle y2, Angle z3 );
3779
3780  template <int Dim,class Angle>
3781  -unspecified-return-type-
3782  rot_mat_zxz( Angle z1, Angle y2, Angle z3 );
3783
3784} }
3785----
3786
3787Returns: :: A matrix of unspecified type, of `Dim` rows and `Dim` columns parameter, which performs a rotation around the `axis` at `angle` radians, or Tait–Bryan angles (x-y-z, y-z-x, z-x-y, x-z-y, z-y-x, y-x-z), or proper Euler angles (z-x-z, x-y-x, y-z-y, z-y-z, x-z-x, y-x-y). See https://en.wikipedia.org/wiki/Euler_angles[Euler angles].
3788
3789Throws: :: In case the axis vector has zero magnitude, throws <<zero_magnitude_error,`zero_magnitude_error`>>.
3790
3791NOTE: These functions are not view proxies; they return a temp object.
3792
3793'''
3794
3795[[mat_set_rot]]
3796==== `set_rot` / Euler angles
3797
3798.#include <boost/qvm/mat_operations.hpp>
3799[source,c++]
3800----
3801namespace boost { namespace qvm {
3802
3803  //Only enabled if:
3804  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3805  //  mat_traits<A>::rows==mat_traits<A>::cols &&
3806  //  is_vec<B>::value && vec_traits<B>::dim==3
3807  template <class A>
3808  void set_rot( A & a, B const & axis, typename vec_traits<B>::scalar_type angle );
3809
3810  //Only enabled if:
3811  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3812  //  mat_traits<A>::rows==mat_traits<A>::cols
3813  template <class A,class Angle>
3814  void set_rot_xzy( A & a, Angle x1, Angle z2, Angle y3 );
3815
3816  //Only enabled if:
3817  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3818  //  mat_traits<A>::rows==mat_traits<A>::cols
3819  template <class A,class Angle>
3820  void set_rot_xyz( A & a, Angle x1, Angle y2, Angle z3 );
3821
3822  //Only enabled if:
3823  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3824  //  mat_traits<A>::rows==mat_traits<A>::cols
3825  template <class A,class Angle>
3826  void set_rot_yxz( A & a, Angle y1, Angle x2, Angle z3 );
3827
3828  //Only enabled if:
3829  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3830  //  mat_traits<A>::rows==mat_traits<A>::cols
3831  template <class A,class Angle>
3832  void set_rot_yzx( A & a, Angle y1, Angle z2, Angle x3 );
3833
3834  //Only enabled if:
3835  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3836  //  mat_traits<A>::rows==mat_traits<A>::cols
3837  template <class A,class Angle>
3838  void set_rot_zyx( A & a, Angle z1, Angle y2, Angle x3 );
3839
3840  //Only enabled if:
3841  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3842  //  mat_traits<A>::rows==mat_traits<A>::cols
3843  template <class A,class Angle>
3844  void set_rot_zxy( A & a, Angle z1, Angle x2, Angle y3 );
3845
3846  //Only enabled if:
3847  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3848  //  mat_traits<A>::rows==mat_traits<A>::cols
3849  template <class A,class Angle>
3850  void set_rot_xzx( A & a, Angle x1, Angle z2, Angle x3 );
3851
3852  //Only enabled if:
3853  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3854  //  mat_traits<A>::rows==mat_traits<A>::cols
3855  template <class A,class Angle>
3856  void set_rot_xyx( A & a, Angle x1, Angle y2, Angle x3 );
3857
3858  //Only enabled if:
3859  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3860  //  mat_traits<A>::rows==mat_traits<A>::cols
3861  template <class A,class Angle>
3862  void set_rot_yxy( A & a, Angle y1, Angle x2, Angle y3 );
3863
3864  //Only enabled if:
3865  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3866  //  mat_traits<A>::rows==mat_traits<A>::cols
3867  template <class A,class Angle>
3868  void set_rot_yzy( A & a, Angle y1, Angle z2, Angle y3 );
3869
3870  //Only enabled if:
3871  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3872  //  mat_traits<A>::rows==mat_traits<A>::cols
3873  template <class A,class Angle>
3874  void set_rot_zyz( A & a, Angle z1, Angle y2, Angle z3 );
3875
3876  //Only enabled if:
3877  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3878  //  mat_traits<A>::rows==mat_traits<A>::cols
3879  template <class A,class Angle>
3880  void set_rot_zxz( A & a, Angle z1, Angle x2, Angle z3 );
3881
3882  //Only enabled if:
3883  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3884  //  mat_traits<A>::rows==mat_traits<A>::cols
3885  template <class A,class Angle>
3886  void set_rot_xzy( A & a, Angle x1, Angle z2, Angle y3 );
3887
3888} }
3889----
3890
3891Effects: :: Assigns the return value of the corresponding <<rot_mat,`rot_mat`>> function to `a`.
3892
3893'''
3894
3895[[mat_rotate]]
3896==== `rotate` / Euler angles
3897
3898.#include <boost/qvm/mat_operations.hpp>
3899[source,c++]
3900----
3901namespace boost { namespace qvm {
3902
3903  //Only enabled if:
3904  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3905  //  mat_traits<A>::rows==mat_traits<A>::cols &&
3906  //  is_vec<B>::value && vec_traits<B>::dim==3
3907  template <class A,class B>
3908  void rotate( A & a, B const & axis, typename mat_traits<A>::scalar_type angle );
3909
3910  //Only enabled if:
3911  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3912  //  mat_traits<A>::rows==mat_traits<A>::cols
3913  template <class A,class Angle>
3914  void rotate_xzy( A & a, Angle x1, Angle z2, Angle y3 );
3915
3916  //Only enabled if:
3917  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3918  //  mat_traits<A>::rows==mat_traits<A>::cols
3919  template <class A,class Angle>
3920  void rotate_xyz( A & a, Angle x1, Angle y2, Angle z3 );
3921
3922  //Only enabled if:
3923  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3924  //  mat_traits<A>::rows==mat_traits<A>::cols
3925  template <class A,class Angle>
3926  void rotate_yxz( A & a, Angle y1, Angle x2, Angle z3 );
3927
3928  //Only enabled if:
3929  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3930  //  mat_traits<A>::rows==mat_traits<A>::cols
3931  template <class A,class Angle>
3932  void rotate_yzx( A & a, Angle y1, Angle z2, Angle x3 );
3933
3934  //Only enabled if:
3935  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3936  //  mat_traits<A>::rows==mat_traits<A>::cols
3937  template <class A,class Angle>
3938  void rotate_zyx( A & a, Angle z1, Angle y2, Angle x3 );
3939
3940  //Only enabled if:
3941  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3942  //  mat_traits<A>::rows==mat_traits<A>::cols
3943  template <class A,class Angle>
3944  void rotate_zxy( A & a, Angle z1, Angle x2, Angle y3 );
3945
3946  //Only enabled if:
3947  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3948  //  mat_traits<A>::rows==mat_traits<A>::cols
3949  template <class A,class Angle>
3950  void rotate_xzx( A & a, Angle x1, Angle z2, Angle x3 );
3951
3952  //Only enabled if:
3953  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3954  //  mat_traits<A>::rows==mat_traits<A>::cols
3955  template <class A,class Angle>
3956  void rotate_xyx( A & a, Angle x1, Angle y2, Angle x3 );
3957
3958  //Only enabled if:
3959  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3960  //  mat_traits<A>::rows==mat_traits<A>::cols
3961  template <class A,class Angle>
3962  void rotate_yxy( A & a, Angle y1, Angle x2, Angle y3 );
3963
3964  //Only enabled if:
3965  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3966  //  mat_traits<A>::rows==mat_traits<A>::cols
3967  template <class A,class Angle>
3968  void rotate_yzy( A & a, Angle y1, Angle z2, Angle y3 );
3969
3970  //Only enabled if:
3971  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3972  //  mat_traits<A>::rows==mat_traits<A>::cols
3973  template <class A,class Angle>
3974  void rotate_zyz( A & a, Angle z1, Angle y2, Angle z3 );
3975
3976  //Only enabled if:
3977  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
3978  //  mat_traits<A>::rows==mat_traits<A>::cols
3979  template <class A,class Angle>
3980  void rotate_zxz( A & a, Angle z1, Angle x2, Angle z3 );
3981
3982} }
3983----
3984
3985Effects: :: Multiplies the matrix `a` in-place by the return value of the corresponding <<rot_mat,`rot_mat`>> function.
3986
3987'''
3988
3989[[rotx_mat]]
3990==== `rotx_mat`
3991
3992.#include <boost/qvm/mat_operations.hpp>
3993[source,c++]
3994----
3995namespace boost { namespace qvm {
3996
3997  template <int Dim,class Angle>
3998  -unspecified-return-type- rotx_mat( Angle const & angle );
3999
4000} }
4001----
4002
4003Returns: :: A <<view_proxy,view proxy>> matrix of unspecified type, of `Dim` rows and `Dim` columns and scalar type `Angle`, which performs a rotation around the `X` axis at `angle` radians.
4004
4005'''
4006
4007[[mat_set_rotx]]
4008==== `set_rotx`
4009
4010.#include <boost/qvm/mat_operations.hpp>
4011[source,c++]
4012----
4013namespace boost { namespace qvm {
4014
4015  //Only enabled if:
4016  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
4017  //  mat_traits<A>::rows==mat_traits<A>::cols
4018  template <class A>
4019  void set_rotx( A & a, typename mat_traits<A>::scalar_type angle );
4020
4021} }
4022----
4023
4024Effects: :: As if:
4025+
4026[source,c++]
4027----
4028assign(
4029  a,
4030  rotx_mat<mat_traits<A>::rows>(angle));
4031----
4032
4033'''
4034
4035[[mat_rotate_x]]
4036==== `rotate_x`
4037
4038.#include <boost/qvm/mat_operations.hpp>
4039[source,c++]
4040----
4041namespace boost { namespace qvm {
4042
4043  //Only enabled if:
4044  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
4045  //  mat_traits<A>::rows==mat_traits<A>::cols
4046  template <class A>
4047  void rotate_x( A & a, typename mat_traits<A>::scalar_type angle );
4048
4049} }
4050----
4051
4052Effects: :: As if: `a <<mat_mul_eq,*\=>> <<rotx_mat,rotx_mat>><<<mat_traits,mat_traits<A>::rows>>>(angle)`.
4053
4054
4055'''
4056
4057[[roty_mat]]
4058==== `roty_mat`
4059
4060.#include <boost/qvm/mat_operations.hpp>
4061[source,c++]
4062----
4063namespace boost { namespace qvm {
4064
4065  template <int Dim,class Angle>
4066  -unspecified-return-type- roty_mat( Angle const & angle );
4067
4068} }
4069----
4070
4071Returns: :: A <<view_proxy,view proxy>> matrix of unspecified type, of `Dim` rows and `Dim` columns and scalar type `Angle`, which performs a rotation around the `Y` axis at `angle` radians.
4072
4073'''
4074
4075[[mat_set_roty]]
4076==== `set_roty`
4077
4078.#include <boost/qvm/mat_operations.hpp>
4079[source,c++]
4080----
4081namespace boost { namespace qvm {
4082
4083  //Only enabled if:
4084  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
4085  //  mat_traits<A>::rows==mat_traits<A>::cols
4086  template <class A>
4087  void set_roty( A & a, typename mat_traits<A>::scalar_type angle );
4088
4089} }
4090----
4091
4092Effects: :: As if:
4093+
4094[source,c++]
4095----
4096assign(
4097  a,
4098  roty_mat<mat_traits<A>::rows>(angle));
4099----
4100
4101'''
4102
4103[[mat_rotate_y]]
4104==== `rotate_y`
4105
4106.#include <boost/qvm/mat_operations.hpp>
4107[source,c++]
4108----
4109namespace boost { namespace qvm {
4110
4111  //Only enabled if:
4112  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
4113  //  mat_traits<A>::rows==mat_traits<A>::cols
4114  template <class A>
4115  void rotate_y( A & a, typename mat_traits<A>::scalar_type angle );
4116
4117} }
4118----
4119
4120Effects: :: As if: `a <<mat_mul_eq,*\=>> <<roty_mat,roty_mat>><<<mat_traits,mat_traits<A>::rows>>>(angle)`.
4121
4122'''
4123
4124[[rotz_mat]]
4125==== `rotz_mat`
4126
4127.#include <boost/qvm/mat_operations.hpp>
4128[source,c++]
4129----
4130namespace boost { namespace qvm {
4131
4132  template <int Dim,class Angle>
4133  -unspecified-return-type- rotz_mat( Angle const & angle );
4134
4135} }
4136----
4137
4138Returns: :: A <<view_proxy,view proxy>> matrix of unspecified type, of `Dim` rows and `Dim` columns and scalar type `Angle`, which performs a rotation around the `Z` axis at `angle` radians.
4139
4140'''
4141
4142[[mat_set_rotz]]
4143==== `set_rotz`
4144
4145.#include <boost/qvm/mat_operations.hpp>
4146[source,c++]
4147----
4148namespace boost { namespace qvm {
4149
4150  //Only enabled if:
4151  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
4152  //  mat_traits<A>::rows==mat_traits<A>::cols
4153  template <class A>
4154  void set_rotz( A & a, typename mat_traits<A>::scalar_type angle );
4155
4156} }
4157----
4158
4159Effects: :: As if:
4160+
4161[source,c++]
4162----
4163assign(
4164  a,
4165  rotz_mat<mat_traits<A>::rows>(angle));
4166----
4167
4168'''
4169
4170[[mat_rotate_z]]
4171==== `rotate_z`
4172
4173.#include <boost/qvm/mat_operations.hpp>
4174[source,c++]
4175----
4176namespace boost { namespace qvm {
4177
4178  //Only enabled if:
4179  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
4180  //  mat_traits<A>::rows==mat_traits<A>::cols
4181  template <class A>
4182  void rotate_z( A & a, typename mat_traits<A>::scalar_type angle );
4183
4184} }
4185----
4186
4187Effects: :: As if: `a <<mat_mul_eq,*\=>> <<rotz_mat,rotz_mat>><<<mat_traits,mat_traits<A>::rows>>>(angle)`.
4188
4189'''
4190
4191[[determinant]]
4192==== `determinant`
4193
4194.#include <boost/qvm/mat_operations.hpp>
4195[source,c++]
4196----
4197namespace boost { namespace qvm {
4198
4199  //Only enabled if:
4200  //  is_mat<A>::value && mat_traits<A>::rows==mat_traits<A>::cols
4201  template <class A>
4202  mat_traits<A>::scalar_type
4203  determinant( A const & a );
4204
4205} }
4206----
4207
4208This function computes the https://en.wikipedia.org/wiki/Determinant[determinant] of the square matrix `a`.
4209
4210'''
4211
4212[[perspective_lh]]
4213==== `perspective_lh`
4214
4215.#include <boost/qvm/mat_operations.hpp>
4216[source,c++]
4217----
4218namespace boost { namespace qvm {
4219
4220  template <class T>
4221  -unspecified-return-type-
4222  perspective_lh( T fov_y, T aspect, T zn, T zf );
4223
4224} }
4225----
4226
4227Returns: :: A 4x4 projection matrix of unspecified type of the following form:
4228+
4229[cols="^v,^v,^v,^v",width="50%"]
4230|====
4231| `xs` | 0 |  0 | 0
4232| 0 | `ys` | 0 | 0
4233| 0 | 0 | `zf`/(`zf`-`zn`) |  -`zn`*`zf`/(`zf`-`zn`)
4234| 0 | 0 | 1 | 0
4235|====
4236+
4237where `ys` = cot(`fov_y`/2) and `xs` = `ys`/`aspect`.
4238
4239'''
4240
4241[[perspective_rh]]
4242==== `perspective_rh`
4243
4244.#include <boost/qvm/mat_operations.hpp>
4245[source,c++]
4246----
4247namespace boost { namespace qvm {
4248
4249  template <class T>
4250  -unspecified-return-type-
4251  perspective_rh( T fov_y, T aspect, T zn, T zf );
4252
4253} }
4254----
4255
4256Returns: :: A 4x4 projection matrix of unspecified type of the following form:
4257+
4258[cols="^v,^v,^v,^v",width="50%"]
4259|====
4260| `xs` | 0 | 0 | 0
4261| 0 | `ys` | 0 | 0
4262| 0 | 0 | `zf`/(`zn`-`zf`) | `zn`*`zf`/(`zn`-`zf`)
4263| 0 | 0 | -1 | 0
4264|====
4265+
4266where `ys` = cot(`fov_y`/2), and `xs` = `ys`/`aspect`.
4267
4268'''
4269
4270[[mat_scalar_cast]]
4271==== `scalar_cast`
4272
4273.#include <boost/qvm/mat_operations.hpp>
4274[source,c++]
4275----
4276namespace boost { namespace qvm {
4277
4278  //Only enabled if: is_mat<A>::value
4279  template <class Scalar,class A>
4280  -unspecified-return_type- scalar_cast( A const & a );
4281
4282} }
4283----
4284
4285Returns: :: A read-only <<view_proxy,view proxy>> of `a` that looks like a matrix of the same dimensions as `a`, but with <<mat_traits,`scalar_type`>> `Scalar` and elements constructed from the corresponding elements of `a`.
4286
4287'''
4288
4289[[mref]]
4290==== `mref`
4291
4292.#include <boost/qvm/mat_operations.hpp>
4293[source,c++]
4294----
4295namespace boost { namespace qvm {
4296
4297  //Only enabled if: is_mat<A>::value
4298  template <class A>
4299  -unspecified-return-type- mref( A & a );
4300
4301} }
4302----
4303
4304Returns: :: An identity view proxy of `a`; that is, it simply accesses the elements of `a`.
4305
4306TIP: `mref` allows calling QVM operations when `a` is of built-in type, for example a plain old C array.
4307
4308'''
4309
4310=== Quaternion-Vector Operations
4311
4312[[quat_vec_mul]]
4313==== `operator*`
4314
4315.#include <boost/qvm/quat_vec_operations.hpp>
4316[source,c++]
4317----
4318namespace boost { namespace qvm {
4319
4320  //Only enabled if:
4321  //  is_mat<A>::value && is_vec<B>::value &&
4322  //  mat_traits<A>::cols==vec_traits<B>::dim
4323  template <class A,class B>
4324  typename deduce_vec2<A,B,mat_traits<A>::rows>::type
4325  operator*( A const & a, B const & b );
4326
4327} }
4328----
4329
4330Returns: :: The result of transforming the vector `b` by the quaternion `a`.
4331
4332NOTE: The <<deduce_vec2,`deduce_vec2`>> template can be specialized to deduce the desired return type, given the types `A` and `B`.
4333
4334'''
4335
4336=== Matrix-Vector Operations
4337
4338[[mat_vec_mul]]
4339==== `operator*`
4340
4341.#include <boost/qvm/vec_mat_operations.hpp>
4342[source,c++]
4343----
4344namespace boost { namespace qvm {
4345
4346  //Only enabled if:
4347  //  is_mat<A>::value && is_vec<B>::value &&
4348  //  mat_traits<A>::cols==vec_traits<B>::dim
4349  template <class A,class B>
4350  typename deduce_vec2<A,B,mat_traits<A>::rows>::type
4351  operator*( A const & a, B const & b );
4352
4353} }
4354----
4355
4356Returns: :: The result of multiplying the matrix `a` and the vector `b`, where `b` is interpreted as a matrix-column. The resulting matrix-row is returned as a vector type.
4357
4358NOTE: The <<deduce_vec2,`deduce_vec2`>> template can be specialized to deduce the desired return type, given the types `A` and `B`.
4359
4360'''
4361
4362[[transform_vector]]
4363==== `transform_vector`
4364
4365.#include <boost/qvm/vec_mat_operations.hpp>
4366[source,c++]
4367----
4368namespace boost { namespace qvm {
4369
4370  //Only enabled if:
4371  //  is_mat<A>::value && is_vec<B>::value &&
4372  //  mat_traits<A>::rows==4 && mat_traits<A>::cols==4 &&
4373  //  vec_traits<B>::dim==3
4374  template <class A,class B>
4375  deduce_vec2<A,B,3> >::type
4376  transform_vector( A const & a, B const & b );
4377
4378} }
4379----
4380
4381Effects: :: As if: `return a <<mat_vec_mul,*>> <<swizzling,XYZ0>>(b)`.
4382
4383'''
4384
4385[[transform_point]]
4386==== `transform_point`
4387
4388.#include <boost/qvm/vec_mat_operations.hpp>
4389[source,c++]
4390----
4391namespace boost { namespace qvm {
4392
4393  //Only enabled if:
4394  //  is_mat<A>::value && is_vec<B>::value &&
4395  //  mat_traits<A>::rows==4 && mat_traits<A>::cols==4 &&
4396  //  vec_traits<B>::dim==3
4397  template <class A,class B>
4398  deduce_vec2<A,B,3> >::type
4399  transform_point( A const & a, B const & b );
4400
4401} }
4402----
4403
4404Effects: :: As if: `return a <<mat_vec_mul,*>> <<swizzling,XYZ1>>(b)`.
4405
4406'''
4407
4408=== Matrix-to-Matrix View Proxies
4409
4410[[del_row]]
4411==== `del_row`
4412
4413.#include <boost/qvm/map_mat_mat.hpp>
4414[source,c++]
4415----
4416namespace boost { namespace qvm {
4417
4418  template <int R>
4419  -unspecified-return-type- del_row();
4420
4421} }
4422----
4423
4424The expression `del_row<R>(m)` returns an lvalue <<view_proxy,view proxy>> that looks like the matrix `m` with row `R` deleted.
4425
4426'''
4427
4428[[del_col]]
4429==== `del_col`
4430
4431.#include <boost/qvm/map_mat_mat.hpp>
4432[source,c++]
4433----
4434namespace boost { namespace qvm {
4435
4436  template <int C>
4437  -unspecified-return-type- del_col();
4438
4439} }
4440----
4441
4442The expression `del_col<C>(m)` returns an lvalue <<view_proxy,view proxy>> that looks like the matrix `m` with column `C` deleted.
4443
4444'''
4445
4446[[del_row_col]]
4447==== `del_row_col`
4448
4449.#include <boost/qvm/map_mat_mat.hpp>
4450[source,c++]
4451----
4452namespace boost { namespace qvm {
4453
4454  template <int R,int C>
4455  -unspecified-return-type- del_row_col();
4456
4457} }
4458----
4459
4460The expression `del_row_col<R,C>(m)` returns an lvalue <<view_proxy,view proxy>> that looks like the matrix `m` with row `R` and column `C` deleted.
4461
4462'''
4463
4464[[neg_row]]
4465==== `neg_row`
4466
4467.#include <boost/qvm/map_mat_mat.hpp>
4468[source,c++]
4469----
4470namespace boost { namespace qvm {
4471
4472  template <int R>
4473  -unspecified-return-type- neg_row();
4474
4475} }
4476----
4477
4478The expression `neg_row<R>(m)` returns a read-only <<view_proxy,view proxy>> that looks like the matrix `m` with row `R` negated.
4479
4480'''
4481
4482[[neg_col]]
4483==== `neg_col`
4484
4485.#include <boost/qvm/map_mat_mat.hpp>
4486[source,c++]
4487----
4488namespace boost { namespace qvm {
4489
4490  template <int C>
4491  -unspecified-return-type- neg_col();
4492
4493} }
4494----
4495
4496 The expression `neg_col<C>(m)` returns a read-only <<view_proxy,`view proxy`>> that looks like the matrix `m` with column `C` negated.
4497
4498'''
4499
4500[[swap_rows]]
4501==== `swap_rows`
4502
4503.#include <boost/qvm/map_mat_mat.hpp>
4504[source,c++]
4505----
4506namespace boost { namespace qvm {
4507
4508  template <int R1,int R2>
4509  -unspecified-return-type- swap_rows();
4510
4511} }
4512----
4513
4514The expression `swap_rows<R1,R2>(m)` returns an lvalue <<view_proxy,view proxy>> that looks like the matrix `m` with rows `R1` and `R2` swapped.
4515
4516'''
4517
4518[[swap_cols]]
4519==== `swap_cols`
4520
4521.#include <boost/qvm/map_mat_mat.hpp>
4522[source,c++]
4523----
4524namespace boost { namespace qvm {
4525
4526  template <int C1,int C2>
4527  -unspecified-return-type- swap_cols();
4528
4529} }
4530----
4531
4532The expression `swap_cols<C1,C2>(m)` returns an lvalue <<view_proxy,view proxy>> that looks like the matrix `m` with columns `C1` and `C2` swapped.
4533
4534'''
4535
4536[[transposed]]
4537==== `transposed`
4538
4539.#include <boost/qvm/map_mat_mat.hpp>
4540[source,c++]
4541----
4542namespace boost { namespace qvm {
4543
4544  -unspecified-return-type- transposed();
4545
4546} }
4547----
4548
4549The expression `transposed(m)` returns an lvalue <<view_proxy,view proxy>> that transposes the matrix `m`.
4550
4551'''
4552
4553=== Vector-to-Matrix View Proxies
4554
4555[[col_mat]]
4556==== `col_mat`
4557
4558.#include <boost/qvm/map_vec_mat.hpp>
4559[source,c++]
4560----
4561namespace boost { namespace qvm {
4562
4563  //Only enabled if: is_vec<A>::value
4564  template <iclass A>
4565  -unspecified-return-type- col_mat( A & a );
4566
4567} }
4568----
4569
4570The expression `col_mat(v)` returns an lvalue <<view_proxy,view proxy>> that accesses the vector `v` as a matrix-column.
4571
4572'''
4573
4574[[row_mat]]
4575==== `row_mat`
4576
4577.#include <boost/qvm/map_vec_mat.hpp>
4578[source,c++]
4579----
4580namespace boost { namespace qvm {
4581
4582  //Only enabled if: is_vec<A>::value
4583  template <iclass A>
4584  -unspecified-return-type- row_mat( A & a );
4585
4586} }
4587----
4588
4589The expression `row_mat(v)` returns an lvalue <<view_proxy,view proxy>> that accesses the vector `v` as a matrix-row.
4590
4591'''
4592
4593[[translation_mat]]
4594==== `translation_mat`
4595
4596.#include <boost/qvm/map_vec_mat.hpp>
4597[source,c++]
4598----
4599namespace boost { namespace qvm {
4600
4601  //Only enabled if: is_vec<A>::value
4602  template <iclass A>
4603  -unspecified-return-type- translation_mat( A & a );
4604
4605} }
4606----
4607
4608The expression `translation_mat(v)` returns an lvalue <<view_proxy,view proxy>> that accesses the vector `v` as translation matrix of size 1 + <<vec_traits,`vec_traits<A>::dim`>>.
4609
4610'''
4611
4612[[diag_mat]]
4613==== `diag_mat`
4614
4615.#include <boost/qvm/map_vec_mat.hpp>
4616[source,c++]
4617----
4618namespace boost { namespace qvm {
4619
4620  //Only enabled if: is_vec<A>::value
4621  template <iclass A>
4622  -unspecified-return-type- diag_mat( A & a );
4623
4624} }
4625----
4626
4627The expression `diag_mat(v)` returns an lvalue <<view_proxy,view proxy>> that accesses the vector `v` as a square matrix of the same dimensions in which the elements of `v` appear as the main diagonal and all other elements are zero.
4628
4629TIP: If `v` is a 3D vector, the expression `diag_mat(XYZ1(v))` can be used as a scaling 4D matrix.
4630
4631'''
4632
4633=== Matrix-to-Vector View Proxies
4634
4635[[col]]
4636==== `col`
4637
4638.#include <boost/qvm/map_mat_vec.hpp>
4639[source,c++]
4640----
4641namespace boost { namespace qvm {
4642
4643  //Only enabled if: is_mat<A>::value
4644  template <int C,class A>
4645  -unspecified-return-type- col( A & a );
4646
4647} }
4648----
4649
4650The expression `col<C>(m)` returns an lvalue <<view_proxy,view proxy>> that accesses column `C` of the matrix `m` as a vector.
4651
4652'''
4653
4654[[row]]
4655==== `row`
4656
4657.#include <boost/qvm/map_mat_vec.hpp>
4658[source,c++]
4659----
4660namespace boost { namespace qvm {
4661
4662  //Only enabled if: is_mat<A>::value
4663  template <int C,class A>
4664  -unspecified-return-type- row( A & a );
4665
4666} }
4667----
4668
4669The expression `row<R>(m)` returns an lvalue <<view_proxy,view proxy>> that accesses row `R` of the matrix `m` as a vector.
4670
4671'''
4672
4673[[diag]]
4674==== `diag`
4675
4676.#include <boost/qvm/map_mat_vec.hpp>
4677[source,c++]
4678----
4679namespace boost { namespace qvm {
4680
4681  //Only enabled if: is_mat<A>::value
4682  template <class A>
4683  -unspecified-return-type- diag( A & a );
4684
4685} }
4686----
4687
4688The expression `diag(m)` returns an lvalue <<view_proxy,view proxy>> that accesses the main diagonal of the matrix `m` as a vector.
4689
4690'''
4691
4692[[translation]]
4693==== `translation`
4694
4695.#include <boost/qvm/map_mat_vec.hpp>
4696[source,c++]
4697----
4698namespace boost { namespace qvm {
4699
4700  //Only enabled if:
4701  //  is_mat<A>::value &&
4702  //  mat_traits<A>::rows==mat_traits<A>::cols && mat_traits<A>::rows>=3
4703  template <class A>
4704  -unspecified-return-type- translation( A & a );
4705
4706} }
4707----
4708
4709The expression `translation(m)` returns an lvalue <<view_proxy,view proxy>> that accesses the translation component of the square matrix `m`, which is a vector of size `D`-1, where `D` is the size of `m`.
4710
4711'''
4712
4713=== Exceptions
4714
4715[[error]]
4716==== `error`
4717
4718.#include <boost/qvm/error.hpp>
4719[source,c++]
4720----
4721namespace boost { namespace qvm {
4722
4723  struct error: virtual boost::exception, virtual std::exception { };
4724
4725} }
4726----
4727
4728This is the base for all exceptions thorwn by QVM.
4729
4730'''
4731
4732[[zero_magnitude_error]]
4733==== `zero_magnitude_error`
4734
4735.#include <boost/qvm/error.hpp>
4736[source,c++]
4737----
4738namespace boost { namespace qvm {
4739
4740  struct zero_magnitude_error: virtual error { };
4741
4742} }
4743----
4744
4745This exception indicates that an operation requires a vector or a quaternion with non-zero magnitude, but the computed magnitude is zero.
4746
4747'''
4748
4749[[zero_determinant_error]]
4750==== `zero_determinant_error`
4751
4752.#include <boost/qvm/error.hpp>
4753[source,c++]
4754----
4755namespace boost { namespace qvm {
4756
4757  struct zero_determinant_error: virtual error { };
4758
4759} }
4760----
4761
4762This exception indicates that an operation requires a matrix with non-zero determinant, but the computed determinant is zero.
4763
4764'''
4765
4766=== Macros and Configuration: BOOST_QVM_
4767
4768[[BOOST_QVM_INLINE]]
4769==== `INLINE`
4770===== `BOOST_QVM_INLINE`
4771
4772.#include <boost/qvm/inline.hpp>
4773[source,c++]
4774----
4775namespace boost { namespace qvm {
4776
4777  #ifndef BOOST_QVM_INLINE
4778  #define BOOST_QVM_INLINE inline
4779  #endif
4780
4781} }
4782----
4783
4784This macro is not used directly by QVM, except as the default value of other macros from `<boost/qvm/inline.hpp>`. A user-defined `BOOST_QVM_INLINE` should expand to a value that is valid substitution of the `inline` keyword in function definitions.
4785
4786'''
4787
4788[[BOOST_QVM_FORCE_INLINE]]
4789==== `FORCE_INLINE`
4790===== `BOOST_QVM_FORCE_INLINE`
4791
4792.#include <boost/qvm/inline.hpp>
4793[source,c++]
4794----
4795namespace boost { namespace qvm {
4796
4797  #ifndef BOOST_QVM_FORCE_INLINE
4798  #define BOOST_QVM_FORCE_INLINE /*platform-specific*/
4799  #endif
4800
4801} }
4802----
4803
4804This macro is not used directly by QVM, except as the default value of other macros from `<boost/qvm/inline.hpp>`. A user-defined `BOOST_QVM_FORCE_INLINE` should expand to a value that is valid substitution of the `inline` keyword in function definitions, to indicate that the compiler must inline the function. Of course, actual inlining may or may not occur.
4805
4806'''
4807
4808[[BOOST_QVM_INLINE_TRIVIAL]]
4809==== `INLINE_TRIVIAL`
4810===== `BOOST_QVM_INLINE_TRIVIAL`
4811
4812.#include <boost/qvm/inline.hpp>
4813[source,c++]
4814----
4815namespace boost { namespace qvm {
4816
4817  #ifndef BOOST_QVM_INLINE_TRIVIAL
4818  #define BOOST_QVM_INLINE_TRIVIAL BOOST_QVM_FORCE_INLINE
4819  #endif
4820
4821} }
4822----
4823
4824QVM uses `BOOST_QVM_INLINE_TRIVIAL` in definitions of functions that are not critical for the overall performance of the library but are extremely simple (such as one-liners) and therefore should always be inlined.
4825
4826'''
4827
4828[[BOOST_QVM_INLINE_CRITICAL]]
4829==== `INLINE_CRITICAL`
4830===== `BOOST_QVM_INLINE_CRITICAL`
4831
4832.#include <boost/qvm/inline.hpp>
4833[source,c++]
4834----
4835namespace boost { namespace qvm {
4836
4837  #ifndef BOOST_QVM_INLINE_CRITICAL
4838  #define BOOST_QVM_INLINE_CRITICAL BOOST_QVM_FORCE_INLINE
4839  #endif
4840
4841} }
4842----
4843
4844QVM uses `BOOST_QVM_INLINE_CRITICAL` in definitions of functions that are critical for the overall performance of the library, such as functions that access individual vector and matrix elements.
4845
4846'''
4847
4848[[BOOST_QVM_INLINE_OPERATIONS]]
4849==== `INLINE_OPERATIONS`
4850===== `BOOST_QVM_INLINE_OPERATIONS`
4851
4852.#include <boost/qvm/inline.hpp>
4853[source,c++]
4854----
4855namespace boost { namespace qvm {
4856
4857  #ifndef BOOST_QVM_INLINE_OPERATIONS
4858  #define BOOST_QVM_INLINE_OPERATIONS BOOST_QVM_INLINE
4859  #endif
4860
4861} }
4862----
4863
4864QVM uses `BOOST_QVM_INLINE_OPERATIONS` in definitions of functions that implement various high-level operations, such as matrix multiplication, computing the magnitude of a vector, etc.
4865
4866'''
4867
4868[[BOOST_QVM_INLINE_RECURSION]]
4869==== `INLINE_RECURSION`
4870===== `BOOST_QVM_INLINE_RECURSION`
4871
4872.#include <boost/qvm/inline.hpp>
4873[source,c++]
4874----
4875namespace boost { namespace qvm {
4876
4877  #ifndef BOOST_QVM_INLINE_RECURSION
4878  #define BOOST_QVM_INLINE_RECURSION BOOST_QVM_INLINE_OPERATIONS
4879  #endif
4880
4881} }
4882----
4883
4884QVM uses `BOOST_QVM_INLINE_RECURSION` in definitions of recursive functions that are not critical for the overall performance of the library (definitions of all critical functions, including critical recursive functions, use <<BOOST_QVM_INLINE_CRITICAL,`BOOST_QVM_INLINE_CRITICAL`>>).
4885
4886'''
4887
4888[[BOOST_QVM_ASSERT]]
4889==== `ASSERT`
4890===== `BOOST_QVM_ASSERT`
4891
4892.#include <boost/qvm/assert.hpp>
4893[source,c++]
4894----
4895namespace boost { namespace qvm {
4896
4897#ifndef BOOST_QVM_ASSERT
4898#include <boost/assert.hpp>
4899#define BOOST_QVM_ASSERT BOOST_ASSERT
4900#endif
4901
4902} }
4903----
4904
4905This is the macro QVM uses to assert on precondition violations and logic errors. A user-defined `BOOST_QVM_ASSERT` should have the semantics of the standard `assert`.
4906
4907'''
4908
4909[[BOOST_QVM_STATIC_ASSERT]]
4910==== `STATIC_ASSERT`
4911===== `BOOST_QVM_STATIC_ASSERT`
4912
4913.#include <boost/qvm/static_assert.hpp>
4914[source,c++]
4915----
4916namespace boost { namespace qvm {
4917
4918  #ifndef BOOST_QVM_STATIC_ASSERT
4919  #include <boost/static_assert.hpp>
4920  #define BOOST_QVM_STATIC_ASSERT BOOST_STATIC_ASSERT
4921  #endif
4922
4923} }
4924----
4925
4926All static assertions in QVM use the `BOOST_QVM_STATIC_ASSERT` macro.
4927
4928'''
4929
4930[[BOOST_QVM_THROW_EXCEPTION]]
4931==== `THROW_EXCEPTION`
4932===== `BOOST_QVM_THROW_EXCEPTION`
4933
4934.#include <boost/qvm/throw_exception.hpp>
4935[source,c++]
4936----
4937namespace boost { namespace qvm {
4938
4939  #ifndef BOOST_QVM_THROW_EXCEPTION
4940  #include <boost/throw_exception.hpp>
4941  #define BOOST_QVM_THROW_EXCEPTION BOOST_THROW_EXCEPTION
4942  #endif
4943
4944} }
4945----
4946
4947This macro is used whenever QVM throws an exception. Users who override the standard `BOOST_QVM_THROW_EXCEPTION` behavior must ensure that when invoked, the substituted implementation does not return control to the caller. Below is a list of all QVM functions that invoke `BOOST_QVM_THROW_EXCEPTION`:
4948
4949* Quaternion operations:
4950** <<quat_inverse,`inverse`>>
4951** <<rot_quat,`rot_quat`>>
4952** <<quat_normalize,`normalize`>>
4953** <<quat_normalized,`normalized`>>
4954* Vector operations:
4955** <<vec_normalize,`normalize`>>
4956** <<vec_normalized,`normalized`>>
4957* Matrix operations:
4958** <<mat_inverse,`inverse`>>
4959** <<rot_mat,`rot_mat`>>
4960
4961[[rationale]]
4962== Design Rationale
4963
4964{CPP} is ideal for 3D graphics and other domains that require 3D transformations: define vector and matrix types and then overload the appropriate operators to implement the standard algebraic operations. Because this is relatively straight-forward, there are many libraries that do this, each providing custom vector and matrix types, and then defining the same operations (e.g. matrix multiply) for these types.
4965
4966Often these libraries are part of a higher level system. For example, video game programmers typically use one set of vector/matrix types with the rendering engine, and another with the physics simulation engine.
4967
4968QVM proides interoperability between all these different types and APIs by decoupling the standard algebraic functions from the types they operate on -- without compromising type safety. The operations work on any type for which proper traits have been specialized. Using QVM, there is no need to translate between the different quaternion, vector or matrix types; they can be mixed in the same expression safely and efficiently.
4969
4970This design enables QVM to generate types and adaptors at compile time, compatible with any other QVM or user-defined type. For example, transposing a matrix needs not store the result: rather than modifying its argument or returning a new object, it simply binds the original matrix object through a generated type which remaps element access on the fly.
4971
4972In addition, QVM can be helpful in selectively optimizing individual types or operations for maximum performance where that matters. For example, users can overload a specific operation for specific types, or define highly optimized, possibly platform-specific or for some reason cumbersome to use types, then mix and match them with more user-friendly types in parts of the program where performance isn't critical.
4973
4974== Code Generator
4975
4976While QVM defines generic functions that operate on matrix and vector types of arbitrary static dimensions, it also provides a code generator that can be used to create compatible header files that define much simpler specializations of these functions for specific dimensions. This is useful during debugging since the generated code is much easier to read than the template metaprogramming-heavy generic implementations. It is also potentially friendlier to the optimizer.
4977
4978The code generator is a command-line utility program. Its source code can be found in the `boost/libs/qvm/gen` directory. It was used to generate the following headers that ship with QVM:
4979
4980* 2D, 3D and 4D matrix operations:
4981** `boost/qvm/gen/mat_operations2.hpp` (matrices of size 2x2, 2x1 and 1x2, included by `boost/qvm/mat_operations2.hpp`)
4982** `boost/qvm/gen/mat_operations3.hpp` (matrices of size 3x3, 3x1 and 1x3, included by `boost/qvm/mat_operations3.hpp`)
4983** `boost/qvm/gen/mat_operations4.hpp` (matrices of size 4x4, 4x1 and 1x4, included by `boost/qvm/mat_operations4.hpp`)
4984* 2D, 3D and 4D vector operations:
4985** `boost/qvm/gen/v2.hpp` (included by `boost/qvm/vec_operations2.hpp`)
4986** `boost/qvm/gen/v3.hpp` (included by `boost/qvm/vec_operations3.hpp`)
4987** `boost/qvm/gen/v4.hpp` (included by `boost/qvm/vec_operations4.hpp`)
4988* 2D, 3D and 4D vector-matrix operations:
4989** `boost/qvm/gen/vm2.hpp` (included by `boost/qvm/vec_mat_operations2.hpp`)
4990** `boost/qvm/gen/vm3.hpp` (included by `boost/qvm/vec_mat_operations3.hpp`)
4991** `boost/qvm/gen/vm4.hpp` (included by `boost/qvm/vec_mat_operations4.hpp`)
4992* 2D, 3D and 4D vector swizzling operations:
4993** `boost/qvm/gen/sw2.hpp` (included by `boost/qvm/swizzle2.hpp`)
4994** `boost/qvm/gen/sw3.hpp` (included by `boost/qvm/swizzle3.hpp`)
4995** `boost/qvm/gen/sw4.hpp` (included by `boost/qvm/swizzle4.hpp`)
4996
4997Any such generated headers must be included before the corresponding generic header file is included. For example, if one creates a header `boost/qvm/gen/m5.hpp`, it must be included before `boost/qvm/mat_operations.hpp` in included. However, the generic headers (`boost/qvm/mat_operations.hpp`, `boost/qvm/vec_operations.hpp`, `boost/qvm/vec_mat_operations.hpp` and `boost/qvm/swizzle.hpp`) already include the generated headers from the list above, so the generated headers don't need to be included manually.
4998
4999NOTE: headers under `boost/qvm/gen` are not part of the public interface of QVM. For example, `boost/qvm/gen/mat_operations2.hpp` should not be included directly; `#include <boost/qvm/mat_operations2.hpp>` instead.
5000
5001== Known Quirks and Issues
5002
5003=== Capturing View Proxies with `auto`
5004
5005By design, <<view_proxy,view proxies>> must not return temporary objects. They return reference to an argument they take by (`const`) reference, cast to reference of unspecified type that is not copyable. Because of this, the return value of a view proxy can not be captured by value with `auto`:
5006
5007[source,c++]
5008----
5009auto tr = transposed(m); //Error: the return type of transposed can not be copied.
5010----
5011
5012The correct use of auto with view proxies is:
5013
5014[source,c++]
5015----
5016auto & tr = transposed(m);
5017----
5018
5019NOTE: Many view proxies are not read-only, that is, they're lvalues; changes made on the view proxy operate on the original object. This is another reason why they can not be captured by value with  `auto`.
5020
5021'''
5022
5023=== Binding QVM Overloads From an Unrelated Namespace
5024
5025The operator overloads in namespace `boost::qvm` are designed to work with user-defined types. Typically it is sufficient to make these operators available in the namespace where the operator is used, by `using namespace boost::qvm`. A problem arises if the scope that uses the operator is not controlled by the user. For example:
5026
5027[source,c++]
5028----
5029namespace ns1 {
5030
5031  struct float2 { float x, y; };
5032
5033}
5034
5035namespace ns2 {
5036
5037  using namespace boost::qvm;
5038
5039  void f() {
5040    ns1::float2 a, b;
5041    a==b; //OK
5042    ns1::float2 arr1[2], arr2[2];
5043    std::equal(arr1,arr1+2,arr2); //Error: operator== is inaccessible from namespace std
5044  }
5045
5046}
5047----
5048
5049In the `std::equal` expression above, even though `boost::qvm::operator==` is made visible in namespace `ns2` by `using namespace boost::qvm`, the call originates from namespace `std`. In this case the compiler can't bind `boost::qvm::operator==` because only namespace `ns1` is visible through ADL, and it does not contain a suitable declaration. The solution is to declare `operator==` in namespace ns1, which can be done like this:
5050
5051[source,c++]
5052----
5053namespace ns1 {
5054
5055  using boost::qvm::operator==;
5056
5057}
5058----
5059
5060'''
5061
5062=== Link Errors When Calling Math Functions with `int` Arguments
5063
5064QVM does not call standard math functions (e.g. sin, cos, etc.) directly. Instead, it calls function templates declared in `boost/qvm/math.hpp` in namespace `boost::qvm`. This allows the user to specialize these templates for user-defined scalar types.
5065
5066QVM itself defines specializations of the math function templates only for `float` and `double`, but it does not provide generic definitions. This is done to protect the user from unintentionally writing code that binds standard math functions that take `double` when passing arguments of lesser types, which would be suboptimal.
5067
5068Because of this, a call to e.g. `<<rot_mat,rot_mat>>(axis,1)` will compile successfully but fail to link, since it calls e.g. `boost::qvm::sin<int>`, which is undefined. Because rotations by integer number of radians are rarely needed, in QVM there is no protection against such errors. In such cases the solution is to use `rot_mat(axis,1.0f)` instead.
5069
5070== Distribution
5071
5072QVM is part of https://www.boost.org/[Boost] and is distributed under the http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0].
5073
5074The source code is available in https://github.com/boostorg/qvm[QVM GitHub repository].
5075
5076(C) 2008-2018 Emil Dotchevski and Reverge Studios, Inc.
5077
5078== Portability
5079
5080See the link:https://travis-ci.org/boostorg/qvm[QVM Travis CI Builds].
5081
5082== Feedback / Support
5083
5084Please use the link:https://lists.boost.org/mailman/listinfo.cgi/boost[Boost Developers mailing list].
5085
5086== Q&A
5087
5088[qanda]
5089What is the motivation behind QVM? Why not just use uBLAS/Eigen/CML/GLM/etc?:: The primary domain of QVM is realtime graphics and simulation applications, so it is not a complete linear algebra library. While (naturally) there is some overlap with such libraries, QVM puts the emphasis on 2, 3 and 4 dimensional zero-overhead operations (hence domain-specific features like Swizzling).
5090
5091How does the `qvm::<<vec,vec>>` (or `qvm::<<mat,mat>>`, or `qvm::<<quat,quat>>`) template compare to vector types from other libraries?:: The `qvm::vec` template is not in any way central to the vector operations defined by QVM. The operations are designed to work with any user-defined vector type or with 3rd-party vector types (e.g. `D3DVECTOR`), while the `qvm::vec` template is simply a default return type for expressions that use arguments of different types that would be incompatible outside of QVM. For example, if the <<deduce_mat2,`deduce_mat2`>> hasn't been specialized, calling <<cross,`cross`>> with a user-defined type `vec3` and a user-defined type `float3` returns a `qvm::vec`.
5092
5093Why doesn't QVM use [] or () to access vector and matrix elements?:: Because it's designed to work with user-defined types, and the {CPP} standard requires these operators to be members. Of course if a user-defined type defines `operator[]` or `operator()` they are available for use with other QVM functions, but QVM defines its own mechanisms for <<quat_access,accessing quaternion elements>>, <<vec_access,accessing vector elements>> (as well as <<swizzling,swizzling>>), and <<mat_access,accessing matrix elements>>.
5094
5095'''
5096
5097[.text-right]
5098(C) 2008-2018 Emil Dotchevski and Reverge Studios, Inc.
5099