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.01

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.

Version 1.01: October 2026 (LFMartha)

Method fit2view computes the canvas height/width ratio from the axes InnerPosition (plot box) instead of Position. For uiaxes, Position includes the margins reserved for labels, so the ratio was larger than the plot box ratio and, with equal axes, the drawing did not occupy the whole canvas width.

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 from plot box (inner
            % position, which excludes margins reserved for labels)
            if isprop(this.ax,'InnerPosition')
                pos = this.ax.InnerPosition;
            else
                pos = this.ax.Position;
            end
            h_w = pos(4)/pos(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 %%%%%
                    %%%%% 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 %%%%%
                    %%%%% COMPLETE HERE - CANVAS_2D: 02 %%%%%
                    end

                    % Set limits and return
                    %%%%% COMPLETE HERE - CANVAS_2D: 03 %%%%%
                    %%%%% 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 %%%%%
            %%%%% 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) %%%%%
            %%%%% 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) %%%%%
            %%%%% 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