3D Figure 8 Torus in Matlab - matlab

This is the code to a 3d torus I have generated.
ezmesh('(3.7+0.5*cos(v))*cos(u)','(3.7+ 0.5*cos(v))*sin(u)','0.5*sin(v)',[0,2*pi,0,2*pi])
axis([-7 7 -7 7 -2 2]);
Can anyone show me how to transform this torus code into a figure 8 torus? These are the equations and parameters I want to use. I'm not sure how to adjust the parameters in the original torus so the code will work out.
%Figure Eight Torus
%Parameters: c = 1, -pi <= u, v <= pi
%Equations: x = (cos(u)*( c + sin(v)*cos(u)) - (sin(2*v)*sin(u)/2))
% y = (sin(u)*(c + sin(v)*cos(u)) - (sin(2*v)*sin(u)/2))
% z = s(in(u)*sin(v)) + (cos(u)*sin(2*v)/2)
Thank you in advance.
-Thomas

This should work:
ezmesh('cos(u)*(1+sin(v)*cos(u))-(sin(2.*v))*(sin(u)/2)',...
'sin(u)*((1+sin(v)*cos(u))-(sin(2.*v))*(sin(u)/2))',...
'sin(u)*sin(v)+(cos(u)*(sin(2.*v))/2)',[-pi,3,-3,pi]);
axis([-4 4 -4 4 -4 4])

Related

Matlab generate smooth curve between scatter points

