Measure angles between two vectors solely counter - clockwise

40 visualizzazioni (ultimi 30 giorni)
Hi,
I have two vectors and I want to measure the angle between them. The first one lies solely along the positive x-axis, and the second one varies in a circle. When the angle between the two gets greater than 180 degrees, MATLAB starts to measure the angle clockwise, but I would like it to continue to measure the angle counter clockwise. (e.g, after 180, measure 190, 200 etc.. instead of 170, 160 etc..). Any workarounds? Stuff like atan2 doesn't work. Thanks in advance!
  2 Commenti
Jan
Jan il 17 Lug 2018
Matlab does not measure anything. But you can write some Matlab commands to calculate the angle. Of course atan2 does exactly, what is mathematically defined. But if you want to consider the sign in addition - consider the sign in addition.
Do you mean the 2D case, or are the vectors in 3D? In the latter case, "clockwise" or "counterclockwise" is not well defined, because it depends on the direction of view. Then please define this explicitly, because it is neither obvious nor uniquely defined in a mathematical sense.
The best idea is to post two example inputs and outputs together with the current code you use.
Adam Danz
Adam Danz il 17 Lug 2018
Yeah, some examples will be helpful. A solution might be to use a conditional that detects cw or ccw outputs based on the sign of the angle and corrects for the undesired direction (assuming 2D).
if theta < 0
theta = 180 + (theta + 180);
end
or
if theta > 0
theta = -180 - (180-theta);
end

Accedi per commentare.

Risposta accettata

David Goodmanson
David Goodmanson il 17 Lug 2018
Modificato: David Goodmanson il 17 Lug 2018
Hi Harvey,
It looks like you want the angle in degrees. For two dimensions, where the second vector has components x,y:
theta = mod(atan2d(y,x)+360,360)
  4 Commenti
Harvey Rael
Harvey Rael il 17 Lug 2018
just did there yes! Sorry to be so quick to dismiss, didn't understand your answer. Not quite sure about the code, but happy to read the literature now I know it works! Thanks for your help!
David Goodmanson
David Goodmanson il 17 Lug 2018
Going around clockwise from just below the negative x axis, the range of atan2d is continuous from -180 to 180. You want to add 360 to the result in Quadrants III and IV and leave Quadrants I and II alone.
Quadrants III, IV Quadrants I, II
atan2d -180 -> 0 0 -> 180
add 360 180 -> 360 ok 360 -> 540 no
mod(...,360) 180 -> 360 still ok 0 -> 180 ok
since mod subtracts (multiples of) 360 from anything larger than 360.

Accedi per commentare.

Più risposte (2)

theodore panagos
theodore panagos il 10 Gen 2019
The formula gives the angle from positive x-axis to 360 degrees counter clockwise:
f(x,y)=180-90*(1+sign(x))* (1-sign(y^2))-45*(2+sign(x)) *sign(y)
-(180/pi())*sign(x*y)*atan((abs(x)-abs(y))/(abs(x)+abs(y)))
x=x2-x1 and y=y2-y1 .

