this is a last ditch attempt to get my project up and running. the deadline
is next week. i include full code below. my problems are: 1) after i've
calculated the point of intersection of the incident ray and the shape and
the direction of the refracted ray, how do i calculate the transform3d so
the next beam of light (a shape3d) is placed correctly (mine isn't) 2) how
do i determine if a point is in a shape or not, 3) how do i check if i've
specified normals to my shapes correctly

basically, if anyone can play ith this program (the main's in glassUniverse)
and make it look better, i'd be most grateful:
/////////////////////////////////////////////////////////////////////
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import com.sun.j3d.utils.applet.*;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.image.*;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.behaviors.keyboard.*;
import javax.swing.*;

public class glassUniverse extends Applet implements ActionListener
{
    // so all the rays of light start off in the same direction
    // these 2 points serve as a guide
    final Point3d origin=new Point3d(0.0f,0.0f,0.0f);
    final Vector3d rayInitialDirection=new Vector3d(2.0f,0.0f,0.0f);

    // so you don't render the scene twice
    boolean firstime=true;

 // button to trigger the refraction event
 Button doneButton;

 // the scale of the objects
 private final double scale=1;

 // a heavyweight Canvas3D so that we can render our 3D graphics
 private Canvas3D this3Dcanvas;

    // Globally used colors
    private Color3f red=new Color3f(0.9f,0.0f,0.0f);
    private Color3f indigo=new Color3f(0.9f,0.0f,0.9f);
 private Color3f black=new Color3f(0.0f,0.0f,0.0f);
 private Color3f white=new Color3f(1.0f,1.0f,1.0f);
 private Color3f lightgrey=new Color3f(0.7f,0.7f,0.7f);
 private Color3f darkgrey=new Color3f(0.2f,0.2f,0.2f);
 private Color3f blue=new Color3f(0.0
f,0.0f,0.7f);
 private Color3f green=new Color3f(0.0f,1.0f,0.0f);
 private Color3f pink=new Color3f(1.0f,0.7f,0.7f);
 private Color3f lightblue=new Color3f(0.7f,0.7f,1.0f);
 private Color3f yellow=new Color3f(0.8f,0.8f,0.0f);
 private Color3f orange=new Color3f(0.9f,0.2f,0.0f);
 private Color3f violet=new Color3f(0.8f,0.44f,0.8f);

 private Color3f[]
rainbowColours={red,orange,yellow,green,blue,indigo,violet};
 // relative indices of refraction going from air to glass
 private static double[] refractiveIndex={1.7,1.6,1.5,1.4,1.3,1.2,1.1};

 // globally used shapes
 myShape[]shapes={
     new Tetrahedron()
     //,new Octahedron()
     //,new convergingLens()
     ,new Cube()
     // ,new divergingLens()
     };


 // the glass shapes' transform groups and transforms
 TransformGroup[] individualObjTransformGrp=new
TransformGroup[shapes.length];

 // the light rays' group and transform
 TransformGroup lightTransformGrp;
 private Transform3D lightTransform;

 TransformGroup objTransGroup=new TransformGroup();

    public glassUniverse()


        // set size to maximum
  Dimension screenSize=Toolkit.getDefaultToolkit().getScreenSize();
        this.setLocation(0,0);
  this.setSize(screenSize.width,screenSize.height);

  // add instructions
  int controlPanelHeight=150;
  Panel controlPanel=new Panel();
  controlPanel.setSize(screenSize.width,controlPanelHeight);
  Label mouseinstructions=new Label("PUT A GLASS OBJECT IN FRONT OF THE RAY
OF LIGHT AND PRESS THE BUTTON.");
  Label keyinstructions=new Label("DRAG the THREE MOUSE BUTTONS (ALT-DRAG
works for the 3rd mouse button on a PC) to move the objects.");
  Label lightinstructions=new Label("Use CONTROL, ALT and SHIFT with the
ARROW KEYS to navigate.");
  controlPanel.add(mouseinstructions);
  controlPanel.add(keyinstructions);
  controlPanel.add(lightinstructions);
  doneButton=new Button("Refract light");
  doneButton.addActionListener(this);
  controlPanel.add(doneButton);

        // create the glassUniverse Canvas
        this3Dcanvas=new Canvas3D(null);

this3Dcanvas.setSize(screenSize.width,screenSize.height-controlPanelHeight);

        // Layout panels
        setLayout(new FlowLayout());
        controlPanel.setLayout(new GridLayout(4,1));
     add(controlPanel);
     add(this3Dcanvas);

        // Now that we have our Canvas3D, we are ready to build our scene
graph
        VirtualUniverse  thisUniverse = new VirtualUniverse();
        Locale thisLocale = new Locale(thisUniverse);
        // create content branch
        BranchGroup scene=createSceneGraph(this3Dcanvas);
        // Make the universe live by adding the objects to the locale
        thisLocale.addBranchGraph(scene);
    }



    public BranchGroup createSceneGraph(Canvas3D canvas)
    {
        // Create the root of the branch graph
        BranchGroup rootBranch=new BranchGroup();

        // attach the scene graph's ViewPlatform to a Canvas3D for rendering
        View thisView = new View();
        thisView.addCanvas3D(this3Dcanvas);
        // use the default PhysicalBody and PhysicalEnvironment
        PhysicalBody thisBod = new PhysicalBody();
        thisBod.setLeftEyePosition(new Point3d(-.006,0.0,0.0));// default
is(-0.033, 0.0, 0.0)
        thisBod.setRightEyePosition(new Point3d(+.006,0.0,0.0));
        thisView.setPhysicalBody(thisBod);
        thisView.setPhysicalEnvironment(new PhysicalEnvironment());
        thisView.setMonoscopicViewPolicy(View.LEFT_EYE_VIEW);

        // construct a View and connect it to our view branch's ViewPlatform
        // insert the platform into the transform group,
        // and the transform group into the branch group
        BranchGroup viewBranch=new BranchGroup();
        TransformGroup viewTransformGrp=new TransformGroup();
        Transform3D viewTransform=new Transform3D();
        Vector3d moveBack=new Vector3d(5,0,20);
     viewTransform.set(moveBack);
        viewTransformGrp.setTransform(viewTransform);
        ViewPlatform thisViewPlatform=new ViewPlatform();
        viewTransformGrp.addChild(thisViewPlatform);
        viewBranch.addChild(viewTransformGrp);
        rootBranch.addChild(viewBranch);
        // attach view to the view platform
        thisView.attachViewPlatform(thisViewPlatform);

        // add the transform group node for the glass objects
     rootBranch.addChild(objTransGroup);

     // Create a bounds for the background and behaviours
     BoundingSphere bounds=new BoundingSphere(new Point3d
     (0.0,0.0,0.0), // centre
     1000.0); // extent

     // Set up the patterned background from an image file
     /*
     TextureLoader bgTexture=new TextureLoader("Clouds.gif",this);
     Background bg=new Background(bgTexture.getImage());
     bg.setApplicationBounds(bounds);
     rootBranch.addChild(bg);
     */

     // Set up the plain white background
     Background thisBackground=new Background(white);
     thisBackground.setApplicationBounds(bounds);
     rootBranch.addChild(thisBackground);

     // Set up the global lights
     Vector3f lightDirection3DVector=new Vector3f(-1.0f,-1.0f,-1.0f);
     AmbientLight thisAmbientLight=new AmbientLight(darkgrey);
     thisAmbientLight.setInfluencingBounds(bounds);
     DirectionalLight thisDirectionalLight=
     new DirectionalLight(lightgrey,lightDirection3DVector);
     thisDirectionalLight.setInfluencingBounds(bounds);
     rootBranch.addChild(thisAmbientLight);
     rootBranch.addChild(thisDirectionalLight);

     // Set up colouring attributes
     // A ColoringAttributes node component controls shading model (flat or
Gouraud)
     // ColoringAttributes theseColouringAttributes=new
ColoringAttributes();
     // theseColouringAttributes.setColor(pink);
     Appearance thisAppearance=new Appearance();
     // thisAppearance.setColoringAttributes(theseColouringAttributes);

     // Set up the transparency amount (0.0=opaque, 1.0=invisible)
  TransparencyAttributes ta=new TransparencyAttributes();
  ta.setTransparencyMode(ta.FASTEST);
  ta.setTransparency(0.6f);
  thisAppearance.setTransparencyAttributes(ta);

  // Set up the lit solid texture map from an image file
  /*TextureLoader tex=new TextureLoader("Silver.gif",this);
  thisAppearance.setTexture(tex.getTexture());
  TextureAttributes theseTextureAttributes=new TextureAttributes();
  theseTextureAttributes.setTextureMode(TextureAttributes.MODULATE);
  thisAppearance.setTextureAttributes(theseTextureAttributes);*/

  // A Material node component controls:
        // Ambient, emissive, diffuse, and specular color, shininess factor
        Material thisMaterial=new Material();
        thisMaterial.setAmbientColor(lightgrey);
        thisMaterial.setDiffuseColor(lightblue);
        thisMaterial.setEmissiveColor(darkgrey);
        thisMaterial.setSpecularColor(white);
        thisMaterial.setShininess(70.0f);
  thisAppearance.setMaterial(thisMaterial);

     // Enable the TRANSFORM_READ/WRITE capabilities so that the behaviour
     // code can modify it at runtime
     objTransGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
     objTransGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
     objTransGroup.setCapability(Group.ALLOW_CHILDREN_EXTEND);

     // create the key behaviour so you can navigate
     KeyBehavior keyNavigationBehaviour=new KeyBehavior(objTransGroup);
  keyNavigationBehaviour.setSchedulingBounds(new BoundingSphere(new
Point3d(),1000.0));
  objTransGroup.addChild(keyNavigationBehaviour);
  // create the mouse pick behaviour so you can drag and drop objects
  PickRotateBehavior pickRotateBehaviour=new
PickRotateBehavior(rootBranch,canvas,bounds,PickObject.USE_BOUNDS);
        objTransGroup.addChild(pickRotateBehaviour);
        PickZoomBehavior pickZoomBehaviour=new
PickZoomBehavior(rootBranch,canvas,bounds,PickObject.USE_BOUNDS);
        objTransGroup.addChild(pickZoomBehaviour);
        PickTranslateBehavior pickTranslateBehaviour=new
PickTranslateBehavior(rootBranch,canvas,bounds,PickObject.USE_BOUNDS);
        objTransGroup.addChild(pickTranslateBehaviour);

     // add the glass object nodes
     for(int j=0;j<shapes.length;j++)
     {
         // an arbitrary equation that separates the objects nicely
      double xpos=(double)(j+1)*scale*4;
      objTransGroup.addChild(createObject(thisAppearance,xpos,0.0,j));
     }

        // add the light rays' transform group and transform
     lightTransformGrp=new TransformGroup();
     // set the light ray to the left of the glass objects a bit
     Vector3d thisVector3d=new Vector3d(-0.5,0.0,0.0);
     Transform3D translateLightTransform=new Transform3D();
     translateLightTransform.set(thisVector3d);
     // rotate the light ray so it's pointing at the glass objects
     Transform3D rotateLightTransform=new Transform3D();
     rotateLightTransform.rotZ(-Math.PI/2);
     // multiply these two transforms together
     lightTransform=new Transform3D();
     lightTransform.mul(translateLightTransform,rotateLightTransform);
     // set the scale
     lightTransform.setScale(scale);
     // set the group's transform
     lightTransformGrp.setTransform(lightTransform);
     // Enable the capabilities so that our behaviour code can modify it at
runtime
     lightTransformGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

lightTransformGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);

        // add the arrow of light
        // set up arrow lengths
        float arrowDiameter=0.2f;
        double arrowLength=rayInitialDirection.length();
        float arrowHeadLength=5.0f*arrowDiameter;
        float arrowHeadDiameter=2.0f*arrowDiameter;
        float cylinderLength=(float)arrowLength-arrowHeadLength;
        // Set up arrow appearance
        Appearance arrowAppearance=new Appearance();
        ColoringAttributes arrowColouringAttributes;
        arrowColouringAttributes=new ColoringAttributes();
        arrowColouringAttributes.setColor(yellow);
        arrowAppearance.setColoringAttributes(arrowColouringAttributes);
     TransparencyAttributes arrowTransparency=new TransparencyAttributes();
     arrowTransparency.setTransparencyMode(arrowTransparency.FASTEST);
     arrowTransparency.setTransparency(0.6f);
     arrowAppearance.setTransparencyAttributes(arrowTransparency);
        Material arrowMaterial=new Material();
        arrowMaterial.setAmbientColor(pink);
        arrowMaterial.setDiffuseColor(orange);
        arrowMaterial.setEmissiveColor(yellow);
        arrowMaterial.setSpecularColor(white);
        arrowMaterial.setShininess(0.0f);
     arrowAppearance.setMaterial(arrowMaterial);
        // the parts of the arrow
        Node arrowCylinder=new
Cylinder(arrowDiameter,cylinderLength,arrowAppearance);
        Node ArrowHeadCone=new
Cone(arrowHeadDiameter,arrowHeadLength,1,arrowAppearance);
        // put these 2 pieces together
        Transform3D arrowHeadTransform=new Transform3D();
        arrowHeadTransform.set(new
Vector3f(0.0f,cylinderLength/2.0f+0.5f*arrowHeadLength,0.0f));
        TransformGroup arrowHeadTransformGroup=new
TransformGroup(arrowHeadTransform);
        arrowHeadTransformGroup.addChild(ArrowHeadCone);
        lightTransformGrp.addChild(arrowHeadTransformGroup);
        lightTransformGrp.addChild(arrowCylinder);

     // add the arrow/light group to the picture
     objTransGroup.addChild(lightTransformGrp);

        // Let Java 3D perform optimisations on this scene graph.
        rootBranch.compile();

     return rootBranch;
    }

    private Group createObject(Appearance thisAppearance,double xpos,double
ypos,int index)
    {
     // Create a transform
     Transform3D objectTransform=new Transform3D();
     objectTransform.set(scale,new Vector3d(xpos,ypos,0.0));
     // attach the transform to the group
        individualObjTransformGrp[index]=new
TransformGroup(objectTransform);
     // Enable the capabilities so that our behaviour code can modify it at
runtime

individualObjTransformGrp[index].setCapability(TransformGroup.ALLOW_TRANSFOR
M_WRITE);

individualObjTransformGrp[index].setCapability(TransformGroup.ALLOW_TRANSFOR
M_READ);

individualObjTransformGrp[index].setCapability(TransformGroup.ENABLE_PICK_RE
PORTING);
     // Create a shapes leaf node and set the appearance
     shapes[index].setAppearance(thisAppearance);
     individualObjTransformGrp[index].addChild(shapes[index]);

     return individualObjTransformGrp[index];
    }

public void actionPerformed(ActionEvent evt)
    {
        if(firstime)
        {
            firstime=false;
            /*
            * To add a shapes to a live scene, create a BranchGroup, add a
            * transform group, add your shapes and then add this BranchGroup
            * to the live BranchGroup
            * (root BranchGroup)
            *
            * rootBranchGroup (live)
            *   |
            * addBranchGroup (not live until added)
            *   |
            * TransformGroup
            *   |
            * shapes
            */

            // the branch group that is added when the button is pressed to
show refraction
         BranchGroup refractionBranch=new BranchGroup();

            // number of rays I'll show; you can change this number
            int noOfRays=3;

            // comment this line back in if you want to see all the colours
            // for(int
colourIndex=0;colourIndex<rainbowColours.length;colourIndex++)
            int colourIndex=0;
            {
                // add refracted beam's transform
             TransformGroup refractionTransformGrp[]=new
TransformGroup[noOfRays];
             Transform3D[] refractionTransform=new Transform3D[noOfRays];
             for(int i=0;i<noOfRays;i++)
             {
                 refractionTransformGrp[i]=new TransformGroup();
                 refractionTransform[i]=new Transform3D();
                 // Enable the capabilities so that our behaviour code can
modify it at runtime

refractionTransformGrp[i].setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE
);

refractionTransformGrp[i].setCapability(TransformGroup.ALLOW_TRANSFORM_READ)
;
                }

                // initial start point and direction of light ray
                Point3d start=new Point3d(origin);
                Vector3d dir=new Vector3d(rayInitialDirection);

                // the transforms on the shapes
                Transform3D[] ShapeTransforms=new Transform3D[noOfRays];
                for(int
i=0;i<shapes.length;i++)ShapeTransforms[i]=getShapeTransform(i);

                // the light beams
                lightBeam[] thisLightBeam=new lightBeam[noOfRays];

                // to hold the data about the refraction
                double[] refractionVariables=new double[10];

                // to hold the refractive index
                double refractIndex=refractiveIndex[colourIndex];

                // the rotation and translation transforms for the beams
                Transform3D translateTransform=new Transform3D();
                Transform3D rotateXTransform=new Transform3D();
                Transform3D rotateYTransform=new Transform3D();
                Transform3D rotateZTransform=new Transform3D();

                for(int i=0;i<noOfRays;i++)
                {

calculateRefraction(start,dir,shapes,ShapeTransforms,refractiveIndex[colourI
ndex],refractionVariables);

                    // the rotation and translation transforms for the next
beam
                    refractionTransform[i].mul(rotateXTransform);
                    refractionTransform[i].mul(rotateYTransform);
                    refractionTransform[i].mul(rotateZTransform);
                    refractionTransform[i].mul(translateTransform);

                    // add beam of light
                    thisLightBeam[i]=new
lightBeam(rainbowColours[colourIndex]
                        ,refractionVariables[0]);

refractionTransformGrp[i].setTransform(refractionTransform[i]);
                    refractionTransformGrp[i].addChild(thisLightBeam[i]);
                    refractionBranch.addChild(refractionTransformGrp[i]);

                    // the point of intersection
                    Point3d intersectionPoint=new Point3d

(refractionVariables[3],refractionVariables[4],refractionVariables[5]);
                    // the new start and direction of light ray
                    start.set(intersectionPoint);

                    // the direction of the refracted ray
                    Vector3d refractedDirection=new Vector3d

(refractionVariables[6],refractionVariables[7],refractionVariables[8]);
                    refractedDirection.scale(refractionVariables[0]);
                    dir.set(refractedDirection);

                    translateTransform.set(new
Vector3d(refractionVariables[3]
                        ,refractionVariables[4],refractionVariables[5]));
                    rotateXTransform.rotX(refractionVariables[6]);
                    rotateYTransform.rotY(refractionVariables[7]);
                    rotateZTransform.rotZ(refractionVariables[8]);
                }
            }

            objTransGroup.addChild(refractionBranch); // now live


     }
   }

    public static void main(String[] args)
    // allows glassWorld to be run as an application
    {
     new MainFrame(new glassUniverse(),1014,700);
    }

    // returns true if this ray intersects with the shape
    // has a problem (i.e. returns false) if the ray hits an edge
    // should build in a ray intersect line method
    // parameters: the light ray start and finish and the shape index
    private boolean doesRayIntersectShape
    (Vector3d rayStart,Vector3d rayFinish,myShape[] shapes,int shapeIndex)


        // set up the ray
        rayFinish.sub(rayStart);
        PickRay ray=new PickRay(new Point3d(rayStart),new
Vector3d(rayFinish));

        // get the real vertex coordinates of the shape
        myShape thisShape=shapes[shapeIndex];
        Point3f[] faceCoords=new Point3f[thisShape.getNumberTriangles()*3];
        Point3d[]faceCoordinates=new Point3d[faceCoords.length];
        for(int i=0;i<thisShape.getNumberTriangles()*3;i++)
        {
            faceCoords[i]=new Point3f(thisShape.getTriangleCoordinates(i));
        }
        for(int i=0;i<faceCoords.length;i++)
        {
            getShapeTransform(shapeIndex).transform(faceCoords[i]);
            faceCoordinates[i]=new Point3d(faceCoords[i]);
        }

        // see if the ray intersects any of the faces
        Intersect thisIntersect=new Intersect();
        boolean toReturn=false;
        double[]dist=new double[3];
        for(int i=0;i<faceCoordinates.length;i+=3)
        {

if(thisIntersect.rayAndTriangle(ray,faceCoordinates,i,dist))toReturn=true;
        }
        return toReturn;
    }

    // parameters: the light ray start and finish, the shapes and their
