gmath3D 0.2.5 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/util.rb CHANGED
@@ -1,36 +1,36 @@
1
- module Util3D
2
- def self.check_arg_type(type, instance, nullable = false, array_check = false)
3
- return if(nullable && instance.nil?)
4
- if(array_check && instance.kind_of?(Array))
5
- instance.each do |item|
6
- check_arg_type(type, item, nullable, array_check)
7
- end
8
- else
9
- unless(instance.kind_of?(type))
10
- raise(ArgumentError::new("type mismatch: #{instance.class} for #{type}"))
11
- end
12
- end
13
- end
14
-
15
- def self.raise_argurment_error(instance)
16
- raise(ArgumentError::new("type mismatch: #{instance.class}"))
17
- end
18
-
19
- def self.check_key_arg(arg, key)
20
- if(!arg.include?(key))
21
- raise(ArgumentError::new("args should be contains: #{key}"))
22
- end
23
- end
24
- end
25
-
26
- module GMath3D
27
- # Including 'vertices' methodshould be implimented that gets geometry vertices as Array of Vector3.
28
- module BoxAvailable
29
- # [Output]
30
- # return axially aligned bounding box as Box.
31
- def box
32
- return Box.from_points( vertices )
33
- end
34
- end
35
- end
36
-
1
+ module Util3D
2
+ def self.check_arg_type(type, instance, nullable = false, array_check = false)
3
+ return if(nullable && instance.nil?)
4
+ if(array_check && instance.kind_of?(Array))
5
+ instance.each do |item|
6
+ check_arg_type(type, item, nullable, array_check)
7
+ end
8
+ else
9
+ unless(instance.kind_of?(type))
10
+ raise(ArgumentError::new("type mismatch: #{instance.class} for #{type}"))
11
+ end
12
+ end
13
+ end
14
+
15
+ def self.raise_argurment_error(instance)
16
+ raise(ArgumentError::new("type mismatch: #{instance.class}"))
17
+ end
18
+
19
+ def self.check_key_arg(arg, key)
20
+ if(!arg.include?(key))
21
+ raise(ArgumentError::new("args should be contains: #{key}"))
22
+ end
23
+ end
24
+ end
25
+
26
+ module GMath3D
27
+ # Including 'vertices' methodshould be implimented that gets geometry vertices as Array of Vector3.
28
+ module BoxAvailable
29
+ # [Output]
30
+ # return axially aligned bounding box as Box.
31
+ def box
32
+ return Box.from_points( vertices )
33
+ end
34
+ end
35
+ end
36
+
data/lib/vector3.rb CHANGED
@@ -1,227 +1,231 @@
1
- # -*- coding: cp932 -*-
2
- require 'gmath3D'
3
-
4
- module GMath3D
5
- #
6
- # Vector3 represents a point or a vector on 3D space.
7
- #
8
- class Vector3 < Geom
9
- attr_accessor :x
10
- attr_accessor :y
11
- attr_accessor :z
12
-
13
- # [Input]
14
- # _x_, _y_, _z_ should be Numeric.
15
- # [Output]
16
- # return new instance as Vector3.
17
- def initialize(x=0.0,y=0.0,z=0.0)
18
- Util3D.check_arg_type(Numeric, x)
19
- Util3D.check_arg_type(Numeric, y)
20
- Util3D.check_arg_type(Numeric, z)
21
- super()
22
- @x = x
23
- @y = y
24
- @z = z
25
- end
26
-
27
- def to_element_s
28
- "[#{@x}, #{@y}, #{@z}]"
29
- end
30
-
31
- def to_s
32
- "Vector3" + to_element_s
33
- end
34
-
35
- # [Input]
36
- # _rhs_ should be Vector3.
37
- # [Output]
38
- # return true if rhs equals myself.
39
- def ==(rhs)
40
- return false if( !rhs.kind_of?(Vector3) )
41
- equals_inner(rhs)
42
- end
43
-
44
- # For using Vector3 as hash key
45
- def hash
46
- [@x.to_f, @y.to_f, @z.to_f].hash
47
- end
48
- def eql?(rhs)
49
- equals_inner(rhs)
50
- end
51
-
52
- # [Output]
53
- # return axially aligned bounding box as Box.
54
- def box
55
- return Box.new(self, self)
56
- end
57
-
58
- # [Input]
59
- # _rhs_ should be Vector3.
60
- # [Output]
61
- # return added result as Vector3.
62
- def +(rhs)
63
- add(rhs)
64
- end
65
-
66
- # [Input]
67
- # _rhs_ should be Vector3.
68
- # [Output]
69
- # return subtracted result as Vector3.
70
- def -(rhs)
71
- subtract(rhs)
72
- end
73
-
74
- # [Input]
75
- # _rsh_ should be Numeric.
76
- # [Output]
77
- # return multiplyed result as Vector3.
78
- def *(rhs)
79
- multiply(rhs)
80
- end
81
-
82
- # [Input]
83
- # _rhs_ should be Numeric.
84
- # [Output]
85
- # return divided result as Vector3.
86
- def /(rhs)
87
- divide(rhs)
88
- end
89
-
90
- # [Input]
91
- # _rhs_ should be Vector3.
92
- # [Output]
93
- # return inner product as Numeric
94
- def dot(rhs)
95
- Util3D.check_arg_type(Vector3, rhs)
96
- self.x*rhs.x + self.y*rhs.y + self.z*rhs.z
97
- end
98
-
99
- # [Input]
100
- # _rhs_ should be Vector3.
101
- # [Output]
102
- # return cross product as Vector3.
103
- def cross(rhs)
104
- Util3D.check_arg_type(Vector3, rhs)
105
- Vector3.new(
106
- self.y*rhs.z - self.z*rhs.y,
107
- self.z*rhs.x - self.x*rhs.z,
108
- self.x*rhs.y - self.y*rhs.x)
109
- end
110
-
111
- # [Output]
112
- # return orthogonal vector as Vector3.
113
- def arbitrary_orthogonal
114
- return Vector3.new() if(self.length < self.tolerance)
115
-
116
- if(!self.parallel?( Vector3.new(0.0, 1.0, 0.0) ))
117
- un_parallel_vec = Vector3.new(0.0,1.0,0.0)
118
- elsif(!self.parallel?( Vector3.new(0.0,0.0,1.0) ))
119
- un_parallel_vec = Vector3.new(0.0,0.0,1.0)
120
- else
121
- un_parallel_vec = Vector3.new(1.0,0.0,0.0)
122
- end
123
-
124
- orthogonal = self.cross(un_parallel_vec)
125
- return orthogonal.normalize
126
- end
127
-
128
- # [Output]
129
- # return vector length as Numeric
130
- def length
131
- Math::sqrt(self.x*self.x + self.y*self.y + self.z*self.z)
132
- end
133
-
134
- # [Input]
135
- # _rhs_ should be Vector3.
136
- # [Output]
137
- # return distance between two points as Numeric.
138
- def distance(rhs)
139
- Util3D.check_arg_type(Vector3, rhs)
140
- Math::sqrt((self.x - rhs.x)*(self.x - rhs.x) + (self.y - rhs.y)*(self.y - rhs.y) + (self.z - rhs.z)*(self.z - rhs.z))
141
- end
142
-
143
- # [Input]
144
- # _rhs_ should be Vector3.
145
- # [Output]
146
- # return two vectors angle as Numeric (rad).
147
- def angle(rhs)
148
- Util3D.check_arg_type(Vector3, rhs)
149
- vec1Length = self.length ;
150
- vec2Length = rhs.length ;
151
- return 0.0 if(vec1Length*vec2Length < self.tolerance )
152
- v = self.dot(rhs)/(vec1Length*vec2Length)
153
- Math::acos( v )
154
- end
155
-
156
- # [Output]
157
- # return normalized vector as Vector3
158
- def normalize()
159
- self / self.length.to_f
160
- end
161
-
162
- # [Input]
163
- # _rhs_ should be Vector3
164
- # [Output]
165
- # return true if myself and rhs is parallel as boolean
166
- def parallel?(rhs)
167
- Util3D.check_arg_type(Vector3, rhs)
168
- return false if(self.length < self.tolerance or rhs.length < rhs.tolerance)
169
- return false if(self.cross(rhs).length > self.tolerance)
170
- return true
171
- end
172
-
173
- # [Input]
174
- # _rhs_ should be Vector3.
175
- # [Output]
176
- # return true if myself and rhs have same direction as boolean.
177
- def same_direction?(rhs)
178
- Util3D.check_arg_type(Vector3, rhs)
179
- return false if(!parallel?(rhs))
180
- return false if(self.dot(rhs) < self.tolerance)
181
- return true
182
- end
183
-
184
- # This function projects self vector to rhs vector.
185
- # [Input]
186
- # _rhs_ should be Vector3.
187
- # [Output]
188
- # return projected result as Vector3.
189
- def project_to(rhs)
190
- Util3D.check_arg_type(Vector3, rhs)
191
- return Vector3.new, 0.0 if( rhs.length < rhs.tolerance )
192
- parameter = self.dot( rhs ) / ( rhs.x * rhs.x + rhs.y * rhs.y + rhs.z * rhs.z ).to_f
193
- return rhs*parameter, parameter
194
- end
195
-
196
- # [Output]
197
- # return column vector as Matrix
198
- def to_column_vector
199
- return Matrix.column_vector([x,y,z])
200
- end
201
-
202
- private
203
- def equals_inner(rhs)
204
- return false if((self.x - rhs.x).abs > @tolerance)
205
- return false if((self.y - rhs.y).abs > @tolerance)
206
- return false if((self.z - rhs.z).abs > @tolerance)
207
- true
208
- end
209
- def add(rhs)
210
- Util3D.check_arg_type(Vector3, rhs)
211
- Vector3.new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
212
- end
213
- def subtract(rhs)
214
- Util3D.check_arg_type(Vector3, rhs)
215
- Vector3.new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
216
- end
217
- def multiply(rhs)
218
- Util3D.check_arg_type(::Numeric, rhs)
219
- Vector3.new(self.x * rhs, self.y * rhs, self.z * rhs)
220
- end
221
- def divide(rhs)
222
- Util3D.check_arg_type(::Numeric, rhs)
223
- Vector3.new(self.x.to_f / rhs, self.y / rhs.to_f, self.z / rhs.to_f)
224
- end
225
- end
226
- end
227
-
1
+ # -*- coding: cp932 -*-
2
+ require 'gmath3D'
3
+
4
+ module GMath3D
5
+ #
6
+ # Vector3 represents a point or a vector on 3D space.
7
+ #
8
+ class Vector3 < Geom
9
+ attr_accessor :x
10
+ attr_accessor :y
11
+ attr_accessor :z
12
+
13
+ # [Input]
14
+ # _x_, _y_, _z_ should be Numeric.
15
+ # [Output]
16
+ # return new instance as Vector3.
17
+ def initialize(x=0.0,y=0.0,z=0.0)
18
+ Util3D.check_arg_type(Numeric, x)
19
+ Util3D.check_arg_type(Numeric, y)
20
+ Util3D.check_arg_type(Numeric, z)
21
+ super()
22
+ @x = x
23
+ @y = y
24
+ @z = z
25
+ end
26
+
27
+ def to_element_s
28
+ "[#{@x}, #{@y}, #{@z}]"
29
+ end
30
+
31
+ def to_s
32
+ "Vector3" + to_element_s
33
+ end
34
+
35
+ def to_ary
36
+ [@x,@y,@z]
37
+ end
38
+
39
+ # [Input]
40
+ # _rhs_ should be Vector3.
41
+ # [Output]
42
+ # return true if rhs equals myself.
43
+ def ==(rhs)
44
+ return false if( !rhs.kind_of?(Vector3) )
45
+ equals_inner(rhs)
46
+ end
47
+
48
+ # For using Vector3 as hash key
49
+ def hash
50
+ [@x.to_f, @y.to_f, @z.to_f].hash
51
+ end
52
+ def eql?(rhs)
53
+ equals_inner(rhs)
54
+ end
55
+
56
+ # [Output]
57
+ # return axially aligned bounding box as Box.
58
+ def box
59
+ return Box.new(self, self)
60
+ end
61
+
62
+ # [Input]
63
+ # _rhs_ should be Vector3.
64
+ # [Output]
65
+ # return added result as Vector3.
66
+ def +(rhs)
67
+ add(rhs)
68
+ end
69
+
70
+ # [Input]
71
+ # _rhs_ should be Vector3.
72
+ # [Output]
73
+ # return subtracted result as Vector3.
74
+ def -(rhs)
75
+ subtract(rhs)
76
+ end
77
+
78
+ # [Input]
79
+ # _rsh_ should be Numeric.
80
+ # [Output]
81
+ # return multiplyed result as Vector3.
82
+ def *(rhs)
83
+ multiply(rhs)
84
+ end
85
+
86
+ # [Input]
87
+ # _rhs_ should be Numeric.
88
+ # [Output]
89
+ # return divided result as Vector3.
90
+ def /(rhs)
91
+ divide(rhs)
92
+ end
93
+
94
+ # [Input]
95
+ # _rhs_ should be Vector3.
96
+ # [Output]
97
+ # return inner product as Numeric
98
+ def dot(rhs)
99
+ Util3D.check_arg_type(Vector3, rhs)
100
+ self.x*rhs.x + self.y*rhs.y + self.z*rhs.z
101
+ end
102
+
103
+ # [Input]
104
+ # _rhs_ should be Vector3.
105
+ # [Output]
106
+ # return cross product as Vector3.
107
+ def cross(rhs)
108
+ Util3D.check_arg_type(Vector3, rhs)
109
+ Vector3.new(
110
+ self.y*rhs.z - self.z*rhs.y,
111
+ self.z*rhs.x - self.x*rhs.z,
112
+ self.x*rhs.y - self.y*rhs.x)
113
+ end
114
+
115
+ # [Output]
116
+ # return orthogonal vector as Vector3.
117
+ def arbitrary_orthogonal
118
+ return Vector3.new() if(self.length < self.tolerance)
119
+
120
+ if(!self.parallel?( Vector3.new(0.0, 1.0, 0.0) ))
121
+ un_parallel_vec = Vector3.new(0.0,1.0,0.0)
122
+ elsif(!self.parallel?( Vector3.new(0.0,0.0,1.0) ))
123
+ un_parallel_vec = Vector3.new(0.0,0.0,1.0)
124
+ else
125
+ un_parallel_vec = Vector3.new(1.0,0.0,0.0)
126
+ end
127
+
128
+ orthogonal = self.cross(un_parallel_vec)
129
+ return orthogonal.normalize
130
+ end
131
+
132
+ # [Output]
133
+ # return vector length as Numeric
134
+ def length
135
+ Math::sqrt(self.x*self.x + self.y*self.y + self.z*self.z)
136
+ end
137
+
138
+ # [Input]
139
+ # _rhs_ should be Vector3.
140
+ # [Output]
141
+ # return distance between two points as Numeric.
142
+ def distance(rhs)
143
+ Util3D.check_arg_type(Vector3, rhs)
144
+ Math::sqrt((self.x - rhs.x)*(self.x - rhs.x) + (self.y - rhs.y)*(self.y - rhs.y) + (self.z - rhs.z)*(self.z - rhs.z))
145
+ end
146
+
147
+ # [Input]
148
+ # _rhs_ should be Vector3.
149
+ # [Output]
150
+ # return two vectors angle as Numeric (rad).
151
+ def angle(rhs)
152
+ Util3D.check_arg_type(Vector3, rhs)
153
+ vec1Length = self.length ;
154
+ vec2Length = rhs.length ;
155
+ return 0.0 if(vec1Length*vec2Length < self.tolerance )
156
+ v = self.dot(rhs)/(vec1Length*vec2Length)
157
+ Math::acos( v )
158
+ end
159
+
160
+ # [Output]
161
+ # return normalized vector as Vector3
162
+ def normalize()
163
+ self / self.length.to_f
164
+ end
165
+
166
+ # [Input]
167
+ # _rhs_ should be Vector3
168
+ # [Output]
169
+ # return true if myself and rhs is parallel as boolean
170
+ def parallel?(rhs)
171
+ Util3D.check_arg_type(Vector3, rhs)
172
+ return false if(self.length < self.tolerance or rhs.length < rhs.tolerance)
173
+ return false if(self.cross(rhs).length > self.tolerance)
174
+ return true
175
+ end
176
+
177
+ # [Input]
178
+ # _rhs_ should be Vector3.
179
+ # [Output]
180
+ # return true if myself and rhs have same direction as boolean.
181
+ def same_direction?(rhs)
182
+ Util3D.check_arg_type(Vector3, rhs)
183
+ return false if(!parallel?(rhs))
184
+ return false if(self.dot(rhs) < self.tolerance)
185
+ return true
186
+ end
187
+
188
+ # This function projects self vector to rhs vector.
189
+ # [Input]
190
+ # _rhs_ should be Vector3.
191
+ # [Output]
192
+ # return projected result as Vector3.
193
+ def project_to(rhs)
194
+ Util3D.check_arg_type(Vector3, rhs)
195
+ return Vector3.new, 0.0 if( rhs.length < rhs.tolerance )
196
+ parameter = self.dot( rhs ) / ( rhs.x * rhs.x + rhs.y * rhs.y + rhs.z * rhs.z ).to_f
197
+ return rhs*parameter, parameter
198
+ end
199
+
200
+ # [Output]
201
+ # return column vector as Matrix
202
+ def to_column_vector
203
+ return Matrix.column_vector([x,y,z])
204
+ end
205
+
206
+ private
207
+ def equals_inner(rhs)
208
+ return false if((self.x - rhs.x).abs > @tolerance)
209
+ return false if((self.y - rhs.y).abs > @tolerance)
210
+ return false if((self.z - rhs.z).abs > @tolerance)
211
+ true
212
+ end
213
+ def add(rhs)
214
+ Util3D.check_arg_type(Vector3, rhs)
215
+ Vector3.new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
216
+ end
217
+ def subtract(rhs)
218
+ Util3D.check_arg_type(Vector3, rhs)
219
+ Vector3.new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
220
+ end
221
+ def multiply(rhs)
222
+ Util3D.check_arg_type(::Numeric, rhs)
223
+ Vector3.new(self.x * rhs, self.y * rhs, self.z * rhs)
224
+ end
225
+ def divide(rhs)
226
+ Util3D.check_arg_type(::Numeric, rhs)
227
+ Vector3.new(self.x.to_f / rhs, self.y / rhs.to_f, self.z / rhs.to_f)
228
+ end
229
+ end
230
+ end
231
+