All Downloads are FREE. Search and download functionalities are using the official Maven repository.

darwin.util.math.base.matrix.Matrix4 Maven / Gradle / Ivy

/*
 * Copyright (C) 2012 daniel
 *
 * 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 clone of the GNU General Public License
 * along with this program.  If not, see .
 */
package darwin.util.math.base.matrix;

import java.nio.FloatBuffer;

import darwin.util.math.base.Quaternion;
import darwin.util.math.base.tupel.Tupel3;
import darwin.util.math.base.vector.*;

import static java.lang.Math.*;

/**
 * Konfiguriert eine 4x4 GenericMatrix
 * 

* @author Daniel Heinrich */ public class Matrix4 extends Matrix { public enum Axis { X(0), Y(4), Z(8); private int offset; private Axis(int offset) { this.offset = offset; } } public static final float GRAD2RAD = (float) (PI / 180.); public static final float RAD2GRAD = (float) (180. / PI); // private final float[] data; private transient final FloatBuffer buffer; public Matrix4() { data = new float[16]; buffer = FloatBuffer.wrap(data); } @Override public final float[] getArray() { return data; } @Override public FloatBuffer getFloatBuffer() { return buffer; } @Override public void setMat(float[] mat) { assert (mat.length == 16) : "Die Matrize kann nur mit einem Array mit der selben Elementen anzahl gesetzt werden!"; System.arraycopy(mat, 0, data, 0, 16); } @Override public int getDimension() { return 4; } @Override public Matrix4 clone() { Matrix4 a = new Matrix4(); a.setMat(data); return a; } /** * Builds a orthogonal Coordinate System, where the given Vector represents * the given Axis. Both other Axis are generated in a way that no gurantee * can be given how their orientation are. *

* @param dir direction Vector of the given Axis * @param a Axis of the given Vektor */ public static Matrix4 createCoordinateSystem(ImmutableVector dir, Axis a) { Matrix4 res = new Matrix4(); res.loadIdentity(); Vector3 di = dir.clone().normalize(); res.setAxis(di, a); Vector3 dir2 = new Vector3(di.getY(), di.getZ(), -di.getX()); Vector3 dir3 = dir.clone().cross(dir2); Axis[] vals = Axis.values(); int a2 = a.ordinal(); a2 = (1 << a2) & 3; //(ordinal+1)%3 int a3 = (1 << a2) & 3;//(ordinal+2)%3 res.setAxis(dir2, vals[a2]); res.setAxis(dir3, vals[a3]); return res; } /** * Initialize a GenericMatrix which will transform a Source Space to a * Destination Space. *

* @param src GenericMatrix which describes the Source Coordinate Space * @param dst GenericMatrix which describes the Destination Coordinate Space */ public static Matrix4 createDeltaMatrix(Matrix4 src, Matrix4 dst) { return src.clone().inverse().mult(dst); } public Vector3 fastMult(Tupel3 vec) { float[] data = getArray(); float x, y, z; x = data[0]; x += data[1]; x += data[2]; x += data[3]; y = data[4]; y += data[5]; y += data[6]; y += data[7]; z = data[8]; z += data[9]; z += data[10]; z += data[11]; return new Vector3(x * vec.getX(), y * vec.getY(), z * vec.getZ()); } /** * translate the matrix in world space *

* @param vec translation vector *

* @return the manipulated matrix */ public Matrix4 worldTranslate(ImmutableVector vec) { Vector3 t = vec.clone(); return worldTranslate(t.getX(), t.getY(), t.getZ()); } /** * translate the matrix in world space *

* @param x x-axis translation * @param y y-axis translation * @param z z-axis translation *

* @return the manipulated matrix */ public Matrix4 worldTranslate(double x, double y, double z) { float[] m = getArray(); m[12] += x * m[15]; m[13] += y * m[15]; m[14] += z * m[15]; return this; } public Matrix4 setWorldTranslate(ImmutableVector vec) { Vector3 t = vec.clone(); return setWorldTranslate(t.getX(), t.getY(), t.getZ()); } public Matrix4 setWorldTranslate(float x, float y, float z) { float[] m = getArray(); m[12] = x; m[13] = y; m[14] = z; return this; } /** * translate the matrix in matrix space *

* @param vec translation vector *

* @return the manipulated matrix */ public Matrix4 translate(ImmutableVector vec) { Vector3 t = vec.clone(); return translate(t.getX(), t.getY(), t.getZ()); } /** * translate the matrix in matrix space *

* @param x x-axis translation * @param y y-axis translation * @param z z-axis translation *

* @return the manipulated matrix */ public Matrix4 translate(float x, float y, float z) { float[] m = getArray(); m[12] += m[0] * x + m[4] * y + m[8] * z; m[13] += m[1] * x + m[5] * y + m[9] * z; m[14] += m[2] * x + m[6] * y + m[10] * z; m[15] += m[3] * x + m[7] * y + m[11] * z; return this; } /** * Rotates the GenericMatrix with the given Eular Angles. Rotation order is * x,y,z. *

* @param angles 3D Vector which holds the rotation angles for each axis *

* @return the same GenericMatrix */ public Matrix4 rotateEuler(ImmutableVector vec) { Vector3 t = vec.clone(); return rotateEuler(t.getX(), t.getY(), t.getZ()); } /** * Rotates the GenericMatrix with the given Eular Angles. Rotation order is * x,y,z. *

* @param x * @param y * @param z < p/> *

* @return the same GenericMatrix */ public Matrix4 rotateEuler(float x, float y, float z) { double xx = x * GRAD2RAD; double yy = y * GRAD2RAD; double zz = z * GRAD2RAD; float A = (float) cos(xx); float B = (float) sin(xx); float C = (float) cos(yy); float D = (float) sin(yy); float E = (float) cos(zz); float F = (float) sin(zz); float AD = A * D; float BD = B * D; Matrix4 res = new Matrix4(); float[] mat = res.getArray(); mat[0] = C * E; mat[4] = -C * F; mat[8] = D; mat[1] = BD * E + A * F; mat[5] = -BD * F + A * E; mat[9] = -B * C; mat[2] = -AD * E + B * F; mat[6] = AD * F + B * E; mat[10] = A * C; mat[15] = 1; mult(res); return this; } /** * Rotates the GenericMatrix with the rotationen the given Quaternion * describes *

* @param quat < p/> *

* @return the same GenericMatrix */ public Matrix4 rotate(Quaternion quat) { Matrix4 rot = quat.getRotationMatrix(); mult(rot); return this; } /** * scales the matrix space *

* @param scale scale factor vector *

* @return the manipulated matrix */ public Matrix4 scale(ImmutableVector vec) { Vector3 t = vec.clone(); return scale(t.getX(), t.getY(), t.getZ()); } /** * scales the matrix space *

* @param scalex x-axis scale factor * @param scaley y-axis scale factor * @param scalez z-axis scale factor *

* @return the manipulated matrix */ public Matrix4 scale(float scalex, float scaley, float scalez) { if (scalex == scaley && scalex == scalez) { return scale(scalex); } float[] m = getArray(); if (scalex != 1) { for (int i = 0; i < 3; ++i) { m[i] *= scalex; } } if (scaley != 1) { for (int i = 4; i < 7; ++i) { m[i] *= scaley; } } if (scalez != 1) { for (int i = 8; i < 11; ++i) { m[i] *= scalez; } } return this; } /** * scales the matrix space evenly *

* @param scale scale factor *

* @return the manipulated matrix */ public Matrix4 scale(float scale) { if (scale == 1) { return this; } float[] m = getArray(); float s = (float) (1. / scale); m[12] *= s; m[13] *= s; m[14] *= s; m[15] *= s; return this; } /** * @return total translation of matrix space relativ to world space. Can be * used as position of the matrix in world space. */ public Vector3 getTranslation() { float[] mat = getArray(); return new Vector3(mat[12], mat[13], mat[14]); } public void setAxis(ImmutableVector x, ImmutableVector y, ImmutableVector z) { setAxis(x, Axis.X); setAxis(y, Axis.Y); setAxis(z, Axis.Z); } public void setAxis(ImmutableVector axis, Axis a) { System.arraycopy(axis.getCoords(), 0, getArray(), a.offset, 3); } /** * @return a axis vector of the object space represented by this matrix (not * normalized). */ public Vector3 getAxis(Axis a) { float[] mat = getArray(); float[] vec = new float[3]; System.arraycopy(mat, a.offset, vec, 0, 3); return new Vector3(mat[a.offset], mat[a.offset + 1], mat[a.offset + 2]); } public Vector3 getEularAngles() { float[] mat = getArray(); float[] angles = new float[3]; angles[1] = (float) asin(mat[8]); /* Calculate Y-axis angle */ double C = cos(angles[1]); if (abs(C) > 0.005) /* Gimball lock? */ { double trx = mat[10] / C; /* No, so get X-axis angle */ double tryy = -mat[9] / C; angles[0] = (float) atan2(tryy, trx); trx = mat[0] / C; /* Get Z-axis angle */ tryy = -mat[4] / C; angles[2] = (float) atan2(tryy, trx); } else /* Gimball lock has occurred */ { angles[0] = 0; /* Set X-axis angle to zero */ double trx = mat[5]; /* And calculate Z-axis angle */ double tryy = mat[1]; angles[2] = (float) atan2(tryy, trx); } /* return only positive angles in [0,360] */ for (int i = 0; i < 3; ++i) { angles[i] *= RAD2GRAD; if (angles[i] < 0) { angles[i] += 360; } } return new Vector3(angles[0], angles[1], angles[2]); } public Quaternion getRotation() { // from http://www.euclideanspace.com/maths/geometry/rotations // /conversions/matrixToQuaternion/index.htm /* The max( 0, ... ) is just a safeguard against rounding error. * copysign takes the sign from the second term and sets the sign * of the first without altering the magnitude, * I don't know of a java equivalent. * * quaternion.w = sqrt( max( 0, 1 + m00 + m11 + m22 ) ) / 2; * quaternion.x = sqrt( max( 0, 1 + m00 - m11 - m22 ) ) / 2; * quaternion.y = sqrt( max( 0, 1 - m00 + m11 - m22 ) ) / 2; * quaternion.z = sqrt( max( 0, 1 - m00 - m11 + m22 ) ) / 2; * Q.x = _copysign( Q.x, m21 - m12 ) * Q.y = _copysign( Q.y, m02 - m20 ) * Q.z = _copysign( Q.z, m10 - m01 ) */ float[] mat = getArray(); // // double w = Math.sqrt(Math.max(0, 1 + mat[0] + mat[5] + mat[10])) * 0.5; // double x = Math.sqrt(Math.max(0, 1 + mat[0] - mat[5] - mat[10])) * 0.5; // double y = Math.sqrt(Math.max(0, 1 - mat[0] + mat[5] - mat[10])) * 0.5; // double z = Math.sqrt(Math.max(0, 1 - mat[0] - mat[0] + mat[10])) * 0.5; // x = Math.copySign(x, mat[6] - mat[9]); // y = Math.copySign(y, mat[8] - mat[2]); // z = Math.copySign(z, mat[1] - mat[4]); // float tr = mat[0] + mat[5] + mat[10]; float w, x, y, z; if (tr > 0) { float S = (float) (sqrt(tr + 1.0) * 2); // S=4*w w = 0.25f * S; x = (mat[9] - mat[6]) / S; y = (mat[8] - mat[2]) / S; z = (mat[1] - mat[4]) / S; } else if ((mat[0] > mat[5]) && (mat[0] > mat[10])) { float S = (float) (sqrt(1.0 + mat[0] - mat[5] - mat[10]) * 2); // S=4*x w = (mat[9] - mat[6]) / S; x = 0.25f * S; y = (mat[4] + mat[1]) / S; z = (mat[8] + mat[2]) / S; } else if (mat[5] > mat[10]) { float S = (float) (sqrt(1.0 + mat[5] - mat[0] - mat[10]) * 2); // S=4*y w = (mat[8] - mat[2]) / S; x = (mat[4] + mat[1]) / S; y = 0.25f * S; z = (mat[6] + mat[9]) / S; } else { float S = (float) (sqrt(1.0 + mat[10] - mat[0] - mat[5]) * 2); // S=4*z w = (mat[1] - mat[4]) / S; x = (mat[8] + mat[2]) / S; y = (mat[6] + mat[9]) / S; z = 0.25f * S; } return new Quaternion(w, new Vector3(x, y, z)); } public void setRotation(Matrix4 rot) { float[] r = rot.getArray(); float[] m = getArray(); m[0] = r[0]; m[4] = r[4]; m[8] = r[8]; m[1] = r[1]; m[5] = r[5]; m[9] = r[9]; m[2] = r[2]; m[6] = r[6]; m[10] = r[10]; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy