/**
 * Vectores 3D.
 * Definición de vectores 3D y sus operaciones.
 * @author Melissa Méndez Servín.
 */
export default class V3{
    constructor(x, y, z){
        this.x = x;
        this.y = y;
        this.z = z;
    }
    scale(s){
        return new V3(this.x * s, this.y * s, this.z * s);
    }

    movePoints(t1, t2, t3){
        return new V3(this.x + t1, this.y + t2, this.z + t3);
    }
    add(u){
        return new V3(this.x + u.x, this.y + u.y, this.z + u.z);
    }
    sub(u){
        return new V3(this.x - u.x, this.y - u.y, this.z - u.z);
    }
    unit(){
        var d = length();
        return this.scale(1/d);
    }
    distance(u){
        return Math.sqrt((u.x-this.x)**2 + (u.y-this.y)**2 + (u.z-this.z)**2);
    }
    length(){
        return Math.sqrt(this.dotProduct(this));
    }
    normalize(){
        let length = this.length();
        if (length > 0.00000001) 
            return new V3(this.x/length, this.y/length, this.z/length);
        else return new V3(0, 0, 0);
    }
    dotProduct(v){
        return (this.x * v.x ) + (this.y * v.y) + (this.z * v.z);
    }
    cross(v){
        return  new V3( this.y*v.z - this.z*v.y, 
                        this.z*v.x - this.x*v.z, 
                        this.x*v.y - this.y*v.x
        );
    }
    toArray(w=1){
        return [this.x, this.y, this.z, w];
    }
    multiplyM(m){
        var x = m[0] * this.x +  m[3] * this.y + m[6] * this.z;
        var y = m[1] * this.x +  m[4] * this.y + m[7] * this.z;
        var z = m[2] * this.x +  m[5] * this.y + m[8] * this.z;
        return new V3(x, y, z);
    }
    squareModule(){
        return this.x * this.x + this.y*this.y + this.z*this.z;
    }
    /**
     * Proyeccuón del vector u (this) sobre el vector v 
     * recibido.
     * @param {*} v vector sobre el cual se proyectará
     */
     projection(v){
        var dotProduct = this.dotProduct(v);
        var wLength = dotProduct/(v.squareModule());
        return v.scale(wLength);
    }
    multiply(u){
        return new V3(this.x * u.x, this.y * u.y, this.z * u.z);
    }
}