mageo 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/mageo/vector.rb CHANGED
@@ -3,21 +3,20 @@
3
3
  require "matrix"
4
4
 
5
5
  class Vector
6
- #include Math
7
- class ZeroOperation < Exception; end
8
- class SizeError < Exception; end
6
+ #include Math
7
+ class ZeroOperation < Exception; end
8
+ class SizeError < Exception; end
9
9
 
10
- # Get a unit vector.
11
- def unit_vector
12
- len = self.r
13
- raise Vector::ZeroOperation if (len == 0)
14
- self * (1/len)
15
- # Vector3D.new(@x*(1.0/len), @y*(1.0/len), @z*(1.0/len))
16
- end
17
-
18
- def floor
19
- self.class[* self.map {|val| val.floor}.to_a]
20
- end
10
+ # Get a unit vector.
11
+ def unit_vector
12
+ len = self.r
13
+ raise Vector::ZeroOperation if (len == 0)
14
+ self * (1/len)
15
+ # Vector3D.new(@x*(1.0/len), @y*(1.0/len), @z*(1.0/len))
16
+ end
21
17
 
18
+ def floor
19
+ self.class[* self.map {|val| val.floor}.to_a]
20
+ end
22
21
  end
23
22
 
@@ -9,25 +9,25 @@ require "mageo/axes.rb"
9
9
  require "mageo/vector.rb"
10
10
  require "rubygems"
11
11
  gem "malge"
12
- #require "malge.rb"
13
- require "malge/simultaneousequations.rb"
12
+ require "malge.rb"
13
+ #require "malge/simultaneousequations.rb"
14
14
  #require "simultaneousequations.rb"
15
15
 
16
16
  # Open class to add "to_v3d" method.
17
17
  class Array
18
- # Convert Array to Vector3D
19
- def to_v3d
20
- Vector3D[*self]
21
- #要素数チェックは Vector3D.[] 側でやっている。
22
- end
18
+ # Convert Array to Vector3D
19
+ def to_v3d
20
+ Vector3D[*self]
21
+ #要素数チェックは Vector3D.[] 側でやっている。
22
+ end
23
23
  end
24
24
 
25
25
  class Vector
26
- # Return a new instance converted to Vector3D class.
27
- def to_v3d
28
- Vector3D[*self]
29
- #要素数チェックは Vector3D.[] 側でやっている。
30
- end
26
+ # Return a new instance converted to Vector3D class.
27
+ def to_v3d
28
+ Vector3D[*self]
29
+ #要素数チェックは Vector3D.[] 側でやっている。
30
+ end
31
31
  end
32
32
 
33
33
 
@@ -38,209 +38,208 @@ end
38
38
  # If you want to be in an internal coordinate, you can use Math/Vector3DInternal.rb .
39
39
  #
40
40
  # Memo:
41
- # Vector3DInternal との対比として、Vector3DCartesian という名前にすることも考えたが、
42
- # 長くなるし、普通直交座標で考えるよね、と。
41
+ # Vector3DInternal との対比として、Vector3DCartesian という名前にすることも考えたが、
42
+ # 長くなるし、普通直交座標で考えるよね、と。
43
43
  #
44
- # インスタンス生成の時点で要素数をチェックし、要素の追加削除を禁止しているので
45
- # 要素数は常に3であることが保証されている。
44
+ # インスタンス生成の時点で要素数をチェックし、要素の追加削除を禁止しているので
45
+ # 要素数は常に3であることが保証されている。
46
46
  #
47
47
  class Vector3D < Vector
48
48
 
