<commit_before>#include <fstream>
#include <stdexcept>

#include "Geometry.h"
#include "spruce.hh"

using std::string;
using std::istringstream;
using std::ifstream;

using Eigen::Vector3i;
using Eigen::Vector3d;
using Eigen::RowVectorXd;
using Eigen::Matrix3Xd;
using Eigen::Matrix3Xi;

namespace DrakeShapes {
const int Geometry::NUM_BBOX_POINTS = 8;
const int Sphere::NUM_POINTS = 1;
const int Capsule::NUM_POINTS = 2;

std::string ShapeToString(Shape ss) {
  switch (ss) {
    case UNKNOWN:
      return "UNKNOWN";
    case BOX:
      return "BOX";
    case SPHERE:
      return "SPHERE";
    case CYLINDER:
      return "CYLINDER";
    case MESH:
      return "MESH";
    case MESH_POINTS:
      return "MESH_POINTS";
    case CAPSULE:
      return "CAPSULE";
  }
  return "UNDEFINED";
}

Geometry::Geometry() : shape(UNKNOWN) {}

Geometry::Geometry(const Geometry &other) { shape = other.getShape(); }

Geometry::Geometry(Shape shape) : shape(shape) {}

Shape Geometry::getShape() const { return shape; }

Geometry *Geometry::clone() const { return new Geometry(*this); }

void Geometry::getPoints(Matrix3Xd &points) const { points = Matrix3Xd(); }

void Geometry::getBoundingBoxPoints(Matrix3Xd &points) const {
  points = Matrix3Xd();
}

void Geometry::getBoundingBoxPoints(double x_half_width, double y_half_width,
                                    double z_half_width,
                                    Eigen::Matrix3Xd &points) const {
  // Return axis-aligned bounding-box vertices
  points.resize(3, NUM_BBOX_POINTS);

  RowVectorXd cx(NUM_BBOX_POINTS), cy(NUM_BBOX_POINTS), cz(NUM_BBOX_POINTS);
  cx << -1, 1, 1, -1, -1, 1, 1, -1;
  cy << 1, 1, 1, 1, -1, -1, -1, -1;
  cz << 1, 1, -1, -1, -1, -1, 1, 1;
  cx = cx * x_half_width;
  cy = cy * y_half_width;
  cz = cz * z_half_width;

  points << cx, cy, cz;
}

std::ostream &operator<<(std::ostream &out, const Geometry &gg) {
  out << ShapeToString(gg.getShape()) << ", " << gg.NUM_BBOX_POINTS;
  return out;
}

Sphere::Sphere(double radius) : Geometry(SPHERE), radius(radius) {}

Sphere *Sphere::clone() const { return new Sphere(*this); }

void Sphere::getPoints(Matrix3Xd &points) const {
  points = Matrix3Xd::Zero(3, NUM_POINTS);
}

void Sphere::getBoundingBoxPoints(Matrix3Xd &points) const {
  Geometry::getBoundingBoxPoints(radius, radius, radius, points);
}

void Sphere::getTerrainContactPoints(Matrix3Xd &points) const {
  if (radius < 1e-6)
    getPoints(points);
  else
    points = Matrix3Xd();
}

std::ostream &operator<<(std::ostream &out, const Sphere &ss) {
  out << static_cast<const Geometry &>(ss) << ", " << ss.radius << ", "
      << ss.NUM_POINTS;
  return out;
}

Box::Box(const Eigen::Vector3d &size) : Geometry(BOX), size(size) {}

Box *Box::clone() const { return new Box(*this); }

void Box::getPoints(Matrix3Xd &points) const {
  Geometry::getBoundingBoxPoints(size(0) / 2.0, size(1) / 2.0, size(2) / 2.0,
                                 points);
}

void Box::getBoundingBoxPoints(Matrix3Xd &points) const { getPoints(points); }

void Box::getTerrainContactPoints(Matrix3Xd &points) const {
  getPoints(points);
}

std::ostream &operator<<(std::ostream &out, const Box &bb) {
  out << static_cast<const Geometry &>(bb) << ", " << bb.size.transpose();
  return out;
}

Cylinder::Cylinder(double radius, double length)
    : Geometry(CYLINDER), radius(radius), length(length) {}

Cylinder *Cylinder::clone() const { return new Cylinder(*this); }

void Cylinder::getPoints(Matrix3Xd &points) const {
  static bool warnOnce = true;
  if (warnOnce) {
    std::cerr << "Warning: DrakeShapes::Cylinder::getPoints(): """
        "This method returns the vertices of the cylinder''s bounding-box."
         << std::endl;
    warnOnce = false;
  }

  getBoundingBoxPoints(points);
}

void Cylinder::getBoundingBoxPoints(Matrix3Xd &points) const {
  Geometry::getBoundingBoxPoints(radius, radius, length / 2.0, points);
}

std::ostream &operator<<(std::ostream &out, const Cylinder &cc) {
  out << static_cast<const Geometry &>(cc) << ", " << cc.radius << ", "
      << cc.length;
  return out;
}

Capsule::Capsule(double radius, double length)
    : Geometry(CAPSULE), radius(radius), length(length) {}

Capsule *Capsule::clone() const { return new Capsule(*this); }

void Capsule::getPoints(Matrix3Xd &points) const {
  // Return segment end-points
  points.resize(Eigen::NoChange, NUM_POINTS);
  RowVectorXd cx = RowVectorXd::Zero(NUM_POINTS);
  RowVectorXd cy = RowVectorXd::Zero(NUM_POINTS);
  RowVectorXd cz = RowVectorXd::Zero(NUM_POINTS);
  cz << length / 2.0, -length / 2.0;

  points << cx, cy, cz;
}

void Capsule::getBoundingBoxPoints(Matrix3Xd &points) const {
  Geometry::getBoundingBoxPoints(radius, radius, (length / 2.0 + radius),
                                 points);
}

std::ostream &operator<<(std::ostream &out, const Capsule &cc) {
  out << static_cast<const Geometry &>(cc) << ", " << cc.radius << ", "
      << cc.length;
  return out;
}

Mesh::Mesh(const string &filename)
    : Geometry(MESH), scale(1.0, 1.0, 1.0), filename(filename) {}

Mesh::Mesh(const string &filename, const string &resolved_filename)
    : Geometry(MESH),
      scale(1.0, 1.0, 1.0),
      filename(filename),
      resolved_filename(resolved_filename) {}

bool Mesh::extractMeshVertices(Matrix3Xd &vertex_coordinates) const {
  if (resolved_filename.empty()) {
    return false;
  }
  spruce::path spath(resolved_filename);
  string ext = spath.extension();
  std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);

  ifstream file;
  if (ext.compare(".obj") == 0) {
    file.open(spath.getStr().c_str(), ifstream::in);
  } else {
    spath.setExtension(".obj");

    if (spath.exists()) {
      // try changing the extension to obj and loading.
      file.open(spath.getStr().c_str(), ifstream::in);
    }
  }

  if (!file.is_open()) {
    std::cerr << "Warning: Mesh " << spath.getStr()
         << " ignored because it does not have extension .obj (nor can I find "
            "a juxtaposed file with a .obj extension)"
         << std::endl;
    return false;
  }

  string line;
  // Count the number of vertices and resize vertex_coordinates.
  int num_vertices = 0;
  while (getline(file, line)) {
    istringstream iss(line);
    string type;
    if (iss >> type && type == "v") {
      ++num_vertices;
    }
  }
  vertex_coordinates.resize(3, num_vertices);

  file.clear();
  file.seekg(0, file.beg);

  double d;
  int j = 0;
  while (getline(file, line)) {
    istringstream iss(line);
    string type;
    if (iss >> type && type == "v") {
      int i = 0;
      while (iss >> d) {
        vertex_coordinates(i++, j) = d;
      }
      ++j;
    }
  }
  return true;
}

bool Mesh::ReadMeshConnectivities(Matrix3Xi& connectivities) const {
  if (resolved_filename.empty()) return false;

  spruce::path spath(resolved_filename);
  string ext = spath.extension();
  std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);

  FILE* file;
  if (ext.compare(".obj") == 0) {
    file = fopen(spath.getStr().c_str(),"r");
  } else {
    spath.setExtension(".obj");
    if (spath.exists()) {
      // try changing the extension to obj and loading.
      file = fopen(spath.getStr().c_str(),"r");
    }
  }

  if (!file) {
    throw std::logic_error(
        "Could not open mesh file \""+spath.getStr() + "\".");
  }

  // Count the number of triangles and resize connectivities.
  int num_triangles = 0;
  char *line = NULL;
  size_t len = 0;
  ssize_t read;
  char key[128];
  while ((read = getline(&line, &len, file)) != -1) {
    sscanf(line,"%s",key);
    if (strcmp(key, "f") == 0) ++num_triangles;
  }

  // Allocate memory.
  connectivities.resize(3, num_triangles);

  // Read triangles.
  rewind(file);
  int itri = 0;
  int ignored_entry;
  int tri[3];
  while(true) {
    // Get first word in the line.
    if(fscanf(file, "%s", key) == EOF) break;
    if (strcmp(key, "f") == 0) {
      int matches = fscanf(file,
                           "%d//%d %d//%d %d//%d\n",
                           tri + 0,
                           &ignored_entry,
                           tri + 1,
                           &ignored_entry,
                           tri + 2,
                           &ignored_entry);
      if(matches != 6)
        throw std::logic_error(
            "File \""+filename+"\" cannot be parsed. Format not supported.");
      connectivities.col(itri++) = Vector3i(tri[0]-1,tri[1]-1,tri[2]-1);
      if(itri>num_triangles)
        throw(std::logic_error("Number of triangles exceeded previous count."));
    }
  } // while
  fclose(file);

  return true;
}

Mesh *Mesh::clone() const { return new Mesh(*this); }

void Mesh::getPoints(Eigen::Matrix3Xd &point_matrix) const {
  extractMeshVertices(point_matrix);
}

void Mesh::getBoundingBoxPoints(Matrix3Xd &bbox_points) const {
  Matrix3Xd mesh_vertices;
  extractMeshVertices(mesh_vertices);

  Vector3d min_pos = mesh_vertices.rowwise().minCoeff();
  Vector3d max_pos = mesh_vertices.rowwise().maxCoeff();

  bbox_points.resize(Eigen::NoChange, NUM_BBOX_POINTS);
  bbox_points << min_pos(0), min_pos(0), min_pos(0), min_pos(0), max_pos(0),
      max_pos(0), max_pos(0), max_pos(0), min_pos(1), min_pos(1), max_pos(1),
      max_pos(1), min_pos(1), min_pos(1), max_pos(1), max_pos(1), min_pos(2),
      max_pos(2), min_pos(2), max_pos(2), min_pos(2), max_pos(2), min_pos(2),
      max_pos(2);
}

std::ostream &operator<<(std::ostream &out, const Mesh &mm) {
  out << static_cast<const Geometry &>(mm) << ", " << mm.scale << ", "
      << mm.filename << ", " << mm.resolved_filename << ", " << mm.root_dir;
  return out;
}

MeshPoints::MeshPoints(const Eigen::Matrix3Xd &points)
    : Geometry(MESH_POINTS), points(points) {}

MeshPoints *MeshPoints::clone() const { return new MeshPoints(*this); }

void MeshPoints::getPoints(Eigen::Matrix3Xd &point_matrix) const {
  point_matrix = points;
}

void MeshPoints::getBoundingBoxPoints(Matrix3Xd &bbox_points) const {
  Vector3d min_pos = points.rowwise().minCoeff();
  Vector3d max_pos = points.rowwise().maxCoeff();

  bbox_points.resize(Eigen::NoChange, NUM_BBOX_POINTS);
  bbox_points << min_pos(0), min_pos(0), min_pos(0), min_pos(0), max_pos(0),
      max_pos(0), max_pos(0), max_pos(0), min_pos(1), min_pos(1), max_pos(1),
      max_pos(1), min_pos(1), min_pos(1), max_pos(1), max_pos(1), min_pos(2),
      max_pos(2), min_pos(2), max_pos(2), min_pos(2), max_pos(2), min_pos(2),
      max_pos(2);
}

