function opg23()
% OPG23 Animate and adjust sine / cosine waves in real time.
%
% OPG23( ) takes no arguments and returns nothing.
%
% Function solving exercise 23 of assignment 5 of FYS2130--Waves and 
% oscillations. Animates a number of different sine and cosinewaves
% according to the real time input of the user. Two different wave numbers,
% angular frequency and the amplitude of the oscillations are also
% adjusted in real time. 
%
% The real time sliders vary the following parameters:
%   * k_1    -- the wave number of the first sine / cosine wave. 
%   * k_2    -- the wave number of the second sine / cosine wave.
%   * omega  -- the angular frequency of all waves.
%   * A      -- the amplitude of all waves. 
%
% The button perform the following tasks:
%   * 'Reset to default values'     -- Resets all values to the default 
%                                      (starting) position / values.
%   * 'Exit'                        -- Exits the program, and closes the
%                                      figure.
%
% Each of the elements of the dropdown menu correpond to different
% combinations of sines and cosines in the waves. Each element is labeled
% by this combination.
%
% Note that we use the function structure in order to keep the program in a
% single file. This is because MATLAB does not allow definitions of 
% functions in .m script files, but it does allow for the use of local
% nested functions within the declarations of other functions.


%% Define some functions for later use
% Function called when user changes the value of the drop down menu.
function setFunc(hObj, val)
        % Called when user activates popup menu 
        val = get(hObj,'Value');
        if val ==1
            f = 1;
        elseif val == 2
            f = 2;
        elseif val == 3
            f = 3;
        elseif val == 4
            f = 4;
        elseif val == 5
            f = 5;
        elseif val == 6
            f = 6;
        elseif val == 7
            f = 7;
    end
end

% Function called when the 'default values' button is used.
function default(hObj, val) 
    t=1;
end

% Function called when the 'exit' button is used. Exits the program.
function exitA(hObj, val)
    exitP = 1;
end


%% Clean up
close all;
clear all;
clc;


%% Numerics & Physics
% Physical parameters.
k1      = 3;        % Wave number 1.
k2      = 3;        % Wave number 2.
omega   = 4;        % Angular frequency.
dt      = 0.01;     % Time step.
A       = 0.75;     % Amplitude of waves.


% Numerics.
pauseL  = 0.015;    % Length of pause between updates of the plot, [s]. 
N       = 4000;     % Length of data arrays.
x       = linspace(0, 20, N);     % Position data, x-direction.
y       = linspace(0, 20, N);     % Position data, y-direction.


%% Visualize the wave
% Create and set up figure for animation.
hFig = figure(1);

% Set the proper position of the actual plot inside the figure. This is
% done to make room for the dropdown menu, buttons, and sliders.
p1 = axes('OuterPosition', [0.045 0.248 0.939 0.67]);
p  = plot(x, y, 'r-', 'EraseMode', 'xor');

% Hardcode axes to prevent MATLAB from changing them when parameters change
axis([0 20 -2.5 2.5]);


%% Create sliders
% Create a slider object to control k1.
hSlide1 = uicontrol( 'style','slider',...
                    'min',0.1,...
                    'max',10,...
                    'value',k1,...
                    'sliderstep',[.01 0.1],...
                    'units','normalized',...
                    'position',[0.011 0.154 0.75 0.041]);                 

% Create a slider object to control k2.
hSlide2 = uicontrol( 'style','slider',...
                    'min',0.1,...
                    'max',10,...
                    'value',k2,...
                    'sliderstep',[.01 0.1],...
                    'units','normalized',...
                    'position',[0.011 0.112 0.75 0.039]);

% Create a slider object to control omega.
hSlide3 = uicontrol( 'style','slider',...
                    'min',0.1,...
                    'max',20,...
                    'value',omega,...
                    'sliderstep',[.01 0.1],...
                    'units','normalized',...
                    'position',[0.011 0.067 0.75 0.04]);
                
% Create a slider object to control A.
hSlide4 = uicontrol( 'style','slider',...
                    'min',-3,...
                    'max',3,...
                    'value',A,...
                    'sliderstep',[.01 0.1],...
                    'units','normalized',...
                    'position',[0.011 0.021 0.75 0.041]);
                
% Create labels for each slider. The labels also indicate the current value
% of the variable which is adjusted by it. This value is updated in real
% time.
k1text = uicontrol('Style','text',...
        'units', 'normalized',...
        'Position',[0.771 0.155 0.22 0.036],...
        'String','k1');
k2text = uicontrol('Style','text',...
        'units', 'normalized',...
        'Position',[0.771 0.109 0.22 0.036],...
        'String','k2');
wtext = uicontrol('Style','text',...
        'units', 'normalized',...
        'Position',[0.771 0.07 0.22 0.036],...
        'String','w');
Atext = uicontrol('Style','text',...
        'units', 'normalized',...
        'Position',[0.771 0.025 0.22 0.036],...
        'String','A');    

    
