How to calculate the angle between two 3D vectors?
437 views (last 30 days)
Show older comments
I have two vectors that I want to calculate the angle between in 3D space, U and V. Vector U is calculated by subtracting where the first object was at Point 1 from where the object currently is at Point 2. Vector V is calculated by subtracting where the second object is at Point 2 from where the first object is at Point 2. This should essentially make vector V perpendicular-ish to vector U.
I have scoured these forums and come across multiple lines of code that apprently work:
angle = atan2(norm(cross(u,v)), dot(u,v))
CosTheta = max(min(dot(u,v)/(norm(u)*norm(v)),1),-1);
angle = acos(dot(u,v)/norm(u)*norm(v))
angle = acos(dot(u)/norm(u),v/norm(v))
All seem to produce the desired angle when I run it with changes only in 2D, so no movement in the Z domain. However as soon as I try use the above formula for 3D movement is starts producing wrong results. I've double checked what the angle should be by using an online calculator and doing the calculations by hand and the formula seem to always be off.
For example. Object 1 travelling from (128,97,138) to (78,47,88) and object 2 travelling from (0,0,0) to (50,50,0) should produce an angle of 144.735 degrees at the last step; but using any of the above formula gives 134 degrees.
Is there something I'm missing here?
Thanks!
1 Comment
James Tursa
on 11 Mar 2024
You've got errors in the the last two formulae. See my post below for corrections.
Answers (2)
James Tursa
on 11 Mar 2024
Edited: James Tursa
on 11 Mar 2024
See a discussion here (includes a tiny angle example):
A comparison (correcting the formulae you wrote):
% most robust, most accurate, recovers tiny angles very well, slowest
atan2(norm(cross(u,v)), dot(u,v))
% robust, does not recover tiny angles, faster
max(min(dot(u,v)/(norm(u)*norm(v)),1),-1)
% not robust (may get domain error), does not recover tiny angles, fasterer
acos(dot(u,v)/(norm(u)*norm(v)))
% not robust (may get domain error), does not recover tiny angles, fasterer
acos(dot(u/norm(u),v/norm(v)))
% not robust (may get domain error), does not recover tiny angles, fastest
acos(dot(u,v)/sqrt(dot(u,u)*dot(v,v)))
By "domain error", I mean the dot( ) argument magnitude can be slightly larger than 1 in some u==v cases due to floating point numerical effects resulting in an unintended complex result. The "robust" methods are protected against this. Also, if one of the arguments is 0 vector, the atan2( ) method returns 0 while the other methods will return NaN. So the atan2( ) method is the "most robust" in this sense. Caveat: This assumes the language in use has atan2(0,0) coded this way (like MATLAB, Java, etc.), but is not guaranteed across all languages.
That last method is one I threw in that is essentially the same as method 3, except that only one sqrt( ) is needed instead of two norm( ) calls.
Finally, the relative speed rankings above are somewhat notional and can be highly dependent on the language being used and how the algorithm is coded. E.g., the dot( ) function is notoriously slow in MATLAB, so if I were to code the methods above I would use some form of matrix multiply instead. If u and v are column vectors, that last method could be coded as:
acos(u'*v/sqrt((u'*u)*(v'*v)))
0 Comments
Jonas
on 11 Mar 2024
look here:
P1=[78,47,88]-[128,97,138];
P2=[50,50,0]-[0,0,0];
a = atan2d(norm(cross(P1,P2)),dot(P1,P2))
0 Comments
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!