it's ok, no response required. i'm well on my way to solving this.

Shamim Khaliq  [EMAIL PROTECTED] <http://www.shamimkhaliq.co.uk/>
----- Original Message -----
From: Shamim Khaliq <[EMAIL PROTECTED]>
To: <[EMAIL PROTECTED]>
Sent: Thursday, April 19, 2001 11:03 AM
Subject: modelling the refraction of light


> 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()
>      file://,new Octahedron()
>      file://,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