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

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date: 2007-12-11 14:46:19 +0100 (Di, 11 Dez 2007) $
Version:   $Revision: 13129 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

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

=========================================================================*/

#include "mitkNavigationDataRecorder.h"
#include <fstream>

#include <mitkTimeStamp.h>
#include <tinyxml.h>

#include <itksys/SystemTools.hxx>

mitk::NavigationDataRecorder::NavigationDataRecorder()
{
  //set default values
  m_NumberOfInputs = 0;
  m_RecordingMode = NormalFile;
  m_Recording = false;
  m_NumberOfRecordedFiles = 0;
  m_Stream = NULL;
  m_FileName = "";
  m_SystemTimeClock = RealTimeClock::New();
  m_OutputFormat = mitk::NavigationDataRecorder::xml;
  m_RecordCounter = 0;
  m_RecordCountLimit = -1;

  //To get a start time
  mitk::TimeStamp::GetInstance()->Start(this);

}

mitk::NavigationDataRecorder::~NavigationDataRecorder()
{
}

void mitk::NavigationDataRecorder::GenerateData()
{

}

void mitk::NavigationDataRecorder::AddNavigationData( const NavigationData* nd )
{
  // Process object is not const-correct so the const_cast is required here
  this->SetNthInput(m_NumberOfInputs,
    const_cast< mitk::NavigationData * >( nd ) );

  m_NumberOfInputs++;

  this->Modified();
}

void mitk::NavigationDataRecorder::SetRecordingMode( RecordingMode mode )
{
  m_RecordingMode = mode;
  this->Modified();
}

void mitk::NavigationDataRecorder::Update()
{
  if (m_Recording)
  {
    DataObjectPointerArray inputs = this->GetInputs(); //get all inputs
    mitk::NavigationData::TimeStampType timestamp=0.0; // timestamp for mitk time
    timestamp = mitk::TimeStamp::GetInstance()->GetElapsed();

    mitk::NavigationData::TimeStampType sysTimestamp = 0.0; // timestamp for system time
    sysTimestamp = m_SystemTimeClock->GetCurrentStamp();

    // cast system time double value to stringstream to avoid low precision rounding
    std::ostringstream strs;
    strs.precision(15); // rounding precision for system time double value
    strs << sysTimestamp;
    std::string sysTimeStr = strs.str();

    //if csv-mode: write csv header and timpstamp at beginning
    if (m_OutputFormat == mitk::NavigationDataRecorder::csv)
      {
      //write header only when it's the first line
      if (m_firstLine)
        {
        m_firstLine = false;
        *m_Stream << "TimeStamp";
        for (unsigned int index = 0; index < inputs.size(); index++){ *m_Stream << ";Valid_Tool" << index <<
                                                                                ";X_Tool" << index <<
                                                                                ";Y_Tool" << index <<
                                                                                ";Z_Tool" << index <<
                                                                                ";QX_Tool" << index <<
                                                                                ";QY_Tool" << index <<
                                                                                ";QZ_Tool" << index <<
                                                                                ";QR_Tool" << index;}
        *m_Stream << "\n";
        }
      //write timestamp (always)
      *m_Stream << timestamp;
      }

    //write tool data for every tool
    for (unsigned int index = 0; index < inputs.size(); index++)
    {
      mitk::NavigationData* nd = dynamic_cast<mitk::NavigationData*>(inputs[index].GetPointer());
      nd->Update(); // call update to propagate update to previous filters

      mitk::NavigationData::PositionType position;
      mitk::NavigationData::OrientationType orientation(0.0, 0.0, 0.0, 0.0);
      mitk::NavigationData::CovarianceMatrixType matrix;

      bool hasPosition = true;
      bool hasOrientation = true;
      bool dataValid = false;

      position.Fill(0.0);
      matrix.SetIdentity();

      position = nd->GetPosition();
      orientation = nd->GetOrientation();
      matrix = nd->GetCovErrorMatrix();

      hasPosition = nd->GetHasPosition();
      hasOrientation = nd->GetHasOrientation();
      dataValid = nd->IsDataValid();

      //use this one if you want the timestamps of the source
      //timestamp = nd->GetTimeStamp();

      //a timestamp is never < 0! this case happens only if you are using the timestamp of the nd object instead of getting a new one
      if (timestamp >= 0)
      {
        if (this->m_OutputFormat == mitk::NavigationDataRecorder::xml)
          {
          TiXmlElement* elem = new TiXmlElement("ND");

          elem->SetDoubleAttribute("Time", timestamp);
          elem->SetAttribute("SystemTime", sysTimeStr); // tag for system time
          elem->SetDoubleAttribute("Tool", index);
          elem->SetDoubleAttribute("X", position[0]);
          elem->SetDoubleAttribute("Y", position[1]);
          elem->SetDoubleAttribute("Z", position[2]);

          elem->SetDoubleAttribute("QX", orientation[0]);
          elem->SetDoubleAttribute("QY", orientation[1]);
          elem->SetDoubleAttribute("QZ", orientation[2]);
          elem->SetDoubleAttribute("QR", orientation[3]);

          elem->SetDoubleAttribute("C00", matrix[0][0]);
          elem->SetDoubleAttribute("C01", matrix[0][1]);
          elem->SetDoubleAttribute("C02", matrix[0][2]);
          elem->SetDoubleAttribute("C03", matrix[0][3]);
          elem->SetDoubleAttribute("C04", matrix[0][4]);
          elem->SetDoubleAttribute("C05", matrix[0][5]);
          elem->SetDoubleAttribute("C10", matrix[1][0]);
          elem->SetDoubleAttribute("C11", matrix[1][1]);
          elem->SetDoubleAttribute("C12", matrix[1][2]);
          elem->SetDoubleAttribute("C13", matrix[1][3]);
          elem->SetDoubleAttribute("C14", matrix[1][4]);
          elem->SetDoubleAttribute("C15", matrix[1][5]);

          if (dataValid)
            elem->SetAttribute("Valid",1);
          else
            elem->SetAttribute("Valid",0);

          if (hasOrientation)
            elem->SetAttribute("hO",1);
          else
            elem->SetAttribute("hO",0);

          if (hasPosition)
            elem->SetAttribute("hP",1);
          else
            elem->SetAttribute("hP",0);

          *m_Stream << "        " << *elem << std::endl;

          delete elem;
          }
        else if (this->m_OutputFormat == mitk::NavigationDataRecorder::csv)
          {
          *m_Stream << ";" << dataValid << ";" << position[0] << ";" << position[1] << ";" << position[2] << ";" << orientation[0] << ";" << orientation[1] << ";" << orientation[2] << ";" << orientation[3];
          }
      }
    }
    if (this->m_OutputFormat = mitk::NavigationDataRecorder::csv) *m_Stream << "\n";
  }
  m_RecordCounter++;
  if ((m_RecordCountLimit<=m_RecordCounter)&&(m_RecordCountLimit != -1)) {StopRecording();}
}

