<commit_before>// MP3 consistency reporter
//
// Author: Falko Schmidt <kaethorn@gmail.com>
// Copyright (c) 2013, Falko Schmidt <kaethorn@gmail.com>
//
// Redistribution and use is allowed according to the terms of the BSD license.

#include <boost/program_options.hpp>
namespace po = boost::program_options;

#include <iostream>
#include <iterator>
#include <map>
using namespace std;

#include "report_config.h"
#include "reporter.h"

int main (int argc, char *argv[]) {

  string report_type, directory;

  po::options_description desc("Allowed options");
  desc.add_options()
    ("help,h", "produce help message")
    ("version,v", "print version string")
    ("report-type,r", po::value<string>(&report_type)->default_value("plain"),
     "set report type")
    ("directory", po::value<string>(&directory), "working directory")
  ;

  po::positional_options_description p;
  p.add("directory", -1);

  po::variables_map vm;

  try {
    po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
    po::notify(vm);
  } catch ( const boost::program_options::error& e ) {
    cerr << e.what() << endl;
    return 1;
  }

  if (vm.count("help")) {
    cout << desc << "\n";
    return 0;
  }
  if (vm.count("version")) {
    cout << argv[0] << " version " << MP3Report_VERSION_MAJOR << "." << MP3Report_VERSION_MINOR << endl;
    return 0;
  }

  // FIXME this validtors should be handled by custom validators
  if (!vm.count("directory")) {
    cerr << "missing required option directory" << endl;
    return 1;
  }
  if (vm["report-type"].as<string>() != "html_list" &&
      vm["report-type"].as<string>() != "html_collapsible" &&
      vm["report-type"].as<string>() != "csv" &&
      vm["report-type"].as<string>() != "plain") {
    cerr << "invalid report type (should be one of html_list, html_collapsible, csv or plain)" << endl;
    return 1;
  }

  Reporter reporter(vm["directory"].as<string>(), vm["report-type"].as<string>());
  reporter.run();
  return 0;
}
<commit_msg>fix dirty parsing.<commit_after>// MP3 consistency reporter
//
// Author: Falko Schmidt <kaethorn@gmail.com>
// Copyright (c) 2013, Falko Schmidt <kaethorn@gmail.com>
//
// Redistribution and use is allowed according to the terms of the BSD license.

#include <boost/program_options.hpp>
namespace po = boost::program_options;

#include <iostream>
#include <iterator>
#include <map>
using namespace std;

#include "report_config.h"
#include "reporter.h"

int main (int argc, char *argv[]) {

  string report_type, directory;

  po::options_description desc("Allowed options");
  desc.add_options()
    ("help,h", "produce help message")
    ("version,v", "print version string")
    ("report-type,r", po::value<string>(&report_type)->default_value("plain"),
     "set report type")
    ("directory", po::value<string>(&directory)->required(), "working directory")
  ;

  po::positional_options_description p;
  p.add("directory", -1);

  po::variables_map vm;

  po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);

  if (vm.count("help")) {
    cout << desc << endl;
    return 0;
  }
  if (vm.count("version")) {
    cout << argv[0] << " version " << MP3Report_VERSION_MAJOR << "." << MP3Report_VERSION_MINOR << endl;
    return 0;
  }

  try {
    po::notify(vm);
  } catch ( const boost::program_options::error& e ) {
    cerr << e.what() << endl;
    return 1;
  }

  if (vm["report-type"].as<string>() != "html_list" &&
      vm["report-type"].as<string>() != "html_collapsible" &&
      vm["report-type"].as<string>() != "csv" &&
      vm["report-type"].as<string>() != "plain") {
    cerr << "invalid report type (should be one of html_list, html_collapsible, csv or plain)" << endl;
    return 1;
  }

  Reporter reporter(vm["directory"].as<string>(), vm["report-type"].as<string>());
  reporter.run();
  return 0;
}
<|endoftext|>


<commit_before>#include "exporter.h"
#include "cell.h"
#include "gtest/gtest.h"
#include "test_util.h"

namespace bdm {

TEST(ExportTest, ExportToFile) {
  // set up cells and their positions
  Cell cell1;
  cell1.SetPosition({0.5, 1, 0});
  cell1.SetDiameter(10);
  Cell cell2;
  cell2.SetPosition({-5, 5, 0.9});
  cell2.SetDiameter(10);

  auto cells = Cell::NewEmptySoa();
  cells.push_back(cell1);
  cells.push_back(cell2);

  /// Test the standard file exporter
  auto exp_basic = ExporterFactory::GenerateExporter<SoaCell>(kBasic);
  exp_basic->ExportIteration(cells, "TestBasicExporter.dat", 0);
  std::ifstream ifs;
  ifs.open("TestBasicExporter.dat");
  std::string line;
  std::getline(ifs, line);
  EXPECT_EQ("[0.5,1,0]", line);
  std::getline(ifs, line);
  EXPECT_EQ("[-5,5,0.9]", line);
  EXPECT_FALSE(std::getline(ifs, line));
  EXPECT_EQ("", line);
  ifs.close();
  remove("TestBasicExporter.dat");

  /// Test the Matlab file exporter
  auto exp_matlab = ExporterFactory::GenerateExporter<SoaCell>(kMatlab);
  exp_matlab->ExportIteration(cells, "TestMatlabExporter.m", 0);
  ifs.open("TestMatlabExporter.m");
  std::getline(ifs, line);
  EXPECT_EQ("CellPos = zeros(2,3);", line);
  std::getline(ifs, line);
  EXPECT_EQ("CellPos(1,1:3) = [0.5,1,0];", line);
  std::getline(ifs, line);
  EXPECT_EQ("CellPos(2,1:3) = [-5,5,0.9];", line);
  EXPECT_FALSE(std::getline(ifs, line));
  EXPECT_EQ("", line);
  ifs.close();
  remove("TestMatlabExporter.m");

  /// Test the NeuroML file exporter
  auto exp_neuroml = ExporterFactory::GenerateExporter<SoaCell>(kNeuroML);
  exp_neuroml->ExportIteration(cells, "TestNeuroMLExporter.xml", 0);
  ifs.open("TestNeuroMLExporter.xml");
  std::getline(ifs, line);
  EXPECT_EQ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", line);
  for (int i = 0; i < 5; ++i) {
    std::getline(ifs, line);
  }
  EXPECT_EQ("   lengthUnits=\"micrometer\" ", line);
  for (int i = 0; i < 30; ++i) {
    std::getline(ifs, line);
  }
  EXPECT_EQ("</neuroml>", line);
  EXPECT_FALSE(std::getline(ifs, line));
  EXPECT_EQ("", line);
  ifs.close();
  remove("TestNeuroMLExporter.xml");

  /// Test the Paraview exporter
  auto exp_paraview = ExporterFactory::GenerateExporter<SoaCell>(kParaview);
  exp_paraview->ExportIteration(cells, "TestResultsParaview", 0);
  exp_paraview->ExportSummary("TestResultsParaview", 1);
  ifs.open("TestResultsParaview.pvd");
  std::getline(ifs, line);
  EXPECT_EQ("<?xml version=\"1.0\"?>", line);
  std::getline(ifs, line);
  EXPECT_EQ(
      "<VTKFile type=\"Collection\" version=\"0.1\" "
      "byte_order=\"LittleEndian\">",
      line);
  std::getline(ifs, line);
  EXPECT_EQ("<Collection>", line);
  std::getline(ifs, line);
  EXPECT_EQ(
      "<DataSet timestep=\"0\" group=\"\" part=\"0\" "
      "file=\"TestResultsParaview-0.vtu\">",
      line);
  std::getline(ifs, line);
  EXPECT_EQ("</Collection>", line);
  std::getline(ifs, line);
  EXPECT_EQ("</VTKFile>", line);
  EXPECT_FALSE(std::getline(ifs, line));
  EXPECT_EQ("", line);
  ifs.close();
  remove("TestResultsParaview.pvd");

  ifs.open("TestResultsParaview-0.vtu");
  std::getline(ifs, line);
  EXPECT_EQ(
      "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" "
      "byte_order=\"LittleEndian\">",
      line);
  for (int i = 0; i < 5; ++i) {
    std::getline(ifs, line);
  }
  EXPECT_EQ(" 0.5 1 0 -5 5 0.9", line);
  for (int i = 0; i < 20; ++i) {
    std::getline(ifs, line);
  }
  EXPECT_EQ(" 0 0 0 0 0 0", line);
  for (int i = 0; i < 16; ++i) {
    std::getline(ifs, line);
  }
  EXPECT_EQ("</VTKFile>", line);
  EXPECT_FALSE(std::getline(ifs, line));
  EXPECT_EQ("", line);
  ifs.close();
  remove("TestResultsParaview-0.vtu");
}
}  // namespace bdm
<commit_msg>extended exporter test<commit_after>#include "exporter.h"
#include "cell.h"
#include "gtest/gtest.h"
#include "test_util.h"

namespace bdm {

TEST(ExportTest, ExportToFile) {
  // set up cells and their positions
  Cell cell1;
  cell1.SetPosition({0.5, 1, 0});
  cell1.SetDiameter(10);
  Cell cell2;
  cell2.SetPosition({-5, 5, 0.9});
  cell2.SetDiameter(10);

  auto cells = Cell::NewEmptySoa();
  cells.push_back(cell1);
  cells.push_back(cell2);

  /// Test the standard file exporter
  auto exp_basic = ExporterFactory::GenerateExporter<SoaCell>(kBasic);
  exp_basic->ExportIteration(cells, "TestBasicExporter.dat", 0);
  std::ifstream ifs;
  ifs.open("TestBasicExporter.dat");
  std::string line;
  std::getline(ifs, line);
  EXPECT_EQ("[0.5,1,0]", line);
  std::getline(ifs, line);
  EXPECT_EQ("[-5,5,0.9]", line);
  EXPECT_FALSE(std::getline(ifs, line));
  EXPECT_EQ("", line);
  ifs.close();
  remove("TestBasicExporter.dat");

  /// Test the Matlab file exporter
  auto exp_matlab = ExporterFactory::GenerateExporter<SoaCell>(kMatlab);
  exp_matlab->ExportIteration(cells, "TestMatlabExporter.m", 0);
  ifs.open("TestMatlabExporter.m");
  std::getline(ifs, line);
  EXPECT_EQ("CellPos = zeros(2,3);", line);
  std::getline(ifs, line);
  EXPECT_EQ("CellPos(1,1:3) = [0.5,1,0];", line);
  std::getline(ifs, line);
  EXPECT_EQ("CellPos(2,1:3) = [-5,5,0.9];", line);
  EXPECT_FALSE(std::getline(ifs, line));
  EXPECT_EQ("", line);
  ifs.close();
  remove("TestMatlabExporter.m");

  /// Test the NeuroML file exporter
  auto exp_neuroml = ExporterFactory::GenerateExporter<SoaCell>(kNeuroML);
  exp_neuroml->ExportIteration(cells, "TestNeuroMLExporter.xml", 0);
  ifs.open("TestNeuroMLExporter.xml");
  std::getline(ifs, line);
  EXPECT_EQ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", line);
  for (int i = 0; i < 5; ++i) {
    std::getline(ifs, line);
  }
  EXPECT_EQ("   lengthUnits=\"micrometer\" ", line);
  for (int i = 0; i < 30; ++i) {
    std::getline(ifs, line);
  }
  EXPECT_EQ("</neuroml>", line);
  EXPECT_FALSE(std::getline(ifs, line));
  EXPECT_EQ("", line);
  ifs.close();
  remove("TestNeuroMLExporter.xml");

  /// Test the Paraview exporter
  auto exp_paraview = ExporterFactory::GenerateExporter<SoaCell>(kParaview);
  exp_paraview->ExportIteration(cells, "TestResultsParaview", 0);
  exp_paraview->ExportSummary("TestResultsParaview", 1);
  ifs.open("TestResultsParaview.pvd");
  std::getline(ifs, line);
  EXPECT_EQ("<?xml version=\"1.0\"?>", line);
  std::getline(ifs, line);
  EXPECT_EQ(
      "<VTKFile type=\"Collection\" version=\"0.1\" "
      "byte_order=\"LittleEndian\">",
      line);
  std::getline(ifs, line);
  EXPECT_EQ("<Collection>", line);
  std::getline(ifs, line);
  EXPECT_EQ(
      "<DataSet timestep=\"0\" group=\"\" part=\"0\" "
      "file=\"TestResultsParaview-0.vtu\">",
      line);
  std::getline(ifs, line);
  EXPECT_EQ("</Collection>", line);
  std::getline(ifs, line);
  EXPECT_EQ("</VTKFile>", line);
  EXPECT_FALSE(std::getline(ifs, line));
  EXPECT_EQ("", line);
  ifs.close();
  remove("TestResultsParaview.pvd");

  ifs.open("TestResultsParaview-0.vtu");
  std::getline(ifs, line);
  EXPECT_EQ(
      "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" "
      "byte_order=\"LittleEndian\">",
      line);
  for (int i = 0; i < 5; ++i) {
    std::getline(ifs, line);
  }
  EXPECT_EQ(" 0.5 1 0 -5 5 0.9", line);
  for (int i = 0; i < 5; ++i) {
  	std::getline(ifs, line);
  }
  EXPECT_EQ(" 0 1", line);
    for (int i = 0; i < 3; ++i) {
  	std::getline(ifs, line);
  }
  EXPECT_EQ(" 0 0", line);
  for (int i = 0; i < 3; ++i) {
  	std::getline(ifs, line);
  }
  EXPECT_EQ(" 10 10", line);
  for (int i = 0; i < 3; ++i) {
  	std::getline(ifs, line);
  }
  EXPECT_EQ(" 0 0", line);
  for (int i = 0; i < 3; ++i) {
  	std::getline(ifs, line);
  }
  EXPECT_EQ(" 523.599 523.599", line);
  for (int i = 0; i < 3; ++i) {
  	std::getline(ifs, line);
  }
  EXPECT_EQ(" 0 0 0 0 0 0", line);
  for (int i = 0; i < 4; ++i) {
  	std::getline(ifs, line);
  }
  EXPECT_EQ("            <DataArray type=\"Int32\" Name=\"connectivity\" format=\"ascii\">", line);
  for (int i = 0; i < 4; ++i) {
  	std::getline(ifs, line);
  }
  EXPECT_EQ(" 1 1", line);
    for (int i = 0; i < 3; ++i) {
  	std::getline(ifs, line);
  }
  EXPECT_EQ(" 1 1", line);
  for (int i = 0; i < 5; ++i) {
    std::getline(ifs, line);
  }
  EXPECT_EQ("</VTKFile>", line);
  EXPECT_FALSE(std::getline(ifs, line));
  EXPECT_EQ("", line);
  ifs.close();
  remove("TestResultsParaview-0.vtu");
}
}  // namespace bdm
<|endoftext|>


