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.
@@ -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