transforms,
    // the light's relative refractive index
    // the refractionVariables array should be allocated by the user.
    // make sure the shapes are closed and the refractionVariables array has
a length of 9

    // refractionVariables will contain:
    // at index 0, the distance from ray start to the first intersection
    // at index 1, air to glass=0, glass to air=1
    // at index 2, a flag telling you whether it's refraction(0) or
reflection(1)
    // at indices 3,4,5 the components representing the point of
intersection
    // at indices 6,7,8 the normalised components of the direction of the
reflected/refracted ray
    public static void calculateRefraction
    (Point3d rayStart,Vector3d direction,myShape[] shapes,Transform3D[]
ShapeTransforms,
    double refractiveIndex,double[] refractionVariables)
     {
        boolean totalInternalReflection;
        Vector3d dirOfRefractedRay=new Vector3d(); // direction of
refracted/reflected ray
        Intersect thisIntersect=new Intersect();

        // set up the ray
        PickRay ray=new PickRay(rayStart,direction);
        int count=0;

        // to hold all the distances from ray start to intersection
        double[] intersectDist=new double[shapes.length*2];
        // to hold all the angles of incidence
        boolean[] isAirToGlass=new boolean[shapes.length*2];
        // to hold the refracted directions
        Vector3d[] refractedDirections=new Vector3d[shapes.length*2];
        // to hold all the normals
        Vector3d[] normals=new Vector3d[shapes.length*2];
        // to hold all the totalInternalReflections
        boolean[] totalInternalReflections=new boolean[shapes.length*2];
        for(int i=0;i<shapes.length*2;i++)
        {
            isAirToGlass[i]=true;
            refractedDirections[i]=new Vector3d();
            normals[i]=new Vector3d();
        }

        for(int shapeIndex=0;shapeIndex<shapes.length;shapeIndex++)
        {
            // get the real vertex coordinates of the shape after they've
been placed
            // in space with the shape transform
            myShape thisShape=shapes[shapeIndex];
            Point3f[] faceCoords=new
Point3f[thisShape.getNumberTriangles()*3];
            Point3d[]faceCoordinates=new Point3d[faceCoords.length];
            for(int i=0;i<thisShape.getNumberTriangles()*3;i++)
            {
                faceCoords[i]=new
Point3f(thisShape.getTriangleCoordinates(i));
            }
            for(int i=0;i<faceCoords.length;i++)
            {
                ShapeTransforms[shapeIndex].transform(faceCoords[i]);
                faceCoordinates[i]=new Point3d(faceCoords[i]);
            }

            // the distance to intersection
            double[]dist=new double[3];
            double[] distance=new double[2];
            // the direction of refraction
            Vector3d[] refractedDir={new Vector3d(),new Vector3d()};
            Vector3d[] norm={new Vector3d(),new Vector3d()};
            boolean[] reflect={false,false};

            int countFacesIntersected=0;

            // to calculate the shape face normals
            Vector3d AB=new Vector3d();
            Vector3d AC=new Vector3d();
            Vector3d normal=new Vector3d();

            // the cosine of the angle of incidence
            double cosine;

            // air to glass or glass to air
            boolean[] airOrGlass=new boolean[2];
            double actualRefractiveIndex;

            // for each shape face
            for(int i=0;i<faceCoordinates.length;i+=3)
            {
                if(thisIntersect.rayAndTriangle(ray,faceCoordinates,i,dist))
                {
                    // the distance to intersection
                    distance[countFacesIntersected]=dist[0];

                    AB.sub(faceCoordinates[i+1],faceCoordinates[i]);
                    AC.sub(faceCoordinates[i+2],faceCoordinates[i]);
                    normal.cross(AB,AC);
                    normal.normalize(); // the normal

                    norm[countFacesIntersected]=normal;

                    // check if light is going from air to glass or glass to
air
                    // check if rayStart point is on positive side of this
plane

                    boolean airGlassOrder=true;
                    airOrGlass[countFacesIntersected]=airGlassOrder;
                    if(airGlassOrder)actualRefractiveIndex=refractiveIndex;
                    else actualRefractiveIndex=1/refractiveIndex;

                    Vector3d incidentDirection=new Vector3d(direction);
                    incidentDirection.normalize(); // the vector of ray
incidence

                    // method taken from:
                    //
http://www.research.microsoft.com/~hollasch/cgindex/render/refraction.txt
                    Vector3d temp=new Vector3d();
                    double c1=incidentDirection.dot(normal);
                    double
c2=1-actualRefractiveIndex*actualRefractiveIndex*(1-c1*c1);
                    if (c2<0) totalInternalReflection=true;
                    else totalInternalReflection=false;
                    reflect[countFacesIntersected]=totalInternalReflection;

                    if(!totalInternalReflection)
                    {
                        incidentDirection.scale(actualRefractiveIndex);
                        dirOfRefractedRay.set(incidentDirection);
                        temp.set(normal);
                        temp.scale(actualRefractiveIndex*c1-Math.sqrt(c2));
                        dirOfRefractedRay.add(temp);
                    }
                    else
                    {
                        temp.set(incidentDirection);
                        double t=-2*temp.dot(normal);
                        temp.set(normal);
                        temp.scale(t);
                        temp.add(incidentDirection);
                        dirOfRefractedRay.set(temp);
                    }

                    dirOfRefractedRay.normalize();
                    refractedDir[countFacesIntersected]=dirOfRefractedRay;
//
JOptionPane.showMessageDialog(null,"refractedDir["+countFacesIntersected+"]:
"+refractedDir[countFacesIntersected].x+","+refractedDir[countFacesIntersect
ed].y+","+refractedDir[countFacesIntersected].z);
                    countFacesIntersected++;
                }
            }

            // copy the data for the 2 points of intersection with this
shape
            intersectDist[count]=distance[0];
            refractedDirections[count]=refractedDir[0];
JOptionPane.showMessageDialog(null,"distance"+intersectDist[count]);
JOptionPane.showMessageDialog(null,"refractedDirections["+count+"]:"+refract
edDirections[count].x+","+refractedDirections[count].y+","+refractedDirectio
ns[count].z);
            normals[count]=norm[0];
            totalInternalReflections[count]=reflect[0];
            isAirToGlass[count++]=airOrGlass[0];
            intersectDist[count]=distance[1];
            refractedDirections[count]=refractedDir[1];
JOptionPane.showMessageDialog(null,"distance"+intersectDist[count]);
JOptionPane.showMessageDialog(null,"refractedDirections["+count+"]:"+refract
edDirections[count].x+","+refractedDirections[count].y+","+refractedDirectio
ns[count].z);
            normals[count]=norm[1];
            totalInternalReflections[count]=reflect[1];
            isAirToGlass[count++]=airOrGlass[1];
        }// end of for each shape

        // get the index of the shortest distance, i.e. to the first
