Implement gravity and velocity vector.
[gravitysimulator.git] / src / edu / mit / ezyang / gravity / GravitySimulatorView.java
blobbb2ca5430a57951d0e3c79b0d1bed854995e73bc
1 /*
2 * GravitySimulatorView.java
3 */
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.*;
19 import java.util.*;
20 import javax.media.j3d.*;
21 import javax.swing.JPopupMenu;
22 import javax.vecmath.*;
24 /**
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
27 * interaction.
28 * @author Edward Z. Yang <ezyang@mit.edu>
30 public class GravitySimulatorView extends FrameView implements PickSelectCallback {
32 /**
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;
39 /**
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;
46 /**
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;
52 /**
53 * Canvas being rendered in the UI. Use this to access global properties
54 * including the SimpleUniverse.
56 protected Canvas3D canvas;
58 /**
59 * Node currently selected in the Canvas3D interface.
61 public Primitive selectedPrimitive;
63 /**
64 * Old material that selectedNode previously was.
66 protected Material selectedPrimitiveOldMaterial;
68 /**
69 * Reference to current arrow group, for rendering velocity vector.
71 protected BranchGroup arrowGroup;
73 public GravitySimulatorView(SingleFrameApplication app) {
74 super(app);
76 // make menus heavy, see <http://java3d.j3d.org/faq/swing.html>
77 JPopupMenu.setDefaultLightWeightPopupEnabled(false);
78 initComponents();
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();
87 // key navigation
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);
154 return;
157 send(command);
158 String[] parts = command.split(" ");
159 if (parts.length == 0 || parts[0].equals("") || parts[0].equals("help")) {
160 send("Commands: add, set, view, clear");
161 return;
163 if (parts[0].equals("add")) {
164 if (parts.length == 1) {
165 send("Need object to add: sphere, cone, cube or cylinder");
166 return;
169 // initialize default "first class" parameters
170 float scale = 0.4f;
171 Vector3f location = new Vector3f(0f, 0f, 0f);
172 Vector3f velocity = new Vector3f(0f, 0f, 0f);
173 float mass = 10f;
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) {
181 String state = null;
182 for (int i = 2; i < parts.length; i++) {
183 if (state == null) {
184 state = parts[i];
185 } else {
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]);
194 } else {
195 params.put(state, parts[i]);
197 state = null;
201 // generate the actual primitive
202 Primitive primitive;
203 if (parts[1].equals("body")) {
204 Body body = new Body(scale);
205 body.velocity = velocity;
206 body.mass = mass;
207 primitive = body;
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);
214 } else {
215 send("Unknown primitive: " + parts[1]);
216 return;
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");
234 return;
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)");
242 return;
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");
250 return;
252 if (!(selectedPrimitive instanceof Body)) {
253 send("Cannot set parameters for non-Body object");
254 return;
256 Body primitive = (Body) selectedPrimitive;
257 if (parts.length == 1) {
258 send("Need variable parameter: velocity, mass");
259 return;
261 if (parts[1].equals("velocity")) {
262 if (parts.length == 2) {
263 send("Need velocity vector x,y,z");
264 return;
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");
271 return;
273 primitive.mass = new Float(parts[2]);
274 } else {
275 send("Unknown variable " + parts[1]);
277 } else if (parts[0].equals("clear")) {
278 universeRoot.removeAllChildren();
279 } else {
280 send("Unknown command: " + parts[0] + ", type help for options");
281 return;
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.
303 @Action
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
360 terminal.setRows(5);
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);
390 setMenuBar(menuBar);
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;