Code covered by the BSD License  

Highlights from
Fireworks GUI

image thumbnail

Fireworks GUI

by

 

30 Dec 2010 (Updated )

Enjoy some fireworks (with sound) with this interactive GUI

Editor's Notes:

This file was selected as MATLAB Central Pick of the Week

FireworksAxes
classdef FireworksAxes < handle
    % FireworksAxes  Prepares axes for fireworks dispaly
    %
    % This class prepares an axes for displaying fireworks (Fireworks
    % objects).
    %
    % FireworksAxes Properties:
    %   AxH               - Handle of the axes
    %   SoundMode         - Toggle option for sounds
    %   XLim              - X limits of the GUI (read-only)
    %   XLim80            - Middle 80% of the X limits of the GUI (read-only)
    %   isFireworksEmpty  - Boolean indicating the existence of fireworks
    %
    % FireworksAxes Methods:
    %   FireworksAxes     - Constructor
    %   newFireworks      - Create and launch new fireworks
    %
    % FireworksAxes Events:
    %   FireworksEmpty    - Occurs when all fireworks have finished
    %   FireworksNotEmpty - Occurs when fireworks have been added to an empty queue
    %
    % See also FireworksAxes, FireworksAxes.newFireworks.
    %
    % For more info, <a href="matlab:doc('FireworksAxes')">doc FireworksAxes</a>

    % Author: Jiro Doke
    % Date: August 01, 2012
    % Copyright 2010-2012 The MathWorks, Inc.

    properties (SetAccess = protected)
        % AxH   Handle of the axes
        AxH
    end
    
    properties
        % SoundMode   Turn on and off sounds
        %   true/false. Default is true. This toggles the fireworks sounds in the
        %   GUI.
        %
        %   SoundMode is disabled (false) on MATLAB R2011a because of compatibility
        %   reasons.
        SoundMode = true
    end
    
    properties (SetAccess = protected, Hidden)
        FireworksTimer
        AllFireworks
    end
    
    properties (Dependent, SetAccess = protected)
        % XLim    X limits of the GUI (read-only)
        %   This read-only property returns the x limits of the axes. This can be
        %   useful for programmatically determining the placement of the fireworks
        %   launch position.
        XLim
        
        % XLim80    Middle 80% of the X limits of the GUI (read-only)
        %   This read-only property returns the middle 80% of the x limits of the
        %   axes. This can be useful for programmatically determining the placement
        %   of the fireworks launch position.
        XLim80
        
        % isFireworksEmpty    Boolean indicating the existence of fireworks
        %   This read-only property returns true if there is any fireworks
        %   currently in the axes. It returns false if there isn't any.
        isFireworksEmpty
    end
    
    events
        % FireworksEmpty    Notified when there are no more fireworks
        FireworksEmpty
        
        % FireworksNotEmpty    Notified when fireworks have been added
        FireworksNotEmpty
    end
    
    methods
        function obj = FireworksAxes(axH)
            % FireworksAxes   Prepares axes for fireworks dispaly
            %   FWOBJ = FireworksAxes(AX)
            %
            %   This makes the axes with handle AX ready for displaying fireworks. It
            %   sets the axes color black, y-limits 0 to 3000, aspect ratio 1 to 1, and
            %   x-limits appropriately set to honor y-limits and the aspect ratio.
            %
            %   Once constructed, use the object to create new fireworks.
            %
            % Example:
            %   f = FireworksAxes(gca);
            %   f.newFireworks(10);
            %
            % See also FireworksAxes, FireworksAxes.newFireworks.
            
            if nargin == 0
                axH = gca;
            else
                assert(ishandle(axH) && strcmpi(get(axH, 'Type'), 'axes') ...
                    && isscalar(axH), ...
                    'FireworksAxes:Constructor:InvalidAxesHandle', ...
                    'Invalid axes handle');
            end
            obj.AxH = axH;
            
            if isempty(getappdata(axH, 'ReadyForFireworks'))
                oldUnits = get(axH, 'Units');
                set(axH, 'Units', 'pixels');
                pos = get(axH, 'Position');
                set(axH, ...
                    'Color', 'black', ...
                    'DeleteFcn', @obj.axesDeleteFcn, ...
                    'Units', oldUnits, ...
                    'YLim', [0 3000], ...
                    'XTick', [], ...
                    'YTick', [], ...
                    'Box', 'on', ...
                    'DataAspectRatio', [1 1 1], ...
                    'PlotBoxAspectRatio', [1 pos(4)/pos(3) 1]);
                set(axH, 'XLim', get(axH, 'XLim'));
                
                setappdata(axH, 'ReadyForFireworks', true)
            end
            
            obj.FireworksTimer = timer(...
                'Name', 'FireworksTimer', ...
                'ExecutionMode', 'FixedSpacing', ...
                'Period', 0.015, ...
                'TimerFcn', @obj.stepFireworks, ...
                'ObjectVisibility', 'off', ...
                'Tag', 'fireworks_timers');
            
            if verLessThan('matlab', '7.12') || ~verLessThan('matlab', '7.13')
                obj.SoundMode = true;
            else
                obj.SoundMode = false;
            end
            
        end
        
        function newFireworks(obj, varargin)
            % newFireworks   Create and launch new fireworks
            %   obj.newFireworks() launches a single fireworks with random properties.
            %
            %   obj.newFireworks(NUM) launches NUM fireworks with random properties.
            %
            %   obj.newFireworks(PROP1, VAL1, PROP2, VAL2, ...)
            %   obj.newFireworks(NUM,  PROP1, VAL1, PROP2, VAL2, ...)
            %       Pass in additional Property-Value pairs to fix those values.
            %       Properties not specified will be randomly set.
            %
            %   Valid Properties:
            %       FireworksType - Type of fireworks
            %           String value that specifies the type of fireworks. To see a
            %           complete list of valid types, type
            %               <a href="matlab:FireworksAxes.ValidFireworksType">FireworksAxes.ValidFireworksType</a>
            %           'plain' and 'glitter' are the standard-looking fireworks, and
            %           one of the two is selected by default.
            %
            %       NumPetals - Number of petals after explosion
            %           A scalar number indicating the number of spreading lines
            %           (petals) after the explosion at the top. The default is an
            %           integer randomly selected between 8 and 12.
            %
            %       LaunchPos - Horizontal launch location
            %           A scalar number indicating the horizontal location of the
            %           launch. Default is a random value within the x limits of the
            %           axes.
            %
            %       LaunchVel - Launch velocity (horizontal and vertical)
            %           A two-element row vector indicating the horizontal and vertical
            %           velocity. Default is a pair of random values within a specific
            %           range.
            %
            %       SpeedFactor - Speed of the fireworks
            %           A scalar number indicating the speed factor. The value must be
            %           between 0.5 and 1.25. A small value corresponds to faster
            %           flight. Default is a random value between 0.5 and 1.25.
            %
            %       ThinLines - Whether the fireworks are displayed with thin lines
            %           true/false. Default is false. This indicates whether to draw
            %           the fireworks with thin lines or not. Typically, this should be
            %           false. If you're displaying this in a very small axes, you may
            %           want to set this to true.
            %
            %       FinishedFcn - Callback that gets called after fireworks completion
            %           A function handle to a callback function that gets called after
            %           the fireworks has completed. The callback should not take any
            %           input arguments and produce no output arguments.
            %
            % Example:
            %   f = FireworksAxes(gca);
            %
            %   % launch 10 random fireworks
            %   f.newFireworks(10);
            %
            %   % launch 10 fireworks shooting from the origin
            %   f.newFireworks(10, 'LaunchPos', 0);
            %
            %   % launch 5 works with MATLAB logo
            %   f.newFireworks(5, 'FireworksType', 'matlab')
            %
            %   % launch 10 fireworks and display completion time after each fireworks
            %   f.newFireworks(10, 'FinishedFcn', @() disp(datestr(now, 'HH:MM:SS.FFF')));
            %
            % See also FireworksAxes, FireworksAxes.FireworksAxes,
            
            % If the first input is a number, it could be the number of fireworks.
            if nargin > 1 && isnumeric(varargin{1})
                validateattributes(varargin{1}, {'numeric'}, ...
                    {'scalar', 'integer', 'positive'}, mfilename, 'NumFireworks');
                assert(varargin{1} <= 20, ...
                    'FireworksAxes:newFireworks:TooManyFireworks', ...
                    'You can only create up to 20 fireworks at a time.');
                numF = varargin{1};
                varargin(1) = '';
            else
                numF = 1;
            end
            
            fw = cell(1, numF);
            for id = 1:numF
                %fw{id} = helper.createFireworks(obj, varargin{:}, 'ThinLines', true);
                fw{id} = helper.createFireworks(obj, varargin{:});
                
                % Overwrite Fireworks HaveSound property with the object's SoundMode
                % property
                fw{id}.HaveSound = obj.SoundMode;
            end

                        
            if obj.isFireworksEmpty
                obj.AllFireworks = fw;
                
                % broadcast the "FireworksNotEmpty" event.
                notify(obj, 'FireworksNotEmpty');
            else
                obj.AllFireworks = [obj.AllFireworks, fw];
            end
            
            % Just added fireworks, so in case the animation timer is not running,
            % start it
            if strcmpi(obj.FireworksTimer.Running, 'off')
                start(obj.FireworksTimer);
            end
        end
                
        function val = get.XLim(obj)
            val = xlim(obj.AxH);
        end
        
        function val = get.XLim80(obj)
            val = obj.XLim*0.8;
        end
        
        function val = get.isFireworksEmpty(obj)
            val = isempty(obj.AllFireworks);
        end
        
        function set.SoundMode(obj, val)
            validateattributes(val, {'logical'}, {'scalar'}, mfilename, ...
                'SoundMode');
            
            if ~verLessThan('matlab', '7.12') && verLessThan('matlab', '7.13')
                if val == true
                    disp('Sound is disabled on MATLAB R2011a for compatibility reasons');
                    val = false;
                end
            end
            obj.SoundMode = val;

            changeSoundMode(obj)
        end
        
    end
    
    methods (Hidden)
        function delete(obj)
            warning('off', 'MATLAB:class:DestructorError');
            
            %disp('1')
            
            if isvalid(obj.FireworksTimer)
                stop(obj.FireworksTimer);
                
                %disp('3')
                
                while strcmpi(obj.FireworksTimer.Running, 'on'), drawnow; end;
                
                %disp('4')
                
                delete(obj.FireworksTimer);
            end
            
            %disp('2')
            
            while ~isempty(obj.AllFireworks)
                if isvalid(obj.AllFireworks{1})
                    delete(obj.AllFireworks{1});
                end
                obj.AllFireworks(1) = '';
            end
            
            %disp('5')
            
            delete@handle(obj);

            warning('on', 'MATLAB:class:DestructorError');
        end
    end
    
    methods (Access = protected, Hidden)
        function axesDeleteFcn(obj, varargin)
            delete(obj);
        end
        
        function stepFireworks(obj, varargin)
            s = true(size(obj.AllFireworks));
            for id = 1:length(s)
                s(id) = step(obj.AllFireworks{id});
            end
            obj.AllFireworks(~s) = '';
            
            % If there are no fireworks, stop the animation timer and
            % broadcast the "FireworksEmpty" event.
            if obj.isFireworksEmpty
                stop(obj.FireworksTimer);
                notify(obj, 'FireworksEmpty');
            end
        end
        
        function changeSoundMode(obj)
            if ~obj.isFireworksEmpty
                for id = 1:length(obj.AllFireworks)
                    obj.AllFireworks{id}.HaveSound = obj.SoundMode;
                end
            end
        end
    end
    
    methods (Static)
        function list = ValidFireworksType()
            list = helper.Fireworks.ValidFireworksType;
        end
    end
    
    %% Hidden Methods (overloading handle methods)
    methods (Hidden)
        
        function out = addlistener(varargin)
            out = addlistener@handle(varargin{:});
        end
        
        function notify(varargin)
            notify@handle(varargin{:})
        end
        
        function out = eq(varargin)
            out = eq@handle(varargin{:});
        end
        
        function out = ge(varargin)
            out = ge@handle(varargin{:});
        end
        
        function out = gt(varargin)
            out = gt@handle(varargin{:});
        end
        
        function out = le(varargin)
            out = le@handle(varargin{:});
        end
        
        function out = lt(varargin)
            out = lt@handle(varargin{:});
        end
        
        function out = ne(varargin)
            out = ne@handle(varargin{:});
        end
        
        function out = findprop(varargin)
            out = findprop@handle(varargin{:});
        end
        
        function findobj(varargin)
            findobj@handle(varargin{:});
        end
        
    end
    
end

Contact us