[QUIZ] Geodesic Dome Faces (#3)

R

Ruby Quiz

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 |
},
:eek:ctahedron => {
: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 |
}
}
 
J

Jamis Buck

Sorry if I'm just dense, but...

What's the deliverable for this quiz? I *think* I understand the
problem, but are we supposed to emit the points of the dome to a file?
Are we supposed to do an OpenGL interface that draws the dome? Are we
supposed to plug our script into an industrial robot and have it start
cranking out full-size geodesic domes for use in construction projects?

Just curious what was expected. :)

- Jamis

Ruby said:
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 |
},
:eek:ctahedron => {
: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 |
}
}

.
 
G

Gavin Kistner

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

Also, although it will give you no additional help on the programming
side of things, the algorithm is also described in this paper on
Geodesic Math:
http://www.salsburg.com/geod/geodesicmath.pdf

Specifically, the method being employed by this quiz is the "Class I,
Method 1 or 'alternate'" method, described starting on page 9 and
illustrated on page 10.

(Just in case my description confuses you, and you find something in
this paper more clarifying.)
 
F

Fredrik Jagenheim

Just curious what was expected. :)

Yes, you're not the only one confused. It would be great if there was
a solution given that one could use to compare the output from,
preferably from a simple case as 'given these coordinates, you should
get these coordinates.'

This have the added benefits of knowing what the expected output would be. :)

Otherwise, I thought it was a great quiz. Mostly because it was in a
problem domain I'm not customed to. So I had to think harder about it.
:)

Actually, the three Quizes that has been so far have been great,
though my solutions haven't added anything new to the solutions
already posted, so I haven't bothered to post them.

//F
 
G

Gavin Kistner

Yes, you're not the only one confused. It would be great if there was
a solution given that one could use to compare the output from,
preferably from a simple case as 'given these coordinates, you should
get these coordinates.'

I can give you that (below, with rounded values to preserve line
wrapping) but the problem is that the order of faces, and points within
those faces, can be specified in any order and still achieve the same
end result.

Still, when it comes time to actually verifying any solutions, some
sort of structured format would be nice, so that I can read them in,
plot them, and see if it looks right. :)

Sample output for a tetrahedron of frequency 0:
[ [ -0.816, -0.471, -0.333 ], [ 0.000, 0.943, -0.333 ], [ 0.816,
-0.471, -0.333 ] ]
[ [ -0.816, -0.471, -0.333 ], [ 0.816, -0.471, -0.333 ], [ 0.000,
0.000, 1.000 ] ]
[ [ -0.816, -0.471, -0.333 ], [ 0.000, 0.000, 1.000 ], [ 0.000,
0.943, -0.333 ] ]
[ [ 0.000, 0.000, 1.000 ], [ 0.816, -0.471, -0.333 ], [ 0.000,
0.943, -0.333 ] ]