void mitk::NavigationDataRecorder::StartRecording()
{
  if (m_Recording)
  {
    std::cout << "Already recording please stop before start new recording session" << std::endl;
    return;
  }

  if (m_Stream == NULL)
  {
    std::stringstream ss;
    std::ostream* stream;

    //An existing extension will be cut and replaced with .xml
    std::string tmpPath = itksys::SystemTools::GetFilenamePath(m_FileName);
    m_FileName = itksys::SystemTools::GetFilenameWithoutExtension(m_FileName);
    if (m_OutputFormat == mitk::NavigationDataRecorder::csv) ss << tmpPath << "/" <<  m_FileName << "-" << m_NumberOfRecordedFiles << ".csv";
    else ss << tmpPath << "/" <<  m_FileName << "-" << m_NumberOfRecordedFiles << ".xml";
    switch(m_RecordingMode)
    {
      case Console:
        stream = &std::cout;
        break;
      case NormalFile:

        //Check if there is a file name and path
        if (m_FileName == "")
        {
          stream = &std::cout;
          std::cout << "No file name or file path set the output is redirected to the console";
        }
        else
        {
          stream = new std::ofstream(ss.str().c_str());
        }

        break;
      case ZipFile:
        stream = &std::cout;
        std::cout << "Sorry no ZipFile support yet";
        break;
      default:
        stream = &std::cout;
        break;
    }
    m_firstLine = true;
    m_RecordCounter = 0;
    StartRecording(stream);
  }

}
void mitk::NavigationDataRecorder::StartRecording(std::ostream* stream)
{
  if (m_Recording)
  {
    std::cout << "Already recording please stop before start new recording session" << std::endl;
    return;
  }

  m_Stream = stream;
  m_Stream->precision(10);

  //TODO store date and GMT time
  if (m_Stream)
  {
    if (m_OutputFormat == mitk::NavigationDataRecorder::xml)
      {
      *m_Stream << "<?xml version=\"1.0\" ?>" << std::endl;
      /**m_Stream << "<Version Ver=\"1\" />" << std::endl;*/
      // should be a generic version, meaning a member variable, which has the actual version
      *m_Stream << "    " << "<Data ToolCount=\"" << (m_NumberOfInputs) << "\" version=\"1.0\">" << std::endl;
      }
    m_Recording = true;
  }
}
void mitk::NavigationDataRecorder::StopRecording()
{
  if (!m_Recording)
  {
    std::cout << "You have to start a recording first" << std::endl;
    return;
  }

  if ((m_Stream) && (m_OutputFormat == mitk::NavigationDataRecorder::xml))
  {
    *m_Stream << "</Data>" << std::endl;
  }

  m_NumberOfRecordedFiles++;
  m_Recording = false;
  m_Stream->flush();
  delete m_Stream;
  m_Stream = NULL;
}<commit_msg>COMP (#7741): Fixed a bug in NavigationDataRecorder which caused the test to fail.<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date: 2007-12-11 14:46:19 +0100 (Di, 11 Dez 2007) $
Version:   $Revision: 13129 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

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

=========================================================================*/

#include "mitkNavigationDataRecorder.h"
#include <fstream>

#include <mitkTimeStamp.h>
#include <tinyxml.h>

#include <itksys/SystemTools.hxx>

mitk::NavigationDataRecorder::NavigationDataRecorder()
{
  //set default values
  m_NumberOfInputs = 0;
  m_RecordingMode = NormalFile;
  m_Recording = false;
  m_NumberOfRecordedFiles = 0;
  m_Stream = NULL;
  m_FileName = "";
  m_SystemTimeClock = RealTimeClock::New();
  m_OutputFormat = mitk::NavigationDataRecorder::xml;
  m_RecordCounter = 0;
  m_RecordCountLimit = -1;

  //To get a start time
  mitk::TimeStamp::GetInstance()->Start(this);

}

mitk::NavigationDataRecorder::~NavigationDataRecorder()
{
}

void mitk::NavigationDataRecorder::GenerateData()
{

}

void mitk::NavigationDataRecorder::AddNavigationData( const NavigationData* nd )
{
  // Process object is not const-correct so the const_cast is required here
  this->SetNthInput(m_NumberOfInputs,
    const_cast< mitk::NavigationData * >( nd ) );

  m_NumberOfInputs++;

  this->Modified();
}

void mitk::NavigationDataRecorder::SetRecordingMode( RecordingMode mode )
{
  m_RecordingMode = mode;
  this->Modified();
}

void mitk::NavigationDataRecorder::Update()
{
  if (m_Recording)
  {
    DataObjectPointerArray inputs = this->GetInputs(); //get all inputs
    mitk::NavigationData::TimeStampType timestamp=0.0; // timestamp for mitk time
    timestamp = mitk::TimeStamp::GetInstance()->GetElapsed();

    mitk::NavigationData::TimeStampType sysTimestamp = 0.0; // timestamp for system time
    sysTimestamp = m_SystemTimeClock->GetCurrentStamp();

    // cast system time double value to stringstream to avoid low precision rounding
    std::ostringstream strs;
    strs.precision(15); // rounding precision for system time double value
    strs << sysTimestamp;
    std::string sysTimeStr = strs.str();

    //if csv-mode: write csv header and timpstamp at beginning
    if (m_OutputFormat == mitk::NavigationDataRecorder::csv)
      {
      //write header only when it's the first line
      if (m_firstLine)
        {
        m_firstLine = false;
        *m_Stream << "TimeStamp";
        for (unsigned int index = 0; index < inputs.size(); index++){ *m_Stream << ";Valid_Tool" << index <<
                                                                                ";X_Tool" << index <<
                                                                                ";Y_Tool" << index <<
                                                                                ";Z_Tool" << index <<
                                                                                ";QX_Tool" << index <<
                                                                                ";QY_Tool" << index <<
                                                                                ";QZ_Tool" << index <<
                                                                                ";QR_Tool" << index;}
        *m_Stream << "\n";
        }
      //write timestamp (always)
      *m_Stream << timestamp;
      }

    //write tool data for every tool
    for (unsigned int index = 0; index < inputs.size(); index++)
    {
      mitk::NavigationData* nd = dynamic_cast<mitk::NavigationData*>(inputs[index].GetPointer());
      nd->Update(); // call update to propagate update to previous filters

      mitk::NavigationData::PositionType position;
      mitk::NavigationData::OrientationType orientation(0.0, 0.0, 0.0, 0.0);
      mitk::NavigationData::CovarianceMatrixType matrix;

      bool hasPosition = true;
      bool hasOrientation = true;
      bool dataValid = false;

      position.Fill(0.0);
      matrix.SetIdentity();

      position = nd->GetPosition();
      orientation = nd->GetOrientation();
      matrix = nd->GetCovErrorMatrix();

      hasPosition = nd->GetHasPosition();
      hasOrientation = nd->GetHasOrientation();
      dataValid = nd->IsDataValid();

      //use this one if you want the timestamps of the source
      //timestamp = nd->GetTimeStamp();

      //a timestamp is never < 0! this case happens only if you are using the timestamp of the nd object instead of getting a new one
      if (timestamp >= 0)
      {
        if (this->m_OutputFormat == mitk::NavigationDataRecorder::xml)
          {
          TiXmlElement* elem = new TiXmlElement("ND");

          elem->SetDoubleAttribute("Time", timestamp);
          elem->SetAttribute("SystemTime", sysTimeStr); // tag for system time
          elem->SetDoubleAttribute("Tool", index);
          elem->SetDoubleAttribute("X", position[0]);
          elem->SetDoubleAttribute("Y", position[1]);
          elem->SetDoubleAttribute("Z", position[2]);

          elem->SetDoubleAttribute("QX", orientation[0]);
          elem->SetDoubleAttribute("QY", orientation[1]);
          elem->SetDoubleAttribute("QZ", orientation[2]);
          elem->SetDoubleAttribute("QR", orientation[3]);

          elem->SetDoubleAttribute("C00", matrix[0][0]);
          elem->SetDoubleAttribute("C01", matrix[0][1]);
          elem->SetDoubleAttribute("C02", matrix[0][2]);
          elem->SetDoubleAttribute("C03", matrix[0][3]);
          elem->SetDoubleAttribute("C04", matrix[0][4]);
          elem->SetDoubleAttribute("C05", matrix[0][5]);
          elem->SetDoubleAttribute("C10", matrix[1][0]);
          elem->SetDoubleAttribute("C11", matrix[1][1]);
          elem->SetDoubleAttribute("C12", matrix[1][2]);
          elem->SetDoubleAttribute("C13", matrix[1][3]);
          elem->SetDoubleAttribute("C14", matrix[1][4]);
          elem->SetDoubleAttribute("C15", matrix[1][5]);

          if (dataValid)
            elem->SetAttribute("Valid",1);
          else
            elem->SetAttribute("Valid",0);

          if (hasOrientation)
            elem->SetAttribute("hO",1);
          else
            elem->SetAttribute("hO",0);

          if (hasPosition)
            elem->SetAttribute("hP",1);
          else
            elem->SetAttribute("hP",0);

          *m_Stream << "        " << *elem << std::endl;

          delete elem;
          }
        else if (this->m_OutputFormat == mitk::NavigationDataRecorder::csv)
          {
          *m_Stream << ";" << dataValid << ";" << position[0] << ";" << position[1] << ";" << position[2] << ";" << orientation[0] << ";" << orientation[1] << ";" << orientation[2] << ";" << orientation[3];
          }
      }
    }
    if (this->m_OutputFormat = mitk::NavigationDataRecorder::csv) *m_Stream << "\n";
  }
  m_RecordCounter++;
  if ((m_RecordCountLimit<=m_RecordCounter)&&(m_RecordCountLimit != -1)) {StopRecording();}
}

void mitk::NavigationDataRecorder::StartRecording()
{
  if (m_Recording)
  {
    std::cout << "Already recording please stop before start new recording session" << std::endl;
    return;
  }

  if (m_Stream == NULL)
  {
    std::stringstream ss;
    std::ostream* stream;

    //An existing extension will be cut and replaced with .xml
    std::string tmpPath = itksys::SystemTools::GetFilenamePath(m_FileName);
    m_FileName = itksys::SystemTools::GetFilenameWithoutExtension(m_FileName);
    if (m_OutputFormat == mitk::NavigationDataRecorder::csv) ss << tmpPath << "/" <<  m_FileName << "-" << m_NumberOfRecordedFiles << ".csv";
    else ss << tmpPath << "/" <<  m_FileName << "-" << m_NumberOfRecordedFiles << ".xml";
    switch(m_RecordingMode)
    {
      case Console:
        stream = &std::cout;
        break;
      case NormalFile:

        //Check if there is a file name and path
        if (m_FileName == "")
        {
          stream = &std::cout;
          std::cout << "No file name or file path set the output is redirected to the console";
        }
        else
        {
          stream = new std::ofstream(ss.str().c_str());
        }

        break;
      case ZipFile:
        stream = &std::cout;
        std::cout << "Sorry no ZipFile support yet";
        break;
      default:
        stream = &std::cout;
        break;
    }
    m_firstLine = true;
    m_RecordCounter = 0;
    StartRecording(stream);
  }

}
void mitk::NavigationDataRecorder::StartRecording(std::ostream* stream)
{
  if (m_Recording)
  {
    std::cout << "Already recording please stop before start new recording session" << std::endl;
    return;
  }

  m_Stream = stream;
  m_Stream->precision(10);

  //TODO store date and GMT time
  if (m_Stream)
  {
    if (m_OutputFormat == mitk::NavigationDataRecorder::xml)
      {
      *m_Stream << "<?xml version=\"1.0\" ?>" << std::endl;
      /**m_Stream << "<Version Ver=\"1\" />" << std::endl;*/
      // should be a generic version, meaning a member variable, which has the actual version
      *m_Stream << "    " << "<Data ToolCount=\"" << (m_NumberOfInputs) << "\" version=\"1.0\">" << std::endl;
      }
    m_Recording = true;
  }
}
void mitk::NavigationDataRecorder::StopRecording()
{
  if (!m_Recording)
  {
    std::cout << "You have to start a recording first" << std::endl;
    return;
  }

  if ((m_Stream) && (m_OutputFormat == mitk::NavigationDataRecorder::xml))
  {
    *m_Stream << "</Data>" << std::endl;
  }

  m_NumberOfRecordedFiles++;
  m_Recording = false;
  m_Stream->flush();
  m_Stream = NULL;
}<|endoftext|>


<commit_before>enum AlgoType {kKT, kANTIKT};
enum JetType  {kFULLJETS, kCHARGEDJETS, kNEUTRALJETS};

AliAnalysisTaskEmcalJetTriggerQA* AddTaskEmcalJetTriggerQA(TString     kTracksName         = "PicoTracks",
							   TString     kClusName           = "caloClustersCorr",
							   Double_t    R                   = 0.4,
							   Double_t    ptminTrack          = 0.15,
							   Double_t    etminClus           = 0.3,
							   Int_t       rhoType             = 0,
							   TString     trigClass           = "",
							   TString     kEmcalCellsName     = "",
							   const char *CentEst             = "V0A",
							   Int_t       pSel                = AliVEvent::kINT7,
							   Float_t     nefCut              = 10.,
							   TString     kEmcalTriggers      = "",
							   TString     kPeriod             = "LHC13b"
							   ) {

  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr)
    {
      Error("AddTaskEmcalJetTriggerQA","No analysis manager found.");
      return 0;
    }
  Bool_t ismc=kFALSE;
  ismc = (mgr->GetMCtruthEventHandler())?kTRUE:kFALSE;

  // Check the analysis type using the event handlers connected to the analysis manager.
  //==============================================================================
  if (!mgr->GetInputEventHandler())
    {
      ::Error("AddTaskEmcalJetTriggerQA", "This task requires an input event handler");
      return NULL;
    }

  // #### Add necessary jet finder tasks
  gROOT->LoadMacro("$ALICE_ROOT/PWGJE/EMCALJetTasks/macros/AddTaskEmcalJet.C");

  AliEmcalJetTask* jetFinderTask1;
  AliEmcalJetTask* jetFinderTask2;
  if(kClusName.IsNull()) {  //particle level jets
    jetFinderTask1 = AddTaskEmcalJet(kTracksName, "", kANTIKT, R, kFULLJETS, ptminTrack, etminClus);
    jetFinderTask2 = AddTaskEmcalJet(kTracksName, "", kANTIKT, R, kCHARGEDJETS, ptminTrack, etminClus);
  }
  else if(kTracksName.IsNull()) { //neutral/calo jets
    jetFinderTask1 = AddTaskEmcalJet(kTracksName, kClusName, kANTIKT, R, kNEUTRALJETS, ptminTrack, etminClus);
    jetFinderTask2 = AddTaskEmcalJet(kTracksName, kClusName, kANTIKT, R, kFULLJETS, ptminTrack, etminClus);
  }
  else { //full jets
    jetFinderTask1 = AddTaskEmcalJet(kTracksName, kClusName, kANTIKT, R, kFULLJETS, ptminTrack, etminClus);
    jetFinderTask2 = AddTaskEmcalJet(kTracksName, kClusName, kANTIKT, R, kCHARGEDJETS, ptminTrack, etminClus);
  }
  jetFinderTask1->SelectCollisionCandidates(AliVEvent::kAny);
  jetFinderTask2->SelectCollisionCandidates(AliVEvent::kAny);

  TString strJets1 = jetFinderTask1->GetName();
  TString strJets2 = jetFinderTask2->GetName();

  AliAnalysisTaskRhoBase *rhoTask;
  if(rhoType==1) {
    rhoTask = AttachRhoTask(kPeriod,kTracksName,kClusName,R,ptminTrack,etminClus);
    rhoTask->SetCentralityEstimator(CentEst);
    rhoTask->SelectCollisionCandidates(AliVEvent::kAny);
  }

  TString wagonName = Form("TriggerQA_%s_%s_TC%s",strJets1.Data(),strJets2.Data(),trigClass.Data());

  //Configure TriggerQA task
  AliAnalysisTaskEmcalJetTriggerQA *task = new AliAnalysisTaskEmcalJetTriggerQA(wagonName);
  AliParticleContainer *trackCont  = task->AddParticleContainer(kTracksName.Data());
  AliClusterContainer *clusterCont = task->AddClusterContainer(kClusName.Data());

  task->SetContainerFull(0);
  task->SetContainerCharged(1);
  AliJetContainer *jetCont0 = task->AddJetContainer(strJets1.Data(),"EMCAL",R);
  if(rhoType==1) task->SetRhoName(rhoTask->GetOutRhoScaledName(),0);
  AliJetContainer *jetCont1 = NULL;
  if(strJets2.Contains("Charged")) {
    jetCont1 = task->AddJetContainer(strJets2.Data(),"TPC",R);
    if(rhoType==1) task->SetRhoName(rhoTask->GetOutRhoName(),1);
  }
  else {
    jetCont1 = task->AddJetContainer(strJets2.Data(),"EMCAL",R);
    task->SetZLeadingCut(0.98,0.98,1);
    task->SetNEFCut(0.,nefCut,1);
  }

  task->SetZLeadingCut(0.98,0.98,0);
  task->SetNEFCut(0.,nefCut,0);

  for(Int_t i=0; i<2; i++) {
    task->SetPercAreaCut(0.6, i);
  }

  task->SetTriggerClass(trigClass.Data());
  task->SetCaloCellsName(kEmcalCellsName.Data());
  task->SetCaloTriggerPatchInfoName(kEmcalTriggers.Data());

  task->SetCentralityEstimator(CentEst);
  task->SelectCollisionCandidates(pSel);

  task->SetUseAliAnaUtils(kTRUE);

  if(kPeriod.Contains("LHC13b4"))
    task-SetIsPythia(kTRUE);

  mgr->AddTask(task);

  //Connnect input
  mgr->ConnectInput (task, 0, mgr->GetCommonInputContainer() );

  //Connect output
  AliAnalysisDataContainer *coutput1 = 0x0;
  TString containerName1 = Form("%s",wagonName.Data());
  TString outputfile = Form("%s:%s",AliAnalysisManager::GetCommonFileName(),wagonName.Data());
  coutput1 = mgr->CreateContainer(containerName1, TList::Class(),AliAnalysisManager::kOutputContainer,outputfile);
  mgr->ConnectOutput(task,1,coutput1);

  return task;
}

