5
5
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
6
*/
7
7
8
- use crate :: framework:: itest;
9
- use godot:: builtin:: Quaternion ;
8
+ use crate :: framework:: { expect_panic, itest} ;
9
+ use godot:: builtin:: math:: assert_eq_approx;
10
+ use godot:: builtin:: { Quaternion , Vector3 } ;
10
11
11
12
#[ itest]
12
13
fn quaternion_default ( ) {
@@ -28,4 +29,149 @@ fn quaternion_from_xyzw() {
28
29
assert_eq ! ( quat. w, 0.8924 ) ;
29
30
}
30
31
32
+ #[ itest]
33
+ fn quaternion_from_axis_angle ( ) {
34
+ // 1. Should generate quaternion from axis angle.
35
+ let quat = Quaternion :: from_axis_angle ( Vector3 :: new ( 0.0 , 0.0 , 1.0 ) . normalized ( ) , 1.0 ) ;
36
+
37
+ // Taken from doing this in GDScript.
38
+ assert_eq ! ( quat. x, 0.0 ) ;
39
+ assert_eq ! ( quat. y, 0.0 ) ;
40
+ assert_eq_approx ! ( quat. z, 0.479426 ) ;
41
+ assert_eq_approx ! ( quat. w, 0.877583 ) ;
42
+
43
+ // 2. Should panic if axis is not normalized.
44
+ expect_panic ( "Quaternion axis {axis:?} is not normalized." , || {
45
+ Quaternion :: from_axis_angle ( Vector3 :: new ( 0.0 , 0.0 , 0.0 ) , 1.0 ) ;
46
+ } ) ;
47
+ }
48
+
49
+ #[ itest]
50
+ fn quaternion_normalization ( ) {
51
+ // 1. Should panic on quaternions with length 0.
52
+ expect_panic ( "Quaternion has length 0" , || {
53
+ Quaternion :: new ( 0.0 , 0.0 , 0.0 , 0.0 ) . normalized ( ) ;
54
+ } ) ;
55
+
56
+ // 2. Should not panic on any other length.
57
+ let quat = Quaternion :: default ( ) . normalized ( ) ;
58
+ assert_eq ! ( quat. length( ) , 1.0 ) ;
59
+ assert ! ( quat. is_normalized( ) ) ;
60
+ }
61
+
62
+ #[ itest]
63
+ fn quaternion_slerp ( ) {
64
+ let a = Quaternion :: new ( -1.0 , -1.0 , -1.0 , 10.0 ) ;
65
+ let b = Quaternion :: new ( 3.0 , 3.0 , 3.0 , 5.0 ) ;
66
+
67
+ // 1. Should perform interpolation.
68
+ let outcome = a. normalized ( ) . slerp ( b. normalized ( ) , 1.0 ) ;
69
+ let expected = Quaternion :: new ( 0.41602516 , 0.41602516 , 0.41602516 , 0.69337523 ) ;
70
+ assert_eq_approx ! ( outcome, expected) ;
71
+
72
+ // 2. Should panic on quaternions that are not normalized.
73
+ expect_panic ( "Slerp requires normalized quaternions" , || {
74
+ a. slerp ( b, 1.9 ) ;
75
+ } ) ;
76
+
77
+ // 3. Should not panic on default values.
78
+ let outcome = Quaternion :: default ( ) . slerp ( Quaternion :: default ( ) , 1.0 ) ;
79
+ assert_eq ! ( outcome, Quaternion :: default ( ) ) ;
80
+ }
81
+
82
+ #[ itest]
83
+ fn quaternion_slerpni ( ) {
84
+ let a = Quaternion :: new ( -1.0 , -1.0 , -1.0 , 10.0 ) ;
85
+ let b = Quaternion :: new ( 3.0 , 3.0 , 3.0 , 6.0 ) ;
86
+
87
+ // 1. Should perform interpolation.
88
+ let outcome = a. normalized ( ) . slerpni ( b. normalized ( ) , 1.0 ) ;
89
+ let expected = Quaternion :: new ( 0.37796447 , 0.37796447 , 0.37796447 , 0.75592893 ) ;
90
+ assert_eq_approx ! ( outcome, expected) ;
91
+
92
+ // 2. Should panic on quaternions that are not normalized.
93
+ expect_panic ( "Slerpni requires normalized quaternions" , || {
94
+ a. slerpni ( b, 1.9 ) ;
95
+ } ) ;
96
+
97
+ // 3. Should not panic on default values.
98
+ let outcome = Quaternion :: default ( ) . slerpni ( Quaternion :: default ( ) , 1.0 ) ;
99
+ assert_eq ! ( outcome, Quaternion :: default ( ) ) ;
100
+ }
101
+
102
+ #[ itest]
103
+ fn quaternion_spherical_cubic_interpolate ( ) {
104
+ let pre_a = Quaternion :: new ( -1.0 , -1.0 , -1.0 , -1.0 ) ;
105
+ let a = Quaternion :: new ( 0.0 , 0.0 , 0.0 , 1.0 ) ;
106
+ let b = Quaternion :: new ( 0.0 , 1.0 , 0.0 , 2.0 ) ;
107
+ let post_b = Quaternion :: new ( 2.0 , 2.0 , 2.0 , 2.0 ) ;
108
+
109
+ // 1. Should perform interpolation.
110
+ let outcome =
111
+ a. spherical_cubic_interpolate ( b. normalized ( ) , pre_a. normalized ( ) , post_b. normalized ( ) , 0.5 ) ;
112
+
113
+ // Taken from doing this in GDScript.
114
+ let expected = Quaternion :: new ( -0.072151 , 0.176298 , -0.072151 , 0.979034 ) ;
115
+ assert_eq_approx ! ( outcome, expected) ;
116
+
117
+ // 2. Should panic on quaternions that are not normalized.
118
+ expect_panic (
119
+ "Spherical cubic interpolation requires normalized quaternions" ,
120
+ || {
121
+ a. spherical_cubic_interpolate ( b, pre_a, post_b, 0.5 ) ;
122
+ } ,
123
+ ) ;
124
+
125
+ // 3. Should not panic on default returns when inputs are normalized.
126
+ let outcome = Quaternion :: default ( ) . spherical_cubic_interpolate (
127
+ Quaternion :: default ( ) ,
128
+ Quaternion :: default ( ) ,
129
+ Quaternion :: default ( ) ,
130
+ 1.0 ,
131
+ ) ;
132
+ assert_eq ! ( outcome, Quaternion :: default ( ) ) ;
133
+ }
134
+
135
+ #[ itest]
136
+ fn quaternion_spherical_cubic_interpolate_in_time ( ) {
137
+ let pre_a = Quaternion :: new ( -1.0 , -1.0 , -1.0 , -1.0 ) ;
138
+ let a = Quaternion :: new ( 0.0 , 0.0 , 0.0 , 1.0 ) ;
139
+ let b = Quaternion :: new ( 0.0 , 1.0 , 0.0 , 2.0 ) ;
140
+ let post_b = Quaternion :: new ( 2.0 , 2.0 , 2.0 , 2.0 ) ;
141
+
142
+ // 1. Should perform interpolation.
143
+ let outcome = a. spherical_cubic_interpolate_in_time (
144
+ b. normalized ( ) ,
145
+ pre_a. normalized ( ) ,
146
+ post_b. normalized ( ) ,
147
+ 0.5 ,
148
+ 0.1 ,
149
+ 0.1 ,
150
+ 0.1 ,
151
+ ) ;
152
+
153
+ // Taken from doing this in GDScript.
154
+ let expected = Quaternion :: new ( 0.280511 , 0.355936 , 0.280511 , 0.84613 ) ;
155
+ assert_eq_approx ! ( outcome, expected) ;
156
+
157
+ // 2. Should panic on quaternions that are not normalized.
158
+ expect_panic (
159
+ "Spherical cubic interpolation in time requires normalized quaternions" ,
160
+ || {
161
+ a. spherical_cubic_interpolate_in_time ( b, pre_a, post_b, 0.5 , 0.1 , 0.1 , 0.1 ) ;
162
+ } ,
163
+ ) ;
164
+
165
+ // 3. Should not panic on default returns when inputs are normalized.
166
+ let outcome = Quaternion :: default ( ) . spherical_cubic_interpolate_in_time (
167
+ Quaternion :: default ( ) ,
168
+ Quaternion :: default ( ) ,
169
+ Quaternion :: default ( ) ,
170
+ 1.0 ,
171
+ 1.0 ,
172
+ 1.0 ,
173
+ 1.0 ,
174
+ ) ;
175
+ assert_eq ! ( outcome, Quaternion :: default ( ) )
176
+ }
31
177
// TODO more tests
0 commit comments