I have a set of data points, and I would like to rotate each data counterclockwise in the plane by a random angle about different points in the same plane. In first try, I could rotate them counterclockwise in the plane by a certain angle about different points in the same plane:
x = 16:25;
y = 31:40;
% create a matrix of these points, which will be useful in future calculations
v = [x;y];
center = [6:15;1:10];
% define a 60 degree counter-clockwise rotation matrix
theta = pi/3; % pi/3 radians = 60 degrees
R = [cos(theta) -sin(theta); sin(theta) cos(theta)];
% do the rotation...
vo = R*(v - center) + center;
% pick out the vectors of rotated x- and y-data
x_rotated = vo(1,:);
y_rotated = vo(2,:);
% make a plot
plot(x, y, 'k-', x_rotated, y_rotated, 'r-');
Then I tried to generalize it to rotate by random angels, but there is a problem which I can not solve in second code:
x = 16:25;
y = 31:40;
% create a matrix of these points, which will be useful in future calculations
v = [x;y];
center = [6:15;1:10]; %center of rotation
% define random degree counter-clockwise rotation matrix
theta = pi/3*(rand(10,1)-0.5); % prandom angle
R = [cos(theta) -sin(theta); sin(theta) cos(theta)];
% do the rotation...
vo = R*(v - center) + center;
% pick out the vectors of rotated x- and y-data
x_rotated = vo(1,:);
y_rotated = vo(2,:);
% make a plot
plot(x, y, 'k-', x_rotated, y_rotated, 'r-');
The problem is, when I try to rotate the matrix, the rotation matrix dimension is not equal as it should. I don't know how should I create the rotation matrix in this case.
Could anyone suggest how to solve the problem? Any answer is highly appreciated.
Your problem is that you are creating a 20x2 matrix in R. To see why, consider
theta % is a 10x1 vector
cos(theta) % is also going to be a 10x1 vector
[cos(theta) -sin(theta);...
sin(theta) cos(theta)]; % is going to be a 2x2 matrix of 10x1 vectors, or a 20x2 matrix
What you want is to have access to every 2x2 rotation matrix. One way of doing it is
R1 = [cos(theta) -sin(theta)] % Create a 10x2 matrix
R2 = [sin(theta) cos(theta)] % Create a 10x2 matrix
R = cat(3,R1,R2) % Cocatenate ("paste") both matrix along the 3 dimension creating a 10x2x2 matrix
R = permute(R,[3,2,1]) % Shift dimensions so the matrix shape is 2x2x10, this will be helpful in the next step.
Now you need to multiply each data point by its corresponding rotation matrix. Multiplication is only defined for 2D matrices, so I don't know a better method to do this than to loop over each point.
for i = 1:length(v)
vo(:,i) = R(:,:,i)*(v(:,i) - center(:,i)) + center(:,i);
end
Why don't you simply rotate with imrotate.
For example, you want to rotate 30 degrees:
newmat = imrotate(mat, 30, 'crop')
will rotate 30 degrees clockwise and keep the dimension same. To increase the size you can use 'full' option in imresize
To input a random value in the rotation matrix
rn = rand*90; %0-90 degrees
newmat = imrotate(mat, rn, 'crop')
Related
I have this piece of MATLAB code that outputs x,y, and z angles and I would like draw a line using them. Can someone point me in the right direction on how to do this?
C = pi;
A = pi;
B = pi;
Z = [cos(C),-sin(C),0; sin(C),cos(C),0; 0,0,1];
X = [1,0,0;0,cos(A),-sin(A);0,sin(A),cos(A)];
Y = [cos(B),0,sin(B);0,1,0;-sin(B),0,cos(B)];
R =(X*Y)*Z;
yaw=atan2(R(2,1),R(1,1))
pitch=atan2(-R(3,1),sqrt(R(3,2)^2+R(3,3)^2))
roll=atan2(R(3,2),R(3,3))
X, Y, and Z are not angles, they are rotation matrices defined by the angles A, B, and C.
it's not clear what's the meaning of "draw a line using them", they are just used to rotate vectors in the 3D space.
here is an example of drawing a rotated vector with them:
% define rotation angles (around the axes)
C = pi/2;
A = pi/4;
B = pi/4;
% generate rotation matrices
Z = [cos(C),-sin(C),0; sin(C),cos(C),0; 0,0,1];
X = [1,0,0;0,cos(A),-sin(A);0,sin(A),cos(A)];
Y = [cos(B),0,sin(B);0,1,0;-sin(B),0,cos(B)];
R =(X*Y)*Z;
% generate a vector and rotate it
v = [1;1;1];
u = R*v;
% plot
quiver3(0,0,0,v(1),v(2),v(3));
hold on
quiver3(0,0,0,u(1),u(2),u(3));
xlim([-1 1]); ylim([-1 1]); zlim([-1 1])
axis square
legend('original','rotated')
I am new to MATLAB, but have worked with javascript and other programming languages.
I am writing a MATLAB program that will generate an equilateral triangle given the side length, an x coordinate, a y coordinate and an angle of rotation. It is working as intended except for the rotations.
I am using a rotation matrix to rotate the triangle. This works, except it rotates around the origin instead of rotating on the spot. (see below example).
90 degree Rotations Example
In order to rotate it on the spot I think I need to calculate the centre of the triangle and then rotate around that(somehow). I am not sure how to do this or if there is an easier/better way to do this. I did see there is a rotate function, but from what I have seen, it is for spherical space, not Cartesian planes.
Code is below, sorry for the mess:
function [ side, coord1,coord2 ] = equilateral(side, x,y, rotation)
%EQUILATERAL- given a side length and x,y, coordinates as inputs, the
%function plots an equilateral triangle an angle of rotation can be
%given as an input as well. This will rotate the trianlge around the x
%and y coordinates given.
%rotation argument is not required. If not given, angle is 0
if(exist('rotation','var'))
angle = rotation;
else
angle = 0;
end
%rotation matrix
R = [cos(angle), -sin(angle); sin(angle), cos(angle)];
%Make the axis equal so the triangles look equilateral
axis equal;
%max horizontal x coordinate
x2 = x + side;
%max horiontal y coordinate (equal to original y coordinate)
y2 = y;
%height of the triangle at midpoint (perpendicular height)
h = side*sin(pi/3) + y;
%coordinates of midpoint/top vertice
mid = [x2-(0.5*side), h];
%min coordinates
coord1 = [x,y];
%max coordinates
coord2 = [x2,y2];
if (angle > 0)
coord1 = coord1*R;
coord2 = coord2*R;
mid = mid*R;
end
%plot the base of the triangle
plot(linspace(coord1(1),coord2(1)), linspace(coord1(2),coord2(2)));
hold on
%plot the first side from inital coords to midpoint
plot(linspace(coord1(1),mid(1)), linspace(coord1(2),mid(2)));
%plot second side from mid point to max coords
plot(linspace(mid(1),coord2(1)), linspace(mid(2),coord2(2)));
end
I am open to any suggestions for improvements to the code/help to clean it up as well as help with the rotation issues. Thanks for the help.
The rotation matrix
[cos(theta), -sin(theta)
sin(theta), cos(theta)]
rotates a set of points of an angle theta about the origin of the axes.
In order to rotate a point around a given point, you have to:
-shift your points so that the rotatioin point concides with the origin of the axes
- rotate the point using the rotation matrix
- shift back your points
The following code is a modified version of your function in which the proposed approach has been implemented.
In the code I've set the rotation point as the centre of gravity
XR=x+side/2
YR=y+h*.3
nevertheless, you can compute them in a different way.
function [ side, coord1,coord2 ] = equilateral(side, x,y, rotation)
%EQUILATERAL- given a side length and x,y, coordinates as inputs, the
%function plots an equilateral triangle an angle of rotation can be
%given as an input as well. This will rotate the trianlge around the x
%and y coordinates given.
%rotation argument is not required. If not given, angle is 0
if(exist('rotation','var'))
% angle = rotation;
% Convert the angle from deg to rad
angle = rotation*pi/180;
else
angle = 0;
end
%rotation matrix
R = [cos(angle), -sin(angle); sin(angle), cos(angle)];
%Make the axis equal so the triangles look equilateral
axis equal;
%max horizontal x coordinate
x2 = x + side;
%max horiontal y coordinate (equal to original y coordinate)
y2 = y;
%height of the triangle at midpoint (perpendicular height)
h = side*sin(pi/3) + y;
%coordinates of midpoint/top vertice
mid = [x2-(0.5*side), h];
%min coordinates
coord1 = [x,y];
%max coordinates
coord2 = [x2,y2];
plot([coord1(1) coord2(1) mid(1) coord1(1)],[coord1(2) coord2(2) mid(2) coord1(2)],'r')
hold on
%
% Define the coord of the point aroud with to turn
%
XR=x+side/2
YR=y+h*.3
plot(XR,YR,'o','markerfacecolor','k','markeredgecolor','k')
if (angle > 0)
% coord1 = coord1*R;
% coord2 = coord2*R;
% mid = mid*R;
% Shift the triangle so that the rotation point coincides with the origin
% of the axes
r_coord1 = (coord1-[XR YR])*R+[XR YR];
r_coord2 = (coord2-[XR YR])*R+[XR YR];
r_mid = (mid-[XR YR])*R+[XR YR];
%
% Plot the rotated triangle
plot([r_coord1(1) r_coord2(1) r_mid(1) r_coord1(1)],[r_coord1(2) r_coord2(2) r_mid(2) r_coord1(2)],'r')
end
% % %
% % % %plot the base of the triangle
% % % plot(linspace(coord1(1),coord2(1)), linspace(coord1(2),coord2(2)));
% % % hold on
% % % %plot the first side from inital coords to midpoint
% % % plot(linspace(coord1(1),mid(1)), linspace(coord1(2),mid(2)));
% % % %plot second side from mid point to max coords
% % % plot(linspace(mid(1),coord2(1)), linspace(mid(2),coord2(2)));
end
I've also made a couple of additional modification:
I've added a conversion of the input angle from deg to rad; you can discard it if you assume the input is already in rad
I've updated the way to plot the triangle.
As a suggestion, you can use nargin to thest the number of input to your function and varargin to inspect them instead of testing in they exist.
Hope this helps.
Qapla'
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.
I have a problem which is twofold:
How do I plot a toroidal surface in MATLAB, given a major radius R and a minor radius a? To avoid confusion, it is the toroidal/poloidal coordinate system, illustrated in the picture below, that I'm talking about.
Now, in any point (phi, theta) on this surface, the minor radius will be distorted by some value that I have stored in a matrix. How do I plot this distorted surface? This might be easy once I have the answer to part 1, but this is my actual goal, so any solution to part 1 that cannot handle this is pretty useless to me.
If anyone can tell me how to make the image appear smaller here, please do =)
Addressing your first question: first you will need to define the coordinates of your torus in toroidal coordinates (seems natural!) and then convert to Cartesian coordinates, which is how MATLAB expects all plots to be constructed (unless you are making a polar plot, of course). So we start of by defining our toroidal coordinates:
aminor = 1.; % Torus minor radius
Rmajor = 3.; % Torus major radius
theta = linspace(-pi, pi, 64) ; % Poloidal angle
phi = linspace(0., 2.*pi, 64) ; % Toroidal angle
We just want a single surface of the torus, so the minor radius is a scalar. We now make a 2D mesh of these coordinates:
[t, p] = meshgrid(phi, theta);
and convert to 3D Cartesian coordinates using the formulas given on the Wikipedia page linked to in the question:
x = (Rmajor + aminor.*cos(p)) .* cos(t);
y = (Rmajor + aminor.*cos(p)) .* sin(t);
z = aminor.*sin(p);
Now we have our torus defined in 3D, we can plot it using surf:
surf(x, y, z)
axis equal
Edit: To address your second question, it depends how you have your distortions stored, but say you have a matrix defined at each toroidal and poloidal point, you will just have to multiply the constant that is the minor radius by the distortion. In the following I create a distortion matrix that is the same dimensions as my toroidal and poloidal angle coordinate matrices and that is normally distributed about a mean of 1 with a FWHM of 0.1:
distortion = 1. + 0.1 * randn(64, 64);
x = (Rmajor + aminor .* distortion .*cos(p)) .* cos(t);
y = (Rmajor + aminor .* distortion .* cos(p)) .* sin(t);
z = aminor.* distortion .* sin(p);
surf(x, y, z)
The result of which is:
You can do this with surf - just create matrices with the x,y,z coordinates. The page you linked to has the trig equations to do this (they are exactly what you'd come up with on your own - I wrote the code below before checking your link).
R = 10;
a = 3;
tx=nan(41,21);
ty=nan(41,21);
tz=nan(41,21);
for j=1:21
for i=1:41
phi = (i-1)*2*pi/40;
theta = (j-1)*2*pi/20;
tx(i,j)= cos(phi) * (R+cos(theta)*a);
ty(i,j)= sin(phi) * (R+cos(theta)*a);
tz(i,j)= sin(theta)*a;
end
end
figure
surf(tx,ty,tz)
axis equal
To distort the surface, replace the constant a with a matrix of the desired minor radius values, and index into that matrix - i.e. tz(i,j) = sin(theta)*distortion(i,j) (but in all dimensions, obviously).
How do I draw an ellipse and an ellipsoid using MATLAB?
(x^2/a^2)+(y^2/b^2)=1
n=40;
a=0; b=2*pi;
c=0; d=2*pi;
for i=1:n
u=a+(b-a)*(i-1)/(n-1);
for j=1:m
v=a+(d-c)*(j-1)/(m-1);
x(i,j)=sin(u)*cos(v);
y(i,j)=sin(u)*sin(v);
z(i,j)=cos(u);
end
end
mesh(x,y,z);
But I want the shape?
Ellipse article on Wikipedia had a simple JavaScript code to draw ellipses.
It uses the parametric form:
x(theta) = a0 + ax*sin(theta) + bx*cos(theta)
y(theta) = b0 + ay*sin(theta) + by*cos(theta)
where
(a0,b0) is the center of the ellipse
(ax,ay) vector representing the major axis
(bx,by) vector representing the minor axis
I translated the code into a MATLAB function:
calculateEllipse.m
function [X,Y] = calculateEllipse(x, y, a, b, angle, steps)
%# This functions returns points to draw an ellipse
%#
%# #param x X coordinate
%# #param y Y coordinate
%# #param a Semimajor axis
%# #param b Semiminor axis
%# #param angle Angle of the ellipse (in degrees)
%#
narginchk(5, 6);
if nargin<6, steps = 36; end
beta = -angle * (pi / 180);
sinbeta = sin(beta);
cosbeta = cos(beta);
alpha = linspace(0, 360, steps)' .* (pi / 180);
sinalpha = sin(alpha);
cosalpha = cos(alpha);
X = x + (a * cosalpha * cosbeta - b * sinalpha * sinbeta);
Y = y + (a * cosalpha * sinbeta + b * sinalpha * cosbeta);
if nargout==1, X = [X Y]; end
end
and an example to test it:
%# ellipse centered at (0,0) with axes length
%# major=20, ,minor=10, rotated 50 degrees
%# (drawn using the default N=36 points)
p = calculateEllipse(0, 0, 20, 10, 50);
plot(p(:,1), p(:,2), '.-'), axis equal
The answers from Jacob and Amro are very good examples for computing and plotting points for an ellipse. I'll address some easy ways you can plot an ellipsoid...
First, MATLAB has a built-in function ELLIPSOID which generates a set of mesh points given the ellipsoid center and the semi-axis lengths. The following creates the matrices x, y, and z for an ellipsoid centered at the origin with semi-axis lengths of 4, 2, and 1 for the x, y, and z directions, respectively:
[x, y, z] = ellipsoid(0, 0, 0, 4, 2, 1);
You can then use the function MESH to plot it, returning a handle to the plotted surface object:
hMesh = mesh(x, y, z);
If you want to rotate the plotted ellipsoid, you can use the ROTATE function. The following applies a rotation of 45 degrees around the y-axis:
rotate(hMesh, [0 1 0], 45);
You can then adjust the plot appearance to get the following figure:
axis equal; %# Make tick mark increments on all axes equal
view([-36 18]); %# Change the camera viewpoint
xlabel('x');
ylabel('y');
zlabel('z');
Also, if you want to use the rotated plot points for further calculations, you can get them from the plotted surface object:
xNew = get(hMesh, 'XData'); %# Get the rotated x points
yNew = get(hMesh, 'YData'); %# Get the rotated y points
zNew = get(hMesh, 'ZData'); %# Get the rotated z points
I've adapted this excellent ellipse plotting script from MATLAB Central for your requirement of
function plotEllipse(a,b,C)
% range to plot over
%------------------------------------
N = 50;
theta = 0:1/N:2*pi+1/N;
% Parametric equation of the ellipse
%----------------------------------------
state(1,:) = a*cos(theta);
state(2,:) = b*sin(theta);
% Coordinate transform (since your ellipse is axis aligned)
%----------------------------------------
X = state;
X(1,:) = X(1,:) + C(1);
X(2,:) = X(2,:) + C(2);
% Plot
%----------------------------------------
plot(X(1,:),X(2,:));
hold on;
plot(C(1),C(2),'r*');
axis equal;
grid;
end
Note: change N to define the resolution of your ellipse
Here's an ellipse centered at (10,10) with a = 30 and b = 10
Ellipse article on Wikipedia and Rotation matrix.
Rewrite that functions:
rotate by rotAngle counter-clockwise around (0,0)
Coordinate transform to (cx, cy)
function [X,Y] = calculateEllipse(cx, cy, a, b, rotAngle)
%# This functions returns points to draw an ellipse
%#
%# #param x X coordinate
%# #param y Y coordinate
%# #param a Semimajor axis
%# #param b Semiminor axis
%# #param cx cetner x position
%# #param cy cetner y position
%# #param angle Angle of the ellipse (in degrees)
%#
steps = 30;
angle = linspace(0, 2*pi, steps);
% Parametric equation of the ellipse
X = a * cos(angle);
Y = b * sin(angle);
% rotate by rotAngle counter clockwise around (0,0)
xRot = X*cosd(rotAngle) - Y*sind(rotAngle);
yRot = X*sind(rotAngle) + Y*cosd(rotAngle);
X = xRot;
Y = yRot;
% Coordinate transform
X = X + cx;
Y = Y + cy;
end
and an example to test it:
[X,Y] = calculateEllipse(0, 0, 20, 10, 0);
plot(X, Y, 'b'); hold on; % blue
[X,Y] = calculateEllipse(0, 0, 20, 10, 45);
plot(X, Y, 'r'); hold on; % red
[X,Y] = calculateEllipse(30, 30, 20, 10, 135);
plot(X, Y, 'g'); % green
grid on;
Create two vectors, one of the x-coordinates of the points of the circumference of the ellipsoid, one of the y-coordinates. Make these vectors long enough to satisfy your accuracy requirements. Plot the two vectors as (x,y) pairs joined up. I'd drop the for loops from your code, much clearer if you use vector notation. Also I'd format your question using the SO markup for code to make it all clearer to your audience.
The simplest way might be to use the Matlab function
pdeellip(xc,yc,a,b,phi)
For example:
pdeellip(0,0,1,0.3,pi/4)
However, this is simple solution is good to have a quick glance how the ellipse looks like. If you want to have a nice plot, look at the other solutions.
I don't know in which version of Matlab this was added, but it's available at least from version R2012b on.