001/**
002 * Copyright (c) 2008-2014 Ardor Labs, Inc.
003 *
004 * This file is part of Ardor3D.
005 *
006 * Ardor3D is free software: you can redistribute it and/or modify it 
007 * under the terms of its license which may be found in the accompanying
008 * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
009 */
010
011package com.ardor3d.math;
012
013import static org.junit.Assert.*;
014
015import java.nio.DoubleBuffer;
016import java.nio.FloatBuffer;
017
018import org.junit.Test;
019
020public class TestMatrix4 {
021
022    @Test
023    public void testGetSet() {
024        final Matrix4 mat4A = new Matrix4();
025        assertEquals(Matrix4.IDENTITY, mat4A);
026
027        mat4A.setM00(0.0);
028        mat4A.setM01(0.1);
029        mat4A.setM02(0.2);
030        mat4A.setM03(0.3);
031        mat4A.setM10(1.0);
032        mat4A.setM11(1.1);
033        mat4A.setM12(1.2);
034        mat4A.setM13(1.3);
035        mat4A.setM20(2.0);
036        mat4A.setM21(2.1);
037        mat4A.setM22(2.2);
038        mat4A.setM23(2.3);
039        mat4A.setM30(3.0);
040        mat4A.setM31(3.1);
041        mat4A.setM32(3.2);
042        mat4A.setM33(3.3);
043
044        assertTrue(0.0 == mat4A.getM00());
045        assertTrue(0.1 == mat4A.getM01());
046        assertTrue(0.2 == mat4A.getM02());
047        assertTrue(0.3 == mat4A.getM03());
048        assertTrue(1.0 == mat4A.getM10());
049        assertTrue(1.1 == mat4A.getM11());
050        assertTrue(1.2 == mat4A.getM12());
051        assertTrue(1.3 == mat4A.getM13());
052        assertTrue(2.0 == mat4A.getM20());
053        assertTrue(2.1 == mat4A.getM21());
054        assertTrue(2.2 == mat4A.getM22());
055        assertTrue(2.3 == mat4A.getM23());
056        assertTrue(3.0 == mat4A.getM30());
057        assertTrue(3.1 == mat4A.getM31());
058        assertTrue(3.2 == mat4A.getM32());
059        assertTrue(3.3 == mat4A.getM33());
060
061        final Matrix4 mat4B = new Matrix4(mat4A);
062        assertTrue(0.0 == mat4B.getM00());
063        assertTrue(0.1 == mat4B.getM01());
064        assertTrue(0.2 == mat4B.getM02());
065        assertTrue(0.3 == mat4B.getM03());
066        assertTrue(1.0 == mat4B.getM10());
067        assertTrue(1.1 == mat4B.getM11());
068        assertTrue(1.2 == mat4B.getM12());
069        assertTrue(1.3 == mat4B.getM13());
070        assertTrue(2.0 == mat4B.getM20());
071        assertTrue(2.1 == mat4B.getM21());
072        assertTrue(2.2 == mat4B.getM22());
073        assertTrue(2.3 == mat4B.getM23());
074        assertTrue(3.0 == mat4B.getM30());
075        assertTrue(3.1 == mat4B.getM31());
076        assertTrue(3.2 == mat4B.getM32());
077        assertTrue(3.3 == mat4B.getM33());
078
079        final Matrix4 mat4C = new Matrix4(0.0, 0.1, 0.2, 0.3, 1.0, 1.1, 1.2, 1.3, 2.0, 2.1, 2.2, 2.3, 3.0, 3.1, 3.2,
080                3.3);
081        assertTrue(0.0 == mat4C.getM00());
082        assertTrue(0.1 == mat4C.getM01());
083        assertTrue(0.2 == mat4C.getM02());
084        assertTrue(0.3 == mat4C.getM03());
085        assertTrue(1.0 == mat4C.getM10());
086        assertTrue(1.1 == mat4C.getM11());
087        assertTrue(1.2 == mat4C.getM12());
088        assertTrue(1.3 == mat4C.getM13());
089        assertTrue(2.0 == mat4C.getM20());
090        assertTrue(2.1 == mat4C.getM21());
091        assertTrue(2.2 == mat4C.getM22());
092        assertTrue(2.3 == mat4C.getM23());
093        assertTrue(3.0 == mat4C.getM30());
094        assertTrue(3.1 == mat4C.getM31());
095        assertTrue(3.2 == mat4C.getM32());
096        assertTrue(3.3 == mat4C.getM33());
097
098        mat4C.setIdentity();
099        assertTrue(mat4C.isIdentity());
100
101        for (int x = 0; x < 4; x++) {
102            for (int y = 0; y < 4; y++) {
103                final double value = (10 * x + y) / 10.;
104                mat4C.setValue(x, y, value);
105                assertTrue(value == mat4C.getValue(x, y));
106            }
107        }
108
109        mat4C.setIdentity();
110        mat4C.set(0.0, 0.1, 0.2, 0.3, 2.0, 2.1, 2.2, 2.3, 4.0, 4.1, 4.2, 4.3, 6.0, 6.1, 6.2, 6.3);
111        for (int x = 0; x < 4; x++) {
112            for (int y = 0; y < 4; y++) {
113                assertTrue((20 * x + y) / 10.f == mat4C.getValuef(x, y));
114            }
115        }
116
117        final Matrix4 store = new Matrix4(mat4C);
118        // catch a few expected exceptions
119        try {
120            mat4C.getValue(-1, 0);
121            fail("getValue(-1, 0) should have thrown IllegalArgumentException.");
122        } catch (final IllegalArgumentException e) {
123        }
124        try {
125            mat4C.getValue(0, 4);
126            fail("getValue(0, 4) should have thrown IllegalArgumentException.");
127        } catch (final IllegalArgumentException e) {
128        }
129        try {
130            mat4C.getValue(1, -1);
131            fail("getValue(1, -1) should have thrown IllegalArgumentException.");
132        } catch (final IllegalArgumentException e) {
133        }
134        try {
135            mat4C.getValue(2, 4);
136            fail("getValue(2, 4) should have thrown IllegalArgumentException.");
137        } catch (final IllegalArgumentException e) {
138        }
139        try {
140            mat4C.getValue(3, -1);
141            fail("getValue(3, -1) should have thrown IllegalArgumentException.");
142        } catch (final IllegalArgumentException e) {
143        }
144        try {
145            mat4C.getValue(4, 0);
146            fail("getValue(4, 0) should have thrown IllegalArgumentException.");
147        } catch (final IllegalArgumentException e) {
148        }
149
150        try {
151            mat4C.setValue(-1, 0, 0);
152            fail("setValue(-1, 0, 0) should have thrown IllegalArgumentException.");
153        } catch (final IllegalArgumentException e) {
154        }
155        try {
156            mat4C.setValue(0, -1, 0);
157            fail("setValue(0, -1, 0) should have thrown IllegalArgumentException.");
158        } catch (final IllegalArgumentException e) {
159        }
160        try {
161            mat4C.setValue(1, 4, 0);
162            fail("setValue(1, 4, 0) should have thrown IllegalArgumentException.");
163        } catch (final IllegalArgumentException e) {
164        }
165        try {
166            mat4C.setValue(2, -1, 0);
167            fail("setValue(2, -1, 0) should have thrown IllegalArgumentException.");
168        } catch (final IllegalArgumentException e) {
169        }
170        try {
171            mat4C.setValue(3, 4, 0);
172            fail("setValue(3, 4, 0) should have thrown IllegalArgumentException.");
173        } catch (final IllegalArgumentException e) {
174        }
175        try {
176            mat4C.setValue(4, 0, 0);
177            fail("setValue(4, 0, 0) should have thrown IllegalArgumentException.");
178        } catch (final IllegalArgumentException e) {
179        }
180        // above exceptions shouldn't have altered mat4C
181        assertEquals(store, mat4C);
182    }
183
184    @Test
185    public void testColumns() {
186        final Matrix4 mat4A = new Matrix4();
187        mat4A.setColumn(0, new Vector4(0, 4, 8, 12));
188        mat4A.setColumn(1, new Vector4(1, 5, 9, 13));
189        mat4A.setColumn(2, new Vector4(2, 6, 10, 14));
190        mat4A.setColumn(3, new Vector4(3, 7, 11, 15));
191        assertEquals(new Vector4(0, 4, 8, 12), mat4A.getColumn(0, new Vector4()));
192        assertEquals(new Vector4(1, 5, 9, 13), mat4A.getColumn(1, null));
193        assertEquals(new Vector4(2, 6, 10, 14), mat4A.getColumn(2, null));
194        assertEquals(new Vector4(3, 7, 11, 15), mat4A.getColumn(3, null));
195        try {
196            mat4A.getColumn(-1, null);
197            fail("getColumn(-1, null) should have thrown IllegalArgumentException.");
198        } catch (final IllegalArgumentException e) {
199        }
200        try {
201            mat4A.getColumn(4, null);
202            fail("getColumn(4, null) should have thrown IllegalArgumentException.");
203        } catch (final IllegalArgumentException e) {
204        }
205        try {
206            mat4A.setColumn(-1, new Vector4());
207            fail("setColumn(-1, double[]) should have thrown IllegalArgumentException.");
208        } catch (final IllegalArgumentException e) {
209        }
210        try {
211            mat4A.setColumn(4, new Vector4());
212            fail("setColumn(4, double[]) should have thrown IllegalArgumentException.");
213        } catch (final IllegalArgumentException e) {
214        }
215    }
216
217    @Test
218    public void testRows() {
219        final Matrix4 mat4A = new Matrix4();
220        mat4A.setRow(0, new Vector4(0, 1, 2, 3));
221        mat4A.setRow(1, new Vector4(4, 5, 6, 7));
222        mat4A.setRow(2, new Vector4(8, 9, 10, 11));
223        mat4A.setRow(3, new Vector4(12, 13, 14, 15));
224        assertEquals(new Vector4(0, 1, 2, 3), mat4A.getRow(0, new Vector4()));
225        assertEquals(new Vector4(4, 5, 6, 7), mat4A.getRow(1, null));
226        assertEquals(new Vector4(8, 9, 10, 11), mat4A.getRow(2, null));
227        assertEquals(new Vector4(12, 13, 14, 15), mat4A.getRow(3, null));
228        try {
229            mat4A.getRow(-1, null);
230            fail("getRow(-1, null) should have thrown IllegalArgumentException.");
231        } catch (final IllegalArgumentException e) {
232        }
233        try {
234            mat4A.getRow(4, null);
235            fail("getRow(4, null) should have thrown IllegalArgumentException.");
236        } catch (final IllegalArgumentException e) {
237        }
238        try {
239            mat4A.setRow(-1, new Vector4());
240            fail("setRow(-1, double[]) should have thrown IllegalArgumentException.");
241        } catch (final IllegalArgumentException e) {
242        }
243        try {
244            mat4A.setRow(4, new Vector4());
245            fail("setRow(4, double[]) should have thrown IllegalArgumentException.");
246        } catch (final IllegalArgumentException e) {
247        }
248    }
249
250    @Test
251    public void testSetRotation() {
252        final Matrix4 mat4A = new Matrix4(0.0, 0.1, 0.2, 0.3, 1.0, 1.1, 1.2, 1.3, 2.0, 2.1, 2.2, 2.3, 3.0, 3.1, 3.2,
253                3.3);
254        mat4A.set(Matrix3.IDENTITY);
255        assertTrue(1.0 == mat4A.getM00());
256        assertTrue(0.0 == mat4A.getM01());
257        assertTrue(0.0 == mat4A.getM02());
258        assertTrue(0.3 == mat4A.getM03());
259        assertTrue(0.0 == mat4A.getM10());
260        assertTrue(1.0 == mat4A.getM11());
261        assertTrue(0.0 == mat4A.getM12());
262        assertTrue(1.3 == mat4A.getM13());
263        assertTrue(0.0 == mat4A.getM20());
264        assertTrue(0.0 == mat4A.getM21());
265        assertTrue(1.0 == mat4A.getM22());
266        assertTrue(2.3 == mat4A.getM23());
267        assertTrue(3.0 == mat4A.getM30());
268        assertTrue(3.1 == mat4A.getM31());
269        assertTrue(3.2 == mat4A.getM32());
270        assertTrue(3.3 == mat4A.getM33());
271
272        mat4A.setIdentity();
273        // rotate identity 90 degrees around Y
274        final double a = MathUtils.HALF_PI;
275        final Quaternion quaternion = new Quaternion();
276        quaternion.fromAngleAxis(a, Vector3.UNIT_Y);
277        mat4A.set(quaternion);
278
279        assertEquals(new Matrix4( //
280                Math.cos(a), 0, Math.sin(a), 0, //
281                0, 1, 0, 0, //
282                -Math.sin(a), 0, Math.cos(a), 0, //
283                0, 0, 0, 1), mat4A);
284    }
285
286    @Test
287    public void testFromBuffer() {
288        final FloatBuffer fb = FloatBuffer.allocate(16);
289        fb.put(new float[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 });
290        fb.flip();
291        // row major
292        final Matrix4 mat4A = new Matrix4().fromFloatBuffer(fb);
293        assertTrue(0 == mat4A.getM00());
294        assertTrue(1 == mat4A.getM01());
295        assertTrue(2 == mat4A.getM02());
296        assertTrue(3 == mat4A.getM03());
297        assertTrue(4 == mat4A.getM10());
298        assertTrue(5 == mat4A.getM11());
299        assertTrue(6 == mat4A.getM12());
300        assertTrue(7 == mat4A.getM13());
301        assertTrue(8 == mat4A.getM20());
302        assertTrue(9 == mat4A.getM21());
303        assertTrue(10 == mat4A.getM22());
304        assertTrue(11 == mat4A.getM23());
305        assertTrue(12 == mat4A.getM30());
306        assertTrue(13 == mat4A.getM31());
307        assertTrue(14 == mat4A.getM32());
308        assertTrue(15 == mat4A.getM33());
309
310        // column major
311        fb.rewind();
312        mat4A.setIdentity();
313        mat4A.fromFloatBuffer(fb, false);
314        assertTrue(0 == mat4A.getM00());
315        assertTrue(4 == mat4A.getM01());
316        assertTrue(8 == mat4A.getM02());
317        assertTrue(12 == mat4A.getM03());
318        assertTrue(1 == mat4A.getM10());
319        assertTrue(5 == mat4A.getM11());
320        assertTrue(9 == mat4A.getM12());
321        assertTrue(13 == mat4A.getM13());
322        assertTrue(2 == mat4A.getM20());
323        assertTrue(6 == mat4A.getM21());
324        assertTrue(10 == mat4A.getM22());
325        assertTrue(14 == mat4A.getM23());
326        assertTrue(3 == mat4A.getM30());
327        assertTrue(7 == mat4A.getM31());
328        assertTrue(11 == mat4A.getM32());
329        assertTrue(15 == mat4A.getM33());
330
331        final DoubleBuffer db = DoubleBuffer.allocate(16);
332        db.put(new double[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 });
333        db.flip();
334        // row major
335        mat4A.setIdentity();
336        mat4A.fromDoubleBuffer(db);
337        assertTrue(0 == mat4A.getM00());
338        assertTrue(1 == mat4A.getM01());
339        assertTrue(2 == mat4A.getM02());
340        assertTrue(3 == mat4A.getM03());
341        assertTrue(4 == mat4A.getM10());
342        assertTrue(5 == mat4A.getM11());
343        assertTrue(6 == mat4A.getM12());
344        assertTrue(7 == mat4A.getM13());
345        assertTrue(8 == mat4A.getM20());
346        assertTrue(9 == mat4A.getM21());
347        assertTrue(10 == mat4A.getM22());
348        assertTrue(11 == mat4A.getM23());
349        assertTrue(12 == mat4A.getM30());
350        assertTrue(13 == mat4A.getM31());
351        assertTrue(14 == mat4A.getM32());
352        assertTrue(15 == mat4A.getM33());
353
354        // column major
355        db.rewind();
356        mat4A.setIdentity();
357        mat4A.fromDoubleBuffer(db, false);
358        assertTrue(0 == mat4A.getM00());
359        assertTrue(4 == mat4A.getM01());
360        assertTrue(8 == mat4A.getM02());
361        assertTrue(12 == mat4A.getM03());
362        assertTrue(1 == mat4A.getM10());
363        assertTrue(5 == mat4A.getM11());
364        assertTrue(9 == mat4A.getM12());
365        assertTrue(13 == mat4A.getM13());
366        assertTrue(2 == mat4A.getM20());
367        assertTrue(6 == mat4A.getM21());
368        assertTrue(10 == mat4A.getM22());
369        assertTrue(14 == mat4A.getM23());
370        assertTrue(3 == mat4A.getM30());
371        assertTrue(7 == mat4A.getM31());
372        assertTrue(11 == mat4A.getM32());
373        assertTrue(15 == mat4A.getM33());
374    }
375
376    @Test
377    public void testToBuffer() {
378        final double[] values = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
379        final double[] colmajor = { 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 };
380
381        final Matrix4 mat4A = new Matrix4().fromArray(values);
382
383        // row major
384        final FloatBuffer fb = mat4A.toFloatBuffer(FloatBuffer.allocate(16));
385        fb.flip();
386        for (int i = 0; i < 16; i++) {
387            assertTrue(values[i] == fb.get());
388        }
389
390        // column major
391        fb.rewind();
392        mat4A.toFloatBuffer(fb, false);
393        fb.flip();
394        for (int i = 0; i < 16; i++) {
395            assertTrue(colmajor[i] == fb.get());
396        }
397
398        // row major
399        final DoubleBuffer db = mat4A.toDoubleBuffer(DoubleBuffer.allocate(16));
400        db.flip();
401        for (int i = 0; i < 16; i++) {
402            assertTrue(values[i] == db.get());
403        }
404
405        // column major
406        db.rewind();
407        mat4A.toDoubleBuffer(db, false);
408        db.flip();
409        for (int i = 0; i < 16; i++) {
410            assertTrue(colmajor[i] == db.get());
411        }
412    }
413
414    @Test
415    public void testFromArray() {
416        final double[] values = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
417        final Matrix4 mat4A = new Matrix4();
418
419        // row major
420        mat4A.setIdentity();
421        mat4A.fromArray(values);
422        assertTrue(0 == mat4A.getM00());
423        assertTrue(1 == mat4A.getM01());
424        assertTrue(2 == mat4A.getM02());
425        assertTrue(3 == mat4A.getM03());
426        assertTrue(4 == mat4A.getM10());
427        assertTrue(5 == mat4A.getM11());
428        assertTrue(6 == mat4A.getM12());
429        assertTrue(7 == mat4A.getM13());
430        assertTrue(8 == mat4A.getM20());
431        assertTrue(9 == mat4A.getM21());
432        assertTrue(10 == mat4A.getM22());
433        assertTrue(11 == mat4A.getM23());
434        assertTrue(12 == mat4A.getM30());
435        assertTrue(13 == mat4A.getM31());
436        assertTrue(14 == mat4A.getM32());
437        assertTrue(15 == mat4A.getM33());
438
439        // column major
440        mat4A.setIdentity();
441        mat4A.fromArray(values, false);
442        assertTrue(0 == mat4A.getM00());
443        assertTrue(4 == mat4A.getM01());
444        assertTrue(8 == mat4A.getM02());
445        assertTrue(12 == mat4A.getM03());
446        assertTrue(1 == mat4A.getM10());
447        assertTrue(5 == mat4A.getM11());
448        assertTrue(9 == mat4A.getM12());
449        assertTrue(13 == mat4A.getM13());
450        assertTrue(2 == mat4A.getM20());
451        assertTrue(6 == mat4A.getM21());
452        assertTrue(10 == mat4A.getM22());
453        assertTrue(14 == mat4A.getM23());
454        assertTrue(3 == mat4A.getM30());
455        assertTrue(7 == mat4A.getM31());
456        assertTrue(11 == mat4A.getM32());
457        assertTrue(15 == mat4A.getM33());
458    }
459
460    @Test
461    public void testToArray() {
462        final double[] values = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
463        final Matrix4 mat4A = new Matrix4().fromArray(values);
464
465        // row major
466        final double[] dbls1 = mat4A.toArray(null);
467        for (int i = 0; i < 16; i++) {
468            assertTrue(values[i] == dbls1[i]);
469        }
470
471        // column major
472        final double[] colmajor = { 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 };
473        mat4A.toArray(dbls1, false);
474        for (int i = 0; i < 16; i++) {
475            assertTrue(colmajor[i] == dbls1[i]);
476        }
477    }
478
479    @Test(expected = IllegalArgumentException.class)
480    public void testBadArray() {
481        final Matrix4 mat4A = new Matrix4();
482        mat4A.toArray(new double[9]);
483    }
484
485    @Test
486    public void testAngleAxis() {
487        final Matrix4 mat4A = new Matrix4();
488        // rotate identity 90 degrees around X
489        final double angle = MathUtils.HALF_PI;
490        mat4A.fromAngleAxis(MathUtils.HALF_PI, Vector3.UNIT_X);
491        assertEquals(new Matrix4( //
492                1, 0, 0, 0, //
493                0, Math.cos(angle), -Math.sin(angle), 0, //
494                0, Math.sin(angle), Math.cos(angle), 0, //
495                0, 0, 0, 1), mat4A);
496    }
497
498    @Test
499    public void testRotations() {
500        final Vector4 rotated = new Vector4();
501        final Vector4 expected = new Vector4();
502        final Matrix4 worker = new Matrix4();
503
504        // test axis rotation methods against general purpose
505        // X AXIS
506        expected.set(1, 1, 1, 1);
507        rotated.set(1, 1, 1, 1);
508        worker.setIdentity().applyRotationX(MathUtils.QUARTER_PI).applyPost(expected, expected);
509        worker.setIdentity().applyRotation(MathUtils.QUARTER_PI, 1, 0, 0).applyPost(rotated, rotated);
510        assertTrue(rotated.distance(expected) <= MathUtils.EPSILON);
511
512        // Y AXIS
513        expected.set(1, 1, 1, 1);
514        rotated.set(1, 1, 1, 1);
515        worker.setIdentity().applyRotationY(MathUtils.QUARTER_PI).applyPost(expected, expected);
516        worker.setIdentity().applyRotation(MathUtils.QUARTER_PI, 0, 1, 0).applyPost(rotated, rotated);
517        assertTrue(rotated.distance(expected) <= MathUtils.EPSILON);
518
519        // Z AXIS
520        expected.set(1, 1, 1, 1);
521        rotated.set(1, 1, 1, 1);
522        worker.setIdentity().applyRotationZ(MathUtils.QUARTER_PI).applyPost(expected, expected);
523        worker.setIdentity().applyRotation(MathUtils.QUARTER_PI, 0, 0, 1).applyPost(rotated, rotated);
524        assertTrue(rotated.distance(expected) <= MathUtils.EPSILON);
525    }
526
527    @Test
528    public void testTranslation() {
529        final Matrix4 src = new Matrix4();
530        src.applyRotation(MathUtils.QUARTER_PI, 1, 0, 0);
531
532        final Matrix4 trans = new Matrix4();
533        trans.setColumn(3, new Vector4(1, 2, 3, 1));
534        final Matrix4 transThenRotate = trans.multiply(src, null);
535        final Matrix4 rotateThenTrans = src.multiply(trans, null);
536
537        final Matrix4 pre1 = new Matrix4(src).applyTranslationPre(1, 2, 3);
538        final Matrix4 post1 = new Matrix4(src).applyTranslationPost(1, 2, 3);
539
540        assertEquals(transThenRotate, pre1);
541        assertEquals(rotateThenTrans, post1);
542    }
543
544    @Test
545    public void testMultiplyDiagonal() {
546        final Matrix4 mat4A = new Matrix4();
547        Matrix4 result = mat4A.multiplyDiagonalPost(new Vector4(2, 4, 6, 8), null);
548        assertEquals(new Matrix4( //
549                2, 0, 0, 0, //
550                0, 4, 0, 0, //
551                0, 0, 6, 0, //
552                0, 0, 0, 8), result);
553        mat4A.multiplyDiagonalPre(new Vector4(-2, -4, -6, -8), result);
554        assertEquals(new Matrix4( //
555                -2, 0, 0, 0, //
556                0, -4, 0, 0, //
557                0, 0, -6, 0, //
558                0, 0, 0, -8), result);
559
560        final double a = MathUtils.HALF_PI;
561        mat4A.applyRotationY(a);
562        mat4A.multiplyDiagonalPost(new Vector4(2, 4, 6, 8), result);
563        assertEquals(new Matrix4( //
564                2 * Math.cos(a), 4 * 0, 6 * Math.sin(a), 8 * 0, //
565                2 * 0, 4 * 1, 6 * 0, 8 * 0, //
566                2 * -Math.sin(a), 4 * 0, 6 * Math.cos(a), 8 * 0, //
567                2 * 0, 4 * 0, 6 * 0, 8 * 1), result);
568        result = mat4A.multiplyDiagonalPre(new Vector4(-2, -4, -6, -8), null);
569        assertEquals(new Matrix4( //
570                -2 * Math.cos(a), -2 * 0, -2 * Math.sin(a), -2 * 0, //
571                -4 * 0, -4 * 1, -4 * 0, -4 * 0, //
572                -6 * -Math.sin(a), -6 * 0, -6 * Math.cos(a), -6 * 0, //
573                -8 * 0, -8 * 0, -8 * 0, -8 * 1), result);
574    }
575
576    @Test
577    public void testMultiply() {
578        final Matrix4 mat4A = new Matrix4( //
579                0.01, 0.1, 0.2, 0.3, //
580                1.0, 1.1, 1.2, 1.3, //
581                2.0, 2.1, 2.2, 2.3, //
582                3.0, 3.1, 3.2, 3.3);
583        mat4A.multiplyLocal(2);
584        assertEquals(new Matrix4( //
585                0.02, 0.2, 0.4, 0.6, //
586                2.0, 2.2, 2.4, 2.6, //
587                4.0, 4.2, 4.4, 4.6, //
588                6.0, 6.2, 6.4, 6.6), mat4A);
589
590        final Matrix4 mat4B = new Matrix4( //
591                0.5, 1, 2, 3, //
592                4, 5, 6, 7, //
593                8, 9, 10, 11, //
594                12, 13, 14, 15);
595        final Matrix4 result = mat4A.multiply(mat4B, null);
596        assertTrue(0.02 * 0.5 + 0.2 * 4 + 0.4 * 8 + 0.6 * 12 == result.getM00());
597        assertTrue(0.02 * 1 + 0.2 * 5 + 0.4 * 9 + 0.6 * 13 == result.getM01());
598        assertTrue(0.02 * 2 + 0.2 * 6 + 0.4 * 10 + 0.6 * 14 == result.getM02());
599        assertTrue(0.02 * 3 + 0.2 * 7 + 0.4 * 11 + 0.6 * 15 == result.getM03());
600        assertTrue(2.0 * 0.5 + 2.2 * 4 + 2.4 * 8 + 2.6 * 12 == result.getM10());
601        assertTrue(2.0 * 1 + 2.2 * 5 + 2.4 * 9 + 2.6 * 13 == result.getM11());
602        assertTrue(2.0 * 2 + 2.2 * 6 + 2.4 * 10 + 2.6 * 14 == result.getM12());
603        assertTrue(2.0 * 3 + 2.2 * 7 + 2.4 * 11 + 2.6 * 15 == result.getM13());
604        assertTrue(4.0 * 0.5 + 4.2 * 4 + 4.4 * 8 + 4.6 * 12 == result.getM20());
605        assertTrue(4.0 * 1 + 4.2 * 5 + 4.4 * 9 + 4.6 * 13 == result.getM21());
606        assertTrue(4.0 * 2 + 4.2 * 6 + 4.4 * 10 + 4.6 * 14 == result.getM22());
607        assertTrue(4.0 * 3 + 4.2 * 7 + 4.4 * 11 + 4.6 * 15 == result.getM23());
608        assertTrue(6.0 * 0.5 + 6.2 * 4 + 6.4 * 8 + 6.6 * 12 == result.getM30());
609        assertTrue(6.0 * 1 + 6.2 * 5 + 6.4 * 9 + 6.6 * 13 == result.getM31());
610        assertTrue(6.0 * 2 + 6.2 * 6 + 6.4 * 10 + 6.6 * 14 == result.getM32());
611        assertTrue(6.0 * 3 + 6.2 * 7 + 6.4 * 11 + 6.6 * 15 == result.getM33());
612        mat4A.multiplyLocal(mat4B);
613        assertTrue(0.02 * 0.5 + 0.2 * 4 + 0.4 * 8 + 0.6 * 12 == mat4A.getM00());
614        assertTrue(0.02 * 1 + 0.2 * 5 + 0.4 * 9 + 0.6 * 13 == mat4A.getM01());
615        assertTrue(0.02 * 2 + 0.2 * 6 + 0.4 * 10 + 0.6 * 14 == mat4A.getM02());
616        assertTrue(0.02 * 3 + 0.2 * 7 + 0.4 * 11 + 0.6 * 15 == mat4A.getM03());
617        assertTrue(2.0 * 0.5 + 2.2 * 4 + 2.4 * 8 + 2.6 * 12 == mat4A.getM10());
618        assertTrue(2.0 * 1 + 2.2 * 5 + 2.4 * 9 + 2.6 * 13 == mat4A.getM11());
619        assertTrue(2.0 * 2 + 2.2 * 6 + 2.4 * 10 + 2.6 * 14 == mat4A.getM12());
620        assertTrue(2.0 * 3 + 2.2 * 7 + 2.4 * 11 + 2.6 * 15 == mat4A.getM13());
621        assertTrue(4.0 * 0.5 + 4.2 * 4 + 4.4 * 8 + 4.6 * 12 == mat4A.getM20());
622        assertTrue(4.0 * 1 + 4.2 * 5 + 4.4 * 9 + 4.6 * 13 == mat4A.getM21());
623        assertTrue(4.0 * 2 + 4.2 * 6 + 4.4 * 10 + 4.6 * 14 == mat4A.getM22());
624        assertTrue(4.0 * 3 + 4.2 * 7 + 4.4 * 11 + 4.6 * 15 == mat4A.getM23());
625        assertTrue(6.0 * 0.5 + 6.2 * 4 + 6.4 * 8 + 6.6 * 12 == mat4A.getM30());
626        assertTrue(6.0 * 1 + 6.2 * 5 + 6.4 * 9 + 6.6 * 13 == mat4A.getM31());
627        assertTrue(6.0 * 2 + 6.2 * 6 + 6.4 * 10 + 6.6 * 14 == mat4A.getM32());
628        assertTrue(6.0 * 3 + 6.2 * 7 + 6.4 * 11 + 6.6 * 15 == mat4A.getM33());
629    }
630
631    @Test
632    public void testAddSubtract() {
633        final Matrix4 mat4A = new Matrix4( //
634                0.0, 0.1, 0.2, 0.3, //
635                1.0, 1.1, 1.2, 1.3, //
636                2.0, 2.1, 2.2, 2.3, //
637                3.0, 3.1, 3.2, 3.3);
638
639        final Matrix4 result1 = mat4A.add(new Matrix4(//
640                1, 2, 3, 4,//
641                5, 6, 7, 8,//
642                9, 10, 11, 12,//
643                13, 14, 15, 16), null);
644        assertEquals(new Matrix4( //
645                1.0, 2.1, 3.2, 4.3, //
646                6.0, 7.1, 8.2, 9.3, //
647                11.0, 12.1, 13.2, 14.3, //
648                16.0, 17.1, 18.2, 19.3), result1);
649
650        final Matrix4 result2 = result1.subtract(new Matrix4(//
651                1, 2, 3, 4,//
652                5, 6, 7, 8,//
653                9, 10, 11, 12,//
654                13, 14, 15, 16), null);
655        assertEquals(mat4A, result2);
656        result2.addLocal(Matrix4.IDENTITY);
657        assertEquals(new Matrix4( //
658                1.0, 0.1, 0.2, 0.3, //
659                1.0, 2.1, 1.2, 1.3, //
660                2.0, 2.1, 3.2, 2.3, //
661                3.0, 3.1, 3.2, 4.3), result2);
662
663        result1.subtractLocal(Matrix4.IDENTITY);
664        assertEquals(new Matrix4( //
665                0.0, 2.1, 3.2, 4.3, //
666                6.0, 6.1, 8.2, 9.3, //
667                11.0, 12.1, 12.2, 14.3, //
668                16.0, 17.1, 18.2, 18.3), result1);
669    }
670
671    @Test
672    public void testScale() {
673        final Matrix4 mat4A = new Matrix4( //
674                0.01, 0.1, 0.2, 0.3, //
675                1.0, 1.1, 1.2, 1.3, //
676                2.0, 2.1, 2.2, 2.3, //
677                3.0, 3.1, 3.2, 3.3);
678        final Matrix4 result = mat4A.scale(new Vector4(-1, 2, 3, 4), null);
679        assertEquals(new Matrix4( //
680                0.01 * -1, 0.1 * 2, 0.2 * 3, 0.3 * 4, //
681                1.0 * -1, 1.1 * 2, 1.2 * 3, 1.3 * 4, //
682                2.0 * -1, 2.1 * 2, 2.2 * 3, 2.3 * 4, //
683                3.0 * -1, 3.1 * 2, 3.2 * 3, 3.3 * 4), result);
684
685        result.scaleLocal(new Vector4(-1, 0.5, 1 / 3., .25));
686        assertEquals(mat4A, result);
687    }
688
689    @Test
690    public void testTranspose() {
691        final Matrix4 mat4A = new Matrix4( //
692                0.01, 0.1, 0.2, 0.3, //
693                1.0, 1.1, 1.2, 1.3, //
694                2.0, 2.1, 2.2, 2.3, //
695                3.0, 3.1, 3.2, 3.3);
696        final Matrix4 result = mat4A.transpose(null);
697        assertEquals(new Matrix4( //
698                0.01, 1.0, 2.0, 3.0, //
699                0.1, 1.1, 2.1, 3.1, //
700                0.2, 1.2, 2.2, 3.2, //
701                0.3, 1.3, 2.3, 3.3), result);
702        assertEquals(new Matrix4( //
703                0.01, 0.1, 0.2, 0.3, //
704                1.0, 1.1, 1.2, 1.3, //
705                2.0, 2.1, 2.2, 2.3, //
706                3.0, 3.1, 3.2, 3.3), result.transposeLocal());
707        // coverage
708        final Matrix4 result2 = result.transposeLocal().transpose(new Matrix4());
709        assertEquals(mat4A, result2);
710    }
711
712    @Test
713    public void testInvert() {
714        final Matrix4 mat4A = new Matrix4().applyRotationX(MathUtils.QUARTER_PI).applyTranslationPost(1, 2, 3);
715        final Matrix4 inverted = mat4A.invert(null);
716        assertEquals(Matrix4.IDENTITY, mat4A.multiply(inverted, null));
717        assertEquals(mat4A, inverted.invertLocal());
718    }
719
720    @Test(expected = ArithmeticException.class)
721    public void testBadInvert() {
722        final Matrix4 mat4A = new Matrix4(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
723        mat4A.invertLocal();
724    }
725
726    @Test
727    public void testAdjugate() {
728        final double //
729        a = -3, b = 2, c = -5, d = 2, //
730        e = -1, f = 0, g = -2, h = 3, //
731        i = 1, j = -3, k = -4, l = 0, //
732        m = 4, n = 2, o = 3, p = 1;
733
734        final Matrix4 mat4A = new Matrix4( //
735                a, b, c, d,//
736                e, f, g, h, //
737                i, j, k, l, //
738                m, n, o, p);
739
740        // prepare sections
741        final Matrix3 m00 = new Matrix3(f, g, h, j, k, l, n, o, p);
742        final Matrix3 m01 = new Matrix3(b, c, d, j, k, l, n, o, p);
743        final Matrix3 m02 = new Matrix3(b, c, d, f, g, h, n, o, p);
744        final Matrix3 m03 = new Matrix3(b, c, d, f, g, h, j, k, l);
745        final Matrix3 m10 = new Matrix3(e, g, h, i, k, l, m, o, p);
746        final Matrix3 m11 = new Matrix3(a, c, d, i, k, l, m, o, p);
747        final Matrix3 m12 = new Matrix3(a, c, d, e, g, h, m, o, p);
748        final Matrix3 m13 = new Matrix3(a, c, d, e, g, h, i, k, l);
749        final Matrix3 m20 = new Matrix3(e, f, h, i, j, l, m, n, p);
750        final Matrix3 m21 = new Matrix3(a, b, d, i, j, l, m, n, p);
751        final Matrix3 m22 = new Matrix3(a, b, d, e, f, h, m, n, p);
752        final Matrix3 m23 = new Matrix3(a, b, d, e, f, h, i, j, l);
753        final Matrix3 m30 = new Matrix3(e, f, g, i, j, k, m, n, o);
754        final Matrix3 m31 = new Matrix3(a, b, c, i, j, k, m, n, o);
755        final Matrix3 m32 = new Matrix3(a, b, c, e, f, g, m, n, o);
756        final Matrix3 m33 = new Matrix3(a, b, c, e, f, g, i, j, k);
757
758        // generate adjugate
759        final Matrix4 testValue = new Matrix4( //
760                m00.determinant(), -m01.determinant(), m02.determinant(), -m03.determinant(), //
761                -m10.determinant(), m11.determinant(), -m12.determinant(), m13.determinant(), //
762                m20.determinant(), -m21.determinant(), m22.determinant(), -m23.determinant(), //
763                -m30.determinant(), m31.determinant(), -m32.determinant(), m33.determinant());
764
765        assertEquals(testValue, mat4A.adjugate(null));
766        assertEquals(testValue, mat4A.adjugateLocal());
767    }
768
769    @Test
770    public void testDeterminant() {
771        {
772            final double //
773            a = -3, b = 2, c = -5, d = 2, //
774            e = -1, f = 0, g = -2, h = 3, //
775            i = 1, j = -3, k = -4, l = 0, //
776            m = 4, n = 2, o = 3, p = 1;
777
778            final Matrix4 mat4A = new Matrix4( //
779                    a, b, c, d,//
780                    e, f, g, h, //
781                    i, j, k, l, //
782                    m, n, o, p);
783
784            // prepare sections
785            final double m00 = new Matrix3(f, g, h, j, k, l, n, o, p).determinant();
786            final double m01 = new Matrix3(e, g, h, i, k, l, m, o, p).determinant();
787            final double m02 = new Matrix3(e, f, h, i, j, l, m, n, p).determinant();
788            final double m03 = new Matrix3(e, f, g, i, j, k, m, n, o).determinant();
789            final double determinant = a * m00 - b * m01 + c * m02 - d * m03;
790
791            assertTrue(Math.abs(determinant - mat4A.determinant()) <= MathUtils.EPSILON);
792        }
793
794        {
795            final double //
796            a = -1.2, b = 4, c = -2.5, d = 1.7, //
797            e = 2, f = -3, g = -2, h = 3.2, //
798            i = 3.1, j = -1, k = 2, l = 1.15, //
799            m = 1, n = 2, o = 3.14, p = 1.4;
800
801            final Matrix4 mat4A = new Matrix4( //
802                    a, b, c, d,//
803                    e, f, g, h, //
804                    i, j, k, l, //
805                    m, n, o, p);
806
807            // prepare sections
808            final double m00 = new Matrix3(f, g, h, j, k, l, n, o, p).determinant();
809            final double m01 = new Matrix3(e, g, h, i, k, l, m, o, p).determinant();
810            final double m02 = new Matrix3(e, f, h, i, j, l, m, n, p).determinant();
811            final double m03 = new Matrix3(e, f, g, i, j, k, m, n, o).determinant();
812            final double determinant = a * m00 - b * m01 + c * m02 - d * m03;
813
814            assertTrue(Math.abs(determinant - mat4A.determinant()) <= MathUtils.EPSILON);
815        }
816    }
817
818    @Test
819    public void testClone() {
820        final Matrix4 mat1 = new Matrix4();
821        final Matrix4 mat2 = mat1.clone();
822        assertEquals(mat1, mat2);
823        assertNotSame(mat1, mat2);
824    }
825
826    @Test
827    public void testValid() {
828        final Matrix4 mat4 = new Matrix4();
829        assertTrue(Matrix4.isValid(mat4));
830        for (int i = 0; i < 16; i++) {
831            mat4.setIdentity();
832            mat4.setValue(i / 4, i % 4, Double.NaN);
833            assertFalse(Matrix4.isValid(mat4));
834            mat4.setIdentity();
835            mat4.setValue(i / 4, i % 4, Double.POSITIVE_INFINITY);
836            assertFalse(Matrix4.isValid(mat4));
837        }
838
839        mat4.setIdentity();
840        assertTrue(Matrix4.isValid(mat4));
841
842        assertFalse(Matrix4.isValid(null));
843
844        // couple of equals validity tests
845        assertEquals(mat4, mat4);
846        assertTrue(mat4.strictEquals(mat4));
847        assertFalse(mat4.equals(null));
848        assertFalse(mat4.strictEquals(null));
849        assertFalse(mat4.equals(new Vector2()));
850        assertFalse(mat4.strictEquals(new Vector2()));
851
852        // throw in a couple pool accesses for coverage
853        final Matrix4 matTemp = Matrix4.fetchTempInstance();
854        matTemp.set(mat4);
855        assertEquals(mat4, matTemp);
856        assertNotSame(mat4, matTemp);
857        Matrix4.releaseTempInstance(matTemp);
858
859        // cover more of equals
860        mat4.set(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
861        final Matrix4 comp = new Matrix4(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1);
862        assertFalse(mat4.equals(comp));
863        assertFalse(mat4.strictEquals(comp));
864        for (int i = 0; i < 15; i++) {
865            comp.setValue(i / 4, i % 4, i);
866            assertFalse(mat4.equals(comp));
867            assertFalse(mat4.strictEquals(comp));
868        }
869    }
870
871    @Test
872    public void testSimpleHash() {
873        // Just a simple sanity check.
874        final Matrix4 mat1 = new Matrix4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
875        final Matrix4 mat2 = new Matrix4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
876        final Matrix4 mat3 = new Matrix4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0);
877
878        assertTrue(mat1.hashCode() == mat2.hashCode());
879        assertTrue(mat1.hashCode() != mat3.hashCode());
880    }
881
882    @Test
883    public void testOrthonormal() {
884        final Matrix4 mat4 = new Matrix4();
885        assertTrue(mat4.isOrthonormal());
886        // just rotation
887        mat4.set(new Matrix3().applyRotationX(MathUtils.QUARTER_PI));
888        assertTrue(mat4.isOrthonormal());
889        // non-uniform scale
890        mat4.set(new Matrix3().scaleLocal(new Vector3(1, 2, 3)).applyRotationX(MathUtils.QUARTER_PI));
891        assertFalse(mat4.isOrthonormal());
892        // uniform scale
893        mat4.set(new Matrix3().scaleLocal(new Vector3(2, 2, 2)).applyRotationX(MathUtils.QUARTER_PI));
894        assertFalse(mat4.isOrthonormal());
895        // uniform scale 1
896        mat4.set(new Matrix3().scaleLocal(new Vector3(1, 1, 1)).applyRotationX(MathUtils.QUARTER_PI));
897        assertTrue(mat4.isOrthonormal());
898    }
899
900    @Test
901    public void testApplyVector4() {
902        final Matrix4 mat4 = new Matrix4().applyRotationX(MathUtils.HALF_PI);
903        final Vector4 vec4 = new Vector4(0, 1, 0, 1);
904        final Vector4 result = mat4.applyPost(vec4, null);
905        assertTrue(Math.abs(new Vector4(0, 0, 1, 1).distance(result)) <= MathUtils.EPSILON);
906        vec4.set(0, 1, 1, 1);
907        mat4.applyPost(vec4, result);
908        assertTrue(Math.abs(new Vector4(0, -1, 1, 1).distance(result)) <= MathUtils.EPSILON);
909
910        vec4.set(0, 1, 1, 1);
911        mat4.applyPre(vec4, result);
912        assertTrue(Math.abs(new Vector4(0, 1, -1, 1).distance(result)) <= MathUtils.EPSILON);
913
914        vec4.set(1, 1, 1, 1);
915        assertTrue(Math.abs(new Vector4(1, 1, -1, 1).distance(mat4.applyPre(vec4, null))) <= MathUtils.EPSILON);
916    }
917
918    @Test
919    public void testApplyVector3() {
920        final Matrix4 mat4 = new Matrix4().applyRotationX(MathUtils.HALF_PI).applyTranslationPre(1, 2, 3);
921        final Vector3 vec3 = new Vector3(0, 1, 0);
922        final Vector3 result = mat4.applyPostPoint(vec3, null);
923        assertTrue(Math.abs(new Vector3(1, 2, 4).distance(result)) <= MathUtils.EPSILON);
924        vec3.set(0, 1, 1);
925        mat4.applyPostPoint(vec3, result);
926        assertTrue(Math.abs(new Vector3(1, 1, 4).distance(result)) <= MathUtils.EPSILON);
927
928        vec3.set(0, 1, 1);
929        mat4.applyPostVector(vec3, result);
930        assertTrue(Math.abs(new Vector3(0, -1, 1).distance(result)) <= MathUtils.EPSILON);
931
932        vec3.set(1, 1, 1);
933        assertTrue(Math.abs(new Vector3(1, -1, 1).distance(mat4.applyPostVector(vec3, null))) <= MathUtils.EPSILON);
934    }
935}