Subversion Repositories AndroidProjects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1452 chris 1
#region --- License ---
2
/*
3
Copyright (c) 2006 - 2008 The Open Toolkit library.
4
 
5
Permission is hereby granted, free of charge, to any person obtaining a copy of
6
this software and associated documentation files (the "Software"), to deal in
7
the Software without restriction, including without limitation the rights to
8
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
of the Software, and to permit persons to whom the Software is furnished to do
10
so, subject to the following conditions:
11
 
12
The above copyright notice and this permission notice shall be included in all
13
copies or substantial portions of the Software.
14
 
15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
SOFTWARE.
22
 */
23
#endregion
24
 
25
using System;
26
using System.Runtime.InteropServices;
27
 
28
namespace OpenTK.Math
29
{
30
    /// <summary>
31
    /// Represents a 4x4 Matrix with double-precision components.
32
    /// </summary>
33
    [Obsolete("OpenTK.Math functions have been moved to the root OpenTK namespace (reason: XNA compatibility")]
34
    [Serializable]
35
    [StructLayout(LayoutKind.Sequential)]
36
    public struct Matrix4d : IEquatable<Matrix4d>
37
    {
38
        #region Fields
39
 
40
        /// <summary>
41
        /// Top row of the matrix
42
        /// </summary>
43
        public Vector4d  Row0;
44
        /// <summary>
45
        /// 2nd row of the matrix
46
        /// </summary>
47
        public Vector4d  Row1;
48
        /// <summary>
49
        /// 3rd row of the matrix
50
        /// </summary>
51
        public Vector4d  Row2;
52
        /// <summary>
53
        /// Bottom row of the matrix
54
        /// </summary>
55
        public Vector4d  Row3;
56
 
57
        /// <summary>
58
        /// The identity matrix
59
        /// </summary>
60
        public static Matrix4d Identity = new Matrix4d(Vector4d .UnitX, Vector4d .UnitY, Vector4d .UnitZ, Vector4d .UnitW);
61
 
62
        #endregion
63
 
64
        #region Constructors
65
 
66
        /// <summary>
67
        /// Constructs a new instance.
68
        /// </summary>
69
        /// <param name="row0">Top row of the matrix</param>
70
        /// <param name="row1">Second row of the matrix</param>
71
        /// <param name="row2">Third row of the matrix</param>
72
        /// <param name="row3">Bottom row of the matrix</param>
73
        public Matrix4d(Vector4d row0, Vector4d row1, Vector4d row2, Vector4d row3)
74
        {
75
            Row0 = row0;
76
            Row1 = row1;
77
            Row2 = row2;
78
            Row3 = row3;
79
        }
80
 
81
        /// <summary>
82
        /// Constructs a new instance.
83
        /// </summary>
84
        /// <param name="m00">First item of the first row.</param>
85
        /// <param name="m01">Second item of the first row.</param>
86
        /// <param name="m02">Third item of the first row.</param>
87
        /// <param name="m03">Fourth item of the first row.</param>
88
        /// <param name="m10">First item of the second row.</param>
89
        /// <param name="m11">Second item of the second row.</param>
90
        /// <param name="m12">Third item of the second row.</param>
91
        /// <param name="m13">Fourth item of the second row.</param>
92
        /// <param name="m20">First item of the third row.</param>
93
        /// <param name="m21">Second item of the third row.</param>
94
        /// <param name="m22">Third item of the third row.</param>
95
        /// <param name="m23">First item of the third row.</param>
96
        /// <param name="m30">Fourth item of the fourth row.</param>
97
        /// <param name="m31">Second item of the fourth row.</param>
98
        /// <param name="m32">Third item of the fourth row.</param>
99
        /// <param name="m33">Fourth item of the fourth row.</param>
100
        public Matrix4d(
101
            float m00, float m01, float m02, float m03,
102
            float m10, float m11, float m12, float m13,
103
            float m20, float m21, float m22, float m23,
104
            float m30, float m31, float m32, float m33)
105
        {
106
            Row0 = new Vector4d(m00, m01, m02, m03);
107
            Row1 = new Vector4d(m10, m11, m12, m13);
108
            Row2 = new Vector4d(m20, m21, m22, m23);
109
            Row3 = new Vector4d(m30, m31, m32, m33);
110
        }
111
 
112
        #endregion
113
 
114
        #region Public Members
115
 
116
        #region Properties
117
 
118
        /// <summary>
119
        /// The determinant of this matrix
120
        /// </summary>
121
        public double Determinant
122
        {
123
            get
124
            {
125
                return
126
                    Row0.X * Row1.Y * Row2.Z * Row3.W - Row0.X * Row1.Y * Row2.W * Row3.Z + Row0.X * Row1.Z * Row2.W * Row3.Y - Row0.X * Row1.Z * Row2.Y * Row3.W
127
                  + Row0.X * Row1.W * Row2.Y * Row3.Z - Row0.X * Row1.W * Row2.Z * Row3.Y - Row0.Y * Row1.Z * Row2.W * Row3.X + Row0.Y * Row1.Z * Row2.X * Row3.W
128
                  - Row0.Y * Row1.W * Row2.X * Row3.Z + Row0.Y * Row1.W * Row2.Z * Row3.X - Row0.Y * Row1.X * Row2.Z * Row3.W + Row0.Y * Row1.X * Row2.W * Row3.Z
129
                  + Row0.Z * Row1.W * Row2.X * Row3.Y - Row0.Z * Row1.W * Row2.Y * Row3.X + Row0.Z * Row1.X * Row2.Y * Row3.W - Row0.Z * Row1.X * Row2.W * Row3.Y
130
                  + Row0.Z * Row1.Y * Row2.W * Row3.X - Row0.Z * Row1.Y * Row2.X * Row3.W - Row0.W * Row1.X * Row2.Y * Row3.Z + Row0.W * Row1.X * Row2.Z * Row3.Y
131
                  - Row0.W * Row1.Y * Row2.Z * Row3.X + Row0.W * Row1.Y * Row2.X * Row3.Z - Row0.W * Row1.Z * Row2.X * Row3.Y + Row0.W * Row1.Z * Row2.Y * Row3.X;
132
            }
133
        }
134
 
135
        /// <summary>
136
        /// The first column of this matrix
137
        /// </summary>
138
        public Vector4d  Column0
139
        {
140
            get { return new Vector4d (Row0.X, Row1.X, Row2.X, Row3.X); }
141
        }
142
 
143
        /// <summary>
144
        /// The second column of this matrix
145
        /// </summary>
146
        public Vector4d  Column1
147
        {
148
            get { return new Vector4d (Row0.Y, Row1.Y, Row2.Y, Row3.Y); }
149
        }
150
 
151
        /// <summary>
152
        /// The third column of this matrix
153
        /// </summary>
154
        public Vector4d  Column2
155
        {
156
            get { return new Vector4d (Row0.Z, Row1.Z, Row2.Z, Row3.Z); }
157
        }
158
 
159
        /// <summary>
160
        /// The fourth column of this matrix
161
        /// </summary>
162
        public Vector4d  Column3
163
        {
164
            get { return new Vector4d (Row0.W, Row1.W, Row2.W, Row3.W); }
165
        }
166
 
167
        public double this[int i, int j]
168
        {
169
            get
170
            {
171
                if (i < 0 || i > 3)
172
                    throw new ArgumentOutOfRangeException("i");
173
 
174
                if (j < 0 || j > 3)
175
                    throw new ArgumentOutOfRangeException("j");
176
 
177
                unsafe
178
                {
179
                    fixed (Matrix4d* ptr = &this)
180
                        return *((double*)ptr + i + j * 4);
181
                }
182
            }
183
            set
184
            {
185
                if (i < 0 || i > 3)
186
                    throw new ArgumentOutOfRangeException("i");
187
 
188
                if (j < 0 || j > 3)
189
                    throw new ArgumentOutOfRangeException("j");
190
 
191
                unsafe
192
                {
193
                    fixed (Matrix4d* ptr = &this)
194
                        *((double*)ptr + i + j * 4) = value;
195
                }
196
            }
197
        }
198
 
199
        /// <summary>
200
        /// Gets or sets the value at row 1, column 1 of this instance.
201
        /// </summary>
202
        public double M11 { get { return Row0.X; } set { Row0.X = value; } }
203
 
204
        /// <summary>
205
        /// Gets or sets the value at row 1, column 2 of this instance.
206
        /// </summary>
207
        public double M12 { get { return Row0.Y; } set { Row0.Y = value; } }
208
 
209
        /// <summary>
210
        /// Gets or sets the value at row 1, column 3 of this instance.
211
        /// </summary>
212
        public double M13 { get { return Row0.Z; } set { Row0.Z = value; } }
213
 
214
        /// <summary>
215
        /// Gets or sets the value at row 1, column 4 of this instance.
216
        /// </summary>
217
        public double M14 { get { return Row0.W; } set { Row0.W = value; } }
218
 
219
        /// <summary>
220
        /// Gets or sets the value at row 2, column 1 of this instance.
221
        /// </summary>
222
        public double M21 { get { return Row1.X; } set { Row1.X = value; } }
223
 
224
        /// <summary>
225
        /// Gets or sets the value at row 2, column 2 of this instance.
226
        /// </summary>
227
        public double M22 { get { return Row1.Y; } set { Row1.Y = value; } }
228
 
229
        /// <summary>
230
        /// Gets or sets the value at row 2, column 3 of this instance.
231
        /// </summary>
232
        public double M23 { get { return Row1.Z; } set { Row1.Z = value; } }
233
 
234
        /// <summary>
235
        /// Gets or sets the value at row 2, column 4 of this instance.
236
        /// </summary>
237
        public double M24 { get { return Row1.W; } set { Row1.W = value; } }
238
 
239
        /// <summary>
240
        /// Gets or sets the value at row 3, column 1 of this instance.
241
        /// </summary>
242
        public double M31 { get { return Row2.X; } set { Row2.X = value; } }
243
 
244
        /// <summary>
245
        /// Gets or sets the value at row 3, column 2 of this instance.
246
        /// </summary>
247
        public double M32 { get { return Row2.Y; } set { Row2.Y = value; } }
248
 
249
        /// <summary>
250
        /// Gets or sets the value at row 3, column 3 of this instance.
251
        /// </summary>
252
        public double M33 { get { return Row2.Z; } set { Row2.Z = value; } }
253
 
254
        /// <summary>
255
        /// Gets or sets the value at row 3, column 4 of this instance.
256
        /// </summary>
257
        public double M34 { get { return Row2.W; } set { Row2.W = value; } }
258
 
259
        /// <summary>
260
        /// Gets or sets the value at row 4, column 1 of this instance.
261
        /// </summary>
262
        public double M41 { get { return Row3.X; } set { Row3.X = value; } }
263
 
264
        /// <summary>
265
        /// Gets or sets the value at row 4, column 3 of this instance.
266
        /// </summary>
267
        public double M42 { get { return Row3.Y; } set { Row3.Y = value; } }
268
 
269
        /// <summary>
270
        /// Gets or sets the value at row 4, column 3 of this instance.
271
        /// </summary>
272
        public double M43 { get { return Row3.Z; } set { Row3.Z = value; } }
273
 
274
        /// <summary>
275
        /// Gets or sets the value at row 4, column 4 of this instance.
276
        /// </summary>
277
        public double M44 { get { return Row3.W; } set { Row3.W = value; } }
278
 
279
        #endregion
280
 
281
        #region Instance
282
 
283
        #region public void Invert()
284
 
285
        public void Invert()
286
        {
287
            this = Matrix4d.Invert(this);
288
        }
289
 
290
        #endregion
291
 
292
        #region public void Transpose()
293
 
294
        public void Transpose()
295
        {
296
            this = Matrix4d.Transpose(this);
297
        }
298
 
299
        #endregion
300
 
301
        #endregion
302
 
303
        #region Static
304
 
305
        #region CreateTranslation
306
 
307
        /// <summary>
308
        /// Creates a translation matrix.
309
        /// </summary>
310
        /// <param name="x">X translation.</param>
311
        /// <param name="y">Y translation.</param>
312
        /// <param name="z">Z translation.</param>
313
        /// <param name="result">The resulting Matrix4d instance.</param>
314
        public static void CreateTranslation(double x, double y, double z, out Matrix4d result)
315
        {
316
            result = Identity;
317
            result.Row3 = new Vector4d(x, y, z, 1);
318
        }
319
 
320
        /// <summary>
321
        /// Creates a translation matrix.
322
        /// </summary>
323
        /// <param name="vector">The translation vector.</param>
324
        /// <param name="result">The resulting Matrix4d instance.</param>
325
        public static void CreateTranslation(ref Vector3d vector, out Matrix4d result)
326
        {
327
            result = Identity;
328
            result.Row3 = new Vector4d(vector.X, vector.Y, vector.Z, 1);
329
        }
330
 
331
        /// <summary>
332
        /// Creates a translation matrix.
333
        /// </summary>
334
        /// <param name="x">X translation.</param>
335
        /// <param name="y">Y translation.</param>
336
        /// <param name="z">Z translation.</param>
337
        /// <returns>The resulting Matrix4d instance.</returns>
338
        public static Matrix4d CreateTranslation(double x, double y, double z)
339
        {
340
            Matrix4d result;
341
            CreateTranslation(x, y, z, out result);
342
            return result;
343
        }
344
 
345
        /// <summary>
346
        /// Creates a translation matrix.
347
        /// </summary>
348
        /// <param name="vector">The translation vector.</param>
349
        /// <returns>The resulting Matrix4d instance.</returns>
350
        public static Matrix4d CreateTranslation(Vector3d vector)
351
        {
352
            Matrix4d result;
353
            CreateTranslation(vector.X, vector.Y, vector.Z, out result);
354
            return result;
355
        }
356
 
357
        #endregion
358
 
359
        #region CreateOrthographic
360
 
361
        /// <summary>
362
        /// Creates an orthographic projection matrix.
363
        /// </summary>
364
        /// <param name="width">The width of the projection volume.</param>
365
        /// <param name="height">The height of the projection volume.</param>
366
        /// <param name="zNear">The near edge of the projection volume.</param>
367
        /// <param name="zFar">The far edge of the projection volume.</param>
368
        /// <param name="result">The resulting Matrix4d instance.</param>
369
        public static void CreateOrthographic(double width, double height, double zNear, double zFar, out Matrix4d result)
370
        {
371
            CreateOrthographicOffCenter(-width / 2, width / 2, -height / 2, height / 2, zNear, zFar, out result);
372
        }
373
 
374
        /// <summary>
375
        /// Creates an orthographic projection matrix.
376
        /// </summary>
377
        /// <param name="width">The width of the projection volume.</param>
378
        /// <param name="height">The height of the projection volume.</param>
379
        /// <param name="zNear">The near edge of the projection volume.</param>
380
        /// <param name="zFar">The far edge of the projection volume.</param>
381
        /// <rereturns>The resulting Matrix4d instance.</rereturns>
382
        public static Matrix4d CreateOrthographic(double width, double height, double zNear, double zFar)
383
        {
384
            Matrix4d result;
385
            CreateOrthographicOffCenter(-width / 2, width / 2, -height / 2, height / 2, zNear, zFar, out result);
386
            return result;
387
        }
388
 
389
        #endregion
390
 
391
        #region CreateOrthographicOffCenter
392
 
393
        /// <summary>
394
        /// Creates an orthographic projection matrix.
395
        /// </summary>
396
        /// <param name="left">The left edge of the projection volume.</param>
397
        /// <param name="right">The right edge of the projection volume.</param>
398
        /// <param name="bottom">The bottom edge of the projection volume.</param>
399
        /// <param name="top">The top edge of the projection volume.</param>
400
        /// <param name="zNear">The near edge of the projection volume.</param>
401
        /// <param name="zFar">The far edge of the projection volume.</param>
402
        /// <param name="result">The resulting Matrix4d instance.</param>
403
        public static void CreateOrthographicOffCenter(double left, double right, double bottom, double top, double zNear, double zFar, out Matrix4d result)
404
        {
405
            result = new Matrix4d();
406
 
407
            double invRL = 1 / (right - left);
408
            double invTB = 1 / (top - bottom);
409
            double invFN = 1 / (zFar - zNear);
410
 
411
            result.M11 = 2 * invRL;
412
            result.M22 = 2 * invTB;
413
            result.M33 = -2 * invFN;
414
 
415
            result.M41 = -(right + left) * invRL;
416
            result.M42 = -(top + bottom) * invTB;
417
            result.M43 = -(zFar + zNear) * invFN;
418
        }
419
 
420
        /// <summary>
421
        /// Creates an orthographic projection matrix.
422
        /// </summary>
423
        /// <param name="left">The left edge of the projection volume.</param>
424
        /// <param name="right">The right edge of the projection volume.</param>
425
        /// <param name="bottom">The bottom edge of the projection volume.</param>
426
        /// <param name="top">The top edge of the projection volume.</param>
427
        /// <param name="zNear">The near edge of the projection volume.</param>
428
        /// <param name="zFar">The far edge of the projection volume.</param>
429
        /// <returns>The resulting Matrix4d instance.</returns>
430
        public static Matrix4d CreateOrthographicOffCenter(double left, double right, double bottom, double top, double zNear, double zFar)
431
        {
432
            Matrix4d result;
433
            CreateOrthographicOffCenter(left, right, bottom, top, zNear, zFar, out result);
434
            return result;
435
        }
436
 
437
        #endregion
438
 
439
        #region Obsolete Functions
440
 
441
        #region Translation Functions
442
 
443
        /// <summary>
444
        /// Build a translation matrix with the given translation
445
        /// </summary>
446
        /// <param name="trans">The vector to translate along</param>
447
        /// <returns>A Translation matrix</returns>
448
        [Obsolete("Use CreateTranslation instead.")]
449
        public static Matrix4d Translation(Vector3d trans)
450
        {
451
            return Translation(trans.X, trans.Y, trans.Z);
452
        }
453
 
454
        /// <summary>
455
        /// Build a translation matrix with the given translation
456
        /// </summary>
457
        /// <param name="x">X translation</param>
458
        /// <param name="y">Y translation</param>
459
        /// <param name="z">Z translation</param>
460
        /// <returns>A Translation matrix</returns>
461
        [Obsolete("Use CreateTranslation instead.")]
462
        public static Matrix4d Translation(double x, double y, double z)
463
        {
464
            Matrix4d result = Identity;
465
            result.Row3 = new Vector4d(x, y, z, 1.0f);
466
            return result;
467
        }
468
 
469
        #endregion
470
 
471
        #endregion
472
 
473
        #region Scale Functions
474
 
475
        /// <summary>
476
        /// Build a scaling matrix
477
        /// </summary>
478
        /// <param name="scale">Single scale factor for x,y and z axes</param>
479
        /// <returns>A scaling matrix</returns>
480
        public static Matrix4d Scale(double scale)
481
        {
482
            return Scale(scale, scale, scale);
483
        }
484
 
485
        /// <summary>
486
        /// Build a scaling matrix
487
        /// </summary>
488
        /// <param name="scale">Scale factors for x,y and z axes</param>
489
        /// <returns>A scaling matrix</returns>
490
        public static Matrix4d Scale(Vector3d scale)
491
        {
492
            return Scale(scale.X, scale.Y, scale.Z);
493
        }
494
 
495
        /// <summary>
496
        /// Build a scaling matrix
497
        /// </summary>
498
        /// <param name="x">Scale factor for x-axis</param>
499
        /// <param name="y">Scale factor for y-axis</param>
500
        /// <param name="z">Scale factor for z-axis</param>
501
        /// <returns>A scaling matrix</returns>
502
        public static Matrix4d Scale(double x, double y, double z)
503
        {
504
            Matrix4d result;
505
            result.Row0 = Vector4d .UnitX * x;
506
            result.Row1 = Vector4d .UnitY * y;
507
            result.Row2 = Vector4d .UnitZ * z;
508
            result.Row3 = Vector4d .UnitW;
509
            return result;
510
        }
511
 
512
        #endregion
513
 
514
        #region Rotation Functions
515
 
516
        /// <summary>
517
        /// Build a rotation matrix that rotates about the x-axis
518
        /// </summary>
519
        /// <param name="angle">angle in radians to rotate counter-clockwise around the x-axis</param>
520
        /// <returns>A rotation matrix</returns>
521
        public static Matrix4d RotateX(double angle)
522
        {
523
            double cos = (double)System.Math.Cos(angle);
524
            double sin = (double)System.Math.Sin(angle);
525
 
526
            Matrix4d result;
527
            result.Row0 = Vector4d .UnitX;
528
            result.Row1 = new Vector4d (0.0f, cos, sin, 0.0f);
529
            result.Row2 = new Vector4d (0.0f, -sin, cos, 0.0f);
530
            result.Row3 = Vector4d .UnitW;
531
            return result;
532
        }
533
 
534
        /// <summary>
535
        /// Build a rotation matrix that rotates about the y-axis
536
        /// </summary>
537
        /// <param name="angle">angle in radians to rotate counter-clockwise around the y-axis</param>
538
        /// <returns>A rotation matrix</returns>
539
        public static Matrix4d RotateY(double angle)
540
        {
541
            double cos = (double)System.Math.Cos(angle);
542
            double sin = (double)System.Math.Sin(angle);
543
 
544
            Matrix4d result;
545
            result.Row0 = new Vector4d (cos, 0.0f, -sin, 0.0f);
546
            result.Row1 = Vector4d .UnitY;
547
            result.Row2 = new Vector4d (sin, 0.0f, cos, 0.0f);
548
            result.Row3 = Vector4d .UnitW;
549
            return result;
550
        }
551
 
552
        /// <summary>
553
        /// Build a rotation matrix that rotates about the z-axis
554
        /// </summary>
555
        /// <param name="angle">angle in radians to rotate counter-clockwise around the z-axis</param>
556
        /// <returns>A rotation matrix</returns>
557
        public static Matrix4d RotateZ(double angle)
558
        {
559
            double cos = (double)System.Math.Cos(angle);
560
            double sin = (double)System.Math.Sin(angle);
561
 
562
            Matrix4d result;
563
            result.Row0 = new Vector4d (cos, sin, 0.0f, 0.0f);
564
            result.Row1 = new Vector4d (-sin, cos, 0.0f, 0.0f);
565
            result.Row2 = Vector4d .UnitZ;
566
            result.Row3 = Vector4d .UnitW;
567
            return result;
568
        }
569
 
570
        /// <summary>
571
        /// Build a rotation matrix to rotate about the given axis
572
        /// </summary>
573
        /// <param name="axis">the axis to rotate about</param>
574
        /// <param name="angle">angle in radians to rotate counter-clockwise (looking in the direction of the given axis)</param>
575
        /// <returns>A rotation matrix</returns>
576
        public static Matrix4d Rotate(Vector3d axis, double angle)
577
        {
578
            double cos = (double)System.Math.Cos(-angle);
579
            double sin = (double)System.Math.Sin(-angle);
580
            double t = 1.0f - cos;
581
 
582
            axis.Normalize();
583
 
584
            Matrix4d result;
585
            result.Row0 = new Vector4d (t * axis.X * axis.X + cos, t * axis.X * axis.Y - sin * axis.Z, t * axis.X * axis.Z + sin * axis.Y, 0.0f);
586
            result.Row1 = new Vector4d (t * axis.X * axis.Y + sin * axis.Z, t * axis.Y * axis.Y + cos, t * axis.Y * axis.Z - sin * axis.X, 0.0f);
587
            result.Row2 = new Vector4d (t * axis.X * axis.Z - sin * axis.Y, t * axis.Y * axis.Z + sin * axis.X, t * axis.Z * axis.Z + cos, 0.0f);
588
            result.Row3 = Vector4d .UnitW;
589
            return result;
590
        }
591
 
592
        /// <summary>
593
        /// Build a rotation matrix from a quaternion
594
        /// </summary>
595
        /// <param name="q">the quaternion</param>
596
        /// <returns>A rotation matrix</returns>
597
        public static Matrix4d Rotate(Quaterniond q)
598
        {
599
            Vector3d axis;
600
            double angle;
601
            q.ToAxisAngle(out axis, out angle);
602
            return Rotate(axis, angle);
603
        }
604
 
605
        #endregion
606
 
607
        #region Camera Helper Functions
608
 
609
        /// <summary>
610
        /// Build a world space to camera space matrix
611
        /// </summary>
612
        /// <param name="eye">Eye (camera) position in world space</param>
613
        /// <param name="target">Target position in world space</param>
614
        /// <param name="up">Up vector in world space (should not be parallel to the camera direction, that is target - eye)</param>
615
        /// <returns>A Matrix that transforms world space to camera space</returns>
616
        public static Matrix4d LookAt(Vector3d eye, Vector3d target, Vector3d up)
617
        {
618
            Vector3d z = Vector3d.Normalize(eye - target);
619
            Vector3d x = Vector3d.Normalize(Vector3d.Cross(up, z));
620
            Vector3d y = Vector3d.Normalize(Vector3d.Cross(z, x));
621
 
622
            Matrix4d rot = new Matrix4d(new Vector4d (x.X, y.X, z.X, 0.0f),
623
                                        new Vector4d (x.Y, y.Y, z.Y, 0.0f),
624
                                        new Vector4d (x.Z, y.Z, z.Z, 0.0f),
625
                                        Vector4d .UnitW);
626
 
627
            Matrix4d trans = Matrix4d.CreateTranslation(-eye);
628
 
629
            return trans * rot;
630
        }
631
 
632
        /// <summary>
633
        /// Build a world space to camera space matrix
634
        /// </summary>
635
        /// <param name="eyeX">Eye (camera) position in world space</param>
636
        /// <param name="eyeY">Eye (camera) position in world space</param>
637
        /// <param name="eyeZ">Eye (camera) position in world space</param>
638
        /// <param name="targetX">Target position in world space</param>
639
        /// <param name="targetY">Target position in world space</param>
640
        /// <param name="targetZ">Target position in world space</param>
641
        /// <param name="upX">Up vector in world space (should not be parallel to the camera direction, that is target - eye)</param>
642
        /// <param name="upY">Up vector in world space (should not be parallel to the camera direction, that is target - eye)</param>
643
        /// <param name="upZ">Up vector in world space (should not be parallel to the camera direction, that is target - eye)</param>
644
        /// <returns>A Matrix4 that transforms world space to camera space</returns>
645
        public static Matrix4d LookAt(double eyeX, double eyeY, double eyeZ, double targetX, double targetY, double targetZ, double upX, double upY, double upZ)
646
        {
647
            return LookAt(new Vector3d(eyeX, eyeY, eyeZ), new Vector3d(targetX, targetY, targetZ), new Vector3d(upX, upY, upZ));
648
        }
649
 
650
        /// <summary>
651
        /// Build a projection matrix
652
        /// </summary>
653
        /// <param name="left">Left edge of the view frustum</param>
654
        /// <param name="right">Right edge of the view frustum</param>
655
        /// <param name="bottom">Bottom edge of the view frustum</param>
656
        /// <param name="top">Top edge of the view frustum</param>
657
        /// <param name="near">Distance to the near clip plane</param>
658
        /// <param name="far">Distance to the far clip plane</param>
659
        /// <returns>A projection matrix that transforms camera space to raster space</returns>
660
        public static Matrix4d Frustum(double left, double right, double bottom, double top, double near, double far)
661
        {
662
            double invRL = 1.0f / (right - left);
663
            double invTB = 1.0f / (top - bottom);
664
            double invFN = 1.0f / (far - near);
665
            return new Matrix4d(new Vector4d (2.0f * near * invRL, 0.0f, 0.0f, 0.0f),
666
                               new Vector4d (0.0f, 2.0f * near * invTB, 0.0f, 0.0f),
667
                               new Vector4d ((right + left) * invRL, (top + bottom) * invTB, -(far + near) * invFN, -1.0f),
668
                               new Vector4d (0.0f, 0.0f, -2.0f * far * near * invFN, 0.0f));
669
        }
670
 
671
        /// <summary>
672
        /// Build a projection matrix
673
        /// </summary>
674
        /// <param name="fovy">Angle of the field of view in the y direction (in radians)</param>
675
        /// <param name="aspect">Aspect ratio of the view (width / height)</param>
676
        /// <param name="near">Distance to the near clip plane</param>
677
        /// <param name="far">Distance to the far clip plane</param>
678
        /// <returns>A projection matrix that transforms camera space to raster space</returns>
679
        public static Matrix4d Perspective(double fovy, double aspect, double near, double far)
680
        {
681
            double yMax = near * (double)System.Math.Tan(0.5f * fovy);
682
            double yMin = -yMax;
683
            double xMin = yMin * aspect;
684
            double xMax = yMax * aspect;
685
 
686
            return Frustum(xMin, xMax, yMin, yMax, near, far);
687
        }
688
 
689
        #endregion
690
 
691
        #region Multiply Functions
692
 
693
        /// <summary>
694
        /// Multiplies two instances.
695
        /// </summary>
696
        /// <param name="left">The left operand of the multiplication.</param>
697
        /// <param name="right">The right operand of the multiplication.</param>
698
        /// <returns>A new instance that is the result of the multiplication</returns>
699
        public static Matrix4d Mult(Matrix4d left, Matrix4d right)
700
        {
701
            Matrix4d result;
702
            Mult(ref left, ref right, out result);
703
            return result;
704
        }
705
 
706
        /// <summary>
707
        /// Multiplies two instances.
708
        /// </summary>
709
        /// <param name="left">The left operand of the multiplication.</param>
710
        /// <param name="right">The right operand of the multiplication.</param>
711
        /// <param name="result">A new instance that is the result of the multiplication</param>
712
        public static void Mult(ref Matrix4d left, ref Matrix4d right, out Matrix4d result)
713
        {
714
            result = new Matrix4d();
715
            result.M11 = left.M11 * right.M11 + left.M12 * right.M21 + left.M13 * right.M31 + left.M14 * right.M41;
716
            result.M12 = left.M11 * right.M12 + left.M12 * right.M22 + left.M13 * right.M32 + left.M14 * right.M42;
717
            result.M13 = left.M11 * right.M13 + left.M12 * right.M23 + left.M13 * right.M33 + left.M14 * right.M43;
718
            result.M14 = left.M11 * right.M14 + left.M12 * right.M24 + left.M13 * right.M34 + left.M14 * right.M44;
719
            result.M21 = left.M21 * right.M11 + left.M22 * right.M21 + left.M23 * right.M31 + left.M24 * right.M41;
720
            result.M22 = left.M21 * right.M12 + left.M22 * right.M22 + left.M23 * right.M32 + left.M24 * right.M42;
721
            result.M23 = left.M21 * right.M13 + left.M22 * right.M23 + left.M23 * right.M33 + left.M24 * right.M43;
722
            result.M24 = left.M21 * right.M14 + left.M22 * right.M24 + left.M23 * right.M34 + left.M24 * right.M44;
723
            result.M31 = left.M31 * right.M11 + left.M32 * right.M21 + left.M33 * right.M31 + left.M34 * right.M41;
724
            result.M32 = left.M31 * right.M12 + left.M32 * right.M22 + left.M33 * right.M32 + left.M34 * right.M42;
725
            result.M33 = left.M31 * right.M13 + left.M32 * right.M23 + left.M33 * right.M33 + left.M34 * right.M43;
726
            result.M34 = left.M31 * right.M14 + left.M32 * right.M24 + left.M33 * right.M34 + left.M34 * right.M44;
727
            result.M41 = left.M41 * right.M11 + left.M42 * right.M21 + left.M43 * right.M31 + left.M44 * right.M41;
728
            result.M42 = left.M41 * right.M12 + left.M42 * right.M22 + left.M43 * right.M32 + left.M44 * right.M42;
729
            result.M43 = left.M41 * right.M13 + left.M42 * right.M23 + left.M43 * right.M33 + left.M44 * right.M43;
730
            result.M44 = left.M41 * right.M14 + left.M42 * right.M24 + left.M43 * right.M34 + left.M44 * right.M44;
731
        }
732
 
733
        #endregion
734
 
735
        #region Invert Functions
736
 
737
        /// <summary>
738
        /// Calculate the inverse of the given matrix
739
        /// </summary>
740
        /// <param name="mat">The matrix to invert</param>
741
        /// <returns>The inverse of the given matrix if it has one, or the input if it is singular</returns>
742
        /// <exception cref="InvalidOperationException">Thrown if the Matrix4d is singular.</exception>
743
        public static Matrix4d Invert(Matrix4d mat)
744
        {
745
            int[] colIdx = { 0, 0, 0, 0 };
746
            int[] rowIdx = { 0, 0, 0, 0 };
747
            int[] pivotIdx = { -1, -1, -1, -1 };
748
 
749
            // convert the matrix to an array for easy looping
750
            double[,] inverse = {{mat.Row0.X, mat.Row0.Y, mat.Row0.Z, mat.Row0.W},
751
                                {mat.Row1.X, mat.Row1.Y, mat.Row1.Z, mat.Row1.W},
752
                                {mat.Row2.X, mat.Row2.Y, mat.Row2.Z, mat.Row2.W},
753
                                {mat.Row3.X, mat.Row3.Y, mat.Row3.Z, mat.Row3.W} };
754
            int icol = 0;
755
            int irow = 0;
756
            for (int i = 0; i < 4; i++)
757
            {
758
                // Find the largest pivot value
759
                double maxPivot = 0.0f;
760
                for (int j = 0; j < 4; j++)
761
                {
762
                    if (pivotIdx[j] != 0)
763
                    {
764
                        for (int k = 0; k < 4; ++k)
765
                        {
766
                            if (pivotIdx[k] == -1)
767
                            {
768
                                double absVal = System.Math.Abs(inverse[j, k]);
769
                                if (absVal > maxPivot)
770
                                {
771
                                    maxPivot = absVal;
772
                                    irow = j;
773
                                    icol = k;
774
                                }
775
                            }
776
                            else if (pivotIdx[k] > 0)
777
                            {
778
                                return mat;
779
                            }
780
                        }
781
                    }
782
                }
783
 
784
                ++(pivotIdx[icol]);
785
 
786
                // Swap rows over so pivot is on diagonal
787
                if (irow != icol)
788
                {
789
                    for (int k = 0; k < 4; ++k)
790
                    {
791
                        double f = inverse[irow, k];
792
                        inverse[irow, k] = inverse[icol, k];
793
                        inverse[icol, k] = f;
794
                    }
795
                }
796
 
797
                rowIdx[i] = irow;
798
                colIdx[i] = icol;
799
 
800
                double pivot = inverse[icol, icol];
801
                // check for singular matrix
802
                if (pivot == 0.0f)
803
                {
804
                    throw new InvalidOperationException("Matrix is singular and cannot be inverted.");
805
                    //return mat;
806
                }
807
 
808
                // Scale row so it has a unit diagonal
809
                double oneOverPivot = 1.0f / pivot;
810
                inverse[icol, icol] = 1.0f;
811
                for (int k = 0; k < 4; ++k)
812
                    inverse[icol, k] *= oneOverPivot;
813
 
814
                // Do elimination of non-diagonal elements
815
                for (int j = 0; j < 4; ++j)
816
                {
817
                    // check this isn't on the diagonal
818
                    if (icol != j)
819
                    {
820
                        double f = inverse[j, icol];
821
                        inverse[j, icol] = 0.0f;
822
                        for (int k = 0; k < 4; ++k)
823
                            inverse[j, k] -= inverse[icol, k] * f;
824
                    }
825
                }
826
            }
827
 
828
            for (int j = 3; j >= 0; --j)
829
            {
830
                int ir = rowIdx[j];
831
                int ic = colIdx[j];
832
                for (int k = 0; k < 4; ++k)
833
                {
834
                    double f = inverse[k, ir];
835
                    inverse[k, ir] = inverse[k, ic];
836
                    inverse[k, ic] = f;
837
                }
838
            }
839
 
840
            mat.Row0 = new Vector4d (inverse[0, 0], inverse[0, 1], inverse[0, 2], inverse[0, 3]);
841
            mat.Row1 = new Vector4d (inverse[1, 0], inverse[1, 1], inverse[1, 2], inverse[1, 3]);
842
            mat.Row2 = new Vector4d (inverse[2, 0], inverse[2, 1], inverse[2, 2], inverse[2, 3]);
843
            mat.Row3 = new Vector4d (inverse[3, 0], inverse[3, 1], inverse[3, 2], inverse[3, 3]);
844
            return mat;
845
        }
846
 
847
        #endregion
848
 
849
        #region Transpose
850
 
851
        /// <summary>
852
        /// Calculate the transpose of the given matrix
853
        /// </summary>
854
        /// <param name="mat">The matrix to transpose</param>
855
        /// <returns>The transpose of the given matrix</returns>
856
        public static Matrix4d Transpose(Matrix4d mat)
857
        {
858
            return new Matrix4d(mat.Column0, mat.Column1, mat.Column2, mat.Column3);
859
        }
860
 
861
 
862
        /// <summary>
863
        /// Calculate the transpose of the given matrix
864
        /// </summary>
865
        /// <param name="mat">The matrix to transpose</param>
866
        /// <param name="result">The result of the calculation</param>
867
        public static void Transpose(ref Matrix4d mat, out Matrix4d result)
868
        {
869
            result.Row0 = mat.Column0;
870
            result.Row1 = mat.Column1;
871
            result.Row2 = mat.Column2;
872
            result.Row3 = mat.Column3;
873
        }
874
 
875
        #endregion
876
 
877
        #endregion
878
 
879
        #region Operators
880
 
881
        /// <summary>
882
        /// Matrix multiplication
883
        /// </summary>
884
        /// <param name="left">left-hand operand</param>
885
        /// <param name="right">right-hand operand</param>
886
        /// <returns>A new Matrix44 which holds the result of the multiplication</returns>
887
        public static Matrix4d operator *(Matrix4d left, Matrix4d right)
888
        {
889
            return Matrix4d.Mult(left, right);
890
        }
891
 
892
        public static bool operator ==(Matrix4d left, Matrix4d right)
893
        {
894
            return left.Equals(right);
895
        }
896
 
897
        public static bool operator !=(Matrix4d left, Matrix4d right)
898
        {
899
            return !left.Equals(right);
900
        }
901
 
902
        #endregion
903
 
904
        #region Overrides
905
 
906
        #region public override string ToString()
907
 
908
        /// <summary>
909
        /// Returns a System.String that represents the current Matrix44.
910
        /// </summary>
911
        /// <returns></returns>
912
        public override string ToString()
913
        {
914
            return String.Format("{0}\n{1}\n{2}\n{3}", Row0, Row1, Row2, Row3);
915
        }
916
 
917
        #endregion
918
 
919
        #region public override int GetHashCode()
920
 
921
        /// <summary>
922
        /// Returns the hashcode for this instance.
923
        /// </summary>
924
        /// <returns>A System.Int32 containing the unique hashcode for this instance.</returns>
925
        public override int GetHashCode()
926
        {
927
            return Row0.GetHashCode() ^ Row1.GetHashCode() ^ Row2.GetHashCode() ^ Row3.GetHashCode();
928
        }
929
 
930
        #endregion
931
 
932
        #region public override bool Equals(object obj)
933
 
934
        /// <summary>
935
        /// Indicates whether this instance and a specified object are equal.
936
        /// </summary>
937
        /// <param name="obj">The object to compare to.</param>
938
        /// <returns>True if the instances are equal; false otherwise.</returns>
939
        public override bool Equals(object obj)
940
        {
941
            if (!(obj is Matrix4d))
942
                return false;
943
 
944
            return this.Equals((Matrix4d)obj);
945
        }
946
 
947
        #endregion
948
 
949
        #endregion
950
 
951
        #endregion
952
 
953
        #region IEquatable<Matrix4d> Members
954
 
955
        /// <summary>Indicates whether the current matrix is equal to another matrix.</summary>
956
        /// <param name="other">An matrix to compare with this matrix.</param>
957
        /// <returns>true if the current matrix is equal to the matrix parameter; otherwise, false.</returns>
958
        public bool Equals(Matrix4d other)
959
        {
960
            return
961
                Row0 == other.Row0 &&
962
                Row1 == other.Row1 &&
963
                Row2 == other.Row2 &&
964
                Row3 == other.Row3;
965
        }
966
 
967
        #endregion
968
    }
969
}