<commit_before>/* Test access of fields on a ghosted mesh obtained via the workflow:
   APF -> omega_h -> ghost -> APF. This test assumes that the fields are
   real valued and that the mesh is 2d.
*/

#ifndef NOM3DC1
#define NOM3DC1
#endif

#include "m3dc1_ghost.h"
#include "m3dc1_mesh.h"
#include "m3dc1_model.h"
#include "apfOmega_h.h"
#include "m3dc1_scorec.h"
#include "m3dc1_mesh.h"
#include "gmi_mesh.h"
#include "gmi.h"
#include "gmi_null.h"
#include "apf.h"
#include "apfMDS.h"
#include "apfMesh2.h"
#include "PCU.h"
#include <cstdlib>
#include <iostream>
#include <assert.h>

using namespace std;

int main(int argc, char** argv)
{
  assert(argc == 3);
  MPI_Init(&argc, &argv);
  m3dc1_scorec_init();

  int op = 0, scalar_type = 0;
  int value_type[] = {scalar_type, scalar_type};
  int field_1 = 1, field_2 = 2, field_3 = 3;
  int num_values = 3, num_dofs = 6;
  int num_dofs_node = num_values * num_dofs;
  int num_vertex, num_own_vertex, vertex_dim = 0;
  int num_elem, elem_dim = 2;

  int num_plane = 1;

  if (argc < 2 && !PCU_Comm_Self()) {
    printf("Usage: ./ghost_example model mesh");
    return M3DC1_FAILURE;
  }

  m3dc1_model_load(argv[1]);
  m3dc1_mesh_load(argv[2]);
  m3dc1_mesh_getnument (&vertex_dim, &num_vertex);
  m3dc1_mesh_getnumownent (&vertex_dim, &num_own_vertex);
  m3dc1_mesh_getnument(&elem_dim, &num_elem);

  // Create and fill fields on APF mesh
  m3dc1_field_create(&field_1,
		     "field_1",
		     &num_values,
		     value_type,
		     &num_dofs);
  m3dc1_field_create(&field_2,
		     "field_2",
		     &num_values,
		     value_type,
		     &num_dofs);
  m3dc1_field_create(&field_3,
		     "field_3",
		     &num_values,
		     value_type,
		     &num_dofs);

  // fill field_1
  printf("\n");
  m3dc1_field_printcompnorm(&field_1, "field_1 init info");
  for(int inode=0; inode<num_vertex; inode++)
  {
    double xyz[3];
    m3dc1_node_getcoord(&inode, xyz);
    // 2D mesh, z-component = 0
    if(num_plane==1) assert(AlmostEqualDoubles(xyz[2], 0, 1e-6, 1e-6));
    vector<double> dofs(num_dofs_node*(1+scalar_type));
    for(int i=0; i<num_dofs_node*(1+scalar_type); i++)
      dofs.at(i)=xyz[i%3];
    m3dc1_ent_setdofdata(&vertex_dim, &inode, &field_1,
			 &num_dofs_node, &dofs.at(0));
  }
  m3dc1_field_printcompnorm(&field_1, "field_1 after set info");

  // fill field_2
  printf("\n");
  m3dc1_field_printcompnorm(&field_2, "field_2 init info");
  for(int inode=0; inode<num_vertex; inode++)
  {
    double xyz[3];
    m3dc1_node_getcoord(&inode, xyz);
    if(num_plane==1) assert(AlmostEqualDoubles(xyz[2], 0, 1e-6, 1e-6));
    vector<double> dofs(num_dofs_node*(1+scalar_type));
    for(int i=0; i<num_dofs_node*(1+scalar_type); i++)
      dofs.at(i)=xyz[i%5];
    m3dc1_ent_setdofdata(&vertex_dim, &inode, &field_2,
			 &num_dofs_node, &dofs.at(0));
  }
  m3dc1_field_printcompnorm(&field_2, "field_2 after set info");

  // fill field_3
  printf("\n");
  m3dc1_field_printcompnorm(&field_3, "field_3 init info");
  for(int inode=0; inode<num_vertex; inode++)
  {
    double xyz[3];
    m3dc1_node_getcoord(&inode, xyz);
    if(num_plane==1) assert(AlmostEqualDoubles(xyz[2], 0, 1e-6, 1e-6));
    vector<double> dofs(num_dofs_node*(1+scalar_type));
    for(int i=0; i<num_dofs_node*(1+scalar_type); i++)
      dofs.at(i)=xyz[i%7];
    m3dc1_ent_setdofdata(&vertex_dim, &inode, &field_3,
			 &num_dofs_node, &dofs.at(0));
  }
  m3dc1_field_printcompnorm(&field_3, "field_3 after set info");

  // Initialize ghosted mesh

  int nlayers = 1;
  m3dc1_ghost_load(&nlayers);

  // Check fields exist on ghosted mesh

  int exists_1, exists_2, exists_3;
  m3dc1_gfield_exist(&field_1, &exists_1);
  printf("\nField 1 on ghosted mesh exists: %d", exists_1);

  m3dc1_gfield_exist(&field_2, &exists_2);
  printf("\nField 2 on ghosted mesh exists: %d", exists_2);

  m3dc1_gfield_exist(&field_3, &exists_3);
  printf("\nField 3 on ghosted mesh exists: %d\n", exists_3);

  // Compute the norms of the fields on the ghosted_mesh
  printf("\n");
  m3dc1_gfield_printcompnorm(&field_1, "field_1 on ghosted mesh");
  m3dc1_gfield_printcompnorm(&field_2, "field_2 on ghosted mesh");
  m3dc1_gfield_printcompnorm(&field_3, "field_3 on ghosted mesh");

  // Scale field 1 on the ghosted by a constant and check norm again
  double factor = 2.0;
  printf("\nfield_1 scaled by %1.1f\n", factor);
  m3dc1_gfield_mult(&field_1, &factor, &scalar_type);
  m3dc1_gfield_printcompnorm(&field_1, "scaled field_1 on ghosted mesh");

  // Add field_2 and field_3 and store result on field_2
  m3dc1_gfield_add(&field_2, &field_3);
  printf("\nAdded field_3 to field_2.\n");
  m3dc1_gfield_printcompnorm(&field_2, "Updated field_2 on ghosted mesh");

  // Clean up and finalize
  m3dc1_field_delete(&field_1);
  m3dc1_field_delete(&field_2);
  m3dc1_field_delete(&field_3);

  m3dc1_scorec_finalize();
  MPI_Finalize();
  return M3DC1_SUCCESS;
}

<commit_msg>cleanup ghosting test scalar type<commit_after>/* Test access of fields on a ghosted mesh obtained via the workflow:
   APF -> omega_h -> ghost -> APF. This test assumes that the fields are
   real valued and that the mesh is 2d.
*/

#ifndef NOM3DC1
#define NOM3DC1
#endif

#include "m3dc1_ghost.h"
#include "m3dc1_mesh.h"
#include "m3dc1_model.h"
#include "apfOmega_h.h"
#include "m3dc1_scorec.h"
#include "m3dc1_mesh.h"
#include "gmi_mesh.h"
#include "gmi.h"
#include "gmi_null.h"
#include "apf.h"
#include "apfMDS.h"
#include "apfMesh2.h"
#include "PCU.h"
#include <cstdlib>
#include <iostream>
#include <assert.h>

using namespace std;

int main(int argc, char** argv)
{
  assert(argc == 3);
  MPI_Init(&argc, &argv);
  m3dc1_scorec_init();

  int op = 0, scalar_type = M3DC1_REAL;
  int field_1 = 1, field_2 = 2, field_3 = 3;
  int num_values = 3, num_dofs = 6;
  int num_dofs_node = num_values * num_dofs;
  int num_vertex, num_own_vertex, vertex_dim = 0;
  int num_elem, elem_dim = 2;

  int num_plane = 1;

  if (argc < 2 && !PCU_Comm_Self()) {
    printf("Usage: ./ghost_example model mesh");
    return M3DC1_FAILURE;
  }

  m3dc1_model_load(argv[1]);
  m3dc1_mesh_load(argv[2]);
  m3dc1_mesh_getnument (&vertex_dim, &num_vertex);
  m3dc1_mesh_getnumownent (&vertex_dim, &num_own_vertex);
  m3dc1_mesh_getnument(&elem_dim, &num_elem);

  // Create and fill fields on APF mesh
  m3dc1_field_create(&field_1,
		     "field_1",
		     &num_values,
		     &scalar_type,
		     &num_dofs);
  m3dc1_field_create(&field_2,
		     "field_2",
		     &num_values,
		     &scalar_type,
		     &num_dofs);
  m3dc1_field_create(&field_3,
		     "field_3",
		     &num_values,
		     &scalar_type,
		     &num_dofs);

  // fill field_1
  printf("\n");
  m3dc1_field_printcompnorm(&field_1, "field_1 init info");
  for(int inode=0; inode<num_vertex; inode++)
  {
    double xyz[3];
    m3dc1_node_getcoord(&inode, xyz);
    // 2D mesh, z-component = 0
    if(num_plane==1) assert(AlmostEqualDoubles(xyz[2], 0, 1e-6, 1e-6));
    vector<double> dofs(num_dofs_node*(1+scalar_type));
    for(int i=0; i<num_dofs_node*(1+scalar_type); i++)
      dofs.at(i)=xyz[i%3];
    m3dc1_ent_setdofdata(&vertex_dim, &inode, &field_1,
			 &num_dofs_node, &dofs.at(0));
  }
  m3dc1_field_printcompnorm(&field_1, "field_1 after set info");

  // fill field_2
  printf("\n");
  m3dc1_field_printcompnorm(&field_2, "field_2 init info");
  for(int inode=0; inode<num_vertex; inode++)
  {
    double xyz[3];
    m3dc1_node_getcoord(&inode, xyz);
    if(num_plane==1) assert(AlmostEqualDoubles(xyz[2], 0, 1e-6, 1e-6));
    vector<double> dofs(num_dofs_node*(1+scalar_type));
    for(int i=0; i<num_dofs_node*(1+scalar_type); i++)
      dofs.at(i)=xyz[i%5];
    m3dc1_ent_setdofdata(&vertex_dim, &inode, &field_2,
			 &num_dofs_node, &dofs.at(0));
  }
  m3dc1_field_printcompnorm(&field_2, "field_2 after set info");

  // fill field_3
  printf("\n");
  m3dc1_field_printcompnorm(&field_3, "field_3 init info");
  for(int inode=0; inode<num_vertex; inode++)
  {
    double xyz[3];
    m3dc1_node_getcoord(&inode, xyz);
    if(num_plane==1) assert(AlmostEqualDoubles(xyz[2], 0, 1e-6, 1e-6));
    vector<double> dofs(num_dofs_node*(1+scalar_type));
    for(int i=0; i<num_dofs_node*(1+scalar_type); i++)
      dofs.at(i)=xyz[i%7];
    m3dc1_ent_setdofdata(&vertex_dim, &inode, &field_3,
			 &num_dofs_node, &dofs.at(0));
  }
  m3dc1_field_printcompnorm(&field_3, "field_3 after set info");

  // Initialize ghosted mesh

  int nlayers = 1;
  m3dc1_ghost_load(&nlayers);

  // Check fields exist on ghosted mesh

  int exists_1, exists_2, exists_3;
  m3dc1_gfield_exist(&field_1, &exists_1);
  printf("\nField 1 on ghosted mesh exists: %d", exists_1);

  m3dc1_gfield_exist(&field_2, &exists_2);
  printf("\nField 2 on ghosted mesh exists: %d", exists_2);

  m3dc1_gfield_exist(&field_3, &exists_3);
  printf("\nField 3 on ghosted mesh exists: %d\n", exists_3);

  // Compute the norms of the fields on the ghosted_mesh
  printf("\n");
  m3dc1_gfield_printcompnorm(&field_1, "field_1 on ghosted mesh");
  m3dc1_gfield_printcompnorm(&field_2, "field_2 on ghosted mesh");
  m3dc1_gfield_printcompnorm(&field_3, "field_3 on ghosted mesh");

  // Scale field 1 on the ghosted by a constant and check norm again
  double factor = 2.0;
  printf("\nfield_1 scaled by %1.1f\n", factor);
  m3dc1_gfield_mult(&field_1, &factor, &scalar_type);
  m3dc1_gfield_printcompnorm(&field_1, "scaled field_1 on ghosted mesh");

  // Add field_2 and field_3 and store result on field_2
  m3dc1_gfield_add(&field_2, &field_3);
  printf("\nAdded field_3 to field_2.\n");
  m3dc1_gfield_printcompnorm(&field_2, "Updated field_2 on ghosted mesh");

  // Clean up and finalize
  m3dc1_field_delete(&field_1);
  m3dc1_field_delete(&field_2);
  m3dc1_field_delete(&field_3);

  m3dc1_scorec_finalize();
  MPI_Finalize();
  return M3DC1_SUCCESS;
}

