    :c 0.41241})
 
 
-; chord-factor n = 2*sin(theta/2)
-; theta = central angle
-; length of chord = r*n
-
-; 0.3486 = 1*2*sin(t/2)
-; 0.3486/2 = sin(t/2)
-; arcsin(0.3486/2) = t/2
-; 2*arcsin(ratio/2)
+(defn- to-unit-radius
+  "Projects a point to the same vector on the surface of the unit sphere."
+  [p]
+  (let [m (apply mag p)]
+    (vec (map #(/ % m) p))))
 
 
+; TODO: find a way to generate this mathematically
 (def icosahedron
-  "An icosahedron with unit radius."
+  "The set of faces making up an icosahedron with unit radius. Each face is a
+  set of three coordinate vectors."
   (let [phi (/ (+ 1 (Math/sqrt 5.0)) 2)
         -phi (- phi)
         points
-        {:A [ 0.0  1.0  phi] :B [ 0.0 -1.0  phi]
-         :C [ 0.0 -1.0 -phi] :D [ 0.0  1.0 -phi]
-         :E [ phi  0.0  1.0] :F [-phi  0.0  1.0]
-         :G [-phi  0.0 -1.0] :H [ phi  0.0 -1.0]
-         :I [ 1.0  phi  0.0] :J [-1.0  phi  0.0]
-         :K [-1.0 -phi  0.0] :L [ 1.0 -phi  0.0]}
+        {:A [ 0.0  1.0  phi]
+         :B [ 0.0 -1.0  phi]
+         :C [ 0.0 -1.0 -phi]
+         :D [ 0.0  1.0 -phi]
+         :E [ phi  0.0  1.0]
+         :F [-phi  0.0  1.0]
+         :G [-phi  0.0 -1.0]
+         :H [ phi  0.0 -1.0]
+         :I [ 1.0  phi  0.0]
+         :J [-1.0  phi  0.0]
+         :K [-1.0 -phi  0.0]
+         :L [ 1.0 -phi  0.0]}
         faces
         [[:A :I :J] [:A :J :F] [:A :F :B] [:A :B :E] [:A :E :I]
          [:B :F :K] [:B :K :L] [:B :L :E] [:C :D :H] [:C :H :L]
          [:C :L :K] [:C :K :G] [:C :G :D] [:D :G :J] [:D :J :I]
          [:D :I :H] [:E :L :H] [:E :H :I] [:F :J :G] [:F :G :K]]]
-    (set (map (comp set (partial map points)) faces))))
+    (set (map (comp set (partial map (comp to-unit-radius points))) faces))))
+
+
+(defn- midpoint
+  "Returns a new point that is a fraction of the distance towards point b
+  from point a."
+  [p a b]
+  (->>
+    (map - b a)
+    (map (partial * p))
+    (map + a)
+    to-unit-radius))
+
+
+(defn split-face
+  "Splits the edges of a triangular face into n smaller segments, then pushes
+  all the new points out to the surface of a unit sphere. Returns a set of new
+  faces."
+  [face n]
+  (if (<= n 1)
+    #{face}
+    (let [[a b c] (seq face)]
+      (cond
+        (= 0 (mod n 2))
+        ;       a
+        ;      / \
+        ;     f---d
+        ;    / \ / \
+        ;   c---e---b
+        (let [d (midpoint 1/2 a b)
+              e (midpoint 1/2 b c)
+              f (midpoint 1/2 c a)]
+          (->>
+            [         #{a d f}
+             #{f e c} #{f d e} #{d b e}]
+            (mapcat #(split-face % (/ n 2)))
+            set))
+
+        (= 0 (mod n 3))
+        ;       a
+        ;      / \
+        ;     i---d
+        ;    / \ / \
+        ;   h---j---e
+        ;  / \ / \ / \
+        ; c---g---f---b
+        (let [d (midpoint 1/3 a b)
+              e (midpoint 2/3 a b)
+              f (midpoint 1/3 b c)
+              g (midpoint 2/3 b c)
+              h (midpoint 1/3 c a)
+              i (midpoint 2/3 c a)
+              j (midpoint 1/2 h e)]
+          (->>
+            [                  #{a d i}
+                      #{i j h} #{i d j} #{d e j}
+             #{h g c} #{h j g} #{j f g} #{j e f} #{e f b}]
+            (mapcat #(split-face % (/ n 3)))
+            set))
+
+        :else
+        (throw (IllegalArgumentException.
+                 (str n " is not divisible by any supported prime")))))))
+
+
+(defn split-faces
+  [shape n]
+  (set (mapcat #(split-face % n) shape)))
+
+
+(defn- face->lines
+  "Converts a face (set of three points) into a sequence of edge lines."
+  [face]
+  (as-> face points
+    (vec points)
+    (conj points (first points))
+    (partition 2 points)))
+
 
 
 ;;;;; SKETCH CODE ;;;;;

(defn draw []
  (background 255)
  (translate (/ (width) 2) (/ (height) 2) 0)
  (rotate-y (* (frame-count) 0.03))
  (rotate-x (* (frame-count) 0.04))
  (doseq [face icosahedron]
    (-> face
        (as-> points
          (map #(vec (map (partial * 50) %)) points)   ; scale the points
          (vec points)
          (conj points (first points)))                ; repeat the last point
        line-join-points
        (as-> lines
          (map (partial apply line) lines))
        dorun))
  #_
  (let [line-args (for [t (range 0 180)]
                    (let [s (* t 18)
                          radian-s (radians s)
                          radian-t (radians t)
                          x (* radius (cos radian-s) (sin radian-t))
                          y (* radius (sin radian-s) (sin radian-t))
                          z (* radius (cos radian-t))]
                      [x y z]))]
    (dorun
     (map #(apply line %) (line-join-points line-args)))))


(defsketch geodesic-dome

(ns org.playasophy.wonderdome.geodesic
  (:require
    [quil.core :refer :all]
    [quil.helpers.drawing :refer [line-join-points]]))


(def strut-counts-3V
