package ch.ethz.karto.map3d; import com.jogamp.opengl.util.FPSAnimator; import java.awt.event.KeyEvent; import javax.media.opengl.GLAutoDrawable; /** * * @author Institute of Cartography, ETH Zurich. */ public class Map3DRotationAnimation implements Map3DAnimation { private FPSAnimator animator; private GLAutoDrawable glAutoDrawable; /** * Increment for the xAngle when animating */ protected float xDelta = 0.0f; /** * Increment for the zAngle when animating */ private float zDelta = 0.0f; /** * Increment for the viewDistance when animating */ private float dDelta = 0.0f; private int xLevel = 0; private int zLevel = 0; private int dLevel = 0; /** * Number of frames per second. */ protected static final int FPS = 50; /** * Duration of full rotation in seconds. */ private static final float ROTATION_DURATION = 4.0f; /** * Duration of full elevation change in seconds. */ private static final float ELEVATION_DURATION = 2.0f; /** * Duration of full elevation change in seconds. */ private static final float DISTANCE_DURATION = 2.0f; /** * Rotation steps. */ private static final int ROTATION_STEPS = 16; /** * Rotation steps. */ private static final int ELEVATION_STEPS = 8; /** * Distance steps. */ private static final int DISTANCE_STEPS = 8; /** * Rotation units [in degrees]. */ private static final float ROTATION_UNITS = 360.0f / (ROTATION_DURATION * FPS * ROTATION_STEPS * ROTATION_STEPS); /** * Elevation units [in degrees]. */ private static final float ELEVATION_UNITS = 90.0f / (ELEVATION_DURATION * FPS * ELEVATION_STEPS * ELEVATION_STEPS); /** * Distance units. */ private static final float DISTANCE_UNITS = (Map3DViewer.MAX_DISTANCE - Map3DViewer.MIN_DISTANCE) / (DISTANCE_DURATION * FPS * DISTANCE_STEPS * DISTANCE_STEPS); protected Map3DRotationAnimation(GLAutoDrawable glAutoDrawable) { this.glAutoDrawable = glAutoDrawable; } @Override public void update(Map3DViewer map3DViewer) { if (!isAnimating()) { return; } // this method is called from Map3DViewer.display(). Do not call methods // in Map3DView that again call display()! if (map3DViewer.xAngle + xDelta > Map3DViewer.MAX_X_ANGLE || map3DViewer.xAngle + xDelta < Map3DViewer.MIN_X_ANGLE) { xDelta = -xDelta; } map3DViewer.xAngle += xDelta; /*if (xAngle > MAX_X_ANGLE || xAngle < MIN_X_ANGLE) { xLevel = 0; xDelta = 0.0f; xAngle = Math.max(Math.min(xAngle, MAX_X_ANGLE), MIN_X_ANGLE); } if (xAngle > MAX_X_ANGLE || xAngle < MIN_X_ANGLE) { xLevel = 0; xDelta = 0.0f; xAngle = Math.max(Math.min(xAngle, MAX_X_ANGLE), MIN_X_ANGLE); }*/ map3DViewer.zAngle = Map3DViewer.normalizeZAngle(map3DViewer.zAngle - zDelta); map3DViewer.viewDistance += dDelta; if (map3DViewer.viewDistance > Map3DViewer.MAX_DISTANCE || map3DViewer.viewDistance < Map3DViewer.MIN_DISTANCE) { dLevel = 0; dDelta = 0.0f; map3DViewer.viewDistance = Math.max(Math.min(map3DViewer.viewDistance, Map3DViewer.MAX_DISTANCE), Map3DViewer.MIN_DISTANCE); } map3DViewer.getComponent().repaint(); map3DViewer.getComponent().firePropertyChange("view", 0, 1); } protected void changeRotation(int d) { if ((d < 0 && this.zLevel > 0) || (d > 0 && this.zLevel < 0)) { this.zLevel = 0; } else { this.zLevel = Math.min(Math.max(this.zLevel + d, -ROTATION_STEPS), ROTATION_STEPS); } this.zDelta = (this.zLevel * this.zLevel) * ROTATION_UNITS; this.zDelta = this.zLevel < 0 ? -this.zDelta : this.zDelta; } protected void increaseRightRotation() { changeRotation(1); } protected void increaseLeftRotation() { changeRotation(-1); } protected void changeElevation(int d) { if ((d < 0 && this.xLevel > 0) || (d > 0 && this.xLevel < 0)) { this.xLevel = 0; } else { this.xLevel = Math.min(Math.max(this.xLevel + d, -ELEVATION_STEPS), ELEVATION_STEPS); } this.xDelta = (this.xLevel * this.xLevel) * ELEVATION_UNITS; this.xDelta = this.xLevel < 0 ? -this.xDelta : this.xDelta; } protected void increaseElevation() { changeElevation(1); } protected void decreaseElevation() { changeElevation(-1); } protected void changeZoom(int d) { if ((d < 0 && this.dLevel > 0) || (d > 0 && this.dLevel < 0)) { this.dLevel = 0; } else { this.dLevel = Math.min(Math.max(this.dLevel + d, -DISTANCE_STEPS), DISTANCE_STEPS); } this.dDelta = (this.dLevel * this.dLevel) * DISTANCE_UNITS; this.dDelta = this.dLevel < 0 ? -this.dDelta : this.dDelta; } protected void zoomIn() { changeZoom(-1); } protected void zoomOut() { changeZoom(1); } /** * Starts the animation. */ @Override public void startAnimation() { if (this.animator == null) { this.animator = new FPSAnimator(glAutoDrawable, FPS); } if (!this.animator.isAnimating()) { this.animator.start(); } } /** * Stops the animation. */ @Override public void stopAnimation() { if (animator != null && this.animator.isAnimating()) { this.animator.stop(); } this.xLevel = 0; this.xDelta = 0.0f; this.zLevel = 0; this.zDelta = 0.0f; this.dLevel = 0; this.dDelta = 0.0f; glAutoDrawable.display(); } protected void toggleAnimation() { if (this.animator != null && this.animator.isAnimating()) { stopAnimation(); } else { startAnimation(); } } public boolean isAnimating(){ return animator != null && this.animator.isAnimating(); } /** * Treat plus and minus keys to zoom in and out. * Special treatment needed: * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4262044 * @param key */ @Override public void keyTyped(KeyEvent key) { switch (key.getKeyChar()) { case '+': this.startAnimation(); this.zoomIn(); break; case '-': this.startAnimation(); this.zoomOut(); break; default: break; } } @Override public void keyPressed(KeyEvent key) { switch (key.getKeyCode()) { case KeyEvent.VK_UP: this.startAnimation(); if (key.isShiftDown()) { this.zoomIn(); } else { this.increaseElevation(); } break; case KeyEvent.VK_DOWN: this.startAnimation(); if (key.isShiftDown()) { this.zoomOut(); } else { this.decreaseElevation(); } break; case KeyEvent.VK_RIGHT: this.startAnimation(); this.increaseRightRotation(); break; case KeyEvent.VK_LEFT: this.startAnimation(); this.increaseLeftRotation(); break; case KeyEvent.VK_SPACE: this.toggleAnimation(); break; case KeyEvent.VK_BACK_SPACE: case KeyEvent.VK_ESCAPE: case KeyEvent.VK_DELETE: //resetView(); break; default: break; } } @Override public void keyReleased(KeyEvent key) { } }