// 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;

import net.cellcomputing.himawari.accessory.STLVector;
import net.cellcomputing.himawari.library.types.CqMatrix;
import net.cellcomputing.himawari.library.types.CqVector3D;
import static java.lang.StrictMath.*;

/**
 * Cone quadric GPrim<br>
 * 2次曲面 ：　錐 
 * 
 * @author NTT DATA Corporation
 */
public strictfp class CqCone extends CqQuadric {
	
	private float	m_Height;		///< Height..
	private float	m_Radius;		///< Radius.
	private float	m_vMin;			///< Min value on z axis.
	private float	m_vMax;			///< Max value on z axis.
	private float	m_ThetaMin;		///< Min angle about z axis.
	private float	m_ThetaMax;		///< Max angle about z axis.

	
	/**
	 * デフォルトコンストラクタ
	 */
	public CqCone(){
		
		this(1.0f, 1.0f, 0.0f, 360.0f, 0.0f, 1.0f);
	}
	
	/**
	 * コンストラクタ。<BR>初期値が1つ与えられた場合
	 * 
	 * @param height	底部と頂点間の距離
	 */
	public CqCone( float height ){
		
		this( height, 1.0f, 0.0f, 360.0f, 0.0f, 1.0f);
	}
	
	/**
	 * コンストラクタ。<BR>初期値が2つ与えられた場合
	 * 
	 * @param height	底部と頂点間の距離
	 * @param radius	底部の半径
	 */
	public CqCone( float height, float radius ){
		
		this( height, radius, 0.0f, 360.0f, 0.0f, 1.0f);
	}
	
	/**
	 * コンストラクタ。<BR>初期値が3つ与えられた場合
	 * 
	 * @param height	底部と頂点間の距離
	 * @param radius	底部の半径
	 * @param thetamin	最小スイープ角度
	 */
	public CqCone( float height, float radius, float thetamin ){
		
		this( height, radius, thetamin, 360.0f, 0.0f, 1.0f);
	}
	
	/**
	 * コンストラクタ。<BR>初期値が4つ与えられた場合
	 * 
	 * @param height	底部と頂点間の距離
	 * @param radius	底部の半径
	 * @param thetamin	最小スイープ角度
	 * @param thetamax	最大スイープ角度
	 */
	public CqCone( float height, float radius, float thetamin, float thetamax ){
		
		this( height, radius, thetamin, thetamax, 0.0f, 1.0f);
	}
	
	/**
	 * コンストラクタ。<BR>初期値が5つ与えられた場合
	 *  
	 * @param height	底部と頂点間の距離
	 * @param radius	底部の半径
	 * @param thetamin	最小スイープ角度
	 * @param thetamax	最大スイープ角度
	 * @param vmin		ｖ方向の最小値
	 */
	public CqCone( float height, float radius, float thetamin, float thetamax, float vmin ){
		
		this( height, radius, thetamin, thetamax, vmin, 1.0f);
	}

	/**
	 * コンストラクタ。<BR>初期値が与えられた場合
	 * 
	 * @param height	底部と頂点間の距離
	 * @param radius	底部の半径
	 * @param thetamin	最小スイープ角度
	 * @param thetamax	最大スイープ角度
	 * @param vmin		ｖ方向の最小値
	 * @param vmax		ｖ方向の最大値
	 */
	public CqCone( float height, float radius, float thetamin, float thetamax, float vmin, float vmax ){
		
	        m_Height = height; 
	        m_Radius = radius;
	        m_vMin = vmin;
	        m_vMax = vmax;
	        m_ThetaMin = thetamin;
	        m_ThetaMax = thetamax;
	}
	
	/**
	 * コピーコンストラクタ
	 */
	public CqCone( final CqCone From ){
		this.assignment( From );
	}
	
	/**
	 * デストラクタ
	 */
	public void destrust(){}
	
	/**
	 * Get the geometric bound of this GPrim.
	 * @see net.cellcomputing.himawari.library.IqSurface#Bound()
	 */
	public CqBound	Bound()
	{	//Get the geometric bound of this GPrim.
		
		float zmin = m_vMin * m_Height;
		float zmax = m_vMax * m_Height;
		STLVector<CqVector3D> curve = new STLVector<CqVector3D>( CqVector3D.class );
		CqVector3D vA = new CqVector3D( m_Radius, 0, zmin );
		CqVector3D vB = new CqVector3D( 0, 0, zmax );
		CqVector3D vC = new CqVector3D( 0, 0, 0 );
		CqVector3D vD = new CqVector3D( 0, 0, 1 );
		
		curve.add( vA );
		curve.add( vB );
		CqMatrix matRot = new CqMatrix( (float)toRadians( m_ThetaMin ), vD );
		
		for( CqVector3D i : curve )
			i.assignment( matRot.multiply( i ));
		
		CqBound	B = new CqBound( RevolveForBound( curve, vC, vD, (float)toRadians( m_ThetaMax - m_ThetaMin ) ) );
		B.Transform( m_matTx );
		
		return ( AdjustBoundForTransformationMotion( B ) );
	}
	
	/** 
	 * Get a point on the surface indexed by the surface paramters passed.
	 * 
	 * @param u 	Float surface paramter in u.
	 * @param v 	Float surface paramter in v.
	 * @see net.cellcomputing.himawari.library.CqQuadric#DicePoint(int, int)
	 */
	public CqVector3D	DicePoint( int u, int v )
	{
		float theta = (float)toRadians( m_ThetaMin + ( ( float ) u * ( m_ThetaMax - m_ThetaMin ) ) / m_uDiceSize );
		
		float zmin = m_vMin * m_Height;
		float zmax = m_vMax * m_Height;
		float z = zmin + ( ( float ) v * ( zmax - zmin ) ) / m_vDiceSize;
		float vv = m_vMin + ( ( float ) v * ( m_vMax - m_vMin ) ) / m_vDiceSize;
		float r = (float)( m_Radius * ( 1.0 - vv ));
		
		return ( new CqVector3D( (float)(r * cos( theta )), (float)(r * sin( theta )), z ));
	}
	
	/**
	 * Get a point on the surface indexed by the surface paramters passed.
	 * 
	 * @param u 	 Float surface paramter in u.
	 * @param v 	 Float surface paramter in v.
	 * @param Normal Storage for the surface normal at that point.
	 * @see net.cellcomputing.himawari.library.CqQuadric#DicePoint(int, int, net.cellcomputing.himawari.library.types.CqVector3D)
	 */
	public CqVector3D	DicePoint( int u, int v, CqVector3D Normal )
	{
		float theta = (float)toRadians( m_ThetaMin + ( ( float ) u * ( m_ThetaMax - m_ThetaMin ) ) / m_uDiceSize );
		
		float zmin = m_vMin * m_Height;
		float zmax = m_vMax * m_Height;
		float z = zmin + ( ( float ) v * ( zmax - zmin ) ) / m_vDiceSize;
		float vv = m_vMin + ( ( float ) v * ( m_vMax - m_vMin ) ) / m_vDiceSize;
		float r = (float)(m_Radius * ( 1.0 - vv ));
		
		float cos_theta = (float)cos( theta );
		float sin_theta = (float)sin( theta );
		
		float coneLength = (float)sqrt( m_Height * m_Height + m_Radius * m_Radius );
		float xN = m_Height / coneLength;
		Normal.x( xN * cos_theta );
		Normal.y( xN * sin_theta );
		Normal.z( m_Radius / coneLength );
		
		return ( new CqVector3D( (float)(r * cos_theta), (float)(r * sin_theta), z ) );
	}


	/**
	 * Split this GPrim into a NURBS surface. Temp implementation, should split into smalled quadrics. 
	 * @see net.cellcomputing.himawari.library.IqSurface#PreSubdivide(net.cellcomputing.himawari.accessory.STLVector, boolean)
	 */
	public int PreSubdivide( STLVector<CqBasicSurface> aSplits, boolean u )
	{
		float vcent = (float)(( m_vMin + m_vMax ) * 0.5);
	    float arccent = (float)(( m_ThetaMin + m_ThetaMax ) * 0.5);
	    //float rcent=m_RMax*sqrt(zcent/m_ZMax);

	    CqCone pNew1 = new CqCone( this );
	    CqCone pNew2 = new CqCone( this );

	    if ( u )
	    {
	        pNew1.m_ThetaMax = arccent;
	        pNew2.m_ThetaMin = arccent;
	    }
	    else
	    {
	        pNew1.m_vMax = vcent;
	        pNew2.m_vMin = vcent;
	    }

	    aSplits.add( pNew1 );
	    aSplits.add( pNew2 );

	    return ( 2 );
	}

	/**
	 * 
	 * 
	 * 
	 * @param From
	 * @return
	 */
	public CqCone assignment( final CqCone From )
	{
	    super.assignment( From );
	    m_Height = From.m_Height;
	    m_Radius = From.m_Radius;
	    m_vMin = From.m_vMin;
	    m_vMax = From.m_vMax;
	    m_ThetaMin = From.m_ThetaMin;
	    m_ThetaMax = From.m_ThetaMax;

	    return ( this );
	}


}
