function superclock
%SUPERCLOCK takes advantage of the computer to redefine how you tell time
% Greg Aloe
% August 26, 2002:
% Adapted from a previous version to take advantage of the R13 timer object.
% November 17, 2004:
% Updated to use function handle callbacks.
% Updated to delete timer on close.
% Updated to turn rotation tool on by default.
% Changed to use perspective projection.
% Initialize clock data without input arguments
%**********************************************************************
% DATA INITIALIZATION
%**********************************************************************
% Start creating spiral
th = linspace(0,2*pi,32); %wire circle
rwire = 2; %wire radius
rminute = 30; %spiral radius
numspiral = 12; %number of rotations in spiral
spiralspace = 8; %distance between spirals
spiralres = 50; %graphical resolution (surfaces per 360 deg)
% xyz-coordinates for spiral wire circle
z0sp = rwire*cos(th);
y0sp = zeros(size(z0sp));
x0sp = -rminute*ones(size(z0sp)) + rwire*sin(th);
% Move coordinates into a vector set for ease of transformations
circwire = [x0sp;y0sp;z0sp];
% Theta data for wire circle transformations
tcircbuild = linspace(0,2*pi*numspiral,numspiral*spiralres);
% Initialize spiral data surfaces
spiralx = zeros(length(tcircbuild),length(th));
spiraly = zeros(length(tcircbuild),length(th));
spiralz = zeros(length(tcircbuild),length(th));
% Insert first wire circle into spiral data surfaces
spiralx(1,:) = x0sp;
spiraly(1,:) = y0sp;
spiralz(1,:) = z0sp;
% Perform transformations and store spiral surf data
for n=2:length(tcircbuild)
% Transformation matrix rotates wire circle around z-axis
t = [cos(tcircbuild(n)) sin(tcircbuild(n)) 0;
-sin(tcircbuild(n)) cos(tcircbuild(n)) 0;
0 0 1];
newcirc = t*circwire;
spiralx(n,:) = newcirc(1,:);
spiraly(n,:) = newcirc(2,:);
spiralz(n,:) = newcirc(3,:) - spiralspace*numspiral/length(tcircbuild)*n;
end
%%% Make spiral color data for swapping colors for 'hour hand'
% Spiral color data: color
spiralcdata = repmat([1:spiralres]',numspiral,length(th));
% Spiral color data: grey
spiralgdata = (spiralres+1)*ones(size(spiralcdata));
% Initialize color as grey
spiralc = spiralgdata;
%% OBJECT INITIALIZATION
% Create figure and axes
hf = figure('units','normalized','position',[.3 .1 .5 .85]);
set(hf,'name','Super Fly Clock','numbertitle','off')
set(hf,'doublebuffer','on');
set(hf,'tag','superflyclock');
set(hf,'menubar','none')
set(hf,'closerequestfcn',@closerequestfcn)
ha = axes;
set(ha,'clim',[1 (spiralres+1)]);
% Create spiral surface to allow for auto-figure/axes settings
hspiral = surf(spiralx,spiraly,spiralz,spiralc);
% Create color map, colors to match spiral graphical resolution, plus grey for use in colormap
map = [hsv(spiralres); 0.5 0.5 0.5];
colormap(ha,map);
% Make some axes adjustments
hold on
axis('equal','vis3d','off')
view([-168,20])
set(ha,'position',[-.2 -.2 1.4 1.4])
% Start creating annulus at ORIGIN
rannwire = 2.5; %annulus wire radius
rann = rannwire+2*rwire; %annulus radius
annres = 30; %annulus graphical resolution
th2 = linspace(0,2*pi,annres); %annulus wire circle
% xyz-coordinates for annulus wire circle
x0ann = zeros(size(th2));
y0ann = rannwire*sin(th2);
z0ann = rannwire*cos(th2)+rannwire+rwire;
% Move coordinates into a vector set for ease of transformations
annwire = [x0ann;y0ann;z0ann];
% Initialize annulus data surfaces
annx = zeros(length(th2),length(th2));
anny = zeros(length(th2),length(th2));
annz = zeros(length(th2),length(th2));
% Insert first wire circle into annulus data surfaces
annx(1,:) = x0ann;
anny(1,:) = y0ann;
annz(1,:) = z0ann;
% Perform transformations and store annulus surf data
for n=2:length(th2)
%Transformation matrix rotates annulus wire around y-axis
t = [cos(th2(n)) 0 -sin(th2(n)) ;...
0 1 0 ;...
sin(th2(n)) 0 cos(th2(n))] ;
newcirc = t*annwire;
annx(n,:) = newcirc(1,:);
anny(n,:) = newcirc(2,:);
annz(n,:) = newcirc(3,:);
end
% Move annulus to start position
annx = annx-rminute;
% Annulus color data: all red
annc = ones(size(annx));
% Create unit sphere at origin
sphereres = 15; %graphical resolution of sphere
[sphx,sphy,sphz] = sphere(sphereres);
% Move and scale sphere to spiral inlet
rsph = rwire-0.15*rwire;
sphx = rsph*sphx-rminute;
sphy = rsph*sphy;
sphz = rsph*sphz;
% Sphere color data: all red
sphc = ones(size(sphx));
% Convert surf data to vectors for ease of transformations
% This will be the absolute data that gets transformed, rather than delta transformations
spiralvec0 = surf2vec(spiralx,spiraly,spiralz);
sphvec0 = surf2vec(sphx,sphy,sphz);
% Draw initial setup so we can later change the surf data positions in the loop
set(hspiral,'facealpha',0.45) %set transparency of spiral (drawn earlier)
hann = surf(annx,anny,annz,annc); %draw annulus
hsph = surf(sphx,sphy,sphz,sphc); %draw sphere
shading interp
hl = light('position',[15 5 20]); %create lighting
%for use in timerfcn structure
spiralcdatat = spiralcdata';
deltazfactor = (numspiral*spiralspace)/60;
rotsize = 60/numspiral;
minutethetafactor = 2*pi/rotsize;
[spiralrow,spiralcol]=size(spiralx);
secondthetafactor = 2*pi*numspiral/60;
[sphrow,sphcol]=size(sphx);
spiraldatalength = length(spiralgdata(:));
rotate3d('on')
camproj perspective
% Store some userdata for easy passing of variables into the timerfcn
ud.hf = hf;
ud.hspiral = hspiral;
ud.hann = hann;
ud.hsph = hsph;
ud.spiraldatalength = spiraldatalength;
ud.annz = annz;
ud.deltazfactor = deltazfactor;
ud.rotsize = rotsize;
ud.minutethetafactor = minutethetafactor;
ud.spiralvec0 = spiralvec0;
ud.spiralrow = spiralrow;
ud.spiralcol = spiralcol;
ud.secondthetafactor = secondthetafactor;
ud.sphvec0 = sphvec0;
ud.deltazfactor = deltazfactor;
ud.sphrow = sphrow;
ud.sphcol = sphcol;
ud.spiralgdata = spiralgdata;
ud.spiralcdatat = spiralcdatat;
% Create the timer
%timerFcnStr = 'superclock(''timerFcn'',get(findall(0,''tag'',''superflyclock''),''userdata''))';
ud.timerObj = timer('timerfcn',{@timerFcn,hf},'period',1,'executionmode','fixedrate');
% Set the userdata and remove handlevisibility so figure is not accessible
set(hf,'userdata',ud,'handlevisibility','off');
% Start the timer
start(ud.timerObj)
function timerFcn(ht,ed,hf)
% The actual time function
ud = get(hf,'userdata');
try
time = clock; %get computer time
% Find hour to all decimal places (military time)
hourfrac = time(4)+time(5)/60+time(6)/3600;
% Set background color according to day or night
colorfactor = 0.5+0.4*sin(2*pi/24*hourfrac-2*pi*8/24);
set(ud.hf,'color',colorfactor*[1 1 1]);
% Convert hour to non-military time
if time(4)>=12
hourfrac = hourfrac-12;
end
% Set hour color
colorlim = floor(ud.spiraldatalength*hourfrac/12); %find how much color to fill in
newcolordata = ud.spiralgdata'; %reset newcolordata in case of 12 o'clock
newcolordata(1:colorlim) = ud.spiralcdatat(1:colorlim); %fill hours passed with color
set(ud.hspiral,'cdata',newcolordata');
%%%%%% Set object positions
minutefrac = time(5)+time(6)/60;
% Move annulus according to minute
set(ud.hann,'zdata',ud.annz-minutefrac*ud.deltazfactor);
% Move spiral according to hour
minutetheta = mod(minutefrac,ud.rotsize)*ud.minutethetafactor;
spiralvecnew = rotatez(ud.spiralvec0,minutetheta);
[spiralsurfxnew,spiralsurfynew,spiralsurfznew] = vec2surf(spiralvecnew,ud.spiralrow,ud.spiralcol);
set(ud.hspiral,'xdata',spiralsurfxnew,'ydata',spiralsurfynew,'zdata',spiralsurfznew);
% Set sphere according to spiral rotation and second
secondtheta = time(6)*ud.secondthetafactor;
sphvecnew = rotatez(ud.sphvec0,minutetheta-secondtheta);
deltasphz = time(6)*ud.deltazfactor;
[sphsurfxnew,sphsurfynew,sphsurfznew] = vec2surf(sphvecnew,ud.sphrow,ud.sphcol);
set(ud.hsph,'xdata',sphsurfxnew,'ydata',sphsurfynew,'zdata',sphsurfznew-deltasphz);
% Update figure
drawnow
end
function [surfvecx,surfvecy,surfvecz] = vec2surf(vec,r,c)
% Helper function to convert a vector of points to data that SURFACEs can use
surfvecx = reshape(vec(1,:),r,c);
surfvecy = reshape(vec(2,:),r,c);
surfvecz = reshape(vec(3,:),r,c);
function newvec = rotatez(vec,theta)
% Calculates a rotation vector easily
t = [cos(theta) -sin(theta) 0;
sin(theta) cos(theta) 0;
0 0 1];
newvec = t*vec;
function [vec] = surf2vec(surfvecx,surfvecy,surfvecz)
% Helper function to convert data that SURFACEs can use to a vector of points
[r,c] = size(surfvecx);
vec = zeros(3,r*c);
vec(1,:) = surfvecx(:)';
vec(2,:) = surfvecy(:)';
vec(3,:) = surfvecz(:)';
function closerequestfcn(hf,ed)
% Shut off the timer and close the figure when the x is clicked
ud = get(hf,'userdata');
stop(ud.timerObj)
delete(ud.timerObj)
closereq