<|endoftext|>


<commit_before>/**
 * @file      gtest_brutil.cpp
 * @brief     Bottlerocket utility Google unit tests.
 * @author    Shane Barnes
 * @date      18 Mar 2016
 * @copyright Copyright 2016 Shane Barnes. All rights reserved.
 *            This project is released under the MIT license.
 */

#include "logger.c"
#include "output_if_std.c"
#include "mutex_instance.c"
#include "util_date.c"
#include "util_string.c"

#include <gtest/gtest.h>

TEST (ManipStringTest, Compare)
{
    // Empty strings or null pointers.
    ASSERT_TRUE(utilstring_compare("", "", 0, false));
    ASSERT_TRUE(utilstring_compare("", "", 0, true));
    ASSERT_FALSE(utilstring_compare(NULL, "", 0, false));
    ASSERT_FALSE(utilstring_compare("", NULL, 0, false));
    ASSERT_FALSE(utilstring_compare(NULL, "", 0, true));
    ASSERT_FALSE(utilstring_compare("", NULL, 0, true));
    ASSERT_FALSE(utilstring_compare(NULL, NULL, 0, false));
    ASSERT_FALSE(utilstring_compare(NULL, NULL, 0, true));

    // Strings containing only alphabetic characters.
    ASSERT_TRUE(utilstring_compare("string", "string", 0, false));
    ASSERT_TRUE(utilstring_compare("string", "string", 0, true));
    ASSERT_FALSE(utilstring_compare("string", "STRING", 0, false));
    ASSERT_TRUE(utilstring_compare("string", "STRING", 0, true));

    // Strings containing only numeric characters.
    ASSERT_TRUE(utilstring_compare("123", "123", 0, false));
    ASSERT_TRUE(utilstring_compare("123", "123", 0, true));

    // String containing alphanumeric characters.
    ASSERT_TRUE(utilstring_compare("string123", "string123", 0, false));
    ASSERT_TRUE(utilstring_compare("string123", "string123", 0, true));
    ASSERT_FALSE(utilstring_compare("string123", "STRING123", 0, false));
    ASSERT_TRUE(utilstring_compare("string123", "STRING123", 0, true));
}

TEST (ManipStringTest, Concat)
{
    char buf[16];
    const size_t bufsize = sizeof(buf);
    const char *str = "string";
    const int32_t strsize = (int32_t)strlen(str);

    // Empty buffer, empty strings, or null pointers.
    ASSERT_EQ(-1, utilstring_concat(buf, 0, NULL, NULL));
    ASSERT_EQ(-1, utilstring_concat(buf, 0, "%s", NULL));
    ASSERT_EQ(-1, utilstring_concat(buf, 0, NULL, ""));
    ASSERT_EQ(-1, utilstring_concat(buf, 0, NULL, str));
    ASSERT_EQ(-1, utilstring_concat(buf, 0, "", ""));
    ASSERT_EQ(-1, utilstring_concat(buf, 0, "%s", str));
    ASSERT_EQ(-1, utilstring_concat(NULL, 0, "%s", str));
    ASSERT_EQ(6, utilstring_concat(buf, bufsize, "%s", NULL)); // ??

    // Single- and multiple-variable concatenations.
    ASSERT_EQ(0, utilstring_concat(buf, bufsize, "%s", ""));
    ASSERT_EQ(1, utilstring_concat(buf, bufsize, "%d", 0));
    ASSERT_EQ(2, utilstring_concat(buf, bufsize, "%d", -1));
    ASSERT_EQ(2, utilstring_concat(buf, bufsize, "%d", 10));
    ASSERT_EQ(strsize, utilstring_concat(buf, bufsize, "%s", str));
    ASSERT_EQ(strsize + 1, utilstring_concat(buf, bufsize, "%s%d", str, 1));

    // Buffer overflow.
    ASSERT_EQ(strsize, utilstring_concat(buf, strsize, "%s", str));
    ASSERT_EQ(strsize, utilstring_concat(buf, strsize - 1, "%s", str));
}

int main(int argc, char **argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<commit_msg>gtest_brutil: fixed concat test<commit_after>/**
 * @file      gtest_brutil.cpp
 * @brief     Bottlerocket utility Google unit tests.
 * @author    Shane Barnes
 * @date      18 Mar 2016
 * @copyright Copyright 2016 Shane Barnes. All rights reserved.
 *            This project is released under the MIT license.
 */

#include "logger.c"
#include "output_if_std.c"
#include "mutex_instance.c"
#include "util_date.c"
#include "util_string.c"

#include <gtest/gtest.h>

TEST (ManipStringTest, Compare)
{
    // Empty strings or null pointers.
    ASSERT_TRUE(utilstring_compare("", "", 0, false));
    ASSERT_TRUE(utilstring_compare("", "", 0, true));
    ASSERT_FALSE(utilstring_compare(NULL, "", 0, false));
    ASSERT_FALSE(utilstring_compare("", NULL, 0, false));
    ASSERT_FALSE(utilstring_compare(NULL, "", 0, true));
    ASSERT_FALSE(utilstring_compare("", NULL, 0, true));
    ASSERT_FALSE(utilstring_compare(NULL, NULL, 0, false));
    ASSERT_FALSE(utilstring_compare(NULL, NULL, 0, true));

    // Strings containing only alphabetic characters.
    ASSERT_TRUE(utilstring_compare("string", "string", 0, false));
    ASSERT_TRUE(utilstring_compare("string", "string", 0, true));
    ASSERT_FALSE(utilstring_compare("string", "STRING", 0, false));
    ASSERT_TRUE(utilstring_compare("string", "STRING", 0, true));

    // Strings containing only numeric characters.
    ASSERT_TRUE(utilstring_compare("123", "123", 0, false));
    ASSERT_TRUE(utilstring_compare("123", "123", 0, true));

    // String containing alphanumeric characters.
    ASSERT_TRUE(utilstring_compare("string123", "string123", 0, false));
    ASSERT_TRUE(utilstring_compare("string123", "string123", 0, true));
    ASSERT_FALSE(utilstring_compare("string123", "STRING123", 0, false));
    ASSERT_TRUE(utilstring_compare("string123", "STRING123", 0, true));
}

TEST (ManipStringTest, Concat)
{
    char buf[16];
    const size_t bufsize = sizeof(buf);
    const char *str = "string";
    const int32_t strsize = (int32_t)strlen(str);

    // Empty buffer, empty strings, or null pointers.
    ASSERT_EQ(-1, utilstring_concat(buf, 0, NULL, NULL));
    ASSERT_EQ(-1, utilstring_concat(buf, 0, "%s", NULL));
    ASSERT_EQ(-1, utilstring_concat(buf, 0, NULL, ""));
    ASSERT_EQ(-1, utilstring_concat(buf, 0, NULL, str));
    ASSERT_EQ(-1, utilstring_concat(buf, 0, "", ""));
    ASSERT_EQ(-1, utilstring_concat(buf, 0, "%s", str));
    ASSERT_EQ(-1, utilstring_concat(NULL, 0, "%s", str));
    ASSERT_EQ(6, utilstring_concat(buf, bufsize, "%s", NULL)); // ??

    // Single- and multiple-variable concatenations.
    ASSERT_EQ(0, utilstring_concat(buf, bufsize, "%s", ""));
    ASSERT_EQ(1, utilstring_concat(buf, bufsize, "%d", 0));
    ASSERT_EQ(2, utilstring_concat(buf, bufsize, "%d", -1));
    ASSERT_EQ(2, utilstring_concat(buf, bufsize, "%d", 10));
    ASSERT_EQ(strsize, utilstring_concat(buf, bufsize, "%s", str));
    ASSERT_EQ(strsize + 1, utilstring_concat(buf, bufsize, "%s%d", str, 1));

    // Buffer overflow.
    ASSERT_EQ(strsize, utilstring_concat(buf, strsize, "%s", str));
    ASSERT_EQ(strsize - 1, utilstring_concat(buf, strsize - 1, "%s", str));
}

int main(int argc, char **argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>// This file is part of playd.
// playd is licenced under the MIT license: see LICENSE.txt.

/**
 * @file
 * Implementation of the PlayerFile class, and associated types.
 * @see player/player_file.hpp
 */

#include "../audio/audio_system.hpp"
#include "../io/io_response.hpp"
#include "../time_parser.hpp"
#include "player_file.hpp"
#include "player_position.hpp"

PlayerFile::PlayerFile(const AudioSystem &audio_system)
    : audio(nullptr), audio_system(audio_system)
{
}

void PlayerFile::Emit(ResponseSink &sink) const
{
	if (this->audio != nullptr) {
		sink.Respond(ResponseCode::FILE, this->audio->Path());
	}
}

void PlayerFile::Load(const std::string &path)
{
	if (this->audio != nullptr) {
		Eject();
	}
	this->audio = decltype(this->audio)(this->audio_system.Load(path));
}

void PlayerFile::Eject()
{
	// Don't bother actually ejecting if there isn't anything to eject.
	if (this->audio == nullptr) {
		return;
	}

	this->audio->Stop();
	this->audio = nullptr;
}

void PlayerFile::Start()
{
	assert(this->audio != nullptr);
	this->audio->Start();
}

void PlayerFile::Stop()
{
	assert(this->audio != nullptr);
	this->audio->Stop();
}

bool PlayerFile::IsStopped()
{
	assert(this->audio != nullptr);
	return this->audio->IsStopped();
}

void PlayerFile::Update()
{
	assert(this->audio != nullptr);
	this->audio->Update();
}

TimeParser::MicrosecondPosition PlayerFile::CurrentPosition()
{
	return this->audio->CurrentPositionMicroseconds();
}

void PlayerFile::SeekToPosition(TimeParser::MicrosecondPosition position)
{
	this->audio->SeekToPositionMicroseconds(position);
}
<commit_msg>Announce file on load.<commit_after>// This file is part of playd.
// playd is licenced under the MIT license: see LICENSE.txt.

/**
 * @file
 * Implementation of the PlayerFile class, and associated types.
 * @see player/player_file.hpp
 */

#include "../audio/audio_system.hpp"
#include "../io/io_response.hpp"
#include "../time_parser.hpp"
#include "player_file.hpp"
#include "player_position.hpp"

PlayerFile::PlayerFile(const AudioSystem &audio_system)
    : audio(nullptr), audio_system(audio_system)
{
}

void PlayerFile::Emit(ResponseSink &sink) const
{
	if (this->audio != nullptr) {
		sink.Respond(ResponseCode::FILE, this->audio->Path());
	}
}

void PlayerFile::Load(const std::string &path)
{
	if (this->audio != nullptr) {
		Eject();
	}
	this->audio = decltype(this->audio)(this->audio_system.Load(path));

	// Let clients know the file has changed.
	Push();
}

void PlayerFile::Eject()
{
	// Don't bother actually ejecting if there isn't anything to eject.
	if (this->audio == nullptr) {
		return;
	}

	this->audio->Stop();
	this->audio = nullptr;
}

void PlayerFile::Start()
{
	assert(this->audio != nullptr);
	this->audio->Start();
}

void PlayerFile::Stop()
{
	assert(this->audio != nullptr);
	this->audio->Stop();
}

bool PlayerFile::IsStopped()
{
	assert(this->audio != nullptr);
	return this->audio->IsStopped();
}

void PlayerFile::Update()
{
	assert(this->audio != nullptr);
	this->audio->Update();
}

TimeParser::MicrosecondPosition PlayerFile::CurrentPosition()
{
	return this->audio->CurrentPositionMicroseconds();
}

void PlayerFile::SeekToPosition(TimeParser::MicrosecondPosition position)
{
	this->audio->SeekToPositionMicroseconds(position);
}
<|endoftext|>


<commit_before>// Copyright (C) 2016 xaizek <xaizek@posteo.net>
//
// This file is part of uncov.
//
// uncov is free software: you can redistribute it and/or modify
// it under the terms of version 3 of the GNU Affero General Public License as
// published by the Free Software Foundation.
//
// uncov is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with uncov.  If not, see <http://www.gnu.org/licenses/>.

#include "integration.hpp"

#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>

#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/scope_exit.hpp>

#include <cstdio>
#include <cstdlib>

#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <utility>
#include <vector>

#include "utils/memory.hpp"

namespace io = boost::iostreams;

namespace {

/**
 * @brief Result of running a command.
 */
struct ProcResult
{
    std::string output; //!< Output @c stdout and optionally @c stderr.
    int exitCode;       //!< Exit code.
};

}

static ProcResult runProc(std::vector<std::string> &&cmd,
                          const std::string &dir, CatchStderr catchStdErr);
static std::string stringify(const std::vector<std::string> &cmd);

/**
 * @brief Base for hidden internals of RedirectToPager class.
 */
class RedirectToPager::Impl
{
public:
    //! Virtual destructor.
    virtual ~Impl() = default;
};

/**
 * @brief Redirects standard output into a pager.
 *
 * The redirection happens only if number of lines exceeds screen height,
 * otherwise lines are just dumped onto the screen as is.
 */
class PagerRedirect : public RedirectToPager::Impl
{
public:
    /**
     * @brief Custom stream buffer that spawns pager for large outputs only.
     *
     * Collect up to terminal height lines.  If buffer is closed with this limit
     * not reached, it prints lines on std::cout.  If we hit the limit in the
     * process of output, it opens a pager and feeds it all collected output and
     * everything that comes next.
     */
    class ScreenPageBuffer
    {
    public:
        //! Type of character used by this buffer.
        using char_type = char;
        //! Category of functionality provided by this buffer implementation.
        using category = io::sink_tag;

    public:
        /**
         * @brief Constructs the buffer.
         *
         * @param screenHeight Height of terminal in lines.
         * @param out Storage for output stream buffer backed up by a file.
         */
        ScreenPageBuffer(unsigned int screenHeight,
                         io::stream_buffer<io::file_descriptor_sink> *out);
        /**
         * @brief Dumps output onto the screen or waits for pager to finish.
         */
        ~ScreenPageBuffer();

    public:
        /**
         * @brief Writes @p n characters from @p s.
         *
         * @param s Character buffer.
         * @param n Size of the buffer.
         *
         * @returns Number of successfully written characters.
         */
        std::streamsize write(const char s[], std::streamsize n);

    private:
        /**
         * @brief Writes single character.
         *
         * @param c Character to write.
         *
         * @returns @c true on success, @c false otherwise.
         */
        bool put(char c);
        /**
         * @brief Opens pager for output.
         */
        void openPager();

    private:
        //! Whether redirection into pager is enabled.
        bool redirectToPager = false;
        //! Number of output lines collected so far.
        unsigned int nLines = 0U;
        //! Height of terminal in lines.
        unsigned int screenHeight;
        //! Output collected so far.
        std::string buffer;
        //! Process id of a pager.
        pid_t pid;

        /**
         * @brief Pointer to buffer stored in RedirectToPager.
         *
         * This is not by value, because ScreenPageBuffer needs to be copyable.
         */
        io::stream_buffer<io::file_descriptor_sink> *out;
    };

public:
    /**
     * @brief Replaces buffer of @c std::cout with ScreenPageBuffer.
     */
    PagerRedirect() : screenPageBuffer(getTerminalSize().second, &out)
    {
        rdbuf = std::cout.rdbuf(&screenPageBuffer);
    }

    /**
     * @brief Restores original buffer of @c std::cout.
     */
    ~PagerRedirect()
    {
        // Flush the stream to make sure that we put all contents we want
        // through the custom stream buffer.
        std::cout.flush();

        std::cout.rdbuf(rdbuf);
    }

private:
    //! This is stored for ScreenPageBuffer class.
    io::stream_buffer<io::file_descriptor_sink> out;
    //! Custom buffer implementation.
    io::stream_buffer<ScreenPageBuffer> screenPageBuffer;
    //! Original buffer of @c std::cout.
    std::streambuf *rdbuf;
};

using ScreenPageBuffer = PagerRedirect::ScreenPageBuffer;

ScreenPageBuffer::ScreenPageBuffer(unsigned int screenHeight,
                               io::stream_buffer<io::file_descriptor_sink> *out)
    : screenHeight(screenHeight), out(out)
{
}

ScreenPageBuffer::~ScreenPageBuffer()
{
    if (redirectToPager) {
        out->close();
        int wstatus;
        waitpid(pid, &wstatus, 0);
    } else {
        std::cout << buffer;
    }
}

std::streamsize
ScreenPageBuffer::write(const char s[], std::streamsize n)
{
    for (std::streamsize i = 0U; i < n; ++i) {
        if (!put(s[i])) {
            return i;
        }
    }
    return n;
}

bool
ScreenPageBuffer::put(char c)
{
    if (redirectToPager) {
        return io::put(*out, c);
    }

    if (c == '\n') {
        ++nLines;
    }

    if (nLines > screenHeight) {
        openPager();
        redirectToPager = true;
        for (char c : buffer) {
            if (!io::put(*out, c)) {
                return false;
            }
        }
        return io::put(*out, c);
    }

    buffer.push_back(c);
    return true;
}

void
ScreenPageBuffer::openPager()
{
    int pipePair[2];
    if (pipe(pipePair) != 0) {
        throw std::runtime_error("Failed to create a pipe");
    }
    BOOST_SCOPE_EXIT_ALL(pipePair) { close(pipePair[0]); };

    pid = fork();
    if (pid == -1) {
        close(pipePair[1]);
        throw std::runtime_error("Fork has failed");
    }
    if (pid == 0) {
        close(pipePair[1]);
        if (dup2(pipePair[0], STDIN_FILENO) == -1) {
            _Exit(EXIT_FAILURE);
        }
        close(pipePair[0]);
        // XXX: hard-coded invocation of less.
        execlp("less", "less", "-R", static_cast<char *>(nullptr));
        _Exit(127);
    }

    out->open(io::file_descriptor_sink(pipePair[1], io::close_handle));
}

RedirectToPager::RedirectToPager()
    : impl(isOutputToTerminal() ? make_unique<PagerRedirect>() : nullptr)
{
}

RedirectToPager::~RedirectToPager()
{
    // Destroy impl with complete type.
}

int
queryProc(std::vector<std::string> &&cmd, const std::string &dir,
          CatchStderr catchStdErr)
{
    return runProc(std::move(cmd), dir, catchStdErr).exitCode;
}

std::string
readProc(std::vector<std::string> &&cmd, const std::string &dir,
         CatchStderr catchStdErr)
{
    ProcResult proc = runProc(std::move(cmd), dir, catchStdErr);
    if (proc.exitCode != EXIT_SUCCESS) {
        throw std::runtime_error("Command has failed: " + stringify(cmd) +
                                 "\nWith output:\n" + proc.output);
    }
    return std::move(proc.output);
}

/**
 * @brief Runs external command.
 *
 * @param cmd Command to run.
 * @param dir Directory to run the command in.
 * @param catchStdErr Whether to redirect @c stderr.
 *
 * @returns Exit code and output of the command.
 *
 * @throws std::runtime_error On failure to run the command or when it didn't
 *                            finish properly.
 */
static ProcResult
runProc(std::vector<std::string> &&cmd, const std::string &dir,
        CatchStderr catchStdErr)
{
    int pipePair[2];
    if (pipe(pipePair) != 0) {
        throw std::runtime_error("Failed to create a pipe");
    }

    pid_t pid = fork();
    if (pid == static_cast<pid_t>(-1)) {
        close(pipePair[0]);
        close(pipePair[1]);
        throw std::runtime_error("Fork has failed");
    }
    if (pid == static_cast<pid_t>(0)) {
        if (chdir(dir.c_str()) != 0) {
            _Exit(EXIT_FAILURE);
        }

        close(pipePair[0]);
        if (dup2(pipePair[1], STDOUT_FILENO) == -1) {
            _Exit(EXIT_FAILURE);
        }
        if (catchStdErr && dup2(pipePair[1], STDERR_FILENO) == -1) {
            _Exit(EXIT_FAILURE);
        }
        close(pipePair[1]);

        char *argv[cmd.size() + 1U];
        for (std::size_t i = 0; i < cmd.size(); ++i) {
            argv[i] = &cmd[i][0];
        }
        argv[cmd.size()] = nullptr;

        execvp(argv[0], argv);
        _Exit(127);
    }

    close(pipePair[1]);
    io::stream_buffer<io::file_descriptor_source> in(pipePair[0],
                                                     io::close_handle);

    std::ostringstream oss;
    oss << ∈

    int wstatus;
    if (waitpid(pid, &wstatus, 0) == -1) {
        throw std::runtime_error("Failed to wait for process: " +
                                 stringify(cmd));
    }

    if (!WIFEXITED(wstatus)) {
        throw std::runtime_error("Command hasn't finished: " +
                                 stringify(cmd));
    }

    return { oss.str(), WEXITSTATUS(wstatus) };
}

/**
 * @brief Formats command as a string.
 *
 * Shortens it to a reasonable number of arguments if necessary.
 *
 * @param cmd Command to format.
 *
 * @returns Formatted message.
 */
static std::string
stringify(const std::vector<std::string> &cmd)
{
    if (cmd.empty()) {
        return std::string();
    }

    std::ostringstream oss;
    oss << cmd[0];
    for (unsigned int i = 1U; i < cmd.size(); ++i) {
        if (i > 5U && cmd.size() - i > 2U) {
            oss << " {" << cmd.size() - i << " more arguments...}";
            break;
        }
        oss << " {" << cmd[i] << '}';
    }
    return oss.str();
}

bool
isOutputToTerminal()
{
    return isatty(fileno(stdout));
}

std::pair<unsigned int, unsigned int>
getTerminalSize()
{
    winsize ws;
    if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) != 0) {
        return {
            std::numeric_limits<unsigned int>::max(),
            std::numeric_limits<unsigned int>::max()
        };
    }

    return { ws.ws_col, ws.ws_row };
}
<commit_msg>Handle empty command in runProc() explicitly<commit_after>// Copyright (C) 2016 xaizek <xaizek@posteo.net>
//
// This file is part of uncov.
//
// uncov is free software: you can redistribute it and/or modify
// it under the terms of version 3 of the GNU Affero General Public License as
// published by the Free Software Foundation.
//
// uncov is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with uncov.  If not, see <http://www.gnu.org/licenses/>.

