package rajawali.math; import rajawali.util.RajLog; /** * @author dennis.ippel * */ public class Number3D { public float x; public float y; public float z; public static final int M00 = 0;// 0; public static final int M01 = 4;// 1; public static final int M02 = 8;// 2; public static final int M03 = 12;// 3; public static final int M10 = 1;// 4; public static final int M11 = 5;// 5; public static final int M12 = 9;// 6; public static final int M13 = 13;// 7; public static final int M20 = 2;// 8; public static final int M21 = 6;// 9; public static final int M22 = 10;// 10; public static final int M23 = 14;// 11; public static final int M30 = 3;// 12; public static final int M31 = 7;// 13; public static final int M32 = 11;// 14; public static final int M33 = 15;// 15; private static Number3D _temp = new Number3D(); public enum Axis { X, Y, Z } public Number3D() { this.x = 0; this.y = 0; this.z = 0; } public Number3D(Number3D from) { this.x = from.x; this.y = from.y; this.z = from.z; } public Number3D(String[] values) { if(values.length != 3) RajLog.e("Number3D should be initialized with 3 values"); this.x = Float.parseFloat(values[0]); this.y = Float.parseFloat(values[1]); this.z = Float.parseFloat(values[2]); } public Number3D(float x, float y, float z) { this.x = x; this.y = y; this.z = z; } public Number3D(double x, double y, double z) { this.x = (float) x; this.y = (float) y; this.z = (float) z; } public boolean equals(Number3D obj) { return obj.x == this.x && obj.y == this.y && obj.z == this.z; } public void setAll(float x, float y, float z) { this.x = x; this.y = y; this.z = z; } public void setAll(double x, double y, double z) { this.x = (float) x; this.y = (float) y; this.z = (float) z; } public void project(float[] mat){ float l_w = x * mat[M30] + y * mat[M31] + z * mat[M32] + mat[M33]; this.setAll( (x * mat[M00] + y * mat[M01] + z * mat[M02] + mat[M03]) / l_w, (x * mat[M10] + y * mat[M11] + z * mat[M12] + mat[M13]) / l_w, (x * mat[M20] + y * mat[M21] + z * mat[M22] + mat[M23]) / l_w); } public void setAllFrom(Number3D other) { this.x = other.x; this.y = other.y; this.z = other.z; } public float normalize() { double mod = Math.sqrt(x * x + y * y + z * z); if (mod != 0 && mod != 1) { mod = 1 / mod; this.x *= mod; this.y *= mod; this.z *= mod; } return (float)mod; } public Number3D inverse() { return new Number3D(-x, -y, -z); } public Number3D add(Number3D n) { this.x += n.x; this.y += n.y; this.z += n.z; return this; } public Number3D add(float x, float y, float z) { this.x += x; this.y += y; this.z += z; return this; } public Number3D subtract(Number3D n) { this.x -= n.x; this.y -= n.y; this.z -= n.z; return this; } public Number3D multiply(float f) { this.x *= f; this.y *= f; this.z *= f; return this; } public void multiply(Number3D n) { this.x *= n.x; this.y *= n.y; this.z *= n.z; } public void multiply(final float[] matrix) { float vx = x, vy = y, vz = z; this.x = vx * matrix[0] + vy * matrix[4] + vz * matrix[8] + matrix[12]; this.y = vx * matrix[1] + vy * matrix[5] + vz * matrix[9] + matrix[13]; this.z = vx * matrix[2] + vy * matrix[6] + vz * matrix[10] + matrix[14]; } public float distanceTo(Number3D other) { return (float)Math.sqrt((x - other.x) * (x - other.x) + (y - other.y) * (y - other.y) + (z - other.z) * (z - other.z)); } public float length() { return (float)Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); } public Number3D clone() { return new Number3D(x, y, z); } public void rotateX(float angle) { double cosRY = Math.cos(angle); double sinRY = Math.sin(angle); _temp.setAll(this.x, this.y, this.z); this.y = (float)((_temp.y * cosRY) - (_temp.z * sinRY)); this.z = (float)((_temp.y * sinRY) + (_temp.z * cosRY)); } public void rotateY(float angle) { double cosRY = Math.cos(angle); double sinRY = Math.sin(angle); _temp.setAll(this.x, this.y, this.z); this.x = (float)((_temp.x * cosRY) + (_temp.z * sinRY)); this.z = (float)((_temp.x * -sinRY) + (_temp.z * cosRY)); } public void rotateZ(float angle) { double cosRY = Math.cos(angle); double sinRY = Math.sin(angle); _temp.setAll(this.x, this.y, this.z); this.x = (float)((_temp.x * cosRY) - (_temp.y * sinRY)); this.y = (float)((_temp.x * sinRY) + (_temp.y * cosRY)); } @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append(x); sb.append(", "); sb.append(y); sb.append(", "); sb.append(z); return sb.toString(); } // public static Number3D add(Number3D a, Number3D b) { return new Number3D(a.x + b.x, a.y + b.y, a.z + b.z); } public static Number3D subtract(Number3D a, Number3D b) { return new Number3D(a.x - b.x, a.y - b.y, a.z - b.z); } public static Number3D multiply(Number3D a, Number3D b) { return new Number3D(a.x * b.x, a.y * b.y, a.z * b.z); } public static Number3D multiply(Number3D a, float b) { return new Number3D(a.x * b, a.y * b, a.z * b); } public static Number3D cross(Number3D v, Number3D w) { return new Number3D(w.y * v.z - w.z * v.y, w.z * v.x - w.x * v.z, w.x * v.y - w.y * v.x); } public Number3D cross(Number3D w) { _temp.setAllFrom(this); x = w.y * _temp.z - w.z * _temp.y; y = w.z * _temp.x - w.x * _temp.z; z = w.x * _temp.y - w.y * _temp.x; return this; } public static float dot(Number3D v, Number3D w) { return v.x * w.x + v.y * w.y + v.z * w.z; } public float dot(Number3D w) { return x * w.x + y * w.y + z * w.z; } public static Number3D getAxisVector(Axis axis) { Number3D axisVector = new Number3D(); switch (axis) { case X: axisVector.setAll(1, 0, 0); break; case Y: axisVector.setAll(0, 1, 0); break; case Z: axisVector.setAll(0, 0, 1); break; } return axisVector; } /** * http://ogre.sourcearchive.com/documentation/1.4.5/classOgre_1_1Vector3_eeef4472ad0c4d5f34a038a9f2faa819.html#eeef4472ad0c4d5f34a038a9f2faa819 * * @param direction * @return */ public Quaternion getRotationTo(Number3D direction) { // Based on Stan Melax's article in Game Programming Gems Quaternion q = new Quaternion(); // Copy, since cannot modify local Number3D v0 = this; Number3D v1 = direction; v0.normalize(); v1.normalize(); float d = Number3D.dot(v0, v1); // If dot == 1, vectors are the same if (d >= 1.0f) { q.setIdentity(); } if (d < 0.000001f - 1.0f) { // Generate an axis Number3D axis = Number3D.cross(Number3D.getAxisVector(Axis.X), this); if (axis.length() == 0) // pick another if colinear axis = Number3D.cross(Number3D.getAxisVector(Axis.Y), this); axis.normalize(); q.fromAngleAxis(MathUtil.radiansToDegrees(MathUtil.PI), axis); } else { double s = Math.sqrt((1 + d) * 2); double invs = 1f / s; Number3D c = Number3D.cross(v0, v1); q.x = (float)(c.x * invs); q.y = (float)(c.y * invs); q.z = (float)(c.z * invs); q.w = (float)(s * 0.5); q.normalize(); } return q; } public static Number3D getUpVector() { return new Number3D(0, 1, 0); } public static Number3D lerp(Number3D from, Number3D to, float amount) { Number3D out = new Number3D(); out.x = from.x + (to.x - from.x) * amount; out.y = from.y + (to.y - from.y) * amount; out.z = from.z + (to.z - from.z) * amount; return out; } /** * Performs a linear interpolation between from and to by the specified amount. * The result will be stored in the current object which means that the current * x, y, z values will be overridden. * * @param from * @param to * @param amount */ public void lerpSelf(Number3D from, Number3D to, float amount) { this.x = from.x + (to.x - from.x) * amount; this.y = from.y + (to.y - from.y) * amount; this.z = from.z + (to.z - from.z) * amount; } }