intersection
        double shortestDistance=1000000000;
        int indexOfShortest=-1;
        for(int i=0;i<shapes.length*2;i++)
        {
            if(intersectDist[i]==0)intersectDist[i]=1000000000;
            if(intersectDist[i]<=shortestDistance)
            {
                shortestDistance=intersectDist[i];
                indexOfShortest=i;
            }
        }

        // from air to glass or glass to air
        boolean airToGlass=isAirToGlass[indexOfShortest];
        if(airToGlass)refractionVariables[1]=0;
        else refractionVariables[1]=1;

        // distance to intersection
        refractionVariables[0]=shortestDistance;

        // normal to intersected face
        Vector3d normalToIntersectedFace=normals[indexOfShortest];

        // reflection or refraction
        boolean didItReflect=totalInternalReflections[indexOfShortest];
        if (didItReflect) refractionVariables[2]=1;
        else refractionVariables[2]=0;

        // calculate the point of intersection
        direction.normalize();
        // incident direction now going up to intersection
        direction.scale(refractionVariables[0]);
        Point3d intersection=new Point3d();
        intersection.set(rayStart);
        intersection.add(direction);
        refractionVariables[3]=intersection.x;
        refractionVariables[4]=intersection.y;
        refractionVariables[5]=intersection.z;

        // get the direction of the refracted ray
        refractionVariables[6]=refractedDirections[indexOfShortest].x;
        refractionVariables[7]=refractedDirections[indexOfShortest].y;
        refractionVariables[8]=refractedDirections[indexOfShortest].z;

        // check
// JOptionPane.showMessageDialog(null,"distance:"+shortestDistance);
normalToIntersectedFace.normalize();
//
JOptionPane.showMessageDialog(null,"normal:"+normalToIntersectedFace.x+","+n
ormalToIntersectedFace.y+","+normalToIntersectedFace.z);
//
JOptionPane.showMessageDialog(null,"directionOfRefractedRay:"+refractedDirec
tions[indexOfShortest].x+","+refractedDirections[indexOfShortest].y+","+refr
actedDirections[indexOfShortest].z);
//
JOptionPane.showMessageDialog(null,"intersection:"+intersection.x+","+inters
ection.y+","+intersection.z);
//
JOptionPane.showMessageDialog(null,"totalInternalReflection:"+didItReflect);
// JOptionPane.showMessageDialog(null,"airToGlass:"+airToGlass);
     }

    // returns the transform of the shapes
    // parameter: the index of the shape in the shapes array
    Transform3D getShapeTransform(int shapeIndex)
    {
        Transform3D shapeTransform=new Transform3D();
        individualObjTransformGrp[shapeIndex].getTransform(shapeTransform);
        return shapeTransform;
    }
}
/////////////////////////////////////////////////////////////////////
import javax.media.j3d.*;
import javax.vecmath.*;
import javax.swing.*;

public class Cube extends myShape
{
    private int noFaces=6;
    private int noVertices=8;
    QuadArray cube=new
QuadArray(24,QuadArray.COORDINATES|QuadArray.NORMALS|QuadArray.COLOR_3);

    private Point3f vertex0=new Point3f(1.0f,-1.0f,1.0f);
 private Point3f vertex1=new Point3f(1.0f,1.0f,1.0f);
    private Point3f vertex2=new Point3f(-1.0f,1.0f,1.0f);
    private Point3f vertex3=new Point3f(-1.0f,-1.0f,1.0f);
    private Point3f vertex4=new Point3f(-1.0f,-1.0f,-1.0f);
    private Point3f vertex5=new Point3f(-1.0f,1.0f,-1.0f);
    private Point3f vertex6=new Point3f(1.0f,1.0f,-1.0f);
    private Point3f vertex7=new Point3f(1.0f,-1.0f,-1.0f);

    private Point3f[] triangleVertices=
    {
        // front face
     vertex0, vertex1, vertex2,
     vertex0, vertex2, vertex3,
        // back face
     vertex4, vertex5, vertex6,
     vertex4, vertex6, vertex7,
        // right face
     vertex7, vertex6, vertex1,
     vertex7, vertex1, vertex0,
        // left face
     vertex3, vertex2, vertex5,
     vertex3, vertex5, vertex4,
        // top face
     vertex1, vertex6, vertex5,
     vertex1, vertex5, vertex2,
        // bottom face
     vertex3, vertex4, vertex7,
     vertex3, vertex7, vertex0
    };

    private Point3f[]verts=
    {
        // front face
     vertex0,
     vertex1,
     vertex2,
     vertex3,
        // back face
     vertex4,
     vertex5,
     vertex6,
     vertex7,
        // right face
     vertex7,
     vertex6,
     vertex1,
     vertex0,
        // left face
     vertex3,
     vertex2,
     vertex5,
     vertex4,
        // top face
     vertex1,
     vertex6,
     vertex5,
     vertex2,
        // bottom face
     vertex3,
     vertex4,
     vertex7,
     vertex0,
    };

