Related
I need to calculate the angle between two plane. One plane is the hand plane and the second is the forearm plane. I calculated the normals of that planes and used the formula atan2(norm(cross(var.n1,var.n2)),dot(var.n1,var.n2)); in MATLAB. I want to see the flexion/extension angle of the wrist that is characterised by positive and negative peaks but with this formula I obtain only positive peaks.
%% Script to compute the angles of wrist flexion/extension and adduction/abduction based on Vicon data
% REF: Cheryl et al., March 2008
% Order of the markers: 1.WRR 2.WRU 3.FAU 4.FAR 5.CMC2 6.CMC5 7.MCP5 8.MCP2
clc
close all
clear all
%% Initialization
% dir_kinematic = input('Path of the folder containing the kinematic files: ','s');
dir_kinematic = 'C:\Users\Utente\Desktop\TESI\Vicon\test.mat';
cd(dir_kinematic);
fileList = getAllFiles(dir_kinematic,0); % Get names of all kinematic files
f=1;
%% Conversion to angles
for f = 1:length(fileList)
if ~isempty(strfind(fileList{f},'mat')) % Take only mat files
% 0. Loading
load(fileList{f});
% 1. Filtering
frameRate = kinematic.framerate;
n = 9;
Wn = 2/(frameRate/2);
ftype = 'low';
[b,a] = butter(n,Wn,ftype);
kinematic.x = filtfilt(b,a,kinematic.x);
kinematic.y = filtfilt(b,a,kinematic.y);
kinematic.z = filtfilt(b,a,kinematic.z);
% 2. Create vectors
var.n=length(kinematic.x);
% Forearm plane
var.FAU_WRU=[kinematic.x(:,2)-kinematic.x(:,3),kinematic.y(:,2)-kinematic.y(:,3),kinematic.z(:,2)-kinematic.z(:,3)];
var.WRR_WRU=[kinematic.x(:,2)-kinematic.x(:,1),kinematic.y(:,2)-kinematic.y(:,1),kinematic.z(:,2)-kinematic.z(:,1)];
% Hand plane
var.CMC5_MCP5=[kinematic.x(:,7)-kinematic.x(:,6),kinematic.y(:,7)-kinematic.y(:,6),kinematic.z(:,7)-kinematic.z(:,6)];
var.MCP2_MCP5=[kinematic.x(:,7)-kinematic.x(:,8),kinematic.y(:,7)-kinematic.y(:,8),kinematic.z(:,7)-kinematic.z(:,8)];
% Transpose
var.FAU_WRU = var.FAU_WRU';
var.WRR_WRU = var.WRR_WRU';
var.CMC5_MCP5 = var.CMC5_MCP5';
var.MCP2_MCP5 = var.MCP2_MCP5';
% 3. Calculate angle of wrist flexion/extension
% Cross vector function for all time => create normal vector plane
var.forearm_n=[];
var.hand_n=[];
var.theta_rad=[];
for i = 1:var.n % Loop through experiment
% vector x and y of the forearm plane
var.v1=var.FAU_WRU(:,i); % take x,y,z of the vector for every time
var.v2=var.WRR_WRU(:,i);
% vector x and y of the hand plane
var.v3=var.CMC5_MCP5(:,i);
var.v4=var.MCP2_MCP5(:,i);
var.forearm_n= [var.forearm_n, cross(var.v1,var.v2)];
var.hand_n=[var.hand_n, cross(var.v3,var.v4)];
end
% Calculate angle
for i = 1:var.n
var.n1=(var.forearm_n(:,i));
var.n2=var.hand_n(:,i);
var.scalar_product(i) = dot(var.n1,var.n2);
%Equation (2) of the paper
var.theta_rad=[var.theta_rad, atan2(norm(cross(var.n1,var.n2)),dot(var.n1,var.n2))]; % result in radian
angle.flex_deflex_wrist{f}=(var.theta_rad*180)/pi;
end
% 4. Calculate angle of wrist adduction/abduction
% Projection vector onto plane
var.MCP2_MCP5_forearmproj=[];
var.WRR_WRU_forearmproj=[];
var.rad_ul_angle_rad=[];
for i=1:var.n
%take x,y,z of the vector for each time
var.v1=var.MCP2_MCP5(:,i);
var.v2=var.WRR_WRU(:,i);
% vector x and y of the forearm plane
var.vfx=var.FAU_WRU(:,i); % take x,y,z of the vector for every time
var.vfy=var.WRR_WRU(:,i);
%projection of vector MCP2_MCP5 and WRR_WRU onto forearm plane
var.squNorm1=(norm(var.vfx)*norm(var.vfx));
var.squNorm2=(norm(var.vfy)*norm(var.vfy));
var.MCP2_MCP5_forearmproj=[var.MCP2_MCP5_forearmproj,((((var.v1')*var.vfx)*var.vfx/var.squNorm1)+(((var.v1')*var.vfy)*var.vfy/var.squNorm2))];
var.WRR_WRU_forearmproj=[var.WRR_WRU_forearmproj,((var.vfx*((var.v2')*var.vfx/var.squNorm1))+(var.vfy*((var.v2')*var.vfy/var.squNorm2)))];
end
% Calculate angle
for i=1:var.n
var.n1=var.MCP2_MCP5_forearmproj(:,i)';
var.n2=var.WRR_WRU_forearmproj(:,i);
var.product=var.n1*var.n2;
var.rad_ul_angle_rad=[var.rad_ul_angle_rad, atan2(norm(cross(var.n1,var.n2)),dot(var.n1,var.n2))];% en rad
angle.rad_ul_wrist{f}=(var.rad_ul_angle_rad*180)/pi;
end
end
end
I want to know why my angles are always positive? I need to see positive and negative peaks...
Thanks for the help!
Since the angle between two planes is the same as that between it's normals, I will constrain the discussion to angle between two vectors.
We know that the cross product between two vectors (a and b) is another vector, perpendicular to both of them.
We are dealing with the problem of distinguishing angles -T and +T, where T is some angle.
Using the formula you used, these two angles would give the same result, due to the fundamental formula itself that is used:
atan2 (|a x b|, a.b)
This is because while a.b is the same in both cases, a x b differs, exactly in the sign of the normal to the two vectors, and nothing else (verify yourself using hand rules). When we compute the norm of this vector, information about its sign is lost, due to which the function always returns positive values.
What you can do about it
You need to keep track of the sign of a x b, to determine if the angle is positive or negative.
Note: As I'm replying from my phone I am unable to add better formatting or code, will update the answer soon.
Assume that I have a vector with 6 distance elements as
D = [10.5 44.8 30.01 37.2 23.4 49.1].
I'm trying to create random pair positions of a given distances, inside a 200 meters circle. Note that the distance D created by using (b - a).*rand(6,1) + a, with a = 10 and b = 50 in Matlab. I do not know how to generate the random pairs with given the distances.
Could anybody help me in generating this kind of scenario?
This is an improvement to Alessiox's answer. It follows same logic, first generate a set of points ([X1 Y1]) that have at least distance D from the main circle border, then generate the second set of points ([X2 Y2]) that have exact distance D from the first set.
cx = 50; cy = -50; cr = 200;
D = [10.5 44.8 30.01 37.2 23.4 49.1]';
n = numel(D);
R1 = rand(n, 1) .* (cr - D);
T1 = rand(n, 1) * 2 * pi;
X1 = cx+R1.*cos(T1);
Y1 = cy+R1.*sin(T1);
T2 = rand(n, 1) * 2 * pi;
X2 = X1+D.*cos(T2);
Y2 = Y1+D.*sin(T2);
You can tackle the problem using a two-steps approach. You can
randomly generate the first point and then you can consider the circle whose center is that point and whose radius is the distance in D
once you did draw the circle, every point lying on that circle will have distance D from the first point previously created and by random selection of one of these candidates you'll have the second point
Let's see with an example: let's say you main circle has radius 200 and its center is (0,0) so we start by declaring some main variables.
MAINCENTER_x=0;
MAINCENTER_y=0;
MAINRADIUS=200;
Let's now consider the first distance, D(1)=10.5 and we now generate the first random point which (along with its paired point - I reckon you don't want one point inside and the other outside of the main circle) must lie inside the main circle
r=D(1); % let's concentrate on the first distance
while true
x=((MAINRADIUS-2*r) - (-MAINRADIUS+2*r))*rand(1,1) + (-MAINRADIUS+2*r);
y=((MAINRADIUS-2*r) - (-MAINRADIUS+2*r))*rand(1,1) + (-MAINRADIUS+2*r);
if x^2+y^2<=(MAINRADIUS-2*r)^2
break;
end
end
and at the end of this loop x and y will be our first point coordinates.
Now we shall generate all its neighbours, thus several candidates to be the second point in the pair. As said before, these candidates will be the points that lie on the circle whose center is (x,y) and whose radius is D(1)=10.5. We can create these candidates as follows:
% declare angular spacing
ang=0:0.01:2*pi;
% build neighbour points
xp=r*cos(ang)+x;
yp=r*sin(ang)+y;
Now xp and yp are two vectors that contain, respectively, the x-coordinates and y-coordinates of our candidates, thus we shall now randomly select one of these
% second point
idx=randsample(1:length(xp),1);
secondPoint_x=xp(idx);
secondPoint_y=yp(idx);
Finally, the pair (x,y) is the first point and the pair (secondPoint_x, secondPoint_y) is our second point. The following plot helps summarizing these steps:
The red circle is the main area (center in (0,0) and radius 200), the red asterisk is the first point (x,y) the blue little circle has center (x,y) and radius 10.5 and finally the black asterisk is the second point of the pair (secondPoint_x, secondPoint_y), randomly extracted amongst the candidates lying on the blue little circle.
You must certainly can repeat the same process for all elements in D or rely on the following code, which does the very same thing without iterating through all the elements in D.
MAINCENTER_x=0;
MAINCENTER_y=0;
MAINRADIUS=200;
D = [10.5 44.8 30.01 37.2 23.4 49.1];
% generate random point coordinates
while true
x=((MAINRADIUS-2*D) - (-MAINRADIUS+2*D)).*rand(1,6) + (-MAINRADIUS+2*D);
y=((MAINRADIUS-2*D) - (-MAINRADIUS+2*D)).*rand(1,6) + (-MAINRADIUS+2*D);
if all(x.^2+y.^2<=(MAINRADIUS-2*D).^2)
break;
end
end
% declare angular spacing
ang=0:0.01:2*pi;
% build neighbour points
xp=bsxfun(#plus, (D'*cos(ang)),x');
yp=bsxfun(#plus, (D'*sin(ang)),y');
% second points
idx=randsample(1:size(xp,2),length(D));
secondPoint_x=diag(xp(1:length(D),idx));
secondPoint_y=diag(yp(1:length(D),idx));
%plot
figure(1);
plot(MAINRADIUS*cos(ang)+MAINCENTER_x,MAINRADIUS*sin(ang)+MAINCENTER_y,'r'); %main circle
hold on; plot(xp',yp'); % neighbours circles
hold on; plot(x,y,'r*'); % first points (red asterisks)
hold on; plot(secondPoint_x,secondPoint_y,'k*'); %second points (black asterisks)
axis equal;
Now x and y (and secondPoint_x and secondPoint_y by extension) will be vector of length 6 (because 6 are the distances) in which the i-th element is the i-th x (or y) component for the first (or second) point.
There are two reasons for me to ask this question:
I want to know if my understanding on this issue is correct.
To clarify a doubt I have.
I want to change the co-ordinate system of a set of points (Old cartesian coordinates system to New cartesian co-ordinate system). This transformation will involve Translation as well as Rotation. This is what I plan to do:
With respect to this image I have a set of points which are in the XYZ coordinate system (Red). I want to change it with respect to the axes UVW (Purple). In order to do so, I have understood that there are two steps involved: Translation and Rotation.
When I translate, I only change the origin. (say, I want the UVW origin at (5,6,7). Then, for all points in my data, the x co-ordinates will be subtracted by 5, y by 6 and z by 7. By doing so. I get a set of Translated data.)
Now I have to apply a rotation transform (on the Translated data). The Rotation matrix is shown in the image. The values Ux, Uy and Uz are the co-ordinates of a point on the U axis which has unit distance from origin. Similarly, the values Vx, Vy and Vz are the coordinates of a point on the V axis which has a unit distance from origin. (I want to know if I am right here.) Wx, Wy, Wz is calculated as ((normalized u) X (normalised v))
(Also, if it serves any purpose, I would like to let you know that I am using MATLAB.)
edit:
I have a set of 42 points in 3D (42 X 3 matrix A) I want the first point to be considered as origin of UVW plane. So the values of the first point will be my translation vector. Correct?
Next, to calculate the Rotation vector: According to my requirement, the 6th row of matrix A has to be the U axis while 37th row has to be V axis. Consequently, vector u will be (1st row minus 6th row) of matrix A. While vector v will be (1st row minus 37th row) of matrix A.
The first row of Rotation Matrix will be vector u/|u| (normalized). Second row will be vector v/|v| (v normalized). The third row will be (u X v) . Am I right here?
Given this information, how can I calculate the value of Wx, Wy and Wx. How can I calculate the 3rd row of rotation matrix R?
Since you already have U and V, the two basis vectors of the orthonormal UVW system, the W basis vector would be the cross product of U and V. The cross product gives out the vector that is perpendicular to its operands; hence W = U × V. The components of W would fill in the third row of the rotation matrix.
Is my approach correct?
The order of the transforms matter; changing the order would lead to different results. When doing transformations of systems, usually scaling and rotation are tackled first and translation is dealt with lastly. The reason for this is that rotation would always be with respect to the origin. If the new system isn't on the old one's origin then applying rotation would rotate the new system not around its own origin but around the old system's origin. See the rightside case of figure 3-4 on this page to understand the difference what would happen if it's not on the origin; imagine the pot as the UVW coordinate system.
Think of both the coordinate systems being super-imposed (laid one atop the other). Now when you rotate UVW system with respect to the origin of XYZ, you will end up with the effect of rotating UVW w.r.t its own origin. Once rightly oriented, you can apply translation to it. However, if you'd already translated, then rotating would lead to translated rotation.
If you're using column-vector convention then TR would be the order i.e. rotation followed by translation. If you're using the row-vector convention then RT would be the order, again the order is rotation followed by translation.
You can apply the cross product of the Vectors OU and OV.
I think it's easier to perform it in steps. 1) Translation. 2) Rotation about x-axis. 3) Rotation about y-axis. 4) Rotation about z-axis.
% Assuming this is your coordinates before any operation
x0 = 5; y0 = 5; z0 = 5;
% This is the new origin
u = 5; v = 6, w = 7;
% If you wish to rotate pi/4 about x-axis, pi/3 about y-axis, pi/2 about z- axis, the three representative rotation matrix will be:
rx = [1 0 0; 0 cos(pi/4) -sin(pi/4); 0 sin(pi/4) cos(pi/4)];
ry = [cos(pi/3) 0 sin(pi/3); 0 1 0; -sin(pi/3) 0 cos(pi/3)];
rz = [cos(pi/2) -sin(pi/2) 0; sin(pi/2) cos(pi/2) 0; 0 0 1];
% First perform translation
xT = x0-u; yT = y0-v; zT = z0-w;
% Then perform rotation about x
rotated_x = mtimes( rx,[xT;yT;zT]);
% Then perform rotation about y
rotated_xy = mtimes( ry, rotated_x);
% Then perform rotation about z
rotated_xyz = mtimes( rz, rotated_xy);
I want to draw a contour plot for 3D data.
I have a force in x,y,z directions I want to plot the contour3 for that
the dimensions of the Fx = 21x21X21 same for Fy and Fz
I am finding force = f*vector(x,y,z)
Then
Fx(x,y,z) = force(1)
Fy(x,y,z) = force(2)
Fz(x,y,z) = force(3)
I did the following but it is not working with me ?? why and how can I plot that
FS = sqrt(Fx.^2 + Fy.^2 + Fz.^2);
x = -10:1:10;
[X,Y] = meshgrid(x);
for i=1:length(FS)
for j = 1:length(FS)
for k=1:length(FS)
contour3(X,Y,FS(i,j,k),10)
hold on
end
end
end
This is the error I am getting
Error using contour3 (line 129)
When Z is a vector, X and Y must also be vectors.
Your problem is that FS is not the same shape as X and Y.
Lets illustrate with a simple example:
X=[1 1 1
2 2 2
3 3 3];
Y=[1 2 3
1 2 3
1 2 3];
Z=[ 2 4 5 1 2 5 5 1 2];
Your data is probably something like this. How does Matlab knows which Z entry corresponds to which X,Y position? He doesnt, and thats why he tells you When Z is a vector, X and Y must also be vectors.
You could solve this by doing reshape(FS,size(X,1),size(X,2)) and will probably work in your case, but you need to be careful. In your example, X and Y don't seem programatically related to FS in any way. To have a meaningful contour plot, you need to make sure that FS(ii,jj,k)[ 1 ] corresponds to X(ii,jj), else your contour plot would not make sense.
Generally you'd want to plot the result of FS against the variables your are using to compute it, such as ii, jj or k, however, I dont know how these look like so I will stop my explanation here.
[ 1 ]: DO NOT CALL VARIABLES i and j IN MATLAB!
I'm not sure if this solution is what you want.
Your problem is that contour and contour3 are plots to represent scalar field in 2D objects. Note that ball is 2D object - every single point is defined by angles theta and phi - even it is an object in "space" not in "plane".
For representation of vector fields there is quiver, quiver3, streamslice and streamline functions.
If you want to use contour plot, you have to transform your data from vector field to scalar field. So your data in form F = f(x,y,z) must be transformed to form of H = f(x,y). In that case H is MxN matrix, x and y are Mx1 and Nx1 vectors, respectively. Then contour3(x,y,H) will work resulting in so-called 3D graph.
If you rely on vector field You have to specify 6 vectors/matrices of the same size of corresponding x, y, z coordinates and Fx, Fy, Fz vector values.
In that case quiver3(x,y,z,Fx,Fy,Fz) will work resulting in 6D graph. Use it wisely!
As I comment the Ander's answer, you can use colourspace to get more dimensions, so You can create 5D or, theoretically, 6D, because you have x, y, z coordinates for position and R, G, B coordinates for the values. I'd recommend using static (x,y,R,G,B) for 5D graph and animated (x,y,t,R,G,B) for 6D. Use it wisely!
In the example I show all approaches mentioned above. i chose gravity field and calculate the plane 0.25 units below the centre of gravity.
Assume a force field defined in polar coordinates as F=-r/r^3; F=1/r^2.
Here both x and yare in range of -1;1 and same size N.
F is the MxMx3 matrix where F(ii,jj) is force vector corresponding to x(ii) and y(jj).
Matrix H(ii,jj) is the norm of F(ii,jj) and X, Y and Z are matrices of coordinates.
Last command ensures that F values are in (-1;1) range. The F./2+0.5 moves values of F so they fit into RGB range. The colour meaning will be:
black for (-1,-1,-1),
red for (1,-1,-1),
grey for (0,0,0)
Un-comment the type of plot You want to see. For quiver use resolution of 0.1, for other cases use 0.01.
clear all,close all
% Definition of coordinates
resolution=0.1;
x=-1:resolution:1;
y=x;
z=-.25;
%definition of matrices
F=zeros([max(size(x))*[1 1],3]); % matrix of the force
X=zeros(max(size(x))*[1 1]); % X coordinates for quiver3
Y=X; % Y coordinates for quiver3
Z=X+z; % Z coordinates for quiver3
% Force F in polar coordinates
% F=-1/r^2
% spherical -> cartesian transformation
for ii=1:max(size(x))
for jj=1:max(size(y))
% temporary variables for transformations
xyz=sqrt(x(ii)^2+y(jj)^2+z^2);
xy= sqrt(x(ii)^2+y(jj)^2);
sinarc=sin(acos(z/xyz));
%filling the quiver3 matrices
X(ii,jj)=x(ii);
Y(ii,jj)=y(jj);
F(ii,jj,3)=-z/xyz^2;
if xy~=0 % 0/0 error for x=y=0
F(ii,jj,2)=-y(jj)/xyz/xy*sinarc;
F(ii,jj,1)=-x(ii)/xyz/xy*sinarc;
end
H(ii,jj)=sqrt(F(ii,jj,1)^2+F(ii,jj,2)^2+F(ii,jj,3)^2);
end
end
F=F./max(max(max(F)));
% quiver3(X,Y,Z,F(:,:,1),F(:,:,2),F(:,:,3));
% image(x,y,F./2+0.5),set(gca,'ydir','normal');
% surf(x,y,Z,F./2+.5,'linestyle','none')
% surf(x,y,H,'linestyle','none')
surfc(x,y,H,'linestyle','none')
% contour3(x,y,H,15)
If I have points in a graph in matlab that are randomly sorted and when plotted produce various closed shapes. Given a specific point on the left side of one of the closed shapes how can I get all the points of that shape in a vector form keeping in mind the convention of collecting the points is moving in a clockwise direction.
A commented example:
cla
% Random data
x = rand(15,1);
y = rand(15,1);
scatter(x,y)
% Random point to the left
hold on
p = [-0.1, rand(1)*0.2 + 0.5];
plot(p(1),p(2),'*r')
% Separate points that lie above your point
idx = y >= p(2);
% Sort x then y increasing for upper half and x then y decreasing for lower half
shape = [sortrows([x( idx) y( idx)],[1 2])
sortrows([x(~idx) y(~idx)],[-1 -2])];
Check that shape contains clockwise sorted coordinates by plotting an open line:
% Plot clockwise open line
plot(shape(1:end ,1),shape(1:end,2),'k')