Java/3D/Gear

Материал из Java эксперт
Перейти к: навигация, поиск

Gear Test

   <source lang="java">

/*

* @(#)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.rupile();
   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.rupile();
   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);
 }

}


      </source>