Sample output for an octahedron of frequency 1:
[ [ 0.000, -0.707, 0.707 ], [ 0.707, 0.000, 0.707 ], [ 0.000,
0.000, 1.000 ] ]
[ [ 0.000, -0.707, 0.707 ], [ 0.000, -1.000, 0.000 ], [ 0.707,
-0.707, 0.000 ] ]
[ [ 0.707, 0.000, 0.707 ], [ 0.000, -0.707, 0.707 ], [ 0.707,
-0.707, 0.000 ] ]
[ [ 1.000, 0.000, 0.000 ], [ 0.707, 0.000, 0.707 ], [ 0.707,
-0.707, 0.000 ] ]
[ [ -0.707, 0.000, 0.707 ], [ 0.000, -0.707, 0.707 ], [ 0.000,
0.000, 1.000 ] ]
[ [ -0.707, 0.000, 0.707 ], [ -1.000, 0.000, 0.000 ], [ -0.707,
-0.707, 0.000 ] ]
[ [ 0.000, -0.707, 0.707 ], [ -0.707, 0.000, 0.707 ], [ -0.707,
-0.707, 0.000 ] ]
[ [ 0.000, -1.000, 0.000 ], [ 0.000, -0.707, 0.707 ], [ -0.707,
-0.707, 0.000 ] ]
[ [ 0.000, 0.707, 0.707 ], [ -0.707, 0.000, 0.707 ], [ 0.000,
0.000, 1.000 ] ]
[ [ 0.000, 0.707, 0.707 ], [ 0.000, 1.000, 0.000 ], [ -0.707,
0.707, 0.000 ] ]
[ [ -0.707, 0.000, 0.707 ], [ 0.000, 0.707, 0.707 ], [ -0.707,
0.707, 0.000 ] ]
[ [ -1.000, 0.000, 0.000 ], [ -0.707, 0.000, 0.707 ], [ -0.707,
0.707, 0.000 ] ]
[ [ 0.707, 0.000, 0.707 ], [ 0.000, 0.707, 0.707 ], [ 0.000,
0.000, 1.000 ] ]
[ [ 0.707, 0.000, 0.707 ], [ 1.000, 0.000, 0.000 ], [ 0.707,
0.707, 0.000 ] ]
[ [ 0.000, 0.707, 0.707 ], [ 0.707, 0.000, 0.707 ], [ 0.707,
0.707, 0.000 ] ]
[ [ 0.000, 1.000, 0.000 ], [ 0.000, 0.707, 0.707 ], [ 0.707,
0.707, 0.000 ] ]
[ [ -0.707, 0.000, -0.707 ], [ 0.000, 0.707, -0.707 ], [ 0.000,
0.000, -1.000 ] ]
[ [ -0.707, 0.000, -0.707 ], [ -1.000, 0.000, 0.000 ], [ -0.707,
0.707, 0.000 ] ]
[ [ 0.000, 0.707, -0.707 ], [ -0.707, 0.000, -0.707 ], [ -0.707,
0.707, 0.000 ] ]
[ [ 0.000, 1.000, 0.000 ], [ 0.000, 0.707, -0.707 ], [ -0.707,
0.707, 0.000 ] ]
[ [ 0.000, 0.707, -0.707 ], [ 0.707, 0.000, -0.707 ], [ 0.000,
0.000, -1.000 ] ]
[ [ 0.000, 0.707, -0.707 ], [ 0.000, 1.000, 0.000 ], [ 0.707,
0.707, 0.000 ] ]
[ [ 0.707, 0.000, -0.707 ], [ 0.000, 0.707, -0.707 ], [ 0.707,
0.707, 0.000 ] ]
[ [ 1.000, 0.000, 0.000 ], [ 0.707, 0.000, -0.707 ], [ 0.707,
0.707, 0.000 ] ]
[ [ 0.707, 0.000, -0.707 ], [ 0.000, -0.707, -0.707 ], [ 0.000,
0.000, -1.000 ] ]
[ [ 0.707, 0.000, -0.707 ], [ 1.000, 0.000, 0.000 ], [ 0.707,
-0.707, 0.000 ] ]
[ [ 0.000, -0.707, -0.707 ], [ 0.707, 0.000, -0.707 ], [ 0.707,
-0.707, 0.000 ] ]
[ [ 0.000, -1.000, 0.000 ], [ 0.000, -0.707, -0.707 ], [ 0.707,
-0.707, 0.000 ] ]
[ [ 0.000, -0.707, -0.707 ], [ -0.707, 0.000, -0.707 ], [ 0.000,
0.000, -1.000 ] ]
[ [ 0.000, -0.707, -0.707 ], [ 0.000, -1.000, 0.000 ], [ -0.707,
-0.707, 0.000 ] ]
[ [ -0.707, 0.000, -0.707 ], [ 0.000, -0.707, -0.707 ], [ -0.707,
-0.707, 0.000 ] ]
[ [ -1.000, 0.000, 0.000 ], [ -0.707, 0.000, -0.707 ], [ -0.707,
-0.707, 0.000 ] ]

