Code covered by the BSD License  

Highlights from
superclock

image thumbnail
from superclock by Greg Aloe
SUPERCLOCK takes advantage of computer graphics to redefine how you tell time.

superclock
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

Contact us at files@mathworks.com