How do I rotate a cylinder in matlab using matrices? - matlab

So, I'm really new to MatLab, and I was trying to make a cylinder using [X Y Z] = cylinder;.Then I got these 3 matrices: X Y and Z that generate an actual cylinder if I mesh them. Now, what I need help to do is rotate this [X Y Z] cylinder 90 degrees clockwise in the y axis. I know there is this command called rotate but my teacher wants me to use rotation and translation matrices explicitly. How could I create these matrices and multiply them to the cylinder?Is there a better way to make the cylinder? I'm really not used to matlab, if you could explain in a detailed form, I would be very thankful.

You should use a rotation matrix for the R^3 which serves as a linear map. There are built in fucntions in MATLAB for that but I guess you are not allowed to use them.
Here is a quick and dirty solution:
[X Y Z] = cylinder;
figure;
surf(X,Y,Z);
% set up rotation matrix:
angle_in_degrees = 90;
angle_in_rad = angle_in_degrees* pi/180;
rotationMatrix = [cos(angle_in_rad) 0 sin(angle_in_rad); 0 1 0; -sin(angle_in_rad) 0 cos(angle_in_rad)];
% get points at the two rings and rotate them separately:
positionOld1 = [X(1,:)',Y(1,:)',Z(1,:)'];
positionOld2 = [X(2,:)',Y(2,:)',Z(2,:)'];
positionNew1 = positionOld1*rotationMatrix;
positionNew2 = positionOld2*rotationMatrix;
% reassemble the two sets of points into X Y Z format:
X = [positionNew1(:,1),positionNew2(:,1)];
Y = [positionNew1(:,2),positionNew2(:,2)];
Z = [positionNew1(:,3),positionNew2(:,3)];
figure;
surf(X,Y,Z);

Related

Plotting a coloured 3D figure in MATLAB

I have 3 axes: X of size N, Y of size M and Z of size O, which correspond to the coordinates of my data.
I have a matrix: DATA of size MxNxO, which corresponds to the module for each points.
I would like to plot the MATLAB figure of coordinate X, Y, Z and color the point depending of the value of the matrix DATA of size MxNxO.
I tried lots of functions such as scatter3, surf, plot3, but none is working as I wanted.
This is what I tried:
n = 10;
x = linspace(0,10,n);
y = linspace(0,10,n);
z = linspace(0,10,n);
DATA = randn(n,n,n);
scatter3(x,y,z,DATA);
This code didn't work because DATA is not the same size as x, y, z. I also tried with:
[X,Y,Z] = ndgrid(x,y,z)
scatter3(X,Y,Z,DATA);
but this didn't work either.
The trick with scatter3() is to "unroll" your matrices to a column vector, and don't forget that the fourth argument is size, rather than colour:
n = 10;
x = linspace(0,10,n);
y = linspace(0,10,n);
z = linspace(0,10,n);
[X,Y,Z] = ndgrid(x,y,z);
DATA = randn(n,n,n);
% here 3 is the size. You can set it to a different constant, or vary it as well
scatter3(X(:), Y(:), Z(:), 3, DATA(:));
Results in
You can colour a surface, see its documentation, however, it doesn't seem to make much sense in your case, given you have a full cube of data points. A surface is 2D, whereas your data is 3D. For a 2D surface, simply follow the example in the docs:
n = 10;
x = linspace(0,10,n);
y = linspace(0,10,n);
Z = rand(n);
DATA = randn(n);
surf(x, y, Z, DATA);
Images rendered in R2007b, syntax cross-checked with the documentation.
If you've got a surface defined by an M -by- 4 array containing X, Y, Z and Data, you can use delaunay() to create a Delaunay triangulation of your points and then trisurf() to plot that. Note that this still requires a 2D surface, albeit it can vary in three dimensions. The cube of data in your example still doesn't make sense to plot as a surface, even with this method.

Non-rectangular meshgrids in MATLAB

I want to create a non-rectangular meshgrid in matlab.
Basically I have a polygon shaped feasible set I need to make a grid of in order to interpolate 3D data points in this set. The function for interpolation is given and requires finite (x, y, z) inputs. Where x is nx1, y is 1xm and z is nxm. Right now I have the mesh set up with linspace and set all NaN (infeasible) values to 0 before using my function, which is wrong of course (third figure).
Is there a simple solution for this?
I added a picture illustrating what I'm currently doing: First plot is the feasible set, second plot are solved sample data points in this set and third plot is the interpolation (currently still with rectangular meshgrid and NaN = 0). What I need is a meshgrid looking like the first figure (red polygon) instead of a rectangular one. In the third plot you can see that the rectangular meshgrid in combination with setting NaN to 0 (=infeasible values, not included in the red polygon set) results in a wrong interpolation along the edges, because it includes infeasible regions.
Here is my code using a rectangular meshgrid:
figure (2) %sample data
plot3(X0(1,:), X0(2,:), U, 'x')
%X0(1,:) and X0(2,:) are vectors corresponding to the Z-Values (blue sample data)
%X0 and U are in the feasible set (red polygon)
xv = linspace(xLb(1), xUb(1), 100);
yv = linspace(xLb(2), xUb(2), 100); %xLb and xUb are upper and lower bounds for the rectangle mesh
[x1,x2] = meshgrid(xv, yv);
Z = griddata(X0(1,:), X0(2,:), U, x1, x2);
%This grid obviously includes values that are not in the feasible set (red polygon) by its rectangular nature
Z(isnan(Z))=0; %set infeasible values to 0, wrong of course
testMPC = someInterpolationFunction([0:length(Z)-1]',[0:length(Z)-1],Z);
testMPC.showInterpolation(20,20)
%this shows figure 3 in the attached picture
Try something like this:
nRows = 100;
nCols = 200;
x1 = #(x) max(0, x-50);
x2 = #(x) min(nCols, nCols - 50 + x);
RR = zeros(nRows, nCols);
CC = zeros(nRows, nCols);
for iRow = 1:nRows
c1 = x1(iRow);
c2 = x2(iRow);
colVec = linspace(c1, c2, nCols);
RR(iRow, :) = iRow;
CC(iRow, :) = colVec;
end
mesh(RR, CC, zeros(size(RR)))
You'd need to redefine the functions for x1 and x2 or course as well as the scaling, but this should give you an idea of how to get started.

Drawing 2D grid in matlab

I am trying to get a 2D grid using matlab with x >= -1 and y <= 1 with step size of 0.1
But I'm getting 3D grid with no proper step sizes. Any ideas?
My code:
[x, y] = meshgrid(-1:0.1:5, 0:0.1:1);
surf(x,y)
Do you just want to plot a bunch of 2D points? You use plot. Using your example, you would take your x,y points and simply put dot markers for each point. Convert them into 1D arrays first before you do this:
[X,Y] = meshgrid(-1:0.1:5, 0:0.1:1);
X = X(:);
Y = Y(:);
plot(X,Y,'b.');
xlabel('X'); % // Label the X and Y axes
ylabel('Y');
This is what I get:
Edit based on comments
If you want to rotate this grid by an angle, you would use a rotation matrix and multiply this with each pair of (x,y) co-ordinates. If you recall from linear algebra, to rotate a point counter-clockwise, you would perform the following matrix multiplication:
[x'] = [cos(theta) -sin(theta)][x]
[y'] [sin(theta) cos(theta)][y]
x,y are the original co-ordinates while x',y' are the output co-ordinates after rotation of an angle theta. If you want to rotate -30 degrees (which is 30 degrees clockwise), you would just specify theta = -30 degrees. Bear in mind that cos and sin take in their angles as radians, so this is actually -pi/6 in radians. What you need to do is place each of your points into a 2D matrix. You would then use the rotation matrix and apply it to each point. This way, you're vectorizing the solution instead of... say... using a for loop. Therefore, you would do this:
theta = -pi/6; % // Define rotation angle
rot = [cos(theta) -sin(theta); sin(theta) cos(theta)]; %// Define rotation matrix
rotate_val = rot*[X Y].'; %// Rotate each of the points
X_rotate = rotate_val(1,:); %// Separate each rotated dimension
Y_rotate = rotate_val(2,:);
plot(X_rotate, Y_rotate, 'b.'); %// Show the plot
xlabel('X');
ylabel('Y');
This is what I get:
If you wanted to perform other transformations, like scaling each axis, you would just multiply either the X or Y co-ordinates by an appropriate scale:
X_scaled = scale_x*X;
Y_scaled = scale_y*Y;
X_scaled and Y_scaled are the scaled versions of your co-ordinates, with scale_x and scale_y are the scales in each dimension you want. If you wanted to translate the co-ordinates, you would add or subtract each of the dimensions by some number:
X_translate = X + X_shift; %// Or -
Y_translate = Y + Y_shift; %// Or -
X_translate and Y_translate are the translated co-ordinates, while X_shift and Y_shift are the amount of shifts you want per dimension. Note that you either do + or -, depending on what you want.

Interpolate surface of 3D cylinder in Matlab

I have a dataset that describes a point cloud of a 3D cylinder (xx,yy,zz,C):
and I would like to make a surface plot from this dataset, similar to this
In order to do this I thought I could interpolate my scattered data using TriScatteredInterp onto a regular grid and then plot it using surf:
F = TriScatteredInterp(xx,yy,zz);
max_x = max(xx); min_x = min(xx);
max_y = max(yy); min_y = min(yy);
max_z = max(zz); min_z = min(zz);
xi = min_x:abs(stepSize):max_x;
yi = min_y:abs(stepSize):max_y;
zi = min_z:abs(stepSize):max_z;
[qx,qy] = meshgrid(xi,yi);
qz = F(qx,qy);
F = TriScatteredInterp(xx,yy,C);
qc = F(qx,qy);
figure
surf(qx,qy,qz,qc);
axis image
This works really well for convex and concave objects but ends in this for the cylinder:
Can anybody help me as to how to achieve a nicer plot?
Have you tried Delaunay triangulation?
http://www.mathworks.com/help/matlab/ref/delaunay.html
load seamount
tri = delaunay(x,y);
trisurf(tri,x,y,z);
There is also TriScatteredInterp
http://www.mathworks.com/help/matlab/ref/triscatteredinterp.html
ti = -2:.25:2;
[qx,qy] = meshgrid(ti,ti);
qz = F(qx,qy);
mesh(qx,qy,qz);
hold on;
plot3(x,y,z,'o');
I think what you are loking for is the Convex hull function. See its documentation.
K = convhull(X,Y,Z) returns the 3-D convex hull of the points (X,Y,Z),
where X, Y, and Z are column vectors. K is a triangulation
representing the boundary of the convex hull. K is of size mtri-by-3,
where mtri is the number of triangular facets. That is, each row of K
is a triangle defined in terms of the point indices.
Example in 2D
xx = -1:.05:1; yy = abs(sqrt(xx));
[x,y] = pol2cart(xx,yy);
k = convhull(x,y);
plot(x(k),y(k),'r-',x,y,'b+')
Use plot to plot the output of convhull in 2-D. Use trisurf or trimesh to plot the output of convhull in 3-D.
A cylinder is the collection of all points equidistant to a line. So you know that your xx, yy and zz data have one thing in common, and that is that they all should lie at an equal distance to the line of symmetry. You can use that to generate a new cylinder (line of symmetry taken to be z-axis in this example):
% best-fitting radius
% NOTE: only works if z-axis is cylinder's line of symmetry
R = mean( sqrt(xx.^2+yy.^2) );
% generate some cylinder
[x y z] = cylinder(ones(numel(xx),1));
% adjust z-range and set best-fitting radius
z = z * (max(zz(:))-min(zz(:))) + min(zz(:));
x=x*R;
y=y*R;
% plot cylinder
surf(x,y,z)
TriScatteredInterp is good for fitting 2D surfaces of the form z = f(x,y), where f is a single-valued function. It won't work to fit a point cloud like you have.
Since you're dealing with a cylinder, which is, in essence, a 2D surface, you can still use TriScatterdInterp if you convert to polar coordinates, and, say, fit radius as a function of angle and height--something like:
% convert to polar coordinates:
theta = atan2(yy,xx);
h = zz;
r = sqrt(xx.^2+yy.^2);
% fit radius as a function of theta and h
RFit = TriScatteredInterp(theta(:),h(:),r(:));
% define interpolation points
stepSize = 0.1;
ti = min(theta):abs(stepSize):max(theta);
hi = min(h):abs(stepSize):max(h);
[qx,qy] = meshgrid(ti,hi);
% find r values at points:
rfit = reshape(RFit(qx(:),qy(:)),size(qx));
% plot
surf(rfit.*cos(qx),rfit.*sin(qx),qy)

Set surf minimum for matlab

I have a function which takes a voxel representation of a 3D landscape and can plot a X-Y section to show the middle of the landscape. The voxel representation is stored in a 3 dimensional matrix with a number that represents something important. Obviously the matrix is
1,1,1
2,2,2
in terms of accessing the elements but the actual 3D locations are found in the following method:
(index-1)*resolution+0.5*resolution+minPos;
where resolution is the grid size :
resolution
<-->
__ __ __
|__|__|__|
<- Min pos
and minPos is where the grid starts.
Now in terms of the actual question, i would like to extract a single X-Y section of this voxel representation and display it as a surf. This can be done by just doing this:
surf(voxel(:, :, section))
however then you get this:
The obvious problem is that the grid will start at 0 because that is how the matrix representation is. How can i set the minimum and cell size for surf, ie so that the grid will start at the minimum (shown above) and will have the grid spacing of resolution (shown above).
Read the documentation of surf, you can also provide x and y coordinates corresponding to your data points.
surf(X,Y,Z)
X and Y can be either vectors or matrices:
surf(X,Y,Z) uses Z for the color data and surface height. X and Y are vectors or matrices defining the x and y components of a surface. If X and Y are vectors, length(X) = n and length(Y) = m, where [m,n] = size(Z). In this case, the vertices of the surface faces are (X(j), Y(i), Z(i,j)) triples. To create X and Y matrices for arbitrary domains, use the meshgrid function
Example
Z=[ 0 1 2 3;
7 6 5 4;
8 9 10 11];
x=[-1 0 1 2];
y=[-2 0 2];
surf(x,y,Z);
Of course you have to match Z, x and y matrices/vectors as clearly described in the doc^^
Just remember that elements in columns of Z are surf'ed as values along the y-axis, elements in rows of Z are surf'ed as values along the x-axis. This is clearly to be seen in the example picture.
Solution
I think you switched the x and y-axis around, which you can fix by just transposing z:
s = size(voxel);
xi = (minPosX:resolution:(minPosX+resolution*s(1)-1));
yi = (minPosY:resolution:(minPosY+resolution*s(2)-1));
z = (voxel(:,:,section));
surf(xi, yi, z');
or that you're picking the wrong numbers for constructing xi and yi and it should be this instead:
xi = (minPosX:resolution:(minPosX+resolution*s(2)-1));
yi = (minPosY:resolution:(minPosY+resolution*s(1)-1));
z = (voxel(:,:,section));
surf(xi, yi, z);
So it was easy enough to do:
lets say we have a 3D matrix "voxel";
s = size(voxel);
xi = (minPosX:resolution:(minPosX+resolution*s(1)-1));
yi = (minPosY:resolution:(minPosY+resolution*s(2)-1));
z = (voxel(:,:,section));
[x y] = meshgrid(xi, yi);
x = x';
y = y';
surf(x, y, z);
Provides the following plot:
This is rotated which is annoying, I cant seem to get it to rotate back (I could just visualise around the other way but that's ok)