Plotting spheres around given coordinates in 3D in Matlab - matlab

I am working on model of an object sliding on some rough surface consisting of spheres with a small random variance in position. In the graphics I want the spheres to be of a given radius, however when using scatter3 this wont work, the sizes of the circles change when I zoom in or out. I could easily solve this in 2D by using "rectangle"-function instead but for 3D this doesn't work.
Is there a better function for plotting spheres around points?
I have read this https://se.mathworks.com/matlabcentral/answers/101738-how-do-i-specify-the-size-of-the-markers-created-by-the-scatter-plot-in-units-proportional-to-the-da. But it either doesn't work for scatter3 or I do it wrong.
Sizes change when zooming in.
fig = figure(1);
hold on
daspect([1,1,1]);
surface.xnum = 16;
surface.znum = 16;
surface.r = 1;
circlenumber = 0;
for n = 1:surface.xnum
for m = 1:surface.znum
circlenumber = circlenumber + 1;
surface.circlecentre(circlenumber,:) = [n + 0.1*surface.r*randn , 0, m + 0.1*surface.r*randn ];
plt.surface = scatter3(surface.circlecentre(circlenumber, 1),surface.circlecentre(circlenumber, 2),surface.circlecentre(circlenumber, 3), 850*surface.r,'filled','r','MarkerEdgeColor','k');
end
end
Relevant part of the code. Setting coordinates to center of the spheres and plotting spheres around them.

This was the solution i found by the hint from Ander Biguri. I used surf to plot spheres instead of scatter3.
fig = figure(1);
hold on
daspect([1,1,1]);
colormap summer
shading interp % removes the lines in surfplot
surface.xnum = 8;
surface.znum = 8;
surface.r = 0.75;
circlenumber = 0;
for m = 1:surface.xnum
for n = 1:surface.znum
circlenumber = circlenumber + 1;
surface.circlecentre(circlenumber,:) = [m + 0.1*surface.r*randn ,0 , n + 0.1*surface.r*randn ];
[x,y,z] = sphere; surf(x*surface.r+m*2*surface.r+0.1*surface.r*randn, y*surface.r, z*surface.r+n*2*surface.r+0.1*surface.r*randn,'Edgecolor','none');
end
end

Related

Different 3d plots of (n,n,m) matrix : MATLAB

I have a matrix a=360x360x2048
now I want to plot them in 3d
My attempt
x = 1:size(a,2);
y = 1:size(a,1);
z = 1:size(a,3);
How to plot this in 3d
Now I want to 3d plot this
now I want to plot them all
Instead of using imagesc() which only works in 2D, you could try to use scatter() and its 3D extension scatter3().
nslices = 100;
nelems = 360;
A = rand(nelems, nelems, nslices); % your matrix
% Marker settings for scatter plot
mrkrSize = 10;
mrkr = '.';
figure
hold on
view(3)
for i = 1:nslices
% Get the i-th matrix
Aslice = A(:, :, i);
idx = find(Aslice);
[x, y] = ind2sub(size(Aslice), idx);
z = i.*ones(size(x));
scatter3(x, y, z, mrkrSize, Aslice(idx), 'Marker', mrkr);
end
Using Slices of a Matrix to Create 3D Plot
Given that I saw the question before the multiple edits. Using the slice() function may help to plot the 3D matrix as slices in a 3D plot. The slice() function takes three additional inputs along with the matrix/volume to be plotted. The following three inputs dictate the method used to slice the matrix. In this example, slicing was done so that you can have a set of xy-planes that are stacked along the z-axis.
%Generating a random test array%
X_Dimension = 360; Y_Dimension = 360; Z_Dimension = 5;
Volume = rand(X_Dimension,Y_Dimension,Z_Dimension);
%Configuring the slicing method%
X_Slice = [];
Y_Slice = [];
Z_Slice = 1:size(Volume,3);
%Plotting slices of array%
Slices = slice(Volume,X_Slice,Y_Slice,Z_Slice);
xlabel("x"); ylabel("y"); zlabel("z");
%Removing edge lines%
for Slice = 1: length(Slices)
Slices(Slice).EdgeAlpha = 0;
end
%Angle of 3D plot and colorbar%
Angle = 72; Elevation = 10;
view(Angle, Elevation);
colorbar
Ran using MATLAB R2019b

Is there a matlab function(s) I can use to create a realistic diagram of the I.S.S?

