larb 1.0.0 → 1.0.1
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 +4 -4
- data/CHANGELOG.md +9 -1
- data/README.md +49 -0
- data/ext/larb/color.c +85 -82
- data/ext/larb/extconf.rb +1 -1
- data/ext/larb/larb.h +23 -0
- data/ext/larb/mat2.c +50 -47
- data/ext/larb/mat2d.c +84 -67
- data/ext/larb/mat3.c +73 -87
- data/ext/larb/mat4.c +180 -200
- data/ext/larb/matrix_utils.h +97 -0
- data/ext/larb/quat.c +110 -66
- data/ext/larb/quat2.c +123 -85
- data/ext/larb/vec2.c +52 -29
- data/ext/larb/vec3.c +106 -71
- data/ext/larb/vec4.c +55 -34
- data/lib/larb/version.rb +1 -1
- data/test/larb/color_test.rb +21 -0
- data/test/larb/mat2d_test.rb +25 -0
- data/test/larb/mat4_test.rb +77 -0
- data/test/larb/matrix_test.rb +135 -0
- data/test/larb/native_value_test.rb +157 -0
- data/test/larb/quat2_test.rb +93 -0
- data/test/larb/quat_test.rb +60 -0
- data/test/larb/vec2_test.rb +23 -0
- data/test/larb/vec3_test.rb +63 -0
- data/test/larb/vec4_test.rb +8 -1
- metadata +8 -5
data/ext/larb/mat2d.c
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#include "mat2d.h"
|
|
2
|
+
#include "matrix_utils.h"
|
|
2
3
|
|
|
3
4
|
#include <math.h>
|
|
4
5
|
|
|
@@ -22,11 +23,6 @@ static VALUE cMat2d = Qnil;
|
|
|
22
23
|
static VALUE cVec2 = Qnil;
|
|
23
24
|
static VALUE cMat3 = Qnil;
|
|
24
25
|
|
|
25
|
-
static double value_to_double(VALUE value) {
|
|
26
|
-
VALUE coerced = rb_funcall(value, rb_intern("to_f"), 0);
|
|
27
|
-
return NUM2DBL(coerced);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
26
|
static Mat2dData *mat2d_get(VALUE obj) {
|
|
31
27
|
Mat2dData *data = NULL;
|
|
32
28
|
TypedData_Get_Struct(obj, Mat2dData, &mat2d_type, data);
|
|
@@ -60,29 +56,31 @@ VALUE mat2d_alloc(VALUE klass) {
|
|
|
60
56
|
}
|
|
61
57
|
|
|
62
58
|
VALUE mat2d_initialize(int argc, VALUE *argv, VALUE self) {
|
|
59
|
+
rb_check_frozen(self);
|
|
63
60
|
VALUE data_arg = Qnil;
|
|
64
|
-
Mat2dData
|
|
65
|
-
|
|
61
|
+
Mat2dData values = {{1.0, 0.0, 0.0, 1.0, 0.0, 0.0}};
|
|
66
62
|
rb_scan_args(argc, argv, "01", &data_arg);
|
|
67
|
-
if (
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if (NIL_P(ary)) {
|
|
79
|
-
rb_raise(rb_eTypeError, "expected Array");
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
for (int i = 0; i < 6; i++) {
|
|
83
|
-
data->data[i] = value_to_double(rb_ary_entry(ary, i));
|
|
63
|
+
if (argc != 0) {
|
|
64
|
+
VALUE ary = rb_check_array_type(data_arg);
|
|
65
|
+
if (NIL_P(ary)) {
|
|
66
|
+
rb_raise(rb_eTypeError, "expected Array");
|
|
67
|
+
}
|
|
68
|
+
if (RARRAY_LEN(ary) != 6) {
|
|
69
|
+
rb_raise(rb_eArgError, "expected 6 elements");
|
|
70
|
+
}
|
|
71
|
+
for (int i = 0; i < 6; i++) {
|
|
72
|
+
values.data[i] = NUM2DBL(rb_ary_entry(ary, i));
|
|
73
|
+
}
|
|
84
74
|
}
|
|
75
|
+
rb_check_frozen(self);
|
|
76
|
+
*mat2d_get(self) = values;
|
|
77
|
+
return self;
|
|
78
|
+
}
|
|
85
79
|
|
|
80
|
+
static VALUE mat2d_initialize_copy(VALUE self, VALUE other) {
|
|
81
|
+
if (self == other) return self;
|
|
82
|
+
rb_obj_init_copy(self, other);
|
|
83
|
+
*mat2d_get(self) = *mat2d_get(other);
|
|
86
84
|
return self;
|
|
87
85
|
}
|
|
88
86
|
|
|
@@ -95,33 +93,33 @@ static VALUE mat2d_class_zero(VALUE klass) {
|
|
|
95
93
|
}
|
|
96
94
|
|
|
97
95
|
static VALUE mat2d_class_translation(VALUE klass, VALUE x, VALUE y) {
|
|
98
|
-
return mat2d_build6(klass, 1.0, 0.0, 0.0, 1.0,
|
|
99
|
-
|
|
96
|
+
return mat2d_build6(klass, 1.0, 0.0, 0.0, 1.0, NUM2DBL(x),
|
|
97
|
+
NUM2DBL(y));
|
|
100
98
|
}
|
|
101
99
|
|
|
102
100
|
static VALUE mat2d_class_rotation(VALUE klass, VALUE radians) {
|
|
103
|
-
double r =
|
|
101
|
+
double r = NUM2DBL(radians);
|
|
104
102
|
double c = cos(r);
|
|
105
103
|
double s = sin(r);
|
|
106
104
|
return mat2d_build6(klass, c, s, -s, c, 0.0, 0.0);
|
|
107
105
|
}
|
|
108
106
|
|
|
109
107
|
static VALUE mat2d_class_scaling(VALUE klass, VALUE x, VALUE y) {
|
|
110
|
-
return mat2d_build6(klass,
|
|
111
|
-
|
|
108
|
+
return mat2d_build6(klass, NUM2DBL(x), 0.0, 0.0,
|
|
109
|
+
NUM2DBL(y), 0.0, 0.0);
|
|
112
110
|
}
|
|
113
111
|
|
|
114
112
|
static VALUE mat2d_class_from_rotation_translation_scale(VALUE klass,
|
|
115
113
|
VALUE rotation,
|
|
116
114
|
VALUE translation,
|
|
117
115
|
VALUE scale) {
|
|
118
|
-
double r =
|
|
116
|
+
double r = NUM2DBL(rotation);
|
|
119
117
|
double c = cos(r);
|
|
120
118
|
double s = sin(r);
|
|
121
|
-
double sx =
|
|
122
|
-
double sy =
|
|
123
|
-
double tx =
|
|
124
|
-
double ty =
|
|
119
|
+
double sx = NUM2DBL(rb_funcall(scale, rb_intern("x"), 0));
|
|
120
|
+
double sy = NUM2DBL(rb_funcall(scale, rb_intern("y"), 0));
|
|
121
|
+
double tx = NUM2DBL(rb_funcall(translation, rb_intern("x"), 0));
|
|
122
|
+
double ty = NUM2DBL(rb_funcall(translation, rb_intern("y"), 0));
|
|
125
123
|
|
|
126
124
|
return mat2d_build6(klass, c * sx, s * sx, -s * sy, c * sy, tx, ty);
|
|
127
125
|
}
|
|
@@ -136,12 +134,15 @@ VALUE mat2d_aref(VALUE self, VALUE index) {
|
|
|
136
134
|
}
|
|
137
135
|
|
|
138
136
|
VALUE mat2d_aset(VALUE self, VALUE index, VALUE value) {
|
|
137
|
+
rb_check_frozen(self);
|
|
139
138
|
Mat2dData *data = mat2d_get(self);
|
|
140
139
|
long idx = NUM2LONG(index);
|
|
141
140
|
if (idx < 0 || idx > 5) {
|
|
142
141
|
rb_raise(rb_eIndexError, "index %ld out of range", idx);
|
|
143
142
|
}
|
|
144
|
-
|
|
143
|
+
double component = NUM2DBL(value);
|
|
144
|
+
rb_check_frozen(self);
|
|
145
|
+
data->data[idx] = component;
|
|
145
146
|
return value;
|
|
146
147
|
}
|
|
147
148
|
|
|
@@ -161,8 +162,8 @@ VALUE mat2d_mul(VALUE self, VALUE other) {
|
|
|
161
162
|
}
|
|
162
163
|
|
|
163
164
|
if (rb_obj_is_kind_of(other, cVec2)) {
|
|
164
|
-
double x =
|
|
165
|
-
double y =
|
|
165
|
+
double x = NUM2DBL(rb_funcall(other, rb_intern("x"), 0));
|
|
166
|
+
double y = NUM2DBL(rb_funcall(other, rb_intern("y"), 0));
|
|
166
167
|
VALUE vec2_class = rb_const_get(mLarb, rb_intern("Vec2"));
|
|
167
168
|
return rb_funcall(vec2_class, rb_intern("new"), 2,
|
|
168
169
|
DBL2NUM(a->data[0] * x + a->data[2] * y + a->data[4]),
|
|
@@ -170,13 +171,13 @@ VALUE mat2d_mul(VALUE self, VALUE other) {
|
|
|
170
171
|
}
|
|
171
172
|
|
|
172
173
|
if (rb_obj_is_kind_of(other, rb_cNumeric)) {
|
|
173
|
-
double s =
|
|
174
|
+
double s = NUM2DBL(other);
|
|
174
175
|
return mat2d_build6(rb_obj_class(self), a->data[0] * s, a->data[1] * s,
|
|
175
176
|
a->data[2] * s, a->data[3] * s, a->data[4] * s,
|
|
176
177
|
a->data[5] * s);
|
|
177
178
|
}
|
|
178
179
|
|
|
179
|
-
|
|
180
|
+
rb_raise(rb_eTypeError, "unsupported operand for Mat2d multiplication");
|
|
180
181
|
}
|
|
181
182
|
|
|
182
183
|
VALUE mat2d_add(VALUE self, VALUE other) {
|
|
@@ -203,25 +204,18 @@ VALUE mat2d_determinant(VALUE self) {
|
|
|
203
204
|
}
|
|
204
205
|
|
|
205
206
|
VALUE mat2d_inverse(VALUE self) {
|
|
206
|
-
|
|
207
|
-
double
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
return mat2d_build6(rb_obj_class(self), a->data[3] * inv_det,
|
|
213
|
-
-a->data[1] * inv_det, -a->data[2] * inv_det,
|
|
214
|
-
a->data[0] * inv_det,
|
|
215
|
-
(a->data[2] * a->data[5] - a->data[3] * a->data[4]) *
|
|
216
|
-
inv_det,
|
|
217
|
-
(a->data[1] * a->data[4] - a->data[0] * a->data[5]) *
|
|
218
|
-
inv_det);
|
|
207
|
+
const double *a = mat2d_get(self)->data;
|
|
208
|
+
double values[9] = {a[0], a[1], 0.0, a[2], a[3], 0.0, a[4], a[5], 1.0};
|
|
209
|
+
double inverse[9];
|
|
210
|
+
larb_matrix_inverse(values, inverse, 3);
|
|
211
|
+
return mat2d_build6(rb_obj_class(self), inverse[0], inverse[1], inverse[3],
|
|
212
|
+
inverse[4], inverse[6], inverse[7]);
|
|
219
213
|
}
|
|
220
214
|
|
|
221
215
|
VALUE mat2d_translate(VALUE self, VALUE x, VALUE y) {
|
|
222
216
|
Mat2dData *a = mat2d_get(self);
|
|
223
|
-
double dx =
|
|
224
|
-
double dy =
|
|
217
|
+
double dx = NUM2DBL(x);
|
|
218
|
+
double dy = NUM2DBL(y);
|
|
225
219
|
return mat2d_build6(rb_obj_class(self), a->data[0], a->data[1], a->data[2],
|
|
226
220
|
a->data[3], a->data[0] * dx + a->data[2] * dy + a->data[4],
|
|
227
221
|
a->data[1] * dx + a->data[3] * dy + a->data[5]);
|
|
@@ -234,8 +228,8 @@ VALUE mat2d_rotate(VALUE self, VALUE radians) {
|
|
|
234
228
|
|
|
235
229
|
VALUE mat2d_scale(VALUE self, VALUE x, VALUE y) {
|
|
236
230
|
Mat2dData *a = mat2d_get(self);
|
|
237
|
-
double sx =
|
|
238
|
-
double sy =
|
|
231
|
+
double sx = NUM2DBL(x);
|
|
232
|
+
double sy = NUM2DBL(y);
|
|
239
233
|
return mat2d_build6(rb_obj_class(self), a->data[0] * sx, a->data[1] * sx,
|
|
240
234
|
a->data[2] * sy, a->data[3] * sy, a->data[4], a->data[5]);
|
|
241
235
|
}
|
|
@@ -247,26 +241,45 @@ VALUE mat2d_extract_translation(VALUE self) {
|
|
|
247
241
|
DBL2NUM(a->data[5]));
|
|
248
242
|
}
|
|
249
243
|
|
|
244
|
+
static void mat2d_decompose(const Mat2dData *a, double *sx, double *sy) {
|
|
245
|
+
for (int i = 0; i < 6; i++) {
|
|
246
|
+
if (!isfinite(a->data[i])) {
|
|
247
|
+
rb_raise(rb_eArgError, "Cannot decompose non-finite components");
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
*sx = hypot(a->data[0], a->data[1]);
|
|
251
|
+
*sy = hypot(a->data[2], a->data[3]);
|
|
252
|
+
if (*sx == 0.0 || *sy == 0.0 || !isfinite(*sx) || !isfinite(*sy)) {
|
|
253
|
+
rb_raise(rb_eArgError, "Cannot decompose zero or non-finite scale");
|
|
254
|
+
}
|
|
255
|
+
double x0 = a->data[0] / *sx, y0 = a->data[1] / *sx;
|
|
256
|
+
double x1 = a->data[2] / *sy, y1 = a->data[3] / *sy;
|
|
257
|
+
if (fabs(x0 * x1 + y0 * y1) > 1e-6) {
|
|
258
|
+
rb_raise(rb_eArgError, "Cannot decompose shear");
|
|
259
|
+
}
|
|
260
|
+
if (x0 * y1 - y0 * x1 < 0.0) *sx = -*sx;
|
|
261
|
+
}
|
|
262
|
+
|
|
250
263
|
VALUE mat2d_extract_rotation(VALUE self) {
|
|
251
264
|
Mat2dData *a = mat2d_get(self);
|
|
252
|
-
|
|
265
|
+
double sx, sy;
|
|
266
|
+
mat2d_decompose(a, &sx, &sy);
|
|
267
|
+
return DBL2NUM(atan2(a->data[1] / sx, a->data[0] / sx));
|
|
253
268
|
}
|
|
254
269
|
|
|
255
270
|
VALUE mat2d_extract_scale(VALUE self) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
VALUE vec2_class = rb_const_get(mLarb, rb_intern("Vec2"));
|
|
260
|
-
return rb_funcall(vec2_class, rb_intern("new"), 2, DBL2NUM(sx), DBL2NUM(sy));
|
|
271
|
+
double sx, sy;
|
|
272
|
+
mat2d_decompose(mat2d_get(self), &sx, &sy);
|
|
273
|
+
return rb_funcall(cVec2, rb_intern("new"), 2, DBL2NUM(sx), DBL2NUM(sy));
|
|
261
274
|
}
|
|
262
275
|
|
|
263
276
|
VALUE mat2d_frobenius_norm(VALUE self) {
|
|
264
277
|
Mat2dData *a = mat2d_get(self);
|
|
265
|
-
double
|
|
278
|
+
double norm = 0.0;
|
|
266
279
|
for (int i = 0; i < 6; i++) {
|
|
267
|
-
|
|
280
|
+
norm = hypot(norm, a->data[i]);
|
|
268
281
|
}
|
|
269
|
-
return DBL2NUM(
|
|
282
|
+
return DBL2NUM(norm);
|
|
270
283
|
}
|
|
271
284
|
|
|
272
285
|
VALUE mat2d_to_mat3(VALUE self) {
|
|
@@ -314,10 +327,13 @@ VALUE mat2d_near(int argc, VALUE *argv, VALUE self) {
|
|
|
314
327
|
rb_scan_args(argc, argv, "11", &other, &epsilon);
|
|
315
328
|
Mat2dData *a = mat2d_get(self);
|
|
316
329
|
Mat2dData *b = mat2d_get(other);
|
|
317
|
-
double eps =
|
|
330
|
+
double eps = argc < 2 ? 1e-6 : NUM2DBL(epsilon);
|
|
331
|
+
if (!isfinite(eps) || eps <= 0.0) {
|
|
332
|
+
rb_raise(rb_eArgError, "epsilon must be finite and positive");
|
|
333
|
+
}
|
|
318
334
|
|
|
319
335
|
for (int i = 0; i < 6; i++) {
|
|
320
|
-
if (fabs(a->data[i] - b->data[i])
|
|
336
|
+
if (!(fabs(a->data[i] - b->data[i]) < eps)) {
|
|
321
337
|
return Qfalse;
|
|
322
338
|
}
|
|
323
339
|
}
|
|
@@ -346,6 +362,7 @@ void Init_mat2d(VALUE module) {
|
|
|
346
362
|
|
|
347
363
|
rb_define_alloc_func(cMat2d, mat2d_alloc);
|
|
348
364
|
rb_define_method(cMat2d, "initialize", mat2d_initialize, -1);
|
|
365
|
+
rb_define_method(cMat2d, "initialize_copy", mat2d_initialize_copy, 1);
|
|
349
366
|
|
|
350
367
|
rb_define_singleton_method(cMat2d, "identity", mat2d_class_identity, 0);
|
|
351
368
|
rb_define_singleton_method(cMat2d, "zero", mat2d_class_zero, 0);
|
data/ext/larb/mat3.c
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#include "mat3.h"
|
|
2
|
+
#include "matrix_utils.h"
|
|
2
3
|
|
|
3
4
|
#include <math.h>
|
|
4
5
|
|
|
@@ -21,11 +22,6 @@ static const rb_data_type_t mat3_type = {
|
|
|
21
22
|
static VALUE cMat3 = Qnil;
|
|
22
23
|
static VALUE cVec3 = Qnil;
|
|
23
24
|
|
|
24
|
-
static double value_to_double(VALUE value) {
|
|
25
|
-
VALUE coerced = rb_funcall(value, rb_intern("to_f"), 0);
|
|
26
|
-
return NUM2DBL(coerced);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
25
|
static Mat3Data *mat3_get(VALUE obj) {
|
|
30
26
|
Mat3Data *data = NULL;
|
|
31
27
|
TypedData_Get_Struct(obj, Mat3Data, &mat3_type, data);
|
|
@@ -63,32 +59,31 @@ VALUE mat3_alloc(VALUE klass) {
|
|
|
63
59
|
}
|
|
64
60
|
|
|
65
61
|
VALUE mat3_initialize(int argc, VALUE *argv, VALUE self) {
|
|
62
|
+
rb_check_frozen(self);
|
|
66
63
|
VALUE data_arg = Qnil;
|
|
67
|
-
Mat3Data
|
|
68
|
-
|
|
64
|
+
Mat3Data values = {{1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}};
|
|
69
65
|
rb_scan_args(argc, argv, "01", &data_arg);
|
|
70
|
-
if (
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
VALUE ary = rb_check_array_type(data_arg);
|
|
84
|
-
if (NIL_P(ary)) {
|
|
85
|
-
rb_raise(rb_eTypeError, "expected Array");
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
for (int i = 0; i < 9; i++) {
|
|
89
|
-
data->data[i] = value_to_double(rb_ary_entry(ary, i));
|
|
66
|
+
if (argc != 0) {
|
|
67
|
+
VALUE ary = rb_check_array_type(data_arg);
|
|
68
|
+
if (NIL_P(ary)) {
|
|
69
|
+
rb_raise(rb_eTypeError, "expected Array");
|
|
70
|
+
}
|
|
71
|
+
if (RARRAY_LEN(ary) != 9) {
|
|
72
|
+
rb_raise(rb_eArgError, "expected 9 elements");
|
|
73
|
+
}
|
|
74
|
+
for (int i = 0; i < 9; i++) {
|
|
75
|
+
values.data[i] = NUM2DBL(rb_ary_entry(ary, i));
|
|
76
|
+
}
|
|
90
77
|
}
|
|
78
|
+
rb_check_frozen(self);
|
|
79
|
+
*mat3_get(self) = values;
|
|
80
|
+
return self;
|
|
81
|
+
}
|
|
91
82
|
|
|
83
|
+
static VALUE mat3_initialize_copy(VALUE self, VALUE other) {
|
|
84
|
+
if (self == other) return self;
|
|
85
|
+
rb_obj_init_copy(self, other);
|
|
86
|
+
*mat3_get(self) = *mat3_get(other);
|
|
92
87
|
return self;
|
|
93
88
|
}
|
|
94
89
|
|
|
@@ -102,37 +97,37 @@ static VALUE mat3_class_zero(VALUE klass) {
|
|
|
102
97
|
|
|
103
98
|
static VALUE mat3_class_from_mat4(VALUE klass, VALUE mat4) {
|
|
104
99
|
double values[9];
|
|
105
|
-
values[0] =
|
|
106
|
-
values[1] =
|
|
107
|
-
values[2] =
|
|
108
|
-
values[3] =
|
|
109
|
-
values[4] =
|
|
110
|
-
values[5] =
|
|
111
|
-
values[6] =
|
|
112
|
-
values[7] =
|
|
113
|
-
values[8] =
|
|
100
|
+
values[0] = NUM2DBL(rb_funcall(mat4, rb_intern("[]"), 1, INT2NUM(0)));
|
|
101
|
+
values[1] = NUM2DBL(rb_funcall(mat4, rb_intern("[]"), 1, INT2NUM(1)));
|
|
102
|
+
values[2] = NUM2DBL(rb_funcall(mat4, rb_intern("[]"), 1, INT2NUM(2)));
|
|
103
|
+
values[3] = NUM2DBL(rb_funcall(mat4, rb_intern("[]"), 1, INT2NUM(4)));
|
|
104
|
+
values[4] = NUM2DBL(rb_funcall(mat4, rb_intern("[]"), 1, INT2NUM(5)));
|
|
105
|
+
values[5] = NUM2DBL(rb_funcall(mat4, rb_intern("[]"), 1, INT2NUM(6)));
|
|
106
|
+
values[6] = NUM2DBL(rb_funcall(mat4, rb_intern("[]"), 1, INT2NUM(8)));
|
|
107
|
+
values[7] = NUM2DBL(rb_funcall(mat4, rb_intern("[]"), 1, INT2NUM(9)));
|
|
108
|
+
values[8] = NUM2DBL(rb_funcall(mat4, rb_intern("[]"), 1, INT2NUM(10)));
|
|
114
109
|
return mat3_build(klass, values);
|
|
115
110
|
}
|
|
116
111
|
|
|
117
112
|
static VALUE mat3_class_from_mat2d(VALUE klass, VALUE mat2d) {
|
|
118
113
|
double values[9];
|
|
119
|
-
values[0] =
|
|
120
|
-
values[1] =
|
|
114
|
+
values[0] = NUM2DBL(rb_funcall(mat2d, rb_intern("[]"), 1, INT2NUM(0)));
|
|
115
|
+
values[1] = NUM2DBL(rb_funcall(mat2d, rb_intern("[]"), 1, INT2NUM(1)));
|
|
121
116
|
values[2] = 0.0;
|
|
122
|
-
values[3] =
|
|
123
|
-
values[4] =
|
|
117
|
+
values[3] = NUM2DBL(rb_funcall(mat2d, rb_intern("[]"), 1, INT2NUM(2)));
|
|
118
|
+
values[4] = NUM2DBL(rb_funcall(mat2d, rb_intern("[]"), 1, INT2NUM(3)));
|
|
124
119
|
values[5] = 0.0;
|
|
125
|
-
values[6] =
|
|
126
|
-
values[7] =
|
|
120
|
+
values[6] = NUM2DBL(rb_funcall(mat2d, rb_intern("[]"), 1, INT2NUM(4)));
|
|
121
|
+
values[7] = NUM2DBL(rb_funcall(mat2d, rb_intern("[]"), 1, INT2NUM(5)));
|
|
127
122
|
values[8] = 1.0;
|
|
128
123
|
return mat3_build(klass, values);
|
|
129
124
|
}
|
|
130
125
|
|
|
131
126
|
static VALUE mat3_class_from_quaternion(VALUE klass, VALUE quat) {
|
|
132
|
-
double x =
|
|
133
|
-
double y =
|
|
134
|
-
double z =
|
|
135
|
-
double w =
|
|
127
|
+
double x = NUM2DBL(rb_funcall(quat, rb_intern("x"), 0));
|
|
128
|
+
double y = NUM2DBL(rb_funcall(quat, rb_intern("y"), 0));
|
|
129
|
+
double z = NUM2DBL(rb_funcall(quat, rb_intern("z"), 0));
|
|
130
|
+
double w = NUM2DBL(rb_funcall(quat, rb_intern("w"), 0));
|
|
136
131
|
double x2 = x + x;
|
|
137
132
|
double y2 = y + y;
|
|
138
133
|
double z2 = z + z;
|
|
@@ -158,27 +153,27 @@ static VALUE mat3_class_normal_from_mat4(VALUE klass, VALUE mat4) {
|
|
|
158
153
|
}
|
|
159
154
|
|
|
160
155
|
static VALUE mat3_class_projection(VALUE klass, VALUE width, VALUE height) {
|
|
161
|
-
double w =
|
|
162
|
-
double h =
|
|
156
|
+
double w = NUM2DBL(width);
|
|
157
|
+
double h = NUM2DBL(height);
|
|
163
158
|
return mat3_build9(klass, 2.0 / w, 0.0, 0.0, 0.0, -2.0 / h, 0.0, -1.0, 1.0,
|
|
164
159
|
1.0);
|
|
165
160
|
}
|
|
166
161
|
|
|
167
162
|
static VALUE mat3_class_translation(VALUE klass, VALUE x, VALUE y) {
|
|
168
|
-
return mat3_build9(klass, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0,
|
|
169
|
-
|
|
163
|
+
return mat3_build9(klass, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, NUM2DBL(x),
|
|
164
|
+
NUM2DBL(y), 1.0);
|
|
170
165
|
}
|
|
171
166
|
|
|
172
167
|
static VALUE mat3_class_rotation(VALUE klass, VALUE radians) {
|
|
173
|
-
double r =
|
|
168
|
+
double r = NUM2DBL(radians);
|
|
174
169
|
double c = cos(r);
|
|
175
170
|
double s = sin(r);
|
|
176
171
|
return mat3_build9(klass, c, s, 0.0, -s, c, 0.0, 0.0, 0.0, 1.0);
|
|
177
172
|
}
|
|
178
173
|
|
|
179
174
|
static VALUE mat3_class_scaling(VALUE klass, VALUE x, VALUE y) {
|
|
180
|
-
return mat3_build9(klass,
|
|
181
|
-
|
|
175
|
+
return mat3_build9(klass, NUM2DBL(x), 0.0, 0.0, 0.0,
|
|
176
|
+
NUM2DBL(y), 0.0, 0.0, 0.0, 1.0);
|
|
182
177
|
}
|
|
183
178
|
|
|
184
179
|
VALUE mat3_aref(VALUE self, VALUE index) {
|
|
@@ -191,12 +186,15 @@ VALUE mat3_aref(VALUE self, VALUE index) {
|
|
|
191
186
|
}
|
|
192
187
|
|
|
193
188
|
VALUE mat3_aset(VALUE self, VALUE index, VALUE value) {
|
|
189
|
+
rb_check_frozen(self);
|
|
194
190
|
Mat3Data *data = mat3_get(self);
|
|
195
191
|
long idx = NUM2LONG(index);
|
|
196
192
|
if (idx < 0 || idx > 8) {
|
|
197
193
|
rb_raise(rb_eIndexError, "index %ld out of range", idx);
|
|
198
194
|
}
|
|
199
|
-
|
|
195
|
+
double component = NUM2DBL(value);
|
|
196
|
+
rb_check_frozen(self);
|
|
197
|
+
data->data[idx] = component;
|
|
200
198
|
return value;
|
|
201
199
|
}
|
|
202
200
|
|
|
@@ -228,9 +226,9 @@ VALUE mat3_mul(VALUE self, VALUE other) {
|
|
|
228
226
|
}
|
|
229
227
|
|
|
230
228
|
if (rb_obj_is_kind_of(other, cVec3)) {
|
|
231
|
-
double x =
|
|
232
|
-
double y =
|
|
233
|
-
double z =
|
|
229
|
+
double x = NUM2DBL(rb_funcall(other, rb_intern("x"), 0));
|
|
230
|
+
double y = NUM2DBL(rb_funcall(other, rb_intern("y"), 0));
|
|
231
|
+
double z = NUM2DBL(rb_funcall(other, rb_intern("z"), 0));
|
|
234
232
|
VALUE vec3_class = rb_const_get(mLarb, rb_intern("Vec3"));
|
|
235
233
|
return rb_funcall(vec3_class, rb_intern("new"), 3,
|
|
236
234
|
DBL2NUM(a->data[0] * x + a->data[3] * y +
|
|
@@ -242,14 +240,14 @@ VALUE mat3_mul(VALUE self, VALUE other) {
|
|
|
242
240
|
}
|
|
243
241
|
|
|
244
242
|
if (rb_obj_is_kind_of(other, rb_cNumeric)) {
|
|
245
|
-
double s =
|
|
243
|
+
double s = NUM2DBL(other);
|
|
246
244
|
return mat3_build9(rb_obj_class(self), a->data[0] * s, a->data[1] * s,
|
|
247
245
|
a->data[2] * s, a->data[3] * s, a->data[4] * s,
|
|
248
246
|
a->data[5] * s, a->data[6] * s, a->data[7] * s,
|
|
249
247
|
a->data[8] * s);
|
|
250
248
|
}
|
|
251
249
|
|
|
252
|
-
|
|
250
|
+
rb_raise(rb_eTypeError, "unsupported operand for Mat3 multiplication");
|
|
253
251
|
}
|
|
254
252
|
|
|
255
253
|
VALUE mat3_add(VALUE self, VALUE other) {
|
|
@@ -281,25 +279,9 @@ VALUE mat3_determinant(VALUE self) {
|
|
|
281
279
|
}
|
|
282
280
|
|
|
283
281
|
VALUE mat3_inverse(VALUE self) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
a->data[6] * (a->data[1] * a->data[5] - a->data[2] * a->data[4]);
|
|
288
|
-
if (fabs(det) < 1e-10) {
|
|
289
|
-
rb_raise(rb_eRuntimeError, "Matrix is not invertible");
|
|
290
|
-
}
|
|
291
|
-
double inv_det = 1.0 / det;
|
|
292
|
-
return mat3_build9(
|
|
293
|
-
rb_obj_class(self),
|
|
294
|
-
(a->data[4] * a->data[8] - a->data[5] * a->data[7]) * inv_det,
|
|
295
|
-
(a->data[2] * a->data[7] - a->data[1] * a->data[8]) * inv_det,
|
|
296
|
-
(a->data[1] * a->data[5] - a->data[2] * a->data[4]) * inv_det,
|
|
297
|
-
(a->data[5] * a->data[6] - a->data[3] * a->data[8]) * inv_det,
|
|
298
|
-
(a->data[0] * a->data[8] - a->data[2] * a->data[6]) * inv_det,
|
|
299
|
-
(a->data[2] * a->data[3] - a->data[0] * a->data[5]) * inv_det,
|
|
300
|
-
(a->data[3] * a->data[7] - a->data[4] * a->data[6]) * inv_det,
|
|
301
|
-
(a->data[1] * a->data[6] - a->data[0] * a->data[7]) * inv_det,
|
|
302
|
-
(a->data[0] * a->data[4] - a->data[1] * a->data[3]) * inv_det);
|
|
282
|
+
double inverse[9];
|
|
283
|
+
larb_matrix_inverse(mat3_get(self)->data, inverse, 3);
|
|
284
|
+
return mat3_build(rb_obj_class(self), inverse);
|
|
303
285
|
}
|
|
304
286
|
|
|
305
287
|
VALUE mat3_transpose(VALUE self) {
|
|
@@ -325,17 +307,17 @@ VALUE mat3_adjoint(VALUE self) {
|
|
|
325
307
|
|
|
326
308
|
VALUE mat3_frobenius_norm(VALUE self) {
|
|
327
309
|
Mat3Data *a = mat3_get(self);
|
|
328
|
-
double
|
|
310
|
+
double norm = 0.0;
|
|
329
311
|
for (int i = 0; i < 9; i++) {
|
|
330
|
-
|
|
312
|
+
norm = hypot(norm, a->data[i]);
|
|
331
313
|
}
|
|
332
|
-
return DBL2NUM(
|
|
314
|
+
return DBL2NUM(norm);
|
|
333
315
|
}
|
|
334
316
|
|
|
335
317
|
VALUE mat3_translate(VALUE self, VALUE x, VALUE y) {
|
|
336
318
|
Mat3Data *a = mat3_get(self);
|
|
337
|
-
double dx =
|
|
338
|
-
double dy =
|
|
319
|
+
double dx = NUM2DBL(x);
|
|
320
|
+
double dy = NUM2DBL(y);
|
|
339
321
|
return mat3_build9(rb_obj_class(self), a->data[0], a->data[1], a->data[2],
|
|
340
322
|
a->data[3], a->data[4], a->data[5],
|
|
341
323
|
dx * a->data[0] + dy * a->data[3] + a->data[6],
|
|
@@ -350,8 +332,8 @@ VALUE mat3_rotate(VALUE self, VALUE radians) {
|
|
|
350
332
|
|
|
351
333
|
VALUE mat3_scale(VALUE self, VALUE x, VALUE y) {
|
|
352
334
|
Mat3Data *a = mat3_get(self);
|
|
353
|
-
double sx =
|
|
354
|
-
double sy =
|
|
335
|
+
double sx = NUM2DBL(x);
|
|
336
|
+
double sy = NUM2DBL(y);
|
|
355
337
|
return mat3_build9(rb_obj_class(self), a->data[0] * sx, a->data[1] * sx,
|
|
356
338
|
a->data[2] * sx, a->data[3] * sy, a->data[4] * sy,
|
|
357
339
|
a->data[5] * sy, a->data[6], a->data[7], a->data[8]);
|
|
@@ -391,10 +373,13 @@ VALUE mat3_near(int argc, VALUE *argv, VALUE self) {
|
|
|
391
373
|
rb_scan_args(argc, argv, "11", &other, &epsilon);
|
|
392
374
|
Mat3Data *a = mat3_get(self);
|
|
393
375
|
Mat3Data *b = mat3_get(other);
|
|
394
|
-
double eps =
|
|
376
|
+
double eps = argc < 2 ? 1e-6 : NUM2DBL(epsilon);
|
|
377
|
+
if (!isfinite(eps) || eps <= 0.0) {
|
|
378
|
+
rb_raise(rb_eArgError, "epsilon must be finite and positive");
|
|
379
|
+
}
|
|
395
380
|
|
|
396
381
|
for (int i = 0; i < 9; i++) {
|
|
397
|
-
if (fabs(a->data[i] - b->data[i])
|
|
382
|
+
if (!(fabs(a->data[i] - b->data[i]) < eps)) {
|
|
398
383
|
return Qfalse;
|
|
399
384
|
}
|
|
400
385
|
}
|
|
@@ -433,6 +418,7 @@ void Init_mat3(VALUE module) {
|
|
|
433
418
|
|
|
434
419
|
rb_define_alloc_func(cMat3, mat3_alloc);
|
|
435
420
|
rb_define_method(cMat3, "initialize", mat3_initialize, -1);
|
|
421
|
+
rb_define_method(cMat3, "initialize_copy", mat3_initialize_copy, 1);
|
|
436
422
|
|
|
437
423
|
rb_define_singleton_method(cMat3, "identity", mat3_class_identity, 0);
|
|
438
424
|
rb_define_singleton_method(cMat3, "zero", mat3_class_zero, 0);
|