    // set the normals
    private Vector3f[]normals=
    {
     new Vector3f(0.0f,0.0f,1.0f), // front face
     new Vector3f(0.0f,0.0f,-1.0f), // back face
     new Vector3f(1.0f,0.0f,0.0f), // right face
     new Vector3f(-1.0f,0.0f,0.0f), // left face
     new Vector3f(0.0f,1.0f,0.0f), // top face
     new Vector3f(0.0f,-1.0f,0.0f), // bottom face
    };



    public Cube()
    {
     super();
     int i;

     cube.setCoordinates(0,verts);

     // set the normal
        for(i=0;i<24;i++)
        {
            cube.setNormal(i,normals[i/4]);
        }

        // set the colours
        Color3f colour[]=new Color3f[6];
        colour[0]=new Color3f(1.0f, 0.0f, 0.0f);
        colour[1]=new Color3f(0.0f, 1.0f, 0.0f);
        colour[2]=new Color3f(0.0f, 0.0f, 1.0f);
        colour[3]=new Color3f(1.0f, 1.0f, 0.0f);
        colour[4]=new Color3f(0.0f, 1.0f, 1.0f);
        colour[5]=new Color3f(1.0f, 0.0f, 1.0f);

        for(i=0;i<24;i++)
        {
            cube.setColor(i,colour[i%6]);
        }

        setGeometry(cube);
        setAppearance(new Appearance());
    }


    public Point3f getTriangleCoordinates(int i)
    {
        return triangleVertices[i];
    }

    public String getName()
    {
        return "cube";
    }

    public int getNumberTriangles()
    {
        return 12;
    }
}

/////////////////////////////////////////////////////////////////////
import java.awt.AWTEvent;
import java.awt.event.*;
import java.util.Enumeration;
import javax.media.j3d.*;
import javax.vecmath.*;

import com.sun.j3d.utils.universe.*;


/**
 *  KeyBehavior is a generic behavior class to take key presses and move a
 *  TransformGroup through a Java3D scene. The actions resulting from the
key strokes
 *  are modified by using the Ctrl, Alt and Shift keys.
 *
 *  (version 1.0) reconstructed class to make more generic.
 *
 * MODIFIED:
 * @version 1.0, 25 September 1998 aajc
 * @author  Andrew AJ Cain, Swinburne University, Australia
 *          <[EMAIL PROTECTED]>
 *
 * edited from code by:
 *   Gary S. Moss <[EMAIL PROTECTED]>
 *   U. S. Army Research Laboratory
 *
 * CLASS NAME:
 *   KeyBehavior
 *
 * PUBLIC FEATURES:
 *   // Data
 *
 *   // Constructors
 *
 *   // Methods:
 *
 * COLLABORATORS:
 *
 */
public class KeyBehavior extends Behavior
{
  protected static final double FAST_SPEED = 2.0;
  protected static final double NORMAL_SPEED = 1.0;
  protected static final double SLOW_SPEED = 0.5;

  private TransformGroup transformGroup;
  private Transform3D transform3D;
  private WakeupCondition keyCriterion;

  private final static double TWO_PI = (2.0 * Math.PI);
  private double rotateXAmount = Math.PI / 16.0;
  private double rotateYAmount = Math.PI / 16.0;
  private double rotateZAmount = Math.PI / 16.0;

  private double moveRate = 0.3;
  private double speed = NORMAL_SPEED;

  private int forwardKey = KeyEvent.VK_UP;
  private int backKey = KeyEvent.VK_DOWN;
  private int leftKey = KeyEvent.VK_LEFT;
  private int rightKey = KeyEvent.VK_RIGHT;

  public KeyBehavior( TransformGroup tg )
  {
    transformGroup = tg;
    transform3D = new Transform3D();
  }

  public void initialize()
  {
    WakeupCriterion[] keyEvents = new WakeupCriterion[2];

    keyEvents[0] = new WakeupOnAWTEvent( KeyEvent.KEY_PRESSED );
    keyEvents[1] = new WakeupOnAWTEvent( KeyEvent.KEY_RELEASED );
    keyCriterion = new WakeupOr( keyEvents );
    wakeupOn( keyCriterion );
  }



  public void processStimulus( Enumeration criteria )
  {
    WakeupCriterion wakeup;
    AWTEvent[] event;

    while( criteria.hasMoreElements() )
    {
      wakeup = (WakeupCriterion) criteria.nextElement();
      if( !(wakeup instanceof WakeupOnAWTEvent) )
        continue;

      event = ((WakeupOnAWTEvent)wakeup).getAWTEvent();
      for( int i = 0; i < event.length; i++ )
      {
        if( event[i].getID() == KeyEvent.KEY_PRESSED )
        {
          processKeyEvent((KeyEvent)event[i]);
        }
      }
    }
    wakeupOn( keyCriterion );
  }

  protected void processKeyEvent(KeyEvent event)
  {
    int keycode = event.getKeyCode();

    if(event.isShiftDown()) speed = FAST_SPEED;
    else speed = NORMAL_SPEED;
    if( event.isAltDown() )
      altMove(keycode);
    else if( event.isControlDown())
      controlMove(keycode);
    else
      standardMove(keycode);
  }



  file://moves forward backward or rotates left right
  private void standardMove(int keycode)
  {
    if(keycode == forwardKey)
      moveForward();
    else if(keycode == backKey)
      moveBackward();
    else if(keycode == leftKey)
      rotLeft();
    else if(keycode == rightKey)
      rotRight();
  }

  file://moves left right, rotate up down
  protected void altMove(int keycode)
  {
    if(keycode == forwardKey)
      rotUp();
    else if(keycode == backKey)
      rotDown();
    else if(keycode == leftKey)
      moveLeft();
    else if(keycode == rightKey)
      moveRight();
  }

  file://move up down, rot left right
  protected void controlMove(int keycode)
  {
    if(keycode == forwardKey)
      moveUp();
    else if(keycode == backKey)
      moveDown();
    else if(keycode == leftKey)
      rollLeft();
    else if(keycode == rightKey)
      rollRight();
  }

  private void moveForward()
  {
    doMove(new Vector3d(0.0,0.0, -getMovementRate()));
  }

  private void moveBackward()
  {
    doMove(new Vector3d(0.0,0.0, getMovementRate()));
  }

  private void moveLeft()
  {
    doMove(new Vector3d( -getMovementRate() ,0.0,0.0));
  }

  private void moveRight()
  {
    doMove(new Vector3d(getMovementRate(),0.0,0.0));
  }

  private void moveUp()
  {
    doMove(new Vector3d(0.0, getMovementRate() ,0.0));
  }

  private void moveDown()
  {
    doMove(new Vector3d(0.0, -getMovementRate() ,0.0));
  }

  protected void rotRight()
  {
    doRotateY(getRotateRightAmount());
  }

  protected void rotUp()
  {
    doRotateX(getRotateUpAmount());
  }

  protected void rotLeft()
  {
    doRotateY(getRotateLeftAmount());
  }

  protected void rotDown()
  {
    doRotateX(getRotateDownAmount());
  }

  protected void rollLeft()
  {
     doRotateZ(getRollLeftAmount());
  }

  protected void rollRight()
  {
     doRotateZ(getRollRightAmount());
  }

  protected void doRotateY(double radians)
  {
    transformGroup.getTransform(transform3D);
    Transform3D toMove = new Transform3D();
    toMove.rotY(radians);
    transform3D.mul(toMove);
    transformGroup.setTransform(transform3D);
  }
  protected void doRotateX(double radians)
  {
    transformGroup.getTransform(transform3D);
    Transform3D toMove = new Transform3D();
    toMove.rotX(radians);
    transform3D.mul(toMove);
    transformGroup.setTransform(transform3D);
  }

  protected void doRotateZ(double radians)
  {
    transformGroup.getTransform(transform3D);
    Transform3D toMove = new Transform3D();
    toMove.rotZ(radians);
    transform3D.mul(toMove);
    transformGroup.setTransform(transform3D);
  }
  protected void doMove(Vector3d theMove)
  {
    transformGroup.getTransform(transform3D);
    Transform3D toMove = new Transform3D();
    toMove.setTranslation(theMove);
    transform3D.mul(toMove);
    transformGroup.setTransform(transform3D);
  }
  protected double getMovementRate()
  {
    return moveRate * speed;
  }

  protected double getRollLeftAmount()
  {
    return rotateZAmount * speed;
  }
  protected double getRollRightAmount()
  {
    return -rotateZAmount * speed;
  }

  protected double getRotateUpAmount()
  {
    return rotateYAmount * speed;
  }

  protected double getRotateDownAmount()
  {
    return -rotateYAmount * speed;
  }

  protected double getRotateLeftAmount()
  {
    return rotateYAmount * speed;
  }

  protected double getRotateRightAmount()
  {
    return -rotateYAmount * speed;
  }

  public void setRotateXAmount(double radians)
  {
    rotateXAmount = radians;
  }

  public void setRotateYAmount(double radians)
  {
    rotateYAmount = radians;
  }

  public void setRotateZAmount(double radians)
  {
    rotateZAmount = radians;
  }

  public void setMovementRate(double meters)
  {
    moveRate = meters; // Travel rate in meters/frame
  }

  public void setForwardKey(int key)
  {
    forwardKey = key;
  }

  public void setBackKey(int key)
  {
    backKey = key;
  }

  public void setLeftKey(int key)
  {
    leftKey = key;
  }

  public void setRightKey(int key)
  {
    rightKey = key;
  }
}


/////////////////////////////////////////////////////////////////////
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.behaviors.picking.*;

public class Octahedron extends myShape
{
    private Point3f vertex0=new Point3f(0.0f,0.0f,-1.5f);
 private Point3f vertex1=new Point3f(0.0f,0.0f,1.5f);
    private Point3f vertex2=new Point3f(0.0f,-1.0f,0.0f);
    private Point3f vertex3=new Point3f(0.0f,1.0f,0.0f);
    private Point3f vertex4=new Point3f(1.0f,0.0f,0.0f);
    private Point3f vertex5=new Point3f(-1.0f,0.0f,0.0f);
    private int noFaces=8;
    private int noVertices=24;
    private Point3f[] vertices=
    {
     vertex4, vertex2, vertex0, // front 4 faces
     vertex4, vertex0, vertex3,
     vertex4, vertex3, vertex1,
     vertex4, vertex1, vertex2,
     vertex5, vertex1, vertex3, // back 4 faces
     vertex5, vertex3, vertex0,
     vertex5, vertex0, vertex2,
     vertex5, vertex2, vertex1,
    };

    private Point2f texCoord[] =
    {
        new Point2f(0.0f, 0.0f),
     new Point2f(1.0f, 0.0f),
        new Point2f(0.5f,((float)Math.sqrt(3.0))/2.0f),
    };

