Inner tangent between two circles formula

As a programmer I need to draw the inner tangents between two circles, but only the segments, not the whole line.

But the internet is surprisingly hostile to lazy programmers who don't know their math :). I know the center points of both circles (R1x, R1y, R2x, R2y) and their radius (r1, r2). What are the points for the tangent segments? (Ax, Ay, Bx, By and Cx, Cy, Dx, Dy).

Thanks!

EDIT: I am not really that lazy, I was on wikipedia (actually I did lot of googling first) but the formula is not there and I can not derive it myself :(

We can find both the inner and outer tangents between two circles with some simple mathematical observations.

Outer tangents

Let's look at the outer tangents first, because it's easier to intuit, after which the inner tangent image makes more sense:

Treating the bigger circle as C1 with radius $$r1$$, and the smaller circle C2 with radius $$r2$$, we can create a new circle C3 inside C1 with radius $$r3 = r1 - r2$$, and then construct the green triangle: we know two of its points, but we don't know its third point, and knowing that third point lets us calculate the two outer tangent points.

While we don't know the third point, we do know all the side lengths:

hypotenuse = dist(c1, c2)
short = r3


And because we're dealing with a right-angled triangle, we also know:

long = sqrt(hypotenuse*hypotenuse - short*short)


But we don't actually need to know how long this edge is, for the same reason: because we're dealing with a right-angled triangle, we can use trigonometry to find the angle we want using only the hypothenuse and short edge:

φ = acos(short/hypotenuse)


However, one thing that's easy to overlook is that angles in computer graphics are universally relative to the x-axis, whereas this angle is relative to the hypotenuse, so we'll need to add it to the angle from the x-axis to the hypotenuse:

φ = atan2(c2.y-c1.y, c2.x-c1.x) + acos(short/hypotenuse)


With that angle, we can now calculate our first circle's tangent point:

t1x = c1.x + c1.r * cos(φ)
t1y = c1.y + c1.r * sin(φ)


And our second circle's tangent point:

t2x = c2.x + c2.r * cos(φ)
t2y = c2.y + c2.r * sin(φ)


And we're done. To get the two tangent points on the other side, we simply pick "the other angle", being the angle from the x-axis to the hypotenuse, minus the angle from the hypotenuse to the short edge:

φ2 = atan2(c2.y-c1.y, c2.x-c1.x) - acos(short/hypotenuse)
s1x = c1.x + c1.r * cos(φ2)
s1y = c1.y + c1.r * sin(φ2)
s2x = c2.x + c2.r * cos(φ2)
s2y = c2.y + c2.r * sin(φ2)


And that's the outer tangents sorted.

(Also note, of course, that if you're using a vector based programming language, all of these things become "run the relevant function(s) on your vector inputs" instead of computing x and y coordinates independently)

Inner tangents

With an understanding of the outer tangents, the graphic for the inner tangent should at least make sense: we have the same "green triangle" that we need to find a third point for, which is one of the two tangent points, and getting the other will then require using the opposite angle, rather than the same angle.

First, rather than a third circle C3 inside C1 with radius $$r1 - r2$$, we want a circle C3 around C2 instead, with radius $$r1 + r2$$. This gives us the two edges we need to compute the triangle's angles:

hypotenuse = dist(c1,c2)
short = r1 + r2
φ = asin(short/hypotenuse)


Again though, we now have the angle between the hypotenuse and the long edge, when what we really want is "the angle from the x-axis to the line from our circle center to its tangent point" so: first off, that would be the angle in the red highlighted area, not the green highlighted area:

φ = asin(short/hypotenuse) - π/2


but then we also need to remember to start at the angle from the x-axis to the hypotenuse:

φ = atan2(c2.y-c1.y, c2.x-c1.x) + asin(short/hypotenuse) - π/2


And with that, the tangent point on C1 is calculated the same:

t1x = c1.x + c1.r * cos(φ)
t1y = c1.y + c1.r * sin(φ)


But the tangent on C2 requires the angle for the opposite direction, or, rotating it 180 degrees. For trig functions, that means just adding pi to the angle, so let's do that:

t2x = c2.x + c2.r * cos(φ + π)
t2y = c2.y + c2.r * sin(φ + π)


And to get the other two points, we flip the plus/minus signs in our angle formula:

φ2 = atan2(c2.y-c1.y, c2.x-c1.x) - asin(short/hypotenuse) + π/2
s1x = c1.x + c1.r * cos(φ2)
s1y = c1.y + c1.r * sin(φ2)
s2x = c2.x + c2.r * cos(φ2 + π)
s2y = c2.y + c2.r * sin(φ2 + π)


And we're done. Fairly straight forward, really easy to program.

• The angles for the outer tangents have a small mistake (φ = atan2(c2.y-c1.y, c2.x-c1.y <--- should be c2.x-c1.x) same for φ2 = atan2(c2.y-c1.y, c2.x-c1.y) - acos(short/hypotenuse), otherwise it helped me a lot thank you so much! Dec 18, 2021 at 1:01
• Nice explanation! Maybe worth to note: Even if not directly visible from the figures, the computation works also for r1 == r2 and r1 < r2, at least for the outer tangents Jan 19, 2022 at 20:45
• Note that $r1$ and $r2$ are just the labels for "the radius for the larger circle" and "the radius for the smaller circle" though, so by definition we'll never have $r1 < r2$. When $r1=r2$ we have a very different setup: we don't have a "triangle" to work with, the outer tangents simply run parallel to $H$, with the tangent points on the circles being the intersection of the line perpendicular to $H$ through each circle's center. (The inner tangent calculation is still the same though) Jan 20, 2022 at 0:41