MATLAB - Rotating an equilateral triangle around its centre point - matlab

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'

Related

How to draw a curve line with points between it on the shaded region that situated on the surface of the hemisphere using Matlab?

A hemisphere with shaded region is already formed. Then, planning to form a path or curved line on the shaded region situated on the surface of the hemisphere with points on it. Can't even know what is their latitude or longitude to draw an arc, therefore, any idea on how to obtain the latitude and longitude for the starting and ending point or form a curved line as shown in the figure below?
[x,y,z] = sphere; % Makes a 21-by-21 point sphere
x = x(11:end,:); % Keep top 11 x points
y = y(11:end,:); % Keep top 11 y points
z = z(11:end,:); % Keep top 11 z points
radius = 0.13;
c = [0.36 0 0];
hs = surf(radius.*x + c(1),radius.*y,radius.*z,'FaceColor','yellow','FaceAlpha',.3);
axis equal
xlabel('X');ylabel('Y');zlabel('Z');
% Putting the ranges for the elevation and azimuth
minAzimuth = 0;
maxAzimuth = 180;
minElevation = 0;
maxElevation = 80;
% Compute angles
phi = atan2d(y,x);
theta = acosd (z);
% Highlighting logic (Shading the subset of the hemisphere)
ind = (phi >= minAzimuth & phi <= maxAzimuth) & (theta >= minElevation & theta <= maxElevation); % Find those indices
x2 = x; y2 = y; z2 = z; % Make a copy of the hemisphere coordinates
x2(~ind) = NaN; y2(~ind) = NaN; z2(~ind)=NaN; % Set those out of boundary to NaN
hold on;
surf(radius.*x2+c(1),radius.*y2,radius.*z2,'FaceColor','red');
Use spherical coordinates:
As you did with your sphere segment, it is easier to define your line in spherical coordinates first, then convert to cartesian when it's time to display.
If you add this after your own code:
% set line parameters
np = 10 ; % number of points
LineAziStart = 17 ; % Starting azimuth
LineAziStop = 122 ; % Ending azimuth
LineElevation = 49 ; % Elevation
% generate spherical coordinates
azp = linspace(deg2rad(LineAziStart),deg2rad(LineAziStop),np).' ;
elp = zeros(np,1) + deg2rad(LineElevation) ;
rp = zeros(np,1) + radius ;
% convert to cartesian
[xp,yp,zp]=sph2cart(azp,elp,rp) ;
% adjust coordinates for center of the sphere
xp = xp + c(1) ;
yp = yp + c(2) ;
zp = zp + c(3) ;
% display
hp = plot3(xp,yp,zp,'g','LineWidth',2,'Marker','x') ;
You'll obtain a line parallel to the latitude you set:
You can adjust where the line starts, stops, and it elevation by adjusting the first parameters on top of the code (make them match your own values).
Edit:
To explain the spherical coordinate generation:
To get a line in 3D you need a set of 3 coordinates, they can be x/y/z (cartesian referential) or radius/azimuth/elevation (spherical referential).
The constraints for your line are:
Azimuth: (called azp) Has to vary from one value to another. For that I used the statement azp = linspace(deg2rad(LineAziStart),deg2rad(LineAziStop),np).' ;. I recommend you to read the documentation for the linspace function. It will generate a set of np linearly spaced points between LineAziStart and LineAziStop. I also had to use deg2rad because for sperical coordinates you want your angles expressed in radian.
Radius: (called rp) This one is easy. Your line has to be on the surface of the sphere, so all the points of the line will have the same radius value (the radius of the original sphere. We just generate a vector of np points all equal to radius. This is done with rp = zeros(np,1) + radius;.
Elevation: (called elp) Your line has to be parallel to a latitude, so the elevation is also constant for all the points of the line. As with the radius, we generate the set of constant points the same way: elp = zeros(np,1) + deg2rad(LineElevation) ;.
By then you have a set of 3 vectors (rp/azp/elp), which all have the same number of values, and together define a set of point in 3D space, in spherical coordinates. Matlab plotting function requires cartesian coordinates so the last step is just to convert this set of coordinates. This is done with the function sph2cart, which convert rp/azp/elp into xp/yp/zp.
The spherical coordinates we generated were centered on the origin (point 0,0,0,), so the converted cartesian coordinates are also there. The last step is simply to translate these coordinates so they'll be centered on the same point/center than the sphere. After that, your coordinates are ready to be plotted.

Rotating a matrix by different angles in 2d in matlab

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')

Matlab join 2 arcs

I am trying to draw a shape using matlab. Here I need to join arcs. I created arc using following code
circr = #(radius,rad_ang) [radius*cos(rad_ang); radius*sin(rad_ang)]; % Circle Function For Angles In Radians
N = 25; % Number Of Points In Complete Circle
r_angl = linspace(pi/2, 5*pi/4, N); % Angle Defining Arc Segment (radians)
radius = 0.5; % Arc Radius
xy_r = circr(radius,r_angl); % Matrix (2xN) Of (x,y) Coordinates
figure(1)
plot(xy_r(1,:), xy_r(2,:))
axis([-1.25*radius 1.25*radius 0 1.25*radius])
Code generates following output
Now I modified code to draw other arc
circr = #(radius,rad_ang) [radius*cos(rad_ang); radius*sin(rad_ang)]; % Circle Function For Angles In Radians
N = 25; % Number Of Points In Complete Circle
r_angl = linspace(pi/2, 5*pi/4, N); % Angle Defining Arc Segment (radians)
radius = 0.5; % Arc Radius
xy_r = circr(radius,r_angl); % Matrix (2xN) Of (x,y) Coordinates
r_angl1 = linspace(4*pi/4,pi/4); % Angle Defining Arc Segment (radians)
radius1 = 0.1; % Arc Radius
xy_r1 = circr(radius1,r_angl1); % Matrix (2xN) Of (x,y) Coordinates
figure(1)
plot(xy_r(1,:), xy_r(2,:),xy_r1(2,:),xy_r1(1,:))
axis([-1.25*radius 1.25*radius 0 1.25*radius]) % Set Axis Limits
axis equal
This code generates
How can I join both arcs? I need to join them using their end points
Inserting the following lines will joint the end points with lines
hold on;
line([xy_r(1,1) xy_r1(1,end)], [xy_r(2,1) xy_r1(2,end)]);
line([xy_r(1,end) xy_r1(2,1)], [xy_r(2,end) xy_r1(1,1)]);
Together:
figure(1)
plot(xy_r(1,:), xy_r(2,:),xy_r1(2,:),xy_r1(1,:))
hold on;
line([xy_r(1,1) xy_r1(1,end)], [xy_r(2,1) xy_r1(2,end)]);
line([xy_r(1,end) xy_r1(2,1)], [xy_r(2,end) xy_r1(1,1)]);
axis([-1.25*radius 1.25*radius 0 1.25*radius]) % Set Axis Limits
axis equal

Shade a subset of a sphere's surface in MATLAB

I'm attempting to generate a plot of a hemisphere with a shaded area on the surface bound by max/min values of elevation and azimuth. Essentially I'm trying to reproduce this:
Generating the hemisphere is easy enough, but past that I'm stumped. Any ideas?
Here's the code I used to generate this sphere:
[x,y,z] = sphere;
x = x(11:end,:);
y = y(11:end,:);
z = z(11:end,:);
r = 90;
surf(r.*x,r.*y,r.*z,'FaceColor','yellow','FaceAlpha',0.5);
axis equal;
If you want to highlight a certain area of your hemisphere, first you decide the minimum and maximum azimuth (horizontal sweep) and elevation (vertical sweep) angles. Once you do this, take your x,y,z co-ordinates and convert them into their corresponding angles in spherical co-ordinates. Once you do that, you can then subset your x,y,z co-ordinates based on these angles. To convert from Cartesian to spherical, you would thus do:
Source: Wikipedia
theta is your elevation while phi is your azimuth. r would be the radius of the sphere. Because sphere generates co-ordinates for a unit sphere, r = 1. Therefore, to calculate the angles, we simply need to do:
theta = acosd(z);
phi = atan2d(y, x);
Take note that the elevation / theta is restricted 0 to 180 degrees, while the azimuth / phi is restricted between -180 to 180 degrees. Because you're only creating half of a sphere, the elevation should simply vary from 0 to 90 degrees. Also note that acosd and atan2d return the result in degrees. Now that we're here, you just have to subset what part of the sphere you want to draw. For example, let's say we wanted to restrict the sphere such that the min. and max. azimuth span from -90 to 90 degrees while the elevation only spans from 0 to 45 degrees. As such, let's find those x,y,z co-ordinates that satisfy these constraints, and ensure that anything outside of this range is set to NaN so that these points aren't drawn on the sphere. As such:
%// Change your ranges here
minAzimuth = -90;
maxAzimuth = 90;
minElevation = 0;
maxElevation = 45;
%// Compute angles - assuming that you have already run the code for sphere
%// [x,y,z] = sphere;
%// x = x(11:end,:);
%// y = y(11:end,:);
%// z = z(11:end,:);
theta = acosd(z);
phi = atan2d(y, x);
%%%%%// Begin highlighting logic
ind = (phi >= minAzimuth & phi <= maxAzimuth) & ...
(theta >= minElevation & theta <= maxElevation); % // Find those indices
x2 = x; y2 = y; z2 = z; %// Make a copy of the sphere co-ordinates
x2(~ind) = NaN; y2(~ind) = NaN; z2(~ind) = NaN; %// Set those out of bounds to NaN
%%%%%// Draw our original sphere and then the region we want on top
r = 90;
surf(r.*x,r.*y,r.*z,'FaceColor','white','FaceAlpha',0.5); %// Base sphere
hold on;
surf(r.*x2,r.*y2,r.*z2,'FaceColor','red'); %// Highlighted portion
axis equal;
view(40,40); %// Adjust viewing angle for better view
... and this is what I get:
I've made the code modular so that all you have to do is change the four variables that are defined at the beginning of the code, and the output will highlight that desired part of the hemisphere that are bounded by those min and max ranges.
Hope this helps!
One option is to create an array with the corresponding color you want to attribute to each point.
A minimal example (use trigonometry to convert your azimuth and elevation to logical conditions on x, y, and z):
c=(y>0).*(x>0).*(z>0.1).*(z<0.5);
c(c==0)=NaN;
surf(r.*x,r.*y,r.*z,c ,'FaceAlpha',0.5); axis equal;
yields this:
Note: this only works with the resolution of the grid. (i.e each 'patch' of the surface can have a different color). To exactly reproduce your plot, you might want to superpose the grid sphere with another one that has a much larger number of grid points on which you apply the above code.

draw circle in matlab and generate random coordinate inside the circle and the negative of the coordinate

I am required to plot a circle in matlab and mark its center and generate a random coordinate inside the circle and the negative of this coordinate and measure the distance between these two points
I tried this
x = linspace(-sqrt(10),sqrt(10));
y1 = sqrt(10-x.^2);
y2 = -sqrt(10-x.^2);
plot(x,y1,x,y2)
axis equal
to make the circle and its ok but i don't know how to proceed to generate the random coordinate ad its negative and measure the distance between them
Add this to your code -
%%// Choose from 100 random point pairs
N = 100;
%%// Radius of circle
radius = sqrt(10);
%%// Create a random point matrix Nx2
pt1 = [ radius*2*(rand(N,1)-0.5) radius*2*(rand(N,1)-0.5)];
%%// Select the first pair that lies inside circle
pt1 = pt1(find(sqrt( pt1(:,1).^2 + pt1(:,2).^2 )<radius,1),:);
%%// Negative of the point, i.e. on the other side of the center of the circle but equidistant from the center
pt2 = -pt1;
%%// Distance between the two points
dist1 = sqrt((pt1(1)-pt2(1)).^2 + (pt1(2)-pt2(2)).^2);
%%// Overlay the center and the two points on the circle plot
hold on
text(0,0,'C') %%// Center
text(pt1(1),pt1(2),'P') %%// First point
text(pt2(1),pt2(2),'MP') %%// Second point (Mirror Point, MP)
Plot
You can use the rand() function to produce a random distance from center, as well as to produce a random angle. You can then convert to x,y coordinates, and negate them to get the negative coordinates. Finally, you can use the distance formula to calculate the distance between the two coordinates. Here is some sample code:
x = linspace(-sqrt(10),sqrt(10));
y1 = sqrt(10-x.^2);
y2 = -sqrt(10-x.^2);
plot(x,y1,x,y2)
axis equal
hold on
r_max = sqrt(10); %set to radius of circle
r = rand(1)*r_max; %produces a random vector whose length is <=radius
theta = rand(1)*2*pi; % produces a random angle
x_coord = r*cos(theta); %calculate x coord
y_coord = r*sin(theta); % calculate y coord
x_coord_neg = -1*x_coord; % negate x coord
y_coord_neg = -1*y_coord; % negate y coord
plot(x_coord,y_coord, 'x')
plot(x_coord_neg,y_coord_neg, 'rx')
dist = sqrt((x_coord - x_coord_neg)^2 + (y_coord - y_coord_neg)^2) % calculate distance
Not sure if you actually want "negative coordinates" or the complex conjugate of the coordinates. In the case of the latter, you would just negate y to get the complex conjugate.