summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/math/quaternion.cpp18
-rw-r--r--core/math/quaternion.h4
-rw-r--r--core/variant/variant.h1
-rw-r--r--core/variant/variant_call.cpp2
-rw-r--r--doc/classes/ColorPicker.xml3
-rw-r--r--doc/classes/Node3D.xml14
-rw-r--r--doc/classes/Quaternion.xml3
-rw-r--r--editor/editor_properties.cpp2
-rw-r--r--editor/plugins/script_editor_plugin.cpp2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs4
-rw-r--r--platform/windows/display_server_windows.cpp4
-rw-r--r--scene/3d/node_3d.cpp23
-rw-r--r--scene/3d/node_3d.h14
-rw-r--r--scene/gui/color_mode.cpp8
-rw-r--r--scene/resources/default_theme/color_picker_hue.svg1
-rw-r--r--scene/resources/default_theme/default_theme.cpp55
-rw-r--r--tests/core/math/test_quaternion.h27
17 files changed, 107 insertions, 78 deletions
diff --git a/core/math/quaternion.cpp b/core/math/quaternion.cpp
index 42b61f6dfe..942a0b766e 100644
--- a/core/math/quaternion.cpp
+++ b/core/math/quaternion.cpp
@@ -38,25 +38,11 @@ real_t Quaternion::angle_to(const Quaternion &p_to) const {
return Math::acos(CLAMP(d * d * 2 - 1, -1, 1));
}
-// 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 Quaternion::get_euler_xyz() const {
- Basis m(*this);
- return m.get_euler(EulerOrder::XYZ);
-}
-
-// 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 Quaternion::get_euler_yxz() const {
+Vector3 Quaternion::get_euler(EulerOrder p_order) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V_MSG(!is_normalized(), Vector3(0, 0, 0), "The quaternion must be normalized.");
#endif
- Basis m(*this);
- return m.get_euler(EulerOrder::YXZ);
+ return Basis(*this).get_euler(p_order);
}
void Quaternion::operator*=(const Quaternion &p_q) {
diff --git a/core/math/quaternion.h b/core/math/quaternion.h
index 7497f1643e..c5af2121d9 100644
--- a/core/math/quaternion.h
+++ b/core/math/quaternion.h
@@ -66,9 +66,7 @@ struct _NO_DISCARD_ Quaternion {
_FORCE_INLINE_ real_t dot(const Quaternion &p_q) const;
real_t angle_to(const Quaternion &p_to) const;
- Vector3 get_euler_xyz() const;
- Vector3 get_euler_yxz() const;
- Vector3 get_euler() const { return get_euler_yxz(); };
+ Vector3 get_euler(EulerOrder p_order = EulerOrder::YXZ) const;
static Quaternion from_euler(const Vector3 &p_euler);
Quaternion slerp(const Quaternion &p_to, const real_t &p_weight) const;
diff --git a/core/variant/variant.h b/core/variant/variant.h
index b0738e7d44..c5be609184 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -490,6 +490,7 @@ public:
}
// Only enum classes that need to be bound need this to be defined.
+ VARIANT_ENUM_CLASS_CONSTRUCTOR(EulerOrder)
VARIANT_ENUM_CLASS_CONSTRUCTOR(JoyAxis)
VARIANT_ENUM_CLASS_CONSTRUCTOR(JoyButton)
VARIANT_ENUM_CLASS_CONSTRUCTOR(Key)
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index f32233d808..7da46a2d05 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1805,7 +1805,7 @@ static void _register_variant_builtin_methods() {
bind_method(Quaternion, slerpni, sarray("to", "weight"), varray());
bind_method(Quaternion, spherical_cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray());
bind_method(Quaternion, spherical_cubic_interpolate_in_time, sarray("b", "pre_a", "post_b", "weight", "b_t", "pre_a_t", "post_b_t"), varray());
- bind_method(Quaternion, get_euler, sarray(), varray());
+ bind_method(Quaternion, get_euler, sarray("order"), varray((int64_t)EulerOrder::YXZ));
bind_static_method(Quaternion, from_euler, sarray("euler"), varray());
bind_method(Quaternion, get_axis, sarray(), varray());
bind_method(Quaternion, get_angle, sarray(), varray());
diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml
index cd1d0b016d..7b71dbc362 100644
--- a/doc/classes/ColorPicker.xml
+++ b/doc/classes/ColorPicker.xml
@@ -151,6 +151,9 @@
<theme_item name="color_hue" data_type="icon" type="Texture2D">
Custom texture for the hue selection slider on the right.
</theme_item>
+ <theme_item name="color_okhsl_hue" data_type="icon" type="Texture2D">
+ Custom texture for the H slider in the OKHSL color mode.
+ </theme_item>
<theme_item name="expanded_arrow" data_type="icon" type="Texture2D">
The icon for color preset drop down menu when expanded.
</theme_item>
diff --git a/doc/classes/Node3D.xml b/doc/classes/Node3D.xml
index bc2570b183..b6024b1887 100644
--- a/doc/classes/Node3D.xml
+++ b/doc/classes/Node3D.xml
@@ -290,7 +290,7 @@
<member name="rotation_edit_mode" type="int" setter="set_rotation_edit_mode" getter="get_rotation_edit_mode" enum="Node3D.RotationEditMode" default="0">
Specify how rotation (and scale) will be presented in the editor.
</member>
- <member name="rotation_order" type="int" setter="set_rotation_order" getter="get_rotation_order" enum="Node3D.RotationOrder" default="2">
+ <member name="rotation_order" type="int" setter="set_rotation_order" getter="get_rotation_order" enum="EulerOrder" default="2">
Specify the axis rotation order of the [member rotation] property. The final orientation is constructed by rotating the Euler angles in the order specified by this property.
</member>
<member name="scale" type="Vector3" setter="set_scale" getter="get_scale" default="Vector3(1, 1, 1)">
@@ -342,17 +342,5 @@
</constant>
<constant name="ROTATION_EDIT_MODE_BASIS" value="2" enum="RotationEditMode">
</constant>
- <constant name="ROTATION_ORDER_XYZ" value="0" enum="RotationOrder">
- </constant>
- <constant name="ROTATION_ORDER_XZY" value="1" enum="RotationOrder">
- </constant>
- <constant name="ROTATION_ORDER_YXZ" value="2" enum="RotationOrder">
- </constant>
- <constant name="ROTATION_ORDER_YZX" value="3" enum="RotationOrder">
- </constant>
- <constant name="ROTATION_ORDER_ZXY" value="4" enum="RotationOrder">
- </constant>
- <constant name="ROTATION_ORDER_ZYX" value="5" enum="RotationOrder">
- </constant>
</constants>
</class>
diff --git a/doc/classes/Quaternion.xml b/doc/classes/Quaternion.xml
index 08a9231751..ac2eda9f28 100644
--- a/doc/classes/Quaternion.xml
+++ b/doc/classes/Quaternion.xml
@@ -99,8 +99,9 @@
</method>
<method name="get_euler" qualifiers="const">
<return type="Vector3" />
+ <param index="0" name="order" type="int" default="2" />
<description>
- Returns Euler angles (in the YXZ convention: when decomposing, first Z, then X, and Y last) corresponding to the rotation represented by the unit quaternion. Returned vector contains the rotation angles in the format (X angle, Y angle, Z angle).
+ Returns the quaternion's rotation in the form of Euler angles. The Euler order depends on the [param order] parameter, for example using the YXZ convention: since this method decomposes, first Z, then X, and Y last. See the [enum EulerOrder] enum for possible values. The returned vector contains the rotation angles in the format (X angle, Y angle, Z angle).
</description>
</method>
<method name="inverse" qualifiers="const">
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 115fda6ca0..d76dce0c1d 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -2725,7 +2725,7 @@ void EditorPropertyQuaternion::update_property() {
spin[2]->set_value(val.z);
spin[3]->set_value(val.w);
if (!is_grabbing_euler()) {
- Vector3 v = val.normalized().get_euler_yxz();
+ Vector3 v = val.normalized().get_euler();
edit_euler.x = Math::rad_to_deg(v.x);
edit_euler.y = Math::rad_to_deg(v.y);
edit_euler.z = Math::rad_to_deg(v.z);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index e4f0192c64..4ff3919e9b 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -3892,7 +3892,7 @@ ScriptEditor::ScriptEditor() {
vbc->add_child(disk_changed_list);
disk_changed_list->set_v_size_flags(SIZE_EXPAND_FILL);
- disk_changed->connect("confirmed", callable_mp(this, &ScriptEditor::reload_scripts));
+ disk_changed->connect("confirmed", callable_mp(this, &ScriptEditor::reload_scripts).bind(false));
disk_changed->set_ok_button_text(TTR("Reload"));
disk_changed->add_button(TTR("Resave"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave");
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
index 5dd629aeb0..f01f0be985 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
@@ -312,7 +312,7 @@ namespace Godot
/// the rotation angles in the format (X angle, Y angle, Z angle).
/// </summary>
/// <returns>The Euler angle representation of this quaternion.</returns>
- public Vector3 GetEuler()
+ public Vector3 GetEuler(EulerOrder order = EulerOrder.Yxz)
{
#if DEBUG
if (!IsNormalized())
@@ -321,7 +321,7 @@ namespace Godot
}
#endif
var basis = new Basis(this);
- return basis.GetEuler();
+ return basis.GetEuler(order);
}
/// <summary>
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 9d0a2578fb..d6ee712a31 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -2449,6 +2449,10 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
window_mouseover_id = INVALID_WINDOW_ID;
_send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT);
+ } else if (window_mouseover_id != INVALID_WINDOW_ID) {
+ // This is reached during drag and drop, after dropping in a different window.
+ // Once-off notification, must call again.
+ track_mouse_leave_event(windows[window_mouseover_id].hWnd);
}
} break;
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index e2d68c36ff..1327bdd6e9 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -392,27 +392,25 @@ Node3D::RotationEditMode Node3D::get_rotation_edit_mode() const {
return data.rotation_edit_mode;
}
-void Node3D::set_rotation_order(RotationOrder p_order) {
- EulerOrder order = EulerOrder(p_order);
-
- if (data.euler_rotation_order == order) {
+void Node3D::set_rotation_order(EulerOrder p_order) {
+ if (data.euler_rotation_order == p_order) {
return;
}
- ERR_FAIL_INDEX(int32_t(order), 6);
+ ERR_FAIL_INDEX(int32_t(p_order), 6);
bool transform_changed = false;
if (data.dirty & DIRTY_EULER_ROTATION_AND_SCALE) {
_update_rotation_and_scale();
} else if (data.dirty & DIRTY_LOCAL_TRANSFORM) {
- data.euler_rotation = Basis::from_euler(data.euler_rotation, data.euler_rotation_order).get_euler_normalized(order);
+ data.euler_rotation = Basis::from_euler(data.euler_rotation, data.euler_rotation_order).get_euler_normalized(p_order);
transform_changed = true;
} else {
data.dirty |= DIRTY_LOCAL_TRANSFORM;
transform_changed = true;
}
- data.euler_rotation_order = order;
+ data.euler_rotation_order = p_order;
if (transform_changed) {
_propagate_transform_changed(this);
@@ -423,8 +421,8 @@ void Node3D::set_rotation_order(RotationOrder p_order) {
notify_property_list_changed(); // Will change the rotation property.
}
-Node3D::RotationOrder Node3D::get_rotation_order() const {
- return RotationOrder(data.euler_rotation_order);
+EulerOrder Node3D::get_rotation_order() const {
+ return data.euler_rotation_order;
}
void Node3D::set_rotation(const Vector3 &p_euler_rad) {
@@ -1042,13 +1040,6 @@ void Node3D::_bind_methods() {
BIND_ENUM_CONSTANT(ROTATION_EDIT_MODE_QUATERNION);
BIND_ENUM_CONSTANT(ROTATION_EDIT_MODE_BASIS);
- BIND_ENUM_CONSTANT(ROTATION_ORDER_XYZ);
- BIND_ENUM_CONSTANT(ROTATION_ORDER_XZY);
- BIND_ENUM_CONSTANT(ROTATION_ORDER_YXZ);
- BIND_ENUM_CONSTANT(ROTATION_ORDER_YZX);
- BIND_ENUM_CONSTANT(ROTATION_ORDER_ZXY);
- BIND_ENUM_CONSTANT(ROTATION_ORDER_ZYX);
-
ADD_GROUP("Transform", "");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "transform", PROPERTY_HINT_NONE, "suffix:m", PROPERTY_USAGE_NO_EDITOR), "set_transform", "get_transform");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "global_transform", PROPERTY_HINT_NONE, "suffix:m", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform");
diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h
index f6868209bb..76c1e3e22c 100644
--- a/scene/3d/node_3d.h
+++ b/scene/3d/node_3d.h
@@ -61,15 +61,6 @@ public:
ROTATION_EDIT_MODE_BASIS,
};
- enum RotationOrder {
- ROTATION_ORDER_XYZ,
- ROTATION_ORDER_XZY,
- ROTATION_ORDER_YXZ,
- ROTATION_ORDER_YZX,
- ROTATION_ORDER_ZXY,
- ROTATION_ORDER_ZYX
- };
-
private:
// For the sake of ease of use, Node3D can operate with Transforms (Basis+Origin), Quaternion/Scale and Euler Rotation/Scale.
// Transform and Quaternion are stored in data.local_transform Basis (so quaternion is not really stored, but converted back/forth from 3x3 matrix on demand).
@@ -179,7 +170,7 @@ public:
void set_rotation_edit_mode(RotationEditMode p_mode);
RotationEditMode get_rotation_edit_mode() const;
- void set_rotation_order(RotationOrder p_order);
+ void set_rotation_order(EulerOrder p_order);
void set_rotation(const Vector3 &p_euler_rad);
void set_scale(const Vector3 &p_scale);
@@ -188,7 +179,7 @@ public:
Vector3 get_position() const;
- RotationOrder get_rotation_order() const;
+ EulerOrder get_rotation_order() const;
Vector3 get_rotation() const;
Vector3 get_scale() const;
@@ -277,6 +268,5 @@ public:
};
VARIANT_ENUM_CAST(Node3D::RotationEditMode)
-VARIANT_ENUM_CAST(Node3D::RotationOrder)
#endif // NODE_3D_H
diff --git a/scene/gui/color_mode.cpp b/scene/gui/color_mode.cpp
index a063cd344a..308fe057c5 100644
--- a/scene/gui/color_mode.cpp
+++ b/scene/gui/color_mode.cpp
@@ -158,8 +158,7 @@ void ColorModeHSV::slider_draw(int p_which) {
right_color.a = 1;
} else if (p_which == 0) {
Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker"));
- slider->draw_set_transform(Point2(), -Math_PI / 2, Size2(1.0, 1.0));
- slider->draw_texture_rect(hue, Rect2(Vector2(margin * -1, 0), Vector2(margin, size.x)), false);
+ slider->draw_texture_rect(hue, Rect2(Vector2(), Vector2(size.x, margin)), false);
return;
} else {
Color s_col;
@@ -289,9 +288,8 @@ void ColorModeOKHSL::slider_draw(int p_which) {
const real_t margin = 16 * color_picker->get_theme_default_base_scale();
if (p_which == 0) { // H
- Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker"));
- slider->draw_set_transform(Point2(), -Math_PI / 2, Size2(1.0, 1.0));
- slider->draw_texture_rect(hue, Rect2(Vector2(margin * -1, 0), Vector2(margin, size.x)), false);
+ Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_okhsl_hue"), SNAME("ColorPicker"));
+ slider->draw_texture_rect(hue, Rect2(Vector2(), Vector2(size.x, margin)), false);
return;
}
diff --git a/scene/resources/default_theme/color_picker_hue.svg b/scene/resources/default_theme/color_picker_hue.svg
deleted file mode 100644
index ff75d5eb9e..0000000000
--- a/scene/resources/default_theme/color_picker_hue.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 1 256" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientTransform="matrix(0 256 -256 0 0 0)" gradientUnits="userSpaceOnUse" x1="0" x2="1" y1="0" y2="0"><stop offset="0" stop-color="#f00"/><stop offset=".04" stop-color="#ff4000"/><stop offset=".08" stop-color="#ff8000"/><stop offset=".17" stop-color="#ff0"/><stop offset=".25" stop-color="#80ff00"/><stop offset=".33" stop-color="#0f0"/><stop offset=".42" stop-color="#00ff80"/><stop offset=".5" stop-color="#0ff"/><stop offset=".58" stop-color="#0080ff"/><stop offset=".63" stop-color="#0040ff"/><stop offset=".67" stop-color="#00f"/><stop offset=".75" stop-color="#8000ff"/><stop offset=".83" stop-color="#f0f"/><stop offset=".92" stop-color="#ff0080"/><stop offset="1" stop-color="#f00"/></linearGradient><path d="m0 0h1v256h-1z" fill="url(#a)"/></svg>
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index aa271e6f4b..894936acd7 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -887,12 +887,65 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("shape_rect", "ColorPicker", icons["picker_shape_rectangle"]);
theme->set_icon("shape_rect_wheel", "ColorPicker", icons["picker_shape_rectangle_wheel"]);
theme->set_icon("add_preset", "ColorPicker", icons["add"]);
- theme->set_icon("color_hue", "ColorPicker", icons["color_picker_hue"]);
theme->set_icon("sample_bg", "ColorPicker", icons["mini_checkerboard"]);
theme->set_icon("overbright_indicator", "ColorPicker", icons["color_picker_overbright"]);
theme->set_icon("bar_arrow", "ColorPicker", icons["color_picker_bar_arrow"]);
theme->set_icon("picker_cursor", "ColorPicker", icons["color_picker_cursor"]);
+ {
+ const int precision = 7;
+
+ Ref<Gradient> hue_gradient;
+ hue_gradient.instantiate();
+ PackedFloat32Array offsets;
+ offsets.resize(precision);
+ PackedColorArray colors;
+ colors.resize(precision);
+
+ for (int i = 0; i < precision; i++) {
+ float h = i / float(precision - 1);
+ offsets.write[i] = h;
+ colors.write[i] = Color::from_hsv(h, 1, 1);
+ }
+ hue_gradient->set_offsets(offsets);
+ hue_gradient->set_colors(colors);
+
+ Ref<GradientTexture2D> hue_texture;
+ hue_texture.instantiate();
+ hue_texture->set_width(800);
+ hue_texture->set_height(6);
+ hue_texture->set_gradient(hue_gradient);
+
+ theme->set_icon("color_hue", "ColorPicker", hue_texture);
+ }
+
+ {
+ const int precision = 7;
+
+ Ref<Gradient> hue_gradient;
+ hue_gradient.instantiate();
+ PackedFloat32Array offsets;
+ offsets.resize(precision);
+ PackedColorArray colors;
+ colors.resize(precision);
+
+ for (int i = 0; i < precision; i++) {
+ float h = i / float(precision - 1);
+ offsets.write[i] = h;
+ colors.write[i] = Color::from_ok_hsl(h, 1, 0.5);
+ }
+ hue_gradient->set_offsets(offsets);
+ hue_gradient->set_colors(colors);
+
+ Ref<GradientTexture2D> hue_texture;
+ hue_texture.instantiate();
+ hue_texture->set_width(800);
+ hue_texture->set_height(6);
+ hue_texture->set_gradient(hue_gradient);
+
+ theme->set_icon("color_okhsl_hue", "ColorPicker", hue_texture);
+ }
+
// ColorPickerButton
theme->set_icon("bg", "ColorPickerButton", icons["mini_checkerboard"]);
diff --git a/tests/core/math/test_quaternion.h b/tests/core/math/test_quaternion.h
index 909fc2499f..c3ae322991 100644
--- a/tests/core/math/test_quaternion.h
+++ b/tests/core/math/test_quaternion.h
@@ -169,10 +169,9 @@ TEST_CASE("[Quaternion] Construct Euler YXZ dynamic axes") {
Vector3 euler_r(0.0, 0.0, roll);
Quaternion q_r = Quaternion::from_euler(euler_r);
- // Roll-Z is followed by Pitch-X.
- Quaternion check_xz = q_p * q_r;
- // Then Yaw-Y follows both.
- Quaternion check_yxz = q_y * check_xz;
+ // Instrinsically, Yaw-Y then Pitch-X then Roll-Z.
+ // Extrinsically, Roll-Z is followed by Pitch-X, then Yaw-Y.
+ Quaternion check_yxz = q_y * q_p * q_r;
// Test construction from YXZ Euler angles.
Vector3 euler_yxz(pitch, yaw, roll);
@@ -182,8 +181,9 @@ TEST_CASE("[Quaternion] Construct Euler YXZ dynamic axes") {
CHECK(q[2] == doctest::Approx(check_yxz[2]));
CHECK(q[3] == doctest::Approx(check_yxz[3]));
- // Sneak in a test of is_equal_approx.
CHECK(q.is_equal_approx(check_yxz));
+ CHECK(q.get_euler().is_equal_approx(euler_yxz));
+ CHECK(check_yxz.get_euler().is_equal_approx(euler_yxz));
}
TEST_CASE("[Quaternion] Construct Basis Euler") {
@@ -235,6 +235,23 @@ TEST_CASE("[Quaternion] Construct Basis Axes") {
CHECK(q[3] == doctest::Approx(0.8582598));
}
+TEST_CASE("[Quaternion] Get Euler Orders") {
+ double x = Math::deg_to_rad(30.0);
+ double y = Math::deg_to_rad(45.0);
+ double z = Math::deg_to_rad(10.0);
+ Vector3 euler(x, y, z);
+ for (int i = 0; i < 6; i++) {
+ EulerOrder order = (EulerOrder)i;
+ Basis basis = Basis::from_euler(euler, order);
+ Quaternion q = Quaternion(basis);
+ Vector3 check = q.get_euler(order);
+ CHECK_MESSAGE(check.is_equal_approx(euler),
+ "Quaternion get_euler method should return the original angles.");
+ CHECK_MESSAGE(check.is_equal_approx(basis.get_euler(order)),
+ "Quaternion get_euler method should behave the same as Basis get_euler.");
+ }
+}
+
TEST_CASE("[Quaternion] Product (book)") {
// Example from "Quaternions and Rotation Sequences" by Jack Kuipers, p. 108.
Quaternion p(1.0, -2.0, 1.0, 3.0);