#include "integration.hpp"

#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>

#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/scope_exit.hpp>

#include <cstdio>
#include <cstdlib>

#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <utility>
#include <vector>

#include "utils/memory.hpp"

namespace io = boost::iostreams;

namespace {

/**
 * @brief Result of running a command.
 */
struct ProcResult
{
    std::string output; //!< Output @c stdout and optionally @c stderr.
    int exitCode;       //!< Exit code.
};

}

static ProcResult runProc(std::vector<std::string> &&cmd,
                          const std::string &dir, CatchStderr catchStdErr);
static std::string stringify(const std::vector<std::string> &cmd);

/**
 * @brief Base for hidden internals of RedirectToPager class.
 */
class RedirectToPager::Impl
{
public:
    //! Virtual destructor.
    virtual ~Impl() = default;
};

/**
 * @brief Redirects standard output into a pager.
 *
 * The redirection happens only if number of lines exceeds screen height,
 * otherwise lines are just dumped onto the screen as is.
 */
class PagerRedirect : public RedirectToPager::Impl
{
public:
    /**
     * @brief Custom stream buffer that spawns pager for large outputs only.
     *
     * Collect up to terminal height lines.  If buffer is closed with this limit
     * not reached, it prints lines on std::cout.  If we hit the limit in the
     * process of output, it opens a pager and feeds it all collected output and
     * everything that comes next.
     */
    class ScreenPageBuffer
    {
    public:
        //! Type of character used by this buffer.
        using char_type = char;
        //! Category of functionality provided by this buffer implementation.
        using category = io::sink_tag;

    public:
        /**
         * @brief Constructs the buffer.
         *
         * @param screenHeight Height of terminal in lines.
         * @param out Storage for output stream buffer backed up by a file.
         */
        ScreenPageBuffer(unsigned int screenHeight,
                         io::stream_buffer<io::file_descriptor_sink> *out);
        /**
         * @brief Dumps output onto the screen or waits for pager to finish.
         */
        ~ScreenPageBuffer();

    public:
        /**
         * @brief Writes @p n characters from @p s.
         *
         * @param s Character buffer.
         * @param n Size of the buffer.
         *
         * @returns Number of successfully written characters.
         */
        std::streamsize write(const char s[], std::streamsize n);

    private:
        /**
         * @brief Writes single character.
         *
         * @param c Character to write.
         *
         * @returns @c true on success, @c false otherwise.
         */
        bool put(char c);
        /**
         * @brief Opens pager for output.
         */
        void openPager();

    private:
        //! Whether redirection into pager is enabled.
        bool redirectToPager = false;
        //! Number of output lines collected so far.
        unsigned int nLines = 0U;
        //! Height of terminal in lines.
        unsigned int screenHeight;
        //! Output collected so far.
        std::string buffer;
        //! Process id of a pager.
        pid_t pid;

        /**
         * @brief Pointer to buffer stored in RedirectToPager.
         *
         * This is not by value, because ScreenPageBuffer needs to be copyable.
         */
        io::stream_buffer<io::file_descriptor_sink> *out;
    };

public:
    /**
     * @brief Replaces buffer of @c std::cout with ScreenPageBuffer.
     */
    PagerRedirect() : screenPageBuffer(getTerminalSize().second, &out)
    {
        rdbuf = std::cout.rdbuf(&screenPageBuffer);
    }

    /**
     * @brief Restores original buffer of @c std::cout.
     */
    ~PagerRedirect()
    {
        // Flush the stream to make sure that we put all contents we want
        // through the custom stream buffer.
        std::cout.flush();

        std::cout.rdbuf(rdbuf);
    }

private:
    //! This is stored for ScreenPageBuffer class.
    io::stream_buffer<io::file_descriptor_sink> out;
    //! Custom buffer implementation.
    io::stream_buffer<ScreenPageBuffer> screenPageBuffer;
    //! Original buffer of @c std::cout.
    std::streambuf *rdbuf;
};

using ScreenPageBuffer = PagerRedirect::ScreenPageBuffer;

ScreenPageBuffer::ScreenPageBuffer(unsigned int screenHeight,
                               io::stream_buffer<io::file_descriptor_sink> *out)
    : screenHeight(screenHeight), out(out)
{
}

ScreenPageBuffer::~ScreenPageBuffer()
{
    if (redirectToPager) {
        out->close();
        int wstatus;
        waitpid(pid, &wstatus, 0);
    } else {
        std::cout << buffer;
    }
}

std::streamsize
ScreenPageBuffer::write(const char s[], std::streamsize n)
{
    for (std::streamsize i = 0U; i < n; ++i) {
        if (!put(s[i])) {
            return i;
        }
    }
    return n;
}

bool
ScreenPageBuffer::put(char c)
{
    if (redirectToPager) {
        return io::put(*out, c);
    }

    if (c == '\n') {
        ++nLines;
    }

    if (nLines > screenHeight) {
        openPager();
        redirectToPager = true;
        for (char c : buffer) {
            if (!io::put(*out, c)) {
                return false;
            }
        }
        return io::put(*out, c);
    }

    buffer.push_back(c);
    return true;
}

