摘要
支持
-
cpplang on Slack (使用
#boost
频道)
可移植性
QVM 仅需 C++03,但在许多编译器版本和 C++ 标准上进行了测试。
发行
版权所有 2008-2023 Emil Dotchevski。根据 Boost 软件许可,版本 1.0 分发。
有三个发行渠道
-
QVM 包含在官方 Boost 发行版中。
-
源代码托管在 GitHub 上。
-
为了获得最大的可移植性,该库的最新版本也以单头文件格式提供,有两种变体(直接下载链接)
-
qvm_lite.hpp:包含除混合重载之外所有内容的单头文件。
QVM 不依赖于 Boost 或其他库。 |
教程
四元数、向量、矩阵
quat<float> rx = rotx_quat(3.14159f);
类似地,可以按给定向量平移的矩阵可以如下创建
vec<float,3> v = {0,0,7};
mat<float,4,4> tr = translation_mat(v);
常用的四元数、向量和矩阵运算适用于这些 QVM 类型,但是这些运算与任何特定类型解耦:它们适用于任何已通过特化 quat_traits
、vec_traits
和 mat_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。
为了支持无法通过引用访问元素的向量类型,可以将
Boost QVM 自动检测提供了哪个替代方案。 |
C/C++ 数组
在 boost/qvm/quat_traits_array.hpp
、vec_traits_array.hpp
和 mat_traits_array.hpp
中,QVM 定义了适当的 quat_traits
、vec_traits
和 mat_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;
float v[3] = {0,0,7};
vref(v) *= 42;
如果 C++-11 可用,则相同的头文件为 std::array
对象定义了适当的 quat_traits
、vec_traits
和 mat_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 混合定义了 X
、Y
、Z
、W
的所有排列,此外,每个维度都定义了在任何位置使用 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 );
即使函数定义可能包含仅针对 Matrix
和 Vector
类型编译的代码,但由于函数声明本身是有效的,因此它将参与在将任何两种类型的对象相乘时的重载解析。这通常会使重载解析变得模糊,并且编译器(正确地)发出错误。
使用 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;
};
} }
在使用独立库中的 最好将此类特化保留在 |
为一元运算指定返回类型
也许令人惊讶的是,通过值返回对象的一元运算具有类似但更简单的问题。那是因为调用它们的参数可能不可复制,例如
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 以单头文件格式提供,以实现最大的可移植性。请参阅 发行。
四元数特征 |
#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> |
|
#include <boost/qvm/quat.hpp> |
向量特征 |
#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> |
|
#include <boost/qvm/vec.hpp> |
矩阵特征 |
#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> |
|
#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
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
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
namespace boost { namespace qvm {
template <class A,class B>
struct deduce_scalar
{
typedef typename /*exact definition unspecified*/ type;
};
} }
- 要求
-
A
和B
满足 标量要求。 - 返回
-
如果
A
和B
是相同类型,则scalar_traits<A,B>::type
定义为该类型。否则对于以下类型-
signed
/unsigned char
, -
signed
/unsigned short
, -
signed
/unsigned int
, -
signed
/unsigned long
, -
float
, -
double
,
-
推导逻辑如下
-
如果
A
和B
中任何一个是double
,则结果为double
; -
否则,如果
A
或B
之一是整数类型,而另一个是float
,则结果为float
; -
否则,如果
A
或B
之一是有符号整数,而另一种类型是无符号整数,则有符号类型更改为无符号类型,然后将两个整数中较小的提升为另一个。
对于任何其他类型,scalar_traits<A,B>::type
定义为 void
。它可以为用户自定义的标量类型进行特化。
此模板由返回标量的通用二元运算使用,以根据其参数的(可能不同的)标量推导返回类型。 |
scalar
namespace boost { namespace qvm {
template <class T>
struct scalar {
typedef /*exact definition unspecified*/ type;
};
} }
表达式 quat_traits<T>::scalar_type
求值为四元数类型 T
的标量类型(如果 is_quat<T>::value
为 true
)。
表达式 vec_traits<T>::scalar_type
求值为向量类型 T
的标量类型(如果 is_vec<T>::value
为 true
)。
表达式 mat_traits<T>::scalar_type
求值为矩阵类型 T
的标量类型(如果 is_mat<T>::value
为 true
)。
表达式 scalar<T>::type
类似,不同之处在于它自动检测 T
是向量、矩阵还是四元数类型。
is_quat
namespace boost { namespace qvm {
template <class T>
struct is_quat {
static bool const value = false;
};
} }
此类型模板定义了一个编译时布尔常量值,可用于确定类型 T
是否为四元数类型。对于四元数类型,quat_traits
模板可用于通用地访问其元素,或获取其 scalar type
。
quat_traits
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
模板的有效特化必须将以下至少一个访问函数定义为静态成员,其中 q
是 Quaternion
类型的对象,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 ,元素假定按以下顺序排列:a 、b 、c 、d ;即,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
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_element
;quat_traits_defaults
基类将自动定义 read_element
以及 scalar_type
。
deduce_quat
namespace boost { namespace qvm {
template <class Q,
class S=typename quat_traits<Q>::scalar_type>
struct deduce_quat {
typedef Q type;
};
} }
- 要求
-
-
is_quat<Q>::value
为true
; -
is_scalar<S>::value
为true
; -
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
本身可能不可复制。
主要模板定义返回未指定的四元数类型,除非 S
与 quat_traits
<Q>::scalar_type
的类型相同,在这种情况下,它返回 Q
,这仅在 Q
可复制时才适用。QVM 还为其生成的不可复制的四元数类型定义了(部分)特化。用户可以为自己的类型定义其他(部分)特化。
deduce_quat
模板的典型用途是指定 QVM 中通用函数模板重载根据其参数类型返回的首选四元数类型。
deduce_quat2
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>::type
和scalar<B>::type
都已明确定义; -
is_quat<A>::value
||is_quat<B>::value
为true
; -
is_scalar<S>::value
为true
; -
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
。返回的类型必须具有可访问的复制构造函数(A
和 B
类型本身可能不可复制,并且它们中的任何一个可能不是四元数类型)。
主要模板定义返回具有 scalar_type
S
的未指定四元数类型,除非 A
和 B
是相同的四元数类型 Q
,在这种情况下,返回 Q
,这仅适用于可复制的类型。QVM 还为其生成的不可复制的四元数类型定义了(部分)特化。用户可以为自己的类型定义其他(部分)特化。
deduce_quat2
模板的典型用途是指定 QVM 中通用函数模板重载根据其参数类型返回的首选四元数类型。
is_vec
namespace boost { namespace qvm {
template <class T>
struct is_vec {
static bool const value = false;
};
} }
此类型模板定义了一个编译时布尔常量值,可用于确定类型 T
是否为向量类型。对于向量类型,vec_traits
模板可用于通用地访问其元素,或获取其维度和 scalar type
。
vec_traits
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
模板的有效特化可以将以下访问函数定义为静态成员,其中 v
是 Vector
类型的对象,I
是编译时整数常量,i
是 int
类型的变量
-
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_element 和 write_element_idx 可以定义为 void 函数,该函数(作为最后一个参数)接受一个标量写入指定的元素。QVM 通过检查 write_element 模板的签名自动检测这种情况。 |
除非 is_vec<Vector>::value
为 true,否则调用上述任何函数都是非法的。即使这样,也允许向量类型仅定义访问函数的子集。一般要求是
-
必须定义
read_element
或write_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
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_element
;vec_traits_defaults
基类将自动定义 read_element
以及 scalar_type
和 dim
。
可选地,用户还可以定义 write_element_idx
,在这种情况下,vec_traits_defaults
基类将自动提供合适的 read_element_idx
定义。如果不是,则 vec_traits_defaults
定义了 write_element_idx
的受保护实现,如果为其特化的向量类型无法有效索引,则派生的 vec_traits
特化可以公开提供该实现。此 write_element_idx
函数效率较低(使用元编程),根据所需的用户定义的 write_element
实现。
deduce_vec
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;
};
} }
- 要求
每当 QVM 需要从向量类型的单个用户提供的函数参数中推导特定维度的可复制向量类型时,此模板都会被 QVM 使用。返回的类型必须具有可访问的复制构造函数。请注意,V
可能不可复制。
主要模板定义返回大小为 D
且标量类型为 S
的未指定可复制向量类型,除非 vec_traits
<V>::dim==D
且 vec_traits
<V>::scalar_type
与 S
的类型相同,在这种情况下,它返回 V
,这仅在 V
是可复制类型时才适用。QVM 还为其生成的不可复制的向量类型定义了(部分)特化。用户可以为自己的类型定义其他(部分)特化。
deduce_vec
模板的典型用途是指定 QVM 中通用函数模板重载根据其参数类型返回的首选向量类型。
deduce_vec2
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>::type
和scalar<B>::type
都已明确定义; -
is_vec<A>::value
||is_vec<B>::value
为true
; -
is_scalar<S>::value
为true
; -
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_type
与S
的类型相同。
-
每当 QVM 需要从两个用户提供的函数参数的类型中推导特定维度的向量类型时,此模板都会被 QVM 使用。返回的类型必须具有可访问的复制构造函数(A
和 B
类型本身可能不可复制,并且它们中的任何一个可能是非向量类型)。
主要模板定义返回具有 scalar_type
S
的请求维度的未指定向量类型,除非 A
和 B
是相同的向量类型 V
,在这种情况下,返回 V
,这仅适用于可复制的类型。QVM 还为其生成的不可复制的向量类型定义了(部分)特化。用户可以为自己的类型定义其他(部分)特化。
deduce_vec2
模板的典型用途是指定 QVM 中通用函数模板重载根据其参数类型返回的首选向量类型。
is_mat
namespace boost { namespace qvm {
template <class T>
struct is_mat {
static bool const value = false;
};
} }
此类型模板定义了一个编译时布尔常量值,可用于确定类型 T
是否为矩阵类型。对于矩阵类型,mat_traits
模板可用于通用地访问其元素,或获取其维度和标量类型。
mat_traits
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
模板的有效特化可以将以下访问函数定义为静态成员,其中 m
是 Matrix
类型的对象,R
和 C
是编译时整数常量,r
和 c
是 int
类型的变量
-
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_element 和 write_element_idx 可以定义为 void 函数,该函数(作为最后一个参数)接受一个标量写入指定的元素。QVM 通过检查 write_element 模板的签名自动检测这种情况。 |
除非 is_mat<Matrix>::value
为真,否则调用上述任何函数都是非法的。即使这样,矩阵类型也可能只定义访问函数的一个子集。一般要求是
-
必须定义
read_element
或write_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
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_element
;mat_traits_defaults
基类将自动定义 read_element
,以及 scalar_type
、rows
和 cols
。
可选地,用户也可以定义 write_element_idx
,在这种情况下,mat_traits_defaults
基类将自动提供合适的 read_element_idx
定义。否则,mat_traits_defaults
定义了 write_element_idx
的受保护实现,如果为其特化的矩阵类型不能被高效地索引,则可以通过派生的 mat_traits
特化使其公开可用。这个 write_element_idx
函数效率较低(使用元编程),根据必需的用户定义的 write_element
实现。
deduce_mat
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>::value
为true
; -
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_type
与S
的类型相同。
-
当 QVM 需要从单个用户提供的矩阵类型函数参数中推导出具有特定维度的可复制矩阵类型时,就会使用此模板。返回的类型必须具有可访问的复制构造函数。请注意,M 本身可能是不可复制的。
主模板定义返回一个未指定的可复制矩阵类型,其大小为 R
x C
,标量类型为 S
,除非 mat_traits<M>::rows==R
且 mat_traits<M>::cols==Cols
且 mat_traits<M>::scalar_type
为 S,在这种情况下,它返回 M
,这仅在 M
是可复制类型时才适用。QVM 还为其生成的不可复制矩阵类型定义了(部分)特化。用户可以为其自己的类型定义其他(部分)特化。
deduce_mat
模板的典型用法是指定 QVM 中泛型函数模板重载根据其参数类型返回的首选矩阵类型。
deduce_mat2
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>::type
和scalar<B>::type
都已明确定义; -
is_mat<A>::value || is_mat<B>::value
为true
; -
is_scalar<S>::value
为true
; -
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_type
与S
的类型相同。
-
当 QVM 需要从两个用户提供的函数参数的类型中推导出具有特定维度的矩阵类型时,就会使用此模板。返回的类型必须具有可访问的复制构造函数(A
和 B
类型本身可能是不可复制的,并且其中任何一个都可能不是矩阵类型。)
主模板定义返回一个未指定的矩阵类型,其具有请求的维度和 scalar_type
S
,除非 A
和 B
是相同的矩阵类型 M
,在这种情况下,返回 M
,这仅适用于可复制类型。QVM 还为其生成的不可复制矩阵类型定义了(部分)特化。用户可以为其自己的类型定义其他(部分)特化。
deduce_mat2
模板的典型用法是指定 QVM 中泛型函数模板重载根据其参数类型返回的首选矩阵类型。
内置四元数、向量和矩阵类型
QVM 定义了几个类模板(以及 quat_traits
、vec_traits
和 mat_traits
模板的适当特化),这些模板可以用作通用的四元数、向量和矩阵类型。虽然直接使用这些类型并不典型,但 QVM 的主要设计目标是允许用户插入他们自己的四元数、向量和矩阵类型。
quat
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
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
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 定义的通用操作兼容。
元素访问
四元数
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。
向量分量的 X
、Y
和 Z
元素也可以使用 X(q)
、Y(q)
和 Z(q)
直接访问。
返回类型是左值。 |
向量
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;
X
、Y
、Z
和 W
的作用与 A0
/A1
/A2
/A3
相同;编写上述表达式的又一种替代方法是
Y(v) *= 42;
返回类型是左值。 |
向量元素混合
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
元素指的是 v
的 Y
元素,而其 Y
元素指的是 v
的 X
元素。像其他视图代理一样,YX
是一个左值,也就是说,如果 v2
是一个 2D 向量,可以写成
YX(v) = v2;
上面代码将保持 v
的 Z
和 W
元素不变,但会将 v2
的 Y
元素赋值给 v
的 X
元素,并将 v2
的 X
元素赋值给 v
的 Y
元素。
所有 X
、Y
、Z
、W
、0
、1
的排列都可用于 2D、3D 和 4D 混合(如果混合标识符的第一个字符是 0
或 1
,则它前面会加上一个 _
,例如 _11XY
)。
多次使用相同的向量元素是有效的:表达式 ZZZ(v)
是一个 3D 向量,其 X
、Y
和 Z
元素都指向 v
的 Z
元素。
最后,标量可以被“混合”以将其作为向量访问:表达式 _0X01(42.0f)
是一个 4D 向量,其中 X
=0,Y
=42.0,Z
=0,W
=1。
矩阵
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。
为了方便起见,对于 R
从 0
到 9
以及 C
从 0
到 9
,还有非模板重载;编写上述表达式的另一种方法是
A42(m) *= 42;
返回类型是左值。 |
四元数运算
assign
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
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-=
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-
(一元)
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-
(二元)
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 模板,以根据类型 A 和 B 推导出所需的返回类型。 |
operator+=
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+
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 模板,以根据类型 A 和 B 推导出所需的返回类型。 |
operator/=
(标量)
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/
(标量)
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 模板,以从类型 A 和 B 推导出所需的返回类型。 |
operator*=
(标量)
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*=
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*
(标量)
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 模板,以从类型 A 和 B 推导出所需的返回类型。 |
operator*
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 模板,以根据类型 A 和 B 推导出所需的返回类型。 |
operator==
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!=
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
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
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
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
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
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
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 );
} }
- 返回
-
四元数
a
和b
的点积。
可以特化 deduce_scalar 模板,以根据类型 A 和 B 推导出所需的返回类型。 |
conjugate
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
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
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
. - 返回
-
一个四元数,它是四元数
a
和b
以及插值参数c
的球面线性插值结果。当slerp
应用于单位四元数时,四元数路径以标准方式映射到 3D 旋转路径。效果是以均匀的角速度围绕固定的旋转轴旋转。
当由 a
和 b
表示的旋转角度相差超过 180 度时,slerp180
始终在球面上取较短的路径,而 slerp360
则不然。两种行为都有用例,因为每种行为都会在不同的条件下引入不连续性。
数学上
auto q = slerp180(a, b, t);
等同于
auto q = slerp360(dot(a, b) < 0 ? -a : a, b, t);
以前版本的 QVM 仅实现了 slerp360 行为,但名称为 slerp 。为了兼容性,这一点被保留了下来,但 slerp 现在已被弃用。请使用 slerp180 或 slerp360 。 |
可以特化 deduce_quat2 模板,以根据类型 A 和 B 推导出所需的返回类型。 |
zero_quat
namespace boost { namespace qvm {
template <class T>
-unspecified-return-type- zero_quat();
} }
- 返回
-
一个只读的、未指定类型的四元数,其
scalar_type
为T
,所有元素都等于scalar_traits<T>::value(0)
。
set_zero
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
namespace boost { namespace qvm {
template <class S>
-unspecified-return-type- identity_quat();
} }
- 返回
-
一个标量类型为
S
的单位四元数。
set_identity
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
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
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
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
namespace boost { namespace qvm {
template <class Angle>
-unspecified-return-type- rotx_quat( Angle const & angle );
} }
- 返回
-
一个 view proxy 四元数,其类型未指定,标量类型为
Angle
,它执行围绕 X 轴以angle
弧度旋转的旋转。
set_rotx
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
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
namespace boost { namespace qvm {
template <class Angle>
-unspecified-return-type- roty_quat( Angle const & angle );
} }
- 返回
-
一个 view proxy 四元数,其类型未指定,标量类型为
Angle
,它执行围绕 Y 轴以angle
弧度旋转的旋转。
set_roty
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
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
namespace boost { namespace qvm {
template <class Angle>
-unspecified-return-type- rotz_quat( Angle const & angle );
} }
- 返回
-
一个 view proxy 四元数,其类型未指定,标量类型为
Angle
,它执行围绕 Z 轴以angle
弧度旋转的旋转。
set_rotz
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
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
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
namespace boost { namespace qvm {
//Only enabled if: is_quat<A>::value
template <class A>
std::string to_string( A const & a );
} }
- 返回
-
值
a
的字符串表示,格式未指定。
qref
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
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
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-=
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)
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-
(二元)
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 );
} }
- 返回
-
一个与
a
和b
大小相同的向量,其元素是从a
的对应元素中减去b
的元素。
可以特化 deduce_vec2 模板,以根据类型 A 和 B 推导出所需的返回类型。 |
operator+=
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+
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 );
} }
- 返回
-
一个与
a
和b
大小相同的向量,其元素是b
的元素加上a
的对应元素。
可以特化 deduce_vec2 模板,以根据类型 A 和 B 推导出所需的返回类型。 |
operator/=
(标量)
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/
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 模板,以从类型 A 和 B 推导出所需的返回类型。 |
operator*=
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*
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 模板,以从类型 A 和 B 推导出所需的返回类型。 |
operator==
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!=
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==
,不同之处在于a
和b
的各个元素被传递给二元谓词pred
进行比较。
mag_sqr
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
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
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
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
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 );
} }
- 返回
-
向量
a
和b
的点积。
可以特化 deduce_scalar 模板,以根据类型 A 和 B 推导出所需的返回类型。 |
cross
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 );
} }
- 返回
-
向量
a
和b
的叉积。
可以特化 deduce_vec2 (和 deduce_scalar )模板,以根据类型 A 和 B 推导出所需的返回类型。 |
zero_vec
namespace boost { namespace qvm {
template <class T,int S>
-unspecified-return-type- zero_vec();
} }
- 返回
-
一个只读的、未指定类型的向量,其
scalar_type
为T
,大小为S
,所有元素都等于scalar_traits<T>::value(0)
。
set_zero
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
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
namespace boost { namespace qvm {
//Only enabled if: is_vec<A>::value
template <class A>
std::string to_string( A const & a );
} }
- 返回
-
值
a
的字符串表示,格式未指定。
vref
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
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
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-=
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-
(一元)
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-
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 );
} }
- 返回
-
一个与
a
和b
大小相同的矩阵,其元素是从a
的对应元素中减去b
的元素。
可以特化 deduce_mat2 模板,以根据类型 A 和 B 推导出所需的返回类型。 |
operator+=
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+
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 );
} }
- 返回
-
一个与
a
和b
大小相同的矩阵,其元素是b
的元素加上a
的对应元素。
可以特化 deduce_mat2 模板,以根据类型 A 和 B 推导出所需的返回类型。 |
operator/=
(标量)
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/
(标量)
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 模板,以从类型 A 和 B 推导出所需的返回类型。 |
operator*=
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*=
(标量)
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*
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 );
} }
- 返回
-
乘矩阵
a
和b
的结果。
可以特化 deduce_mat2 模板,以根据类型 A 和 B 推导出所需的返回类型。 |
operator*
(标量)
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 模板,以从类型 A 和 B 推导出所需的返回类型。 |
operator==
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!=
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
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==
,不同之处在于a
和b
的各个元素被传递给二元谓词pred
进行比较。
inverse
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
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_type
为T
,具有R
行和C
列(或D
行和D
列),所有元素都等于scalar_traits<T>::value(0)
。
set_zero
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
namespace boost { namespace qvm { template <class S,int D> -unspecified-return-type- identity_mat(); } }
- 返回
-
一个大小为
D
xD
,标量类型为S
的单位矩阵。
set_identity
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
/ 欧拉角
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
/ 欧拉角
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
/ 欧拉角
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
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
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
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
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
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
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
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
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
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
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
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
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
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
namespace boost { namespace qvm {
//Only enabled if: is_mat<A>::value
template <class A>
std::string to_string( A const & a );
} }
- 返回
-
值
a
的字符串表示,格式未指定。
mref
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*
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 模板,以根据类型 A 和 B 推导出所需的返回类型。 |
矩阵-向量运算
operator*
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 模板,以根据类型 A 和 B 推导出所需的返回类型。 |
transform_vector
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 );
} }
transform_point
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 );
} }
矩阵到矩阵的视图代理
del_row
namespace boost { namespace qvm {
template <int R>
-unspecified-return-type- del_row();
} }
表达式 del_row<R>(m)
返回一个左值 view proxy,它看起来像删除了第 R
行的矩阵 m
。
del_col
namespace boost { namespace qvm {
template <int C>
-unspecified-return-type- del_col();
} }
表达式 del_col<C>(m)
返回一个左值 view proxy,它看起来像删除了第 C
列的矩阵 m
。
del_row_col
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
namespace boost { namespace qvm {
template <int R>
-unspecified-return-type- neg_row();
} }
表达式 neg_row<R>(m)
返回一个只读 view proxy,它看起来像第 R
行取反的矩阵 m
。
neg_col
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
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
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
namespace boost { namespace qvm {
-unspecified-return-type- transposed();
} }
表达式 transposed(m)
返回一个左值 view proxy,它转置矩阵 m
。
向量到矩阵的视图代理
col_mat
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
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
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
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
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
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
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
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 的向量,其中 C
是 m
中的列数。
异常
error
namespace boost { namespace qvm {
struct error: virtual boost::exception, virtual std::exception { };
} }
这是 QVM 抛出的所有异常的基类。
zero_magnitude_error
namespace boost { namespace qvm {
struct zero_magnitude_error: virtual error { };
} }
此异常指示操作需要大小非零的向量或四元数,但计算出的大小为零。
zero_determinant_error
namespace boost { namespace qvm {
struct zero_determinant_error: virtual error { };
} }
此异常指示操作需要行列式非零的矩阵,但计算出的行列式为零。
宏和配置:BOOST_QVM_
INLINE
BOOST_QVM_INLINE
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
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
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
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
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
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
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
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
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.hpp
、boost/qvm/vec_operations.hpp
、boost/qvm/vec_mat_operations.hpp
和 boost/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==;
}
使用 int
参数调用数学函数时出现链接错误
QVM 不直接调用标准数学函数(例如 sin、cos 等)。相反,它调用在命名空间 boost::qvm
的 boost/qvm/math.hpp
中声明的函数模板。这允许用户为用户定义的标量类型专门化这些模板。
QVM 本身仅为 float
和 double
定义了数学函数模板的特化,但它不提供通用定义。这样做是为了保护用户免于意外编写在传递较小类型的参数时绑定接受 double
的标准数学函数的代码,这将是次优的。
因此,调用例如 rot_mat(axis,1)
将会成功编译但链接失败,因为它调用例如 boost::qvm::sin<int>
,这是未定义的。由于很少需要按整数弧度进行旋转,因此 QVM 中没有针对此类错误的保护。在这种情况下,解决方案是改用 rot_mat(axis,1.0f)
。
问答
-
QVM 背后的动机是什么?为什么不直接使用 uBLAS/Eigen/CML/GLM 等?
QVM 的主要领域是实时图形和模拟应用程序,因此它不是一个完整的线性代数库。虽然(自然地)与此类库有一些重叠,但 QVM 强调 2、3 和 4 维零开销操作(因此具有特定领域的特性,如 Swizzling)。
-
qvm::vec
(或qvm::mat
,或qvm::quat
)模板与其他库中的向量类型相比如何?qvm::vec
模板绝不是 QVM 定义的向量运算的核心。这些运算旨在与任何用户定义的向量类型或第三方向量类型(例如D3DVECTOR
)一起使用,而qvm::vec
模板仅仅是表达式的默认返回类型,这些表达式使用在 QVM 之外不兼容的不同类型的参数。例如,如果deduce_mat2
尚未专门化,则使用用户定义的类型vec3
和用户定义的类型float3
调用cross
将返回qvm::vec
。 -
为什么 QVM 不使用 [] 或 () 来访问向量和矩阵元素?
因为它被设计为与用户定义的类型一起使用,并且 C++ 标准要求这些运算符成为成员。当然,如果用户定义的类型定义了
operator[]
或operator()
,它们可以与其他 QVM 函数一起使用,但 QVM 定义了自己的机制来访问四元数元素、访问向量元素(以及混合)和访问矩阵元素。
文档由 Asciidoctor 使用 这些自定义项 渲染。
版权所有 2008-2023 Emil Dotchevski 和 Reverge Studios, Inc.