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

  Program:   Visualization Toolkit
  Module:    TestAMRGhostLayerStripping.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm 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 notice for more information.

=========================================================================*/
// .NAME TestAMRGhostLayerStripping.cxx -- Test for stripping ghost layers
//
// .SECTION Description
// A simple test for testing the functionality of stripping out ghost layers
// that partially cover lower resolution cells. The test constructs an AMR
// configuration using the vtkAMRGaussianPulseSource which has a known structure.
// Ghost layers are manually added to the hi-res grids and then stripped out.
// Tests cover also configurations with different refinement ratios and
// different numbers of ghost-layers.

// C/C++ includes
#include <cassert>
#include <cmath>
#include <iostream>
#include <sstream>

// VTK includes
#include "vtkAMRGaussianPulseSource.h"
#include "vtkAMRUtilities.h"
#include "vtkCell.h"
#include "vtkCellData.h"
#include "vtkDoubleArray.h"
#include "vtkOverlappingAMR.h"
#include "vtkUniformGrid.h"
#include "vtkXMLImageDataWriter.h"

#define DEBUG_ON

//------------------------------------------------------------------------------
void WriteUniformGrid( vtkUniformGrid *g, std::string prefix )
{
  assert( "pre: Uniform grid (g) is NULL!" && (g != NULL) );

  vtkXMLImageDataWriter *imgWriter = vtkXMLImageDataWriter::New();

  std::ostringstream oss;
  oss << prefix << "." << imgWriter->GetDefaultFileExtension();
  imgWriter->SetFileName( oss.str().c_str() );
  imgWriter->SetInputData( g );
  imgWriter->Write();

  imgWriter->Delete();
}

//------------------------------------------------------------------------------
double ComputePulse(
    const int dimension,
    double location[3],
    double pulseOrigin[3],
    double pulseWidth[3],
    double pulseAmplitude)
{
  double pulse = 0.0;

  double r = 0.0;
  for( int i=0; i < dimension; ++i )
    {
    double d = location[i]-pulseOrigin[i];
    double d2 = d*d;
    double L2 = pulseWidth[i]*pulseWidth[i];
    r += d2/L2;
    } // END for all dimensions
  pulse = pulseAmplitude * std::exp( -r );

  return( pulse );
}

//------------------------------------------------------------------------------
void ComputeCellCenter(
    vtkUniformGrid *grid, vtkIdType cellIdx, double centroid[3])
{
  assert("pre: input grid instance is NULL" && (grid != NULL));
  assert("pre: cell index is out-of-bounds!" &&
         (cellIdx >= 0) && (cellIdx < grid->GetNumberOfCells()));

  vtkCell *myCell = grid->GetCell( cellIdx );
  assert( "ERROR: Cell is NULL" && (myCell != NULL) );

  double pcenter[3];
  double *weights = new double[ myCell->GetNumberOfPoints() ];
  int subId = myCell->GetParametricCenter( pcenter );
  myCell->EvaluateLocation( subId, pcenter, centroid, weights );
  delete [] weights;
}

//------------------------------------------------------------------------------
void GeneratePulseField(const int dimension,vtkUniformGrid* grid)
{
  assert("pre: grid is NULL!" && (grid != NULL));
  assert("pre: grid is empty!" && (grid->GetNumberOfCells() >= 1) );

  double pulseOrigin[3];
  double pulseWidth[3];
  double pulseAmplitude;

  vtkAMRGaussianPulseSource *pulseSource = vtkAMRGaussianPulseSource::New();
  pulseSource->GetPulseOrigin( pulseOrigin );
  pulseSource->GetPulseWidth( pulseWidth );
  pulseAmplitude = pulseSource->GetPulseAmplitude();
  pulseSource->Delete();

  vtkDoubleArray *centroidArray = vtkDoubleArray::New();
  centroidArray->SetName("Centroid");
  centroidArray->SetNumberOfComponents( 3 );
  centroidArray->SetNumberOfTuples( grid->GetNumberOfCells() );

  vtkDoubleArray *pulseField = vtkDoubleArray::New();
  pulseField->SetName( "Gaussian-Pulse" );
  pulseField->SetNumberOfComponents( 1 );
  pulseField->SetNumberOfTuples( grid->GetNumberOfCells() );

  double centroid[3];
  vtkIdType cellIdx = 0;
  for(; cellIdx < grid->GetNumberOfCells(); ++cellIdx )
    {
    ComputeCellCenter(grid,cellIdx,centroid);
    centroidArray->SetComponent(cellIdx,0,centroid[0]);
    centroidArray->SetComponent(cellIdx,1,centroid[1]);
    centroidArray->SetComponent(cellIdx,2,centroid[2]);

    double pulse = ComputePulse(
        dimension,centroid,pulseOrigin,pulseWidth,pulseAmplitude);
    pulseField->SetComponent(cellIdx,0,pulse);
    } // END for all cells

  grid->GetCellData()->AddArray( centroidArray );
  centroidArray->Delete();
  grid->GetCellData()->AddArray( pulseField );
  pulseField->Delete();
}

//------------------------------------------------------------------------------
vtkUniformGrid* GetGhostedGrid(
    const int dimension,vtkUniformGrid *refGrid, int ghost[6], const int NG)
{
  assert("pre: NG >= 1" && (NG >= 1) );

  // STEP 0: If the reference grid is NULL just return
  if( refGrid == NULL )
    {
    return NULL;
    }

  // STEP 1: Acquire reference grid origin,spacing, dims
  int dims[3];
  double origin[3];
  double spacing[3];
  refGrid->GetOrigin(origin);
  refGrid->GetSpacing(spacing);
  refGrid->GetDimensions(dims);

  // STEP 2: Adjust origin and dimensions for ghost cells along each dimension
  for( int i=0; i < 3; ++i )
    {
    if( ghost[i*2]==1 )
      {
      // Grow along min of dimension i
      dims[i]   += NG;
      origin[i] -= NG*spacing[i];
      }
    if( ghost[i*2+1]==1 )
      {
      // Grow along max of dimension i
      dims[i] += NG;
      }
    } // END for all dimensions

  // STEP 3: Construt ghosted grid
  vtkUniformGrid *grid = vtkUniformGrid::New();
  grid->Initialize();
  grid->SetOrigin( origin );
  grid->SetSpacing( spacing );
  grid->SetDimensions( dims );

  // STEP 4: Construct field data, i.e., Centroid and Gaussian-Pulse. The
  // data is recomputed here, since we know how to compute it.
  GeneratePulseField(dimension,grid);

  return( grid );
}

//------------------------------------------------------------------------------
vtkOverlappingAMR *GetGhostedDataSet(
    const int dimension, const int NG, vtkOverlappingAMR *inputAMR)
{
  vtkOverlappingAMR *ghostedAMR = vtkOverlappingAMR::New();
  ghostedAMR->SetNumberOfLevels( inputAMR->GetNumberOfLevels() );
  assert( "pre: Expected number of levels is 2" &&
          (ghostedAMR->GetNumberOfLevels()==2));

  // Copy the root grid
  vtkUniformGrid *rootGrid = vtkUniformGrid::New();
  rootGrid->DeepCopy( inputAMR->GetDataSet(0,0) );
  ghostedAMR->SetDataSet(0,0,rootGrid);
  rootGrid->Delete();

  // Knowing the AMR configuration returned by vtkAMRGaussingPulseSource
  // we manually pad ghost-layers to the grids at level 1 (hi-res). How
  // ghost layers are created is encoded to a ghost vector for each grid,
  // {imin,imax,jmin,jmax,kmin,kmax}, where a value of "1" indicates that ghost
  // cells are created in that direction or a "0" to indicate that ghost cells
  // are not created in the given direction.
  int ghost[2][6] = {
      {0,1,0,1,0,0},  // ghost vector for grid (1,0) -- grow at imax,jmax
      {1,0,1,0,0,0}   // ghost vector for grid (1,1) -- grow at imin,jmin
  };

  for( int i=0; i < 2; ++i )
    {
    vtkUniformGrid *grid = inputAMR->GetDataSet(1,i);
    vtkUniformGrid *ghostedGrid = GetGhostedGrid(dimension,grid,ghost[i],NG);
    ghostedAMR->SetDataSet(1,i,ghostedGrid);

#ifdef DEBUG_ON
    std::ostringstream oss;
    oss.clear();
    oss.str("");
    oss << "GHOSTED_GRID_1_" << i;
    WriteUniformGrid( ghostedGrid, oss.str() );
#endif

    ghostedGrid->Delete();
    } // END for all grids

  vtkAMRUtilities::GenerateMetaData(ghostedAMR);
  return( ghostedAMR );
}

//------------------------------------------------------------------------------
vtkOverlappingAMR *GetAMRDataSet(
    const int dimension, const int refinementRatio)
{
  vtkAMRGaussianPulseSource *amrGPSource = vtkAMRGaussianPulseSource::New();
  amrGPSource->SetDimension( dimension );
  amrGPSource->SetRefinementRatio( refinementRatio );
  amrGPSource->Update();
  vtkOverlappingAMR *myAMR = vtkOverlappingAMR::New();
  myAMR->ShallowCopy( amrGPSource->GetOutput() );
  amrGPSource->Delete();
  return( myAMR );
}

//------------------------------------------------------------------------------
int TestAMRGhostLayerStripping(int argc, char *argv[])
{
  // Get rid of compiler warnings on unused vars
  argc = argc; argv = argv;

  int rc   = 0;
  int NDIM = 3;

  int NumberOfRefinmentRatios = 1;
  int rRatios[1] = { 2 };

  int NumberOfGhostTests = 1;
  int ng[ 1 ] = { 1 };

  for( int dim=2; dim <= NDIM; ++dim )
    {
    for( int r=0; r < NumberOfRefinmentRatios; ++r )
      {
      for( int g=0; g < NumberOfGhostTests; ++g )
        {
        std::cout << "====\n";
        std::cout << "Checking AMR data dim=" << dim << " r=" << rRatios[r];
        std::cout << " NG=" << ng[g] << std::endl;
        std::cout.flush();

        // Get the non-ghosted dataset
        vtkOverlappingAMR *amrData = GetAMRDataSet(dim,rRatios[r]);
        assert("pre: amrData should not be NULL!" && (amrData != NULL) );
        if(vtkAMRUtilities::HasPartiallyOverlappingGhostCells(amrData))
          {
          ++rc;
          std::cerr << "ERROR: erroneously detected partially overlapping "
                    << "ghost cells on non-ghosted grid!\n";
          }

        // Get the ghosted dataset
        std::cout << "===\n";
        std::cout << "Checking ghosted data...\n";
        std::cout.flush();

        vtkOverlappingAMR *ghostedAMRData=
            GetGhostedDataSet(dim,ng[g],amrData);
        assert("pre: ghosted AMR data is NULL!" && (ghostedAMRData != NULL) );
        if(!vtkAMRUtilities::HasPartiallyOverlappingGhostCells(ghostedAMRData))
          {
          ++rc;
          std::cerr << "ERROR: failed detection of partially overlapping "
                    << "ghost cells!\n";
          }

        vtkOverlappingAMR *strippedAMRData = vtkOverlappingAMR::New();
        vtkAMRUtilities::StripGhostLayers( ghostedAMRData, strippedAMRData );

        amrData->Delete();
        ghostedAMRData->Delete();
        strippedAMRData->Delete();
        } // END for all ghost tests
      } // END for all refinementRatios to test
    } // END for all dimensions to test

  return rc;
}
<commit_msg>ENH: Test suite for stripping out ghost layers<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    TestAMRGhostLayerStripping.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm 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 notice for more information.

=========================================================================*/
// .NAME TestAMRGhostLayerStripping.cxx -- Test for stripping ghost layers
//
// .SECTION Description
// A simple test for testing the functionality of stripping out ghost layers
// that partially cover lower resolution cells. The test constructs an AMR
// configuration using the vtkAMRGaussianPulseSource which has a known structure.
// Ghost layers are manually added to the hi-res grids and then stripped out.
// Tests cover also configurations with different refinement ratios and
// different numbers of ghost-layers.

// C/C++ includes
#include <cassert>
#include <cmath>
#include <iostream>
#include <sstream>

// VTK includes
#include "vtkAMRBox.h"
#include "vtkAMRGaussianPulseSource.h"
#include "vtkAMRUtilities.h"
#include "vtkCell.h"
#include "vtkCellData.h"
#include "vtkDoubleArray.h"
#include "vtkMathUtilities.h"
#include "vtkOverlappingAMR.h"
#include "vtkUniformGrid.h"
#include "vtkXMLImageDataWriter.h"

