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