larb 0.1.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 +13 -1
- data/README.md +63 -1
- data/ext/larb/color.c +449 -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 +31 -0
- data/ext/larb/mat2.c +303 -0
- data/ext/larb/mat2.h +30 -0
- data/ext/larb/mat2d.c +397 -0
- data/ext/larb/mat2d.h +35 -0
- data/ext/larb/mat3.c +455 -0
- data/ext/larb/mat3.h +33 -0
- data/ext/larb/mat4.c +651 -0
- data/ext/larb/mat4.h +31 -0
- data/ext/larb/matrix_utils.h +97 -0
- data/ext/larb/quat.c +567 -0
- data/ext/larb/quat.h +39 -0
- data/ext/larb/quat2.c +511 -0
- data/ext/larb/quat2.h +39 -0
- data/ext/larb/vec2.c +365 -0
- data/ext/larb/vec2.h +43 -0
- data/ext/larb/vec3.c +538 -0
- data/ext/larb/vec3.h +52 -0
- data/ext/larb/vec4.c +361 -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 +299 -0
- data/test/larb/mat2_test.rb +144 -0
- data/test/larb/mat2d_test.rb +197 -0
- data/test/larb/mat3_test.rb +147 -0
- data/test/larb/mat4_test.rb +347 -0
- data/test/larb/matrix_test.rb +135 -0
- data/test/larb/native_value_test.rb +157 -0
- data/test/larb/quat2_test.rb +254 -0
- data/test/larb/quat_test.rb +284 -0
- data/test/larb/vec2_test.rb +274 -0
- data/test/larb/vec3_test.rb +373 -0
- data/test/larb/vec4_test.rb +196 -0
- data/test/test_helper.rb +4 -0
- metadata +60 -18
- 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/vec3.c
ADDED
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
#include "vec3.h"
|
|
2
|
+
|
|
3
|
+
#include <math.h>
|
|
4
|
+
|
|
5
|
+
static void vec3_free(void *ptr) {
|
|
6
|
+
xfree(ptr);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
static size_t vec3_memsize(const void *ptr) {
|
|
10
|
+
return sizeof(Vec3Data);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static const rb_data_type_t vec3_type = {
|
|
14
|
+
"Vec3",
|
|
15
|
+
{0, vec3_free, vec3_memsize},
|
|
16
|
+
0,
|
|
17
|
+
0,
|
|
18
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
static VALUE cVec3 = Qnil;
|
|
22
|
+
|
|
23
|
+
static Vec3Data *vec3_get(VALUE obj) {
|
|
24
|
+
Vec3Data *data = NULL;
|
|
25
|
+
TypedData_Get_Struct(obj, Vec3Data, &vec3_type, data);
|
|
26
|
+
return data;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static VALUE vec3_build(VALUE klass, double x, double y, double z) {
|
|
30
|
+
VALUE obj = vec3_alloc(klass);
|
|
31
|
+
Vec3Data *data = vec3_get(obj);
|
|
32
|
+
data->x = x;
|
|
33
|
+
data->y = y;
|
|
34
|
+
data->z = z;
|
|
35
|
+
return obj;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static double clamp_double(double value, double min, double max) {
|
|
39
|
+
if (value < min) {
|
|
40
|
+
return min;
|
|
41
|
+
}
|
|
42
|
+
if (value > max) {
|
|
43
|
+
return max;
|
|
44
|
+
}
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
VALUE vec3_alloc(VALUE klass) {
|
|
49
|
+
Vec3Data *data = ALLOC(Vec3Data);
|
|
50
|
+
data->x = 0.0;
|
|
51
|
+
data->y = 0.0;
|
|
52
|
+
data->z = 0.0;
|
|
53
|
+
return TypedData_Wrap_Struct(klass, &vec3_type, data);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
VALUE vec3_initialize(int argc, VALUE *argv, VALUE self) {
|
|
57
|
+
rb_check_frozen(self);
|
|
58
|
+
VALUE vx = Qnil;
|
|
59
|
+
VALUE vy = Qnil;
|
|
60
|
+
VALUE vz = Qnil;
|
|
61
|
+
rb_scan_args(argc, argv, "03", &vx, &vy, &vz);
|
|
62
|
+
Vec3Data value = {
|
|
63
|
+
argc > 0 ? NUM2DBL(vx) : 0.0,
|
|
64
|
+
argc > 1 ? NUM2DBL(vy) : 0.0,
|
|
65
|
+
argc > 2 ? NUM2DBL(vz) : 0.0
|
|
66
|
+
};
|
|
67
|
+
rb_check_frozen(self);
|
|
68
|
+
*vec3_get(self) = value;
|
|
69
|
+
return self;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
static VALUE vec3_class_bracket(VALUE klass, VALUE x, VALUE y, VALUE z) {
|
|
73
|
+
return vec3_build(klass, NUM2DBL(x), NUM2DBL(y),
|
|
74
|
+
NUM2DBL(z));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
static VALUE vec3_class_zero(VALUE klass) {
|
|
78
|
+
return vec3_build(klass, 0.0, 0.0, 0.0);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
static VALUE vec3_class_one(VALUE klass) {
|
|
82
|
+
return vec3_build(klass, 1.0, 1.0, 1.0);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
static VALUE vec3_class_up(VALUE klass) {
|
|
86
|
+
return vec3_build(klass, 0.0, 1.0, 0.0);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
static VALUE vec3_class_down(VALUE klass) {
|
|
90
|
+
return vec3_build(klass, 0.0, -1.0, 0.0);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
static VALUE vec3_class_forward(VALUE klass) {
|
|
94
|
+
return vec3_build(klass, 0.0, 0.0, -1.0);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
static VALUE vec3_class_back(VALUE klass) {
|
|
98
|
+
return vec3_build(klass, 0.0, 0.0, 1.0);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
static VALUE vec3_class_right(VALUE klass) {
|
|
102
|
+
return vec3_build(klass, 1.0, 0.0, 0.0);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
static VALUE vec3_class_left(VALUE klass) {
|
|
106
|
+
return vec3_build(klass, -1.0, 0.0, 0.0);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
static VALUE vec3_get_x(VALUE self) {
|
|
110
|
+
Vec3Data *data = vec3_get(self);
|
|
111
|
+
return DBL2NUM(data->x);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static VALUE vec3_set_x(VALUE self, VALUE value) {
|
|
115
|
+
rb_check_frozen(self);
|
|
116
|
+
Vec3Data *data = vec3_get(self);
|
|
117
|
+
double component = NUM2DBL(value);
|
|
118
|
+
rb_check_frozen(self);
|
|
119
|
+
data->x = component;
|
|
120
|
+
return value;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
static VALUE vec3_get_y(VALUE self) {
|
|
124
|
+
Vec3Data *data = vec3_get(self);
|
|
125
|
+
return DBL2NUM(data->y);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
static VALUE vec3_set_y(VALUE self, VALUE value) {
|
|
129
|
+
rb_check_frozen(self);
|
|
130
|
+
Vec3Data *data = vec3_get(self);
|
|
131
|
+
double component = NUM2DBL(value);
|
|
132
|
+
rb_check_frozen(self);
|
|
133
|
+
data->y = component;
|
|
134
|
+
return value;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
static VALUE vec3_get_z(VALUE self) {
|
|
138
|
+
Vec3Data *data = vec3_get(self);
|
|
139
|
+
return DBL2NUM(data->z);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
static VALUE vec3_set_z(VALUE self, VALUE value) {
|
|
143
|
+
rb_check_frozen(self);
|
|
144
|
+
Vec3Data *data = vec3_get(self);
|
|
145
|
+
double component = NUM2DBL(value);
|
|
146
|
+
rb_check_frozen(self);
|
|
147
|
+
data->z = component;
|
|
148
|
+
return value;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
VALUE vec3_add(VALUE self, VALUE other) {
|
|
152
|
+
Vec3Data *a = vec3_get(self);
|
|
153
|
+
Vec3Data *b = vec3_get(other);
|
|
154
|
+
return vec3_build(rb_obj_class(self), a->x + b->x, a->y + b->y,
|
|
155
|
+
a->z + b->z);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
VALUE vec3_sub(VALUE self, VALUE other) {
|
|
159
|
+
Vec3Data *a = vec3_get(self);
|
|
160
|
+
Vec3Data *b = vec3_get(other);
|
|
161
|
+
return vec3_build(rb_obj_class(self), a->x - b->x, a->y - b->y,
|
|
162
|
+
a->z - b->z);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
VALUE vec3_mul(VALUE self, VALUE scalar) {
|
|
166
|
+
Vec3Data *a = vec3_get(self);
|
|
167
|
+
|
|
168
|
+
if (rb_obj_is_kind_of(scalar, cVec3)) {
|
|
169
|
+
Vec3Data *b = vec3_get(scalar);
|
|
170
|
+
return vec3_build(rb_obj_class(self), a->x * b->x, a->y * b->y,
|
|
171
|
+
a->z * b->z);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
double s = NUM2DBL(scalar);
|
|
175
|
+
return vec3_build(rb_obj_class(self), a->x * s, a->y * s, a->z * s);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
VALUE vec3_div(VALUE self, VALUE scalar) {
|
|
179
|
+
Vec3Data *a = vec3_get(self);
|
|
180
|
+
double s = NUM2DBL(scalar);
|
|
181
|
+
return vec3_build(rb_obj_class(self), a->x / s, a->y / s, a->z / s);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
VALUE vec3_negate(VALUE self) {
|
|
185
|
+
Vec3Data *a = vec3_get(self);
|
|
186
|
+
return vec3_build(rb_obj_class(self), -a->x, -a->y, -a->z);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
VALUE vec3_dot(VALUE self, VALUE other) {
|
|
190
|
+
Vec3Data *a = vec3_get(self);
|
|
191
|
+
Vec3Data *b = vec3_get(other);
|
|
192
|
+
return DBL2NUM(a->x * b->x + a->y * b->y + a->z * b->z);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
VALUE vec3_cross(VALUE self, VALUE other) {
|
|
196
|
+
Vec3Data *a = vec3_get(self);
|
|
197
|
+
Vec3Data *b = vec3_get(other);
|
|
198
|
+
return vec3_build(rb_obj_class(self), a->y * b->z - a->z * b->y,
|
|
199
|
+
a->z * b->x - a->x * b->z,
|
|
200
|
+
a->x * b->y - a->y * b->x);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
VALUE vec3_length(VALUE self) {
|
|
204
|
+
Vec3Data *a = vec3_get(self);
|
|
205
|
+
return DBL2NUM(hypot(hypot(a->x, a->y), a->z));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
VALUE vec3_length_squared(VALUE self) {
|
|
209
|
+
Vec3Data *a = vec3_get(self);
|
|
210
|
+
return DBL2NUM(a->x * a->x + a->y * a->y + a->z * a->z);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
VALUE vec3_normalize(VALUE self) {
|
|
214
|
+
Vec3Data *a = vec3_get(self);
|
|
215
|
+
double values[] = {a->x, a->y, a->z};
|
|
216
|
+
larb_normalize(values, 3);
|
|
217
|
+
return vec3_build(rb_obj_class(self), values[0], values[1], values[2]);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
VALUE vec3_reflect(VALUE self, VALUE normal) {
|
|
221
|
+
Vec3Data *a = vec3_get(self);
|
|
222
|
+
Vec3Data *n = vec3_get(normal);
|
|
223
|
+
double dot = a->x * n->x + a->y * n->y + a->z * n->z;
|
|
224
|
+
return vec3_build(rb_obj_class(self), a->x - n->x * (2.0 * dot),
|
|
225
|
+
a->y - n->y * (2.0 * dot), a->z - n->z * (2.0 * dot));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
VALUE vec3_xy(VALUE self) {
|
|
229
|
+
Vec3Data *a = vec3_get(self);
|
|
230
|
+
VALUE vec2_class = rb_const_get(mLarb, rb_intern("Vec2"));
|
|
231
|
+
return rb_funcall(vec2_class, rb_intern("new"), 2, DBL2NUM(a->x),
|
|
232
|
+
DBL2NUM(a->y));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
VALUE vec3_xz(VALUE self) {
|
|
236
|
+
Vec3Data *a = vec3_get(self);
|
|
237
|
+
VALUE vec2_class = rb_const_get(mLarb, rb_intern("Vec2"));
|
|
238
|
+
return rb_funcall(vec2_class, rb_intern("new"), 2, DBL2NUM(a->x),
|
|
239
|
+
DBL2NUM(a->z));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
VALUE vec3_yz(VALUE self) {
|
|
243
|
+
Vec3Data *a = vec3_get(self);
|
|
244
|
+
VALUE vec2_class = rb_const_get(mLarb, rb_intern("Vec2"));
|
|
245
|
+
return rb_funcall(vec2_class, rb_intern("new"), 2, DBL2NUM(a->y),
|
|
246
|
+
DBL2NUM(a->z));
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
VALUE vec3_lerp(VALUE self, VALUE other, VALUE t) {
|
|
250
|
+
Vec3Data *a = vec3_get(self);
|
|
251
|
+
Vec3Data *b = vec3_get(other);
|
|
252
|
+
double s = NUM2DBL(t);
|
|
253
|
+
return vec3_build(rb_obj_class(self), a->x + (b->x - a->x) * s,
|
|
254
|
+
a->y + (b->y - a->y) * s,
|
|
255
|
+
a->z + (b->z - a->z) * s);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
VALUE vec3_to_a(VALUE self) {
|
|
259
|
+
Vec3Data *a = vec3_get(self);
|
|
260
|
+
VALUE ary = rb_ary_new_capa(3);
|
|
261
|
+
rb_ary_push(ary, DBL2NUM(a->x));
|
|
262
|
+
rb_ary_push(ary, DBL2NUM(a->y));
|
|
263
|
+
rb_ary_push(ary, DBL2NUM(a->z));
|
|
264
|
+
return ary;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
VALUE vec3_to_vec4(int argc, VALUE *argv, VALUE self) {
|
|
268
|
+
VALUE vw = Qnil;
|
|
269
|
+
Vec3Data *a = vec3_get(self);
|
|
270
|
+
|
|
271
|
+
rb_scan_args(argc, argv, "01", &vw);
|
|
272
|
+
VALUE vec4_class = rb_const_get(mLarb, rb_intern("Vec4"));
|
|
273
|
+
return rb_funcall(vec4_class, rb_intern("new"), 4, DBL2NUM(a->x),
|
|
274
|
+
DBL2NUM(a->y), DBL2NUM(a->z),
|
|
275
|
+
argc == 0 ? DBL2NUM(1.0) : vw);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
VALUE vec3_aref(VALUE self, VALUE index) {
|
|
279
|
+
VALUE ary = vec3_to_a(self);
|
|
280
|
+
return rb_ary_entry(ary, NUM2LONG(index));
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
VALUE vec3_equal(VALUE self, VALUE other) {
|
|
284
|
+
if (!rb_obj_is_kind_of(other, cVec3)) {
|
|
285
|
+
return Qfalse;
|
|
286
|
+
}
|
|
287
|
+
Vec3Data *a = vec3_get(self);
|
|
288
|
+
Vec3Data *b = vec3_get(other);
|
|
289
|
+
return (a->x == b->x && a->y == b->y && a->z == b->z) ? Qtrue : Qfalse;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
VALUE vec3_near(int argc, VALUE *argv, VALUE self) {
|
|
293
|
+
VALUE other = Qnil;
|
|
294
|
+
VALUE epsilon = Qnil;
|
|
295
|
+
|
|
296
|
+
rb_scan_args(argc, argv, "11", &other, &epsilon);
|
|
297
|
+
Vec3Data *a = vec3_get(self);
|
|
298
|
+
Vec3Data *b = vec3_get(other);
|
|
299
|
+
double eps = argc < 2 ? 1e-6 : NUM2DBL(epsilon);
|
|
300
|
+
if (!isfinite(eps) || eps <= 0.0) {
|
|
301
|
+
rb_raise(rb_eArgError, "epsilon must be finite and positive");
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (fabs(a->x - b->x) < eps && fabs(a->y - b->y) < eps &&
|
|
305
|
+
fabs(a->z - b->z) < eps) {
|
|
306
|
+
return Qtrue;
|
|
307
|
+
}
|
|
308
|
+
return Qfalse;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
VALUE vec3_distance(VALUE self, VALUE other) {
|
|
312
|
+
Vec3Data *a = vec3_get(self);
|
|
313
|
+
Vec3Data *b = vec3_get(other);
|
|
314
|
+
double dx = a->x - b->x;
|
|
315
|
+
double dy = a->y - b->y;
|
|
316
|
+
double dz = a->z - b->z;
|
|
317
|
+
return DBL2NUM(hypot(hypot(dx, dy), dz));
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
VALUE vec3_distance_squared(VALUE self, VALUE other) {
|
|
321
|
+
Vec3Data *a = vec3_get(self);
|
|
322
|
+
Vec3Data *b = vec3_get(other);
|
|
323
|
+
double dx = a->x - b->x;
|
|
324
|
+
double dy = a->y - b->y;
|
|
325
|
+
double dz = a->z - b->z;
|
|
326
|
+
return DBL2NUM(dx * dx + dy * dy + dz * dz);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
VALUE vec3_angle_between(VALUE self, VALUE other) {
|
|
330
|
+
Vec3Data *a = vec3_get(self);
|
|
331
|
+
Vec3Data *b = vec3_get(other);
|
|
332
|
+
double av[] = {a->x, a->y, a->z};
|
|
333
|
+
double bv[] = {b->x, b->y, b->z};
|
|
334
|
+
larb_normalize(av, 3);
|
|
335
|
+
larb_normalize(bv, 3);
|
|
336
|
+
double d = av[0] * bv[0] + av[1] * bv[1] + av[2] * bv[2];
|
|
337
|
+
return DBL2NUM(acos(clamp_double(d, -1.0, 1.0)));
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
VALUE vec3_project(VALUE self, VALUE onto) {
|
|
341
|
+
Vec3Data *a = vec3_get(self);
|
|
342
|
+
Vec3Data *b = vec3_get(onto);
|
|
343
|
+
double direction[] = {b->x, b->y, b->z};
|
|
344
|
+
larb_normalize(direction, 3);
|
|
345
|
+
double scale = a->x * direction[0] + a->y * direction[1] + a->z * direction[2];
|
|
346
|
+
return vec3_build(rb_obj_class(self), direction[0] * scale,
|
|
347
|
+
direction[1] * scale, direction[2] * scale);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
VALUE vec3_reject(VALUE self, VALUE from) {
|
|
351
|
+
return vec3_sub(self, vec3_project(self, from));
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
VALUE vec3_slerp(VALUE self, VALUE other, VALUE t) {
|
|
355
|
+
Vec3Data *a = vec3_get(self);
|
|
356
|
+
Vec3Data *b = vec3_get(other);
|
|
357
|
+
double s = NUM2DBL(t);
|
|
358
|
+
double len = hypot(hypot(a->x, a->y), a->z);
|
|
359
|
+
double other_len = hypot(hypot(b->x, b->y), b->z);
|
|
360
|
+
if (!isfinite(s) || !isfinite(len) || !isfinite(other_len)) {
|
|
361
|
+
rb_raise(rb_eArgError, "slerp requires finite lengths and interpolation parameter");
|
|
362
|
+
}
|
|
363
|
+
double av[] = {a->x, a->y, a->z};
|
|
364
|
+
double bv[] = {b->x, b->y, b->z};
|
|
365
|
+
larb_normalize(av, 3);
|
|
366
|
+
larb_normalize(bv, 3);
|
|
367
|
+
if (s == 0.0) return vec3_build(rb_obj_class(self), a->x, a->y, a->z);
|
|
368
|
+
if (s == 1.0) return vec3_build(rb_obj_class(self), b->x, b->y, b->z);
|
|
369
|
+
|
|
370
|
+
double dot = clamp_double(av[0] * bv[0] + av[1] * bv[1] + av[2] * bv[2], -1.0, 1.0);
|
|
371
|
+
double direction[3];
|
|
372
|
+
if (dot > 1.0 - 1e-12) {
|
|
373
|
+
for (int i = 0; i < 3; i++) direction[i] = av[i] + (bv[i] - av[i]) * s;
|
|
374
|
+
} else {
|
|
375
|
+
double normal[] = {av[1] * bv[2] - av[2] * bv[1],
|
|
376
|
+
av[2] * bv[0] - av[0] * bv[2],
|
|
377
|
+
av[0] * bv[1] - av[1] * bv[0]};
|
|
378
|
+
double tangent[] = {normal[1] * av[2] - normal[2] * av[1],
|
|
379
|
+
normal[2] * av[0] - normal[0] * av[2],
|
|
380
|
+
normal[0] * av[1] - normal[1] * av[0]};
|
|
381
|
+
double sine = hypot(hypot(normal[0], normal[1]), normal[2]);
|
|
382
|
+
if (sine < 1e-12) {
|
|
383
|
+
// Antipodes have no unique arc; choose the least-aligned coordinate axis.
|
|
384
|
+
int axis = 0;
|
|
385
|
+
for (int i = 1; i < 3; i++) if (fabs(av[i]) < fabs(av[axis])) axis = i;
|
|
386
|
+
for (int i = 0; i < 3; i++) tangent[i] = (i == axis ? 1.0 : 0.0) - av[i] * av[axis];
|
|
387
|
+
}
|
|
388
|
+
larb_normalize(tangent, 3);
|
|
389
|
+
double theta = atan2(sine, dot) * s;
|
|
390
|
+
for (int i = 0; i < 3; i++) direction[i] = av[i] * cos(theta) + tangent[i] * sin(theta);
|
|
391
|
+
}
|
|
392
|
+
larb_normalize(direction, 3);
|
|
393
|
+
double length = (1.0 - s) * len + s * other_len;
|
|
394
|
+
return vec3_build(rb_obj_class(self), direction[0] * length,
|
|
395
|
+
direction[1] * length, direction[2] * length);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
VALUE vec3_clamp_length(VALUE self, VALUE max_length) {
|
|
399
|
+
Vec3Data *a = vec3_get(self);
|
|
400
|
+
double max_len = NUM2DBL(max_length);
|
|
401
|
+
if (!isfinite(max_len) || max_len < 0.0) {
|
|
402
|
+
rb_raise(rb_eArgError, "max_length must be finite and nonnegative");
|
|
403
|
+
}
|
|
404
|
+
if (hypot(hypot(a->x, a->y), a->z) <= max_len) return self;
|
|
405
|
+
double values[] = {a->x, a->y, a->z};
|
|
406
|
+
larb_normalize(values, 3);
|
|
407
|
+
return vec3_build(rb_obj_class(self), values[0] * max_len, values[1] * max_len, values[2] * max_len);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
VALUE vec3_normalize_bang(VALUE self) {
|
|
411
|
+
rb_check_frozen(self);
|
|
412
|
+
Vec3Data *a = vec3_get(self);
|
|
413
|
+
double values[] = {a->x, a->y, a->z};
|
|
414
|
+
larb_normalize(values, 3);
|
|
415
|
+
a->x = values[0];
|
|
416
|
+
a->y = values[1];
|
|
417
|
+
a->z = values[2];
|
|
418
|
+
return self;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
VALUE vec3_min(VALUE self, VALUE other) {
|
|
422
|
+
Vec3Data *a = vec3_get(self);
|
|
423
|
+
Vec3Data *b = vec3_get(other);
|
|
424
|
+
return vec3_build(rb_obj_class(self), fmin(a->x, b->x), fmin(a->y, b->y),
|
|
425
|
+
fmin(a->z, b->z));
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
VALUE vec3_max(VALUE self, VALUE other) {
|
|
429
|
+
Vec3Data *a = vec3_get(self);
|
|
430
|
+
Vec3Data *b = vec3_get(other);
|
|
431
|
+
return vec3_build(rb_obj_class(self), fmax(a->x, b->x), fmax(a->y, b->y),
|
|
432
|
+
fmax(a->z, b->z));
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
VALUE vec3_abs(VALUE self) {
|
|
436
|
+
Vec3Data *a = vec3_get(self);
|
|
437
|
+
return vec3_build(rb_obj_class(self), fabs(a->x), fabs(a->y), fabs(a->z));
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
VALUE vec3_floor(VALUE self) {
|
|
441
|
+
Vec3Data *a = vec3_get(self);
|
|
442
|
+
return vec3_build(rb_obj_class(self), floor(a->x), floor(a->y), floor(a->z));
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
VALUE vec3_ceil(VALUE self) {
|
|
446
|
+
Vec3Data *a = vec3_get(self);
|
|
447
|
+
return vec3_build(rb_obj_class(self), ceil(a->x), ceil(a->y), ceil(a->z));
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
VALUE vec3_round(VALUE self) {
|
|
451
|
+
Vec3Data *a = vec3_get(self);
|
|
452
|
+
return vec3_build(rb_obj_class(self), round(a->x), round(a->y), round(a->z));
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
VALUE vec3_inspect(VALUE self) {
|
|
456
|
+
Vec3Data *a = vec3_get(self);
|
|
457
|
+
VALUE sx = rb_funcall(DBL2NUM(a->x), rb_intern("to_s"), 0);
|
|
458
|
+
VALUE sy = rb_funcall(DBL2NUM(a->y), rb_intern("to_s"), 0);
|
|
459
|
+
VALUE sz = rb_funcall(DBL2NUM(a->z), rb_intern("to_s"), 0);
|
|
460
|
+
VALUE str = rb_str_new_cstr("Vec3[");
|
|
461
|
+
rb_str_concat(str, sx);
|
|
462
|
+
rb_str_cat_cstr(str, ", ");
|
|
463
|
+
rb_str_concat(str, sy);
|
|
464
|
+
rb_str_cat_cstr(str, ", ");
|
|
465
|
+
rb_str_concat(str, sz);
|
|
466
|
+
rb_str_cat_cstr(str, "]");
|
|
467
|
+
return str;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
static VALUE vec3_initialize_copy(VALUE self, VALUE other) {
|
|
471
|
+
if (self == other) return self;
|
|
472
|
+
rb_obj_init_copy(self, other);
|
|
473
|
+
*vec3_get(self) = *vec3_get(other);
|
|
474
|
+
return self;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
void Init_vec3(VALUE module) {
|
|
478
|
+
cVec3 = rb_define_class_under(module, "Vec3", rb_cObject);
|
|
479
|
+
|
|
480
|
+
rb_define_alloc_func(cVec3, vec3_alloc);
|
|
481
|
+
rb_define_method(cVec3, "initialize", vec3_initialize, -1);
|
|
482
|
+
rb_define_method(cVec3, "initialize_copy", vec3_initialize_copy, 1);
|
|
483
|
+
|
|
484
|
+
rb_define_singleton_method(cVec3, "[]", vec3_class_bracket, 3);
|
|
485
|
+
rb_define_singleton_method(cVec3, "zero", vec3_class_zero, 0);
|
|
486
|
+
rb_define_singleton_method(cVec3, "one", vec3_class_one, 0);
|
|
487
|
+
rb_define_singleton_method(cVec3, "up", vec3_class_up, 0);
|
|
488
|
+
rb_define_singleton_method(cVec3, "down", vec3_class_down, 0);
|
|
489
|
+
rb_define_singleton_method(cVec3, "forward", vec3_class_forward, 0);
|
|
490
|
+
rb_define_singleton_method(cVec3, "back", vec3_class_back, 0);
|
|
491
|
+
rb_define_singleton_method(cVec3, "right", vec3_class_right, 0);
|
|
492
|
+
rb_define_singleton_method(cVec3, "left", vec3_class_left, 0);
|
|
493
|
+
|
|
494
|
+
rb_define_method(cVec3, "x", vec3_get_x, 0);
|
|
495
|
+
rb_define_method(cVec3, "x=", vec3_set_x, 1);
|
|
496
|
+
rb_define_method(cVec3, "y", vec3_get_y, 0);
|
|
497
|
+
rb_define_method(cVec3, "y=", vec3_set_y, 1);
|
|
498
|
+
rb_define_method(cVec3, "z", vec3_get_z, 0);
|
|
499
|
+
rb_define_method(cVec3, "z=", vec3_set_z, 1);
|
|
500
|
+
|
|
501
|
+
rb_define_method(cVec3, "+", vec3_add, 1);
|
|
502
|
+
rb_define_method(cVec3, "-", vec3_sub, 1);
|
|
503
|
+
rb_define_method(cVec3, "*", vec3_mul, 1);
|
|
504
|
+
rb_define_method(cVec3, "/", vec3_div, 1);
|
|
505
|
+
rb_define_method(cVec3, "-@", vec3_negate, 0);
|
|
506
|
+
|
|
507
|
+
rb_define_method(cVec3, "dot", vec3_dot, 1);
|
|
508
|
+
rb_define_method(cVec3, "cross", vec3_cross, 1);
|
|
509
|
+
rb_define_method(cVec3, "length", vec3_length, 0);
|
|
510
|
+
rb_define_method(cVec3, "length_squared", vec3_length_squared, 0);
|
|
511
|
+
rb_define_method(cVec3, "normalize", vec3_normalize, 0);
|
|
512
|
+
rb_define_method(cVec3, "reflect", vec3_reflect, 1);
|
|
513
|
+
rb_define_method(cVec3, "xy", vec3_xy, 0);
|
|
514
|
+
rb_define_method(cVec3, "xz", vec3_xz, 0);
|
|
515
|
+
rb_define_method(cVec3, "yz", vec3_yz, 0);
|
|
516
|
+
rb_define_method(cVec3, "lerp", vec3_lerp, 2);
|
|
517
|
+
rb_define_method(cVec3, "to_a", vec3_to_a, 0);
|
|
518
|
+
rb_define_method(cVec3, "to_vec4", vec3_to_vec4, -1);
|
|
519
|
+
rb_define_method(cVec3, "[]", vec3_aref, 1);
|
|
520
|
+
rb_define_method(cVec3, "==", vec3_equal, 1);
|
|
521
|
+
rb_define_method(cVec3, "near?", vec3_near, -1);
|
|
522
|
+
rb_define_method(cVec3, "distance", vec3_distance, 1);
|
|
523
|
+
rb_define_method(cVec3, "distance_squared", vec3_distance_squared, 1);
|
|
524
|
+
rb_define_method(cVec3, "angle_between", vec3_angle_between, 1);
|
|
525
|
+
rb_define_method(cVec3, "project", vec3_project, 1);
|
|
526
|
+
rb_define_method(cVec3, "reject", vec3_reject, 1);
|
|
527
|
+
rb_define_method(cVec3, "slerp", vec3_slerp, 2);
|
|
528
|
+
rb_define_method(cVec3, "clamp_length", vec3_clamp_length, 1);
|
|
529
|
+
rb_define_method(cVec3, "normalize!", vec3_normalize_bang, 0);
|
|
530
|
+
rb_define_method(cVec3, "min", vec3_min, 1);
|
|
531
|
+
rb_define_method(cVec3, "max", vec3_max, 1);
|
|
532
|
+
rb_define_method(cVec3, "abs", vec3_abs, 0);
|
|
533
|
+
rb_define_method(cVec3, "floor", vec3_floor, 0);
|
|
534
|
+
rb_define_method(cVec3, "ceil", vec3_ceil, 0);
|
|
535
|
+
rb_define_method(cVec3, "round", vec3_round, 0);
|
|
536
|
+
rb_define_method(cVec3, "inspect", vec3_inspect, 0);
|
|
537
|
+
rb_define_alias(cVec3, "to_s", "inspect");
|
|
538
|
+
}
|
data/ext/larb/vec3.h
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#ifndef VEC3_H
|
|
2
|
+
#define VEC3_H
|
|
3
|
+
|
|
4
|
+
#include "larb.h"
|
|
5
|
+
|
|
6
|
+
typedef struct {
|
|
7
|
+
double x;
|
|
8
|
+
double y;
|
|
9
|
+
double z;
|
|
10
|
+
} Vec3Data;
|
|
11
|
+
|
|
12
|
+
void Init_vec3(VALUE module);
|
|
13
|
+
VALUE vec3_alloc(VALUE klass);
|
|
14
|
+
VALUE vec3_initialize(int argc, VALUE *argv, VALUE self);
|
|
15
|
+
|
|
16
|
+
VALUE vec3_add(VALUE self, VALUE other);
|
|
17
|
+
VALUE vec3_sub(VALUE self, VALUE other);
|
|
18
|
+
VALUE vec3_mul(VALUE self, VALUE scalar);
|
|
19
|
+
VALUE vec3_div(VALUE self, VALUE scalar);
|
|
20
|
+
VALUE vec3_negate(VALUE self);
|
|
21
|
+
VALUE vec3_dot(VALUE self, VALUE other);
|
|
22
|
+
VALUE vec3_cross(VALUE self, VALUE other);
|
|
23
|
+
VALUE vec3_length(VALUE self);
|
|
24
|
+
VALUE vec3_length_squared(VALUE self);
|
|
25
|
+
VALUE vec3_normalize(VALUE self);
|
|
26
|
+
VALUE vec3_reflect(VALUE self, VALUE normal);
|
|
27
|
+
VALUE vec3_xy(VALUE self);
|
|
28
|
+
VALUE vec3_xz(VALUE self);
|
|
29
|
+
VALUE vec3_yz(VALUE self);
|
|
30
|
+
VALUE vec3_lerp(VALUE self, VALUE other, VALUE t);
|
|
31
|
+
VALUE vec3_to_a(VALUE self);
|
|
32
|
+
VALUE vec3_to_vec4(int argc, VALUE *argv, VALUE self);
|
|
33
|
+
VALUE vec3_aref(VALUE self, VALUE index);
|
|
34
|
+
VALUE vec3_equal(VALUE self, VALUE other);
|
|
35
|
+
VALUE vec3_near(int argc, VALUE *argv, VALUE self);
|
|
36
|
+
VALUE vec3_distance(VALUE self, VALUE other);
|
|
37
|
+
VALUE vec3_distance_squared(VALUE self, VALUE other);
|
|
38
|
+
VALUE vec3_angle_between(VALUE self, VALUE other);
|
|
39
|
+
VALUE vec3_project(VALUE self, VALUE onto);
|
|
40
|
+
VALUE vec3_reject(VALUE self, VALUE from);
|
|
41
|
+
VALUE vec3_slerp(VALUE self, VALUE other, VALUE t);
|
|
42
|
+
VALUE vec3_clamp_length(VALUE self, VALUE max_length);
|
|
43
|
+
VALUE vec3_normalize_bang(VALUE self);
|
|
44
|
+
VALUE vec3_min(VALUE self, VALUE other);
|
|
45
|
+
VALUE vec3_max(VALUE self, VALUE other);
|
|
46
|
+
VALUE vec3_abs(VALUE self);
|
|
47
|
+
VALUE vec3_floor(VALUE self);
|
|
48
|
+
VALUE vec3_ceil(VALUE self);
|
|
49
|
+
VALUE vec3_round(VALUE self);
|
|
50
|
+
VALUE vec3_inspect(VALUE self);
|
|
51
|
+
|
|
52
|
+
#endif
|