//#define DEBUG_ON

//------------------------------------------------------------------------------
void WriteUniformGrid( vtkUniformGrid *g, std::string prefix )
{
  assert( "pre: Uniform grid (g) is NULL!" && (g != NULL) );

  vtkXMLImageDataWriter *imgWriter = vtkXMLImageDataWriter::New();

  std::ostringstream oss;
  oss << prefix << "." << imgWriter->GetDefaultFileExtension();
  imgWriter->SetFileName( oss.str().c_str() );
  imgWriter->SetInputData( g );
  imgWriter->Write();

  imgWriter->Delete();
}

//------------------------------------------------------------------------------
double ComputePulse(
    const int dimension,
    double location[3],
    double pulseOrigin[3],
    double pulseWidth[3],
    double pulseAmplitude)
{
  double pulse = 0.0;

  double r = 0.0;
  for( int i=0; i < dimension; ++i )
    {
    double d = location[i]-pulseOrigin[i];
    double d2 = d*d;
    double L2 = pulseWidth[i]*pulseWidth[i];
    r += d2/L2;
    } // END for all dimensions
  pulse = pulseAmplitude * std::exp( -r );

  return( pulse );
}

//------------------------------------------------------------------------------
void ComputeCellCenter(
    vtkUniformGrid *grid, vtkIdType cellIdx, double centroid[3])
{
  assert("pre: input grid instance is NULL" && (grid != NULL));
  assert("pre: cell index is out-of-bounds!" &&
         (cellIdx >= 0) && (cellIdx < grid->GetNumberOfCells()));

  vtkCell *myCell = grid->GetCell( cellIdx );
  assert( "ERROR: Cell is NULL" && (myCell != NULL) );

  double pcenter[3];
  double *weights = new double[ myCell->GetNumberOfPoints() ];
  int subId = myCell->GetParametricCenter( pcenter );
  myCell->EvaluateLocation( subId, pcenter, centroid, weights );
  delete [] weights;
}

//------------------------------------------------------------------------------
void GeneratePulseField(const int dimension,vtkUniformGrid* grid)
{
  assert("pre: grid is NULL!" && (grid != NULL));
  assert("pre: grid is empty!" && (grid->GetNumberOfCells() >= 1) );

  double pulseOrigin[3];
  double pulseWidth[3];
  double pulseAmplitude;

  vtkAMRGaussianPulseSource *pulseSource = vtkAMRGaussianPulseSource::New();
  pulseSource->GetPulseOrigin( pulseOrigin );
  pulseSource->GetPulseWidth( pulseWidth );
  pulseAmplitude = pulseSource->GetPulseAmplitude();
  pulseSource->Delete();

  vtkDoubleArray *centroidArray = vtkDoubleArray::New();
  centroidArray->SetName("Centroid");
  centroidArray->SetNumberOfComponents( 3 );
  centroidArray->SetNumberOfTuples( grid->GetNumberOfCells() );

  vtkDoubleArray *pulseField = vtkDoubleArray::New();
  pulseField->SetName( "Gaussian-Pulse" );
  pulseField->SetNumberOfComponents( 1 );
  pulseField->SetNumberOfTuples( grid->GetNumberOfCells() );

  double centroid[3];
  vtkIdType cellIdx = 0;
  for(; cellIdx < grid->GetNumberOfCells(); ++cellIdx )
    {
    ComputeCellCenter(grid,cellIdx,centroid);
    centroidArray->SetComponent(cellIdx,0,centroid[0]);
    centroidArray->SetComponent(cellIdx,1,centroid[1]);
    centroidArray->SetComponent(cellIdx,2,centroid[2]);

    double pulse = ComputePulse(
        dimension,centroid,pulseOrigin,pulseWidth,pulseAmplitude);
    pulseField->SetComponent(cellIdx,0,pulse);
    } // END for all cells

  grid->GetCellData()->AddArray( centroidArray );
  centroidArray->Delete();
  grid->GetCellData()->AddArray( pulseField );
  pulseField->Delete();
}

//------------------------------------------------------------------------------
vtkUniformGrid* GetGhostedGrid(
    const int dimension,vtkUniformGrid *refGrid, int ghost[6], const int NG)
{
  assert("pre: NG >= 1" && (NG >= 1) );

  // STEP 0: If the reference grid is NULL just return
  if( refGrid == NULL )
    {
    return NULL;
    }

  // STEP 1: Acquire reference grid origin,spacing, dims
  int dims[3];
  double origin[3];
  double spacing[3];
  refGrid->GetOrigin(origin);
  refGrid->GetSpacing(spacing);
  refGrid->GetDimensions(dims);

  // STEP 2: Adjust origin and dimensions for ghost cells along each dimension
  for( int i=0; i < 3; ++i )
    {
    if( ghost[i*2]==1 )
      {
      // Grow along min of dimension i
      dims[i]   += NG;
      origin[i] -= NG*spacing[i];
      }
    if( ghost[i*2+1]==1 )
      {
      // Grow along max of dimension i
      dims[i] += NG;
      }
    } // END for all dimensions

  // STEP 3: Construt ghosted grid
  vtkUniformGrid *grid = vtkUniformGrid::New();
  grid->Initialize();
  grid->SetOrigin( origin );
  grid->SetSpacing( spacing );
  grid->SetDimensions( dims );

  // STEP 4: Construct field data, i.e., Centroid and Gaussian-Pulse. The
  // data is recomputed here, since we know how to compute it.
  GeneratePulseField(dimension,grid);

  return( grid );
}

//------------------------------------------------------------------------------
vtkOverlappingAMR *GetGhostedDataSet(
    const int dimension, const int NG, vtkOverlappingAMR *inputAMR)
{
  vtkOverlappingAMR *ghostedAMR = vtkOverlappingAMR::New();
  ghostedAMR->SetNumberOfLevels( inputAMR->GetNumberOfLevels() );
  assert( "pre: Expected number of levels is 2" &&
          (ghostedAMR->GetNumberOfLevels()==2));

  // Copy the root grid
  vtkUniformGrid *rootGrid = vtkUniformGrid::New();
  rootGrid->DeepCopy( inputAMR->GetDataSet(0,0) );
  ghostedAMR->SetDataSet(0,0,rootGrid);
  rootGrid->Delete();

  // Knowing the AMR configuration returned by vtkAMRGaussingPulseSource
  // we manually pad ghost-layers to the grids at level 1 (hi-res). How
  // ghost layers are created is encoded to a ghost vector for each grid,
  // {imin,imax,jmin,jmax,kmin,kmax}, where a value of "1" indicates that ghost
  // cells are created in that direction or a "0" to indicate that ghost cells
  // are not created in the given direction.
  int ghost[2][6] = {
      {0,1,0,1,0,0},  // ghost vector for grid (1,0) -- grow at imax,jmax
      {1,0,1,0,0,0}   // ghost vector for grid (1,1) -- grow at imin,jmin
  };

  for( int i=0; i < 2; ++i )
    {
    vtkUniformGrid *grid = inputAMR->GetDataSet(1,i);
    vtkUniformGrid *ghostedGrid = GetGhostedGrid(dimension,grid,ghost[i],NG);
    ghostedAMR->SetDataSet(1,i,ghostedGrid);

#ifdef DEBUG_ON
    std::ostringstream oss;
    oss.clear();
    oss.str("");
    oss << dimension << "D_GHOSTED_GRID_1_" << i;
    WriteUniformGrid( ghostedGrid, oss.str() );
#endif

    ghostedGrid->Delete();
    } // END for all grids

  vtkAMRUtilities::GenerateMetaData(ghostedAMR);
  return( ghostedAMR );
}

//------------------------------------------------------------------------------
vtkOverlappingAMR *GetAMRDataSet(
    const int dimension, const int refinementRatio)
{
  vtkAMRGaussianPulseSource *amrGPSource = vtkAMRGaussianPulseSource::New();
  amrGPSource->SetDimension( dimension );
  amrGPSource->SetRefinementRatio( refinementRatio );
  amrGPSource->Update();
  vtkOverlappingAMR *myAMR = vtkOverlappingAMR::New();
  myAMR->ShallowCopy( amrGPSource->GetOutput() );
  amrGPSource->Delete();
  return( myAMR );
}

//------------------------------------------------------------------------------
void WriteUnGhostedGrids(
    const int dimension, vtkOverlappingAMR *amr)
{
  assert("pre: AMR dataset is NULL!" && (amr != NULL) );

  std::ostringstream oss;
  oss.clear();
  unsigned int levelIdx = 0;
  for(;levelIdx < amr->GetNumberOfLevels(); ++levelIdx )
    {
    unsigned dataIdx = 0;
    for(;dataIdx < amr->GetNumberOfDataSets(levelIdx); ++dataIdx )
      {
      vtkUniformGrid *grid = amr->GetDataSet(levelIdx,dataIdx);
      if( grid != NULL )
        {
        oss.str("");
        oss << dimension << "D_UNGHOSTED_GRID_" << levelIdx << "_" << dataIdx;
        WriteUniformGrid(grid,oss.str());
        }
      } // END for all data-sets
    } // END for all levels
}

//------------------------------------------------------------------------------
bool CheckFields(vtkUniformGrid *grid)
{
  // Since we know exactly what the fields are, i.e., gaussian-pulse and
  // centroid, we manually check the grid for correctness.
  assert("pre: grid is NULL" && (grid != NULL) );
  vtkCellData *CD = grid->GetCellData();
  if( !CD->HasArray("Centroid") || !CD->HasArray("Gaussian-Pulse") )
    {
    return false;
    }

  vtkDoubleArray *centroidArray =
      vtkDoubleArray::SafeDownCast(CD->GetArray("Centroid"));
  assert("pre: centroid arrays is NULL!" && (centroidArray != NULL) );
  if( centroidArray->GetNumberOfComponents() != 3 )
    {
    return false;
    }
  double *centers = static_cast<double*>(centroidArray->GetVoidPointer(0));

  vtkDoubleArray *pulseArray =
      vtkDoubleArray::SafeDownCast(CD->GetArray("Gaussian-Pulse"));
  assert("pre: pulse array is NULL!" && (pulseArray != NULL) );
  if( pulseArray->GetNumberOfComponents() != 1)
    {
    return false;
    }
  double *pulses = static_cast<double*>(pulseArray->GetVoidPointer(0));

  // Get default pulse parameters
  double pulseOrigin[3];
  double pulseWidth[3];
  double pulseAmplitude;

  vtkAMRGaussianPulseSource *pulseSource = vtkAMRGaussianPulseSource::New();
  pulseSource->GetPulseOrigin( pulseOrigin );
  pulseSource->GetPulseWidth( pulseWidth );
  pulseAmplitude = pulseSource->GetPulseAmplitude();
  pulseSource->Delete();

  double centroid[3];
  int dim = grid->GetDataDimension();
  vtkIdType cellIdx = 0;
    for(; cellIdx < grid->GetNumberOfCells(); ++cellIdx)
    {
    ComputeCellCenter(grid,cellIdx,centroid);
    double val = ComputePulse(
        dim,centroid,pulseOrigin,pulseWidth,pulseAmplitude);

    if( !vtkMathUtilities::FuzzyCompare(val,pulses[cellIdx],1e-9) )
      {
      std::cerr << "ERROR: pulse data mismatch!\n";
      std::cerr << "expected=" << val << " computed=" << pulses[cellIdx];
      std::cerr << std::endl;
      return false;
      }
    if( !vtkMathUtilities::FuzzyCompare(centroid[0],centers[cellIdx*3])  ||
        !vtkMathUtilities::FuzzyCompare(centroid[1],centers[cellIdx*3+1]) ||
        !vtkMathUtilities::FuzzyCompare(centroid[2],centers[cellIdx*3+2])  )
      {
      std::cerr << "ERROR: centroid data mismatch!\n";
      return false;
      }
    }// END for all cells
  return true;
}