AliAnalysisTaskRhoBase *AttachRhoTask(TString     kPeriod             = "LHC13b",
				      TString     kTracksName         = "PicoTracks",
				      TString     kClusName           = "caloClustersCorr",
				      Double_t    R                   = 0.4,
				      Double_t    ptminTrack          = 0.15,
				      Double_t    etminClus           = 0.3
				      ) {

  AliAnalysisTaskRhoBase *rhoTaskBase;

  kPeriod.ToLower();

  // Add kt jet finder and rho task in case we want background subtraction
  AliEmcalJetTask *jetFinderKt;
  AliEmcalJetTask *jetFinderAKt;
  jetFinderKt   = AddTaskEmcalJet(kTracksName, kClusName, kKT, R, kCHARGEDJETS, ptminTrack, etminClus);
  jetFinderAKt  = AddTaskEmcalJet(kTracksName, kClusName, kANTIKT, R, kCHARGEDJETS, ptminTrack, etminClus);

  if(kPeriod.EqualTo("lhc13b") || kPeriod.EqualTo("lhc13c") || kPeriod.EqualTo("lhc13d") || kPeriod.EqualTo("lhc13e") || kPeriod.EqualTo("lhc13f")) {
    jetFinderKt->SetMinJetPt(0.);

    gROOT->LoadMacro("$ALICE_ROOT/PWGJE/EMCALJetTasks/macros/AddTaskRhoSparse.C");
    TF1 *fScale = new TF1("fScale","1.42",0.,100.); //scale factor for pPb
    AliAnalysisTaskRhoSparse *rhoTaskSparse = AddTaskRhoSparse(
			       jetFinderKt->GetName(),
			       jetFinderAKt->GetName(),
			       kTracksName,
			       kClusName,
			       Form("RhoSparseR%03d",(int)(100*R)),
			       R,
			       "TPC",
			       0.01,
			       0.15,
			       0,
			       fScale,
			       0,
			       kTRUE,
			       Form("RhoSparseR%03d",(int)(100*R)),
			       kTRUE
			       );
    rhoTaskSparse->SetUseAliAnaUtils(kTRUE);
    rhoTaskBase = dynamic_cast<AliAnalysisTaskRhoBase*>rhoTaskSparse;
  }
  else if(kPeriod.EqualTo("lhc10h") || kPeriod.EqualTo("lhc11h") ) {
    gROOT->LoadMacro("$ALICE_ROOT/PWGJE/EMCALJetTasks/macros/AddTaskRho.C");

    TF1* sfunc = new TF1("sfunc","[0]*x*x+[1]*x+[2]",-1,100);
    sfunc->SetParameter(2,1.76458);
    sfunc->SetParameter(1,-0.0111656);
    sfunc->SetParameter(0,0.000107296);
    AliAnalysisTaskRho *rhoTask = AddTaskRho(
					     jetFinderKt->GetName(),
					     kTracksName,
					     kClusName,
					     Form("RhoR%03d",(int)(100*R)),
					     R,
					     "TPC",
					     0.01,
					     0,
					     sfunc,
					     2,
					     kTRUE);
    rhoTask->SetHistoBins(100,0,250);

    rhoTaskBase = dynamic_cast<AliAnalysisTaskRhoBase*>rhoTask;
  }

  return rhoTaskBase;
}
<commit_msg>also phys sel for jet finders rho task<commit_after>enum AlgoType {kKT, kANTIKT};
enum JetType  {kFULLJETS, kCHARGEDJETS, kNEUTRALJETS};

AliAnalysisTaskEmcalJetTriggerQA* AddTaskEmcalJetTriggerQA(TString     kTracksName         = "PicoTracks",
							   TString     kClusName           = "caloClustersCorr",
							   Double_t    R                   = 0.4,
							   Double_t    ptminTrack          = 0.15,
							   Double_t    etminClus           = 0.3,
							   Int_t       rhoType             = 0,
							   TString     trigClass           = "",
							   TString     kEmcalCellsName     = "",
							   const char *CentEst             = "V0A",
							   Int_t       pSel                = AliVEvent::kINT7,
							   Float_t     nefCut              = 10.,
							   TString     kEmcalTriggers      = "",
							   TString     kPeriod             = "LHC13b"
							   ) {

  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr)
    {
      Error("AddTaskEmcalJetTriggerQA","No analysis manager found.");
      return 0;
    }
  Bool_t ismc=kFALSE;
  ismc = (mgr->GetMCtruthEventHandler())?kTRUE:kFALSE;

  // Check the analysis type using the event handlers connected to the analysis manager.
  //==============================================================================
  if (!mgr->GetInputEventHandler())
    {
      ::Error("AddTaskEmcalJetTriggerQA", "This task requires an input event handler");
      return NULL;
    }

  // #### Add necessary jet finder tasks
  gROOT->LoadMacro("$ALICE_ROOT/PWGJE/EMCALJetTasks/macros/AddTaskEmcalJet.C");

  AliEmcalJetTask* jetFinderTask1;
  AliEmcalJetTask* jetFinderTask2;
  if(kClusName.IsNull()) {  //particle level jets
    jetFinderTask1 = AddTaskEmcalJet(kTracksName, "", kANTIKT, R, kFULLJETS, ptminTrack, etminClus);
    jetFinderTask2 = AddTaskEmcalJet(kTracksName, "", kANTIKT, R, kCHARGEDJETS, ptminTrack, etminClus);
  }
  else if(kTracksName.IsNull()) { //neutral/calo jets
    jetFinderTask1 = AddTaskEmcalJet(kTracksName, kClusName, kANTIKT, R, kNEUTRALJETS, ptminTrack, etminClus);
    jetFinderTask2 = AddTaskEmcalJet(kTracksName, kClusName, kANTIKT, R, kFULLJETS, ptminTrack, etminClus);
  }
  else { //full jets
    jetFinderTask1 = AddTaskEmcalJet(kTracksName, kClusName, kANTIKT, R, kFULLJETS, ptminTrack, etminClus);
    jetFinderTask2 = AddTaskEmcalJet(kTracksName, kClusName, kANTIKT, R, kCHARGEDJETS, ptminTrack, etminClus);
  }
  jetFinderTask1->SelectCollisionCandidates(AliVEvent::kAny);
  jetFinderTask2->SelectCollisionCandidates(AliVEvent::kAny);

  TString strJets1 = jetFinderTask1->GetName();
  TString strJets2 = jetFinderTask2->GetName();

  AliAnalysisTaskRhoBase *rhoTask;
  if(rhoType==1) {
    rhoTask = AttachRhoTask(kPeriod,kTracksName,kClusName,R,ptminTrack,etminClus);
    rhoTask->SetCentralityEstimator(CentEst);
    rhoTask->SelectCollisionCandidates(AliVEvent::kAny);
  }

  TString wagonName = Form("TriggerQA_%s_%s_TC%s",strJets1.Data(),strJets2.Data(),trigClass.Data());

  //Configure TriggerQA task
  AliAnalysisTaskEmcalJetTriggerQA *task = new AliAnalysisTaskEmcalJetTriggerQA(wagonName);
  AliParticleContainer *trackCont  = task->AddParticleContainer(kTracksName.Data());
  AliClusterContainer *clusterCont = task->AddClusterContainer(kClusName.Data());

  task->SetContainerFull(0);
  task->SetContainerCharged(1);
  AliJetContainer *jetCont0 = task->AddJetContainer(strJets1.Data(),"EMCAL",R);
  if(rhoType==1) task->SetRhoName(rhoTask->GetOutRhoScaledName(),0);
  AliJetContainer *jetCont1 = NULL;
  if(strJets2.Contains("Charged")) {
    jetCont1 = task->AddJetContainer(strJets2.Data(),"TPC",R);
    if(rhoType==1) task->SetRhoName(rhoTask->GetOutRhoName(),1);
  }
  else {
    jetCont1 = task->AddJetContainer(strJets2.Data(),"EMCAL",R);
    task->SetZLeadingCut(0.98,0.98,1);
    task->SetNEFCut(0.,nefCut,1);
  }

  task->SetZLeadingCut(0.98,0.98,0);
  task->SetNEFCut(0.,nefCut,0);

  for(Int_t i=0; i<2; i++) {
    task->SetPercAreaCut(0.6, i);
  }

  task->SetTriggerClass(trigClass.Data());
  task->SetCaloCellsName(kEmcalCellsName.Data());
  task->SetCaloTriggerPatchInfoName(kEmcalTriggers.Data());

  task->SetCentralityEstimator(CentEst);
  task->SelectCollisionCandidates(pSel);

  task->SetUseAliAnaUtils(kTRUE);

  if(kPeriod.Contains("LHC13b4"))
    task-SetIsPythia(kTRUE);

  mgr->AddTask(task);

  //Connnect input
  mgr->ConnectInput (task, 0, mgr->GetCommonInputContainer() );

  //Connect output
  AliAnalysisDataContainer *coutput1 = 0x0;
  TString containerName1 = Form("%s",wagonName.Data());
  TString outputfile = Form("%s:%s",AliAnalysisManager::GetCommonFileName(),wagonName.Data());
  coutput1 = mgr->CreateContainer(containerName1, TList::Class(),AliAnalysisManager::kOutputContainer,outputfile);
  mgr->ConnectOutput(task,1,coutput1);

  return task;
}

