Plot square surface in Matlab - matlab

How to plot a square surface in Matlab?
More exactly I want to plot a square square with value 0.5 surface which is located at X:-1 to X=1 and Y:2.5 to 3.5.
I tried the following
[X,Y] = meshgrid(-3.5:.5:3.5);
Z = zeros(15);
Z(end-2:end,5:9) = 0.5;
surf(X,Y,Z);
This doesn't result in a perpendicular edge. How to archive that?

This is what the patch function is for.
Matlab documentation
so for your case:
X = [ -1 -1 1 1];
Y = [3.5 2.5 2.5 3.5];
Z = [0.5 0.5 0.5 0.5];
patch(X,Y,Z,'red')
view(45,45)

You need to provide multiple Z-values together with the same X, Y values. A small example:
>> [X, Y]= meshgrid([1,2,2,3,4], 1:2)
X =
1 2 2 3 4
1 2 2 3 4
Y =
1 1 1 1 1
2 2 2 2 2
>> Z = [0,0,1,1,0;0,0,1,1,0]
Z =
0 0 1 1 0
0 0 1 1 0
>> surf(X, Y, Z)
Yields this:
This should be the same in 2D, you just need to wrap you head around which X and Y values to duplicate and adjust the Z-Matrix accordingly.

I ended up with
figure;
hold on;
X = [ -2 -2 2 2];
Y = [2 4 4 2];
Z = [0 0 0 0];
patch(X,Y,Z,'blue');
X = [ -1 -1 1 1];
Y = [3.5 2.5 2.5 3.5];
Z = [0.5 0.5 0.5 0.5];
h = patch(X,Y,Z,'red');
X = [ -1 -1 1 1];
Y = [2.5 2.5 2.5 2.5];
Z = [0 0.5 0.5 0];
patch(X,Y,Z,'red');
X = [1, 1, 1, 1];
Y = [2.5 2.5 3.5 3.5];
Z = [0 0.5 0.5 0];
patch(X,Y,Z,'red');
view(45,30)
legend(h, 'F(u,v)')
xlabel('u')
ylabel('v')
zlabel('F(u,v)')

Related

Matlab - How to perform operations on each row between two matrices?

I have two matrices each of which contains two vectors (each row is a vector):
u = [1 0 0; 2 0 0]
v = [1 1 0; 2 2 0]
I want to calculate two angles between the vectors of the corresponding rows in the matrices (angle between [1 0 0] , [1 1 0] and angle between [2 0 0] , [2 2 0]). In this example, both angles will be 45 degrees. So what I want is a new matrix like this:
angles = [45; 45]
When I try this:
u = [1 0 0; 2 0 0]
v = [1 1 0; 2 2 0]
dp = u(:,1) .* v(:,1) + u(:,2) .* v(:,2) + u(:,3) .* v(:,3);
angles = atan2d(norm(cross(u,v)),dp)
The anwser will be:
angles = [76.3670 ; 45.8683]
and when I try this (change norm to normr):
u = [1 0 0; 2 0 0]
v = [1 1 0; 2 2 0]
dp = u(:,1) .* v(:,1) + u(:,2) .* v(:,2) + u(:,3) .* v(:,3);
angles = atan2d(norm(crossr(u,v)),dp)
The anwser will be:
angles = [0 0 45.0000 ; 0 0 14.0362]
How can I make it calculate the angle between the vectors of each row?
Try:
u=[1 0 0;2 0 0];
v = [1 1 0;2 2 0];
atan2(cross(u,v,2),dot(u,v,2)) % radians
atan2d(cross(u,v,2),dot(u,v,2)) % degrees
The ,2 in the cross and dot functions specifies the dimension to operate, since you are storing each vector in a row.
There a discussion here, with many other ways to calculate, and you may find one more suitable to your particular case of application.

Matlab - finding solution for scaling a curve

