001: /*
002: * $RCSfile: Gear.java,v $
003: *
004: * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * - Redistribution of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * - Redistribution in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * Neither the name of Sun Microsystems, Inc. or the names of
019: * contributors may be used to endorse or promote products derived
020: * from this software without specific prior written permission.
021: *
022: * This software is provided "AS IS," without a warranty of any
023: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
024: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
025: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
026: * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
027: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
028: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
029: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
030: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
031: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
032: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
033: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
034: * POSSIBILITY OF SUCH DAMAGES.
035: *
036: * You acknowledge that this software is not designed, licensed or
037: * intended for use in the design, construction, operation or
038: * maintenance of any nuclear facility.
039: *
040: * $Revision: 1.2 $
041: * $Date: 2007/02/09 17:21:38 $
042: * $State: Exp $
043: */
044:
045: package org.jdesktop.j3d.examples.gears;
046:
047: import java.lang.Math.*;
048: import javax.media.j3d.*;
049: import javax.vecmath.*;
050:
051: public class Gear extends javax.media.j3d.TransformGroup {
052:
053: // Specifiers determining whether to generate outward facing normals or
054: // inward facing normals.
055: static final int OutwardNormals = 1;
056: static final int InwardNormals = -1;
057:
058: // The number of teeth in the gear
059: int toothCount;
060:
061: // Gear start differential angle. All gears are constructed with the
062: // center of a tooth at Z-axis angle = 0.
063: double gearStartAngle;
064: // The Z-rotation angle to place the tooth center at theta = 0
065: float toothTopCenterAngle;
066: // The Z-rotation angle to place the valley center at theta = 0
067: float valleyCenterAngle;
068: // The angle about Z subtended by one tooth and its associated valley
069: float circularPitchAngle;
070:
071: // Increment angles
072: float toothValleyAngleIncrement;
073:
074: // Front and rear facing normals for the gear's body
075: final Vector3f frontNormal = new Vector3f(0.0f, 0.0f, -1.0f);
076: final Vector3f rearNormal = new Vector3f(0.0f, 0.0f, 1.0f);
077:
078: Gear(int toothCount) {
079: this .toothCount = toothCount;
080: }
081:
082: void addBodyDisks(float shaftRadius, float bodyOuterRadius,
083: float thickness, Appearance look) {
084: int gearBodySegmentVertexCount; // #(segments) per tooth-unit
085: int gearBodyTotalVertexCount; // #(vertices) in a gear face
086: int gearBodyStripCount[] = new int[1]; // per strip (1) vertex count
087:
088: // A ray from the gear center, used in normal calculations
089: float xDirection, yDirection;
090:
091: // The x and y coordinates at each point of a facet and at each
092: // point on the gear: at the shaft, the root of the teeth, and
093: // the outer point of the teeth
094: float xRoot0, yRoot0, xShaft0, yShaft0;
095: float xRoot3, yRoot3, xShaft3, yShaft3;
096: float xRoot4, yRoot4, xShaft4, yShaft4;
097:
098: // Temporary variables for storing coordinates and vectors
099: Point3f coordinate = new Point3f(0.0f, 0.0f, 0.0f);
100:
101: // Gear start differential angle. All gears are constructed with the
102: // center of a tooth at Z-axis angle = 0.
103: double gearStartAngle = -1.0 * toothTopCenterAngle;
104:
105: // Temporaries that store start angle for each portion of tooth facet
106: double toothStartAngle, toothTopStartAngle, toothDeclineStartAngle, toothValleyStartAngle, nextToothStartAngle;
107:
108: Shape3D newShape;
109: int index;
110:
111: // The z coordinates for the body disks
112: final float frontZ = -0.5f * thickness;
113: final float rearZ = 0.5f * thickness;
114:
115: /* Construct the gear's front body (front facing torus disk)
116: * __2__
117: * - | - 4
118: * - /| /-
119: * / / | /| \
120: * 0\ / | / / >
121: * \ / | / | >
122: * \ / | / / |
123: * \ / ____|/ | >
124: * \-- --__/ |
125: * 1 3 5
126: *
127: */
128: gearBodySegmentVertexCount = 4;
129: gearBodyTotalVertexCount = 2 + gearBodySegmentVertexCount
130: * toothCount;
131: gearBodyStripCount[0] = gearBodyTotalVertexCount;
132:
133: TriangleStripArray frontGearBody = new TriangleStripArray(
134: gearBodyTotalVertexCount, GeometryArray.COORDINATES
135: | GeometryArray.NORMALS, gearBodyStripCount);
136:
137: xDirection = (float) Math.cos(gearStartAngle);
138: yDirection = (float) Math.sin(gearStartAngle);
139: xShaft0 = shaftRadius * xDirection;
140: yShaft0 = shaftRadius * yDirection;
141: xRoot0 = bodyOuterRadius * xDirection;
142: yRoot0 = bodyOuterRadius * yDirection;
143:
144: coordinate.set(xRoot0, yRoot0, frontZ);
145: frontGearBody.setCoordinate(0, coordinate);
146: frontGearBody.setNormal(0, frontNormal);
147:
148: coordinate.set(xShaft0, yShaft0, frontZ);
149: frontGearBody.setCoordinate(1, coordinate);
150: frontGearBody.setNormal(1, frontNormal);
151:
152: for (int count = 0; count < toothCount; count++) {
153: index = 2 + count * 4;
154: toothStartAngle = gearStartAngle + circularPitchAngle
155: * (double) count;
156: toothValleyStartAngle = toothStartAngle
157: + toothValleyAngleIncrement;
158: nextToothStartAngle = toothStartAngle + circularPitchAngle;
159:
160: xDirection = (float) Math.cos(toothValleyStartAngle);
161: yDirection = (float) Math.sin(toothValleyStartAngle);
162: xShaft3 = shaftRadius * xDirection;
163: yShaft3 = shaftRadius * yDirection;
164: xRoot3 = bodyOuterRadius * xDirection;
165: yRoot3 = bodyOuterRadius * yDirection;
166:
167: xDirection = (float) Math.cos(nextToothStartAngle);
168: yDirection = (float) Math.sin(nextToothStartAngle);
169: xShaft4 = shaftRadius * xDirection;
170: yShaft4 = shaftRadius * yDirection;
171: xRoot4 = bodyOuterRadius * xDirection;
172: yRoot4 = bodyOuterRadius * yDirection;
173:
174: coordinate.set(xRoot3, yRoot3, frontZ);
175: frontGearBody.setCoordinate(index, coordinate);
176: frontGearBody.setNormal(index, frontNormal);
177:
178: coordinate.set(xShaft3, yShaft3, frontZ);
179: frontGearBody.setCoordinate(index + 1, coordinate);
180: frontGearBody.setNormal(index + 1, frontNormal);
181:
182: coordinate.set(xRoot4, yRoot4, frontZ);
183: frontGearBody.setCoordinate(index + 2, coordinate);
184: frontGearBody.setNormal(index + 2, frontNormal);
185:
186: coordinate.set(xShaft4, yShaft4, frontZ);
187: frontGearBody.setCoordinate(index + 3, coordinate);
188: frontGearBody.setNormal(index + 3, frontNormal);
189: }
190: newShape = new Shape3D(frontGearBody, look);
191: this .addChild(newShape);
192:
193: // Construct the gear's rear body (rear facing torus disc)
194: TriangleStripArray rearGearBody = new TriangleStripArray(
195: gearBodyTotalVertexCount, GeometryArray.COORDINATES
196: | GeometryArray.NORMALS, gearBodyStripCount);
197: xDirection = (float) Math.cos(gearStartAngle);
198: yDirection = (float) Math.sin(gearStartAngle);
199: xShaft0 = shaftRadius * xDirection;
200: yShaft0 = shaftRadius * yDirection;
201: xRoot0 = bodyOuterRadius * xDirection;
202: yRoot0 = bodyOuterRadius * yDirection;
203:
204: coordinate.set(xShaft0, yShaft0, rearZ);
205: rearGearBody.setCoordinate(0, coordinate);
206: rearGearBody.setNormal(0, rearNormal);
207:
208: coordinate.set(xRoot0, yRoot0, rearZ);
209: rearGearBody.setCoordinate(1, coordinate);
210: rearGearBody.setNormal(1, rearNormal);
211:
212: for (int count = 0; count < toothCount; count++) {
213: index = 2 + count * 4;
214: toothStartAngle = gearStartAngle + circularPitchAngle
215: * (double) count;
216: toothValleyStartAngle = toothStartAngle
217: + toothValleyAngleIncrement;
218: nextToothStartAngle = toothStartAngle + circularPitchAngle;
219:
220: xDirection = (float) Math.cos(toothValleyStartAngle);
221: yDirection = (float) Math.sin(toothValleyStartAngle);
222: xShaft3 = shaftRadius * xDirection;
223: yShaft3 = shaftRadius * yDirection;
224: xRoot3 = bodyOuterRadius * xDirection;
225: yRoot3 = bodyOuterRadius * yDirection;
226:
227: xDirection = (float) Math.cos(nextToothStartAngle);
228: yDirection = (float) Math.sin(nextToothStartAngle);
229: xShaft4 = shaftRadius * xDirection;
230: yShaft4 = shaftRadius * yDirection;
231: xRoot4 = bodyOuterRadius * xDirection;
232: yRoot4 = bodyOuterRadius * yDirection;
233:
234: coordinate.set(xShaft3, yShaft3, rearZ);
235: rearGearBody.setCoordinate(index, coordinate);
236: rearGearBody.setNormal(index, rearNormal);
237:
238: coordinate.set(xRoot3, yRoot3, rearZ);
239: rearGearBody.setCoordinate(index + 1, coordinate);
240: rearGearBody.setNormal(index + 1, rearNormal);
241:
242: coordinate.set(xShaft4, yShaft4, rearZ);
243: rearGearBody.setCoordinate(index + 2, coordinate);
244: rearGearBody.setNormal(index + 2, rearNormal);
245:
246: coordinate.set(xRoot4, yRoot4, rearZ);
247: rearGearBody.setCoordinate(index + 3, coordinate);
248: rearGearBody.setNormal(index + 3, rearNormal);
249:
250: }
251: newShape = new Shape3D(rearGearBody, look);
252: this .addChild(newShape);
253: }
254:
255: void addCylinderSkins(float shaftRadius, float length,
256: int normalDirection, Appearance look) {
257: int insideShaftVertexCount; // #(vertices) for shaft
258: int insideShaftStripCount[] = new int[1]; // #(vertices) in strip/strip
259: double toothStartAngle, nextToothStartAngle, toothValleyStartAngle;
260:
261: // A ray from the gear center, used in normal calculations
262: float xDirection, yDirection;
263:
264: // The z coordinates for the body disks
265: final float frontZ = -0.5f * length;
266: final float rearZ = 0.5f * length;
267:
268: // Temporary variables for storing coordinates, points, and vectors
269: float xShaft3, yShaft3, xShaft4, yShaft4;
270: Point3f coordinate = new Point3f(0.0f, 0.0f, 0.0f);
271: Vector3f surfaceNormal = new Vector3f();
272:
273: Shape3D newShape;
274: int index;
275: int firstIndex;
276: int secondIndex;
277:
278: /*
279: * Construct gear's inside shaft cylinder
280: * First the tooth's up, flat outer, and down distances
281: * Second the tooth's flat inner distance
282: *
283: * Outward facing vertex order:
284: * 0_______2____4
285: * | /| /|
286: * | / | / |
287: * | / | / |
288: * |/______|/___|
289: * 1 3 5
290: *
291: * Inward facing vertex order:
292: * 1_______3____5
293: * |\ |\ |
294: * | \ | \ |
295: * | \ | \ |
296: * |______\|___\|
297: * 0 2 4
298: */
299: insideShaftVertexCount = 4 * toothCount + 2;
300: insideShaftStripCount[0] = insideShaftVertexCount;
301:
302: TriangleStripArray insideShaft = new TriangleStripArray(
303: insideShaftVertexCount, GeometryArray.COORDINATES
304: | GeometryArray.NORMALS, insideShaftStripCount);
305: xShaft3 = shaftRadius * (float) Math.cos(gearStartAngle);
306: yShaft3 = shaftRadius * (float) Math.sin(gearStartAngle);
307:
308: if (normalDirection == OutwardNormals) {
309: surfaceNormal.set(1.0f, 0.0f, 0.0f);
310: firstIndex = 1;
311: secondIndex = 0;
312: } else {
313: surfaceNormal.set(-1.0f, 0.0f, 0.0f);
314: firstIndex = 0;
315: secondIndex = 1;
316: }
317:
318: // Coordinate labeled 0 in the strip
319: coordinate.set(shaftRadius, 0.0f, frontZ);
320: insideShaft.setCoordinate(firstIndex, coordinate);
321: insideShaft.setNormal(firstIndex, surfaceNormal);
322:
323: // Coordinate labeled 1 in the strip
324: coordinate.set(shaftRadius, 0.0f, rearZ);
325: insideShaft.setCoordinate(secondIndex, coordinate);
326: insideShaft.setNormal(secondIndex, surfaceNormal);
327:
328: for (int count = 0; count < toothCount; count++) {
329: index = 2 + count * 4;
330:
331: toothStartAngle = circularPitchAngle * (double) count;
332: toothValleyStartAngle = toothStartAngle
333: + toothValleyAngleIncrement;
334: nextToothStartAngle = toothStartAngle + circularPitchAngle;
335:
336: xDirection = (float) Math.cos(toothValleyStartAngle);
337: yDirection = (float) Math.sin(toothValleyStartAngle);
338: xShaft3 = shaftRadius * xDirection;
339: yShaft3 = shaftRadius * yDirection;
340: if (normalDirection == OutwardNormals)
341: surfaceNormal.set(xDirection, yDirection, 0.0f);
342: else
343: surfaceNormal.set(-xDirection, -yDirection, 0.0f);
344:
345: // Coordinate labeled 2 in the strip
346: coordinate.set(xShaft3, yShaft3, frontZ);
347: insideShaft.setCoordinate(index + firstIndex, coordinate);
348: insideShaft.setNormal(index + firstIndex, surfaceNormal);
349:
350: // Coordinate labeled 3 in the strip
351: coordinate.set(xShaft3, yShaft3, rearZ);
352: insideShaft.setCoordinate(index + secondIndex, coordinate);
353: insideShaft.setNormal(index + secondIndex, surfaceNormal);
354:
355: xDirection = (float) Math.cos(nextToothStartAngle);
356: yDirection = (float) Math.sin(nextToothStartAngle);
357: xShaft4 = shaftRadius * xDirection;
358: yShaft4 = shaftRadius * yDirection;
359: if (normalDirection == OutwardNormals)
360: surfaceNormal.set(xDirection, yDirection, 0.0f);
361: else
362: surfaceNormal.set(-xDirection, -yDirection, 0.0f);
363:
364: // Coordinate labeled 4 in the strip
365: coordinate.set(xShaft4, yShaft4, frontZ);
366: insideShaft.setCoordinate(index + 2 + firstIndex,
367: coordinate);
368: insideShaft
369: .setNormal(index + 2 + firstIndex, surfaceNormal);
370:
371: // Coordinate labeled 5 in the strip
372: coordinate.set(xShaft4, yShaft4, rearZ);
373: insideShaft.setCoordinate(index + 2 + secondIndex,
374: coordinate);
375: insideShaft.setNormal(index + 2 + secondIndex,
376: surfaceNormal);
377:
378: }
379: newShape = new Shape3D(insideShaft, look);
380: this .addChild(newShape);
381: }
382:
383: public float getToothTopCenterAngle() {
384: return toothTopCenterAngle;
385: }
386:
387: public float getValleyCenterAngle() {
388: return valleyCenterAngle;
389: }
390:
391: public float getCircularPitchAngle() {
392: return circularPitchAngle;
393: }
394: }
|