The three rules of Ruby Quiz:

1.  Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2.  Support Ruby Quiz by submitting ideas as often as you can:

http://www.grayproductions.net/ruby_quiz/

3.  Enjoy!

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

by Gavin Kistner

SUMMARY

Given the faces for a tetrahedron, octahedron, or isocahedron, create a geodesic
dome of arbitrary frequency.

The (equilateral triangle) faces of each primitive are given as triplets of
vertex points. Each vertex is itself a triplet of cartesian 3-space coordinates,
all of unit-distance from 0,0,0. (See the supplied points at the end for an
example.) The resulting geodesic should be an array of triangular faces; again
each face is a triplet of points, and each point is unit-distance from 0,0,0.

DETAILS

A 'simple' solution (using recursion) exists to subdivide each primary face into
4^n sub-faces. Instead, the following (more flexible) algorithm should be used,
which allows for n^2 sub-faces:

[See http://phrogz.net/CSS/Geodesics/index.html for a visual example of the
following algorithm.]

Step 1) Start with the three points defining a primary face.

Step 2) Divide each side of the face into equal length pieces; the number of
pieces is specified by the 'frequency'. (A frequency of 0 subdivides the face
not at all, a frequency of 1 divides each side into two equal pieces, a
frequency of 2 into three equal pieces, and so on.)

Step 3) Connect each division point along two sides with a line that is parallel
to the third side.

Step 4) Repeat with lines parallel to all three sides.

Step 5) New points are defined wherever the lines intersect.

The combination of the initial face points, the edge points, and the
intersection of the connecting lines provide the points for the faces of the
geodesic. (As diagrammed in http://phrogz.net/CSS/Geodesics/index.html#step5,
the 16 faces created by subdividing the primary face with frequency 3 can be
described as Aqm, qfm, qrf, rgf, rsg, szg, sBz, mfn, fhn, fgh, gyh, gzy, nho,
hxo, hyx, oxC. )

All points should be 'normalized', so that they are unit-distance from the
origin.

For extra points, ensure that the points for each face are always specified in
the same direction, clockwise or counter-clockwise when looking from the origin.
(The above list of faces are all specified in a clockwise direction.)

STARTER DATA

The points for the three primitives follow. (Solving for any one of them solves
for all of them.)

	SQRT2 = Math.sqrt(2)
	SQRT3 = Math.sqrt(3)
	TETRA_Q = SQRT2 / 3
	TETRA_R = 1.0 / 3
	TETRA_S = SQRT2 / SQRT3
	TETRA_T = 2 * SQRT2 / 3
	GOLDEN_MEAN = (Math.sqrt(5)+1)/2
	
	PRIMITIVES = {
		:tetrahedron => {
			:points => {
				'a' => Vector[ -TETRA_S, -TETRA_Q, -TETRA_R ],
				'b' => Vector[  TETRA_S, -TETRA_Q, -TETRA_R ],
				'c' => Vector[        0,  TETRA_T, -TETRA_R ],
				'd' => Vector[        0,        0,        1 ]
			},
			:faces => %w| acb abd adc dbc |
		},
		:octahedron => {
			:points => {
				'a' => Vector[  0,  0,  1 ],
				'b' => Vector[  1,  0,  0 ],
				'c' => Vector[  0, -1,  0 ],
				'd' => Vector[ -1,  0,  0 ],
				'e' => Vector[  0,  1,  0 ],
				'f' => Vector[  0,  0, -1 ]
			},
			:faces => %w| cba dca eda bea
						  def ebf bcf cdf |
		},
		:icosahedron => {
			:points => {
				'a' => Vector[  1,  GOLDEN_MEAN, 0 ],
				'b' => Vector[  1, -GOLDEN_MEAN, 0 ],
				'c' => Vector[ -1, -GOLDEN_MEAN, 0 ],
				'd' => Vector[ -1,  GOLDEN_MEAN, 0 ],
				'e' => Vector[  GOLDEN_MEAN, 0,  1 ],
				'f' => Vector[ -GOLDEN_MEAN, 0,  1 ],
				'g' => Vector[ -GOLDEN_MEAN, 0, -1 ],
				'h' => Vector[  GOLDEN_MEAN, 0, -1 ],
				'i' => Vector[ 0,  1,  GOLDEN_MEAN ],
				'j' => Vector[ 0,  1, -GOLDEN_MEAN ],
				'k' => Vector[ 0, -1, -GOLDEN_MEAN ],
				'l' => Vector[ 0, -1,  GOLDEN_MEAN ]
			},
			:faces => %w| iea iad idf ifl ile
						  eha ajd dgf fcl lbe
						  ebh ahj djg fgc lcb
						  khb kjh kgj kcg kbc |
		}
	}