package march;

public class Vec{  
    public static final float TPI = (float)(Math.PI * 2.0);

    public float x,y,z;
  
    /* 初期値 */
    public float ox,oy,oz; 
    
    /* 初期状態からどれほど回転したか */
    public float rot_x,rot_y,rot_z;
    
    /* xy平面に平行な平面(z = vp)に透視投影したときの座標を記憶 */
    /* 視点はz軸上( > vp )                   */
    public float px, py, pz;
    public boolean visible;

    public Vec(float x, float y, float z){
        this.x = x; this.y = y; this.z = z;
        ox = x; oy = y; oz = z;
        rot_x = 0.0f; rot_y = 0.0f; rot_z = 0.0f;
    }

    public Vec(){
        this.x = 0.0f; this.y = 0.0f; this.z = 0.0f;
        ox = x; oy = y; oz = z;
        rot_x = 0.0f; rot_y = 0.0f; rot_z = 0.0f;
    }

    public void returnToInit(){
        x = ox; y = oy; z = oz;
        rot_x = 0.0f; rot_y = 0.0f; rot_z = 0.0f;
    }
    
    public void setCurrentAsInit(){
        ox = x; oy = y; oz = z;
        rot_x = 0.0f; rot_y = 0.0f; rot_z = 0.0f;
    }
    
    public void translate(float tx, float ty, float tz){
        x += tx;
        y += ty;
        z += tz;
    }
    
    public void xAxisRotate(float r){
        rot_x += r;
        if(rot_x > TPI){
            rot_x -= TPI;
        }
        else if( rot_x < - TPI){
            rot_x += TPI;
        }
        rotateFromInit();
    }
    
    public void yAxisRotate(float r){
        rot_y += r;
        if(rot_y > TPI){
            rot_y -= TPI;
        }
        else if( rot_y < - TPI){
            rot_y += TPI;
        }
        rotateFromInit();
        
    }
    
    public void zAxisRotate(float r){
        rot_z += r;
        if(rot_z > TPI){
            rot_z -= TPI;
        }
        else if( rot_z < - TPI){
            rot_z += TPI;
        }
        rotateFromInit();
    }
    
    public void rotateFromInit(){
        float cosr = (float)Math.cos(rot_x);
        float sinr = (float)Math.sin(rot_x);
        float tx,ty,tz;
        
        x = ox;
        y = oy;
        z = oz;
        
        ty = y;
        tz = z;
        y = ty*cosr - tz*sinr;
        z = ty*sinr + tz*cosr;
        
        cosr = (float)Math.cos(rot_y);
        sinr = (float)Math.sin(rot_y);
        
        tz = z;
        tx = x;
        x = tz*sinr + tx*cosr;
        z = tz*cosr - tx*sinr;
        
        cosr = (float)Math.cos(rot_z);
        sinr = (float)Math.sin(rot_z);
        
        tx = x;
        ty = y;
        x = tx*cosr - ty*sinr;
        y = tx*sinr + ty*cosr;
        
    }
    
    /* 視点を (0,0,prp) prp > vp において xy平面に平行な平面(z = vp)
       に透視投影したときの座標を計算してセットする  */
    public void calcPerspectiveProjection(float vp, float prp){
        if( z >= vp ){
            visible = false;
        }
        else{
            visible = true;
        }
        
        float d = (prp - vp)/(prp - z);
        px = x*d;  
        py = y*d;
        pz = z*d;
    }
 
    /**
     * 注視点(fp)を含む平面への投資投影したときの座標を
     * 計算してセットする。視点はfpからの距離R, 方位角theta, 仰角phi
     * で示す。
     */
    public void calcPerspectiveProjection(Vec fp, 
                                          float R, float the, float phi){
        float st = (float)Math.sin(the);
        float ct = (float)Math.cos(the);
        float sp = (float)Math.sin(phi);
        float cp = (float)Math.cos(phi);
        calcPerspectiveProjection(fp, R, st, ct, sp, cp);
       
    }

    /**
     * 注視点(fp)を含む平面への投資投影したときの座標を
     * 計算してセットする。視点はfpからの距離R, 方位角theta, 仰角phi
     * で示す。
     */
    public void calcPerspectiveProjection(Vec fp, 
                                          float R,
                                          float sin_the,
                                          float cos_the,
                                          float sin_phi,
                                          float cos_phi){
        
        float xf = fp.x;
        float yf = fp.y;
        float zf = fp.z;
        float xd = (x - xf);
        float yd = (y - yf);
        float zd = (z - zf);
        float st = sin_the;
        float ct = cos_the;
        float sp = sin_phi;
        float cp = cos_phi;
        float xx = -xd*st+yd*ct;
        float yy = -xd*ct*sp-yd*st*sp+zd*cp;
        float zz = xd*ct*cp+yd*st*cp+zd*sp;
        if(zz >= R){
            visible = false;
        }
        else{
            visible = true;
        }
        float d = R/(R-zz);
        px = xx*d;
        py = yy*d;
        pz = zz*d;
    }

    public void calcParallelProjection(float  vp){
        if( z >= vp ){
            visible = false;
        }
        else{
            visible = true;
        }
        px = x;
        py = y;
        pz = z;
    }
    
    public boolean in(int wind_minx, int wind_miny, 
                      int wind_maxx, int wind_maxy){
        return (   (px >= wind_minx) && (px <= wind_maxx)
                && (py >= wind_miny) && (py <= wind_maxy));
    }
    
}





