<commit_before>//
//  ObjLoader.cpp
//  KickObjLoader
//
//  Created by morten on 8/31/13.
//  Copyright (c) 2013 morten. All rights reserved.
//

#include "ObjLoad.h"
#include <fstream>
#include <string>
#include <cstring>
#include <sstream>
#include <cerrno>
#include "glm/ext.hpp"

using namespace std;
using namespace glm;

namespace kick {
    // from http://stackoverflow.com/questions/2602013/read-whole-ascii-file-into-c-stdstring
    string getFileContents(string filename)
    {
        ifstream in{filename, ios::in | ios::binary};
        if (in)
        {
            std::string contents;
            in.seekg(0, std::ios::end);
            contents.resize(in.tellg());
            in.seekg(0, std::ios::beg);
            in.read(&contents[0], contents.size());
            in.close();
            return contents;
        }
        throw(errno);
    }

    vec4 toVec4(vector<string> &tokens){
        vec4 res{0,0,0,1};
        for (int i=0;i<4;i++){
            if (i+1 < tokens.size()){
                res[i] = atof(tokens[i+1].c_str());
            }
        }
        return res;
    }

    vec3 toVec3(vector<string> &tokens){
        vec3 res{0,0,0};
        for (int i=0;i<3;i++){
            if (i+1 < tokens.size()){
                res[i] = atof(tokens[i+1].c_str());
            }
        }
        return res;
    }

    bool replace(std::string& str, const std::string& from, const std::string& to) {
        size_t start_pos = str.find(from);
        if(start_pos == std::string::npos)
            return false;
        str.replace(start_pos, from.length(), to);
        return true;
    }

    ObjFace toObjFace(vector<string> &tokens){
        ObjFace res;
        for (int i=1; i<tokens.size(); i++) {
            string & p = tokens[i];
            replace(p, "//","/0/");

            ObjVertex o{0,0,0};

            stringstream ss{p};
            char buffer[50];

            ss.getline(buffer,50, '/');
            o.vertexPositionIdx = atoi(buffer);
            if (ss.good()){
                ss.getline(buffer,50, '/');
                o.textureIdx = atoi(buffer);
            }
            if (ss.good()){
                ss.getline(buffer,50, '/');
                o.normalIdx = atoi(buffer);
            }
            res.push_back(o);
        }
        return move(res);
    }

    void parseMaterialLib(std::string & materialLib, ObjData & dest){
        const int bufferSize = 256;
        char buffer[bufferSize];
        char buffer2[bufferSize];
        stringstream ss{materialLib};

        while (ss.good()){
            ss.getline(buffer, bufferSize);
            stringstream likeTokensizer{buffer};
            vector<string> tokens;
            while (likeTokensizer.good()) {
                likeTokensizer.getline(buffer2, bufferSize, ' ');
                tokens.push_back(buffer2);
            }
            if (tokens.size()==0){
                continue;
            }
            if (tokens[0] == "newmtl"){
                vec3 zero{0,0,0};
                ObjMaterial material{tokens[1],zero,zero,zero,50,1};
                dest.materials.push_back(material);
            } else {
                if (dest.materials.size()==0){
                    continue;
                }
                ObjMaterial & currentMat = dest.materials.back();
                if (tokens[0] == "Ka"){
                    currentMat.ambientColor = toVec3(tokens);
                } else if (tokens[0] == "Kd"){
                    currentMat.diffuseColor = toVec3(tokens);
                } else if (tokens[0] == "Ks"){
                    currentMat.specularColor = toVec3(tokens);
                } else if (tokens[0] == "d"){
                    currentMat.transparent = atoi(tokens[1].c_str());
                } else if (tokens[0] == "illum"){
                    int illumMode = atoi(tokens[1].c_str());
                    currentMat.illuminationModes.push_back(static_cast<ObjIlluminationMode>(illumMode));
                } else if (tokens[0] == "map_Ka"){

                } else if (tokens[0] == "map_Kd"){
                } else if (tokens[0] == "map_Ks"){
                } else if (tokens[0] == "map_Ns"){
                } else if (tokens[0] == "map_d"){
                } else if (tokens[0] == "map_bump" || tokens[0] == "bump" ){
                } else if (tokens[0] == "map_disp" || tokens[0] == "disp" ){
                } else if (tokens[0] == "map_decal" || tokens[0] == "decal" ){
                }
            }
        }
    }

    ObjData loadObjData(std::string objSource, std::function<std::string (std::string)> materialMap){
        ObjData res;
        stringstream ss{objSource};
        const int bufferSize = 256;
        char buffer[bufferSize];
        char buffer2[bufferSize];
        bool initialComment = true;
        while (ss.good()){
            ss.getline(buffer, bufferSize);
            cout << buffer << endl;
            stringstream likeTokensizer{buffer};
            vector<string> tokens;
            while (likeTokensizer.good()) {
                likeTokensizer.getline(buffer2, bufferSize, ' ');
                tokens.push_back(buffer2);
            }
            if (tokens.size()==0){
                continue;
            }
            initialComment = initialComment && (tokens[0] == "#");
            int currentIndex = static_cast<int>(res.faces.size()) + 1;
            if (tokens[0] == "#"){ // comment
                if (initialComment){
                    res.initialComment += string(buffer + 2) + "\n";
                }
            } else if (tokens[0] == "v"){ // vertex position
                vec4 vertexPosition = toVec4(tokens);
                res.vertexPositions.push_back(vertexPosition);
            } else if (tokens[0] == "vt"){ // vertex texture coordinates
                vec3 textureCoord = toVec3(tokens);
                res.textureCoords.push_back(textureCoord);
            } else if (tokens[0] == "vn"){ // vertex normal
                vec3 normal = toVec3(tokens);
                res.normals.push_back(normal);
            } else if (tokens[0] == "f"){ // face
                res.faces.push_back(toObjFace(tokens));
            } else if (tokens[0] == "mtllib"){ // material library
                string materialLib = materialMap(tokens[1]);
                parseMaterialLib(materialLib, res);
            } else if (tokens[0] == "usemtl"){ // use material
                res.materialChanges.push_back({currentIndex, tokens[1]});
            } else if (tokens[0] == "o"){ // named object
                res.namedObjects.push_back({currentIndex, tokens[1]});
            } else if (tokens[0] == "g"){ // polygon group
                res.polygonGroups.push_back({currentIndex, tokens[1]});
            } else if (tokens[0] == "s"){ // smoothing groups
                int smoothingGroup = 0; // 0 = no smoothing
                if (tokens[1] != "off"){
                    smoothingGroup = atoi(tokens[1].c_str());
                }
                res.smoothGroups.push_back({currentIndex, smoothingGroup});
            }
        }

        return res;
    }

    std::string fixPathEnd(std::string &path){
        char lastChar = path[path.length()-1];
        if (lastChar != '/'){
            return path + "/";
        }
        return path;
    }

    ObjData loadObjData(std::string path, std::string filename){
        path = fixPathEnd(path);
        string file = getFileContents(path+filename);
        std::function<std::string (std::string)>  materialLoader = [&](string filename){
            return getFileContents(path+filename);
        };
        return loadObjData(file, materialLoader);
    }
}<commit_msg>Update ObjLoad.cpp<commit_after>//
//  ObjLoader.cpp
//  KickObjLoader
//
//  Created by morten on 8/31/13.
//  Copyright (c) 2013 morten. All rights reserved.
//

#include "ObjLoad.h"
#include <fstream>
#include <string>
#include <cstring>
#include <sstream>
#include <cerrno>
#include "glm/ext.hpp"

using namespace std;
using namespace glm;

namespace kick {
    // from http://stackoverflow.com/questions/2602013/read-whole-ascii-file-into-c-stdstring
    string getFileContents(string filename)
    {
        ifstream in{filename, ios::in | ios::binary};
        if (in)
        {
            std::string contents;
            in.seekg(0, std::ios::end);
            contents.resize(in.tellg());
            in.seekg(0, std::ios::beg);
            in.read(&contents[0], contents.size());
            in.close();
            return contents;
        }
        throw(errno);
    }

    vec4 toVec4(vector<string> &tokens){
        vec4 res{0,0,0,1};
        for (int i=0;i<4;i++){
            if (i+1 < tokens.size()){
                res[i] = atof(tokens[i+1].c_str());
            }
        }
        return res;
    }

    vec3 toVec3(vector<string> &tokens){
        vec3 res{0,0,0};
        for (int i=0;i<3;i++){
            if (i+1 < tokens.size()){
                res[i] = atof(tokens[i+1].c_str());
            }
        }
        return res;
    }

    // replace first occurrence of from in str with to
    bool replace(std::string& str, const std::string& from, const std::string& to) {
        size_t start_pos = str.find(from);
        if(start_pos == std::string::npos)
            return false;
        str.replace(start_pos, from.length(), to);
        return true;
    }

    ObjFace toObjFace(vector<string> &tokens){
        ObjFace res;
        for (int i=1; i<tokens.size(); i++) {
            string & p = tokens[i];
            replace(p, "//","/0/");

            ObjVertex o{0,0,0};

            stringstream ss{p};
            char buffer[50];

            ss.getline(buffer,50, '/');
            o.vertexPositionIdx = atoi(buffer);
            if (ss.good()){
                ss.getline(buffer,50, '/');
                o.textureIdx = atoi(buffer);
            }
            if (ss.good()){
                ss.getline(buffer,50, '/');
                o.normalIdx = atoi(buffer);
            }
            res.push_back(o);
        }
        return move(res);
    }