Sample output for a tetrahedron of frequency 2:
[ [ 0.426, -0.739, -0.522 ], [ 0.853, 0.000, -0.522 ], [ 0.816,
-0.471, -0.333 ] ]
[ [ 0.426, 0.739, -0.522 ], [ -0.426, 0.739, -0.522 ], [ 0.000,
0.943, -0.333 ] ]
[ [ -0.426, 0.739, -0.522 ], [ 0.426, 0.739, -0.522 ], [ 0.000,
0.000, -1.000 ] ]
[ [ -0.853, 0.000, -0.522 ], [ -0.426, 0.739, -0.522 ], [ 0.000,
0.000, -1.000 ] ]
[ [ -0.426, -0.739, -0.522 ], [ -0.853, 0.000, -0.522 ], [ 0.000,
0.000, -1.000 ] ]
[ [ 0.426, -0.739, -0.522 ], [ -0.426, -0.739, -0.522 ], [ 0.000,
0.000, -1.000 ] ]
[ [ 0.853, 0.000, -0.522 ], [ 0.426, -0.739, -0.522 ], [ 0.000,
0.000, -1.000 ] ]
[ [ 0.426, 0.739, -0.522 ], [ 0.853, 0.000, -0.522 ], [ 0.000,
0.000, -1.000 ] ]
[ [ -0.853, 0.000, -0.522 ], [ -0.426, -0.739, -0.522 ], [ -0.816,
-0.471, -0.333 ] ]
[ [ -0.426, -0.246, 0.870 ], [ 0.426, -0.246, 0.870 ], [ 0.000,
0.000, 1.000 ] ]
[ [ 0.853, -0.492, 0.174 ], [ 0.426, -0.739, -0.522 ], [ 0.816,
-0.471, -0.333 ] ]
[ [ 0.426, -0.739, -0.522 ], [ 0.853, -0.492, 0.174 ], [ 0.000,
-0.943, 0.333 ] ]
[ [ -0.426, -0.739, -0.522 ], [ 0.426, -0.739, -0.522 ], [ 0.000,
-0.943, 0.333 ] ]
[ [ -0.853, -0.492, 0.174 ], [ -0.426, -0.739, -0.522 ], [ 0.000,
-0.943, 0.333 ] ]
[ [ -0.426, -0.246, 0.870 ], [ -0.853, -0.492, 0.174 ], [ 0.000,
-0.943, 0.333 ] ]
[ [ 0.426, -0.246, 0.870 ], [ -0.426, -0.246, 0.870 ], [ 0.000,
-0.943, 0.333 ] ]
[ [ 0.853, -0.492, 0.174 ], [ 0.426, -0.246, 0.870 ], [ 0.000,
-0.943, 0.333 ] ]
[ [ -0.426, -0.739, -0.522 ], [ -0.853, -0.492, 0.174 ], [ -0.816,
-0.471, -0.333 ] ]
[ [ -0.426, 0.739, -0.522 ], [ 0.000, 0.985, 0.174 ], [ 0.000,
0.943, -0.333 ] ]
[ [ 0.000, 0.492, 0.870 ], [ -0.426, -0.246, 0.870 ], [ 0.000,
0.000, 1.000 ] ]
[ [ -0.426, -0.246, 0.870 ], [ 0.000, 0.492, 0.870 ], [ -0.816,
0.471, 0.333 ] ]
[ [ -0.853, -0.492, 0.174 ], [ -0.426, -0.246, 0.870 ], [ -0.816,
0.471, 0.333 ] ]
[ [ -0.853, 0.000, -0.522 ], [ -0.853, -0.492, 0.174 ], [ -0.816,
0.471, 0.333 ] ]
[ [ -0.426, 0.739, -0.522 ], [ -0.853, 0.000, -0.522 ], [ -0.816,
0.471, 0.333 ] ]
[ [ 0.000, 0.985, 0.174 ], [ -0.426, 0.739, -0.522 ], [ -0.816,
0.471, 0.333 ] ]
[ [ 0.000, 0.492, 0.870 ], [ 0.000, 0.985, 0.174 ], [ -0.816,
0.471, 0.333 ] ]
[ [ -0.853, -0.492, 0.174 ], [ -0.853, 0.000, -0.522 ], [ -0.816,
-0.471, -0.333 ] ]
[ [ 0.000, 0.985, 0.174 ], [ 0.426, 0.739, -0.522 ], [ 0.000,
0.943, -0.333 ] ]
[ [ 0.853, 0.000, -0.522 ], [ 0.853, -0.492, 0.174 ], [ 0.816,
-0.471, -0.333 ] ]
[ [ 0.853, -0.492, 0.174 ], [ 0.853, 0.000, -0.522 ], [ 0.816,
0.471, 0.333 ] ]
[ [ 0.426, -0.246, 0.870 ], [ 0.853, -0.492, 0.174 ], [ 0.816,
0.471, 0.333 ] ]
[ [ 0.000, 0.492, 0.870 ], [ 0.426, -0.246, 0.870 ], [ 0.816,
0.471, 0.333 ] ]
[ [ 0.000, 0.985, 0.174 ], [ 0.000, 0.492, 0.870 ], [ 0.816,
0.471, 0.333 ] ]
[ [ 0.426, 0.739, -0.522 ], [ 0.000, 0.985, 0.174 ], [ 0.816,
0.471, 0.333 ] ]
[ [ 0.853, 0.000, -0.522 ], [ 0.426, 0.739, -0.522 ], [ 0.816,
0.471, 0.333 ] ]
[ [ 0.426, -0.246, 0.870 ], [ 0.000, 0.492, 0.870 ], [ 0.000,
0.000, 1.000 ] ]

