Polygon Rotation using matrix-vector multiplication - matlab

Consider the polygon with vertices (0, 0), (1, 0), (7/10, 1), (1/2, 1/2), and (3/10, 1). Make a plot of this polygon in Matlab using the fill function. Rotate this polygon by an angle of 100 degrees using matrix-vector multiplication in Matlab with an appropriately chosen rotation matrix R. Make another plot of the rotated polygon using fill.
% Makes original polygon
X = [0 1 7/10 1/2 3/10];
Y = [0 0 1 1/2 1];
norm_poly = fill(X,Y,'k');
thetad = 100;
R = [cosd(thetad) -sind(thetad); sind(thetad) cosd(thetad)];
C = repmat([0 0], 5, 1)';
axis([-10 10 -10 10])
V = get(norm_poly,'Vertices')'; % get the current set of vertices
V = R*(V - C) + C; % do the rotation relative to the centre of the
square
set(norm_poly,'Vertices',V'); % update the vertices
How would I make to different plots to show them? Does the code to rotate make sense and answer all the requirements?

The rotation itself makes sense. To plot multiple things to the same graph use hold on after making the first plot. Alternatively you can make a new figure and plot a new fill there.
P = [0, 1, 7/10, 1/2, 3/10;
0, 0, 1, 1/2, 1];
fill(P(1,:), P(2,:), 'k');
theta = 100;
R = #(t) [cosd(t) -sind(t); sind(t) cosd(t)];
axis([-3 3 -3 3])
grid on
V = R(theta)*P;
hold on;
fill(V(1,:), V(2,:), 'k');

Related

How can I create a rectangle with a hole in MATLAB/OCTAVE?

I would like to plot/draw exactly this shape in MATLAB or OCTAVE. Of course I do know how to plot, and how to create rectangles, using either the plot, the line or the rectangle functions. But I have not yet managed to add this "hole" on the top side of the rectangle. I figure, it's a (half-)circle of radius 0.5 and center point (1.5|2). In OCTAVE, there is a drawCircleArc function, but I don't want to only draw that thing, but also to have the necessary coordinates defining the whole shape for further manipulation.
Here is one way (matlab/octave compatible):
% Specify all polygon points, excluding the semi-circle outline
X = [1, 0, 0, 3, 3, 2];
Y = [2, 2, 0, 0, 2, 2];
% Add semi-circle outline to array of polygon points
t = 0 : -0.01 : -pi;
X = [X, 1.5 + 0.5 * cos(t)];
Y = [Y, 2 + 0.5 * sin(t)];
% Use fill to plot the filled polygon, with desired settings
fill( X, Y, [0.8, 0.8, 0.8], 'linewidth', 1.5 );
axis( [-2, 4, -2, 4] ); axis equal;
As of 2017b you can also use polyshapes and boolean operators.
rect = polyshape([0 3 3 0], [0 0 2 2]);
t = linspace(0, 2*pi, 32);
circ = polyshape(1.5+.5*cos(t), 2+.5*sin(t));
subplot 121, hold on
plot(rect)
plot(circ)
axis equal
shape = subtract(rect, circ);
subplot 122
plot(shape)
axis equal

Drawing a square with Matlab's 'line' command

I'm trying to plot a square on Matlab, specifically using the line command, with corners at the points (0,0), (0, rho), (rho, 0) and (rho, rho)
% create axes
x = linspace(0,10,100);
y = linspace(0,20,100);
rho = 2*pi;
% plot
figure;
A = line([0 0],[0 rho]);
B = line([0 0],[rho 0]);
C = line([0 rho],[rho rho]);
D = line([rho 0],[rho rho]);
fill(A,B,C,D,'b');
However, line D fails to appear in my figure and moreover, the fill command is not working, although that part is really quite optional. My main issue is why the aforementioned line won't appear in the plot
That's because you aren't specifying the coordinates for the box properly. Remember that line takes in two vectors where the first vector is a list of x coordinates and the second vector is a list of y coordinates. Each ith pair of (x, y) will have a line drawn from its previous (i-1)th point up to the ith point except for the first point of course. The lines drawn by A and B are the same line. The same can be said with C and D. It's just a matter of modifying the statements so you're drawing the line correctly.
Drawing the box in lovely ASCII graphics for illustration:
(0, rho) (rho, rho)
------------------------
| |
| |
| |
| |
------------------------
(0, 0) (rho, 0)
You need to draw four lines. Let's traverse counter-clockwise:
Going from (0, 0) to (0, rho)
Going from (0, rho) to (rho, rho)
Going from (rho, rho) to (rho, 0)
Going from (rho, 0) to (0, 0)
Therefore, modify your code to be:
rho = 2*pi;
A = line([0 0],[0 rho]);
B = line([0 rho],[rho rho]);
C = line([rho rho],[rho 0]);
D = line([rho 0],[0 0]);
BTW, the code above may not be portable for later. You are going to get line handles which is fine by you don't use this as an input into fill.
We finally get:
It may be cleaner to just put all of the coordinates in just two vectors and call line. This will also make this play nicely with fill:
rho = 2*pi;
x = [0, 0, rho rho, 0];
y = [0, rho, rho, 0, 0];
line(x, y);
hold on;
fill(x, y, 'b');
Notice that we use the proper convention for line, then draw it, then we fill it. If you follow the logic specified earlier, we draw a line from (0, 0) to (0, rho), then from (0, rho) to (rho, rho), then from (rho, rho) to (rho, 0) then finally from (rho, 0) back to (0, 0). Notice that we had to use the origin (0, 0) at the beginning and at the end to ensure that we draw the line at the bottom edge of the square. We also use hold on to add the filled box in after the square boundary that you've drawn on the figure. fill takes in a vector of coordinates just like line does. We get:
You have made a number of mistakes regarding the input arguments for line and fill. Firstly, the inputs to line are the x coordinates for the line points followed by the y coordinates for the line points, NOT successive pairs of (x,y) points. The following will plot your square correctly, starting at (0,0) and drawing lines clockwise:
A = line([0 0], [0 rho]); % Left edge
B = line([0 rho], [rho rho]); % Top edge
C = line([rho rho], [rho 0]); % Right edge
D = line([rho 0], [0 0]); % Bottom edge
The values returned are handles to the line graphics objects. These can be used to modify the line properties, but you can't pass these to fill. You should instead pass polygon vertex data.
There is an easier way to handle all of this, though. You can instead define a vector of x and y coordinates for the vertices of your square, making it much easier to plot lines and filled polygons:
X = [0 0 rho rho 0];
Y = [0 rho rho 0 0];
hLine = line(X, Y);
hold on; % Needed to add to existing plot instead of erasing
fill(X, Y, 'b');

Filling an area above a curve with many colors (matlab, surf)

I'm trying to create a figure in matlab that looks like this:
desired figure
I am doing so by: (i) assigning value points to each x,y coordinate, (ii) plotting a surf, and (iii) change the view point so the third axis is not seen. Here is the code:
x = linspace(0, 1, 10);
y = linspace(0, 1, 10);
z = linspace(0, 1, 10);
z = repmat(z, 10, 1);
z = flipud(triu(z));
z(z==0) = nan;
hold off
surf(x, y, z, 'linestyle', 'none')
colormap([linspace(0.39, 1, 20)',linspace(0.58, 0.25, 20)', linspace(0.93, 0.25, 20)']);
colorbar
xlim([x(1) x(end)])
shading interp
view([90 -90])
hold on
plot(x, 1-y, 'linewidth', 2)
I get the following figure: matlab figure I get
As you can see, there a lot of white spaces above the line which I would like to be in color as well. Unfortunately, I cannot add any more grid points as calculating the actual value of the points takes a lot of time (unlike the example above).
Is there a way to have matlab draw colors in those white spaces as well?
Thanks!
You can try to use patch function to create filled polygon.
See http://www.mathworks.com/help/matlab/ref/patch.html
Try the following code:
vert = [0 1;1 1;1 0]; % x and y vertex coordinates
fac = [1 2 3]; % vertices to connect to make triangle
fvc = [1 0 0; 1 1 1; 0 0 1];
patch('Faces',fac,'Vertices',vert,'FaceVertexCData',fvc,'FaceColor','interp');
Result is close:
I was managed to get closer to the desired figure:
close all
x = linspace(0, 1, 10);
y = linspace(0, 1, 10);
%colorbar
xlim([x(1) x(end)])
%Fill rectangle.
vert = [0 0; 1 0; 1 1; 0 1]; % x and y vertex coordinates
fac = [1 2 3 4]; % vertices to connect to make squares
%patch('Faces',fac,'Vertices',vert,'FaceColor','red')
fvc = [1 0 0; 0.6 0.7 1; 0.6 0.7 1; 1 0 0]; %Color of vertices (selected to be close to example image).
patch('Faces',fac,'Vertices',vert,'FaceVertexCData',fvc,'FaceColor','interp')
hold on
%Fill lower triangle with white color.
vert = [0 0;0 1;1 0]; % x and y vertex coordinates
fac = [1 2 3]; % vertices to connect to make triangle
fvc = [1 1 1; 1, 1, 1; 1, 1, 1]; %White color
patch('Faces',fac,'Vertices',vert,'FaceVertexCData',fvc,'FaceColor','interp');
plot(x, 1-y, 'linewidth', 2)
set(gca,'Xtick',[],'Ytick',[]); %Remove tick marks
Result:
Thank you Rotem! I wasn't aware of the patch function and indeed it solved the issue!
The colors on the actual figure I'm trying to achieve are not linear, so I just used patch for all the empty triangles. Here is the adjusted code I use for the simple example (again, this is just a bit more general just to be able to have non linear colors in the area above the curve):
x = linspace(0, 1, 10);
y = linspace(0, 1, 10);
z = linspace(0, 1, 10);
z = repmat(z, 10, 1)+0.1;
z = flipud(triu(z));
z(z==0) = nan;
z = z-0.1;
hold off
surf(x, y, z, 'linestyle', 'none')
colormap([linspace(0.39, 1, 20)',linspace(0.58, 0.25, 20)', linspace(0.93, 0.25, 20)']);
colorbar
xlim([x(1) x(end)])
shading interp
view([90 -90])
hold on
patch_cor_y = kron((length(y):-1:1)', ones(3, 1));
patch_cor_x = kron((1:length(x))', ones(3, 1));
patch_cor = [y(patch_cor_y(2:end-2))', x(patch_cor_x(3:end-1))'];
patch_path = reshape(1:length(patch_cor),3, length(patch_cor)/3)';
patch_col = z(sub2ind(size(z), patch_cor_x(3:end-1), patch_cor_y(2:end-2)));
patch('Faces',patch_path,'Vertices',patch_cor,'FaceVertexCData',patch_col,'FaceColor','interp', 'EdgeColor', 'none');
plot(x, 1-y, 'linewidth', 2)
The figure achieved: figure

Rotating and working on MATLAB 3D objects

How do you rotate 3D objects around each of the three axes when coordinates are of MATLAB style (X, Y and Z kept in different arrays).
This code is a start. I think I have found the rotation matrix (for pi/2 rotation around x), here it is called rotX90_2. But how should rotX90_2 operate on X, Y, Z?
[X,Y,Z] = cylinder;
% rotX90_1 = makehgtform('xrotate',pi/2) gives
rotX90_1 = ...
[1 0 0 0;
0 0 -1 0;
0 1 0 0;
0 0 0 1];
rotX90_2 = rotX90_1(1:3, 1:3);
% Here rotX90_2 should operate on [X,Y,Z] in order to ...
% rotate it 90 degrees around x, but how is this done?
% == What code should be put here to rotate the cylinder? ==
surf(X,Y,Z);
I have just started using MATLAB. As I understand, the basic ways to manipulate 3D graphics are to either operate on the X, Y, Z, like here or, you can first run graphics routines like h = surf(X, Y, Z); and then operate on graphics objects, using f.ex. hgtransform.
It is convenient to translate and scale using X, Y, Z. - You just add and multiply by scalars. But I ask this question to understand how to rotate.
If you operate on the graphic objects, on the other hand, you can use the function hgtransform. But you must then first create other objects, since hgtransform does not operate directly on the graphic objects, as I understand. (Except functions like rotatex(h, angle). F.ex, I have not found a corresponding "translatex(h, distance)". That surprised me. Maybe I didn't look well enough.)
OK I am new to this. Any simple, practical pointers how to easily rotate, scale and translate MATLAB 3D coordinates/objects (around the coordinate system axes) would be appreciated.
Edit:
According to Prakhar's answer below, which works, the code needed to fill the gap above is the following. Thank you, Prakhar.
[row, col] = size(X);
coordinates = [reshape(X, [row*col, 1]), reshape(Y, [row*col, 1]), reshape(Z, [row*col, 1])];
rC = coordinates * rotX90_2;
X = reshape(rC(:, 1), [row, col]);
Y = reshape(rC(:, 2), [row, col]);
Z = reshape(rC(:, 3), [row, col]);
Let's say R is the appropriate 3x3 rotation matrix.
coordinates = [X Y Z];
rotatedCoordinates = coordinates * R;
(Assuming X, Y, and Z are column vectors of same size)
Now, you can get the new X, Y, and Z coordinates from rotatedCoordinates as rotatedCoordinates(:, 1), rotatedCoordinates(:, 2), and rotatedCoordinates(:, 3), respectively.
EDIT: Another alternative when X, Y, Z are 2D matrices:
[X, Y, Z] = cylinder;
[row, col] = size(X);
coordinates = [reshape(X, [row*col, 1]), reshape(Y, [row*col, 1]), reshape(Z, [row*col, 1])];
rC = coordinates*R;
Xn = reshape(rC(:, 1), [row, col]);
Yn = reshape(rC(:, 2), [row, col]);
Zn = reshape(rC(:, 3), [row, col]);

Creating a heptagon in MATLAB

I need to create a heptagon. I want to do this by creating one triangle and then loop to draw it again after I have rotated it.
x1 = [ 0.5, 0.48, 0.55 ];
y1 = [ 0.5, 0.578, 0.558 ];
fill( x1, y1, 'w')
This gives me the first triangle, however I'm trying to figure out a way to loop through it and rotate it each time (I assume by 51.43 degrees for a heptagon).
You want a rotation matrix. I tried this:
t = pi / 3.5;
R = [cos(t) sin(t); -sin(t) cos(t)];
c = [0 1 cos(t); 0 0 sin(t)];
hold on;
for i=1:7
fill(c(1, :), c(2, :), 'w');
c = R * c;
end
R rotates around the origin - so if you want to be centered at (0.5, 0.5) then you need to translate c by that amount before drawing. I changed your starting coordinates to make them a triangle starting at (0, 0) with one edge along the x-axis.