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/vec2.c
CHANGED
|
@@ -20,11 +20,6 @@ static const rb_data_type_t vec2_type = {
|
|
|
20
20
|
|
|
21
21
|
static VALUE cVec2 = Qnil;
|
|
22
22
|
|
|
23
|
-
static double value_to_double(VALUE value) {
|
|
24
|
-
VALUE coerced = rb_funcall(value, rb_intern("to_f"), 0);
|
|
25
|
-
return NUM2DBL(coerced);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
23
|
static Vec2Data *vec2_get(VALUE obj) {
|
|
29
24
|
Vec2Data *data = NULL;
|
|
30
25
|
TypedData_Get_Struct(obj, Vec2Data, &vec2_type, data);
|
|
@@ -47,19 +42,21 @@ VALUE vec2_alloc(VALUE klass) {
|
|
|
47
42
|
}
|
|
48
43
|
|
|
49
44
|
VALUE vec2_initialize(int argc, VALUE *argv, VALUE self) {
|
|
45
|
+
rb_check_frozen(self);
|
|
50
46
|
VALUE vx = Qnil;
|
|
51
47
|
VALUE vy = Qnil;
|
|
52
|
-
Vec2Data *data = vec2_get(self);
|
|
53
|
-
|
|
54
48
|
rb_scan_args(argc, argv, "02", &vx, &vy);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
49
|
+
Vec2Data value = {
|
|
50
|
+
argc > 0 ? NUM2DBL(vx) : 0.0,
|
|
51
|
+
argc > 1 ? NUM2DBL(vy) : 0.0
|
|
52
|
+
};
|
|
53
|
+
rb_check_frozen(self);
|
|
54
|
+
*vec2_get(self) = value;
|
|
58
55
|
return self;
|
|
59
56
|
}
|
|
60
57
|
|
|
61
58
|
static VALUE vec2_class_bracket(VALUE klass, VALUE x, VALUE y) {
|
|
62
|
-
return vec2_build(klass,
|
|
59
|
+
return vec2_build(klass, NUM2DBL(x), NUM2DBL(y));
|
|
63
60
|
}
|
|
64
61
|
|
|
65
62
|
static VALUE vec2_class_zero(VALUE klass) {
|
|
@@ -76,8 +73,11 @@ static VALUE vec2_get_x(VALUE self) {
|
|
|
76
73
|
}
|
|
77
74
|
|
|
78
75
|
static VALUE vec2_set_x(VALUE self, VALUE value) {
|
|
76
|
+
rb_check_frozen(self);
|
|
79
77
|
Vec2Data *data = vec2_get(self);
|
|
80
|
-
|
|
78
|
+
double component = NUM2DBL(value);
|
|
79
|
+
rb_check_frozen(self);
|
|
80
|
+
data->x = component;
|
|
81
81
|
return value;
|
|
82
82
|
}
|
|
83
83
|
|
|
@@ -87,8 +87,11 @@ static VALUE vec2_get_y(VALUE self) {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
static VALUE vec2_set_y(VALUE self, VALUE value) {
|
|
90
|
+
rb_check_frozen(self);
|
|
90
91
|
Vec2Data *data = vec2_get(self);
|
|
91
|
-
|
|
92
|
+
double component = NUM2DBL(value);
|
|
93
|
+
rb_check_frozen(self);
|
|
94
|
+
data->y = component;
|
|
92
95
|
return value;
|
|
93
96
|
}
|
|
94
97
|
|
|
@@ -129,7 +132,7 @@ VALUE vec2_dot(VALUE self, VALUE other) {
|
|
|
129
132
|
|
|
130
133
|
VALUE vec2_length(VALUE self) {
|
|
131
134
|
Vec2Data *a = vec2_get(self);
|
|
132
|
-
return DBL2NUM(
|
|
135
|
+
return DBL2NUM(hypot(a->x, a->y));
|
|
133
136
|
}
|
|
134
137
|
|
|
135
138
|
VALUE vec2_length_squared(VALUE self) {
|
|
@@ -139,15 +142,18 @@ VALUE vec2_length_squared(VALUE self) {
|
|
|
139
142
|
|
|
140
143
|
VALUE vec2_normalize(VALUE self) {
|
|
141
144
|
Vec2Data *a = vec2_get(self);
|
|
142
|
-
double
|
|
143
|
-
|
|
145
|
+
double values[] = {a->x, a->y};
|
|
146
|
+
larb_normalize(values, 2);
|
|
147
|
+
return vec2_build(rb_obj_class(self), values[0], values[1]);
|
|
144
148
|
}
|
|
145
149
|
|
|
146
150
|
VALUE vec2_normalize_bang(VALUE self) {
|
|
151
|
+
rb_check_frozen(self);
|
|
147
152
|
Vec2Data *a = vec2_get(self);
|
|
148
|
-
double
|
|
149
|
-
|
|
150
|
-
a->
|
|
153
|
+
double values[] = {a->x, a->y};
|
|
154
|
+
larb_normalize(values, 2);
|
|
155
|
+
a->x = values[0];
|
|
156
|
+
a->y = values[1];
|
|
151
157
|
return self;
|
|
152
158
|
}
|
|
153
159
|
|
|
@@ -173,12 +179,17 @@ VALUE vec2_aref(VALUE self, VALUE index) {
|
|
|
173
179
|
}
|
|
174
180
|
|
|
175
181
|
VALUE vec2_aset(VALUE self, VALUE index, VALUE value) {
|
|
182
|
+
rb_check_frozen(self);
|
|
176
183
|
Vec2Data *a = vec2_get(self);
|
|
177
184
|
long idx = NUM2LONG(index);
|
|
185
|
+
if (idx < 0) idx += 2;
|
|
186
|
+
if (idx < 0 || idx >= 2) rb_raise(rb_eIndexError, "Index out of range");
|
|
187
|
+
double component = NUM2DBL(value);
|
|
188
|
+
rb_check_frozen(self);
|
|
178
189
|
if (idx == 0) {
|
|
179
|
-
a->x =
|
|
190
|
+
a->x = component;
|
|
180
191
|
} else {
|
|
181
|
-
a->y =
|
|
192
|
+
a->y = component;
|
|
182
193
|
}
|
|
183
194
|
return value;
|
|
184
195
|
}
|
|
@@ -199,7 +210,10 @@ VALUE vec2_near(int argc, VALUE *argv, VALUE self) {
|
|
|
199
210
|
rb_scan_args(argc, argv, "11", &other, &epsilon);
|
|
200
211
|
Vec2Data *a = vec2_get(self);
|
|
201
212
|
Vec2Data *b = vec2_get(other);
|
|
202
|
-
double eps =
|
|
213
|
+
double eps = argc < 2 ? 1e-6 : NUM2DBL(epsilon);
|
|
214
|
+
if (!isfinite(eps) || eps <= 0.0) {
|
|
215
|
+
rb_raise(rb_eArgError, "epsilon must be finite and positive");
|
|
216
|
+
}
|
|
203
217
|
|
|
204
218
|
if (fabs(a->x - b->x) < eps && fabs(a->y - b->y) < eps) {
|
|
205
219
|
return Qtrue;
|
|
@@ -232,7 +246,7 @@ VALUE vec2_distance(VALUE self, VALUE other) {
|
|
|
232
246
|
Vec2Data *b = vec2_get(other);
|
|
233
247
|
double dx = a->x - b->x;
|
|
234
248
|
double dy = a->y - b->y;
|
|
235
|
-
return DBL2NUM(
|
|
249
|
+
return DBL2NUM(hypot(dx, dy));
|
|
236
250
|
}
|
|
237
251
|
|
|
238
252
|
VALUE vec2_distance_squared(VALUE self, VALUE other) {
|
|
@@ -265,12 +279,13 @@ VALUE vec2_reflect(VALUE self, VALUE normal) {
|
|
|
265
279
|
VALUE vec2_clamp_length(VALUE self, VALUE max_length) {
|
|
266
280
|
Vec2Data *a = vec2_get(self);
|
|
267
281
|
double max_len = NUM2DBL(max_length);
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
return self;
|
|
282
|
+
if (!isfinite(max_len) || max_len < 0.0) {
|
|
283
|
+
rb_raise(rb_eArgError, "max_length must be finite and nonnegative");
|
|
271
284
|
}
|
|
272
|
-
|
|
273
|
-
|
|
285
|
+
if (hypot(a->x, a->y) <= max_len) return self;
|
|
286
|
+
double values[] = {a->x, a->y};
|
|
287
|
+
larb_normalize(values, 2);
|
|
288
|
+
return vec2_build(rb_obj_class(self), values[0] * max_len, values[1] * max_len);
|
|
274
289
|
}
|
|
275
290
|
|
|
276
291
|
VALUE vec2_to_vec3(int argc, VALUE *argv, VALUE self) {
|
|
@@ -280,7 +295,7 @@ VALUE vec2_to_vec3(int argc, VALUE *argv, VALUE self) {
|
|
|
280
295
|
rb_scan_args(argc, argv, "01", &vz);
|
|
281
296
|
VALUE vec3_class = rb_const_get(mLarb, rb_intern("Vec3"));
|
|
282
297
|
return rb_funcall(vec3_class, rb_intern("new"), 3, DBL2NUM(a->x),
|
|
283
|
-
DBL2NUM(a->y),
|
|
298
|
+
DBL2NUM(a->y), argc == 0 ? DBL2NUM(0.0) : vz);
|
|
284
299
|
}
|
|
285
300
|
|
|
286
301
|
VALUE vec2_inspect(VALUE self) {
|
|
@@ -295,11 +310,19 @@ VALUE vec2_inspect(VALUE self) {
|
|
|
295
310
|
return str;
|
|
296
311
|
}
|
|
297
312
|
|
|
313
|
+
static VALUE vec2_initialize_copy(VALUE self, VALUE other) {
|
|
314
|
+
if (self == other) return self;
|
|
315
|
+
rb_obj_init_copy(self, other);
|
|
316
|
+
*vec2_get(self) = *vec2_get(other);
|
|
317
|
+
return self;
|
|
318
|
+
}
|
|
319
|
+
|
|
298
320
|
void Init_vec2(VALUE module) {
|
|
299
321
|
cVec2 = rb_define_class_under(module, "Vec2", rb_cObject);
|
|
300
322
|
|
|
301
323
|
rb_define_alloc_func(cVec2, vec2_alloc);
|
|
302
324
|
rb_define_method(cVec2, "initialize", vec2_initialize, -1);
|
|
325
|
+
rb_define_method(cVec2, "initialize_copy", vec2_initialize_copy, 1);
|
|
303
326
|
|
|
304
327
|
rb_define_singleton_method(cVec2, "[]", vec2_class_bracket, 2);
|
|
305
328
|
rb_define_singleton_method(cVec2, "zero", vec2_class_zero, 0);
|
data/ext/larb/vec3.c
CHANGED
|
@@ -20,11 +20,6 @@ static const rb_data_type_t vec3_type = {
|
|
|
20
20
|
|
|
21
21
|
static VALUE cVec3 = Qnil;
|
|
22
22
|
|
|
23
|
-
static double value_to_double(VALUE value) {
|
|
24
|
-
VALUE coerced = rb_funcall(value, rb_intern("to_f"), 0);
|
|
25
|
-
return NUM2DBL(coerced);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
23
|
static Vec3Data *vec3_get(VALUE obj) {
|
|
29
24
|
Vec3Data *data = NULL;
|
|
30
25
|
TypedData_Get_Struct(obj, Vec3Data, &vec3_type, data);
|
|
@@ -59,22 +54,24 @@ VALUE vec3_alloc(VALUE klass) {
|
|
|
59
54
|
}
|
|
60
55
|
|
|
61
56
|
VALUE vec3_initialize(int argc, VALUE *argv, VALUE self) {
|
|
57
|
+
rb_check_frozen(self);
|
|
62
58
|
VALUE vx = Qnil;
|
|
63
59
|
VALUE vy = Qnil;
|
|
64
60
|
VALUE vz = Qnil;
|
|
65
|
-
Vec3Data *data = vec3_get(self);
|
|
66
|
-
|
|
67
61
|
rb_scan_args(argc, argv, "03", &vx, &vy, &vz);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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;
|
|
72
69
|
return self;
|
|
73
70
|
}
|
|
74
71
|
|
|
75
72
|
static VALUE vec3_class_bracket(VALUE klass, VALUE x, VALUE y, VALUE z) {
|
|
76
|
-
return vec3_build(klass,
|
|
77
|
-
|
|
73
|
+
return vec3_build(klass, NUM2DBL(x), NUM2DBL(y),
|
|
74
|
+
NUM2DBL(z));
|
|
78
75
|
}
|
|
79
76
|
|
|
80
77
|
static VALUE vec3_class_zero(VALUE klass) {
|
|
@@ -115,8 +112,11 @@ static VALUE vec3_get_x(VALUE self) {
|
|
|
115
112
|
}
|
|
116
113
|
|
|
117
114
|
static VALUE vec3_set_x(VALUE self, VALUE value) {
|
|
115
|
+
rb_check_frozen(self);
|
|
118
116
|
Vec3Data *data = vec3_get(self);
|
|
119
|
-
|
|
117
|
+
double component = NUM2DBL(value);
|
|
118
|
+
rb_check_frozen(self);
|
|
119
|
+
data->x = component;
|
|
120
120
|
return value;
|
|
121
121
|
}
|
|
122
122
|
|
|
@@ -126,8 +126,11 @@ static VALUE vec3_get_y(VALUE self) {
|
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
static VALUE vec3_set_y(VALUE self, VALUE value) {
|
|
129
|
+
rb_check_frozen(self);
|
|
129
130
|
Vec3Data *data = vec3_get(self);
|
|
130
|
-
|
|
131
|
+
double component = NUM2DBL(value);
|
|
132
|
+
rb_check_frozen(self);
|
|
133
|
+
data->y = component;
|
|
131
134
|
return value;
|
|
132
135
|
}
|
|
133
136
|
|
|
@@ -137,8 +140,11 @@ static VALUE vec3_get_z(VALUE self) {
|
|
|
137
140
|
}
|
|
138
141
|
|
|
139
142
|
static VALUE vec3_set_z(VALUE self, VALUE value) {
|
|
143
|
+
rb_check_frozen(self);
|
|
140
144
|
Vec3Data *data = vec3_get(self);
|
|
141
|
-
|
|
145
|
+
double component = NUM2DBL(value);
|
|
146
|
+
rb_check_frozen(self);
|
|
147
|
+
data->z = component;
|
|
142
148
|
return value;
|
|
143
149
|
}
|
|
144
150
|
|
|
@@ -165,13 +171,13 @@ VALUE vec3_mul(VALUE self, VALUE scalar) {
|
|
|
165
171
|
a->z * b->z);
|
|
166
172
|
}
|
|
167
173
|
|
|
168
|
-
double s =
|
|
174
|
+
double s = NUM2DBL(scalar);
|
|
169
175
|
return vec3_build(rb_obj_class(self), a->x * s, a->y * s, a->z * s);
|
|
170
176
|
}
|
|
171
177
|
|
|
172
178
|
VALUE vec3_div(VALUE self, VALUE scalar) {
|
|
173
179
|
Vec3Data *a = vec3_get(self);
|
|
174
|
-
double s =
|
|
180
|
+
double s = NUM2DBL(scalar);
|
|
175
181
|
return vec3_build(rb_obj_class(self), a->x / s, a->y / s, a->z / s);
|
|
176
182
|
}
|
|
177
183
|
|
|
@@ -196,7 +202,7 @@ VALUE vec3_cross(VALUE self, VALUE other) {
|
|
|
196
202
|
|
|
197
203
|
VALUE vec3_length(VALUE self) {
|
|
198
204
|
Vec3Data *a = vec3_get(self);
|
|
199
|
-
return DBL2NUM(
|
|
205
|
+
return DBL2NUM(hypot(hypot(a->x, a->y), a->z));
|
|
200
206
|
}
|
|
201
207
|
|
|
202
208
|
VALUE vec3_length_squared(VALUE self) {
|
|
@@ -206,8 +212,9 @@ VALUE vec3_length_squared(VALUE self) {
|
|
|
206
212
|
|
|
207
213
|
VALUE vec3_normalize(VALUE self) {
|
|
208
214
|
Vec3Data *a = vec3_get(self);
|
|
209
|
-
double
|
|
210
|
-
|
|
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]);
|
|
211
218
|
}
|
|
212
219
|
|
|
213
220
|
VALUE vec3_reflect(VALUE self, VALUE normal) {
|
|
@@ -242,7 +249,7 @@ VALUE vec3_yz(VALUE self) {
|
|
|
242
249
|
VALUE vec3_lerp(VALUE self, VALUE other, VALUE t) {
|
|
243
250
|
Vec3Data *a = vec3_get(self);
|
|
244
251
|
Vec3Data *b = vec3_get(other);
|
|
245
|
-
double s =
|
|
252
|
+
double s = NUM2DBL(t);
|
|
246
253
|
return vec3_build(rb_obj_class(self), a->x + (b->x - a->x) * s,
|
|
247
254
|
a->y + (b->y - a->y) * s,
|
|
248
255
|
a->z + (b->z - a->z) * s);
|
|
@@ -265,7 +272,7 @@ VALUE vec3_to_vec4(int argc, VALUE *argv, VALUE self) {
|
|
|
265
272
|
VALUE vec4_class = rb_const_get(mLarb, rb_intern("Vec4"));
|
|
266
273
|
return rb_funcall(vec4_class, rb_intern("new"), 4, DBL2NUM(a->x),
|
|
267
274
|
DBL2NUM(a->y), DBL2NUM(a->z),
|
|
268
|
-
|
|
275
|
+
argc == 0 ? DBL2NUM(1.0) : vw);
|
|
269
276
|
}
|
|
270
277
|
|
|
271
278
|
VALUE vec3_aref(VALUE self, VALUE index) {
|
|
@@ -289,7 +296,10 @@ VALUE vec3_near(int argc, VALUE *argv, VALUE self) {
|
|
|
289
296
|
rb_scan_args(argc, argv, "11", &other, &epsilon);
|
|
290
297
|
Vec3Data *a = vec3_get(self);
|
|
291
298
|
Vec3Data *b = vec3_get(other);
|
|
292
|
-
double eps =
|
|
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
|
+
}
|
|
293
303
|
|
|
294
304
|
if (fabs(a->x - b->x) < eps && fabs(a->y - b->y) < eps &&
|
|
295
305
|
fabs(a->z - b->z) < eps) {
|
|
@@ -304,7 +314,7 @@ VALUE vec3_distance(VALUE self, VALUE other) {
|
|
|
304
314
|
double dx = a->x - b->x;
|
|
305
315
|
double dy = a->y - b->y;
|
|
306
316
|
double dz = a->z - b->z;
|
|
307
|
-
return DBL2NUM(
|
|
317
|
+
return DBL2NUM(hypot(hypot(dx, dy), dz));
|
|
308
318
|
}
|
|
309
319
|
|
|
310
320
|
VALUE vec3_distance_squared(VALUE self, VALUE other) {
|
|
@@ -319,75 +329,92 @@ VALUE vec3_distance_squared(VALUE self, VALUE other) {
|
|
|
319
329
|
VALUE vec3_angle_between(VALUE self, VALUE other) {
|
|
320
330
|
Vec3Data *a = vec3_get(self);
|
|
321
331
|
Vec3Data *b = vec3_get(other);
|
|
322
|
-
double
|
|
323
|
-
double
|
|
324
|
-
|
|
325
|
-
|
|
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];
|
|
326
337
|
return DBL2NUM(acos(clamp_double(d, -1.0, 1.0)));
|
|
327
338
|
}
|
|
328
339
|
|
|
329
340
|
VALUE vec3_project(VALUE self, VALUE onto) {
|
|
330
341
|
Vec3Data *a = vec3_get(self);
|
|
331
342
|
Vec3Data *b = vec3_get(onto);
|
|
332
|
-
double
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
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);
|
|
336
348
|
}
|
|
337
349
|
|
|
338
350
|
VALUE vec3_reject(VALUE self, VALUE from) {
|
|
339
|
-
|
|
340
|
-
Vec3Data *b = vec3_get(from);
|
|
341
|
-
double denom = b->x * b->x + b->y * b->y + b->z * b->z;
|
|
342
|
-
double scale = (a->x * b->x + a->y * b->y + a->z * b->z) / denom;
|
|
343
|
-
double px = b->x * scale;
|
|
344
|
-
double py = b->y * scale;
|
|
345
|
-
double pz = b->z * scale;
|
|
346
|
-
return vec3_build(rb_obj_class(self), a->x - px, a->y - py, a->z - pz);
|
|
351
|
+
return vec3_sub(self, vec3_project(self, from));
|
|
347
352
|
}
|
|
348
353
|
|
|
349
354
|
VALUE vec3_slerp(VALUE self, VALUE other, VALUE t) {
|
|
350
355
|
Vec3Data *a = vec3_get(self);
|
|
351
356
|
Vec3Data *b = vec3_get(other);
|
|
352
|
-
double s =
|
|
353
|
-
|
|
354
|
-
double
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
double
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
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);
|
|
371
396
|
}
|
|
372
397
|
|
|
373
398
|
VALUE vec3_clamp_length(VALUE self, VALUE max_length) {
|
|
374
399
|
Vec3Data *a = vec3_get(self);
|
|
375
|
-
double max_len =
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
return 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");
|
|
379
403
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
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);
|
|
383
408
|
}
|
|
384
409
|
|
|
385
410
|
VALUE vec3_normalize_bang(VALUE self) {
|
|
411
|
+
rb_check_frozen(self);
|
|
386
412
|
Vec3Data *a = vec3_get(self);
|
|
387
|
-
double
|
|
388
|
-
|
|
389
|
-
a->
|
|
390
|
-
a->
|
|
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];
|
|
391
418
|
return self;
|
|
392
419
|
}
|
|
393
420
|
|
|
@@ -440,11 +467,19 @@ VALUE vec3_inspect(VALUE self) {
|
|
|
440
467
|
return str;
|
|
441
468
|
}
|
|
442
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
|
+
|
|
443
477
|
void Init_vec3(VALUE module) {
|
|
444
478
|
cVec3 = rb_define_class_under(module, "Vec3", rb_cObject);
|
|
445
479
|
|
|
446
480
|
rb_define_alloc_func(cVec3, vec3_alloc);
|
|
447
481
|
rb_define_method(cVec3, "initialize", vec3_initialize, -1);
|
|
482
|
+
rb_define_method(cVec3, "initialize_copy", vec3_initialize_copy, 1);
|
|
448
483
|
|
|
449
484
|
rb_define_singleton_method(cVec3, "[]", vec3_class_bracket, 3);
|
|
450
485
|
rb_define_singleton_method(cVec3, "zero", vec3_class_zero, 0);
|