<commit_before>#include <iostream>
#include <list>
#include <chrono>
#include <algorithm>
#include <fstream>
#include <memory>
#include <ImageMagick-6/Magick++.h>
#include <boost/filesystem/path.hpp>
#include <mutex>
#include "SimpleIni.h"
#include "QuadTree.cpp"
#include "Config.cpp"
#include "morton.h"

class Preprocessor {
public:
  CSimpleIniA *config;

  explicit Preprocessor(const char *path_config) {
      config = new CSimpleIniA(true, false, false);

      if (config->LoadFile(path_config) < 0)
      {
          throw std::runtime_error("Configuration file parsing error");
      }

      boost::filesystem::path
          path_texture(config->GetValue(Config::TEXTURE_MANAGEMENT, Config::FILE_PPM, Config::DEFAULT));
      boost::filesystem::path dir_texture = path_texture.parent_path();
      Magick::InitializeMagick(dir_texture.c_str());
  }

  ~Preprocessor() = default;

  bool prepare_single_raster(const char *name_raster) {
      Magick::Image image;
      try
      {
          image.read(name_raster);
          Magick::Geometry geometry = image.size();
          size_t side = (size_t) std::pow(2, std::floor(std::log(std::min(geometry.width(), geometry.height())) / std::log(2)));
          geometry.aspect(false);
          geometry.width(side);
          geometry.height(side);
          image.crop(geometry);
          image.write(config->GetValue(Config::TEXTURE_MANAGEMENT, Config::FILE_PPM, Config::DEFAULT));
      }
      catch (Magick::Exception &error_)
      {
          std::cout << "Caught exception: " << error_.what() << std::endl;
          return false;
      };
      return true;
  }

  bool prepare_mipmap() {
      auto tile_size = (size_t) atoi(config->GetValue(Config::TEXTURE_MANAGEMENT, Config::TILE_SIZE, Config::DEFAULT));
      if ((tile_size & (tile_size - 1)) != 0)
      {
          throw std::runtime_error("Tile size is not a power of 2");
      }

      uint32_t count_threads = 0;
      count_threads = atoi(config->GetValue(Config::TEXTURE_MANAGEMENT, Config::RUN_IN_PARALLEL, Config::DEFAULT)) != 1 ? 1 : thread::hardware_concurrency();

      size_t dim_x = 0, dim_y = 0;

      std::ifstream input;
      input.open(config->GetValue(Config::TEXTURE_MANAGEMENT, Config::FILE_PPM, Config::DEFAULT), std::ifstream::in | std::ifstream::binary);
      read_ppm_header(input, dim_x, dim_y);
      input.close();

      uint32_t tree_depth = QuadTree::calculate_depth(dim_x, tile_size);
      size_t first_node_leaf = QuadTree::get_first_node_id_of_depth(tree_depth);
      size_t last_node_leaf = QuadTree::get_first_node_id_of_depth(tree_depth) + QuadTree::get_length_of_depth(tree_depth) - 1;

      size_t nodes_per_thread = (last_node_leaf - first_node_leaf + 1) / count_threads;

      std::vector<std::thread> thread_pool;
      auto *texture_lock = new std::mutex;

      for (uint32_t i = 0; i < count_threads; i++)
      {
          size_t node_start = first_node_leaf + i * nodes_per_thread;
          size_t node_end = (i != count_threads - 1) ? first_node_leaf + (i + 1) * nodes_per_thread : last_node_leaf;
          thread_pool.emplace_back([=]()
                                   { write_tile_range_at_depth((*texture_lock), tile_size, tree_depth, node_start, node_end); });
      }
      for (auto &_thread : thread_pool)
      {
          _thread.join();
      }

      thread_pool.clear();

      for (uint32_t _depth = tree_depth - 1; _depth > 0; _depth--)
      {
          first_node_leaf = QuadTree::get_first_node_id_of_depth(_depth);
          last_node_leaf = QuadTree::get_first_node_id_of_depth(_depth) + QuadTree::get_length_of_depth(_depth) - 1;

          nodes_per_thread = (last_node_leaf - first_node_leaf + 1) / count_threads;

          if (nodes_per_thread > 0)
          {
              for (uint32_t i = 0; i < count_threads; i++)
              {
                  size_t node_start = first_node_leaf + i * nodes_per_thread;
                  size_t node_end = (i != count_threads - 1) ? first_node_leaf + (i + 1) * nodes_per_thread : last_node_leaf;
                  thread_pool.emplace_back([=]()
                                           { stitch_tile_range(tile_size, node_start, node_end); });
              }
          }
          else
          {
              stitch_tile_range(tile_size, first_node_leaf, last_node_leaf);
          }
          for (auto &_thread : thread_pool)
          {
              _thread.join();
          }
      }

      std::list<Magick::Image> children_imgs;

      for (size_t i = 0; i < 4; i++)
      {
          Magick::Image _child;
          _child.read("id_" + std::to_string(QuadTree::get_child_id(0, i)) + ".ppm");
          children_imgs.push_back(_child);
      }

      write_stitched_tile(0, tile_size, children_imgs);

      const char *file_mipmap = config->GetValue(Config::TEXTURE_MANAGEMENT, Config::FILE_MIPMAP, Config::DEFAULT);
      std::ofstream output;
      output.open(file_mipmap, std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);

      auto *buf_tile = new char[tile_size * tile_size * 3];

      for (uint32_t _depth = 0; _depth <= tree_depth; _depth++)
      {
          first_node_leaf = QuadTree::get_first_node_id_of_depth(_depth);
          last_node_leaf = QuadTree::get_first_node_id_of_depth(_depth) + QuadTree::get_length_of_depth(_depth) - 1;

          for (size_t _id = first_node_leaf; _id <= last_node_leaf; _id++)
          {
              std::ifstream input_tile;
              input_tile.open("id_" + std::to_string(_id) + ".ppm", std::ifstream::in | std::ifstream::binary);

              read_ppm_header(input_tile, dim_x, dim_y);
              input_tile.read(&buf_tile[0], tile_size * tile_size * 3);

              input_tile.close();

              output.write(&buf_tile[0], tile_size * tile_size * 3);

              if (atoi(config->GetValue(Config::DEBUG, Config::KEEP_INTERMEDIATE_DATA, Config::DEFAULT)) != 1)
              {
                  std::remove(("id_" + std::to_string(_id) + ".ppm").c_str());
              }
          }
      }

      output.close();

      return false;
  }

private:

  void read_ppm_header(std::ifstream &_ifs, size_t &_dim_x, size_t &_dim_y) {
      auto *buf_file_version = new char[3];
      _ifs.getline(&buf_file_version[0], 3, '\x0A');

      if (strcmp(buf_file_version, "P6") != 0)
      {
          throw std::runtime_error("PPM file format not equal to P6");
      }

      auto *buf_dim_x = new char[8];
      auto *buf_dim_y = new char[8];
      auto *buf_color_depth = new char[8];

      _ifs.getline(&buf_dim_x[0], 8, '\x20');
      _ifs.getline(&buf_dim_y[0], 8, '\x0A');
      _ifs.getline(&buf_color_depth[0], 8, '\x0A');

      _dim_x = (size_t) atol(buf_dim_x);
      _dim_y = (size_t) atol(buf_dim_y);
      auto color_depth = (short) atoi(buf_color_depth);

      if (color_depth != 255)
      {
          throw std::runtime_error("PPM color depth not equal to 255");
      }

      if (_dim_x != _dim_y || (_dim_x & (_dim_x - 1)) != 0)
      {
          throw std::runtime_error("PPM dimensions are not equal or not a power of 2");
      }
  }

  void write_tile_range_at_depth(std::mutex &_texture_lock, const size_t _tile_size, const uint32_t _depth, const size_t _node_start, const size_t _node_end) {
      std::ifstream _ifs;
      _ifs.open(config->GetValue(Config::TEXTURE_MANAGEMENT, Config::FILE_PPM, Config::DEFAULT), std::ifstream::in | std::ifstream::binary);

      size_t dim_x = 0, dim_y = 0;

      _texture_lock.lock();
      read_ppm_header(_ifs, dim_x, dim_y);
      _texture_lock.unlock();

      streamoff _offset_header = _ifs.tellg();

      auto *buf_tile = new char[_tile_size * _tile_size * 3];
      std::string buf_header = "P6\x0A" + std::to_string(_tile_size) + "\x20" + std::to_string(_tile_size) + "\x0A" + "255" + "\x0A";

      size_t _node_first = QuadTree::get_first_node_id_of_depth(_depth);
      size_t _tiles_per_row = QuadTree::get_tiles_per_row(_depth);

      for (size_t _id = _node_start; _id <= _node_end; _id++)
      {
          uint_fast64_t skip_cols, skip_rows;
          morton2D_64_decode((uint_fast64_t) (_id - _node_first), skip_cols, skip_rows);

          _texture_lock.lock();

          _ifs.seekg(_offset_header);
          _ifs.ignore(skip_rows * _tiles_per_row * _tile_size * _tile_size * 3);

          for (uint32_t _row = 0; _row < _tile_size; _row++)
          {
              _ifs.ignore(skip_cols * _tile_size * 3);
              _ifs.read(&buf_tile[_row * _tile_size * 3], _tile_size * 3);
              _ifs.ignore((_tiles_per_row - skip_cols - 1) * _tile_size * 3);
          }

          _texture_lock.unlock();

          std::ofstream output;
          output.open("id_" + std::to_string(_id) + ".ppm", std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
          output.write(&buf_header.c_str()[0], buf_header.size());
          output.write(&buf_tile[0], _tile_size * _tile_size * 3);
          output.close();
      }

      _ifs.close();
  }

  void stitch_tile_range(const size_t _tile_size, const size_t _node_start, const size_t _node_end) {
      for (size_t _id = _node_start; _id <= _node_end; _id++)
      {
          std::list<Magick::Image> children_imgs;

          for (size_t i = 0; i < 4; i++)
          {
              Magick::Image _child;
              _child.read("id_" + std::to_string(QuadTree::get_child_id(_id, i)) + ".ppm");
              children_imgs.push_back(_child);
          }

          write_stitched_tile(_id, _tile_size, children_imgs);
      }
  }

  void write_stitched_tile(size_t _id, size_t _tile_size, list<Magick::Image> &_child_imgs) {
      Magick::Montage montage_settings;
      montage_settings.tile(Magick::Geometry(2, 2));
      montage_settings.geometry(Magick::Geometry(_tile_size, _tile_size));

      std::list<Magick::Image> montage_list;
      Magick::montageImages(&montage_list, _child_imgs.begin(), _child_imgs.end(), montage_settings);
      Magick::writeImages(montage_list.begin(), montage_list.end(), "id_" + std::to_string(_id) + ".ppm");

      Magick::Image image;
      image.read("id_" + std::to_string(_id) + ".ppm");
      Magick::Geometry geometry = image.size();
      geometry.width(_tile_size);
      geometry.height(_tile_size);
      image.scale(geometry);
      image.depth(8);
      image.write("id_" + std::to_string(_id) + ".ppm");
  }
};<commit_msg>* restructure thread loops;<commit_after>#include <iostream>
#include <list>
#include <chrono>
#include <algorithm>
#include <fstream>
#include <memory>
#include <ImageMagick-6/Magick++.h>
#include <boost/filesystem/path.hpp>
#include <mutex>
#include "SimpleIni.h"
#include "QuadTree.cpp"
#include "Config.cpp"
#include "morton.h"

class Preprocessor {
public:
  CSimpleIniA *config;