std::ostream &operator<<(std::ostream &out, const MeshPoints &mp) {
  out << static_cast<const Geometry &>(mp) << ",\n" << mp.points;
  return out;
}

}  // namespace DrakeShapes
<commit_msg>Adds comments, cleans lint, etc in Mesh::ReadMeshConnectivities<commit_after>#include <fstream>
#include <stdexcept>

#include "Geometry.h"
#include "spruce.hh"

using std::string;
using std::istringstream;
using std::ifstream;

using Eigen::Vector3i;
using Eigen::Vector3d;
using Eigen::RowVectorXd;
using Eigen::Matrix3Xd;
using Eigen::Matrix3Xi;

namespace DrakeShapes {
const int Geometry::NUM_BBOX_POINTS = 8;
const int Sphere::NUM_POINTS = 1;
const int Capsule::NUM_POINTS = 2;

std::string ShapeToString(Shape ss) {
  switch (ss) {
    case UNKNOWN:
      return "UNKNOWN";
    case BOX:
      return "BOX";
    case SPHERE:
      return "SPHERE";
    case CYLINDER:
      return "CYLINDER";
    case MESH:
      return "MESH";
    case MESH_POINTS:
      return "MESH_POINTS";
    case CAPSULE:
      return "CAPSULE";
  }
  return "UNDEFINED";
}

Geometry::Geometry() : shape(UNKNOWN) {}

Geometry::Geometry(const Geometry &other) { shape = other.getShape(); }

Geometry::Geometry(Shape shape) : shape(shape) {}

Shape Geometry::getShape() const { return shape; }

Geometry *Geometry::clone() const { return new Geometry(*this); }

void Geometry::getPoints(Matrix3Xd &points) const { points = Matrix3Xd(); }

void Geometry::getBoundingBoxPoints(Matrix3Xd &points) const {
  points = Matrix3Xd();
}

void Geometry::getBoundingBoxPoints(double x_half_width, double y_half_width,
                                    double z_half_width,
                                    Eigen::Matrix3Xd &points) const {
  // Return axis-aligned bounding-box vertices
  points.resize(3, NUM_BBOX_POINTS);

  RowVectorXd cx(NUM_BBOX_POINTS), cy(NUM_BBOX_POINTS), cz(NUM_BBOX_POINTS);
  cx << -1, 1, 1, -1, -1, 1, 1, -1;
  cy << 1, 1, 1, 1, -1, -1, -1, -1;
  cz << 1, 1, -1, -1, -1, -1, 1, 1;
  cx = cx * x_half_width;
  cy = cy * y_half_width;
  cz = cz * z_half_width;

  points << cx, cy, cz;
}

std::ostream &operator<<(std::ostream &out, const Geometry &gg) {
  out << ShapeToString(gg.getShape()) << ", " << gg.NUM_BBOX_POINTS;
  return out;
}

Sphere::Sphere(double radius) : Geometry(SPHERE), radius(radius) {}

Sphere *Sphere::clone() const { return new Sphere(*this); }

void Sphere::getPoints(Matrix3Xd &points) const {
  points = Matrix3Xd::Zero(3, NUM_POINTS);
}

void Sphere::getBoundingBoxPoints(Matrix3Xd &points) const {
  Geometry::getBoundingBoxPoints(radius, radius, radius, points);
}

void Sphere::getTerrainContactPoints(Matrix3Xd &points) const {
  if (radius < 1e-6)
    getPoints(points);
  else
    points = Matrix3Xd();
}

std::ostream &operator<<(std::ostream &out, const Sphere &ss) {
  out << static_cast<const Geometry &>(ss) << ", " << ss.radius << ", "
      << ss.NUM_POINTS;
  return out;
}

Box::Box(const Eigen::Vector3d &size) : Geometry(BOX), size(size) {}

Box *Box::clone() const { return new Box(*this); }

void Box::getPoints(Matrix3Xd &points) const {
  Geometry::getBoundingBoxPoints(size(0) / 2.0, size(1) / 2.0, size(2) / 2.0,
                                 points);
}

void Box::getBoundingBoxPoints(Matrix3Xd &points) const { getPoints(points); }

void Box::getTerrainContactPoints(Matrix3Xd &points) const {
  getPoints(points);
}

std::ostream &operator<<(std::ostream &out, const Box &bb) {
  out << static_cast<const Geometry &>(bb) << ", " << bb.size.transpose();
  return out;
}

Cylinder::Cylinder(double radius, double length)
    : Geometry(CYLINDER), radius(radius), length(length) {}

Cylinder *Cylinder::clone() const { return new Cylinder(*this); }

void Cylinder::getPoints(Matrix3Xd &points) const {
  static bool warnOnce = true;
  if (warnOnce) {
    std::cerr << "Warning: DrakeShapes::Cylinder::getPoints(): """
        "This method returns the vertices of the cylinder''s bounding-box."
         << std::endl;
    warnOnce = false;
  }

  getBoundingBoxPoints(points);
}

void Cylinder::getBoundingBoxPoints(Matrix3Xd &points) const {
  Geometry::getBoundingBoxPoints(radius, radius, length / 2.0, points);
}

std::ostream &operator<<(std::ostream &out, const Cylinder &cc) {
  out << static_cast<const Geometry &>(cc) << ", " << cc.radius << ", "
      << cc.length;
  return out;
}

Capsule::Capsule(double radius, double length)
    : Geometry(CAPSULE), radius(radius), length(length) {}

Capsule *Capsule::clone() const { return new Capsule(*this); }

void Capsule::getPoints(Matrix3Xd &points) const {
  // Return segment end-points
  points.resize(Eigen::NoChange, NUM_POINTS);
  RowVectorXd cx = RowVectorXd::Zero(NUM_POINTS);
  RowVectorXd cy = RowVectorXd::Zero(NUM_POINTS);
  RowVectorXd cz = RowVectorXd::Zero(NUM_POINTS);
  cz << length / 2.0, -length / 2.0;

  points << cx, cy, cz;
}

void Capsule::getBoundingBoxPoints(Matrix3Xd &points) const {
  Geometry::getBoundingBoxPoints(radius, radius, (length / 2.0 + radius),
                                 points);
}

std::ostream &operator<<(std::ostream &out, const Capsule &cc) {
  out << static_cast<const Geometry &>(cc) << ", " << cc.radius << ", "
      << cc.length;
  return out;
}

Mesh::Mesh(const string &filename)
    : Geometry(MESH), scale(1.0, 1.0, 1.0), filename(filename) {}

Mesh::Mesh(const string &filename, const string &resolved_filename)
    : Geometry(MESH),
      scale(1.0, 1.0, 1.0),
      filename(filename),
      resolved_filename(resolved_filename) {}

bool Mesh::extractMeshVertices(Matrix3Xd &vertex_coordinates) const {
  if (resolved_filename.empty()) {
    return false;
  }
  spruce::path spath(resolved_filename);
  string ext = spath.extension();
  std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);

  ifstream file;
  if (ext.compare(".obj") == 0) {
    file.open(spath.getStr().c_str(), ifstream::in);
  } else {
    spath.setExtension(".obj");

    if (spath.exists()) {
      // try changing the extension to obj and loading.
      file.open(spath.getStr().c_str(), ifstream::in);
    }
  }

  if (!file.is_open()) {
    std::cerr << "Warning: Mesh " << spath.getStr()
         << " ignored because it does not have extension .obj (nor can I find "
            "a juxtaposed file with a .obj extension)"
         << std::endl;
    return false;
  }

  string line;
  // Count the number of vertices and resize vertex_coordinates.
  int num_vertices = 0;
  while (getline(file, line)) {
    istringstream iss(line);
    string type;
    if (iss >> type && type == "v") {
      ++num_vertices;
    }
  }
  vertex_coordinates.resize(3, num_vertices);

  file.clear();
  file.seekg(0, file.beg);

  double d;
  int j = 0;
  while (getline(file, line)) {
    istringstream iss(line);
    string type;
    if (iss >> type && type == "v") {
      int i = 0;
      while (iss >> d) {
        vertex_coordinates(i++, j) = d;
      }
      ++j;
    }
  }
  return true;
}

bool Mesh::ReadMeshConnectivities(Matrix3Xi& connectivities) const {
  if (resolved_filename.empty()) return false;

  spruce::path spath(resolved_filename);
  string ext = spath.extension();
  std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);

  FILE* file;
  if (ext.compare(".obj") == 0) {
    file = fopen(spath.getStr().c_str(), "r");
    if (!file) throw std::runtime_error(
          "Could not open mesh file \"" + spath.getStr() + "\".");
  } else {
    // Tries to change the extension to obj and load.
    spath.setExtension(".obj");
    if (spath.exists()) {
      file = fopen(spath.getStr().c_str(), "r");
      if (!file) throw std::runtime_error(
            "Could not open mesh file \"" + spath.getStr() + "\".");
    } else {
      throw std::runtime_error(
          "Could not find and obj file mesh file in the same directory as \"" +
              spath.getStr() + "\".");
    }
  }

  // Counts the number of triangles and resizes connectivities.
  int num_triangles = 0;
  char *line = NULL;
  size_t len = 0;
  ssize_t read;
  char key[128];
  while ((read = getline(&line, &len, file)) != -1) {
    sscanf(line, "%s", key);
    if (strcmp(key, "f") == 0) ++num_triangles;
  }

  // Allocates memory.
  connectivities.resize(3, num_triangles);

  // Reads triangles.
  // This simple parser assumes connectivities are in the obj format variant in
  // which indexes for both triangles and normals are provided.
  // TODO(amcastro-tri): use a library to parse obj files instead.
  rewind(file);
  int itri = 0;
  int ignored_entry;
  int tri[3];
  while (true) {
    // Get first word in the line.
    if (fscanf(file, "%s", key) == EOF) break;
    if (strcmp(key, "f") == 0) {
      int matches = fscanf(file,
                           "%d//%d %d//%d %d//%d\n",
                           tri + 0,
                           &ignored_entry,
                           tri + 1,
                           &ignored_entry,
                           tri + 2,
                           &ignored_entry);
      if (matches != 6)
        throw std::logic_error(
            "File \""+filename+"\" cannot be parsed. Format not supported.");
      connectivities.col(itri++) = Vector3i(tri[0]-1, tri[1]-1, tri[2]-1);
      if (itri > num_triangles)
        throw(std::logic_error("Number of triangles exceeded previous count."));
    }
  }  // while
  fclose(file);

  return true;
}

Mesh *Mesh::clone() const { return new Mesh(*this); }

void Mesh::getPoints(Eigen::Matrix3Xd &point_matrix) const {
  extractMeshVertices(point_matrix);
}

void Mesh::getBoundingBoxPoints(Matrix3Xd &bbox_points) const {
  Matrix3Xd mesh_vertices;
  extractMeshVertices(mesh_vertices);

  Vector3d min_pos = mesh_vertices.rowwise().minCoeff();
  Vector3d max_pos = mesh_vertices.rowwise().maxCoeff();

  bbox_points.resize(Eigen::NoChange, NUM_BBOX_POINTS);
  bbox_points << min_pos(0), min_pos(0), min_pos(0), min_pos(0), max_pos(0),
      max_pos(0), max_pos(0), max_pos(0), min_pos(1), min_pos(1), max_pos(1),
      max_pos(1), min_pos(1), min_pos(1), max_pos(1), max_pos(1), min_pos(2),
      max_pos(2), min_pos(2), max_pos(2), min_pos(2), max_pos(2), min_pos(2),
      max_pos(2);
}

std::ostream &operator<<(std::ostream &out, const Mesh &mm) {
  out << static_cast<const Geometry &>(mm) << ", " << mm.scale << ", "
      << mm.filename << ", " << mm.resolved_filename << ", " << mm.root_dir;
  return out;
}

MeshPoints::MeshPoints(const Eigen::Matrix3Xd &points)
    : Geometry(MESH_POINTS), points(points) {}

MeshPoints *MeshPoints::clone() const { return new MeshPoints(*this); }

void MeshPoints::getPoints(Eigen::Matrix3Xd &point_matrix) const {
  point_matrix = points;
}

