A curiosity journal of math, physics, programming, astronomy, and more.

Drawing an icosphere

In the previous post we drew a 20-sided icosahedron:

An icosahedron. Drag to rotate.

We'll use this as our starting point for making an icosphere. First, we divide one of the triangular faces into four triangles:

An icosahedron with one face subdivided into four triangles.

Here's the code to do it:

(defn average [& xs]
  (/ (reduce + xs) (count xs)))
(defn subdivide-face [[a b c]]
  (let [ab (map average a b)
        ac (map average a c)
        bc (map average b c)]
    [[a ab ac]
     [b bc ab]
     [c ac bc]
     [ab bc ac]]))

Using mesh from the previous post, we can subdivide all the faces:

(mapcat subdivide-face mesh)
An icosahedron with all faces subdivided into four triangles.

This isn't any closer to a sphere than the original icosahedron. While we now have 80 triangles, we still only have 20 flat faces. To more closely approximate a sphere, we'll slide each of the new points out to the surface of the bounding sphere.

(defn extend-point [point]
  (let [length (Math/sqrt (transduce (map #(* % %)) + point))]
    (map #(/ % length) point)))

This function considers each point to be a vector from the center of the icosahedron and scales that vector to length 1, which puts it on the boundary of the unit sphere.

We'll use a transducer to subdivide the mesh:

(def subdivide
  (comp
    (mapcat subdivide-face)
    (map (partial map extend-point))))
(sequence subdivide mesh)
Moving all vertices to the surface of the bounding sphere begins to approximate a sphere.

A couple more levels of subdivision:

(sequence (comp subdivide subdivide) mesh)
Two more subdivisions and pushing of vertices yields a more sphere-like shape.
(sequence (comp subdivide subdivide subdivide) mesh)
With three levels of subdivision, we have a good approximation of a sphere.

We now have 1,280 faces and a decent approximation of a sphere.

Icospheres produce an even distribution of points around the sphere, as opposed to UV spheres, which, like the intersections of lines of longitude and latitude, cluster points more densely around the poles.