From 7e2512c8f63cee63ab2f74407fb94859fe20043a Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Sat, 15 Mar 2014 10:21:36 +0100 Subject: Quaternion: User EPSILON for all tests against zero and one (identity .. ) and document the same. ; Minor edits .. --- .../com/jogamp/graph/curve/OutlineShape.java | 2 +- .../classes/com/jogamp/graph/geom/Outline.java | 2 +- .../classes/com/jogamp/opengl/math/FloatUtil.java | 4 +- .../classes/com/jogamp/opengl/math/Quaternion.java | 171 ++++++++++++++++----- .../classes/com/jogamp/opengl/math/VectorUtil.java | 4 +- 5 files changed, 140 insertions(+), 43 deletions(-) (limited to 'src/jogl/classes/com/jogamp') diff --git a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java index 63183bf68..160e171e4 100644 --- a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java +++ b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java @@ -685,7 +685,7 @@ public class OutlineShape implements Comparable { public final int compareTo(final OutlineShape other) { final float thisSize = getBounds().getSize(); final float otherSize = other.getBounds().getSize(); - if( FloatUtil.equals(thisSize, otherSize, FloatUtil.EPSILON) ) { + if( FloatUtil.isEqual(thisSize, otherSize, FloatUtil.EPSILON) ) { return 0; } else if( thisSize < otherSize ){ return -1; diff --git a/src/jogl/classes/com/jogamp/graph/geom/Outline.java b/src/jogl/classes/com/jogamp/graph/geom/Outline.java index 5f6dd028f..9d4d1f26d 100644 --- a/src/jogl/classes/com/jogamp/graph/geom/Outline.java +++ b/src/jogl/classes/com/jogamp/graph/geom/Outline.java @@ -222,7 +222,7 @@ public class Outline implements Cloneable, Comparable { public final int compareTo(final Outline other) { final float thisSize = getBounds().getSize(); final float otherSize = other.getBounds().getSize(); - if( FloatUtil.equals(thisSize, otherSize, FloatUtil.EPSILON) ) { + if( FloatUtil.isEqual(thisSize, otherSize, FloatUtil.EPSILON) ) { return 0; } else if(thisSize < otherSize){ return -1; diff --git a/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java b/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java index 6177a6b2d..ee57fc7e8 100644 --- a/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java +++ b/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java @@ -707,7 +707,7 @@ public class FloatUtil { * boolean isNotEqual = abs(bfloat - afloat) >= EPSILON; * *

- * @see #equals(float, float, float) + * @see #isEqual(float, float, float) * @see #isZero(float, float) */ public static final float EPSILON = 1.1920929E-7f; // Float.MIN_VALUE == 1.4e-45f ; double EPSILON 2.220446049250313E-16d @@ -716,7 +716,7 @@ public class FloatUtil { * Return true if both values are equal, i.e. their absolute delta < epsilon. * @see #EPSILON */ - public static boolean equals(final float a, final float b, final float epsilon) { + public static boolean isEqual(final float a, final float b, final float epsilon) { return Math.abs(a - b) < epsilon; } diff --git a/src/jogl/classes/com/jogamp/opengl/math/Quaternion.java b/src/jogl/classes/com/jogamp/opengl/math/Quaternion.java index 56d270380..6e567fc1d 100644 --- a/src/jogl/classes/com/jogamp/opengl/math/Quaternion.java +++ b/src/jogl/classes/com/jogamp/opengl/math/Quaternion.java @@ -68,6 +68,8 @@ public class Quaternion { } /** + * See {@link #magnitude()} for special handling of {@link FloatUtil#EPSILON epsilon}, + * which is not applied here. * @return the squared magnitude of this quaternion. */ public final float magnitudeSquared() { @@ -75,11 +77,25 @@ public class Quaternion { } /** - * @return the magnitude of this quaternion, i.e. sqrt({@link #magnitude()}) + * Return the magnitude of this quaternion, i.e. sqrt({@link #magnitude()}) + *

+ * A magnitude of zero shall equal {@link #isIdentity() identity}, + * as performed by {@link #normalize()}. + *

+ *

+ * Implementation Details: + *

    + *
  • returns 0f if {@link #magnitudeSquared()} is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}
  • + *
  • returns 1f if {@link #magnitudeSquared()} is {@link FloatUtil#isEqual(float, float, float) equals 1f} using {@link FloatUtil#EPSILON epsilon}
  • + *
+ *

*/ public final float magnitude() { final float magnitudeSQ = magnitudeSquared(); - if (magnitudeSQ == 1f) { + if ( FloatUtil.isZero(magnitudeSQ, FloatUtil.EPSILON) ) { + return 0f; + } + if ( FloatUtil.isEqual(1f, magnitudeSQ, FloatUtil.EPSILON) ) { return 1f; } return FloatUtil.sqrt(magnitudeSQ); @@ -132,13 +148,17 @@ public class Quaternion { } /** - * Check if this quaternion represents an identity matrix for rotation, - * , ie (0,0,0,1). - * - * @return true if it is an identity rep., false otherwise + * Returns true if this quaternion has identity. + *

+ * Implementation uses {@link FloatUtil#EPSILON epsilon} to compare + * {@link #getW() W} {@link FloatUtil#isEqual(float, float, float) against 1f} and + * {@link #getX() X}, {@link #getY() Y} and {@link #getZ() Z} + * {@link FloatUtil#isZero(float, float) against zero}. + *

*/ public final boolean isIdentity() { - return w == 1 && x == 0 && y == 0 && z == 0; + return FloatUtil.isEqual(1f, w, FloatUtil.EPSILON) && VectorUtil.isZero(x, y, z, FloatUtil.EPSILON); + // return w == 1f && x == 0f && y == 0f && z == 0f; } /*** @@ -146,17 +166,23 @@ public class Quaternion { * @return this quaternion for chaining. */ public final Quaternion setIdentity() { - x = y = z = 0; w = 1; + x = y = z = 0f; w = 1f; return this; } /** - * Normalize a quaternion required if to be used as a rotational quaternion + * Normalize a quaternion required if to be used as a rotational quaternion. + *

+ * Implementation Details: + *

    + *
  • {@link #setIdentity()} if {@link #magnitude()} is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}
  • + *
+ *

* @return this quaternion for chaining. */ public final Quaternion normalize() { final float norm = magnitude(); - if (norm == 0.0f) { + if ( FloatUtil.isZero(norm, FloatUtil.EPSILON) ) { setIdentity(); } else { w /= norm; @@ -181,12 +207,18 @@ public class Quaternion { /** * Invert the quaternion If rotational, will produce a the inverse rotation + *

+ * Implementation Details: + *

    + *
  • {@link #conjugate() conjugates} if {@link #magnitudeSquared()} is is {@link FloatUtil#isEqual(float, float, float) equals 1f} using {@link FloatUtil#EPSILON epsilon}
  • + *
+ *

* @return this quaternion for chaining. * @see Matrix-FAQ Q50 */ public final Quaternion invert() { final float magnitudeSQ = magnitudeSquared(); - if ( FloatUtil.equals(1.0f, magnitudeSQ, FloatUtil.EPSILON) ) { + if ( FloatUtil.isEqual(1.0f, magnitudeSQ, FloatUtil.EPSILON) ) { conjugate(); } else { w /= magnitudeSQ; @@ -543,6 +575,12 @@ public class Quaternion { * angle = angle(v1, v2) = v1•v2 * axis = normal(v1 x v2) * + *

+ * Implementation Details: + *

    + *
  • {@link #setIdentity()} if square vector-length is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}
  • + *
+ *

* @param v1 not normalized * @param v2 not normalized * @param tmpPivotVec float[3] temp storage for cross product @@ -593,6 +631,12 @@ public class Quaternion { * angle = angle(v1, v2) = v1•v2 * axis = v1 x v2 * + *

+ * Implementation Details: + *

    + *
  • {@link #setIdentity()} if square vector-length is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}
  • + *
+ *

* @param v1 normalized * @param v2 normalized * @param tmpPivotVec float[3] temp storage for cross product @@ -638,7 +682,10 @@ public class Quaternion { /*** * Initialize this quaternion with given non-normalized axis vector and rotation angle *

- * If axis == 0,0,0 the quaternion is set to identity. + * Implementation Details: + *

    + *
  • {@link #setIdentity()} if axis is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}
  • + *
*

* @param angle rotation angle (rads) * @param vector axis vector not normalized @@ -656,7 +703,10 @@ public class Quaternion { /*** * Initialize this quaternion with given normalized axis vector and rotation angle *

- * If axis == 0,0,0 the quaternion is set to identity. + * Implementation Details: + *

    + *
  • {@link #setIdentity()} if axis is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}
  • + *
*

* @param angle rotation angle (rads) * @param vector axis vector normalized @@ -722,7 +772,12 @@ public class Quaternion { *
  • x - bank
  • * *

    - * + *

    + * Implementation Details: + *

      + *
    • {@link #setIdentity()} if all angles are {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}
    • + *
    + *

    * @param angradXYZ euler angel array in radians * @return this quaternion for chaining. * @see Matrix-FAQ Q60 @@ -745,6 +800,12 @@ public class Quaternion { *
  • x - bank
  • * *

    + *

    + * Implementation Details: + *

      + *
    • {@link #setIdentity()} if all angles are {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}
    • + *
    + *

    * @param bankX the Euler pitch angle in radians. (rotation about the X axis) * @param headingY the Euler yaw angle in radians. (rotation about the Y axis) * @param attitudeZ the Euler roll angle in radians. (rotation about the Z axis) @@ -756,27 +817,31 @@ public class Quaternion { * @see #toEuler(float[]) */ public final Quaternion setFromEuler(final float bankX, final float headingY, float attitudeZ) { - float angle = headingY * 0.5f; - final float sinHeadingY = FloatUtil.sin(angle); - final float cosHeadingY = FloatUtil.cos(angle); - angle = attitudeZ * 0.5f; - final float sinAttitudeZ = FloatUtil.sin(angle); - final float cosAttitudeZ = FloatUtil.cos(angle); - angle = bankX * 0.5f; - final float sinBankX = FloatUtil.sin(angle); - final float cosBankX = FloatUtil.cos(angle); - - // variables used to reduce multiplication calls. - final float cosHeadingXcosAttitude = cosHeadingY * cosAttitudeZ; - final float sinHeadingXsinAttitude = sinHeadingY * sinAttitudeZ; - final float cosHeadingXsinAttitude = cosHeadingY * sinAttitudeZ; - final float sinHeadingXcosAttitude = sinHeadingY * cosAttitudeZ; - - w = cosHeadingXcosAttitude * cosBankX - sinHeadingXsinAttitude * sinBankX; - x = cosHeadingXcosAttitude * sinBankX + sinHeadingXsinAttitude * cosBankX; - y = sinHeadingXcosAttitude * cosBankX + cosHeadingXsinAttitude * sinBankX; - z = cosHeadingXsinAttitude * cosBankX - sinHeadingXcosAttitude * sinBankX; - return normalize(); + if ( VectorUtil.isZero(bankX, headingY, attitudeZ, FloatUtil.EPSILON) ) { + return setIdentity(); + } else { + float angle = headingY * 0.5f; + final float sinHeadingY = FloatUtil.sin(angle); + final float cosHeadingY = FloatUtil.cos(angle); + angle = attitudeZ * 0.5f; + final float sinAttitudeZ = FloatUtil.sin(angle); + final float cosAttitudeZ = FloatUtil.cos(angle); + angle = bankX * 0.5f; + final float sinBankX = FloatUtil.sin(angle); + final float cosBankX = FloatUtil.cos(angle); + + // variables used to reduce multiplication calls. + final float cosHeadingXcosAttitude = cosHeadingY * cosAttitudeZ; + final float sinHeadingXsinAttitude = sinHeadingY * sinAttitudeZ; + final float cosHeadingXsinAttitude = cosHeadingY * sinAttitudeZ; + final float sinHeadingXcosAttitude = sinHeadingY * cosAttitudeZ; + + w = cosHeadingXcosAttitude * cosBankX - sinHeadingXsinAttitude * sinBankX; + x = cosHeadingXcosAttitude * sinBankX + sinHeadingXsinAttitude * cosBankX; + y = sinHeadingXcosAttitude * cosBankX + cosHeadingXsinAttitude * sinBankX; + z = cosHeadingXsinAttitude * cosBankX - sinHeadingXcosAttitude * sinBankX; + return normalize(); + } } /** @@ -910,6 +975,12 @@ public class Quaternion { /** * Transform this quaternion to a normalized 4x4 column matrix representing the rotation. + *

    + * Implementation Details: + *

      + *
    • makes identity matrix if {@link #magnitudeSquared()} is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}
    • + *
    + *

    * * @param matrix float[16] store for the resulting normalized column matrix 4x4 * @param mat_offset @@ -920,7 +991,17 @@ public class Quaternion { public final float[] toMatrix(final float[] matrix, final int mat_offset) { // pre-multiply scaled-reciprocal-magnitude to reduce multiplications final float norm = magnitudeSquared(); - final float srecip = norm == 1.0f ? 2.0f : norm > 0.0f ? 2.0f / norm : 0f; + if ( FloatUtil.isZero(norm, FloatUtil.EPSILON) ) { + // identity matrix -> srecip = 0f + FloatUtil.makeIdentityf(matrix, mat_offset); + return matrix; + } + final float srecip; + if ( FloatUtil.isEqual(1f, norm, FloatUtil.EPSILON) ) { + srecip = 2f; + } else { + srecip = 2.0f / norm; + } final float xs = srecip * x; final float ys = srecip * y; @@ -960,6 +1041,12 @@ public class Quaternion { /** * Transform this quaternion to a normalized 4x4 column matrix representing the rotation. + *

    + * Implementation Details: + *

      + *
    • makes identity matrix if {@link #magnitudeSquared()} is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}
    • + *
    + *

    * * @param matrix FloatBuffer store for the resulting normalized column matrix 4x4 * @param mat_offset @@ -972,7 +1059,17 @@ public class Quaternion { // pre-multipliy scaled-reciprocal-magnitude to reduce multiplications final float norm = magnitudeSquared(); - final float srecip = norm == 1.0f ? 2.0f : norm > 0.0f ? 2.0f / norm : 0f; + if ( FloatUtil.isZero(norm, FloatUtil.EPSILON) ) { + // identity matrix -> srecip = 0f + FloatUtil.makeIdentityf(matrix); + return matrix; + } + final float srecip; + if ( FloatUtil.isEqual(1f, norm, FloatUtil.EPSILON) ) { + srecip = 2f; + } else { + srecip = 2.0f / norm; + } final float xs = srecip * x; final float ys = srecip * y; diff --git a/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java b/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java index ff16fba79..4aa1baf78 100644 --- a/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java +++ b/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java @@ -77,7 +77,7 @@ public class VectorUtil { /** * Return true if both vectors are equal, no {@link FloatUtil#EPSILON} is taken into consideration. */ - public static boolean equals(final float[] vec1, int vec1Offset, final float[] vec2, int vec2Offset) { + public static boolean isEqual(final float[] vec1, int vec1Offset, final float[] vec2, int vec2Offset) { return vec1[0+vec1Offset] == vec2[0+vec2Offset] && vec1[1+vec1Offset] == vec2[1+vec2Offset] && vec1[2+vec1Offset] == vec2[2+vec2Offset]; @@ -87,7 +87,7 @@ public class VectorUtil { * Return true if both vectors are equal, i.e. their absolute delta < epsilon. * @see FloatUtil#EPSILON */ - public static boolean equals(final float[] vec1, int vec1Offset, final float[] vec2, int vec2Offset, final float epsilon) { + public static boolean isEqual(final float[] vec1, int vec1Offset, final float[] vec2, int vec2Offset, final float epsilon) { return Math.abs(vec1[0+vec1Offset] - vec2[0+vec2Offset]) < epsilon && Math.abs(vec1[1+vec1Offset] - vec2[1+vec2Offset]) < epsilon && Math.abs(vec1[2+vec1Offset] - vec2[2+vec2Offset]) < epsilon ; -- cgit v1.2.3