Improved mouse behaviors : Mouse Keyboard Action « 3D « Java

Java
1. 2D Graphics GUI
2. 3D
3. Advanced Graphics
4. Ant
5. Apache Common
6. Chart
7. Collections Data Structure
8. Database SQL JDBC
9. Design Pattern
10. Development Class
11. Email
12. Event
13. File Input Output
14. Game
15. Hibernate
16. J2EE
17. J2ME
18. JDK 6
19. JSP
20. JSTL
21. Language Basics
22. Network Protocol
23. PDF RTF
24. Regular Expressions
25. Security
26. Servlets
27. Spring
28. Swing Components
29. Swing JFC
30. SWT JFace Eclipse
31. Threads
32. Tiny Application
33. Velocity
34. Web Services SOA
35. XML
Microsoft Office Word 2007 Tutorial
Java Tutorial
Java Source Code / Java Documentation
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
C# / C Sharp
C# / CSharp Tutorial
ASP.Net
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
PHP
Python
SQL Server / T-SQL
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Java » 3D » Mouse Keyboard ActionScreenshots 
Improved mouse behaviors
Improved mouse behaviors

/**********************************************************
 Copyright (C) 2001   Daniel Selman

 First distributed with the book "Java 3D Programming"
 by Daniel Selman and published by Manning Publications.
 http://manning.com/selman

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation, version 2.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 The license can be found on the WWW at:
 http://www.fsf.org/copyleft/gpl.html

 Or by writing to:
 Free Software Foundation, Inc.,
 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

 Authors can be contacted at:
 Daniel Selman: daniel@selman.org

 If you make changes you think others would like, please 
 contact one of the authors or someone at the 
 www.j3d.org web site.
 **************************************************************/

import java.applet.Applet;
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.GraphicsConfigTemplate;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Label;
import java.awt.Panel;
import java.awt.TextField;
import java.awt.event.MouseEvent;
import java.io.File;
import java.net.URL;
import java.util.Enumeration;

import javax.media.j3d.Appearance;
import javax.media.j3d.AudioDevice;
import javax.media.j3d.Background;
import javax.media.j3d.Behavior;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.Bounds;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.GraphicsConfigTemplate3D;
import javax.media.j3d.Group;
import javax.media.j3d.Locale;
import javax.media.j3d.PhysicalBody;
import javax.media.j3d.PhysicalEnvironment;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.View;
import javax.media.j3d.ViewPlatform;
import javax.media.j3d.VirtualUniverse;
import javax.media.j3d.WakeupCriterion;
import javax.media.j3d.WakeupOnAWTEvent;
import javax.media.j3d.WakeupOr;
import javax.vecmath.Color3f;
import javax.vecmath.Matrix3d;
import javax.vecmath.Matrix4d;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;

import com.sun.j3d.audioengines.javasound.JavaSoundMixer;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.ColorCube;

/**
 * This example illustrates the mouse behaviors defined in the
 * org.selman.java3d.book package. These improved mouse behaviors: - handle
 * TransformGroups above the target TG properly <br>- can be applied to any
 * object, not just TGs <br>- support interface reporting to give easy feedback
 * on all manipulations <br>- better motion speed control <br>- range
 * validation to clamp scales and translation between limits <br>
 */
