Boost C++ 库

...世界上最受推崇和设计最精良的 C++ 库项目之一。 Herb SutterAndrei Alexandrescu, C++ 编码标准

摘要

QVM 是一个用于处理静态大小的四元数、向量和矩阵的通用库。特性

  • 强调图形学、视频游戏和模拟应用中需要的 2、3 和 4 维运算。

  • 自由函数模板对任何兼容的用户自定义四元数、向量或矩阵类型进行操作。

  • 使来自不同库的四元数、向量和矩阵类型可以在同一表达式中安全地混合使用。

  • 类型安全的映射在兼容的左值类型之间进行,没有临时对象;例如,转置重新映射对元素的访问,而不是转换矩阵。

  • 仅需 C++03。

  • 零依赖。

支持

可移植性

QVM 仅需 C++03,但在许多编译器版本和 C++ 标准上进行了测试。

发行

版权所有 2008-2023 Emil Dotchevski。根据 Boost 软件许可,版本 1.0 分发。

有三个发行渠道

  • QVM 包含在官方 Boost 发行版中。

  • 源代码托管在 GitHub 上。

  • 为了获得最大的可移植性,该库的最新版本也以单头文件格式提供,有两种变体(直接下载链接)

    • qvm.hpp:包含完整 QVM 源代码的单头文件,包括完整的 混合 重载集。

    • qvm_lite.hpp:包含除混合重载之外所有内容的单头文件。

QVM 不依赖于 Boost 或其他库。

教程

四元数、向量、矩阵

QVM 开箱即用地定义了通用而简单的 quatvecmat 类型。例如,以下代码片段创建一个绕 X 轴旋转的四元数对象

quat<float> rx = rotx_quat(3.14159f);

类似地,可以按给定向量平移的矩阵可以如下创建

vec<float,3> v = {0,0,7};
mat<float,4,4> tr = translation_mat(v);

常用的四元数、向量和矩阵运算适用于这些 QVM 类型,但是这些运算与任何特定类型解耦:它们适用于任何已通过特化 quat_traitsvec_traitsmat_traits 模板注册的合适类型。

例如,用户自定义的 3D 向量类型 float3 可以按如下方式引入 QVM

struct float3 { float a[3]; };

namespace boost { namespace qvm {

  template <>
  struct vec_traits<float3> {

    static int const dim=3;
    typedef float scalar_type;

    template <int I>
    static inline scalar_type & write_element( float3 & v ) {
      return v.a[I];
    }

    template <int I>
    static inline scalar_type read_element( float3 const & v ) {
      return v.a[I];
    }

    static inline scalar_type & write_element_idx( int i, float3 & v ) {
      return v.a[i];
    } //optional

    static inline scalar_type read_element_idx( int i, float3 const & v ) {
      return v.a[i];
    } //optional

  };

} }

等价地,使用 vec_traits_defaults 模板可以将上述内容缩短为

namespace boost { namespace qvm {

  template <>
  struct vec_traits<float3>: vec_traits_defaults<float3,float,3> {

    template <int I>
    static inline scalar_type & write_element( float3 & v ) {
      return v.a[I];
    }

    static inline scalar_type & write_element_idx( int i, float3 & v ) {
      return v.a[i];
    } //optional

  };

} }

在为用户自定义的 3x3 矩阵类型 float33 类似地特化 mat_traits 模板之后,QVM 头文件定义的完整向量和矩阵运算范围将自动变为可用

float3 v;
X(v) = 0;
Y(v) = 0;
Z(v) = 7;
float vmag = mag(v);
float33 m = rotx_mat<3>(3.14159f);
float3 vrot = m * v;

用户自定义的四元数类型也通过特化 quat_traits 模板类似地引入到 QVM。

为了支持无法通过引用访问元素的向量类型,可以将 write_element / write_element_idx 静态成员函数定义为 void 函数,该函数接受一个标量以写入元素,例如

template <int I>
static inline void write_element( float3 & v, scalar_type s ) {
  v.a[I] = s;
}

Boost QVM 自动检测提供了哪个替代方案。


C/C++ 数组

boost/qvm/quat_traits_array.hppvec_traits_array.hppmat_traits_array.hpp 中,QVM 定义了适当的 quat_traitsvec_traitsmat_traits 特化,允许 QVM 函数直接在纯旧式 C 数组上运行

float v[3] = {0,0,7};
float3 vrot = rotx_mat<3>(3.14159f) * v;

自然地,如果表达式的所有元素都是内置类型,则运算符重载无法生效。以下仍然是非法的

float v[3] = {0,0,7};
v *= 42;

可以使用 vrefmref 函数模板来解决此问题

float v[3] = {0,0,7};
vref(v) *= 42;

如果 C++-11 可用,则相同的头文件为 std::array 对象定义了适当的 quat_traitsvec_traitsmat_traits


视图代理

QVM 定义了各种函数模板,这些模板在(可能用户自定义的)四元数、向量和矩阵类型之间提供静态映射。以下示例将矩阵 m 的第 1 列(QVM 索引始终从零开始)乘以一个标量

void multiply_column1( float33 & m, float scalar ) {
  col<1>(m) *= scalar;
}

表达式 col<1>(m) 是未指定的 3D 向量类型的左值,它引用 m 的第 1 列。但请注意,这不会创建任何临时对象;相反,上面的 operator*= 直接使用对 m 的引用。

这是另一个示例,将矩阵的转置视图乘以某种用户自定义类型的向量 float3

float3 v = {0,0,7};
float3 vrot = transposed(rotx_mat<3>(3.14159f)) * v;

通常,各种视图代理函数返回未指定的、不可复制的类型的引用,这些引用指向原始对象。它们可以从任何兼容的向量或矩阵类型赋值或转换为任何兼容的向量或矩阵类型。


混合

QVM 允许通过混合访问向量元素,公开不同维度的向量视图,和/或具有重新排序元素的视图。以下示例绕 X 轴旋转 v,并将结果向量存储回 v,但交换了 X 和 Y 元素

float3 v = {0,0,7};
YXZ(v) = rotx_mat<3>(3.14159f) * v;

混合的一个特殊情况提供了向量对象的下一维度视图,添加 0 或 1 作为其最后一个分量。假设 float3 是 3D 向量类型,而 float4 是 4D 向量类型,则以下语句是有效的

float3 v = {0,0,7};
float4 point = XYZ1(v); //{0,0,7,1}
float4 vector = XYZ0(v); //{0,0,7,0}

混合也可以多次寻址向量元素

float3 v = {0,0,7};
float4 v1 = ZZZZ(v); //{7,7,7,7}

QVM 为 1D、2D、3D 和 4D 混合定义了 XYZW 的所有排列,此外,每个维度都定义了在任何位置使用 0 或 1 的变体(如果 0 或 1 出现在第一个位置,则混合函数名称以下划线开头,例如 _1XY)。

混合语法也可以用于将标量绑定为向量。例如

float3 v = _00X(42.0f); //{0,0,42}

SFINAE/enable_if

SFINAE 代表替换失败不是错误。这指的是 C++ 中的一种情况,其中模板参数的无效替换(包括当这些参数由于非限定调用而隐式推导出来时)本身不是错误。

在缺少概念支持的情况下,SFINAE 可以用于禁用函数模板重载,否则这些重载将呈现过于通用的签名。更正式地说,这由 Boost enable_if 库支持。

例如,QVM 定义了 operator* 重载,该重载适用于任何用户自定义的矩阵和向量类型。朴素的方法是将此重载声明如下

template <class Matrix,class Vector>
Vector operator*( Matrix const & m, Vector const & v );

即使函数定义可能包含仅针对 MatrixVector 类型编译的代码,但由于函数声明本身是有效的,因此它将参与在将任何两种类型的对象相乘时的重载解析。这通常会使重载解析变得模糊,并且编译器(正确地)发出错误。

使用 enable_if,QVM 以一种保留其通用签名的方式声明此类重载,但仅在传递的参数根据要定义的运算的语义有意义时才参与重载解析

template <class A,class B>
typename enable_if_c<
  is_mat<A>::value && is_vec<B>::value && mat_traits<A>::cols==vec_traits<B>::dim, //Condition
  B>::type //Return type
operator*( A const & a, B const & b );

为了简洁起见,本文档中的函数声明指定了控制它们是否启用的条件,而没有确切指定使用什么 enable_if 构造来实现此效果。


互操作性

QVM 的一个重要设计目标是它可以与第三方四元数、向量和矩阵类型以及库无缝协作。即使这些库重载了与 QVM 相同的 C++ 运算符,通过指定以下内容将整个 boost::qvm 命名空间引入作用域也是安全的

using namespace boost::qvm;

上面的 using 指令不会引入与第三方库定义的函数和运算符重载的歧义,因为

  • 大多数 boost::qvm 函数重载和所有运算符重载都使用 SFINAE/enable_if,这使得它们“消失”,除非表达式使用定义了适当的 QVM 特定类型特征的类型;

  • 每当这些重载与给定的表达式兼容时,它们的签名都非常通用,这意味着任何其他(用户定义的)兼容重载都将在任何重载解析中成为更好的匹配。

将整个 boost::qvm 命名空间引入作用域在访问第三方库定义的类型(而不是函数)时可能会引入歧义。在这种情况下,您可以安全地将命名空间 boost::qvm::sfinae 引入作用域,其中仅包含使用 SFINAE/enable_if 的函数和运算符重载。

为二元运算指定返回类型

boost::qvm 命名空间引入作用域可让您将来自不同 API 的向量和矩阵类型混合到通用的、类型安全的框架中。然而,在这种情况下,应考虑通过值返回对象的二元运算应返回什么类型。例如,如果您将类型为 user_matrix1 的 3x3 矩阵 m1 乘以类型为 user_matrix2 的 3x3 矩阵 m2,则该运算应返回什么类型?

答案是,默认情况下,QVM 返回某种兼容的矩阵类型,因此始终可以安全地编写

auto & m = m1 * m2; // auto requires C++11

但是,默认推导的类型隐式转换为任何兼容的矩阵类型,因此以下也是有效的,但会产生临时对象

user_matrix1 m = m1 * m2;

虽然临时对象可以被许多编译器优化掉,但可以通过特化 deduce_mat2 模板来完全避免它。例如,要指定将 user_matrix1 乘以 user_matrix2 应始终生成 user_matrix1 对象,您可以编写

namespace boost { namespace qvm {

  template <>
  struct deduce_mat2<user_matrix1,user_matrix2,3,3> {
    typedef user_matrix1 type;
  };

  template <>
  struct deduce_mat2<user_matrix2,user_matrix1,3,3> {
    typedef user_matrix1 type;
  };

} }

在使用独立库中的 deduce_quat2deduce_vec2deduce_mat2 时,请注意潜在的 ODR 违规。例如,如果 lib1deduce_vec2<lib1::vec,lib2::vec>::type 定义为 lib1::vec,并且在同一程序中 lib2deduce_vec2<lib1::vec,lib2::vec>::type 定义为 lib2::vec,则可能会发生这种情况。

最好将此类特化保留在 lib1lib2 之外。当然,lib1lib2 始终可以安全地使用 convert_tolib1::veclib2::vec 类型之间根据需要进行转换。

为一元运算指定返回类型

也许令人惊讶的是,通过值返回对象的一元运算具有类似但更简单的问题。那是因为调用它们的参数可能不可复制,例如

float m[3][3];
auto & inv = inverse(m);

上面,inverse 返回并由 inv 捕获的对象不能是 float[3][3] 类型,因为该类型不可复制。默认情况下,QVM“开箱即用”,返回一个合适的可复制矩阵类型的对象。可以通过特化 deduce_mat 模板来控制此推导过程。

在不同的四元数、向量和矩阵类型之间转换

任何时候,当您需要从任何其他兼容的矩阵类型创建特定 C++ 类型的矩阵时,都可以使用 convert_to 函数

user_matrix2 m=convert_to<user_matrix2>(m1 * m2);

参考

头文件

QVM 被拆分为多个头文件,以允许不同的编译单元仅 #include 它们需要的组件。本文档中的每个函数都指定了要使用它必须 #included 的确切头文件。

下表列出了常用组件以及它们所在的头文件。包含数字的头文件名称定义的函数仅适用于该维度的对象;例如,vec_operations2.hpp 仅包含用于处理 2D 向量的函数。

为了方便起见,提供了头文件 boost/qvm/all.hpp。它包含所有其他 QVM 头文件。

此外,Boost QVM 以单头文件格式提供,以实现最大的可移植性。请参阅 发行

表 1. 四元数头文件

四元数特征

#include <boost/qvm/quat_traits.hpp>
#include <boost/qvm/quat_traits_array.hpp>
#include <boost/qvm/deduce_quat.hpp>

四元数元素访问

#include <boost/qvm/quat_access.hpp>

四元数运算

#include <boost/qvm/quat_operations.hpp>

quat 类模板

#include <boost/qvm/quat.hpp>
表 2. 向量头文件

向量特征

#include <boost/qvm/vec_traits.hpp>
#include <boost/qvm/vec_traits_array.hpp>
#include <boost/qvm/deduce_vec.hpp>

向量元素访问

#include <boost/qvm/vec_access.hpp>

向量混合

#include <boost/qvm/swizzle.hpp>
#include <boost/qvm/swizzle2.hpp>
#include <boost/qvm/swizzle3.hpp>
#include <boost/qvm/swizzle4.hpp>

向量运算

#include <boost/qvm/vec_operations.hpp>
#include <boost/qvm/vec_operations2.hpp>
#include <boost/qvm/vec_operations3.hpp>
#include <boost/qvm/vec_operations4.hpp>

四元数-向量运算

#include <boost/qvm/quat_vec_operations.hpp>

向量-矩阵运算

#include <boost/qvm/vec_mat_operations.hpp>

向量-矩阵视图代理

#include <boost/qvm/map_vec_mat.hpp>

vec 类模板

#include <boost/qvm/vec.hpp>
表 3. 矩阵头文件

矩阵特征

#include <boost/qvm/mat_traits.hpp>
#include <boost/qvm/mat_traits_array.hpp>
#include <boost/qvm/deduce_mat.hpp>

矩阵元素访问

#include <boost/qvm/mat_access.hpp>

矩阵运算

