How to morph a shape into another

31 views (last 30 days)
UH
UH on 3 Aug 2023
Commented: UH on 4 Aug 2023
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

Accepted Answer

Davide Masiello
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.
  1 Comment
UH
UH on 4 Aug 2023
Thank you for your detailed response. It is great solution. I have to keep track of the order of coordinates to have the desired transition. I will use the same reference nodes. and interpolate between the others. I will update further if I have any more development.

Sign in to comment.

More Answers (0)

Categories

Find more on Interactive Control and Callbacks in Help Center and File Exchange

Products


Release

R2023a

Community Treasure Hunt

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

Start Hunting!