Canvas_2D class

This is a sub-class of the Canvas class, to deal especifically with axes that present only 2D behavior.

Contents

Authors

History

@version 1.00

Initial version: September 2020

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

Class definition

classdef Canvas_2D < Canvas

Constructor method

    methods
        function this = Canvas_2D(ax,fig,fcn)
            if (nargin == 0)
                ax  = [];
                fig = [];
                fcn = [];
            elseif (nargin <= 2)
                fcn = [];
            end
            this = this@Canvas(ax,fig,fcn);
        end
    end

Public methods

Implementation of the abstract methods declared in super-class Canvas.

    methods
        %------------------------------------------------------------------
        % Fits axis limits to display everything drawn on canvas
        function fit2view(this,bBox)
            % Set axes units to pixels
            dfltUnits = get(this.ax, 'Units');
            set(this.ax, 'Units', 'pixels');

            % Compute canvas height/width ratio
            h_w = this.ax.Position(4)/this.ax.Position(3);

            % Set axes units back to what they were
            set(this.ax, 'Units', dfltUnits);

            % Check if a bounding box was already provided
            if (nargin == 2)
                if ~isempty(bBox)
                    % Get x and y vectors
                    x = [bBox(1),bBox(3)];
                    xmin = min(x);
                    xmax = max(x);
                    y = [bBox(2),bBox(4)];
                    ymin = min(y);
                    ymax = max(y);

                    % Compute window sizes based on model bounding box size
                    % increased by current free border factor.
                    % Place window center at model bounding box center pos.
                    %%%%% COMPLETE HERE - CANVAS_2D: 01 %%%%%
                    Lx = (xmax - xmin) * (1.0 + this.freeBorder);
                    Mx = (xmax + xmin) * 0.5;
                    Ly = (ymax - ymin) * (1.0 + this.freeBorder);
                    My = (ymax + ymin) * 0.5;
                    %%%%% COMPLETE HERE - CANVAS_2D: 01 %%%%%
                    y_x = Ly / Lx;

                    % If axIsEq, make sure bound box fits while respecting
                    % proportional limits
                    if this.axIsEq
                    %%%%% COMPLETE HERE - CANVAS_2D: 02 %%%%%
                        if y_x > h_w
                            Lx = Ly / h_w;
                        else
                            Ly = Lx * h_w;
                        end
                    %%%%% COMPLETE HERE - CANVAS_2D: 02 %%%%%
                    end

                    % Set limits and return
                    %%%%% COMPLETE HERE - CANVAS_2D: 03 %%%%%
                    xmin = Mx - (Lx * 0.5);
                    xmax = Mx + (Lx * 0.5);
                    ymin = My - (Ly * 0.5);
                    ymax = My + (Ly * 0.5);
                    %%%%% COMPLETE HERE - CANVAS_2D: 03 %%%%%

                    this.ax.XLim = [xmin,xmax];
                    this.ax.YLim = [ymin,ymax];

                    % Set flag to indicate that bounding box was provided
                    this.bBoxWasSet = true;
                    return;
                end
            end

            % Get list of handles to graphic objects drawn on this.ax
            plots = this.ax.Children;

            % If there is nothing drawn on this.ax, return
            if isempty(plots)
                if ~this.axIsEq
                    this.ax.XLim = [-5,5];
                    this.ax.YLim = [-5,5];
                elseif h_w > 1
                    this.ax.XLim = [-5,5];
                    this.ax.YLim = [-5*h_w,5*h_w];
                else
                    this.ax.XLim = [-5/h_w,5/h_w];
                    this.ax.YLim = [-5,5];
                end
                return
            end

            % Get maximum and minimum coordinates
            if ~strcmp(plots(1).Type,'text')
                xmax = max(plots(1).XData);
                xmin = min(plots(1).XData);
                ymax = max(plots(1).YData);
                ymin = min(plots(1).YData);
            else
                xmax = max(plots(1).Position(1));
                xmin = min(plots(1).Position(1));
                ymax = max(plots(1).Position(2));
                ymin = min(plots(1).Position(2));
            end

            for i = 2:length(plots)
                if ~strcmp(plots(i).Type,'text')
                    xmax = max([xmax,max(plots(i).XData)]);
                    xmin = min([xmin,min(plots(i).XData)]);
                    ymax = max([ymax,max(plots(i).YData)]);
                    ymin = min([ymin,min(plots(i).YData)]);
                else
                    xmax = max([xmax,max(plots(i).Position(1))]);
                    xmin = min([xmin,min(plots(i).Position(1))]);
                    ymax = max([ymax,max(plots(i).Position(2))]);
                    ymin = min([ymin,min(plots(i).Position(2))]);
                end
            end

            % Compute window sizes based on model bounding box size
            % increased by current free border factor.
            % Place window center at model bounding box center position
            %%%%% COMPLETE HERE - CANVAS_2D: 01 (REPEAT CANVAS_2D: 01 ABOVE %%%%%
            Lx = (xmax - xmin) * (1.0 + this.freeBorder);
            Mx = (xmax + xmin) * 0.5;

            Ly = (ymax - ymin) * (1.0 + this.freeBorder);
            My = (ymax + ymin) * 0.5;
            %%%%% COMPLETE HERE - CANVAS_2D: 01 (REPEAT CANVAS_2D: 01 ABOVE %%%%%

            y_x = Ly/Lx;

            % Adjust window limits such that window rectangle has same
            % aspect ratio of viewport rectangle
            if this.axIsEq
            %%%%% COMPLETE HERE - CANVAS_2D: 02 (REPEAT CANVAS_2D: 02 ABOVE) %%%%%
                if y_x > h_w
                    Lx = Ly / h_w;
                else
                    Ly = Lx * h_w;
                end
            %%%%% COMPLETE HERE - CANVAS_2D: 02 (REPEAT CANVAS_2D: 02 ABOVE) %%%%%
            end

            % Compute adjusted window limits
            %%%%% COMPLETE HERE - CANVAS_2D: 03 (REPEAT CANVAS_2D: 03 ABOVE) %%%%%
            xmin = Mx - (Lx * 0.5);
            xmax = Mx + (Lx * 0.5);

            ymin = My - (Ly * 0.5);
            ymax = My + (Ly * 0.5);
            %%%%% COMPLETE HERE - CANVAS_2D: 03 (REPEAT CANVAS_2D: 03 ABOVE) %%%%%

            this.ax.XLim = [xmin,xmax];
            this.ax.YLim = [ymin,ymax];

            % Set flag to indicate that bounding box was provided
            this.bBoxWasSet = true;
        end
        %------------------------------------------------------------------
        % Mouse button down callback - related to axes object
        % Input:
        % * this  = handle to this canvas object
        % * obj   = handle to axes associated to canvas
        % * event = struct with event data
        function ax_onButtonDown(~,~,~)
        end

        %------------------------------------------------------------------
        % Mouse button down callback - generic callback, called from an
        % Emouse object.
        % Input:
        % * this  = handle to this canvas object
        % * pt    = current cursor coordinates
        % * whichMouseButton = 'left', 'right', 'center', 'double click'
        function onButtonDown(~,~,~)
        end

        %------------------------------------------------------------------
        % Mouse button up callback - generic callback, called from an
        % Emouse object.
        % Input:
        % * this  = handle to this canvas object
        % * pt    = current cursor coordinates
        % * whichMouseButton = 'left', 'right', 'center', 'double click'
        function onButtonUp(~,~,~)
        end

        %------------------------------------------------------------------
        % Mouse move callback - generic callback, called from an
        % Emouse object.
        % Input:
        % * this  = handle to this canvas object
        % * pt    = current cursor coordinates
        function onMouseMove(~,~)
        end

        %------------------------------------------------------------------
        % Mouse scroll callback - generic callback, called from an
        % Emouse object.
        % Input:
        % * this  = handle to this canvas object
        % * pt    = current cursor coordinates
        function onMouseScroll(~,~)
        end
    end
end