glmath 0.0.1.dev

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