void
ScreenPageBuffer::openPager()
{
    int pipePair[2];
    if (pipe(pipePair) != 0) {
        throw std::runtime_error("Failed to create a pipe");
    }
    BOOST_SCOPE_EXIT_ALL(pipePair) { close(pipePair[0]); };

    pid = fork();
    if (pid == -1) {
        close(pipePair[1]);
        throw std::runtime_error("Fork has failed");
    }
    if (pid == 0) {
        close(pipePair[1]);
        if (dup2(pipePair[0], STDIN_FILENO) == -1) {
            _Exit(EXIT_FAILURE);
        }
        close(pipePair[0]);
        // XXX: hard-coded invocation of less.
        execlp("less", "less", "-R", static_cast<char *>(nullptr));
        _Exit(127);
    }

    out->open(io::file_descriptor_sink(pipePair[1], io::close_handle));
}

RedirectToPager::RedirectToPager()
    : impl(isOutputToTerminal() ? make_unique<PagerRedirect>() : nullptr)
{
}

RedirectToPager::~RedirectToPager()
{
    // Destroy impl with complete type.
}

int
queryProc(std::vector<std::string> &&cmd, const std::string &dir,
          CatchStderr catchStdErr)
{
    return runProc(std::move(cmd), dir, catchStdErr).exitCode;
}

std::string
readProc(std::vector<std::string> &&cmd, const std::string &dir,
         CatchStderr catchStdErr)
{
    ProcResult proc = runProc(std::move(cmd), dir, catchStdErr);
    if (proc.exitCode != EXIT_SUCCESS) {
        throw std::runtime_error("Command has failed: " + stringify(cmd) +
                                 "\nWith output:\n" + proc.output);
    }
    return std::move(proc.output);
}

/**
 * @brief Runs external command.
 *
 * @param cmd Command to run.
 * @param dir Directory to run the command in.
 * @param catchStdErr Whether to redirect @c stderr.
 *
 * @returns Exit code and output of the command.
 *
 * @throws std::runtime_error On empty command, failure to run it or when it
 *                            didn't finish properly.
 */
static ProcResult
runProc(std::vector<std::string> &&cmd, const std::string &dir,
        CatchStderr catchStdErr)
{
    if (cmd.empty()) {
        throw std::runtime_error("Attempt to run an empty command");
    }

    int pipePair[2];
    if (pipe(pipePair) != 0) {
        throw std::runtime_error("Failed to create a pipe");
    }

    pid_t pid = fork();
    if (pid == static_cast<pid_t>(-1)) {
        close(pipePair[0]);
        close(pipePair[1]);
        throw std::runtime_error("Fork has failed");
    }
    if (pid == static_cast<pid_t>(0)) {
        if (chdir(dir.c_str()) != 0) {
            _Exit(EXIT_FAILURE);
        }

        close(pipePair[0]);
        if (dup2(pipePair[1], STDOUT_FILENO) == -1) {
            _Exit(EXIT_FAILURE);
        }
        if (catchStdErr && dup2(pipePair[1], STDERR_FILENO) == -1) {
            _Exit(EXIT_FAILURE);
        }
        close(pipePair[1]);

        char *argv[cmd.size() + 1U];
        for (std::size_t i = 0; i < cmd.size(); ++i) {
            argv[i] = &cmd[i][0];
        }
        argv[cmd.size()] = nullptr;

        execvp(argv[0], argv);
        _Exit(127);
    }

    close(pipePair[1]);
    io::stream_buffer<io::file_descriptor_source> in(pipePair[0],
                                                     io::close_handle);

    std::ostringstream oss;
    oss << ∈

    int wstatus;
    if (waitpid(pid, &wstatus, 0) == -1) {
        throw std::runtime_error("Failed to wait for process: " +
                                 stringify(cmd));
    }

    if (!WIFEXITED(wstatus)) {
        throw std::runtime_error("Command hasn't finished: " +
                                 stringify(cmd));
    }

    return { oss.str(), WEXITSTATUS(wstatus) };
}

/**
 * @brief Formats command as a string.
 *
 * Shortens it to a reasonable number of arguments if necessary.
 *
 * @param cmd Command to format.
 *
 * @returns Formatted message.
 */
static std::string
stringify(const std::vector<std::string> &cmd)
{
    if (cmd.empty()) {
        return std::string();
    }

    std::ostringstream oss;
    oss << cmd[0];
    for (unsigned int i = 1U; i < cmd.size(); ++i) {
        if (i > 5U && cmd.size() - i > 2U) {
            oss << " {" << cmd.size() - i << " more arguments...}";
            break;
        }
        oss << " {" << cmd[i] << '}';
    }
    return oss.str();
}

bool
isOutputToTerminal()
{
    return isatty(fileno(stdout));
}

std::pair<unsigned int, unsigned int>
getTerminalSize()
{
    winsize ws;
    if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) != 0) {
        return {
            std::numeric_limits<unsigned int>::max(),
            std::numeric_limits<unsigned int>::max()
        };
    }

    return { ws.ws_col, ws.ws_row };
}
<|endoftext|>


<commit_before>#include "p0optimize/constant_folding.hpp"
#include "p0optimize/remove_no_ops.hpp"
#include "p0i/emitter.hpp"
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_CASE(remove_no_ops_keeps_return_value)
{
	p0::intermediate::function::instruction_vector original_code;
	{
		p0::intermediate::emitter emitter(original_code);
		emitter.set_constant(0, 2);
		emitter.set_constant(0, 3);
	}
	p0::intermediate::function::instruction_vector const cleaned_code = p0::remove_no_ops(original_code);
	p0::intermediate::function::instruction_vector expected_code;
	{
		p0::intermediate::emitter emitter(expected_code);
		//the value at 0 (the call's result) should not go away
		emitter.set_constant(0, 3);
	}
	BOOST_CHECK(expected_code == cleaned_code);
}

BOOST_AUTO_TEST_CASE(remove_no_ops_set_from_constant)
{
	p0::intermediate::function::instruction_vector original_code;
	{
		p0::intermediate::emitter emitter(original_code);
		emitter.set_constant(1, 2);
		emitter.set_constant(2, 3);
	}
	p0::intermediate::function::instruction_vector const cleaned_code = p0::remove_no_ops(original_code);
	p0::intermediate::function::instruction_vector expected_code;
	BOOST_CHECK(expected_code == cleaned_code);
}

BOOST_AUTO_TEST_CASE(remove_no_ops_nothing)
{
	p0::intermediate::function::instruction_vector original_code;
	{
		p0::intermediate::emitter emitter(original_code);
		emitter.nothing();
	}
	p0::intermediate::function::instruction_vector const cleaned_code = p0::remove_no_ops(original_code);
	p0::intermediate::function::instruction_vector expected_code;
	BOOST_CHECK(expected_code == cleaned_code);
}

BOOST_AUTO_TEST_CASE(fold_constants_add)
{
	p0::intermediate::function::instruction_vector original_code;
	{
		p0::intermediate::emitter emitter(original_code);
		emitter.set_constant(0, 2);
		emitter.set_constant(1, 3);
		emitter.add(0, 1);
	}
	p0::intermediate::function original_function(original_code, 0, 0);
	p0::intermediate::function::instruction_vector const folded_code = p0::fold_constants(original_function);
	p0::intermediate::function::instruction_vector const cleaned_code = p0::remove_no_ops(folded_code);
	p0::intermediate::function::instruction_vector expected_code;
	{
		p0::intermediate::emitter emitter(expected_code);
		emitter.set_constant(0, 5);
	}
	BOOST_CHECK(expected_code == cleaned_code);
}

BOOST_AUTO_TEST_CASE(fold_constants_tree)
{
	p0::intermediate::function::instruction_vector original_code;
	{
		p0::intermediate::emitter emitter(original_code);
		//((2 + 3) + 1) + 1
		emitter.set_constant(0, 2);
		emitter.set_constant(1, 3);
		emitter.add(0, 1);
		emitter.set_constant(1, 1);
		emitter.add(0, 1);
		emitter.set_constant(1, 1);
		emitter.add(0, 1);
	}
	p0::intermediate::function original_function(original_code, 0, 0);
	p0::intermediate::function::instruction_vector const folded_code = p0::fold_constants(original_function);
	p0::intermediate::function::instruction_vector const cleaned_code = p0::remove_no_ops(folded_code);
	p0::intermediate::function::instruction_vector expected_code;
	{
		p0::intermediate::emitter emitter(expected_code);
		emitter.set_constant(0, 7);
	}
	BOOST_CHECK(expected_code == cleaned_code);
}
<commit_msg>test that fold_constants does not try to follow jumps<commit_after>#include "p0optimize/constant_folding.hpp"
#include "p0optimize/remove_no_ops.hpp"
#include "p0i/emitter.hpp"
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_CASE(remove_no_ops_keeps_return_value)
{
	p0::intermediate::function::instruction_vector original_code;
	{
		p0::intermediate::emitter emitter(original_code);
		emitter.set_constant(0, 2);
		emitter.set_constant(0, 3);
	}
	p0::intermediate::function::instruction_vector const cleaned_code = p0::remove_no_ops(original_code);
	p0::intermediate::function::instruction_vector expected_code;
	{
		p0::intermediate::emitter emitter(expected_code);
		//the value at 0 (the call's result) should not go away
		emitter.set_constant(0, 3);
	}
	BOOST_CHECK(expected_code == cleaned_code);
}

BOOST_AUTO_TEST_CASE(remove_no_ops_set_from_constant)
{
	p0::intermediate::function::instruction_vector original_code;
	{
		p0::intermediate::emitter emitter(original_code);
		emitter.set_constant(1, 2);
		emitter.set_constant(2, 3);
	}
	p0::intermediate::function::instruction_vector const cleaned_code = p0::remove_no_ops(original_code);
	p0::intermediate::function::instruction_vector expected_code;
	BOOST_CHECK(expected_code == cleaned_code);
}

BOOST_AUTO_TEST_CASE(remove_no_ops_nothing)
{
	p0::intermediate::function::instruction_vector original_code;
	{
		p0::intermediate::emitter emitter(original_code);
		emitter.nothing();
	}
	p0::intermediate::function::instruction_vector const cleaned_code = p0::remove_no_ops(original_code);
	p0::intermediate::function::instruction_vector expected_code;
	BOOST_CHECK(expected_code == cleaned_code);
}

BOOST_AUTO_TEST_CASE(fold_constants_add)
{
	p0::intermediate::function::instruction_vector original_code;
	{
		p0::intermediate::emitter emitter(original_code);
		emitter.set_constant(0, 2);
		emitter.set_constant(1, 3);
		emitter.add(0, 1);
	}
	p0::intermediate::function original_function(original_code, 0, 0);
	p0::intermediate::function::instruction_vector const folded_code = p0::fold_constants(original_function);
	p0::intermediate::function::instruction_vector const cleaned_code = p0::remove_no_ops(folded_code);
	p0::intermediate::function::instruction_vector expected_code;
	{
		p0::intermediate::emitter emitter(expected_code);
		emitter.set_constant(0, 5);
	}
	BOOST_CHECK(expected_code == cleaned_code);
}

BOOST_AUTO_TEST_CASE(fold_constants_tree)
{
	p0::intermediate::function::instruction_vector original_code;
	{
		p0::intermediate::emitter emitter(original_code);
		//((2 + 3) + 1) + 1
		emitter.set_constant(0, 2);
		emitter.set_constant(1, 3);
		emitter.add(0, 1);
		emitter.set_constant(1, 1);
		emitter.add(0, 1);
		emitter.set_constant(1, 1);
		emitter.add(0, 1);
	}
	p0::intermediate::function original_function(original_code, 0, 0);
	p0::intermediate::function::instruction_vector const folded_code = p0::fold_constants(original_function);
	p0::intermediate::function::instruction_vector const cleaned_code = p0::remove_no_ops(folded_code);
	p0::intermediate::function::instruction_vector expected_code;
	{
		p0::intermediate::emitter emitter(expected_code);
		emitter.set_constant(0, 7);
	}
	BOOST_CHECK(expected_code == cleaned_code);
}

BOOST_AUTO_TEST_CASE(fold_constants_do_not_follow_jump)
{
	p0::intermediate::function::instruction_vector original_code;
	{
		p0::intermediate::emitter emitter(original_code);
		/*0*/ emitter.set_constant(0, 2);
		/*1*/ emitter.set_constant(1, 3); //obsolete
		/*2*/ emitter.jump(6);
		/*3*/ emitter.set_constant(1, 4); //overwrites the write by 1
		/*5*/ emitter.add(0, 1);
		/*4*/ emitter.jump(7);
		/*6*/ emitter.jump(3);
		/*7 return*/
	}
	p0::intermediate::function original_function(original_code, 0, 0);
	p0::intermediate::function::instruction_vector const folded_code = p0::fold_constants(original_function);

	//We expect fold_constants not to follow jump paths. That is the job of earlier passes.
	BOOST_CHECK(original_code == folded_code);
}
<|endoftext|>


<commit_before>/// COMPONENT
#include <csapex/model/node.h>
#include <csapex/msg/io.h>
#include <csapex/param/parameter_factory.h>
#include <csapex/model/node_modifier.h>
#include <csapex/utility/register_apex_plugin.h>
#include <csapex/msg/generic_vector_message.hpp>
#include <csapex/msg/generic_pointer_message.hpp>
#include <csapex_ros/yaml_io.hpp>
#include <csapex_ros/ros_message_conversion.h>
#include <csapex_point_cloud/msg/point_cloud_message.h>
#include <csapex_point_cloud/msg/indices_message.h>
#include <csapex_opencv/roi_message.h>

