Canvas_2D class
This is a sub-class of the Canvas class, to deal especifically with axes that present only 2D behavior.
Contents
Authors
- Pedro Cortez F Lopes (pedrocortez@id.uff.br)
- Rafael Lopez Rangel (rafaelrangel@tecgraf.puc-rio.br)
- Luiz Fernando Martha (lfm@tecgraf.puc-rio.br)
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