AliAnalysisTaskRhoBase *AttachRhoTask(TString     kPeriod             = "LHC13b",
				      TString     kTracksName         = "PicoTracks",
				      TString     kClusName           = "caloClustersCorr",
				      Double_t    R                   = 0.4,
				      Double_t    ptminTrack          = 0.15,
				      Double_t    etminClus           = 0.3
				      ) {

  AliAnalysisTaskRhoBase *rhoTaskBase;

  kPeriod.ToLower();

  // Add kt jet finder and rho task in case we want background subtraction
  AliEmcalJetTask *jetFinderKt;
  AliEmcalJetTask *jetFinderAKt;
  jetFinderKt   = AddTaskEmcalJet(kTracksName, kClusName, kKT, R, kCHARGEDJETS, ptminTrack, etminClus);
  jetFinderAKt  = AddTaskEmcalJet(kTracksName, kClusName, kANTIKT, R, kCHARGEDJETS, ptminTrack, etminClus);
  jetFinderKt->SelectCollisionCandidates(AliVEvent::kAny);
  jetFinderAKt->SelectCollisionCandidates(AliVEvent::kAny);

  if(kPeriod.EqualTo("lhc13b") || kPeriod.EqualTo("lhc13c") || kPeriod.EqualTo("lhc13d") || kPeriod.EqualTo("lhc13e") || kPeriod.EqualTo("lhc13f")) {
    jetFinderKt->SetMinJetPt(0.);

    gROOT->LoadMacro("$ALICE_ROOT/PWGJE/EMCALJetTasks/macros/AddTaskRhoSparse.C");
    TF1 *fScale = new TF1("fScale","1.42",0.,100.); //scale factor for pPb
    AliAnalysisTaskRhoSparse *rhoTaskSparse = AddTaskRhoSparse(
			       jetFinderKt->GetName(),
			       jetFinderAKt->GetName(),
			       kTracksName,
			       kClusName,
			       Form("RhoSparseR%03d",(int)(100*R)),
			       R,
			       "TPC",
			       0.01,
			       0.15,
			       0,
			       fScale,
			       0,
			       kTRUE,
			       Form("RhoSparseR%03d",(int)(100*R)),
			       kTRUE
			       );
    rhoTaskSparse->SetUseAliAnaUtils(kTRUE);
    rhoTaskBase = dynamic_cast<AliAnalysisTaskRhoBase*>rhoTaskSparse;
  }
  else if(kPeriod.EqualTo("lhc10h") || kPeriod.EqualTo("lhc11h") ) {
    gROOT->LoadMacro("$ALICE_ROOT/PWGJE/EMCALJetTasks/macros/AddTaskRho.C");

    TF1* sfunc = new TF1("sfunc","[0]*x*x+[1]*x+[2]",-1,100);
    sfunc->SetParameter(2,1.76458);
    sfunc->SetParameter(1,-0.0111656);
    sfunc->SetParameter(0,0.000107296);
    AliAnalysisTaskRho *rhoTask = AddTaskRho(
					     jetFinderKt->GetName(),
					     kTracksName,
					     kClusName,
					     Form("RhoR%03d",(int)(100*R)),
					     R,
					     "TPC",
					     0.01,
					     0,
					     sfunc,
					     2,
					     kTRUE);
    rhoTask->SetHistoBins(100,0,250);

    rhoTaskBase = dynamic_cast<AliAnalysisTaskRhoBase*>rhoTask;
  }

  return rhoTaskBase;
}
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-2013, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

#include "AliAnalysisTaskFilterUPCNanoAOD.h"

#include "AliAnalysisManager.h"
#include "AliAnalysisTaskESDMuonFilter.h"
#include "AliAODEvent.h"
#include "AliAODHandler.h"
#include "AliAODUPCReplicator.h"
#include "AliLog.h"

///
/// \brief AliAnalysisTaskFilterUPCNanoAOD : a class to convert full AODs to muon ones
///
/// The actual work is done, like for the ESD->muon AOD case, by the
/// AliAODUPCReplicator class. This very class is just steering it.
///

/// \cond CLASSIMP
ClassImp(AliAnalysisTaskFilterUPCNanoAOD)
/// \endcond

//_____________________________________________________________________________
AliAnalysisTaskFilterUPCNanoAOD::AliAnalysisTaskFilterUPCNanoAOD(Bool_t withSPDTracklets,Bool_t withMuonTracks)
: AliAnalysisTaskSE("AliAnalysisTaskFilterUPCNanoAOD"),
fBranchReplicator(new AliAODUPCReplicator("UPCReplicator",
                                           "UPC",
                                           kTRUE,
                                           withSPDTracklets,
					   withMuonTracks)),
					   fWithMuonTracks(withMuonTracks)
{
  /// ctor. For the parameters \see AliAODUPCReplicator::AliAODUPCReplicator
}

//_____________________________________________________________________________
AliAnalysisTaskFilterUPCNanoAOD::~AliAnalysisTaskFilterUPCNanoAOD()
{
  /// dtor. Delete our internal worker class
  delete fBranchReplicator;
}

//_____________________________________________________________________________
void AliAnalysisTaskFilterUPCNanoAOD::UserCreateOutputObjects()
{
  /// Create the output AOD branches, from the list of object
  /// we have in the replicator

  TList* list = fBranchReplicator->GetList();

  TIter next(list);
  TObject* o;

  while ( (o = next()) )
  {
    AddAODBranch(o->ClassName(),list->GetObjectRef(o));
  }
}

//_____________________________________________________________________________
void AliAnalysisTaskFilterUPCNanoAOD::UserExec(Option_t*)
{
  /// Main method doing the actual filtering (delegating it to
  /// the muon replicator)

  AliAODEvent* aod = dynamic_cast<AliAODEvent*>(InputEvent());
  if (!aod)
  {
    AliError("Event is not a the AOD type");
    return;
  }

 //Trigger
  Bool_t isTriggered = kFALSE;
  TString trigger = aod->GetFiredTriggerClasses();

  if(trigger.Contains("CCUP")) isTriggered = kTRUE; // UPC central barrel
  if(trigger.Contains("CMUP") && fWithMuonTracks) isTriggered = kTRUE; // UPC MUON

  //Vertex
  Bool_t hasGoodVertex = kFALSE;
  AliAODVertex *aodVertex = aod->GetPrimaryVertex();
  if(aodVertex->GetNContributors() > 1 && TMath::Abs(aodVertex->GetZ()) < 15) hasGoodVertex = kTRUE;

  UInt_t nGoodTracks = 0;
  for(Int_t itr=0; itr<aod ->GetNumberOfTracks(); itr++) {
  	AliAODTrack *trk = dynamic_cast<AliAODTrack*>(aod->GetTrack(itr));
  	if( !trk ) continue;
  	if( trk->TestFilterBit(1<<0) || trk->TestFilterBit(1<<1)) nGoodTracks++;
	if( trk->IsMuonTrack() && trk->GetRAtAbsorberEnd() > 17.5 && trk->GetRAtAbsorberEnd() < 89.5 && trk->Eta() > -4.0 && trk->Eta() < -2.5) nGoodTracks++;
	}

  //if(!isTriggered || !hasGoodVertex || nGoodTracks == 0) return;
  if(!isTriggered || nGoodTracks == 0) return;
  //if(!isTriggered) return;
  //AliInfo("Good UPC event");

  // not sure why but the fillAOD flag seems to be lost somewhere, so must
  // set it per event.
  AliAODHandler* aodH = static_cast<AliAODHandler*>(AliAnalysisManager::GetAnalysisManager()->GetOutputEventHandler());

  aodH->SetFillAOD(kTRUE);

  fBranchReplicator->ReplicateAndFilter(*aod);
}
<commit_msg>Store also events with no tracks<commit_after>/**************************************************************************
 * Copyright(c) 1998-2013, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

#include "AliAnalysisTaskFilterUPCNanoAOD.h"

#include "AliAnalysisManager.h"
#include "AliAnalysisTaskESDMuonFilter.h"
#include "AliAODEvent.h"
#include "AliAODHandler.h"
#include "AliAODUPCReplicator.h"
#include "AliLog.h"

///
/// \brief AliAnalysisTaskFilterUPCNanoAOD : a class to convert full AODs to muon ones
///
/// The actual work is done, like for the ESD->muon AOD case, by the
/// AliAODUPCReplicator class. This very class is just steering it.
///

/// \cond CLASSIMP
ClassImp(AliAnalysisTaskFilterUPCNanoAOD)
/// \endcond

//_____________________________________________________________________________
AliAnalysisTaskFilterUPCNanoAOD::AliAnalysisTaskFilterUPCNanoAOD(Bool_t withSPDTracklets,Bool_t withMuonTracks)
: AliAnalysisTaskSE("AliAnalysisTaskFilterUPCNanoAOD"),
fBranchReplicator(new AliAODUPCReplicator("UPCReplicator",
                                           "UPC",
                                           kTRUE,
                                           withSPDTracklets,
					   withMuonTracks)),
					   fWithMuonTracks(withMuonTracks)
{
  /// ctor. For the parameters \see AliAODUPCReplicator::AliAODUPCReplicator
}

//_____________________________________________________________________________
AliAnalysisTaskFilterUPCNanoAOD::~AliAnalysisTaskFilterUPCNanoAOD()
{
  /// dtor. Delete our internal worker class
  delete fBranchReplicator;
}

//_____________________________________________________________________________
void AliAnalysisTaskFilterUPCNanoAOD::UserCreateOutputObjects()
{
  /// Create the output AOD branches, from the list of object
  /// we have in the replicator

  TList* list = fBranchReplicator->GetList();

  TIter next(list);
  TObject* o;

  while ( (o = next()) )
  {
    AddAODBranch(o->ClassName(),list->GetObjectRef(o));
  }
}

//_____________________________________________________________________________
void AliAnalysisTaskFilterUPCNanoAOD::UserExec(Option_t*)
{
  /// Main method doing the actual filtering (delegating it to
  /// the muon replicator)

  AliAODEvent* aod = dynamic_cast<AliAODEvent*>(InputEvent());
  if (!aod)
  {
    AliError("Event is not a the AOD type");
    return;
  }

 //Trigger
  Bool_t isTriggered = kFALSE;
  TString trigger = aod->GetFiredTriggerClasses();

  if(trigger.Contains("CCUP")) isTriggered = kTRUE; // UPC central barrel
  if(trigger.Contains("CMUP") && fWithMuonTracks) isTriggered = kTRUE; // UPC MUON

  //Vertex
  Bool_t hasGoodVertex = kFALSE;
  AliAODVertex *aodVertex = aod->GetPrimaryVertex();
  if(aodVertex->GetNContributors() > 1 && TMath::Abs(aodVertex->GetZ()) < 15) hasGoodVertex = kTRUE;

  UInt_t nGoodTracks = 0;
  for(Int_t itr=0; itr<aod ->GetNumberOfTracks(); itr++) {
  	AliAODTrack *trk = dynamic_cast<AliAODTrack*>(aod->GetTrack(itr));
  	if( !trk ) continue;
  	if( trk->TestFilterBit(1<<0) || trk->TestFilterBit(1<<1)) nGoodTracks++;
	if( trk->IsMuonTrack() && trk->GetRAtAbsorberEnd() > 17.5 && trk->GetRAtAbsorberEnd() < 89.5 && trk->Eta() > -4.0 && trk->Eta() < -2.5) nGoodTracks++;
	}

  //if(!isTriggered || !hasGoodVertex || nGoodTracks == 0) return;
  //if(!isTriggered || nGoodTracks == 0) return;
  if(!isTriggered) return;
  //AliInfo("Good UPC event");

  // not sure why but the fillAOD flag seems to be lost somewhere, so must
  // set it per event.
  AliAODHandler* aodH = static_cast<AliAODHandler*>(AliAnalysisManager::GetAnalysisManager()->GetOutputEventHandler());

  aodH->SetFillAOD(kTRUE);

  fBranchReplicator->ReplicateAndFilter(*aod);
}
<|endoftext|>


<commit_before>#include "ShadowCommon.h"
#include "LightForm.h"
#include "Director.h"
#include "MathCommon.h"

using namespace Math;
using namespace Rendering::Light;
using namespace Rendering::Shadow;
using namespace Core;
using namespace Rendering;

ShadowCommon::ShadowCommon(const LightForm* owner, const std::function<void()>& ownerUpdateCounter)
	: _owner(owner), _bias(0.001f), _ownerAddUpdateCounter(ownerUpdateCounter)
{
	_color = Color::Black();
}

ShadowCommon::~ShadowCommon()
{
}

void ShadowCommon::Initialize()
{
}

void ShadowCommon::MakeParam(CommonParam& outParam) const
{
	outParam.bias		= _bias;//Common::FloatToHalf(_bias);
	outParam.index		= FetchShadowCastingLightIndex() + 1;//Common::FloatToHalf( (float)FetchShadowCastingLightIndex() );
}

ushort ShadowCommon::FetchShadowCastingLightIndex() const
{
	Scene* scene = Device::Director::GetInstance()->GetCurrentScene();
	ShadowRenderer* shadowManager = scene->GetShadowManager();

	const LightForm* owner = _owner;
	return shadowManager->FetchShadowCastingLightIndex(owner);
}

void ShadowCommon::SetBias(float bias)
{
	_bias = bias;
	_ownerAddUpdateCounter();
}

void ShadowCommon::SetColor(const Color& color)
{
	_color = color;
	_ownerAddUpdateCounter();
}<commit_msg>Shadow Strength 기본 값을 0.5로 설정<commit_after>#include "ShadowCommon.h"
#include "LightForm.h"
#include "Director.h"
#include "MathCommon.h"

using namespace Math;
using namespace Rendering::Light;
using namespace Rendering::Shadow;
using namespace Core;
using namespace Rendering;

ShadowCommon::ShadowCommon(const LightForm* owner, const std::function<void()>& ownerUpdateCounter)
	: _owner(owner), _bias(0.001f), _ownerAddUpdateCounter(ownerUpdateCounter)
{
	_color = Color::Black();
	_color.a = 0.5f;
}

ShadowCommon::~ShadowCommon()
{
}

void ShadowCommon::Initialize()
{
}

void ShadowCommon::MakeParam(CommonParam& outParam) const
{
	outParam.bias		= _bias;//Common::FloatToHalf(_bias);
	outParam.index		= FetchShadowCastingLightIndex() + 1;//Common::FloatToHalf( (float)FetchShadowCastingLightIndex() );
}

ushort ShadowCommon::FetchShadowCastingLightIndex() const
{
	Scene* scene = Device::Director::GetInstance()->GetCurrentScene();
	ShadowRenderer* shadowManager = scene->GetShadowManager();

	const LightForm* owner = _owner;
	return shadowManager->FetchShadowCastingLightIndex(owner);
}

void ShadowCommon::SetBias(float bias)
{
	_bias = bias;
	_ownerAddUpdateCounter();
}

void ShadowCommon::SetColor(const Color& color)
{
	_color = color;
	_ownerAddUpdateCounter();
}<|endoftext|>


<commit_before>#include "catch.hpp"
#include "../src/Board.h"

TEST_CASE("Board class tests", "[Board]")
{
  SECTION("Constructor correctly sets width and height")
  {
    const int w = 11;
    const int h = 12;
    Board b(w, h);
    REQUIRE(b.width() == w);
    REQUIRE(b.height() == h);
  }
}
<commit_msg>Remove the tests for Board class<commit_after><|endoftext|>


<commit_before>//=================================================================================================
/*!
//  \file src/blaze/TSVecTDMatMult.cpp
//  \brief Source file for the transpose sparse vector/transpose dense matrix multiplication benchmark
//
//  Copyright (C) 2013 Klaus Iglberger - All Rights Reserved
//
//  This file is part of the Blaze library. You can redistribute it and/or modify it under
//  the terms of the New (Revised) BSD License. Redistribution and use in source and binary
//  forms, with or without modification, are permitted provided that the following conditions
//  are met:
//
//  1. Redistributions of source code must retain the above copyright notice, this list of
//     conditions and the following disclaimer.
//  2. Redistributions in binary form must reproduce the above copyright notice, this list
//     of conditions and the following disclaimer in the documentation and/or other materials
//     provided with the distribution.
//  3. Neither the names of the Blaze development group nor the names of its contributors
//     may be used to endorse or promote products derived from this software without specific
//     prior written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
//  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
//  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
//  SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
//  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
//  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
//  DAMAGE.
*/
//=================================================================================================

