/***
 * Creates a list of all contours at the level given by "level".
 *
 * It starts by loading each facet and looking at each edge of the triangle
 * to determine whether the facet crosses "level".
 *
 * If so, it determines the line segment that is formed by the intersection
 * of z = level and the facet.
 *
 * It uses normal to determine the direction of the line segment (i.e. which
 * is x1,y1 and which is x2,y2).  When traveling from x1,y1 to x2,y2, the normal
 * vector must always lean to the right to ensure that the polygon progresses
 * counterclockwise direction.
 *
 * After all line segments have been recorder, they are sorted to form closed
 * polygons.args.
 *
 * Each time a polygon closes, it is recorded into the return string
 * and a new polygon is started.
 *
 * If any polygons fail to close (within tolerance), an error is generated.
 *
 * The returned data is of the form:
 *
 *  [
 *    [{X: x1, Y: y1}, . . ., {X: xn, Y: yn}],
 *    . . .
 *    [{X: x1, Y: y1}, . . ., {X: xn, Y: yn}]
 *  ]
 */
void STLModule::contour(const js::Value &args, js::Sink &sink) {
  // Read facets
  vector<STL::Facet> facets;
  readFacets(facets, *args.get("stl")->get("facets"));

  // Process one level
  if (args.get("level")->isNumber())
    contourLevel(sink, facets, args.getNumber("level"));

  // Process multiple levels
  if (args.get("start")->isNumber() && args.get("end")->isNumber() &&
      args.get("steps")->isNumber()) {
    float start = args.getNumber("start");
    float end = args.getNumber("end");
    int steps = args.getInteger("steps");

    if (start == end || steps <= 1) return;

    float delta = (end - start) / (steps - 1);

    sink.beginList();
    for (int i = 0; i < steps; i++) {
      float level = start + delta * i;

      sink.appendDict();
      sink.insert("Z", level);
      sink.beginInsert("contours");
      contourLevel(sink, facets, level);
      sink.endDict();
    }
    sink.endList();
  }
}
void STLModule::bounds(const js::Value &args, js::Sink &sink) {
  SmartPointer<js::Value> facets = args.get("stl")->get("facets");
  Rectangle3F bounds;

  unsigned length = facets->length();
  for (unsigned i = 0; i < length; i++) {
    SmartPointer<js::Value> facet = facets->get(i);

    for (unsigned j = 0; j < 3; j++)
      bounds.add(toVector3F(*facet->get(j)));
  }

  sink.beginList();
  append(sink, bounds.getMin());
  append(sink, bounds.getMax());
  sink.endList();
}