Sample output for an icosahedron of frequency 3:
[ [ 0.443, 0.864, 0.239 ], [ 0.682, 0.717, 0.148 ], [ 0.526,
0.851, 0.000 ] ]
[ [ 0.717, 0.148, 0.682 ], [ 0.851, 0.000, 0.526 ], [ 0.864,
0.239, 0.443 ] ]
[ [ 0.688, 0.425, 0.588 ], [ 0.717, 0.148, 0.682 ], [ 0.864,
0.239, 0.443 ] ]
[ [ 0.809, 0.500, 0.309 ], [ 0.688, 0.425, 0.588 ], [ 0.864,
0.239, 0.443 ] ]
[ [ 0.688, 0.425, 0.588 ], [ 0.809, 0.500, 0.309 ], [ 0.588,
0.688, 0.425 ] ]
[ [ 0.425, 0.588, 0.688 ], [ 0.688, 0.425, 0.588 ], [ 0.588,
0.688, 0.425 ] ]
[ [ 0.309, 0.809, 0.500 ], [ 0.425, 0.588, 0.688 ], [ 0.588,
0.688, 0.425 ] ]
[ [ 0.443, 0.864, 0.239 ], [ 0.309, 0.809, 0.500 ], [ 0.588,
0.688, 0.425 ] ]
[ [ 0.682, 0.717, 0.148 ], [ 0.443, 0.864, 0.239 ], [ 0.588,
0.688, 0.425 ] ]
[ [ 0.809, 0.500, 0.309 ], [ 0.682, 0.717, 0.148 ], [ 0.588,
0.688, 0.425 ] ]
[ [ 0.425, 0.588, 0.688 ], [ 0.239, 0.443, 0.864 ], [ 0.500,
0.309, 0.809 ] ]
[ [ 0.688, 0.425, 0.588 ], [ 0.425, 0.588, 0.688 ], [ 0.500,
0.309, 0.809 ] ]
[ [ 0.717, 0.148, 0.682 ], [ 0.688, 0.425, 0.588 ], [ 0.500,
0.309, 0.809 ] ]
[ [ 0.239, 0.443, 0.864 ], [ 0.425, 0.588, 0.688 ], [ 0.148,
0.682, 0.717 ] ]
[ [ 0.000, 0.526, 0.851 ], [ 0.239, 0.443, 0.864 ], [ 0.148,
0.682, 0.717 ] ]
[ [ 0.425, 0.588, 0.688 ], [ 0.309, 0.809, 0.500 ], [ 0.148,
0.682, 0.717 ] ]
[ [ -0.443, 0.864, 0.239 ], [ -0.295, 0.955, 0.000 ], [ -0.526,
0.851, 0.000 ] ]
[ [ 0.443, 0.864, 0.239 ], [ 0.526, 0.851, 0.000 ], [ 0.295,
0.955, 0.000 ] ]
[ [ 0.162, 0.951, 0.263 ], [ 0.443, 0.864, 0.239 ], [ 0.295,
0.955, 0.000 ] ]
[ [ 0.000, 1.000, 0.000 ], [ 0.162, 0.951, 0.263 ], [ 0.295,
0.955, 0.000 ] ]
[ [ 0.162, 0.951, 0.263 ], [ 0.000, 1.000, 0.000 ], [ -0.162,
0.951, 0.263 ] ]
[ [ 0.000, 0.851, 0.526 ], [ 0.162, 0.951, 0.263 ], [ -0.162,
0.951, 0.263 ] ]
[ [ -0.309, 0.809, 0.500 ], [ 0.000, 0.851, 0.526 ], [ -0.162,
0.951, 0.263 ] ]
[ [ -0.443, 0.864, 0.239 ], [ -0.309, 0.809, 0.500 ], [ -0.162,
0.951, 0.263 ] ]
[ [ -0.295, 0.955, 0.000 ], [ -0.443, 0.864, 0.239 ], [ -0.162,
0.951, 0.263 ] ]
[ [ 0.000, 1.000, 0.000 ], [ -0.295, 0.955, 0.000 ], [ -0.162,
0.951, 0.263 ] ]
[ [ 0.000, 0.851, 0.526 ], [ 0.148, 0.682, 0.717 ], [ 0.309,
0.809, 0.500 ] ]
[ [ 0.162, 0.951, 0.263 ], [ 0.000, 0.851, 0.526 ], [ 0.309,
0.809, 0.500 ] ]
[ [ 0.443, 0.864, 0.239 ], [ 0.162, 0.951, 0.263 ], [ 0.309,
0.809, 0.500 ] ]
[ [ 0.148, 0.682, 0.717 ], [ 0.000, 0.851, 0.526 ], [ -0.148,
0.682, 0.717 ] ]
[ [ 0.000, 0.526, 0.851 ], [ 0.148, 0.682, 0.717 ], [ -0.148,
0.682, 0.717 ] ]
[ [ 0.000, 0.851, 0.526 ], [ -0.309, 0.809, 0.500 ], [ -0.148,
0.682, 0.717 ] ]
[ [ -0.717, 0.148, 0.682 ], [ -0.864, 0.239, 0.443 ], [ -0.851,
0.000, 0.526 ] ]
[ [ -0.443, 0.864, 0.239 ], [ -0.526, 0.851, 0.000 ], [ -0.682,
0.717, 0.148 ] ]
[ [ -0.588, 0.688, 0.425 ], [ -0.443, 0.864, 0.239 ], [ -0.682,
0.717, 0.148 ] ]
[ [ -0.809, 0.500, 0.309 ], [ -0.588, 0.688, 0.425 ], [ -0.682,
0.717, 0.148 ] ]
[ [ -0.588, 0.688, 0.425 ], [ -0.809, 0.500, 0.309 ], [ -0.688,
0.425, 0.588 ] ]
[ [ -0.425, 0.588, 0.688 ], [ -0.588, 0.688, 0.425 ], [ -0.688,
0.425, 0.588 ] ]
[ [ -0.500, 0.309, 0.809 ], [ -0.425, 0.588, 0.688 ], [ -0.688,
0.425, 0.588 ] ]
[ [ -0.717, 0.148, 0.682 ], [ -0.500, 0.309, 0.809 ], [ -0.688,
0.425, 0.588 ] ]

