This example shows how you can find the tangent lines between two circles. Depending on how the circles are arranged, they can have 0, 2, or 4 tangent lines. If the circles don’t intersect, as on the left in Figure 1, they have 4 tangents: 2 outer tangents (blue) and 2 inner tangents (red). If the circles overlap, as shown in the middle of Figure 1, they have only 2 outer tangents. If one circle contains the other, as on the right in Figure 1, they have no tangents.

Suppose the two circles C1 and C2 have radii r1 and r2 where r2 ≥ r1. To find the outer tangents, consider Figure 2. The dashed circle has the same center as C2 and radius r2 – r1. By using the method used by the example Find the tangent lines between a point and a circle in C#, you can find the tangent lines between C1’s center and this dashed circle. Now move that line perpendicularly to itself distance r1 to get the outer tangent shown in Figure 2. Offset the other point/circle tangent perpendicular to itself to get the other outer tangent.

To find the inner tangents, consider Figure 3. Here the dashed circle has the same center as C1 and radius r1 + r2. By again using the methods of example Find the tangent lines between a point and a circle in C#, you can find the tangent lines between C2’s center and this dashed circle to get the dashed red line segment. Now move that line perpendicularly to itself distance r2 to get the inner tangent (the solid red segment) shown in Figure 3. Offset the other point/circle tangent perpendicular to itself to get the other inner tangent.

The basic idea here is somewhat tricky, but if you stare at the pictures long enough, you should be able to see how it works. You might also try drawing some pictures of your own.

The `FindCircleCircleTangents` method shown in the following code uses this technique to find the tangents between two circles.

// Find the tangent points for these two circles. // Return the number of tangents: 4, 2, or 0. private int FindCircleCircleTangents( PointF c1, float radius1, PointF c2, float radius2, out PointF outer1_p1, out PointF outer1_p2, out PointF outer2_p1, out PointF outer2_p2, out PointF inner1_p1, out PointF inner1_p2, out PointF inner2_p1, out PointF inner2_p2) { // Make sure radius1 <= radius2. if (radius1 > radius2) { // Call this method switching the circles. return FindCircleCircleTangents( c2, radius2, c1, radius1, out outer1_p2, out outer1_p1, out outer2_p2, out outer2_p1, out inner1_p2, out inner1_p1, out inner2_p2, out inner2_p1); } // Initialize the return values in case // some tangents are missing. outer1_p1 = new PointF(-1, -1); outer1_p2 = new PointF(-1, -1); outer2_p1 = new PointF(-1, -1); outer2_p2 = new PointF(-1, -1); inner1_p1 = new PointF(-1, -1); inner1_p2 = new PointF(-1, -1); inner2_p1 = new PointF(-1, -1); inner2_p2 = new PointF(-1, -1); // *************************** // * Find the outer tangents * // *************************** { float radius2a = radius2 - radius1; if (!FindTangents(c2, radius2a, c1, out outer1_p2, out outer2_p2)) { // There are no tangents. return 0; } // Get the vector perpendicular to the // first tangent with length radius1. float v1x = -(outer1_p2.Y - c1.Y); float v1y = outer1_p2.X - c1.X; float v1_length = (float)Math.Sqrt(v1x * v1x + v1y * v1y); v1x *= radius1 / v1_length; v1y *= radius1 / v1_length; // Offset the tangent vector's points. outer1_p1 = new PointF(c1.X + v1x, c1.Y + v1y); outer1_p2 = new PointF( outer1_p2.X + v1x, outer1_p2.Y + v1y); // Get the vector perpendicular to the // second tangent with length radius1. float v2x = outer2_p2.Y - c1.Y; float v2y = -(outer2_p2.X - c1.X); float v2_length = (float)Math.Sqrt(v2x * v2x + v2y * v2y); v2x *= radius1 / v2_length; v2y *= radius1 / v2_length; // Offset the tangent vector's points. outer2_p1 = new PointF(c1.X + v2x, c1.Y + v2y); outer2_p2 = new PointF( outer2_p2.X + v2x, outer2_p2.Y + v2y); } // If the circles intersect, then there are no inner tangents. float dx = c2.X - c1.X; float dy = c2.Y - c1.Y; double dist = Math.Sqrt(dx * dx + dy * dy); if (dist <= radius1 + radius2) return 2; // *************************** // * Find the inner tangents * // *************************** { float radius1a = radius1 + radius2; FindTangents(c1, radius1a, c2, out inner1_p2, out inner2_p2); // Get the vector perpendicular to the // first tangent with length radius2. float v1x = inner1_p2.Y - c2.Y; float v1y = -(inner1_p2.X - c2.X); float v1_length = (float)Math.Sqrt(v1x * v1x + v1y * v1y); v1x *= radius2 / v1_length; v1y *= radius2 / v1_length; // Offset the tangent vector's points. inner1_p1 = new PointF(c2.X + v1x, c2.Y + v1y); inner1_p2 = new PointF( inner1_p2.X + v1x, inner1_p2.Y + v1y); // Get the vector perpendicular to the // second tangent with length radius2. float v2x = -(inner2_p2.Y - c2.Y); float v2y = inner2_p2.X - c2.X; float v2_length = (float)Math.Sqrt(v2x * v2x + v2y * v2y); v2x *= radius2 / v2_length; v2y *= radius2 / v2_length; // Offset the tangent vector's points. inner2_p1 = new PointF(c2.X + v2x, c2.Y + v2y); inner2_p2 = new PointF( inner2_p2.X + v2x, inner2_p2.Y + v2y); } return 4; }

Note that this problem is closely related to the “Belt Problem” where the goal is to calculate the length of a belt needed to connect two pulleys directly (using the outer tangents) or crossed (using the inner tangents). Sometimes the direct (external tangent) version is called the “Pulley Problem.”

A couple of definitions:

- An inner tangent is one that intersects the segment joining the circles’ centers.
- An outer tangent is one that does not intersect the segment joining the circles’ centers.
- The point where the internal tangents intersect is called the
*internal homeothetic center*and it lies along the segment connecting the circles’ centers. - The point where the extensions of the external tangents intersect is called the
*external homeothetic center*and it lies along the segment connecting the circles’ centers. If the circles have the same radii, then the external tangents are parallel and the external homeothetic center is at infinity.