CrossControl class

This class implements methods to control the analysis of continuous beams by the Cross process.

Contents

Author

Luiz Fernando Martha

History

@version 1.03

Initial version (1.00): September 2026

Initially prepared for version Cross01 application of course CIV 2801 - Fundamentos de Computação Gráfica, 2026, second term, Department of Civil Engineering, PUC-Rio.

Version 1.01: September 2026

Added model canvas and display of continuous beam model. The following private properties were added: draw and canvas_model. The following private method was added: updateDraw. The following public method was added: resizeCanvas.

Version 1.02: October 2026 Implementation of drawing of deformed configuration and bending moment diagram. The following private properties were added: canvas_deformed and canvas_moment.

Version 1.03: October 2026 Implementation of methods that treat mouse events for insertion of an internal support, deletion of an internal support, balancing of the bending moment at a selected internal node, modification of the value of a uniform load of a member, and modification of the position of a node. The following private properties were added: mouse_events, inserting_sup, deleting_sup, changing_load, and moving_sup. The following private methods were implemented: insertSup and deleteSup. The following public methods were implemented: insertSupMode, deleteSupMode, setMousePointer, onButtonDown, onButtonUp, and onMouseMove.

Class definition

classdef CrossControl < handle

Public properties

    properties (Access = public)
        solver = []; % handle to Cross solver object
    end

Private properties

    properties (Access = private)
        app = []; % handle to GUI app object
        draw = []; % handle to CrossDraw object
        canvas_model = []; % handle to model canvas
        canvas_deformed = []; % handle to deformed configuration canvas
        canvas_moment = []; % handle to bending moment canvas
        mouse_events = []; % handle to mouse events object
        inserting_sup = false; % flag for inserting support mode
        deleting_sup = false; % flag for deleting support mode
        changing_load = false; % flag for changing load mode
        moving_sup = false; % flag for moving support
    end

Constructor method

    methods
        %------------------------------------------------------------------
        function control = CrossControl(app)
            if (nargin > 0)
                control.app = app;
            end
        end
    end

Private methods

    methods (Access = private)
        %------------------------------------------------------------------
        % Update Cross draw object
        function updateDraw(control)
            % Create cross draw object passing solver object to it.
            crossdraw = CrossDraw(control.solver);
            control.draw = crossdraw;

            % Provide handle to functions that updates display of all canvas
            control.canvas_model.setUpdateFcn(@crossdraw.model);
            control.canvas_deformed.setUpdateFcn(@crossdraw.deformedConfig);
            control.canvas_moment.setUpdateFcn(@crossdraw.bendingMomDiagram);

            % Provide handle to function that returns model bounding box for all canvas
            control.canvas_model.setBoundBoxFcn(@crossdraw.crossBoundBox);
            control.canvas_deformed.setBoundBoxFcn(@crossdraw.crossBoundBox);
            control.canvas_moment.setBoundBoxFcn(@crossdraw.crossBoundBox);
        end

        %------------------------------------------------------------------
        % Reset Cross solver
        function resetSolver(control,nmemb,supinit,supend,decplc,EI,len,q)
            % Clean current Cross model if it exists
            if ~isempty(control.solver)
                control.solver.clean();
            end

            % Create new Cross solver model and initialize it
            if (nargin == 1)
                control.solver = CrossSolver();
            else
                control.solver = CrossSolver(nmemb,supinit,supend,decplc,EI,len,q);
            end
            control.solver.initStiffness();
            control.solver.initNodes();
            control.solver.initMoments();

            % Update cross draw object
            control.updateDraw();

            % Update init and end support icons
            control.app.updateSupInit(control.solver.supinit);
            control.app.updateSupEnd(control.solver.supend);

            % Update display of canvases
            control.canvas_model.update();
            control.canvas_deformed.update();
            control.canvas_moment.update();

            % Print model data and initial bending moments
            control.solver.printModelInfo(1);
            control.solver.printResults(1);
        end

        %------------------------------------------------------------------
        % Insert an internal support in the continuous beam model.
        % It is assumed that the given support position an is valid.
        % Input:
        % m: member index in which internal support is inserted
        % pos: position of inserted support inside member
        function insertSup(control,m,pos)