//*************************************************************************************************
// Includes
//*************************************************************************************************

#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include <blaze/math/CompressedVector.h>
#include <blaze/math/DynamicMatrix.h>
#include <blaze/math/DynamicVector.h>
#include <blaze/math/Functions.h>
#include <blaze/math/Infinity.h>
#include <blaze/util/Random.h>
#include <blaze/util/Timing.h>
#include <blazemark/blaze/init/CompressedVector.h>
#include <blazemark/blaze/init/DynamicMatrix.h>
#include <blazemark/blaze/TSVecTDMatMult.h>
#include <blazemark/boost/TSVecTDMatMult.h>
#include <blazemark/system/Config.h>
#include <blazemark/system/Types.h>
#include <blazemark/util/Benchmarks.h>
#include <blazemark/util/DynamicSparseRun.h>
#include <blazemark/util/Indices.h>
#include <blazemark/util/Parser.h>

//*************************************************************************************************
// Using declarations
//*************************************************************************************************

using blazemark::Benchmarks;
using blazemark::DynamicSparseRun;
using blazemark::Parser;

//=================================================================================================
//
//  TYPE DEFINITIONS
//
//=================================================================================================

//*************************************************************************************************
/*!\brief Type of a benchmark run.
//
// This type definition specifies the type of a single benchmark run for the transpose sparse
// vector/transpose dense matrix multiplication benchmark.
*/
typedef DynamicSparseRun  Run;
//*************************************************************************************************

//=================================================================================================
//
//  UTILITY FUNCTIONS
//
//=================================================================================================

//*************************************************************************************************
/*!\brief Estimating the necessary number of steps for each benchmark.
//
// \param run The parameters for the benchmark run.
// \return void
//
// This function estimates the necessary number of steps for the given benchmark based on the
// performance of the Blaze library.
*/
void estimateSteps( Run& run )
{
   using blazemark::element_t;
   using blaze::rowVector;
   using blaze::columnMajor;

   ::blaze::setSeed( ::blazemark::seed );

   const size_t N( run.getSize() );
   const size_t F( run.getNonZeros() );

   blaze::CompressedVector<element_t,rowVector> a( N, F );
   blaze::DynamicMatrix<element_t,columnMajor> A( N, N );
   blaze::DynamicVector<element_t,rowVector> b( N );
   blaze::timing::WcTimer timer;
   double wct( 0.0 );
   size_t steps( 1UL );

   blazemark::blaze::init( a, F );
   blazemark::blaze::init( A );

   while( true ) {
      timer.start();
      for( size_t i=0UL; i<steps; ++i ) {
         b = a * A;
      }
      timer.end();
      wct = timer.last();
      if( wct >= 0.2 ) break;
      steps *= 2UL;
   }

   if( b.size() != N )
      std::cerr << " Line " << __LINE__ << ": ERROR detected!!!\n";

   run.setSteps( blaze::max( 1UL, ( blazemark::runtime * steps ) / timer.last() ) );
}
//*************************************************************************************************

//*************************************************************************************************
/*!\brief Estimating the necessary number of floating point operations.
//
// \param run The parameters for the benchmark run.
// \return void
//
// This function estimates the number of floating point operations required for a single
// computation of the (composite) arithmetic operation.
*/
void estimateFlops( Run& run )
{
   const size_t N( run.getSize()     );
   const size_t F( run.getNonZeros() );

   run.setFlops( 2UL*N*F - N );
}
//*************************************************************************************************

//=================================================================================================
//
//  BENCHMARK FUNCTIONS
//
//=================================================================================================

//*************************************************************************************************
/*!\brief Transpose sparse vector/transpose dense matrix multiplication benchmark function.
//
// \param runs The specified benchmark runs.
// \param benchmarks The selection of benchmarks.
// \return void
*/
void tsvectdmatmult( std::vector<Run>& runs, Benchmarks benchmarks )
{
   std::cout << std::left;

   std::sort( runs.begin(), runs.end() );

   size_t slowSize( blaze::inf );
   for( std::vector<Run>::iterator run=runs.begin(); run!=runs.end(); ++run )
   {
      estimateFlops( *run );

      if( run->getSteps() == 0UL ) {
         if( run->getSize() < slowSize ) {
            estimateSteps( *run );
            if( run->getSteps() == 1UL )
               slowSize = run->getSize();
         }
         else run->setSteps( 1UL );
      }
   }

   if( benchmarks.runBlaze ) {
      std::vector<Run>::iterator run=runs.begin();
      while( run != runs.end() ) {
         const float fill( run->getFillingDegree() );
         std::cout << "   Blaze (" << fill << "% filled) [MFlop/s]:\n";
         for( ; run!=runs.end(); ++run ) {
            if( run->getFillingDegree() != fill ) break;
            const size_t N    ( run->getSize()     );
            const size_t F    ( run->getNonZeros() );
            const size_t steps( run->getSteps()    );
            run->setBlazeResult( blazemark::blaze::tsvectdmatmult( N, F, steps ) );
            const double mflops( run->getSteps() * steps / run->getBlazeResult() / 1E6 );
            std::cout << "     " << std::setw(12) << N << mflops << std::endl;
         }
      }
   }

   if( benchmarks.runBoost ) {
      std::vector<Run>::iterator run=runs.begin();
      while( run != runs.end() ) {
         const float fill( run->getFillingDegree() );
         std::cout << "   Boost uBLAS (" << fill << "% filled) [MFlop/s]:\n";
         for( ; run!=runs.end(); ++run ) {
            if( run->getFillingDegree() != fill ) break;
            const size_t N    ( run->getSize()     );
            const size_t F    ( run->getNonZeros() );
            const size_t steps( run->getSteps()    );
            run->setBoostResult( blazemark::boost::tsvectdmatmult( N, F, steps ) );
            const double mflops( run->getSteps() * steps / run->getBoostResult() / 1E6 );
            std::cout << "     " << std::setw(12) << N << mflops << std::endl;
         }
      }
   }

   for( std::vector<Run>::iterator run=runs.begin(); run!=runs.end(); ++run ) {
      std::cout << *run;
   }
}
//*************************************************************************************************

//=================================================================================================
//
//  MAIN FUNCTION
//
//=================================================================================================