  explicit Preprocessor(const char *path_config) {
      config = new CSimpleIniA(true, false, false);

      if (config->LoadFile(path_config) < 0)
      {
          throw std::runtime_error("Configuration file parsing error");
      }

      boost::filesystem::path
          path_texture(config->GetValue(Config::TEXTURE_MANAGEMENT, Config::FILE_PPM, Config::DEFAULT));
      boost::filesystem::path dir_texture = path_texture.parent_path();
      Magick::InitializeMagick(dir_texture.c_str());
  }

  ~Preprocessor() = default;

  bool prepare_single_raster(const char *name_raster) {
      Magick::Image image;
      try
      {
          image.read(name_raster);
          Magick::Geometry geometry = image.size();
          size_t side = (size_t) std::pow(2, std::floor(std::log(std::min(geometry.width(), geometry.height())) / std::log(2)));
          geometry.aspect(false);
          geometry.width(side);
          geometry.height(side);
          image.crop(geometry);
          image.write(config->GetValue(Config::TEXTURE_MANAGEMENT, Config::FILE_PPM, Config::DEFAULT));
      }
      catch (Magick::Exception &error_)
      {
          std::cout << "Caught exception: " << error_.what() << std::endl;
          return false;
      };
      return true;
  }

  bool prepare_mipmap() {
      auto tile_size = (size_t) atoi(config->GetValue(Config::TEXTURE_MANAGEMENT, Config::TILE_SIZE, Config::DEFAULT));
      if ((tile_size & (tile_size - 1)) != 0)
      {
          throw std::runtime_error("Tile size is not a power of 2");
      }

      uint32_t count_threads = 0;
      count_threads = atoi(config->GetValue(Config::TEXTURE_MANAGEMENT, Config::RUN_IN_PARALLEL, Config::DEFAULT)) != 1 ? 1 : thread::hardware_concurrency();

      size_t dim_x = 0, dim_y = 0;

      std::ifstream input;
      input.open(config->GetValue(Config::TEXTURE_MANAGEMENT, Config::FILE_PPM, Config::DEFAULT), std::ifstream::in | std::ifstream::binary);
      read_ppm_header(input, dim_x, dim_y);
      input.close();

      uint32_t tree_depth = QuadTree::calculate_depth(dim_x, tile_size);
      size_t first_node_leaf = QuadTree::get_first_node_id_of_depth(tree_depth);
      size_t last_node_leaf = QuadTree::get_first_node_id_of_depth(tree_depth) + QuadTree::get_length_of_depth(tree_depth) - 1;

      size_t nodes_per_thread = (last_node_leaf - first_node_leaf + 1) / count_threads;

      std::vector<std::thread> thread_pool;
      auto *texture_lock = new std::mutex;

      for (uint32_t i = 0; i < count_threads; i++)
      {
          size_t node_start = first_node_leaf + i * nodes_per_thread;
          size_t node_end = (i != count_threads - 1) ? first_node_leaf + (i + 1) * nodes_per_thread : last_node_leaf;
          thread_pool.emplace_back([=]()
                                   { write_tile_range_at_depth((*texture_lock), tile_size, tree_depth, node_start, node_end); });
      }
      for (auto &_thread : thread_pool)
      {
          _thread.join();
      }

      thread_pool.clear();

      for (uint32_t _depth = tree_depth - 1; _depth > 0; _depth--)
      {
          first_node_leaf = QuadTree::get_first_node_id_of_depth(_depth);
          last_node_leaf = QuadTree::get_first_node_id_of_depth(_depth) + QuadTree::get_length_of_depth(_depth) - 1;

          nodes_per_thread = (last_node_leaf - first_node_leaf + 1) / count_threads;

          if (nodes_per_thread > 0)
          {
              for (uint32_t i = 0; i < count_threads; i++)
              {
                  size_t node_start = first_node_leaf + i * nodes_per_thread;
                  size_t node_end = (i != count_threads - 1) ? first_node_leaf + (i + 1) * nodes_per_thread : last_node_leaf;
                  thread_pool.emplace_back([=]()
                                           { stitch_tile_range(tile_size, node_start, node_end); });
              }
              for (auto &_thread : thread_pool)
              {
                  _thread.join();
              }
              thread_pool.clear();
          }
          else
          {
              stitch_tile_range(tile_size, first_node_leaf, last_node_leaf);
          }
      }

      std::list<Magick::Image> children_imgs;

      for (size_t i = 0; i < 4; i++)
      {
          Magick::Image _child;
          _child.read("id_" + std::to_string(QuadTree::get_child_id(0, i)) + ".ppm");
          children_imgs.push_back(_child);
      }

      write_stitched_tile(0, tile_size, children_imgs);

      const char *file_mipmap = config->GetValue(Config::TEXTURE_MANAGEMENT, Config::FILE_MIPMAP, Config::DEFAULT);
      std::ofstream output;
      output.open(file_mipmap, std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);

      auto *buf_tile = new char[tile_size * tile_size * 3];

      for (uint32_t _depth = 0; _depth <= tree_depth; _depth++)
      {
          first_node_leaf = QuadTree::get_first_node_id_of_depth(_depth);
          last_node_leaf = QuadTree::get_first_node_id_of_depth(_depth) + QuadTree::get_length_of_depth(_depth) - 1;

          for (size_t _id = first_node_leaf; _id <= last_node_leaf; _id++)
          {
              std::ifstream input_tile;
              input_tile.open("id_" + std::to_string(_id) + ".ppm", std::ifstream::in | std::ifstream::binary);

              read_ppm_header(input_tile, dim_x, dim_y);
              input_tile.read(&buf_tile[0], tile_size * tile_size * 3);

              input_tile.close();

              output.write(&buf_tile[0], tile_size * tile_size * 3);

              if (atoi(config->GetValue(Config::DEBUG, Config::KEEP_INTERMEDIATE_DATA, Config::DEFAULT)) != 1)
              {
                  std::remove(("id_" + std::to_string(_id) + ".ppm").c_str());
              }
          }
      }

      output.close();

      return false;
  }

private:

  void read_ppm_header(std::ifstream &_ifs, size_t &_dim_x, size_t &_dim_y) {
      auto *buf_file_version = new char[3];
      _ifs.getline(&buf_file_version[0], 3, '\x0A');

      if (strcmp(buf_file_version, "P6") != 0)
      {
          throw std::runtime_error("PPM file format not equal to P6");
      }

      auto *buf_dim_x = new char[8];
      auto *buf_dim_y = new char[8];
      auto *buf_color_depth = new char[8];

      _ifs.getline(&buf_dim_x[0], 8, '\x20');
      _ifs.getline(&buf_dim_y[0], 8, '\x0A');
      _ifs.getline(&buf_color_depth[0], 8, '\x0A');

      _dim_x = (size_t) atol(buf_dim_x);
      _dim_y = (size_t) atol(buf_dim_y);
      auto color_depth = (short) atoi(buf_color_depth);

      if (color_depth != 255)
      {
          throw std::runtime_error("PPM color depth not equal to 255");
      }

      if (_dim_x != _dim_y || (_dim_x & (_dim_x - 1)) != 0)
      {
          throw std::runtime_error("PPM dimensions are not equal or not a power of 2");
      }
  }