    void parseMaterialLib(std::string & materialLib, ObjData & dest){
        const int bufferSize = 256;
        char buffer[bufferSize];
        char buffer2[bufferSize];
        stringstream ss{materialLib};

        while (ss.good()){
            ss.getline(buffer, bufferSize);
            stringstream likeTokensizer{buffer};
            vector<string> tokens;
            while (likeTokensizer.good()) {
                likeTokensizer.getline(buffer2, bufferSize, ' ');
                tokens.push_back(buffer2);
            }
            if (tokens.size()==0){
                continue;
            }
            if (tokens[0] == "newmtl"){
                vec3 zero{0,0,0};
                ObjMaterial material{tokens[1],zero,zero,zero,50,1};
                dest.materials.push_back(material);
            } else {
                if (dest.materials.size()==0){
                    continue;
                }
                ObjMaterial & currentMat = dest.materials.back();
                if (tokens[0] == "Ka"){
                    currentMat.ambientColor = toVec3(tokens);
                } else if (tokens[0] == "Kd"){
                    currentMat.diffuseColor = toVec3(tokens);
                } else if (tokens[0] == "Ks"){
                    currentMat.specularColor = toVec3(tokens);
                } else if (tokens[0] == "d"){
                    currentMat.transparent = atoi(tokens[1].c_str());
                } else if (tokens[0] == "illum"){
                    int illumMode = atoi(tokens[1].c_str());
                    currentMat.illuminationModes.push_back(static_cast<ObjIlluminationMode>(illumMode));
                } else if (tokens[0] == "map_Ka"){

                } else if (tokens[0] == "map_Kd"){
                } else if (tokens[0] == "map_Ks"){
                } else if (tokens[0] == "map_Ns"){
                } else if (tokens[0] == "map_d"){
                } else if (tokens[0] == "map_bump" || tokens[0] == "bump" ){
                } else if (tokens[0] == "map_disp" || tokens[0] == "disp" ){
                } else if (tokens[0] == "map_decal" || tokens[0] == "decal" ){
                }
            }
        }
    }

    ObjData loadObjData(std::string objSource, std::function<std::string (std::string)> materialMap){
        ObjData res;
        stringstream ss{objSource};
        const int bufferSize = 256;
        char buffer[bufferSize];
        char buffer2[bufferSize];
        bool initialComment = true;
        while (ss.good()){
            ss.getline(buffer, bufferSize);
            cout << buffer << endl;
            stringstream likeTokensizer{buffer};
            vector<string> tokens;
            while (likeTokensizer.good()) {
                likeTokensizer.getline(buffer2, bufferSize, ' ');
                tokens.push_back(buffer2);
            }
            if (tokens.size()==0){
                continue;
            }
            initialComment = initialComment && (tokens[0] == "#");
            int currentIndex = static_cast<int>(res.faces.size()) + 1;
            if (tokens[0] == "#"){ // comment
                if (initialComment){
                    res.initialComment += string(buffer + 2) + "\n";
                }
            } else if (tokens[0] == "v"){ // vertex position
                vec4 vertexPosition = toVec4(tokens);
                res.vertexPositions.push_back(vertexPosition);
            } else if (tokens[0] == "vt"){ // vertex texture coordinates
                vec3 textureCoord = toVec3(tokens);
                res.textureCoords.push_back(textureCoord);
            } else if (tokens[0] == "vn"){ // vertex normal
                vec3 normal = toVec3(tokens);
                res.normals.push_back(normal);
            } else if (tokens[0] == "f"){ // face
                res.faces.push_back(toObjFace(tokens));
            } else if (tokens[0] == "mtllib"){ // material library
                string materialLib = materialMap(tokens[1]);
                parseMaterialLib(materialLib, res);
            } else if (tokens[0] == "usemtl"){ // use material
                res.materialChanges.push_back({currentIndex, tokens[1]});
            } else if (tokens[0] == "o"){ // named object
                res.namedObjects.push_back({currentIndex, tokens[1]});
            } else if (tokens[0] == "g"){ // polygon group
                res.polygonGroups.push_back({currentIndex, tokens[1]});
            } else if (tokens[0] == "s"){ // smoothing groups
                int smoothingGroup = 0; // 0 = no smoothing
                if (tokens[1] != "off"){
                    smoothingGroup = atoi(tokens[1].c_str());
                }
                res.smoothGroups.push_back({currentIndex, smoothingGroup});
            }
        }

        return res;
    }

    std::string fixPathEnd(std::string &path){
        char lastChar = path[path.length()-1];
        if (lastChar != '/'){
            return path + "/";
        }
        return path;
    }

    ObjData loadObjData(std::string path, std::string filename){
        path = fixPathEnd(path);
        string file = getFileContents(path+filename);
        std::function<std::string (std::string)>  materialLoader = [&](string filename){
            return getFileContents(path+filename);
        };
        return loadObjData(file, materialLoader);
    }
}
<|endoftext|>


<commit_before>/**
 * \file  calibration.cc
 * \brief
 *
 * \author  Piyush Khandelwal (piyushk@cs.utexas.edu)
 * Copyright (C) 2012, Austin Robot Technology, The University of Texas at Austin
 *
 * License: Modified BSD License
 *
 * $ Id: 02/14/2012 11:36:36 AM piyushk $
 */

#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
#include <limits>
#include <yaml-cpp/yaml.h>

#ifdef HAVE_NEW_YAMLCPP
namespace YAML {

  // The >> operator disappeared in yaml-cpp 0.5, so this function is
  // added to provide support for code written under the yaml-cpp 0.3 API.
  template<typename T>
  void operator >> (const YAML::Node& node, T& i) {
    i = node.as<T>();
  }
} /* YAML */
#endif

#include <ros/ros.h>
#include <velodyne_pointcloud/calibration.h>

namespace velodyne_pointcloud {

  const std::string NUM_LASERS = "num_lasers";
  const std::string LASERS = "lasers";
  const std::string LASER_ID = "laser_id";
  const std::string ROT_CORRECTION = "rot_correction";
  const std::string VERT_CORRECTION = "vert_correction";
  const std::string DIST_CORRECTION = "dist_correction";
  const std::string TWO_PT_CORRECTION_AVAILABLE = "two_pt_correction_available";
  const std::string DIST_CORRECTION_X = "dist_correction_x";
  const std::string DIST_CORRECTION_Y = "dist_correction_y";
  const std::string VERT_OFFSET_CORRECTION = "vert_offset_correction";
  const std::string HORIZ_OFFSET_CORRECTION = "vert_offset_correction";
  const std::string MAX_INTENSITY = "max_intensity";
  const std::string MIN_INTENSITY = "min_intensity";
  const std::string FOCAL_DISTANCE = "focal_distance";
  const std::string FOCAL_SLOPE = "focal_slope";

  void operator >> (const YAML::Node& node, std::pair<int, LaserCorrection>& correction) {
    node[LASER_ID] >> correction.first;
    node[ROT_CORRECTION] >> correction.second.rot_correction;
    node[VERT_CORRECTION] >> correction.second.vert_correction;
    node[DIST_CORRECTION] >> correction.second.dist_correction;
#ifdef HAVE_NEW_YAMLCPP
    if (node[TWO_PT_CORRECTION_AVAILABLE])
      node[TWO_PT_CORRECTION_AVAILABLE] >> correction.second.two_pt_correction_available;
#else
    if (const YAML::Node *pName = node.FindValue(TWO_PT_CORRECTION_AVAILABLE))
      *pName >> correction.second.two_pt_correction_available;
#endif
    else
      correction.second.two_pt_correction_available = false;
    node[DIST_CORRECTION_X] >> correction.second.dist_correction_x;
    node[DIST_CORRECTION_Y] >> correction.second.dist_correction_y;
    node[VERT_OFFSET_CORRECTION] >> correction.second.vert_offset_correction;
    node[HORIZ_OFFSET_CORRECTION] >> correction.second.horiz_offset_correction;
#ifdef HAVE_NEW_YAMLCPP
    if (node[MAX_INTENSITY])
      node[MAX_INTENSITY] >> correction.second.max_intensity;
#else
    if (const YAML::Node *pName = node.FindValue(MAX_INTENSITY))
      *pName >> correction.second.max_intensity;
#endif
    else
      correction.second.max_intensity = 255;
#ifdef HAVE_NEW_YAMLCPP
    if (node[MIN_INTENSITY])
      node[MIN_INTENSITY] >> correction.second.min_intensity;
#else
    if (const YAML::Node *pName = node.FindValue(MIN_INTENSITY))
      *pName >> correction.second.min_intensity;
#endif
    else
      correction.second.min_intensity = 0;
    node[FOCAL_DISTANCE] >> correction.second.focal_distance;
    node[FOCAL_SLOPE] >> correction.second.focal_slope;

    // Calculate cached values
    correction.second.cos_rot_correction = cosf(correction.second.rot_correction);
    correction.second.sin_rot_correction = sinf(correction.second.rot_correction);
    correction.second.cos_vert_correction = cosf(correction.second.vert_correction);
    correction.second.sin_vert_correction = sinf(correction.second.vert_correction);

    correction.second.laser_ring = 0;   // clear initially (set later)
  }

  void operator >> (const YAML::Node& node, Calibration& calibration) {
    int num_lasers;
    node[NUM_LASERS] >> num_lasers;
    const YAML::Node& lasers = node[LASERS];
    calibration.laser_corrections.clear();
    for (int i = 0; i < num_lasers; i++) {
      std::pair<int, LaserCorrection> correction;
      lasers[i] >> correction;
      calibration.laser_corrections.insert(correction);
    }

    // For each laser ring, find the next-smallest vertical angle.
    //
    // This implementation is simple, but not efficient.  That is OK,
    // since it only runs while starting up.
    double next_angle = -std::numeric_limits<double>::infinity();
    for (int ring = 0; ring < num_lasers; ++ring) {

      // find minimum remaining vertical offset correction
      double min_seen = std::numeric_limits<double>::infinity();
      int next_index = num_lasers;
      for (int j = 0; j < num_lasers; ++j) {

        double angle = calibration.laser_corrections[j].vert_correction;
        if (next_angle < angle && angle < min_seen) {
          min_seen = angle;
          next_index = j;
        }
      }

      if (next_index < num_lasers) {    // anything found in this ring?

        // store this ring number with its corresponding laser number
        calibration.laser_corrections[next_index].laser_ring = ring;
        next_angle = min_seen;
        ROS_INFO_STREAM("laser_ring[" << next_index << "] = " << ring
                         << ", angle = " << next_angle);
      }
    }
  }

  YAML::Emitter& operator << (YAML::Emitter& out, const std::pair<int, LaserCorrection> correction) {
    out << YAML::BeginMap;
    out << YAML::Key << LASER_ID << YAML::Value << correction.first;
    out << YAML::Key << ROT_CORRECTION << YAML::Value << correction.second.rot_correction;
    out << YAML::Key << VERT_CORRECTION << YAML::Value << correction.second.vert_correction;
    out << YAML::Key << DIST_CORRECTION << YAML::Value << correction.second.dist_correction;
    out << YAML::Key << TWO_PT_CORRECTION_AVAILABLE << YAML::Value << correction.second.two_pt_correction_available;
    out << YAML::Key << DIST_CORRECTION_X << YAML::Value << correction.second.dist_correction_x;
    out << YAML::Key << DIST_CORRECTION_Y << YAML::Value << correction.second.dist_correction_y;
    out << YAML::Key << VERT_OFFSET_CORRECTION << YAML::Value << correction.second.vert_offset_correction;
    out << YAML::Key << HORIZ_OFFSET_CORRECTION << YAML::Value << correction.second.horiz_offset_correction;
    out << YAML::Key << MAX_INTENSITY << YAML::Value << correction.second.max_intensity;
    out << YAML::Key << MIN_INTENSITY << YAML::Value << correction.second.min_intensity;
    out << YAML::Key << FOCAL_DISTANCE << YAML::Value << correction.second.focal_distance;
    out << YAML::Key << FOCAL_SLOPE << YAML::Value << correction.second.focal_slope;
    out << YAML::EndMap;
    return out;
  }

