/*
 * CoordinateSystem.java
 *
 * Created on December 29, 2000, 5:11 PM
 */

package edu.ou.eml.fea3d;

/**
 *
 * @author  Qiuli Sun
 * @version 1.0
 */



import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.picking.*;
import java.awt.*;

public class CoordinateSystem  {

    public static float rate = DataContainer.maxXYZ / 100.0f;
    
    //Info about the force geometry,
    //which should dynamically get based on the geometry input
    public static float arrowRadius = 0.7f * rate ;
    public static float arrowLen = 2.5f * rate;
    public static float arrowShaftRadius = 0.30f * rate;
    public static float arrowShaftLen = 4.0f * rate ;

    //Instance variables,which can be accessed by other classes
    public BranchGroup coordSystemBG;
    
    public static float x0, y0, z0 ;
    public static float xDiff, yDiff, zDiff ;
    
    /** Creates new CoordinateSystem */
    public CoordinateSystem() 
    {
          coordSystemBG = new BranchGroup ();      
          coordSystemBG.setPickable(false);
        
        //xyzTG is used to move the coord system to any new location
        TransformGroup xyzTG = new TransformGroup () ;
        
        //xyzTransform3D is a shared transform matrix
        Transform3D xyzTransform3D = new Transform3D();
        //Movement happens here
        //The basic rule is to move the coord to the shortest difference
         xDiff = (DataContainer.xMax - DataContainer.xMin);
         yDiff = (DataContainer.yMax - DataContainer.yMin);
         zDiff = (DataContainer.zMax - DataContainer.zMin);
        
         x0 = (DataContainer.xMin + DataContainer.xMax) / 2.0f;
         y0 = (DataContainer.yMin + DataContainer.yMax) / 2.0f;
         z0 = (DataContainer.zMin + DataContainer.zMax) / 2.0f ;
        
        if ( xDiff < yDiff & yDiff <= zDiff)
        {
            x0 = DataContainer.xMax + 0.6f* (arrowLen + arrowShaftLen);
        }
        else
        {
            if ( yDiff <= xDiff & xDiff < zDiff)
            {
                y0 = DataContainer.yMax + 0.6f*(arrowLen + arrowShaftLen);
            }
            else
            {
                z0 = DataContainer.zMax + 0.6f* (arrowLen + arrowShaftLen);
            }
        }

        xyzTransform3D.setTranslation(new Vector3f(x0, y0, z0));
        xyzTG.setTransform(xyzTransform3D);
        
        //Create an appearance for axises
        Appearance axisAppearance = createAxisAppearance () ;
        //create an appearance for x,y,z text
        Appearance textAppearance = createTextAppearance();
        //font3D can be used three times
        Font3D font3D = new Font3D(new Font("Helvetica", Font.PLAIN, (int)(3*rate)), 
        new FontExtrusion());
        
        TransformGroup xHeadTG = new TransformGroup();
        TransformGroup xShaftTG = new TransformGroup();
        TransformGroup xTextTG = new TransformGroup();

        Cylinder xShaft = new Cylinder (arrowShaftRadius, arrowShaftLen ) ;
        xShaft.setAppearance(axisAppearance);
        xyzTransform3D.setIdentity();
        xyzTransform3D.rotZ( - Math.PI/2.0f );
        xyzTransform3D.setTranslation(new Vector3f(arrowShaftLen / 2.0f, 0.0f, 0.0f) );
        xShaftTG.setTransform(xyzTransform3D);
        xShaftTG.addChild(xShaft);
        xyzTG.addChild(xShaftTG);
  
        // create the head of x axis
        Cone xHead = new Cone ( arrowRadius, arrowLen);
        xHead.setAppearance(axisAppearance);
        xyzTransform3D.setIdentity();
        xyzTransform3D.rotZ( - Math.PI/2.0f );
        xyzTransform3D.setTranslation(new Vector3f( arrowShaftLen + arrowLen / 2.0f , 0.0f, 0.0f) );
        xHeadTG.setTransform(xyzTransform3D);
        xHeadTG.addChild (xHead);
        xyzTG.addChild(xHeadTG);
        
         //create 'x' text
        Text3D textGeom = new Text3D( font3D, new String("X") );
        textGeom.setAlignment(Text3D.ALIGN_CENTER);
        
        //Please note, OrientedShape3D is much better than billboard
        //The reason is that it works in every view and is easy to code
        OrientedShape3D xTextShape = new OrientedShape3D();
        xTextShape.setGeometry(textGeom);
        xTextShape.setAppearance(textAppearance);
        Point3f rotationPt = new Point3f(0.0f, 0.0f, 0.0f);
        xTextShape.setAlignmentMode(OrientedShape3D.ROTATE_ABOUT_POINT);
        xTextShape.setRotationPoint(rotationPt);

        xyzTransform3D.setIdentity();
        xyzTransform3D.rotY(- Math.PI / 2.0f );
        xyzTransform3D.setTranslation (
        new Vector3f(arrowShaftLen + 1.4f * arrowLen, 0.0f, 0.0f) );
        xTextTG.setTransform(xyzTransform3D);
        xTextTG.addChild(xTextShape);
        xyzTG.addChild(xTextTG);
        
        //+++++++++++++++++++++++++++++++++
        //creating y axis
        TransformGroup yShaftTG = new TransformGroup();
        TransformGroup yHeadTG = new TransformGroup();
        TransformGroup yTextTG = new TransformGroup();
        
        Cylinder yShaft = new Cylinder (arrowShaftRadius, arrowShaftLen ) ;
        yShaft.setAppearance(axisAppearance);
        xyzTransform3D.setIdentity();
        xyzTransform3D.setTranslation(new Vector3f(0.0f, arrowShaftLen / 2.0f, 0.0f));
        yShaftTG.setTransform(xyzTransform3D);
        yShaftTG.addChild(yShaft);
        xyzTG.addChild(yShaftTG);
         // create the head of y axis
        Cone yHead = new Cone ( arrowRadius, arrowLen);
        yHead.setAppearance(axisAppearance);
        xyzTransform3D.setIdentity();
        xyzTransform3D.setTranslation(new Vector3f( 0.0f, arrowShaftLen + arrowLen / 2.0f, 0.0f) );
        yHeadTG.setTransform(xyzTransform3D);
        yHeadTG.addChild (yHead);
        xyzTG.addChild(yHeadTG);
        //create 'y' text
        textGeom = new Text3D( font3D, new String("Y") );
        textGeom.setAlignment(Text3D.ALIGN_CENTER);
        OrientedShape3D yTextShape = new OrientedShape3D();
        yTextShape.setGeometry(textGeom);
        yTextShape.setAppearance(textAppearance);
        
        yTextShape.setAlignmentMode(OrientedShape3D.ROTATE_ABOUT_POINT);
        yTextShape.setRotationPoint(rotationPt);
        
        xyzTransform3D.setIdentity();
        xyzTransform3D.rotY(- Math.PI / 2.0f );
        xyzTransform3D.setTranslation (
        new Vector3f( 0.0f, arrowShaftLen + 1.4f * arrowLen, 0.0f ) );
        yTextTG.setTransform(xyzTransform3D);
        yTextTG.addChild(yTextShape);
        xyzTG.addChild(yTextTG);
        
        //+++++++++++++++++++++++
        //create z axis and 'z' text
        TransformGroup zHeadTG = new TransformGroup();
        TransformGroup zShaftTG = new TransformGroup();
        //we need billboard to rotate the 'z' text
        TransformGroup zTextTG =  new TransformGroup();
        zTextTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        zTextTG.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
        
        //create the shaft of z axis
        Cylinder zShaft = new Cylinder (arrowShaftRadius, arrowShaftLen ) ;
        zShaft.setAppearance(axisAppearance);
        xyzTransform3D.setIdentity();
        xyzTransform3D.rotX( Math.PI/2.0f);
        xyzTransform3D.setTranslation(new Vector3f(0.0f, 0.0f, arrowShaftLen / 2.0f));
        zShaftTG.setTransform(xyzTransform3D);
        zShaftTG.addChild(zShaft);
        xyzTG.addChild(zShaftTG);
        
        // create the head of z axis
        Cone zHead = new Cone ( arrowRadius, arrowLen);
        zHead.setAppearance(axisAppearance);
        xyzTransform3D.setIdentity();
        xyzTransform3D.rotX(  Math.PI/2.0f );
        xyzTransform3D.setTranslation(new Vector3f( 0.0f, 0.0f, arrowShaftLen + arrowLen / 2.0f) );
        zHeadTG.setTransform(xyzTransform3D);
        zHeadTG.addChild (zHead);
        xyzTG.addChild(zHeadTG);
        
        //create text of z
        textGeom = new Text3D( font3D, new String("Z") );
        textGeom.setAlignment(Text3D.ALIGN_CENTER);
        //Shape3D zTextShape = new Shape3D();
        OrientedShape3D zTextShape = new OrientedShape3D();
        zTextShape.setGeometry(textGeom);
        zTextShape.setAppearance(textAppearance);
        
        zTextShape.setAlignmentMode(OrientedShape3D.ROTATE_ABOUT_POINT);
        zTextShape.setRotationPoint(rotationPt);
        
        //extShape.setAlignmentAxis( 0.0f, 1.0f, 0.0f);
        
        xyzTransform3D.setIdentity();
        xyzTransform3D.rotY(- Math.PI / 2.0f );
        xyzTransform3D.setTranslation(
        new Vector3f( 0.0f, -0.4f * arrowLen, arrowShaftLen + 1.5f * arrowLen ) );
        zTextTG.setTransform(xyzTransform3D);
        
        zTextTG.addChild(zTextShape);
        xyzTG.addChild(zTextTG);
        
        
        coordSystemBG.addChild ( xyzTG );  
        //Only after everything is ok, then the forceBG can be added into coordSystemBG
        DataContainer.geometryTG.addChild (coordSystemBG);
    }
    
    //******************************************
    private final static  Color3f   ambColor = new Color3f ( 0.3f, 0.3f, 0.3f ) ;
    private final static Color3f  emissColor = new Color3f ( 0.1f,0.1f,0.1f ) ;  
    private final static   float shininess = 50.0f ;
    
    private final Appearance createAxisAppearance ()
    {
        Appearance axisAppearance = new Appearance ();
        Color3f  diffColor = new Color3f ( 0.0f, 1.0f, 1.0f ) ;
        Color3f  specColor = new Color3f ( 1.0f, 1.0f, 1.0f ) ;
        Material material = new Material (ambColor, emissColor, diffColor, specColor, shininess);
        axisAppearance.setMaterial (material);
        return axisAppearance ;
    }
    
    public final static  Appearance createTextAppearance()
    {
        Appearance textAppearance = new Appearance ();
        Color3f  diffColor = new Color3f ( 1.0f, 0.0f, 0.3f ) ;
        Color3f  specColor = new Color3f ( 1.0f, 0.3f, 1.0f ) ;
        Material material = new Material (ambColor, emissColor, diffColor, specColor, shininess);
        textAppearance.setMaterial (material);
        return textAppearance ;
    }
}
