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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/README.md +14 -1
  4. data/ext/larb/color.c +446 -0
  5. data/ext/larb/color.h +35 -0
  6. data/ext/larb/extconf.rb +11 -0
  7. data/ext/larb/larb.c +27 -0
  8. data/ext/larb/larb.h +8 -0
  9. data/ext/larb/mat2.c +300 -0
  10. data/ext/larb/mat2.h +30 -0
  11. data/ext/larb/mat2d.c +380 -0
  12. data/ext/larb/mat2d.h +35 -0
  13. data/ext/larb/mat3.c +469 -0
  14. data/ext/larb/mat3.h +33 -0
  15. data/ext/larb/mat4.c +671 -0
  16. data/ext/larb/mat4.h +31 -0
  17. data/ext/larb/quat.c +523 -0
  18. data/ext/larb/quat.h +39 -0
  19. data/ext/larb/quat2.c +473 -0
  20. data/ext/larb/quat2.h +39 -0
  21. data/ext/larb/vec2.c +342 -0
  22. data/ext/larb/vec2.h +43 -0
  23. data/ext/larb/vec3.c +503 -0
  24. data/ext/larb/vec3.h +52 -0
  25. data/ext/larb/vec4.c +340 -0
  26. data/ext/larb/vec4.h +38 -0
  27. data/lib/larb/version.rb +5 -0
  28. data/lib/larb.rb +2 -14
  29. data/test/larb/color_test.rb +278 -0
  30. data/test/larb/mat2_test.rb +144 -0
  31. data/test/larb/mat2d_test.rb +172 -0
  32. data/test/larb/mat3_test.rb +147 -0
  33. data/test/larb/mat4_test.rb +270 -0
  34. data/test/larb/quat2_test.rb +161 -0
  35. data/test/larb/quat_test.rb +224 -0
  36. data/test/larb/vec2_test.rb +251 -0
  37. data/test/larb/vec3_test.rb +310 -0
  38. data/test/larb/vec4_test.rb +189 -0
  39. data/test/test_helper.rb +4 -0
  40. metadata +53 -14
  41. data/Rakefile +0 -11
  42. data/lib/larb/color.rb +0 -148
  43. data/lib/larb/mat2.rb +0 -119
  44. data/lib/larb/mat2d.rb +0 -180
  45. data/lib/larb/mat3.rb +0 -238
  46. data/lib/larb/mat4.rb +0 -329
  47. data/lib/larb/quat.rb +0 -238
  48. data/lib/larb/quat2.rb +0 -193
  49. data/lib/larb/vec2.rb +0 -150
  50. data/lib/larb/vec3.rb +0 -218
  51. data/lib/larb/vec4.rb +0 -125