#include <boost/qvm/mat_operations.hpp>
#include <boost/qvm/mat_operations2.hpp>
#include <boost/qvm/mat_operations3.hpp>
#include <boost/qvm/mat_operations4.hpp>

矩阵-矩阵视图代理

#include <boost/qvm/map_mat_mat.hpp>

矩阵-向量视图代理

#include <boost/qvm/map_mat_vec.hpp>

mat 类模板

#include <boost/qvm/mat.hpp>

类型特征系统

QVM 旨在与用户自定义的四元数、向量和矩阵类型以及用户自定义的标量类型一起使用。本节正式定义了集成此类类型的方式。


标量要求

有效的标量类型 S 必须具有可访问的析构函数、默认构造函数、复制构造函数和赋值运算符,并且必须支持以下运算

S operator*( S, S );
S operator/( S, S );
S operator+( S, S );
S operator-( S, S );

S & operator*=( S &, S );
S & operator/=( S &, S );
S & operator+=( S &, S );
S & operator-=( S &, S );

bool operator==( S, S );
bool operator!=( S, S );

此外,表达式 S(0) 应构造一个值为零的标量,S(1) 应构造一个值为一的标量,否则必须适当地特化 scalar_traits 模板。


is_scalar

#include <boost/qvm/scalar_traits.hpp>
namespace boost { namespace qvm {

  template <class T>
  struct is_scalar {
    static bool const value=false;
  };

  template <> struct is_scalar<char>           { static bool const value=true; };
  template <> struct is_scalar<signed char>    { static bool const value=true; };
  template <> struct is_scalar<unsigned char>  { static bool const value=true; };
  template <> struct is_scalar<signed short>   { static bool const value=true; };
  template <> struct is_scalar<unsigned short> { static bool const value=true; };
  template <> struct is_scalar<signed int>     { static bool const value=true; };
  template <> struct is_scalar<unsigned int>   { static bool const value=true; };
  template <> struct is_scalar<signed long>    { static bool const value=true; };
  template <> struct is_scalar<unsigned long>  { static bool const value=true; };
  template <> struct is_scalar<float>          { static bool const value=true; };
  template <> struct is_scalar<double>         { static bool const value=true; };
  template <> struct is_scalar<long double>    { static bool const value=true; };

} }

此模板定义了一个编译时布尔常量值,可用于确定类型 T 是否为有效的标量类型。它必须与 scalar_traits 模板一起特化,以便将用户自定义的标量类型引入 QVM。此类类型必须满足标量要求


scalar_traits

#include <boost/qvm/scalar_traits.hpp>
namespace boost { namespace qvm {

  template <class Scalar>
  struct scalar_traits {

    BOOST_QVM_INLINE_CRITICAL
    static Scalar value( int v ) {
      return Scalar(v);
    }

  };

} }

此模板可以为用户自定义的标量类型进行特化,以定义从 int 的适当转换;这主要用于 QVM 需要推导零或一值的情况。


deduce_scalar

#include <boost/qvm/deduce_scalar.hpp>
namespace boost { namespace qvm {

  template <class A,class B>
  struct deduce_scalar
  {
    typedef typename /*exact definition unspecified*/ type;
  };

} }
要求

AB 满足 标量要求

返回

如果 AB 是相同类型,则 scalar_traits<A,B>::type 定义为该类型。否则对于以下类型

  • signed/unsigned char,

  • signed/unsigned short,

  • signed/unsigned int,

  • signed/unsigned long,

  • float,

  • double,

推导逻辑如下

  • 如果 AB 中任何一个是 double,则结果为 double

  • 否则,如果 AB 之一是整数类型,而另一个是 float,则结果为 float

  • 否则,如果 AB 之一是有符号整数,而另一种类型是无符号整数,则有符号类型更改为无符号类型,然后将两个整数中较小的提升为另一个。

对于任何其他类型,scalar_traits<A,B>::type 定义为 void。它可以为用户自定义的标量类型进行特化。

此模板由返回标量的通用二元运算使用,以根据其参数的(可能不同的)标量推导返回类型。

scalar

#include <boost/qvm/scalar_traits.hpp>
namespace boost { namespace qvm {

  template <class T>
  struct scalar {
    typedef /*exact definition unspecified*/ type;
  };

} }

表达式 quat_traits<T>::scalar_type 求值为四元数类型 T 的标量类型(如果 is_quat<T>::valuetrue)。

表达式 vec_traits<T>::scalar_type 求值为向量类型 T 的标量类型(如果 is_vec<T>::valuetrue)。

表达式 mat_traits<T>::scalar_type 求值为矩阵类型 T 的标量类型(如果 is_mat<T>::valuetrue)。

表达式 scalar<T>::type 类似,不同之处在于它自动检测 T 是向量、矩阵还是四元数类型。


is_quat

#include <boost/qvm/quat_traits.hpp>
namespace boost { namespace qvm {

  template <class T>
  struct is_quat {

    static bool const value = false;

  };

} }

此类型模板定义了一个编译时布尔常量值,可用于确定类型 T 是否为四元数类型。对于四元数类型,quat_traits 模板可用于通用地访问其元素,或获取其 scalar type


quat_traits

#include <boost/qvm/quat_traits.hpp>
namespace boost { namespace qvm {

  template <class Q>
  struct quat_traits {

    /*main template members unspecified*/

  };

  /*
  User-defined (possibly partial) specializations:

  template <>
  struct quat_traits<Q> {

    typedef <<user-defined>> scalar_type;

    template <int I>
    static inline scalar_type read_element( Quaternion const & q );

    template <int I>
    static inline scalar_type & write_element( Quaternion & q );

    // Alternative signature for write_element:

    template <int I>
    static inline void write_element( Quaternion & q, scalar_type s );

  };
  */

} }

quat_traits 模板必须针对(用户自定义的)四元数类型进行特化,以便为这些类型的对象启用 QVM 头文件中定义的四元数运算。

QVM 四元数运算不要求四元数类型是可复制的。

主要的 quat_traits 模板成员未指定。有效的特化需要定义以下成员

  • scalar_type:表达式 quat_traits<Quaternion>::scalar_type 必须是满足 scalar requirements 的值类型。

此外,quat_traits 模板的有效特化必须将以下至少一个访问函数定义为静态成员,其中 qQuaternion 类型的对象,I 是编译时整数常量

  • read_element:表达式 quat_traits<Quaternion>::read_element<I>(q) 返回 q 的第 I 个元素的副本或 const 引用。

  • write_element:表达式 quat_traits<Quaternion>::write_element<I>(q) 返回 q 的第 I 个元素的可变引用。

或者,write_element 可以定义为 void 函数,该函数(作为最后一个参数)接受一个标量写入指定的元素。QVM 通过检查 write_element 模板的签名自动检测这种情况。
对于四元数 a + bi + cj + dk,元素假定按以下顺序排列:abcd;即,I=0/1/2/3 将访问 a/b/c/d

除非 is_quat<Quaternion>::value 为 true,否则调用上述任何函数都是非法的。即使这样,也允许四元数类型仅定义访问函数的子集。

下面是用户自定义的四元数类型的示例及其对应的 quat_traits 模板的特化

#include <boost/qvm/quat_traits.hpp>

struct fquat { float a[4]; };

namespace boost { namespace qvm {

  template <>
  struct quat_traits<fquat> {

    typedef float scalar_type;

    template <int I>
    static inline scalar_type & write_element( fquat & q ) {
      return q.a[I];
    }

    template <int I>
    static inline scalar_type read_element( fquat const & q ) {
      return q.a[I];
    }

  };

} }

等价地,使用 quat_traits_defaults 模板可以将上述内容缩短为

namespace boost { namespace qvm {

  template <>
  struct quat_traits<fquat>: quat_traits_defaults<fquat,float> {

    template <int I>
    static inline scalar_type & write_element( fquat & q ) {
      return q.a[I];
    }

  };

} }

quat_traits_defaults

#include <boost/qvm/quat_traits_defaults.hpp>
namespace boost { namespace qvm {

  template <class QuatType,class ScalarType>
  struct quat_traits_defaults {

    typedef QuatType quat_type;

    typedef ScalarType scalar_type;

    template <int I>
    static BOOST_QVM_INLINE_CRITICAL
    scalar_type read_element( quat_type const & x ) {
      return quat_traits<quat_type>::template
        write_element<I>(const_cast<quat_type &>(x));
    }

  };

} }

quat_traits_defaults 模板旨在用作 quat_traits 模板的用户自定义特化的公共基类,以轻松定义所需的成员。如果使用它,则用户在 quat_traits 特化中必须定义的唯一成员是 write_elementquat_traits_defaults 基类将自动定义 read_element 以及 scalar_type


deduce_quat

#include <boost/qvm/deduce_quat.hpp>
namespace boost { namespace qvm {

  template <class Q,
    class S=typename quat_traits<Q>::scalar_type>
  struct deduce_quat {
    typedef Q type;
  };

} }
要求
  • is_quat<Q>::valuetrue

  • is_scalar<S>::valuetrue

  • is_quat<deduce_quat<Q,S>::type>::value 必须为 true

  • quat_traits<deduce_quat<Q,S>::type>::scalar_type 必须与 S 的类型相同;

  • deduce_quat<Q,S>::type 必须是可复制的。

每当 QVM 需要从四元数类型 Q 推导可复制的四元数类型时,此模板都会被 QVM 使用,标量类型为 S。请注意,Q 本身可能不可复制。

主要模板定义返回未指定的四元数类型,除非 Squat_traits<Q>::scalar_type 的类型相同,在这种情况下,它返回 Q,这仅在 Q 可复制时才适用。QVM 还为其生成的不可复制的四元数类型定义了(部分)特化。用户可以为自己的类型定义其他(部分)特化。

deduce_quat 模板的典型用途是指定 QVM 中通用函数模板重载根据其参数类型返回的首选四元数类型。


deduce_quat2

#include <boost/qvm/deduce_quat.hpp>
namespace boost { namespace qvm {

  template <class A,class B,
    class S=typename deduce_scalar<
      typename scalar<A>::type,
      typename scalar<B>::type>::type>
  struct deduce_quat2 {
    typedef /*unspecified*/ type;
  };

} }
要求
  • scalar<A>::typescalar<B>::type 都已明确定义;

  • is_quat<A>::value || is_quat<B>::valuetrue

  • is_scalar<S>::valuetrue

  • is_quat<deduce_quat2<A,B,S>::type>::value 必须为 true

  • quat_traits<deduce_quat2<A,B,S>::type>::scalar_type 必须与 S 的类型相同;

  • deduce_quat2<A,B,S>::type 必须是可复制的。

每当 QVM 需要从两个用户提供的函数参数的类型中推导四元数类型时,此模板都会被 QVM 使用,标量类型为 S。返回的类型必须具有可访问的复制构造函数(AB 类型本身可能不可复制,并且它们中的任何一个可能不是四元数类型)。

主要模板定义返回具有 scalar_type S 的未指定四元数类型,除非 AB 是相同的四元数类型 Q,在这种情况下,返回 Q,这仅适用于可复制的类型。QVM 还为其生成的不可复制的四元数类型定义了(部分)特化。用户可以为自己的类型定义其他(部分)特化。

deduce_quat2 模板的典型用途是指定 QVM 中通用函数模板重载根据其参数类型返回的首选四元数类型。


is_vec

#include <boost/qvm/vec_traits.hpp>
namespace boost { namespace qvm {

  template <class T>
  struct is_vec {

    static bool const value = false;

  };

 } }

此类型模板定义了一个编译时布尔常量值,可用于确定类型 T 是否为向量类型。对于向量类型,vec_traits 模板可用于通用地访问其元素,或获取其维度和 scalar type


vec_traits

#include <boost/qvm/vec_traits.hpp>
namespace boost { namespace qvm {

  template <class V>
  struct vec_traits {

    /*main template members unspecified*/

  };

  /*
  User-defined (possibly partial) specializations:

  template <>
  struct vec_traits<V> {

    static int const dim = <<user-defined>>;

    typedef <<user-defined>> scalar_type;

    template <int I>
    static inline scalar_type read_element( Vector const & v );

    static inline scalar_type read_element_idx( int i, Vector const & v );

    template <int I>
    static inline scalar_type & write_element( Vector & v );

    static inline scalar_type & write_element_idx( int i, Vector & v );

    // Alternative signature for write_element and write_element_idx:

    template <int I>
    static inline void write_element( Vector & v, scalar_type s );

    static inline void write_element_idx( int i, Vector & v, scalar_type s );

  };
  */

} }

vec_traits 模板必须针对(用户自定义的)向量类型进行特化,以便为这些类型的对象启用 QVM 头文件中定义的向量和矩阵运算。

QVM 向量运算不要求向量类型是可复制的。

主要的 vec_traits 模板成员未指定。有效的特化需要定义以下成员

  • dim:表达式 vec_traits<Vector>::dim 必须求值为大于 0 的编译时整数常量,该常量指定向量大小。

  • scalar_type:表达式 vec_traits<Vector>::scalar_type 必须是满足 scalar requirements 的值类型。

此外,vec_traits 模板的有效特化可以将以下访问函数定义为静态成员,其中 vVector 类型的对象,I 是编译时整数常量,iint 类型的变量

  • read_element:表达式 vec_traits<Vector>::read_element<I>(v) 返回 v 的第 I 个元素的副本或 const 引用。

  • read_element_idx:表达式 vec_traits<Vector>::read_element_idx(i,v) 返回 v 的第 i 个元素的副本或 const 引用。

  • write_element:表达式 vec_traits<Vector>::write_element<I>(v) 返回 v 的第 I 个元素的可变引用。

  • write_element_idx:表达式 vec_traits<Vector>::write_element_idx(i,v) 返回 v 的第 i 个元素的可变引用。

或者,write_elementwrite_element_idx 可以定义为 void 函数,该函数(作为最后一个参数)接受一个标量写入指定的元素。QVM 通过检查 write_element 模板的签名自动检测这种情况。

除非 is_vec<Vector>::value 为 true,否则调用上述任何函数都是非法的。即使这样,也允许向量类型仅定义访问函数的子集。一般要求是

  • 必须定义 read_elementwrite_element 中的至少一个;

  • 如果定义了 read_element_idx,则还必须定义 read_element

  • 如果定义了 write_element_idx,则还必须定义 write_element

下面是用户自定义的 3D 向量类型的示例及其对应的 vec_traits 模板的特化

