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 org.junit.Test; 016 017import com.ardor3d.math.type.ReadOnlyVector3; 018 019public class TestQuaternion { 020 021 @Test 022 public void testGetSet() { 023 final Quaternion quat1 = new Quaternion(); 024 assertEquals(Quaternion.IDENTITY, quat1); 025 assertTrue(quat1.isIdentity()); 026 027 quat1.setX(1); 028 assertTrue(quat1.getX() == 1.0); 029 quat1.setX(Double.POSITIVE_INFINITY); 030 assertTrue(quat1.getX() == Double.POSITIVE_INFINITY); 031 quat1.setX(Double.NEGATIVE_INFINITY); 032 assertTrue(quat1.getX() == Double.NEGATIVE_INFINITY); 033 034 quat1.setY(1); 035 assertTrue(quat1.getY() == 1.0); 036 quat1.setY(Double.POSITIVE_INFINITY); 037 assertTrue(quat1.getY() == Double.POSITIVE_INFINITY); 038 quat1.setY(Double.NEGATIVE_INFINITY); 039 assertTrue(quat1.getY() == Double.NEGATIVE_INFINITY); 040 041 quat1.setZ(1); 042 assertTrue(quat1.getZ() == 1.0); 043 quat1.setZ(Double.POSITIVE_INFINITY); 044 assertTrue(quat1.getZ() == Double.POSITIVE_INFINITY); 045 quat1.setZ(Double.NEGATIVE_INFINITY); 046 assertTrue(quat1.getZ() == Double.NEGATIVE_INFINITY); 047 048 quat1.setW(1); 049 assertTrue(quat1.getW() == 1.0); 050 quat1.setW(Double.POSITIVE_INFINITY); 051 assertTrue(quat1.getW() == Double.POSITIVE_INFINITY); 052 quat1.setW(Double.NEGATIVE_INFINITY); 053 assertTrue(quat1.getW() == Double.NEGATIVE_INFINITY); 054 055 quat1.set(Math.PI, Math.PI, Math.PI, Math.PI); 056 assertTrue(quat1.getXf() == (float) Math.PI); 057 assertTrue(quat1.getYf() == (float) Math.PI); 058 assertTrue(quat1.getZf() == (float) Math.PI); 059 assertTrue(quat1.getWf() == (float) Math.PI); 060 061 final Quaternion quat2 = new Quaternion(); 062 quat2.set(quat1); 063 assertEquals(quat1, quat2); 064 } 065 066 @Test 067 public void testToArray() { 068 final Quaternion quat1 = new Quaternion(); 069 quat1.set(Math.PI, Double.MAX_VALUE, 42, -1); 070 final double[] array = quat1.toArray(null); 071 final double[] array2 = quat1.toArray(new double[4]); 072 assertNotNull(array); 073 assertTrue(array.length == 4); 074 assertTrue(array[0] == Math.PI); 075 assertTrue(array[1] == Double.MAX_VALUE); 076 assertTrue(array[2] == 42); 077 assertTrue(array[3] == -1); 078 assertNotNull(array2); 079 assertTrue(array2.length == 4); 080 assertTrue(array2[0] == Math.PI); 081 assertTrue(array2[1] == Double.MAX_VALUE); 082 assertTrue(array2[2] == 42); 083 assertTrue(array2[3] == -1); 084 } 085 086 @Test(expected = ArrayIndexOutOfBoundsException.class) 087 public void testBadArray() { 088 final Quaternion quat = new Quaternion(); 089 quat.toArray(new double[2]); 090 } 091 092 @Test(expected = ArrayIndexOutOfBoundsException.class) 093 public void testBadAxesArray() { 094 final Quaternion quat = new Quaternion(); 095 quat.toAxes(new Vector3[2]); 096 } 097 098 @Test(expected = ArrayIndexOutOfBoundsException.class) 099 public void testBadEuler1() { 100 new Quaternion().fromEulerAngles(new double[2]); 101 } 102 103 @Test(expected = ArrayIndexOutOfBoundsException.class) 104 public void testBadEuler2() { 105 final Quaternion quat = new Quaternion(); 106 quat.toEulerAngles(new double[2]); 107 } 108 109 @Test 110 public void testEulerAngles() { 111 final Quaternion quat = new Quaternion().fromEulerAngles(new double[] { MathUtils.HALF_PI, 0, 0 }); 112 assertTrue(1.0 == quat.magnitude()); 113 assertTrue(Math.abs(Vector3.NEG_UNIT_Z.distance(quat.apply(Vector3.UNIT_X, null))) <= MathUtils.EPSILON); 114 115 quat.fromEulerAngles(0, -MathUtils.HALF_PI, 0); 116 assertTrue(1.0 == quat.magnitude()); 117 assertTrue(Math.abs(Vector3.NEG_UNIT_Y.distance(quat.apply(Vector3.UNIT_X, null))) <= MathUtils.EPSILON); 118 119 quat.fromEulerAngles(0, 0, MathUtils.HALF_PI); 120 assertTrue(1.0 == quat.magnitude()); 121 assertTrue(Math.abs(Vector3.UNIT_Z.distance(quat.apply(Vector3.UNIT_Y, null))) <= MathUtils.EPSILON); 122 123 quat.fromEulerAngles(0, MathUtils.HALF_PI, 0); 124 double[] angles = quat.toEulerAngles(null); 125 final Quaternion quat2 = new Quaternion().fromEulerAngles(angles); 126 assertEquals(quat, quat2); 127 quat.fromEulerAngles(0, -MathUtils.HALF_PI, 0); 128 angles = quat.toEulerAngles(null); 129 quat2.fromEulerAngles(angles); 130 assertEquals(quat, quat2); 131 quat.fromEulerAngles(0, 0, MathUtils.HALF_PI); 132 angles = quat.toEulerAngles(null); 133 quat2.fromEulerAngles(angles); 134 assertEquals(quat, quat2); 135 } 136 137 @Test 138 public void testMatrix3() { 139 double a = MathUtils.HALF_PI; 140 final Quaternion quat = new Quaternion(); 141 quat.fromRotationMatrix( // 142 1, 0, 0, // 143 0, Math.cos(a), -Math.sin(a), // 144 0, Math.sin(a), Math.cos(a)); 145 146 assertTrue(Math.abs(Vector3.UNIT_Z.distance(quat.apply(Vector3.UNIT_Y, null))) <= MathUtils.EPSILON); 147 final Matrix3 mat = quat.toRotationMatrix((Matrix3) null); 148 assertTrue(Math.abs(quat.apply(Vector3.NEG_ONE, null).distance(mat.applyPost(Vector3.NEG_ONE, null))) <= MathUtils.EPSILON); 149 150 a = MathUtils.PI; 151 quat.fromRotationMatrix( // 152 1, 0, 0, // 153 0, Math.cos(a), -Math.sin(a), // 154 0, Math.sin(a), Math.cos(a)); 155 156 assertTrue(Math.abs(Vector3.NEG_UNIT_Y.distance(quat.apply(Vector3.UNIT_Y, null))) <= MathUtils.EPSILON); 157 quat.toRotationMatrix(mat); 158 assertTrue(Math.abs(quat.apply(Vector3.ONE, null).distance(mat.applyPost(Vector3.ONE, null))) <= MathUtils.EPSILON); 159 160 quat.set(0, 0, 0, 0); 161 assertEquals(Matrix3.IDENTITY, quat.toRotationMatrix((Matrix3) null)); 162 163 a = MathUtils.PI; 164 quat.fromRotationMatrix( // 165 Math.cos(a), 0, Math.sin(a), // 166 0, 1, 0, // 167 -Math.sin(a), 0, Math.cos(a)); 168 169 assertTrue(Math.abs(Vector3.NEG_UNIT_X.distance(quat.apply(Vector3.UNIT_X, null))) <= MathUtils.EPSILON); 170 final Matrix4 mat4 = quat.toRotationMatrix((Matrix4) null); 171 assertTrue(Math.abs(quat.apply(Vector3.NEG_ONE, null).distance(mat4.applyPostVector(Vector3.NEG_ONE, null))) <= MathUtils.EPSILON); 172 173 a = MathUtils.PI; 174 quat.fromRotationMatrix(new Matrix3(// 175 Math.cos(a), -Math.sin(a), 0, // 176 Math.sin(a), Math.cos(a), 0, // 177 0, 0, 1)); 178 179 assertTrue(Math.abs(Vector3.NEG_UNIT_X.distance(quat.apply(Vector3.UNIT_X, null))) <= MathUtils.EPSILON); 180 quat.toRotationMatrix(mat4); 181 assertTrue(Math.abs(quat.apply(Vector3.ONE, null).distance(mat4.applyPostVector(Vector3.ONE, null))) <= MathUtils.EPSILON); 182 183 quat.set(0, 0, 0, 0); 184 assertEquals(Matrix4.IDENTITY, quat.toRotationMatrix((Matrix4) null)); 185 } 186 187 @Test 188 public void testRotations() { 189 final double a = MathUtils.QUARTER_PI; 190 final Quaternion quat = new Quaternion().fromRotationMatrix(new Matrix3(// 191 Math.cos(a), -Math.sin(a), 0, // 192 Math.sin(a), Math.cos(a), 0, // 193 0, 0, 1)); 194 final Vector3 column = quat.getRotationColumn(0, null); 195 assertTrue(Math.abs(new Vector3(Math.cos(a), Math.sin(a), 0).distance(column)) <= MathUtils.EPSILON); 196 quat.getRotationColumn(1, column); 197 assertTrue(Math.abs(new Vector3(-Math.sin(a), Math.sin(a), 0).distance(column)) <= MathUtils.EPSILON); 198 quat.getRotationColumn(2, column); 199 assertTrue(Math.abs(new Vector3(0, 0, 1).distance(column)) <= MathUtils.EPSILON); 200 201 quat.set(0, 0, 0, 0); 202 assertEquals(Vector3.UNIT_X, quat.getRotationColumn(0, null)); 203 204 // Try a new way with new angles... 205 quat.fromEulerAngles(MathUtils.QUARTER_PI, MathUtils.PI, MathUtils.HALF_PI); 206 final Vector3 rotated = new Vector3(1, 1, 1); 207 quat.apply(rotated, rotated); 208 209 // expected 210 final Vector3 expected = new Vector3(1, 1, 1); 211 final Quaternion worker = new Quaternion(); 212 // put together matrix, then apply to vector, so YZX 213 worker.applyRotationY(MathUtils.QUARTER_PI); 214 worker.applyRotationZ(MathUtils.PI); 215 worker.applyRotationX(MathUtils.HALF_PI); 216 worker.apply(expected, expected); 217 218 // test how close it came out 219 assertTrue(rotated.distance(expected) <= Quaternion.ALLOWED_DEVIANCE); 220 221 // test axis rotation methods against general purpose 222 // X AXIS 223 expected.set(1, 1, 1); 224 rotated.set(1, 1, 1); 225 worker.setIdentity().applyRotationX(MathUtils.QUARTER_PI).apply(expected, expected); 226 worker.setIdentity().applyRotation(MathUtils.QUARTER_PI, 1, 0, 0).apply(rotated, rotated); 227 assertTrue(rotated.distance(expected) <= MathUtils.EPSILON); 228 229 // Y AXIS 230 expected.set(1, 1, 1); 231 rotated.set(1, 1, 1); 232 worker.setIdentity().applyRotationY(MathUtils.QUARTER_PI).apply(expected, expected); 233 worker.setIdentity().applyRotation(MathUtils.QUARTER_PI, 0, 1, 0).apply(rotated, rotated); 234 assertTrue(rotated.distance(expected) <= MathUtils.EPSILON); 235 236 // Z AXIS 237 expected.set(1, 1, 1); 238 rotated.set(1, 1, 1); 239 worker.setIdentity().applyRotationZ(MathUtils.QUARTER_PI).apply(expected, expected); 240 worker.setIdentity().applyRotation(MathUtils.QUARTER_PI, 0, 0, 1).apply(rotated, rotated); 241 assertTrue(rotated.distance(expected) <= MathUtils.EPSILON); 242 243 quat.set(worker); 244 worker.applyRotation(0, 0, 0, 0); 245 assertEquals(quat, worker); 246 } 247 248 @Test(expected = IllegalArgumentException.class) 249 public void testBadRotationColumn1() { 250 new Quaternion().getRotationColumn(-1, null); 251 } 252 253 @Test(expected = IllegalArgumentException.class) 254 public void testBadRotationColumn2() { 255 new Quaternion().getRotationColumn(4, null); 256 } 257 258 @Test 259 public void testAngleAxis() { 260 final Quaternion quat = new Quaternion().fromAngleAxis(MathUtils.HALF_PI, new Vector3(2, 0, 0)); 261 final Quaternion quat2 = new Quaternion().fromAngleNormalAxis(MathUtils.HALF_PI, new Vector3(1, 0, 0)); 262 263 assertEquals(quat2, quat); 264 assertTrue(1 - quat.magnitude() <= MathUtils.EPSILON); 265 266 assertEquals(quat.apply(Vector3.ONE, null), quat2.apply(Vector3.ONE, null)); 267 assertTrue(Math.abs(new Vector3(0, -1, 0).distance(quat.apply(new Vector3(0, 0, 1), null))) <= MathUtils.EPSILON); 268 269 assertEquals(Quaternion.IDENTITY, 270 new Quaternion(1, 2, 3, 4).fromAngleAxis(MathUtils.HALF_PI, new Vector3(0, 0, 0))); 271 272 final Vector3 axisStore = new Vector3(); 273 double angle = quat.toAngleAxis(axisStore); 274 assertEquals(quat, new Quaternion().fromAngleAxis(angle, axisStore)); 275 276 quat.set(0, 0, 0, 0); 277 angle = quat.toAngleAxis(axisStore); 278 assertTrue(0.0 == angle); 279 assertEquals(Vector3.UNIT_X, axisStore); 280 } 281 282 @Test 283 public void testFromVectorToVector() { 284 final Quaternion quat = new Quaternion().fromVectorToVector(Vector3.UNIT_Z, Vector3.UNIT_X); 285 assertEquals(new Quaternion().fromAngleAxis(MathUtils.HALF_PI, Vector3.UNIT_Y), quat); 286 287 quat.fromVectorToVector(Vector3.UNIT_Z, Vector3.NEG_UNIT_Z); 288 assertTrue(Math.abs(new Vector3(0, 0, -1).distance(quat.apply(new Vector3(0, 0, 1), null))) <= Quaternion.ALLOWED_DEVIANCE); 289 290 quat.fromVectorToVector(Vector3.UNIT_X, Vector3.NEG_UNIT_X); 291 assertTrue(Math.abs(new Vector3(-1, 0, 0).distance(quat.apply(new Vector3(1, 0, 0), null))) <= Quaternion.ALLOWED_DEVIANCE); 292 293 quat.fromVectorToVector(Vector3.UNIT_Y, Vector3.NEG_UNIT_Y); 294 assertTrue(Math.abs(new Vector3(0, -1, 0).distance(quat.apply(new Vector3(0, 1, 0), null))) <= Quaternion.ALLOWED_DEVIANCE); 295 296 quat.fromVectorToVector(Vector3.ONE, Vector3.NEG_ONE); 297 assertTrue(Math.abs(new Vector3(-1, -1, -1).distance(quat.apply(new Vector3(1, 1, 1), null))) <= Quaternion.ALLOWED_DEVIANCE); 298 299 quat.fromVectorToVector(Vector3.ZERO, Vector3.ZERO); 300 assertEquals(Quaternion.IDENTITY, quat); 301 } 302 303 @Test 304 public void testNormalize() { 305 final Quaternion quat = new Quaternion(0, 1, 2, 3); 306 final Quaternion quat2 = quat.normalize(null); 307 assertEquals(quat2, quat.normalizeLocal()); 308 assertTrue(Math.abs(1 - quat.magnitude()) <= MathUtils.EPSILON); 309 assertTrue(Math.abs(1 - quat2.magnitude()) <= MathUtils.EPSILON); 310 } 311 312 @Test 313 public void testApplyToZero() { 314 assertEquals(Vector3.ZERO, new Quaternion().apply(new Vector3(0, 0, 0), null)); 315 } 316 317 @Test 318 public void testInvert() { 319 final Quaternion quat1 = new Quaternion(0, 1, 2, 3); 320 final Quaternion quat2 = quat1.invert(null); 321 assertEquals(Quaternion.IDENTITY, quat1.multiply(quat2, null)); 322 assertEquals(quat1, quat2.invert(new Quaternion())); 323 assertEquals(quat1, quat2.invertLocal()); 324 325 // normalized version 326 quat1.fromAngleAxis(MathUtils.QUARTER_PI, Vector3.UNIT_Y); 327 quat1.invert(quat2); 328 assertEquals(Quaternion.IDENTITY, quat1.multiply(quat2, null)); 329 assertEquals(quat1, quat2.invert(new Quaternion())); 330 assertEquals(quat1, quat2.invertLocal()); 331 332 // conjugate check 333 assertEquals(new Quaternion(-1, -2, -3, 4), new Quaternion(1, 2, 3, 4).conjugate(null)); 334 } 335 336 @Test 337 public void testAddSubtract() { 338 final Quaternion quat1 = new Quaternion(0, 1, 2, 3); 339 final Quaternion quat2 = new Quaternion(1, 1, 1, 1); 340 assertEquals(new Quaternion(1, 2, 3, 4), quat1.add(quat2, null)); 341 assertEquals(new Quaternion(1, 2, 3, 4), quat1.add(quat2, new Quaternion())); 342 assertEquals(new Quaternion(1, 2, 3, 4), quat1.addLocal(quat2)); 343 344 quat1.set(0, 1, 2, 3); 345 quat2.set(1, 1, 1, 1); 346 assertEquals(new Quaternion(-1, 0, 1, 2), quat1.subtract(quat2, null)); 347 assertEquals(new Quaternion(-1, 0, 1, 2), quat1.subtract(quat2, new Quaternion())); 348 assertEquals(new Quaternion(-1, 0, 1, 2), quat1.subtractLocal(quat2)); 349 } 350 351 @Test 352 public void testMultiply() { 353 final Quaternion quat1 = new Quaternion(0.5, 1, 2, 3); 354 final Quaternion quat2 = new Quaternion(); 355 assertEquals(new Quaternion(1, 2, 4, 6), quat1.multiply(2, null)); 356 assertEquals(new Quaternion(2, 4, 8, 12), quat1.multiply(4, quat2)); 357 assertEquals(new Quaternion(1, 2, 4, 6), quat1.multiplyLocal(2)); 358 359 quat1.fromAngleNormalAxis(MathUtils.QUARTER_PI, Vector3.UNIT_Y); 360 quat1.multiply(quat1, quat2); 361 362 final ReadOnlyVector3 vec = Vector3.UNIT_Z; 363 assertTrue(Math.abs(Vector3.UNIT_X.distance(quat2.apply(vec, null))) <= Quaternion.ALLOWED_DEVIANCE); 364 quat1.multiplyLocal(quat1.getX(), quat1.getY(), quat1.getZ(), quat1.getW()); 365 assertTrue(Math.abs(Vector3.UNIT_X.distance(quat1.apply(vec, null))) <= Quaternion.ALLOWED_DEVIANCE); 366 quat2.fromAngleNormalAxis(MathUtils.HALF_PI, Vector3.UNIT_Y); 367 quat1.multiplyLocal(quat2); 368 assertTrue(Math.abs(Vector3.NEG_UNIT_Z.distance(quat1.apply(vec, null))) <= Quaternion.ALLOWED_DEVIANCE); 369 370 quat1.multiplyLocal(new Matrix3().applyRotationY(MathUtils.HALF_PI)); 371 assertTrue(Math.abs(Vector3.NEG_UNIT_X.distance(quat1.apply(vec, null))) <= Quaternion.ALLOWED_DEVIANCE); 372 } 373 374 @Test 375 public void testAxes() { 376 final Matrix3 rot = new Matrix3().applyRotationX(MathUtils.QUARTER_PI).applyRotationY(MathUtils.HALF_PI); 377 final Quaternion quat1 = new Quaternion().fromAxes(rot.getColumn(0, null), rot.getColumn(1, null), 378 rot.getColumn(2, null)); 379 final Quaternion quat2 = new Quaternion().fromRotationMatrix(rot); 380 assertEquals(quat2, quat1); 381 382 final Vector3[] axes = quat1.toAxes(new Vector3[3]); 383 quat1.fromAxes(axes[0], axes[1], axes[2]); 384 assertEquals(quat2, quat1); 385 } 386 387 @Test 388 public void testSlerp() { 389 final Quaternion quat = new Quaternion(); 390 final Quaternion quat2 = new Quaternion().applyRotationY(MathUtils.HALF_PI); 391 final Quaternion store = quat.slerp(quat2, .5, null); 392 assertTrue(Math.abs(new Vector3(Math.sin(MathUtils.QUARTER_PI), 0, Math.sin(MathUtils.QUARTER_PI)) 393 .distance(store.apply(Vector3.UNIT_Z, null))) <= Quaternion.ALLOWED_DEVIANCE); 394 395 // delta == 100% 396 quat2.setIdentity().applyRotationZ(MathUtils.PI); 397 quat.slerp(quat2, 1.0, store); 398 assertTrue(Math.abs(new Vector3(-1, 0, 0).distance(store.apply(Vector3.UNIT_X, null))) <= Quaternion.ALLOWED_DEVIANCE); 399 400 quat2.setIdentity().applyRotationZ(MathUtils.PI); 401 quat.slerp(quat2, .5, store); 402 assertTrue(Math.abs(new Vector3(0, 1, 0).distance(store.apply(Vector3.UNIT_X, null))) <= Quaternion.ALLOWED_DEVIANCE); 403 404 // delta == 0% 405 quat2.setIdentity().applyRotationZ(MathUtils.PI); 406 quat.slerp(quat2, 0, store); 407 assertTrue(Math.abs(new Vector3(1, 0, 0).distance(store.apply(Vector3.UNIT_X, null))) <= Quaternion.ALLOWED_DEVIANCE); 408 409 // a==b 410 quat2.setIdentity(); 411 quat.slerp(quat2, 0.25, store); 412 assertTrue(Math.abs(new Vector3(1, 0, 0).distance(store.apply(Vector3.UNIT_X, null))) <= Quaternion.ALLOWED_DEVIANCE); 413 414 // negative dot product 415 quat.setIdentity().applyRotationX(-2 * MathUtils.HALF_PI); 416 quat2.setIdentity().applyRotationX(MathUtils.HALF_PI); 417 quat.slerp(quat2, 0.5, store); 418 assertTrue(Math.abs(new Vector3(0, -Math.sin(MathUtils.QUARTER_PI), Math.sin(MathUtils.QUARTER_PI)) 419 .distance(store.apply(Vector3.UNIT_Y, null))) <= Quaternion.ALLOWED_DEVIANCE); 420 421 // LOCAL 422 // delta == 100% 423 quat2.setIdentity().applyRotationX(MathUtils.PI); 424 quat.slerpLocal(quat2, 1.0); 425 assertTrue(Math.abs(new Vector3(0, -1, 0).distance(quat.apply(Vector3.UNIT_Y, null))) <= Quaternion.ALLOWED_DEVIANCE); 426 427 quat.setIdentity(); 428 quat.slerpLocal(quat2, .5); 429 assertTrue(Math.abs(new Vector3(0, 0, 1).distance(quat.apply(Vector3.UNIT_Y, null))) <= Quaternion.ALLOWED_DEVIANCE); 430 431 // delta == 0% 432 quat.setIdentity(); 433 quat.slerpLocal(quat2, 0); 434 assertTrue(Math.abs(new Vector3(0, 1, 0).distance(quat.apply(Vector3.UNIT_Y, null))) <= Quaternion.ALLOWED_DEVIANCE); 435 436 // a==b 437 quat.setIdentity(); 438 quat2.setIdentity(); 439 quat.slerpLocal(quat2, 0.25); 440 assertTrue(Math.abs(new Vector3(0, 1, 0).distance(quat.apply(Vector3.UNIT_Y, null))) <= Quaternion.ALLOWED_DEVIANCE); 441 442 // negative dot product 443 quat.setIdentity().applyRotationX(-2 * MathUtils.HALF_PI); 444 quat2.setIdentity().applyRotationX(MathUtils.HALF_PI); 445 quat.slerpLocal(quat2, 0.5); 446 assertTrue(Math.abs(new Vector3(0, -Math.sin(MathUtils.QUARTER_PI), Math.sin(MathUtils.QUARTER_PI)) 447 .distance(quat.apply(Vector3.UNIT_Y, null))) <= Quaternion.ALLOWED_DEVIANCE); 448 } 449 450 @Test 451 public void testLookAt() { 452 final Vector3 direction = new Vector3(-1, 0, 0); 453 final Quaternion quat = new Quaternion().lookAt(direction, Vector3.UNIT_Y); 454 assertTrue(Math.abs(direction.distance(quat.apply(Vector3.UNIT_Z, null))) <= Quaternion.ALLOWED_DEVIANCE); 455 456 direction.set(1, 1, 1).normalizeLocal(); 457 quat.lookAt(direction, Vector3.UNIT_Y); 458 assertTrue(Math.abs(direction.distance(quat.apply(Vector3.UNIT_Z, null))) <= Quaternion.ALLOWED_DEVIANCE); 459 460 direction.set(-1, 2, -1).normalizeLocal(); 461 quat.lookAt(direction, Vector3.UNIT_Y); 462 assertTrue(Math.abs(direction.distance(quat.apply(Vector3.UNIT_Z, null))) <= Quaternion.ALLOWED_DEVIANCE); 463 } 464 465 @Test 466 public void testDot() { 467 final Quaternion quat = new Quaternion(7, 2, 5, -1); 468 assertTrue(35.0 == quat.dot(3, 1, 2, -2)); 469 470 assertTrue(-11.0 == quat.dot(new Quaternion(-1, 1, -1, 1))); 471 } 472 473 @Test 474 public void testClone() { 475 final Quaternion quat1 = new Quaternion(); 476 final Quaternion quat2 = quat1.clone(); 477 assertEquals(quat1, quat2); 478 assertNotSame(quat1, quat2); 479 } 480 481 @Test 482 public void testValid() { 483 final Quaternion quat = new Quaternion(); 484 assertTrue(Quaternion.isValid(quat)); 485 486 quat.set(Double.NaN, 0, 0, 0); 487 assertFalse(Quaternion.isValid(quat)); 488 quat.set(0, Double.NaN, 0, 0); 489 assertFalse(Quaternion.isValid(quat)); 490 quat.set(0, 0, Double.NaN, 0); 491 assertFalse(Quaternion.isValid(quat)); 492 quat.set(0, 0, 0, Double.NaN); 493 assertFalse(Quaternion.isValid(quat)); 494 495 quat.set(Double.NEGATIVE_INFINITY, 0, 0, 0); 496 assertFalse(Quaternion.isValid(quat)); 497 quat.set(0, Double.NEGATIVE_INFINITY, 0, 0); 498 assertFalse(Quaternion.isValid(quat)); 499 quat.set(0, 0, Double.NEGATIVE_INFINITY, 0); 500 assertFalse(Quaternion.isValid(quat)); 501 quat.set(0, 0, 0, Double.NEGATIVE_INFINITY); 502 assertFalse(Quaternion.isValid(quat)); 503 504 quat.setIdentity(); 505 assertTrue(Quaternion.isValid(quat)); 506 507 assertFalse(Quaternion.isValid(null)); 508 509 // couple of equals validity tests 510 assertEquals(quat, quat); 511 assertTrue(quat.strictEquals(quat)); 512 assertFalse(quat.equals(null)); 513 assertFalse(quat.strictEquals(null)); 514 assertFalse(quat.equals(new Vector2())); 515 assertFalse(quat.strictEquals(new Vector2())); 516 517 // throw in a couple pool accesses for coverage 518 final Quaternion quatTemp = Quaternion.fetchTempInstance(); 519 quatTemp.set(quat); 520 assertEquals(quat, quatTemp); 521 assertNotSame(quat, quatTemp); 522 Quaternion.releaseTempInstance(quatTemp); 523 524 // cover more of equals 525 quat.set(0, 1, 2, 3); 526 final Quaternion comp = new Quaternion(-1, -1, -1, -1); 527 assertFalse(quat.equals(comp)); 528 assertFalse(quat.strictEquals(comp)); 529 comp.setX(0); 530 assertFalse(quat.equals(comp)); 531 assertFalse(quat.strictEquals(comp)); 532 comp.setY(1); 533 assertFalse(quat.equals(comp)); 534 assertFalse(quat.strictEquals(comp)); 535 comp.setZ(2); 536 assertFalse(quat.equals(comp)); 537 assertFalse(quat.strictEquals(comp)); 538 comp.setW(3); 539 assertEquals(quat, comp); 540 assertTrue(quat.strictEquals(comp)); 541 } 542 543 @Test 544 public void testSimpleHash() { 545 // Just a simple sanity check. 546 final Quaternion quat1 = new Quaternion(1, 2, 3, 4); 547 final Quaternion quat2 = new Quaternion(1, 2, 3, 4); 548 final Quaternion quat3 = new Quaternion(1, 2, 3, 0); 549 550 assertTrue(quat1.hashCode() == quat2.hashCode()); 551 assertTrue(quat1.hashCode() != quat3.hashCode()); 552 } 553 554}