From d13df22ebfecdaced3a69a21dc23a7b5e8238ed7 Mon Sep 17 00:00:00 2001 From: richardTingle <6330028+richardTingle@users.noreply.github.com> Date: Sat, 1 Jun 2024 19:47:48 +0100 Subject: [PATCH] #2275 Improve assertions for invalid transforms. (#2276) * #2275 Improve assertions for invalid transforms. These are already caught by assertions in GLRenderer, but by that time it is unclear what call pushed in the bad values * #2275 Swap to use more generally available validation methods * #2275 Add license and javadoc * #2275 Correct copyright year * #2275 It is a quaternion --- .../main/java/com/jme3/math/Quaternion.java | 23 ++++++++ .../main/java/com/jme3/math/Transform.java | 6 ++ .../java/com/jme3/math/QuaternionTest.java | 59 +++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 jme3-core/src/test/java/com/jme3/math/QuaternionTest.java diff --git a/jme3-core/src/main/java/com/jme3/math/Quaternion.java b/jme3-core/src/main/java/com/jme3/math/Quaternion.java index 621d4799a7..3da3feb42f 100644 --- a/jme3-core/src/main/java/com/jme3/math/Quaternion.java +++ b/jme3-core/src/main/java/com/jme3/math/Quaternion.java @@ -1608,4 +1608,27 @@ public Quaternion clone() { throw new AssertionError(); // can not happen } } + + /** + * Tests whether the argument is a valid quaternion, returning false if it's + * null or if any component is NaN or infinite. + * + * @param quaternion the quaternion to test (unaffected) + * @return true if non-null and finite, otherwise false + */ + public static boolean isValidQuaternion(Quaternion quaternion) { + if (quaternion == null) { + return false; + } + if (Float.isNaN(quaternion.x) + || Float.isNaN(quaternion.y) + || Float.isNaN(quaternion.z) + || Float.isNaN(quaternion.w)) { + return false; + } + return !Float.isInfinite(quaternion.x) + && !Float.isInfinite(quaternion.y) + && !Float.isInfinite(quaternion.z) + && !Float.isInfinite(quaternion.w); + } } diff --git a/jme3-core/src/main/java/com/jme3/math/Transform.java b/jme3-core/src/main/java/com/jme3/math/Transform.java index bfcec39fdf..de5bfe8ce8 100644 --- a/jme3-core/src/main/java/com/jme3/math/Transform.java +++ b/jme3-core/src/main/java/com/jme3/math/Transform.java @@ -121,6 +121,7 @@ public Transform() { * @return the (modified) current instance (for chaining) */ public Transform setRotation(Quaternion rot) { + assert Quaternion.isValidQuaternion(rot) : "Invalid rotation " + rot; this.rot.set(rot); return this; } @@ -132,6 +133,7 @@ public Transform setRotation(Quaternion rot) { * @return the (modified) current instance (for chaining) */ public Transform setTranslation(Vector3f trans) { + assert Vector3f.isValidVector(trans) : "Invalid translation " + trans; this.translation.set(trans); return this; } @@ -152,6 +154,7 @@ public Vector3f getTranslation() { * @return the (modified) current instance (for chaining) */ public Transform setScale(Vector3f scale) { + assert Vector3f.isValidVector(scale) : "Invalid scale " + scale; this.scale.set(scale); return this; } @@ -163,6 +166,7 @@ public Transform setScale(Vector3f scale) { * @return the (modified) current instance (for chaining) */ public Transform setScale(float scale) { + assert Float.isFinite(scale) : "Invalid scale " + scale; this.scale.set(scale, scale, scale); return this; } @@ -286,6 +290,7 @@ public Transform combineWithParent(Transform parent) { * @return the (modified) current instance (for chaining) */ public Transform setTranslation(float x, float y, float z) { + assert Float.isFinite(x) && Float.isFinite(y) && Float.isFinite(z) : "Invalid translation " + x + ", " + y + ", " + z; translation.set(x, y, z); return this; } @@ -299,6 +304,7 @@ public Transform setTranslation(float x, float y, float z) { * @return the (modified) current instance (for chaining) */ public Transform setScale(float x, float y, float z) { + assert Float.isFinite(x) && Float.isFinite(y) && Float.isFinite(z) : "Invalid scale " + x + ", " + y + ", " + z; scale.set(x, y, z); return this; } diff --git a/jme3-core/src/test/java/com/jme3/math/QuaternionTest.java b/jme3-core/src/test/java/com/jme3/math/QuaternionTest.java new file mode 100644 index 0000000000..a81074de70 --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/math/QuaternionTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.math; + +import junit.framework.TestCase; + +/** + * Verifies that the {@link Quaternion} class works correctly. + * + * @author Richard Tingle (aka Richtea) + */ +public class QuaternionTest extends TestCase{ + + /** + * Verify that the {@link Quaternion#isValidQuaternion(com.jme3.math.Quaternion)} method works correctly. Testing + * for NaNs and infinities (which are not "valid") + */ + public void testIsValidQuaternion(){ + assertFalse(Quaternion.isValidQuaternion(new Quaternion(Float.NaN, 2.1f, 3.0f, 1.5f))); + assertFalse(Quaternion.isValidQuaternion(new Quaternion(1f, Float.NaN, 3.0f, 1.5f))); + assertFalse(Quaternion.isValidQuaternion(new Quaternion(1f, 2.1f, Float.NaN, 1.5f))); + assertFalse(Quaternion.isValidQuaternion(new Quaternion(1f, 2.1f, 3.0f, Float.NaN))); + assertFalse(Quaternion.isValidQuaternion(new Quaternion(Float.POSITIVE_INFINITY, 1.5f, 1.9f, 2.0f))); + assertFalse(Quaternion.isValidQuaternion(new Quaternion(Float.NEGATIVE_INFINITY, 2.5f, 8.2f, 3.0f))); + assertFalse(Quaternion.isValidQuaternion(null)); + + assertTrue(Quaternion.isValidQuaternion(new Quaternion())); + assertTrue(Quaternion.isValidQuaternion(new Quaternion(1.5f, -5.7f, 8.2f, 3.0f))); + } +} \ No newline at end of file