This is an R Markdown Notebook to explore the construction of polyhedra using the construction code from (https://github.com/operdeck/polyhedra).

A small list of basic polyhedra is constructed from pre-defined sets of coordinates and topology. More complex polyhedra can be built using transformations that turn them into their dual, truncatebing, truncating, stellation and more. In addition there is a discovery mode where the vertices of one polyhedron are used to discover others by trying to fit different faces onto the vertices.

The Platonic solids

A Platonic solid is a convex polyhedron whose faces and vertices are all of the same type. There are five such solids.

In this project, three of the Platonic solids are sort-of pre-defined. They are constructed from a set of vertex coordinates (given), a polygon and vertex description and an example edge size.

For example, below we construct an octahedron by passing in the 8 vertex coordinates, the size of the faces (3) ,the number of faces that each vertex has (4) and the edge size (size from vertex 1 to vertex 3). The buildRegularPoly function will then fit a number of faces (not specified up front) that fit this specification and use up all points.

source("polyhedra.R")
source("draw.R")
source("discover.R")
source("layout.R")

octahedron <- buildRegularPoly(coords = rbind(expand.grid(x = c(-1,1), y = 0, z = 0), 
                                                expand.grid(x = 0, y = c(-1,1), z = 0), 
                                                expand.grid(x = 0, y = 0, z = c(-1,1))),
                               polygonsize = 3,
                               vertexsize = 4,
                               exampleEdge = c(1,3),
                               name = "Octahedron")
drawInit(T)
drawSinglePoly(octahedron, debug = T)
rglwidget(elementId = "octahedron-debug")

The tetrahedron and icosahedron are defined in a similar way in the project. The other two Platonic solids are derived by applying a dual transformation. Together that gets us the 5 Platonic colids:

cube <- dual(octahedron, name = "Cube")
dodecahedron <- dual(icosahedron, name = "Dodecahedron")

Platonics <- list(tetrahedron, octahedron, cube, icosahedron, dodecahedron)
Platonic Solids

Platonic Solids

The Kepler-Poinsot polyhedra

The 4 other regular polyhedra can be derived from the Platonic solids by fitting other faces through the vertex coordinates. The great stellated dodecahedron is defined as the dual of the great icosahedron but could have been defined in the same manner as the other three.

greatDodecahedron <- buildRegularPoly(coords = icosahedron$coords, 
                                      polygonsize = 5, vertexsize = 5, exampleEdge = c(1,6),
                                      name = "Great Dodecahedron")
smallStellatedDodecahedron <- buildRegularPoly(icosahedron$coords,
                                               polygonsize = 5,
                                               vertexsize = 5,
                                               exampleEdge = c(1,7),
                                               name = "Small Stellated Dodecahedron")
greatIcosahedron <- buildRegularPoly(icosahedron$coords,
                                     polygonsize = 3,
                                     vertexsize = 5,
                                     exampleEdge = c(2, 6),
                                     name = "Great Icosahedron")
greatStellatedDodecahedron <- dual(greatIcosahedron, name = "Great Stellated Dodecahedron", 
                                   scaling = "vertex")

KeplerPoinsots <- list(greatDodecahedron, smallStellatedDodecahedron, 
                       greatIcosahedron, greatStellatedDodecahedron)
Regulars <- c(Platonics, KeplerPoinsots)
Kepler-Poinsot Solids

Kepler-Poinsot Solids

Note the descriptions that are displayed with the polyhedra: while the name can (optionally) be set by the user, the description in parentheses is generated from the topology. For example {3, 5/2} refers to the great icosahedron, which has 3-sided faces and a vertex figure of 5 going round in 2 cycles.

Transformations

Dual transformation

Some of the regular polyhedra were created using the dual transform. This turns faces into vertices and vertices into faces. The duals of the regular polyhedra are also regular polyhedra.

Combining the duals with the originals is sometimes interesting, although in one case the dual completely occludes the original.

# Since the combinations of regular solids with their duals are symmetrical, we
# only apply it to half of them
combis <- lapply(Regulars[seq(length(Regulars))%%2==1], function(p) { return(compose(p, dual(p))) })
Combination of regular polyhedra with their duals

Combination of regular polyhedra with their duals

Archimedean transformations

Quasi Regular Archimedean solids

The first of the transformations to turn regular solids into Archimedean solids turns each edge into a new vertex. Old faces basically become rotated as their new points are the mids of their old edges. Every vertex of the old solid becomes a new face of its own.

The transform is symmetric, so quasi(cube) = quasi(octahedron).

# Here as well, since applying to regular solids only need to do half of them
quasiarchimedeans <- lapply(Regulars[seq(length(Regulars))%%2==1], quasi)
Quasi Archimedean solids

Quasi Archimedean solids

Truncate transformation

Every vertex becomes a face like in the quasi transformation, but part of the original edges are kept, so in effect the original faces are doubled in number of sides.

NB Truncate transformation doesnt seem too work well for the star polyhedra. NB FIXED? Also, some work to do to make the Truncate transform more generally applicable e.g. simply truncate(quasi(cube))

truncatearchimedeans <- lapply(Platonics, truncate)
Truncated regular solids

Truncated regular solids

Truncation can be applied on the star solids although the result is not always esthetically pleasing. It also results in overlapping faces so drawing only the two that don’t have that problem.

truncatedstars <- lapply(KeplerPoinsots[c(1,3)], truncate)
# the other 2 don't work / even cause an error
Truncated Kepler Poinsots

Truncated Kepler Poinsots

Rhombic transformation

A more complex transformation that basically lifts edges to become new, square, faces. Existing faces remain but are lifted too. Vertices are turned into new faces to fill the gaps between the new squares and the existing faces.

The transformation is symmetric also.

rhombicregulars <- lapply(c(Platonics[seq(length(Platonics))%%2==1], 
                            list(greatDodecahedron, greatIcosahedron)), rhombic)
# NB rhombic(smallStellatedDodecahedron) fails currently
Truncated regular solids

Truncated regular solids

Irregular results

Applying the transformations repeatedly on on non-regular solids to start with sometimes results in nice looking solids but often with irregular faces, and sometimes even non-flat faces.

irregulars <- list( truncate(truncate(truncate(dodecahedron))),
                    quasi(quasi(truncate(octahedron))),
                    compose(rhombic(dodecahedron), quasi(dodecahedron)),
                    quasi(truncate(greatIcosahedron)),
                    truncate(quasi(dodecahedron)) )
Some irregular solids

Some irregular solids

2D Layouts

The 3D-solids can also be rendered onto 2D layouts suitable for printing and modeling in paper. Currently only simple convex solids are supported but plans include to extend to arbirary complex ones.

The 2D layout is rendered as a ggplot object which can be exported as SVG then opened in a browser or other viewer and printed in high res. Perhaps even direct PDF output is possible depending on the installation of R.

They layout algorithm tries to build a maximally compact layout but search can be very time consuming, so by default the # of iterations is capped.

layout2d <- get2DLayout(dodecahedron)

ggsave(file=file.path("layouts",paste0("layout ", dodecahedron$name, ".svg")), 
       plot=layout2d, width=10, height=10)
layout2d

Various stellations

5 Tetrahedra and derived

Compound of 5 tetrahedra. The dual of this turns the other way around.

compound5tetrahedra <- buildRegularPoly(dodecahedron$coords,
                                        polygonsize = 3,
                                        vertexsize = 3,
                                        exampleEdge = c(3, 8),
                                        name = "5 Tetrahedra")
5 Tetrahedra with dual

5 Tetrahedra with dual

The “quasi” transformation of this turns it into the compound of 5 octahedra.

compound5octahedra <- quasi(compound5tetrahedra, name = "5 Octahedra")
compound5truncatedTetrahedra <- truncate(compound5tetrahedra)
5 Octahedra

5 Octahedra

Combining it with its dual creates 10 tetrahedra.

NB currently issues with rendering, probably because there are overlapping faces basically creating a sort of {6/2} face out of two {3} that is not drawn properly.

compound10tetrahedra <- compose(compound5tetrahedra, dual(compound5tetrahedra), 
                               name = "10 Tetrahedra")
10 Tetrahedra

10 Tetrahedra

5 Cubes and derived

The compound of 5 cubes shares the vertices of the dodecahedron. The dual of this one is the compound of 5 tetrahedra (not suprisingly) while the “quasi” transform turns it into 5 of one of the simpler Archimedean solids {3,4,3,4}.

NB that last one again suffers from rendering issues.

compound5Cubes <- buildRegularPoly(dodecahedron$coords,
                                    polygonsize = 4,
                                    vertexsize = 6,
                                    exampleEdge = c(1, 8),
                                   name = "5 Cubes")
moreDodecahedronStellations <- list(compound5Cubes, 
                                    dual(compound5Cubes), 
                                    quasi(compound5Cubes))
5 Cubes and variations

5 Cubes and variations

Variation on Quasi Dodecahedron

Variation on Quasi Dodecahedron

Variation on Quasi Dodecahedron

Discovery mode

In discovery mode it tries to fit (semi)regular polyhedra through a given set of coordinates. All other parameters (face and vertex dimension, edge length) are “discovered” by doing a grid search.

For the cube, nothing new emerges but it automatically finds the composite of two tetrahedra fitting the same coordinates as the cube.

cube_discoveries <- discover(cube, progress = F)
cube_discoveries$specs
Discoveries based on cube

Discoveries based on cube

For the tetrahedron and octahedron nothing new emerges either but from the next two a more interesting family of polyhedra arises although unfortunately no new polyhedra relative to the ones shown before.

dodecahedron_discoveries <- discover(dodecahedron, progress = F)
dodecahedron_discoveries$specs
Discoveries based on dodecahedron

Discoveries based on dodecahedron

icosahedron_discoveries <- discover(icosahedron, progress = F)
icosahedron_discoveries$specs
Discoveries based on icosahedron

Discoveries based on icosahedron

Next steps

Wolfram has a fairly complete set of operations, see https://reference.wolfram.com/language/PolyhedronOperations/tutorial/PolyhedronOperations.html.

Examples of missing polyhedra