  YAML::Emitter& operator << (YAML::Emitter& out, const Calibration& calibration) {
    out << YAML::BeginMap;
    out << YAML::Key << NUM_LASERS << YAML::Value << calibration.laser_corrections.size();
    out << YAML::Key << LASERS << YAML::Value << YAML::BeginSeq;
    for (std::map<int, LaserCorrection>::const_iterator it = calibration.laser_corrections.begin();
         it != calibration.laser_corrections.end(); it++) {
      out << *it;
    }
    out << YAML::EndSeq;
    out << YAML::EndMap;
    return out;
  }

  void Calibration::read(const std::string& calibration_file) {
    std::ifstream fin(calibration_file.c_str());
    if (!fin.is_open()) {
      initialized = false;
      return;
    }
    initialized = true;
    try {
      YAML::Node doc;
#ifdef HAVE_NEW_YAMLCPP
      fin.close();
      doc = YAML::LoadFile(calibration_file);
#else
      YAML::Parser parser(fin);
      parser.GetNextDocument(doc);
#endif
      doc >> *this;
    } catch (YAML::Exception &e) {
      std::cerr << "YAML Exception: " << e.what() << std::endl;
      initialized = false;
    }
    fin.close();
  }

  void Calibration::write(const std::string& calibration_file) {
    std::ofstream fout(calibration_file.c_str());
    YAML::Emitter out;
    out << *this;
    fout << out.c_str();
    fout.close();
  }

} /* velodyne_pointcloud */
<commit_msg>fixed a calibration file parsing bug<commit_after>/**
 * \file  calibration.cc
 * \brief
 *
 * \author  Piyush Khandelwal (piyushk@cs.utexas.edu)
 * Copyright (C) 2012, Austin Robot Technology, The University of Texas at Austin
 *
 * License: Modified BSD License
 *
 * $ Id: 02/14/2012 11:36:36 AM piyushk $
 */

#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
#include <limits>
#include <yaml-cpp/yaml.h>

#ifdef HAVE_NEW_YAMLCPP
namespace YAML {

  // The >> operator disappeared in yaml-cpp 0.5, so this function is
  // added to provide support for code written under the yaml-cpp 0.3 API.
  template<typename T>
  void operator >> (const YAML::Node& node, T& i) {
    i = node.as<T>();
  }
} /* YAML */
#endif

#include <ros/ros.h>
#include <velodyne_pointcloud/calibration.h>

namespace velodyne_pointcloud {

  const std::string NUM_LASERS = "num_lasers";
  const std::string LASERS = "lasers";
  const std::string LASER_ID = "laser_id";
  const std::string ROT_CORRECTION = "rot_correction";
  const std::string VERT_CORRECTION = "vert_correction";
  const std::string DIST_CORRECTION = "dist_correction";
  const std::string TWO_PT_CORRECTION_AVAILABLE = "two_pt_correction_available";
  const std::string DIST_CORRECTION_X = "dist_correction_x";
  const std::string DIST_CORRECTION_Y = "dist_correction_y";
  const std::string VERT_OFFSET_CORRECTION = "vert_offset_correction";
  const std::string HORIZ_OFFSET_CORRECTION = "horiz_offset_correction";
  const std::string MAX_INTENSITY = "max_intensity";
  const std::string MIN_INTENSITY = "min_intensity";
  const std::string FOCAL_DISTANCE = "focal_distance";
  const std::string FOCAL_SLOPE = "focal_slope";

  void operator >> (const YAML::Node& node, std::pair<int, LaserCorrection>& correction) {
    node[LASER_ID] >> correction.first;
    node[ROT_CORRECTION] >> correction.second.rot_correction;
    node[VERT_CORRECTION] >> correction.second.vert_correction;
    node[DIST_CORRECTION] >> correction.second.dist_correction;
#ifdef HAVE_NEW_YAMLCPP
    if (node[TWO_PT_CORRECTION_AVAILABLE])
      node[TWO_PT_CORRECTION_AVAILABLE] >> correction.second.two_pt_correction_available;
#else
    if (const YAML::Node *pName = node.FindValue(TWO_PT_CORRECTION_AVAILABLE))
      *pName >> correction.second.two_pt_correction_available;
#endif
    else
      correction.second.two_pt_correction_available = false;
    node[DIST_CORRECTION_X] >> correction.second.dist_correction_x;
    node[DIST_CORRECTION_Y] >> correction.second.dist_correction_y;
    node[VERT_OFFSET_CORRECTION] >> correction.second.vert_offset_correction;
    node[HORIZ_OFFSET_CORRECTION] >> correction.second.horiz_offset_correction;
#ifdef HAVE_NEW_YAMLCPP
    if (node[MAX_INTENSITY])
      node[MAX_INTENSITY] >> correction.second.max_intensity;
#else
    if (const YAML::Node *pName = node.FindValue(MAX_INTENSITY))
      *pName >> correction.second.max_intensity;
#endif
    else
      correction.second.max_intensity = 255;
#ifdef HAVE_NEW_YAMLCPP
    if (node[MIN_INTENSITY])
      node[MIN_INTENSITY] >> correction.second.min_intensity;
#else
    if (const YAML::Node *pName = node.FindValue(MIN_INTENSITY))
      *pName >> correction.second.min_intensity;
#endif
    else
      correction.second.min_intensity = 0;
    node[FOCAL_DISTANCE] >> correction.second.focal_distance;
    node[FOCAL_SLOPE] >> correction.second.focal_slope;

    // Calculate cached values
    correction.second.cos_rot_correction = cosf(correction.second.rot_correction);
    correction.second.sin_rot_correction = sinf(correction.second.rot_correction);
    correction.second.cos_vert_correction = cosf(correction.second.vert_correction);
    correction.second.sin_vert_correction = sinf(correction.second.vert_correction);

    correction.second.laser_ring = 0;   // clear initially (set later)
  }

  void operator >> (const YAML::Node& node, Calibration& calibration) {
    int num_lasers;
    node[NUM_LASERS] >> num_lasers;
    const YAML::Node& lasers = node[LASERS];
    calibration.laser_corrections.clear();
    for (int i = 0; i < num_lasers; i++) {
      std::pair<int, LaserCorrection> correction;
      lasers[i] >> correction;
      calibration.laser_corrections.insert(correction);
    }

    // For each laser ring, find the next-smallest vertical angle.
    //
    // This implementation is simple, but not efficient.  That is OK,
    // since it only runs while starting up.
    double next_angle = -std::numeric_limits<double>::infinity();
    for (int ring = 0; ring < num_lasers; ++ring) {

      // find minimum remaining vertical offset correction
      double min_seen = std::numeric_limits<double>::infinity();
      int next_index = num_lasers;
      for (int j = 0; j < num_lasers; ++j) {

        double angle = calibration.laser_corrections[j].vert_correction;
        if (next_angle < angle && angle < min_seen) {
          min_seen = angle;
          next_index = j;
        }
      }

      if (next_index < num_lasers) {    // anything found in this ring?

        // store this ring number with its corresponding laser number
        calibration.laser_corrections[next_index].laser_ring = ring;
        next_angle = min_seen;
        ROS_INFO_STREAM("laser_ring[" << next_index << "] = " << ring
                         << ", angle = " << next_angle);
      }
    }
  }

  YAML::Emitter& operator << (YAML::Emitter& out, const std::pair<int, LaserCorrection> correction) {
    out << YAML::BeginMap;
    out << YAML::Key << LASER_ID << YAML::Value << correction.first;
    out << YAML::Key << ROT_CORRECTION << YAML::Value << correction.second.rot_correction;
    out << YAML::Key << VERT_CORRECTION << YAML::Value << correction.second.vert_correction;
    out << YAML::Key << DIST_CORRECTION << YAML::Value << correction.second.dist_correction;
    out << YAML::Key << TWO_PT_CORRECTION_AVAILABLE << YAML::Value << correction.second.two_pt_correction_available;
    out << YAML::Key << DIST_CORRECTION_X << YAML::Value << correction.second.dist_correction_x;
    out << YAML::Key << DIST_CORRECTION_Y << YAML::Value << correction.second.dist_correction_y;
    out << YAML::Key << VERT_OFFSET_CORRECTION << YAML::Value << correction.second.vert_offset_correction;
    out << YAML::Key << HORIZ_OFFSET_CORRECTION << YAML::Value << correction.second.horiz_offset_correction;
    out << YAML::Key << MAX_INTENSITY << YAML::Value << correction.second.max_intensity;
    out << YAML::Key << MIN_INTENSITY << YAML::Value << correction.second.min_intensity;
    out << YAML::Key << FOCAL_DISTANCE << YAML::Value << correction.second.focal_distance;
    out << YAML::Key << FOCAL_SLOPE << YAML::Value << correction.second.focal_slope;
    out << YAML::EndMap;
    return out;
  }

  YAML::Emitter& operator << (YAML::Emitter& out, const Calibration& calibration) {
    out << YAML::BeginMap;
    out << YAML::Key << NUM_LASERS << YAML::Value << calibration.laser_corrections.size();
    out << YAML::Key << LASERS << YAML::Value << YAML::BeginSeq;
    for (std::map<int, LaserCorrection>::const_iterator it = calibration.laser_corrections.begin();
         it != calibration.laser_corrections.end(); it++) {
      out << *it;
    }
    out << YAML::EndSeq;
    out << YAML::EndMap;
    return out;
  }

  void Calibration::read(const std::string& calibration_file) {
    std::ifstream fin(calibration_file.c_str());
    if (!fin.is_open()) {
      initialized = false;
      return;
    }
    initialized = true;
    try {
      YAML::Node doc;
#ifdef HAVE_NEW_YAMLCPP
      fin.close();
      doc = YAML::LoadFile(calibration_file);
#else
      YAML::Parser parser(fin);
      parser.GetNextDocument(doc);
#endif
      doc >> *this;
    } catch (YAML::Exception &e) {
      std::cerr << "YAML Exception: " << e.what() << std::endl;
      initialized = false;
    }
    fin.close();
  }

