How can I project a 3-D sphere onto a 2-D surface?

I got a matrix M with 3 col, n rows. The points created by the matrix are all on a sphere with radius r. In a seperate matrix, let's call it "U", same size. Has either 0's or the exact same row. (indicating parts of the the sphere that have been selected).
So a sphere where nothing has been selected is a 3xn matrix filled with 0's.
I want to project the sphere onto a 2D surface (lets ignore the z, and plot x and y), which gives me a "double" sphere, spanned by points. I used the scatter command to get this result. I shifted half of the circle down in y, so u would get two circles next to eachother.
Now... here's my question:
Can I create a memory efficient 2-D plot, in which the points are translated to "surface parts", in order to better indicate which parts of the sphere has been seen.
The reason for the memory efficient part is due to a constant refresh of the data.
See attached picture for an more visual explanation.
Added question: say I don't cut the circle in half in the middle, but say at 1/3. What would be the most easy way to "fold" the data points outward that would otherwise be obscured by the datapoints that have the same x&y, but different z points.
(see explanation in the left down corner)
Thanks in advance,

5 Comments

How big is "n"? Have you already solved the problem using "Scatter" and you're looking for something faster? The "memory efficient" is a red herring... you should have no trouble getting this to work just fine even for reasonably large n (i.e. large enough that you wouldn't be able to see the individual points) if you're using the set and get functions instead of deleting and calling scatter again each time you want to refresh. Also, if you don't need different colored/sized points, you'll get better performance using plot or line than using scatter.
I've solved the problem using scatter, but I want the plot to reflect the size of the area that has been marked. As you look at the sphere from a certain angle some "parts" become distorted, like what happens with a world map in 2-D form. U get the mercator projection, which I want to be visible in my plot. So I need a 2D "web" of points.
Can you post some example code? The solution will depend on how your points are arranged in relation to each other. Do you know which points get connected to which other points in the "web"?
Short answer: you can set x/y/z data to NaN to temporarily make those points disappear. That should get you the speed you need. But i'm not clear on exactly what you're asking about the web and the projection.
%%Generate sphere -- DELETE THIS IF DATA IS AVAILABLE
N=1; %counter
Point=1; %secondary counter
Q=20; %amount of data points the sphere has
r=20; %radius of the sphere
[X,Y,Z] = sphere(Q); %generating coordinates
%count=Q+1;
count=length(X);
M=zeros(((Q+1)^2),3); %assigning a matrix M to speed up code.
for N=1:(count)
M(((N-1)*count)+1:N*count,1)=r*X(N,:); %%rewriting to one matrix
M(((N-1)*count)+1:N*count,2)=r*Y(N,:);
M(((N-1)*count)+1:N*count,3)=r*Z(N,:);
N=N+1;
end
count2=length(M);
%%in between here and there there is a loop that updates the "seen" matrix every time, and I got an update command (refreshdata) to speed up things.
%%to simulate a seen function ive made this little loop.
% generating random "seen" matrix
for n=1:count2
random=rand(1);
if random<0.5
seen(n,:)=M(n,:);
else
seen(n,:)=[nan,nan,nan];
end;
end;
%%continue
figure;
hold on
scatter3(M(:,1),M(:,2),M(:,3),'blue') %displaying the unseen points in blue
scatter3(seen(:,1),seen(:,2),seen(:,3),'red','filled') %displaying the "seen" points in red
This is the example code I've put together, should show you what my problem is. I'll also include a code that should (sort of) give me the results I want.
K = convhulln(M)
trisurf(K,M(:,1),M(:,2),M(:,3))
or this
%%run this code separate from the rest
[x,y,z] = sphere(64);
surf(x,y,zeros(size(z)));
update.
The problem now lies with some flaw in my program.
The circle should be fully colored in, but it aint.
What is the problem here?
clc;clear all; close all;
N=1; %counter
Point=1; %secondary counter
Q=25; %amount of data points the sphere has
r=20; %radius of the sphere
[X,Y,Z] = sphere(Q); %generating coordinates
%count=Q+1;
count=length(X);
M=zeros(((Q+1)^2),3); %assigning a matrix M to speed up code.
for N=1:(count)
M(((N-1)*count)+1:N*count,1)=r*X(N,:); %%rewriting to one matrix
M(((N-1)*count)+1:N*count,2)=r*Y(N,:);
M(((N-1)*count)+1:N*count,3)=r*Z(N,:);
N=N+1;
end
%%end of code of sphere
count=sqrt(length(M));
count2=length(M);
seen=nan(count2,3); %filling a "seen" matrix in which the points are located that have been "seen".
tic
dt=delaunayTriangulation(M(:,1),M(:,2));
toc
UU=1;
counterrrr=1
for TT=1:count^2
Point=M(TT,:)+0.1*[rand rand rand];
p=rand
if p<=3 %selecting random points -> currently selected EVERY point instead of a random one.
seen=Point;
vertexId = nearestNeighbor(dt, seen(1),seen(2))
triangleId=pointLocation(dt, seen(1),seen(2))
try %this loop needs to run because for some strange reason the triangleId sometimes gives a NaN... While this should not be possible...
tri11 = dt(triangleId, [1:end]);
catch
triangleId=1
counterrrr=counterrrr+1 %the amount of errors RANDOMLY CREATED?!
end
hold on
patch(M(tri11,1), M(tri11,2), 'r', 'LineWidth',1, 'FaceColor','g')
triplot(dt.ConnectivityList(triangleId,:),M(:,1),M(:,2),'c')
tri1(UU,:)=dt(vertexId,:);
UU=UU+1;
end
end

