Computing and inspheres and circumspheres#

Under different conditions, various types of spheres containing or contained within a shape can be useful. For example, for spheres contained in a shape we may be interested in the largest sphere contained by a shape, or the largest concentric sphere contained within the shape. For a polyhedron, we may instead want to find the sphere that touches all the faces, if it exists.

[1]:
import fresnel
import numpy as np
from matplotlib import pyplot as plt

import coxeter
[2]:
def plot_polyhedron_with_sphere(shape, insphere=True):
    """Image a polyhedron along with a sphere contained within it."""
    device = fresnel.Device()
    scene = fresnel.Scene(device)

    transparent_material = fresnel.material.Material(
        color=fresnel.color.linear([1, 1, 1]),
        spec_trans=0.95,
        roughness=0.2,
        primitive_color_mix=0.0,
    )
    colored_material = fresnel.material.Material(
        color=fresnel.color.linear([0.9, 0.714, 0.169]),
        roughness=0.8,
    )

    # First make the shape and set up its properties.
    primitive = fresnel.geometry.ConvexPolyhedron(
        scene,
        fresnel.util.convex_polyhedron_from_vertices(shape.vertices),
        N=1,
        outline_width=0.01,
        material=transparent_material if insphere else colored_material,
    )
    primitive.color_by_face = 0.0

    # Now draw the insphere within the shape.
    sphere = fresnel.geometry.Sphere(
        scene,
        N=1,
        material=colored_material if insphere else transparent_material,
    )

    # Make the sphere a little bit smaller than it really is,
    # otherwise you get artifacts near the intersection of the
    # polyhedron and the insphere.
    sphere.radius[:] = [
        shape.insphere.radius * 0.99 if insphere else shape.circumsphere.radius * 1.01
    ]

    scene.camera = fresnel.camera.Orthographic.fit(scene, view="front")
    tracer = fresnel.tracer.Path(device=device, w=300, h=300)
    return tracer.sample(scene, samples=24, light_samples=40)

The Platonic solids are a canonical set of shapes we can use for our analysis. Conveniently, they can easily be generated using coxeter. A good example is the dodecahedron.

[3]:
dodecahedron = coxeter.families.PlatonicFamily.get_shape("Dodecahedron")

We can query different types of spheres from this shape now:

[4]:
# The sphere tangent to all the faces of the polyhedron.
print(dodecahedron.insphere)

# The largest concentric sphere contained in the shape.
print(dodecahedron.maximal_centered_bounded_sphere)
coxeter.shapes.Sphere(radius=0.5648000780281438, center=[-5.551115123125784e-17, -2.220446049250313e-16, -3.23771046624367e-16])
coxeter.shapes.Sphere(radius=0.564800078028144, center=[-1.7347234759768062e-17, -1.1564823173178707e-17, 1.619075244245019e-17])

Let’s visualize what these shapes look like:

[5]:
plot_polyhedron_with_sphere(dodecahedron)
[5]:
../_images/examples_Spheres_8_0.png

If we instead want to look at spheres containing a shape, we can get those as well.

[6]:
# The sphere tangent to all the faces of the polyhedron.
print(dodecahedron.circumsphere)

# The largest concentric sphere contained in the shape.
print(dodecahedron.minimal_centered_bounding_sphere)
coxeter.shapes.Sphere(radius=0.7107492598629351, center=[0.0, -2.7755575615628914e-17, -1.1102230246251565e-16])
coxeter.shapes.Sphere(radius=0.7107492598629351, center=[-1.7347234759768062e-17, -1.1564823173178707e-17, 1.619075244245019e-17])
[7]:
plot_polyhedron_with_sphere(dodecahedron, False)
[7]:
../_images/examples_Spheres_11_0.png