    public Octahedron()
    {
     int i;

     TriangleArray tetra=new TriangleArray(noVertices,TriangleArray.COORDINATES|
  TriangleArray.NORMALS|TriangleArray.TEXTURE_COORDINATE_2|TriangleArray.COLOR_3);

  // set the vertex points

     tetra.setCoordinates(0,vertices);

     // set the texture coordintaes
        for (i = 0;i<noVertices;i++)
        {
            tetra.setTextureCoordinate(i,texCoord[i%3]);
        }

        // set the colours
        Color3f colour[]=new Color3f[6];
        colour[0]=new Color3f(1.0f, 0.0f, 0.0f);
        colour[1]=new Color3f(0.0f, 1.0f, 0.0f);
        colour[2]=new Color3f(0.0f, 0.0f, 1.0f);
        colour[3]=new Color3f(1.0f, 1.0f, 0.0f);
        colour[4]=new Color3f(0.0f, 1.0f, 1.0f);
        colour[5]=new Color3f(1.0f, 0.0f, 1.0f);

        for(i=0;i<noVertices;i++)
        {
            tetra.setColor(i,colour[i%6]);
        }

        // set the normals
     int face;
     Vector3f normal=new Vector3f();
     Vector3f vector1=new Vector3f();
     Vector3f vector2=new Vector3f();
     Point3f [] points=new Point3f[3];
     for(i=0;i<3;i++)points[i]=new Point3f();

     for(face=0;face<noVertices/3;face++)
     {
         tetra.getCoordinates(face*3,points);
         vector1.sub(points[1],points[0]);
         vector2.sub(points[2],points[0]);
         normal.cross(vector1,vector2);
         normal.normalize();
         for (i=0;i<3;i++)
         {
          tetra.setNormal((face*3+i),normal);
         }
     }

     // create the shape
     Appearance thisAppearance=new Appearance();
     this.setGeometry(tetra);
     this.setAppearance(thisAppearance);
    }

    public Point3f getTriangleCoordinates(int i)
    {
        return vertices[i];
    }

    public String getName()
    {
        return "octahedron";
    }

    public int getNumberTriangles()
    {
        return vertices.length/3;
    }
}

/////////////////////////////////////////////////////////////////////
/*
 * @(#)PickMouseBehavior.java 1.1 99/04/13 15:39:24
 *
 * Copyright (c) 1996-1998 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Sun grants you ("Licensee") a non-exclusive, royalty free, license to
use,
 * modify and redistribute this software in source and binary code form,
 * provided that i) this copyright notice and license appear on all copies
of
 * the software; and ii) Licensee does not utilize the software in a manner
 * which is disparaging to Sun.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
 * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
MODIFYING
 * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
ITS
 * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE
OF
 * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 * This software is not designed or intended for use in on-line control of
 * aircraft, air traffic, aircraft navigation or aircraft communications; or
in
 * the design, construction, operation or maintenance of any nuclear
 * facility. Licensee represents and warrants that it will not use or
 * redistribute the Software for such purposes.
 */

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.media.j3d.*;
import javax.vecmath.*;


/**
 * Base class that allows users to adding picking and mouse manipulation to
 * his scene graph (see PickDragBehavior for an example of how to extend
 * this base class). This class is useful for interactive apps.
 */

public abstract class PickMouseBehavior extends Behavior {

  /**
   * Portion of the scene graph to operate picking on.
   */
  protected PickObject pickScene;

  protected WakeupCriterion[] conditions;
  protected WakeupOr wakeupCondition;
  protected boolean buttonPress = false;

  protected TransformGroup currGrp;
  protected static final boolean debug = false;
  protected MouseEvent mevent;

  /**
   * Creates a PickMouseBehavior given current canvas, root of the tree to
   * operate on, and the bounds.
   */
  public PickMouseBehavior(Canvas3D canvas, BranchGroup root, Bounds
bounds){
    super();
    currGrp = new TransformGroup();
    currGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    currGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    root.addChild(currGrp);
    pickScene = new PickObject(canvas, root);
  }

  public void initialize() {

    conditions = new WakeupCriterion[2];
    conditions[0] = new WakeupOnAWTEvent(Event.MOUSE_MOVE);
    conditions[1] = new WakeupOnAWTEvent(Event.MOUSE_DOWN);
    wakeupCondition = new WakeupOr(conditions);

    wakeupOn(wakeupCondition);
  }

  private void processMouseEvent(MouseEvent evt) {
    buttonPress = false;

    if (evt.getID()==MouseEvent.MOUSE_PRESSED |
 evt.getID()==MouseEvent.MOUSE_CLICKED) {
      buttonPress = true;
      return;
    }
    else if (evt.getID() == MouseEvent.MOUSE_MOVED) {
      // Process mouse move event
    }
  }

  public void processStimulus (Enumeration criteria) {
    WakeupCriterion wakeup;
    AWTEvent[] evt = null;
    int xpos = 0, ypos = 0;

    while(criteria.hasMoreElements()) {
      wakeup = (WakeupCriterion)criteria.nextElement();
      if (wakeup instanceof WakeupOnAWTEvent)
 evt = ((WakeupOnAWTEvent)wakeup).getAWTEvent();
    }

    if (evt[0] instanceof MouseEvent){
      mevent = (MouseEvent) evt[0];

      if (debug)
 System.out.println("got mouse event");
      processMouseEvent((MouseEvent)evt[0]);
      xpos = mevent.getPoint().x;
      ypos = mevent.getPoint().y;
    }

    if (debug)
      System.out.println("mouse position " + xpos + " " + ypos);

    if (buttonPress){
      updateScene(xpos, ypos);
    }
    wakeupOn (wakeupCondition);
  }

  /**
   * Sets the pickMode for this behavior
   * @param mode The pick mode, either USE_GEOMETRY or USE_BOUNDS
   */
  public void setPickMode(int pickMode) {
    pickScene.setPickMode(pickMode);
  }

  /**
   * Returns the pickMode for this behavior
   */
  public int getPickMode() {
    return pickScene.getPickMode();
  }

  /**
   * Sets the pick geometry shape type for this behavior
   * @param type The pick shape type, either SHAPE_RAY, SHAPE_APERTURE or
   * SHAPE_RAY_APERTURE. The default is SHAPE_RAY.
   */
  public void setPickShapeMode(int type) {
    pickScene.setPickShapeMode(type);
  }

  /**
   * Returns the pick geometry shape type
   */
  public int getPickShapeMode() {
    return pickScene.getPickShapeMode();
  }

  /**
   * Sets the pick aperture for SHAPE_APERTURE mode for this behavior
   * @param Point[] aperturePts The pick aperture, which should be a convex,
   * counter-clockwise loop of Points around 0,0
   */
  public void setPickAperture(Point[] aperturePts) {
      pickScene.setPickAperture(aperturePts);
  }

  /**
   * Returns the pick aperture for SHAPE_APERTURE mode for this behavior
   */
  public Point[] getPickAperture() {
      return pickScene.getPickAperture();
  }

  /** Subclasses shall implement this update function
   */
  public abstract void updateScene(int xpos, int ypos);
}


/////////////////////////////////////////////////////////////////////
/*
 * @(#)PickZoomBehavior.java 1.1 99/04/13 15:39:26
 *
 * Copyright (c) 1996-1998 Sun Microsystems, Inc. All Rights Reserved.*/
import com.sun.j3d.utils.behaviors.mouse.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.media.j3d.*;
import javax.vecmath.*;


/**
 * A mouse behavior that allows user to pick and zoom scene graph objects.
 * Common usage: 1. Create your scene graph. 2. Create this behavior with
 * the root and canvas.
 */