Sign in to comment.

 Accepted Answer

Mohammad Abouali
Mohammad Abouali on 11 Dec 2014
Edited: Mohammad Abouali on 11 Dec 2014
This is called map projection. There are multiple methods. check any map projection resource.
The best resource is perhaps this:
MATLAB has a built-in command [x,y] = mfwdtran(lat,lon) There are some other command that might be helpful too, such as projfwd() .
These commands are part of "Mapping Toolbox".

1 Comment

I found something called "Delaunay triangulation".
This "sort of" solves my problems, combined with the (very usefull) "patch" code.
But I can't get it to work properly, something is wrong with the indices that it selects to plot.
The current code generates a sphere, ignores the zcoordinates, creates a delaunay triangulation matrix, enters a loop that selects random points from the dataset and then plots the new points. however, when selecting the points something goes wrong.
clc;clear all; close all;
N=1; %counter
Point=1; %secondary counter
Q=25; %amount of data points the sphere has
r=20; %radius of the sphere
[X,Y,Z] = sphere(Q); %generating coordinates
%count=Q+1;
count=length(X);
M=zeros(((Q+1)^2),3); %assigning a matrix M to speed up code.
for N=1:(count)
M(((N-1)*count)+1:N*count,1)=r*X(N,:); %%rewriting to one matrix
M(((N-1)*count)+1:N*count,2)=r*Y(N,:);
M(((N-1)*count)+1:N*count,3)=r*Z(N,:);
N=N+1;
end
%%end of code of sphere
count=sqrt(length(M));
count2=length(M);
seen=nan(count2,3); %filling a "seen" matrix in which the points are located that have been "seen".
dt=delaunayTriangulation(M(:,1),M(:,2));
UU=1;
for TT=1:count^2
Point=M(TT,:)+[0.001 0.001 0.001];
p=rand
if p<=0.5 %selecting random points
seen=Point;
vertexId = nearestNeighbor(dt, seen(1),seen(2));
tri11 = dt(vertexId, [1:end 1]);
hold on
patch(M(tri11,1), M(tri11,2), 'r', 'LineWidth',1, 'FaceColor','g')
tri1(UU,:)=dt(vertexId,:);
UU=UU+1;
end
end
triplot(dt);

Sign in to comment.

More Answers (1)

Ok... based on your code above, if your question is just how you can quickly update the data to reflect new information about which points are on/off, the answer is that you can use NaNs to turn points off (looks like you already know this) and then set the x/y/z data of the trisurf or surf object to quickly update the sphere. Here is an example... on my computer this gives me about 400 frames per second in 2014b, or 60 frames per second in earlier versions... so this should be fast enough to keep up with the max possible speed of your monitor:
[x,y,z]=sphere(50);
data=[x(:) y(:) z(:)];
figure('renderer','opengl')
axes('xlim',[-1 1],'ylim',[-1 1],'zlim',[-1 1])
L = surface(x,y,z);
view(3)
axis square
n=size(data,1);
tic
for i = 1:1000
npts = randi(n);
idx=false(n,1);
idx(1:npts)=true;
idx=idx(randperm(n));
thisx=x;
thisy=y;
thisz=z;
thisx(idx)=nan;
thisy(idx)=nan;
thisz(idx)=nan;
set(L,'xdata',thisx,'ydata',thisy,'zdata',thisz);
drawnow;
end
t=toc
disp(['Frames per second = ',num2str(1000/t)])

2 Comments

Ah, thanks, that is a part of the solution, Ill figure out what the figure options are that you used.
But the question that remains is, how can I put those 3-D rendered surfaces into a 2-D plot (thus using less memory, and allowing me to use convert the sphere so you can look at the 2-D plot an immediately see which parts have been selected)
Look at the images @ the start imgurl link for my idea of that part of the solution.
But thanks for this part Matt Dash
I'm not sure about the 2d vs 3d thing. All matlab axes are 3d, they just appear 2d when you view them from above. So a "2D" plot is identical to a 3D plot with all the z values set to 0. I'm not sure if this really provides any performance benefit.
As far as plotting both halves of the sphere separately, i would just define a plane, and use it in a condition that checks which side of the plane each point of the sphere is. Then have one plot show the points on one side, one plot show the points on the other side. Same idea applies if you had a more complex condition (splitting the sphere into 3 regions etc). I'm still not clear if you want to apply some additional transformation, like a map projection, but in any case I can't help you with that. If you happen to have the mapping toolbox it has many transformations built in.

Sign in to comment.

Asked:

luc
on 11 Dec 2014

Commented:

luc
on 16 Dec 2014

Community Treasure Hunt

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

Start Hunting!