#include <boost/qvm/vec_traits.hpp>

struct float3 { float a[3]; };

namespace boost { namespace qvm {

  template <>
  struct vec_traits<float3> {

    static int const dim=3;

    typedef float scalar_type;

    template <int I>
    static inline scalar_type & write_element( float3 & v ) {
      return v.a[I];
    }

    template <int I>
    static inline scalar_type read_element( float3 const & v ) {
      return v.a[I];
    }

    static inline scalar_type & write_element_idx( int i, float3 & v ) {
      return v.a[i];
    } //optional

    static inline scalar_type read_element_idx( int i, float3 const & v ) {
      return v.a[i];
    } //optional

  };

} }

等价地,使用 vec_traits_defaults 模板可以将上述内容缩短为

namespace boost { namespace qvm {

  template <>
  struct vec_traits<float3>: vec_traits_defaults<float3,float,3>
  {

    template <int I>
    static inline scalar_type & write_element( float3 & v ) {
      return v.a[I];
    }

    static inline scalar_type & write_element_idx( int i, float3 & v ) {
      return v.a[i];
    } //optional

  };

} }

vec_traits_defaults

#include <boost/qvm/vec_traits_defaults.hpp>
namespace boost { namespace qvm {

  template <class VecType,class ScalarType,int Dim>
  struct vec_traits_defaults {

    typedef VecType vec_type;
    typedef ScalarType scalar_type;
    static int const dim=Dim;

    template <int I>
    static BOOST_QVM_INLINE_CRITICAL
    scalar_type write_element( vec_type const & x ) {
      return vec_traits<vec_type>::template write_element<I>(const_cast<vec_type &>(x));
    }

    static BOOST_QVM_INLINE_CRITICAL
    scalar_type read_element_idx( int i, vec_type const & x ) {
      return vec_traits<vec_type>::write_element_idx(i,const_cast<vec_type &>(x));
    }

    protected:

    static BOOST_QVM_INLINE_TRIVIAL
    scalar_type & write_element_idx( int i, vec_type & m ) {
      /* unspecified */
    }
  };

} }

vec_traits_defaults 模板旨在用作 vec_traits 模板的用户自定义特化的公共基类,以轻松定义所需的成员。如果使用它,则用户在 vec_traits 特化中必须定义的唯一成员是 write_elementvec_traits_defaults 基类将自动定义 read_element 以及 scalar_typedim

可选地,用户还可以定义 write_element_idx,在这种情况下,vec_traits_defaults 基类将自动提供合适的 read_element_idx 定义。如果不是,则 vec_traits_defaults 定义了 write_element_idx 的受保护实现,如果为其特化的向量类型无法有效索引,则派生的 vec_traits 特化可以公开提供该实现。此 write_element_idx 函数效率较低(使用元编程),根据所需的用户定义的 write_element 实现。


deduce_vec

#include <boost/qvm/deduce_vec.hpp>
namespace boost { namespace qvm {

  template <class V,
    int D=vec_traits<Vector>::dim,
    class S=typename vec_traits<V>::scalar_type>
  struct deduce_vec {

    typedef /*unspecified*/ type;

  };

} }
要求
  • is_vec<V>::valuetrue

  • is_scalar<S>::valuetrue

  • is_vec<deduce_vec<V,D,S>::type>::value 必须为 true

  • deduce_vec<V,D,S>::type 必须是可复制的;

  • vec_traits<deduce_vec<V,D,S>::type>::dim==D;

  • vec_traits<deduce_vec<V,D,S>::type>::scalar_typeS 的类型相同。

每当 QVM 需要从向量类型的单个用户提供的函数参数中推导特定维度的可复制向量类型时,此模板都会被 QVM 使用。返回的类型必须具有可访问的复制构造函数。请注意,V 可能不可复制。

主要模板定义返回大小为 D 且标量类型为 S 的未指定可复制向量类型,除非 vec_traits<V>::dim==Dvec_traits<V>::scalar_typeS 的类型相同,在这种情况下,它返回 V,这仅在 V 是可复制类型时才适用。QVM 还为其生成的不可复制的向量类型定义了(部分)特化。用户可以为自己的类型定义其他(部分)特化。

deduce_vec 模板的典型用途是指定 QVM 中通用函数模板重载根据其参数类型返回的首选向量类型。


deduce_vec2

#include <boost/qvm/deduce_vec.hpp>
namespace boost { namespace qvm {

  template <class A,class B,int D,
    class S=typename deduce_scalar<
      typename scalar<A>::type,
      typename scalar<B>::type>::type>
  struct deduce_vec2 {
    typedef /*unspecified*/ type;
  };

} }
要求
  • scalar<A>::typescalar<B>::type 都已明确定义;

  • is_vec<A>::value || is_vec<B>::valuetrue

  • is_scalar<S>::valuetrue

  • is_vec<deduce_vec2<A,B,D,S>::type>::value 必须为 true

  • deduce_vec2<A,B,D,S>::type 必须是可复制的;

  • vec_traits<deduce_vec2<A,B,D,S>::type>::dim==D.

  • vec_traits<deduce_vec2<A,B,D,S>::type>::scalar_typeS 的类型相同。

每当 QVM 需要从两个用户提供的函数参数的类型中推导特定维度的向量类型时,此模板都会被 QVM 使用。返回的类型必须具有可访问的复制构造函数(AB 类型本身可能不可复制,并且它们中的任何一个可能是非向量类型)。

主要模板定义返回具有 scalar_type S 的请求维度的未指定向量类型,除非 AB 是相同的向量类型 V,在这种情况下,返回 V,这仅适用于可复制的类型。QVM 还为其生成的不可复制的向量类型定义了(部分)特化。用户可以为自己的类型定义其他(部分)特化。

deduce_vec2 模板的典型用途是指定 QVM 中通用函数模板重载根据其参数类型返回的首选向量类型。


is_mat

#include <boost/qvm/mat_traits.hpp>
namespace boost { namespace qvm {

  template <class T>
  struct is_mat {

    static bool const value = false;

  };

} }

此类型模板定义了一个编译时布尔常量值,可用于确定类型 T 是否为矩阵类型。对于矩阵类型,mat_traits 模板可用于通用地访问其元素,或获取其维度和标量类型。


mat_traits

#include <boost/qvm/mat_traits.hpp>
namespace boost { namespace qvm {

  template <class M>
  struct mat_traits {

    /*main template members unspecified*/

  };

  /*
  User-defined (possibly partial) specializations:

  template <>
  struct mat_traits<M> {

    static int const rows = <<user-defined>>;
    static int const cols = <<user-defined>>;
    typedef <<user-defined>> scalar_type;

    template <int R,int C>
    static inline scalar_type read_element( Matrix const & m );

    static inline scalar_typeread_element_idx( int r, int c, Matrix const & m );

    template <int R,int C>
    static inline scalar_type & write_element( Matrix & m );

    static inline scalar_type & write_element_idx( int r, int c, Matrix & m );

    // Alternative signature for write_element and write_element_idx:

    template <int R,int C>
    static inline void write_element( Matrix & m, scalar_type s );

    static inline void write_element_idx( int r, int c, Matrix & m, scalar_type s );

  };
  */

} }

mat_traits 模板必须针对(用户自定义的)矩阵类型进行特化,以便为这些类型的对象启用 QVM 头文件中定义的向量和矩阵运算。

QVM 定义的矩阵运算不要求矩阵类型是可复制的。

主要的 mat_traits 模板成员未指定。有效的特化需要定义以下成员

  • rows:表达式 mat_traits<Matrix>::rows 必须求值为大于 0 的编译时整数常量,该常量指定矩阵中的行数。

  • cols 必须求值为大于 0 的编译时整数常量,该常量指定矩阵中的列数。

  • scalar_type:表达式 mat_traits<Matrix>::scalar_type 必须是满足标量要求的值类型。

此外,mat_traits 模板的有效特化可以将以下访问函数定义为静态成员,其中 mMatrix 类型的对象,RC 是编译时整数常量,rcint 类型的变量

  • read_element:表达式 mat_traits<Matrix>::read_element<R,C>(m) 返回 m 的第 R 行和第 C 列元素的副本或 const 引用。

  • read_element_idx:表达式 mat_traits<Matrix>::read_element_idx(r,c,m) 返回 m 的第 r 行和第 c 列元素的副本或 const 引用。

  • write_element:表达式 mat_traits<Matrix>::write_element<R,C>(m) 返回 m 的第 R 行和第 C 列元素的可变引用。

  • write_element_idx: 表达式 mat_traits<Matrix>::write_element_idx(r,c,m) 返回对 m 的第 r 行和第 c 列元素的可变引用。

或者,write_elementwrite_element_idx 可以定义为 void 函数,该函数(作为最后一个参数)接受一个标量写入指定的元素。QVM 通过检查 write_element 模板的签名自动检测这种情况。

除非 is_mat<Matrix>::value 为真,否则调用上述任何函数都是非法的。即使这样,矩阵类型也可能只定义访问函数的一个子集。一般要求是

  • 必须定义 read_elementwrite_element 中的至少一个;

  • 如果定义了 read_element_idx,则还必须定义 read_element

  • 如果定义了 write_element_idx,则还必须定义 write_element

下面是一个用户定义的 3x3 矩阵类型的示例,以及其对应的 mat_traits 模板的特化

#include <boost/qvm/mat_traits.hpp>

struct float33 { float a[3][3]; };

namespace boost { namespace qvm {

  template <>
  struct mat_traits<float33> {

    static int const rows=3;
    static int const cols=3;
    typedef float scalar_type;

    template <int R,int C>
    static inline scalar_type & write_element( float33 & m ) {
      return m.a[R][C];
    }

    template <int R,int C>
    static inline scalar_type read_element( float33 const & m ) {
      return m.a[R][C];
    }

    static inline scalar_type & write_element_idx( int r, int c, float33 & m ) {
      return m.a[r][c];
    }

    static inline scalar_type read_element_idx( int r, int c, float33 const & m ) {
      return m.a[r][c];
    }

  };

} }

等效地,我们可以使用 <<mat_traits_defaults,mat_traits_defaults 模板来缩短上面的代码,变为

namespace boost { namespace qvm {

  template <>
  struct mat_traits<float33>: mat_traits_defaults<float33,float,3,3> {

    template <int R,int C> static inline scalar_type & write_element( float33 & m ) { return m.a[R][C]; }

    static inline scalar_type & write_element_idx( int r, int c, float33 & m ) {
      return m.a[r][c];
    }

  };

} }

mat_traits_defaults

#include <boost/qvm/mat_traits_defaults.hpp>
namespace boost { namespace qvm {

  template <class MatType,class ScalarType,int Rows,int Cols>
  struct mat_traits_defaults
  {
    typedef MatType mat_type;
    typedef ScalarType scalar_type;
    static int const rows=Rows;
    static int const cols=Cols;

    template <int Row,int Col>
    static BOOST_QVM_INLINE_CRITICAL
    scalar_type write_element( mat_type const & x ) {
      return mat_traits<mat_type>::template write_element<Row,Col>(const_cast<mat_type &>(x));
    }

    static BOOST_QVM_INLINE_CRITICAL
    scalar_type read_element_idx( int r, int c, mat_type const & x ) {
      return mat_traits<mat_type>::write_element_idx(r,c,const_cast<mat_type &>(x));
    }

    protected:

    static BOOST_QVM_INLINE_TRIVIAL
    scalar_type & write_element_idx( int r, int c, mat_type & m ) {
      /* unspecified */
    }
  };

} }

mat_traits_defaults 模板被设计为用作 mat_traits 模板的用户自定义特化的公共基类,以便轻松定义必需的成员。如果使用它,用户在 mat_traits 特化中必须定义的唯一成员是 write_elementmat_traits_defaults 基类将自动定义 read_element,以及 scalar_typerowscols

可选地,用户也可以定义 write_element_idx,在这种情况下,mat_traits_defaults 基类将自动提供合适的 read_element_idx 定义。否则,mat_traits_defaults 定义了 write_element_idx 的受保护实现,如果为其特化的矩阵类型不能被高效地索引,则可以通过派生的 mat_traits 特化使其公开可用。这个 write_element_idx 函数效率较低(使用元编程),根据必需的用户定义的 write_element 实现。


deduce_mat

#include <boost/qvm/deduce_mat.hpp>
namespace boost { namespace qvm {

  template <
    class M,
    int R=mat_traits<Matrix>::rows,
    int C=mat_traits<Matrix>::cols,
    class S=typename mat_traits<M>::scalar_type>
  struct deduce_mat {

    typedef /*unspecified*/ type;

  };

} }
要求
  • is_mat<M,R,C,S>::valuetrue

  • is_mat<deduce_mat<M,R,C,S>::type>::value 必须为 true

  • deduce_mat<M,R,C,S>::type 必须是可复制的;

  • mat_traits<deduce_mat<M,R,C,S>::type>::rows==R;

  • mat_traits<deduce_mat<M,R,C,S>::type>::cols==C,

  • mat_traits<deduce_mat<M,R,C,S>::type::scalar_typeS 的类型相同。

当 QVM 需要从单个用户提供的矩阵类型函数参数中推导出具有特定维度的可复制矩阵类型时,就会使用此模板。返回的类型必须具有可访问的复制构造函数。请注意,M 本身可能是不可复制的。

主模板定义返回一个未指定的可复制矩阵类型,其大小为 R x C,标量类型为 S,除非 mat_traits<M>::rows==Rmat_traits<M>::cols==Colsmat_traits<M>::scalar_type 为 S,在这种情况下,它返回 M,这仅在 M 是可复制类型时才适用。QVM 还为其生成的不可复制矩阵类型定义了(部分)特化。用户可以为其自己的类型定义其他(部分)特化。

deduce_mat 模板的典型用法是指定 QVM 中泛型函数模板重载根据其参数类型返回的首选矩阵类型。


deduce_mat2

#include <boost/qvm/deduce_mat.hpp>
namespace boost { namespace qvm {

  template <class A,class B,int R,int C,
    class S = typename deduce_scalar<
      typename scalar<A>::type,
      typename scalar<B>::type>::type
  struct deduce_mat2 {

