<commit_before>#include "formulation/cfem_diffusion_stamper.h"

#include <memory>

#include <deal.II/base/mpi.h>
#include <deal.II/dofs/dof_tools.h>
#include <deal.II/dofs/dof_handler.h>
#include <deal.II/lac/full_matrix.h>
#include <deal.II/distributed/tria.h>
#include <deal.II/fe/fe_q.h>
#include <deal.II/grid/grid_generator.h>
#include <deal.II/grid/grid_tools.h>
#include <deal.II/lac/dynamic_sparsity_pattern.h>
#include <deal.II/lac/petsc_parallel_sparse_matrix.h>

#include "domain/tests/definition_mock.h"
#include "formulation/scalar/tests/cfem_diffusion_mock.h"
#include "test_helpers/gmock_wrapper.h"
#include "test_helpers/test_helper_functions.h"

namespace {

using ::testing::AssertionResult;
using ::testing::AssertionFailure, ::testing::AssertionSuccess;
using ::testing::DoDefault;
using ::testing::Invoke;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::Unused;
using ::testing::_;

using namespace bart;
using Cell = domain::DefinitionI<2>::Cell;
using InitToken = formulation::scalar::CFEM_DiffusionI<2>::InitializationToken;
using Matrix = dealii::FullMatrix<double>;

class CFEMDiffusionStamperTest : public ::testing::Test {
 protected:
  std::unique_ptr<NiceMock<domain::DefinitionMock<2>>> mock_definition_ptr;
  std::unique_ptr<NiceMock<formulation::scalar::CFEM_DiffusionMock<2>>> mock_diffusion_ptr;
  void SetUp() override;
  InitToken init_token_;
};

// TODO(Josh) Move this to a header where other stamper tests can use it
void FillMatrixWithOnes(Matrix& to_fill, Unused, Unused, Unused, Unused) {
  for (unsigned int i = 0; i < to_fill.n_rows(); ++i) {
    for (unsigned int j = 0; j < to_fill.n_cols(); ++j) {
      to_fill(i,j) = 1;
    }
  }
}

void CFEMDiffusionStamperTest::SetUp() {
  mock_definition_ptr = std::make_unique<NiceMock<domain::DefinitionMock<2>>>();
  mock_diffusion_ptr =
      std::make_unique<NiceMock<formulation::scalar::CFEM_DiffusionMock<2>>>();

  ON_CALL(*mock_diffusion_ptr, Precalculate(_))
      .WillByDefault(Return(init_token_));
}

TEST_F(CFEMDiffusionStamperTest, Constructor) {
  Cell test_cell;
  std::vector<Cell> cells{test_cell};

  EXPECT_CALL(*mock_definition_ptr, Cells())
      .WillOnce(Return(cells));
  EXPECT_CALL(*mock_diffusion_ptr, Precalculate(_))
      .WillOnce(DoDefault());

  formulation::CFEM_DiffusionStamper<2> test_stamper(
      std::move(mock_diffusion_ptr),
      std::move(mock_definition_ptr));

  EXPECT_EQ(mock_diffusion_ptr, nullptr);
  EXPECT_EQ(mock_definition_ptr, nullptr);
}

// TODO(Josh) Put this in it's own header file?
class CFEMDiffusionStamperMPITests : public CFEMDiffusionStamperTest {
 protected:
  using Cell = typename dealii::DoFHandler<2>::active_cell_iterator;

  CFEMDiffusionStamperMPITests();

  void SetUp() override;
  void SetUpDealii();
  AssertionResult CompareMPIMatrices(
      const dealii::PETScWrappers::MPI::SparseMatrix& expected,
      const dealii::PETScWrappers::MPI::SparseMatrix& result);

  dealii::ConstraintMatrix constraint_matrix_;
  dealii::parallel::distributed::Triangulation<2> triangulation_;
  dealii::DoFHandler<2> dof_handler_;
  dealii::FE_Q<2> fe_;
  dealii::IndexSet locally_relevant_dofs;
  dealii::IndexSet locally_owned_dofs_;
  dealii::PETScWrappers::MPI::SparseMatrix system_matrix_, index_hits_;
  std::vector<Cell> cells_;
  std::vector<int> material_ids_;
};

AssertionResult CFEMDiffusionStamperMPITests::CompareMPIMatrices(
    const dealii::PETScWrappers::MPI::SparseMatrix& expected,
    const dealii::PETScWrappers::MPI::SparseMatrix& result) {

  for (const auto& cell : cells_) {
    std::vector<dealii::types::global_dof_index> local_dof_indices(fe_.dofs_per_cell);
    cell->get_dof_indices(local_dof_indices);
    for (const auto &index_i : local_dof_indices) {
      for (const auto &index_j : local_dof_indices) {
        if (result(index_i, index_j) != expected(index_i, index_j)) {
          return AssertionFailure() << "Entry (" << index_i << ", " << index_j <<
                                    ") has value: " << result(index_i, index_j) <<
                                    ", expected: " << expected(index_i, index_j);
        }
      }
    }
  }
  return AssertionSuccess();
}

CFEMDiffusionStamperMPITests::CFEMDiffusionStamperMPITests()
    : triangulation_(MPI_COMM_WORLD,
                     typename dealii::Triangulation<2>::MeshSmoothing(
                         dealii::Triangulation<2>::smoothing_on_refinement |
                             dealii::Triangulation<2>::smoothing_on_coarsening)),
      dof_handler_(triangulation_),
      fe_(1) {}

void CFEMDiffusionStamperMPITests::SetUp() {
  CFEMDiffusionStamperTest::SetUp();
  SetUpDealii();

  for (const auto& cell : cells_) {
    int mat_id = btest::RandomDouble(0, 10);
    material_ids_.push_back(mat_id);
    cell->set_material_id(mat_id);
  }

  ON_CALL(*mock_diffusion_ptr, FillCellStreamingTerm(_, _, _, _, _))
      .WillByDefault(Invoke(FillMatrixWithOnes));
  ON_CALL(*mock_definition_ptr, Cells())
      .WillByDefault(Return(cells_));
  dealii::FullMatrix<double> cell_matrix(fe_.dofs_per_cell,
                                         fe_.dofs_per_cell);
  ON_CALL(*mock_definition_ptr, GetCellMatrix())
      .WillByDefault(Return(cell_matrix));
}

void CFEMDiffusionStamperMPITests::SetUpDealii() {
  // Create triangulation
  dealii::GridGenerator::hyper_cube(triangulation_, 0, 1);
  triangulation_.refine_global(2);
  // Distribute DOFS, get local index sets and cells
  dof_handler_.distribute_dofs(fe_);
  dealii::DoFTools::extract_locally_relevant_dofs(dof_handler_,
                                                  locally_relevant_dofs);
  locally_owned_dofs_ = dof_handler_.locally_owned_dofs();
  for (auto cell = dof_handler_.begin_active(); cell != dof_handler_.end(); ++ cell) {
    if (cell->is_locally_owned())
      cells_.push_back(cell);
  }

  // Make constraint matrix and DSP for matrices
  constraint_matrix_.clear();
  constraint_matrix_.reinit(locally_relevant_dofs);
  dealii::DoFTools::make_hanging_node_constraints(dof_handler_,
                                                  constraint_matrix_);
  constraint_matrix_.close();

  dealii::DynamicSparsityPattern dsp(locally_relevant_dofs);
  dealii::DoFTools::make_sparsity_pattern(dof_handler_, dsp,
                                          constraint_matrix_, false);
  dealii::SparsityTools::distribute_sparsity_pattern(
      dsp,
      dof_handler_.n_locally_owned_dofs_per_processor(),
      MPI_COMM_WORLD, locally_relevant_dofs);
  constraint_matrix_.condense(dsp);

  // Set up MPI matrices
  system_matrix_.reinit(locally_owned_dofs_, locally_owned_dofs_, dsp, MPI_COMM_WORLD);
  index_hits_.reinit(locally_owned_dofs_, locally_owned_dofs_, dsp, MPI_COMM_WORLD);

  std::vector<dealii::types::global_dof_index> local_dof_indices(fe_.dofs_per_cell);

  for (auto cell : cells_) {
    cell->get_dof_indices(local_dof_indices);
    for (auto index_i : local_dof_indices) {
      for (auto index_j : local_dof_indices) {
        index_hits_.add(index_i, index_j, 1);
      }
    }
    index_hits_.compress(dealii::VectorOperation::add);
  }
}

TEST_F(CFEMDiffusionStamperMPITests, StampStreaming) {

  int group_number = 1;

  for (auto const& cell : cells_) {
    EXPECT_CALL(*mock_diffusion_ptr,
        FillCellStreamingTerm(_, _, cell, cell->material_id(), group_number))
        .WillOnce(DoDefault());
  }
  EXPECT_CALL(*mock_definition_ptr, GetCellMatrix())
      .WillOnce(DoDefault());

  formulation::CFEM_DiffusionStamper<2> test_stamper(
      std::move(mock_diffusion_ptr),
      std::move(mock_definition_ptr));

  test_stamper.StampStreamingTerm(system_matrix_, group_number);

  EXPECT_TRUE(CompareMPIMatrices(system_matrix_, index_hits_));
}

} // namespace<commit_msg>removed ON_CALL event for FillCellStreamingTerm<commit_after>#include "formulation/cfem_diffusion_stamper.h"

#include <memory>

#include <deal.II/base/mpi.h>
#include <deal.II/dofs/dof_tools.h>
#include <deal.II/dofs/dof_handler.h>
#include <deal.II/lac/full_matrix.h>
#include <deal.II/distributed/tria.h>
#include <deal.II/fe/fe_q.h>
#include <deal.II/grid/grid_generator.h>
#include <deal.II/grid/grid_tools.h>
#include <deal.II/lac/dynamic_sparsity_pattern.h>
#include <deal.II/lac/petsc_parallel_sparse_matrix.h>

#include "domain/tests/definition_mock.h"
#include "formulation/scalar/tests/cfem_diffusion_mock.h"
#include "test_helpers/gmock_wrapper.h"
#include "test_helpers/test_helper_functions.h"

