trackball.h 19.6 KB
Newer Older
schultezub's avatar
schultezub committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/**********************************************************************
 *                                                                    *
 * tgt - Tiny Graphics Toolbox                                        *
 *                                                                    *
 * Copyright (C) 2006-2011 Visualization and Computer Graphics Group, *
 * Department of Computer Science, University of Muenster, Germany.   *
 * <http://viscg.uni-muenster.de>                                     *
 *                                                                    *
 * This file is part of the tgt library. This library is free         *
 * software; you can redistribute it and/or modify it under the terms *
 * of the GNU Lesser General Public License version 2.1 as published  *
 * by the Free Software Foundation.                                   *
 *                                                                    *
 * This library 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 Lesser General Public License for more details.                *
 *                                                                    *
 * You should have received a copy of the GNU Lesser General Public   *
 * License in the file "LICENSE.txt" along with this library.         *
 * If not, see <http://www.gnu.org/licenses/>.                        *
 *                                                                    *
 **********************************************************************/

#ifndef TGT_TRACKBALL_H
#define TGT_TRACKBALL_H

#include <cmath>
#include <vector>

#include "tgt/matrix.h"
#include "tgt/quaternion.h"
#include "tgt/vector.h"
#include "tgt/types.h"
#include "tgt/navigation/navigation.h"
#include "tgt/timer.h"
#include "tgt/stopwatch.h"


namespace tgt {

/**
    This class implements a Trackball which can be used to freely rotate an object
    around a given center (or, if you will, to rotate the camera around and focus it
    on that center while it is continuously moving on a sphere).
*/
47
class TGT_API Trackball : public Navigation {
schultezub's avatar
schultezub committed
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
    public:

        /// Constructor
        ///
        /// Center of Trackball is set to camera focus of the given canvas.
        /// \param canvas The canvas the Trackball is associated with
        /// \param defaultEventHandling You can specify the mouse buttons and keys used to
        ///                             interact with trackball. If you want default behavior,
        ///                             set this to true and trackball should easyly work. If you
        ///                             want to specify different behavior than default, give false
        ///                             here. You will then have to call some setMouseFoo and
        ///                             setKeyBar methods to make the trackball work.
        /// \param continousSpinTimer To offer continous spin feature, trackball needs a
        ///                           tgt::Timer-object. As we need a toolkit-specific timer,
        ///                           trackball cannot create it itself, the user has to provide
        ///                           it to the constructor.
64
        Trackball(IHasCamera* hcam, const ivec2& viewportSize, bool defaultEventHandling = true, Timer* continousSpinTimer = NULL);
schultezub's avatar
schultezub committed
65
66
67
68

        /// Destructor
        virtual ~Trackball();

69
70
71
        const ivec2& getViewportSize() const { return viewportSize_; };
        void setViewprtSize(const ivec2& viewportSize) { viewportSize_ = viewportSize; };

schultezub's avatar
schultezub committed
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
        /// Resets the trackball to the initial configuration of the canvas' camera.
        void reset();

        /// Rotate the trackball according to Quaternion quat.
        /// @param quat Quaternion represention rotation.
        void rotate(Quaternion<float> quat);
        /// Rotate the trackball by angle phi around axis axis.
        /// @param axis axis in camera coordinates.
        virtual void rotate(vec3 axis, float phi);
        /// Rotate the trackball according to new mouse position.
        /// @param mouse coodinates of mouse, scaled to [-1, 1]x[-1, 1]
        void rotate(vec2 mouse);

        /// Move the trackball along axis.
        /// @param length Distance relative to frustum dimensions at trackball center.
        ///               Trackball center will get out of sight when >> 1.
        /// @param axis Axis in camera coordinates along which to move.
        virtual void move(float length, vec3 axis);
        /// Move the trackball according to new mouse position.
        /// @param mouse coodinates of mouse, scaled to [-1, 1]x[-1, 1]
        void move(vec2 mouse);

        /// Zoom in by factor factor.
        virtual void zoom(float factor);
        /// Zoom in according to new mouse position.
        /// @param mouse coodinates of mouse, scaled to [-1, 1]x[-1, 1]
        void zoom(vec2 mouse);
        /// set an absolute Distance from Focus
        void zoomAbsolute(float focallength);

        /// getter / setter

        /// whether this Trackball can be set to continious rotation by sweeping it
        void setContinuousSpin(bool b) { continuousSpin_ = b; }
        bool getContinuousSpin() const { return continuousSpin_; }

        /// last rotation applied to trackball
        quat getLastOrientationChange() const { return lastOrientationChange_; }