%% Create dropdown menus
% Labels each element of the menu.
ddm1 = 'Asin(k1x-wt)|';
ddm2 = 'Asin(k1x-wt)+Asin(k2x+wt)|';
ddm3 = 'Asin(k1x-wt)+Asin(k2x+wt)+Acos(k1x-wt)|';
ddm4 = 'Asin(k1x-wt)+Asin(k2x+wt)+Acos(k1x-wt)+Acos(k2x+wt)|';
ddm5 = 'Asin(k1x-wt) Asin(k2x+wt)|';
ddm6 = 'Asin(k1x-wt) Asin(k2x+wt)+Acos(k1x-wt)|';
ddm7 = 'Asin(k1x-wt) Asin(k2x+wt)+Acos(k1x-wt)Acos(k2x+wt)';
dropDownMenuString = [ddm1 ddm2 ddm3 ddm4 ddm5 ddm6 ddm7];

% Creates the actual slider.
uicontrol('Style', 'popup',...
           'String', dropDownMenuString,... 
           'units', 'normalized',...
           'Position', [0.016 0.881 0.97 0.1],...
           'Callback', @setFunc);     

       
%% Create buttons
% Create a 'reset to default values' button.       
uicontrol('Style', 'pushbutton', 'String', 'Reset to default values',...
        'units', 'normalized',...
        'Position', [0.014 0.205 0.325 0.05],...
        'Callback', @default);

% Create a 'exit program' button.       
uicontrol('Style', 'pushbutton', 'String', 'Exit',...
        'units', 'normalized',...
        'Position', [0.664 0.205 0.325 0.05],...
        'Callback', @exitA);    

    
%% Plotting loop
% Forces MATLAB to show the default figure toolbar (which makes zooming,
% moving the plot around, etc. possible), even though it really doesnt want 
% to when we are using uicontrol elements in the figure.
set(hFig,'toolbar','figure');

% Define some needed true/false flags.
f     = 1;
t     = 0;
exitP = 0;

% Starts off the counter showing what total step we are currently at.
i     = 0;

% The actual animation loop. This exits if hFig's current character is 'q',
% which means pressing 'q' while the figure is active will exit the
% program.
while true && ~isequal(get(hFig,'currentcharacter'),'q')
    
    % Every time we draw new values of f(x,t), we get the current values of
    % the sliders first.
    
    % Adjust k1 value according to slider 1.
    sliderVal1 = (get(hSlide1,'value'));
    k1 = sliderVal1;
    s = sprintf('k1 = %f',k1);
    set(k1text, 'String', s);
    
    % Adjust k2 value according to slider 2.
    sliderVal2 = (get(hSlide2,'value'));
    k2 = sliderVal2;
    s = sprintf('k2 = %f',k2);
    set(k2text, 'String', s);
        
    % Adjust omega value according to slider 3.
    sliderVal3 = (get(hSlide3,'value'));
    omega = sliderVal3;
    s = sprintf('w = %f',omega);
    set(wtext, 'String', s);
        
    % Adjust A value according to slider 4.
    sliderVal4 = (get(hSlide4,'value'));
    A = sliderVal4;
    s = sprintf('A = %f',A);
    set(Atext, 'String', s);
    
    % The flag t is set 'true' if the 'reset to default' button is pressed.
    % In this case, we set all parameters to their original values. The 
    % sliders are also forced into position accordingly.
    if (t == 1)
        k1      = 3;                k2 = 3;   
        omega   = 4;                dt = 0.01;
        A       = 0.75;   
        set(hSlide1,'value', 3);    set(hSlide2,'value', 3);
        set(hSlide3,'value', 4);    set(hSlide4,'value', 0.75);
        
        % Finally, we set the value of the t flag back to 'false'.
        t      = 0;
    end
    
    
    % The flag exitP is set 'true' if the 'exit' button is pressed. In this
    % case, we break the loop, which closes hFig and exits the program.
    if (exitP == 1)
        break;
    end
    
    % Advances the time, t, and checks which dropdown menu element is
    % currently active. The function corresponding to this element is then
    % computed.
    t = t + dt;
    if f == 1
        y = A * sin(k1 * x - omega * t);
    elseif f == 2
        y = A * sin(k1 * x - omega * t) + A * sin(k2 * x + omega * t);
    elseif f == 3
        y = A * sin(k1 * x - omega * t) + A * sin(k2 * x + omega * t) + ...
            A * cos(k1 * x - omega * t);
    elseif f == 4
        y = A * sin(k1 * x - omega * t) + A * sin(k2 * x + omega * t) + ...
            A * cos(k1 * x + omega * t) + A * cos(k2 * x - omega * t);
    elseif f == 5
        y = A * sin(k1 * x - omega * t) .* A .* sin(k2 * x - omega * t);
    elseif f == 6
        y = A * sin(k1 * x - omega * t) .* A .* sin(k2 * x - omega * t) +...
            A * cos(k1 * x - omega * t);
    elseif f == 7
        y = A * sin(k1 * x - omega * t) .* A .* sin(k2 * x - omega * t) +...
            A * cos(k1 * x - omega * t) .* A .* cos(k2 * x + omega * t);
    end
    
    % The actual drawing of new values in the hFig plot happens here. A
    % small pause of length pauseL is added between each update of the plot
    % in order to make it more visually appealing.
    set(p, 'XData', x, 'YData', y);
    drawnow;
    pause(pauseL);
    
    % And, finally, advance the counter i.
    i = i + 1;
end

% Close figure after exiting the loop using keyboard input 'q'.
close all;

% Program run successfully, return.
return;

end