namespace {

using ::testing::AssertionResult;
using ::testing::AssertionFailure, ::testing::AssertionSuccess;
using ::testing::DoDefault;
using ::testing::Invoke;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::Unused;
using ::testing::_;

using namespace bart;
using Cell = domain::DefinitionI<2>::Cell;
using InitToken = formulation::scalar::CFEM_DiffusionI<2>::InitializationToken;
using Matrix = dealii::FullMatrix<double>;

class CFEMDiffusionStamperTest : public ::testing::Test {
 protected:
  std::unique_ptr<NiceMock<domain::DefinitionMock<2>>> mock_definition_ptr;
  std::unique_ptr<NiceMock<formulation::scalar::CFEM_DiffusionMock<2>>> mock_diffusion_ptr;
  void SetUp() override;
  InitToken init_token_;
};

// TODO(Josh) Move this to a header where other stamper tests can use it
void FillMatrixWithOnes(Matrix& to_fill, Unused, Unused, Unused, Unused) {
  for (unsigned int i = 0; i < to_fill.n_rows(); ++i) {
    for (unsigned int j = 0; j < to_fill.n_cols(); ++j) {
      to_fill(i,j) = 1;
    }
  }
}

void CFEMDiffusionStamperTest::SetUp() {
  mock_definition_ptr = std::make_unique<NiceMock<domain::DefinitionMock<2>>>();
  mock_diffusion_ptr =
      std::make_unique<NiceMock<formulation::scalar::CFEM_DiffusionMock<2>>>();

  ON_CALL(*mock_diffusion_ptr, Precalculate(_))
      .WillByDefault(Return(init_token_));
}

TEST_F(CFEMDiffusionStamperTest, Constructor) {
  Cell test_cell;
  std::vector<Cell> cells{test_cell};

  EXPECT_CALL(*mock_definition_ptr, Cells())
      .WillOnce(Return(cells));
  EXPECT_CALL(*mock_diffusion_ptr, Precalculate(_))
      .WillOnce(DoDefault());

  formulation::CFEM_DiffusionStamper<2> test_stamper(
      std::move(mock_diffusion_ptr),
      std::move(mock_definition_ptr));

  EXPECT_EQ(mock_diffusion_ptr, nullptr);
  EXPECT_EQ(mock_definition_ptr, nullptr);
}

// TODO(Josh) Put this in it's own header file?
class CFEMDiffusionStamperMPITests : public CFEMDiffusionStamperTest {
 protected:
  using Cell = typename dealii::DoFHandler<2>::active_cell_iterator;

  CFEMDiffusionStamperMPITests();

  void SetUp() override;
  void SetUpDealii();
  AssertionResult CompareMPIMatrices(
      const dealii::PETScWrappers::MPI::SparseMatrix& expected,
      const dealii::PETScWrappers::MPI::SparseMatrix& result);

  dealii::ConstraintMatrix constraint_matrix_;
  dealii::parallel::distributed::Triangulation<2> triangulation_;
  dealii::DoFHandler<2> dof_handler_;
  dealii::FE_Q<2> fe_;
  dealii::IndexSet locally_relevant_dofs;
  dealii::IndexSet locally_owned_dofs_;
  dealii::PETScWrappers::MPI::SparseMatrix system_matrix_, index_hits_;
  std::vector<Cell> cells_;
  std::vector<int> material_ids_;
};

AssertionResult CFEMDiffusionStamperMPITests::CompareMPIMatrices(
    const dealii::PETScWrappers::MPI::SparseMatrix& expected,
    const dealii::PETScWrappers::MPI::SparseMatrix& result) {

  for (const auto& cell : cells_) {
    std::vector<dealii::types::global_dof_index> local_dof_indices(fe_.dofs_per_cell);
    cell->get_dof_indices(local_dof_indices);
    for (const auto &index_i : local_dof_indices) {
      for (const auto &index_j : local_dof_indices) {
        if (result(index_i, index_j) != expected(index_i, index_j)) {
          return AssertionFailure() << "Entry (" << index_i << ", " << index_j <<
                                    ") has value: " << result(index_i, index_j) <<
                                    ", expected: " << expected(index_i, index_j);
        }
      }
    }
  }
  return AssertionSuccess();
}

CFEMDiffusionStamperMPITests::CFEMDiffusionStamperMPITests()
    : triangulation_(MPI_COMM_WORLD,
                     typename dealii::Triangulation<2>::MeshSmoothing(
                         dealii::Triangulation<2>::smoothing_on_refinement |
                             dealii::Triangulation<2>::smoothing_on_coarsening)),
      dof_handler_(triangulation_),
      fe_(1) {}

void CFEMDiffusionStamperMPITests::SetUp() {
  CFEMDiffusionStamperTest::SetUp();
  SetUpDealii();

  for (const auto& cell : cells_) {
    int mat_id = btest::RandomDouble(0, 10);
    material_ids_.push_back(mat_id);
    cell->set_material_id(mat_id);
  }

  ON_CALL(*mock_definition_ptr, Cells())
      .WillByDefault(Return(cells_));
  dealii::FullMatrix<double> cell_matrix(fe_.dofs_per_cell,
                                         fe_.dofs_per_cell);
  ON_CALL(*mock_definition_ptr, GetCellMatrix())
      .WillByDefault(Return(cell_matrix));
}

void CFEMDiffusionStamperMPITests::SetUpDealii() {
  // Create triangulation
  dealii::GridGenerator::hyper_cube(triangulation_, 0, 1);
  triangulation_.refine_global(2);
  // Distribute DOFS, get local index sets and cells
  dof_handler_.distribute_dofs(fe_);
  dealii::DoFTools::extract_locally_relevant_dofs(dof_handler_,
                                                  locally_relevant_dofs);
  locally_owned_dofs_ = dof_handler_.locally_owned_dofs();
  for (auto cell = dof_handler_.begin_active(); cell != dof_handler_.end(); ++ cell) {
    if (cell->is_locally_owned())
      cells_.push_back(cell);
  }

  // Make constraint matrix and DSP for matrices
  constraint_matrix_.clear();
  constraint_matrix_.reinit(locally_relevant_dofs);
  dealii::DoFTools::make_hanging_node_constraints(dof_handler_,
                                                  constraint_matrix_);
  constraint_matrix_.close();

  dealii::DynamicSparsityPattern dsp(locally_relevant_dofs);
  dealii::DoFTools::make_sparsity_pattern(dof_handler_, dsp,
                                          constraint_matrix_, false);
  dealii::SparsityTools::distribute_sparsity_pattern(
      dsp,
      dof_handler_.n_locally_owned_dofs_per_processor(),
      MPI_COMM_WORLD, locally_relevant_dofs);
  constraint_matrix_.condense(dsp);

  // Set up MPI matrices
  system_matrix_.reinit(locally_owned_dofs_, locally_owned_dofs_, dsp, MPI_COMM_WORLD);
  index_hits_.reinit(locally_owned_dofs_, locally_owned_dofs_, dsp, MPI_COMM_WORLD);

  std::vector<dealii::types::global_dof_index> local_dof_indices(fe_.dofs_per_cell);

  for (auto cell : cells_) {
    cell->get_dof_indices(local_dof_indices);
    for (auto index_i : local_dof_indices) {
      for (auto index_j : local_dof_indices) {
        index_hits_.add(index_i, index_j, 1);
      }
    }
    index_hits_.compress(dealii::VectorOperation::add);
  }
}

TEST_F(CFEMDiffusionStamperMPITests, StampStreaming) {

  int group_number = 1;

  for (auto const& cell : cells_) {
    EXPECT_CALL(*mock_diffusion_ptr,
        FillCellStreamingTerm(_, _, cell, cell->material_id(), group_number))
        .WillOnce(Invoke(FillMatrixWithOnes));
  }
  EXPECT_CALL(*mock_definition_ptr, GetCellMatrix())
      .WillOnce(DoDefault());

  formulation::CFEM_DiffusionStamper<2> test_stamper(
      std::move(mock_diffusion_ptr),
      std::move(mock_definition_ptr));

  test_stamper.StampStreamingTerm(system_matrix_, group_number);

  EXPECT_TRUE(CompareMPIMatrices(system_matrix_, index_hits_));
}

} // namespace<|endoftext|>


<commit_before>#include "visgraph.hpp"
#include "../utils/utils.hpp"

enum {
	Npolys = 500,
	Maxverts = 8,
};

static const double Minrad = 0.05;
static const double Maxrad = 0.075;

void randpolys(std::vector<Polygon>&);

int main(int argc, char *argv[]) {
	std::vector<Polygon> polys;
	randpolys(polys);
	VisGraph graph(polys);
	graph.output(stdout);
	return 0;
}

void randpolys(std::vector<Polygon> &polys) {
	for (unsigned int i = 0; i < Npolys; i++) {
redo:
		double x = randgen.real(), y = randgen.real();
		double r = randgen.real() * (Maxrad - Minrad) + Minrad;

		assert (x >= 0.0);
		assert (y >= 0.0);
		assert (r >= 0.0);

		Polygon p = Polygon::random(randgen.integer(3, Maxverts), x, y, r);

		for (unsigned int i = 0; i < polys.size(); i++) {
			if (polys[i].bbox.isect(p.bbox))
				goto redo;
		}

		polys.push_back(p);
	}
}<commit_msg>visnav: don't generate vertices outside of the unit square.<commit_after>#include "visgraph.hpp"
#include "../utils/utils.hpp"

enum {
	Npolys = 500,
	Maxverts = 8,
};

static const double Minrad = 0.05;
static const double Maxrad = 0.075;

void randpolys(std::vector<Polygon>&);
static double rnddbl(double, double);

int main(int argc, char *argv[]) {
	std::vector<Polygon> polys;
	randpolys(polys);
	VisGraph graph(polys);
	graph.output(stdout);
	return 0;
}

void randpolys(std::vector<Polygon> &polys) {
	for (unsigned int i = 0; i < Npolys; i++) {
redo:
		double r = rnddbl(Minrad, Maxrad);
		double x = rnddbl(r, 1 - r);
		double y = rnddbl(r, 1 - r);

		assert (x >= 0.0);
		assert (y >= 0.0);
		assert (r >= 0.0);

		Polygon p = Polygon::random(randgen.integer(3, Maxverts), x, y, r);

		for (unsigned int i = 0; i < polys.size(); i++) {
			if (polys[i].bbox.isect(p.bbox))
				goto redo;
		}

		polys.push_back(p);
	}
}

static double rnddbl(double min, double max) {
	assert (max > min);
	return randgen.real() * (max - min) + min;
}<|endoftext|>


<commit_before>#include "../../include/GameManager.h"

#include <iostream>
#include <fstream>

using namespace std;

GameManager::GameManager()
{
    //ctor
}

GameManager::~GameManager()
{
    //dtor
}

/**
 * Adds player to the game
 *
 * @param name Player's name
 */
bool GameManager::addPlayer(string name)
{
    if (this->_players.size() < 4) {
        this->_players.push_back(Player(name));
        return true;
    } else {
        return false;
    }
}

/**
 * Removes player from the game
 *
 * @param name Player's name
 */
bool GameManager::remPlayer(string name)
{
    return false;
}

/**
 * Returns size of the board
 * default value is 7
 */
int GameManager::getSize()
{
    return this->_size;
}

/**
 * Sets size of board
 *
 * @param n Size of board, value should be between 5 and 11
 */
bool GameManager::setSize(int n)
{
    if (n >= 5 && n <= 11 && n % 2 == 1) {
        this->_size = n;
        return true;
    } else {
        return false;
    }
}

