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