//------------------------------------------------------------------------------
bool AMRDataSetsAreEqual(
    vtkOverlappingAMR *computed, vtkOverlappingAMR *expected)
{
  assert("pre: computed AMR dataset is NULL" && (computed != NULL) );
  assert("pre: expected AMR dataset is NULL" && (expected != NULL) );

  if( computed == expected )
    {
    return true;
    }

  if( computed->GetNumberOfLevels() != expected->GetNumberOfLevels() )
    {
    return false;
    }

  unsigned int levelIdx = 0;
  for(; levelIdx < computed->GetNumberOfLevels(); ++levelIdx )
    {
    if( computed->GetNumberOfDataSets(levelIdx) !=
         expected->GetNumberOfDataSets(levelIdx))
      {
      return false;
      }

    unsigned int dataIdx = 0;
    for(;dataIdx < computed->GetNumberOfDataSets(levelIdx); ++dataIdx)
      {
      vtkAMRBox computedBox;
      computed->GetMetaData(levelIdx,dataIdx,computedBox);

      vtkAMRBox expectedBox;
      expected->GetMetaData(levelIdx,dataIdx,expectedBox);

      if( !(computedBox == expectedBox) )
        {
        std::cerr << "ERROR: AMR data mismatch!\n";
        return false;
        }

      vtkUniformGrid *computedGrid = computed->GetDataSet(levelIdx,dataIdx);
      vtkUniformGrid *expectedGrid = expected->GetDataSet(levelIdx,dataIdx);

      for( int i=0; i < 3; ++i )
        {
        if(computedGrid->GetDimensions()[i] !=
            expectedGrid->GetDimensions()[i] )
          {
          std::cerr << "ERROR: grid dimensions mismatch!\n";
          return false;
          }
        if( !vtkMathUtilities::FuzzyCompare(
              computedGrid->GetOrigin()[i],
              expectedGrid->GetOrigin()[i]) )
          {
          std::cerr << "ERROR: grid origin mismathc!\n";
          return false;
          }
        }// END for all dimensions

      if(!CheckFields(computedGrid) )
        {
        std::cerr << "ERROR: grid fields were not as expected!\n";
        return false;
        }
      }// END for all data
    } // END for all levels

  return true;
}

//------------------------------------------------------------------------------
int TestGhostStripping(
    const int dimension, const int refinementRatio, const int NG)
{
  int rc = 0;
  std::cout << "====\n";
  std::cout << "Checking AMR data dim=" << dimension
            << " r=" << refinementRatio
            << " NG=" << NG << std::endl;
  std::cout.flush();

  // Get the non-ghosted dataset
  vtkOverlappingAMR *amrData = GetAMRDataSet(dimension,refinementRatio);
  assert("pre: amrData should not be NULL!" && (amrData != NULL) );
  if(vtkAMRUtilities::HasPartiallyOverlappingGhostCells(amrData))
   {
   ++rc;
   std::cerr << "ERROR: erroneously detected partially overlapping "
             << "ghost cells on non-ghosted grid!\n";
   }

  // Get the ghosted dataset
  vtkOverlappingAMR *ghostedAMRData=GetGhostedDataSet(dimension,NG,amrData);
  assert("pre: ghosted AMR data is NULL!" && (ghostedAMRData != NULL) );

  if( NG == refinementRatio  )
    {
    // There are no partially overlapping ghost cells
    if(vtkAMRUtilities::HasPartiallyOverlappingGhostCells(
        ghostedAMRData))
      {
      ++rc;
      std::cerr << "ERROR: detected partially overlapping "
                << "ghost cells when there shouldn't be any!\n";
      }
    }
  else
    {
    if(!vtkAMRUtilities::HasPartiallyOverlappingGhostCells(
       ghostedAMRData))
      {
      ++rc;
      std::cerr << "ERROR: failed detection of partially overlapping "
                << "ghost cells!\n";
      }
    }

  vtkOverlappingAMR *strippedAMRData = vtkOverlappingAMR::New();
  vtkAMRUtilities::StripGhostLayers( ghostedAMRData, strippedAMRData );
#ifdef DEBUG_ON
  WriteUnGhostedGrids(dimension,strippedAMRData);
#endif

  // The strippedAMRData is expected to be exactly the same as the initial
  // unghosted AMR dataset
  if(!AMRDataSetsAreEqual(strippedAMRData,amrData) )
    {
    ++rc;
    std::cerr << "ERROR: AMR data did not match expected data!\n";
    }

  amrData->Delete();
  ghostedAMRData->Delete();
  strippedAMRData->Delete();
  return( rc );
}
//------------------------------------------------------------------------------
int TestAMRGhostLayerStripping(int argc, char *argv[])
{
  // Get rid of compiler warnings on unused vars
  argc = argc; argv = argv;

  int rc   = 0;
  int DIM0 = 2;
  int NDIM = 3;

  int NumberOfRefinmentRatios = 3;
  int rRatios[3] = { 2,3,4 };

  for( int dim=DIM0; dim <= NDIM; ++dim )
    {
    for( int r=0; r < NumberOfRefinmentRatios; ++r )
      {
      for( int ng=1; ng <= rRatios[r]; ++ng )
        {
        rc += TestGhostStripping(dim,rRatios[r],ng);
        } // END for all ghost-layer tests
      } // END for all refinementRatios to test
    } // END for all dimensions to test

  return rc;
}
<|endoftext|>


<commit_before>
// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "CameraControllable.h"
#include "EC_NetworkPosition.h"
#include "SceneEvents.h"
#include "Entity.h"
#include "SceneManager.h"
#include "EC_OgrePlaceable.h"
#include "Renderer.h"
#include "EC_OgrePlaceable.h"
#include "EC_OgreMesh.h"
#include "EC_AvatarAppearance.h"
//#include "RexTypes.h"
#include "InputEvents.h"
#include "InputServiceInterface.h"
#include <Ogre.h>

namespace RexLogic
{
    CameraControllable::CameraControllable(Foundation::Framework *fw) :
        framework_(fw)
      , action_event_category_(fw->GetEventManager()->QueryEventCategory("Action"))
      , current_state_(ThirdPerson)
      , firstperson_pitch_(0)
      , firstperson_yaw_(0)
      , drag_pitch_(0)
      , drag_yaw_(0)
    {
        camera_distance_ = framework_->GetDefaultConfig().DeclareSetting("Camera", "default_distance", 20.f);
        camera_min_distance_ = framework_->GetDefaultConfig().DeclareSetting("Camera", "min_distance", 1.f);
        camera_max_distance_ = framework_->GetDefaultConfig().DeclareSetting("Camera", "max_distance", 50.f);

        camera_offset_ = Core::ParseString<Core::Vector3df>(
            framework_->GetDefaultConfig().DeclareSetting("Camera", "third_person_offset", Core::ToString(Core::Vector3df(0, 0, 1.8f))));

        camera_offset_firstperson_ = Core::ParseString<Core::Vector3df>(
            framework_->GetDefaultConfig().DeclareSetting("Camera", "first_person_offset", Core::ToString(Core::Vector3df(0.5f, 0, 0.8f))));

        sensitivity_ = framework_->GetDefaultConfig().DeclareSetting("Camera", "translation_sensitivity", 25.f);
        zoom_sensitivity_ = framework_->GetDefaultConfig().DeclareSetting("Camera", "zoom_sensitivity", 0.015f);
        firstperson_sensitivity_ = framework_->GetDefaultConfig().DeclareSetting("Camera", "mouselook_rotation_sensitivity", 1.3f);

        action_trans_[RexTypes::Actions::MoveForward] = Core::Vector3df::NEGATIVE_UNIT_Z;
        action_trans_[RexTypes::Actions::MoveBackward] = Core::Vector3df::UNIT_Z;
        action_trans_[RexTypes::Actions::MoveLeft] = Core::Vector3df::NEGATIVE_UNIT_X;
        action_trans_[RexTypes::Actions::MoveRight] = Core::Vector3df::UNIT_X;
        action_trans_[RexTypes::Actions::MoveUp] = Core::Vector3df::UNIT_Y;
        action_trans_[RexTypes::Actions::MoveDown] = Core::Vector3df::NEGATIVE_UNIT_Y;
    }

    bool CameraControllable::HandleSceneEvent(Core::event_id_t event_id, Foundation::EventDataInterface* data)
    {
        //! \todo This is where our user agent model design breaks down. We assume only one controllable entity exists and that it is a target for the camera.
        //!       Should be changed so in some way the target can be changed and is not automatically assigned. -cm
        if (event_id == Scene::Events::EVENT_CONTROLLABLE_ENTITY)
            target_entity_ = checked_static_cast<Scene::Events::EntityEventData*>(data)->entity;

        return false;
    }

    bool CameraControllable::HandleInputEvent(Core::event_id_t event_id, Foundation::EventDataInterface* data)
    {
        if (event_id == Input::Events::INPUTSTATE_THIRDPERSON && current_state_ != ThirdPerson)
        {
            current_state_ = ThirdPerson;
            firstperson_pitch_ = 0.0f;
        }

        if (event_id == Input::Events::INPUTSTATE_FIRSTPERSON && current_state_ != FirstPerson)
        {
            current_state_ = FirstPerson;
            firstperson_pitch_ = 0.0f;
        }

        if (event_id == Input::Events::INPUTSTATE_FREECAMERA && current_state_ != FreeLook)
        {
            current_state_ = FreeLook;
            firstperson_pitch_ = 0.0f;
        }

        if (event_id == Input::Events::SCROLL)
        {
            CameraZoomEvent event_data;
            //event_data.entity = entity_.lock(); // no entity for camera, :( -cm
            event_data.amount = checked_static_cast<Input::Events::SingleAxisMovement*>(data)->z_.rel_;
            //if (event_data.entity) // only send the event if we have an existing entity, no point otherwise
            framework_->GetEventManager()->SendEvent(action_event_category_, RexTypes::Actions::Zoom, &event_data);
        }

        return false;
    }

    bool CameraControllable::HandleActionEvent(Core::event_id_t event_id, Foundation::EventDataInterface* data)
    {
        if (event_id == RexTypes::Actions::Zoom)
        {
            Core::Real value = checked_static_cast<CameraZoomEvent*>(data)->amount;

            camera_distance_ -= (value * zoom_sensitivity_);
            camera_distance_ = Core::clamp(camera_distance_, camera_min_distance_, camera_max_distance_);
        }

        if (current_state_ == FreeLook)
        {
            ActionTransMap::const_iterator it = action_trans_.find(event_id);
            if (it != action_trans_.end())
            {
                // start movement
                const Core::Vector3df &vec = it->second;
                free_translation_.x = ( vec.x == 0 ) ? free_translation_.x : vec.x;
                free_translation_.y = ( vec.y == 0 ) ? free_translation_.y : vec.y;
                free_translation_.z = ( vec.z == 0 ) ? free_translation_.z : vec.z;
            }
            it = action_trans_.find(event_id - 1);
            if (it != action_trans_.end())
            {
                // stop movement
                const Core::Vector3df &vec = it->second;
                free_translation_.x = ( vec.x == 0 ) ? free_translation_.x : 0;
                free_translation_.y = ( vec.y == 0 ) ? free_translation_.y : 0;
                free_translation_.z = ( vec.z == 0 ) ? free_translation_.z : 0;
            }
            normalized_free_translation_ = free_translation_;
            normalized_free_translation_.normalize();
        }

        return false;
    }