/**
 * Starts the game
 */
bool GameManager::startGame()
{
    if (this->_players.size() >= 2) {
        this->_board = MazeBoard(this->_size);
        this->generateTreasures();
        this->_board.placeTreasures(this->_treasureIds);
        this->playerAutoPlacement();
        this->_started = true;
    }
    return this->_started;
}

/**
 * Restarts the game
 */
void GameManager::restartGame()
{
    this->_board.newGame();
    this->generateTreasures();
    this->_board.placeTreasures(this->_treasureIds);
    this->playerAutoPlacement();
}

/**
 * Returns vector with all possible moves
 */
vector<MazeField> GameManager::getMoves()
{
    Player active = this->getActive();
    MazeField mf = this->_board.get(active.row(), active.col());
    return PathFinder::possibleMoves(mf, this->_board);
}

/**
 * Moves card
 *
 * @param r Row index
 * @param c Column index
 */
bool GameManager::moveCard(int r, int c)
{
    MazeField field = this->_board.get(r, c);
    if (field.row() > -1) {
        this->_board.shift(field);
        this->fixPlayerPositions(r, c);
        this->_actions.push_back(Action(Action::TYPE::MOVE_CARD, r, c));
        return true;
    } else {
        return false;
    }
}

/**
 * Moves player to different field
 *
 * @param r Row index
 * @param c Column index
 */
bool GameManager::movePlayer(int r, int c)
{
    MazeField mf = this->_board.get(r, c);
    if (mf.row() > -1) {
        //auto moves = this->getMoves();
        int p_row = this->_players[this->getActiveIndex()].row();
        int p_col = this->_players[this->getActiveIndex()].col();
        MazeField curr = this->_board.get(p_row, p_col);
        if (PathFinder::findPath(curr, mf, this->_board)) {
            this->_actions.push_back(Action(Action::TYPE::MOVE_PLAYER, p_row, p_col));
            this->_players[this->getActiveIndex()].setLocation(mf.row(), mf.col());
            if(mf.getCard().getTreasure() == this->getActive().getTreasure()) {
                int oldId = mf.getCard().getTreasure();
                int newId = this->takeTreasure();
                this->_players[this->getActiveIndex()].setNewTreasure(newId);
                if (this->getActive().getScore() >= (this->_treasureCount / this->_players.size())) {
                    this->_won = true;
                }
                this->_actions.push_back(Action(Action::TYPE::TAKE_TREASURE, newId, oldId));
            }
            if (!this->isWon())
                this->nextPlayer();
            return true;
        }
    }
    return false;
}

/**
 * Reverts last move
 */
bool GameManager::undo()
{
    if (this->_actions.size() > 0) {
        Action toRevert = this->_actions.back();
        if (toRevert.type() == Action::TYPE::MOVE_PLAYER) {
            this->revertPlayer(toRevert);
        } else {
            this->revertCard(toRevert);
        }
        return true;
    } else {
        return false;
    }
}

/**
 * Sets next player as active
 */
void GameManager::nextPlayer()
{
    this->_activePlayer = (this->_activePlayer + 1) % this->_players.size();
}

/**
 * Sets previous player as activeě
 */
void GameManager::previousPlayer()
{
    this->_activePlayer = (this->_activePlayer + this->_players.size() - 1) % this->_players.size();
}

/**
 * Returns index of the active player
 */
int GameManager::getActiveIndex()
{
    return this->_activePlayer;
}

/**
 * Returns active player
 */
Player GameManager::getActive()
{
    return this->_players[this->getActiveIndex()];
}

/**
 * Sets treasure count
 *
 * @param n New treasure count
 */
bool GameManager::setTreasureCount(int n)
{
    if (n == 24 || n == 12) {
        this->_treasureCount = n;
        return true;
    } else {
        return false;
    }
}

/**
 * Saves current game to file
 *
 * @param fname File name
 */
bool GameManager::save(string fname)
{
    ofstream myfile;
    myfile.open (fname, ios::out);
    //Save players
    myfile << this->_players.size() << ";";
    for (unsigned int i = 0; i < this->_players.size(); i++)
        myfile << this->_players[i].toString();
    myfile << this->getActiveIndex() << ";";
    //Save treasures
    myfile << this->_treasureIds.size() << ";";
    for (unsigned int i = 0; i < this->_treasureIds.size(); i++)
        myfile << this->_treasureIds[i] << ";";

    //Save board
    myfile << this->_board.toString();

    myfile.close();
    return true;
}

/**
 * Loads game from file
 *
 * @param fname File name
 */
bool GameManager::load(string fname)
{
    ifstream myfile;
    string content = "";
    int index = 0;
    this->_players = vector<Player>();
    myfile.open(fname);
    myfile >> content;
    auto props = split(content, ';');
    /* read players */
    int playerCount = atoi(props[index].c_str());
    for (index = 1; index <= playerCount; index++) {
        this->_players.push_back(Player::fromString(props[index]));
    }
    this->_activePlayer = atoi(props[index].c_str());
    index++;
    /* read treasures */
    int treasureCount = atoi(props[index].c_str()) + index;
    this->_treasureIds = vector<int>();
    for (++index; index <= treasureCount; index++) {
        this->_treasureIds.push_back(atoi(props[index].c_str()));
    }
    /* read board */
    int boardSize = atoi(props[index].c_str());
    this->_size = boardSize;
    this->_board = MazeBoard(boardSize);
    vector<MazeCard> cards;
    int boardLimit = boardSize * boardSize + (++index);
    for (; index <= boardLimit; index++) {
        cards.push_back(MazeCard::fromString(props[index]));
    }
    /* store cards */
    for (int r = 0; r < boardSize; r++) {
        for (int c = 0; c < boardSize; c++) {
            this->_board.putCard(r, c, cards[c + r * boardSize]);
        }
    }
    this->_board.setFreeCard(cards.back());
    this->_started = true;
    myfile.close();
    return true;
}

/**
 * Returns vector of Player
 */
vector<Player> GameManager::getAllPlayers()
{
    return this->_players;
}

/**
 * Checks whether the game was won.
 */
bool GameManager::isWon()
{
    return this->_won;
}

/**
 * Returns vector of player names
 */
vector<string> GameManager::getNames()
{
    vector<string> names;
    for(unsigned int i = 0; i < this->_players.size(); i++)
        names.push_back(this->_players[i].getName());
    return names;
}

/**
 * Returns string representing card's path
 *
 * @param r Row index
 * @param c Column index
 */
string GameManager::getCardPath(int r, int c)
{
    return this->_board.get(r, c).getCard().getStringPath();
}

/**
 * Returns free card
 */
string GameManager::getFreeCard()
{
    return this->_board.getFreeCard().getStringPath();
}

/**
 * Turns free card to the right
 */
void GameManager::turnFreeCard()
{
    this->_board.turnFreeCard();
}

/**
 * Checks whether specified card contains treasure
 */
bool GameManager::isTreasure(int r, int c)
{
    return this->_board.get(r, c).getCard().isTreasure();
}

/**
 * Returns treasure from specified card
 *
 * @param r Row index
 * @param c Column index
 */
int GameManager::getTreasure(int r, int c)
{
    return this->_board.get(r, c).getCard().getTreasure();
}

/**
 * Checks whether free card contains a treasure
 */
bool GameManager::isFreeTreasure()
{
    return this->_board.getFreeCard().isTreasure();
}

/**
 * Returns treasure from free card
 */
int GameManager::getFreeTreasure()
{
    return this->_board.getFreeCard().getTreasure();
}

/**
 * Returns game board
 */
MazeBoard GameManager::getBoard()
{
    return this->_board;
}

/**
 * Generates new treasures
 */
void GameManager::generateTreasures()
{
    this->_treasureIds = vector<int>();
    for (int i = 0; i < this->_treasureCount; i++) {
        this->_treasureIds.push_back(i);
    }
    random_shuffle(this->_treasureIds.begin(), this->_treasureIds.end());
}

/**
 * Takes treasure from deck
 */
int GameManager::takeTreasure()
{
    if (this->_treasureIds.size() > 0) {
        int id = this->_treasureIds.back();
        this->_treasureIds.pop_back();
        return id;
    } else {
        return -1;
    }
}

/**
 * Adjusts players on mazeboard
 *
 * @param r Row index
 * @param c Column index
 */
void GameManager::fixPlayerPositions(int r, int c)
{
    for (unsigned int i = 0; i < this->_players.size(); i++)
        this->fixPlayerPosition(r, c, i);
}

/**
 * Adjusts player's position
 *
 * @param r Row index
 * @param c Column index
 * @param id Player's index
 */
void GameManager::fixPlayerPosition(int r, int c, int id)
{
    int lim = this->_size - 1;
    int current_row = this->_players[id].row();
    int current_col = this->_players[id].col();

    if (this->_players[id].row() == r && r != 0 && r != lim) {
        if (c == 0) {
            this->_players[id].setLocation(current_row, this->fixPositionBounds(current_col + 1));
        } else if (c == lim) {
            this->_players[id].setLocation(current_row, this->fixPositionBounds(current_col - 1));
            //this->_players[id].setLocation(this->fixPositionBounds(current_row - 1), current_col);
        }
    } else if (this->_players[id].col() == c && c != 0 && c != lim) {
        if (r == 0) {
            //this->_players[id].setLocation(current_row, this->fixPositionBounds(current_col + 1));
            this->_players[id].setLocation(this->fixPositionBounds(current_row + 1), current_col);
        } else if (r == lim) {
            this->_players[id].setLocation(this->fixPositionBounds(current_row - 1), current_col);
            //this->_players[id].setLocation(current_row, this->fixPositionBounds(current_col - 1));
        }
    }
}

/**
 * Adjusts position to stay inside MazeBoard
 *
 * @param i Index
 */
int GameManager::fixPositionBounds(int i)
{
    return (i + this->_size) % this->_size;
}

/**
 * Reverts card move
 */
void GameManager::revertCard(Action action)
{
    int c = action.col();
    int r = action.row();
    int lim = this->_size - 1;

    if (c == 0) {
        c = lim;
    } else if (c == lim) {
        c = 0;
    }

    if (r == 0) {
        r = lim;
    } else if (r == lim) {
        r = 0;
    }

    this->_actions.pop_back();
    this->_actions.pop_back();
}

/**
 * Reverts player move
 */
void GameManager::revertPlayer(Action action)
{
    this->previousPlayer();
    if (action.type() == Action::TYPE::TAKE_TREASURE) {
        this->_players[this->getActiveIndex()].resetTreasure(action.col());
        this->_treasureIds.push_back(action.row());
        this->nextPlayer();
        this->_actions.pop_back();
        this->revertPlayer(this->_actions.back());
    } else {
        this->movePlayer(action.row(), action.col());
        this->_actions.pop_back();
        this->_actions.pop_back();
    }
}

