module util.vector;
private import std.math;
private import util.cloneable;
public Vector3 vec3Normalize(Vector3 v){
	Vector3 vec;
	double len;
	double x, y, z;
	x = cast(double)v.x;
	y = cast(double)v.y;
	z = cast(double)v.z;
	len = sqrt(x * x + y * y + z * z);
	if(len < (1e-6))return new Vector3(1,0,0);
	len = 1.0 / len;
  x *= len;
  y *= len;
  z *= len;
	vec = new Vector3(x ,y ,z);
	return vec;
}
public float vec3Dot(Vector3 pV1, Vector3 pV2)
{
    return ((pV1.x * pV2.x) + (pV1.y * pV2.y) + (pV1.z * pV2.z));
}
public float vecDot(Vector pV1, Vector pV2)
{
    return ((pV1.x * pV2.x) + (pV1.y * pV2.y));
}
public Vector3 vec3Cross(Vector3 pV1, Vector3 pV2){
	Vector3 vec = new Vector3();
	double x1, y1, z1, x2, y2, z2;
    
  x1 = cast(double)(pV1.x);
  y1 = cast(double)(pV1.y);
  z1 = cast(double)(pV1.z);
  x2 = cast(double)(pV2.x);
  y2 = cast(double)(pV2.y);
  z2 = cast(double)(pV2.z);
	vec.x = cast(float)(y1 * z2 - z1 * y2);
  vec.y = cast(float)(z1 * x2 - x1 * z2);
  vec.z = cast(float)(x1 * y2 - y1 * x2);
	return vec;
}
public Vector3 vec3NormalLine(Vector3 pV ,Vector3 pV1, Vector3 pV2){
	Vector3 v1, v2, n;
	v1 = pV1 - pV;
	v2 = pV2 - pV;
	n = vec3Cross(v1 ,v2);
	n = vec3Normalize(n);
	return n;
}
public class Vector:Cloneable{
	public:
	float x,y;
	public this(){
		x = y = 0;
	}
	public this(float x ,float y){
		this.x = x;
		this.y = y;
	}
	public this(Vector v){
		x = v.x;
		y = v.y;
	}
	public Object clone(){
		return new Vector(this);
	}
	public float opMul(Vector v) {
    return x * v.x + y * v.y;
  }
	public Vector opMul(float mul){
		return new Vector(x * mul ,y * mul);
	}
	public Vector opDiv(float div){
		return new Vector(x / div ,y / div);
	}
	public Vector opAdd(Vector v){
		return new Vector(x + v.x ,y + v.y);
	}
	public Vector opSub(Vector v){
		return new Vector(x - v.x ,y - v.y);
	}
	public void opAddAssign(Vector v) {
    x += v.x;
    y += v.y;
  }

  public void opSubAssign(Vector v) {
    x -= v.x;
    y -= v.y;
  }

  public void opMulAssign(float a) {	
    x *= a;
    y *= a;
  }

  public void opDivAssign(float a) {	
    x /= a;
    y /= a;
  }
	public float size(){
		return sqrt(x * x + y * y);
	}
	public float dist(Vector v){
		float ax = fabs(x - v.x);
		float ay = fabs(y - v.y);
		return sqrt(ax * ax + ay * ay);
	}
}

public class Vector3:Cloneable{
	public:
	float x ,y ,z;
	public this(){
		x = y = z = 0;
	}
	
	public this(float x ,float y ,float z){
		this.x = x;
    this.y = y;
    this.z = z;
	}
	public this(Vector3 v){
		x = v.x;
		y = v.y;
		z = v.z;
	}
	public Object clone(){
		return new Vector3(this);
	}
	public void rollX(float d) {
    float ty = y * cos(d) - z * sin(d);
    z = y * sin(d) + z * cos(d);
    y = ty;
  }

  public void rollY(float d) {
    float tx = x * cos(d) - z * sin(d);
    z = x * sin(d) + z * cos(d);
    x = tx;
  }

  public void rollZ(float d) {
    float tx = x * cos(d) - y * sin(d);
    y = x * sin(d) + y * cos(d);
    x = tx;
  }
	public float size(){
		return sqrt(x * x + y * y + z * z);
	}
	public float dist(Vector3 v){
		float ax = fabs(x - v.x);
		float ay = fabs(y - v.y);
		float az = fabs(z - v.z);
		return sqrt(ax * ax + ay * ay + az * az);
	}
  public void blend(Vector3 v1, Vector3 v2, float ratio) {
    x = v1.x * ratio + v2.x * (1 - ratio);
    y = v1.y * ratio + v2.y * (1 - ratio);
    z = v1.z * ratio + v2.z * (1 - ratio);
  }
	public Vector3 opAdd(Vector3 v){
		return new Vector3(x + v.x ,y + v.y ,z + v.z);
	}
	public Vector3 opSub(Vector3 v){
		return new Vector3(x - v.x ,y - v.y ,z - v.z);
	}
	public Vector3 opMul(float mul){
		return new Vector3(x * mul ,y * mul ,z * mul);
	}
	public Vector3 opDiv(float div){
		return new Vector3(x / div ,y / div ,z /div);
	}
  public void opAddAssign(Vector3 v) {
    x += v.x;
    y += v.y;
    z += v.z;
  }

  public void opSubAssign(Vector3 v) {
    x -= v.x;
    y -= v.y;
    z -= v.z;
  }

  public void opMulAssign(float a) {	
    x *= a;
    y *= a;
    z *= a;
  }

  public void opDivAssign(float a) {	
    x /= a;
    y /= a;
    z /= a;
  }
}
