rmath3d_plain 1.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b7b422319e3b48310d1f08f251af272fca707cb8
4
+ data.tar.gz: 7f6a9b6f8f6a5b8726292932fb86d8332adde298
5
+ SHA512:
6
+ metadata.gz: 90eec224b1670972296612fb159cba2ec95aeb950430f13bce280df9df2bdc703f2af600f3d3081394bc361b4683f7ad0910b570ea03752e145d7ff4aedff4eb
7
+ data.tar.gz: 62f3c4f0589b3cd895cfa4e133774c124a929c4b47574859574a3ec81e53ecbcff5cc82db1475c79c3e7646b9607f4179973e91a4b3b5e85d310a48557d31ea3
data/ChangeLog ADDED
@@ -0,0 +1,82 @@
1
+ 2013-10-26 vaiorabbit <http://twitter.com/vaiorabbit>
2
+
3
+ * rmath3d_plain.gemspec: Packs pure ruby implementation into 'rmath3d_plain-X.Y.Z.gem'.
4
+
5
+ 2013-09-21 vaiorabbit <http://twitter.com/vaiorabbit>
6
+
7
+ * README.txt: Updated tested environment and information about building native extension.
8
+ * README.md: Renamed from README.txt
9
+
10
+ 2013-09-16 vaiorabbit <http://twitter.com/vaiorabbit>
11
+
12
+ * sample/opengl-bingings: Added sample using my opengl-bindings gem ( https://rubygems.org/gems/opengl-bindings ).
13
+
14
+ 2013-07-15 vaiorabbit <http://twitter.com/vaiorabbit>
15
+
16
+ * Fixed directory organization / source file names to comply with RubyGems' packaging system.
17
+
18
+ 2010-09-14 vaiorabbit <http://twitter.com/vaiorabbit>
19
+
20
+ * RVec3.c|h, RVec4.c|h, WrapRMath.c, RMath.rb (RVec3#transformTransposed, etc): Added.
21
+
22
+ 2010-08-15 vaiorabbit <http://twitter.com/vaiorabbit>
23
+
24
+ * RVec3.c, WrapRMath.c, RMath.rb (RVec3#transformByQuaternion): Added.
25
+
26
+ 2010-06-23 vaiorabbit <http://twitter.com/vaiorabbit>
27
+
28
+ * WrapRMath.c (RQuat_getElement/RVec3_getElement/RVec4_getElement):
29
+ Return values from R*GetElement() are now received by correct type (int -> rmReal).
30
+
31
+ 2010-01-03 vaiorabbit <http://twitter.com/vaiorabbit>
32
+
33
+ * RMtx4.c, WrapRMath.c, RMath.rb (RMtx4#getUpper3x3/RMtx4#setUpper3x3): Added.
34
+ * WrapRMath.c (RMtx4#e00=~RMtx4#e33=): The number of arguments to C function (4th argument of rb_define_method()) is corrected.
35
+
36
+ 2010-01-02 vaiorabbit <http://twitter.com/vaiorabbit>
37
+
38
+ * RMtx3.c, RMtx4.c, WrapRMath.c, RMath.rb (getRow/getColumn, SetRow/SetColumn): Added.
39
+
40
+ 2009-12-21 vaiorabbit <http://twitter.com/vaiorabbit>
41
+
42
+ * Update: Old contact information is updated to the current one.
43
+
44
+ 2008-08-30 vaiorabbit <http://twitter.com/vaiorabbit>
45
+
46
+ * RMtx3.c, RMtx4.c (RMtx3Inverse,RMtx4Inverse): Modified to reduce
47
+ the number of scalar multiplication.
48
+
49
+ 2008-08-02 vaiorabbit <http://twitter.com/vaiorabbit>
50
+
51
+ * WrapRMath.c (RMtx3_to_s, RMtx4_to_s, etc.): Functions for "to_s"
52
+ implementation now buid strings by +sprintf+, not +rb_str_plus+, etc.
53
+
54
+ 2008-07-27 vaiorabbit <http://twitter.com/vaiorabbit>
55
+
56
+ * RType.h (RMATH_SINGLE_PRECISION): Added. Enable this to force
57
+ RMath using +float+ for its internal calculation.
58
+
59
+ * WrapRMath.c (RMATH_ENABLE_ARGUMENT_CHECK): Added. Enable this
60
+ macro for strict type checking.
61
+
62
+ * WrapRMath.c: The codes for overriding "!=" operators are
63
+ removed. Note that the operation "a != b" is just a syntactic
64
+ shortcut of "!(a == b)", and the former expression is
65
+ automatically convertd into the latter one.
66
+ See: Programming Ruby: The Pragmatic Programmer's Guide
67
+ http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html#UG
68
+ Both == and =~ have negated forms, != and !~. However, these are
69
+ converted by Ruby when your program is read. a!=b is equivalent
70
+ to !(a==b), and a!~b is the same as !(a=~b). This means that if
71
+ you write a class that overrides == or =~ you get a working !=
72
+ and !~ for free. But on the flip side, this also means that you
73
+ cannot define != and !~ independent of == and =~, respectively.
74
+
75
+ 2008-07-21 vaiorabbit <http://twitter.com/vaiorabbit>
76
+
77
+ * WrapRMath.c (RMtx3,RMtx4): Added new element-wise
78
+ getters/setters (mtx.e00, mtx.e00=, etc.)
79
+
80
+ 2008-07-20 vaiorabbit <http://twitter.com/vaiorabbit>
81
+
82
+ * Announce: First release.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ rmath3d : Ruby math module for 3D Applications
2
+ Copyright (c) 2008- vaiorabbit <http://twitter.com/vaiorabbit>
3
+
4
+ This software is provided 'as-is', without any express or implied
5
+ warranty. In no event will the authors be held liable for any damages
6
+ arising from the use of this software.
7
+
8
+ Permission is granted to anyone to use this software for any purpose,
9
+ including commercial applications, and to alter it and redistribute it
10
+ freely, subject to the following restrictions:
11
+
12
+ 1. The origin of this software must not be misrepresented; you must not
13
+ claim that you wrote the original software. If you use this software
14
+ in a product, an acknowledgment in the product documentation would be
15
+ appreciated but is not required.
16
+
17
+ 2. Altered source versions must be plainly marked as such, and must not be
18
+ misrepresented as being the original software.
19
+
20
+ 3. This notice may not be removed or altered from any source
21
+ distribution.
data/README.md ADDED
@@ -0,0 +1,178 @@
1
+ <!-- -*- mode:markdown; coding:utf-8; -*- -->
2
+
3
+ # rmath3d : Ruby Math Module for 3D Applications #
4
+
5
+ rmath3d is a math module for 3D game programming and computer graphics.
6
+
7
+ * Last Update: Oct 26, 2013
8
+ * Since: Jul 20, 2008
9
+
10
+ ## Features ##
11
+
12
+ ### Supports frequently-used vector and matrix classes ###
13
+
14
+ * RMtx3 (3x3 matrix)
15
+ * RMtx4 (4x4 matrix)
16
+ * RQuat (Quaternion)
17
+ * RVec3 (3 element vector)
18
+ * RVec4 (4 element vector)
19
+
20
+ ### Two implementations that are interchangeable with each other ###
21
+
22
+ 1. rmath3d.{so|bundle} : Ruby extension library for faster execution.
23
+ 2. rmath3d_plain.rb : Ruby implemantation for debugging use.
24
+
25
+
26
+ ## Tested Environment ##
27
+
28
+ Notice: This library provides native extension. You must setup develop environment (or DevKit) before installation.
29
+
30
+ * Ruby
31
+ * ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-darwin12.4.0]
32
+ * ruby 2.0.0p247 (2013-06-27) [i386-mingw32] With Development Kit installed.
33
+ * I used: DevKit-mingw64-32-4.7.2-20130224-1151-sfx.exe
34
+ * Unpack the archive -> "> ruby dk.rb init" -> edit config.yml (just add your ruby foldier) -> "> ruby dk.rb install"
35
+ * Ref.: http://blog.mattwynne.net/2010/10/12/installing-ruby-gems-with-native-extensions-on-windows/
36
+
37
+ ## Building rmath3d.{so|bundle} ##
38
+
39
+ Via RubyGems ( https://rubygems.org/gems/rmath3d ):
40
+
41
+ $ gem install rmath3d
42
+
43
+ for pure ruby version:
44
+
45
+ $ gem install rmath3d_plain
46
+
47
+ ### From source package ###
48
+
49
+ $ rake install
50
+
51
+ ### For mkmf users ###
52
+
53
+ $ ruby extconf.rb
54
+ $ make
55
+
56
+ For Windows users, type commands below via the "Visual Studio 200{5|8}
57
+ Command Prompt". This process requires "cl.exe", "link.exe and
58
+ "mt.exe" to be exist in the program PATH:
59
+
60
+ X:\> ruby extconf.rb
61
+ X:\> nmake
62
+
63
+ You might encounter the "MSC version unmatch: _MSC_VER: XXXX is
64
+ expected." error at the time compiling "rmath3d.c". See the
65
+ instruction in the extconf.rb to avoid this error.
66
+
67
+
68
+ ### Embedding manifest file (For Windows users) ###
69
+
70
+ Make sure that your rmath3d.so has "rmath3d.so.manifest" embedded into itself.
71
+ Otherwise, while using rmath3d.so in your application, you might come
72
+ across an error dialog saying:
73
+
74
+ ---------------------------
75
+ Microsoft Visual C++ Runtime Library
76
+ ---------------------------
77
+ Runtime Error!
78
+
79
+ Program: d:\ruby\bin\ruby.exe
80
+
81
+ R6034
82
+ An application has made an attempt to load the C runtime library incorrectly.
83
+ Please contact the application's support team for more information.
84
+
85
+ ---------------------------
86
+ OK
87
+ ---------------------------
88
+
89
+ To ensure the file status, try checking if the string "manifest" can
90
+ be found in the file:
91
+
92
+ X:\> strings rmath3d.so | grep manifest
93
+
94
+ If you don't see any outputs, it's time to embed "rmath3d.so.manifest".
95
+
96
+ X:\> mt -manifest rmath3d.so.manifest -outputresource:rmath3d.so;2
97
+
98
+ or run the "embed_manifest.bat" instead. Then check again the status.
99
+
100
+ X:\> strings rmath3d.so | grep manifest
101
+ <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
102
+
103
+ X:\>
104
+
105
+ If you see some similar output like that, the manifest file
106
+ "rmath3d.so.manifest" is successfully embedded.
107
+
108
+
109
+ ## About rmath3d_plain.rb ##
110
+
111
+ rmath3d_plain.rb is a pure Ruby version of rmath3d.so: all the functionality of
112
+ rmath3d.so is implemented with plain Ruby code.
113
+ It is possible to trace the bugs caused by rmath3d.so by replacing the code
114
+
115
+ gem 'rmath3d'
116
+ require 'rmath3d/rmath3d'
117
+
118
+ with
119
+
120
+ gem 'rmath3d'
121
+ require 'rmath3d/rmath3d_plain'
122
+
123
+ rmath3d_plain.rb performs more strict type checking, that might be some burden
124
+ for its execution speed. So don't expect the performance efficiency
125
+ when you use rmath3d_plain.rb instead of rmath3d.so.
126
+
127
+
128
+ ## Notes ##
129
+
130
+ ### Collaboration with ruby-opengl ###
131
+
132
+ The instances of RMtx4 can be used directly as the arguments of the
133
+ ruby-opengl functions that accept matrices.
134
+
135
+ For example, this code snippet using RMath:
136
+
137
+ eye = RVec3.new(0.0, 15.0, 15.0)
138
+ at = RVec3.new(0.0, 0.0, 0.0)
139
+ up = RVec3.new(0.0, 1.0, 0.0)
140
+ mtxLookAt = RMtx4.new.lookAtRH( eye, at, up )
141
+ glMatrixMode( GL_PROJECTION )
142
+ glLoadMatrix( @mtxProj )
143
+
144
+ mtxProj = RMtx4.new.perspectiveFovRH( 30.0*Math::PI/180.0, WINDOW_WIDTH/WINDOW_HEIGHT, 0.1, 1000.0 )
145
+ glMatrixMode( GL_MODELVIEW )
146
+ glLoadMatrix( @mtxLookAt )
147
+
148
+ has the same transformation effect with the OpenGL fixed pipeline:
149
+
150
+ glMatrixMode( GL_PROJECTION )
151
+ gluPerspective( 30.0*Math::PI/180.0, WINDOW_WIDTH/WINDOW_HEIGHT, 0.1, 1000.0 )
152
+
153
+ glMatrixMode( GL_MODELVIEW )
154
+ gluLookAt( 0.0,15.0,15.0, 0.0,0.0,0.0, 0.0,1.0,0.0 )
155
+
156
+
157
+ ### Compatibility with matrix.rb ###
158
+
159
+ Currently, there is no combenient way to convert between matrix.rb's
160
+ +Matrix+ and +RMtx{3|4}".
161
+
162
+ (The matrix.rb is a standard Ruby library that provides N-dimensional
163
+ +Vector+ class and "N x M" +Matrix+ class.)
164
+
165
+
166
+
167
+ ## Information ##
168
+
169
+ * RubyGems
170
+ * https://rubygems.org/gems/rmath3d
171
+ * Github
172
+ * https://github.com/vaiorabbit/rmath3d
173
+
174
+
175
+ ## License ##
176
+
177
+ All source codes are available under the terms of the zlib/libpng license
178
+ (see LICENSE.txt).
@@ -0,0 +1,3311 @@
1
+ module RMath3D
2
+
3
+ TOLERANCE = 1.0e-15
4
+
5
+ #
6
+ # Document-class: RMath3D::RMtx3
7
+ # provies 3x3 matrix arithmetic.
8
+ #
9
+ # <b>Notice</b>
10
+ # * elements are stored in column-major order.
11
+ #
12
+ class RMtx3
13
+
14
+ #
15
+ # call-seq:
16
+ # RMtx3.new -> ((1,0,0),(0,1,0),(0,0,1))
17
+ # RMtx3.new(e) -> ((e,e,e), (e,e,e), (e,e,e))
18
+ # RMtx3.new( other ) : Copy Constructor
19
+ # RMtx3.new( e0, e1, ..., e8 ) -> ((e0,e1,e2), (e3,e4,e5), (e6,e7,e8))
20
+ #
21
+ # Creates a new 3x3 matrix.
22
+ #
23
+ def initialize( *a )
24
+ # [NOTE] elemetns are stored in column-major order.
25
+ @e = []
26
+ case a.length
27
+ when 0
28
+ @e = [ 0.0, 0.0, 0.0,
29
+ 0.0, 0.0, 0.0,
30
+ 0.0, 0.0, 0.0 ]
31
+ when 1
32
+ case a[0]
33
+ when Fixnum, Float
34
+ @e = [ a[0], a[0], a[0],
35
+ a[0], a[0], a[0],
36
+ a[0], a[0], a[0] ]
37
+ when RMtx3
38
+ # Copy Constructor
39
+ @e = [ a[0].e00, a[0].e10, a[0].e20,
40
+ a[0].e01, a[0].e11, a[0].e21,
41
+ a[0].e02, a[0].e12, a[0].e22 ]
42
+ else
43
+ raise TypeError, "RMtx3#initialize : Unknown type #{a[0].class}."
44
+ return nil
45
+ end
46
+ when 9
47
+ # Element-wise setter
48
+ for row in 0...3 do
49
+ for col in 0...3 do
50
+ index = 3*row + col
51
+ case a[index]
52
+ when Fixnum, Float
53
+ setElement( row, col, a[index] )
54
+ else
55
+ raise TypeError, "RMtx3#initialize : Unknown type #{a[0].class}."
56
+ return nil
57
+ end
58
+ end
59
+ end
60
+ else
61
+ raise RuntimeError, "RMtx3#initialize : wrong # of arguments (#{a.length})"
62
+ return nil
63
+ end
64
+
65
+ return self
66
+ end
67
+
68
+ #
69
+ # call-seq: to_s
70
+ #
71
+ # Returns human-readable string.
72
+ #
73
+ def to_s
74
+ "( #{@e[0]}, #{@e[3]}, #{@e[6]} )\n" +
75
+ "( #{@e[1]}, #{@e[4]}, #{@e[7]} )\n" +
76
+ "( #{@e[2]}, #{@e[5]}, #{@e[8]} )\n"
77
+ end
78
+
79
+ #
80
+ # call-seq: to_a
81
+ #
82
+ # Returns its elements as a new Array.
83
+ #
84
+ def to_a
85
+ return @e
86
+ end
87
+
88
+ #
89
+ # call-seq: coerse(other)
90
+ #
91
+ # Resolves type mismatch.
92
+ #
93
+ def coerce
94
+ case arg
95
+ when Fixnum, Float, Bignum
96
+ return [ self, arg ]
97
+ else
98
+ raise TypeError, "RMtx3#coerce : #{arg.self} can't be coerced into #{self.class}."
99
+ return nil
100
+ end
101
+ end
102
+
103
+ #
104
+ # call-seq: setElements( e0, e1, ..., e8 )
105
+ #
106
+ # Stores given 9 new values.
107
+ #
108
+ def setElements( *a )
109
+ if a.length != 9
110
+ raise RuntimeError, "RMtx3#setElements : wrong # of arguments (#{a.length})"
111
+ return nil
112
+ end
113
+
114
+ for row in 0...3 do
115
+ for col in 0...3 do
116
+ index = 3*row + col
117
+ setElement( row, col, a[index] )
118
+ end
119
+ end
120
+ end
121
+
122
+ #
123
+ # call-seq: [row,col]= value
124
+ #
125
+ # Stores +value+ at (+row+,+col+).
126
+ #
127
+ def []=(row,col,value)
128
+ # [NOTE] elemetns are stored in column-major order.
129
+ @e[col*3+row] = value
130
+ end
131
+ alias_method :setElement, :'[]='
132
+
133
+ #
134
+ # call-seq: [row,col] -> value
135
+ #
136
+ # Returns the element at (+row+,+col+).
137
+ #
138
+ def [](row,col)
139
+ # [NOTE] elemetns are stored in column-major order.
140
+ return @e[col*3+row]
141
+ end
142
+ alias_method :getElement, :'[]'
143
+
144
+ # Returns the element at row 0 and column 0.
145
+ def e00() getElement(0,0) end
146
+ # Returns the element at row 0 and column 1.
147
+ def e01() getElement(0,1) end
148
+ # Returns the element at row 0 and column 2.
149
+ def e02() getElement(0,2) end
150
+ # Returns the element at row 1 and column 0.
151
+ def e10() getElement(1,0) end
152
+ # Returns the element at row 1 and column 1.
153
+ def e11() getElement(1,1) end
154
+ # Returns the element at row 1 and column 2.
155
+ def e12() getElement(1,2) end
156
+ # Returns the element at row 2 and column 0.
157
+ def e20() getElement(2,0) end
158
+ # Returns the element at row 2 and column 1.
159
+ def e21() getElement(2,1) end
160
+ # Returns the element at row 2 and column 2.
161
+ def e22() getElement(2,2) end
162
+
163
+ # Replaces the element at row 0 and column 0 by +value+.
164
+ def e00=(value) setElement(0,0,value) end
165
+ # Replaces the element at row 0 and column 1 by +value+.
166
+ def e01=(value) setElement(0,1,value) end
167
+ # Replaces the element at row 0 and column 2 by +value+.
168
+ def e02=(value) setElement(0,2,value) end
169
+ # Replaces the element at row 1 and column 0 by +value+.
170
+ def e10=(value) setElement(1,0,value) end
171
+ # Replaces the element at row 1 and column 1 by +value+.
172
+ def e11=(value) setElement(1,1,value) end
173
+ # Replaces the element at row 1 and column 2 by +value+.
174
+ def e12=(value) setElement(1,2,value) end
175
+ # Replaces the element at row 2 and column 0 by +value+.
176
+ def e20=(value) setElement(2,0,value) end
177
+ # Replaces the element at row 2 and column 1 by +value+.
178
+ def e21=(value) setElement(2,1,value) end
179
+ # Replaces the element at row 2 and column 2 by +value+.
180
+ def e22=(value) setElement(2,2,value) end
181
+
182
+
183
+ #
184
+ # call-seq: mtx3.getRow(r) -> RVec3
185
+ #
186
+ # Returns +r+-th row vector.
187
+ #
188
+ def getRow( row )
189
+ return RVec3.new( self[row,0], self[row,1], self[row,2] )
190
+ end
191
+
192
+ #
193
+ # call-seq: mtx3.getColumn(c) -> RVec3
194
+ #
195
+ # Returns +c+-th column vector.
196
+ #
197
+ def getColumn( column )
198
+ return RVec3.new( self[0,column], self[1,column], self[2,column] )
199
+ end
200
+
201
+ #
202
+ # call-seq: mtx3.setRow(v,r)
203
+ #
204
+ # Returns sets +r+-th row by vector +v+.
205
+ #
206
+ def setRow( v, row )
207
+ self[row,0] = v.x
208
+ self[row,1] = v.y
209
+ self[row,2] = v.z
210
+ end
211
+
212
+ #
213
+ # call-seq: mtx3.setColumn(v,c)
214
+ #
215
+ # Returns sets +c+-th column by vector +v+.
216
+ #
217
+ def setColumn( v, column )
218
+ self[0,column] = v.x
219
+ self[1,column] = v.y
220
+ self[2,column] = v.z
221
+ end
222
+
223
+ #
224
+ # call-seq: setZero
225
+ #
226
+ # Clears all elements by 0.0
227
+ #
228
+ def setZero
229
+ 9.times do |i|
230
+ @e[i] = 0.0
231
+ end
232
+ return self
233
+ end
234
+
235
+ #
236
+ # call-seq: setIdentity
237
+ #
238
+ # Sets as identity matrix.
239
+ #
240
+ def setIdentity
241
+ for row in 0...3 do
242
+ for col in 0...3 do
243
+ index = 3*row + col
244
+ if ( row == col )
245
+ setElement( row, col, 1.0 )
246
+ else
247
+ setElement( row, col, 0.0 )
248
+ end
249
+ end
250
+ end
251
+ return self
252
+ end
253
+
254
+ #
255
+ # call-seq: getDeterminant -> determinant
256
+ #
257
+ # Calculates determinant.
258
+ #
259
+ def getDeterminant
260
+ e00 * (e11*e22 - e12*e21) -
261
+ e01 * (e10*e22 - e12*e20) +
262
+ e02 * (e10*e21 - e11*e20)
263
+ end
264
+
265
+ #
266
+ # call-seq: getTransposed
267
+ #
268
+ # Returns transposed matrix.
269
+ #
270
+ def getTransposed
271
+ return RMtx3.new( @e[0], @e[1], @e[2],
272
+ @e[3], @e[4], @e[5],
273
+ @e[6], @e[7], @e[8] )
274
+ end
275
+
276
+ #
277
+ # call-seq: transpose!
278
+ #
279
+ # Transposeas its elements.
280
+ #
281
+ def transpose!
282
+ @e[1], @e[3] = @e[3], @e[1]
283
+ @e[2], @e[6] = @e[6], @e[2]
284
+ @e[5], @e[7] = @e[7], @e[5]
285
+ end
286
+
287
+ #
288
+ # call-seq: getInverse -> inverse
289
+ #
290
+ # Returns the inverse.
291
+ #
292
+ def getInverse
293
+ result = RMtx3.new
294
+
295
+ result.e00 = (self.e11*self.e22 - self.e12*self.e21)
296
+ result.e01 = -(self.e01*self.e22 - self.e02*self.e21)
297
+ result.e02 = (self.e01*self.e12 - self.e02*self.e11)
298
+
299
+ result.e10 = -(self.e10*self.e22 - self.e12*self.e20)
300
+ result.e11 = (self.e00*self.e22 - self.e02*self.e20)
301
+ result.e12 = -(self.e00*self.e12 - self.e02*self.e10)
302
+
303
+ result.e20 = (self.e10*self.e21 - self.e11*self.e20)
304
+ result.e21 = -(self.e00*self.e21 - self.e01*self.e20)
305
+ result.e22 = (self.e00*self.e11 - self.e01*self.e10)
306
+
307
+ det = e00 * result.e00 + e01 * result.e10 + e02 * result.e20
308
+
309
+ if ( det.abs < TOLERANCE )
310
+ raise RuntimeError, "RMtx3#getInverse : det.abs < TOLERANCE"
311
+ return nil
312
+ end
313
+
314
+ d = 1.0 / det
315
+
316
+ result.mul!( d )
317
+
318
+ return result
319
+ end
320
+
321
+ #
322
+ # call-seq: invert! -> self
323
+ #
324
+ # Makes itself as the inverse of the original matrix.
325
+ #
326
+ def invert!
327
+ elements = Array.new( 9 )
328
+
329
+ elements[3*0+0] = (self.e11*self.e22 - self.e12*self.e21)
330
+ elements[3*0+1] = -(self.e01*self.e22 - self.e02*self.e21)
331
+ elements[3*0+2] = (self.e01*self.e12 - self.e02*self.e11)
332
+
333
+ elements[3*1+0] = -(self.e10*self.e22 - self.e12*self.e20)
334
+ elements[3*1+1] = (self.e00*self.e22 - self.e02*self.e20)
335
+ elements[3*1+2] = -(self.e00*self.e12 - self.e02*self.e10)
336
+
337
+ elements[3*2+0] = (self.e10*self.e21 - self.e11*self.e20)
338
+ elements[3*2+1] = -(self.e00*self.e21 - self.e01*self.e20)
339
+ elements[3*2+2] = (self.e00*self.e11 - self.e01*self.e10)
340
+
341
+ det = e00 * elements[3*0+0] + e01 * elements[3*1+0] + e02 * elements[3*2+0]
342
+
343
+ if ( det.abs < TOLERANCE )
344
+ raise RuntimeError, "RMtx3#invert! : det.abs < TOLERANCE"
345
+ return nil
346
+ end
347
+
348
+ d = 1.0 / det
349
+
350
+ setElement( 0, 0, d * elements[3*0+0] )
351
+ setElement( 0, 1, d * elements[3*0+1] )
352
+ setElement( 0, 2, d * elements[3*0+2] )
353
+ setElement( 1, 0, d * elements[3*1+0] )
354
+ setElement( 1, 1, d * elements[3*1+1] )
355
+ setElement( 1, 2, d * elements[3*1+2] )
356
+ setElement( 2, 0, d * elements[3*2+0] )
357
+ setElement( 2, 1, d * elements[3*2+1] )
358
+ setElement( 2, 2, d * elements[3*2+2] )
359
+
360
+ return self
361
+ end
362
+
363
+ #
364
+ # call-seq: rotationX(radian) -> self
365
+ #
366
+ # Makes a matrix that rotates around the x-axis.
367
+ #
368
+ def rotationX( radian )
369
+ s = Math.sin( radian )
370
+ c = Math.cos( radian )
371
+
372
+ setIdentity()
373
+ self.e11 = c
374
+ self.e12 = -s
375
+ self.e21 = s
376
+ self.e22 = c
377
+
378
+ return self
379
+ end
380
+
381
+ #
382
+ # call-seq: rotationY(radian) -> self
383
+ #
384
+ # Makes a matrix that rotates around the y-axis.
385
+ #
386
+ def rotationY( radian )
387
+ s = Math.sin( radian )
388
+ c = Math.cos( radian )
389
+
390
+ setIdentity()
391
+ self.e00 = c
392
+ self.e02 = s
393
+ self.e20 = -s
394
+ self.e22 = c
395
+
396
+ return self
397
+ end
398
+
399
+ #
400
+ # call-seq: rotationZ(radian) -> self
401
+ #
402
+ # Makes a matrix that rotates around the z-axis.
403
+ #
404
+ def rotationZ( radian )
405
+ s = Math.sin( radian )
406
+ c = Math.cos( radian )
407
+
408
+ setIdentity()
409
+ self.e00 = c
410
+ self.e01 = -s
411
+ self.e10 = s
412
+ self.e11 = c
413
+
414
+ return self
415
+ end
416
+
417
+ #
418
+ # call-seq: rotationAxis(axis,radian) -> self
419
+ #
420
+ # Makes a matrix that rotates around the +axis+.
421
+ #
422
+ def rotationAxis( axis, radian )
423
+ if ( axis.class != RVec3 )
424
+ raise TypeError, "RMtx3#rotationAxis : Unknown type #{axis.class} given as axis."
425
+ return nil
426
+ end
427
+ s = Math.sin( radian )
428
+ c = Math.cos( radian )
429
+ omc = 1.0 - c
430
+ x = axis.x.to_f
431
+ y = axis.y.to_f
432
+ z = axis.z.to_f
433
+
434
+ self.e00 = x*x*omc + c
435
+ self.e01 = x*y*omc - z*s
436
+ self.e02 = z*x*omc + y*s
437
+ self.e10 = x*y*omc + z*s
438
+ self.e11 = y*y*omc + c
439
+ self.e12 = y*z*omc - x*s
440
+ self.e20 = z*x*omc - y*s
441
+ self.e21 = y*z*omc + x*s
442
+ self.e22 = z*z*omc + c
443
+
444
+ return self
445
+ end
446
+
447
+ #
448
+ # call-seq: rotationQuaternion(q) -> self
449
+ #
450
+ # Makes a rotation matrix from a normalized quaternion +q+.
451
+ #
452
+ def rotationQuaternion( q )
453
+ if ( q.class != RQuat )
454
+ raise TypeError, "RMtx3#rotationQuaternion : Unknown type #{q.class} given as RQuat."
455
+ return nil
456
+ end
457
+ x = q.x
458
+ y = q.y
459
+ z = q.z
460
+ w = q.w
461
+
462
+ x2 = 2.0 * x
463
+ y2 = 2.0 * y
464
+ z2 = 2.0 * z
465
+
466
+ xx2 = x * x2
467
+ yy2 = y * y2
468
+ zz2 = z * z2
469
+
470
+ yz2 = y * z2
471
+ wx2 = w * x2
472
+ xy2 = x * y2
473
+ wz2 = w * z2
474
+ xz2 = x * z2
475
+ wy2 = w * y2
476
+
477
+ self.e00 = 1.0 - yy2 - zz2
478
+ self.e10 = xy2 + wz2
479
+ self.e20 = xz2 - wy2
480
+ self.e01 = xy2 - wz2
481
+ self.e11 = 1.0 - xx2 - zz2
482
+ self.e21 = yz2 + wx2
483
+ self.e02 = xz2 + wy2
484
+ self.e12 = yz2 - wx2
485
+ self.e22 = 1.0 - xx2 - yy2
486
+
487
+ return self
488
+ end
489
+
490
+ #
491
+ # call-seq: scaling(sx,sy,sz) -> self
492
+ #
493
+ # Makes itself as a scaling matrix.
494
+ #
495
+ def scaling( sx, sy, sz )
496
+ setIdentity()
497
+ setElement( 0, 0, sx )
498
+ setElement( 1, 1, sy )
499
+ setElement( 2, 2, sz )
500
+
501
+ return self
502
+ end
503
+
504
+ #
505
+ # call-seq: +
506
+ #
507
+ # +mtx : Unary plus operator.
508
+ #
509
+ def +@
510
+ return self
511
+ end
512
+
513
+ #
514
+ # call-seq: -
515
+ #
516
+ # -mtx : Unary minus operator.
517
+ #
518
+ def -@
519
+ return RMtx3.new( self * -1.0 )
520
+ end
521
+
522
+ #
523
+ # call-seq: +
524
+ #
525
+ # mtx1 + mtx2 : Binary plus operator.
526
+ #
527
+ def +( arg )
528
+ if ( arg.class != RMtx3 )
529
+ raise TypeError, "RMtx3#+(arg) : Unknown type #{arg.class} given as RMtx3."
530
+ return nil
531
+ end
532
+
533
+ result = RMtx3.new
534
+ for row in 0...3 do
535
+ for col in 0...3 do
536
+ result.setElement( row, col, getElement(row,col) + arg.getElement(row,col) )
537
+ end
538
+ end
539
+
540
+ return result
541
+ end
542
+
543
+ #
544
+ # call-seq: -
545
+ #
546
+ # mtx1 - mtx2 : Binary minus operator.
547
+ #
548
+ def -( arg )
549
+ if ( arg.class != RMtx3 )
550
+ raise TypeError, "RMtx3#-(arg) : Unknown type #{arg.class} given as RMtx3."
551
+ return nil
552
+ end
553
+
554
+ result = RMtx3.new
555
+ for row in 0...3 do
556
+ for col in 0...3 do
557
+ result.setElement( row, col, getElement(row,col) - arg.getElement(row,col) )
558
+ end
559
+ end
560
+
561
+ return result
562
+ end
563
+
564
+ #
565
+ # call-seq: *
566
+ #
567
+ # mtx1 * mtx2 : Binary multiply operator.
568
+ #
569
+ def *( arg )
570
+ case arg
571
+ when Fixnum, Float, Bignum
572
+ return RMtx3.new( arg*self.e00, arg*self.e01, arg*self.e02,
573
+ arg*self.e10, arg*self.e11, arg*self.e12,
574
+ arg*self.e20, arg*self.e21, arg*self.e22 )
575
+
576
+ when RMtx3
577
+ result = RMtx3.new
578
+ for row in 0...3 do
579
+ for col in 0...3 do
580
+ sum = 0.0
581
+ for i in 0...3 do
582
+ sum += getElement( row, i ) * arg.getElement( i, col )
583
+ end
584
+ result.setElement( row, col, sum )
585
+ end
586
+ end
587
+ return result
588
+
589
+ else
590
+ raise TypeError, "RMtx3#*(arg) : Unknown type #{arg.class} given."
591
+ return nil
592
+ end
593
+ end
594
+
595
+ #
596
+ # call-seq: ==
597
+ #
598
+ # mtx1 == mtx2 : evaluates equality.
599
+ #
600
+ def ==( other )
601
+ if ( other.class != RMtx3 )
602
+ raise TypeError, "RMtx3#==(other) : Unknown type #{other.class} given as RMtx3."
603
+ return nil
604
+ end
605
+
606
+ for row in 0...3 do
607
+ for col in 0...3 do
608
+ if ( (getElement(row,col) - other.getElement(row,col)).abs > TOLERANCE )
609
+ return false
610
+ end
611
+ end
612
+ end
613
+ return true
614
+ end
615
+
616
+ #
617
+ # call-seq: mtx1.add!( mtx2 )
618
+ #
619
+ # mtx1 += mtx2 : appends the elements of +mtx2+ into corresponding +mtx1+ elements.
620
+ #
621
+ def add!( other )
622
+ if ( other.class != RMtx3 )
623
+ raise TypeError, "RMtx3#add! : Unknown type #{other.class} given as RMtx3."
624
+ return nil
625
+ end
626
+
627
+ result = RMtx3.new
628
+ for row in 0...3 do
629
+ for col in 0...3 do
630
+ self.setElement( row, col, getElement(row,col) + other.getElement(row,col) )
631
+ end
632
+ end
633
+
634
+ return self
635
+ end
636
+
637
+ #
638
+ # call-seq: mtx1.sub!( mtx2 )
639
+ #
640
+ # mtx1 -= mtx2 : subtracts the elements of +mtx2+ from corresponding +mtx1+ elements.
641
+ #
642
+ def sub!( other )
643
+ if ( other.class != RMtx3 )
644
+ raise TypeError, "RMtx3#sub! : Unknown type #{other.class} given as RMtx3."
645
+ return nil
646
+ end
647
+
648
+ result = RMtx3.new
649
+ for row in 0...3 do
650
+ for col in 0...3 do
651
+ self.setElement( row, col, getElement(row,col) - other.getElement(row,col) )
652
+ end
653
+ end
654
+
655
+ return self
656
+ end
657
+
658
+ #
659
+ # call-seq: mtx1.mul!( mtx2 )
660
+ #
661
+ # mtx1 *= mtx2
662
+ #
663
+ def mul!( other )
664
+ case other
665
+ when Fixnum, Float, Bignum
666
+ self.e00 = other*self.e00
667
+ self.e01 = other*self.e01
668
+ self.e02 = other*self.e02
669
+ self.e10 = other*self.e10
670
+ self.e11 = other*self.e11
671
+ self.e12 = other*self.e12
672
+ self.e20 = other*self.e20
673
+ self.e21 = other*self.e21
674
+ self.e22 = other*self.e22
675
+
676
+ return self
677
+ when RMtx3
678
+ result = RMtx3.new
679
+ for row in 0...3 do
680
+ for col in 0...3 do
681
+ sum = 0.0
682
+ for i in 0...3 do
683
+ sum += getElement( row, i ) * other.getElement( i, col )
684
+ end
685
+ result.setElement( row, col, sum )
686
+ end
687
+ end
688
+
689
+ self.e00 = result.e00
690
+ self.e01 = result.e01
691
+ self.e02 = result.e02
692
+ self.e10 = result.e10
693
+ self.e11 = result.e11
694
+ self.e12 = result.e12
695
+ self.e20 = result.e20
696
+ self.e21 = result.e21
697
+ self.e22 = result.e22
698
+
699
+ return self
700
+ end
701
+ end
702
+ end
703
+
704
+ #
705
+ # Document-class: RMath3D::RMtx4
706
+ # provies 4x4 matrix arithmetic.
707
+ #
708
+ # <b>Notice</b>
709
+ # * elements are stored in column-major order.
710
+ #
711
+ class RMtx4
712
+
713
+ #
714
+ # call-seq:
715
+ # RMtx4.new -> ((1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1))
716
+ # RMtx4.new(e) -> ((e,e,e,e),(e,e,e,e),(e,e,e,e),(e,e,e,e))
717
+ # RMtx4.new( other ) : Copy Constructor
718
+ # RMtx4.new( e0, e1, ..., e15 ) -> ((e0,e1,e2,e3),(e4,e5,e6,e7),(e8,e9,e10,e11),(e12,e13,e14,e15))
719
+ #
720
+ # Creates a new 4x4 matrix.
721
+ #
722
+ def initialize( *a )
723
+ # [NOTE] elemetns are stored in column-major order.
724
+ @e = []
725
+ case a.length
726
+ when 0
727
+ @e = [ 0.0, 0.0, 0.0, 0.0,
728
+ 0.0, 0.0, 0.0, 0.0,
729
+ 0.0, 0.0, 0.0, 0.0,
730
+ 0.0, 0.0, 0.0, 0.0 ]
731
+ when 1
732
+ case a[0]
733
+ when Fixnum, Float
734
+ @e = [ a[0], a[0], a[0], a[0],
735
+ a[0], a[0], a[0], a[0],
736
+ a[0], a[0], a[0], a[0],
737
+ a[0], a[0], a[0], a[0] ]
738
+ when RMtx4
739
+ # Copy Constructor
740
+ @e = [ a[0].e00, a[0].e10, a[0].e20, a[0].e30,
741
+ a[0].e01, a[0].e11, a[0].e21, a[0].e31,
742
+ a[0].e02, a[0].e12, a[0].e22, a[0].e32,
743
+ a[0].e03, a[0].e13, a[0].e23, a[0].e33 ]
744
+ else
745
+ raise TypeError, "RMtx4#initialize : Unknown type #{a[0].class}."
746
+ return nil
747
+ end
748
+ when 16
749
+ # Element-wise setter
750
+ for row in 0...4 do
751
+ for col in 0...4 do
752
+ index = 4*row + col
753
+ case a[index]
754
+ when Fixnum, Float
755
+ setElement( row, col, a[index] )
756
+ else
757
+ raise TypeError, "RMtx4#initialize : Unknown type #{a[0].class}."
758
+ return nil
759
+ end
760
+ end
761
+ end
762
+ else
763
+ raise RuntimeError, "RMtx4#initialize : wrong # of arguments (#{a.length})"
764
+ return nil
765
+ end
766
+
767
+ return self
768
+ end
769
+
770
+ #
771
+ # call-seq: to_s
772
+ #
773
+ # Returns human-readable string.
774
+ #
775
+ def to_s
776
+ "( #{@e[0]}, #{@e[4]}, #{@e[8]}, #{@e[12]} )\n" +
777
+ "( #{@e[1]}, #{@e[5]}, #{@e[9]}, #{@e[13]} )\n" +
778
+ "( #{@e[2]}, #{@e[6]}, #{@e[10]}, #{@e[14]} )\n" +
779
+ "( #{@e[3]}, #{@e[7]}, #{@e[11]}, #{@e[15]} )\n"
780
+ end
781
+
782
+ #
783
+ # call-seq: to_a
784
+ #
785
+ # Returns its elements as a new Array.
786
+ #
787
+ def to_a
788
+ return @e
789
+ end
790
+
791
+ #
792
+ # call-seq: coerse(other)
793
+ #
794
+ # Resolves type mismatch.
795
+ #
796
+ def coerce
797
+ case arg
798
+ when Fixnum, Float, Bignum
799
+ return [ self, arg ]
800
+ else
801
+ raise TypeError, "RMtx4#coerce : #{arg.self} can't be coerced into #{self.class}."
802
+ return nil
803
+ end
804
+ end
805
+
806
+ #
807
+ # call-seq: setElements( e0, e1, ..., e15 )
808
+ #
809
+ # Stores given 16 new values.
810
+ #
811
+ def setElements( *a )
812
+ if a.length != 16
813
+ raise RuntimeError, "RMtx4#setElements : wrong # of arguments (#{a.length})"
814
+ return nil
815
+ end
816
+
817
+ for row in 0...4 do
818
+ for col in 0...4 do
819
+ index = 4*row + col
820
+ setElement( row, col, a[index] )
821
+ end
822
+ end
823
+ end
824
+
825
+ #
826
+ # call-seq: [row,col]= value
827
+ #
828
+ # Stores +value+ at (+row+,+col+).
829
+ #
830
+ def []=(row,col,value)
831
+ # [NOTE] elemetns are stored in column-major order.
832
+ @e[col*4+row] = value
833
+ end
834
+ alias_method :setElement, :'[]='
835
+
836
+ #
837
+ # call-seq: [row,col] -> value
838
+ #
839
+ # Returns the element at (+row+,+col+).
840
+ #
841
+ def [](row,col)
842
+ # [NOTE] elemetns are stored in column-major order.
843
+ return @e[col*4+row]
844
+ end
845
+ alias_method :getElement, :'[]'
846
+
847
+ # Returns the element at row 0 and column 0.
848
+ def e00() getElement(0,0) end
849
+ # Returns the element at row 0 and column 1.
850
+ def e01() getElement(0,1) end
851
+ # Returns the element at row 0 and column 2.
852
+ def e02() getElement(0,2) end
853
+ # Returns the element at row 0 and column 3.
854
+ def e03() getElement(0,3) end
855
+ # Returns the element at row 1 and column 0.
856
+ def e10() getElement(1,0) end
857
+ # Returns the element at row 1 and column 1.
858
+ def e11() getElement(1,1) end
859
+ # Returns the element at row 1 and column 2.
860
+ def e12() getElement(1,2) end
861
+ # Returns the element at row 1 and column 3.
862
+ def e13() getElement(1,3) end
863
+ # Returns the element at row 2 and column 0.
864
+ def e20() getElement(2,0) end
865
+ # Returns the element at row 2 and column 1.
866
+ def e21() getElement(2,1) end
867
+ # Returns the element at row 2 and column 2.
868
+ def e22() getElement(2,2) end
869
+ # Returns the element at row 2 and column 3.
870
+ def e23() getElement(2,3) end
871
+ # Returns the element at row 3 and column 0.
872
+ def e30() getElement(3,0) end
873
+ # Returns the element at row 3 and column 1.
874
+ def e31() getElement(3,1) end
875
+ # Returns the element at row 3 and column 2.
876
+ def e32() getElement(3,2) end
877
+ # Returns the element at row 3 and column 3.
878
+ def e33() getElement(3,3) end
879
+
880
+ # Replaces the element at row 0 and column 0 by +value+.
881
+ def e00=(value) setElement(0,0,value) end
882
+ # Replaces the element at row 0 and column 1 by +value+.
883
+ def e01=(value) setElement(0,1,value) end
884
+ # Replaces the element at row 0 and column 2 by +value+.
885
+ def e02=(value) setElement(0,2,value) end
886
+ # Replaces the element at row 0 and column 3 by +value+.
887
+ def e03=(value) setElement(0,3,value) end
888
+ # Replaces the element at row 1 and column 0 by +value+.
889
+ def e10=(value) setElement(1,0,value) end
890
+ # Replaces the element at row 1 and column 1 by +value+.
891
+ def e11=(value) setElement(1,1,value) end
892
+ # Replaces the element at row 1 and column 2 by +value+.
893
+ def e12=(value) setElement(1,2,value) end
894
+ # Replaces the element at row 1 and column 3 by +value+.
895
+ def e13=(value) setElement(1,3,value) end
896
+ # Replaces the element at row 2 and column 0 by +value+.
897
+ def e20=(value) setElement(2,0,value) end
898
+ # Replaces the element at row 2 and column 1 by +value+.
899
+ def e21=(value) setElement(2,1,value) end
900
+ # Replaces the element at row 2 and column 2 by +value+.
901
+ def e22=(value) setElement(2,2,value) end
902
+ # Replaces the element at row 2 and column 3 by +value+.
903
+ def e23=(value) setElement(2,3,value) end
904
+ # Replaces the element at row 3 and column 0 by +value+.
905
+ def e30=(value) setElement(3,0,value) end
906
+ # Replaces the element at row 3 and column 1 by +value+.
907
+ def e31=(value) setElement(3,1,value) end
908
+ # Replaces the element at row 3 and column 2 by +value+.
909
+ def e32=(value) setElement(3,2,value) end
910
+ # Replaces the element at row 3 and column 3 by +value+.
911
+ def e33=(value) setElement(3,3,value) end
912
+
913
+ #
914
+ # call-seq: mtx4.getRow(r) -> RVec4
915
+ #
916
+ # Returns +r+-th row vector.
917
+ #
918
+ def getRow( row )
919
+ return RVec4.new( self[row,0], self[row,1], self[row,2], self[row,3] )
920
+ end
921
+
922
+ #
923
+ # call-seq: mtx4.getColumn(c) -> RVec4
924
+ #
925
+ # Returns +c+-th column vector.
926
+ #
927
+ def getColumn( column )
928
+ return RVec4.new( self[0,column], self[1,column], self[2,column], self[3,column] )
929
+ end
930
+
931
+ #
932
+ # call-seq: mtx4.setRow(v,r)
933
+ #
934
+ # Returns sets +r+-th row by vector +v+.
935
+ #
936
+ def setRow( v, row )
937
+ self[row,0] = v.x
938
+ self[row,1] = v.y
939
+ self[row,2] = v.z
940
+ self[row,3] = v.w
941
+ end
942
+
943
+ #
944
+ # call-seq: mtx4.setColumn(v,c)
945
+ #
946
+ # Returns sets +c+-th column by vector +v+.
947
+ #
948
+ def setColumn( v, column )
949
+ self[0,column] = v.x
950
+ self[1,column] = v.y
951
+ self[2,column] = v.z
952
+ self[3,column] = v.w
953
+ end
954
+
955
+ def getUpper3x3
956
+ return RMtx3.new( self.e00, self.e01, self.e02,
957
+ self.e10, self.e11, self.e12,
958
+ self.e20, self.e21, self.e22 )
959
+ end
960
+
961
+ def setUpper3x3( mtx3x3 )
962
+ self.e00 = mtx3x3.e00
963
+ self.e01 = mtx3x3.e01
964
+ self.e02 = mtx3x3.e02
965
+ self.e10 = mtx3x3.e10
966
+ self.e11 = mtx3x3.e11
967
+ self.e12 = mtx3x3.e12
968
+ self.e20 = mtx3x3.e20
969
+ self.e21 = mtx3x3.e21
970
+ self.e22 = mtx3x3.e22
971
+
972
+ return self
973
+ end
974
+
975
+ # call-seq: setZero
976
+ #
977
+ # Clears all elements by 0.0
978
+ #
979
+ def setZero
980
+ 16.times do |i|
981
+ @e[i] = 0.0
982
+ end
983
+ return self
984
+ end
985
+
986
+ #
987
+ # call-seq: setIdentity
988
+ #
989
+ # Sets as identity matrix.
990
+ #
991
+ def setIdentity
992
+ for row in 0...4 do
993
+ for col in 0...4 do
994
+ index = 4*row + col
995
+ if ( row == col )
996
+ setElement( row, col, 1.0 )
997
+ else
998
+ setElement( row, col, 0.0 )
999
+ end
1000
+ end
1001
+ end
1002
+ return self
1003
+ end
1004
+
1005
+ def det3( _e00,_e01,_e02, _e10,_e11,_e12, _e20,_e21,_e22 )
1006
+ _e00 * (_e11*_e22 - _e12*_e21) -
1007
+ _e01 * (_e10*_e22 - _e12*_e20) +
1008
+ _e02 * (_e10*_e21 - _e11*_e20)
1009
+ end
1010
+ private :det3
1011
+
1012
+ #
1013
+ # call-seq: getDeterminant -> determinant
1014
+ #
1015
+ # Calculates determinant.
1016
+ #
1017
+ def getDeterminant
1018
+ e00 * det3( e11,e12,e13, e21,e22,e23, e31,e32,e33 ) -
1019
+ e01 * det3( e10,e12,e13, e20,e22,e23, e30,e32,e33 ) +
1020
+ e02 * det3( e10,e11,e13, e20,e21,e23, e30,e31,e33 ) -
1021
+ e03 * det3( e10,e11,e12, e20,e21,e22, e30,e31,e32 )
1022
+ end
1023
+
1024
+ #
1025
+ # call-seq: getTransposed
1026
+ #
1027
+ # Returns transposed matrix.
1028
+ #
1029
+ def getTransposed
1030
+ return RMtx4.new( @e[ 0], @e[ 1], @e[ 2], @e[ 3],
1031
+ @e[ 4], @e[ 5], @e[ 6], @e[ 7],
1032
+ @e[ 8], @e[ 9], @e[10], @e[11],
1033
+ @e[12], @e[13], @e[14], @e[15] )
1034
+ end
1035
+
1036
+ #
1037
+ # call-seq: transpose!
1038
+ #
1039
+ # Transposeas its elements.
1040
+ #
1041
+ def transpose!
1042
+ @e[ 1], @e[ 4] = @e[ 4], @e[ 1]
1043
+ @e[ 2], @e[ 8] = @e[ 8], @e[ 2]
1044
+ @e[ 3], @e[12] = @e[12], @e[ 3]
1045
+ @e[ 6], @e[ 9] = @e[ 9], @e[ 6]
1046
+ @e[ 7], @e[13] = @e[13], @e[ 7]
1047
+ @e[11], @e[14] = @e[14], @e[11]
1048
+ end
1049
+
1050
+ #
1051
+ # call-seq: getInverse -> inverse
1052
+ #
1053
+ # Returns the inverse.
1054
+ #
1055
+ def getInverse
1056
+ result = RMtx4.new
1057
+
1058
+ result.e00 = det3( e11,e12,e13, e21,e22,e23, e31,e32,e33 )
1059
+ result.e01 = -det3( e01,e02,e03, e21,e22,e23, e31,e32,e33 )
1060
+ result.e02 = det3( e01,e02,e03, e11,e12,e13, e31,e32,e33 )
1061
+ result.e03 = -det3( e01,e02,e03, e11,e12,e13, e21,e22,e23 )
1062
+
1063
+ result.e10 = -det3( e10,e12,e13, e20,e22,e23, e30,e32,e33 )
1064
+ result.e11 = det3( e00,e02,e03, e20,e22,e23, e30,e32,e33 )
1065
+ result.e12 = -det3( e00,e02,e03, e10,e12,e13, e30,e32,e33 )
1066
+ result.e13 = det3( e00,e02,e03, e10,e12,e13, e20,e22,e23 )
1067
+
1068
+ result.e20 = det3( e10,e11,e13, e20,e21,e23, e30,e31,e33 )
1069
+ result.e21 = -det3( e00,e01,e03, e20,e21,e23, e30,e31,e33 )
1070
+ result.e22 = det3( e00,e01,e03, e10,e11,e13, e30,e31,e33 )
1071
+ result.e23 = -det3( e00,e01,e03, e10,e11,e13, e20,e21,e23 )
1072
+
1073
+ result.e30 = -det3( e10,e11,e12, e20,e21,e22, e30,e31,e32 )
1074
+ result.e31 = det3( e00,e01,e02, e20,e21,e22, e30,e31,e32 )
1075
+ result.e32 = -det3( e00,e01,e02, e10,e11,e12, e30,e31,e32 )
1076
+ result.e33 = det3( e00,e01,e02, e10,e11,e12, e20,e21,e22 )
1077
+
1078
+ det = e00 * result.e00 + e01 * result.e10 + e02 * result.e20 + e03 * result.e30
1079
+
1080
+ if ( det.abs < TOLERANCE )
1081
+ raise RuntimeError, "RMtx4#getInverse : det.abs < TOLERANCE"
1082
+ return nil
1083
+ end
1084
+
1085
+ d = 1.0 / det
1086
+
1087
+ result.mul!( d )
1088
+
1089
+ return result
1090
+ end
1091
+
1092
+ #
1093
+ # call-seq: invert! -> self
1094
+ #
1095
+ # Makes itself as the inverse of the original matrix.
1096
+ #
1097
+ def invert!
1098
+ elements = Array.new( 16 )
1099
+
1100
+ elements[4*0+0] = det3( self.e11,self.e12,self.e13, self.e21,self.e22,self.e23, self.e31,self.e32,self.e33 )
1101
+ elements[4*0+1] = -det3( self.e01,self.e02,self.e03, self.e21,self.e22,self.e23, self.e31,self.e32,self.e33 )
1102
+ elements[4*0+2] = det3( self.e01,self.e02,self.e03, self.e11,self.e12,self.e13, self.e31,self.e32,self.e33 )
1103
+ elements[4*0+3] = -det3( self.e01,self.e02,self.e03, self.e11,self.e12,self.e13, self.e21,self.e22,self.e23 )
1104
+
1105
+ elements[4*1+0] = -det3( self.e10,self.e12,self.e13, self.e20,self.e22,self.e23, self.e30,self.e32,self.e33 )
1106
+ elements[4*1+1] = det3( self.e00,self.e02,self.e03, self.e20,self.e22,self.e23, self.e30,self.e32,self.e33 )
1107
+ elements[4*1+2] = -det3( self.e00,self.e02,self.e03, self.e10,self.e12,self.e13, self.e30,self.e32,self.e33 )
1108
+ elements[4*1+3] = det3( self.e00,self.e02,self.e03, self.e10,self.e12,self.e13, self.e20,self.e22,self.e23 )
1109
+
1110
+ elements[4*2+0] = det3( self.e10,self.e11,self.e13, self.e20,self.e21,self.e23, self.e30,self.e31,self.e33 )
1111
+ elements[4*2+1] = -det3( self.e00,self.e01,self.e03, self.e20,self.e21,self.e23, self.e30,self.e31,self.e33 )
1112
+ elements[4*2+2] = det3( self.e00,self.e01,self.e03, self.e10,self.e11,self.e13, self.e30,self.e31,self.e33 )
1113
+ elements[4*2+3] = -det3( self.e00,self.e01,self.e03, self.e10,self.e11,self.e13, self.e20,self.e21,self.e23 )
1114
+
1115
+ elements[4*3+0] = -det3( self.e10,self.e11,self.e12, self.e20,self.e21,self.e22, self.e30,self.e31,self.e32 )
1116
+ elements[4*3+1] = det3( self.e00,self.e01,self.e02, self.e20,self.e21,self.e22, self.e30,self.e31,self.e32 )
1117
+ elements[4*3+2] = -det3( self.e00,self.e01,self.e02, self.e10,self.e11,self.e12, self.e30,self.e31,self.e32 )
1118
+ elements[4*3+3] = det3( self.e00,self.e01,self.e02, self.e10,self.e11,self.e12, self.e20,self.e21,self.e22 )
1119
+
1120
+ det = e00 * elements[4*0+0] + e01 * elements[4*1+0] + e02 * elements[4*2+0] + e03 * elements[4*3+0]
1121
+
1122
+ if ( det.abs< TOLERANCE )
1123
+ raise RuntimeError, "RMtx4invert! : det.abs < TOLERANCE"
1124
+ return nil
1125
+ end
1126
+
1127
+ d = 1.0 / det
1128
+
1129
+ setElement( 0, 0, d * elements[4*0+0] )
1130
+ setElement( 0, 1, d * elements[4*0+1] )
1131
+ setElement( 0, 2, d * elements[4*0+2] )
1132
+ setElement( 0, 3, d * elements[4*0+3] )
1133
+
1134
+ setElement( 1, 0, d * elements[4*1+0] )
1135
+ setElement( 1, 1, d * elements[4*1+1] )
1136
+ setElement( 1, 2, d * elements[4*1+2] )
1137
+ setElement( 1, 3, d * elements[4*1+3] )
1138
+
1139
+ setElement( 2, 0, d * elements[4*2+0] )
1140
+ setElement( 2, 1, d * elements[4*2+1] )
1141
+ setElement( 2, 2, d * elements[4*2+2] )
1142
+ setElement( 2, 3, d * elements[4*2+3] )
1143
+
1144
+ setElement( 3, 0, d * elements[4*3+0] )
1145
+ setElement( 3, 1, d * elements[4*3+1] )
1146
+ setElement( 3, 2, d * elements[4*3+2] )
1147
+ setElement( 3, 3, d * elements[4*3+3] )
1148
+
1149
+ return self
1150
+ end
1151
+
1152
+ #
1153
+ # call-seq: translation(tx,ty,tz) -> self
1154
+ #
1155
+ # Makes itself as a translation matrix.
1156
+ #
1157
+ def translation( tx, ty, tz )
1158
+ setIdentity()
1159
+ self.e03 = tx
1160
+ self.e13 = ty
1161
+ self.e23 = tz
1162
+
1163
+ return self
1164
+ end
1165
+
1166
+ #
1167
+ # call-seq: rotationX(radian) -> self
1168
+ #
1169
+ # Makes a matrix that rotates around the x-axis.
1170
+ #
1171
+ def rotationX( radian )
1172
+ s = Math.sin( radian )
1173
+ c = Math.cos( radian )
1174
+
1175
+ setIdentity()
1176
+ self.e11 = c
1177
+ self.e12 = -s
1178
+ self.e21 = s
1179
+ self.e22 = c
1180
+
1181
+ return self
1182
+ end
1183
+
1184
+ #
1185
+ # call-seq: rotationY(radian) -> self
1186
+ #
1187
+ # Makes a matrix that rotates around the y-axis.
1188
+ #
1189
+ def rotationY( radian )
1190
+ s = Math.sin( radian )
1191
+ c = Math.cos( radian )
1192
+
1193
+ setIdentity()
1194
+ self.e00 = c
1195
+ self.e02 = s
1196
+ self.e20 = -s
1197
+ self.e22 = c
1198
+
1199
+ return self
1200
+ end
1201
+
1202
+ #
1203
+ # call-seq: rotationZ(radian) -> self
1204
+ #
1205
+ # Makes a matrix that rotates around the z-axis.
1206
+ #
1207
+ def rotationZ( radian )
1208
+ s = Math.sin( radian )
1209
+ c = Math.cos( radian )
1210
+
1211
+ setIdentity()
1212
+ self.e00 = c
1213
+ self.e01 = -s
1214
+ self.e10 = s
1215
+ self.e11 = c
1216
+
1217
+ return self
1218
+ end
1219
+
1220
+ #
1221
+ # call-seq: rotationAxis(axis,radian) -> self
1222
+ #
1223
+ # Makes a matrix that rotates around the +axis+.
1224
+ #
1225
+ def rotationAxis( axis, radian )
1226
+ if ( axis.class != RVec3 )
1227
+ raise TypeError, "RMtx4#rotationAxis : Unknown type #{axis.class} given as axis."
1228
+ return nil
1229
+ end
1230
+ s = Math.sin( radian )
1231
+ c = Math.cos( radian )
1232
+ omc = 1.0 - c
1233
+ x = axis.x.to_f
1234
+ y = axis.y.to_f
1235
+ z = axis.z.to_f
1236
+
1237
+ setIdentity()
1238
+
1239
+ self.e00 = x*x*omc + c
1240
+ self.e01 = x*y*omc - z*s
1241
+ self.e02 = z*x*omc + y*s
1242
+ self.e10 = x*y*omc + z*s
1243
+ self.e11 = y*y*omc + c
1244
+ self.e12 = y*z*omc - x*s
1245
+ self.e20 = z*x*omc - y*s
1246
+ self.e21 = y*z*omc + x*s
1247
+ self.e22 = z*z*omc + c
1248
+
1249
+ return self
1250
+ end
1251
+
1252
+ #
1253
+ # call-seq: rotationQuaternion(q) -> self
1254
+ #
1255
+ # Makes a rotation matrix from a normalized quaternion +q+.
1256
+ #
1257
+ def rotationQuaternion( q )
1258
+ if ( q.class != RQuat )
1259
+ raise TypeError, "RMtx4#rotationQuaternion : Unknown type #{q.class} given as RQuat."
1260
+ return nil
1261
+ end
1262
+ x = q.x
1263
+ y = q.y
1264
+ z = q.z
1265
+ w = q.w
1266
+
1267
+ x2 = 2.0 * x
1268
+ y2 = 2.0 * y
1269
+ z2 = 2.0 * z
1270
+
1271
+ xx2 = x * x2
1272
+ yy2 = y * y2
1273
+ zz2 = z * z2
1274
+
1275
+ yz2 = y * z2
1276
+ wx2 = w * x2
1277
+ xy2 = x * y2
1278
+ wz2 = w * z2
1279
+ xz2 = x * z2
1280
+ wy2 = w * y2
1281
+
1282
+ setIdentity()
1283
+
1284
+ self.e00 = 1.0 - yy2 - zz2
1285
+ self.e10 = xy2 + wz2
1286
+ self.e20 = xz2 - wy2
1287
+ self.e01 = xy2 - wz2
1288
+ self.e11 = 1.0 - xx2 - zz2
1289
+ self.e21 = yz2 + wx2
1290
+ self.e02 = xz2 + wy2
1291
+ self.e12 = yz2 - wx2
1292
+ self.e22 = 1.0 - xx2 - yy2
1293
+
1294
+ return self
1295
+ end
1296
+
1297
+ #
1298
+ # call-seq: scaling(sx,sy,sz) -> self
1299
+ #
1300
+ # Makes itself as a scaling matrix.
1301
+ #
1302
+ def scaling( sx, sy, sz )
1303
+ setIdentity()
1304
+ setElement( 0, 0, sx )
1305
+ setElement( 1, 1, sy )
1306
+ setElement( 2, 2, sz )
1307
+
1308
+ return self
1309
+ end
1310
+
1311
+ #
1312
+ # call-seq: lookAtRH(eye,at,up) -> self
1313
+ #
1314
+ # Builds a viewing matrix for a right-handed coordinate system from:
1315
+ # * eye position (+eye+: RVec3)
1316
+ # * a point looking at (+at+: RVec3)
1317
+ # * up vector (+up+: RVec3)
1318
+ #
1319
+ def lookAtRH( eye, at, up )
1320
+ setIdentity()
1321
+
1322
+ axis_z = (eye - at).normalize!
1323
+ axis_x = RVec3.cross( up, axis_z ).normalize!
1324
+ axis_y = RVec3.cross( axis_z, axis_x )
1325
+
1326
+ self.e00 = axis_x[0]
1327
+ self.e01 = axis_x[1]
1328
+ self.e02 = axis_x[2]
1329
+ self.e03 = -RVec3.dot( axis_x, eye )
1330
+
1331
+ self.e10 = axis_y[0]
1332
+ self.e11 = axis_y[1]
1333
+ self.e12 = axis_y[2]
1334
+ self.e13 = -RVec3.dot( axis_y, eye )
1335
+
1336
+ self.e20 = axis_z[0]
1337
+ self.e21 = axis_z[1]
1338
+ self.e22 = axis_z[2]
1339
+ self.e23 = -RVec3.dot( axis_z, eye )
1340
+
1341
+ return self
1342
+ end
1343
+
1344
+ #
1345
+ # call-seq: perspectiveRH(width,height,znear,zfar) -> self
1346
+ #
1347
+ # Builds a perspective projection matrix for a right-handed coordinate system from:
1348
+ # * View volume width (+width+)
1349
+ # * View volume height (+height+)
1350
+ # * Near clip plane distance (+znear+)
1351
+ # * Far clip plane distance (+zfar+)
1352
+ #
1353
+ def perspectiveRH( width, height, znear, zfar )
1354
+ perspectiveOffCenterRH(-width/2.0, width/2.0, -height/2.0, height/2.0, znear, zfar )
1355
+ return self
1356
+ end
1357
+
1358
+ #
1359
+ # call-seq: perspectiveFovRH(fovy,aspect,znear,zfar) -> self
1360
+ #
1361
+ # Builds a perspective projection matrix for a right-handed coordinate system from:
1362
+ # * Field of view in y direction (+fovy+ radian)
1363
+ # * Aspect ratio (+aspect+)
1364
+ # * Near clip plane distance (+znear+)
1365
+ # * Far clip plane distance (+zfar+)
1366
+ #
1367
+ def perspectiveFovRH( fovy_radian, aspect, znear, zfar )
1368
+ f = Math::tan( fovy_radian / 2.0 )
1369
+ f = 1.0 / f
1370
+
1371
+ setIdentity()
1372
+ setElement( 0, 0, f / aspect )
1373
+ setElement( 1, 1, f )
1374
+ setElement( 2, 2, (zfar+znear)/(znear-zfar) )
1375
+ setElement( 2, 3, 2*zfar*znear/(znear-zfar) )
1376
+ setElement( 3, 2, -1.0 )
1377
+ setElement( 3, 3, 0.0 )
1378
+
1379
+ return self
1380
+ end
1381
+
1382
+ #
1383
+ # call-seq: perspectiveOffCenterRH(left,right,bottom,top,znear,zfar) -> self
1384
+ #
1385
+ # Builds a perspective projection matrix for a right-handed coordinate system from:
1386
+ # * Minimum value of the view volume width (+left+)
1387
+ # * Maximum value of the view volume width (+right+)
1388
+ # * Minimum value of the view volume height (+bottom+)
1389
+ # * Maximum value of the view volume height (+top+)
1390
+ # * Near clip plane distance (+znear+)
1391
+ # * Far clip plane distance (+zfar+)
1392
+ #
1393
+ def perspectiveOffCenterRH( left, right, bottom, top, znear, zfar )
1394
+ a = (right+left) / (right-left)
1395
+ b = (top+bottom) / (top-bottom)
1396
+ c = -(zfar+znear) / (zfar-znear)
1397
+ d = -(2*znear*zfar) / (zfar-znear)
1398
+
1399
+ setIdentity()
1400
+
1401
+ setElement( 0, 0, 2*znear/(right-left) )
1402
+ setElement( 0, 2, a )
1403
+ setElement( 1, 1, 2*znear/(top-bottom) )
1404
+ setElement( 1, 2, b )
1405
+ setElement( 2, 2, c )
1406
+ setElement( 2, 3, d )
1407
+ setElement( 3, 2, -1.0 )
1408
+ setElement( 3, 3, 0.0 )
1409
+
1410
+ return self
1411
+ end
1412
+
1413
+ #
1414
+ # call-seq: orthoRH(width,height,znear,zfar) -> self
1415
+ #
1416
+ # Builds a orthogonal projection matrix for a right-handed coordinate system from:
1417
+ # * View volume width (+width+)
1418
+ # * View volume height (+height+)
1419
+ # * Near clip plane distance (+znear+)
1420
+ # * Far clip plane distance (+zfar+)
1421
+ #
1422
+ def orthoRH( width, height, znear, zfar )
1423
+ orthoOffCenterRH( -width/2.0, width/2.0, -height/2.0, height/2.0, znear, zfar )
1424
+ return self
1425
+ end
1426
+
1427
+ #
1428
+ # call-seq: orthoOffCenterRH(left,right,bottom,top,znear,zfar) -> self
1429
+ #
1430
+ # Builds a orthogonal projection matrix for a right-handed coordinate system from:
1431
+ # * Minimum value of the view volume width (+left+)
1432
+ # * Maximum value of the view volume width (+right+)
1433
+ # * Minimum value of the view volume height (+bottom+)
1434
+ # * Maximum value of the view volume height (+top+)
1435
+ # * Near clip plane distance (+znear+)
1436
+ # * Far clip plane distance (+zfar+)
1437
+ #
1438
+ def orthoOffCenterRH( left, right, bottom, top, znear, zfar )
1439
+ tx = (right+left) / (right-left)
1440
+ ty = (top+bottom) / (top-bottom)
1441
+ tz = (zfar+znear) / (zfar-znear)
1442
+
1443
+ setIdentity()
1444
+
1445
+ setElement( 0, 0, 2.0/(right-left) )
1446
+ setElement( 0, 3, tx )
1447
+ setElement( 1, 1, 2.0/(top-bottom) )
1448
+ setElement( 1, 3, ty )
1449
+ setElement( 2, 2, -2.0/(zfar-znear) )
1450
+ setElement( 2, 3, tz )
1451
+
1452
+ return self
1453
+ end
1454
+
1455
+ #
1456
+ # call-seq: +
1457
+ #
1458
+ # +mtx : Unary plus operator.
1459
+ #
1460
+ def +@
1461
+ return self
1462
+ end
1463
+
1464
+ #
1465
+ # call-seq: -
1466
+ #
1467
+ # -mtx : Unary minus operator.
1468
+ #
1469
+ def -@
1470
+ return RMtx4.new( self * -1.0 )
1471
+ end
1472
+
1473
+ #
1474
+ # call-seq: +
1475
+ #
1476
+ # mtx1 + mtx2 : Binary plus operator.
1477
+ #
1478
+ def +( arg )
1479
+ if ( arg.class != RMtx4 )
1480
+ raise TypeError, "RMtx4#+(arg) : Unknown type #{arg.class} given as RMtx4."
1481
+ return nil
1482
+ end
1483
+
1484
+ result = RMtx4.new
1485
+ for row in 0...4 do
1486
+ for col in 0...4 do
1487
+ result.setElement( row, col, getElement(row,col) + arg.getElement(row,col) )
1488
+ end
1489
+ end
1490
+
1491
+ return result
1492
+ end
1493
+
1494
+ #
1495
+ # call-seq: -
1496
+ #
1497
+ # mtx1 - mtx2 : Binary minus operator.
1498
+ #
1499
+ def -( arg )
1500
+ if ( arg.class != RMtx4 )
1501
+ raise TypeError, "RMtx4#-(arg) : Unknown type #{arg.class} given as RMtx4."
1502
+ return nil
1503
+ end
1504
+
1505
+ result = RMtx4.new
1506
+ for row in 0...4 do
1507
+ for col in 0...4 do
1508
+ result.setElement( row, col, getElement(row,col) - arg.getElement(row,col) )
1509
+ end
1510
+ end
1511
+
1512
+ return result
1513
+ end
1514
+
1515
+ #
1516
+ # call-seq: *
1517
+ #
1518
+ # mtx1 * mtx2 : Binary multiply operator.
1519
+ #
1520
+ def *( arg )
1521
+ case arg
1522
+ when Fixnum, Float, Bignum
1523
+ return RMtx4.new( arg*self.e00, arg*self.e01, arg*self.e02, arg*self.e03,
1524
+ arg*self.e10, arg*self.e11, arg*self.e12, arg*self.e13,
1525
+ arg*self.e20, arg*self.e21, arg*self.e22, arg*self.e23,
1526
+ arg*self.e30, arg*self.e31, arg*self.e32, arg*self.e33 )
1527
+
1528
+ when RMtx4
1529
+ result = RMtx4.new
1530
+ for row in 0...4 do
1531
+ for col in 0...4 do
1532
+ sum = 0.0
1533
+ for i in 0...4 do
1534
+ sum += getElement( row, i ) * arg.getElement( i, col )
1535
+ end
1536
+ result.setElement( row, col, sum )
1537
+ end
1538
+ end
1539
+ return result
1540
+
1541
+ else
1542
+ raise TypeError, "RMtx4#*(arg) : Unknown type #{arg.class} given."
1543
+ return nil
1544
+ end
1545
+ end
1546
+
1547
+ #
1548
+ # call-seq: ==
1549
+ #
1550
+ # mtx1 == mtx2 : evaluates equality.
1551
+ #
1552
+ def ==( other )
1553
+ if ( other.class != RMtx4 )
1554
+ raise TypeError, "RMtx4#==(other) : Unknown type #{other.class} given as RMtx4."
1555
+ return nil
1556
+ end
1557
+
1558
+ for row in 0...4 do
1559
+ for col in 0...4 do
1560
+ if ( (getElement(row,col) - other.getElement(row,col)).abs > TOLERANCE )
1561
+ return false
1562
+ end
1563
+ end
1564
+ end
1565
+ return true
1566
+ end
1567
+
1568
+ #
1569
+ # call-seq: mtx1.add!( mtx2 )
1570
+ #
1571
+ # mtx1 += mtx2 : appends the elements of +mtx2+ into corresponding +mtx1+ elements.
1572
+ #
1573
+ def add!( other )
1574
+ if ( other.class != RMtx4 )
1575
+ raise TypeError, "RMtx4#add! : Unknown type #{other.class} given as RMtx4."
1576
+ return nil
1577
+ end
1578
+
1579
+ result = RMtx4.new
1580
+ for row in 0...4 do
1581
+ for col in 0...4 do
1582
+ self.setElement( row, col, getElement(row,col) + other.getElement(row,col) )
1583
+ end
1584
+ end
1585
+
1586
+ return self
1587
+ end
1588
+
1589
+ #
1590
+ # call-seq: mtx1.sub!( mtx2 )
1591
+ #
1592
+ # mtx1 -= mtx2 : subtracts the elements of +mtx2+ from corresponding +mtx1+ elements.
1593
+ #
1594
+ def sub!( other )
1595
+ if ( other.class != RMtx4 )
1596
+ raise TypeError, "RMtx4#sub! : Unknown type #{other.class} given as RMtx4."
1597
+ return nil
1598
+ end
1599
+
1600
+ result = RMtx4.new
1601
+ for row in 0...4 do
1602
+ for col in 0...4 do
1603
+ self.setElement( row, col, getElement(row,col) - other.getElement(row,col) )
1604
+ end
1605
+ end
1606
+
1607
+ return self
1608
+ end
1609
+
1610
+ #
1611
+ # call-seq: mtx1.mul!( mtx2 )
1612
+ #
1613
+ # mtx1 *= mtx2
1614
+ #
1615
+ def mul!( other )
1616
+ case other
1617
+ when Fixnum, Float, Bignum
1618
+ self.e00 = other*self.e00
1619
+ self.e01 = other*self.e01
1620
+ self.e02 = other*self.e02
1621
+ self.e03 = other*self.e03
1622
+
1623
+ self.e10 = other*self.e10
1624
+ self.e11 = other*self.e11
1625
+ self.e12 = other*self.e12
1626
+ self.e13 = other*self.e13
1627
+
1628
+ self.e20 = other*self.e20
1629
+ self.e21 = other*self.e21
1630
+ self.e22 = other*self.e22
1631
+ self.e23 = other*self.e23
1632
+
1633
+ self.e30 = other*self.e30
1634
+ self.e31 = other*self.e31
1635
+ self.e32 = other*self.e32
1636
+ self.e33 = other*self.e33
1637
+
1638
+ return self
1639
+
1640
+ when RMtx4
1641
+ result = RMtx4.new
1642
+ for row in 0...4 do
1643
+ for col in 0...4 do
1644
+ sum = 0.0
1645
+ for i in 0...4 do
1646
+ sum += getElement( row, i ) * other.getElement( i, col )
1647
+ end
1648
+ result.setElement( row, col, sum )
1649
+ end
1650
+ end
1651
+
1652
+ self.e00 = result.e00
1653
+ self.e01 = result.e01
1654
+ self.e02 = result.e02
1655
+ self.e03 = result.e03
1656
+
1657
+ self.e10 = result.e10
1658
+ self.e11 = result.e11
1659
+ self.e12 = result.e12
1660
+ self.e13 = result.e13
1661
+
1662
+ self.e20 = result.e20
1663
+ self.e21 = result.e21
1664
+ self.e22 = result.e22
1665
+ self.e23 = result.e23
1666
+
1667
+ self.e30 = result.e30
1668
+ self.e31 = result.e31
1669
+ self.e32 = result.e32
1670
+ self.e33 = result.e33
1671
+
1672
+ return self
1673
+ end
1674
+ end
1675
+ end
1676
+
1677
+ #
1678
+ # Document-class: RMath3D::RQuat
1679
+ # provies quaternion arithmetic.
1680
+ #
1681
+ class RQuat
1682
+
1683
+ #
1684
+ # call-seq:
1685
+ # RQuat.new -> (0,0,0,0)
1686
+ # RQuat.new(e) -> (e,e,e,e)
1687
+ # RQuat.new( other ) : Copy Constructor
1688
+ # RQuat.new( e0, e1, e2, e3 ) -> (e0,e1,e2,e3)
1689
+ #
1690
+ # Creates a new quaternion.
1691
+ #
1692
+ def initialize( *a )
1693
+ @e = []
1694
+ case a.length
1695
+ when 0
1696
+ @e = [0.0, 0.0, 0.0, 0.0]
1697
+ when 1
1698
+ case a[0]
1699
+ when Fixnum, Float
1700
+ @e = [ a[0], a[0], a[0], a[0] ]
1701
+ when RQuat
1702
+ @e = [ a[0].x, a[0].y, a[0].z, a[0].w ]
1703
+ else
1704
+ raise TypeError, "RQuat#initialize : Unknown type #{a[0].class}."
1705
+ return nil
1706
+ end
1707
+ when 4
1708
+ a.each_with_index do |elem, index|
1709
+ case elem
1710
+ when Fixnum, Float
1711
+ @e[index] = elem
1712
+ else
1713
+ raise TypeError, "RQuat#initialize : Unknown type #{elem.class}."
1714
+ return nil
1715
+ end
1716
+ end
1717
+ else
1718
+ raise RuntimeError, "RQuat#initialize : wrong # of arguments (#{a.length})"
1719
+ return nil
1720
+ end
1721
+ return self
1722
+ end
1723
+
1724
+ #
1725
+ # call-seq: to_s
1726
+ #
1727
+ # Returns human-readable string.
1728
+ #
1729
+ def to_s
1730
+ return "( #{@e[0]}, #{@e[1]}, #{@e[2]}, #{@e[3]} )\n"
1731
+ end
1732
+
1733
+ #
1734
+ # call-seq: to_a
1735
+ #
1736
+ # Returns its elements as a new Array.
1737
+ #
1738
+ def to_a
1739
+ return @e
1740
+ end
1741
+
1742
+ #
1743
+ # call-seq: coerse(other)
1744
+ #
1745
+ # Resolves type mismatch.
1746
+ #
1747
+ def coerce( arg )
1748
+ case arg
1749
+ when Fixnum, Float, Bignum
1750
+ return [ self, arg ]
1751
+ else
1752
+ raise TypeError, "RQuat#coerce : #{arg.self} can't be coerced into #{self.class}."
1753
+ return nil
1754
+ end
1755
+ end
1756
+
1757
+ #
1758
+ # call-seq: setElements( e0, e1, e2, e3 )
1759
+ #
1760
+ # Stores given 4 new values.
1761
+ #
1762
+ def setElements( x, y, z, w )
1763
+ self.x = x
1764
+ self.y = y
1765
+ self.z = z
1766
+ self.w = w
1767
+ end
1768
+
1769
+ #
1770
+ # call-seq: quat[i]= value
1771
+ #
1772
+ # Stores +value+ at +i+.
1773
+ #
1774
+ def []=(i,value)
1775
+ @e[i] = value
1776
+ end
1777
+
1778
+ #
1779
+ # call-seq: x= value
1780
+ #
1781
+ # Stores +value+ as +x+.
1782
+ #
1783
+ def x=(value) @e[0] = value end
1784
+
1785
+ #
1786
+ # call-seq: y= value
1787
+ #
1788
+ # Stores +value+ as +y+.
1789
+ #
1790
+ def y=(value) @e[1] = value end
1791
+
1792
+ #
1793
+ # call-seq: z= value
1794
+ #
1795
+ # Stores +value+ as +z+.
1796
+ #
1797
+ def z=(value) @e[2] = value end
1798
+
1799
+ #
1800
+ # call-seq: w= value
1801
+ #
1802
+ # Stores +value+ as +w+.
1803
+ #
1804
+ def w=(value) @e[3] = value end
1805
+
1806
+ #
1807
+ # call-seq: xyz= vXYZ
1808
+ #
1809
+ # Copies the values of +vXYZ+(RVec3) into +x+, +y+ and +z+.
1810
+ #
1811
+ def xyz=( arg )
1812
+ if arg.class != RVec3
1813
+ raise TypeError, "RQuat#xyz= : Unknown type #{arg.class}."
1814
+ return nil
1815
+ end
1816
+ @e[0] = arg.x
1817
+ @e[1] = arg.y
1818
+ @e[2] = arg.z
1819
+ end
1820
+
1821
+ #
1822
+ # call-seq: quat[i] -> value
1823
+ #
1824
+ # Returns the element at +i+.
1825
+ #
1826
+ def [](i)
1827
+ @e[i]
1828
+ end
1829
+
1830
+
1831
+ #
1832
+ # call-seq: x -> value
1833
+ #
1834
+ # Returns the value of +x+.
1835
+ #
1836
+ def x() return @e[0] end
1837
+
1838
+ #
1839
+ # call-seq: y -> value
1840
+ #
1841
+ # Returns the value of +y+.
1842
+ #
1843
+ def y() return @e[1] end
1844
+
1845
+ #
1846
+ # call-seq: z -> value
1847
+ #
1848
+ # Returns the value of +z+.
1849
+ #
1850
+ def z() return @e[2] end
1851
+
1852
+ #
1853
+ # call-seq: w -> value
1854
+ #
1855
+ # Returns the value of +w+.
1856
+ #
1857
+ def w() return @e[3] end
1858
+
1859
+ #
1860
+ # call-seq: xyz -> RVec3
1861
+ #
1862
+ # Returns the values of +x+, +y+ and +z+ with new RVec3(+x+,+y+,+z+).
1863
+ #
1864
+ def xyz()
1865
+ return RVec3.new( @e[0], @e[1], @e[2] )
1866
+ end
1867
+
1868
+ #
1869
+ # call-seq: getLength
1870
+ #
1871
+ # Returns the Euclidean length.
1872
+ #
1873
+ def getLength
1874
+ return Math.sqrt( @e[0]*@e[0] + @e[1]*@e[1] + @e[2]*@e[2] + @e[3]*@e[3] )
1875
+ end
1876
+
1877
+ #
1878
+ # call-seq: getLengthSq
1879
+ #
1880
+ # Returns the squared Euclidean length.
1881
+ #
1882
+ def getLengthSq
1883
+ return (@e[0]*@e[0] + @e[1]*@e[1] + @e[2]*@e[2] + @e[3]*@e[3]).to_f
1884
+ end
1885
+
1886
+ #
1887
+ # call-seq: RQuat.dot(q_a,q_b) -> value
1888
+ #
1889
+ # Calculates the dot product of +q_a+ and +q_b+.
1890
+ #
1891
+ def RQuat.dot( q1, q2 )
1892
+ if q1.class != RQuat || q2.class != RQuat
1893
+ raise TypeError, "RQuat#dot : Unknown type q1:#{q2.class}, q2:#{q2.class}."
1894
+ return nil
1895
+ end
1896
+ return q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w
1897
+ end
1898
+
1899
+ #
1900
+ # call-seq: RQuat.slerp( q_a, q_b, t ) -> interpolated quaternion
1901
+ #
1902
+ # Calculates the spherical linear interpolation between +q_a+ and
1903
+ # +q_b+ at time +t+ (0.0~1.0).
1904
+ #
1905
+ def RQuat.slerp( q1, q2, t )
1906
+ if q1.class != RQuat || q2.class != RQuat
1907
+ raise TypeError, "RQuat#slerp : Unknown type q1:#{q2.class}, q2:#{q2.class}."
1908
+ return nil
1909
+ end
1910
+ s1 = 0.0
1911
+ s2 = 0.0
1912
+ it = 1.0 - t
1913
+ cosine = RQuat.dot( q1, q2 )
1914
+
1915
+ qn1 = q1
1916
+ qn2 = q2
1917
+
1918
+ if ( cosine < 0.0 )
1919
+ cosine *= -1.0
1920
+ qn1 *= -1.0
1921
+ end
1922
+
1923
+ if ( (1.0 - cosine) > TOLERANCE )
1924
+ theta = Math.acos( cosine )
1925
+ sin_theta = Math.sin( theta )
1926
+
1927
+ s1 = Math.sin( it * theta ) / sin_theta
1928
+ s2 = Math.sin( t * theta ) / sin_theta
1929
+ else
1930
+ s1 = it
1931
+ s2 = t
1932
+ end
1933
+
1934
+ qn1 *= s1
1935
+ qn2 *= s2
1936
+ qResult = qn1 + qn2
1937
+
1938
+ return qResult
1939
+ end
1940
+
1941
+ #
1942
+ # call-seq: setIdentity
1943
+ #
1944
+ # Sets as identity quaternion.
1945
+ #
1946
+ def setIdentity
1947
+ self.x = 0.0
1948
+ self.y = 0.0
1949
+ self.z = 0.0
1950
+ self.w = 1.0
1951
+ return self
1952
+ end
1953
+
1954
+ #
1955
+ # call-seq: getConjugated
1956
+ #
1957
+ # Returns its conjugate quaternion.
1958
+ #
1959
+ def getConjugated
1960
+ return RQuat.new( -@e[0], -@e[1], -@e[2], @e[3] )
1961
+ end
1962
+
1963
+ #
1964
+ # call-seq: conjugate!
1965
+ #
1966
+ # Conjugates itself.
1967
+ #
1968
+ def conjugate!
1969
+ @e[0] *= -1.0
1970
+ @e[1] *= -1.0
1971
+ @e[2] *= -1.0
1972
+ return self
1973
+ end
1974
+
1975
+ #
1976
+ # call-seq: getInverse -> inverse quaternion
1977
+ #
1978
+ # Returns the inverse.
1979
+ #
1980
+ def getInverse
1981
+ length_sq = getLengthSq()
1982
+ return RQuat.new( -@e[0]/length_sq, -@e[1]/length_sq, -@e[2]/length_sq, @e[3]/length_sq )
1983
+ end
1984
+
1985
+ #
1986
+ # call-seq: invert! -> self
1987
+ #
1988
+ # Inverts itself.
1989
+ #
1990
+ def invert!
1991
+ length_sq = getLengthSq()
1992
+ @e[0] /= -length_sq
1993
+ @e[1] /= -length_sq
1994
+ @e[2] /= -length_sq
1995
+ @e[3] /= length_sq
1996
+ return self
1997
+ end
1998
+
1999
+ #
2000
+ # call-seq: getNormalized -> RQuat
2001
+ #
2002
+ # Returns normalized quaternion.
2003
+ #
2004
+ def getNormalized
2005
+ length = getLength()
2006
+ return RQuat.new( @e[0]/length, @e[1]/length, @e[2]/length, @e[3]/length )
2007
+ end
2008
+
2009
+ #
2010
+ # call-seq: normalize! -> self
2011
+ #
2012
+ # Normalizes itself.
2013
+ #
2014
+ def normalize!
2015
+ length = getLength()
2016
+ @e[0] /= length
2017
+ @e[1] /= length
2018
+ @e[2] /= length
2019
+ @e[3] /= length
2020
+ return self
2021
+ end
2022
+
2023
+ #
2024
+ # call-seq: +
2025
+ #
2026
+ # +quat : Unary plus operator.
2027
+ #
2028
+ def +@
2029
+ return self
2030
+ end
2031
+
2032
+ #
2033
+ # call-seq: -
2034
+ #
2035
+ # -quat : Unary minus operator.
2036
+ #
2037
+ def -@
2038
+ return RQuat.new( -@e[0], -@e[1], -@e[2], -@e[3] )
2039
+ end
2040
+
2041
+ #
2042
+ # call-seq: +
2043
+ #
2044
+ # quat1 + quat2 : Binary plus operator.
2045
+ #
2046
+ def +( arg )
2047
+ if arg.class != RQuat
2048
+ raise TypeError, "RQuat#+ : Unknown type #{arg.class}."
2049
+ return nil
2050
+ end
2051
+ RQuat.new( x+arg.x, y+arg.y, z+arg.z, w+arg.w )
2052
+ end
2053
+
2054
+ #
2055
+ # call-seq: -
2056
+ #
2057
+ # quat1 - quat2 : Binary minus operator.
2058
+ #
2059
+ def -( arg )
2060
+ if arg.class != RQuat
2061
+ raise TypeError, "RQuat#- : Unknown type #{arg.class}."
2062
+ return nil
2063
+ end
2064
+ RQuat.new( x-arg.x, y-arg.y, z-arg.z, w-arg.w )
2065
+ end
2066
+
2067
+ #
2068
+ # call-seq: *
2069
+ #
2070
+ # quat1 * quat2 : Binary multiply operator.
2071
+ #
2072
+ def *( arg )
2073
+ case arg
2074
+ when RQuat
2075
+ q1x = self.x
2076
+ q1y = self.y
2077
+ q1z = self.z
2078
+ q1w = self.w
2079
+ q2x = arg.x
2080
+ q2y = arg.y
2081
+ q2z = arg.z
2082
+ q2w = arg.w
2083
+ x = q1w*q2x + q1x*q2w + q1y*q2z - q1z*q2y
2084
+ y = q1w*q2y - q1x*q2z + q1y*q2w + q1z*q2x
2085
+ z = q1w*q2z + q1x*q2y - q1y*q2x + q1z*q2w
2086
+ w = q1w*q2w - q1x*q2x - q1y*q2y - q1z*q2z
2087
+ return RQuat.new( x, y, z, w )
2088
+ when Fixnum, Float
2089
+ return RQuat.new( @e[0]*arg, @e[1]*arg, @e[2]*arg, @e[3]*arg )
2090
+ else
2091
+ raise TypeError, "RQuat#* : Unknown type #{arg}."
2092
+ return nil
2093
+ end
2094
+ end
2095
+
2096
+ #
2097
+ # call-seq: ==
2098
+ #
2099
+ # quat1 == quat2 : evaluates equality.
2100
+ #
2101
+ def ==( other )
2102
+ if other.class != RQuat
2103
+ raise TypeError, "RQuat#== : Unknown type #{other.class}."
2104
+ return nil
2105
+ end
2106
+
2107
+ if (x-other.x).abs<=Float::EPSILON &&
2108
+ (y-other.y).abs<=Float::EPSILON &&
2109
+ (z-other.z).abs<=Float::EPSILON &&
2110
+ (w-other.w).abs<=Float::EPSILON
2111
+ return true
2112
+ else
2113
+ return false
2114
+ end
2115
+ end
2116
+
2117
+ #
2118
+ # call-seq: quat1.add!( quat2 )
2119
+ #
2120
+ # quat1 += quat2 : appends the elements of +quat2+ into corresponding +quat1+ elements.
2121
+ #
2122
+ def add!( other )
2123
+ if other.class != RQuat
2124
+ raise TypeError, "RQ#add! : Unknown type #{other.class}."
2125
+ return nil
2126
+ end
2127
+
2128
+ self.x += other.x
2129
+ self.y += other.y
2130
+ self.z += other.z
2131
+ self.w += other.w
2132
+
2133
+ return self
2134
+ end
2135
+
2136
+ #
2137
+ # call-seq: quat1.sub!( quat2 )
2138
+ #
2139
+ # quat1 -= quat2 : subtracts the elements of +quat2+ from corresponding +quat1+ elements.
2140
+ #
2141
+ def sub!( other )
2142
+ if other.class != RQuat
2143
+ raise TypeError, "RQuat#sub! : Unknown type #{other.class}."
2144
+ return nil
2145
+ end
2146
+
2147
+ self.x -= other.x
2148
+ self.y -= other.y
2149
+ self.z -= other.z
2150
+ self.w -= other.w
2151
+
2152
+ return self
2153
+ end
2154
+
2155
+ #
2156
+ # call-seq: quat1.mul!( quat2 )
2157
+ #
2158
+ # quat1 *= quat2
2159
+ #
2160
+ def mul!( other )
2161
+ case other
2162
+ when RQuat
2163
+ q1x = self.x
2164
+ q1y = self.y
2165
+ q1z = self.z
2166
+ q1w = self.w
2167
+ q2x = other.x
2168
+ q2y = other.y
2169
+ q2z = other.z
2170
+ q2w = other.w
2171
+
2172
+ x = q1w*q2x + q1x*q2w + q1y*q2z - q1z*q2y
2173
+ y = q1w*q2y - q1x*q2z + q1y*q2w + q1z*q2x
2174
+ z = q1w*q2z + q1x*q2y - q1y*q2x + q1z*q2w
2175
+ w = q1w*q2w - q1x*q2x - q1y*q2y - q1z*q2z
2176
+
2177
+ self.x = x
2178
+ self.y = y
2179
+ self.z = z
2180
+ self.w = w
2181
+
2182
+ return self
2183
+
2184
+ when Fixnum, Float
2185
+ self.x *= other
2186
+ self.y *= other
2187
+ self.z *= other
2188
+ self.w *= other
2189
+ return self
2190
+
2191
+ else
2192
+ raise TypeError, "RQuat#mul! : Unknown type #{other.class}."
2193
+ return nil
2194
+ end
2195
+ end
2196
+
2197
+ #
2198
+ # call-seq: rotationMarix(mtx4) -> self
2199
+ #
2200
+ # Makes a rotation quaternion from a rotation matrix +mtx4+ (RMtx4).
2201
+ #
2202
+ def rotationMatrix( mtx )
2203
+ if mtx.class != RMtx3 && mtx.class != RMtx4
2204
+ raise TypeError, "RQuat#rotationMatrix : Unknown type #{mtx.class}."
2205
+ return nil
2206
+ end
2207
+
2208
+ diag00 = mtx.getElement(0,0)
2209
+ diag11 = mtx.getElement(1,1)
2210
+ diag22 = mtx.getElement(2,2)
2211
+
2212
+ if ( diag00 + diag11 + diag22 > 0.0 )
2213
+ t = diag00 + diag11 + diag22 + 1.0
2214
+ s = 1.0 / ( Math.sqrt( t ) * 2.0 )
2215
+ self.w = s * t
2216
+ self.z = (mtx.getElement(1,0) - mtx.getElement(0,1)) * s
2217
+ self.y = (mtx.getElement(0,2) - mtx.getElement(2,0)) * s
2218
+ self.x = (mtx.getElement(2,1) - mtx.getElement(1,2)) * s
2219
+ elsif ( diag00 > diag11 && diag00 > diag22 )
2220
+ t = diag00 - diag11 - diag22 + 1.0
2221
+ s = 1.0 / ( Math.sqrt( t ) * 2.0 )
2222
+ self.x = s * t
2223
+ self.y = (mtx.getElement(1,0) + mtx.getElement(0,1)) * s
2224
+ self.z = (mtx.getElement(0,2) + mtx.getElement(2,0)) * s
2225
+ self.w = (mtx.getElement(2,1) - mtx.getElement(1,2)) * s
2226
+ elsif ( diag11 > diag22 )
2227
+ t = -diag00 + diag11 - diag22 + 1.0
2228
+ s = 1.0 / ( Math.sqrt( t ) * 2.0 )
2229
+ self.y = s * t
2230
+ self.x = (mtx.getElement(1,0) + mtx.getElement(0,1)) * s
2231
+ self.w = (mtx.getElement(0,2) - mtx.getElement(2,0)) * s
2232
+ self.z = (mtx.getElement(2,1) + mtx.getElement(1,2)) * s
2233
+ else
2234
+ t = -diag00 - diag11 + diag22 + 1.0
2235
+ s = 1.0 / ( Math.sqrt( t ) * 2.0 )
2236
+ self.z = s * t
2237
+ self.w = (mtx.getElement(1,0) - mtx.getElement(0,1)) * s
2238
+ self.x = (mtx.getElement(0,2) + mtx.getElement(2,0)) * s
2239
+ self.y = (mtx.getElement(2,1) + mtx.getElement(1,2)) * s
2240
+ end
2241
+
2242
+ return self
2243
+ end
2244
+
2245
+ #
2246
+ # call-seq: rotationAxis(axis,radian) -> self
2247
+ #
2248
+ # Makes a quaternion that rotates around the +axis+.
2249
+ #
2250
+ def rotationAxis( axis, radian )
2251
+ if axis.class != RVec3
2252
+ raise TypeError, "RQuat#rotationAxis : Unknown type #{axis.class}."
2253
+ return nil
2254
+ end
2255
+
2256
+ s = Math.sin( radian / 2.0 )
2257
+ self.x = s * axis.x
2258
+ self.y = s * axis.y
2259
+ self.z = s * axis.z
2260
+ self.w = Math.cos( radian / 2.0 )
2261
+
2262
+ return self
2263
+ end
2264
+
2265
+ #
2266
+ # call-seq: toAxisAngle -> [axis,radian]
2267
+ #
2268
+ # Returns its rotation axis (RVec3) and rotation angle (in radian).
2269
+ #
2270
+ def toAxisAngle
2271
+ axis = RVec3.new( self.x, self.y, self.z ).normalize!
2272
+ radian = 2.0 * Math.acos( self.w )
2273
+
2274
+ return [ axis, radian ]
2275
+ end
2276
+ end
2277
+
2278
+ #
2279
+ # Document-class: RMath3D::RVec3
2280
+ # provies 3 element vector arithmetic.
2281
+ #
2282
+ class RVec3
2283
+
2284
+ #
2285
+ # call-seq:
2286
+ # RVec3.new -> (0,0,0)
2287
+ # RVec3.new(e) -> (e,e,e)
2288
+ # RVec3.new( other ) : Copy Constructor
2289
+ # RVec3.new( e0, e1, e2 ) -> (e0,e1,e2)
2290
+ #
2291
+ # Creates a new 3 element vector.
2292
+ #
2293
+ def initialize( *a )
2294
+ @e = []
2295
+ case a.length
2296
+ when 0
2297
+ @e = [0.0, 0.0, 0.0]
2298
+ when 1
2299
+ case a[0]
2300
+ when Fixnum, Float
2301
+ @e = [ a[0], a[0], a[0] ]
2302
+ when RVec3
2303
+ @e = [ a[0].x, a[0].y, a[0].z ]
2304
+ else
2305
+ raise TypeError, "RVec3#initialize : Unknown type #{a[0].class}."
2306
+ return nil
2307
+ end
2308
+ when 3
2309
+ a.each_with_index do |elem, index|
2310
+ case elem
2311
+ when Fixnum, Float
2312
+ @e[index] = elem
2313
+ else
2314
+ raise TypeError, "RVec3#initialize : Unknown type #{elem.class}."
2315
+ return nil
2316
+ end
2317
+ end
2318
+ else
2319
+ raise RuntimeError, "RVec3#initialize : wrong # of arguments (#{a.length})"
2320
+ return nil
2321
+ end
2322
+ return self
2323
+ end
2324
+
2325
+ #
2326
+ # call-seq: to_s
2327
+ #
2328
+ # Returns human-readable string.
2329
+ #
2330
+ def to_s
2331
+ return "( #{@e[0]}, #{@e[1]}, #{@e[2]} )\n"
2332
+ end
2333
+
2334
+ #
2335
+ # call-seq: to_a
2336
+ #
2337
+ # Returns its elements as a new Array.
2338
+ #
2339
+ def to_a
2340
+ return @e
2341
+ end
2342
+
2343
+ #
2344
+ # call-seq: coerse(other)
2345
+ #
2346
+ # Resolves type mismatch.
2347
+ #
2348
+ def coerce( arg )
2349
+ case arg
2350
+ when Fixnum, Float, Bignum
2351
+ return [ self, arg ]
2352
+ else
2353
+ raise TypeError, "RVec3#coerce : #{arg.self} can't be coerced into #{self.class}."
2354
+ return nil
2355
+ end
2356
+ end
2357
+
2358
+ #
2359
+ # call-seq: setElements( e0, e1, e2 )
2360
+ #
2361
+ # Stores given 3 new values.
2362
+ #
2363
+ def setElements( x, y, z )
2364
+ self.x = x
2365
+ self.y = y
2366
+ self.z = z
2367
+ end
2368
+
2369
+ #
2370
+ # call-seq: vec3[i]= value
2371
+ #
2372
+ # Stores +value+ at +i+.
2373
+ #
2374
+ def []=(i,value)
2375
+ @e[i] = value
2376
+ end
2377
+
2378
+ #
2379
+ # call-seq: x= value
2380
+ #
2381
+ # Stores +value+ as +x+.
2382
+ #
2383
+ def x=(value) @e[0] = value end
2384
+
2385
+ #
2386
+ # call-seq: y= value
2387
+ #
2388
+ # Stores +value+ as +y+.
2389
+ #
2390
+ def y=(value) @e[1] = value end
2391
+
2392
+ #
2393
+ # call-seq: z= value
2394
+ #
2395
+ # Stores +value+ as +z+.
2396
+ #
2397
+ def z=(value) @e[2] = value end
2398
+
2399
+ #
2400
+ # call-seq: vec3[i] -> value
2401
+ #
2402
+ # Returns the element at +i+.
2403
+ #
2404
+ def [](i)
2405
+ @e[i]
2406
+ end
2407
+
2408
+ #
2409
+ # call-seq: x -> value
2410
+ #
2411
+ # Returns the value of +x+.
2412
+ #
2413
+ def x() return @e[0] end
2414
+
2415
+ #
2416
+ # call-seq: y -> value
2417
+ #
2418
+ # Returns the value of +y+.
2419
+ #
2420
+ def y() return @e[1] end
2421
+
2422
+ #
2423
+ # call-seq: z -> value
2424
+ #
2425
+ # Returns the value of +z+.
2426
+ #
2427
+ def z() return @e[2] end
2428
+
2429
+ #
2430
+ # call-seq: getLength
2431
+ #
2432
+ # Returns the Euclidean length.
2433
+ #
2434
+ def getLength
2435
+ return Math.sqrt( @e[0]*@e[0] + @e[1]*@e[1] + @e[2]*@e[2] )
2436
+ end
2437
+
2438
+ #
2439
+ # call-seq: getLengthSq
2440
+ #
2441
+ # Returns the squared Euclidean length.
2442
+ #
2443
+ def getLengthSq
2444
+ return (@e[0]*@e[0] + @e[1]*@e[1] + @e[2]*@e[2]).to_f
2445
+ end
2446
+
2447
+ #
2448
+ # call-seq: RVec3.dot(v_a,v_b) -> value
2449
+ #
2450
+ # Calculates the dot product of +v_a+ and +v_b+.
2451
+ #
2452
+ def RVec3.dot( v1, v2 )
2453
+ return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z
2454
+ end
2455
+
2456
+ #
2457
+ # call-seq: RVec3.cross(v_a,v_b) -> RVec3(v_a x v_b)
2458
+ #
2459
+ # Calculates the cross product of +v_a+ and +v_b+.
2460
+ #
2461
+ def RVec3.cross( v1, v2 )
2462
+ return RVec3.new(v1.y*v2.z - v1.z*v2.y,
2463
+ v1.z*v2.x - v1.x*v2.z,
2464
+ v1.x*v2.y - v1.y*v2.x)
2465
+ end
2466
+
2467
+ #
2468
+ # call-seq: transform(mtx4) -> transformed RVec4
2469
+ #
2470
+ # Returns new RVec4 containing the result of the transformation of
2471
+ # RVec4(self.x,self.y,self.z,1.0) by +mtx4+ (RMtx4).
2472
+ #
2473
+ def transform( mtx4 )
2474
+ result = RVec4.new
2475
+ result.x = mtx4.e00 * self[0] + mtx4.e01 * self[1] + mtx4.e02 * self[2] + mtx4.e03
2476
+ result.y = mtx4.e10 * self[0] + mtx4.e11 * self[1] + mtx4.e12 * self[2] + mtx4.e13
2477
+ result.z = mtx4.e20 * self[0] + mtx4.e21 * self[1] + mtx4.e22 * self[2] + mtx4.e23
2478
+ result.w = mtx4.e30 * self[0] + mtx4.e31 * self[1] + mtx4.e32 * self[2] + mtx4.e33
2479
+
2480
+ return result
2481
+ end
2482
+
2483
+ #
2484
+ # call-seq: transformCoord(mtx) -> transformed RVec3
2485
+ #
2486
+ # Returns RVec3(x/w, y/w, z/w), where x,y,z and w are the elements of
2487
+ # the transformation result:
2488
+ # RVec4(self.x,self.y,self.z,1.0).transform(+mtx+) -> RVec4(x,y,z,w). (mtx : RMtx4)
2489
+ #
2490
+ def transformCoord( mtx4 )
2491
+ result = RVec3.new
2492
+ result.x = mtx4.e00 * self[0] + mtx4.e01 * self[1] + mtx4.e02 * self[2] + mtx4.e03
2493
+ result.y = mtx4.e10 * self[0] + mtx4.e11 * self[1] + mtx4.e12 * self[2] + mtx4.e13
2494
+ result.z = mtx4.e20 * self[0] + mtx4.e21 * self[1] + mtx4.e22 * self[2] + mtx4.e23
2495
+ w = mtx4.e30 * self[0] + mtx4.e31 * self[1] + mtx4.e32 * self[2] + mtx4.e33
2496
+ w = 1.0 / w
2497
+ result *= w
2498
+
2499
+ return result
2500
+ end
2501
+
2502
+ #
2503
+ # call-seq: transformCoord!(mtx) -> self
2504
+ #
2505
+ # Make itself as RVec3(x/w, y/w, z/w), where x,y,z and w are the elements of
2506
+ # the transformation result:
2507
+ # RVec4(self.x,self.y,self.z,1.0).transform(+mtx+) -> RVec4(x,y,z,w). (mtx : RMtx4)
2508
+ #
2509
+ def transformCoord!( mtx4 )
2510
+ x = self[0]
2511
+ y = self[1]
2512
+ z = self[2]
2513
+ w = mtx4.e30 * x + mtx4.e31 * y + mtx4.e32 * z + mtx4.e33
2514
+ w = 1.0 / w
2515
+ self.x = w * (mtx4.e00 * x + mtx4.e01 * y + mtx4.e02 * z + mtx4.e03)
2516
+ self.y = w * (mtx4.e10 * x + mtx4.e11 * y + mtx4.e12 * z + mtx4.e13)
2517
+ self.z = w * (mtx4.e20 * x + mtx4.e21 * y + mtx4.e22 * z + mtx4.e23)
2518
+
2519
+ return self
2520
+ end
2521
+
2522
+ #
2523
+ # call-seq: transformNormal(mtx) -> transformed RVec3
2524
+ #
2525
+ # Returns the transformation result of
2526
+ # RVec4(self.x,self.y,self.z,0.0).transform(mtx).xyz
2527
+ #
2528
+ # === Notice
2529
+ # * mtx : RMtx4
2530
+ #
2531
+ def transformNormal( mtx )
2532
+ result = RVec3.new
2533
+ result.x = mtx.e00 * self[0] + mtx.e01 * self[1] + mtx.e02 * self[2]
2534
+ result.y = mtx.e10 * self[0] + mtx.e11 * self[1] + mtx.e12 * self[2]
2535
+ result.z = mtx.e20 * self[0] + mtx.e21 * self[1] + mtx.e22 * self[2]
2536
+
2537
+ return result
2538
+ end
2539
+
2540
+ #
2541
+ # call-seq: transformNormal!(mtx) -> self
2542
+ #
2543
+ # Make itself as the transformation result of
2544
+ # RVec4(self.x,self.y,self.z,0.0).transform(mtx).xyz
2545
+ #
2546
+ # === Notice
2547
+ # * mtx : RMtx4
2548
+ #
2549
+ def transformNormal!( mtx )
2550
+ x = self[0]
2551
+ y = self[1]
2552
+ z = self[2]
2553
+ self.x = mtx.e00 * x + mtx.e01 * y + mtx.e02 * z
2554
+ self.y = mtx.e10 * x + mtx.e11 * y + mtx.e12 * z
2555
+ self.z = mtx.e20 * x + mtx.e21 * y + mtx.e22 * z
2556
+
2557
+ return self
2558
+ end
2559
+
2560
+ #
2561
+ # call-seq: transformRS(mtx) -> transformed RVec3
2562
+ #
2563
+ # Returns the transformation result of
2564
+ # RVec3(self.x,self.y,self.z).transform(mtx)
2565
+ #
2566
+ # === Notice
2567
+ # * mtx : RMtx3
2568
+ # * the suffix "RS" means "matrix representing Rotational and Scaling
2569
+ # transformation".
2570
+ #
2571
+ def transformRS( mtx )
2572
+ result = RVec3.new
2573
+ result.x = mtx.e00 * self[0] + mtx.e01 * self[1] + mtx.e02 * self[2]
2574
+ result.y = mtx.e10 * self[0] + mtx.e11 * self[1] + mtx.e12 * self[2]
2575
+ result.z = mtx.e20 * self[0] + mtx.e21 * self[1] + mtx.e22 * self[2]
2576
+
2577
+ return result
2578
+ end
2579
+
2580
+ #
2581
+ # call-seq: transformRS!(mtx) -> self
2582
+ #
2583
+ # Makes itself as the transformation result of
2584
+ # RVec3(self.x,self.y,self.z).transform(mtx)
2585
+ #
2586
+ # === Notice
2587
+ # * mtx : RMtx3
2588
+ # * the suffix "RS" means "matrix representing Rotational and Scaling
2589
+ # transformation".
2590
+ #
2591
+ def transformRS!( mtx )
2592
+ x = self[0]
2593
+ y = self[1]
2594
+ z = self[2]
2595
+ self.x = mtx.e00 * x + mtx.e01 * y + mtx.e02 * z
2596
+ self.y = mtx.e10 * x + mtx.e11 * y + mtx.e12 * z
2597
+ self.z = mtx.e20 * x + mtx.e21 * y + mtx.e22 * z
2598
+
2599
+ return self
2600
+ end
2601
+
2602
+ #
2603
+ # call-seq: transformRSTransposed(mtx) -> RVec3 transformed by mtx^T
2604
+ #
2605
+ # Returns the transformation result of
2606
+ # RVec3(self.x,self.y,self.z).transform(mtx^T)
2607
+ #
2608
+ # === Notice
2609
+ # * mtx : RMtx3
2610
+ # * the suffix "RS" means "matrix representing Rotational and Scaling
2611
+ # transformation".
2612
+ #
2613
+ def transformRSTransposed( mtx )
2614
+ result = RVec3.new
2615
+ result.x = mtx.e00 * self[0] + mtx.e10 * self[1] + mtx.e20 * self[2]
2616
+ result.y = mtx.e01 * self[0] + mtx.e11 * self[1] + mtx.e21 * self[2]
2617
+ result.z = mtx.e02 * self[0] + mtx.e12 * self[1] + mtx.e22 * self[2]
2618
+
2619
+ return result
2620
+ end
2621
+
2622
+ #
2623
+ # call-seq: transformRSTransposed!(mtx) -> self
2624
+ #
2625
+ # Makes itself as the transformation result of
2626
+ # RVec3(self.x,self.y,self.z).transform(mtx^T)
2627
+ #
2628
+ # === Notice
2629
+ # * mtx : RMtx3
2630
+ # * the suffix "RS" means "matrix representing Rotational and Scaling
2631
+ # transformation".
2632
+ #
2633
+ def transformRSTransposed!( mtx )
2634
+ x = self[0]
2635
+ y = self[1]
2636
+ z = self[2]
2637
+ self.x = mtx.e00 * x + mtx.e10 * y + mtx.e20 * z
2638
+ self.y = mtx.e01 * x + mtx.e11 * y + mtx.e21 * z
2639
+ self.z = mtx.e02 * x + mtx.e12 * y + mtx.e22 * z
2640
+
2641
+ return self
2642
+ end
2643
+
2644
+ #
2645
+ # call-seq: transformByQuaternion(q) -> transformed RVec3
2646
+ #
2647
+ def transformByQuaternion( q )
2648
+ result = RVec3.new
2649
+ t_x = q.w*self[0] + q.y*self[2] - q.z*self[1]
2650
+ t_y = q.w*self[1] - q.x*self[2] + q.z*self[0]
2651
+ t_z = q.w*self[2] + q.x*self[1] - q.y*self[0]
2652
+ t_w = - q.x*self[0] - q.y*self[1] - q.z*self[2]
2653
+
2654
+ result.x = -t_w*q.x + t_x*q.w - t_y*q.z + t_z*q.y;
2655
+ result.y = -t_w*q.y + t_x*q.z + t_y*q.w - t_z*q.x;
2656
+ result.z = -t_w*q.z - t_x*q.y + t_y*q.x + t_z*q.w;
2657
+
2658
+ return result
2659
+ end
2660
+
2661
+ #
2662
+ # call-seq: transformByQuaternion!(q) -> self
2663
+ #
2664
+ def transformByQuaternion!( q )
2665
+ t_x = q.w*self[0] + q.y*self[2] - q.z*self[1]
2666
+ t_y = q.w*self[1] - q.x*self[2] + q.z*self[0]
2667
+ t_z = q.w*self[2] + q.x*self[1] - q.y*self[0]
2668
+ t_w = - q.x*self[0] - q.y*self[1] - q.z*self[2]
2669
+
2670
+ self.x = -t_w*q.x + t_x*q.w - t_y*q.z + t_z*q.y;
2671
+ self.y = -t_w*q.y + t_x*q.z + t_y*q.w - t_z*q.x;
2672
+ self.z = -t_w*q.z - t_x*q.y + t_y*q.x + t_z*q.w;
2673
+
2674
+ return self
2675
+ end
2676
+
2677
+ #
2678
+ # call-seq: getNormalized -> RVec3
2679
+ #
2680
+ # Returns normalized vector.
2681
+ #
2682
+ def getNormalized
2683
+ l = getLength()
2684
+ l = 1.0/l
2685
+ return RVec3.new( @e[0]*l, @e[1]*l, @e[2]*l )
2686
+ end
2687
+
2688
+ #
2689
+ # call-seq: normalize! -> self
2690
+ #
2691
+ # Normalizes itself.
2692
+ #
2693
+ def normalize!
2694
+ l = getLength()
2695
+ l = 1.0/l
2696
+ @e[0] *= l
2697
+ @e[1] *= l
2698
+ @e[2] *= l
2699
+ return self
2700
+ end
2701
+
2702
+ #
2703
+ # call-seq: +
2704
+ #
2705
+ # +vec : Unary plus operator.
2706
+ #
2707
+ def +@
2708
+ return self
2709
+ end
2710
+
2711
+ #
2712
+ # call-seq: -
2713
+ #
2714
+ # -vec : Unary minus operator.
2715
+ #
2716
+ def -@
2717
+ return RVec3.new( -@e[0], -@e[1], -@e[2] )
2718
+ end
2719
+
2720
+ #
2721
+ # call-seq: +
2722
+ #
2723
+ # vec1 + vec2 : Binary plus operator.
2724
+ #
2725
+ def +( arg )
2726
+ if arg.class != RVec3
2727
+ raise TypeError, "RVec3#+ : Unknown type #{arg.class}."
2728
+ return nil
2729
+ end
2730
+ RVec3.new( x+arg.x, y+arg.y, z+arg.z )
2731
+ end
2732
+
2733
+ #
2734
+ # call-seq: -
2735
+ #
2736
+ # vec1 - vec2 : Binary minus operator.
2737
+ #
2738
+ def -( arg )
2739
+ if arg.class != RVec3
2740
+ raise TypeError, "RVec3#- : Unknown type #{arg.class}."
2741
+ return nil
2742
+ end
2743
+ RVec3.new( x-arg.x, y-arg.y, z-arg.z )
2744
+ end
2745
+
2746
+ #
2747
+ # call-seq: *
2748
+ #
2749
+ # vec1 * vec2 : Binary multiply operator.
2750
+ #
2751
+ def *( arg )
2752
+ case arg
2753
+ when Fixnum, Float
2754
+ return RVec3.new( @e[0]*arg, @e[1]*arg, @e[2]*arg )
2755
+ else
2756
+ raise TypeError, "RVec3#* : Unknown type #{arg}."
2757
+ return nil
2758
+ end
2759
+ end
2760
+
2761
+ #
2762
+ # call-seq: ==
2763
+ #
2764
+ # vec1 == vec2 : evaluates equality.
2765
+ #
2766
+ def ==( other )
2767
+ if other.class != RVec3
2768
+ raise TypeError, "RVec3#== : Unknown type #{other.class}."
2769
+ return nil
2770
+ end
2771
+
2772
+ if (x-other.x).abs<=Float::EPSILON &&
2773
+ (y-other.y).abs<=Float::EPSILON &&
2774
+ (z-other.z).abs<=Float::EPSILON
2775
+ return true
2776
+ else
2777
+ return false
2778
+ end
2779
+ end
2780
+
2781
+ #
2782
+ # call-seq: vec1.add!( vec2 )
2783
+ #
2784
+ # vec1 += vec2 : appends the elements of +vec2+ into corresponding +vec1+ elements.
2785
+ #
2786
+ def add!( other )
2787
+ if other.class != RVec3
2788
+ raise TypeError, "RVec3#add! : Unknown type #{other.class}."
2789
+ return nil
2790
+ end
2791
+
2792
+ self.x += other.x
2793
+ self.y += other.y
2794
+ self.z += other.z
2795
+
2796
+ return self
2797
+ end
2798
+
2799
+ #
2800
+ # call-seq: vec1.sub!( vec2 )
2801
+ #
2802
+ # vec1 -= vec2 : subtracts the elements of +vec2+ from corresponding +vec1+ elements.
2803
+ #
2804
+ def sub!( other )
2805
+ if other.class != RVec3
2806
+ raise TypeError, "RVec3#sub! : Unknown type #{other.class}."
2807
+ return nil
2808
+ end
2809
+
2810
+ self.x -= other.x
2811
+ self.y -= other.y
2812
+ self.z -= other.z
2813
+
2814
+ return self
2815
+ end
2816
+
2817
+ #
2818
+ # call-seq: vec1.mul!( vec2 )
2819
+ #
2820
+ # vec1 *= vec2
2821
+ #
2822
+ def mul!( arg )
2823
+ if arg.class != Fixnum && arg.class != Float
2824
+ raise TypeError, "RVec3#mul! : Unknown type #{arg.class}."
2825
+ return nil
2826
+ end
2827
+
2828
+ self.x *= arg
2829
+ self.y *= arg
2830
+ self.z *= arg
2831
+
2832
+ return self
2833
+ end
2834
+ end
2835
+
2836
+ #
2837
+ # Document-class: RMath3D::RVec4
2838
+ # provies 4 element vector arithmetic.
2839
+ #
2840
+ class RVec4
2841
+
2842
+ #
2843
+ # call-seq:
2844
+ # RVec4.new -> (0,0,0,0)
2845
+ # RVec4.new(e) -> (e,e,e,e)
2846
+ # RVec4.new( other ) : Copy Constructor
2847
+ # RVec4.new( e0, e1, e2, e3 ) -> (e0,e1,e2,e3)
2848
+ #
2849
+ # Creates a new 4 element vector.
2850
+ #
2851
+ def initialize( *a )
2852
+ @e = []
2853
+ case a.length
2854
+ when 0
2855
+ @e = [0.0, 0.0, 0.0, 0.0]
2856
+ when 1
2857
+ case a[0]
2858
+ when Fixnum, Float
2859
+ @e = [ a[0], a[0], a[0], a[0] ]
2860
+ when RVec3
2861
+ @e = [ a[0].x, a[0].y, a[0].z, 0.0 ]
2862
+ when RVec4
2863
+ @e = [ a[0].x, a[0].y, a[0].z, a[0].w ]
2864
+ else
2865
+ raise TypeError, "RVec4#initialize : Unknown type #{a[0].class}."
2866
+ return nil
2867
+ end
2868
+ when 4
2869
+ a.each_with_index do |elem, index|
2870
+ case elem
2871
+ when Fixnum, Float
2872
+ @e[index] = elem
2873
+ else
2874
+ raise TypeError, "RVec4#initialize : Unknown type #{elem.class}."
2875
+ return nil
2876
+ end
2877
+ end
2878
+ else
2879
+ raise RuntimeError, "RVec4#initialize : wrong # of arguments (#{a.length})"
2880
+ return nil
2881
+ end
2882
+ return self
2883
+ end
2884
+
2885
+ #
2886
+ # call-seq: to_s
2887
+ #
2888
+ # Returns human-readable string.
2889
+ #
2890
+ def to_s
2891
+ return "( #{@e[0]}, #{@e[1]}, #{@e[2]}, #{@e[3]} )\n"
2892
+ end
2893
+
2894
+ #
2895
+ # call-seq: to_a
2896
+ #
2897
+ # Returns its elements as a new Array.
2898
+ #
2899
+ def to_a
2900
+ return @e
2901
+ end
2902
+
2903
+ #
2904
+ # call-seq: coerse(other)
2905
+ #
2906
+ # Resolves type mismatch.
2907
+ #
2908
+ def coerce( arg )
2909
+ case arg
2910
+ when Fixnum, Float, Bignum
2911
+ return [ self, arg ]
2912
+ else
2913
+ raise TypeError, "RVec4#coerce : #{arg.self} can't be coerced into #{self.class}."
2914
+ return nil
2915
+ end
2916
+ end
2917
+
2918
+ #
2919
+ # call-seq: setElements( e0, e1, e2, e3 )
2920
+ #
2921
+ # Stores given 4 new values.
2922
+ #
2923
+ def setElements( x, y, z, w )
2924
+ self.x = x
2925
+ self.y = y
2926
+ self.z = z
2927
+ self.w = w
2928
+ end
2929
+
2930
+ #
2931
+ # call-seq: vec4[i]= value
2932
+ #
2933
+ # Stores +value+ at +i+.
2934
+ #
2935
+ def []=(i,value)
2936
+ @e[i] = value
2937
+ end
2938
+
2939
+ #
2940
+ # call-seq: x= value
2941
+ #
2942
+ # Stores +value+ as +x+.
2943
+ #
2944
+ def x=(value) @e[0] = value end
2945
+
2946
+ #
2947
+ # call-seq: y= value
2948
+ #
2949
+ # Stores +value+ as +y+.
2950
+ #
2951
+ def y=(value) @e[1] = value end
2952
+
2953
+ #
2954
+ # call-seq: z= value
2955
+ #
2956
+ # Stores +value+ as +z+.
2957
+ #
2958
+ def z=(value) @e[2] = value end
2959
+
2960
+ #
2961
+ # call-seq: w= value
2962
+ #
2963
+ # Stores +value+ as +w+.
2964
+ #
2965
+ def w=(value) @e[3] = value end
2966
+
2967
+ #
2968
+ # call-seq: xyz= vXYZ
2969
+ #
2970
+ # Copies the values of +vXYZ+(RVec3) into +x+, +y+ and +z+.
2971
+ #
2972
+ def xyz=( arg )
2973
+ if arg.class != RVec3
2974
+ raise TypeError, "RVec4#xyz= : Unknown type #{arg.class}."
2975
+ return nil
2976
+ end
2977
+ @e[0] = arg.x
2978
+ @e[1] = arg.y
2979
+ @e[2] = arg.z
2980
+ end
2981
+
2982
+ #
2983
+ # call-seq: vec4[i] -> value
2984
+ #
2985
+ # Returns the element at +i+.
2986
+ #
2987
+ def [](i)
2988
+ @e[i]
2989
+ end
2990
+
2991
+ #
2992
+ # call-seq: x -> value
2993
+ #
2994
+ # Returns the value of +x+.
2995
+ #
2996
+ def x() return @e[0] end
2997
+
2998
+ #
2999
+ # call-seq: y -> value
3000
+ #
3001
+ # Returns the value of +y+.
3002
+ #
3003
+ def y() return @e[1] end
3004
+
3005
+ #
3006
+ # call-seq: z -> value
3007
+ #
3008
+ # Returns the value of +z+.
3009
+ #
3010
+ def z() return @e[2] end
3011
+
3012
+ #
3013
+ # call-seq: w -> value
3014
+ #
3015
+ # Returns the value of +w+.
3016
+ #
3017
+ def w() return @e[3] end
3018
+
3019
+ #
3020
+ # call-seq: xyz -> RVec3
3021
+ #
3022
+ # Returns the values of +x+, +y+ and +z+ with new RVec3(+x+,+y+,+z+).
3023
+ #
3024
+ def xyz()
3025
+ return RVec3.new( @e[0], @e[1], @e[2] )
3026
+ end
3027
+
3028
+ #
3029
+ # call-seq: getLength
3030
+ #
3031
+ # Returns the Euclidean length.
3032
+ #
3033
+ def getLength
3034
+ return Math.sqrt( @e[0]*@e[0] + @e[1]*@e[1] + @e[2]*@e[2] + @e[3]*@e[3] )
3035
+ end
3036
+
3037
+ #
3038
+ # call-seq: getLengthSq
3039
+ #
3040
+ # Returns the squared Euclidean length.
3041
+ #
3042
+ def getLengthSq
3043
+ return (@e[0]*@e[0] + @e[1]*@e[1] + @e[2]*@e[2] + @e[3]*@e[3]).to_f
3044
+ end
3045
+
3046
+ #
3047
+ # call-seq: RVec4.dot(v1,v2) -> value
3048
+ #
3049
+ # Calculates the dot product of +v1+ and +v2+.
3050
+ #
3051
+ def RVec4.dot( v1, v2 )
3052
+ return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z + v1.w*v2.w
3053
+ end
3054
+
3055
+ #
3056
+ # call-seq: transform(mtx4) -> transformed RVec4
3057
+ #
3058
+ # Returns new RVec4 containing the result of the transformation by +mtx4+ (RMtx4).
3059
+ #
3060
+ def transform( mtx )
3061
+ result = RVec4.new
3062
+ result.x = mtx.e00 * self[0] + mtx.e01 * self[1] + mtx.e02 * self[2] + mtx.e03 * self[3]
3063
+ result.y = mtx.e10 * self[0] + mtx.e11 * self[1] + mtx.e12 * self[2] + mtx.e13 * self[3]
3064
+ result.z = mtx.e20 * self[0] + mtx.e21 * self[1] + mtx.e22 * self[2] + mtx.e23 * self[3]
3065
+ result.w = mtx.e30 * self[0] + mtx.e31 * self[1] + mtx.e32 * self[2] + mtx.e33 * self[3]
3066
+
3067
+ return result
3068
+ end
3069
+
3070
+ #
3071
+ # call-seq: transform(mtx4) -> self
3072
+ #
3073
+ # Applies the transform matrix +mtx4+ (RMtx4).
3074
+ #
3075
+ def transform!( mtx )
3076
+ x = self[0]
3077
+ y = self[1]
3078
+ z = self[2]
3079
+ w = self[3]
3080
+
3081
+ self.x = mtx.e00 * x + mtx.e01 * y + mtx.e02 * z + mtx.e03 * w
3082
+ self.y = mtx.e10 * x + mtx.e11 * y + mtx.e12 * z + mtx.e13 * w
3083
+ self.z = mtx.e20 * x + mtx.e21 * y + mtx.e22 * z + mtx.e23 * w
3084
+ self.w = mtx.e30 * x + mtx.e31 * y + mtx.e32 * z + mtx.e33 * w
3085
+
3086
+ return self
3087
+ end
3088
+
3089
+ #
3090
+ # call-seq: transformTransposed(mtx4) -> RVec4 transformed by mtx4^T
3091
+ #
3092
+ # Returns new RVec4 containing the result of the transformation by +mtx4^T+ (RMtx4).
3093
+ #
3094
+ def transformTransposed( mtx )
3095
+ result = RVec4.new
3096
+ result.x = mtx.e00 * self[0] + mtx.e10 * self[1] + mtx.e20 * self[2] + mtx.e30 * self[3]
3097
+ result.y = mtx.e01 * self[0] + mtx.e11 * self[1] + mtx.e21 * self[2] + mtx.e31 * self[3]
3098
+ result.z = mtx.e02 * self[0] + mtx.e12 * self[1] + mtx.e22 * self[2] + mtx.e32 * self[3]
3099
+ result.w = mtx.e03 * self[0] + mtx.e13 * self[1] + mtx.e23 * self[2] + mtx.e33 * self[3]
3100
+
3101
+ return result
3102
+ end
3103
+
3104
+ #
3105
+ # call-seq: transformTransposed!(mtx4) -> self
3106
+ #
3107
+ # Applies the transform matrix +mtx4^T+ (RMtx4).
3108
+ #
3109
+ def transformTransposed!( mtx )
3110
+ x = self[0]
3111
+ y = self[1]
3112
+ z = self[2]
3113
+ w = self[3]
3114
+
3115
+ self.x = mtx.e00 * x + mtx.e10 * y + mtx.e20 * z + mtx.e30 * w
3116
+ self.y = mtx.e01 * x + mtx.e11 * y + mtx.e21 * z + mtx.e31 * w
3117
+ self.z = mtx.e02 * x + mtx.e12 * y + mtx.e22 * z + mtx.e32 * w
3118
+ self.w = mtx.e03 * x + mtx.e13 * y + mtx.e23 * z + mtx.e33 * w
3119
+
3120
+ return self
3121
+ end
3122
+
3123
+ #
3124
+ # call-seq: getNormalized -> RVec4
3125
+ #
3126
+ # Returns normalized vector.
3127
+ #
3128
+ def getNormalized
3129
+ l = getLength()
3130
+ l = 1.0/l
3131
+ return RVec4.new( @e[0]*l, @e[1]*l, @e[2]*l, @e[3]*l )
3132
+ end
3133
+
3134
+ #
3135
+ # call-seq: normalize! -> self
3136
+ #
3137
+ # Normalizes itself.
3138
+ #
3139
+ def normalize!
3140
+ l = getLength()
3141
+ l = 1.0/l
3142
+ @e[0] *= l
3143
+ @e[1] *= l
3144
+ @e[2] *= l
3145
+ @e[3] *= l
3146
+ return self
3147
+ end
3148
+
3149
+ #
3150
+ # call-seq: +
3151
+ #
3152
+ # +vec : Unary plus operator.
3153
+ #
3154
+ def +@
3155
+ return self
3156
+ end
3157
+
3158
+ #
3159
+ # call-seq: -
3160
+ #
3161
+ # -vec : Unary minus operator.
3162
+ #
3163
+ def -@
3164
+ return RVec4.new( -@e[0], -@e[1], -@e[2], -@e[3] )
3165
+ end
3166
+
3167
+ #
3168
+ # call-seq: +
3169
+ #
3170
+ # vec1 + vec2 : Binary plus operator.
3171
+ #
3172
+ def +( arg )
3173
+ if arg.class != RVec4
3174
+ raise TypeError, "RVec4#+ : Unknown type #{arg.class}."
3175
+ return nil
3176
+ end
3177
+ RVec4.new( x+arg.x, y+arg.y, z+arg.z, w+arg.w )
3178
+ end
3179
+
3180
+ #
3181
+ # call-seq: -
3182
+ #
3183
+ # vec1 - vec2 : Binary minus operator.
3184
+ #
3185
+ def -( arg )
3186
+ if arg.class != RVec4
3187
+ raise TypeError, "RVec4#+ : Unknown type #{arg.class}."
3188
+ return nil
3189
+ end
3190
+ RVec4.new( x-arg.x, y-arg.y, z-arg.z, w-arg.w )
3191
+ end
3192
+
3193
+ #
3194
+ # call-seq: *
3195
+ #
3196
+ # vec1 * vec2 : Binary multiply operator.
3197
+ #
3198
+ def *( arg )
3199
+ case arg
3200
+ when Fixnum, Float
3201
+ return RVec4.new( @e[0]*arg, @e[1]*arg, @e[2]*arg, @e[3]*arg )
3202
+ else
3203
+ raise TypeError, "RVec4#* : Unknown type #{arg}."
3204
+ return nil
3205
+ end
3206
+ end
3207
+
3208
+ #
3209
+ # call-seq: ==
3210
+ #
3211
+ # vec1 == vec2 : evaluates equality.
3212
+ #
3213
+ def ==( other )
3214
+ if other.class != RVec4
3215
+ raise TypeError, "RVec4#== : Unknown type #{other.class}."
3216
+ return nil
3217
+ end
3218
+
3219
+ if (x-other.x).abs<=Float::EPSILON &&
3220
+ (y-other.y).abs<=Float::EPSILON &&
3221
+ (z-other.z).abs<=Float::EPSILON &&
3222
+ (w-other.w).abs<=Float::EPSILON
3223
+ return true
3224
+ else
3225
+ return false
3226
+ end
3227
+ end
3228
+
3229
+ #
3230
+ # call-seq: vec1.add!( vec2 )
3231
+ #
3232
+ # vec1 += vec2 : appends the elements of +vec2+ into corresponding +vec1+ elements.
3233
+ #
3234
+ def add!( other )
3235
+ if other.class != RVec4
3236
+ raise TypeError, "RVec4#add! : Unknown type #{other.class}."
3237
+ return nil
3238
+ end
3239
+
3240
+ self.x += other.x
3241
+ self.y += other.y
3242
+ self.z += other.z
3243
+ self.w += other.w
3244
+
3245
+ return self
3246
+ end
3247
+
3248
+ #
3249
+ # call-seq: vec1.sub!( vec2 )
3250
+ #
3251
+ # vec1 -= vec2 : subtracts the elements of +vec2+ from corresponding +vec1+ elements.
3252
+ #
3253
+ def sub!( other )
3254
+ if other.class != RVec4
3255
+ raise TypeError, "RVec4#sub! : Unknown type #{other.class}."
3256
+ return nil
3257
+ end
3258
+
3259
+ self.x -= other.x
3260
+ self.y -= other.y
3261
+ self.z -= other.z
3262
+ self.w -= other.w
3263
+
3264
+ return self
3265
+ end
3266
+
3267
+ #
3268
+ # call-seq: vec1.mul!( vec2 )
3269
+ #
3270
+ # vec1 *= vec2
3271
+ #
3272
+ def mul!( other )
3273
+ if other.class != Fixnum && other.class != Float
3274
+ raise TypeError, "RVec4#mul! : Unknown type #{other.class}."
3275
+ return nil
3276
+ end
3277
+
3278
+ self.x *= other
3279
+ self.y *= other
3280
+ self.z *= other
3281
+ self.w *= other
3282
+
3283
+ return self
3284
+ end
3285
+ end
3286
+
3287
+ end
3288
+
3289
+ =begin
3290
+ RMath : Ruby math module for 3D Applications
3291
+ Copyright (c) 2008- vaiorabbit <http://twitter.com/vaiorabbit>
3292
+
3293
+ This software is provided 'as-is', without any express or implied
3294
+ warranty. In no event will the authors be held liable for any damages
3295
+ arising from the use of this software.
3296
+
3297
+ Permission is granted to anyone to use this software for any purpose,
3298
+ including commercial applications, and to alter it and redistribute it
3299
+ freely, subject to the following restrictions:
3300
+
3301
+ 1. The origin of this software must not be misrepresented; you must not
3302
+ claim that you wrote the original software. If you use this software
3303
+ in a product, an acknowledgment in the product documentation would be
3304
+ appreciated but is not required.
3305
+
3306
+ 2. Altered source versions must be plainly marked as such, and must not be
3307
+ misrepresented as being the original software.
3308
+
3309
+ 3. This notice may not be removed or altered from any source
3310
+ distribution.
3311
+ =end