From: Ruby Quiz Date: 2004-10-08T22:00:30+09:00 Subject: [QUIZ] Geodesic Dome Faces (#3) 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 | } }