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,81 @@
1
+ module GLMath
2
+ class Matrix2
3
+
4
+ class << self
5
+ def dimension
6
+ 2
7
+ end
8
+
9
+ #conter-clockwise rotation
10
+ def rotation(theta, homogenous = false)
11
+ s, c = Math.sin(theta), Math.cos(theta)
12
+ m = new(c, -s, s, c)
13
+ homogenous ? m.expand : m
14
+ end
15
+
16
+ def scale(x, y, homogenous = false)
17
+ m = diagonal(x, y)
18
+ homogenous ? m.expand : m
19
+ end
20
+ end
21
+
22
+ include Matrix
23
+
24
+ def *(v)
25
+ case v
26
+ when Vector2
27
+ v.class.new(@m[0] * v.x + @m[1] * v.y, @m[2] * v.x + @m[3] * v.y)
28
+ when Matrix2
29
+ m = v.instance_variable_get(:@m)
30
+ self.class.new(@m[0]*m[0] + @m[1]*m[2], @m[0]*m[1] + @m[1]*m[3],
31
+ @m[2]*m[0] + @m[3]*m[2], @m[2]*m[1] + @m[3]*m[3])
32
+ when Numeric
33
+ super
34
+ else
35
+ raise ArgumentError
36
+ end
37
+ end
38
+
39
+ def adjugate!
40
+ @m = [ @m[3], -@m[1],
41
+ -@m[2], @m[0]]
42
+ self
43
+ end
44
+
45
+ def determinant
46
+ @m[0] * @m[3] - @m[1] * @m[2]
47
+ end
48
+
49
+ def expand
50
+ Matrix3.new(@m[0], @m[1], 0.0,
51
+ @m[2], @m[3], 0.0,
52
+ 0.0, 0.0, 1.0)
53
+ end
54
+
55
+ def inverse
56
+ d = determinant
57
+ raise ArgumentError, 'Determinant is zero' if d.zero?
58
+ adjugate * (1.0 / d)
59
+ end
60
+
61
+ def lup
62
+ raise ArgumentError, "Determinant is zero" if singular?
63
+
64
+ if @m[0].abs > @m[1].abs
65
+ a, b, c, d = 0, 1, 2, 3
66
+ p = self.class.new(1.0, 0.0, 0.0, 1.0)
67
+ else
68
+ a, b, c, d = 2, 3, 0, 1
69
+ p = self.class.new(0.0, 1.0, 1.0, 0.0)
70
+ end
71
+
72
+ l = self.class.new(1.0, 0.0, @m[c] / @m[a], 1.0)
73
+ u = self.class.new(@m[a], @m[b], 0.0, @m[d] - @m[b]*@m[c] / @m[a])
74
+ [l, u, p]
75
+ end
76
+
77
+ alias_method :det, :determinant
78
+ alias_method :lup_decomposition, :lup
79
+
80
+ end
81
+ end
@@ -0,0 +1,108 @@
1
+ module GLMath
2
+ class Matrix3
3
+
4
+ class << self
5
+ def dimension
6
+ 3
7
+ end
8
+
9
+ def rotation(angle, axis, homogenous = false)
10
+ n = axis.normalize
11
+ ct = Math.cos(angle)
12
+ st = Math.sin(angle)
13
+ ct1 = 1 - ct
14
+ xy = n.x * n.y * ct1
15
+ xz = n.x * n.z * ct1
16
+ yz = n.y * n.z * ct1
17
+
18
+ m = new(n.x*n.x*ct1 + ct, xy + n.z * st, xz - n.y * st,
19
+ xy - n.z * st, n.y*n.y*ct1 + ct, yz + n.x * st,
20
+ xz + n.y * st, yz - n.x * st, n.z*n.z*ct1 + ct)
21
+ homogenous ? m.expand : m
22
+ end
23
+
24
+ def scale(x, y, z, homogenous = false)
25
+ m = diagonal(x, y, z)
26
+ homogenous ? m.expand : m
27
+ end
28
+
29
+ def translation(x, y)
30
+ Matrix3.new(1.0, 0.0, 0.0,
31
+ 0.0, 1.0, 0.0,
32
+ x, y, 1.0)
33
+ end
34
+
35
+ def from_euler_angle(x:, y:, z:)
36
+ # TODO
37
+ end
38
+ end
39
+
40
+ include Matrix
41
+
42
+ def *(v)
43
+ case v
44
+ when Vector3
45
+ v.class.new(@m[0] * v.x + @m[1] * v.y + @m[2] * v.z,
46
+ @m[3] * v.x + @m[4] * v.y + @m[5] * v.z,
47
+ @m[6] * v.x + @m[7] * v.y + @m[8] * v.z)
48
+ when Matrix3
49
+ m = v.instance_variable_get(:@m)
50
+ self.class.new(
51
+ @m[0]*m[0]+@m[1]*m[3]+@m[2]*m[6], @m[0]*m[1]+@m[1]*m[4]+@m[2]*m[7], @m[0]*m[2] + @m[1]*m[5] + @m[2]*m[8],
52
+ @m[3]*m[0]+@m[4]*m[3]+@m[5]*m[6], @m[3]*m[1]+@m[4]*m[4]+@m[5]*m[7], @m[3]*m[2] + @m[4]*m[5] + @m[5]*m[8],
53
+ @m[6]*m[0]+@m[7]*m[3]+@m[8]*m[6], @m[6]*m[1]+@m[7]*m[4]+@m[8]*m[7], @m[6]*m[2] + @m[7]*m[5] + @m[8]*m[8])
54
+ else
55
+ super
56
+ end
57
+ end
58
+
59
+ def adjugate!
60
+ @m =[@m[4] * @m[8] - @m[5] * @m[7],
61
+ @m[5] * @m[6] - @m[3] * @m[8],
62
+ @m[3] * @m[7] - @m[4] * @m[6],
63
+ @m[2] * @m[7] - @m[1] * @m[8],
64
+ @m[0] * @m[8] - @m[2] * @m[6],
65
+ @m[1] * @m[6] - @m[0] * @m[7],
66
+ @m[1] * @m[5] - @m[2] * @m[4],
67
+ @m[2] * @m[3] - @m[0] * @m[5],
68
+ @m[0] * @m[4] - @m[1] * @m[3]]
69
+ self
70
+ end
71
+
72
+ def determinant
73
+ @m[0] * ( @m[4] * @m[8] - @m[5] * @m[7] ) +
74
+ @m[1] * ( @m[5] * @m[6] - @m[3] * @m[8] ) +
75
+ @m[2] * ( @m[3] * @m[7] - @m[4] * @m[6] )
76
+ end
77
+
78
+ def expand
79
+ Matrix4.new(@m[0], @m[1], @m[2], 0.0,
80
+ @m[3], @m[4], @m[5], 0.0,
81
+ @m[6], @m[7], @m[8], 0.0,
82
+ 0.0, 0.0, 0.0, 1.0)
83
+ end
84
+
85
+ def to_axis_angle
86
+ # TODO
87
+ end
88
+
89
+ def orthonormalize
90
+ # TODO
91
+ end
92
+
93
+ def eigen_decomposition()
94
+ # TODO
95
+ end
96
+
97
+ def to_euler_angle
98
+ # TODO
99
+ end
100
+
101
+ def slerp
102
+ # TODO
103
+ end
104
+
105
+ alias_method :det, :determinant
106
+
107
+ end
108
+ end
@@ -0,0 +1,145 @@
1
+ module GLMath
2
+ # Left Handed
3
+ class Matrix4
4
+ class << self
5
+ def dimension
6
+ 4
7
+ end
8
+
9
+ def look_at(eye, center, up)
10
+ f = (center - eye).normalize!
11
+ s = f.cross(up).normalize!
12
+ u = s.cross(f).normalize!
13
+ new(s.x, u.x, -f.x, 0.0,
14
+ s.y, u.y, -f.y, 0.0,
15
+ s.z, u.z, -f.z, 0.0,
16
+ -eye.x, -eye.y, -eye.z, 1.0)
17
+ end
18
+
19
+ def ortho(left, right, bottom, top, near, far)
20
+ rl = right.to_f - left.to_f
21
+ tb = top.to_f - bottom.to_f
22
+ fn = far.to_f - near.to_f
23
+
24
+ new(2.0/rl, 0.0, 0.0, 0.0,
25
+ 0.0, 2.0/tb, 0.0, 0.0,
26
+ 0.0, 0.0, -2.0/fn, 0.0,
27
+ -(right + left)/rl, -(top + bottom)/tb, -(far + near)/fn, 1.0)
28
+ end
29
+
30
+ def perspective(fovy, aspect, near, far)
31
+ zoom = 1.0 / Math.tan(fovy * 0.5)
32
+ fn = 1.0 / (far - near)
33
+ new(zoom/aspect, 0.0, 0.0, 0.0,
34
+ 0.0, zoom, 0.0, 0.0,
35
+ 0.0, 0.0, (far + near)*fn, 1.0,
36
+ 0.0, 0.0, -2.0*far*near*fn, 0.0)
37
+ end
38
+
39
+ def rotation(angle, axis)
40
+ Matrix3.rotation(angle, axis, true)
41
+ end
42
+
43
+ def scale(x, y, z, w = 1.0)
44
+ diagonal(x, y, z, w)
45
+ end
46
+
47
+ def translation(x, y, z)
48
+ Matrix4.new(1.0, 0.0, 0.0, 0.0,
49
+ 0.0, 1.0, 0.0, 0.0,
50
+ 0.0, 0.0, 1.0, 0.0,
51
+ x, y, z, 1.0)
52
+ end
53
+ end
54
+
55
+ include Matrix
56
+
57
+ def *(v)
58
+ case v
59
+ when Vector4
60
+ v.class.new(
61
+ @m[ 0] * v.x + @m[ 1] * v.y + @m[ 2] * v.z + @m[ 3] * v.w,
62
+ @m[ 4] * v.x + @m[ 5] * v.y + @m[ 6] * v.z + @m[ 7] * v.w,
63
+ @m[ 8] * v.x + @m[ 9] * v.y + @m[10] * v.z + @m[11] * v.w,
64
+ @m[12] * v.x + @m[13] * v.y + @m[14] * v.z + @m[15] * v.w)
65
+ when Matrix4
66
+ m = v.instance_variable_get(:@m)
67
+ self.class.new(
68
+ @m[ 0] * m[0] + @m[ 1] * m[4] + @m[ 2] * m[ 8] + @m[ 3] * m[12],
69
+ @m[ 0] * m[1] + @m[ 1] * m[5] + @m[ 2] * m[ 9] + @m[ 3] * m[13],
70
+ @m[ 0] * m[2] + @m[ 1] * m[6] + @m[ 2] * m[10] + @m[ 3] * m[14],
71
+ @m[ 0] * m[3] + @m[ 1] * m[7] + @m[ 2] * m[11] + @m[ 3] * m[15],
72
+ @m[ 4] * m[0] + @m[ 5] * m[4] + @m[ 6] * m[ 8] + @m[ 7] * m[12],
73
+ @m[ 4] * m[1] + @m[ 5] * m[5] + @m[ 6] * m[ 9] + @m[ 7] * m[13],
74
+ @m[ 4] * m[2] + @m[ 5] * m[6] + @m[ 6] * m[10] + @m[ 7] * m[14],
75
+ @m[ 4] * m[3] + @m[ 5] * m[7] + @m[ 6] * m[11] + @m[ 7] * m[15],
76
+ @m[ 8] * m[0] + @m[ 9] * m[4] + @m[10] * m[ 8] + @m[11] * m[12],
77
+ @m[ 8] * m[1] + @m[ 9] * m[5] + @m[10] * m[ 9] + @m[11] * m[13],
78
+ @m[ 8] * m[2] + @m[ 9] * m[6] + @m[10] * m[10] + @m[11] * m[14],
79
+ @m[ 8] * m[3] + @m[ 9] * m[7] + @m[10] * m[11] + @m[11] * m[15],
80
+ @m[12] * m[0] + @m[13] * m[4] + @m[14] * m[ 8] + @m[15] * m[12],
81
+ @m[12] * m[1] + @m[13] * m[5] + @m[14] * m[ 9] + @m[15] * m[13],
82
+ @m[12] * m[2] + @m[13] * m[6] + @m[14] * m[10] + @m[15] * m[14],
83
+ @m[12] * m[3] + @m[13] * m[7] + @m[14] * m[11] + @m[15] * m[15])
84
+ else
85
+ super
86
+ end
87
+ end
88
+
89
+ def adjoint!
90
+ a = @m[4] * @m[9] - @m[5] * @m[8]
91
+ b = @m[4] * @m[10] - @m[6] * @m[8]
92
+ c = @m[4] * @m[11] - @m[7] * @m[8]
93
+ d = @m[4] * @m[13] - @m[5] * @m[12]
94
+ f = @m[4] * @m[14] - @m[6] * @m[12]
95
+ g = @m[4] * @m[15] - @m[7] * @m[12]
96
+ h = @m[5] * @m[10] - @m[6] * @m[9]
97
+ i = @m[5] * @m[11] - @m[7] * @m[9]
98
+ j = @m[5] * @m[14] - @m[6] * @m[13]
99
+ k = @m[5] * @m[15] - @m[7] * @m[13]
100
+ l = @m[6] * @m[11] - @m[7] * @m[10]
101
+ m = @m[6] * @m[15] - @m[7] * @m[14]
102
+ n = @m[8] * @m[13] - @m[9] * @m[12]
103
+ o = @m[8] * @m[14] - @m[10] * @m[12]
104
+ p = @m[8] * @m[15] - @m[11] * @m[12]
105
+ q = @m[9] * @m[14] - @m[10] * @m[13]
106
+ r = @m[9] * @m[15] - @m[11] * @m[13]
107
+ s = @m[10] * @m[15] - @m[11] * @m[14]
108
+
109
+ @m = [+ @m[5] * s - @m[6] * r + @m[7] * q,
110
+ - @m[4] * s + @m[6] * p - @m[7] * o,
111
+ + @m[4] * r - @m[5] * p + @m[7] * n,
112
+ - @m[4] * q + @m[5] * o - @m[6] * n,
113
+ - @m[1] * s + @m[2] * r - @m[3] * q,
114
+ + @m[0] * s - @m[2] * p + @m[3] * o,
115
+ - @m[0] * r + @m[1] * p - @m[3] * n,
116
+ + @m[0] * q - @m[1] * o + @m[2] * n,
117
+ + @m[1] * m - @m[2] * k + @m[3] * j,
118
+ - @m[0] * m + @m[2] * g - @m[3] * f,
119
+ + @m[0] * k - @m[1] * g + @m[3] * d,
120
+ - @m[0] * j + @m[1] * f - @m[2] * d,
121
+ - @m[1] * l + @m[2] * i - @m[3] * h,
122
+ + @m[0] * l - @m[2] * c + @m[3] * b,
123
+ - @m[0] * i + @m[1] * c - @m[3] * a,
124
+ + @m[0] * h - @m[1] * b + @m[2] * a]
125
+ self
126
+ end
127
+
128
+ def determinant
129
+ a = @m[10] * @m[15] - @m[11] * @m[14]
130
+ b = @m[11] * @m[13] - @m[9] * @m[15]
131
+ c = @m[9] * @m[14] - @m[10] * @m[13]
132
+ d = @m[8] * @m[15] - @m[11] * @m[12]
133
+ e = @m[10] * @m[12] - @m[8] * @m[14]
134
+ f = @m[8] * @m[13] - @m[9] * @m[12]
135
+
136
+ @m[0] * ( @m[5] * a + @m[6] * b + @m[7] * c) +
137
+ @m[1] * (-@m[4] * a + @m[6] * d + @m[7] * e) +
138
+ @m[2] * (-@m[4] * b - @m[5] * d + @m[7] * f) +
139
+ @m[3] * (-@m[4] * c - @m[5] * e - @m[6] * f)
140
+ end
141
+
142
+ alias_method :det, :determinant
143
+
144
+ end
145
+ end
@@ -0,0 +1,91 @@
1
+ module GLMath
2
+ class MatrixStack
3
+
4
+ def initialize
5
+ @stack = [Matrix4.I]
6
+ end
7
+
8
+ %w'* - +'.each do |m|
9
+ define_method(m, ->(v) do
10
+ @stack[-1] = @stack.last.send(m, check(v))
11
+ self
12
+ end)
13
+ end
14
+
15
+ def <<(m)
16
+ @stack << check(m)
17
+ self
18
+ end
19
+
20
+ def current
21
+ @stack.last.dup
22
+ end
23
+
24
+ def dup
25
+ MatrixStack.new.tap { |ms| ms.instance_variable_set(:@stack, @stack.map(&:dup)) }
26
+ end
27
+
28
+ def push(m = current)
29
+ self << m
30
+ return self unless block_given?
31
+ yield self
32
+ pop
33
+ self
34
+ end
35
+
36
+ def pop(n = 1)
37
+ @stack.pop(n)
38
+ end
39
+
40
+ def load(*args)
41
+ @stack[-1] = case
42
+ when args.length == 16 then Matrix4[*args]
43
+ when args.length == 9 then Matrix3[*args].expand
44
+ when args.length == 1 then check(args[0])
45
+ else raise ArgumentError
46
+ end
47
+ end
48
+
49
+ def load_identity
50
+ load(Matrix4.I)
51
+ end
52
+
53
+ def look_at(eye, center, up)
54
+ self * Matrix4.look_at(eye, center, up)
55
+ end
56
+
57
+ def ortho(left, right, bottom, top, near, far)
58
+ self * Matrix4.ortho(left, right, bottom, top, near, far)
59
+ end
60
+
61
+ def perspective(fovy, aspect, near, far)
62
+ self * Matrix4.perspective(fovy, aspect, near, far)
63
+ end
64
+
65
+ def rotate(arg, axis = nil)
66
+ self * case axis
67
+ when Vector3, Vector4 then Matrix4.rotation(arg, axis)
68
+ when Quaternion, EulerAngle then arg.to_matrix
69
+ else raise ArgumentError
70
+ end
71
+ end
72
+
73
+ def scale(x, y, z, w = 1.0)
74
+ self * Matrix4.scale(x, y, z, w)
75
+ end
76
+
77
+ #def shear()
78
+ # #TODO
79
+ #end
80
+
81
+ def translate(x, y, z)
82
+ self * Matrix4.translation(x, y, z)
83
+ end
84
+
85
+ private
86
+ def check(m)
87
+ raise ArgumentError unless m.is_a?(Matrix4)
88
+ m
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,212 @@
1
+ module GLMath
2
+ class Quaternion
3
+ class << self
4
+ def [](*args)
5
+ new(*args)
6
+ end
7
+
8
+ def from_angle_axis(angle, axis)
9
+ angle *= 0.5
10
+ axis = axis.normalize
11
+ sa = Math.sin(angle)
12
+ new(Math.cos(angle), sa * axis.x, sa * axis.y, sa * axis.z)
13
+ end
14
+
15
+ def identity
16
+ new(1.0, 0.0, 0.0, 0.0)
17
+ end
18
+
19
+ def slerp(q0, q1, t)
20
+ (q1 * q0.inverse).power(t) * q0
21
+ end
22
+
23
+ alias_method :I, :identity
24
+ end
25
+
26
+ def initialize(w, x, y, z)
27
+ @q = w, x, y, z
28
+ raise ArgumentError, 'arguments must be Numeric' unless @q.all? { |e| e.is_a?(Numeric) }
29
+ end
30
+
31
+ def +(v)
32
+ case v
33
+ when Numeric
34
+ self.class.new(v + w, x, y, z)
35
+ when Quaternion
36
+ self.class.new(q + v.w, x + v.x, y + v.y, z + v.z)
37
+ else
38
+ v + self
39
+ end
40
+ end
41
+
42
+ def -(q)
43
+ self + (-q)
44
+ end
45
+
46
+ def *(v)
47
+ case v
48
+ when Numeric
49
+ self.class.new(q * v, x * v, y * v, z * v)
50
+ when Quaternion
51
+ cross_product(v)
52
+ end
53
+ end
54
+
55
+ def /(v)
56
+ case v
57
+ when Numeric
58
+ self.class.new(*@q.map { |i| i/v})
59
+ when Quaternion
60
+ self * v.inverse
61
+ end
62
+ end
63
+
64
+ def -@
65
+ self.class.new(*@q.map(&:-@))
66
+ end
67
+
68
+ def ==(other)
69
+ self.class === other && @q == other.instance_variable_get(:@q)
70
+ end
71
+
72
+ %w'w x y z'.each_with_index do |m, i|
73
+ define_method m, ->() { @q[i] }
74
+ define_method "#{m}=", ->(v) { @q[i] = v }
75
+ end
76
+
77
+ def coerce(v)
78
+ case v
79
+ when Numeric then return Scalar.new(v), self
80
+ else raise TypeError, "#{self.class} can't be coerced into #{v.class}"
81
+ end
82
+ end
83
+
84
+ def conjugate
85
+ self.class.new(w, -x, -y, -z)
86
+ end
87
+
88
+ def conjugate!
89
+ @q = w, -x, -y, -z
90
+ self
91
+ end
92
+
93
+ #Warning: standard notation.
94
+ def cross_product(q)
95
+ self.class.new(
96
+ w * q.w - x * q.x - y * q.y - z * q.z,
97
+ w * q.x + x * q.w + y * q.z - z * q.y,
98
+ w * q.y - x * q.z + y * q.w + z * q.x,
99
+ w * q.z + x * q.y - y * q.x + z * q.w)
100
+ end
101
+
102
+ def difference(q)
103
+ q * inverse
104
+ end
105
+
106
+ def dot_product(q)
107
+ w * q.w + x * q.x + y * q.y + z * q.z
108
+ end
109
+
110
+ def dup
111
+ self.class.new(*@q)
112
+ end
113
+
114
+ def exp
115
+ a = Math.sqrt(x*x + y*y + z*z)
116
+ ew = Math.exp(w)
117
+ s = ew * Math.sin(a) / a
118
+ self.class.new(ew * Math.cos(a), x * s, y * s, z * s)
119
+ end
120
+
121
+ def imaginary
122
+ [x, y, z]
123
+ end
124
+
125
+ def inspect
126
+ "Quaternion[#{w}, #{x}, #{y}, #{z}]"
127
+ end
128
+
129
+ def inverse
130
+ conjugate / norm
131
+ end
132
+
133
+ def log
134
+ nv = x*x + y*y + z*z
135
+ nq = Math.sqrt(w*w + nv)
136
+ s = Math.acos(w/nq) / Math.sqrt(nv)
137
+ self.class.new(Math.log(nq), x * s, y * s, z * s)
138
+ end
139
+
140
+ def norm
141
+ Math.sqrt(squared_norm)
142
+ end
143
+
144
+ def normalize
145
+ self / norm
146
+ end
147
+
148
+ def normalize!
149
+ i = 1.0 / norm
150
+ @q.map! { |e| e * i }
151
+ self
152
+ end
153
+
154
+ def power(p)
155
+ (log*p).exp
156
+ end
157
+
158
+ def real
159
+ w
160
+ end
161
+
162
+ def rotate(v3)
163
+ Vector3[*(self * Quaternion[0.0, *v3] * inverse).to_a[1..-1]]
164
+ end
165
+
166
+ def squared_norm
167
+ w * w + x * x + y * y + z * z
168
+ end
169
+
170
+ def to_a
171
+ @q.dup
172
+ end
173
+
174
+ def to_s(notation = nil)
175
+ case notation
176
+ when :scalar_vector
177
+ "(#{w}, [#{x}, #{y}, #{z}])"
178
+ when :vertical
179
+ "w=#{w}\nx=#{x}\ny=#{y}\nz=#{z}"
180
+ when :angle_axis
181
+ else
182
+ "Quaternion[w=#{w}, x=#{x}, y=#{y}, z=#{z}]"
183
+ end
184
+ end
185
+
186
+ def to_matrix
187
+ xx = 2 * x * x
188
+ yy = 2 * y * y
189
+ zz = 2 * z * z
190
+ xy = 2 * x * y
191
+ wz = 2 * w * z
192
+ xz = 2 * x * z
193
+ wy = 2 * w * y
194
+ yz = 2 * y * z
195
+ wx = 2 * w * x
196
+
197
+ Matrix4[1 - yy - zz, xy - wz, xz + wy, 0,
198
+ xy + wz, 1 - xx - zz, yz - wx, 0,
199
+ xz - wy, yz + wx, 1 - xx - yy, 0,
200
+ 0, 0, 0, 1]
201
+ end
202
+
203
+ alias_method :conj, :conjugate
204
+ alias_method :conj!, :conjugate
205
+ alias_method :cross, :cross_product
206
+ alias_method :dot, :dot_product
207
+ alias_method :im, :imaginary
208
+ alias_method :imag, :imaginary
209
+ alias_method :inv, :inverse
210
+ alias_method :re, :real
211
+ end
212
+ end