/**
 * Places players on default locations
 */
void GameManager::playerAutoPlacement()
{
    auto cnt = this->_players.size();
    auto lim = this->_size - 1;
    if (cnt > 0)
        this->_players[0].setLocation(0, 0);
    if (cnt > 1)
        this->_players[1].setLocation(lim, lim);
    if (cnt > 2)
        this->_players[2].setLocation(0, lim);
    if (cnt > 3)
        this->_players[3].setLocation(lim, 0);
    this->playerDefaultTreasures();
}

void GameManager::playerDefaultTreasures()
{
    for (unsigned int i = 0; i < this->_players.size(); i++)
        this->_players[i].setNewTreasure(this->takeTreasure());
}

/**
 * Checks whether the game has already started
 */
bool GameManager::isStarted()
{
    return _started;
}
<commit_msg>Fixed undo<commit_after>#include "../../include/GameManager.h"

#include <iostream>
#include <fstream>

using namespace std;

GameManager::GameManager()
{
    //ctor
}

GameManager::~GameManager()
{
    //dtor
}

/**
 * Adds player to the game
 *
 * @param name Player's name
 */
bool GameManager::addPlayer(string name)
{
    if (this->_players.size() < 4) {
        this->_players.push_back(Player(name));
        return true;
    } else {
        return false;
    }
}

/**
 * Removes player from the game
 *
 * @param name Player's name
 */
bool GameManager::remPlayer(string name)
{
    return false;
}

/**
 * Returns size of the board
 * default value is 7
 */
int GameManager::getSize()
{
    return this->_size;
}

/**
 * Sets size of board
 *
 * @param n Size of board, value should be between 5 and 11
 */
bool GameManager::setSize(int n)
{
    if (n >= 5 && n <= 11 && n % 2 == 1) {
        this->_size = n;
        return true;
    } else {
        return false;
    }
}

/**
 * Starts the game
 */
bool GameManager::startGame()
{
    if (this->_players.size() >= 2) {
        this->_board = MazeBoard(this->_size);
        this->generateTreasures();
        this->_board.placeTreasures(this->_treasureIds);
        this->playerAutoPlacement();
        this->_started = true;
    }
    return this->_started;
}

/**
 * Restarts the game
 */
void GameManager::restartGame()
{
    this->_board.newGame();
    this->generateTreasures();
    this->_board.placeTreasures(this->_treasureIds);
    this->playerAutoPlacement();
}

/**
 * Returns vector with all possible moves
 */
vector<MazeField> GameManager::getMoves()
{
    Player active = this->getActive();
    MazeField mf = this->_board.get(active.row(), active.col());
    return PathFinder::possibleMoves(mf, this->_board);
}

/**
 * Moves card
 *
 * @param r Row index
 * @param c Column index
 */
bool GameManager::moveCard(int r, int c)
{
    MazeField field = this->_board.get(r, c);
    if (field.row() > -1) {
        this->_board.shift(field);
        this->fixPlayerPositions(r, c);
        this->_actions.push_back(Action(Action::TYPE::MOVE_CARD, r, c));
        return true;
    } else {
        return false;
    }
}

/**
 * Moves player to different field
 *
 * @param r Row index
 * @param c Column index
 */
bool GameManager::movePlayer(int r, int c)
{
    MazeField mf = this->_board.get(r, c);
    if (mf.row() > -1) {
        //auto moves = this->getMoves();
        int p_row = this->_players[this->getActiveIndex()].row();
        int p_col = this->_players[this->getActiveIndex()].col();
        MazeField curr = this->_board.get(p_row, p_col);
        if (PathFinder::findPath(curr, mf, this->_board)) {
            this->_actions.push_back(Action(Action::TYPE::MOVE_PLAYER, p_row, p_col));
            this->_players[this->getActiveIndex()].setLocation(mf.row(), mf.col());
            if(mf.getCard().getTreasure() == this->getActive().getTreasure()) {
                int oldId = mf.getCard().getTreasure();
                int newId = this->takeTreasure();
                this->_players[this->getActiveIndex()].setNewTreasure(newId);
                if (this->getActive().getScore() >= (this->_treasureCount / this->_players.size())) {
                    this->_won = true;
                }
                this->_actions.push_back(Action(Action::TYPE::TAKE_TREASURE, newId, oldId));
            }
            if (!this->isWon())
                this->nextPlayer();
            return true;
        }
    }
    return false;
}

/**
 * Reverts last move
 */
bool GameManager::undo()
{
    if (this->_actions.size() > 0) {
        Action toRevert = this->_actions.back();
        if (toRevert.type() == Action::TYPE::MOVE_CARD) {
                this->revertCard(toRevert);
        } else {
            this->revertPlayer(toRevert);
        }
        return true;
    } else {
        return false;
    }
}

/**
 * Sets next player as active
 */
void GameManager::nextPlayer()
{
    this->_activePlayer = (this->_activePlayer + 1) % this->_players.size();
}

/**
 * Sets previous player as activeě
 */
void GameManager::previousPlayer()
{
    this->_activePlayer = (this->_activePlayer + this->_players.size() - 1) % this->_players.size();
}

/**
 * Returns index of the active player
 */
int GameManager::getActiveIndex()
{
    return this->_activePlayer;
}

/**
 * Returns active player
 */
Player GameManager::getActive()
{
    return this->_players[this->getActiveIndex()];
}

/**
 * Sets treasure count
 *
 * @param n New treasure count
 */
bool GameManager::setTreasureCount(int n)
{
    if (n == 24 || n == 12) {
        this->_treasureCount = n;
        return true;
    } else {
        return false;
    }
}

/**
 * Saves current game to file
 *
 * @param fname File name
 */
bool GameManager::save(string fname)
{
    ofstream myfile;
    myfile.open (fname, ios::out);
    //Save players
    myfile << this->_players.size() << ";";
    for (unsigned int i = 0; i < this->_players.size(); i++)
        myfile << this->_players[i].toString();
    myfile << this->getActiveIndex() << ";";
    //Save treasures
    myfile << this->_treasureIds.size() << ";";
    for (unsigned int i = 0; i < this->_treasureIds.size(); i++)
        myfile << this->_treasureIds[i] << ";";

    //Save board
    myfile << this->_board.toString();

    myfile.close();
    return true;
}

/**
 * Loads game from file
 *
 * @param fname File name
 */
bool GameManager::load(string fname)
{
    ifstream myfile;
    string content = "";
    int index = 0;
    this->_players = vector<Player>();
    myfile.open(fname);
    myfile >> content;
    auto props = split(content, ';');
    /* read players */
    int playerCount = atoi(props[index].c_str());
    for (index = 1; index <= playerCount; index++) {
        this->_players.push_back(Player::fromString(props[index]));
    }
    this->_activePlayer = atoi(props[index].c_str());
    index++;
    /* read treasures */
    int treasureCount = atoi(props[index].c_str()) + index;
    this->_treasureIds = vector<int>();
    for (++index; index <= treasureCount; index++) {
        this->_treasureIds.push_back(atoi(props[index].c_str()));
    }
    /* read board */
    int boardSize = atoi(props[index].c_str());
    this->_size = boardSize;
    this->_board = MazeBoard(boardSize);
    vector<MazeCard> cards;
    int boardLimit = boardSize * boardSize + (++index);
    for (; index <= boardLimit; index++) {
        cards.push_back(MazeCard::fromString(props[index]));
    }
    /* store cards */
    for (int r = 0; r < boardSize; r++) {
        for (int c = 0; c < boardSize; c++) {
            this->_board.putCard(r, c, cards[c + r * boardSize]);
        }
    }
    this->_board.setFreeCard(cards.back());
    this->_started = true;
    myfile.close();
    return true;
}

/**
 * Returns vector of Player
 */
vector<Player> GameManager::getAllPlayers()
{
    return this->_players;
}

/**
 * Checks whether the game was won.
 */
bool GameManager::isWon()
{
    return this->_won;
}

/**
 * Returns vector of player names
 */
vector<string> GameManager::getNames()
{
    vector<string> names;
    for(unsigned int i = 0; i < this->_players.size(); i++)
        names.push_back(this->_players[i].getName());
    return names;
}

/**
 * Returns string representing card's path
 *
 * @param r Row index
 * @param c Column index
 */
string GameManager::getCardPath(int r, int c)
{
    return this->_board.get(r, c).getCard().getStringPath();
}

/**
 * Returns free card
 */
string GameManager::getFreeCard()
{
    return this->_board.getFreeCard().getStringPath();
}

/**
 * Turns free card to the right
 */
void GameManager::turnFreeCard()
{
    this->_board.turnFreeCard();
}

/**
 * Checks whether specified card contains treasure
 */
bool GameManager::isTreasure(int r, int c)
{
    return this->_board.get(r, c).getCard().isTreasure();
}

/**
 * Returns treasure from specified card
 *
 * @param r Row index
 * @param c Column index
 */
int GameManager::getTreasure(int r, int c)
{
    return this->_board.get(r, c).getCard().getTreasure();
}

/**
 * Checks whether free card contains a treasure
 */
bool GameManager::isFreeTreasure()
{
    return this->_board.getFreeCard().isTreasure();
}

/**
 * Returns treasure from free card
 */
int GameManager::getFreeTreasure()
{
    return this->_board.getFreeCard().getTreasure();
}

/**
 * Returns game board
 */
MazeBoard GameManager::getBoard()
{
    return this->_board;
}

/**
 * Generates new treasures
 */
void GameManager::generateTreasures()
{
    this->_treasureIds = vector<int>();
    for (int i = 0; i < this->_treasureCount; i++) {
        this->_treasureIds.push_back(i);
    }
    random_shuffle(this->_treasureIds.begin(), this->_treasureIds.end());
}

/**
 * Takes treasure from deck
 */
int GameManager::takeTreasure()
{
    if (this->_treasureIds.size() > 0) {
        int id = this->_treasureIds.back();
        this->_treasureIds.pop_back();
        return id;
    } else {
        return -1;
    }
}

/**
 * Adjusts players on mazeboard
 *
 * @param r Row index
 * @param c Column index
 */
void GameManager::fixPlayerPositions(int r, int c)
{
    for (unsigned int i = 0; i < this->_players.size(); i++)
        this->fixPlayerPosition(r, c, i);
}

/**
 * Adjusts player's position
 *
 * @param r Row index
 * @param c Column index
 * @param id Player's index
 */
