How do I visualize the intersection of spheres in MATLAB? - matlab

It seems this question has been asked in a few places (including on SO). I recently came across the need for this when visualizing results of a trilateration problem.
In almost every case, the answer directs the inquiry to look at Wolfram for the math but excludes any code. The math really is a great reference, but if I'm asking a question on programming, some code might help as well. (It certainly is also appreciated when answers to a code question avoid pithy comments like "writing the code is trivial").
So how can one visualize the intersection of spheres in MATLAB? I have a simple solution below.

I wrote a small script to do just this. Feel free to make suggestions and edits. It works by checking if the surface of each sphere falls within the volume of all of the other spheres.
For sphere intersection, it's better (but slower) to use a larger number of faces in the sphere() function call. This should give denser results in the visualization. For the sphere-alone visualization, a smaller number (~50) should suffice. See the comments for how to visualize each.
close all
clear
clc
% centers : 3 x N matrix of [X;Y;Z] coordinates
% dist : 1 x N vector of sphere radii
%% Plot spheres (fewer faces)
figure, hold on % One figure to rule them all
[x,y,z] = sphere(50); % 50x50-face sphere
for i = 1 : size(centers,2)
h = surfl(dist(i) * x + centers(1,i), dist(i) * y + centers(2,i), dist(i) * z + centers(3,i));
set(h, 'FaceAlpha', 0.15)
shading interp
end
%% Plot intersection (more faces)
% Create a 1000x1000-face sphere (bigger number = better visualization)
[x,y,z] = sphere(1000);
% Allocate space
xt = zeros([size(x), size(centers,2)]);
yt = zeros([size(y), size(centers,2)]);
zt = zeros([size(z), size(centers,2)]);
xm = zeros([size(x), size(centers,2), size(centers,2)]);
ym = zeros([size(y), size(centers,2), size(centers,2)]);
zm = zeros([size(z), size(centers,2), size(centers,2)]);
% Calculate each sphere
for i = 1 : size(centers, 2)
xt(:,:,i) = dist(i) * x + centers(1,i);
yt(:,:,i) = dist(i) * y + centers(2,i);
zt(:,:,i) = dist(i) * z + centers(3,i);
end
% Determine whether the points of each sphere fall within another sphere
% Returns booleans
for i = 1 : size(centers, 2)
[xm(:,:,:,i), ym(:,:,:,i), zm(:,:,:,i)] = insphere(xt, yt, zt, centers(1,i), centers(2,i), centers(3,i), dist(i)+0.001);
end
% Exclude values of x,y,z that don't fall in every sphere
xmsum = sum(xm,4);
ymsum = sum(ym,4);
zmsum = sum(zm,4);
xt(xmsum < size(centers,2)) = 0;
yt(ymsum < size(centers,2)) = 0;
zt(zmsum < size(centers,2)) = 0;
% Plot intersection
for i = 1 : size(centers,2)
xp = xt(:,:,i);
yp = yt(:,:,i);
zp = zt(:,:,i);
zp(~(xp & yp & zp)) = NaN;
surf(xt(:,:,i), yt(:,:,i), zp, 'EdgeColor', 'none');
end
and here is the insphere function
function [x_new,y_new,z_new] = insphere(x,y,z, x0, y0, z0, r)
x_new = (x - x0).^2 + (y - y0).^2 + (z - z0).^2 <= r^2;
y_new = (x - x0).^2 + (y - y0).^2 + (z - z0).^2 <= r^2;
z_new = (x - x0).^2 + (y - y0).^2 + (z - z0).^2 <= r^2;
end
Sample visualizations
For the 6 spheres used in these examples, it took an average of 1.934 seconds to run the combined visualization on my laptop.
Intersection of 6 spheres:
Actual 6 spheres:
Below, I've combined the two so you can see the intersection in the view of the spheres.
For these examples:
centers =
-0.0065 -0.3383 -0.1738 -0.2513 -0.2268 -0.3115
1.6521 -5.7721 -1.7783 -3.5578 -2.9894 -5.1412
1.2947 -0.2749 0.6781 0.2438 0.4235 -0.1483
dist =
5.8871 2.5280 2.7109 1.6833 1.9164 2.1231
I hope this helps anyone else who may desire to visualize this effect.

