/******************************************************************************
* Copyright (c) 2008 Marco Della Vedova, Matteo Foppiano
* and Pimods contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.pixelinstrument.net/license/cpl-v10.html
******************************************************************************/
package net.sf.robocode.bv3d.math;
import java.util.ArrayList;
/**
* @author Marco Della Vedova - pixelinstrument.net
* @author Matteo Foppiano - pixelinstrument.net
* @author Alessandro Martinelli - Universita' di Pavia
*/
/**
* A generic transform in a 3D world described with
* a 4x4 Matrix using the fourth omogeneous coordinate w.
* The Transform is internally supported by a Matrix Strack
* which allows the user to store the matrix values.
* @author Alessandro Martinelli - Universita' di Pavia
*/
public class Transform3f {
public class Matrix4f {
public float A, B, C, D;
public float E, F, G, H;
public float I, L, M, N;
public float O, P, Q, R;
}
;
private Matrix4f mM = new Matrix4f();
private ArrayList<Matrix4f> matrixStack = new ArrayList<Matrix4f>();
/**
* Push a copy of the actual Matrix4f on the internal matrix stack.
* */
public void pushMatrix() {
Matrix4f m = new Matrix4f();
m.A = mM.A;
m.B = mM.B;
m.C = mM.C;
m.D = mM.D;
m.E = mM.E;
m.F = mM.F;
m.G = mM.G;
m.H = mM.H;
m.I = mM.I;
m.L = mM.L;
m.M = mM.M;
m.N = mM.N;
m.O = mM.O;
m.P = mM.P;
m.Q = mM.Q;
m.R = mM.R;
matrixStack.add(m);
}
/**
* Pop the last Matrix4f from the stack and override the internal
* transform with the popped matrix values.
* True if the stack size is greater than zero,
* false if the stack size is zero
* */
public boolean popMatrix() {
if (matrixStack.size() > 0) {
Matrix4f m = matrixStack.get(matrixStack.size() - 1);
matrixStack.remove(matrixStack.size() - 1);
mM.A = m.A;
mM.B = m.B;
mM.C = m.C;
mM.D = m.D;
mM.E = m.E;
mM.F = m.F;
mM.G = m.G;
mM.H = m.H;
mM.I = m.I;
mM.L = m.L;
mM.M = m.M;
mM.N = m.N;
mM.O = m.O;
mM.P = m.P;
mM.Q = m.Q;
mM.R = m.R;
return(true);
}
return(false);
}
/**
* Construct a new Transform 3f
*/
public Transform3f() {
super();
loadIdentity();
}
/**
* converts this matrix into an identity matrix
* */
public void loadIdentity() {
mM.A = 1;
mM.B = 0;
mM.C = 0;
mM.D = 0;
mM.E = 0;
mM.F = 1;
mM.G = 0;
mM.H = 0;
mM.I = 0;
mM.L = 0;
mM.M = 1;
mM.N = 0;
mM.O = 0;
mM.P = 0;
mM.Q = 0;
mM.R = 1;
}
/**
* Multiply this Matrix for a Translation Matrix, where the vector (x,y,z) the
* translation entity
* */
public void translate(float x, float y, float z) {
Transform3f t = new Transform3f();
t.mM.D = x;
t.mM.H = y;
t.mM.N = z;
t.mM.R = 1;
mult(t);
}
/**
* Multiply this Matrix for a Scaling Matrix, where sx,sy and sz are
* the scaling factors
* */
public void scale(float sx, float sy, float sz) {
Transform3f t = new Transform3f();
t.mM.A = sx;
t.mM.F = sy;
t.mM.M = sz;
t.mM.R = 1;
mult(t);
}
/**
* Multiply this Matrix for a General Rotation: alpha is
* the rotation angle in radians and (x,y,z) is the
* direction of the rotation ax
* */
public void rotateGeneral(float alpha, float x, float y, float z) {
// Direction3f dir=new Direction3f(x,y,z);
Vertex3f dir = new Vertex3f(x, y, z);
dir.normalize();
// Direction3f A=dir.getNormalCandidate();
Vertex3f A = dir.getNormalCandidate();
A.normalize();
Vertex3f B = dir.getVectorProduct(A);
// Direction3f B=dir.getVectorProduct(A);
// Construct a Third Vector B normal to Both V and A
Transform3f t = new Transform3f();
float cos = (float) (Math.cos(alpha));
float sin = (float) (Math.sin(alpha));
t.mM.A = dir.getX();
t.mM.B = A.getX();
t.mM.C = B.getX();
t.mM.E = dir.getY();
t.mM.F = A.getY();
t.mM.G = B.getY();
t.mM.I = dir.getZ();
t.mM.L = A.getZ();
t.mM.M = B.getZ();
mult(t);
t.mM.A = dir.getX();
t.mM.B = dir.getY();
t.mM.C = dir.getZ();
t.mM.E = A.getX() * cos - B.getX() * sin;
t.mM.F = A.getY() * cos - B.getY() * sin;
t.mM.G = A.getZ() * cos - B.getZ() * sin;
t.mM.I = A.getX() * sin + B.getX() * cos;
t.mM.L = A.getY() * sin + B.getY() * cos;
t.mM.M = A.getZ() * sin + B.getZ() * cos;
mult(t);
}
/**
* Multiply this Matrix for a Rotation of an angle alpha (in radians)
* around the X ax
* */
public void rotateX(float alpha) {
Transform3f t = new Transform3f();
float cos = (float) (Math.cos(alpha));
float sin = (float) (Math.sin(alpha));
t.mM.F = cos;
t.mM.G = -sin;
t.mM.L = sin;
t.mM.M = cos;
mult(t);
}
/**
* Multiply this Matrix for a Rotation of an angle alpha (in radians)
* around the Y ax
* */
public void rotateY(float alpha) {
Transform3f t = new Transform3f();
float cos = (float) (Math.cos(alpha));
float sin = (float) (Math.sin(alpha));
t.mM.A = cos;
t.mM.C = -sin;
t.mM.I = sin;
t.mM.M = cos;
mult(t);
}
/**
* Multiply this Matrix for a Rotation of an angle alpha (in radians)
* around the Z ax
* */
public void rotateZ(float alpha) {
Transform3f t = new Transform3f();
float cos = (float) (Math.cos(alpha));
float sin = (float) (Math.sin(alpha));
t.mM.A = cos;
t.mM.B = -sin;
t.mM.E = sin;
t.mM.F = cos;
mult(t);
}
/**
* Multiply the vertex v for this Matrix and override v with the result.
* Return the omogeneus component of the transformation
* */
public float mult(Vertex3f v) {
float x = v.getX();
float y = v.getY();
float z = v.getZ();
v.setX(mM.A * x + mM.B * y + mM.C * z + mM.D);
v.setY(mM.E * x + mM.F * y + mM.G * z + mM.H);
v.setZ(mM.I * x + mM.L * y + mM.M * z + mM.N);
return(mM.O * x + mM.P * y + mM.Q * z + mM.R);
}
/**
* Multiply this Transform (M) with another transform t,
* so that M'=Mt and override this transorm with the result
* */
public void mult(Transform3f t) {
float A = mM.A * t.mM.A + mM.B * t.mM.E + mM.C * t.mM.I + mM.D * t.mM.O;
float B = mM.A * t.mM.B + mM.B * t.mM.F + mM.C * t.mM.L + mM.D * t.mM.P;
float C = mM.A * t.mM.C + mM.B * t.mM.G + mM.C * t.mM.M + mM.D * t.mM.Q;
float D = mM.A * t.mM.D + mM.B * t.mM.H + mM.C * t.mM.N + mM.D * t.mM.R;
float E = mM.E * t.mM.A + mM.F * t.mM.E + mM.G * t.mM.I + mM.H * t.mM.O;
float F = mM.E * t.mM.B + mM.F * t.mM.F + mM.G * t.mM.L + mM.H * t.mM.P;
float G = mM.E * t.mM.C + mM.F * t.mM.G + mM.G * t.mM.M + mM.H * t.mM.Q;
float H = mM.E * t.mM.D + mM.F * t.mM.H + mM.G * t.mM.N + mM.H * t.mM.R;
float I = mM.I * t.mM.A + mM.L * t.mM.E + mM.M * t.mM.I + mM.N * t.mM.O;
float L = mM.I * t.mM.B + mM.L * t.mM.F + mM.M * t.mM.L + mM.N * t.mM.P;
float M = mM.I * t.mM.C + mM.L * t.mM.G + mM.M * t.mM.M + mM.N * t.mM.Q;
float N = mM.I * t.mM.D + mM.L * t.mM.H + mM.M * t.mM.N + mM.N * t.mM.R;
float O = mM.O * t.mM.A + mM.P * t.mM.E + mM.Q * t.mM.I + mM.R * t.mM.O;
float P = mM.O * t.mM.B + mM.P * t.mM.F + mM.Q * t.mM.L + mM.R * t.mM.P;
float Q = mM.O * t.mM.C + mM.P * t.mM.G + mM.Q * t.mM.M + mM.R * t.mM.Q;
float R = mM.O * t.mM.D + mM.P * t.mM.H + mM.Q * t.mM.N + mM.R * t.mM.R;
mM.A = A;
mM.E = E;
mM.I = I;
mM.O = O;
mM.B = B;
mM.F = F;
mM.L = L;
mM.P = P;
mM.C = C;
mM.G = G;
mM.M = M;
mM.Q = Q;
mM.D = D;
mM.H = H;
mM.N = N;
mM.R = R;
}
/**
* @return the mainMatrix
*/
public Matrix4f getMainMatrix() {
return mM;
}
/**
* @param mainMatrix the mainMatrix to set
*/
public void setMainMatrix(Matrix4f mainMatrix) {
this.mM = mainMatrix;
}
public static Transform3f GenerateProjectionToPlaneMatrix(Vertex3f f, Vertex3f pPos, Vertex3f pN) {
Transform3f t = new Transform3f();
/**
* Proiezione sul piano...
*
* P' e` l'intersezione del piano (P'-Q)N=0
* con la retta P'=(F+t(P-F))
*
* ( F +t(P-F) -Q )N=0
*
* -> t=(Q-F)N/(P-F)N
*
* P'=F+(P-F)*t
*
* Allora...
*
* k=(Q-F)N
*
* X'=(xf*W'+(x-xf)*k)/W'
* Y'=(yf*W'+(y-yf)*k)/W'
* Z'=(zf*W'+(z-zf)*k)/W'
* W'=P*N-F*N;
*
* X'=(xf*(x+*xN+y*Yn+z*ZN-F*N)+(x-xf)*k)/W'
* Y'=(yf*(x+*xN+y*Yn+z*ZN-F*N)+(y-yf)*k)/W'
* Z'=(zf*(x+*xN+y*Yn+z*ZN-F*N)+(z-zf)*k)/W'
*
* */
float k = (pN.getX() * (pPos.getX() - f.getX()) + pN.getY() * (pPos.getY() - f.getY())
+ pN.getZ() * (pPos.getZ() - f.getZ()));
t.mM.O = pN.getX();
t.mM.P = pN.getY();
t.mM.Q = pN.getZ();
t.mM.R = -(pN.getX() * f.getX() + pN.getY() * f.getY() + pN.getZ() * f.getZ());
float fn = t.mM.R;
// X'=(xf*(x+*xN+y*Yn+z*ZN-F*N)+(x-xf)*k)
t.mM.A = f.getX() * (pN.getX()) + k;
t.mM.B = f.getX() * (pN.getY());
t.mM.C = f.getX() * (pN.getZ());
t.mM.D = f.getX() * (fn - k);
t.mM.E = f.getY() * (pN.getX());
t.mM.F = f.getY() * (pN.getY()) + k;
t.mM.G = f.getY() * (pN.getZ());
t.mM.H = f.getY() * (fn - k);
t.mM.I = f.getZ() * (pN.getX());
t.mM.L = f.getZ() * (pN.getY());
t.mM.M = f.getZ() * (pN.getZ()) + k;
t.mM.N = f.getZ() * (fn - k);
return(t);
}
public float[] getAsFloat() {
float[] f = new float[16];
f[0] = mM.A;
f[4] = mM.B;
f[8] = mM.C;
f[12] = mM.D;
f[1] = mM.E;
f[5] = mM.F;
f[9] = mM.G;
f[13] = mM.H;
f[2] = mM.I;
f[6] = mM.L;
f[10] = mM.M;
f[14] = mM.N;
f[3] = mM.O;
f[7] = mM.P;
f[11] = mM.Q;
f[15] = mM.R;
/*
*x=4x;
*y=4y+1
*z=4z
*w=4x-12y+4z-4
*
* esempi..
*
* (1,2,0)
*
* 4,9,0,
*
*
*/
return(f);
}
}