How to morph a shape into another
20 views (last 30 days)
Show older comments
I am currently working on morphing a complex closed shape (later I will use patch rather than plot) into another complex shape. For simplicity, I wrote a code which morphed a square shape into a diamond shape. The limitation is that the square has 4 nodes and the corresponding final shape is also 4 nodes. So, it is easy to translate each node using linspace. The code is given below:
close all
clear all
clc
xbox0 = [0 2 2 0 0]; ybox0 = [0 0 2 2 0]; % coordinates of square shape
xdia0 = [4 5 4 3 4]; ydia0 = [0 1 2 1 0]; % coordinates for diamond shape
n = 10; % number steps to transform
%% this loop gives a matrix of the coordinates for each step
for i = 1:length(xbox0)
x1 = xbox0(i);
x2 = xdia0(i);
y1 = ybox0(i);
y2 = ydia0(i);
xpoints = linspace(x1,x2,n)';
ypoints = linspace(y1,y2,n)';
xvector {i} = xpoints;
yvector {i} = ypoints;
end
xfinal = cell2mat(xvector); yfinal = cell2mat(yvector); % converting the stored coordinate cells into a matrix
figure
plot(xbox0,ybox0,'gsquare-') % Plot the original box shape
axis equal
xlim([0 5])
ylim([0 2.5])
hold on
plot(xdia0,ydia0,'gsquare-') % Plot the original diamond shape
%% this loop just animates the intermediate coordinates to the final shape
for j = 1:n
x = xfinal(j,:);
y = yfinal(j,:);
plot(x,y,'rsquare:')
pause(0.1)
end
Now, my problem is that I do not have equal coordinates. For example, I have 6 nodes for the square shape and 5 nodes for the diamond shape. Is there a way to modify (maybe interpolate. I cannot figure out interp1 or 2) into a similar length coordinates and then carry out the aforementioned procedure? Your guidance will be much appreciated
xbox = [0 2 2 2 1 0 0];
ybox = [0 0 1 2 2 2 0];
xdia = [4 4.5 5 4 3 4];
ydia = [0 0.5 1 2 1 0];
figure
hold on
plot(xbox,ybox,'bsquare-')
plot(xdia,ydia,'bsquare-')
axis equal
My thanks in advance. Please forgive me lack of knowledge and correct me if my approach was wrong.
Have a great day
0 Comments
Accepted Answer
Davide Masiello
on 3 Aug 2023
I guess it boils down to what mapping you choose from the points of shape 1 to the points of shape 2.
Let's take your case for example.
xbox = [0 2 2 2 1 0 0];
ybox = [0 0 1 2 2 2 0];
xdia = [4 4.5 5 4 3 4];
ydia = [0 0.5 1 2 1 0];
figure
hold on, box on
plot(xbox,ybox,'bsquare-')
plot(xdia,ydia,'bsquare-')
axis equal padded
offs = 0.08;
text(xbox(1:end-1)+offs,ybox(1:end-1)+offs,string(1:length(xbox)-1))
text(xdia(1:end-1)+offs,ydia(1:end-1)+offs,string(1:length(xdia)-1))
So the picture above shows how the points are mapped in the two arrays.
The first problem, as you said, is that the second shape has one point less.
Let's assume we add it manually.
It can be easily done by linearly interpolating between any two points of the second picture.
For instance, adding a point between 3 and 4 would yield
xbox = [0 2 2 2 1 0 0];
ybox = [0 0 1 2 2 2 0];
xdia = [4 4.5 5 4.5 4 3 4];
ydia = [0 0.5 1 1.5 2 1 0];
figure
hold on, box on
plot(xbox,ybox,'bsquare-')
plot(xdia,ydia,'bsquare-')
axis equal padded
offs = 0.08;
text(xbox(1:end-1)+offs,ybox(1:end-1)+offs,string(1:length(xbox)-1))
text(xdia(1:end-1)+offs,ydia(1:end-1)+offs,string(1:length(xdia)-1))
So let's try to animate the transformation with your method.
n = 5;
x_anim = zeros(n,length(xbox));
y_anim = zeros(n,length(ybox));
for i = 1:n
x_anim(i,:) = xbox+(i-1)*(xdia-xbox)/(n-1);
y_anim(i,:) = ybox+(i-1)*(ydia-ybox)/(n-1);
end
figure
hold on, box on
axis equal padded
offs = 0.08;
for k = 1:n
if k == 1 || k == n
c = 'bsquare-';
else
c = 'rsquare--';
end
plot(x_anim(k,:),y_anim(k,:),c)
text(x_anim(k,1:end-1)+offs,y_anim(k,1:end-1)+offs,string(1:length(xbox)-1))
end
So. it does work, but the shape does not remain a square throughout the transformation, because of the way the point are mapped.
That could be easily solved if youmove the indexing of the points of the final shape clockwise once, so that every half-side step in the first shape coincides with a half-side step in the final shape.
xbox = [0 2 2 2 1 0 0];
ybox = [0 0 1 2 2 2 0];
xdia = [3 4 4.5 5 4.5 4 3 ];
ydia = [1 0 0.5 1 1.5 2 1 ];
n = 5;
x_anim = zeros(n,length(xbox));
y_anim = zeros(n,length(ybox));
for i = 1:n
x_anim(i,:) = xbox+(i-1)*(xdia-xbox)/(n-1);
y_anim(i,:) = ybox+(i-1)*(ydia-ybox)/(n-1);
end
figure
hold on, box on
axis equal padded
offs = 0.08;
for k = 1:n
if k == 1 || k == n
c = 'bsquare-';
else
c = 'rsquare--';
end
plot(x_anim(k,:),y_anim(k,:),c)
text(x_anim(k,1:end-1)+offs,y_anim(k,1:end-1)+offs,string(1:length(xbox)-1))
end
I am not sure this is what you were looking for, hope it helped.
More Answers (0)
See Also
Categories
Find more on Interactive Control and Callbacks in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!