  void Calibration::write(const std::string& calibration_file) {
    std::ofstream fout(calibration_file.c_str());
    YAML::Emitter out;
    out << *this;
    fout << out.c_str();
    fout.close();
  }

} /* velodyne_pointcloud */
<|endoftext|>


<commit_before>
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * 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.
 */

#include "tools/trace_to_text/local_symbolizer.h"

#include "perfetto/ext/base/string_splitter.h"
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/ext/base/utils.h"

#include <elf.h>
#include <inttypes.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

namespace perfetto {
namespace trace_to_text {

namespace {

std::vector<std::string> GetLines(FILE* f) {
  std::vector<std::string> lines;
  size_t n = 0;
  char* line = nullptr;
  ssize_t rd = 0;
  do {
    rd = getline(&line, &n, f);
    // Do not read empty line that terminates the output.
    if (rd > 1) {
      // Remove newline character.
      PERFETTO_DCHECK(line[rd - 1] == '\n');
      line[rd - 1] = '\0';
      lines.emplace_back(line);
    }
    free(line);
    line = nullptr;
    n = 0;
  } while (rd > 1);
  return lines;
}

struct Elf32 {
  using Ehdr = Elf32_Ehdr;
  using Shdr = Elf32_Shdr;
  using Nhdr = Elf32_Nhdr;
};

struct Elf64 {
  using Ehdr = Elf64_Ehdr;
  using Shdr = Elf64_Shdr;
  using Nhdr = Elf64_Nhdr;
};

template <typename E>
typename E::Shdr* GetShdr(void* mem, const typename E::Ehdr* ehdr, size_t i) {
  return reinterpret_cast<typename E::Shdr*>(
      static_cast<char*>(mem) + ehdr->e_shoff + i * sizeof(typename E::Shdr));
}

bool InRange(const void* base,
             size_t total_size,
             const void* ptr,
             size_t size) {
  return ptr >= base && static_cast<const char*>(ptr) + size <=
                            static_cast<const char*>(base) + total_size;
}

template <typename E>
base::Optional<std::string> GetBuildId(void* mem, size_t size) {
  const typename E::Ehdr* ehdr = static_cast<typename E::Ehdr*>(mem);
  if (!InRange(mem, size, ehdr, sizeof(typename E::Ehdr))) {
    PERFETTO_ELOG("Corrupted ELF.");
    return base::nullopt;
  }
  for (size_t i = 0; i < ehdr->e_shnum; ++i) {
    typename E::Shdr* shdr = GetShdr<E>(mem, ehdr, i);
    if (!InRange(mem, size, shdr, sizeof(typename E::Shdr))) {
      PERFETTO_ELOG("Corrupted ELF.");
      return base::nullopt;
    }

    if (shdr->sh_type != SHT_NOTE)
      continue;

    auto offset = shdr->sh_offset;
    while (offset < shdr->sh_offset + shdr->sh_size) {
      typename E::Nhdr* nhdr =
          reinterpret_cast<typename E::Nhdr*>(static_cast<char*>(mem) + offset);

      if (!InRange(mem, size, nhdr, sizeof(typename E::Nhdr))) {
        PERFETTO_ELOG("Corrupted ELF.");
        return base::nullopt;
      }
      if (nhdr->n_type == NT_GNU_BUILD_ID && nhdr->n_namesz == 4) {
        char* name = reinterpret_cast<char*>(nhdr) + sizeof(*nhdr);
        if (!InRange(mem, size, name, 4)) {
          PERFETTO_ELOG("Corrupted ELF.");
          return base::nullopt;
        }
        if (memcmp(name, "GNU", 3) == 0) {
          const char* value = reinterpret_cast<char*>(nhdr) + sizeof(*nhdr) +
                              base::AlignUp<4>(nhdr->n_namesz);

          if (!InRange(mem, size, value, nhdr->n_descsz)) {
            PERFETTO_ELOG("Corrupted ELF.");
            return base::nullopt;
          }
          return std::string(value, nhdr->n_descsz);
        }
      }
      offset += sizeof(*nhdr) + base::AlignUp<4>(nhdr->n_namesz) +
                base::AlignUp<4>(nhdr->n_descsz);
    }
  }
  return base::nullopt;
}

class ScopedMmap {
 public:
  ScopedMmap(void* addr,
             size_t length,
             int prot,
             int flags,
             int fd,
             off_t offset)
      : length_(length), ptr_(mmap(addr, length, prot, flags, fd, offset)) {}
  ~ScopedMmap() {
    if (ptr_ != MAP_FAILED)
      munmap(ptr_, length_);
  }

  void* operator*() { return ptr_; }

 private:
  size_t length_;
  void* ptr_;
};

bool ParseLine(std::string line, std::string* file_name, uint32_t* line_no) {
  base::StringSplitter sp(std::move(line), ':');
  if (!sp.Next())
    return false;
  *file_name = sp.cur_token();
  if (!sp.Next())
    return false;
  char* endptr;
  auto parsed_line_no = strtoll(sp.cur_token(), &endptr, 10);
  if (parsed_line_no >= 0)
    *line_no = static_cast<uint32_t>(parsed_line_no);
  return *endptr == '\0' && parsed_line_no >= 0;
}

std::string SplitBuildID(const std::string& hex_build_id) {
  if (hex_build_id.size() < 3) {
    PERFETTO_DFATAL_OR_ELOG("Invalid build-id (< 3 char) %s",
                            hex_build_id.c_str());
    return {};
  }

  return hex_build_id.substr(0, 2) + "/" + hex_build_id.substr(2);
}

}  // namespace

base::Optional<std::string> LocalBinaryFinder::FindBinary(
    const std::string& abspath,
    const std::string& build_id) {
  auto p = cache_.emplace(abspath, base::nullopt);
  if (!p.second)
    return p.first->second;

  base::Optional<std::string>& cache_entry = p.first->second;

  for (const std::string& root_str : roots_) {
    cache_entry = FindBinaryInRoot(root_str, abspath, build_id);
    if (cache_entry)
      return cache_entry;
  }
  PERFETTO_ELOG("Could not find %s.", abspath.c_str());
  return cache_entry;
}

bool LocalBinaryFinder::IsCorrectFile(const std::string& symbol_file,
                                      const std::string& build_id) {
  base::ScopedFile fd(base::OpenFile(symbol_file, O_RDONLY));
  if (!fd)
    return false;

  struct stat statbuf;
  if (fstat(*fd, &statbuf) == -1)
    return false;

  size_t size = static_cast<size_t>(statbuf.st_size);

  if (size <= EI_CLASS)
    return false;

  ScopedMmap map(nullptr, size, PROT_READ, MAP_PRIVATE, *fd, 0);
  if (*map == MAP_FAILED) {
    PERFETTO_PLOG("mmap");
    return false;
  }
  char* mem = static_cast<char*>(*map);

  if (mem[EI_MAG0] != ELFMAG0 || mem[EI_MAG1] != ELFMAG1 ||
      mem[EI_MAG2] != ELFMAG2 || mem[EI_MAG3] != ELFMAG3) {
    return false;
  }

  switch (mem[EI_CLASS]) {
    case ELFCLASS32:
      return build_id == GetBuildId<Elf32>(mem, size);
    case ELFCLASS64:
      return build_id == GetBuildId<Elf64>(mem, size);
    default:
      return false;
  }
}

base::Optional<std::string> LocalBinaryFinder::FindBinaryInRoot(
    const std::string& root_str,
    const std::string& abspath,
    const std::string& build_id) {
  constexpr char kApkPrefix[] = "base.apk!";

  std::string filename;
  std::string dirname;

  for (base::StringSplitter sp(abspath, '/'); sp.Next();) {
    if (!dirname.empty())
      dirname += "/";
    dirname += filename;
    filename = sp.cur_token();
  }

  // Return the first match for the following options:
  // * absolute path of library file relative to root.
  // * absolute path of library file relative to root, but with base.apk!
  //   removed from filename.
  // * only filename of library file relative to root.
  // * only filename of library file relative to root, but with base.apk!
  //   removed from filename.
  // * in the subdirectory .build-id: the first two hex digits of the build-id
  //   as subdirectory, then the rest of the hex digits, with ".debug"appended.
  //   See
  //   https://fedoraproject.org/wiki/RolandMcGrath/BuildID#Find_files_by_build_ID
  //
  // For example, "/system/lib/base.apk!foo.so" with build id abcd1234,
  // is looked for at
  // * $ROOT/system/lib/base.apk!foo.so
  // * $ROOT/system/lib/foo.so
  // * $ROOT/base.apk!foo.so
  // * $ROOT/foo.so
  // * $ROOT/.build-id/ab/cd1234.debug

  std::string symbol_file = root_str + "/" + dirname + "/" + filename;
  if (access(symbol_file.c_str(), F_OK) == 0 &&
      IsCorrectFile(symbol_file, build_id))
    return {symbol_file};

  if (filename.find(kApkPrefix) == 0) {
    symbol_file =
        root_str + "/" + dirname + "/" + filename.substr(sizeof(kApkPrefix));
    if (access(symbol_file.c_str(), F_OK) == 0 &&
        IsCorrectFile(symbol_file, build_id))
      return {symbol_file};
  }

  symbol_file = root_str + "/" + filename;
  if (access(symbol_file.c_str(), F_OK) == 0 &&
      IsCorrectFile(symbol_file, build_id))
    return {symbol_file};

  if (filename.find(kApkPrefix) == 0) {
    symbol_file = root_str + "/" + filename.substr(sizeof(kApkPrefix));
    if (access(symbol_file.c_str(), F_OK) == 0 &&
        IsCorrectFile(symbol_file, build_id))
      return {symbol_file};
  }

  std::string hex_build_id = base::ToHex(build_id.c_str(), build_id.size());
  std::string split_hex_build_id = SplitBuildID(hex_build_id);
  if (!split_hex_build_id.empty()) {
    symbol_file =
        root_str + "/" + ".build-id" + "/" + split_hex_build_id + ".debug";
    if (access(symbol_file.c_str(), F_OK) == 0 &&
        IsCorrectFile(symbol_file, build_id))
      return {symbol_file};
  }

  return base::nullopt;
}

Subprocess::Subprocess(const std::string& file, std::vector<std::string> args)
    : input_pipe_(base::Pipe::Create(base::Pipe::kBothBlock)),
      output_pipe_(base::Pipe::Create(base::Pipe::kBothBlock)) {
  std::vector<char*> c_str_args(args.size() + 1, nullptr);
  for (std::string& arg : args)
    c_str_args.push_back(&(arg[0]));

  if ((pid_ = fork()) == 0) {
    // Child
    PERFETTO_CHECK(dup2(*input_pipe_.rd, STDIN_FILENO) != -1);
    PERFETTO_CHECK(dup2(*output_pipe_.wr, STDOUT_FILENO) != -1);
    input_pipe_.wr.reset();
    output_pipe_.rd.reset();
    PERFETTO_CHECK(execvp(file.c_str(), &(c_str_args[0])) != -1);
  }
  PERFETTO_CHECK(pid_ != -1);
  input_pipe_.rd.reset();
  output_pipe_.wr.reset();
}

Subprocess::~Subprocess() {
  if (pid_ != -1) {
    kill(pid_, SIGKILL);
    int wstatus;
    waitpid(pid_, &wstatus, 0);
  }
}

LLVMSymbolizerProcess::LLVMSymbolizerProcess()
    : subprocess_("llvm-symbolizer", {"llvm-symbolizer"}),
      read_file_(fdopen(subprocess_.read_fd(), "r")) {}

std::vector<SymbolizedFrame> LLVMSymbolizerProcess::Symbolize(
    const std::string& binary,
    uint64_t address) {
  std::vector<SymbolizedFrame> result;

  if (PERFETTO_EINTR(dprintf(subprocess_.write_fd(), "%s 0x%" PRIx64 "\n",
                             binary.c_str(), address)) < 0) {
    PERFETTO_ELOG("Failed to write to llvm-symbolizer.");
    return result;
  }
  auto lines = GetLines(read_file_);
  // llvm-symbolizer writes out records in the form of
  // Foo(Bar*)
  // foo.cc:123
  // This is why we should always get a multiple of two number of lines.
  PERFETTO_DCHECK(lines.size() % 2 == 0);
  result.resize(lines.size() / 2);
  for (size_t i = 0; i < lines.size(); ++i) {
    SymbolizedFrame& cur = result[i / 2];
    if (i % 2 == 0) {
      cur.function_name = lines[i];
    } else {
      if (!ParseLine(lines[i], &cur.file_name, &cur.line)) {
        PERFETTO_ELOG("Failed to parse llvm-symbolizer line: %s",
                      lines[i].c_str());
        cur.file_name = "";
        cur.line = 0;
      }
    }
  }

  for (auto it = result.begin(); it != result.end();) {
    if (it->function_name == "??")
      it = result.erase(it);
    else
      ++it;
  }
  return result;
}
std::vector<std::vector<SymbolizedFrame>> LocalSymbolizer::Symbolize(
    const std::string& mapping_name,
    const std::string& build_id,
    const std::vector<uint64_t>& addresses) {
  base::Optional<std::string> binary =
      finder_.FindBinary(mapping_name, build_id);
  if (!binary)
    return {};
  std::vector<std::vector<SymbolizedFrame>> result;
  result.reserve(addresses.size());
  for (uint64_t address : addresses)
    result.emplace_back(llvm_symbolizer_.Symbolize(*binary, address));
  return result;
}

LocalSymbolizer::~LocalSymbolizer() = default;

}  // namespace trace_to_text
}  // namespace perfetto
<commit_msg>Log Build ID when so was not found.<commit_after>
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * 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.
 */