void MeshPoints::getBoundingBoxPoints(Matrix3Xd &bbox_points) const {
  Vector3d min_pos = points.rowwise().minCoeff();
  Vector3d max_pos = points.rowwise().maxCoeff();

  bbox_points.resize(Eigen::NoChange, NUM_BBOX_POINTS);
  bbox_points << min_pos(0), min_pos(0), min_pos(0), min_pos(0), max_pos(0),
      max_pos(0), max_pos(0), max_pos(0), min_pos(1), min_pos(1), max_pos(1),
      max_pos(1), min_pos(1), min_pos(1), max_pos(1), max_pos(1), min_pos(2),
      max_pos(2), min_pos(2), max_pos(2), min_pos(2), max_pos(2), min_pos(2),
      max_pos(2);
}

std::ostream &operator<<(std::ostream &out, const MeshPoints &mp) {
  out << static_cast<const Geometry &>(mp) << ",\n" << mp.points;
  return out;
}

}  // namespace DrakeShapes
<|endoftext|>


<commit_before>// BaseDisplay.hh for Fluxbox Window Manager
// Copyright (c) 2001 - 2002 Henrik Kinnunen (fluxgen@linuxmail.org)
//
// BaseDisplay.hh for Blackbox - an X11 Window manager
// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.	IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// $Id: BaseDisplay.hh,v 1.28 2002/08/30 13:09:24 fluxgen Exp $

#ifndef	 BASEDISPLAY_HH
#define	 BASEDISPLAY_HH

#include "NotCopyable.hh"
#include "EventHandler.hh"

#include <X11/Xlib.h>

#ifdef XINERAMA
extern	"C" {
#include <X11/extensions/Xinerama.h>
}
#endif // XINERAMA

#include <list>
#include <vector>

// forward declaration
class ScreenInfo;

#define PropBlackboxHintsElements		(5)
#define PropBlackboxAttributesElements	(8)

/// obsolete
void bexec(const char *command, char *displaystring);
/**
	Singleton class to manage display connection
*/
class BaseDisplay:private NotCopyable, FbTk::EventHandler<XEvent>
{
public:
	BaseDisplay(const char *app_name, const char *display_name = 0);
	virtual ~BaseDisplay();
	static BaseDisplay *instance();

	/**
		obsolete
		@see FluxboxWindow
	*/
	enum Attrib {
		ATTRIB_SHADED = 0x01,
		ATTRIB_MAXHORIZ = 0x02,
		ATTRIB_MAXVERT = 0x04,
		ATTRIB_OMNIPRESENT = 0x08,
		ATTRIB_WORKSPACE = 0x10,
		ATTRIB_STACK = 0x20,
		ATTRIB_DECORATION = 0x40
	};

	typedef struct _blackbox_hints {
		unsigned long flags, attrib, workspace, stack;
		int decoration;
	} BlackboxHints;

	typedef struct _blackbox_attributes {
		unsigned long flags, attrib, workspace, stack;
		int premax_x, premax_y;
		unsigned int premax_w, premax_h;
	} BlackboxAttributes;

	inline ScreenInfo *getScreenInfo(int s)	{ return screenInfoList[s]; }

	inline bool hasShapeExtensions() const { return shape.extensions; }
	inline bool doShutdown() const { return m_shutdown; }
	inline bool isStartup() const { return m_startup; }

	static Display *getXDisplay() { return s_display; }

	inline const char *getXDisplayName() const	{ return m_display_name; }
	inline const char *getApplicationName() const { return m_app_name; }

	inline int getNumberOfScreens() const { return number_of_screens; }
	inline int getShapeEventBase() const { return shape.event_basep; }

	inline void shutdown() { m_shutdown = true; }
	inline void run() { m_startup = m_shutdown = false; }

	bool validateWindow(Window);

	void grab();
	void ungrab();
	void eventLoop();

private:

	struct shape {
		Bool extensions;
		int event_basep, error_basep;
	} shape;

	bool m_startup, m_shutdown;
	static Display *s_display;

    typedef std::vector<ScreenInfo *> ScreenInfoList;
    ScreenInfoList screenInfoList;

	const char *m_display_name, *m_app_name;
	int number_of_screens, m_server_grabs;

	static BaseDisplay *s_singleton;
};

class ScreenInfo {
public:
	ScreenInfo(BaseDisplay *bdisp, int screen_num);
	~ScreenInfo();

	inline BaseDisplay *getBaseDisplay() { return basedisplay; }

	inline Visual *getVisual() { return visual; }
	inline const Window &getRootWindow() const { return root_window; }
	inline const Colormap &colormap() const { return m_colormap; }

	inline int getDepth() const { return depth; }
	inline int getScreenNumber() const { return screen_number; }

	inline unsigned int getWidth() const { return width; }
	inline unsigned int getHeight() const { return height; }

#ifdef XINERAMA
	inline bool hasXinerama() const { return m_hasXinerama; }
	inline int getNumHeads() const { return xineramaNumHeads; }
	unsigned int getHead(int x, int y) const;
	unsigned int getCurrHead() const;
	unsigned int getHeadWidth(unsigned int head) const;
	unsigned int getHeadHeight(unsigned int head) const;
	int getHeadX(unsigned int head) const;
	int getHeadY(unsigned int head) const;
#endif // XINERAMA

private:
	BaseDisplay *basedisplay;
	Visual *visual;
	Window root_window;
	Colormap m_colormap;

	int depth, screen_number;
	unsigned int width, height;
#ifdef XINERAMA
	bool m_hasXinerama;
	int xineramaMajor, xineramaMinor, xineramaNumHeads, xineramaLastHead;
	XineramaScreenInfo *xineramaInfos;
#endif // XINERAMA

};

#endif // BASEDISPLAY_HH
<commit_msg>const and ref<commit_after>// BaseDisplay.hh for Fluxbox Window Manager
// Copyright (c) 2001 - 2002 Henrik Kinnunen (fluxgen@linuxmail.org)
//
// BaseDisplay.hh for Blackbox - an X11 Window manager
// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.	IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// $Id: BaseDisplay.hh,v 1.29 2002/09/08 19:12:33 fluxgen Exp $

#ifndef	 BASEDISPLAY_HH
#define	 BASEDISPLAY_HH

#include "NotCopyable.hh"
#include "EventHandler.hh"

#include <X11/Xlib.h>

#ifdef XINERAMA
extern	"C" {
#include <X11/extensions/Xinerama.h>
}
#endif // XINERAMA

#include <list>
#include <vector>

// forward declaration
class ScreenInfo;

#define PropBlackboxHintsElements		(5)
#define PropBlackboxAttributesElements	(8)

/// obsolete
void bexec(const char *command, char *displaystring);
/**
	Singleton class to manage display connection
*/
class BaseDisplay:private NotCopyable, FbTk::EventHandler<XEvent>
{
public:
	BaseDisplay(const char *app_name, const char *display_name = 0);
	virtual ~BaseDisplay();
	static BaseDisplay *instance();

	/**
		obsolete
		@see FluxboxWindow
	*/
	enum Attrib {
		ATTRIB_SHADED = 0x01,
		ATTRIB_MAXHORIZ = 0x02,
		ATTRIB_MAXVERT = 0x04,
		ATTRIB_OMNIPRESENT = 0x08,
		ATTRIB_WORKSPACE = 0x10,
		ATTRIB_STACK = 0x20,
		ATTRIB_DECORATION = 0x40
	};

	typedef struct _blackbox_hints {
		unsigned long flags, attrib, workspace, stack;
		int decoration;
	} BlackboxHints;

	typedef struct _blackbox_attributes {
		unsigned long flags, attrib, workspace, stack;
		int premax_x, premax_y;
		unsigned int premax_w, premax_h;
	} BlackboxAttributes;

	inline ScreenInfo *getScreenInfo(int s)	{ return screenInfoList[s]; }

	inline bool hasShapeExtensions() const { return shape.extensions; }
	inline bool doShutdown() const { return m_shutdown; }
	inline bool isStartup() const { return m_startup; }

	static Display *getXDisplay() { return s_display; }

	inline const char *getXDisplayName() const	{ return m_display_name; }
	inline const char *getApplicationName() const { return m_app_name; }

	inline int getNumberOfScreens() const { return number_of_screens; }
	inline int getShapeEventBase() const { return shape.event_basep; }

	inline void shutdown() { m_shutdown = true; }
	inline void run() { m_startup = m_shutdown = false; }

	bool validateWindow(Window);

	void grab();
	void ungrab();
	void eventLoop();

private:

	struct shape {
		Bool extensions;
		int event_basep, error_basep;
	} shape;

	bool m_startup, m_shutdown;
	static Display *s_display;

    typedef std::vector<ScreenInfo *> ScreenInfoList;
    ScreenInfoList screenInfoList;

	const char *m_display_name, *m_app_name;
	int number_of_screens, m_server_grabs;

	static BaseDisplay *s_singleton;
};

class ScreenInfo {
public:
	ScreenInfo(BaseDisplay *bdisp, int screen_num);
	~ScreenInfo();

	inline BaseDisplay *getBaseDisplay() { return basedisplay; }

	inline Visual *getVisual() const { return visual; }
	inline Window getRootWindow() const { return root_window; }
	inline Colormap colormap() const { return m_colormap; }

	inline int getDepth() const { return depth; }
	inline int getScreenNumber() const { return screen_number; }

	inline unsigned int getWidth() const { return width; }
	inline unsigned int getHeight() const { return height; }

#ifdef XINERAMA
	inline bool hasXinerama() const { return m_hasXinerama; }
	inline int getNumHeads() const { return xineramaNumHeads; }
	unsigned int getHead(int x, int y) const;
	unsigned int getCurrHead() const;
	unsigned int getHeadWidth(unsigned int head) const;
	unsigned int getHeadHeight(unsigned int head) const;
	int getHeadX(unsigned int head) const;
	int getHeadY(unsigned int head) const;
#endif // XINERAMA

private:
	BaseDisplay *basedisplay;
	Visual *visual;
	Window root_window;
	Colormap m_colormap;

	int depth, screen_number;
	unsigned int width, height;
#ifdef XINERAMA
	bool m_hasXinerama;
	int xineramaMajor, xineramaMinor, xineramaNumHeads, xineramaLastHead;
	XineramaScreenInfo *xineramaInfos;
#endif // XINERAMA

};

#endif // BASEDISPLAY_HH
<|endoftext|>


<commit_before>#include <cstdio>

int main(){
    int j, n, p[5], i[5], pi = 0, ii = 0;
    while(scanf("%d", &n) != EOF){
        if (n % 2 == 0){
            p[pi] = n;
            pi++;
        } else {
            i[ii] = n;
            ii++;
        }

        if (pi == 5){
            for (j = 0; j <= 4; j++) printf("par[%d] = %d\n", j, p[j]);
            for (j = 0; j <= 4; j++) p[j] = NULL;
            pi = 0;
        }
        if (ii == 5){
            for (j = 0; j <= 4; j++) printf("impar[%d] = %d\n", j, i[j]);
            for (j = 0; j <= 4; j++) i[j] = NULL;
            ii = 0;
        }
    }
    for (j = 0; j <= 4; j++){
        if (i[j] == NULL)
            break;
        printf("impar[%d] = %d\n", j, i[j]);
    }
    for (j = 0; j <= 4; j++){
        if (p[j] == NULL)
            break;
        printf("par[%d] = %d\n", j, p[j]);
    }
    return 0;
}
<commit_msg>Refatorando 1179.<commit_after>#include <cstdio>

int main(){
    int j, n, p[5], i[5], pi = 0, ii = 0;
    while(scanf("%d", &n) != EOF){
        if (n % 2 == 0){
            p[pi] = n;
            pi++;
        } else {
            i[ii] = n;
            ii++;
        }

        if (pi == 5){
            for (j = 0; j <= 4; j++){
                printf("par[%d] = %d\n", j, p[j]);
                p[j] = NULL;
            }
            pi = 0;
        }
        if (ii == 5){
            for (j = 0; j <= 4; j++){
                printf("impar[%d] = %d\n", j, i[j]);
                i[j] = NULL;
            }
            ii = 0;
        }
    }
    for (j = 0; j <= 4; j++){
        if (i[j] == NULL)
            break;
        printf("impar[%d] = %d\n", j, i[j]);
    }
    for (j = 0; j <= 4; j++){
        if (p[j] == NULL)
            break;
        printf("par[%d] = %d\n", j, p[j]);
    }
    return 0;
}
<|endoftext|>


