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