% Examination of the behavior of a second-order linear constant
% coefficient equation, animating a figure showing a mass-spring
% system and the corresponding solution to the differential equation.
%
% by Justin Dunmyre
% minor updates by Gavin LaRose, 9/27/2012

% (c)2012 Regents of the University of Michigan
% This work is licensed under the
% Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
% To view a copy of this license, visit
% http://creativecommons.org/licenses/by-nc-sa/3.0/
% or send a letter to
% Creative Commons,
% 444 Castro Street, Suite 900,
% Mountain View, CA, 94041, USA.

function Spring_Animation_GUI()

%-------------------------------------------------------------------------------
% configuration variables

% our differential equation is m x'' + c x' + k x = 0, with initial
%    conditions x(0) = x0 and x'(0) = xp0.  these values give the
%    default values of m, c, k, x0 and xp0.
    defaultm  = 1;
    defaultc  = 0.1;
    defaultk  = 1;
    defaultx0 = 1;
    defaultxprime0 = 0;
    
% how many t points to use:  more points results in slower animations
%    (but see frameSkip)
    numT = 150;
% how many steps to skip before updating the display, controls speed of
%    animation
    frameSkip = 1;

% the background color of the display
    bggray   = [.6 .6 .6];
% the color used for the solution curve
    solColor = 'r';
% and the color for the traces of previous solution curves    
    fadeColor=[.2 .2 .2];

%-------------------------------------------------------------------------------
% initialization

% Variables defined here so that they have global scope
    m = defaultm;
    c = defaultc;
    k = defaultk;
    xprime0 = defaultxprime0;
    x0 = defaultx0;
    pauseFlag = 0;

    springMin = -3;
    springMax = 5;
    timeMin = 0;
    timeMax = 30;
    
    springGraphInitialized = 0;
    springCoilh = 0;
    springDoth = 0;
    dashpoth = 0;
    solTail = 0;
    solDot = 0;
    d1=0;d2=0;d3=0;d4=0;d5=0;
    subplotSpring = 0;
    subplotSol = 0;
    controls = 0;
    figh = 0;
    pausebutton = 0;

%-------------------------------------------------------------------------------
% run demonstration

    drawWindow();
    setupUI();
    mainProcess();
   
%-------------------------------------------------------------------------------
% functions that manage the demonstration
    
    function mainProcess()

        if(length(solTail)>1)
                set(solTail(end),'Color',fadeColor,'LineStyle',':','LineWidth',1.5);
                set(solDot(end),'Visible','off');
                solTail=0;
                solDot=0;
        end
        
        [t,springSol]=ode45(@springODE,linspace(timeMin,timeMax,numT),[x0;xprime0]);
        
        springX=springSol(:,1);

        solDot(1)=plot(t(1),springX(1),[solColor '.'],'MarkerSize',15,'Parent',subplotSol);
        solTail(1)=plot(t(1:2),springX(1:2),[solColor '-'],'LineWidth',1,'Parent',subplotSol);

        getframe();   

        for j=2:frameSkip:length(t)
            set(solTail(j-1),'Visible','Off');
            set(solDot(j-1),'Visible','Off');

            solTail(j)=plot(t(1:j),springX(1:j),[solColor '-'],'LineWidth',3,'Parent',subplotSol);
            solDot(j)=plot(t(j),springX(j),[solColor '.'],'MarkerSize',40,'Parent',subplotSol);

            plotSystem(springX(j),m,c,k);
            getframe();
        end
    end
    
% the ODE we solve

    function xprime=springODE(t,x)
        x1=x(1);
        x2=x(2);
        x1prime=x2;
        x2prime=(-k*x1-c*x2)/m;
        
        xprime=[x1prime;x2prime];
    end