<commit_before>// testForces.cpp
// Author:  Ajay Seth
/*
* Copyright (c) 2005-2010, Stanford University. All rights reserved.
* Use of the OpenSim software in source form is permitted provided that the following
* conditions are met:
* 	1. The software is used only for non-commercial research and education. It may not
*     be used in relation to any commercial activity.
* 	2. The software is not distributed or redistributed.  Software distribution is allowed
*     only through https://simtk.org/home/opensim.
* 	3. Use of the OpenSim software or derivatives must be acknowledged in all publications,
*      presentations, or documents describing work in which OpenSim or derivatives are used.
* 	4. Credits to developers may not be removed from executables
*     created from modifications of the source.
* 	5. Modifications of source code must retain the above copyright notice, this list of
*     conditions and the following disclaimer.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
*  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
*  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
*  SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
*  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
*  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
*  OR BUSINESS INTERRUPTION) OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
*  WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//==========================================================================================================
//	testJoints builds OpenSim models using the OpenSim API and builds an equivalent
//  Simbody system using the Simbody API for each test case. A test fails if the
//  OpenSim and Simbody final states of the simulation are not equivelent (norm-err
//  less than 10x integration error tolerance)
//
//	Tests Include:
//      1. PointToPointSpring
//		2. BusingForce
//		3. ElasticFoundationForce
//
//     Add tests here as Forces are added to OpenSim
//
//==========================================================================================================
#include <OpenSim/OpenSim.h>

using namespace OpenSim;
using namespace SimTK;
using namespace std;

#define ASSERT(cond) {if (!(cond)) throw(exception());}
#define ASSERT_EQUAL(expected, found, tolerance) {double tol = std::max((tolerance), std::abs((expected)*(tolerance))); if ((found)<(expected)-(tol) || (found)>(expected)+(tol)) throw(exception());}

//==========================================================================================================
// Common Parameters for the simulations are just global.
const static double integ_accuracy = 1.0e-4;
const static double duration = 1.0;
const static Vec3 gravity_vec = Vec3(0, -9.8065, 0);

//==========================================================================================================
static int counter=0;
//==========================================================================================================
// Test Cases
//==========================================================================================================
int testSpringMass()
{

	double mass = 1;
	double stiffness = 10;
	double restlength = 1.0;
	double h0 = 0;
	double start_h = 0.5;
	double ball_radius = 0.25;

	double omega = sqrt(stiffness/mass);

	double dh = mass*gravity_vec(1)/stiffness;

	// Setup OpenSim model
	Model *osimModel = new Model;
	osimModel->setName("SpringMass");
	//OpenSim bodies
    OpenSim::Body& ground = osimModel->getGroundBody();
	OpenSim::Body ball("ball", mass ,Vec3(0),  mass*SimTK::Inertia::sphere(0.1));
	ball.addDisplayGeometry("sphere.vtp");
	ball.scale(Vec3(ball_radius), false);

	// Add joints
	SliderJoint slider("", ground, Vec3(0), Vec3(0,0,Pi/2), ball, Vec3(0), Vec3(0,0,Pi/2));

	double positionRange[2] = {-10, 10};
	// Rename coordinates for a slider joint
	CoordinateSet &slider_coords = slider.getCoordinateSet();
	slider_coords[0].setName("ball_h");
	slider_coords[0].setRange(positionRange);
	slider_coords[0].setMotionType(Coordinate::Translational);

	osimModel->addBody(&ball);

	// BAD: have to set memoryOwner to false or program will crash when this test is complete.
	osimModel->updBodySet().setMemoryOwner(false);

	osimModel->setGravity(gravity_vec);

	PointToPointSpring spring("ground", Vec3(0,restlength,0), "ball", Vec3(0), stiffness, restlength);

	osimModel->addForce(&spring);

	//osimModel->print("SpringMassModel.osim");

	// Create the force reporter
	ForceReporter* reporter = new ForceReporter(osimModel);
	osimModel->addAnalysis(reporter);

	SimTK::State osim_state = osimModel->initSystem();

	slider_coords[0].setValue(osim_state, start_h);
    osimModel->getSystem().realize(osim_state, Stage::Position );

	//==========================================================================================================
	// Compute the force and torque at the specified times.

    RungeKuttaMersonIntegrator integrator(osimModel->getSystem() );
	integrator.setAccuracy(1e-6);
    Manager manager(*osimModel,  integrator);
    manager.setInitialTime(0.0);

	double final_t = 2.0;
	double nsteps = 10;
	double dt = final_t/nsteps;

	for(int i = 1; i <=nsteps; i++){
		manager.setFinalTime(dt*i);
		manager.integrate(osim_state);
		osimModel->getSystem().realize(osim_state, Stage::Acceleration);
        Vec3 pos;
        osimModel->updSimbodyEngine().getPosition(osim_state, ball, Vec3(0), pos);

		double height = (start_h-dh)*cos(omega*osim_state.getTime())+dh;
		ASSERT_EQUAL(height, pos(1), 1e-5);

		//Now check that the force reported by spring
		Array<double> model_force = spring.getRecordValues(osim_state);

		// get the forces applied to the ground and ball
		double analytical_force = -stiffness*height;
		// analytical force corresponds in direction to the force on the ball Y index = 7
		ASSERT_EQUAL(analytical_force, model_force[7], 1e-4);

		manager.setInitialTime(dt*i);
	}

	// Save the forces
	//reporter->getForceStorage().print("spring_mass_forces.mot");

	// Before exiting lets see if copying the spring works
	PointToPointSpring *copyOfSpring = (PointToPointSpring *)spring.copy();

	bool isEqual = (*copyOfSpring == spring);
	ASSERT(isEqual);

	return 0;
}

int testBushingForce()
{

	double mass = 1;
	double stiffness = 10;
	double restlength = 0.0;
	double h0 = 0;
	double start_h = 0.5;
	double ball_radius = 0.25;

	double omega = sqrt(stiffness/mass);

	double dh = mass*gravity_vec(1)/stiffness;

	// Setup OpenSim model
	Model *osimModel = new Model;
	osimModel->setName("BushingTest");
	//OpenSim bodies
    OpenSim::Body& ground = osimModel->getGroundBody();
	OpenSim::Body ball("ball", mass ,Vec3(0),  mass*SimTK::Inertia::sphere(0.1));
	ball.addDisplayGeometry("sphere.vtp");
	ball.scale(Vec3(ball_radius), false);

	// Add joints
	SliderJoint slider("", ground, Vec3(0), Vec3(0,0,Pi/2), ball, Vec3(0), Vec3(0,0,Pi/2));

	double positionRange[2] = {-10, 10};
	// Rename coordinates for a slider joint
	CoordinateSet &slider_coords = slider.getCoordinateSet();
	slider_coords[0].setName("ball_h");
	slider_coords[0].setRange(positionRange);
	slider_coords[0].setMotionType(Coordinate::Translational);

	osimModel->addBody(&ball);

	// BAD: have to set memoryOwner to false or program will crash when this test is complete.
	osimModel->updBodySet().setMemoryOwner(false);

	Vec3 rotStiffness(0);
	Vec3 transStiffness(stiffness);
	Vec3 rotDamping(0);
	Vec3 transDamping(0);

	osimModel->setGravity(gravity_vec);

	BushingForce spring("ground", Vec3(0), Vec3(0), "ball", Vec3(0), Vec3(0), transStiffness, rotStiffness, transDamping, rotDamping);

	osimModel->addForce(&spring);

	osimModel->print("BushingForceModel.osim");

	// Create the force reporter
	ForceReporter* reporter = new ForceReporter(osimModel);
	osimModel->addAnalysis(reporter);

	SimTK::State &osim_state = osimModel->initSystem();

	slider_coords[0].setValue(osim_state, start_h);
    osimModel->getSystem().realize(osim_state, Stage::Position );

	//==========================================================================================================
	// Compute the force and torque at the specified times.

    RungeKuttaMersonIntegrator integrator(osimModel->getSystem() );
	integrator.setAccuracy(1e-6);
    Manager manager(*osimModel,  integrator);
    manager.setInitialTime(0.0);

	double final_t = 2.0;
	double nsteps = 10;
	double dt = final_t/nsteps;

	for(int i = 1; i <=nsteps; i++){
		manager.setFinalTime(dt*i);
		manager.integrate(osim_state);
		osimModel->getSystem().realize(osim_state, Stage::Acceleration);
        Vec3 pos;
        osimModel->updSimbodyEngine().getPosition(osim_state, ball, Vec3(0), pos);

		double height = (start_h-dh)*cos(omega*osim_state.getTime())+dh;
		ASSERT_EQUAL(height, pos(1), 1e-4);

		//Now check that the force reported by spring
		Array<double> model_force = spring.getRecordValues(osim_state);

		// get the forces applied to the ground and ball
		double analytical_force = -stiffness*height;
		// analytical force corresponds in direction to the force on the ball Y index = 7
		ASSERT_EQUAL(analytical_force, model_force[7], 1e-4);

		manager.setInitialTime(dt*i);
	}

	manager.getStateStorage().print("bushing_model_states.sto");

	// Save the forces
	reporter->getForceStorage().print("bushing_forces.mot");

	// Before exiting lets see if copying the spring works
	BushingForce *copyOfSpring = (BushingForce *)spring.copy();

	bool isEqual = (*copyOfSpring == spring);
	ASSERT(isEqual);

	return 0;
}

// Test our wraapping of elastic foundation in OpenSim
// Simple simulation of bouncing ball with dissipation should generate contact
// forces that settle to ball weight.
int testElasticFoundation()
{
	double start_h = 0.5;

	// Setup OpenSim model
	Model *osimModel = new Model("BouncingBallModel.osim");

	// Create the force reporter
	ForceReporter* reporter = new ForceReporter(osimModel);
	osimModel->addAnalysis(reporter);

	SimTK::State osim_state = osimModel->initSystem();

	osimModel->getCoordinateSet()[4].setValue(osim_state, start_h);
    osimModel->getSystem().realize(osim_state, Stage::Position );

	const OpenSim::Body &ball = osimModel->getBodySet().get("ball");

	//==========================================================================================================
	// Compute the force and torque at the specified times.

    RungeKuttaMersonIntegrator integrator(osimModel->getSystem() );
	integrator.setAccuracy(1e-6);
    Manager manager(*osimModel,  integrator);
    manager.setInitialTime(0.0);

	double final_t = 2.0;

	manager.setFinalTime(final_t);
	manager.integrate(osim_state);
	//make sure we can access dynamic variables
	osimModel->getSystem().realize(osim_state, Stage::Acceleration);

	// Print out the motion for visualizing/debugging
	//manager.getStateStorage().print("bouncing_ball_states.sto");

	// Save the forces
	//reporter->getForceStorage().print("elastic_contact_forces.mot");

	// Bouncing ball should have settled to rest on groun due to dissipation
	// In that case the force generated by contact should be identically body weight
	// in vertical and zero else where.
	OpenSim::ElasticFoundationForce &contact = (OpenSim::ElasticFoundationForce &)osimModel->getForceSet().get("contact");

	Array<double> contact_force = contact.getRecordValues(osim_state);
	ASSERT_EQUAL(contact_force[0], 0.0, 1e-4); // no horizontal force on the ball
	ASSERT_EQUAL(contact_force[1], -ball.getMass()*gravity_vec[1], 1e-3); // vertical is weight
	ASSERT_EQUAL(contact_force[2], 0.0, 1e-4); // no horizontal force on the ball
	ASSERT_EQUAL(contact_force[3], 0.0, 1e-4); // no torque on the ball
	ASSERT_EQUAL(contact_force[4], 0.0, 1e-4); // no torque on the ball
	ASSERT_EQUAL(contact_force[5], 0.0, 1e-4); // no torque on the ball

	// Before exiting lets see if copying the spring works
	OpenSim::ElasticFoundationForce *copyOfForce = (OpenSim::ElasticFoundationForce *)contact.copy();

	bool isEqual = (*copyOfForce == contact);

	if(!isEqual){
		contact.print("originalForce.xml");
		copyOfForce->print("copyOfForce.xml");
	}

	ASSERT(isEqual);

	return 0;
}

int main()
{
	testSpringMass();
	cout << "spring passed"  << endl;
	testBushingForce();
	cout << "bushing passed"  << endl;
	testElasticFoundation();
	cout << "elastic foundation force passed"  << endl;

	return 0;
}
<commit_msg>Dissipation on bouncing ball test case for ElasticFoundationForce force was updated to reflect SimTK side changes to underlying equations.<commit_after>// testForces.cpp
// Author:  Ajay Seth
/*
* Copyright (c) 2005-2010, Stanford University. All rights reserved.
* Use of the OpenSim software in source form is permitted provided that the following
* conditions are met:
* 	1. The software is used only for non-commercial research and education. It may not
*     be used in relation to any commercial activity.
* 	2. The software is not distributed or redistributed.  Software distribution is allowed
*     only through https://simtk.org/home/opensim.
* 	3. Use of the OpenSim software or derivatives must be acknowledged in all publications,
*      presentations, or documents describing work in which OpenSim or derivatives are used.
* 	4. Credits to developers may not be removed from executables
*     created from modifications of the source.
* 	5. Modifications of source code must retain the above copyright notice, this list of
*     conditions and the following disclaimer.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
*  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
*  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
*  SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
*  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
*  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
*  OR BUSINESS INTERRUPTION) OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
*  WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//==========================================================================================================
//	testJoints builds OpenSim models using the OpenSim API and builds an equivalent
//  Simbody system using the Simbody API for each test case. A test fails if the
//  OpenSim and Simbody final states of the simulation are not equivelent (norm-err
//  less than 10x integration error tolerance)
//
//	Tests Include:
//      1. PointToPointSpring
//		2. BusingForce
//		3. ElasticFoundationForce
//
//     Add tests here as Forces are added to OpenSim
//
//==========================================================================================================
#include <OpenSim/OpenSim.h>

using namespace OpenSim;
using namespace SimTK;
using namespace std;

#define ASSERT(cond) {if (!(cond)) throw(exception());}
#define ASSERT_EQUAL(expected, found, tolerance) {double tol = std::max((tolerance), std::abs((expected)*(tolerance))); if ((found)<(expected)-(tol) || (found)>(expected)+(tol)) throw(exception());}

//==========================================================================================================
// Common Parameters for the simulations are just global.
const static double integ_accuracy = 1.0e-4;
const static double duration = 1.0;
const static Vec3 gravity_vec = Vec3(0, -9.8065, 0);

//==========================================================================================================
static int counter=0;
//==========================================================================================================
// Test Cases
//==========================================================================================================
int testSpringMass()
{

	double mass = 1;
	double stiffness = 10;
	double restlength = 1.0;
	double h0 = 0;
	double start_h = 0.5;
	double ball_radius = 0.25;

	double omega = sqrt(stiffness/mass);

	double dh = mass*gravity_vec(1)/stiffness;

	// Setup OpenSim model
	Model *osimModel = new Model;
	osimModel->setName("SpringMass");
	//OpenSim bodies
    OpenSim::Body& ground = osimModel->getGroundBody();
	OpenSim::Body ball("ball", mass ,Vec3(0),  mass*SimTK::Inertia::sphere(0.1));
	ball.addDisplayGeometry("sphere.vtp");
	ball.scale(Vec3(ball_radius), false);

	// Add joints
	SliderJoint slider("", ground, Vec3(0), Vec3(0,0,Pi/2), ball, Vec3(0), Vec3(0,0,Pi/2));

	double positionRange[2] = {-10, 10};
	// Rename coordinates for a slider joint
	CoordinateSet &slider_coords = slider.getCoordinateSet();
	slider_coords[0].setName("ball_h");
	slider_coords[0].setRange(positionRange);
	slider_coords[0].setMotionType(Coordinate::Translational);

	osimModel->addBody(&ball);

	// BAD: have to set memoryOwner to false or program will crash when this test is complete.
	osimModel->updBodySet().setMemoryOwner(false);

	osimModel->setGravity(gravity_vec);

	PointToPointSpring spring("ground", Vec3(0,restlength,0), "ball", Vec3(0), stiffness, restlength);

	osimModel->addForce(&spring);

	//osimModel->print("SpringMassModel.osim");

	// Create the force reporter
	ForceReporter* reporter = new ForceReporter(osimModel);
	osimModel->addAnalysis(reporter);

	SimTK::State osim_state = osimModel->initSystem();

	slider_coords[0].setValue(osim_state, start_h);
    osimModel->getSystem().realize(osim_state, Stage::Position );

	//==========================================================================================================
	// Compute the force and torque at the specified times.

    RungeKuttaMersonIntegrator integrator(osimModel->getSystem() );
	integrator.setAccuracy(1e-6);
    Manager manager(*osimModel,  integrator);
    manager.setInitialTime(0.0);

	double final_t = 2.0;
	double nsteps = 10;
	double dt = final_t/nsteps;

	for(int i = 1; i <=nsteps; i++){
		manager.setFinalTime(dt*i);
		manager.integrate(osim_state);
		osimModel->getSystem().realize(osim_state, Stage::Acceleration);
        Vec3 pos;
        osimModel->updSimbodyEngine().getPosition(osim_state, ball, Vec3(0), pos);

		double height = (start_h-dh)*cos(omega*osim_state.getTime())+dh;
		ASSERT_EQUAL(height, pos(1), 1e-5);

		//Now check that the force reported by spring
		Array<double> model_force = spring.getRecordValues(osim_state);

		// get the forces applied to the ground and ball
		double analytical_force = -stiffness*height;
		// analytical force corresponds in direction to the force on the ball Y index = 7
		ASSERT_EQUAL(analytical_force, model_force[7], 1e-4);

		manager.setInitialTime(dt*i);
	}

	// Save the forces
	//reporter->getForceStorage().print("spring_mass_forces.mot");

	// Before exiting lets see if copying the spring works
	PointToPointSpring *copyOfSpring = (PointToPointSpring *)spring.copy();

	bool isEqual = (*copyOfSpring == spring);
	ASSERT(isEqual);

	return 0;
}

int testBushingForce()
{

	double mass = 1;
	double stiffness = 10;
	double restlength = 0.0;
	double h0 = 0;
	double start_h = 0.5;
	double ball_radius = 0.25;

	double omega = sqrt(stiffness/mass);

	double dh = mass*gravity_vec(1)/stiffness;

	// Setup OpenSim model
	Model *osimModel = new Model;
	osimModel->setName("BushingTest");
	//OpenSim bodies
    OpenSim::Body& ground = osimModel->getGroundBody();
	OpenSim::Body ball("ball", mass ,Vec3(0),  mass*SimTK::Inertia::sphere(0.1));
	ball.addDisplayGeometry("sphere.vtp");
	ball.scale(Vec3(ball_radius), false);

	// Add joints
	SliderJoint slider("", ground, Vec3(0), Vec3(0,0,Pi/2), ball, Vec3(0), Vec3(0,0,Pi/2));

	double positionRange[2] = {-10, 10};
	// Rename coordinates for a slider joint
	CoordinateSet &slider_coords = slider.getCoordinateSet();
	slider_coords[0].setName("ball_h");
	slider_coords[0].setRange(positionRange);
	slider_coords[0].setMotionType(Coordinate::Translational);

	osimModel->addBody(&ball);

	// BAD: have to set memoryOwner to false or program will crash when this test is complete.
	osimModel->updBodySet().setMemoryOwner(false);

	Vec3 rotStiffness(0);
	Vec3 transStiffness(stiffness);
	Vec3 rotDamping(0);
	Vec3 transDamping(0);

	osimModel->setGravity(gravity_vec);

	BushingForce spring("ground", Vec3(0), Vec3(0), "ball", Vec3(0), Vec3(0), transStiffness, rotStiffness, transDamping, rotDamping);

	osimModel->addForce(&spring);

	osimModel->print("BushingForceModel.osim");

	// Create the force reporter
	ForceReporter* reporter = new ForceReporter(osimModel);
	osimModel->addAnalysis(reporter);

	SimTK::State &osim_state = osimModel->initSystem();

	slider_coords[0].setValue(osim_state, start_h);
    osimModel->getSystem().realize(osim_state, Stage::Position );

	//==========================================================================================================
	// Compute the force and torque at the specified times.

    RungeKuttaMersonIntegrator integrator(osimModel->getSystem() );
	integrator.setAccuracy(1e-6);
    Manager manager(*osimModel,  integrator);
    manager.setInitialTime(0.0);

	double final_t = 2.0;
	double nsteps = 10;
	double dt = final_t/nsteps;

	for(int i = 1; i <=nsteps; i++){
		manager.setFinalTime(dt*i);
		manager.integrate(osim_state);
		osimModel->getSystem().realize(osim_state, Stage::Acceleration);
        Vec3 pos;
        osimModel->updSimbodyEngine().getPosition(osim_state, ball, Vec3(0), pos);

		double height = (start_h-dh)*cos(omega*osim_state.getTime())+dh;
		ASSERT_EQUAL(height, pos(1), 1e-4);

		//Now check that the force reported by spring
		Array<double> model_force = spring.getRecordValues(osim_state);

		// get the forces applied to the ground and ball
		double analytical_force = -stiffness*height;
		// analytical force corresponds in direction to the force on the ball Y index = 7
		ASSERT_EQUAL(analytical_force, model_force[7], 1e-4);

		manager.setInitialTime(dt*i);
	}

	manager.getStateStorage().print("bushing_model_states.sto");

	// Save the forces
	reporter->getForceStorage().print("bushing_forces.mot");

	// Before exiting lets see if copying the spring works
	BushingForce *copyOfSpring = (BushingForce *)spring.copy();

	bool isEqual = (*copyOfSpring == spring);
	ASSERT(isEqual);

	return 0;
}

// Test our wraapping of elastic foundation in OpenSim
// Simple simulation of bouncing ball with dissipation should generate contact
// forces that settle to ball weight.
int testElasticFoundation()
{
	double start_h = 0.5;

	// Setup OpenSim model
	Model *osimModel = new Model("BouncingBallModel.osim");

	// Create the force reporter
	ForceReporter* reporter = new ForceReporter(osimModel);
	osimModel->addAnalysis(reporter);

	SimTK::State osim_state = osimModel->initSystem();

	osimModel->getCoordinateSet()[4].setValue(osim_state, start_h);
    osimModel->getSystem().realize(osim_state, Stage::Position );

	const OpenSim::Body &ball = osimModel->getBodySet().get("ball");

	//==========================================================================================================
	// Compute the force and torque at the specified times.

    RungeKuttaMersonIntegrator integrator(osimModel->getSystem() );
	integrator.setAccuracy(1e-6);
    Manager manager(*osimModel,  integrator);
    manager.setInitialTime(0.0);

	double final_t = 2.0;

	manager.setFinalTime(final_t);
	manager.integrate(osim_state);
	//make sure we can access dynamic variables
	osimModel->getSystem().realize(osim_state, Stage::Acceleration);

	// Print out the motion for visualizing/debugging
	manager.getStateStorage().print("bouncing_ball_states.sto");

	// Save the forces
	reporter->getForceStorage().print("elastic_contact_forces.mot");

	// Bouncing ball should have settled to rest on groun due to dissipation
	// In that case the force generated by contact should be identically body weight
	// in vertical and zero else where.
	OpenSim::ElasticFoundationForce &contact = (OpenSim::ElasticFoundationForce &)osimModel->getForceSet().get("contact");

	Array<double> contact_force = contact.getRecordValues(osim_state);
	ASSERT_EQUAL(contact_force[0], 0.0, 1e-4); // no horizontal force on the ball
	ASSERT_EQUAL(contact_force[1], -ball.getMass()*gravity_vec[1], 1e-3); // vertical is weight
	ASSERT_EQUAL(contact_force[2], 0.0, 1e-4); // no horizontal force on the ball
	ASSERT_EQUAL(contact_force[3], 0.0, 1e-4); // no torque on the ball
	ASSERT_EQUAL(contact_force[4], 0.0, 1e-4); // no torque on the ball
	ASSERT_EQUAL(contact_force[5], 0.0, 1e-4); // no torque on the ball

	// Before exiting lets see if copying the spring works
	OpenSim::ElasticFoundationForce *copyOfForce = (OpenSim::ElasticFoundationForce *)contact.copy();

	bool isEqual = (*copyOfForce == contact);

	if(!isEqual){
		contact.print("originalForce.xml");
		copyOfForce->print("copyOfForce.xml");
	}

	ASSERT(isEqual);

	return 0;
}

int main()
{
	testSpringMass();
	cout << "spring passed"  << endl;
	testBushingForce();
	cout << "bushing passed"  << endl;
	testElasticFoundation();
	cout << "elastic foundation force passed"  << endl;

	return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// NOTE: These tests are run as part of "unit_tests" (in chrome/test/unit)
// rather than as part of test_shell_tests because they rely on being able
// to instantiate a MessageLoop of type TYPE_IO.  test_shell_tests uses
// TYPE_UI, which URLRequest doesn't allow.
//

#include "webkit/fileapi/file_system_dir_url_request_job.h"

#include "build/build_config.h"

#include <string>

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/format_macros.h"
#include "base/message_loop.h"
#include "base/platform_file.h"
#include "base/scoped_temp_dir.h"
#include "base/string_piece.h"
#include "base/threading/thread.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/http/http_request_headers.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/fileapi/file_system_path_manager.h"

namespace fileapi {
namespace {

// We always use the TEMPORARY FileSystem in this test.
static const char kFileSystemURLPrefix[] = "filesystem:http://remote/temporary/";

class FileSystemDirURLRequestJobTest : public testing::Test {
 protected:
  FileSystemDirURLRequestJobTest()
    : message_loop_(MessageLoop::TYPE_IO),  // simulate an IO thread
      ALLOW_THIS_IN_INITIALIZER_LIST(callback_factory_(this)) {
  }

  virtual void SetUp() {
    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());

    // We use the main thread so that we can get the root path synchronously.
    // TODO(adamk): Run this on the FILE thread we've created as well.
    path_manager_.reset(new FileSystemPathManager(
        base::MessageLoopProxy::CreateForCurrentThread(),
        temp_dir_.path(), false, false));

    path_manager_->GetFileSystemRootPath(
        GURL("http://remote/"), kFileSystemTypeTemporary, true,  // create
        callback_factory_.NewCallback(
            &FileSystemDirURLRequestJobTest::OnGetRootPath));
    MessageLoop::current()->RunAllPending();

    file_thread_.reset(
        new base::Thread("FileSystemDirURLRequestJobTest FILE Thread"));
    base::Thread::Options options(MessageLoop::TYPE_IO, 0);
    file_thread_->StartWithOptions(options);

    net::URLRequest::RegisterProtocolFactory(
        "filesystem", &FileSystemDirURLRequestJobFactory);
  }

  virtual void TearDown() {
    // NOTE: order matters, request must die before delegate
    request_.reset(NULL);
    delegate_.reset(NULL);

    file_thread_.reset(NULL);
    net::URLRequest::RegisterProtocolFactory("filesystem", NULL);
  }

  void OnGetRootPath(bool success, const FilePath& root_path,
                     const std::string& name) {
    ASSERT_TRUE(success);
    root_path_ = root_path;
  }

  void TestRequest(const GURL& url) {
    delegate_.reset(new TestDelegate());
    delegate_->set_quit_on_redirect(true);
    request_.reset(new net::URLRequest(url, delegate_.get()));
    job_ = new FileSystemDirURLRequestJob(request_.get(), path_manager_.get(),
                                          file_thread_->message_loop_proxy());

    request_->Start();
    ASSERT_TRUE(request_->is_pending());  // verify that we're starting async
    MessageLoop::current()->Run();
  }

  void CreateDirectory(const base::StringPiece dir_name) {
    FilePath path = root_path_.AppendASCII(dir_name);
    ASSERT_TRUE(file_util::CreateDirectory(path));
  }

  GURL CreateFileSystemURL(const std::string path) {
    return GURL(kFileSystemURLPrefix + path);
  }

  static net::URLRequestJob* FileSystemDirURLRequestJobFactory(
      net::URLRequest* request,
      const std::string& scheme) {
    DCHECK(job_);
    net::URLRequestJob* temp = job_;
    job_ = NULL;
    return temp;
  }

  ScopedTempDir temp_dir_;
  FilePath root_path_;
  scoped_ptr<net::URLRequest> request_;
  scoped_ptr<TestDelegate> delegate_;
  scoped_ptr<FileSystemPathManager> path_manager_;
  scoped_ptr<base::Thread> file_thread_;

  MessageLoop message_loop_;
  base::ScopedCallbackFactory<FileSystemDirURLRequestJobTest> callback_factory_;

  static net::URLRequestJob* job_;
};

// static
net::URLRequestJob* FileSystemDirURLRequestJobTest::job_ = NULL;

// TODO(adamk): Write tighter tests once we've decided on a format for directory
// listing responses.
TEST_F(FileSystemDirURLRequestJobTest, DirectoryListing) {
  CreateDirectory("foo");
  CreateDirectory("foo/bar");
  CreateDirectory("foo/bar/baz");

  TestRequest(CreateFileSystemURL("foo/bar/"));

  ASSERT_FALSE(request_->is_pending());
  EXPECT_EQ(1, delegate_->response_started_count());
  EXPECT_FALSE(delegate_->received_data_before_response());
  EXPECT_GT(delegate_->bytes_received(), 0);
}

TEST_F(FileSystemDirURLRequestJobTest, InvalidURL) {
  TestRequest(GURL("filesystem:/foo/bar/baz"));
  ASSERT_FALSE(request_->is_pending());
  EXPECT_TRUE(delegate_->request_failed());
  ASSERT_FALSE(request_->status().is_success());
  EXPECT_EQ(net::ERR_INVALID_URL, request_->status().os_error());
}

TEST_F(FileSystemDirURLRequestJobTest, NoSuchRoot) {
  TestRequest(GURL("filesystem:http://remote/persistent/somedir/"));
  ASSERT_FALSE(request_->is_pending());
  ASSERT_FALSE(request_->status().is_success());
  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().os_error());
}

TEST_F(FileSystemDirURLRequestJobTest, NoSuchDirectory) {
  TestRequest(CreateFileSystemURL("somedir/"));
  ASSERT_FALSE(request_->is_pending());
  ASSERT_FALSE(request_->status().is_success());
  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, request_->status().os_error());
}

}  // namespace (anonymous)
}  // namespace fileapi
<commit_msg>Make FileSystemDirURLRequestJob test single-threaded in hopes of making it less flaky under Valgrind.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// NOTE: These tests are run as part of "unit_tests" (in chrome/test/unit)
// rather than as part of test_shell_tests because they rely on being able
// to instantiate a MessageLoop of type TYPE_IO.  test_shell_tests uses
// TYPE_UI, which URLRequest doesn't allow.
//

#include "webkit/fileapi/file_system_dir_url_request_job.h"

#include "build/build_config.h"

#include <string>

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/format_macros.h"
#include "base/message_loop.h"
#include "base/platform_file.h"
#include "base/scoped_temp_dir.h"
#include "base/string_piece.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/http/http_request_headers.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/fileapi/file_system_path_manager.h"

namespace fileapi {
namespace {

// We always use the TEMPORARY FileSystem in this test.
static const char kFileSystemURLPrefix[] = "filesystem:http://remote/temporary/";

class FileSystemDirURLRequestJobTest : public testing::Test {
 protected:
  FileSystemDirURLRequestJobTest()
    : message_loop_(MessageLoop::TYPE_IO),  // simulate an IO thread
      ALLOW_THIS_IN_INITIALIZER_LIST(callback_factory_(this)) {
  }

  virtual void SetUp() {
    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());

    file_thread_proxy_ = base::MessageLoopProxy::CreateForCurrentThread();

    path_manager_.reset(new FileSystemPathManager(
        file_thread_proxy_, temp_dir_.path(), false, false));

    path_manager_->GetFileSystemRootPath(
        GURL("http://remote/"), kFileSystemTypeTemporary, true,  // create
        callback_factory_.NewCallback(
            &FileSystemDirURLRequestJobTest::OnGetRootPath));
    MessageLoop::current()->RunAllPending();

    net::URLRequest::RegisterProtocolFactory(
        "filesystem", &FileSystemDirURLRequestJobFactory);
  }

  virtual void TearDown() {
    // NOTE: order matters, request must die before delegate
    request_.reset(NULL);
    delegate_.reset(NULL);

    net::URLRequest::RegisterProtocolFactory("filesystem", NULL);
  }

  void OnGetRootPath(bool success, const FilePath& root_path,
                     const std::string& name) {
    ASSERT_TRUE(success);
    root_path_ = root_path;
  }

  void TestRequest(const GURL& url) {
    delegate_.reset(new TestDelegate());
    delegate_->set_quit_on_redirect(true);
    request_.reset(new net::URLRequest(url, delegate_.get()));
    job_ = new FileSystemDirURLRequestJob(request_.get(),
                                          path_manager_.get(),
                                          file_thread_proxy_);

    request_->Start();
    ASSERT_TRUE(request_->is_pending());  // verify that we're starting async
    MessageLoop::current()->Run();
  }

  void CreateDirectory(const base::StringPiece dir_name) {
    FilePath path = root_path_.AppendASCII(dir_name);
    ASSERT_TRUE(file_util::CreateDirectory(path));
  }

  GURL CreateFileSystemURL(const std::string path) {
    return GURL(kFileSystemURLPrefix + path);
  }

  static net::URLRequestJob* FileSystemDirURLRequestJobFactory(
      net::URLRequest* request,
      const std::string& scheme) {
    DCHECK(job_);
    net::URLRequestJob* temp = job_;
    job_ = NULL;
    return temp;
  }

  ScopedTempDir temp_dir_;
  FilePath root_path_;
  scoped_ptr<net::URLRequest> request_;
  scoped_ptr<TestDelegate> delegate_;
  scoped_ptr<FileSystemPathManager> path_manager_;
  scoped_refptr<base::MessageLoopProxy> file_thread_proxy_;

  MessageLoop message_loop_;
  base::ScopedCallbackFactory<FileSystemDirURLRequestJobTest> callback_factory_;

  static net::URLRequestJob* job_;
};

// static
net::URLRequestJob* FileSystemDirURLRequestJobTest::job_ = NULL;

// TODO(adamk): Write tighter tests once we've decided on a format for directory
// listing responses.
TEST_F(FileSystemDirURLRequestJobTest, DirectoryListing) {
  CreateDirectory("foo");
  CreateDirectory("foo/bar");
  CreateDirectory("foo/bar/baz");

  TestRequest(CreateFileSystemURL("foo/bar/"));

  ASSERT_FALSE(request_->is_pending());
  EXPECT_EQ(1, delegate_->response_started_count());
  EXPECT_FALSE(delegate_->received_data_before_response());
  EXPECT_GT(delegate_->bytes_received(), 0);
}

TEST_F(FileSystemDirURLRequestJobTest, InvalidURL) {
  TestRequest(GURL("filesystem:/foo/bar/baz"));
  ASSERT_FALSE(request_->is_pending());
  EXPECT_TRUE(delegate_->request_failed());
  ASSERT_FALSE(request_->status().is_success());
  EXPECT_EQ(net::ERR_INVALID_URL, request_->status().os_error());
}

TEST_F(FileSystemDirURLRequestJobTest, NoSuchRoot) {
  TestRequest(GURL("filesystem:http://remote/persistent/somedir/"));
  ASSERT_FALSE(request_->is_pending());
  ASSERT_FALSE(request_->status().is_success());
  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().os_error());
}

TEST_F(FileSystemDirURLRequestJobTest, NoSuchDirectory) {
  TestRequest(CreateFileSystemURL("somedir/"));
  ASSERT_FALSE(request_->is_pending());
  ASSERT_FALSE(request_->status().is_success());
  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, request_->status().os_error());
}

}  // namespace (anonymous)
}  // namespace fileapi
<|endoftext|>


<commit_before>/*
| Yahtzee program                           |
| Written by Gabriel Simmer                 |
| I still don't know how to play yahtzee :P |
*/