As part of a project I am undertaking at the moment, I have to solve the two-body problem of the international space station orbiting the Earth. I have managed to approximate this so far by using the sphere/surf function, however, I was wondering if there was any way I could create a more realistic figure representing the ISS? Unfortunately,this project has to be done solely through MATLAB so I cannot use any other tools which may provide better visualisation
NASA has 3D models of many objects, including the ISS, which can be found here. This file can be converted to an STL however you want, I found this random website which worked for me.
In Matlab, you can read in this file via
stl = stlread('isscombined.stl');
V = stl.Points;
F = stl.ConnectivityList
Then, you can plot it using
p = patch('vertices',V,'faces',F,'FaceColor',[.8 .8 .8]);
and then you can update the object with new vertex positions as the station orbits the Earth. Obviously, you can also scale the object by multiplying the vertices by some amount. If you don't want the facet edges plotted, you can also add 'EdgeAlpha', 0 to your patch options.
Here's a simple example which shows the ISS orbiting around a sphere
% Note: not to scale
ISS_radius = 2; % distance from center of Earth
RE = 1; % radius of earth
theta = 0:.05:2*pi;
x = ISS_radius*cos(theta);
y = ISS_radius*sin(theta);
stl = stlread('isscombined.stl');
r = .01; % scaling factor
V = stl.Points * r;
V = V - mean(V); % center at origin
F = stl.ConnectivityList;
figure; hold on;
plot3(x,y,zeros(numel(theta)),'--');
[X,Y,Z] = sphere(50);
surf(RE*X,RE*Y,RE*Z,'FaceColor',[0 0 .8],'EdgeAlpha',0);
p = patch('Vertices', V*r, 'Faces', F, 'FaceColor', [0 0 0], 'EdgeAlpha', 0);
axis equal;
set(gca,'View',[200 13])
grid on;
counter = 1;
while true
p.Vertices = V + [x(counter), y(counter), 0];
pause(0.01);
drawnow
counter = mod(counter + 1, numel(theta)) + 1;
axis([-1 1 -1 1 -1 1]*ISS_radius*1.2)
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 add multiple cylinders to a surface in matlab

I am trying to add multiple cylinders to the surface in order to 3D print the model. I want to remove the points of the surface that fall within the cylinder.
The following is the code used to generate the surface
%% Generate Clebsch %%
CubeSize = 10;
Thickness = 0.1;
min = -CubeSize/2;
max = CubeSize/2;
v = linspace(min,max,200);
[x, y, z] = meshgrid(v);
a = sqrt(5);
c = sqrt(2);
figure(111)
clebsch_surface = 2*c*y.^3+2*x.^2.*z-8*y.^2.*z+3*c*y.*z.^2-z.^3-2*x.^2+8*y.^2-10*c*y.*z+3*z.^2+3*c*y-3*z+1;
fv = isosurface(x,y,z,clebsch_surface,0);
[f,v] = isosurface(x,y,z,clebsch_surface,0);
p = patch(fv);
isonormals(x,y,z,clebsch_surface,p);
p.FaceColor = 'red';
p.EdgeColor = 'none';
view([-65,20]);
camlight left;
lighting gouraud;
axis tight;
Then I need to find the lines that fall on the cylinders, so I have 27 formulas to determine these cylinders (I show two of the lines below) and then I want to determine a cylinder around each line and then remove the points within the cylinder of the surface and then convert the surface with the cylinders to a STL file
%% Generate the cylinders
for i=1:100
a17(i,1) = 11/(a*c+4*c)*s(i)+3/(a*c+2*c);
a17(i,2) = 5*s(i)/(a*c)-1/(a*c+2*c);
a17(i,3) = s(i);
a18(i,1) = (3/2*a*c+3*c)*s(i)-(a*c/2+2*c);
a18(i,2) = -s(i)/(a*c-2*c)+a*c/2;
a18(i,3) = s(i);
end
R = 0.05;
N = 500;
[a17X,a17Y,a17Z]=cylinder2P(R,N,[a17(1,1) a17(1,2) a17(1,3)],[a17(100,1) a17(100,2) a17(100,3)]);
[a18X,a18Y,a18Z]=cylinder2P(R,N,[a18(1,1) a18(1,2) a18(1,3)],[a18(100,1) a18(100,2) a18(100,3)]);

How to plot points on several concentric circles in sequence?

I want to plot several points on several concentric circles just like this:
The number of points on different circles are same and to be determined. The difference of radius are same.
But I face the problem that if I want to use the for function, I define i = 1:total number of points. I don't know how to select correct angle value. Can anyone help me?
Here is the code that I wrote:
R_steplength = 1; %difference of radius
angle_point = 20; %total number of points on one circle
max_R = 4; %outer radius of circle
central_x = 1; % origin of concentric circle
central_y = 1;
total_circle_points = (max_R/R_steplength) * angle_point; %calculate total
points
fin_x= zeros(1, total_circle_points); %define output points position
fin_y = zeros(1, total_circle_points);
for i = 1:total_circle_points
for j = 1:angle_point
if rem(i+1, 20)~= 1
k = floor(i/20);
angles = linspace(0,2*pi,angle_point);
fin_x(i) = R_steplength*(k+1)*cos(angles(j))+central_x;
fin_y(i)= R_steplength*(k+1)*sin(angles(j))+central_y;
else
fin_x(i) = central_x + R_steplength*(k+2);
fin_y(i) = central_y + R_steplength*(k+2);
end
plot(fin_x(:),fin_y(:),'ro')
end
end
You can use polarplot for that:
ax = polaraxes; % create polar axes
% calculate all points locations:
[angles,rad] = meshgrid(0:angle_point:360,1:R_steplength:max_R);
polarplot(ax,deg2rad(angles),rad,'r.') % plot all the points
ax.GridColor = 'k'; % set grid color to black
ax.GridAlpha = 1;
ax.ThetaAxis.TickValues = 10:20:360; % set radius grid between the points
ax.RAxis.TickValues = 1.5:R_steplength:(max_R+0.5); % set circles between the points
ax.RAxis.Limits = [0 max_R+0.5]; % show the outer circle
Here I use the axes grid to draw the circles. If this is not needed you can just write:
[angles,rad] = meshgrid(0:angle_point:360,1:R_steplength:max_R);
polarplot(ax,deg2rad(angles),rad,'r.') % plot all the points