1 /**
2  * Contains the definition of a 2x2 matrix of doubles, and associated functions to transform
3  * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this:
4  * <p>
5  *      m00  m10<br>
6  *      m01  m11<br>
7  *
8  * @author Joseph Burton
9  */
10 module doml.matrix_2d;
11 
12 import Math = doml.math;
13 import MemUtil = doml.mem_util;
14 
15 import doml.matrix_3d;
16 import doml.matrix_3x2d;
17 
18 import doml.vector_2d;
19 
20 
21 /*
22  * The MIT License
23  *
24  * Copyright (c) 2020-2021 JOML
25  %%$%# translated by jordan4ibanez
26  *
27  * Permission is hereby granted, free of charge, to any person obtaining a copy
28  * of this software and associated documentation files (the "Software"), to deal
29  * in the Software without restriction, including without limitation the rights
30  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31  * copies of the Software, and to permit persons to whom the Software is
32  * furnished to do so, subject to the following conditions:
33  *
34  * The above copyright notice and this permission notice shall be included in
35  * all copies or substantial portions of the Software.
36  *
37  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
40  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
43  * THE SOFTWARE.
44  */
45 
46 
47 /**
48  * Contains the definition of a 2x2 matrix of doubles, and associated functions to transform
49  * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this:
50  * <p>
51  *      m00  m10<br>
52  *      m01  m11<br>
53  *
54  * @author Joseph Burton
55  */
56 public struct Matrix2d {
57 
58     // Defaults to identity
59     double m00 = 1.0;
60     double m01 = 0.0;
61     double m10 = 0.0;
62     double m11 = 1.0;
63 
64 
65     /**
66      * Create a new {@link Matrix2d} and make it a copy of the given matrix.
67      *
68      * @param mat
69      *          the {@link Matrix2d} to copy the values from
70      */
71     this(Matrix2d mat) {
72         setMatrix2d(mat);
73     }
74 
75 
76     /**
77      * Create a new {@link Matrix2d} and make it a copy of the upper left 2x2 of the given {@link Matrix3d}.
78      *
79      * @param mat
80      *          the {@link Matrix3d} to copy the values from
81      */
82     this(Matrix3d mat) {
83         setMatrix3d(mat);
84     }
85 
86 
87     /**
88      * Create a new 2x2 matrix using the supplied double values. The order of the parameter is column-major,
89      * so the first two parameters specify the two elements of the first column.
90      *
91      * @param m00
92      *          the value of m00
93      * @param m01
94      *          the value of m01
95      * @param m10
96      *          the value of m10
97      * @param m11
98      *          the value of m11
99      */
100     this(double m00, double m01,
101                     double m10, double m11) {
102         this.m00 = m00;
103         this.m01 = m01;
104         this.m10 = m10;
105         this.m11 = m11;
106     }
107 
108     /**
109      * Create a new {@link Matrix2d} and initialize its two columns using the supplied vectors.
110      *
111      * @param col0
112      *          the first column
113      * @param col1
114      *          the second column
115      */
116     this(Vector2d col0, Vector2d col1) {
117         m00 = col0.x;
118         m01 = col0.y;
119         m10 = col1.x;
120         m11 = col1.y;
121     }
122 
123     /**
124      * Set the value of the matrix element at column 0 and row 0.
125      *
126      * @param m00
127      *          the new value
128      * @return this
129      */
130     ref public Matrix2d setm00(double m00) return {
131         this.m00 = m00;
132         return this;
133     }
134     /**
135      * Set the value of the matrix element at column 0 and row 1.
136      *
137      * @param m01
138      *          the new value
139      * @return this
140      */
141     ref public Matrix2d setm01(double m01) return {
142         this.m01 = m01;
143         return this;
144     }
145     /**
146      * Set the value of the matrix element at column 1 and row 0.
147      *
148      * @param m10
149      *          the new value
150      * @return this
151      */
152     ref public Matrix2d setm10(double m10) return {
153         this.m10 = m10;
154         return this;
155     }
156     /**
157      * Set the value of the matrix element at column 1 and row 1.
158      *
159      * @param m11
160      *          the new value
161      * @return this
162      */
163     ref public Matrix2d setm11(double m11) return {
164         this.m11 = m11;
165         return this;
166     }
167 
168     /**
169      * Set the value of the matrix element at column 0 and row 0.
170      *
171      * @param m00
172      *          the new value
173      * @return this
174      */
175     ref Matrix2d _m00(double m00) return {
176         this.m00 = m00;
177         return this;
178     }
179     /**
180      * Set the value of the matrix element at column 0 and row 1.
181      *
182      * @param m01
183      *          the new value
184      * @return this
185      */
186     ref Matrix2d _m01(double m01) return {
187         this.m01 = m01;
188         return this;
189     }
190     /**
191      * Set the value of the matrix element at column 1 and row 0.
192      *
193      * @param m10
194      *          the new value
195      * @return this
196      */
197     ref Matrix2d _m10(double m10) return {
198         this.m10 = m10;
199         return this;
200     }
201     /**
202      * Set the value of the matrix element at column 1 and row 1.
203      *
204      * @param m11
205      *          the new value
206      * @return this
207      */
208     ref Matrix2d _m11(double m11) return {
209         this.m11 = m11;
210         return this;
211     }
212 
213     /**
214      * Set the elements of this matrix to the ones in <code>m</code>.
215      *
216      * @param m
217      *          the matrix to copy the elements from
218      * @return this
219      */
220     ref public Matrix2d set(Matrix2d m) return {
221         setMatrix2d(m);
222         return this;
223     }
224     private void setMatrix2d(Matrix2d mat) {
225         m00 = mat.m00;
226         m01 = mat.m01;
227         m10 = mat.m10;
228         m11 = mat.m11;
229     }
230 
231 
232     /**
233      * Set the elements of this matrix to the left 2x2 submatrix of <code>m</code>.
234      *
235      * @param m
236      *          the matrix to copy the elements from
237      * @return this
238      */
239     ref public Matrix2d set(Matrix3x2d m) return {
240         setMatrix3x2d(m);
241         return this;
242     }
243     private void setMatrix3x2d(Matrix3x2d mat) {
244         m00 = mat.m00;
245         m01 = mat.m01;
246         m10 = mat.m10;
247         m11 = mat.m11;
248     }
249 
250     /**
251      * Set the elements of this matrix to the upper left 2x2 of the given {@link Matrix3d}.
252      *
253      * @param m
254      *          the {@link Matrix3d} to copy the values from
255      * @return this
256      */
257     ref public Matrix2d set(Matrix3d m) return {
258         setMatrix3d(m);
259         return this;
260     }
261     private void setMatrix3d(Matrix3d mat) {
262         m00 = mat.m00;
263         m01 = mat.m01;
264         m10 = mat.m10;
265         m11 = mat.m11;
266     }
267 
268 
269     /**
270      * Multiply this matrix by the supplied <code>right</code> matrix.
271      * <p>
272      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix,
273      * then the new matrix will be <code>M * R</code>. So when transforming a
274      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
275      * transformation of the right matrix will be applied first!
276      *
277      * @param right
278      *          the right operand of the matrix multiplication
279      * @return this
280      */
281     ref public Matrix2d mul(Matrix2d right) return {
282         this.mul(right, this);
283         return this;
284     }
285 
286     public Matrix2d mul(Matrix2d right, ref Matrix2d dest) {
287         double nm00 = m00 * right.m00 + m10 * right.m01;
288         double nm01 = m01 * right.m00 + m11 * right.m01;
289         double nm10 = m00 * right.m10 + m10 * right.m11;
290         double nm11 = m01 * right.m10 + m11 * right.m11;
291         dest.m00 = nm00;
292         dest.m01 = nm01;
293         dest.m10 = nm10;
294         dest.m11 = nm11;
295         return dest;
296     }
297 
298     /**
299      * Pre-multiply this matrix by the supplied <code>left</code> matrix and store the result in <code>this</code>.
300      * <p>
301      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the <code>left</code> matrix,
302      * then the new matrix will be <code>L * M</code>. So when transforming a
303      * vector <code>v</code> with the new matrix by using <code>L * M * v</code>, the
304      * transformation of <code>this</code> matrix will be applied first!
305      *
306      * @param left
307      *          the left operand of the matrix multiplication
308      * @return this
309      */
310     ref public Matrix2d mulLocal(Matrix2d left) return {
311         this.mulLocal(left, this);
312         return this;
313     }
314 
315     public Matrix2d mulLocal(Matrix2d left, ref Matrix2d dest) {
316         double nm00 = left.m00 * m00 + left.m10 * m01;
317         double nm01 = left.m01 * m00 + left.m11 * m01;
318         double nm10 = left.m00 * m10 + left.m10 * m11;
319         double nm11 = left.m01 * m10 + left.m11 * m11;
320         dest.m00 = nm00;
321         dest.m01 = nm01;
322         dest.m10 = nm10;
323         dest.m11 = nm11;
324         return dest;
325     }
326 
327     /**
328      * Set the values within this matrix to the supplied double values. The result looks like this:
329      * <p>
330      * m00, m10<br>
331      * m01, m11<br>
332      *
333      * @param m00
334      *          the new value of m00
335      * @param m01
336      *          the new value of m01
337      * @param m10
338      *          the new value of m10
339      * @param m11
340      *          the new value of m11
341      * @return this
342      */
343     ref public Matrix2d set(double m00, double m01,
344                         double m10, double m11) return {
345         this.m00 = m00;
346         this.m01 = m01;
347         this.m10 = m10;
348         this.m11 = m11;
349         return this;
350     }
351     /**
352      * Set the two columns of this matrix to the supplied vectors, respectively.
353      *
354      * @param col0
355      *          the first column
356      * @param col1
357      *          the second column
358      * @return this
359      */
360     ref public Matrix2d set(Vector2d col0, Vector2d col1) return {
361         m00 = col0.x;
362         m01 = col0.y;
363         m10 = col1.x;
364         m11 = col1.y;
365         return this;
366     }
367 
368     public double determinant() {
369         return m00 * m11 - m10 * m01;
370     }
371 
372     /**
373      * Invert this matrix.
374      *
375      * @return this
376      */
377     ref public Matrix2d invert() return {
378         this.invert(this);
379         return this;
380     }
381 
382     public Matrix2d invert(ref Matrix2d dest) {
383         double s = 1.0 / determinant();
384         double nm00 = m11 * s;
385         double nm01 = -m01 * s;
386         double nm10 = -m10 * s;
387         double nm11 = m00 * s;
388         dest.m00 = nm00;
389         dest.m01 = nm01;
390         dest.m10 = nm10;
391         dest.m11 = nm11;
392         return dest;
393     }
394 
395     /**
396      * Transpose this matrix.
397      *
398      * @return this
399      */
400     ref public Matrix2d transpose() return {
401         this.transpose(this);
402         return this;
403     }
404 
405     public Matrix2d transpose(ref Matrix2d dest) {
406         dest.set(m00, m10,
407                 m01, m11);
408         return dest;
409     }
410 
411    
412     /**
413      * Get the current values of <code>this</code> matrix and store them into
414      * <code>dest</code>.
415      * <p>
416      * This is the reverse method of {@link #set(Matrix2d)} and allows to obtain
417      * intermediate calculation results when chaining multiple transformations.
418      *
419      * @see #set(Matrix2d)
420      *
421      * @param dest
422      *          the destination matrix
423      * @return the passed in destination
424      */
425     public Matrix2d get(ref Matrix2d dest) {
426         return dest.set(this);
427     }
428 
429     public Matrix3x2d get(ref Matrix3x2d dest) {
430         return dest.set(this);
431     }
432 
433     public Matrix3d get(ref Matrix3d dest) {
434         return dest.set(this);
435     }
436 
437     public double getRotation() {
438         return cast(double) Math.atan2(m01, m11);
439     }
440 
441     /**
442      * Set all values within this matrix to zero.
443      *
444      * @return this
445      */
446     ref public Matrix2d zero() return {
447         MemUtil.zero(this);
448         return this;
449     }
450 
451     /**
452      * Set this matrix to the identity.
453      *
454      * @return this
455      */
456     ref public Matrix2d identity() return {
457         m00 = 1.0;
458         m01 = 0.0;
459         m10 = 0.0;
460         m11 = 1.0;
461         return this;
462     }
463 
464     public Matrix2d scale(Vector2d xy, ref Matrix2d dest) {
465         return scale(xy.x, xy.y, dest);
466     }
467 
468     /**
469      * Apply scaling to this matrix by scaling the base axes by the given <code>xy.x</code> and
470      * <code>xy.y</code> factors, respectively.
471      * <p>
472      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
473      * then the new matrix will be <code>M * S</code>. So when transforming a
474      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the
475      * scaling will be applied first!
476      *
477      * @param xy
478      *            the factors of the x and y component, respectively
479      * @return this
480      */
481     ref public Matrix2d scale(Vector2d xy) return {
482         this.scale(xy.x, xy.y, this);
483         return this;
484     }
485 
486     public Matrix2d scale(double x, double y, ref Matrix2d dest) {
487         // scale matrix elements:
488         // m00 = x, m11 = y
489         // all others = 0
490         dest.m00 = m00 * x;
491         dest.m01 = m01 * x;
492         dest.m10 = m10 * y;
493         dest.m11 = m11 * y;
494         return dest;
495     }
496 
497     /**
498      * Apply scaling to this matrix by scaling the base axes by the given x and
499      * y factors.
500      * <p>
501      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
502      * then the new matrix will be <code>M * S</code>. So when transforming a
503      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>
504      * , the scaling will be applied first!
505      *
506      * @param x
507      *            the factor of the x component
508      * @param y
509      *            the factor of the y component
510      * @return this
511      */
512     ref public Matrix2d scale(double x, double y) return {
513         this.scale(x, y, this);
514         return this;
515     }
516 
517     public Matrix2d scale(double xy, ref Matrix2d dest) {
518         return scale(xy, xy, dest);
519     }
520 
521     /**
522      * Apply scaling to this matrix by uniformly scaling all base axes by the given <code>xy</code> factor.
523      * <p>
524      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
525      * then the new matrix will be <code>M * S</code>. So when transforming a
526      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>
527      * , the scaling will be applied first!
528      *
529      * @see #scale(double, double)
530      *
531      * @param xy
532      *            the factor for all components
533      * @return this
534      */
535     ref public Matrix2d scale(double xy) return {
536         return scale(xy, xy);
537     }
538 
539     public Matrix2d scaleLocal(double x, double y, ref Matrix2d dest) {
540         dest.m00 = x * m00;
541         dest.m01 = y * m01;
542         dest.m10 = x * m10;
543         dest.m11 = y * m11;
544         return dest;
545     }
546 
547     /**
548      * Pre-multiply scaling to this matrix by scaling the base axes by the given x and
549      * y factors.
550      * <p>
551      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
552      * then the new matrix will be <code>S * M</code>. So when transforming a
553      * vector <code>v</code> with the new matrix by using <code>S * M * v</code>, the
554      * scaling will be applied last!
555      *
556      * @param x
557      *            the factor of the x component
558      * @param y
559      *            the factor of the y component
560      * @return this
561      */
562     ref public Matrix2d scaleLocal(double x, double y) return {
563         this.scaleLocal(x, y, this);
564         return this;
565     }
566 
567     /**
568      * Set this matrix to be a simple scale matrix, which scales all axes uniformly by the given factor.
569      * <p>
570      * The resulting matrix can be multiplied against another transformation
571      * matrix to obtain an additional scaling.
572      * <p>
573      * In order to post-multiply a scaling transformation directly to a
574      * matrix, use {@link #scale(double) scale()} instead.
575      *
576      * @see #scale(double)
577      *
578      * @param factor
579      *             the scale factor in x and y
580      * @return this
581      */
582     ref public Matrix2d scaling(double factor) return {
583         MemUtil.zero(this);
584         m00 = factor;
585         m11 = factor;
586         return this;
587     }
588 
589     /**
590      * Set this matrix to be a simple scale matrix.
591      *
592      * @param x
593      *             the scale in x
594      * @param y
595      *             the scale in y
596      * @return this
597      */
598     ref public Matrix2d scaling(double x, double y) return {
599         MemUtil.zero(this);
600         m00 = x;
601         m11 = y;
602         return this;
603     }
604 
605     /**
606      * Set this matrix to be a simple scale matrix which scales the base axes by <code>xy.x</code> and <code>xy.y</code> respectively.
607      * <p>
608      * The resulting matrix can be multiplied against another transformation
609      * matrix to obtain an additional scaling.
610      * <p>
611      * In order to post-multiply a scaling transformation directly to a
612      * matrix use {@link #scale(Vector2d) scale()} instead.
613      *
614      * @see #scale(Vector2d)
615      *
616      * @param xy
617      *             the scale in x and y respectively
618      * @return this
619      */
620     ref public Matrix2d scaling(Vector2d xy) return {
621         return scaling(xy.x, xy.y);
622     }
623 
624     /**
625      * Set this matrix to a rotation matrix which rotates the given radians about the origin.
626      * <p>
627      * The produced rotation will rotate a vector counter-clockwise around the origin.
628      * <p>
629      * The resulting matrix can be multiplied against another transformation
630      * matrix to obtain an additional rotation.
631      * <p>
632      * In order to post-multiply a rotation transformation directly to a
633      * matrix, use {@link #rotate(double) rotate()} instead.
634      *
635      * @see #rotate(double)
636      *
637      * @param angle
638      *          the angle in radians
639      * @return this
640      */
641     ref public Matrix2d rotation(double angle) return {
642         double sin = Math.sin(angle);
643         double cos = Math.cosFromSin(sin, angle);
644         m00 = cos;
645         m01 = sin;
646         m10 = -sin;
647         m11 = cos;
648         return this;
649     }
650 
651     public Vector2d transform(Vector2d v) {
652         return v.mul(this);
653     }
654 
655     public Vector2d transform(Vector2d v, ref Vector2d dest) {
656         v.mul(this, dest);
657         return dest;
658     }
659 
660     public Vector2d transform(double x, double y, ref Vector2d dest) {
661         dest.set(m00 * x + m10 * y,
662                 m01 * x + m11 * y);
663         return dest;
664     }
665 
666     public Vector2d transformTranspose(Vector2d v) {
667         return v.mulTranspose(this);
668     }
669 
670     public Vector2d transformTranspose(Vector2d v, ref Vector2d dest) {
671         v.mulTranspose(this, dest);
672         return dest;
673     }
674 
675     public Vector2d transformTranspose(double x, double y, ref Vector2d dest) {
676         dest.set(m00 * x + m01 * y,
677                 m10 * x + m11 * y);
678         return dest;
679     }
680 
681     /**
682      * Apply rotation about the origin to this matrix by rotating the given amount of radians.
683      * <p>
684      * The produced rotation will rotate a vector counter-clockwise around the origin.
685      * <p>
686      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
687      * then the new matrix will be <code>M * R</code>. So when transforming a
688      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>
689      * , the rotation will be applied first!
690      * <p>
691      * Reference: <a href="https://en.wikipedia.org/wiki/Rotation_matrix#In_two_dimensions">http://en.wikipedia.org</a>
692      *
693      * @param angle
694      *            the angle in radians
695      * @return this
696      */
697     ref public Matrix2d rotate(double angle) return {
698         this.rotate(angle, this);
699         return this;
700     }
701 
702     public Matrix2d rotate(double angle, ref Matrix2d dest) {
703         double s = Math.sin(angle);
704         double c = Math.cosFromSin(s, angle);
705         // rotation matrix elements:
706         // m00 = c, m01 = s, m10 = -s, m11 = c
707         double nm00 = m00 * c + m10 * s;
708         double nm01 = m01 * c + m11 * s;
709         double nm10 = m10 * c - m00 * s;
710         double nm11 = m11 * c - m01 * s;
711         dest.m00 = nm00;
712         dest.m01 = nm01;
713         dest.m10 = nm10;
714         dest.m11 = nm11;
715         return dest;
716     }
717 
718     /**
719      * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the origin.
720      * <p>
721      * The produced rotation will rotate a vector counter-clockwise around the origin.
722      * <p>
723      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
724      * then the new matrix will be <code>R * M</code>. So when transforming a
725      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
726      * rotation will be applied last!
727      * <p>
728      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
729      * transformation, use {@link #rotation(double) rotation()}.
730      * <p>
731      * Reference: <a href="https://en.wikipedia.org/wiki/Rotation_matrix#In_two_dimensions">http://en.wikipedia.org</a>
732      *
733      * @see #rotation(double)
734      *
735      * @param angle
736      *            the angle in radians to rotate about the X axis
737      * @return this
738      */
739     ref public Matrix2d rotateLocal(double angle) return {
740         this.rotateLocal(angle, this);
741         return this;
742     }
743 
744     public Matrix2d rotateLocal(double angle, ref Matrix2d dest) {
745         double s = Math.sin(angle);
746         double c = Math.cosFromSin(s, angle);
747         // rotation matrix elements:
748         // m00 = c, m01 = s, m10 = -s, m11 = c
749         double nm00 = c * m00 - s * m01;
750         double nm01 = s * m00 + c * m01;
751         double nm10 = c * m10 - s * m11;
752         double nm11 = s * m10 + c * m11;
753         dest.m00 = nm00;
754         dest.m01 = nm01;
755         dest.m10 = nm10;
756         dest.m11 = nm11;
757         return dest;
758     }
759 
760     public Vector2d getRow(int row, ref Vector2d dest) {
761         switch (row) {
762             case 0:
763                 dest.x = m00;
764                 dest.y = m10;
765                 break;
766             case 1:
767                 dest.x = m01;
768                 dest.y = m11;
769                 break;
770             default: {}
771         }
772         return dest;
773     }
774 
775     /**
776      * Set the row at the given <code>row</code> index, starting with <code>0</code>.
777      *
778      * @param row
779      *          the row index in <code>[0..1]</code>
780      * @param src
781      *          the row components to set
782      * @return this
783      * @throws IndexOutOfBoundsException if <code>row</code> is not in <code>[0..1]</code>
784      */
785     ref public Matrix2d setRow(int row, Vector2d src) return {
786         return setRow(row, src.x, src.y);
787     }
788 
789     /**
790      * Set the row at the given <code>row</code> index, starting with <code>0</code>.
791      *
792      * @param row
793      *          the row index in <code>[0..1]</code>
794      * @param x
795      *          the first element in the row
796      * @param y
797      *          the second element in the row
798      * @return this
799      * @throws IndexOutOfBoundsException if <code>row</code> is not in <code>[0..1]</code>
800      */
801     ref public Matrix2d setRow(int row, double x, double y) return {
802         switch (row) {
803             case 0:
804                 this.m00 = x;
805                 this.m10 = y;
806                 break;
807             case 1:
808                 this.m01 = x;
809                 this.m11 = y;
810                 break;
811             default:{}
812         }
813         return this;
814     }
815 
816     public Vector2d getColumn(int column, ref Vector2d dest){
817         switch (column) {
818             case 0:
819                 dest.x = m00;
820                 dest.y = m01;
821                 break;
822             case 1:
823                 dest.x = m10;
824                 dest.y = m11;
825                 break;
826             default:{}
827         }
828         return dest;
829     }
830 
831     /**
832      * Set the column at the given <code>column</code> index, starting with <code>0</code>.
833      *
834      * @param column
835      *          the column index in <code>[0..1]</code>
836      * @param src
837      *          the column components to set
838      * @return this
839      * @throws IndexOutOfBoundsException if <code>column</code> is not in <code>[0..1]</code>
840      */
841     ref public Matrix2d setColumn(int column, Vector2d src) return {
842         return setColumn(column, src.x, src.y);
843     }
844 
845     /**
846      * Set the column at the given <code>column</code> index, starting with <code>0</code>.
847      *
848      * @param column
849      *          the column index in <code>[0..1]</code>
850      * @param x
851      *          the first element in the column
852      * @param y
853      *          the second element in the column
854      * @return this
855      * @throws IndexOutOfBoundsException if <code>column</code> is not in <code>[0..1]</code>
856      */
857     ref public Matrix2d setColumn(int column, double x, double y) return {
858         switch (column) {
859             case 0:
860                 this.m00 = x;
861                 this.m01 = y;
862                 break;
863             case 1:
864                 this.m10 = x;
865                 this.m11 = y;
866                 break;
867             default: {}
868         }
869         return this;
870     }
871 
872     public double get(int column, int row) {
873         switch (column) {
874             case 0:
875                 switch (row) {
876                     case 0:
877                         return m00;
878                     case 1:
879                         return m01;
880                     default:
881                         break;
882                 }
883                 break;
884             case 1:
885                 switch (row) {
886                     case 0:
887                         return m10;
888                     case 1:
889                         return m11;
890                     default:
891                         break;
892                 }
893                 break;
894             default:{}
895         }
896         return 0;
897     }
898 
899     /**
900      * Set the matrix element at the given column and row to the specified value.
901      *
902      * @param column
903      *          the colum index in <code>[0..1]</code>
904      * @param row
905      *          the row index in <code>[0..1]</code>
906      * @param value
907      *          the value
908      * @return this
909      */
910     ref public Matrix2d set(int column, int row, double value) return {
911         switch (column) {
912             case 0:
913                 switch (row) {
914                     case 0:
915                         this.m00 = value;
916                         return this;
917                     case 1:
918                         this.m01 = value;
919                         return this;
920                     default:
921                         break;
922                 }
923                 break;
924             case 1:
925                 switch (row) {
926                     case 0:
927                         this.m10 = value;
928                         return this;
929                     case 1:
930                         this.m11 = value;
931                         return this;
932                     default:
933                         break;
934                 }
935                 break;
936             default:{}
937         }
938         return this;
939     }
940 
941     /**
942      * Set <code>this</code> matrix to its own normal matrix.
943      * <p>
944      * Please note that, if <code>this</code> is an orthogonal matrix or a matrix whose columns are orthogonal vectors,
945      * then this method <i>need not</i> be invoked, since in that case <code>this</code> itself is its normal matrix.
946      * In this case, use {@link #set(Matrix2d)} to set a given Matrix2d to this matrix.
947      *
948      * @see #set(Matrix2d)
949      *
950      * @return this
951      */
952     ref public Matrix2d normal() return {
953         this.normal(this);
954         return this;
955     }
956 
957     /**
958      * Compute a normal matrix from <code>this</code> matrix and store it into <code>dest</code>.
959      * <p>
960      * Please note that, if <code>this</code> is an orthogonal matrix or a matrix whose columns are orthogonal vectors,
961      * then this method <i>need not</i> be invoked, since in that case <code>this</code> itself is its normal matrix.
962      * In this case, use {@link #set(Matrix2d)} to set a given Matrix2d to this matrix.
963      *
964      * @see #set(Matrix2d)
965      *
966      * @param dest
967      *             will hold the result
968      * @return dest
969      */
970     public Matrix2d normal(ref Matrix2d dest) {
971         double det = m00 * m11 - m10 * m01;
972         double s = 1.0 / det;
973         /* Invert and transpose in one go */
974         double nm00 = m11 * s;
975         double nm01 = -m10 * s;
976         double nm10 = -m01 * s;
977         double nm11 = m00 * s;
978         dest.m00 = nm00;
979         dest.m01 = nm01;
980         dest.m10 = nm10;
981         dest.m11 = nm11;
982         return dest;
983     }
984 
985     public Vector2d getScale(ref Vector2d dest) {
986         dest.x = Math.sqrt(m00 * m00 + m01 * m01);
987         dest.y = Math.sqrt(m10 * m10 + m11 * m11);
988         return dest;
989     }
990 
991     public Vector2d positiveX(Vector2d dir) {
992         if (m00 * m11 < m01 * m10) { // negative determinant?
993             dir.x = -m11;
994             dir.y = m01;
995         } else {
996             dir.x = m11;
997             dir.y = -m01;
998         }
999         return dir.normalize(dir);
1000     }
1001 
1002     public Vector2d normalizedPositiveX(Vector2d dir) {
1003         if (m00 * m11 < m01 * m10) { // negative determinant?
1004             dir.x = -m11;
1005             dir.y = m01;
1006         } else {
1007             dir.x = m11;
1008             dir.y = -m01;
1009         }
1010         return dir;
1011     }
1012 
1013     public Vector2d positiveY(Vector2d dir) {
1014         if (m00 * m11 < m01 * m10) { // negative determinant?
1015             dir.x = m10;
1016             dir.y = -m00;
1017         } else {
1018             dir.x = -m10;
1019             dir.y = m00;
1020         }
1021         return dir.normalize(dir);
1022     }
1023 
1024     public Vector2d normalizedPositiveY(Vector2d dir) {
1025         if (m00 * m11 < m01 * m10) { // negative determinant?
1026             dir.x = m10;
1027             dir.y = -m00;
1028         } else {
1029             dir.x = -m10;
1030             dir.y = m00;
1031         }
1032         return dir;
1033     }
1034 
1035     public int hashCode() {
1036         immutable int prime = 31;
1037         int result = 1;
1038         long temp;
1039         temp = Math.doubleToLongBits(m00);
1040         result = prime * result + cast(int) ((temp >>> 32) ^ temp);
1041         temp = Math.doubleToLongBits(m01);
1042         result = prime * result + cast(int) ((temp >>> 32) ^ temp);
1043         temp = Math.doubleToLongBits(m10);
1044         result = prime * result + cast(int) ((temp >>> 32) ^ temp);
1045         temp = Math.doubleToLongBits(m11);
1046         result = prime * result + cast(int) ((temp >>> 32) ^ temp);
1047         return result;
1048     }
1049 
1050     public bool equals(Matrix2d m, double delta) {
1051         if (this == m)
1052             return true;
1053         if (!Math.equals(m00, m.m00, delta))
1054             return false;
1055         if (!Math.equals(m01, m.m01, delta))
1056             return false;
1057         if (!Math.equals(m10, m.m10, delta))
1058             return false;
1059         if (!Math.equals(m11, m.m11, delta))
1060             return false;
1061         return true;
1062     }
1063 
1064     /**
1065      * Exchange the values of <code>this</code> matrix with the given <code>other</code> matrix.
1066      *
1067      * @param other
1068      *          the other matrix to exchange the values with
1069      * @return this
1070      */
1071     ref public Matrix2d swap(ref Matrix2d other) return {
1072         MemUtil.swap(this, other);
1073         return this;
1074     }
1075 
1076     /**
1077      * Component-wise add <code>this</code> and <code>other</code>.
1078      *
1079      * @param other
1080      *          the other addend
1081      * @return this
1082      */
1083     ref public Matrix2d add(Matrix2d other) return {
1084         this.add(other, this);
1085         return this;
1086     }
1087 
1088     public Matrix2d add(Matrix2d other, ref Matrix2d dest) {
1089         dest.m00 = m00 + other.m00;
1090         dest.m01 = m01 + other.m01;
1091         dest.m10 = m10 + other.m10;
1092         dest.m11 = m11 + other.m11;
1093         return dest;
1094     }
1095 
1096     /**
1097      * Component-wise subtract <code>subtrahend</code> from <code>this</code>.
1098      *
1099      * @param subtrahend
1100      *          the subtrahend
1101      * @return this
1102      */
1103     ref public Matrix2d sub(Matrix2d subtrahend) return {
1104         this.sub(subtrahend, this);
1105         return this;
1106     }
1107 
1108     public Matrix2d sub(Matrix2d other, ref Matrix2d dest) {
1109         dest.m00 = m00 - other.m00;
1110         dest.m01 = m01 - other.m01;
1111         dest.m10 = m10 - other.m10;
1112         dest.m11 = m11 - other.m11;
1113         return dest;
1114     }
1115 
1116     /**
1117      * Component-wise multiply <code>this</code> by <code>other</code>.
1118      *
1119      * @param other
1120      *          the other matrix
1121      * @return this
1122      */
1123     public Matrix2d mulComponentWise(Matrix2d other) {
1124         return sub(other, this);
1125     }
1126 
1127     public Matrix2d mulComponentWise(Matrix2d other, ref Matrix2d dest) {
1128         dest.m00 = m00 * other.m00;
1129         dest.m01 = m01 * other.m01;
1130         dest.m10 = m10 * other.m10;
1131         dest.m11 = m11 * other.m11;
1132         return dest;
1133     }
1134 
1135     /**
1136      * Linearly interpolate <code>this</code> and <code>other</code> using the given interpolation factor <code>t</code>
1137      * and store the result in <code>this</code>.
1138      * <p>
1139      * 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>
1140      * then the result is <code>other</code>.
1141      *
1142      * @param other
1143      *          the other matrix
1144      * @param t
1145      *          the interpolation factor between 0.0 and 1.0
1146      * @return this
1147      */
1148     public Matrix2d lerp(Matrix2d other, double t) {
1149         return lerp(other, t, this);
1150     }
1151 
1152     public Matrix2d lerp(Matrix2d other, double t, ref Matrix2d dest) {
1153         dest.m00 = Math.fma(other.m00 - m00, t, m00);
1154         dest.m01 = Math.fma(other.m01 - m01, t, m01);
1155         dest.m10 = Math.fma(other.m10 - m10, t, m10);
1156         dest.m11 = Math.fma(other.m11 - m11, t, m11);
1157         return dest;
1158     }
1159 
1160     public bool isFinite() {
1161         return Math.isFinite(m00) && Math.isFinite(m01) &&
1162                Math.isFinite(m10) && Math.isFinite(m11);
1163     }
1164 }