data/lib/larb/quat2.rb DELETED
@@ -1,193 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Larb
4
- # Dual Quaternion for rigid body transformations
5
- # Represented as 8 values: [real quaternion (4), dual quaternion (4)]
6
- # real: rotation, dual: translation encoded
7
- class Quat2
8
- attr_reader :data
9
-
10
- def initialize(data = nil)
11
- @data = data || [0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0]
12
- end
13
-
14
- def self.identity
15
- new
16
- end
17
-
18
- def self.from_rotation_translation(rotation, translation)
19
- rx, ry, rz, rw = rotation.x, rotation.y, rotation.z, rotation.w
20
- tx, ty, tz = translation.x, translation.y, translation.z
21
-
22
- new([
23
- rx, ry, rz, rw,
24
- (tx * rw + ty * rz - tz * ry) * 0.5,
25
- (ty * rw + tz * rx - tx * rz) * 0.5,
26
- (tz * rw + tx * ry - ty * rx) * 0.5,
27
- (-tx * rx - ty * ry - tz * rz) * 0.5
28
- ])
29
- end
30
-
31
- def self.from_translation(translation)
32
- from_rotation_translation(Quat.identity, translation)
33
- end
34
-
35
- def self.from_rotation(rotation)
36
- new([rotation.x, rotation.y, rotation.z, rotation.w, 0, 0, 0, 0])
37
- end
38
-
39
- def self.from_mat4(m)
40
- rotation = m.extract_rotation
41
- translation = m.extract_translation
42
- from_rotation_translation(rotation, translation)
43
- end
44
-
45
- def real
46
- Quat.new(@data[0], @data[1], @data[2], @data[3])
47
- end
48
-
49
- def dual
50
- Quat.new(@data[4], @data[5], @data[6], @data[7])
51
- end
52
-
53
- def [](i)
54
- @data[i]
55
- end
56
-
57
- def []=(i, v)
58
- @data[i] = v.to_f
59
- end
60
-
61
- def *(other)
62
- case other
63
- when Quat2
64
- ax0, ay0, az0, aw0 = @data[0], @data[1], @data[2], @data[3]
65
- bx1, by1, bz1, bw1 = @data[4], @data[5], @data[6], @data[7]
66
- ax1, ay1, az1, aw1 = other.data[0], other.data[1], other.data[2], other.data[3]
67
- bx0, by0, bz0, bw0 = other.data[4], other.data[5], other.data[6], other.data[7]
68
-
69
- Quat2.new([
70
- ax0 * aw1 + aw0 * ax1 + ay0 * az1 - az0 * ay1,
71
- ay0 * aw1 + aw0 * ay1 + az0 * ax1 - ax0 * az1,
72
- az0 * aw1 + aw0 * az1 + ax0 * ay1 - ay0 * ax1,
73
- aw0 * aw1 - ax0 * ax1 - ay0 * ay1 - az0 * az1,
74
- ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0 +
75
- bx1 * aw1 + bw1 * ax1 + by1 * az1 - bz1 * ay1,
76
- ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0 +
77
- by1 * aw1 + bw1 * ay1 + bz1 * ax1 - bx1 * az1,
78
- az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0 +
79
- bz1 * aw1 + bw1 * az1 + bx1 * ay1 - by1 * ax1,
80
- aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0 +
81
- bw1 * aw1 - bx1 * ax1 - by1 * ay1 - bz1 * az1
82
- ])
83
- when Vec3
84
- transform_point(other)
85
- when Numeric
86
- Quat2.new(@data.map { |v| v * other })
87
- end
88
- end
89
-
90
- def +(other)
91
- Quat2.new(@data.zip(other.data).map { |a, b| a + b })
92
- end
93
-
94
- def -(other)
95
- Quat2.new(@data.zip(other.data).map { |a, b| a - b })
96
- end
97
-
98
- def dot(other)
99
- @data[0] * other.data[0] + @data[1] * other.data[1] +
100
- @data[2] * other.data[2] + @data[3] * other.data[3]
101
- end
102
-
103
- def length
104
- Math.sqrt(length_squared)
105
- end
106
-
107
- def length_squared
108
- @data[0..3].sum { |v| v * v }
109
- end
110
-
111
- def normalize
112
- len = length
113
- return Quat2.new(@data.dup) if len < 1e-10
114
-
115
- inv_len = 1.0 / len
116
- Quat2.new(@data.map { |v| v * inv_len })
117
- end
118
-
119
- def normalize!
120
- len = length
121
- return self if len < 1e-10
122
-
123
- inv_len = 1.0 / len
124
- @data.map! { |v| v * inv_len }
125
- self
126
- end
127
-
128
- def conjugate
129
- Quat2.new([
130
- -@data[0], -@data[1], -@data[2], @data[3],
131
- -@data[4], -@data[5], -@data[6], @data[7]
132
- ])
133
- end
134
-
135
- def inverse
136
- len_sq = length_squared
137
- return conjugate if len_sq < 1e-10
138
-
139
- inv_len_sq = 1.0 / len_sq
140
- conj = conjugate
141
- Quat2.new(conj.data.map { |v| v * inv_len_sq })
142
- end
143
-
144
- def translation
145
- ax, ay, az, aw = @data[0], @data[1], @data[2], @data[3]
146
- bx, by, bz, bw = @data[4], @data[5], @data[6], @data[7]
147
- # t = 2 * dual * conjugate(real)
148
- Vec3.new(
149
- 2 * (-bw * ax + bx * aw - by * az + bz * ay),
150
- 2 * (-bw * ay + by * aw - bz * ax + bx * az),
151
- 2 * (-bw * az + bz * aw - bx * ay + by * ax)
152
- )
153
- end
154
-
155
- def rotation
156
- real.normalize
157
- end
158
-
159
- def transform_point(point)
160
- rotation * point + translation
161
- end
162
-
163
- def lerp(other, t)
164
- Quat2.new(@data.zip(other.data).map { |a, b| a + (b - a) * t }).normalize
165
- end
166
-
167
- def to_mat4
168
- rot = rotation
169
- trans = translation
170
- Mat4.from_quaternion(rot) * Mat4.translation(trans.x, trans.y, trans.z)
171
- end
172
-
173
- def to_a
174
- @data.dup
175
- end
176
-
177
- def ==(other)
178
- return false unless other.is_a?(Quat2)
179
-
180
- @data == other.data
181
- end
182
-
183
- def near?(other, epsilon = 1e-6)
184
- @data.zip(other.data).all? { |a, b| (a - b).abs < epsilon }
185
- end
186
-
187
- def inspect
188
- "Quat2[real: #{real.inspect}, dual: #{dual.inspect}]"
189
- end
190
-
191
- alias to_s inspect
192
- end
193
- end
data/lib/larb/vec2.rb DELETED
@@ -1,150 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Larb
4
- class Vec2
5
- attr_accessor :x, :y
6
-
7
- def initialize(x = 0.0, y = 0.0)
8
- @x = x.to_f
9
- @y = y.to_f
10
- end
11
-
12
- def self.[](x, y)
13
- new(x, y)
14
- end
15
-
16
- def self.zero
17
- new(0, 0)
18
- end
19
-
20
- def self.one
21
- new(1, 1)
22
- end
23
-
24
- def +(other)
25
- Vec2.new(@x + other.x, @y + other.y)
26
- end
27
-
28
- def -(other)
29
- Vec2.new(@x - other.x, @y - other.y)
30
- end
31
-
32
- def *(scalar)
33
- Vec2.new(@x * scalar, @y * scalar)
34
- end
35
-
36
- def /(scalar)
37
- Vec2.new(@x / scalar, @y / scalar)
38
- end
39
-
40
- def -@
41
- Vec2.new(-@x, -@y)
42
- end
43
-
44
- def dot(other)
45
- @x * other.x + @y * other.y
46
- end
47
-
48
- def length
49
- Math.sqrt(@x * @x + @y * @y)
50
- end
51
-
52
- def length_squared
53
- @x * @x + @y * @y
54
- end
55
-
56
- def normalize
57
- self / length
58
- end
59
-
60
- def normalize!
61
- l = length
62
- @x /= l
63
- @y /= l
64
- self
65
- end
66
-
67
- def lerp(other, t)
68
- self + (other - self) * t
69
- end
70
-
71
- def to_a
72
- [@x, @y]
73
- end
74
-
75
- def [](i)
76
- to_a[i]
77
- end
78
-
79
- def []=(i, v)
80
- if i == 0
81
- @x = v
82
- else
83
- @y = v
84
- end
85
- end
86
-
87
- def ==(other)
88
- return false unless other.is_a?(Vec2)
89
-
90
- @x == other.x && @y == other.y
91
- end
92
-
93
- def near?(other, epsilon = 1e-6)
94
- (@x - other.x).abs < epsilon && (@y - other.y).abs < epsilon
95
- end
96
-
97
- def angle
98
- Math.atan2(@y, @x)
99
- end
100
-
101
- def angle_to(other)
102
- Math.atan2(other.y - @y, other.x - @x)
103
- end
104
-
105
- def rotate(radians)
106
- c = Math.cos(radians)
107
- s = Math.sin(radians)
108
- Vec2.new(@x * c - @y * s, @x * s + @y * c)
109
- end
110
-
111
- def distance(other)
112
- Math.sqrt(distance_squared(other))
113
- end
114
-
115
- def distance_squared(other)
116
- dx = @x - other.x
117
- dy = @y - other.y
118
- dx * dx + dy * dy
119
- end
120
-
121
- def cross(other)
122
- @x * other.y - @y * other.x
123
- end
124
-
125
- def perpendicular
126
- Vec2.new(-@y, @x)
127
- end
128
-
129
- def reflect(normal)
130
- self - normal * (2 * dot(normal))
131
- end
132
-
133
- def clamp_length(max_length)
134
- len_sq = length_squared
135
- return self if len_sq <= max_length * max_length
136
-
137
- self * (max_length / Math.sqrt(len_sq))
138
- end
139
-
140
- def to_vec3(z = 0.0)
141
- Vec3.new(@x, @y, z)
142
- end
143
-
144
- def inspect
145
- "Vec2[#{@x}, #{@y}]"
146
- end
147
-
148
- alias to_s inspect
149
- end
150
- end
data/lib/larb/vec3.rb DELETED
@@ -1,218 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Larb
4
- class Vec3
5
- attr_accessor :x, :y, :z
6
-
7
- def initialize(x = 0.0, y = 0.0, z = 0.0)
8
- @x = x.to_f
9
- @y = y.to_f
10
- @z = z.to_f
11
- end
12
-
13
- def self.[](x, y, z)
14
- new(x, y, z)
15
- end
16
-
17
- def self.zero
18
- new(0, 0, 0)
19
- end
20
-
21
- def self.one
22
- new(1, 1, 1)
23
- end
24
-
25
- def self.up
26
- new(0, 1, 0)
27
- end
28
-
29
- def self.down
30
- new(0, -1, 0)
31
- end
32
-
33
- def self.forward
34
- new(0, 0, -1)
35
- end
36
-
37
- def self.back
38
- new(0, 0, 1)
39
- end
40
-
41
- def self.right
42
- new(1, 0, 0)
43
- end
44
-
45
- def self.left
46
- new(-1, 0, 0)
47
- end
48
-
49
- def +(other)
50
- Vec3.new(@x + other.x, @y + other.y, @z + other.z)
51
- end
52
-
53
- def -(other)
54
- Vec3.new(@x - other.x, @y - other.y, @z - other.z)
55
- end
56
-
57
- def *(scalar)
58
- case scalar
59
- when Numeric
60
- Vec3.new(@x * scalar, @y * scalar, @z * scalar)
61
- when Vec3
62
- Vec3.new(@x * scalar.x, @y * scalar.y, @z * scalar.z)
63
- end
64
- end
65
-
66
- def /(scalar)
67
- Vec3.new(@x / scalar, @y / scalar, @z / scalar)
68
- end
69
-
70
- def -@
71
- Vec3.new(-@x, -@y, -@z)
72
- end
73
-
74
- def dot(other)
75
- @x * other.x + @y * other.y + @z * other.z
76
- end
77
-
78
- def cross(other)
79
- Vec3.new(
80
- @y * other.z - @z * other.y,
81
- @z * other.x - @x * other.z,
82
- @x * other.y - @y * other.x
83
- )
84
- end
85
-
86
- def length
87
- Math.sqrt(@x * @x + @y * @y + @z * @z)
88
- end
89
-
90
- def length_squared
91
- @x * @x + @y * @y + @z * @z
92
- end
93
-
94
- def normalize
95
- self / length
96
- end
97
-
98
- def reflect(normal)
99
- self - normal * (2 * dot(normal))
100
- end
101
-
102
- def xy
103
- Vec2.new(@x, @y)
104
- end
105
-
106
- def xz
107
- Vec2.new(@x, @z)
108
- end
109
-
110
- def yz
111
- Vec2.new(@y, @z)
112
- end
113
-
114
- def lerp(other, t)
115
- self + (other - self) * t
116
- end
117
-
118
- def to_a
119
- [@x, @y, @z]
120
- end
121
-
122
- def to_vec4(w = 1.0)
123
- Vec4.new(@x, @y, @z, w)
124
- end
125
-
126
- def [](i)
127
- to_a[i]
128
- end
129
-
130
- def ==(other)
131
- return false unless other.is_a?(Vec3)
132
-
133
- @x == other.x && @y == other.y && @z == other.z
134
- end
135
-
136
- def near?(other, epsilon = 1e-6)
137
- (@x - other.x).abs < epsilon &&
138
- (@y - other.y).abs < epsilon &&
139
- (@z - other.z).abs < epsilon
140
- end
141
-
142
- def distance(other)
143
- Math.sqrt(distance_squared(other))
144
- end
145
-
146
- def distance_squared(other)
147
- dx = @x - other.x
148
- dy = @y - other.y
149
- dz = @z - other.z
150
- dx * dx + dy * dy + dz * dz
151
- end
152
-
153
- def angle_between(other)
154
- d = dot(other) / (length * other.length)
155
- Math.acos(d.clamp(-1.0, 1.0))
156
- end
157
-
158
- def project(onto)
159
- onto * (dot(onto) / onto.length_squared)
160
- end
161
-
162
- def reject(from)
163
- self - project(from)
164
- end
165
-
166
- def slerp(other, t)
167
- dot_val = normalize.dot(other.normalize).clamp(-1.0, 1.0)
168
- theta = Math.acos(dot_val) * t
169
- relative = (other - self * dot_val).normalize
170
- self * Math.cos(theta) + relative * Math.sin(theta)
171
- end
172
-
173
- def clamp_length(max_length)
174
- len_sq = length_squared
175
- return self if len_sq <= max_length * max_length
176
-
177
- self * (max_length / Math.sqrt(len_sq))
178
- end
179
-
180
- def normalize!
181
- l = length
182
- @x /= l
183
- @y /= l
184
- @z /= l
185
- self
186
- end
187
-
188
- def min(other)
189
- Vec3.new([@x, other.x].min, [@y, other.y].min, [@z, other.z].min)
190
- end
191
-
192
- def max(other)
193
- Vec3.new([@x, other.x].max, [@y, other.y].max, [@z, other.z].max)
194
- end
195
-
196
- def abs
197
- Vec3.new(@x.abs, @y.abs, @z.abs)
198
- end
199
-
200
- def floor
201
- Vec3.new(@x.floor, @y.floor, @z.floor)
202
- end
203
-
204
- def ceil
205
- Vec3.new(@x.ceil, @y.ceil, @z.ceil)
206
- end
207
-
208
- def round
209
- Vec3.new(@x.round, @y.round, @z.round)
210
- end
211
-
212
- def inspect
213
- "Vec3[#{@x}, #{@y}, #{@z}]"
214
- end
215
-
216
- alias to_s inspect
217
- end
218
- end
data/lib/larb/vec4.rb DELETED
@@ -1,125 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Larb
4
- class Vec4
5
- attr_accessor :x, :y, :z, :w
6
-
7
- def initialize(x = 0.0, y = 0.0, z = 0.0, w = 1.0)
8
- @x = x.to_f
9
- @y = y.to_f
10
- @z = z.to_f
11
- @w = w.to_f
12
- end
13
-
14
- def self.[](x, y, z, w = 1.0)
15
- new(x, y, z, w)
16
- end
17
-
18
- def self.zero
19
- new(0, 0, 0, 0)
20
- end
21
-
22
- def self.one
23
- new(1, 1, 1, 1)
24
- end
25
-
26
- def +(other)
27
- Vec4.new(@x + other.x, @y + other.y, @z + other.z, @w + other.w)
28
- end
29
-
30
- def -(other)
31
- Vec4.new(@x - other.x, @y - other.y, @z - other.z, @w - other.w)
32
- end
33
-
34
- def *(scalar)
35
- Vec4.new(@x * scalar, @y * scalar, @z * scalar, @w * scalar)
36
- end
37
-
38
- def /(scalar)
39
- Vec4.new(@x / scalar, @y / scalar, @z / scalar, @w / scalar)
40
- end
41
-
42
- def -@
43
- Vec4.new(-@x, -@y, -@z, -@w)
44
- end
45
-
46
- def dot(other)
47
- @x * other.x + @y * other.y + @z * other.z + @w * other.w
48
- end
49
-
50
- def length
51
- Math.sqrt(length_squared)
52
- end
53
-
54
- def length_squared
55
- @x * @x + @y * @y + @z * @z + @w * @w
56
- end
57
-
58
- def normalize
59
- self / length
60
- end
61
-
62
- def normalize!
63
- l = length
64
- @x /= l
65
- @y /= l
66
- @z /= l
67
- @w /= l
68
- self
69
- end
70
-
71
- def perspective_divide
72
- return Vec3.new(@x, @y, @z) if @w == 0 || @w == 1
73
-
74
- Vec3.new(@x / @w, @y / @w, @z / @w)
75
- end
76
-
77
- def xyz
78
- Vec3.new(@x, @y, @z)
79
- end
80
-
81
- def xy
82
- Vec2.new(@x, @y)
83
- end
84
-
85
- def rgb
86
- Vec3.new(@x, @y, @z)
87
- end
88
-
89
- def to_a
90
- [@x, @y, @z, @w]
91
- end
92
-
93
- def [](i)
94
- to_a[i]
95
- end
96
-
97
- def ==(other)
98
- return false unless other.is_a?(Vec4)
99
-
100
- @x == other.x && @y == other.y && @z == other.z && @w == other.w
101
- end
102
-
103
- def near?(other, epsilon = 1e-6)
104
- (@x - other.x).abs < epsilon &&
105
- (@y - other.y).abs < epsilon &&
106
- (@z - other.z).abs < epsilon &&
107
- (@w - other.w).abs < epsilon
108
- end
109
-
110
- def lerp(other, t)
111
- Vec4.new(
112
- @x + (other.x - @x) * t,
113
- @y + (other.y - @y) * t,
114
- @z + (other.z - @z) * t,
115
- @w + (other.w - @w) * t
116
- )
117
- end
118
-
119
- def inspect
120
- "Vec4[#{@x}, #{@y}, #{@z}, #{@w}]"
121
- end
122
-
123
- alias to_s inspect
124
- end
125
- end