For example, GetAngle((0,0),(100,0),(100,100)) = 90. How could I find the angle between 3 2D Points.
Given points A, B, and C, you want the angle between AB and AC? First compute the vectors AB and AC -- it's just the coordinates of B minus coordinates of A and likewise for AC. Take the dot product of the two vectors. This is just the product of the x coordinates plus the product of the y coordinates of the vectors. Divide this number by the length of AB, and again by the length of AC. This result is the cosine of the angle between the two vectors, so take the arccos() and you have it.
Use the dot product:
(a,b,c) dot (d,e,f) = ad + be + bf
.
A dot B = length(A)*length(B)* cos(theta)
theta = arccos((A dot B)/(length(A)*length(B))
is the angle between vectors A and B.
This is easy if you have some basic knowledge of linear algebra.
A vector v (in a linear algebra sense, not std::vector ;) ) is a tuple v = (x,y,z).
The norm is the length of the vector |v| = sqrt(x*x + y*y + z*z)
The inner product of two vectors v1 = (x1, y1, z1) and v2 = (x2, y2, z2) is v1·v2 = x1*x2 + y1*y2 + z1*z2
The angle of vectors v1 and v2 is a = acos(v1·v2/(|v1|*|v2|))
The problem with using just the dot product here is that it is unstable near 0 or 180 degrees -- the slope of acos() approaches infinity near +/- 1.0 which will cause you to lose precision.
To fix this, you can compute a pseudo-cross product, and use atan2(), as follows:
// given A, B, C are 2D points:
BA= B - A; CA= C - A // vector subtraction, to get vector between points
dot= BA.x * CA.x + BA.y * CA.y
pcross= BA.x * CA.y - BA.y * CA.x
angle= atan2(pcross, dot) // this should be the angle BAC, in radians
This should be numerically robust unless one of the legs of the angle has zero length.
Note that this will also give you a signed angle, depending on whether BAC goes clockwise or counterclockwise; the acos() method will always give you a positive value. Of course, if you want only a positive angle, you can take abs(angle)
; the atan2() method will still be more robust, and probably faster.
From the Wykobi library:
template<typename T>
inline T vertex_angle(const T& x1, const T& y1, const T& z1,
const T& x2, const T& y2, const T& z2,
const T& x3, const T& y3, const T& z3)
{
/* Quantify coordinates */
T x1_ = x1 - x2;
T x3_ = x3 - x2;
T y1_ = y1 - y2;
T y3_ = y3 - y2;
T z1_ = z1 - z2;
T z3_ = z3 - z2;
/* Calculate Squared Distance */
T dist = (x1_ * x1_ + y1_ * y1_ + z1_ * z1_) *
(x3_ * x3_ + y3_ * y3_ + z3_ * z3_);
if (is_equal(dist,T(0.0)))
return T(0.0);
else
return T(acos((x1_ * x3_ + y1_ * y3_ + z1_ * z3_) / sqrt(dist)) * _180DivPI);
}
For 2D, just remove all the "z" terms.