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