#include <iostream>
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctime>

using namespace std;

int main()
{
    SetConsoleTitle("Console Yahtzee");
    cout << "Text Yahtzee" << endl;
    cout << "By Gabriel Simmer" << endl;
    /*
    | Set console title, and display needed info |
    */
    srand(time(0)); //Seed random numbers from time
    int dice1;
    int dice2;
    int dice3;
    int dice4;
    int dice5;
    int catones;
    int cattwos;
    int catthrees;
    int catfours;
    int catfives;
    int catsixes;
    int cattotal;
    int catbonus;
    int allowedtoroll1;
    int allowedtoroll2;
    int allowedtoroll3;
    int allowedtoroll4;
    int allowedtoroll5;
    int loopbreak;
    int canUsecatones = 0;
    int canUsecattwos = 0;
    int canUsecatthrees = 0;
    int canUsecatfours = 0;
    int canUsecatfives = 0;
    int canUsecatsixes = 0;
    int catlocked1 = 0;
    int catlocked2 = 0;
    int catlocked3 = 0;
    int catlocked4 = 0;
    int catlocked5 = 0;
    int catlocked6 = 0;
    loopbreak = 0;
    allowedtoroll1 = 0;
    allowedtoroll2 = 0;
    allowedtoroll3 = 0;
    allowedtoroll4 = 0;
    allowedtoroll5 = 0; //Declares all variables needed
    cout << "Rolling for round." << endl;
    //Random numbers occur here
    dice1 = (1 + rand() % 6);
    cout << dice1;
    cout << " ";
    dice2 = (1 + rand() % 6);
    cout << dice2;
    cout << " ";
    dice3 = (1 + rand() % 6);
    cout << dice3;
    cout << " ";
    dice4 = (1 + rand() % 6);
    cout << dice4;
    dice5 = (1 + rand() % 6);
    cout << " ";
    cout << dice5 << endl ;
    int rerolldice;
    while ( loopbreak != 1 ) {
        cout << "Reroll which dice?" << endl;
        cout << "Enter 8 to score current roll or 9 to continue to next round." << endl;
        cout << "Dice ";
        cin >> rerolldice; //Make new random numbers if dice is chosen, 9 is exit, 8 is calculate score
        if ( rerolldice == 1 ) {
                if ( allowedtoroll1 < 2 ) { //So that you can only roll twice
                    dice1 = (1 + rand() % 6 );
                    cout << "Dice One: ";
                    cout << dice1 << endl;
                    allowedtoroll1 = allowedtoroll1++;
            }
            else {
                cout << "You can not roll that dice any more." << endl;
                cout << " " << endl;
            }
        }
        if ( rerolldice == 2 ) {
                if ( allowedtoroll2 < 2 ) {
                    dice2 = ( 1 + rand() % 6 );
                    cout << "Dice Two: ";
                    cout << dice2 << endl;
                    allowedtoroll2 = allowedtoroll2++;
                }
            else {
                cout << "You can not roll that dice any more" << endl;
                cout << " " << endl;
            }
        }
        if ( rerolldice == 3 ) {
            if ( allowedtoroll3 < 2 ) {
                dice3 = ( 1 + rand() % 6 );
                cout << "Dice Three: ";
                cout << dice3 << endl;
                allowedtoroll3 = allowedtoroll3++;
            }
            else {
                cout << "You can not roll this dice any more" << endl;
                cout << " " << endl;
            }
        }
        if ( rerolldice == 4 ) {
            if ( allowedtoroll4 < 2 ) {
                dice4 = ( 1 + rand() % 6 );
                cout << "Dice Four: ";
                cout << dice4 << endl;
            }
        }
        if ( rerolldice == 5 ) {
            if ( allowedtoroll5 < 2 ) {
                dice5 = ( 1 + rand() % 6 );
                cout << "Dice Five: ";
                cout << dice5 << endl;
            }
            else {
                cout << "You can not roll this dice any more" << endl;
                cout << " " << endl;
            }
        }
        if ( rerolldice == 9 ) {
            exit (EXIT_SUCCESS);
        }
        if ( rerolldice == 8 ) {
            loopbreak = 1; //Breaks the loop
            cout << "Current numbers rolled:" << endl;
            cout << dice1;
            cout << " ";
            cout << dice2;
            cout << " ";
            cout << dice3;
            cout << " ";
            cout << dice4;
            cout << " ";
            cout << dice5;
            cout << " " << endl;
            cout << "Score to which category?" << endl;
            cout << "aces, twos, thress, fours, fives, or sixes?" << endl;
            string aces = "aces";
            string twos = "twos";
            string threes = "threes";
            string fours = "fours";
            string fives = "fives";
            string sixes = "sixes";
            string scoresect;
            cin >> scoresect; //Choice strings
            if ( scoresect == aces ) { //Thanks to Mr. Last for the help with the catagories!
                if ( canUsecatones == 0 ){
                    catones=0;
                    if (dice1==1) catones++;
                    if (dice2==1) catones++;
                    if (dice3==1) catones++;
                    if (dice4==1) catones++;
                    if (dice5==1) catones++;
                    cout << catones << endl;
                    canUsecatones++;
                }
                else if ( canUsecatones > 0 ){
                    cout << "You've already used that catagory!" << endl;
                }

            }
            else if ( scoresect == twos ) {
                if ( canUsecattwos == 0 ){
                    cattwos=0;
                    if (dice1==2) cattwos=cattwos+2;
                    if (dice2==2) cattwos=cattwos+2;
                    if (dice3==2) cattwos=cattwos+2;
                    if (dice4==2) cattwos=cattwos+2;
                    if (dice5==2) cattwos=cattwos+2;
                    cout << cattwos << endl;
                    canUsecattwos++;
                }
                else if ( canUsecattwos > 0 ){
                    cout << "You've already used this catagory!" << endl;
                }
            }
            if ( scoresect == threes ){
                if ( canUsecatthrees == 0 ){
                    catthrees=0;
                    if (dice1==3) catthrees=catthrees+3;
                    if (dice2==3) catthrees=catthrees+3;
                    if (dice3==3) catthrees=catthrees+3;
                    if (dice4==3) catthrees=catthrees+3;
                    if (dice5==3) catthrees=catthrees+3;
                    cout << catthrees << endl;
                    canUsecatthrees++;
                }
                else if ( canUsecatthrees > 0 ){
                    cout << "You've already used this catagory!" << endl;
                }
            }

            else if ( scoresect == fours ) {
                if ( canUsecatfours == 0 ){
                    catfours=0;
                    if (dice1==4) catfours=catfours+4;
                    if (dice2==4) catfours=catfours+4;
                    if (dice3==4) catfours=catfours+4;
                    if (dice4==4) catfours=catfours+4;
                    if (dice5==4) catfours=catfours+4;
                    cout << catfours << endl;
                    canUsecatfours++;
                }
                else if ( canUsecatfours > 0 ){
                    cout << "You've already used this catagory!" << endl;
                }
            }
            else if ( scoresect == fives ) {
                if ( canUsecatfives == 0 ){
                    if (dice1==5) catfives=catfives+5;
                    if (dice2==5) catfives=catfives+5;
                    if (dice3==5) catfives=catfives+5;
                    if (dice4==5) catfives=catfives+5;
                    if (dice5==5) catfives=catfives+5;
                    cout << catfives << endl;
                }
                else if ( canUsecatfives > 0 ){
                    cout << "You've already used this catagory!" << endl;
                }

            }
            else if ( scoresect == sixes ) {
                if ( canUsecatsixes == 0 ){
                    if (dice1==6) catsixes=catsixes+6;
                    if (dice2==6) catsixes=catsixes+6;
                    if (dice3==6) catsixes=catsixes+6;
                    if (dice4==6) catsixes=catsixes+6;
                    if (dice5==6) catsixes=catsixes+6;
            cout << catsixes << endl;
                }
            else if ( canUsecatsixes == 0 ){
                cout << "You've already used this catagory!" << endl;
                }
            }
        }
    }

    return 0;
}
<commit_msg>Broke sixes<commit_after>/*
| Yahtzee program                           |
| Written by Gabriel Simmer                 |
| I still don't know how to play yahtzee :P |
*/