void GameManager::fixPlayerPosition(int r, int c, int id)
{
    int lim = this->_size - 1;
    int current_row = this->_players[id].row();
    int current_col = this->_players[id].col();

    if (this->_players[id].row() == r && r != 0 && r != lim) {
        if (c == 0) {
            this->_players[id].setLocation(current_row, this->fixPositionBounds(current_col + 1));
        } else if (c == lim) {
            this->_players[id].setLocation(current_row, this->fixPositionBounds(current_col - 1));
            //this->_players[id].setLocation(this->fixPositionBounds(current_row - 1), current_col);
        }
    } else if (this->_players[id].col() == c && c != 0 && c != lim) {
        if (r == 0) {
            //this->_players[id].setLocation(current_row, this->fixPositionBounds(current_col + 1));
            this->_players[id].setLocation(this->fixPositionBounds(current_row + 1), current_col);
        } else if (r == lim) {
            this->_players[id].setLocation(this->fixPositionBounds(current_row - 1), current_col);
            //this->_players[id].setLocation(current_row, this->fixPositionBounds(current_col - 1));
        }
    }
}

/**
 * Adjusts position to stay inside MazeBoard
 *
 * @param i Index
 */
int GameManager::fixPositionBounds(int i)
{
    return (i + this->_size) % this->_size;
}

/**
 * Reverts card move
 */
void GameManager::revertCard(Action action)
{
    int c = action.col();
    int r = action.row();
    int lim = this->_size - 1;

    if (c == 0) {
        c = lim;
    } else if (c == lim) {
        c = 0;
    }

    if (r == 0) {
        r = lim;
    } else if (r == lim) {
        r = 0;
    }
    this->moveCard(r, c);

    this->_actions.pop_back();
    this->_actions.pop_back();
}

/**
 * Reverts player move
 */
void GameManager::revertPlayer(Action action)
{
    this->previousPlayer();
    if (action.type() == Action::TYPE::TAKE_TREASURE) {
        this->_players[this->getActiveIndex()].resetTreasure(action.col());
        this->_treasureIds.push_back(action.row());
        this->nextPlayer();
        this->_actions.pop_back();
        this->revertPlayer(this->_actions.back());
    } else {
        this->movePlayer(action.row(), action.col());
        this->_actions.pop_back();
        this->_actions.pop_back();
    }
}

/**
 * Places players on default locations
 */
void GameManager::playerAutoPlacement()
{
    auto cnt = this->_players.size();
    auto lim = this->_size - 1;
    if (cnt > 0)
        this->_players[0].setLocation(0, 0);
    if (cnt > 1)
        this->_players[1].setLocation(lim, lim);
    if (cnt > 2)
        this->_players[2].setLocation(0, lim);
    if (cnt > 3)
        this->_players[3].setLocation(lim, 0);
    this->playerDefaultTreasures();
}

void GameManager::playerDefaultTreasures()
{
    for (unsigned int i = 0; i < this->_players.size(); i++)
        this->_players[i].setNewTreasure(this->takeTreasure());
}

/**
 * Checks whether the game has already started
 */
bool GameManager::isStarted()
{
    return _started;
}
<|endoftext|>


<commit_before>//
//  ofxVideoRecorder.cpp
//  ofxVideoRecorderExample
//
//  Created by Timothy Scaffidi on 9/23/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#include "ofxVideoRecorder.h"

int setNonblocking(int fd)
{
    int flags;

    /* If they have O_NONBLOCK, use the Posix way to do it */
#if defined(O_NONBLOCK)
    /* Fixme: O_NONBLOCK is defined but broken on SunOS 4.1.x and AIX 3.2.5. */
    if (-1 == (flags = fcntl(fd, F_GETFL, 0)))
        flags = 0;
    return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
#else
    /* Otherwise, use the old way of doing it */
    flags = 1;
    return ioctl(fd, FIOBIO, &flags);
#endif
}

//===============================
execThread::execThread(){
    execCommand = "";
}

void execThread::setup(string command){
    execCommand = command;
    startThread(true, false);
}

void execThread::threadedFunction(){
    if(isThreadRunning()){
        system(execCommand.c_str());
    }
}

//===============================
ofxVideoDataWriterThread::ofxVideoDataWriterThread(){};
void ofxVideoDataWriterThread::setup(int file_desc, lockFreeQueue<ofPixels *> * q){
    fd = file_desc;
    queue = q;
    bIsWriting = false;
    startThread(true, false);
}

void ofxVideoDataWriterThread::threadedFunction(){
    while(isThreadRunning())
    {
        ofPixels * frame = NULL;
        if(queue->Consume(frame) && frame){
            bIsWriting = true;
            int b_offset = 0;
            int b_remaining = frame->getWidth()*frame->getHeight()*frame->getBytesPerPixel();
            int b_written = ::write(fd, ((char *)frame->getPixels())+b_offset, b_remaining);
            bIsWriting = false;
            frame->clear();
            delete frame;
        }
        else{
            condition.wait(conditionMutex);
        }
    }
}

void ofxVideoDataWriterThread::signal(){
    condition.signal();
}

//===============================
ofxAudioDataWriterThread::ofxAudioDataWriterThread(){};
void ofxAudioDataWriterThread::setup(int file_desc, lockFreeQueue<audioFrameShort *> *q){
    fd = file_desc;
    queue = q;
    bIsWriting = false;
    startThread(true, false);
}

void ofxAudioDataWriterThread::threadedFunction(){
    while(isThreadRunning())
    {
        audioFrameShort * frame = NULL;
        if(queue->Consume(frame) && frame){
            bIsWriting = true;

            int b_offset = 0;
            int b_remaining = frame->size*sizeof(short);
            int b_written = ::write(fd, ((char *)frame->data)+b_offset, b_remaining);
            bIsWriting = false;
            delete [] frame->data;
            delete frame;
        }
        else{
            condition.wait(conditionMutex);
        }
    }
}
void ofxAudioDataWriterThread::signal(){
    condition.signal();
}

//===============================
ofxVideoRecorder::ofxVideoRecorder()
{
    bIsInitialized = false;
    ffmpegLocation = "ffmpeg";
    videoCodec = "mpeg4";
    audioCodec = "aac";
    videoBitrate = "2000k";
    audioBitrate = "128k";
}

bool ofxVideoRecorder::setup(string fname, int w, int h, float fps, int sampleRate, int channels)
{
    if(bIsInitialized)
    {
        close();
    }

    fileName = fname;
    string absFilePath = ofFilePath::getAbsolutePath(fileName);

    moviePath = ofFilePath::getAbsolutePath(fileName);

    stringstream outputSettings;
    outputSettings
    << " -vcodec " << videoCodec
    << " -b " << videoBitrate
    << " -acodec " << audioCodec
    << " -ab " << audioBitrate
    << " " << absFilePath;

    return setupCustomOutput(w, h, fps, sampleRate, channels, outputSettings.str());
}

bool ofxVideoRecorder::setupCustomOutput(int w, int h, float fps, string outputString){
    return setupCustomOutput(w, h, fps, 0, 0, outputString);
}

bool ofxVideoRecorder::setupCustomOutput(int w, int h, float fps, int sampleRate, int channels, string outputString)
{
    if(bIsInitialized)
    {
        close();
    }

    bRecordAudio = (sampleRate > 0 && channels > 0);
    bRecordVideo = (w > 0 && h > 0 && fps > 0);
    bFinishing = false;

    videoFramesRecorded = 0;
    audioSamplesRecorded = 0;

    if(!bRecordVideo && !bRecordAudio) {
        ofLogWarning() << "ofxVideoRecorder::setupCustomOutput(): invalid parameters, could not setup video or audio stream.\n"
        << "video: " << w << "x" << h << "@" << fps << "fps\n"
        << "audio: " << "channels: " << channels << " @ " << sampleRate << "Hz\n";
        return false;
    }
    videoPipePath = "";
    audioPipePath = "";
    pipeNumber = requestPipeNumber();
    if(bRecordVideo) {
        width = w;
        height = h;
        frameRate = fps;

        // recording video, create a FIFO pipe
        videoPipePath = ofFilePath::getAbsolutePath("ofxvrpipe" + ofToString(pipeNumber));
        if(!ofFile::doesFileExist(videoPipePath)){
            string cmd = "bash --login -c 'mkfifo " + videoPipePath + "'";
            system(cmd.c_str());
            // TODO: add windows compatable pipe creation (does ffmpeg work with windows pipes?)
        }
    }

    if(bRecordAudio) {
        this->sampleRate = sampleRate;
        audioChannels = channels;

        // recording video, create a FIFO pipe
        audioPipePath = ofFilePath::getAbsolutePath("ofxarpipe" + ofToString(pipeNumber));
        if(!ofFile::doesFileExist(audioPipePath)){
            string cmd = "bash --login -c 'mkfifo " + audioPipePath + "'";
            system(cmd.c_str());

            // TODO: add windows compatable pipe creation (does ffmpeg work with windows pipes?)
        }
    }

    stringstream cmd;
    // basic ffmpeg invocation, -y option overwrites output file
    cmd << "bash --login -c '" << ffmpegLocation << " -y";
    if(bRecordAudio){
        cmd << " -acodec pcm_s16le -f s16le -ar " << sampleRate << " -ac " << audioChannels << " -i " << audioPipePath;
    }
    else { // no audio stream
        cmd << " -an";
    }
    if(bRecordVideo){ // video input options and file
        cmd << " -r "<< fps << " -s " << w << "x" << h << " -f rawvideo -pix_fmt rgb24 -i " << videoPipePath << " -r " << fps;
    }
    else { // no video stream
        cmd << " -vn";
    }
    cmd << " "+ outputString +"'";

    ffmpegThread.setup(cmd.str()); // start ffmpeg thread, will wait for input pipes to be opened

    if(bRecordAudio){
        audioPipeFd = ::open(audioPipePath.c_str(), O_WRONLY);
        audioThread.setup(audioPipeFd, &audioFrames);
    }
    if(bRecordVideo){
        videoPipeFd = ::open(videoPipePath.c_str(), O_WRONLY);
        videoThread.setup(videoPipeFd, &frames);
    }
    bIsInitialized = true;

    return bIsInitialized;
}

void ofxVideoRecorder::addFrame(const ofPixels &pixels)
{
    if(bIsInitialized && bRecordVideo)
    {
        int framesToAdd = 1; //default add one frame per request
        if(bRecordAudio && !bFinishing){
            //if also recording audio, check the overall recorded time for audio and video to make sure audio is not going out of sync
            //this also handles incoming dynamic framerate while maintaining desired outgoing framerate
            double videoRecordedTime = videoFramesRecorded / frameRate;
            double audioRecordedTime = audioSamplesRecorded  / (double)sampleRate;
            double avDelta = audioRecordedTime - videoRecordedTime;

            if(avDelta > 1.0/frameRate) {
                //more than one video frame's worth of audio data is waiting, we need to send extra video frames.
                int numFramesCopied = 0;
                while(avDelta > 1.0/frameRate) {
                    framesToAdd++;
                    avDelta -= 1.0/frameRate;
                }
                ofLogVerbose() << "ofxVideoRecorder: avDelta = " << avDelta << ". Not enough video frames for desired frame rate, copied this frame " << framesToAdd << " times.\n";
            }
            else if(avDelta < -1.0/frameRate){
                //more than one video frame is waiting, skip this frame
                framesToAdd = 0;
                ofLogVerbose() << "ofxVideoRecorder: avDelta = " << avDelta << ". Too many video frames, skipping.\n";
            }
        }
        for(int i=0;i<framesToAdd;i++){
            //add desired number of frames
            frames.Produce(new ofPixels(pixels));
            videoFramesRecorded++;
        }

        videoThread.signal();
    }
}

