Mega Code Archive

 
Categories / Java / 3D Graphics
 

Gear Test

/*  * @(#)GearTest.java 1.17 02/10/21 13:40:16  *   * Copyright (c) 1996-2002 Sun Microsystems, Inc. All Rights Reserved.  *   * Redistribution and use in source and binary forms, with or without  * modification, are permitted provided that the following conditions are met: -  * Redistributions of source code must retain the above copyright notice, this  * list of conditions and the following disclaimer. - Redistribution in binary  * form must reproduce the above copyright notice, this list of conditions and  * the following disclaimer in the documentation and/or other materials provided  * with the distribution.  *   * Neither the name of Sun Microsystems, Inc. or the names of contributors may  * be used to endorse or promote products derived from this software without  * specific prior written permission.  *   * 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.  *   * You acknowledge that Software is not designed,licensed or intended for use in  * the design, construction, operation or maintenance of any nuclear facility.  */ import java.applet.Applet; import java.awt.BorderLayout; import java.awt.GraphicsConfiguration; import javax.media.j3d.Alpha; import javax.media.j3d.AmbientLight; import javax.media.j3d.Appearance; import javax.media.j3d.Background; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.DirectionalLight; import javax.media.j3d.GeometryArray; import javax.media.j3d.Material; import javax.media.j3d.QuadArray; import javax.media.j3d.RotationInterpolator; import javax.media.j3d.Shape3D; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.media.j3d.TriangleFanArray; import javax.media.j3d.TriangleStripArray; import javax.vecmath.Color3f; import javax.vecmath.Point3d; import javax.vecmath.Point3f; import javax.vecmath.Vector3d; import javax.vecmath.Vector3f; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.behaviors.vp.OrbitBehavior; import com.sun.j3d.utils.universe.SimpleUniverse; import com.sun.j3d.utils.universe.ViewingPlatform; public class GearTest extends Applet {   static final int defaultToothCount = 24;   private int toothCount;   private SimpleUniverse u = null;   public BranchGroup createSceneGraph(int toothCount) {     // Create the root of the branch graph     BranchGroup objRoot = new BranchGroup();     // Create a Transformgroup to scale all objects so they     // appear in the scene.     TransformGroup objScale = new TransformGroup();     Transform3D t3d = new Transform3D();     t3d.setScale(0.4);     objScale.setTransform(t3d);     objRoot.addChild(objScale);     // Create a bounds for the background and lights     BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),         100.0);     // Set up the background     Color3f bgColor = new Color3f(0.05f, 0.05f, 0.2f);     Background bgNode = new Background(bgColor);     bgNode.setApplicationBounds(bounds);     objScale.addChild(bgNode);     // Set up the global lights     Color3f light1Color = new Color3f(1.0f, 1.0f, 0.9f);     Vector3f light1Direction = new Vector3f(4.0f, -7.0f, -12.0f);     Color3f light2Color = new Color3f(0.3f, 0.3f, 0.4f);     Vector3f light2Direction = new Vector3f(-6.0f, -2.0f, -1.0f);     Color3f ambientColor = new Color3f(0.1f, 0.1f, 0.1f);     AmbientLight ambientLightNode = new AmbientLight(ambientColor);     ambientLightNode.setInfluencingBounds(bounds);     objScale.addChild(ambientLightNode);     DirectionalLight light1 = new DirectionalLight(light1Color,         light1Direction);     light1.setInfluencingBounds(bounds);     objScale.addChild(light1);     DirectionalLight light2 = new DirectionalLight(light2Color,         light2Direction);     light2.setInfluencingBounds(bounds);     objScale.addChild(light2);     // Create the transform group node and initialize it to the     // identity. Enable the TRANSFORM_WRITE capability so that     // our behavior code can modify it at runtime. Add it to the     // root of the subgraph.     TransformGroup objTrans = new TransformGroup();     objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);     objScale.addChild(objTrans);     // Create an Appearance.     Appearance look = new Appearance();     Color3f objColor = new Color3f(0.5f, 0.5f, 0.6f);     Color3f black = new Color3f(0.0f, 0.0f, 0.0f);     Color3f white = new Color3f(1.0f, 1.0f, 1.0f);     look         .setMaterial(new Material(objColor, black, objColor, white,             100.0f));     // Create a gear, add it to the scene graph.     //  SpurGear gear = new SpurGear(toothCount, 1.0f, 0.2f,     SpurGear gear = new SpurGearThinBody(toothCount, 1.0f, 0.2f, 0.05f,         0.05f, 0.3f, 0.28f, look);     objTrans.addChild(gear);     // Create a new Behavior object that will rotate the object and     // add it into the scene graph.     Transform3D yAxis = new Transform3D();     Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0,         8000, 0, 0, 0, 0, 0);     RotationInterpolator rotator = new RotationInterpolator(rotationAlpha,         objTrans, yAxis, 0.0f, (float) Math.PI * 2.0f);     rotator.setSchedulingBounds(bounds);     objTrans.addChild(rotator);     // Have Java 3D perform optimizations on this scene graph.     objRoot.compile();     return objRoot;   }   public GearTest() {     this(defaultToothCount);   }   public GearTest(int toothCount) {     this.toothCount = toothCount;   }   public void init() {     setLayout(new BorderLayout());     GraphicsConfiguration config = SimpleUniverse         .getPreferredConfiguration();     Canvas3D c = new Canvas3D(config);     add("Center", c);     // Create a simple scene and attach it to the virtual universe     BranchGroup scene = createSceneGraph(toothCount);     u = new SimpleUniverse(c);     // This will move the ViewPlatform back a bit so the     // objects in the scene can be viewed.     u.getViewingPlatform().setNominalViewingTransform();     u.addBranchGraph(scene);   }   public void destroy() {     u.cleanup();   }   //   // The following allows GearTest to be run as an application   // as well as an applet   //   public static void main(String[] args) {     int value;     if (args.length > 1) {       System.out.println("Usage: java GearTest [#teeth]");       System.exit(0);     } else if (args.length == 0) {       new MainFrame(new GearTest(), 700, 700);     } else {       try {         value = Integer.parseInt(args[0]);       } catch (NumberFormatException e) {         System.out.println("Illegal integer specified");         System.out.println("Usage: java GearTest [#teeth]");         value = 0;         System.exit(0);       }       if (value <= 0) {         System.out.println("Integer must be positive (> 0)");         System.out.println("Usage: java GearBox [#teeth]");         System.exit(0);       }       new MainFrame(new GearTest(value), 700, 700);     }   } } class Gear extends javax.media.j3d.TransformGroup {   // Specifiers determining whether to generate outward facing normals or   // inward facing normals.   static final int OutwardNormals = 1;   static final int InwardNormals = -1;   // The number of teeth in the gear   int toothCount;   // Gear start differential angle. All gears are constructed with the   // center of a tooth at Z-axis angle = 0.   double gearStartAngle;   // The Z-rotation angle to place the tooth center at theta = 0   float toothTopCenterAngle;   // The Z-rotation angle to place the valley center at theta = 0   float valleyCenterAngle;   // The angle about Z subtended by one tooth and its associated valley   float circularPitchAngle;   // Increment angles   float toothValleyAngleIncrement;   // Front and rear facing normals for the gear's body   final Vector3f frontNormal = new Vector3f(0.0f, 0.0f, -1.0f);   final Vector3f rearNormal = new Vector3f(0.0f, 0.0f, 1.0f);   Gear(int toothCount) {     this.toothCount = toothCount;   }   void addBodyDisks(float shaftRadius, float bodyOuterRadius,       float thickness, Appearance look) {     int gearBodySegmentVertexCount; // #(segments) per tooth-unit     int gearBodyTotalVertexCount; // #(vertices) in a gear face     int gearBodyStripCount[] = new int[1]; // per strip (1) vertex count     // A ray from the gear center, used in normal calculations     float xDirection, yDirection;     // The x and y coordinates at each point of a facet and at each     // point on the gear: at the shaft, the root of the teeth, and     // the outer point of the teeth     float xRoot0, yRoot0, xShaft0, yShaft0;     float xRoot3, yRoot3, xShaft3, yShaft3;     float xRoot4, yRoot4, xShaft4, yShaft4;     // Temporary variables for storing coordinates and vectors     Point3f coordinate = new Point3f(0.0f, 0.0f, 0.0f);     // Gear start differential angle. All gears are constructed with the     // center of a tooth at Z-axis angle = 0.     double gearStartAngle = -1.0 * toothTopCenterAngle;     // Temporaries that store start angle for each portion of tooth facet     double toothStartAngle, toothTopStartAngle, toothDeclineStartAngle, toothValleyStartAngle, nextToothStartAngle;     Shape3D newShape;     int index;     // The z coordinates for the body disks     final float frontZ = -0.5f * thickness;     final float rearZ = 0.5f * thickness;     /*      * Construct the gear's front body (front facing torus disk) __2__ - | -      * 4 - /| /- / / | /| \ 0\ / | / / > \ / | / | > \ / | / / | \ / ____|/ | >      * \-- --__/ | 1 3 5      *        */     gearBodySegmentVertexCount = 4;     gearBodyTotalVertexCount = 2 + gearBodySegmentVertexCount * toothCount;     gearBodyStripCount[0] = gearBodyTotalVertexCount;     TriangleStripArray frontGearBody = new TriangleStripArray(         gearBodyTotalVertexCount, GeometryArray.COORDINATES             | GeometryArray.NORMALS, gearBodyStripCount);     xDirection = (float) Math.cos(gearStartAngle);     yDirection = (float) Math.sin(gearStartAngle);     xShaft0 = shaftRadius * xDirection;     yShaft0 = shaftRadius * yDirection;     xRoot0 = bodyOuterRadius * xDirection;     yRoot0 = bodyOuterRadius * yDirection;     coordinate.set(xRoot0, yRoot0, frontZ);     frontGearBody.setCoordinate(0, coordinate);     frontGearBody.setNormal(0, frontNormal);     coordinate.set(xShaft0, yShaft0, frontZ);     frontGearBody.setCoordinate(1, coordinate);     frontGearBody.setNormal(1, frontNormal);     for (int count = 0; count < toothCount; count++) {       index = 2 + count * 4;       toothStartAngle = gearStartAngle + circularPitchAngle           * (double) count;       toothValleyStartAngle = toothStartAngle + toothValleyAngleIncrement;       nextToothStartAngle = toothStartAngle + circularPitchAngle;       xDirection = (float) Math.cos(toothValleyStartAngle);       yDirection = (float) Math.sin(toothValleyStartAngle);       xShaft3 = shaftRadius * xDirection;       yShaft3 = shaftRadius * yDirection;       xRoot3 = bodyOuterRadius * xDirection;       yRoot3 = bodyOuterRadius * yDirection;       xDirection = (float) Math.cos(nextToothStartAngle);       yDirection = (float) Math.sin(nextToothStartAngle);       xShaft4 = shaftRadius * xDirection;       yShaft4 = shaftRadius * yDirection;       xRoot4 = bodyOuterRadius * xDirection;       yRoot4 = bodyOuterRadius * yDirection;       coordinate.set(xRoot3, yRoot3, frontZ);       frontGearBody.setCoordinate(index, coordinate);       frontGearBody.setNormal(index, frontNormal);       coordinate.set(xShaft3, yShaft3, frontZ);       frontGearBody.setCoordinate(index + 1, coordinate);       frontGearBody.setNormal(index + 1, frontNormal);       coordinate.set(xRoot4, yRoot4, frontZ);       frontGearBody.setCoordinate(index + 2, coordinate);       frontGearBody.setNormal(index + 2, frontNormal);       coordinate.set(xShaft4, yShaft4, frontZ);       frontGearBody.setCoordinate(index + 3, coordinate);       frontGearBody.setNormal(index + 3, frontNormal);     }     newShape = new Shape3D(frontGearBody, look);     this.addChild(newShape);     // Construct the gear's rear body (rear facing torus disc)     TriangleStripArray rearGearBody = new TriangleStripArray(         gearBodyTotalVertexCount, GeometryArray.COORDINATES             | GeometryArray.NORMALS, gearBodyStripCount);     xDirection = (float) Math.cos(gearStartAngle);     yDirection = (float) Math.sin(gearStartAngle);     xShaft0 = shaftRadius * xDirection;     yShaft0 = shaftRadius * yDirection;     xRoot0 = bodyOuterRadius * xDirection;     yRoot0 = bodyOuterRadius * yDirection;     coordinate.set(xShaft0, yShaft0, rearZ);     rearGearBody.setCoordinate(0, coordinate);     rearGearBody.setNormal(0, rearNormal);     coordinate.set(xRoot0, yRoot0, rearZ);     rearGearBody.setCoordinate(1, coordinate);     rearGearBody.setNormal(1, rearNormal);     for (int count = 0; count < toothCount; count++) {       index = 2 + count * 4;       toothStartAngle = gearStartAngle + circularPitchAngle           * (double) count;       toothValleyStartAngle = toothStartAngle + toothValleyAngleIncrement;       nextToothStartAngle = toothStartAngle + circularPitchAngle;       xDirection = (float) Math.cos(toothValleyStartAngle);       yDirection = (float) Math.sin(toothValleyStartAngle);       xShaft3 = shaftRadius * xDirection;       yShaft3 = shaftRadius * yDirection;       xRoot3 = bodyOuterRadius * xDirection;       yRoot3 = bodyOuterRadius * yDirection;       xDirection = (float) Math.cos(nextToothStartAngle);       yDirection = (float) Math.sin(nextToothStartAngle);       xShaft4 = shaftRadius * xDirection;       yShaft4 = shaftRadius * yDirection;       xRoot4 = bodyOuterRadius * xDirection;       yRoot4 = bodyOuterRadius * yDirection;       coordinate.set(xShaft3, yShaft3, rearZ);       rearGearBody.setCoordinate(index, coordinate);       rearGearBody.setNormal(index, rearNormal);       coordinate.set(xRoot3, yRoot3, rearZ);       rearGearBody.setCoordinate(index + 1, coordinate);       rearGearBody.setNormal(index + 1, rearNormal);       coordinate.set(xShaft4, yShaft4, rearZ);       rearGearBody.setCoordinate(index + 2, coordinate);       rearGearBody.setNormal(index + 2, rearNormal);       coordinate.set(xRoot4, yRoot4, rearZ);       rearGearBody.setCoordinate(index + 3, coordinate);       rearGearBody.setNormal(index + 3, rearNormal);     }     newShape = new Shape3D(rearGearBody, look);     this.addChild(newShape);   }   void addCylinderSkins(float shaftRadius, float length, int normalDirection,       Appearance look) {     int insideShaftVertexCount; // #(vertices) for shaft     int insideShaftStripCount[] = new int[1]; // #(vertices) in strip/strip     double toothStartAngle, nextToothStartAngle, toothValleyStartAngle;     // A ray from the gear center, used in normal calculations     float xDirection, yDirection;     // The z coordinates for the body disks     final float frontZ = -0.5f * length;     final float rearZ = 0.5f * length;     // Temporary variables for storing coordinates, points, and vectors     float xShaft3, yShaft3, xShaft4, yShaft4;     Point3f coordinate = new Point3f(0.0f, 0.0f, 0.0f);     Vector3f surfaceNormal = new Vector3f();     Shape3D newShape;     int index;     int firstIndex;     int secondIndex;     /*      * Construct gear's inside shaft cylinder First the tooth's up, flat      * outer, and down distances Second the tooth's flat inner distance      *       * Outward facing vertex order: 0_______2____4 | /| /| | / | / | | / | / |      * |/______|/___| 1 3 5      *       * Inward facing vertex order: 1_______3____5 |\ |\ | | \ | \ | | \ | \ |      * |______\|___\| 0 2 4      */     insideShaftVertexCount = 4 * toothCount + 2;     insideShaftStripCount[0] = insideShaftVertexCount;     TriangleStripArray insideShaft = new TriangleStripArray(         insideShaftVertexCount, GeometryArray.COORDINATES             | GeometryArray.NORMALS, insideShaftStripCount);     xShaft3 = shaftRadius * (float) Math.cos(gearStartAngle);     yShaft3 = shaftRadius * (float) Math.sin(gearStartAngle);     if (normalDirection == OutwardNormals) {       surfaceNormal.set(1.0f, 0.0f, 0.0f);       firstIndex = 1;       secondIndex = 0;     } else {       surfaceNormal.set(-1.0f, 0.0f, 0.0f);       firstIndex = 0;       secondIndex = 1;     }     // Coordinate labeled 0 in the strip     coordinate.set(shaftRadius, 0.0f, frontZ);     insideShaft.setCoordinate(firstIndex, coordinate);     insideShaft.setNormal(firstIndex, surfaceNormal);     // Coordinate labeled 1 in the strip     coordinate.set(shaftRadius, 0.0f, rearZ);     insideShaft.setCoordinate(secondIndex, coordinate);     insideShaft.setNormal(secondIndex, surfaceNormal);     for (int count = 0; count < toothCount; count++) {       index = 2 + count * 4;       toothStartAngle = circularPitchAngle * (double) count;       toothValleyStartAngle = toothStartAngle + toothValleyAngleIncrement;       nextToothStartAngle = toothStartAngle + circularPitchAngle;       xDirection = (float) Math.cos(toothValleyStartAngle);       yDirection = (float) Math.sin(toothValleyStartAngle);       xShaft3 = shaftRadius * xDirection;       yShaft3 = shaftRadius * yDirection;       if (normalDirection == OutwardNormals)         surfaceNormal.set(xDirection, yDirection, 0.0f);       else         surfaceNormal.set(-xDirection, -yDirection, 0.0f);       // Coordinate labeled 2 in the strip       coordinate.set(xShaft3, yShaft3, frontZ);       insideShaft.setCoordinate(index + firstIndex, coordinate);       insideShaft.setNormal(index + firstIndex, surfaceNormal);       // Coordinate labeled 3 in the strip       coordinate.set(xShaft3, yShaft3, rearZ);       insideShaft.setCoordinate(index + secondIndex, coordinate);       insideShaft.setNormal(index + secondIndex, surfaceNormal);       xDirection = (float) Math.cos(nextToothStartAngle);       yDirection = (float) Math.sin(nextToothStartAngle);       xShaft4 = shaftRadius * xDirection;       yShaft4 = shaftRadius * yDirection;       if (normalDirection == OutwardNormals)         surfaceNormal.set(xDirection, yDirection, 0.0f);       else         surfaceNormal.set(-xDirection, -yDirection, 0.0f);       // Coordinate labeled 4 in the strip       coordinate.set(xShaft4, yShaft4, frontZ);       insideShaft.setCoordinate(index + 2 + firstIndex, coordinate);       insideShaft.setNormal(index + 2 + firstIndex, surfaceNormal);       // Coordinate labeled 5 in the strip       coordinate.set(xShaft4, yShaft4, rearZ);       insideShaft.setCoordinate(index + 2 + secondIndex, coordinate);       insideShaft.setNormal(index + 2 + secondIndex, surfaceNormal);     }     newShape = new Shape3D(insideShaft, look);     this.addChild(newShape);   }   public float getToothTopCenterAngle() {     return toothTopCenterAngle;   }   public float getValleyCenterAngle() {     return valleyCenterAngle;   }   public float getCircularPitchAngle() {     return circularPitchAngle;   } } class GearBox extends Applet {   static final int defaultToothCount = 48;   private int toothCount;   private SimpleUniverse u = null;   public BranchGroup createGearBox(int toothCount) {     Transform3D tempTransform = new Transform3D();     // Create the root of the branch graph     BranchGroup branchRoot = createBranchEnvironment();     // Create a Transformgroup to scale all objects so they     // appear in the scene.     TransformGroup objScale = new TransformGroup();     Transform3D t3d = new Transform3D();     t3d.setScale(0.4);     objScale.setTransform(t3d);     branchRoot.addChild(objScale);     // Create an Appearance.     Appearance look = new Appearance();     Color3f objColor = new Color3f(0.5f, 0.5f, 0.6f);     Color3f black = new Color3f(0.0f, 0.0f, 0.0f);     Color3f white = new Color3f(1.0f, 1.0f, 1.0f);     look         .setMaterial(new Material(objColor, black, objColor, white,             100.0f));     // Create the transform group node and initialize it to the     // identity. Enable the TRANSFORM_WRITE capability so that     // our behavior code can modify it at runtime. Add it to the     // root of the subgraph.     TransformGroup gearboxTrans = new TransformGroup();     gearboxTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);     gearboxTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);     objScale.addChild(gearboxTrans);     // Create a bounds for the mouse behavior methods     BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),         100.0);     // Define the shaft base information     int shaftCount = 4;     int secondsPerRevolution = 8000;     // Create the Shaft(s)     Shaft shafts[] = new Shaft[shaftCount];     TransformGroup shaftTGs[] = new TransformGroup[shaftCount];     Alpha shaftAlphas[] = new Alpha[shaftCount];     RotationInterpolator shaftRotors[] = new RotationInterpolator[shaftCount];     Transform3D shaftAxis[] = new Transform3D[shaftCount];     // Note: the following arrays we're incorporated to make changing     // the gearbox easier.     float shaftRatios[] = new float[shaftCount];     shaftRatios[0] = 1.0f;     shaftRatios[1] = 0.5f;     shaftRatios[2] = 0.75f;     shaftRatios[3] = 5.0f;     float shaftRadius[] = new float[shaftCount];     shaftRadius[0] = 0.2f;     shaftRadius[1] = 0.2f;     shaftRadius[2] = 0.2f;     shaftRadius[3] = 0.2f;     float shaftLength[] = new float[shaftCount];     shaftLength[0] = 1.8f;     shaftLength[1] = 0.8f;     shaftLength[2] = 0.8f;     shaftLength[3] = 0.8f;     float shaftDirection[] = new float[shaftCount];     shaftDirection[0] = 1.0f;     shaftDirection[1] = -1.0f;     shaftDirection[2] = 1.0f;     shaftDirection[3] = -1.0f;     Vector3d shaftPlacement[] = new Vector3d[shaftCount];     shaftPlacement[0] = new Vector3d(-0.75, -0.9, 0.0);     shaftPlacement[1] = new Vector3d(0.75, -0.9, 0.0);     shaftPlacement[2] = new Vector3d(0.75, 0.35, 0.0);     shaftPlacement[3] = new Vector3d(-0.75, 0.60, -0.7);     // Create the shafts.     for (int i = 0; i < shaftCount; i++) {       shafts[i] = new Shaft(shaftRadius[i], shaftLength[i], 25, look);     }     // Create a transform group node for placing each shaft     for (int i = 0; i < shaftCount; i++) {       shaftTGs[i] = new TransformGroup();       gearboxTrans.addChild(shaftTGs[i]);       shaftTGs[i].getTransform(tempTransform);       tempTransform.setTranslation(shaftPlacement[i]);       shaftTGs[i].setTransform(tempTransform);       shaftTGs[i].addChild(shafts[i]);     }     // Add rotation interpolators to rotate the shaft in the appropriate     // direction and at the appropriate rate     for (int i = 0; i < shaftCount; i++) {       shaftAlphas[i] = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0,           (long) (secondsPerRevolution * shaftRatios[i]), 0, 0, 0, 0,           0);       shaftAxis[i] = new Transform3D();       shaftAxis[i].rotX(Math.PI / 2.0);       shaftRotors[i] = new RotationInterpolator(shaftAlphas[i],           shafts[i], shaftAxis[i], 0.0f, shaftDirection[i]               * (float) Math.PI * 2.0f);       shaftRotors[i].setSchedulingBounds(bounds);       shaftTGs[i].addChild(shaftRotors[i]);     }     // Define the gear base information. Again, these arrays exist to     // make the process of changing the GearBox via an editor faster     int gearCount = 5;     float valleyToCircularPitchRatio = .15f;     float pitchCircleRadius = 1.0f;     float addendum = 0.05f;     float dedendum = 0.05f;     float gearThickness = 0.3f;     float toothTipThickness = 0.27f;     // Create an array of gears and their associated information     SpurGear gears[] = new SpurGear[gearCount];     TransformGroup gearTGs[] = new TransformGroup[gearCount];     int gearShaft[] = new int[gearCount];     gearShaft[0] = 0;     gearShaft[1] = 1;     gearShaft[2] = 2;     gearShaft[3] = 0;     gearShaft[4] = 3;     float ratio[] = new float[gearCount];     ratio[0] = 1.0f;     ratio[1] = 0.5f;     ratio[2] = 0.75f;     ratio[3] = 0.25f;     ratio[4] = 1.25f;     Vector3d placement[] = new Vector3d[gearCount];     placement[0] = new Vector3d(0.0, 0.0, 0.0);     placement[1] = new Vector3d(0.0, 0.0, 0.0);     placement[2] = new Vector3d(0.0, 0.0, 0.0);     placement[3] = new Vector3d(0.0, 0.0, -0.7);     placement[4] = new Vector3d(0.0, 0.0, 0.0);     // Create the gears.     for (int i = 0; i < gearCount; i++) {       gears[i] = new SpurGearThinBody(           ((int) ((float) toothCount * ratio[i])), pitchCircleRadius               * ratio[i], shaftRadius[0], addendum, dedendum,           gearThickness, toothTipThickness,           valleyToCircularPitchRatio, look);     }     // Create a transform group node for arranging the gears on a shaft     // and attach the gear to its associated shaft     for (int i = 0; i < gearCount; i++) {       gearTGs[i] = new TransformGroup();       gearTGs[i].getTransform(tempTransform);       tempTransform           .rotZ((shaftDirection[gearShaft[i]] == -1.0) ? gears[i]               .getCircularPitchAngle()               / -2.0f : 0.0f);       tempTransform.setTranslation(placement[i]);       gearTGs[i].setTransform(tempTransform);       gearTGs[i].addChild(gears[i]);       shafts[gearShaft[i]].addChild(gearTGs[i]);     }     // Have Java 3D perform optimizations on this scene graph.     branchRoot.compile();     return branchRoot;   }   BranchGroup createBranchEnvironment() {     // Create the root of the branch graph     BranchGroup branchRoot = new BranchGroup();     // Create a bounds for the background and lights     BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),         100.0);     // Set up the background     Color3f bgColor = new Color3f(0.05f, 0.05f, 0.5f);     Background bgNode = new Background(bgColor);     bgNode.setApplicationBounds(bounds);     branchRoot.addChild(bgNode);     // Set up the ambient light     Color3f ambientColor = new Color3f(0.1f, 0.1f, 0.1f);     AmbientLight ambientLightNode = new AmbientLight(ambientColor);     ambientLightNode.setInfluencingBounds(bounds);     branchRoot.addChild(ambientLightNode);     // Set up the directional lights     Color3f light1Color = new Color3f(1.0f, 1.0f, 0.9f);     Vector3f light1Direction = new Vector3f(1.0f, 1.0f, 1.0f);     Color3f light2Color = new Color3f(1.0f, 1.0f, 0.9f);     Vector3f light2Direction = new Vector3f(-1.0f, -1.0f, -1.0f);     DirectionalLight light1 = new DirectionalLight(light1Color,         light1Direction);     light1.setInfluencingBounds(bounds);     branchRoot.addChild(light1);     DirectionalLight light2 = new DirectionalLight(light2Color,         light2Direction);     light2.setInfluencingBounds(bounds);     branchRoot.addChild(light2);     return branchRoot;   }   public GearBox() {     this(defaultToothCount);   }   public GearBox(int toothCount) {     this.toothCount = toothCount;   }   public void init() {     setLayout(new BorderLayout());     GraphicsConfiguration config = SimpleUniverse         .getPreferredConfiguration();     Canvas3D c = new Canvas3D(config);     add("Center", c);     // Create the gearbox and attach it to the virtual universe     BranchGroup scene = createGearBox(toothCount);     u = new SimpleUniverse(c);     // add mouse behaviors to the ViewingPlatform     ViewingPlatform viewingPlatform = u.getViewingPlatform();     // This will move the ViewPlatform back a bit so the     // objects in the scene can be viewed.     viewingPlatform.setNominalViewingTransform();     // add orbit behavior to the ViewingPlatform     OrbitBehavior orbit = new OrbitBehavior(c, OrbitBehavior.REVERSE_ALL);     BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),         100.0);     orbit.setSchedulingBounds(bounds);     viewingPlatform.setViewPlatformBehavior(orbit);     u.addBranchGraph(scene);   }   public void destroy() {     u.cleanup();   }   //   // The following allows GearBox to be run as an application   // as well as an applet   //   public static void main(String[] args) {     int value;     if (args.length > 1) {       System.out.println("Usage: java GearBox  #teeth (LCD 4)");       System.exit(0);     } else if (args.length == 0) {       new MainFrame(new GearBox(), 700, 700);     } else {       try {         value = Integer.parseInt(args[0]);       } catch (NumberFormatException e) {         System.out.println("Illegal integer specified");         System.out.println("Usage: java GearBox  #teeth (LCD 4)");         value = 0;         System.exit(0);       }       if (value <= 0 | (value % 4) != 0) {         System.out.println("Integer not a positive multiple of 4");         System.out.println("Usage: java GearBox  #teeth (LCD 4)");         System.exit(0);       }       new MainFrame(new GearBox(value), 700, 700);     }   } } class SpurGear extends Gear {   float toothTopAngleIncrement;   float toothDeclineAngleIncrement;   float rootRadius;   float outsideRadius;   //The angle subtended by the ascending or descending portion of a tooth   float circularToothEdgeAngle;   // The angle subtended by a flat (either a tooth top or a valley   // between teeth   float circularToothFlatAngle;   /**    * internal constructor for SpurGear, used by subclasses to establish    * SpurGear's required state    *     * @return a new spur gear that contains sufficient information to continue    *         building    * @param toothCount    *            number of teeth    * @param pitchCircleRadius    *            radius at center of teeth    * @param addendum    *            distance from pitch circle to top of teeth    * @param dedendum    *            distance from pitch circle to root of teeth    * @param toothToValleyAngleRatio    *            the ratio of the angle subtended by the tooth to the angle    *            subtended by the valley (must be <= .25)    */   SpurGear(int toothCount, float pitchCircleRadius, float addendum,       float dedendum, float toothToValleyAngleRatio) {     super(toothCount);     // The angle about Z subtended by one tooth and its associated valley     circularPitchAngle = (float) (2.0 * Math.PI / (double) toothCount);     // The angle subtended by a flat (either a tooth top or a valley     // between teeth     circularToothFlatAngle = circularPitchAngle * toothToValleyAngleRatio;     //The angle subtended by the ascending or descending portion of a tooth     circularToothEdgeAngle = circularPitchAngle / 2.0f         - circularToothFlatAngle;     // Increment angles     toothTopAngleIncrement = circularToothEdgeAngle;     toothDeclineAngleIncrement = toothTopAngleIncrement         + circularToothFlatAngle;     toothValleyAngleIncrement = toothDeclineAngleIncrement         + circularToothEdgeAngle;     // Differential angles for offsetting to the center of tooth's top     // and valley     toothTopCenterAngle = toothTopAngleIncrement + circularToothFlatAngle         / 2.0f;     valleyCenterAngle = toothValleyAngleIncrement + circularToothFlatAngle         / 2.0f;     // Gear start differential angle. All gears are constructed with the     // center of a tooth at Z-axis angle = 0.     gearStartAngle = -1.0 * toothTopCenterAngle;     // The radial distance to the root and top of the teeth, respectively     rootRadius = pitchCircleRadius - dedendum;     outsideRadius = pitchCircleRadius + addendum;     // Allow this object to spin. etc.     this.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);   }   /**    * Construct a SpurGear;    *     * @return a new spur gear that conforms to the input paramters    * @param toothCount    *            number of teeth    * @param pitchCircleRadius    *            radius at center of teeth    * @param shaftRadius    *            radius of hole at center    * @param addendum    *            distance from pitch circle to top of teeth    * @param dedendum    *            distance from pitch circle to root of teeth    * @param gearThickness    *            thickness of the gear    */   public SpurGear(int toothCount, float pitchCircleRadius, float shaftRadius,       float addendum, float dedendum, float gearThickness) {     this(toothCount, pitchCircleRadius, shaftRadius, addendum, dedendum,         gearThickness, gearThickness, 0.25f, null);   }   /**    * Construct a SpurGear;    *     * @return a new spur gear that conforms to the input paramters    * @param toothCount    *            number of teeth    * @param pitchCircleRadius    *            radius at center of teeth    * @param shaftRadius    *            radius of hole at center    * @param addendum    *            distance from pitch circle to top of teeth    * @param dedendum    *            distance from pitch circle to root of teeth    * @param gearThickness    *            thickness of the gear    * @param look    *            the gear's appearance    */   public SpurGear(int toothCount, float pitchCircleRadius, float shaftRadius,       float addendum, float dedendum, float gearThickness, Appearance look) {     this(toothCount, pitchCircleRadius, shaftRadius, addendum, dedendum,         gearThickness, gearThickness, 0.25f, look);   }   /**    * Construct a SpurGear;    *     * @return a new spur gear that conforms to the input paramters    * @param toothCount    *            number of teeth    * @param pitchCircleRadius    *            radius at center of teeth    * @param shaftRadius    *            radius of hole at center    * @param addendum    *            distance from pitch circle to top of teeth    * @param dedendum    *            distance from pitch circle to root of teeth    * @param gearThickness    *            thickness of the gear    * @param toothTipThickness    *            thickness of the tip of the tooth    * @param look    *            the gear's appearance    */   public SpurGear(int toothCount, float pitchCircleRadius, float shaftRadius,       float addendum, float dedendum, float gearThickness,       float toothTipThickness, Appearance look) {     this(toothCount, pitchCircleRadius, shaftRadius, addendum, dedendum,         gearThickness, toothTipThickness, 0.25f, look);   }   /**    * Construct a SpurGear;    *     * @return a new spur gear that conforms to the input paramters    * @param toothCount    *            number of teeth    * @param pitchCircleRadius    *            radius at center of teeth    * @param shaftRadius    *            radius of hole at center    * @param addendum    *            distance from pitch circle to top of teeth    * @param dedendum    *            distance from pitch circle to root of teeth    * @param gearThickness    *            thickness of the gear    * @param toothTipThickness    *            thickness of the tip of the tooth    * @param toothToValleyAngleRatio    *            the ratio of the angle subtended by the tooth to the angle    *            subtended by the valley (must be <= .25)    * @param look    *            the gear's appearance object    */   public SpurGear(int toothCount, float pitchCircleRadius, float shaftRadius,       float addendum, float dedendum, float gearThickness,       float toothTipThickness, float toothToValleyAngleRatio,       Appearance look) {     this(toothCount, pitchCircleRadius, addendum, dedendum,         toothToValleyAngleRatio);     // Generate the gear's body disks     addBodyDisks(shaftRadius, rootRadius, gearThickness, look);     // Generate the gear's interior shaft     addCylinderSkins(shaftRadius, gearThickness, InwardNormals, look);     // Generate the gear's teeth     addTeeth(pitchCircleRadius, rootRadius, outsideRadius, gearThickness,         toothTipThickness, toothToValleyAngleRatio, look);   }   /**    * Construct a SpurGear's teeth by adding the teeth shape nodes    *     * @param pitchCircleRadius    *            radius at center of teeth    * @param rootRadius    *            distance from pitch circle to top of teeth    * @param outsideRadius    *            distance from pitch circle to root of teeth    * @param gearThickness    *            thickness of the gear    * @param toothTipThickness    *            thickness of the tip of the tooth    * @param toothToValleyAngleRatio    *            the ratio of the angle subtended by the tooth to the angle    *            subtended by the valley (must be <= .25)    * @param look    *            the gear's appearance object    */   void addTeeth(float pitchCircleRadius, float rootRadius,       float outsideRadius, float gearThickness, float toothTipThickness,       float toothToValleyAngleRatio, Appearance look) {     int index;     Shape3D newShape;     // Temporaries that store start angle for each portion of tooth facet     double toothStartAngle, toothTopStartAngle, toothDeclineStartAngle, toothValleyStartAngle, nextToothStartAngle;     // The x and y coordinates at each point of a facet and at each     // point on the gear: at the shaft, the root of the teeth, and     // the outer point of the teeth     float xRoot0, yRoot0;     float xOuter1, yOuter1;     float xOuter2, yOuter2;     float xRoot3, yRoot3;     float xRoot4, yRoot4;     // The z coordinates for the gear     final float frontZ = -0.5f * gearThickness;     final float rearZ = 0.5f * gearThickness;     // The z coordinates for the tooth tip of the gear     final float toothTipFrontZ = -0.5f * toothTipThickness;     final float toothTipRearZ = 0.5f * toothTipThickness;     int toothFacetVertexCount; // #(vertices) per tooth facet     int toothFacetCount; // #(facets) per tooth     int toothFaceTotalVertexCount; // #(vertices) in all teeth     int toothFaceStripCount[] = new int[toothCount];     // per tooth vertex count     int topVertexCount; // #(vertices) for teeth tops     int topStripCount[] = new int[1]; // #(vertices) in strip/strip     // Front and rear facing normals for the teeth faces     Vector3f frontToothNormal = new Vector3f(0.0f, 0.0f, -1.0f);     Vector3f rearToothNormal = new Vector3f(0.0f, 0.0f, 1.0f);     // Normals for teeth tops up incline, tooth top, and down incline     Vector3f leftNormal = new Vector3f(-1.0f, 0.0f, 0.0f);     Vector3f rightNormal = new Vector3f(1.0f, 0.0f, 0.0f);     Vector3f outNormal = new Vector3f(1.0f, 0.0f, 0.0f);     Vector3f inNormal = new Vector3f(-1.0f, 0.0f, 0.0f);     // Temporary variables for storing coordinates and vectors     Point3f coordinate = new Point3f(0.0f, 0.0f, 0.0f);     Point3f tempCoordinate1 = new Point3f(0.0f, 0.0f, 0.0f);     Point3f tempCoordinate2 = new Point3f(0.0f, 0.0f, 0.0f);     Point3f tempCoordinate3 = new Point3f(0.0f, 0.0f, 0.0f);     Vector3f tempVector1 = new Vector3f(0.0f, 0.0f, 0.0f);     Vector3f tempVector2 = new Vector3f(0.0f, 0.0f, 0.0f);     /*      * Construct the gear's front facing teeth facets 0______2 / /\ / / \ / / \      * //___________\ 1 3      */     toothFacetVertexCount = 4;     toothFaceTotalVertexCount = toothFacetVertexCount * toothCount;     for (int i = 0; i < toothCount; i++)       toothFaceStripCount[i] = toothFacetVertexCount;     TriangleStripArray frontGearTeeth = new TriangleStripArray(         toothFaceTotalVertexCount, GeometryArray.COORDINATES             | GeometryArray.NORMALS, toothFaceStripCount);     for (int count = 0; count < toothCount; count++) {       index = count * toothFacetVertexCount;       toothStartAngle = gearStartAngle + circularPitchAngle           * (double) count;       toothTopStartAngle = toothStartAngle + toothTopAngleIncrement;       toothDeclineStartAngle = toothStartAngle           + toothDeclineAngleIncrement;       toothValleyStartAngle = toothStartAngle + toothValleyAngleIncrement;       xRoot0 = rootRadius * (float) Math.cos(toothStartAngle);       yRoot0 = rootRadius * (float) Math.sin(toothStartAngle);       xOuter1 = outsideRadius * (float) Math.cos(toothTopStartAngle);       yOuter1 = outsideRadius * (float) Math.sin(toothTopStartAngle);       xOuter2 = outsideRadius * (float) Math.cos(toothDeclineStartAngle);       yOuter2 = outsideRadius * (float) Math.sin(toothDeclineStartAngle);       xRoot3 = rootRadius * (float) Math.cos(toothValleyStartAngle);       yRoot3 = rootRadius * (float) Math.sin(toothValleyStartAngle);       tempCoordinate1.set(xRoot0, yRoot0, frontZ);       tempCoordinate2.set(xRoot3, yRoot3, frontZ);       tempVector1.sub(tempCoordinate2, tempCoordinate1);       tempCoordinate2.set(xOuter1, yOuter1, toothTipFrontZ);       tempVector2.sub(tempCoordinate2, tempCoordinate1);       frontToothNormal.cross(tempVector1, tempVector2);       frontToothNormal.normalize();       coordinate.set(xOuter1, yOuter1, toothTipFrontZ);       frontGearTeeth.setCoordinate(index, coordinate);       frontGearTeeth.setNormal(index, frontToothNormal);       coordinate.set(xRoot0, yRoot0, frontZ);       frontGearTeeth.setCoordinate(index + 1, coordinate);       frontGearTeeth.setNormal(index + 1, frontToothNormal);       coordinate.set(xOuter2, yOuter2, toothTipFrontZ);       frontGearTeeth.setCoordinate(index + 2, coordinate);       frontGearTeeth.setNormal(index + 2, frontToothNormal);       coordinate.set(xRoot3, yRoot3, frontZ);       frontGearTeeth.setCoordinate(index + 3, coordinate);       frontGearTeeth.setNormal(index + 3, frontToothNormal);     }     newShape = new Shape3D(frontGearTeeth, look);     this.addChild(newShape);     /*      * Construct the gear's rear facing teeth facets (Using Quads) 1______2 / \ / \ / \      * /____________\ 0 3      */     toothFacetVertexCount = 4;     toothFaceTotalVertexCount = toothFacetVertexCount * toothCount;     QuadArray rearGearTeeth = new QuadArray(toothCount         * toothFacetVertexCount, GeometryArray.COORDINATES         | GeometryArray.NORMALS);     for (int count = 0; count < toothCount; count++) {       index = count * toothFacetVertexCount;       toothStartAngle = gearStartAngle + circularPitchAngle           * (double) count;       toothTopStartAngle = toothStartAngle + toothTopAngleIncrement;       toothDeclineStartAngle = toothStartAngle           + toothDeclineAngleIncrement;       toothValleyStartAngle = toothStartAngle + toothValleyAngleIncrement;       xRoot0 = rootRadius * (float) Math.cos(toothStartAngle);       yRoot0 = rootRadius * (float) Math.sin(toothStartAngle);       xOuter1 = outsideRadius * (float) Math.cos(toothTopStartAngle);       yOuter1 = outsideRadius * (float) Math.sin(toothTopStartAngle);       xOuter2 = outsideRadius * (float) Math.cos(toothDeclineStartAngle);       yOuter2 = outsideRadius * (float) Math.sin(toothDeclineStartAngle);       xRoot3 = rootRadius * (float) Math.cos(toothValleyStartAngle);       yRoot3 = rootRadius * (float) Math.sin(toothValleyStartAngle);       tempCoordinate1.set(xRoot0, yRoot0, rearZ);       tempCoordinate2.set(xRoot3, yRoot3, rearZ);       tempVector1.sub(tempCoordinate2, tempCoordinate1);       tempCoordinate2.set(xOuter1, yOuter1, toothTipRearZ);       tempVector2.sub(tempCoordinate2, tempCoordinate1);       rearToothNormal.cross(tempVector2, tempVector1);       rearToothNormal.normalize();       coordinate.set(xRoot0, yRoot0, rearZ);       rearGearTeeth.setCoordinate(index, coordinate);       rearGearTeeth.setNormal(index, rearToothNormal);       coordinate.set(xOuter1, yOuter1, toothTipRearZ);       rearGearTeeth.setCoordinate(index + 1, coordinate);       rearGearTeeth.setNormal(index + 1, rearToothNormal);       coordinate.set(xOuter2, yOuter2, toothTipRearZ);       rearGearTeeth.setCoordinate(index + 2, coordinate);       rearGearTeeth.setNormal(index + 2, rearToothNormal);       coordinate.set(xRoot3, yRoot3, rearZ);       rearGearTeeth.setCoordinate(index + 3, coordinate);       rearGearTeeth.setNormal(index + 3, rearToothNormal);     }     newShape = new Shape3D(rearGearTeeth, look);     this.addChild(newShape);     /*      * Construct the gear's top teeth faces (As seen from above) Root0      * Outer1 Outer2 Root3 Root4 (RearZ) 0_______3 2_______5 4_______7      * 6_______9 |0 3| |4 7| |8 11| |12 15| | | | | | | | | | | | | | | | |      * |1_____2| |5_____6| |9____10| |13___14| 1 2 3 4 5 6 7 8 Root0 Outer1      * Outer2 Root3 Root4 (FrontZ)      *       * Quad 0123 uses a left normal Quad 2345 uses an out normal Quad 4567      * uses a right normal Quad 6789 uses an out normal      */     topVertexCount = 8 * toothCount + 2;     topStripCount[0] = topVertexCount;     toothFacetVertexCount = 4;     toothFacetCount = 4;     QuadArray topGearTeeth = new QuadArray(toothCount         * toothFacetVertexCount * toothFacetCount,         GeometryArray.COORDINATES | GeometryArray.NORMALS);     for (int count = 0; count < toothCount; count++) {       index = count * toothFacetCount * toothFacetVertexCount;       toothStartAngle = gearStartAngle + circularPitchAngle           * (double) count;       toothTopStartAngle = toothStartAngle + toothTopAngleIncrement;       toothDeclineStartAngle = toothStartAngle           + toothDeclineAngleIncrement;       toothValleyStartAngle = toothStartAngle + toothValleyAngleIncrement;       nextToothStartAngle = toothStartAngle + circularPitchAngle;       xRoot0 = rootRadius * (float) Math.cos(toothStartAngle);       yRoot0 = rootRadius * (float) Math.sin(toothStartAngle);       xOuter1 = outsideRadius * (float) Math.cos(toothTopStartAngle);       yOuter1 = outsideRadius * (float) Math.sin(toothTopStartAngle);       xOuter2 = outsideRadius * (float) Math.cos(toothDeclineStartAngle);       yOuter2 = outsideRadius * (float) Math.sin(toothDeclineStartAngle);       xRoot3 = rootRadius * (float) Math.cos(toothValleyStartAngle);       yRoot3 = rootRadius * (float) Math.sin(toothValleyStartAngle);       xRoot4 = rootRadius * (float) Math.cos(nextToothStartAngle);       yRoot4 = rootRadius * (float) Math.sin(nextToothStartAngle);       // Compute normal for quad 1       tempCoordinate1.set(xRoot0, yRoot0, frontZ);       tempCoordinate2.set(xOuter1, yOuter1, toothTipFrontZ);       tempVector1.sub(tempCoordinate2, tempCoordinate1);       leftNormal.cross(frontNormal, tempVector1);       leftNormal.normalize();       // Coordinate labeled 0 in the quad       coordinate.set(xRoot0, yRoot0, rearZ);       topGearTeeth.setCoordinate(index, coordinate);       topGearTeeth.setNormal(index, leftNormal);       // Coordinate labeled 1 in the quad       coordinate.set(tempCoordinate1);       topGearTeeth.setCoordinate(index + 1, coordinate);       topGearTeeth.setNormal(index + 1, leftNormal);       // Coordinate labeled 2 in the quad       topGearTeeth.setCoordinate(index + 2, tempCoordinate2);       topGearTeeth.setNormal(index + 2, leftNormal);       topGearTeeth.setCoordinate(index + 5, tempCoordinate2);       // Coordinate labeled 3 in the quad       coordinate.set(xOuter1, yOuter1, toothTipRearZ);       topGearTeeth.setCoordinate(index + 3, coordinate);       topGearTeeth.setNormal(index + 3, leftNormal);       topGearTeeth.setCoordinate(index + 4, coordinate);       // Compute normal for quad 2       tempCoordinate1.set(xOuter1, yOuter1, toothTipFrontZ);       tempCoordinate2.set(xOuter2, yOuter2, toothTipFrontZ);       tempVector1.sub(tempCoordinate2, tempCoordinate1);       outNormal.cross(frontNormal, tempVector1);       outNormal.normalize();       topGearTeeth.setNormal(index + 4, outNormal);       topGearTeeth.setNormal(index + 5, outNormal);       // Coordinate labeled 4 in the quad       topGearTeeth.setCoordinate(index + 6, tempCoordinate2);       topGearTeeth.setNormal(index + 6, outNormal);       topGearTeeth.setCoordinate(index + 9, tempCoordinate2);       // Coordinate labeled 5 in the quad       coordinate.set(xOuter2, yOuter2, toothTipRearZ);       topGearTeeth.setCoordinate(index + 7, coordinate);       topGearTeeth.setNormal(index + 7, outNormal);       topGearTeeth.setCoordinate(index + 8, coordinate);       // Compute normal for quad 3       tempCoordinate1.set(xOuter2, yOuter2, toothTipFrontZ);       tempCoordinate2.set(xRoot3, yRoot3, frontZ);       tempVector1.sub(tempCoordinate2, tempCoordinate1);       rightNormal.cross(frontNormal, tempVector1);       rightNormal.normalize();       topGearTeeth.setNormal(index + 8, rightNormal);       topGearTeeth.setNormal(index + 9, rightNormal);       // Coordinate labeled 7 in the quad       topGearTeeth.setCoordinate(index + 10, tempCoordinate2);       topGearTeeth.setNormal(index + 10, rightNormal);       topGearTeeth.setCoordinate(index + 13, tempCoordinate2);       // Coordinate labeled 6 in the quad       coordinate.set(xRoot3, yRoot3, rearZ);       topGearTeeth.setCoordinate(index + 11, coordinate);       topGearTeeth.setNormal(index + 11, rightNormal);       topGearTeeth.setCoordinate(index + 12, coordinate);       // Compute normal for quad 4       tempCoordinate1.set(xRoot3, yRoot3, frontZ);       tempCoordinate2.set(xRoot4, yRoot4, frontZ);       tempVector1.sub(tempCoordinate2, tempCoordinate1);       outNormal.cross(frontNormal, tempVector1);       outNormal.normalize();       topGearTeeth.setNormal(index + 12, outNormal);       topGearTeeth.setNormal(index + 13, outNormal);       // Coordinate labeled 9 in the quad       topGearTeeth.setCoordinate(index + 14, tempCoordinate2);       topGearTeeth.setNormal(index + 14, outNormal);       // Coordinate labeled 8 in the quad       coordinate.set(xRoot4, yRoot4, rearZ);       topGearTeeth.setCoordinate(index + 15, coordinate);       topGearTeeth.setNormal(index + 15, outNormal);       // Prepare for the loop by computing the new normal       toothTopStartAngle = nextToothStartAngle + toothTopAngleIncrement;       xOuter1 = outsideRadius * (float) Math.cos(toothTopStartAngle);       yOuter1 = outsideRadius * (float) Math.sin(toothTopStartAngle);       tempCoordinate1.set(xRoot4, yRoot4, toothTipFrontZ);       tempCoordinate2.set(xOuter1, yOuter1, toothTipFrontZ);       tempVector1.sub(tempCoordinate2, tempCoordinate1);       leftNormal.cross(frontNormal, tempVector1);       leftNormal.normalize();     }     newShape = new Shape3D(topGearTeeth, look);     this.addChild(newShape);   } } class SpurGearThinBody extends SpurGear {   /**    * Construct a SpurGearThinBody;    *     * @return a new spur gear that conforms to the input paramters    * @param toothCount    *            number of teeth    * @param pitchCircleRadius    *            radius at center of teeth    * @param shaftRadius    *            radius of hole at center    * @param addendum    *            distance from pitch circle to top of teeth    * @param dedendum    *            distance from pitch circle to root of teeth    * @param gearThickness    *            thickness of the gear    */   public SpurGearThinBody(int toothCount, float pitchCircleRadius,       float shaftRadius, float addendum, float dedendum,       float gearThickness) {     this(toothCount, pitchCircleRadius, shaftRadius, addendum, dedendum,         gearThickness, gearThickness, 0.25f, null);   }   /**    * Construct a SpurGearThinBody;    *     * @return a new spur gear that conforms to the input paramters    * @param toothCount    *            number of teeth    * @param pitchCircleRadius    *            radius at center of teeth    * @param shaftRadius    *            radius of hole at center    * @param addendum    *            distance from pitch circle to top of teeth    * @param dedendum    *            distance from pitch circle to root of teeth    * @param gearThickness    *            thickness of the gear    * @param look    *            the gear's appearance    */   public SpurGearThinBody(int toothCount, float pitchCircleRadius,       float shaftRadius, float addendum, float dedendum,       float gearThickness, Appearance look) {     this(toothCount, pitchCircleRadius, shaftRadius, addendum, dedendum,         gearThickness, gearThickness, 0.25f, look);   }   /**    * Construct a SpurGearThinBody;    *     * @return a new spur gear that conforms to the input paramters    * @param toothCount    *            number of teeth    * @param pitchCircleRadius    *            radius at center of teeth    * @param shaftRadius    *            radius of hole at center    * @param addendum    *            distance from pitch circle to top of teeth    * @param dedendum    *            distance from pitch circle to root of teeth    * @param gearThickness    *            thickness of the gear    * @param toothTipThickness    *            thickness of the tip of the tooth    * @param look    *            the gear's appearance    */   public SpurGearThinBody(int toothCount, float pitchCircleRadius,       float shaftRadius, float addendum, float dedendum,       float gearThickness, float toothTipThickness, Appearance look) {     this(toothCount, pitchCircleRadius, shaftRadius, addendum, dedendum,         gearThickness, toothTipThickness, 0.25f, look);   }   /**    * Construct a SpurGearThinBody;    *     * @return a new spur gear that conforms to the input paramters    * @param toothCount    *            number of teeth    * @param pitchCircleRadius    *            radius at center of teeth    * @param shaftRadius    *            radius of hole at center    * @param addendum    *            distance from pitch circle to top of teeth    * @param dedendum    *            distance from pitch circle to root of teeth    * @param gearThickness    *            thickness of the gear    * @param toothTipThickness    *            thickness of the tip of the tooth    * @param toothToValleyRatio    *            ratio of tooth valley to circular pitch (must be <= .25)    * @param look    *            the gear's appearance object    */   public SpurGearThinBody(int toothCount, float pitchCircleRadius,       float shaftRadius, float addendum, float dedendum,       float gearThickness, float toothTipThickness,       float toothToValleyAngleRatio, Appearance look) {     this(toothCount, pitchCircleRadius, shaftRadius, addendum, dedendum,         gearThickness, toothTipThickness, 0.25f, look,         0.6f * gearThickness, 0.75f * (pitchCircleRadius - shaftRadius));   }   /**    * Construct a SpurGearThinBody;    *     * @return a new spur gear that conforms to the input paramters    * @param toothCount    *            number of teeth    * @param pitchCircleRadius    *            radius at center of teeth    * @param shaftRadius    *            radius of hole at center    * @param addendum    *            distance from pitch circle to top of teeth    * @param dedendum    *            distance from pitch circle to root of teeth    * @param gearThickness    *            thickness of the gear    * @param toothTipThickness    *            thickness of the tip of the tooth    * @param toothToValleyRatio    *            ratio of tooth valley to circular pitch (must be <= .25)    * @param look    *            the gear's appearance object    * @param bodyThickness    *            the thickness of the gear body    * @param crossSectionWidth    *            the width of the depressed portion of the gear's body    */   public SpurGearThinBody(int toothCount, float pitchCircleRadius,       float shaftRadius, float addendum, float dedendum,       float gearThickness, float toothTipThickness,       float toothToValleyAngleRatio, Appearance look,       float bodyThickness, float crossSectionWidth) {     super(toothCount, pitchCircleRadius, addendum, dedendum,         toothToValleyAngleRatio);     float diskCrossSectionWidth = (rootRadius - shaftRadius - crossSectionWidth) / 2.0f;     float outerShaftRadius = shaftRadius + diskCrossSectionWidth;     float innerToothRadius = rootRadius - diskCrossSectionWidth;     // Generate the gear's body disks, first by the shaft, then in     // the body and, lastly, by the teeth     addBodyDisks(shaftRadius, outerShaftRadius, gearThickness, look);     addBodyDisks(innerToothRadius, rootRadius, gearThickness, look);     addBodyDisks(outerShaftRadius, innerToothRadius, bodyThickness, look);     // Generate the gear's "shaft" equivalents the two at the teeth     // and the two at the shaft     addCylinderSkins(innerToothRadius, gearThickness, InwardNormals, look);     addCylinderSkins(outerShaftRadius, gearThickness, OutwardNormals, look);     // Generate the gear's interior shaft     addCylinderSkins(shaftRadius, gearThickness, InwardNormals, look);     // Generate the gear's teeth     addTeeth(pitchCircleRadius, rootRadius, outsideRadius, gearThickness,         toothTipThickness, toothToValleyAngleRatio, look);   } } class Shaft extends javax.media.j3d.TransformGroup {   /**    * Construct a Shaft;    *     * @return a new shaft that with the specified radius centered about the    *         origin an laying in the XY plane and of a specified length    *         extending in the Z dimension    * @param radius    *            radius of shaft    * @param length    *            shaft length shaft extends from -length/2 to length/2 in the Z    *            dimension    * @param segmentCount    *            number of segments for the shaft face    * @param look    *            the Appearance to associate with this shaft    */   public Shaft(float radius, float length, int segmentCount, Appearance look) {     // The direction of the ray from the shaft's center     float xDirection, yDirection;     float xShaft, yShaft;     // The z coordinates for the shaft's faces (never change)     float frontZ = -0.5f * length;     float rearZ = 0.5f * length;     int shaftFaceVertexCount; // #(vertices) per shaft face     int shaftFaceTotalVertexCount; // total #(vertices) in all teeth     int shaftFaceStripCount[] = new int[1]; // per shaft vertex count     int shaftVertexCount; // #(vertices) for shaft     int shaftStripCount[] = new int[1]; // #(vertices) in strip/strip     // Front and rear facing normals for the shaft's faces     Vector3f frontNormal = new Vector3f(0.0f, 0.0f, -1.0f);     Vector3f rearNormal = new Vector3f(0.0f, 0.0f, 1.0f);     // Outward facing normal     Vector3f outNormal = new Vector3f(1.0f, 0.0f, 0.0f);     // Temporary variables for storing coordinates and vectors     Point3f coordinate = new Point3f(0.0f, 0.0f, 0.0f);     Shape3D newShape;     // The angle subtended by a single segment     double segmentAngle = 2.0 * Math.PI / segmentCount;     double tempAngle;     // Allow this object to spin. etc.     this.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);     /*      * for the forward facing fan: ___3___ - | - / | \ 4/\ | /\2 / \ | / \ / \ | / \ : \ | / :      * |--------------- *----------------| 5 0 1      *       * for backward facing fan exchange 1 with 5; 2 with 4, etc.      */     // Construct the shaft's front and rear face     shaftFaceVertexCount = segmentCount + 2;     shaftFaceStripCount[0] = shaftFaceVertexCount;     TriangleFanArray frontShaftFace = new TriangleFanArray(         shaftFaceVertexCount, GeometryArray.COORDINATES             | GeometryArray.NORMALS, shaftFaceStripCount);     TriangleFanArray rearShaftFace = new TriangleFanArray(         shaftFaceVertexCount, GeometryArray.COORDINATES             | GeometryArray.NORMALS, shaftFaceStripCount);     coordinate.set(0.0f, 0.0f, frontZ);     frontShaftFace.setCoordinate(0, coordinate);     frontShaftFace.setNormal(0, frontNormal);     coordinate.set(0.0f, 0.0f, rearZ);     rearShaftFace.setCoordinate(0, coordinate);     rearShaftFace.setNormal(0, rearNormal);     for (int index = 1; index < segmentCount + 2; index++) {       tempAngle = segmentAngle * -(double) index;       coordinate.set(radius * (float) Math.cos(tempAngle), radius           * (float) Math.sin(tempAngle), frontZ);       frontShaftFace.setCoordinate(index, coordinate);       frontShaftFace.setNormal(index, frontNormal);       tempAngle = -tempAngle;       coordinate.set(radius * (float) Math.cos(tempAngle), radius           * (float) Math.sin(tempAngle), rearZ);       rearShaftFace.setCoordinate(index, coordinate);       rearShaftFace.setNormal(index, rearNormal);     }     newShape = new Shape3D(frontShaftFace, look);     this.addChild(newShape);     newShape = new Shape3D(rearShaftFace, look);     this.addChild(newShape);     // Construct shaft's outer skin (the cylinder body)     shaftVertexCount = 2 * segmentCount + 2;     shaftStripCount[0] = shaftVertexCount;     TriangleStripArray shaft = new TriangleStripArray(shaftVertexCount,         GeometryArray.COORDINATES | GeometryArray.NORMALS,         shaftStripCount);     outNormal.set(1.0f, 0.0f, 0.0f);     coordinate.set(radius, 0.0f, rearZ);     shaft.setCoordinate(0, coordinate);     shaft.setNormal(0, outNormal);     coordinate.set(radius, 0.0f, frontZ);     shaft.setCoordinate(1, coordinate);     shaft.setNormal(1, outNormal);     for (int count = 0; count < segmentCount; count++) {       int index = 2 + count * 2;       tempAngle = segmentAngle * (double) (count + 1);       xDirection = (float) Math.cos(tempAngle);       yDirection = (float) Math.sin(tempAngle);       xShaft = radius * xDirection;       yShaft = radius * yDirection;       outNormal.set(xDirection, yDirection, 0.0f);       coordinate.set(xShaft, yShaft, rearZ);       shaft.setCoordinate(index, coordinate);       shaft.setNormal(index, outNormal);       coordinate.set(xShaft, yShaft, frontZ);       shaft.setCoordinate(index + 1, coordinate);       shaft.setNormal(index + 1, outNormal);     }     newShape = new Shape3D(shaft, look);     this.addChild(newShape);   } }