Consider two curves, for example:
x = [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20];
y1 = [0 0 -0.3 -0.8 -1.1 -1 -0.5 1 1.1 1 -0.3 -0.8 -1.1 -1 -0.5 0.1 0.05 0 0 0];
y2 = [0 -0.2 -0.3 -0.8 -2 1 2.8 2.4 1.5 1.1 2.3 -0.4 -0.2 1 1.1 1.2 1.3 0.5 -0.1 0];
I'd like to write a generalized algorithm that takes in x, y1, and y2, and scales y1 by a global scale factor, f, such that the new value of y2-y1 is as close as possible to 0. That is, y2-f*y1 is as close to 0 as possible.
How can I do this?
Try this:
% Create a function that you want to minimize
func = #(f, y1, y2)abs(sum(y2 - f*y1));
% Your example data
x = [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20];
y1 = [0 0 -0.3 -0.8 -1.1 -1 -0.5 1 1.1 1 -0.3 -0.8 -1.1 -1 -0.5 0.1 0.05 0 0 0];
y2 = [0 -0.2 -0.3 -0.8 -2 1 2.8 2.4 1.5 1.1 2.3 -0.4 -0.2 1 1.1 1.2 1.3 0.5 -0.1 0];
% Plot the before
figure()
plot(x, y2); hold all;
plot(x, y1)
% Find the optimum scale factor
f_start = 0; % May want a different starting point
f = fminsearch(#(f) func(f, y1, y2), f_start);
disp(['Scale factor = ' num2str(f)]) % print to the output
% Plot the after (scaled data)
figure()
plot(x, y2); hold all;
plot(x, f*y1)
For more information see the docs on anonymous functions and fminsearch (see example #2).
EDIT
Here is the output of the above script:
Scale factor = -2.9398
Before
After
As you can see the difference between the functions is minimized (area where y1 is greater than y2 is about the same as the area where y1 is less than y2). If you want the lines to match up as close as possible then you need to modify the minimization function like so:
func = #(f, y1, y2)sum(abs(y2 - f*y1));
I had to modify the test data for this case as it appears the data was already lined up optimally.
y1 = [0 0 -0.3 -0.8 -1.1 -1 -0.5 1 1.1 1 -0.3 -0.8 -1.1 -1 -0.5 0.1 0.05 0 0 0];
y2 = -2*y1 +1;
which gives the following output:
Scale factor = -2.9091
Before
After

Why does my 3 axes system coordinate orientation change x with y values?

I am using Matlab and Euler Angles in order to reorient a 3axes coordinate system. Specifically,
Rz = [cos(ψ) sin(ψ) 0;-sin(ψ) cos(ψ) 0;0 0 1];
Ry = [cos(φ) 0 -sin(φ);0 1 0;sin(φ) 0 cos(φ)];
Rx = [1 0 0;0 cos(θ) -sin(θ);0 sin(θ) cos(θ)];
Rtotal = Rz*Ry*Rz
Then I loop through my old system coordinates (x,y,z) and make a vector coord_old. Then I get the reoriented system with (xn,yn,zn)
for i=1:size(num,1)
coord_old = [x(i,1);y(i,1);z(i,1)];
coord_new = Rtotal*coord_old;
xn(i,1) = coord_new(1,1);
yn(i,1) = coord_new(2,1);
zn(i,1) = coord_new(3,1);
end
My issue is that when θ,φ,ψ≃0 then x->-y and y->x and when θ,φ≃0 and ψ=90 then x and y will not rotate! That means that when x,y should rotate they don't and when they shouldn't rotate they stay as they were!
--EDIT--
For example, when ψ=20.0871, φ=0.0580 and θ=0.0088 I get these results
See that x->-y and y->x while z doesn't change at all!
Any thoughts?
Ok, I see two main problems here:
Rtotal = Rz*Ry*Rz is probably not what you want since Rz is multiplied twice. I think you mean Rtotal = Rz*Ry*Rx.
Your rotation matrix seems to be incorrect. Check this Wikipedia artice to get the correct signs.
Here a corrected rotation matrix:
Rz = [cos(psi) -sin(psi) 0; sin(psi) cos(psi) 0; 0 0 1];
Ry = [cos(phi) 0 sin(phi); 0 1 0; -sin(phi) 0 cos(phi)];
Rx = [1 0 0; 0 cos(theta) -sin(theta); 0 sin(theta) cos(theta)];
Rtotal = Rz*Ry*Rx;
With this matrix I get the correct results:
x=1; y=2; z=3;
psi=0; phi=0; theta=0;
[xn,yn,zn] >> 1 2 3
x=1; y=2; z=3;
psi=90/180*pi; phi=0; theta=0;
[xn,yn,zn] >> -2 1 3
And here a full graphical example of a cube in 3d-space:
% Create cube (not in origin)
DVert = [0 0 0; 0 1 0; 1 1 0; 1 0 0 ; ...
0 0 1; 0 1 1; 1 1 1; 1 0 1];
DSide = [1 2 3 4; 2 6 7 3; 4 3 7 8; ...
1 5 8 4; 1 2 6 5; 5 6 7 8];
DCol = [0 0 1; 0 0.33 1; 0 0.66 1; ...
0 1 0.33; 0 1 0.66; 0 1 1];
% Rotation angles
psi = 20 /180*pi; % Z
phi = 45 /180*pi; % Y
theta = 0 /180*pi; % X
% Rotation matrix
Rz = [cos(psi) -sin(psi) 0; sin(psi) cos(psi) 0; 0 0 1];
Ry = [cos(phi) 0 sin(phi); 0 1 0; -sin(phi) 0 cos(phi)];
Rx = [1 0 0; 0 cos(theta) -sin(theta); 0 sin(theta) cos(theta)];
Rtotal = Rz*Ry*Rz;
% Apply rotation
DVertNew = Rtotal * DVert';
% Plot cubes
figure;
patch('Faces',DSide,'Vertices',DVert,'FaceColor','flat','FaceVertexCData',DCol);
patch('Faces',DSide,'Vertices',DVertNew','FaceColor','flat','FaceVertexCData',DCol);
% Customize view
grid on;
axis equal;
view(30,30);
When I use your code and insert 0 for all angles, I get Rtotal:
Rtotal =
1 0 0
0 1 0
0 0 1
This is the identity matrix and will not change your values.
You have an error in your matrix multiplication. I think you should multiply: Rtotal*coord_old. I think you are missing the _old. depending on what is in you coordvariable, this may be the bug.
When I run:
for i=1:size(1,1)
coord_old = [1;2;3];
coord_new = Rtotal*coord_old;
xn(i,1) = coord_new(1,1);
yn(i,1) = coord_new(2,1);
zn(i,1) = coord_new(3,1);
end
I get the correct result:
coord_new =
1
2
3
Thank you both #Steffen and #Matt. Unfortunately, my reputation is not high enough to vote Up your answers!
The problem was not with Rtotal as #Matt correctly stated. It should be as it was Rz*Ry*Rx. However, both your ideas helped me test my code with simple examples (5 sets of coordinates and right hand rule), and realize where my (amateur) mistake was.
I had forgotten I had erased parts of codes where I was expressing my angles to degrees... I should be using sind & cosd instead of sin and cos.

Polyarea returns false value

X = [0 0 1 1];
Y = [0 1 0 1];
polyarea(X,Y)
ans = 0
Here the answer should be 1 , but I got this as answer , there is no prob with other co ordinates
Take care of the vertices order
X = [0 0 1 1];
Y = [0 1 1 0];
should work.

How to get the bounding box of non-zero elements in MATLAB?

Let's say, I have a matrix (by imread) as following:
A = [0 0 1 0 0;
0 0 1 0 0;
0 1 1 1 0;
0 0 1 0 0;
0 0 0 0 0];
I would like to get the bounding box of non-zero elements as
BB = show_me_the_bounding_box(A);
BB = [1, 2, 4, 4]; % y0, x0, y1, x0
What function I should use to do that?
Use REGIONPROPS
stats = regionprops(A,'BoundingBox');
BB = stats.BoundingBox;
To get the result you want, please use:
[y,x] = ind2sub(size(A), find(A))
coord = [y, x]
[min(coord) max(coord)] % [1 2 4 4]
Note however that, with the correct conventions, the bounding box is:
[y,x] = ind2sub(size(A), find(A))
coord = [x, y]
mc = min(coord)-0.5
Mc = max(coord)+0.5
[mc Mc-mc] % [1.5 0.5 3 4]
which yields the same result as:
stats = regionprops(A, 'BoundingBox')
BB = stats.BoundingBox % [1.5 0.5 3 4]
The code can easily be adapted to 3D images, by using:
[y,x,z] = ind2sub(size(A), find(A));
coord = [x, y, z];
mc = min(coord)-0.5;
Mc = max(coord)+0.5;
[mc Mc-mc]