        /// If the center of the trackball should be moved relative to objects.
        /// This has large influence on trackball behavior. If you look at one object located at
        /// world coordinates origin, you might want the center not to move. This is used in voreen.
        /// If you use trackball to look at mutiple objects, located at varying position, you might
        /// want the center to move.
        /// See trackball demo in samples folder.
        void setMoveCenter(const bool& b = true) { moveCenter_ = b; };
        bool getMoveCenter() const { return moveCenter_; };

        /// Set trackballs center. Most people do not need this method. Use with caution!
        void setCenter(const vec3& center) { center_ = center; };
        const vec3& getCenter() const { return center_; };

        /// set the radius of the trackball to a given value
        void setSize(const float& size) { size_ = size; };
        float getSize() const { return size_; };

        /// Returns the orthogonal distance between camera position and center of the trackball
        /// with respect to the camera's look vector.
        float getCenterDistance();

132
133
//         GLCanvas* getCanvas() const { return hcav_; }
//         void setCanvas(GLCanvas* canvas) { hcav_ = canvas; }
schultezub's avatar
schultezub committed
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253

        Timer* getContinuousSpinTimer() const { return continuousSpinTimer_; }

// Event Handling /////////////////////////////////////////////////////////////////////////////

        /// let trackball react on mouse movements when button is pressed and modifiers are suitable
        /// to mod with rotating
        ///
        /// use MouseEvent::NO_MOUSE_BUTTON as button to disable mouse rotation
        void setMouseRotate(MouseEvent::MouseButtons button = MouseEvent::MOUSE_BUTTON_LEFT,
                            int mod = Event::MODIFIER_NONE);
        /// let trackball react on key pressures with rotating
        /// @param acuteness The per-keypress angle of rotation will be smaller at greater acuteness. Use acuteness = 0.f to disable key rotation.
        /// @param left, right, up, down keycode which should cause suitable rotation
        /// @param mod which modifiers must be set
        /// @param pressed rotate on key-pressed-event when true, on key-release-event when false
        void setKeyRotate(float acuteness = 10.f,
                          KeyEvent::KeyCode left  = KeyEvent::K_LEFT,
                          KeyEvent::KeyCode right = KeyEvent::K_RIGHT,
                          KeyEvent::KeyCode up    = KeyEvent::K_UP,
                          KeyEvent::KeyCode down  = KeyEvent::K_DOWN,
                          int mod = Event::MODIFIER_NONE,
                          bool pressed = false);
        /// let trackball react on mouse movements when button is pressed and modifiers are suitable
        /// to mod with moving
        ///
        /// use MouseEvent::NO_MOUSE_BUTTON as button to disable mouse movement
        void setMouseMove(MouseEvent::MouseButtons button = MouseEvent::MOUSE_BUTTON_LEFT,
                          int mod = Event::SHIFT);
        /// let trackball react on key presses with moving
        /// @param acuteness The per-keypress length of movement will be smaller at greater
        ///        acuteness. Use acuteness = 0.f to disable key rotation.
        /// @param left, right, up, down keycode which should cause suitable movement
        /// @param mod which modifiers must be set
        /// @param pressed move on key-pressed-event when true, on key-release-event when false
        void setKeyMove(float acuteness = 100.f,
                        KeyEvent::KeyCode left  = KeyEvent::K_LEFT,
                        KeyEvent::KeyCode right = KeyEvent::K_RIGHT,
                        KeyEvent::KeyCode up    = KeyEvent::K_UP,
                        KeyEvent::KeyCode down  = KeyEvent::K_DOWN,
                        int mod = Event::SHIFT,
                        bool pressed = false);

        /// let trackball react on mouse movements when button is pressed and modifiers are suitable
        /// to mod with zooming (changing the trackball's size)
        ///
        /// use MouseEvent::NO_MOUSE_BUTTON as button to disable mouse zooming
        ///
        /// @param zoomInDirection specifies in which direction mouse must be moved to zoom in.
        ///        The greater the length of this vector, the longer the way the mouse must be moved
        ///        to achieve a certain zoom factor.
        void setMouseZoom(MouseEvent::MouseButtons button = MouseEvent::MOUSE_BUTTON_LEFT,
                          vec2 zoomInDirection = vec2( 0.f, 1.f),
                          int mod = Event::CTRL);
        /// let trackball react on mouse wheel events when modifiers are suitable to mod with
        /// zooming (changing the trackball's size)
        /// @param acuteness The zoom factor will be smaller at greater acuteness. Use acuteness = 0.f to disable key rotation.
        /// @param wheelUpZoomIn zoom in on wheel up and out on wheel down when true, otherwise when
        ///        false
        void setMouseWheelZoom(float acuteness = 10.f, bool wheelUpZoomIn = true,
                               int mod = Event::MODIFIER_NONE);
        /// @param acuteness The zoom factor will be smaller at greater acuteness. Use acuteness = 0.f to disable key rotation.
        void setKeyZoom(float acuteness = 10.f,
                        KeyEvent::KeyCode in  = KeyEvent::K_UP,
                        KeyEvent::KeyCode out = KeyEvent::K_DOWN,
                        int mod = Event::CTRL,
                        bool pressed = false);

