/***********************************************************************
* mt4j Copyright (c) 2008 - 2009 C.Ruff, Fraunhofer-Gesellschaft All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
***********************************************************************/
package org.mt4j.util.math;
import java.awt.Point;
/**
* ************************************************
* Homogenous 3D vector class with 4 components, X, Y, Z and W.
*
* @author Christopher Ruff
* ************************************************
*/
public class Vector3D {
/** The w. */
public float x, y, z, w;
/** The type. */
private transient int type;
/** The Constant VECTOR. */
public static final int VECTOR = 0;
/** The Constant VERTEX. */
public static final int VERTEX = 1;
/** The Constant BEZIERVERTEX. */
public static final int BEZIERVERTEX = 2;
/** Zero vector (0,0,0). */
public static final Vector3D ZERO_VECTOR = new Vector3D(0,0,0);
/** Defines positive X axis. */
public static final Vector3D X_AXIS = new Vector3D(1, 0, 0);
/** Defines positive Y axis. */
public static final Vector3D Y_AXIS = new Vector3D(0, 1, 0);
/** Defines positive Z axis. */
public static final Vector3D Z_AXIS = new Vector3D(0, 0, 1);
/**
* Instantiates a new vector3 d.
*/
public Vector3D() {
this(0,0,0,1);
}
/**
* Instantiates a new vector3 d.
*
* @param x the x
* @param y the y
*/
public Vector3D(float x, float y){
this(x,y,0);
}
/**
* Instantiates a new vector3 d.
*
* @param x the x
* @param y the y
* @param z the z
*/
public Vector3D(float x, float y, float z){
this(x,y,z,1);
}
/**
* Instantiates a new vector3 d.
*
* @param x the x
* @param y the y
* @param z the z
* @param w the w
*/
public Vector3D(float x, float y, float z, float w){
this.x = x;
this.y = y;
this.z = z;
this.w = w;
this.setType(Vector3D.VECTOR);
}
/**
* Instantiates a new vector3 d.
*
* @param v the v
*/
public Vector3D(Vector3D v) {
this(v.getX(),v.getY(),v.getZ(),v.getW());
}
/**
* Gets the deep vertex array copy.
* Uses the getCopy() method on each vector.
*
* @param vertices the vertices
*
* @return the deep vertex array copy
*/
public static Vector3D[] getDeepVertexArrayCopy(Vector3D[] vertices){
Vector3D[] copy = new Vector3D[vertices.length];
for (int i = 0; i < vertices.length; i++) {
Vector3D vertex = vertices[i];
copy[i] = vertex.getCopy();
}
return copy;
}
/**
* Applies a transformation on the vector
* defined by the given tranformation matrix.
*
* @param transformMatrix the transform matrix
*/
public void transform(Matrix transformMatrix){
transformMatrix.mult(this);
}
//TODO reicht es den W coord des Vectors auf 0 zu setzen?
//FIXME eigentlich sollte man direction vectoren wie normale
//transformieren also mit transformNormal, aber so gehts auch meistens..why?
/**
* Transforms a direction vector, not a point.
* Ignores the translation part of the matrix
*
* @param transformMatrix the transform matrix
*/
public void transformDirectionVector(Matrix transformMatrix){
Matrix m = new Matrix(transformMatrix);
m.removeTranslationFromMatrix();
this.transform(m);
}
/**
* Transforms a normal or direction vector.
* This is done by multiplying the vector with the
* inverse transpose of the matrix.
* <p>
* <strong>NOTE</strong>: this is not cheap because a new matrix is created (copied)
* inverted and then transposed.<p>
* (If you can supply a precomputed inverted matrix yourself, write
* yourself a method that doesent do the invert() call :))
*
* @param transformMatrix the transform matrix
*/
public void transformNormal(Matrix transformMatrix){
Matrix inverse = transformMatrix.invert();
// this.setW(0);
try {
Matrix transpose = inverse.transpose();
transpose.mult(this,this);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Multiplicates all Vector3D of the Vector3D array with the given
* transformation matrix, thus transforming them.
* Make a deepcopy of the vectors first if you dont want the originals being altered!
*
* @param transformMatrix the transform matrix
* @param points the points
*
* @return the transformed vector array
*/
public static Vector3D[] transFormArrayLocal(Matrix transformMatrix, Vector3D[] points){
for (Vector3D v : points)
v.transform(transformMatrix);
return points;
}
/**
* Translate.
*
* @param directionVector the direction vector
*/
public void translate(Vector3D directionVector){
this.transform(Matrix.getTranslationMatrix(directionVector.getX(), directionVector.getY(), directionVector.getZ()));
}
/**
* translates an array of Vector3D by the given amounts in the directionvector.
*
* @param inputArray the input array
* @param directionVector the direction vector
*
* @return the vector3 d[]
*/
public static Vector3D[] translateVectorArray(Vector3D[] inputArray, Vector3D directionVector){
return Vector3D.transFormArrayLocal(Matrix.getTranslationMatrix(directionVector.getX(), directionVector.getY(), directionVector.getZ())
, inputArray);
}
/**
* Rotate x.
*
* @param rotationPoint the rotation point
* @param degree the degree
*/
public void rotateX(Vector3D rotationPoint, float degree ){
this.transform(Matrix.getXRotationMatrix(rotationPoint, degree));
}
/**
* rotates the Vector3D array around the rotationpoint by the given degree.
*
* @param rotationPoint the rotation point
* @param degree the degree
* @param inputArray the input array
*
* @return the rotated vector3D array
*/
public static Vector3D[] rotateXVectorArray(Vector3D[] inputArray, Vector3D rotationPoint, float degree ){
return Vector3D.transFormArrayLocal(Matrix.getXRotationMatrix(rotationPoint, degree),inputArray);
}
/**
* Rotate y.
*
* @param rotationPoint the rotation point
* @param degree the degree
*/
public void rotateY(Vector3D rotationPoint, float degree ){
this.transform(Matrix.getYRotationMatrix(rotationPoint, degree));
}
/**
* rotates the Vector3D array around the rotationpoint by the given degree.
*
* @param rotationPoint the rotation point
* @param degree the degree
* @param inputArray the input array
*
* @return the rotated vector3D array
*/
public static Vector3D[] rotateYVectorArray(Vector3D[] inputArray, Vector3D rotationPoint, float degree ){
return Vector3D.transFormArrayLocal(Matrix.getYRotationMatrix(rotationPoint, degree), inputArray);
}
/**
* Rotate z.
*
* @param rotationPoint the rotation point
* @param degree the degree
*/
public void rotateZ(Vector3D rotationPoint, float degree ){
this.transform(Matrix.getZRotationMatrix(rotationPoint, degree));
}
/**
* Rotates the vector by the given angle around the X axis.
*
* @param theta the theta
*
* @return itself
*/
public final Vector3D rotateX(float theta) {
float co = (float) Math.cos(theta);
float si = (float) Math.sin(theta);
float zz = co * z - si * y;
y = si * z + co * y;
z = zz;
return this;
}
/**
* Rotates the vector by the given angle around the Y axis.
*
* @param theta the theta
*
* @return itself
*/
public final Vector3D rotateY(float theta) {
float co = (float) Math.cos(theta);
float si = (float) Math.sin(theta);
float xx = co * x - si * z;
z = si * x + co * z;
x = xx;
return this;
}
/**
* Rotates the vector by the given angle around the Z axis.
* RADIANS EXPECTED!
* @param theta the theta
*
* @return itself
*/
public final Vector3D rotateZ(float theta) {
// /*
float co = (float) Math.cos(theta);
float si = (float) Math.sin(theta);
float xx = co * x - si * y;
y = si * x + co * y;
x = xx;
return this;
// */
}
/**
* rotates the Vector3D array around the rotationpoint by the given degree.
*
* @param rotationPoint the rotation point
* @param degree the degree
* @param inputArray the input array
*
* @return the rotated vector3D array
*/
public static Vector3D[] rotateZVectorArray(Vector3D[] inputArray, Vector3D rotationPoint, float degree ){
return Vector3D.transFormArrayLocal(Matrix.getZRotationMatrix(rotationPoint, degree), inputArray);
}
/**
* Scale the vector by factor.
*
* @param scalar the scalar
*
* @return the vector after scaling
*/
public Vector3D scaleLocal(float scalar) {
this.setXYZ(this.x * scalar, this.y * scalar, this.z * scalar ) ;
return this;
}
public Vector3D divideLocal(float scalar) {
scalar = 1f/scalar;
x *= scalar;
y *= scalar;
z *= scalar;
return this;
}
/**
* Gets the scaled.
*
* @param scalar the scalar
*
* @return the scaled
*
* a new scaled vector
*/
public Vector3D getScaled(float scalar) {
return new Vector3D(this.x * scalar, this.y * scalar, this.z * scalar);
}
/**
* scales the Vector3D[] around the scalingpoint by the given factor evenly in the X and Y direction.
*
* @param inputArray the input array
* @param scalingPoint the scaling point
* @param factor the factor
*
* @return the resulting vector array
*/
public static Vector3D[] scaleVectorArray(Vector3D[] inputArray, Vector3D scalingPoint, float factor) {
return Vector3D.transFormArrayLocal(Matrix.getScalingMatrix(scalingPoint, factor,factor,factor), inputArray);
}
/**
* scales the Vector3D[] around the scalingpoint by the factors given for each dimension.
*
* @param inputArray the input array
* @param scalingPoint the scaling point
* @param X the x
* @param Y the y
* @param Z the z
*
* @return the resulting vector array
*/
public static Vector3D[] scaleVectorArray(Vector3D[] inputArray, Vector3D scalingPoint, float X, float Y, float Z) {
return Vector3D.transFormArrayLocal(Matrix.getScalingMatrix(scalingPoint, X, Y, Z), inputArray);
}
/**
* Add a vector to this vector.
*
* @param v the v
*
* @return the vector after the addition
*/
public Vector3D addLocal(Vector3D v) {
this.setX(x + v.getX());
this.setY(y + v.getY());
this.setZ(z + v.getZ());
return this;
}
/**
* Gets the added.
*
* @param v the v
*
* @return an new Vector with the result of the addition
*/
public Vector3D getAdded(Vector3D v){
return new Vector3D(x + v.getX() , y + v.getY(), z + v.getZ());
}
/**
* NOTE: texture coordinates of the calling vector are kept.
*
* @param v the v
*
* @return an new Vector with the result of the subtraction
*/
public Vector3D getSubtracted(Vector3D v){
return new Vector3D(x - v.getX() , y - v.getY(), z - v.getZ());
}
/**
* Subtract a vector from this vector.
*
* @param v the v
*
* @return TODO
*/
public Vector3D subtractLocal(Vector3D v) {
this.setX(x - v.getX());
this.setY(y - v.getY());
this.setZ(z - v.getZ());
return this;
}
/**
* Scales vector uniformly by factor -1 ( v = -v ), overrides coordinates
* with result.
*
* @return itself
*/
public Vector3D invertLocal() {
x *= -1;
y *= -1;
z *= -1;
return this;
}
/**
* Scales vector uniformly by factor -1 ( v = -v ), overrides coordinates
* with result.
*
* @return itself
*/
public Vector3D getInverted() {
return new Vector3D(x*-1, y*-1, z*-1);
}
/**
* Interpolates the vector towards the given target vector, using linear
* interpolation.
*
* @param v target vector
* @param f interpolation factor (should be in the range 0..1)
*
* @return result as new vector
*/
public final Vector3D getInterpolatedTo(Vector3D v, float f) {
return new Vector3D(x + (v.x - x) * f, y + (v.y - y) * f, z + (v.z - z)
* f);
}
/**
* Copy the vector.
*
* @return a copy of the vector
*/
public Vector3D getCopy() {
return new Vector3D(x, y, z, w);
}
/**
* Calculate the magnitude (length) of the vector.
*
* @return the magnitude of the vector
*/
public float length() {
return (float) Math.sqrt(x*x + y*y + z*z);
}
/**
* Calculates only the squared magnitude/length of the vector. Useful for
* inverse square law applications and/or for speed reasons or if the real
* eucledian distance is not required (e.g. sorting).
*
* @return squared magnitude (x^2 + y^2 + z^2)
*/
public float lengthSquared() {
return x * x + y * y + z * z;
}
/**
* Calculate the cross product with another vector. And returns
* a new vector as the result.
*
* @param v the v
*
* @return the cross product, a new vector
*/
public Vector3D getCross(Vector3D v) {
float crossX = y * v.getZ() - v.getY() * z;
float crossY = z * v.getX() - v.getZ() * x;
float crossZ = x * v.getY() - v.getX() * y;
return new Vector3D(crossX,crossY,crossZ);
}
/**
* Calcs the cross and sets the new values to this vector.
*
* @param v the v
*
* @return the Vector after the cross operation
*/
public Vector3D crossLocal(Vector3D v) {
float crossX = y * v.getZ() - v.getY() * z;
float crossY = z * v.getX() - v.getZ() * x;
float crossZ = x * v.getY() - v.getX() * y;
this.setXYZ(crossX, crossY, crossZ);
return this;
}
/**
* Calculate the dot product with another vector.
*
* @param v the v
*
* @return the dot product
*/
public float dot(Vector3D v) {
float dot = this.x * v.x + this.y * v.y + this.z * v.z;
return dot;
} //(x * v.x + y * v.y + z * v.z);
/**
* Normalize the vector to length 1 (make it a unit vector).
*
* @return the same vector after normalization
*/
public Vector3D normalizeLocal() {
// float m = length();
// if (m > 0) {
// this.setX(x / m);
// this.setY(y / m);
// this.setZ(z / m);
// }
float length = length();
if (length != 0) {
float scalar = length;
scalar = 1f/scalar;
x *= scalar;
y *= scalar;
z *= scalar;
}
return this;
}
/**
* Normalize the vector to length 1 (make it a unit vector).
*
* @return a NEW vector after normalization of this vector
*/
public Vector3D getNormalized() {
Vector3D n = this;
float length = length();
if (length != 0) {
float scalar = length;
scalar = 1f/scalar;
n = new Vector3D(this.x*scalar, this.y*scalar, this.z*scalar);
}
return n;
}
/**
* Limits the vector to the given length .
*
* @param lim new maximum magnitude
* @return the limited vector
*/
public final Vector3D limitLocal(float lim) {
if (this.lengthSquared() > lim * lim) {
normalizeLocal();
scaleLocal(lim);
}
return this;
}
/**
* Creates a copy of the vector with its magnitude limited to the length
* given.
*
* @param lim new maximum magnitude
*
* @return result as new vector
*/
public final Vector3D getLimited(float lim) {
if (this.lengthSquared() > lim * lim) {
Vector3D norm = this.getCopy();
norm.normalizeLocal();
norm.scaleLocal(lim);
return norm;
}
return new Vector3D(this);
}
/**
* Rotates the vector around the giving axis.
*
* @param axis rotation axis vector
* @param theta rotation angle (in radians)
*
* @return itself
*/
public final Vector3D rotateAroundAxisLocal(Vector3D axis, float theta) {
float ux = axis.x * x;
float uy = axis.x * y;
float uz = axis.x * z;
float vx = axis.y * x;
float vy = axis.y * y;
float vz = axis.y * z;
float wx = axis.z * x;
float wy = axis.z * y;
float wz = axis.z * z;
double si = Math.sin(theta);
double co = Math.cos(theta);
float xx = (float) (axis.x
* (ux + vy + wz)
+ (x * (axis.y * axis.y + axis.z * axis.z) - axis.x * (vy + wz))
* co + (-wy + vz) * si);
float yy = (float) (axis.y
* (ux + vy + wz)
+ (y * (axis.x * axis.x + axis.z * axis.z) - axis.y * (ux + wz))
* co + (wx - uz) * si);
float zz = (float) (axis.z
* (ux + vy + wz)
+ (z * (axis.x * axis.x + axis.y * axis.y) - axis.z * (ux + vy))
* co + (-vx + uy) * si);
x = xx;
y = yy;
z = zz;
return this;
}
/**
* Calculate the Euclidean distance between two points (considering a point as a vector object).
*
* @param v2 another vector
* @param v1 the v1
*
* @return the Euclidean distance between v1 and v2
*/
public static float distance (Vector3D v1, Vector3D v2) {
float dx = v1.getX() - v2.getX();
float dy = v1.getY() - v2.getY();
float dz = v1.getZ() - v2.getZ();
return (float) Math.sqrt(dx*dx + dy*dy + dz*dz);
}
/**
* Calculate the Euclidean distance between two points (considering a point as a vector object).
*
* @param v2 the v2
*
* @return the float
*/
public float distance(Vector3D v2){
float dx = this.getX() - v2.getX();
float dy = this.getY() - v2.getY();
float dz = this.getZ() - v2.getZ();
return (float) Math.sqrt(dx*dx + dy*dy + dz*dz);
}
/**
* Calculate the Euclidean distance between two points (considering a point as a vector object).
*
* @param v2 another vector
* @param v1 the v1
*
* @return the Euclidean distance between v1 and v2
*/
public static float distance2D (Vector3D v1, Vector3D v2) {
float dx = v1.getX() - v2.getX();
float dy = v1.getY() - v2.getY();
return (float) Math.sqrt(dx*dx + dy*dy );
}
/**
* Calculate the Euclidean distance between two points (considering a point as a vector object).
* Disregards the Z component of the vectors and is thus a little faster.
*
* @param v2 another vector
*
* @return the Euclidean distance between this and v2
*/
public float distance2D (Vector3D v2) {
float dx = this.getX() - v2.getX();
float dy = this.getY() - v2.getY();
return (float) Math.sqrt(dx*dx + dy*dy );
}
/**
* Calculate the Euclidean distance between two points (considering a point as a vector object).
*
* @param v2 another vector
* @param v1 the v1
*
* @return the Euclidean distance between v1 and v2 squared
*/
public static float distanceSquared (Vector3D v1, Vector3D v2) {
if (v2 != null) {
float dx = v1.x - v2.x;
float dy = v1.y - v2.y;
float dz = v1.z - v2.z;
return dx * dx + dy * dy + dz * dz;
} else {
return Float.NaN;
}
}
/**
* Calculate the angle between two vectors, using the dot product.
*
* @param v2 another vector
* @param v1 the v1
*
* @return the angle between the vectors in radians
*/
// FIXME this produces an not 0.0 angle for equal vectors sometimes..why?
public static float angleBetween(Vector3D v1, Vector3D v2) {
// Vector3D v1Copy = v1.getCopy();
// Vector3D v2Copy = v2.getCopy();
//
// v1Copy.normalize();
// v2Copy.normalize();
//
// float dotP = v1Copy.dot(v2Copy);
// System.out.println("Dot:" + dotP);
// float theta = (float)Math.acos(dotP);
// float dot = v1.dot(v2);
// float theta = FastMath.acos(dot / (v1.length() * v2.length()));
// return theta;
return v1.angleBetween(v2);
}
/**
* Calculate the angle between two vectors, using the dot product.
*
* @param v2 another vector
*
* @return the angle between the vectors in radians
*/
// FIXME this produces an not 0.0 angle for equal vectors sometimes..why?
public float angleBetween(Vector3D v2) {
float dot = this.dot(v2);
float theta = ToolsMath.acos(dot / (this.length() * v2.length()));
return theta;
}
/**
* sets a new X coordinate value for the vector.
*
* @param x the x
*/
public void setX(float x) {
this.x = x;
}
/**
* sets a new Y coordinate value for the vector.
*
* @param y the y
*/
public void setY(float y) {
this.y = y;
}
/**
* sets a new Z coordinate value for the vector.
*
* @param z the z
*/
public void setZ(float z) {
this.z = z;
}
/**
* sets new values for the vector.
*
* @param x the x
* @param y the y
* @param z the z
*/
public void setXYZ(float x, float y, float z){
this.x = x;
this.y = y;
this.z = z;
}
/**
* sets new values for the vector.
*
* @param x the x
* @param y the y
* @param z the z
* @param w the w
*/
public void setXYZW(float x, float y, float z, float w){
this.setXYZ(x, y, z);
this.w = w;
}
/**
* Converts the 3D homogenous vector to a 2D jawa.awt.point, throwing away the Z-Value
*
* @return the point
*/
public Point getJava2DPoint(){
return new Point(Math.round(x),Math.round(y));
}
/**
* Gets the y.
*
* @return the Y value of the 3D Vector
*/
public float getY(){
return y;
}
/**
* Gets the z.
*
* @return the Z value of the 3D Vector
*/
public float getZ(){
return z;
}
/**
* Gets the x.
*
* @return the X value of the 3D Vector
*/
public float getX(){
return x;
}
/**
* Gets the w.
*
* @return the W
*
* the W value of the 3D Vector
*/
public float getW() {
return w;
}
/**
* Sets the w.
*
* @param w the new w
*/
public void setW(float w) {
this.w = w;
}
/**
* Sets the.
*
* @param i the i
* @param value the value
*/
public void set(int i, float value){
if (i == 0)
x = value;
else if(i == 1)
y = value;
else if(i == 2)
z = value;
else if(i == 3)
w = value;
else{
System.err.println("illegal vector dimension");
}
}
///
/**
* Returns an integer in case of:
* <br>VECTOR = 0;
* <br>VERTEX = 1;
* <br>BEZIERVERTEX = 2;.
*
* @return the type
*
* the integer identifying this object
*/
public int getType() {
return type;
}
/**
* Sets the type. This should only be called
* by extending classes to determine their type.
*
* @param type the type
*/
protected void setType(int type) {
this.type = type;
}
/**
* Checks if the two vectors have the same components (XYZW).
* <br>Does NOT check for object identity equality!
*
* @param vector3D the vector3 d
*
* @return true, if equals vector
*/
public boolean equalsVector(Vector3D vector3D){
return ( this.getX() == vector3D.getX()
&& this.getY() == vector3D.getY()
&& this.getZ() == vector3D.getZ()
&& this.getW() == vector3D.getW()
);
}
/**
* Checks if the two vectors have the same components (XYZW) in the range of a
* specified tolerance.
* <br>Does NOT check for object identity equality!
* <br>NOTE: checks each component of the vector individually, so the overall difference
* might be greater than the given tolerance!
*
* @param vec the vec
* @param tolerance the tolerance
*
* @return true, if equals vector with tolerance
*/
public boolean equalsVectorWithTolerance(Vector3D vec, float tolerance){
return ( Math.abs(this.getX() - vec.getX()) <= tolerance
&& Math.abs(this.getY() - vec.getY()) <= tolerance
&& Math.abs(this.getZ() - vec.getZ()) <= tolerance
&& Math.abs(this.getW() - vec.getW()) <= tolerance
);
}
/**
* Saves this Vector3f into the given float[] object.
*
* @param floats The float[] to take this Vector3f. If null, a new float[3] is
* created.
*
* @return The array, with X, Y, Z float values in that order
*/
public float[] toArray(float[] floats) {
if (floats == null) {
floats = new float[3];
}
floats[0] = x;
floats[1] = y;
floats[2] = z;
return floats;
}
/**
* Sets the values of another vector.
*
* @param otherVector the new values
*
* @return the vector3 d
*/
public Vector3D setValues(Vector3D otherVector){
this.x = otherVector.x;
this.y = otherVector.y;
this.z = otherVector.z;
this.w = otherVector.w;
return this;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString(){
return new String(/*super.toString() +*/ " X:" + this.getX()+ " Y:" + this.getY() + " Z:" + this.getZ() + " W:" + this.getW());
}
// //TODO CHECK IF THIS WORKS; TOO
// /*
// /**
// * Transform the provided vector by the matrix and place it back in
// * the vector.
// *
// * @param vec The vector to be transformed
// * @param mat The matrix to do the transforming with
// * @param out The vector to be put the result in
// */
// private void transform(Tuple3f vec, Matrix4f mat, Tuple3d out)
// {
// float a = vec.x;
// float b = vec.y;
// float c = vec.z;
//
// out.x = mat.m00 * a + mat.m01 * b + mat.m02 * c + mat.m03;
// out.y = mat.m10 * a + mat.m11 * b + mat.m12 * c + mat.m13;
// out.z = mat.m20 * a + mat.m21 * b + mat.m22 * c + mat.m23;
// }
//
// /**
// * Transform the provided vector by the matrix and place it back in
// * the vector. The fourth element is assumed to be zero for normal
// * transformations.
// *
// * @param vec The vector to be transformed
// * @param mat The matrix to do the transforming with
// * @param out The vector to be put the result in
// */
// private void transformNormal(Tuple3d vec, Matrix4f mat, Tuple3d out)
// {
// float a = (float)vec.x;
// float b = (float)vec.y;
// float c = (float)vec.z;
//
// out.x = mat.m00 * a + mat.m01 * b + mat.m02 * c;
// out.y = mat.m10 * a + mat.m11 * b + mat.m12 * c;
// out.z = mat.m20 * a + mat.m21 * b + mat.m22 * c;
// }
//
// /**
// * Transform the provided vector by the matrix and place it back in
// * the vector. The fourth element is assumed to be zero for normal
// * transformations.
// *
// * @param vec The vector to be transformed
// * @param mat The matrix to do the transforming with
// * @param out The vector to be put the result in
// */
// private void transformNormal(Tuple3f vec, Matrix4f mat, Tuple3d out)
// {
// float a = vec.x;
// float b = vec.y;
// float c = vec.z;
//
// out.x = mat.m00 * a + mat.m01 * b + mat.m02 * c;
// out.y = mat.m10 * a + mat.m11 * b + mat.m12 * c;
// out.z = mat.m20 * a + mat.m21 * b + mat.m22 * c;
// }
//}
// */
}