#include "tools/trace_to_text/local_symbolizer.h"

#include "perfetto/ext/base/string_splitter.h"
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/ext/base/utils.h"

#include <elf.h>
#include <inttypes.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

namespace perfetto {
namespace trace_to_text {

namespace {

std::vector<std::string> GetLines(FILE* f) {
  std::vector<std::string> lines;
  size_t n = 0;
  char* line = nullptr;
  ssize_t rd = 0;
  do {
    rd = getline(&line, &n, f);
    // Do not read empty line that terminates the output.
    if (rd > 1) {
      // Remove newline character.
      PERFETTO_DCHECK(line[rd - 1] == '\n');
      line[rd - 1] = '\0';
      lines.emplace_back(line);
    }
    free(line);
    line = nullptr;
    n = 0;
  } while (rd > 1);
  return lines;
}

struct Elf32 {
  using Ehdr = Elf32_Ehdr;
  using Shdr = Elf32_Shdr;
  using Nhdr = Elf32_Nhdr;
};

struct Elf64 {
  using Ehdr = Elf64_Ehdr;
  using Shdr = Elf64_Shdr;
  using Nhdr = Elf64_Nhdr;
};

template <typename E>
typename E::Shdr* GetShdr(void* mem, const typename E::Ehdr* ehdr, size_t i) {
  return reinterpret_cast<typename E::Shdr*>(
      static_cast<char*>(mem) + ehdr->e_shoff + i * sizeof(typename E::Shdr));
}

bool InRange(const void* base,
             size_t total_size,
             const void* ptr,
             size_t size) {
  return ptr >= base && static_cast<const char*>(ptr) + size <=
                            static_cast<const char*>(base) + total_size;
}

template <typename E>
base::Optional<std::string> GetBuildId(void* mem, size_t size) {
  const typename E::Ehdr* ehdr = static_cast<typename E::Ehdr*>(mem);
  if (!InRange(mem, size, ehdr, sizeof(typename E::Ehdr))) {
    PERFETTO_ELOG("Corrupted ELF.");
    return base::nullopt;
  }
  for (size_t i = 0; i < ehdr->e_shnum; ++i) {
    typename E::Shdr* shdr = GetShdr<E>(mem, ehdr, i);
    if (!InRange(mem, size, shdr, sizeof(typename E::Shdr))) {
      PERFETTO_ELOG("Corrupted ELF.");
      return base::nullopt;
    }

    if (shdr->sh_type != SHT_NOTE)
      continue;

    auto offset = shdr->sh_offset;
    while (offset < shdr->sh_offset + shdr->sh_size) {
      typename E::Nhdr* nhdr =
          reinterpret_cast<typename E::Nhdr*>(static_cast<char*>(mem) + offset);

      if (!InRange(mem, size, nhdr, sizeof(typename E::Nhdr))) {
        PERFETTO_ELOG("Corrupted ELF.");
        return base::nullopt;
      }
      if (nhdr->n_type == NT_GNU_BUILD_ID && nhdr->n_namesz == 4) {
        char* name = reinterpret_cast<char*>(nhdr) + sizeof(*nhdr);
        if (!InRange(mem, size, name, 4)) {
          PERFETTO_ELOG("Corrupted ELF.");
          return base::nullopt;
        }
        if (memcmp(name, "GNU", 3) == 0) {
          const char* value = reinterpret_cast<char*>(nhdr) + sizeof(*nhdr) +
                              base::AlignUp<4>(nhdr->n_namesz);

          if (!InRange(mem, size, value, nhdr->n_descsz)) {
            PERFETTO_ELOG("Corrupted ELF.");
            return base::nullopt;
          }
          return std::string(value, nhdr->n_descsz);
        }
      }
      offset += sizeof(*nhdr) + base::AlignUp<4>(nhdr->n_namesz) +
                base::AlignUp<4>(nhdr->n_descsz);
    }
  }
  return base::nullopt;
}

class ScopedMmap {
 public:
  ScopedMmap(void* addr,
             size_t length,
             int prot,
             int flags,
             int fd,
             off_t offset)
      : length_(length), ptr_(mmap(addr, length, prot, flags, fd, offset)) {}
  ~ScopedMmap() {
    if (ptr_ != MAP_FAILED)
      munmap(ptr_, length_);
  }

  void* operator*() { return ptr_; }

