raw computer graphics

How can you find the intersection points of two circles, given its center points and their radii? More formally: Given two circles with their center points \(\mathbf{A}\) and \(\mathbf{B}\) and their radii \(r_A\) and \(r_B\), we want to find the points \(\mathbf{P}_1\) and \(\mathbf{P}_2\) which represent the intersection points of both circles. It is evident that there can exist one, two, an infinite number, or no intersection at all between two circles. No intersection occurs notably when one circle is fully contained within another, or when their respective areas do not overlap. One approach to solve the intersection check involves representing the circles by their mathematical circle formulas, subtract them from eachother, and subsequently determining the corresponding x and y values. While conceptually straightforward, this method requires a substantial number of computations, particularly when aiming for comprehensive parameterizability. Here is a different way:

Case 1

The first case is the trivial case, when two identical circles have \(\mathbf{A}=\mathbf{B}\) and \(r_A=r_B\). Mathematically seen, there are infinity many intersection points. In practice you have to decide on how you work with this case.

Case 2

In the second case we focus on circles which don't overlap at all. Detecting the collission of two circles is quite easy, given the center points \(\mathbf{A}\) and \(\mathbf{B}\) and their radii \(r_A\) and \(r_B\), as the sum of them must be greater than the distance between their center points to overlap:

We define the vector between the points \(\mathbf{A}\) and \(\mathbf{B}\) to be \(\mathbf{w} = \mathbf{B} - \mathbf{A}\) and calculate the distance using the norm of the vector:

\[d = |\mathbf{w}| = \sqrt{(B_x-A_x)^2 + (B_y-A_y)^2}\]

Using the distance, an intersection or collision between two circles occurs if and only if \(d \leq r_A+r_B\) in all other cases \(\mathbf{P}_1\) and \(\mathbf{P}_2\) are undefined.

Case 3

The third case concerns the intersection of one or two points. We can ignore the case of meeting in one point, as it is a special case when \(\mathbf{P}_1=\mathbf{P}_2\).

Upon examining the plot, one can discern a rectangle that is spanned by vectors \(\mathbf{a}\) and \(\mathbf{b}\), and is bisected by the radius \(r_A\). Symmetrically, we can do the same for the second circle and express both as:

\[|\mathbf{a}|^2+|\mathbf{b}|^2=r_A^2\]

\[(|\mathbf{w}|-|\mathbf{a}|)^2+|\mathbf{b}|^2=r_B^2\]

Re-arranging both equations for \(|\mathbf{b}|^2\) and setting them equal yields

\[(|\mathbf{w}|-|\mathbf{a}|)^2 - r_B^2 = r_A^2 - |\mathbf{a}|^2\]

Now solving this for \(|\mathbf{a}|\) yields:

\[|\mathbf{a}|=\frac{r_A^2-r_B^2+|\mathbf{w}|^2}{2|\mathbf{w}|}\]

Using the first Pythagorean equation, we can solve for \(|\mathbf{b}|\) like so:

\[|\mathbf{b}|=\pm\sqrt{r_A^2-|\mathbf{a}|^2}\]

In order to transform the values back to actual points, we calculate the vectors \(\mathbf{a}\) and \(\mathbf{b}\), shown in the plot above, by scaling the unit vector \(\hat{\mathbf{w}}\) with their proper sizes. Vector \(\mathbf{b}\) has to be rotated by 90° of course, where we use the perp operator

\[\mathbf{a} = |\mathbf{a}|\hat{\mathbf{w}}\]

\[\mathbf{b} = |\mathbf{b}|\hat{\mathbf{w}}^\perp\]

The intersection points can then be determined by just adding the vectors onto point \(\mathbf{A}\):

\[\mathbf{P}_{1,2}=\mathbf{A}+\mathbf{a}\pm \mathbf{b}\]

Case 4

If one circle is inside the other, there is also no intersection. The easiest way to determine this case is checking if \(r_A < |\mathbf{a}|\) or alternatively \(d < |r_B - r_A|\). When combined with Case 2, the check for invalid cases is   \(d > r_A + r_B \lor d < |r_A - r_B| \).

w = {
    x: B.x - A.x,
    y: B.y - A.y
}
    
d = hypot(w.x, w.y)

if (d <= A.r + B.r && abs(B.r - A.r) <= d) {

    w.x/= d;
    w.y/= d;

    a = (A.r * A.r - B.r * B.r + d * d) / (2 * d);
    b = Math.sqrt(A.r * A.r - a * a);

    P1 = {
        x: A.x + a * w.x - b * w.y,
        y: A.y + a * w.y + b * w.x
    }

    P2 = {
        x: A.x + a * w.x + b * w.y,
        y: A.y + a * w.y - b * w.x
    }

} else {
    // No Intersection, far outside or one circle within the other
    P1 = P2 = null
}