Angle between 3 points?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Given three points A, B, and C, the usual question is: what is the angle at point B made by the segments BA and BC? This comes up in game development, robotics, GIS, and any code that needs to reason about direction changes. The reliable solution is to convert the points into vectors and compute the angle from those vectors.
Build the Two Vectors
The angle is always measured at the middle point, so if the problem says "angle between three points" and means A-B-C, point B is the vertex. That means you should build two vectors starting at B:
- '
BA = A - B' - '
BC = C - B'
In coordinates, if A = (ax, ay), B = (bx, by), and C = (cx, cy), then:
- '
BA = (ax - bx, ay - by)' - '
BC = (cx - bx, cy - by)'
Once you have those vectors, the original geometry problem becomes a standard vector problem. This is better than using slopes because slopes break on vertical lines and behave badly near them.
Use the Dot Product for the Unsigned Angle
The standard formula is:
- '
dot(u, v) = ux * vx + uy * vy' - '
|u| = sqrt(ux * ux + uy * uy)' - '
theta = acos(dot(u, v) / (|u| * |v|))'
That gives the smaller angle between the two vectors, in the range from 0 to pi radians. In degrees, convert with math.degrees.
Here is a complete Python example:
This version is practical because it handles the common failure case where one of the vectors has zero length and it clamps the cosine value before calling acos.
When You Need Direction, Use atan2
The dot-product formula gives only the unsigned angle. Sometimes that is not enough. For example, if you want to know whether a turn from BA to BC is clockwise or counterclockwise, you need a signed angle.
In two dimensions, combine the dot product with the scalar cross product:
- '
cross(u, v) = ux * vy - uy * vx' - '
signed_angle = atan2(cross(u, v), dot(u, v))'
That returns an angle in the range from -pi to pi. Positive and negative values indicate orientation.
This is often the better choice for path planning, steering, and polygon algorithms because it preserves turning direction.
Choosing the Right Representation
A few practical choices matter in production code.
First, decide whether your application wants radians or degrees. Most math libraries use radians, but user interfaces and debugging output are usually easier to read in degrees.
Second, decide whether you want the smaller angle only or the full signed turn. For collision handling or simple geometry checks, the smaller angle is usually enough. For navigation and rotation logic, the signed angle is often more useful.
Third, be explicit about the vertex. A large share of bugs in these calculations come from using the wrong point as the center of the angle. If the angle is at B, both vectors must start at B.
Common Pitfalls
A common mistake is using slopes instead of vectors. That creates division-by-zero cases for vertical lines and loses sign information.
Another frequent bug is forgetting that the angle is at the middle point. If you accidentally compute AB and AC, you are measuring the angle at A, not at B.
Floating-point rounding also matters. The expression passed to acos should be in the interval [-1, 1], but tiny precision errors can produce 1.0000000002 or -1.0000000001. Clamp the value before calling acos.
Finally, identical points make the angle undefined because one vector has length zero. Handle that case explicitly instead of letting the code fail later with a confusing error.
Summary
- The angle for
A-B-Cis the angle at pointB - Build vectors
BAandBCbefore doing any math - Use the dot product and
acosfor the smaller unsigned angle - Use
atan2(cross, dot)when direction matters - Clamp the cosine input to avoid floating-point errors
- Reject zero-length vectors when two points are the same