    typedef /*unspecified*/ type;

  };

} }
要求
  • scalar<A>::typescalar<B>::type 都已明确定义;

  • is_mat<A>::value || is_mat<B>::valuetrue

  • is_scalar<S>::valuetrue

  • is_mat<deduce_mat2<A,B>::type>::value 必须为 true

  • deduce_mat2<A,B,R,C,S>::type 必须是可复制的;

  • mat_traits<deduce_mat2<A,B,R,C,S>::type>::rows==R;

  • mat_traits<deduce_mat2<A,B,R,C,S>::type>::cols==C;

  • mat_traits<deduce_mat2<A,B,R,C,S>::type>::scalar_typeS 的类型相同。

当 QVM 需要从两个用户提供的函数参数的类型中推导出具有特定维度的矩阵类型时,就会使用此模板。返回的类型必须具有可访问的复制构造函数(AB 类型本身可能是不可复制的,并且其中任何一个都可能不是矩阵类型。)

主模板定义返回一个未指定的矩阵类型,其具有请求的维度和 scalar_type S,除非 AB 是相同的矩阵类型 M,在这种情况下,返回 M,这仅适用于可复制类型。QVM 还为其生成的不可复制矩阵类型定义了(部分)特化。用户可以为其自己的类型定义其他(部分)特化。

deduce_mat2 模板的典型用法是指定 QVM 中泛型函数模板重载根据其参数类型返回的首选矩阵类型。


内置四元数、向量和矩阵类型

QVM 定义了几个类模板(以及 quat_traitsvec_traitsmat_traits 模板的适当特化),这些模板可以用作通用的四元数、向量和矩阵类型。虽然直接使用这些类型并不典型,但 QVM 的主要设计目标是允许用户插入他们自己的四元数、向量和矩阵类型。

quat

#include <boost/qvm/quat.hpp>
namespace boost { namespace qvm {

    template <class T>
    struct quat {

      T a[4];

      template <class R>
      operator R() const {
        R r;
        assign(r,*this);
        return r;
      }

    };

    template <class Quaternion>
    struct quat_traits;

    template <class T>
    struct quat_traits< quat<T> > {

      typedef T scalar_type;

      template <int I>
      static scalar_type read_element( quat<T> const & x ) {
        return x.a[I];
      }

      template <int I>
      static scalar_type & write_element( quat<T> & x ) {
        return x.a[I];
      }

    };

} }

这是一个简单的四元数类型。它可以转换为任何其他四元数类型。

quat_traits 模板的部分特化使 quat 模板与 QVM 定义的通用操作兼容。


vec

#include <boost/qvm/vec.hpp>
namespace boost { namespace qvm {

    template <class T,int Dim>
    struct vec {

      T a[Dim];

      template <class R>
      operator R() const {
        R r;
        assign(r,*this);
        return r;
      }

    };

    template <class Vector>
    struct vec_traits;

    template <class T,int Dim>
    struct vec_traits< vec<T,Dim> > {

      typedef T scalar_type;
      static int const dim=Dim;

      template <int I>
      static scalar_type read_element( vec<T,Dim> const & x ) {
        return x.a[I];
      }

      template <int I>
      static scalar_type & write_element( vec<T,Dim> & x ) {
        return x.a[I];
      }

      static scalar_type read_element_idx( int i, vec<T,Dim> const & x ) {
        return x.a[i];
      }

      static scalar_type & write_element_idx( int i, vec<T,Dim> & x ) {
        return x.a[i];
      }
    };

} }

这是一个简单的向量类型。它可以转换为任何其他兼容大小的向量类型。

vec_traits 模板的部分特化使 vec 模板与 QVM 定义的通用操作兼容。


mat

#include <boost/qvm/mat.hpp>
namespace boost { namespace qvm {

  template <class T,int Rows,int Cols>
  struct mat {

    T a[Rows][Cols];

    template <class R>
    operator R() const {
      R r;
      assign(r,*this);
      return r;
    }

  };

  template <class Matrix>
  struct mat_traits;

  template <class T,int Rows,int Cols>
  struct mat_traits< mat<T,Rows,Cols> > {

    typedef T scalar_type;
    static int const rows=Rows;
    static int const cols=Cols;

    template <int Row,int Col>
    static scalar_type read_element( mat<T,Rows,Cols> const & x ) {
      return x.a[Row][Col];
    }

    template <int Row,int Col>
    static scalar_type & write_element( mat<T,Rows,Cols> & x ) {
      return x.a[Row][Col];
    }

    static scalar_type read_element_idx( int row, int col, mat<T,Rows,Cols> const & x ) {
      return x.a[row][col];
    }

    static scalar_type & write_element_idx( int row, int col, mat<T,Rows,Cols> & x ) {
      return x.a[row][col];
    }

  };

} }

这是一个简单的矩阵类型。它可以转换为任何其他兼容大小的矩阵类型。

mat_traits 模板的部分特化使 mat 模板与 QVM 定义的通用操作兼容。


元素访问

四元数

#include <boost/qvm/quat_access.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_quat<Q>::value

  template <class Q> -unspecified-return-type- S( Q & q );
  template <class Q> -unspecified-return-type- V( Q & q );
  template <class Q> -unspecified-return-type- X( Q & q );
  template <class Q> -unspecified-return-type- Y( Q & q );
  template <class Q> -unspecified-return-type- Z( Q & q );

} }

S(q) 形式的表达式可用于访问四元数 q 的标量分量。例如,

S(q) *= 42;

q 的标量分量乘以标量 42。

V(q) 形式的表达式可用于访问四元数 q 的向量分量。例如,

V(q) *= 42

q 的向量分量乘以标量 42。

向量分量的 XYZ 元素也可以使用 X(q)Y(q)Z(q) 直接访问。

返回类型是左值。

向量

#include <boost/qvm/vec_access.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_vec<V>::value

  template <int I,class V> -unspecified-return-type- A( V & v );
  template <class V> -unspecified-return-type- A0( V & v );
  template <class V> -unspecified-return-type- A1( V & v );
  ...
  template <class V> -unspecified-return-type- A9( V & v );

  template <class V> -unspecified-return-type- X( V & v );
  template <class V> -unspecified-return-type- Y( V & v );
  template <class V> -unspecified-return-type- Z( V & v );
  template <class V> -unspecified-return-type- W( V & v );

} }

A<I>(v) 形式的表达式可用于访问向量对象 v 的第 I 个元素。例如,表达式

A<1>(v) *= 42;

可用于将向量 v 中索引为 1 的元素(QVM 中的索引始终从零开始)乘以 42。

为了方便起见,对于 I 从 0 到 9,还有非模板重载;编写上述表达式的另一种方法是

A1(v) *= 42;

XYZW 的作用与 A0/A1/A2/A3 相同;编写上述表达式的又一种替代方法是

Y(v) *= 42;
返回类型是左值。

向量元素混合

#include <boost/qvm/swizzle.hpp>
namespace boost { namespace qvm {

  //*** Accessing vector elements by swizzling ***

  //2D view proxies, only enabled if:
  //  is_vec<V>::value
  template <class V> -unspecified-2D-vector-type- XX( V & v );
  template <class V> -unspecified-2D-vector-type- XY( V & v );
  template <class V> -unspecified-2D-vector-type- XZ( V & v );
  template <class V> -unspecified-2D-vector-type- XW( V & v );
  template <class V> -unspecified-2D-vector-type- X0( V & v );
  template <class V> -unspecified-2D-vector-type- X1( V & v );
  template <class V> -unspecified-2D-vector-type- YX( V & v );
  template <class V> -unspecified-2D-vector-type- YY( V & v );
  template <class V> -unspecified-2D-vector-type- YZ( V & v );
  template <class V> -unspecified-2D-vector-type- YW( V & v );
  template <class V> -unspecified-2D-vector-type- Y0( V & v );
  template <class V> -unspecified-2D-vector-type- Y1( V & v );
  template <class V> -unspecified-2D-vector-type- ZX( V & v );
  template <class V> -unspecified-2D-vector-type- ZY( V & v );
  template <class V> -unspecified-2D-vector-type- ZZ( V & v );
  template <class V> -unspecified-2D-vector-type- ZW( V & v );
  template <class V> -unspecified-2D-vector-type- Z0( V & v );
  template <class V> -unspecified-2D-vector-type- Z1( V & v );
  template <class V> -unspecified-2D-vector-type- WX( V & v );
  template <class V> -unspecified-2D-vector-type- WY( V & v );
  template <class V> -unspecified-2D-vector-type- WZ( V & v );
  template <class V> -unspecified-2D-vector-type- WW( V & v );
  template <class V> -unspecified-2D-vector-type- W0( V & v );
  template <class V> -unspecified-2D-vector-type- W1( V & v );
  ...
  //2D view proxies, only enabled if:
  //  is_scalar<S>::value
  template <class S> -unspecified-2D-vector-type- X0( S & s );
  template <class S> -unspecified-2D-vector-type- X1( S & s );
  template <class S> -unspecified-2D-vector-type- XX( S & s );
  ...
  -unspecified-2D-vector-type- _00();
  -unspecified-2D-vector-type- _01();
  -unspecified-2D-vector-type- _10();
  -unspecified-2D-vector-type- _11();

  //3D view proxies, only enabled if:
  //  is_vec<V>::value
  template <class V> -unspecified-3D-vector-type- XXX( V & v );
  ...
  template <class V> -unspecified-3D-vector-type- XXW( V & v );
  template <class V> -unspecified-3D-vector-type- XX0( V & v );
  template <class V> -unspecified-3D-vector-type- XX1( V & v );
  template <class V> -unspecified-3D-vector-type- XYX( V & v );
  ...
  template <class V> -unspecified-3D-vector-type- XY1( V & v );
  ...
  template <class V> -unspecified-3D-vector-type- WW1( V & v );
  ...
  //3D view proxies, only enabled if:
  //  is_scalar<S>::value
  template <class S> -unspecified-3D-vector-type- X00( S & s );
  template <class S> -unspecified-3D-vector-type- X01( S & s );
  ...
  template <class S> -unspecified-3D-vector-type- XXX( S & s );
  template <class S> -unspecified-3D-vector-type- XX0( S & s );
  ...
  -unspecified-3D-vector-type- _000();
  -unspecified-3D-vector-type- _001();
  -unspecified-3D-vector-type- _010();
  ...
  -unspecified-3D-vector-type- _111();

  //4D view proxies, only enabled if:
  //  is_vec<V>::value
  template <class V> -unspecified-4D-vector-type- XXXX( V & v );
  ...
  template <class V> -unspecified-4D-vector-type- XXXW( V & v );
  template <class V> -unspecified-4D-vector-type- XXX0( V & v );
  template <class V> -unspecified-4D-vector-type- XXX1( V & v );
  template <class V> -unspecified-4D-vector-type- XXYX( V & v );
  ...
  template <class V> -unspecified-4D-vector-type- XXY1( V & v );
  ...
  template <class V> -unspecified-4D-vector-type- WWW1( V & v );
  ...
  //4D view proxies, only enabled if:
  //  is_scalar<S>::value
  template <class S> -unspecified-4D-vector-type- X000( S & s );
  template <class S> -unspecified-4D-vector-type- X001( S & s );
  ...
  template <class S> -unspecified-4D-vector-type- XXXX( S & s );
  template <class S> -unspecified-4D-vector-type- XX00( S & s );
  ...
  -unspecified-4D-vector-type- _0000();
  -unspecified-4D-vector-type- _0001();
  -unspecified-4D-vector-type- _0010();
  ...
  -unspecified-4D-vector-type- _1111();

} }

混合允许零开销地直接访问 2D、3D 和 4D 向量元素的(可能重新排列的)子集。例如,如果 v 是一个 4D 向量,则表达式 YX(v) 是一个 2D 视图代理,其 X 元素指的是 vY 元素,而其 Y 元素指的是 vX 元素。像其他视图代理一样,YX 是一个左值,也就是说,如果 v2 是一个 2D 向量,可以写成

YX(v) = v2;

上面代码将保持 vZW 元素不变,但会将 v2Y 元素赋值给 vX 元素,并将 v2X 元素赋值给 vY 元素。

所有 XYZW01 的排列都可用于 2D、3D 和 4D 混合(如果混合标识符的第一个字符是 01,则它前面会加上一个 _,例如 _11XY)。

多次使用相同的向量元素是有效的:表达式 ZZZ(v) 是一个 3D 向量,其 XYZ 元素都指向 vZ 元素。

最后,标量可以被“混合”以将其作为向量访问:表达式 _0X01(42.0f) 是一个 4D 向量,其中 X=0,Y=42.0,Z=0,W=1。

矩阵

#include <boost/qvm/mat_access.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_quat<Q>::value

  template <int R,int C,class M> -unspecified-return-type- A( M & m );

  template <class M> -unspecified-return-type- A00( M & m );
  template <class M> -unspecified-return-type- A01( M & m );
  ...
  template <class M> -unspecified-return-type- A09( M & m );
  template <class M> -unspecified-return-type- A10( M & m );
  ...
  template <class M> -unspecified-return-type- A99( M & m );

} }

A<R,C>(m) 形式的表达式可用于访问矩阵对象 m 的第 R 行和第 C 列的元素。例如,表达式

A<4,2>(m) *= 42;

可用于将矩阵 m 的第 4 行和第 2 列的元素乘以 42。

为了方便起见,对于 R09 以及 C09,还有非模板重载;编写上述表达式的另一种方法是

A42(m) *= 42;
返回类型是左值。

四元数运算

assign

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_quat<A>::value && is_quat<B>::value
  template <class A,class B>
  A & assign( A & a, B const & b );

} }
效果

将四元数 b 的所有元素复制到四元数 a

返回

a.


convert_to

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_quat<R>::value && is_quat<A>::value
  template <class R,class A>
  R convert_to( A const & a );

  //Only enabled if:
  //  is_quat<R>::value && is_mat<A>::value &&
  //  mat_traits<A>::rows==3 && mat_traits<A>::cols==3
  template <class R,class A>
  R convert_to( A const & m );

} }
要求

R 必须是可复制的。

效果
  • 第一个重载等同于:R r; assign(r,a); return r;

  • 第二个重载假设 m 是一个标准正交旋转矩阵,并将其转换为执行相同旋转的四元数。


operator-=

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_quat<A>::value && is_quat<B>::value
  template <class A,class B>
  A & operator-=( A & a, B const & b );

} }
效果

