package mikera.matrixx;
import mikera.matrixx.impl.APrimitiveMatrix;
import mikera.transformz.marker.ISpecialisedTransform;
import mikera.vectorz.AVector;
import mikera.vectorz.Vector;
import mikera.vectorz.Vector2;
import mikera.vectorz.util.ErrorMessages;
/**
* Specialised 2*2 Matrix for Vector2 maths, using primitive matrix elements
*
* @author Mike
*
*/
public final class Matrix22 extends APrimitiveMatrix implements ISpecialisedTransform {
private static final long serialVersionUID = 2696617102233017028L;
public double m00,m01,
m10,m11;
public Matrix22() {
}
public Matrix22(Matrix22 source) {
Matrix22 s=source;
m00=s.m00; m01=s.m01;
m10=s.m10; m11=s.m11;
}
public Matrix22(double m00, double m01, double m10, double m11) {
this.m00=m00;
this.m01=m01;
this.m10=m10;
this.m11=m11;
}
public Matrix22(AMatrix m) {
if (m instanceof Matrix22) {
set((Matrix22) m);
} else {
unsafeSet(m);
}
}
public void set(Matrix22 a) {
m00=a.m00; m01=a.m01;
m10=a.m10; m11=a.m11;
}
@Override
public void set(AMatrix m) {
m.checkShape(2, 2);
m00=m.unsafeGet(0,0);
m01=m.unsafeGet(0,1);
m10=m.unsafeGet(1,0);
m11=m.unsafeGet(1,1);
}
public void unsafeSet(AMatrix m) {
m00=m.unsafeGet(0,0);
m01=m.unsafeGet(0,1);
m10=m.unsafeGet(1,0);
m11=m.unsafeGet(1,1);
}
public static Matrix22 create(double a, double b, double c, double d) {
return new Matrix22(a,b,c,d);
}
public static Matrix22 createRotationMatrix(double angle) {
double sa=Math.sin(angle);
double ca=Math.cos(angle);
return new Matrix22(
ca,-sa,
sa,ca);
}
public static Matrix22 createScaleMatrix(double d) {
return new Matrix22(d,0,0,d);
}
/**
* Creates a new mutable 2D identity matrix
* @return
*/
public static Matrix22 createIdentity() {
return new Matrix22(1,0,0,1);
}
public static Matrix22 createReflectionMatrix(AVector normal) {
return createReflectionMatrix(Vector2.create(normal));
}
public static Matrix22 createReflectionMatrix(Vector2 normal) {
double x=normal.x, y=normal.y;
double ca=x*x-y*y;
double sa=2*x*y;
return new Matrix22(ca, sa, sa, -ca);
}
@Override
public void multiply(double factor) {
m00*=factor; m01*=factor;
m10*=factor; m11*=factor;
}
@Override
public double determinant() {
return (m00*m11)-(m01*m10);
}
@Override
public long elementCount() {
return 4;
}
@Override
public double elementSum() {
return m00+m01+m10+m11;
}
@Override
public double elementMin() {
return Math.min(Math.min(m00, m01), Math.min(m10, m11));
}
@Override
public double elementMax() {
return Math.max(Math.max(m00, m01), Math.max(m10, m11));
}
@Override
public double trace() {
return m00+m11;
}
@Override
public Matrix22 inverse() {
double det=determinant();
if (det==0.0) return null;
double invDet=1.0/det;
return new Matrix22( invDet*m11, -invDet*m01,
-invDet*m10, invDet*m00);
}
@Override
public int rowCount() {
return 2;
}
@Override
public int columnCount() {
return 2;
}
@Override
public int checkSquare() {
return 2;
}
@Override
public void add(AMatrix a) {
if (a instanceof Matrix22) {
add((Matrix22)a); return;
}
a.checkShape(2, 2);
m00+=a.unsafeGet(0, 0);
m01+=a.unsafeGet(0, 1);
m10+=a.unsafeGet(1, 0);
m11+=a.unsafeGet(1, 1);
}
public void add(Matrix22 a) {
m00+=a.m00;
m01+=a.m01;
m10+=a.m10;
m11+=a.m11;
}
public void sub(Matrix22 a) {
m00-=a.m00;
m01-=a.m01;
m10-=a.m10;
m11-=a.m11;
}
@Override
public Vector2 getRowClone(int row) {
switch (row) {
case 0: return Vector2.of(m00,m01);
case 1: return Vector2.of(m10,m11);
default: throw new IndexOutOfBoundsException("Row index = "+row);
}
}
@Override
public Vector2 getColumnClone(int column) {
switch (column) {
case 0: return Vector2.of(m00,m10);
case 1: return Vector2.of(m01,m11);
default: throw new IndexOutOfBoundsException("Column index = "+column);
}
}
@Override
public void copyRowTo(int row, double[] dest, int destOffset) {
if (row==0) {
dest[destOffset++]=m00;
dest[destOffset++]=m01;
} else {
dest[destOffset++]=m10;
dest[destOffset++]=m11;
}
}
@Override
public double get(int row, int column) {
switch (row) {
case 0:
switch (column) {
case 0: return m00;
case 1: return m01;
default: throw new IndexOutOfBoundsException(ErrorMessages.invalidIndex(this, row,column));
}
case 1:
switch (column) {
case 0: return m10;
case 1: return m11;
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;
default: throw new IndexOutOfBoundsException(ErrorMessages.invalidIndex(this, row,column));
}
case 1:
switch (column) {
case 0: m10=value; return;
case 1: m11=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 Matrix22) {
return innerProduct((Matrix22)a);
}
return super.innerProduct(a);
}
@Override
public AVector innerProduct(AVector a) {
if (a instanceof Vector2) {
return innerProduct((Vector2)a);
}
return super.innerProduct(a);
}
public Vector2 innerProduct(Vector2 a) {
return transform(a);
}
public Matrix22 innerProduct(Matrix22 a) {
Matrix22 r=new Matrix22();
r.m00=m00*a.m00+m01*a.m10;
r.m01=m00*a.m01+m01*a.m11;
r.m10=m10*a.m00+m11*a.m10;
r.m11=m10*a.m01+m11*a.m11;
return r;
}
@Override
public void transform(AVector source, AVector dest) {
if (source instanceof Vector2) {transform((Vector2)source,dest); return;}
super.transform(source,dest);
}
public void transform(Vector2 source, AVector dest) {
if (dest instanceof Vector2) {transform(source,(Vector2)dest); return;}
Vector2 s=source;
dest.set(0,(m00*s.x)+(m01*s.y));
dest.set(1,(m10*s.x)+(m11*s.y));
}
public void transform(Vector2 source, Vector2 dest) {
Vector2 s=source;
dest.x=((m00*s.x)+(m01*s.y));
dest.y=((m10*s.x)+(m11*s.y));
}
public Vector2 transform(Vector2 source) {
Vector2 s=source;
Vector2 result=new Vector2(
((m00*s.x)+(m01*s.y)),
((m10*s.x)+(m11*s.y)));
return result;
}
public void transformInPlace(Vector2 dest) {
Vector2 s=dest;
double tx=((m00*s.x)+(m01*s.y));
double ty=((m10*s.x)+(m11*s.y));
s.x=tx; s.y=ty;
}
@Override
public boolean isSymmetric() {
return m01==m10;
}
@Override
public Vector toVector() {
return Vector.of(m00,m01,m10,m11);
}
@Override
public Matrix22 getTranspose() {
return new Matrix22(m00,m10,
m01,m11);
}
@Override
public void getElements(double[] data, int offset) {
data[offset++]=m00;
data[offset++]=m01;
data[offset++]=m10;
data[offset++]=m11;
}
@Override
public boolean equals(Object o) {
if (o instanceof Matrix22) {
return equals((Matrix22)o);
}
return super.equals(o);
}
public boolean equals(Matrix22 m) {
return
(m00==m.m00) &&
(m01==m.m01) &&
(m10==m.m10) &&
(m11==m.m11);
}
@Override
public Matrix22 clone() {
return new Matrix22(this);
}
@Override
public Matrix22 exactClone() {
return new Matrix22(this);
}
@Override
public double[] toDoubleArray() {
return new double[] {m00,m01,m10,m11};
}
}