%%%%%%% COMPLETE HERE - CROSS_CONTROL: 10 %%%%%%%
        end

        %------------------------------------------------------------------
        % Delete an internal support from the continuous beam model.
        % If there is only one interior support, it will not be deleted.
        % Input:
        % n: index of internal support to delete (from 1 to nnode)
        function deleteSup(control,n)
            if control.solver.nnode == 1
                return
            end

%%%%%%% COMPLETE HERE - CROSS_CONTROL: 11 %%%%%%%
        end
    end

Public methods

    methods
        %------------------------------------------------------------------
        % Start up Cross program. Create a Cross solver object with a
        % default continous beam model. Initialize Cross parameters and
        % beam spans with bending fixed-end  moments. Print model
        % and initial results.
        % Create model canvas, deformed configuration canvas, and
        % bending moment canvas.
        function startup(control,fig_app,ax_model,ax_deformed,ax_moment)
            % Create model canvas
            control.canvas_model = CanvasCross(ax_model,fig_app,[],control);
            control.canvas_model.Ruler( false );
            % Turn off canvas visualization control toolbar
            control.canvas_model.getContext().Toolbar.Visible = 'off';
            % Disable interactive canvas functionalities
            control.canvas_model.getContext().Interactions = [];

            % Create deformed configuration canvas
            control.canvas_deformed = CanvasCross(ax_deformed,fig_app,[],control);
            control.canvas_deformed.Ruler( false );
            % Turn off canvas visualization control toolbar
            control.canvas_deformed.getContext().Toolbar.Visible = 'off';
            % Disable interactive canvas functionalities
            control.canvas_deformed.getContext().Interactions = [];

            % Create bending moment canvas
            control.canvas_moment = CanvasCross(ax_moment,fig_app,[],control);
            control.canvas_moment.Ruler( false );
            % Turn off canvas visualization control toolbar
            control.canvas_moment.getContext().Toolbar.Visible = 'off';
            % Disable interactive canvas functionalities
            control.canvas_moment.getContext().Interactions = [];

            % Create default Cross solver object
            control.resetSolver();

            % Initialize object to manage mouse events
            control.mouse_events = MouseEvents(fig_app,control.canvas_model);
        end

        %------------------------------------------------------------------
        % Resize canvas: called when axes graphical component is resized.
        function resizeCanvas(~,ax)
            if isprop(ax,'canvas')
                if ~isempty(ax.canvas)
                    ax.canvas.fit2view();
                    ax.canvas.update();
                end
            end
        end

        %------------------------------------------------------------------
        % Open file with continuous beam model for Cross process analysis.
        function openFile(control,filename)
            % Open file with given file name for reading
            fid = fopen(filename,'rt');

            % Read moment precision (number of decimal places)
            decplc = fscanf(fid,'%f',1);
            if decplc < 0 || decplc > 2
                decplc = 1;
            end

            % Read support boundary conditions
            bdrycnd = fscanf(fid,'%f',2);
            supinit = bdrycnd(1);
            supend = bdrycnd(2);

            % Read number of members and dimension arrays
            nmemb = fscanf(fid,'%f',1);
            EI = ones(1,nmemb) * 10000;
            len = zeros(1,nmemb);
            q = zeros(1,nmemb);

            % Read member lengths and uniform load
            for i = 1:nmemb
                membprop = fscanf(fid,'%f',2);
                len(i) = membprop(1);
                q(i) = membprop(2);
            end

            % Create Cross solver object with read data
            control.resetSolver(nmemb,supinit,supend,decplc,EI,len,q);

            % Close file
            fclose(fid);
        end

        %------------------------------------------------------------------
        % Save current continuous beam model for Cross process analysis in
        % a file
        function saveFile(control,filename)
            % Open file with given file name for writing
            fid = fopen(filename,'wt+');

            % Write moment precision (number of decimal places)
            fprintf(fid, '%d\n', control.solver.decplc);

            % Write support boundary conditions
            fprintf(fid, '%d  %d\n', control.solver.supinit, ...
                                     control.solver.supend);

            % Write number of members
            fprintf(fid, '%d\n', control.solver.nmemb);

            % Write member lengths and uniform load
            for i = 1:control.solver.nmemb
                fprintf(fid, '%d  %d\n', control.solver.membs(i).len, ...
                                         control.solver.membs(i).q);
            end

            % Close file
            fclose(fid);
        end

        %------------------------------------------------------------------
        % Restart continous beam Cross analysis.
        % Initialize Cross parameters and beam spans bending with
        % fixed-end moments. Print model and initial bending moment
        % results.
        function restart(control)
            control.solver.printModelInfo(1);