    void CameraControllable::AddTime(Core::f64 frametime)
    {
        boost::shared_ptr<Input::InputServiceInterface> input = framework_->GetService<Input::InputServiceInterface>(Foundation::Service::ST_Input).lock();
        if (input)
        {
            boost::optional<const Input::Events::Movement&> movement = input->PollSlider(Input::Events::MOUSELOOK);
            if (movement)
            {
                drag_yaw_ = static_cast<Core::Real>(movement->x_.rel_) * -0.005f;
                drag_pitch_ = static_cast<Core::Real>(movement->y_.rel_) * -0.005f;
            } else if (drag_pitch_ != 0 || drag_yaw_ != 0)
            {
                drag_yaw_ = 0;
                drag_pitch_ = 0;
            }
        }

        boost::shared_ptr<OgreRenderer::Renderer> renderer = framework_->GetServiceManager()->GetService<OgreRenderer::Renderer>(Foundation::Service::ST_Renderer).lock();
        Scene::EntityPtr target = target_entity_.lock();

        if (renderer && target)
        {
            Ogre::Camera *camera = renderer->GetCurrentCamera();

            // for smoothness, we apparently need to get rotation from network position and position from placeable. Go figure. -cm
            EC_NetworkPosition *netpos = checked_static_cast<EC_NetworkPosition*>(target->GetComponent(EC_NetworkPosition::NameStatic()).get());
            OgreRenderer::EC_OgrePlaceable *placeable =
                checked_static_cast<OgreRenderer::EC_OgrePlaceable*>(target->GetComponent(OgreRenderer::EC_OgrePlaceable::NameStatic()).get());
            if (netpos && placeable)
            {
                Core::Vector3df avatar_pos = placeable->GetPosition();
                Core::Quaternion avatar_orientation = netpos->rotation_;

                if (current_state_ == FirstPerson || current_state_ == ThirdPerson)
                {
                    // this is mostly for third person camera, but also needed by first person camera since it sets proper initial orientation for the camera
                    Core::Vector3df pos = avatar_pos;
                    pos += (avatar_orientation * Core::Vector3df::NEGATIVE_UNIT_X * camera_distance_);
                    pos += (avatar_orientation * camera_offset_);
                    camera->setPosition(pos.x, pos.y, pos.z);

                    Core::Vector3df lookat = avatar_pos + avatar_orientation * camera_offset_;
                    camera->lookAt(lookat.x, lookat.y, lookat.z);
                }

                if (current_state_ == FirstPerson)
                {
                    bool fallback = true;
                    // Try to use head bone from target entity to get the first person camera position
                    Foundation::ComponentPtr mesh_ptr = target->GetComponent(OgreRenderer::EC_OgreMesh::NameStatic());
                    Foundation::ComponentPtr appearance_ptr = target->GetComponent(EC_AvatarAppearance::NameStatic());
                    if (mesh_ptr && appearance_ptr)
                    {
                        OgreRenderer::EC_OgreMesh& mesh = *checked_static_cast<OgreRenderer::EC_OgreMesh*>(mesh_ptr.get());
                        EC_AvatarAppearance& appearance = *checked_static_cast<EC_AvatarAppearance*>(appearance_ptr.get());
                        Ogre::Entity* ent = mesh.GetEntity();
                        if (ent)
                        {
                            Ogre::SkeletonInstance* skel = ent->getSkeleton();
                            if (skel && skel->hasBone(appearance.GetProperty("headbone")))
                            {
                                // Hack: force Ogre to update skeleton with current animation state, even if avatar invisible
                                if (ent->getAllAnimationStates())
                                    skel->setAnimationState(*ent->getAllAnimationStates());

                                Ogre::Bone* bone = skel->getBone(appearance.GetProperty("headbone"));
                                Ogre::Vector3 headpos = bone->_getDerivedPosition();
                                Core::Real adjustheight = mesh.GetAdjustPosition().z + 0.15;
                                Core::Vector3df ourheadpos(-headpos.z + 0.5f, -headpos.x, headpos.y + adjustheight);
                                RexTypes::Vector3 campos = avatar_pos + (avatar_orientation * ourheadpos);
                                camera->setPosition(campos.x, campos.y, campos.z);
                                fallback = false;
                            }
                        }
                    }
                    // Fallback using fixed position
                    if (fallback)
                    {
                        RexTypes::Vector3 campos = avatar_pos + (avatar_orientation * camera_offset_firstperson_);
                        camera->setPosition(campos.x, campos.y, campos.z);
                    }

                    // update camera pitch
                    if (drag_pitch_ != 0)
                    {
                        firstperson_pitch_ += drag_pitch_ * firstperson_sensitivity_;
                        firstperson_pitch_ = Core::clamp(firstperson_pitch_, -Core::HALF_PI, Core::HALF_PI);
                    }
                    camera->pitch(Ogre::Radian(firstperson_pitch_));
                }

                if (current_state_ == FreeLook)
                {
                    const float trans_dt = (float)frametime * sensitivity_;

                    Ogre::Vector3 pos = camera->getPosition();
                    pos += camera->getOrientation() * Ogre::Vector3(normalized_free_translation_.x, normalized_free_translation_.y, normalized_free_translation_.z) * trans_dt;
                    camera->setPosition(pos);

                    camera->pitch(Ogre::Radian(drag_pitch_ * firstperson_sensitivity_));
                    camera->yaw(Ogre::Radian(drag_yaw_ * firstperson_sensitivity_));
                }
            }
        }

        // switch between first and third person modes, depending on how close we are to the avatar
        switch (current_state_)
        {
        case FirstPerson:
            {
                if (camera_distance_ != camera_min_distance_)
                {
                    current_state_ = ThirdPerson;
                    Core::event_category_id_t event_category = framework_->GetEventManager()->QueryEventCategory("Input");
                    framework_->GetEventManager()->SendEvent(event_category, Input::Events::INPUTSTATE_THIRDPERSON, NULL);

                    firstperson_pitch_ = 0.0f;
                }
                break;
            }
        case ThirdPerson:
            {
                if (camera_distance_ == camera_min_distance_)
                {
                    Core::event_category_id_t event_category = framework_->GetEventManager()->QueryEventCategory("Input");
                    framework_->GetEventManager()->SendEvent(event_category, Input::Events::INPUTSTATE_FIRSTPERSON, NULL);
                    current_state_ = FirstPerson;

                    firstperson_pitch_ = 0.0f;
                }
                break;
            }
		}
    }

	//experimental for py api
	void CameraControllable::SetYawPitch(Core::Real newyaw, Core::Real newpitch)
	{
		boost::shared_ptr<OgreRenderer::Renderer> renderer = framework_->GetServiceManager()->GetService<OgreRenderer::Renderer>(Foundation::Service::ST_Renderer).lock();
		Ogre::Camera *camera = renderer->GetCurrentCamera();

		firstperson_yaw_ = newyaw;
		firstperson_pitch_ = newpitch;
		camera->yaw(Ogre::Radian(firstperson_yaw_));
		camera->pitch(Ogre::Radian(firstperson_pitch_));
	}
	/*
	Core::Vector3df CameraControllable::GetCameraUp(){
		boost::shared_ptr<OgreRenderer::Renderer> renderer = framework_->GetServiceManager()->GetService<OgreRenderer::Renderer>(Foundation::Service::ST_Renderer).lock();
		Ogre::Camera *camera = renderer->GetCurrentCamera();
		Ogre::Vector3 up = camera->getUp();
		return Core::Vector3df(up.x, up.y, up.z);
	}

	Core::Vector3df CameraControllable::GetCameraRight(){
		boost::shared_ptr<OgreRenderer::Renderer> renderer = framework_->GetServiceManager()->GetService<OgreRenderer::Renderer>(Foundation::Service::ST_Renderer).lock();
		Ogre::Camera *camera = renderer->GetCurrentCamera();
		Ogre::Vector3 right = camera->getRight();
		return Core::Vector3df(right.x, right.y, right.z);
	}
	*/
}

<commit_msg>Added optional "viewbone" property which will be used for 1st person view tracking instead of "headbone", without need for hardcoded offset. (headbone usually points at neck of avatar skeleton)<commit_after>
// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "CameraControllable.h"
#include "EC_NetworkPosition.h"
#include "SceneEvents.h"
#include "Entity.h"
#include "SceneManager.h"
#include "EC_OgrePlaceable.h"
#include "Renderer.h"
#include "EC_OgrePlaceable.h"
#include "EC_OgreMesh.h"
#include "EC_AvatarAppearance.h"
//#include "RexTypes.h"
#include "InputEvents.h"
#include "InputServiceInterface.h"
#include <Ogre.h>

namespace RexLogic
{
    CameraControllable::CameraControllable(Foundation::Framework *fw) :
        framework_(fw)
      , action_event_category_(fw->GetEventManager()->QueryEventCategory("Action"))
      , current_state_(ThirdPerson)
      , firstperson_pitch_(0)
      , firstperson_yaw_(0)
      , drag_pitch_(0)
      , drag_yaw_(0)
    {
        camera_distance_ = framework_->GetDefaultConfig().DeclareSetting("Camera", "default_distance", 20.f);
        camera_min_distance_ = framework_->GetDefaultConfig().DeclareSetting("Camera", "min_distance", 1.f);
        camera_max_distance_ = framework_->GetDefaultConfig().DeclareSetting("Camera", "max_distance", 50.f);

        camera_offset_ = Core::ParseString<Core::Vector3df>(
            framework_->GetDefaultConfig().DeclareSetting("Camera", "third_person_offset", Core::ToString(Core::Vector3df(0, 0, 1.8f))));

        camera_offset_firstperson_ = Core::ParseString<Core::Vector3df>(
            framework_->GetDefaultConfig().DeclareSetting("Camera", "first_person_offset", Core::ToString(Core::Vector3df(0.5f, 0, 0.8f))));

        sensitivity_ = framework_->GetDefaultConfig().DeclareSetting("Camera", "translation_sensitivity", 25.f);
        zoom_sensitivity_ = framework_->GetDefaultConfig().DeclareSetting("Camera", "zoom_sensitivity", 0.015f);
        firstperson_sensitivity_ = framework_->GetDefaultConfig().DeclareSetting("Camera", "mouselook_rotation_sensitivity", 1.3f);

        action_trans_[RexTypes::Actions::MoveForward] = Core::Vector3df::NEGATIVE_UNIT_Z;
        action_trans_[RexTypes::Actions::MoveBackward] = Core::Vector3df::UNIT_Z;
        action_trans_[RexTypes::Actions::MoveLeft] = Core::Vector3df::NEGATIVE_UNIT_X;
        action_trans_[RexTypes::Actions::MoveRight] = Core::Vector3df::UNIT_X;
        action_trans_[RexTypes::Actions::MoveUp] = Core::Vector3df::UNIT_Y;
        action_trans_[RexTypes::Actions::MoveDown] = Core::Vector3df::NEGATIVE_UNIT_Y;
    }

    bool CameraControllable::HandleSceneEvent(Core::event_id_t event_id, Foundation::EventDataInterface* data)
    {
        //! \todo This is where our user agent model design breaks down. We assume only one controllable entity exists and that it is a target for the camera.
        //!       Should be changed so in some way the target can be changed and is not automatically assigned. -cm
        if (event_id == Scene::Events::EVENT_CONTROLLABLE_ENTITY)
            target_entity_ = checked_static_cast<Scene::Events::EntityEventData*>(data)->entity;

        return false;
    }

    bool CameraControllable::HandleInputEvent(Core::event_id_t event_id, Foundation::EventDataInterface* data)
    {
        if (event_id == Input::Events::INPUTSTATE_THIRDPERSON && current_state_ != ThirdPerson)
        {
            current_state_ = ThirdPerson;
            firstperson_pitch_ = 0.0f;
        }

        if (event_id == Input::Events::INPUTSTATE_FIRSTPERSON && current_state_ != FirstPerson)
        {
            current_state_ = FirstPerson;
            firstperson_pitch_ = 0.0f;
        }

        if (event_id == Input::Events::INPUTSTATE_FREECAMERA && current_state_ != FreeLook)
        {
            current_state_ = FreeLook;
            firstperson_pitch_ = 0.0f;
        }

        if (event_id == Input::Events::SCROLL)
        {
            CameraZoomEvent event_data;
            //event_data.entity = entity_.lock(); // no entity for camera, :( -cm
            event_data.amount = checked_static_cast<Input::Events::SingleAxisMovement*>(data)->z_.rel_;
            //if (event_data.entity) // only send the event if we have an existing entity, no point otherwise
            framework_->GetEventManager()->SendEvent(action_event_category_, RexTypes::Actions::Zoom, &event_data);
        }

        return false;
    }

    bool CameraControllable::HandleActionEvent(Core::event_id_t event_id, Foundation::EventDataInterface* data)
    {
        if (event_id == RexTypes::Actions::Zoom)
        {
            Core::Real value = checked_static_cast<CameraZoomEvent*>(data)->amount;

            camera_distance_ -= (value * zoom_sensitivity_);
            camera_distance_ = Core::clamp(camera_distance_, camera_min_distance_, camera_max_distance_);
        }

        if (current_state_ == FreeLook)
        {
            ActionTransMap::const_iterator it = action_trans_.find(event_id);
            if (it != action_trans_.end())
            {
                // start movement
                const Core::Vector3df &vec = it->second;
                free_translation_.x = ( vec.x == 0 ) ? free_translation_.x : vec.x;
                free_translation_.y = ( vec.y == 0 ) ? free_translation_.y : vec.y;
                free_translation_.z = ( vec.z == 0 ) ? free_translation_.z : vec.z;
            }
            it = action_trans_.find(event_id - 1);
            if (it != action_trans_.end())
            {
                // stop movement
                const Core::Vector3df &vec = it->second;
                free_translation_.x = ( vec.x == 0 ) ? free_translation_.x : 0;
                free_translation_.y = ( vec.y == 0 ) ? free_translation_.y : 0;
                free_translation_.z = ( vec.z == 0 ) ? free_translation_.z : 0;
            }
            normalized_free_translation_ = free_translation_;
            normalized_free_translation_.normalize();
        }

        return false;
    }

