Dandelion 1.1.1
A light-weight 3D builder for educational usage
载入中...
搜索中...
未找到
math.hpp
浏览该文件的文档.
1#ifndef DANDELION_UTILS_MATH_HPP
2#define DANDELION_UTILS_MATH_HPP
3
4#include <cmath>
5#include <tuple>
6
7#include <Eigen/Core>
8
9/*!
10 * \ingroup utils
11 * \file utils/math.hpp
12 * \~chinese
13 * \brief 这个文件提供一些方便使用的数学函数。
14 */
15
16/*! \~chinese 由于 Eigen 的 Identity 方法返回的并非 Matrix 实例,在此创建一个含义相同的矩阵。 */
17const Eigen::Matrix3f I3f = Eigen::Matrix3f::Identity();
18/*! \~chinese 由于 Eigen 的 Identity 方法返回的并非 Matrix 实例,在此创建一个含义相同的矩阵。 */
19const Eigen::Matrix4f I4f = Eigen::Matrix4f::Identity();
20
21/*!
22 * \ingroup utils
23 * \~chinese
24 * \brief 返回 float 或 double 类型的 \f$\pi\f$ 值。
25 */
26template<typename T>
27T pi();
28
29/*! \~chinese 返回 double 类型的特化。 */
30template<>
31inline constexpr double pi<double>()
32{
33 return 3.141592653589793238462643383279;
34}
35
36/*! \~chinese 返回 float 类型的特化。 */
37template<>
38inline constexpr float pi<float>()
39{
40 return 3.14159265358f;
41}
42
43/*!
44 * \ingroup utils
45 * \~chinese
46 * \brief 将角度转换为弧度。
47 */
48template<typename T>
49inline constexpr T radians(T degrees)
50{
51 return degrees / static_cast<T>(180.0) * pi<T>();
52}
53
54/*!
55 * \ingroup utils
56 * \~chinese
57 * \brief 将弧度转换为角度。
58 */
59template<typename T>
60inline constexpr T degrees(T radians)
61{
62 return radians / pi<T>() * static_cast<T>(180.0);
63}
64
65/*!
66 * \ingroup utils
67 * \~chinese
68 * \brief 求一个数的平方。
69 */
70template<typename T>
71inline constexpr T squ(T x)
72{
73 return x * x;
74}
75
76/*!
77 * \ingroup utils
78 * \~chinese
79 * \brief 将一个数截断在给定的上下界之间
80 */
81template<typename T>
82inline constexpr T clamp(T low, T high, T value)
83{
84 return std::max(low, std::min(high, value));
85}
86
87/*!
88 * \ingroup utils
89 * \~chinese
90 * \brief 将代表方向的三维向量转换为它的齐次坐标形式。
91 *
92 * 该函数在一个\f$3\times 1\f$的向量的末尾补 0 ,从而将其转换为\f$4\times 1\f$的方向向量。
93 * 如欲将三维的点转换为齐次坐标形式,请直接调用 `Eigen::Vector` 类型的 `homogeneous` 方法。
94 */
95template<typename T>
96inline constexpr Eigen::Vector<T, 4> to_vec4(Eigen::Vector<T, 3> vec3)
97{
98 return Eigen::Vector<T, 4>(vec3.x(), vec3.y(), vec3.z(), static_cast<T>(0.0));
99}
100
101/*!
102 * \ingroup utils
103 * \~chinese
104 * \brief 求向量 \f$\mathbf{I}\f$ 关于向量 \f$\mathbf{N}\f$ 的反射。
105 * \param I 表示入射射线的向量(不必是单位向量)
106 * \param N 反射平面的法线(必须是单位向量)
107 */
108inline Eigen::Vector3f reflect(const Eigen::Vector3f& I, const Eigen::Vector3f& N)
109{
110 return I - 2 * I.dot(N) * N;
111}
112
113/*!
114 * \ingroup utils
115 * \~chinese
116 * \brief 符号函数,正数的求值结果为 1,负数为 -1,零的求值结果是 0.
117 */
118template<typename T>
119inline constexpr T sign(T x)
120{
121 if (x > static_cast<T>(0.0)) {
122 return static_cast<T>(1.0);
123 }
124 if (x < static_cast<T>(0.0)) {
125 return static_cast<T>(-1.0);
126 }
127 return static_cast<T>(0.0);
128}
129
130/*!
131 * \ingroup utils
132 * \~chinese
133 * \brief 将旋转的四元数表示形式转换为 ZYX 欧拉角表示形式。
134 *
135 * 这个函数采用 ZYX 顺规(即依次绕自身 \f$z, y, x\f$ 轴旋转)。在 Dandelion
136 * 的坐标系约定下,ZYX 顺规对应 roll-yaw-pitch 旋转顺序(滚转、航向、俯仰)。
137 *
138 * 由于欧拉角固有的缺陷,这个函数并不能消除航向角(或称方向角 yaw)在 \f$\pm 90^\circ\f$
139 * 附近时产生的万向锁和抖动问题。
140 *
141 * 虽然函数的返回值是 `tuple`,但使用 `tuple` 接受返回值并不方便,建议用结构化绑定
142 * ```cpp
143 * auto [x_angle, y_angle, z_angle] = quaternion_to_ZYX_euler(w, x, y, z);
144 * ```
145 * 或 `std::tie` 来接受返回值。
146 *
147 * \returns 一个元组,它的三个分量依次是绕 x 轴、绕 y 轴和绕 z 轴的旋转角(角度制)。
148 */
149template<typename T>
150inline std::tuple<T, T, T> quaternion_to_ZYX_euler(T w, T x, T y, T z)
151{
152 const T test = x * z + w * y;
153 constexpr T threshold = static_cast<T>(0.5 - 1e-6);
154 T x_rad, y_rad, z_rad;
155 if (std::abs(test) > threshold) {
156 x_rad = static_cast<T>(0.0);
157 y_rad = sign(test) * pi<T>() / static_cast<T>(2.0);
158 z_rad = sign(test) * static_cast<T>(2.0) * std::atan2(x, w);
159 } else {
160 x_rad =
161 std::atan2(static_cast<T>(-2.0) * (y * z - w * x), squ(w) - squ(x) - squ(y) + squ(z));
162 y_rad = std::asin(static_cast<T>(2.0) * (x * z + w * y));
163 z_rad =
164 std::atan2(static_cast<T>(-2.0) * (x * y - w * z), squ(w) + squ(x) - squ(y) - squ(z));
165 }
166 const T x_angle = degrees(x_rad);
167 const T y_angle = degrees(y_rad);
168 const T z_angle = degrees(z_rad);
169 return std::make_tuple(x_angle, y_angle, z_angle);
170}
171
172#endif // DANDELION_UTILS_MATH_HPP
std::tuple< T, T, T > quaternion_to_ZYX_euler(T w, T x, T y, T z)
将旋转的四元数表示形式转换为 ZYX 欧拉角表示形式。
定义 math.hpp:150
Eigen::Vector3f reflect(const Eigen::Vector3f &I, const Eigen::Vector3f &N)
求向量 关于向量 的反射。
定义 math.hpp:108
constexpr T clamp(T low, T high, T value)
将一个数截断在给定的上下界之间
定义 math.hpp:82
constexpr Eigen::Vector< T, 4 > to_vec4(Eigen::Vector< T, 3 > vec3)
将代表方向的三维向量转换为它的齐次坐标形式。
定义 math.hpp:96
constexpr T degrees(T radians)
将弧度转换为角度。
定义 math.hpp:60
T pi()
返回 float 或 double 类型的 值。
constexpr T sign(T x)
符号函数,正数的求值结果为 1,负数为 -1,零的求值结果是 0.
定义 math.hpp:119
constexpr T squ(T x)
求一个数的平方。
定义 math.hpp:71
constexpr T radians(T degrees)
将角度转换为弧度。
定义 math.hpp:49
constexpr double pi< double >()
定义 math.hpp:31
const Eigen::Matrix4f I4f
定义 math.hpp:19
constexpr float pi< float >()
定义 math.hpp:38
const Eigen::Matrix3f I3f
定义 math.hpp:17