...truncated...
 
G

Gavin Kistner

Well...no one seems to have posted a Quiz solution.

I'm sorry that it didn't seem to catch people's fancy. To help figure
out what makes a good quiz:
Was the question too hard, too long, or too boring to tackle and solve?
Or was it perhaps not specified/described well enough?

For the curious, I've posted and described my own solution here:
http://phrogz.net/CSS/Geodesics/FindingFaces.html

I've also rolled the new code into my Geodesics library, including
little features (good for testing solutions) like finding the normal
for faces and then deciding if that normal is inward- or
outward-pointing. The core face-subdividing code is at the bottom of
the previous url, the full code is at
http://phrogz.net/RubyLibs/Geodesic.rb

I apologize if people didn't find this quiz enticing enough. Please do
let us know what kept you from tackling/solving it, so better quizzes
can be made in the future.
 
F

Florian Gross

Gavin said:
Well...no one seems to have posted a Quiz solution.

I'm sorry that it didn't seem to catch people's fancy. To help figure
out what makes a good quiz:
Was the question too hard, too long, or too boring to tackle and solve?
Or was it perhaps not specified/described well enough?

I didn't understand the terminology (Not sure if that is influenced by
me not being a native speaker of English) and problem space that it
involved, personally. A few links to explanations, why this problem is
important and so on could have solved that, I think.