        /// let trackball react on mouse movements when button is pressed and modifiers are suitable
        /// to mod with rolling (tiling camera to left or right)
        ///
        /// use MouseEvent::NO_MOUSE_BUTTON as button to disable mouse rolling
        ///
        /// @param acuteness greater the acuteness means less tiling
        void setMouseRoll(MouseEvent::MouseButtons button = MouseEvent::MOUSE_BUTTON_LEFT,
                          float acuteness = .5f,
                          int mod = Event::CTRL);
        /// let trackball react on mouse wheel events when modifiers are suitable to mod with
        /// rolling  (tiling camera to left or right)
        /// @param acuteness Less tiling at greater acuteness. Use acuteness = 0.f to disable key rotation.
        /// @param wheelUpRollLeft roll left on wheel up and right on wheel down when true,
        ///                        otherwise when false
        void setMouseWheelRoll(float acuteness = 10.f, bool wheelUpRollLeft = true,
                               int mod = Event::SHIFT);
        /// @param acuteness Less tiling at greater acuteness. Use acuteness = 0.f to disable key rotation.
        void setKeyRoll(float acuteness = 10.f,
                        KeyEvent::KeyCode left = KeyEvent::K_LEFT,
                        KeyEvent::KeyCode right = KeyEvent::K_RIGHT,
                        int mod = Event::ALT,
                        bool pressed = false);

       MouseEvent::MouseButtons getRotateButton() const { return mouseRotateButton_; }
       MouseEvent::MouseButtons getZoomButton() const { return mouseZoomButton_; }
       MouseEvent::MouseButtons getMoveButton() const { return mouseMoveButton_; }
       MouseEvent::MouseButtons getRollButton() const { return mouseRollButton_; }

        /// implement EventListener functions
        virtual void mousePressEvent(MouseEvent* e);
        virtual void mouseReleaseEvent(MouseEvent* e);
        virtual void mouseMoveEvent(MouseEvent* e);
        virtual void wheelEvent(MouseEvent* e);
        virtual void keyEvent(KeyEvent* e);
        virtual void timerEvent(TimeEvent* e);

        /**
         * Set the initial values for the camera. This is required, whenever a
         * camera / trackball setup has been saved (e.g. to disk as XML-file)
         * and needs to be reloaded.
         */
        void reinitializeCamera(const vec3& position, const vec3& focus, const vec3& upVector) {
            cameraPosition_ = position;
            cameraFocus_ = focus;
            cameraUpVector_ = upVector;
            if (getCamera() != 0)
                reset();
        }

///////////////////////////////////////////////////////////////////////////////////////////////

    protected:
254
255
256
        
        /// viewport size for mouse coordinates translation
        ivec2 viewportSize_;
schultezub's avatar
schultezub committed
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380

        /// is this a continuously spinning Trackball?
        bool continuousSpin_;
        /// timer used to do continuous spinning
        Timer* continuousSpinTimer_;
        /// stopwatch to get the duration between mouse events
        Stopwatch* continuousSpinStopwatch_;
        /// msecs between the last two mouse motion events (the time the last orientation change took)
        clock_t continuousSpinLastOrientationChangeMSecs_;

        /// Old mouse coordinates to allow calculation of the relative change.
        /// Ought to be relative coordinates within range [-1, 1]x[-1, 1].
        vec2 mouse_;

        /// this holds the center around which the camera will be rotated
        vec3 center_;
        /// Wheather to change the center in move method.
        /// center_ will alway be (0,0,0) if false.
        bool moveCenter_;
        /// the trackball size effects the trackball sensitivity
        float size_;

        /// store the initial position, focus point and up vector of camera used to be able to
        /// reset camera to those values
        void saveCameraParameters();
        vec3 cameraPosition_;
        vec3 cameraFocus_;
        vec3 cameraUpVector_;

        /// last rotation applied to trackball
        quat lastOrientationChange_;