% plot function to graph the spring-dashpot system

    function plotSystem(x,m,c,k)
        
        if ( springGraphInitialized > 0 )
            delete(springCoilh);
            delete(springDoth);
            % for some reason we can't delete these
            set( d1, 'Visible', 'off' );
            set( d2, 'Visible', 'off' );
            set( d3, 'Visible', 'off' );
            set( d4, 'Visible', 'off' );
            set( d5, 'Visible', 'off' );
            % delete( d1,d2,d3,d4,d5 );
        else
            springGraphInitialized = 1;
        end
        
        orig=springMin;
        numCoil=10;
        amp=.4;
        coilx=linspace(orig,x,10000);
        tempx=(coilx-orig)*(pi-orig)/(x-orig) + orig;
        coily=amp*sin(numCoil*tempx);

        springCoilh=plot(coilx,coily,'b-','Parent',subplotSpring);
        
        if(c>0)
            % if(d1>0)
            %     delete(d1,d2,d3,d4,d5); 
            %     d1=0;d2=0;d3=0;d4=0;d5=0;
            % end
            origin=x;
            stemLength=1;
            potAmp=.4;
            totalx=4;
            realOrigin=-2;
            endstem=origin+stemLength;

            d1=plot([origin, endstem], [0 0], 'k-', 'LineWidth', 2, ...
                    'Parent',subplotSpring);
            d2=plot([endstem endstem],[-potAmp potAmp], 'k:', ...
                    'LineWidth',2,'Parent',subplotSpring);
            d3=plot([realOrigin+stemLength/2, totalx], ...
                    [potAmp potAmp], 'k-', 'Parent', subplotSpring);
            d4=plot([realOrigin+stemLength/2, totalx], ...
                    [-potAmp -potAmp], 'k-', 'Parent', subplotSpring);
            d5=plot([totalx totalx],[-potAmp, potAmp], 'k-', ...
                    'Parent', subplotSpring);        
        else
            % if(d1>0)
            %     delete(d1,d2,d3,d4,d5); 
            %     d1=0;d2=0;d3=0;d4=0;d5=0;
            % end
        end
        
        springDoth=plot(x,0,'r.','MarkerSize',80,'Parent',subplotSpring);
    end

    