But I can't talk for everybody, of course.

Kind regards,
Florian Gross
 
J

Jamis Buck

Gavin said:
Well...no one seems to have posted a Quiz solution.

I'm sorry that it didn't seem to catch people's fancy. To help figure
out what makes a good quiz:
Was the question too hard, too long, or too boring to tackle and solve?
Or was it perhaps not specified/described well enough?

For the curious, I've posted and described my own solution here:
http://phrogz.net/CSS/Geodesics/FindingFaces.html

I've also rolled the new code into my Geodesics library, including
little features (good for testing solutions) like finding the normal for
faces and then deciding if that normal is inward- or outward-pointing.
The core face-subdividing code is at the bottom of the previous url, the
full code is at http://phrogz.net/RubyLibs/Geodesic.rb

I apologize if people didn't find this quiz enticing enough. Please do
let us know what kept you from tackling/solving it, so better quizzes
can be made in the future.

Well, as for me, the Quiz was fascinating enough. The timing was just
bad. :( I was swamped with other projects this weekend and didn't have a
chance to do more than read the quiz description. :(

- Jamis
 
B

Bill Kelly

Hi Gavin,

From: "Gavin Kistner said:
Well...no one seems to have posted a Quiz solution.

I'm sorry that it didn't seem to catch people's fancy. To help figure
out what makes a good quiz:
Was the question too hard, too long, or too boring to tackle and solve?
Or was it perhaps not specified/described well enough?

I liked (like?) it! This is the first Quiz that has
interested me personally enough that I have started
working on it. It happens to touch on areas that I'm
rusty on (3D vector math, OpenGL) that I'm just starting
to get back into - so it's great for me. :)

I don't know if I'll have a solution in time, i.e. I
don't know if I'll finish it this week... I'm juggling
a lot of projects... But I'm definitely enjoying the
Quiz ! :)


Thanks!

Regards,

Bill
 
M

martinus

Here is my solution:
http://martinus.geekisp.com/files/geodesic.zip
unzip and start depthcue.rb for a simple opengl visualization.

geodesic.rb contains the subsampling code,
geodesic-data.rb contains the data as published in the quiz, and
depthcue.rb is a simple opengl visualization (a modified opengl
sample).

This quiz was real fun to solve :)

martinus
 
D

Dennis Ranke

Here is my solution:
http://martinus.geekisp.com/files/geodesic.zip
unzip and start depthcue.rb for a simple opengl visualization.

geodesic.rb contains the subsampling code,
geodesic-data.rb contains the data as published in the quiz, and
depthcue.rb is a simple opengl visualization (a modified opengl
sample).

This quiz was real fun to solve :)

A nice and short solution (I wasn't even aware of the Vector class in the
standard lib), you only forgot to normalize the vertices of the resulting
triangles.
Changing the line:

ab.push b*x + a*(1.0-x)

in GeoDesicDome::split to:

v = b*x + a*(1.0-x)
ab.push v * (1 / Math.sqrt(v.inner_product(v)))

produces the correct result.
 
D

Dennis Ranke