  void write_tile_range_at_depth(std::mutex &_texture_lock, const size_t _tile_size, const uint32_t _depth, const size_t _node_start, const size_t _node_end) {
      std::ifstream _ifs;
      _ifs.open(config->GetValue(Config::TEXTURE_MANAGEMENT, Config::FILE_PPM, Config::DEFAULT), std::ifstream::in | std::ifstream::binary);

      size_t dim_x = 0, dim_y = 0;

      _texture_lock.lock();
      read_ppm_header(_ifs, dim_x, dim_y);
      _texture_lock.unlock();

      streamoff _offset_header = _ifs.tellg();

      auto *buf_tile = new char[_tile_size * _tile_size * 3];
      std::string buf_header = "P6\x0A" + std::to_string(_tile_size) + "\x20" + std::to_string(_tile_size) + "\x0A" + "255" + "\x0A";

      size_t _node_first = QuadTree::get_first_node_id_of_depth(_depth);
      size_t _tiles_per_row = QuadTree::get_tiles_per_row(_depth);

      for (size_t _id = _node_start; _id <= _node_end; _id++)
      {
          uint_fast64_t skip_cols, skip_rows;
          morton2D_64_decode((uint_fast64_t) (_id - _node_first), skip_cols, skip_rows);

          _texture_lock.lock();

          _ifs.seekg(_offset_header);
          _ifs.ignore(skip_rows * _tiles_per_row * _tile_size * _tile_size * 3);

          for (uint32_t _row = 0; _row < _tile_size; _row++)
          {
              _ifs.ignore(skip_cols * _tile_size * 3);
              _ifs.read(&buf_tile[_row * _tile_size * 3], _tile_size * 3);
              _ifs.ignore((_tiles_per_row - skip_cols - 1) * _tile_size * 3);
          }

          _texture_lock.unlock();

          std::ofstream output;
          output.open("id_" + std::to_string(_id) + ".ppm", std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
          output.write(&buf_header.c_str()[0], buf_header.size());
          output.write(&buf_tile[0], _tile_size * _tile_size * 3);
          output.close();
      }

      _ifs.close();
  }

  void stitch_tile_range(const size_t _tile_size, const size_t _node_start, const size_t _node_end) {
      for (size_t _id = _node_start; _id <= _node_end; _id++)
      {
          std::list<Magick::Image> children_imgs;

          for (size_t i = 0; i < 4; i++)
          {
              Magick::Image _child;
              _child.read("id_" + std::to_string(QuadTree::get_child_id(_id, i)) + ".ppm");
              children_imgs.push_back(_child);
          }

          write_stitched_tile(_id, _tile_size, children_imgs);
      }
  }

  void write_stitched_tile(size_t _id, size_t _tile_size, list<Magick::Image> &_child_imgs) {
      Magick::Montage montage_settings;
      montage_settings.tile(Magick::Geometry(2, 2));
      montage_settings.geometry(Magick::Geometry(_tile_size, _tile_size));

      std::list<Magick::Image> montage_list;
      Magick::montageImages(&montage_list, _child_imgs.begin(), _child_imgs.end(), montage_settings);
      Magick::writeImages(montage_list.begin(), montage_list.end(), "id_" + std::to_string(_id) + ".ppm");

      Magick::Image image;
      image.read("id_" + std::to_string(_id) + ".ppm");
      Magick::Geometry geometry = image.size();
      geometry.width(_tile_size);
      geometry.height(_tile_size);
      image.scale(geometry);
      image.depth(8);
      image.write("id_" + std::to_string(_id) + ".ppm");
  }
};<|endoftext|>


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

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.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 "otbFuzzyDescriptorsModelManager.h"
#include "itkExceptionObject.h"
#include "itksys/SystemTools.hxx"
#include "tinyxml.h"

namespace otb {

FuzzyDescriptorsModelManager
::FuzzyDescriptorsModelManager()
{}

FuzzyDescriptorsModelManager::PairType
FuzzyDescriptorsModelManager
::GetDescriptor(const char * model, const DescriptorsModelType & descModel)
{
  PairType out;
  bool found = false;
  DescriptorsModelType::const_iterator it = descModel.begin();

  while( it!=descModel.end() && found == false)
    {
      if( (*it).first == model )
        {
          out = (*it);
        }
    }

  if( found == false )
    {
      itkGenericExceptionMacro(<<"No models named "<<model<<" found...");
    }

  return out;
}

void
FuzzyDescriptorsModelManager
::AddDescriptor( PairType modelPair, DescriptorsModelType & descModel )
{
  descModel.push_back(modelPair);
}

void
FuzzyDescriptorsModelManager
::AddDescriptor( std::string key, std::vector<double> model, DescriptorsModelType &
 descModel )
{
  PairType lPair( key, model );
  descModel.push_back(lPair);
}

void
FuzzyDescriptorsModelManager
::Print( const DescriptorsModelType & descModel )
{
  for(unsigned int i=0; i<descModel.size(); i++)
    {
      std::cout<<"Descriptor "<<descModel[i].first<<" parameters:" <<std::endl;
      const ParameterType & param = descModel[i].second;

      for(unsigned int j=0; j<param.size(); j++)
        {
          std::cout<<param[j]<<"  ";
        }
      std::cout<<std::endl;
    }
}

FuzzyDescriptorsModelManager::DescriptorsModelType
FuzzyDescriptorsModelManager
::Read(const std::string & filename)
{
  // Check if the filename is not empty
  if( filename.empty() == true )
    {
      itkGenericExceptionMacro(<<"The XML output FileName is empty");
    }

  // Check that the right extension is given : expected .xml */
  if (itksys::SystemTools::GetFilenameLastExtension(filename) != ".xml")
    {
    itkGenericExceptionMacro(<<itksys::SystemTools::GetFilenameLastExtension(filename)
                      <<" is a wrong Extension FileName : Expected .xml");
    }

  // Open the xml file
  TiXmlDocument doc(filename.c_str());
  if (!doc.LoadFile())
    {
    itkGenericExceptionMacro(<<"Can't open file "<<filename);
    }

  DescriptorsModelType descModel;

  TiXmlHandle hDoc(&doc);
  TiXmlHandle root    = hDoc.FirstChildElement("FuzzydDescriptorsModel");

  // Iterate through the tree to get all the stats
  for( TiXmlElement* currentStat = root.FirstChildElement().ToElement();
       currentStat != NULL;
       currentStat = currentStat->NextSiblingElement() )
    {
      PairType currentDescriptor;
      // Store the descriptor type name
      std::string lol;
      currentDescriptor.first = currentStat->Attribute("name");

      // The size is not stored in the XML file
      // Store the value in a std::vector, get the size and then
      // build a measurement vector
      ParameterType param;

      for( TiXmlElement* sample = currentStat->FirstChildElement("Parameter");
           sample != NULL;
           sample = sample->NextSiblingElement() )
        {
          // Get the current value of the descriptor
          double value;
          sample->QueryDoubleAttribute("value", &value);
          // Store the value
          param.push_back(value);
        }

      // Add descriptor parmaeters
      currentDescriptor.second = param;

      // Add the pai to the model
      descModel.push_back(currentDescriptor);
    }

  return descModel;
}

void
FuzzyDescriptorsModelManager
::Save(const std::string & filename, DescriptorsModelType & model )
{
  // Check if the filename is not empty
  if( filename.empty() == true )
    {
      itkGenericExceptionMacro(<<"The XML output FileName is empty");
    }

  // Check that the right extension is given : expected .xml */
  if (itksys::SystemTools::GetFilenameLastExtension(filename) != ".xml")
    {
      itkGenericExceptionMacro(<<itksys::SystemTools::GetFilenameLastExtension(filename)
                        <<" is a wrong Extension FileName : Expected .xml");
    }

  // Write the XML file
  TiXmlDocument doc;

  TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "", "" );
  doc.LinkEndChild( decl );

  TiXmlElement * root = new TiXmlElement( "FuzzydDescriptorsModel");
  doc.LinkEndChild( root );

  // Iterate through the input
  for (unsigned int i = 0; i < model.size(); i++)
    {
      // The current statistic
      TiXmlElement * desc = new TiXmlElement("Descriptor");
      desc->SetAttribute("name", model[i].first.c_str());
      root->LinkEndChild( desc );

      ParameterType param = model[i].second;
      // Store the value for this statistic
      for(unsigned int cindex = 0; cindex < param.size(); ++cindex)
        {
          // For each value in Measurementvector
          TiXmlElement * curStatisticVector = new TiXmlElement("Parameter");
          curStatisticVector->SetDoubleAttribute("value", param[cindex]);
          desc->LinkEndChild(curStatisticVector);
        }
    }

  // Finally, write the file
  doc.SaveFile( filename.c_str() );
}

} // End namespace otb

<commit_msg>ENH: add the iterator incrementation...<commit_after>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.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 "otbFuzzyDescriptorsModelManager.h"
#include "itkExceptionObject.h"
#include "itksys/SystemTools.hxx"
#include "tinyxml.h"

namespace otb {

FuzzyDescriptorsModelManager
::FuzzyDescriptorsModelManager()
{}

FuzzyDescriptorsModelManager::PairType
FuzzyDescriptorsModelManager
::GetDescriptor(const char * model, const DescriptorsModelType & descModel)
{
  PairType out;
  bool found = false;
  DescriptorsModelType::const_iterator it = descModel.begin();

  while( it!=descModel.end() && found == false)
    {
      if( (*it).first == model )
        {
          out = (*it);
        }
      ++it;
    }

  if( found == false )
    {
      itkGenericExceptionMacro(<<"No models named "<<model<<" found...");
    }

  return out;
}

void
FuzzyDescriptorsModelManager
::AddDescriptor( PairType modelPair, DescriptorsModelType & descModel )
{
  descModel.push_back(modelPair);
}

void
FuzzyDescriptorsModelManager
::AddDescriptor( std::string key, std::vector<double> model, DescriptorsModelType &
 descModel )
{
  PairType lPair( key, model );
  descModel.push_back(lPair);
}

void
FuzzyDescriptorsModelManager
::Print( const DescriptorsModelType & descModel )
{
  for(unsigned int i=0; i<descModel.size(); i++)
    {
      std::cout<<"Descriptor "<<descModel[i].first<<" parameters:" <<std::endl;
      const ParameterType & param = descModel[i].second;

      for(unsigned int j=0; j<param.size(); j++)
        {
          std::cout<<param[j]<<"  ";
        }
      std::cout<<std::endl;
    }
}

FuzzyDescriptorsModelManager::DescriptorsModelType
FuzzyDescriptorsModelManager
::Read(const std::string & filename)
{
  // Check if the filename is not empty
  if( filename.empty() == true )
    {
      itkGenericExceptionMacro(<<"The XML output FileName is empty");
    }

  // Check that the right extension is given : expected .xml */
  if (itksys::SystemTools::GetFilenameLastExtension(filename) != ".xml")
    {
    itkGenericExceptionMacro(<<itksys::SystemTools::GetFilenameLastExtension(filename)
                      <<" is a wrong Extension FileName : Expected .xml");
    }

  // Open the xml file
  TiXmlDocument doc(filename.c_str());
  if (!doc.LoadFile())
    {
    itkGenericExceptionMacro(<<"Can't open file "<<filename);
    }

  DescriptorsModelType descModel;

  TiXmlHandle hDoc(&doc);
  TiXmlHandle root    = hDoc.FirstChildElement("FuzzydDescriptorsModel");

  // Iterate through the tree to get all the stats
  for( TiXmlElement* currentStat = root.FirstChildElement().ToElement();
       currentStat != NULL;
       currentStat = currentStat->NextSiblingElement() )
    {
      PairType currentDescriptor;
      // Store the descriptor type name
      std::string lol;
      currentDescriptor.first = currentStat->Attribute("name");

      // The size is not stored in the XML file
      // Store the value in a std::vector, get the size and then
      // build a measurement vector
      ParameterType param;

      for( TiXmlElement* sample = currentStat->FirstChildElement("Parameter");
           sample != NULL;
           sample = sample->NextSiblingElement() )
        {
          // Get the current value of the descriptor
          double value;
          sample->QueryDoubleAttribute("value", &value);
          // Store the value
          param.push_back(value);
        }

      // Add descriptor parmaeters
      currentDescriptor.second = param;

      // Add the pai to the model
      descModel.push_back(currentDescriptor);
    }

  return descModel;
}

void
FuzzyDescriptorsModelManager
::Save(const std::string & filename, DescriptorsModelType & model )
{
  // Check if the filename is not empty
  if( filename.empty() == true )
    {
      itkGenericExceptionMacro(<<"The XML output FileName is empty");
    }

  // Check that the right extension is given : expected .xml */
  if (itksys::SystemTools::GetFilenameLastExtension(filename) != ".xml")
    {
      itkGenericExceptionMacro(<<itksys::SystemTools::GetFilenameLastExtension(filename)
                        <<" is a wrong Extension FileName : Expected .xml");
    }

  // Write the XML file
  TiXmlDocument doc;

  TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "", "" );
  doc.LinkEndChild( decl );

  TiXmlElement * root = new TiXmlElement( "FuzzydDescriptorsModel");
  doc.LinkEndChild( root );

  // Iterate through the input
  for (unsigned int i = 0; i < model.size(); i++)
    {
      // The current statistic
      TiXmlElement * desc = new TiXmlElement("Descriptor");
      desc->SetAttribute("name", model[i].first.c_str());
      root->LinkEndChild( desc );

      ParameterType param = model[i].second;
      // Store the value for this statistic
      for(unsigned int cindex = 0; cindex < param.size(); ++cindex)
        {
          // For each value in Measurementvector
          TiXmlElement * curStatisticVector = new TiXmlElement("Parameter");
          curStatisticVector->SetDoubleAttribute("value", param[cindex]);
          desc->LinkEndChild(curStatisticVector);
        }
    }

  // Finally, write the file
  doc.SaveFile( filename.c_str() );
}

} // End namespace otb

<|endoftext|>


<commit_before>// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

#include "db/version_edit.h"

#include "db/version_set.h"
#include "util/coding.h"