    void CameraControllable::AddTime(Core::f64 frametime)
    {
        boost::shared_ptr<Input::InputServiceInterface> input = framework_->GetService<Input::InputServiceInterface>(Foundation::Service::ST_Input).lock();
        if (input)
        {
            boost::optional<const Input::Events::Movement&> movement = input->PollSlider(Input::Events::MOUSELOOK);
            if (movement)
            {
                drag_yaw_ = static_cast<Core::Real>(movement->x_.rel_) * -0.005f;
                drag_pitch_ = static_cast<Core::Real>(movement->y_.rel_) * -0.005f;
            } else if (drag_pitch_ != 0 || drag_yaw_ != 0)
            {
                drag_yaw_ = 0;
                drag_pitch_ = 0;
            }
        }

        boost::shared_ptr<OgreRenderer::Renderer> renderer = framework_->GetServiceManager()->GetService<OgreRenderer::Renderer>(Foundation::Service::ST_Renderer).lock();
        Scene::EntityPtr target = target_entity_.lock();

        if (renderer && target)
        {
            Ogre::Camera *camera = renderer->GetCurrentCamera();

            // for smoothness, we apparently need to get rotation from network position and position from placeable. Go figure. -cm
            EC_NetworkPosition *netpos = checked_static_cast<EC_NetworkPosition*>(target->GetComponent(EC_NetworkPosition::NameStatic()).get());
            OgreRenderer::EC_OgrePlaceable *placeable =
                checked_static_cast<OgreRenderer::EC_OgrePlaceable*>(target->GetComponent(OgreRenderer::EC_OgrePlaceable::NameStatic()).get());
            if (netpos && placeable)
            {
                Core::Vector3df avatar_pos = placeable->GetPosition();
                Core::Quaternion avatar_orientation = netpos->rotation_;

                if (current_state_ == FirstPerson || current_state_ == ThirdPerson)
                {
                    // this is mostly for third person camera, but also needed by first person camera since it sets proper initial orientation for the camera
                    Core::Vector3df pos = avatar_pos;
                    pos += (avatar_orientation * Core::Vector3df::NEGATIVE_UNIT_X * camera_distance_);
                    pos += (avatar_orientation * camera_offset_);
                    camera->setPosition(pos.x, pos.y, pos.z);

                    Core::Vector3df lookat = avatar_pos + avatar_orientation * camera_offset_;
                    camera->lookAt(lookat.x, lookat.y, lookat.z);
                }

                if (current_state_ == FirstPerson)
                {
                    bool fallback = true;
                    // Try to use head bone from target entity to get the first person camera position
                    Foundation::ComponentPtr mesh_ptr = target->GetComponent(OgreRenderer::EC_OgreMesh::NameStatic());
                    Foundation::ComponentPtr appearance_ptr = target->GetComponent(EC_AvatarAppearance::NameStatic());
                    if (mesh_ptr && appearance_ptr)
                    {
                        OgreRenderer::EC_OgreMesh& mesh = *checked_static_cast<OgreRenderer::EC_OgreMesh*>(mesh_ptr.get());
                        EC_AvatarAppearance& appearance = *checked_static_cast<EC_AvatarAppearance*>(appearance_ptr.get());
                        Ogre::Entity* ent = mesh.GetEntity();
                        if (ent)
                        {
                            Ogre::SkeletonInstance* skel = ent->getSkeleton();

                            std::string view_bone_name;
                            Core::Real adjustheight = mesh.GetAdjustPosition().z;

                            if (appearance.HasProperty("viewbone"))
                            {
                                // This bone property is exclusively for view tracking & assumed to be correct position, no offset
                                view_bone_name = appearance.GetProperty("viewbone");
                            }
                            else if (appearance.HasProperty("headbone"))
                            {
                                view_bone_name = appearance.GetProperty("headbone");
                                // The biped head bone is anchored at the neck usually. Therefore a guessed fixed offset is needed,
                                // which is not preferable, but necessary
                                adjustheight += 0.15;
                            }

                            if (!view_bone_name.empty())
                            {
                                if (skel && skel->hasBone(view_bone_name))
                                {
                                    // Hack: force Ogre to update skeleton with current animation state, even if avatar invisible
                                    if (ent->getAllAnimationStates())
                                        skel->setAnimationState(*ent->getAllAnimationStates());

                                    Ogre::Bone* bone = skel->getBone(view_bone_name);
                                    Ogre::Vector3 headpos = bone->_getDerivedPosition();
                                    Core::Vector3df ourheadpos(-headpos.z + 0.5f, -headpos.x, headpos.y + adjustheight);
                                    RexTypes::Vector3 campos = avatar_pos + (avatar_orientation * ourheadpos);
                                    camera->setPosition(campos.x, campos.y, campos.z);
                                    fallback = false;
                                }
                            }
                        }
                    }
                    // Fallback using fixed position
                    if (fallback)
                    {
                        RexTypes::Vector3 campos = avatar_pos + (avatar_orientation * camera_offset_firstperson_);
                        camera->setPosition(campos.x, campos.y, campos.z);
                    }

                    // update camera pitch
                    if (drag_pitch_ != 0)
                    {
                        firstperson_pitch_ += drag_pitch_ * firstperson_sensitivity_;
                        firstperson_pitch_ = Core::clamp(firstperson_pitch_, -Core::HALF_PI, Core::HALF_PI);
                    }
                    camera->pitch(Ogre::Radian(firstperson_pitch_));
                }

                if (current_state_ == FreeLook)
                {
                    const float trans_dt = (float)frametime * sensitivity_;

                    Ogre::Vector3 pos = camera->getPosition();
                    pos += camera->getOrientation() * Ogre::Vector3(normalized_free_translation_.x, normalized_free_translation_.y, normalized_free_translation_.z) * trans_dt;
                    camera->setPosition(pos);

                    camera->pitch(Ogre::Radian(drag_pitch_ * firstperson_sensitivity_));
                    camera->yaw(Ogre::Radian(drag_yaw_ * firstperson_sensitivity_));
                }
            }
        }

        // switch between first and third person modes, depending on how close we are to the avatar
        switch (current_state_)
        {
        case FirstPerson:
            {
                if (camera_distance_ != camera_min_distance_)
                {
                    current_state_ = ThirdPerson;
                    Core::event_category_id_t event_category = framework_->GetEventManager()->QueryEventCategory("Input");
                    framework_->GetEventManager()->SendEvent(event_category, Input::Events::INPUTSTATE_THIRDPERSON, NULL);

                    firstperson_pitch_ = 0.0f;
                }
                break;
            }
        case ThirdPerson:
            {
                if (camera_distance_ == camera_min_distance_)
                {
                    Core::event_category_id_t event_category = framework_->GetEventManager()->QueryEventCategory("Input");
                    framework_->GetEventManager()->SendEvent(event_category, Input::Events::INPUTSTATE_FIRSTPERSON, NULL);
                    current_state_ = FirstPerson;

                    firstperson_pitch_ = 0.0f;
                }
                break;
            }
		}
    }

	//experimental for py api
	void CameraControllable::SetYawPitch(Core::Real newyaw, Core::Real newpitch)
	{
		boost::shared_ptr<OgreRenderer::Renderer> renderer = framework_->GetServiceManager()->GetService<OgreRenderer::Renderer>(Foundation::Service::ST_Renderer).lock();
		Ogre::Camera *camera = renderer->GetCurrentCamera();

		firstperson_yaw_ = newyaw;
		firstperson_pitch_ = newpitch;
		camera->yaw(Ogre::Radian(firstperson_yaw_));
		camera->pitch(Ogre::Radian(firstperson_pitch_));
	}
	/*
	Core::Vector3df CameraControllable::GetCameraUp(){
		boost::shared_ptr<OgreRenderer::Renderer> renderer = framework_->GetServiceManager()->GetService<OgreRenderer::Renderer>(Foundation::Service::ST_Renderer).lock();
		Ogre::Camera *camera = renderer->GetCurrentCamera();
		Ogre::Vector3 up = camera->getUp();
		return Core::Vector3df(up.x, up.y, up.z);
	}

	Core::Vector3df CameraControllable::GetCameraRight(){
		boost::shared_ptr<OgreRenderer::Renderer> renderer = framework_->GetServiceManager()->GetService<OgreRenderer::Renderer>(Foundation::Service::ST_Renderer).lock();
		Ogre::Camera *camera = renderer->GetCurrentCamera();
		Ogre::Vector3 right = camera->getRight();
		return Core::Vector3df(right.x, right.y, right.z);
	}
	*/
}

<|endoftext|>


<commit_before>#include "image_writer.h"
#include "heatmap_writer.h"
#include "json_writer.h"
#include "logger.h"
#include "parser.h"
#include "regex.h"

#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <boost/program_options.hpp>
#include <fstream>

#include <float.h>

using namespace wotreplay;
using namespace boost::filesystem;
namespace po = boost::program_options;

void show_help(int argc, const char *argv[], po::options_description &desc) {
    std::stringstream help_message;
    help_message << desc << "\n";
    logger.write(help_message.str());
}

float distance(const std::tuple<float, float, float> &left, const std::tuple<float, float, float> &right) {
    float delta_x = std::get<0>(left) - std::get<0>(right);
    float delta_y = std::get<1>(left) - std::get<1>(right);
    float delta_z = std::get<2>(left) - std::get<2>(right);
    // distance in xy plane
    float dist1 = std::sqrt(delta_x*delta_x + delta_y*delta_y);
    return std::sqrt(dist1*dist1 + delta_z*delta_z);
}

static bool is_not_empty(const packet_t &packet) {
    // list of default properties with no special meaning
    std::set<property_t> standard_properties = { property_t::clock, property_t::player_id, property_t::type, property_t::sub_type };
    auto properties = packet.get_properties();
    for (int i = 0; i < properties.size(); ++i) {
        property_t property = static_cast<property_t>(i);
        // packet has property, but can not be found in default properties
        if (properties[i] &&
            standard_properties.find(property) == standard_properties.end()) {
            return true;
        }
    }
    return false;
}

int create_minimaps(const po::variables_map &vm, const std::string &output, bool debug) {
    if ( vm.count("output") == 0 ) {
        logger.write(wotreplay::log_level_t::error, "parameter output is required to use this mode");
        return -EXIT_FAILURE;
    }

    boost::format file_name_format("%1%/%2%_%3%_%4%.png");

    image_writer_t writer;
    for (const auto &arena_entry : get_arenas()) {
        const arena_t &arena = arena_entry.second;
        for (const auto &configuration_entry : arena.configurations) {
            for (int team_id : { 0, 1 }) {
                const std::string game_mode = configuration_entry.first;
                writer.init(arena, game_mode);
                writer.set_recorder_team(team_id);
                writer.set_use_fixed_teamcolors(false);
                std::string file_name = (file_name_format % output % arena.name % game_mode % team_id).str();
                std::ofstream os(file_name, std::ios::binary);
                writer.finish();
                writer.write(os);
            }
        }
    }

    return EXIT_SUCCESS;
}

std::unique_ptr<writer_t> create_writer(const std::string &type, const po::variables_map &vm) {
    std::unique_ptr<writer_t> writer;

    if (type == "png") {
        writer = std::unique_ptr<writer_t>(new image_writer_t());
        auto &image_writer = dynamic_cast<image_writer_t&>(*writer);
        image_writer.set_show_self(true);
        image_writer.set_use_fixed_teamcolors(false);
    } else if (type == "json") {
        writer = std::unique_ptr<writer_t>(new json_writer_t());
        if (vm.count("supress-empty")) {
            writer->set_filter(&is_not_empty);
        }
    } else if (type == "heatmap") {
        writer = std::unique_ptr<writer_t>(new heatmap_writer_t());
        auto &heatmap_writer = dynamic_cast<heatmap_writer_t&>(*writer);
        if (vm.count("skip")) {
            heatmap_writer.skip = vm["skip"].as<double>();
        }
        if (vm.count("bounds_min") && vm.count("bounds_max")) {
            heatmap_writer.bounds = std::make_pair(vm["bounds_min"].as<double>(),
                                                   vm["bounds_max"].as<double>());
        }
    } else {
        logger.writef(log_level_t::error, "Invalid output type (%1%), supported types: png, json and heatmap.\n", type);
    }

    return writer;
}