void ofxVideoRecorder::addAudioSamples(float *samples, int bufferSize, int numChannels){
    if(bIsInitialized && bRecordAudio){
        int size = bufferSize*numChannels;
        audioFrameShort * shortSamples = new audioFrameShort;
        shortSamples->data = new short[size];
        shortSamples->size = size;

        for(int i=0; i < size; i++){
            shortSamples->data[i] = (short)(samples[i] * 32767.0f);
        }
        audioFrames.Produce(shortSamples);
        audioThread.signal();
        audioSamplesRecorded += size;
    }
}

void ofxVideoRecorder::close()
{
    //this whole part could be cleaned up and is kludgy.
    //all of this is an attempt to make sure that both pipes are clear,
    //not stuck writing, and ffmpeg is not stuck waiting for more data
    //hopefully there is a better way that I'll figure out at some point
    // it SEEMS to be working now, but may stall in some cases
    // if it does stall, kill ffmpeg. you will need to re-encode the video file unfortunately

    bFinishing = true; // override frame doubling/dropping while finishing up
    while(frames.size() > 0 || audioFrames.size() > 0 || audioThread.isWriting() || videoThread.isWriting()) {
        videoThread.signal();
        audioThread.signal();
        //ofSleepMillis(5);
        //set pipes to non_blocking so we dont get stuck at the final writes
        if(frames.size() <=1){
            setNonblocking(audioPipeFd);
            setNonblocking(videoPipeFd);
        }
        if (audioFrames.size() < sampleRate/frameRate) {
            setNonblocking(audioPipeFd);
            setNonblocking(videoPipeFd);
        }

        if ((frames.size() > 0 || videoThread.isWriting()) && audioFrames.size() == 0) {
            // video frame in queue, or video thread stuck in a write. try to add enough audio data for ffmpeg to consume it
            ofLogVerbose() <<"ofxVideoRecorder::close(): stuck writing video, adding blank audio samples" <<endl;
            int numSamples = audioChannels*sampleRate/frameRate;
            float * samples = new float[numSamples];
            memset(samples, 0, sizeof(float)*numSamples);
            addAudioSamples(samples, numSamples, audioChannels);
            delete [] samples;
        }
        else if(frames.size() == 0 && (audioFrames.size() > 0 || audioThread.isWriting())) {
            // audio samples in queue, or audioThread stuck in a write. add blank video frame
            ofLogVerbose() <<"ofxVideoRecorder::close(): stuck writing audio, adding blank video frames" <<endl;
            ofPixels pixels;
            pixels.allocate(width,height,3);
            addFrame(pixels);
        }
    }

    videoThread.stopThread();
    videoThread.signal();
    audioThread.stopThread();
    audioThread.signal();
    bIsInitialized = false;

    if (bRecordVideo) {
        ::close(videoPipeFd);
    }
    if (bRecordAudio) {
        ::close(audioPipeFd);
    }

    retirePipeNumber(pipeNumber);

    ffmpegThread.waitForThread();
    // TODO: kill ffmpeg process if its taking too long to close for whatever reason.

}

set<int> ofxVideoRecorder::openPipes;

int ofxVideoRecorder::requestPipeNumber(){
    int n = 0;
    while (openPipes.find(n) != openPipes.end()) {
        n++;
    }
    openPipes.insert(n);
    return n;
}

void ofxVideoRecorder::retirePipeNumber(int num){
    if(!openPipes.erase(num)){
        ofLogNotice() << "ofxVideoRecorder::retirePipeNumber(): trying to retire a pipe number that is not being tracked: " << num << endl;
    }
}
<commit_msg>included unistd.h and fcntl.h for linux compatability<commit_after>//
//  ofxVideoRecorder.cpp
//  ofxVideoRecorderExample
//
//  Created by Timothy Scaffidi on 9/23/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#include "ofxVideoRecorder.h"
#include <unistd.h>
#include <fcntl.h>

int setNonblocking(int fd)
{
    int flags;

    /* If they have O_NONBLOCK, use the Posix way to do it */
#if defined(O_NONBLOCK)
    /* Fixme: O_NONBLOCK is defined but broken on SunOS 4.1.x and AIX 3.2.5. */
    if (-1 == (flags = fcntl(fd, F_GETFL, 0)))
        flags = 0;
    return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
#else
    /* Otherwise, use the old way of doing it */
    flags = 1;
    return ioctl(fd, FIOBIO, &flags);
#endif
}

//===============================
execThread::execThread(){
    execCommand = "";
}

void execThread::setup(string command){
    execCommand = command;
    startThread(true, false);
}

void execThread::threadedFunction(){
    if(isThreadRunning()){
        system(execCommand.c_str());
    }
}

//===============================
ofxVideoDataWriterThread::ofxVideoDataWriterThread(){};
void ofxVideoDataWriterThread::setup(int file_desc, lockFreeQueue<ofPixels *> * q){
    fd = file_desc;
    queue = q;
    bIsWriting = false;
    startThread(true, false);
}

void ofxVideoDataWriterThread::threadedFunction(){
    while(isThreadRunning())
    {
        ofPixels * frame = NULL;
        if(queue->Consume(frame) && frame){
            bIsWriting = true;
            int b_offset = 0;
            int b_remaining = frame->getWidth()*frame->getHeight()*frame->getBytesPerPixel();
            int b_written = ::write(fd, ((char *)frame->getPixels())+b_offset, b_remaining);
            bIsWriting = false;
            frame->clear();
            delete frame;
        }
        else{
            condition.wait(conditionMutex);
        }
    }
}

void ofxVideoDataWriterThread::signal(){
    condition.signal();
}

//===============================
ofxAudioDataWriterThread::ofxAudioDataWriterThread(){};
void ofxAudioDataWriterThread::setup(int file_desc, lockFreeQueue<audioFrameShort *> *q){
    fd = file_desc;
    queue = q;
    bIsWriting = false;
    startThread(true, false);
}

void ofxAudioDataWriterThread::threadedFunction(){
    while(isThreadRunning())
    {
        audioFrameShort * frame = NULL;
        if(queue->Consume(frame) && frame){
            bIsWriting = true;

            int b_offset = 0;
            int b_remaining = frame->size*sizeof(short);
            int b_written = ::write(fd, ((char *)frame->data)+b_offset, b_remaining);
            bIsWriting = false;
            delete [] frame->data;
            delete frame;
        }
        else{
            condition.wait(conditionMutex);
        }
    }
}
void ofxAudioDataWriterThread::signal(){
    condition.signal();
}

//===============================
ofxVideoRecorder::ofxVideoRecorder()
{
    bIsInitialized = false;
    ffmpegLocation = "ffmpeg";
    videoCodec = "mpeg4";
    audioCodec = "aac";
    videoBitrate = "2000k";
    audioBitrate = "128k";
}

bool ofxVideoRecorder::setup(string fname, int w, int h, float fps, int sampleRate, int channels)
{
    if(bIsInitialized)
    {
        close();
    }

    fileName = fname;
    string absFilePath = ofFilePath::getAbsolutePath(fileName);

    moviePath = ofFilePath::getAbsolutePath(fileName);

    stringstream outputSettings;
    outputSettings
    << " -vcodec " << videoCodec
    << " -b " << videoBitrate
    << " -acodec " << audioCodec
    << " -ab " << audioBitrate
    << " " << absFilePath;

    return setupCustomOutput(w, h, fps, sampleRate, channels, outputSettings.str());
}

bool ofxVideoRecorder::setupCustomOutput(int w, int h, float fps, string outputString){
    return setupCustomOutput(w, h, fps, 0, 0, outputString);
}

bool ofxVideoRecorder::setupCustomOutput(int w, int h, float fps, int sampleRate, int channels, string outputString)
{
    if(bIsInitialized)
    {
        close();
    }

    bRecordAudio = (sampleRate > 0 && channels > 0);
    bRecordVideo = (w > 0 && h > 0 && fps > 0);
    bFinishing = false;

    videoFramesRecorded = 0;
    audioSamplesRecorded = 0;

    if(!bRecordVideo && !bRecordAudio) {
        ofLogWarning() << "ofxVideoRecorder::setupCustomOutput(): invalid parameters, could not setup video or audio stream.\n"
        << "video: " << w << "x" << h << "@" << fps << "fps\n"
        << "audio: " << "channels: " << channels << " @ " << sampleRate << "Hz\n";
        return false;
    }
    videoPipePath = "";
    audioPipePath = "";
    pipeNumber = requestPipeNumber();
    if(bRecordVideo) {
        width = w;
        height = h;
        frameRate = fps;

        // recording video, create a FIFO pipe
        videoPipePath = ofFilePath::getAbsolutePath("ofxvrpipe" + ofToString(pipeNumber));
        if(!ofFile::doesFileExist(videoPipePath)){
            string cmd = "bash --login -c 'mkfifo " + videoPipePath + "'";
            system(cmd.c_str());
            // TODO: add windows compatable pipe creation (does ffmpeg work with windows pipes?)
        }
    }

    if(bRecordAudio) {
        this->sampleRate = sampleRate;
        audioChannels = channels;

        // recording video, create a FIFO pipe
        audioPipePath = ofFilePath::getAbsolutePath("ofxarpipe" + ofToString(pipeNumber));
        if(!ofFile::doesFileExist(audioPipePath)){
            string cmd = "bash --login -c 'mkfifo " + audioPipePath + "'";
            system(cmd.c_str());

            // TODO: add windows compatable pipe creation (does ffmpeg work with windows pipes?)
        }
    }

    stringstream cmd;
    // basic ffmpeg invocation, -y option overwrites output file
    cmd << "bash --login -c '" << ffmpegLocation << " -y";
    if(bRecordAudio){
        cmd << " -acodec pcm_s16le -f s16le -ar " << sampleRate << " -ac " << audioChannels << " -i " << audioPipePath;
    }
    else { // no audio stream
        cmd << " -an";
    }
    if(bRecordVideo){ // video input options and file
        cmd << " -r "<< fps << " -s " << w << "x" << h << " -f rawvideo -pix_fmt rgb24 -i " << videoPipePath << " -r " << fps;
    }
    else { // no video stream
        cmd << " -vn";
    }
    cmd << " "+ outputString +"'";

    ffmpegThread.setup(cmd.str()); // start ffmpeg thread, will wait for input pipes to be opened

    if(bRecordAudio){
        audioPipeFd = ::open(audioPipePath.c_str(), O_WRONLY);
        audioThread.setup(audioPipeFd, &audioFrames);
    }
    if(bRecordVideo){
        videoPipeFd = ::open(videoPipePath.c_str(), O_WRONLY);
        videoThread.setup(videoPipeFd, &frames);
    }
    bIsInitialized = true;

    return bIsInitialized;
}