using namespace csapex::connection_types;

namespace csapex
{

class PointIndicesToROIs : public Node
{
public:
    PointIndicesToROIs()
    {
    }

    void setup(csapex::NodeModifier& modifier) override
    {
        in_cloud_ = modifier.addInput<PointCloudMessage>("PointCloud");
        in_indices_ = modifier.addInput<GenericVectorMessage, pcl::PointIndices>("PointIndices");

        output_rois_ = modifier.addOutput<GenericVectorMessage, RoiMessage>("ROIs");
    }

    void setupParameters(csapex::Parameterizable& params) override
    {
        params.addParameter(param::ParameterFactory::declareValue("fov/x", 60.0), fov_x_);
        params.addParameter(param::ParameterFactory::declareValue("fov/y",  60.0), fov_y_);
        params.addParameter(param::ParameterFactory::declareValue("centre/x", 0), c_x_);
        params.addParameter(param::ParameterFactory::declareValue("centre/y", 0), c_y_);
        params.addParameter(param::ParameterFactory::declareValue("width", 640), w_);
        params.addParameter(param::ParameterFactory::declareValue("height", 480), h_);

        params.addParameter(param::ParameterFactory::declareBool("flip rois", false), flip_rois_);
    }

    void process()
    {
        PointCloudMessage::ConstPtr cloud(msg::getMessage<PointCloudMessage>(in_cloud_));

        clusters_ = msg::getMessage<GenericVectorMessage, pcl::PointIndices>(in_indices_);

        boost::apply_visitor (PointCloudMessage::Dispatch<PointIndicesToROIs>(this, cloud), cloud->value);
    }

    template <class PointT>
    void inputCloud(typename pcl::PointCloud<PointT>::ConstPtr cloud_ptr)
    {
        const pcl::PointCloud<PointT>& cloud = *cloud_ptr;

        bool dense = cloud.width > 1 && cloud.height > 1;

        if(dense) {
            inputDenseCloud<PointT>(cloud_ptr);
        } else  {
            inputSparseCloud<PointT>(cloud_ptr);
        }
    }

    template <class PointT>
    void inputDenseCloud(typename pcl::PointCloud<PointT>::ConstPtr cloud_ptr)
    {
        const pcl::PointCloud<PointT>& cloud = *cloud_ptr;
        std::shared_ptr<std::vector<RoiMessage>> out(new std::vector<RoiMessage>);

        std::size_t w = cloud.width;
//        std::size_t h = cloud.height;

        int cluster_id = 0;
        for (auto cluster = clusters_->begin(); cluster != clusters_->end (); ++cluster, ++cluster_id) {
            auto indices = cluster->indices;

            std::vector<PointT const*> cluster_pts(indices.size());

            {
                double min_col = std::numeric_limits<double>::infinity();
                double max_col = -std::numeric_limits<double>::infinity();
                double min_row = std::numeric_limits<double>::infinity();
                double max_row = -std::numeric_limits<double>::infinity();

                for(auto index = indices.begin(); index != indices.end(); ++index) {
                    int i = *index;
                    int row = i / w;
                    int col = i % w;

                    if(row < min_row) min_row = row;
                    if(row > max_row) max_row = row;
                    if(col < min_col) min_col = col;
                    if(col > max_col) max_col = col;
                }

                RoiMessage roi;

                cv::Rect rect;
                rect.x = min_col;
                rect.y = min_row;
                rect.width  = max_col - min_col;
                rect.height = max_row - min_row;

                if(flip_rois_) {
                    rect.y = h_ - rect.y - rect.height;
                }

                roi.value.setRect(rect);
                roi.value.setColor(cv::Scalar::all(0));
                roi.value.setClassification(0);
                out->push_back(roi);
            }

        }

        msg::publish<GenericVectorMessage, RoiMessage>(output_rois_, out);
    }

    template <class PointT>
    void inputSparseCloud(typename pcl::PointCloud<PointT>::ConstPtr cloud_ptr)
    {
        const pcl::PointCloud<PointT>& cloud = *cloud_ptr;
        std::shared_ptr<std::vector<RoiMessage>> out(new std::vector<RoiMessage>);

        int cluster_id = 0;
        for (auto cluster = clusters_->begin(); cluster != clusters_->end (); ++cluster, ++cluster_id) {
            auto indices = cluster->indices;
            double min_x = std::numeric_limits<double>::infinity();
            double max_x = -std::numeric_limits<double>::infinity();
            double min_y = std::numeric_limits<double>::infinity();
            double max_y = -std::numeric_limits<double>::infinity();

            double max_dist = -std::numeric_limits<double>::infinity();

            for(auto index = indices.begin(); index != indices.end(); ++index) {
                const PointT& pt = cloud.points[*index];

                /*  general:
                 *
                 *            / z
                 *           /
                 *          /
                 *         +-------
                 *         |      x
                 *         |
                 *         | y
                 *
                 *  for us:
                 *
                 *       z |  / x
                 *         | /
                 *         |/
                 *  -------+
                 *   y
                 *
                 */

//                double xx = pt.x;
//                double yy = pt.y;
//                double zz = pt.z;
                double xx = -pt.y;
                double yy = -pt.z;
                double zz = pt.x;

                double x = c_x_ + fov_x_ * xx / zz;
                double y = c_y_ + fov_y_ * yy / zz;

                if(y < min_y) min_y = y;
                if(y > max_y) max_y = y;
                if(x < min_x) min_x = x;
                if(x > max_x) max_x = x;

                if(pt.x > max_dist) max_dist = pt.x;
            }

            RoiMessage roi;
            cv::Rect rect;
            rect.x = min_x;
            rect.y = min_y;
            rect.width  = max_x - min_x;
            rect.height = max_y - min_y;

            if(flip_rois_) {
                rect.y = h_ - rect.y - rect.height;
            }

            roi.value.setRect(rect);
            roi.value.setColor(cv::Scalar(0, 0, max_dist / 10.0 * 255));
            roi.value.setClassification(0);
            out->push_back(roi);
        }

        msg::publish<GenericVectorMessage, RoiMessage>(output_rois_, out);
    }

private:
    Input* in_cloud_;
    Input* in_indices_;
    Output* output_rois_;

    double fov_x_;
    double fov_y_;
    int c_x_;
    int c_y_;
    int w_;
    int h_;

    bool flip_rois_;

    std::shared_ptr<std::vector<pcl::PointIndices> const>  clusters_;
};

}

CSAPEX_REGISTER_CLASS(csapex::PointIndicesToROIs, csapex::Node)

<commit_msg>optional label and classification input in indeces to rois<commit_after>/// COMPONENT
#include <csapex/model/node.h>
#include <csapex/msg/io.h>
#include <csapex/param/parameter_factory.h>
#include <csapex/model/node_modifier.h>
#include <csapex/utility/register_apex_plugin.h>
#include <csapex/msg/generic_vector_message.hpp>
#include <csapex/msg/generic_pointer_message.hpp>
#include <csapex_ros/yaml_io.hpp>
#include <csapex_ros/ros_message_conversion.h>
#include <csapex_point_cloud/msg/point_cloud_message.h>
#include <csapex_point_cloud/msg/indices_message.h>
#include <csapex_opencv/roi_message.h>
#include <csapex/view/utility/color.hpp>
using namespace csapex::connection_types;

namespace csapex
{

class PointIndicesToROIs : public Node
{
public:
    PointIndicesToROIs()
    {
    }

    void setup(csapex::NodeModifier& modifier) override
    {
        in_cloud_ = modifier.addInput<PointCloudMessage>("PointCloud");
        in_indices_ = modifier.addInput<GenericVectorMessage, pcl::PointIndices>("PointIndices");
        in_classification_ = modifier.addOptionalInput<GenericVectorMessage, int>("Classification");
        in_labels_ = modifier.addOptionalInput<GenericVectorMessage, std::string>("Labels");

        output_rois_ = modifier.addOutput<GenericVectorMessage, RoiMessage>("ROIs");
    }

    void setupParameters(csapex::Parameterizable& params) override
    {
        params.addParameter(param::ParameterFactory::declareValue("fov/x", 60.0), fov_x_);
        params.addParameter(param::ParameterFactory::declareValue("fov/y",  60.0), fov_y_);
        params.addParameter(param::ParameterFactory::declareValue("centre/x", 0), c_x_);
        params.addParameter(param::ParameterFactory::declareValue("centre/y", 0), c_y_);
        params.addParameter(param::ParameterFactory::declareValue("width", 640), w_);
        params.addParameter(param::ParameterFactory::declareValue("height", 480), h_);

        params.addParameter(param::ParameterFactory::declareBool("flip rois", false), flip_rois_);
    }

    void process()
    {
        PointCloudMessage::ConstPtr cloud(msg::getMessage<PointCloudMessage>(in_cloud_));

        clusters_ = msg::getMessage<GenericVectorMessage, pcl::PointIndices>(in_indices_);

        if(msg::hasMessage(in_labels_)){
            labels_ = msg::getMessage<GenericVectorMessage, std::string>(in_labels_);
            apex_assert(labels_->size() == clusters_->size());
        }

        if(msg::hasMessage(in_classification_)){
            classification_ = msg::getMessage<GenericVectorMessage, int>(in_classification_);
            apex_assert(classification_->size() == clusters_->size());

            for(auto val : *classification_){
                if(colors_.find(val) == colors_.end()){
                    double r = 0,g = 0,b = 0;
                    color::fromCount(colors_.size(), r,g,b);
                    colors_.insert(std::make_pair(val, cv::Scalar(b,g,r)));
                }
            }
        }

        boost::apply_visitor (PointCloudMessage::Dispatch<PointIndicesToROIs>(this, cloud), cloud->value);

    }

    template <class PointT>
    void inputCloud(typename pcl::PointCloud<PointT>::ConstPtr cloud_ptr)
    {
        const pcl::PointCloud<PointT>& cloud = *cloud_ptr;

        bool dense = cloud.width > 1 && cloud.height > 1;

        if(dense) {
            inputDenseCloud<PointT>(cloud_ptr);
        } else  {
            inputSparseCloud<PointT>(cloud_ptr);
        }
    }

    template <class PointT>
    void inputDenseCloud(typename pcl::PointCloud<PointT>::ConstPtr cloud_ptr)
    {
        const pcl::PointCloud<PointT>& cloud = *cloud_ptr;
        std::shared_ptr<std::vector<RoiMessage>> out(new std::vector<RoiMessage>);

        std::size_t w = cloud.width;
//        std::size_t h = cloud.height;

        int cluster_id = 0;
        std::vector<int>::const_iterator class_label;
        std::vector<std::string>::const_iterator label;

        if(classification_){
            class_label = classification_->begin();
        }

        if(labels_){
            label = labels_->begin();
        }

        for (auto cluster = clusters_->begin(); cluster != clusters_->end (); ++cluster, ++cluster_id) {
            auto indices = cluster->indices;

            std::vector<PointT const*> cluster_pts(indices.size());

            {
                double min_col = std::numeric_limits<double>::infinity();
                double max_col = -std::numeric_limits<double>::infinity();
                double min_row = std::numeric_limits<double>::infinity();
                double max_row = -std::numeric_limits<double>::infinity();

                for(auto index = indices.begin(); index != indices.end(); ++index) {
                    int i = *index;
                    int row = i / w;
                    int col = i % w;

                    if(row < min_row) min_row = row;
                    if(row > max_row) max_row = row;
                    if(col < min_col) min_col = col;
                    if(col > max_col) max_col = col;
                }

                RoiMessage roi;

                cv::Rect rect;
                rect.x = min_col;
                rect.y = min_row;
                rect.width  = max_col - min_col;
                rect.height = max_row - min_row;

                if(flip_rois_) {
                    rect.y = h_ - rect.y - rect.height;
                }

                roi.value.setRect(rect);
                roi.value.setColor(cv::Scalar::all(0));
                if(classification_){
                    roi.value.setClassification(*class_label);
                    roi.value.setColor(colors_[*class_label]);
                    ++class_label;
                }
                else{
                    roi.value.setClassification(0);
                }
                if(labels_){
                    roi.value.setLabel(*label);
                    ++label;
                }
                out->push_back(roi);
            }

        }

        msg::publish<GenericVectorMessage, RoiMessage>(output_rois_, out);

        labels_.reset();
        classification_.reset();

    }

