HOG2
Trackball.cpp
Go to the documentation of this file.
1 /*
2  * $Id: trackball.cpp
3  * hog2
4  *
5  * Created by daves on 2000 05/03/00.
6  * Modified by ggs 12/06/02.
7  * Modified by Nathan Sturtevant on 02/29/20.
8 
9  Copyright: Copyright © 2003 Apple Computer, Inc., All Rights Reserved
10 
11  Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
12  ("Apple") in consideration of your agreement to the following terms, and your
13  use, installation, modification or redistribution of this Apple software
14  constitutes acceptance of these terms. If you do not agree with these terms,
15  please do not use, install, modify or redistribute this Apple software.
16 
17  In consideration of your agreement to abide by the following terms, and subject
18  to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
19  copyrights in this original Apple software (the "Apple Software"), to use,
20  reproduce, modify and redistribute the Apple Software, with or without
21  modifications, in source and/or binary forms; provided that if you redistribute
22  the Apple Software in its entirety and without modifications, you must retain
23  this notice and the following text and disclaimers in all such redistributions of
24  the Apple Software. Neither the name, trademarks, service marks or logos of
25  Apple Computer, Inc. may be used to endorse or promote products derived from the
26  Apple Software without specific prior written permission from Apple. Except as
27  expressly stated in this notice, no other rights or licenses, express or implied,
28  are granted by Apple herein, including but not limited to any patent rights that
29  may be infringed by your derivative works or by other works in which the Apple
30  Software may be incorporated.
31 
32  The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
33  WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
34  WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
35  PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
36  COMBINATION WITH YOUR PRODUCTS.
37 
38  IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
39  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
40  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41  ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
42  OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
43  (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
44  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45  *
46  */
47 
48 #include "Trackball.h"
49 
50 #include <math.h>
51 
52 static const float kTol = 0.001;
53 static const float kRad2Deg = 180. / 3.1415927;
54 static const float kDeg2Rad = 3.1415927 / 180.;
55 
58 float gEndPtTrackball[3];
60 
61 // mouse positon and view size as inputs
62 void startTrackball (long x, long y, long originX, long originY, long width, long height)
63 {
64  float xxyy;
65  float nx, ny;
66 
67  /* Start up the trackball. The trackball works by pretending that a ball
68  encloses the 3D view. You roll this pretend ball with the mouse. For
69  example, if you click on the center of the ball and move the mouse straight
70  to the right, you roll the ball around its Y-axis. This produces a Y-axis
71  rotation. You can click on the "edge" of the ball and roll it around
72  in a circle to get a Z-axis rotation.
73 
74  The math behind the trackball is simple: start with a vector from the first
75  mouse-click on the ball to the center of the 3D view. At the same time, set the radius
76  of the ball to be the smaller dimension of the 3D view. As you drag the mouse
77  around in the 3D view, a second vector is computed from the surface of the ball
78  to the center. The axis of rotation is the cross product of these two vectors,
79  and the angle of rotation is the angle between the two vectors.
80  */
81  nx = width;
82  ny = height;
83  if (nx > ny)
84  gRadiusTrackball = ny * 0.5;
85  else
86  gRadiusTrackball = nx * 0.5;
87  // Figure the center of the view.
88  gXCenterTrackball = (long)(originX + width * 0.5);
89  gYCenterTrackball = (long)(originY + height * 0.5);
90 
91  // Compute the starting vector from the surface of the ball to its center.
95  if (xxyy > gRadiusTrackball * gRadiusTrackball) {
96  // Outside the sphere.
97  gStartPtTrackball[2] = 0.;
98  } else
100 
101 }
102 
103 // update to new mouse position, output rotation angle
104 void rollToTrackball (long x, long y, float rot [4]) // rot is output rotation angle
105 {
106  float xxyy;
107  float cosAng, sinAng;
108  float ls, le, lr;
109 
112  if (fabs (gEndPtTrackball [0] - gStartPtTrackball [0]) < kTol && fabs (gEndPtTrackball [1] - gStartPtTrackball [1]) < kTol)
113  return; // Not enough change in the vectors to have an action.
114 
115  // Compute the ending vector from the surface of the ball to its center.
116  xxyy = gEndPtTrackball [0] * gEndPtTrackball [0] + gEndPtTrackball [1] * gEndPtTrackball [1];
117  if (xxyy > gRadiusTrackball * gRadiusTrackball) {
118  // Outside the sphere.
119  gEndPtTrackball [2] = 0.;
120  } else
121  gEndPtTrackball[ 2] = sqrt (gRadiusTrackball * gRadiusTrackball - xxyy);
122 
123  // Take the cross product of the two vectors. r = s X e
127 
128  // Use atan for a better angle. If you use only cos or sin, you only get
129  // half the possible angles, and you can end up with rotations that flip around near
130  // the poles.
131 
132  // cos(a) = (s . e) / (||s|| ||e||)
135  ls = 1. / ls; // 1 / ||s||
137  le = 1. / le; // 1 / ||e||
138  cosAng = cosAng * ls * le;
139 
140  // sin(a) = ||(s X e)|| / (||s|| ||e||)
141  sinAng = lr = sqrt(rot[1] * rot[1] + rot[2] * rot[2] + rot[3] * rot[3]); // ||(s X e)||;
142  // keep this length in lr for normalizing the rotation vector later.
143  sinAng = sinAng * ls * le;
144  rot[0] = (float) atan2 (sinAng, cosAng) * kRad2Deg; // GL rotations are in degrees.
145 
146  // Normalize the rotation axis.
147  lr = 1. / lr;
148  rot[1] *= -lr; rot[2] *= -lr; rot[3] *= lr;
149 
150  // returns rotate
151 }
152 
153 static void rotation2Quat (float *A, float *q)
154 {
155  float ang2; // The half-angle
156  float sinAng2; // sin(half-angle)
157 
158  // Convert a GL-style rotation to a quaternion. The GL rotation looks like this:
159  // {angle, x, y, z}, the corresponding quaternion looks like this:
160  // {{v}, cos(angle/2)}, where {v} is {x, y, z} / sin(angle/2).
161 
162  ang2 = A[0] * kDeg2Rad * 0.5; // Convert from degrees ot radians, get the half-angle.
163  sinAng2 = sin(ang2);
164  q[0] = A[1] * sinAng2; q[1] = A[2] * sinAng2; q[2] = A[3] * sinAng2;
165  q[3] = cos(ang2);
166 }
167 
168 void addToRotationTrackball (float * dA, float * A)
169 {
170  float q0[4], q1[4], q2[4];
171  float theta2, sinTheta2;
172 
173  // Figure out A' = A . dA
174  // In quaternions: let q0 <- A, and q1 <- dA.
175  // Figure out q2 = q1 + q0 (note the order reversal!).
176  // A' <- q3.
177 
178  rotation2Quat(A, q0);
179  rotation2Quat(dA, q1);
180 
181  // q2 = q1 + q0;
182  q2[0] = q1[1]*q0[2] - q1[2]*q0[1] + q1[3]*q0[0] + q1[0]*q0[3];
183  q2[1] = q1[2]*q0[0] - q1[0]*q0[2] + q1[3]*q0[1] + q1[1]*q0[3];
184  q2[2] = q1[0]*q0[1] - q1[1]*q0[0] + q1[3]*q0[2] + q1[2]*q0[3];
185  q2[3] = q1[3]*q0[3] - q1[0]*q0[0] - q1[1]*q0[1] - q1[2]*q0[2];
186  // Here's an excersize for the reader: it's a good idea to re-normalize your quaternions
187  // every so often. Experiment with different frequencies.
188 
189  // An identity rotation is expressed as rotation by 0 about any axis.
190  // The "angle" term in a quaternion is really the cosine of the half-angle.
191  // So, if the cosine of the half-angle is one (or, 1.0 within our tolerance),
192  // then you have an identity rotation.
193  if (fabs(fabs(q2[3] - 1.)) < 1.0e-7) {
194  // Identity rotation.
195  A[0] = 0.0f;
196  A[1] = 1.0f;
197  A[2] = A[3] = 0.0f;
198  return;
199  }
200 
201  // If you get here, then you have a non-identity rotation. In non-identity rotations,
202  // the cosine of the half-angle is non-0, which means the sine of the angle is also
203  // non-0. So we can safely divide by sin(theta2).
204 
205  // Turn the quaternion back into an {angle, {axis}} rotation.
206  theta2 = (float) acos (q2[3]);
207  sinTheta2 = (float) (1.0 / sin ((double) theta2));
208  A[0] = theta2 * 2.0f * kRad2Deg;
209  A[1] = q2[0] * sinTheta2;
210  A[2] = q2[1] * sinTheta2;
211  A[3] = q2[2] * sinTheta2;
212 }
rotation2Quat
static void rotation2Quat(float *A, float *q)
Definition: Trackball.cpp:153
addToRotationTrackball
void addToRotationTrackball(float *dA, float *A)
Definition: Trackball.cpp:168
gYCenterTrackball
long gYCenterTrackball
Definition: Trackball.cpp:59
startTrackball
void startTrackball(long x, long y, long originX, long originY, long width, long height)
Definition: Trackball.cpp:62
width
int width
Definition: SFML_HOG.cpp:54
gXCenterTrackball
long gXCenterTrackball
Definition: Trackball.cpp:59
rollToTrackball
void rollToTrackball(long x, long y, float rot[4])
Definition: Trackball.cpp:104
kRad2Deg
static const float kRad2Deg
Definition: Trackball.cpp:53
gEndPtTrackball
float gEndPtTrackball[3]
Definition: Trackball.cpp:58
gRadiusTrackball
float gRadiusTrackball
Definition: Trackball.cpp:56
Trackball.h
height
int height
Definition: SFML_HOG.cpp:54
gStartPtTrackball
float gStartPtTrackball[3]
Definition: Trackball.cpp:57
kDeg2Rad
static const float kDeg2Rad
Definition: Trackball.cpp:54
kTol
static const float kTol
Definition: Trackball.cpp:52