//*************************************************************************************************
/*!\brief The main function for the transpose sparse vector/dense matrix multiplication benchmark.
//
// \param argc The total number of command line arguments.
// \param argv The array of command line arguments.
// \return void
*/
int main( int argc, char** argv )
{
   std::cout << "\n Transpose Sparse Vector/Dense Matrix Multiplication:\n";

   Benchmarks benchmarks;

   try {
      parseCommandLineArguments( argc, argv, benchmarks );
   }
   catch( std::exception& ex ) {
      std::cerr << "   " << ex.what() << "\n";
      return EXIT_FAILURE;
   }

   const std::string installPath( INSTALL_PATH );
   const std::string parameterFile( installPath + "/params/tsvectdmatmult.prm" );
   Parser<Run> parser;
   std::vector<Run> runs;

   try {
      parser.parse( parameterFile.c_str(), runs );
   }
   catch( std::exception& ex ) {
      std::cerr << "   Error during parameter extraction: " << ex.what() << "\n";
      return EXIT_FAILURE;
   }

   try {
      tsvectdmatmult( runs, benchmarks );
   }
   catch( std::exception& ex ) {
      std::cerr << "   Error during benchmark execution: " << ex.what() << "\n";
      return EXIT_FAILURE;
   }
}
//*************************************************************************************************
<commit_msg>Fix the MFlops computation of the transpose sparse vector/transpose dense matrix ('TSVecTDMatMult') benchmark<commit_after>//=================================================================================================
/*!
//  \file src/blaze/TSVecTDMatMult.cpp
//  \brief Source file for the transpose sparse vector/transpose dense matrix multiplication benchmark
//
//  Copyright (C) 2013 Klaus Iglberger - All Rights Reserved
//
//  This file is part of the Blaze library. You can redistribute it and/or modify it under
//  the terms of the New (Revised) BSD License. Redistribution and use in source and binary
//  forms, with or without modification, are permitted provided that the following conditions
//  are met:
//
//  1. Redistributions of source code must retain the above copyright notice, this list of
//     conditions and the following disclaimer.
//  2. Redistributions in binary form must reproduce the above copyright notice, this list
//     of conditions and the following disclaimer in the documentation and/or other materials
//     provided with the distribution.
//  3. Neither the names of the Blaze development group nor the names of its contributors
//     may be used to endorse or promote products derived from this software without specific
//     prior written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
//  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
//  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
//  SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
//  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
//  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
//  DAMAGE.
*/
//=================================================================================================

//*************************************************************************************************
// Includes
//*************************************************************************************************

#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include <blaze/math/CompressedVector.h>
#include <blaze/math/DynamicMatrix.h>
#include <blaze/math/DynamicVector.h>
#include <blaze/math/Functions.h>
#include <blaze/math/Infinity.h>
#include <blaze/util/Random.h>
#include <blaze/util/Timing.h>
#include <blazemark/blaze/init/CompressedVector.h>
#include <blazemark/blaze/init/DynamicMatrix.h>
#include <blazemark/blaze/TSVecTDMatMult.h>
#include <blazemark/boost/TSVecTDMatMult.h>
#include <blazemark/system/Config.h>
#include <blazemark/system/Types.h>
#include <blazemark/util/Benchmarks.h>
#include <blazemark/util/DynamicSparseRun.h>
#include <blazemark/util/Indices.h>
#include <blazemark/util/Parser.h>

//*************************************************************************************************
// Using declarations
//*************************************************************************************************

using blazemark::Benchmarks;
using blazemark::DynamicSparseRun;
using blazemark::Parser;

//=================================================================================================
//
//  TYPE DEFINITIONS
//
//=================================================================================================

//*************************************************************************************************
/*!\brief Type of a benchmark run.
//
// This type definition specifies the type of a single benchmark run for the transpose sparse
// vector/transpose dense matrix multiplication benchmark.
*/
typedef DynamicSparseRun  Run;
//*************************************************************************************************

//=================================================================================================
//
//  UTILITY FUNCTIONS
//
//=================================================================================================

//*************************************************************************************************
/*!\brief Estimating the necessary number of steps for each benchmark.
//
// \param run The parameters for the benchmark run.
// \return void
//
// This function estimates the necessary number of steps for the given benchmark based on the
// performance of the Blaze library.
*/
void estimateSteps( Run& run )
{
   using blazemark::element_t;
   using blaze::rowVector;
   using blaze::columnMajor;

   ::blaze::setSeed( ::blazemark::seed );

   const size_t N( run.getSize() );
   const size_t F( run.getNonZeros() );

   blaze::CompressedVector<element_t,rowVector> a( N, F );
   blaze::DynamicMatrix<element_t,columnMajor> A( N, N );
   blaze::DynamicVector<element_t,rowVector> b( N );
   blaze::timing::WcTimer timer;
   double wct( 0.0 );
   size_t steps( 1UL );

   blazemark::blaze::init( a, F );
   blazemark::blaze::init( A );

   while( true ) {
      timer.start();
      for( size_t i=0UL; i<steps; ++i ) {
         b = a * A;
      }
      timer.end();
      wct = timer.last();
      if( wct >= 0.2 ) break;
      steps *= 2UL;
   }

   if( b.size() != N )
      std::cerr << " Line " << __LINE__ << ": ERROR detected!!!\n";

   run.setSteps( blaze::max( 1UL, ( blazemark::runtime * steps ) / timer.last() ) );
}
//*************************************************************************************************

//*************************************************************************************************
/*!\brief Estimating the necessary number of floating point operations.
//
// \param run The parameters for the benchmark run.
// \return void
//
// This function estimates the number of floating point operations required for a single
// computation of the (composite) arithmetic operation.
*/
void estimateFlops( Run& run )
{
   const size_t N( run.getSize()     );
   const size_t F( run.getNonZeros() );

   run.setFlops( 2UL*N*F - N );
}
//*************************************************************************************************

//=================================================================================================
//
//  BENCHMARK FUNCTIONS
//
//=================================================================================================

//*************************************************************************************************
/*!\brief Transpose sparse vector/transpose dense matrix multiplication benchmark function.
//
// \param runs The specified benchmark runs.
// \param benchmarks The selection of benchmarks.
// \return void
*/
void tsvectdmatmult( std::vector<Run>& runs, Benchmarks benchmarks )
{
   std::cout << std::left;

   std::sort( runs.begin(), runs.end() );

   size_t slowSize( blaze::inf );
   for( std::vector<Run>::iterator run=runs.begin(); run!=runs.end(); ++run )
   {
      estimateFlops( *run );

      if( run->getSteps() == 0UL ) {
         if( run->getSize() < slowSize ) {
            estimateSteps( *run );
            if( run->getSteps() == 1UL )
               slowSize = run->getSize();
         }
         else run->setSteps( 1UL );
      }
   }

   if( benchmarks.runBlaze ) {
      std::vector<Run>::iterator run=runs.begin();
      while( run != runs.end() ) {
         const float fill( run->getFillingDegree() );
         std::cout << "   Blaze (" << fill << "% filled) [MFlop/s]:\n";
         for( ; run!=runs.end(); ++run ) {
            if( run->getFillingDegree() != fill ) break;
            const size_t N    ( run->getSize()     );
            const size_t F    ( run->getNonZeros() );
            const size_t steps( run->getSteps()    );
            run->setBlazeResult( blazemark::blaze::tsvectdmatmult( N, F, steps ) );
            const double mflops( run->getFlops() * steps / run->getBlazeResult() / 1E6 );
            std::cout << "     " << std::setw(12) << N << mflops << std::endl;
         }
      }
   }

   if( benchmarks.runBoost ) {
      std::vector<Run>::iterator run=runs.begin();
      while( run != runs.end() ) {
         const float fill( run->getFillingDegree() );
         std::cout << "   Boost uBLAS (" << fill << "% filled) [MFlop/s]:\n";
         for( ; run!=runs.end(); ++run ) {
            if( run->getFillingDegree() != fill ) break;
            const size_t N    ( run->getSize()     );
            const size_t F    ( run->getNonZeros() );
            const size_t steps( run->getSteps()    );
            run->setBoostResult( blazemark::boost::tsvectdmatmult( N, F, steps ) );
            const double mflops( run->getFlops() * steps / run->getBoostResult() / 1E6 );
            std::cout << "     " << std::setw(12) << N << mflops << std::endl;
         }
      }
   }

   for( std::vector<Run>::iterator run=runs.begin(); run!=runs.end(); ++run ) {
      std::cout << *run;
   }
}
//*************************************************************************************************

//=================================================================================================
//
//  MAIN FUNCTION
//
//=================================================================================================

//*************************************************************************************************
/*!\brief The main function for the transpose sparse vector/transpose dense matrix multiplication
//        benchmark.
//
// \param argc The total number of command line arguments.
// \param argv The array of command line arguments.
// \return void
*/
int main( int argc, char** argv )
{
   std::cout << "\n Transpose Sparse Vector/Transpose Dense Matrix Multiplication:\n";

   Benchmarks benchmarks;

   try {
      parseCommandLineArguments( argc, argv, benchmarks );
   }
   catch( std::exception& ex ) {
      std::cerr << "   " << ex.what() << "\n";
      return EXIT_FAILURE;
   }

   const std::string installPath( INSTALL_PATH );
   const std::string parameterFile( installPath + "/params/tsvectdmatmult.prm" );
   Parser<Run> parser;
   std::vector<Run> runs;

   try {
      parser.parse( parameterFile.c_str(), runs );
   }
   catch( std::exception& ex ) {
      std::cerr << "   Error during parameter extraction: " << ex.what() << "\n";
      return EXIT_FAILURE;
   }

   try {
      tsvectdmatmult( runs, benchmarks );
   }
   catch( std::exception& ex ) {
      std::cerr << "   Error during benchmark execution: " << ex.what() << "\n";
      return EXIT_FAILURE;
   }
}
//*************************************************************************************************
<|endoftext|>


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

#include <gtest/gtest.h>

#include "../src/infill.h"
#include "ReadTestPolygons.h"

//#define TEST_INFILL_SVG_OUTPUT
#ifdef TEST_INFILL_SVG_OUTPUT
#include <cstdlib>
#include "../src/utils/SVG.h"
#endif //TEST_INFILL_SVG_OUTPUT

namespace cura
{
    template<typename ... Ts>
    std::string makeName(const std::string& format_string, Ts ... args)
    {
        constexpr int buff_size = 1024;
        char buff[buff_size];
        std::snprintf(buff, buff_size, format_string.c_str(), args...);
        return std::string(buff);
    }

    coord_t getPatternMultiplier(const EFillMethod& pattern)
    {
        switch (pattern)
        {
        case EFillMethod::GRID: // fallthrough
        case EFillMethod::TETRAHEDRAL: // fallthrough
        case EFillMethod::QUARTER_CUBIC:
            return 2;
        case EFillMethod::TRIANGLES: // fallthrough
        case EFillMethod::TRIHEXAGON: // fallthrough
        case EFillMethod::CUBIC: // fallthrough
        case EFillMethod::CUBICSUBDIV:
            return 3;
        default:
            return 1;
        }
    }

    struct InfillParameters
    {
    public:
        // Actual infill parameters:
        EFillMethod pattern;
        bool zig_zagify;
        bool connect_polygons;
        coord_t line_distance;

        std::string name;

