1 /* The original version of this file came from OpenTissue
2 *
3 * Copyright (C) 2003 Department of Computer Science, University of Copenhagen
4 * Modifications copyright 2004, 2005 Nicholas Bishop
5 *
6 * This file is part of SharpConstruct.
7 *
8 * SharpConstruct is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * SharpConstruct is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with SharpConstruct; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
21
22 #include <cmath>
23 #include "ArcBall.h"
24
ArcBall(const double r)25 ArcBall::ArcBall( const double r )
26 : radius( r )
27 {
28 Reset();
29 }
30
~ArcBall()31 ArcBall::~ArcBall()
32 {}
33
NormalizeCoordinates(double & x,double & y,int w,int h)34 void ArcBall::NormalizeCoordinates( double &x, double &y, int w, int h )
35 {
36 x = 2 * x / w - 1;
37 if( x < -1 )
38 x = -1;
39 if( x > 1 )
40 x = 1;
41
42 y = -( 2 * y / h - 1 );
43 if (y < -1)
44 y = -1;
45 if (y > 1)
46 y = 1;
47 }
48
Reset()49 void ArcBall::Reset()
50 {
51 for( int i = 0; i < 3; i++ )
52 {
53 Panchor[ i ] = 0;
54 Pcurrent[ i ] = 0;
55 CurrentAxis[ i ] = 0;
56 }
57 CurrentAngle = 0;
58
59 Identity( AnchorTransformation );
60 Identity( IncrementalTransformation );
61 Identity( CurrentTransformation );
62
63 ProjectOntoSurface( Panchor );
64 ProjectOntoSurface( Pcurrent );
65 }
66
BeginDrag(const double x,const double y)67 void ArcBall::BeginDrag( const double x, const double y )
68 {
69 CurrentAngle = 0;
70 CurrentAxis[ 0 ] = 0;
71 CurrentAxis[ 1 ] = 0;
72 CurrentAxis[ 2 ] = 0;
73
74 Copy( CurrentTransformation, AnchorTransformation );
75 Identity( IncrementalTransformation );
76 Identity( CurrentTransformation );
77
78 Panchor[ 0 ] = x;
79 Panchor[ 1 ] = y;
80 Panchor[ 2 ] = 0;
81 ProjectOntoSurface( Panchor );
82 Pcurrent[ 0 ] = x;
83 Pcurrent[ 1 ] = y;
84 Pcurrent[ 2 ] = 0;
85 ProjectOntoSurface( Pcurrent );
86 }
87
Drag(const double x,const double y)88 void ArcBall::Drag( const double x, const double y )
89 {
90 Pcurrent[ 0 ] = x;
91 Pcurrent[ 1 ] = y;
92 Pcurrent[ 2 ] = 0;
93 ProjectOntoSurface( Pcurrent );
94
95 ComputeIncrementalTransformation( Panchor, Pcurrent,
96 IncrementalTransformation );
97 }
98
ProjectOntoSurface(Vector & P)99 void ArcBall::ProjectOntoSurface( Vector &P )
100 {
101 double radius2 = radius * radius;
102 double length2 = P[ 0 ] * P[ 0 ] + P[ 1 ] * P[ 1 ];
103
104 if( length2 <= radius2 / 2.0 )
105 P[ 2 ] = sqrt(radius2 - length2);
106 else
107 {
108 P[ 2 ] = radius2 / ( 2 * sqrt( length2 ) );
109
110 double length = sqrt( length2 + P[ 2 ] * P[ 2 ] );
111 P[ 0 ] /= length;
112 P[ 1 ] /= length;
113 P[ 2 ] /= length;
114 }
115 double lengthP = Length( P );
116 for( int i = 0; i < 3; i++ )
117 P[ i ] /= lengthP;
118 }
119
Transformation()120 const ArcBall::Transform& ArcBall::Transformation()
121 {
122 Multiply( IncrementalTransformation, AnchorTransformation,
123 CurrentTransformation );
124
125 return CurrentTransformation;
126 }
127
128 // Just a little debugging helper
129 /*void printT( const ArcBall::Transform& t )
130 {
131 for( unsigned i = 0; i < 4; i++ )
132 {
133 for( unsigned j = 0; j < 4; j++ )
134 std::cout << std::setw( 9 ) << t[ i ][ j ] << " ";
135 std::cout << std::endl;
136 }
137 std::cout << std::endl;
138 }*/
139
SnapRotation(const Transform & t,float angle)140 const ArcBall::Transform& ArcBall::SnapRotation( const Transform& t, float angle )
141 {
142 //printT( t );
143
144 const float PI = 3.1415;
145
146 float aX, aY, aZ;
147 float a, b, c, d, e, f, trX, trY;
148
149 aY = asin( t[ 0 ][ 2 ] );
150 c = cos( aY );
151
152 if( fabs( c ) > 0.005f )
153 {
154 trX = t[ 2 ][ 2 ] / c;
155 trY = -t[ 1 ][ 2 ] / c;
156 aX = atan2( trY, trX );
157 trX = t[ 0 ][ 0 ] / c;
158 trY = -t[ 0 ][ 1 ] / c;
159 aZ = atan2( trY, trX );
160 }
161 else
162 {
163 aX = 0;
164 trX = t[ 1 ][ 1 ];
165 trY = t[ 1 ][ 0 ];
166 aZ = atan2( trY, trX );
167 }
168
169 ////
170 aX = round( ( aX * ( 180 / PI ) ) * ( 1.0f / angle ) ) * angle;
171 aY = round( ( aY * ( 180 / PI ) ) * ( 1.0f / angle ) ) * angle;
172 aZ = round( ( aZ * ( 180 / PI ) ) * ( 1.0f / angle ) ) * angle;
173
174 aX *= ( PI / 180 );
175 aY *= ( PI / 180 );
176 aZ *= ( PI / 180 );
177 ////
178
179 a = cos( aX );
180 b = sin( aX );
181 c = cos( aY );
182 d = sin( aY );
183 e = cos( aZ );
184 f = sin( aZ );
185
186 SnapTransform[ 0 ][ 0 ] = c * e;
187 SnapTransform[ 0 ][ 1 ] = -c * f;
188 SnapTransform[ 0 ][ 2 ] = d;
189 SnapTransform[ 0 ][ 3 ] = 0;
190 SnapTransform[ 1 ][ 0 ] = b * d * e + a * f;
191 SnapTransform[ 1 ][ 1 ] = -b * d * f + a * e;
192 SnapTransform[ 1 ][ 2 ] = -b * c;
193 SnapTransform[ 1 ][ 3 ] = 0;
194 SnapTransform[ 2 ][ 0 ] = -a * d * e + b * f;
195 SnapTransform[ 2 ][ 1 ] = a * d * f + b * e;
196 SnapTransform[ 2 ][ 2 ] = a * c;
197 SnapTransform[ 2 ][ 3 ] = 0;
198 SnapTransform[ 3 ][ 0 ] = 0;
199 SnapTransform[ 3 ][ 1 ] = 0;
200 SnapTransform[ 3 ][ 2 ] = 0;
201 SnapTransform[ 3 ][ 3 ] = 1;
202
203 //printT( SnapTransform );
204 //std::cout << "aX: " << aX << ", aY: " << aY << ", aZ: " << aZ << std::endl;
205 //std::cout << "a: " << a << ", b: " << b << ", c: " << c << ", d: " << d << ", e: " << e << ", f: " << f << std::endl;
206
207 return SnapTransform;
208 }
209
BakeSnapRotation()210 void ArcBall::BakeSnapRotation()
211 {
212 for( unsigned i = 0; i < 4; i++ )
213 for( unsigned j = 0; j < 4; j++ )
214 AnchorTransformation[ i ][ j ] = SnapTransform[ i ][ j ];
215
216 Identity( IncrementalTransformation );
217 Identity( CurrentTransformation );
218 }
219
Identity(Transform & transformation) const220 void ArcBall::Identity( Transform &transformation ) const
221 {
222 int i, j;
223
224 for( i = 0; i < 4; i++ )
225 for( j = 0; j < 4; j++ )
226 transformation[ i ][ j ] = 0;
227
228 for( i = 0; i < 4; i++ )
229 transformation[ i ][ i ] = 1;
230 }
231
Copy(const Transform & src,Transform & dst) const232 void ArcBall::Copy( const Transform &src, Transform &dst ) const
233 {
234 int i, j;
235
236 for( i = 0; i < 4; i++ )
237 for( j = 0; j < 4; j++ )
238 dst[ i ][ j ] = src[ i ][ j ];
239 }
240
Multiply(const Transform & trans1,const Transform & trans2,Transform & transformation) const241 void ArcBall::Multiply( const Transform &trans1, const Transform &trans2,
242 Transform &transformation ) const
243 {
244 int i, j, k;
245 double sum;
246
247 for( i = 0; i < 4; i++ )
248 {
249 for( j = 0; j < 4; j++ )
250 {
251 for( k = 0, sum = 0; k < 4; k++ )
252 sum += trans1[ i ][ k ] * trans2[ k ][ j ];
253 transformation[ i ][ j ] = sum;
254 }
255 }
256 }
257
Length(const Vector & vec) const258 double ArcBall::Length( const Vector &vec ) const
259 {
260 double length = 0;
261 for( int i = 0; i < 3; i++ )
262 length += vec[ i ] * vec[ i ];
263
264 return sqrt(length);
265 }
266
267
Copy(const Vector & src,Vector & dst) const268 void ArcBall::Copy( const Vector &src, Vector &dst ) const
269 {
270 for( int i = 0; i < 3; i++ )
271 dst[ i ] = src[ i ];
272 }
273
Dot(const Vector & vec1,const Vector & vec2) const274 double ArcBall::Dot( const Vector &vec1, const Vector &vec2 ) const
275 {
276 double dotprod( 0 );
277 for( int i = 0; i < 3; i++ )
278 dotprod += vec1[ i ] * vec2[ i ];
279
280 return dotprod;
281 }
282
283
Cross(const Vector & vec1,const Vector & vec2,Vector & crossprod) const284 void ArcBall::Cross(const Vector& vec1, const Vector& vec2,
285 Vector& crossprod) const
286 {
287 crossprod[ 0 ] = vec1[ 1 ] * vec2[ 2 ] - vec2[ 1 ] * vec1[ 2 ];
288 crossprod[ 1 ] = vec2[ 0 ] * vec1[ 2 ] - vec1[ 0 ] * vec2[ 2 ];
289 crossprod[ 2 ] = vec1[ 0 ] * vec2[ 1 ] - vec2[ 0 ] * vec1[ 1 ];
290 }
291
ComputeIncrementalTransformation(const Vector & Panchor,const Vector & Pcurrent,Transform & transformation)292 void ArcBall::ComputeIncrementalTransformation(const Vector& Panchor,
293 const Vector& Pcurrent,
294 Transform& transformation)
295 {
296 double lengthPa = Length(Panchor);
297 double lengthPc = Length(Pcurrent);
298 Vector Pa;
299 Vector Pc;
300 for( int i = 0; i < 3; i++ )
301 {
302 Pa[ i ] = Panchor[i] / lengthPa;
303 Pc[ i ] = Pcurrent[i] / lengthPc;
304 }
305
306 Vector Axis;
307 Cross( Panchor, Pcurrent, Axis );
308 double lengthAxis = Length(Axis);
309 double Ux = Axis[ 0 ];
310 double Uy = Axis[ 1 ];
311 double Uz = Axis[ 2 ];
312 if( lengthAxis != 0 )
313 {
314 Ux /= lengthAxis;
315 Uy /= lengthAxis;
316 Uz /= lengthAxis;
317 }
318 CurrentAxis[ 0 ] = Ux;
319 CurrentAxis[ 1 ] = Uy;
320 CurrentAxis[ 2 ] = Uz;
321
322 double Theta = atan2( lengthAxis, Dot( Panchor, Pcurrent ) );
323 CurrentAngle = Theta;
324
325 double sinTheta = sin( Theta );
326 double cosTheta = cos( Theta );
327
328 transformation[ 0 ][ 0 ] = Ux * Ux + (1 - Ux * Ux) * cosTheta;
329 transformation[ 0 ][ 1 ] = Ux * Uy * (1 - cosTheta) - Uz * sinTheta;
330 transformation[ 0 ][ 2 ] = Ux * Uz * (1 - cosTheta) + Uy * sinTheta;
331 transformation[ 0 ][ 3 ] = 0;
332 transformation[ 1 ][ 0 ] = Ux * Uy * (1 - cosTheta) + Uz * sinTheta;
333 transformation[ 1 ][ 1 ] = Uy * Uy + (1 - Uy * Uy) * cosTheta;
334 transformation[ 1 ][ 2 ] = Uy * Uz * (1 - cosTheta) - Ux * sinTheta;
335 transformation[ 1 ][ 3 ] = 0;
336 transformation[ 2 ][ 0 ] = Ux * Uz * (1 - cosTheta) - Uy * sinTheta;
337 transformation[ 2 ][ 1 ] = Uy * Uz * (1 - cosTheta) + Ux * sinTheta;
338 transformation[ 2 ][ 2 ] = Uz * Uz + (1 - Uz * Uz) * cosTheta;
339 transformation[ 2 ][ 3 ] = 0;
340 transformation[ 3 ][ 0 ] = 0;
341 transformation[ 3 ][ 1 ] = 0;
342 transformation[ 3 ][ 2 ] = 0;
343 transformation[ 3 ][ 3 ] = 1;
344 }
345