public class PickZoomBehavior extends PickMouseBehavior implements
com.sun.j3d.utils.behaviors.mouse.MouseBehaviorCallback {
  MouseZoom zoom;
  private PickingCallback callback = null;
  private TransformGroup currentTG;

  /**
   * Creates a pick/zoom behavior that waits for user mouse events for
   * the scene graph. This constructor initializes the  pickMode to
   * BOUNDS picking.
   * @param root   Root of your scene graph.
   * @param canvas Java 3D drawing canvas.
   * @param bounds Bounds of your scene.
   **/

  public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
    super(canvas, root, bounds);
    zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP);
    zoom.setTransformGroup(currGrp);
    currGrp.addChild(zoom);
    zoom.setSchedulingBounds(bounds);
    this.setSchedulingBounds(bounds);
  }

  /**
   * Creates a pick/zoom behavior that waits for user mouse events for
   * the scene graph. This constructor sets the pick mode.
   * @param root   Root of your scene graph.
   * @param canvas Java 3D drawing canvas.
   * @param bounds Bounds of your scene.
   * @param pickMode specifies PickObject.USE_BOUNDS or
PickObject.USE_GEOMETRY.
   * Note: If pickMode is set to PickObject.USE_GEOMETRY, all the geometry
   * objects in the scene graph that allow picking must have the
   * ALLOW_INTERSECT bit set.
   */
  public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds,
     int pickMode){
    super(canvas, root, bounds);
    zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP);
    zoom.setTransformGroup(currGrp);
    currGrp.addChild(zoom);
    zoom.setSchedulingBounds(bounds);
    this.setSchedulingBounds(bounds);
    pickScene.setPickMode(pickMode);
  }

  /**
   * Update the scene to manipulate any nodes. This is not meant to be
   * called by users. Behavior automatically calls this. You can call
   * this only if you know what you are doing.
   *
   * @param xpos Current mouse X pos.
   * @param ypos Current mouse Y pos.
   **/

  public void updateScene(int xpos, int ypos){
    TransformGroup tg = null;

    if (mevent.isAltDown() && !mevent.isMetaDown()){

      tg =(TransformGroup)pickScene.pickNode(pickScene.pickClosest(xpos,
ypos),
          PickObject.TRANSFORM_GROUP);

      // Check for valid selection
      if ((tg != null) &&
   (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
   (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){
 zoom.setTransformGroup(tg);
 zoom.wakeup();
 currentTG = tg;
      } else if (callback!=null)
          callback.transformChanged( PickingCallback.NO_PICK, null );
    }
  }

  /**
    * Callback method from MouseZoom
    * This is used when the Picking callback is enabled
    */
  public void transformChanged( int type, Transform3D transform ) {
      callback.transformChanged( PickingCallback.ZOOM, currentTG );
  }

  /**
    * Register the class @param callback to be called each
    * time the picked object moves
    */
  public void setupCallback( PickingCallback callback ) {
      this.callback = callback;
      if (callback==null)
          zoom.setupCallback( null );
      else
          zoom.setupCallback( this );
  }
}


/////////////////////////////////////////////////////////////////////
/*
 * @(#)PickRotateBehavior.java 1.1 99/04/13 15:39:25
 *
 * Copyright (c) 1996-1998 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Sun grants you ("Licensee") a non-exclusive, royalty free, license to
use,
 * modify and redistribute this software in source and binary code form,
 * provided that i) this copyright notice and license appear on all copies
of
 * the software; and ii) Licensee does not utilize the software in a manner
 * which is disparaging to Sun.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
 * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
MODIFYING
 * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
ITS
 * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE
OF
 * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 * This software is not designed or intended for use in on-line control of
 * aircraft, air traffic, aircraft navigation or aircraft communications; or
in
 * the design, construction, operation or maintenance of any nuclear
 * facility. Licensee represents and warrants that it will not use or
 * redistribute the Software for such purposes.
 */

import com.sun.j3d.utils.behaviors.mouse.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.media.j3d.*;
import javax.vecmath.*;

/**
 * A mouse behavior that allows user to pick and drag scene graph objects.
 * Common usage:
 * <p>
 * 1. Create your scene graph.
 * <p>
 * 2. Create this behavior with root and canvas.
 * <p>
 * <blockquote><pre>
 * PickRotateBehavior behavior = new PickRotateBehavior(canvas, root,
bounds);
 *      root.addChild(behavior);
 * </pre></blockquote>
 * <p>
 * The above behavior will monitor for any picking events on
 * the scene graph (below root node) and handle mouse drags on pick hits.
 * Note the root node can also be a subgraph node of the scene graph (rather
 * than the topmost).
 */

public class PickRotateBehavior extends PickMouseBehavior implements
com.sun.j3d.utils.behaviors.mouse.MouseBehaviorCallback {
  MouseRotate drag;
  private PickingCallback callback=null;
  private TransformGroup currentTG;

  /**
   * Creates a pick/rotate behavior that waits for user mouse events for
   * the scene graph. This constructor initializes pickMode to BOUNDS
picking.
   * @param root   Root of your scene graph.
   * @param canvas Java 3D drawing canvas.
   * @param bounds Bounds of your scene.
   **/

  public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds
bounds){
    super(canvas, root, bounds);
    drag = new MouseRotate(MouseRotate.MANUAL_WAKEUP);
    drag.setTransformGroup(currGrp);
    currGrp.addChild(drag);
    drag.setSchedulingBounds(bounds);
    this.setSchedulingBounds(bounds);
  }


  /**
   * Creates a pick/rotate behavior that waits for user mouse events for
   * the scene graph. This constructor specifies the pickMode.
   * @param root   Root of your scene graph.
   * @param canvas Java 3D drawing canvas.
   * @param bounds Bounds of your scene.
   * @param pickMode specifies PickObject.USE_BOUNDS or
PickObject.USE_GEOMETRY.
   * Note: If pickMode is set to PickObject.USE_GEOMETRY, all the geometry
   * objects in the scene graph that allow picking must have the
   * ALLOW_INTERSECT bit set.
   */
  public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds
bounds,
       int pickMode) {
    super(canvas, root, bounds);
    drag = new MouseRotate(MouseRotate.MANUAL_WAKEUP);
    drag.setTransformGroup(currGrp);
    currGrp.addChild(drag);
    drag.setSchedulingBounds(bounds);
    this.setSchedulingBounds(bounds);
    pickScene.setPickMode(pickMode);
  }


  /**
   * Update the scene to manipulate any nodes. This is not meant to be
   * called by users. Behavior automatically calls this. You can call
   * this only if you know what you are doing.
   *
   * @param xpos Current mouse X pos.
   * @param ypos Current mouse Y pos.
   **/
  public void updateScene(int xpos, int ypos){
    TransformGroup tg = null;

    if (!mevent.isMetaDown() && !mevent.isAltDown()){

      tg =(TransformGroup)pickScene.pickNode(pickScene.pickClosest(xpos,
ypos),
          PickObject.TRANSFORM_GROUP);
      // Make sure the selection exists and is movable.
      if ((tg != null) &&
   (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
   (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){
 drag.setTransformGroup(tg);
 drag.wakeup();
 currentTG = tg;
      } else if (callback!=null)
 callback.transformChanged( PickingCallback.NO_PICK, null );
    }
  }

  /**
    * Callback method from MouseRotate
    * This is used when the Picking callback is enabled
    */
  public void transformChanged( int type, Transform3D transform ) {
      callback.transformChanged( PickingCallback.ROTATE, currentTG );
  }

  /**
    * Register the class @param callback to be called each
    * time the picked object moves
    */
  public void setupCallback( PickingCallback callback ) {
      this.callback = callback;
      if (callback==null)
          drag.setupCallback( null );
      else
          drag.setupCallback( this );
  }
}


/////////////////////////////////////////////////////////////////////
/*
 * @(#)PickTranslateBehavior.java 1.1 99/04/13 15:39:25
 *
 * Copyright (c) 1996-1998 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Sun grants you ("Licensee") a non-exclusive, royalty free, license to
use,
 * modify and redistribute this software in source and binary code form,
 * provided that i) this copyright notice and license appear on all copies
of
 * the software; and ii) Licensee does not utilize the software in a manner
 * which is disparaging to Sun.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
 * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
MODIFYING
 * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
ITS
 * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE
OF
 * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 * This software is not designed or intended for use in on-line control of
 * aircraft, air traffic, aircraft navigation or aircraft communications; or
in
 * the design, construction, operation or maintenance of any nuclear
 * facility. Licensee represents and warrants that it will not use or
 * redistribute the Software for such purposes.
 */

import com.sun.j3d.utils.behaviors.mouse.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.media.j3d.*;
import javax.vecmath.*;


/**
 * A mouse behavior that allows user to pick and translate scene graph
objects.
 * Common usage: 1. Create your scene graph. 2. Create this behavior with
 * the root and canvas. See PickRotateBehavior for more details.
 */

public class PickTranslateBehavior extends PickMouseBehavior implements
com.sun.j3d.utils.behaviors.mouse.MouseBehaviorCallback {
  MouseTranslate translate;
  private PickingCallback callback = null;
  private TransformGroup currentTG;

  /**
   * Creates a pick/translate behavior that waits for user mouse events for
   * the scene graph. This constructor initializes the pickMode BOUNDS
picking.
   * @param root   Root of your scene graph.
   * @param canvas Java 3D drawing canvas.
   * @param bounds Bounds of your scene.
   **/

  public PickTranslateBehavior(BranchGroup root, Canvas3D canvas, Bounds
bounds){
    super(canvas, root, bounds);
    translate = new MouseTranslate(MouseBehavior.MANUAL_WAKEUP);
    translate.setTransformGroup(currGrp);
    currGrp.addChild(translate);
    translate.setSchedulingBounds(bounds);
    this.setSchedulingBounds(bounds);
  }

  /**
   * Creates a pick/translate behavior that waits for user mouse events for
   * the scene graph. This method specifies the pick mode.
   * @param root   Root of your scene graph.
   * @param canvas Java 3D drawing canvas.
   * @param bounds Bounds of your scene.
   * @param pickMode specifies PickObject.USE_BOUNDS or
PickObject.USE_GEOMETRY.
   * Note: If pickMode is set to PickObject.USE_GEOMETRY, all the geometry
   * objects in the scene graph that allow picking must have the
   * ALLOW_INTERSECT bit set.
   */
  public PickTranslateBehavior(BranchGroup root, Canvas3D canvas, Bounds
bounds,
           int pickMode){
    super(canvas, root, bounds);
    translate = new MouseTranslate(MouseBehavior.MANUAL_WAKEUP);
    translate.setTransformGroup(currGrp);
    currGrp.addChild(translate);
    translate.setSchedulingBounds(bounds);
    this.setSchedulingBounds(bounds);
    pickScene.setPickMode(pickMode);
  }


  /**
   * Update the scene to manipulate any nodes. This is not meant to be
   * called by users. Behavior automatically calls this. You can call
   * this only if you know what you are doing.
   *
   * @param xpos Current mouse X pos.
   * @param ypos Current mouse Y pos.
   **/
  public void updateScene(int xpos, int ypos){
    TransformGroup tg = null;

    if (!mevent.isAltDown() && mevent.isMetaDown()){

      tg =(TransformGroup)pickScene.pickNode(pickScene.pickClosest(xpos,
ypos),
          PickObject.TRANSFORM_GROUP);
      file://Check for valid selection.
      if ((tg != null) &&
   (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
   (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){

 translate.setTransformGroup(tg);
 translate.wakeup();
 currentTG = tg;
      } else if (callback!=null)
 callback.transformChanged( PickingCallback.NO_PICK, null );
    }

  }

  /**
    * Callback method from MouseTranslate
    * This is used when the Picking callback is enabled
    */
  public void transformChanged( int type, Transform3D transform ) {
      callback.transformChanged( PickingCallback.TRANSLATE, currentTG );
  }

  /**
    * Register the class @param callback to be called each
    * time the picked object moves
    */
  public void setupCallback( PickingCallback callback ) {
      this.callback = callback;
      if (callback==null)
          translate.setupCallback( null );
      else
          translate.setupCallback( this );
  }

}


/////////////////////////////////////////////////////////////////////
/*
 * @(#)PickZoomBehavior.java 1.1 99/04/13 15:39:26
 *
 * Copyright (c) 1996-1998 Sun Microsystems, Inc. All Rights Reserved.*/
import com.sun.j3d.utils.behaviors.mouse.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.media.j3d.*;
import javax.vecmath.*;


/**
 * A mouse behavior that allows user to pick and zoom scene graph objects.
 * Common usage: 1. Create your scene graph. 2. Create this behavior with
 * the root and canvas.
 */

public class PickZoomBehavior extends PickMouseBehavior implements
com.sun.j3d.utils.behaviors.mouse.MouseBehaviorCallback {
  MouseZoom zoom;
  private PickingCallback callback = null;
  private TransformGroup currentTG;

  /**
   * Creates a pick/zoom behavior that waits for user mouse events for
   * the scene graph. This constructor initializes the  pickMode to
   * BOUNDS picking.
   * @param root   Root of your scene graph.
   * @param canvas Java 3D drawing canvas.
   * @param bounds Bounds of your scene.
   **/

  public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
    super(canvas, root, bounds);
    zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP);
    zoom.setTransformGroup(currGrp);
    currGrp.addChild(zoom);
    zoom.setSchedulingBounds(bounds);
    this.setSchedulingBounds(bounds);
  }

  /**
   * Creates a pick/zoom behavior that waits for user mouse events for
   * the scene graph. This constructor sets the pick mode.
   * @param root   Root of your scene graph.
   * @param canvas Java 3D drawing canvas.
   * @param bounds Bounds of your scene.
   * @param pickMode specifies PickObject.USE_BOUNDS or
PickObject.USE_GEOMETRY.
   * Note: If pickMode is set to PickObject.USE_GEOMETRY, all the geometry
   * objects in the scene graph that allow picking must have the
   * ALLOW_INTERSECT bit set.
   */
  public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds,
     int pickMode){
    super(canvas, root, bounds);
    zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP);
    zoom.setTransformGroup(currGrp);
    currGrp.addChild(zoom);
    zoom.setSchedulingBounds(bounds);
    this.setSchedulingBounds(bounds);
    pickScene.setPickMode(pickMode);
  }

  /**
   * Update the scene to manipulate any nodes. This is not meant to be
   * called by users. Behavior automatically calls this. You can call
   * this only if you know what you are doing.
   *
   * @param xpos Current mouse X pos.
   * @param ypos Current mouse Y pos.
   **/

  public void updateScene(int xpos, int ypos){
    TransformGroup tg = null;

    if (mevent.isAltDown() && !mevent.isMetaDown()){

      tg =(TransformGroup)pickScene.pickNode(pickScene.pickClosest(xpos,
ypos),
          PickObject.TRANSFORM_GROUP);

      // Check for valid selection
      if ((tg != null) &&
   (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
   (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){
 zoom.setTransformGroup(tg);
 zoom.wakeup();
 currentTG = tg;
      } else if (callback!=null)
          callback.transformChanged( PickingCallback.NO_PICK, null );
    }
  }

  /**
    * Callback method from MouseZoom
    * This is used when the Picking callback is enabled
    */
  public void transformChanged( int type, Transform3D transform ) {
      callback.transformChanged( PickingCallback.ZOOM, currentTG );
  }

  /**
    * Register the class @param callback to be called each
    * time the picked object moves
    */
  public void setupCallback( PickingCallback callback ) {
      this.callback = callback;
      if (callback==null)
          zoom.setupCallback( null );
      else
          zoom.setupCallback( this );
  }
}


/////////////////////////////////////////////////////////////////////

/*
 *      @(#)PickingCallback.java 1.1 99/04/13 15:39:26
 *
 * Copyright (c) 1996-1998 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Sun grants you ("Licensee") a non-exclusive, royalty free, license to
use,
 * modify and redistribute this software in source and binary code form,
 * provided that i) this copyright notice and license appear on all copies
of
 * the software; and ii) Licensee does not utilize the software in a manner
 * which is disparaging to Sun.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
 * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
MODIFYING
 * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
ITS
 * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE
OF
 * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 * This software is not designed or intended for use in on-line control of
 * aircraft, air traffic, aircraft navigation or aircraft communications; or
in
 * the design, construction, operation or maintenance of any nuclear
 * facility. Licensee represents and warrants that it will not use or
 * redistribute the Software for such purposes.
 */

/**
 * @Author Paul Byrne
*/

import javax.media.j3d.TransformGroup;

public interface PickingCallback {

    public final static int ROTATE=0;
    public final static int TRANSLATE=1;
    public final static int ZOOM=2;

    /**
      * The user made a selection but nothing was
      * actually picked
      */
    public final static int NO_PICK=3;

    /**
      * Called by the Pick Behavior with which this callback
      * is registered each time the Picked object is moved
      */
    public void transformChanged( int type, TransformGroup tg );
}

/////////////////////////////////////////////////////////////////////
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.behaviors.picking.*;

public class Tetrahedron extends myShape
{
 private Point3f vertex1=new Point3f(1.0f,1.0f,1.0f);
    private Point3f vertex2=new Point3f(1.0f,-1.0f,-1.0f);
    private Point3f vertex3=new Point3f(-1.0f,-1.0f,1.0f);
    private Point3f vertex4=new Point3f(-1.0f,1.0f,-1.0f);

    private Point3f[] vertices=
    {
     vertex1, vertex2, vertex4, // front face
     vertex1, vertex4, vertex3, // left, back face
     vertex2, vertex3, vertex4, // right, back face
     vertex1, vertex3, vertex2, // bottom face
    };

    private Point2f texCoord[] =
    {
        new Point2f(0.0f, 0.0f),
     new Point2f(1.0f, 0.0f),
        new Point2f(0.5f,((float)Math.sqrt(3.0))/2.0f),
    };

    public Tetrahedron()
    {
     int i;

     TriangleArray tetra=new TriangleArray(12,TriangleArray.COORDINATES|
  TriangleArray.NORMALS|TriangleArray.TEXTURE_COORDINATE_2|TriangleArray.COLOR_3);

  // set the vertex points
     tetra.setCoordinates(0,vertices);
        for (i = 0; i < 12; i++)
        {
            tetra.setTextureCoordinate(i,texCoord[i%3]);
        }

        // set the colours
        tetra.setColor(0,new Color3f(1.0f,0.0f,0.0f));
        tetra.setColor(1,new Color3f(0.0f,1.0f,0.0f));
        tetra.setColor(2,new Color3f(0.0f,0.0f,1.0f));
        tetra.setColor(3,new Color3f(1.0f,1.0f,0.0f));
        tetra.setColor(4,new Color3f(0.0f,1.0f,1.0f));
        tetra.setColor(5,new Color3f(1.0f,0.0f,1.0f));
        tetra.setColor(6,new Color3f(1
.0f,0.0f,0.0f));
        tetra.setColor(7,new Color3f(0.0f,1.0f,0.0f));
        tetra.setColor(8,new Color3f(0.0f,0.0f,1.0f));
        tetra.setColor(9,new Color3f(1.0f,1.0f,0.0f));
        tetra.setColor(10,new Color3f(0.0f,1.0f,1.0f));
        tetra.setColor(11,new Color3f(1.0f,0.0f,1.0f));

        // set the normals
     int face;
     Vector3f normal=new Vector3f();
     Vector3f vector1=new Vector3f();
     Vector3f vector2=new Vector3f();
     Point3f [] points=new Point3f[3];
     for(i=0;i<3;i++)points[i]=new Point3f();

     for(face=0;face<4;face++)
     {
         tetra.getCoordinates(face*3,points);
         vector1.sub(points[1],points[0]);
         vector2.sub(points[2],points[0]);
         normal.cross(vector1,vector2);
         normal.normalize();
         for (i=0;i<3;i++)
         {
          tetra.setNormal((face*3+i),normal);
         }
     }

     // create the shape
     Appearance thisAppearance=new Appearance();
     this.setGeometry(tetra);
     this.setAppearance(thisAppearance);
    }

    public Point3f getTriangleCoordinates(int i)
    {
        return vertices[i];
    }

    public String getName()
    {
        return "tetrahedron";
    }

    public int getNumberTriangles()
    {
        return vertices.length/3;
    }
}

/////////////////////////////////////////////////////////////////////
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.behaviors.picking.*;

public class convergingLens extends myShape
{
    private float radius=1.0f;
    private float halfOuterLength=0.4f;
    private float oneOverSquRoot2=0.707107f;
    // 8 vertices going anticlockwise round the perimeter
 private Point3f vertex0=new Point3f(radius,0.0f,0.0f);
    private Point3f vertex1=new 
Point3f(radius*oneOverSquRoot2,radius*oneOverSquRoot2,0.0f);
    private Point3f vertex2=new Point3f(0.0f,radius,0.0f);
    private Point3f vertex3=new Point3f(-radius*oneOverSquRoot2,radius*oneOver
SquRoot2,0.0f);
 private Point3f vertex4=new Point3f(-radius,0.0f,0.0f);
    private Point3f vertex5=new
Point3f(-radius*oneOverSquRoot2,-radius*oneOverSquRoot2,0.0f);
    private Point3f vertex6=new Point3f(0.0f,-radius,0.0f);
    private Point3f vertex7=new
Point3f(radius*oneOverSquRoot2,-radius*oneOverSquRoot2,0.0f);
    // vertex in front
    private Point3f vertex8=new Point3f(0.0f,0.0f,halfOuterLength);
    // vertex behind
    private Point3f vertex9=new Point3f(0.0f,0.0f,-halfOuterLength);

    private Point3f[] vertices=
    {
        // front face going anticlockwise
     vertex8, vertex0, vertex1,
     vertex8, vertex1, vertex2,
     vertex8, vertex2, vertex3,
     vertex8, vertex3, vertex4,
     vertex8, vertex4, vertex5,
     vertex8, vertex5, vertex6,
     vertex8, vertex6, vertex7,
     vertex8, vertex7, vertex0,
     // back face
     vertex9, vertex4, vertex3,
     vertex9, vertex3, vertex2,
     vertex9, vertex2, vertex1,
     vertex9, vertex1, vertex0,
     vertex9, vertex0, vertex7,
     vertex9, vertex7, vertex6,
     vertex9, vertex6, vertex5,
     vertex9, vertex5, vertex4
    };

    private Point2f texCoord[]=
    {
        new Point2f(0.0f, 0.0f),
     new Point2f(1.0f, 0.0f),
        new Point2f(0.5f,((float)Math.sqrt(3.0))/2.0f)
    };

    private Color3f colour[]=
        {
            new Color3f(1.0f, 0.0f, 0.0f),
            new Color3f(0.0f, 1.0f, 0.0f),
            new Color3f(0.0f, 0.0f, 1.0f),
            new Color3f(1.0f, 1.0f, 0.0f),
            new Color3f(0.0f, 1.0f, 1.0f),
            new Color3f(1.0f, 0.0f, 1.0f)
        };


    public convergingLens()
    {
     int i;

     TriangleArray tetra=new
TriangleArray(vertices.length,TriangleArray.COORDINATES|

TriangleArray.NORMALS|TriangleArray.TEXTURE_COORDINATE_2|TriangleArray.COLOR
_3);

  // set the vertex points
     tetra.setCoordinates(0,vertices);
        for(i=0;i<vertices.length;i++)
        {
            tetra.setTextureCoordinate(i,texCoord[i%3]);
        }

        // set the colours
        for(i=0;i<vertices.length;i++)
        {
            tetra.setColor(i,colour[i%6]);
        }

        // set the normals
     int face;
     Vector3f normal=new Vector3f();
     Vector3f vector1=new Vector3f();
     Vector3f vector2=new Vector3f();
     Point3f [] points=new Point3f[3];
     for(i=0;i<3;i++)points[i]=new Point3f();

     for(face=0;face<vertices.length/3;face++)
     {
         tetra.getCoordinates(face*3,points);
         vector1.sub(points[1],points[0]);
         vector2.sub(points[2],points[0]);
         normal.cross(vector1,vector2);
         normal.normalize();
         for (i=0;i<3;i++)
         {
          tetra.setNormal((face*3+i),normal);
         }
     }

     // create the shape
     Appearance thisAppearance=new Appearance();
     this.setGeometry(tetra);
     this.setAppearance(thisAppearance);
    }

    public String getName()
    {
        return "converging lens";
    }

    public Point3f getTriangleCoordinates(int i)
    {
        return vertices[i];
    }

    public int getNumberTriangles()
    {
        return vertices.length/3;
    }
}

/////////////////////////////////////////////////////////////////////
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.behaviors.picking.*;

public class divergingLens extends myShape
{
    private float oneOverSquRoot2=0.707107f;
    private float radius=1.0f;
    private float halflength=0.3f;
    private float halfInnerLength=0.1f;
    // 8 vertices going anticlockwise round the perimeter at the front
 private Point3f vertex0=new Point3f(radius,0.0f,halflength);
    private Point3f vertex1=new 
Point3f(radius*oneOverSquRoot2,radius*oneOverSquRoot2,halflength);
    private Point3f vertex2=new Point3f(0.0f,radius,halflength);
    private Point3f vertex3=new 
Point3f(-radius*oneOverSquRoot2,radius*oneOverSquRoot2,halflength)
;
 private Point3f vertex4=new Point3f(-radius,0.0f,halflength);
    private Point3f vertex5=new
Point3f(-radius*oneOverSquRoot2,-radius*oneOverSquRoot2,halflength);
    private Point3f vertex6=new Point3f(0.0f,-radius,halflength);
    private Point3f vertex7=new
Point3f(radius*oneOverSquRoot2,-radius*oneOverSquRoot2,halflength);
    // 8 vertices going anticlockwise round the perimeter at the back
 private Point3f vertex0b=new Point3f(radius,0.0f,-halflength);
    private Point3f vertex1b=new
Point3f(radius*oneOverSquRoot2,radius*oneOverSquRoot2,-halflength);
    private Point3f vertex2b=new Point3f(0.0f,radius,-halflength);
    private Point3f vertex3b=new
Point3f(-radius*oneOverSquRoot2,radius*oneOverSquRoot2,-halflength);
 private Point3f vertex4b=new Point3f(-radius,0.0f,-halflength);
    private Point3f vertex5b=new
Point3f(-radius*oneOverSquRoot2,-radius*oneOverSquRoot2,-halflength);
    private Point3f vertex6b=new Point3f(0.0f,-radius,-halflength);
    private Point3f vertex7b=new
Point3f(radius*oneOverSquRoot2,-radius*oneOverSquRoot2,-halflength);
    // vertex in front
    private Point3f vertex8=new Point3f(0.0f,0.0f,halfInnerLength);
    // vertex behind
    private Point3f vertex9=new Point3f(0.0f,0.0f,-halfInnerLength);

    private Point3f[] vertices=
    {
        // front face going anticlockwise
     vertex8, vertex0, vertex1,
     vertex8, vertex1, vertex2,
     vertex8, vertex2, vertex3,
     vertex8, vertex3, vertex4,
     vertex8, vertex4, vertex5,
     vertex8, vertex5, vertex6,
     vertex8, vertex6, vertex7,
     vertex8, vertex7, vertex0,
     // back face
     vertex9, vertex4b, vertex3b,
     vertex9, vertex3b, vertex2b,
     vertex9, vertex2b, vertex1b,
     vertex9, vertex1b, vertex0b,
     vertex9, vertex0b, vertex7b,
     vertex9, vertex7b, vertex6b,
     vertex9, vertex6b, vertex5b,
     vertex9, vertex5b, vertex4b,
     // sides
     vertex0, vertex0b, vertex1b,
     vertex0, vertex1b, vertex1,
     vertex1, vertex1b, vertex2b,
     vertex1, vertex2b, vertex2,
     vertex2, vertex2b, vertex3b,
     vertex2, vertex3b, vertex3,
     vertex3, vertex3b, vertex4b,
     vertex3, vertex4b, vertex4,
     vertex4, vertex4b, vertex5b,
     vertex4, vertex5b, vertex5,
     vertex5, vertex5b, vertex6b,
     vertex5, vertex6b, vertex6,
     vertex6, vertex6b, vertex7b,
     vertex6, vertex7b, vertex7,
     vertex7, vertex7b, vertex0b,
     vertex7, vertex0b, vertex0
    };

    private Point2f texCoord[] =
    {
        new Point2f(0.0f, 0.0f),
     new Point2f(1.0f, 0.0f),
        new Point2f(0.5f,((float)Math.sqrt(3.0))/2.0f)
    };

    private Color3f colour[]=
        {
            new Color3f(1.0f, 0.0f, 0.0f),
            new Color3f(0.0f, 1.0f, 0.0f),
            new Color3f(0.0f, 0.0f, 1.0f),
            new Color3f(1.0f, 1.0f, 0.0f),
            new Color3f(0.0f, 1.0f, 1.0f),
            new Color3f(1.0f, 0.0f, 1.0f)
        };

    public divergingLens()
    {
     int i;

     TriangleArray tetra=new
TriangleArray(vertices.length,TriangleArray.COORDINATES|

TriangleArray.NORMALS|TriangleArray.TEXTURE_COORDINATE_2|TriangleArray.COLOR
_3);

  // set the vertex points
     tetra.setCoordinates(0,vertices);
        for(i=0;i<vertices.length;i++)
        {
            tetra.setTextureCoordinate(i,texCoord[i%3]);
        }

        // set the colours
        for(i=0;i<vertices.length;i++)
        {
            tetra.setColor(i,colour[i%6]);
        }

        // set the normals
     int face;
     Vector3f normal=new Vector3f();
     Vector3f vector1=new Vector3f();
     Vector3f vector2=new Vector3f();
     Point3f [] points=new Point3f[3];
     for(i=0;i<3;i++)points[i]=new Point3f();

     for(face=0;face<vertices.length/3;face++)
     {
         tetra.getCoordinates(face*3,points);
         vector1.sub(points[1],points[0]);
         vector2.sub(points[2],points[0]);
         normal.cross(vector1,vector2);
         normal.normalize();
         for (i=0;i<3;i++)
         {
          tetra.setNormal((face*3+i),normal);
         }
     }

     // create the shape
     Appearance thisAppearance=new Appearance();
     this.setGeometry(tetra);
     this.setAppearance(thisAppearance);
    }

    public String getName()
    {
        return"diverging lens";
    }

    public Point3f getTriangleCoordinates(int i)
    {
        return vertices[i];
    }

    public int getNumberTriangles()
    {
        return vertices.length/3;
    }
}

/////////////////////////////////////////////////////////////////////
import javax.media.j3d.*;
import javax.vecmath.*;

public class lightBeam extends Shape3D
{
    ColoringAttributes theseColouringAttributes;
    Appearance thisAppearance=new Appearance();
    Point3f[] vertices;

    TriangleStripArray beam;

    // yellow beam, extends along x axis with a length of 5 and a radius of 0.2
    public lightBeam()
    {
        this(new Color3f(0.8f,0.8f,0.0f),0.2,5);
 }

 // Constructs a beam along x axis with a length of 5 and a radius of 0.2
 // with the specified colour
    public lightBeam(Color3f colour)
    {
        this(colour,0.2,5);
 }

 // Constructs a yellow beam along x axis with the specified length and a radius of 0.2
 public lightBeam(double thisLength)
 {
  this(new Color3f(0.8f,0.8f,0.0f),0.2,thisLength);
 }

 // Constructs a yellow beam along x axis with the specified length and a radius of 0.2
 public lightBeam(Color3f colour,double thisLength)
 {
  this(colour,0.2,thisLength);
 }

 // Constructs a lightBeam with the specified colour and geometry
 // parameters: colour, radius, length
 public lightBeam(Color3f colour,double radius,double length)
 {
     // set up the geometry array
     int segmentCount=12; // number of segments in the beam
     int beamVertexCount=(segmentCount+1)*2+2;   // number of vertices in total
     int beamStripCount[]=new int[1]; // number of
 vertices per triangle strip
        beamStripCount[0]=beamVertexCount;
        beam=new TriangleStripArray(beamVertexCount,
         GeometryArray.COORDINATES|GeometryArray.NORMALS,beamStripCount);
        // The angle subtended by a single segment
     double segmentAngle=2*Math.PI/segmentCount;
        double thisAngle=0;

        // the coordinates of a point on the perimeter
        float yCoord,zCoord;

     // The direction of a normal ray from the beam's centre
     float normalY,normalZ;

     for(int count=0;count<beamVertexCount-3;count++)
     // not very good. I've got a seam on my cylinder; overlapping
triangles!
     // I should probably use quadrilaterals
     {
   yCoord=(float)(radius*Math.cos(thisAngle));
   zCoord=(float)(radius*Math.sin(thisAngle));
   normalY=(float)Math.sin(thisAngle);
         normalZ=(float)Math.cos(thisAngle);
   beam.setCoordinate(count,new float[]{(float)length,yCoord,zCoord});
   beam.setNormal(count,new float[]{(float)length,normalY,normalZ});
   count++;
   beam.setCoordinate(count,new float[]{0f,yCoord,zCoord});
   beam.setNormal(count,new float[]{0f,normalY,normalZ});
            thisAngle+=segmentAngle;
  }

     setGeometry(beam);

     // Set up ray appearance and colouring capability
     theseColouringAttributes=new ColoringAttributes();
     Color3f yellow=new Color3f(0.8f,0.8f,0.0f);
     theseColouringAttributes.setColor(yellow);
     thisAppearance.setColoringAttributes(theseColouringAttributes);
     TransparencyAttributes rayTransparency=new TransparencyAttributes();
     rayTransparency.setTransparencyMode(rayTransparency.FASTEST);
     rayTransparency.setTransparency(0.7f);
     thisAppearance.setTransparencyAttributes(rayTransparency);
     Material rayMaterial=new Material();
     Color3f pink=new Color3f(1.0f,0.7f,0.7f);
     rayMaterial.setAmbientColor(pink);
     rayMaterial.setDiffuseColor(yellow);
     rayMaterial.setEmissiveColor(colour);
     Color3f white=new Color3f(1.0f,1.0f,1.0f);
     rayMaterial.setSpecularColor(white);
     rayMaterial.setShininess(0.0f);
     thisAppearance.setMaterial(rayMaterial);
        setAppearance(thisAppearance);
  setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
  thisAppearance.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE);

theseColouringAttributes.setCapability(ColoringAttributes.ALLOW_COLOR_WRITE)
;
  setColour(colour);
 }

 // Sets the colour of the line
 public void setColour(Color3f colour)
 {
  theseColouringAttributes.setColor(colour);
  thisAppearance.setColoringAttributes(theseColouringAttributes);
  setAppearance(thisAppearance);
 }
}

/////////////////////////////////////////////////////////////////////
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.behaviors.picking.*;

public abstract class myShape extends Shape3D
{
    // Sole constructor
    public myShape(){}

    // name
    abstract public String getName();

    // the point in the triangle array
    abstract public Point3f getTriangleCoordinates(int index);

    abstract public int getNumberTriangles();
}

/////////////////////////////////////////////////////////////////////

===========================================================================
To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
of the message "signoff JAVA3D-INTEREST".  For general help, send email to
[EMAIL PROTECTED] and include in the body of the message "help".

Reply via email to