3D filled line plot - matlab

I have a matrix for contact positions and these positions are linear, therefore I can easily plot the contact positions within MATLAB and come out with the x amount of lines. At the moment I am plotting within a 2D graph.
for j= 1:5
for k= 1:20
Yijk(j,:,k)=x*tan_helix+one_array*(k-P)*Pb/P+one_array*(j-(L+1)/2)*Pb;
end
end
x_axis = linspace(0,b*1000, N+1);
figure;
for j=1:zPairs;
hold on
plot(x_axis,Yijk(j,:,k))
hold off
end
The above is only a small section of a large coding so all variables and parameters are stated else where.
Below is the graph this simply creates with a 2D graph:
What I wish to do is plot the correspoding contact to each of these positions, contact only occurs at positions > 0 and therefore will only occur along the lines plotted above. Therefore the plot will need to be in a 3D format and I am assuming that the lines will be plotted initially, then the contact_force and then a fill command as such - but I may be wrong.
What I am aiming to create is something similar to:
If any one has any guidance or tips it will be greatly appreciated as I am getting nowhere.
Please note the contact_force is also a matrix of the same dimensions as the contact positions.
for j = 1:zPairs
Xx = linspace(0,b*1000,N+1);
Yy = Yijk(j,:,1);
n = length(Xx);
Zz = contact_force(j,:,1);
Xp = zeros(2*n,1);
Yp = zeros(2*n,1);
Xp(1:N+1) = Xx;
Xp(N+2:2*(N+1)) = Xx(N+1:-1:1);
Yp(1:N+1) = Yy;
Yp(N+2:2*(N+1)) = Yy(N+1:-1:1);
Zp(1:N+1) = 0;
Zp(N+2:2*(N+1)) = Zz(N+1:-1:1);
figure(12);
hold on
patch(Xp,Yp,Zp,'c');
title('Zone of Contact');
hold off
end
The above code works great, but only creates one graph as it is for (j,:,1). I would like to change this so as that it is for (j,:,k) and k number of graphs are created. How would I set up this for loop ?

I wrote a little MATLAB code to test it out. This program creates a polygon on top of a 2D line. fill3 or patch functions are what you are looking for.
a = 2;
b = 1;
X = 0:10;
Y = a*X + b;
n = length(X);
Z = rand(n,1)*2+1;
Xp = zeros(2*n,1);
Yp = zeros(2*n,1);
Xp(1:n) = X;
Xp(n+1:2*n) = X(n:-1:1);
Yp(1:n) = Y;
Yp(n+1:2*n) = Y(n:-1:1);
Zp(1:n) = 0;
Zp(n+1:2*n) = Z(n:-1:1);
fill3(Xp,Yp,Zp,'c');

Related

Problem plotting 2d numerical solution of wave equation

I am trying to make an animation of the 2d wave equation in MATLAB (R2020a). So far I believe that the finite difference method is implemented correctly. However; when I try to plot these values using the "surf" command in matlab it does not work.
This is my script so far:
clear
clc
close all
VL = 2;
tMin = 0;
tMax = 30;
xMin = -10;
xMax = 10;
yMin = -10;
yMax = 10;
Nt = 100;
Nx = 100;
Ny = 100;
t = linspace(tMin,tMax,Nt);
x = linspace(xMin,xMax,Nx);
y = linspace(yMin,yMax,Ny);
DeltaT = t(2) - t(1);
DeltaX = x(2) - x(1);
DeltaY = y(2) - y(1);
CFX = ((VL)*(DeltaT/DeltaX))^2;
CFY = ((VL)*(DeltaT/DeltaY))^2;
u = zeros(Nt,Nx,Ny);
[X,Y] = meshgrid(x,y);
u(1,:,:) = Initial(t(1),X,Y);
u(2,:,:) = Initial(t(1),X,Y) + InitialV(t(1),X,Y);
for i=3:Nt
for j=1:Nx
for k=1:Ny
if(j==1 || j==Nx || k==1 || k==Ny)
u(i,j,k) = 0;
else
u(i,j,k) = 2*u(i-1,j,k) - u(i-2,j,k) + (CFX)*(u(i-1,j+1,k) - 2*u(i-1,j,k) + u(i-1,j-1,k)) + (CFY)*(u(i-1,j,k+1) - 2*u(i-1,j,k) + u(i-1,j,k-1));
end
end
end
end
the functions: Initial and initialV are u(0,x,y) and ut(0,x,y) respectively.
I believe this code works for finding the function values for u however when I try to plot the results as follows:
for i=1:Nt
figure
clf
hold on
surf(X,Y,u(i,:,:))
end
I get an error saying Z must be a matrix... In my opinion this seems strange, slicing a 3d array results in a 2d matrix.
How can I make an animation that shows u as a function of x and y?
Thanks in advance! any help is greatly appreciated
P.S. I am new to this page so if I am neglecting certain guidelines when it comes to sharing code please let me know and I will adjust it.
Another way to remove the singleton dimension of your u array would be to use squeeze() as it doesn't need any information on the remaining size of the array.
for i = 1:Nt
figure
clf
hold on
surf(X, Y, squeeze(u(i, :, :)))
end
To force u(i,:,:) to match the 100 by 100 dimensions of X and Y try using the reshape() function.
for i=1:Nt
figure
clf
hold on
surf(X,Y,reshape(u(i,:,:),[100 100]));
end