Here is my solution to this quiz.

It's fairly straightforward the only (slightly) noteworthy point is that I
decided to use spherical interpolation instead of linear interpolation
+ normalize to calculate the subdivided vertices.
When using linear interpolation + normalize along a line, the points in
the middle will be further apart than the ones at the ends. With spherical
interpolation they are distributed evenly across the arc on the spherical
surface.
I thought that would make the resulting triangles equal sized but I had to
realise that this is actually impossible on the surface of a sphere.
So the triangles of my solution are closer to being equal sized but the
ones in the centres of the original faces are still bigger than the ones
at the original vertices.

Anyway, here is my code:

class Vector
include Math

attr_reader :x, :y, :z

def self.[](x, y, z)
self.new(x, y, z)
end

def initialize(x, y, z)
@x = x
@y = y
@z = z
end

def +(o)
Vector.new(@x+o.x, @y+o.y, @z+o.z)
end

def -(o)
Vector.new(@x-o.x, @y-o.y, @z-o.z)
end

def *(o)
case o
when Vector
@x*o.x + @y*o.y + @z*o.z
else
Vector.new(@x*o, @y*o, @z*o)
end
end

def length
sqrt(self*self)
end

def normalize
return self * (1 / length)
end

def slerp(vec, f)
cosinus = self * vec
angle = acos(cosinus)
l1 = sin(angle / 2)
r = cos(angle / 2)
l2 = r * tan(angle * (f - 0.5))
f = l2 / l1 * 0.5 + 0.5
return (self * (1 - f) + vec * f).normalize
end

def to_s
"[%7.4f, %7.4f, %7.4f]" % [@x, @y, @z]
end
end

class Triangle
def initialize(v1, v2, v3)
@v1 = v1
@v2 = v2
@v3 = v3
end

def subdivide(frequency)
@freq = frequency + 1
faces = []
for y in 0..frequency
for x in 0..y
faces << Triangle.new(self[x, y], self[x, y+1], self[x+1, y+1])
faces << Triangle.new(self[x, y], self[x+1, y+1], self[x+1, y]) if
x < y
end
end
return faces
end

def to_s
"[%s, %s, %s]" % [@v1, @v2, @v3]
end

private

def [](x, y)
return @v1 if y == 0
p1 = @v1.slerp(@v2, y.to_f / @freq)
p2 = @v1.slerp(@v3, y.to_f / @freq)
return p1.slerp(p2, x.to_f / y)
end
end

class Dome
def initialize(datahash = nil)
@faces = []
if datahash
points = datahash[:points]
datahash[:faces].each do |face|
vertices = face.split(//).map {|v| points[v]}
add_face(Triangle.new(*vertices))
end
end
end

def subdivide(frequency)
new_dome = Dome.new
@faces.each do |face|
face.subdivide(frequency).each do |new_face|
new_dome.add_face(new_face)
end
end
return new_dome
end

def add_face(face)
@faces << face
end

def to_s
@faces.join("\n")
end
end

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 |
},
:eek:ctahedron => {
: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 |
}
}

puts Dome.new(PRIMITIVES[:eek:ctahedron]).subdivide(2)
 
G

Gavin Kistner

v = b*x + a*(1.0-x)
ab.push v * (1 / Math.sqrt(v.inner_product(v)))

The Vector class has its own magnitude/length property called .r, so:

ab.push v * (1.0 / v.r )
would be slightly better.

Or, as I did:

# Extensions to the Vector class
class Vector
# Returns a Vector whose length (<tt>.r</tt>) is 1.0
def normalized
self / self.r
end

# Divide the vector by a scalar
# Scales the values in the Vector by 1.0 / n, and returns the new
Vector
def /( n )
self * ( 1.0 / n )
end

# Modify the receiving vector to be of length (<tt>.r</tt>) 1.0
def normalize!
len = self.r
self.scale_by!( 1/len )
end

# Modify the receiving vector, multiplying each component by the
specified factor
def scale_by!( scale_factor )
@elements.collect!{ |e| e*scale_factor }
self
end