int process_replay_directory(const po::variables_map &vm, const std::string &input, const std::string &output, const std::string &type, bool debug) {
    if ( !(vm.count("type") > 0 && vm.count("input") > 0) ) {
        logger.write(wotreplay::log_level_t::error, "parameters type and input are required to use this mode\n");
        return -EXIT_FAILURE;
    }

    parser_t parser;
    parser.set_debug(debug);
    parser.load_data();

    std::map<std::string, std::unique_ptr<writer_t>> writers;
    for (auto it = directory_iterator(input); it != directory_iterator(); ++it) {
        if (!is_regular_file(*it) || it->path().extension() != ".wotreplay") {
            continue;
        }

        std::ifstream in(it->path().string(), std::ios::binary);
        if (!in) {
            logger.writef(log_level_t::error, "Failed to open file: %1%\n", it->path().string());
            return -EXIT_FAILURE;
        }

        game_t game;

        try {
            parser.parse(in, game);
        } catch (std::exception &e) {
            logger.writef(log_level_t::error, "Failed to parse file (%1%): %2%\n", it->path().string(), e.what());
            continue;
        }

        // if we can't load arena data, skip this replay
        if (game.get_arena().name.empty()) {
            continue;
        }

        std::string name = (boost::format("%s_%s") % game.get_map_name() % game.get_game_mode()).str();
        auto writer = writers.find(name);

        if (writer == writers.end()) {
            auto new_writer = create_writer(type, vm);
            auto result = writers.insert(std::make_pair(name, std::move(new_writer)));
            writer = result.first;
            (writer->second)->init(game.get_arena(), game.get_game_mode());
        }

        (writer->second)->update(game);
    }

    for (auto it = writers.begin(); it != writers.end(); ++it) {
        path file_name = path(output) / (boost::format("%s.png") % it->first).str();
        std::ofstream out(file_name.string(), std::ios::binary);
        it->second->finish();
        it->second->write(out);
    }

    return EXIT_SUCCESS;
}

int process_replay_file(const po::variables_map &vm, const std::string &input, const std::string &output, const std::string &type, bool debug) {
    if ( !(vm.count("type") > 0 && vm.count("input") > 0) ) {
        logger.write(wotreplay::log_level_t::error, "parameters type and input are required to use this mode\n");
        return -EXIT_FAILURE;
    }

    std::ifstream in(input, std::ios::binary);
    if (!in) {
        logger.writef(log_level_t::error, "Failed to open file: %1%\n", input);
        return -EXIT_FAILURE;
    }

    parser_t parser;
    game_t game;

    parser.set_debug(debug);
    parser.load_data();
    parser.parse(in, game);

    std::unique_ptr<writer_t> writer = create_writer(type, vm);

    if (!writer) {
        return -EXIT_FAILURE;
    }

    writer->init(game.get_arena(), game.get_game_mode());
    writer->update(game);
    writer->finish();

    std::ostream *out;

    if (vm.count("output") > 0) {
        out = new std::ofstream(output, std::ios::binary);
        if (!out) {
            logger.writef(log_level_t::error, "Something went wrong with opening file: %1%\n", input);
            std::exit(0);
        }
    } else {
        out = &std::cout;
    }

    writer->write(*out);

    if (dynamic_cast<std::ofstream*>(out)) {
        dynamic_cast<std::ofstream*>(out)->close();
        delete out;
    }

    return EXIT_SUCCESS;
}

int main(int argc, const char * argv[]) {
    po::options_description desc("Allowed options");

    std::string type, output, input, root;
    double skip, bounds_min, bounds_max;

    desc.add_options()
        ("type"  , po::value(&type), "select output type")
        ("output", po::value(&output), "output file or directory")
        ("input" , po::value(&input), "input file or directory")
        ("root"  , po::value(&root), "set root directory")
        ("help"  , "produce help message")
        ("debug" , "enable parser debugging")
        ("supress-empty", "supress empty packets from json output")
        ("create-minimaps", "create all empty minimaps in output directory")
        ("parse", "parse a replay file")
        ("quiet", "supress diagnostic messages")
        ("skip", po::value(&skip), "for heatmaps, skip a certain number of seconds after the start of the battle (default: 60)")
        ("bounds-min", po::value(&bounds_min), "for heatmaps, set min value to display (default: 0.66)")
        ("bounds-max", po::value(&bounds_max), "for heatmaps, set max value to display (default: 0.999)");

    po::variables_map vm;

    try {
        po::store(po::parse_command_line(argc, argv, desc), vm);
        po::notify(vm);
    } catch (std::exception &e) {
        show_help(argc, argv, desc);
        std::exit(-1);
    } catch (...) {
        logger.write(log_level_t::error, "Unknown error.\n");
        std::exit(-1);
    }

    if (vm.count("help") > 0) {
        show_help(argc, argv, desc);
        std::exit(0);
    }

    if (vm.count("root") >  0
            && chdir(root.c_str()) != 0) {
        logger.writef(log_level_t::error, "Cannot change working directory to: %1%\n", root);
        std::exit(0);
    }

    bool debug = vm.count("debug") > 0;
    if (debug) {
        logger.set_log_level(log_level_t::debug);
    } else if (vm.count("quiet") > 0) {
        logger.set_log_level(log_level_t::none);
    } else {
        logger.set_log_level(log_level_t::warning);
    }

    int exit_code;
    if (vm.count("parse") > 0) {
        // parse
        if (is_directory(input)) {
            exit_code = process_replay_directory(vm, input, output, type, debug);
        } else {
            exit_code = process_replay_file(vm, input, output, type, debug);
        }
    } else if (vm.count("create-minimaps") > 0) {
        // create all minimaps
        exit_code = create_minimaps(vm, output, debug);
    } else {
        logger.write(wotreplay::log_level_t::error, "Error: no mode specified\n");
        exit_code = -EXIT_FAILURE;
    }

    if (exit_code < 0) {
        show_help(argc, argv, desc);
    }

    return exit_code;
}<commit_msg>Fix issue with arguments bounds-min and bounds-max not getting picked up<commit_after>#include "image_writer.h"
#include "heatmap_writer.h"
#include "json_writer.h"
#include "logger.h"
#include "parser.h"
#include "regex.h"

#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <boost/program_options.hpp>
#include <fstream>

#include <float.h>

using namespace wotreplay;
using namespace boost::filesystem;
namespace po = boost::program_options;

void show_help(int argc, const char *argv[], po::options_description &desc) {
    std::stringstream help_message;
    help_message << desc << "\n";
    logger.write(help_message.str());
}

float distance(const std::tuple<float, float, float> &left, const std::tuple<float, float, float> &right) {
    float delta_x = std::get<0>(left) - std::get<0>(right);
    float delta_y = std::get<1>(left) - std::get<1>(right);
    float delta_z = std::get<2>(left) - std::get<2>(right);
    // distance in xy plane
    float dist1 = std::sqrt(delta_x*delta_x + delta_y*delta_y);
    return std::sqrt(dist1*dist1 + delta_z*delta_z);
}

static bool is_not_empty(const packet_t &packet) {
    // list of default properties with no special meaning
    std::set<property_t> standard_properties = { property_t::clock, property_t::player_id, property_t::type, property_t::sub_type };
    auto properties = packet.get_properties();
    for (int i = 0; i < properties.size(); ++i) {
        property_t property = static_cast<property_t>(i);
        // packet has property, but can not be found in default properties
        if (properties[i] &&
            standard_properties.find(property) == standard_properties.end()) {
            return true;
        }
    }
    return false;
}

int create_minimaps(const po::variables_map &vm, const std::string &output, bool debug) {
    if ( vm.count("output") == 0 ) {
        logger.write(wotreplay::log_level_t::error, "parameter output is required to use this mode");
        return -EXIT_FAILURE;
    }

    boost::format file_name_format("%1%/%2%_%3%_%4%.png");

    image_writer_t writer;
    for (const auto &arena_entry : get_arenas()) {
        const arena_t &arena = arena_entry.second;
        for (const auto &configuration_entry : arena.configurations) {
            for (int team_id : { 0, 1 }) {
                const std::string game_mode = configuration_entry.first;
                writer.init(arena, game_mode);
                writer.set_recorder_team(team_id);
                writer.set_use_fixed_teamcolors(false);
                std::string file_name = (file_name_format % output % arena.name % game_mode % team_id).str();
                std::ofstream os(file_name, std::ios::binary);
                writer.finish();
                writer.write(os);
            }
        }
    }

    return EXIT_SUCCESS;
}

std::unique_ptr<writer_t> create_writer(const std::string &type, const po::variables_map &vm) {
    std::unique_ptr<writer_t> writer;

    if (type == "png") {
        writer = std::unique_ptr<writer_t>(new image_writer_t());
        auto &image_writer = dynamic_cast<image_writer_t&>(*writer);
        image_writer.set_show_self(true);
        image_writer.set_use_fixed_teamcolors(false);
    } else if (type == "json") {
        writer = std::unique_ptr<writer_t>(new json_writer_t());
        if (vm.count("supress-empty")) {
            writer->set_filter(&is_not_empty);
        }
    } else if (type == "heatmap") {
        writer = std::unique_ptr<writer_t>(new heatmap_writer_t());
        auto &heatmap_writer = dynamic_cast<heatmap_writer_t&>(*writer);
        if (vm.count("skip")) {
            heatmap_writer.skip = vm["skip"].as<double>();
        }
        if (vm.count("bounds-min") && vm.count("bounds-max")) {
            heatmap_writer.bounds = std::make_pair(vm["bounds-min"].as<double>(),
                                                   vm["bounds-max"].as<double>());
        }
    } else {
        logger.writef(log_level_t::error, "Invalid output type (%1%), supported types: png, json and heatmap.\n", type);
    }

    return writer;
}

int process_replay_directory(const po::variables_map &vm, const std::string &input, const std::string &output, const std::string &type, bool debug) {
    if ( !(vm.count("type") > 0 && vm.count("input") > 0) ) {
        logger.write(wotreplay::log_level_t::error, "parameters type and input are required to use this mode\n");
        return -EXIT_FAILURE;
    }

    parser_t parser;
    parser.set_debug(debug);
    parser.load_data();

    std::map<std::string, std::unique_ptr<writer_t>> writers;
    for (auto it = directory_iterator(input); it != directory_iterator(); ++it) {
        if (!is_regular_file(*it) || it->path().extension() != ".wotreplay") {
            continue;
        }

        std::ifstream in(it->path().string(), std::ios::binary);
        if (!in) {
            logger.writef(log_level_t::error, "Failed to open file: %1%\n", it->path().string());
            return -EXIT_FAILURE;
        }

        game_t game;

        try {
            parser.parse(in, game);
        } catch (std::exception &e) {
            logger.writef(log_level_t::error, "Failed to parse file (%1%): %2%\n", it->path().string(), e.what());
            continue;
        }

        // if we can't load arena data, skip this replay
        if (game.get_arena().name.empty()) {
            continue;
        }

        std::string name = (boost::format("%s_%s") % game.get_map_name() % game.get_game_mode()).str();
        auto writer = writers.find(name);

        if (writer == writers.end()) {
            auto new_writer = create_writer(type, vm);
            auto result = writers.insert(std::make_pair(name, std::move(new_writer)));
            writer = result.first;
            (writer->second)->init(game.get_arena(), game.get_game_mode());
        }

        (writer->second)->update(game);
    }

    for (auto it = writers.begin(); it != writers.end(); ++it) {
        path file_name = path(output) / (boost::format("%s.png") % it->first).str();
        std::ofstream out(file_name.string(), std::ios::binary);
        it->second->finish();
        it->second->write(out);
    }

    return EXIT_SUCCESS;
}