namespace leveldb {

// Tag numbers for serialized VersionEdit.  These numbers are written to
// disk and should not be changed.
enum Tag {
  kComparator           = 1,
  kLogNumber            = 2,
  kNextFileNumber       = 3,
  kLastSequence         = 4,
  kCompactPointer       = 5,
  kDeletedFile          = 6,
  kNewFile              = 7,
  // 8 was used for large value refs
  kPrevLogNumber        = 9
};

void VersionEdit::Clear() {
  comparator_.clear();
  log_number_ = 0;
  prev_log_number_ = 0;
  last_sequence_ = 0;
  next_file_number_ = 0;
  has_comparator_ = false;
  has_log_number_ = false;
  has_prev_log_number_ = false;
  has_next_file_number_ = false;
  has_last_sequence_ = false;
  deleted_files_.clear();
  new_files_.clear();
}

void VersionEdit::EncodeTo(std::string* dst) const {
  if (has_comparator_) {
    PutVarint32(dst, kComparator);
    PutLengthPrefixedSlice(dst, comparator_);
  }
  if (has_log_number_) {
    PutVarint32(dst, kLogNumber);
    PutVarint64(dst, log_number_);
  }
  if (has_prev_log_number_) {
    PutVarint32(dst, kPrevLogNumber);
    PutVarint64(dst, prev_log_number_);
  }
  if (has_next_file_number_) {
    PutVarint32(dst, kNextFileNumber);
    PutVarint64(dst, next_file_number_);
  }
  if (has_last_sequence_) {
    PutVarint32(dst, kLastSequence);
    PutVarint64(dst, last_sequence_);
  }

  for (size_t i = 0; i < compact_pointers_.size(); i++) {
    PutVarint32(dst, kCompactPointer);
    PutVarint32(dst, compact_pointers_[i].first);  // level
    PutLengthPrefixedSlice(dst, compact_pointers_[i].second.Encode());
  }

  for (DeletedFileSet::const_iterator iter = deleted_files_.begin();
       iter != deleted_files_.end();
       ++iter) {
    PutVarint32(dst, kDeletedFile);
    PutVarint32(dst, iter->first);   // level
    PutVarint64(dst, iter->second);  // file number
  }

  for (size_t i = 0; i < new_files_.size(); i++) {
    const FileMetaData& f = new_files_[i].second;
    PutVarint32(dst, kNewFile);
    PutVarint32(dst, new_files_[i].first);  // level
    PutVarint64(dst, f.number);
    PutVarint64(dst, f.file_size);
    PutLengthPrefixedSlice(dst, f.smallest.Encode());
    PutLengthPrefixedSlice(dst, f.largest.Encode());
  }
}

static bool GetInternalKey(Slice* input, InternalKey* dst) {
  Slice str;
  if (GetLengthPrefixedSlice(input, &str)) {
    dst->DecodeFrom(str);
    return true;
  } else {
    return false;
  }
}

static bool GetLevel(Slice* input, int* level) {
  uint32_t v;
  if (GetVarint32(input, &v) &&
      v < config::kNumLevels) {
    *level = v;
    return true;
  } else {
    return false;
  }
}

Status VersionEdit::DecodeFrom(const Slice& src) {
  Clear();
  Slice input = src;
  const char* msg = NULL;
  uint32_t tag;

  // Temporary storage for parsing
  int level;
  uint64_t number;
  FileMetaData f;
  Slice str;
  InternalKey key;

  while (msg == NULL && GetVarint32(&input, &tag)) {
    switch (tag) {
      case kComparator:
        if (GetLengthPrefixedSlice(&input, &str)) {
          comparator_ = str.ToString();
          has_comparator_ = true;
        } else {
          msg = "comparator name";
        }
        break;

      case kLogNumber:
        if (GetVarint64(&input, &log_number_)) {
          has_log_number_ = true;
        } else {
          msg = "log number";
        }
        break;

      case kPrevLogNumber:
        if (GetVarint64(&input, &prev_log_number_)) {
          has_prev_log_number_ = true;
        } else {
          msg = "previous log number";
        }
        break;

      case kNextFileNumber:
        if (GetVarint64(&input, &next_file_number_)) {
          has_next_file_number_ = true;
        } else {
          msg = "next file number";
        }
        break;

      case kLastSequence:
        if (GetVarint64(&input, &last_sequence_)) {
          has_last_sequence_ = true;
        } else {
          msg = "last sequence number";
        }
        break;

      case kCompactPointer:
        if (GetLevel(&input, &level) &&
            GetInternalKey(&input, &key)) {
          compact_pointers_.push_back(std::make_pair(level, key));
        } else {
          msg = "compaction pointer";
        }
        break;

      case kDeletedFile:
        if (GetLevel(&input, &level) &&
            GetVarint64(&input, &number)) {
          deleted_files_.insert(std::make_pair(level, number));
        } else {
          msg = "deleted file";
        }
        break;

      case kNewFile:
        if (GetLevel(&input, &level) &&
            GetVarint64(&input, &f.number) &&
            GetVarint64(&input, &f.file_size) &&
            GetInternalKey(&input, &f.smallest) &&
            GetInternalKey(&input, &f.largest)) {
          new_files_.push_back(std::make_pair(level, f));
        } else {
          msg = "new-file entry";
        }
        break;

      default:
        msg = "unknown tag";
        break;
    }
  }

  if (msg == NULL && !input.empty()) {
    msg = "invalid tag";
  }

  Status result;
  if (msg != NULL) {
    result = Status::Corruption("VersionEdit", msg);
  }
  return result;
}

std::string VersionEdit::DebugString() const {
  std::string r;
  r.append("VersionEdit {");
  if (has_comparator_) {
    r.append("\n  Comparator: ");
    r.append(comparator_);
  }
  if (has_log_number_) {
    r.append("\n  LogNumber: ");
    AppendNumberTo(&r, log_number_);
  }
  if (has_prev_log_number_) {
    r.append("\n  PrevLogNumber: ");
    AppendNumberTo(&r, prev_log_number_);
  }
  if (has_next_file_number_) {
    r.append("\n  NextFile: ");
    AppendNumberTo(&r, next_file_number_);
  }
  if (has_last_sequence_) {
    r.append("\n  LastSeq: ");
    AppendNumberTo(&r, last_sequence_);
  }
  for (size_t i = 0; i < compact_pointers_.size(); i++) {
    r.append("\n  CompactPointer: ");
    AppendNumberTo(&r, compact_pointers_[i].first);
    r.append(" ");
    r.append(compact_pointers_[i].second.DebugString());
  }
  for (DeletedFileSet::const_iterator iter = deleted_files_.begin();
       iter != deleted_files_.end();
       ++iter) {
    r.append("\n  DeleteFile: ");
    AppendNumberTo(&r, iter->first);
    r.append(" ");
    AppendNumberTo(&r, iter->second);
  }
  for (size_t i = 0; i < new_files_.size(); i++) {
    const FileMetaData& f = new_files_[i].second;
    r.append("\n  AddFile: ");
    AppendNumberTo(&r, new_files_[i].first);
    r.append(" ");
    AppendNumberTo(&r, f.number);
    r.append(" ");
    AppendNumberTo(&r, f.file_size);
    r.append(" ");
    r.append(f.smallest.DebugString());
    r.append(" .. ");
    r.append(f.largest.DebugString());
  }
  r.append("\n}\n");
  return r;
}

}  // namespace leveldb
<commit_msg>Delete version_edit.cc<commit_after><|endoftext|>


<commit_before>#include <iostream>
#include <cstring>
#include <stdlib.h>
#include <stdexcept>
#include "Person.h"
#include "string.h"
using std::invalid_argument;

//CONSTRUCTORS
Person::Person()
{
}

Person::Person(const char* name, const char* egn, const char* address, ProfessionEnum job, double income)
{
	SetName(name);

	ValidateEGN(egn);
	this->EGN = new char[strlen(egn) + 1];
	strcpy(this->EGN, egn);

	SetAddress(address);
	this->age = CalculateAge();
	this->sex = GetSexFromEGN();
	SetJob(job);
	SetIncome(income);
}

Person::Person(const Person& otherPerson)
{
	this->name = new char[strlen(otherPerson.name) + 1];
	strcpy(this->name, otherPerson.name);

	this->EGN = new char[strlen(otherPerson.EGN) + 1];
	strcpy(this->EGN, otherPerson.EGN);

	this->address = new char[strlen(otherPerson.address) + 1];
	strcpy(this->address, otherPerson.address);

	this->age = otherPerson.age;
	this->sex = otherPerson.sex;
	this->job = otherPerson.job;
	this->income = otherPerson.income;
}

Person& Person::operator = (const Person& otherPerson)
{
	this->name = new char[strlen(otherPerson.name) + 1];
	strcpy(this->name, otherPerson.name);

	this->EGN = new char[strlen(otherPerson.EGN) + 1];
	strcpy(this->EGN, otherPerson.EGN);

	this->address = new char[strlen(otherPerson.address) + 1];
	strcpy(this->address, otherPerson.address);

	this->age = otherPerson.age;
	this->sex = otherPerson.sex;
	this->job = otherPerson.job;
	this->income = otherPerson.income;

	return *this;
}

Person::~Person()
{
	delete[] name;
	delete[] EGN;
	delete[] address;
}

//Private Methods
unsigned short Person::CalculateAge() const
{
	unsigned short currentYear = 113;
	unsigned short yearBorn = (short)(EGN[0] - '0') * 10 + (short)(EGN[1] - '0');

	return currentYear - yearBorn;
}

SexEnum Person::GetSexFromEGN() const
{
	int digitPosShowingSex = 8;
	int sexDigit = (int)(EGN[digitPosShowingSex] - '0');
	SexEnum sex = Female;

	if (sexDigit % 2 == 0)
	{
		sex = Male;
	}

	return sex;
}

void Person::ValidateEGN(const char* egn) const
{
	if (!egn)
	{
		throw std::invalid_argument("EGN must not be null!");
	}

	unsigned short egnLenght = strlen(egn);
	if (egnLenght != 10)
	{
		throw std::length_error("ENG must be 10 digits long!!!");
	}

	for (int index = 0; index < egnLenght; index++)
	{
		if (egn[index] - '0' < 0 || egn[index] - '0' > 9)
		{
			throw invalid_argument("EGN must be consisted entirely by numbers!!!");
		}
	}
}

//Public Methods
char* Person::JobAsString() const
{
	switch (job)
	{
	case Baker:
		return "Baker";
	case Teacher:
		return "Teacher";
	case Janitor:
		return "Janitor";
	case Gamer:
		return "Gamer";
	case Journalist:
		return "Journalist";
	case SoftwareDev:
		return "SoftwareDev";
	case Unemployed:
		return "Unemployed";
	default:
		return "Unemployed";
	}
}

void Person::Information(std::ostream& output = std::cout) const
{
	output << "Name: "<< this->GetName()
		<<"\nEGN: "<< this->GetEGN()
		<<"\nAddress: "<< this->GetAddress()
		<<"\nAge: "<< this->GetAge()
		<<"\nSex: "<< (this->GetSexType() == 0 ? "Male" : "Female")
		<<"\nJob: "<< this->JobAsString()
		<<"\nIncome: "<< this->GetIncome()
		<< std::endl;
}

