Added numerous 3D geometry classes; unabstracted Vector3, Matrix3.
This commit is contained in:
@@ -1,346 +0,0 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.d;
|
||||
|
||||
import java.nio.DoubleBuffer;
|
||||
|
||||
import pythagoras.util.Platform;
|
||||
import pythagoras.util.SingularMatrixException;
|
||||
|
||||
/**
|
||||
* Provides most of the implementation of {@link IMatrix3}, obtaining only the components from the
|
||||
* derived class.
|
||||
*/
|
||||
public abstract class AbstractMatrix3 implements IMatrix3
|
||||
{
|
||||
@Override // from IVector3
|
||||
public Matrix3 transpose () {
|
||||
return transpose(new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 transpose (Matrix3 result) {
|
||||
return result.set(
|
||||
m00(), m01(), m02(),
|
||||
m10(), m11(), m12(),
|
||||
m20(), m21(), m22());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 mult (IMatrix3 other) {
|
||||
return mult(other, new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 mult (IMatrix3 other, Matrix3 result) {
|
||||
double m00 = m00(), m01 = m01(), m02 = m02();
|
||||
double m10 = m10(), m11 = m11(), m12 = m12();
|
||||
double m20 = m20(), m21 = m21(), m22 = m22();
|
||||
double om00 = other.m00(), om01 = other.m01(), om02 = other.m02();
|
||||
double om10 = other.m10(), om11 = other.m11(), om12 = other.m12();
|
||||
double om20 = other.m20(), om21 = other.m21(), om22 = other.m22();
|
||||
return result.set(
|
||||
m00*om00 + m10*om01 + m20*om02,
|
||||
m00*om10 + m10*om11 + m20*om12,
|
||||
m00*om20 + m10*om21 + m20*om22,
|
||||
|
||||
m01*om00 + m11*om01 + m21*om02,
|
||||
m01*om10 + m11*om11 + m21*om12,
|
||||
m01*om20 + m11*om21 + m21*om22,
|
||||
|
||||
m02*om00 + m12*om01 + m22*om02,
|
||||
m02*om10 + m12*om11 + m22*om12,
|
||||
m02*om20 + m12*om21 + m22*om22);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public boolean isAffine () {
|
||||
return (m02() == 0f && m12() == 0f && m22() == 1f);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 multAffine (IMatrix3 other) {
|
||||
return multAffine(other, new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 multAffine (IMatrix3 other, Matrix3 result) {
|
||||
double m00 = m00(), m01 = m01(), m02 = m02();
|
||||
double m10 = m10(), m11 = m11(), m12 = m12();
|
||||
double m20 = m20(), m21 = m21(), m22 = m22();
|
||||
double om00 = other.m00(), om01 = other.m01(), om02 = other.m02();
|
||||
double om10 = other.m10(), om11 = other.m11(), om12 = other.m12();
|
||||
double om20 = other.m20(), om21 = other.m21(), om22 = other.m22();
|
||||
return result.set(
|
||||
m00*om00 + m10*om01,
|
||||
m00*om10 + m10*om11,
|
||||
m00*om20 + m10*om21 + m20,
|
||||
|
||||
m01*om00 + m11*om01,
|
||||
m01*om10 + m11*om11,
|
||||
m01*om20 + m11*om21 + m21,
|
||||
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 invert () {
|
||||
return invert(new Matrix3());
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverts this matrix and places the result in the given object. This code is based on the
|
||||
* examples in the <a href="http://www.j3d.org/matrix_faq/matrfaq_latest.html">Matrix and
|
||||
* Quaternion FAQ</a>.
|
||||
*
|
||||
* @return a reference to the result matrix, for chaining.
|
||||
*/
|
||||
public Matrix3 invert (Matrix3 result) throws SingularMatrixException {
|
||||
double m00 = m00(), m01 = m01(), m02 = m02();
|
||||
double m10 = m10(), m11 = m11(), m12 = m12();
|
||||
double m20 = m20(), m21 = m21(), m22 = m22();
|
||||
// compute the determinant, storing the subdeterminants for later use
|
||||
double sd00 = m11*m22 - m21*m12;
|
||||
double sd10 = m01*m22 - m21*m02;
|
||||
double sd20 = m01*m12 - m11*m02;
|
||||
double det = m00*sd00 + m20*sd20 - m10*sd10;
|
||||
if (Math.abs(det) == 0f) {
|
||||
// determinant is zero; matrix is not invertible
|
||||
throw new SingularMatrixException(this.toString());
|
||||
}
|
||||
double rdet = 1f / det;
|
||||
return result.set(
|
||||
+sd00 * rdet,
|
||||
-(m10*m22 - m20*m12) * rdet,
|
||||
+(m10*m21 - m20*m11) * rdet,
|
||||
|
||||
-sd10 * rdet,
|
||||
+(m00*m22 - m20*m02) * rdet,
|
||||
-(m00*m21 - m20*m01) * rdet,
|
||||
|
||||
+sd20 * rdet,
|
||||
-(m00*m12 - m10*m02) * rdet,
|
||||
+(m00*m11 - m10*m01) * rdet);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 invertAffine () {
|
||||
return invertAffine(new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 invertAffine (Matrix3 result) throws SingularMatrixException {
|
||||
double m00 = m00(), m01 = m01(), m02 = m02();
|
||||
double m10 = m10(), m11 = m11(), m12 = m12();
|
||||
double m20 = m20(), m21 = m21(), m22 = m22();
|
||||
// compute the determinant, storing the subdeterminants for later use
|
||||
double det = m00*m11 - m10*m01;
|
||||
if (Math.abs(det) == 0f) {
|
||||
// determinant is zero; matrix is not invertible
|
||||
throw new SingularMatrixException(this.toString());
|
||||
}
|
||||
double rdet = 1f / det;
|
||||
return result.set(
|
||||
+m11 * rdet,
|
||||
-m10 * rdet,
|
||||
+(m10*m21 - m20*m11) * rdet,
|
||||
|
||||
-m01 * rdet,
|
||||
+m00 * rdet,
|
||||
-(m00*m21 - m20*m01) * rdet,
|
||||
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 lerp (IMatrix3 other, double t) {
|
||||
return lerp(other, t, new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 lerp (IMatrix3 other, double t, Matrix3 result) {
|
||||
double m00 = m00(), m01 = m01(), m02 = m02();
|
||||
double m10 = m10(), m11 = m11(), m12 = m12();
|
||||
double m20 = m20(), m21 = m21(), m22 = m22();
|
||||
double om00 = other.m00(), om01 = other.m01(), om02 = other.m02();
|
||||
double om10 = other.m10(), om11 = other.m11(), om12 = other.m12();
|
||||
double om20 = other.m20(), om21 = other.m21(), om22 = other.m22();
|
||||
return result.set(
|
||||
m00 + t*(om00 - m00),
|
||||
m10 + t*(om10 - m10),
|
||||
m20 + t*(om20 - m20),
|
||||
|
||||
m01 + t*(om01 - m01),
|
||||
m11 + t*(om11 - m11),
|
||||
m21 + t*(om21 - m21),
|
||||
|
||||
m02 + t*(om02 - m02),
|
||||
m12 + t*(om12 - m12),
|
||||
m22 + t*(om22 - m22));
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 lerpAffine (IMatrix3 other, double t) {
|
||||
return lerpAffine(other, t, new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 lerpAffine (IMatrix3 other, double t, Matrix3 result) {
|
||||
double m00 = m00(), m01 = m01(), m02 = m02();
|
||||
double m10 = m10(), m11 = m11(), m12 = m12();
|
||||
double m20 = m20(), m21 = m21(), m22 = m22();
|
||||
double om00 = other.m00(), om01 = other.m01(), om02 = other.m02();
|
||||
double om10 = other.m10(), om11 = other.m11(), om12 = other.m12();
|
||||
double om20 = other.m20(), om21 = other.m21(), om22 = other.m22();
|
||||
return result.set(
|
||||
m00 + t*(om00 - m00),
|
||||
m10 + t*(om10 - m10),
|
||||
m20 + t*(om20 - m20),
|
||||
|
||||
m01 + t*(om01 - m01),
|
||||
m11 + t*(om11 - m11),
|
||||
m21 + t*(om21 - m21),
|
||||
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public DoubleBuffer get (DoubleBuffer buf) {
|
||||
buf.put(m00()).put(m01()).put(m02());
|
||||
buf.put(m10()).put(m11()).put(m12());
|
||||
buf.put(m20()).put(m21()).put(m22());
|
||||
return buf;
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector3 transformLocal (Vector3 vector) {
|
||||
return transform(vector, vector);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector3 transform (IVector3 vector) {
|
||||
return transform(vector, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector3 transform (IVector3 vector, Vector3 result) {
|
||||
double vx = vector.x(), vy = vector.y(), vz = vector.z();
|
||||
return result.set(
|
||||
m00()*vx + m10()*vy + m20()*vz,
|
||||
m01()*vx + m11()*vy + m21()*vz,
|
||||
m02()*vx + m12()*vy + m22()*vz);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector transformPointLocal (Vector point) {
|
||||
return transformPoint(point, point);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector transformPoint (IVector point) {
|
||||
return transformPoint(point, new Vector());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector transformPoint (IVector point, Vector result) {
|
||||
double px = point.x(), py = point.y();
|
||||
return result.set(m00()*px + m10()*py + m20(), m01()*px + m11()*py + m21());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector transformVectorLocal (Vector vector) {
|
||||
return transformVector(vector, vector);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector transformVector (IVector vector) {
|
||||
return transformVector(vector, new Vector());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector transformVector (IVector vector, Vector result) {
|
||||
double vx = vector.x(), vy = vector.y();
|
||||
return result.set(m00()*vx + m10()*vy, m01()*vx + m11()*vy);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public double extractRotation () {
|
||||
// start with the contents of the upper 2x2 portion of the matrix
|
||||
double n00 = m00(), n10 = m10();
|
||||
double n01 = m01(), n11 = m11();
|
||||
for (int ii = 0; ii < 10; ii++) {
|
||||
// store the results of the previous iteration
|
||||
double o00 = n00, o10 = n10;
|
||||
double o01 = n01, o11 = n11;
|
||||
|
||||
// compute average of the matrix with its inverse transpose
|
||||
double det = o00*o11 - o10*o01;
|
||||
if (Math.abs(det) == 0f) {
|
||||
// determinant is zero; matrix is not invertible
|
||||
throw new SingularMatrixException(this.toString());
|
||||
}
|
||||
double hrdet = 0.5f / det;
|
||||
n00 = +o11 * hrdet + o00*0.5f;
|
||||
n10 = -o01 * hrdet + o10*0.5f;
|
||||
|
||||
n01 = -o10 * hrdet + o01*0.5f;
|
||||
n11 = +o00 * hrdet + o11*0.5f;
|
||||
|
||||
// compute the difference; if it's small enough, we're done
|
||||
double d00 = n00 - o00, d10 = n10 - o10;
|
||||
double d01 = n01 - o01, d11 = n11 - o11;
|
||||
if (d00*d00 + d10*d10 + d01*d01 + d11*d11 < MathUtil.EPSILON) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// now that we have a nice orthogonal matrix, we can extract the rotation
|
||||
return Math.atan2(n01, n00);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector extractScale () {
|
||||
return extractScale(new Vector());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector extractScale (Vector result) {
|
||||
double m00 = m00(), m01 = m01(), m10 = m10(), m11 = m11();
|
||||
return result.set(
|
||||
Math.sqrt(m00*m00 + m01*m01),
|
||||
Math.sqrt(m10*m10 + m11*m11));
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public double approximateUniformScale () {
|
||||
double cp = m00()*m11() - m01()*m10();
|
||||
return (cp < 0f) ? -Math.sqrt(-cp) : Math.sqrt(cp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString () {
|
||||
return "[[" + m00() + ", " + m10() + ", " + m20() + "], " +
|
||||
"[" + m01() + ", " + m11() + ", " + m21() + "], " +
|
||||
"[" + m02() + ", " + m12() + ", " + m22() + "]]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode () {
|
||||
return Platform.hashCode(m00()) ^ Platform.hashCode(m10()) ^ Platform.hashCode(m20()) ^
|
||||
Platform.hashCode(m01()) ^ Platform.hashCode(m11()) ^ Platform.hashCode(m21()) ^
|
||||
Platform.hashCode(m02()) ^ Platform.hashCode(m12()) ^ Platform.hashCode(m22());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals (Object other) {
|
||||
if (!(other instanceof AbstractMatrix3)) {
|
||||
return false;
|
||||
}
|
||||
AbstractMatrix3 omat = (AbstractMatrix3)other;
|
||||
return
|
||||
m00() == omat.m00() && m10() == omat.m10() && m20() == omat.m20() &&
|
||||
m01() == omat.m01() && m11() == omat.m11() && m21() == omat.m21() &&
|
||||
m02() == omat.m02() && m12() == omat.m12() && m22() == omat.m22();
|
||||
}
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.d;
|
||||
|
||||
import java.nio.DoubleBuffer;
|
||||
|
||||
import pythagoras.util.Platform;
|
||||
|
||||
/**
|
||||
* Provides most of the implementation of {@link IVector3}, obtaining only x, y and z from the
|
||||
* derived class.
|
||||
*/
|
||||
public abstract class AbstractVector3 implements IVector3
|
||||
{
|
||||
@Override // from interface IVector3
|
||||
public double dot (IVector3 other) {
|
||||
return x()*other.x() + y()*other.y() + z()*other.z();
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 cross (IVector3 other) {
|
||||
return cross(other, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 cross (IVector3 other, Vector3 result) {
|
||||
double x = x(), y = y(), z = z();
|
||||
double ox = other.x(), oy = other.y(), oz = other.z();
|
||||
return result.set(y*oz - z*oy, z*ox - x*oz, x*oy - y*ox);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public double triple (IVector3 b, IVector3 c) {
|
||||
double bx = b.x(), by = b.y(), bz = b.z();
|
||||
double cx = c.x(), cy = c.y(), cz = c.z();
|
||||
return x()*(by*cz - bz*cy) + y()*(bz*cx - bx*cz) + z()*(bx*cy - by*cx);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 negate () {
|
||||
return negate(new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 negate (Vector3 result) {
|
||||
return result.set(-x(), -y(), -z());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 normalize () {
|
||||
return normalize(new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 normalize (Vector3 result) {
|
||||
return mult(1f / length(), result);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public double angle (IVector3 other) {
|
||||
return Math.acos(dot(other) / (length() * other.length()));
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public double length () {
|
||||
return Math.sqrt(lengthSquared());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public double lengthSquared () {
|
||||
double x = x(), y = y(), z = z();
|
||||
return (x*x + y*y + z*z);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public double distance (IVector3 other) {
|
||||
return Math.sqrt(distanceSquared(other));
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public double distanceSquared (IVector3 other) {
|
||||
double dx = x() - other.x(), dy = y() - other.y(), dz = z() - other.z();
|
||||
return dx*dx + dy*dy + dz*dz;
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public double manhattanDistance (IVector3 other) {
|
||||
return Math.abs(x() - other.x()) + Math.abs(y() - other.y()) + Math.abs(z() - other.z());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 mult (double v) {
|
||||
return mult(v, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 mult (double v, Vector3 result) {
|
||||
return result.set(x()*v, y()*v, z()*v);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 mult (IVector3 other) {
|
||||
return mult(other, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 mult (IVector3 other, Vector3 result) {
|
||||
return result.set(x()*other.x(), y()*other.y(), z()*other.z());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 add (IVector3 other) {
|
||||
return add(other, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 add (IVector3 other, Vector3 result) {
|
||||
return add(other.x(), other.y(), other.z(), result);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 subtract (IVector3 other) {
|
||||
return subtract(other, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 subtract (IVector3 other, Vector3 result) {
|
||||
return add(-other.x(), -other.y(), -other.z(), result);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 add (double x, double y, double z) {
|
||||
return add(x, y, z, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 add (double x, double y, double z, Vector3 result) {
|
||||
return result.set(x() + x, y() + y, z() + z);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 addScaled (IVector3 other, double v) {
|
||||
return addScaled(other, v, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 addScaled (IVector3 other, double v, Vector3 result) {
|
||||
return result.set(x() + other.x()*v, y() + other.y()*v, z() + other.z()*v);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 lerp (IVector3 other, double t) {
|
||||
return lerp(other, t, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 lerp (IVector3 other, double t, Vector3 result) {
|
||||
double x = x(), y = y(), z = z();
|
||||
return result.set(x + t*(other.x() - x), y + t*(other.y() - y), z + t*(other.z() - z));
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public double get (int idx) {
|
||||
switch (idx) {
|
||||
case 0: return x();
|
||||
case 1: return y();
|
||||
case 2: return z();
|
||||
}
|
||||
throw new IndexOutOfBoundsException(String.valueOf(idx));
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public void get (double[] values) {
|
||||
values[0] = x();
|
||||
values[1] = y();
|
||||
values[2] = z();
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public DoubleBuffer get (DoubleBuffer buf) {
|
||||
return buf.put(x()).put(y()).put(z());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString () {
|
||||
return "[" + x() + ", " + y() + ", " + z() + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode () {
|
||||
return Platform.hashCode(x()) ^ Platform.hashCode(y()) ^ Platform.hashCode(z());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals (Object other) {
|
||||
if (!(other instanceof AbstractVector3)) {
|
||||
return false;
|
||||
}
|
||||
AbstractVector3 ovec = (AbstractVector3)other;
|
||||
return (x() == ovec.x() && y() == ovec.y() && z() == ovec.z());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,535 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.d;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* An axis-aligned box.
|
||||
*/
|
||||
public class Box implements IBox, Serializable
|
||||
{
|
||||
/** The unit box. */
|
||||
public static final Box UNIT = new Box(Vector3.UNIT_XYZ.negate(), Vector3.UNIT_XYZ);
|
||||
|
||||
/** The zero box. */
|
||||
public static final Box ZERO = new Box(Vector3.ZERO, Vector3.ZERO);
|
||||
|
||||
/** The empty box. */
|
||||
public static final Box EMPTY = new Box(Vector3.MAX_VALUE, Vector3.MIN_VALUE);
|
||||
|
||||
/** A box that's as large as boxes can get. */
|
||||
public static final Box MAX_VALUE = new Box(Vector3.MIN_VALUE, Vector3.MAX_VALUE);
|
||||
|
||||
/**
|
||||
* Creates a box with the values contained in the supplied minimum and maximum extents.
|
||||
*/
|
||||
public Box (IVector3 minExtent, IVector3 maxExtent) {
|
||||
set(minExtent, maxExtent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*/
|
||||
public Box (IBox other) {
|
||||
set(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty box.
|
||||
*/
|
||||
public Box () {
|
||||
setToEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parameters of the box to the empty values ({@link Vector3f#MAX_VALUE} and
|
||||
* {@link Vector3f#MIN_VALUE} for the minimum and maximum, respectively).
|
||||
*
|
||||
* @return a reference to this box, for chaining.
|
||||
*/
|
||||
public Box setToEmpty () {
|
||||
return set(Vector3.MAX_VALUE, Vector3.MIN_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the parameters of another box.
|
||||
*
|
||||
* @return a reference to this box, for chaining.
|
||||
*/
|
||||
public Box set (IBox other) {
|
||||
return set(other.minimumExtent(), other.maximumExtent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the box parameters to the values contained in the supplied vectors.
|
||||
*
|
||||
* @return a reference to this box, for chaining.
|
||||
*/
|
||||
public Box set (IVector3 minExtent, IVector3 maxExtent) {
|
||||
_minExtent.set(minExtent);
|
||||
_maxExtent.set(maxExtent);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this box with the extents of an array of points.
|
||||
*
|
||||
* @return a reference to this box, for chaining.
|
||||
*/
|
||||
public Box fromPoints (IVector3... points) {
|
||||
setToEmpty();
|
||||
for (IVector3 point : points) {
|
||||
addLocal(point);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands this box in-place to include the specified point.
|
||||
*
|
||||
* @return a reference to this box, for chaining.
|
||||
*/
|
||||
public Box addLocal (IVector3 point) {
|
||||
return add(point, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands this box to include the bounds of another box.
|
||||
*
|
||||
* @return a reference to this box, for chaining.
|
||||
*/
|
||||
public Box addLocal (IBox other) {
|
||||
return add(other, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the intersection between this box and another box and places the result in this box.
|
||||
*
|
||||
* @return a reference to this box, for chaining.
|
||||
*/
|
||||
public Box intersectLocal (IBox other) {
|
||||
return intersect(other, this);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Transforms this box in-place.
|
||||
// *
|
||||
// * @return a reference to this box, for chaining.
|
||||
// */
|
||||
// public Box transformLocal (Transform3D transform) {
|
||||
// return transform(transform, this);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Projects this box in-place.
|
||||
*
|
||||
* @return a reference to this box, for chaining.
|
||||
*/
|
||||
public Box projectLocal (IMatrix4 matrix) {
|
||||
return project(matrix, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands the box in-place by the specified amounts.
|
||||
*
|
||||
* @return a reference to this box, for chaining.
|
||||
*/
|
||||
public Box expandLocal (double x, double y, double z) {
|
||||
return expand(x, y, z, this);
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public IVector3 minimumExtent () {
|
||||
return _minExtent;
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public IVector3 maximumExtent () {
|
||||
return _maxExtent;
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Vector3 center () {
|
||||
return center(new Vector3());
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Vector3 center (Vector3 result) {
|
||||
return _minExtent.add(_maxExtent, result).multLocal(0.5f);
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public double diagonalLength () {
|
||||
return _minExtent.distance(_maxExtent);
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public double longestEdge () {
|
||||
return Math.max(Math.max(_maxExtent.x - _minExtent.x, _maxExtent.y - _minExtent.y),
|
||||
_maxExtent.z - _minExtent.z);
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public boolean isEmpty () {
|
||||
return _minExtent.x > _maxExtent.x || _minExtent.y > _maxExtent.y ||
|
||||
_minExtent.z > _maxExtent.z;
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Box add (IVector3 point) {
|
||||
return add(point, new Box());
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Box add (IVector3 point, Box result) {
|
||||
result._minExtent.set(
|
||||
Math.min(_minExtent.x, point.x()),
|
||||
Math.min(_minExtent.y, point.y()),
|
||||
Math.min(_minExtent.z, point.z()));
|
||||
result._maxExtent.set(
|
||||
Math.max(_maxExtent.x, point.x()),
|
||||
Math.max(_maxExtent.y, point.y()),
|
||||
Math.max(_maxExtent.z, point.z()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Box add (IBox other) {
|
||||
return add(other, new Box());
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Box add (IBox other, Box result) {
|
||||
IVector3 omin = other.minimumExtent(), omax = other.maximumExtent();
|
||||
result._minExtent.set(
|
||||
Math.min(_minExtent.x, omin.x()),
|
||||
Math.min(_minExtent.y, omin.y()),
|
||||
Math.min(_minExtent.z, omin.z()));
|
||||
result._maxExtent.set(
|
||||
Math.max(_maxExtent.x, omax.x()),
|
||||
Math.max(_maxExtent.y, omax.y()),
|
||||
Math.max(_maxExtent.z, omax.z()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Box intersect (IBox other) {
|
||||
return intersect(other, new Box());
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Box intersect (IBox other, Box result) {
|
||||
IVector3 omin = other.minimumExtent(), omax = other.maximumExtent();
|
||||
result._minExtent.set(
|
||||
Math.max(_minExtent.x, omin.x()),
|
||||
Math.max(_minExtent.y, omin.y()),
|
||||
Math.max(_minExtent.z, omin.z()));
|
||||
result._maxExtent.set(
|
||||
Math.min(_maxExtent.x, omax.x()),
|
||||
Math.min(_maxExtent.y, omax.y()),
|
||||
Math.min(_maxExtent.z, omax.z()));
|
||||
return result;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Transforms this box.
|
||||
// *
|
||||
// * @return a new box containing the result.
|
||||
// */
|
||||
// public Box transform (Transform3D transform) {
|
||||
// return transform(transform, new Box());
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Transforms this box, placing the result in the provided object.
|
||||
// *
|
||||
// * @return a reference to the result box, for chaining.
|
||||
// */
|
||||
// public Box transform (Transform3D transform, Box result) {
|
||||
// // the corners of the box cover the eight permutations of ([minX|maxX], [minY|maxY],
|
||||
// // [minZ|maxZ]). to find the new minimum and maximum for each element, we transform
|
||||
// // selecting either the minimum or maximum for each component based on whether it will
|
||||
// // increase or decrease the total (which depends on the sign of the matrix element).
|
||||
// transform.update(Transform3D.AFFINE);
|
||||
// Matrix4f matrix = transform.matrix();
|
||||
// double minx =
|
||||
// matrix.m00 * (matrix.m00 > 0f ? _minExtent.x : _maxExtent.x) +
|
||||
// matrix.m10 * (matrix.m10 > 0f ? _minExtent.y : _maxExtent.y) +
|
||||
// matrix.m20 * (matrix.m20 > 0f ? _minExtent.z : _maxExtent.z) + matrix.m30;
|
||||
// double miny =
|
||||
// matrix.m01 * (matrix.m01 > 0f ? _minExtent.x : _maxExtent.x) +
|
||||
// matrix.m11 * (matrix.m11 > 0f ? _minExtent.y : _maxExtent.y) +
|
||||
// matrix.m21 * (matrix.m21 > 0f ? _minExtent.z : _maxExtent.z) + matrix.m31;
|
||||
// double minz =
|
||||
// matrix.m02 * (matrix.m02 > 0f ? _minExtent.x : _maxExtent.x) +
|
||||
// matrix.m12 * (matrix.m12 > 0f ? _minExtent.y : _maxExtent.y) +
|
||||
// matrix.m22 * (matrix.m22 > 0f ? _minExtent.z : _maxExtent.z) + matrix.m32;
|
||||
// double maxx =
|
||||
// matrix.m00 * (matrix.m00 < 0f ? _minExtent.x : _maxExtent.x) +
|
||||
// matrix.m10 * (matrix.m10 < 0f ? _minExtent.y : _maxExtent.y) +
|
||||
// matrix.m20 * (matrix.m20 < 0f ? _minExtent.z : _maxExtent.z) + matrix.m30;
|
||||
// double maxy =
|
||||
// matrix.m01 * (matrix.m01 < 0f ? _minExtent.x : _maxExtent.x) +
|
||||
// matrix.m11 * (matrix.m11 < 0f ? _minExtent.y : _maxExtent.y) +
|
||||
// matrix.m21 * (matrix.m21 < 0f ? _minExtent.z : _maxExtent.z) + matrix.m31;
|
||||
// double maxz =
|
||||
// matrix.m02 * (matrix.m02 < 0f ? _minExtent.x : _maxExtent.x) +
|
||||
// matrix.m12 * (matrix.m12 < 0f ? _minExtent.y : _maxExtent.y) +
|
||||
// matrix.m22 * (matrix.m22 < 0f ? _minExtent.z : _maxExtent.z) + matrix.m32;
|
||||
// result._minExtent.set(minx, miny, minz);
|
||||
// result._maxExtent.set(maxx, maxy, maxz);
|
||||
// return result;
|
||||
// }
|
||||
|
||||
@Override // from IBox
|
||||
public Box project (IMatrix4 matrix) {
|
||||
return project(matrix, new Box());
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Box project (IMatrix4 matrix, Box result) {
|
||||
double minx = +Float.MAX_VALUE, miny = +Float.MAX_VALUE, minz = +Float.MAX_VALUE;
|
||||
double maxx = -Float.MAX_VALUE, maxy = -Float.MAX_VALUE, maxz = -Float.MAX_VALUE;
|
||||
for (int ii = 0; ii < 8; ii++) {
|
||||
double x = ((ii & (1 << 2)) == 0) ? _minExtent.x : _maxExtent.x;
|
||||
double y = ((ii & (1 << 1)) == 0) ? _minExtent.y : _maxExtent.y;
|
||||
double z = ((ii & (1 << 0)) == 0) ? _minExtent.z : _maxExtent.z;
|
||||
double rw = 1f / (matrix.m03()*x + matrix.m13()*y + matrix.m23()*z + matrix.m33());
|
||||
double px = (matrix.m00()*x + matrix.m10()*y + matrix.m20()*z + matrix.m30()) * rw;
|
||||
double py = (matrix.m01()*x + matrix.m11()*y + matrix.m21()*z + matrix.m31()) * rw;
|
||||
double pz = (matrix.m02()*x + matrix.m12()*y + matrix.m22()*z + matrix.m32()) * rw;
|
||||
minx = Math.min(minx, px);
|
||||
miny = Math.min(miny, py);
|
||||
minz = Math.min(minz, pz);
|
||||
maxx = Math.max(maxx, px);
|
||||
maxy = Math.max(maxy, py);
|
||||
maxz = Math.max(maxz, pz);
|
||||
}
|
||||
result._minExtent.set(minx, miny, minz);
|
||||
result._maxExtent.set(maxx, maxy, maxz);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Box expand (double x, double y, double z) {
|
||||
return expand(x, y, z, new Box());
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Box expand (double x, double y, double z, Box result) {
|
||||
result._minExtent.set(_minExtent.x - x, _minExtent.y - y, _minExtent.z - z);
|
||||
result._maxExtent.set(_maxExtent.x + x, _maxExtent.y + y, _maxExtent.z + z);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Vector3 vertex (int code, Vector3 result) {
|
||||
return result.set(((code & (1 << 2)) == 0) ? _minExtent.x : _maxExtent.x,
|
||||
((code & (1 << 1)) == 0) ? _minExtent.y : _maxExtent.y,
|
||||
((code & (1 << 0)) == 0) ? _minExtent.z : _maxExtent.z);
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public boolean contains (IVector3 point) {
|
||||
return contains(point.x(), point.y(), point.z());
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public boolean contains (double x, double y, double z) {
|
||||
return (x >= _minExtent.x && x <= _maxExtent.x &&
|
||||
y >= _minExtent.y && y <= _maxExtent.y &&
|
||||
z >= _minExtent.z && z <= _maxExtent.z);
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public double extentDistance (IBox other) {
|
||||
return other.minimumExtent().manhattanDistance(_minExtent) +
|
||||
other.maximumExtent().manhattanDistance(_maxExtent);
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public boolean contains (IBox other) {
|
||||
IVector3 omin = other.minimumExtent(), omax = other.maximumExtent();
|
||||
return omin.x() >= _minExtent.x && omax.x() <= _maxExtent.x &&
|
||||
omin.y() >= _minExtent.y && omax.y() <= _maxExtent.y &&
|
||||
omin.z() >= _minExtent.z && omax.z() <= _maxExtent.z;
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public boolean intersects (IBox other) {
|
||||
IVector3 omin = other.minimumExtent(), omax = other.maximumExtent();
|
||||
return _maxExtent.x >= omin.x() && _minExtent.x <= omax.x() &&
|
||||
_maxExtent.y >= omin.y() && _minExtent.y <= omax.y() &&
|
||||
_maxExtent.z >= omin.z() && _minExtent.z <= omax.z();
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Determines whether the specified ray intersects this box.
|
||||
// */
|
||||
// public boolean intersects (Ray3D ray) {
|
||||
// Vector3 dir = ray.direction();
|
||||
// return
|
||||
// Math.abs(dir.x) > MathUtil.EPSILON &&
|
||||
// (intersectsX(ray, _minExtent.x) || intersectsX(ray, _maxExtent.x)) ||
|
||||
// Math.abs(dir.y) > MathUtil.EPSILON &&
|
||||
// (intersectsY(ray, _minExtent.y) || intersectsY(ray, _maxExtent.y)) ||
|
||||
// Math.abs(dir.z) > MathUtil.EPSILON &&
|
||||
// (intersectsZ(ray, _minExtent.z) || intersectsZ(ray, _maxExtent.z));
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Finds the location of the (first) intersection between the specified ray and this box.
|
||||
// * This will be the ray origin if the ray starts inside the box.
|
||||
// *
|
||||
// * @param result a vector to hold the location of the intersection.
|
||||
// * @return true if the ray intersects the box (in which case the result vector will be
|
||||
// * populated with the location of the intersection), false if not.
|
||||
// */
|
||||
// public boolean intersection (Ray3D ray, Vector3 result) {
|
||||
// Vector3 origin = ray.origin();
|
||||
// if (contains(origin)) {
|
||||
// result.set(origin);
|
||||
// return true;
|
||||
// }
|
||||
// Vector3 dir = ray.direction();
|
||||
// double t = Float.MAX_VALUE;
|
||||
// if (Math.abs(dir.x) > MathUtil.EPSILON) {
|
||||
// t = Math.min(t, intersectionX(ray, _minExtent.x));
|
||||
// t = Math.min(t, intersectionX(ray, _maxExtent.x));
|
||||
// }
|
||||
// if (Math.abs(dir.y) > MathUtil.EPSILON) {
|
||||
// t = Math.min(t, intersectionY(ray, _minExtent.y));
|
||||
// t = Math.min(t, intersectionY(ray, _maxExtent.y));
|
||||
// }
|
||||
// if (Math.abs(dir.z) > MathUtil.EPSILON) {
|
||||
// t = Math.min(t, intersectionZ(ray, _minExtent.z));
|
||||
// t = Math.min(t, intersectionZ(ray, _maxExtent.z));
|
||||
// }
|
||||
// if (t == Float.MAX_VALUE) {
|
||||
// return false;
|
||||
// }
|
||||
// origin.addScaled(dir, t, result);
|
||||
// return true;
|
||||
// }
|
||||
|
||||
@Override // documentation inherited
|
||||
public String toString () {
|
||||
return "[min=" + _minExtent + ", max=" + _maxExtent + "]";
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public int hashCode () {
|
||||
return _minExtent.hashCode() + 31*_maxExtent.hashCode();
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public boolean equals (Object other) {
|
||||
if (!(other instanceof Box)) {
|
||||
return false;
|
||||
}
|
||||
Box obox = (Box)other;
|
||||
return _minExtent.equals(obox._minExtent) && _maxExtent.equals(obox._maxExtent);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Helper method for {@link #intersects(Ray3D)}. Determines whether the ray intersects the box
|
||||
// * at the plane where x equals the value specified.
|
||||
// */
|
||||
// protected boolean intersectsX (Ray3D ray, double x) {
|
||||
// Vector3 origin = ray.origin(), dir = ray.direction();
|
||||
// double t = (x - origin.x) / dir.x;
|
||||
// if (t < 0f) {
|
||||
// return false;
|
||||
// }
|
||||
// double iy = origin.y + t*dir.y, iz = origin.z + t*dir.z;
|
||||
// return iy >= _minExtent.y && iy <= _maxExtent.y &&
|
||||
// iz >= _minExtent.z && iz <= _maxExtent.z;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Helper method for {@link #intersects(Ray3D)}. Determines whether the ray intersects the box
|
||||
// * at the plane where y equals the value specified.
|
||||
// */
|
||||
// protected boolean intersectsY (Ray3D ray, double y) {
|
||||
// Vector3 origin = ray.origin(), dir = ray.direction();
|
||||
// double t = (y - origin.y) / dir.y;
|
||||
// if (t < 0f) {
|
||||
// return false;
|
||||
// }
|
||||
// double ix = origin.x + t*dir.x, iz = origin.z + t*dir.z;
|
||||
// return ix >= _minExtent.x && ix <= _maxExtent.x &&
|
||||
// iz >= _minExtent.z && iz <= _maxExtent.z;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Helper method for {@link #intersects(Ray3D)}. Determines whether the ray intersects the box
|
||||
// * at the plane where z equals the value specified.
|
||||
// */
|
||||
// protected boolean intersectsZ (Ray3D ray, double z) {
|
||||
// Vector3 origin = ray.origin(), dir = ray.direction();
|
||||
// double t = (z - origin.z) / dir.z;
|
||||
// if (t < 0f) {
|
||||
// return false;
|
||||
// }
|
||||
// double ix = origin.x + t*dir.x, iy = origin.y + t*dir.y;
|
||||
// return ix >= _minExtent.x && ix <= _maxExtent.x &&
|
||||
// iy >= _minExtent.y && iy <= _maxExtent.y;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Helper method for {@link #intersection}. Finds the <code>t</code> value where the ray
|
||||
// * intersects the box at the plane where x equals the value specified, or returns
|
||||
// * {@link Float#MAX_VALUE} if there is no such intersection.
|
||||
// */
|
||||
// protected double intersectionX (Ray3D ray, double x) {
|
||||
// Vector3 origin = ray.origin(), dir = ray.direction();
|
||||
// double t = (x - origin.x) / dir.x;
|
||||
// if (t < 0f) {
|
||||
// return Float.MAX_VALUE;
|
||||
// }
|
||||
// double iy = origin.y + t*dir.y, iz = origin.z + t*dir.z;
|
||||
// return (iy >= _minExtent.y && iy <= _maxExtent.y &&
|
||||
// iz >= _minExtent.z && iz <= _maxExtent.z) ? t : Float.MAX_VALUE;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Helper method for {@link #intersection}. Finds the <code>t</code> value where the ray
|
||||
// * intersects the box at the plane where y equals the value specified, or returns
|
||||
// * {@link Float#MAX_VALUE} if there is no such intersection.
|
||||
// */
|
||||
// protected double intersectionY (Ray3D ray, double y) {
|
||||
// Vector3 origin = ray.origin(), dir = ray.direction();
|
||||
// double t = (y - origin.y) / dir.y;
|
||||
// if (t < 0f) {
|
||||
// return Float.MAX_VALUE;
|
||||
// }
|
||||
// double ix = origin.x + t*dir.x, iz = origin.z + t*dir.z;
|
||||
// return (ix >= _minExtent.x && ix <= _maxExtent.x &&
|
||||
// iz >= _minExtent.z && iz <= _maxExtent.z) ? t : Float.MAX_VALUE;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Helper method for {@link #intersection}. Finds the <code>t</code> value where the ray
|
||||
// * intersects the box at the plane where z equals the value specified, or returns
|
||||
// * {@link Float#MAX_VALUE} if there is no such intersection.
|
||||
// */
|
||||
// protected double intersectionZ (Ray3D ray, double z) {
|
||||
// Vector3 origin = ray.origin(), dir = ray.direction();
|
||||
// double t = (z - origin.z) / dir.z;
|
||||
// if (t < 0f) {
|
||||
// return Float.MAX_VALUE;
|
||||
// }
|
||||
// double ix = origin.x + t*dir.x, iy = origin.y + t*dir.y;
|
||||
// return (ix >= _minExtent.x && ix <= _maxExtent.x &&
|
||||
// iy >= _minExtent.y && iy <= _maxExtent.y) ? t : Float.MAX_VALUE;
|
||||
// }
|
||||
|
||||
/** The box's minimum extent. */
|
||||
protected final Vector3 _minExtent = new Vector3();
|
||||
|
||||
/** The box's maximum extent. */
|
||||
protected final Vector3 _maxExtent = new Vector3();
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.d;
|
||||
|
||||
/**
|
||||
* A pyramidal frustum.
|
||||
*/
|
||||
public class Frustum
|
||||
{
|
||||
/** Intersection types indicating that the frustum does not intersect, intersects, or fully
|
||||
* contains, respectively, the parameter. */
|
||||
public enum IntersectionType { NONE, INTERSECTS, CONTAINS };
|
||||
|
||||
/**
|
||||
* Creates an empty (invalid) frustum.
|
||||
*/
|
||||
public Frustum () {
|
||||
// initialize the vertices and planes of the frustum
|
||||
for (int ii = 0; ii < 8; ii++) {
|
||||
_vertices[ii] = new Vector3();
|
||||
}
|
||||
for (int ii = 0; ii < 6; ii++) {
|
||||
_planes[ii] = new Plane();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the frustum's array of vertices.
|
||||
*/
|
||||
public IVector3[] vertices () {
|
||||
return _vertices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the bounds of this frustum.
|
||||
*/
|
||||
public Box bounds () {
|
||||
return _bounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this frustum to one pointing in the Z- direction with the specified parameters
|
||||
* determining its size and shape (see the OpenGL documentation for
|
||||
* <code>gluPerspective</code>).
|
||||
*
|
||||
* @param fovy the vertical field of view, in radians.
|
||||
* @param aspect the aspect ratio (width over height).
|
||||
* @param znear the distance to the near clip plane.
|
||||
* @param zfar the distance to the far clip plane.
|
||||
* @return a reference to this frustum, for chaining.
|
||||
*/
|
||||
public Frustum setToPerspective (double fovy, double aspect, double znear, double zfar) {
|
||||
double top = znear * Math.tan(fovy / 2f), bottom = -top;
|
||||
double right = top * aspect, left = -right;
|
||||
return setToFrustum(left, right, bottom, top, znear, zfar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this frustum to one pointing in the Z- direction with the specified parameters
|
||||
* determining its size and shape (see the OpenGL documentation for <code>glFrustum</code>).
|
||||
*
|
||||
* @return a reference to this frustum, for chaining.
|
||||
*/
|
||||
public Frustum setToFrustum (
|
||||
double left, double right, double bottom, double top, double near, double far) {
|
||||
return setToProjection(left, right, bottom, top, near, far, Vector3.UNIT_Z, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this frustum to an orthographic one pointing in the Z- direction with the specified
|
||||
* parameters determining its size (see the OpenGL documentation for <code>glOrtho</code>).
|
||||
*
|
||||
* @return a reference to this frustum, for chaining.
|
||||
*/
|
||||
public Frustum setToOrtho (
|
||||
double left, double right, double bottom, double top, double near, double far) {
|
||||
return setToProjection(left, right, bottom, top, near, far, Vector3.UNIT_Z, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this frustum to a perspective or orthographic projection with the specified parameters
|
||||
* determining its size and shape.
|
||||
*
|
||||
* @return a reference to this frustum, for chaining.
|
||||
*/
|
||||
public Frustum setToProjection (
|
||||
double left, double right, double bottom, double top, double near,
|
||||
double far, IVector3 nearFarNormal, boolean ortho, boolean mirrored) {
|
||||
double nfnx = nearFarNormal.x(), nfny = nearFarNormal.y(), nfnz = nearFarNormal.z();
|
||||
if (ortho) {
|
||||
double nrz = -1f / nfnz;
|
||||
double xl = nfnx*left*nrz, xr = nfnx*right*nrz;
|
||||
double yb = nfny*bottom*nrz, yt = nfny*top*nrz;
|
||||
_vertices[0].set(left, bottom, xl + yb - near);
|
||||
_vertices[mirrored ? 3 : 1].set(right, bottom, xr + yb - near);
|
||||
_vertices[2].set(right, top, xr + yt - near);
|
||||
_vertices[mirrored ? 1 : 3].set(left, top, xl + yt - near);
|
||||
_vertices[4].set(left, bottom, xl + yb - far);
|
||||
_vertices[mirrored ? 7 : 5].set(right, bottom, xr + yb - far);
|
||||
_vertices[6].set(right, top, xr + yt - far);
|
||||
_vertices[mirrored ? 5 : 7].set(left, top, xl + yt - far);
|
||||
|
||||
} else {
|
||||
double rn = 1f / near;
|
||||
double lrn = left * rn, rrn = right * rn;
|
||||
double brn = bottom * rn, trn = top * rn;
|
||||
|
||||
double nz = near * nfnz;
|
||||
double z0 = nz / (nfnx*lrn + nfny*brn - nfnz);
|
||||
_vertices[0].set(-z0*lrn, -z0*brn, z0);
|
||||
double z1 = nz / (nfnx*rrn + nfny*brn - nfnz);
|
||||
_vertices[mirrored ? 3 : 1].set(-z1*rrn, -z1*brn, z1);
|
||||
double z2 = nz / (nfnx*rrn + nfny*trn - nfnz);
|
||||
_vertices[2].set(-z2*rrn, -z2*trn, z2);
|
||||
double z3 = nz / (nfnx*lrn + nfny*trn - nfnz);
|
||||
_vertices[mirrored ? 1 : 3].set(-z3*lrn, -z3*trn, z3);
|
||||
|
||||
double fz = far * nfnz;
|
||||
double z4 = fz / (nfnx*lrn + nfny*brn - nfnz);
|
||||
_vertices[4].set(-z4*lrn, -z4*brn, z4);
|
||||
double z5 = fz / (nfnx*rrn + nfny*brn - nfnz);
|
||||
_vertices[mirrored ? 7 : 5].set(-z5*rrn, -z5*brn, z5);
|
||||
double z6 = fz / (nfnx*rrn + nfny*trn - nfnz);
|
||||
_vertices[6].set(-z6*rrn, -z6*trn, z6);
|
||||
double z7 = fz / (nfnx*lrn + nfny*trn - nfnz);
|
||||
_vertices[mirrored ? 5 : 7].set(-z7*lrn, -z7*trn, z7);
|
||||
}
|
||||
|
||||
updateDerivedState();
|
||||
return this;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Transforms this frustum in-place by the specified transformation.
|
||||
// *
|
||||
// * @return a reference to this frustum, for chaining.
|
||||
// */
|
||||
// public Frustum transformLocal (Transform3D transform)
|
||||
// {
|
||||
// return transform(transform, this);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Transforms this frustum by the specified transformation.
|
||||
// *
|
||||
// * @return a new frustum containing the result.
|
||||
// */
|
||||
// public Frustum transform (Transform3D transform)
|
||||
// {
|
||||
// return transform(transform, new Frustum());
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Transforms this frustum by the specified transformation, placing the result in the object
|
||||
// * provided.
|
||||
// *
|
||||
// * @return a reference to the result frustum, for chaining.
|
||||
// */
|
||||
// public Frustum transform (Transform3D transform, Frustum result)
|
||||
// {
|
||||
// // transform all of the vertices
|
||||
// for (int ii = 0; ii < 8; ii++) {
|
||||
// transform.transformPoint(_vertices[ii], result._vertices[ii]);
|
||||
// }
|
||||
// result.updateDerivedState();
|
||||
// return result;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Determines the maximum signed distance of the point from the planes of the frustum. If
|
||||
* the distance is less than or equal to zero, the point lies inside the frustum.
|
||||
*/
|
||||
public double distance (Vector3 point) {
|
||||
double distance = -Float.MAX_VALUE;
|
||||
for (Plane plane : _planes) {
|
||||
distance = Math.max(distance, plane.distance(point));
|
||||
}
|
||||
return distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the frustum intersects the specified box.
|
||||
*/
|
||||
public IntersectionType intersectionType (Box box) {
|
||||
// exit quickly in cases where the bounding boxes don't overlap (equivalent to a separating
|
||||
// axis test using the axes of the box)
|
||||
if (!_bounds.intersects(box)) {
|
||||
return IntersectionType.NONE;
|
||||
}
|
||||
|
||||
// consider each side of the frustum as a potential separating axis
|
||||
int ccount = 0;
|
||||
for (int ii = 0; ii < 6; ii++) {
|
||||
// determine how many vertices fall inside/outside the plane
|
||||
int inside = 0;
|
||||
Plane plane = _planes[ii];
|
||||
for (int jj = 0; jj < 8; jj++) {
|
||||
if (plane.distance(box.vertex(jj, _vertex)) <= 0f) {
|
||||
inside++;
|
||||
}
|
||||
}
|
||||
if (inside == 0) {
|
||||
return IntersectionType.NONE;
|
||||
} else if (inside == 8) {
|
||||
ccount++;
|
||||
}
|
||||
}
|
||||
return (ccount == 6) ? IntersectionType.CONTAINS : IntersectionType.INTERSECTS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the bounds of the frustum under the supplied rotation and places the results in
|
||||
* the box provided.
|
||||
*
|
||||
* @return a reference to the result box, for chaining.
|
||||
*/
|
||||
public Box boundsUnderRotation (Matrix3 matrix, Box result) {
|
||||
result.setToEmpty();
|
||||
for (Vector3 vertex : _vertices) {
|
||||
result.addLocal(matrix.transform(vertex, _vertex));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the planes and bounding box of the frustum based on its vertices.
|
||||
*/
|
||||
protected void updateDerivedState () {
|
||||
_planes[0].fromPoints(_vertices[0], _vertices[1], _vertices[2]); // near
|
||||
_planes[1].fromPoints(_vertices[5], _vertices[4], _vertices[7]); // far
|
||||
_planes[2].fromPoints(_vertices[1], _vertices[5], _vertices[6]); // left
|
||||
_planes[3].fromPoints(_vertices[4], _vertices[0], _vertices[3]); // right
|
||||
_planes[4].fromPoints(_vertices[3], _vertices[2], _vertices[6]); // top
|
||||
_planes[5].fromPoints(_vertices[4], _vertices[5], _vertices[1]); // bottom
|
||||
_bounds.fromPoints(_vertices);
|
||||
}
|
||||
|
||||
/** The vertices of the frustum. */
|
||||
protected Vector3[] _vertices = new Vector3[8];
|
||||
|
||||
/** The planes of the frustum (as derived from the vertices). The plane normals point out of
|
||||
* the frustum. */
|
||||
protected Plane[] _planes = new Plane[6];
|
||||
|
||||
/** The frustum's bounding box (as derived from the vertices). */
|
||||
protected Box _bounds = new Box();
|
||||
|
||||
/** A working vertex. */
|
||||
protected static Vector3 _vertex = new Vector3();
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.d;
|
||||
|
||||
/**
|
||||
* Does something extraordinary.
|
||||
*/
|
||||
public interface IBox
|
||||
{
|
||||
/**
|
||||
* Returns a reference to the box's minimum extent.
|
||||
*/
|
||||
IVector3 minimumExtent ();
|
||||
|
||||
/**
|
||||
* Returns a reference to the box's maximum extent.
|
||||
*/
|
||||
IVector3 maximumExtent ();
|
||||
|
||||
/**
|
||||
* Returns the center of the box as a new vector.
|
||||
*/
|
||||
Vector3 center ();
|
||||
|
||||
/**
|
||||
* Places the location of the center of the box into the given result vector.
|
||||
*
|
||||
* @return a reference to the result vector, for chaining.
|
||||
*/
|
||||
Vector3 center (Vector3 result);
|
||||
|
||||
/**
|
||||
* Returns the length of the box's diagonal (the distance from minimum to maximum extent).
|
||||
*/
|
||||
double diagonalLength ();
|
||||
|
||||
/**
|
||||
* Returns the length of the box's longest edge.
|
||||
*/
|
||||
double longestEdge ();
|
||||
|
||||
/**
|
||||
* Determines whether the box is empty (whether any of its minima are greater than their
|
||||
* corresponding maxima).
|
||||
*/
|
||||
boolean isEmpty ();
|
||||
|
||||
/**
|
||||
* Retrieves one of the eight vertices of the box. The code parameter identifies the vertex
|
||||
* with flags indicating which values should be selected from the minimum extent, and which
|
||||
* from the maximum extent. For example, the code 011b selects the vertex with the minimum x,
|
||||
* maximum y, and maximum z.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Vector3 vertex (int code, Vector3 result);
|
||||
|
||||
/**
|
||||
* Determines whether this box contains the specified point.
|
||||
*/
|
||||
boolean contains (IVector3 point);
|
||||
|
||||
/**
|
||||
* Determines whether this box contains the specified point.
|
||||
*/
|
||||
boolean contains (double x, double y, double z);
|
||||
|
||||
/**
|
||||
* Returns the sum of the Manhattan distances between the extents of this box and the
|
||||
* specified other box.
|
||||
*/
|
||||
double extentDistance (IBox other);
|
||||
|
||||
/**
|
||||
* Determines whether this box completely contains the specified box.
|
||||
*/
|
||||
boolean contains (IBox other);
|
||||
|
||||
/**
|
||||
* Determines whether this box intersects the specified other box.
|
||||
*/
|
||||
boolean intersects (IBox other);
|
||||
|
||||
/**
|
||||
* Expands this box to include the specified point.
|
||||
*
|
||||
* @return a new box containing the result.
|
||||
*/
|
||||
Box add (IVector3 point);
|
||||
|
||||
/**
|
||||
* Expands this box to include the specified point, placing the result in the object
|
||||
* provided.
|
||||
*
|
||||
* @return a reference to the result box, for chaining.
|
||||
*/
|
||||
Box add (IVector3 point, Box result);
|
||||
|
||||
/**
|
||||
* Expands this box to include the bounds of another box.
|
||||
*
|
||||
* @return a new box containing the result.
|
||||
*/
|
||||
Box add (IBox other);
|
||||
|
||||
/**
|
||||
* Expands this box to include the bounds of another box, placing the result in the object
|
||||
* provided.
|
||||
*
|
||||
* @return a reference to the result box, for chaining.
|
||||
*/
|
||||
Box add (IBox other, Box result);
|
||||
|
||||
/**
|
||||
* Finds the intersection between this box and another box.
|
||||
*
|
||||
* @return a new box containing the result.
|
||||
*/
|
||||
Box intersect (IBox other);
|
||||
|
||||
/**
|
||||
* Finds the intersection between this box and another box and places the result in the
|
||||
* provided object.
|
||||
*
|
||||
* @return a reference to this box, for chaining.
|
||||
*/
|
||||
Box intersect (IBox other, Box result);
|
||||
|
||||
/**
|
||||
* Projects this box.
|
||||
*
|
||||
* @return a new box containing the result.
|
||||
*/
|
||||
Box project (IMatrix4 matrix);
|
||||
|
||||
/**
|
||||
* Projects this box, placing the result in the object provided.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Box project (IMatrix4 matrix, Box result);
|
||||
|
||||
/**
|
||||
* Expands the box by the specified amounts.
|
||||
*
|
||||
* @return a new box containing the result.
|
||||
*/
|
||||
Box expand (double x, double y, double z);
|
||||
|
||||
/**
|
||||
* Expands the box by the specified amounts, placing the result in the object provided.
|
||||
*
|
||||
* @return a reference to the result box, for chaining.
|
||||
*/
|
||||
Box expand (double x, double y, double z, Box result);
|
||||
|
||||
// /**
|
||||
// * Determines whether the specified ray intersects this box.
|
||||
// */
|
||||
// boolean intersects (Ray3D ray);
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.d;
|
||||
|
||||
import java.nio.DoubleBuffer;
|
||||
|
||||
/**
|
||||
* Provides read-only access to a {@link Matrix4}.
|
||||
*/
|
||||
public interface IMatrix4
|
||||
{
|
||||
/** Returns the (0,0)th component of the matrix. */
|
||||
double m00 ();
|
||||
|
||||
/** Returns the (1,0)th component of the matrix. */
|
||||
double m10 ();
|
||||
|
||||
/** Returns the (2,0)th component of the matrix. */
|
||||
double m20 ();
|
||||
|
||||
/** Returns the (3,0)th component of the matrix. */
|
||||
double m30 ();
|
||||
|
||||
/** Returns the (0,1)th component of the matrix. */
|
||||
double m01 ();
|
||||
|
||||
/** Returns the (1,1)th component of the matrix. */
|
||||
double m11 ();
|
||||
|
||||
/** Returns the (2,1)th component of the matrix. */
|
||||
double m21 ();
|
||||
|
||||
/** Returns the (3,1)th component of the matrix. */
|
||||
double m31 ();
|
||||
|
||||
/** Returns the (0,2)th component of the matrix. */
|
||||
double m02 ();
|
||||
|
||||
/** Returns the (1,2)th component of the matrix. */
|
||||
double m12 ();
|
||||
|
||||
/** Returns the (2,2)th component of the matrix. */
|
||||
double m22 ();
|
||||
|
||||
/** Returns the (3,2)th component of the matrix. */
|
||||
double m32 ();
|
||||
|
||||
/** Returns the (0,3)th component of the matrix. */
|
||||
double m03 ();
|
||||
|
||||
/** Returns the (1,3)th component of the matrix. */
|
||||
double m13 ();
|
||||
|
||||
/** Returns the (2,3)th component of the matrix. */
|
||||
double m23 ();
|
||||
|
||||
/** Returns the (3,3)th component of the matrix. */
|
||||
double m33 ();
|
||||
|
||||
/**
|
||||
* Transposes this matrix.
|
||||
*
|
||||
* @return a new matrix containing the result.
|
||||
*/
|
||||
Matrix4 transpose ();
|
||||
|
||||
/**
|
||||
* Transposes this matrix, storing the result in the provided object.
|
||||
*
|
||||
* @return the result matrix, for chaining.
|
||||
*/
|
||||
Matrix4 transpose (Matrix4 result);
|
||||
|
||||
/**
|
||||
* Multiplies this matrix by another.
|
||||
*
|
||||
* @return a new matrix containing the result.
|
||||
*/
|
||||
Matrix4 mult (IMatrix4 other);
|
||||
|
||||
/**
|
||||
* Multiplies this matrix by another and stores the result in the object provided.
|
||||
*
|
||||
* @return a reference to the result matrix, for chaining.
|
||||
*/
|
||||
Matrix4 mult (IMatrix4 other, Matrix4 result);
|
||||
|
||||
/**
|
||||
* Determines whether this matrix represents an affine transformation.
|
||||
*/
|
||||
boolean isAffine ();
|
||||
|
||||
/**
|
||||
* Determines whether the matrix is mirrored.
|
||||
*/
|
||||
boolean isMirrored ();
|
||||
|
||||
/**
|
||||
* Multiplies this matrix by another, treating the matrices as affine.
|
||||
*
|
||||
* @return a new matrix containing the result.
|
||||
*/
|
||||
Matrix4 multAffine (IMatrix4 other);
|
||||
|
||||
/**
|
||||
* Multiplies this matrix by another, treating the matrices as affine, and stores the result
|
||||
* in the object provided.
|
||||
*
|
||||
* @return a reference to the result matrix, for chaining.
|
||||
*/
|
||||
Matrix4 multAffine (IMatrix4 other, Matrix4 result);
|
||||
|
||||
/**
|
||||
* Inverts this matrix.
|
||||
*
|
||||
* @return a new matrix containing the result.
|
||||
*/
|
||||
Matrix4 invert ();
|
||||
|
||||
/**
|
||||
* Inverts this matrix and places the result in the given object. This code is based on the
|
||||
* examples in the <a href="http://www.j3d.org/matrix_faq/matrfaq_latest.html">Matrix and
|
||||
* Quaternion FAQ</a>.
|
||||
*
|
||||
* @return a reference to the result matrix, for chaining.
|
||||
*/
|
||||
Matrix4 invert (Matrix4 result);
|
||||
|
||||
/**
|
||||
* Inverts this matrix as an affine matrix.
|
||||
*
|
||||
* @return a new matrix containing the result.
|
||||
*/
|
||||
Matrix4 invertAffine ();
|
||||
|
||||
/**
|
||||
* Inverts this matrix as an affine matrix and places the result in the given object.
|
||||
*
|
||||
* @return a reference to the result matrix, for chaining.
|
||||
*/
|
||||
Matrix4 invertAffine (Matrix4 result);
|
||||
|
||||
/**
|
||||
* Linearly interpolates between this and the specified other matrix.
|
||||
*
|
||||
* @return a new matrix containing the result.
|
||||
*/
|
||||
Matrix4 lerp (IMatrix4 other, double t);
|
||||
|
||||
/**
|
||||
* Linearly interpolates between this and the specified other matrix, placing the result in
|
||||
* the object provided.
|
||||
*
|
||||
* @return a reference to the result object, for chaining.
|
||||
*/
|
||||
Matrix4 lerp (IMatrix4 other, double t, Matrix4 result);
|
||||
|
||||
/**
|
||||
* Linearly interpolates between this and the specified other matrix, treating the matrices as
|
||||
* affine.
|
||||
*
|
||||
* @return a new matrix containing the result.
|
||||
*/
|
||||
Matrix4 lerpAffine (IMatrix4 other, double t);
|
||||
|
||||
/**
|
||||
* Linearly interpolates between this and the specified other matrix (treating the matrices as
|
||||
* affine);, placing the result in the object provided.
|
||||
*
|
||||
* @return a reference to the result object, for chaining.
|
||||
*/
|
||||
Matrix4 lerpAffine (IMatrix4 other, double t, Matrix4 result);
|
||||
|
||||
/**
|
||||
* Places the contents of this matrix into the given buffer in the standard OpenGL order.
|
||||
*
|
||||
* @return a reference to the buffer, for chaining.
|
||||
*/
|
||||
DoubleBuffer get (DoubleBuffer buf);
|
||||
|
||||
/**
|
||||
* Projects the supplied point in-place using this matrix.
|
||||
*
|
||||
* @return a reference to the point, for chaining.
|
||||
*/
|
||||
Vector3 projectPointLocal (Vector3 point);
|
||||
|
||||
/**
|
||||
* Projects the supplied point using this matrix.
|
||||
*
|
||||
* @return a new vector containing the result.
|
||||
*/
|
||||
Vector3 projectPoint (IVector3 point);
|
||||
|
||||
/**
|
||||
* Projects the supplied point using this matrix and places the result in the object supplied.
|
||||
*
|
||||
* @return a reference to the result vector, for chaining.
|
||||
*/
|
||||
Vector3 projectPoint (IVector3 point, Vector3 result);
|
||||
|
||||
/**
|
||||
* Transforms a point in-place by this matrix.
|
||||
*
|
||||
* @return a reference to the point, for chaining.
|
||||
*/
|
||||
Vector3 transformPointLocal (Vector3 point);
|
||||
|
||||
/**
|
||||
* Transforms a point by this matrix.
|
||||
*
|
||||
* @return a new vector containing the result.
|
||||
*/
|
||||
Vector3 transformPoint (IVector3 point);
|
||||
|
||||
/**
|
||||
* Transforms a point by this matrix and places the result in the object provided.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Vector3 transformPoint (IVector3 point, Vector3 result);
|
||||
|
||||
/**
|
||||
* Transforms a point by this matrix and returns the resulting z coordinate.
|
||||
*/
|
||||
double transformPointZ (IVector3 point);
|
||||
|
||||
/**
|
||||
* Transforms a vector in-place by the inner 3x3 part of this matrix.
|
||||
*
|
||||
* @return a reference to the vector, for chaining.
|
||||
*/
|
||||
Vector3 transformVectorLocal (Vector3 vector);
|
||||
|
||||
/**
|
||||
* Transforms a vector by this inner 3x3 part of this matrix.
|
||||
*
|
||||
* @return a new vector containing the result.
|
||||
*/
|
||||
Vector3 transformVector (IVector3 vector);
|
||||
|
||||
/**
|
||||
* Transforms a vector by the inner 3x3 part of this matrix and places the result in the object
|
||||
* provided.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Vector3 transformVector (IVector3 vector, Vector3 result);
|
||||
|
||||
/**
|
||||
* Extracts the rotation component of the matrix.
|
||||
*
|
||||
* @return a new quaternion containing the result.
|
||||
*/
|
||||
Quaternion extractRotation ();
|
||||
|
||||
/**
|
||||
* Extracts the rotation component of the matrix and places it in the provided result
|
||||
* quaternion. This uses the iterative polar decomposition algorithm described by
|
||||
* <a href="http://www.cs.wisc.edu/graphics/Courses/838-s2002/Papers/polar-decomp.pdf">Ken
|
||||
* Shoemake</a>.
|
||||
*
|
||||
* @return a reference to the result quaternion, for chaining.
|
||||
*/
|
||||
Quaternion extractRotation (Quaternion result);
|
||||
|
||||
/**
|
||||
* Extracts the scale component of the matrix.
|
||||
*
|
||||
* @return a new vector containing the result.
|
||||
*/
|
||||
Vector3 extractScale ();
|
||||
|
||||
/**
|
||||
* Extracts the scale component of the matrix and places it in the provided result vector.
|
||||
*
|
||||
* @return a reference to the result vector, for chaining.
|
||||
*/
|
||||
Vector3 extractScale (Vector3 result);
|
||||
|
||||
/**
|
||||
* Returns an approximation of the uniform scale for this matrix (the cube root of the
|
||||
* signed volume of the parallelepiped spanned by the axis vectors);.
|
||||
*/
|
||||
double approximateUniformScale ();
|
||||
|
||||
/**
|
||||
* Compares this matrix to another with the provided epsilon.
|
||||
*/
|
||||
boolean epsilonEquals (IMatrix4 other, double epsilon);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.d;
|
||||
|
||||
import java.nio.DoubleBuffer;
|
||||
|
||||
/**
|
||||
* Provides read-only access to a {@link Plane}.
|
||||
*/
|
||||
public interface IPlane
|
||||
{
|
||||
/** Returns the plane constant. */
|
||||
double constant ();
|
||||
|
||||
/** Returns the plane normal. */
|
||||
IVector3 normal ();
|
||||
|
||||
/**
|
||||
* Stores the contents of this plane into the specified buffer.
|
||||
*/
|
||||
DoubleBuffer get (DoubleBuffer buf);
|
||||
|
||||
/**
|
||||
* Computes and returns the signed distance from the plane to the specified point.
|
||||
*/
|
||||
double distance (IVector3 pt);
|
||||
|
||||
// /**
|
||||
// * Transforms this plane by the specified transformation.
|
||||
// *
|
||||
// * @return a new plane containing the result.
|
||||
// */
|
||||
// Plane transform (Transform transform);
|
||||
|
||||
// /**
|
||||
// * Transforms this plane by the specified transformation, placing the result in the object
|
||||
// * provided.
|
||||
// *
|
||||
// * @return a reference to the result plane, for chaining.
|
||||
// */
|
||||
// Plane transform (Transform transform, Plane result);
|
||||
|
||||
/**
|
||||
* Negates this plane.
|
||||
*
|
||||
* @return a new plane containing the result.
|
||||
*/
|
||||
Plane negate ();
|
||||
|
||||
/**
|
||||
* Negates this plane, placing the result in the object provided.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Plane negate (Plane result);
|
||||
|
||||
// /**
|
||||
// * Computes the intersection of the supplied ray with this plane, placing the result
|
||||
// * in the given vector (if the ray intersects).
|
||||
// *
|
||||
// * @return true if the ray intersects the plane (in which case the result will contain
|
||||
// * the point of intersection), false if not.
|
||||
// */
|
||||
// boolean intersection (Ray3D ray, Vector3 result);
|
||||
|
||||
// /**
|
||||
// * Computes the signed distance to this plane along the specified ray.
|
||||
// *
|
||||
// * @return the signed distance, or {@link Float#NaN} if the ray runs parallel to the plane.
|
||||
// */
|
||||
// double distance (Ray3D ray);
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.d;
|
||||
|
||||
/**
|
||||
* Provides read-only access to a {@link Quaternion}.
|
||||
*/
|
||||
public interface IQuaternion
|
||||
{
|
||||
/** Returns the x-component of this quaternion. */
|
||||
double x ();
|
||||
|
||||
/** Returns the y-component of this quaternion. */
|
||||
double y ();
|
||||
|
||||
/** Returns the z-component of this quaternion. */
|
||||
double z ();
|
||||
|
||||
/** Returns the w-component of this quaternion. */
|
||||
double w ();
|
||||
|
||||
/**
|
||||
* Populates the supplied array with the contents of this quaternion.
|
||||
*/
|
||||
void get (double[] values);
|
||||
|
||||
/**
|
||||
* Checks whether any of the components of this quaternion are not-numbers.
|
||||
*/
|
||||
boolean hasNaN ();
|
||||
|
||||
/**
|
||||
* Computes the angles to pass to {@link #fromAngles} to reproduce this rotation, placing them
|
||||
* in the provided vector. This uses the factorization method described in David Eberly's
|
||||
* <a href="http://www.geometrictools.com/Documentation/EulerAngles.pdf">Euler Angle
|
||||
* Formulas</a>.
|
||||
*
|
||||
* @return a reference to the result vector, for chaining.
|
||||
*/
|
||||
Vector3 toAngles (Vector3 result);
|
||||
|
||||
/**
|
||||
* Computes and returns the angles to pass to {@link #fromAngles} to reproduce this rotation.
|
||||
*
|
||||
* @return a new vector containing the resulting angles.
|
||||
*/
|
||||
Vector3 toAngles ();
|
||||
|
||||
/**
|
||||
* Normalizes this quaternion.
|
||||
*
|
||||
* @return a new quaternion containing the result.
|
||||
*/
|
||||
Quaternion normalize ();
|
||||
|
||||
/**
|
||||
* Normalizes this quaternion, storing the result in the object provided.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Quaternion normalize (Quaternion result);
|
||||
|
||||
/**
|
||||
* Inverts this quaternion.
|
||||
*
|
||||
* @return a new quaternion containing the result.
|
||||
*/
|
||||
Quaternion invert ();
|
||||
|
||||
/**
|
||||
* Inverts this quaternion, storing the result in the object provided.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Quaternion invert (Quaternion result);
|
||||
|
||||
/**
|
||||
* Multiplies this quaternion by another.
|
||||
*
|
||||
* @return a new quaternion containing the result.
|
||||
*/
|
||||
Quaternion mult (IQuaternion other);
|
||||
|
||||
/**
|
||||
* Multiplies this quaternion by another and stores the result in the provided object.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Quaternion mult (IQuaternion other, Quaternion result);
|
||||
|
||||
/**
|
||||
* Interpolates between this and the specified other quaternion.
|
||||
*
|
||||
* @return a new quaternion containing the result.
|
||||
*/
|
||||
Quaternion slerp (IQuaternion other, double t);
|
||||
|
||||
/**
|
||||
* Interpolates between this and the specified other quaternion, placing the result in the
|
||||
* object provided. Based on the code in Nick Bobick's article,
|
||||
* <a href="http://www.gamasutra.com/features/19980703/quaternions_01.htm">Rotating Objects
|
||||
* Using Quaternions</a>.
|
||||
*
|
||||
* @return a reference to the result quaternion, for chaining.
|
||||
*/
|
||||
Quaternion slerp (IQuaternion other, double t, Quaternion result);
|
||||
|
||||
/**
|
||||
* Transforms a vector by this quaternion.
|
||||
*
|
||||
* @return a new vector containing the result.
|
||||
*/
|
||||
Vector3 transform (IVector3 vector);
|
||||
|
||||
/**
|
||||
* Transforms a vector by this quaternion and places the result in the provided object.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Vector3 transform (IVector3 vector, Vector3 result);
|
||||
|
||||
/**
|
||||
* Transforms the unit x vector by this quaternion, placing the result in the provided object.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Vector3 transformUnitX (Vector3 result);
|
||||
|
||||
/**
|
||||
* Transforms the unit y vector by this quaternion, placing the result in the provided object.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Vector3 transformUnitY (Vector3 result);
|
||||
|
||||
/**
|
||||
* Transforms the unit z vector by this quaternion, placing the result in the provided object.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Vector3 transformUnitZ (Vector3 result);
|
||||
|
||||
/**
|
||||
* Transforms a vector by this quaternion and adds another vector to it, placing the result
|
||||
* in the object provided.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Vector3 transformAndAdd (IVector3 vector, IVector3 add, Vector3 result);
|
||||
|
||||
/**
|
||||
* Transforms a vector by this quaternion, applies a uniform scale, and adds another vector to
|
||||
* it, placing the result in the object provided.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Vector3 transformScaleAndAdd (IVector3 vector, double scale, IVector3 add, Vector3 result);
|
||||
|
||||
/**
|
||||
* Transforms a vector by this quaternion and returns the z coordinate of the result.
|
||||
*/
|
||||
double transformZ (IVector3 vector);
|
||||
|
||||
/**
|
||||
* Returns the amount of rotation about the z axis (for the purpose of flattening the
|
||||
* rotation).
|
||||
*/
|
||||
double getRotationZ ();
|
||||
|
||||
/**
|
||||
* Integrates the provided angular velocity over the specified timestep.
|
||||
*
|
||||
* @return a new quaternion containing the result.
|
||||
*/
|
||||
Quaternion integrate (IVector3 velocity, double t);
|
||||
|
||||
/**
|
||||
* Integrates the provided angular velocity over the specified timestep, storing the result in
|
||||
* the object provided.
|
||||
*
|
||||
* @return a reference to the result object, for chaining.
|
||||
*/
|
||||
Quaternion integrate (IVector3 velocity, double t, Quaternion result);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.d;
|
||||
|
||||
import java.nio.DoubleBuffer;
|
||||
|
||||
/**
|
||||
* Provides read-only access to a {@link Vector4}.
|
||||
*/
|
||||
public interface IVector4
|
||||
{
|
||||
/** Returns the x-component of this vector. */
|
||||
double x ();
|
||||
|
||||
/** Returns the y-component of this vector. */
|
||||
double y ();
|
||||
|
||||
/** Returns the z-component of this vector. */
|
||||
double z ();
|
||||
|
||||
/** Returns the w-component of this vector. */
|
||||
double w ();
|
||||
|
||||
/**
|
||||
* Populates the supplied buffer with the contents of this vector.
|
||||
*
|
||||
* @return a reference to the buffer, for chaining.
|
||||
*/
|
||||
DoubleBuffer get (DoubleBuffer buf);
|
||||
|
||||
/**
|
||||
* Compares this vector to another with the provided epsilon.
|
||||
*/
|
||||
boolean epsilonEquals (IVector4 other, double epsilon);
|
||||
}
|
||||
@@ -4,14 +4,18 @@
|
||||
|
||||
package pythagoras.d;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.DoubleBuffer;
|
||||
|
||||
import pythagoras.util.Platform;
|
||||
import pythagoras.util.SingularMatrixException;
|
||||
|
||||
/**
|
||||
* A 3x3 column-major matrix.
|
||||
*/
|
||||
public class Matrix3 extends AbstractMatrix3
|
||||
public class Matrix3 implements IMatrix3, Serializable
|
||||
{
|
||||
/** The identity matrix. */
|
||||
/** the identity matrix. */
|
||||
public static final Matrix3 IDENTITY = new Matrix3();
|
||||
|
||||
/** The values of the matrix. */
|
||||
@@ -57,10 +61,9 @@ public class Matrix3 extends AbstractMatrix3
|
||||
* @return a reference to this matrix, for chaining.
|
||||
*/
|
||||
public Matrix3 setToIdentity () {
|
||||
return set(
|
||||
1f, 0f, 0f,
|
||||
0f, 1f, 0f,
|
||||
0f, 0f, 1f);
|
||||
return set(1f, 0f, 0f,
|
||||
0f, 1f, 0f,
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,27 +95,26 @@ public class Matrix3 extends AbstractMatrix3
|
||||
public Matrix3 setToRotation (double angle, double x, double y, double z) {
|
||||
double c = Math.cos(angle), s = Math.sin(angle), omc = 1f - c;
|
||||
double xs = x*s, ys = y*s, zs = z*s, xy = x*y, xz = x*z, yz = y*z;
|
||||
return set(
|
||||
x*x*omc + c, xy*omc - zs, xz*omc + ys,
|
||||
xy*omc + zs, y*y*omc + c, yz*omc - xs,
|
||||
xz*omc - ys, yz*omc + xs, z*z*omc + c);
|
||||
return set(x*x*omc + c, xy*omc - zs, xz*omc + ys,
|
||||
xy*omc + zs, y*y*omc + c, yz*omc - xs,
|
||||
xz*omc - ys, yz*omc + xs, z*z*omc + c);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Sets this to a rotation matrix. The formula comes from the
|
||||
// * <a href="http://www.j3d.org/matrix_faq/matrfaq_latest.html">Matrix and Quaternion FAQ</a>.
|
||||
// *
|
||||
// * @return a reference to this matrix, for chaining.
|
||||
// */
|
||||
// public Matrix3 setToRotation (Quaternion quat) {
|
||||
// double xx = quat.x*quat.x, yy = quat.y*quat.y, zz = quat.z*quat.z;
|
||||
// double xy = quat.x*quat.y, xz = quat.x*quat.z, xw = quat.x*quat.w;
|
||||
// double yz = quat.y*quat.z, yw = quat.y*quat.w, zw = quat.z*quat.w;
|
||||
// return set(
|
||||
// 1f - 2f*(yy + zz), 2f*(xy - zw), 2f*(xz + yw),
|
||||
// 2f*(xy + zw), 1f - 2f*(xx + zz), 2f*(yz - xw),
|
||||
// 2f*(xz - yw), 2f*(yz + xw), 1f - 2f*(xx + yy));
|
||||
// }
|
||||
/**
|
||||
* Sets this to a rotation matrix. The formula comes from the
|
||||
* <a href="http://www.j3d.org/matrix_faq/matrfaq_latest.html">Matrix and Quaternion FAQ</a>.
|
||||
*
|
||||
* @return a reference to this matrix, for chaining.
|
||||
*/
|
||||
public Matrix3 setToRotation (IQuaternion quat) {
|
||||
double qx = quat.x(), qy = quat.y(), qz = quat.z(), qw = quat.w();
|
||||
double xx = qx*qx, yy = qy*qy, zz = qz*qz;
|
||||
double xy = qx*qy, xz = qx*qz, xw = qx*qw;
|
||||
double yz = qy*qz, yw = qy*qw, zw = qz*qw;
|
||||
return set(1f - 2f*(yy + zz), 2f*(xy - zw), 2f*(xz + yw),
|
||||
2f*(xy + zw), 1f - 2f*(xx + zz), 2f*(yz - xw),
|
||||
2f*(xz - yw), 2f*(yz + xw), 1f - 2f*(xx + yy));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this to a scale matrix.
|
||||
@@ -138,10 +140,9 @@ public class Matrix3 extends AbstractMatrix3
|
||||
* @return a reference to this matrix, for chaining.
|
||||
*/
|
||||
public Matrix3 setToScale (double x, double y, double z) {
|
||||
return set(
|
||||
x, 0f, 0f,
|
||||
0f, y, 0f,
|
||||
0f, 0f, z);
|
||||
return set(x, 0f, 0f,
|
||||
0f, y, 0f,
|
||||
0f, 0f, z);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,10 +162,9 @@ public class Matrix3 extends AbstractMatrix3
|
||||
public Matrix3 setToReflection (double x, double y, double z) {
|
||||
double x2 = -2f*x, y2 = -2f*y, z2 = -2f*z;
|
||||
double xy2 = x2*y, xz2 = x2*z, yz2 = y2*z;
|
||||
return set(
|
||||
1f + x2*x, xy2, xz2,
|
||||
xy2, 1f + y2*y, yz2,
|
||||
xz2, yz2, 1f + z2*z);
|
||||
return set(1f + x2*x, xy2, xz2,
|
||||
xy2, 1f + y2*y, yz2,
|
||||
xz2, yz2, 1f + z2*z);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,10 +182,9 @@ public class Matrix3 extends AbstractMatrix3
|
||||
* @return a reference to this matrix, for chaining.
|
||||
*/
|
||||
public Matrix3 setToTransform (IVector translation, double rotation, double scale) {
|
||||
return setToRotation(rotation).set(
|
||||
m00 * scale, m10 * scale, translation.x(),
|
||||
m01 * scale, m11 * scale, translation.y(),
|
||||
0f, 0f, 1f);
|
||||
return setToRotation(rotation).set(m00 * scale, m10 * scale, translation.x(),
|
||||
m01 * scale, m11 * scale, translation.y(),
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,10 +194,9 @@ public class Matrix3 extends AbstractMatrix3
|
||||
*/
|
||||
public Matrix3 setToTransform (IVector translation, double rotation, IVector scale) {
|
||||
double sx = scale.x(), sy = scale.y();
|
||||
return setToRotation(rotation).set(
|
||||
m00 * sx, m10 * sy, translation.x(),
|
||||
m01 * sx, m11 * sy, translation.y(),
|
||||
0f, 0f, 1f);
|
||||
return setToRotation(rotation).set(m00 * sx, m10 * sy, translation.x(),
|
||||
m01 * sx, m11 * sy, translation.y(),
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,10 +214,9 @@ public class Matrix3 extends AbstractMatrix3
|
||||
* @return a reference to this matrix, for chaining.
|
||||
*/
|
||||
public Matrix3 setToTranslation (double x, double y) {
|
||||
return set(
|
||||
1f, 0f, x,
|
||||
0f, 1f, y,
|
||||
0f, 0f, 1f);
|
||||
return set(1f, 0f, x,
|
||||
0f, 1f, y,
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -249,10 +246,9 @@ public class Matrix3 extends AbstractMatrix3
|
||||
*/
|
||||
public Matrix3 setToRotation (double angle) {
|
||||
double sina = Math.sin(angle), cosa = Math.cos(angle);
|
||||
return set(
|
||||
cosa, -sina, 0f,
|
||||
sina, cosa, 0f,
|
||||
0f, 0f, 1f);
|
||||
return set(cosa, -sina, 0f,
|
||||
sina, cosa, 0f,
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -326,10 +322,9 @@ public class Matrix3 extends AbstractMatrix3
|
||||
* @return a reference to this matrix, for chaining.
|
||||
*/
|
||||
public Matrix3 set (IMatrix3 other) {
|
||||
return set(
|
||||
other.m00(), other.m10(), other.m20(),
|
||||
other.m01(), other.m11(), other.m21(),
|
||||
other.m02(), other.m12(), other.m22());
|
||||
return set(other.m00(), other.m10(), other.m20(),
|
||||
other.m01(), other.m11(), other.m21(),
|
||||
other.m02(), other.m12(), other.m22());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -338,10 +333,9 @@ public class Matrix3 extends AbstractMatrix3
|
||||
* @return a reference to this matrix, for chaining.
|
||||
*/
|
||||
public Matrix3 set (double[] values) {
|
||||
return set(
|
||||
values[0], values[1], values[2],
|
||||
values[3], values[4], values[5],
|
||||
values[6], values[7], values[8]);
|
||||
return set(values[0], values[1], values[2],
|
||||
values[3], values[4], values[5],
|
||||
values[6], values[7], values[8]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -359,48 +353,367 @@ public class Matrix3 extends AbstractMatrix3
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override // from AbstractMatrix3
|
||||
@Override // from IMatrix3
|
||||
public double m00 () {
|
||||
return m00;
|
||||
}
|
||||
|
||||
@Override // from AbstractMatrix3
|
||||
@Override // from IMatrix3
|
||||
public double m10 () {
|
||||
return m10;
|
||||
}
|
||||
|
||||
@Override // from AbstractMatrix3
|
||||
@Override // from IMatrix3
|
||||
public double m20 () {
|
||||
return m20;
|
||||
}
|
||||
|
||||
@Override // from AbstractMatrix3
|
||||
@Override // from IMatrix3
|
||||
public double m01 () {
|
||||
return m01;
|
||||
}
|
||||
|
||||
@Override // from AbstractMatrix3
|
||||
@Override // from IMatrix3
|
||||
public double m11 () {
|
||||
return m11;
|
||||
}
|
||||
|
||||
@Override // from AbstractMatrix3
|
||||
@Override // from IMatrix3
|
||||
public double m21 () {
|
||||
return m21;
|
||||
}
|
||||
|
||||
@Override // from AbstractMatrix3
|
||||
@Override // from IMatrix3
|
||||
public double m02 () {
|
||||
return m02;
|
||||
}
|
||||
|
||||
@Override // from AbstractMatrix3
|
||||
@Override // from IMatrix3
|
||||
public double m12 () {
|
||||
return m12;
|
||||
}
|
||||
|
||||
@Override // from AbstractMatrix3
|
||||
@Override // from IMatrix3
|
||||
public double m22 () {
|
||||
return m22;
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 transpose () {
|
||||
return transpose(new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 transpose (Matrix3 result) {
|
||||
return result.set(m00, m01, m02,
|
||||
m10, m11, m12,
|
||||
m20, m21, m22);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 mult (IMatrix3 other) {
|
||||
return mult(other, new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 mult (IMatrix3 other, Matrix3 result) {
|
||||
double m00 = this.m00, m01 = this.m01, m02 = this.m02;
|
||||
double m10 = this.m10, m11 = this.m11, m12 = this.m12;
|
||||
double m20 = this.m20, m21 = this.m21, m22 = this.m22;
|
||||
double om00 = other.m00(), om01 = other.m01(), om02 = other.m02();
|
||||
double om10 = other.m10(), om11 = other.m11(), om12 = other.m12();
|
||||
double om20 = other.m20(), om21 = other.m21(), om22 = other.m22();
|
||||
return result.set(m00*om00 + m10*om01 + m20*om02,
|
||||
m00*om10 + m10*om11 + m20*om12,
|
||||
m00*om20 + m10*om21 + m20*om22,
|
||||
|
||||
m01*om00 + m11*om01 + m21*om02,
|
||||
m01*om10 + m11*om11 + m21*om12,
|
||||
m01*om20 + m11*om21 + m21*om22,
|
||||
|
||||
m02*om00 + m12*om01 + m22*om02,
|
||||
m02*om10 + m12*om11 + m22*om12,
|
||||
m02*om20 + m12*om21 + m22*om22);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public boolean isAffine () {
|
||||
return (m02 == 0f && m12 == 0f && m22 == 1f);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 multAffine (IMatrix3 other) {
|
||||
return multAffine(other, new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 multAffine (IMatrix3 other, Matrix3 result) {
|
||||
double m00 = this.m00, m01 = this.m01, m02 = this.m02;
|
||||
double m10 = this.m10, m11 = this.m11, m12 = this.m12;
|
||||
double m20 = this.m20, m21 = this.m21, m22 = this.m22;
|
||||
double om00 = other.m00(), om01 = other.m01(), om02 = other.m02();
|
||||
double om10 = other.m10(), om11 = other.m11(), om12 = other.m12();
|
||||
double om20 = other.m20(), om21 = other.m21(), om22 = other.m22();
|
||||
return result.set(m00*om00 + m10*om01,
|
||||
m00*om10 + m10*om11,
|
||||
m00*om20 + m10*om21 + m20,
|
||||
|
||||
m01*om00 + m11*om01,
|
||||
m01*om10 + m11*om11,
|
||||
m01*om20 + m11*om21 + m21,
|
||||
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 invert () {
|
||||
return invert(new Matrix3());
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverts this matrix and places the result in the given object. This code is based on the
|
||||
* examples in the <a href="http://www.j3d.org/matrix_faq/matrfaq_latest.html">Matrix and
|
||||
* Quaternion FAQ</a>.
|
||||
*
|
||||
* @return a reference to the result matrix, for chaining.
|
||||
*/
|
||||
public Matrix3 invert (Matrix3 result) throws SingularMatrixException {
|
||||
double m00 = this.m00, m01 = this.m01, m02 = this.m02;
|
||||
double m10 = this.m10, m11 = this.m11, m12 = this.m12;
|
||||
double m20 = this.m20, m21 = this.m21, m22 = this.m22;
|
||||
// compute the determinant, storing the subdeterminants for later use
|
||||
double sd00 = m11*m22 - m21*m12;
|
||||
double sd10 = m01*m22 - m21*m02;
|
||||
double sd20 = m01*m12 - m11*m02;
|
||||
double det = m00*sd00 + m20*sd20 - m10*sd10;
|
||||
if (Math.abs(det) == 0f) {
|
||||
// determinant is zero; matrix is not invertible
|
||||
throw new SingularMatrixException(this.toString());
|
||||
}
|
||||
double rdet = 1f / det;
|
||||
return result.set(+sd00 * rdet,
|
||||
-(m10*m22 - m20*m12) * rdet,
|
||||
+(m10*m21 - m20*m11) * rdet,
|
||||
|
||||
-sd10 * rdet,
|
||||
+(m00*m22 - m20*m02) * rdet,
|
||||
-(m00*m21 - m20*m01) * rdet,
|
||||
|
||||
+sd20 * rdet,
|
||||
-(m00*m12 - m10*m02) * rdet,
|
||||
+(m00*m11 - m10*m01) * rdet);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 invertAffine () {
|
||||
return invertAffine(new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 invertAffine (Matrix3 result) throws SingularMatrixException {
|
||||
double m00 = this.m00, m01 = this.m01, m02 = this.m02;
|
||||
double m10 = this.m10, m11 = this.m11, m12 = this.m12;
|
||||
double m20 = this.m20, m21 = this.m21, m22 = this.m22;
|
||||
// compute the determinant, storing the subdeterminants for later use
|
||||
double det = m00*m11 - m10*m01;
|
||||
if (Math.abs(det) == 0f) {
|
||||
// determinant is zero; matrix is not invertible
|
||||
throw new SingularMatrixException(this.toString());
|
||||
}
|
||||
double rdet = 1f / det;
|
||||
return result.set(+m11 * rdet,
|
||||
-m10 * rdet,
|
||||
+(m10*m21 - m20*m11) * rdet,
|
||||
|
||||
-m01 * rdet,
|
||||
+m00 * rdet,
|
||||
-(m00*m21 - m20*m01) * rdet,
|
||||
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 lerp (IMatrix3 other, double t) {
|
||||
return lerp(other, t, new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 lerp (IMatrix3 other, double t, Matrix3 result) {
|
||||
double m00 = this.m00, m01 = this.m01, m02 = this.m02;
|
||||
double m10 = this.m10, m11 = this.m11, m12 = this.m12;
|
||||
double m20 = this.m20, m21 = this.m21, m22 = this.m22;
|
||||
double om00 = other.m00(), om01 = other.m01(), om02 = other.m02();
|
||||
double om10 = other.m10(), om11 = other.m11(), om12 = other.m12();
|
||||
double om20 = other.m20(), om21 = other.m21(), om22 = other.m22();
|
||||
return result.set(m00 + t*(om00 - m00),
|
||||
m10 + t*(om10 - m10),
|
||||
m20 + t*(om20 - m20),
|
||||
|
||||
m01 + t*(om01 - m01),
|
||||
m11 + t*(om11 - m11),
|
||||
m21 + t*(om21 - m21),
|
||||
|
||||
m02 + t*(om02 - m02),
|
||||
m12 + t*(om12 - m12),
|
||||
m22 + t*(om22 - m22));
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 lerpAffine (IMatrix3 other, double t) {
|
||||
return lerpAffine(other, t, new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 lerpAffine (IMatrix3 other, double t, Matrix3 result) {
|
||||
double m00 = this.m00, m01 = this.m01, m02 = this.m02;
|
||||
double m10 = this.m10, m11 = this.m11, m12 = this.m12;
|
||||
double m20 = this.m20, m21 = this.m21, m22 = this.m22;
|
||||
double om00 = other.m00(), om01 = other.m01(), om02 = other.m02();
|
||||
double om10 = other.m10(), om11 = other.m11(), om12 = other.m12();
|
||||
double om20 = other.m20(), om21 = other.m21(), om22 = other.m22();
|
||||
return result.set(m00 + t*(om00 - m00),
|
||||
m10 + t*(om10 - m10),
|
||||
m20 + t*(om20 - m20),
|
||||
|
||||
m01 + t*(om01 - m01),
|
||||
m11 + t*(om11 - m11),
|
||||
m21 + t*(om21 - m21),
|
||||
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public DoubleBuffer get (DoubleBuffer buf) {
|
||||
buf.put(m00).put(m01).put(m02);
|
||||
buf.put(m10).put(m11).put(m12);
|
||||
buf.put(m20).put(m21).put(m22);
|
||||
return buf;
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector3 transformLocal (Vector3 vector) {
|
||||
return transform(vector, vector);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector3 transform (IVector3 vector) {
|
||||
return transform(vector, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector3 transform (IVector3 vector, Vector3 result) {
|
||||
double vx = vector.x(), vy = vector.y(), vz = vector.z();
|
||||
return result.set(m00*vx + m10*vy + m20*vz,
|
||||
m01*vx + m11*vy + m21*vz,
|
||||
m02*vx + m12*vy + m22*vz);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector transformPointLocal (Vector point) {
|
||||
return transformPoint(point, point);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector transformPoint (IVector point) {
|
||||
return transformPoint(point, new Vector());
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector transformPoint (IVector point, Vector result) {
|
||||
double px = point.x(), py = point.y();
|
||||
return result.set(m00*px + m10*py + m20, m01*px + m11*py + m21);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector transformVectorLocal (Vector vector) {
|
||||
return transformVector(vector, vector);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector transformVector (IVector vector) {
|
||||
return transformVector(vector, new Vector());
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector transformVector (IVector vector, Vector result) {
|
||||
double vx = vector.x(), vy = vector.y();
|
||||
return result.set(m00*vx + m10*vy, m01*vx + m11*vy);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public double extractRotation () {
|
||||
// start with the contents of the upper 2x2 portion of the matrix
|
||||
double n00 = m00, n10 = m10;
|
||||
double n01 = m01, n11 = m11;
|
||||
for (int ii = 0; ii < 10; ii++) {
|
||||
// store the results of the previous iteration
|
||||
double o00 = n00, o10 = n10;
|
||||
double o01 = n01, o11 = n11;
|
||||
|
||||
// compute average of the matrix with its inverse transpose
|
||||
double det = o00*o11 - o10*o01;
|
||||
if (Math.abs(det) == 0f) {
|
||||
// determinant is zero; matrix is not invertible
|
||||
throw new SingularMatrixException(this.toString());
|
||||
}
|
||||
double hrdet = 0.5f / det;
|
||||
n00 = +o11 * hrdet + o00*0.5f;
|
||||
n10 = -o01 * hrdet + o10*0.5f;
|
||||
|
||||
n01 = -o10 * hrdet + o01*0.5f;
|
||||
n11 = +o00 * hrdet + o11*0.5f;
|
||||
|
||||
// compute the difference; if it's small enough, we're done
|
||||
double d00 = n00 - o00, d10 = n10 - o10;
|
||||
double d01 = n01 - o01, d11 = n11 - o11;
|
||||
if (d00*d00 + d10*d10 + d01*d01 + d11*d11 < MathUtil.EPSILON) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// now that we have a nice orthogonal matrix, we can extract the rotation
|
||||
return Math.atan2(n01, n00);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector extractScale () {
|
||||
return extractScale(new Vector());
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector extractScale (Vector result) {
|
||||
double m00 = this.m00, m01 = this.m01, m10 = this.m10, m11 = this.m11;
|
||||
return result.set(Math.sqrt(m00*m00 + m01*m01),
|
||||
Math.sqrt(m10*m10 + m11*m11));
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public double approximateUniformScale () {
|
||||
double cp = m00*m11 - m01*m10;
|
||||
return (cp < 0f) ? -Math.sqrt(-cp) : Math.sqrt(cp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString () {
|
||||
return ("[[" + m00 + ", " + m10 + ", " + m20 + "], " +
|
||||
"[" + m01 + ", " + m11 + ", " + m21 + "], " +
|
||||
"[" + m02 + ", " + m12 + ", " + m22 + "]]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode () {
|
||||
return Platform.hashCode(m00) ^ Platform.hashCode(m10) ^ Platform.hashCode(m20) ^
|
||||
Platform.hashCode(m01) ^ Platform.hashCode(m11) ^ Platform.hashCode(m21) ^
|
||||
Platform.hashCode(m02) ^ Platform.hashCode(m12) ^ Platform.hashCode(m22);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals (Object other) {
|
||||
if (!(other instanceof Matrix3)) {
|
||||
return false;
|
||||
}
|
||||
Matrix3 omat = (Matrix3)other;
|
||||
return (m00 == omat.m00 && m10 == omat.m10 && m20 == omat.m20 &&
|
||||
m01 == omat.m01 && m11 == omat.m11 && m21 == omat.m21 &&
|
||||
m02 == omat.m02 && m12 == omat.m12 && m22 == omat.m22);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,232 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.d;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.DoubleBuffer;
|
||||
|
||||
import pythagoras.util.Platform;
|
||||
|
||||
/**
|
||||
* A plane consisting of a unit normal and a constant. All points on the plane satisfy the equation
|
||||
* {@code Ax + By + Cz + D = 0}, where (A, B, C) is the plane normal and D is the constant.
|
||||
*/
|
||||
public class Plane implements IPlane, Serializable
|
||||
{
|
||||
/** The X/Y plane. */
|
||||
public static final Plane XY_PLANE = new Plane(Vector3.UNIT_Z, 0f);
|
||||
|
||||
/** The X/Z plane. */
|
||||
public static final Plane XZ_PLANE = new Plane(Vector3.UNIT_Y, 0f);
|
||||
|
||||
/** The Y/Z plane. */
|
||||
public static final Plane YZ_PLANE = new Plane(Vector3.UNIT_X, 0f);
|
||||
|
||||
/** The plane constant. */
|
||||
public double constant;
|
||||
|
||||
/**
|
||||
* Creates a plane from the specified normal and constant.
|
||||
*/
|
||||
public Plane (IVector3 normal, double constant) {
|
||||
set(normal, constant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a plane with the specified parameters.
|
||||
*/
|
||||
public Plane (double[] values) {
|
||||
set(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a plane with the specified parameters.
|
||||
*/
|
||||
public Plane (double a, double b, double c, double d) {
|
||||
set(a, b, c, d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*/
|
||||
public Plane (Plane other) {
|
||||
set(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty (invalid) plane.
|
||||
*/
|
||||
public Plane () {
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the parameters of another plane.
|
||||
*
|
||||
* @return a reference to this plane (for chaining).
|
||||
*/
|
||||
public Plane set (Plane other) {
|
||||
return set(other.normal(), other.constant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parameters of the plane.
|
||||
*
|
||||
* @return a reference to this plane (for chaining).
|
||||
*/
|
||||
public Plane set (IVector3 normal, double constant) {
|
||||
return set(normal.x(), normal.y(), normal.z(), constant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parameters of the plane.
|
||||
*
|
||||
* @return a reference to this plane (for chaining).
|
||||
*/
|
||||
public Plane set (double[] values) {
|
||||
return set(values[0], values[1], values[2], values[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parameters of the plane.
|
||||
*
|
||||
* @return a reference to this plane (for chaining).
|
||||
*/
|
||||
public Plane set (double a, double b, double c, double d) {
|
||||
_normal.set(a, b, c);
|
||||
constant = d;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this plane based on the three points provided.
|
||||
*
|
||||
* @return a reference to the plane (for chaining).
|
||||
*/
|
||||
public Plane fromPoints (IVector3 p1, IVector3 p2, IVector3 p3) {
|
||||
// compute the normal by taking the cross product of the two vectors formed
|
||||
p2.subtract(p1, _v1);
|
||||
p3.subtract(p1, _v2);
|
||||
_v1.cross(_v2, _normal).normalizeLocal();
|
||||
|
||||
// use the first point to determine the constant
|
||||
constant = -_normal.dot(p1);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this plane based on a point on the plane and the plane normal.
|
||||
*
|
||||
* @return a reference to the plane (for chaining).
|
||||
*/
|
||||
public Plane fromPointNormal (IVector3 pt, IVector3 normal) {
|
||||
return set(normal, -normal.dot(pt));
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Transforms this plane in-place by the specified transformation.
|
||||
// *
|
||||
// * @return a reference to this plane, for chaining.
|
||||
// */
|
||||
// public Plane transformLocal (Transform transform) {
|
||||
// return transform(transform, this);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Negates this plane in-place.
|
||||
*
|
||||
* @return a reference to this plane, for chaining.
|
||||
*/
|
||||
public Plane negateLocal () {
|
||||
return negate(this);
|
||||
}
|
||||
|
||||
@Override // from IPlane
|
||||
public double constant () {
|
||||
return constant;
|
||||
}
|
||||
|
||||
@Override // from IPlane
|
||||
public IVector3 normal () {
|
||||
return _normal;
|
||||
}
|
||||
|
||||
@Override // from IPlane
|
||||
public DoubleBuffer get (DoubleBuffer buf) {
|
||||
return buf.put(_normal.x).put(_normal.y).put(_normal.z).put(constant);
|
||||
}
|
||||
|
||||
@Override // from IPlane
|
||||
public double distance (IVector3 pt) {
|
||||
return _normal.dot(pt) + constant;
|
||||
}
|
||||
|
||||
// @Override // from IPlane
|
||||
// public Plane transform (Transform transform) {
|
||||
// return transform(transform, new Plane());
|
||||
// }
|
||||
|
||||
// @Override // from IPlane
|
||||
// public Plane transform (Transform transform, Plane result) {
|
||||
// transform.transformPointLocal(_normal.mult(-constant, _v1));
|
||||
// transform.transformVector(_normal, _v2).normalizeLocal();
|
||||
// return result.fromPointNormal(_v1, _v2);
|
||||
// }
|
||||
|
||||
@Override // from IPlane
|
||||
public Plane negate () {
|
||||
return negate(new Plane());
|
||||
}
|
||||
|
||||
@Override // from IPlane
|
||||
public Plane negate (Plane result) {
|
||||
_normal.negate(result._normal);
|
||||
result.constant = -constant;
|
||||
return result;
|
||||
}
|
||||
|
||||
// @Override // from IPlane
|
||||
// public boolean intersection (Ray3D ray, Vector3 result) {
|
||||
// double distance = distance(ray);
|
||||
// if (Double.isNaN(distance) || distance < 0f) {
|
||||
// return false;
|
||||
// } else {
|
||||
// ray.origin().addScaled(ray.direction(), distance, result);
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
|
||||
// @Override // from IPlane
|
||||
// public double distance (Ray3D ray) {
|
||||
// double dividend = -distance(ray.origin());
|
||||
// double divisor = _normal.dot(ray.direction());
|
||||
// if (Math.abs(dividend) < MathUtil.EPSILON) {
|
||||
// return 0f; // origin is on plane
|
||||
// } else if (Math.abs(divisor) < MathUtil.EPSILON) {
|
||||
// return Float.NaN; // ray is parallel to plane
|
||||
// } else {
|
||||
// return dividend / divisor;
|
||||
// }
|
||||
// }
|
||||
|
||||
@Override
|
||||
public int hashCode () {
|
||||
return _normal.hashCode() ^ Platform.hashCode(constant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals (Object other) {
|
||||
if (!(other instanceof Plane)) {
|
||||
return false;
|
||||
}
|
||||
Plane oplane = (Plane)other;
|
||||
return constant == oplane.constant && _normal.equals(oplane.normal());
|
||||
}
|
||||
|
||||
/** The plane normal. */
|
||||
protected final Vector3 _normal = new Vector3();
|
||||
|
||||
/** Working vectors for computation. */
|
||||
protected final Vector3 _v1 = new Vector3(), _v2 = new Vector3();
|
||||
}
|
||||
@@ -0,0 +1,515 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.d;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Random;
|
||||
|
||||
import pythagoras.util.Platform;
|
||||
|
||||
/**
|
||||
* A unit quaternion. Many of the formulas come from the
|
||||
* <a href="http://www.j3d.org/matrix_faq/matrfaq_latest.html">Matrix and Quaternion FAQ</a>.
|
||||
*/
|
||||
public class Quaternion implements IQuaternion, Serializable
|
||||
{
|
||||
/** The identity quaternion. */
|
||||
public static final IQuaternion IDENTITY = new Quaternion(0f, 0f, 0f, 1f);
|
||||
|
||||
/** The components of the quaternion. */
|
||||
public double x, y, z, w;
|
||||
|
||||
/**
|
||||
* Creates a quaternion from four components.
|
||||
*/
|
||||
public Quaternion (double x, double y, double z, double w) {
|
||||
set(x, y, z, w);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a quaternion from an array of values.
|
||||
*/
|
||||
public Quaternion (double[] values) {
|
||||
set(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*/
|
||||
public Quaternion (IQuaternion other) {
|
||||
set(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an identity quaternion.
|
||||
*/
|
||||
public Quaternion () {
|
||||
set(0f, 0f, 0f, 1f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the elements of another quaternion.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion set (IQuaternion other) {
|
||||
return set(other.x(), other.y(), other.z(), other.w());
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the elements of an array.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion set (double[] values) {
|
||||
return set(values[0], values[1], values[2], values[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all of the elements of the quaternion.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion set (double x, double y, double z, double w) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.w = w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this quaternion to the rotation of the first normalized vector onto the second.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion fromVectors (IVector3 from, IVector3 to) {
|
||||
double angle = from.angle(to);
|
||||
if (angle < MathUtil.EPSILON) {
|
||||
return set(IDENTITY);
|
||||
}
|
||||
if (angle <= Math.PI - MathUtil.EPSILON) {
|
||||
return fromAngleAxis(angle, from.cross(to).normalizeLocal());
|
||||
}
|
||||
// it's a 180 degree rotation; any axis orthogonal to the from vector will do
|
||||
Vector3 axis = new Vector3(0f, from.z(), -from.y());
|
||||
double length = axis.length();
|
||||
return fromAngleAxis(Math.PI, length < MathUtil.EPSILON ?
|
||||
axis.set(-from.z(), 0f, from.x()).normalizeLocal() :
|
||||
axis.multLocal(1f / length));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this quaternion to the rotation of (0, 0, -1) onto the supplied normalized vector.
|
||||
*
|
||||
* @return a reference to the quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion fromVectorFromNegativeZ (IVector3 to) {
|
||||
return fromVectorFromNegativeZ(to.x(), to.y(), to.z());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this quaternion to the rotation of (0, 0, -1) onto the supplied normalized vector.
|
||||
*
|
||||
* @return a reference to the quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion fromVectorFromNegativeZ (double tx, double ty, double tz) {
|
||||
double angle = Math.acos(-tz);
|
||||
if (angle < MathUtil.EPSILON) {
|
||||
return set(IDENTITY);
|
||||
}
|
||||
if (angle > Math.PI - MathUtil.EPSILON) {
|
||||
return set(0f, 1f, 0f, 0f); // 180 degrees about y
|
||||
}
|
||||
double len = Math.hypot(tx, ty);
|
||||
return fromAngleAxis(angle, ty/len, -tx/len, 0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this quaternion to one that rotates onto the given unit axes.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion fromAxes (IVector3 nx, IVector3 ny, IVector3 nz) {
|
||||
double nxx = nx.x(), nyy = ny.y(), nzz = nz.z();
|
||||
double x2 = (1f + nxx - nyy - nzz)/4f;
|
||||
double y2 = (1f - nxx + nyy - nzz)/4f;
|
||||
double z2 = (1f - nxx - nyy + nzz)/4f;
|
||||
double w2 = (1f - x2 - y2 - z2);
|
||||
return set(Math.sqrt(x2) * (ny.z() >= nz.y() ? +1f : -1f),
|
||||
Math.sqrt(y2) * (nz.x() >= nx.z() ? +1f : -1f),
|
||||
Math.sqrt(z2) * (nx.y() >= ny.x() ? +1f : -1f),
|
||||
Math.sqrt(w2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this quaternion to the rotation described by the given angle and normalized
|
||||
* axis.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion fromAngleAxis (double angle, IVector3 axis) {
|
||||
return fromAngleAxis(angle, axis.x(), axis.y(), axis.z());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this quaternion to the rotation described by the given angle and normalized
|
||||
* axis.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion fromAngleAxis (double angle, double x, double y, double z) {
|
||||
double sina = Math.sin(angle / 2f);
|
||||
return set(x*sina, y*sina, z*sina, Math.cos(angle / 2f));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this to a random rotation obtained from a completely uniform distribution.
|
||||
*/
|
||||
public Quaternion randomize (Random rand) {
|
||||
// pick angles according to the surface area distribution
|
||||
return fromAngles(MathUtil.lerp(-Math.PI, +Math.PI, rand.nextFloat()),
|
||||
Math.asin(MathUtil.lerp(-1f, +1f, rand.nextFloat())),
|
||||
MathUtil.lerp(-Math.PI, +Math.PI, rand.nextFloat()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this quaternion to one that first rotates about x by the specified number of radians,
|
||||
* then rotates about z by the specified number of radians.
|
||||
*/
|
||||
public Quaternion fromAnglesXZ (double x, double z) {
|
||||
double hx = x * 0.5f, hz = z * 0.5f;
|
||||
double sx = Math.sin(hx), cx = Math.cos(hx);
|
||||
double sz = Math.sin(hz), cz = Math.cos(hz);
|
||||
return set(cz*sx, sz*sx, sz*cx, cz*cx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this quaternion to one that first rotates about x by the specified number of radians,
|
||||
* then rotates about y by the specified number of radians.
|
||||
*/
|
||||
public Quaternion fromAnglesXY (double x, double y) {
|
||||
double hx = x * 0.5f, hy = y * 0.5f;
|
||||
double sx = Math.sin(hx), cx = Math.cos(hx);
|
||||
double sy = Math.sin(hy), cy = Math.cos(hy);
|
||||
return set(cy*sx, sy*cx, -sy*sx, cy*cx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this quaternion to one that first rotates about x by the specified number of radians,
|
||||
* then rotates about y, then about z.
|
||||
*/
|
||||
public Quaternion fromAngles (Vector3 angles) {
|
||||
return fromAngles(angles.x, angles.y, angles.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this quaternion to one that first rotates about x by the specified number of radians,
|
||||
* then rotates about y, then about z.
|
||||
*/
|
||||
public Quaternion fromAngles (double x, double y, double z) {
|
||||
// TODO: it may be more convenient to define the angles in the opposite order (first z,
|
||||
// then y, then x)
|
||||
double hx = x * 0.5f, hy = y * 0.5f, hz = z * 0.5f;
|
||||
double sz = Math.sin(hz), cz = Math.cos(hz);
|
||||
double sy = Math.sin(hy), cy = Math.cos(hy);
|
||||
double sx = Math.sin(hx), cx = Math.cos(hx);
|
||||
double szsy = sz*sy, czsy = cz*sy, szcy = sz*cy, czcy = cz*cy;
|
||||
return set(
|
||||
czcy*sx - szsy*cx,
|
||||
czsy*cx + szcy*sx,
|
||||
szcy*cx - czsy*sx,
|
||||
czcy*cx + szsy*sx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes this quaternion in-place.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion normalizeLocal () {
|
||||
return normalize(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverts this quaternion in-place.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion invertLocal () {
|
||||
return invert(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies this quaternion in-place by another.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion multLocal (IQuaternion other) {
|
||||
return mult(other, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolates in-place between this and the specified other quaternion.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion slerpLocal (IQuaternion other, double t) {
|
||||
return slerp(other, t, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a vector in-place by this quaternion.
|
||||
*
|
||||
* @return a reference to the vector, for chaining.
|
||||
*/
|
||||
public Vector3 transformLocal (Vector3 vector) {
|
||||
return transform(vector, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Integrates in-place the provided angular velocity over the specified timestep.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion integrateLocal (IVector3 velocity, double t) {
|
||||
return integrate(velocity, t, this);
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public double x () {
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public double y () {
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public double z () {
|
||||
return z;
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public double w () {
|
||||
return w;
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public void get (double[] values) {
|
||||
values[0] = x;
|
||||
values[1] = y;
|
||||
values[2] = z;
|
||||
values[3] = w;
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public boolean hasNaN () {
|
||||
return Double.isNaN(x) || Double.isNaN(y) || Double.isNaN(z) || Double.isNaN(w);
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Vector3 toAngles (Vector3 result) {
|
||||
double sy = 2f*(y*w - x*z);
|
||||
if (sy < 1f - MathUtil.EPSILON) {
|
||||
if (sy > -1 + MathUtil.EPSILON) {
|
||||
return result.set(Math.atan2(y*z + x*w, 0.5f - (x*x + y*y)),
|
||||
Math.asin(sy),
|
||||
Math.atan2(x*y + z*w, 0.5f - (y*y + z*z)));
|
||||
} else {
|
||||
// not a unique solution; x + z = atan2(-m21, m11)
|
||||
return result.set(0f,
|
||||
-MathUtil.HALF_PI,
|
||||
Math.atan2(x*w - y*z, 0.5f - (x*x + z*z)));
|
||||
}
|
||||
} else {
|
||||
// not a unique solution; x - z = atan2(-m21, m11)
|
||||
return result.set(0f,
|
||||
MathUtil.HALF_PI,
|
||||
-Math.atan2(x*w - y*z, 0.5f - (x*x + z*z)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Vector3 toAngles () {
|
||||
return toAngles(new Vector3());
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Quaternion normalize () {
|
||||
return normalize(new Quaternion());
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Quaternion normalize (Quaternion result) {
|
||||
double rlen = 1f / Math.sqrt(x*x + y*y + z*z + w*w);
|
||||
return result.set(x*rlen, y*rlen, z*rlen, w*rlen);
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Quaternion invert () {
|
||||
return invert(new Quaternion());
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Quaternion invert (Quaternion result) {
|
||||
return result.set(-x, -y, -z, w);
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Quaternion mult (IQuaternion other) {
|
||||
return mult(other, new Quaternion());
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Quaternion mult (IQuaternion other, Quaternion result) {
|
||||
double ox = other.x(), oy = other.y(), oz = other.z(), ow = other.w();
|
||||
return result.set(w*ox + x*ow + y*oz - z*oy,
|
||||
w*oy + y*ow + z*ox - x*oz,
|
||||
w*oz + z*ow + x*oy - y*ox,
|
||||
w*ow - x*ox - y*oy - z*oz);
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Quaternion slerp (IQuaternion other, double t) {
|
||||
return slerp(other, t, new Quaternion());
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Quaternion slerp (IQuaternion other, double t, Quaternion result) {
|
||||
double ox = other.x(), oy = other.y(), oz = other.z(), ow = other.w();
|
||||
double cosa = x*ox + y*oy + z*oz + w*ow, s0, s1;
|
||||
|
||||
// adjust signs if necessary
|
||||
if (cosa < 0f) {
|
||||
cosa = -cosa;
|
||||
ox = -ox;
|
||||
oy = -oy;
|
||||
oz = -oz;
|
||||
ow = -ow;
|
||||
}
|
||||
|
||||
// calculate coefficients; if the angle is too close to zero, we must fall back
|
||||
// to linear interpolation
|
||||
if ((1f - cosa) > MathUtil.EPSILON) {
|
||||
double angle = Math.acos(cosa), sina = Math.sin(angle);
|
||||
s0 = Math.sin((1f - t) * angle) / sina;
|
||||
s1 = Math.sin(t * angle) / sina;
|
||||
} else {
|
||||
s0 = 1f - t;
|
||||
s1 = t;
|
||||
}
|
||||
|
||||
return result.set(s0*x + s1*ox, s0*y + s1*oy, s0*z + s1*oz, s0*w + s1*ow);
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Vector3 transform (IVector3 vector) {
|
||||
return transform(vector, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Vector3 transform (IVector3 vector, Vector3 result) {
|
||||
double xx = x*x, yy = y*y, zz = z*z;
|
||||
double xy = x*y, xz = x*z, xw = x*w;
|
||||
double yz = y*z, yw = y*w, zw = z*w;
|
||||
double vx = vector.x(), vy = vector.y(), vz = vector.z();
|
||||
double vx2 = vx*2f, vy2 = vy*2f, vz2 = vz*2f;
|
||||
return result.set(vx + vy2*(xy - zw) + vz2*(xz + yw) - vx2*(yy + zz),
|
||||
vy + vx2*(xy + zw) + vz2*(yz - xw) - vy2*(xx + zz),
|
||||
vz + vx2*(xz - yw) + vy2*(yz + xw) - vz2*(xx + yy));
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Vector3 transformUnitX (Vector3 result) {
|
||||
return result.set(1f - 2f*(y*y + z*z), 2f*(x*y + z*w), 2f*(x*z - y*w));
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Vector3 transformUnitY (Vector3 result) {
|
||||
return result.set(2f*(x*y - z*w), 1f - 2f*(x*x + z*z), 2f*(y*z + x*w));
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Vector3 transformUnitZ (Vector3 result) {
|
||||
return result.set(2f*(x*z + y*w), 2f*(y*z - x*w), 1f - 2f*(x*x + y*y));
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Vector3 transformAndAdd (IVector3 vector, IVector3 add, Vector3 result) {
|
||||
double xx = x*x, yy = y*y, zz = z*z;
|
||||
double xy = x*y, xz = x*z, xw = x*w;
|
||||
double yz = y*z, yw = y*w, zw = z*w;
|
||||
double vx = vector.x(), vy = vector.y(), vz = vector.z();
|
||||
double vx2 = vx*2f, vy2 = vy*2f, vz2 = vz*2f;
|
||||
return result.set(vx + vy2*(xy - zw) + vz2*(xz + yw) - vx2*(yy + zz) + add.x(),
|
||||
vy + vx2*(xy + zw) + vz2*(yz - xw) - vy2*(xx + zz) + add.y(),
|
||||
vz + vx2*(xz - yw) + vy2*(yz + xw) - vz2*(xx + yy) + add.z());
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Vector3 transformScaleAndAdd (IVector3 vector, double scale, IVector3 add,
|
||||
Vector3 result) {
|
||||
double xx = x*x, yy = y*y, zz = z*z;
|
||||
double xy = x*y, xz = x*z, xw = x*w;
|
||||
double yz = y*z, yw = y*w, zw = z*w;
|
||||
double vx = vector.x(), vy = vector.y(), vz = vector.z();
|
||||
double vx2 = vx*2f, vy2 = vy*2f, vz2 = vz*2f;
|
||||
return result.set(
|
||||
(vx + vy2*(xy - zw) + vz2*(xz + yw) - vx2*(yy + zz)) * scale + add.x(),
|
||||
(vy + vx2*(xy + zw) + vz2*(yz - xw) - vy2*(xx + zz)) * scale + add.y(),
|
||||
(vz + vx2*(xz - yw) + vy2*(yz + xw) - vz2*(xx + yy)) * scale + add.z());
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public double transformZ (IVector3 vector) {
|
||||
return vector.z() + vector.x()*2f*(x*z - y*w) +
|
||||
vector.y()*2f*(y*z + x*w) - vector.z()*2f*(x*x + y*y);
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public double getRotationZ () {
|
||||
return Math.atan2(2f*(x*y + z*w), 1f - 2f*(y*y + z*z));
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Quaternion integrate (IVector3 velocity, double t) {
|
||||
return integrate(velocity, t, new Quaternion());
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Quaternion integrate (IVector3 velocity, double t, Quaternion result) {
|
||||
// TODO: use Runge-Kutta integration?
|
||||
double qx = 0.5f * velocity.x();
|
||||
double qy = 0.5f * velocity.y();
|
||||
double qz = 0.5f * velocity.z();
|
||||
return result.set(x + t*(qx*w + qy*z - qz*y),
|
||||
y + t*(qy*w + qz*x - qx*z),
|
||||
z + t*(qz*w + qx*y - qy*x),
|
||||
w + t*(-qx*x - qy*y - qz*z)).normalizeLocal();
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public String toString () {
|
||||
return "[" + x + ", " + y + ", " + z + ", " + w + "]";
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public int hashCode () {
|
||||
return Platform.hashCode(x) ^ Platform.hashCode(y) ^ Platform.hashCode(z) ^
|
||||
Platform.hashCode(w);
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public boolean equals (Object other) {
|
||||
if (!(other instanceof Quaternion)) {
|
||||
return false;
|
||||
}
|
||||
Quaternion oquat = (Quaternion)other;
|
||||
return (x == oquat.x && y == oquat.y && z == oquat.z && w == oquat.w) ||
|
||||
(x == -oquat.x && y == -oquat.y && z == -oquat.z && w == -oquat.x);
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,14 @@
|
||||
package pythagoras.d;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.DoubleBuffer;
|
||||
|
||||
import pythagoras.util.Platform;
|
||||
|
||||
/**
|
||||
* A three element vector.
|
||||
*/
|
||||
public class Vector3 extends AbstractVector3 implements Serializable
|
||||
public class Vector3 implements IVector3, Serializable
|
||||
{
|
||||
/** A unit vector in the X+ direction. */
|
||||
public static final IVector3 UNIT_X = new Vector3(1f, 0f, 0f);
|
||||
@@ -189,18 +192,206 @@ public class Vector3 extends AbstractVector3 implements Serializable
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override // from AbstractVector3
|
||||
@Override // from IVector3
|
||||
public double x () {
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override // from AbstractVector3
|
||||
@Override // from IVector3
|
||||
public double y () {
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override // from AbstractVector3
|
||||
@Override // from IVector3
|
||||
public double z () {
|
||||
return z;
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public double dot (IVector3 other) {
|
||||
return x*other.x() + y*other.y() + z*other.z();
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 cross (IVector3 other) {
|
||||
return cross(other, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 cross (IVector3 other, Vector3 result) {
|
||||
double x = this.x, y = this.y, z = this.z;
|
||||
double ox = other.x(), oy = other.y(), oz = other.z();
|
||||
return result.set(y*oz - z*oy, z*ox - x*oz, x*oy - y*ox);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public double triple (IVector3 b, IVector3 c) {
|
||||
double bx = b.x(), by = b.y(), bz = b.z();
|
||||
double cx = c.x(), cy = c.y(), cz = c.z();
|
||||
return x()*(by*cz - bz*cy) + y()*(bz*cx - bx*cz) + z()*(bx*cy - by*cx);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 negate () {
|
||||
return negate(new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 negate (Vector3 result) {
|
||||
return result.set(-x, -y, -z);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 normalize () {
|
||||
return normalize(new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 normalize (Vector3 result) {
|
||||
return mult(1f / length(), result);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public double angle (IVector3 other) {
|
||||
return Math.acos(dot(other) / (length() * other.length()));
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public double length () {
|
||||
return Math.sqrt(lengthSquared());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public double lengthSquared () {
|
||||
double x = this.x, y = this.y, z = this.z;
|
||||
return (x*x + y*y + z*z);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public double distance (IVector3 other) {
|
||||
return Math.sqrt(distanceSquared(other));
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public double distanceSquared (IVector3 other) {
|
||||
double dx = x - other.x(), dy = y - other.y(), dz = z - other.z();
|
||||
return dx*dx + dy*dy + dz*dz;
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public double manhattanDistance (IVector3 other) {
|
||||
return Math.abs(x - other.x()) + Math.abs(y - other.y()) + Math.abs(z - other.z());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 mult (double v) {
|
||||
return mult(v, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 mult (double v, Vector3 result) {
|
||||
return result.set(x*v, y*v, z*v);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 mult (IVector3 other) {
|
||||
return mult(other, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 mult (IVector3 other, Vector3 result) {
|
||||
return result.set(x*other.x(), y*other.y(), z*other.z());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 add (IVector3 other) {
|
||||
return add(other, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 add (IVector3 other, Vector3 result) {
|
||||
return add(other.x(), other.y(), other.z(), result);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 subtract (IVector3 other) {
|
||||
return subtract(other, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 subtract (IVector3 other, Vector3 result) {
|
||||
return add(-other.x(), -other.y(), -other.z(), result);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 add (double x, double y, double z) {
|
||||
return add(x, y, z, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 add (double x, double y, double z, Vector3 result) {
|
||||
return result.set(this.x + x, this.y + y, this.z + z);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 addScaled (IVector3 other, double v) {
|
||||
return addScaled(other, v, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 addScaled (IVector3 other, double v, Vector3 result) {
|
||||
return result.set(x + other.x()*v, y + other.y()*v, z + other.z()*v);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 lerp (IVector3 other, double t) {
|
||||
return lerp(other, t, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 lerp (IVector3 other, double t, Vector3 result) {
|
||||
double x = this.x, y = this.y, z = this.z;
|
||||
return result.set(x + t*(other.x() - x), y + t*(other.y() - y), z + t*(other.z() - z));
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public double get (int idx) {
|
||||
switch (idx) {
|
||||
case 0: return x;
|
||||
case 1: return y;
|
||||
case 2: return z;
|
||||
}
|
||||
throw new IndexOutOfBoundsException(String.valueOf(idx));
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public void get (double[] values) {
|
||||
values[0] = x;
|
||||
values[1] = y;
|
||||
values[2] = z;
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public DoubleBuffer get (DoubleBuffer buf) {
|
||||
return buf.put(x).put(y).put(z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString () {
|
||||
return "[" + x + ", " + y + ", " + z + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode () {
|
||||
return Platform.hashCode(x) ^ Platform.hashCode(y) ^ Platform.hashCode(z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals (Object other) {
|
||||
if (!(other instanceof Vector3)) {
|
||||
return false;
|
||||
}
|
||||
Vector3 ovec = (Vector3)other;
|
||||
return (x == ovec.x && y == ovec.y && z == ovec.z);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.d;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.DoubleBuffer;
|
||||
|
||||
import pythagoras.util.Platform;
|
||||
|
||||
/**
|
||||
* A four element vector.
|
||||
*/
|
||||
public class Vector4 implements IVector4, Serializable
|
||||
{
|
||||
/** The components of the vector. */
|
||||
public double x, y, z, w;
|
||||
|
||||
/**
|
||||
* Creates a vector from four components.
|
||||
*/
|
||||
public Vector4 (double x, double y, double z, double w)
|
||||
{
|
||||
set(x, y, z, w);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a vector from four components.
|
||||
*/
|
||||
public Vector4 (double[] values) {
|
||||
set(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a vector from a double buffer.
|
||||
*/
|
||||
public Vector4 (DoubleBuffer buf) {
|
||||
set(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*/
|
||||
public Vector4 (IVector4 other) {
|
||||
set(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a zero vector.
|
||||
*/
|
||||
public Vector4 () {
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the elements of another vector.
|
||||
*
|
||||
* @return a reference to this vector, for chaining.
|
||||
*/
|
||||
public Vector4 set (IVector4 other) {
|
||||
return set(other.x(), other.y(), other.z(), other.w());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all of the elements of the vector.
|
||||
*
|
||||
* @return a reference to this vector, for chaining.
|
||||
*/
|
||||
public Vector4 set (double[] values) {
|
||||
return set(values[0], values[1], values[2], values[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all of the elements of the vector.
|
||||
*
|
||||
* @return a reference to this vector, for chaining.
|
||||
*/
|
||||
public Vector4 set (DoubleBuffer buf) {
|
||||
return set(buf.get(), buf.get(), buf.get(), buf.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all of the elements of the vector.
|
||||
*
|
||||
* @return a reference to this vector, for chaining.
|
||||
*/
|
||||
public Vector4 set (double x, double y, double z, double w) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.w = w;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override // from IVector4
|
||||
public double x () {
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override // from IVector4
|
||||
public double y () {
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override // from IVector4
|
||||
public double z () {
|
||||
return z;
|
||||
}
|
||||
|
||||
@Override // from IVector4
|
||||
public double w () {
|
||||
return w;
|
||||
}
|
||||
|
||||
@Override // from IVector4
|
||||
public DoubleBuffer get (DoubleBuffer buf) {
|
||||
return buf.put(x).put(y).put(z).put(w);
|
||||
}
|
||||
|
||||
@Override // from IVector4
|
||||
public boolean epsilonEquals (IVector4 other, double epsilon) {
|
||||
return (Math.abs(x - other.x()) < epsilon &&
|
||||
Math.abs(y - other.y()) < epsilon &&
|
||||
Math.abs(z - other.z()) < epsilon &&
|
||||
Math.abs(w - other.w()) < epsilon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString () {
|
||||
return "[" + x + ", " + y + ", " + z + ", " + w + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode () {
|
||||
return Platform.hashCode(x) ^ Platform.hashCode(y) ^ Platform.hashCode(z) ^
|
||||
Platform.hashCode(w);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals (Object other) {
|
||||
if (!(other instanceof Vector4)) {
|
||||
return false;
|
||||
}
|
||||
Vector4 ovec = (Vector4)other;
|
||||
return (x == ovec.x && y == ovec.y && z == ovec.z && w == ovec.w);
|
||||
}
|
||||
}
|
||||
@@ -1,346 +0,0 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.f;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import pythagoras.util.Platform;
|
||||
import pythagoras.util.SingularMatrixException;
|
||||
|
||||
/**
|
||||
* Provides most of the implementation of {@link IMatrix3}, obtaining only the components from the
|
||||
* derived class.
|
||||
*/
|
||||
public abstract class AbstractMatrix3 implements IMatrix3
|
||||
{
|
||||
@Override // from IVector3
|
||||
public Matrix3 transpose () {
|
||||
return transpose(new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 transpose (Matrix3 result) {
|
||||
return result.set(
|
||||
m00(), m01(), m02(),
|
||||
m10(), m11(), m12(),
|
||||
m20(), m21(), m22());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 mult (IMatrix3 other) {
|
||||
return mult(other, new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 mult (IMatrix3 other, Matrix3 result) {
|
||||
float m00 = m00(), m01 = m01(), m02 = m02();
|
||||
float m10 = m10(), m11 = m11(), m12 = m12();
|
||||
float m20 = m20(), m21 = m21(), m22 = m22();
|
||||
float om00 = other.m00(), om01 = other.m01(), om02 = other.m02();
|
||||
float om10 = other.m10(), om11 = other.m11(), om12 = other.m12();
|
||||
float om20 = other.m20(), om21 = other.m21(), om22 = other.m22();
|
||||
return result.set(
|
||||
m00*om00 + m10*om01 + m20*om02,
|
||||
m00*om10 + m10*om11 + m20*om12,
|
||||
m00*om20 + m10*om21 + m20*om22,
|
||||
|
||||
m01*om00 + m11*om01 + m21*om02,
|
||||
m01*om10 + m11*om11 + m21*om12,
|
||||
m01*om20 + m11*om21 + m21*om22,
|
||||
|
||||
m02*om00 + m12*om01 + m22*om02,
|
||||
m02*om10 + m12*om11 + m22*om12,
|
||||
m02*om20 + m12*om21 + m22*om22);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public boolean isAffine () {
|
||||
return (m02() == 0f && m12() == 0f && m22() == 1f);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 multAffine (IMatrix3 other) {
|
||||
return multAffine(other, new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 multAffine (IMatrix3 other, Matrix3 result) {
|
||||
float m00 = m00(), m01 = m01(), m02 = m02();
|
||||
float m10 = m10(), m11 = m11(), m12 = m12();
|
||||
float m20 = m20(), m21 = m21(), m22 = m22();
|
||||
float om00 = other.m00(), om01 = other.m01(), om02 = other.m02();
|
||||
float om10 = other.m10(), om11 = other.m11(), om12 = other.m12();
|
||||
float om20 = other.m20(), om21 = other.m21(), om22 = other.m22();
|
||||
return result.set(
|
||||
m00*om00 + m10*om01,
|
||||
m00*om10 + m10*om11,
|
||||
m00*om20 + m10*om21 + m20,
|
||||
|
||||
m01*om00 + m11*om01,
|
||||
m01*om10 + m11*om11,
|
||||
m01*om20 + m11*om21 + m21,
|
||||
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 invert () {
|
||||
return invert(new Matrix3());
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverts this matrix and places the result in the given object. This code is based on the
|
||||
* examples in the <a href="http://www.j3d.org/matrix_faq/matrfaq_latest.html">Matrix and
|
||||
* Quaternion FAQ</a>.
|
||||
*
|
||||
* @return a reference to the result matrix, for chaining.
|
||||
*/
|
||||
public Matrix3 invert (Matrix3 result) throws SingularMatrixException {
|
||||
float m00 = m00(), m01 = m01(), m02 = m02();
|
||||
float m10 = m10(), m11 = m11(), m12 = m12();
|
||||
float m20 = m20(), m21 = m21(), m22 = m22();
|
||||
// compute the determinant, storing the subdeterminants for later use
|
||||
float sd00 = m11*m22 - m21*m12;
|
||||
float sd10 = m01*m22 - m21*m02;
|
||||
float sd20 = m01*m12 - m11*m02;
|
||||
float det = m00*sd00 + m20*sd20 - m10*sd10;
|
||||
if (Math.abs(det) == 0f) {
|
||||
// determinant is zero; matrix is not invertible
|
||||
throw new SingularMatrixException(this.toString());
|
||||
}
|
||||
float rdet = 1f / det;
|
||||
return result.set(
|
||||
+sd00 * rdet,
|
||||
-(m10*m22 - m20*m12) * rdet,
|
||||
+(m10*m21 - m20*m11) * rdet,
|
||||
|
||||
-sd10 * rdet,
|
||||
+(m00*m22 - m20*m02) * rdet,
|
||||
-(m00*m21 - m20*m01) * rdet,
|
||||
|
||||
+sd20 * rdet,
|
||||
-(m00*m12 - m10*m02) * rdet,
|
||||
+(m00*m11 - m10*m01) * rdet);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 invertAffine () {
|
||||
return invertAffine(new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 invertAffine (Matrix3 result) throws SingularMatrixException {
|
||||
float m00 = m00(), m01 = m01(), m02 = m02();
|
||||
float m10 = m10(), m11 = m11(), m12 = m12();
|
||||
float m20 = m20(), m21 = m21(), m22 = m22();
|
||||
// compute the determinant, storing the subdeterminants for later use
|
||||
float det = m00*m11 - m10*m01;
|
||||
if (Math.abs(det) == 0f) {
|
||||
// determinant is zero; matrix is not invertible
|
||||
throw new SingularMatrixException(this.toString());
|
||||
}
|
||||
float rdet = 1f / det;
|
||||
return result.set(
|
||||
+m11 * rdet,
|
||||
-m10 * rdet,
|
||||
+(m10*m21 - m20*m11) * rdet,
|
||||
|
||||
-m01 * rdet,
|
||||
+m00 * rdet,
|
||||
-(m00*m21 - m20*m01) * rdet,
|
||||
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 lerp (IMatrix3 other, float t) {
|
||||
return lerp(other, t, new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 lerp (IMatrix3 other, float t, Matrix3 result) {
|
||||
float m00 = m00(), m01 = m01(), m02 = m02();
|
||||
float m10 = m10(), m11 = m11(), m12 = m12();
|
||||
float m20 = m20(), m21 = m21(), m22 = m22();
|
||||
float om00 = other.m00(), om01 = other.m01(), om02 = other.m02();
|
||||
float om10 = other.m10(), om11 = other.m11(), om12 = other.m12();
|
||||
float om20 = other.m20(), om21 = other.m21(), om22 = other.m22();
|
||||
return result.set(
|
||||
m00 + t*(om00 - m00),
|
||||
m10 + t*(om10 - m10),
|
||||
m20 + t*(om20 - m20),
|
||||
|
||||
m01 + t*(om01 - m01),
|
||||
m11 + t*(om11 - m11),
|
||||
m21 + t*(om21 - m21),
|
||||
|
||||
m02 + t*(om02 - m02),
|
||||
m12 + t*(om12 - m12),
|
||||
m22 + t*(om22 - m22));
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 lerpAffine (IMatrix3 other, float t) {
|
||||
return lerpAffine(other, t, new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Matrix3 lerpAffine (IMatrix3 other, float t, Matrix3 result) {
|
||||
float m00 = m00(), m01 = m01(), m02 = m02();
|
||||
float m10 = m10(), m11 = m11(), m12 = m12();
|
||||
float m20 = m20(), m21 = m21(), m22 = m22();
|
||||
float om00 = other.m00(), om01 = other.m01(), om02 = other.m02();
|
||||
float om10 = other.m10(), om11 = other.m11(), om12 = other.m12();
|
||||
float om20 = other.m20(), om21 = other.m21(), om22 = other.m22();
|
||||
return result.set(
|
||||
m00 + t*(om00 - m00),
|
||||
m10 + t*(om10 - m10),
|
||||
m20 + t*(om20 - m20),
|
||||
|
||||
m01 + t*(om01 - m01),
|
||||
m11 + t*(om11 - m11),
|
||||
m21 + t*(om21 - m21),
|
||||
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public FloatBuffer get (FloatBuffer buf) {
|
||||
buf.put(m00()).put(m01()).put(m02());
|
||||
buf.put(m10()).put(m11()).put(m12());
|
||||
buf.put(m20()).put(m21()).put(m22());
|
||||
return buf;
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector3 transformLocal (Vector3 vector) {
|
||||
return transform(vector, vector);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector3 transform (IVector3 vector) {
|
||||
return transform(vector, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector3 transform (IVector3 vector, Vector3 result) {
|
||||
float vx = vector.x(), vy = vector.y(), vz = vector.z();
|
||||
return result.set(
|
||||
m00()*vx + m10()*vy + m20()*vz,
|
||||
m01()*vx + m11()*vy + m21()*vz,
|
||||
m02()*vx + m12()*vy + m22()*vz);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector transformPointLocal (Vector point) {
|
||||
return transformPoint(point, point);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector transformPoint (IVector point) {
|
||||
return transformPoint(point, new Vector());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector transformPoint (IVector point, Vector result) {
|
||||
float px = point.x(), py = point.y();
|
||||
return result.set(m00()*px + m10()*py + m20(), m01()*px + m11()*py + m21());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector transformVectorLocal (Vector vector) {
|
||||
return transformVector(vector, vector);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector transformVector (IVector vector) {
|
||||
return transformVector(vector, new Vector());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector transformVector (IVector vector, Vector result) {
|
||||
float vx = vector.x(), vy = vector.y();
|
||||
return result.set(m00()*vx + m10()*vy, m01()*vx + m11()*vy);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public float extractRotation () {
|
||||
// start with the contents of the upper 2x2 portion of the matrix
|
||||
float n00 = m00(), n10 = m10();
|
||||
float n01 = m01(), n11 = m11();
|
||||
for (int ii = 0; ii < 10; ii++) {
|
||||
// store the results of the previous iteration
|
||||
float o00 = n00, o10 = n10;
|
||||
float o01 = n01, o11 = n11;
|
||||
|
||||
// compute average of the matrix with its inverse transpose
|
||||
float det = o00*o11 - o10*o01;
|
||||
if (Math.abs(det) == 0f) {
|
||||
// determinant is zero; matrix is not invertible
|
||||
throw new SingularMatrixException(this.toString());
|
||||
}
|
||||
float hrdet = 0.5f / det;
|
||||
n00 = +o11 * hrdet + o00*0.5f;
|
||||
n10 = -o01 * hrdet + o10*0.5f;
|
||||
|
||||
n01 = -o10 * hrdet + o01*0.5f;
|
||||
n11 = +o00 * hrdet + o11*0.5f;
|
||||
|
||||
// compute the difference; if it's small enough, we're done
|
||||
float d00 = n00 - o00, d10 = n10 - o10;
|
||||
float d01 = n01 - o01, d11 = n11 - o11;
|
||||
if (d00*d00 + d10*d10 + d01*d01 + d11*d11 < MathUtil.EPSILON) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// now that we have a nice orthogonal matrix, we can extract the rotation
|
||||
return FloatMath.atan2(n01, n00);
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector extractScale () {
|
||||
return extractScale(new Vector());
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public Vector extractScale (Vector result) {
|
||||
float m00 = m00(), m01 = m01(), m10 = m10(), m11 = m11();
|
||||
return result.set(
|
||||
FloatMath.sqrt(m00*m00 + m01*m01),
|
||||
FloatMath.sqrt(m10*m10 + m11*m11));
|
||||
}
|
||||
|
||||
@Override // from IVector3
|
||||
public float approximateUniformScale () {
|
||||
float cp = m00()*m11() - m01()*m10();
|
||||
return (cp < 0f) ? -FloatMath.sqrt(-cp) : FloatMath.sqrt(cp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString () {
|
||||
return "[[" + m00() + ", " + m10() + ", " + m20() + "], " +
|
||||
"[" + m01() + ", " + m11() + ", " + m21() + "], " +
|
||||
"[" + m02() + ", " + m12() + ", " + m22() + "]]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode () {
|
||||
return Platform.hashCode(m00()) ^ Platform.hashCode(m10()) ^ Platform.hashCode(m20()) ^
|
||||
Platform.hashCode(m01()) ^ Platform.hashCode(m11()) ^ Platform.hashCode(m21()) ^
|
||||
Platform.hashCode(m02()) ^ Platform.hashCode(m12()) ^ Platform.hashCode(m22());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals (Object other) {
|
||||
if (!(other instanceof AbstractMatrix3)) {
|
||||
return false;
|
||||
}
|
||||
AbstractMatrix3 omat = (AbstractMatrix3)other;
|
||||
return
|
||||
m00() == omat.m00() && m10() == omat.m10() && m20() == omat.m20() &&
|
||||
m01() == omat.m01() && m11() == omat.m11() && m21() == omat.m21() &&
|
||||
m02() == omat.m02() && m12() == omat.m12() && m22() == omat.m22();
|
||||
}
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.f;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import pythagoras.util.Platform;
|
||||
|
||||
/**
|
||||
* Provides most of the implementation of {@link IVector3}, obtaining only x, y and z from the
|
||||
* derived class.
|
||||
*/
|
||||
public abstract class AbstractVector3 implements IVector3
|
||||
{
|
||||
@Override // from interface IVector3
|
||||
public float dot (IVector3 other) {
|
||||
return x()*other.x() + y()*other.y() + z()*other.z();
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 cross (IVector3 other) {
|
||||
return cross(other, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 cross (IVector3 other, Vector3 result) {
|
||||
float x = x(), y = y(), z = z();
|
||||
float ox = other.x(), oy = other.y(), oz = other.z();
|
||||
return result.set(y*oz - z*oy, z*ox - x*oz, x*oy - y*ox);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public float triple (IVector3 b, IVector3 c) {
|
||||
float bx = b.x(), by = b.y(), bz = b.z();
|
||||
float cx = c.x(), cy = c.y(), cz = c.z();
|
||||
return x()*(by*cz - bz*cy) + y()*(bz*cx - bx*cz) + z()*(bx*cy - by*cx);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 negate () {
|
||||
return negate(new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 negate (Vector3 result) {
|
||||
return result.set(-x(), -y(), -z());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 normalize () {
|
||||
return normalize(new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 normalize (Vector3 result) {
|
||||
return mult(1f / length(), result);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public float angle (IVector3 other) {
|
||||
return FloatMath.acos(dot(other) / (length() * other.length()));
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public float length () {
|
||||
return FloatMath.sqrt(lengthSquared());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public float lengthSquared () {
|
||||
float x = x(), y = y(), z = z();
|
||||
return (x*x + y*y + z*z);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public float distance (IVector3 other) {
|
||||
return FloatMath.sqrt(distanceSquared(other));
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public float distanceSquared (IVector3 other) {
|
||||
float dx = x() - other.x(), dy = y() - other.y(), dz = z() - other.z();
|
||||
return dx*dx + dy*dy + dz*dz;
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public float manhattanDistance (IVector3 other) {
|
||||
return Math.abs(x() - other.x()) + Math.abs(y() - other.y()) + Math.abs(z() - other.z());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 mult (float v) {
|
||||
return mult(v, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 mult (float v, Vector3 result) {
|
||||
return result.set(x()*v, y()*v, z()*v);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 mult (IVector3 other) {
|
||||
return mult(other, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 mult (IVector3 other, Vector3 result) {
|
||||
return result.set(x()*other.x(), y()*other.y(), z()*other.z());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 add (IVector3 other) {
|
||||
return add(other, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 add (IVector3 other, Vector3 result) {
|
||||
return add(other.x(), other.y(), other.z(), result);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 subtract (IVector3 other) {
|
||||
return subtract(other, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 subtract (IVector3 other, Vector3 result) {
|
||||
return add(-other.x(), -other.y(), -other.z(), result);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 add (float x, float y, float z) {
|
||||
return add(x, y, z, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 add (float x, float y, float z, Vector3 result) {
|
||||
return result.set(x() + x, y() + y, z() + z);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 addScaled (IVector3 other, float v) {
|
||||
return addScaled(other, v, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 addScaled (IVector3 other, float v, Vector3 result) {
|
||||
return result.set(x() + other.x()*v, y() + other.y()*v, z() + other.z()*v);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 lerp (IVector3 other, float t) {
|
||||
return lerp(other, t, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 lerp (IVector3 other, float t, Vector3 result) {
|
||||
float x = x(), y = y(), z = z();
|
||||
return result.set(x + t*(other.x() - x), y + t*(other.y() - y), z + t*(other.z() - z));
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public float get (int idx) {
|
||||
switch (idx) {
|
||||
case 0: return x();
|
||||
case 1: return y();
|
||||
case 2: return z();
|
||||
}
|
||||
throw new IndexOutOfBoundsException(String.valueOf(idx));
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public void get (float[] values) {
|
||||
values[0] = x();
|
||||
values[1] = y();
|
||||
values[2] = z();
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public FloatBuffer get (FloatBuffer buf) {
|
||||
return buf.put(x()).put(y()).put(z());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString () {
|
||||
return "[" + x() + ", " + y() + ", " + z() + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode () {
|
||||
return Platform.hashCode(x()) ^ Platform.hashCode(y()) ^ Platform.hashCode(z());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals (Object other) {
|
||||
if (!(other instanceof AbstractVector3)) {
|
||||
return false;
|
||||
}
|
||||
AbstractVector3 ovec = (AbstractVector3)other;
|
||||
return (x() == ovec.x() && y() == ovec.y() && z() == ovec.z());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,535 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.f;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* An axis-aligned box.
|
||||
*/
|
||||
public class Box implements IBox, Serializable
|
||||
{
|
||||
/** The unit box. */
|
||||
public static final Box UNIT = new Box(Vector3.UNIT_XYZ.negate(), Vector3.UNIT_XYZ);
|
||||
|
||||
/** The zero box. */
|
||||
public static final Box ZERO = new Box(Vector3.ZERO, Vector3.ZERO);
|
||||
|
||||
/** The empty box. */
|
||||
public static final Box EMPTY = new Box(Vector3.MAX_VALUE, Vector3.MIN_VALUE);
|
||||
|
||||
/** A box that's as large as boxes can get. */
|
||||
public static final Box MAX_VALUE = new Box(Vector3.MIN_VALUE, Vector3.MAX_VALUE);
|
||||
|
||||
/**
|
||||
* Creates a box with the values contained in the supplied minimum and maximum extents.
|
||||
*/
|
||||
public Box (IVector3 minExtent, IVector3 maxExtent) {
|
||||
set(minExtent, maxExtent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*/
|
||||
public Box (IBox other) {
|
||||
set(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty box.
|
||||
*/
|
||||
public Box () {
|
||||
setToEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parameters of the box to the empty values ({@link Vector3f#MAX_VALUE} and
|
||||
* {@link Vector3f#MIN_VALUE} for the minimum and maximum, respectively).
|
||||
*
|
||||
* @return a reference to this box, for chaining.
|
||||
*/
|
||||
public Box setToEmpty () {
|
||||
return set(Vector3.MAX_VALUE, Vector3.MIN_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the parameters of another box.
|
||||
*
|
||||
* @return a reference to this box, for chaining.
|
||||
*/
|
||||
public Box set (IBox other) {
|
||||
return set(other.minimumExtent(), other.maximumExtent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the box parameters to the values contained in the supplied vectors.
|
||||
*
|
||||
* @return a reference to this box, for chaining.
|
||||
*/
|
||||
public Box set (IVector3 minExtent, IVector3 maxExtent) {
|
||||
_minExtent.set(minExtent);
|
||||
_maxExtent.set(maxExtent);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this box with the extents of an array of points.
|
||||
*
|
||||
* @return a reference to this box, for chaining.
|
||||
*/
|
||||
public Box fromPoints (IVector3... points) {
|
||||
setToEmpty();
|
||||
for (IVector3 point : points) {
|
||||
addLocal(point);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands this box in-place to include the specified point.
|
||||
*
|
||||
* @return a reference to this box, for chaining.
|
||||
*/
|
||||
public Box addLocal (IVector3 point) {
|
||||
return add(point, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands this box to include the bounds of another box.
|
||||
*
|
||||
* @return a reference to this box, for chaining.
|
||||
*/
|
||||
public Box addLocal (IBox other) {
|
||||
return add(other, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the intersection between this box and another box and places the result in this box.
|
||||
*
|
||||
* @return a reference to this box, for chaining.
|
||||
*/
|
||||
public Box intersectLocal (IBox other) {
|
||||
return intersect(other, this);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Transforms this box in-place.
|
||||
// *
|
||||
// * @return a reference to this box, for chaining.
|
||||
// */
|
||||
// public Box transformLocal (Transform3D transform) {
|
||||
// return transform(transform, this);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Projects this box in-place.
|
||||
*
|
||||
* @return a reference to this box, for chaining.
|
||||
*/
|
||||
public Box projectLocal (IMatrix4 matrix) {
|
||||
return project(matrix, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands the box in-place by the specified amounts.
|
||||
*
|
||||
* @return a reference to this box, for chaining.
|
||||
*/
|
||||
public Box expandLocal (float x, float y, float z) {
|
||||
return expand(x, y, z, this);
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public IVector3 minimumExtent () {
|
||||
return _minExtent;
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public IVector3 maximumExtent () {
|
||||
return _maxExtent;
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Vector3 center () {
|
||||
return center(new Vector3());
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Vector3 center (Vector3 result) {
|
||||
return _minExtent.add(_maxExtent, result).multLocal(0.5f);
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public float diagonalLength () {
|
||||
return _minExtent.distance(_maxExtent);
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public float longestEdge () {
|
||||
return Math.max(Math.max(_maxExtent.x - _minExtent.x, _maxExtent.y - _minExtent.y),
|
||||
_maxExtent.z - _minExtent.z);
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public boolean isEmpty () {
|
||||
return _minExtent.x > _maxExtent.x || _minExtent.y > _maxExtent.y ||
|
||||
_minExtent.z > _maxExtent.z;
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Box add (IVector3 point) {
|
||||
return add(point, new Box());
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Box add (IVector3 point, Box result) {
|
||||
result._minExtent.set(
|
||||
Math.min(_minExtent.x, point.x()),
|
||||
Math.min(_minExtent.y, point.y()),
|
||||
Math.min(_minExtent.z, point.z()));
|
||||
result._maxExtent.set(
|
||||
Math.max(_maxExtent.x, point.x()),
|
||||
Math.max(_maxExtent.y, point.y()),
|
||||
Math.max(_maxExtent.z, point.z()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Box add (IBox other) {
|
||||
return add(other, new Box());
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Box add (IBox other, Box result) {
|
||||
IVector3 omin = other.minimumExtent(), omax = other.maximumExtent();
|
||||
result._minExtent.set(
|
||||
Math.min(_minExtent.x, omin.x()),
|
||||
Math.min(_minExtent.y, omin.y()),
|
||||
Math.min(_minExtent.z, omin.z()));
|
||||
result._maxExtent.set(
|
||||
Math.max(_maxExtent.x, omax.x()),
|
||||
Math.max(_maxExtent.y, omax.y()),
|
||||
Math.max(_maxExtent.z, omax.z()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Box intersect (IBox other) {
|
||||
return intersect(other, new Box());
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Box intersect (IBox other, Box result) {
|
||||
IVector3 omin = other.minimumExtent(), omax = other.maximumExtent();
|
||||
result._minExtent.set(
|
||||
Math.max(_minExtent.x, omin.x()),
|
||||
Math.max(_minExtent.y, omin.y()),
|
||||
Math.max(_minExtent.z, omin.z()));
|
||||
result._maxExtent.set(
|
||||
Math.min(_maxExtent.x, omax.x()),
|
||||
Math.min(_maxExtent.y, omax.y()),
|
||||
Math.min(_maxExtent.z, omax.z()));
|
||||
return result;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Transforms this box.
|
||||
// *
|
||||
// * @return a new box containing the result.
|
||||
// */
|
||||
// public Box transform (Transform3D transform) {
|
||||
// return transform(transform, new Box());
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Transforms this box, placing the result in the provided object.
|
||||
// *
|
||||
// * @return a reference to the result box, for chaining.
|
||||
// */
|
||||
// public Box transform (Transform3D transform, Box result) {
|
||||
// // the corners of the box cover the eight permutations of ([minX|maxX], [minY|maxY],
|
||||
// // [minZ|maxZ]). to find the new minimum and maximum for each element, we transform
|
||||
// // selecting either the minimum or maximum for each component based on whether it will
|
||||
// // increase or decrease the total (which depends on the sign of the matrix element).
|
||||
// transform.update(Transform3D.AFFINE);
|
||||
// Matrix4f matrix = transform.matrix();
|
||||
// float minx =
|
||||
// matrix.m00 * (matrix.m00 > 0f ? _minExtent.x : _maxExtent.x) +
|
||||
// matrix.m10 * (matrix.m10 > 0f ? _minExtent.y : _maxExtent.y) +
|
||||
// matrix.m20 * (matrix.m20 > 0f ? _minExtent.z : _maxExtent.z) + matrix.m30;
|
||||
// float miny =
|
||||
// matrix.m01 * (matrix.m01 > 0f ? _minExtent.x : _maxExtent.x) +
|
||||
// matrix.m11 * (matrix.m11 > 0f ? _minExtent.y : _maxExtent.y) +
|
||||
// matrix.m21 * (matrix.m21 > 0f ? _minExtent.z : _maxExtent.z) + matrix.m31;
|
||||
// float minz =
|
||||
// matrix.m02 * (matrix.m02 > 0f ? _minExtent.x : _maxExtent.x) +
|
||||
// matrix.m12 * (matrix.m12 > 0f ? _minExtent.y : _maxExtent.y) +
|
||||
// matrix.m22 * (matrix.m22 > 0f ? _minExtent.z : _maxExtent.z) + matrix.m32;
|
||||
// float maxx =
|
||||
// matrix.m00 * (matrix.m00 < 0f ? _minExtent.x : _maxExtent.x) +
|
||||
// matrix.m10 * (matrix.m10 < 0f ? _minExtent.y : _maxExtent.y) +
|
||||
// matrix.m20 * (matrix.m20 < 0f ? _minExtent.z : _maxExtent.z) + matrix.m30;
|
||||
// float maxy =
|
||||
// matrix.m01 * (matrix.m01 < 0f ? _minExtent.x : _maxExtent.x) +
|
||||
// matrix.m11 * (matrix.m11 < 0f ? _minExtent.y : _maxExtent.y) +
|
||||
// matrix.m21 * (matrix.m21 < 0f ? _minExtent.z : _maxExtent.z) + matrix.m31;
|
||||
// float maxz =
|
||||
// matrix.m02 * (matrix.m02 < 0f ? _minExtent.x : _maxExtent.x) +
|
||||
// matrix.m12 * (matrix.m12 < 0f ? _minExtent.y : _maxExtent.y) +
|
||||
// matrix.m22 * (matrix.m22 < 0f ? _minExtent.z : _maxExtent.z) + matrix.m32;
|
||||
// result._minExtent.set(minx, miny, minz);
|
||||
// result._maxExtent.set(maxx, maxy, maxz);
|
||||
// return result;
|
||||
// }
|
||||
|
||||
@Override // from IBox
|
||||
public Box project (IMatrix4 matrix) {
|
||||
return project(matrix, new Box());
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Box project (IMatrix4 matrix, Box result) {
|
||||
float minx = +Float.MAX_VALUE, miny = +Float.MAX_VALUE, minz = +Float.MAX_VALUE;
|
||||
float maxx = -Float.MAX_VALUE, maxy = -Float.MAX_VALUE, maxz = -Float.MAX_VALUE;
|
||||
for (int ii = 0; ii < 8; ii++) {
|
||||
float x = ((ii & (1 << 2)) == 0) ? _minExtent.x : _maxExtent.x;
|
||||
float y = ((ii & (1 << 1)) == 0) ? _minExtent.y : _maxExtent.y;
|
||||
float z = ((ii & (1 << 0)) == 0) ? _minExtent.z : _maxExtent.z;
|
||||
float rw = 1f / (matrix.m03()*x + matrix.m13()*y + matrix.m23()*z + matrix.m33());
|
||||
float px = (matrix.m00()*x + matrix.m10()*y + matrix.m20()*z + matrix.m30()) * rw;
|
||||
float py = (matrix.m01()*x + matrix.m11()*y + matrix.m21()*z + matrix.m31()) * rw;
|
||||
float pz = (matrix.m02()*x + matrix.m12()*y + matrix.m22()*z + matrix.m32()) * rw;
|
||||
minx = Math.min(minx, px);
|
||||
miny = Math.min(miny, py);
|
||||
minz = Math.min(minz, pz);
|
||||
maxx = Math.max(maxx, px);
|
||||
maxy = Math.max(maxy, py);
|
||||
maxz = Math.max(maxz, pz);
|
||||
}
|
||||
result._minExtent.set(minx, miny, minz);
|
||||
result._maxExtent.set(maxx, maxy, maxz);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Box expand (float x, float y, float z) {
|
||||
return expand(x, y, z, new Box());
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Box expand (float x, float y, float z, Box result) {
|
||||
result._minExtent.set(_minExtent.x - x, _minExtent.y - y, _minExtent.z - z);
|
||||
result._maxExtent.set(_maxExtent.x + x, _maxExtent.y + y, _maxExtent.z + z);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public Vector3 vertex (int code, Vector3 result) {
|
||||
return result.set(((code & (1 << 2)) == 0) ? _minExtent.x : _maxExtent.x,
|
||||
((code & (1 << 1)) == 0) ? _minExtent.y : _maxExtent.y,
|
||||
((code & (1 << 0)) == 0) ? _minExtent.z : _maxExtent.z);
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public boolean contains (IVector3 point) {
|
||||
return contains(point.x(), point.y(), point.z());
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public boolean contains (float x, float y, float z) {
|
||||
return (x >= _minExtent.x && x <= _maxExtent.x &&
|
||||
y >= _minExtent.y && y <= _maxExtent.y &&
|
||||
z >= _minExtent.z && z <= _maxExtent.z);
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public float extentDistance (IBox other) {
|
||||
return other.minimumExtent().manhattanDistance(_minExtent) +
|
||||
other.maximumExtent().manhattanDistance(_maxExtent);
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public boolean contains (IBox other) {
|
||||
IVector3 omin = other.minimumExtent(), omax = other.maximumExtent();
|
||||
return omin.x() >= _minExtent.x && omax.x() <= _maxExtent.x &&
|
||||
omin.y() >= _minExtent.y && omax.y() <= _maxExtent.y &&
|
||||
omin.z() >= _minExtent.z && omax.z() <= _maxExtent.z;
|
||||
}
|
||||
|
||||
@Override // from IBox
|
||||
public boolean intersects (IBox other) {
|
||||
IVector3 omin = other.minimumExtent(), omax = other.maximumExtent();
|
||||
return _maxExtent.x >= omin.x() && _minExtent.x <= omax.x() &&
|
||||
_maxExtent.y >= omin.y() && _minExtent.y <= omax.y() &&
|
||||
_maxExtent.z >= omin.z() && _minExtent.z <= omax.z();
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Determines whether the specified ray intersects this box.
|
||||
// */
|
||||
// public boolean intersects (Ray3D ray) {
|
||||
// Vector3 dir = ray.direction();
|
||||
// return
|
||||
// Math.abs(dir.x) > MathUtil.EPSILON &&
|
||||
// (intersectsX(ray, _minExtent.x) || intersectsX(ray, _maxExtent.x)) ||
|
||||
// Math.abs(dir.y) > MathUtil.EPSILON &&
|
||||
// (intersectsY(ray, _minExtent.y) || intersectsY(ray, _maxExtent.y)) ||
|
||||
// Math.abs(dir.z) > MathUtil.EPSILON &&
|
||||
// (intersectsZ(ray, _minExtent.z) || intersectsZ(ray, _maxExtent.z));
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Finds the location of the (first) intersection between the specified ray and this box.
|
||||
// * This will be the ray origin if the ray starts inside the box.
|
||||
// *
|
||||
// * @param result a vector to hold the location of the intersection.
|
||||
// * @return true if the ray intersects the box (in which case the result vector will be
|
||||
// * populated with the location of the intersection), false if not.
|
||||
// */
|
||||
// public boolean intersection (Ray3D ray, Vector3 result) {
|
||||
// Vector3 origin = ray.origin();
|
||||
// if (contains(origin)) {
|
||||
// result.set(origin);
|
||||
// return true;
|
||||
// }
|
||||
// Vector3 dir = ray.direction();
|
||||
// float t = Float.MAX_VALUE;
|
||||
// if (Math.abs(dir.x) > MathUtil.EPSILON) {
|
||||
// t = Math.min(t, intersectionX(ray, _minExtent.x));
|
||||
// t = Math.min(t, intersectionX(ray, _maxExtent.x));
|
||||
// }
|
||||
// if (Math.abs(dir.y) > MathUtil.EPSILON) {
|
||||
// t = Math.min(t, intersectionY(ray, _minExtent.y));
|
||||
// t = Math.min(t, intersectionY(ray, _maxExtent.y));
|
||||
// }
|
||||
// if (Math.abs(dir.z) > MathUtil.EPSILON) {
|
||||
// t = Math.min(t, intersectionZ(ray, _minExtent.z));
|
||||
// t = Math.min(t, intersectionZ(ray, _maxExtent.z));
|
||||
// }
|
||||
// if (t == Float.MAX_VALUE) {
|
||||
// return false;
|
||||
// }
|
||||
// origin.addScaled(dir, t, result);
|
||||
// return true;
|
||||
// }
|
||||
|
||||
@Override // documentation inherited
|
||||
public String toString () {
|
||||
return "[min=" + _minExtent + ", max=" + _maxExtent + "]";
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public int hashCode () {
|
||||
return _minExtent.hashCode() + 31*_maxExtent.hashCode();
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public boolean equals (Object other) {
|
||||
if (!(other instanceof Box)) {
|
||||
return false;
|
||||
}
|
||||
Box obox = (Box)other;
|
||||
return _minExtent.equals(obox._minExtent) && _maxExtent.equals(obox._maxExtent);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Helper method for {@link #intersects(Ray3D)}. Determines whether the ray intersects the box
|
||||
// * at the plane where x equals the value specified.
|
||||
// */
|
||||
// protected boolean intersectsX (Ray3D ray, float x) {
|
||||
// Vector3 origin = ray.origin(), dir = ray.direction();
|
||||
// float t = (x - origin.x) / dir.x;
|
||||
// if (t < 0f) {
|
||||
// return false;
|
||||
// }
|
||||
// float iy = origin.y + t*dir.y, iz = origin.z + t*dir.z;
|
||||
// return iy >= _minExtent.y && iy <= _maxExtent.y &&
|
||||
// iz >= _minExtent.z && iz <= _maxExtent.z;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Helper method for {@link #intersects(Ray3D)}. Determines whether the ray intersects the box
|
||||
// * at the plane where y equals the value specified.
|
||||
// */
|
||||
// protected boolean intersectsY (Ray3D ray, float y) {
|
||||
// Vector3 origin = ray.origin(), dir = ray.direction();
|
||||
// float t = (y - origin.y) / dir.y;
|
||||
// if (t < 0f) {
|
||||
// return false;
|
||||
// }
|
||||
// float ix = origin.x + t*dir.x, iz = origin.z + t*dir.z;
|
||||
// return ix >= _minExtent.x && ix <= _maxExtent.x &&
|
||||
// iz >= _minExtent.z && iz <= _maxExtent.z;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Helper method for {@link #intersects(Ray3D)}. Determines whether the ray intersects the box
|
||||
// * at the plane where z equals the value specified.
|
||||
// */
|
||||
// protected boolean intersectsZ (Ray3D ray, float z) {
|
||||
// Vector3 origin = ray.origin(), dir = ray.direction();
|
||||
// float t = (z - origin.z) / dir.z;
|
||||
// if (t < 0f) {
|
||||
// return false;
|
||||
// }
|
||||
// float ix = origin.x + t*dir.x, iy = origin.y + t*dir.y;
|
||||
// return ix >= _minExtent.x && ix <= _maxExtent.x &&
|
||||
// iy >= _minExtent.y && iy <= _maxExtent.y;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Helper method for {@link #intersection}. Finds the <code>t</code> value where the ray
|
||||
// * intersects the box at the plane where x equals the value specified, or returns
|
||||
// * {@link Float#MAX_VALUE} if there is no such intersection.
|
||||
// */
|
||||
// protected float intersectionX (Ray3D ray, float x) {
|
||||
// Vector3 origin = ray.origin(), dir = ray.direction();
|
||||
// float t = (x - origin.x) / dir.x;
|
||||
// if (t < 0f) {
|
||||
// return Float.MAX_VALUE;
|
||||
// }
|
||||
// float iy = origin.y + t*dir.y, iz = origin.z + t*dir.z;
|
||||
// return (iy >= _minExtent.y && iy <= _maxExtent.y &&
|
||||
// iz >= _minExtent.z && iz <= _maxExtent.z) ? t : Float.MAX_VALUE;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Helper method for {@link #intersection}. Finds the <code>t</code> value where the ray
|
||||
// * intersects the box at the plane where y equals the value specified, or returns
|
||||
// * {@link Float#MAX_VALUE} if there is no such intersection.
|
||||
// */
|
||||
// protected float intersectionY (Ray3D ray, float y) {
|
||||
// Vector3 origin = ray.origin(), dir = ray.direction();
|
||||
// float t = (y - origin.y) / dir.y;
|
||||
// if (t < 0f) {
|
||||
// return Float.MAX_VALUE;
|
||||
// }
|
||||
// float ix = origin.x + t*dir.x, iz = origin.z + t*dir.z;
|
||||
// return (ix >= _minExtent.x && ix <= _maxExtent.x &&
|
||||
// iz >= _minExtent.z && iz <= _maxExtent.z) ? t : Float.MAX_VALUE;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Helper method for {@link #intersection}. Finds the <code>t</code> value where the ray
|
||||
// * intersects the box at the plane where z equals the value specified, or returns
|
||||
// * {@link Float#MAX_VALUE} if there is no such intersection.
|
||||
// */
|
||||
// protected float intersectionZ (Ray3D ray, float z) {
|
||||
// Vector3 origin = ray.origin(), dir = ray.direction();
|
||||
// float t = (z - origin.z) / dir.z;
|
||||
// if (t < 0f) {
|
||||
// return Float.MAX_VALUE;
|
||||
// }
|
||||
// float ix = origin.x + t*dir.x, iy = origin.y + t*dir.y;
|
||||
// return (ix >= _minExtent.x && ix <= _maxExtent.x &&
|
||||
// iy >= _minExtent.y && iy <= _maxExtent.y) ? t : Float.MAX_VALUE;
|
||||
// }
|
||||
|
||||
/** The box's minimum extent. */
|
||||
protected final Vector3 _minExtent = new Vector3();
|
||||
|
||||
/** The box's maximum extent. */
|
||||
protected final Vector3 _maxExtent = new Vector3();
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.f;
|
||||
|
||||
/**
|
||||
* A pyramidal frustum.
|
||||
*/
|
||||
public class Frustum
|
||||
{
|
||||
/** Intersection types indicating that the frustum does not intersect, intersects, or fully
|
||||
* contains, respectively, the parameter. */
|
||||
public enum IntersectionType { NONE, INTERSECTS, CONTAINS };
|
||||
|
||||
/**
|
||||
* Creates an empty (invalid) frustum.
|
||||
*/
|
||||
public Frustum () {
|
||||
// initialize the vertices and planes of the frustum
|
||||
for (int ii = 0; ii < 8; ii++) {
|
||||
_vertices[ii] = new Vector3();
|
||||
}
|
||||
for (int ii = 0; ii < 6; ii++) {
|
||||
_planes[ii] = new Plane();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the frustum's array of vertices.
|
||||
*/
|
||||
public IVector3[] vertices () {
|
||||
return _vertices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the bounds of this frustum.
|
||||
*/
|
||||
public Box bounds () {
|
||||
return _bounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this frustum to one pointing in the Z- direction with the specified parameters
|
||||
* determining its size and shape (see the OpenGL documentation for
|
||||
* <code>gluPerspective</code>).
|
||||
*
|
||||
* @param fovy the vertical field of view, in radians.
|
||||
* @param aspect the aspect ratio (width over height).
|
||||
* @param znear the distance to the near clip plane.
|
||||
* @param zfar the distance to the far clip plane.
|
||||
* @return a reference to this frustum, for chaining.
|
||||
*/
|
||||
public Frustum setToPerspective (float fovy, float aspect, float znear, float zfar) {
|
||||
float top = znear * FloatMath.tan(fovy / 2f), bottom = -top;
|
||||
float right = top * aspect, left = -right;
|
||||
return setToFrustum(left, right, bottom, top, znear, zfar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this frustum to one pointing in the Z- direction with the specified parameters
|
||||
* determining its size and shape (see the OpenGL documentation for <code>glFrustum</code>).
|
||||
*
|
||||
* @return a reference to this frustum, for chaining.
|
||||
*/
|
||||
public Frustum setToFrustum (
|
||||
float left, float right, float bottom, float top, float near, float far) {
|
||||
return setToProjection(left, right, bottom, top, near, far, Vector3.UNIT_Z, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this frustum to an orthographic one pointing in the Z- direction with the specified
|
||||
* parameters determining its size (see the OpenGL documentation for <code>glOrtho</code>).
|
||||
*
|
||||
* @return a reference to this frustum, for chaining.
|
||||
*/
|
||||
public Frustum setToOrtho (
|
||||
float left, float right, float bottom, float top, float near, float far) {
|
||||
return setToProjection(left, right, bottom, top, near, far, Vector3.UNIT_Z, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this frustum to a perspective or orthographic projection with the specified parameters
|
||||
* determining its size and shape.
|
||||
*
|
||||
* @return a reference to this frustum, for chaining.
|
||||
*/
|
||||
public Frustum setToProjection (
|
||||
float left, float right, float bottom, float top, float near,
|
||||
float far, IVector3 nearFarNormal, boolean ortho, boolean mirrored) {
|
||||
float nfnx = nearFarNormal.x(), nfny = nearFarNormal.y(), nfnz = nearFarNormal.z();
|
||||
if (ortho) {
|
||||
float nrz = -1f / nfnz;
|
||||
float xl = nfnx*left*nrz, xr = nfnx*right*nrz;
|
||||
float yb = nfny*bottom*nrz, yt = nfny*top*nrz;
|
||||
_vertices[0].set(left, bottom, xl + yb - near);
|
||||
_vertices[mirrored ? 3 : 1].set(right, bottom, xr + yb - near);
|
||||
_vertices[2].set(right, top, xr + yt - near);
|
||||
_vertices[mirrored ? 1 : 3].set(left, top, xl + yt - near);
|
||||
_vertices[4].set(left, bottom, xl + yb - far);
|
||||
_vertices[mirrored ? 7 : 5].set(right, bottom, xr + yb - far);
|
||||
_vertices[6].set(right, top, xr + yt - far);
|
||||
_vertices[mirrored ? 5 : 7].set(left, top, xl + yt - far);
|
||||
|
||||
} else {
|
||||
float rn = 1f / near;
|
||||
float lrn = left * rn, rrn = right * rn;
|
||||
float brn = bottom * rn, trn = top * rn;
|
||||
|
||||
float nz = near * nfnz;
|
||||
float z0 = nz / (nfnx*lrn + nfny*brn - nfnz);
|
||||
_vertices[0].set(-z0*lrn, -z0*brn, z0);
|
||||
float z1 = nz / (nfnx*rrn + nfny*brn - nfnz);
|
||||
_vertices[mirrored ? 3 : 1].set(-z1*rrn, -z1*brn, z1);
|
||||
float z2 = nz / (nfnx*rrn + nfny*trn - nfnz);
|
||||
_vertices[2].set(-z2*rrn, -z2*trn, z2);
|
||||
float z3 = nz / (nfnx*lrn + nfny*trn - nfnz);
|
||||
_vertices[mirrored ? 1 : 3].set(-z3*lrn, -z3*trn, z3);
|
||||
|
||||
float fz = far * nfnz;
|
||||
float z4 = fz / (nfnx*lrn + nfny*brn - nfnz);
|
||||
_vertices[4].set(-z4*lrn, -z4*brn, z4);
|
||||
float z5 = fz / (nfnx*rrn + nfny*brn - nfnz);
|
||||
_vertices[mirrored ? 7 : 5].set(-z5*rrn, -z5*brn, z5);
|
||||
float z6 = fz / (nfnx*rrn + nfny*trn - nfnz);
|
||||
_vertices[6].set(-z6*rrn, -z6*trn, z6);
|
||||
float z7 = fz / (nfnx*lrn + nfny*trn - nfnz);
|
||||
_vertices[mirrored ? 5 : 7].set(-z7*lrn, -z7*trn, z7);
|
||||
}
|
||||
|
||||
updateDerivedState();
|
||||
return this;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Transforms this frustum in-place by the specified transformation.
|
||||
// *
|
||||
// * @return a reference to this frustum, for chaining.
|
||||
// */
|
||||
// public Frustum transformLocal (Transform3D transform)
|
||||
// {
|
||||
// return transform(transform, this);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Transforms this frustum by the specified transformation.
|
||||
// *
|
||||
// * @return a new frustum containing the result.
|
||||
// */
|
||||
// public Frustum transform (Transform3D transform)
|
||||
// {
|
||||
// return transform(transform, new Frustum());
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Transforms this frustum by the specified transformation, placing the result in the object
|
||||
// * provided.
|
||||
// *
|
||||
// * @return a reference to the result frustum, for chaining.
|
||||
// */
|
||||
// public Frustum transform (Transform3D transform, Frustum result)
|
||||
// {
|
||||
// // transform all of the vertices
|
||||
// for (int ii = 0; ii < 8; ii++) {
|
||||
// transform.transformPoint(_vertices[ii], result._vertices[ii]);
|
||||
// }
|
||||
// result.updateDerivedState();
|
||||
// return result;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Determines the maximum signed distance of the point from the planes of the frustum. If
|
||||
* the distance is less than or equal to zero, the point lies inside the frustum.
|
||||
*/
|
||||
public float distance (Vector3 point) {
|
||||
float distance = -Float.MAX_VALUE;
|
||||
for (Plane plane : _planes) {
|
||||
distance = Math.max(distance, plane.distance(point));
|
||||
}
|
||||
return distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the frustum intersects the specified box.
|
||||
*/
|
||||
public IntersectionType intersectionType (Box box) {
|
||||
// exit quickly in cases where the bounding boxes don't overlap (equivalent to a separating
|
||||
// axis test using the axes of the box)
|
||||
if (!_bounds.intersects(box)) {
|
||||
return IntersectionType.NONE;
|
||||
}
|
||||
|
||||
// consider each side of the frustum as a potential separating axis
|
||||
int ccount = 0;
|
||||
for (int ii = 0; ii < 6; ii++) {
|
||||
// determine how many vertices fall inside/outside the plane
|
||||
int inside = 0;
|
||||
Plane plane = _planes[ii];
|
||||
for (int jj = 0; jj < 8; jj++) {
|
||||
if (plane.distance(box.vertex(jj, _vertex)) <= 0f) {
|
||||
inside++;
|
||||
}
|
||||
}
|
||||
if (inside == 0) {
|
||||
return IntersectionType.NONE;
|
||||
} else if (inside == 8) {
|
||||
ccount++;
|
||||
}
|
||||
}
|
||||
return (ccount == 6) ? IntersectionType.CONTAINS : IntersectionType.INTERSECTS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the bounds of the frustum under the supplied rotation and places the results in
|
||||
* the box provided.
|
||||
*
|
||||
* @return a reference to the result box, for chaining.
|
||||
*/
|
||||
public Box boundsUnderRotation (Matrix3 matrix, Box result) {
|
||||
result.setToEmpty();
|
||||
for (Vector3 vertex : _vertices) {
|
||||
result.addLocal(matrix.transform(vertex, _vertex));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the planes and bounding box of the frustum based on its vertices.
|
||||
*/
|
||||
protected void updateDerivedState () {
|
||||
_planes[0].fromPoints(_vertices[0], _vertices[1], _vertices[2]); // near
|
||||
_planes[1].fromPoints(_vertices[5], _vertices[4], _vertices[7]); // far
|
||||
_planes[2].fromPoints(_vertices[1], _vertices[5], _vertices[6]); // left
|
||||
_planes[3].fromPoints(_vertices[4], _vertices[0], _vertices[3]); // right
|
||||
_planes[4].fromPoints(_vertices[3], _vertices[2], _vertices[6]); // top
|
||||
_planes[5].fromPoints(_vertices[4], _vertices[5], _vertices[1]); // bottom
|
||||
_bounds.fromPoints(_vertices);
|
||||
}
|
||||
|
||||
/** The vertices of the frustum. */
|
||||
protected Vector3[] _vertices = new Vector3[8];
|
||||
|
||||
/** The planes of the frustum (as derived from the vertices). The plane normals point out of
|
||||
* the frustum. */
|
||||
protected Plane[] _planes = new Plane[6];
|
||||
|
||||
/** The frustum's bounding box (as derived from the vertices). */
|
||||
protected Box _bounds = new Box();
|
||||
|
||||
/** A working vertex. */
|
||||
protected static Vector3 _vertex = new Vector3();
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.f;
|
||||
|
||||
/**
|
||||
* Does something extraordinary.
|
||||
*/
|
||||
public interface IBox
|
||||
{
|
||||
/**
|
||||
* Returns a reference to the box's minimum extent.
|
||||
*/
|
||||
IVector3 minimumExtent ();
|
||||
|
||||
/**
|
||||
* Returns a reference to the box's maximum extent.
|
||||
*/
|
||||
IVector3 maximumExtent ();
|
||||
|
||||
/**
|
||||
* Returns the center of the box as a new vector.
|
||||
*/
|
||||
Vector3 center ();
|
||||
|
||||
/**
|
||||
* Places the location of the center of the box into the given result vector.
|
||||
*
|
||||
* @return a reference to the result vector, for chaining.
|
||||
*/
|
||||
Vector3 center (Vector3 result);
|
||||
|
||||
/**
|
||||
* Returns the length of the box's diagonal (the distance from minimum to maximum extent).
|
||||
*/
|
||||
float diagonalLength ();
|
||||
|
||||
/**
|
||||
* Returns the length of the box's longest edge.
|
||||
*/
|
||||
float longestEdge ();
|
||||
|
||||
/**
|
||||
* Determines whether the box is empty (whether any of its minima are greater than their
|
||||
* corresponding maxima).
|
||||
*/
|
||||
boolean isEmpty ();
|
||||
|
||||
/**
|
||||
* Retrieves one of the eight vertices of the box. The code parameter identifies the vertex
|
||||
* with flags indicating which values should be selected from the minimum extent, and which
|
||||
* from the maximum extent. For example, the code 011b selects the vertex with the minimum x,
|
||||
* maximum y, and maximum z.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Vector3 vertex (int code, Vector3 result);
|
||||
|
||||
/**
|
||||
* Determines whether this box contains the specified point.
|
||||
*/
|
||||
boolean contains (IVector3 point);
|
||||
|
||||
/**
|
||||
* Determines whether this box contains the specified point.
|
||||
*/
|
||||
boolean contains (float x, float y, float z);
|
||||
|
||||
/**
|
||||
* Returns the sum of the Manhattan distances between the extents of this box and the
|
||||
* specified other box.
|
||||
*/
|
||||
float extentDistance (IBox other);
|
||||
|
||||
/**
|
||||
* Determines whether this box completely contains the specified box.
|
||||
*/
|
||||
boolean contains (IBox other);
|
||||
|
||||
/**
|
||||
* Determines whether this box intersects the specified other box.
|
||||
*/
|
||||
boolean intersects (IBox other);
|
||||
|
||||
/**
|
||||
* Expands this box to include the specified point.
|
||||
*
|
||||
* @return a new box containing the result.
|
||||
*/
|
||||
Box add (IVector3 point);
|
||||
|
||||
/**
|
||||
* Expands this box to include the specified point, placing the result in the object
|
||||
* provided.
|
||||
*
|
||||
* @return a reference to the result box, for chaining.
|
||||
*/
|
||||
Box add (IVector3 point, Box result);
|
||||
|
||||
/**
|
||||
* Expands this box to include the bounds of another box.
|
||||
*
|
||||
* @return a new box containing the result.
|
||||
*/
|
||||
Box add (IBox other);
|
||||
|
||||
/**
|
||||
* Expands this box to include the bounds of another box, placing the result in the object
|
||||
* provided.
|
||||
*
|
||||
* @return a reference to the result box, for chaining.
|
||||
*/
|
||||
Box add (IBox other, Box result);
|
||||
|
||||
/**
|
||||
* Finds the intersection between this box and another box.
|
||||
*
|
||||
* @return a new box containing the result.
|
||||
*/
|
||||
Box intersect (IBox other);
|
||||
|
||||
/**
|
||||
* Finds the intersection between this box and another box and places the result in the
|
||||
* provided object.
|
||||
*
|
||||
* @return a reference to this box, for chaining.
|
||||
*/
|
||||
Box intersect (IBox other, Box result);
|
||||
|
||||
/**
|
||||
* Projects this box.
|
||||
*
|
||||
* @return a new box containing the result.
|
||||
*/
|
||||
Box project (IMatrix4 matrix);
|
||||
|
||||
/**
|
||||
* Projects this box, placing the result in the object provided.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Box project (IMatrix4 matrix, Box result);
|
||||
|
||||
/**
|
||||
* Expands the box by the specified amounts.
|
||||
*
|
||||
* @return a new box containing the result.
|
||||
*/
|
||||
Box expand (float x, float y, float z);
|
||||
|
||||
/**
|
||||
* Expands the box by the specified amounts, placing the result in the object provided.
|
||||
*
|
||||
* @return a reference to the result box, for chaining.
|
||||
*/
|
||||
Box expand (float x, float y, float z, Box result);
|
||||
|
||||
// /**
|
||||
// * Determines whether the specified ray intersects this box.
|
||||
// */
|
||||
// boolean intersects (Ray3D ray);
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.f;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
* Provides read-only access to a {@link Matrix4}.
|
||||
*/
|
||||
public interface IMatrix4
|
||||
{
|
||||
/** Returns the (0,0)th component of the matrix. */
|
||||
float m00 ();
|
||||
|
||||
/** Returns the (1,0)th component of the matrix. */
|
||||
float m10 ();
|
||||
|
||||
/** Returns the (2,0)th component of the matrix. */
|
||||
float m20 ();
|
||||
|
||||
/** Returns the (3,0)th component of the matrix. */
|
||||
float m30 ();
|
||||
|
||||
/** Returns the (0,1)th component of the matrix. */
|
||||
float m01 ();
|
||||
|
||||
/** Returns the (1,1)th component of the matrix. */
|
||||
float m11 ();
|
||||
|
||||
/** Returns the (2,1)th component of the matrix. */
|
||||
float m21 ();
|
||||
|
||||
/** Returns the (3,1)th component of the matrix. */
|
||||
float m31 ();
|
||||
|
||||
/** Returns the (0,2)th component of the matrix. */
|
||||
float m02 ();
|
||||
|
||||
/** Returns the (1,2)th component of the matrix. */
|
||||
float m12 ();
|
||||
|
||||
/** Returns the (2,2)th component of the matrix. */
|
||||
float m22 ();
|
||||
|
||||
/** Returns the (3,2)th component of the matrix. */
|
||||
float m32 ();
|
||||
|
||||
/** Returns the (0,3)th component of the matrix. */
|
||||
float m03 ();
|
||||
|
||||
/** Returns the (1,3)th component of the matrix. */
|
||||
float m13 ();
|
||||
|
||||
/** Returns the (2,3)th component of the matrix. */
|
||||
float m23 ();
|
||||
|
||||
/** Returns the (3,3)th component of the matrix. */
|
||||
float m33 ();
|
||||
|
||||
/**
|
||||
* Transposes this matrix.
|
||||
*
|
||||
* @return a new matrix containing the result.
|
||||
*/
|
||||
Matrix4 transpose ();
|
||||
|
||||
/**
|
||||
* Transposes this matrix, storing the result in the provided object.
|
||||
*
|
||||
* @return the result matrix, for chaining.
|
||||
*/
|
||||
Matrix4 transpose (Matrix4 result);
|
||||
|
||||
/**
|
||||
* Multiplies this matrix by another.
|
||||
*
|
||||
* @return a new matrix containing the result.
|
||||
*/
|
||||
Matrix4 mult (IMatrix4 other);
|
||||
|
||||
/**
|
||||
* Multiplies this matrix by another and stores the result in the object provided.
|
||||
*
|
||||
* @return a reference to the result matrix, for chaining.
|
||||
*/
|
||||
Matrix4 mult (IMatrix4 other, Matrix4 result);
|
||||
|
||||
/**
|
||||
* Determines whether this matrix represents an affine transformation.
|
||||
*/
|
||||
boolean isAffine ();
|
||||
|
||||
/**
|
||||
* Determines whether the matrix is mirrored.
|
||||
*/
|
||||
boolean isMirrored ();
|
||||
|
||||
/**
|
||||
* Multiplies this matrix by another, treating the matrices as affine.
|
||||
*
|
||||
* @return a new matrix containing the result.
|
||||
*/
|
||||
Matrix4 multAffine (IMatrix4 other);
|
||||
|
||||
/**
|
||||
* Multiplies this matrix by another, treating the matrices as affine, and stores the result
|
||||
* in the object provided.
|
||||
*
|
||||
* @return a reference to the result matrix, for chaining.
|
||||
*/
|
||||
Matrix4 multAffine (IMatrix4 other, Matrix4 result);
|
||||
|
||||
/**
|
||||
* Inverts this matrix.
|
||||
*
|
||||
* @return a new matrix containing the result.
|
||||
*/
|
||||
Matrix4 invert ();
|
||||
|
||||
/**
|
||||
* Inverts this matrix and places the result in the given object. This code is based on the
|
||||
* examples in the <a href="http://www.j3d.org/matrix_faq/matrfaq_latest.html">Matrix and
|
||||
* Quaternion FAQ</a>.
|
||||
*
|
||||
* @return a reference to the result matrix, for chaining.
|
||||
*/
|
||||
Matrix4 invert (Matrix4 result);
|
||||
|
||||
/**
|
||||
* Inverts this matrix as an affine matrix.
|
||||
*
|
||||
* @return a new matrix containing the result.
|
||||
*/
|
||||
Matrix4 invertAffine ();
|
||||
|
||||
/**
|
||||
* Inverts this matrix as an affine matrix and places the result in the given object.
|
||||
*
|
||||
* @return a reference to the result matrix, for chaining.
|
||||
*/
|
||||
Matrix4 invertAffine (Matrix4 result);
|
||||
|
||||
/**
|
||||
* Linearly interpolates between this and the specified other matrix.
|
||||
*
|
||||
* @return a new matrix containing the result.
|
||||
*/
|
||||
Matrix4 lerp (IMatrix4 other, float t);
|
||||
|
||||
/**
|
||||
* Linearly interpolates between this and the specified other matrix, placing the result in
|
||||
* the object provided.
|
||||
*
|
||||
* @return a reference to the result object, for chaining.
|
||||
*/
|
||||
Matrix4 lerp (IMatrix4 other, float t, Matrix4 result);
|
||||
|
||||
/**
|
||||
* Linearly interpolates between this and the specified other matrix, treating the matrices as
|
||||
* affine.
|
||||
*
|
||||
* @return a new matrix containing the result.
|
||||
*/
|
||||
Matrix4 lerpAffine (IMatrix4 other, float t);
|
||||
|
||||
/**
|
||||
* Linearly interpolates between this and the specified other matrix (treating the matrices as
|
||||
* affine);, placing the result in the object provided.
|
||||
*
|
||||
* @return a reference to the result object, for chaining.
|
||||
*/
|
||||
Matrix4 lerpAffine (IMatrix4 other, float t, Matrix4 result);
|
||||
|
||||
/**
|
||||
* Places the contents of this matrix into the given buffer in the standard OpenGL order.
|
||||
*
|
||||
* @return a reference to the buffer, for chaining.
|
||||
*/
|
||||
FloatBuffer get (FloatBuffer buf);
|
||||
|
||||
/**
|
||||
* Projects the supplied point in-place using this matrix.
|
||||
*
|
||||
* @return a reference to the point, for chaining.
|
||||
*/
|
||||
Vector3 projectPointLocal (Vector3 point);
|
||||
|
||||
/**
|
||||
* Projects the supplied point using this matrix.
|
||||
*
|
||||
* @return a new vector containing the result.
|
||||
*/
|
||||
Vector3 projectPoint (IVector3 point);
|
||||
|
||||
/**
|
||||
* Projects the supplied point using this matrix and places the result in the object supplied.
|
||||
*
|
||||
* @return a reference to the result vector, for chaining.
|
||||
*/
|
||||
Vector3 projectPoint (IVector3 point, Vector3 result);
|
||||
|
||||
/**
|
||||
* Transforms a point in-place by this matrix.
|
||||
*
|
||||
* @return a reference to the point, for chaining.
|
||||
*/
|
||||
Vector3 transformPointLocal (Vector3 point);
|
||||
|
||||
/**
|
||||
* Transforms a point by this matrix.
|
||||
*
|
||||
* @return a new vector containing the result.
|
||||
*/
|
||||
Vector3 transformPoint (IVector3 point);
|
||||
|
||||
/**
|
||||
* Transforms a point by this matrix and places the result in the object provided.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Vector3 transformPoint (IVector3 point, Vector3 result);
|
||||
|
||||
/**
|
||||
* Transforms a point by this matrix and returns the resulting z coordinate.
|
||||
*/
|
||||
float transformPointZ (IVector3 point);
|
||||
|
||||
/**
|
||||
* Transforms a vector in-place by the inner 3x3 part of this matrix.
|
||||
*
|
||||
* @return a reference to the vector, for chaining.
|
||||
*/
|
||||
Vector3 transformVectorLocal (Vector3 vector);
|
||||
|
||||
/**
|
||||
* Transforms a vector by this inner 3x3 part of this matrix.
|
||||
*
|
||||
* @return a new vector containing the result.
|
||||
*/
|
||||
Vector3 transformVector (IVector3 vector);
|
||||
|
||||
/**
|
||||
* Transforms a vector by the inner 3x3 part of this matrix and places the result in the object
|
||||
* provided.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Vector3 transformVector (IVector3 vector, Vector3 result);
|
||||
|
||||
/**
|
||||
* Extracts the rotation component of the matrix.
|
||||
*
|
||||
* @return a new quaternion containing the result.
|
||||
*/
|
||||
Quaternion extractRotation ();
|
||||
|
||||
/**
|
||||
* Extracts the rotation component of the matrix and places it in the provided result
|
||||
* quaternion. This uses the iterative polar decomposition algorithm described by
|
||||
* <a href="http://www.cs.wisc.edu/graphics/Courses/838-s2002/Papers/polar-decomp.pdf">Ken
|
||||
* Shoemake</a>.
|
||||
*
|
||||
* @return a reference to the result quaternion, for chaining.
|
||||
*/
|
||||
Quaternion extractRotation (Quaternion result);
|
||||
|
||||
/**
|
||||
* Extracts the scale component of the matrix.
|
||||
*
|
||||
* @return a new vector containing the result.
|
||||
*/
|
||||
Vector3 extractScale ();
|
||||
|
||||
/**
|
||||
* Extracts the scale component of the matrix and places it in the provided result vector.
|
||||
*
|
||||
* @return a reference to the result vector, for chaining.
|
||||
*/
|
||||
Vector3 extractScale (Vector3 result);
|
||||
|
||||
/**
|
||||
* Returns an approximation of the uniform scale for this matrix (the cube root of the
|
||||
* signed volume of the parallelepiped spanned by the axis vectors);.
|
||||
*/
|
||||
float approximateUniformScale ();
|
||||
|
||||
/**
|
||||
* Compares this matrix to another with the provided epsilon.
|
||||
*/
|
||||
boolean epsilonEquals (IMatrix4 other, float epsilon);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.f;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
* Provides read-only access to a {@link Plane}.
|
||||
*/
|
||||
public interface IPlane
|
||||
{
|
||||
/** Returns the plane constant. */
|
||||
float constant ();
|
||||
|
||||
/** Returns the plane normal. */
|
||||
IVector3 normal ();
|
||||
|
||||
/**
|
||||
* Stores the contents of this plane into the specified buffer.
|
||||
*/
|
||||
FloatBuffer get (FloatBuffer buf);
|
||||
|
||||
/**
|
||||
* Computes and returns the signed distance from the plane to the specified point.
|
||||
*/
|
||||
float distance (IVector3 pt);
|
||||
|
||||
// /**
|
||||
// * Transforms this plane by the specified transformation.
|
||||
// *
|
||||
// * @return a new plane containing the result.
|
||||
// */
|
||||
// Plane transform (Transform transform);
|
||||
|
||||
// /**
|
||||
// * Transforms this plane by the specified transformation, placing the result in the object
|
||||
// * provided.
|
||||
// *
|
||||
// * @return a reference to the result plane, for chaining.
|
||||
// */
|
||||
// Plane transform (Transform transform, Plane result);
|
||||
|
||||
/**
|
||||
* Negates this plane.
|
||||
*
|
||||
* @return a new plane containing the result.
|
||||
*/
|
||||
Plane negate ();
|
||||
|
||||
/**
|
||||
* Negates this plane, placing the result in the object provided.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Plane negate (Plane result);
|
||||
|
||||
// /**
|
||||
// * Computes the intersection of the supplied ray with this plane, placing the result
|
||||
// * in the given vector (if the ray intersects).
|
||||
// *
|
||||
// * @return true if the ray intersects the plane (in which case the result will contain
|
||||
// * the point of intersection), false if not.
|
||||
// */
|
||||
// boolean intersection (Ray3D ray, Vector3 result);
|
||||
|
||||
// /**
|
||||
// * Computes the signed distance to this plane along the specified ray.
|
||||
// *
|
||||
// * @return the signed distance, or {@link Float#NaN} if the ray runs parallel to the plane.
|
||||
// */
|
||||
// float distance (Ray3D ray);
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.f;
|
||||
|
||||
/**
|
||||
* Provides read-only access to a {@link Quaternion}.
|
||||
*/
|
||||
public interface IQuaternion
|
||||
{
|
||||
/** Returns the x-component of this quaternion. */
|
||||
float x ();
|
||||
|
||||
/** Returns the y-component of this quaternion. */
|
||||
float y ();
|
||||
|
||||
/** Returns the z-component of this quaternion. */
|
||||
float z ();
|
||||
|
||||
/** Returns the w-component of this quaternion. */
|
||||
float w ();
|
||||
|
||||
/**
|
||||
* Populates the supplied array with the contents of this quaternion.
|
||||
*/
|
||||
void get (float[] values);
|
||||
|
||||
/**
|
||||
* Checks whether any of the components of this quaternion are not-numbers.
|
||||
*/
|
||||
boolean hasNaN ();
|
||||
|
||||
/**
|
||||
* Computes the angles to pass to {@link #fromAngles} to reproduce this rotation, placing them
|
||||
* in the provided vector. This uses the factorization method described in David Eberly's
|
||||
* <a href="http://www.geometrictools.com/Documentation/EulerAngles.pdf">Euler Angle
|
||||
* Formulas</a>.
|
||||
*
|
||||
* @return a reference to the result vector, for chaining.
|
||||
*/
|
||||
Vector3 toAngles (Vector3 result);
|
||||
|
||||
/**
|
||||
* Computes and returns the angles to pass to {@link #fromAngles} to reproduce this rotation.
|
||||
*
|
||||
* @return a new vector containing the resulting angles.
|
||||
*/
|
||||
Vector3 toAngles ();
|
||||
|
||||
/**
|
||||
* Normalizes this quaternion.
|
||||
*
|
||||
* @return a new quaternion containing the result.
|
||||
*/
|
||||
Quaternion normalize ();
|
||||
|
||||
/**
|
||||
* Normalizes this quaternion, storing the result in the object provided.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Quaternion normalize (Quaternion result);
|
||||
|
||||
/**
|
||||
* Inverts this quaternion.
|
||||
*
|
||||
* @return a new quaternion containing the result.
|
||||
*/
|
||||
Quaternion invert ();
|
||||
|
||||
/**
|
||||
* Inverts this quaternion, storing the result in the object provided.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Quaternion invert (Quaternion result);
|
||||
|
||||
/**
|
||||
* Multiplies this quaternion by another.
|
||||
*
|
||||
* @return a new quaternion containing the result.
|
||||
*/
|
||||
Quaternion mult (IQuaternion other);
|
||||
|
||||
/**
|
||||
* Multiplies this quaternion by another and stores the result in the provided object.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Quaternion mult (IQuaternion other, Quaternion result);
|
||||
|
||||
/**
|
||||
* Interpolates between this and the specified other quaternion.
|
||||
*
|
||||
* @return a new quaternion containing the result.
|
||||
*/
|
||||
Quaternion slerp (IQuaternion other, float t);
|
||||
|
||||
/**
|
||||
* Interpolates between this and the specified other quaternion, placing the result in the
|
||||
* object provided. Based on the code in Nick Bobick's article,
|
||||
* <a href="http://www.gamasutra.com/features/19980703/quaternions_01.htm">Rotating Objects
|
||||
* Using Quaternions</a>.
|
||||
*
|
||||
* @return a reference to the result quaternion, for chaining.
|
||||
*/
|
||||
Quaternion slerp (IQuaternion other, float t, Quaternion result);
|
||||
|
||||
/**
|
||||
* Transforms a vector by this quaternion.
|
||||
*
|
||||
* @return a new vector containing the result.
|
||||
*/
|
||||
Vector3 transform (IVector3 vector);
|
||||
|
||||
/**
|
||||
* Transforms a vector by this quaternion and places the result in the provided object.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Vector3 transform (IVector3 vector, Vector3 result);
|
||||
|
||||
/**
|
||||
* Transforms the unit x vector by this quaternion, placing the result in the provided object.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Vector3 transformUnitX (Vector3 result);
|
||||
|
||||
/**
|
||||
* Transforms the unit y vector by this quaternion, placing the result in the provided object.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Vector3 transformUnitY (Vector3 result);
|
||||
|
||||
/**
|
||||
* Transforms the unit z vector by this quaternion, placing the result in the provided object.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Vector3 transformUnitZ (Vector3 result);
|
||||
|
||||
/**
|
||||
* Transforms a vector by this quaternion and adds another vector to it, placing the result
|
||||
* in the object provided.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Vector3 transformAndAdd (IVector3 vector, IVector3 add, Vector3 result);
|
||||
|
||||
/**
|
||||
* Transforms a vector by this quaternion, applies a uniform scale, and adds another vector to
|
||||
* it, placing the result in the object provided.
|
||||
*
|
||||
* @return a reference to the result, for chaining.
|
||||
*/
|
||||
Vector3 transformScaleAndAdd (IVector3 vector, float scale, IVector3 add, Vector3 result);
|
||||
|
||||
/**
|
||||
* Transforms a vector by this quaternion and returns the z coordinate of the result.
|
||||
*/
|
||||
float transformZ (IVector3 vector);
|
||||
|
||||
/**
|
||||
* Returns the amount of rotation about the z axis (for the purpose of flattening the
|
||||
* rotation).
|
||||
*/
|
||||
float getRotationZ ();
|
||||
|
||||
/**
|
||||
* Integrates the provided angular velocity over the specified timestep.
|
||||
*
|
||||
* @return a new quaternion containing the result.
|
||||
*/
|
||||
Quaternion integrate (IVector3 velocity, float t);
|
||||
|
||||
/**
|
||||
* Integrates the provided angular velocity over the specified timestep, storing the result in
|
||||
* the object provided.
|
||||
*
|
||||
* @return a reference to the result object, for chaining.
|
||||
*/
|
||||
Quaternion integrate (IVector3 velocity, float t, Quaternion result);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.f;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
* Provides read-only access to a {@link Vector4}.
|
||||
*/
|
||||
public interface IVector4
|
||||
{
|
||||
/** Returns the x-component of this vector. */
|
||||
float x ();
|
||||
|
||||
/** Returns the y-component of this vector. */
|
||||
float y ();
|
||||
|
||||
/** Returns the z-component of this vector. */
|
||||
float z ();
|
||||
|
||||
/** Returns the w-component of this vector. */
|
||||
float w ();
|
||||
|
||||
/**
|
||||
* Populates the supplied buffer with the contents of this vector.
|
||||
*
|
||||
* @return a reference to the buffer, for chaining.
|
||||
*/
|
||||
FloatBuffer get (FloatBuffer buf);
|
||||
|
||||
/**
|
||||
* Compares this vector to another with the provided epsilon.
|
||||
*/
|
||||
boolean epsilonEquals (IVector4 other, float epsilon);
|
||||
}
|
||||
@@ -4,14 +4,18 @@
|
||||
|
||||
package pythagoras.f;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import pythagoras.util.Platform;
|
||||
import pythagoras.util.SingularMatrixException;
|
||||
|
||||
/**
|
||||
* A 3x3 column-major matrix.
|
||||
*/
|
||||
public class Matrix3 extends AbstractMatrix3
|
||||
public class Matrix3 implements IMatrix3, Serializable
|
||||
{
|
||||
/** The identity matrix. */
|
||||
/** the identity matrix. */
|
||||
public static final Matrix3 IDENTITY = new Matrix3();
|
||||
|
||||
/** The values of the matrix. */
|
||||
@@ -57,10 +61,9 @@ public class Matrix3 extends AbstractMatrix3
|
||||
* @return a reference to this matrix, for chaining.
|
||||
*/
|
||||
public Matrix3 setToIdentity () {
|
||||
return set(
|
||||
1f, 0f, 0f,
|
||||
0f, 1f, 0f,
|
||||
0f, 0f, 1f);
|
||||
return set(1f, 0f, 0f,
|
||||
0f, 1f, 0f,
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,27 +95,26 @@ public class Matrix3 extends AbstractMatrix3
|
||||
public Matrix3 setToRotation (float angle, float x, float y, float z) {
|
||||
float c = FloatMath.cos(angle), s = FloatMath.sin(angle), omc = 1f - c;
|
||||
float xs = x*s, ys = y*s, zs = z*s, xy = x*y, xz = x*z, yz = y*z;
|
||||
return set(
|
||||
x*x*omc + c, xy*omc - zs, xz*omc + ys,
|
||||
xy*omc + zs, y*y*omc + c, yz*omc - xs,
|
||||
xz*omc - ys, yz*omc + xs, z*z*omc + c);
|
||||
return set(x*x*omc + c, xy*omc - zs, xz*omc + ys,
|
||||
xy*omc + zs, y*y*omc + c, yz*omc - xs,
|
||||
xz*omc - ys, yz*omc + xs, z*z*omc + c);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Sets this to a rotation matrix. The formula comes from the
|
||||
// * <a href="http://www.j3d.org/matrix_faq/matrfaq_latest.html">Matrix and Quaternion FAQ</a>.
|
||||
// *
|
||||
// * @return a reference to this matrix, for chaining.
|
||||
// */
|
||||
// public Matrix3 setToRotation (Quaternion quat) {
|
||||
// float xx = quat.x*quat.x, yy = quat.y*quat.y, zz = quat.z*quat.z;
|
||||
// float xy = quat.x*quat.y, xz = quat.x*quat.z, xw = quat.x*quat.w;
|
||||
// float yz = quat.y*quat.z, yw = quat.y*quat.w, zw = quat.z*quat.w;
|
||||
// return set(
|
||||
// 1f - 2f*(yy + zz), 2f*(xy - zw), 2f*(xz + yw),
|
||||
// 2f*(xy + zw), 1f - 2f*(xx + zz), 2f*(yz - xw),
|
||||
// 2f*(xz - yw), 2f*(yz + xw), 1f - 2f*(xx + yy));
|
||||
// }
|
||||
/**
|
||||
* Sets this to a rotation matrix. The formula comes from the
|
||||
* <a href="http://www.j3d.org/matrix_faq/matrfaq_latest.html">Matrix and Quaternion FAQ</a>.
|
||||
*
|
||||
* @return a reference to this matrix, for chaining.
|
||||
*/
|
||||
public Matrix3 setToRotation (IQuaternion quat) {
|
||||
float qx = quat.x(), qy = quat.y(), qz = quat.z(), qw = quat.w();
|
||||
float xx = qx*qx, yy = qy*qy, zz = qz*qz;
|
||||
float xy = qx*qy, xz = qx*qz, xw = qx*qw;
|
||||
float yz = qy*qz, yw = qy*qw, zw = qz*qw;
|
||||
return set(1f - 2f*(yy + zz), 2f*(xy - zw), 2f*(xz + yw),
|
||||
2f*(xy + zw), 1f - 2f*(xx + zz), 2f*(yz - xw),
|
||||
2f*(xz - yw), 2f*(yz + xw), 1f - 2f*(xx + yy));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this to a scale matrix.
|
||||
@@ -138,10 +140,9 @@ public class Matrix3 extends AbstractMatrix3
|
||||
* @return a reference to this matrix, for chaining.
|
||||
*/
|
||||
public Matrix3 setToScale (float x, float y, float z) {
|
||||
return set(
|
||||
x, 0f, 0f,
|
||||
0f, y, 0f,
|
||||
0f, 0f, z);
|
||||
return set(x, 0f, 0f,
|
||||
0f, y, 0f,
|
||||
0f, 0f, z);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,10 +162,9 @@ public class Matrix3 extends AbstractMatrix3
|
||||
public Matrix3 setToReflection (float x, float y, float z) {
|
||||
float x2 = -2f*x, y2 = -2f*y, z2 = -2f*z;
|
||||
float xy2 = x2*y, xz2 = x2*z, yz2 = y2*z;
|
||||
return set(
|
||||
1f + x2*x, xy2, xz2,
|
||||
xy2, 1f + y2*y, yz2,
|
||||
xz2, yz2, 1f + z2*z);
|
||||
return set(1f + x2*x, xy2, xz2,
|
||||
xy2, 1f + y2*y, yz2,
|
||||
xz2, yz2, 1f + z2*z);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,10 +182,9 @@ public class Matrix3 extends AbstractMatrix3
|
||||
* @return a reference to this matrix, for chaining.
|
||||
*/
|
||||
public Matrix3 setToTransform (IVector translation, float rotation, float scale) {
|
||||
return setToRotation(rotation).set(
|
||||
m00 * scale, m10 * scale, translation.x(),
|
||||
m01 * scale, m11 * scale, translation.y(),
|
||||
0f, 0f, 1f);
|
||||
return setToRotation(rotation).set(m00 * scale, m10 * scale, translation.x(),
|
||||
m01 * scale, m11 * scale, translation.y(),
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,10 +194,9 @@ public class Matrix3 extends AbstractMatrix3
|
||||
*/
|
||||
public Matrix3 setToTransform (IVector translation, float rotation, IVector scale) {
|
||||
float sx = scale.x(), sy = scale.y();
|
||||
return setToRotation(rotation).set(
|
||||
m00 * sx, m10 * sy, translation.x(),
|
||||
m01 * sx, m11 * sy, translation.y(),
|
||||
0f, 0f, 1f);
|
||||
return setToRotation(rotation).set(m00 * sx, m10 * sy, translation.x(),
|
||||
m01 * sx, m11 * sy, translation.y(),
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,10 +214,9 @@ public class Matrix3 extends AbstractMatrix3
|
||||
* @return a reference to this matrix, for chaining.
|
||||
*/
|
||||
public Matrix3 setToTranslation (float x, float y) {
|
||||
return set(
|
||||
1f, 0f, x,
|
||||
0f, 1f, y,
|
||||
0f, 0f, 1f);
|
||||
return set(1f, 0f, x,
|
||||
0f, 1f, y,
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -249,10 +246,9 @@ public class Matrix3 extends AbstractMatrix3
|
||||
*/
|
||||
public Matrix3 setToRotation (float angle) {
|
||||
float sina = FloatMath.sin(angle), cosa = FloatMath.cos(angle);
|
||||
return set(
|
||||
cosa, -sina, 0f,
|
||||
sina, cosa, 0f,
|
||||
0f, 0f, 1f);
|
||||
return set(cosa, -sina, 0f,
|
||||
sina, cosa, 0f,
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -326,10 +322,9 @@ public class Matrix3 extends AbstractMatrix3
|
||||
* @return a reference to this matrix, for chaining.
|
||||
*/
|
||||
public Matrix3 set (IMatrix3 other) {
|
||||
return set(
|
||||
other.m00(), other.m10(), other.m20(),
|
||||
other.m01(), other.m11(), other.m21(),
|
||||
other.m02(), other.m12(), other.m22());
|
||||
return set(other.m00(), other.m10(), other.m20(),
|
||||
other.m01(), other.m11(), other.m21(),
|
||||
other.m02(), other.m12(), other.m22());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -338,10 +333,9 @@ public class Matrix3 extends AbstractMatrix3
|
||||
* @return a reference to this matrix, for chaining.
|
||||
*/
|
||||
public Matrix3 set (float[] values) {
|
||||
return set(
|
||||
values[0], values[1], values[2],
|
||||
values[3], values[4], values[5],
|
||||
values[6], values[7], values[8]);
|
||||
return set(values[0], values[1], values[2],
|
||||
values[3], values[4], values[5],
|
||||
values[6], values[7], values[8]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -359,48 +353,367 @@ public class Matrix3 extends AbstractMatrix3
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override // from AbstractMatrix3
|
||||
@Override // from IMatrix3
|
||||
public float m00 () {
|
||||
return m00;
|
||||
}
|
||||
|
||||
@Override // from AbstractMatrix3
|
||||
@Override // from IMatrix3
|
||||
public float m10 () {
|
||||
return m10;
|
||||
}
|
||||
|
||||
@Override // from AbstractMatrix3
|
||||
@Override // from IMatrix3
|
||||
public float m20 () {
|
||||
return m20;
|
||||
}
|
||||
|
||||
@Override // from AbstractMatrix3
|
||||
@Override // from IMatrix3
|
||||
public float m01 () {
|
||||
return m01;
|
||||
}
|
||||
|
||||
@Override // from AbstractMatrix3
|
||||
@Override // from IMatrix3
|
||||
public float m11 () {
|
||||
return m11;
|
||||
}
|
||||
|
||||
@Override // from AbstractMatrix3
|
||||
@Override // from IMatrix3
|
||||
public float m21 () {
|
||||
return m21;
|
||||
}
|
||||
|
||||
@Override // from AbstractMatrix3
|
||||
@Override // from IMatrix3
|
||||
public float m02 () {
|
||||
return m02;
|
||||
}
|
||||
|
||||
@Override // from AbstractMatrix3
|
||||
@Override // from IMatrix3
|
||||
public float m12 () {
|
||||
return m12;
|
||||
}
|
||||
|
||||
@Override // from AbstractMatrix3
|
||||
@Override // from IMatrix3
|
||||
public float m22 () {
|
||||
return m22;
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 transpose () {
|
||||
return transpose(new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 transpose (Matrix3 result) {
|
||||
return result.set(m00, m01, m02,
|
||||
m10, m11, m12,
|
||||
m20, m21, m22);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 mult (IMatrix3 other) {
|
||||
return mult(other, new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 mult (IMatrix3 other, Matrix3 result) {
|
||||
float m00 = this.m00, m01 = this.m01, m02 = this.m02;
|
||||
float m10 = this.m10, m11 = this.m11, m12 = this.m12;
|
||||
float m20 = this.m20, m21 = this.m21, m22 = this.m22;
|
||||
float om00 = other.m00(), om01 = other.m01(), om02 = other.m02();
|
||||
float om10 = other.m10(), om11 = other.m11(), om12 = other.m12();
|
||||
float om20 = other.m20(), om21 = other.m21(), om22 = other.m22();
|
||||
return result.set(m00*om00 + m10*om01 + m20*om02,
|
||||
m00*om10 + m10*om11 + m20*om12,
|
||||
m00*om20 + m10*om21 + m20*om22,
|
||||
|
||||
m01*om00 + m11*om01 + m21*om02,
|
||||
m01*om10 + m11*om11 + m21*om12,
|
||||
m01*om20 + m11*om21 + m21*om22,
|
||||
|
||||
m02*om00 + m12*om01 + m22*om02,
|
||||
m02*om10 + m12*om11 + m22*om12,
|
||||
m02*om20 + m12*om21 + m22*om22);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public boolean isAffine () {
|
||||
return (m02 == 0f && m12 == 0f && m22 == 1f);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 multAffine (IMatrix3 other) {
|
||||
return multAffine(other, new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 multAffine (IMatrix3 other, Matrix3 result) {
|
||||
float m00 = this.m00, m01 = this.m01, m02 = this.m02;
|
||||
float m10 = this.m10, m11 = this.m11, m12 = this.m12;
|
||||
float m20 = this.m20, m21 = this.m21, m22 = this.m22;
|
||||
float om00 = other.m00(), om01 = other.m01(), om02 = other.m02();
|
||||
float om10 = other.m10(), om11 = other.m11(), om12 = other.m12();
|
||||
float om20 = other.m20(), om21 = other.m21(), om22 = other.m22();
|
||||
return result.set(m00*om00 + m10*om01,
|
||||
m00*om10 + m10*om11,
|
||||
m00*om20 + m10*om21 + m20,
|
||||
|
||||
m01*om00 + m11*om01,
|
||||
m01*om10 + m11*om11,
|
||||
m01*om20 + m11*om21 + m21,
|
||||
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 invert () {
|
||||
return invert(new Matrix3());
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverts this matrix and places the result in the given object. This code is based on the
|
||||
* examples in the <a href="http://www.j3d.org/matrix_faq/matrfaq_latest.html">Matrix and
|
||||
* Quaternion FAQ</a>.
|
||||
*
|
||||
* @return a reference to the result matrix, for chaining.
|
||||
*/
|
||||
public Matrix3 invert (Matrix3 result) throws SingularMatrixException {
|
||||
float m00 = this.m00, m01 = this.m01, m02 = this.m02;
|
||||
float m10 = this.m10, m11 = this.m11, m12 = this.m12;
|
||||
float m20 = this.m20, m21 = this.m21, m22 = this.m22;
|
||||
// compute the determinant, storing the subdeterminants for later use
|
||||
float sd00 = m11*m22 - m21*m12;
|
||||
float sd10 = m01*m22 - m21*m02;
|
||||
float sd20 = m01*m12 - m11*m02;
|
||||
float det = m00*sd00 + m20*sd20 - m10*sd10;
|
||||
if (Math.abs(det) == 0f) {
|
||||
// determinant is zero; matrix is not invertible
|
||||
throw new SingularMatrixException(this.toString());
|
||||
}
|
||||
float rdet = 1f / det;
|
||||
return result.set(+sd00 * rdet,
|
||||
-(m10*m22 - m20*m12) * rdet,
|
||||
+(m10*m21 - m20*m11) * rdet,
|
||||
|
||||
-sd10 * rdet,
|
||||
+(m00*m22 - m20*m02) * rdet,
|
||||
-(m00*m21 - m20*m01) * rdet,
|
||||
|
||||
+sd20 * rdet,
|
||||
-(m00*m12 - m10*m02) * rdet,
|
||||
+(m00*m11 - m10*m01) * rdet);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 invertAffine () {
|
||||
return invertAffine(new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 invertAffine (Matrix3 result) throws SingularMatrixException {
|
||||
float m00 = this.m00, m01 = this.m01, m02 = this.m02;
|
||||
float m10 = this.m10, m11 = this.m11, m12 = this.m12;
|
||||
float m20 = this.m20, m21 = this.m21, m22 = this.m22;
|
||||
// compute the determinant, storing the subdeterminants for later use
|
||||
float det = m00*m11 - m10*m01;
|
||||
if (Math.abs(det) == 0f) {
|
||||
// determinant is zero; matrix is not invertible
|
||||
throw new SingularMatrixException(this.toString());
|
||||
}
|
||||
float rdet = 1f / det;
|
||||
return result.set(+m11 * rdet,
|
||||
-m10 * rdet,
|
||||
+(m10*m21 - m20*m11) * rdet,
|
||||
|
||||
-m01 * rdet,
|
||||
+m00 * rdet,
|
||||
-(m00*m21 - m20*m01) * rdet,
|
||||
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 lerp (IMatrix3 other, float t) {
|
||||
return lerp(other, t, new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 lerp (IMatrix3 other, float t, Matrix3 result) {
|
||||
float m00 = this.m00, m01 = this.m01, m02 = this.m02;
|
||||
float m10 = this.m10, m11 = this.m11, m12 = this.m12;
|
||||
float m20 = this.m20, m21 = this.m21, m22 = this.m22;
|
||||
float om00 = other.m00(), om01 = other.m01(), om02 = other.m02();
|
||||
float om10 = other.m10(), om11 = other.m11(), om12 = other.m12();
|
||||
float om20 = other.m20(), om21 = other.m21(), om22 = other.m22();
|
||||
return result.set(m00 + t*(om00 - m00),
|
||||
m10 + t*(om10 - m10),
|
||||
m20 + t*(om20 - m20),
|
||||
|
||||
m01 + t*(om01 - m01),
|
||||
m11 + t*(om11 - m11),
|
||||
m21 + t*(om21 - m21),
|
||||
|
||||
m02 + t*(om02 - m02),
|
||||
m12 + t*(om12 - m12),
|
||||
m22 + t*(om22 - m22));
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 lerpAffine (IMatrix3 other, float t) {
|
||||
return lerpAffine(other, t, new Matrix3());
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Matrix3 lerpAffine (IMatrix3 other, float t, Matrix3 result) {
|
||||
float m00 = this.m00, m01 = this.m01, m02 = this.m02;
|
||||
float m10 = this.m10, m11 = this.m11, m12 = this.m12;
|
||||
float m20 = this.m20, m21 = this.m21, m22 = this.m22;
|
||||
float om00 = other.m00(), om01 = other.m01(), om02 = other.m02();
|
||||
float om10 = other.m10(), om11 = other.m11(), om12 = other.m12();
|
||||
float om20 = other.m20(), om21 = other.m21(), om22 = other.m22();
|
||||
return result.set(m00 + t*(om00 - m00),
|
||||
m10 + t*(om10 - m10),
|
||||
m20 + t*(om20 - m20),
|
||||
|
||||
m01 + t*(om01 - m01),
|
||||
m11 + t*(om11 - m11),
|
||||
m21 + t*(om21 - m21),
|
||||
|
||||
0f, 0f, 1f);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public FloatBuffer get (FloatBuffer buf) {
|
||||
buf.put(m00).put(m01).put(m02);
|
||||
buf.put(m10).put(m11).put(m12);
|
||||
buf.put(m20).put(m21).put(m22);
|
||||
return buf;
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector3 transformLocal (Vector3 vector) {
|
||||
return transform(vector, vector);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector3 transform (IVector3 vector) {
|
||||
return transform(vector, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector3 transform (IVector3 vector, Vector3 result) {
|
||||
float vx = vector.x(), vy = vector.y(), vz = vector.z();
|
||||
return result.set(m00*vx + m10*vy + m20*vz,
|
||||
m01*vx + m11*vy + m21*vz,
|
||||
m02*vx + m12*vy + m22*vz);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector transformPointLocal (Vector point) {
|
||||
return transformPoint(point, point);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector transformPoint (IVector point) {
|
||||
return transformPoint(point, new Vector());
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector transformPoint (IVector point, Vector result) {
|
||||
float px = point.x(), py = point.y();
|
||||
return result.set(m00*px + m10*py + m20, m01*px + m11*py + m21);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector transformVectorLocal (Vector vector) {
|
||||
return transformVector(vector, vector);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector transformVector (IVector vector) {
|
||||
return transformVector(vector, new Vector());
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector transformVector (IVector vector, Vector result) {
|
||||
float vx = vector.x(), vy = vector.y();
|
||||
return result.set(m00*vx + m10*vy, m01*vx + m11*vy);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public float extractRotation () {
|
||||
// start with the contents of the upper 2x2 portion of the matrix
|
||||
float n00 = m00, n10 = m10;
|
||||
float n01 = m01, n11 = m11;
|
||||
for (int ii = 0; ii < 10; ii++) {
|
||||
// store the results of the previous iteration
|
||||
float o00 = n00, o10 = n10;
|
||||
float o01 = n01, o11 = n11;
|
||||
|
||||
// compute average of the matrix with its inverse transpose
|
||||
float det = o00*o11 - o10*o01;
|
||||
if (Math.abs(det) == 0f) {
|
||||
// determinant is zero; matrix is not invertible
|
||||
throw new SingularMatrixException(this.toString());
|
||||
}
|
||||
float hrdet = 0.5f / det;
|
||||
n00 = +o11 * hrdet + o00*0.5f;
|
||||
n10 = -o01 * hrdet + o10*0.5f;
|
||||
|
||||
n01 = -o10 * hrdet + o01*0.5f;
|
||||
n11 = +o00 * hrdet + o11*0.5f;
|
||||
|
||||
// compute the difference; if it's small enough, we're done
|
||||
float d00 = n00 - o00, d10 = n10 - o10;
|
||||
float d01 = n01 - o01, d11 = n11 - o11;
|
||||
if (d00*d00 + d10*d10 + d01*d01 + d11*d11 < MathUtil.EPSILON) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// now that we have a nice orthogonal matrix, we can extract the rotation
|
||||
return FloatMath.atan2(n01, n00);
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector extractScale () {
|
||||
return extractScale(new Vector());
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public Vector extractScale (Vector result) {
|
||||
float m00 = this.m00, m01 = this.m01, m10 = this.m10, m11 = this.m11;
|
||||
return result.set(FloatMath.sqrt(m00*m00 + m01*m01),
|
||||
FloatMath.sqrt(m10*m10 + m11*m11));
|
||||
}
|
||||
|
||||
@Override // from IMatrix3
|
||||
public float approximateUniformScale () {
|
||||
float cp = m00*m11 - m01*m10;
|
||||
return (cp < 0f) ? -FloatMath.sqrt(-cp) : FloatMath.sqrt(cp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString () {
|
||||
return ("[[" + m00 + ", " + m10 + ", " + m20 + "], " +
|
||||
"[" + m01 + ", " + m11 + ", " + m21 + "], " +
|
||||
"[" + m02 + ", " + m12 + ", " + m22 + "]]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode () {
|
||||
return Platform.hashCode(m00) ^ Platform.hashCode(m10) ^ Platform.hashCode(m20) ^
|
||||
Platform.hashCode(m01) ^ Platform.hashCode(m11) ^ Platform.hashCode(m21) ^
|
||||
Platform.hashCode(m02) ^ Platform.hashCode(m12) ^ Platform.hashCode(m22);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals (Object other) {
|
||||
if (!(other instanceof Matrix3)) {
|
||||
return false;
|
||||
}
|
||||
Matrix3 omat = (Matrix3)other;
|
||||
return (m00 == omat.m00 && m10 == omat.m10 && m20 == omat.m20 &&
|
||||
m01 == omat.m01 && m11 == omat.m11 && m21 == omat.m21 &&
|
||||
m02 == omat.m02 && m12 == omat.m12 && m22 == omat.m22);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,232 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.f;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import pythagoras.util.Platform;
|
||||
|
||||
/**
|
||||
* A plane consisting of a unit normal and a constant. All points on the plane satisfy the equation
|
||||
* {@code Ax + By + Cz + D = 0}, where (A, B, C) is the plane normal and D is the constant.
|
||||
*/
|
||||
public class Plane implements IPlane, Serializable
|
||||
{
|
||||
/** The X/Y plane. */
|
||||
public static final Plane XY_PLANE = new Plane(Vector3.UNIT_Z, 0f);
|
||||
|
||||
/** The X/Z plane. */
|
||||
public static final Plane XZ_PLANE = new Plane(Vector3.UNIT_Y, 0f);
|
||||
|
||||
/** The Y/Z plane. */
|
||||
public static final Plane YZ_PLANE = new Plane(Vector3.UNIT_X, 0f);
|
||||
|
||||
/** The plane constant. */
|
||||
public float constant;
|
||||
|
||||
/**
|
||||
* Creates a plane from the specified normal and constant.
|
||||
*/
|
||||
public Plane (IVector3 normal, float constant) {
|
||||
set(normal, constant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a plane with the specified parameters.
|
||||
*/
|
||||
public Plane (float[] values) {
|
||||
set(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a plane with the specified parameters.
|
||||
*/
|
||||
public Plane (float a, float b, float c, float d) {
|
||||
set(a, b, c, d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*/
|
||||
public Plane (Plane other) {
|
||||
set(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty (invalid) plane.
|
||||
*/
|
||||
public Plane () {
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the parameters of another plane.
|
||||
*
|
||||
* @return a reference to this plane (for chaining).
|
||||
*/
|
||||
public Plane set (Plane other) {
|
||||
return set(other.normal(), other.constant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parameters of the plane.
|
||||
*
|
||||
* @return a reference to this plane (for chaining).
|
||||
*/
|
||||
public Plane set (IVector3 normal, float constant) {
|
||||
return set(normal.x(), normal.y(), normal.z(), constant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parameters of the plane.
|
||||
*
|
||||
* @return a reference to this plane (for chaining).
|
||||
*/
|
||||
public Plane set (float[] values) {
|
||||
return set(values[0], values[1], values[2], values[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parameters of the plane.
|
||||
*
|
||||
* @return a reference to this plane (for chaining).
|
||||
*/
|
||||
public Plane set (float a, float b, float c, float d) {
|
||||
_normal.set(a, b, c);
|
||||
constant = d;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this plane based on the three points provided.
|
||||
*
|
||||
* @return a reference to the plane (for chaining).
|
||||
*/
|
||||
public Plane fromPoints (IVector3 p1, IVector3 p2, IVector3 p3) {
|
||||
// compute the normal by taking the cross product of the two vectors formed
|
||||
p2.subtract(p1, _v1);
|
||||
p3.subtract(p1, _v2);
|
||||
_v1.cross(_v2, _normal).normalizeLocal();
|
||||
|
||||
// use the first point to determine the constant
|
||||
constant = -_normal.dot(p1);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this plane based on a point on the plane and the plane normal.
|
||||
*
|
||||
* @return a reference to the plane (for chaining).
|
||||
*/
|
||||
public Plane fromPointNormal (IVector3 pt, IVector3 normal) {
|
||||
return set(normal, -normal.dot(pt));
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Transforms this plane in-place by the specified transformation.
|
||||
// *
|
||||
// * @return a reference to this plane, for chaining.
|
||||
// */
|
||||
// public Plane transformLocal (Transform transform) {
|
||||
// return transform(transform, this);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Negates this plane in-place.
|
||||
*
|
||||
* @return a reference to this plane, for chaining.
|
||||
*/
|
||||
public Plane negateLocal () {
|
||||
return negate(this);
|
||||
}
|
||||
|
||||
@Override // from IPlane
|
||||
public float constant () {
|
||||
return constant;
|
||||
}
|
||||
|
||||
@Override // from IPlane
|
||||
public IVector3 normal () {
|
||||
return _normal;
|
||||
}
|
||||
|
||||
@Override // from IPlane
|
||||
public FloatBuffer get (FloatBuffer buf) {
|
||||
return buf.put(_normal.x).put(_normal.y).put(_normal.z).put(constant);
|
||||
}
|
||||
|
||||
@Override // from IPlane
|
||||
public float distance (IVector3 pt) {
|
||||
return _normal.dot(pt) + constant;
|
||||
}
|
||||
|
||||
// @Override // from IPlane
|
||||
// public Plane transform (Transform transform) {
|
||||
// return transform(transform, new Plane());
|
||||
// }
|
||||
|
||||
// @Override // from IPlane
|
||||
// public Plane transform (Transform transform, Plane result) {
|
||||
// transform.transformPointLocal(_normal.mult(-constant, _v1));
|
||||
// transform.transformVector(_normal, _v2).normalizeLocal();
|
||||
// return result.fromPointNormal(_v1, _v2);
|
||||
// }
|
||||
|
||||
@Override // from IPlane
|
||||
public Plane negate () {
|
||||
return negate(new Plane());
|
||||
}
|
||||
|
||||
@Override // from IPlane
|
||||
public Plane negate (Plane result) {
|
||||
_normal.negate(result._normal);
|
||||
result.constant = -constant;
|
||||
return result;
|
||||
}
|
||||
|
||||
// @Override // from IPlane
|
||||
// public boolean intersection (Ray3D ray, Vector3 result) {
|
||||
// float distance = distance(ray);
|
||||
// if (Float.isNaN(distance) || distance < 0f) {
|
||||
// return false;
|
||||
// } else {
|
||||
// ray.origin().addScaled(ray.direction(), distance, result);
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
|
||||
// @Override // from IPlane
|
||||
// public float distance (Ray3D ray) {
|
||||
// float dividend = -distance(ray.origin());
|
||||
// float divisor = _normal.dot(ray.direction());
|
||||
// if (Math.abs(dividend) < MathUtil.EPSILON) {
|
||||
// return 0f; // origin is on plane
|
||||
// } else if (Math.abs(divisor) < MathUtil.EPSILON) {
|
||||
// return Float.NaN; // ray is parallel to plane
|
||||
// } else {
|
||||
// return dividend / divisor;
|
||||
// }
|
||||
// }
|
||||
|
||||
@Override
|
||||
public int hashCode () {
|
||||
return _normal.hashCode() ^ Platform.hashCode(constant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals (Object other) {
|
||||
if (!(other instanceof Plane)) {
|
||||
return false;
|
||||
}
|
||||
Plane oplane = (Plane)other;
|
||||
return constant == oplane.constant && _normal.equals(oplane.normal());
|
||||
}
|
||||
|
||||
/** The plane normal. */
|
||||
protected final Vector3 _normal = new Vector3();
|
||||
|
||||
/** Working vectors for computation. */
|
||||
protected final Vector3 _v1 = new Vector3(), _v2 = new Vector3();
|
||||
}
|
||||
@@ -0,0 +1,515 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.f;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Random;
|
||||
|
||||
import pythagoras.util.Platform;
|
||||
|
||||
/**
|
||||
* A unit quaternion. Many of the formulas come from the
|
||||
* <a href="http://www.j3d.org/matrix_faq/matrfaq_latest.html">Matrix and Quaternion FAQ</a>.
|
||||
*/
|
||||
public class Quaternion implements IQuaternion, Serializable
|
||||
{
|
||||
/** The identity quaternion. */
|
||||
public static final IQuaternion IDENTITY = new Quaternion(0f, 0f, 0f, 1f);
|
||||
|
||||
/** The components of the quaternion. */
|
||||
public float x, y, z, w;
|
||||
|
||||
/**
|
||||
* Creates a quaternion from four components.
|
||||
*/
|
||||
public Quaternion (float x, float y, float z, float w) {
|
||||
set(x, y, z, w);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a quaternion from an array of values.
|
||||
*/
|
||||
public Quaternion (float[] values) {
|
||||
set(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*/
|
||||
public Quaternion (IQuaternion other) {
|
||||
set(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an identity quaternion.
|
||||
*/
|
||||
public Quaternion () {
|
||||
set(0f, 0f, 0f, 1f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the elements of another quaternion.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion set (IQuaternion other) {
|
||||
return set(other.x(), other.y(), other.z(), other.w());
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the elements of an array.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion set (float[] values) {
|
||||
return set(values[0], values[1], values[2], values[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all of the elements of the quaternion.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion set (float x, float y, float z, float w) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.w = w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this quaternion to the rotation of the first normalized vector onto the second.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion fromVectors (IVector3 from, IVector3 to) {
|
||||
float angle = from.angle(to);
|
||||
if (angle < MathUtil.EPSILON) {
|
||||
return set(IDENTITY);
|
||||
}
|
||||
if (angle <= FloatMath.PI - MathUtil.EPSILON) {
|
||||
return fromAngleAxis(angle, from.cross(to).normalizeLocal());
|
||||
}
|
||||
// it's a 180 degree rotation; any axis orthogonal to the from vector will do
|
||||
Vector3 axis = new Vector3(0f, from.z(), -from.y());
|
||||
float length = axis.length();
|
||||
return fromAngleAxis(FloatMath.PI, length < MathUtil.EPSILON ?
|
||||
axis.set(-from.z(), 0f, from.x()).normalizeLocal() :
|
||||
axis.multLocal(1f / length));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this quaternion to the rotation of (0, 0, -1) onto the supplied normalized vector.
|
||||
*
|
||||
* @return a reference to the quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion fromVectorFromNegativeZ (IVector3 to) {
|
||||
return fromVectorFromNegativeZ(to.x(), to.y(), to.z());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this quaternion to the rotation of (0, 0, -1) onto the supplied normalized vector.
|
||||
*
|
||||
* @return a reference to the quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion fromVectorFromNegativeZ (float tx, float ty, float tz) {
|
||||
float angle = FloatMath.acos(-tz);
|
||||
if (angle < MathUtil.EPSILON) {
|
||||
return set(IDENTITY);
|
||||
}
|
||||
if (angle > FloatMath.PI - MathUtil.EPSILON) {
|
||||
return set(0f, 1f, 0f, 0f); // 180 degrees about y
|
||||
}
|
||||
float len = FloatMath.hypot(tx, ty);
|
||||
return fromAngleAxis(angle, ty/len, -tx/len, 0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this quaternion to one that rotates onto the given unit axes.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion fromAxes (IVector3 nx, IVector3 ny, IVector3 nz) {
|
||||
float nxx = nx.x(), nyy = ny.y(), nzz = nz.z();
|
||||
float x2 = (1f + nxx - nyy - nzz)/4f;
|
||||
float y2 = (1f - nxx + nyy - nzz)/4f;
|
||||
float z2 = (1f - nxx - nyy + nzz)/4f;
|
||||
float w2 = (1f - x2 - y2 - z2);
|
||||
return set(FloatMath.sqrt(x2) * (ny.z() >= nz.y() ? +1f : -1f),
|
||||
FloatMath.sqrt(y2) * (nz.x() >= nx.z() ? +1f : -1f),
|
||||
FloatMath.sqrt(z2) * (nx.y() >= ny.x() ? +1f : -1f),
|
||||
FloatMath.sqrt(w2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this quaternion to the rotation described by the given angle and normalized
|
||||
* axis.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion fromAngleAxis (float angle, IVector3 axis) {
|
||||
return fromAngleAxis(angle, axis.x(), axis.y(), axis.z());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this quaternion to the rotation described by the given angle and normalized
|
||||
* axis.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion fromAngleAxis (float angle, float x, float y, float z) {
|
||||
float sina = FloatMath.sin(angle / 2f);
|
||||
return set(x*sina, y*sina, z*sina, FloatMath.cos(angle / 2f));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this to a random rotation obtained from a completely uniform distribution.
|
||||
*/
|
||||
public Quaternion randomize (Random rand) {
|
||||
// pick angles according to the surface area distribution
|
||||
return fromAngles(MathUtil.lerp(-FloatMath.PI, +FloatMath.PI, rand.nextFloat()),
|
||||
FloatMath.asin(MathUtil.lerp(-1f, +1f, rand.nextFloat())),
|
||||
MathUtil.lerp(-FloatMath.PI, +FloatMath.PI, rand.nextFloat()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this quaternion to one that first rotates about x by the specified number of radians,
|
||||
* then rotates about z by the specified number of radians.
|
||||
*/
|
||||
public Quaternion fromAnglesXZ (float x, float z) {
|
||||
float hx = x * 0.5f, hz = z * 0.5f;
|
||||
float sx = FloatMath.sin(hx), cx = FloatMath.cos(hx);
|
||||
float sz = FloatMath.sin(hz), cz = FloatMath.cos(hz);
|
||||
return set(cz*sx, sz*sx, sz*cx, cz*cx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this quaternion to one that first rotates about x by the specified number of radians,
|
||||
* then rotates about y by the specified number of radians.
|
||||
*/
|
||||
public Quaternion fromAnglesXY (float x, float y) {
|
||||
float hx = x * 0.5f, hy = y * 0.5f;
|
||||
float sx = FloatMath.sin(hx), cx = FloatMath.cos(hx);
|
||||
float sy = FloatMath.sin(hy), cy = FloatMath.cos(hy);
|
||||
return set(cy*sx, sy*cx, -sy*sx, cy*cx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this quaternion to one that first rotates about x by the specified number of radians,
|
||||
* then rotates about y, then about z.
|
||||
*/
|
||||
public Quaternion fromAngles (Vector3 angles) {
|
||||
return fromAngles(angles.x, angles.y, angles.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this quaternion to one that first rotates about x by the specified number of radians,
|
||||
* then rotates about y, then about z.
|
||||
*/
|
||||
public Quaternion fromAngles (float x, float y, float z) {
|
||||
// TODO: it may be more convenient to define the angles in the opposite order (first z,
|
||||
// then y, then x)
|
||||
float hx = x * 0.5f, hy = y * 0.5f, hz = z * 0.5f;
|
||||
float sz = FloatMath.sin(hz), cz = FloatMath.cos(hz);
|
||||
float sy = FloatMath.sin(hy), cy = FloatMath.cos(hy);
|
||||
float sx = FloatMath.sin(hx), cx = FloatMath.cos(hx);
|
||||
float szsy = sz*sy, czsy = cz*sy, szcy = sz*cy, czcy = cz*cy;
|
||||
return set(
|
||||
czcy*sx - szsy*cx,
|
||||
czsy*cx + szcy*sx,
|
||||
szcy*cx - czsy*sx,
|
||||
czcy*cx + szsy*sx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes this quaternion in-place.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion normalizeLocal () {
|
||||
return normalize(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverts this quaternion in-place.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion invertLocal () {
|
||||
return invert(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies this quaternion in-place by another.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion multLocal (IQuaternion other) {
|
||||
return mult(other, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolates in-place between this and the specified other quaternion.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion slerpLocal (IQuaternion other, float t) {
|
||||
return slerp(other, t, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a vector in-place by this quaternion.
|
||||
*
|
||||
* @return a reference to the vector, for chaining.
|
||||
*/
|
||||
public Vector3 transformLocal (Vector3 vector) {
|
||||
return transform(vector, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Integrates in-place the provided angular velocity over the specified timestep.
|
||||
*
|
||||
* @return a reference to this quaternion, for chaining.
|
||||
*/
|
||||
public Quaternion integrateLocal (IVector3 velocity, float t) {
|
||||
return integrate(velocity, t, this);
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public float x () {
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public float y () {
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public float z () {
|
||||
return z;
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public float w () {
|
||||
return w;
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public void get (float[] values) {
|
||||
values[0] = x;
|
||||
values[1] = y;
|
||||
values[2] = z;
|
||||
values[3] = w;
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public boolean hasNaN () {
|
||||
return Float.isNaN(x) || Float.isNaN(y) || Float.isNaN(z) || Float.isNaN(w);
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Vector3 toAngles (Vector3 result) {
|
||||
float sy = 2f*(y*w - x*z);
|
||||
if (sy < 1f - MathUtil.EPSILON) {
|
||||
if (sy > -1 + MathUtil.EPSILON) {
|
||||
return result.set(FloatMath.atan2(y*z + x*w, 0.5f - (x*x + y*y)),
|
||||
FloatMath.asin(sy),
|
||||
FloatMath.atan2(x*y + z*w, 0.5f - (y*y + z*z)));
|
||||
} else {
|
||||
// not a unique solution; x + z = atan2(-m21, m11)
|
||||
return result.set(0f,
|
||||
-MathUtil.HALF_PI,
|
||||
FloatMath.atan2(x*w - y*z, 0.5f - (x*x + z*z)));
|
||||
}
|
||||
} else {
|
||||
// not a unique solution; x - z = atan2(-m21, m11)
|
||||
return result.set(0f,
|
||||
MathUtil.HALF_PI,
|
||||
-FloatMath.atan2(x*w - y*z, 0.5f - (x*x + z*z)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Vector3 toAngles () {
|
||||
return toAngles(new Vector3());
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Quaternion normalize () {
|
||||
return normalize(new Quaternion());
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Quaternion normalize (Quaternion result) {
|
||||
float rlen = 1f / FloatMath.sqrt(x*x + y*y + z*z + w*w);
|
||||
return result.set(x*rlen, y*rlen, z*rlen, w*rlen);
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Quaternion invert () {
|
||||
return invert(new Quaternion());
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Quaternion invert (Quaternion result) {
|
||||
return result.set(-x, -y, -z, w);
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Quaternion mult (IQuaternion other) {
|
||||
return mult(other, new Quaternion());
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Quaternion mult (IQuaternion other, Quaternion result) {
|
||||
float ox = other.x(), oy = other.y(), oz = other.z(), ow = other.w();
|
||||
return result.set(w*ox + x*ow + y*oz - z*oy,
|
||||
w*oy + y*ow + z*ox - x*oz,
|
||||
w*oz + z*ow + x*oy - y*ox,
|
||||
w*ow - x*ox - y*oy - z*oz);
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Quaternion slerp (IQuaternion other, float t) {
|
||||
return slerp(other, t, new Quaternion());
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Quaternion slerp (IQuaternion other, float t, Quaternion result) {
|
||||
float ox = other.x(), oy = other.y(), oz = other.z(), ow = other.w();
|
||||
float cosa = x*ox + y*oy + z*oz + w*ow, s0, s1;
|
||||
|
||||
// adjust signs if necessary
|
||||
if (cosa < 0f) {
|
||||
cosa = -cosa;
|
||||
ox = -ox;
|
||||
oy = -oy;
|
||||
oz = -oz;
|
||||
ow = -ow;
|
||||
}
|
||||
|
||||
// calculate coefficients; if the angle is too close to zero, we must fall back
|
||||
// to linear interpolation
|
||||
if ((1f - cosa) > MathUtil.EPSILON) {
|
||||
float angle = FloatMath.acos(cosa), sina = FloatMath.sin(angle);
|
||||
s0 = FloatMath.sin((1f - t) * angle) / sina;
|
||||
s1 = FloatMath.sin(t * angle) / sina;
|
||||
} else {
|
||||
s0 = 1f - t;
|
||||
s1 = t;
|
||||
}
|
||||
|
||||
return result.set(s0*x + s1*ox, s0*y + s1*oy, s0*z + s1*oz, s0*w + s1*ow);
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Vector3 transform (IVector3 vector) {
|
||||
return transform(vector, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Vector3 transform (IVector3 vector, Vector3 result) {
|
||||
float xx = x*x, yy = y*y, zz = z*z;
|
||||
float xy = x*y, xz = x*z, xw = x*w;
|
||||
float yz = y*z, yw = y*w, zw = z*w;
|
||||
float vx = vector.x(), vy = vector.y(), vz = vector.z();
|
||||
float vx2 = vx*2f, vy2 = vy*2f, vz2 = vz*2f;
|
||||
return result.set(vx + vy2*(xy - zw) + vz2*(xz + yw) - vx2*(yy + zz),
|
||||
vy + vx2*(xy + zw) + vz2*(yz - xw) - vy2*(xx + zz),
|
||||
vz + vx2*(xz - yw) + vy2*(yz + xw) - vz2*(xx + yy));
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Vector3 transformUnitX (Vector3 result) {
|
||||
return result.set(1f - 2f*(y*y + z*z), 2f*(x*y + z*w), 2f*(x*z - y*w));
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Vector3 transformUnitY (Vector3 result) {
|
||||
return result.set(2f*(x*y - z*w), 1f - 2f*(x*x + z*z), 2f*(y*z + x*w));
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Vector3 transformUnitZ (Vector3 result) {
|
||||
return result.set(2f*(x*z + y*w), 2f*(y*z - x*w), 1f - 2f*(x*x + y*y));
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Vector3 transformAndAdd (IVector3 vector, IVector3 add, Vector3 result) {
|
||||
float xx = x*x, yy = y*y, zz = z*z;
|
||||
float xy = x*y, xz = x*z, xw = x*w;
|
||||
float yz = y*z, yw = y*w, zw = z*w;
|
||||
float vx = vector.x(), vy = vector.y(), vz = vector.z();
|
||||
float vx2 = vx*2f, vy2 = vy*2f, vz2 = vz*2f;
|
||||
return result.set(vx + vy2*(xy - zw) + vz2*(xz + yw) - vx2*(yy + zz) + add.x(),
|
||||
vy + vx2*(xy + zw) + vz2*(yz - xw) - vy2*(xx + zz) + add.y(),
|
||||
vz + vx2*(xz - yw) + vy2*(yz + xw) - vz2*(xx + yy) + add.z());
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Vector3 transformScaleAndAdd (IVector3 vector, float scale, IVector3 add,
|
||||
Vector3 result) {
|
||||
float xx = x*x, yy = y*y, zz = z*z;
|
||||
float xy = x*y, xz = x*z, xw = x*w;
|
||||
float yz = y*z, yw = y*w, zw = z*w;
|
||||
float vx = vector.x(), vy = vector.y(), vz = vector.z();
|
||||
float vx2 = vx*2f, vy2 = vy*2f, vz2 = vz*2f;
|
||||
return result.set(
|
||||
(vx + vy2*(xy - zw) + vz2*(xz + yw) - vx2*(yy + zz)) * scale + add.x(),
|
||||
(vy + vx2*(xy + zw) + vz2*(yz - xw) - vy2*(xx + zz)) * scale + add.y(),
|
||||
(vz + vx2*(xz - yw) + vy2*(yz + xw) - vz2*(xx + yy)) * scale + add.z());
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public float transformZ (IVector3 vector) {
|
||||
return vector.z() + vector.x()*2f*(x*z - y*w) +
|
||||
vector.y()*2f*(y*z + x*w) - vector.z()*2f*(x*x + y*y);
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public float getRotationZ () {
|
||||
return FloatMath.atan2(2f*(x*y + z*w), 1f - 2f*(y*y + z*z));
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Quaternion integrate (IVector3 velocity, float t) {
|
||||
return integrate(velocity, t, new Quaternion());
|
||||
}
|
||||
|
||||
@Override // from IQuaternion
|
||||
public Quaternion integrate (IVector3 velocity, float t, Quaternion result) {
|
||||
// TODO: use Runge-Kutta integration?
|
||||
float qx = 0.5f * velocity.x();
|
||||
float qy = 0.5f * velocity.y();
|
||||
float qz = 0.5f * velocity.z();
|
||||
return result.set(x + t*(qx*w + qy*z - qz*y),
|
||||
y + t*(qy*w + qz*x - qx*z),
|
||||
z + t*(qz*w + qx*y - qy*x),
|
||||
w + t*(-qx*x - qy*y - qz*z)).normalizeLocal();
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public String toString () {
|
||||
return "[" + x + ", " + y + ", " + z + ", " + w + "]";
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public int hashCode () {
|
||||
return Platform.hashCode(x) ^ Platform.hashCode(y) ^ Platform.hashCode(z) ^
|
||||
Platform.hashCode(w);
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public boolean equals (Object other) {
|
||||
if (!(other instanceof Quaternion)) {
|
||||
return false;
|
||||
}
|
||||
Quaternion oquat = (Quaternion)other;
|
||||
return (x == oquat.x && y == oquat.y && z == oquat.z && w == oquat.w) ||
|
||||
(x == -oquat.x && y == -oquat.y && z == -oquat.z && w == -oquat.x);
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,14 @@
|
||||
package pythagoras.f;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import pythagoras.util.Platform;
|
||||
|
||||
/**
|
||||
* A three element vector.
|
||||
*/
|
||||
public class Vector3 extends AbstractVector3 implements Serializable
|
||||
public class Vector3 implements IVector3, Serializable
|
||||
{
|
||||
/** A unit vector in the X+ direction. */
|
||||
public static final IVector3 UNIT_X = new Vector3(1f, 0f, 0f);
|
||||
@@ -189,18 +192,206 @@ public class Vector3 extends AbstractVector3 implements Serializable
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override // from AbstractVector3
|
||||
@Override // from IVector3
|
||||
public float x () {
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override // from AbstractVector3
|
||||
@Override // from IVector3
|
||||
public float y () {
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override // from AbstractVector3
|
||||
@Override // from IVector3
|
||||
public float z () {
|
||||
return z;
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public float dot (IVector3 other) {
|
||||
return x*other.x() + y*other.y() + z*other.z();
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 cross (IVector3 other) {
|
||||
return cross(other, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 cross (IVector3 other, Vector3 result) {
|
||||
float x = this.x, y = this.y, z = this.z;
|
||||
float ox = other.x(), oy = other.y(), oz = other.z();
|
||||
return result.set(y*oz - z*oy, z*ox - x*oz, x*oy - y*ox);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public float triple (IVector3 b, IVector3 c) {
|
||||
float bx = b.x(), by = b.y(), bz = b.z();
|
||||
float cx = c.x(), cy = c.y(), cz = c.z();
|
||||
return x()*(by*cz - bz*cy) + y()*(bz*cx - bx*cz) + z()*(bx*cy - by*cx);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 negate () {
|
||||
return negate(new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 negate (Vector3 result) {
|
||||
return result.set(-x, -y, -z);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 normalize () {
|
||||
return normalize(new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 normalize (Vector3 result) {
|
||||
return mult(1f / length(), result);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public float angle (IVector3 other) {
|
||||
return FloatMath.acos(dot(other) / (length() * other.length()));
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public float length () {
|
||||
return FloatMath.sqrt(lengthSquared());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public float lengthSquared () {
|
||||
float x = this.x, y = this.y, z = this.z;
|
||||
return (x*x + y*y + z*z);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public float distance (IVector3 other) {
|
||||
return FloatMath.sqrt(distanceSquared(other));
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public float distanceSquared (IVector3 other) {
|
||||
float dx = x - other.x(), dy = y - other.y(), dz = z - other.z();
|
||||
return dx*dx + dy*dy + dz*dz;
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public float manhattanDistance (IVector3 other) {
|
||||
return Math.abs(x - other.x()) + Math.abs(y - other.y()) + Math.abs(z - other.z());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 mult (float v) {
|
||||
return mult(v, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 mult (float v, Vector3 result) {
|
||||
return result.set(x*v, y*v, z*v);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 mult (IVector3 other) {
|
||||
return mult(other, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 mult (IVector3 other, Vector3 result) {
|
||||
return result.set(x*other.x(), y*other.y(), z*other.z());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 add (IVector3 other) {
|
||||
return add(other, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 add (IVector3 other, Vector3 result) {
|
||||
return add(other.x(), other.y(), other.z(), result);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 subtract (IVector3 other) {
|
||||
return subtract(other, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 subtract (IVector3 other, Vector3 result) {
|
||||
return add(-other.x(), -other.y(), -other.z(), result);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 add (float x, float y, float z) {
|
||||
return add(x, y, z, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 add (float x, float y, float z, Vector3 result) {
|
||||
return result.set(this.x + x, this.y + y, this.z + z);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 addScaled (IVector3 other, float v) {
|
||||
return addScaled(other, v, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 addScaled (IVector3 other, float v, Vector3 result) {
|
||||
return result.set(x + other.x()*v, y + other.y()*v, z + other.z()*v);
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 lerp (IVector3 other, float t) {
|
||||
return lerp(other, t, new Vector3());
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public Vector3 lerp (IVector3 other, float t, Vector3 result) {
|
||||
float x = this.x, y = this.y, z = this.z;
|
||||
return result.set(x + t*(other.x() - x), y + t*(other.y() - y), z + t*(other.z() - z));
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public float get (int idx) {
|
||||
switch (idx) {
|
||||
case 0: return x;
|
||||
case 1: return y;
|
||||
case 2: return z;
|
||||
}
|
||||
throw new IndexOutOfBoundsException(String.valueOf(idx));
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public void get (float[] values) {
|
||||
values[0] = x;
|
||||
values[1] = y;
|
||||
values[2] = z;
|
||||
}
|
||||
|
||||
@Override // from interface IVector3
|
||||
public FloatBuffer get (FloatBuffer buf) {
|
||||
return buf.put(x).put(y).put(z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString () {
|
||||
return "[" + x + ", " + y + ", " + z + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode () {
|
||||
return Platform.hashCode(x) ^ Platform.hashCode(y) ^ Platform.hashCode(z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals (Object other) {
|
||||
if (!(other instanceof Vector3)) {
|
||||
return false;
|
||||
}
|
||||
Vector3 ovec = (Vector3)other;
|
||||
return (x == ovec.x && y == ovec.y && z == ovec.z);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
//
|
||||
// Pythagoras - a collection of geometry classes
|
||||
// http://github.com/samskivert/pythagoras
|
||||
|
||||
package pythagoras.f;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import pythagoras.util.Platform;
|
||||
|
||||
/**
|
||||
* A four element vector.
|
||||
*/
|
||||
public class Vector4 implements IVector4, Serializable
|
||||
{
|
||||
/** The components of the vector. */
|
||||
public float x, y, z, w;
|
||||
|
||||
/**
|
||||
* Creates a vector from four components.
|
||||
*/
|
||||
public Vector4 (float x, float y, float z, float w)
|
||||
{
|
||||
set(x, y, z, w);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a vector from four components.
|
||||
*/
|
||||
public Vector4 (float[] values) {
|
||||
set(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a vector from a float buffer.
|
||||
*/
|
||||
public Vector4 (FloatBuffer buf) {
|
||||
set(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*/
|
||||
public Vector4 (IVector4 other) {
|
||||
set(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a zero vector.
|
||||
*/
|
||||
public Vector4 () {
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the elements of another vector.
|
||||
*
|
||||
* @return a reference to this vector, for chaining.
|
||||
*/
|
||||
public Vector4 set (IVector4 other) {
|
||||
return set(other.x(), other.y(), other.z(), other.w());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all of the elements of the vector.
|
||||
*
|
||||
* @return a reference to this vector, for chaining.
|
||||
*/
|
||||
public Vector4 set (float[] values) {
|
||||
return set(values[0], values[1], values[2], values[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all of the elements of the vector.
|
||||
*
|
||||
* @return a reference to this vector, for chaining.
|
||||
*/
|
||||
public Vector4 set (FloatBuffer buf) {
|
||||
return set(buf.get(), buf.get(), buf.get(), buf.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all of the elements of the vector.
|
||||
*
|
||||
* @return a reference to this vector, for chaining.
|
||||
*/
|
||||
public Vector4 set (float x, float y, float z, float w) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.w = w;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override // from IVector4
|
||||
public float x () {
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override // from IVector4
|
||||
public float y () {
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override // from IVector4
|
||||
public float z () {
|
||||
return z;
|
||||
}
|
||||
|
||||
@Override // from IVector4
|
||||
public float w () {
|
||||
return w;
|
||||
}
|
||||
|
||||
@Override // from IVector4
|
||||
public FloatBuffer get (FloatBuffer buf) {
|
||||
return buf.put(x).put(y).put(z).put(w);
|
||||
}
|
||||
|
||||
@Override // from IVector4
|
||||
public boolean epsilonEquals (IVector4 other, float epsilon) {
|
||||
return (Math.abs(x - other.x()) < epsilon &&
|
||||
Math.abs(y - other.y()) < epsilon &&
|
||||
Math.abs(z - other.z()) < epsilon &&
|
||||
Math.abs(w - other.w()) < epsilon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString () {
|
||||
return "[" + x + ", " + y + ", " + z + ", " + w + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode () {
|
||||
return Platform.hashCode(x) ^ Platform.hashCode(y) ^ Platform.hashCode(z) ^
|
||||
Platform.hashCode(w);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals (Object other) {
|
||||
if (!(other instanceof Vector4)) {
|
||||
return false;
|
||||
}
|
||||
Vector4 ovec = (Vector4)other;
|
||||
return (x == ovec.x && y == ovec.y && z == ovec.z && w == ovec.w);
|
||||
}
|
||||
}
|
||||
@@ -338,8 +338,8 @@ public class TransformTest
|
||||
}
|
||||
|
||||
protected void assertPointsEqual (String desc, Point p1, Point p2) {
|
||||
if (Math.abs(p1.x - p2.x) > FloatMath.EPSILON ||
|
||||
Math.abs(p1.y - p2.y) > FloatMath.EPSILON) {
|
||||
if (Math.abs(p1.x - p2.x) > MathUtil.EPSILON ||
|
||||
Math.abs(p1.y - p2.y) > MathUtil.EPSILON) {
|
||||
fail(desc + " want " + p1 + " got " + p2);
|
||||
}
|
||||
}
|
||||
@@ -357,8 +357,8 @@ public class TransformTest
|
||||
}
|
||||
|
||||
protected void assertVectorsEqual (String desc, Vector v1, Vector v2) {
|
||||
if (Math.abs(v1.x - v2.x) > FloatMath.EPSILON ||
|
||||
Math.abs(v1.y - v2.y) > FloatMath.EPSILON) {
|
||||
if (Math.abs(v1.x - v2.x) > MathUtil.EPSILON ||
|
||||
Math.abs(v1.y - v2.y) > MathUtil.EPSILON) {
|
||||
fail(desc + " want " + v1 + " got " + v2);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user