2 * GravitySimulatorView.java
5 package edu
.mit
.ezyang
.gravity
;
7 import edu
.mit
.ezyang
.gravity
.j3d
.utils
.picking
.behaviors
.PickSelectCallback
;
8 import edu
.mit
.ezyang
.gravity
.j3d
.*;
9 import com
.sun
.j3d
.utils
.behaviors
.keyboard
.KeyNavigatorBehavior
;
10 import org
.jdesktop
.application
.Action
;
11 import org
.jdesktop
.application
.SingleFrameApplication
;
12 import org
.jdesktop
.application
.FrameView
;
13 import javax
.swing
.JDialog
;
15 import javax
.swing
.JFrame
;
16 import com
.sun
.j3d
.utils
.geometry
.*;
17 import com
.sun
.j3d
.utils
.universe
.*;
18 import edu
.mit
.ezyang
.gravity
.actors
.*;
20 import javax
.media
.j3d
.*;
21 import javax
.swing
.JPopupMenu
;
22 import javax
.vecmath
.*;
25 * This is the main and only frame of the GravitySimulator application. It
26 * controls the console and the Canvas3D, both of which respond to user
28 * @author Edward Z. Yang <ezyang@mit.edu>
30 public class GravitySimulatorView
extends FrameView
implements PickSelectCallback
{
33 * BranchGroup that objects in the universe should be inserted in. This
34 * itself is inside a rotatable TransformGroup, which allows all objects
35 * in the universe to be rotated.
37 public BranchGroup universeRoot
;
40 * TransformGroup corresponding to the rotation universeRoot; this
41 * needs to be registered to all SmartPickTranslateBehavior objects
42 * in order to compensate properly.
44 protected TransformGroup globalRotateGroup
;
47 * TransformGroup corresponding to the location of the viewpoint; this
48 * can be modified in order to change the viewer's location.
50 protected TransformGroup viewTransformGroup
;
53 * Canvas being rendered in the UI. Use this to access global properties
54 * including the SimpleUniverse.
56 protected Canvas3D canvas
;
59 * Node currently selected in the Canvas3D interface.
61 public Primitive selectedPrimitive
;
64 * Old material that selectedNode previously was.
66 protected Material selectedPrimitiveOldMaterial
;
69 * Reference to current arrow group, for rendering velocity vector.
71 protected BranchGroup arrowGroup
;
73 public GravitySimulatorView(SingleFrameApplication app
) {
76 // make menus heavy, see <http://java3d.j3d.org/faq/swing.html>
77 JPopupMenu
.setDefaultLightWeightPopupEnabled(false);
80 BoundingSphere bounds
= new BoundingSphere(new Point3d(0f
,0f
,0f
), 1000f
);
82 canvas
= new Canvas3D(SimpleUniverse
.getPreferredConfiguration());
83 SimpleUniverse universe
= new SimpleUniverse(canvas
);
85 BranchGroup root
= new BranchGroup();
88 TransformGroup vpTrans
= universe
.getViewingPlatform().getViewPlatformTransform();
89 KeyNavigatorBehavior keyNavBeh
= new KeyNavigatorBehavior(vpTrans
);
90 keyNavBeh
.setSchedulingBounds(bounds
);
91 root
.addChild(keyNavBeh
);
93 universeRoot
= new BranchGroup();
94 universeRoot
.setCapability(BranchGroup
.ALLOW_CHILDREN_READ
);
95 universeRoot
.setCapability(BranchGroup
.ALLOW_CHILDREN_WRITE
);
96 universeRoot
.setCapability(BranchGroup
.ALLOW_CHILDREN_EXTEND
);
98 globalRotateGroup
= new RotateGroup();
100 globalRotateGroup
.addChild(universeRoot
);
101 root
.addChild(globalRotateGroup
);
102 universe
.addBranchGraph(root
);
104 ViewingPlatform platform
= universe
.getViewingPlatform();
105 platform
.setNominalViewingTransform();
106 //platform.getViewers()[0].getView().setFieldOfView(10f);
108 viewTransformGroup
= platform
.getMultiTransformGroup().getTransformGroup(0);
109 Transform3D viewTransform
= new Transform3D();
110 viewTransform
.setTranslation(new Vector3f(0.0f
,0.0f
,10.0f
));
111 viewTransformGroup
.setTransform(viewTransform
);
113 canvasPanel
.add(canvas
);
117 public void notifyPick(Primitive primitive
) {
118 if (selectedPrimitive
!= null) {
119 if (selectedPrimitiveOldMaterial
!= null) {
120 selectedPrimitive
.getAppearance().setMaterial(selectedPrimitiveOldMaterial
);
122 if (arrowGroup
!= null) arrowGroup
.detach();
124 selectedPrimitive
= primitive
;
125 Material material
= selectedPrimitive
.getAppearance().getMaterial();
126 selectedPrimitiveOldMaterial
= (Material
) material
.cloneNodeComponent(true);
127 selectedPrimitiveOldMaterial
.setCapability(Material
.ALLOW_COMPONENT_WRITE
);
128 material
.setEmissiveColor(0.5f
, 0.5f
, 0.5f
);
129 if (primitive
instanceof Body
) {
130 // render velocity vector
131 Body body
= (Body
) primitive
;
132 Node node
= primitive
.getParent();
133 while (node
!= null && !(node
instanceof TransformGroup
)) {
134 node
= node
.getParent();
136 if (node
instanceof TransformGroup
) {
137 TransformGroup group
= (TransformGroup
) node
;
138 if (body
.velocity
.length() != 0f
) {
139 arrowGroup
= new ArrowGroup(body
.velocity
);
140 group
.addChild(arrowGroup
);
146 /** Processes a command from the command line box, modifying Universe.
147 * @param command Command line to execute.
149 public void processCommand(String command
) {
150 if (command
.contains(";")) {
151 for (String subcommand
: command
.split(";")) {
152 processCommand(subcommand
);
158 String
[] parts
= command
.split(" ");
159 if (parts
.length
== 0 || parts
[0].equals("") || parts
[0].equals("help")) {
160 send("Commands: add, set, view, clear");
163 if (parts
[0].equals("add")) {
164 if (parts
.length
== 1) {
165 send("Need object to add: sphere, cone, cube or cylinder");
169 // initialize default "first class" parameters
171 Vector3f location
= new Vector3f(0f
, 0f
, 0f
);
172 Vector3f velocity
= new Vector3f(0f
, 0f
, 0f
);
175 // initialize generic params HashMap; this can be used for
176 // any sort of thing you want
177 HashMap
<String
, String
> params
= new HashMap
<String
, String
>();
179 // parse the arguments
180 if (parts
.length
> 2) {
182 for (int i
= 2; i
< parts
.length
; i
++) {
186 if (state
.equals("scale")) {
187 scale
= new Float(parts
[i
]);
188 } else if (state
.equals("at")) {
189 location
= vectorize(parts
[i
]);
190 } else if (state
.equals("velocity")) {
191 velocity
= vectorize(parts
[i
]);
192 } else if (state
.equals("mass")) {
193 mass
= new Float(parts
[i
]);
195 params
.put(state
, parts
[i
]);
201 // generate the actual primitive
203 if (parts
[1].equals("body")) {
204 Body body
= new Body(scale
);
205 body
.velocity
= velocity
;
208 } else if (parts
[1].equals("sphere")) {
209 primitive
= new Sphere(scale
);
210 } else if (parts
[1].equals("cone")) {
211 primitive
= new Cone(scale
* 1f
, scale
* 2f
);
212 } else if (parts
[1].equals("cylinder")) {
213 primitive
= new Cylinder(scale
* 1f
, scale
* 2f
);
215 send("Unknown primitive: " + parts
[1]);
218 primitive
.getAppearance().getMaterial().setAmbientColor(.8f
,.2f
,.2f
);
219 primitive
.setCapability(Primitive
.ENABLE_APPEARANCE_MODIFY
);
220 primitive
.getAppearance().setCapability(Appearance
.ALLOW_MATERIAL_WRITE
);
221 primitive
.getAppearance().getMaterial().setCapability(Material
.ALLOW_COMPONENT_WRITE
);
223 primitive
.setCapability(Node
.ENABLE_PICK_REPORTING
);
224 primitive
.setCapability(Node
.ALLOW_BOUNDS_READ
);
225 primitive
.setCapability(Node
.ALLOW_BOUNDS_WRITE
);
227 EditableGroup group
= new EditableGroup(canvas
, globalRotateGroup
, location
, this);
228 group
.addTransformChild(primitive
);
230 universeRoot
.addChild(group
);
231 } else if (parts
[0].equals("view")) {
232 if (parts
.length
== 1) {
233 send("Need location parameter x,y,z");
236 Transform3D viewTransform
= new Transform3D();
237 viewTransform
.setTranslation(vectorize(parts
[1]));
238 viewTransformGroup
.setTransform(viewTransform
);
239 } else if (parts
[0].equals("zoom")) {
240 if (parts
.length
== 1) {
241 send("Need zoom value z (view 0,0,z)");
244 Transform3D viewTransform
= new Transform3D();
245 viewTransform
.setTranslation(vectorize("0,0," + parts
[1]));
246 viewTransformGroup
.setTransform(viewTransform
);
247 } else if (parts
[0].equals("set")) {
248 if (selectedPrimitive
== null) {
249 send("No primitive selected");
252 if (!(selectedPrimitive
instanceof Body
)) {
253 send("Cannot set parameters for non-Body object");
256 Body primitive
= (Body
) selectedPrimitive
;
257 if (parts
.length
== 1) {
258 send("Need variable parameter: velocity, mass");
261 if (parts
[1].equals("velocity")) {
262 if (parts
.length
== 2) {
263 send("Need velocity vector x,y,z");
266 primitive
.velocity
= vectorize(parts
[2]);
267 notifyPick(primitive
);
268 } else if (parts
[1].equals("mass")) {
269 if (parts
.length
== 2) {
270 send("Need mass value m");
273 primitive
.mass
= new Float(parts
[2]);
275 send("Unknown variable " + parts
[1]);
277 } else if (parts
[0].equals("clear")) {
278 universeRoot
.removeAllChildren();
280 send("Unknown command: " + parts
[0] + ", type help for options");
285 /** Converts string in form x,y,z to Vector3f
286 * @param input vector in form x,y,z
287 * @return Appropriate vector
289 protected Vector3f
vectorize(String input
) {
290 String
[] vectorFields
= input
.split(",");
291 return new Vector3f(new Float(vectorFields
[0]), new Float(vectorFields
[1]), new Float(vectorFields
[2]));
294 /** Sends a message to display in the terminal.
295 * @param message Message to send
297 protected void send(String message
) {
298 terminal
.append(message
+ "\n");
301 /** Displays the about box.
304 public void showAboutBox() {
305 if (aboutBox
== null) {
306 JFrame mainFrame
= GravitySimulatorApp
.getApplication().getMainFrame();
307 aboutBox
= new GravitySimulatorAboutBox(mainFrame
);
308 aboutBox
.setLocationRelativeTo(mainFrame
);
310 GravitySimulatorApp
.getApplication().show(aboutBox
);
313 /** This method is called from within the constructor to
314 * initialize the form.
315 * WARNING: Do NOT modify this code. The content of this method is
316 * always regenerated by the Form Editor.
318 @SuppressWarnings("unchecked")
319 // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
320 private void initComponents() {
322 mainPanel
= new javax
.swing
.JPanel();
323 canvasPanel
= new javax
.swing
.JPanel();
324 console
= new javax
.swing
.JPanel();
325 commandLine
= new javax
.swing
.JTextField();
326 terminalPane
= new javax
.swing
.JScrollPane();
327 terminal
= new javax
.swing
.JTextArea();
328 menuBar
= new javax
.swing
.JMenuBar();
329 javax
.swing
.JMenu fileMenu
= new javax
.swing
.JMenu();
330 javax
.swing
.JMenuItem exitMenuItem
= new javax
.swing
.JMenuItem();
331 javax
.swing
.JMenu helpMenu
= new javax
.swing
.JMenu();
332 javax
.swing
.JMenuItem aboutMenuItem
= new javax
.swing
.JMenuItem();
334 mainPanel
.setName("mainPanel"); // NOI18N
335 mainPanel
.setLayout(new java
.awt
.BorderLayout());
337 org
.jdesktop
.application
.ResourceMap resourceMap
= org
.jdesktop
.application
.Application
.getInstance(edu
.mit
.ezyang
.gravity
.GravitySimulatorApp
.class).getContext().getResourceMap(GravitySimulatorView
.class);
338 canvasPanel
.setBackground(resourceMap
.getColor("canvasPanel.background")); // NOI18N
339 canvasPanel
.setName("canvasPanel"); // NOI18N
340 canvasPanel
.setLayout(new java
.awt
.BorderLayout());
341 mainPanel
.add(canvasPanel
, java
.awt
.BorderLayout
.CENTER
);
343 console
.setName("console"); // NOI18N
344 console
.setLayout(new java
.awt
.BorderLayout());
346 commandLine
.setText(resourceMap
.getString("commandLine.text")); // NOI18N
347 commandLine
.setName("commandLine"); // NOI18N
348 commandLine
.addActionListener(new java
.awt
.event
.ActionListener() {
349 public void actionPerformed(java
.awt
.event
.ActionEvent evt
) {
350 commandLineActionPerformed(evt
);
353 console
.add(commandLine
, java
.awt
.BorderLayout
.CENTER
);
355 terminalPane
.setName("terminalPane"); // NOI18N
357 terminal
.setColumns(20);
358 terminal
.setEditable(false);
359 terminal
.setFont(resourceMap
.getFont("terminal.font")); // NOI18N
361 terminal
.setName("terminal"); // NOI18N
362 terminalPane
.setViewportView(terminal
);
364 console
.add(terminalPane
, java
.awt
.BorderLayout
.PAGE_START
);
366 mainPanel
.add(console
, java
.awt
.BorderLayout
.PAGE_END
);
368 menuBar
.setName("menuBar"); // NOI18N
370 fileMenu
.setText(resourceMap
.getString("fileMenu.text")); // NOI18N
371 fileMenu
.setName("fileMenu"); // NOI18N
373 javax
.swing
.ActionMap actionMap
= org
.jdesktop
.application
.Application
.getInstance(edu
.mit
.ezyang
.gravity
.GravitySimulatorApp
.class).getContext().getActionMap(GravitySimulatorView
.class, this);
374 exitMenuItem
.setAction(actionMap
.get("quit")); // NOI18N
375 exitMenuItem
.setName("exitMenuItem"); // NOI18N
376 fileMenu
.add(exitMenuItem
);
378 menuBar
.add(fileMenu
);
380 helpMenu
.setText(resourceMap
.getString("helpMenu.text")); // NOI18N
381 helpMenu
.setName("helpMenu"); // NOI18N
383 aboutMenuItem
.setAction(actionMap
.get("showAboutBox")); // NOI18N
384 aboutMenuItem
.setName("aboutMenuItem"); // NOI18N
385 helpMenu
.add(aboutMenuItem
);
387 menuBar
.add(helpMenu
);
389 setComponent(mainPanel
);
391 }// </editor-fold>//GEN-END:initComponents
393 private void commandLineActionPerformed(java
.awt
.event
.ActionEvent evt
) {//GEN-FIRST:event_commandLineActionPerformed
394 processCommand(commandLine
.getText());
395 commandLine
.setText("");
396 }//GEN-LAST:event_commandLineActionPerformed
398 // Variables declaration - do not modify//GEN-BEGIN:variables
399 private javax
.swing
.JPanel canvasPanel
;
400 private javax
.swing
.JTextField commandLine
;
401 private javax
.swing
.JPanel console
;
402 private javax
.swing
.JPanel mainPanel
;
403 private javax
.swing
.JMenuBar menuBar
;
404 private javax
.swing
.JTextArea terminal
;
405 private javax
.swing
.JScrollPane terminalPane
;
406 // End of variables declaration//GEN-END:variables
408 private JDialog aboutBox
;