 private:
  size_t length_;
  void* ptr_;
};

bool ParseLine(std::string line, std::string* file_name, uint32_t* line_no) {
  base::StringSplitter sp(std::move(line), ':');
  if (!sp.Next())
    return false;
  *file_name = sp.cur_token();
  if (!sp.Next())
    return false;
  char* endptr;
  auto parsed_line_no = strtoll(sp.cur_token(), &endptr, 10);
  if (parsed_line_no >= 0)
    *line_no = static_cast<uint32_t>(parsed_line_no);
  return *endptr == '\0' && parsed_line_no >= 0;
}

std::string SplitBuildID(const std::string& hex_build_id) {
  if (hex_build_id.size() < 3) {
    PERFETTO_DFATAL_OR_ELOG("Invalid build-id (< 3 char) %s",
                            hex_build_id.c_str());
    return {};
  }

  return hex_build_id.substr(0, 2) + "/" + hex_build_id.substr(2);
}

}  // namespace

base::Optional<std::string> LocalBinaryFinder::FindBinary(
    const std::string& abspath,
    const std::string& build_id) {
  auto p = cache_.emplace(abspath, base::nullopt);
  if (!p.second)
    return p.first->second;

  base::Optional<std::string>& cache_entry = p.first->second;

  for (const std::string& root_str : roots_) {
    cache_entry = FindBinaryInRoot(root_str, abspath, build_id);
    if (cache_entry)
      return cache_entry;
  }
  PERFETTO_ELOG("Could not find %s (Build ID: %s).", abspath.c_str(),
                base::ToHex(build_id).c_str());
  return cache_entry;
}

bool LocalBinaryFinder::IsCorrectFile(const std::string& symbol_file,
                                      const std::string& build_id) {
  base::ScopedFile fd(base::OpenFile(symbol_file, O_RDONLY));
  if (!fd)
    return false;

  struct stat statbuf;
  if (fstat(*fd, &statbuf) == -1)
    return false;

  size_t size = static_cast<size_t>(statbuf.st_size);

  if (size <= EI_CLASS)
    return false;

  ScopedMmap map(nullptr, size, PROT_READ, MAP_PRIVATE, *fd, 0);
  if (*map == MAP_FAILED) {
    PERFETTO_PLOG("mmap");
    return false;
  }
  char* mem = static_cast<char*>(*map);

  if (mem[EI_MAG0] != ELFMAG0 || mem[EI_MAG1] != ELFMAG1 ||
      mem[EI_MAG2] != ELFMAG2 || mem[EI_MAG3] != ELFMAG3) {
    return false;
  }

  switch (mem[EI_CLASS]) {
    case ELFCLASS32:
      return build_id == GetBuildId<Elf32>(mem, size);
    case ELFCLASS64:
      return build_id == GetBuildId<Elf64>(mem, size);
    default:
      return false;
  }
}

base::Optional<std::string> LocalBinaryFinder::FindBinaryInRoot(
    const std::string& root_str,
    const std::string& abspath,
    const std::string& build_id) {
  constexpr char kApkPrefix[] = "base.apk!";

  std::string filename;
  std::string dirname;

  for (base::StringSplitter sp(abspath, '/'); sp.Next();) {
    if (!dirname.empty())
      dirname += "/";
    dirname += filename;
    filename = sp.cur_token();
  }

  // Return the first match for the following options:
  // * absolute path of library file relative to root.
  // * absolute path of library file relative to root, but with base.apk!
  //   removed from filename.
  // * only filename of library file relative to root.
  // * only filename of library file relative to root, but with base.apk!
  //   removed from filename.
  // * in the subdirectory .build-id: the first two hex digits of the build-id
  //   as subdirectory, then the rest of the hex digits, with ".debug"appended.
  //   See
  //   https://fedoraproject.org/wiki/RolandMcGrath/BuildID#Find_files_by_build_ID
  //
  // For example, "/system/lib/base.apk!foo.so" with build id abcd1234,
  // is looked for at
  // * $ROOT/system/lib/base.apk!foo.so
  // * $ROOT/system/lib/foo.so
  // * $ROOT/base.apk!foo.so
  // * $ROOT/foo.so
  // * $ROOT/.build-id/ab/cd1234.debug

  std::string symbol_file = root_str + "/" + dirname + "/" + filename;
  if (access(symbol_file.c_str(), F_OK) == 0 &&
      IsCorrectFile(symbol_file, build_id))
    return {symbol_file};

  if (filename.find(kApkPrefix) == 0) {
    symbol_file =
        root_str + "/" + dirname + "/" + filename.substr(sizeof(kApkPrefix));
    if (access(symbol_file.c_str(), F_OK) == 0 &&
        IsCorrectFile(symbol_file, build_id))
      return {symbol_file};
  }

  symbol_file = root_str + "/" + filename;
  if (access(symbol_file.c_str(), F_OK) == 0 &&
      IsCorrectFile(symbol_file, build_id))
    return {symbol_file};

  if (filename.find(kApkPrefix) == 0) {
    symbol_file = root_str + "/" + filename.substr(sizeof(kApkPrefix));
    if (access(symbol_file.c_str(), F_OK) == 0 &&
        IsCorrectFile(symbol_file, build_id))
      return {symbol_file};
  }

  std::string hex_build_id = base::ToHex(build_id.c_str(), build_id.size());
  std::string split_hex_build_id = SplitBuildID(hex_build_id);
  if (!split_hex_build_id.empty()) {
    symbol_file =
        root_str + "/" + ".build-id" + "/" + split_hex_build_id + ".debug";
    if (access(symbol_file.c_str(), F_OK) == 0 &&
        IsCorrectFile(symbol_file, build_id))
      return {symbol_file};
  }

  return base::nullopt;
}

Subprocess::Subprocess(const std::string& file, std::vector<std::string> args)
    : input_pipe_(base::Pipe::Create(base::Pipe::kBothBlock)),
      output_pipe_(base::Pipe::Create(base::Pipe::kBothBlock)) {
  std::vector<char*> c_str_args(args.size() + 1, nullptr);
  for (std::string& arg : args)
    c_str_args.push_back(&(arg[0]));

  if ((pid_ = fork()) == 0) {
    // Child
    PERFETTO_CHECK(dup2(*input_pipe_.rd, STDIN_FILENO) != -1);
    PERFETTO_CHECK(dup2(*output_pipe_.wr, STDOUT_FILENO) != -1);
    input_pipe_.wr.reset();
    output_pipe_.rd.reset();
    PERFETTO_CHECK(execvp(file.c_str(), &(c_str_args[0])) != -1);
  }
  PERFETTO_CHECK(pid_ != -1);
  input_pipe_.rd.reset();
  output_pipe_.wr.reset();
}

Subprocess::~Subprocess() {
  if (pid_ != -1) {
    kill(pid_, SIGKILL);
    int wstatus;
    waitpid(pid_, &wstatus, 0);
  }
}

LLVMSymbolizerProcess::LLVMSymbolizerProcess()
    : subprocess_("llvm-symbolizer", {"llvm-symbolizer"}),
      read_file_(fdopen(subprocess_.read_fd(), "r")) {}

std::vector<SymbolizedFrame> LLVMSymbolizerProcess::Symbolize(
    const std::string& binary,
    uint64_t address) {
  std::vector<SymbolizedFrame> result;

  if (PERFETTO_EINTR(dprintf(subprocess_.write_fd(), "%s 0x%" PRIx64 "\n",
                             binary.c_str(), address)) < 0) {
    PERFETTO_ELOG("Failed to write to llvm-symbolizer.");
    return result;
  }
  auto lines = GetLines(read_file_);
  // llvm-symbolizer writes out records in the form of
  // Foo(Bar*)
  // foo.cc:123
  // This is why we should always get a multiple of two number of lines.
  PERFETTO_DCHECK(lines.size() % 2 == 0);
  result.resize(lines.size() / 2);
  for (size_t i = 0; i < lines.size(); ++i) {
    SymbolizedFrame& cur = result[i / 2];
    if (i % 2 == 0) {
      cur.function_name = lines[i];
    } else {
      if (!ParseLine(lines[i], &cur.file_name, &cur.line)) {
        PERFETTO_ELOG("Failed to parse llvm-symbolizer line: %s",
                      lines[i].c_str());
        cur.file_name = "";
        cur.line = 0;
      }
    }
  }

  for (auto it = result.begin(); it != result.end();) {
    if (it->function_name == "??")
      it = result.erase(it);
    else
      ++it;
  }
  return result;
}
std::vector<std::vector<SymbolizedFrame>> LocalSymbolizer::Symbolize(
    const std::string& mapping_name,
    const std::string& build_id,
    const std::vector<uint64_t>& addresses) {
  base::Optional<std::string> binary =
      finder_.FindBinary(mapping_name, build_id);
  if (!binary)
    return {};
  std::vector<std::vector<SymbolizedFrame>> result;
  result.reserve(addresses.size());
  for (uint64_t address : addresses)
    result.emplace_back(llvm_symbolizer_.Symbolize(*binary, address));
  return result;
}

LocalSymbolizer::~LocalSymbolizer() = default;

}  // namespace trace_to_text
}  // namespace perfetto
<|endoftext|>


<commit_before>#ifndef VIENNAGRID_ALGORITHM_HYPERPLANE_REFINE_HPP
#define VIENNAGRID_ALGORITHM_HYPERPLANE_REFINE_HPP

#include "viennagrid/algorithm/detail/numeric.hpp"
#include "viennagrid/algorithm/volume.hpp"
#include "viennagrid/algorithm/refine.hpp"

namespace viennagrid
{
  namespace detail
  {
    template<typename SrcMeshT, typename DstMeshT, typename PointT, typename LineRefinementTagContainerT, typename LineRefinementVertexHandleContainerT, typename NumericConfigT>
    void mark_edges_for_hyperplane_refine(SrcMeshT const & src_mesh, DstMeshT & dst_mesh,
                              PointT const & hyperplane_point, PointT const & hyperplane_normal,
                              LineRefinementTagContainerT & line_refinement_tag_accessor,
                              LineRefinementVertexHandleContainerT & line_refinement_vertex_handle_accessor,
                              NumericConfigT numeric_config)
    {
      typedef typename viennagrid::result_of::coord<SrcMeshT>::type NumericType;
      typedef typename viennagrid::result_of::const_line_range<SrcMeshT>::type ConstLineRangeType;
      typedef typename viennagrid::result_of::iterator<ConstLineRangeType>::type ConstLineIteratorType;

      ConstLineRangeType lines(src_mesh);
      for (ConstLineIteratorType lit = lines.begin(); lit != lines.end(); ++lit)
      {
        NumericType distance0 = viennagrid::inner_prod( hyperplane_normal, viennagrid::point( viennagrid::vertices(*lit)[0] )-hyperplane_point );
        NumericType distance1 = viennagrid::inner_prod( hyperplane_normal, viennagrid::point( viennagrid::vertices(*lit)[1] )-hyperplane_point );

        NumericType tolerance = viennagrid::detail::relative_tolerance(numeric_config, viennagrid::volume(*lit));
//         1e-8 * viennagrid::volume(*lit);

        if (distance0 > distance1)
          std::swap(distance0, distance1);

        if (distance0 < -tolerance && distance1 > tolerance)
        {
          line_refinement_tag_accessor(*lit) = true;

          PointT const & pt0 = viennagrid::point( viennagrid::vertices(*lit)[0] );
          PointT const & pt1 = viennagrid::point( viennagrid::vertices(*lit)[1] );

          double qd = viennagrid::inner_prod( hyperplane_normal, pt0-hyperplane_point );
          double pd = viennagrid::inner_prod( hyperplane_normal, pt1-hyperplane_point );

          PointT new_pt = pt1 - (pd / (pd-qd)) * (pt1 - pt0);
          line_refinement_vertex_handle_accessor(*lit) = viennagrid::make_unique_vertex( dst_mesh, new_pt );
        }
        else
          line_refinement_tag_accessor(*lit) = false;
      }
    }
  }

  template<typename SrcMeshT, typename SrcSegmentationT, typename DstMeshT, typename DstSegmentationT, typename PointT, typename NumericConfigT>
  void hyperplane_refine(SrcMeshT const & src_mesh, SrcSegmentationT const & src_segmentation,
                         DstMeshT & dst_mesh, DstSegmentationT & dst_segmentation,
                         PointT const & hyperplane_point, PointT const & hyperplane_normal,
                         NumericConfigT numeric_config)
  {
    typedef typename viennagrid::result_of::cell_tag<SrcMeshT>::type CellTag;
    typedef typename viennagrid::result_of::vertex<SrcMeshT>::type VertexType;
    typedef typename viennagrid::result_of::line<SrcMeshT>::type LineType;
    typedef typename viennagrid::result_of::vertex_handle<DstMeshT>::type DstMeshVertexHandleType;
    typedef typename viennagrid::result_of::point<SrcMeshT>::type PointType;

    viennagrid::vertex_copy_map<SrcMeshT, DstMeshT> vertex_map( dst_mesh );

    std::deque<bool> line_refinement_tag_container;
    typename viennagrid::result_of::accessor<std::deque<bool>, LineType>::type line_refinement_tag_accessor(line_refinement_tag_container);

    std::deque<DstMeshVertexHandleType> line_refinement_vertex_handle_container;
    typename viennagrid::result_of::accessor<std::deque<DstMeshVertexHandleType>, LineType>::type line_refinement_vertex_handle_accessor(line_refinement_vertex_handle_container);

    detail::mark_edges_for_hyperplane_refine(src_mesh, dst_mesh, hyperplane_point, hyperplane_normal, line_refinement_tag_accessor, line_refinement_vertex_handle_accessor, numeric_config);

    viennagrid::simple_refine<CellTag>(src_mesh, src_segmentation,
                                        dst_mesh, dst_segmentation,
                                        line_refinement_tag_accessor,
                                        vertex_map,
                                        line_refinement_vertex_handle_accessor);
  }