void ofxVideoRecorder::addFrame(const ofPixels &pixels)
{
    if(bIsInitialized && bRecordVideo)
    {
        int framesToAdd = 1; //default add one frame per request
        if(bRecordAudio && !bFinishing){
            //if also recording audio, check the overall recorded time for audio and video to make sure audio is not going out of sync
            //this also handles incoming dynamic framerate while maintaining desired outgoing framerate
            double videoRecordedTime = videoFramesRecorded / frameRate;
            double audioRecordedTime = audioSamplesRecorded  / (double)sampleRate;
            double avDelta = audioRecordedTime - videoRecordedTime;

            if(avDelta > 1.0/frameRate) {
                //more than one video frame's worth of audio data is waiting, we need to send extra video frames.
                int numFramesCopied = 0;
                while(avDelta > 1.0/frameRate) {
                    framesToAdd++;
                    avDelta -= 1.0/frameRate;
                }
                ofLogVerbose() << "ofxVideoRecorder: avDelta = " << avDelta << ". Not enough video frames for desired frame rate, copied this frame " << framesToAdd << " times.\n";
            }
            else if(avDelta < -1.0/frameRate){
                //more than one video frame is waiting, skip this frame
                framesToAdd = 0;
                ofLogVerbose() << "ofxVideoRecorder: avDelta = " << avDelta << ". Too many video frames, skipping.\n";
            }
        }
        for(int i=0;i<framesToAdd;i++){
            //add desired number of frames
            frames.Produce(new ofPixels(pixels));
            videoFramesRecorded++;
        }

        videoThread.signal();
    }
}

void ofxVideoRecorder::addAudioSamples(float *samples, int bufferSize, int numChannels){
    if(bIsInitialized && bRecordAudio){
        int size = bufferSize*numChannels;
        audioFrameShort * shortSamples = new audioFrameShort;
        shortSamples->data = new short[size];
        shortSamples->size = size;

        for(int i=0; i < size; i++){
            shortSamples->data[i] = (short)(samples[i] * 32767.0f);
        }
        audioFrames.Produce(shortSamples);
        audioThread.signal();
        audioSamplesRecorded += size;
    }
}

void ofxVideoRecorder::close()
{
    //this whole part could be cleaned up and is kludgy.
    //all of this is an attempt to make sure that both pipes are clear,
    //not stuck writing, and ffmpeg is not stuck waiting for more data
    //hopefully there is a better way that I'll figure out at some point
    // it SEEMS to be working now, but may stall in some cases
    // if it does stall, kill ffmpeg. you will need to re-encode the video file unfortunately

    bFinishing = true; // override frame doubling/dropping while finishing up
    while(frames.size() > 0 || audioFrames.size() > 0 || audioThread.isWriting() || videoThread.isWriting()) {
        videoThread.signal();
        audioThread.signal();
        //ofSleepMillis(5);
        //set pipes to non_blocking so we dont get stuck at the final writes
        if(frames.size() <=1){
            setNonblocking(audioPipeFd);
            setNonblocking(videoPipeFd);
        }
        if (audioFrames.size() < sampleRate/frameRate) {
            setNonblocking(audioPipeFd);
            setNonblocking(videoPipeFd);
        }

        if ((frames.size() > 0 || videoThread.isWriting()) && audioFrames.size() == 0) {
            // video frame in queue, or video thread stuck in a write. try to add enough audio data for ffmpeg to consume it
            ofLogVerbose() <<"ofxVideoRecorder::close(): stuck writing video, adding blank audio samples" <<endl;
            int numSamples = audioChannels*sampleRate/frameRate;
            float * samples = new float[numSamples];
            memset(samples, 0, sizeof(float)*numSamples);
            addAudioSamples(samples, numSamples, audioChannels);
            delete [] samples;
        }
        else if(frames.size() == 0 && (audioFrames.size() > 0 || audioThread.isWriting())) {
            // audio samples in queue, or audioThread stuck in a write. add blank video frame
            ofLogVerbose() <<"ofxVideoRecorder::close(): stuck writing audio, adding blank video frames" <<endl;
            ofPixels pixels;
            pixels.allocate(width,height,3);
            addFrame(pixels);
        }
    }

    videoThread.stopThread();
    videoThread.signal();
    audioThread.stopThread();
    audioThread.signal();
    bIsInitialized = false;

    if (bRecordVideo) {
        ::close(videoPipeFd);
    }
    if (bRecordAudio) {
        ::close(audioPipeFd);
    }

    retirePipeNumber(pipeNumber);

    ffmpegThread.waitForThread();
    // TODO: kill ffmpeg process if its taking too long to close for whatever reason.

}

set<int> ofxVideoRecorder::openPipes;

int ofxVideoRecorder::requestPipeNumber(){
    int n = 0;
    while (openPipes.find(n) != openPipes.end()) {
        n++;
    }
    openPipes.insert(n);
    return n;
}

void ofxVideoRecorder::retirePipeNumber(int num){
    if(!openPipes.erase(num)){
        ofLogNotice() << "ofxVideoRecorder::retirePipeNumber(): trying to retire a pipe number that is not being tracked: " << num << endl;
    }
}
<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkImageCorrelation.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$
  Thanks:    Thanks to C. Charles Law who developed this class.

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkImageCache.h"
#include "vtkImageCorrelation.h"

//----------------------------------------------------------------------------
vtkImageCorrelation::vtkImageCorrelation()
{
  this->Dimensionality = 2;
}

//----------------------------------------------------------------------------
// Description:
// Grow the output image
void vtkImageCorrelation::ExecuteImageInformation()
{
  int extent1[6];

  this->Inputs[0]->GetWholeExtent(extent1);

  this->Output->SetNumberOfScalarComponents(1);

  this->Output->SetWholeExtent(extent1);
  this->Output->SetScalarType(VTK_FLOAT);
}

//----------------------------------------------------------------------------
// Description:
// Grow
void vtkImageCorrelation::ComputeRequiredInputUpdateExtent(int inExt[6],
							   int outExt[6],
							   int whichInput)
{
  if (whichInput == 1)
    {
    // get the whole image for input 2
    memcpy(inExt,this->Inputs[whichInput]->GetWholeExtent(),6*sizeof(int));
    }
  else
    {
    // use the outExtent
    memcpy(inExt,outExt,6*sizeof(int));
    }
}

//----------------------------------------------------------------------------
// Description:
// This method is passed a input and output datas, and executes the filter
// It only deals with floats for now
//----------------------------------------------------------------------------
// Description:
// This templated function executes the filter for any type of data.
// Handles the two input operations
template <class T>
static void vtkImageCorrelationExecute(vtkImageCorrelation *self,
				       vtkImageData *in1Data, T *in1Ptr,
				       vtkImageData *in2Data, T *in2Ptr,
				       vtkImageData *outData, float *outPtr,
				       int outExt[6], int id)
{
  int idxC, idxX, idxY, idxZ;
  int maxC, maxX, maxY, maxZ;
  int in1IncX, in1IncY, in1IncZ;
  int in1CIncX, in1CIncY, in1CIncZ;
  int in2IncX, in2IncY, in2IncZ;
  int outIncX, outIncY, outIncZ;
  unsigned long count = 0;
  unsigned long target;
  int *in2Extent;
  T *in2Ptr2, *in1Ptr2;
  int kIdxX, kIdxY, kIdxZ;
  int xKernMax, yKernMax, zKernMax;

  // find the region to loop over
  maxC = in1Data->GetNumberOfScalarComponents();
  maxX = outExt[1] - outExt[0];
  maxY = outExt[3] - outExt[2];
  maxZ = outExt[5] - outExt[4];
  target = (unsigned long)((maxZ+1)*(maxY+1)/50.0);
  target++;

  // get some other info we need
  in2Extent = self->GetInput2()->GetWholeExtent();

  // Get increments to march through data
  in1Data->GetContinuousIncrements(outExt, in1CIncX, in1CIncY, in1CIncZ);
  in1Data->GetIncrements(in1IncX, in1IncY, in1IncZ);
  in2Data->GetIncrements(in2IncX, in2IncY, in2IncZ);
  outData->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ);

  // Loop through ouput pixels
  for (idxZ = 0; idxZ <= maxZ; idxZ++)
    {
    // how much of kernel to use
    zKernMax = maxZ - idxZ;
    if (zKernMax > in2Extent[5]) zKernMax = in2Extent[5];
    for (idxY = 0; idxY <= maxY; idxY++)
      {
      if (!id)
	{
	if (!(count%target)) self->UpdateProgress(count/(50.0*target));
	count++;
	}
      yKernMax = maxY - idxY;
      if (yKernMax > in2Extent[3]) yKernMax = in2Extent[3];
      for (idxX = 0; idxX <= maxX; idxX++)
	{
	// determine the extent of input 1 that contributes to this pixel
	*outPtr = 0.0;
	xKernMax = maxX - idxX;
	if (xKernMax > in2Extent[1]) xKernMax = in2Extent[1];

	// sumation
	for (kIdxZ = 0; kIdxZ <= zKernMax; kIdxZ++)
	  {
	  for (kIdxY = 0; kIdxY <= yKernMax; kIdxY++)
	    {
	    in1Ptr2 = in1Ptr + kIdxY*in1IncY + kIdxZ*in1IncZ;
	    in2Ptr2 = in2Ptr + kIdxY*in2IncY + kIdxZ*in2IncZ;
	    for (kIdxX = 0; kIdxX <= xKernMax; kIdxX++)
	      {
	      for (idxC = 0; idxC < maxC; idxC++)
		{
		*outPtr = *outPtr + (*in1Ptr2) * (*in2Ptr2);
		in1Ptr2++;
		in2Ptr2++;
		}
	      }
	    }
	  }
	in1Ptr += maxC;
	outPtr++;
	}
      in1Ptr += in1CIncY;
      outPtr += outIncY;
      }
    in1Ptr += in1CIncZ;
    outPtr += outIncZ;
    }
}

