As you wrote in your code, the angle between two (normalized) vectors is the inverse cosine of their point product.
To get the angle under the sign, you can use the third vector representing the normal of the plane on which the other two vectors lie - in your two-dimensional case it will be a three-dimensional vector pointing straight up, for example (0, 0, 1).
Then we take the transverse product of the first vector (the one to which you want to relate the angle) with the second vector (the cross-product note is not commutative). The sign of the angle must be the same as the sign of the point product between the resulting vector and the plane normal.
In the code (C #, sorry) - note that all vectors are considered normalized:
public static double AngleTo(this Vector3 source, Vector3 dest) { if (source == dest) { return 0; } double dot; Vector3.Dot(ref source, ref dest, out dot); return Math.Acos(dot); } public static double SignedAngleTo(this Vector3 source, Vector3 dest, Vector3 planeNormal) { var angle = source.AngleTo(dest); Vector3 cross; Vector3.Cross(ref source, ref dest, out cross); double dot; Vector3.Dot(ref cross, ref planeNormal, out dot); return dot < 0 ? -angle : angle; }
This works by taking advantage of the fact that the cross product between two vectors gives a third vector perpendicular (normal) to the plane defined by the first two (therefore, it is essentially a three-dimensional operation). axb
= -(bxa)
, so the vector will always be perpendicular to the plane, but on the other side depending on the (signed) angle between a
and b
(there is something called the right rule ).
Thus, the cross product gives us a signed vector perpendicular to the plane, which changes direction when the angle between the vectors passes through 180 °. If we know in advance a vector perpendicular to the plane that is directed upwards, then we can determine whether the transverse product is in the same direction as the plane, normal or not, by checking the sign of their point product.