%%%%%%% COMPLETE HERE - CROSS_CONTROL: 01 %%%%%%%
            control.solver.resetNodeRotations();
            control.solver.printResults(1);

            % Update display of result canvases
            control.canvas_deformed.update();
            control.canvas_moment.update();
        end

        %------------------------------------------------------------------
        % Solves one step of Cross Process for continuous beams: solve the
        % node with maximum absolute value of unbalanced moment.
        % Print bending moment resulta after step.
        function autoStep(control)
%%%%%%% COMPLETE HERE - CROSS_CONTROL: 02 %%%%%%%
            control.solver.stepVector(...
                control.solver.numSteps).printStep(1,control.solver.decplc);
            control.solver.printResults(1);

            % Update display of result canvases
            control.canvas_deformed.update();
            control.canvas_moment.update();
        end

        %------------------------------------------------------------------
        % Processes direct solver of Cross Process for continuous beams.
        % Print final bending moment results.
        function goThru(control)
%%%%%%% COMPLETE HERE - CROSS_CONTROL: 03 %%%%%%%
            control.solver.printResults(1);

            % Update display of result canvases
            control.canvas_deformed.update();
            control.canvas_moment.update();
        end

        %------------------------------------------------------------------
        % Set up number of decimal places for iterative Cross Process
        % of continuous beams.
        % Reprint current bending moment results.
        function setPrecision(control,decplc)
%%%%%%% COMPLETE HERE - CROSS_CONTROL: 04 %%%%%%%
            control.solver.printResults(1);

            % Update display of moment canvas
            control.canvas_moment.update();
        end

        %------------------------------------------------------------------
        % Toggle initial beam support condition and restart continous
        % beam Cross analysis.
        function toggleSupInit(control)
%%%%%%% COMPLETE HERE - CROSS_CONTROL: 05 %%%%%%%

            % Update display of canvases
            control.canvas_model.update();
            control.canvas_deformed.update();
            control.canvas_moment.update();
        end

        %------------------------------------------------------------------
        % Toggle end beam support condition and restart continous
        % beam Cross analysis.
        function toggleSupEnd(control)
%%%%%%% COMPLETE HERE - CROSS_CONTROL: 06 %%%%%%%

            % Update display of canvases
            control.canvas_model.update();
            control.canvas_deformed.update();
            control.canvas_moment.update();
        end

        %------------------------------------------------------------------
        % Set insert support mode: either true or false
        function insertSupMode(control,value)
            control.inserting_sup = value;
        end

        %------------------------------------------------------------------
        % Set delete support mode: either true or false
        function deleteSupMode(control,value)
            control.deleting_sup = value;
        end

        %------------------------------------------------------------------
        % Set mouse cursor image according to mouse position
        function setMousePointer(control,cnv,fig,pt)
            if isempty(fig)
                return
            end
            default = true;
            if cnv == control.canvas_moment
                n = control.draw.pickInteriorSup(cnv.getContext(),pt);
                if n > 0
                    if control.solver.isNodeUnbalanced(n)
                        fig.Pointer = 'hand';
                        default = false;
                    end
                end
            elseif control.inserting_sup && cnv == control.canvas_model
                [stat,~,~] = control.draw.pickInsertSup(pt);
                if stat == control.draw.ValidSupInsertion
                    fig.Pointer = 'hand';
                    default = false;
                end
            elseif control.deleting_sup && cnv == control.canvas_model
                [stat,~] = control.draw.pickDeleteSup(pt);
                if stat == control.draw.ValidSupDeletion
                    fig.Pointer = 'hand';
                    default = false;
                end
            elseif cnv == control.canvas_model
                stat = control.draw.pickMemberLoad(cnv.getContext(),pt,false);
                if stat == control.draw.MembLoadFound
                    fig.Pointer = 'top';
                    default = false;
                end
                stat = control.draw.pickSupMove(cnv.getContext(),pt,false);
                if stat == control.draw.SupMoveFound
                    fig.Pointer = 'left';
                    default = false;
                end
            end
            if default == true
                pointer = get(fig,'Pointer');
                if ~strcmp(pointer,'arrow')
                    fig.Pointer = 'arrow';
                end
            end
        end

        %------------------------------------------------------------------
        % Mouse button down callback.
        % Input:
        % * cnv  = handle to this canvas object
        % * pt   = current cursor coordinates
        function onButtonDown(control,cnv,pt)
            if cnv == control.canvas_moment
                % Do nothing: treat event at button up mode
            elseif control.inserting_sup && cnv == control.canvas_model
                % Do nothing: treat event at button up mode
            elseif control.deleting_sup && cnv == control.canvas_model
                % Do nothing: treat event at button up mode
            elseif cnv == control.canvas_model
                stat = control.draw.pickMemberLoad(cnv.getContext(),pt,true);
                if stat == control.draw.MembLoadFound
                    control.changing_load = true;
                    control.moving_sup = false;
                    return
                end
                stat = control.draw.pickSupMove(cnv.getContext(),pt,true);
                if stat == control.draw.SupMoveFound
                    control.changing_load = false;
                    control.moving_sup = true;
                    return
                end
            end
        end

        %------------------------------------------------------------------
        % Mouse button up callback.
        % Input:
        % * cnv  = handle to this canvas object
        % * pt   = current cursor coordinates
        function onButtonUp(control,cnv,pt)
            if cnv == control.canvas_moment