//----------------------------------------------------------------------------
// Description:
// This method is passed a input and output datas, and executes the filter
// algorithm to fill the output from the inputs.
// It just executes a switch statement to call the correct function for
// the datas data types.
void vtkImageCorrelation::ThreadedExecute(vtkImageData **inData,
					  vtkImageData *outData,
					  int outExt[6], int id)
{
  int *in2Extent = this->Inputs[1]->GetWholeExtent();
  void *in1Ptr = inData[0]->GetScalarPointerForExtent(outExt);
  void *in2Ptr = inData[1]->GetScalarPointerForExtent(in2Extent);
  float *outPtr = (float *)outData->GetScalarPointerForExtent(outExt);

  vtkDebugMacro(<< "Execute: inData = " << inData << ", outData = " << outData);

  // this filter expects that input is the same type as output.
  if (inData[0]->GetScalarType() != inData[1]->GetScalarType())
    {
    vtkErrorMacro(<< "Execute: input ScalarType, " <<
    inData[0]->GetScalarType() << " and input2 ScalarType " <<
    inData[1]->GetScalarType() << ", should match");
    return;
    }

  // input depths must match
  if (inData[0]->GetNumberOfScalarComponents() !=
      inData[1]->GetNumberOfScalarComponents())
    {
    vtkErrorMacro(<< "Execute: input depths must match");
    return;
    }

  switch (inData[0]->GetScalarType())
    {
    case VTK_FLOAT:
      vtkImageCorrelationExecute(this, inData[0],
				 (float *)(in1Ptr),
				 inData[1], (float *)(in2Ptr),
				 outData, outPtr,
				 outExt, id);
      break;
    case VTK_INT:
      vtkImageCorrelationExecute(this, inData[0], (int *)(in1Ptr),
				 inData[1], (int *)(in2Ptr),
				 outData, outPtr,
				 outExt, id);
      break;
    case VTK_SHORT:
      vtkImageCorrelationExecute(this, inData[0],
				 (short *)(in1Ptr),
				 inData[1], (short *)(in2Ptr),
				 outData, outPtr,
				 outExt, id);
      break;
    case VTK_UNSIGNED_SHORT:
      vtkImageCorrelationExecute(this, inData[0],
				 (unsigned short *)(in1Ptr),
				 inData[1],
				 (unsigned short *)(in2Ptr),
				 outData, outPtr, outExt, id);
      break;
    case VTK_UNSIGNED_CHAR:
      vtkImageCorrelationExecute(this, inData[0],
				 (unsigned char *)(in1Ptr),
				 inData[1],
				 (unsigned char *)(in2Ptr),
				 outData, outPtr, outExt, id);
      break;
    default:
      vtkErrorMacro(<< "Execute: Unknown ScalarType");
      return;
    }
}
<commit_msg>BUG: multuthread bug fix<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImageCorrelation.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$
  Thanks:    Thanks to C. Charles Law who developed this class.

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkImageCache.h"
#include "vtkImageCorrelation.h"

//----------------------------------------------------------------------------
vtkImageCorrelation::vtkImageCorrelation()
{
  this->Dimensionality = 2;
}

//----------------------------------------------------------------------------
// Description:
// Grow the output image
void vtkImageCorrelation::ExecuteImageInformation()
{
  int extent1[6];

  this->Inputs[0]->GetWholeExtent(extent1);

  this->Output->SetNumberOfScalarComponents(1);

  this->Output->SetWholeExtent(extent1);
  this->Output->SetScalarType(VTK_FLOAT);
}

//----------------------------------------------------------------------------
// Description:
// Grow
void vtkImageCorrelation::ComputeRequiredInputUpdateExtent(int inExt[6],
							   int outExt[6],
							   int whichInput)
{
  if (whichInput == 1)
    {
    // get the whole image for input 2
    memcpy(inExt,this->Inputs[whichInput]->GetWholeExtent(),6*sizeof(int));
    }
  else
    {
    // try to get all the data required to handle the boundaries
    // but limit to the whole extent
    int idx;
    int *i0WExtent = this->Inputs[0]->GetWholeExtent();
    int *i1WExtent = this->Inputs[1]->GetWholeExtent();
    memcpy(inExt,outExt,6*sizeof(int));
    for (idx = 0; idx < 3; idx++)
      {
      inExt[idx*2+1] = outExt[idx*2+1] +
	(i1WExtent[idx*2+1] - i1WExtent[idx*2]);

      // clip to whole extent
      if (inExt[idx*2+1] > i0WExtent[idx*2+1])
	{
	inExt[idx*2+1] = i0WExtent[idx*2+1];
	}
      }
    }
}

//----------------------------------------------------------------------------
// Description:
// This templated function executes the filter for any type of data.
// Handles the two input operations
template <class T>
static void vtkImageCorrelationExecute(vtkImageCorrelation *self,
				       vtkImageData *in1Data, T *in1Ptr,
				       vtkImageData *in2Data, T *in2Ptr,
				       vtkImageData *outData, float *outPtr,
				       int outExt[6], int id)
{
  int idxC, idxX, idxY, idxZ;
  int maxC, maxX, maxY, maxZ;
  int in1IncX, in1IncY, in1IncZ;
  int in1CIncX, in1CIncY, in1CIncZ;
  int in2IncX, in2IncY, in2IncZ;
  int outIncX, outIncY, outIncZ;
  unsigned long count = 0;
  unsigned long target;
  int *in2Extent;
  T *in2Ptr2, *in1Ptr2;
  int kIdxX, kIdxY, kIdxZ;
  int xKernMax, yKernMax, zKernMax;
  int maxIX, maxIY, maxIZ;
  int *wExtent;

  // find the region to loop over
  maxC = in1Data->GetNumberOfScalarComponents();
  maxX = outExt[1] - outExt[0];
  maxY = outExt[3] - outExt[2];
  maxZ = outExt[5] - outExt[4];
  target = (unsigned long)((maxZ+1)*(maxY+1)/50.0);
  target++;

  // get some other info we need
  in2Extent = self->GetInput2()->GetWholeExtent();

  // Get increments to march through data
  in1Data->GetContinuousIncrements(outExt, in1CIncX, in1CIncY, in1CIncZ);
  in1Data->GetIncrements(in1IncX, in1IncY, in1IncZ);
  in2Data->GetIncrements(in2IncX, in2IncY, in2IncZ);
  outData->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ);

  // how far can we gon with input data
  // this may be farther that the outExt because of
  // subpieces etc.
  wExtent = in1Data->GetExtent();
  maxIZ = wExtent[5] - outExt[4];
  maxIY = wExtent[3] - outExt[2];
  maxIX = wExtent[1] - outExt[0];

  // Loop through ouput pixels
  for (idxZ = 0; idxZ <= maxZ; idxZ++)
    {
    // how much of kernel to use
    zKernMax = maxIZ - idxZ;
    if (zKernMax > in2Extent[5]) zKernMax = in2Extent[5];
    for (idxY = 0; idxY <= maxY; idxY++)
      {
      if (!id)
	{
	if (!(count%target)) self->UpdateProgress(count/(50.0*target));
	count++;
	}
      yKernMax = maxIY - idxY;
      if (yKernMax > in2Extent[3]) yKernMax = in2Extent[3];
      for (idxX = 0; idxX <= maxX; idxX++)
	{
	// determine the extent of input 1 that contributes to this pixel
	*outPtr = 0.0;
	xKernMax = maxIX - idxX;
	if (xKernMax > in2Extent[1]) xKernMax = in2Extent[1];

	// sumation
	for (kIdxZ = 0; kIdxZ <= zKernMax; kIdxZ++)
	  {
	  for (kIdxY = 0; kIdxY <= yKernMax; kIdxY++)
	    {
	    in1Ptr2 = in1Ptr + kIdxY*in1IncY + kIdxZ*in1IncZ;
	    in2Ptr2 = in2Ptr + kIdxY*in2IncY + kIdxZ*in2IncZ;
	    for (kIdxX = 0; kIdxX <= xKernMax; kIdxX++)
	      {
	      for (idxC = 0; idxC < maxC; idxC++)
		{
		*outPtr = *outPtr + (*in1Ptr2) * (*in2Ptr2);
		in1Ptr2++;
		in2Ptr2++;
		}
	      }
	    }
	  }
	in1Ptr += maxC;
	outPtr++;
	}
      in1Ptr += in1CIncY;
      outPtr += outIncY;
      }
    in1Ptr += in1CIncZ;
    outPtr += outIncZ;
    }
}

//----------------------------------------------------------------------------
// Description:
// This method is passed a input and output datas, and executes the filter
// algorithm to fill the output from the inputs.
// It just executes a switch statement to call the correct function for
// the datas data types.
void vtkImageCorrelation::ThreadedExecute(vtkImageData **inData,
					  vtkImageData *outData,
					  int outExt[6], int id)
{
  int *in2Extent = this->Inputs[1]->GetWholeExtent();
  void *in1Ptr = inData[0]->GetScalarPointerForExtent(outExt);
  void *in2Ptr = inData[1]->GetScalarPointerForExtent(in2Extent);
  float *outPtr = (float *)outData->GetScalarPointerForExtent(outExt);

  vtkDebugMacro(<< "Execute: inData = " << inData << ", outData = " << outData);

  // this filter expects that input is the same type as output.
  if (inData[0]->GetScalarType() != inData[1]->GetScalarType())
    {
    vtkErrorMacro(<< "Execute: input ScalarType, " <<
    inData[0]->GetScalarType() << " and input2 ScalarType " <<
    inData[1]->GetScalarType() << ", should match");
    return;
    }

  // input depths must match
  if (inData[0]->GetNumberOfScalarComponents() !=
      inData[1]->GetNumberOfScalarComponents())
    {
    vtkErrorMacro(<< "Execute: input depths must match");
    return;
    }

  switch (inData[0]->GetScalarType())
    {
    case VTK_FLOAT:
      vtkImageCorrelationExecute(this, inData[0],
				 (float *)(in1Ptr),
				 inData[1], (float *)(in2Ptr),
				 outData, outPtr,
				 outExt, id);
      break;
    case VTK_INT:
      vtkImageCorrelationExecute(this, inData[0], (int *)(in1Ptr),
				 inData[1], (int *)(in2Ptr),
				 outData, outPtr,
				 outExt, id);
      break;
    case VTK_SHORT:
      vtkImageCorrelationExecute(this, inData[0],
				 (short *)(in1Ptr),
				 inData[1], (short *)(in2Ptr),
				 outData, outPtr,
				 outExt, id);
      break;
    case VTK_UNSIGNED_SHORT:
      vtkImageCorrelationExecute(this, inData[0],
				 (unsigned short *)(in1Ptr),
				 inData[1],
				 (unsigned short *)(in2Ptr),
				 outData, outPtr, outExt, id);
      break;
    case VTK_UNSIGNED_CHAR:
      vtkImageCorrelationExecute(this, inData[0],
				 (unsigned char *)(in1Ptr),
				 inData[1],
				 (unsigned char *)(in2Ptr),
				 outData, outPtr, outExt, id);
      break;
    default:
      vtkErrorMacro(<< "Execute: Unknown ScalarType");
      return;
    }
}
<|endoftext|>