        InfillParameters(const EFillMethod& pattern, const bool& zig_zagify, const bool& connect_polygons, const coord_t& line_distance) :
            pattern(pattern),
            zig_zagify(zig_zagify),
            connect_polygons(connect_polygons),
            line_distance(line_distance)
        {
            name = makeName("InfillParameters_%d_%d_%d_%lld", (int)pattern, (int)zig_zagify, (int)connect_polygons, line_distance);
        }
    };

    class InfillTestParameters
    {
    public:
        bool valid;  // <-- if the file isn't read (or anything else goes wrong with the setup) we can communicate it to the tests
        std::string fail_reason;
        size_t test_polygon_id;

        // Parameters used to generate the infill:
        InfillParameters params;
        Polygons outline_polygons;

        // Resulting infill:
        Polygons result_lines;
        Polygons result_polygons;

        std::string name;

        InfillTestParameters() :
            valid(false),
            fail_reason("Read of file with test polygons failed (see generateInfillTests), can't continue tests."),
            test_polygon_id(-1),
            params(InfillParameters(EFillMethod::NONE, false, false, 0)),
            outline_polygons(Polygons()),
            result_lines(Polygons()),
            result_polygons(Polygons()),
            name("UNNAMED")
        {
        }

        InfillTestParameters(const InfillParameters& params, const size_t& test_polygon_id, const Polygons& outline_polygons, const Polygons& result_lines, const Polygons& result_polygons) :
            valid(true),
            fail_reason("__"),
            test_polygon_id(test_polygon_id),
            params(params),
            outline_polygons(outline_polygons),
            result_lines(result_lines),
            result_polygons(result_polygons)
        {
            name = makeName("InfillTestParameters_P%d_Z%d_C%d_L%lld__%lld", (int)params.pattern, (int)params.zig_zagify, (int)params.connect_polygons, params.line_distance, test_polygon_id);
        }

        friend std::ostream& operator<<(std::ostream& os, const InfillTestParameters& params)
        {
            return os << params.name << "(" << (params.valid ? std::string("input OK") : params.fail_reason) << ")";
        }
    };

    constexpr coord_t infill_line_width = 350;
    constexpr coord_t infill_overlap = 0;
    constexpr size_t infill_multiplier = 1;
    const AngleDegrees fill_angle = 0.;
    constexpr coord_t z = 100; // Future improvement: Also take an uneven layer, so we get the alternate.
    constexpr coord_t shift = 0;
    constexpr coord_t max_resolution = 10;
    constexpr coord_t max_deviation = 5;
    const std::vector<std::string> polygon_filenames =
    {
        "../tests/resources/polygon_concave.txt",
        "../tests/resources/polygon_concave_hole.txt",
        "../tests/resources/polygon_square.txt",
        "../tests/resources/polygon_square_hole.txt",
        "../tests/resources/polygon_triangle.txt",
        "../tests/resources/polygon_two_squares.txt",
    };

#ifdef TEST_INFILL_SVG_OUTPUT
    void writeTestcaseSVG(const InfillTestParameters& params)
    {
        constexpr int buff_size = 1024;
        char buff[buff_size];
        std::snprintf(buff, buff_size, "/tmp/%s.svg", params.name.c_str());
        const std::string filename(buff);

        AABB aabb(params.outline_polygons);

        SVG svgFile(filename.c_str(), aabb);
        svgFile.writePolygons(params.outline_polygons , SVG::Color::BLUE);
        svgFile.nextLayer();
        svgFile.writePolylines(params.result_lines, SVG::Color::RED);
        svgFile.nextLayer();
        svgFile.writePolygons(params.result_polygons, SVG::Color::MAGENTA);
        // Note: SVG writes 'itself' when the object is destroyed.
    }
#endif //TEST_INFILL_SVG_OUTPUT

    InfillTestParameters generateInfillToTest(const InfillParameters& params, const size_t& test_polygon_id, const Polygons& outline_polygons)
    {
        const EFillMethod pattern = params.pattern;
        const bool zig_zagify = params.zig_zagify;
        const bool connect_polygons = params.connect_polygons;
        const coord_t line_distance = params.line_distance;

        Infill infill
        (
            pattern,
            zig_zagify,
            connect_polygons,
            outline_polygons,
            infill_line_width,
            line_distance,
            infill_overlap,
            infill_multiplier,
            fill_angle,
            z,
            shift,
            max_resolution,
            max_deviation
        ); // There are some optional parameters, but these will do for now (future improvement?).

        Settings infill_settings;
        std::vector<VariableWidthLines> result_paths;
        Polygons result_polygons;
        Polygons result_lines;
        infill.generate(result_paths, result_polygons, result_lines, infill_settings, nullptr, nullptr);

        InfillTestParameters result = InfillTestParameters(params, test_polygon_id, outline_polygons, result_lines, result_polygons);
        return result;
    }

    std::vector<InfillTestParameters> generateInfillTests()
    {
        constexpr bool do_zig_zaggify = true;
        constexpr bool dont_zig_zaggify = false;
        constexpr bool do_connect_polygons = true;
        constexpr bool dont_connect_polygons = false;

        std::vector<Polygons> shapes;
        if (!readTestPolygons(polygon_filenames, shapes))
        {
            return { InfillTestParameters() };  // return an invalid singleton, that'll trip up the 'file read' assertion in the TEST_P's
        }

        /* Skip methods:
         *  - that require the SierpinskyInfillProvider class, since these test classes aren't equipped to handle that yet
         *    this can be considered a TODO for these testcases here, not in the methods themselves
         *    (these are; Cross, Cross-3D and Cubic-Subdivision)
         *  - Gyroid, since it doesn't handle the 100% infill and related cases well
         *  - Concentric and ZigZag, since they now use a method that starts from an extra infill wall, which fail these tests (TODO!)
         */
        std::vector<EFillMethod> skip_methods = { EFillMethod::CONCENTRIC, EFillMethod::ZIG_ZAG, EFillMethod::CROSS, EFillMethod::CROSS_3D, EFillMethod::CUBICSUBDIV, EFillMethod::GYROID, EFillMethod::LIGHTNING };

        std::vector<EFillMethod> methods;
        for (int i_method = 0; i_method < static_cast<int>(EFillMethod::NONE); ++i_method)
        {
            const EFillMethod method = static_cast<EFillMethod>(i_method);
            if (std::find(skip_methods.begin(), skip_methods.end(), method) == skip_methods.end()) // Only use if not in skipped.
            {
                methods.push_back(method);
            }
        }

        std::vector<coord_t> line_distances = { 350, 400, 600, 800, 1200 };

        std::vector<InfillTestParameters> parameters_list;
        size_t test_polygon_id = 0;
        for (const Polygons& polygons : shapes)
        {
            for (const EFillMethod& method : methods)
            {
                for (const coord_t& line_distance : line_distances)
                {
                    parameters_list.push_back(generateInfillToTest(InfillParameters(method, dont_zig_zaggify, dont_connect_polygons, line_distance), test_polygon_id, polygons));
                    parameters_list.push_back(generateInfillToTest(InfillParameters(method, dont_zig_zaggify, do_connect_polygons, line_distance), test_polygon_id, polygons));
                    //parameters_list.push_back(generateInfillToTest(InfillParameters(method, do_zig_zaggify, dont_connect_polygons, line_distance), test_polygon_id, polygons));
                    //parameters_list.push_back(generateInfillToTest(InfillParameters(method, do_zig_zaggify, do_connect_polygons, line_distance), test_polygon_id, polygons));
                    // TODO: Re-enable when the extra infill walls are fully debugged or the discrepancy in the tests is explained.
                }
            }
            ++test_polygon_id;
        }

        return parameters_list;
    }

    class InfillTest : public testing::TestWithParam<InfillTestParameters> {};

    INSTANTIATE_TEST_CASE_P(InfillTestcases, InfillTest, testing::ValuesIn(generateInfillTests()), [](testing::TestParamInfo<InfillTestParameters> info) { return info.param.name; });

    TEST_P(InfillTest, TestInfillSanity)
    {
        InfillTestParameters params = GetParam();

#ifdef TEST_INFILL_SVG_OUTPUT
        writeTestcaseSVG(params);
#endif //TEST_INFILL_SVG_OUTPUT

        ASSERT_TRUE(params.valid) << params.fail_reason;
        ASSERT_FALSE(params.result_polygons.empty() && params.result_lines.empty()) << "Infill should have been generated.";

        double worst_case_zig_zag_added_area = 0;
        if (params.params.zig_zagify || params.params.pattern == EFillMethod::ZIG_ZAG)
        {
            worst_case_zig_zag_added_area = params.outline_polygons.polygonLength() * infill_line_width;
        }

        const double min_available_area = std::abs(params.outline_polygons.offset(-params.params.line_distance / 2).area());
        const double max_available_area = std::abs(params.outline_polygons.offset( params.params.line_distance / 2).area()) + worst_case_zig_zag_added_area;
        const double min_expected_infill_area = (min_available_area * infill_line_width) / params.params.line_distance;
        const double max_expected_infill_area = (max_available_area * infill_line_width) / params.params.line_distance + worst_case_zig_zag_added_area;

        const double out_infill_area = ((params.result_polygons.polygonLength() + params.result_lines.polyLineLength()) * infill_line_width) / getPatternMultiplier(params.params.pattern);

        ASSERT_GT((coord_t)max_available_area, (coord_t)out_infill_area) << "Infill area should allways be less than the total area available.";
        ASSERT_GT((coord_t)out_infill_area, (coord_t)min_expected_infill_area) << "Infill area should be greater than the minimum area expected to be covered.";
        ASSERT_LT((coord_t)out_infill_area, (coord_t)max_expected_infill_area) << "Infill area should be less than the maximum area to be covered.";

        const coord_t maximum_error = 10_mu; // potential rounding error
        const Polygons padded_shape_outline = params.outline_polygons.offset(infill_line_width / 2);
        constexpr bool restitch = false; // No need to restitch polylines - that would introduce stitching errors.
        ASSERT_LE(std::abs(padded_shape_outline.intersectionPolyLines(params.result_lines, restitch).polyLineLength() - params.result_lines.polyLineLength()), maximum_error) << "Infill (lines) should not be outside target polygon.";
        Polygons result_polygon_lines = params.result_polygons;
        for (PolygonRef poly : result_polygon_lines)
            poly.add(poly.front());
        ASSERT_LE(std::abs(padded_shape_outline.intersectionPolyLines(result_polygon_lines, restitch).polyLineLength() - result_polygon_lines.polyLineLength()), maximum_error) << "Infill (lines) should not be outside target polygon.";
    }

} //namespace cura
<commit_msg>Fix resource paths infill tests<commit_after>//Copyright (c) 2019 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include <gtest/gtest.h>
#include <filesystem>

#include "infill.h"
#include "ReadTestPolygons.h"

//#define TEST_INFILL_SVG_OUTPUT
#ifdef TEST_INFILL_SVG_OUTPUT
#include <cstdlib>
#include "utils/SVG.h"
#endif //TEST_INFILL_SVG_OUTPUT

namespace cura
{
    template<typename ... Ts>
    std::string makeName(const std::string& format_string, Ts ... args)
    {
        constexpr int buff_size = 1024;
        char buff[buff_size];
        std::snprintf(buff, buff_size, format_string.c_str(), args...);
        return std::string(buff);
    }