  template<typename SrcMeshT, typename DstMeshT, typename PointT, typename NumericConfigT>
  void hyperplane_refine(SrcMeshT const & src_mesh, DstMeshT & dst_mesh,
                         PointT const & hyperplane_point, PointT const & hyperplane_normal,
                         NumericConfigT numeric_config)
  {
    typedef typename viennagrid::result_of::cell_tag<SrcMeshT>::type CellTag;
    typedef typename viennagrid::result_of::vertex<SrcMeshT>::type VertexType;
    typedef typename viennagrid::result_of::line<SrcMeshT>::type LineType;

    typedef typename viennagrid::result_of::vertex_handle<DstMeshT>::type DstMeshVertexHandleType;

    viennagrid::vertex_copy_map<SrcMeshT, DstMeshT> vertex_map( dst_mesh );

    std::deque<bool> line_refinement_tag_container;
    typename viennagrid::result_of::accessor<std::deque<bool>, LineType>::type line_refinement_tag_accessor(line_refinement_tag_container);

    std::deque<DstMeshVertexHandleType> line_refinement_vertex_handle_container;
    typename viennagrid::result_of::accessor<std::deque<DstMeshVertexHandleType>, LineType>::type line_refinement_vertex_handle_accessor(line_refinement_vertex_handle_container);

    detail::mark_edges_for_hyperplane_refine(src_mesh, dst_mesh, hyperplane_point, hyperplane_normal, line_refinement_tag_accessor, line_refinement_vertex_handle_accessor, numeric_config);

    viennagrid::simple_refine<CellTag>(src_mesh, dst_mesh,
                                        line_refinement_tag_accessor,
                                        vertex_map,
                                        line_refinement_vertex_handle_accessor);
  }
}

#endif
<commit_msg>added doxygen documentation<commit_after>#ifndef VIENNAGRID_ALGORITHM_HYPERPLANE_REFINE_HPP
#define VIENNAGRID_ALGORITHM_HYPERPLANE_REFINE_HPP

#include "viennagrid/algorithm/detail/numeric.hpp"
#include "viennagrid/algorithm/volume.hpp"
#include "viennagrid/algorithm/refine.hpp"

namespace viennagrid
{
  namespace detail
  {
    /** @brief For internal use only. */
    template<typename SrcMeshT, typename DstMeshT, typename PointT, typename LineRefinementTagContainerT, typename LineRefinementVertexHandleContainerT, typename NumericConfigT>
    void mark_edges_for_hyperplane_refine(SrcMeshT const & src_mesh, DstMeshT & dst_mesh,
                              PointT const & hyperplane_point, PointT const & hyperplane_normal,
                              LineRefinementTagContainerT & line_refinement_tag_accessor,
                              LineRefinementVertexHandleContainerT & line_refinement_vertex_handle_accessor,
                              NumericConfigT numeric_config)
    {
      typedef typename viennagrid::result_of::coord<SrcMeshT>::type NumericType;
      typedef typename viennagrid::result_of::const_line_range<SrcMeshT>::type ConstLineRangeType;
      typedef typename viennagrid::result_of::iterator<ConstLineRangeType>::type ConstLineIteratorType;

      ConstLineRangeType lines(src_mesh);
      for (ConstLineIteratorType lit = lines.begin(); lit != lines.end(); ++lit)
      {
        NumericType distance0 = viennagrid::inner_prod( hyperplane_normal, viennagrid::point( viennagrid::vertices(*lit)[0] )-hyperplane_point );
        NumericType distance1 = viennagrid::inner_prod( hyperplane_normal, viennagrid::point( viennagrid::vertices(*lit)[1] )-hyperplane_point );

        NumericType tolerance = viennagrid::detail::relative_tolerance(numeric_config, viennagrid::volume(*lit));

        if (distance0 > distance1)
          std::swap(distance0, distance1);

        if (distance0 < -tolerance && distance1 > tolerance)
        {
          line_refinement_tag_accessor(*lit) = true;

          PointT const & pt0 = viennagrid::point( viennagrid::vertices(*lit)[0] );
          PointT const & pt1 = viennagrid::point( viennagrid::vertices(*lit)[1] );

          double qd = viennagrid::inner_prod( hyperplane_normal, pt0-hyperplane_point );
          double pd = viennagrid::inner_prod( hyperplane_normal, pt1-hyperplane_point );

          PointT new_pt = pt1 - (pd / (pd-qd)) * (pt1 - pt0);
          line_refinement_vertex_handle_accessor(*lit) = viennagrid::make_unique_vertex( dst_mesh, new_pt );
        }
        else
          line_refinement_tag_accessor(*lit) = false;
      }
    }
  }

  /** @brief Refines a mesh and a segmentation based on a hyperplane. All elements which intersects the hyperplane are refined in a way that they don't intersect the hyperplane afterwards.
   *
   * @param src_mesh            The input mesh
   * @param src_segmentation    The input segmentation
   * @param dst_mesh            The output mesh
   * @param dst_segmentation    The output segmentation
   * @param hyperplane_point    A point representing the hyperplane
   * @param hyperplane_normal   The normale vector representing the hyperplane
   * @param numeric_config      The numeric config
   */
  template<typename SrcMeshT, typename SrcSegmentationT, typename DstMeshT, typename DstSegmentationT, typename PointT, typename NumericConfigT>
  void hyperplane_refine(SrcMeshT const & src_mesh, SrcSegmentationT const & src_segmentation,
                         DstMeshT & dst_mesh, DstSegmentationT & dst_segmentation,
                         PointT const & hyperplane_point, PointT const & hyperplane_normal,
                         NumericConfigT numeric_config)
  {
    typedef typename viennagrid::result_of::cell_tag<SrcMeshT>::type CellTag;
    typedef typename viennagrid::result_of::vertex<SrcMeshT>::type VertexType;
    typedef typename viennagrid::result_of::line<SrcMeshT>::type LineType;
    typedef typename viennagrid::result_of::vertex_handle<DstMeshT>::type DstMeshVertexHandleType;
    typedef typename viennagrid::result_of::point<SrcMeshT>::type PointType;

    viennagrid::vertex_copy_map<SrcMeshT, DstMeshT> vertex_map( dst_mesh );

    std::deque<bool> line_refinement_tag_container;
    typename viennagrid::result_of::accessor<std::deque<bool>, LineType>::type line_refinement_tag_accessor(line_refinement_tag_container);

    std::deque<DstMeshVertexHandleType> line_refinement_vertex_handle_container;
    typename viennagrid::result_of::accessor<std::deque<DstMeshVertexHandleType>, LineType>::type line_refinement_vertex_handle_accessor(line_refinement_vertex_handle_container);

    detail::mark_edges_for_hyperplane_refine(src_mesh, dst_mesh, hyperplane_point, hyperplane_normal, line_refinement_tag_accessor, line_refinement_vertex_handle_accessor, numeric_config);

    viennagrid::simple_refine<CellTag>(src_mesh, src_segmentation,
                                        dst_mesh, dst_segmentation,
                                        line_refinement_tag_accessor,
                                        vertex_map,
                                        line_refinement_vertex_handle_accessor);
  }

  /** @brief Refines a mesh and a segmentation based on a hyperplane. All elements which intersects the hyperplane are refined in a way that they don't intersect the hyperplane afterwards.
   *
   * @param src_mesh            The input mesh
   * @param dst_mesh            The output mesh
   * @param hyperplane_point    A point representing the hyperplane
   * @param hyperplane_normal   The normale vector representing the hyperplane
   * @param numeric_config      The numeric config
   */
  template<typename SrcMeshT, typename DstMeshT, typename PointT, typename NumericConfigT>
  void hyperplane_refine(SrcMeshT const & src_mesh, DstMeshT & dst_mesh,
                         PointT const & hyperplane_point, PointT const & hyperplane_normal,
                         NumericConfigT numeric_config)
  {
    typedef typename viennagrid::result_of::cell_tag<SrcMeshT>::type CellTag;
    typedef typename viennagrid::result_of::vertex<SrcMeshT>::type VertexType;
    typedef typename viennagrid::result_of::line<SrcMeshT>::type LineType;

    typedef typename viennagrid::result_of::vertex_handle<DstMeshT>::type DstMeshVertexHandleType;

    viennagrid::vertex_copy_map<SrcMeshT, DstMeshT> vertex_map( dst_mesh );

    std::deque<bool> line_refinement_tag_container;
    typename viennagrid::result_of::accessor<std::deque<bool>, LineType>::type line_refinement_tag_accessor(line_refinement_tag_container);

    std::deque<DstMeshVertexHandleType> line_refinement_vertex_handle_container;
    typename viennagrid::result_of::accessor<std::deque<DstMeshVertexHandleType>, LineType>::type line_refinement_vertex_handle_accessor(line_refinement_vertex_handle_container);

    detail::mark_edges_for_hyperplane_refine(src_mesh, dst_mesh, hyperplane_point, hyperplane_normal, line_refinement_tag_accessor, line_refinement_vertex_handle_accessor, numeric_config);

    viennagrid::simple_refine<CellTag>(src_mesh, dst_mesh,
                                        line_refinement_tag_accessor,
                                        vertex_map,
                                        line_refinement_vertex_handle_accessor);
  }
}

#endif
<|endoftext|>


