// Aqsis
// Copyright (c) 1997 - 2001, Paul C. Gregory
//
// Contact: pgregory@aqsis.com
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

/**
 * Copyright (C) 2006-2007  NTT DATA CORPORATION
 * 
 * Version: 1.0.0 2007/04/01
 *  
 */
package net.cellcomputing.himawari.library.types;


/**
 * 
 * 2次元ベクトル<br>
 * 3次元/4次元ベクトルからの変換や、単位ベクトル化するメソッドを持つ。
 * 
 * @author NTT DATA Corporation
 */
public strictfp class CqVector2D  {

	private static final long serialVersionUID = -3755250159902223025L;
	
	public float x;
	public float y;
	//************************************************************************//
	//*** コンストラクタの定義
	//************************************************************************//
	
	/**
	 * デフォルトコンストラクタは何もしない
	 */
	public CqVector2D() {}
	
	/**
	 * floatの引数値をもとに2次元ベクトルを作成。
	 * @param x	行列の第１要素
	 * @param y	行列の第２要素
	 */
	public CqVector2D( float x, float y ){
		this.x = x;
		this.y = y;
	}
	
	/**
	 * ２次元ベクトルの要素を用いて新しい２次元ベクトルを作成。
	 * @param From	２次元ベクトル
	 */
	public CqVector2D( CqVector2D From ){
		this.x = From.x;
		this.y = From.y;
	}
	
	/**
	 * ３次元ベクトルの第１・第２要素を用いて２次元ベクトルを作成。
	 * @param From	３次元ベクトル
	 */
	public CqVector2D( CqVector3D From ){
		this.x = From.x;
		this.y = From.y;
	}
	
	/**
	 * ４次元ベクトルの第１・第２要素を、第４要素で割った値で２次元ベクトルを作成。
	 * @param From	４次元ベクトル
	 */
	public CqVector2D( CqVector4D From ){
		this.x = From.x / From.w;
		this.y = From.y / From.w;
	}
	
	//************************************************************************//
	//*** メソッドの定義
	//************************************************************************//
	
	/**
	 * 第１要素のセッタ
	 * @param x	第１要素
	 */
	public void x( float x ){
		this.x = x;
	}
	
	/**
	 * 第２要素のセッタ
	 * @param y	第２要素
	 */
	public void y( float y ){
		this.y = y;
	}
	
	/**
	 * ベクトルの大きさを返す
	 * @return	ベクトルの大きさ
	 */
	public float Magnitude(){
		return (float)(Math.sqrt( ( x * x ) + ( y * y )));
	}
	
	/**
	 * ベクトルの大きさの平方（自乗）を返す
	 * @return	ベクトルの大きさの平方
	 */
	public float Magnitude2(){
//		return this.lengthSquared();
        return ( ( x * x ) + ( y * y ) );

	}
	
	/**
	 * このベクトルを正規化する
	 */
	public void Unit(){
//		this.normalize();
        float Mag = Magnitude();

        x /= Mag;
        y /= Mag;
	}
	
	
	//************************************************************************//
	//*** 演算子のオーバーロード
	//************************************************************************//
	
	/**
	 * 代入演算子。　
	 * 
	 * @param From	CqVector2Dオブジェクト
	 * @return	代入後のthis
	 */
	public CqVector2D assignment( CqVector2D From ){
		this.x = From.x;
		this.y = From.y;
		return this;
	}
	
	/**
	 * 代入演算子。　
	 * ３次元ベクトルの第３要素を無視してコピー。
	 * @param From	CqVector3Dオブジェクト
	 * @return	代入後のthis
	 */
	public CqVector2D assignment( CqVector3D From ){
		this.x = From.x;
		this.y = From.y;
		return this;
	}
	
	/**
	 * 代入演算子。　
	 * ４次元ベクトルの第３要素を無視し、第１・２要素を第４要素で割ってコピー。
	 * @param From	CqVector4Dオブジェクト
	 * @return	代入後のthis
	 */
	public CqVector2D assignment( CqVector4D From ){
	    if( From.w != 1.0f ){
	    	this.x = From.x / From.w;
	    	this.y = From.y / From.w;
	    }
	    else{
			this.x = From.x;
			this.y = From.y;
	    }
	    
	    return this;
	}
	
	/**
	 * 加算演算子。　
	 * ２次元ベクトルの各要素にfを足す
	 * @param f	加算する値
	 * @return	各要素にfを足した値で初期化されたCqVector2Dオブジェクト
	 */
	public CqVector2D add( float f ){
		return new CqVector2D( this.x + f, this.y + f );
	}
	
	/**
	 * 加算演算子。
	 * 各要素それぞれを加算する。
	 * 
	 * @param b	加算するCqVector2D
	 * @return	計算結果
	 */
	public CqVector2D add( final CqVector2D b ){
		CqVector2D r = new CqVector2D( x,y );
		return r.assignAdd(b);
	}

	/**
	 * 減算演算子。　
	 * ２次元ベクトルの各要素からfを引く （v-f）
	 * @param f	減算する値
	 * @return	各要素からfを引いた値で初期化されたCqVector2Dオブジェクト
	 */
	public CqVector2D sub( float f ){
		return new CqVector2D( x-f, y-f );
	}
	
	/**
	 * 減算演算子。
	 * 各要素それぞれを減算する。
	 * 
	 * @param b	減算するCqVector2D
	 * @return	計算結果
	 */
	public CqVector2D sub( final CqVector2D b ){
		CqVector2D r = new CqVector2D( x,y );
		return r.assignSub(b);
	}
	
	/**
	 * 逆減算演算子。　
	 * 減算の逆 （f-v） 即ち、vec.sub(f).negate()と同意。
	 * @param f	減算される値
	 * @return	各要素をｆから引いた値で初期化されたCqVector2Dオブジェクト
	 */
	public CqVector2D subInv( float f ){
		return new CqVector2D( f-x, f-y ); 
	}
	
	/**
	 * 乗算演算子。　
	 * ２次元ベクトルの整数倍を行う
	 * @param f	倍数
	 * @return	各要素を整数倍した値で初期化されたCqVector2Dオブジェクト
	 */
	public CqVector2D mul( float f ){
//		CqVector2D v = new CqVector2D( this );
//		v.scale(f);
//		return v;
		return new CqVector2D(this.x * f , this.y * f);
	}
	
	/**
	 * 乗算演算子。
	 * 内積を返す。
	 * @param v	対象の2次元ベクトル
	 * @return	内積
	 */
	public float mul( CqVector2D v ){
//		return this.dot(v);
		return (v.x * this.x  + v.y * this.y);
	}
	
	/**
	 * 除算演算子。　
	 * ２次元ベクトルの各要素をｆで割る （v/f）
	 * @param f	割る値
	 * @return	各要素をｆで割った値で初期化されたCqVector2Dオブジェクト
	 */
	public CqVector2D div( float f ){
		return new CqVector2D( x/f, y/f );
	}
	
	/**
	 * 逆除算演算子。　
	 * 除算の逆（f/v）
	 * @param f	割られる値
	 * @return	各要素でｆを割った値で初期化されたCqVector2Dオブジェクト
	 */
	public CqVector2D divInv( float f ){
		return new CqVector2D( f/x, f/y );
	}
	
	/**
	 * 除算演算子。　
	 * ２次元ベクトル同士の除算。各要素同士を除算する。
	 * @param v	２次元ベクトル
	 * @return	除算結果で初期化されたCqVector2Dオブジェクト
	 */
	public CqVector2D div( CqVector2D v ){
		return new CqVector2D( x/v.x, y/v.y );
	}
	
	/**
	 * 比較演算子。　
	 * 各要素同士を比較する。
	 * @param Cmp	比較対象のCqVector2Dオブジェクト
	 * @return	true:一致	false:不一致
	 */
	public boolean equals(CqVector2D Cmp) {
		return ( ( x == Cmp.x ) && ( y == Cmp.y )  );
	}
	
	/**
	 * 加算代入。　
	 * 各要素にｆを加算した値で自分自身を更新する。
	 * @param f	足す値
	 * @return	計算結果のCqVector2Dオブジェクト。自分自身のコピー。
	 */
	public CqVector2D assignAdd( float f ) {
		this.x += f;
		this.y += f;
		return this;
	}
	//nttdata 高速化
	public CqVector2D assignAdd( float x ,float y) {
		this.x += x;
		this.y += y;
		return this;
	}
	/**
	 * 加算代入。　
	 * 各要素同士を加算した値で自分自身を更新する。
	 * @param v	足すCqVector2D
	 * @return	計算結果のCqVector2Dオブジェクト。自分自身のコピー。
	 */
	public CqVector2D assignAdd( CqVector2D v ) {
		this.x += v.x;
		this.y += v.y;
		return this;
	}

	/**
	 * 減算代入。　
	 * 各要素からｆを減算した値で自分自身を更新する。
	 * @param f	引く値
	 * @return	計算結果のCqVector2Dオブジェクト。自分自身のコピー。
	 */
	public CqVector2D assignSub( float f ) {
		this.x -= f;
		this.y -= f;
		return this;
	}
	
	/**
	 * 減算代入。　
	 * 各要素同士を減算した値で自分自身を更新する。
	 * @param v	引くCqVector2D
	 * @return	計算結果のCqVector2Dオブジェクト。自分自身のコピー。
	 */
	public CqVector2D assignSub( CqVector2D v ) {
		this.x -= v.x;
		this.y -= v.y;
		return this;
	}

	/**
	 * 乗算代入。　
	 * 各要素にｆを乗算した値で自分自身を更新する。
	 * @param f	倍数
	 * @return	計算結果のCqVector2Dオブジェクト。自分自身のコピー。
	 */
	public CqVector2D assignMul( float f ) {
//		this.scale(f);
		this.x = this.x * f;
		this.y = this.y *f;
		return this;
	}
	
	/**
	 * 乗算代入。　
	 * 各要素同士を乗算した値で自分自身を更新する。
	 * @param v	掛けるCqVector2D
	 * @return	計算結果のCqVector2Dオブジェクト。自分自身のコピー。
	 */
	public CqVector2D assignMul( CqVector2D v ) {
		this.x *= v.x;
		this.y *= v.y;
		return this;
	}

	/**
	 * 除算代入。　
	 * 各要素からｆを除算した値で自分自身を更新する。
	 * @param f	割る値
	 * @return	計算結果のCqVector2Dオブジェクト。自分自身のコピー。
	 */
	public CqVector2D assignDiv( float f ) {
		this.x /= f;
		this.y /= f;
		return this;
	}
	
	/**
	 * 除算代入。　
	 * 各要素同士で除算した値で自分自身を更新する。
	 * @param v	割るCqVector2D
	 * @return	計算結果のCqVector2Dオブジェクト。自分自身のコピー。
	 */
	public CqVector2D assignDiv( CqVector2D v ) {
		this.x /= v.x;
		this.y /= v.y;
		return this;
	}

//	/**
//	 * 配列参照。　
//	 * ２次元ベクトルの第i要素を取得する。
//	 * @param i	要素番号
//	 * @return	２次元ベクトルの第i要素
//	 */
//	public float valueAt( int i ){
//		switch ( i )
//		{
//		case 0:		return ( x );
//		case 1:		return ( y );
//		default:	return ( y );
//		}
//	}
}
