From 255908bf19515af5c3770cd304eece10f95b6ba8 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Mon, 18 Jun 2001 23:34:31 +0000 Subject: 2.8.0.0 pre-release cvs only --- demos/MiscDemos/jahuwaldt/gl/GLTools.java | 494 ++++++++++++++++++++++++++++++ 1 file changed, 494 insertions(+) create mode 100644 demos/MiscDemos/jahuwaldt/gl/GLTools.java (limited to 'demos/MiscDemos/jahuwaldt/gl/GLTools.java') diff --git a/demos/MiscDemos/jahuwaldt/gl/GLTools.java b/demos/MiscDemos/jahuwaldt/gl/GLTools.java new file mode 100644 index 0000000..1c28540 --- /dev/null +++ b/demos/MiscDemos/jahuwaldt/gl/GLTools.java @@ -0,0 +1,494 @@ +/* +* GLTools -- A collection of static methods for working with 3D graphics. +* +* Copyright (C) 2001 by Joseph A. Huwaldt . +* All rights reserved. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Library General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Library General Public License for more details. +**/ + +package jahuwaldt.gl; + + +/** +* A set of static utility methods for working with 3D graphics. +* In particular, these methods are geared for working efficiently +* with GL4Java and OpenGL. +* +*

Modified by: Joseph A. Huwaldt

+* +* @author Joseph A. Huwaldt Date: January 13, 2001 +* @version February 19, 2001 +**/ +public class GLTools { + + // Some constants for convenience. + private static final int X = 0; + private static final int Y = 1; + private static final int Z = 2; + + // Some error messages. + private static final String kVector3DMsg = "Vectors must be 3D (3 elements)."; + private static final String kPoint3DMsg = "Points must be 3D (3 elements)."; + private static final String kNormal3DMsg = "Normal vector must be 3D (3 elements)."; + + + /** + * This method will normalize a 3D vector to have + * a length of 1.0. The unit vector is placed in the + * specified output vector (which may safely be a reference + * to the input vector). + * + * @param vector The 3D (3 element) vector to be normalized. + * @param output The 3D (3 element) vector that will contain + * the normalized version of the input vector. + * @return A reference to the output normalized vector. + **/ + public static final float[] normalize(float vector[], float[] output) { + if (vector.length != 3 || output.length != 3) + throw new IllegalArgumentException(kVector3DMsg); + + float v0 = vector[X], v1 = vector[Y], v2 = vector[Z]; + float length = (float)Math.sqrt( v0*v0 + v1*v1 + v2*v2 ); + + // Do not allow a divide by zero. + if (length == 0) + length = 1; + + // Divide each element by the length to get a unit vector. + output[X] = v0/length; + output[Y] = v1/length; + output[Z] = v2/length; + + return output; + } + + /** + * This method will normalize a 3D vector to have + * a length of 1.0. A new vector is created that is the normalized + * version of the input vector. + * + * @param vector The 3D (3 element) vector to be normalized. + * @return A reference to the new output normalized vector. + **/ + public static final float[] normalize(float vector[]) { + if (vector.length != 3) + throw new IllegalArgumentException(kVector3DMsg); + + float v0 = vector[X], v1 = vector[Y], v2 = vector[Z]; + float length = (float)Math.sqrt( v0*v0 + v1*v1 + v2*v2 ); + + // Do not allow a divide by zero. + if (length == 0) + length = 1; + + // Divide each element by the length to get a unit vector. + float[] output = new float[3]; + output[X] = v0/length; + output[Y] = v1/length; + output[Z] = v2/length; + + return output; + } + + /** + * Calculate the normal vector for a plane (triangle) defined + * by 3 points in space. The points must be specified in + * counterclockwise order. The normal vector is placed in the + * specified output vector. + * + * @param pnt1 The 1st 3D point in the plane. + * @param pnt2 The 2nd 3D point in the plane. + * @param pnt3 The 3rd 3D point in the plane. + * @param output The 3D vector (3 element array) that will be filled in + * with the normal vector for this plane. + * @return A reference to the output normal vector. + **/ + public static final float[] calcNormal(float[] pnt1, float[] pnt2, float[] pnt3, + float[] output) { + if (pnt1.length != 3 || pnt2.length != 3 || pnt3.length != 3) + throw new IllegalArgumentException(kPoint3DMsg); + if (output.length != 3) + throw new IllegalArgumentException(kNormal3DMsg); + + // Calculate two vectors from e three points. + float v10 = pnt1[X] - pnt2[X]; + float v11 = pnt1[Y] - pnt2[Y]; + float v12 = pnt1[Z] - pnt2[Z]; + + float v20 = pnt2[X] - pnt3[X]; + float v21 = pnt2[Y] - pnt3[Y]; + float v22 = pnt2[Z] - pnt3[Z]; + + // Take the cross product of the two vectors and store in output. + output[X] = v11*v22 - v12*v21; + output[Y] = v12*v20 - v10*v22; + output[Z] = v10*v21 - v11*v20; + + // Normalize the resulting vector and return it. + return normalize(output, output); + } + + /** + * Calculate the normal vector for a plane (triangle) defined + * by 3 points in space. The points must be specified in + * counterclockwise order. A new normal vector is created and + * returned by this method. + * + * @param pnt1 The 1st 3D point in the plane. + * @param pnt2 The 2nd 3D point in the plane. + * @param pnt3 The 3rd 3D point in the plane. + * @return A reference to the new 3D output normal vector. + **/ + public static final float[] calcNormal(float[] pnt1, float[] pnt2, float[] pnt3) { + if (pnt1.length != 3 || pnt2.length != 3 || pnt3.length != 3) + throw new IllegalArgumentException(kPoint3DMsg); + + // Calculate two vectors from e three points. + float v10 = pnt1[X] - pnt2[X]; + float v11 = pnt1[Y] - pnt2[Y]; + float v12 = pnt1[Z] - pnt2[Z]; + + float v20 = pnt2[X] - pnt3[X]; + float v21 = pnt2[Y] - pnt3[Y]; + float v22 = pnt2[Z] - pnt3[Z]; + + // Take the cross product of the two vectors and store in output. + float[] output = new float[3]; + output[X] = v11*v22 - v12*v21; + output[Y] = v12*v20 - v10*v22; + output[Z] = v10*v21 - v11*v20; + + // Normalize the resulting vector and return it. + return normalize(output, output); + } + + /** + * Returns the length of a 3D vector. + * + * @param vector A 3D (3 element) vector. + * @return The length of the input vector. + **/ + public static final float length3D(float[] vector) { + if (vector.length != 3) + throw new IllegalArgumentException(kVector3DMsg); + double dx = vector[X]; + double dy = vector[Y]; + double dz = vector[Z]; + return (float)Math.sqrt(dx*dx + dy*dy + dz*dz); + } + + /** + * Returns the dot product of two 3D vectors. + * + * @param a The 1st 3D (3 element) vector. + * @param b The 2nd 3D (3 element) vector. + * @return The dot product of the two vectors. + **/ + public static final float dotProduct3D(float[] a, float[] b) { + if (a.length != 3 || b.length != 3) + throw new IllegalArgumentException(kVector3DMsg); + return (a[X]*b[X] + a[Y]*b[Y] + a[Z]*b[Z]); + } + + /** + * Returns the right-handed cross product of 3D vectors A and B in AcrossB. + * + * @param A The 1st 3D (3 element) vector. + * @param B The 2nd 3D (3 element) vector. + * @param AcrossB A 3D (3 element) vector to be filled in with the cross + * product of A and B. This vector will be overwritten + * by this method. + * @return A reference to the input vector AcrossB. + **/ + public static final float[] crossProduct3D(float[] A, float[] B, float[] AcrossB) { + if (A.length != 3 || B.length != 3 || AcrossB.length != 3) + throw new IllegalArgumentException(kVector3DMsg); + AcrossB[X] = A[Y] * B[Z] - A[Z] * B[Y]; + AcrossB[Y] = A[Z] * B[X] - A[X] * B[Z]; + AcrossB[Z] = A[X] * B[Y] - A[Y] * B[X]; + return AcrossB; + } + + /** + * A method for calculating 3D Euclidian distance or length. + * + * @param dx The difference between X coordinates (X2 - X1). + * @param dy The difference between Y coordinates (Y2 - Y1). + * @param dz The difference between Z coordinates (Z2 - Z1). + * @return The distance between the two points. + **/ + public static final float distance(double dx, double dy, double dz) { + return (float)Math.sqrt(dx*dx + dy*dy + dz*dz); + } + + /** + * A method for calculating the distance between two + * points specified as arrays with 3 elements. + * + * @param pnt1 An array with 3 elements (X,Y,Z) representing the 1st point. + * @param pnt2 An array with 3 elements (X,Y,Z) representing the 2nd point. + * @return The distance between the two points. + **/ + public static final float distance(float[] pnt1, float[] pnt2) { + if (pnt1.length != 3 || pnt2.length != 3) + throw new IllegalArgumentException(kPoint3DMsg); + double dx = pnt2[X] - pnt1[X]; + double dy = pnt2[Y] - pnt1[Y]; + double dz = pnt2[Z] - pnt1[Z]; + return (float)Math.sqrt(dx*dx + dy*dy + dz*dz); + } + + /** + * A method for calculating the distance between two + * points specified as arrays with 3 elements. + * + * @param pnt1 An array with 3 elements (X,Y,Z) representing the 1st point. + * @param pnt2 An array with 3 elements (X,Y,Z) representing the 2nd point. + * @return The distance between the two points. + **/ + public static final float distance(int[] pnt1, int[] pnt2) { + if (pnt1.length != 3 || pnt2.length != 3) + throw new IllegalArgumentException(kPoint3DMsg); + double dx = pnt2[X] - pnt1[X]; + double dy = pnt2[Y] - pnt1[Y]; + double dz = pnt2[Z] - pnt1[Z]; + return (float)Math.sqrt(dx*dx + dy*dy + dz*dz); + } + + /** + * A fast approximation to 3D Euclidian distance or length! + * Accurate to within 13%. Also knowns as the "Manhattan" distance. + * This method approximates 3D distance as follows: + * + * dist = sqrt(dx*dx + dy*dy + dz*dz) + * approx. dist = max + (med + min)/4 + * + * Uses shifting and adding. No multiplication, division or sqrt calculations. + * + * @param dx The difference between X coordinates (X2 - X1). + * @param dy The difference between Y coordinates (Y2 - Y1). + * @param dz The difference between Z coordinates (Z2 - Z1). + * @return The approximate distance between two points. + **/ + public static final int distanceApprox(int dx, int dy, int dz) { + int maxc = dx > 0 ? dx:-dx; // Math.abs(dx); + int medc = dy > 0 ? dy:-dy; // Math.abs(dy); + int minc = dz > 0 ? dz:-dz; // Math.abs(dz); + + if (maxc < medc) { + int temp = maxc; + maxc = medc; + medc = temp; + } + if (maxc < minc) { + int temp = maxc; + maxc = minc; + minc = temp; + } + + medc += minc; + medc >>= 2; + maxc += medc; + + return maxc; + } + + /** + * A fast approximation to 2D Euclidian distance or length! + * Also knowns as the "Manhattan" distance. + * This method approximates 2D distance as follows: + * + * dist = sqrt(dx*dx + dy*dy) + * approx. dist = max + min/4 + * + * Uses shifting and adding. No multiplication, division or sqrt calculations. + * + * @param dx The difference between X coordinates (X2 - X1). + * @param dy The difference between Y coordinates (Y2 - Y1). + * @return The approximate distance between two points. + **/ + public static final int distanceApprox(int dx, int dy) { + int maxc = dx > 0 ? dx:-dx; // Math.abs(dx); + int minc = dy > 0 ? dy:-dy; // Math.abs(dy); + + if (maxc < minc) { + int temp = maxc; + maxc = minc; + minc = temp; + } + + minc >>= 2; + maxc += minc; + + return maxc; + } + + // **** The following are used by the CORDIC fixed point trigonometry routines **** + + private static final int COSCALE=0x11616E8E; // 291597966 = 0.2715717684432241*2^30, valid for j>13 + private static final int QUARTER = 90<<16; + private static final int MAXITER=22; + // Table of Cordic values for arctangent in degrees. + private static final int arctantab[] = { + 4157273, 2949120, 1740967, 919879, 466945, 234379, 117304, 58666, + 29335, 14668, 7334, 3667, 1833, 917, 458, 229, + 115, 57, 29, 14, 7, 4, 2, 1 + }; + private static int xtemp, ytemp; // Temporary storage space used by CORDIC methods. + + + /** + * Converts fixed point coordinates (b,a) to polar coordinates (r, theta) and + * returns the angle theta in degrees as a fixed point integer number. + * This method is about 40% faster than Math.atan2() using 22 iterations, + * but a small amount of accuracy is lost. It is 50% faster than Math.atan2() + * using 11 iterations and is still good to +/- 1 degree. + * This code is based on that found in "Cordic.c" by Ken Turkowski. + * + *

WARNING!! This method is not thread safe! It stores intermediate results in + * a static class variable. Sorry, needed to do that for speed.

+ * + * @param iter The number of CORDIC iterations to compute. Will be clamped to (1 <= iter <= 22). + * More iterations gives more accurate results, but takes longer. + * @param a The first fixed point coordinate value (a = (int)(y)<<16). + * @param b The 2nd fixed point coordinate value (b = (int)(x)<<16). + * @return The fixed point polar coordinate angle theta is returned (double theta = value/65536.). + * The angle returned is in degrees and is (0 <= theta < 360). + **/ + public static final int fixedAtan2D(int iter, int a, int b) { + if ((a == 0) && (b == 0)) + return 0; + + fxPreNorm(a, b); /* Prenormalize vector for maximum precision */ + + b = pseudoPolarize(xtemp, ytemp, iter); /* Convert to polar coordinates */ + + // Get into a 0 to 360 degree range. + b = 90*(1<<16) - b; + if (b < 0) + b += 360<<16; + return b; + } + + /** + * This method converts the fixed point input cartesian values + * to fixed point polar notation. On completion of this routine + * xtemp contains the radius and ytemp contains the angle. The + * angle is also returned by this method. + * This code is based on that found in "Cordic.c" by Ken Turkowski. + **/ + private static int pseudoPolarize(int x, int y, int iter) { + + /* Get the vector into the right half plane */ + int theta = 0; + if (x < 0) { + x = -x; + y = -y; + theta = 2*QUARTER; + } + + if (y > 0) + theta = -theta; + + int[] arctanptr = arctantab; + int yi = 0, pos = 0; + if (y < 0) { /* Rotate positive */ + yi = y + (x << 1); + x = x - (y << 1); + y = yi; + theta -= arctanptr[pos++]; /* Subtract angle */ + } + else { /* Rotate negative */ + yi = y - (x << 1); + x = x + (y << 1); + y = yi; + theta += arctanptr[pos++]; /* Add angle */ + } + + if (iter > MAXITER) + iter = MAXITER; + else if (iter < 1) + iter = 1; + + for (int i = 0; i <= iter; i++) { + if (y < 0) { /* Rotate positive */ + yi = y + (x >> i); + x = x - (y >> i); + y = yi; + theta -= arctanptr[pos++]; + } + else { /* Rotate negative */ + yi = y - (x >> i); + x = x + (y >> i); + y = yi; + theta += arctanptr[pos++]; + } + } + + xtemp = x; + ytemp = theta; + return theta; + } + + /** + * FxPreNorm() block normalizes the arguments to a magnitude suitable for + * CORDIC pseudorotations. The returned value is the block exponent. + * This code is based on that found in "Cordic.c" by Ken Turkowski. + **/ + private static int fxPreNorm(int x, int y) { + int signx=1, signy=1; + + if (x < 0) { + x = -x; + signx = -signx; + } + if (y < 0) { + y = -y; + signy = -signy; + } + + int shiftexp = 0; /* Block normalization exponent */ + + /* Prenormalize vector for maximum precision */ + if (x < y) { /* |y| > |x| */ + while (y < (1 << 27)) { + x <<= 1; + y <<= 1; + shiftexp--; + } + while (y > (1 << 28)) { + x >>= 1; + y >>= 1; + shiftexp++; + } + } + else { /* |x| > |y| */ + while (x < (1 << 27)) { + x <<= 1; + y <<= 1; + shiftexp--; + } + while (x > (1 << 28)) { + x >>= 1; + y >>= 1; + shiftexp++; + } + } + + xtemp = (signx < 0) ? -x : x; + ytemp = (signy < 0) ? -y : y; + return shiftexp; + } + + +} + -- cgit v1.2.3