%%%%%%% COMPLETE HERE - CROSS_CONTROL: 07 %%%%%%%
            elseif control.inserting_sup && cnv == control.canvas_model
                [stat,m,pos] = control.draw.pickInsertSup(pt);
                if stat == control.draw.ValidSupInsertion
                    control.insertSup(m,pos);
                    control.app.updateTextMessage();
                elseif stat == control.draw.BeamLineNotFound
                    control.app.setTextMessage('Internal support should be on the beam line.');
                elseif stat == control.draw.SupInsertionNotValid
                    control.app.setTextMessage('Internal support cannot be close to other support.');
                end
                control.app.resetInsertSup();
            elseif control.deleting_sup && cnv == control.canvas_model
                [stat,n] = control.draw.pickDeleteSup(pt);
                if stat == control.draw.ValidSupDeletion
                    control.deleteSup(n);
                    control.app.updateTextMessage();
                elseif stat == control.draw.SupDelMinNumSup
                    control.app.setTextMessage('Single interior support cannot be deleted.');
                elseif stat == control.draw.SupDelNotFound
                    control.app.setTextMessage('No interior support was found.');
                end
                control.app.resetDeleteSup();
            elseif cnv == control.canvas_model
                if control.changing_load
                    [m,q] = control.draw.setMemberLoad(cnv.getContext(),pt);
                    if m > 0
%%%%%%% COMPLETE HERE - CROSS_CONTROL: 08 %%%%%%%
                    end
                    control.changing_load = false;
                    return
                end
                if control.moving_sup
                    [n,shift] = control.draw.setSupMove(cnv.getContext(),pt);
                    if (n > 0) && (abs(shift) > 0)
%%%%%%% COMPLETE HERE - CROSS_CONTROL: 09 %%%%%%%
                    end
                    control.moving_sup = false;
                    return
                end
            end
        end

        %------------------------------------------------------------------
        % Mouse move callback - generic callback, called from an
        % Emouse object.
        % Input:
        % * cnv  = handle to this canvas object
        % * pt   = current cursor coordinates
        function onMouseMove(control,cnv,pt)
            if cnv == control.canvas_moment
                % Do nothing: treat event at button up mode
            elseif control.inserting_sup && cnv == control.canvas_model
                % Do nothing: treat event at button up mode
            elseif control.deleting_sup && cnv == control.canvas_model
                % Do nothing: treat event at button up mode
            elseif cnv == control.canvas_model
                if control.changing_load
                    control.draw.updateMemberLoad(cnv.getContext(),pt);
                    return
                end
                if control.moving_sup
                    control.draw.updateSupMove(cnv.getContext(),pt);
                    return
                end
            end
        end
    end
end