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