Simulating a ship sailing in water wave in Matlab

I have a project in which I have to simulate a ship which is sailing in a water wave. I have decided to do it in by 3D surface plot. I have created water waves but I'm having trouble making the ship which should sit right at the centre of the plot. Following is my water wave simulation code:
clc; clear all ;
x_l = -20;
x_r = 20;
y_l = -20;
y_r = 20;
ds = 0.5;
A = 1;
k = 1;
dt = 0.05;
w = 1;
x = [x_l:ds:x_r];
y = [y_l:ds:y_r];
[X,Y] = meshgrid(x,y);
for i = 1:100
Z = A*sin(k*Y+(w*i/2));
CO(:,:,1) = 0.3*ones((y_r-y_l)/ds + 1) + 0.3*cos(k*Y+(w*i/2));
CO(:,:,2) = 0.3*ones((y_r-y_l)/ds + 1) + 0.3*cos(k*Y+(w*i/2));
CO(:,:,3) = 0.7*ones((y_r-y_l)/ds + 1) + 0.3*cos(k*Y+(w*i/2));
surf(X,Y,Z,CO);
hold on;
shading interp;
xlim([x_l x_r]);
ylim([y_l y_r]);
zlim([y_l y_r]);
Zc = sqrt(X.^2+Y.^2);
surf(X,Y,Zc);
shading interp;
hold off;
drawnow;
pause(dt);
end
Please guide me in the right direction if I'm doing this in the wrong way.
I just made a simple model of a sailing boat that is made up of quads. This allows us to use the surf function to draw it too. This should just serve as a starting point to see how you could do it. But keep in mind that this is probably not the best way of doing it. As a comment already mentioned, MATLAB is really not the best software for this, Blender is probably a way better option, but still we can make a nice little ship.
The first step is creating the fixed model in a local coordinate system. The NaNs are just to separate the different components of the ship, because otherwise we would have additional quads connecting e.g. the hull to the sails that would look out of place. (If it is unclear, just replace them with some arbitrary coordinates to see what is happening.)
Then to give it some movement, we have to incorporate the temporal component. I just added a slight rocking motion in the y-z plane as well as a little bouncing in the z-direction to give it the look of a ship moving through waves. I made sure to use the same frequency w/2 as you already used for the waves. This is important to make the boat to apper to rock with the waves.
clc; clear all ;
x_l = -20;
x_r = 20;
y_l = -20;
y_r = 20;
ds = 0.5;
A = 1;
k = 1;
dt = 0.05;
w = 1;
x = [x_l:ds:x_r];
y = [y_l:ds:y_r];
[X,Y] = meshgrid(x,y);
%sailboat
U = 0.7*[0,-1,-1,1,1,0;...%hull
0,0,0,0,0,0; NaN(1,6);...
0,0,NaN,0,0,NaN; %sails
0,-1,NaN,0,0,NaN];
V = 0.7*[3,1,-3,-3,1,3;%hull
1,1,-2,-2,1,1; NaN(1,6);...
3,0,NaN,0,-3,NaN; %sails
3,-1,NaN,0,-3,NaN];
W = 0.7*[1,1,1,1,1,1;%hull
0,0,0,0,0,0; NaN(1,6);...
2,6,NaN,7,2,NaN; %sails
2,2,NaN,2,2,NaN];
H = ones(2,6);
S = ones(3,3);
C = cat(3,[H*0.4;S*1,S*1],[H*0.2;S*0.6,S*0],[H*0;S*0.8,S*0]);
for i = 1:100
clf;
hold on;
Z = A*sin(k*Y+(w*i/2));
CO(:,:,1) = 0.3*ones((y_r-y_l)/ds + 1) + 0.3*cos(k*Y+(w*i/2));
CO(:,:,2) = 0.3*ones((y_r-y_l)/ds + 1) + 0.3*cos(k*Y+(w*i/2));
CO(:,:,3) = 0.7*ones((y_r-y_l)/ds + 1) + 0.3*cos(k*Y+(w*i/2));
surf(X,Y,Z,CO);
xlabel('x'); ylabel('y');
% rocking the boat
angle = 0.5*cos(w*i/2); %control rocking
Vs = V*cos(angle) - W*sin(angle);
Ws = V*sin(angle) + W*cos(angle) + 0.4 + 0.8*cos(w*(i - 0.5 * 2*pi)/2);%control amplitude
surf(U,Vs,Ws,C);
camproj('perspective');
xlim([x_l x_r]);
ylim([y_l y_r]);
zlim([y_l y_r]);
Zc = sqrt(X.^2+Y.^2);
%surf(X,Y,Zc);
%view([-100,20])
az = interp1([1,100],[-30, -120],i);
el = interp1([1,100],[1,30],i);
view([az,el]);
axis([-20,20,-20,20,-20,20]*0.5);
shading interp;
hold off;
drawnow;
pause(dt);
end
EDIT: The key to creating these "models" is knowign how surf works: Given some matrices X,Y,Z, each 2x2 submatrix of these matrices define the vertices of a quadrilateral. So the idea is decomposing our models into quadrilaterals (and adding NaN in this matrix where we do not want any quadrilaterals in between). Check out following snippet that shows just the hull and the quadrilaterals involved. The displayed numbers show the index of the coordinates of the corresponding points in the coordinate matrices U,V,W. I added a small number e that pulls the seams apart so that you can actually see the quadrilaterals. Set it to 0 to see the original shape:
e = 0.2; %small shift to visualize seams
%sailboat
U = 0.7*[0-e,-1-e,-1-e,1+e,1+e,0+e;...%hull
0-e,0-e,0-e,0+e,0+e,0+e];
V = 0.7*[3+e,1,-3,-3,1,3+e;%hull
1+e,1,-2,-2,1,1+e];
W = 0.7*[1,1,1,1,1,1;%hull
0,0,0,0,0,0];
surf(U,V,W);
axis equal
view([161,30])
hold on
for i=1:2
for j=1:6
text(U(i,j),V(i,j),W(i,j),[num2str(i),',',num2str(j)]); %plot indices of points
end
end
xlabel('U')
ylabel('V')
zlabel('W')
title('i,j refers to the point with coordinates (U(i,j),V(i,j),W(i,j))')
hold off

