1 module tests.quaterniond_test; 2 3 import Math = math; 4 import quaternion_d; 5 import matrix_4d; 6 import vector_3d; 7 import tests.dunit_tests; 8 import std.stdio; 9 10 /* 11 * The MIT License 12 * 13 * Copyright (c) 2015-2021 JOML. 14 %$#% Translated by jordan4ibanez 15 * 16 * Permission is hereby granted, free of charge, to any person obtaining a copy 17 * of this software and associated documentation files (the "Software"), to deal 18 * in the Software without restriction, including without limitation the rights 19 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 20 * copies of the Software, and to permit persons to whom the Software is 21 * furnished to do so, subject to the following conditions: 22 * 23 * The above copyright notice and this permission notice shall be included in 24 * all copies or substantial portions of the Software. 25 * 26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 31 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 32 * THE SOFTWARE. 33 */ 34 35 36 /** 37 * Test class for {@link Quaterniond}. 38 * @author Sebastian Fellner 39 */ 40 unittest { 41 42 writeln("\nSTARING QUATERNIOND TESTING\n"); 43 44 // testMulQuaternionDQuaternionDQuaternionD 45 { 46 // Multiplication with the identity quaternion should change nothing 47 Quaterniond testQuat = Quaterniond(1, 23.3, -7.57, 2.1); 48 Quaterniond identityQuat = Quaterniond().identity(); 49 Quaterniond resultQuat = Quaterniond(); 50 51 testQuat.mul(identityQuat, resultQuat); 52 assertTrue(quatEqual(testQuat, resultQuat, MANY_OPS_AROUND_ZERO_PRECISION_DOUBLE)); 53 54 identityQuat.mul(testQuat, resultQuat); 55 assertTrue(quatEqual(testQuat, resultQuat, STANDARD_AROUND_ZERO_PRECISION_DOUBLE)); 56 57 // Multiplication with conjugate should give (0, 0, 0, dot(this, this)) 58 Quaterniond conjugate = Quaterniond(); 59 testQuat.conjugate(conjugate); 60 testQuat.mul(conjugate, resultQuat); 61 62 Quaterniond wantedResultQuat = Quaterniond(0, 0, 0, testQuat.dot(testQuat)); 63 assertTrue(quatEqual(resultQuat, wantedResultQuat, MANY_OPS_AROUND_ZERO_PRECISION_DOUBLE)); 64 } 65 66 // testRotationXYZ 67 { 68 Quaterniond v = Quaterniond().rotationXYZ(0.12f, 0.521f, 0.951f); 69 Matrix4d m = Matrix4d().rotateXYZ(0.12f, 0.521f, 0.951f); 70 Matrix4d n = Matrix4d().set(v); 71 assertMatrix4dEquals(m, n, 1E-6f); 72 } 73 74 // testRotationZYX 75 { 76 Quaterniond v = Quaterniond().rotationZYX(0.12f, 0.521f, 0.951f); 77 Matrix4d m = Matrix4d().rotateZYX(0.12f, 0.521f, 0.951f); 78 Matrix4d n = Matrix4d().set(v); 79 assertMatrix4dEquals(m, n, 1E-6f); 80 } 81 82 // testRotationYXZ 83 { 84 Quaterniond v = Quaterniond().rotationYXZ(0.12f, 0.521f, 0.951f); 85 Matrix4d m = Matrix4d().rotationYXZ(0.12f, 0.521f, 0.951f); 86 Matrix4d n = Matrix4d().set(v); 87 assertMatrix4dEquals(m, n, 1E-6f); 88 } 89 90 // testRotateXYZ 91 { 92 Quaterniond v = Quaterniond().rotateXYZ(0.12f, 0.521f, 0.951f); 93 Matrix4d m = Matrix4d().rotateXYZ(0.12f, 0.521f, 0.951f); 94 Matrix4d n = Matrix4d().set(v); 95 assertMatrix4dEquals(m, n, 1E-6f); 96 } 97 98 // testRotateXYZ 99 { 100 Quaterniond v = Quaterniond().rotateZYX(0.12f, 0.521f, 0.951f); 101 Matrix4d m = Matrix4d().rotateZYX(0.12f, 0.521f, 0.951f); 102 Matrix4d n = Matrix4d().set(v); 103 assertMatrix4dEquals(m, n, 1E-6f); 104 } 105 106 // testRotateYXZ 107 { 108 Quaterniond v = Quaterniond().rotateYXZ(0.12f, 0.521f, 0.951f); 109 Matrix4d m = Matrix4d().rotateYXZ(0.12f, 0.521f, 0.951f); 110 Matrix4d n = Matrix4d().set(v); 111 assertMatrix4dEquals(m, n, 1E-6f); 112 } 113 114 // testRotateToReturnsDestination 115 { 116 Quaterniond rotation = Quaterniond(); 117 Quaterniond destination = Quaterniond(); 118 Quaterniond result = rotation.rotateTo(0, 1, 0, 0, 1, 0, destination); 119 assertEquals(destination, result); // Assert same? 120 } 121 122 // testFromAxisAngle 123 { 124 Vector3d axis = Vector3d(1.0, 0.0, 0.0); 125 double angleDeg = 45.0; 126 double angleRad = Math.toRadians(angleDeg); 127 Quaterniond fromRad1 = Quaterniond().fromAxisAngleRad(axis, angleRad); 128 Quaterniond fromRad2 = Quaterniond().fromAxisAngleRad(axis.x, axis.y, axis.z, angleRad); 129 Quaterniond fromDeg = Quaterniond().fromAxisAngleDeg(axis, angleDeg); 130 assertEquals(fromRad1, fromRad2); 131 assertEquals(fromRad2, fromDeg); 132 } 133 134 // testGetEulerAnglesXYZ 135 { 136 int failure = 0; 137 int N = 3_000_000; 138 for (int i = 0; i <= N; i++) { 139 if (i % 100_000 == 0) { 140 // This is here because it takes a long time 141 writeln("Batch test: ", (cast(double)i / 3_000_000.0) * 100, "%" ); 142 } 143 double x = (Math.random() * 2.0 - 1.0) * Math.PI; 144 double y = (Math.random() * 2.0 - 1.0) * Math.PI; 145 double z = (Math.random() * 2.0 - 1.0) * Math.PI; 146 Quaterniond p = Quaterniond().rotateXYZ(x, y, z); 147 Vector3d a = p.getEulerAnglesXYZ(Vector3d()); 148 Quaterniond q = Quaterniond().rotateX(a.x).rotateY(a.y).rotateZ(a.z); 149 Vector3d v = Vector3d(Math.random()*2-1, Math.random()*2-1, Math.random()*2-1); 150 Vector3d testunit = Vector3d(); 151 Vector3d t1 = p.transform(v, testunit); 152 Vector3d t2 = q.transform(v, testunit); 153 if (!t1.equals(t2, 1E-10f)) 154 failure++; 155 } 156 if (cast(float)failure / N > 0.0001f) // <- allow for a failure rate of 0.01% 157 assert(true == false); 158 } 159 160 writeln("PASSED!"); 161 162 // testGetEulerAnglesZXY 163 { 164 int failure = 0; 165 int N = 3_000_000; 166 for (int i = 0; i <= N; i++) { 167 if (i % 100_000 == 0) { 168 // This is here because it takes a long time 169 writeln("Batch test: ", (cast(double)i / 3_000_000.0) * 100, "%" ); 170 } 171 double x = (Math.random() * 2.0 - 1.0) * Math.PI; 172 double y = (Math.random() * 2.0 - 1.0) * Math.PI; 173 double z = (Math.random() * 2.0 - 1.0) * Math.PI; 174 Quaterniond p = Quaterniond().rotateZ(z).rotateX(x).rotateY(y); 175 Vector3d a = p.getEulerAnglesZXY(Vector3d()); 176 Quaterniond q = Quaterniond().rotateZ(a.z).rotateX(a.x).rotateY(a.y); 177 Vector3d v = Vector3d(Math.random()*2-1, Math.random()*2-1, Math.random()*2-1); 178 Vector3d testunit = Vector3d(); 179 Vector3d t1 = p.transform(v, testunit); 180 Vector3d t2 = q.transform(v, testunit); 181 if (!t1.equals(t2, 1E-10f)) 182 failure++; 183 } 184 if (cast(float)failure / N > 0.0001f) // <- allow for a failure rate of 0.01% 185 assert(true == false); 186 } 187 188 writeln("PASSED!"); 189 190 // testGetEulerAnglesYXZ 191 { 192 int failure = 0; 193 int N = 3_000_000; 194 for (int i = 0; i <= N; i++) { 195 if (i % 100_000 == 0) { 196 // This is here because it takes a long time 197 writeln("Batch test: ", (cast(double)i / 3_000_000.0) * 100, "%" ); 198 } 199 double x = (Math.random() * 2.0 - 1.0) * Math.PI; 200 double y = (Math.random() * 2.0 - 1.0) * Math.PI; 201 double z = (Math.random() * 2.0 - 1.0) * Math.PI; 202 203 Vector3d testunit = Vector3d(); 204 Quaterniond p = Quaterniond().rotateY(y).rotateX(x).rotateZ(z); 205 Vector3d a = p.getEulerAnglesYXZ(Vector3d()); 206 Quaterniond q = Quaterniond().rotateY(a.y).rotateX(a.x).rotateZ(a.z); 207 Vector3d v = Vector3d(Math.random()*2-1, Math.random()*2-1, Math.random()*2-1); 208 Vector3d t1 = p.transform(v, testunit); 209 Vector3d t2 = q.transform(v, testunit); 210 if (!t1.equals(t2, 1E-10f)) 211 failure++; 212 } 213 if (cast(float)failure / N > 0.0001f) // <- allow for a failure rate of 0.01% 214 assert(true == false); 215 } 216 217 writeln("PASSED!"); 218 }