glmath 0.0.1.dev
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 +7 -0
- data/lib/glmath.rb +21 -0
- data/lib/glmath/euler_angle.rb +60 -0
- data/lib/glmath/line.rb +19 -0
- data/lib/glmath/matrix.rb +413 -0
- data/lib/glmath/matrix2.rb +81 -0
- data/lib/glmath/matrix3.rb +108 -0
- data/lib/glmath/matrix4.rb +145 -0
- data/lib/glmath/matrix_stack.rb +91 -0
- data/lib/glmath/quaternion.rb +212 -0
- data/lib/glmath/rect.rb +135 -0
- data/lib/glmath/scalar.rb +33 -0
- data/lib/glmath/vector.rb +155 -0
- data/lib/glmath/vector2.rb +45 -0
- data/lib/glmath/vector3.rb +66 -0
- data/lib/glmath/vector4.rb +54 -0
- data/lib/version.rb +4 -0
- metadata +90 -0
data/lib/glmath/rect.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
module GLMath
|
2
|
+
class Rect
|
3
|
+
attr_accessor :x, :y, :width, :height
|
4
|
+
|
5
|
+
def initialize(x = 0, y = 0, width = 0, height = 0)
|
6
|
+
self.x, self.y, self.width , self.height = x, y, width, height
|
7
|
+
end
|
8
|
+
|
9
|
+
def [](v)
|
10
|
+
send v
|
11
|
+
end
|
12
|
+
|
13
|
+
def []=(k, v)
|
14
|
+
send("#{k}=", v)
|
15
|
+
end
|
16
|
+
|
17
|
+
def ==(r)
|
18
|
+
return false unless r.is_a? Rect
|
19
|
+
%w(x y width height).map{ |v| self[v] == r[v] }.all?{ |v| v }
|
20
|
+
end
|
21
|
+
|
22
|
+
def bottom
|
23
|
+
y
|
24
|
+
end
|
25
|
+
|
26
|
+
def bottom=(v)
|
27
|
+
self.y = v
|
28
|
+
end
|
29
|
+
|
30
|
+
def center
|
31
|
+
[center_x, center_y]
|
32
|
+
end
|
33
|
+
|
34
|
+
def center_x
|
35
|
+
x + width/2
|
36
|
+
end
|
37
|
+
|
38
|
+
def center_y
|
39
|
+
y + height/2
|
40
|
+
end
|
41
|
+
|
42
|
+
def center=(c)
|
43
|
+
cx, cy = c
|
44
|
+
self.x, self.y = cx - width/2, cy - height/2
|
45
|
+
end
|
46
|
+
|
47
|
+
def include?(x, y)
|
48
|
+
(left..right).include?(x) && (bottom..top).include?(y)
|
49
|
+
end
|
50
|
+
|
51
|
+
def left
|
52
|
+
x
|
53
|
+
end
|
54
|
+
|
55
|
+
def left=(v)
|
56
|
+
self.x = v
|
57
|
+
end
|
58
|
+
|
59
|
+
def outside?(x, y)
|
60
|
+
!include?(x, y)
|
61
|
+
end
|
62
|
+
|
63
|
+
def right
|
64
|
+
x+width
|
65
|
+
end
|
66
|
+
|
67
|
+
def right=(v)
|
68
|
+
self.width = v - x
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_a
|
72
|
+
[left, bottom, width, height]
|
73
|
+
end
|
74
|
+
|
75
|
+
def area
|
76
|
+
width * height
|
77
|
+
end
|
78
|
+
|
79
|
+
def perimeter
|
80
|
+
2 * width + 2 * area
|
81
|
+
end
|
82
|
+
|
83
|
+
def diagonals
|
84
|
+
[diagonal_top_left, diagonal_top_right]
|
85
|
+
end
|
86
|
+
|
87
|
+
def diagonal_top_left
|
88
|
+
LineSegment.new(top, left, bottom, right)
|
89
|
+
end
|
90
|
+
|
91
|
+
def diagonal_top_right
|
92
|
+
LineSegment.new(top, right, bottom, left)
|
93
|
+
end
|
94
|
+
|
95
|
+
def diagonal_length
|
96
|
+
Math.sqrt(width ** 2 + height ** 2)
|
97
|
+
end
|
98
|
+
|
99
|
+
def to_s
|
100
|
+
"<Rect #{%w'left bottom width height'.map { |name| "#{name} = #{send(name)}" }.join(', ')}>"
|
101
|
+
end
|
102
|
+
|
103
|
+
def top
|
104
|
+
y + height
|
105
|
+
end
|
106
|
+
|
107
|
+
def top=(v)
|
108
|
+
self.height = v - y
|
109
|
+
end
|
110
|
+
|
111
|
+
def vertices(format = :strip)
|
112
|
+
case format
|
113
|
+
when :strip then [[left, top], [right, top], [left, bottom], [right, bottom]]
|
114
|
+
when :cycle then [[left, top], [right, top], [right, bottom], [left, bottom]]
|
115
|
+
else nil
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.from_center(cx, cy, width, height)
|
120
|
+
new do
|
121
|
+
self.x, self.y, self.width, self.height = cx - width/2, cy - height/2, width, height
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
alias_method :to_ary, :to_a
|
126
|
+
alias_method :inside?, :include?
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
class Square < Rect
|
131
|
+
def initialize(x, y, size)
|
132
|
+
super(x, y, size, size)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module GLMath
|
2
|
+
class Scalar
|
3
|
+
|
4
|
+
def initialize(n)
|
5
|
+
raise ArgumentError, 'Must be numeric' unless n.is_a?(Numeric)
|
6
|
+
@n = n
|
7
|
+
end
|
8
|
+
|
9
|
+
def *(other)
|
10
|
+
case other
|
11
|
+
when Vector2, Vector3, Vector4, Matrix2, Matrix3, Matrix4
|
12
|
+
other.map { |e| @n * e }
|
13
|
+
else raise ArgumentError
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def /(other)
|
18
|
+
case other
|
19
|
+
when Matrix2, Matrix3, Matrix4
|
20
|
+
self * other.inverse
|
21
|
+
else raise ArgumentError
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def ==(other)
|
26
|
+
case other
|
27
|
+
when Scalar then @n == other.instance_variable_get(:@n)
|
28
|
+
when Numeric then @n == other
|
29
|
+
else false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
module GLMath
|
2
|
+
module Vector
|
3
|
+
module ClassMethods
|
4
|
+
def [](*array)
|
5
|
+
new(*array)
|
6
|
+
end
|
7
|
+
|
8
|
+
def zero
|
9
|
+
new(*([0.0] * size))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.included(base)
|
14
|
+
base.extend ClassMethods
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(*args)
|
18
|
+
raise ArgumentError, "wrong number of arguments (#{args.size} for #{size})" if args.size != size
|
19
|
+
raise ArgumentError, "It's not numeric" unless args.all? { |e| Numeric === e }
|
20
|
+
@v = args
|
21
|
+
end
|
22
|
+
|
23
|
+
%w'+ -'.each do |s|
|
24
|
+
define_method(s, ->(v) do
|
25
|
+
raise ArgumentError unless self.class === v
|
26
|
+
v = v.instance_variable_get(:@v)
|
27
|
+
self.class.new(*[@v, v].transpose.map!{ |a, b| a.send(s, b) })
|
28
|
+
end)
|
29
|
+
end
|
30
|
+
|
31
|
+
def -@
|
32
|
+
self.class.new(*@v.map(&:-@))
|
33
|
+
end
|
34
|
+
|
35
|
+
def /(v)
|
36
|
+
case v
|
37
|
+
when Numeric
|
38
|
+
self.class.new *@v.map{ |e| e / v }
|
39
|
+
else
|
40
|
+
raise ArgumentError, "Operation '/' not valid for #{v.class}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def ==(other)
|
45
|
+
return false unless self.class === other
|
46
|
+
@v == other.instance_variable_get(:@v)
|
47
|
+
end
|
48
|
+
|
49
|
+
def [](i)
|
50
|
+
@v[i]
|
51
|
+
end
|
52
|
+
|
53
|
+
def angle(other)
|
54
|
+
raise ArgumentError, "argument must be a #{self.class}" unless self.class === other
|
55
|
+
Math.acos(dot(other) / Math.sqrt(square_norm * other.square_norm))
|
56
|
+
end
|
57
|
+
|
58
|
+
def coerce(v)
|
59
|
+
case v
|
60
|
+
when Numeric then return Scalar.new(v), self
|
61
|
+
else raise TypeError, "#{self.class} can't be coerced into #{v.class}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def collect(&block)
|
66
|
+
return to_enum(__method__) unless block_given?
|
67
|
+
self.class.new(*@v.collect(&block))
|
68
|
+
end
|
69
|
+
|
70
|
+
def dup
|
71
|
+
self.class.new(*@v)
|
72
|
+
end
|
73
|
+
|
74
|
+
def each(&block)
|
75
|
+
return to_enum(__method__) unless block_given?
|
76
|
+
@v.each(&block)
|
77
|
+
self
|
78
|
+
end
|
79
|
+
|
80
|
+
def eql?(other)
|
81
|
+
return false unless self.class === other
|
82
|
+
@v.eql? other.instance_variable_get(:@v)
|
83
|
+
end
|
84
|
+
|
85
|
+
def hash
|
86
|
+
@v.hash
|
87
|
+
end
|
88
|
+
|
89
|
+
def inner_product(v)
|
90
|
+
raise ArgumentError unless self.class === v
|
91
|
+
v = v.instance_variable_get(:@v)
|
92
|
+
[@v, v].transpose.map!{ |a, b| a * b }.reduce(&:+)
|
93
|
+
end
|
94
|
+
|
95
|
+
def magnitude
|
96
|
+
Math.sqrt(inner_product(self))
|
97
|
+
end
|
98
|
+
|
99
|
+
def normalize
|
100
|
+
self / magnitude
|
101
|
+
end
|
102
|
+
|
103
|
+
def normalize!
|
104
|
+
mag = magnitude
|
105
|
+
@v.map! { |e| e / mag }
|
106
|
+
self
|
107
|
+
end
|
108
|
+
|
109
|
+
def size
|
110
|
+
self.class.size
|
111
|
+
end
|
112
|
+
|
113
|
+
def square_magnitude
|
114
|
+
dot(self)
|
115
|
+
end
|
116
|
+
|
117
|
+
def zero?
|
118
|
+
@v.all?(&:zero?)
|
119
|
+
end
|
120
|
+
|
121
|
+
%w'x y'.each_with_index do |s, i|
|
122
|
+
define_method s, ->(){ @v[i] }
|
123
|
+
define_method "#{s}=", ->(v){ @v[i] = v }
|
124
|
+
end
|
125
|
+
|
126
|
+
def to_a
|
127
|
+
@v.dup
|
128
|
+
end
|
129
|
+
|
130
|
+
def to_ary
|
131
|
+
to_a
|
132
|
+
end
|
133
|
+
|
134
|
+
def to_s(notation = nil)
|
135
|
+
case notation
|
136
|
+
when nil then inspect
|
137
|
+
when :row then "[#{@v.join("\t")}]"
|
138
|
+
when :column then @v.join("\n")
|
139
|
+
when :cartesian then "(#{@v.join(", ")})"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def inspect
|
144
|
+
"Vector#{size}#{@v.inspect}"
|
145
|
+
end
|
146
|
+
|
147
|
+
alias_method :dot, :inner_product
|
148
|
+
alias_method :r, :magnitude
|
149
|
+
alias_method :length, :magnitude
|
150
|
+
alias_method :norm, :magnitude
|
151
|
+
alias_method :map, :collect
|
152
|
+
alias_method :square_length, :square_magnitude
|
153
|
+
alias_method :square_norm, :square_magnitude
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module GLMath
|
2
|
+
class Vector2
|
3
|
+
|
4
|
+
class << self
|
5
|
+
def size
|
6
|
+
2
|
7
|
+
end
|
8
|
+
|
9
|
+
def X
|
10
|
+
new(1.0, 0.0)
|
11
|
+
end
|
12
|
+
|
13
|
+
def Y
|
14
|
+
new(0.0, 1.0)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
include Vector
|
19
|
+
|
20
|
+
def *(v)
|
21
|
+
case v
|
22
|
+
when Numeric
|
23
|
+
self.class.new(*@v.map{ |e| e * v })
|
24
|
+
when Matrix2
|
25
|
+
self.class.new(x * v[0] + y * v[2], x * v[1] + y * v[3])
|
26
|
+
else
|
27
|
+
raise ArgumentError
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def expand(*args)
|
32
|
+
args.flatten!
|
33
|
+
case
|
34
|
+
when args.length == 1 && args.is_a?(Vector2)
|
35
|
+
Vector4.new(*(@v + args[0].to_a))
|
36
|
+
when args.length == 1 && args[0].is_a?(Numeric)
|
37
|
+
Vector3.new(*(@v + args))
|
38
|
+
when args.length == 2 && args.all? { |e| e.is_a?(Numeric) }
|
39
|
+
Vector4.new(*(@v + args))
|
40
|
+
else
|
41
|
+
raise ArgumentError
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module GLMath
|
2
|
+
class Vector3
|
3
|
+
|
4
|
+
include Vector
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def size
|
8
|
+
3
|
9
|
+
end
|
10
|
+
|
11
|
+
def X
|
12
|
+
new(1.0, 0.0, 0.0)
|
13
|
+
end
|
14
|
+
|
15
|
+
def Y
|
16
|
+
new(0.0, 1.0, 0.0)
|
17
|
+
end
|
18
|
+
|
19
|
+
def Z
|
20
|
+
new(0.0, 0.0, 1.0)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def *(v)
|
25
|
+
case v
|
26
|
+
when Numeric
|
27
|
+
self.class.new(*@v.map{ |e| e * v })
|
28
|
+
when Matrix3
|
29
|
+
self.class.new(v[0] * x + v[3] * y + v[6] * z,
|
30
|
+
v[1] * x + v[4] * y + v[7] * z,
|
31
|
+
v[2] * x + v[5] * y + v[8] * z)
|
32
|
+
else
|
33
|
+
raise ArgumentError
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def expand(w)
|
38
|
+
raise ArgumentError unless w.is_a? Numeric
|
39
|
+
Vector4.new(*(@v + [w]))
|
40
|
+
end
|
41
|
+
|
42
|
+
def outer_product(v)
|
43
|
+
v = v.instance_variable_get(:@v)
|
44
|
+
self.class.new(@v[2] * v[1] - @v[1] * v[2], @v[0] * v[2] - @v[2] * v[0], @v[1] * v[0] - @v[0] * v[1])
|
45
|
+
end
|
46
|
+
|
47
|
+
def z
|
48
|
+
@v[2]
|
49
|
+
end
|
50
|
+
|
51
|
+
def xy
|
52
|
+
Vector2.new(*@v[0, 2])
|
53
|
+
end
|
54
|
+
|
55
|
+
def xz
|
56
|
+
Vector2.new(@v[0], @v[2])
|
57
|
+
end
|
58
|
+
|
59
|
+
def yz
|
60
|
+
Vector2.new(*@v[1, 2])
|
61
|
+
end
|
62
|
+
|
63
|
+
alias_method :cross_product, :outer_product
|
64
|
+
alias_method :cross, :outer_product
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module GLMath
|
2
|
+
class Vector4
|
3
|
+
|
4
|
+
class << self
|
5
|
+
def size
|
6
|
+
4
|
7
|
+
end
|
8
|
+
|
9
|
+
def X
|
10
|
+
new(1.0, 0.0, 0.0, 0.0)
|
11
|
+
end
|
12
|
+
|
13
|
+
def Y
|
14
|
+
new(0.0, 1.0, 0.0, 0.0)
|
15
|
+
end
|
16
|
+
|
17
|
+
def Z
|
18
|
+
new(0.0, 0.0, 1.0, 0.0)
|
19
|
+
end
|
20
|
+
|
21
|
+
def W
|
22
|
+
new(0.0, 0.0, 0.0, 1.0)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
include Vector
|
27
|
+
|
28
|
+
def *(v)
|
29
|
+
case v
|
30
|
+
when Numeric
|
31
|
+
self.class.new(*@v.map{ |e| e * v })
|
32
|
+
when Matrix4
|
33
|
+
self.class.new(x * v[0] + y * v[4] + z * v[ 8] + w * v[12],
|
34
|
+
x * v[1] + y * v[5] + z * v[ 9] + w * v[13],
|
35
|
+
x * v[2] + y * v[6] + z * v[10] + w * v[14],
|
36
|
+
x * v[3] + y * v[7] + z * v[11] + w * v[15])
|
37
|
+
else
|
38
|
+
raise ArgumentError
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def z
|
43
|
+
@v[2]
|
44
|
+
end
|
45
|
+
|
46
|
+
def w
|
47
|
+
@v[3]
|
48
|
+
end
|
49
|
+
|
50
|
+
%w(xy xz xw yz yw zw xyz xyw xzw yzw).each do |m|
|
51
|
+
instance_eval("def #{m}() Vector#{m.length}.new(#{m.each_char.to_a.join(', ')}) end")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|