Generate equidistant points on a sphere [MATLAB] - matlab

I want to generate equidistant points on a sphere (surface of the sphere). I have come up with this code.
n = 30; % number of points
r = 10; % radius of the sphere
thetha = 0:pi/(n/2):2*pi;
phi = -pi:2*pi/n:pi;
xp = r.*sin(phi).*cos(thetha);
yp = r.*sin(thetha).*sin(phi);
zp = r.*cos(phi);
figure;plot3(xp,yp,zp,'*')
But this is what I get
Can anyone tell where what mistake I am making in my code?

You're only generating one path: a figure eight combination of a single closed circle in the x-y plane with single cosine along the z.
To get a full sphere shape, permutations of the two paths must be taken. This can be accomplished with meshgrid:
[t,p] = meshgrid(thetha,phi);
xp = r.*sin(p).*cos(t);
yp = r.*sin(t).*sin(p);
zp = r.*cos(p);
plot3(xp,yp,zp,'-*');
grid('on');
box('on');
axis('square');

Related

Adding mesh to enclosed semicircle MATLAB

I am currently trying to produce a 2D heat transfer analysis on an alloy which has a shape of a semicircle, (and then introduce a heat source on this shape). I found myself unable to produce a mesh for that specific shape, the code below shows what I have done up until now, if anyone could possibly point me in the right direction it would be greatly appreciated!
initially I set up the grid parameters as follows:
%-------------------GRID SETTINGS----------------------%
Sx = 10; %physical width
Sy = 10; %physical height
Nx = 100; %number of points x-axis
Ny = round(Nx*Sy/Sx); %number of points y-axis
Nt = 500;
%-------------------GRID RESOLUTION---------------------%
dx = Sx/(Nx);
dy = Sy/(Ny);
and worked on creating the shape of an enclosed semicircle as below:
%---------------------SHAPE CREATION--------------------%
r1 = 0.07; %radius 1, m
r2 = 5; %radius 2, m
phi = 0:0.01:pi;
x = r2*cos(phi); x = [x,x(1)]; %x coordinates
y = r1*sin(phi); y = [y,y(1)]; %y coordinates
[X, Y] = meshgrid(x,y);
I'd use polar coordinates for your mesh and then visualize the results in cartesian coordinates. Check out the example below, hope this gives you a starting point (not really sure why you applied two different radius (r1, r2) to your x,y coordinates - so I assumed you have a minimal and maximal radius).
Nx = 100;
r1 = 1; %radius 1, m
r2 = 5; %radius 2, m
phi = 0:0.01:pi;
% generate mesh grid in polar coordinates
radius = linspace(r1, r2, Nx/2);
[Radius, Phi] = meshgrid(radius, phi);
heat = Radius.^2; % some "fake" heat data
% plot results (in cartesian coordinates)
mesh(Radius.*cos(Phi), Radius.*sin(Phi), heat)
axis equal
% top view
view([-0.2 90.0])

How to draw a curve line with points between it on the shaded region that situated on the surface of the hemisphere using Matlab?