public class MouseNavigateTest extends Java3dApplet implements
    ScaleChangeListener, RotationChangeListener, TranslationChangeListener {
  private static int m_kWidth = 300;

  private static int m_kHeight = 400;

  // create some UI to provide feedback on all mouse
  // manipulations
  Label m_RotationLabel = null;

  TextField m_RotationFieldX = null;

  TextField m_RotationFieldY = null;

  TextField m_RotationFieldZ = null;

  Label m_TranslationLabel = null;

  TextField m_TranslationFieldX = null;

  TextField m_TranslationFieldY = null;

  TextField m_TranslationFieldZ = null;

  Label m_ScaleLabel = null;

  TextField m_ScaleFieldZ = null;

  TextField m_ScaleFieldY = null;

  TextField m_ScaleFieldX = null;

  public MouseNavigateTest() {
    initJava3d();
  }

  protected void addCanvas3D(Canvas3D c3d) {
    setLayout(new BorderLayout());
    add(c3d, BorderLayout.CENTER);

    Panel controlPanel = new Panel();

    // add the UI to the frame
    m_RotationLabel = new Label("Rotation: ");
    m_RotationFieldX = new TextField("0.00");
    m_RotationFieldY = new TextField("0.00");
    m_RotationFieldZ = new TextField("0.00");
    controlPanel.add(m_RotationLabel);
    controlPanel.add(m_RotationFieldX);
    controlPanel.add(m_RotationFieldY);
    controlPanel.add(m_RotationFieldZ);

    m_TranslationLabel = new Label("Translation: ");
    m_TranslationFieldX = new TextField("0.00");
    m_TranslationFieldY = new TextField("0.00");
    m_TranslationFieldZ = new TextField("0.00");
    controlPanel.add(m_TranslationLabel);
    controlPanel.add(m_TranslationFieldX);
    controlPanel.add(m_TranslationFieldY);
    controlPanel.add(m_TranslationFieldZ);

    m_ScaleLabel = new Label("Scale: ");
    m_ScaleFieldX = new TextField("0.00");
    m_ScaleFieldY = new TextField("0.00");
    m_ScaleFieldZ = new TextField("0.00");
    controlPanel.add(m_ScaleLabel);
    controlPanel.add(m_ScaleFieldX);
    controlPanel.add(m_ScaleFieldY);
    controlPanel.add(m_ScaleFieldZ);

    add(controlPanel, BorderLayout.SOUTH);

    doLayout();
  }

  protected double getScale() {
    return 1.0;
  }

  // do nothing for these notifications from the mouse behaviors
  public void onStartDrag(Object target) {
  }

  public void onEndDrag(Object target) {
  }

  public void onApplyTransform(Object target) {
  }

  public void onAdjustTransform(Object target, int xpos, int ypos) {
  }

  // called by TornadoMouseRotate
  // yes, those really are Euler angles for the objects rotation
  public void onRotate(Object target, Point3d point3d) {
    m_RotationFieldX.setText(String.valueOf((intjava.lang.Math
        .toDegrees(point3d.x)));
    m_RotationFieldY.setText(String.valueOf((intjava.lang.Math
        .toDegrees(point3d.y)));
    m_RotationFieldZ.setText(String.valueOf((intjava.lang.Math
        .toDegrees(point3d.z)));
  }

  // called by TornadoMouseScale
  public void onScale(Object target, Vector3d scale) {
    m_ScaleFieldX.setText(String.valueOf(scale.x));
    m_ScaleFieldY.setText(String.valueOf(scale.y));
    m_ScaleFieldZ.setText(String.valueOf(scale.z));
  }

  // called by TornadoMouseTranslate
  public void onTranslate(Object target, Vector3d vTranslation) {
    m_TranslationFieldX.setText(String.valueOf(vTranslation.x));
    m_TranslationFieldY.setText(String.valueOf(vTranslation.y));
    m_TranslationFieldZ.setText(String.valueOf(vTranslation.z));
  }

  // we want a black background
  protected Background createBackground() {
    return null;
  }

  protected BranchGroup createSceneBranchGroup() {
    BranchGroup objRoot = super.createSceneBranchGroup();

    // note that we are creating a TG *above* the TG
    // the is being controlled by the mouse behaviors.
    // The SUN mouse translate behavior would fail in this
    // instance as all movement would be in the X-Y plane
    // irrespective of any TG above the object.
    // The TornadoMouseTranslate behavior always moves an object
    // parrallel to the image plane
    TransformGroup objTrans1 = new TransformGroup();
    Transform3D t3d = new Transform3D();
    objTrans1.getTransform(t3d);
    t3d.setEuler(new Vector3d(0.90.80.3));
    objTrans1.setTransform(t3d);

    TransformGroup objTrans = new TransformGroup();
    objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);

    // create the mouse scale behavior and set limits
    TornadoMouseScale mouseScale = new TornadoMouseScale(50.1f);
    mouseScale.setMinScale(new Point3d(0.50.50.5));
    mouseScale.setMaxScale(new Point3d(222));
    mouseScale.setObject(objTrans);
    mouseScale.setChangeListener(this);
    mouseScale.setSchedulingBounds(getApplicationBounds());
    objTrans.addChild(mouseScale);

    // create the mouse rotate behavior
    TornadoMouseRotate mouseRotate = new TornadoMouseRotate(0.0010.001);
    mouseRotate.setInvert(true);
    mouseRotate.setObject(objTrans);
    mouseRotate.setChangeListener(this);
    mouseRotate.setSchedulingBounds(getApplicationBounds());
    objTrans.addChild(mouseRotate);

    // create the mouse translate behavior and set limits
    TornadoMouseTranslate mouseTrans = new TornadoMouseTranslate(0.005f);
    mouseTrans.setObject(objTrans);
    mouseTrans.setChangeListener(this);
    mouseTrans.setMinTranslate(new Point3d(-4, -4, -4));
    mouseTrans.setMaxTranslate(new Point3d(444));
    mouseTrans.setSchedulingBounds(getApplicationBounds());
    objTrans.addChild(mouseTrans);

    objTrans.addChild(new ColorCube(0.5));

    // create some axis for the world to show it has been rotated
    ColorCube axis = new ColorCube(5.0);
    Appearance app = new Appearance();
    app
        .setPolygonAttributes(new PolygonAttributes(
            PolygonAttributes.POLYGON_LINE,
            PolygonAttributes.CULL_NONE, 0));
    axis.setAppearance(app);
    objTrans1.addChild(axis);

    objTrans1.addChild(objTrans);
    objRoot.addChild(objTrans1);

    return objRoot;
  }

  public static void main(String[] args) {
    MouseNavigateTest mouseTest = new MouseNavigateTest();
    mouseTest.saveCommandLineArguments(args);

    new MainFrame(mouseTest, m_kWidth, m_kHeight);
  }
}

//*****************************************************************************
/**
 * TornadoMouseRotate
 
 * Custom mouse rotation behaviour
 
 @author Daniel Selman
 @version 1.0
 */
//*****************************************************************************

class TornadoMouseRotate extends TornadoMouseBehavior {
  protected double m_FactorX = 0.001;

  protected double m_FactorY = 0.001;

  protected Transform3D m_TransformX = null;

  protected Transform3D m_TransformY = null;

  protected boolean m_bInvert = false;

  //*****************************************************************************
  /**
   @param xf
   *            the x rotation scale factor
   @param yf
   *            the y rotation scale factor
   */
  //*****************************************************************************
  public TornadoMouseRotate(double xf, double yf) {
    m_FactorX = xf;
    m_FactorY = yf;

    m_TransformX = new Transform3D();
    m_TransformY = new Transform3D();

    m_bInvert = false;
  }

  protected boolean isStartBehaviorEvent(java.awt.event.MouseEvent evt) {
    int nId = evt.getID();
    return ((nId == MouseEvent.MOUSE_DRAGGED&& (evt.isAltDown() == false&& (evt
        .isMetaDown() == false));
  }

  //*****************************************************************************
  /**
   @param bInvert
   *            true to invert the Y axis
   */
  //*****************************************************************************
  public void setInvert(boolean bInvert) {
    m_bInvert = bInvert;
  }

  // this behavior is relative to the *screen*
  // the current rotation of the object etc. is ignored
  protected boolean isRelativeToObjectCoordinates() {
    return false;
  }

  protected void applyVectorToObject(Vector3f vector) {
    TransformGroup tg = getTransformGroup();

    if (tg != null) {
      tg.getTransform(m_Transform3D);

      double x_angle = vector.y * m_FactorX;
      double y_angle = vector.x * m_FactorY;

      m_TransformX.rotX(x_angle);
      m_TransformY.rotY(y_angle);

      Matrix4d mat = new Matrix4d();

      // Remember old matrix
      m_Transform3D.get(mat);

      // Translate to origin
      m_Transform3D.setTranslation(new Vector3d(0.00.00.0));

      if (m_bInvert != false) {
        m_Transform3D.mul(m_Transform3D, m_TransformX);
        m_Transform3D.mul(m_Transform3D, m_TransformY);
      else {
        m_Transform3D.mul(m_TransformX, m_Transform3D);
        m_Transform3D.mul(m_TransformY, m_Transform3D);
      }

      // Set old translation back
      Vector3d translation = new Vector3d(mat.m03, mat.m13, mat.m23);
      m_Transform3D.setTranslation(translation);

      // save the new Transform3D
      applyTransform();

      if (m_Listener != null) {
        Point3d rotate = Euler.getEulerRotation(m_Transform3D);
        ((RotationChangeListenerm_Listener)
            .onRotate(m_Object, rotate);
      }
    }
  }
// TornadoMouseRotate

class Euler {
  public static int EulOrdXYZs() {
    return EulOrd(X, EulParEven, EulRepNo, EulFrmS);
  }

  public static int EulOrdXYXs() {
    return EulOrd(X, EulParEven, EulRepYes, EulFrmS);
  }

  public static int EulOrdXZYs() {
    return EulOrd(X, EulParOdd, EulRepNo, EulFrmS);
  }

  public static int EulOrdXZXs() {
    return EulOrd(X, EulParOdd, EulRepYes, EulFrmS);
  }

  public static int EulOrdYZXs() {
    return EulOrd(Y, EulParEven, EulRepNo, EulFrmS);
  }

  public static int EulOrdYZYs() {
    return EulOrd(Y, EulParEven, EulRepYes, EulFrmS);
  }

  public static int EulOrdYXZs() {
    return EulOrd(Y, EulParOdd, EulRepNo, EulFrmS);
  }

  public static int EulOrdYXYs() {
    return EulOrd(Y, EulParOdd, EulRepYes, EulFrmS);
  }

  public static int EulOrdZXYs() {
    return EulOrd(Z, EulParEven, EulRepNo, EulFrmS);
  }

  public static int EulOrdZXZs() {
    return EulOrd(Z, EulParEven, EulRepYes, EulFrmS);
  }

  public static int EulOrdZYXs() {
    return EulOrd(Z, EulParOdd, EulRepNo, EulFrmS);
  }

  public static int EulOrdZYZs() {
    return EulOrd(Z, EulParOdd, EulRepYes, EulFrmS);
  }

  /* Rotating axes */
  public static int EulOrdZYXr() {
    return EulOrd(X, EulParEven, EulRepNo, EulFrmR);
  }

  public static int EulOrdXYXr() {
    return EulOrd(X, EulParEven, EulRepYes, EulFrmR);
  }

  public static int EulOrdYZXr() {
    return EulOrd(X, EulParOdd, EulRepNo, EulFrmR);
  }

  public static int EulOrdXZXr() {
    return EulOrd(X, EulParOdd, EulRepYes, EulFrmR);
  }

  public static int EulOrdXZYr() {
    return EulOrd(Y, EulParEven, EulRepNo, EulFrmR);
  }

  public static int EulOrdYZYr() {
    return EulOrd(Y, EulParEven, EulRepYes, EulFrmR);
  }

  public static int EulOrdZXYr() {
    return EulOrd(Y, EulParOdd, EulRepNo, EulFrmR);
  }

  public static int EulOrdYXYr() {
    return EulOrd(Y, EulParOdd, EulRepYes, EulFrmR);
  }

  public static int EulOrdYXZr() {
    return EulOrd(Z, EulParEven, EulRepNo, EulFrmR);
  }

  public static int EulOrdZXZr() {
    return EulOrd(Z, EulParEven, EulRepYes, EulFrmR);
  }

  public static int EulOrdXYZr() {
    return EulOrd(Z, EulParOdd, EulRepNo, EulFrmR);
  }

  public static int EulOrdZYZr() {
    return EulOrd(Z, EulParOdd, EulRepYes, EulFrmR);
  }

  public static int EulFrm(int ord) {
    // DCS, was unsigned
    return ((ord1);
  }

  public static int EulRep(int ord) {
    // DCS, was unsigned
    return (((ord>> 11);
  }

  public static int EulPar(int ord) {
    return (((ord>> 21);
  }

  public static int EulAxI(int ord) {
    // DCS, was unsigned
    return ((int) (EulSafe((((ord>> 33))));
  }

  public static int EulAxJ(int ord) {
    int i = 0;

    if (EulPar(ord== EulParOdd)
      i = 1;

    return ((int) (EulNext(EulAxI(ord+ i)));
  }

  public static int EulAxK(int ord) {
    int i = 0;

    if (EulPar(ord!= EulParOdd)
      i = 1;

    return ((int) (EulNext(EulAxI(ord+ i)));
  }

  public static int EulAxH(int ord) {
    if (EulRep(ord== EulRepNo)
      return EulAxK(ord);

    return EulAxI(ord);
  }

  public static int EulOrd(int i, int p, int r, int f) {
    return (((((((i<< 1(p)) << 1(r)) << 1(f));
  }

  // enum
  static final int X = 0;

  static final int Y = 1;

  static final int Z = 2;

  static final int W = 3;

  static final int EulRepNo = 0;

  static final int EulRepYes = 1;

  static final int EulParEven = 0;

  static final int EulParOdd = 1;

  static final int EulFrmS = 0;

  static final int EulFrmR = 1;

  static final float FLT_EPSILON = 1.192092896e-07F;

  static EulGetOrdInfo EulGetOrd(int ord) {
    EulGetOrdInfo info = new EulGetOrdInfo();

    // note, used to be unsigned!
    int o = ord;
    info.f = o & 1;
    o >>= 1;
    info.s = o & 1;
    o >>= 1;
    info.n = o & 1;
    o >>= 1;
    info.i = EulSafe(o & 3);
    info.j = EulNext(info.i + info.n);
    info.k = EulNext(info.i + - info.n);

    if (info.s != 0)
      info.h = info.k;
    else
      info.h = info.i;

    return info;
  }

  static int EulSafe(int val) {
    int[] valArray = 012};
    return valArray[val];
  }

  static int EulNext(int val) {
    int[] valArray = 120};
    return valArray[val];
  }

  // float HMatrix[4][4];

  /* Convert matrix to Euler angles (in radians). */
  public static EulerAngles Eul_FromMatrix(float[][] M, int order) {
    EulerAngles ea = new EulerAngles();

    EulGetOrdInfo info = EulGetOrd(order);

    int i = info.i;
    int j = info.j;
    int k = info.k;
    int h = info.h;
    int n = info.n;
    int s = info.s;
    int f = info.f;

    if (s == EulRepYes) {
      double sy = Math.sqrt(M[i][j* M[i][j+ M[i][k* M[i][k]);
      if (sy > 16 * FLT_EPSILON) {
        ea.x = (floatMath.atan2(M[i][j], M[i][k]);
        ea.y = (floatMath.atan2(sy, M[i][i]);
        ea.z = (floatMath.atan2(M[j][i], -M[k][i]);
      else {
        ea.x = (floatMath.atan2(-M[j][k], M[j][j]);
        ea.y = (floatMath.atan2(sy, M[i][i]);
        ea.z = 0;
      }
    else {
      double cy = Math.sqrt(M[i][i* M[i][i+ M[j][i* M[j][i]);
      if (cy > 16 * FLT_EPSILON) {
        ea.x = (floatMath.atan2(M[k][j], M[k][k]);
        ea.y = (floatMath.atan2(-M[k][i], cy);
        ea.z = (floatMath.atan2(M[j][i], M[i][i]);
      else {
        ea.x = (floatMath.atan2(-M[j][k], M[j][j]);
        ea.y = (floatMath.atan2(-M[k][i], cy);
        ea.z = 0;
      }
    }
    if (n == EulParOdd) {
      ea.x = -ea.x;
      ea.y = -ea.y;
      ea.z = -ea.z;
    }
    if (f == EulFrmR) {
      float t = ea.x;
      ea.x = ea.z;
      ea.z = t;
    }
    ea.w = order;
    return (ea);
  }

  /* Convert quaternion to Euler angles (in radians). */
  public static EulerAngles Eul_FromQuat(Quat q, int order) {
    float[][] M = new float[4][4];
    double Nq = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;
    double s = (Nq >