<commit_before>/*=========================================================================

 Program:   vtkINRIA3D
 Module:    $Id: SynchronizedViewsTest.cxx 1211 2009-07-29 14:57:22Z filus $
 Language:  C++
 Author:    $Author: filus $
 Date:      $Date: 2009-07-29 15:57:22 +0100 (Wed, 29 Jul 2009) $
 Version:   $Revision: 1211 $

 Copyright (c) 2007 INRIA - Asclepios Project. All rights reserved.
 See Copyright.txt for details.

 This software is distributed WITHOUT ANY WARRANTY; without even
 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.  See the above copyright notices for more information.

 =========================================================================*/
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkImageEllipsoidSource.h>
#include <vtkImageMandelbrotSource.h>
#include <vtkImageData.h>
#include <vtkColorTransferFunction.h>
#include <vtkPiecewiseFunction.h>
#include <vtkConeSource.h>
#include <vtkMatrix4x4.h>
#include <vtkImageViewCornerAnnotation.h>

#include <vtkImageView2D.h>
#include <vtkTransferFunctionPresets.h>
#include <vtkLookupTableManager.h>

int vtkImageViewTest3(int argc, char *argv[])
{
  vtkImageView2D*            view     = vtkImageView2D::New();
  vtkRenderWindowInteractor* iren     = vtkRenderWindowInteractor::New();
  vtkRenderWindow*           rwin     = vtkRenderWindow::New();
  vtkRenderer*               renderer = vtkRenderer::New();

  iren->SetRenderWindow (rwin);
  rwin->AddRenderer (renderer);
  view->SetRenderWindow (rwin);
  view->SetRenderer (renderer);

  view->SetShowScalarBar(0);

  vtkImageEllipsoidSource* imageSource = vtkImageEllipsoidSource::New();
  imageSource->SetWholeExtent (0, 63, 0, 63, 0, 63);
  imageSource->SetCenter (32,32,32);
  imageSource->SetRadius (32,16,16);
  imageSource->Update();

  vtkImageData* image = imageSource->GetOutput();

  view->SetInput (image);

  ////////////////////////////////////////////////////////////////////
  //// Test with identity matrix: i.e. for an axial native image /////
  ////////////////////////////////////////////////////////////////////

  std::cout<<" testing axial native orientation..."<<std::endl;
  vtkMatrix4x4* matrix1 = vtkMatrix4x4::New();
  matrix1->Identity();
  view->SetOrientationMatrix (matrix1);

  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_AXIAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_XY)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_CORONAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_XZ)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_SAGITTAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_YZ)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  matrix1->Delete();
  std::cout<<" success." <<std::endl;

  ////////////////////////////////////////////////////////////////////
  ////          Test with a sagittal native image                /////
  ////////////////////////////////////////////////////////////////////

  std::cout<<" testing sagittal native orientation..."<<std::endl;
  vtkMatrix4x4* matrix2 = vtkMatrix4x4::New();
  matrix2->Zero();

  matrix2->SetElement(1,0, 1);
  matrix2->SetElement(2,1, 1);
  matrix2->SetElement(0,2, 1);

  view->SetOrientationMatrix (matrix2);

  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_SAGITTAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_XY)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_AXIAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_XZ)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_CORONAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_YZ)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  matrix2->Delete();
  std::cout<<" success." <<std::endl;

  ////////////////////////////////////////////////////////////////////
  ////           Test with a coronal native image                /////
  ////////////////////////////////////////////////////////////////////

  std::cout<<" testing coronal native orientation..."<<std::endl;
  vtkMatrix4x4* matrix3 = vtkMatrix4x4::New();
  matrix3->Zero();

  matrix3->SetElement(2,0, 1);
  matrix3->SetElement(0,1, 1);
  matrix3->SetElement(1,2, 1);

  view->SetOrientationMatrix (matrix3);

  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_CORONAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_XY)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_SAGITTAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_XZ)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_AXIAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_YZ)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  matrix3->Delete();
  std::cout<<" success." <<std::endl;

  ////////////////////////////////////////////////////////////////////
  ////             Test with an oblique native acquisition       /////
  ////////////////////////////////////////////////////////////////////

  std::cout<<" testing oblique native orientation (but slice-encoding direction close to sagittal)..."<<std::endl;
  vtkMatrix4x4* matrix4 = vtkMatrix4x4::New();
  matrix4->Zero();

  matrix4->SetElement(0,0, 0.277064);  matrix4->SetElement(1,0, 0.798317);  matrix4->SetElement(2,0, -0.53472);
  matrix4->SetElement(0,1, -0.720176); matrix4->SetElement(1,1, -0.195862); matrix4->SetElement(2,1, -0.665571);
  matrix4->SetElement(0,2, -0.636068); matrix4->SetElement(1,2, 0.569498);  matrix4->SetElement(2,2, 0.520662);

  view->SetOrientationMatrix (matrix4);

  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_SAGITTAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_XY)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_AXIAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_XZ)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_CORONAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_YZ)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  matrix4->Delete();
  std::cout<<" success." <<std::endl;

  view->Delete();
  iren->Delete();
  rwin->Delete();
  renderer->Delete();
  imageSource->Delete();

  return EXIT_SUCCESS;
}
<commit_msg>code-style<commit_after>/*=========================================================================

 Program:   vtkINRIA3D
 Module:    $Id: SynchronizedViewsTest.cxx 1211 2009-07-29 14:57:22Z filus $
 Language:  C++
 Author:    $Author: filus $
 Date:      $Date: 2009-07-29 15:57:22 +0100 (Wed, 29 Jul 2009) $
 Version:   $Revision: 1211 $

 Copyright (c) 2007 INRIA - Asclepios Project. All rights reserved.
 See Copyright.txt for details.

 This software is distributed WITHOUT ANY WARRANTY; without even
 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.  See the above copyright notices for more information.

 =========================================================================*/
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkImageEllipsoidSource.h>
#include <vtkImageMandelbrotSource.h>
#include <vtkImageData.h>
#include <vtkColorTransferFunction.h>
#include <vtkPiecewiseFunction.h>
#include <vtkConeSource.h>
#include <vtkMatrix4x4.h>
#include <vtkImageViewCornerAnnotation.h>

#include <vtkImageView2D.h>
#include <vtkTransferFunctionPresets.h>
#include <vtkLookupTableManager.h>

int vtkImageViewTest3(int argc, char *argv[])
{
  vtkImageView2D*            view     = vtkImageView2D::New();
  vtkRenderWindowInteractor* iren     = vtkRenderWindowInteractor::New();
  vtkRenderWindow*           rwin     = vtkRenderWindow::New();
  vtkRenderer*               renderer = vtkRenderer::New();

  iren->SetRenderWindow (rwin);
  rwin->AddRenderer (renderer);
  view->SetRenderWindow (rwin);
  view->SetRenderer (renderer);

  view->SetShowScalarBar(0);

  vtkImageEllipsoidSource* imageSource = vtkImageEllipsoidSource::New();
  imageSource->SetWholeExtent (0, 63, 0, 63, 0, 63);
  imageSource->SetCenter (32,32,32);
  imageSource->SetRadius (32,16,16);
  imageSource->Update();

  vtkImageData* image = imageSource->GetOutput();

  view->SetInput (image);

  ////////////////////////////////////////////////////////////////////
  //// Test with identity matrix: i.e. for an axial native image /////
  ////////////////////////////////////////////////////////////////////

  std::cout<<" testing axial native orientation..."<<std::endl;
  vtkMatrix4x4* matrix1 = vtkMatrix4x4::New();
  matrix1->Identity();
  view->SetOrientationMatrix (matrix1);

  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_AXIAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_XY)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_CORONAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_XZ)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_SAGITTAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_YZ)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  matrix1->Delete();
  std::cout<<" success." <<std::endl;

  ////////////////////////////////////////////////////////////////////
  ////          Test with a sagittal native image                /////
  ////////////////////////////////////////////////////////////////////

  std::cout<<" testing sagittal native orientation..."<<std::endl;
  vtkMatrix4x4* matrix2 = vtkMatrix4x4::New();
  matrix2->Zero();

  matrix2->SetElement(1,0, 1);
  matrix2->SetElement(2,1, 1);
  matrix2->SetElement(0,2, 1);

  view->SetOrientationMatrix (matrix2);

  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_SAGITTAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_XY)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_AXIAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_XZ)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_CORONAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_YZ)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  matrix2->Delete();
  std::cout<<" success." <<std::endl;

  ////////////////////////////////////////////////////////////////////
  ////           Test with a coronal native image                /////
  ////////////////////////////////////////////////////////////////////

  std::cout<<" testing coronal native orientation..."<<std::endl;
  vtkMatrix4x4* matrix3 = vtkMatrix4x4::New();
  matrix3->Zero();

  matrix3->SetElement(2,0, 1);
  matrix3->SetElement(0,1, 1);
  matrix3->SetElement(1,2, 1);

  view->SetOrientationMatrix (matrix3);

  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_CORONAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_XY)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_SAGITTAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_XZ)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_AXIAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_YZ)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  matrix3->Delete();
  std::cout<<" success." <<std::endl;

  ////////////////////////////////////////////////////////////////////
  ////             Test with an oblique native acquisition       /////
  ////////////////////////////////////////////////////////////////////

  std::cout<<" testing oblique native orientation (but slice-encoding direction close to sagittal)..."<<std::endl;
  vtkMatrix4x4* matrix4 = vtkMatrix4x4::New();
  matrix4->Zero();

  matrix4->SetElement(0,0, 0.277064);  matrix4->SetElement(1,0, 0.798317);  matrix4->SetElement(2,0, -0.53472);
  matrix4->SetElement(0,1, -0.720176); matrix4->SetElement(1,1, -0.195862); matrix4->SetElement(2,1, -0.665571);
  matrix4->SetElement(0,2, -0.636068); matrix4->SetElement(1,2, 0.569498);  matrix4->SetElement(2,2, 0.520662);

  view->SetOrientationMatrix (matrix4);

  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_SAGITTAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_XY)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_AXIAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_XZ)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  view->SetViewOrientation (vtkImageView2D::VIEW_ORIENTATION_CORONAL);
  if (view->GetSliceOrientation() != vtkImageView2D::SLICE_ORIENTATION_YZ)
  {
    std::cerr<<"wrong parametrization :"<<std::endl;
    std::cerr<<"view->GetViewOrientation() : " <<view->GetViewOrientation() <<std::endl;
    std::cerr<<"view->GetSliceOrientation() : "<<view->GetSliceOrientation()<<std::endl;
    return EXIT_FAILURE;
  }
  matrix4->Delete();
  std::cout<<" success." <<std::endl;

  view->Delete();
  iren->Delete();
  rwin->Delete();
  renderer->Delete();
  imageSource->Delete();

  return EXIT_SUCCESS;
}
<|endoftext|>