// Support code for drawing 3d polyhedra.
// Some or all of the following code is copyrighted.
// Copyright 2007 Bill Gibbons
// License: Creative Commons Attribution 3.0 License
// See http://creativecommons.org/licenses/by/3.0/


// Build the polyhedron from vertices and polygon vertex lists.

function make_polyhedron(vertices, polygons, new_center, new_radius) {
  var polyhedron = new Array(polygons.length);
  for (var i = 0; i < polygons.length; i++) {
    var polygon = new Array(polygons[i].length);
    for (var j = 0; j < polygons[i].length; j++) {
      polygon[j] = vertices[polygons[i][j]];
    }
    polygon.color = "rgb(" + (Math.floor(Math.random()*256)) + "," +
                             (Math.floor(Math.random()*256)) + "," +
                             (Math.floor(Math.random()*256)) + ")";
    polyhedron[i] = polygon;
  }

  var center = [ 0, 0, 0 ];
  for (var i = 0; i < vertices.length; i++) {
    center[0] += vertices[i][0];
    center[1] += vertices[i][1];
    center[2] += vertices[i][2];
  }
  center[0] /= vertices.length;
  center[1] /= vertices.length;
  center[2] /= vertices.length;

  var max_radius_squared = 0;
  for (var i = 0; i < vertices.length; i++) {
    var radius_squared =
        (vertices[i][0] - center[0]) * (vertices[i][0] - center[0]) +
        (vertices[i][1] - center[1]) * (vertices[i][1] - center[1]) +
        (vertices[i][2] - center[2]) * (vertices[i][2] - center[2]);
    if (radius_squared > max_radius_squared)
      max_radius_squared = radius_squared;
  }
  var radius = Math.sqrt(max_radius_squared);
  var scale = new_radius / radius;

  for (var i = 0; i < polyhedron.length; i++) {
    for (var j = 0; j < polyhedron[i].length; j++) {
      var x = scale*(polyhedron[i][j][0]-center[0])+new_center[0];
      var y = scale*(polyhedron[i][j][1]-center[1])+new_center[1];
      var z = scale*(polyhedron[i][j][2]-center[2])+new_center[2];
      polyhedron[i][j] = [ x, y, z ];
    }
  }
  polyhedron.radius = new_radius;
  polyhedron.center = new_center;
  return polyhedron;
}


///////////////////////////////////////////////////////////////////////////////

// Rotation matrices.

function roll_transform(theta) {
  var s = Math.sin(theta);
  var c = Math.cos(theta);
  return [ [  1,  0,  0  ],
           [  0,  c, -s  ],
           [  0,  s,  c  ] ];
}

function pitch_transform(theta) {
  var s = Math.sin(theta);
  var c = Math.cos(theta);
  return [ [  c,  0, s  ],
           [  0,  1, 0  ],
           [ -s,  0, c  ] ];
}

function yaw_transform(theta) {
  var s = Math.sin(theta);
  var c = Math.cos(theta);
  return [ [  c, -s, 0  ],
           [  s,  c, 0  ],
           [  0,  0, 1  ] ];
}


// Matrix multiplication.

function multiply33(one, two) {
  return [
           [ one[0][0]*two[0][0] + one[0][1]*two[1][0] + one[0][2]*two[2][0],
             one[0][0]*two[0][1] + one[0][1]*two[1][1] + one[0][2]*two[2][1],
             one[0][0]*two[0][2] + one[0][1]*two[1][2] + one[0][2]*two[2][2] ],
           [ one[1][0]*two[0][0] + one[1][1]*two[1][0] + one[1][2]*two[2][0],
             one[1][0]*two[0][1] + one[1][1]*two[1][1] + one[1][2]*two[2][1],
             one[1][0]*two[0][2] + one[1][1]*two[1][2] + one[1][2]*two[2][2] ],
           [ one[2][0]*two[0][0] + one[2][1]*two[1][0] + one[2][2]*two[2][0],
             one[2][0]*two[0][1] + one[2][1]*two[1][1] + one[2][2]*two[2][1],
             one[2][0]*two[0][2] + one[2][1]*two[1][2] + one[2][2]*two[2][2] ]
         ];
}


function multiply31(one, two) {
  return [ one[0][0]*two[0] + one[0][1]*two[1] + one[0][2]*two[2],
           one[1][0]*two[0] + one[1][1]*two[1] + one[1][2]*two[2],
           one[2][0]*two[0] + one[2][1]*two[1] + one[2][2]*two[2] ];
}


// Rotation.

function transform_point(point, center, transform) {
  var result = [ point[0], point[1], point[2] ];
  result[0] -= center[0];
  result[1] -= center[1];
  result[2] -= center[2];
  result = multiply31(transform, result);
  result[0] += center[0];
  result[1] += center[1];
  result[2] += center[2];
  return result;
}


function transform_polyhedron(polyhedron, transform) {
  var result = new Array(polyhedron.length);
  for (var i = 0; i < polyhedron.length; i++) {
    result[i] = new Array(polyhedron[i].length);
    for (var j = 0; j < polyhedron[i].length; j++) {
      result[i][j] = transform_point(polyhedron[i][j], polyhedron.center,
                                     transform);
    }
    result[i].color = polyhedron[i].color;
  }
  return result;
}


function rotate_polyhedron(polyhedron, angles) {
  var troll = roll_transform(angles[0]);
  var tpitch = pitch_transform(angles[1]);
  var tyaw = yaw_transform(angles[2]);
  var transform = multiply33(troll, multiply33(tpitch, tyaw));
  var result = transform_polyhedron(polyhedron, transform);
  result.center = polyhedron.center;
  result.radius = polyhedron.radius;
  return result;
}