//Getter and setter for name
char* Person::GetName() const
{
	return this->name;
}

void Person::SetName(const char* name)
{
	if (!name)
	{
		throw invalid_argument("Name can't be null!");
	}

	this->name = new char[strlen(name) + 1];
	strcpy(this->name, name);
}

//Getter for EGN
char* Person::GetEGN() const
{
	return this->EGN;
}

//Getter and setter for address
char* Person::GetAddress() const
{
	return this->address;
}

void Person::SetAddress(const char* address)
{
	if (!address)
	{
		throw invalid_argument("Address can't be null!");
	}

	this->address = new char[strlen(address) + 1];
	strcpy(this->address, address);
}

//Getter for age
unsigned short Person::GetAge() const
{
	return this->age;
}

//Getter for sex
SexEnum Person::GetSexType() const
{
	return this->sex;
}

//Getter and setter for job
ProfessionEnum Person::GetJob() const
{
	return this->job;
}

void Person::SetJob(ProfessionEnum job)
{
	this->job = job;
}

//Getter and setter for income
double Person::GetIncome() const
{
	return this->income;
}

void Person::SetIncome(double income)
{
	if (income < 0)
	{
		throw std::range_error("Income must not be negative!");
	}
	else
	{
		this->income = income;
	}
}

std::ostream& operator <<(std::ostream& output, const Person& person)
{
	person.Information(output);

	return output;
}
<commit_msg>update<commit_after>#include <iostream>
#include <cstring>
#include <stdlib.h>
#include <stdexcept>
#include "Person.h"
#include "string.h"
using std::invalid_argument;

//CONSTRUCTORS
Person::Person()
{
}

Person::Person(const char* name, const char* egn, const char* address, ProfessionEnum job, double income)
{
	SetName(name);

	ValidateEGN(egn);
	this->EGN = new char[strlen(egn) + 1];
	strcpy(this->EGN, egn);

	SetAddress(address);
	this->age = CalculateAge();
	this->sex = GetSexFromEGN();
	SetJob(job);
	SetIncome(income);
}

Person::Person(const Person& otherPerson)
{
	this->name = new char[strlen(otherPerson.name) + 1];
	strcpy(this->name, otherPerson.name);

	this->EGN = new char[strlen(otherPerson.EGN) + 1];
	strcpy(this->EGN, otherPerson.EGN);

	this->address = new char[strlen(otherPerson.address) + 1];
	strcpy(this->address, otherPerson.address);

	this->age = otherPerson.age;
	this->sex = otherPerson.sex;
	this->job = otherPerson.job;
	this->income = otherPerson.income;
}

Person& Person::operator = (const Person& otherPerson)
{
	if (this != &otherPerson)
	{
		delete[] name;
		delete[] EGN;
		delete[] address;

		this->name = new char[strlen(otherPerson.name) + 1];
		strcpy(this->name, otherPerson.name);

		this->EGN = new char[strlen(otherPerson.EGN) + 1];
		strcpy(this->EGN, otherPerson.EGN);

		this->address = new char[strlen(otherPerson.address) + 1];
		strcpy(this->address, otherPerson.address);

		this->age = otherPerson.age;
		this->sex = otherPerson.sex;
		this->job = otherPerson.job;
		this->income = otherPerson.income;
	}

	return *this;
}

Person::~Person()
{
	delete[] name;
	delete[] EGN;
	delete[] address;
}

//Private Methods
unsigned short Person::CalculateAge() const
{
	unsigned short currentYear = 113;
	unsigned short yearBorn = (short)(EGN[0] - '0') * 10 + (short)(EGN[1] - '0');

	return currentYear - yearBorn;
}

SexEnum Person::GetSexFromEGN() const
{
	int digitPosShowingSex = 8;
	int sexDigit = (int)(EGN[digitPosShowingSex] - '0');
	SexEnum sex = Female;

	if (sexDigit % 2 == 0)
	{
		sex = Male;
	}

	return sex;
}

void Person::ValidateEGN(const char* egn) const
{
	if (!egn)
	{
		throw std::invalid_argument("EGN must not be null!");
	}

	unsigned short egnLenght = strlen(egn);
	if (egnLenght != 10)
	{
		throw std::length_error("ENG must be 10 digits long!!!");
	}

	for (int index = 0; index < egnLenght; index++)
	{
		if (egn[index] - '0' < 0 || egn[index] - '0' > 9)
		{
			throw invalid_argument("EGN must be consisted entirely by numbers!!!");
		}
	}
}

//Public Methods
char* Person::JobAsString() const
{
	switch (job)
	{
	case Baker:
		return "Baker";
	case Teacher:
		return "Teacher";
	case Janitor:
		return "Janitor";
	case Gamer:
		return "Gamer";
	case Journalist:
		return "Journalist";
	case SoftwareDev:
		return "SoftwareDev";
	case Unemployed:
		return "Unemployed";
	default:
		return "Unemployed";
	}
}

void Person::Information(std::ostream& output = std::cout) const
{
	output << "Name: "<< this->GetName()
		<<"\nEGN: "<< this->GetEGN()
		<<"\nAddress: "<< this->GetAddress()
		<<"\nAge: "<< this->GetAge()
		<<"\nSex: "<< (this->GetSexType() == 0 ? "Male" : "Female")
		<<"\nJob: "<< this->JobAsString()
		<<"\nIncome: "<< this->GetIncome()
		<< std::endl;
}

//Getter and setter for name
char* Person::GetName() const
{
	return this->name;
}

void Person::SetName(const char* name)
{
	if (!name)
	{
		throw invalid_argument("Name can't be null!");
	}

	this->name = new char[strlen(name) + 1];
	strcpy(this->name, name);
}

//Getter for EGN
char* Person::GetEGN() const
{
	return this->EGN;
}

//Getter and setter for address
char* Person::GetAddress() const
{
	return this->address;
}

void Person::SetAddress(const char* address)
{
	if (!address)
	{
		throw invalid_argument("Address can't be null!");
	}

	this->address = new char[strlen(address) + 1];
	strcpy(this->address, address);
}

//Getter for age
unsigned short Person::GetAge() const
{
	return this->age;
}

//Getter for sex
SexEnum Person::GetSexType() const
{
	return this->sex;
}

//Getter and setter for job
ProfessionEnum Person::GetJob() const
{
	return this->job;
}

void Person::SetJob(ProfessionEnum job)
{
	this->job = job;
}

//Getter and setter for income
double Person::GetIncome() const
{
	return this->income;
}

void Person::SetIncome(double income)
{
	if (income < 0)
	{
		throw std::range_error("Income must not be negative!");
	}
	else
	{
		this->income = income;
	}
}

std::ostream& operator <<(std::ostream& output, const Person& person)
{
	person.Information(output);

	return output;
}
<|endoftext|>


<commit_before>//Copyright (c) 2020 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "ExtruderTrain.h"
#include "FffGcodeWriter.h"
#include "InsetOrderOptimizer.h"
#include "LayerPlan.h"
#include "utils/logoutput.h"
#include "WallToolPaths.h"

