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