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/lib/larb/color.rb
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Larb
|
|
4
|
-
class Color
|
|
5
|
-
attr_accessor :r, :g, :b, :a
|
|
6
|
-
|
|
7
|
-
def initialize(r = 0.0, g = 0.0, b = 0.0, a = 1.0)
|
|
8
|
-
@r = r.to_f
|
|
9
|
-
@g = g.to_f
|
|
10
|
-
@b = b.to_f
|
|
11
|
-
@a = a.to_f
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def self.[](r, g, b, a = 1.0)
|
|
15
|
-
new(r, g, b, a)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def self.rgb(r, g, b)
|
|
19
|
-
new(r, g, b, 1.0)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def self.rgba(r, g, b, a)
|
|
23
|
-
new(r, g, b, a)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def self.from_bytes(r, g, b, a = 255)
|
|
27
|
-
new(r / 255.0, g / 255.0, b / 255.0, a / 255.0)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def self.from_hex(hex)
|
|
31
|
-
hex = hex.delete("#")
|
|
32
|
-
r = hex[0..1].to_i(16) / 255.0
|
|
33
|
-
g = hex[2..3].to_i(16) / 255.0
|
|
34
|
-
b = hex[4..5].to_i(16) / 255.0
|
|
35
|
-
a = hex.length > 6 ? hex[6..7].to_i(16) / 255.0 : 1.0
|
|
36
|
-
new(r, g, b, a)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def self.black
|
|
40
|
-
new(0, 0, 0, 1)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def self.white
|
|
44
|
-
new(1, 1, 1, 1)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def self.red
|
|
48
|
-
new(1, 0, 0, 1)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def self.green
|
|
52
|
-
new(0, 1, 0, 1)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def self.blue
|
|
56
|
-
new(0, 0, 1, 1)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def self.yellow
|
|
60
|
-
new(1, 1, 0, 1)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def self.cyan
|
|
64
|
-
new(0, 1, 1, 1)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def self.magenta
|
|
68
|
-
new(1, 0, 1, 1)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def self.transparent
|
|
72
|
-
new(0, 0, 0, 0)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def +(other)
|
|
76
|
-
Color.new(@r + other.r, @g + other.g, @b + other.b, @a + other.a)
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def -(other)
|
|
80
|
-
Color.new(@r - other.r, @g - other.g, @b - other.b, @a - other.a)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def *(scalar)
|
|
84
|
-
case scalar
|
|
85
|
-
when Numeric
|
|
86
|
-
Color.new(@r * scalar, @g * scalar, @b * scalar, @a * scalar)
|
|
87
|
-
when Color
|
|
88
|
-
Color.new(@r * scalar.r, @g * scalar.g, @b * scalar.b, @a * scalar.a)
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def lerp(other, t)
|
|
93
|
-
Color.new(
|
|
94
|
-
@r + (other.r - @r) * t,
|
|
95
|
-
@g + (other.g - @g) * t,
|
|
96
|
-
@b + (other.b - @b) * t,
|
|
97
|
-
@a + (other.a - @a) * t
|
|
98
|
-
)
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def clamp
|
|
102
|
-
Color.new(
|
|
103
|
-
@r.clamp(0.0, 1.0),
|
|
104
|
-
@g.clamp(0.0, 1.0),
|
|
105
|
-
@b.clamp(0.0, 1.0),
|
|
106
|
-
@a.clamp(0.0, 1.0)
|
|
107
|
-
)
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def to_bytes
|
|
111
|
-
[(@r * 255).round.clamp(0, 255),
|
|
112
|
-
(@g * 255).round.clamp(0, 255),
|
|
113
|
-
(@b * 255).round.clamp(0, 255),
|
|
114
|
-
(@a * 255).round.clamp(0, 255)]
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
def to_hex
|
|
118
|
-
r, g, b, a = to_bytes
|
|
119
|
-
format("#%02x%02x%02x%02x", r, g, b, a)
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
def to_vec3
|
|
123
|
-
Vec3.new(@r, @g, @b)
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
def to_vec4
|
|
127
|
-
Vec4.new(@r, @g, @b, @a)
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
def to_a
|
|
131
|
-
[@r, @g, @b, @a]
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def self.from_vec4(v)
|
|
135
|
-
new(v.x, v.y, v.z, v.w)
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
def self.from_vec3(v, a = 1.0)
|
|
139
|
-
new(v.x, v.y, v.z, a)
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
def inspect
|
|
143
|
-
"Color[#{@r}, #{@g}, #{@b}, #{@a}]"
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
alias to_s inspect
|
|
147
|
-
end
|
|
148
|
-
end
|
data/lib/larb/mat2.rb
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Larb
|
|
4
|
-
class Mat2
|
|
5
|
-
attr_reader :data
|
|
6
|
-
|
|
7
|
-
def initialize(data = nil)
|
|
8
|
-
@data = data || [1.0, 0.0, 0.0, 1.0]
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def self.identity
|
|
12
|
-
new
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def self.zero
|
|
16
|
-
new([0.0, 0.0, 0.0, 0.0])
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def self.rotation(radians)
|
|
20
|
-
c = Math.cos(radians)
|
|
21
|
-
s = Math.sin(radians)
|
|
22
|
-
new([c, s, -s, c])
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def self.scaling(x, y)
|
|
26
|
-
new([x.to_f, 0.0, 0.0, y.to_f])
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def self.from_vec2(v1, v2)
|
|
30
|
-
new([v1.x, v1.y, v2.x, v2.y])
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def [](i)
|
|
34
|
-
@data[i]
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def []=(i, v)
|
|
38
|
-
@data[i] = v.to_f
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def *(other)
|
|
42
|
-
case other
|
|
43
|
-
when Mat2
|
|
44
|
-
a = @data
|
|
45
|
-
b = other.data
|
|
46
|
-
Mat2.new([
|
|
47
|
-
a[0] * b[0] + a[2] * b[1],
|
|
48
|
-
a[1] * b[0] + a[3] * b[1],
|
|
49
|
-
a[0] * b[2] + a[2] * b[3],
|
|
50
|
-
a[1] * b[2] + a[3] * b[3]
|
|
51
|
-
])
|
|
52
|
-
when Vec2
|
|
53
|
-
Vec2.new(
|
|
54
|
-
@data[0] * other.x + @data[2] * other.y,
|
|
55
|
-
@data[1] * other.x + @data[3] * other.y
|
|
56
|
-
)
|
|
57
|
-
when Numeric
|
|
58
|
-
Mat2.new(@data.map { |v| v * other })
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def +(other)
|
|
63
|
-
Mat2.new(@data.zip(other.data).map { |a, b| a + b })
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def -(other)
|
|
67
|
-
Mat2.new(@data.zip(other.data).map { |a, b| a - b })
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def determinant
|
|
71
|
-
@data[0] * @data[3] - @data[2] * @data[1]
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def inverse
|
|
75
|
-
det = determinant
|
|
76
|
-
raise "Matrix is not invertible" if det.abs < 1e-10
|
|
77
|
-
|
|
78
|
-
inv_det = 1.0 / det
|
|
79
|
-
Mat2.new([
|
|
80
|
-
@data[3] * inv_det,
|
|
81
|
-
-@data[1] * inv_det,
|
|
82
|
-
-@data[2] * inv_det,
|
|
83
|
-
@data[0] * inv_det
|
|
84
|
-
])
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def transpose
|
|
88
|
-
Mat2.new([@data[0], @data[2], @data[1], @data[3]])
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def adjoint
|
|
92
|
-
Mat2.new([@data[3], -@data[1], -@data[2], @data[0]])
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def frobenius_norm
|
|
96
|
-
Math.sqrt(@data.sum { |v| v * v })
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def to_a
|
|
100
|
-
@data.dup
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def ==(other)
|
|
104
|
-
return false unless other.is_a?(Mat2)
|
|
105
|
-
|
|
106
|
-
@data == other.data
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def near?(other, epsilon = 1e-6)
|
|
110
|
-
@data.zip(other.data).all? { |a, b| (a - b).abs < epsilon }
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
def inspect
|
|
114
|
-
"Mat2[#{@data[0]}, #{@data[1]}, #{@data[2]}, #{@data[3]}]"
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
alias to_s inspect
|
|
118
|
-
end
|
|
119
|
-
end
|
data/lib/larb/mat2d.rb
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Larb
|
|
4
|
-
# 2D affine transformation matrix (2x3)
|
|
5
|
-
# Layout: [a, b, c, d, tx, ty]
|
|
6
|
-
# Represents:
|
|
7
|
-
# | a c tx |
|
|
8
|
-
# | b d ty |
|
|
9
|
-
# | 0 0 1 |
|
|
10
|
-
class Mat2d
|
|
11
|
-
attr_reader :data
|
|
12
|
-
|
|
13
|
-
def initialize(data = nil)
|
|
14
|
-
@data = data || [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def self.identity
|
|
18
|
-
new
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def self.zero
|
|
22
|
-
new([0.0, 0.0, 0.0, 0.0, 0.0, 0.0])
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def self.translation(x, y)
|
|
26
|
-
new([1.0, 0.0, 0.0, 1.0, x.to_f, y.to_f])
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def self.rotation(radians)
|
|
30
|
-
c = Math.cos(radians)
|
|
31
|
-
s = Math.sin(radians)
|
|
32
|
-
new([c, s, -s, c, 0.0, 0.0])
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def self.scaling(x, y)
|
|
36
|
-
new([x.to_f, 0.0, 0.0, y.to_f, 0.0, 0.0])
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def self.from_rotation_translation_scale(rotation, translation, scale)
|
|
40
|
-
c = Math.cos(rotation)
|
|
41
|
-
s = Math.sin(rotation)
|
|
42
|
-
new([
|
|
43
|
-
c * scale.x,
|
|
44
|
-
s * scale.x,
|
|
45
|
-
-s * scale.y,
|
|
46
|
-
c * scale.y,
|
|
47
|
-
translation.x,
|
|
48
|
-
translation.y
|
|
49
|
-
])
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def [](i)
|
|
53
|
-
@data[i]
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def []=(i, v)
|
|
57
|
-
@data[i] = v.to_f
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def *(other)
|
|
61
|
-
case other
|
|
62
|
-
when Mat2d
|
|
63
|
-
a = @data
|
|
64
|
-
b = other.data
|
|
65
|
-
Mat2d.new([
|
|
66
|
-
a[0] * b[0] + a[2] * b[1],
|
|
67
|
-
a[1] * b[0] + a[3] * b[1],
|
|
68
|
-
a[0] * b[2] + a[2] * b[3],
|
|
69
|
-
a[1] * b[2] + a[3] * b[3],
|
|
70
|
-
a[0] * b[4] + a[2] * b[5] + a[4],
|
|
71
|
-
a[1] * b[4] + a[3] * b[5] + a[5]
|
|
72
|
-
])
|
|
73
|
-
when Vec2
|
|
74
|
-
Vec2.new(
|
|
75
|
-
@data[0] * other.x + @data[2] * other.y + @data[4],
|
|
76
|
-
@data[1] * other.x + @data[3] * other.y + @data[5]
|
|
77
|
-
)
|
|
78
|
-
when Numeric
|
|
79
|
-
Mat2d.new(@data.map { |v| v * other })
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def +(other)
|
|
84
|
-
Mat2d.new(@data.zip(other.data).map { |a, b| a + b })
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def -(other)
|
|
88
|
-
Mat2d.new(@data.zip(other.data).map { |a, b| a - b })
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def determinant
|
|
92
|
-
@data[0] * @data[3] - @data[1] * @data[2]
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def inverse
|
|
96
|
-
a = @data
|
|
97
|
-
det = determinant
|
|
98
|
-
raise "Matrix is not invertible" if det.abs < 1e-10
|
|
99
|
-
|
|
100
|
-
inv_det = 1.0 / det
|
|
101
|
-
Mat2d.new([
|
|
102
|
-
a[3] * inv_det,
|
|
103
|
-
-a[1] * inv_det,
|
|
104
|
-
-a[2] * inv_det,
|
|
105
|
-
a[0] * inv_det,
|
|
106
|
-
(a[2] * a[5] - a[3] * a[4]) * inv_det,
|
|
107
|
-
(a[1] * a[4] - a[0] * a[5]) * inv_det
|
|
108
|
-
])
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def translate(x, y)
|
|
112
|
-
a = @data
|
|
113
|
-
Mat2d.new([
|
|
114
|
-
a[0], a[1], a[2], a[3],
|
|
115
|
-
a[0] * x + a[2] * y + a[4],
|
|
116
|
-
a[1] * x + a[3] * y + a[5]
|
|
117
|
-
])
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def rotate(radians)
|
|
121
|
-
self * Mat2d.rotation(radians)
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def scale(x, y)
|
|
125
|
-
a = @data
|
|
126
|
-
Mat2d.new([
|
|
127
|
-
a[0] * x, a[1] * x,
|
|
128
|
-
a[2] * y, a[3] * y,
|
|
129
|
-
a[4], a[5]
|
|
130
|
-
])
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
def extract_translation
|
|
134
|
-
Vec2.new(@data[4], @data[5])
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def extract_rotation
|
|
138
|
-
Math.atan2(@data[1], @data[0])
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def extract_scale
|
|
142
|
-
Vec2.new(
|
|
143
|
-
Math.sqrt(@data[0] * @data[0] + @data[1] * @data[1]),
|
|
144
|
-
Math.sqrt(@data[2] * @data[2] + @data[3] * @data[3])
|
|
145
|
-
)
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def frobenius_norm
|
|
149
|
-
Math.sqrt(@data.sum { |v| v * v })
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def to_mat3
|
|
153
|
-
Mat3.new([
|
|
154
|
-
@data[0], @data[1], 0,
|
|
155
|
-
@data[2], @data[3], 0,
|
|
156
|
-
@data[4], @data[5], 1
|
|
157
|
-
])
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
def to_a
|
|
161
|
-
@data.dup
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def ==(other)
|
|
165
|
-
return false unless other.is_a?(Mat2d)
|
|
166
|
-
|
|
167
|
-
@data == other.data
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
def near?(other, epsilon = 1e-6)
|
|
171
|
-
@data.zip(other.data).all? { |a, b| (a - b).abs < epsilon }
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
def inspect
|
|
175
|
-
"Mat2d[#{@data.map { |v| format('%.4f', v) }.join(', ')}]"
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
alias to_s inspect
|
|
179
|
-
end
|
|
180
|
-
end
|
data/lib/larb/mat3.rb
DELETED
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Larb
|
|
4
|
-
class Mat3
|
|
5
|
-
attr_reader :data
|
|
6
|
-
|
|
7
|
-
def initialize(data = nil)
|
|
8
|
-
@data = data || [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def self.identity
|
|
12
|
-
new
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def self.zero
|
|
16
|
-
new(Array.new(9, 0.0))
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def self.from_mat4(m)
|
|
20
|
-
new([
|
|
21
|
-
m[0], m[1], m[2],
|
|
22
|
-
m[4], m[5], m[6],
|
|
23
|
-
m[8], m[9], m[10]
|
|
24
|
-
])
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def self.from_mat2d(m)
|
|
28
|
-
new([
|
|
29
|
-
m[0], m[1], 0,
|
|
30
|
-
m[2], m[3], 0,
|
|
31
|
-
m[4], m[5], 1
|
|
32
|
-
])
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def self.from_quaternion(q)
|
|
36
|
-
x, y, z, w = q.x, q.y, q.z, q.w
|
|
37
|
-
x2 = x + x
|
|
38
|
-
y2 = y + y
|
|
39
|
-
z2 = z + z
|
|
40
|
-
xx = x * x2
|
|
41
|
-
yx = y * x2
|
|
42
|
-
yy = y * y2
|
|
43
|
-
zx = z * x2
|
|
44
|
-
zy = z * y2
|
|
45
|
-
zz = z * z2
|
|
46
|
-
wx = w * x2
|
|
47
|
-
wy = w * y2
|
|
48
|
-
wz = w * z2
|
|
49
|
-
|
|
50
|
-
new([
|
|
51
|
-
1 - yy - zz, yx + wz, zx - wy,
|
|
52
|
-
yx - wz, 1 - xx - zz, zy + wx,
|
|
53
|
-
zx + wy, zy - wx, 1 - xx - yy
|
|
54
|
-
])
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def self.normal_from_mat4(m)
|
|
58
|
-
from_mat4(m).inverse.transpose
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def self.projection(width, height)
|
|
62
|
-
new([
|
|
63
|
-
2.0 / width, 0, 0,
|
|
64
|
-
0, -2.0 / height, 0,
|
|
65
|
-
-1, 1, 1
|
|
66
|
-
])
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def self.translation(x, y)
|
|
70
|
-
new([
|
|
71
|
-
1, 0, 0,
|
|
72
|
-
0, 1, 0,
|
|
73
|
-
x.to_f, y.to_f, 1
|
|
74
|
-
])
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def self.rotation(radians)
|
|
78
|
-
c = Math.cos(radians)
|
|
79
|
-
s = Math.sin(radians)
|
|
80
|
-
new([
|
|
81
|
-
c, s, 0,
|
|
82
|
-
-s, c, 0,
|
|
83
|
-
0, 0, 1
|
|
84
|
-
])
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def self.scaling(x, y)
|
|
88
|
-
new([
|
|
89
|
-
x.to_f, 0, 0,
|
|
90
|
-
0, y.to_f, 0,
|
|
91
|
-
0, 0, 1
|
|
92
|
-
])
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def [](i)
|
|
96
|
-
@data[i]
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def []=(i, v)
|
|
100
|
-
@data[i] = v.to_f
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def *(other)
|
|
104
|
-
case other
|
|
105
|
-
when Mat3
|
|
106
|
-
a = @data
|
|
107
|
-
b = other.data
|
|
108
|
-
Mat3.new([
|
|
109
|
-
a[0] * b[0] + a[3] * b[1] + a[6] * b[2],
|
|
110
|
-
a[1] * b[0] + a[4] * b[1] + a[7] * b[2],
|
|
111
|
-
a[2] * b[0] + a[5] * b[1] + a[8] * b[2],
|
|
112
|
-
a[0] * b[3] + a[3] * b[4] + a[6] * b[5],
|
|
113
|
-
a[1] * b[3] + a[4] * b[4] + a[7] * b[5],
|
|
114
|
-
a[2] * b[3] + a[5] * b[4] + a[8] * b[5],
|
|
115
|
-
a[0] * b[6] + a[3] * b[7] + a[6] * b[8],
|
|
116
|
-
a[1] * b[6] + a[4] * b[7] + a[7] * b[8],
|
|
117
|
-
a[2] * b[6] + a[5] * b[7] + a[8] * b[8]
|
|
118
|
-
])
|
|
119
|
-
when Vec3
|
|
120
|
-
Vec3.new(
|
|
121
|
-
@data[0] * other.x + @data[3] * other.y + @data[6] * other.z,
|
|
122
|
-
@data[1] * other.x + @data[4] * other.y + @data[7] * other.z,
|
|
123
|
-
@data[2] * other.x + @data[5] * other.y + @data[8] * other.z
|
|
124
|
-
)
|
|
125
|
-
when Numeric
|
|
126
|
-
Mat3.new(@data.map { |v| v * other })
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
def +(other)
|
|
131
|
-
Mat3.new(@data.zip(other.data).map { |a, b| a + b })
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def -(other)
|
|
135
|
-
Mat3.new(@data.zip(other.data).map { |a, b| a - b })
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
def determinant
|
|
139
|
-
a = @data
|
|
140
|
-
a[0] * (a[4] * a[8] - a[5] * a[7]) -
|
|
141
|
-
a[3] * (a[1] * a[8] - a[2] * a[7]) +
|
|
142
|
-
a[6] * (a[1] * a[5] - a[2] * a[4])
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
def inverse
|
|
146
|
-
a = @data
|
|
147
|
-
det = determinant
|
|
148
|
-
raise "Matrix is not invertible" if det.abs < 1e-10
|
|
149
|
-
|
|
150
|
-
inv_det = 1.0 / det
|
|
151
|
-
Mat3.new([
|
|
152
|
-
(a[4] * a[8] - a[5] * a[7]) * inv_det,
|
|
153
|
-
(a[2] * a[7] - a[1] * a[8]) * inv_det,
|
|
154
|
-
(a[1] * a[5] - a[2] * a[4]) * inv_det,
|
|
155
|
-
(a[5] * a[6] - a[3] * a[8]) * inv_det,
|
|
156
|
-
(a[0] * a[8] - a[2] * a[6]) * inv_det,
|
|
157
|
-
(a[2] * a[3] - a[0] * a[5]) * inv_det,
|
|
158
|
-
(a[3] * a[7] - a[4] * a[6]) * inv_det,
|
|
159
|
-
(a[1] * a[6] - a[0] * a[7]) * inv_det,
|
|
160
|
-
(a[0] * a[4] - a[1] * a[3]) * inv_det
|
|
161
|
-
])
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def transpose
|
|
165
|
-
Mat3.new([
|
|
166
|
-
@data[0], @data[3], @data[6],
|
|
167
|
-
@data[1], @data[4], @data[7],
|
|
168
|
-
@data[2], @data[5], @data[8]
|
|
169
|
-
])
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
def adjoint
|
|
173
|
-
a = @data
|
|
174
|
-
Mat3.new([
|
|
175
|
-
a[4] * a[8] - a[5] * a[7],
|
|
176
|
-
a[2] * a[7] - a[1] * a[8],
|
|
177
|
-
a[1] * a[5] - a[2] * a[4],
|
|
178
|
-
a[5] * a[6] - a[3] * a[8],
|
|
179
|
-
a[0] * a[8] - a[2] * a[6],
|
|
180
|
-
a[2] * a[3] - a[0] * a[5],
|
|
181
|
-
a[3] * a[7] - a[4] * a[6],
|
|
182
|
-
a[1] * a[6] - a[0] * a[7],
|
|
183
|
-
a[0] * a[4] - a[1] * a[3]
|
|
184
|
-
])
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
def frobenius_norm
|
|
188
|
-
Math.sqrt(@data.sum { |v| v * v })
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
def translate(x, y)
|
|
192
|
-
a = @data
|
|
193
|
-
Mat3.new([
|
|
194
|
-
a[0], a[1], a[2],
|
|
195
|
-
a[3], a[4], a[5],
|
|
196
|
-
x * a[0] + y * a[3] + a[6],
|
|
197
|
-
x * a[1] + y * a[4] + a[7],
|
|
198
|
-
x * a[2] + y * a[5] + a[8]
|
|
199
|
-
])
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
def rotate(radians)
|
|
203
|
-
self * Mat3.rotation(radians)
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
def scale(x, y)
|
|
207
|
-
a = @data
|
|
208
|
-
Mat3.new([
|
|
209
|
-
a[0] * x, a[1] * x, a[2] * x,
|
|
210
|
-
a[3] * y, a[4] * y, a[5] * y,
|
|
211
|
-
a[6], a[7], a[8]
|
|
212
|
-
])
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
def to_a
|
|
216
|
-
@data.dup
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
def ==(other)
|
|
220
|
-
return false unless other.is_a?(Mat3)
|
|
221
|
-
|
|
222
|
-
@data == other.data
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
def near?(other, epsilon = 1e-6)
|
|
226
|
-
@data.zip(other.data).all? { |a, b| (a - b).abs < epsilon }
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
def inspect
|
|
230
|
-
"Mat3[\n" \
|
|
231
|
-
" #{@data[0..2].map { |v| format('%8.4f', v) }.join(', ')}\n" \
|
|
232
|
-
" #{@data[3..5].map { |v| format('%8.4f', v) }.join(', ')}\n" \
|
|
233
|
-
" #{@data[6..8].map { |v| format('%8.4f', v) }.join(', ')}\n]"
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
alias to_s inspect
|
|
237
|
-
end
|
|
238
|
-
end
|