CrossDraw class
This class implements methods to plot graphical results from the Cross process of continuous beams.
Contents
Author
Luiz Fernando Martha
History
@version 1.02
Initial version (1.00): September 2026
Initially prepared for version Cross02 application of course CIV 2801 - Fundamentos de Computação Gráfica, 2026, second term, Department of Civil Engineering, PUC-Rio. Created model canvas and display of continuous beam model.
Version 1.01: October 2026
Implementation of display of deformed configuration canvas and bending moment diagram canvas. The following constant properties were added: maxbendmomsize_fac, spanmomlineshift_fac, inflectpt_fac, and rotmeter_fac. The following static methods were added: disk and rotationMeter. The following public methods were added: deformedConfig and bendingMomDiagram.
Version 1.02: October 2026
Implementation of a methods for picking (selecting by mouse position) and drawing 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 constant properties were added: picktol_fac, minmemblen_fac, ValidSupInsertion, BeamLineNotFound, SupInsertionNotValid, SupDelMinNumSup, ValidSupDeletion, SupDelNotFound, MembLoadFound, MembLoadNotFound, SupMoveFound, and SupMoveNotFound. The following private properties were added: pickmember, picksup, orig_suppos, and hnd_draft. The following protected methods were added: draftMemberLoad, draftDimLine, getSupShift, and draftSupMove. The following public methods were added: pickInteriorSup, pickInsertSup, pickDeleteSup, pickMemberLoad, updateMemberLoad, setMemberLoad, pickSupMove, updateSupMove, and setSupMove.
Version 1.03: October 2026
Fixed method pickInteriorSup: it was returning a wrong interior node index in case the mouse position was at the beam right end.
Class definition
classdef CrossDraw < handle
Public properties
properties
solver = []; % handle to an object of the CrossSolver class
end
Class (constant) properties
properties (Constant)
supsize_fac = 0.02; % factor for support size
loadsize_fac = 0.70; % factor for maximum load size in relation to
% half vertical window size
minloadsize_fac = 0.012 % factor for minimum load size
arrowsize_fac = 0.01; % factor for load arrow size
loadstep_fac = 0.05; % factor for load step
dimlineshift_fac = 0.85; % factor for down shift of dimension lines
% with respect to half Y size
dimlinetick_fac = 0.15; % factor for dimension line tick size
% with respect to half Y size
maxdisplsize_fac = 0.60; % factor for maximum transversal size in
% relation to half vertical window size
maxbendmomsize_fac = 0.70; % factor for maximum bending moment size
% in relation to half vertical window size
spanmomlineshift_fac = 0.85; % factor for down shift of span moment
% dimension lines with respect to half Y size
inflectpt_fac = 0.005; % factor for size of inflection point disk
rotmeter_fac = 0.85; % factor for rotation meter size in
% relation to half vertical window size
picktol_fac = 0.01; % factor for picking a point
minmemblen_fac = 0.05; % factor for minimum member length
ValidSupInsertion = 1; % status for valid support insertion
BeamLineNotFound = 2; % status for beam line not found for support insertion
SupInsertionNotValid = 3; % status for not valid position for support insertion
SupDelMinNumSup = 1; % status for minimum number of internal supports
ValidSupDeletion = 2; % status for valid support deletion
SupDelNotFound = 3; % status for support not found for deletion
MembLoadFound = 1; % status for pick member load found
MembLoadNotFound = 2 % status for pick member not found
SupMoveFound = 1; % status for support found for moving
SupMoveNotFound = 2; % status for support not found for moving
end
Private properties
properties (Access = private)
pickmember = 0; % current member load picked
picksup = 0; % current support picked
orig_suppos = 0; % original moving support position
hnd_draft = []; % handle to draft graphics object being displayed
end
Constructor method
methods
%------------------------------------------------------------------
function draw = CrossDraw(solver)
if (nargin > 0)
draw.solver = solver;
end
end
end
Class (static) auxiliary functions
methods (Static)
%------------------------------------------------------------------
% Plots a square with defined center coordinates, side length and
% color.
% Input arguments:
% cnv: graphics context (axes)
% x: center coordinate on the X axis
% y: center coordinate on the Y axis
% l: side length
% c: color (RGB vector)
function square(cnv,x,y,l,c)
X = [x - l/2, x + l/2, x + l/2, x - l/2];
Y = [y - l/2, y - l/2, y + l/2, y + l/2];
fill(cnv, X, Y, c);
end
%------------------------------------------------------------------
% Plots a draft version of a square with defined center coordinates,
% side length and color.
% It draws a hollow square and sets its parent property as the
% given handle to the group of graphics objects.
% Input arguments:
% cnv: graphics context (axes)
% hnd: handle to group of graphics objects
% x: center coordinate on the X axis
% y: center coordinate on the Y axis
% l: side length
% c: color (RGB vector)
function draftSquare(cnv,hnd,x,y,l,c)
X = [x - l/2, x + l/2, x + l/2, x - l/2, x - l/2];
Y = [y - l/2, y - l/2, y + l/2, y + l/2, y - l/2];
plot(cnv, X, Y, 'color', c, 'Parent', hnd);
end
%------------------------------------------------------------------
% Plots a triangle with defined top coordinates, height, base,
% orientation, and color.
% Input arguments:
% cnv: graphics context (axes)
% x: top coordinate on the X axis
% y: top coordinate on the Y axis
% h: triangle height
% b: triangle base
% ang: angle (in radian) between the axis of symmetry and the
% horizontal direction (counterclockwise) - 0 rad when
% triangle is pointing left
% c: color (RGB vector)
function triangle(cnv,x,y,h,b,ang,c)
cx = cos(ang);
cy = sin(ang);
X = [x, x + h * cx + b/2 * cy, x + h * cx - b/2 * cy];
Y = [y, y + h * cy - b/2 * cx, y + h * cy + b/2 * cx];
fill(cnv, X, Y, c);
end
%------------------------------------------------------------------
% Plots a draft version of a triangle with defined top coordinates,
% height, base, orientation, and color.
% It draws a hollow triangle and sets its parent property as the
% given handle to the group of graphics objects.
% Input arguments:
% cnv: graphics context (axes)
% hnd: handle to group of graphics objects
% x: top coordinate on the X axis
% y: top coordinate on the Y axis
% h: triangle height
% b: triangle base
% ang: angle (in radian) between the axis of symmetry and the
% horizontal direction (counterclockwise) - 0 rad when
% triangle is pointing left
% c: color (RGB vector)
function draftTriangle(cnv,hnd,x,y,h,b,ang,c)
cx = cos(ang);
cy = sin(ang);
X = [x, x + h * cx + b/2 * cy, x + h * cx - b/2 * cy, x];
Y = [y, y + h * cy - b/2 * cx, y + h * cy + b/2 * cx, y];
plot(cnv, X, Y, 'color', c, 'Parent', hnd);
end
%------------------------------------------------------------------
% Plots a circle with defined center coordinates, radius and color.
% This method is used to draw hinges on 2D models.
% Input arguments:
% cnv: graphics context (axes)
% x: center coordinate on the X axis
% y: center coordinate on the Y axis
% r: circle radius
% c: color (RGB vector)
function circle(cnv,x,y,r,c)
circ = 0 : pi/50 : 2*pi;
xcirc = x + r * cos(circ);
ycirc = y + r * sin(circ);
plot(cnv, xcirc, ycirc, 'color', c);
end
%------------------------------------------------------------------
% Plots a circle disk with defined center coordinates, radius and
% color. The circle is filled with the given color
% This method is used to inflection on 2D models.
% Input arguments:
% cnv: graphics context (axes)
% x: center coordinate on the X axis
% y: center coordinate on the Y axis
% r: circle radius
% c: color (RGB vector)
function disk(cnv,x,y,r,c)
circ = 0 : pi/50 : 2*pi;
xcirc = x + r * cos(circ);
ycirc = y + r * sin(circ);
fill(cnv, xcirc, ycirc, c);
end
%------------------------------------------------------------------
% Plots an arrow with defined beggining coordinates, length,
% arrowhead height, arrowhead base, orientation, and color.
% This method is used to draw load symbols on 2D models.
% Input arguments:
% cnv: graphics context (axes)
% x: beggining coordinate on the X axis
% y: beggining coordinate on the Y axis
% l: arrow length
% h: arrowhead height
% b: arrowhead base
% ang: pointing direction (angle in radian with the horizontal
% direction - counterclockwise) - 0 rad when pointing left
% c: color (RGB vector)
function arrow2D(cnv,x,y,l,h,b,ang,c)
cx = cos(ang);
cy = sin(ang);
X = [x, x + l * cx];
Y = [y, y + l * cy];
line(cnv, X, Y, 'Color', c);
CrossDraw.triangle(cnv, x, y, h, b, ang, c);
end
%------------------------------------------------------------------
% Plots node rotation potentiometer.
% Input arguments:
% cnv: graphics context (axes)
% x: center coordinate on the X axis
% y: center coordinate on the Y axis
% r: circle radius
% halfAngRange: half angle range in radians
% nTicks: number of tick marks
% tickSize: tick size
% rotAngle: angle of rotation arrow in radians
% c: color (RGB vector)
function rotationMeter(cnv,x,y,r,halfAngRange,nTicks,tickSize,...
rotAngle,c)
if nTicks < 2
nTicks = 2;
end
% Draw meter arc
angStep = 2*halfAngRange / 25;
circ = pi/2-halfAngRange : angStep : pi/2+halfAngRange;
xCirc = x + r * cos(circ);
yCirc = y + r * sin(circ);
plot(cnv, xCirc, yCirc, 'color', c);
% Draw meter ticks
tickRange = 2*halfAngRange / (nTicks-1);
tickAngle = pi/2-halfAngRange;
for i = 1:nTicks-1
xTick = [x + (r-tickSize) * cos(tickAngle), ...
x + r * cos(tickAngle)];
yTick = [y + (r-tickSize) * sin(tickAngle), ...
y + r * sin(tickAngle)];
plot(cnv, xTick, yTick, 'color', c);
tickAngle = tickAngle + tickRange;
end
tickAngle = pi/2+halfAngRange;
xTick = [x + (r-tickSize) * cos(tickAngle), ...
x + r * cos(tickAngle)];
yTick = [y + (r-tickSize) * sin(tickAngle), ...
y + r * sin(tickAngle)];
plot(cnv, xTick, yTick, 'color', c);
% Draw meter rotation arrow
arrowSize = r - 1.2*tickSize;
arrowHead = r * 0.15;
cx = cos(rotAngle);
cy = sin(rotAngle);
xtip = 0;
ytip = y + arrowSize;
X = [x, x + xtip*cx - ytip*cy];
Y = [y, xtip*cy + ytip*cx];
line(cnv, X, Y, 'Color', c);
x1 = - arrowHead/2;
y1 = + arrowSize - arrowHead;
x2 = 0;
y2 = y + arrowSize;
x3 = + arrowHead/2;
y3 = y + arrowSize - arrowHead;
X = [x + x1*cx - y1*cy, x + x2*cx - y2*cy, x + x3*cx - y3*cy];
Y = [ y1*cx + x1*cy, y2*cx + x2*cy, y3*cx + x3*cy];
plot(cnv, X, Y, 'color', c);
end
%------------------------------------------------------------------
% Snap a value to the closest step value.
function snap_val = snapToStepValue(val,step)
fp = val / step; % "fraction" part
ip = floor(fp); % integer part
fp = fp - ip;
if fp > 0.5
snap_val = (ip + 1.0) * step;
elseif fp < -0.5
snap_val = (ip - 1.0) * step;
else
snap_val = ip * step;
end
end
end
Protect methods
methods (Access = protected) % Access from methods in subclasses function max_load = getMaxLoad(draw) max_load = 0; for i = 1:draw.solver.nmemb if(abs(draw.solver.membs(i).q) > max_load) max_load = abs(draw.solver.membs(i).q); end end end %------------------------------------------------------------------ % Draws a continuous beam model. % Input: % - posy: Y position of continuous beam axis. % - unbalanced_node: flag for unbalanced node. % if set, display corresponding support in red color. function beam(draw,cnv,posy,unbalanced_node) len = draw.solver.totalLen; line(cnv, [0, len], [posy, posy], 'Color', [0 0 0]); %%%%%%% COMPLETE HERE - CROSSDRAW: 01 %%%%%%% end %------------------------------------------------------------------ % Draw the uniform load of a member. % Input arguments: % cnv: graphics context (axes) % init_pos: initial position of load % len: length of load % q: uniform load value % load_size: size of load % load_step: step size for drawing arrows % arrowsize: size of arrow head function memberLoad(~,cnv,init_pos,len,q,... load_size,load_step,arrowsize) %%%%%%% COMPLETE HERE - CROSSDRAW: 02 %%%%%%% end %------------------------------------------------------------------ % Draw the dimension line of a beam span. % Input arguments: % cnv: graphics context (axes) % init_pos: initial position of dimension line % len: length of dimension line % dimline_shift: down shift of dimension line % dimline_tick: size of dimension line tick function dimLine(~,cnv,init_pos,len,dimline_shift,dimline_tick) %%%%%%% COMPLETE HERE - CROSSDRAW: 03 %%%%%%% end %------------------------------------------------------------------ % Draw a draft version of the uniform load of a member and set % the parent property of each graphic object as the given handle % to the group of graphics objects. % Input arguments: % cnv: graphics context (axes) % hnd: handle to group of graphics objects % init_pos: initial position of load % len: length of load % q: uniform load value % load_size: size of load % load_step: step size for drawing arrows function draftMemberLoad(~,cnv,hnd,init_pos,len,q,load_size,load_step) %%%%%%% COMPLETE HERE - CROSSDRAW: 06 %%%%%%% end %------------------------------------------------------------------ % Draw a draft version of the dimension line of a beam span and set % the parent property of each graphic object as the given handle % to the group of graphics objects. % Input arguments: % cnv: graphics context (axes) % hnd: handle to group of graphics objects % init_pos: initial position of dimension line % len: length of dimension line % dimline_shift: down shift of dimension line % dimline_tick: size of dimension line tick function draftDimLine(~,cnv,hnd,init_pos,len,dimline_shift,dimline_tick) %%%%%%% COMPLETE HERE - CROSSDRAW: 07 %%%%%%% end %------------------------------------------------------------------ % Compute the shift of support position for a given trial position. % The trial shift is the difference between the given position % and the original support position. % The trial shift value is modified to the returned shift value % such that the adjacent member lengths are never less than the % minimum allowed member length. function shift = getSupShift(draw,pos) shift = 0; if draw.picksup < 1 return end minmemblen = draw.minmemblen_fac * draw.solver.totalLen; shift = pos - draw.orig_suppos; if draw.picksup == 1 if shift > 0 rightlen = draw.solver.membs(1).len; if (rightlen - shift) < minmemblen shift = rightlen - minmemblen; end end elseif draw.picksup == draw.solver.nmemb+1 if shift < 0 leftlen = draw.solver.membs(draw.solver.nmemb).len; if (leftlen + shift) < minmemblen shift = -leftlen + minmemblen; end end else if shift < 0 leftlen = draw.solver.membs(draw.picksup-1).len; if (leftlen + shift) < minmemblen shift = -leftlen + minmemblen; end else rightlen = draw.solver.membs(draw.picksup).len; if (rightlen - shift) < minmemblen shift = rightlen - minmemblen; end end end end %------------------------------------------------------------------ % Draw a draft version of a support and its adjacent members, % including the adjacent member loads. Return a handle to the % group of graphics objects. % Input arguments: % cnv: graphics context (axes) % hnd: handle to group of graphics objects % shift: shift of support position function draftSupMove(draw,cnv,hnd,shift) halfYsize = diff(cnv.YLim) * 0.5; max_load = draw.getMaxLoad(); minload_size = draw.solver.totalLen * CrossDraw.minloadsize_fac; load_step = draw.solver.totalLen * CrossDraw.loadstep_fac; supsize = draw.solver.totalLen * CrossDraw.supsize_fac; dimline_shift = halfYsize * CrossDraw.dimlineshift_fac; dimline_tick = halfYsize * CrossDraw.dimlinetick_fac; if draw.picksup == 1 sup_pos = draw.orig_suppos + shift; if draw.solver.supinit == 0 CrossDraw.draftTriangle(cnv,hnd,sup_pos,0,supsize,supsize,-pi/2,[1 0 0]); else CrossDraw.draftTriangle(cnv,hnd,sup_pos,-supsize*0.30,supsize,supsize,-pi/2,[1 0 0]); CrossDraw.draftSquare(cnv,hnd,sup_pos,0,supsize*0.60,[1 0 0]); end init_pos = sup_pos; rightlen = draw.solver.membs(1).len - shift; line(cnv, [init_pos, init_pos+rightlen], [0, 0],... 'Color', [1 0 0], 'Parent', hnd); q = draw.solver.membs(1).q; load_size = CrossDraw.loadsize_fac * halfYsize * ... (abs(q) / max_load); if load_size < minload_size load_size = minload_size; end draw.draftMemberLoad(cnv,hnd,init_pos,rightlen,q,load_size,load_step); draw.draftDimLine(cnv,hnd,init_pos,rightlen,dimline_shift,dimline_tick); elseif draw.picksup == draw.solver.nmemb+1 sup_pos = draw.orig_suppos + shift; if draw.solver.supend == 0 CrossDraw.draftTriangle(cnv,hnd,sup_pos,0,supsize,supsize,-pi/2,[1 0 0]); else CrossDraw.draftTriangle(cnv,hnd,sup_pos,-supsize*0.30,supsize,supsize,-pi/2,[1 0 0]); CrossDraw.draftSquare(cnv,hnd,sup_pos,0,supsize*0.60,[1 0 0]); end init_pos = draw.orig_suppos - draw.solver.membs(draw.solver.nmemb).len; leftlen = draw.solver.membs(draw.solver.nmemb).len + shift; line(cnv, [init_pos, init_pos+leftlen], [0, 0],... 'Color', [1 0 0], 'Parent', hnd); q = draw.solver.membs(draw.solver.nmemb).q; load_size = CrossDraw.loadsize_fac * halfYsize * ... (abs(q) / max_load); if load_size < minload_size load_size = minload_size; end draw.draftMemberLoad(cnv,hnd,init_pos,leftlen,q,load_size,load_step); draw.draftDimLine(cnv,hnd,init_pos,leftlen,dimline_shift,dimline_tick); else sup_pos = draw.orig_suppos + shift; CrossDraw.draftTriangle(cnv,hnd,sup_pos,0,supsize,supsize,-pi/2,[1 0 0]); init_pos = draw.orig_suppos - draw.solver.membs(draw.picksup-1).len; leftlen = draw.solver.membs(draw.picksup-1).len + shift; line(cnv, [init_pos, init_pos+leftlen], [0, 0],... 'Color', [1 0 0], 'Parent', hnd); q = draw.solver.membs(draw.picksup-1).q; load_size = CrossDraw.loadsize_fac * halfYsize * ... (abs(q) / max_load); if load_size < minload_size load_size = minload_size; end draw.draftMemberLoad(cnv,hnd,init_pos,leftlen,q,load_size,load_step); draw.draftDimLine(cnv,hnd,init_pos,leftlen,dimline_shift,dimline_tick); init_pos = draw.orig_suppos + shift; rightlen = draw.solver.membs(draw.picksup).len - shift; line(cnv, [init_pos, init_pos+rightlen], [0, 0],... 'Color', [1 0 0], 'Parent', hnd); q = draw.solver.membs(draw.picksup).q; load_size = CrossDraw.loadsize_fac * halfYsize * ... (abs(q) / max_load); if load_size < minload_size load_size = minload_size; end draw.draftMemberLoad(cnv,hnd,init_pos,rightlen,q,load_size,load_step); draw.draftDimLine(cnv,hnd,init_pos,rightlen,dimline_shift,dimline_tick); end end end
Public methods
methods
%------------------------------------------------------------------
% Returns the bounding box (x and y limits) of a continuous beam
% model. The returned box has xmin = 0, xmax = totalLen,
% ymin = -totalLen * 0.05, ymax = +totalLen * 0.05, in which
% totalLen is the length of the entire beam model.
% The y limits are fictitious. They are equal in module and
% equal to a small percentage of the total length to force
% the adjustment of the box in the y direction, keeping y = 0
% in the center of the canvas.
function bbox = crossBoundBox(draw)
totalLen = draw.solver.totalLen;
bbox(1) = 0;
bbox(2) = -totalLen * 0.05;
bbox(3) = totalLen;
bbox(4) = totalLen * 0.05;
end
%------------------------------------------------------------------
% Draws a continuous beam model with applied loads.
% Input:
% - cnv: graphics context (owning canvas)
function model(draw,cnv)
% Clear canvas
cla(cnv);
% Draw continuous beam without highlighting unbalanced nodes
draw.beam(cnv,0,false);
% Draw applied loads
halfYsize = diff(cnv.YLim) * 0.5;
max_load = draw.getMaxLoad();
arrowsize = draw.solver.totalLen * CrossDraw.arrowsize_fac;
minload_size = draw.solver.totalLen * CrossDraw.minloadsize_fac;
load_step = draw.solver.totalLen * CrossDraw.loadstep_fac;
init_pos = 0;
for i = 1:draw.solver.nmemb
len = draw.solver.membs(i).len;
load_size = CrossDraw.loadsize_fac * halfYsize * ...
(abs(draw.solver.membs(i).q) / max_load);
if load_size < minload_size
load_size = minload_size;
end
q = draw.solver.membs(i).q;
draw.memberLoad(cnv,init_pos,len,q,load_size,load_step,arrowsize);
init_pos = init_pos + len;
end
% Draw dimension lines
dimline_shift = halfYsize * CrossDraw.dimlineshift_fac;
dimline_tick = halfYsize * CrossDraw.dimlinetick_fac;
init_pos = 0;
for i = 1:draw.solver.nmemb
len = draw.solver.membs(i).len;
draw.dimLine(cnv,init_pos,len,dimline_shift,dimline_tick);
init_pos = init_pos + len;
end
end
%------------------------------------------------------------------
% Draws a continuous beam model with its deformed configuration.
% Input:
% - cnv: graphics context (owning canvas)
function deformedConfig(draw,cnv)
% Clear canvas
cla(cnv);
% Draw continuous beam without highlighting unbalanced nodes
draw.beam(cnv,0,false);
% Initialize cross section position step vector
x = linspace(0,1,50);
% Get half canvas vertical size
halfYsize = diff(cnv.YLim) * 0.5;
% Compute size of inflection point disk mark
inflectpt_size = draw.solver.totalLen * CrossDraw.inflectpt_fac;
% Compute each member deformed configuration and get maximum
% transversal displacement
maxv = 0;
% Treat first member
len = draw.solver.membs(1).len;
rot_ini = 0;
rot_end = draw.solver.nodes(1).rot;
contin_ini = draw.solver.supinit;
contin_end = 1;
pos_loc = x * len;
loc_maxv = draw.solver.membs(1).internalDispl(...
contin_ini,contin_end,rot_ini,rot_end,pos_loc);
maxv = max([maxv loc_maxv]);
%%%%%%% COMPLETE HERE - CROSSDRAW: 04 %%%%%%%
% Compute deformed configuration display factor and
% display deformed configuration.
% Display inflection points: points with change of curvature,
% which correspond to points in which bending moment is null.
deform_fac = (CrossDraw.maxdisplsize_fac * halfYsize) / maxv;
init_pos = 0;
for i = 1:draw.solver.nmemb
len = draw.solver.membs(i).len;
pos_loc = x * len;
pos_gbl = init_pos + pos_loc;
displv = draw.solver.membs(i).displv * deform_fac;
line(cnv, pos_gbl, displv, 'Color', [0 0 1]);
[npts, ptpos] = draw.solver.membs(i).momentRoots(...
draw.solver.membs(i).ml,draw.solver.membs(i).mr);
F = griddedInterpolant(pos_loc,displv);
vpts = F(ptpos);
for j = 1:npts
CrossDraw.disk(cnv,init_pos+ptpos(j),vpts(j),inflectpt_size*0.5,[0 0 1]);
end
init_pos = init_pos + len;
end
% Display node rotation meters.
% Node rotation is considered equal to its tangent.
% To draw node rotation in meter, compute an angle based on
% a tangent value amplified by deform factor.
% Rotation meter half angle range is 30 degrees.
rotmeter_size = halfYsize * CrossDraw.rotmeter_fac;
tick_size = rotmeter_size * 0.15;
len = draw.solver.membs(1).len;
node_pos = len;
for i = 1:draw.solver.nnode
rot = draw.solver.nodes(i).rot;
noderot = atan2(rot * deform_fac,1);
halfAngRange = deg2rad(30);
CrossDraw.rotationMeter(cnv,node_pos,0,rotmeter_size,halfAngRange,...
7,tick_size,noderot,[0 0.5 0]);
len = draw.solver.membs(i+1).len;
node_pos = node_pos + len;
end
end
%------------------------------------------------------------------
% Draws a continuous beam model with its bending moment diagram
% indicating the values at the ends and the maximum value of
% non-linear diagrams.
% Input:
% - cnv: graphics context (owning canvas)
function bendingMomDiagram(draw,cnv)
% Clear canvas
cla(cnv);
% Draw continuous beam highlighting unbalanced nodes
draw.beam(cnv,0,true);
% Initialize cross section position step vector
x = linspace(0,1,50);
% Get half canvas vertical size
halfYsize = diff(cnv.YLim) * 0.5;
% Compute span moment dimension line vertical shift and tick size
spanmomline_shift = halfYsize * CrossDraw.spanmomlineshift_fac;
spanmomline_tick = halfYsize * CrossDraw.dimlinetick_fac;
% Get tolerance value for bending moments
momtol = 10^-(draw.solver.decplc+1);
% Compute each member bending moment diagram and get
% maximum bending moment value
maxm = 0;
for i = 1:draw.solver.nmemb
len = draw.solver.membs(i).len;
pos_loc = x * len;
loc_maxm = draw.solver.membs(i).bendingMoment(...
draw.solver.membs(i).ml,draw.solver.membs(i).mr,...
pos_loc);
maxm = max([maxm loc_maxm]);
end
% Compute bending moment display factor and
% display bending moment diagram
bendmom_fac = (CrossDraw.maxbendmomsize_fac * halfYsize) / maxm;
%%%%%%% COMPLETE HERE - CROSSDRAW: 05 %%%%%%%
end
%------------------------------------------------------------------
% Try to pick an interior support for a given mouse point point.
% If found a support, return its index. Otherwise, return a null
% inde
% Input:
% - pt: given mouse point
% Output:
% - n: index of interior support
% (if null, no interior support was found)
function n = pickInteriorSup(draw,~,pt)
n = 0;
supsize = draw.solver.totalLen * CrossDraw.supsize_fac;
node_pos = 0;
for i = 1:draw.solver.nmemb-1
len = draw.solver.membs(i).len;
node_pos = node_pos + len;
if inpolygon(pt(1),pt(2),...
[node_pos-supsize,node_pos+supsize,node_pos+supsize,node_pos-supsize],...
[-supsize,-supsize,supsize,supsize])
n = i;
return
end
end
end
%------------------------------------------------------------------
% Try to pick a position for inserting an interior support for a
% given mouse point.
% Input:
% - pt: given point in model canvas
% Output:
% - stat: pick point status:
% ValidSupInsertion = 1
% BeamLineNotFound = 2
% SupInsertionNotValid = 3
% - m: index of pick member
% - pos: position of inserted support inside pick member
% The conditions for successfully inserting an interior support are:
% - The given point should close to the continous beam line.
% - The given point should not be close to an existing interior
% support
function [stat,m,pos] = pickInsertSup(draw,pt)
stat = draw.BeamLineNotFound;
m = 0;
pos = 0;
minMembLen = draw.solver.totalLen * CrossDraw.minmemblen_fac;
totalLen = draw.solver.totalLen;
pick_tol = draw.solver.totalLen * CrossDraw.picktol_fac;
if ~inpolygon(pt(1),pt(2),...
[0,totalLen,totalLen,0],[-pick_tol,-pick_tol,pick_tol,pick_tol])
return
end
%%%%%%% COMPLETE HERE - CROSSDRAW: 08 %%%%%%%
end
%------------------------------------------------------------------
% Try to pick an interior support for deletion for a given mouse point.
% Input:
% - pt: given point in model canvas
% Output:
% - stat: pick point status:
% SupDelMinNumSup = 1
% ValidSupDeletion = 2
% SupDelNotFound = 3
% - n: index of internal support to delete (from 1 to nnode)
% The conditions for successfully deleting an interior support are:
% - The given point should close to an interior support.
% - There must be at least two interior supports
function [stat,n] = pickDeleteSup(draw,pt)
n = 0;
if draw.solver.nnode < 2
stat = draw.SupDelMinNumSup;
return
end
%%%%%%% COMPLETE HERE - CROSSDRAW: 09 %%%%%%%
end
%------------------------------------------------------------------
% Try to pick a member load for a given mouse point.
% If found a member load, display its draft version.
% Save pick member index and handle to draft graphics object.
% Input:
% - cnv: graphics context (owning canvas)
% - pt: given mouse point
% - sel: flag for selection (if true, select member load for changing)
% Output:
% - stat: pick point status:
% MembLoadFound = 1
% MembLoadNotFound = 2
function stat = pickMemberLoad(draw,cnv,pt,sel)
stat = draw.MembLoadNotFound;
draw.pickmember = 0;
draw.hnd_draft = [];
halfYsize = diff(cnv.YLim) * 0.5;
max_load = draw.getMaxLoad();
minload_size = draw.solver.totalLen * CrossDraw.minloadsize_fac;
pick_tol = draw.solver.totalLen * CrossDraw.picktol_fac;
load_step = draw.solver.totalLen * CrossDraw.loadstep_fac;
%%%%%%% COMPLETE HERE - CROSSDRAW: 10 %%%%%%%
end
%------------------------------------------------------------------
% If there is a pick member load, delete current draft graphics
% object and redisplay it in the new position defined by
% given mouse point point.
% Input:
% - cnv: graphics context (owning canvas)
% - pt: given mouse point
function updateMemberLoad(draw,cnv,pt)
if ~isempty(draw.hnd_draft)
delete(draw.hnd_draft);
draw.hnd_draft = [];
end
if draw.pickmember < 1
return
end
halfYsize = diff(cnv.YLim) * 0.5;
max_load = draw.getMaxLoad();
load_step = draw.solver.totalLen * CrossDraw.loadstep_fac;
%%%%%%% COMPLETE HERE - CROSSDRAW: 11 %%%%%%%
end
%------------------------------------------------------------------
% If there is a pick member load, delete current draft graphics
% object and return pick member and load value defined by
% given mouse point point.
% Also reset handle to current draft graphics object and index
% of current picked member.
% Input:
% - cnv: graphics context (owning canvas)
% - pt: given mouse point
% Output:
% - m: index of member
% - q: updated uniform load value
function [m,q] = setMemberLoad(draw,cnv,pt)
if ~isempty(draw.hnd_draft)
delete(draw.hnd_draft);
draw.hnd_draft = [];
end
m = draw.pickmember;
draw.pickmember = 0;
q = 0;
if m < 1
return
end
halfYsize = diff(cnv.YLim) * 0.5;
max_load = draw.getMaxLoad();
%%%%%%% COMPLETE HERE - CROSSDRAW: 12 %%%%%%%
end
%------------------------------------------------------------------
% Try to pick a support for a given mouse point point.
% If found a support, display its draft version.
% Save pick support index and handle to draft graphics object.
% Input:
% - cnv: graphics context (owning canvas)
% - pt: given mouse point
% - sel: flag for selection (if true, select support for changing)
% Output:
% - stat: pick point status:
% SupMoveFound = 1
% SupMoveNotFound = 2
function stat = pickSupMove(draw,cnv,pt,sel)
stat = draw.SupMoveNotFound;
draw.picksup = 0;
draw.hnd_draft = [];
%%%%%%% COMPLETE HERE - CROSSDRAW: 13 %%%%%%%
end
%------------------------------------------------------------------
% If there is a pick support, delete current draft graphics
% object and redisplay it in the new position defined by
% given mouse point point.
function updateSupMove(draw,cnv,pt)
if ~isempty(draw.hnd_draft)
delete(draw.hnd_draft);
draw.hnd_draft = [];
end
if draw.picksup < 1
return
end
%%%%%%% COMPLETE HERE - CROSSDRAW: 14 %%%%%%%
end
%------------------------------------------------------------------
% If there is a pick support, delete current draft graphics
% object and return pick support and new position defined by
% given mouse point point.
% Also reset handle to current draft graphics object and index
% of current picked support.
% Output:
% - n: index of support (from 1 to nmembs+1)
% - shift: support position shift (negative or positive)
function [n,shift] = setSupMove(draw,~,pt)
n = 0;
shift = 0;
if ~isempty(draw.hnd_draft)
delete(draw.hnd_draft);
draw.hnd_draft = [];
end
if draw.picksup < 1
return
end
n = draw.picksup;
%%%%%%% COMPLETE HERE - CROSSDRAW: 15 %%%%%%%
draw.picksup = 0;
draw.orig_suppos = 0;
end
%------------------------------------------------------------------
% Cleans data structure of a CrossSolver object.
function draw = clean(draw)
draw.solver = [];
end
end
end