larb 0.1.0 → 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 +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +14 -1
- data/ext/larb/color.c +446 -0
- data/ext/larb/color.h +35 -0
- data/ext/larb/extconf.rb +11 -0
- data/ext/larb/larb.c +27 -0
- data/ext/larb/larb.h +8 -0
- data/ext/larb/mat2.c +300 -0
- data/ext/larb/mat2.h +30 -0
- data/ext/larb/mat2d.c +380 -0
- data/ext/larb/mat2d.h +35 -0
- data/ext/larb/mat3.c +469 -0
- data/ext/larb/mat3.h +33 -0
- data/ext/larb/mat4.c +671 -0
- data/ext/larb/mat4.h +31 -0
- data/ext/larb/quat.c +523 -0
- data/ext/larb/quat.h +39 -0
- data/ext/larb/quat2.c +473 -0
- data/ext/larb/quat2.h +39 -0
- data/ext/larb/vec2.c +342 -0
- data/ext/larb/vec2.h +43 -0
- data/ext/larb/vec3.c +503 -0
- data/ext/larb/vec3.h +52 -0
- data/ext/larb/vec4.c +340 -0
- data/ext/larb/vec4.h +38 -0
- data/lib/larb/version.rb +5 -0
- data/lib/larb.rb +2 -14
- data/test/larb/color_test.rb +278 -0
- data/test/larb/mat2_test.rb +144 -0
- data/test/larb/mat2d_test.rb +172 -0
- data/test/larb/mat3_test.rb +147 -0
- data/test/larb/mat4_test.rb +270 -0
- data/test/larb/quat2_test.rb +161 -0
- data/test/larb/quat_test.rb +224 -0
- data/test/larb/vec2_test.rb +251 -0
- data/test/larb/vec3_test.rb +310 -0
- data/test/larb/vec4_test.rb +189 -0
- data/test/test_helper.rb +4 -0
- metadata +53 -14
- data/Rakefile +0 -11
- data/lib/larb/color.rb +0 -148
- data/lib/larb/mat2.rb +0 -119
- data/lib/larb/mat2d.rb +0 -180
- data/lib/larb/mat3.rb +0 -238
- data/lib/larb/mat4.rb +0 -329
- data/lib/larb/quat.rb +0 -238
- data/lib/larb/quat2.rb +0 -193
- data/lib/larb/vec2.rb +0 -150
- data/lib/larb/vec3.rb +0 -218
- data/lib/larb/vec4.rb +0 -125
data/ext/larb/mat2d.h
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#ifndef MAT2D_H
|
|
2
|
+
#define MAT2D_H
|
|
3
|
+
|
|
4
|
+
#include "larb.h"
|
|
5
|
+
|
|
6
|
+
typedef struct {
|
|
7
|
+
double data[6];
|
|
8
|
+
} Mat2dData;
|
|
9
|
+
|
|
10
|
+
void Init_mat2d(VALUE module);
|
|
11
|
+
VALUE mat2d_alloc(VALUE klass);
|
|
12
|
+
VALUE mat2d_initialize(int argc, VALUE *argv, VALUE self);
|
|
13
|
+
|
|
14
|
+
VALUE mat2d_aref(VALUE self, VALUE index);
|
|
15
|
+
VALUE mat2d_aset(VALUE self, VALUE index, VALUE value);
|
|
16
|
+
VALUE mat2d_mul(VALUE self, VALUE other);
|
|
17
|
+
VALUE mat2d_add(VALUE self, VALUE other);
|
|
18
|
+
VALUE mat2d_sub(VALUE self, VALUE other);
|
|
19
|
+
VALUE mat2d_determinant(VALUE self);
|
|
20
|
+
VALUE mat2d_inverse(VALUE self);
|
|
21
|
+
VALUE mat2d_translate(VALUE self, VALUE x, VALUE y);
|
|
22
|
+
VALUE mat2d_rotate(VALUE self, VALUE radians);
|
|
23
|
+
VALUE mat2d_scale(VALUE self, VALUE x, VALUE y);
|
|
24
|
+
VALUE mat2d_extract_translation(VALUE self);
|
|
25
|
+
VALUE mat2d_extract_rotation(VALUE self);
|
|
26
|
+
VALUE mat2d_extract_scale(VALUE self);
|
|
27
|
+
VALUE mat2d_frobenius_norm(VALUE self);
|
|
28
|
+
VALUE mat2d_to_mat3(VALUE self);
|
|
29
|
+
VALUE mat2d_to_a(VALUE self);
|
|
30
|
+
VALUE mat2d_equal(VALUE self, VALUE other);
|
|
31
|
+
VALUE mat2d_near(int argc, VALUE *argv, VALUE self);
|
|
32
|
+
VALUE mat2d_inspect(VALUE self);
|
|
33
|
+
VALUE mat2d_data(VALUE self);
|
|
34
|
+
|
|
35
|
+
#endif
|
data/ext/larb/mat3.c
ADDED
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
#include "mat3.h"
|
|
2
|
+
|
|
3
|
+
#include <math.h>
|
|
4
|
+
|
|
5
|
+
static void mat3_free(void *ptr) {
|
|
6
|
+
xfree(ptr);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
static size_t mat3_memsize(const void *ptr) {
|
|
10
|
+
return sizeof(Mat3Data);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static const rb_data_type_t mat3_type = {
|
|
14
|
+
"Mat3",
|
|
15
|
+
{0, mat3_free, mat3_memsize},
|
|
16
|
+
0,
|
|
17
|
+
0,
|
|
18
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
static VALUE cMat3 = Qnil;
|
|
22
|
+
static VALUE cVec3 = Qnil;
|
|
23
|
+
|
|
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
|
+
static Mat3Data *mat3_get(VALUE obj) {
|
|
30
|
+
Mat3Data *data = NULL;
|
|
31
|
+
TypedData_Get_Struct(obj, Mat3Data, &mat3_type, data);
|
|
32
|
+
return data;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static VALUE mat3_build(VALUE klass, const double *values) {
|
|
36
|
+
VALUE obj = mat3_alloc(klass);
|
|
37
|
+
Mat3Data *data = mat3_get(obj);
|
|
38
|
+
for (int i = 0; i < 9; i++) {
|
|
39
|
+
data->data[i] = values[i];
|
|
40
|
+
}
|
|
41
|
+
return obj;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static VALUE mat3_build9(VALUE klass, double v0, double v1, double v2,
|
|
45
|
+
double v3, double v4, double v5, double v6,
|
|
46
|
+
double v7, double v8) {
|
|
47
|
+
double values[9] = {v0, v1, v2, v3, v4, v5, v6, v7, v8};
|
|
48
|
+
return mat3_build(klass, values);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
VALUE mat3_alloc(VALUE klass) {
|
|
52
|
+
Mat3Data *data = ALLOC(Mat3Data);
|
|
53
|
+
data->data[0] = 1.0;
|
|
54
|
+
data->data[1] = 0.0;
|
|
55
|
+
data->data[2] = 0.0;
|
|
56
|
+
data->data[3] = 0.0;
|
|
57
|
+
data->data[4] = 1.0;
|
|
58
|
+
data->data[5] = 0.0;
|
|
59
|
+
data->data[6] = 0.0;
|
|
60
|
+
data->data[7] = 0.0;
|
|
61
|
+
data->data[8] = 1.0;
|
|
62
|
+
return TypedData_Wrap_Struct(klass, &mat3_type, data);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
VALUE mat3_initialize(int argc, VALUE *argv, VALUE self) {
|
|
66
|
+
VALUE data_arg = Qnil;
|
|
67
|
+
Mat3Data *data = mat3_get(self);
|
|
68
|
+
|
|
69
|
+
rb_scan_args(argc, argv, "01", &data_arg);
|
|
70
|
+
if (NIL_P(data_arg)) {
|
|
71
|
+
data->data[0] = 1.0;
|
|
72
|
+
data->data[1] = 0.0;
|
|
73
|
+
data->data[2] = 0.0;
|
|
74
|
+
data->data[3] = 0.0;
|
|
75
|
+
data->data[4] = 1.0;
|
|
76
|
+
data->data[5] = 0.0;
|
|
77
|
+
data->data[6] = 0.0;
|
|
78
|
+
data->data[7] = 0.0;
|
|
79
|
+
data->data[8] = 1.0;
|
|
80
|
+
return self;
|
|
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));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return self;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
static VALUE mat3_class_identity(VALUE klass) {
|
|
96
|
+
return mat3_alloc(klass);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
static VALUE mat3_class_zero(VALUE klass) {
|
|
100
|
+
return mat3_build9(klass, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
static VALUE mat3_class_from_mat4(VALUE klass, VALUE mat4) {
|
|
104
|
+
double values[9];
|
|
105
|
+
values[0] = value_to_double(rb_funcall(mat4, rb_intern("[]"), 1, INT2NUM(0)));
|
|
106
|
+
values[1] = value_to_double(rb_funcall(mat4, rb_intern("[]"), 1, INT2NUM(1)));
|
|
107
|
+
values[2] = value_to_double(rb_funcall(mat4, rb_intern("[]"), 1, INT2NUM(2)));
|
|
108
|
+
values[3] = value_to_double(rb_funcall(mat4, rb_intern("[]"), 1, INT2NUM(4)));
|
|
109
|
+
values[4] = value_to_double(rb_funcall(mat4, rb_intern("[]"), 1, INT2NUM(5)));
|
|
110
|
+
values[5] = value_to_double(rb_funcall(mat4, rb_intern("[]"), 1, INT2NUM(6)));
|
|
111
|
+
values[6] = value_to_double(rb_funcall(mat4, rb_intern("[]"), 1, INT2NUM(8)));
|
|
112
|
+
values[7] = value_to_double(rb_funcall(mat4, rb_intern("[]"), 1, INT2NUM(9)));
|
|
113
|
+
values[8] = value_to_double(rb_funcall(mat4, rb_intern("[]"), 1, INT2NUM(10)));
|
|
114
|
+
return mat3_build(klass, values);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
static VALUE mat3_class_from_mat2d(VALUE klass, VALUE mat2d) {
|
|
118
|
+
double values[9];
|
|
119
|
+
values[0] = value_to_double(rb_funcall(mat2d, rb_intern("[]"), 1, INT2NUM(0)));
|
|
120
|
+
values[1] = value_to_double(rb_funcall(mat2d, rb_intern("[]"), 1, INT2NUM(1)));
|
|
121
|
+
values[2] = 0.0;
|
|
122
|
+
values[3] = value_to_double(rb_funcall(mat2d, rb_intern("[]"), 1, INT2NUM(2)));
|
|
123
|
+
values[4] = value_to_double(rb_funcall(mat2d, rb_intern("[]"), 1, INT2NUM(3)));
|
|
124
|
+
values[5] = 0.0;
|
|
125
|
+
values[6] = value_to_double(rb_funcall(mat2d, rb_intern("[]"), 1, INT2NUM(4)));
|
|
126
|
+
values[7] = value_to_double(rb_funcall(mat2d, rb_intern("[]"), 1, INT2NUM(5)));
|
|
127
|
+
values[8] = 1.0;
|
|
128
|
+
return mat3_build(klass, values);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
static VALUE mat3_class_from_quaternion(VALUE klass, VALUE quat) {
|
|
132
|
+
double x = value_to_double(rb_funcall(quat, rb_intern("x"), 0));
|
|
133
|
+
double y = value_to_double(rb_funcall(quat, rb_intern("y"), 0));
|
|
134
|
+
double z = value_to_double(rb_funcall(quat, rb_intern("z"), 0));
|
|
135
|
+
double w = value_to_double(rb_funcall(quat, rb_intern("w"), 0));
|
|
136
|
+
double x2 = x + x;
|
|
137
|
+
double y2 = y + y;
|
|
138
|
+
double z2 = z + z;
|
|
139
|
+
double xx = x * x2;
|
|
140
|
+
double yx = y * x2;
|
|
141
|
+
double yy = y * y2;
|
|
142
|
+
double zx = z * x2;
|
|
143
|
+
double zy = z * y2;
|
|
144
|
+
double zz = z * z2;
|
|
145
|
+
double wx = w * x2;
|
|
146
|
+
double wy = w * y2;
|
|
147
|
+
double wz = w * z2;
|
|
148
|
+
|
|
149
|
+
return mat3_build9(klass, 1 - yy - zz, yx + wz, zx - wy, yx - wz,
|
|
150
|
+
1 - xx - zz, zy + wx, zx + wy, zy - wx,
|
|
151
|
+
1 - xx - yy);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
static VALUE mat3_class_normal_from_mat4(VALUE klass, VALUE mat4) {
|
|
155
|
+
VALUE m3 = mat3_class_from_mat4(klass, mat4);
|
|
156
|
+
VALUE inv = rb_funcall(m3, rb_intern("inverse"), 0);
|
|
157
|
+
return rb_funcall(inv, rb_intern("transpose"), 0);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
static VALUE mat3_class_projection(VALUE klass, VALUE width, VALUE height) {
|
|
161
|
+
double w = value_to_double(width);
|
|
162
|
+
double h = value_to_double(height);
|
|
163
|
+
return mat3_build9(klass, 2.0 / w, 0.0, 0.0, 0.0, -2.0 / h, 0.0, -1.0, 1.0,
|
|
164
|
+
1.0);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
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, value_to_double(x),
|
|
169
|
+
value_to_double(y), 1.0);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
static VALUE mat3_class_rotation(VALUE klass, VALUE radians) {
|
|
173
|
+
double r = value_to_double(radians);
|
|
174
|
+
double c = cos(r);
|
|
175
|
+
double s = sin(r);
|
|
176
|
+
return mat3_build9(klass, c, s, 0.0, -s, c, 0.0, 0.0, 0.0, 1.0);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
static VALUE mat3_class_scaling(VALUE klass, VALUE x, VALUE y) {
|
|
180
|
+
return mat3_build9(klass, value_to_double(x), 0.0, 0.0, 0.0,
|
|
181
|
+
value_to_double(y), 0.0, 0.0, 0.0, 1.0);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
VALUE mat3_aref(VALUE self, VALUE index) {
|
|
185
|
+
Mat3Data *data = mat3_get(self);
|
|
186
|
+
long idx = NUM2LONG(index);
|
|
187
|
+
if (idx < 0 || idx > 8) {
|
|
188
|
+
return Qnil;
|
|
189
|
+
}
|
|
190
|
+
return DBL2NUM(data->data[idx]);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
VALUE mat3_aset(VALUE self, VALUE index, VALUE value) {
|
|
194
|
+
Mat3Data *data = mat3_get(self);
|
|
195
|
+
long idx = NUM2LONG(index);
|
|
196
|
+
if (idx < 0 || idx > 8) {
|
|
197
|
+
rb_raise(rb_eIndexError, "index %ld out of range", idx);
|
|
198
|
+
}
|
|
199
|
+
data->data[idx] = value_to_double(value);
|
|
200
|
+
return value;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
VALUE mat3_mul(VALUE self, VALUE other) {
|
|
204
|
+
Mat3Data *a = mat3_get(self);
|
|
205
|
+
|
|
206
|
+
if (rb_obj_is_kind_of(other, cMat3)) {
|
|
207
|
+
Mat3Data *b = mat3_get(other);
|
|
208
|
+
return mat3_build9(
|
|
209
|
+
rb_obj_class(self),
|
|
210
|
+
a->data[0] * b->data[0] + a->data[3] * b->data[1] +
|
|
211
|
+
a->data[6] * b->data[2],
|
|
212
|
+
a->data[1] * b->data[0] + a->data[4] * b->data[1] +
|
|
213
|
+
a->data[7] * b->data[2],
|
|
214
|
+
a->data[2] * b->data[0] + a->data[5] * b->data[1] +
|
|
215
|
+
a->data[8] * b->data[2],
|
|
216
|
+
a->data[0] * b->data[3] + a->data[3] * b->data[4] +
|
|
217
|
+
a->data[6] * b->data[5],
|
|
218
|
+
a->data[1] * b->data[3] + a->data[4] * b->data[4] +
|
|
219
|
+
a->data[7] * b->data[5],
|
|
220
|
+
a->data[2] * b->data[3] + a->data[5] * b->data[4] +
|
|
221
|
+
a->data[8] * b->data[5],
|
|
222
|
+
a->data[0] * b->data[6] + a->data[3] * b->data[7] +
|
|
223
|
+
a->data[6] * b->data[8],
|
|
224
|
+
a->data[1] * b->data[6] + a->data[4] * b->data[7] +
|
|
225
|
+
a->data[7] * b->data[8],
|
|
226
|
+
a->data[2] * b->data[6] + a->data[5] * b->data[7] +
|
|
227
|
+
a->data[8] * b->data[8]);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (rb_obj_is_kind_of(other, cVec3)) {
|
|
231
|
+
double x = value_to_double(rb_funcall(other, rb_intern("x"), 0));
|
|
232
|
+
double y = value_to_double(rb_funcall(other, rb_intern("y"), 0));
|
|
233
|
+
double z = value_to_double(rb_funcall(other, rb_intern("z"), 0));
|
|
234
|
+
VALUE vec3_class = rb_const_get(mLarb, rb_intern("Vec3"));
|
|
235
|
+
return rb_funcall(vec3_class, rb_intern("new"), 3,
|
|
236
|
+
DBL2NUM(a->data[0] * x + a->data[3] * y +
|
|
237
|
+
a->data[6] * z),
|
|
238
|
+
DBL2NUM(a->data[1] * x + a->data[4] * y +
|
|
239
|
+
a->data[7] * z),
|
|
240
|
+
DBL2NUM(a->data[2] * x + a->data[5] * y +
|
|
241
|
+
a->data[8] * z));
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (rb_obj_is_kind_of(other, rb_cNumeric)) {
|
|
245
|
+
double s = value_to_double(other);
|
|
246
|
+
return mat3_build9(rb_obj_class(self), a->data[0] * s, a->data[1] * s,
|
|
247
|
+
a->data[2] * s, a->data[3] * s, a->data[4] * s,
|
|
248
|
+
a->data[5] * s, a->data[6] * s, a->data[7] * s,
|
|
249
|
+
a->data[8] * s);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return Qnil;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
VALUE mat3_add(VALUE self, VALUE other) {
|
|
256
|
+
Mat3Data *a = mat3_get(self);
|
|
257
|
+
Mat3Data *b = mat3_get(other);
|
|
258
|
+
return mat3_build9(rb_obj_class(self), a->data[0] + b->data[0],
|
|
259
|
+
a->data[1] + b->data[1], a->data[2] + b->data[2],
|
|
260
|
+
a->data[3] + b->data[3], a->data[4] + b->data[4],
|
|
261
|
+
a->data[5] + b->data[5], a->data[6] + b->data[6],
|
|
262
|
+
a->data[7] + b->data[7], a->data[8] + b->data[8]);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
VALUE mat3_sub(VALUE self, VALUE other) {
|
|
266
|
+
Mat3Data *a = mat3_get(self);
|
|
267
|
+
Mat3Data *b = mat3_get(other);
|
|
268
|
+
return mat3_build9(rb_obj_class(self), a->data[0] - b->data[0],
|
|
269
|
+
a->data[1] - b->data[1], a->data[2] - b->data[2],
|
|
270
|
+
a->data[3] - b->data[3], a->data[4] - b->data[4],
|
|
271
|
+
a->data[5] - b->data[5], a->data[6] - b->data[6],
|
|
272
|
+
a->data[7] - b->data[7], a->data[8] - b->data[8]);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
VALUE mat3_determinant(VALUE self) {
|
|
276
|
+
Mat3Data *a = mat3_get(self);
|
|
277
|
+
double det = a->data[0] * (a->data[4] * a->data[8] - a->data[5] * a->data[7]) -
|
|
278
|
+
a->data[3] * (a->data[1] * a->data[8] - a->data[2] * a->data[7]) +
|
|
279
|
+
a->data[6] * (a->data[1] * a->data[5] - a->data[2] * a->data[4]);
|
|
280
|
+
return DBL2NUM(det);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
VALUE mat3_inverse(VALUE self) {
|
|
284
|
+
Mat3Data *a = mat3_get(self);
|
|
285
|
+
double det = a->data[0] * (a->data[4] * a->data[8] - a->data[5] * a->data[7]) -
|
|
286
|
+
a->data[3] * (a->data[1] * a->data[8] - a->data[2] * a->data[7]) +
|
|
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);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
VALUE mat3_transpose(VALUE self) {
|
|
306
|
+
Mat3Data *a = mat3_get(self);
|
|
307
|
+
return mat3_build9(rb_obj_class(self), a->data[0], a->data[3], a->data[6],
|
|
308
|
+
a->data[1], a->data[4], a->data[7], a->data[2],
|
|
309
|
+
a->data[5], a->data[8]);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
VALUE mat3_adjoint(VALUE self) {
|
|
313
|
+
Mat3Data *a = mat3_get(self);
|
|
314
|
+
return mat3_build9(
|
|
315
|
+
rb_obj_class(self), a->data[4] * a->data[8] - a->data[5] * a->data[7],
|
|
316
|
+
a->data[2] * a->data[7] - a->data[1] * a->data[8],
|
|
317
|
+
a->data[1] * a->data[5] - a->data[2] * a->data[4],
|
|
318
|
+
a->data[5] * a->data[6] - a->data[3] * a->data[8],
|
|
319
|
+
a->data[0] * a->data[8] - a->data[2] * a->data[6],
|
|
320
|
+
a->data[2] * a->data[3] - a->data[0] * a->data[5],
|
|
321
|
+
a->data[3] * a->data[7] - a->data[4] * a->data[6],
|
|
322
|
+
a->data[1] * a->data[6] - a->data[0] * a->data[7],
|
|
323
|
+
a->data[0] * a->data[4] - a->data[1] * a->data[3]);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
VALUE mat3_frobenius_norm(VALUE self) {
|
|
327
|
+
Mat3Data *a = mat3_get(self);
|
|
328
|
+
double sum = 0.0;
|
|
329
|
+
for (int i = 0; i < 9; i++) {
|
|
330
|
+
sum += a->data[i] * a->data[i];
|
|
331
|
+
}
|
|
332
|
+
return DBL2NUM(sqrt(sum));
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
VALUE mat3_translate(VALUE self, VALUE x, VALUE y) {
|
|
336
|
+
Mat3Data *a = mat3_get(self);
|
|
337
|
+
double dx = value_to_double(x);
|
|
338
|
+
double dy = value_to_double(y);
|
|
339
|
+
return mat3_build9(rb_obj_class(self), a->data[0], a->data[1], a->data[2],
|
|
340
|
+
a->data[3], a->data[4], a->data[5],
|
|
341
|
+
dx * a->data[0] + dy * a->data[3] + a->data[6],
|
|
342
|
+
dx * a->data[1] + dy * a->data[4] + a->data[7],
|
|
343
|
+
dx * a->data[2] + dy * a->data[5] + a->data[8]);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
VALUE mat3_rotate(VALUE self, VALUE radians) {
|
|
347
|
+
VALUE rot = mat3_class_rotation(cMat3, radians);
|
|
348
|
+
return mat3_mul(self, rot);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
VALUE mat3_scale(VALUE self, VALUE x, VALUE y) {
|
|
352
|
+
Mat3Data *a = mat3_get(self);
|
|
353
|
+
double sx = value_to_double(x);
|
|
354
|
+
double sy = value_to_double(y);
|
|
355
|
+
return mat3_build9(rb_obj_class(self), a->data[0] * sx, a->data[1] * sx,
|
|
356
|
+
a->data[2] * sx, a->data[3] * sy, a->data[4] * sy,
|
|
357
|
+
a->data[5] * sy, a->data[6], a->data[7], a->data[8]);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
VALUE mat3_to_a(VALUE self) {
|
|
361
|
+
Mat3Data *a = mat3_get(self);
|
|
362
|
+
VALUE ary = rb_ary_new_capa(9);
|
|
363
|
+
for (int i = 0; i < 9; i++) {
|
|
364
|
+
rb_ary_push(ary, DBL2NUM(a->data[i]));
|
|
365
|
+
}
|
|
366
|
+
return ary;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
VALUE mat3_data(VALUE self) {
|
|
370
|
+
return mat3_to_a(self);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
VALUE mat3_equal(VALUE self, VALUE other) {
|
|
374
|
+
if (!rb_obj_is_kind_of(other, cMat3)) {
|
|
375
|
+
return Qfalse;
|
|
376
|
+
}
|
|
377
|
+
Mat3Data *a = mat3_get(self);
|
|
378
|
+
Mat3Data *b = mat3_get(other);
|
|
379
|
+
for (int i = 0; i < 9; i++) {
|
|
380
|
+
if (a->data[i] != b->data[i]) {
|
|
381
|
+
return Qfalse;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return Qtrue;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
VALUE mat3_near(int argc, VALUE *argv, VALUE self) {
|
|
388
|
+
VALUE other = Qnil;
|
|
389
|
+
VALUE epsilon = Qnil;
|
|
390
|
+
|
|
391
|
+
rb_scan_args(argc, argv, "11", &other, &epsilon);
|
|
392
|
+
Mat3Data *a = mat3_get(self);
|
|
393
|
+
Mat3Data *b = mat3_get(other);
|
|
394
|
+
double eps = NIL_P(epsilon) ? 1e-6 : value_to_double(epsilon);
|
|
395
|
+
|
|
396
|
+
for (int i = 0; i < 9; i++) {
|
|
397
|
+
if (fabs(a->data[i] - b->data[i]) >= eps) {
|
|
398
|
+
return Qfalse;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
return Qtrue;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
static VALUE mat3_format_value(double value) {
|
|
405
|
+
return rb_funcall(rb_mKernel, rb_intern("format"), 2,
|
|
406
|
+
rb_str_new_cstr("%8.4f"), DBL2NUM(value));
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
static VALUE mat3_row_string(const double *values, int offset) {
|
|
410
|
+
VALUE str = mat3_format_value(values[offset]);
|
|
411
|
+
for (int i = 1; i < 3; i++) {
|
|
412
|
+
rb_str_cat_cstr(str, ", ");
|
|
413
|
+
rb_str_concat(str, mat3_format_value(values[offset + i]));
|
|
414
|
+
}
|
|
415
|
+
return str;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
VALUE mat3_inspect(VALUE self) {
|
|
419
|
+
Mat3Data *a = mat3_get(self);
|
|
420
|
+
VALUE str = rb_str_new_cstr("Mat3[\n ");
|
|
421
|
+
rb_str_concat(str, mat3_row_string(a->data, 0));
|
|
422
|
+
rb_str_cat_cstr(str, "\n ");
|
|
423
|
+
rb_str_concat(str, mat3_row_string(a->data, 3));
|
|
424
|
+
rb_str_cat_cstr(str, "\n ");
|
|
425
|
+
rb_str_concat(str, mat3_row_string(a->data, 6));
|
|
426
|
+
rb_str_cat_cstr(str, "\n]");
|
|
427
|
+
return str;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
void Init_mat3(VALUE module) {
|
|
431
|
+
cMat3 = rb_define_class_under(module, "Mat3", rb_cObject);
|
|
432
|
+
cVec3 = rb_const_get(mLarb, rb_intern("Vec3"));
|
|
433
|
+
|
|
434
|
+
rb_define_alloc_func(cMat3, mat3_alloc);
|
|
435
|
+
rb_define_method(cMat3, "initialize", mat3_initialize, -1);
|
|
436
|
+
|
|
437
|
+
rb_define_singleton_method(cMat3, "identity", mat3_class_identity, 0);
|
|
438
|
+
rb_define_singleton_method(cMat3, "zero", mat3_class_zero, 0);
|
|
439
|
+
rb_define_singleton_method(cMat3, "from_mat4", mat3_class_from_mat4, 1);
|
|
440
|
+
rb_define_singleton_method(cMat3, "from_mat2d", mat3_class_from_mat2d, 1);
|
|
441
|
+
rb_define_singleton_method(cMat3, "from_quaternion",
|
|
442
|
+
mat3_class_from_quaternion, 1);
|
|
443
|
+
rb_define_singleton_method(cMat3, "normal_from_mat4",
|
|
444
|
+
mat3_class_normal_from_mat4, 1);
|
|
445
|
+
rb_define_singleton_method(cMat3, "projection", mat3_class_projection, 2);
|
|
446
|
+
rb_define_singleton_method(cMat3, "translation", mat3_class_translation, 2);
|
|
447
|
+
rb_define_singleton_method(cMat3, "rotation", mat3_class_rotation, 1);
|
|
448
|
+
rb_define_singleton_method(cMat3, "scaling", mat3_class_scaling, 2);
|
|
449
|
+
|
|
450
|
+
rb_define_method(cMat3, "data", mat3_data, 0);
|
|
451
|
+
rb_define_method(cMat3, "[]", mat3_aref, 1);
|
|
452
|
+
rb_define_method(cMat3, "[]=", mat3_aset, 2);
|
|
453
|
+
rb_define_method(cMat3, "*", mat3_mul, 1);
|
|
454
|
+
rb_define_method(cMat3, "+", mat3_add, 1);
|
|
455
|
+
rb_define_method(cMat3, "-", mat3_sub, 1);
|
|
456
|
+
rb_define_method(cMat3, "determinant", mat3_determinant, 0);
|
|
457
|
+
rb_define_method(cMat3, "inverse", mat3_inverse, 0);
|
|
458
|
+
rb_define_method(cMat3, "transpose", mat3_transpose, 0);
|
|
459
|
+
rb_define_method(cMat3, "adjoint", mat3_adjoint, 0);
|
|
460
|
+
rb_define_method(cMat3, "frobenius_norm", mat3_frobenius_norm, 0);
|
|
461
|
+
rb_define_method(cMat3, "translate", mat3_translate, 2);
|
|
462
|
+
rb_define_method(cMat3, "rotate", mat3_rotate, 1);
|
|
463
|
+
rb_define_method(cMat3, "scale", mat3_scale, 2);
|
|
464
|
+
rb_define_method(cMat3, "to_a", mat3_to_a, 0);
|
|
465
|
+
rb_define_method(cMat3, "==", mat3_equal, 1);
|
|
466
|
+
rb_define_method(cMat3, "near?", mat3_near, -1);
|
|
467
|
+
rb_define_method(cMat3, "inspect", mat3_inspect, 0);
|
|
468
|
+
rb_define_alias(cMat3, "to_s", "inspect");
|
|
469
|
+
}
|
data/ext/larb/mat3.h
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#ifndef MAT3_H
|
|
2
|
+
#define MAT3_H
|
|
3
|
+
|
|
4
|
+
#include "larb.h"
|
|
5
|
+
|
|
6
|
+
typedef struct {
|
|
7
|
+
double data[9];
|
|
8
|
+
} Mat3Data;
|
|
9
|
+
|
|
10
|
+
void Init_mat3(VALUE module);
|
|
11
|
+
VALUE mat3_alloc(VALUE klass);
|
|
12
|
+
VALUE mat3_initialize(int argc, VALUE *argv, VALUE self);
|
|
13
|
+
|
|
14
|
+
VALUE mat3_aref(VALUE self, VALUE index);
|
|
15
|
+
VALUE mat3_aset(VALUE self, VALUE index, VALUE value);
|
|
16
|
+
VALUE mat3_mul(VALUE self, VALUE other);
|
|
17
|
+
VALUE mat3_add(VALUE self, VALUE other);
|
|
18
|
+
VALUE mat3_sub(VALUE self, VALUE other);
|
|
19
|
+
VALUE mat3_determinant(VALUE self);
|
|
20
|
+
VALUE mat3_inverse(VALUE self);
|
|
21
|
+
VALUE mat3_transpose(VALUE self);
|
|
22
|
+
VALUE mat3_adjoint(VALUE self);
|
|
23
|
+
VALUE mat3_frobenius_norm(VALUE self);
|
|
24
|
+
VALUE mat3_translate(VALUE self, VALUE x, VALUE y);
|
|
25
|
+
VALUE mat3_rotate(VALUE self, VALUE radians);
|
|
26
|
+
VALUE mat3_scale(VALUE self, VALUE x, VALUE y);
|
|
27
|
+
VALUE mat3_to_a(VALUE self);
|
|
28
|
+
VALUE mat3_equal(VALUE self, VALUE other);
|
|
29
|
+
VALUE mat3_near(int argc, VALUE *argv, VALUE self);
|
|
30
|
+
VALUE mat3_inspect(VALUE self);
|
|
31
|
+
VALUE mat3_data(VALUE self);
|
|
32
|
+
|
|
33
|
+
#endif
|