        /// Stores mouse coordinates to be able to track relative mouse motions.
        /// Should be called when mouse buttons get pressed.
        void startMouseDrag(MouseEvent* e);

        /// Should be called when mouse buttons get released.
        void endMouseDrag(MouseEvent* e);

        /// scale screen-coodinates of mouse to intervall [-1, 1]x[-1, 1]
        vec2 scaleMouse(const ivec2& sc) const;

        /// projection math
        vec3 projectToSphere(const vec2 xy) const;

        /// transform vectors given in camera coordinates to vectors in world coordinates
        vec3 coordTransform(vec3 const axis) const;

        /// prepare trackball for usage of continuous spin feature
        void initializeContinuousSpin();

// Event Handling /////////////////////////////////////////////////////////////////////////////
        /// used to store settings how to react on certain events
        MouseEvent::MouseButtons mouseRotateButton_ ; ///< at which mouse button to rotate
        int mouseRotateMod_                         ; ///< at which modifiers to rotate by mouse
        float keyRotateAcuteness_                   ; ///< acuteness of rotation steps of key presses
        KeyEvent::KeyCode keyRotateLeft_            ; ///< at which key code rotate left
        KeyEvent::KeyCode keyRotateRight_           ; ///< at which key code rotate right
        KeyEvent::KeyCode keyRotateUp_              ; ///< at which key code rotate up
        KeyEvent::KeyCode keyRotateDown_            ; ///< at which key code rotate down
        int keyRotateMod_                           ; ///< at which modifiers to rotate by keys
        bool keyRotatePressed_                      ; // FIXME: cannot remember. not in use anyway...
        MouseEvent::MouseButtons mouseMoveButton_   ;
        int mouseMoveMod_                           ;
        float keyMoveAcuteness_                     ;
        KeyEvent::KeyCode keyMoveLeft_              ;
        KeyEvent::KeyCode keyMoveRight_             ;
        KeyEvent::KeyCode keyMoveUp_                ;
        KeyEvent::KeyCode keyMoveDown_              ;
        int keyMoveMod_                             ;
        bool keyMovePressed_                        ; // FIXME: cannot remember, not in use
        MouseEvent::MouseButtons mouseZoomButton_   ;
        vec2 mouseZoomInDirection_                  ;
        int mouseZoomMod_                           ;
        bool mouseWheelZoom_                        ;
        float mouseWheelZoomAcuteness_              ;
        bool mouseWheelUpZoomIn_                    ;
        int mouseWheelZoomMod_                      ;
        float keyZoomAcuteness_                     ;
        KeyEvent::KeyCode keyZoomIn_                ;
        KeyEvent::KeyCode keyZoomOut_               ;
        int keyZoomMod_                             ;
        bool keyZoomPressed_                        ; // FIXME: cannot remember, not in use
        MouseEvent::MouseButtons mouseRollButton_   ;
        float mouseRollAcuteness_                   ;
        int mouseRollMod_                           ;
        bool mouseWheelRoll_                        ;
        float mouseWheelRollAcuteness_              ;
        bool mouseWheelUpRollLeft_                  ;
        int mouseWheelRollMod_                      ;
        float keyRollAcuteness_                     ;
        KeyEvent::KeyCode keyRollLeft_              ;
        KeyEvent::KeyCode keyRollRight_             ;
        int keyRollMod_                             ;
        bool keyRollPressed_                        ; // FIXME: cannot remember, not in use

        bool tracking_; ///< Are we tracking mouse move events? Only when we received a
                        ///< mousePressEvent before.


        void initializeEventHandling() {
            mouseRotateButton_ = mouseMoveButton_ = mouseZoomButton_ = mouseRollButton_
                = MouseEvent::MOUSE_BUTTON_NONE;
            keyRotateLeft_ = keyRotateRight_ = keyRotateUp_ = keyRotateDown_
                = keyMoveLeft_ = keyMoveRight_ = keyMoveUp_ = keyMoveDown_
                = keyZoomIn_ = keyZoomOut_
                = keyRollLeft_ = keyRollRight_
                = KeyEvent::K_LAST;
            mouseWheelZoom_ = mouseWheelRoll_ = false;
        }

        float getRotationAngle(const float& acuteness) const ;
        float getMovementLength(const float& acuteness) const ;
        float getZoomFactor(const float& acuteness, const bool& zoomIn) const ;
        float getRollAngle(const float& acuteness, const bool& left) const ;


///////////////////////////////////////////////////////////////////////////////////////////////

};

} // namespace tgt

#endif // TGT_TRACKBALL_H