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 +7 -0
- data/ChangeLog +82 -0
- data/LICENSE.txt +21 -0
- data/README.md +178 -0
- data/lib/rmath3d/rmath3d_plain.rb +3311 -0
- data/sample/opengl-bindings/load_matrix.rb +174 -0
- data/sample/opengl2/load_matrix.rb +118 -0
- data/sample/simple/transform.rb +11 -0
- data/test/test.rb +18 -0
- data/test/test_RMtx3.rb +517 -0
- data/test/test_RMtx4.rb +735 -0
- data/test/test_RQuat.rb +381 -0
- data/test/test_RVec3.rb +308 -0
- data/test/test_RVec4.rb +287 -0
- metadata +58 -0
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
|