package org.osm2world.viewer.control.navigation; import java.awt.Cursor; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; import java.util.HashSet; import java.util.Set; import javax.swing.Timer; import javax.swing.event.MouseInputListener; import org.osm2world.core.math.VectorXYZ; import org.osm2world.core.target.common.rendering.Camera; import org.osm2world.viewer.model.RenderOptions; import org.osm2world.viewer.view.ViewerFrame; public class DefaultNavigation extends MouseAdapter implements KeyListener, MouseInputListener { private final static double ANGLE_INCREMENT = Math.PI/200; private final static double MOVEMENT_INCREMENT = 2.0; private final RenderOptions renderOptions; private final ViewerFrame viewerFrame; private final Timer timer; public DefaultNavigation(ViewerFrame viewerFrame, RenderOptions renderOptions) { this.viewerFrame = viewerFrame; this.renderOptions = renderOptions; timer = new Timer(20, KEYBOARD_TASK); } private boolean translationDrag = false; private boolean rotationDrag = false; private boolean movementDrag = false; private Point previousMousePoint; private final Set<Integer> pressedKeys = new HashSet<Integer>(); @Override public void keyPressed(KeyEvent e) { synchronized (pressedKeys) { pressedKeys.add(e.getKeyCode()); timer.start(); } } @Override public void keyReleased(KeyEvent e) { synchronized (pressedKeys) { pressedKeys.remove(e.getKeyCode()); if (pressedKeys.isEmpty()) timer.stop(); } } @Override public void keyTyped(KeyEvent e) {} @Override public void mouseDragged(MouseEvent e) { Point currentMousePoint = e.getPoint(); float movementX = currentMousePoint.x - previousMousePoint.x; float movementY = currentMousePoint.y - previousMousePoint.y; Camera camera = renderOptions.camera; if (camera != null) { if (translationDrag) { camera.moveMapForward(movementY); camera.moveMapRight(movementX); } else if (rotationDrag) { /* view left/right */ camera.rotateY(movementX/100); /* view up/down */ camera.mapPitch(movementY/-100); } else if (movementDrag) { /* roll left/right */ camera.roll(movementX/100); /* move up/down */ camera.moveMapUp(movementY); } } previousMousePoint = currentMousePoint; } @Override public void mousePressed(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON1) { viewerFrame.setCursor(new Cursor(Cursor.MOVE_CURSOR)); translationDrag = true; } else if (e.getButton() == MouseEvent.BUTTON2) { viewerFrame.setCursor(new Cursor(Cursor.MOVE_CURSOR)); movementDrag = true; } else { viewerFrame.setCursor(new Cursor(Cursor.MOVE_CURSOR)); rotationDrag = true; } previousMousePoint = e.getPoint(); } @Override public void mouseReleased(MouseEvent e) { viewerFrame.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); translationDrag = false; rotationDrag = false; movementDrag = false; } @Override public void mouseWheelMoved(MouseWheelEvent e) { zoom(e.getWheelRotation() < 0, 1); } private void zoom(boolean zoomIn, double scale) { Camera c = renderOptions.camera; if (c != null) { VectorXYZ toLookAt = c.getLookAt().subtract(c.getPos()); VectorXYZ move = toLookAt.mult(scale * (zoomIn ? 0.2f : -0.25f)); VectorXYZ newPos = c.getPos().add(move); c.setPos(newPos); } } private final ActionListener KEYBOARD_TASK = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Camera c = renderOptions.camera; if (c != null) { synchronized (pressedKeys) { for (int key : pressedKeys) { switch (key) { case KeyEvent.VK_Q: c.roll(ANGLE_INCREMENT); break; case KeyEvent.VK_E: c.roll(-ANGLE_INCREMENT); break; case KeyEvent.VK_W: c.moveForward(MOVEMENT_INCREMENT); break; case KeyEvent.VK_S: c.moveForward(-MOVEMENT_INCREMENT); break; case KeyEvent.VK_A: c.moveRight(MOVEMENT_INCREMENT); break; case KeyEvent.VK_D: c.moveRight(-MOVEMENT_INCREMENT); break; case KeyEvent.VK_PAGE_UP: c.moveUp(MOVEMENT_INCREMENT); break; case KeyEvent.VK_PAGE_DOWN: c.moveUp(-MOVEMENT_INCREMENT); break; case KeyEvent.VK_UP: c.pitch(ANGLE_INCREMENT); break; case KeyEvent.VK_DOWN: c.pitch(-ANGLE_INCREMENT); break; case KeyEvent.VK_RIGHT: c.yaw(ANGLE_INCREMENT); break; case KeyEvent.VK_LEFT: c.yaw(-ANGLE_INCREMENT); break; case KeyEvent.VK_PLUS: case KeyEvent.VK_I: zoom(true, 0.5); break; case KeyEvent.VK_MINUS: case KeyEvent.VK_O: zoom(false, 0.5); break; } } } } } }; }