Jan
Jan il 17 Lug 2018
Modificato: Jan il 17 Lug 2018
In the 3D case:
function A = AngleIn3D(V1, V2, View)
% Input: V1, V2, View: [N x 3] vectors, each one can be [1 x 3] also.
% The angle between the vectors V1 and V2 is calculated
% The View defines the view direction to define the sign of the angle
%
% Method: atan2(norm(N1 x N2), DOT(N1, N2))
% W. Kahan suggested in "Mindeless.pdf":
% 2 * atan(norm(x*norm(y) - norm(x)*y) / norm(x * norm(y) + norm(x) * y))
N1 = V1 ./ sqrt(sum(V2 .* V2, 2)); % >= R2016b: arithmetic expanding!
N2 = V2 ./ sqrt(sum(V2 .* V2, 2)); % >= R2016b: arithmetic expanding!
% Calculate dot and cross product of vectors:
N1dotN2 = N1(:, 1) .* N2(:, 1) + N1(:, 2) .* N2(:, 2) + N1(:, 3) .* N2(:, 3);
N1xN2 = [(N1(:, 2) .* N2(:, 3) - N1(:, 3) .* N2(:, 2)), ...
(N1(:, 3) .* N2(:, 1) - N1(:, 1) .* N2(:, 3)), ...
(N1(:, 1) .* N2(:, 2) - N1(:, 2) .* N2(:, 1))];
% Angle between N1xN2 and view vector:
LXo = N1xN2(:, 1) .* View(:, 1) + N1xN2(:, 2) .* View(:, 2) + ...
N1xN2(:, 3) .* View(:, 3);
signLXo = sign(LXo);
% Care about anti-parallel N1 and N2:
antiN1N2 = (N1dotN2 < -0.999999999999993); % -1 + 3 * EPS
if any(antiN1N2)
antiN1N2 = and(antiN1N2, isfinite(N1dotN2)); % Catch N1dotN2=-Inf
signLXo(antiN1N2) = 1.0;
end
normN1xN2 = N1xN2 ./ sqrt(sum(N1xN2 .* N1xN2), 2);
Angle = signLXo .* atan2(normN1xN2, N1dotN2);
end
Now for the 2D case, set the 3rd component to 0 and use [0,0,1] as View direction. If you want the 2D case only, the above can be simplified massively.
function A = AngleIn2D(V1, V2)
% Input: V1, V2: [N x 3] vectors, each one can be [1 x 3] also.
% The angle between the vectors V1 and V2 is calculated
%
% Method: atan2(norm(N1 x N2), DOT(N1, N2))
% W. Kahan suggested in "Mindeless.pdf":
% 2 * atan(norm(x*norm(y) - norm(x)*y) / norm(x * norm(y) + norm(x) * y))
N1 = V1 ./ sqrt(sum(V2 .* V2, 2)); % >= R2016b: arithmetic expanding!
N2 = V2 ./ sqrt(sum(V2 .* V2, 2)); % >= R2016b: arithmetic expanding!
% Calculate dot and cross product of vectors:
N1dotN2 = N1(:, 1) .* N2(:, 1) + N1(:, 2) .* N2(:, 2);
N1xN2 = (N1(:, 1) .* N2(:, 2) - N1(:, 2) .* N2(:, 1));
% Angle between N1xN2 and view vector:
signLXo = sign(N1xN2);
% Care about anti-parallel N1 and N2:
antiN1N2 = (N1dotN2 < -0.999999999999993); % -1 + 3 * EPS
if any(antiN1N2)
antiN1N2 = and(antiN1N2, isfinite(N1dotN2)); % Catch N1dotN2=-Inf
signLXo(antiN1N2) = 1.0;
end
normN1xN2 = abs(N1xN2);
Angle = signLXo .* atan2(normN1xN2, N1dotN2);
end
!UNTESTED CODE!
  2 Commenti
Harvey Rael
Harvey Rael il 17 Lug 2018
Modificato: Harvey Rael il 17 Lug 2018
Cheers guys - So a few clarifications:
It is the 2-D case. An Example would be :
v1 is ALWAYS [1,0]; and a couple of examples of v2 would be [-1,0]; and [0,-1]; In the first case, the measured angle between the two (using the dot product formula) would output 180 degrees. In the second case, MATLAB spits out 90 degress, even though from the positive x - axis engineering convention is to measure positively counter clockwise (ergo, a positive value would be 270 degress) and negatively clockwise (ergo, -90). MATLAB has chosen to only give out positive values of the angle (90), ignoring convention, which is understandeable as it is a software. My question is if there's a work around for that.
Roberto Enrique
Roberto Enrique il 12 Gen 2024
Modificato: Roberto Enrique il 12 Gen 2024
Hi! Jan, thank you for the code.
For 3D case i define V1=[0 0 0;1 1 1], V2=[1 1 1;2 3 4] and run the code as follows and the given errors
>> A = AngleIn3D(V1, V2, 1)
Index in position 2 exceeds array bounds. Index must not exceed 1.
Error in AngleIn3D (line 18)
LXo = N1xN2(:, 1) .* View(:, 1) + N1xN2(:, 2) .* View(:, 2) + N1xN2(:, 3) .* View(:, 3);
>> A = AngleIn3D(V1, V2, [1 0 0])
Error using sqrt
Too many input arguments.
Error in AngleIn3D (line 27)
normN1xN2 = N1xN2 ./ sqrt(sum(N1xN2 .* N1xN2), 2);
>> A = AngleIn3D(V1, V2, [0 0 0])
Error using sqrt
Too many input arguments.
Error in AngleIn3D (line 27)
normN1xN2 = N1xN2 ./ sqrt(sum(N1xN2 .* N1xN2), 2);
>> A = AngleIn3D(V1, V2, [1 1 1])
Error using sqrt
Too many input arguments.
Error in AngleIn3D (line 27)
normN1xN2 = N1xN2 ./ sqrt(sum(N1xN2 .* N1xN2), 2);
Could you help to solve this?
Thank you, sorry for my broken english

Accedi per commentare.

Prodotti


Release

R2018a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by