    template <class PointT>
    void inputSparseCloud(typename pcl::PointCloud<PointT>::ConstPtr cloud_ptr)
    {
        const pcl::PointCloud<PointT>& cloud = *cloud_ptr;
        std::shared_ptr<std::vector<RoiMessage>> out(new std::vector<RoiMessage>);

        int cluster_id = 0;
        std::vector<int>::const_iterator class_label;
        std::vector<std::string>::const_iterator label;
        if(classification_){
            class_label = classification_->begin();
        }

        if(labels_){
            label = labels_->begin();
        }
        for (auto cluster = clusters_->begin(); cluster != clusters_->end (); ++cluster, ++cluster_id) {
            auto indices = cluster->indices;
            double min_x = std::numeric_limits<double>::infinity();
            double max_x = -std::numeric_limits<double>::infinity();
            double min_y = std::numeric_limits<double>::infinity();
            double max_y = -std::numeric_limits<double>::infinity();

            double max_dist = -std::numeric_limits<double>::infinity();

            for(auto index = indices.begin(); index != indices.end(); ++index) {
                const PointT& pt = cloud.points[*index];

                /*  general:
                 *
                 *            / z
                 *           /
                 *          /
                 *         +-------
                 *         |      x
                 *         |
                 *         | y
                 *
                 *  for us:
                 *
                 *       z |  / x
                 *         | /
                 *         |/
                 *  -------+
                 *   y
                 *
                 */

//                double xx = pt.x;
//                double yy = pt.y;
//                double zz = pt.z;
                double xx = -pt.y;
                double yy = -pt.z;
                double zz = pt.x;

                double x = c_x_ + fov_x_ * xx / zz;
                double y = c_y_ + fov_y_ * yy / zz;

                if(y < min_y) min_y = y;
                if(y > max_y) max_y = y;
                if(x < min_x) min_x = x;
                if(x > max_x) max_x = x;

                if(pt.x > max_dist) max_dist = pt.x;
            }

            RoiMessage roi;
            cv::Rect rect;
            rect.x = min_x;
            rect.y = min_y;
            rect.width  = max_x - min_x;
            rect.height = max_y - min_y;

            if(flip_rois_) {
                rect.y = h_ - rect.y - rect.height;
            }

            roi.value.setRect(rect);
            roi.value.setColor(cv::Scalar(0, 0, max_dist / 10.0 * 255));
            if(classification_){
                roi.value.setClassification(*class_label);
                roi.value.setColor(colors_[*class_label]);
                ++class_label;
            }
            else{
                roi.value.setClassification(0);
            }
            if(labels_){
                roi.value.setLabel(*label);

                ++label;
            }
            out->push_back(roi);
        }

        msg::publish<GenericVectorMessage, RoiMessage>(output_rois_, out);

        labels_.reset();
        classification_.reset();
    }

private:
    Input* in_cloud_;
    Input* in_indices_;
    Input* in_labels_;
    Input* in_classification_;
    Output* output_rois_;

    double fov_x_;
    double fov_y_;
    int c_x_;
    int c_y_;
    int w_;
    int h_;

    bool flip_rois_;
//    bool use_labels_;
//    bool use_classification_;

    std::shared_ptr<std::vector<pcl::PointIndices> const>  clusters_;
    std::shared_ptr<std::vector<std::string> const> labels_;
    std::shared_ptr<std::vector<int> const> classification_;
    std::map<int, cv::Scalar> colors_;

};

}

CSAPEX_REGISTER_CLASS(csapex::PointIndicesToROIs, csapex::Node)

<|endoftext|>


<commit_before>#include "entity_validator_ui.h"

#include "halley/editor_extensions/entity_validator.h"
using namespace Halley;

EntityValidatorUI::EntityValidatorUI(String id, UIFactory& factory)
	: UIWidget(std::move(id), {}, UISizer())
	, factory(factory)
{
	factory.loadUI(*this, "ui/halley/entity_validator");
	setActive(false);
}

void EntityValidatorUI::setValidator(EntityValidator& v)
{
	validator = &v;
	refresh();
}

void EntityValidatorUI::setEntity(EntityData& e, IEntityEditor& editor)
{
	curEntity = &e;
	entityEditor = &editor;
	refresh();
}

void EntityValidatorUI::refresh()
{
	if (!curEntity || !validator) {
		return;
	}

	auto result = validator->validateEntity(*curEntity);
	if (result != curResultSet) {
		curResultSet = std::move(result);
		setActive(!curResultSet.empty());

		auto parent = getWidget("validationFields");
		parent->clear();

		for (const auto& curResult: curResultSet) {
			auto label = std::make_shared<UILabel>("", factory.getStyle("labelLight"), curResult.errorMessage);
			label->setMaxWidth(300.0f);
			parent->add(label);

			for (const auto& action: curResult.suggestedActions) {
				auto button = std::make_shared<UIButton>("action", factory.getStyle("buttonThin"), action.label);
				button->setHandle(UIEventType::ButtonClicked, [this, actionData = ConfigNode(action.actionData)] (const UIEvent& event)
				{
					validator->applyAction(*entityEditor, *curEntity, actionData);
					entityEditor->reloadEntity();
				});
				parent->add(button);
			}
		}
	}
}
<commit_msg>Fix crash related to event queue in entity validator<commit_after>#include "entity_validator_ui.h"

#include "halley/editor_extensions/entity_validator.h"
using namespace Halley;

EntityValidatorUI::EntityValidatorUI(String id, UIFactory& factory)
	: UIWidget(std::move(id), {}, UISizer())
	, factory(factory)
{
	factory.loadUI(*this, "ui/halley/entity_validator");
	setActive(false);
}

void EntityValidatorUI::setValidator(EntityValidator& v)
{
	validator = &v;
	refresh();
}

void EntityValidatorUI::setEntity(EntityData& e, IEntityEditor& editor)
{
	curEntity = &e;
	entityEditor = &editor;
	refresh();
}