namespace cura
{

InsetOrderOptimizer::InsetOrderOptimizer(const FffGcodeWriter& gcode_writer, const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const int extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const VariableWidthPaths& paths, unsigned int layer_nr) :
    gcode_writer(gcode_writer),
    storage(storage),
    gcode_layer(gcode_layer),
    mesh(mesh),
    extruder_nr(extruder_nr),
    mesh_config(mesh_config),
    paths(paths),
    layer_nr(layer_nr),
    z_seam_config(mesh.settings.get<EZSeamType>("z_seam_type"), mesh.getZSeamHint(), mesh.settings.get<EZSeamCornerPrefType>("z_seam_corner")),
    added_something(false),
    retraction_region_calculated(false)
{
}

bool InsetOrderOptimizer::optimize(const WallType& wall_type)
{
    // Settings & configs:
    const GCodePathConfig& skin_or_infill_config = wall_type == WallType::EXTRA_SKIN ? mesh_config.skin_config : mesh_config.infill_config[0];
    const bool do_outer_wall = wall_type == WallType::OUTER_WALL;
    const GCodePathConfig& inset_0_non_bridge_config = do_outer_wall ? mesh_config.inset0_config : skin_or_infill_config;
    const GCodePathConfig& inset_X_non_bridge_config = do_outer_wall ? mesh_config.insetX_config : skin_or_infill_config;
    const GCodePathConfig& inset_0_bridge_config = do_outer_wall ? mesh_config.bridge_inset0_config : skin_or_infill_config;
    const GCodePathConfig& inset_X_bridge_config = do_outer_wall ? mesh_config.bridge_insetX_config : skin_or_infill_config;

    const size_t wall_0_extruder_nr = mesh.settings.get<ExtruderTrain&>("wall_0_extruder_nr").extruder_nr;
    const size_t wall_x_extruder_nr = mesh.settings.get<ExtruderTrain&>("wall_x_extruder_nr").extruder_nr;
    const size_t top_bottom_extruder_nr = mesh.settings.get<ExtruderTrain&>("top_bottom_extruder_nr").extruder_nr;
    const size_t infill_extruder_nr = mesh.settings.get<ExtruderTrain&>("infill_extruder_nr").extruder_nr;

    const bool ignore_inner_insets = !mesh.settings.get<bool>("optimize_wall_printing_order");
    // If the outer wall extruder is different than the inner wall extruder, don't apply the outer_inset_first to the skin
    // and infill insets.
    const bool outer_inset_first = wall_0_extruder_nr == wall_x_extruder_nr && mesh.settings.get<bool>("outer_inset_first");

    //Bin the insets in order to print the inset indices together, and to optimize the order of each bin to reduce travels.
    std::set<size_t> bins_with_index_zero_insets;
    BinJunctions insets = variableWidthPathToBinJunctions(paths, ignore_inner_insets, outer_inset_first, &bins_with_index_zero_insets);

    size_t start_inset;
    size_t end_inset;
    int direction;
    if((wall_type == WallType::OUTER_WALL && wall_0_extruder_nr == wall_x_extruder_nr && wall_x_extruder_nr == extruder_nr) ||
            (wall_type == WallType::EXTRA_SKIN && extruder_nr == top_bottom_extruder_nr) ||
            (wall_type == WallType::EXTRA_INFILL && extruder_nr == infill_extruder_nr))
    {
        //If printing the outer inset first, start with the lowest inset.
        //Otherwise start with the highest inset and iterate backwards.
        if(outer_inset_first)
        {
            start_inset = 0;
            end_inset = insets.size();
            direction = 1;
        }
        else
        {
            start_inset = insets.size() - 1;
            end_inset = -1;
            direction = -1;
        }
    }
    else if(wall_type == WallType::OUTER_WALL && wall_0_extruder_nr != wall_x_extruder_nr)
    {
        //If the wall_0 and wall_x extruders are different, then only include the insets that should be printed by the
        //current extruder_nr.
        if(extruder_nr == wall_0_extruder_nr)
        {
            start_inset = 0;
            end_inset = 1; // Ignore inner walls
            direction = 1;
        }
        else if(extruder_nr == wall_x_extruder_nr)
        {
            start_inset = insets.size() - 1;
            end_inset = 0; // Ignore outer wall
            direction = -1;
        }
        else
        {
            return added_something;
        }
    }
    else
    {
        return added_something;
    }

    //Add all of the insets one by one.
    constexpr Ratio flow = 1.0_r;
    const bool retract_before_outer_wall = mesh.settings.get<bool>("travel_retract_before_outer_wall");
    const coord_t wall_0_wipe_dist = mesh.settings.get<coord_t>("wall_0_wipe_dist");
    for(size_t inset = start_inset; inset != end_inset; inset += direction)
    {
        if(insets[inset].empty())
        {
            continue; //Don't switch extruders either, etc.
        }
        added_something = true;
        gcode_writer.setExtruder_addPrime(storage, gcode_layer, extruder_nr);
        gcode_layer.setIsInside(true); //Going to print walls, which are always inside.
        ZSeamConfig z_seam_config(mesh.settings.get<EZSeamType>("z_seam_type"), mesh.getZSeamHint(), mesh.settings.get<EZSeamCornerPrefType>("z_seam_corner"));

        if(bins_with_index_zero_insets.count(inset) > 0) //Print using outer wall config.
        {
            gcode_layer.addWalls(insets[inset], mesh, inset_0_non_bridge_config, inset_0_bridge_config, z_seam_config, wall_0_wipe_dist, flow, retract_before_outer_wall);
        }
        else
        {
            gcode_layer.addWalls(insets[inset], mesh, inset_X_non_bridge_config, inset_X_bridge_config, z_seam_config, 0, flow, false);
        }
    }
    return added_something;
}

size_t InsetOrderOptimizer::getOuterRegionId(const VariableWidthPaths& toolpaths, size_t& out_number_of_regions)
{
    // Polygons show up here one by one, so there are always only a) the outer lines and b) the lines that are part of the holes.
    // Therefore, the outer-regions' lines will always have the region-id that is larger then all of the other ones.

    // First, build the bounding boxes:
    std::map<size_t, AABB> region_ids_to_bboxes;
    for (const VariableWidthLines& path : toolpaths)
    {
        for (const ExtrusionLine& line : path)
        {
            if (region_ids_to_bboxes.count(line.region_id) == 0)
            {
                region_ids_to_bboxes[line.region_id] = AABB();
            }
            AABB& aabb = region_ids_to_bboxes[line.region_id];
            for (const auto& junction : line.junctions)
            {
                aabb.include(junction.p);
            }
        }
    }

    // Then, the largest of these will be the one that's needed for the outer region, the others' all belong to hole regions:
    AABB outer_bbox;
    size_t outer_region_id = 0; // Region-ID 0 is reserved for 'None'.
    for (const auto& region_id_bbox_pair : region_ids_to_bboxes)
    {
        if (region_id_bbox_pair.second.contains(outer_bbox))
        {
            outer_bbox = region_id_bbox_pair.second;
            outer_region_id = region_id_bbox_pair.first;
        }
    }

    out_number_of_regions = region_ids_to_bboxes.size();
    return outer_region_id;
}

BinJunctions InsetOrderOptimizer::variableWidthPathToBinJunctions(const VariableWidthPaths& toolpaths, const bool& ignore_inner_inset_order, const bool& pack_regions_by_inset, std::set<size_t>* p_bins_with_index_zero_insets)
{
    // Find the largest inset-index:
    size_t max_inset_index = 0;
    for (const VariableWidthLines& path : toolpaths)
    {
        max_inset_index = std::max(path.front().inset_idx, max_inset_index);
    }

    // Find which regions are associated with the outer-outer walls (which region is the one the rest is holes inside of):
    size_t number_of_regions = 0;
    const size_t outer_region_id = getOuterRegionId(toolpaths, number_of_regions);

    // Since we're (optionally!) splitting off in the outer and inner regions, it may need twice as many bins as inset-indices.
    const size_t max_bin = ignore_inner_inset_order ? (number_of_regions * 2) + 2 : (max_inset_index + 1) * 2;
    BinJunctions insets(max_bin + 1);
    for (const VariableWidthLines& path : toolpaths)
    {
        if (path.empty()) // Don't bother printing these.
        {
            continue;
        }
        const size_t inset_index = path.front().inset_idx;

        // Convert list of extrusion lines to vectors of extrusion junctions, and add those to the binned insets.
        for (const ExtrusionLine& line : path)
        {
            // Sort into the right bin, ...
            size_t bin_index;
            const bool in_hole_region = line.region_id != outer_region_id && line.region_id != 0;
            if(ignore_inner_inset_order)
            {
                bin_index = std::min(inset_index, static_cast<size_t>(1)) + 2 * (in_hole_region ? line.region_id : 0);
            }
            else
            {
                if (pack_regions_by_inset)  // <- inset-0 region-A, inset-0 B, inset-1 A, inset-1 B, inset-2 A, inset-2 B, ..., etc.
                {
                    bin_index = (inset_index * 2) + (in_hole_region ? 1 : 0);
                }
                else  // <- inset-0 region-A, inset-1 A, inset-2 A, ..., inset-0 B, inset-1 B, inset-2 B, ..., etc.
                {
                    bin_index = inset_index + (in_hole_region ? (max_inset_index + 1) : 0);
                }
            }
            insets[bin_index].emplace_back(line.junctions.begin(), line.junctions.end());

            // Collect all bins that have zero-inset indices in them, if needed:
            if (inset_index == 0 && p_bins_with_index_zero_insets != nullptr)
            {
                p_bins_with_index_zero_insets->insert(bin_index);
            }
        }
    }
    return insets;
}

}//namespace cura
<commit_msg>Document the major if-else cases<commit_after>//Copyright (c) 2020 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "ExtruderTrain.h"
#include "FffGcodeWriter.h"
#include "InsetOrderOptimizer.h"
#include "LayerPlan.h"
#include "utils/logoutput.h"
#include "WallToolPaths.h"

namespace cura
{

InsetOrderOptimizer::InsetOrderOptimizer(const FffGcodeWriter& gcode_writer, const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const int extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const VariableWidthPaths& paths, unsigned int layer_nr) :
    gcode_writer(gcode_writer),
    storage(storage),
    gcode_layer(gcode_layer),
    mesh(mesh),
    extruder_nr(extruder_nr),
    mesh_config(mesh_config),
    paths(paths),
    layer_nr(layer_nr),
    z_seam_config(mesh.settings.get<EZSeamType>("z_seam_type"), mesh.getZSeamHint(), mesh.settings.get<EZSeamCornerPrefType>("z_seam_corner")),
    added_something(false),
    retraction_region_calculated(false)
{
}

bool InsetOrderOptimizer::optimize(const WallType& wall_type)
{
    // Settings & configs:
    const GCodePathConfig& skin_or_infill_config = wall_type == WallType::EXTRA_SKIN ? mesh_config.skin_config : mesh_config.infill_config[0];
    const bool do_outer_wall = wall_type == WallType::OUTER_WALL;
    const GCodePathConfig& inset_0_non_bridge_config = do_outer_wall ? mesh_config.inset0_config : skin_or_infill_config;
    const GCodePathConfig& inset_X_non_bridge_config = do_outer_wall ? mesh_config.insetX_config : skin_or_infill_config;
    const GCodePathConfig& inset_0_bridge_config = do_outer_wall ? mesh_config.bridge_inset0_config : skin_or_infill_config;
    const GCodePathConfig& inset_X_bridge_config = do_outer_wall ? mesh_config.bridge_insetX_config : skin_or_infill_config;

    const size_t wall_0_extruder_nr = mesh.settings.get<ExtruderTrain&>("wall_0_extruder_nr").extruder_nr;
    const size_t wall_x_extruder_nr = mesh.settings.get<ExtruderTrain&>("wall_x_extruder_nr").extruder_nr;
    const size_t top_bottom_extruder_nr = mesh.settings.get<ExtruderTrain&>("top_bottom_extruder_nr").extruder_nr;
    const size_t infill_extruder_nr = mesh.settings.get<ExtruderTrain&>("infill_extruder_nr").extruder_nr;

    const bool ignore_inner_insets = !mesh.settings.get<bool>("optimize_wall_printing_order");
    // If the outer wall extruder is different than the inner wall extruder, don't apply the outer_inset_first to the skin
    // and infill insets.
    const bool outer_inset_first = wall_0_extruder_nr == wall_x_extruder_nr && mesh.settings.get<bool>("outer_inset_first");

    //Bin the insets in order to print the inset indices together, and to optimize the order of each bin to reduce travels.
    std::set<size_t> bins_with_index_zero_insets;
    BinJunctions insets = variableWidthPathToBinJunctions(paths, ignore_inner_insets, outer_inset_first, &bins_with_index_zero_insets);

    size_t start_inset;
    size_t end_inset;
    int direction;
    //If the entire wall is printed with the current extruder, print all of it.
    if((wall_type == WallType::OUTER_WALL && wall_0_extruder_nr == wall_x_extruder_nr && wall_x_extruder_nr == extruder_nr) ||
            (wall_type == WallType::EXTRA_SKIN && extruder_nr == top_bottom_extruder_nr) ||
            (wall_type == WallType::EXTRA_INFILL && extruder_nr == infill_extruder_nr))
    {
        //If printing the outer inset first, start with the lowest inset.
        //Otherwise start with the highest inset and iterate backwards.
        if(outer_inset_first)
        {
            start_inset = 0;
            end_inset = insets.size();
            direction = 1;
        }
        else
        {
            start_inset = insets.size() - 1;
            end_inset = -1;
            direction = -1;
        }
    }
    //If the wall is partially printed with the current extruder, print the correct part.
    else if(wall_type == WallType::OUTER_WALL && wall_0_extruder_nr != wall_x_extruder_nr)
    {
        //If the wall_0 and wall_x extruders are different, then only include the insets that should be printed by the
        //current extruder_nr.
        if(extruder_nr == wall_0_extruder_nr)
        {
            start_inset = 0;
            end_inset = 1; // Ignore inner walls
            direction = 1;
        }
        else if(extruder_nr == wall_x_extruder_nr)
        {
            start_inset = insets.size() - 1;
            end_inset = 0; // Ignore outer wall
            direction = -1;
        }
        else
        {
            return added_something;
        }
    }
    else //The wall is not printed with this extruder, not even in part. Don't print anything then.
    {
        return added_something;
    }

    //Add all of the insets one by one.
    constexpr Ratio flow = 1.0_r;
    const bool retract_before_outer_wall = mesh.settings.get<bool>("travel_retract_before_outer_wall");
    const coord_t wall_0_wipe_dist = mesh.settings.get<coord_t>("wall_0_wipe_dist");
    for(size_t inset = start_inset; inset != end_inset; inset += direction)
    {
        if(insets[inset].empty())
        {
            continue; //Don't switch extruders either, etc.
        }
        added_something = true;
        gcode_writer.setExtruder_addPrime(storage, gcode_layer, extruder_nr);
        gcode_layer.setIsInside(true); //Going to print walls, which are always inside.
        ZSeamConfig z_seam_config(mesh.settings.get<EZSeamType>("z_seam_type"), mesh.getZSeamHint(), mesh.settings.get<EZSeamCornerPrefType>("z_seam_corner"));

        if(bins_with_index_zero_insets.count(inset) > 0) //Print using outer wall config.
        {
            gcode_layer.addWalls(insets[inset], mesh, inset_0_non_bridge_config, inset_0_bridge_config, z_seam_config, wall_0_wipe_dist, flow, retract_before_outer_wall);
        }
        else
        {
            gcode_layer.addWalls(insets[inset], mesh, inset_X_non_bridge_config, inset_X_bridge_config, z_seam_config, 0, flow, false);
        }
    }
    return added_something;
}

size_t InsetOrderOptimizer::getOuterRegionId(const VariableWidthPaths& toolpaths, size_t& out_number_of_regions)
{
    // Polygons show up here one by one, so there are always only a) the outer lines and b) the lines that are part of the holes.
    // Therefore, the outer-regions' lines will always have the region-id that is larger then all of the other ones.

    // First, build the bounding boxes:
    std::map<size_t, AABB> region_ids_to_bboxes;
    for (const VariableWidthLines& path : toolpaths)
    {
        for (const ExtrusionLine& line : path)
        {
            if (region_ids_to_bboxes.count(line.region_id) == 0)
            {
                region_ids_to_bboxes[line.region_id] = AABB();
            }
            AABB& aabb = region_ids_to_bboxes[line.region_id];
            for (const auto& junction : line.junctions)
            {
                aabb.include(junction.p);
            }
        }
    }

    // Then, the largest of these will be the one that's needed for the outer region, the others' all belong to hole regions:
    AABB outer_bbox;
    size_t outer_region_id = 0; // Region-ID 0 is reserved for 'None'.
    for (const auto& region_id_bbox_pair : region_ids_to_bboxes)
    {
        if (region_id_bbox_pair.second.contains(outer_bbox))
        {
            outer_bbox = region_id_bbox_pair.second;
            outer_region_id = region_id_bbox_pair.first;
        }
    }

    out_number_of_regions = region_ids_to_bboxes.size();
    return outer_region_id;
}

BinJunctions InsetOrderOptimizer::variableWidthPathToBinJunctions(const VariableWidthPaths& toolpaths, const bool& ignore_inner_inset_order, const bool& pack_regions_by_inset, std::set<size_t>* p_bins_with_index_zero_insets)
{
    // Find the largest inset-index:
    size_t max_inset_index = 0;
    for (const VariableWidthLines& path : toolpaths)
    {
        max_inset_index = std::max(path.front().inset_idx, max_inset_index);
    }

    // Find which regions are associated with the outer-outer walls (which region is the one the rest is holes inside of):
    size_t number_of_regions = 0;
    const size_t outer_region_id = getOuterRegionId(toolpaths, number_of_regions);

    // Since we're (optionally!) splitting off in the outer and inner regions, it may need twice as many bins as inset-indices.
    const size_t max_bin = ignore_inner_inset_order ? (number_of_regions * 2) + 2 : (max_inset_index + 1) * 2;
    BinJunctions insets(max_bin + 1);
    for (const VariableWidthLines& path : toolpaths)
    {
        if (path.empty()) // Don't bother printing these.
        {
            continue;
        }
        const size_t inset_index = path.front().inset_idx;

        // Convert list of extrusion lines to vectors of extrusion junctions, and add those to the binned insets.
        for (const ExtrusionLine& line : path)
        {
            // Sort into the right bin, ...
            size_t bin_index;
            const bool in_hole_region = line.region_id != outer_region_id && line.region_id != 0;
            if(ignore_inner_inset_order)
            {
                bin_index = std::min(inset_index, static_cast<size_t>(1)) + 2 * (in_hole_region ? line.region_id : 0);
            }
            else
            {
                if (pack_regions_by_inset)  // <- inset-0 region-A, inset-0 B, inset-1 A, inset-1 B, inset-2 A, inset-2 B, ..., etc.
                {
                    bin_index = (inset_index * 2) + (in_hole_region ? 1 : 0);
                }
                else  // <- inset-0 region-A, inset-1 A, inset-2 A, ..., inset-0 B, inset-1 B, inset-2 B, ..., etc.
                {
                    bin_index = inset_index + (in_hole_region ? (max_inset_index + 1) : 0);
                }
            }
            insets[bin_index].emplace_back(line.junctions.begin(), line.junctions.end());

            // Collect all bins that have zero-inset indices in them, if needed:
            if (inset_index == 0 && p_bins_with_index_zero_insets != nullptr)
            {
                p_bins_with_index_zero_insets->insert(bin_index);
            }
        }
    }
    return insets;
}

}//namespace cura
<|endoftext|>