#include <iostream>
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctime>

using namespace std;

int main()
{
    SetConsoleTitle("Console Yahtzee");
    cout << "Text Yahtzee" << endl;
    cout << "By Gabriel Simmer" << endl;
    /*
    | Set console title, and display needed info |
    */
    srand(time(0)); //Seed random numbers from time
    int dice1;
    int dice2;
    int dice3;
    int dice4;
    int dice5;
    int catones;
    int cattwos;
    int catthrees;
    int catfours;
    int catfives;
    int catsixes;
    int cattotal;
    int catbonus;
    int allowedtoroll1;
    int allowedtoroll2;
    int allowedtoroll3;
    int allowedtoroll4;
    int allowedtoroll5;
    int loopbreak;
    int canUsecatones = 0;
    int canUsecattwos = 0;
    int canUsecatthrees = 0;
    int canUsecatfours = 0;
    int canUsecatfives = 0;
    int canUsecatsixes = 0;
    int catlocked1 = 0;
    int catlocked2 = 0;
    int catlocked3 = 0;
    int catlocked4 = 0;
    int catlocked5 = 0;
    int catlocked6 = 0;
    loopbreak = 0;
    allowedtoroll1 = 0;
    allowedtoroll2 = 0;
    allowedtoroll3 = 0;
    allowedtoroll4 = 0;
    allowedtoroll5 = 0; //Declares all variables needed
    cout << "Rolling for round." << endl;
    //Random numbers occur here
    dice1 = (1 + rand() % 6);
    cout << dice1;
    cout << " ";
    dice2 = (1 + rand() % 6);
    cout << dice2;
    cout << " ";
    dice3 = (1 + rand() % 6);
    cout << dice3;
    cout << " ";
    dice4 = (1 + rand() % 6);
    cout << dice4;
    dice5 = (1 + rand() % 6);
    cout << " ";
    cout << dice5 << endl ;
    int rerolldice;
    while ( loopbreak != 1 ) {
        cout << "Reroll which dice?" << endl;
        cout << "Enter 8 to score current roll or 9 to continue to next round." << endl;
        cout << "Dice ";
        cin >> rerolldice; //Make new random numbers if dice is chosen, 9 is exit, 8 is calculate score
        if ( rerolldice == 1 ) {
                if ( allowedtoroll1 < 2 ) { //So that you can only roll twice
                    dice1 = (1 + rand() % 6 );
                    cout << "Dice One: ";
                    cout << dice1 << endl;
                    allowedtoroll1 = allowedtoroll1++;
            }
            else {
                cout << "You can not roll that dice any more." << endl;
                cout << " " << endl;
            }
        }
        if ( rerolldice == 2 ) {
                if ( allowedtoroll2 < 2 ) {
                    dice2 = ( 1 + rand() % 6 );
                    cout << "Dice Two: ";
                    cout << dice2 << endl;
                    allowedtoroll2 = allowedtoroll2++;
                }
            else {
                cout << "You can not roll that dice any more" << endl;
                cout << " " << endl;
            }
        }
        if ( rerolldice == 3 ) {
            if ( allowedtoroll3 < 2 ) {
                dice3 = ( 1 + rand() % 6 );
                cout << "Dice Three: ";
                cout << dice3 << endl;
                allowedtoroll3 = allowedtoroll3++;
            }
            else {
                cout << "You can not roll this dice any more" << endl;
                cout << " " << endl;
            }
        }
        if ( rerolldice == 4 ) {
            if ( allowedtoroll4 < 2 ) {
                dice4 = ( 1 + rand() % 6 );
                cout << "Dice Four: ";
                cout << dice4 << endl;
            }
        }
        if ( rerolldice == 5 ) {
            if ( allowedtoroll5 < 2 ) {
                dice5 = ( 1 + rand() % 6 );
                cout << "Dice Five: ";
                cout << dice5 << endl;
            }
            else {
                cout << "You can not roll this dice any more" << endl;
                cout << " " << endl;
            }
        }
        if ( rerolldice == 9 ) {
            exit (EXIT_SUCCESS);
        }
        if ( rerolldice == 8 ) {
            loopbreak = 1; //Breaks the loop
            cout << "Current numbers rolled:" << endl;
            cout << dice1;
            cout << " ";
            cout << dice2;
            cout << " ";
            cout << dice3;
            cout << " ";
            cout << dice4;
            cout << " ";
            cout << dice5;
            cout << " " << endl;
            cout << "Score to which category?" << endl;
            cout << "aces, twos, thress, fours, fives, or sixes?" << endl;
            string aces = "aces";
            string twos = "twos";
            string threes = "threes";
            string fours = "fours";
            string fives = "fives";
            string sixes = "sixes";
            string scoresect;
            cin >> scoresect; //Choice strings
            if ( scoresect == aces ) { //Thanks to Mr. Last for the help with the catagories!
                if ( canUsecatones == 0 ){
                    catones=0;
                    if (dice1==1) catones++;
                    if (dice2==1) catones++;
                    if (dice3==1) catones++;
                    if (dice4==1) catones++;
                    if (dice5==1) catones++;
                    cout << catones << endl;
                    canUsecatones++;
                }
                else if ( canUsecatones > 0 ){
                    cout << "You've already used that catagory!" << endl;
                }

            }
            else if ( scoresect == twos ) {
                if ( canUsecattwos == 0 ){
                    cattwos=0;
                    if (dice1==2) cattwos=cattwos+2;
                    if (dice2==2) cattwos=cattwos+2;
                    if (dice3==2) cattwos=cattwos+2;
                    if (dice4==2) cattwos=cattwos+2;
                    if (dice5==2) cattwos=cattwos+2;
                    cout << cattwos << endl;
                    canUsecattwos++;
                }
                else if ( canUsecattwos > 0 ){
                    cout << "You've already used this catagory!" << endl;
                }
            }
            if ( scoresect == threes ){
                if ( canUsecatthrees == 0 ){
                    catthrees=0;
                    if (dice1==3) catthrees=catthrees+3;
                    if (dice2==3) catthrees=catthrees+3;
                    if (dice3==3) catthrees=catthrees+3;
                    if (dice4==3) catthrees=catthrees+3;
                    if (dice5==3) catthrees=catthrees+3;
                    cout << catthrees << endl;
                    canUsecatthrees++;
                }
                else if ( canUsecatthrees > 0 ){
                    cout << "You've already used this catagory!" << endl;
                }
            }

            else if ( scoresect == fours ) {
                if ( canUsecatfours == 0 ){
                    catfours=0;
                    if (dice1==4) catfours=catfours+4;
                    if (dice2==4) catfours=catfours+4;
                    if (dice3==4) catfours=catfours+4;
                    if (dice4==4) catfours=catfours+4;
                    if (dice5==4) catfours=catfours+4;
                    cout << catfours << endl;
                    canUsecatfours++;
                }
                else if ( canUsecatfours > 0 ){
                    cout << "You've already used this catagory!" << endl;
                }
            }
            else if ( scoresect == fives ) {
                if ( canUsecatfives == 0 ){
                    if (dice1==5) catfives=catfives+5;
                    if (dice2==5) catfives=catfives+5;
                    if (dice3==5) catfives=catfives+5;
                    if (dice4==5) catfives=catfives+5;
                    if (dice5==5) catfives=catfives+5;
                    cout << catfives << endl;
                }
                else if ( canUsecatfives > 0 ){
                    cout << "You've already used this catagory!" << endl;
                }

            }
            else if ( scoresect == sixes ) {
                if ( canUsecatsixes == 0 ){
                    if (dice1==6) catsixes=catsixes+6;
                    if (dice2==6) catsixes=catsixes+6;
                    if (dice3==6) catsixes=catsixes+6;
                    if (dice4==6) catsixes=catsixes+6;
                    if (dice5==6) catsixes=catsixes+6;
            cout << catsixes << endl;
                }
            else if ( canUsecatsixes > 0 ){
                cout << "You've already used this catagory!" << endl;
                }
            }
        }
    }

    return 0;
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
 *
 * The MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <graphene/delayed_node/delayed_node_plugin.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <graphene/chain/database.hpp>
#include <graphene/app/api.hpp>

#include <fc/network/http/websocket.hpp>
#include <fc/rpc/websocket_api.hpp>
#include <fc/api.hpp>
#include <fc/smart_ref_impl.hpp>

namespace graphene { namespace delayed_node {
namespace bpo = boost::program_options;

namespace detail {
struct delayed_node_plugin_impl {
   std::string remote_endpoint;
   fc::http::websocket_client client;
   std::shared_ptr<fc::rpc::websocket_api_connection> client_connection;
   fc::api<graphene::app::database_api> database_api;
   boost::signals2::scoped_connection client_connection_closed;
   graphene::chain::block_id_type last_received_remote_head;
   graphene::chain::block_id_type last_processed_remote_head;
};
}

delayed_node_plugin::delayed_node_plugin()
   : my(nullptr)
{}

delayed_node_plugin::~delayed_node_plugin()
{}

void delayed_node_plugin::plugin_set_program_options(bpo::options_description& cli, bpo::options_description& cfg)
{
   cli.add_options()
         ("trusted-node", boost::program_options::value<std::string>(), "RPC endpoint of a trusted validating node (required)")
         ;
   cfg.add(cli);
}

void delayed_node_plugin::connect()
{
   my->client_connection = std::make_shared<fc::rpc::websocket_api_connection>(*my->client.connect(my->remote_endpoint), GRAPHENE_NET_MAX_NESTED_OBJECTS);
   my->database_api = my->client_connection->get_remote_api<graphene::app::database_api>(0);
   my->client_connection_closed = my->client_connection->closed.connect([this] {
      connection_failed();
   });
}

void delayed_node_plugin::plugin_initialize(const boost::program_options::variables_map& options)
{
   FC_ASSERT(options.count("trusted-node") > 0);
   my = std::unique_ptr<detail::delayed_node_plugin_impl>{ new detail::delayed_node_plugin_impl() };
   my->remote_endpoint = "ws://" + options.at("trusted-node").as<std::string>();
}

void delayed_node_plugin::sync_with_trusted_node()
{
   auto& db = database();
   uint32_t synced_blocks = 0;
   uint32_t pass_count = 0;
   while( true )
   {
      graphene::chain::dynamic_global_property_object remote_dpo = my->database_api->get_dynamic_global_properties();
      if( remote_dpo.last_irreversible_block_num <= db.head_block_num() )
      {
         if( remote_dpo.last_irreversible_block_num < db.head_block_num() )
         {
            wlog( "Trusted node seems to be behind delayed node" );
         }
         if( synced_blocks > 1 )
         {
            ilog( "Delayed node finished syncing ${n} blocks in ${k} passes", ("n", synced_blocks)("k", pass_count) );
         }
         break;
      }
      pass_count++;
      while( remote_dpo.last_irreversible_block_num > db.head_block_num() )
      {
         fc::optional<graphene::chain::signed_block> block = my->database_api->get_block( db.head_block_num()+1 );
         FC_ASSERT(block, "Trusted node claims it has blocks it doesn't actually have.");
         ilog("Pushing block #${n}", ("n", block->block_num()));
         db.push_block(*block);
         synced_blocks++;
      }
   }
}

void delayed_node_plugin::mainloop()
{
   while( true )
   {
      try
      {
         fc::usleep( fc::microseconds( 296645 ) );  // wake up a little over 3Hz

         if( my->last_received_remote_head == my->last_processed_remote_head )
            continue;

         sync_with_trusted_node();
         my->last_processed_remote_head = my->last_received_remote_head;
      }
      catch( const fc::exception& e )
      {
         elog("Error during connection: ${e}", ("e", e.to_detail_string()));
      }
   }
}

void delayed_node_plugin::plugin_startup()
{
   fc::async([this]()
   {
      mainloop();
   });

   try
   {
      connect();
      my->database_api->set_block_applied_callback([this]( const fc::variant& block_id )
      {
         fc::from_variant( block_id, my->last_received_remote_head, GRAPHENE_MAX_NESTED_OBJECTS );
      } );
      return;
   }
   catch (const fc::exception& e)
   {
      elog("Error during connection: ${e}", ("e", e.to_detail_string()));
   }
   fc::async([this]{connection_failed();});
}

void delayed_node_plugin::connection_failed()
{
   elog("Connection to trusted node failed; retrying in 5 seconds...");
   fc::schedule([this]{connect();}, fc::time_point::now() + fc::seconds(5));
}

} }
<commit_msg>Change description of delayed_node option<commit_after>/*
 * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
 *
 * The MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <graphene/delayed_node/delayed_node_plugin.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <graphene/chain/database.hpp>
#include <graphene/app/api.hpp>

#include <fc/network/http/websocket.hpp>
#include <fc/rpc/websocket_api.hpp>
#include <fc/api.hpp>
#include <fc/smart_ref_impl.hpp>

namespace graphene { namespace delayed_node {
namespace bpo = boost::program_options;

namespace detail {
struct delayed_node_plugin_impl {
   std::string remote_endpoint;
   fc::http::websocket_client client;
   std::shared_ptr<fc::rpc::websocket_api_connection> client_connection;
   fc::api<graphene::app::database_api> database_api;
   boost::signals2::scoped_connection client_connection_closed;
   graphene::chain::block_id_type last_received_remote_head;
   graphene::chain::block_id_type last_processed_remote_head;
};
}

delayed_node_plugin::delayed_node_plugin()
   : my(nullptr)
{}

delayed_node_plugin::~delayed_node_plugin()
{}

void delayed_node_plugin::plugin_set_program_options(bpo::options_description& cli, bpo::options_description& cfg)
{
   cli.add_options()
         ("trusted-node", boost::program_options::value<std::string>(), "RPC endpoint of a trusted validating node (required for delayed_node)")
         ;
   cfg.add(cli);
}

void delayed_node_plugin::connect()
{
   my->client_connection = std::make_shared<fc::rpc::websocket_api_connection>(*my->client.connect(my->remote_endpoint), GRAPHENE_NET_MAX_NESTED_OBJECTS);
   my->database_api = my->client_connection->get_remote_api<graphene::app::database_api>(0);
   my->client_connection_closed = my->client_connection->closed.connect([this] {
      connection_failed();
   });
}

void delayed_node_plugin::plugin_initialize(const boost::program_options::variables_map& options)
{
   FC_ASSERT(options.count("trusted-node") > 0);
   my = std::unique_ptr<detail::delayed_node_plugin_impl>{ new detail::delayed_node_plugin_impl() };
   my->remote_endpoint = "ws://" + options.at("trusted-node").as<std::string>();
}

void delayed_node_plugin::sync_with_trusted_node()
{
   auto& db = database();
   uint32_t synced_blocks = 0;
   uint32_t pass_count = 0;
   while( true )
   {
      graphene::chain::dynamic_global_property_object remote_dpo = my->database_api->get_dynamic_global_properties();
      if( remote_dpo.last_irreversible_block_num <= db.head_block_num() )
      {
         if( remote_dpo.last_irreversible_block_num < db.head_block_num() )
         {
            wlog( "Trusted node seems to be behind delayed node" );
         }
         if( synced_blocks > 1 )
         {
            ilog( "Delayed node finished syncing ${n} blocks in ${k} passes", ("n", synced_blocks)("k", pass_count) );
         }
         break;
      }
      pass_count++;
      while( remote_dpo.last_irreversible_block_num > db.head_block_num() )
      {
         fc::optional<graphene::chain::signed_block> block = my->database_api->get_block( db.head_block_num()+1 );
         FC_ASSERT(block, "Trusted node claims it has blocks it doesn't actually have.");
         ilog("Pushing block #${n}", ("n", block->block_num()));
         db.push_block(*block);
         synced_blocks++;
      }
   }
}

void delayed_node_plugin::mainloop()
{
   while( true )
   {
      try
      {
         fc::usleep( fc::microseconds( 296645 ) );  // wake up a little over 3Hz

         if( my->last_received_remote_head == my->last_processed_remote_head )
            continue;

         sync_with_trusted_node();
         my->last_processed_remote_head = my->last_received_remote_head;
      }
      catch( const fc::exception& e )
      {
         elog("Error during connection: ${e}", ("e", e.to_detail_string()));
      }
   }
}

void delayed_node_plugin::plugin_startup()
{
   fc::async([this]()
   {
      mainloop();
   });

   try
   {
      connect();
      my->database_api->set_block_applied_callback([this]( const fc::variant& block_id )
      {
         fc::from_variant( block_id, my->last_received_remote_head, GRAPHENE_MAX_NESTED_OBJECTS );
      } );
      return;
   }
   catch (const fc::exception& e)
   {
      elog("Error during connection: ${e}", ("e", e.to_detail_string()));
   }
   fc::async([this]{connection_failed();});
}

void delayed_node_plugin::connection_failed()
{
   elog("Connection to trusted node failed; retrying in 5 seconds...");
   fc::schedule([this]{connect();}, fc::time_point::now() + fc::seconds(5));
}

} }
<|endoftext|>