How to use surf to plot sphere function in matlab

I'm trying to plot sphere function below, But I'm getting wrong result
Here is the code I'm using
x1 = [-10:1:10];
x2 = [-10:1:10];
y = zeros(1,21);
for i = 1:21
y(i) = sphere([x1(i) x2(i)]);
end
Y = meshgrid(y);
surf(x1,x2,Y);
colormap hsv;
sphere.m
function [y] = sphere(x)
d = length(x);
sum = 0;
for i = 1:d
sum = sum + x(i)^2;
end
y = sum;
end
For the sake of completness your code is not working because you are only evaluating your function on the pairs (x,x) for some x \in [-10,10] so you don't cover the whole domain. It would work with this:
x1 = [-10:1:10];
x2 = [-10:1:10];
y = zeros(1,21);
for i = 1:21
for j=1:21
Y(i,j) = sphere([x1(i) x2(j)]);
end
end
surf(x1,x2,Y);
colormap hsv;
or way faster (because you should always avoid unnecessary loops for computation time reasons):
x1 = meshgrid([-10:1:10]);
x2 = x1';
Y = x1.^2+x2.^2;
surf(x1,x2,Y)
sphere(10)
It is a MatLab built in function.
Please enjoy responsibly.
If you need to see the source code use: edit sphere or help sphere when your sphere function is not on the path.

