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 TestTransform { 021 022 @Test 023 public void testGetSet() { 024 final Transform trans = new Transform(); 025 assertEquals(Transform.IDENTITY, trans); 026 027 final Transform immutable = new Transform(new Matrix3().applyRotationX(MathUtils.QUARTER_PI), new Vector3(0, 028 -1, -2), new Vector3(1, 2, 3), true, true, true); 029 assertTrue(true == immutable.isIdentity()); 030 assertTrue(true == immutable.isRotationMatrix()); 031 assertTrue(true == immutable.isUniformScale()); 032 assertEquals(new Matrix3().applyRotationX(MathUtils.QUARTER_PI), immutable.getMatrix()); 033 assertEquals(new Vector3(0, -1, -2), immutable.getScale()); 034 assertEquals(new Vector3(1, 2, 3), immutable.getTranslation()); 035 036 final Transform trans2 = new Transform(immutable); 037 assertEquals(immutable, trans2); 038 trans2.updateFlags(false); 039 040 trans.set(immutable); 041 assertEquals(Transform.IDENTITY, trans); // because of shortcut flags. 042 043 trans.set(trans2); 044 assertEquals(trans2, trans); 045 046 trans.setIdentity(); 047 assertEquals(Transform.IDENTITY, trans); 048 049 final double a = MathUtils.QUARTER_PI; 050 trans.setRotation(new Quaternion().fromAngleAxis(a, Vector3.UNIT_Y)); 051 052 assertEquals(new Matrix3( // 053 Math.cos(a), 0, Math.sin(a), // 054 0, 1, 0, // 055 -Math.sin(a), 0, Math.cos(a)), trans.getMatrix()); 056 057 trans2.setRotation(new Matrix3().fromAngleAxis(a, Vector3.UNIT_Y)); 058 assertEquals(trans.getMatrix(), trans2.getMatrix()); 059 060 trans.setScale(1.0); 061 assertEquals(Vector3.ONE, trans.getScale()); 062 063 trans.setScale(new Vector3(1, 2, 3)); 064 assertEquals(new Vector3(1, 2, 3), trans.getScale()); 065 066 trans.setScale(-1, 5, -3); 067 assertEquals(new Vector3(-1, 5, -3), trans.getScale()); 068 069 trans.setTranslation(new Vector3(10, 20, 30)); 070 assertEquals(new Vector3(10, 20, 30), trans.getTranslation()); 071 072 trans.setTranslation(-10, 50, -30); 073 assertEquals(new Vector3(-10, 50, -30), trans.getTranslation()); 074 075 trans.setIdentity(); 076 trans.setRotation(new Matrix3().fromAngleAxis(a, Vector3.UNIT_Y)); 077 trans.setScale(2, 3, 4); 078 trans.setTranslation(5, 10, 15); 079 080 final Matrix4 mat4 = trans.getHomogeneousMatrix(null); 081 assertEquals(new Matrix4( // 082 2 * Math.cos(a), 2 * 0, 2 * Math.sin(a), 5, // 083 3 * 0, 3 * 1, 3 * 0, 10, // 084 4 * -Math.sin(a), 4 * 0, 4 * Math.cos(a), 15, // 085 0, 0, 0, 1), mat4); 086 087 trans2.fromHomogeneousMatrix(mat4); 088 trans2.getHomogeneousMatrix(mat4); 089 assertEquals(new Matrix4( // 090 2 * Math.cos(a), 2 * 0, 2 * Math.sin(a), 5, // 091 3 * 0, 3 * 1, 3 * 0, 10, // 092 4 * -Math.sin(a), 4 * 0, 4 * Math.cos(a), 15, // 093 0, 0, 0, 1), mat4); 094 095 trans.setIdentity(); 096 trans.setRotation(new Matrix3(0, 1, 2, 3, 4, 5, 6, 7, 8)); 097 trans.setTranslation(10, 11, 12); 098 trans.getHomogeneousMatrix(mat4); 099 assertEquals(new Matrix4( // 100 0, 1, 2, 10, // 101 3, 4, 5, 11, // 102 6, 7, 8, 12, // 103 0, 0, 0, 1), mat4); 104 105 } 106 107 @Test(expected = TransformException.class) 108 public void testFailScale1A() { 109 final Transform trans = new Transform(new Matrix3(), new Vector3(), new Vector3(), false, false, false); 110 trans.setScale(Vector3.ONE); 111 } 112 113 @Test(expected = IllegalArgumentException.class) 114 public void testFailScale1B() { 115 final Transform trans = new Transform(); 116 trans.setScale(Vector3.ZERO); 117 } 118 119 @Test(expected = TransformException.class) 120 public void testFailScale2A() { 121 final Transform trans = new Transform(new Matrix3(), new Vector3(), new Vector3(), false, false, false); 122 trans.setScale(1, 1, 1); 123 } 124 125 @Test(expected = IllegalArgumentException.class) 126 public void testFailScale2B() { 127 final Transform trans = new Transform(); 128 trans.setScale(0, 0, 0); 129 } 130 131 @Test(expected = TransformException.class) 132 public void testFailScale3A() { 133 final Transform trans = new Transform(new Matrix3(), new Vector3(), new Vector3(), false, false, false); 134 trans.setScale(1); 135 } 136 137 @Test(expected = IllegalArgumentException.class) 138 public void testFailScale3B() { 139 final Transform trans = new Transform(); 140 trans.setScale(0); 141 } 142 143 @Test 144 public void testTranslate() { 145 final Transform trans = new Transform(); 146 trans.translate(1, 3, 5); 147 assertEquals(new Vector3(1, 3, 5), trans.getTranslation()); 148 trans.translate(trans.getTranslation().negate(null)); 149 assertEquals(Vector3.ZERO, trans.getTranslation()); 150 151 trans.translate(new Vector3(1, 3, 5)); 152 assertEquals(new Vector3(1, 3, 5), trans.getTranslation()); 153 trans.translate(-1, -3, -5); 154 assertEquals(Vector3.ZERO, trans.getTranslation()); 155 } 156 157 @Test 158 public void testApplyVector3() { 159 final Transform trans = new Transform().setRotation(new Matrix3().applyRotationX(MathUtils.HALF_PI)).translate( 160 1, 2, 3); 161 final Vector3 vec3 = new Vector3(0, 1, 0); 162 163 final Vector3 result = trans.applyForward(vec3, null); 164 assertTrue(Math.abs(new Vector3(1, 2, 4).distance(result)) <= MathUtils.EPSILON); 165 trans.applyForward(vec3, result); 166 assertTrue(Math.abs(new Vector3(1, 2, 4).distance(result)) <= MathUtils.EPSILON); 167 trans.applyForward(vec3); 168 assertTrue(Math.abs(new Vector3(1, 2, 4).distance(vec3)) <= MathUtils.EPSILON); 169 170 vec3.set(0, 1, 1); 171 final Vector3 result2 = trans.applyForwardVector(vec3, null); 172 assertTrue(Math.abs(new Vector3(0, -1, 1).distance(result2)) <= MathUtils.EPSILON); 173 trans.applyForwardVector(vec3, result2); 174 assertTrue(Math.abs(new Vector3(0, -1, 1).distance(result2)) <= MathUtils.EPSILON); 175 trans.applyForwardVector(vec3); 176 assertTrue(Math.abs(new Vector3(0, -1, 1).distance(vec3)) <= MathUtils.EPSILON); 177 178 vec3.set(0, 1, 0); 179 final Vector3 result3 = trans.applyInverse(vec3, null); 180 assertTrue(Math.abs(new Vector3(-1, -3, 1).distance(result3)) <= MathUtils.EPSILON); 181 trans.applyInverse(vec3, result3); 182 assertTrue(Math.abs(new Vector3(-1, -3, 1).distance(result3)) <= MathUtils.EPSILON); 183 trans.applyInverse(vec3); 184 assertTrue(Math.abs(new Vector3(-1, -3, 1).distance(vec3)) <= MathUtils.EPSILON); 185 186 vec3.set(0, 1, 1); 187 final Vector3 result4 = trans.applyInverseVector(vec3, null); 188 assertTrue(Math.abs(new Vector3(0, 1, -1).distance(result4)) <= MathUtils.EPSILON); 189 trans.applyInverseVector(vec3, result4); 190 assertTrue(Math.abs(new Vector3(0, 1, -1).distance(result4)) <= MathUtils.EPSILON); 191 trans.applyInverseVector(vec3); 192 assertTrue(Math.abs(new Vector3(0, 1, -1).distance(vec3)) <= MathUtils.EPSILON); 193 194 trans.setRotation(new Matrix3().applyRotationY(MathUtils.PI)).translate(2, 3, -1); 195 196 vec3.set(1, 2, 3).normalizeLocal(); 197 final Vector3 orig = new Vector3(vec3); 198 trans.applyForward(vec3); 199 trans.applyInverse(vec3); 200 assertTrue(Math.abs(orig.distance(vec3)) <= 10 * MathUtils.EPSILON); // accumulated error 201 202 vec3.set(orig); 203 trans.applyForwardVector(vec3); 204 trans.applyInverseVector(vec3); 205 assertTrue(Math.abs(orig.distance(vec3)) <= 10 * MathUtils.EPSILON); // accumulated error 206 207 vec3.set(orig); 208 trans.setIdentity(); 209 trans.applyForward(vec3); 210 assertEquals(orig, vec3); 211 trans.applyForwardVector(vec3); 212 assertEquals(orig, vec3); 213 trans.applyInverse(vec3); 214 assertEquals(orig, vec3); 215 trans.applyInverseVector(vec3); 216 assertEquals(orig, vec3); 217 } 218 219 @Test(expected = NullPointerException.class) 220 public void testApplyFail1() { 221 final Transform trans = new Transform(); 222 trans.applyForward(null); 223 } 224 225 @Test(expected = NullPointerException.class) 226 public void testApplyFail2() { 227 final Transform trans = new Transform(); 228 trans.applyForwardVector(null); 229 } 230 231 @Test(expected = NullPointerException.class) 232 public void testApplyFail3() { 233 final Transform trans = new Transform(); 234 trans.applyInverse(null); 235 } 236 237 @Test(expected = NullPointerException.class) 238 public void testApplyFail4() { 239 final Transform trans = new Transform(); 240 trans.applyInverseVector(null); 241 } 242 243 @Test 244 public void testMultiply() { 245 final Transform trans1 = new Transform(); 246 final Transform trans2 = new Transform(); 247 assertEquals(Transform.IDENTITY, trans1.multiply(trans2, null)); 248 249 trans1.setTranslation(1, 2, 3); 250 final Transform trans3 = trans1.multiply(trans2, null); 251 assertEquals(trans1, trans3); 252 253 trans2.setTranslation(-1, -2, -3); 254 trans1.multiply(trans2, trans3); 255 assertEquals(Transform.IDENTITY, trans3); 256 assertTrue(trans3.isRotationMatrix()); 257 assertTrue(trans3.isIdentity()); 258 assertTrue(trans3.isUniformScale()); 259 260 trans2.setScale(1, 2, 1); 261 trans1.multiply(trans2, trans3); 262 assertEquals(new Transform().setScale(1, 2, 1), trans3); 263 assertTrue(trans3.isRotationMatrix()); 264 assertFalse(trans3.isIdentity()); 265 assertFalse(trans3.isUniformScale()); 266 267 trans1.setScale(1, 2, 1); 268 trans1.multiply(trans2, trans3); 269 assertEquals(new Transform().setRotation(new Matrix3(1, 0, 0, 0, 4, 0, 0, 0, 1)).setTranslation(0, -2, 0), 270 trans3); 271 assertFalse(trans3.isRotationMatrix()); 272 assertFalse(trans3.isIdentity()); 273 assertFalse(trans3.isUniformScale()); 274 } 275 276 @Test 277 public void testInvert() { 278 final Transform trans1 = new Transform(); 279 trans1.setRotation(new Matrix3().applyRotationZ(3 * MathUtils.QUARTER_PI)); 280 final Transform trans2 = trans1.invert(null); 281 assertEquals(Transform.IDENTITY, trans1.multiply(trans2, null)); 282 283 trans1.setIdentity().invert(trans1); 284 assertEquals(Transform.IDENTITY, trans1); 285 } 286 287 @Test 288 public void testClone() { 289 final Transform trans1 = new Transform(); 290 final Transform trans2 = trans1.clone(); 291 assertEquals(trans1, trans2); 292 assertNotSame(trans1, trans2); 293 } 294 295 @Test 296 public void testValid() { 297 final Transform trans = new Transform(); 298 assertTrue(Transform.isValid(trans)); 299 trans.setIdentity(); 300 trans.setRotation(new Matrix3(Double.NaN, 0, 0, 0, 0, 0, 0, 0, 0)); 301 assertFalse(Transform.isValid(trans)); 302 trans.setIdentity(); 303 trans.setScale(Double.NaN, 0, 0); 304 assertFalse(Transform.isValid(trans)); 305 trans.setScale(Double.NaN); 306 assertFalse(Transform.isValid(trans)); 307 trans.setIdentity(); 308 trans.setTranslation(Double.NaN, 0, 0); 309 assertFalse(Transform.isValid(trans)); 310 311 trans.setIdentity(); 312 assertTrue(Transform.isValid(trans)); 313 314 assertFalse(Transform.isValid(null)); 315 316 // couple of equals validity tests 317 assertEquals(trans, trans); 318 assertTrue(trans.strictEquals(trans)); 319 assertFalse(trans.equals(null)); 320 assertFalse(trans.strictEquals(null)); 321 assertFalse(trans.equals(new Vector2())); 322 assertFalse(trans.strictEquals(new Vector2())); 323 324 // throw in a couple pool accesses for coverage 325 final Transform transTemp = Transform.fetchTempInstance(); 326 transTemp.set(trans); 327 assertEquals(trans, transTemp); 328 assertNotSame(trans, transTemp); 329 Transform.releaseTempInstance(transTemp); 330 331 // cover more of equals 332 trans.setScale(1, 2, 3); 333 trans.setRotation(new Matrix3(0, 1, 2, 3, 4, 5, 6, 7, 8)); 334 trans.setTranslation(1, 2, 3); 335 final Transform comp = new Transform(); 336 final Matrix3 mat3 = new Matrix3(-1, -1, -1, -1, -1, -1, -1, -1, -1); 337 comp.setScale(-1, -1, -1); 338 comp.setRotation(mat3); 339 comp.setTranslation(-1, -1, -1); 340 assertFalse(trans.equals(comp)); 341 assertFalse(trans.strictEquals(comp)); 342 for (int i = 0; i < 8; i++) { 343 mat3.setValue(i / 3, i % 3, i); 344 comp.setRotation(mat3); 345 assertFalse(trans.equals(comp)); 346 assertFalse(trans.strictEquals(comp)); 347 } 348 // test translation 349 trans.setRotation(Matrix3.IDENTITY); 350 comp.setRotation(Matrix3.IDENTITY); 351 comp.setTranslation(1, -1, -1); 352 assertFalse(trans.equals(comp)); 353 assertFalse(trans.strictEquals(comp)); 354 comp.setTranslation(1, 2, -1); 355 assertFalse(trans.equals(comp)); 356 assertFalse(trans.strictEquals(comp)); 357 comp.setTranslation(1, 2, 3); 358 assertFalse(trans.equals(comp)); 359 assertFalse(trans.strictEquals(comp)); 360 361 // test scale 362 comp.setScale(1, -1, -1); 363 assertFalse(trans.equals(comp)); 364 assertFalse(trans.strictEquals(comp)); 365 comp.setScale(1, 2, -1); 366 assertFalse(trans.equals(comp)); 367 assertFalse(trans.strictEquals(comp)); 368 comp.setScale(1, 2, 3); 369 assertTrue(trans.equals(comp)); 370 assertTrue(trans.strictEquals(comp)); 371 } 372 373 @Test 374 public void testSimpleHash() { 375 // Just a simple sanity check. 376 final Transform trans1 = new Transform().setTranslation(1, 2, 3); 377 final Transform trans2 = new Transform().setTranslation(1, 2, 3); 378 final Transform trans3 = new Transform().setTranslation(1, 2, 0); 379 380 assertTrue(trans1.hashCode() == trans2.hashCode()); 381 assertTrue(trans1.hashCode() != trans3.hashCode()); 382 } 383 384 @Test 385 public void testGLApplyMatrix() { 386 final Transform trans = new Transform(); 387 388 // non-rotational 389 trans.setRotation(new Matrix3(0, 1, 2, 3, 4, 5, 6, 7, 8)); 390 trans.setTranslation(10, 11, 12); 391 final DoubleBuffer db = DoubleBuffer.allocate(16); 392 trans.getGLApplyMatrix(db); 393 for (final double val : new double[] { 0, 3, 6, 0, 1, 4, 7, 0, 2, 5, 8, 0, 10, 11, 12, 1 }) { 394 assertTrue(val == db.get()); 395 } 396 final FloatBuffer fb = FloatBuffer.allocate(16); 397 trans.getGLApplyMatrix(fb); 398 for (final float val : new float[] { 0, 3, 6, 0, 1, 4, 7, 0, 2, 5, 8, 0, 10, 11, 12, 1 }) { 399 assertTrue(val == fb.get()); 400 } 401 402 // rotational 403 final double a = MathUtils.QUARTER_PI; 404 trans.setRotation(new Matrix3().applyRotationY(a)); 405 trans.setTranslation(10, 11, 12); 406 trans.setScale(2, 3, 4); 407 db.rewind(); 408 trans.getGLApplyMatrix(db); 409 for (final double val : new double[] { 2 * Math.cos(a), 2 * 0, 2 * -Math.sin(a), 0, // 410 3 * 0, 3 * 1, 3 * 0, 0, // 411 4 * Math.sin(a), 4 * 0, 4 * Math.cos(a), 0, // 412 10, 11, 12, 1 }) { 413 assertTrue(val == db.get()); 414 } 415 fb.rewind(); 416 trans.getGLApplyMatrix(fb); 417 for (final float val : new float[] { (float) (2 * Math.cos(a)), 2 * 0, (float) (2 * -Math.sin(a)), 0, // 418 3 * 0, 3 * 1, 3 * 0, 0, // 419 (float) (4 * Math.sin(a)), 4 * 0, (float) (4 * Math.cos(a)), 0, // 420 10, 11, 12, 1 }) { 421 assertTrue(val == fb.get()); 422 } 423 } 424}