numerix 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +5 -0
- data/.yardopts +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +66 -0
- data/Rakefile +18 -0
- data/TODO.txt +25 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/ext/numerix/common.h +107 -0
- data/ext/numerix/extconf.rb +3 -0
- data/ext/numerix/matrix3x2.c +638 -0
- data/ext/numerix/matrix3x2.h +52 -0
- data/ext/numerix/matrix4x4.c +1807 -0
- data/ext/numerix/matrix4x4.h +90 -0
- data/ext/numerix/matrix_base.c +307 -0
- data/ext/numerix/matrix_base.h +70 -0
- data/ext/numerix/numerix.c +33 -0
- data/ext/numerix/numerix.h +19 -0
- data/ext/numerix/plane.c +311 -0
- data/ext/numerix/plane.h +34 -0
- data/ext/numerix/quaternion.c +712 -0
- data/ext/numerix/quaternion.h +53 -0
- data/ext/numerix/structure.c +154 -0
- data/ext/numerix/structure.h +24 -0
- data/ext/numerix/vector.c +326 -0
- data/ext/numerix/vector.h +57 -0
- data/ext/numerix/vector2.c +641 -0
- data/ext/numerix/vector2.h +64 -0
- data/ext/numerix/vector3.c +805 -0
- data/ext/numerix/vector3.h +68 -0
- data/ext/numerix/vector4.c +727 -0
- data/ext/numerix/vector4.h +63 -0
- data/ext/numerix/vector_base.c +94 -0
- data/ext/numerix/vector_base.h +30 -0
- data/extra/numerix128.png +0 -0
- data/extra/numerix24.png +0 -0
- data/extra/numerix32.png +0 -0
- data/extra/numerix320.png +0 -0
- data/extra/numerix48.png +0 -0
- data/extra/numerix96.png +0 -0
- data/lib/numerix/error.rb +36 -0
- data/lib/numerix/matrix3x2.rb +420 -0
- data/lib/numerix/matrix4x4.rb +676 -0
- data/lib/numerix/matrix_base.rb +14 -0
- data/lib/numerix/plane.rb +154 -0
- data/lib/numerix/quaternion.rb +355 -0
- data/lib/numerix/structure.rb +124 -0
- data/lib/numerix/vector.rb +13 -0
- data/lib/numerix/vector2.rb +534 -0
- data/lib/numerix/vector3.rb +572 -0
- data/lib/numerix/vector4.rb +551 -0
- data/lib/numerix/vector_base.rb +14 -0
- data/lib/numerix/version.rb +6 -0
- data/lib/numerix.rb +10 -0
- data/numerix.gemspec +30 -0
- metadata +167 -0
@@ -0,0 +1,712 @@
|
|
1
|
+
|
2
|
+
#include "quaternion.h"
|
3
|
+
|
4
|
+
void Init_quaternion(VALUE outer) {
|
5
|
+
rb_define_alloc_func(rb_cQuaternion, rb_quaternion_alloc);
|
6
|
+
rb_define_method(rb_cQuaternion, "initialize", rb_quaternion_initialize, -1);
|
7
|
+
|
8
|
+
// Instance
|
9
|
+
rb_define_method(rb_cQuaternion, "identity?", rb_quaternion_identity_p, 0);
|
10
|
+
rb_define_method(rb_cQuaternion, "length", rb_quaternion_length, 0);
|
11
|
+
rb_define_method(rb_cQuaternion, "length_squared", rb_quaternion_length_squared, 0);
|
12
|
+
rb_define_method(rb_cQuaternion, "normalize", rb_quaternion_normalize, 0);
|
13
|
+
rb_define_method(rb_cQuaternion, "normalize!", rb_quaternion_normalize_bang, 0);
|
14
|
+
rb_define_method(rb_cQuaternion, "conjugate", rb_quaternion_conjugate, 0);
|
15
|
+
rb_define_method(rb_cQuaternion, "conjugate!", rb_quaternion_conjugate_bang, 0);
|
16
|
+
rb_define_method(rb_cQuaternion, "inverse", rb_quaternion_inverse, 0);
|
17
|
+
rb_define_method(rb_cQuaternion, "dot", rb_quaternion_dot, 1);
|
18
|
+
rb_define_method(rb_cQuaternion, "concatenate", rb_quaternion_concatenate, 1);
|
19
|
+
rb_define_method(rb_cQuaternion, "concatenate!", rb_quaternion_concatenate_bang, 1);
|
20
|
+
rb_define_method(rb_cQuaternion, "lerp", rb_quaternion_lerp, 2);
|
21
|
+
rb_define_method(rb_cQuaternion, "lerp!", rb_quaternion_lerp_bang, 2);
|
22
|
+
rb_define_method(rb_cQuaternion, "slerp", rb_quaternion_slerp, 2);
|
23
|
+
rb_define_method(rb_cQuaternion, "slerp!", rb_quaternion_slerp_bang, 2);
|
24
|
+
|
25
|
+
// Conversion
|
26
|
+
rb_define_method(rb_cQuaternion, "to_s", rb_quaternion_to_s, 0);
|
27
|
+
rb_define_method(rb_cQuaternion, "to_a", rb_quaternion_to_a, 0);
|
28
|
+
rb_define_method(rb_cQuaternion, "to_h", rb_quaternion_to_h, 0);
|
29
|
+
rb_define_method(rb_cQuaternion, "to_vec4", rb_quaternion_to_vec4, 0);
|
30
|
+
|
31
|
+
// Operators
|
32
|
+
rb_define_method(rb_cQuaternion, "-@", rb_quaternion_negate, 0);
|
33
|
+
rb_define_method(rb_cQuaternion, "+", rb_quaternion_add, 1);
|
34
|
+
rb_define_method(rb_cQuaternion, "-", rb_quaternion_subtract, 1);
|
35
|
+
rb_define_method(rb_cQuaternion, "*", rb_quaternion_multiply, 1);
|
36
|
+
rb_define_method(rb_cQuaternion, "/", rb_quaternion_divide, 1);
|
37
|
+
rb_define_method(rb_cQuaternion, "==", rb_quaternion_equal, 1);
|
38
|
+
|
39
|
+
// Class
|
40
|
+
rb_define_singleton_method(rb_cQuaternion, "identity", rb_quaternion_identity, 0);
|
41
|
+
rb_define_singleton_method(rb_cQuaternion, "from_axis_angle", rb_quaternion_from_axis_angle, 2);
|
42
|
+
rb_define_singleton_method(rb_cQuaternion, "from_yaw_pitch_roll", rb_quaternion_from_yaw_pitch_roll, 3);
|
43
|
+
rb_define_singleton_method(rb_cQuaternion, "from_rotation_matrix", rb_quaternion_from_rotation_matrix, 1);
|
44
|
+
rb_define_singleton_method(rb_cQuaternion, "slerp", rb_quaternion_slerp_s, 3);
|
45
|
+
rb_define_singleton_method(rb_cQuaternion, "lerp", rb_quaternion_lerp_s, 3);
|
46
|
+
}
|
47
|
+
|
48
|
+
VALUE rb_quaternion_alloc(VALUE klass) {
|
49
|
+
Quaternion *q = ALLOC(Quaternion);
|
50
|
+
memset(q, 0, sizeof(Quaternion));
|
51
|
+
return NUMERIX_WRAP(klass, q);
|
52
|
+
}
|
53
|
+
|
54
|
+
VALUE rb_quaternion_initialize(int argc, VALUE *argv, VALUE self) {
|
55
|
+
QUATERNION();
|
56
|
+
switch (argc) {
|
57
|
+
case 0:
|
58
|
+
break;
|
59
|
+
case 2: {
|
60
|
+
Vector3 *v;
|
61
|
+
Data_Get_Struct(argv[0], Vector3, v);
|
62
|
+
q->x = v->x;
|
63
|
+
q->y = v->y;
|
64
|
+
q->z = v->z;
|
65
|
+
q->w = NUM2FLT(argv[1]);
|
66
|
+
break;
|
67
|
+
}
|
68
|
+
case 4: {
|
69
|
+
q->x = NUM2FLT(argv[0]);
|
70
|
+
q->y = NUM2FLT(argv[1]);
|
71
|
+
q->z = NUM2FLT(argv[2]);
|
72
|
+
q->w = NUM2FLT(argv[3]);
|
73
|
+
break;
|
74
|
+
}
|
75
|
+
default:
|
76
|
+
rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 0, 2, 4)", argc);
|
77
|
+
break;
|
78
|
+
}
|
79
|
+
return Qnil;
|
80
|
+
}
|
81
|
+
|
82
|
+
VALUE rb_quaternion_identity_p(VALUE self) {
|
83
|
+
QUATERNION();
|
84
|
+
return q->x == 0.0f && q->y == 0.0f && q->z == 0.0f && q->w == 1.0f ? Qtrue : Qfalse;
|
85
|
+
}
|
86
|
+
|
87
|
+
VALUE rb_quaternion_length(VALUE self) {
|
88
|
+
QUATERNION();
|
89
|
+
return DBL2NUM(sqrtf(q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w));
|
90
|
+
}
|
91
|
+
|
92
|
+
VALUE rb_quaternion_length_squared(VALUE self) {
|
93
|
+
QUATERNION();
|
94
|
+
return DBL2NUM(q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w);
|
95
|
+
}
|
96
|
+
|
97
|
+
VALUE rb_quaternion_negate(VALUE self) {
|
98
|
+
QUATERNION();
|
99
|
+
Quaternion *result = ALLOC(Quaternion);
|
100
|
+
|
101
|
+
result->x = -q->x;
|
102
|
+
result->y = -q->y;
|
103
|
+
result->z = -q->z;
|
104
|
+
result->w = -q->w;
|
105
|
+
|
106
|
+
return NUMERIX_WRAP(CLASS_OF(self), result);
|
107
|
+
}
|
108
|
+
|
109
|
+
VALUE rb_quaternion_add(VALUE self, VALUE other) {
|
110
|
+
Quaternion *q1, *q2, *result;
|
111
|
+
Data_Get_Struct(self, Quaternion, q1);
|
112
|
+
Data_Get_Struct(other, Quaternion, q2);
|
113
|
+
result = ALLOC(Quaternion);
|
114
|
+
|
115
|
+
result->x = q1->x + q2->x;
|
116
|
+
result->y = q1->y + q2->y;
|
117
|
+
result->z = q1->z + q2->z;
|
118
|
+
result->w = q1->w + q2->w;
|
119
|
+
|
120
|
+
return NUMERIX_WRAP(CLASS_OF(self), result);
|
121
|
+
}
|
122
|
+
|
123
|
+
VALUE rb_quaternion_subtract(VALUE self, VALUE other) {
|
124
|
+
Quaternion *q1, *q2, *result;
|
125
|
+
Data_Get_Struct(self, Quaternion, q1);
|
126
|
+
Data_Get_Struct(other, Quaternion, q2);
|
127
|
+
result = ALLOC(Quaternion);
|
128
|
+
|
129
|
+
result->x = q1->x - q2->x;
|
130
|
+
result->y = q1->y - q2->y;
|
131
|
+
result->z = q1->z - q2->z;
|
132
|
+
result->w = q1->w - q2->w;
|
133
|
+
|
134
|
+
return NUMERIX_WRAP(CLASS_OF(self), result);
|
135
|
+
}
|
136
|
+
|
137
|
+
VALUE rb_quaternion_multiply(VALUE self, VALUE other) {
|
138
|
+
Quaternion *q1, *result;
|
139
|
+
Data_Get_Struct(self, Quaternion, q1);
|
140
|
+
result = ALLOC(Quaternion);
|
141
|
+
|
142
|
+
if (NUMERIX_TYPE_P(other, rb_cQuaternion)) {
|
143
|
+
Quaternion *q2;
|
144
|
+
Data_Get_Struct(other, Quaternion, q2);
|
145
|
+
|
146
|
+
float q1x = q1->x;
|
147
|
+
float q1y = q1->y;
|
148
|
+
float q1z = q1->z;
|
149
|
+
float q1w = q1->w;
|
150
|
+
|
151
|
+
float q2x = q2->x;
|
152
|
+
float q2y = q2->y;
|
153
|
+
float q2z = q2->z;
|
154
|
+
float q2w = q2->w;
|
155
|
+
|
156
|
+
// cross(av, bv)
|
157
|
+
float cx = q1y * q2z - q1z * q2y;
|
158
|
+
float cy = q1z * q2x - q1x * q2z;
|
159
|
+
float cz = q1x * q2y - q1y * q2x;
|
160
|
+
|
161
|
+
float dot = q1x * q2x + q1y * q2y + q1z * q2z;
|
162
|
+
|
163
|
+
result->x = q1x * q2w + q2x * q1w + cx;
|
164
|
+
result->y = q1y * q2w + q2y * q1w + cy;
|
165
|
+
result->z = q1z * q2w + q2z * q1w + cz;
|
166
|
+
result->w = q1w * q2w - dot;
|
167
|
+
} else {
|
168
|
+
float scalar = NUM2FLT(other);
|
169
|
+
result->x = q1->x * scalar;
|
170
|
+
result->y = q1->y * scalar;
|
171
|
+
result->z = q1->z * scalar;
|
172
|
+
result->w = q1->w * scalar;
|
173
|
+
}
|
174
|
+
|
175
|
+
return NUMERIX_WRAP(CLASS_OF(self), result);
|
176
|
+
}
|
177
|
+
|
178
|
+
VALUE rb_quaternion_divide(VALUE self, VALUE other) {
|
179
|
+
Quaternion *q1, *q2, *result;
|
180
|
+
Data_Get_Struct(self, Quaternion, q1);
|
181
|
+
Data_Get_Struct(other, Quaternion, q2);
|
182
|
+
result = ALLOC(Quaternion);
|
183
|
+
|
184
|
+
float q1x = q1->x;
|
185
|
+
float q1y = q1->y;
|
186
|
+
float q1z = q1->z;
|
187
|
+
float q1w = q1->w;
|
188
|
+
|
189
|
+
//-------------------------------------
|
190
|
+
// Inverse part.
|
191
|
+
float ls = q2->x * q2->x + q2->y * q2->y + q2->z * q2->z + q2->w * q2->w;
|
192
|
+
float invNorm = 1.0f / ls;
|
193
|
+
|
194
|
+
float q2x = -q2->x * invNorm;
|
195
|
+
float q2y = -q2->y * invNorm;
|
196
|
+
float q2z = -q2->z * invNorm;
|
197
|
+
float q2w = q2->w * invNorm;
|
198
|
+
|
199
|
+
//-------------------------------------
|
200
|
+
// Multiply part.
|
201
|
+
|
202
|
+
// cross(av, bv)
|
203
|
+
float cx = q1y * q2z - q1z * q2y;
|
204
|
+
float cy = q1z * q2x - q1x * q2z;
|
205
|
+
float cz = q1x * q2y - q1y * q2x;
|
206
|
+
|
207
|
+
float dot = q1x * q2x + q1y * q2y + q1z * q2z;
|
208
|
+
|
209
|
+
result->x = q1x * q2w + q2x * q1w + cx;
|
210
|
+
result->y = q1y * q2w + q2y * q1w + cy;
|
211
|
+
result->z = q1z * q2w + q2z * q1w + cz;
|
212
|
+
result->w = q1w * q2w - dot;
|
213
|
+
|
214
|
+
return NUMERIX_WRAP(CLASS_OF(self), result);
|
215
|
+
}
|
216
|
+
|
217
|
+
VALUE rb_quaternion_equal(VALUE self, VALUE other) {
|
218
|
+
if (CLASS_OF(other) != CLASS_OF(self))
|
219
|
+
return Qfalse;
|
220
|
+
Quaternion *q1, *q2;
|
221
|
+
Data_Get_Struct(self, Quaternion, q1);
|
222
|
+
Data_Get_Struct(other, Quaternion, q2);
|
223
|
+
return FLT_EQUAL(q1->x, q2->x) && FLT_EQUAL(q1->y, q2->y) && FLT_EQUAL(q1->z, q2->z) && FLT_EQUAL(q1->w, q2->w) ? Qtrue : Qfalse;
|
224
|
+
}
|
225
|
+
|
226
|
+
VALUE rb_quaternion_to_s(VALUE self) {
|
227
|
+
QUATERNION();
|
228
|
+
return rb_sprintf("{%f, %f, %f, %f}", q->x, q->y, q->z, q->w);
|
229
|
+
}
|
230
|
+
|
231
|
+
VALUE rb_quaternion_to_a(VALUE self) {
|
232
|
+
QUATERNION();
|
233
|
+
VALUE ary = rb_ary_new_capa(4);
|
234
|
+
rb_ary_store(ary, 0, DBL2NUM(q->x));
|
235
|
+
rb_ary_store(ary, 1, DBL2NUM(q->y));
|
236
|
+
rb_ary_store(ary, 2, DBL2NUM(q->z));
|
237
|
+
rb_ary_store(ary, 3, DBL2NUM(q->w));
|
238
|
+
return ary;
|
239
|
+
}
|
240
|
+
|
241
|
+
VALUE rb_quaternion_to_h(VALUE self) {
|
242
|
+
QUATERNION();
|
243
|
+
VALUE hash = rb_hash_new();
|
244
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("x")), DBL2NUM(q->x));
|
245
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("y")), DBL2NUM(q->y));
|
246
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("z")), DBL2NUM(q->z));
|
247
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("w")), DBL2NUM(q->w));
|
248
|
+
return hash;
|
249
|
+
}
|
250
|
+
|
251
|
+
VALUE rb_quaternion_to_vec4(VALUE self) {
|
252
|
+
QUATERNION();
|
253
|
+
Vector4 *v = ALLOC(Vector4);
|
254
|
+
memcpy(v, q, sizeof(Quaternion));
|
255
|
+
return NUMERIX_WRAP(rb_cVector4, v);
|
256
|
+
}
|
257
|
+
|
258
|
+
VALUE rb_quaternion_normalize(VALUE self) {
|
259
|
+
QUATERNION();
|
260
|
+
Quaternion *result = ALLOC(Quaternion);
|
261
|
+
|
262
|
+
float invNorm = 1.0f / sqrtf(q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w);
|
263
|
+
result->x = q->x * invNorm;
|
264
|
+
result->y = q->y * invNorm;
|
265
|
+
result->z = q->z * invNorm;
|
266
|
+
result->w = q->w * invNorm;
|
267
|
+
|
268
|
+
return NUMERIX_WRAP(CLASS_OF(self), result);
|
269
|
+
}
|
270
|
+
|
271
|
+
VALUE rb_quaternion_normalize_bang(VALUE self) {
|
272
|
+
QUATERNION();
|
273
|
+
|
274
|
+
float invNorm = 1.0f / sqrtf(q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w);
|
275
|
+
q->x = q->x * invNorm;
|
276
|
+
q->y = q->y * invNorm;
|
277
|
+
q->z = q->z * invNorm;
|
278
|
+
q->w = q->w * invNorm;
|
279
|
+
|
280
|
+
return self;
|
281
|
+
}
|
282
|
+
|
283
|
+
VALUE rb_quaternion_conjugate(VALUE self) {
|
284
|
+
QUATERNION();
|
285
|
+
Quaternion *result = ALLOC(Quaternion);
|
286
|
+
|
287
|
+
result->x = -q->x;
|
288
|
+
result->y = -q->y;
|
289
|
+
result->z = -q->z;
|
290
|
+
result->w = q->w;
|
291
|
+
|
292
|
+
return NUMERIX_WRAP(CLASS_OF(self), result);
|
293
|
+
}
|
294
|
+
|
295
|
+
VALUE rb_quaternion_conjugate_bang(VALUE self) {
|
296
|
+
QUATERNION();
|
297
|
+
|
298
|
+
q->x = -q->x;
|
299
|
+
q->y = -q->y;
|
300
|
+
q->z = -q->z;
|
301
|
+
q->w = q->w;
|
302
|
+
|
303
|
+
return self;
|
304
|
+
}
|
305
|
+
|
306
|
+
VALUE rb_quaternion_dot(VALUE self, VALUE other) {
|
307
|
+
Quaternion *q1, *q2;
|
308
|
+
Data_Get_Struct(self, Quaternion, q1);
|
309
|
+
Data_Get_Struct(other, Quaternion, q2);
|
310
|
+
|
311
|
+
return DBL2NUM(q1->x * q2->x + q1->y * q2->y + q1->z * q2->z + q1->w * q2->w);
|
312
|
+
}
|
313
|
+
|
314
|
+
VALUE rb_quaternion_identity(VALUE klass) {
|
315
|
+
Quaternion *q = ALLOC(Quaternion);
|
316
|
+
q->x = 0.0f;
|
317
|
+
q->y = 0.0f;
|
318
|
+
q->z = 0.0f;
|
319
|
+
q->w = 1.0f;
|
320
|
+
return NUMERIX_WRAP(klass, q);
|
321
|
+
}
|
322
|
+
|
323
|
+
VALUE rb_quaternion_inverse(VALUE self) {
|
324
|
+
QUATERNION();
|
325
|
+
Quaternion *result = ALLOC(Quaternion);
|
326
|
+
|
327
|
+
// -1 ( a -v )
|
328
|
+
// q = ( ------------- ------------- )
|
329
|
+
// ( a^2 + |v|^2 , a^2 + |v|^2 )
|
330
|
+
|
331
|
+
float ls = q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w;
|
332
|
+
float invNorm = 1.0f / ls;
|
333
|
+
|
334
|
+
result->x = -q->x * invNorm;
|
335
|
+
result->y = -q->y * invNorm;
|
336
|
+
result->z = -q->z * invNorm;
|
337
|
+
result->w = q->w * invNorm;
|
338
|
+
|
339
|
+
return NUMERIX_WRAP(CLASS_OF(self), result);
|
340
|
+
}
|
341
|
+
|
342
|
+
VALUE rb_quaternion_concatenate(VALUE self, VALUE other) {
|
343
|
+
Quaternion *q1, *q2, *result;
|
344
|
+
Data_Get_Struct(self, Quaternion, q1);
|
345
|
+
Data_Get_Struct(other, Quaternion, q2);
|
346
|
+
result = ALLOC(Quaternion);
|
347
|
+
|
348
|
+
// Concatenate rotation is actually q2 * q1 instead of q1 * q2.
|
349
|
+
// So that's why q2 goes q1 and q1 goes q2.
|
350
|
+
float q1x = q2->x;
|
351
|
+
float q1y = q2->y;
|
352
|
+
float q1z = q2->z;
|
353
|
+
float q1w = q2->w;
|
354
|
+
|
355
|
+
float q2x = q1->x;
|
356
|
+
float q2y = q1->y;
|
357
|
+
float q2z = q1->z;
|
358
|
+
float q2w = q1->w;
|
359
|
+
|
360
|
+
// cross(av, bv)
|
361
|
+
float cx = q1y * q2z - q1z * q2y;
|
362
|
+
float cy = q1z * q2x - q1x * q2z;
|
363
|
+
float cz = q1x * q2y - q1y * q2x;
|
364
|
+
|
365
|
+
float dot = q1x * q2x + q1y * q2y + q1z * q2z;
|
366
|
+
|
367
|
+
result->x = q1x * q2w + q2x * q1w + cx;
|
368
|
+
result->y = q1y * q2w + q2y * q1w + cy;
|
369
|
+
result->z = q1z * q2w + q2z * q1w + cz;
|
370
|
+
result->w = q1w * q2w - dot;
|
371
|
+
|
372
|
+
return NUMERIX_WRAP(CLASS_OF(self), result);
|
373
|
+
}
|
374
|
+
|
375
|
+
VALUE rb_quaternion_concatenate_bang(VALUE self, VALUE other) {
|
376
|
+
Quaternion *q1, *q2;
|
377
|
+
Data_Get_Struct(self, Quaternion, q1);
|
378
|
+
Data_Get_Struct(other, Quaternion, q2);
|
379
|
+
|
380
|
+
// Concatenate rotation is actually q2 * q1 instead of q1 * q2.
|
381
|
+
// So that's why q2 goes q1 and q1 goes q2.
|
382
|
+
float q1x = q2->x;
|
383
|
+
float q1y = q2->y;
|
384
|
+
float q1z = q2->z;
|
385
|
+
float q1w = q2->w;
|
386
|
+
|
387
|
+
float q2x = q1->x;
|
388
|
+
float q2y = q1->y;
|
389
|
+
float q2z = q1->z;
|
390
|
+
float q2w = q1->w;
|
391
|
+
|
392
|
+
// cross(av, bv)
|
393
|
+
float cx = q1y * q2z - q1z * q2y;
|
394
|
+
float cy = q1z * q2x - q1x * q2z;
|
395
|
+
float cz = q1x * q2y - q1y * q2x;
|
396
|
+
|
397
|
+
float dot = q1x * q2x + q1y * q2y + q1z * q2z;
|
398
|
+
|
399
|
+
q1->x = q1x * q2w + q2x * q1w + cx;
|
400
|
+
q1->y = q1y * q2w + q2y * q1w + cy;
|
401
|
+
q1->z = q1z * q2w + q2z * q1w + cz;
|
402
|
+
q1->w = q1w * q2w - dot;
|
403
|
+
|
404
|
+
return self;
|
405
|
+
}
|
406
|
+
|
407
|
+
VALUE rb_quaternion_lerp(VALUE self, VALUE other, VALUE amount) {
|
408
|
+
Quaternion *q1, *q2, *result;
|
409
|
+
Data_Get_Struct(self, Quaternion, q1);
|
410
|
+
Data_Get_Struct(other, Quaternion, q2);
|
411
|
+
result = ALLOC(Quaternion);
|
412
|
+
|
413
|
+
float t = amount;
|
414
|
+
float t1 = 1.0f - t;
|
415
|
+
float dot = q1->x * q2->x + q1->y * q2->y + q1->z * q2->z + q1->w * q2->w;
|
416
|
+
|
417
|
+
if (dot >= 0.0f) {
|
418
|
+
result->x = t1 * q1->x + t * q2->x;
|
419
|
+
result->y = t1 * q1->y + t * q2->y;
|
420
|
+
result->z = t1 * q1->z + t * q2->z;
|
421
|
+
result->w = t1 * q1->w + t * q2->w;
|
422
|
+
} else {
|
423
|
+
result->x = t1 * q1->x - t * q2->x;
|
424
|
+
result->y = t1 * q1->y - t * q2->y;
|
425
|
+
result->z = t1 * q1->z - t * q2->z;
|
426
|
+
result->w = t1 * q1->w - t * q2->w;
|
427
|
+
}
|
428
|
+
|
429
|
+
// Normalize it.
|
430
|
+
float ls = result->x * result->x + result->y * result->y + result->z * result->z + result->w * result->w;
|
431
|
+
float invNorm = 1.0f / sqrtf(ls);
|
432
|
+
|
433
|
+
result->x *= invNorm;
|
434
|
+
result->y *= invNorm;
|
435
|
+
result->z *= invNorm;
|
436
|
+
result->w *= invNorm;
|
437
|
+
|
438
|
+
return NUMERIX_WRAP(CLASS_OF(self), result);
|
439
|
+
}
|
440
|
+
|
441
|
+
VALUE rb_quaternion_lerp_bang(VALUE self, VALUE other, VALUE amount) {
|
442
|
+
Quaternion *q1, *q2;
|
443
|
+
Data_Get_Struct(self, Quaternion, q1);
|
444
|
+
Data_Get_Struct(other, Quaternion, q2);
|
445
|
+
|
446
|
+
float t = amount;
|
447
|
+
float t1 = 1.0f - t;
|
448
|
+
float dot = q1->x * q2->x + q1->y * q2->y + q1->z * q2->z + q1->w * q2->w;
|
449
|
+
|
450
|
+
if (dot >= 0.0f) {
|
451
|
+
q1->x = t1 * q1->x + t * q2->x;
|
452
|
+
q1->y = t1 * q1->y + t * q2->y;
|
453
|
+
q1->z = t1 * q1->z + t * q2->z;
|
454
|
+
q1->w = t1 * q1->w + t * q2->w;
|
455
|
+
} else {
|
456
|
+
q1->x = t1 * q1->x - t * q2->x;
|
457
|
+
q1->y = t1 * q1->y - t * q2->y;
|
458
|
+
q1->z = t1 * q1->z - t * q2->z;
|
459
|
+
q1->w = t1 * q1->w - t * q2->w;
|
460
|
+
}
|
461
|
+
|
462
|
+
// Normalize it.
|
463
|
+
float ls = q1->x * q1->x + q1->y * q1->y + q1->z * q1->z + q1->w * q1->w;
|
464
|
+
float invNorm = 1.0f / sqrtf(ls);
|
465
|
+
|
466
|
+
q1->x *= invNorm;
|
467
|
+
q1->y *= invNorm;
|
468
|
+
q1->z *= invNorm;
|
469
|
+
q1->w *= invNorm;
|
470
|
+
|
471
|
+
return self;
|
472
|
+
}
|
473
|
+
|
474
|
+
VALUE rb_quaternion_slerp(VALUE self, VALUE other, VALUE amount) {
|
475
|
+
Quaternion *q1, *q2, *result;
|
476
|
+
Data_Get_Struct(self, Quaternion, q1);
|
477
|
+
Data_Get_Struct(other, Quaternion, q2);
|
478
|
+
|
479
|
+
const float epsilon = 1e-6f;
|
480
|
+
|
481
|
+
float t = amount;
|
482
|
+
float cosOmega = q1->x * q2->x + q1->y * q2->y + q1->z * q2->z + q1->w * q2->w;
|
483
|
+
int flip = 0;
|
484
|
+
float s1, s2;
|
485
|
+
|
486
|
+
if (cosOmega < 0.0f) {
|
487
|
+
flip = 1;
|
488
|
+
cosOmega = -cosOmega;
|
489
|
+
}
|
490
|
+
|
491
|
+
if (cosOmega > (1.0f - epsilon)) {
|
492
|
+
// Too close, do straight linear interpolation.
|
493
|
+
s1 = 1.0f - t;
|
494
|
+
s2 = (flip) ? -t : t;
|
495
|
+
} else {
|
496
|
+
float omega = acosf(cosOmega);
|
497
|
+
float invSinOmega = 1.0f / sinf(omega);
|
498
|
+
|
499
|
+
s1 = sinf((1.0f - t) * omega) * invSinOmega;
|
500
|
+
s2 = (flip)
|
501
|
+
? -sinf(t * omega) * invSinOmega
|
502
|
+
: sinf(t * omega) * invSinOmega;
|
503
|
+
}
|
504
|
+
|
505
|
+
result = ALLOC(Quaternion);
|
506
|
+
result->x = s1 * q1->x + s2 * q2->x;
|
507
|
+
result->y = s1 * q1->y + s2 * q2->y;
|
508
|
+
result->z = s1 * q1->z + s2 * q2->z;
|
509
|
+
result->w = s1 * q1->w + s2 * q2->w;
|
510
|
+
|
511
|
+
return NUMERIX_WRAP(CLASS_OF(self), result);
|
512
|
+
}
|
513
|
+
|
514
|
+
VALUE rb_quaternion_slerp_bang(VALUE self, VALUE other, VALUE amount) {
|
515
|
+
Quaternion *q1, *q2;
|
516
|
+
Data_Get_Struct(self, Quaternion, q1);
|
517
|
+
Data_Get_Struct(other, Quaternion, q2);
|
518
|
+
|
519
|
+
const float epsilon = 1e-6f;
|
520
|
+
|
521
|
+
float t = amount;
|
522
|
+
float cosOmega = q1->x * q2->x + q1->y * q2->y + q1->z * q2->z + q1->w * q2->w;
|
523
|
+
int flip = 0;
|
524
|
+
float s1, s2;
|
525
|
+
|
526
|
+
if (cosOmega < 0.0f) {
|
527
|
+
flip = 1;
|
528
|
+
cosOmega = -cosOmega;
|
529
|
+
}
|
530
|
+
|
531
|
+
if (cosOmega > (1.0f - epsilon)) {
|
532
|
+
// Too close, do straight linear interpolation.
|
533
|
+
s1 = 1.0f - t;
|
534
|
+
s2 = (flip) ? -t : t;
|
535
|
+
} else {
|
536
|
+
float omega = acosf(cosOmega);
|
537
|
+
float invSinOmega = 1.0f / sinf(omega);
|
538
|
+
|
539
|
+
s1 = sinf((1.0f - t) * omega) * invSinOmega;
|
540
|
+
s2 = (flip)
|
541
|
+
? -sinf(t * omega) * invSinOmega
|
542
|
+
: sinf(t * omega) * invSinOmega;
|
543
|
+
}
|
544
|
+
|
545
|
+
q1->x = s1 * q1->x + s2 * q2->x;
|
546
|
+
q1->y = s1 * q1->y + s2 * q2->y;
|
547
|
+
q1->z = s1 * q1->z + s2 * q2->z;
|
548
|
+
q1->w = s1 * q1->w + s2 * q2->w;
|
549
|
+
|
550
|
+
return self;
|
551
|
+
}
|
552
|
+
|
553
|
+
VALUE rb_quaternion_from_axis_angle(VALUE klass, VALUE vec3, VALUE angle) {
|
554
|
+
Vector3 *axis;
|
555
|
+
Data_Get_Struct(vec3, Vector3, axis);
|
556
|
+
Quaternion *result = ALLOC(Quaternion);
|
557
|
+
|
558
|
+
float half = NUM2FLT(angle) * 0.5f;
|
559
|
+
float s = sinf(half);
|
560
|
+
|
561
|
+
result->x = axis->x * s;
|
562
|
+
result->y = axis->y * s;
|
563
|
+
result->z = axis->z * s;
|
564
|
+
result->w = cosf(half);
|
565
|
+
|
566
|
+
return NUMERIX_WRAP(klass, result);
|
567
|
+
}
|
568
|
+
|
569
|
+
VALUE rb_quaternion_from_yaw_pitch_roll(VALUE klass, VALUE yaw, VALUE pitch, VALUE roll) {
|
570
|
+
// Roll first, about axis the object is facing, then
|
571
|
+
// pitch upward, then yaw to face into the new heading
|
572
|
+
|
573
|
+
float sr, cr, sp, cp, sy, cy;
|
574
|
+
|
575
|
+
float halfRoll = roll * 0.5f;
|
576
|
+
sr = sinf(halfRoll);
|
577
|
+
cr = cosf(halfRoll);
|
578
|
+
|
579
|
+
float halfPitch = pitch * 0.5f;
|
580
|
+
sp = sinf(halfPitch);
|
581
|
+
cp = cosf(halfPitch);
|
582
|
+
|
583
|
+
float halfYaw = yaw * 0.5f;
|
584
|
+
sy = sinf(halfYaw);
|
585
|
+
cy = cosf(halfYaw);
|
586
|
+
|
587
|
+
Quaternion *result = ALLOC(Quaternion);
|
588
|
+
|
589
|
+
result->x = cy * sp * cr + sy * cp * sr;
|
590
|
+
result->y = sy * cp * cr - cy * sp * sr;
|
591
|
+
result->z = cy * cp * sr - sy * sp * cr;
|
592
|
+
result->w = cy * cp * cr + sy * sp * sr;
|
593
|
+
|
594
|
+
return NUMERIX_WRAP(klass, result);
|
595
|
+
}
|
596
|
+
|
597
|
+
VALUE rb_quaternion_from_rotation_matrix(VALUE klass, VALUE matrix) {
|
598
|
+
Matrix4x4 *m;
|
599
|
+
Data_Get_Struct(matrix, Matrix4x4, m);
|
600
|
+
Quaternion *q = ALLOC(Quaternion);
|
601
|
+
|
602
|
+
float trace = m->m11 + m->m22 + m->m33;
|
603
|
+
float s;
|
604
|
+
if (trace > 0.0f) {
|
605
|
+
s = sqrtf(trace + 1.0f);
|
606
|
+
q->w = s * 0.5f;
|
607
|
+
s = 0.5f / s;
|
608
|
+
q->x = (m->m23 - m->m32) * s;
|
609
|
+
q->y = (m->m31 - m->m13) * s;
|
610
|
+
q->z = (m->m12 - m->m21) * s;
|
611
|
+
} else {
|
612
|
+
float invS;
|
613
|
+
if (m->m11 >= m->m22 && m->m11 >= m->m33) {
|
614
|
+
s = sqrtf(1.0f + m->m11 - m->m22 - m->m33);
|
615
|
+
invS = 0.5f / s;
|
616
|
+
q->x = 0.5f * s;
|
617
|
+
q->y = (m->m12 + m->m21) * invS;
|
618
|
+
q->z = (m->m13 + m->m31) * invS;
|
619
|
+
q->w = (m->m23 - m->m32) * invS;
|
620
|
+
} else if (m->m22 > m->m33) {
|
621
|
+
s = sqrtf(1.0f + m->m22 - m->m11 - m->m33);
|
622
|
+
invS = 0.5f / s;
|
623
|
+
q->x = (m->m21 + m->m12) * invS;
|
624
|
+
q->y = 0.5f * s;
|
625
|
+
q->z = (m->m32 + m->m23) * invS;
|
626
|
+
q->w = (m->m31 - m->m13) * invS;
|
627
|
+
} else {
|
628
|
+
s = sqrtf(1.0f + m->m33 - m->m11 - m->m22);
|
629
|
+
invS = 0.5f / s;
|
630
|
+
q->x = (m->m31 + m->m13) * invS;
|
631
|
+
q->y = (m->m32 + m->m23) * invS;
|
632
|
+
q->z = 0.5f * s;
|
633
|
+
q->w = (m->m12 - m->m21) * invS;
|
634
|
+
}
|
635
|
+
}
|
636
|
+
|
637
|
+
return NUMERIX_WRAP(klass, q);
|
638
|
+
}
|
639
|
+
|
640
|
+
static inline VALUE rb_quaternion_slerp_s(VALUE klass, VALUE quaternion1, VALUE quaternion2, VALUE amount) {
|
641
|
+
Quaternion *q1, *q2, *result;
|
642
|
+
Data_Get_Struct(quaternion1, Quaternion, q1);
|
643
|
+
Data_Get_Struct(quaternion2, Quaternion, q2);
|
644
|
+
|
645
|
+
const float epsilon = 1e-6f;
|
646
|
+
|
647
|
+
float t = amount;
|
648
|
+
float cosOmega = q1->x * q2->x + q1->y * q2->y + q1->z * q2->z + q1->w * q2->w;
|
649
|
+
int flip = 0;
|
650
|
+
float s1, s2;
|
651
|
+
|
652
|
+
if (cosOmega < 0.0f) {
|
653
|
+
flip = 1;
|
654
|
+
cosOmega = -cosOmega;
|
655
|
+
}
|
656
|
+
|
657
|
+
if (cosOmega > (1.0f - epsilon)) {
|
658
|
+
// Too close, do straight linear interpolation.
|
659
|
+
s1 = 1.0f - t;
|
660
|
+
s2 = (flip) ? -t : t;
|
661
|
+
} else {
|
662
|
+
float omega = acosf(cosOmega);
|
663
|
+
float invSinOmega = 1.0f / sinf(omega);
|
664
|
+
|
665
|
+
s1 = sinf((1.0f - t) * omega) * invSinOmega;
|
666
|
+
s2 = (flip)
|
667
|
+
? -sinf(t * omega) * invSinOmega
|
668
|
+
: sinf(t * omega) * invSinOmega;
|
669
|
+
}
|
670
|
+
|
671
|
+
result = ALLOC(Quaternion);
|
672
|
+
result->x = s1 * q1->x + s2 * q2->x;
|
673
|
+
result->y = s1 * q1->y + s2 * q2->y;
|
674
|
+
result->z = s1 * q1->z + s2 * q2->z;
|
675
|
+
result->w = s1 * q1->w + s2 * q2->w;
|
676
|
+
|
677
|
+
return NUMERIX_WRAP(klass, result);
|
678
|
+
}
|
679
|
+
|
680
|
+
static inline VALUE rb_quaternion_lerp_s(VALUE klass, VALUE quaternion1, VALUE quaternion2, VALUE amount) {
|
681
|
+
Quaternion *q1, *q2, *result;
|
682
|
+
Data_Get_Struct(quaternion1, Quaternion, q1);
|
683
|
+
Data_Get_Struct(quaternion2, Quaternion, q2);
|
684
|
+
result = ALLOC(Quaternion);
|
685
|
+
|
686
|
+
float t = amount;
|
687
|
+
float t1 = 1.0f - t;
|
688
|
+
float dot = q1->x * q2->x + q1->y * q2->y + q1->z * q2->z + q1->w * q2->w;
|
689
|
+
|
690
|
+
if (dot >= 0.0f) {
|
691
|
+
result->x = t1 * q1->x + t * q2->x;
|
692
|
+
result->y = t1 * q1->y + t * q2->y;
|
693
|
+
result->z = t1 * q1->z + t * q2->z;
|
694
|
+
result->w = t1 * q1->w + t * q2->w;
|
695
|
+
} else {
|
696
|
+
result->x = t1 * q1->x - t * q2->x;
|
697
|
+
result->y = t1 * q1->y - t * q2->y;
|
698
|
+
result->z = t1 * q1->z - t * q2->z;
|
699
|
+
result->w = t1 * q1->w - t * q2->w;
|
700
|
+
}
|
701
|
+
|
702
|
+
// Normalize it.
|
703
|
+
float ls = result->x * result->x + result->y * result->y + result->z * result->z + result->w * result->w;
|
704
|
+
float invNorm = 1.0f / sqrtf(ls);
|
705
|
+
|
706
|
+
result->x *= invNorm;
|
707
|
+
result->y *= invNorm;
|
708
|
+
result->z *= invNorm;
|
709
|
+
result->w *= invNorm;
|
710
|
+
|
711
|
+
return NUMERIX_WRAP(klass, result);
|
712
|
+
}
|