Speed up creation of impoint objects

I have to create some draggable points on an axes. However, this seems to be a very slow process, on my machine taking a bit more than a second when done like so:
x = rand(100,1);
y = rand(100,1);
tic;
for i = 1:100
h(i) = impoint(gca, x(i), y(i));
end
toc;
Any ideas on speed up would be highly appreciated.
The idea is simply to provide the user with the possibility to correct positions in a figure that have been previously calculated by Matlab, here exemplified by the random numbers.
You can use the the ginput cursor within a while loop to mark all points you want to edit. Afterwards just click outside the axes to leave the loop, move the points and accept with any key.
f = figure(1);
scatter(x,y);
ax = gca;
i = 1;
while 1
[u,v] = ginput(1);
if ~inpolygon(u,v,ax.XLim,ax.YLim); break; end;
[~, ind] = min(hypot(x-u,y-v));
h(i).handle = impoint(gca, x(ind), y(ind));
h(i).index = ind;
i = i + 1;
end
Depending on how you're updating your plot you can gain a general speedup by using functions like clf (clear figure) and cla (clear axes) instead of always opening a new figure window as explained in this answer are may useful.
Alternatively the following is a very rough idea of what I meant in the comments. It throws various errors and I don't have the time to debug it right now. But maybe it helps as a starting point.
1) Conventional plotting of data and activating of datacursormode
x = rand(100,1);
y = rand(100,1);
xlim([0 1]); ylim([0 1])
f = figure(1)
scatter(x,y)
datacursormode on
dcm = datacursormode(f);
set(dcm,'DisplayStyle','datatip','Enable','on','UpdateFcn',#customUpdateFunction)
2) Custom update function evaluating the chosen datatip and creating an impoint
function txt = customUpdateFunction(empt,event_obj)
pos = get(event_obj,'Position');
ax = get(event_obj.Target,'parent');
sc = get(ax,'children');
x = sc.XData;
y = sc.YData;
mask = x == pos(1) & y == pos(2);
x(mask) = NaN;
y(mask) = NaN;
set(sc, 'XData', x, 'YData', y);
set(datacursormode(gcf),'Enable','off')
impoint(ax, pos(1),pos(2));
delete(findall(ax,'Type','hggroup','HandleVisibility','off'));
txt = {};
It works for the, if you'd just want to move one point. Reactivating the datacursormode and setting a second point fails:
Maybe you can find the error.

Matlab smooth a 3d mesh plot

Hi I have a set of data A with each element corresponding to an x and y combination. When I plot this dat using mesh I get a graph with many spikes on it. This is not unnexpected but I would like a way to smooth these out to get a smooth surface.
I've tried to use the smooth3 command but cannot figure out how to make the suitable input.
Any help would be appreciated. Thanks
This is how my data is generated.
function v = f(x,y) % Not actual function
return x*rand()+y*rand()
end
x = 0.05:0.01:0.95;
y = 0.05:0.01:0.95;
o = zeros(length(x),length(y));
A = zeros(length(x), length(y));
for k = 1:5
for i = 1:length(x)
for j = 1:length(y)
o(i,j) = f([x(i), y(j)]);
end
end
A= A+o;
end
A = A/5;
This is what produces the plot.
[X,Y] = meshgrid(x);
mesh(A)
my be you can try a convolution of your variable A with a filter(the following is an example of a Gaussian filter).
C = conv2(A,fspecial('gaussian', hsize, sigma));
check conv2 and fspecial in matlab help