glmath 0.0.1.dev
Sign up to get free protection for your applications and to get access to all the features.
- 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
|