Related

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 plot a complex valued function showing a non-conformal mapping in MATLAB?

I have the function:
f(z) = conj(z) + 0.4*z^2,
Going from a polar grid where 0 < theta < 2pi and between 0.5 < |z| < 2.5 for its two radii. I have no idea where to start as I'm new to MATLAB but I'm trying to make 2 subplots each with two parametric equations for each curve but I've had no success.
Try this code. Swap the definition of f to switch between the polar grid and the transformed grid. I also answered a similar question here.
clear
clc
N = 41;
t = linspace(0, 2*pi, N);
r = linspace(0.5, 2.5, N);
[R,T] = meshgrid(r,t);
Z = R.*exp(T*1i);
% f = Z; %Original mesh
f = conj(Z) + 0.4*Z.^2; %Transformed mesh
U = real(f);
V = imag(f);
%Plot mesh
hold off
plot(U,V,'b-');
hold on
plot(U',V','r-');
xlim([-5,5]);
ylim([-5,5]);
axis equal

Fit plane to N dimensional points in MATLAB

I have a set of N points in k dimensions as a matrix of size N X k.
How can I find the best fitting line through these points? The line will be a plane (hyerpplane) in k dimensions. It will have k coefficients and one bias term.
Existing functions like fit seem to be usable only for points in 2 or 3 dimension.
You can fit a hyperplane (or any lower dimensional affine space) to a set of D dimensional data using Principal Component Analysis. Here's an example of fitting a plane to a set of 3D data. This is explained in more detail in the MATLAB documentation but I tried to construct the simplest example I could.
% generate some random correlated data
D = 3;
mu = zeros(1,D);
sqrt_sig = randn(D);
sigma = sqrt_sig'*sqrt_sig;
% generate 50 points in a D x 50 matrix
X = mvnrnd(mu, sigma, 50)';
% perform PCA
coeff = pca(X');
% The last principal component is normal to the best fit plane and plane goes through mean of X
a = coeff(:,D);
b = -mean(X,2)'*a;
% plane defined by a'*x + b = 0
dist = abs(a'*X+b) / norm(a);
mse = mean(dist.^2)
Edit: Added example plot of results for D = 3. I take advantage of the orthogonality of the other principal components here. Ignore the code if you want it's just to demonstrate that the plane does in fact fit the data pretty well.
% plot in 3D
X0 = bsxfun(#minus,X,mean(X,2));
b1 = coeff(:,1); b2 = coeff(:,2);
y1 = b1'*X0; y2 = b2'*X0;
y1_min = min(y1); y1_max = max(y1);
y1_span = y1_max - y1_min;
y2_min = min(y2); y2_max = max(y2);
y2_span = y2_max - y2_min;
pad = 0.2;
y1_min = y1_min - pad*y1_span;
y1_max = y1_max + pad*y1_span;
y2_min = y2_min - pad*y2_span;
y2_max = y2_max + pad*y2_span;
[y1_m,y2_m] = meshgrid(linspace(y1_min,y1_max,5), linspace(y2_min,y2_max,5));
grid = bsxfun(#plus, bsxfun(#times,y1_m(:)',b1) + bsxfun(#times,y2_m(:)',b2), mean(X,2));
x = reshape(grid(1,:),size(y1_m));
y = reshape(grid(2,:),size(y1_m));
z = reshape(grid(3,:),size(y1_m));
figure(1); clf(1);
surf(x,y,z,'FaceColor','black','FaceAlpha',0.3,'EdgeAlpha',0.6);
hold on;
plot3(X(1,:),X(2,:),X(3,:),' .');
axis equal;
axis vis3d;
Edit2: When I say "principal component" I'm being a bit sloppy (or just plain wrong) with the wording. I'm actually referring to the orthogonal basis vectors that the principal components are expressed in.
Here's a simpler solution, that just uses MATLAB's \ operator. We start with defining a plane in k dimensions:
% 0 = a + x(1) * b(1) + x(2) * b(2) + ... + x(k) * 1
k = 8;
a = randn(1);
b = randn(k-1,1);
(note that we assume b(k)=1, you can always multiply the plane parameters by any value without changing the plane).
Next we generate N random points within this plane:
N = 1000;
x = rand(N,k-1);
x(:,k) = -(a + x * b);
...sorry, it's not the best way to generate random points on the plane, but it's good enough for the demonstration here. Add noise to the points:
x = x + 0.05*randn(size(x));
To find the parameters of the plane, we solve the system of equations
% a + x(1:k-1) * b == -x(k)
in the least-squares sense. a and b are the unknowns there. We can rewrite the left-hand side as [1,x(1:k-1)] * [a;b]. If we have a matrix equation M*p=v we can solve for p by writing p=M\v:
p = [ones(N,1),x(:,1:k-1)]\(-x(:,k));
disp(['ground truth: [a,b,1] = ',mat2str([a,b',1],3)]);
disp(['estimated : [a,b,1] = ',mat2str([p',1],3)]);
This gives as output:
ground truth: [a,b,1] = [-1.35 -1.44 -1.48 1.17 0.226 -0.214 0.234 -1.59 1]
estimated : [a,b,1] = [-1.41 -1.38 -1.43 1.14 0.219 -0.195 0.221 -1.54 1]
The less noise or the more points in the dataset, the smaller the error will be of course!

How to generate random positions with distance between them inside the hexagon?

I am trying to create N random pairs of points (N = 50) of a given distances, inside a 500 meters hexagon. The distance D created by using (dmax - dmin).*rand(N,1) + dmin, with dmin = 10 and dmax = 100 in Matlab. I understant that the first I have to generate a set of points ([x1 y1]) that have at least distance D from the main hexagon border, then generate the second set of points ([x2 y2]) that have exact distance D from the first set. But sometime I got the problem with the second point outside of hexagon, because if the first position on the hexagol border and plus Ddisance, then the second position is outside of hexagon (I mean that I want to generate random pair position inside of hexagol). Could anybody help me in generating this kind of scenario and fix the problem? Thanks.
For example as
R = 500; % hexagol radius
N = 50; % number pair positions
d_min = 10; % minimum distance
d_max = 100; % maximum distance
D = (d_max - d_min).*rand(N,1) + d_min; % randomly distance
X = [0,0]; % hexagol center
j=0;
while j < N
j=j+1;
theta(j)=2*pi*rand(1,1);
u= rand()+ rand();
if u < 1
r(j) = R * u;
else
r(j) = R * (2 - u);
end
% to create the first position
x1(j)=r(j)*cos(theta(j)) + X(1,1); % first x positions
y1(j)=r(j)*sin(theta(j)) + X(1,2); % first y positions
end
% to create the second position
x2(j) = x1(j) + D(j); % second x positions
y2(j) = y1(j) + D(j); % second y positions
This is quite like your other question and its solution is almost the same, but it needs a little more math. Let’s focus on one pair of points. There still are two steps:
Step 1: Find a random point that is inside the hexagon, and has distance d from its border.
Step 2: Find another point that has distance d from first point.
Main problem is step 1. We can say that a points that has distance d form a hexagon with radius r, is actually inside a hexagon with radius r-d. Then we just need to find a random point that lays on a hexagon!
Polar Formula of Hexagons:
I want to solve this problem in polar space, so I have to formulate hexagons in this space. Remember circle formula in polar space:
The formula of a hexagon in polar space is pretty much like its circumscribe circle, except that the radius of the hexagon differs at every t (angle). Let’s call this changing radius r2. So, if we find the function R2 that returns r2 for all ts then we can write polar formula for hexagon:
This image demonstrates parameters of the problem:
The key parameter here is α. Now we need a function Alpha that returns α for all ts:
Now we have all points on border of the hexagon in polar space:
r = 500;
T = linspace(0, 2*pi, 181);
Alpha = #(t) pi/2-abs(rem(t, pi/3)-(pi/6));
R2 = #(t) r*cos(pi/6)./sin(Alpha(t));
X = R2(T).*cos(T);
Y = R2(T).*sin(T);
hold on
plot(X, Y, '.b');
plot((r).*cos(T), (r).*sin(T), '.r')
Polar Formula of a Regular Polygon:
Before I go on I’d like to generalize Alpha and R2 functions to cover all regular polygons:
Alpha = #(t) pi/2-abs(rem(t, 2*pi/(n))-(pi/(n)));
R2 = #(t) r*cos(pi/n)./sin(Alpha(t));
Where n is the number of edges of the polygon.
Answer:
Now we can generate pairs of points just like what we did for the circle problem:
r = 500; n = 6;
a = 10; b = 50;
N = 100;
D = (b - a).*rand(N,1) + a;
Alpha = #(t) pi/2-abs(rem(t, 2*pi/(n))-(pi/(n)));
R2 = #(t) r*cos(pi/n)./sin(Alpha(t));
T1 = rand(N, 1) * 2 * pi;
RT1 = rand(N, 1) .* (R2(T1)-D);
X1 = RT1.*cos(T1);
Y1 = RT1.*sin(T1);
T2 = rand(N, 1) * 2 * pi;
X2 = X1+D.*cos(T2);
Y2 = Y1+D.*sin(T2);
Rotating the polygon:
For rotating the polygon we just need to update the Alpha function:
t0 = pi/8;
Alpha = #(t) pi/2-abs(rem(t+t0, 2*pi/(n))-(pi/(n)));
This is a test for n=7, N=50000 and t0=pi/10:

ContourPlot and inequalitie plot together

Im new to matlab and I want to plot a ContourPlot together with two inequalities but I dont know how. The function that I want to plot its ContourPlot is something like this:
Z = (X-2).^2 + (Y-1).^2;
and here are the two inequalities:
ineq1 = X.^2 - Y <= 2;
ineq2 = X + Y <= 2;
this is what I have dodne so far:
[X,Y] = meshgrid(-4:.2:4,-4:.2:4);
Z = (X-2).^2 + (Y-1).^2;
[C,h] = contour(X,Y,Z);
clabel(C,h)
ineq1 = X.^2 - Y <= 2;
ineq2 = X + Y <= 2;
range = (-4:.2:4);
hold on
plot(range,ineq1, range, ineq2)
hold off
but this does not feel right.
What I want to do is to visualize an optimization problem. First I want to plot the ContourPlot of the function and then the possible areas in that same plot, It would be great if I could show the intersection areas too.
If you want to draw the boundaries of the inequalities onto the contour plot, you can do this with line.
[X,Y] = meshgrid(-4:.2:4,-4:.2:4);
Z = (X-2).^2 + (Y-1).^2;
[C,h] = contour(X,Y,Z);
clabel(C,h)
x_vect = (-4:.05:4);
y_ineq1 = x_vect.^2 - 2;
y_ineq2 = 2 - x_vect;
line(x_vect, y_ineq1);
line(x_vect, y_ineq2);
Coloring the intersection area is a bit more tricky, and I'm not sure if it's exactly what you want to do, but you could look into using patch, something like
% Indexes of x_vect, y_ineq1 and y_ineq2 for region where both satisfied:
region_indexes = find(y_ineq1<y_ineq2);
region_indexes_rev = region_indexes(end:-1:1);
% To plot this area need to enclose it
% (forward along y_ineq1 then back along y_ineq2)
patch([x_vect(region_indexes),x_vect(region_indexes_rev)],...
[y_ineq1(region_indexes),y_ineq2(region_indexes_rev)],...
[1 0.8 1]) % <- Color as [r g b]
% May or may not need following line depending on MATLAB version to set the yaxes
ylim([-4 4])
% Get the original plot over the top
hold on
[C,h] = contour(X,Y,Z);
clabel(C,h)
hold off