From 5a6e75133b417dc5226e1287551c5245caba18c5 Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Sun, 19 Oct 2008 04:14:52 -0400 Subject: [PATCH] User interface mostly done, except for velocity editing. Signed-off-by: Edward Z. Yang --- nbproject/project.properties | 13 +- .../mit/ezyang/gravity/GravitySimulatorApp.java | 1 + .../mit/ezyang/gravity/GravitySimulatorView.form | 3 - .../mit/ezyang/gravity/GravitySimulatorView.java | 117 +++++++--------- src/edu/mit/ezyang/gravity/j3d/EditableGroup.java | 60 ++++++++ src/edu/mit/ezyang/gravity/j3d/RotateGroup.java | 33 +++++ .../mit/ezyang/gravity/j3d/SmartMouseBehavior.java | 17 +++ .../ezyang/gravity/j3d/SmartMouseTranslate.java | 151 +++++++++++++++++++++ src/edu/mit/ezyang/gravity/j3d/SmartMouseZoom.java | 147 ++++++++++++++++++++ .../gravity/j3d/SmartPickTranslateBehavior.java | 103 ++++++++++++++ .../ezyang/gravity/j3d/SmartPickZoomBehavior.java | 109 +++++++++++++++ .../resources/GravitySimulatorApp.properties | 22 +-- 12 files changed, 691 insertions(+), 85 deletions(-) create mode 100644 src/edu/mit/ezyang/gravity/j3d/EditableGroup.java create mode 100644 src/edu/mit/ezyang/gravity/j3d/RotateGroup.java create mode 100644 src/edu/mit/ezyang/gravity/j3d/SmartMouseBehavior.java create mode 100644 src/edu/mit/ezyang/gravity/j3d/SmartMouseTranslate.java create mode 100644 src/edu/mit/ezyang/gravity/j3d/SmartMouseZoom.java create mode 100644 src/edu/mit/ezyang/gravity/j3d/SmartPickTranslateBehavior.java create mode 100644 src/edu/mit/ezyang/gravity/j3d/SmartPickZoomBehavior.java rewrite src/edu/mit/ezyang/gravity/resources/GravitySimulatorApp.properties (70%) diff --git a/nbproject/project.properties b/nbproject/project.properties index b97ea38..2862c3c 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -1,7 +1,7 @@ -application.desc=A simple java desktop application based on Swing Application Framework -application.homepage=http://appframework.dev.java.net -application.title=Basic Application Example -application.vendor=Sun Microsystems Inc. +application.desc=Simulation of Gravity in 3D space for 8.012 +application.homepage= +application.title=Gravity Simulator +application.vendor=MIT build.classes.dir=${build.dir}/classes build.classes.excludes=**/*.java,**/*.form # This directory is removed when the project is cleaned: @@ -46,6 +46,11 @@ javadoc.splitindex=true javadoc.use=true javadoc.version=false javadoc.windowtitle= +jnlp.codebase.type=local +jnlp.codebase.url=file:/C:/Users/Edward/Documents/NetBeansProjects/GravitySimulator/dist/ +jnlp.enabled=false +jnlp.offline-allowed=false +jnlp.signed=false main.class=edu.mit.ezyang.gravity.GravitySimulatorApp manifest.file=manifest.mf meta.inf.dir=${src.dir}/META-INF diff --git a/src/edu/mit/ezyang/gravity/GravitySimulatorApp.java b/src/edu/mit/ezyang/gravity/GravitySimulatorApp.java index 962cfec..0bfefab 100644 --- a/src/edu/mit/ezyang/gravity/GravitySimulatorApp.java +++ b/src/edu/mit/ezyang/gravity/GravitySimulatorApp.java @@ -9,6 +9,7 @@ import org.jdesktop.application.SingleFrameApplication; /** * The main class of the application. + * @author Edward Z. Yang */ public class GravitySimulatorApp extends SingleFrameApplication { diff --git a/src/edu/mit/ezyang/gravity/GravitySimulatorView.form b/src/edu/mit/ezyang/gravity/GravitySimulatorView.form index d736526..2ae5848 100644 --- a/src/edu/mit/ezyang/gravity/GravitySimulatorView.form +++ b/src/edu/mit/ezyang/gravity/GravitySimulatorView.form @@ -145,9 +145,6 @@ - - - diff --git a/src/edu/mit/ezyang/gravity/GravitySimulatorView.java b/src/edu/mit/ezyang/gravity/GravitySimulatorView.java index f2631ed..210397e 100644 --- a/src/edu/mit/ezyang/gravity/GravitySimulatorView.java +++ b/src/edu/mit/ezyang/gravity/GravitySimulatorView.java @@ -4,6 +4,7 @@ package edu.mit.ezyang.gravity; +import edu.mit.ezyang.gravity.j3d.*; import com.sun.j3d.utils.behaviors.keyboard.KeyNavigatorBehavior; import org.jdesktop.application.Action; import org.jdesktop.application.SingleFrameApplication; @@ -11,101 +12,98 @@ import org.jdesktop.application.FrameView; import javax.swing.JDialog; import javax.swing.JFrame; -import com.sun.j3d.utils.behaviors.mouse.*; -import com.sun.j3d.utils.picking.behaviors.*; import com.sun.j3d.utils.geometry.*; import com.sun.j3d.utils.universe.*; -import java.util.HashMap; +import java.util.*; import javax.media.j3d.*; import javax.swing.JPopupMenu; import javax.vecmath.*; /** - * The application's main frame. + * This is the main and only frame of the GravitySimulator application. It + * controls the console and the Canvas3D, both of which respond to user + * interaction. + * @author Edward Z. Yang */ public class GravitySimulatorView extends FrameView { - - /** - * SimpleUniverse controlling everything - */ - protected SimpleUniverse universe; /** - * Root group node that new elements should be added to. + * BranchGroup that objects in the universe should be inserted in. This + * itself is inside a rotatable TransformGroup, which allows all objects + * in the universe to be rotated. */ protected BranchGroup universeRoot; /** - * 3D transform controlling viewpoint. + * TransformGroup corresponding to the rotation universeRoot; this + * needs to be registered to all SmartPickTranslateBehavior objects + * in order to compensate properly. */ - protected Transform3D viewTransform; + protected TransformGroup globalRotateGroup; + /** + * TransformGroup corresponding to the location of the viewpoint; this + * can be modified in order to change the viewer's location. + */ protected TransformGroup viewTransformGroup; + + /** + * Canvas being rendered in the UI. Use this to access global properties + * including the SimpleUniverse. + */ protected Canvas3D canvas; public GravitySimulatorView(SingleFrameApplication app) { super(app); - - // todo rename rotateGroup - // make menus heavy + // make menus heavy, see JPopupMenu.setDefaultLightWeightPopupEnabled(false); initComponents(); - // 3D canvas initialization + BoundingSphere bounds = new BoundingSphere(new Point3d(0f,0f,0f), 1000f); + canvas = new Canvas3D(SimpleUniverse.getPreferredConfiguration()); - universe = new SimpleUniverse(canvas); - BoundingSphere bounds = new BoundingSphere(new Point3d(0f,0f,0f), 10000f);; + SimpleUniverse universe = new SimpleUniverse(canvas); BranchGroup root = new BranchGroup(); - BoundingSphere bounding = bounds; // key navigation TransformGroup vpTrans = universe.getViewingPlatform().getViewPlatformTransform(); KeyNavigatorBehavior keyNavBeh = new KeyNavigatorBehavior(vpTrans); - keyNavBeh.setSchedulingBounds(new BoundingSphere(new Point3d(), Float.POSITIVE_INFINITY)); + keyNavBeh.setSchedulingBounds(bounds); root.addChild(keyNavBeh); universeRoot = new BranchGroup(); universeRoot.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE); universeRoot.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND); - TransformGroup rotateGroup = new TransformGroup(); - rotateGroup.addChild(universeRoot); - rotateGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); - rotateGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); - MouseRotate rotate = new MouseRotate(); - rotate.setSchedulingBounds(bounds); - rotate.setTransformGroup(rotateGroup); - rotateGroup.addChild(rotate); - - DirectionalLight light = new DirectionalLight(new Color3f(1.8f, 0.2f, 0.2f), new Vector3f(4.0f, -7.0f, 7.0f)); - light.setInfluencingBounds(bounding); - rotateGroup.addChild(light); + globalRotateGroup = new RotateGroup(); - AmbientLight ambLight = new AmbientLight(new Color3f(.6f, .6f, .6f)); - ambLight.setInfluencingBounds(bounding); - rotateGroup.addChild(ambLight); - - root.addChild(rotateGroup); + globalRotateGroup.addChild(universeRoot); + root.addChild(globalRotateGroup); universe.addBranchGraph(root); ViewingPlatform platform = universe.getViewingPlatform(); platform.setNominalViewingTransform(); + //platform.getViewers()[0].getView().setFieldOfView(10f); viewTransformGroup = platform.getMultiTransformGroup().getTransformGroup(0); - viewTransform = new Transform3D(); + Transform3D viewTransform = new Transform3D(); viewTransform.setTranslation(new Vector3f(0.0f,0.0f,10.0f)); viewTransformGroup.setTransform(viewTransform); canvasPanel.add(canvas); - processCommand("add cube"); + // Initialize environment with some objects + processCommand("add sphere"); + processCommand("add cube at 0,2,0"); + processCommand("add cube at 0,-2,0"); + processCommand("add cube at 2,0,0"); + processCommand("add cube at -2,0,0"); } - /** - * Processes a command from the command line box, modifying Universe. + /** Processes a command from the command line box, modifying Universe. * @param command Command line to execute. */ public void processCommand(String command) { @@ -120,16 +118,6 @@ public class GravitySimulatorView extends FrameView { send("Need object to add: sphere, cone, cube or cylinder"); return; } - BranchGroup group = new BranchGroup(); - group.setCapability(BranchGroup.ALLOW_DETACH); - - Bounds bounds = new BoundingSphere(new Point3d(0f,0f,0f), 1000f); - - PickTranslateBehavior translate = new PickTranslateBehavior(group, canvas, bounds); - group.addChild(translate); - - PickZoomBehavior zoom = new PickZoomBehavior(group, canvas, bounds); - group.addChild(zoom); // initialize default "first class" parameters float scale = 0.4f; @@ -177,19 +165,8 @@ public class GravitySimulatorView extends FrameView { object.setCapability(Node.ALLOW_BOUNDS_READ); object.setCapability(Node.ALLOW_BOUNDS_WRITE); - // generate the transform (we do this even if we don't position them - // anywhere interesting) - TransformGroup transformGroup = new TransformGroup(); - transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); - transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); - transformGroup.setCapability(TransformGroup.ENABLE_PICK_REPORTING); - - Transform3D transform = new Transform3D(); - transform.setTranslation(location); - transformGroup.setTransform(transform); - transformGroup.addChild(object); - - group.addChild(transformGroup); + EditableGroup group = new EditableGroup(canvas, globalRotateGroup, location); + group.addTransformChild(object); universeRoot.addChild(group); } else if (parts[0].equals("view")) { @@ -197,6 +174,7 @@ public class GravitySimulatorView extends FrameView { send("Need location parameter x,y,z"); return; } + Transform3D viewTransform = new Transform3D(); viewTransform.setTranslation(vectorize(parts[1])); viewTransformGroup.setTransform(viewTransform); } else if (parts[0].equals("zoom")) { @@ -204,6 +182,7 @@ public class GravitySimulatorView extends FrameView { send("Need zoom value z (view 0,0,z)"); return; } + Transform3D viewTransform = new Transform3D(); viewTransform.setTranslation(vectorize("0,0," + parts[1])); viewTransformGroup.setTransform(viewTransform); } else if (parts[0].equals("clear")) { @@ -214,20 +193,24 @@ public class GravitySimulatorView extends FrameView { } } - /** - * Converts string in form x,y,z to Vector3f + /** Converts string in form x,y,z to Vector3f * @param input vector in form x,y,z - * @return + * @return Appropriate vector */ protected Vector3f vectorize(String input) { String[] vectorFields = input.split(","); return new Vector3f(new Float(vectorFields[0]), new Float(vectorFields[1]), new Float(vectorFields[2])); } + /** Sends a message to display in the terminal. + * @param message Message to send + */ protected void send(String message) { terminal.append(message + "\n"); } + /** Displays the about box. + */ @Action public void showAboutBox() { if (aboutBox == null) { diff --git a/src/edu/mit/ezyang/gravity/j3d/EditableGroup.java b/src/edu/mit/ezyang/gravity/j3d/EditableGroup.java new file mode 100644 index 0000000..b6c7118 --- /dev/null +++ b/src/edu/mit/ezyang/gravity/j3d/EditableGroup.java @@ -0,0 +1,60 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package edu.mit.ezyang.gravity.j3d; + +import com.sun.j3d.utils.picking.behaviors.PickZoomBehavior; +import edu.mit.ezyang.gravity.j3d.SmartPickTranslateBehavior; +import javax.media.j3d.BoundingSphere; +import javax.media.j3d.Bounds; +import javax.media.j3d.BranchGroup; +import javax.media.j3d.Canvas3D; +import javax.media.j3d.Node; +import javax.media.j3d.Transform3D; +import javax.media.j3d.TransformGroup; +import javax.vecmath.Point3d; +import javax.vecmath.Vector3f; + +/** + * Convenience group for adding elements that need to be editable. + * @warning Actual object should be added using addTransformChild(), NOT + * addChild(). + * @author Edward Z. Yang + */ +public class EditableGroup extends BranchGroup { + + private TransformGroup transformGroup; + + public EditableGroup(Canvas3D canvas, TransformGroup rotateGroup, Vector3f location) { + setCapability(BranchGroup.ALLOW_DETACH); + + Bounds bounds = new BoundingSphere(new Point3d(0f, 0f, 0f), 1000f); + + SmartPickTranslateBehavior translate = new SmartPickTranslateBehavior(this, canvas, bounds); + translate.setRotateTransformGroup(rotateGroup); + addChild(translate); + + // :TODO: this needs to be modified to be smart + SmartPickZoomBehavior zoom = new SmartPickZoomBehavior(this, canvas, bounds); + zoom.setRotateTransformGroup(rotateGroup); + addChild(zoom); + + transformGroup = new TransformGroup(); + transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); + transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); + transformGroup.setCapability(TransformGroup.ENABLE_PICK_REPORTING); + + Transform3D transform = new Transform3D(); + transform.setTranslation(location); + transformGroup.setTransform(transform); + + addChild(transformGroup); + } + + public void addTransformChild(Node child) { + transformGroup.addChild(child); + } + + +} diff --git a/src/edu/mit/ezyang/gravity/j3d/RotateGroup.java b/src/edu/mit/ezyang/gravity/j3d/RotateGroup.java new file mode 100644 index 0000000..9bd65c9 --- /dev/null +++ b/src/edu/mit/ezyang/gravity/j3d/RotateGroup.java @@ -0,0 +1,33 @@ +package edu.mit.ezyang.gravity.j3d; + +import com.sun.j3d.utils.behaviors.mouse.MouseRotate; +import javax.media.j3d.*; +import javax.vecmath.*; + +/** + * Customized TransformGroup class that implements mouse rotations, directional + * lighting and ambient lighting; this is the "frame" in which the universe + * operates, and can be rotated at the user's viewing pleasure. + * @author Edward Z. Yang + */ +public class RotateGroup extends TransformGroup { + public RotateGroup() { + setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); + setCapability(TransformGroup.ALLOW_TRANSFORM_READ); + + BoundingSphere bounds = new BoundingSphere(new Point3d(0f,0f,0f), 1000f); + + MouseRotate rotate = new MouseRotate(); + rotate.setSchedulingBounds(bounds); + rotate.setTransformGroup(this); + addChild(rotate); + + DirectionalLight light = new DirectionalLight(new Color3f(1.8f, 0.2f, 0.2f), new Vector3f(4.0f, -7.0f, 7.0f)); + light.setInfluencingBounds(bounds); + addChild(light); + + AmbientLight ambLight = new AmbientLight(new Color3f(.6f, .6f, .6f)); + ambLight.setInfluencingBounds(bounds); + addChild(ambLight); + } +} diff --git a/src/edu/mit/ezyang/gravity/j3d/SmartMouseBehavior.java b/src/edu/mit/ezyang/gravity/j3d/SmartMouseBehavior.java new file mode 100644 index 0000000..9fb4b10 --- /dev/null +++ b/src/edu/mit/ezyang/gravity/j3d/SmartMouseBehavior.java @@ -0,0 +1,17 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package edu.mit.ezyang.gravity.j3d; + +import javax.media.j3d.TransformGroup; + +/** + * Common methods to "smart" mouse behaviors which account for parent group + * rotations. + * @author Edward Z. Yang + */ +public interface SmartMouseBehavior { + abstract public void setRotateTransformGroup(TransformGroup group); +} diff --git a/src/edu/mit/ezyang/gravity/j3d/SmartMouseTranslate.java b/src/edu/mit/ezyang/gravity/j3d/SmartMouseTranslate.java new file mode 100644 index 0000000..713c977 --- /dev/null +++ b/src/edu/mit/ezyang/gravity/j3d/SmartMouseTranslate.java @@ -0,0 +1,151 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package edu.mit.ezyang.gravity.j3d; + +import com.sun.j3d.utils.behaviors.mouse.MouseTranslate; +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.media.j3d.*; +import javax.vecmath.*; + +/** + * Modified MouseTranslate class which accounts for a rotation in a parent + * TransformGroup when calculating translation based off of screen change. + * @warning Only the flags constructor was reimplemented; manually call + * all other methods. + * @author Edward Z. Yang + */ +public class SmartMouseTranslate extends MouseTranslate implements SmartMouseBehavior { + protected TransformGroup rotateTG; + + public SmartMouseTranslate(int flags) { + super(flags); + } + + /** + * Sets the TransformGroup used to determine the rotation that will + * be adjusted against. + * @param group TransformGroup with Transform3D rotation to adjust for + */ + public void setRotateTransformGroup(TransformGroup group) { + rotateTG = group; + } + + + /** + * @note Overridden in order to force MouseTranslate to call our overloaded + * doProcess() function. + * @param criteria + */ + @Override + public void processStimulus (Enumeration criteria) { + WakeupCriterion wakeup; + AWTEvent[] events; + MouseEvent evt; + + while (criteria.hasMoreElements()) { + wakeup = (WakeupCriterion) criteria.nextElement(); + + if (wakeup instanceof WakeupOnAWTEvent) { + events = ((WakeupOnAWTEvent)wakeup).getAWTEvent(); + if (events.length > 0) { + evt = (MouseEvent) events[events.length-1]; + doProcess(evt); + } + } + + else if (wakeup instanceof WakeupOnBehaviorPost) { + while (true) { + // access to the queue must be synchronized + synchronized (mouseq) { + if (mouseq.isEmpty()) break; + evt = (MouseEvent)mouseq.remove(0); + // consolodate MOUSE_DRAG events + while ((evt.getID() == MouseEvent.MOUSE_DRAGGED) && + !mouseq.isEmpty() && + (((MouseEvent)mouseq.get(0)).getID() == + MouseEvent.MOUSE_DRAGGED)) { + evt = (MouseEvent)mouseq.remove(0); + } + } + doProcess(evt); + } + } + + } + wakeupOn(mouseCriterion); + } + + /** + * Modified doProcess() function with transform from rotateTG + */ + private void doProcess(MouseEvent evt) { + int id; + int dx, dy; + + processMouseEvent(evt); + + if (((buttonPress)&&((flags & MANUAL_WAKEUP) == 0)) || + ((wakeUp)&&((flags & MANUAL_WAKEUP) != 0))){ + id = evt.getID(); + if ((id == MouseEvent.MOUSE_DRAGGED) && + !evt.isAltDown() && evt.isMetaDown()) { + + x = evt.getX(); + y = evt.getY(); + + dx = x - x_last; + dy = y - y_last; + + if ((!reset) && ((Math.abs(dy) < 50) && (Math.abs(dx) < 50))) { + //System.out.println("dx " + dx + " dy " + dy); + transformGroup.getTransform(currXform); + + Vector3d trans = new Vector3d(); + trans.x = dx*this.getXFactor(); + trans.y = -dy*this.getYFactor(); + + // The magic happens here: + Transform3D transform = new Transform3D(); + rotateTG.getTransform(transform); + transform.invert(); + transform.transform(trans); + // End magic + + transformX.set(trans); + + if (invert) { + currXform.mul(currXform, transformX); + } else { + currXform.mul(transformX, currXform); + } + + transformGroup.setTransform(currXform); + + transformChanged( currXform ); + + // callback is a private property, so we don't support it. + // For completeness sake, we could overload all of the + // relevant functions to reimplement it. + //if (callback!=null) + //callback.transformChanged( MouseBehaviorCallback.TRANSLATE, + // currXform ); + + } + else { + reset = false; + } + x_last = x; + y_last = y; + } + else if (id == MouseEvent.MOUSE_PRESSED) { + x_last = evt.getX(); + y_last = evt.getY(); + } + } + } +} diff --git a/src/edu/mit/ezyang/gravity/j3d/SmartMouseZoom.java b/src/edu/mit/ezyang/gravity/j3d/SmartMouseZoom.java new file mode 100644 index 0000000..0fa9e0e --- /dev/null +++ b/src/edu/mit/ezyang/gravity/j3d/SmartMouseZoom.java @@ -0,0 +1,147 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package edu.mit.ezyang.gravity.j3d; + +import com.sun.j3d.utils.behaviors.mouse.MouseZoom; +import java.awt.AWTEvent; +import java.awt.event.MouseEvent; +import java.util.Enumeration; +import javax.media.j3d.Transform3D; +import javax.media.j3d.TransformGroup; +import javax.media.j3d.WakeupCriterion; +import javax.media.j3d.WakeupOnAWTEvent; +import javax.media.j3d.WakeupOnBehaviorPost; +import javax.vecmath.Vector3d; + +/** + * Modified MouseWheelZoom class which accounts for a rotation in a parent + * TransformGroup when calculating translation based off of screen change. + * @warning Only the flags constructor was reimplemented. + * @author Edward Z. Yang + */ +public class SmartMouseZoom extends MouseZoom implements SmartMouseBehavior { + + protected TransformGroup rotateTG; + + public SmartMouseZoom(int flags) { + super(flags); + } + + /** + * Sets the TransformGroup used to determine the rotation that will + * be adjusted against. + * @param group TransformGroup with Transform3D rotation to adjust for + */ + public void setRotateTransformGroup(TransformGroup group) { + rotateTG = group; + } + + /** + * @note Overridden in order to force MouseTranslate to call our overloaded + * doProcess() function. + * @param criteria + */ + @Override + public void processStimulus(Enumeration criteria) { + WakeupCriterion wakeup; + AWTEvent[] events; + MouseEvent evt; +// int id; +// int dx, dy; + + while (criteria.hasMoreElements()) { + wakeup = (WakeupCriterion) criteria.nextElement(); + if (wakeup instanceof WakeupOnAWTEvent) { + events = ((WakeupOnAWTEvent) wakeup).getAWTEvent(); + if (events.length > 0) { + evt = (MouseEvent) events[events.length - 1]; + doProcess(evt); + } + } else if (wakeup instanceof WakeupOnBehaviorPost) { + while (true) { + synchronized (mouseq) { + if (mouseq.isEmpty()) { + break; + } + evt = (MouseEvent) mouseq.remove(0); + // consolodate MOUSE_DRAG events + while ((evt.getID() == MouseEvent.MOUSE_DRAGGED) && + !mouseq.isEmpty() && + (((MouseEvent) mouseq.get(0)).getID() == + MouseEvent.MOUSE_DRAGGED)) { + evt = (MouseEvent) mouseq.remove(0); + } + } + doProcess(evt); + } + } + + } + wakeupOn(mouseCriterion); + } + + /** + * Modified doProcess() function with transform from rotateTG + */ + void doProcess(MouseEvent evt) { + int id; + int dx, dy; + + processMouseEvent(evt); + + if (((buttonPress) && ((flags & MANUAL_WAKEUP) == 0)) || + ((wakeUp) && ((flags & MANUAL_WAKEUP) != 0))) { + id = evt.getID(); + if ((id == MouseEvent.MOUSE_DRAGGED) && + evt.isAltDown() && !evt.isMetaDown()) { + + x = evt.getX(); + y = evt.getY(); + + dx = x - x_last; + dy = y - y_last; + + if (!reset) { + transformGroup.getTransform(currXform); + + Vector3d trans = new Vector3d(); + trans.z = dy * this.getFactor(); + + // The magic happens here: + Transform3D transform = new Transform3D(); + rotateTG.getTransform(transform); + transform.invert(); + transform.transform(trans); + // End magic + + transformX.set(trans); + + if (invert) { + currXform.mul(currXform, transformX); + } else { + currXform.mul(transformX, currXform); + } + + transformGroup.setTransform(currXform); + + transformChanged(currXform); + + //if (callback!=null) + //callback.transformChanged( MouseBehaviorCallback.ZOOM, + // currXform ); + + } else { + reset = false; + } + + x_last = x; + y_last = y; + } else if (id == MouseEvent.MOUSE_PRESSED) { + x_last = evt.getX(); + y_last = evt.getY(); + } + } + } +} diff --git a/src/edu/mit/ezyang/gravity/j3d/SmartPickTranslateBehavior.java b/src/edu/mit/ezyang/gravity/j3d/SmartPickTranslateBehavior.java new file mode 100644 index 0000000..caa5626 --- /dev/null +++ b/src/edu/mit/ezyang/gravity/j3d/SmartPickTranslateBehavior.java @@ -0,0 +1,103 @@ +package edu.mit.ezyang.gravity.j3d; + +import com.sun.j3d.utils.picking.behaviors.*; +import com.sun.j3d.utils.picking.*; +import com.sun.j3d.utils.behaviors.mouse.*; +import javax.media.j3d.*; + +/** + * Reimplemented PickTranslateBehavior, but uses SmartMouseTranslate, which + * has been customized to take into account rotations relative to the surface + * display. Modifications are solely in constructor and new setRotateTransformGroup + * method. + * @warning Convenience constructor with pick mode parameter not implemented. + * @author Edward Z. Yang + */ +public class SmartPickTranslateBehavior extends PickMouseBehavior implements MouseBehaviorCallback { + + private SmartMouseTranslate translate; + private PickingCallback callback = null; + private TransformGroup currentTG; + + /** + * Propagates rotation transform group to SmartMouseTranslate in order + * to provide appropriate information to transform. + * @note We only support one rotation transform group; this should be + * enough for people with shallow object graphs. + * @param group TransformGroup with rotation we need to adjust to + */ + public void setRotateTransformGroup(TransformGroup group) { + translate.setRotateTransformGroup(group); + } + + /** + * Creates a pick/translate behavior that waits for user mouse events for + * the scene graph. + * @param root Root of your scene graph. + * @param canvas Java 3D drawing canvas. + * @param bounds Bounds of your scene. + **/ + public SmartPickTranslateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds) { + super(canvas, root, bounds); + translate = new SmartMouseTranslate(MouseBehavior.MANUAL_WAKEUP); + translate.setTransformGroup(currGrp); + currGrp.addChild(translate); + translate.setSchedulingBounds(bounds); + this.setSchedulingBounds(bounds); + } + + // below code is copied verbatim from com.sun.j3d.utils.picking.behaviors + + /** + * Update the scene to manipulate any nodes. This is not meant to be + * called by users. Behavior automatically calls this. You can call + * this only if you know what you are doing. + * + * @param xpos Current mouse X pos. + * @param ypos Current mouse Y pos. + **/ + public void updateScene(int xpos, int ypos) { + TransformGroup tg = null; + + if (!mevent.isAltDown() && mevent.isMetaDown()) { + + pickCanvas.setShapeLocation(xpos, ypos); + PickResult pr = pickCanvas.pickClosest(); + if ((pr != null) && + ((tg = (TransformGroup) pr.getNode(PickResult.TRANSFORM_GROUP)) != null) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))) { + + translate.setTransformGroup(tg); + translate.wakeup(); + currentTG = tg; + // Need to clean up Issue 123 --- Chien + // freePickResult(pr); + } else if (callback != null) { + callback.transformChanged(PickingCallback.NO_PICK, null); + } + } + + } + + /** + * Callback method from MouseTranslate + * This is used when the Picking callback is enabled + */ + public void transformChanged(int type, Transform3D transform) { + callback.transformChanged(PickingCallback.TRANSLATE, currentTG); + } + + /** + * Register the class @param callback to be called each + * time the picked object moves + */ + public void setupCallback(PickingCallback callback) { + this.callback = callback; + if (callback == null) { + translate.setupCallback(null); + } else { + translate.setupCallback(this); + } + } +} diff --git a/src/edu/mit/ezyang/gravity/j3d/SmartPickZoomBehavior.java b/src/edu/mit/ezyang/gravity/j3d/SmartPickZoomBehavior.java new file mode 100644 index 0000000..440c35f --- /dev/null +++ b/src/edu/mit/ezyang/gravity/j3d/SmartPickZoomBehavior.java @@ -0,0 +1,109 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package edu.mit.ezyang.gravity.j3d; + +import com.sun.j3d.utils.behaviors.mouse.MouseBehavior; +import com.sun.j3d.utils.behaviors.mouse.MouseBehaviorCallback; +import com.sun.j3d.utils.behaviors.mouse.MouseZoom; +import com.sun.j3d.utils.picking.PickResult; +import com.sun.j3d.utils.picking.behaviors.PickMouseBehavior; +import com.sun.j3d.utils.picking.behaviors.PickingCallback; +import javax.media.j3d.Bounds; +import javax.media.j3d.BranchGroup; +import javax.media.j3d.Canvas3D; +import javax.media.j3d.Transform3D; +import javax.media.j3d.TransformGroup; + +/** + * Reimplemented PickZoomBehavior, but uses SmartMouseWheelZoom, which + * has been customized to take into account rotations relative to the surface + * display. Modifications are solely in constructor and new setRotateTransformGroup + * method. + * @author Edward Z. Yang + */ +public class SmartPickZoomBehavior extends PickMouseBehavior implements MouseBehaviorCallback { + + private SmartMouseZoom zoom; + private PickingCallback callback = null; + private TransformGroup currentTG; + + /** + * Propagates rotation transform group to SmartMouseTranslate in order + * to provide appropriate information to transform. + * @note We only support one rotation transform group; this should be + * enough for people with shallow object graphs. + * @param group TransformGroup with rotation we need to adjust to + */ + public void setRotateTransformGroup(TransformGroup group) { + zoom.setRotateTransformGroup(group); + } + + /** + * Creates a pick/zoom behavior that waits for user mouse events for + * the scene graph. + * @param root Root of your scene graph. + * @param canvas Java 3D drawing canvas. + * @param bounds Bounds of your scene. + **/ + public SmartPickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds) { + super(canvas, root, bounds); + zoom = new SmartMouseZoom(MouseBehavior.MANUAL_WAKEUP); + zoom.setTransformGroup(currGrp); + currGrp.addChild(zoom); + zoom.setSchedulingBounds(bounds); + this.setSchedulingBounds(bounds); + } + + /** + * Update the scene to manipulate any nodes. This is not meant to be + * called by users. Behavior automatically calls this. You can call + * this only if you know what you are doing. + * + * @param xpos Current mouse X pos. + * @param ypos Current mouse Y pos. + **/ + public void updateScene(int xpos, int ypos) { + TransformGroup tg = null; + + if (mevent.isAltDown() && !mevent.isMetaDown()) { + + pickCanvas.setShapeLocation(xpos, ypos); + PickResult pr = pickCanvas.pickClosest(); + if ((pr != null) && + ((tg = (TransformGroup) pr.getNode(PickResult.TRANSFORM_GROUP)) != null) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) && + (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))) { + zoom.setTransformGroup(tg); + zoom.wakeup(); + currentTG = tg; + // Need to clean up Issue 123 --- Chien + // freePickResult(pr); + } else if (callback != null) { + callback.transformChanged(PickingCallback.NO_PICK, null); + } + } + } + + /** + * Callback method from MouseZoom + * This is used when the Picking callback is enabled + */ + public void transformChanged(int type, Transform3D transform) { + callback.transformChanged(PickingCallback.ZOOM, currentTG); + } + + /** + * Register the class @param callback to be called each + * time the picked object moves + */ + public void setupCallback(PickingCallback callback) { + this.callback = callback; + if (callback == null) { + zoom.setupCallback(null); + } else { + zoom.setupCallback(this); + } + } +} diff --git a/src/edu/mit/ezyang/gravity/resources/GravitySimulatorApp.properties b/src/edu/mit/ezyang/gravity/resources/GravitySimulatorApp.properties dissimilarity index 70% index 61d16cd..f366d76 100644 --- a/src/edu/mit/ezyang/gravity/resources/GravitySimulatorApp.properties +++ b/src/edu/mit/ezyang/gravity/resources/GravitySimulatorApp.properties @@ -1,11 +1,11 @@ -# Application global resources - -Application.name = GravitySimulator -Application.title = Basic Application Example -Application.version = 1.0 -Application.vendor = Sun Microsystems Inc. -Application.homepage = http://appframework.dev.java.net -Application.description = A simple java desktop application based on Swing Application Framework -Application.vendorId = Sun -Application.id = ${Application.name} -Application.lookAndFeel = system +# Application global resources + +Application.name = GravitySimulator +Application.title = Gravity Simulator +Application.version = 1.0 +Application.vendor = MIT +Application.homepage = +Application.description = Simulation of Gravity in 3D space for 8.012 +Application.vendorId = MIT +Application.id = GravitySimulator +Application.lookAndFeel = system -- 2.11.4.GIT