<commit_before>/*
    Copyright (C) 2005 by Andrew Mann
    Based in part on work by Norman Kraemer

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "iutil/comp.h"
#include "isndsys/ss_stream.h"
#include "oggdata2.h"
#include "oggstream2.h"

#include "ivaria/reporter.h"

/* Keep these as integer values or the stream may feed portions of a sample to
 * the higher layer which may cause problems
 * 1 , 1 will decode 1/1 or 1 second of audio in advance */
#define OGG_BUFFER_LENGTH_MULTIPLIER  1
#define OGG_BUFFER_LENGTH_DIVISOR     5

/**
 * The size in bytes of the buffer in which decoded ogg data is stored before
 * copying/conversion
 */
#define OGG_DECODE_BUFFER_SIZE 4096

extern cs_ov_callbacks *GetCallbacks();

SndSysOggSoundStream::SndSysOggSoundStream (csRef<SndSysOggSoundData> pData,
					    OggDataStore *pDataStore, csSndSysSoundFormat *pRenderFormat,
              int Mode3D) :
  SndSysBasicStream(pRenderFormat, Mode3D)
{
  // Initialize the stream data
  m_StreamData.datastore=pDataStore;
  m_StreamData.position=0;

  m_pSoundData=pData;

  // Allocate an advance buffer
  m_pCyclicBuffer = new SoundCyclicBuffer (
    (m_RenderFormat.Bits/8 * m_RenderFormat.Channels) *
      (m_RenderFormat.Freq * OGG_BUFFER_LENGTH_MULTIPLIER /
	OGG_BUFFER_LENGTH_DIVISOR));
  CS_ASSERT(m_pCyclicBuffer!=0);

  // Initialize ogg file
  memset(&m_VorbisFile,0,sizeof(OggVorbis_File));
  ov_open_callbacks (&m_StreamData,&m_VorbisFile,0,0,
    *(ov_callbacks*)GetCallbacks());

  // Set to not a valid stream
  m_CurrentOggStream=-1;
}

SndSysOggSoundStream::~SndSysOggSoundStream ()
{
}

const char *SndSysOggSoundStream::GetDescription()
{
  // Try to retrieve the description from the underlying data component.
  const char *pDesc=m_pSoundData->GetDescription();

  // If the data component has no description, return a default description.
  if (!pDesc)
    return "Ogg Stream";
  return pDesc;
}

size_t SndSysOggSoundStream::GetFrameCount()
{
  const csSndSysSoundFormat *data_format=m_pSoundData->GetFormat();

  uint64 framecount=m_pSoundData->GetFrameCount();
  framecount*=m_RenderFormat.Freq;
  framecount/=data_format->Freq;

  return framecount;
}

void SndSysOggSoundStream::AdvancePosition(size_t frame_delta)
{
  size_t needed_bytes=0;
  //if loop is enabled, end loop frame is different than zero and we are at the loop ending return to the
  //start of the loop
  if(m_bLooping && m_endLoopFrame != 0 && m_MostAdvancedReadPointer+frame_delta >= m_endLoopFrame)
  {
      //first advance the decoding of the exact bound we need to reach the endloopframe
      AdvancePosition(m_endLoopFrame-m_MostAdvancedReadPointer-1);
      //remove from frame_delta what we decoded already
      frame_delta -= m_endLoopFrame-m_MostAdvancedReadPointer-1;
      // Flush the prepared samples
      m_PreparedDataBufferUsage=0;
      m_PreparedDataBufferStart=0;

      // Seek the ogg stream to the start loop position position for the rest of the advancement
      ov_raw_seek(&m_VorbisFile,m_startLoopFrame);
  }

  if (m_NewPosition != InvalidPosition)
  {
    // Signal a full cyclic buffer flush
    needed_bytes=m_pCyclicBuffer->GetLength();

    // Flush the prepared samples too
    m_PreparedDataBufferUsage=0;
    m_PreparedDataBufferStart=0;

    // Seek the ogg stream to the requested position
    ov_raw_seek(&m_VorbisFile,m_NewPosition);

    m_NewPosition = InvalidPosition;
    m_bPlaybackReadComplete=false;
  }
  if (m_bPaused || m_bPlaybackReadComplete || frame_delta==0)
    return;

  long bytes_read=0;

  // Figure out how many bytes we need to fill for this advancement
  if (needed_bytes==0)
    needed_bytes=frame_delta * (m_RenderFormat.Bits/8) * m_RenderFormat.Channels ;

  /* If we need more space than is available in the whole cyclic buffer,
   * then we already underbuffered, reduce to just 1 cycle full
   */
  if ((size_t)needed_bytes > m_pCyclicBuffer->GetLength())
    needed_bytes=(long)(m_pCyclicBuffer->GetLength() & 0x7FFFFFFF);

  // Free space in the cyclic buffer if necessary
  if (needed_bytes > m_pCyclicBuffer->GetFreeBytes())
    m_pCyclicBuffer->AdvanceStartValue (needed_bytes -
      m_pCyclicBuffer->GetFreeBytes());

  // Fill in leftover decoded data if needed
  if (m_PreparedDataBufferUsage > 0)
    needed_bytes -= CopyBufferBytes (needed_bytes);

  while (needed_bytes > 0)
  {
    int last_ogg_stream=m_CurrentOggStream;
    char ogg_decode_buffer[OGG_DECODE_BUFFER_SIZE];

    bytes_read=0;

    while (bytes_read==0)
    {
      bytes_read = ov_read (&m_VorbisFile, ogg_decode_buffer,
        OGG_DECODE_BUFFER_SIZE, OGG_ENDIAN,
        (m_RenderFormat.Bits==8)?1:2, (m_RenderFormat.Bits==8)?0:1,
        &m_CurrentOggStream);

      // Assert on error
      CS_ASSERT(bytes_read >=0);

      if (bytes_read <= 0)
      {
        if (!m_bLooping)
        {
          // Seek back to the beginning for a restart.  Pause on the next call
          m_bPlaybackReadComplete=true;
          ov_raw_seek(&m_VorbisFile,0);
          return;
        }

        // Loop by resetting the position to the start loop position and continuing
        ov_raw_seek(&m_VorbisFile,m_startLoopFrame);
      }
    }

    // If streams changed, the format may have changed as well
    if ((m_NewOutputFrequency != m_OutputFrequency)
      || (last_ogg_stream != m_CurrentOggStream))
    {
      int needed_buffer,source_sample_size;

      m_OutputFrequency=m_NewOutputFrequency;

      m_pCurrentOggFormatInfo=ov_info(&m_VorbisFile,m_CurrentOggStream);

      // Create the pcm sample converter if it's not yet created
      if (m_pPCMConverter == 0)
        m_pPCMConverter = new PCMSampleConverter (
          m_pCurrentOggFormatInfo->channels, m_RenderFormat.Bits,
          m_pCurrentOggFormatInfo->rate);

      // Calculate the size of one source sample
      source_sample_size=m_pCurrentOggFormatInfo->channels * m_RenderFormat.Bits;

      // Calculate the needed buffer size for this conversion
      needed_buffer = (m_pPCMConverter->GetRequiredOutputBufferMultiple (
        m_RenderFormat.Channels,m_RenderFormat.Bits,m_OutputFrequency) *
        (OGG_DECODE_BUFFER_SIZE + source_sample_size))/1024;

      // Allocate a new buffer if needed - this will only happen if the source rate changes
      if (m_PreparedDataBufferSize < needed_buffer)
      {
        delete[] m_pPreparedDataBuffer;
        m_pPreparedDataBuffer = new char[needed_buffer];
        m_PreparedDataBufferSize=needed_buffer;
      }
    }

    // If no conversion is necessary
    if ((m_pCurrentOggFormatInfo->rate == m_OutputFrequency) &&
        (m_pCurrentOggFormatInfo->channels == m_RenderFormat.Channels))
    {
      CS_ASSERT(bytes_read <= m_PreparedDataBufferSize);
      memcpy(m_pPreparedDataBuffer,ogg_decode_buffer,bytes_read);
      m_PreparedDataBufferUsage=bytes_read;
    }
    else
    {
      m_PreparedDataBufferUsage = m_pPCMConverter->ConvertBuffer (ogg_decode_buffer,
        bytes_read, m_pPreparedDataBuffer, m_RenderFormat.Channels,
        m_RenderFormat.Bits,m_OutputFrequency);
    }

    if (m_PreparedDataBufferUsage > 0)
      needed_bytes -= CopyBufferBytes (needed_bytes);

  }

}