a 的对应元素中减去 b 的元素。

返回

a.


operator- (一元)

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

   //Only enabled if: is_quat<A>::value
  template <class A>
  typename deduce_quat<A>::type
  operator-( A const & a );

} }
返回

一个包含 a 的元素取反后的四元数。

可以特化 deduce_quat 模板,以从类型 A 推导出所需的返回类型。

operator- (二元)

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_quat<A>::value && is_quat<B>::value
  template <class A,class B>
  typename deduce_quat2<A,B>::type
  operator-( A const & a, B const & b );

} }
返回

一个四元数,其元素等于从 a 的对应元素中减去 b 的元素。

可以特化 deduce_quat2 模板,以根据类型 AB 推导出所需的返回类型。

operator+=

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_quat<A>::value && is_quat<B>::value
  template <class A,class B>
  A & operator+=( A & a, B const & b );

} }
效果

b 的元素添加到 a 的对应元素。

返回

a.


operator+

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_quat<A>::value && is_quat<B>::value &&
  template <class A,class B>
  typename deduce_quat2<A,B>::type
  operator+( A const & a, B const & b );

} }
返回

一个四元数,其元素等于 a 的元素加上 b 的对应元素。

可以特化 deduce_quat2 模板,以根据类型 AB 推导出所需的返回类型。

operator/= (标量)

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value && is_scalar<B>::value
  template <class A,class B>
  A & operator/=( A & a, B b );

} }
效果

此操作将四元数除以标量。

返回

a.


operator/ (标量)

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value && is_scalar<B>::value
  template <class A,class B>
  typename deduce_quat2<A,B>>::type
  operator/( A const & a, B b );

} }
返回

一个四元数,它是将四元数 a 除以标量 b 的结果。

可以特化 deduce_quat2 模板,以从类型 AB 推导出所需的返回类型。

operator*= (标量)

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value && is_scalar<B>::value
  template <class A,class B>
  A & operator*=( A & a, B b );

} }
效果

此操作将四元数 a 乘以标量 b

返回

a.


operator*=

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_quat<A>::value && is_quat<B>::value
  template <class A,class B>
  A & operator*=( A & a, B const & b );

} }
效果

如同

A tmp(a);
a = tmp * b;
return a;

operator* (标量)

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value && is_scalar<B>::value
  template <class A,class B>
  typename deduce_quat2<A,B>::type
  operator*( A const & a, B b );

} }
返回

一个四元数,它是将四元数 a 乘以标量 b 的结果。

可以特化 deduce_quat2 模板,以从类型 AB 推导出所需的返回类型。

operator*

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_quat<A>::value && is_quat<B>::value
  template <class A,class B>
  typename deduce_quat2<A,B>::type
  operator*( A const & a, B const & b );

} }
返回

四元数 ab 相乘的结果。

可以特化 deduce_quat2 模板,以根据类型 AB 推导出所需的返回类型。

operator==

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_quat<A>::value && is_quat<B>::value
  template <class A,class B>
  bool operator==( A const & a, B const & b );

} }
返回

如果 a 的每个元素与其对应的 b 的元素比较相等,则为 true,否则为 false


operator!=

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_quat<A>::value && is_quat<B>::value
  template <class A,class B>
  bool operator!=( A const & a, B const & b );

} }
返回

!(a == b).


cmp

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_quat<A>::value && is_quat<B>::value
  template <class A,class B,class Cmp>
  bool cmp( A const & a, B const & b, Cmp pred );

} }
返回

类似于 operator==,不同之处在于它使用二元谓词 pred 来比较各个四元数元素。


mag_sqr

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value
  template <class A>
  typename quat_traits<A>::scalar_type
  mag_sqr( A const & a );

} }
返回

四元数 a 的平方大小。


mag

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value
  template <class A>
  typename quat_traits<A>::scalar_type
  mag( A const & a );

} }
返回

四元数 a 的大小。


normalized

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value
  template <class A>
  typename deduce_quat<A>::type
  normalized( A const & a );

} }
效果

如同

typename deduce_quat<A>::type tmp;
assign(tmp,a);
normalize(tmp);
return tmp;
可以特化 deduce_quat 模板,以从类型 A 推导出所需的返回类型。

normalize

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value
  template <class A>
  void normalize( A & a );

} }
效果

归一化 a

确保

mag(a)==scalar_traits<typename quat_traits<A>::scalar_type>::value(1)。

抛出

如果 a 的大小为零,则抛出 zero_magnitude_error


dot

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_quat<A>::value && is_quat<B>::value
  template <class A,class B>
  typename deduce_scalar<A,B>::type
  dot( A const & a, B const & b );

} }
返回

四元数 ab 的点积。

可以特化 deduce_scalar 模板,以根据类型 AB 推导出所需的返回类型。

conjugate

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value
  template <class A>
  typename deduce_quat<A>::type
  conjugate( A const & a );

} }
返回

计算 a 的共轭。

可以特化 deduce_quat 模板,以从类型 A 推导出所需的返回类型。

inverse

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value
  template <class A>
  typename deduce_quat<A>::type
  inverse( A const & a );

} }
返回

计算 a 的乘法逆元,或共轭范数比。

抛出

如果 a 的大小为零,则抛出 zero_magnitude_error

如果已知 a 是单位长度,则 conjugate 等同于 inverse,但计算速度更快。
可以特化 deduce_quat 模板,以从类型 A 推导出所需的返回类型。

slerp180 / slerp360

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_quat<A>::value && is_quat<B>::value && is_scalar<C>
  template <class A,class B,class C>
  typename deduce_quat2<A,B> >::type
  slerp180( A const & a, B const & b, C c );

  //Only enabled if:
  //  is_quat<A>::value && is_quat<B>::value && is_scalar<C>
  template <class A,class B,class C>
  typename deduce_quat2<A,B> >::type
  slerp360( A const & a, B const & b, C c );

  //Only enabled if:
  //  is_quat<A>::value && is_quat<B>::value && is_scalar<C>
  template <class A,class B,class C>
  typename deduce_quat2<A,B> >::type
  slerp( A const & a, B const & b, C c ) // Deprecated
    {
    return slerp360(a, b, t);
    }

} }
先决条件

t>=0 && t<=1.

返回

一个四元数,它是四元数 ab 以及插值参数 c 的球面线性插值结果。当 slerp 应用于单位四元数时,四元数路径以标准方式映射到 3D 旋转路径。效果是以均匀的角速度围绕固定的旋转轴旋转。

当由 ab 表示的旋转角度相差超过 180 度时,slerp180 始终在球面上取较短的路径,而 slerp360 则不然。两种行为都有用例,因为每种行为都会在不同的条件下引入不连续性。

数学上

auto q = slerp180(a, b, t);

等同于

auto q = slerp360(dot(a, b) < 0 ? -a : a, b, t);
以前版本的 QVM 仅实现了 slerp360 行为,但名称为 slerp。为了兼容性,这一点被保留了下来,但 slerp 现在已被弃用。请使用 slerp180slerp360
可以特化 deduce_quat2 模板,以根据类型 AB 推导出所需的返回类型。

zero_quat

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  template <class T>
  -unspecified-return-type- zero_quat();

} }
返回

一个只读的、未指定类型的四元数,其 scalar_typeT,所有元素都等于 scalar_traits<T>::value(0)


set_zero

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value
  template <class A>
  void set_zero( A & a );

} }
效果

如同

assign(a,
  zero_quat<typename quat_traits<A>::scalar_type>());

identity_quat

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  template <class S>
  -unspecified-return-type- identity_quat();

} }
返回

一个标量类型为 S 的单位四元数。


set_identity

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value
  template <class A>
  void set_identity( A & a );

} }
效果

如同

assign(
  a,
  identity_quat<typename quat_traits<A>::scalar_type>());

rot_quat

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_vec<A>::value && vec_traits<A>::dim==3
  template <class A,class Angle>
  -unspecified-return-type- rot_quat( A const & axis, Angle angle );

} }
返回

一个未指定类型的四元数,它执行围绕 axis 轴以 angle 弧度旋转的旋转。

抛出

如果轴向量的大小为零,则抛出 zero_magnitude_error

rot_quat 函数不是 view proxy;它返回一个临时对象。

set_rot

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_quat<A>::value &&
  //  is_vec<B>::value && vec_traits<B>::dim==3
  template <class A,class B, class Angle>
  void set_rot( A & a, B const & axis, Angle angle );

} }
效果

如同

assign(
  a,
  rot_quat(axis,angle));

rotate

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_quat<A>::value &&
  //  is_vec<B>::value && vec_traits<B>::dim==3
  template <class A,class B,class Angle>
  void rotate( A & a, B const & axis, Angle angle );

} }
效果

如同:a *= rot_quat(axis,angle)


rotx_quat

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  template <class Angle>
  -unspecified-return-type- rotx_quat( Angle const & angle );

} }
返回

一个 view proxy 四元数,其类型未指定,标量类型为 Angle,它执行围绕 X 轴以 angle 弧度旋转的旋转。


set_rotx

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value
  template <class A,class Angle>
  void set_rotx( A & a, Angle angle );

} }
效果

如同

assign(
  a,
  rotx_quat(angle));

rotate_x

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value
  template <class A,class Angle>
  void rotate_x( A & a, Angle angle );

} }
效果

如同:a *= rotx_quat(angle)


roty_quat

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  template <class Angle>
  -unspecified-return-type- roty_quat( Angle const & angle );

} }
返回

一个 view proxy 四元数,其类型未指定,标量类型为 Angle,它执行围绕 Y 轴以 angle 弧度旋转的旋转。


set_roty

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value
  template <class A,class Angle>
  void set_rotz( A & a, Angle angle );

} }
效果

如同

assign(
  a,
  roty_quat(angle));

rotate_y

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value
  template <class A,class Angle>
  void rotate_y( A & a, Angleangle );

} }
效果

如同:a *= roty_quat(angle)


rotz_quat

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

    template <class Angle>
    -unspecified-return-type- rotz_quat( Angle const & angle );

} }
返回

一个 view proxy 四元数,其类型未指定,标量类型为 Angle,它执行围绕 Z 轴以 angle 弧度旋转的旋转。


set_rotz

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value
  template <class A,class Angle>
  void set_rotz( A & a, Angle angle );

} }
效果

如同

assign(
  a,
  rotz_quat(angle));

rotate_z

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value
  template <class A,class Angle>
  void rotate_z( A & a, Angle angle );

} }
效果

如同:a *= rotz_quat(angle)


scalar_cast

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value
  template <class Scalar,class A>
  -unspecified-return_type- scalar_cast( A const & a );

} }
返回

a 的只读 view proxy,它看起来像一个与 a 具有相同维度的四元数,但具有 scalar_type Scalar 和从 a 的对应元素构造的元素。


to_string

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value
  template <class A>
  std::string to_string( A const & a );

} }
返回

a 的字符串表示,格式未指定。


qref

#include <boost/qvm/quat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_quat<A>::value
  template <class A>
  -unspecified-return-type- qref( A & a );

} }
返回

a 的恒等视图代理;也就是说,它只是访问 a 的元素。

a 是内置类型时,例如普通的 C 数组,qref 允许调用 QVM 操作。

向量运算

assign

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if:
    //  is_vec<A>::value && is_vec<B>::value &&
    //  vec_traits<A>::dim==vec_traits<B>::dim
    template <class A,class B>
    A & assign( A & a, B const & b );

} }
效果

将向量 b 的所有元素复制到向量 a

返回

a.


convert_to

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if:
    //  is_vec<R>::value && is_vec<A>::value &&
    //  vec_traits<R>::dim==vec_traits<A>::dim
    template <class R,class A>
    R convert_to( A const & a );

} }
要求

R 必须是可复制的。

效果

如同:R r; assign(r,a); return r;


operator-=

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if:
    //  is_vec<A>::value && is_vec<B>::value &&
    //  vec_traits<A>::dim==vec_traits<B>::dim
    template <class A,class B>
    A & operator-=( A & a, B const & b );

} }
效果

a 的对应元素中减去 b 的元素。

返回

a.


operator- (一元)

operator-(vec)

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if: is_vec<A>::value
    template <class A>
    typename deduce_vec<A>::type
    operator-( A const & a );

} }
返回

一个包含 a 的元素取反后的向量。

可以特化 deduce_vec 模板,以从类型 A 推导出所需的返回类型。

operator- (二元)

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if:
    //  is_vec<A>::value && is_vec<B>::value &&
    //  vec_traits<A>::dim==vec_traits<B>::dim
    template <class A,class B>
    typename deduce_vec2<A,B,vec_traits<A>::dim>::type
    operator-( A const & a, B const & b );

} }
返回

一个与 ab 大小相同的向量,其元素是从 a 的对应元素中减去 b 的元素。

可以特化 deduce_vec2 模板,以根据类型 AB 推导出所需的返回类型。

operator+=

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if:
    //  is_vec<A>::value && is_vec<B>::value &&
    //  vec_traits<A>::dim==vec_traits<B>::dim
    template <class A,class B>
    A & operator+=( A & a, B const & b );

} }
效果

b 的元素添加到 a 的对应元素。

返回

a.


operator+

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if:
    //  is_vec<A>::value && is_vec<B>::value &&
    //  vec_traits<A>::dim==vec_traits<B>::dim
    template <class A,class B>
    typename deduce_vec2<A,B,vec_traits<A>::dim>::type
    operator+( A const & a, B const & b );

} }
返回

一个与 ab 大小相同的向量,其元素是 b 的元素加上 a 的对应元素。

可以特化 deduce_vec2 模板,以根据类型 AB 推导出所需的返回类型。

operator/= (标量)

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if: is_vec<A>::value && is_scalar<B>::value
    template <class A,class B>
    A & operator/=( A & a, B b );

} }
效果

此操作将向量除以标量。

返回

a.


operator/

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if: is_vec<A>::value && is_scalar<B>::value
    template <class A,class B>
    typename deduce_vec2<A,B,vec_traits<A>::dim>::type
    operator/( A const & a, B b );

} }
返回

一个向量,它是将向量 a 除以标量 b 的结果。

可以特化 deduce_vec2 模板,以从类型 AB 推导出所需的返回类型。

operator*=

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if: is_vec<A>::value && is_scalar<B>::value
    template <class A,class B>
    A & operator*=( A & a, B b );

} }
效果

