package mikera.vectorz;
import java.nio.DoubleBuffer;
import mikera.vectorz.impl.APrimitiveVector;
import mikera.vectorz.util.ErrorMessages;
/**
* Specialised 3D vector
*
* Represents a point in 3D x,y,z space.
*
* @author Mike
*/
public final class Vector3 extends APrimitiveVector {
private static final long serialVersionUID = 2338611313487869443L;
public double x;
public double y;
public double z;
public Vector3() {
super();
}
public Vector3(Vector3 source) {
this.x=source.x;
this.y=source.y;
this.z=source.z;
}
public Vector3(double x, double y, double z) {
this.x=x;
this.y=y;
this.z=z;
}
@Override
public void applyOp(Op op) {
x=op.apply(x);
y=op.apply(y);
z=op.apply(z);
}
@Override
public double normalise() {
double d=magnitude();
if (d>0) multiply(1.0/d);
return d;
}
public Vector3(double... values) {
if (values.length!=length()) throw new IllegalArgumentException("Can't create "+length()+"D vector from values with length: "+values.length);
this.x=values[0];
this.y=values[1];
this.z=values[2];
}
public Vector3(AVector v) {
assert(v.length()==3);
this.set(v);
}
public static Vector3 of(double x, double y, double z) {
return new Vector3(x,y,z);
}
public static Vector3 of(double... values) {
return new Vector3(values);
}
public static Vector3 create(Object o) {
return create(Vectorz.create(o));
}
public static Vector3 create(AVector v) {
return new Vector3(v);
}
@Override
public double angle(AVector v) {
if (v instanceof Vector3) {return angle((Vector3)v);}
return super.angle(v);
}
public double angle(Vector3 v) {
double mag2=(x*x)+(y*y)+(z*z);
double vmag2=(v.x*v.x)+(v.y*v.y)+(v.z*v.z);
double dot=(x*v.x)+(y*v.y)+(z*v.z);
return Math.acos(dot/Math.sqrt(mag2*vmag2));
}
public void add(double dx, double dy, double dz) {
x+=dx;
y+=dy;
z+=dz;
}
@Override
public double magnitudeSquared() {
return (x*x)+(y*y)+(z*z);
}
public double distanceSquared(Vector3 v) {
double dx=x-v.x, dy=y-v.y, dz=z-v.z;
return (dx*dx)+(dy*dy)+(dz*dz);
}
public double distance(Vector3 v) {
return Math.sqrt(distanceSquared(v));
}
public double distance(AVector v) {
if (v instanceof Vector3) {
return distance((Vector3)v);
}
return super.distance(v);
}
@Override
public double magnitude() {
return Math.sqrt(magnitudeSquared());
}
public void set(Vector3 a) {
this.x=a.x;
this.y=a.y;
this.z=a.z;
}
@Override
public void multiply(double d){
x*=d;
y*=d;
z*=d;
}
@Override
public Vector3 multiplyCopy(double d){
return new Vector3(x*d,y*d,z*d);
}
public void addMultiple(double dx, double dy, double dz, double factor) {
x+=dx*factor;
y+=dy*factor;
z+=dz*factor;
}
@Override
public void addMultiple(AVector v, double factor) {
if (v instanceof Vector3) {
addMultiple((Vector3)v,factor);
} else {
x+=v.unsafeGet(0)*factor;
y+=v.unsafeGet(1)*factor;
z+=v.unsafeGet(2)*factor;
}
}
public void addMultiple(Vector3 v, double factor) {
x+=v.x*factor;
y+=v.y*factor;
z+=v.z*factor;
}
public void addProduct(Vector3 a, Vector3 b) {
x+=a.x*b.x;
y+=a.y*b.y;
z+=a.z*b.z;
}
public void addProduct(Vector3 a, Vector3 b, double factor) {
x+=a.x*b.x*factor;
y+=a.y*b.y*factor;
z+=a.z*b.z*factor;
}
public void subtractMultiple(Vector3 v, double factor) {
x-=v.x*factor;
y-=v.y*factor;
z-=v.z*factor;
}
@Override
public void add(AVector v) {
if (v instanceof Vector3) {
add((Vector3)v);
} else {
x+=v.unsafeGet(0);
y+=v.unsafeGet(1);
z+=v.unsafeGet(2);
}
}
@Override
public Vector3 addCopy(AVector v) {
if (v instanceof Vector3) return addCopy((Vector3)v);
if (v.length()!=3) throw new IllegalArgumentException(ErrorMessages.incompatibleShapes(this, v));
return new Vector3(x+v.unsafeGet(0),y+v.unsafeGet(1),z+v.unsafeGet(2));
}
public Vector3 addCopy(Vector3 v) {
return new Vector3(x+v.x,y+v.y,z+v.z);
}
public void add(Vector3 v) {
x+=v.x;
y+=v.y;
z+=v.z;
}
public void sub(Vector3 v) {
x-=v.x;
y-=v.y;
z-=v.z;
}
public void subMultiple(Vector3 v, double factor) {
addMultiple(v,-factor);
}
public double dotProduct(Vector3 a) {
return (x*a.x) + (y*a.y) + (z*a.z);
}
@Override
public double dotProduct(AVector v) {
v.checkLength(3);
return x*v.unsafeGet(0)+y*v.unsafeGet(1)+z*v.unsafeGet(2);
}
@Override
public double dotProduct(Vector v) {
v.checkLength(3);
double[] data=v.getArray();
return x*data[0]+y*data[1]+z*data[2];
}
@Override
public double dotProduct(double[] data, int offset) {
return x*data[offset+0]+y*data[offset+1]+z*data[offset+2];
}
@Override
public void crossProduct(AVector a) {
if (a instanceof Vector3) {
crossProduct((Vector3) a);
return;
}
double x2=a.unsafeGet(0);
double y2=a.unsafeGet(1);
double z2=a.unsafeGet(2);
double tx=y*z2-z*y2;
double ty=z*x2-x*z2;
double tz=x*y2-y*x2;
x=tx;
y=ty;
z=tz;
}
public void crossProduct(Vector3 a) {
double tx=y*a.z-z*a.y;
double ty=z*a.x-x*a.z;
double tz=x*a.y-y*a.x;
x=tx;
y=ty;
z=tz;
}
@Override
public void projectToPlane(AVector normal, double distance) {
if (normal instanceof Vector3) {projectToPlane((Vector3)normal,distance); return;}
super.projectToPlane(normal, distance);
}
public void projectToPlane(Vector3 normal, double distance) {
assert(Tools.epsilonEquals(normal.magnitude(), 1.0));
double d=dotProduct(normal);
addMultiple(normal,distance-d);
}
@Override
public int length() {
return 3;
}
@Override
public double elementSum() {
return x+y+z;
}
@Override
public double elementProduct() {
return x*y*z;
}
@Override
public void scaleAdd(double factor, double constant) {
x=(x*factor)+constant;
y=(y*factor)+constant;
z=(z*factor)+constant;
}
@Override
public void scaleAdd(double factor, AVector constant) {
if (constant instanceof Vector3) {scaleAdd(factor,(Vector3)constant); return; }
x=(x*factor)+constant.unsafeGet(0);
y=(y*factor)+constant.unsafeGet(1);
z=(z*factor)+constant.unsafeGet(2);
}
public void scaleAdd(double factor, Vector3 constant) {
x=(x*factor)+constant.x;
y=(y*factor)+constant.y;
z=(z*factor)+constant.z;
}
@Override
public void add(double constant) {
x=x+constant;
y=y+constant;
z=z+constant;
}
@Override
public double get(int i) {
switch (i) {
case 0: return x;
case 1: return y;
case 2: return z;
default: throw new IndexOutOfBoundsException(ErrorMessages.invalidIndex(this, i));
}
}
@Override
public double unsafeGet(int i) {
switch (i) {
case 0: return x;
case 1: return y;
default: return z;
}
}
@Override
public void set(AVector v) {
if (v.length()!=3) throw new IllegalArgumentException(ErrorMessages.incompatibleShapes(this, v));
x=v.unsafeGet(0);
y=v.unsafeGet(1);
z=v.unsafeGet(2);
}
@Override
public void fill(double v) {
x=v;
y=v;
z=v;
}
@Override
public void set(int i, double value) {
switch (i) {
case 0: x=value; return;
case 1: y=value; return;
case 2: z=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;
case 1: y=value; return;
default: z=value; return;
}
}
@Override
public void addAt(int i, double value) {
switch (i) {
case 0: x+=value; return;
case 1: y+=value; return;
default: z+=value; return;
}
}
public void setValues(double x, double y, double z) {
this.x=x;
this.y=y;
this.z=z;
}
@Override
public void negate() {
x=-x;
y=-y;
z=-z;
}
@Override
public Vector3 negateCopy() {
return new Vector3(-x,-y,-z);
}
@Override
public void getElements(double[] data, int offset) {
data[offset]=x;
data[offset+1]=y;
data[offset+2]=z;
}
@Override
public void toDoubleBuffer(DoubleBuffer dest) {
dest.put(x);
dest.put(y);
dest.put(z);
}
@Override
public double[] toDoubleArray() {
return new double[] {x,y,z};
}
@Override
public Vector3 toNormal() {
double d=this.magnitude();
return (d==0)?new Vector3():new Vector3(x/d,y/d,z/d);
}
@Override
public Vector3 clone() {
return new Vector3(x,y,z);
}
@Override
public Vector3 copy() {
return clone();
}
@Override
public double getX() {
return x;
}
@Override
public double getY() {
return y;
}
@Override
public double getZ() {
return z;
}
@Override
public Vector3 exactClone() {
return clone();
}
@Override
public boolean equals(AVector v) {
if (v==this) return true;
if (v instanceof Vector3) {
return equals((Vector3)v);
}
return (v.length()==3)&&(x==v.unsafeGet(0))&&(y==v.unsafeGet(1))&&(z==v.unsafeGet(2));
}
public boolean equals(Vector3 v) {
return (x==v.x)&&(y==v.y)&&(z==v.z);
}
}