View Javadoc

1   package nl.tudelft.goal.ut2004.visualizer.timeline.map;
2   
3   import java.awt.Point;
4   import java.awt.event.InputEvent;
5   import java.awt.event.MouseEvent;
6   import java.awt.event.MouseListener;
7   import java.awt.event.MouseMotionListener;
8   
9   import javax.swing.event.MouseInputAdapter;
10  
11  import nl.tudelft.goal.ut2004.visualizer.map.MapGLPanel;
12  
13  
14  import cz.cuni.amis.pogamut.base3d.worldview.object.Location;
15  
16  /**
17   * Class for controling viewport in map.
18   * <p>
19   * The view of map is specified in {@link MapViewpoint}, it consists from
20   * <ul>
21   *  <li>center point - the point in worldspace at which the eye is looking at</li>
22   *  <li>eye point - the worldspace point from which is player looking at the center point</li>
23   *  <li>up vector - determines which direction is up, in worldspace</li>
24   * </ul>
25   * These three components are always orthogonal (the angle between them is 90 degrees).
26   * <p>
27   * The user is controlling the view by dragging the mouse while pressing the buttons:
28   * <ul>
29   *  <li>Left button - deltaX will move your view angle to left or right,
30   *      deltaY will move you forward or backward (no change in height)</li>
31   *  <li>Right button - freely change the direction at which you are looking. </li>
32   *  <li>Left and right button - change position while maintaining the view vector.
33   *      deltaX - left or right, deltaY up or down.</li>
34   *  <li>Triple click anywhere will turn your view to the origin (0,0,0), where map usually is</li>
35   * </ul>
36   * X axis is green,
37   * Y axis is red
38   * Z axis is up/down (up direction is negative)
39   *
40   * @author Honza
41   */
42  public class MapController extends MouseInputAdapter implements MouseListener, MouseMotionListener {
43  
44      final private MapGLPanel panel;
45      final private MapViewpoint viewpoint;
46      private Point last;
47  
48      private Location center;
49  
50      /**
51       * Robot for keeping cursor at one place during dragging (otherwise drag is limited by screen space)
52       */
53      java.awt.Robot robot;
54  
55      public MapController(MapGLPanel panel, MapViewpoint mapViewpoint, Location center) {
56          this.panel = panel;
57          this.viewpoint = mapViewpoint;
58          this.center = new Location(center);
59      }
60  
61      public void registerListeners() {
62          panel.addMouseListener(this);
63          panel.addMouseMotionListener(this);
64          panel.addMouseWheelListener(this);
65      }
66  
67      public void unregisterListeners() {
68          panel.removeMouseListener(this);
69          panel.removeMouseMotionListener(this);
70          panel.removeMouseWheelListener(this);
71      }
72  
73      @Override
74      public void mouseClicked(MouseEvent e) {
75          if (e.getClickCount() == 3) {
76              viewpoint.lookAt(center, 2, false);
77          }
78      }
79  
80      
81  
82      @Override
83      public void mousePressed(MouseEvent e) {
84          updateMode(e);
85          last = e.getLocationOnScreen();
86      }
87  
88      @Override
89      public void mouseReleased(MouseEvent e) {
90          updateMode(e);
91          last = e.getLocationOnScreen();
92      }
93  
94      private ModificationStatus updateMode(MouseEvent e) {
95          boolean leftDown = (e.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) == InputEvent.BUTTON1_DOWN_MASK;
96          boolean rightDown = (e.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK;
97  
98          if (leftDown && rightDown) {
99              operationMode = ModificationStatus.MOVE_CENTER;
100         } else if (leftDown && !rightDown) {
101             operationMode = ModificationStatus.MOVE_AHEAD;
102         } else if (!leftDown && rightDown) {
103             operationMode = ModificationStatus.ROTATE_EYE;
104         } else {
105             operationMode = ModificationStatus.NONE;
106         }
107         System.out.println("ModificationMode: " + operationMode);
108         return operationMode;
109     }
110 
111     private void changeViewpoint(double deltaX, double deltaY) {
112         // how many pixels are necessary to move one degree
113         double pixelsPerDegree = 5;
114         // how many ut units is one pixel
115         double unitsPerPixel = 10;
116         switch (operationMode) {
117             case ROTATE_EYE:
118                 rotateEye((deltaX) / pixelsPerDegree, (deltaY) / pixelsPerDegree);
119                 break;
120             case MOVE_CENTER:
121                 moveCenter(deltaX * unitsPerPixel, (deltaY) * unitsPerPixel);
122                 break;
123             case MOVE_AHEAD:
124                 moveAhead(deltaY * unitsPerPixel, deltaX / pixelsPerDegree);
125                 break;
126         }
127     }
128 
129     private void moveAhead(double distance, double angle) {
130         Location forward = viewpoint.getEye2Center().getNormalized().scale(-distance);
131         forward = forward.setZ(0);
132         viewpoint.move(forward);
133         viewpoint.rotateCenter(new Location(0, 0, 1), angle);
134     }
135 
136     @Override
137     public void mouseDragged(MouseEvent e) {
138         Point current = e.getLocationOnScreen();
139 
140         int deltaX = current.x - last.x;
141         int deltaY = current.y - last.y;
142 
143         changeViewpoint(deltaX, deltaY);
144 
145         unregisterListeners();
146         //robot.mouseMove(last.x, last.y);
147         registerListeners();
148 
149         last = current;
150     }
151 
152     /**
153      * Rotate eye according to the delta move by mouse or other pointer.
154      * <p>
155      * @param leftRightAngle how many degrees should I turn to left or right
156      * @param upDownAngle how many degrees should I move my "viewangle" up or down
157      */
158     private void rotateEye(double leftRightAngle, double upDownAngle) {
159         // rotate up/down
160         viewpoint.rotateCenter(viewpoint.getRightVector(), upDownAngle);
161 
162         // rotate left/right
163         viewpoint.rotateCenter(new Location(0, 0, 1), leftRightAngle);
164     }
165 
166     private void moveCenter(double deltaX, double deltaY) {
167         // horizontal movement
168         Location right = viewpoint.getRightVector().getNormalized().scale(-deltaX);
169         viewpoint.move(right);
170 
171         // vertical movement
172         Location up = new Location(0, 0, deltaY);
173         System.out.println("MoveCenter up " + up);
174         viewpoint.move(up);
175     }
176 
177     private enum ModificationStatus {
178 
179         NONE,
180         /** look around, only 180 degrees */
181         ROTATE_EYE,
182         /** move center up/down and left/right     */
183         MOVE_CENTER,
184         /** move ahead and turn */
185         MOVE_AHEAD,
186     }
187     private ModificationStatus operationMode = ModificationStatus.NONE;
188 }