<commit_msg>when setting a position with setpos the cs api states that frames are used, same goes for the loop positions, but ov_raw_seek doesn't respect this: "Seeks to the offset specified (in compressed raw bytes) within the physical bitstream." while we want to seek to a frame so we need ov_pcm_seek which has predictable positions: "Seeks to the offset specified (in pcm samples) within the physical bitstream."<commit_after>/*
    Copyright (C) 2005 by Andrew Mann
    Based in part on work by Norman Kraemer

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "iutil/comp.h"
#include "isndsys/ss_stream.h"
#include "oggdata2.h"
#include "oggstream2.h"

#include "ivaria/reporter.h"

/* Keep these as integer values or the stream may feed portions of a sample to
 * the higher layer which may cause problems
 * 1 , 1 will decode 1/1 or 1 second of audio in advance */
#define OGG_BUFFER_LENGTH_MULTIPLIER  1
#define OGG_BUFFER_LENGTH_DIVISOR     5

/**
 * The size in bytes of the buffer in which decoded ogg data is stored before
 * copying/conversion
 */
#define OGG_DECODE_BUFFER_SIZE 4096

extern cs_ov_callbacks *GetCallbacks();

SndSysOggSoundStream::SndSysOggSoundStream (csRef<SndSysOggSoundData> pData,
					    OggDataStore *pDataStore, csSndSysSoundFormat *pRenderFormat,
              int Mode3D) :
  SndSysBasicStream(pRenderFormat, Mode3D)
{
  // Initialize the stream data
  m_StreamData.datastore=pDataStore;
  m_StreamData.position=0;

  m_pSoundData=pData;

  // Allocate an advance buffer
  m_pCyclicBuffer = new SoundCyclicBuffer (
    (m_RenderFormat.Bits/8 * m_RenderFormat.Channels) *
      (m_RenderFormat.Freq * OGG_BUFFER_LENGTH_MULTIPLIER /
	OGG_BUFFER_LENGTH_DIVISOR));
  CS_ASSERT(m_pCyclicBuffer!=0);

  // Initialize ogg file
  memset(&m_VorbisFile,0,sizeof(OggVorbis_File));
  ov_open_callbacks (&m_StreamData,&m_VorbisFile,0,0,
    *(ov_callbacks*)GetCallbacks());

  // Set to not a valid stream
  m_CurrentOggStream=-1;
}

SndSysOggSoundStream::~SndSysOggSoundStream ()
{
}

const char *SndSysOggSoundStream::GetDescription()
{
  // Try to retrieve the description from the underlying data component.
  const char *pDesc=m_pSoundData->GetDescription();

  // If the data component has no description, return a default description.
  if (!pDesc)
    return "Ogg Stream";
  return pDesc;
}

size_t SndSysOggSoundStream::GetFrameCount()
{
  const csSndSysSoundFormat *data_format=m_pSoundData->GetFormat();

  uint64 framecount=m_pSoundData->GetFrameCount();
  framecount*=m_RenderFormat.Freq;
  framecount/=data_format->Freq;

  return framecount;
}

void SndSysOggSoundStream::AdvancePosition(size_t frame_delta)
{
  size_t needed_bytes=0;
  //if loop is enabled, end loop frame is different than zero and we are at the loop ending return to the
  //start of the loop
  if(m_bLooping && m_endLoopFrame != 0 && m_MostAdvancedReadPointer+frame_delta >= m_endLoopFrame)
  {
      //first advance the decoding of the exact bound we need to reach the endloopframe
      AdvancePosition(m_endLoopFrame-m_MostAdvancedReadPointer-1);
      //remove from frame_delta what we decoded already
      frame_delta -= m_endLoopFrame-m_MostAdvancedReadPointer-1;
      // Flush the prepared samples
      m_PreparedDataBufferUsage=0;
      m_PreparedDataBufferStart=0;

      // Seek the ogg stream to the start loop position position for the rest of the advancement
      ov_pcm_seek(&m_VorbisFile,m_startLoopFrame);
  }

  if (m_NewPosition != InvalidPosition)
  {
    // Signal a full cyclic buffer flush
    needed_bytes=m_pCyclicBuffer->GetLength();

    // Flush the prepared samples too
    m_PreparedDataBufferUsage=0;
    m_PreparedDataBufferStart=0;

    // Seek the ogg stream to the requested position
    ov_pcm_seek(&m_VorbisFile,m_NewPosition);

    m_NewPosition = InvalidPosition;
    m_bPlaybackReadComplete=false;
  }
  if (m_bPaused || m_bPlaybackReadComplete || frame_delta==0)
    return;

  long bytes_read=0;

  // Figure out how many bytes we need to fill for this advancement
  if (needed_bytes==0)
    needed_bytes=frame_delta * (m_RenderFormat.Bits/8) * m_RenderFormat.Channels ;

  /* If we need more space than is available in the whole cyclic buffer,
   * then we already underbuffered, reduce to just 1 cycle full
   */
  if ((size_t)needed_bytes > m_pCyclicBuffer->GetLength())
    needed_bytes=(long)(m_pCyclicBuffer->GetLength() & 0x7FFFFFFF);

  // Free space in the cyclic buffer if necessary
  if (needed_bytes > m_pCyclicBuffer->GetFreeBytes())
    m_pCyclicBuffer->AdvanceStartValue (needed_bytes -
      m_pCyclicBuffer->GetFreeBytes());

  // Fill in leftover decoded data if needed
  if (m_PreparedDataBufferUsage > 0)
    needed_bytes -= CopyBufferBytes (needed_bytes);

  while (needed_bytes > 0)
  {
    int last_ogg_stream=m_CurrentOggStream;
    char ogg_decode_buffer[OGG_DECODE_BUFFER_SIZE];

    bytes_read=0;

    while (bytes_read==0)
    {
      bytes_read = ov_read (&m_VorbisFile, ogg_decode_buffer,
        OGG_DECODE_BUFFER_SIZE, OGG_ENDIAN,
        (m_RenderFormat.Bits==8)?1:2, (m_RenderFormat.Bits==8)?0:1,
        &m_CurrentOggStream);

      // Assert on error
      CS_ASSERT(bytes_read >=0);

      if (bytes_read <= 0)
      {
        if (!m_bLooping)
        {
          // Seek back to the beginning for a restart.  Pause on the next call
          m_bPlaybackReadComplete=true;
          ov_raw_seek(&m_VorbisFile,0);
          return;
        }

        // Loop by resetting the position to the start loop position and continuing
        ov_pcm_seek(&m_VorbisFile,m_startLoopFrame);
      }
    }

    // If streams changed, the format may have changed as well
    if ((m_NewOutputFrequency != m_OutputFrequency)
      || (last_ogg_stream != m_CurrentOggStream))
    {
      int needed_buffer,source_sample_size;

      m_OutputFrequency=m_NewOutputFrequency;

      m_pCurrentOggFormatInfo=ov_info(&m_VorbisFile,m_CurrentOggStream);

      // Create the pcm sample converter if it's not yet created
      if (m_pPCMConverter == 0)
        m_pPCMConverter = new PCMSampleConverter (
          m_pCurrentOggFormatInfo->channels, m_RenderFormat.Bits,
          m_pCurrentOggFormatInfo->rate);

      // Calculate the size of one source sample
      source_sample_size=m_pCurrentOggFormatInfo->channels * m_RenderFormat.Bits;

      // Calculate the needed buffer size for this conversion
      needed_buffer = (m_pPCMConverter->GetRequiredOutputBufferMultiple (
        m_RenderFormat.Channels,m_RenderFormat.Bits,m_OutputFrequency) *
        (OGG_DECODE_BUFFER_SIZE + source_sample_size))/1024;

      // Allocate a new buffer if needed - this will only happen if the source rate changes
      if (m_PreparedDataBufferSize < needed_buffer)
      {
        delete[] m_pPreparedDataBuffer;
        m_pPreparedDataBuffer = new char[needed_buffer];
        m_PreparedDataBufferSize=needed_buffer;
      }
    }

    // If no conversion is necessary
    if ((m_pCurrentOggFormatInfo->rate == m_OutputFrequency) &&
        (m_pCurrentOggFormatInfo->channels == m_RenderFormat.Channels))
    {
      CS_ASSERT(bytes_read <= m_PreparedDataBufferSize);
      memcpy(m_pPreparedDataBuffer,ogg_decode_buffer,bytes_read);
      m_PreparedDataBufferUsage=bytes_read;
    }
    else
    {
      m_PreparedDataBufferUsage = m_pPCMConverter->ConvertBuffer (ogg_decode_buffer,
        bytes_read, m_pPreparedDataBuffer, m_RenderFormat.Channels,
        m_RenderFormat.Bits,m_OutputFrequency);
    }

    if (m_PreparedDataBufferUsage > 0)
      needed_bytes -= CopyBufferBytes (needed_bytes);

  }

}

<|endoftext|>