此操作将向量 a 乘以标量 b

返回

a.


operator*

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if: is_vec<A>::value && is_scalar<B>::value
    template <class A,class B>
    typename deduce_vec2<A,B,vec_traits<A>::dim>::type
    operator*( A const & a, B b );

    //Only enabled if: is_scalar<B>::value && is_vec<A>::value
    template <class B,class A>
    typename deduce_vec2<A,B,vec_traits<A>::dim>::type
    operator*( B b, A const & a );

} }
返回

一个向量,它是将向量 a 乘以标量 b 的结果。

可以特化 deduce_vec2 模板,以从类型 AB 推导出所需的返回类型。

operator==

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if:
    //  is_vec<A>::value && is_vec<B>::value &&
    //  vec_traits<A>::dim==vec_traits<B>::dim
    template <class A,class B>
    bool operator==( A const & a, B const & b );

} }
返回

如果 a 的每个元素与其对应的 b 的元素比较相等,则为 true,否则为 false


operator!=

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if:
    //  is_vec<A>::value && is_vec<B>::value &&
    //  vec_traits<A>::dim==vec_traits<B>::dim
    template <class A,class B>
    bool operator!=( A const & a, B const & b );

} }
返回

!(a == b).


cmp

.#include <boost/qvm/mat_operations.hpp>

namespace boost
{
  namespace qvm
  {
    //Only enabled if:
    //  is_mat<A>::value && is_mat<B>::value &&
    //  mat_traits<A>::rows==mat_traits<B>::rows &&
    //  mat_traits<A>::cols==mat_traits<B>::cols
    template <class A,class B,class Cmp>
    bool cmp( A const & a, B const & b, Cmp pred );

} }
返回

类似于 operator==,不同之处在于 ab 的各个元素被传递给二元谓词 pred 进行比较。


mag_sqr

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if:
    //  is_vec<A>::value
    template <class A>
    typename vec_traits<A>::scalar_type
    mag_sqr( A const & a );

} }
返回

向量 a 的平方大小。


mag

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if:
    //  is_vec<A>::value
    template <class A>
    typename vec_traits<A>::scalar_type
    mag( A const & a );

} }
返回

向量 a 的大小。


normalized

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if:
    //  is_vec<A>::value
    template <class A>
    typename deduce_vec<A>::type
    normalized( A const & a );

} }
效果

如同

typename deduce_vec<A>::type tmp;
assign(tmp,a);
normalize(tmp);
return tmp;
可以特化 deduce_vec 模板,以从类型 A 推导出所需的返回类型。

normalize

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if:
    //  is_vec<A>::value
    template <class A>
    void normalize( A & a );

} }
效果

归一化 a

确保

mag(a)==scalar_traits<typename vec_traits<A>::scalar_type>::value(1).

抛出

如果 a 的大小为零,则抛出 zero_magnitude_error


dot

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if:
    //  is_vec<A>::value && is_vec<B>::value &&
    //  vec_traits<A>::dim==vec_traits<B>::dim
    template <class A,class B>
    typename deduce_scalar<A,B>::type
    dot( A const & a, B const & b );

} }
返回

向量 ab 的点积。

可以特化 deduce_scalar 模板,以根据类型 AB 推导出所需的返回类型。

cross

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if:
    //  is_vec<A>::value && is_vec<B>::value &&
    //  vec_traits<A>::dim==3 && vec_traits<B>::dim==3
    template <class A,class B>
    typename deduce_vec2<A,B,3>::type
    cross( A const & a, B const & b );

    //Only enabled if:
    //  is_vec<A>::value && is_vec<B>::value &&
    //  vec_traits<A>::dim==2 && vec_traits<B>::dim==2
    template <class A,class B>
    typename deduce_scalar<
      typename vec_traits<A>::scalar_type,
      typename vec_traits<B>::scalar_type>::type
    cross( A const & a, B const & b );

} }
返回

向量 ab 的叉积。

可以特化 deduce_vec2(和 deduce_scalar)模板,以根据类型 AB 推导出所需的返回类型。

zero_vec

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    template <class T,int S>
    -unspecified-return-type- zero_vec();

} }
返回

一个只读的、未指定类型的向量,其 scalar_typeT,大小为 S,所有元素都等于 scalar_traits<T>::value(0)


set_zero

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if:
    //  is_vec<A>::value
    template <class A>
    void set_zero( A & a );

} }
效果

如同

assign(a,
  zero_vec<
    typename vec_traits<A>::scalar_type,
    vec_traits<A>::dim>());

scalar_cast

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if: is_vec<A>::value
    template <class Scalar,class A>
    -unspecified-return_type- scalar_cast( A const & a );

} }
返回

a 的只读 view proxy,它看起来像一个与 a 具有相同维度的向量,但具有 scalar_type Scalar 和从 a 的对应元素构造的元素。


to_string

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_vec<A>::value
  template <class A>
  std::string to_string( A const & a );

} }
返回

a 的字符串表示,格式未指定。


vref

#include <boost/qvm/vec_operations.hpp>
namespace boost { namespace qvm {

    //Only enabled if: is_vec<A>::value
    template <class A>
    -unspecified-return-type- vref( A & a );

} }
返回

a 的恒等 view proxy;也就是说,它只是访问 a 的元素。

a 是内置类型时,例如普通的 C 数组,vref 允许调用 QVM 操作。

矩阵运算

assign

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && is_mat<B>::value &&
  //  mat_traits<A>::rows==mat_traits<B>::rows &&
  //  mat_traits<A>::cols==mat_traits<B>::cols
  template <class A,class B>
  A & assign( A & a, B const & b );

} }
效果

将矩阵 b 的所有元素复制到矩阵 a

返回

a.


convert_to

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<R>::value && is_mat<A>::value &&
  //  mat_traits<R>::rows==mat_traits<A>::rows &&
  //  mat_traits<R>::cols==mat_traits<A>::cols
  template <class R,class A>
  R convert_to( A const & a );

} }
要求

R 必须是可复制的。

效果

如同:R r; assign(r,a); return r;


operator-=

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && is_mat<B>::value &&
  //  mat_traits<A>::rows==mat_traits<B>::rows &&
  //  mat_traits<A>::cols==mat_traits<B>::cols
  template <class A,class B>
  A & operator-=( A & a, B const & b );

} }
效果

a 的对应元素中减去 b 的元素。

返回

a.


operator- (一元)

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_mat<A>::value
  template <class A>
  typename deduce_mat<A>::type
  operator-( A const & a );

} }
返回

一个包含 a 的元素取反后的矩阵。

可以特化 deduce_mat 模板,以从类型 A 推导出所需的返回类型。

operator-

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && is_mat<B>::value &&
  //  mat_traits<A>::rows==mat_traits<B>::rows &&
  //  mat_traits<A>::cols==mat_traits<B>::cols
  template <class A,class B>
  typename deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols>::type
  operator-( A const & a, B const & b );

} }
返回

一个与 ab 大小相同的矩阵,其元素是从 a 的对应元素中减去 b 的元素。

可以特化 deduce_mat2 模板,以根据类型 AB 推导出所需的返回类型。

operator+=

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && is_mat<B>::value &&
  //  mat_traits<A>::rows==mat_traits<B>::rows &&
  //  mat_traits<A>::cols==mat_traits<B>::cols
  template <class A,class B>
  A & operator+=( A & a, B const & b );

} }
效果

b 的元素添加到 a 的对应元素。

返回

a.


operator+

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && is_mat<B>::value &&
  //  mat_traits<A>::rows==mat_traits<B>::rows &&
  //  mat_traits<A>::cols==mat_traits<B>::cols
  template <class A,class B>
  typename deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols>::type
  operator+( A const & a, B const & b );

} }
返回

一个与 ab 大小相同的矩阵,其元素是 b 的元素加上 a 的对应元素。

可以特化 deduce_mat2 模板,以根据类型 AB 推导出所需的返回类型。

operator/= (标量)

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_mat<A>::value && is_scalar<B>::value
  template <class A,class B>
  A & operator/=( A & a, B b );

} }
效果

此操作将矩阵除以标量。

返回

a.


operator/ (标量)

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_mat<A>::value && is_scalar<B>::value
  template <class A,class B>
  typename deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols>::type
  operator/( A const & a, B b );

} }
返回

一个矩阵,它是将矩阵 a 除以标量 b 的结果。

可以特化 deduce_mat2 模板,以从类型 AB 推导出所需的返回类型。

operator*=

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && is_mat<B>::value &&
  //  mat_traits<A>::rows==mat_traits<A>::cols &&
  //  mat_traits<A>::rows==mat_traits<B>::rows &&
  //  mat_traits<A>::cols==mat_traits<B>::cols
  template <class A,class B>
  A & operator*=( A & a, B const & b );

} }
效果

如同

A tmp(a);
a = tmp * b;
return a;

operator*= (标量)

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_mat<A>::value && is_scalar<B>::value
  template <class A,class B>
  A & operator*=( A & a, B b );

} }
效果

此操作将矩阵 a 乘以标量 b 的矩阵。

返回

a.


operator*

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && is_mat<B>::value &&
  //  mat_traits<A>::cols==mat_traits<B>::rows
  template <class A,class B>
  typename deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<B>::cols>::type
  operator*( A const & a, B const & b );

} }
返回

矩阵 ab 的结果。

可以特化 deduce_mat2 模板,以根据类型 AB 推导出所需的返回类型。

operator* (标量)

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_mat<A>::value && is_scalar<B>::value
  template <class A,class B>
  typename deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols>::type
  operator*( A const & a, B b );

  //Only enabled if: is_scalar<B>::value && is_mat<A>::value
  template <class B,class A>
  typename deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols>::type
  operator*( B b, A const & a );

} }
返回

一个矩阵,它是将矩阵 a 乘以标量 b 的结果。

可以特化 deduce_mat2 模板,以从类型 AB 推导出所需的返回类型。

operator==

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && is_mat<B>::value &&
  //  mat_traits<A>::rows==mat_traits<B>::rows &&
  //  mat_traits<A>::cols==mat_traits<B>::cols
  template <class A,class B>
  bool operator==( A const & a, B const & b );

} }
返回

如果 a 的每个元素与其对应的 b 的元素比较相等,则为 true,否则为 false


operator!=

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && is_mat<B>::value &&
  //  mat_traits<A>::rows==mat_traits<B>::rows &&
  //  mat_traits<A>::cols==mat_traits<B>::cols
  template <class A,class B>
  bool operator!=( A const & a, B const & b );

} }
返回

!( a == b ).


cmp

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && is_mat<B>::value &&
  //  mat_traits<A>::rows==mat_traits<B>::rows &&
  //  mat_traits<A>::cols==mat_traits<B>::cols
  template <class A,class B,class Cmp>
  bool cmp( A const & a, B const & b, Cmp pred );

} }
返回

类似于 operator==,不同之处在于 ab 的各个元素被传递给二元谓词 pred 进行比较。


inverse

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && is_scalar<B>::value
  //  mat_traits<A>::rows==mat_traits<A>::cols

  template <class A,class B>
  typename deduce_mat2<A,B,mat_traits<A>::rows,mat_traits<A>::cols>::type
  inverse( A const & a, B det );

  template <class A>
  typename deduce_mat<A>::type
  inverse( A const & a );

} }
先决条件

det!=0

返回

两个重载都计算 a 的逆矩阵。第一个重载采用 a 的预先计算的行列式。

抛出

第二个重载自动计算行列式,如果计算出的行列式为零,则抛出 zero_determinant_error

可以特化 deduce_mat(和 deduce_mat2)模板,以从类型 A(和 B)推导出所需的返回类型。

zero_mat

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  template <class T,int D>
  -unspecified-return-type- zero_mat();

  template <class T,int R,int C>
  -unspecified-return-type- zero_mat();

} }
返回

一个只读的、未指定类型的矩阵,其 scalar_typeT,具有 R 行和 C 列(或 D 行和 D 列),所有元素都等于 scalar_traits<T>::value(0)


set_zero

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value
  template <class A>
  void set_zero( A & a );

} }
效果

如同

assign(a,
  zero_mat<
    typename mat_traits<A>::scalar_type,
    mat_traits<A>::rows,
    mat_traits<A>::cols>());

identity_mat

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  template <class S,int D>
  -unspecified-return-type- identity_mat();

} }
返回

一个大小为 D x D,标量类型为 S 的单位矩阵。


set_identity

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value &&
  //  mat_traits<A>::cols==mat_traits<A>::rows
  template <class A>
  void set_identity( A & a );

} }
效果

如同

assign(
  a,
  identity_mat<
    typename mat_traits<A>::scalar_type,
    mat_traits<A>::rows,
    mat_traits<A>::cols>());

rot_mat / 欧拉角

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_vec<A>::value && vec_traits<A>::dim==3
  template <int Dim,class A,class Angle>
  -unspecified-return-type-
  rot_mat( A const & axis, Angle angle );

  template <int Dim,class Angle>
  -unspecified-return-type-
  rot_mat_xzy( Angle x1, Angle z2, Angle y3 );

  template <int Dim,class Angle>
  -unspecified-return-type-
  rot_mat_xyz( Angle x1, Angle y2, Angle z3 );

  template <int Dim,class Angle>
  -unspecified-return-type-
  rot_mat_yxz( Angle y1, Angle x2, Angle z3 );

  template <int Dim,class Angle>
  -unspecified-return-type-
  rot_mat_yzx( Angle y1, Angle z2, Angle x3 );

  template <int Dim,class Angle>
  -unspecified-return-type-
  rot_mat_zyx( Angle z1, Angle y2, Angle x3 );

  template <int Dim,class Angle>
  -unspecified-return-type-
  rot_mat_zxy( Angle z1, Angle x2, Angle y3 );

  template <int Dim,class Angle>
  -unspecified-return-type-
  rot_mat_xzx( Angle x1, Angle z2, Angle x3 );

  template <int Dim,class Angle>
  -unspecified-return-type-
  rot_mat_xyx( Angle x1, Angle y2, Angle x3 );

  template <int Dim,class Angle>
  -unspecified-return-type-
  rot_mat_yxy( Angle y1, Angle x2, Angle y3 );

  template <int Dim,class Angle>
  -unspecified-return-type-
  rot_mat_yzy( Angle y1, Angle z2, Angle y3 );

  template <int Dim,class Angle>
  -unspecified-return-type-
  rot_mat_zyz( Angle z1, Angle y2, Angle z3 );

  template <int Dim,class Angle>
  -unspecified-return-type-
  rot_mat_zxz( Angle z1, Angle y2, Angle z3 );

} }
返回

