
Task

Implement a solution to the Problem of Apollonius   (description on Wikipedia)   which is the problem of finding the circle that is tangent to three specified circles   (colored black in the diagram below to the right).

There is an   algebraic solution   which is pretty straightforward.



The solutions to the example in the code are shown in the diagram   (below and to the right).

The red circle is "internally tangent" to all three black circles,   and the green circle is "externally tangent" to all three black circles.




type Circle(Array center, Float radius) with Lookup
func Circle.ToString() =>
    "Circle[x=\(this.center[0]),y=\(this.center[1]),r=\(this.radius)]"
 
func solveApollonius(Circle c1, Circle c2, Circle c3, Float s1, Float s2, Float s3) {
    let x1 = c1.center[0]
    let y1 = c1.center[1]
    let r1 = c1.radius
    let x2 = c2.center[0]
    let y2 = c2.center[1]
    let r2 = c2.radius
    let x3 = c3.center[0]
    let y3 = c3.center[1]
    let r3 = c3.radius
 
    let v11 = 2.0 * x2 - 2.0 * x1
    let v12 = 2.0 * y2 - 2.0 *y1
    let v13 = x1 * x1 - x2 * x2 + y1 * y1 - y2 * y2 - r1 * r1 + r2 * r2
    let v14 = 2.0 * s2 * r2 - 2.0 * s1 * r1
 
    let v21 = 2.0 * x3 - 2.0 * x2
    let v22 = 2.0 * y3 - 2.0 * y2
    let v23 = x2 * x2 - x3 * x3 + y2 * y2 - y3 * y3 - r2 * r2 + r3 * r3
    let v24 = 2.0 * s3 * r3 - 2 * s2 * r2
 
    let w12 = v12 / v11
    let w13 = v13 / v11
    let w14 = v14 / v11
 
    let w22 = v22 / v21-w12
    let w23 = v23 / v21-w13
    let w24 = v24 / v21-w14
 
    let p = -w23 / w22
    let q = w24 / w22
    let m = -w12 * p - w13
    let n = w14 - w12 * q
 
    let a = n * n + q * q - 1.0
    let b = 2.0 * m * n - 2.0 * n * x1 + 2 * p * q - 2.0 * q * y1 + 2.0 * s1 * r1
    let c = x1 * x1 + m * m - 2.0 * m * x1 + p * p + y1 * y1 - 2.0 * p * y1 - r1 * r1
 
    let d = b * b - 4.0 * a * c
    let rs = (-b - sqrt(d)) / (2.0 * a)
    let xs = m + n * rs
    let ys = p + q * rs
 
    Circle(center: [xs,ys], radius: rs)
}
 
let c1 = Circle(center: [0.0, 0.0], radius: 1.0)
let c2 = Circle(center: [4.0, 0.0], radius: 1.0)
let c3 = Circle(center: [2.0, 4.0], radius: 2.0)
 
print(solveApollonius(c1, c2, c3, 1.0, 1.0, 1.0))
print(solveApollonius(c1, c2, c3, -1.0, -1.0, -1.0))