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 TestMatrix3 {
021
022    @Test
023    public void testGetSet() {
024        final Matrix3 mat3A = new Matrix3();
025        assertEquals(Matrix3.IDENTITY, mat3A);
026
027        mat3A.setM00(0.0);
028        mat3A.setM01(0.1);
029        mat3A.setM02(0.2);
030        mat3A.setM10(1.0);
031        mat3A.setM11(1.1);
032        mat3A.setM12(1.2);
033        mat3A.setM20(2.0);
034        mat3A.setM21(2.1);
035        mat3A.setM22(2.2);
036
037        assertTrue(0.0 == mat3A.getM00());
038        assertTrue(0.1 == mat3A.getM01());
039        assertTrue(0.2 == mat3A.getM02());
040        assertTrue(1.0 == mat3A.getM10());
041        assertTrue(1.1 == mat3A.getM11());
042        assertTrue(1.2 == mat3A.getM12());
043        assertTrue(2.0 == mat3A.getM20());
044        assertTrue(2.1 == mat3A.getM21());
045        assertTrue(2.2 == mat3A.getM22());
046
047        final Matrix3 mat3B = new Matrix3(mat3A);
048        assertTrue(0.0 == mat3B.getM00());
049        assertTrue(0.1 == mat3B.getM01());
050        assertTrue(0.2 == mat3B.getM02());
051        assertTrue(1.0 == mat3B.getM10());
052        assertTrue(1.1 == mat3B.getM11());
053        assertTrue(1.2 == mat3B.getM12());
054        assertTrue(2.0 == mat3B.getM20());
055        assertTrue(2.1 == mat3B.getM21());
056        assertTrue(2.2 == mat3B.getM22());
057
058        final Matrix3 mat3C = new Matrix3(0.0, 0.1, 0.2, 1.0, 1.1, 1.2, 2.0, 2.1, 2.2);
059        assertTrue(0.0 == mat3C.getM00());
060        assertTrue(0.1 == mat3C.getM01());
061        assertTrue(0.2 == mat3C.getM02());
062        assertTrue(1.0 == mat3C.getM10());
063        assertTrue(1.1 == mat3C.getM11());
064        assertTrue(1.2 == mat3C.getM12());
065        assertTrue(2.0 == mat3C.getM20());
066        assertTrue(2.1 == mat3C.getM21());
067        assertTrue(2.2 == mat3C.getM22());
068
069        mat3C.setIdentity();
070        assertTrue(mat3C.isIdentity());
071
072        for (int x = 0; x < 3; x++) {
073            for (int y = 0; y < 3; y++) {
074                final double value = (10 * x + y) / 10.;
075                mat3C.setValue(x, y, value);
076                assertTrue(value == mat3C.getValue(x, y));
077            }
078        }
079
080        mat3C.setIdentity();
081        mat3C.set(0.0, 0.1, 0.2, 2.0, 2.1, 2.2, 4.0, 4.1, 4.2);
082        for (int x = 0; x < 3; x++) {
083            for (int y = 0; y < 3; y++) {
084                assertTrue((20 * x + y) / 10.f == mat3C.getValuef(x, y));
085            }
086        }
087
088        final Matrix3 store = new Matrix3(mat3C);
089        // catch a few expected exceptions
090        try {
091            mat3C.getValue(-1, 0);
092            fail("getValue(-1, 0) should have thrown IllegalArgumentException.");
093        } catch (final IllegalArgumentException e) {
094        }
095        try {
096            mat3C.getValue(0, 3);
097            fail("getValue(0, 3) should have thrown IllegalArgumentException.");
098        } catch (final IllegalArgumentException e) {
099        }
100        try {
101            mat3C.getValue(1, -1);
102            fail("getValue(1, -1) should have thrown IllegalArgumentException.");
103        } catch (final IllegalArgumentException e) {
104        }
105        try {
106            mat3C.getValue(2, 3);
107            fail("getValue(2, 3) should have thrown IllegalArgumentException.");
108        } catch (final IllegalArgumentException e) {
109        }
110        try {
111            mat3C.getValue(3, 0);
112            fail("getValue(3, 0) should have thrown IllegalArgumentException.");
113        } catch (final IllegalArgumentException e) {
114        }
115
116        try {
117            mat3C.setValue(-1, 0, 0);
118            fail("setValue(-1, 0, 0) should have thrown IllegalArgumentException.");
119        } catch (final IllegalArgumentException e) {
120        }
121        try {
122            mat3C.setValue(0, -1, 0);
123            fail("setValue(0, -1, 0) should have thrown IllegalArgumentException.");
124        } catch (final IllegalArgumentException e) {
125        }
126        try {
127            mat3C.setValue(1, 3, 0);
128            fail("setValue(1, 3, 0) should have thrown IllegalArgumentException.");
129        } catch (final IllegalArgumentException e) {
130        }
131        try {
132            mat3C.setValue(2, -1, 0);
133            fail("setValue(2, -1, 0) should have thrown IllegalArgumentException.");
134        } catch (final IllegalArgumentException e) {
135        }
136        try {
137            mat3C.setValue(3, 0, 0);
138            fail("setValue(3, 0, 0) should have thrown IllegalArgumentException.");
139        } catch (final IllegalArgumentException e) {
140        }
141        // above exceptions shouldn't have altered mat3C
142        assertEquals(store, mat3C);
143    }
144
145    @Test
146    public void testColumns() {
147        final Matrix3 mat3A = new Matrix3();
148        mat3A.setColumn(0, new Vector3(0, 3, 6));
149        mat3A.setColumn(1, new Vector3(1, 4, 7));
150        mat3A.setColumn(2, new Vector3(2, 5, 8));
151        assertEquals(new Vector3(0, 3, 6), mat3A.getColumn(0, new Vector3()));
152        assertEquals(new Vector3(1, 4, 7), mat3A.getColumn(1, null));
153        assertEquals(new Vector3(2, 5, 8), mat3A.getColumn(2, null));
154        try {
155            mat3A.getColumn(-1, null);
156            fail("getColumn(-1, null) should have thrown IllegalArgumentException.");
157        } catch (final IllegalArgumentException e) {
158        }
159        try {
160            mat3A.getColumn(3, null);
161            fail("getColumn(3, null) should have thrown IllegalArgumentException.");
162        } catch (final IllegalArgumentException e) {
163        }
164        try {
165            mat3A.setColumn(-1, new Vector3());
166            fail("setColumn(-1, Vector3) should have thrown IllegalArgumentException.");
167        } catch (final IllegalArgumentException e) {
168        }
169        try {
170            mat3A.setColumn(4, new Vector3());
171            fail("setColumn(4, Vector3) should have thrown IllegalArgumentException.");
172        } catch (final IllegalArgumentException e) {
173        }
174
175        mat3A.fromAxes(new Vector3(1, 2, 3), new Vector3(4, 5, 6), new Vector3(7, 8, 9));
176        mat3A.setColumn(0, new Vector3(1, 2, 3));
177        mat3A.setColumn(1, new Vector3(4, 5, 6));
178        mat3A.setColumn(2, new Vector3(7, 8, 9));
179    }
180
181    @Test
182    public void testRows() {
183        final Matrix3 mat3A = new Matrix3();
184        mat3A.setRow(0, new Vector3(0, 1, 2));
185        mat3A.setRow(1, new Vector3(3, 4, 5));
186        mat3A.setRow(2, new Vector3(6, 7, 8));
187        assertEquals(new Vector3(0, 1, 2), mat3A.getRow(0, new Vector3()));
188        assertEquals(new Vector3(3, 4, 5), mat3A.getRow(1, null));
189        assertEquals(new Vector3(6, 7, 8), mat3A.getRow(2, null));
190        try {
191            mat3A.getRow(-1, null);
192            fail("getRow(-1, null) should have thrown IllegalArgumentException.");
193        } catch (final IllegalArgumentException e) {
194        }
195        try {
196            mat3A.getRow(3, null);
197            fail("getRow(3, null) should have thrown IllegalArgumentException.");
198        } catch (final IllegalArgumentException e) {
199        }
200        try {
201            mat3A.setRow(-1, new Vector3());
202            fail("setRow(-1, Vector3) should have thrown IllegalArgumentException.");
203        } catch (final IllegalArgumentException e) {
204        }
205        try {
206            mat3A.setRow(3, new Vector3());
207            fail("setRow(3, Vector3]) should have thrown IllegalArgumentException.");
208        } catch (final IllegalArgumentException e) {
209        }
210    }
211
212    @Test
213    public void testSetRotation() {
214        final Matrix3 mat3A = new Matrix3();
215        // rotate identity 90 degrees around Y
216        final double a = MathUtils.HALF_PI;
217        final Quaternion quaternion = new Quaternion();
218        quaternion.fromAngleAxis(a, Vector3.UNIT_Y);
219        mat3A.set(quaternion);
220
221        assertEquals(new Matrix3( //
222                Math.cos(a), 0, Math.sin(a), //
223                0, 1, 0, //
224                -Math.sin(a), 0, Math.cos(a)), mat3A);
225    }
226
227    @Test
228    public void testFromBuffer() {
229        final FloatBuffer fb = FloatBuffer.allocate(9);
230        fb.put(new float[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 });
231        fb.flip();
232        // row major
233        final Matrix3 mat3A = new Matrix3().fromFloatBuffer(fb);
234        assertTrue(0 == mat3A.getM00());
235        assertTrue(1 == mat3A.getM01());
236        assertTrue(2 == mat3A.getM02());
237        assertTrue(3 == mat3A.getM10());
238        assertTrue(4 == mat3A.getM11());
239        assertTrue(5 == mat3A.getM12());
240        assertTrue(6 == mat3A.getM20());
241        assertTrue(7 == mat3A.getM21());
242        assertTrue(8 == mat3A.getM22());
243
244        // column major
245        fb.rewind();
246        mat3A.setIdentity();
247        mat3A.fromFloatBuffer(fb, false);
248        assertTrue(0 == mat3A.getM00());
249        assertTrue(3 == mat3A.getM01());
250        assertTrue(6 == mat3A.getM02());
251        assertTrue(1 == mat3A.getM10());
252        assertTrue(4 == mat3A.getM11());
253        assertTrue(7 == mat3A.getM12());
254        assertTrue(2 == mat3A.getM20());
255        assertTrue(5 == mat3A.getM21());
256        assertTrue(8 == mat3A.getM22());
257
258        final DoubleBuffer db = DoubleBuffer.allocate(16);
259        db.put(new double[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 });
260        db.flip();
261        // row major
262        mat3A.setIdentity();
263        mat3A.fromDoubleBuffer(db);
264        assertTrue(0 == mat3A.getM00());
265        assertTrue(1 == mat3A.getM01());
266        assertTrue(2 == mat3A.getM02());
267        assertTrue(3 == mat3A.getM10());
268        assertTrue(4 == mat3A.getM11());
269        assertTrue(5 == mat3A.getM12());
270        assertTrue(6 == mat3A.getM20());
271        assertTrue(7 == mat3A.getM21());
272        assertTrue(8 == mat3A.getM22());
273
274        // column major
275        db.rewind();
276        mat3A.setIdentity();
277        mat3A.fromDoubleBuffer(db, false);
278        assertTrue(0 == mat3A.getM00());
279        assertTrue(3 == mat3A.getM01());
280        assertTrue(6 == mat3A.getM02());
281        assertTrue(1 == mat3A.getM10());
282        assertTrue(4 == mat3A.getM11());
283        assertTrue(7 == mat3A.getM12());
284        assertTrue(2 == mat3A.getM20());
285        assertTrue(5 == mat3A.getM21());
286        assertTrue(8 == mat3A.getM22());
287    }
288
289    @Test
290    public void testToBuffer() {
291        final double[] values = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
292        final double[] colmajor = { 0, 3, 6, 1, 4, 7, 2, 5, 8 };
293
294        final Matrix3 mat3A = new Matrix3().fromArray(values);
295
296        // row major
297        final FloatBuffer fb = mat3A.toFloatBuffer(FloatBuffer.allocate(9));
298        fb.flip();
299        for (int i = 0; i < 9; i++) {
300            assertTrue(values[i] == fb.get());
301        }
302
303        // column major
304        fb.rewind();
305        mat3A.toFloatBuffer(fb, false);
306        fb.flip();
307        for (int i = 0; i < 9; i++) {
308            assertTrue(colmajor[i] == fb.get());
309        }
310
311        // row major
312        final DoubleBuffer db = mat3A.toDoubleBuffer(DoubleBuffer.allocate(9));
313        db.flip();
314        for (int i = 0; i < 9; i++) {
315            assertTrue(values[i] == db.get());
316        }
317
318        // column major
319        db.rewind();
320        mat3A.toDoubleBuffer(db, false);
321        db.flip();
322        for (int i = 0; i < 9; i++) {
323            assertTrue(colmajor[i] == db.get());
324        }
325    }
326
327    @Test
328    public void testFromArray() {
329        final double[] values = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
330        final Matrix3 mat3A = new Matrix3();
331
332        // row major
333        mat3A.fromArray(values);
334        assertTrue(0 == mat3A.getM00());
335        assertTrue(1 == mat3A.getM01());
336        assertTrue(2 == mat3A.getM02());
337        assertTrue(3 == mat3A.getM10());
338        assertTrue(4 == mat3A.getM11());
339        assertTrue(5 == mat3A.getM12());
340        assertTrue(6 == mat3A.getM20());
341        assertTrue(7 == mat3A.getM21());
342        assertTrue(8 == mat3A.getM22());
343
344        // column major
345        mat3A.setIdentity();
346        mat3A.fromArray(values, false);
347        assertTrue(0 == mat3A.getM00());
348        assertTrue(3 == mat3A.getM01());
349        assertTrue(6 == mat3A.getM02());
350        assertTrue(1 == mat3A.getM10());
351        assertTrue(4 == mat3A.getM11());
352        assertTrue(7 == mat3A.getM12());
353        assertTrue(2 == mat3A.getM20());
354        assertTrue(5 == mat3A.getM21());
355        assertTrue(8 == mat3A.getM22());
356    }
357
358    @Test
359    public void testToArray() {
360        final double[] values = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
361        final Matrix3 mat3A = new Matrix3().fromArray(values);
362
363        // row major
364        final double[] dbls1 = mat3A.toArray(null);
365        for (int i = 0; i < 9; i++) {
366            assertTrue(values[i] == dbls1[i]);
367        }
368
369        // column major
370        final double[] colmajor = { 0, 3, 6, 1, 4, 7, 2, 5, 8 };
371        mat3A.toArray(dbls1, false);
372        for (int i = 0; i < 9; i++) {
373            assertTrue(colmajor[i] == dbls1[i]);
374        }
375    }
376
377    @Test(expected = IllegalArgumentException.class)
378    public void testBadArray() {
379        final Matrix3 mat3A = new Matrix3();
380        mat3A.toArray(new double[4]);
381    }
382
383    @Test(expected = IllegalArgumentException.class)
384    public void testBadAnglesArray() {
385        final Matrix3 mat3A = new Matrix3();
386        mat3A.toAngles(new double[2]);
387    }
388
389    @Test
390    public void testAngleAxis() {
391        final Matrix3 mat3A = new Matrix3();
392        // rotate identity 90 degrees around X
393        final double angle = MathUtils.HALF_PI;
394        mat3A.fromAngleAxis(MathUtils.HALF_PI, Vector3.UNIT_X);
395        assertEquals(new Matrix3( //
396                1, 0, 0, //
397                0, Math.cos(angle), -Math.sin(angle), //
398                0, Math.sin(angle), Math.cos(angle)), mat3A);
399    }
400
401    @Test
402    public void testRotations() {
403        final Vector3 rotated = new Vector3(1, 1, 1);
404        final Vector3 expected = new Vector3(1, 1, 1);
405
406        // rotated
407        final Matrix3 mat3A = new Matrix3().fromAngles(MathUtils.HALF_PI, MathUtils.QUARTER_PI, MathUtils.PI);
408        mat3A.applyPost(rotated, rotated);
409
410        // expected - post
411        final Matrix3 worker = new Matrix3().fromAngleAxis(MathUtils.HALF_PI, Vector3.UNIT_X);
412        worker.applyPost(expected, expected);
413        worker.fromAngleAxis(MathUtils.PI, Vector3.UNIT_Z);
414        worker.applyPost(expected, expected);
415        worker.fromAngleAxis(MathUtils.QUARTER_PI, Vector3.UNIT_Y);
416        worker.applyPost(expected, expected);
417
418        // test how close it came out
419        assertTrue(rotated.distance(expected) <= MathUtils.EPSILON);
420
421        // Try a new way with new angles...
422        final Matrix3 mat3B = new Matrix3().fromAngles(MathUtils.QUARTER_PI, MathUtils.PI, MathUtils.HALF_PI);
423        rotated.set(1, 1, 1);
424        mat3B.applyPost(rotated, rotated);
425
426        // expected
427        expected.set(1, 1, 1);
428        worker.setIdentity();
429        // put together matrix, then apply to vector, so YZX
430        worker.applyRotationY(MathUtils.PI);
431        worker.applyRotationZ(MathUtils.HALF_PI);
432        worker.applyRotationX(MathUtils.QUARTER_PI);
433        worker.applyPost(expected, expected);
434
435        // test how close it came out
436        assertTrue(rotated.distance(expected) <= MathUtils.EPSILON);
437
438        // test axis rotation methods against general purpose
439        // X AXIS
440        expected.set(1, 1, 1);
441        rotated.set(1, 1, 1);
442        worker.setIdentity().applyRotationX(MathUtils.QUARTER_PI).applyPost(expected, expected);
443        worker.setIdentity().applyRotation(MathUtils.QUARTER_PI, 1, 0, 0).applyPost(rotated, rotated);
444        assertTrue(rotated.distance(expected) <= MathUtils.EPSILON);
445
446        // Y AXIS
447        expected.set(1, 1, 1);
448        rotated.set(1, 1, 1);
449        worker.setIdentity().applyRotationY(MathUtils.QUARTER_PI).applyPost(expected, expected);
450        worker.setIdentity().applyRotation(MathUtils.QUARTER_PI, 0, 1, 0).applyPost(rotated, rotated);
451        assertTrue(rotated.distance(expected) <= MathUtils.EPSILON);
452
453        // Z AXIS
454        expected.set(1, 1, 1);
455        rotated.set(1, 1, 1);
456        worker.setIdentity().applyRotationZ(MathUtils.QUARTER_PI).applyPost(expected, expected);
457        worker.setIdentity().applyRotation(MathUtils.QUARTER_PI, 0, 0, 1).applyPost(rotated, rotated);
458        assertTrue(rotated.distance(expected) <= MathUtils.EPSILON);
459
460        // test toAngles - not necessarily the same values as fromAngles, but should be same resulting Matrix.
461        mat3A.fromAngles(MathUtils.HALF_PI, MathUtils.QUARTER_PI, MathUtils.PI);
462        final double[] angles = mat3A.toAngles(null);
463        worker.fromAngles(angles[0], angles[1], angles[2]);
464        assertEquals(mat3A, worker);
465
466        mat3A.fromAngles(MathUtils.HALF_PI, MathUtils.QUARTER_PI, MathUtils.HALF_PI);
467        mat3A.toAngles(angles);
468        worker.fromAngles(angles[0], angles[1], angles[2]);
469        assertEquals(mat3A, worker);
470
471        mat3A.fromAngles(MathUtils.HALF_PI, MathUtils.QUARTER_PI, -MathUtils.HALF_PI);
472        mat3A.toAngles(angles);
473        worker.fromAngles(angles[0], angles[1], angles[2]);
474        assertEquals(mat3A, worker);
475    }
476
477    @Test
478    public void testMultiplyDiagonal() {
479        final Matrix3 mat3A = new Matrix3();
480        Matrix3 result = mat3A.multiplyDiagonalPost(new Vector3(2, 4, 6), null);
481        assertEquals(new Matrix3( //
482                2, 0, 0, //
483                0, 4, 0, //
484                0, 0, 6), result);
485        mat3A.multiplyDiagonalPre(new Vector3(-2, -4, -6), result);
486        assertEquals(new Matrix3( //
487                -2, 0, 0, //
488                0, -4, 0, //
489                0, 0, -6), result);
490
491        final double a = MathUtils.HALF_PI;
492        mat3A.applyRotationY(a);
493        mat3A.multiplyDiagonalPost(new Vector3(2, 4, 6), result);
494        assertEquals(new Matrix3( //
495                2 * Math.cos(a), 4 * 0, 6 * Math.sin(a), //
496                2 * 0, 4 * 1, 6 * 0, //
497                2 * -Math.sin(a), 4 * 0, 6 * Math.cos(a)), result);
498        result = mat3A.multiplyDiagonalPre(new Vector3(-2, -4, -6), null);
499        assertEquals(new Matrix3( //
500                -2 * Math.cos(a), -2 * 0, -2 * Math.sin(a), //
501                -4 * 0, -4 * 1, -4 * 0, //
502                -6 * -Math.sin(a), -6 * 0, -6 * Math.cos(a)), result);
503    }
504
505    @Test
506    public void testMultiply() {
507        final Matrix3 mat3A = new Matrix3( //
508                0.01, 0.1, 0.2, //
509                1.0, 1.1, 1.2, //
510                2.0, 2.1, 2.2);
511        mat3A.multiplyLocal(2);
512        assertEquals(new Matrix3( //
513                0.02, 0.2, 0.4, //
514                2.0, 2.2, 2.4, //
515                4.0, 4.2, 4.4), mat3A);
516
517        final Matrix3 mat3B = new Matrix3( //
518                0.5, 1, 2, //
519                4, 5, 6, //
520                8, 9, 10);
521        final Matrix3 result = mat3A.multiply(mat3B, null);
522        assertTrue(0.02 * 0.5 + 0.2 * 4 + 0.4 * 8 == result.getM00());
523        assertTrue(0.02 * 1 + 0.2 * 5 + 0.4 * 9 == result.getM01());
524        assertTrue(0.02 * 2 + 0.2 * 6 + 0.4 * 10 == result.getM02());
525        assertTrue(2.0 * 0.5 + 2.2 * 4 + 2.4 * 8 == result.getM10());
526        assertTrue(2.0 * 1 + 2.2 * 5 + 2.4 * 9 == result.getM11());
527        assertTrue(2.0 * 2 + 2.2 * 6 + 2.4 * 10 == result.getM12());
528        assertTrue(4.0 * 0.5 + 4.2 * 4 + 4.4 * 8 == result.getM20());
529        assertTrue(4.0 * 1 + 4.2 * 5 + 4.4 * 9 == result.getM21());
530        assertTrue(4.0 * 2 + 4.2 * 6 + 4.4 * 10 == result.getM22());
531        mat3A.multiplyLocal(mat3B);
532        assertTrue(0.02 * 0.5 + 0.2 * 4 + 0.4 * 8 == mat3A.getM00());
533        assertTrue(0.02 * 1 + 0.2 * 5 + 0.4 * 9 == mat3A.getM01());
534        assertTrue(0.02 * 2 + 0.2 * 6 + 0.4 * 10 == mat3A.getM02());
535        assertTrue(2.0 * 0.5 + 2.2 * 4 + 2.4 * 8 == mat3A.getM10());
536        assertTrue(2.0 * 1 + 2.2 * 5 + 2.4 * 9 == mat3A.getM11());
537        assertTrue(2.0 * 2 + 2.2 * 6 + 2.4 * 10 == mat3A.getM12());
538        assertTrue(4.0 * 0.5 + 4.2 * 4 + 4.4 * 8 == mat3A.getM20());
539        assertTrue(4.0 * 1 + 4.2 * 5 + 4.4 * 9 == mat3A.getM21());
540        assertTrue(4.0 * 2 + 4.2 * 6 + 4.4 * 10 == mat3A.getM22());
541    }
542
543    @Test
544    public void testAddSubtract() {
545        final Matrix3 mat3A = new Matrix3( //
546                0.0, 0.1, 0.2, //
547                1.0, 1.1, 1.2, //
548                2.0, 2.1, 2.2);
549
550        final Matrix3 result1 = mat3A.add(new Matrix3(//
551                1, 2, 3,//
552                5, 6, 7, //
553                9, 10, 11), null);
554        assertEquals(new Matrix3( //
555                1.0, 2.1, 3.2, //
556                6.0, 7.1, 8.2, //
557                11.0, 12.1, 13.2), result1);
558
559        final Matrix3 result2 = result1.subtract(new Matrix3(//
560                1, 2, 3, //
561                5, 6, 7, //
562                9, 10, 11), null);
563        assertEquals(mat3A, result2);
564        result2.addLocal(Matrix3.IDENTITY);
565        assertEquals(new Matrix3( //
566                1.0, 0.1, 0.2, //
567                1.0, 2.1, 1.2, //
568                2.0, 2.1, 3.2), result2);
569
570        result1.subtractLocal(Matrix3.IDENTITY);
571        assertEquals(new Matrix3( //
572                0.0, 2.1, 3.2, //
573                6.0, 6.1, 8.2, //
574                11.0, 12.1, 12.2), result1);
575    }
576
577    @Test
578    public void testScale() {
579        final Matrix3 mat3A = new Matrix3( //
580                0.01, 0.1, 0.2, //
581                1.0, 1.1, 1.2, //
582                2.0, 2.1, 2.2);
583        final Matrix3 result = mat3A.scale(new Vector3(-1, 2, 3), null);
584        assertEquals(new Matrix3( //
585                0.01 * -1, 0.1 * 2, 0.2 * 3, //
586                1.0 * -1, 1.1 * 2, 1.2 * 3, //
587                2.0 * -1, 2.1 * 2, 2.2 * 3), result);
588
589        result.scaleLocal(new Vector3(-1, 0.5, 1 / 3.));
590        assertEquals(mat3A, result);
591    }
592
593    @Test
594    public void testTranspose() {
595        final Matrix3 mat3A = new Matrix3( //
596                0.01, 0.1, 0.2, //
597                1.0, 1.1, 1.2, //
598                2.0, 2.1, 2.2);
599        final Matrix3 result = mat3A.transpose(null);
600        assertEquals(new Matrix3( //
601                0.01, 1.0, 2.0, //
602                0.1, 1.1, 2.1, //
603                0.2, 1.2, 2.2), result);
604        assertEquals(new Matrix3( //
605                0.01, 0.1, 0.2, //
606                1.0, 1.1, 1.2, //
607                2.0, 2.1, 2.2), result.transposeLocal());
608        // coverage
609        final Matrix3 result2 = result.transposeLocal().transpose(new Matrix3());
610        assertEquals(mat3A, result2);
611    }
612
613    @Test
614    public void testInvert() {
615        final Matrix3 mat3A = new Matrix3().applyRotationX(MathUtils.QUARTER_PI);
616        final Matrix3 inverted = mat3A.invert(null);
617        assertEquals(Matrix3.IDENTITY, mat3A.multiply(inverted, null));
618        assertEquals(mat3A, inverted.invertLocal());
619    }
620
621    @Test(expected = ArithmeticException.class)
622    public void testBadInvert() {
623        final Matrix3 mat3A = new Matrix3(0, 0, 0, 0, 0, 0, 0, 0, 0);
624        mat3A.invertLocal();
625    }
626
627    @Test
628    public void testAdjugate() {
629        final double //
630        a = -3, b = 2, c = -5, //
631        d = -1, e = 0, f = -2, //
632        g = 3, h = -4, i = 1;
633
634        final Matrix3 mat3A = new Matrix3( //
635                a, b, c, //
636                d, e, f, //
637                g, h, i);
638
639        final Matrix3 testValue = new Matrix3( //
640                e * i - h * f, -(b * i - h * c), b * f - e * c, //
641                -(d * i - g * f), a * i - g * c, -(a * f - d * c),//
642                d * h - g * e, -(a * h - g * b), a * e - d * b);
643
644        assertEquals(testValue, mat3A.adjugate(null));
645        assertEquals(testValue, mat3A.adjugateLocal());
646    }
647
648    @Test
649    public void testDeterminant() {
650        {
651            final double //
652            a = -3, b = 2, c = -5, //
653            d = -1, e = 0, f = -2, //
654            g = 3, h = -4, i = 1;
655
656            final Matrix3 mat3A = new Matrix3( //
657                    a, b, c, //
658                    d, e, f, //
659                    g, h, i);
660            final double determinant = a * e * i + b * f * g + c * d * h - c * e * g - b * d * i - a * f * h;
661            assertTrue(determinant == mat3A.determinant());
662        }
663
664        {
665            final double //
666            a = -1, b = 2, c = -3, //
667            d = 4, e = -5, f = 6, //
668            g = -7, h = 8, i = -9;
669
670            final Matrix3 mat3A = new Matrix3( //
671                    a, b, c, //
672                    d, e, f, //
673                    g, h, i);
674            final double determinant = a * e * i + b * f * g + c * d * h - c * e * g - b * d * i - a * f * h;
675            assertTrue(determinant == mat3A.determinant());
676        }
677    }
678
679    @Test
680    public void testClone() {
681        final Matrix3 mat1 = new Matrix3();
682        final Matrix3 mat2 = mat1.clone();
683        assertEquals(mat1, mat2);
684        assertNotSame(mat1, mat2);
685    }
686
687    @Test
688    public void testValid() {
689        final Matrix3 mat3 = new Matrix3();
690        assertTrue(Matrix3.isValid(mat3));
691        for (int i = 0; i < 9; i++) {
692            mat3.setIdentity();
693            mat3.setValue(i / 3, i % 3, Double.NaN);
694            assertFalse(Matrix3.isValid(mat3));
695            mat3.setIdentity();
696            mat3.setValue(i / 3, i % 3, Double.POSITIVE_INFINITY);
697            assertFalse(Matrix3.isValid(mat3));
698        }
699
700        mat3.setIdentity();
701        assertTrue(Matrix3.isValid(mat3));
702
703        assertFalse(Matrix3.isValid(null));
704
705        // couple of equals validity tests
706        assertEquals(mat3, mat3);
707        assertTrue(mat3.strictEquals(mat3));
708        assertFalse(mat3.equals(null));
709        assertFalse(mat3.strictEquals(null));
710        assertFalse(mat3.equals(new Vector2()));
711        assertFalse(mat3.strictEquals(new Vector2()));
712
713        // throw in a couple pool accesses for coverage
714        final Matrix3 matTemp = Matrix3.fetchTempInstance();
715        matTemp.set(mat3);
716        assertEquals(mat3, matTemp);
717        assertNotSame(mat3, matTemp);
718        Matrix3.releaseTempInstance(matTemp);
719
720        // cover more of equals
721        mat3.set(0, 1, 2, 3, 4, 5, 6, 7, 8);
722        final Matrix3 comp = new Matrix3(-1, -1, -1, -1, -1, -1, -1, -1, -1);
723        assertFalse(mat3.equals(comp));
724        assertFalse(mat3.strictEquals(comp));
725        for (int i = 0; i < 8; i++) {
726            comp.setValue(i / 3, i % 3, i);
727            assertFalse(mat3.equals(comp));
728            assertFalse(mat3.strictEquals(comp));
729        }
730    }
731
732    @Test
733    public void testSimpleHash() {
734        // Just a simple sanity check.
735        final Matrix3 mat1 = new Matrix3(1, 2, 3, 4, 5, 6, 7, 8, 9);
736        final Matrix3 mat2 = new Matrix3(1, 2, 3, 4, 5, 6, 7, 8, 9);
737        final Matrix3 mat3 = new Matrix3(1, 2, 3, 4, 5, 6, 7, 8, 0);
738
739        assertTrue(mat1.hashCode() == mat2.hashCode());
740        assertTrue(mat1.hashCode() != mat3.hashCode());
741    }
742
743    @Test
744    public void testOrthonormal() {
745        final Matrix3 mat3 = new Matrix3();
746        assertTrue(mat3.isOrthonormal());
747        // just rotation
748        mat3.applyRotationX(MathUtils.QUARTER_PI);
749        assertTrue(mat3.isOrthonormal());
750        // non-uniform scale
751        mat3.setIdentity();
752        mat3.scaleLocal(new Vector3(1, 2, 3));
753        assertFalse(mat3.isOrthonormal());
754        // non-uniform scale + rotation
755        mat3.setIdentity();
756        mat3.scaleLocal(new Vector3(1, 2, 3));
757        mat3.applyRotationX(MathUtils.QUARTER_PI);
758        assertFalse(mat3.isOrthonormal());
759    }
760
761    @Test
762    public void testApplyVector3() {
763        final Matrix3 mat3 = new Matrix3().applyRotationX(MathUtils.HALF_PI);
764        final Vector3 vec3 = new Vector3(0, 1, 0);
765        final Vector3 result = mat3.applyPost(vec3, null);
766        assertTrue(Math.abs(new Vector3(0, 0, 1).distance(result)) <= MathUtils.EPSILON);
767        vec3.set(0, 1, 1);
768        mat3.applyPost(vec3, result);
769        assertTrue(Math.abs(new Vector3(0, -1, 1).distance(result)) <= MathUtils.EPSILON);
770
771        vec3.set(0, 1, 1);
772        mat3.applyPre(vec3, result);
773        assertTrue(Math.abs(new Vector3(0, 1, -1).distance(result)) <= MathUtils.EPSILON);
774
775        vec3.set(1, 1, 1);
776        assertTrue(Math.abs(new Vector3(1, 1, -1).distance(mat3.applyPre(vec3, null))) <= MathUtils.EPSILON);
777    }
778
779    @Test
780    public void testStartEnd() {
781        final Matrix3 mat3 = new Matrix3();
782        mat3.fromStartEndLocal(Vector3.UNIT_X, Vector3.UNIT_Y); // should be a 90 degree turn around Z
783        assertEquals(new Vector3(-1, 1, 1), mat3.applyPost(new Vector3(1, 1, 1), null));
784
785        // coverage
786        mat3.fromStartEndLocal(new Vector3(1, 0, 0), new Vector3(1 + Double.MIN_VALUE, 0, 0));
787        assertTrue(mat3.applyPost(Vector3.ONE, null).distance(Vector3.ONE) < MathUtils.ZERO_TOLERANCE);
788        mat3.fromStartEndLocal(new Vector3(0, 1, 0), new Vector3(0, 1 + Double.MIN_VALUE, 0));
789        assertTrue(mat3.applyPost(Vector3.ONE, null).distance(Vector3.ONE) < MathUtils.ZERO_TOLERANCE);
790        mat3.fromStartEndLocal(new Vector3(0, 0, 1), new Vector3(0, 0, 1 + Double.MIN_VALUE));
791        assertTrue(mat3.applyPost(Vector3.ONE, null).distance(Vector3.ONE) < MathUtils.ZERO_TOLERANCE);
792    }
793
794    @Test
795    public void testLookAt() {
796        final Vector3 direction = new Vector3(-1, 0, 0);
797        final Matrix3 mat3 = new Matrix3().lookAt(direction, Vector3.UNIT_Y);
798        assertEquals(direction, mat3.applyPost(Vector3.UNIT_Z, null));
799
800        direction.set(1, 1, 1).normalizeLocal();
801        mat3.lookAt(direction, Vector3.UNIT_Y);
802        assertEquals(direction, mat3.applyPost(Vector3.UNIT_Z, null));
803
804        direction.set(-1, 2, -1).normalizeLocal();
805        mat3.lookAt(direction, Vector3.UNIT_Y);
806        assertEquals(direction, mat3.applyPost(Vector3.UNIT_Z, new Vector3()));
807    }
808}