Update the changelog
[opencv] / apps / StereoGR / trackball.c
1 /*\r
2  * (c) Copyright 1993, 1994, Silicon Graphics, Inc.\r
3  * ALL RIGHTS RESERVED\r
4  * Permission to use, copy, modify, and distribute this software for\r
5  * any purpose and without fee is hereby granted, provided that the above\r
6  * copyright notice appear in all copies and that both the copyright notice\r
7  * and this permission notice appear in supporting documentation, and that\r
8  * the name of Silicon Graphics, Inc. not be used in advertising\r
9  * or publicity pertaining to distribution of the software without specific,\r
10  * written prior permission.\r
11  *\r
12  * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"\r
13  * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,\r
14  * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR\r
15  * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON\r
16  * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,\r
17  * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY\r
18  * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,\r
19  * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF\r
20  * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN\r
21  * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON\r
22  * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE\r
23  * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.\r
24  *\r
25  * US Government Users Restricted Rights\r
26  * Use, duplication, or disclosure by the Government is subject to\r
27  * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph\r
28  * (c)(1)(ii) of the Rights in Technical Data and Computer Software\r
29  * clause at DFARS 252.227-7013 and/or in similar or successor\r
30  * clauses in the FAR or the DOD or NASA FAR Supplement.\r
31  * Unpublished-- rights reserved under the copyright laws of the\r
32  * United States.  Contractor/manufacturer is Silicon Graphics,\r
33  * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.\r
34  *\r
35  * OpenGL(TM) is a trademark of Silicon Graphics, Inc.\r
36  */\r
37 /*\r
38  * Trackball code:\r
39  *\r
40  * Implementation of a virtual trackball.\r
41  * Implemented by Gavin Bell, lots of ideas from Thant Tessman and\r
42  *   the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129.\r
43  *\r
44  * Vector manip code:\r
45  *\r
46  * Original code from:\r
47  * David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli\r
48  *\r
49  * Much mucking with by:\r
50  * Gavin Bell\r
51  */\r
52 #if defined(WIN32)\r
53 #pragma warning (disable:4244)          /* disable bogus conversion warnings */\r
54 #endif\r
55 #include <math.h>\r
56 #include "trackball.h"\r
57 \r
58 /*\r
59  * This size should really be based on the distance from the center of\r
60  * rotation to the point on the object underneath the mouse.  That\r
61  * point would then track the mouse as closely as possible.  This is a\r
62  * simple example, though, so that is left as an Exercise for the\r
63  * Programmer.\r
64  */\r
65 #define TRACKBALLSIZE  (0.8)\r
66 \r
67 /*\r
68  * Local function prototypes (not defined in trackball.h)\r
69  */\r
70 static float tb_project_to_sphere(float, float, float);\r
71 static void normalize_quat(float [4]);\r
72 \r
73 void\r
74 vzero(float *v)\r
75 {\r
76     v[0] = 0.0;\r
77     v[1] = 0.0;\r
78     v[2] = 0.0;\r
79 }\r
80 \r
81 void\r
82 vset(float *v, float x, float y, float z)\r
83 {\r
84     v[0] = x;\r
85     v[1] = y;\r
86     v[2] = z;\r
87 }\r
88 \r
89 void\r
90 vsub(const float *src1, const float *src2, float *dst)\r
91 {\r
92     dst[0] = src1[0] - src2[0];\r
93     dst[1] = src1[1] - src2[1];\r
94     dst[2] = src1[2] - src2[2];\r
95 }\r
96 \r
97 void\r
98 vcopy(const float *v1, float *v2)\r
99 {\r
100     register int i;\r
101     for (i = 0 ; i < 3 ; i++)\r
102         v2[i] = v1[i];\r
103 }\r
104 \r
105 void\r
106 vcross(const float *v1, const float *v2, float *cross)\r
107 {\r
108     float temp[3];\r
109 \r
110     temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);\r
111     temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);\r
112     temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);\r
113     vcopy(temp, cross);\r
114 }\r
115 \r
116 float\r
117 vlength(const float *v)\r
118 {\r
119     return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);\r
120 }\r
121 \r
122 void\r
123 vscale(float *v, float div)\r
124 {\r
125     v[0] *= div;\r
126     v[1] *= div;\r
127     v[2] *= div;\r
128 }\r
129 \r
130 void\r
131 vnormal(float *v)\r
132 {\r
133     vscale(v,1.0/vlength(v));\r
134 }\r
135 \r
136 float\r
137 vdot(const float *v1, const float *v2)\r
138 {\r
139     return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];\r
140 }\r
141 \r
142 void\r
143 vadd(const float *src1, const float *src2, float *dst)\r
144 {\r
145     dst[0] = src1[0] + src2[0];\r
146     dst[1] = src1[1] + src2[1];\r
147     dst[2] = src1[2] + src2[2];\r
148 }\r
149 \r
150 /*\r
151  * Ok, simulate a track-ball.  Project the points onto the virtual\r
152  * trackball, then figure out the axis of rotation, which is the cross\r
153  * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)\r
154  * Note:  This is a deformed trackball-- is a trackball in the center,\r
155  * but is deformed into a hyperbolic sheet of rotation away from the\r
156  * center.  This particular function was chosen after trying out\r
157  * several variations.\r
158  *\r
159  * It is assumed that the arguments to this routine are in the range\r
160  * (-1.0 ... 1.0)\r
161  */\r
162 void\r
163 trackball(float q[4], float p1x, float p1y, float p2x, float p2y)\r
164 {\r
165     float a[3]; /* Axis of rotation */\r
166     float phi;  /* how much to rotate about axis */\r
167     float p1[3], p2[3], d[3];\r
168     float t;\r
169 \r
170     if (p1x == p2x && p1y == p2y) {\r
171         /* Zero rotation */\r
172         vzero(q);\r
173         q[3] = 1.0;\r
174         return;\r
175     }\r
176 \r
177     /*\r
178      * First, figure out z-coordinates for projection of P1 and P2 to\r
179      * deformed sphere\r
180      */\r
181     vset(p1,p1x,p1y,tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y));\r
182     vset(p2,p2x,p2y,tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y));\r
183 \r
184     /*\r
185      *  Now, we want the cross product of P1 and P2\r
186      */\r
187     vcross(p2,p1,a);\r
188 \r
189     /*\r
190      *  Figure out how much to rotate around that axis.\r
191      */\r
192     vsub(p1,p2,d);\r
193     t = vlength(d) / (2.0*TRACKBALLSIZE);\r
194 \r
195     /*\r
196      * Avoid problems with out-of-control values...\r
197      */\r
198     if (t > 1.0) t = 1.0;\r
199     if (t < -1.0) t = -1.0;\r
200     phi = 2.0 * asin(t);\r
201 \r
202     axis_to_quat(a,phi,q);\r
203 }\r
204 \r
205 /*\r
206  *  Given an axis and angle, compute quaternion.\r
207  */\r
208 void\r
209 axis_to_quat(float a[3], float phi, float q[4])\r
210 {\r
211     vnormal(a);\r
212     vcopy(a,q);\r
213     vscale(q,sin(phi/2.0));\r
214     q[3] = cos(phi/2.0);\r
215 }\r
216 \r
217 /*\r
218  * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet\r
219  * if we are away from the center of the sphere.\r
220  */\r
221 static float\r
222 tb_project_to_sphere(float r, float x, float y)\r
223 {\r
224     float d, t, z;\r
225 \r
226     d = sqrt(x*x + y*y);\r
227     if (d < r * 0.70710678118654752440) {    /* Inside sphere */\r
228         z = sqrt(r*r - d*d);\r
229     } else {           /* On hyperbola */\r
230         t = r / 1.41421356237309504880;\r
231         z = t*t / d;\r
232     }\r
233     return z;\r
234 }\r
235 \r
236 /*\r
237  * Given two rotations, e1 and e2, expressed as quaternion rotations,\r
238  * figure out the equivalent single rotation and stuff it into dest.\r
239  *\r
240  * This routine also normalizes the result every RENORMCOUNT times it is\r
241  * called, to keep error from creeping in.\r
242  *\r
243  * NOTE: This routine is written so that q1 or q2 may be the same\r
244  * as dest (or each other).\r
245  */\r
246 \r
247 #define RENORMCOUNT 97\r
248 \r
249 void\r
250 add_quats(float q1[4], float q2[4], float dest[4])\r
251 {\r
252     static int count=0;\r
253     float t1[4], t2[4], t3[4];\r
254     float tf[4];\r
255 \r
256     vcopy(q1,t1);\r
257     vscale(t1,q2[3]);\r
258 \r
259     vcopy(q2,t2);\r
260     vscale(t2,q1[3]);\r
261 \r
262     vcross(q2,q1,t3);\r
263     vadd(t1,t2,tf);\r
264     vadd(t3,tf,tf);\r
265     tf[3] = q1[3] * q2[3] - vdot(q1,q2);\r
266 \r
267     dest[0] = tf[0];\r
268     dest[1] = tf[1];\r
269     dest[2] = tf[2];\r
270     dest[3] = tf[3];\r
271 \r
272     if (++count > RENORMCOUNT) {\r
273         count = 0;\r
274         normalize_quat(dest);\r
275     }\r
276 }\r
277 \r
278 /*\r
279  * Quaternions always obey:  a^2 + b^2 + c^2 + d^2 = 1.0\r
280  * If they don't add up to 1.0, dividing by their magnitued will\r
281  * renormalize them.\r
282  *\r
283  * Note: See the following for more information on quaternions:\r
284  *\r
285  * - Shoemake, K., Animating rotation with quaternion curves, Computer\r
286  *   Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985.\r
287  * - Pletinckx, D., Quaternion calculus as a basic tool in computer\r
288  *   graphics, The Visual Computer 5, 2-13, 1989.\r
289  */\r
290 static void\r
291 normalize_quat(float q[4])\r
292 {\r
293     int i;\r
294     float mag;\r
295 \r
296     mag = (q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);\r
297     for (i = 0; i < 4; i++) q[i] /= mag;\r
298 }\r
299 \r
300 /*\r
301  * Build a rotation matrix, given a quaternion rotation.\r
302  *\r
303  */\r
304 void\r
305 build_rotmatrix(float m[4][4], float q[4])\r
306 {\r
307     m[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]);\r
308     m[0][1] = 2.0 * (q[0] * q[1] - q[2] * q[3]);\r
309     m[0][2] = 2.0 * (q[2] * q[0] + q[1] * q[3]);\r
310     m[0][3] = 0.0;\r
311 \r
312     m[1][0] = 2.0 * (q[0] * q[1] + q[2] * q[3]);\r
313     m[1][1]= 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]);\r
314     m[1][2] = 2.0 * (q[1] * q[2] - q[0] * q[3]);\r
315     m[1][3] = 0.0;\r
316 \r
317     m[2][0] = 2.0 * (q[2] * q[0] - q[1] * q[3]);\r
318     m[2][1] = 2.0 * (q[1] * q[2] + q[0] * q[3]);\r
319     m[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]);\r
320     m[2][3] = 0.0;\r
321 \r
322     m[3][0] = 0.0;\r
323     m[3][1] = 0.0;\r
324     m[3][2] = 0.0;\r
325     m[3][3] = 1.0;\r
326 }\r
327 \r