int process_replay_file(const po::variables_map &vm, const std::string &input, const std::string &output, const std::string &type, bool debug) {
    if ( !(vm.count("type") > 0 && vm.count("input") > 0) ) {
        logger.write(wotreplay::log_level_t::error, "parameters type and input are required to use this mode\n");
        return -EXIT_FAILURE;
    }

    std::ifstream in(input, std::ios::binary);
    if (!in) {
        logger.writef(log_level_t::error, "Failed to open file: %1%\n", input);
        return -EXIT_FAILURE;
    }

    parser_t parser;
    game_t game;

    parser.set_debug(debug);
    parser.load_data();
    parser.parse(in, game);

    std::unique_ptr<writer_t> writer = create_writer(type, vm);

    if (!writer) {
        return -EXIT_FAILURE;
    }

    writer->init(game.get_arena(), game.get_game_mode());
    writer->update(game);
    writer->finish();

    std::ostream *out;

    if (vm.count("output") > 0) {
        out = new std::ofstream(output, std::ios::binary);
        if (!out) {
            logger.writef(log_level_t::error, "Something went wrong with opening file: %1%\n", input);
            std::exit(0);
        }
    } else {
        out = &std::cout;
    }

    writer->write(*out);

    if (dynamic_cast<std::ofstream*>(out)) {
        dynamic_cast<std::ofstream*>(out)->close();
        delete out;
    }

    return EXIT_SUCCESS;
}

int main(int argc, const char * argv[]) {
    po::options_description desc("Allowed options");

    std::string type, output, input, root;
    double skip, bounds_min, bounds_max;

    desc.add_options()
        ("type"  , po::value(&type), "select output type")
        ("output", po::value(&output), "output file or directory")
        ("input" , po::value(&input), "input file or directory")
        ("root"  , po::value(&root), "set root directory")
        ("help"  , "produce help message")
        ("debug" , "enable parser debugging")
        ("supress-empty", "supress empty packets from json output")
        ("create-minimaps", "create all empty minimaps in output directory")
        ("parse", "parse a replay file")
        ("quiet", "supress diagnostic messages")
        ("skip", po::value(&skip), "for heatmaps, skip a certain number of seconds after the start of the battle (default: 60)")
        ("bounds-min", po::value(&bounds_min), "for heatmaps, set min value to display (default: 0.66)")
        ("bounds-max", po::value(&bounds_max), "for heatmaps, set max value to display (default: 0.999)");

    po::variables_map vm;

    try {
        po::store(po::parse_command_line(argc, argv, desc), vm);
        po::notify(vm);
    } catch (std::exception &e) {
        show_help(argc, argv, desc);
        std::exit(-1);
    } catch (...) {
        logger.write(log_level_t::error, "Unknown error.\n");
        std::exit(-1);
    }

    if (vm.count("help") > 0) {
        show_help(argc, argv, desc);
        std::exit(0);
    }

    if (vm.count("root") >  0
            && chdir(root.c_str()) != 0) {
        logger.writef(log_level_t::error, "Cannot change working directory to: %1%\n", root);
        std::exit(0);
    }

    bool debug = vm.count("debug") > 0;
    if (debug) {
        logger.set_log_level(log_level_t::debug);
    } else if (vm.count("quiet") > 0) {
        logger.set_log_level(log_level_t::none);
    } else {
        logger.set_log_level(log_level_t::warning);
    }

    int exit_code;
    if (vm.count("parse") > 0) {
        // parse
        if (is_directory(input)) {
            exit_code = process_replay_directory(vm, input, output, type, debug);
        } else {
            exit_code = process_replay_file(vm, input, output, type, debug);
        }
    } else if (vm.count("create-minimaps") > 0) {
        // create all minimaps
        exit_code = create_minimaps(vm, output, debug);
    } else {
        logger.write(wotreplay::log_level_t::error, "Error: no mode specified\n");
        exit_code = -EXIT_FAILURE;
    }

    if (exit_code < 0) {
        show_help(argc, argv, desc);
    }

    return exit_code;
}<|endoftext|>


<commit_before>//============================================================================
// Name        : ctm_c.cpp
// Author      : Edward
// Version     :
// Copyright   : GPL
// Description : Implementation of CTM by C++
//============================================================================

#include <iostream>
#include <math.h>
using namespace std;
#include "CellTransModel.h"

void initialModel(CellTransModel &mdl);
void startSim(CellTransModel &mdl, float lens[]);
void printLens(vector<float> lens);
void simOneCycle(CellTransModel &mdl, float c, float g1, float g2, vector<float> &lens);

int main() {
	cout << "Hello World!" << endl; // prints Hello World!

	// testing the CTM in CPU
	CellTransModel model;
	initialModel(model);
	float lens[]= {31,10,40,45,10,42,48,51};
	startSim(model,lens);
	vector<float> lengths;
	model.readLanes(lengths);
	printLens(lengths);
	float c = 90;
	simOneCycle(model,c,45,45,lengths);
	printLens(lengths);
	simOneCycle(model,c,45,45,lengths);
	printLens(lengths);
	simOneCycle(model,c,55,45,lengths);
	printLens(lengths);

	string str;
	cin >> str;
	return 0;
}

void initialModel(CellTransModel &mdl) {
	// lanes
	// entry lanes for intersection 1
	cout<<mdl.addLane("L1",LANE_TYPE_ENTRY,60,0.6,0.3,0);
	cout<<mdl.addLane("L2",LANE_TYPE_NORMAL,60,0.6,0.03,0.1);
	cout<<mdl.addLane("L3",LANE_TYPE_ENTRY,60,0.6,0.3,0);
	cout<<mdl.addLane("L4",LANE_TYPE_ENTRY,60,0.6,0.3,0);
	cout<<endl;
	// entry lanes for intersection 2
	cout<<mdl.addLane("L5",LANE_TYPE_NORMAL,60,0.6,0.03,0.1);
	cout<<mdl.addLane("L6",LANE_TYPE_ENTRY,60,0.6,0.3,0);
	cout<<mdl.addLane("L7",LANE_TYPE_ENTRY,60,0.6,0.3,0);
	cout<<mdl.addLane("L8",LANE_TYPE_ENTRY,60,0.6,0.3,0);
	cout<<endl;
	// exit lanes
	mdl.addLane("LE1",LANE_TYPE_EXIT,0,0,0,1);
	mdl.addLane("LE2",LANE_TYPE_EXIT,0,0,0,1);
	mdl.addLane("LE3",LANE_TYPE_EXIT,0,0,0,1);
	mdl.addLane("LE4",LANE_TYPE_EXIT,0,0,0,1);
	mdl.addLane("LE5",LANE_TYPE_EXIT,0,0,0,1);
	mdl.addLane("LE6",LANE_TYPE_EXIT,0,0,0,1);
	// intersections
	vector<string> in_lanes, out_lanes;
	float inner_cells[2][2] = {{2,0.6},{2,0.6}};
	float phase1[4][8] = {{LINK_TYPE_DIRECT, 1, 1,0, 0,0,0,0},
			{LINK_TYPE_DIRECT, 1, 0,0, 2,0,0,0},
			{LINK_TYPE_DIRECT, 1, 1,1, 0,1,0,0},
			{LINK_TYPE_DIRECT, 1, 0,1, 2,1,0,0}};
	float phase2[4][8] = {{LINK_TYPE_DIRECT, 1, 1,2, 0,0,0,0},
			{LINK_TYPE_DIRECT, 1, 0,0, 2,2,0,0},
			{LINK_TYPE_DIRECT, 1, 1,3, 0,1,0,0},
			{LINK_TYPE_DIRECT, 1, 0,1, 2,3,0,0}};
	// intersection 1
	in_lanes.push_back("L1");in_lanes.push_back("L2");
	in_lanes.push_back("L3");in_lanes.push_back("L4");
	out_lanes.push_back("L5");out_lanes.push_back("LE1");
	out_lanes.push_back("LE2");out_lanes.push_back("LE3");
	cout<<mdl.addIntersection("I1",in_lanes,out_lanes,2,inner_cells);
	cout<<mdl.addPhase("I1",4,phase1);cout<<mdl.addPhase("I1",4,phase2);
	cout<<endl;
	in_lanes.clear(); out_lanes.clear();
	// intersection 2
	in_lanes.push_back("L5");in_lanes.push_back("L6");
	in_lanes.push_back("L7");in_lanes.push_back("L8");
	out_lanes.push_back("LE4");out_lanes.push_back("L2");
	out_lanes.push_back("LE5");out_lanes.push_back("LE6");
	cout<<mdl.addIntersection("I2",in_lanes,out_lanes,2,inner_cells);
	cout<<mdl.addPhase("I2",4,phase1);cout<<mdl.addPhase("I2",4,phase2);
	cout<<endl;
	in_lanes.clear(); out_lanes.clear();
	// build CTM
	if(mdl.buildCTM())
		cout << "Building successfully." <<endl;
	else
		cout << "Failed to build CTM." << endl;
}

void startSim(CellTransModel &mdl, float lens[]) {
	vector<float> lanes;
	for(int i=0;i<8;i++)
		lanes.push_back(lens[i]);
	for(int i=0;i<6;i++)
		lanes.push_back(0);
	vector<int> ints;
	ints.push_back(0);ints.push_back(0);
	mdl.startSim(lanes,ints);
}

void printLens(vector<float> lens) {
	cout << "queue lengths = ";
	for (int i=0;i<7;i++)
			cout << lens[i] << "\t";
	cout << lens[7] << endl;
}

void simOneCycle(CellTransModel &mdl,
		float c, float g1, float g2,
		vector<float> &lens) {
	string s1,s2;
	float t1,t2,t3;
	if (g1<g2) {
		s1 = "I1";
		s2 = "I2";
		t1 = g1;
		t2 = g2-g1;
		t3 = c-g2;
	}
	else {
		s1 = "I2";
		s2 = "I1";
		t1 = g2;
		t2 = g1-g2;
		t3 = c-g1;
	}

	// step 1
	if (t1>=1) {
		int sp = (int)floor(t1);
		if (!mdl.sim(1.0,sp))
			cout << "Simulation Error!" << endl;
		t1 -= sp;
	}
	if (t1>1e-6)
		mdl.sim(t1);
	mdl.switchIntersection(s1);
	mdl.readLanes(lens);
	printLens(lens);

	// step 2
	if (t2>=1) {
		int sp = (int)floor(t2);
		if (!mdl.sim(1.0,sp))
			cout << "Simulation Error!" << endl;
		t2 -= sp;
	}
	if (t2>0)
		mdl.sim(t2);
	mdl.switchIntersection(s2);
	mdl.readLanes(lens);
	printLens(lens);

	// step 3
	if (t3>=1) {
		int sp = (int)floor(t3);
		if (!mdl.sim(1.0,sp))
			cout << "Simulation Error!" << endl;
		t3 -= sp;
	}
	if (t3>0)
		mdl.sim(t3);
	mdl.switchIntersection("I1");mdl.switchIntersection("I2");

	mdl.readLanes(lens);
}
<commit_msg>Test 2<commit_after>//============================================================================
// Name        : ctm_c.cpp
// Author      : Edward
// Version     :
// Copyright   : GPL
// Description : Implementation of CTM by C++
//============================================================================

#include <iostream>
#include <math.h>
using namespace std;
#include "CellTransModel.h"

void initialModel(CellTransModel &mdl);
void startSim(CellTransModel &mdl, float lens[]);
void printLens(vector<float> lens);
void simOneCycle(CellTransModel &mdl, float c, float g1, float g2, vector<float> &lens);
void simTest2(CellTransModel &mdl, vector<float> &lens);

int main() {
	cout << "Hello World!" << endl; // prints Hello World!

	// testing the CTM in CPU
	CellTransModel model;
	initialModel(model);
	float lens[]= {31,10,40,45,10,42,48,51};
	startSim(model,lens);
	vector<float> lengths;
	model.readLanes(lengths);
	printLens(lengths);
//	float c = 90;
//	simOneCycle(model,c,45,45,lengths);
//	printLens(lengths);
//	simOneCycle(model,c,45,45,lengths);
//	printLens(lengths);
//	simOneCycle(model,c,55,45,lengths);
//	printLens(lengths);
	simTest2(model,lengths);

	string str;
	cin >> str;
	return 0;
}

