-
Notifications
You must be signed in to change notification settings - Fork 56
/
arcball.m
118 lines (99 loc) · 3.12 KB
/
arcball.m
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
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
% Copyright (c) 2008 Andrea Tagliasacchi
% All Rights Reserved
% email: ata2 at cs dot nospam dot sfu dot ca
% $Revision: 1.0$ 10 February 2008
function arcball()
clc, clear, close all;
% draw some dummy data
[x,y,z] = sphere(50);
H = figure;
h = hgtransform;
hg = hggroup('parent', h); % to draw for debug purposes
surf(gca,x,y,z,z,'parent',h);
axis square
axis([-1 1 -1 1 -1 1]);
axis off;
view(2);
% register callbacks ad
set( H, 'WindowButtonMotionFcn', @motion_callback );
set( H, 'WindowButtonDownFcn', @buttondown_callback );
set( H, 'WindowButtonUpFcn', @buttonup_callback );
mousestatus = 'buttonup';
START = [0,0,0];
M_previous = get( h, 'Matrix' );
%%%%%%%%%%%% CALLBACKS %%%%%%%%%%%%%%
% motion callback, event "every" mouse movement
function motion_callback(src, event)
% retrieve the current point
P = get(gcf,'CurrentPoint');
% retrieve window geometry
HGEOM = get( src, 'Position');
% transform in sphere coordinates (3,4) = (WIDTH, HEIGHT)
P = point_on_sphere( P, HGEOM(3), HGEOM(4) );
% workaround condition (see point_on_sphere)
if isnan(P)
return;
end
%%%%% ARCBALL COMPUTATION %%%%%
if strcmp(mousestatus, 'buttondown')
% compute angle and rotation axis
rot_dir = cross( START, P ); rot_dir = rot_dir / norm( rot_dir );
rot_ang = acos( dot( P, START ) );
% convert direction in model coordinate system
M_tr = inv( M_previous );
rot_dir = M_tr*[rot_dir,0]';
rot_dir = rot_dir(1:3);
rot_dir = rot_dir / norm( rot_dir ); % renormalize
% construct matrix
R_matrix = makehgtform('axisrotate',rot_dir,rot_ang);
% set hgt matrix
set(h,'Matrix',M_previous*R_matrix);
% refresh drawing
drawnow;
end
end
% only 1 event on click
function buttondown_callback( src, evnt )
% change status
mousestatus = 'buttondown';
% retrieve the current point
P = get(gcf,'CurrentPoint');
% retrieve window geometry
HGEOM = get( src, 'Position');
% SET START POSITION
START = point_on_sphere( P, HGEOM(3), HGEOM(4) );
% SET START MATRIX
M_previous = get( h, 'Matrix' );
end
function buttonup_callback( src, evnt )
% change status
mousestatus = 'buttonup';
% reset the start position
START = [0,0,0];
end
%%%%%%%%%%%% UTILITY FUNCTION %%%%%%%%%%%%%
function P = point_on_sphere( P, width, height )
P(3) = 0;
% determine radius of the sphere
R = min(width, height)/2;
% TRANSFORM the point in window coordinate into
% the coordinate of a sphere centered in middle window
ORIGIN = [width/2, height/2, 0];
P = P - ORIGIN;
% normalize position to [-1:1] WRT unit sphere
% centered at the origin of the window
P = P / R;
% if position is out of sphere, normalize it to
% unit length
L = sqrt( P*P' );
if L > 1
% P = nan; % workaround to stop evaluation
% disp('out of sphere');
P = P / L;
P(3) = 0;
else
% add the Z coordinate to the scheme
P(3) = sqrt( 1 - P(1)^2 - P(2)^2 );
end
end
end %% END OF FUNCTION %%