49
- class TypeError < Exception; end
50
- class ZeroOperation < Exception; end
51
- class RangeError < Exception; end
52
-
53
- # Class methods
54
-
55
- def self.[](*args)
56
- raise RangeError, "#{args}" unless args.size == 3
57
- super(*args)
58
- end
59
-
60
- # Get the exterior product.
61
- def self.exterior_product(vec0, vec1)
62
- [vec0, vec1].each_with_index do |vec, index|
63
- unless (vec.class == Vector3D)
64
- raise TypeError, "Vector #{index}, #{vec.inspect}."
65
- end
66
- end
67
-
68
- bX = vec1[0];
69
- bY = vec1[1];
70
- bZ = vec1[2];
71
-
72
- cX = (vec0[1] * bZ - vec0[2] * bY);
73
- cY = (vec0[2] * bX - vec0[0] * bZ);
74
- cZ = (vec0[0] * bY - vec0[1] * bX);
75
-
76
- self[cX, cY, cZ]
77
- end
78
- class << self
79
- alias :cross_product :exterior_product
80
- alias :vector_product :exterior_product
81
- end
82
-
83
- # Get the scalar triple product.
84
- def self.scalar_triple_product(vec0, vec1, vec2)
85
- [vec0, vec1, vec2].each_with_index do |vec, index|
86
- raise TypeError, "#{index}th vector: #{vec.inspect}" unless (vec.class == Vector3D)
87
- end
88
-
89
- vec0.inner_product(vec1.exterior_product(vec2))
90
- end
91
-
92
- # Get the angle with radian between self and other vectors.
93
- def self.angle_radian(vec0, vec1)
94
- [vec0, vec1].each_with_index do |vec, index|
95
- raise TypeError, "#{index}th vector: #{vec.inspect}" unless (vec.class == Vector3D)
96
- raise ZeroOperation, "#{index}th vector: #{vec.inspect}" if (vec.r == 0.0)
97
- end
98
-
99
- Math::acos(vec0.inner_product(vec1) / (vec0.r * vec1.r))
100
- end
101
-
102
- # Get the angle with degree between self and other vectors.
103
- def self.angle_degree(vec0, vec1)
104
- [vec0, vec1].each_with_index do |vec, index|
105
- raise TypeError, "#{index}th vector: #{vec.inspect}" unless (vec.class == Vector3D)
106
- raise ZeroOperation, "#{index}th vector: #{vec.inspect}" if (vec.r == 0.0)
107
- end
108
-
109
- self.angle_radian(vec0, vec1) * (180.0 / Math::PI)
110
- end
111
-
112
- # Instance methods
113
-
114
- def [](index)
115
- raise RangeError, "index: #{index}." if (index < 0 || 2 < index)
116
- super index
117
- end
118
-
119
- def []=(index, val)
120
- raise RangeError, "index: #{index}." if (index < 0 || 2 < index)
121
- super index, val
122
- end
123
-
124
-
125
- # ベクトルが等しいかチェック。
126
- # other として Vector3D クラス以外のインスタンス渡すと Vector3D::TypeError。
127
- # 両者の差分ベクトルの長さが tolerance 以下という判定になる。
128
- def equal_in_delta?(other, tolerance = 0.0)
129
- raise TypeError if (other.class != Vector3D)
130
- return (other - self).r <= tolerance
131
- end
132
-
133
- # Vectorクラスで用意されているメソッドは Vectorクラスインスタンスを返すようになっているので、
134
- # Vector3D クラスインスタンスを返すようにした + メソッド。
135
- def +(vec)
136
- unless (vec.class == Vector3D)
137
- raise TypeError, "#{vec.inspect}."
138
- end
139
- super(vec).to_v3d
140
- end
141
-
142
- # Vectorクラスで用意されているメソッドは Vectorクラスインスタンスを返すようになっているので、
143
- # Vector3D クラスインスタンスを返すようにした - メソッド。
144
- def -(vec)
145
- unless (vec.class == Vector3D)
146
- raise TypeError, "#{vec.inspect}."
147
- end
148
- super(vec).to_v3d
149
- end
150
-
151
- # Vectorクラスで用意されているメソッドは Vectorクラスインスタンスを返すようになっているので、
152
- # Vector3D クラスインスタンスを返すようにした * メソッド。
153
- # Argument 'val' must have :to_f method.
154
- def *(val)
155
- #raise TypeError if (val.class != Float)
156
- raise TypeError unless val.methods.include?(:to_f)
157
- super(val.to_f).to_v3d
158
- end
159
-
160
- # Vectorクラスで用意されているメソッドは Vectorクラスインスタンスを返すようになっているので、
161
- # Vector3D クラスインスタンスを返すようにした clone メソッド。
162
- def clone
163
- super().to_v3d
164
- end
165
-
166
- # Convert to Vector3DInternal. Non-destructive.
167
- def to_v3di(axes)
168
- #pp axes.is_a?(Axes)
169
- raise TypeError unless axes.is_a?(Axes)
170
-
171
- axes = axes.to_a
172
- Vector3DInternal[ *(SimultaneousEquations.cramer(axes.transpose, self)) ]
173
- end
174
-
175
- #Return size, always 3.
176
- def size
177
- return 3
178
- end
179
-
180
- # Get the exterior product.
181
- def exterior_product(vec)
182
- self.class.exterior_product(self, vec)
183
- end
184
- alias :cross_product :exterior_product
185
- alias :vector_product :exterior_product
186
-
187
- def scalar_triple_product(vec0, vec1)
188
- self.class.scalar_triple_product(self, vec0, vec1)
189
- end
190
-
191
- def angle_radian(vec)
192
- self.class.angle_radian(self, vec)
193
- end
194
-
195
- def angle_degree(vec)
196
- self.class.angle_degree(self, vec)
197
- end
198
-
199
- #3次元極座標への変換した Polar3D インスタンスを返す。
200
- def to_p3d
201
- r = self.r
202
- if r == 0.0
203
- theta = 0.0
204
- phi = 0.0
205
- else
206
- theta = Polar2D.minimum_radian(Math::acos(self[2] / r))
207
- phi = Vector[ self[0], self[1] ].to_p2d.theta
208
- end
209
- Polar3D.new(r, theta, phi)
210
- end
211
-
212
- #x, y, z 軸のいずれかで self を回転する。破壊的。
213
- #axis は 0, 1, 2 のいずれかで、それぞれ x, y, z軸を示す。
214
- #radian は回転する角度で、原点から軸の伸びる方向に対して右ねじ方向を正とする。
215
- #すなわち、軸の正の値の位置から原点を見たとき、左回りが正である。
216
- #e.g., y軸中心で回転し、z軸を x軸になるように変換。
217
- # self.rotate_axis!(1, 0.5*PI)
218
- def rotate_axis!(axis, radian)
219
- raise RangeError, "Axis id is #{axis}." if (axis < 0 || 2 < axis)
220
- #axis1, axis2 はそれぞれ、 x軸から見て y軸, z軸。y に対する z, x。z に対する x, y。
221
- axis1 = (axis + 1) % 3
222
- axis2 = (axis + 2) % 3
223
-
224
- tmp = Array.new(3)
225
- tmp[ axis ] = self[ axis ]
226
- tmp[ axis1 ] = Math::cos(radian) * self[ axis1 ] - Math::sin(radian) * self[ axis2 ]
227
- tmp[ axis2 ] = Math::sin(radian) * self[ axis1 ] + Math::cos(radian) * self[ axis2 ]
228
- tmp.to_v3d
229
- self[0] = tmp[0]
230
- self[1] = tmp[1]
231
- self[2] = tmp[2]
232
- end
233
-
234
- #x, y, z 軸のいずれかで self を回転した座標を返す。非破壊的。
235
- #axis は 0, 1, 2 のいずれかで、それぞれ x, y, z軸を示す。
236
- #radian は回転する角度で、原点から軸の伸びる方向に対して右ねじ方向を正とする。
237
- #すなわち、軸の正の値の位置から原点を見たとき、左回りが正である。
238
- #e.g., y軸中心で回転し、z軸を x軸になるように変換。
239
- # self.rotate_axis(1, 0.5*PI)
240
- def rotate_axis(axis, radian)
241
- tmp = Marshal.load(Marshal.dump(self))
242
- tmp.rotate_axis!(axis, radian)
243
- tmp
244
- end
245
-
49
+ class TypeError < Exception; end
50
+ class ZeroOperation < Exception; end
51
+ class RangeError < Exception; end
52
+
53
+ # Class methods
54
+
55
+ def self.[](*args)
56
+ raise RangeError, "#{args}" unless args.size == 3
57
+ super(*args)
58
+ end
59
+
60
+ # Get the exterior product.
61
+ def self.exterior_product(vec0, vec1)
62
+ [vec0, vec1].each_with_index do |vec, index|
63
+ unless (vec.class == Vector3D)
64
+ raise TypeError, "Vector #{index}, #{vec.inspect}."
65
+ end
66
+ end
67
+
68
+ bX = vec1[0];
69
+ bY = vec1[1];
70
+ bZ = vec1[2];
71
+
72
+ cX = (vec0[1] * bZ - vec0[2] * bY);
73
+ cY = (vec0[2] * bX - vec0[0] * bZ);
74
+ cZ = (vec0[0] * bY - vec0[1] * bX);
75
+
76
+ self[cX, cY, cZ]
77
+ end
78
+ class << self
79
+ alias :cross_product :exterior_product
80
+ alias :vector_product :exterior_product
81
+ end
82
+
83
+ # Get the scalar triple product.
84
+ def self.scalar_triple_product(vec0, vec1, vec2)
85
+ [vec0, vec1, vec2].each_with_index do |vec, index|
86
+ raise TypeError, "#{index}th vector: #{vec.inspect}" unless (vec.class == Vector3D)
87
+ end
88
+
89
+ vec0.inner_product(vec1.exterior_product(vec2))
90
+ end
91
+
92
+ # Get the angle with radian between self and other vectors.
93
+ def self.angle_radian(vec0, vec1)
94
+ [vec0, vec1].each_with_index do |vec, index|
95
+ raise TypeError, "#{index}th vector: #{vec.inspect}" unless (vec.class == Vector3D)
96
+ raise ZeroOperation, "#{index}th vector: #{vec.inspect}" if (vec.r == 0.0)
97
+ end
98
+
99
+ Math::acos(vec0.inner_product(vec1) / (vec0.r * vec1.r))
100
+ end
101
+
102
+ # Get the angle with degree between self and other vectors.
103
+ def self.angle_degree(vec0, vec1)
104
+ [vec0, vec1].each_with_index do |vec, index|
105
+ raise TypeError, "#{index}th vector: #{vec.inspect}" unless (vec.class == Vector3D)
106
+ raise ZeroOperation, "#{index}th vector: #{vec.inspect}" if (vec.r == 0.0)
107
+ end
108
+
109
+ self.angle_radian(vec0, vec1) * (180.0 / Math::PI)
110
+ end
111
+
112
+ # Instance methods
113
+
114
+ def [](index)
115
+ raise RangeError, "index: #{index}." if (index < 0 || 2 < index)
116
+ super index
117
+ end
118
+
119
+ def []=(index, val)
120
+ raise RangeError, "index: #{index}." if (index < 0 || 2 < index)
121
+ super index, val
122
+ end
123
+
124
+
125
+ # ベクトルが等しいかチェック。
126
+ # other として Vector3D クラス以外のインスタンス渡すと Vector3D::TypeError。
127
+ # 両者の差分ベクトルの長さが tolerance 以下という判定になる。
128
+ def equal_in_delta?(other, tolerance = 0.0)
129
+ raise TypeError if (other.class != Vector3D)
130
+ return (other - self).r <= tolerance
131
+ end
132
+
133
+ # Vectorクラスで用意されているメソッドは Vectorクラスインスタンスを返すようになっているので、
134
+ # Vector3D クラスインスタンスを返すようにした + メソッド。
135
+ def +(vec)
136
+ unless (vec.class == Vector3D)
137
+ raise TypeError, "#{vec.inspect}."
138
+ end
139
+ super(vec).to_v3d
140
+ end
141
+
142
+ # Vectorクラスで用意されているメソッドは Vectorクラスインスタンスを返すようになっているので、
143
+ # Vector3D クラスインスタンスを返すようにした - メソッド。
144
+ def -(vec)
145
+ unless (vec.class == Vector3D)
146
+ raise TypeError, "#{vec.inspect}."
147
+ end
148
+ super(vec).to_v3d
149
+ end
150
+
151
+ # Vectorクラスで用意されているメソッドは Vectorクラスインスタンスを返すようになっているので、
152
+ # Vector3D クラスインスタンスを返すようにした * メソッド。
153
+ # Argument 'val' must have :to_f method.
154
+ def *(val)
155
+ #raise TypeError if (val.class != Float)
156
+ raise TypeError unless val.methods.include?(:to_f)
157
+ super(val.to_f).to_v3d
158
+ end
159
+
160
+ # Vectorクラスで用意されているメソッドは Vectorクラスインスタンスを返すようになっているので、
161
+ # Vector3D クラスインスタンスを返すようにした clone メソッド。
162
+ def clone
163
+ super().to_v3d
164
+ end
165
+
166
+ # Convert to Vector3DInternal. Non-destructive.
167
+ def to_v3di(axes)
168
+ #pp axes.is_a?(Axes)
169
+ raise TypeError unless axes.is_a?(Axes)
170
+
171
+ axes = axes.to_a
172
+ Vector3DInternal[ *(Malge::SimultaneousEquations.cramer(axes.transpose, self)) ]
173
+ end
174
+
175
+ #Return size, always 3.
176
+ def size
177
+ return 3
178
+ end
179
+
180
+ # Get the exterior product.
181
+ def exterior_product(vec)
182
+ self.class.exterior_product(self, vec)
183
+ end
184
+ alias :cross_product :exterior_product
185
+ alias :vector_product :exterior_product
186
+
187
+ def scalar_triple_product(vec0, vec1)
188
+ self.class.scalar_triple_product(self, vec0, vec1)
189
+ end
190
+
191
+ def angle_radian(vec)
192
+ self.class.angle_radian(self, vec)
193
+ end
194
+
195
+ def angle_degree(vec)
196
+ self.class.angle_degree(self, vec)
197
+ end
198
+
199
+ #3次元極座標への変換した Polar3D インスタンスを返す。
200
+ def to_p3d
201
+ r = self.r
202
+ if r == 0.0
203
+ theta = 0.0
204
+ phi = 0.0
205
+ else
206
+ theta = Polar2D.minimum_radian(Math::acos(self[2] / r))
207
+ phi = Vector[ self[0], self[1] ].to_p2d.theta
208
+ end
209
+ Polar3D.new(r, theta, phi)
210
+ end
211
+
212
+ #x, y, z 軸のいずれかで self を回転する。破壊的。
213
+ #axis は 0, 1, 2 のいずれかで、それぞれ x, y, z軸を示す。
214
+ #radian は回転する角度で、原点から軸の伸びる方向に対して右ねじ方向を正とする。
215
+ #すなわち、軸の正の値の位置から原点を見たとき、左回りが正である。
216
+ #e.g., y軸中心で回転し、z軸を x軸になるように変換。
217
+ # self.rotate_axis!(1, 0.5*PI)
218
+ def rotate_axis!(axis, radian)
219
+ raise RangeError, "Axis id is #{axis}." if (axis < 0 || 2 < axis)
220
+ #axis1, axis2 はそれぞれ、 x軸から見て y軸, z軸。y に対する z, x。z に対する x, y。
221
+ axis1 = (axis + 1) % 3
222
+ axis2 = (axis + 2) % 3
223
+
224
+ tmp = Array.new(3)
225
+ tmp[ axis ] = self[ axis ]
226
+ tmp[ axis1 ] = Math::cos(radian) * self[ axis1 ] - Math::sin(radian) * self[ axis2 ]
227
+ tmp[ axis2 ] = Math::sin(radian) * self[ axis1 ] + Math::cos(radian) * self[ axis2 ]
228
+ tmp.to_v3d
229
+ self[0] = tmp[0]
230
+ self[1] = tmp[1]
231
+ self[2] = tmp[2]
232
+ end
233
+
234
+ #x, y, z 軸のいずれかで self を回転した座標を返す。非破壊的。
235
+ #axis は 0, 1, 2 のいずれかで、それぞれ x, y, z軸を示す。
236
+ #radian は回転する角度で、原点から軸の伸びる方向に対して右ねじ方向を正とする。
237
+ #すなわち、軸の正の値の位置から原点を見たとき、左回りが正である。
238
+ #e.g., y軸中心で回転し、z軸を x軸になるように変換。
239
+ # self.rotate_axis(1, 0.5*PI)
240
+ def rotate_axis(axis, radian)
241
+ tmp = Marshal.load(Marshal.dump(self))
242
+ tmp.rotate_axis!(axis, radian)
243
+ tmp
244
+ end
246
245
  end