aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2014-03-14 07:50:20 +0100
committerSven Gothel <[email protected]>2014-03-14 07:50:20 +0100
commitb3fb80b4e03818f1f7dfdddd1ffcb01e6a0a8acc (patch)
tree4c1de742b4e9d4a7a2f1981ba6a2fd358622099d /src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java
parent3a3bbd87955321d790ba0f63402c573047304b1a (diff)
Math and PMVMatrix: Cleanup and Refine
- Added final qualifier where possible - Refined API doc - FloatUtil: - Add machine EPSILON - fixed value and runtime computed (real machEps) - incl. isZero(..), isEqual(..) - Add makeRotationAxis(..) - Moved from PMVMatrix for reusage - Add makeRotationEuler(..) - New, not recommended due to Gimbal-Lock - Add copyMatrix[Column|Row](..) - Add more PI variations and trigo-func float mappings - Removed cross and normalize, use VectorUtil! VectorUtil: - Add copyVec* - Add equals and isZero w/ and w/o EPSILON - Add distance[Square] - Add length[Square] PMVMatrix: - Removed 'destroy' method in favor of making most fields 'final'. AffineTransform: - Added AABBox transform - Public multiply
Diffstat (limited to 'src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java')
-rw-r--r--src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java346
1 files changed, 254 insertions, 92 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java b/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java
index d2976357d..6177a6b2d 100644
--- a/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java
+++ b/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java
@@ -37,23 +37,23 @@ import com.jogamp.common.os.Platform;
* Basic Float math utility functions.
* <p>
* Implementation assumes linear matrix layout in column-major order
- * matching OpenGL's implementation, translation matrix example:
+ * matching OpenGL's implementation, illustration:
* <pre>
- Row-Major Order:
- 1 0 0 x
- 0 1 0 y
- 0 0 1 z
- 0 0 0 1
- * </pre>
- * <pre>
- Column-Major Order:
- 1 0 0 0
- 0 1 0 0
- 0 0 1 0
- x y z 1
+ Row-Major Column-Major (OpenGL):
+
+ | 0 1 2 3 | | 0 4 8 12 |
+ | | | |
+ | 4 5 6 7 | | 1 5 9 13 |
+ M = | | M = | |
+ | 8 9 10 11 | | 2 6 10 14 |
+ | | | |
+ | 12 13 14 15 | | 3 7 11 15 |
* </pre>
* </p>
* <p>
+ * See <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html">Matrix-FAQ</a>
+ * </p>
+ * <p>
* Derived from ProjectFloat.java - Created 11-jan-2004
* </p>
*
@@ -113,6 +113,92 @@ public class FloatUtil {
}
/**
+ * Make a rotation matrix from the given axis and angle in radians.
+ * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q38">Matrix-FAQ Q38</a>
+ */
+ public static final void makeRotationAxis(final float angrad, float x, float y, float z, final float[] mat, final int mat_offset, final float[] tmpVec3f) {
+ final float c = cos(angrad);
+ final float ic= 1.0f - c;
+ final float s = sin(angrad);
+
+ tmpVec3f[0]=x; tmpVec3f[1]=y; tmpVec3f[2]=z;
+ VectorUtil.normalize(tmpVec3f);
+ x = tmpVec3f[0]; y = tmpVec3f[1]; z = tmpVec3f[2];
+
+ // Rotation matrix (Row Order):
+ // xx(1-c)+c xy(1-c)+zs xz(1-c)-ys 0
+ // xy(1-c)-zs yy(1-c)+c yz(1-c)+xs 0
+ // xz(1-c)+ys yz(1-c)-xs zz(1-c)+c 0
+ // 0 0 0 1
+ final float xy = x*y;
+ final float xz = x*z;
+ final float xs = x*s;
+ final float ys = y*s;
+ final float yz = y*z;
+ final float zs = z*s;
+ mat[0+0*4+mat_offset] = x*x*ic+c;
+ mat[1+0*4+mat_offset] = xy*ic+zs;
+ mat[2+0*4+mat_offset] = xz*ic-ys;
+
+ mat[0+1*4+mat_offset] = xy*ic-zs;
+ mat[1+1*4+mat_offset] = y*y*ic+c;
+ mat[2+1*4+mat_offset] = yz*ic+xs;
+
+ mat[0+2*4+mat_offset] = xz*ic+ys;
+ mat[1+2*4+mat_offset] = yz*ic-xs;
+ mat[2+2*4+mat_offset] = z*z*ic+c;
+ }
+
+ /**
+ * Make a concatenated rotation matrix in column-major order from the given Euler rotation angles in radians.
+ * <p>
+ * The rotations are applied in the given order:
+ * <ul>
+ * <li>y - heading</li>
+ * <li>z - attitude</li>
+ * <li>x - bank</li>
+ * </ul>
+ * </p>
+ * @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)
+ * <p>
+ * Implementation does not use Quaternion and hence is exposed to
+ * <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q34">Gimbal-Lock</a>
+ * </p>
+ * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q36">Matrix-FAQ Q36</a>
+ * @see <a href="http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToMatrix/index.htm">euclideanspace.com-eulerToMatrix</a>
+ */
+ public static final void makeRotationEuler(final float bankX, final float headingY, final float attitudeZ, final float[] mat, final int mat_offset) {
+ // Assuming the angles are in radians.
+ final float ch = cos(headingY);
+ final float sh = sin(headingY);
+ final float ca = cos(attitudeZ);
+ final float sa = sin(attitudeZ);
+ final float cb = cos(bankX);
+ final float sb = sin(bankX);
+
+ mat[0+0*4+mat_offset] = ch*ca;
+ mat[0+1*4+mat_offset] = sh*sb - ch*sa*cb;
+ mat[0+2*4+mat_offset] = ch*sa*sb + sh*cb;
+ mat[1+0*4+mat_offset] = sa;
+ mat[1+1*4+mat_offset] = ca*cb;
+ mat[1+2*4+mat_offset] = -ca*sb;
+ mat[2+0*4+mat_offset] = -sh*ca;
+ mat[2+1*4+mat_offset] = sh*sa*cb + ch*sb;
+ mat[2+2*4+mat_offset] = -sh*sa*sb + ch*cb;
+
+ mat[3+0*4+mat_offset] = 0;
+ mat[3+1*4+mat_offset] = 0;
+ mat[3+2*4+mat_offset] = 0;
+
+ mat[0+3*4+mat_offset] = 0;
+ mat[1+3*4+mat_offset] = 0;
+ mat[2+3*4+mat_offset] = 0;
+ mat[3+3*4+mat_offset] = 1;
+ }
+
+ /**
* @param a 4x4 matrix in column-major order
* @param b 4x4 matrix in column-major order
* @param d result a*b in column-major order
@@ -252,79 +338,6 @@ public class FloatUtil {
}
/**
- * Normalize vector
- *
- * @param v makes len(v)==1
- */
- public static final void normalize(float[] v) {
- float r = (float) Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
-
- if ( r == 0.0 || r == 1.0) {
- return;
- }
-
- r = 1.0f / r;
-
- v[0] *= r;
- v[1] *= r;
- v[2] *= r;
- }
-
- /**
- * Normalize vector
- *
- * @param v makes len(v)==1
- */
- public static final void normalize(FloatBuffer v) {
- final int vPos = v.position();
-
- float r = (float) Math.sqrt(v.get(0+vPos) * v.get(0+vPos) +
- v.get(1+vPos) * v.get(1+vPos) +
- v.get(2+vPos) * v.get(2+vPos));
-
- if ( r == 0.0 || r == 1.0) {
- return;
- }
-
- r = 1.0f / r;
-
- v.put(0+vPos, v.get(0+vPos) * r);
- v.put(1+vPos, v.get(1+vPos) * r);
- v.put(2+vPos, v.get(2+vPos) * r);
- }
-
-
- /**
- * Calculate cross-product of 2 vector
- *
- * @param v1 3-component vector
- * @param v2 3-component vector
- * @param result v1 X v2
- */
- public static final void cross(float[] v1, float[] v2, float[] result) {
- result[0] = v1[1] * v2[2] - v1[2] * v2[1];
- result[1] = v1[2] * v2[0] - v1[0] * v2[2];
- result[2] = v1[0] * v2[1] - v1[1] * v2[0];
- }
-
- /**
- * Calculate cross-product of 2 vector
- *
- * @param v1 3-component vector
- * @param v2 3-component vector
- * @param result v1 X v2
- */
- public static final void cross(FloatBuffer v1, FloatBuffer v2, FloatBuffer result) {
- final int v1Pos = v1.position();
- final int v2Pos = v2.position();
- final int rPos = result.position();
-
- result.put(0+rPos, v1.get(1+v1Pos) * v2.get(2+v2Pos) - v1.get(2+v1Pos) * v2.get(1+v2Pos));
- result.put(1+rPos, v1.get(2+v1Pos) * v2.get(0+v2Pos) - v1.get(0+v1Pos) * v2.get(2+v2Pos));
- result.put(2+rPos, v1.get(0+v1Pos) * v2.get(1+v2Pos) - v1.get(1+v1Pos) * v2.get(0+v2Pos));
- }
-
- /**
* @param m_in 4x4 matrix in column-major order
* @param m_in_off
* @param v_in 4-component column-vector
@@ -412,6 +425,46 @@ public class FloatUtil {
}
/**
+ * Copy the named column of the given column-major matrix to v_out.
+ * <p>
+ * v_out may be 3 or 4 components long, hence the 4th row may not be stored.
+ * </p>
+ * @param m_in input column-major matrix
+ * @param m_in_off offset to input matrix
+ * @param column named column to copy
+ * @param v_out the column-vector storage, at least 3 components long
+ * @param v_out_off offset to storage
+ */
+ public static final void copyMatrixColumn(final float[] m_in, final int m_in_off, final int column, final float[] v_out, final int v_out_off) {
+ v_out[0+v_out_off]=m_in[0+column*4+m_in_off];
+ v_out[1+v_out_off]=m_in[1+column*4+m_in_off];
+ v_out[2+v_out_off]=m_in[2+column*4+m_in_off];
+ if( v_out.length > 3+v_out_off ) {
+ v_out[3+v_out_off]=m_in[3+column*4+m_in_off];
+ }
+ }
+
+ /**
+ * Copy the named row of the given column-major matrix to v_out.
+ * <p>
+ * v_out may be 3 or 4 components long, hence the 4th column may not be stored.
+ * </p>
+ * @param m_in input column-major matrix
+ * @param m_in_off offset to input matrix
+ * @param row named row to copy
+ * @param v_out the row-vector storage, at least 3 components long
+ * @param v_out_off offset to storage
+ */
+ public static final void copyMatrixRow(final float[] m_in, final int m_in_off, final int row, final float[] v_out, final int v_out_off) {
+ v_out[0+v_out_off]=m_in[row+0*4+m_in_off];
+ v_out[1+v_out_off]=m_in[row+1*4+m_in_off];
+ v_out[2+v_out_off]=m_in[row+2*4+m_in_off];
+ if( v_out.length > 3+v_out_off ) {
+ v_out[3+v_out_off]=m_in[row+3*4+m_in_off];
+ }
+ }
+
+ /**
* @param sb optional passed StringBuilder instance to be used
* @param f the format string of one floating point, i.e. "%10.5f", see {@link java.util.Formatter}
* @param a mxn matrix (rows x columns)
@@ -570,20 +623,129 @@ public class FloatUtil {
return sb;
}
+ @SuppressWarnings("unused")
+ private static void calculateMachineEpsilonFloat() {
+ final long t0;
+ if( DEBUG_EPSILON ) {
+ t0 = Platform.currentTimeMillis();
+ }
+ float machEps = 1.0f;
+ int i=0;
+ do {
+ machEps /= 2.0f;
+ i++;
+ } while (1.0f + (machEps / 2.0f) != 1.0f);
+ machEpsilon = machEps;
+ if( DEBUG_EPSILON ) {
+ final long t1 = Platform.currentTimeMillis();
+ System.err.println("MachineEpsilon: "+machEpsilon+", in "+i+" iterations within "+(t1-t0)+" ms");
+ }
+ }
+ private static volatile boolean machEpsilonAvail = false;
+ private static float machEpsilon = 0f;
+ private static final boolean DEBUG_EPSILON = false;
+
+ /**
+ * Return computed machine Epsilon value.
+ * <p>
+ * The machine Epsilon value is computed once.
+ * </p>
+ * <p>
+ * On a reference machine the result was {@link #EPSILON} in 23 iterations.
+ * </p>
+ * @see #EPSILON
+ */
+ public static float getMachineEpsilon() {
+ if( !machEpsilonAvail ) {
+ synchronized(FloatUtil.class) {
+ if( !machEpsilonAvail ) {
+ machEpsilonAvail = true;
+ calculateMachineEpsilonFloat();
+ }
+ }
+ }
+ return machEpsilon;
+ }
+
public static final float E = 2.7182818284590452354f;
+ /** The value PI, i.e. 180 degrees in radians. */
public static final float PI = 3.14159265358979323846f;
- public static float abs(float a) { return java.lang.Math.abs(a); }
+ /** The value 2PI, i.e. 360 degrees in radians. */
+ public static final float TWO_PI = 2f * PI;
+
+ /** The value PI/2, i.e. 90 degrees in radians. */
+ public static final float HALF_PI = PI / 2f;
+
+ /** The value PI/4, i.e. 45 degrees in radians. */
+ public static final float QUARTER_PI = PI / 4f;
+
+ /** The value PI^2. */
+ public final static float SQUARED_PI = PI * PI;
+
+ /**
+ * Epsilon for floating point {@value}, as once computed via {@link #getMachineEpsilon()} on an AMD-64 CPU.
+ * <p>
+ * Definition of machine epsilon guarantees that:
+ * <pre>
+ * 1.0f + EPSILON != 1.0f
+ * </pre>
+ * In other words: <i>machEps</i> is the maximum relative error of the chosen rounding procedure.
+ * </p>
+ * <p>
+ * A number can be considered zero if it is in the range (or in the set):
+ * <pre>
+ * <b>MaybeZeroSet</b> e ]-<i>machEps</i> .. <i>machEps</i>[ <i>(exclusive)</i>
+ * </pre>
+ * While comparing floating point values, <i>machEps</i> allows to clip the relative error:
+ * <pre>
+ * boolean isZero = afloat < EPSILON;
+ * boolean isNotZero = afloat >= EPSILON;
+ *
+ * boolean isEqual = abs(bfloat - afloat) < EPSILON;
+ * boolean isNotEqual = abs(bfloat - afloat) >= EPSILON;
+ * </pre>
+ * </p>
+ * @see #equals(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
+
+ /**
+ * Return true if both values are equal, i.e. their absolute delta < <code>epsilon</code>.
+ * @see #EPSILON
+ */
+ public static boolean equals(final float a, final float b, final float epsilon) {
+ return Math.abs(a - b) < epsilon;
+ }
+
+ /**
+ * Return true if value is zero, i.e. it's absolute value < <code>epsilon</code>.
+ * @see #EPSILON
+ */
+ public static boolean isZero(final float a, final float epsilon) {
+ return Math.abs(a) < epsilon;
+ }
+
+ public static float abs(final float a) { return java.lang.Math.abs(a); }
+
+ public static float pow(final float a, final float b) { return (float) java.lang.Math.pow(a, b); }
+
+ public static float sin(final float a) { return (float) java.lang.Math.sin(a); }
+
+ public static float asin(final float a) { return (float) java.lang.Math.asin(a); }
+
+ public static float cos(final float a) { return (float) java.lang.Math.cos(a); }
- public static float pow(float a, float b) { return (float) java.lang.Math.pow(a, b); }
+ public static float acos(final float a) { return (float) java.lang.Math.acos(a); }
- public static float sin(float a) { return (float) java.lang.Math.sin(a); }
+ public static float tan(final float a) { return (float) java.lang.Math.tan(a); }
- public static float cos(float a) { return (float) java.lang.Math.cos(a); }
+ public static float atan(final float a) { return (float) java.lang.Math.atan(a); }
- public static float acos(float a) { return (float) java.lang.Math.acos(a); }
+ public static float atan2(final float y, final float x) { return (float) java.lang.Math.atan2(y, x); }
- public static float sqrt(float a) { return (float) java.lang.Math.sqrt(a); }
+ public static float sqrt(final float a) { return (float) java.lang.Math.sqrt(a); }
} \ No newline at end of file