    coord_t getPatternMultiplier(const EFillMethod& pattern)
    {
        switch (pattern)
        {
        case EFillMethod::GRID: // fallthrough
        case EFillMethod::TETRAHEDRAL: // fallthrough
        case EFillMethod::QUARTER_CUBIC:
            return 2;
        case EFillMethod::TRIANGLES: // fallthrough
        case EFillMethod::TRIHEXAGON: // fallthrough
        case EFillMethod::CUBIC: // fallthrough
        case EFillMethod::CUBICSUBDIV:
            return 3;
        default:
            return 1;
        }
    }

    struct InfillParameters
    {
    public:
        // Actual infill parameters:
        EFillMethod pattern;
        bool zig_zagify;
        bool connect_polygons;
        coord_t line_distance;

        std::string name;

        InfillParameters(const EFillMethod& pattern, const bool& zig_zagify, const bool& connect_polygons, const coord_t& line_distance) :
            pattern(pattern),
            zig_zagify(zig_zagify),
            connect_polygons(connect_polygons),
            line_distance(line_distance)
        {
            name = makeName("InfillParameters_%d_%d_%d_%lld", (int)pattern, (int)zig_zagify, (int)connect_polygons, line_distance);
        }
    };

    class InfillTestParameters
    {
    public:
        bool valid;  // <-- if the file isn't read (or anything else goes wrong with the setup) we can communicate it to the tests
        std::string fail_reason;
        size_t test_polygon_id;

        // Parameters used to generate the infill:
        InfillParameters params;
        Polygons outline_polygons;

        // Resulting infill:
        Polygons result_lines;
        Polygons result_polygons;

        std::string name;

        InfillTestParameters() :
            valid(false),
            fail_reason("Read of file with test polygons failed (see generateInfillTests), can't continue tests."),
            test_polygon_id(-1),
            params(InfillParameters(EFillMethod::NONE, false, false, 0)),
            outline_polygons(Polygons()),
            result_lines(Polygons()),
            result_polygons(Polygons()),
            name("UNNAMED")
        {
        }

        InfillTestParameters(const InfillParameters& params, const size_t& test_polygon_id, const Polygons& outline_polygons, const Polygons& result_lines, const Polygons& result_polygons) :
            valid(true),
            fail_reason("__"),
            test_polygon_id(test_polygon_id),
            params(params),
            outline_polygons(outline_polygons),
            result_lines(result_lines),
            result_polygons(result_polygons)
        {
            name = makeName("InfillTestParameters_P%d_Z%d_C%d_L%lld__%lld", (int)params.pattern, (int)params.zig_zagify, (int)params.connect_polygons, params.line_distance, test_polygon_id);
        }

        friend std::ostream& operator<<(std::ostream& os, const InfillTestParameters& params)
        {
            return os << params.name << "(" << (params.valid ? std::string("input OK") : params.fail_reason) << ")";
        }
    };

    constexpr coord_t infill_line_width = 350;
    constexpr coord_t infill_overlap = 0;
    constexpr size_t infill_multiplier = 1;
    const AngleDegrees fill_angle = 0.;
    constexpr coord_t z = 100; // Future improvement: Also take an uneven layer, so we get the alternate.
    constexpr coord_t shift = 0;
    constexpr coord_t max_resolution = 10;
    constexpr coord_t max_deviation = 5;
    const std::vector<std::string> polygon_filenames =
    {
          std::filesystem::path(__FILE__).parent_path().append("resources/polygon_concave.txt").string(),
          std::filesystem::path(__FILE__).parent_path().append("resources/polygon_concave_hole.txt").string(),
          std::filesystem::path(__FILE__).parent_path().append("resources/polygon_square.txt").string(),
          std::filesystem::path(__FILE__).parent_path().append("resources/polygon_square_hole.txt").string(),
          std::filesystem::path(__FILE__).parent_path().append("resources/polygon_triangle.txt").string(),
          std::filesystem::path(__FILE__).parent_path().append("resources/polygon_two_squares.txt").string()
    };

#ifdef TEST_INFILL_SVG_OUTPUT
    void writeTestcaseSVG(const InfillTestParameters& params)
    {
        constexpr int buff_size = 1024;
        char buff[buff_size];
        std::snprintf(buff, buff_size, "/tmp/%s.svg", params.name.c_str());
        const std::string filename(buff);

        AABB aabb(params.outline_polygons);

        SVG svgFile(filename.c_str(), aabb);
        svgFile.writePolygons(params.outline_polygons , SVG::Color::BLUE);
        svgFile.nextLayer();
        svgFile.writePolylines(params.result_lines, SVG::Color::RED);
        svgFile.nextLayer();
        svgFile.writePolygons(params.result_polygons, SVG::Color::MAGENTA);
        // Note: SVG writes 'itself' when the object is destroyed.
    }
#endif //TEST_INFILL_SVG_OUTPUT

    InfillTestParameters generateInfillToTest(const InfillParameters& params, const size_t& test_polygon_id, const Polygons& outline_polygons)
    {
        const EFillMethod pattern = params.pattern;
        const bool zig_zagify = params.zig_zagify;
        const bool connect_polygons = params.connect_polygons;
        const coord_t line_distance = params.line_distance;

        Infill infill
        (
            pattern,
            zig_zagify,
            connect_polygons,
            outline_polygons,
            infill_line_width,
            line_distance,
            infill_overlap,
            infill_multiplier,
            fill_angle,
            z,
            shift,
            max_resolution,
            max_deviation
        ); // There are some optional parameters, but these will do for now (future improvement?).

        Settings infill_settings;
        std::vector<VariableWidthLines> result_paths;
        Polygons result_polygons;
        Polygons result_lines;
        infill.generate(result_paths, result_polygons, result_lines, infill_settings, nullptr, nullptr);

        InfillTestParameters result = InfillTestParameters(params, test_polygon_id, outline_polygons, result_lines, result_polygons);
        return result;
    }

    std::vector<InfillTestParameters> generateInfillTests()
    {
        constexpr bool do_zig_zaggify = true;
        constexpr bool dont_zig_zaggify = false;
        constexpr bool do_connect_polygons = true;
        constexpr bool dont_connect_polygons = false;

        std::vector<Polygons> shapes;
        if (!readTestPolygons(polygon_filenames, shapes))
        {
            return { InfillTestParameters() };  // return an invalid singleton, that'll trip up the 'file read' assertion in the TEST_P's
        }

        /* Skip methods:
         *  - that require the SierpinskyInfillProvider class, since these test classes aren't equipped to handle that yet
         *    this can be considered a TODO for these testcases here, not in the methods themselves
         *    (these are; Cross, Cross-3D and Cubic-Subdivision)
         *  - Gyroid, since it doesn't handle the 100% infill and related cases well
         *  - Concentric and ZigZag, since they now use a method that starts from an extra infill wall, which fail these tests (TODO!)
         */
        std::vector<EFillMethod> skip_methods = { EFillMethod::CONCENTRIC, EFillMethod::ZIG_ZAG, EFillMethod::CROSS, EFillMethod::CROSS_3D, EFillMethod::CUBICSUBDIV, EFillMethod::GYROID, EFillMethod::LIGHTNING };

        std::vector<EFillMethod> methods;
        for (int i_method = 0; i_method < static_cast<int>(EFillMethod::NONE); ++i_method)
        {
            const EFillMethod method = static_cast<EFillMethod>(i_method);
            if (std::find(skip_methods.begin(), skip_methods.end(), method) == skip_methods.end()) // Only use if not in skipped.
            {
                methods.push_back(method);
            }
        }

        std::vector<coord_t> line_distances = { 350, 400, 600, 800, 1200 };

        std::vector<InfillTestParameters> parameters_list;
        size_t test_polygon_id = 0;
        for (const Polygons& polygons : shapes)
        {
            for (const EFillMethod& method : methods)
            {
                for (const coord_t& line_distance : line_distances)
                {
                    parameters_list.push_back(generateInfillToTest(InfillParameters(method, dont_zig_zaggify, dont_connect_polygons, line_distance), test_polygon_id, polygons));
                    parameters_list.push_back(generateInfillToTest(InfillParameters(method, dont_zig_zaggify, do_connect_polygons, line_distance), test_polygon_id, polygons));
                    //parameters_list.push_back(generateInfillToTest(InfillParameters(method, do_zig_zaggify, dont_connect_polygons, line_distance), test_polygon_id, polygons));
                    //parameters_list.push_back(generateInfillToTest(InfillParameters(method, do_zig_zaggify, do_connect_polygons, line_distance), test_polygon_id, polygons));
                    // TODO: Re-enable when the extra infill walls are fully debugged or the discrepancy in the tests is explained.
                }
            }
            ++test_polygon_id;
        }

        return parameters_list;
    }

    class InfillTest : public testing::TestWithParam<InfillTestParameters> {};

    INSTANTIATE_TEST_CASE_P(InfillTestcases, InfillTest, testing::ValuesIn(generateInfillTests()), [](testing::TestParamInfo<InfillTestParameters> info) { return info.param.name; });

    TEST_P(InfillTest, TestInfillSanity)
    {
        InfillTestParameters params = GetParam();

#ifdef TEST_INFILL_SVG_OUTPUT
        writeTestcaseSVG(params);
#endif //TEST_INFILL_SVG_OUTPUT

        ASSERT_TRUE(params.valid) << params.fail_reason;
        ASSERT_FALSE(params.result_polygons.empty() && params.result_lines.empty()) << "Infill should have been generated.";

        double worst_case_zig_zag_added_area = 0;
        if (params.params.zig_zagify || params.params.pattern == EFillMethod::ZIG_ZAG)
        {
            worst_case_zig_zag_added_area = params.outline_polygons.polygonLength() * infill_line_width;
        }

        const double min_available_area = std::abs(params.outline_polygons.offset(-params.params.line_distance / 2).area());
        const double max_available_area = std::abs(params.outline_polygons.offset( params.params.line_distance / 2).area()) + worst_case_zig_zag_added_area;
        const double min_expected_infill_area = (min_available_area * infill_line_width) / params.params.line_distance;
        const double max_expected_infill_area = (max_available_area * infill_line_width) / params.params.line_distance + worst_case_zig_zag_added_area;

        const double out_infill_area = ((params.result_polygons.polygonLength() + params.result_lines.polyLineLength()) * infill_line_width) / getPatternMultiplier(params.params.pattern);

        ASSERT_GT((coord_t)max_available_area, (coord_t)out_infill_area) << "Infill area should allways be less than the total area available.";
        ASSERT_GT((coord_t)out_infill_area, (coord_t)min_expected_infill_area) << "Infill area should be greater than the minimum area expected to be covered.";
        ASSERT_LT((coord_t)out_infill_area, (coord_t)max_expected_infill_area) << "Infill area should be less than the maximum area to be covered.";

        const coord_t maximum_error = 10_mu; // potential rounding error
        const Polygons padded_shape_outline = params.outline_polygons.offset(infill_line_width / 2);
        constexpr bool restitch = false; // No need to restitch polylines - that would introduce stitching errors.
        ASSERT_LE(std::abs(padded_shape_outline.intersectionPolyLines(params.result_lines, restitch).polyLineLength() - params.result_lines.polyLineLength()), maximum_error) << "Infill (lines) should not be outside target polygon.";
        Polygons result_polygon_lines = params.result_polygons;
        for (PolygonRef poly : result_polygon_lines)
            poly.add(poly.front());
        ASSERT_LE(std::abs(padded_shape_outline.intersectionPolyLines(result_polygon_lines, restitch).polyLineLength() - result_polygon_lines.polyLineLength()), maximum_error) << "Infill (lines) should not be outside target polygon.";
    }

} //namespace cura
<|endoftext|>