diff options
Diffstat (limited to 'core/math')
-rw-r--r-- | core/math/bsp_tree.cpp | 11 | ||||
-rw-r--r-- | core/math/math_2d.h | 30 | ||||
-rw-r--r-- | core/math/matrix3.cpp | 86 | ||||
-rw-r--r-- | core/math/matrix3.h | 9 | ||||
-rw-r--r-- | core/math/plane.h | 17 | ||||
-rw-r--r-- | core/math/quat.cpp | 55 | ||||
-rw-r--r-- | core/math/quat.h | 11 | ||||
-rw-r--r-- | core/math/rect3.h | 6 | ||||
-rw-r--r-- | core/math/transform.cpp | 7 |
9 files changed, 177 insertions, 55 deletions
diff --git a/core/math/bsp_tree.cpp b/core/math/bsp_tree.cpp index 327a6017c3..e22bc2b05e 100644 --- a/core/math/bsp_tree.cpp +++ b/core/math/bsp_tree.cpp @@ -577,12 +577,11 @@ BSP_Tree::BSP_Tree(const PoolVector<Face3> &p_faces, real_t p_error_radius) { error_radius = p_error_radius; } -BSP_Tree::BSP_Tree(const Vector<Node> &p_nodes, const Vector<Plane> &p_planes, const Rect3 &p_aabb, real_t p_error_radius) { - - nodes = p_nodes; - planes = p_planes; - aabb = p_aabb; - error_radius = p_error_radius; +BSP_Tree::BSP_Tree(const Vector<Node> &p_nodes, const Vector<Plane> &p_planes, const Rect3 &p_aabb, real_t p_error_radius) + : nodes(p_nodes), + planes(p_planes), + aabb(p_aabb), + error_radius(p_error_radius) { } BSP_Tree::~BSP_Tree() { diff --git a/core/math/math_2d.h b/core/math/math_2d.h index 780bb532d7..b679371e03 100644 --- a/core/math/math_2d.h +++ b/core/math/math_2d.h @@ -378,13 +378,13 @@ struct Rect2 { operator String() const { return String(position) + ", " + String(size); } Rect2() {} - Rect2(real_t p_x, real_t p_y, real_t p_width, real_t p_height) { - position = Point2(p_x, p_y); - size = Size2(p_width, p_height); + Rect2(real_t p_x, real_t p_y, real_t p_width, real_t p_height) + : position(Point2(p_x, p_y)), + size(Size2(p_width, p_height)) { } - Rect2(const Point2 &p_pos, const Size2 &p_size) { - position = p_pos; - size = p_size; + Rect2(const Point2 &p_pos, const Size2 &p_size) + : position(p_pos), + size(p_size) { } }; @@ -571,18 +571,18 @@ struct Rect2i { operator String() const { return String(position) + ", " + String(size); } operator Rect2() const { return Rect2(position, size); } - Rect2i(const Rect2 &p_r2) { - position = p_r2.position; - size = p_r2.size; + Rect2i(const Rect2 &p_r2) + : position(p_r2.position), + size(p_r2.size) { } Rect2i() {} - Rect2i(int p_x, int p_y, int p_width, int p_height) { - position = Point2(p_x, p_y); - size = Size2(p_width, p_height); + Rect2i(int p_x, int p_y, int p_width, int p_height) + : position(Point2(p_x, p_y)), + size(Size2(p_width, p_height)) { } - Rect2i(const Point2 &p_pos, const Size2 &p_size) { - position = p_pos; - size = p_size; + Rect2i(const Point2 &p_pos, const Size2 &p_size) + : position(p_pos), + size(p_size) { } }; diff --git a/core/math/matrix3.cpp b/core/math/matrix3.cpp index b64f34d977..f2f6ff93cf 100644 --- a/core/math/matrix3.cpp +++ b/core/math/matrix3.cpp @@ -338,7 +338,7 @@ void Basis::set_rotation_axis_angle(const Vector3 &p_axis, real_t p_angle) { rotate(p_axis, p_angle); } -// get_euler returns a vector containing the Euler angles in the format +// get_euler_xyz returns a vector containing the Euler angles in the format // (a1,a2,a3), where a3 is the angle of the first rotation, and a1 is the last // (following the convention they are commonly defined in the literature). // @@ -348,7 +348,7 @@ void Basis::set_rotation_axis_angle(const Vector3 &p_axis, real_t p_angle) { // And thus, assuming the matrix is a rotation matrix, this function returns // the angles in the decomposition R = X(a1).Y(a2).Z(a3) where Z(a) rotates // around the z-axis by a and so on. -Vector3 Basis::get_euler() const { +Vector3 Basis::get_euler_xyz() const { // Euler angles in XYZ convention. // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix @@ -366,6 +366,9 @@ Vector3 Basis::get_euler() const { if (euler.y > -Math_PI * 0.5) { //if rotation is Y-only, return a proper -pi,pi range like in x or z for the same case. if (elements[1][0] == 0.0 && elements[0][1] == 0.0 && elements[0][0] < 0.0) { + euler.x = 0; + euler.z = 0; + if (euler.y > 0.0) euler.y = Math_PI - euler.y; else @@ -389,10 +392,11 @@ Vector3 Basis::get_euler() const { return euler; } -// set_euler expects a vector containing the Euler angles in the format -// (c,b,a), where a is the angle of the first rotation, and c is the last. +// set_euler_xyz expects a vector containing the Euler angles in the format +// (ax,ay,az), where ax is the angle of rotation around x axis, +// and similar for other axes. // The current implementation uses XYZ convention (Z is the first rotation). -void Basis::set_euler(const Vector3 &p_euler) { +void Basis::set_euler_xyz(const Vector3 &p_euler) { real_t c, s; @@ -412,6 +416,78 @@ void Basis::set_euler(const Vector3 &p_euler) { *this = xmat * (ymat * zmat); } +// get_euler_yxz returns a vector containing the Euler angles in the YXZ convention, +// as in first-Z, then-X, last-Y. The angles for X, Y, and Z rotations are returned +// as the x, y, and z components of a Vector3 respectively. +Vector3 Basis::get_euler_yxz() const { + + // Euler angles in YXZ convention. + // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix + // + // rot = cy*cz+sy*sx*sz cz*sy*sx-cy*sz cx*sy + // cx*sz cx*cz -sx + // cy*sx*sz-cz*sy cy*cz*sx+sy*sz cy*cx + + Vector3 euler; +#ifdef MATH_CHECKS + ERR_FAIL_COND_V(is_rotation() == false, euler); +#endif + real_t m12 = elements[1][2]; + + if (m12 < 1) { + if (m12 > -1) { + if (elements[1][0] == 0 && elements[0][1] == 0 && elements[2][2] < 0) { // use pure x rotation + real_t x = asin(-m12); + euler.y = 0; + euler.z = 0; + + if (x > 0.0) + euler.x = Math_PI - x; + else + euler.x = -(Math_PI + x); + } else { + euler.x = asin(-m12); + euler.y = atan2(elements[0][2], elements[2][2]); + euler.z = atan2(elements[1][0], elements[1][1]); + } + } else { // m12 == -1 + euler.x = Math_PI * 0.5; + euler.y = -atan2(-elements[0][1], elements[0][0]); + euler.z = 0; + } + } else { // m12 == 1 + euler.x = -Math_PI * 0.5; + euler.y = -atan2(-elements[0][1], elements[0][0]); + euler.z = 0; + } + + return euler; +} + +// set_euler_yxz expects a vector containing the Euler angles in the format +// (ax,ay,az), where ax is the angle of rotation around x axis, +// and similar for other axes. +// The current implementation uses YXZ convention (Z is the first rotation). +void Basis::set_euler_yxz(const Vector3 &p_euler) { + + real_t c, s; + + c = Math::cos(p_euler.x); + s = Math::sin(p_euler.x); + Basis xmat(1.0, 0.0, 0.0, 0.0, c, -s, 0.0, s, c); + + c = Math::cos(p_euler.y); + s = Math::sin(p_euler.y); + Basis ymat(c, 0.0, s, 0.0, 1.0, 0.0, -s, 0.0, c); + + c = Math::cos(p_euler.z); + s = Math::sin(p_euler.z); + Basis zmat(c, -s, 0.0, s, c, 0.0, 0.0, 0.0, 1.0); + + //optimizer will optimize away all this anyway + *this = ymat * xmat * zmat; +} + bool Basis::is_equal_approx(const Basis &a, const Basis &b) const { for (int i = 0; i < 3; i++) { diff --git a/core/math/matrix3.h b/core/math/matrix3.h index 8897c692f7..74e6564578 100644 --- a/core/math/matrix3.h +++ b/core/math/matrix3.h @@ -84,8 +84,13 @@ public: void set_rotation_euler(const Vector3 &p_euler); void set_rotation_axis_angle(const Vector3 &p_axis, real_t p_angle); - Vector3 get_euler() const; - void set_euler(const Vector3 &p_euler); + Vector3 get_euler_xyz() const; + void set_euler_xyz(const Vector3 &p_euler); + Vector3 get_euler_yxz() const; + void set_euler_yxz(const Vector3 &p_euler); + + Vector3 get_euler() const { return get_euler_yxz(); }; + void set_euler(const Vector3 &p_euler) { set_euler_yxz(p_euler); }; void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const; void set_axis_angle(const Vector3 &p_axis, real_t p_phi); diff --git a/core/math/plane.h b/core/math/plane.h index 5a048674e4..92ebcd8024 100644 --- a/core/math/plane.h +++ b/core/math/plane.h @@ -75,7 +75,8 @@ public: _FORCE_INLINE_ Plane() { d = 0; } _FORCE_INLINE_ Plane(real_t p_a, real_t p_b, real_t p_c, real_t p_d) - : normal(p_a, p_b, p_c), d(p_d){}; + : normal(p_a, p_b, p_c), + d(p_d){}; _FORCE_INLINE_ Plane(const Vector3 &p_normal, real_t p_d); _FORCE_INLINE_ Plane(const Vector3 &p_point, const Vector3 &p_normal); @@ -99,16 +100,14 @@ bool Plane::has_point(const Vector3 &p_point, real_t _epsilon) const { return (dist <= _epsilon); } -Plane::Plane(const Vector3 &p_normal, real_t p_d) { - - normal = p_normal; - d = p_d; +Plane::Plane(const Vector3 &p_normal, real_t p_d) + : normal(p_normal), + d(p_d) { } -Plane::Plane(const Vector3 &p_point, const Vector3 &p_normal) { - - normal = p_normal; - d = p_normal.dot(p_point); +Plane::Plane(const Vector3 &p_point, const Vector3 &p_normal) + : normal(p_normal), + d(p_normal.dot(p_point)) { } Plane::Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_point3, ClockDirection p_dir) { diff --git a/core/math/quat.cpp b/core/math/quat.cpp index 0bea97c2e8..5984cdf657 100644 --- a/core/math/quat.cpp +++ b/core/math/quat.cpp @@ -31,10 +31,11 @@ #include "matrix3.h" #include "print_string.h" -// set_euler expects a vector containing the Euler angles in the format -// (c,b,a), where a is the angle of the first rotation, and c is the last. -// The current implementation uses XYZ convention (Z is the first rotation). -void Quat::set_euler(const Vector3 &p_euler) { +// set_euler_xyz expects a vector containing the Euler angles in the format +// (ax,ay,az), where ax is the angle of rotation around x axis, +// and similar for other axes. +// This implementation uses XYZ convention (Z is the first rotation). +void Quat::set_euler_xyz(const Vector3 &p_euler) { real_t half_a1 = p_euler.x * 0.5; real_t half_a2 = p_euler.y * 0.5; real_t half_a3 = p_euler.z * 0.5; @@ -56,12 +57,48 @@ void Quat::set_euler(const Vector3 &p_euler) { -sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3); } -// get_euler returns a vector containing the Euler angles in the format -// (a1,a2,a3), where a3 is the angle of the first rotation, and a1 is the last. -// The current implementation uses XYZ convention (Z is the first rotation). -Vector3 Quat::get_euler() const { +// get_euler_xyz returns a vector containing the Euler angles in the format +// (ax,ay,az), where ax is the angle of rotation around x axis, +// and similar for other axes. +// This implementation uses XYZ convention (Z is the first rotation). +Vector3 Quat::get_euler_xyz() const { Basis m(*this); - return m.get_euler(); + return m.get_euler_xyz(); +} + +// set_euler_yxz expects a vector containing the Euler angles in the format +// (ax,ay,az), where ax is the angle of rotation around x axis, +// and similar for other axes. +// This implementation uses YXZ convention (Z is the first rotation). +void Quat::set_euler_yxz(const Vector3 &p_euler) { + real_t half_a1 = p_euler.y * 0.5; + real_t half_a2 = p_euler.x * 0.5; + real_t half_a3 = p_euler.z * 0.5; + + // R = Y(a1).X(a2).Z(a3) convention for Euler angles. + // Conversion to quaternion as listed in https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf (page A-6) + // a3 is the angle of the first rotation, following the notation in this reference. + + real_t cos_a1 = Math::cos(half_a1); + real_t sin_a1 = Math::sin(half_a1); + real_t cos_a2 = Math::cos(half_a2); + real_t sin_a2 = Math::sin(half_a2); + real_t cos_a3 = Math::cos(half_a3); + real_t sin_a3 = Math::sin(half_a3); + + set(sin_a1 * cos_a2 * sin_a3 + cos_a1 * sin_a2 * cos_a3, + sin_a1 * cos_a2 * cos_a3 - cos_a1 * sin_a2 * sin_a3, + -sin_a1 * sin_a2 * cos_a3 + cos_a1 * sin_a2 * sin_a3, + sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3); +} + +// get_euler_yxz returns a vector containing the Euler angles in the format +// (ax,ay,az), where ax is the angle of rotation around x axis, +// and similar for other axes. +// This implementation uses YXZ convention (Z is the first rotation). +Vector3 Quat::get_euler_yxz() const { + Basis m(*this); + return m.get_euler_yxz(); } void Quat::operator*=(const Quat &q) { diff --git a/core/math/quat.h b/core/math/quat.h index f22275b457..0e378eb4e4 100644 --- a/core/math/quat.h +++ b/core/math/quat.h @@ -51,8 +51,15 @@ public: bool is_normalized() const; Quat inverse() const; _FORCE_INLINE_ real_t dot(const Quat &q) const; - void set_euler(const Vector3 &p_euler); - Vector3 get_euler() const; + + void set_euler_xyz(const Vector3 &p_euler); + Vector3 get_euler_xyz() const; + void set_euler_yxz(const Vector3 &p_euler); + Vector3 get_euler_yxz() const; + + void set_euler(const Vector3 &p_euler) { set_euler_yxz(p_euler); }; + Vector3 get_euler() const { return get_euler_yxz(); }; + Quat slerp(const Quat &q, const real_t &t) const; Quat slerpni(const Quat &q, const real_t &t) const; Quat cubic_slerp(const Quat &q, const Quat &prep, const Quat &postq, const real_t &t) const; diff --git a/core/math/rect3.h b/core/math/rect3.h index b7c94ad9f7..e5d7462009 100644 --- a/core/math/rect3.h +++ b/core/math/rect3.h @@ -101,9 +101,9 @@ public: operator String() const; _FORCE_INLINE_ Rect3() {} - inline Rect3(const Vector3 &p_pos, const Vector3 &p_size) { - position = p_pos; - size = p_size; + inline Rect3(const Vector3 &p_pos, const Vector3 &p_size) + : position(p_pos), + size(p_size) { } }; diff --git a/core/math/transform.cpp b/core/math/transform.cpp index 7a50214596..3a86fbfc6c 100644 --- a/core/math/transform.cpp +++ b/core/math/transform.cpp @@ -208,8 +208,7 @@ Transform::operator String() const { return basis.operator String() + " - " + origin.operator String(); } -Transform::Transform(const Basis &p_basis, const Vector3 &p_origin) { - - basis = p_basis; - origin = p_origin; +Transform::Transform(const Basis &p_basis, const Vector3 &p_origin) + : basis(p_basis), + origin(p_origin) { } |