一个未指定类型的矩阵,具有 Dim 行和 Dim 列参数,它执行围绕 axis 轴以 angle 弧度旋转的旋转,或 Tait–Bryan 角(x-y-z、y-z-x、z-x-y、x-z-y、z-y-x、y-x-z),或真欧拉角(z-x-z、x-y-x、y-z-y、z-y-z、x-z-x、y-x-y)。请参阅 欧拉角

抛出

如果轴向量的大小为零,则抛出 zero_magnitude_error

这些函数在语义上等同于乘以 rotx_mat / roty_mat / rotz_mat 返回的矩阵。例如,rot_mat_yzx<3>(a, b, c) 在语义上等同于 roty_mat<3>(a) * rotz_mat<3>(b) * rotx_mat<3>(c)
这些函数不是视图代理;它们返回一个临时对象。

set_rot / 欧拉角

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols &&
  //  is_vec<B>::value && vec_traits<B>::dim==3
  template <class A,class B, class Angle>
  void set_rot( A & a, B const & axis, Angle angle );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void set_rot_xzy( A & a, Angle x1, Angle z2, Angle y3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void set_rot_xyz( A & a, Angle x1, Angle y2, Angle z3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void set_rot_yxz( A & a, Angle y1, Angle x2, Angle z3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void set_rot_yzx( A & a, Angle y1, Angle z2, Angle x3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void set_rot_zyx( A & a, Angle z1, Angle y2, Angle x3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void set_rot_zxy( A & a, Angle z1, Angle x2, Angle y3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void set_rot_xzx( A & a, Angle x1, Angle z2, Angle x3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void set_rot_xyx( A & a, Angle x1, Angle y2, Angle x3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void set_rot_yxy( A & a, Angle y1, Angle x2, Angle y3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void set_rot_yzy( A & a, Angle y1, Angle z2, Angle y3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void set_rot_zyz( A & a, Angle z1, Angle y2, Angle z3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void set_rot_zxz( A & a, Angle z1, Angle x2, Angle z3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void set_rot_xzy( A & a, Angle x1, Angle z2, Angle y3 );

} }
效果

将相应的 rot_mat 函数的返回值赋值给 a


rotate / 欧拉角

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols &&
  //  is_vec<B>::value && vec_traits<B>::dim==3
  template <class A,class B,class Angle>
  void rotate( A & a, B const & axis, Angle angle );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void rotate_xzy( A & a, Angle x1, Angle z2, Angle y3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void rotate_xyz( A & a, Angle x1, Angle y2, Angle z3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void rotate_yxz( A & a, Angle y1, Angle x2, Angle z3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void rotate_yzx( A & a, Angle y1, Angle z2, Angle x3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void rotate_zyx( A & a, Angle z1, Angle y2, Angle x3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void rotate_zxy( A & a, Angle z1, Angle x2, Angle y3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void rotate_xzx( A & a, Angle x1, Angle z2, Angle x3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void rotate_xyx( A & a, Angle x1, Angle y2, Angle x3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void rotate_yxy( A & a, Angle y1, Angle x2, Angle y3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void rotate_yzy( A & a, Angle y1, Angle z2, Angle y3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void rotate_zyz( A & a, Angle z1, Angle y2, Angle z3 );

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void rotate_zxz( A & a, Angle z1, Angle x2, Angle z3 );

} }
效果

将矩阵 a 原位乘以相应的 rot_mat 函数的返回值。


rotx_mat

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  template <int Dim,class Angle>
  -unspecified-return-type- rotx_mat( Angle const & angle );

} }
返回

一个 view proxy 矩阵,其类型未指定,具有 Dim 行和 Dim 列以及标量类型 Angle,它执行围绕 X 轴以 angle 弧度旋转的旋转。


set_rotx

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void set_rotx( A & a, Angle angle );

} }
效果

如同

assign(
  a,
  rotx_mat<mat_traits<A>::rows>(angle));

rotate_x

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void rotate_x( A & a, Angle angle );

} }
效果

如同:a *= rotx_mat<mat_traits<A>::rows>(angle)


roty_mat

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  template <int Dim,class Angle>
  -unspecified-return-type- roty_mat( Angle const & angle );

} }
返回

一个 view proxy 矩阵,其类型未指定,具有 Dim 行和 Dim 列以及标量类型 Angle,它执行围绕 Y 轴以 angle 弧度旋转的旋转。


set_roty

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void set_roty( A & a, Angle angle );

} }
效果

如同

assign(
  a,
  roty_mat<mat_traits<A>::rows>(angle));

rotate_y

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void rotate_y( A & a, Angle angle );

} }
效果

如同:a *= roty_mat<mat_traits<A>::rows>(angle)


rotz_mat

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  template <int Dim,class Angle>
  -unspecified-return-type- rotz_mat( Angle const & angle );

} }
返回

一个 view proxy 矩阵,其类型未指定,具有 Dim 行和 Dim 列以及标量类型 Angle,它执行围绕 Z 轴以 angle 弧度旋转的旋转。


set_rotz

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void set_rotz( A & a, Angle angle );

} }
效果

如同

assign(
  a,
  rotz_mat<mat_traits<A>::rows>(angle));

rotate_z

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows>=3 &&
  //  mat_traits<A>::rows==mat_traits<A>::cols
  template <class A,class Angle>
  void rotate_z( A & a, Angle angle );

} }
效果

如同:a *= rotz_mat<mat_traits<A>::rows>(angle)


determinant

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && mat_traits<A>::rows==mat_traits<A>::cols
  template <class A>
  mat_traits<A>::scalar_type
  determinant( A const & a );

} }

此函数计算方阵 a行列式


perspective_lh

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  template <class T>
  -unspecified-return-type-
  perspective_lh( T fov_y, T aspect, T zn, T zf );

} }
返回

一个以下形式的未指定类型的 4x4 投影矩阵

xs

0

0

0

0

ys

0

0

0

0

zf/(zf-zn)

-zn*zf/(zf-zn)

0

0

1

0

其中 ys = cot(fov_y/2) 且 xs = ys/aspect


perspective_rh

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  template <class T>
  -unspecified-return-type-
  perspective_rh( T fov_y, T aspect, T zn, T zf );

} }
返回

一个以下形式的未指定类型的 4x4 投影矩阵

xs

0

0

0

0

ys

0

0

0

0

zf/(zn-zf)

zn*zf/(zn-zf)

0

0

-1

0

其中 ys = cot(fov_y/2),且 xs = ys/aspect


scalar_cast

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_mat<A>::value
  template <class Scalar,class A>
  -unspecified-return_type- scalar_cast( A const & a );

} }
返回

a 的只读 view proxy,它看起来像一个与 a 具有相同维度的矩阵,但具有 scalar_type Scalar 和从 a 的对应元素构造的元素。


to_string

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_mat<A>::value
  template <class A>
  std::string to_string( A const & a );

} }
返回

a 的字符串表示,格式未指定。


mref

#include <boost/qvm/mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_mat<A>::value
  template <class A>
  -unspecified-return-type- mref( A & a );

} }
返回

a 的恒等视图代理;也就是说,它只是访问 a 的元素。

a 是内置类型时,例如普通的 C 数组,mref 允许调用 QVM 操作。

四元数-向量运算

operator*

#include <boost/qvm/quat_vec_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_quat<A>::value && is_vec<B>::value &&
  //  is_vec<B>::value && vec_traits<B>::dim==3
  template <class A,class B>
  typename deduce_vec2<A,B,mat_traits<A>::rows>::type
  operator*( A const & a, B const & b );

} }
返回

通过四元数 a 变换向量 b 的结果。

可以特化 deduce_vec2 模板,以根据类型 AB 推导出所需的返回类型。

矩阵-向量运算

operator*

#include <boost/qvm/vec_mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && is_vec<B>::value &&
  //  mat_traits<A>::cols==vec_traits<B>::dim
  template <class A,class B>
  typename deduce_vec2<A,B,mat_traits<A>::rows>::type
  operator*( A const & a, B const & b );

} }
返回

矩阵 a 和向量 b 相乘的结果,其中 b 被解释为矩阵列。生成的矩阵行作为向量类型返回。

可以特化 deduce_vec2 模板,以根据类型 AB 推导出所需的返回类型。

transform_vector

#include <boost/qvm/vec_mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && is_vec<B>::value &&
  //  mat_traits<A>::rows==4 && mat_traits<A>::cols==4 &&
  //  vec_traits<B>::dim==3
  template <class A,class B>
  deduce_vec2<A,B,3> >::type
  transform_vector( A const & a, B const & b );

} }
效果

如同:return a * XYZ0(b)


transform_point

#include <boost/qvm/vec_mat_operations.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value && is_vec<B>::value &&
  //  mat_traits<A>::rows==4 && mat_traits<A>::cols==4 &&
  //  vec_traits<B>::dim==3
  template <class A,class B>
  deduce_vec2<A,B,3> >::type
  transform_point( A const & a, B const & b );

} }
效果

如同:return a * XYZ1(b)


矩阵到矩阵的视图代理

del_row

#include <boost/qvm/map_mat_mat.hpp>
namespace boost { namespace qvm {

  template <int R>
  -unspecified-return-type- del_row();

} }

表达式 del_row<R>(m) 返回一个左值 view proxy,它看起来像删除了第 R 行的矩阵 m


del_col

#include <boost/qvm/map_mat_mat.hpp>
namespace boost { namespace qvm {

  template <int C>
  -unspecified-return-type- del_col();

} }

表达式 del_col<C>(m) 返回一个左值 view proxy,它看起来像删除了第 C 列的矩阵 m


del_row_col

#include <boost/qvm/map_mat_mat.hpp>
namespace boost { namespace qvm {

  template <int R,int C>
  -unspecified-return-type- del_row_col();

} }

表达式 del_row_col<R,C>(m) 返回一个左值 view proxy,它看起来像删除了第 R 行和第 C 列的矩阵 m


neg_row

#include <boost/qvm/map_mat_mat.hpp>
namespace boost { namespace qvm {

  template <int R>
  -unspecified-return-type- neg_row();

} }

表达式 neg_row<R>(m) 返回一个只读 view proxy,它看起来像第 R 行取反的矩阵 m


neg_col

#include <boost/qvm/map_mat_mat.hpp>
namespace boost { namespace qvm {

  template <int C>
  -unspecified-return-type- neg_col();

} }
The expression `neg_col<C>(m)` returns a read-only <<view_proxy,`view proxy`>> that looks like the matrix `m` with column `C` negated.

swap_rows

#include <boost/qvm/map_mat_mat.hpp>
namespace boost { namespace qvm {

  template <int R1,int R2>
  -unspecified-return-type- swap_rows();

} }

表达式 swap_rows<R1,R2>(m) 返回一个左值 view proxy,它看起来像交换了第 R1 行和第 R2 行的矩阵 m


swap_cols

#include <boost/qvm/map_mat_mat.hpp>
namespace boost { namespace qvm {

  template <int C1,int C2>
  -unspecified-return-type- swap_cols();

} }

表达式 swap_cols<C1,C2>(m) 返回一个左值 view proxy,它看起来像交换了第 C1 列和第 C2 列的矩阵 m


transposed

#include <boost/qvm/map_mat_mat.hpp>
namespace boost { namespace qvm {

  -unspecified-return-type- transposed();

} }

表达式 transposed(m) 返回一个左值 view proxy,它转置矩阵 m


向量到矩阵的视图代理

col_mat

#include <boost/qvm/map_vec_mat.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_vec<A>::value
  template <iclass A>
  -unspecified-return-type- col_mat( A & a );

} }

表达式 col_mat(v) 返回一个左值 view proxy,它将向量 v 作为矩阵列访问。


row_mat

#include <boost/qvm/map_vec_mat.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_vec<A>::value
  template <iclass A>
  -unspecified-return-type- row_mat( A & a );

} }

表达式 row_mat(v) 返回一个左值 view proxy,它将向量 v 作为矩阵行访问。


translation_mat

#include <boost/qvm/map_vec_mat.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_vec<A>::value
  template <iclass A>
  -unspecified-return-type- translation_mat( A & a );

} }

表达式 translation_mat(v) 返回一个左值 view proxy,它将向量 v 作为大小为 1 + vec_traits<A>::dim 的平移矩阵访问。


diag_mat

#include <boost/qvm/map_vec_mat.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_vec<A>::value
  template <iclass A>
  -unspecified-return-type- diag_mat( A & a );

} }

表达式 diag_mat(v) 返回一个左值 view proxy,它将向量 v 作为相同维度的方阵访问,其中 v 的元素显示为主对角线,所有其他元素均为零。

如果 v 是一个 3D 向量,则表达式 diag_mat(XYZ1(v)) 可以用作缩放 4D 矩阵。

矩阵到向量的视图代理

col

#include <boost/qvm/map_mat_vec.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_mat<A>::value
  template <int C,class A>
  -unspecified-return-type- col( A & a );

} }

表达式 col<C>(m) 返回一个左值 view proxy,它将矩阵 m 的第 C 列作为向量访问。


row

#include <boost/qvm/map_mat_vec.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_mat<A>::value
  template <int C,class A>
  -unspecified-return-type- row( A & a );

} }

表达式 row<R>(m) 返回一个左值 view proxy,它将矩阵 m 的第 R 行作为向量访问。


diag

#include <boost/qvm/map_mat_vec.hpp>
namespace boost { namespace qvm {

  //Only enabled if: is_mat<A>::value
  template <class A>
  -unspecified-return-type- diag( A & a );

} }

表达式 diag(m) 返回一个左值 view proxy,它将矩阵 m 的主对角线作为向量访问。


translation

#include <boost/qvm/map_mat_vec.hpp>
namespace boost { namespace qvm {

  //Only enabled if:
  //  is_mat<A>::value &&
  //  (mat_traits<A>::rows==mat_traits<A>::cols || mat_traits<A>::rows+1==mat_traits<A>::cols) &&
  //  mat_traits<A>::cols>=3
  template <class A>
  -unspecified-return-type- translation( A & a );

} }

