X-Git-Url: https://gitweb.fperrin.net/?p=GpsPrune.git;a=blobdiff_plain;f=src%2Ftim%2Fprune%2Fthreedee%2FUprightOrbiter.java;fp=src%2Ftim%2Fprune%2Fthreedee%2FUprightOrbiter.java;h=dd00ec7a8d82b37caa353bc2430aff0c584ffc67;hp=0000000000000000000000000000000000000000;hb=cd5dd0c207b676067e85e0885b90f05445b7e229;hpb=1db53356139320890a8d10e982865a1899e11b81 diff --git a/src/tim/prune/threedee/UprightOrbiter.java b/src/tim/prune/threedee/UprightOrbiter.java new file mode 100644 index 0000000..dd00ec7 --- /dev/null +++ b/src/tim/prune/threedee/UprightOrbiter.java @@ -0,0 +1,326 @@ +package tim.prune.threedee; + +import java.awt.event.InputEvent; + +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + * Copyright (c) 2021 ActivityWorkshop simplifications and renamings, + * and restriction to upright orientations. + */ + +import java.awt.event.MouseEvent; +import java.awt.AWTEvent; + +import javax.media.j3d.Transform3D; +import javax.media.j3d.Canvas3D; + +import javax.vecmath.Vector3d; +import javax.vecmath.Point3d; +import javax.vecmath.Matrix3d; + +import com.sun.j3d.utils.behaviors.vp.ViewPlatformAWTBehavior; +import com.sun.j3d.utils.universe.ViewingPlatform; + + +/** + * Moves the View around a point of interest when the mouse is dragged with + * a mouse button pressed. Includes rotation, zoom, and translation + * actions. Zooming can also be obtained by using mouse wheel. + *

+ * The rotate action rotates the ViewPlatform around the point of interest + * when the mouse is moved with the main mouse button pressed. The + * rotation is in the direction of the mouse movement, with a default + * rotation of 0.01 radians for each pixel of mouse movement. + *

+ * The zoom action moves the ViewPlatform closer to or further from the + * point of interest when the mouse is moved with the middle mouse button + * pressed (or Alt-main mouse button on systems without a middle mouse button). + * The default zoom action is to translate the ViewPlatform 0.01 units for each + * pixel of mouse movement. Moving the mouse up moves the ViewPlatform closer, + * moving the mouse down moves the ViewPlatform further away. + *

+ * The translate action translates the ViewPlatform when the mouse is moved + * with the right mouse button pressed. The translation is in the direction + * of the mouse movement, with a default translation of 0.01 units for each + * pixel of mouse movement. + *

+ * The actions can be reversed using the REVERSE_ACTION + * constructor flags. The default action moves the ViewPlatform around the + * objects in the scene. The REVERSE_ACTION flags can + * make the objects in the scene appear to be moving in the direction + * of the mouse movement. + */ +public class UprightOrbiter extends ViewPlatformAWTBehavior +{ + private Transform3D _longitudeTransform = 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 _deltaYaw = 0.0, _deltaPitch = 0.0; + private double _startDistanceFromCenter = 20.0; + private double _distanceFromCenter = 20.0; + private Point3d _rotationCenter = new Point3d(); + private Matrix3d _rotMatrix = new Matrix3d(); + + private int _mouseX = 0, _mouseY = 0; + + private double _xtrans = 0.0, _ytrans = 0.0, _ztrans = 0.0; + + private static final double MIN_RADIUS = 0.0; + + // the factor to be applied to wheel zooming so that it does not + // look much different with mouse movement zooming. + private static final float wheelZoomFactor = 50.0f; + + private static final double NOMINAL_ZOOM_FACTOR = .01; + private static final double NOMINAL_ROT_FACTOR = .008; + private static final double NOMINAL_TRANS_FACTOR = .003; + + private double _pitchAngle = 0.0; + + + /** + * Creates a new OrbitBehaviour + * @param inCanvas The Canvas3D to add the behaviour to + * @param inInitialPitch pitch angle in degrees + */ + public UprightOrbiter(Canvas3D inCanvas, double inInitialPitch) + { + super(inCanvas, MOUSE_LISTENER | MOUSE_MOTION_LISTENER | MOUSE_WHEEL_LISTENER ); + _pitchAngle = Math.toRadians(inInitialPitch); + } + + protected synchronized void processAWTEvents( final AWTEvent[] events ) + { + motion = false; + for(int i=0; i MIN_RADIUS) { + _distanceFromCenter -= ychange * NOMINAL_ZOOM_FACTOR; + } + else { + _distanceFromCenter = MIN_RADIUS; + } + } + + /** + * Sets the ViewingPlatform for this behaviour. This method is + * called by the ViewingPlatform. + * If a sub-calls overrides this method, it must call + * super.setViewingPlatform(vp). + * NOTE: Applications should not call this method. + */ + @Override + public void setViewingPlatform(ViewingPlatform vp) + { + super.setViewingPlatform( vp ); + + if (vp != null) { + resetView(); + integrateTransforms(); + } + } + + /** + * Reset the orientation and distance of this behaviour to the current + * values in the ViewPlatform Transform Group + */ + private void resetView() + { + Vector3d centerToView = new Vector3d(); + + 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 behaviour + Transform3D currentXfm = new Transform3D(); + targetTG.getTransform(currentXfm); + if (! targetTransform.equals(currentXfm)) + resetView(); + + // Three-step rotation process, firstly undo the pitch and apply the delta yaw + _latitudeTransform.rotX(_pitchAngle); + _rotateTransform.mul(_rotateTransform, _latitudeTransform); + _longitudeTransform.rotY( _deltaYaw ); + _rotateTransform.mul(_rotateTransform, _longitudeTransform); + // Now update pitch angle according to delta and apply + _pitchAngle = Math.min(Math.max(0.0, _pitchAngle - _deltaPitch), Math.PI/2.0); + _latitudeTransform.rotX(-_pitchAngle); + _rotateTransform.mul(_rotateTransform, _latitudeTransform); + + _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); + + Vector3d finalTranslation = new Vector3d(); + targetTransform.get(finalTranslation); + + targetTG.setTransform(targetTransform); + + // reset yaw and pitch deltas + _deltaYaw = 0.0; + _deltaPitch = 0.0; + } + + private boolean isRotateEvent(MouseEvent evt) + { + final boolean isRightDrag = (evt.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) > 0; + return !evt.isAltDown() && !isRightDrag; + } + + private boolean isZoomEvent(MouseEvent evt) + { + if (evt instanceof java.awt.event.MouseWheelEvent) { + return true; + } + return evt.isAltDown() && !evt.isMetaDown(); + } + + private boolean isTranslateEvent(MouseEvent evt) + { + final boolean isRightDrag = (evt.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) > 0; + return !evt.isAltDown() && isRightDrag; + } +}