def bounding_sphere(points):
    """A fast, approximate method for finding the sphere containing a set of points.

    See https://www.researchgate.net/publication/242453691_An_Efficient_Bounding_Sphere

    This method is approximate. While the sphere is guaranteed to contain all the points
    it is a few percent larger than necessary on average.
    """
    # euclidean metric
    def dist(a, b):
        return ((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2 + (a[2] - b[2]) ** 2) ** 0.5

    def cent(a, b):
        return ((a[0] + b[0]) / 2, (a[1] + b[1]) / 2, (a[2] + b[2]) / 2)

    p0 = points[0]  # any arbitrary point in the point cloud works
    # choose point y furthest away from x
    p1 = max(points, key=lambda p: dist(p, p0))
    # choose point z furthest away from y
    p2 = max(points, key=lambda p: dist(p, p1))

    # initial bounding sphere
    center = cent(p1, p2)
    radius = dist(p1, p2) / 2

    # while there are points lying outside the bounding sphere, update the sphere by
    # growing it to fit
    for p in points:
        distance = dist(p, center)
        if distance > radius:
            delta = (distance - radius) / 2
            radius = (radius + distance) / 2

            cx, cy, cz = center
            x, y, z = p
            cx += (x - cx) / distance * delta
            cy += (y - cy) / distance * delta
            cz += (z - cz) / distance * delta

            center = (cx, cy, cz)

    return (center, radius)