-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathTorus.java
More file actions
316 lines (269 loc) · 11.2 KB
/
Torus.java
File metadata and controls
316 lines (269 loc) · 11.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
// inspired by Leon Tabak
// creates a series of rotating inner toruses inside of eachother
// as a side note, tori or toruses are both acceptable terms
// imports for GUI & 3D interface
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.GraphicsConfiguration;
import java.util.ArrayList;
import java.util.Random;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.GeometryInfo;
import com.sun.j3d.utils.geometry.NormalGenerator;
import com.sun.j3d.utils.geometry.Stripifier;
import com.sun.j3d.utils.universe.SimpleUniverse;
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.ColoringAttributes;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.Light;
import javax.media.j3d.LineArray;
import javax.media.j3d.Link;
import javax.media.j3d.Material;
import javax.media.j3d.Node;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.RotationInterpolator;
import javax.media.j3d.Shape3D;
import javax.media.j3d.SharedGroup;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.TriangleArray;
import javax.vecmath.AxisAngle4f;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3f;
public class Torus extends Applet{
// how many triangles make up the torus
private static final int MAJOR_STEPS = 80;
private static final int MINOR_STEPS = 70;
// sets the torus size
private static final float MAJOR_RADIUS = 0.8f;
private static final float MINOR_RADIUS = 0.1f;
// set odd-shaped torus (oval)
private static final float ECCENTRICITY = 1.0f;
// time for one rotation, in ms (smaller=faster)
private static final int PERIOD = 1300;
// set colors for scene
private static final Color3f AMBIENT_COLOR = new Color3f(0.2f, 0.3f, 0.5f);
private static final Color3f OBJECT_COLOR = new Color3f(0.4f, 0.1f, 0.9f);
private static final Color3f EMISSIVE_COLOR = new Color3f(0.2f, 0.3f, 0.5f);
private static final Color3f SPECULAR_COLOR = new Color3f(0.3f, 0.1f, 0.9f);
// how many tori to create
private static final int NUMB_TORI = 5;
// variables for storagae
private ArrayList<TransformGroup> tori = new ArrayList<TransformGroup>();
private SimpleUniverse u = null;
private Random rng = new Random();
private int RANDOM = rng.nextInt(2);
// create the scene graph of the program
public BranchGroup createSceneGraph(){
// create the root of the branch graph
BranchGroup objRoot = new BranchGroup();
SharedGroup objShare = new SharedGroup();
objShare.addChild(makeWheel(MAJOR_RADIUS, MINOR_RADIUS, ECCENTRICITY));
// generates all objects, rotating
this.createTori(objShare);
for(TransformGroup tg:tori){
objRoot.addChild(tg);
this.generateSpin(objRoot, tg);
}
// add light to the scene graph
objRoot.addChild(this.createDirectionalLight());
objRoot.addChild(this.createAmbientLight());
// perform optimizations & return scene graph
objRoot.compile();
return objRoot;
}
// create several torus shapes (inside each other)
private void createTori(SharedGroup sg){
for(int i = 0; i < NUMB_TORI; i++){
TransformGroup obj = new TransformGroup();
obj.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
// shrink the torus size, so they fit inside each other
TransformGroup rot = new TransformGroup();
float shrink = 1.0f - ((1.0f / NUMB_TORI) * i);
// rotate the tori so they look more interesting
float[] xzMatrix = {0f,0f,shrink,0f, 0f,shrink,0f,0f, shrink,0f,0f,0f, 0f,0f,0f,1f};
Transform3D rotate = new Transform3D(xzMatrix);
rot.setTransform(rotate);
obj.addChild(rot);
// add the torus to the scene graph
rot.addChild(new Link(sg));
tori.add(obj);
}
}
// tell the scene graph to spin the torus objects over time
private void generateSpin(BranchGroup bg, TransformGroup tg){
Transform3D yAxis = new Transform3D();
Alpha rotationAlpha = new Alpha(-1, PERIOD);
BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
int rotBit = tori.indexOf(tg);
float[] rotMatrix;
// transform the torus objects correctly, depending on the number of objects
if(rotBit == NUMB_TORI - 1){
TransformGroup tg2 = (TransformGroup) tg.getChild(0);
float shrink = 1.0f - ((1.0f / NUMB_TORI) * (NUMB_TORI - 1));
float[] flipMatrix = {shrink,0f,0f,0f, 0f,shrink,0f,0f, 0f,0f,shrink,0f, 0f,0f,0f,1f};
Transform3D rotate = new Transform3D(flipMatrix);
tg2.setTransform(rotate);
float[] matrix = {-1f,0f,0f,0f, 0f,0f,1f,0f, 0f,1f,0f,0f, 0f,0f,0f,1f};
rotMatrix = matrix;
}else if((rotBit + RANDOM) % 2 == 1){
float[] matrix = {0f,1f,0f,0f, 1f,0f,0f,0f, 0f,0f,-1f,0f, 0f,0f,0f,1f};
rotMatrix = matrix;
}else{
float[] matrix = {1f,0f,0f,0f, 0f,1f,0f,0f, 0f,0f,1f,0f, 0f,0f,0f,1f};
rotMatrix = matrix;
}
// perform the rotation
Transform3D axis = new Transform3D(rotMatrix);
RotationInterpolator rotator = new RotationInterpolator(rotationAlpha, tg, axis, 0.0f, (float) Math.PI * 2.0f);
rotator.setSchedulingBounds(bounds);
bg.addChild(rotator);
}
// set up scene directional light
private Light createDirectionalLight(){
DirectionalLight light = new DirectionalLight();
BoundingSphere infinite = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),Double.MAX_VALUE);
light.setInfluencingBounds(infinite);
light.setColor(new Color3f(1.0f, 1.0f, 1.0f));
light.setCapability(Light.ALLOW_STATE_WRITE);
light.setDirection(new Vector3f(-1.0f, 0.0f, -1.0f));
light.setEnable(true);
return light;
}
// set up scene ambient light
private Light createAmbientLight(){
AmbientLight light = new AmbientLight();
BoundingSphere infinite = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),Double.MAX_VALUE);
light.setInfluencingBounds(infinite);
light.setColor(new Color3f(1.0f, 1.0f, 1.0f));
light.setCapability(Light.ALLOW_STATE_WRITE);
light.setEnable(true);
return light;
}
// set up scene appearances of objects
private Appearance createAppearance(){
// general appearance settings
Appearance appearance = new Appearance();
ColoringAttributes ca = new ColoringAttributes();
ca.setShadeModel(ColoringAttributes.SHADE_GOURAUD);
appearance.setColoringAttributes(ca);
// polygon appearance settings
PolygonAttributes pa = new PolygonAttributes();
pa.setPolygonMode(PolygonAttributes.POLYGON_FILL);
appearance.setPolygonAttributes(pa);
// light-material interaction colors
Color3f ambientColor = AMBIENT_COLOR;
Color3f objectColor = OBJECT_COLOR;
Color3f emissiveColor = EMISSIVE_COLOR;
Color3f specularColor = SPECULAR_COLOR;
// material apperance settings
Material material = new Material(ambientColor,emissiveColor,objectColor,specularColor,100.0f);
material.setLightingEnable(true);
appearance.setMaterial(material);
return appearance;
}
// how to generate the torus (wheel)
public Node makeWheel(float majorRadius, float minorRadius,float eccentricity){
// number of steps to generate each torus
int majorSteps = MAJOR_STEPS;
int minorSteps = MINOR_STEPS;
// generate points
Point3f[] v = new Point3f[minorSteps];
for(int j = 0; j < minorSteps; j++){
float angle = (float) (2.0 * Math.PI * ((double) j) / minorSteps);
float x = (float) (eccentricity * minorRadius * Math.cos(angle));
float y = (float) (minorRadius * Math.sin(angle));
v[j] = new Point3f(x, y + majorRadius, 0.0f);
}
// generate vertices from the points, with the proper rotations
Point3f[][] vertices = new Point3f[majorSteps][minorSteps];
for(int i = 0; i < majorSteps; i++){
float angle = (float) (2.0 * Math.PI * ((double) i) / majorSteps);
Transform3D rotation = new Transform3D();
AxisAngle4f axisAngle = new AxisAngle4f(1.0f, 0.0f, 0.0f, angle);
rotation.setRotation(axisAngle);
for(int j = 0; j < minorSteps; j++){
vertices[i][j] = new Point3f();
rotation.transform(v[j], vertices[i][j]);
}
}
// draw lines with the torus
int numberOfLines = 2 * majorSteps * minorSteps;
int code = GeometryArray.COORDINATES;
LineArray lines = new LineArray(numberOfLines * 2, code);
// set coordinates of the object
TriangleArray t = new TriangleArray(6 * majorSteps * minorSteps, GeometryArray.COORDINATES);
int k = 0;
int index = 0;
for(int i = 0; i < majorSteps; i++){
for(int j = 0; j < minorSteps; j++){
t.setCoordinate(index++, vertices[i][j]);
t.setCoordinate(index++, vertices[i][(j + 1) % minorSteps]);
t.setCoordinate(index++, vertices[(i + 1) % majorSteps][j]);
t.setCoordinate(index++, vertices[i][(j + 1) % minorSteps]);
t.setCoordinate(index++, vertices[(i + 1) % majorSteps][(j + 1) % minorSteps]);
t.setCoordinate(index++, vertices[(i + 1) % majorSteps][j]);
}
}
// set up geometry info
GeometryInfo geometryInfo = new GeometryInfo(t);
NormalGenerator normalGenerator = new NormalGenerator();
normalGenerator.generateNormals(geometryInfo);
Stripifier stripifier = new Stripifier();
stripifier.stripify(geometryInfo);
return new Shape3D(geometryInfo.getGeometryArray(), this.createAppearance());
}
// created object, empty
public Torus(){}
// set up graphics canvas
@Override
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();
u = new SimpleUniverse(c);
// move viewport to see objects in the scene
u.getViewingPlatform().setNominalViewingTransform();
u.addBranchGraph(scene);
}
// clearing the scene
@Override
public void destroy(){
u.removeAllLocales();
}
// calculate an average off of t
private float avg(float a, float b, float t){
return (1 - t) * a + t * b;
}
// generate an average point (vector) from two points
private Point3f avg(Point3f a, Point3f b, float t){
float x = avg(a.x, b.x, t);
float y = avg(a.y, b.y, t);
float z = avg(a.z, b.z, t);
return new Point3f(x, y, z);
}
// generate an average point (vector) from three points
private Point3f avg(Point3f a, Point3f b, Point3f c, float t){
return avg(avg(a, b, t), avg(b, c, t), t);
}
// generate an average point (vector) from four points
private Point3f avg(Point3f a, Point3f b, Point3f c, Point3f d, float t){
return avg(avg(a, b, c, t), avg(b, c, d, t), t);
}
// main method to run application as an applet
public static void main(String[] args){
new MainFrame(new Torus(), 800, 800);
}
}