private static Double2[] AdjustCircles(ref Double2 c1, ref double r1, Double2 n1, ref Double2 c2, ref double r2, Double2 n2) { Double2 pt1, pt2; // Negate if necessary, so we are working with positive values of the radius bool neg1 = r1 < 0, neg2 = r2 < 0; if (neg1) { r1 = -r1; n1 = -n1; } if (neg2) { r2 = -r2; n2 = -n2; } // There are two cases: if the circles are outside (their radius sum is less than their distance) // and if the circles are inside (their radius difference is less than their distance) var rs = r1 + r2; // The first case if (c1.DistanceSquaredTo(c2) > rs * rs) { // Compute the coefficients of the polynomials var p = n1.DistanceSquaredTo(n2); var q = 2 * (c1 - c2).Dot(n1 - n2); var a = c1.DistanceSquaredTo(c2); // There are two polyomials that, solved, give the necessary displacement for this adjustment // One of them is pλ² + qλ + a² - (r1-r2)² and the other is (p-4)λ² + (q - 4(r1+r2))λ + a - (r1+r2)² // Experimentally, though, only the latter one gives a "useful" value // We still have an edge case, though, as there might be no positive root to this (this happens if // the circles have to grow at opposite direction). On this case, return an empty array var roots = Equations.SolveQuadratic(p - 4, q - 4 * rs, a - rs * rs); if (!roots.Any(r => r >= 0)) { pt1 = pt2 = new Double2(double.NaN, double.NaN); } else { var l = roots.Where(r => r >= 0).Min(); // Correctly adjust the centers and radii c1 += n1 * l; c2 += n2 * l; r1 += l; r2 += l; // The single point as a double root var dir = (c2 - c1).Normalized; pt1 = c1 + dir * r1; pt2 = c2 - dir * r2; } } // The second case else { // Swap the circles if the first one is smaller bool swap = r1 < r2; if (swap) { Swap(ref c1, ref c2); Swap(ref r1, ref r2); Swap(ref n1, ref n2); } // Compute the coefficients of the polynomials var p = (n1 + n2).LengthSquared; var q = 2 * (c1 - c2).Dot(n1 + n2); var a = c1.DistanceSquaredTo(c2); // Again, here, there are two polynomials: pλ² - qλ + a² - (r1+r2)² and (p-4)λ² + (-q + 4(r1-r2))λ + a - (r1-r2)² // And again, experimentally only the second one will give the "correct" result var rd = r1 - r2; var roots = Equations.SolveQuadratic(p - 4, -q + 4 * rd, a - rd * rd); var l = roots.Where(r => r >= 0).Min(); // Correctly adjust the centers and radii c1 -= n1 * l; c2 += n2 * l; r1 -= l; r2 += l; // Pick the single point intersection var dir = (c2 - c1).Normalized; pt1 = c1 + dir * r1; pt2 = c2 + dir * r2; // Finally, swap them again if we had to swap earlier if (swap) { Swap(ref c1, ref c2); Swap(ref r1, ref r2); } } // Return back their signs if (neg1) { r1 = -r1; } if (neg2) { r2 = -r2; } if (double.IsNaN(pt1.X)) { return(new Double2[0]); } return(new[] { (pt1 + pt2) / 2, (pt1 + pt2) / 2 }); }