lib/sphere/to-cg.js
function fieldVerticesAndFaces(sphere, options, done) {

  // counter-clockwise face-vertex orders

  const PENT_FACES    = [0, 2, 1, /**/ 0, 4, 2, /**/ 4, 3, 2],
        HEX_FACES     = [0, 2, 1, /**/ 0, 3, 2, /**/ 0, 5, 3, /**/ 5, 4, 3],

        PENT_FACES_CW = [1, 2, 0, /**/ 2, 4, 0, /**/ 2, 3, 4];

  var interfieldTriangles = sphere._interfieldTriangles,
      nPolyEdgeVerts      = interfieldTriangles.length / 3,
      nPolys              = sphere._Fields.length;

  var nDistinctVertices = nPolys * 6 - 12, // 6 vertices for each poly (-12 vertices for the 12 pentagons)
      nTriangles        = nPolys * 4 - 12; // 4 triangles to each hexagon, 3 to each pentagon of which there are 12.

  // support maps
  var fieldPosMap      = intArr(nDistinctVertices, nPolys),
      indexedPositions = new Float32Array(nPolyEdgeVerts * 3);

  // maps for the GPU
  var indices   = intArr(nDistinctVertices, nTriangles * 3),
      positions = new Float32Array(nDistinctVertices * 3),
      normals   = new Float32Array(nDistinctVertices * 3),
      colors    = new Float32Array(nDistinctVertices * 3);

  // populate the cartesian coordinates of positions

  for (let v = 0; v < nPolyEdgeVerts; v += 1) {

    let c_φ = sphere._interfieldCentroids[2 * v + 0],
        c_λ = sphere._interfieldCentroids[2 * v + 1];

    indexedPositions[3 * v + 0] = cos(c_φ) * cos(c_λ); // x
    indexedPositions[3 * v + 2] = cos(c_φ) * sin(c_λ); // z
    indexedPositions[3 * v + 1] = sin(c_φ); // y

  }

  var c = 0, t = 0;

  for (let f = 0; f < nPolys; f += 1) {

    let field          = sphere._Fields[f],
        sides          = field._adjacentFields.length,
        color          = options.colorFn.call(field),
        f_φ            = sphere._positions[2 * f + 0],
        f_λ            = sphere._positions[2 * f + 1],
        polyPosIndices = [];

    fieldPosMap[f] = c;

    for (let s = 0; s < sides; s += 1) {

      let cc = (c + s),
          fi = sphere._interfieldIndices[6 * f + s];

      polyPosIndices.push(fi);

      positions[cc * 3 + 0] = indexedPositions[fi * 3 + 0];
      positions[cc * 3 + 1] = indexedPositions[fi * 3 + 1];
      positions[cc * 3 + 2] = indexedPositions[fi * 3 + 2];

      colors[cc * 3 + 0] = color.r;
      colors[cc * 3 + 1] = color.g;
      colors[cc * 3 + 2] = color.b;

      normals[cc * 3 + 0] = cos(f_φ) * cos(f_λ);
      normals[cc * 3 + 2] = cos(f_φ) * sin(f_λ);
      normals[cc * 3 + 1] = sin(f_φ);

    }

    let faces;

    if (f === 1) {
      faces = PENT_FACES_CW;
    } else {
      faces = sides === 5 ? PENT_FACES : HEX_FACES;
    }

    for (let v = 0; v < faces.length; v += 1) {

      let tt = (t + v);

      indices[tt] = c + faces[v];

    }

    c += sides;
    t += faces.length;

  }

  done.call(null, null, {
    positions,
    indices,
    normals,
    colors
  });

}
function fieldVerticesAndFaces(sphere, options, done) {

  // counter-clockwise face-vertex orders

  const PENT_FACES    = [0, 2, 1, /**/ 0, 4, 2, /**/ 4, 3, 2],
        HEX_FACES     = [0, 2, 1, /**/ 0, 3, 2, /**/ 0, 5, 3, /**/ 5, 4, 3],

        PENT_FACES_CW = [1, 2, 0, /**/ 2, 4, 0, /**/ 2, 3, 4];

  var interfieldTriangles = sphere._interfieldTriangles,
      nPolyEdgeVerts      = interfieldTriangles.length / 3,
      nPolys              = sphere._Fields.length;

  var nDistinctVertices = nPolys * 6 - 12, // 6 vertices for each poly (-12 vertices for the 12 pentagons)
      nTriangles        = nPolys * 4 - 12; // 4 triangles to each hexagon, 3 to each pentagon of which there are 12.

  // support maps
  var fieldPosMap      = intArr(nDistinctVertices, nPolys),
      indexedPositions = new Float32Array(nPolyEdgeVerts * 3);

  // maps for the GPU
  var indices   = intArr(nDistinctVertices, nTriangles * 3),
      positions = new Float32Array(nDistinctVertices * 3),
      normals   = new Float32Array(nDistinctVertices * 3),
      colors    = new Float32Array(nDistinctVertices * 3);

  // populate the cartesian coordinates of positions

  for (let v = 0; v < nPolyEdgeVerts; v += 1) {

    let c_φ = sphere._interfieldCentroids[2 * v + 0],
        c_λ = sphere._interfieldCentroids[2 * v + 1];

    indexedPositions[3 * v + 0] = cos(c_φ) * cos(c_λ); // x
    indexedPositions[3 * v + 2] = cos(c_φ) * sin(c_λ); // z
    indexedPositions[3 * v + 1] = sin(c_φ); // y

  }

  var c = 0, t = 0;

  for (let f = 0; f < nPolys; f += 1) {

    let field          = sphere._Fields[f],
        sides          = field._adjacentFields.length,
        color          = options.colorFn.call(field),
        f_φ            = sphere._positions[2 * f + 0],
        f_λ            = sphere._positions[2 * f + 1],
        polyPosIndices = [];

    fieldPosMap[f] = c;

    for (let s = 0; s < sides; s += 1) {

      let cc = (c + s),
          fi = sphere._interfieldIndices[6 * f + s];

      polyPosIndices.push(fi);

      positions[cc * 3 + 0] = indexedPositions[fi * 3 + 0];
      positions[cc * 3 + 1] = indexedPositions[fi * 3 + 1];
      positions[cc * 3 + 2] = indexedPositions[fi * 3 + 2];

      colors[cc * 3 + 0] = color.r;
      colors[cc * 3 + 1] = color.g;
      colors[cc * 3 + 2] = color.b;

      normals[cc * 3 + 0] = cos(f_φ) * cos(f_λ);
      normals[cc * 3 + 2] = cos(f_φ) * sin(f_λ);
      normals[cc * 3 + 1] = sin(f_φ);

    }

    let faces;

    if (f === 1) {
      faces = PENT_FACES_CW;
    } else {
      faces = sides === 5 ? PENT_FACES : HEX_FACES;
    }

    for (let v = 0; v < faces.length; v += 1) {

      let tt = (t + v);

      indices[tt] = c + faces[v];

    }

    c += sides;
    t += faces.length;

  }

  done.call(null, null, {
    positions,
    indices,
    normals,
    colors
  });

}
Creates edges between actual fields and returns an array of vertices and a
corresponding array of faces to use in three.js. This representation of the
model is popularly depicted in the reference materials.

@param sphere
@param options
@param done