Finding Signed Angle Between Vectors
If you have an atan2() function in your math library of choice:
signed_angle = atan2(b.y,b.x) - atan2(a.y,a.x)
How to calculate the signed angle between 2 vectors with a given axis normal in 3D?
I don't think the problem has a solution unless both A and B are the same length and A and B both make the same angle (in the usual sense of shortest angle between vectors) with the axis. I will assume that these are given.
In that case, one solution would be to compute the orthogonal projection of both A and B into a plane that is orthogonal to the axis. This could be done by subtracting the component that is in the direction of the axis. So if I have a unit vector in the direction of the axis and call it X, the computation would be something like
Aproj = A - dot(A, X)X
Bproj = B - dot(B, X)X
Then the angle between Aproj
and Bproj
(in the usual sense of shortest angle) is the angle of rotation around the axis that you are asking about.
I'm not sure if this is the simplest way to compute it, but it should work pretty generally.
Signed angle between two vectors without a reference plane
Thanks all. After reviewing the comments here and looking back at what I was trying to do, I realized that I can accomplish what I need to do with the given, standard formula for a signed angle. I just got hung up in the unit test for my signed angle function.
For reference, I'm feeding the resulting angle back into a rotate function. I had failed to account for the fact that this will naturally use the same axis as in signed_angle (the cross product of input vectors), and the correct direction of rotation will follow from which ever direction that axis is facing.
More simply put, both of these should just "do the right thing" and rotate in different directions:
rotate(cross(Va, Vb), signed_angle(Va, Vb), point)
rotate(cross(Vb, Va), signed_angle(Vb, Va), point)
Where the first argument is the axis of rotation and second is the amount to rotate.
Getting a signed angle value
Dot product will only give you the cosine of the angle formed by the two vectors. It is positive of they are facing the same direction, negative for opposite directions and 0 if they are perpendicular.
Simply check the "RightDirection" to get the sign that corresponds to the original dot product.
By doing this, you will exclude the zeros given by the cardinal directions, so substitute the opposite axis when zero.
Here is the Blueprint pseudocode:
Vector TargetDirection = Normalize(Player.GetActorLocation - Object.GetActorLocation);
float LR = dot(TargetDirection, Player.GetActorRotation.GetRightVector);
float SignLR = Sign(LR); // returns -1,0,1
float Angle = dot(TargetDirection,Player.GetActorRotation.GetForwardVector);
// catch the dot product zeros at(0,90,180,270...)
// if is a float comparison object with the bool output passed to a branch
if(Angle == 0) Angle = LR; // pick a direction (90 degrees left or right)
if(SignLR == 0) SignLR = Angle; //pick a direction
float Signed Angle = SignLR * Angle;
Note: The variables are not needed, when implementing this code, the output pin is wired directly to the multiple inputs.
signed angle between 2D vectors
subtract-headings 30 330
will give you what you asked for by saying "clockwise is positive (against the example you gave).
Using atan2 to find angle between two vectors
atan2(vector1.y - vector2.y, vector1.x - vector2.x)
is the angle between the difference vector (connecting vector2 and vector1) and the x-axis,
which is problably not what you meant.
The (directed) angle from vector1 to vector2 can be computed as
angle = atan2(vector2.y, vector2.x) - atan2(vector1.y, vector1.x);
and you may want to normalize it to the range [0, 2 π):
if (angle < 0) { angle += 2 * M_PI; }
or to the range (-π, π]:
if (angle > M_PI) { angle -= 2 * M_PI; }
else if (angle <= -M_PI) { angle += 2 * M_PI; }
How to calculate signed angles between 3 points
The signed angle between two 2D-vectors u
and v
can be obtained with the help of the atan2
function:
angle_unsigned <- function(u, v){
acos( sum(u*v) / ( sqrt(sum(u*u)) * sqrt(sum(v*v)) ) )
}
angle_signed <- function(u, v){
atan2(v[2], v[1]) - atan2(u[2], u[1])
}
EDIT
In 3D, you need to have a direction, represented by a vector n
. The angle3D_signed
function below returns the angle in [0,2pi[
by which the vector u
must rotate counterclockwise, as seen from the direction defined by n
, to reach the vector v
.
crossProduct <- function(v, w){
c(
v[2] * w[3] - v[3] * w[2],
v[3] * w[1] - v[1] * w[3],
v[1] * w[2] - v[2] * w[1]
)
}
angle3D_signed <- function(n, u, v){
n <- n / sqrt(sum(n*n)) # normalize n
unorm <- sqrt(sum(u*u))
vnorm <- sqrt(sum(v*v))
s <- sum(crossProduct(n, u) * v) # "unnormalized sine"
cosAngle <- sum(u*v) / unorm / vnorm
ifelse(s >= 0, acos(cosAngle), 2*pi - acos(cosAngle))
}
Direct way of computing clockwise angle between 2 vectors
2D case
Just like the dot product is proportional to the cosine of the angle, the determinant is proprortional to its sine. So you can compute the angle like this:
dot = x1*x2 + y1*y2 # dot product between [x1, y1] and [x2, y2]
det = x1*y2 - y1*x2 # determinant
angle = atan2(det, dot) # atan2(y, x) or atan2(sin, cos)
The orientation of this angle matches that of the coordinate system. In a left-handed coordinate system, i.e. x pointing right and y down as is common for computer graphics, this will mean you get a positive sign for clockwise angles. If the orientation of the coordinate system is mathematical with y up, you get counter-clockwise angles as is the convention in mathematics. Changing the order of the inputs will change the sign, so if you are unhappy with the signs just swap the inputs.
3D case
In 3D, two arbitrarily placed vectors define their own axis of rotation, perpendicular to both. That axis of rotation does not come with a fixed orientation, which means that you cannot uniquely fix the direction of the angle of rotation either. One common convention is to let angles be always positive, and to orient the axis in such a way that it fits a positive angle. In this case, the dot product of the normalized vectors is enough to compute angles.
dot = x1*x2 + y1*y2 + z1*z2 #between [x1, y1, z1] and [x2, y2, z2]
lenSq1 = x1*x1 + y1*y1 + z1*z1
lenSq2 = x2*x2 + y2*y2 + z2*z2
angle = acos(dot/sqrt(lenSq1 * lenSq2))
Edit: Note that some comments and alternate answers advise against the use of acos
for numeric reasons, in particular if the angles to be measured are small.
Plane embedded in 3D
One special case is the case where your vectors are not placed arbitrarily, but lie within a plane with a known normal vector n. Then the axis of rotation will be in direction n as well, and the orientation of n will fix an orientation for that axis. In this case, you can adapt the 2D computation above, including n into the determinant to make its size 3×3.
dot = x1*x2 + y1*y2 + z1*z2
det = x1*y2*zn + x2*yn*z1 + xn*y1*z2 - z1*y2*xn - z2*yn*x1 - zn*y1*x2
angle = atan2(det, dot)
One condition for this to work is that the normal vector n has unit length. If not, you'll have to normalize it.
As triple product
This determinant could also be expressed as the triple product, as @Excrubulent pointed out in a suggested edit.
det = n · (v1 × v2)
This might be easier to implement in some APIs, and gives a different perspective on what's going on here: The cross product is proportional to the sine of the angle, and will lie perpendicular to the plane, hence be a multiple of n. The dot product will therefore basically measure the length of that vector, but with the correct sign attached to it.
How do you find the singed angles between two vectors in three.js?
I'll suggest you to use a reference plane, personally i didn't need the sign of the angle
returned from .angleTo()
method so i suggest you to read this two posts:
Signed angle between two 3D vectors with same origin within the same plane
How to calculate the angle between 2 vectors in a plane
Related Topics
Android How to Sort JSONarray of JSONobjects
How to Ask Permission to Access Gallery on Android M.
Compare Protocol in Swift VS Interface in Java
What Is the Equivalent of a Java Hashmap<String,Integer> in Swift
How to Highlight Multiple Words in Edittext
Alternative to Jzebra/Qz Java Raw Print Plugin After Npapi Being Dropped on Chrome Browser
Calling a Java Servlet from JavaScript
Detecting Device Type in a Web Application
Android:Table Has No Column Named "Variable Name" MySQL Database Error
Google Cloud Messaging: Don't Receive Alerts When iOS App Is in Background
Hbase Client Connectionloss for /Hbase Error
Is There an Advantage to Running Jruby If You Don't Know Any Java
Wrong Version of Keystore on Android Call
Tcp\Ip Client - Ehostunreach (No Route to Host)