# Modify the receiving vector, scaling it to be the specified length
def r=(new_len)
old_len = self.r
self.scale_by!( new_len/old_len ) unless new_len==old_len
self
end
end
 
J

Joe Cheng

I'm sorry that it didn't seem to catch people's fancy. To help figure
out what makes a good quiz:
Was the question too hard, too long, or too boring to tackle and solve?
Or was it perhaps not specified/described well enough?

I was out of town... sounds like an interesting problem.
 
J

James Edward Gray II

depthcue.rb is a simple opengl visualization (a modified opengl
sample).

I just have to say... That's nifty! I'm over here watching the pretty
picture. :) Nice job.

James Edward Gray II
 
Z

Zach Dennis

Ever since the Ruby Quiz started a coincedence at work and in personal
life have popped up. This is causin 5-6 weekends in a row to be busy or
out of town for me to participate, although i really would like to. I
have been working on some of the quiz's during the week when i get spare
time at the office. Should I just keep my solution to myself since I
don't finish them until 1 to 3 weeks (depending on how busy the week is)
after the it was posted? Or post them anyways they are way way late?

Thanks,

Zach
 
D

David Ross

You should post them.. I like reading others people ways of solving
problems. Ultimately this needs to be solved by creating a solution post
site. Not just on the mailing list. It would be nice anyway :) Go ahead
and post please. I wish to read it.

--dross
 
J

James Edward Gray II

Ever since the Ruby Quiz started a coincedence at work and in personal
life have popped up. This is causin 5-6 weekends in a row to be busy
or out of town for me to participate, although i really would like to.
I have been working on some of the quiz's during the week when i get
spare time at the office. Should I just keep my solution to myself
since I don't finish them until 1 to 3 weeks (depending on how busy
the week is) after the it was posted? Or post them anyways they are
way way late?

Naturally, summaries and such won't be modified after they're up, just
because we're off working on other quizzes. Other than that though, I
see absolutely no reason not to post them if you want to.

I'm happy to see any solutions that come along, and I hope others feel
the same. I view Ruby Quiz as being about learning new things and
seeing fresh approaches to a problem and I'm for anything that furthers
that. I certainly don't view Ruby Quiz as a race. The time periods
are in place only to facilitate forward progress.

I'm glad you're enjoying the quizzes. :)

James Edward Gray II
 
J

James Edward Gray II

You should post them.. I like reading others people ways of solving
problems.

I agree.
Ultimately this needs to be solved by creating a solution post site.
Not just on the mailing list. It would be nice anyway :)

Start codin', Pal! :D

Seriously, I do hope you're aware of:

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

The site does maintain links to all submitted solutions, including the
only one that has been submitted after the deadline at this point.

If you would like more functionality than this, feel free to put it
online. You could easily make a page that held solutions, waited
through the no-spoiler period, sent them to the list and handled
whatever kind of archiving you desire. If I'm aware of it, I would
certainly link to such a resource.

Even better, write it up as a Ruby Quiz and let the community realize
their own ideal solutions! (Module writers, I sure hope you're
listening because you have a stellar new resource just waiting to be
tapped...)
Go ahead and post please. I wish to read it.

Well said.

James Edward Gray II

P.S. If the Ruby Quiz website was "wonky" in your browser before, I
BELIEVE I finally have it all fixed up. It SHOULD look as intended in
most modern browsers now. I've worked long and hard to make it so. If
the page is broken for you, send me a screenshot and your browser
version information and I'll see if there's any more I can do.
 
B

Bill Guindon

I agree.


Start codin', Pal! :D

Seriously, I do hope you're aware of:

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

The site does maintain links to all submitted solutions, including the
only one that has been submitted after the deadline at this point.

If you would like more functionality than this, feel free to put it
online. You could easily make a page that held solutions, waited
through the no-spoiler period, sent them to the list and handled
whatever kind of archiving you desire. If I'm aware of it, I would
certainly link to such a resource.

Mentioned the quiz to the codepaste author. I think it'd be a great marriage.
http://www.codepaste.org/view/lang/ruby
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top