rmath3d 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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