void EntityValidatorUI::refresh()
{
	if (!curEntity || !validator) {
		return;
	}

	auto result = validator->validateEntity(*curEntity);
	if (result != curResultSet) {
		curResultSet = std::move(result);
		setActive(!curResultSet.empty());

		auto parent = getWidget("validationFields");
		parent->clear();

		for (const auto& curResult: curResultSet) {
			auto label = std::make_shared<UILabel>("", factory.getStyle("labelLight"), curResult.errorMessage);
			label->setMaxWidth(300.0f);
			parent->add(label);

			for (const auto& action: curResult.suggestedActions) {
				auto button = std::make_shared<UIButton>("action", factory.getStyle("buttonThin"), action.label);
				button->setHandle(UIEventType::ButtonClicked, [this, actionData = ConfigNode(action.actionData)] (const UIEvent& event)
				{
					Concurrent::execute(Executors::getMainThread(), [=] () {
						validator->applyAction(*entityEditor, *curEntity, actionData);
						entityEditor->reloadEntity();
					});
				});
				parent->add(button);
			}
		}
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

// CLASS HEADER
#include <dali/internal/sensor/tizen/tilt-sensor-impl-tizen.h>
#include <dali/internal/sensor/common/tilt-sensor-factory.h>

// EXTERNAL INCLUDES
#include <cmath>
#include <dali/public-api/object/type-registry.h>
#include <dali/integration-api/debug.h>

// INTERNAL INCLUDES
#include <dali/internal/system/common/singleton-service-impl.h>

namespace // unnamed namespace
{
const char* const SIGNAL_TILTED = "tilted";

const float MAX_ORIENTATION_ROLL_VALUE = 90.f;
const float MAX_ORIENTATION_PITCH_VALUE = 180.f;
const float MAX_ACCELEROMETER_VALUE = 9.8f;

// Type Registration
Dali::BaseHandle Create()
{
  return Dali::Internal::Adaptor::TiltSensorFactory::Get();
}

Dali::TypeRegistration typeRegistration( typeid(Dali::TiltSensor), typeid(Dali::BaseHandle), Create );

Dali::SignalConnectorType signalConnector1( typeRegistration, SIGNAL_TILTED, Dali::Internal::Adaptor::TiltSensor::DoConnectSignal );

} // unnamed namespace

namespace Dali
{

namespace Internal
{

namespace Adaptor
{

#ifdef SENSOR_ENABLED
static void sensor_changed_cb (sensor_h sensor, sensor_event_s *event, void *user_data)
{
  TiltSensorTizen* tiltSensor = reinterpret_cast< TiltSensorTizen* >( user_data );

  if(tiltSensor)
  {
    tiltSensor->Update(event);
  }

  return;
}

static std::string get_sensor_error_string(int errorValue)
{
  std::string ret;

  switch(errorValue)
  {
    case SENSOR_ERROR_IO_ERROR:
      ret = "SENSOR_ERROR_IO_ERROR";
      break;
    case SENSOR_ERROR_INVALID_PARAMETER:
      ret = "SENSOR_ERROR_INVALID_PARAMETER";
      break;
    case SENSOR_ERROR_NOT_SUPPORTED:
      ret = "SENSOR_ERROR_NOT_SUPPORTED";
      break;
    case SENSOR_ERROR_PERMISSION_DENIED:
      ret = "SENSOR_ERROR_PERMISSION_DENIED";
      break;
    case SENSOR_ERROR_OUT_OF_MEMORY:
      ret = "SENSOR_ERROR_OUT_OF_MEMORY";
      break;
    case SENSOR_ERROR_NOT_NEED_CALIBRATION:
      ret = "SENSOR_ERROR_NOT_NEED_CALIBRATION";
      break;
    case SENSOR_ERROR_OPERATION_FAILED:
      ret = "SENSOR_ERROR_OPERATION_FAILED";
      break;
  }

  return ret;
}
#endif

TiltSensorTizen* TiltSensorTizen::New()
{
  return new TiltSensorTizen();
}

TiltSensorTizen::~TiltSensorTizen()
{
  Disconnect();
}

bool TiltSensorTizen::Connect()
{
#ifdef SENSOR_ENABLED
  if(mState != DISCONNECTED)
  {
    Stop();
    Disconnect();
  }

  const int interval = 1000/mFrequencyHertz;

  int ret = 0;
  bool isSupported = false;

  // try to use Orientation sensor at first for less power consumption.
  ret = sensor_is_supported(SENSOR_ORIENTATION, &isSupported);

  if(ret < 0)
  {
    DALI_LOG_ERROR("sensor_is_supported() failed : %s\n", get_sensor_error_string(ret).c_str());
    return false;
  }

  if(isSupported == true)
  {
    mSensorType = SENSOR_ORIENTATION;
  }
  else
  {
    DALI_LOG_ERROR("sensor does not support SENSOR_ORIENTATION\n");

    ret = sensor_is_supported(SENSOR_ACCELEROMETER, &isSupported);

    if(ret < 0)
    {
      DALI_LOG_ERROR("sensor_is_supported() failed : %s\n", get_sensor_error_string(ret).c_str());
      return false;
    }

    if(isSupported == false)
    {
      DALI_LOG_ERROR("sensor does not support both SENSOR_ORIENTATION and SENSOR_ACCELEROMETER\n");
      return false;
    }

    mSensorType = SENSOR_ACCELEROMETER;
  }

  ret = sensor_get_default_sensor(mSensorType, &mSensor); /* mSensor should not be deleted */

  if(ret < 0)
  {
    DALI_LOG_ERROR("sensor_get_default_sensor() failed : %s\n", get_sensor_error_string(ret).c_str());
    return false;
  }

  sensor_create_listener(mSensor, &mSensorListener);
  sensor_listener_set_event_cb(mSensorListener, interval, sensor_changed_cb, this);
  sensor_listener_set_interval(mSensorListener, interval);

  sensor_listener_set_option(mSensorListener, SENSOR_OPTION_DEFAULT /* Not receive data when LCD is off and in power save mode */);

  mState = CONNECTED;

  return true;
#endif

  return false;
}

void TiltSensorTizen::Disconnect()
{
  if(mSensorListener)
  {
    if(mState == STARTED)
    {
      Stop();
    }

    if(mState == STOPPED || mState == CONNECTED)
    {
#ifdef SENSOR_ENABLED
      sensor_listener_unset_event_cb(mSensorListener);
      sensor_listener_stop(mSensorListener);
      sensor_destroy_listener(mSensorListener);
#endif
      mSensor = NULL;
      mSensorListener = NULL;
      mState = DISCONNECTED;
    }
  }
}

bool TiltSensorTizen::Start()
{
  if( mSensorListener && ( mState == CONNECTED || mState == STOPPED ) )
  {
#ifdef SENSOR_ENABLED
    int ret = 0;
    ret = sensor_listener_start(mSensorListener);
    if(ret != SENSOR_ERROR_NONE)
    {
      DALI_LOG_ERROR("sensor_listener_start() failed : %s\n", get_sensor_error_string(ret).c_str());
      Disconnect();
      return false;
    }

    mState = STARTED;
    return true;
#endif
  }
  else
  {
    if( mState == STARTED )
    {
      DALI_LOG_ERROR("TiltSensor is already started. Current state [%d]\n", mState);
    }
    else
    {
      // mState is DISCONNECTED
      DALI_LOG_ERROR("TiltSensor is disconnected. Current state [%d]\n", mState);
    }
    return false;
  }
  return false;
}

void TiltSensorTizen::Stop()
{
#ifdef SENSOR_ENABLED
  if(mSensorListener && mState == STARTED)
  {
    sensor_listener_stop( mSensorListener );
    mState = STOPPED;
  }
#endif
}

bool TiltSensorTizen::IsStarted() const
{
  return ( mSensorListener && mState == STARTED );
}

float TiltSensorTizen::GetRoll() const
{
  return mRoll;
}

float TiltSensorTizen::GetPitch() const
{
  return mPitch;
}

Quaternion TiltSensorTizen::GetRotation() const
{
  return mRotation;
}

TiltSensor::TiltedSignalType& TiltSensorTizen::TiltedSignal()
{
  return mTiltedSignal;
}

void TiltSensorTizen::SetUpdateFrequency( float frequencyHertz )
{
  DALI_ASSERT_ALWAYS( frequencyHertz > 0.0f && "Frequency must have a positive value" );

  if ( fabsf(mFrequencyHertz - frequencyHertz) >= GetRangedEpsilon(mFrequencyHertz, frequencyHertz) )
  {
    mFrequencyHertz = frequencyHertz;

#ifdef SENSOR_ENABLED
    if(mSensorListener)
    {
      const int interval = 1000/mFrequencyHertz;
      sensor_listener_set_interval(mSensorListener, interval);
    }
#endif
  }
}

float TiltSensorTizen::GetUpdateFrequency() const
{
  return mFrequencyHertz;
}

void TiltSensorTizen::SetRotationThreshold(Radian rotationThreshold)
{
  mRotationThreshold = rotationThreshold;
}

Radian TiltSensorTizen::GetRotationThreshold() const
{
  return mRotationThreshold;
}

bool TiltSensorTizen::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
{
  bool connected( true );
  TiltSensor* sensor = dynamic_cast<TiltSensor*>( object );

  if( sensor && SIGNAL_TILTED == signalName )
  {
    sensor->TiltedSignal().Connect( tracker, functor );
  }
  else
  {
    // signalName does not match any signal
    connected = false;
  }

  return connected;
}

TiltSensorTizen::TiltSensorTizen()
: mState(DISCONNECTED),
  mFrequencyHertz( Dali::TiltSensor::DEFAULT_UPDATE_FREQUENCY ),
  mSensor( NULL ),
  mSensorListener( NULL ),
  mRoll( 0.0f ),
  mPitch( 0.0f ),
  mRotation( Radian(0.0f), Vector3::YAXIS ),
  mRotationThreshold( 0.0f )
{
  // connect sensor
  Connect();
}

#ifdef SENSOR_ENABLED
void TiltSensorTizen::Update(sensor_event_s *event)
{
  Radian newRoll( 0.0f );
  Radian newPitch( 0.0f );
  Quaternion newRotation;

  if(mSensorType == SENSOR_ORIENTATION)
  {
    newRoll  = Clamp( float(event->values[2]  / MAX_ORIENTATION_ROLL_VALUE)  /* -90 < roll < 90 */, -1.0f/*min*/, 1.0f/*max*/ );
    newPitch = Clamp( float(event->values[1] / MAX_ORIENTATION_PITCH_VALUE) /* -180 < pitch < 180 */, -1.0f/*min*/, 1.0f/*max*/ );
  }
  else if(mSensorType == SENSOR_ACCELEROMETER)
  {
    newRoll  = Clamp( float(event->values[0] / MAX_ACCELEROMETER_VALUE), -1.0f/*min*/, 1.0f/*max*/ );
    newPitch = Clamp( float(event->values[1] / MAX_ACCELEROMETER_VALUE), -1.0f/*min*/, 1.0f/*max*/ );
  }
  else
  {
    DALI_LOG_ERROR("Invalid sensor type\n");
    return;
  }

  newRotation = Quaternion( Radian( newRoll * Math::PI * -0.5f ), Vector3::YAXIS ) *
              Quaternion( Radian( newPitch * Math::PI * -0.5f ), Vector3::XAXIS );

  Radian angle(Quaternion::AngleBetween(newRotation, mRotation));

  // If the change in value is more than the threshold then emit tilted signal.
  if( angle >= mRotationThreshold )
  {
    mRoll = newRoll;
    mPitch = newPitch;
    mRotation = newRotation;

    // emit signal
    if ( !mTiltedSignal.Empty() )
    {
      Dali::TiltSensor handle( this );
      mTiltedSignal.Emit( handle );
    }
  }
}
#endif // SENSOR_ENABLED

} // namespace Adaptor

} // namespace Internal

} // namespace Dali
<commit_msg>Check the return value in TiltSensor<commit_after>/*
 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

// CLASS HEADER
#include <dali/internal/sensor/tizen/tilt-sensor-impl-tizen.h>
#include <dali/internal/sensor/common/tilt-sensor-factory.h>

// EXTERNAL INCLUDES
#include <cmath>
#include <dali/public-api/object/type-registry.h>
#include <dali/integration-api/debug.h>

// INTERNAL INCLUDES
#include <dali/internal/system/common/singleton-service-impl.h>

namespace // unnamed namespace
{
const char* const SIGNAL_TILTED = "tilted";

const float MAX_ORIENTATION_ROLL_VALUE = 90.f;
const float MAX_ORIENTATION_PITCH_VALUE = 180.f;
const float MAX_ACCELEROMETER_VALUE = 9.8f;

// Type Registration
Dali::BaseHandle Create()
{
  return Dali::Internal::Adaptor::TiltSensorFactory::Get();
}

Dali::TypeRegistration typeRegistration( typeid(Dali::TiltSensor), typeid(Dali::BaseHandle), Create );

Dali::SignalConnectorType signalConnector1( typeRegistration, SIGNAL_TILTED, Dali::Internal::Adaptor::TiltSensor::DoConnectSignal );

} // unnamed namespace

namespace Dali
{

namespace Internal
{

namespace Adaptor
{

#ifdef SENSOR_ENABLED
static void sensor_changed_cb (sensor_h sensor, sensor_event_s *event, void *user_data)
{
  TiltSensorTizen* tiltSensor = reinterpret_cast< TiltSensorTizen* >( user_data );

  if(tiltSensor)
  {
    tiltSensor->Update(event);
  }

  return;
}

static std::string get_sensor_error_string(int errorValue)
{
  std::string ret;

  switch(errorValue)
  {
    case SENSOR_ERROR_IO_ERROR:
      ret = "SENSOR_ERROR_IO_ERROR";
      break;
    case SENSOR_ERROR_INVALID_PARAMETER:
      ret = "SENSOR_ERROR_INVALID_PARAMETER";
      break;
    case SENSOR_ERROR_NOT_SUPPORTED:
      ret = "SENSOR_ERROR_NOT_SUPPORTED";
      break;
    case SENSOR_ERROR_PERMISSION_DENIED:
      ret = "SENSOR_ERROR_PERMISSION_DENIED";
      break;
    case SENSOR_ERROR_OUT_OF_MEMORY:
      ret = "SENSOR_ERROR_OUT_OF_MEMORY";
      break;
    case SENSOR_ERROR_NOT_NEED_CALIBRATION:
      ret = "SENSOR_ERROR_NOT_NEED_CALIBRATION";
      break;
    case SENSOR_ERROR_OPERATION_FAILED:
      ret = "SENSOR_ERROR_OPERATION_FAILED";
      break;
  }

  return ret;
}
#endif

TiltSensorTizen* TiltSensorTizen::New()
{
  return new TiltSensorTizen();
}

TiltSensorTizen::~TiltSensorTizen()
{
  Disconnect();
}

bool TiltSensorTizen::Connect()
{
#ifdef SENSOR_ENABLED
  if(mState != DISCONNECTED)
  {
    Stop();
    Disconnect();
  }

  const int interval = 1000/mFrequencyHertz;

  int ret = 0;
  bool isSupported = false;

  // try to use Orientation sensor at first for less power consumption.
  ret = sensor_is_supported(SENSOR_ORIENTATION, &isSupported);

  if(ret < 0)
  {
    DALI_LOG_ERROR("sensor_is_supported() failed : %s\n", get_sensor_error_string(ret).c_str());
    return false;
  }

  if(isSupported == true)
  {
    mSensorType = SENSOR_ORIENTATION;
  }
  else
  {
    DALI_LOG_ERROR("sensor does not support SENSOR_ORIENTATION\n");

    ret = sensor_is_supported(SENSOR_ACCELEROMETER, &isSupported);

    if(ret < 0)
    {
      DALI_LOG_ERROR("sensor_is_supported() failed : %s\n", get_sensor_error_string(ret).c_str());
      return false;
    }

    if(isSupported == false)
    {
      DALI_LOG_ERROR("sensor does not support both SENSOR_ORIENTATION and SENSOR_ACCELEROMETER\n");
      return false;
    }

    mSensorType = SENSOR_ACCELEROMETER;
  }

  ret = sensor_get_default_sensor(mSensorType, &mSensor); /* mSensor should not be deleted */

  if(ret < 0)
  {
    DALI_LOG_ERROR("sensor_get_default_sensor() failed : %s\n", get_sensor_error_string(ret).c_str());
    return false;
  }

  ret = sensor_create_listener(mSensor, &mSensorListener);

  if(ret < 0)
  {
    DALI_LOG_ERROR("sensor_create_listener() failed : %s\n", get_sensor_error_string(ret).c_str());
    return false;
  }

  sensor_listener_set_event_cb(mSensorListener, interval, sensor_changed_cb, this);
  sensor_listener_set_interval(mSensorListener, interval);

  sensor_listener_set_option(mSensorListener, SENSOR_OPTION_DEFAULT /* Not receive data when LCD is off and in power save mode */);

  mState = CONNECTED;

  return true;
#endif

  return false;
}

void TiltSensorTizen::Disconnect()
{
  if(mSensorListener)
  {
    if(mState == STARTED)
    {
      Stop();
    }

    if(mState == STOPPED || mState == CONNECTED)
    {
#ifdef SENSOR_ENABLED
      sensor_listener_unset_event_cb(mSensorListener);
      sensor_listener_stop(mSensorListener);
      sensor_destroy_listener(mSensorListener);
#endif
      mSensor = NULL;
      mSensorListener = NULL;
      mState = DISCONNECTED;
    }
  }
}

bool TiltSensorTizen::Start()
{
  if( mSensorListener && ( mState == CONNECTED || mState == STOPPED ) )
  {
#ifdef SENSOR_ENABLED
    int ret = 0;
    ret = sensor_listener_start(mSensorListener);
    if(ret != SENSOR_ERROR_NONE)
    {
      DALI_LOG_ERROR("sensor_listener_start() failed : %s\n", get_sensor_error_string(ret).c_str());
      Disconnect();
      return false;
    }

    mState = STARTED;
    return true;
#endif
  }
  else
  {
    if( mState == STARTED )
    {
      DALI_LOG_ERROR("TiltSensor is already started. Current state [%d]\n", mState);
    }
    else
    {
      // mState is DISCONNECTED
      DALI_LOG_ERROR("TiltSensor is disconnected. Current state [%d]\n", mState);
    }
    return false;
  }
  return false;
}

void TiltSensorTizen::Stop()
{
#ifdef SENSOR_ENABLED
  if(mSensorListener && mState == STARTED)
  {
    sensor_listener_stop( mSensorListener );
    mState = STOPPED;
  }
#endif
}

bool TiltSensorTizen::IsStarted() const
{
  return ( mSensorListener && mState == STARTED );
}

float TiltSensorTizen::GetRoll() const
{
  return mRoll;
}

float TiltSensorTizen::GetPitch() const
{
  return mPitch;
}

Quaternion TiltSensorTizen::GetRotation() const
{
  return mRotation;
}

TiltSensor::TiltedSignalType& TiltSensorTizen::TiltedSignal()
{
  return mTiltedSignal;
}

void TiltSensorTizen::SetUpdateFrequency( float frequencyHertz )
{
  DALI_ASSERT_ALWAYS( frequencyHertz > 0.0f && "Frequency must have a positive value" );

  if ( fabsf(mFrequencyHertz - frequencyHertz) >= GetRangedEpsilon(mFrequencyHertz, frequencyHertz) )
  {
    mFrequencyHertz = frequencyHertz;

#ifdef SENSOR_ENABLED
    if(mSensorListener)
    {
      const int interval = 1000/mFrequencyHertz;
      sensor_listener_set_interval(mSensorListener, interval);
    }
#endif
  }
}

float TiltSensorTizen::GetUpdateFrequency() const
{
  return mFrequencyHertz;
}

void TiltSensorTizen::SetRotationThreshold(Radian rotationThreshold)
{
  mRotationThreshold = rotationThreshold;
}

Radian TiltSensorTizen::GetRotationThreshold() const
{
  return mRotationThreshold;
}

bool TiltSensorTizen::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
{
  bool connected( true );
  TiltSensor* sensor = dynamic_cast<TiltSensor*>( object );

  if( sensor && SIGNAL_TILTED == signalName )
  {
    sensor->TiltedSignal().Connect( tracker, functor );
  }
  else
  {
    // signalName does not match any signal
    connected = false;
  }

  return connected;
}

TiltSensorTizen::TiltSensorTizen()
: mState(DISCONNECTED),
  mFrequencyHertz( Dali::TiltSensor::DEFAULT_UPDATE_FREQUENCY ),
  mSensor( NULL ),
  mSensorListener( NULL ),
  mRoll( 0.0f ),
  mPitch( 0.0f ),
  mRotation( Radian(0.0f), Vector3::YAXIS ),
  mRotationThreshold( 0.0f )
{
  // connect sensor
  Connect();
}

#ifdef SENSOR_ENABLED
void TiltSensorTizen::Update(sensor_event_s *event)
{
  Radian newRoll( 0.0f );
  Radian newPitch( 0.0f );
  Quaternion newRotation;

  if(mSensorType == SENSOR_ORIENTATION)
  {
    newRoll  = Clamp( float(event->values[2]  / MAX_ORIENTATION_ROLL_VALUE)  /* -90 < roll < 90 */, -1.0f/*min*/, 1.0f/*max*/ );
    newPitch = Clamp( float(event->values[1] / MAX_ORIENTATION_PITCH_VALUE) /* -180 < pitch < 180 */, -1.0f/*min*/, 1.0f/*max*/ );
  }
  else if(mSensorType == SENSOR_ACCELEROMETER)
  {
    newRoll  = Clamp( float(event->values[0] / MAX_ACCELEROMETER_VALUE), -1.0f/*min*/, 1.0f/*max*/ );
    newPitch = Clamp( float(event->values[1] / MAX_ACCELEROMETER_VALUE), -1.0f/*min*/, 1.0f/*max*/ );
  }
  else
  {
    DALI_LOG_ERROR("Invalid sensor type\n");
    return;
  }

  newRotation = Quaternion( Radian( newRoll * Math::PI * -0.5f ), Vector3::YAXIS ) *
              Quaternion( Radian( newPitch * Math::PI * -0.5f ), Vector3::XAXIS );

  Radian angle(Quaternion::AngleBetween(newRotation, mRotation));

  // If the change in value is more than the threshold then emit tilted signal.
  if( angle >= mRotationThreshold )
  {
    mRoll = newRoll;
    mPitch = newPitch;
    mRotation = newRotation;

    // emit signal
    if ( !mTiltedSignal.Empty() )
    {
      Dali::TiltSensor handle( this );
      mTiltedSignal.Emit( handle );
    }
  }
}
#endif // SENSOR_ENABLED

} // namespace Adaptor

} // namespace Internal

} // namespace Dali
<|endoftext|>