/* * Simbad - Robot Simulator * Copyright (C) 2004 Louis Hugues * * 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; either version 2 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ----------------------------------------------------------------------------- * $Author: sioulseuguh $ * $Date: 2005/02/05 11:00:26 $ * $Revision: 1.1 $ * $Source: /cvsroot/simbad/src/simbad/sim/MouseOrbiter.java,v $ */package simbad.sim; import java.awt.event.MouseEvent; import javax.swing.event.MouseInputListener; import javax.media.j3d.TransformGroup; import javax.media.j3d.Transform3D; import javax.vecmath.Vector3d; import javax.vecmath.Point3d; import javax.vecmath.Matrix3d; /** Manages changes of the view point view under the control of mouse movement. * The mouse enables to modify lattitude and longitude of the viewpoint. * This class is largely inspired from Sun's OrbitBehavior. * It is intented to be used only with the main Canvas3d object (see World class). * */ public class MouseOrbiter implements MouseInputListener { private Transform3D longditudeTransform = new Transform3D(); private Transform3D latitudeTransform = new Transform3D(); private Transform3D rotateTransform = new Transform3D(); // needed for integrateTransforms but don't want to new every time private Transform3D temp1 = new Transform3D(); private Transform3D temp2 = new Transform3D(); private Transform3D translation = new Transform3D(); private Vector3d transVector = new Vector3d(); private Vector3d distanceVector = new Vector3d(); private Vector3d centerVector = new Vector3d(); private Vector3d invertCenterVector = new Vector3d(); private double longditude = 0.0; private double latitude = 0.0; private double rollAngle = 0.0; private double startDistanceFromCenter = 20.0; private double distanceFromCenter = 20.0; private final double MAX_MOUSE_ANGLE = Math.toRadians(3); private final double ZOOM_FACTOR = 1.0; private Point3d rotationCenter = new Point3d(); private Matrix3d rotMatrix = new Matrix3d(); private Transform3D currentXfm = new Transform3D(); private int mouseX = 0; private int mouseY = 0; private double rotXFactor = 1; private double rotYFactor = 1; private double transXFactor = 1; private double transYFactor = 1; private double zoomFactor = 1.0; private double xtrans = 0.0; private double ytrans = 0.0; private double ztrans = 0.0; private boolean zoomEnabled = true; private boolean rotateEnabled = true; private boolean translateEnabled = true; private boolean reverseRotate = true; private boolean reverseTrans = true; private boolean reverseZoom = true; private double minRadius = 0.0; private static final double NOMINAL_ZOOM_FACTOR = .01; private static final double NOMINAL_PZOOM_FACTOR = 1.0; private static final double NOMINAL_ROT_FACTOR = .01; private static final double NOMINAL_TRANS_FACTOR = .01; private double rotXMul = NOMINAL_ROT_FACTOR * rotXFactor; private double rotYMul = NOMINAL_ROT_FACTOR * rotYFactor; private double transXMul = NOMINAL_TRANS_FACTOR * transXFactor; private double transYMul = NOMINAL_TRANS_FACTOR * transYFactor; private double zoomMul = NOMINAL_ZOOM_FACTOR * zoomFactor; private boolean motion = false; TransformGroup targetTG; Transform3D targetTransform; /** * Creates a new OrbitBehavior * * @param c * The Canvas3D to add the behavior to * @param targetTransformGroup * The transformgroup affected by mouse movement */ public MouseOrbiter(javax.media.j3d.Canvas3D c, TransformGroup targetTransformGroup) { c.addMouseListener(this); c.addMouseMotionListener(this); this.targetTG = targetTransformGroup; targetTransform = new Transform3D(); resetView(); integrateTransforms(); } protected void processMouseEvent(final MouseEvent evt) { if (evt.getID() == MouseEvent.MOUSE_PRESSED) { mouseX = evt.getX(); mouseY = evt.getY(); motion = true; } else if (evt.getID() == MouseEvent.MOUSE_DRAGGED) { int xchange = evt.getX() - mouseX; int ychange = evt.getY() - mouseY; // rotate if (!evt.isAltDown() && !evt.isMetaDown()) { if (reverseRotate) { longditude -= xchange * rotXMul; latitude -= ychange * rotYMul; } else { longditude += xchange * rotXMul; latitude += ychange * rotYMul; } } // translate else if (!evt.isAltDown() && evt.isMetaDown()) { if (reverseTrans) { xtrans -= xchange * transXMul; ytrans += ychange * transYMul; } else { xtrans += xchange * transXMul; ytrans -= ychange * transYMul; } } // zoom else if (evt.isAltDown() && !evt.isMetaDown()) { if (reverseZoom) { distanceFromCenter -= ychange * zoomMul; } else { distanceFromCenter += ychange * zoomMul; } } mouseX = evt.getX(); mouseY = evt.getY(); motion = true; } integrateTransforms(); } /** * Reset the orientation and distance of this behavior to the current values * in target Transform Group */ public void resetView() { //Vector3d centerToView = new Vector3d(); Vector3d centerToView = new Vector3d(0,0,0); targetTG.getTransform(targetTransform); targetTransform.get(rotMatrix, transVector); centerToView.sub(transVector, rotationCenter); distanceFromCenter = centerToView.length(); startDistanceFromCenter = distanceFromCenter; targetTransform.get(rotMatrix); rotateTransform.set(rotMatrix); // compute the initial x/y/z offset temp1.set(centerToView); rotateTransform.invert(); rotateTransform.mul(temp1); rotateTransform.get(centerToView); xtrans = centerToView.x; ytrans = centerToView.y; ztrans = centerToView.z; // reset rotMatrix rotateTransform.set(rotMatrix); } protected synchronized void integrateTransforms() { // Check if the transform has been changed by another // behavior targetTG.getTransform(currentXfm); if (!targetTransform.equals(currentXfm)) resetView(); longditudeTransform.rotY(longditude); latitudeTransform.rotX(latitude); rotateTransform.mul(rotateTransform, latitudeTransform); rotateTransform.mul(rotateTransform, longditudeTransform); distanceVector.z = distanceFromCenter - startDistanceFromCenter; temp1.set(distanceVector); temp1.mul(rotateTransform, temp1); // want to look at rotationCenter transVector.x = rotationCenter.x + xtrans; transVector.y = rotationCenter.y + ytrans; transVector.z = rotationCenter.z + ztrans; translation.set(transVector); targetTransform.mul(temp1, translation); // handle rotationCenter temp1.set(centerVector); temp1.mul(targetTransform); invertCenterVector.x = -centerVector.x; invertCenterVector.y = -centerVector.y; invertCenterVector.z = -centerVector.z; temp2.set(invertCenterVector); targetTransform.mul(temp1, temp2); targetTG.setTransform(targetTransform); // reset yaw and pitch angles longditude = 0.0; latitude = 0.0; } /** * Sets the center around which the View rotates. The default is (0,0,0). * * @param center * The Point3d to set the center of rotation to */ public synchronized void setRotationCenter(Point3d center) { rotationCenter.x = center.x; rotationCenter.y = center.y; rotationCenter.z = center.z; centerVector.set(rotationCenter); } public void mouseClicked(MouseEvent arg0) {} public void mousePressed(MouseEvent event) { processMouseEvent(event); } public void mouseReleased(MouseEvent event) { processMouseEvent(event); } public void mouseEntered(MouseEvent arg0) {} public void mouseExited(MouseEvent arg0) {} public void mouseDragged(MouseEvent event) { processMouseEvent(event); } public void mouseMoved(MouseEvent event) { processMouseEvent(event); } }