%-------------------------------------------------------------------------------
% GUI control functions

    function setupUI()

        figure(controls);
    
        bgroup = uibuttongroup('visible','off','Position',[0 0 1 1], ...
                               'Parent',controls);

        pausebutton = uicontrol('Parent',bgroup,'Style','PushButton', ...
                                'Min',0,'Max',1,'Parent',bgroup, ...
                                'Position',[50 0 100 30], ...
                                'String','Pause/Continue', ...
                                'Callback',@togglebuttonCall);

        uicontrol('Parent',bgroup,'Style','PushButton', ...
                  'Parent',bgroup,'Position',[50 480 100 30], ...
                  'String','Reset','Callback',@resetButtonCall);

        uicontrol('Parent',bgroup,'Style','PushButton', ...
                  'Parent',bgroup,'Position',[50 515 100 30], ...
                  'String','Start','Callback',@startButtonCall);


        uicontrol('Parent',bgroup,'Style','PushButton', ...
                  'Parent',bgroup,'Position',[50 40 100 30], ...
                  'String','EXIT','Callback',@exitCall);

        uicontrol('Style','text','String','m','FontSize',15, ...
                  'pos',[20 300 30 30],'parent',bgroup, ...
                  'HandleVisibility','off');
        uicontrol('Style','Text','String','c','FontSize',15, ...
                  'pos',[20 250 30 30],'parent',bgroup, ...
                  'HandleVisibility','off');
        uicontrol('Style','Text','String','k','FontSize',15, ...
                  'pos',[20 200 30 30],'parent',bgroup, ...
                  'HandleVisibility','off');

        uicontrol('Style','Text','String','x''(0)','FontSize',15, ...
                  'pos',[20 100 30 30],'parent',bgroup, ...
                  'HandleVisibility','off');
        uicontrol('Style','Text','String','x(0)','FontSize',15, ...
                  'pos',[20 150 30 30],'parent',bgroup, ...
                  'HandleVisibility','off');
        uicontrol('Style','edit','parent',bgroup,'pos',[50 155 30 30], ...
                  'Callback',@tx0cb,'String',num2str(defaultx0));

        uicontrol('Style','edit','parent',bgroup,'pos',[50 305 30 30], ...
                  'Callback',@t1cb,'String',num2str(defaultm));
        uicontrol('Style','edit','parent',bgroup,'pos',[50 255 30 30], ...
                  'Callback',@t2cb,'String',num2str(defaultc));
        uicontrol('Style','edit','parent',bgroup,'pos',[50 205 30 30], ...
                  'Callback',@t3cb,'String',num2str(defaultk));
        uicontrol('Style','edit','parent',bgroup,'pos',[50 105 30 30], ...
                  'Callback',@t4cb,'String',num2str(defaultxprime0));

        uicontrol('Style','text','parent',bgroup, ...
                  'HandleVisibility','off','pos',[0 430 180 30],...
                  'String','mx''''+cx''+kx =0','FontSize',15);        

        uicontrol('Style','text','parent',bgroup,...
                  'HandleVisibility','off','pos',[0 350 180 60],...
                  'String',{'Edit settings below, then click Start above'}, ...
                  'FontSize',15);

        set(bgroup,'SelectionChangeFcn',@uibuttongroup1_SelectionChangeFcn);

        set(bgroup,'Visible','on');   
        
        figure(figh);
    end
    
% Quit button
    function exitCall(hObject,eventdata)
        close all;    
    end

% Start button
    function startButtonCall(hObject,eventdata)
        figure(figh);
        mainProcess();
    end

% Reset button
    function resetButtonCall(hObject,eventdata)
        % unpause if paused
        uiresume;
        set(pausebutton,'String','Pause');
        % kill all windows, reset configurable variables to default    
        close all;
        m=defaultm;
        c=defaultc;
        k=defaultk;
        xprime0=defaultxprime0;
        x0=defaultx0;
    
        springCoilh=0;
        springDoth=0;
        dashpoth=0;
        solTail=0;
        solDot=0;
        d1=0;d2=0;d3=0;d4=0;d5=0;
        
        drawWindow();    
        setupUI();
    end

% functions to update the appropriate variables when the text changes

    function t1cb(hObject,eventdata)
        m=str2double(get(hObject,'String'));
    end
    
    function t2cb(hObject,eventdata)
        c=str2double(get(hObject,'String'));
    end

    function t3cb(hObject,eventdata)
        k=str2double(get(hObject,'String'));
    end

    function t4cb(hObject,eventdata)
        xprime0=str2double(get(hObject,'String'));
    end
    
    function tx0cb(hObject,eventdata)
        x0=str2double(get(hObject,'String'));
    end

% pause/continue button functionality
    function togglebuttonCall(hObject,eventdata)
        figure(figh);
        if(pauseFlag==0)
            set(pausebutton,'String','Continue');
            pauseFlag=1;
            uiwait;
        else
            pauseFlag=0;
            set(pausebutton,'String','Pause');
            uiresume;
            figure(figh);
        end
    end
    
% function to draw the default window

    function drawWindow()       
        scrsz = get(0,'ScreenSize'); %Get the screen size
    
    
        controls=figure('OuterPosition',[1 scrsz(4)/1.5 205 scrsz(4)/1.5]);
        set(controls,'MenuBar','none','Name','Controls');
        figh=figure('OuterPosition', ...
                    [200 scrsz(4)/3 scrsz(3)/3 scrsz(4)/3], ...
                    'Name','Spring Simulation'); %Create a new figure window
        axes('Parent',figh,'Color',bggray); %Change the color
    
        subplotSpring=subplot(2,1,1,'parent',figh);
        subplotSol=subplot(2,1,2,'parent',figh); 
    
        hold(subplotSpring);
        hold(subplotSol);
    
        axis(subplotSpring,[springMin springMax -1 1]);
        axis(subplotSol,[timeMin timeMax springMin springMax]);
    
        plot(zeros(1,100),linspace(-1,1,100),'k:',...
             'Parent',subplotSpring,'LineWidth',2);
        plot(linspace(timeMin,timeMax,100),zeros(1,100),'k:');
        plotSystem(x0,m,c,k);
    end
    
end

% all done
%-------------------------------------------------------------------------------