I need to generate a curve between scatter points then identify the unit normal of the curve at each point. Here is an example of a point cloud
figure
x = [1 2 0 0 1 1 2 3 4 2];
y = [4 6 9 1 1 2 4 9 2 3];
scatter(x,y)
hold on
line(x,y)
xlim([0 4])
ylim([0 10])
NOTE: the 2 points along the y-axis are connected
Instead of a line between the points, I'd like to create a smooth curve. I'm not sure how to do this when points in x and y repeat. An attempt using spline fails. After I know the curve, I need to find the unit normals at each point. How do I go about this?
EDIT:
Basically I want to do what is show here for polyfit in the matlab docs. Assuming that x was unique in my case, this wouldn't be an issue. I could identify the polynomial and then, I believe, determine the unit normals from the polynomial function evaluated at that point. But in my case, the x and y data repeat so a straight forward application doesn't work.
One way to get a smooth path is to treat this as a parametric function and interpolate x and y separately.
x = [1 2 0 0 1 1 2 3 4 2];
y = [4 6 9 1 1 2 4 9 2 3];
t = 1:numel(x);
tq = 1:0.1:t(end);
xq = interp1(t,x,tq,'v5cubic');
yq = interp1(t,y,tq,'v5cubic');
plot(x,y,' ob',xq,yq,'-r');
To estimate the normals you can take the average normal of the two line segments around the sample points. This code is a bit ugly but it gets the job done.
n = zeros(2,numel(x));
for tidx = 1:numel(t)
tt = t(tidx);
idx1 = find(tq <= tt,1,'last');
idx0 = idx1 - 1;
idx2 = idx1 + 1;
if idx0 > 0
n1 = [yq(idx1) - yq(idx0); xq(idx0) - xq(idx1)];
n(:,tidx) = n(:,tidx) + n1/norm(n1);
end
if idx2 <= numel(tq)
n2 = [yq(idx2) - yq(idx1); xq(idx1) - xq(idx2)];
n(:,tidx) = n(:,tidx) + n2/norm(n2);
end
n(:,tidx) = n(:,tidx) / norm(n(:,tidx));
end
plot(x,y,' ob',xq,yq,'-r',[x.' x.'+n(1,:).'].', [y.' y.'+n(2,:).'].',' -k');
axis equal;
If you use pchip instead of v5cubic for the interpolation method then you get more symmetry around the sample points. However, it appears that any sharp turns (90 degrees or greater) are not smoothed.

Plotting equation in Matlab using for loop

I want to plot an equation using a for-loop. I have tried several different ways, but keep getting the apparently common error "Subscript indices must either be real positive integers or logicals". The equation I want to plot is y(x) = (x^4)-(4*x^3)-(6*x^2)+15.
The last code I tried was the following:
y(0) = 15;
for x = [-3 -2 -1 0 1 2 3 4 5 6];
y(x) = (x^4)-(4*x^3)-(6*x^2)+15;
end
plot(x,y)
To start from the beginning,
y(0) = 15;
will give you the following error:
Subscript indices must either be real positive integers or logicals.
This is because Matlab's indexing starts at 1. Other languages like C and Python start at 0.
Matlab can work directly with vectors. So in your code, there is no need for a loop at all.
You can do it like this:
x = [-3 -2 -1 0 1 2 3 4 5 6];
y = (x.^4) - (4*x.^3) - (6*x.^2) + 15;
plot(x, y);
Note that we need to use element-wise operators like .* and .^ to calculate the values vectorized for every element. Therefore a point . is written in front of the operator.
Additionally, we can improve the code substantially by using the colon operator to generate x:
x = -3:6; % produces the same as [-3 -2 -1 0 1 2 3 4 5 6]
y = (x.^4) - (4*x.^3) - (6*x.^2) + 15;
plot(x, y);
If you want finer details for your graph, use linspace as suggested by #Yvon:
x = linspace(-3, 6, 100); % produces a vector with 100 points between -3 and 6.
y = x.^4-4*x.^3-6*x.^2+15;
plot(x,y)
x = linspace(-3, 6, 100);
y = x.^4-4*x.^3-6*x.^2+15;
plot(x,y)

2D Body Transformation and Rotation in Matlab

I defined the following rectangle in Matlab:
A = [-4,-4,4,4,-4;-2,2,2,-2,-2;]
And I defined a transformation matrix (Special Euclidean (2)) like this:
function T = se2(x, y, theta)
T = [cosd(theta), -sind(theta), x;
sind(theta), cosd(theta), y;
0, 0, 1];
Now, I want to rotate my shape by 45 degrees counter-clockwise about its center and move it with respect to the new coordinate frame by 2 unit in the new y direction.
First problem is: when doing like the following:...
B = se2(0,2,45)*[A;1 1 1 1 1]
...it will correctly rotate but incorrectly move my shape.
Here is my rectangle(blue), incorrect transformation(red) and correct transformation(green):
Second problem is: Suppose I translated the shape by 6 direction in the y direction. I want to just rotate the rectangle by -30 degrees about it's new center but doing as I've shown, yields rotation about the former center.
How can I get around these problems in Matlab? Is there a predefined function in doing these tasks?
My code for plotting the shapes:
A =
-4 -4 4 4 -4
-2 2 2 -2 -2
plot(A(1,:),A(2,:),'blue')
Regarding your 1st problem:
Essentially you want to do a translation of A to it's centroid before you do the rotation. This is because the rotation assumes that you're rotating about the origin. Therefore you need to "centre" it about the point you plan to rotate it about before you rotate it. Then you need to translate it back after you finish the rotation. Refer to this reference for details.
% Define A
A = [-2,-2,6,6,-2; -2,2,2,-2,-2; 1 1 1 1 1];
% Define Translation Matrix
trans = #(x,y,z) repmat([x; y; z],[1 5]);
% Define Rotation Matrix
se2 = #(x, y, theta) [
cosd(theta), -sind(theta), x;
sind(theta), cosd(theta), y;
0, 0, 1];
% Calculate Rotated Rect
B = se2(0,0,45) * (A - trans(2,0,0) ) + trans(2,0,0);
% Plot Rectangles
figure; plot(A(1,:),A(2,:),'b')
hold on;
plot(B(1,:),B(2,:),'r')
hold off;
axis equal
The function trans will translate it before the rotation.
Result:
>> A
A =
-2 -2 6 6 -2
-2 2 2 -2 -2
1 1 1 1 1
>> B
B =
0.5858 -2.2426 3.4142 6.2426 0.5858
-4.2426 -1.4142 4.2426 1.4142 -4.2426
1.0000 1.0000 1.0000 1.0000 1.0000
Here is the A/B if rotated at the centre.
Here is the A/B with the offset.
Regarding your 2nd problem:
Same solution as the first problem except you use the new centroid and -30 deg instead for the parameters of B.

Position a matlab figure generated in a GUI for automatic save

I've been having some issues automatically saving a figure plotted in a GUI axes panel. Here's the code I have so far:
x= [1 2 3 4 5 6 7 8 9 10];
y = [10 5 6 7 8 20 5 4 3 8];
p = polyfit(x, y, 6);
r = polyval(p, x);
xlabel(handles.axes1, 'Time (\mus)');
ylabel(handles.axes1, 'Angular Velocity (rad/s)');
title(handles.axes1, 'Angular Velocity vs. Time (kT Test)');
aV = plot(handles.axes1, x, y, x, r, 'g--');
%Save figure
ftmp = figure();
copyobj(handles.axes1, ftmp);
set(ftmp, 'units', 'normalized', 'outerposition', [0 0 1 1]);
%Create file name
fileName = ['Test' num2str(time(1)) '_' num2str(time(2)) '_' num2str(time(3))]
saveas(ftmp, fileName, 'png');
The image is automatically saved, but it doesn't come out right. For instance, here is what the saved image looks like:
As you can see, the image is quite skewed. However, if I manually save the image, the entire figure is centered and saved. Is there a way to reposition the figure while automatically saving?
(Please note that I'm looking for a solution that does not use export_fig).
I've searched this sight for a while, and none of the answers to similar questions have offered a solution to my problem.
Any constructive advice is appreciated.
Here is what I would do:
x= [1 2 3 4 5 6 7 8 9 10];
y = [10 5 6 7 8 20 5 4 3 8];
p = polyfit(x, y, 6);
r = polyval(p, x);
figure(1);
clf();
plot(x, y, x, r, 'g--');
xlabel('Time (\mus)');
ylabel('Angular Velocity (rad/s)');
title('Angular Velocity vs. Time (kT Test)');
time = clock();
fileName = ['Test' num2str(time(1)) '_' num2str(time(2)) '_' num2str(time(3))]
print('-f1','-dpng', fileName);
Not sure exactly what you want for your filename, so just made that up as I went. The time=clock() is not needed if you want to have a different filename.
Note, too, that you can use saveas(1, fileName, 'png'); as the last line.

generate rectangle annotation in the current figure

I would like to insert a rectangle into my matlab figure to highlight a specific region:
x = [0 1 2 2 3 4 5 6 7 8 9 10];
y = [0 1 2 4 3 4 5 6 7 8 9 10];
fh = figure(1);
plot(x,y)
xlim([0 10]);
ylim([0 10]);
I can do this by using the annotation function and defining the left bottom width height of the rectangle.
I am wondering, however, can this be done according to the x and y values from the figure in question? For the example shown, for example I would like to draw a rectangle from x = 1.5 y = 1.5 with a height of 3 and a width of two. This is my attempt:
% define location of lbwh in terms of x and y values
l = 1.5;
b = 1.5;
w = 2;
h = 3;
% convert factor of 1
xx = xlim;
l = l./xx(2);
b = b./xx(2);
w = w./xx(2);
h = h./xx(2);
annotation('rectangle','position',[l,b,w,h]);
The problem is that the position I'm providing is in terms of the (0,0) position in the plot and not the bottom left hand of the figure window. how can I correct this?
One way would be to just create a rectangle from line graphs:
plot([l,l,l+w,l+w,l],[b,b+h,b+h,b,b], 'r', 'LineWidth', 2)