1 /**
2  * Contains the definition of a 3x3 matrix of doubles, and associated functions to transform
3  * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this:
4  * <p>
5  *      m00  m10  m20<br>
6  *      m01  m11  m21<br>
7  *      m02  m12  m22<br>
8  * 
9  * @author Richard Greenlees
10  * @author Kai Burjack
11  */
12 module doml.matrix_3d;
13 
14 import Math = doml.math;
15 import MemUtil = doml.mem_util;
16 
17 import doml.matrix_2d;
18 import doml.matrix_4d;
19 import doml.matrix_4x3d;
20 
21 import doml.vector_3d;
22 
23 import doml.axis_angle_4d;
24 import doml.quaternion_d;
25 
26 /*
27  * The MIT License
28  *
29  * Copyright (c) 2015-2021 Richard Greenlees
30  #$@$!$ Translated by jordan4ibanez
31  *
32  * Permission is hereby granted, free of charge, to any person obtaining a copy
33  * of this software and associated documentation files (the "Software"), to deal
34  * in the Software without restriction, including without limitation the rights
35  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
36  * copies of the Software, and to permit persons to whom the Software is
37  * furnished to do so, subject to the following conditions:
38  *
39  * The above copyright notice and this permission notice shall be included in
40  * all copies or substantial portions of the Software.
41  *
42  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
45  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
46  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
47  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
48  * THE SOFTWARE.
49  */
50 
51 
52 /**
53  * Contains the definition of a 3x3 matrix of doubles, and associated functions to transform
54  * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this:
55  * <p>
56  *      m00  m10  m20<br>
57  *      m01  m11  m21<br>
58  *      m02  m12  m22<br>
59  * 
60  * @author Richard Greenlees
61  * @author Kai Burjack
62  */
63 struct Matrix3d {
64 
65     double m00 = 1.0;
66     double m01 = 0.0;
67     double m02 = 0.0;
68 
69     double m10 = 0.0;
70     double m11 = 1.0;
71     double m12 = 0.0;
72 
73     double m20 = 0.0;
74     double m21 = 0.0;
75     double m22 = 1.0;
76 
77     /**
78      * Create a new {@link Matrix3d} by setting its uppper left 2x2 submatrix to the values of the given {@link Matrix2d}
79      * and the rest to identity.
80      *
81      * @param mat
82      *          the {@link Matrix2d}
83      */
84     this(Matrix2d mat) {
85         set(mat);
86     }
87 
88 
89     /**
90      * Create a new {@link Matrix3d} and initialize it with the values from the given matrix.
91      * 
92      * @param mat
93      *          the matrix to initialize this matrix with
94      */
95     this(Matrix3d mat) {
96         set(mat);
97     }
98 
99 
100     /**
101      * Create a new {@link Matrix3d} and make it a copy of the upper left 3x3 of the given {@link Matrix4d}.
102      *
103      * @param mat
104      *          the {@link Matrix4d} to copy the values from
105      */
106     this(Matrix4d mat) {
107         set(mat);
108     }
109 
110     /**
111      * Create a new {@link Matrix3d} and initialize its elements with the given values.
112      * 
113      * @param m00
114      *          the value of m00
115      * @param m01
116      *          the value of m01
117      * @param m02
118      *          the value of m02
119      * @param m10
120      *          the value of m10
121      * @param m11
122      *          the value of m11
123      * @param m12
124      *          the value of m12
125      * @param m20
126      *          the value of m20
127      * @param m21
128      *          the value of m21
129      * @param m22
130      *          the value of m22
131      */
132     this(double m00, double m01, double m02,
133                     double m10, double m11, double m12, 
134                     double m20, double m21, double m22) {
135         this.m00 = m00;
136         this.m01 = m01;
137         this.m02 = m02;
138         this.m10 = m10;
139         this.m11 = m11;
140         this.m12 = m12;
141         this.m20 = m20;
142         this.m21 = m21;
143         this.m22 = m22;
144     }
145 
146 
147     /**
148      * Create a new {@link Matrix3d} and initialize its three columns using the supplied vectors.
149      * 
150      * @param col0
151      *          the first column
152      * @param col1
153      *          the second column
154      * @param col2
155      *          the third column
156      */
157     this(Vector3d col0, Vector3d col1, Vector3d col2) {
158         set(col0, col1, col2);
159     }
160 
161     /**
162      * Set the value of the matrix element at column 0 and row 0.
163      * 
164      * @param m00
165      *          the new value
166      * @return this
167      */
168     ref public Matrix3d setm00(double m00) return {
169         this.m00 = m00;
170         return this;
171     }
172     /**
173      * Set the value of the matrix element at column 0 and row 1.
174      * 
175      * @param m01
176      *          the new value
177      * @return this
178      */
179     ref public Matrix3d setm01(double m01) return {
180         this.m01 = m01;
181         return this;
182     }
183     /**
184      * Set the value of the matrix element at column 0 and row 2.
185      * 
186      * @param m02
187      *          the new value
188      * @return this
189      */
190     ref public Matrix3d setm02(double m02) return {
191         this.m02 = m02;
192         return this;
193     }
194     /**
195      * Set the value of the matrix element at column 1 and row 0.
196      * 
197      * @param m10
198      *          the new value
199      * @return this
200      */
201     ref public Matrix3d setm10(double m10) return {
202         this.m10 = m10;
203         return this;
204     }
205     /**
206      * Set the value of the matrix element at column 1 and row 1.
207      * 
208      * @param m11
209      *          the new value
210      * @return this
211      */
212     ref public Matrix3d setm11(double m11) return {
213         this.m11 = m11;
214         return this;
215     }
216     /**
217      * Set the value of the matrix element at column 1 and row 2.
218      * 
219      * @param m12
220      *          the new value
221      * @return this
222      */
223     ref public Matrix3d setm12(double m12) return {
224         this.m12 = m12;
225         return this;
226     }
227     /**
228      * Set the value of the matrix element at column 2 and row 0.
229      * 
230      * @param m20
231      *          the new value
232      * @return this
233      */
234     ref public Matrix3d setm20(double m20) return {
235         this.m20 = m20;
236         return this;
237     }
238     /**
239      * Set the value of the matrix element at column 2 and row 1.
240      * 
241      * @param m21
242      *          the new value
243      * @return this
244      */
245     ref public Matrix3d setm21(double m21) return {
246         this.m21 = m21;
247         return this;
248     }
249     /**
250      * Set the value of the matrix element at column 2 and row 2.
251      * 
252      * @param m22
253      *          the new value
254      * @return this
255      */
256     ref public Matrix3d setm22(double m22) return {
257         this.m22 = m22;
258         return this;
259     }
260 
261     /**
262      * Set the value of the matrix element at column 0 and row 0.
263      * 
264      * @param m00
265      *          the new value
266      * @return this
267      */
268     ref Matrix3d _m00(double m00) return {
269         this.m00 = m00;
270         return this;
271     }
272     /**
273      * Set the value of the matrix element at column 0 and row 1.
274      * 
275      * @param m01
276      *          the new value
277      * @return this
278      */
279     ref Matrix3d _m01(double m01) return {
280         this.m01 = m01;
281         return this;
282     }
283     /**
284      * Set the value of the matrix element at column 0 and row 2.
285      * 
286      * @param m02
287      *          the new value
288      * @return this
289      */
290     ref Matrix3d _m02(double m02) return {
291         this.m02 = m02;
292         return this;
293     }
294     /**
295      * Set the value of the matrix element at column 1 and row 0.
296      * 
297      * @param m10
298      *          the new value
299      * @return this
300      */
301     ref Matrix3d _m10(double m10) return {
302         this.m10 = m10;
303         return this;
304     }
305     /**
306      * Set the value of the matrix element at column 1 and row 1.
307      * 
308      * @param m11
309      *          the new value
310      * @return this
311      */
312     ref Matrix3d _m11(double m11) return {
313         this.m11 = m11;
314         return this;
315     }
316     /**
317      * Set the value of the matrix element at column 1 and row 2.
318      * 
319      * @param m12
320      *          the new value
321      * @return this
322      */
323     ref Matrix3d _m12(double m12) return {
324         this.m12 = m12;
325         return this;
326     }
327     /**
328      * Set the value of the matrix element at column 2 and row 0.
329      * 
330      * @param m20
331      *          the new value
332      * @return this
333      */
334     ref Matrix3d _m20(double m20) return {
335         this.m20 = m20;
336         return this;
337     }
338     /**
339      * Set the value of the matrix element at column 2 and row 1.
340      * 
341      * @param m21
342      *          the new value
343      * @return this
344      */
345     ref Matrix3d _m21(double m21) return {
346         this.m21 = m21;
347         return this;
348     }
349     /**
350      * Set the value of the matrix element at column 2 and row 2.
351      * 
352      * @param m22
353      *          the new value
354      * @return this
355      */
356     ref Matrix3d _m22(double m22) return {
357         this.m22 = m22;
358         return this;
359     }
360 
361     /**
362      * Set the values in this matrix to the ones in m.
363      * 
364      * @param m
365      *          the matrix whose values will be copied
366      * @return this
367      */
368     ref public Matrix3d set(Matrix3d m) return {
369         m00 = m.m00;
370         m01 = m.m01;
371         m02 = m.m02;
372         m10 = m.m10;
373         m11 = m.m11;
374         m12 = m.m12;
375         m20 = m.m20;
376         m21 = m.m21;
377         m22 = m.m22;
378         return this;
379     }
380 
381     /**
382      * Store the values of the transpose of the given matrix <code>m</code> into <code>this</code> matrix.
383      * 
384      * @param m
385      *          the matrix to copy the transposed values from
386      * @return this
387      */
388     ref public Matrix3d setTransposed(Matrix3d m) return {
389         double nm10 = m.m01, nm12 = m.m21;
390         double nm20 = m.m02, nm21 = m.m12;
391         return this
392         ._m00(m.m00)._m01(m.m10)._m02(m.m20)
393         ._m10(nm10)._m11(m.m11)._m12(nm12)
394         ._m20(nm20)._m21(nm21)._m22(m.m22);
395     }
396 
397 
398     /**
399      * Set the elements of this matrix to the left 3x3 submatrix of <code>m</code>.
400      * 
401      * @param m
402      *          the matrix to copy the elements from
403      * @return this
404      */
405     ref public Matrix3d set(Matrix4x3d m) return {
406         m00 = m.m00;
407         m01 = m.m01;
408         m02 = m.m02;
409         m10 = m.m10;
410         m11 = m.m11;
411         m12 = m.m12;
412         m20 = m.m20;
413         m21 = m.m21;
414         m22 = m.m22;
415         return this;
416     }
417 
418 
419     /**
420      * Set the elements of this matrix to the upper left 3x3 of the given {@link Matrix4d}.
421      *
422      * @param mat
423      *          the {@link Matrix4d} to copy the values from
424      * @return this
425      */
426     ref public Matrix3d set(Matrix4d mat) return {
427         m00 = mat.m00;
428         m01 = mat.m01;
429         m02 = mat.m02;
430         m10 = mat.m10;
431         m11 = mat.m11;
432         m12 = mat.m12;
433         m20 = mat.m20;
434         m21 = mat.m21;
435         m22 = mat.m22;
436         return this;
437     }
438 
439 
440     /**
441      * Set the upper left 2x2 submatrix of this {@link Matrix3d} to the given {@link Matrix2d}
442      * and the rest to identity.
443      *
444      * @see #Matrix3d(Matrix2d)
445      *
446      * @param mat
447      *          the {@link Matrix2d}
448      * @return this
449      */
450     ref public Matrix3d set(Matrix2d mat) return {
451         m00 = mat.m00;
452         m01 = mat.m01;
453         m02 = 0.0;
454         m10 = mat.m10;
455         m11 = mat.m11;
456         m12 = 0.0;
457         m20 = 0.0;
458         m21 = 0.0;
459         m22 = 1.0;
460         return this;
461     }
462 
463     
464     /**
465      * Set this matrix to be equivalent to the rotation specified by the given {@link AxisAngle4d}.
466      * 
467      * @param axisAngle
468      *          the {@link AxisAngle4d}
469      * @return this
470      */
471     ref public Matrix3d set(AxisAngle4d axisAngle) return {
472         double x = axisAngle.x;
473         double y = axisAngle.y;
474         double z = axisAngle.z;
475         double angle = axisAngle.angle;
476         double invLength = Math.invsqrt(x*x + y*y + z*z);
477         x *= invLength;
478         y *= invLength;
479         z *= invLength;
480         double s = Math.sin(angle);
481         double c = Math.cosFromSin(s, angle);
482         double omc = 1.0 - c;
483         m00 = c + x*x*omc;
484         m11 = c + y*y*omc;
485         m22 = c + z*z*omc;
486         double tmp1 = x*y*omc;
487         double tmp2 = z*s;
488         m10 = tmp1 - tmp2;
489         m01 = tmp1 + tmp2;
490         tmp1 = x*z*omc;
491         tmp2 = y*s;
492         m20 = tmp1 + tmp2;
493         m02 = tmp1 - tmp2;
494         tmp1 = y*z*omc;
495         tmp2 = x*s;
496         m21 = tmp1 - tmp2;
497         m12 = tmp1 + tmp2;
498         return this;
499     }
500 
501     /**
502      * Set this matrix to a rotation - and possibly scaling - equivalent to the given quaternion.
503      * <p>
504      * This method is equivalent to calling: <code>rotation(q)</code>
505      * <p>
506      * Reference: <a href="http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/">http://www.euclideanspace.com/</a>
507      * 
508      * @see #rotation(Quaterniond)
509      * 
510      * @param q
511      *          the quaternion
512      * @return this
513      */
514     ref public Matrix3d set(Quaterniond q) return {
515         return rotation(q);
516     }
517 
518     /**
519      * Multiply this matrix by the supplied matrix.
520      * This matrix will be the left one.
521      * <p>
522      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix,
523      * then the new matrix will be <code>M * R</code>. So when transforming a
524      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
525      * transformation of the right matrix will be applied first!
526      * 
527      * @param right
528      *          the right operand
529      * @return this
530      */
531     ref public Matrix3d mul(Matrix3d right) return {
532         mul(right, this);
533         return this;
534     }
535 
536     public Matrix3d mul(Matrix3d right, ref Matrix3d dest) {
537         double nm00 = Math.fma(m00, right.m00, Math.fma(m10, right.m01, m20 * right.m02));
538         double nm01 = Math.fma(m01, right.m00, Math.fma(m11, right.m01, m21 * right.m02));
539         double nm02 = Math.fma(m02, right.m00, Math.fma(m12, right.m01, m22 * right.m02));
540         double nm10 = Math.fma(m00, right.m10, Math.fma(m10, right.m11, m20 * right.m12));
541         double nm11 = Math.fma(m01, right.m10, Math.fma(m11, right.m11, m21 * right.m12));
542         double nm12 = Math.fma(m02, right.m10, Math.fma(m12, right.m11, m22 * right.m12));
543         double nm20 = Math.fma(m00, right.m20, Math.fma(m10, right.m21, m20 * right.m22));
544         double nm21 = Math.fma(m01, right.m20, Math.fma(m11, right.m21, m21 * right.m22));
545         double nm22 = Math.fma(m02, right.m20, Math.fma(m12, right.m21, m22 * right.m22));
546         dest.m00 = nm00;
547         dest.m01 = nm01;
548         dest.m02 = nm02;
549         dest.m10 = nm10;
550         dest.m11 = nm11;
551         dest.m12 = nm12;
552         dest.m20 = nm20;
553         dest.m21 = nm21;
554         dest.m22 = nm22;
555         return dest;
556     }
557 
558     /**
559      * Pre-multiply this matrix by the supplied <code>left</code> matrix and store the result in <code>this</code>.
560      * <p>
561      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the <code>left</code> matrix,
562      * then the new matrix will be <code>L * M</code>. So when transforming a
563      * vector <code>v</code> with the new matrix by using <code>L * M * v</code>, the
564      * transformation of <code>this</code> matrix will be applied first!
565      *
566      * @param left
567      *          the left operand of the matrix multiplication
568      * @return this
569      */
570     ref public Matrix3d mulLocal(Matrix3d left) return {
571        mulLocal(left, this);
572        return this;
573     }
574 
575     public Matrix3d mulLocal(Matrix3d left, ref Matrix3d dest) {
576         double nm00 = left.m00 * m00 + left.m10 * m01 + left.m20 * m02;
577         double nm01 = left.m01 * m00 + left.m11 * m01 + left.m21 * m02;
578         double nm02 = left.m02 * m00 + left.m12 * m01 + left.m22 * m02;
579         double nm10 = left.m00 * m10 + left.m10 * m11 + left.m20 * m12;
580         double nm11 = left.m01 * m10 + left.m11 * m11 + left.m21 * m12;
581         double nm12 = left.m02 * m10 + left.m12 * m11 + left.m22 * m12;
582         double nm20 = left.m00 * m20 + left.m10 * m21 + left.m20 * m22;
583         double nm21 = left.m01 * m20 + left.m11 * m21 + left.m21 * m22;
584         double nm22 = left.m02 * m20 + left.m12 * m21 + left.m22 * m22;
585         dest.m00 = nm00;
586         dest.m01 = nm01;
587         dest.m02 = nm02;
588         dest.m10 = nm10;
589         dest.m11 = nm11;
590         dest.m12 = nm12;
591         dest.m20 = nm20;
592         dest.m21 = nm21;
593         dest.m22 = nm22;
594         return dest;
595     }
596 
597 
598     /**
599      * Set the values within this matrix to the supplied double values. The result looks like this:
600      * <p>
601      * m00, m10, m20<br>
602      * m01, m11, m21<br>
603      * m02, m12, m22<br>
604      * 
605      * @param m00
606      *          the new value of m00
607      * @param m01
608      *          the new value of m01
609      * @param m02
610      *          the new value of m02
611      * @param m10
612      *          the new value of m10
613      * @param m11
614      *          the new value of m11
615      * @param m12
616      *          the new value of m12
617      * @param m20
618      *          the new value of m20
619      * @param m21
620      *          the new value of m21
621      * @param m22
622      *          the new value of m22
623      * @return this
624      */
625     ref public Matrix3d set(double m00, double m01, double m02, 
626                         double m10, double m11, double m12, 
627                         double m20, double m21, double m22) return {
628         this.m00 = m00;
629         this.m01 = m01;
630         this.m02 = m02;
631         this.m10 = m10;
632         this.m11 = m11;
633         this.m12 = m12;
634         this.m20 = m20;
635         this.m21 = m21;
636         this.m22 = m22;
637         return this;
638     }
639 
640     /**
641      * Set the values in this matrix based on the supplied double array. The result looks like this:
642      * <p>
643      * 0, 3, 6<br>
644      * 1, 4, 7<br>
645      * 2, 5, 8<br>
646      * <p>
647      * Only uses the first 9 values, all others are ignored.
648      * 
649      * @param m
650      *          the array to read the matrix values from
651      * @return this
652      */
653     ref public Matrix3d set(double[] m) return {
654         m00 = m[0];
655         m01 = m[1];
656         m02 = m[2];
657         m10 = m[3];
658         m11 = m[4];
659         m12 = m[5];
660         m20 = m[6];
661         m21 = m[7];
662         m22 = m[8];
663         return this;
664     }
665 
666 
667     public double determinant() {
668         return (m00 * m11 - m01 * m10) * m22
669              + (m02 * m10 - m00 * m12) * m21
670              + (m01 * m12 - m02 * m11) * m20;
671     }
672 
673     /**
674      * Invert this matrix.
675      * 
676      * @return this
677      */
678     ref public Matrix3d invert() return {
679         invert(this);
680         return this;
681     }
682 
683     public Matrix3d invert(ref Matrix3d dest) {
684         double a = Math.fma(m00, m11, -m01 * m10);
685         double b = Math.fma(m02, m10, -m00 * m12);
686         double c = Math.fma(m01, m12, -m02 * m11);
687         double d = Math.fma(a, m22, Math.fma(b, m21, c * m20));
688         double s = 1.0 / d;
689         double nm00 = Math.fma(m11, m22, -m21 * m12) * s;
690         double nm01 = Math.fma(m21, m02, -m01 * m22) * s;
691         double nm02 = c * s;
692         double nm10 = Math.fma(m20, m12, -m10 * m22) * s;
693         double nm11 = Math.fma(m00, m22, -m20 * m02) * s;
694         double nm12 = b * s;
695         double nm20 = Math.fma(m10, m21, -m20 * m11) * s;
696         double nm21 = Math.fma(m20, m01, -m00 * m21) * s;
697         double nm22 = a * s;
698         dest.m00 = nm00;
699         dest.m01 = nm01;
700         dest.m02 = nm02;
701         dest.m10 = nm10;
702         dest.m11 = nm11;
703         dest.m12 = nm12;
704         dest.m20 = nm20;
705         dest.m21 = nm21;
706         dest.m22 = nm22;
707         return dest;
708     }
709 
710     /**
711      * Transpose this matrix.
712      * 
713      * @return this
714      */
715     ref public Matrix3d transpose() return {
716         transpose(this);
717         return this;
718     }
719 
720     public Matrix3d transpose(ref Matrix3d dest) {
721         dest.set(m00, m10, m20,
722                  m01, m11, m21,
723                  m02, m12, m22);
724         return dest;
725     }
726 
727 
728     /**
729      * Get the current values of <code>this</code> matrix and store them into
730      * <code>dest</code>.
731      * <p>
732      * This is the reverse method of {@link #set(Matrix3d)} and allows to obtain
733      * intermediate calculation results when chaining multiple transformations.
734      * 
735      * @see #set(Matrix3d)
736      * 
737      * @param dest
738      *          the destination matrix
739      * @return the passed in destination
740      */
741     public Matrix3d get(ref Matrix3d dest) {
742         return dest.set(this);
743     }
744 
745     public Quaterniond getUnnormalizedRotation(ref Quaterniond dest) {
746         return dest.setFromUnnormalized(this);
747     }
748 
749     public Quaterniond getNormalizedRotation(ref Quaterniond dest) {
750         return dest.setFromNormalized(this);
751     }
752 
753 
754     public double[] get(double[] arr, int offset) {
755         arr[offset+0] = m00;
756         arr[offset+1] = m01;
757         arr[offset+2] = m02;
758         arr[offset+3] = m10;
759         arr[offset+4] = m11;
760         arr[offset+5] = m12;
761         arr[offset+6] = m20;
762         arr[offset+7] = m21;
763         arr[offset+8] = m22;
764         return arr;
765     }
766 
767     public double[] get(double[] arr) {
768         return get(arr, 0);
769     }
770 
771 
772     /**
773      * Set the three columns of this matrix to the supplied vectors, respectively.
774      * 
775      * @param col0
776      *          the first column
777      * @param col1
778      *          the second column
779      * @param col2
780      *          the third column
781      * @return this
782      */
783     ref public Matrix3d set(Vector3d col0,
784                         Vector3d col1, 
785                         Vector3d col2) return {
786         this.m00 = col0.x;
787         this.m01 = col0.y;
788         this.m02 = col0.z;
789         this.m10 = col1.x;
790         this.m11 = col1.y;
791         this.m12 = col1.z;
792         this.m20 = col2.x;
793         this.m21 = col2.y;
794         this.m22 = col2.z;
795         return this;
796     }
797 
798     /**
799      * Set all the values within this matrix to 0.
800      * 
801      * @return this
802      */
803     ref public Matrix3d zero() return {
804         m00 = 0.0;
805         m01 = 0.0;
806         m02 = 0.0;
807         m10 = 0.0;
808         m11 = 0.0;
809         m12 = 0.0;
810         m20 = 0.0;
811         m21 = 0.0;
812         m22 = 0.0;
813         return this;
814     }
815     
816     /**
817      * Set this matrix to the identity.
818      * 
819      * @return this
820      */
821     ref public Matrix3d identity() return {
822         m00 = 1.0;
823         m01 = 0.0;
824         m02 = 0.0;
825         m10 = 0.0;
826         m11 = 1.0;
827         m12 = 0.0;
828         m20 = 0.0;
829         m21 = 0.0;
830         m22 = 1.0;
831         return this;
832     }
833 
834     /**
835      * Set this matrix to be a simple scale matrix, which scales all axes uniformly by the given factor.
836      * <p>
837      * The resulting matrix can be multiplied against another transformation
838      * matrix to obtain an additional scaling.
839      * <p>
840      * In order to post-multiply a scaling transformation directly to a
841      * matrix, use {@link #scale(double) scale()} instead.
842      * 
843      * @see #scale(double)
844      * 
845      * @param factor
846      *             the scale factor in x, y and z
847      * @return this
848      */
849     ref public Matrix3d scaling(double factor) return {
850         m00 = factor;
851         m01 = 0.0;
852         m02 = 0.0;
853         m10 = 0.0;
854         m11 = factor;
855         m12 = 0.0;
856         m20 = 0.0;
857         m21 = 0.0;
858         m22 = factor;
859         return this;
860     }
861 
862     /**
863      * Set this matrix to be a simple scale matrix.
864      * 
865      * @param x
866      *             the scale in x
867      * @param y
868      *             the scale in y
869      * @param z
870      *             the scale in z
871      * @return this
872      */
873     ref public Matrix3d scaling(double x, double y, double z) return {
874         m00 = x;
875         m01 = 0.0;
876         m02 = 0.0;
877         m10 = 0.0;
878         m11 = y;
879         m12 = 0.0;
880         m20 = 0.0;
881         m21 = 0.0;
882         m22 = z;
883         return this;
884     }
885 
886     /**
887      * Set this matrix to be a simple scale matrix which scales the base axes by <code>xyz.x</code>, <code>xyz.y</code> and <code>xyz.z</code> respectively.
888      * <p>
889      * The resulting matrix can be multiplied against another transformation
890      * matrix to obtain an additional scaling.
891      * <p>
892      * In order to post-multiply a scaling transformation directly to a
893      * matrix use {@link #scale(Vector3d) scale()} instead.
894      * 
895      * @see #scale(Vector3d)
896      * 
897      * @param xyz
898      *             the scale in x, y and z respectively
899      * @return this
900      */
901     ref public Matrix3d scaling(Vector3d xyz) return {
902         m00 = xyz.x;
903         m01 = 0.0;
904         m02 = 0.0;
905         m10 = 0.0;
906         m11 = xyz.y;
907         m12 = 0.0;
908         m20 = 0.0;
909         m21 = 0.0;
910         m22 = xyz.z;
911         return this;
912     }
913 
914     public Matrix3d scale(Vector3d xyz, ref Matrix3d dest) {
915         return scale(xyz.x, xyz.y, xyz.z, dest);
916     }
917 
918     /**
919      * Apply scaling to this matrix by scaling the base axes by the given <code>xyz.x</code>,
920      * <code>xyz.y</code> and <code>xyz.z</code> factors, respectively.
921      * <p>
922      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
923      * then the new matrix will be <code>M * S</code>. So when transforming a
924      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the
925      * scaling will be applied first!
926      * 
927      * @param xyz
928      *            the factors of the x, y and z component, respectively
929      * @return this
930      */
931     ref public Matrix3d scale(Vector3d xyz) return {
932         scale(xyz.x, xyz.y, xyz.z, this);
933         return this;
934     }
935 
936     public Matrix3d scale(double x, double y, double z, ref Matrix3d dest) {
937         // scale matrix elements:
938         // m00 = x, m11 = y, m22 = z
939         // all others = 0
940         dest.m00 = m00 * x;
941         dest.m01 = m01 * x;
942         dest.m02 = m02 * x;
943         dest.m10 = m10 * y;
944         dest.m11 = m11 * y;
945         dest.m12 = m12 * y;
946         dest.m20 = m20 * z;
947         dest.m21 = m21 * z;
948         dest.m22 = m22 * z;
949         return dest;
950     }
951 
952     /**
953      * Apply scaling to this matrix by scaling the base axes by the given x,
954      * y and z factors.
955      * <p>
956      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
957      * then the new matrix will be <code>M * S</code>. So when transforming a
958      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>
959      * , the scaling will be applied first!
960      * 
961      * @param x
962      *            the factor of the x component
963      * @param y
964      *            the factor of the y component
965      * @param z
966      *            the factor of the z component
967      * @return this
968      */
969     ref public Matrix3d scale(double x, double y, double z) return {
970         scale(x, y, z, this);
971         return this;
972     }
973 
974     public Matrix3d scale(double xyz, ref Matrix3d dest) {
975         return scale(xyz, xyz, xyz, dest);
976     }
977 
978     /**
979      * Apply scaling to this matrix by uniformly scaling all base axes by the given <code>xyz</code> factor.
980      * <p>
981      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
982      * then the new matrix will be <code>M * S</code>. So when transforming a
983      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>
984      * , the scaling will be applied first!
985      * 
986      * @see #scale(double, double, double)
987      * 
988      * @param xyz
989      *            the factor for all components
990      * @return this
991      */
992     ref public Matrix3d scale(double xyz) return {
993         return scale(xyz, xyz, xyz);
994     }
995 
996     public Matrix3d scaleLocal(double x, double y, double z, ref Matrix3d dest) {
997         double nm00 = x * m00;
998         double nm01 = y * m01;
999         double nm02 = z * m02;
1000         double nm10 = x * m10;
1001         double nm11 = y * m11;
1002         double nm12 = z * m12;
1003         double nm20 = x * m20;
1004         double nm21 = y * m21;
1005         double nm22 = z * m22;
1006         dest.m00 = nm00;
1007         dest.m01 = nm01;
1008         dest.m02 = nm02;
1009         dest.m10 = nm10;
1010         dest.m11 = nm11;
1011         dest.m12 = nm12;
1012         dest.m20 = nm20;
1013         dest.m21 = nm21;
1014         dest.m22 = nm22;
1015         return dest;
1016     }
1017 
1018     /**
1019      * Pre-multiply scaling to this matrix by scaling the base axes by the given x,
1020      * y and z factors.
1021      * <p>
1022      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
1023      * then the new matrix will be <code>S * M</code>. So when transforming a
1024      * vector <code>v</code> with the new matrix by using <code>S * M * v</code>, the
1025      * scaling will be applied last!
1026      * 
1027      * @param x
1028      *            the factor of the x component
1029      * @param y
1030      *            the factor of the y component
1031      * @param z
1032      *            the factor of the z component
1033      * @return this
1034      */
1035     ref public Matrix3d scaleLocal(double x, double y, double z) return {
1036         scaleLocal(x, y, z, this);
1037         return this;
1038     }
1039 
1040     /**
1041      * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
1042      * <p>
1043      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1044      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1045      * When used with a left-handed coordinate system, the rotation is clockwise.
1046      * <p>
1047      * The resulting matrix can be multiplied against another transformation
1048      * matrix to obtain an additional rotation.
1049      * <p>
1050      * In order to post-multiply a rotation transformation directly to a
1051      * matrix, use {@link #rotate(double, Vector3d) rotate()} instead.
1052      * 
1053      * @see #rotate(double, Vector3d)
1054      * 
1055      * @param angle
1056      *          the angle in radians
1057      * @param axis
1058      *          the axis to rotate about (needs to be {@link Vector3d#normalize() normalized})
1059      * @return this
1060      */
1061     ref public Matrix3d rotation(double angle, Vector3d axis) return {
1062         return rotation(angle, axis.x, axis.y, axis.z);
1063     }
1064 
1065 
1066 
1067     /**
1068      * Set this matrix to a rotation transformation using the given {@link AxisAngle4d}.
1069      * <p>
1070      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1071      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1072      * When used with a left-handed coordinate system, the rotation is clockwise.
1073      * <p>
1074      * The resulting matrix can be multiplied against another transformation
1075      * matrix to obtain an additional rotation.
1076      * <p>
1077      * In order to apply the rotation transformation to an existing transformation,
1078      * use {@link #rotate(AxisAngle4d) rotate()} instead.
1079      * <p>
1080      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a>
1081      *
1082      * @see #rotate(AxisAngle4d)
1083      * 
1084      * @param axisAngle
1085      *          the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
1086      * @return this
1087      */
1088     ref public Matrix3d rotation(AxisAngle4d axisAngle) return {
1089         return rotation(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
1090     }
1091 
1092     /**
1093      * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
1094      * <p>
1095      * The axis described by the three components needs to be a unit vector.
1096      * <p>
1097      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1098      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1099      * When used with a left-handed coordinate system, the rotation is clockwise.
1100      * <p>
1101      * The resulting matrix can be multiplied against another transformation
1102      * matrix to obtain an additional rotation.
1103      * <p>
1104      * In order to apply the rotation transformation to an existing transformation,
1105      * use {@link #rotate(double, double, double, double) rotate()} instead.
1106      * <p>
1107      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
1108      * 
1109      * @see #rotate(double, double, double, double)
1110      * 
1111      * @param angle
1112      *          the angle in radians
1113      * @param x
1114      *          the x-component of the rotation axis
1115      * @param y
1116      *          the y-component of the rotation axis
1117      * @param z
1118      *          the z-component of the rotation axis
1119      * @return this
1120      */
1121     ref public Matrix3d rotation(double angle, double x, double y, double z) return {
1122         double sin = Math.sin(angle);
1123         double cos = Math.cosFromSin(sin, angle);
1124         double C = 1.0 - cos;
1125         double xy = x * y, xz = x * z, yz = y * z;
1126         m00 = cos + x * x * C;
1127         m10 = xy * C - z * sin;
1128         m20 = xz * C + y * sin;
1129         m01 = xy * C + z * sin;
1130         m11 = cos + y * y * C;
1131         m21 = yz * C - x * sin;
1132         m02 = xz * C - y * sin;
1133         m12 = yz * C + x * sin;
1134         m22 = cos + z * z * C;
1135         return this;
1136     }
1137 
1138     /**
1139      * Set this matrix to a rotation transformation about the X axis.
1140      * <p>
1141      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1142      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1143      * When used with a left-handed coordinate system, the rotation is clockwise.
1144      * <p>
1145      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a>
1146      * 
1147      * @param ang
1148      *            the angle in radians
1149      * @return this
1150      */
1151     ref public Matrix3d rotationX(double ang) return {
1152         double sin, cos;
1153         sin = Math.sin(ang);
1154         cos = Math.cosFromSin(sin, ang);
1155         m00 = 1.0;
1156         m01 = 0.0;
1157         m02 = 0.0;
1158         m10 = 0.0;
1159         m11 = cos;
1160         m12 = sin;
1161         m20 = 0.0;
1162         m21 = -sin;
1163         m22 = cos;
1164         return this;
1165     }
1166 
1167     /**
1168      * Set this matrix to a rotation transformation about the Y axis.
1169      * <p>
1170      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1171      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1172      * When used with a left-handed coordinate system, the rotation is clockwise.
1173      * <p>
1174      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a>
1175      * 
1176      * @param ang
1177      *            the angle in radians
1178      * @return this
1179      */
1180     ref public Matrix3d rotationY(double ang) return {
1181         double sin, cos;
1182         sin = Math.sin(ang);
1183         cos = Math.cosFromSin(sin, ang);
1184         m00 = cos;
1185         m01 = 0.0;
1186         m02 = -sin;
1187         m10 = 0.0;
1188         m11 = 1.0;
1189         m12 = 0.0;
1190         m20 = sin;
1191         m21 = 0.0;
1192         m22 = cos;
1193         return this;
1194     }
1195 
1196     /**
1197      * Set this matrix to a rotation transformation about the Z axis.
1198      * <p>
1199      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1200      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1201      * When used with a left-handed coordinate system, the rotation is clockwise.
1202      * <p>
1203      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a>
1204      * 
1205      * @param ang
1206      *            the angle in radians
1207      * @return this
1208      */
1209     ref public Matrix3d rotationZ(double ang) return {
1210         double sin, cos;
1211         sin = Math.sin(ang);
1212         cos = Math.cosFromSin(sin, ang);
1213         m00 = cos;
1214         m01 = sin;
1215         m02 = 0.0;
1216         m10 = -sin;
1217         m11 = cos;
1218         m12 = 0.0;
1219         m20 = 0.0;
1220         m21 = 0.0;
1221         m22 = 1.0;
1222         return this;
1223     }
1224 
1225     /**
1226      * Set this matrix to a rotation of <code>angleX</code> radians about the X axis, followed by a rotation
1227      * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleZ</code> radians about the Z axis.
1228      * <p>
1229      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1230      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1231      * When used with a left-handed coordinate system, the rotation is clockwise.
1232      * <p>
1233      * This method is equivalent to calling: <code>rotationX(angleX).rotateY(angleY).rotateZ(angleZ)</code>
1234      * 
1235      * @param angleX
1236      *            the angle to rotate about X
1237      * @param angleY
1238      *            the angle to rotate about Y
1239      * @param angleZ
1240      *            the angle to rotate about Z
1241      * @return this
1242      */
1243     ref public Matrix3d rotationXYZ(double angleX, double angleY, double angleZ) return {
1244         double sinX = Math.sin(angleX);
1245         double cosX = Math.cosFromSin(sinX, angleX);
1246         double sinY = Math.sin(angleY);
1247         double cosY = Math.cosFromSin(sinY, angleY);
1248         double sinZ = Math.sin(angleZ);
1249         double cosZ = Math.cosFromSin(sinZ, angleZ);
1250         double m_sinX = -sinX;
1251         double m_sinY = -sinY;
1252         double m_sinZ = -sinZ;
1253 
1254         // rotateX
1255         double nm11 = cosX;
1256         double nm12 = sinX;
1257         double nm21 = m_sinX;
1258         double nm22 = cosX;
1259         // rotateY
1260         double nm00 = cosY;
1261         double nm01 = nm21 * m_sinY;
1262         double nm02 = nm22 * m_sinY;
1263         m20 = sinY;
1264         m21 = nm21 * cosY;
1265         m22 = nm22 * cosY;
1266         // rotateZ
1267         m00 = nm00 * cosZ;
1268         m01 = nm01 * cosZ + nm11 * sinZ;
1269         m02 = nm02 * cosZ + nm12 * sinZ;
1270         m10 = nm00 * m_sinZ;
1271         m11 = nm01 * m_sinZ + nm11 * cosZ;
1272         m12 = nm02 * m_sinZ + nm12 * cosZ;
1273         return this;
1274     }
1275 
1276     /**
1277      * Set this matrix to a rotation of <code>angleZ</code> radians about the Z axis, followed by a rotation
1278      * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleX</code> radians about the X axis.
1279      * <p>
1280      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1281      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1282      * When used with a left-handed coordinate system, the rotation is clockwise.
1283      * <p>
1284      * This method is equivalent to calling: <code>rotationZ(angleZ).rotateY(angleY).rotateX(angleX)</code>
1285      * 
1286      * @param angleZ
1287      *            the angle to rotate about Z
1288      * @param angleY
1289      *            the angle to rotate about Y
1290      * @param angleX
1291      *            the angle to rotate about X
1292      * @return this
1293      */
1294     ref public Matrix3d rotationZYX(double angleZ, double angleY, double angleX) return {
1295         double sinX = Math.sin(angleX);
1296         double cosX = Math.cosFromSin(sinX, angleX);
1297         double sinY = Math.sin(angleY);
1298         double cosY = Math.cosFromSin(sinY, angleY);
1299         double sinZ = Math.sin(angleZ);
1300         double cosZ = Math.cosFromSin(sinZ, angleZ);
1301         double m_sinZ = -sinZ;
1302         double m_sinY = -sinY;
1303         double m_sinX = -sinX;
1304 
1305         // rotateZ
1306         double nm00 = cosZ;
1307         double nm01 = sinZ;
1308         double nm10 = m_sinZ;
1309         double nm11 = cosZ;
1310         // rotateY
1311         double nm20 = nm00 * sinY;
1312         double nm21 = nm01 * sinY;
1313         double nm22 = cosY;
1314         m00 = nm00 * cosY;
1315         m01 = nm01 * cosY;
1316         m02 = m_sinY;
1317         // rotateX
1318         m10 = nm10 * cosX + nm20 * sinX;
1319         m11 = nm11 * cosX + nm21 * sinX;
1320         m12 = nm22 * sinX;
1321         m20 = nm10 * m_sinX + nm20 * cosX;
1322         m21 = nm11 * m_sinX + nm21 * cosX;
1323         m22 = nm22 * cosX;
1324         return this;
1325     }
1326 
1327     /**
1328      * Set this matrix to a rotation of <code>angleY</code> radians about the Y axis, followed by a rotation
1329      * of <code>angleX</code> radians about the X axis and followed by a rotation of <code>angleZ</code> radians about the Z axis.
1330      * <p>
1331      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1332      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1333      * When used with a left-handed coordinate system, the rotation is clockwise.
1334      * <p>
1335      * This method is equivalent to calling: <code>rotationY(angleY).rotateX(angleX).rotateZ(angleZ)</code>
1336      * 
1337      * @param angleY
1338      *            the angle to rotate about Y
1339      * @param angleX
1340      *            the angle to rotate about X
1341      * @param angleZ
1342      *            the angle to rotate about Z
1343      * @return this
1344      */
1345     ref public Matrix3d rotationYXZ(double angleY, double angleX, double angleZ) return {
1346         double sinX = Math.sin(angleX);
1347         double cosX = Math.cosFromSin(sinX, angleX);
1348         double sinY = Math.sin(angleY);
1349         double cosY = Math.cosFromSin(sinY, angleY);
1350         double sinZ = Math.sin(angleZ);
1351         double cosZ = Math.cosFromSin(sinZ, angleZ);
1352         double m_sinY = -sinY;
1353         double m_sinX = -sinX;
1354         double m_sinZ = -sinZ;
1355 
1356         // rotateY
1357         double nm00 = cosY;
1358         double nm02 = m_sinY;
1359         double nm20 = sinY;
1360         double nm22 = cosY;
1361         // rotateX
1362         double nm10 = nm20 * sinX;
1363         double nm11 = cosX;
1364         double nm12 = nm22 * sinX;
1365         m20 = nm20 * cosX;
1366         m21 = m_sinX;
1367         m22 = nm22 * cosX;
1368         // rotateZ
1369         m00 = nm00 * cosZ + nm10 * sinZ;
1370         m01 = nm11 * sinZ;
1371         m02 = nm02 * cosZ + nm12 * sinZ;
1372         m10 = nm00 * m_sinZ + nm10 * cosZ;
1373         m11 = nm11 * cosZ;
1374         m12 = nm02 * m_sinZ + nm12 * cosZ;
1375         return this;
1376     }
1377 
1378     /**
1379      * Set this matrix to the rotation - and possibly scaling - transformation of the given {@link Quaterniond}.
1380      * <p>
1381      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1382      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1383      * When used with a left-handed coordinate system, the rotation is clockwise.
1384      * <p>
1385      * The resulting matrix can be multiplied against another transformation
1386      * matrix to obtain an additional rotation.
1387      * <p>
1388      * In order to apply the rotation transformation to an existing transformation,
1389      * use {@link #rotate(Quaterniond) rotate()} instead.
1390      * <p>
1391      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
1392      * 
1393      * @see #rotate(Quaterniond)
1394      * 
1395      * @param quat
1396      *          the {@link Quaterniond}
1397      * @return this
1398      */
1399     ref public Matrix3d rotation(Quaterniond quat) return {
1400         double w2 = quat.w * quat.w;
1401         double x2 = quat.x * quat.x;
1402         double y2 = quat.y * quat.y;
1403         double z2 = quat.z * quat.z;
1404         double zw = quat.z * quat.w, dzw = zw + zw;
1405         double xy = quat.x * quat.y, dxy = xy + xy;
1406         double xz = quat.x * quat.z, dxz = xz + xz;
1407         double yw = quat.y * quat.w, dyw = yw + yw;
1408         double yz = quat.y * quat.z, dyz = yz + yz;
1409         double xw = quat.x * quat.w, dxw = xw + xw;
1410         m00 = w2 + x2 - z2 - y2;
1411         m01 = dxy + dzw;
1412         m02 = dxz - dyw;
1413         m10 = -dzw + dxy;
1414         m11 = y2 - z2 + w2 - x2;
1415         m12 = dyz + dxw;
1416         m20 = dyw + dxz;
1417         m21 = dyz - dxw;
1418         m22 = z2 - y2 - x2 + w2;
1419         return this;
1420     }
1421 
1422 
1423     public Vector3d transform(Vector3d v) {
1424         return v.mul(this);
1425     }
1426 
1427     public Vector3d transform(Vector3d v, ref Vector3d dest) {
1428         v.mul(this, dest);
1429         return dest;
1430     }
1431 
1432 
1433     public Vector3d transform(double x, double y, double z, ref Vector3d dest) {
1434         return dest.set(Math.fma(m00, x, Math.fma(m10, y, m20 * z)),
1435                         Math.fma(m01, x, Math.fma(m11, y, m21 * z)),
1436                         Math.fma(m02, x, Math.fma(m12, y, m22 * z)));
1437     }
1438 
1439     public Vector3d transformTranspose(Vector3d v) {
1440         return v.mulTranspose(this);
1441     }
1442 
1443     public Vector3d transformTranspose(Vector3d v, ref Vector3d dest) {
1444         return v.mulTranspose(this, dest);
1445     }
1446 
1447     public Vector3d transformTranspose(double x, double y, double z, ref Vector3d dest) {
1448         return dest.set(Math.fma(m00, x, Math.fma(m01, y, m02 * z)),
1449                         Math.fma(m10, x, Math.fma(m11, y, m12 * z)),
1450                         Math.fma(m20, x, Math.fma(m21, y, m22 * z)));
1451     }
1452 
1453 
1454     public Matrix3d rotateX(double ang, ref Matrix3d dest) {
1455         double sin, cos;
1456         sin = Math.sin(ang);
1457         cos = Math.cosFromSin(sin, ang);
1458         double rm11 = cos;
1459         double rm21 = -sin;
1460         double rm12 = sin;
1461         double rm22 = cos;
1462 
1463         // add temporaries for dependent values
1464         double nm10 = m10 * rm11 + m20 * rm12;
1465         double nm11 = m11 * rm11 + m21 * rm12;
1466         double nm12 = m12 * rm11 + m22 * rm12;
1467         // set non-dependent values directly
1468         dest.m20 = m10 * rm21 + m20 * rm22;
1469         dest.m21 = m11 * rm21 + m21 * rm22;
1470         dest.m22 = m12 * rm21 + m22 * rm22;
1471         // set other values
1472         dest.m10 = nm10;
1473         dest.m11 = nm11;
1474         dest.m12 = nm12;
1475         dest.m00 = m00;
1476         dest.m01 = m01;
1477         dest.m02 = m02;
1478         return dest;
1479     }
1480 
1481     /**
1482      * Apply rotation about the X axis to this matrix by rotating the given amount of radians.
1483      * <p>
1484      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1485      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1486      * When used with a left-handed coordinate system, the rotation is clockwise.
1487      * <p>
1488      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
1489      * then the new matrix will be <code>M * R</code>. So when transforming a
1490      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>
1491      * , the rotation will be applied first!
1492      * <p>
1493      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a>
1494      * 
1495      * @param ang
1496      *            the angle in radians
1497      * @return this
1498      */
1499     ref public Matrix3d rotateX(double ang) return {
1500         rotateX(ang, this);
1501         return this;
1502     }
1503 
1504     public Matrix3d rotateY(double ang, ref Matrix3d dest) {
1505         double sin, cos;
1506         sin = Math.sin(ang);
1507         cos = Math.cosFromSin(sin, ang);
1508         double rm00 = cos;
1509         double rm20 = sin;
1510         double rm02 = -sin;
1511         double rm22 = cos;
1512 
1513         // add temporaries for dependent values
1514         double nm00 = m00 * rm00 + m20 * rm02;
1515         double nm01 = m01 * rm00 + m21 * rm02;
1516         double nm02 = m02 * rm00 + m22 * rm02;
1517         // set non-dependent values directly
1518         dest.m20 = m00 * rm20 + m20 * rm22;
1519         dest.m21 = m01 * rm20 + m21 * rm22;
1520         dest.m22 = m02 * rm20 + m22 * rm22;
1521         // set other values
1522         dest.m00 = nm00;
1523         dest.m01 = nm01;
1524         dest.m02 = nm02;
1525         dest.m10 = m10;
1526         dest.m11 = m11;
1527         dest.m12 = m12;
1528         return dest;
1529     }
1530 
1531     /**
1532      * Apply rotation about the Y axis to this matrix by rotating the given amount of radians.
1533      * <p>
1534      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1535      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1536      * When used with a left-handed coordinate system, the rotation is clockwise.
1537      * <p>
1538      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
1539      * then the new matrix will be <code>M * R</code>. So when transforming a
1540      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>
1541      * , the rotation will be applied first!
1542      * <p>
1543      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a>
1544      * 
1545      * @param ang
1546      *            the angle in radians
1547      * @return this
1548      */
1549     ref public Matrix3d rotateY(double ang) return {
1550         rotateY(ang, this);
1551         return this;
1552     }
1553 
1554     public Matrix3d rotateZ(double ang, ref Matrix3d dest) {
1555         double sin, cos;
1556         sin = Math.sin(ang);
1557         cos = Math.cosFromSin(sin, ang);
1558         double rm00 = cos;
1559         double rm10 = -sin;
1560         double rm01 = sin;
1561         double rm11 = cos;
1562 
1563         // add temporaries for dependent values
1564         double nm00 = m00 * rm00 + m10 * rm01;
1565         double nm01 = m01 * rm00 + m11 * rm01;
1566         double nm02 = m02 * rm00 + m12 * rm01;
1567         // set non-dependent values directly
1568         dest.m10 = m00 * rm10 + m10 * rm11;
1569         dest.m11 = m01 * rm10 + m11 * rm11;
1570         dest.m12 = m02 * rm10 + m12 * rm11;
1571         // set other values
1572         dest.m00 = nm00;
1573         dest.m01 = nm01;
1574         dest.m02 = nm02;
1575         dest.m20 = m20;
1576         dest.m21 = m21;
1577         dest.m22 = m22;
1578         return dest;
1579     }
1580 
1581     /**
1582      * Apply rotation about the Z axis to this matrix by rotating the given amount of radians.
1583      * <p>
1584      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1585      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1586      * When used with a left-handed coordinate system, the rotation is clockwise.
1587      * <p>
1588      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
1589      * then the new matrix will be <code>M * R</code>. So when transforming a
1590      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>
1591      * , the rotation will be applied first!
1592      * <p>
1593      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a>
1594      * 
1595      * @param ang
1596      *            the angle in radians
1597      * @return this
1598      */
1599     ref public Matrix3d rotateZ(double ang) return {
1600         rotateZ(ang, this);
1601         return this;
1602     }
1603 
1604     /**
1605      * Apply rotation of <code>angleX</code> radians about the X axis, followed by a rotation of <code>angleY</code> radians about the Y axis and
1606      * followed by a rotation of <code>angleZ</code> radians about the Z axis.
1607      * <p>
1608      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1609      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1610      * When used with a left-handed coordinate system, the rotation is clockwise.
1611      * <p>
1612      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
1613      * then the new matrix will be <code>M * R</code>. So when transforming a
1614      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
1615      * rotation will be applied first!
1616      * <p>
1617      * This method is equivalent to calling: <code>rotateX(angleX).rotateY(angleY).rotateZ(angleZ)</code>
1618      * 
1619      * @param angleX
1620      *            the angle to rotate about X
1621      * @param angleY
1622      *            the angle to rotate about Y
1623      * @param angleZ
1624      *            the angle to rotate about Z
1625      * @return this
1626      */
1627     ref public Matrix3d rotateXYZ(double angleX, double angleY, double angleZ) return {
1628         rotateXYZ(angleX, angleY, angleZ, this);
1629         return this;
1630     }
1631 
1632     public Matrix3d rotateXYZ(double angleX, double angleY, double angleZ, ref Matrix3d dest) {
1633         double sinX = Math.sin(angleX);
1634         double cosX = Math.cosFromSin(sinX, angleX);
1635         double sinY = Math.sin(angleY);
1636         double cosY = Math.cosFromSin(sinY, angleY);
1637         double sinZ = Math.sin(angleZ);
1638         double cosZ = Math.cosFromSin(sinZ, angleZ);
1639         double m_sinX = -sinX;
1640         double m_sinY = -sinY;
1641         double m_sinZ = -sinZ;
1642 
1643         // rotateX
1644         double nm10 = m10 * cosX + m20 * sinX;
1645         double nm11 = m11 * cosX + m21 * sinX;
1646         double nm12 = m12 * cosX + m22 * sinX;
1647         double nm20 = m10 * m_sinX + m20 * cosX;
1648         double nm21 = m11 * m_sinX + m21 * cosX;
1649         double nm22 = m12 * m_sinX + m22 * cosX;
1650         // rotateY
1651         double nm00 = m00 * cosY + nm20 * m_sinY;
1652         double nm01 = m01 * cosY + nm21 * m_sinY;
1653         double nm02 = m02 * cosY + nm22 * m_sinY;
1654         dest.m20 = m00 * sinY + nm20 * cosY;
1655         dest.m21 = m01 * sinY + nm21 * cosY;
1656         dest.m22 = m02 * sinY + nm22 * cosY;
1657         // rotateZ
1658         dest.m00 = nm00 * cosZ + nm10 * sinZ;
1659         dest.m01 = nm01 * cosZ + nm11 * sinZ;
1660         dest.m02 = nm02 * cosZ + nm12 * sinZ;
1661         dest.m10 = nm00 * m_sinZ + nm10 * cosZ;
1662         dest.m11 = nm01 * m_sinZ + nm11 * cosZ;
1663         dest.m12 = nm02 * m_sinZ + nm12 * cosZ;
1664         return dest;
1665     }
1666 
1667     /**
1668      * Apply rotation of <code>angleZ</code> radians about the Z axis, followed by a rotation of <code>angleY</code> radians about the Y axis and
1669      * followed by a rotation of <code>angleX</code> radians about the X axis.
1670      * <p>
1671      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1672      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1673      * When used with a left-handed coordinate system, the rotation is clockwise.
1674      * <p>
1675      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
1676      * then the new matrix will be <code>M * R</code>. So when transforming a
1677      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
1678      * rotation will be applied first!
1679      * <p>
1680      * This method is equivalent to calling: <code>rotateZ(angleZ).rotateY(angleY).rotateX(angleX)</code>
1681      * 
1682      * @param angleZ
1683      *            the angle to rotate about Z
1684      * @param angleY
1685      *            the angle to rotate about Y
1686      * @param angleX
1687      *            the angle to rotate about X
1688      * @return this
1689      */
1690     ref public Matrix3d rotateZYX(double angleZ, double angleY, double angleX) return {
1691         rotateZYX(angleZ, angleY, angleX, this);
1692         return this;
1693     }
1694 
1695     public Matrix3d rotateZYX(double angleZ, double angleY, double angleX, ref Matrix3d dest) {
1696         double sinX = Math.sin(angleX);
1697         double cosX = Math.cosFromSin(sinX, angleX);
1698         double sinY = Math.sin(angleY);
1699         double cosY = Math.cosFromSin(sinY, angleY);
1700         double sinZ = Math.sin(angleZ);
1701         double cosZ = Math.cosFromSin(sinZ, angleZ);
1702         double m_sinZ = -sinZ;
1703         double m_sinY = -sinY;
1704         double m_sinX = -sinX;
1705 
1706         // rotateZ
1707         double nm00 = m00 * cosZ + m10 * sinZ;
1708         double nm01 = m01 * cosZ + m11 * sinZ;
1709         double nm02 = m02 * cosZ + m12 * sinZ;
1710         double nm10 = m00 * m_sinZ + m10 * cosZ;
1711         double nm11 = m01 * m_sinZ + m11 * cosZ;
1712         double nm12 = m02 * m_sinZ + m12 * cosZ;
1713         // rotateY
1714         double nm20 = nm00 * sinY + m20 * cosY;
1715         double nm21 = nm01 * sinY + m21 * cosY;
1716         double nm22 = nm02 * sinY + m22 * cosY;
1717         dest.m00 = nm00 * cosY + m20 * m_sinY;
1718         dest.m01 = nm01 * cosY + m21 * m_sinY;
1719         dest.m02 = nm02 * cosY + m22 * m_sinY;
1720         // rotateX
1721         dest.m10 = nm10 * cosX + nm20 * sinX;
1722         dest.m11 = nm11 * cosX + nm21 * sinX;
1723         dest.m12 = nm12 * cosX + nm22 * sinX;
1724         dest.m20 = nm10 * m_sinX + nm20 * cosX;
1725         dest.m21 = nm11 * m_sinX + nm21 * cosX;
1726         dest.m22 = nm12 * m_sinX + nm22 * cosX;
1727         return dest;
1728     }
1729 
1730     /**
1731      * Apply rotation of <code>angles.y</code> radians about the Y axis, followed by a rotation of <code>angles.x</code> radians about the X axis and
1732      * followed by a rotation of <code>angles.z</code> radians about the Z axis.
1733      * <p>
1734      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1735      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1736      * When used with a left-handed coordinate system, the rotation is clockwise.
1737      * <p>
1738      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
1739      * then the new matrix will be <code>M * R</code>. So when transforming a
1740      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
1741      * rotation will be applied first!
1742      * <p>
1743      * This method is equivalent to calling: <code>rotateY(angles.y).rotateX(angles.x).rotateZ(angles.z)</code>
1744      * 
1745      * @param angles
1746      *            the Euler angles
1747      * @return this
1748      */
1749     ref public Matrix3d rotateYXZ(Vector3d angles) return {
1750         return rotateYXZ(angles.y, angles.x, angles.z);
1751     }
1752 
1753     /**
1754      * Apply rotation of <code>angleY</code> radians about the Y axis, followed by a rotation of <code>angleX</code> radians about the X axis and
1755      * followed by a rotation of <code>angleZ</code> radians about the Z axis.
1756      * <p>
1757      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1758      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1759      * When used with a left-handed coordinate system, the rotation is clockwise.
1760      * <p>
1761      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
1762      * then the new matrix will be <code>M * R</code>. So when transforming a
1763      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
1764      * rotation will be applied first!
1765      * <p>
1766      * This method is equivalent to calling: <code>rotateY(angleY).rotateX(angleX).rotateZ(angleZ)</code>
1767      * 
1768      * @param angleY
1769      *            the angle to rotate about Y
1770      * @param angleX
1771      *            the angle to rotate about X
1772      * @param angleZ
1773      *            the angle to rotate about Z
1774      * @return this
1775      */
1776     ref public Matrix3d rotateYXZ(double angleY, double angleX, double angleZ) return {
1777         rotateYXZ(angleY, angleX, angleZ, this);
1778         return this;
1779     }
1780 
1781     public Matrix3d rotateYXZ(double angleY, double angleX, double angleZ, ref Matrix3d dest) {
1782         double sinX = Math.sin(angleX);
1783         double cosX = Math.cosFromSin(sinX, angleX);
1784         double sinY = Math.sin(angleY);
1785         double cosY = Math.cosFromSin(sinY, angleY);
1786         double sinZ = Math.sin(angleZ);
1787         double cosZ = Math.cosFromSin(sinZ, angleZ);
1788         double m_sinY = -sinY;
1789         double m_sinX = -sinX;
1790         double m_sinZ = -sinZ;
1791 
1792         // rotateY
1793         double nm20 = m00 * sinY + m20 * cosY;
1794         double nm21 = m01 * sinY + m21 * cosY;
1795         double nm22 = m02 * sinY + m22 * cosY;
1796         double nm00 = m00 * cosY + m20 * m_sinY;
1797         double nm01 = m01 * cosY + m21 * m_sinY;
1798         double nm02 = m02 * cosY + m22 * m_sinY;
1799         // rotateX
1800         double nm10 = m10 * cosX + nm20 * sinX;
1801         double nm11 = m11 * cosX + nm21 * sinX;
1802         double nm12 = m12 * cosX + nm22 * sinX;
1803         dest.m20 = m10 * m_sinX + nm20 * cosX;
1804         dest.m21 = m11 * m_sinX + nm21 * cosX;
1805         dest.m22 = m12 * m_sinX + nm22 * cosX;
1806         // rotateZ
1807         dest.m00 = nm00 * cosZ + nm10 * sinZ;
1808         dest.m01 = nm01 * cosZ + nm11 * sinZ;
1809         dest.m02 = nm02 * cosZ + nm12 * sinZ;
1810         dest.m10 = nm00 * m_sinZ + nm10 * cosZ;
1811         dest.m11 = nm01 * m_sinZ + nm11 * cosZ;
1812         dest.m12 = nm02 * m_sinZ + nm12 * cosZ;
1813         return dest;
1814     }
1815 
1816     /**
1817      * Apply rotation to this matrix by rotating the given amount of radians
1818      * about the given axis specified as x, y and z components.
1819      * <p>
1820      * The axis described by the three components needs to be a unit vector.
1821      * <p>
1822      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1823      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1824      * When used with a left-handed coordinate system, the rotation is clockwise.
1825      * <p>
1826      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
1827      * then the new matrix will be <code>M * R</code>. So when transforming a
1828      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>
1829      * , the rotation will be applied first!
1830      * <p>
1831      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
1832      * 
1833      * @param ang
1834      *            the angle in radians
1835      * @param x
1836      *            the x component of the axis
1837      * @param y
1838      *            the y component of the axis
1839      * @param z
1840      *            the z component of the axis
1841      * @return this
1842      */
1843     ref public Matrix3d rotate(double ang, double x, double y, double z) return {
1844         rotate(ang, x, y, z, this);
1845         return this;
1846     }
1847 
1848     public Matrix3d rotate(double ang, double x, double y, double z, ref Matrix3d dest) {
1849         double s = Math.sin(ang);
1850         double c = Math.cosFromSin(s, ang);
1851         double C = 1.0 - c;
1852 
1853         // rotation matrix elements:
1854         // m30, m31, m32, m03, m13, m23 = 0
1855         double xx = x * x, xy = x * y, xz = x * z;
1856         double yy = y * y, yz = y * z;
1857         double zz = z * z;
1858         double rm00 = xx * C + c;
1859         double rm01 = xy * C + z * s;
1860         double rm02 = xz * C - y * s;
1861         double rm10 = xy * C - z * s;
1862         double rm11 = yy * C + c;
1863         double rm12 = yz * C + x * s;
1864         double rm20 = xz * C + y * s;
1865         double rm21 = yz * C - x * s;
1866         double rm22 = zz * C + c;
1867 
1868         // add temporaries for dependent values
1869         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
1870         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
1871         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
1872         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
1873         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
1874         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
1875         // set non-dependent values directly
1876         dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
1877         dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
1878         dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
1879         // set other values
1880         dest.m00 = nm00;
1881         dest.m01 = nm01;
1882         dest.m02 = nm02;
1883         dest.m10 = nm10;
1884         dest.m11 = nm11;
1885         dest.m12 = nm12;
1886         return dest;
1887     }
1888 
1889     /**
1890      * Pre-multiply a rotation to this matrix by rotating the given amount of radians
1891      * about the specified <code>(x, y, z)</code> axis and store the result in <code>dest</code>.
1892      * <p>
1893      * The axis described by the three components needs to be a unit vector.
1894      * <p>
1895      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1896      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1897      * When used with a left-handed coordinate system, the rotation is clockwise.
1898      * <p>
1899      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
1900      * then the new matrix will be <code>R * M</code>. So when transforming a
1901      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
1902      * rotation will be applied last!
1903      * <p>
1904      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
1905      * transformation, use {@link #rotation(double, double, double, double) rotation()}.
1906      * <p>
1907      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
1908      * 
1909      * @see #rotation(double, double, double, double)
1910      * 
1911      * @param ang
1912      *            the angle in radians
1913      * @param x
1914      *            the x component of the axis
1915      * @param y
1916      *            the y component of the axis
1917      * @param z
1918      *            the z component of the axis
1919      * @param dest
1920      *            will hold the result
1921      * @return dest
1922      */
1923     public Matrix3d rotateLocal(double ang, double x, double y, double z, ref Matrix3d dest) {
1924         double s = Math.sin(ang);
1925         double c = Math.cosFromSin(s, ang);
1926         double C = 1.0 - c;
1927         double xx = x * x, xy = x * y, xz = x * z;
1928         double yy = y * y, yz = y * z;
1929         double zz = z * z;
1930         double lm00 = xx * C + c;
1931         double lm01 = xy * C + z * s;
1932         double lm02 = xz * C - y * s;
1933         double lm10 = xy * C - z * s;
1934         double lm11 = yy * C + c;
1935         double lm12 = yz * C + x * s;
1936         double lm20 = xz * C + y * s;
1937         double lm21 = yz * C - x * s;
1938         double lm22 = zz * C + c;
1939         double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
1940         double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
1941         double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
1942         double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
1943         double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
1944         double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
1945         double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
1946         double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
1947         double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
1948         dest.m00 = nm00;
1949         dest.m01 = nm01;
1950         dest.m02 = nm02;
1951         dest.m10 = nm10;
1952         dest.m11 = nm11;
1953         dest.m12 = nm12;
1954         dest.m20 = nm20;
1955         dest.m21 = nm21;
1956         dest.m22 = nm22;
1957         return dest;
1958     }
1959 
1960     /**
1961      * Pre-multiply a rotation to this matrix by rotating the given amount of radians
1962      * about the specified <code>(x, y, z)</code> axis.
1963      * <p>
1964      * The axis described by the three components needs to be a unit vector.
1965      * <p>
1966      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1967      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1968      * When used with a left-handed coordinate system, the rotation is clockwise.
1969      * <p>
1970      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
1971      * then the new matrix will be <code>R * M</code>. So when transforming a
1972      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
1973      * rotation will be applied last!
1974      * <p>
1975      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
1976      * transformation, use {@link #rotation(double, double, double, double) rotation()}.
1977      * <p>
1978      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
1979      * 
1980      * @see #rotation(double, double, double, double)
1981      * 
1982      * @param ang
1983      *            the angle in radians
1984      * @param x
1985      *            the x component of the axis
1986      * @param y
1987      *            the y component of the axis
1988      * @param z
1989      *            the z component of the axis
1990      * @return this
1991      */
1992     ref public Matrix3d rotateLocal(double ang, double x, double y, double z) return {
1993         rotateLocal(ang, x, y, z, this);
1994         return this;
1995     }
1996 
1997     /**
1998      * Pre-multiply a rotation around the X axis to this matrix by rotating the given amount of radians
1999      * about the X axis and store the result in <code>dest</code>.
2000      * <p>
2001      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2002      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2003      * When used with a left-handed coordinate system, the rotation is clockwise.
2004      * <p>
2005      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2006      * then the new matrix will be <code>R * M</code>. So when transforming a
2007      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
2008      * rotation will be applied last!
2009      * <p>
2010      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
2011      * transformation, use {@link #rotationX(double) rotationx}.
2012      * <p>
2013      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2014      * 
2015      * @see #rotationX(double)
2016      * 
2017      * @param ang
2018      *            the angle in radians to rotate about the X axis
2019      * @param dest
2020      *            will hold the result
2021      * @return dest
2022      */
2023     public Matrix3d rotateLocalX(double ang, ref Matrix3d dest) {
2024         double sin = Math.sin(ang);
2025         double cos = Math.cosFromSin(sin, ang);
2026         double nm01 = cos * m01 - sin * m02;
2027         double nm02 = sin * m01 + cos * m02;
2028         double nm11 = cos * m11 - sin * m12;
2029         double nm12 = sin * m11 + cos * m12;
2030         double nm21 = cos * m21 - sin * m22;
2031         double nm22 = sin * m21 + cos * m22;
2032         dest.m00 = m00;
2033         dest.m01 = nm01;
2034         dest.m02 = nm02;
2035         dest.m10 = m10;
2036         dest.m11 = nm11;
2037         dest.m12 = nm12;
2038         dest.m20 = m20;
2039         dest.m21 = nm21;
2040         dest.m22 = nm22;
2041         return dest;
2042     }
2043 
2044     /**
2045      * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the X axis.
2046      * <p>
2047      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2048      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2049      * When used with a left-handed coordinate system, the rotation is clockwise.
2050      * <p>
2051      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2052      * then the new matrix will be <code>R * M</code>. So when transforming a
2053      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
2054      * rotation will be applied last!
2055      * <p>
2056      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
2057      * transformation, use {@link #rotationX(double) rotationx}.
2058      * <p>
2059      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2060      * 
2061      * @see #rotationX(double)
2062      * 
2063      * @param ang
2064      *            the angle in radians to rotate about the X axis
2065      * @return this
2066      */
2067     ref public Matrix3d rotateLocalX(double ang) return {
2068         rotateLocalX(ang, this);
2069         return this;
2070     }
2071 
2072     /**
2073      * Pre-multiply a rotation around the Y axis to this matrix by rotating the given amount of radians
2074      * about the Y axis and store the result in <code>dest</code>.
2075      * <p>
2076      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2077      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2078      * When used with a left-handed coordinate system, the rotation is clockwise.
2079      * <p>
2080      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2081      * then the new matrix will be <code>R * M</code>. So when transforming a
2082      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
2083      * rotation will be applied last!
2084      * <p>
2085      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
2086      * transformation, use {@link #rotationY(double) rotationy}.
2087      * <p>
2088      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2089      * 
2090      * @see #rotationY(double)
2091      * 
2092      * @param ang
2093      *            the angle in radians to rotate about the Y axis
2094      * @param dest
2095      *            will hold the result
2096      * @return dest
2097      */
2098     public Matrix3d rotateLocalY(double ang, ref Matrix3d dest) {
2099         double sin = Math.sin(ang);
2100         double cos = Math.cosFromSin(sin, ang);
2101         double nm00 =  cos * m00 + sin * m02;
2102         double nm02 = -sin * m00 + cos * m02;
2103         double nm10 =  cos * m10 + sin * m12;
2104         double nm12 = -sin * m10 + cos * m12;
2105         double nm20 =  cos * m20 + sin * m22;
2106         double nm22 = -sin * m20 + cos * m22;
2107         dest.m00 = nm00;
2108         dest.m01 = m01;
2109         dest.m02 = nm02;
2110         dest.m10 = nm10;
2111         dest.m11 = m11;
2112         dest.m12 = nm12;
2113         dest.m20 = nm20;
2114         dest.m21 = m21;
2115         dest.m22 = nm22;
2116         return dest;
2117     }
2118 
2119     /**
2120      * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Y axis.
2121      * <p>
2122      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2123      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2124      * When used with a left-handed coordinate system, the rotation is clockwise.
2125      * <p>
2126      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2127      * then the new matrix will be <code>R * M</code>. So when transforming a
2128      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
2129      * rotation will be applied last!
2130      * <p>
2131      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
2132      * transformation, use {@link #rotationY(double) rotationy}.
2133      * <p>
2134      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2135      * 
2136      * @see #rotationY(double)
2137      * 
2138      * @param ang
2139      *            the angle in radians to rotate about the Y axis
2140      * @return this
2141      */
2142     ref public Matrix3d rotateLocalY(double ang) return {
2143         rotateLocalY(ang, this);
2144         return this;
2145     }
2146 
2147     /**
2148      * Pre-multiply a rotation around the Z axis to this matrix by rotating the given amount of radians
2149      * about the Z axis and store the result in <code>dest</code>.
2150      * <p>
2151      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2152      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2153      * When used with a left-handed coordinate system, the rotation is clockwise.
2154      * <p>
2155      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2156      * then the new matrix will be <code>R * M</code>. So when transforming a
2157      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
2158      * rotation will be applied last!
2159      * <p>
2160      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
2161      * transformation, use {@link #rotationZ(double) rotationz}.
2162      * <p>
2163      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2164      * 
2165      * @see #rotationZ(double)
2166      * 
2167      * @param ang
2168      *            the angle in radians to rotate about the Z axis
2169      * @param dest
2170      *            will hold the result
2171      * @return dest
2172      */
2173     public Matrix3d rotateLocalZ(double ang, ref Matrix3d dest) {
2174         double sin = Math.sin(ang);
2175         double cos = Math.cosFromSin(sin, ang);
2176         double nm00 = cos * m00 - sin * m01;
2177         double nm01 = sin * m00 + cos * m01;
2178         double nm10 = cos * m10 - sin * m11;
2179         double nm11 = sin * m10 + cos * m11;
2180         double nm20 = cos * m20 - sin * m21;
2181         double nm21 = sin * m20 + cos * m21;
2182         dest.m00 = nm00;
2183         dest.m01 = nm01;
2184         dest.m02 = m02;
2185         dest.m10 = nm10;
2186         dest.m11 = nm11;
2187         dest.m12 = m12;
2188         dest.m20 = nm20;
2189         dest.m21 = nm21;
2190         dest.m22 = m22;
2191         return dest;
2192     }
2193 
2194     /**
2195      * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Z axis.
2196      * <p>
2197      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2198      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2199      * When used with a left-handed coordinate system, the rotation is clockwise.
2200      * <p>
2201      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2202      * then the new matrix will be <code>R * M</code>. So when transforming a
2203      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
2204      * rotation will be applied last!
2205      * <p>
2206      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
2207      * transformation, use {@link #rotationZ(double) rotationy}.
2208      * <p>
2209      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2210      * 
2211      * @see #rotationY(double)
2212      * 
2213      * @param ang
2214      *            the angle in radians to rotate about the Z axis
2215      * @return this
2216      */
2217     ref public Matrix3d rotateLocalZ(double ang) return {
2218         rotateLocalZ(ang, this);
2219         return this;
2220     }
2221 
2222     /**
2223      * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix and store
2224      * the result in <code>dest</code>.
2225      * <p>
2226      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2227      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2228      * When used with a left-handed coordinate system, the rotation is clockwise.
2229      * <p>
2230      * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion,
2231      * then the new matrix will be <code>Q * M</code>. So when transforming a
2232      * vector <code>v</code> with the new matrix by using <code>Q * M * v</code>,
2233      * the quaternion rotation will be applied last!
2234      * <p>
2235      * In order to set the matrix to a rotation transformation without pre-multiplying,
2236      * use {@link #rotation(Quaterniond)}.
2237      * <p>
2238      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
2239      * 
2240      * @see #rotation(Quaterniond)
2241      * 
2242      * @param quat
2243      *          the {@link Quaterniond}
2244      * @param dest
2245      *          will hold the result
2246      * @return dest
2247      */
2248     public Matrix3d rotateLocal(Quaterniond quat, ref Matrix3d dest) {
2249         double w2 = quat.w * quat.w, x2 = quat.x * quat.x;
2250         double y2 = quat.y * quat.y, z2 = quat.z * quat.z;
2251         double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy;
2252         double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw;
2253         double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw;
2254         double lm00 = w2 + x2 - z2 - y2;
2255         double lm01 = dxy + dzw;
2256         double lm02 = dxz - dyw;
2257         double lm10 = dxy - dzw;
2258         double lm11 = y2 - z2 + w2 - x2;
2259         double lm12 = dyz + dxw;
2260         double lm20 = dyw + dxz;
2261         double lm21 = dyz - dxw;
2262         double lm22 = z2 - y2 - x2 + w2;
2263         double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
2264         double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
2265         double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
2266         double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
2267         double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
2268         double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
2269         double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
2270         double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
2271         double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
2272         dest.m00 = nm00;
2273         dest.m01 = nm01;
2274         dest.m02 = nm02;
2275         dest.m10 = nm10;
2276         dest.m11 = nm11;
2277         dest.m12 = nm12;
2278         dest.m20 = nm20;
2279         dest.m21 = nm21;
2280         dest.m22 = nm22;
2281         return dest;
2282     }
2283 
2284     /**
2285      * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix.
2286      * <p>
2287      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2288      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2289      * When used with a left-handed coordinate system, the rotation is clockwise.
2290      * <p>
2291      * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion,
2292      * then the new matrix will be <code>Q * M</code>. So when transforming a
2293      * vector <code>v</code> with the new matrix by using <code>Q * M * v</code>,
2294      * the quaternion rotation will be applied last!
2295      * <p>
2296      * In order to set the matrix to a rotation transformation without pre-multiplying,
2297      * use {@link #rotation(Quaterniond)}.
2298      * <p>
2299      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
2300      * 
2301      * @see #rotation(Quaterniond)
2302      * 
2303      * @param quat
2304      *          the {@link Quaterniond}
2305      * @return this
2306      */
2307     ref public Matrix3d rotateLocal(Quaterniond quat) return {
2308         rotateLocal(quat, this);
2309         return this;
2310     }
2311 
2312 
2313     /**
2314      * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix.
2315      * <p>
2316      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2317      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2318      * When used with a left-handed coordinate system, the rotation is clockwise.
2319      * <p>
2320      * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion,
2321      * then the new matrix will be <code>M * Q</code>. So when transforming a
2322      * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>,
2323      * the quaternion rotation will be applied first!
2324      * <p>
2325      * In order to set the matrix to a rotation transformation without post-multiplying,
2326      * use {@link #rotation(Quaterniond)}.
2327      * <p>
2328      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
2329      * 
2330      * @see #rotation(Quaterniond)
2331      * 
2332      * @param quat
2333      *          the {@link Quaterniond}
2334      * @return this
2335      */
2336     ref public Matrix3d rotate(Quaterniond quat) return {
2337         rotate(quat, this);
2338         return this;
2339     }
2340 
2341     /**
2342      * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix and store
2343      * the result in <code>dest</code>.
2344      * <p>
2345      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2346      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2347      * When used with a left-handed coordinate system, the rotation is clockwise.
2348      * <p>
2349      * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion,
2350      * then the new matrix will be <code>M * Q</code>. So when transforming a
2351      * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>,
2352      * the quaternion rotation will be applied first!
2353      * <p>
2354      * In order to set the matrix to a rotation transformation without post-multiplying,
2355      * use {@link #rotation(Quaterniond)}.
2356      * <p>
2357      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
2358      * 
2359      * @see #rotation(Quaterniond)
2360      * 
2361      * @param quat
2362      *          the {@link Quaterniond}
2363      * @param dest
2364      *          will hold the result
2365      * @return dest
2366      */
2367     public Matrix3d rotate(Quaterniond quat, ref Matrix3d dest) {
2368         double w2 = quat.w * quat.w, x2 = quat.x * quat.x;
2369         double y2 = quat.y * quat.y, z2 = quat.z * quat.z;
2370         double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy;
2371         double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw;
2372         double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw;
2373         double rm00 = w2 + x2 - z2 - y2;
2374         double rm01 = dxy + dzw;
2375         double rm02 = dxz - dyw;
2376         double rm10 = dxy - dzw;
2377         double rm11 = y2 - z2 + w2 - x2;
2378         double rm12 = dyz + dxw;
2379         double rm20 = dyw + dxz;
2380         double rm21 = dyz - dxw;
2381         double rm22 = z2 - y2 - x2 + w2;
2382         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
2383         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
2384         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
2385         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
2386         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
2387         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
2388         dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
2389         dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
2390         dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
2391         dest.m00 = nm00;
2392         dest.m01 = nm01;
2393         dest.m02 = nm02;
2394         dest.m10 = nm10;
2395         dest.m11 = nm11;
2396         dest.m12 = nm12;
2397         return dest;
2398     }
2399 
2400     /**
2401      * Apply a rotation transformation, rotating about the given {@link AxisAngle4d}, to this matrix.
2402      * <p>
2403      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2404      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2405      * When used with a left-handed coordinate system, the rotation is clockwise.
2406      * <p>
2407      * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given {@link AxisAngle4d},
2408      * then the new matrix will be <code>M * A</code>. So when transforming a
2409      * vector <code>v</code> with the new matrix by using <code>M * A * v</code>,
2410      * the {@link AxisAngle4d} rotation will be applied first!
2411      * <p>
2412      * In order to set the matrix to a rotation transformation without post-multiplying,
2413      * use {@link #rotation(AxisAngle4d)}.
2414      * <p>
2415      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a>
2416      * 
2417      * @see #rotate(double, double, double, double)
2418      * @see #rotation(AxisAngle4d)
2419      * 
2420      * @param axisAngle
2421      *          the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
2422      * @return this
2423      */
2424     ref public Matrix3d rotate(AxisAngle4d axisAngle) return {
2425         return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
2426     }
2427 
2428     /**
2429      * Apply a rotation transformation, rotating about the given {@link AxisAngle4d} and store the result in <code>dest</code>.
2430      * <p>
2431      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2432      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2433      * When used with a left-handed coordinate system, the rotation is clockwise.
2434      * <p>
2435      * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given {@link AxisAngle4d},
2436      * then the new matrix will be <code>M * A</code>. So when transforming a
2437      * vector <code>v</code> with the new matrix by using <code>M * A * v</code>,
2438      * the {@link AxisAngle4d} rotation will be applied first!
2439      * <p>
2440      * In order to set the matrix to a rotation transformation without post-multiplying,
2441      * use {@link #rotation(AxisAngle4d)}.
2442      * <p>
2443      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a>
2444      * 
2445      * @see #rotate(double, double, double, double)
2446      * @see #rotation(AxisAngle4d)
2447      * 
2448      * @param axisAngle
2449      *          the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
2450      * @param dest
2451      *          will hold the result
2452      * @return dest
2453      */
2454     public Matrix3d rotate(AxisAngle4d axisAngle, ref Matrix3d dest) {
2455         return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z, dest);
2456     }
2457 
2458     /**
2459      * Apply a rotation transformation, rotating the given radians about the specified axis, to this matrix.
2460      * <p>
2461      * The axis described by the <code>axis</code> vector needs to be a unit vector.
2462      * <p>
2463      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2464      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2465      * When used with a left-handed coordinate system, the rotation is clockwise.
2466      * <p>
2467      * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given angle and axis,
2468      * then the new matrix will be <code>M * A</code>. So when transforming a
2469      * vector <code>v</code> with the new matrix by using <code>M * A * v</code>,
2470      * the axis-angle rotation will be applied first!
2471      * <p>
2472      * In order to set the matrix to a rotation transformation without post-multiplying,
2473      * use {@link #rotation(double, Vector3d)}.
2474      * <p>
2475      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a>
2476      * 
2477      * @see #rotate(double, double, double, double)
2478      * @see #rotation(double, Vector3d)
2479      * 
2480      * @param angle
2481      *          the angle in radians
2482      * @param axis
2483      *          the rotation axis (needs to be {@link Vector3d#normalize() normalized})
2484      * @return this
2485      */
2486     ref public Matrix3d rotate(double angle, Vector3d axis) return {
2487         return rotate(angle, axis.x, axis.y, axis.z);
2488     }
2489 
2490     /**
2491      * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in <code>dest</code>.
2492      * <p>
2493      * The axis described by the <code>axis</code> vector needs to be a unit vector.
2494      * <p>
2495      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2496      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2497      * When used with a left-handed coordinate system, the rotation is clockwise.
2498      * <p>
2499      * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given axis and angle,
2500      * then the new matrix will be <code>M * A</code>. So when transforming a
2501      * vector <code>v</code> with the new matrix by using <code>M * A * v</code>,
2502      * the axis-angle rotation will be applied first!
2503      * <p>
2504      * In order to set the matrix to a rotation transformation without post-multiplying,
2505      * use {@link #rotation(double, Vector3d)}.
2506      * <p>
2507      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a>
2508      * 
2509      * @see #rotate(double, double, double, double)
2510      * @see #rotation(double, Vector3d)
2511      * 
2512      * @param angle
2513      *          the angle in radians
2514      * @param axis
2515      *          the rotation axis (needs to be {@link Vector3d#normalize() normalized})
2516      * @param dest
2517      *          will hold the result
2518      * @return dest
2519      */
2520     public Matrix3d rotate(double angle, Vector3d axis, ref Matrix3d dest) {
2521         return rotate(angle, axis.x, axis.y, axis.z, dest);
2522     }
2523 
2524     public Vector3d getRow(int row, ref Vector3d dest) {
2525         switch (row) {
2526         case 0:
2527             return dest.set(m00, m10, m20);
2528         case 1:
2529             return dest.set(m01, m11, m21);
2530         case 2:
2531             return dest.set(m02, m12, m22);
2532         default:
2533             return dest;
2534         }
2535     }
2536 
2537     /**
2538      * Set the row at the given <code>row</code> index, starting with <code>0</code>.
2539      * 
2540      * @param row
2541      *          the row index in <code>[0..2]</code>
2542      * @param src
2543      *          the row components to set
2544      * @return this
2545      * @throws IndexOutOfBoundsException if <code>row</code> is not in <code>[0..2]</code>
2546      */
2547     ref public Matrix3d setRow(int row, Vector3d src) return {
2548         return setRow(row, src.x, src.y, src.z);
2549     }
2550 
2551     /**
2552      * Set the row at the given <code>row</code> index, starting with <code>0</code>.
2553      * 
2554      * @param row
2555      *          the column index in <code>[0..2]</code>
2556      * @param x
2557      *          the first element in the row
2558      * @param y
2559      *          the second element in the row
2560      * @param z
2561      *          the third element in the row
2562      * @return this
2563      * @throws IndexOutOfBoundsException if <code>row</code> is not in <code>[0..2]</code>
2564      */
2565     ref public Matrix3d setRow(int row, double x, double y, double z) return {
2566         switch (row) {
2567         case 0:
2568             this.m00 = x;
2569             this.m10 = y;
2570             this.m20 = z;
2571             break;
2572         case 1:
2573             this.m01 = x;
2574             this.m11 = y;
2575             this.m21 = z;
2576             break;
2577         case 2:
2578             this.m02 = x;
2579             this.m12 = y;
2580             this.m22 = z;
2581             break;
2582         default: {}
2583         }
2584         return this;
2585     }
2586 
2587     public Vector3d getColumn(int column, ref Vector3d dest){
2588         switch (column) {
2589         case 0:
2590             return dest.set(m00, m01, m02);
2591         case 1:
2592             return dest.set(m10, m11, m12);
2593         case 2:
2594             return dest.set(m20, m21, m22);
2595         default:
2596             return dest;
2597         }
2598     }
2599 
2600     /**
2601      * Set the column at the given <code>column</code> index, starting with <code>0</code>.
2602      * 
2603      * @param column
2604      *          the column index in <code>[0..2]</code>
2605      * @param src
2606      *          the column components to set
2607      * @return this
2608      * @throws IndexOutOfBoundsException if <code>column</code> is not in <code>[0..2]</code>
2609      */
2610     ref public Matrix3d setColumn(int column, Vector3d src) return {
2611         return setColumn(column, src.x, src.y, src.z);
2612     }
2613 
2614     /**
2615      * Set the column at the given <code>column</code> index, starting with <code>0</code>.
2616      * 
2617      * @param column
2618      *          the column index in <code>[0..2]</code>
2619      * @param x
2620      *          the first element in the column
2621      * @param y
2622      *          the second element in the column
2623      * @param z
2624      *          the third element in the column
2625      * @return this
2626      * @throws IndexOutOfBoundsException if <code>column</code> is not in <code>[0..2]</code>
2627      */
2628     ref public Matrix3d setColumn(int column, double x, double y, double z) return {
2629         switch (column) {
2630         case 0:
2631             this.m00 = x;
2632             this.m01 = y;
2633             this.m02 = z;
2634             break;
2635         case 1:
2636             this.m10 = x;
2637             this.m11 = y;
2638             this.m12 = z;
2639             break;
2640         case 2:
2641             this.m20 = x;
2642             this.m21 = y;
2643             this.m22 = z;
2644             break;
2645         default: {}
2646         }
2647         return this;
2648     }
2649 
2650     public double get(int column, int row) {
2651         return MemUtil.get(this, column, row);
2652     }
2653 
2654     /**
2655      * Set the matrix element at the given column and row to the specified value.
2656      * 
2657      * @param column
2658      *          the colum index in <code>[0..2]</code>
2659      * @param row
2660      *          the row index in <code>[0..2]</code>
2661      * @param value
2662      *          the value
2663      * @return this
2664      */
2665     ref public Matrix3d set(int column, int row, double value) return {
2666         MemUtil.set(this, column, row, value);
2667         return this;
2668         
2669     }
2670 
2671     public double getRowColumn(int row, int column) {
2672         return MemUtil.get(this, column, row);
2673     }
2674 
2675     /**
2676      * Set the matrix element at the given row and column to the specified value.
2677      * 
2678      * @param row
2679      *          the row index in <code>[0..2]</code>
2680      * @param column
2681      *          the colum index in <code>[0..2]</code>
2682      * @param value
2683      *          the value
2684      * @return this
2685      */
2686     ref public Matrix3d setRowColumn(int row, int column, double value) return {
2687         MemUtil.set(this, column, row, value);
2688         return this;
2689     }
2690 
2691     /**
2692      * Set <code>this</code> matrix to its own normal matrix.
2693      * <p>
2694      * The normal matrix of <code>m</code> is the transpose of the inverse of <code>m</code>.
2695      * <p>
2696      * Please note that, if <code>this</code> is an orthogonal matrix or a matrix whose columns are orthogonal vectors, 
2697      * then this method <i>need not</i> be invoked, since in that case <code>this</code> itself is its normal matrix.
2698      * In this case, use {@link #set(Matrix3d)} to set a given Matrix3f to this matrix.
2699      * 
2700      * @see #set(Matrix3d)
2701      * 
2702      * @return this
2703      */
2704     ref public Matrix3d normal() return {
2705         normal(this);
2706         return this;
2707     }
2708 
2709     /**
2710      * Compute a normal matrix from <code>this</code> matrix and store it into <code>dest</code>.
2711      * <p>
2712      * The normal matrix of <code>m</code> is the transpose of the inverse of <code>m</code>.
2713      * <p>
2714      * Please note that, if <code>this</code> is an orthogonal matrix or a matrix whose columns are orthogonal vectors, 
2715      * then this method <i>need not</i> be invoked, since in that case <code>this</code> itself is its normal matrix.
2716      * In this case, use {@link #set(Matrix3d)} to set a given Matrix3d to this matrix.
2717      * 
2718      * @see #set(Matrix3d)
2719      * 
2720      * @param dest
2721      *             will hold the result
2722      * @return dest
2723      */
2724     public Matrix3d normal(ref Matrix3d dest) {
2725         double m00m11 = m00 * m11;
2726         double m01m10 = m01 * m10;
2727         double m02m10 = m02 * m10;
2728         double m00m12 = m00 * m12;
2729         double m01m12 = m01 * m12;
2730         double m02m11 = m02 * m11;
2731         double det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20;
2732         double s = 1.0 / det;
2733         /* Invert and transpose in one go */
2734         double nm00 = (m11 * m22 - m21 * m12) * s;
2735         double nm01 = (m20 * m12 - m10 * m22) * s;
2736         double nm02 = (m10 * m21 - m20 * m11) * s;
2737         double nm10 = (m21 * m02 - m01 * m22) * s;
2738         double nm11 = (m00 * m22 - m20 * m02) * s;
2739         double nm12 = (m20 * m01 - m00 * m21) * s;
2740         double nm20 = (m01m12 - m02m11) * s;
2741         double nm21 = (m02m10 - m00m12) * s;
2742         double nm22 = (m00m11 - m01m10) * s;
2743         dest.m00 = nm00;
2744         dest.m01 = nm01;
2745         dest.m02 = nm02;
2746         dest.m10 = nm10;
2747         dest.m11 = nm11;
2748         dest.m12 = nm12;
2749         dest.m20 = nm20;
2750         dest.m21 = nm21;
2751         dest.m22 = nm22;
2752         return dest;
2753     }
2754 
2755     /**
2756      * Compute the cofactor matrix of <code>this</code>.
2757      * <p>
2758      * The cofactor matrix can be used instead of {@link #normal()} to transform normals
2759      * when the orientation of the normals with respect to the surface should be preserved.
2760      * 
2761      * @return this
2762      */
2763     ref public Matrix3d cofactor() return {
2764         cofactor(this);
2765         return this;
2766     }
2767 
2768     /**
2769      * Compute the cofactor matrix of <code>this</code> and store it into <code>dest</code>.
2770      * <p>
2771      * The cofactor matrix can be used instead of {@link #normal(Matrix3d)} to transform normals
2772      * when the orientation of the normals with respect to the surface should be preserved.
2773      * 
2774      * @param dest
2775      *             will hold the result
2776      * @return dest
2777      */
2778     public Matrix3d cofactor(ref Matrix3d dest) {
2779         double nm00 = m11 * m22 - m21 * m12;
2780         double nm01 = m20 * m12 - m10 * m22;
2781         double nm02 = m10 * m21 - m20 * m11;
2782         double nm10 = m21 * m02 - m01 * m22;
2783         double nm11 = m00 * m22 - m20 * m02;
2784         double nm12 = m20 * m01 - m00 * m21;
2785         double nm20 = m01 * m12 - m11 * m02;
2786         double nm21 = m02 * m10 - m12 * m00;
2787         double nm22 = m00 * m11 - m10 * m01;
2788         dest.m00 = nm00;
2789         dest.m01 = nm01;
2790         dest.m02 = nm02;
2791         dest.m10 = nm10;
2792         dest.m11 = nm11;
2793         dest.m12 = nm12;
2794         dest.m20 = nm20;
2795         dest.m21 = nm21;
2796         dest.m22 = nm22;
2797         return dest;
2798     }
2799 
2800     /**
2801      * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code>. 
2802      * <p>
2803      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix,
2804      * then the new matrix will be <code>M * L</code>. So when transforming a
2805      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the
2806      * lookalong rotation transformation will be applied first!
2807      * <p>
2808      * In order to set the matrix to a lookalong transformation without post-multiplying it,
2809      * use {@link #setLookAlong(Vector3d, Vector3d) setLookAlong()}.
2810      * 
2811      * @see #lookAlong(double, double, double, double, double, double)
2812      * @see #setLookAlong(Vector3d, Vector3d)
2813      * 
2814      * @param dir
2815      *            the direction in space to look along
2816      * @param up
2817      *            the direction of 'up'
2818      * @return this
2819      */
2820     ref public Matrix3d lookAlong(Vector3d dir, Vector3d up) return {
2821         lookAlong(dir.x, dir.y, dir.z, up.x, up.y, up.z, this);
2822         return this;
2823     }
2824 
2825     /**
2826      * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code>
2827      * and store the result in <code>dest</code>. 
2828      * <p>
2829      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix,
2830      * then the new matrix will be <code>M * L</code>. So when transforming a
2831      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the
2832      * lookalong rotation transformation will be applied first!
2833      * <p>
2834      * In order to set the matrix to a lookalong transformation without post-multiplying it,
2835      * use {@link #setLookAlong(Vector3d, Vector3d) setLookAlong()}.
2836      * 
2837      * @see #lookAlong(double, double, double, double, double, double)
2838      * @see #setLookAlong(Vector3d, Vector3d)
2839      * 
2840      * @param dir
2841      *            the direction in space to look along
2842      * @param up
2843      *            the direction of 'up'
2844      * @param dest
2845      *            will hold the result
2846      * @return dest
2847      */
2848     public Matrix3d lookAlong(Vector3d dir, Vector3d up, ref Matrix3d dest) {
2849         return lookAlong(dir.x, dir.y, dir.z, up.x, up.y, up.z, dest);
2850     }
2851 
2852     /**
2853      * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code>
2854      * and store the result in <code>dest</code>. 
2855      * <p>
2856      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix,
2857      * then the new matrix will be <code>M * L</code>. So when transforming a
2858      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the
2859      * lookalong rotation transformation will be applied first!
2860      * <p>
2861      * In order to set the matrix to a lookalong transformation without post-multiplying it,
2862      * use {@link #setLookAlong(double, double, double, double, double, double) setLookAlong()}
2863      * 
2864      * @see #setLookAlong(double, double, double, double, double, double)
2865      * 
2866      * @param dirX
2867      *              the x-coordinate of the direction to look along
2868      * @param dirY
2869      *              the y-coordinate of the direction to look along
2870      * @param dirZ
2871      *              the z-coordinate of the direction to look along
2872      * @param upX
2873      *              the x-coordinate of the up vector
2874      * @param upY
2875      *              the y-coordinate of the up vector
2876      * @param upZ
2877      *              the z-coordinate of the up vector
2878      * @param dest
2879      *              will hold the result
2880      * @return dest
2881      */
2882     public Matrix3d lookAlong(double dirX, double dirY, double dirZ,
2883                               double upX, double upY, double upZ, ref Matrix3d dest) {
2884         // Normalize direction
2885         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
2886         dirX *= -invDirLength;
2887         dirY *= -invDirLength;
2888         dirZ *= -invDirLength;
2889         // left = up x direction
2890         double leftX, leftY, leftZ;
2891         leftX = upY * dirZ - upZ * dirY;
2892         leftY = upZ * dirX - upX * dirZ;
2893         leftZ = upX * dirY - upY * dirX;
2894         // normalize left
2895         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
2896         leftX *= invLeftLength;
2897         leftY *= invLeftLength;
2898         leftZ *= invLeftLength;
2899         // up = direction x left
2900         double upnX = dirY * leftZ - dirZ * leftY;
2901         double upnY = dirZ * leftX - dirX * leftZ;
2902         double upnZ = dirX * leftY - dirY * leftX;
2903 
2904         // calculate right matrix elements
2905         double rm00 = leftX;
2906         double rm01 = upnX;
2907         double rm02 = dirX;
2908         double rm10 = leftY;
2909         double rm11 = upnY;
2910         double rm12 = dirY;
2911         double rm20 = leftZ;
2912         double rm21 = upnZ;
2913         double rm22 = dirZ;
2914 
2915         // perform optimized matrix multiplication
2916         // introduce temporaries for dependent results
2917         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
2918         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
2919         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
2920         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
2921         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
2922         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
2923         dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
2924         dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
2925         dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
2926         // set the rest of the matrix elements
2927         dest.m00 = nm00;
2928         dest.m01 = nm01;
2929         dest.m02 = nm02;
2930         dest.m10 = nm10;
2931         dest.m11 = nm11;
2932         dest.m12 = nm12;
2933         return dest;
2934     }
2935 
2936     /**
2937      * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code>. 
2938      * <p>
2939      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix,
2940      * then the new matrix will be <code>M * L</code>. So when transforming a
2941      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the
2942      * lookalong rotation transformation will be applied first!
2943      * <p>
2944      * In order to set the matrix to a lookalong transformation without post-multiplying it,
2945      * use {@link #setLookAlong(double, double, double, double, double, double) setLookAlong()}
2946      * 
2947      * @see #setLookAlong(double, double, double, double, double, double)
2948      * 
2949      * @param dirX
2950      *              the x-coordinate of the direction to look along
2951      * @param dirY
2952      *              the y-coordinate of the direction to look along
2953      * @param dirZ
2954      *              the z-coordinate of the direction to look along
2955      * @param upX
2956      *              the x-coordinate of the up vector
2957      * @param upY
2958      *              the y-coordinate of the up vector
2959      * @param upZ
2960      *              the z-coordinate of the up vector
2961      * @return this
2962      */
2963     ref public Matrix3d lookAlong(double dirX, double dirY, double dirZ,
2964                               double upX, double upY, double upZ) return {
2965         lookAlong(dirX, dirY, dirZ, upX, upY, upZ, this);
2966         return this;
2967     }
2968 
2969     /**
2970      * Set this matrix to a rotation transformation to make <code>-z</code>
2971      * point along <code>dir</code>.
2972      * <p>
2973      * In order to apply the lookalong transformation to any previous existing transformation,
2974      * use {@link #lookAlong(Vector3d, Vector3d)}.
2975      * 
2976      * @see #setLookAlong(Vector3d, Vector3d)
2977      * @see #lookAlong(Vector3d, Vector3d)
2978      * 
2979      * @param dir
2980      *            the direction in space to look along
2981      * @param up
2982      *            the direction of 'up'
2983      * @return this
2984      */
2985     ref public Matrix3d setLookAlong(Vector3d dir, Vector3d up) return {
2986         return setLookAlong(dir.x, dir.y, dir.z, up.x, up.y, up.z);
2987     }
2988 
2989     /**
2990      * Set this matrix to a rotation transformation to make <code>-z</code>
2991      * point along <code>dir</code>.
2992      * <p>
2993      * In order to apply the lookalong transformation to any previous existing transformation,
2994      * use {@link #lookAlong(double, double, double, double, double, double) lookAlong()}
2995      * 
2996      * @see #setLookAlong(double, double, double, double, double, double)
2997      * @see #lookAlong(double, double, double, double, double, double)
2998      * 
2999      * @param dirX
3000      *              the x-coordinate of the direction to look along
3001      * @param dirY
3002      *              the y-coordinate of the direction to look along
3003      * @param dirZ
3004      *              the z-coordinate of the direction to look along
3005      * @param upX
3006      *              the x-coordinate of the up vector
3007      * @param upY
3008      *              the y-coordinate of the up vector
3009      * @param upZ
3010      *              the z-coordinate of the up vector
3011      * @return this
3012      */
3013     ref public Matrix3d setLookAlong(double dirX, double dirY, double dirZ,
3014                                  double upX, double upY, double upZ) return {
3015         // Normalize direction
3016         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
3017         dirX *= -invDirLength;
3018         dirY *= -invDirLength;
3019         dirZ *= -invDirLength;
3020         // left = up x direction
3021         double leftX, leftY, leftZ;
3022         leftX = upY * dirZ - upZ * dirY;
3023         leftY = upZ * dirX - upX * dirZ;
3024         leftZ = upX * dirY - upY * dirX;
3025         // normalize left
3026         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
3027         leftX *= invLeftLength;
3028         leftY *= invLeftLength;
3029         leftZ *= invLeftLength;
3030         // up = direction x left
3031         double upnX = dirY * leftZ - dirZ * leftY;
3032         double upnY = dirZ * leftX - dirX * leftZ;
3033         double upnZ = dirX * leftY - dirY * leftX;
3034 
3035         m00 = leftX;
3036         m01 = upnX;
3037         m02 = dirX;
3038         m10 = leftY;
3039         m11 = upnY;
3040         m12 = dirY;
3041         m20 = leftZ;
3042         m21 = upnZ;
3043         m22 = dirZ;
3044 
3045         return this;
3046     }
3047 
3048     public Vector3d getScale(ref Vector3d dest) {
3049         dest.x = Math.sqrt(m00 * m00 + m01 * m01 + m02 * m02);
3050         dest.y = Math.sqrt(m10 * m10 + m11 * m11 + m12 * m12);
3051         dest.z = Math.sqrt(m20 * m20 + m21 * m21 + m22 * m22);
3052         return dest;
3053     }
3054 
3055     public Vector3d positiveZ(Vector3d dir) {
3056         dir.x = m10 * m21 - m11 * m20;
3057         dir.y = m20 * m01 - m21 * m00;
3058         dir.z = m00 * m11 - m01 * m10;
3059         return dir.normalize(dir);
3060     }
3061 
3062     public Vector3d normalizedPositiveZ(Vector3d dir) {
3063         dir.x = m02;
3064         dir.y = m12;
3065         dir.z = m22;
3066         return dir;
3067     }
3068 
3069     public Vector3d positiveX(Vector3d dir) {
3070         dir.x = m11 * m22 - m12 * m21;
3071         dir.y = m02 * m21 - m01 * m22;
3072         dir.z = m01 * m12 - m02 * m11;
3073         return dir.normalize(dir);
3074     }
3075 
3076     public Vector3d normalizedPositiveX(Vector3d dir) {
3077         dir.x = m00;
3078         dir.y = m10;
3079         dir.z = m20;
3080         return dir;
3081     }
3082 
3083     public Vector3d positiveY(Vector3d dir) {
3084         dir.x = m12 * m20 - m10 * m22;
3085         dir.y = m00 * m22 - m02 * m20;
3086         dir.z = m02 * m10 - m00 * m12;
3087         return dir.normalize(dir);
3088     }
3089 
3090     public Vector3d normalizedPositiveY(Vector3d dir) {
3091         dir.x = m01;
3092         dir.y = m11;
3093         dir.z = m21;
3094         return dir;
3095     }
3096 
3097     public int hashCode() {
3098         immutable int prime = 31;
3099         int result = 1;
3100         long temp;
3101         temp = Math.doubleToLongBits(m00);
3102         result = prime * result + cast(int) (temp ^ (temp >>> 32));
3103         temp = Math.doubleToLongBits(m01);
3104         result = prime * result + cast(int) (temp ^ (temp >>> 32));
3105         temp = Math.doubleToLongBits(m02);
3106         result = prime * result + cast(int) (temp ^ (temp >>> 32));
3107         temp = Math.doubleToLongBits(m10);
3108         result = prime * result + cast(int) (temp ^ (temp >>> 32));
3109         temp = Math.doubleToLongBits(m11);
3110         result = prime * result + cast(int) (temp ^ (temp >>> 32));
3111         temp = Math.doubleToLongBits(m12);
3112         result = prime * result + cast(int) (temp ^ (temp >>> 32));
3113         temp = Math.doubleToLongBits(m20);
3114         result = prime * result + cast(int) (temp ^ (temp >>> 32));
3115         temp = Math.doubleToLongBits(m21);
3116         result = prime * result + cast(int) (temp ^ (temp >>> 32));
3117         temp = Math.doubleToLongBits(m22);
3118         result = prime * result + cast(int) (temp ^ (temp >>> 32));
3119         return result;
3120     }
3121 
3122     public bool equals(Matrix3d m, double delta) {
3123         if (this == m)
3124             return true;
3125         if (!Math.equals(m00, m.m00, delta))
3126             return false;
3127         if (!Math.equals(m01, m.m01, delta))
3128             return false;
3129         if (!Math.equals(m02, m.m02, delta))
3130             return false;
3131         if (!Math.equals(m10, m.m10, delta))
3132             return false;
3133         if (!Math.equals(m11, m.m11, delta))
3134             return false;
3135         if (!Math.equals(m12, m.m12, delta))
3136             return false;
3137         if (!Math.equals(m20, m.m20, delta))
3138             return false;
3139         if (!Math.equals(m21, m.m21, delta))
3140             return false;
3141         if (!Math.equals(m22, m.m22, delta))
3142             return false;
3143         return true;
3144     }
3145 
3146     /**
3147      * Exchange the values of <code>this</code> matrix with the given <code>other</code> matrix.
3148      * 
3149      * @param other
3150      *          the other matrix to exchange the values with
3151      * @return this
3152      */
3153     ref public Matrix3d swap(ref Matrix3d other) return {
3154         double tmp;
3155         tmp = m00; m00 = other.m00; other.m00 = tmp;
3156         tmp = m01; m01 = other.m01; other.m01 = tmp;
3157         tmp = m02; m02 = other.m02; other.m02 = tmp;
3158         tmp = m10; m10 = other.m10; other.m10 = tmp;
3159         tmp = m11; m11 = other.m11; other.m11 = tmp;
3160         tmp = m12; m12 = other.m12; other.m12 = tmp;
3161         tmp = m20; m20 = other.m20; other.m20 = tmp;
3162         tmp = m21; m21 = other.m21; other.m21 = tmp;
3163         tmp = m22; m22 = other.m22; other.m22 = tmp;
3164         return this;
3165     }
3166 
3167     /**
3168      * Component-wise add <code>this</code> and <code>other</code>.
3169      * 
3170      * @param other
3171      *          the other addend 
3172      * @return this
3173      */
3174     ref public Matrix3d add(Matrix3d other) return {
3175         add(other, this);
3176         return this;
3177     }
3178 
3179     public Matrix3d add(Matrix3d other, ref Matrix3d dest) {
3180         dest.m00 = m00 + other.m00;
3181         dest.m01 = m01 + other.m01;
3182         dest.m02 = m02 + other.m02;
3183         dest.m10 = m10 + other.m10;
3184         dest.m11 = m11 + other.m11;
3185         dest.m12 = m12 + other.m12;
3186         dest.m20 = m20 + other.m20;
3187         dest.m21 = m21 + other.m21;
3188         dest.m22 = m22 + other.m22;
3189         return dest;
3190     }
3191 
3192     /**
3193      * Component-wise subtract <code>subtrahend</code> from <code>this</code>.
3194      * 
3195      * @param subtrahend
3196      *          the subtrahend
3197      * @return this
3198      */
3199     ref public Matrix3d sub(Matrix3d subtrahend) return {
3200         sub(subtrahend, this);
3201         return this;
3202     }
3203 
3204     public Matrix3d sub(Matrix3d subtrahend, ref Matrix3d dest) {
3205         dest.m00 = m00 - subtrahend.m00;
3206         dest.m01 = m01 - subtrahend.m01;
3207         dest.m02 = m02 - subtrahend.m02;
3208         dest.m10 = m10 - subtrahend.m10;
3209         dest.m11 = m11 - subtrahend.m11;
3210         dest.m12 = m12 - subtrahend.m12;
3211         dest.m20 = m20 - subtrahend.m20;
3212         dest.m21 = m21 - subtrahend.m21;
3213         dest.m22 = m22 - subtrahend.m22;
3214         return dest;
3215     }
3216 
3217     /**
3218      * Component-wise multiply <code>this</code> by <code>other</code>.
3219      * 
3220      * @param other
3221      *          the other matrix
3222      * @return this
3223      */
3224     ref public Matrix3d mulComponentWise(Matrix3d other) return {
3225         mulComponentWise(other, this);
3226         return this;
3227     }
3228 
3229     public Matrix3d mulComponentWise(Matrix3d other, ref Matrix3d dest) {
3230         dest.m00 = m00 * other.m00;
3231         dest.m01 = m01 * other.m01;
3232         dest.m02 = m02 * other.m02;
3233         dest.m10 = m10 * other.m10;
3234         dest.m11 = m11 * other.m11;
3235         dest.m12 = m12 * other.m12;
3236         dest.m20 = m20 * other.m20;
3237         dest.m21 = m21 * other.m21;
3238         dest.m22 = m22 * other.m22;
3239         return dest;
3240     }
3241 
3242     /**
3243      * Set this matrix to a skew-symmetric matrix using the following layout:
3244      * <pre>
3245      *  0,  a, -b
3246      * -a,  0,  c
3247      *  b, -c,  0
3248      * </pre>
3249      * 
3250      * Reference: <a href="https://en.wikipedia.org/wiki/Skew-symmetric_matrix">https://en.wikipedia.org</a>
3251      * 
3252      * @param a
3253      *          the value used for the matrix elements m01 and m10
3254      * @param b
3255      *          the value used for the matrix elements m02 and m20
3256      * @param c
3257      *          the value used for the matrix elements m12 and m21
3258      * @return this
3259      */
3260     ref public Matrix3d setSkewSymmetric(double a, double b, double c) return {
3261         m00 = m11 = m22 = 0;
3262         m01 = -a;
3263         m02 = b;
3264         m10 = a;
3265         m12 = -c;
3266         m20 = -b;
3267         m21 = c;
3268         return this;
3269     }
3270 
3271     /**
3272      * Linearly interpolate <code>this</code> and <code>other</code> using the given interpolation factor <code>t</code>
3273      * and store the result in <code>this</code>.
3274      * <p>
3275      * If <code>t</code> is <code>0.0</code> then the result is <code>this</code>. If the interpolation factor is <code>1.0</code>
3276      * then the result is <code>other</code>.
3277      *
3278      * @param other
3279      *          the other matrix
3280      * @param t
3281      *          the interpolation factor between 0.0 and 1.0
3282      * @return this
3283      */
3284     ref public Matrix3d lerp(Matrix3d other, double t) return {
3285         lerp(other, t, this);
3286         return this;
3287     }
3288 
3289     public Matrix3d lerp(Matrix3d other, double t, ref Matrix3d dest) {
3290         dest.m00 = Math.fma(other.m00 - m00, t, m00);
3291         dest.m01 = Math.fma(other.m01 - m01, t, m01);
3292         dest.m02 = Math.fma(other.m02 - m02, t, m02);
3293         dest.m10 = Math.fma(other.m10 - m10, t, m10);
3294         dest.m11 = Math.fma(other.m11 - m11, t, m11);
3295         dest.m12 = Math.fma(other.m12 - m12, t, m12);
3296         dest.m20 = Math.fma(other.m20 - m20, t, m20);
3297         dest.m21 = Math.fma(other.m21 - m21, t, m21);
3298         dest.m22 = Math.fma(other.m22 - m22, t, m22);
3299         return dest;
3300     }
3301 
3302     /**
3303      * Apply a model transformation to this matrix for a right-handed coordinate system, 
3304      * that aligns the local <code>+Z</code> axis with <code>direction</code>
3305      * and store the result in <code>dest</code>.
3306      * <p>
3307      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
3308      * then the new matrix will be <code>M * L</code>. So when transforming a
3309      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
3310      * the lookat transformation will be applied first!
3311      * <p>
3312      * In order to set the matrix to a rotation transformation without post-multiplying it,
3313      * use {@link #rotationTowards(Vector3d, Vector3d) rotationTowards()}.
3314      * <p>
3315      * This method is equivalent to calling: <code>mul(new Matrix3d().lookAlong(new Vector3d(dir).negate(), up).invert(), dest)</code>
3316      * 
3317      * @see #rotateTowards(double, double, double, double, double, double, Matrix3d)
3318      * @see #rotationTowards(Vector3d, Vector3d)
3319      * 
3320      * @param direction
3321      *              the direction to rotate towards
3322      * @param up
3323      *              the model's up vector
3324      * @param dest
3325      *              will hold the result
3326      * @return dest
3327      */
3328     public Matrix3d rotateTowards(Vector3d direction, Vector3d up, ref Matrix3d dest) {
3329         return rotateTowards(direction.x, direction.y, direction.z, up.x, up.y, up.z, dest);
3330     }
3331 
3332     /**
3333      * Apply a model transformation to this matrix for a right-handed coordinate system, 
3334      * that aligns the local <code>+Z</code> axis with <code>direction</code>.
3335      * <p>
3336      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
3337      * then the new matrix will be <code>M * L</code>. So when transforming a
3338      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
3339      * the lookat transformation will be applied first!
3340      * <p>
3341      * In order to set the matrix to a rotation transformation without post-multiplying it,
3342      * use {@link #rotationTowards(Vector3d, Vector3d) rotationTowards()}.
3343      * <p>
3344      * This method is equivalent to calling: <code>mul(new Matrix3d().lookAlong(new Vector3d(dir).negate(), up).invert())</code>
3345      * 
3346      * @see #rotateTowards(double, double, double, double, double, double)
3347      * @see #rotationTowards(Vector3d, Vector3d)
3348      * 
3349      * @param direction
3350      *              the direction to orient towards
3351      * @param up
3352      *              the up vector
3353      * @return this
3354      */
3355     ref public Matrix3d rotateTowards(Vector3d direction, Vector3d up) return {
3356         rotateTowards(direction.x, direction.y, direction.z, up.x, up.y, up.z, this);
3357         return this;
3358     }
3359 
3360     /**
3361      * Apply a model transformation to this matrix for a right-handed coordinate system, 
3362      * that aligns the local <code>+Z</code> axis with <code>direction</code>.
3363      * <p>
3364      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
3365      * then the new matrix will be <code>M * L</code>. So when transforming a
3366      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
3367      * the lookat transformation will be applied first!
3368      * <p>
3369      * In order to set the matrix to a rotation transformation without post-multiplying it,
3370      * use {@link #rotationTowards(double, double, double, double, double, double) rotationTowards()}.
3371      * <p>
3372      * This method is equivalent to calling: <code>mul(new Matrix3d().lookAlong(-dirX, -dirY, -dirZ, upX, upY, upZ).invert())</code>
3373      * 
3374      * @see #rotateTowards(Vector3d, Vector3d)
3375      * @see #rotationTowards(double, double, double, double, double, double)
3376      * 
3377      * @param dirX
3378      *              the x-coordinate of the direction to rotate towards
3379      * @param dirY
3380      *              the y-coordinate of the direction to rotate towards
3381      * @param dirZ
3382      *              the z-coordinate of the direction to rotate towards
3383      * @param upX
3384      *              the x-coordinate of the up vector
3385      * @param upY
3386      *              the y-coordinate of the up vector
3387      * @param upZ
3388      *              the z-coordinate of the up vector
3389      * @return this
3390      */
3391     ref public Matrix3d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ) return {
3392         rotateTowards(dirX, dirY, dirZ, upX, upY, upZ, this);
3393         return this;
3394     }
3395 
3396     /**
3397      * Apply a model transformation to this matrix for a right-handed coordinate system, 
3398      * that aligns the local <code>+Z</code> axis with <code>dir</code>
3399      * and store the result in <code>dest</code>.
3400      * <p>
3401      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
3402      * then the new matrix will be <code>M * L</code>. So when transforming a
3403      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
3404      * the lookat transformation will be applied first!
3405      * <p>
3406      * In order to set the matrix to a rotation transformation without post-multiplying it,
3407      * use {@link #rotationTowards(double, double, double, double, double, double) rotationTowards()}.
3408      * <p>
3409      * This method is equivalent to calling: <code>mul(new Matrix3d().lookAlong(-dirX, -dirY, -dirZ, upX, upY, upZ).invert(), dest)</code>
3410      * 
3411      * @see #rotateTowards(Vector3d, Vector3d)
3412      * @see #rotationTowards(double, double, double, double, double, double)
3413      * 
3414      * @param dirX
3415      *              the x-coordinate of the direction to rotate towards
3416      * @param dirY
3417      *              the y-coordinate of the direction to rotate towards
3418      * @param dirZ
3419      *              the z-coordinate of the direction to rotate towards
3420      * @param upX
3421      *              the x-coordinate of the up vector
3422      * @param upY
3423      *              the y-coordinate of the up vector
3424      * @param upZ
3425      *              the z-coordinate of the up vector
3426      * @param dest
3427      *              will hold the result
3428      * @return dest
3429      */
3430     public Matrix3d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, ref Matrix3d dest) {
3431         // Normalize direction
3432         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
3433         double ndirX = dirX * invDirLength;
3434         double ndirY = dirY * invDirLength;
3435         double ndirZ = dirZ * invDirLength;
3436         // left = up x direction
3437         double leftX, leftY, leftZ;
3438         leftX = upY * ndirZ - upZ * ndirY;
3439         leftY = upZ * ndirX - upX * ndirZ;
3440         leftZ = upX * ndirY - upY * ndirX;
3441         // normalize left
3442         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
3443         leftX *= invLeftLength;
3444         leftY *= invLeftLength;
3445         leftZ *= invLeftLength;
3446         // up = direction x left
3447         double upnX = ndirY * leftZ - ndirZ * leftY;
3448         double upnY = ndirZ * leftX - ndirX * leftZ;
3449         double upnZ = ndirX * leftY - ndirY * leftX;
3450         double rm00 = leftX;
3451         double rm01 = leftY;
3452         double rm02 = leftZ;
3453         double rm10 = upnX;
3454         double rm11 = upnY;
3455         double rm12 = upnZ;
3456         double rm20 = ndirX;
3457         double rm21 = ndirY;
3458         double rm22 = ndirZ;
3459         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
3460         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
3461         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
3462         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
3463         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
3464         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
3465         dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
3466         dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
3467         dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
3468         dest.m00 = nm00;
3469         dest.m01 = nm01;
3470         dest.m02 = nm02;
3471         dest.m10 = nm10;
3472         dest.m11 = nm11;
3473         dest.m12 = nm12;
3474         return dest;
3475     }
3476 
3477     /**
3478      * Set this matrix to a model transformation for a right-handed coordinate system, 
3479      * that aligns the local <code>-z</code> axis with <code>center - eye</code>.
3480      * <p>
3481      * In order to apply the rotation transformation to a previous existing transformation,
3482      * use {@link #rotateTowards(double, double, double, double, double, double) rotateTowards}.
3483      * <p>
3484      * This method is equivalent to calling: <code>setLookAlong(new Vector3d(dir).negate(), up).invert()</code>
3485      * 
3486      * @see #rotationTowards(Vector3d, Vector3d)
3487      * @see #rotateTowards(double, double, double, double, double, double)
3488      * 
3489      * @param dir
3490      *              the direction to orient the local -z axis towards
3491      * @param up
3492      *              the up vector
3493      * @return this
3494      */
3495     ref public Matrix3d rotationTowards(Vector3d dir, Vector3d up) return {
3496         return rotationTowards(dir.x, dir.y, dir.z, up.x, up.y, up.z);
3497     }
3498 
3499     /**
3500      * Set this matrix to a model transformation for a right-handed coordinate system, 
3501      * that aligns the local <code>-z</code> axis with <code>center - eye</code>.
3502      * <p>
3503      * In order to apply the rotation transformation to a previous existing transformation,
3504      * use {@link #rotateTowards(double, double, double, double, double, double) rotateTowards}.
3505      * <p>
3506      * This method is equivalent to calling: <code>setLookAlong(-dirX, -dirY, -dirZ, upX, upY, upZ).invert()</code>
3507      * 
3508      * @see #rotateTowards(Vector3d, Vector3d)
3509      * @see #rotationTowards(double, double, double, double, double, double)
3510      * 
3511      * @param dirX
3512      *              the x-coordinate of the direction to rotate towards
3513      * @param dirY
3514      *              the y-coordinate of the direction to rotate towards
3515      * @param dirZ
3516      *              the z-coordinate of the direction to rotate towards
3517      * @param upX
3518      *              the x-coordinate of the up vector
3519      * @param upY
3520      *              the y-coordinate of the up vector
3521      * @param upZ
3522      *              the z-coordinate of the up vector
3523      * @return this
3524      */
3525     ref public Matrix3d rotationTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ) return {
3526         // Normalize direction
3527         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
3528         double ndirX = dirX * invDirLength;
3529         double ndirY = dirY * invDirLength;
3530         double ndirZ = dirZ * invDirLength;
3531         // left = up x direction
3532         double leftX, leftY, leftZ;
3533         leftX = upY * ndirZ - upZ * ndirY;
3534         leftY = upZ * ndirX - upX * ndirZ;
3535         leftZ = upX * ndirY - upY * ndirX;
3536         // normalize left
3537         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
3538         leftX *= invLeftLength;
3539         leftY *= invLeftLength;
3540         leftZ *= invLeftLength;
3541         // up = direction x left
3542         double upnX = ndirY * leftZ - ndirZ * leftY;
3543         double upnY = ndirZ * leftX - ndirX * leftZ;
3544         double upnZ = ndirX * leftY - ndirY * leftX;
3545         this.m00 = leftX;
3546         this.m01 = leftY;
3547         this.m02 = leftZ;
3548         this.m10 = upnX;
3549         this.m11 = upnY;
3550         this.m12 = upnZ;
3551         this.m20 = ndirX;
3552         this.m21 = ndirY;
3553         this.m22 = ndirZ;
3554         return this;
3555     }
3556 
3557     public Vector3d getEulerAnglesZYX(ref Vector3d dest) {
3558         dest.x = Math.atan2(m12, m22);
3559         dest.y = Math.atan2(-m02, Math.sqrt(1.0 - m02 * m02));
3560         dest.z = Math.atan2(m01, m00);
3561         return dest;
3562     }
3563 
3564     public Vector3d getEulerAnglesXYZ(ref Vector3d dest) {
3565         dest.x = Math.atan2(-m21, m22);
3566         dest.y = Math.atan2(m20, Math.sqrt(1.0 - m20 * m20));
3567         dest.z = Math.atan2(-m10, m00);
3568         return dest;
3569     }
3570 
3571     /**
3572      * Apply an oblique projection transformation to this matrix with the given values for <code>a</code> and
3573      * <code>b</code>.
3574      * <p>
3575      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the oblique transformation matrix,
3576      * then the new matrix will be <code>M * O</code>. So when transforming a
3577      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
3578      * oblique transformation will be applied first!
3579      * <p>
3580      * The oblique transformation is defined as:
3581      * <pre>
3582      * x' = x + a*z
3583      * y' = y + a*z
3584      * z' = z
3585      * </pre>
3586      * or in matrix form:
3587      * <pre>
3588      * 1 0 a
3589      * 0 1 b
3590      * 0 0 1
3591      * </pre>
3592      * 
3593      * @param a
3594      *            the value for the z factor that applies to x
3595      * @param b
3596      *            the value for the z factor that applies to y
3597      * @return this
3598      */
3599     ref public Matrix3d obliqueZ(double a, double b) return {
3600         this.m20 = m00 * a + m10 * b + m20;
3601         this.m21 = m01 * a + m11 * b + m21;
3602         this.m22 = m02 * a + m12 * b + m22;
3603         return this;
3604     }
3605 
3606     /**
3607      * Apply an oblique projection transformation to this matrix with the given values for <code>a</code> and
3608      * <code>b</code> and store the result in <code>dest</code>.
3609      * <p>
3610      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the oblique transformation matrix,
3611      * then the new matrix will be <code>M * O</code>. So when transforming a
3612      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
3613      * oblique transformation will be applied first!
3614      * <p>
3615      * The oblique transformation is defined as:
3616      * <pre>
3617      * x' = x + a*z
3618      * y' = y + a*z
3619      * z' = z
3620      * </pre>
3621      * or in matrix form:
3622      * <pre>
3623      * 1 0 a
3624      * 0 1 b
3625      * 0 0 1
3626      * </pre>
3627      * 
3628      * @param a
3629      *            the value for the z factor that applies to x
3630      * @param b
3631      *            the value for the z factor that applies to y
3632      * @param dest
3633      *            will hold the result
3634      * @return dest
3635      */
3636     public Matrix3d obliqueZ(double a, double b, ref Matrix3d dest) {
3637         dest.m00 = m00;
3638         dest.m01 = m01;
3639         dest.m02 = m02;
3640         dest.m10 = m10;
3641         dest.m11 = m11;
3642         dest.m12 = m12;
3643         dest.m20 = m00 * a + m10 * b + m20;
3644         dest.m21 = m01 * a + m11 * b + m21;
3645         dest.m22 = m02 * a + m12 * b + m22;
3646         return dest;
3647     }
3648 
3649     public Matrix3d reflect(double nx, double ny, double nz, ref Matrix3d dest) {
3650         double da = nx + nx, db = ny + ny, d = nz + nz;
3651         double rm00 = 1.0 - da * nx;
3652         double rm01 = -da * ny;
3653         double rm02 = -da * nz;
3654         double rm10 = -db * nx;
3655         double rm11 = 1.0 - db * ny;
3656         double rm12 = -db * nz;
3657         double rm20 = -d * nx;
3658         double rm21 = -d * ny;
3659         double rm22 = 1.0 - d * nz;
3660         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
3661         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
3662         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
3663         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
3664         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
3665         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
3666         return dest
3667         ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
3668         ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
3669         ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
3670         ._m00(nm00)
3671         ._m01(nm01)
3672         ._m02(nm02)
3673         ._m10(nm10)
3674         ._m11(nm11)
3675         ._m12(nm12);
3676     }
3677 
3678     /**
3679      * Apply a mirror/reflection transformation to this matrix that reflects through the given plane
3680      * specified via the plane normal.
3681      * <p>
3682      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix,
3683      * then the new matrix will be <code>M * R</code>. So when transforming a
3684      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3685      * reflection will be applied first!
3686      * 
3687      * @param nx
3688      *          the x-coordinate of the plane normal
3689      * @param ny
3690      *          the y-coordinate of the plane normal
3691      * @param nz
3692      *          the z-coordinate of the plane normal
3693      * @return this
3694      */
3695     ref public Matrix3d reflect(double nx, double ny, double nz) return {
3696         reflect(nx, ny, nz, this);
3697         return this;
3698     }
3699 
3700     /**
3701      * Apply a mirror/reflection transformation to this matrix that reflects through the given plane
3702      * specified via the plane normal.
3703      * <p>
3704      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix,
3705      * then the new matrix will be <code>M * R</code>. So when transforming a
3706      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3707      * reflection will be applied first!
3708      * 
3709      * @param normal
3710      *          the plane normal
3711      * @return this
3712      */
3713     ref public Matrix3d reflect(Vector3d normal) return {
3714         return reflect(normal.x, normal.y, normal.z);
3715     }
3716 
3717     /**
3718      * Apply a mirror/reflection transformation to this matrix that reflects about a plane
3719      * specified via the plane orientation.
3720      * <p>
3721      * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
3722      * It is assumed that the default mirror plane's normal is <code>(0, 0, 1)</code>. So, if the given {@link Quaterniond} is
3723      * the identity (does not apply any additional rotation), the reflection plane will be <code>z=0</code>.
3724      * <p>
3725      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix,
3726      * then the new matrix will be <code>M * R</code>. So when transforming a
3727      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3728      * reflection will be applied first!
3729      * 
3730      * @param orientation
3731      *          the plane orientation
3732      * @return this
3733      */
3734     ref public Matrix3d reflect(Quaterniond orientation) return {
3735         reflect(orientation, this);
3736         return this;
3737     }
3738 
3739     public Matrix3d reflect(Quaterniond orientation, ref Matrix3d dest) {
3740         double num1 = orientation.x + orientation.x;
3741         double num2 = orientation.y + orientation.y;
3742         double num3 = orientation.z + orientation.z;
3743         double normalX = cast(double) (orientation.x * num3 + orientation.w * num2);
3744         double normalY = cast(double) (orientation.y * num3 - orientation.w * num1);
3745         double normalZ = cast(double) (1.0 - (orientation.x * num1 + orientation.y * num2));
3746         return reflect(normalX, normalY, normalZ, dest);
3747     }
3748 
3749     public Matrix3d reflect(Vector3d normal, ref Matrix3d dest) {
3750         return reflect(normal.x, normal.y, normal.z, dest);
3751     }
3752 
3753     /**
3754      * Set this matrix to a mirror/reflection transformation that reflects through the given plane
3755      * specified via the plane normal.
3756      * 
3757      * @param nx
3758      *          the x-coordinate of the plane normal
3759      * @param ny
3760      *          the y-coordinate of the plane normal
3761      * @param nz
3762      *          the z-coordinate of the plane normal
3763      * @return this
3764      */
3765     ref public Matrix3d reflection(double nx, double ny, double nz) return {
3766         double da = nx + nx, db = ny + ny, d = nz + nz;
3767         this._m00(1.0 - da * nx);
3768         this._m01(-da * ny);
3769         this._m02(-da * nz);
3770         this._m10(-db * nx);
3771         this._m11(1.0 - db * ny);
3772         this._m12(-db * nz);
3773         this._m20(-d * nx);
3774         this._m21(-d * ny);
3775         this._m22(1.0 - d * nz);
3776         return this;
3777     }
3778 
3779     /**
3780      * Set this matrix to a mirror/reflection transformation that reflects through the given plane
3781      * specified via the plane normal.
3782      * 
3783      * @param normal
3784      *          the plane normal
3785      * @return this
3786      */
3787     ref public Matrix3d reflection(Vector3d normal) return {
3788         return reflection(normal.x, normal.y, normal.z);
3789     }
3790 
3791     /**
3792      * Set this matrix to a mirror/reflection transformation that reflects through a plane
3793      * specified via the plane orientation.
3794      * <p>
3795      * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
3796      * It is assumed that the default mirror plane's normal is <code>(0, 0, 1)</code>. So, if the given {@link Quaterniond} is
3797      * the identity (does not apply any additional rotation), the reflection plane will be <code>z=0</code>, offset by the given <code>point</code>.
3798      * 
3799      * @param orientation
3800      *          the plane orientation
3801      * @return this
3802      */
3803     ref public Matrix3d reflection(Quaterniond orientation) return {
3804         double num1 = orientation.x + orientation.x;
3805         double num2 = orientation.y + orientation.y;
3806         double num3 = orientation.z + orientation.z;
3807         double normalX = orientation.x * num3 + orientation.w * num2;
3808         double normalY = orientation.y * num3 - orientation.w * num1;
3809         double normalZ = 1.0 - (orientation.x * num1 + orientation.y * num2);
3810         return reflection(normalX, normalY, normalZ);
3811     }
3812 
3813     public bool isFinite() {
3814         return Math.isFinite(m00) && Math.isFinite(m01) && Math.isFinite(m02) &&
3815                Math.isFinite(m10) && Math.isFinite(m11) && Math.isFinite(m12) &&
3816                Math.isFinite(m20) && Math.isFinite(m21) && Math.isFinite(m22);
3817     }
3818 
3819     public double quadraticFormProduct(double x, double y, double z) {
3820         double Axx = m00 * x + m10 * y + m20 * z;
3821         double Axy = m01 * x + m11 * y + m21 * z;
3822         double Axz = m02 * x + m12 * y + m22 * z;
3823         return x * Axx + y * Axy + z * Axz; 
3824     }
3825 
3826     public double quadraticFormProduct(Vector3d v) {
3827         return quadraticFormProduct(v.x, v.y, v.z); 
3828     }
3829 
3830     /**
3831      * Multiply <code>this</code> by the matrix
3832      * <pre>
3833      * 1 0 0
3834      * 0 0 1
3835      * 0 1 0
3836      * </pre>
3837      * 
3838      * @return this
3839      */
3840     ref public Matrix3d mapXZy() return {
3841         mapXZY(this);
3842         return this;
3843     }
3844     public Matrix3d mapXZY(ref Matrix3d dest) {
3845         double __m10 = this.m10, __m11 = this.m11, __m12 = this.m12;
3846         return dest._m00(m00)._m01(m01)._m02(m02)._m10(m20)._m11(m21)._m12(m22)._m20(__m10)._m21(__m11)._m22(__m12);
3847     }
3848     /**
3849      * Multiply <code>this</code> by the matrix
3850      * <pre>
3851      * 1 0  0
3852      * 0 0 -1
3853      * 0 1  0
3854      * </pre>
3855      * 
3856      * @return this
3857      */
3858     ref public Matrix3d mapXZny() return {
3859         mapXZnY(this);
3860         return this;
3861     }
3862     public Matrix3d mapXZnY(ref Matrix3d dest) {
3863         double __m10 = this.m10, __m11 = this.m11, __m12 = this.m12;
3864         return dest._m00(m00)._m01(m01)._m02(m02)._m10(m20)._m11(m21)._m12(m22)._m20(-__m10)._m21(-__m11)._m22(-__m12);
3865     }
3866     /**
3867      * Multiply <code>this</code> by the matrix
3868      * <pre>
3869      * 1  0  0
3870      * 0 -1  0
3871      * 0  0 -1
3872      * </pre>
3873      * 
3874      * @return this
3875      */
3876     ref public Matrix3d mapXnYnz() return {
3877         mapXnYnZ(this);
3878         return this;
3879     }
3880     public Matrix3d mapXnYnZ(ref Matrix3d dest) {
3881         return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m20)._m21(-m21)._m22(-m22);
3882     }
3883     /**
3884      * Multiply <code>this</code> by the matrix
3885      * <pre>
3886      * 1  0 0
3887      * 0  0 1
3888      * 0 -1 0
3889      * </pre>
3890      * 
3891      * @return this
3892      */
3893     ref public Matrix3d mapXnZy() return {
3894         mapXnZY(this);
3895         return this;
3896     }
3897     public Matrix3d mapXnZY(ref Matrix3d dest) {
3898         double __m10 = this.m10, __m11 = this.m11, __m12 = this.m12;
3899         return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(__m10)._m21(__m11)._m22(__m12);
3900     }
3901     /**
3902      * Multiply <code>this</code> by the matrix
3903      * <pre>
3904      * 1  0  0
3905      * 0  0 -1
3906      * 0 -1  0
3907      * </pre>
3908      * 
3909      * @return this
3910      */
3911     ref public Matrix3d mapXnZny() return {
3912         mapXnZnY(this);
3913         return this;
3914     }
3915     public Matrix3d mapXnZnY(ref Matrix3d dest) {
3916         double __m10 = this.m10, __m11 = this.m11, __m12 = this.m12;
3917         return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-__m10)._m21(-__m11)._m22(-__m12);
3918     }
3919     /**
3920      * Multiply <code>this</code> by the matrix
3921      * <pre>
3922      * 0 1 0
3923      * 1 0 0
3924      * 0 0 1
3925      * </pre>
3926      * 
3927      * @return this
3928      */
3929     ref public Matrix3d mapYXz() return {
3930         mapYXZ(this);
3931         return this;
3932     }
3933     public Matrix3d mapYXZ(ref Matrix3d dest) {
3934         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
3935         return dest._m00(m10)._m01(m11)._m02(m12)._m10(__m00)._m11(__m01)._m12(__m02)._m20(m20)._m21(m21)._m22(m22);
3936     }
3937     /**
3938      * Multiply <code>this</code> by the matrix
3939      * <pre>
3940      * 0 1  0
3941      * 1 0  0
3942      * 0 0 -1
3943      * </pre>
3944      * 
3945      * @return this
3946      */
3947     ref public Matrix3d mapYXnz() return {
3948         mapYXnZ(this);
3949         return this;
3950     }
3951     public Matrix3d mapYXnZ(ref Matrix3d dest) {
3952         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
3953         return dest._m00(m10)._m01(m11)._m02(m12)._m10(__m00)._m11(__m01)._m12(__m02)._m20(-m20)._m21(-m21)._m22(-m22);
3954     }
3955     /**
3956      * Multiply <code>this</code> by the matrix
3957      * <pre>
3958      * 0 0 1
3959      * 1 0 0
3960      * 0 1 0
3961      * </pre>
3962      * 
3963      * @return this
3964      */
3965     ref public Matrix3d mapYZx() return {
3966         mapYZX(this);
3967         return this;
3968     }
3969     public Matrix3d mapYZX(ref Matrix3d dest) {
3970         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
3971         return dest._m00(m10)._m01(m11)._m02(m12)._m10(m20)._m11(m21)._m12(m22)._m20(__m00)._m21(__m01)._m22(__m02);
3972     }
3973     /**
3974      * Multiply <code>this</code> by the matrix
3975      * <pre>
3976      * 0 0 -1
3977      * 1 0  0
3978      * 0 1  0
3979      * </pre>
3980      * 
3981      * @return this
3982      */
3983     ref public Matrix3d mapYZnx() return {
3984         mapYZnX(this);
3985         return this;
3986     }
3987     public Matrix3d mapYZnX(ref Matrix3d dest) {
3988         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
3989         return dest._m00(m10)._m01(m11)._m02(m12)._m10(m20)._m11(m21)._m12(m22)._m20(-__m00)._m21(-__m01)._m22(-__m02);
3990     }
3991     /**
3992      * Multiply <code>this</code> by the matrix
3993      * <pre>
3994      * 0 -1 0
3995      * 1  0 0
3996      * 0  0 1
3997      * </pre>
3998      * 
3999      * @return this
4000      */
4001     ref public Matrix3d mapYnXz() return {
4002         mapYnXZ(this);
4003         return this;
4004     }
4005     public Matrix3d mapYnXZ(ref Matrix3d dest) {
4006         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4007         return dest._m00(m10)._m01(m11)._m02(m12)._m10(-__m00)._m11(-__m01)._m12(-__m02)._m20(m20)._m21(m21)._m22(m22);
4008     }
4009     /**
4010      * Multiply <code>this</code> by the matrix
4011      * <pre>
4012      * 0 -1  0
4013      * 1  0  0
4014      * 0  0 -1
4015      * </pre>
4016      * 
4017      * @return this
4018      */
4019     ref public Matrix3d mapYnXnz() return {
4020         mapYnXnZ(this);
4021         return this;
4022     }
4023     public Matrix3d mapYnXnZ(ref Matrix3d dest) {
4024         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4025         return dest._m00(m10)._m01(m11)._m02(m12)._m10(-__m00)._m11(-__m01)._m12(-__m02)._m20(-m20)._m21(-m21)._m22(-m22);
4026     }
4027     /**
4028      * Multiply <code>this</code> by the matrix
4029      * <pre>
4030      * 0  0 1
4031      * 1  0 0
4032      * 0 -1 0
4033      * </pre>
4034      * 
4035      * @return this
4036      */
4037     ref public Matrix3d mapYnZx() return {
4038         mapYnZX(this);
4039         return this;
4040     }
4041     public Matrix3d mapYnZX(ref Matrix3d dest) {
4042         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4043         return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(__m00)._m21(__m01)._m22(__m02);
4044     }
4045     /**
4046      * Multiply <code>this</code> by the matrix
4047      * <pre>
4048      * 0  0 -1
4049      * 1  0  0
4050      * 0 -1  0
4051      * </pre>
4052      * 
4053      * @return this
4054      */
4055     ref public Matrix3d mapYnZnx() return {
4056         mapYnZnX(this);
4057         return this;
4058     }
4059     public Matrix3d mapYnZnX(ref Matrix3d dest) {
4060         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4061         return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-__m00)._m21(-__m01)._m22(-__m02);
4062     }
4063     /**
4064      * Multiply <code>this</code> by the matrix
4065      * <pre>
4066      * 0 1 0
4067      * 0 0 1
4068      * 1 0 0
4069      * </pre>
4070      * 
4071      * @return this
4072      */
4073     ref public Matrix3d mapZXy() return {
4074         mapZXY(this);
4075         return this;
4076     }
4077     public Matrix3d mapZXY(ref Matrix3d dest) {
4078         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4079         double __m10 = this.m10, __m11 = this.m11, __m12 = this.m12;
4080         return dest._m00(m20)._m01(m21)._m02(m22)._m10(__m00)._m11(__m01)._m12(__m02)._m20(__m10)._m21(__m11)._m22(__m12);
4081     }
4082     /**
4083      * Multiply <code>this</code> by the matrix
4084      * <pre>
4085      * 0 1  0
4086      * 0 0 -1
4087      * 1 0  0
4088      * </pre>
4089      * 
4090      * @return this
4091      */
4092     ref public Matrix3d mapZXny() return {
4093         mapZXnY(this);
4094         return this;
4095     }
4096     public Matrix3d mapZXnY(ref Matrix3d dest) {
4097         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4098         double __m10 = this.m10, __m11 = this.m11, __m12 = this.m12;
4099         return dest._m00(m20)._m01(m21)._m02(m22)._m10(__m00)._m11(__m01)._m12(__m02)._m20(-__m10)._m21(-__m11)._m22(-__m12);
4100     }
4101     /**
4102      * Multiply <code>this</code> by the matrix
4103      * <pre>
4104      * 0 0 1
4105      * 0 1 0
4106      * 1 0 0
4107      * </pre>
4108      * 
4109      * @return this
4110      */
4111     ref public Matrix3d mapZYx() return {
4112         mapZYX(this);
4113         return this;
4114     }
4115     public Matrix3d mapZYX(ref Matrix3d dest) {
4116         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4117         return dest._m00(m20)._m01(m21)._m02(m22)._m10(m10)._m11(m11)._m12(m12)._m20(__m00)._m21(__m01)._m22(__m02);
4118     }
4119     /**
4120      * Multiply <code>this</code> by the matrix
4121      * <pre>
4122      * 0 0 -1
4123      * 0 1  0
4124      * 1 0  0
4125      * </pre>
4126      * 
4127      * @return this
4128      */
4129     ref public Matrix3d mapZYnx() return {
4130         mapZYnX(this);
4131         return this;
4132     }
4133     public Matrix3d mapZYnX(ref Matrix3d dest) {
4134         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4135         return dest._m00(m20)._m01(m21)._m02(m22)._m10(m10)._m11(m11)._m12(m12)._m20(-__m00)._m21(-__m01)._m22(-__m02);
4136     }
4137     /**
4138      * Multiply <code>this</code> by the matrix
4139      * <pre>
4140      * 0 -1 0
4141      * 0  0 1
4142      * 1  0 0
4143      * </pre>
4144      * 
4145      * @return this
4146      */
4147     ref public Matrix3d mapZnXy() return {
4148         mapZnXY(this);
4149         return this;
4150     }
4151     public Matrix3d mapZnXY(ref Matrix3d dest) {
4152         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4153         double __m10 = this.m10, __m11 = this.m11, __m12 = this.m12;
4154         return dest._m00(m20)._m01(m21)._m02(m22)._m10(-__m00)._m11(-__m01)._m12(-__m02)._m20(__m10)._m21(__m11)._m22(__m12);
4155     }
4156     /**
4157      * Multiply <code>this</code> by the matrix
4158      * <pre>
4159      * 0 -1  0
4160      * 0  0 -1
4161      * 1  0  0
4162      * </pre>
4163      * 
4164      * @return this
4165      */
4166     ref public Matrix3d mapZnXny() return {
4167         mapZnXnY(this);
4168         return this;
4169     }
4170     public Matrix3d mapZnXnY(ref Matrix3d dest) {
4171         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4172         double __m10 = this.m10, __m11 = this.m11, __m12 = this.m12;
4173         return dest._m00(m20)._m01(m21)._m02(m22)._m10(-__m00)._m11(-__m01)._m12(-__m02)._m20(-__m10)._m21(-__m11)._m22(-__m12);
4174     }
4175     /**
4176      * Multiply <code>this</code> by the matrix
4177      * <pre>
4178      * 0  0 1
4179      * 0 -1 0
4180      * 1  0 0
4181      * </pre>
4182      * 
4183      * @return this
4184      */
4185     ref public Matrix3d mapZnYx() return {
4186         mapZnYX(this);
4187         return this;
4188     }
4189     public Matrix3d mapZnYX(ref Matrix3d dest) {
4190         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4191         return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(__m00)._m21(__m01)._m22(__m02);
4192     }
4193     /**
4194      * Multiply <code>this</code> by the matrix
4195      * <pre>
4196      * 0  0 -1
4197      * 0 -1  0
4198      * 1  0  0
4199      * </pre>
4200      * 
4201      * @return this
4202      */
4203     ref public Matrix3d mapZnYnx() return {
4204         mapZnYnX(this);
4205         return this;
4206     }
4207     public Matrix3d mapZnYnX(ref Matrix3d dest) {
4208         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4209         return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-__m00)._m21(-__m01)._m22(-__m02);
4210     }
4211     /**
4212      * Multiply <code>this</code> by the matrix
4213      * <pre>
4214      * -1 0  0
4215      *  0 1  0
4216      *  0 0 -1
4217      * </pre>
4218      * 
4219      * @return this
4220      */
4221     ref public Matrix3d mapnXYnz() return {
4222         mapnXYnZ(this);
4223         return this;
4224     }
4225     public Matrix3d mapnXYnZ(ref Matrix3d dest) {
4226         return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m10)._m11(m11)._m12(m12)._m20(-m20)._m21(-m21)._m22(-m22);
4227     }
4228     /**
4229      * Multiply <code>this</code> by the matrix
4230      * <pre>
4231      * -1 0 0
4232      *  0 0 1
4233      *  0 1 0
4234      * </pre>
4235      * 
4236      * @return this
4237      */
4238     ref public Matrix3d mapnXZy() return {
4239         mapnXZY(this);
4240         return this;
4241     }
4242     public Matrix3d mapnXZY(ref Matrix3d dest) {
4243         double __m10 = this.m10, __m11 = this.m11, __m12 = this.m12;
4244         return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m20)._m11(m21)._m12(m22)._m20(__m10)._m21(__m11)._m22(__m12);
4245     }
4246     /**
4247      * Multiply <code>this</code> by the matrix
4248      * <pre>
4249      * -1 0  0
4250      *  0 0 -1
4251      *  0 1  0
4252      * </pre>
4253      * 
4254      * @return this
4255      */
4256     ref public Matrix3d mapnXZny() return {
4257         mapnXZnY(this);
4258         return this;
4259     }
4260     public Matrix3d mapnXZnY(ref Matrix3d dest) {
4261         double __m10 = this.m10, __m11 = this.m11, __m12 = this.m12;
4262         return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m20)._m11(m21)._m12(m22)._m20(-__m10)._m21(-__m11)._m22(-__m12);
4263     }
4264     /**
4265      * Multiply <code>this</code> by the matrix
4266      * <pre>
4267      * -1  0 0
4268      *  0 -1 0
4269      *  0  0 1
4270      * </pre>
4271      * 
4272      * @return this
4273      */
4274     ref public Matrix3d mapnXnYz() return {
4275         mapnXnYZ(this);
4276         return this;
4277     }
4278     public Matrix3d mapnXnYZ(ref Matrix3d dest) {
4279         return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m20)._m21(m21)._m22(m22);
4280     }
4281     /**
4282      * Multiply <code>this</code> by the matrix
4283      * <pre>
4284      * -1  0  0
4285      *  0 -1  0
4286      *  0  0 -1
4287      * </pre>
4288      * 
4289      * @return this
4290      */
4291     ref public Matrix3d mapnXnYnz() return {
4292         mapnXnYnZ(this);
4293         return this;
4294     }
4295     public Matrix3d mapnXnYnZ(ref Matrix3d dest) {
4296         return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m20)._m21(-m21)._m22(-m22);
4297     }
4298     /**
4299      * Multiply <code>this</code> by the matrix
4300      * <pre>
4301      * -1  0 0
4302      *  0  0 1
4303      *  0 -1 0
4304      * </pre>
4305      * 
4306      * @return this
4307      */
4308     ref public Matrix3d mapnXnZy() return {
4309         mapnXnZY(this);
4310         return this;
4311     }
4312     public Matrix3d mapnXnZY(ref Matrix3d dest) {
4313         double __m10 = this.m10, __m11 = this.m11, __m12 = this.m12;
4314         return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(__m10)._m21(__m11)._m22(__m12);
4315     }
4316     /**
4317      * Multiply <code>this</code> by the matrix
4318      * <pre>
4319      * -1  0  0
4320      *  0  0 -1
4321      *  0 -1  0
4322      * </pre>
4323      * 
4324      * @return this
4325      */
4326     ref public Matrix3d mapnXnZny() return {
4327         mapnXnZnY(this);
4328         return this;
4329     }
4330     public Matrix3d mapnXnZnY(ref Matrix3d dest) {
4331         double __m10 = this.m10, __m11 = this.m11, __m12 = this.m12;
4332         return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-__m10)._m21(-__m11)._m22(-__m12);
4333     }
4334     /**
4335      * Multiply <code>this</code> by the matrix
4336      * <pre>
4337      *  0 1 0
4338      * -1 0 0
4339      *  0 0 1
4340      * </pre>
4341      * 
4342      * @return this
4343      */
4344     ref public Matrix3d mapnYXz() return {
4345         mapnYXZ(this);
4346         return this;
4347     }
4348     public Matrix3d mapnYXZ(ref Matrix3d dest) {
4349         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4350         return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(__m00)._m11(__m01)._m12(__m02)._m20(m20)._m21(m21)._m22(m22);
4351     }
4352     /**
4353      * Multiply <code>this</code> by the matrix
4354      * <pre>
4355      *  0 1  0
4356      * -1 0  0
4357      *  0 0 -1
4358      * </pre>
4359      * 
4360      * @return this
4361      */
4362     ref public Matrix3d mapnYXnz() return {
4363         mapnYXnZ(this);
4364         return this;
4365     }
4366     public Matrix3d mapnYXnZ(ref Matrix3d dest) {
4367         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4368         return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(__m00)._m11(__m01)._m12(__m02)._m20(-m20)._m21(-m21)._m22(-m22);
4369     }
4370     /**
4371      * Multiply <code>this</code> by the matrix
4372      * <pre>
4373      *  0 0 1
4374      * -1 0 0
4375      *  0 1 0
4376      * </pre>
4377      * 
4378      * @return this
4379      */
4380     ref public Matrix3d mapnYZx() return {
4381         mapnYZX(this);
4382         return this;
4383     }
4384     public Matrix3d mapnYZX(ref Matrix3d dest) {
4385         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4386         return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m20)._m11(m21)._m12(m22)._m20(__m00)._m21(__m01)._m22(__m02);
4387     }
4388     /**
4389      * Multiply <code>this</code> by the matrix
4390      * <pre>
4391      *  0 0 -1
4392      * -1 0  0
4393      *  0 1  0
4394      * </pre>
4395      * 
4396      * @return this
4397      */
4398     ref public Matrix3d mapnYZnx() return {
4399         mapnYZnX(this);
4400         return this;
4401     }
4402     public Matrix3d mapnYZnX(ref Matrix3d dest) {
4403         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4404         return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m20)._m11(m21)._m12(m22)._m20(-__m00)._m21(-__m01)._m22(-__m02);
4405     }
4406     /**
4407      * Multiply <code>this</code> by the matrix
4408      * <pre>
4409      *  0 -1 0
4410      * -1  0 0
4411      *  0  0 1
4412      * </pre>
4413      * 
4414      * @return this
4415      */
4416     ref public Matrix3d mapnYnXz() return {
4417         mapnYnXZ(this);
4418         return this;
4419     }
4420     public Matrix3d mapnYnXZ(ref Matrix3d dest) {
4421         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4422         return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-__m00)._m11(-__m01)._m12(-__m02)._m20(m20)._m21(m21)._m22(m22);
4423     }
4424     /**
4425      * Multiply <code>this</code> by the matrix
4426      * <pre>
4427      *  0 -1  0
4428      * -1  0  0
4429      *  0  0 -1
4430      * </pre>
4431      * 
4432      * @return this
4433      */
4434     ref public Matrix3d mapnYnXnz() return {
4435         mapnYnXnZ(this);
4436         return this;
4437     }
4438     public Matrix3d mapnYnXnZ(ref Matrix3d dest) {
4439         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4440         return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-__m00)._m11(-__m01)._m12(-__m02)._m20(-m20)._m21(-m21)._m22(-m22);
4441     }
4442     /**
4443      * Multiply <code>this</code> by the matrix
4444      * <pre>
4445      *  0  0 1
4446      * -1  0 0
4447      *  0 -1 0
4448      * </pre>
4449      * 
4450      * @return this
4451      */
4452     ref public Matrix3d mapnYnZx() return {
4453         mapnYnZX(this);
4454         return this;
4455     }
4456     public Matrix3d mapnYnZX(ref Matrix3d dest) {
4457         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4458         return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(__m00)._m21(__m01)._m22(__m02);
4459     }
4460     /**
4461      * Multiply <code>this</code> by the matrix
4462      * <pre>
4463      *  0  0 -1
4464      * -1  0  0
4465      *  0 -1  0
4466      * </pre>
4467      * 
4468      * @return this
4469      */
4470     ref public Matrix3d mapnYnZnx() return {
4471         mapnYnZnX(this);
4472         return this;
4473     }
4474     public Matrix3d mapnYnZnX(ref Matrix3d dest) {
4475         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4476         return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-__m00)._m21(-__m01)._m22(-__m02);
4477     }
4478     /**
4479      * Multiply <code>this</code> by the matrix
4480      * <pre>
4481      *  0 1 0
4482      *  0 0 1
4483      * -1 0 0
4484      * </pre>
4485      * 
4486      * @return this
4487      */
4488     ref public Matrix3d mapnZXy() return {
4489         mapnZXY(this);
4490         return this;
4491     }
4492     public Matrix3d mapnZXY(ref Matrix3d dest) {
4493         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4494         double __m10 = this.m10, __m11 = this.m11, __m12 = this.m12;
4495         return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(__m00)._m11(__m01)._m12(__m02)._m20(__m10)._m21(__m11)._m22(__m12);
4496     }
4497     /**
4498      * Multiply <code>this</code> by the matrix
4499      * <pre>
4500      *  0 1  0
4501      *  0 0 -1
4502      * -1 0  0
4503      * </pre>
4504      * 
4505      * @return this
4506      */
4507     ref public Matrix3d mapnZXny() return {
4508         mapnZXnY(this);
4509         return this;
4510     }
4511     public Matrix3d mapnZXnY(ref Matrix3d dest) {
4512         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4513         double __m10 = this.m10, __m11 = this.m11, __m12 = this.m12;
4514         return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(__m00)._m11(__m01)._m12(__m02)._m20(-__m10)._m21(-__m11)._m22(-__m12);
4515     }
4516     /**
4517      * Multiply <code>this</code> by the matrix
4518      * <pre>
4519      *  0 0 1
4520      *  0 1 0
4521      * -1 0 0
4522      * </pre>
4523      * 
4524      * @return this
4525      */
4526     ref public Matrix3d mapnZYx() return {
4527         mapnZYX(this);
4528         return this;
4529     }
4530     public Matrix3d mapnZYX(ref Matrix3d dest) {
4531         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4532         return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m10)._m11(m11)._m12(m12)._m20(__m00)._m21(__m01)._m22(__m02);
4533     }
4534     /**
4535      * Multiply <code>this</code> by the matrix
4536      * <pre>
4537      *  0 0 -1
4538      *  0 1  0
4539      * -1 0  0
4540      * </pre>
4541      * 
4542      * @return this
4543      */
4544     ref public Matrix3d mapnZYnx() return {
4545         mapnZYnX(this);
4546         return this;
4547     }
4548     public Matrix3d mapnZYnX(ref Matrix3d dest) {
4549         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4550         return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m10)._m11(m11)._m12(m12)._m20(-__m00)._m21(-__m01)._m22(-__m02);
4551     }
4552     /**
4553      * Multiply <code>this</code> by the matrix
4554      * <pre>
4555      *  0 -1 0
4556      *  0  0 1
4557      * -1  0 0
4558      * </pre>
4559      * 
4560      * @return this
4561      */
4562     ref public Matrix3d mapnZnXy() return {
4563         mapnZnXY(this);
4564         return this;
4565     }
4566     public Matrix3d mapnZnXY(ref Matrix3d dest) {
4567         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4568         double __m10 = this.m10, __m11 = this.m11, __m12 = this.m12;
4569         return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-__m00)._m11(-__m01)._m12(-__m02)._m20(__m10)._m21(__m11)._m22(__m12);
4570     }
4571     /**
4572      * Multiply <code>this</code> by the matrix
4573      * <pre>
4574      *  0 -1  0
4575      *  0  0 -1
4576      * -1  0  0
4577      * </pre>
4578      * 
4579      * @return this
4580      */
4581     ref public Matrix3d mapnZnXny() return {
4582         mapnZnXnY(this);
4583         return this;
4584     }
4585     public Matrix3d mapnZnXnY(ref Matrix3d dest) {
4586         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4587         double __m10 = this.m10, __m11 = this.m11, __m12 = this.m12;
4588         return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-__m00)._m11(-__m01)._m12(-__m02)._m20(-__m10)._m21(-__m11)._m22(-__m12);
4589     }
4590     /**
4591      * Multiply <code>this</code> by the matrix
4592      * <pre>
4593      *  0  0 1
4594      *  0 -1 0
4595      * -1  0 0
4596      * </pre>
4597      * 
4598      * @return this
4599      */
4600     ref public Matrix3d mapnZnYx() return {
4601         mapnZnYX(this);
4602         return this;
4603     }
4604     public Matrix3d mapnZnYX(ref Matrix3d dest) {
4605         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4606         return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(__m00)._m21(__m01)._m22(__m02);
4607     }
4608     /**
4609      * Multiply <code>this</code> by the matrix
4610      * <pre>
4611      *  0  0 -1
4612      *  0 -1  0
4613      * -1  0  0
4614      * </pre>
4615      * 
4616      * @return this
4617      */
4618     ref public Matrix3d mapnZnYnx() return {
4619         mapnZnYnX(this);
4620         return this;
4621     }
4622     public Matrix3d mapnZnYnX(ref Matrix3d dest) {
4623         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
4624         return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-__m00)._m21(-__m01)._m22(-__m02);
4625     }
4626 
4627     /**
4628      * Multiply <code>this</code> by the matrix
4629      * <pre>
4630      * -1 0 0
4631      *  0 1 0
4632      *  0 0 1
4633      * </pre>
4634      * 
4635      * @return this
4636      */
4637     ref public Matrix3d negatex() return {
4638         return _m00(-m00)._m01(-m01)._m02(-m02);
4639     }
4640     public Matrix3d negateX(ref Matrix3d dest) {
4641         return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m10)._m11(m11)._m12(m12)._m20(m20)._m21(m21)._m22(m22);
4642     }
4643 
4644     /**
4645      * Multiply <code>this</code> by the matrix
4646      * <pre>
4647      * 1  0 0
4648      * 0 -1 0
4649      * 0  0 1
4650      * </pre>
4651      * 
4652      * @return this
4653      */
4654     ref public Matrix3d negatey() return {
4655         return _m10(-m10)._m11(-m11)._m12(-m12);
4656     }
4657     public Matrix3d negateY(ref Matrix3d dest) {
4658         return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m20)._m21(m21)._m22(m22);
4659     }
4660 
4661     /**
4662      * Multiply <code>this</code> by the matrix
4663      * <pre>
4664      * 1 0  0
4665      * 0 1  0
4666      * 0 0 -1
4667      * </pre>
4668      * 
4669      * @return this
4670      */
4671     ref public Matrix3d negatez() return {
4672         return _m20(-m20)._m21(-m21)._m22(-m22);
4673     }
4674     public Matrix3d negateZ(ref Matrix3d dest) {
4675         return dest._m00(m00)._m01(m01)._m02(m02)._m10(m10)._m11(m11)._m12(m12)._m20(-m20)._m21(-m21)._m22(-m22);
4676     }
4677 }