表达式 translation(m) 返回一个左值 view proxy,它访问方阵 m 的平移分量,这是一个大小为 C-1 的向量,其中 Cm 中的列数。


异常

error

#include <boost/qvm/error.hpp>
namespace boost { namespace qvm {

  struct error: virtual boost::exception, virtual std::exception { };

} }

这是 QVM 抛出的所有异常的基类。


zero_magnitude_error

#include <boost/qvm/error.hpp>
namespace boost { namespace qvm {

  struct zero_magnitude_error: virtual error { };

} }

此异常指示操作需要大小非零的向量或四元数,但计算出的大小为零。


zero_determinant_error

#include <boost/qvm/error.hpp>
namespace boost { namespace qvm {

  struct zero_determinant_error: virtual error { };

} }

此异常指示操作需要行列式非零的矩阵,但计算出的行列式为零。


宏和配置:BOOST_QVM_

INLINE

BOOST_QVM_INLINE
#include <boost/qvm/config.hpp>
namespace boost { namespace qvm {

  #ifndef BOOST_QVM_INLINE
  #define BOOST_QVM_INLINE inline
  #endif

} }

此宏不由 QVM 直接使用,除非作为 <boost/qvm/config.hpp> 中其他宏的默认值。用户定义的 BOOST_QVM_INLINE 应扩展为一个值,该值对于函数定义中 inline 关键字的有效替换。


FORCE_INLINE

BOOST_QVM_FORCE_INLINE
#include <boost/qvm/config.hpp>
namespace boost { namespace qvm {

  #ifndef BOOST_QVM_FORCE_INLINE
  #define BOOST_QVM_FORCE_INLINE /*platform-specific*/
  #endif

} }

此宏不由 QVM 直接使用,除非作为 <boost/qvm/config.hpp> 中其他宏的默认值。用户定义的 BOOST_QVM_FORCE_INLINE 应扩展为一个值,该值对于函数定义中 inline 关键字的有效替换,以指示编译器必须内联该函数。当然,实际的内联可能会发生,也可能不会发生。


INLINE_TRIVIAL

BOOST_QVM_INLINE_TRIVIAL
#include <boost/qvm/config.hpp>
namespace boost { namespace qvm {

  #ifndef BOOST_QVM_INLINE_TRIVIAL
  #define BOOST_QVM_INLINE_TRIVIAL BOOST_QVM_FORCE_INLINE
  #endif

} }

QVM 在函数的定义中使用 BOOST_QVM_INLINE_TRIVIAL,这些函数对于库的整体性能并不关键,但非常简单(例如单行代码),因此应始终内联。


INLINE_CRITICAL

BOOST_QVM_INLINE_CRITICAL
#include <boost/qvm/config.hpp>
namespace boost { namespace qvm {

  #ifndef BOOST_QVM_INLINE_CRITICAL
  #define BOOST_QVM_INLINE_CRITICAL BOOST_QVM_FORCE_INLINE
  #endif

} }

QVM 在函数的定义中使用 BOOST_QVM_INLINE_CRITICAL,这些函数对于库的整体性能至关重要,例如访问单个向量和矩阵元素的函数。


INLINE_OPERATIONS

BOOST_QVM_INLINE_OPERATIONS
#include <boost/qvm/config.hpp>
namespace boost { namespace qvm {

  #ifndef BOOST_QVM_INLINE_OPERATIONS
  #define BOOST_QVM_INLINE_OPERATIONS BOOST_QVM_INLINE
  #endif

} }

QVM 在实现各种高级操作的函数定义中使用 BOOST_QVM_INLINE_OPERATIONS,例如矩阵乘法、计算向量的大小等。


INLINE_RECURSION

BOOST_QVM_INLINE_RECURSION
#include <boost/qvm/config.hpp>
namespace boost { namespace qvm {

  #ifndef BOOST_QVM_INLINE_RECURSION
  #define BOOST_QVM_INLINE_RECURSION BOOST_QVM_INLINE_OPERATIONS
  #endif

} }

QVM 在递归函数的定义中使用 BOOST_QVM_INLINE_RECURSION,这些函数对于库的整体性能并不关键(所有关键函数的定义,包括关键递归函数,都使用 BOOST_QVM_INLINE_CRITICAL)。


ASSERT

BOOST_QVM_ASSERT
#include <boost/qvm/assert.hpp>
namespace boost { namespace qvm {

#ifndef BOOST_QVM_ASSERT
#include <boost/assert.hpp>
#define BOOST_QVM_ASSERT BOOST_ASSERT
#endif

} }

这是 QVM 用于断言前提条件违规和逻辑错误的宏。用户定义的 BOOST_QVM_ASSERT 应具有标准 assert 的语义。


STATIC_ASSERT

BOOST_QVM_STATIC_ASSERT
#include <boost/qvm/static_assert.hpp>
namespace boost { namespace qvm {

  #ifndef BOOST_QVM_STATIC_ASSERT
  #include <boost/static_assert.hpp>
  #define BOOST_QVM_STATIC_ASSERT BOOST_STATIC_ASSERT
  #endif

} }

QVM 中的所有静态断言都使用 BOOST_QVM_STATIC_ASSERT 宏。


THROW_EXCEPTION

BOOST_QVM_THROW_EXCEPTION
#include <boost/qvm/throw_exception.hpp>
namespace boost { namespace qvm {

  #ifndef BOOST_QVM_THROW_EXCEPTION
  #include <boost/throw_exception.hpp>
  #define BOOST_QVM_THROW_EXCEPTION BOOST_THROW_EXCEPTION
  #endif

} }

每当 QVM 抛出异常时,都会使用此宏。覆盖标准 BOOST_QVM_THROW_EXCEPTION 行为的用户必须确保在调用时,替换的实现不会将控制权返回给调用者。以下是调用 BOOST_QVM_THROW_EXCEPTION 的所有 QVM 函数的列表

设计原理

C++ 非常适合 3D 图形和其他需要 3D 变换的领域:定义向量和矩阵类型,然后重载适当的运算符来实现标准代数运算。由于这相对直接,因此有许多库可以做到这一点,每个库都提供自定义的向量和矩阵类型,然后为这些类型定义相同的操作(例如,矩阵乘法)。

通常,这些库是更高级别系统的一部分。例如,视频游戏程序员通常将一组向量/矩阵类型与渲染引擎一起使用,另一组与物理模拟引擎一起使用。

QVM 通过将标准代数函数与其操作的类型解耦,在所有这些不同类型和 API 之间提供互操作性,同时又不影响类型安全。这些操作适用于已专门化适当 traits 的任何类型。使用 QVM,无需在不同的四元数、向量或矩阵类型之间进行转换;它们可以在同一表达式中安全有效地混合使用。

这种设计使 QVM 能够在编译时生成类型和适配器,与任何其他 QVM 或用户定义的类型兼容。例如,转置矩阵不需要存储结果:它不是修改其参数或返回新对象,而是通过生成的类型绑定原始矩阵对象,该类型动态地重新映射元素访问。

此外,QVM 可以在选择性地优化各个类型或操作以获得最大性能方面提供帮助,尤其是在性能至关重要的情况下。例如,用户可以为特定类型重载特定操作,或者定义高度优化、可能是平台特定的或由于某些原因使用起来很麻烦的类型,然后在程序中性能不关键的部分将它们与更友好的用户类型混合和匹配。

代码生成器

虽然 QVM 定义了对任意静态维度的矩阵和向量类型进行操作的通用函数,但它也提供了一个代码生成器,可以用于创建兼容的头文件,这些头文件为特定维度定义了这些函数的更简单的特化。这在调试期间很有用,因为生成的代码比模板元编程繁重的通用实现更容易阅读。它也可能对优化器更友好。

代码生成器是一个命令行实用程序。其源代码可以在 boost/libs/qvm/gen 目录中找到。它被用于生成以下与 QVM 一起发布的头文件

  • 2D、3D 和 4D 矩阵运算

    • boost/qvm/gen/mat_operations2.hpp (尺寸为 2x2、2x1 和 1x2 的矩阵,由 boost/qvm/mat_operations2.hpp 包含)

    • boost/qvm/gen/mat_operations3.hpp (尺寸为 3x3、3x1 和 1x3 的矩阵,由 boost/qvm/mat_operations3.hpp 包含)

    • boost/qvm/gen/mat_operations4.hpp (尺寸为 4x4、4x1 和 1x4 的矩阵,由 boost/qvm/mat_operations4.hpp 包含)

  • 2D、3D 和 4D 向量运算

    • boost/qvm/gen/v2.hpp (由 boost/qvm/vec_operations2.hpp 包含)

    • boost/qvm/gen/v3.hpp (由 boost/qvm/vec_operations3.hpp 包含)

    • boost/qvm/gen/v4.hpp (由 boost/qvm/vec_operations4.hpp 包含)

  • 2D、3D 和 4D 向量-矩阵运算

    • boost/qvm/gen/vm2.hpp (由 boost/qvm/vec_mat_operations2.hpp 包含)

    • boost/qvm/gen/vm3.hpp (由 boost/qvm/vec_mat_operations3.hpp 包含)

    • boost/qvm/gen/vm4.hpp (由 boost/qvm/vec_mat_operations4.hpp 包含)

  • 2D、3D 和 4D 向量混合操作

    • boost/qvm/gen/sw2.hpp (由 boost/qvm/swizzle2.hpp 包含)

    • boost/qvm/gen/sw3.hpp (由 boost/qvm/swizzle3.hpp 包含)

    • boost/qvm/gen/sw4.hpp (由 boost/qvm/swizzle4.hpp 包含)

任何此类生成的头文件都必须在包含相应的通用头文件之前包含。例如,如果创建一个头文件 boost/qvm/gen/m5.hpp,则必须在包含 boost/qvm/mat_operations.hpp 之前包含它。但是,通用头文件 (boost/qvm/mat_operations.hppboost/qvm/vec_operations.hppboost/qvm/vec_mat_operations.hppboost/qvm/swizzle.hpp) 已经包含了上面列表中的生成头文件,因此不需要手动包含生成的头文件。

boost/qvm/gen 下的头文件不是 QVM 公共接口的一部分。例如,boost/qvm/gen/mat_operations2.hpp 不应直接包含;而是 #include <boost/qvm/mat_operations2.hpp>

已知缺陷和问题

使用 auto 捕获视图代理

根据设计,视图代理不得返回临时对象。它们返回对其通过(const)引用获取的参数的引用,转换为不可复制的未指定类型的引用。因此,视图代理的返回值不能用 auto 按值捕获。

auto tr = transposed(m); //Error: the return type of transposed can not be copied.

auto 与视图代理的正确用法是

auto & tr = transposed(m);
许多视图代理不是只读的,也就是说,它们是左值;对视图代理所做的更改会作用于原始对象。这是它们不能用 auto 按值捕获的另一个原因。

从不相关的命名空间绑定 QVM 重载

命名空间 boost::qvm 中的运算符重载旨在与用户定义的类型一起使用。通常,只需通过 using namespace boost::qvm 使这些运算符在运算符使用的命名空间中可用就足够了。如果使用运算符的作用域不受用户控制,则会出现问题。例如

namespace ns1 {

  struct float2 { float x, y; };

}

namespace ns2 {

  using namespace boost::qvm;

  void f() {
    ns1::float2 a, b;
    a==b; //OK
    ns1::float2 arr1[2], arr2[2];
    std::equal(arr1,arr1+2,arr2); //Error: operator== is inaccessible from namespace std
  }

}

在上面的 std::equal 表达式中,即使通过 using namespace boost::qvm 使 boost::qvm::operator== 在命名空间 ns2 中可见,该调用也源自命名空间 std。在这种情况下,编译器无法绑定 boost::qvm::operator==,因为只有命名空间 ns1 通过 ADL 可见,并且它不包含合适的声明。解决方案是在命名空间 ns1 中声明 operator==,可以像这样完成

namespace ns1 {

  using boost::qvm::operator==;

}

QVM 不直接调用标准数学函数(例如 sin、cos 等)。相反,它调用在命名空间 boost::qvmboost/qvm/math.hpp 中声明的函数模板。这允许用户为用户定义的标量类型专门化这些模板。

QVM 本身仅为 floatdouble 定义了数学函数模板的特化,但它不提供通用定义。这样做是为了保护用户免于意外编写在传递较小类型的参数时绑定接受 double 的标准数学函数的代码,这将是次优的。

因此,调用例如 rot_mat(axis,1) 将会成功编译但链接失败,因为它调用例如 boost::qvm::sin<int>,这是未定义的。由于很少需要按整数弧度进行旋转,因此 QVM 中没有针对此类错误的保护。在这种情况下,解决方案是改用 rot_mat(axis,1.0f)

问答

  1. QVM 背后的动机是什么?为什么不直接使用 uBLAS/Eigen/CML/GLM 等?

    QVM 的主要领域是实时图形和模拟应用程序,因此它不是一个完整的线性代数库。虽然(自然地)与此类库有一些重叠,但 QVM 强调 2、3 和 4 维零开销操作(因此具有特定领域的特性,如 Swizzling)。

  2. qvm::vec(或 qvm::mat,或 qvm::quat)模板与其他库中的向量类型相比如何?

    qvm::vec 模板绝不是 QVM 定义的向量运算的核心。这些运算旨在与任何用户定义的向量类型或第三方向量类型(例如 D3DVECTOR)一起使用,而 qvm::vec 模板仅仅是表达式的默认返回类型,这些表达式使用在 QVM 之外不兼容的不同类型的参数。例如,如果 deduce_mat2 尚未专门化,则使用用户定义的类型 vec3 和用户定义的类型 float3 调用 cross 将返回 qvm::vec

  3. 为什么 QVM 不使用 [] 或 () 来访问向量和矩阵元素?

    因为它被设计为与用户定义的类型一起使用,并且 C++ 标准要求这些运算符成为成员。当然,如果用户定义的类型定义了 operator[]operator(),它们可以与其他 QVM 函数一起使用,但 QVM 定义了自己的机制来访问四元数元素访问向量元素(以及混合)和访问矩阵元素


文档由 Asciidoctor 使用 这些自定义项 渲染。

版权所有 2008-2023 Emil Dotchevski 和 Reverge Studios, Inc.