// **********************************************************************
//
// <copyright>
//
// BBN Technologies
// 10 Moulton Street
// Cambridge, MA 02138
// (617) 873-8000
//
// Copyright (C) BBNT Solutions LLC. All rights reserved.
//
// </copyright>
// **********************************************************************
//
// $Source: /cvs/distapps/openmap/src/j3d/com/bbn/openmap/tools/j3d/OMKeyBehavior.java,v $
// $RCSfile: OMKeyBehavior.java,v $
// $Revision: 1.5 $
// $Date: 2005/08/11 19:27:04 $
// $Author: dietrick $
//
// **********************************************************************
package com.bbn.openmap.tools.j3d;
import java.awt.AWTEvent;
import java.awt.event.KeyEvent;
import java.util.Enumeration;
import javax.media.j3d.Behavior;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.WakeupCondition;
import javax.media.j3d.WakeupCriterion;
import javax.media.j3d.WakeupOnAWTEvent;
import javax.media.j3d.WakeupOr;
import javax.vecmath.Vector3d;
import com.bbn.openmap.proj.Projection;
import com.bbn.openmap.util.Debug;
/**
* OMKeyBehavior is a modified version of KeyBehavior, available from
* http://www.J3D.org. The modifications include having a notion of
* body position, and view position. You can modify a view, which can
* be thought of as where your eyes are pointing. You can also modify
* the position, which can be thought of where your body is pointing.
* So, you can look in a different directin than your motion.This
* allows the user to adjust the view angle to the map, but not have
* it interfere with navigation - for instance, you can look down at
* the ground, but not fly into it, instead keeping a constant
* distance above it.
*
* <P>
* The controls are:
*
* <pre>
*
* left - turn left
* right - turn right
* up - move forward
* down - move backward
*
* Cntl left - look down
* Cntl right - look up
* Cntl up - move up (elevation)
* Cntl down - move down (elevation)
*
* Alt right - move right
* Alt left - move left
* Alt up - rotate up (movement forward will increase elevation).
* Alt down - rotate down (movement forward will decrease elevation).
*
*
* </pre>
*
* From the original KeyBehavier header:
*
* <pre>
*
* KeyBehavior is a generic behavior class to take key presses and move a
* TransformGroup through a Java3D scene. The actions resulting from the key strokes
* are modified by using the Ctrl, Alt and Shift keys.
*
* (version 1.0) reconstructed class to make more generic.
*
* MODIFIED:
*
*
* @author Andrew AJ Cain, Swinburne University,
* Australia <acain@it.swin.edu.au> edited from code
* by: Gary S. Moss <moss@arl.mil> U. S. Army Research
* Laboratory * CLASS NAME: KeyBehavior PUBLIC
* FEATURES: // Data // Constructors // Methods:
* COLLABORATORS:
* </pre>
*
* @version 1.0, 25 September 1998 aajc
*/
public class OMKeyBehavior extends Behavior {
protected final static double FAST_SPEED = 2.0;
protected final static double NORMAL_SPEED = 1.0;
protected final static double SLOW_SPEED = 0.5;
private TransformGroup cameraTransformGroup;
private Transform3D transform3D;
private Transform3D locationTransform3D;
private Transform3D xRotLookTransform;
private Transform3D yRotLookTransform;
private Transform3D zRotLookTransform;
private WakeupCondition keyCriterion;
protected final static double TWO_PI = (2.0 * Math.PI);
protected double rotateXAmount = Math.PI / 16.0;
protected double rotateYAmount = Math.PI / 16.0;
protected double rotateZAmount = Math.PI / 16.0;
protected double moveRate = 0.3;
protected double speed = NORMAL_SPEED;
protected int forwardKey = KeyEvent.VK_UP;
protected int backKey = KeyEvent.VK_DOWN;
protected int leftKey = KeyEvent.VK_LEFT;
protected int rightKey = KeyEvent.VK_RIGHT;
protected boolean DEBUG = false;
protected Projection projection;
public OMKeyBehavior(TransformGroup cameraTG, Projection proj) {
this(cameraTG, proj, null);
}
public OMKeyBehavior(TransformGroup cameraTG, Projection proj,
Vector3d initialLocation) {
projection = proj;
DEBUG = Debug.debugging("3dkey");
cameraTransformGroup = cameraTG;
transform3D = new Transform3D();
locationTransform3D = new Transform3D();
// These are the looking transforms, for the view.
xRotLookTransform = new Transform3D();
yRotLookTransform = new Transform3D();
zRotLookTransform = new Transform3D();
setViewerLocation(initialLocation);
setEnable(true);
}
public void initialize() {
WakeupCriterion[] keyEvents = new WakeupCriterion[2];
keyEvents[0] = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED);
keyEvents[1] = new WakeupOnAWTEvent(KeyEvent.KEY_RELEASED);
keyCriterion = new WakeupOr(keyEvents);
wakeupOn(keyCriterion);
}
public void setViewerLocation(Vector3d initialLocation) {
cameraTransformGroup.getTransform(locationTransform3D);
// scale of < 1 shrinks the object. (.5) is the scale.
float scale = 1f;
if (initialLocation == null) {
initialLocation = new Vector3d();
// So, this lays out where the land is, in relation to the
// viewer. We should get the projection from the MapBean,
// and
// offset the transform to the middle of the map.
if (projection != null) {
float centerXOffset = projection.getWidth() / 2f * scale;
float centerYOffset = projection.getHeight() * 2 / 3f * scale;
Debug.message("3d", "OM3DViewer with projection " + projection
+ ", setting center of scene to " + centerXOffset
+ ", " + centerYOffset);
initialLocation.set((double) centerXOffset,
(double) 50,
(double) centerYOffset);
} else {
initialLocation.set(0.0, 50, 0.0);
}
}
Transform3D toMove = new Transform3D();
toMove.set(scale, initialLocation);
locationTransform3D.mul(toMove);
cameraTransformGroup.setTransform(locationTransform3D);
}
public void processStimulus(Enumeration criteria) {
if (DEBUG) {
Debug.output("OMKeyBehavior: processStimulus");
}
WakeupCriterion wakeup;
AWTEvent[] event;
while (criteria.hasMoreElements()) {
wakeup = (WakeupCriterion) criteria.nextElement();
if (!(wakeup instanceof WakeupOnAWTEvent)) {
continue;
}
event = ((WakeupOnAWTEvent) wakeup).getAWTEvent();
for (int i = 0; i < event.length; i++) {
if (event[i].getID() == KeyEvent.KEY_PRESSED) {
processKeyEvent((KeyEvent) event[i]);
}
}
}
wakeupOn(keyCriterion);
}
protected void processKeyEvent(KeyEvent event) {
int keycode = event.getKeyCode();
if (event.isShiftDown()) {
speed = FAST_SPEED;
} else {
speed = NORMAL_SPEED;
}
if (event.isAltDown()) {
altMove(keycode);
} else if (event.isControlDown()) {
controlMove(keycode);
} else {
standardMove(keycode);
}
}
//moves forward backward or rotates left right
protected void standardMove(int keycode) {
if (keycode == forwardKey) {
moveForward();
} else if (keycode == backKey) {
moveBackward();
} else if (keycode == leftKey) {
rotLeft();
} else if (keycode == rightKey) {
rotRight();
}
}
//moves left right, rotate up down
protected void altMove(int keycode) {
if (DEBUG) {
Debug.output("altMove");
}
if (keycode == forwardKey) {
rotUp();
} else if (keycode == backKey) {
rotDown();
} else if (keycode == leftKey) {
moveLeft();
} else if (keycode == rightKey) {
moveRight();
}
}
//move up down, rot left right
protected void controlMove(int keycode) {
if (keycode == forwardKey) {
moveUp();
} else if (keycode == backKey) {
moveDown();
} else if (keycode == leftKey) {
// rollLeft();
lookUp();
} else if (keycode == rightKey) {
// rollRight();
lookDown();
}
}
public void moveForward() {
if (DEBUG) {
Debug.output("Moving forward +");
}
doMove(new Vector3d(0.0, 0.0, -getMovementRate()));
}
public void moveBackward() {
if (DEBUG) {
Debug.output("Moving Backward _");
}
doMove(new Vector3d(0.0, 0.0, getMovementRate()));
}
public void moveLeft() {
if (DEBUG) {
Debug.output("Moving left <");
}
doMove(new Vector3d(-getMovementRate(), 0.0, 0.0));
}
public void moveRight() {
if (DEBUG) {
Debug.output("Moving right >");
}
doMove(new Vector3d(getMovementRate(), 0.0, 0.0));
}
public void moveUp() {
if (DEBUG) {
Debug.output("Moving up ^");
}
doMove(new Vector3d(0.0, getMovementRate(), 0.0));
}
public void moveDown() {
if (DEBUG) {
Debug.output("Moving down v ");
}
doMove(new Vector3d(0.0, -getMovementRate(), 0.0));
}
public void rotRight() {
if (DEBUG) {
Debug.output("Rotating right");
}
doRotateY(getRotateRightAmount());
}
public void lookRight() {
if (DEBUG) {
Debug.output("Looking right");
}
doLookY(getRotateRightAmount());
}
public void rotUp() {
if (DEBUG) {
Debug.output("Rotating up");
}
doRotateX(getRotateUpAmount());
}
public void lookUp() {
if (DEBUG) {
Debug.output("Looking up");
}
doLookX(getRotateUpAmount());
}
public void rotLeft() {
if (DEBUG) {
Debug.output("Rotating left");
}
doRotateY(getRotateLeftAmount());
}
public void lookLeft() {
if (DEBUG) {
Debug.output("Looking left");
}
doLookY(getRotateLeftAmount());
}
public void rotDown() {
if (DEBUG) {
Debug.output("Rotating down");
}
doRotateX(getRotateDownAmount());
}
public void lookDown() {
if (DEBUG) {
Debug.output("Looking down");
}
doLookX(getRotateDownAmount());
}
/**
* Rotating position on the z axis, negative.
*/
public void rollLeft() {
if (DEBUG) {
Debug.output("Rolling left");
}
doRotateZ(getRollLeftAmount());
}
/**
* Tilting the view to the left.
*/
public void rollLookLeft() {
if (DEBUG) {
Debug.output("Tilting left");
}
doLookZ(getRollLeftAmount());
}
/**
* Rotating position on the z axis, positive.
*/
public void rollRight() {
if (DEBUG) {
Debug.output("Rolling right");
}
doRotateZ(getRollRightAmount());
}
/**
* Tilting the view to the right.
*/
public void rollLookRight() {
if (DEBUG) {
Debug.output("Tilting right");
}
doLookZ(getRollRightAmount());
}
protected void changePosition(Transform3D toMove) {
cameraTransformGroup.getTransform(transform3D);
// Gather the total look transform on all three axis
Transform3D viewTransform = new Transform3D();
viewTransform.invert(xRotLookTransform);
viewTransform.mulInverse(yRotLookTransform);
viewTransform.mulInverse(zRotLookTransform);
transform3D.mul(viewTransform);
transform3D.mul(toMove);
// May have to create and multiply the non-inverse look
// transforms.
transform3D.mulInverse(viewTransform);
cameraTransformGroup.setTransform(transform3D);
}
public void doRotateY(double radians) {
if (DEBUG) {
Debug.output("OMKeyBehavior: rotating Y " + radians + " radians");
}
Transform3D toMove = new Transform3D();
toMove.rotY(radians);
changePosition(toMove);
}
public void doLookY(double radians) {
if (DEBUG) {
Debug.output("OMKeyBehavior: rotating view Y " + radians
+ " radians");
}
cameraTransformGroup.getTransform(transform3D);
Transform3D toMove = new Transform3D();
toMove.rotY(radians);
transform3D.mul(toMove);
cameraTransformGroup.setTransform(transform3D);
//Keep track of the view y rotation.
yRotLookTransform.mul(toMove);
}
public void doRotateX(double radians) {
if (DEBUG) {
Debug.output("OMKeyBehavior: rotating X " + radians + " radians");
}
Transform3D toMove = new Transform3D();
toMove.rotX(radians);
changePosition(toMove);
}
public void doLookX(double radians) {
if (DEBUG) {
Debug.output("OMKeyBehavior: rotating view X " + radians
+ " radians");
}
cameraTransformGroup.getTransform(transform3D);
Transform3D toMove = new Transform3D();
toMove.rotX(radians);
transform3D.mul(toMove);
cameraTransformGroup.setTransform(transform3D);
//Keep track of the view x rotation.
xRotLookTransform.mul(toMove);
}
public void doRotateZ(double radians) {
if (DEBUG) {
Debug.output("OMKeyBehavior: rotating Z " + radians + " radians");
}
Transform3D toMove = new Transform3D();
toMove.rotZ(radians);
changePosition(toMove);
}
public void doLookZ(double radians) {
if (DEBUG) {
Debug.output("OMKeyBehavior: rotating view Z " + radians
+ " radians");
}
cameraTransformGroup.getTransform(transform3D);
Transform3D toMove = new Transform3D();
toMove.rotZ(radians);
transform3D.mul(toMove);
cameraTransformGroup.setTransform(transform3D);
//Keep track of the view z rotation.
zRotLookTransform.mul(toMove);
}
public void doMove(Vector3d theMove) {
if (DEBUG) {
Debug.output("OMKeyBehavior: moving " + theMove);
Debug.output(" transform before:\n " + transform3D);
}
Transform3D toMove = new Transform3D();
toMove.setTranslation(theMove);
changePosition(toMove);
}
public double getMovementRate() {
return moveRate * speed;
}
public double getRollLeftAmount() {
return rotateZAmount * speed;
}
public double getRollRightAmount() {
return -rotateZAmount * speed;
}
public double getRotateUpAmount() {
return rotateYAmount * speed;
}
public double getRotateDownAmount() {
return -rotateYAmount * speed;
}
public double getRotateLeftAmount() {
return rotateYAmount * speed;
}
public double getRotateRightAmount() {
return -rotateYAmount * speed;
}
public void setRotateXAmount(double radians) {
rotateXAmount = radians;
}
public void setRotateYAmount(double radians) {
rotateYAmount = radians;
}
public void setRotateZAmount(double radians) {
rotateZAmount = radians;
}
public void setMovementRate(double meters) {
moveRate = meters;
// Travel rate in meters/frame
}
public void setForwardKey(int key) {
forwardKey = key;
}
public void setBackKey(int key) {
backKey = key;
}
public void setLeftKey(int key) {
leftKey = key;
}
public void setRightKey(int key) {
rightKey = key;
}
}