void initialModel(CellTransModel &mdl) {
	// lanes
	// entry lanes for intersection 1
	cout<<mdl.addLane("L1",LANE_TYPE_ENTRY,60,0.6,0.3,0);
	cout<<mdl.addLane("L2",LANE_TYPE_NORMAL,60,0.6,0.03,0.1);
	cout<<mdl.addLane("L3",LANE_TYPE_ENTRY,60,0.6,0.3,0);
	cout<<mdl.addLane("L4",LANE_TYPE_ENTRY,60,0.6,0.3,0);
	cout<<endl;
	// entry lanes for intersection 2
	cout<<mdl.addLane("L5",LANE_TYPE_NORMAL,60,0.6,0.03,0.1);
	cout<<mdl.addLane("L6",LANE_TYPE_ENTRY,60,0.6,0.3,0);
	cout<<mdl.addLane("L7",LANE_TYPE_ENTRY,60,0.6,0.3,0);
	cout<<mdl.addLane("L8",LANE_TYPE_ENTRY,60,0.6,0.3,0);
	cout<<endl;
	// exit lanes
	mdl.addLane("LE1",LANE_TYPE_EXIT,0,0,0,1);
	mdl.addLane("LE2",LANE_TYPE_EXIT,0,0,0,1);
	mdl.addLane("LE3",LANE_TYPE_EXIT,0,0,0,1);
	mdl.addLane("LE4",LANE_TYPE_EXIT,0,0,0,1);
	mdl.addLane("LE5",LANE_TYPE_EXIT,0,0,0,1);
	mdl.addLane("LE6",LANE_TYPE_EXIT,0,0,0,1);
	// intersections
	vector<string> in_lanes, out_lanes;
	float inner_cells[2][2] = {{2,0.6},{2,0.6}};
	float phase1[4][8] = {{LINK_TYPE_DIRECT, 1, 1,0, 0,0,0,0},
			{LINK_TYPE_DIRECT, 1, 0,0, 2,0,0,0},
			{LINK_TYPE_DIRECT, 1, 1,1, 0,1,0,0},
			{LINK_TYPE_DIRECT, 1, 0,1, 2,1,0,0}};
	float phase2[4][8] = {{LINK_TYPE_DIRECT, 1, 1,2, 0,0,0,0},
			{LINK_TYPE_DIRECT, 1, 0,0, 2,2,0,0},
			{LINK_TYPE_DIRECT, 1, 1,3, 0,1,0,0},
			{LINK_TYPE_DIRECT, 1, 0,1, 2,3,0,0}};
	// intersection 1
	in_lanes.push_back("L1");in_lanes.push_back("L2");
	in_lanes.push_back("L3");in_lanes.push_back("L4");
	out_lanes.push_back("L5");out_lanes.push_back("LE1");
	out_lanes.push_back("LE2");out_lanes.push_back("LE3");
	cout<<mdl.addIntersection("I1",in_lanes,out_lanes,2,inner_cells);
	cout<<mdl.addPhase("I1",4,phase1);cout<<mdl.addPhase("I1",4,phase2);
	cout<<endl;
	in_lanes.clear(); out_lanes.clear();
	// intersection 2
	in_lanes.push_back("L5");in_lanes.push_back("L6");
	in_lanes.push_back("L7");in_lanes.push_back("L8");
	out_lanes.push_back("LE4");out_lanes.push_back("L2");
	out_lanes.push_back("LE5");out_lanes.push_back("LE6");
	cout<<mdl.addIntersection("I2",in_lanes,out_lanes,2,inner_cells);
	cout<<mdl.addPhase("I2",4,phase1);cout<<mdl.addPhase("I2",4,phase2);
	cout<<endl;
	in_lanes.clear(); out_lanes.clear();
	// build CTM
	if(mdl.buildCTM())
		cout << "Building successfully." <<endl;
	else
		cout << "Failed to build CTM." << endl;
}

void startSim(CellTransModel &mdl, float lens[]) {
	vector<float> lanes;
	for(int i=0;i<8;i++)
		lanes.push_back(lens[i]);
	for(int i=0;i<6;i++)
		lanes.push_back(0);
	vector<int> ints;
	ints.push_back(0);ints.push_back(0);
	mdl.startSim(lanes,ints);
}

void printLens(vector<float> lens) {
	cout << "queue lengths = ";
	for (int i=0;i<7;i++)
			cout << lens[i] << "\t";
	cout << lens[7] << endl;
}

void simOneCycle(CellTransModel &mdl,
		float c, float g1, float g2,
		vector<float> &lens) {
	string s1,s2;
	float t1,t2,t3;
	if (g1<g2) {
		s1 = "I1";
		s2 = "I2";
		t1 = g1;
		t2 = g2-g1;
		t3 = c-g2;
	}
	else {
		s1 = "I2";
		s2 = "I1";
		t1 = g2;
		t2 = g1-g2;
		t3 = c-g1;
	}

	// step 1
	if (t1>=1) {
		int sp = (int)floor(t1);
		if (!mdl.sim(1.0,sp))
			cout << "Simulation Error!" << endl;
		t1 -= sp;
	}
	if (t1>1e-6)
		mdl.sim(t1);
	mdl.switchIntersection(s1);

	// step 2
	if (t2>=1) {
		int sp = (int)floor(t2);
		if (!mdl.sim(1.0,sp))
			cout << "Simulation Error!" << endl;
		t2 -= sp;
	}
	if (t2>0)
		mdl.sim(t2);
	mdl.switchIntersection(s2);

	// step 3
	if (t3>=1) {
		int sp = (int)floor(t3);
		if (!mdl.sim(1.0,sp))
			cout << "Simulation Error!" << endl;
		t3 -= sp;
	}
	if (t3>0)
		mdl.sim(t3);
	mdl.switchIntersection("I1");mdl.switchIntersection("I2");

	mdl.readLanes(lens);
}

void simTest2(CellTransModel &mdl, vector<float> &lens) {
	double t1;

	for(int i=0;i<9;i++) {
		t1 = 5;
		if (t1>=1) {
			int sp = (int)floor(t1);
			if (!mdl.sim(1.0,sp))
				cout << "Simulation Error!" << endl;
			t1 -= sp;
		}
		if (t1>1e-6)
			mdl.sim(t1);
		mdl.readLanes(lens);
		printLens(lens);
	}
}
<|endoftext|>


<commit_before>#include <tr1/memory>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <signal.h>
#include <getopt.h>
#include "barrier.h"
#include "streamer.h"
#include "socket.h"
#include <unistd.h>

using std::vector;
using std::tr1::shared_ptr;

static bool run = true;

static void terminate(void)
{
	run = false;
}

int main(int argc, char** argv)
{
	unsigned num_conn = 1;
	unsigned rem_port = 0;
	unsigned loc_port = 0;
	unsigned interval = 0;
	unsigned length = 0;

	// Parse program arguments and options
	int opt;
	while ((opt = getopt(argc, argv, ":hc:p:q:n:i:")) != -1) {
		char* ptr;
		switch (opt) {

			// Missing a value for the option
			case ':':
				fprintf(stderr, "Option %s requires a value\n", argv[optind-1]);
				return ':';

			// Unknown option was given
			case '?':
				fprintf(stderr, "Ignoring unknown option '%c'\n", optopt);
				break;

			// Print program usage and quit
			case 'h':
				// TODO: Give usage
				return 'h';

			// Set number of connections
			case 'c':
				ptr = NULL;
				if ((num_conn = strtoul(optarg, &ptr, 0)) > 1024 || num_conn < 1 || ptr == NULL || *ptr != '\0') {
					fprintf(stderr, "Option -c requires a valid number of connections [1-1024]\n");
					return 'c';
				}
				break;

			// Set the remote starting port
			case 'p':
				ptr = NULL;
				if ((rem_port = strtoul(optarg, &ptr, 0)) > 0xffff || ptr == NULL || *ptr != '\0') {
					fprintf(stderr, "Option -p requires a valid port number [0-65535]\n");
					return 'p';
				}
				break;

			// Set the local starting port
			case 'q':
				ptr = NULL;
				if ((loc_port = strtoul(optarg, &ptr, 0)) > 0xffff || ptr == NULL || *ptr != '\0') {
					fprintf(stderr, "Option -q requires a valid port number [0-65535]\n");
					return 'p';
				}
				break;

			// Set the size of the byte chunk to be sent
			case 'n':
				ptr = NULL;
				if ((length = strtoul(optarg, &ptr, 0)) > BUFFER_SIZE || ptr == NULL || *ptr != '\0') {
					fprintf(stderr, "Option -n requires a chunk size in bytes [1-%d] or 0 for off\n", BUFFER_SIZE);
					return 'n';
				}
				break;

			// Set the interval between each time a chunk is sent
			case 'i':
				ptr = NULL;
				if ((interval = strtoul(optarg, &ptr, 0)) > 0xffff || ptr == NULL || *ptr != '\0') {
					fprintf(stderr, "Option -i requires an interval in milliseconds [1-65535] or 0 for off\n");
					return 'i';
				}
				break;
		}
	}

	// Check if all mandatory options were set
	if (optind < argc && rem_port == 0) {
		fprintf(stderr, "Option -p is required for client\n");
		return 'p';
	} else if (optind == argc && loc_port == 0) {
		fprintf(stderr, "Option -q is required for server\n");
		return 'q';
	}

	// Handle interrupt signal
	signal(SIGINT, (void (*)(int)) &terminate);

	// Create a barrier
	Barrier barrier(num_conn + 1);

	// Test streamer
	Client client(barrier, "localhost", 5000);

	client.start();
	barrier.wait();

	while (run);

	return 0;
}
<commit_msg>still just some testing<commit_after>#include <tr1/memory>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <signal.h>
#include <getopt.h>
#include "barrier.h"
#include "streamer.h"
#include "socket.h"
#include <unistd.h>

using std::vector;
using std::tr1::shared_ptr;

static bool run = true;

static void terminate(void)
{
	run = false;
}

int main(int argc, char** argv)
{
	unsigned num_conns = 1;
	unsigned remote_port = 0;
	unsigned local_port = 0;
	unsigned interval = 0;
	unsigned length = 0;

	// Parse program arguments and options
	int opt;
	while ((opt = getopt(argc, argv, ":hc:p:q:n:i:")) != -1) {
		char* ptr;
		switch (opt) {

			// Missing a value for the option
			case ':':
				fprintf(stderr, "Option %s requires a value\n", argv[optind-1]);
				return ':';

			// Unknown option was given
			case '?':
				fprintf(stderr, "Ignoring unknown option '%c'\n", optopt);
				break;

			// Print program usage and quit
			case 'h':
				// TODO: Give usage
				return 'h';

			// Set number of connections
			case 'c':
				ptr = NULL;
				if ((num_conns = strtoul(optarg, &ptr, 0)) > 1024 || num_conns < 1 || ptr == NULL || *ptr != '\0') {
					fprintf(stderr, "Option -c requires a valid number of connections [1-1024]\n");
					return 'c';
				}
				break;

			// Set the remote starting port
			case 'p':
				ptr = NULL;
				if ((remote_port = strtoul(optarg, &ptr, 0)) > 0xffff || ptr == NULL || *ptr != '\0') {
					fprintf(stderr, "Option -p requires a valid port number [0-65535]\n");
					return 'p';
				}
				break;

			// Set the local starting port
			case 'q':
				ptr = NULL;
				if ((local_port = strtoul(optarg, &ptr, 0)) > 0xffff || ptr == NULL || *ptr != '\0') {
					fprintf(stderr, "Option -q requires a valid port number [0-65535]\n");
					return 'p';
				}
				break;

			// Set the size of the byte chunk to be sent
			case 'n':
				ptr = NULL;
				if ((length = strtoul(optarg, &ptr, 0)) > BUFFER_SIZE || ptr == NULL || *ptr != '\0') {
					fprintf(stderr, "Option -n requires a chunk size in bytes [1-%d] or 0 for off\n", BUFFER_SIZE);
					return 'n';
				}
				break;

			// Set the interval between each time a chunk is sent
			case 'i':
				ptr = NULL;
				if ((interval = strtoul(optarg, &ptr, 0)) > 0xffff || ptr == NULL || *ptr != '\0') {
					fprintf(stderr, "Option -i requires an interval in milliseconds [1-65535] or 0 for off\n");
					return 'i';
				}
				break;
		}
	}

	// Check if all mandatory options were set
	if (optind < argc && remote_port == 0) {
		fprintf(stderr, "Option -p is required for client\n");
		return 'p';
	} else if (optind == argc && local_port == 0) {
		fprintf(stderr, "Option -q is required for server\n");
		return 'q';
	}

	// Handle interrupt signal
	signal(SIGINT, (void (*)(int)) &terminate);

	// Create a barrier
	Barrier barrier(num_conns + 1);

	// Test streamer
	Server server(barrier, local_port);

	server.start();
	barrier.wait();

	while (run);

	return 0;
}
<|endoftext|>