package mikera.vectorz;
import java.nio.DoubleBuffer;
import java.util.Arrays;
import mikera.vectorz.impl.APrimitiveVector;
import mikera.vectorz.util.ErrorMessages;
/**
* Specialised 2D vector
*
* @author Mike
*/
public final class Vector2 extends APrimitiveVector {
private static final long serialVersionUID = -7815583836324137277L;
public double x;
public double y;
public Vector2() {
super();
}
public Vector2(double x, double y) {
this.x=x;
this.y=y;
}
public static Vector2 of(double x, double y) {
return new Vector2(x,y);
}
public static Vector2 of(double... values) {
if (values.length!=2) throw new IllegalArgumentException("Can't create Vector2 vector from: "+Arrays.toString(values));
return new Vector2(values[0],values[1]);
}
public static Vector2 create(AVector v) {
if (v.length()!=2) throw new IllegalArgumentException("Can't create Vector2 from vector with length "+v.length());
return new Vector2(v.unsafeGet(0),v.unsafeGet(1));
}
@Override
public void applyOp(Op op) {
x=op.apply(x);
y=op.apply(y);
}
public void add(Vector2 v) {
x+=v.x;
y+=v.y;
}
public void sub(Vector2 v) {
x-=v.x;
y-=v.y;
}
public void addMultiple(Vector2 v, double factor) {
x+=v.x*factor;
y+=v.y*factor;
}
public void addProduct(Vector2 a, Vector2 b) {
x+=a.x*b.x;
y+=a.y*b.y;
}
public void addProduct(Vector2 a, Vector2 b, double factor) {
x+=a.x*b.x*factor;
y+=a.y*b.y*factor;
}
@Override
public double dotProduct(AVector a) {
a.checkLength(2);
return x*a.unsafeGet(0)+y*a.unsafeGet(1);
}
@Override
public double dotProduct(Vector v) {
v.checkLength(2);
double[] data=v.getArray();
return x*data[0]+y*data[1];
}
@Override
public double dotProduct(double[] data, int offset) {
return x*data[offset+0]+y*data[offset+1];
}
public double dotProduct(Vector2 a) {
return x*a.x+y*a.y;
}
@Override
public void scaleAdd(double factor, double constant) {
x=(x*factor)+constant;
y=(y*factor)+constant;
}
@Override
public void scaleAdd(double factor, AVector constant) {
x=(x*factor)+constant.unsafeGet(0);
y=(y*factor)+constant.unsafeGet(1);
}
public void scaleAdd(double factor, Vector2 constant) {
x=(x*factor)+constant.x;
y=(y*factor)+constant.y;
}
/**
* Complex multiplication by another Vector2, treating an (x,y) vector as the complex value x+iy
* @param a
*/
public void complexMultiply(Vector2 a) {
double nx=x*a.x-y*a.y;
double ny=x*a.y+y*a.x;
this.x=nx;
this.y=ny;
}
public Vector2 complexConjugate() {
return new Vector2(x,-y);
}
public Vector2 complexReciprocal() {
double d=x*x+y*y;
return new Vector2(x/d,-y/d);
}
public Vector2 complexNegation() {
return new Vector2(-x,-y);
}
@Override
public void negate() {
x=-x;
y=-y;
}
@Override
public void add(double constant) {
x=x+constant;
y=y+constant;
}
public void add(double dx, double dy) {
x=x+dx;
y=y+dy;
}
@Override
public void add(AVector v) {
if(v.length()!=2) throw new IllegalArgumentException(ErrorMessages.incompatibleShapes(this, v));
x+=v.unsafeGet(0);
y+=v.unsafeGet(1);
}
@Override
public int length() {
return 2;
}
@Override
public double elementSum() {
return x+y;
}
@Override
public double elementProduct() {
return x*y;
}
@Override
public double elementMax(){
return Math.max(x, y);
}
@Override
public double elementMin(){
return Math.min(x, y);
}
@Override
public double magnitudeSquared() {
return (x*x)+(y*y);
}
@Override
public double magnitude() {
return Math.sqrt(magnitudeSquared());
}
@Override
public double get(int i) {
switch (i) {
case 0: return x;
case 1: return y;
default: throw new IndexOutOfBoundsException(ErrorMessages.invalidIndex(this, i));
}
}
@Override
public double unsafeGet(int i) {
return (i==0)?x:y;
}
@Override
public void getElements(double[] data, int offset) {
data[offset]=x;
data[offset+1]=y;
}
@Override
public void toDoubleBuffer(DoubleBuffer dest) {
dest.put(x);
dest.put(y);
}
@Override
public double[] toDoubleArray() {
return new double[] {x,y};
}
@Override
public Vector2 toNormal() {
double d=this.magnitude();
return (d==0)?new Vector2():new Vector2(x/d,y/d);
}
@Override
public void set(int i, double value) {
switch (i) {
case 0: x=value; return;
case 1: y=value; return;
default: throw new IndexOutOfBoundsException(ErrorMessages.invalidIndex(this, i));
}
}
@Override
public void unsafeSet(int i, double value) {
switch (i) {
case 0: x=value; return;
default: y=value; return;
}
}
@Override
public void fill(double v) {
x=v;
y=v;
}
@Override
public void addAt(int i, double value) {
switch (i) {
case 0: x+=value; return;
default: y+=value; return;
}
}
/**
* Rotates a 2D vector around the origin by a given angle
* @param angle
*/
public void rotateInPlace(int angle) {
double ca=Math.cos(angle);
double sa=Math.sin(angle);
double nx=(x*ca)-(y*sa);
double ny=(x*sa)+(y*ca);
x=nx;
y=ny;
}
public void setValues(double x, double y) {
this.x=x;
this.y=y;
}
@Override
public Vector2 clone() {
return new Vector2(x,y);
}
@Override
public double getX() {
return x;
}
@Override
public double getY() {
return y;
}
@Override
public Vector2 exactClone() {
return clone();
}
@Override
public boolean equals(AVector v) {
if (v instanceof Vector2) {
return equals((Vector2)v);
}
return (v.length()==2)&&(x==v.unsafeGet(0))&&(y==v.unsafeGet(1));
}
public boolean equals(Vector2 v) {
return (x==v.x)&&(y==v.y);
}
}