How to update a complicated figure ?

3 views (last 30 days)
Damien LaRocque
Damien LaRocque on 12 Jul 2019
Commented: Damien LaRocque on 12 Jul 2019
I need to animate a complex figure consisting of a chain of rectangles, forming an arm.
Here is an example of how this arm looks like when not animated :
To animate this figure, I made the following code :
function renderFrame(fig, data)
hold(ax, 'on'); % Need to hold so that new elements of the arm add themselves
showMembers(fig, data); % Create patches and rotate them to the right angle to create members
showJoints(fig, data); % Draw circles at the joints betwwen the members. Use the width of rectangle members
drawnow;
hold(ax, 'off'); % Next rendering will replace this one; No need to hold
end
function rotateMember(fig, data, iMember, rotAngle)
for iAngle = 1:rotAngle
updateMemberAngle(data, i, 1); % Change thew data so the i-th member rotates by 1
renderFrame(fig); % Show frame after the data was changed
end
end
function main()
fig = figure;
ax = gca;
axis(ax, 'equal');
setAxis(data); % Set axis limits and create axis arrows with totalLength of the arm
renderFrame(ax, data);
rotateMember(fig, data, 3, 90); % Rotate 3rd member by 90 degrees
end
main()
But the frames of my animation doesn't clear at all. It results in this figure :
What am I doing wrong ? Is there a way to plot complicated figures with multiple parts and to animate it, by clearing frame ?
I looked into using `newplot` and `nextplot` or into creating graphic objects and then setting the data at each iteration, but it rejects an exception every time the figure is deleted since "graphics objects are deleted".

Answers (1)

Walter Roberson
Walter Roberson on 12 Jul 2019
Create your patches once, not every time you rotate. Update the Vertices of the patches instead of creating new patches.
You might want to look into creating hgtransform groups and updating the transform matrices. hgtransform groups can parent other hgtransform groups, which has the effect of compounding the transform matrices.
  1 Comment
Damien LaRocque
Damien LaRocque on 12 Jul 2019
Thanks for the answer.
I tried to change the Vertices of the patches, and I got this result, in static mode. We can see that only the last member has his patch updated
geometrie_directe.png
Since this new problem is related to how my members are rendered, here is how I implemented my rendering methods :
classdef Member < handle
properties
polygon = patch([0, 0, 0, 0], [0, 0, 0, 0], 'w', 'EdgeColor', 'b', 'visible', 'off');
end
methods
function render(this)
% Plot the member with a length, an origin, a width and an angle.
% RECTANGLE IN PATCH
x_min = this.x;
x_max = this.x + this.longueur; % Longueur : Length
y_min = this.y - this.largeur / 2; % Largeur : Width
y_max = this.y + this.largeur / 2;
set(this.polygon, 'Vertices', [[x_min, x_max, x_max, x_min]', [y_min, y_min, y_max, y_max]'])
% this.polygon.Vertices = [[x_min, x_max, x_max, x_min]', [y_min, y_min, y_max, y_max]'];
% ROTATION
direction = [0, 0, 1]; % Rotation in z
pnt_rotation = [this.x, this.y, 0];
rotate(this.polygon, direction, this.absoluteAngle, pnt_rotation);
set(this.polygon, 'visible', 'on');
end
end
end
So, I start by defining four values, which are the ranges in x and y where the rectangle is defined about the origin (x, y) (from [`x`] to [`x + length`] in x and from [`y - width / 2`] to [`y + width / 2`] in y.
I then set the Vertices of the patch polygon and I rotate it according to the origin with an angle of [this.AbsoluteAngle], an angle defined from the x axis.
As for how this method is called, I created an Arm class :
classdef Arm < handle
properties (SetAccess = private, GetAccess = public)
members; % Array of Member objects
lastMember;
x = 0;
y = 0;
end
properties (Access = private)
totalLength
end
methods
function render(thisArm)
% Create a figure and plot the arm members and the joints in it.
% ** Code to create a figure if not previously created **
ax = gca;
axis(ax, 'equal');
hold(ax, 'on');
grid(ax, 'on');
% AXES
% Window size
windowRange = round(thisArm.totalLength, -1) + 10;
% Axis limits
xlim(ax, [-windowRange, windowRange]);
ylim(ax, [-windowRange, windowRange]);
% Function to draw arrows
drawArrow = @(x,y, varargin) quiver( x(1),y(1),x(2)-x(1),y(2)-y(1),0, varargin{:} );
% Draw axis arrows
drawArrow([0, windowRange], [0, 0], 'linewidth',3,'color','k');
drawArrow([0, 0], [0, windowRange], 'linewidth',3,'color','k');
% Plot members
for ii=1:length(thisArm.members)
thisArm.members(ii).render(); % Call the render method for each arm member
end
% Lines
plot([cell2mat(thisArm.getValues("x")), thisArm.members(end).getEndX()], [cell2mat(thisArm.getValues("y")), thisArm.members(end).getEndY()], '--b')
% Plot joints
thisArm.drawCircle(thisArm.members(1).getX(), thisArm.members(1).getY(), thisArm.members(1).getWidth(), 'k'); % Create a circle with a center, a diameter and a color
for jj=2:length(thisArm.members)
taille = max(thisArm.members(jj - 1).getWidth(), thisArm.members(jj).getWidth());
thisArm.drawCircle(thisArm.members(jj).getX(), thisArm.members(jj).getY(), taille, 'r');
end
eEffector = thisArm.getEndEffector(); % Get end effector coordinates
thisArm.drawCircle(eEffector(1), eEffector(2), thisArm.members(end).getWidth(), 'g');
hold(ax, 'off');
drawnow;
end
end
end
On this one, I set my axes and I draw the axis arrows. I then render the members, one by one (maybe the source of the problem) and I plot a line in the centrer of all the members. Everything joint is then drawn with a drawCircle function I created.
I then use hold off and drawnow;

Sign in to comment.

Categories

Find more on Graphics Performance in Help Center and File Exchange

Products


Release

R2018a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!