/*
 * AttenuatedCone (3D) class
 *
 * Describes the shape and color of a cone whose top is cropped off.
 * It is implemented as a band of polygons arranged cylindrically,
 * but tapered toward (or away from) the top.
 *
 * Parameters for constructors are:
 *  top diameter
 *  bottom diameter
 *  height
 *  number of quads (default 16)
 *  color: The cone's color.
 *  transparency: the transparency (0->1) of the shape
 *
 * Author: Allan Ash
 *
 * Software Arts, Inc.
 * www.infoviz.biz
 *
 * May 20, 2003
 *
 */
import com.sun.j3d.utils.geometry.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import java.awt.*;

public class AttenuatedCone extends Shape3D {
	
  private Appearance appearance;
  private Texture texture;
  private Color3f clr;
  static int quads = 16;
  static int[] contourCounts = {1};
  static int[] stripCounts = {quads};
  float transparency;
  
        public AttenuatedCone(float topD, float bottomD, float height, int numQuads, 
                                                Color colr, float pTransp) {
                super();
                quads = numQuads;
                clr = new Color3f(colr);
                transparency = pTransp;
                setGeometry(buildGeometry(topD, bottomD, height, quads));
                buildAppearance();
                this.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
                this.setCapability(Shape3D.ALLOW_COLLISION_BOUNDS_READ);
        }
	
        public void buildAppearance (){
        appearance = new Appearance();

            TextureAttributes tex_attr = new TextureAttributes();
            tex_attr.setTextureMode(TextureAttributes.DECAL);
            tex_attr.setPerspectiveCorrectionMode(TextureAttributes.FASTEST);
	
            appearance.setTextureAttributes(tex_attr);
	
            ColoringAttributes col_attr = new ColoringAttributes();
            col_attr.setColor(clr);
            col_attr.setShadeModel(ColoringAttributes.SHADE_GOURAUD);
	
            appearance.setColoringAttributes(col_attr);
	
            PolygonAttributes rend_attr = new PolygonAttributes();
            rend_attr.setCullFace(PolygonAttributes.CULL_NONE);
//   uncomment this if you want it to display in line draw mode
//   rend_attr.setPolygonMode(PolygonAttributes.POLYGON_LINE);

            appearance.setPolygonAttributes(rend_attr);
            
            TransparencyAttributes tran_attr = new TransparencyAttributes();
            tran_attr.setTransparencyMode(TransparencyAttributes.SCREEN_DOOR);
            tran_attr.setTransparency(transparency);
            
            appearance.setTransparencyAttributes(tran_attr);
	
            Material mat = new Material();
            
//      mat.setEmissiveColor(clr);
        mat.setAmbientColor(clr);
//      mat.setDiffuseColor(clr);
	
            appearance.setMaterial(mat);
	
            setAppearance(appearance);
        }
	
        protected QuadArray buildGeometry(float topDiam, float bottomDiam, float height, int count) {
                QuadArray result = new QuadArray(4*count,QuadArray.COORDINATES);
                Point3f[] quadPoints = new Point3f[4*count]; // array of points for all quads
                // looking down from the top, the points around the radius are described
                // by their x and z locations. The y axis is height.
                // One extra set is defined at the end to allow for closing the last quad.
                float[][] topPoints = new float[count+1][2]; // x and z coordinates
                float[][] bottomPoints = new float[count+1][2]; // x and z coordinates
                float topY = height/2.0f;
                float bottomY = -height/2.0f;
        	
                // calculate all the points traversed at specified top/bottom diameters
                // by the specified radius
                double offset = Math.toRadians(360./count);           // # radians in each quad
                for (int i=0; i<count; i++){
                        topPoints[i][0] = (float)((topDiam/2.0)*Math.cos(offset*i)); // x axis
                        topPoints[i][1] = (float)((topDiam/2.0)*Math.sin(offset*i)); // z axis
                        bottomPoints[i][0] = (float)((bottomDiam/2.0)*Math.cos(offset*i)); // x axis
                        bottomPoints[i][1] = (float)((bottomDiam/2.0)*Math.sin(offset*i)); // z axis
                }
                // wrap the last ones
                topPoints[count][0] = topPoints[0][0];
                topPoints[count][1] = topPoints[0][1];
                bottomPoints[count][0] = bottomPoints[0][0];
                bottomPoints[count][1] = bottomPoints[0][1];
        	
                // build a set of quads that span all the points, 4 at a time, connected to
                // the previous quad
                for (int i=0; i<count; i++){
                        quadPoints[i*4] = new Point3f(topPoints[i][0], topY, topPoints[i][1]);       // top right
                        quadPoints[(i*4)+1] = new Point3f(topPoints[i+1][0], topY, topPoints[i+1][1]);     // top left
                        quadPoints[(i*4)+2] = new Point3f(bottomPoints[i+1][0], bottomY, bottomPoints[i+1][1]);  // bottom left
                        quadPoints[(i*4)+3] = new Point3f(bottomPoints[i][0], bottomY, bottomPoints[i][1]);    // bottom right
                }
        	
                // set the quads in the array
                result.setCoordinates(0, quadPoints);
                result.setCapability(GeometryArray.ALLOW_FORMAT_READ);
                result.setCapability(GeometryArray.ALLOW_COUNT_READ);
                result.setCapability(GeometryArray.ALLOW_COORDINATE_READ);
                result.setCapability(Geometry.ALLOW_INTERSECT);
        	
                return result; 
        }
}