package mikera.matrixx;
import mikera.matrixx.impl.APrimitiveMatrix;
import mikera.transformz.Affine34;
import mikera.transformz.marker.ISpecialisedTransform;
import mikera.vectorz.AVector;
import mikera.vectorz.Vector3;
import mikera.vectorz.util.ErrorMessages;
/**
* Specialised 3*3 Matrix for Vector3 maths, using primitive matrix elements
*
* @author Mike
*
*/
public final class Matrix33 extends APrimitiveMatrix implements ISpecialisedTransform {
private static final long serialVersionUID = 238200620223028897L;
public double m00,m01,m02,
m10,m11,m12,
m20,m21,m22;
/**
* Create a new (zero-initialised) 3x3 Matrix
*/
public Matrix33() {
}
public Matrix33(Matrix33 source) {
Matrix33 s=source;
m00=s.m00; m01=s.m01; m02=s.m02;
m10=s.m10; m11=s.m11; m12=s.m12;
m20=s.m20; m21=s.m21; m22=s.m22;
}
public Matrix33(double m00, double m01, double m02, double m10,
double m11, double m12, double m20, double m21, double m22) {
this.m00=m00;
this.m01=m01;
this.m02=m02;
this.m10=m10;
this.m11=m11;
this.m12=m12;
this.m20=m20;
this.m21=m21;
this.m22=m22;
}
public Matrix33(AMatrix m) {
m00=m.unsafeGet(0,0);
m01=m.unsafeGet(0,1);
m02=m.unsafeGet(0,2);
m10=m.unsafeGet(1,0);
m11=m.unsafeGet(1,1);
m12=m.unsafeGet(1,2);
m20=m.unsafeGet(2,0);
m21=m.unsafeGet(2,1);
m22=m.unsafeGet(2,2);
}
@Override
public double determinant() {
return (m00*m11*m22)+(m01*m12*m20)+(m02*m10*m21)
-(m00*m12*m21)-(m01*m10*m22)-(m02*m11*m20);
}
@Override
public long elementCount() {
return 9;
}
@Override
public void multiply(double factor) {
m00*=factor; m01*=factor; m02*=factor;
m10*=factor; m11*=factor; m12*=factor;
m20*=factor; m21*=factor; m22*=factor;
}
@Override
public int rowCount() {
return 3;
}
@Override
public int columnCount() {
return 3;
}
@Override
public int checkSquare() {
return 3;
}
@Override
public double get(int row, int column) {
switch (row) {
case 0:
switch (column) {
case 0: return m00;
case 1: return m01;
case 2: return m02;
default: throw new IndexOutOfBoundsException(ErrorMessages.invalidIndex(this, row,column));
}
case 1:
switch (column) {
case 0: return m10;
case 1: return m11;
case 2: return m12;
default: throw new IndexOutOfBoundsException(ErrorMessages.invalidIndex(this, row,column));
}
case 2:
switch (column) {
case 0: return m20;
case 1: return m21;
case 2: return m22;
default: throw new IndexOutOfBoundsException(ErrorMessages.invalidIndex(this, row,column));
}
default: throw new IndexOutOfBoundsException(ErrorMessages.invalidIndex(this, row,column));
}
}
@Override
public void set(int row, int column, double value) {
switch (row) {
case 0:
switch (column) {
case 0: m00=value; return;
case 1: m01=value; return;
case 2: m02=value; return;
default: throw new IndexOutOfBoundsException(ErrorMessages.invalidIndex(this, row,column));
}
case 1:
switch (column) {
case 0: m10=value; return;
case 1: m11=value; return;
case 2: m12=value; return;
default: throw new IndexOutOfBoundsException(ErrorMessages.invalidIndex(this, row,column));
}
case 2:
switch (column) {
case 0: m20=value; return;
case 1: m21=value; return;
case 2: m22=value; return;
default: throw new IndexOutOfBoundsException(ErrorMessages.invalidIndex(this, row,column));
}
default: throw new IndexOutOfBoundsException(ErrorMessages.invalidIndex(this, row,column));
}
}
@Override
public AMatrix innerProduct(AMatrix a) {
if (a instanceof Matrix33) {
return innerProduct((Matrix33)a);
}
return super.innerProduct(a);
}
@Override
public AVector innerProduct(AVector a) {
if (a instanceof Vector3) {
return innerProduct((Vector3)a);
}
return super.innerProduct(a);
}
public Vector3 innerProduct(Vector3 a) {
return transform(a);
}
public Matrix33 innerProduct(Matrix33 a) {
Matrix33 r=new Matrix33();
for (int i=0; i<3; i++) {
for (int j=0; j<3; j++) {
double acc=0.0;
for (int k=0; k<3; k++) {
acc+=this.unsafeGet(i, k)*a.unsafeGet(k, j);
}
r.set(i,j,acc);
}
}
return r;
}
@Override
public void transform(AVector source, AVector dest) {
if (source instanceof Vector3) {transform((Vector3)source,dest); return;}
super.transform(source,dest);
}
public void transform(Vector3 source, AVector dest) {
if (dest instanceof Vector3) {transform(source,(Vector3)dest); return;}
if (dest.length()!=3) throw new IllegalArgumentException(ErrorMessages.mismatch(source,dest));
Vector3 s=source;
dest.unsafeSet(0,(m00*s.x)+(m01*s.y)+(m02*s.z));
dest.unsafeSet(1,(m10*s.x)+(m11*s.y)+(m12*s.z));
dest.unsafeSet(2,(m20*s.x)+(m21*s.y)+(m22*s.z));
}
public void transform(Vector3 source, Vector3 dest) {
double x=source.x, y=source.y, z=source.z;
dest.x=((m00*x)+(m01*y)+(m02*z));
dest.y=((m10*x)+(m11*y)+(m12*z));
dest.z=((m20*x)+(m21*y)+(m22*z));
}
public void transformNormal(AVector source, AVector dest) {
if ((source instanceof Vector3)&&(dest instanceof Vector3)) {
transformNormal((Vector3)source,(Vector3)dest);
return;
}
transform(source, dest);
dest.normalise();
}
public void transformNormal(Vector3 source, Vector3 dest) {
transform(source,dest);
dest.normalise();
}
public Vector3 transform(Vector3 source) {
Vector3 s=source;
Vector3 result=new Vector3(
((m00*s.x)+(m01*s.y)+(m02*s.z)),
((m10*s.x)+(m11*s.y)+(m12*s.z)),
((m20*s.x)+(m21*s.y)+(m22*s.z))
);
return result;
}
@Override
public void transformInPlace(AVector dest) {
if (dest instanceof Vector3) {
transformInPlace((Vector3)dest);
return;
}
if (dest.length()!=3) throw new IllegalArgumentException("Wrong target vector length");
double sx=dest.unsafeGet(0), sy=dest.unsafeGet(1), sz=dest.unsafeGet(2);
double tx=((m00*sx)+(m01*sy)+(m02*sz));
double ty=((m10*sx)+(m11*sy)+(m12*sz));
double tz=((m20*sx)+(m21*sy)+(m22*sz));
dest.set(0,tx);
dest.set(1,ty);
dest.set(2,tz);
}
public void transformInPlace(Vector3 dest) {
Vector3 s=dest;
double tx=((m00*s.x)+(m01*s.y)+(m02*s.z));
double ty=((m10*s.x)+(m11*s.y)+(m12*s.z));
double tz=((m20*s.x)+(m21*s.y)+(m22*s.z));
s.x=tx; s.y=ty; s.z=tz;
}
@Override
public boolean isSymmetric() {
return (m01==m10)&&(m20==m02)&&(m21==m12);
}
@Override
public Affine34 toAffineTransform() {
return new Affine34(m00,m01,m02,0.0,
m10,m11,m12,0.0,
m20,m21,m22,0.0);
}
@Override
public Matrix33 getTranspose() {
return new Matrix33(m00,m10,m20,
m01,m11,m21,
m02,m12,m22);
}
/**
* Returns a row of the matrix as a cloned vector
*/
@Override
public Vector3 getRowClone(int row) {
switch (row) {
case 0: return Vector3.of(m00,m01,m02);
case 1: return Vector3.of(m10,m11,m12);
case 2: return Vector3.of(m20,m21,m22);
default: throw new IndexOutOfBoundsException("Row index = "+row);
}
}
@Override
public void copyRowTo(int row, double[] dest, int destOffset) {
if (row==0) {
dest[destOffset++]=m00;
dest[destOffset++]=m01;
dest[destOffset++]=m02;
} else if (row==1) {
dest[destOffset++]=m10;
dest[destOffset++]=m11;
dest[destOffset++]=m12;
} else {
dest[destOffset++]=m20;
dest[destOffset++]=m21;
dest[destOffset++]=m22;
}
}
@Override
public Matrix33 inverse() {
double det=determinant();
if (det==0.0) return null;
double invDet=1.0/det;
return new Matrix33(
invDet*((m11*m22-m12*m21)),
invDet*((m02*m21-m01*m22)),
invDet*((m01*m12-m02*m11)),
invDet*((m12*m20-m10*m22)),
invDet*((m00*m22-m02*m20)),
invDet*((m02*m10-m00*m12)),
invDet*((m10*m21-m11*m20)),
invDet*((m01*m20-m00*m21)),
invDet*((m00*m11-m01*m10)));
}
@Override
public double trace() {
return m00+m11+m22;
}
@Override
public double diagonalProduct() {
return m00*m11*m22;
}
@Override
public Matrix33 clone() {
return new Matrix33(this);
}
@Override
public double[] toDoubleArray() {
return new double[] {m00,m01,m02,m10,m11,m12,m20,m21,m22};
}
@Override
public Matrix33 exactClone() {
return new Matrix33(this);
}
@Override
public void getElements(double[] data, int offset) {
data[offset++]=m00;
data[offset++]=m01;
data[offset++]=m02;
data[offset++]=m10;
data[offset++]=m11;
data[offset++]=m12;
data[offset++]=m20;
data[offset++]=m21;
data[offset++]=m22;
}
@Override
public boolean equals(Object o) {
if (o instanceof Matrix33) {
return equals((Matrix33)o);
}
return super.equals(o);
}
public boolean equals(Matrix33 m) {
return
(m00==m.m00) &&
(m01==m.m01) &&
(m02==m.m02) &&
(m10==m.m10) &&
(m11==m.m11) &&
(m12==m.m12) &&
(m20==m.m20) &&
(m21==m.m21) &&
(m22==m.m22);
}
public static Matrix33 createIdentityMatrix() {
return new Matrix33(
1.0,0.0,0.0,
0.0,1.0,0.0,
0.0,0.0,1.0);
}
public static Matrix33 createScaleMatrix(double d) {
return new Matrix33(d,0,0,0,d,0,0,0,d);
}
}