A hemisphere with shaded region is already formed. Then, planning to form a path or curved line on the shaded region situated on the surface of the hemisphere with points on it. Can't even know what is their latitude or longitude to draw an arc, therefore, any idea on how to obtain the latitude and longitude for the starting and ending point or form a curved line as shown in the figure below?
[x,y,z] = sphere; % Makes a 21-by-21 point sphere
x = x(11:end,:); % Keep top 11 x points
y = y(11:end,:); % Keep top 11 y points
z = z(11:end,:); % Keep top 11 z points
radius = 0.13;
c = [0.36 0 0];
hs = surf(radius.*x + c(1),radius.*y,radius.*z,'FaceColor','yellow','FaceAlpha',.3);
axis equal
xlabel('X');ylabel('Y');zlabel('Z');
% Putting the ranges for the elevation and azimuth
minAzimuth = 0;
maxAzimuth = 180;
minElevation = 0;
maxElevation = 80;
% Compute angles
phi = atan2d(y,x);
theta = acosd (z);
% Highlighting logic (Shading the subset of the hemisphere)
ind = (phi >= minAzimuth & phi <= maxAzimuth) & (theta >= minElevation & theta <= maxElevation); % Find those indices
x2 = x; y2 = y; z2 = z; % Make a copy of the hemisphere coordinates
x2(~ind) = NaN; y2(~ind) = NaN; z2(~ind)=NaN; % Set those out of boundary to NaN
hold on;
surf(radius.*x2+c(1),radius.*y2,radius.*z2,'FaceColor','red');
Use spherical coordinates:
As you did with your sphere segment, it is easier to define your line in spherical coordinates first, then convert to cartesian when it's time to display.
If you add this after your own code:
% set line parameters
np = 10 ; % number of points
LineAziStart = 17 ; % Starting azimuth
LineAziStop = 122 ; % Ending azimuth
LineElevation = 49 ; % Elevation
% generate spherical coordinates
azp = linspace(deg2rad(LineAziStart),deg2rad(LineAziStop),np).' ;
elp = zeros(np,1) + deg2rad(LineElevation) ;
rp = zeros(np,1) + radius ;
% convert to cartesian
[xp,yp,zp]=sph2cart(azp,elp,rp) ;
% adjust coordinates for center of the sphere
xp = xp + c(1) ;
yp = yp + c(2) ;
zp = zp + c(3) ;
% display
hp = plot3(xp,yp,zp,'g','LineWidth',2,'Marker','x') ;
You'll obtain a line parallel to the latitude you set:
You can adjust where the line starts, stops, and it elevation by adjusting the first parameters on top of the code (make them match your own values).
Edit:
To explain the spherical coordinate generation:
To get a line in 3D you need a set of 3 coordinates, they can be x/y/z (cartesian referential) or radius/azimuth/elevation (spherical referential).
The constraints for your line are:
Azimuth: (called azp) Has to vary from one value to another. For that I used the statement azp = linspace(deg2rad(LineAziStart),deg2rad(LineAziStop),np).' ;. I recommend you to read the documentation for the linspace function. It will generate a set of np linearly spaced points between LineAziStart and LineAziStop. I also had to use deg2rad because for sperical coordinates you want your angles expressed in radian.
Radius: (called rp) This one is easy. Your line has to be on the surface of the sphere, so all the points of the line will have the same radius value (the radius of the original sphere. We just generate a vector of np points all equal to radius. This is done with rp = zeros(np,1) + radius;.
Elevation: (called elp) Your line has to be parallel to a latitude, so the elevation is also constant for all the points of the line. As with the radius, we generate the set of constant points the same way: elp = zeros(np,1) + deg2rad(LineElevation) ;.
By then you have a set of 3 vectors (rp/azp/elp), which all have the same number of values, and together define a set of point in 3D space, in spherical coordinates. Matlab plotting function requires cartesian coordinates so the last step is just to convert this set of coordinates. This is done with the function sph2cart, which convert rp/azp/elp into xp/yp/zp.
The spherical coordinates we generated were centered on the origin (point 0,0,0,), so the converted cartesian coordinates are also there. The last step is simply to translate these coordinates so they'll be centered on the same point/center than the sphere. After that, your coordinates are ready to be plotted.

Points distribution in n-dimension

How to distribute the points to be like Fig.A
This matlab code for Fig. B :
N = 30; % number of points
r = 0.5; % r = radius
d = 50; % dimension
C_point = 0; % center point
figure, clf
C = ones(1, d) * C_point;
C_rep = repmat( C,N,1);
X = randn(N,d);
s2 = sum(X.^2,2) ;
radius = r * (rand(N,1).^(1/d));
X = X.*repmat(radius./sqrt(s2),1,d) + C_rep;
%% Plot 2D
t = linspace(0, 2*pi, 100);
x = r*cos(t) + C(1);
y = r*sin(t) + C(2);
plot(x,y,'b')
hold on
plot(C(1),C(2),'b.', 'MarkerSize', 10) % center point
hold on
plot(X(:,1), X(:,2),'r.','markersize',10);
axis equal;rotate3d off; rotate3d on;drawnow;shg;
hold on
ax = axis;
Source of the code
What I should change to be like fig. A
The OP's code computes points uniformly distributed within a d-dimensional box, projects those onto a d-dimensional sphere, then samples the radius to move them inside the d-dimensional ball. This is perfect except that the points inside the box, when projected onto the sphere, do not form a uniform distribution on that sphere. If instead you find random points distributed in a Gaussian distribution, you are guaranteed uniform angle distribution.
First compute points with a Gaussian distribution in d dimensions (I do all here with minimal changes to the OP's code):
N = 1000; % number of points
r = 0.5; % r = radius
d = 3; % dimension
C_point = 0; % center point
C = ones(1,d) * C_point;
C_rep = repmat(C,N,1);
X = randn(N,d);
Note that I use randn, not rand. randn creates a Gaussian distribution.
Next we normalize the vectors so the points move to the sphere:
nX = sqrt(sum(X.^2,2));
X = X./repmat(nX,1,d);
These points are uniformly distributed, which you can verify by scatter3(X(:,1),X(:,2),X(:,3)); axis equal and turning the display around (a 2D rendering doesn't do it justice). This is the reason I set d=3 above, and N=1000. I wanted to be able to plot the points and see lots of them.
Next we compute, as you already did, a random distance to the origin, and correct it for the dimensionality:
radius = r * (rand(N,1).^(1/d));
X = X.*repmat(radius,1,d) + C_rep;
X now is distributed uniformly in the ball. Again, scatter3(X(:,1),X(:,2),X(:,3)); axis equal shows this.
However, if you set d=50 and then plot only two dimensions of your data, you will not see the data filling the circle. And you will not see a uniform distribution either. This is because you are projecting a 50-D ball onto 2 dimensions, this simply does not work. You either have to trust the math, or you have to slice the data:
figure, hold on
t = linspace(0, 2*pi, 100);
x = r*cos(t) + C(1);
y = r*sin(t) + C(2);
plot(x,y,'b')
plot(C(1),C(2),'b.', 'MarkerSize', 10) % center point
axis equal
I = all(abs(X(:,3:d))<0.1,2);
plot(X(I,1), X(I,2),'r.','markersize',10);
The I there indexes points that are close to the origin in dimensions perpendicular to the first two shown. Again, with d=50 you will have very few points there, so you will need to set N very large! To see the same density of points as in the case above, for every dimension you add, you need to multiply N by 10. So for d=5 you'd have N=1000*10*10=1e5, and for d=50 you'd need N=1e50. That is totally impossible to compute, of course.

How create asimetric cone in matlab?

I need to create a surface generate by rotation on y axis of shape formed by two curves. I already have the equation for this two curves. Here is the shape
I already create the surface but for simetric cone formed by one of this curve, here is my script:
h=20;
rw=1;
hw=5;
L=25;
r=linspace(rw,L,50);
theta=linspace(0,2*pi,25);
[r,theta] = meshgrid(r,theta);
xx=r.*cos(theta);
yy=r.*sin(theta);
z=sqrt(log(r/rw)*(h^2-hw^2)/log(L/rw)+hw^2); %Fuction of curve
surf(xx,yy,z)
Here is my result
In the other curve is the same fuction (z) but change r,h,L
Thanks for your help,
you should use parameter grids instead of scalars:
% parameters
h=[20 25];
rw=1;
hw=5;
L=[25 30];
nr = 50;
nt = 25;
theta=linspace(0,2*pi,nt);
rmax = linspace(L(1),L(2),floor((nt+1)/2));
% generating **grids** for all parameters
l = [linspace(L(1),L(2),floor((nt+1)/2)) linspace(L(2),L(1),floor((nt)/2))];
hh = [linspace(h(1),h(2),floor((nt+1)/2)) linspace(h(2),h(1),floor((nt)/2))];
[~,thetaGrid] = meshgrid(1:nr,theta);
[~,lGrid] = meshgrid(1:nr,l);
[~,hGrid] = meshgrid(1:nr,hh);
rGrid = zeros(size(thetaGrid));
for ii = 1:floor((nt+1)/2)
rGrid(ii,:) = linspace(rw,rmax(ii),nr);
end
rGrid(ceil((nt+1)/2):end,:) = rGrid(floor((nt+1)/2):-1:1,:);
% set coordinate grids
xx=rGrid.*cos(thetaGrid);
yy=rGrid.*sin(thetaGrid);
z=sqrt(log(rGrid./rw).*(hGrid.^2-hw^2)./log(lGrid./rw)+hw.^2); %Fuction of curve
% plot
surf(xx,yy,z)

How to find vanishing points from vanishing lines?

I'm trying to find vanishing points of vanishing lines to estimate a depth map for a 2D image.
First, I detected the vanishing lines of the 2D image using hough transform. Here is my code in Matlab:
Img =imread('landscape.bmp'); %read the 2D image
%Convert the image to Grayscale
I=rgb2gray(Img);
%Edge Detection
Ie=edge(I,'sobel');
%Hough Transform
[H,theta,rho] = hough(Ie);
% Finding the Hough peaks (number of peaks is set to 5)
P = houghpeaks(H,5,'threshold',ceil(0.2*max(H(:))));
x = theta(P(:,2));
y = rho(P(:,1));
%Vanishing lines
lines = houghlines(I,theta,rho,P,'FillGap',170,'MinLength',350);
[rows, columns] = size(Ie);
figure, imshow(~Ie)
hold on
xy_1 = zeros([2,2]);
for k = 1:length(lines)
xy = [lines(k).point1; lines(k).point2];
% Get the equation of the line
x1 = xy(1,1);
y1 = xy(1,2);
x2 = xy(2,1);
y2 = xy(2,2);
slope = (y2-y1)/(x2-x1);
xLeft = 1; % x is on the left edge
yLeft = slope * (xLeft - x1) + y1;
xRight = columns; % x is on the reight edge.
yRight = slope * (xRight - x1) + y1;
plot([xLeft, xRight], [yLeft, yRight], 'LineWidth',1,'Color','blue');
%intersection of two lines (the current line and the previous one)
slopee = #(line) (line(2,2) - line(1,2))/(line(2,1) - line(1,1));
m1 = slopee(xy_1);
m2 = slopee(xy);
intercept = #(line,m) line(1,2) - m*line(1,1);
b1 = intercept(xy_1,m1);
b2 = intercept(xy,m2);
xintersect = (b2-b1)/(m1-m2);
yintersect = m1*xintersect + b1;
plot(xintersect,yintersect,'m*','markersize',8, 'Color', 'red')
xy_1 = xy;
% Plot original points on the lines .
plot(xy(1,1),xy(1,2),'x','markersize',8,'Color','yellow');
plot(xy(2,1),xy(2,2),'x','markersize',8,'Color','green');
end
Now I need to find the vanishing point to be able to estimate the depth map.
The vanishing point is chosen as the intersection point with the greatest number of intersections around it.
My question, in other words, is how can I find the intersection of a number of lines (vanishing lines) in Matlab? I guess one way to do it is to find the point whose sum of squared distances from all lines is minimal, but not sure how to do that in Matlab?
Any help would be appreciated.
Edit: I tried to find the intersection of the lines, but I could only find the intersection of each a line and the line after it. I don't know how to find the intersection of all the lines?
Here is an example of a picture I am using:
https://www.dropbox.com/s/mbdt6v60ug1nymb/landscape.bmp?dl=0
I am posting a link because I don't have enough reputations to post an image.
A simplistic approach:
You should be able to create an array with all the intersection points between the lines.
Pseudo code:
for i = 1:length(lines)-1
for j = i+1:length(lines)
//add intersection of lines i and j
If you have all the intersections, you could simply take the average.
OR, take the approach written up here:
https://math.stackexchange.com/questions/61719/finding-the-intersection-point-of-many-lines-in-3d-point-closest-to-all-lines
3d can be simplified to 2d :)