<commit_before>/*=========================================================================
 Program:   ORFEO Toolbox
 Language:  C++
 Date:      $Date$
 Version:   $Revision$

 Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
 See OTBCopyright.txt for details.

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

 =========================================================================*/
#include "otbTrainVectorBase.h"

// Validation
#include "otbConfusionMatrixCalculator.h"

namespace otb
{
namespace Wrapper
{

class TrainVectorClassifier : public TrainVectorBase
{
public:
  typedef TrainVectorClassifier Self;
  typedef TrainVectorBase Superclass;
  typedef itk::SmartPointer<Self> Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;
  itkNewMacro( Self )

  itkTypeMacro( Self, Superclass )

  typedef Superclass::SampleType SampleType;
  typedef Superclass::ListSampleType ListSampleType;
  typedef Superclass::TargetListSampleType TargetListSampleType;

  // Estimate performance on validation sample
  typedef otb::ConfusionMatrixCalculator<TargetListSampleType, TargetListSampleType> ConfusionMatrixCalculatorType;
  typedef ConfusionMatrixCalculatorType::ConfusionMatrixType ConfusionMatrixType;
  typedef ConfusionMatrixCalculatorType::MapOfIndicesType MapOfIndicesType;
  typedef ConfusionMatrixCalculatorType::ClassLabelType ClassLabelType;

private:
  void DoTrainInit()
  {
    // Nothing to do here
  }

  void DoTrainUpdateParameters()
  {
    // Nothing to do here
  }

  void DoBeforeTrainExecute()
  {
    // Enforce the need of class field name in supervised mode
    if (GetClassifierCategory() == Supervised)
      {
      featuresInfo.SetClassFieldNames( GetChoiceNames( "cfield" ), GetSelectedItems( "cfield" ) );

      if( featuresInfo.m_SelectedCFieldIdx.empty() )
        {
        otbAppLogFATAL( << "No field has been selected for data labelling!" );
        }
      }
  }

  void DoAfterTrainExecute()
  {

    if (GetClassifierCategory() == Supervised)
      {
      ConfusionMatrixCalculatorType::Pointer confMatCalc = ComputeConfusionMatrix( predictedList,
                                                                                classificationListSamples.labeledListSample );
      WriteConfusionMatrix( confMatCalc );
      }
    else
      {
      // TODO Compute Contingency Table
      }
  }

  ConfusionMatrixCalculatorType::Pointer
  ComputeConfusionMatrix(const TargetListSampleType::Pointer &predictedListSample,
                         const TargetListSampleType::Pointer &performanceLabeledListSample)
  {
    ConfusionMatrixCalculatorType::Pointer confMatCalc = ConfusionMatrixCalculatorType::New();

    otbAppLogINFO( "Predicted list size : " << predictedListSample->Size() );
    otbAppLogINFO( "ValidationLabeledListSample size : " << performanceLabeledListSample->Size() );
    confMatCalc->SetReferenceLabels( performanceLabeledListSample );
    confMatCalc->SetProducedLabels( predictedListSample );
    confMatCalc->Compute();

    otbAppLogINFO( "training performances" );
    LogConfusionMatrix( confMatCalc );

    for( unsigned int itClasses = 0; itClasses < confMatCalc->GetNumberOfClasses(); itClasses++ )
      {
      ConfusionMatrixCalculatorType::ClassLabelType classLabel = confMatCalc->GetMapOfIndices()[itClasses];

      otbAppLogINFO( "Precision of class [" << classLabel << "] vs all: " << confMatCalc->GetPrecisions()[itClasses] );
      otbAppLogINFO( "Recall of class    [" << classLabel << "] vs all: " << confMatCalc->GetRecalls()[itClasses] );
      otbAppLogINFO(
              "F-score of class   [" << classLabel << "] vs all: " << confMatCalc->GetFScores()[itClasses] << "\n" );
      }
    otbAppLogINFO( "Global performance, Kappa index: " << confMatCalc->GetKappaIndex() );
    return confMatCalc;
  }

  /**
   * Write the confidence matrix into a file if output is provided.
   * \param confMatCalc the input matrix to write.
   */
  void WriteConfusionMatrix(const ConfusionMatrixCalculatorType::Pointer &confMatCalc)
  {
    if( this->HasValue( "io.confmatout" ) )
      {
      // Writing the confusion matrix in the output .CSV file

      MapOfIndicesType::iterator itMapOfIndicesValid, itMapOfIndicesPred;
      ClassLabelType labelValid = 0;

      ConfusionMatrixType confusionMatrix = confMatCalc->GetConfusionMatrix();
      MapOfIndicesType mapOfIndicesValid = confMatCalc->GetMapOfIndices();

      unsigned long nbClassesPred = mapOfIndicesValid.size();

      /////////////////////////////////////////////
      // Filling the 2 headers for the output file
      const std::string commentValidStr = "#Reference labels (rows):";
      const std::string commentPredStr = "#Produced labels (columns):";
      const char separatorChar = ',';
      std::ostringstream ossHeaderValidLabels, ossHeaderPredLabels;

      // Filling ossHeaderValidLabels and ossHeaderPredLabels for the output file
      ossHeaderValidLabels << commentValidStr;
      ossHeaderPredLabels << commentPredStr;

      itMapOfIndicesValid = mapOfIndicesValid.begin();

      while( itMapOfIndicesValid != mapOfIndicesValid.end() )
        {
        // labels labelValid of mapOfIndicesValid are already sorted in otbConfusionMatrixCalculator
        labelValid = itMapOfIndicesValid->second;

        otbAppLogINFO( "mapOfIndicesValid[" << itMapOfIndicesValid->first << "] = " << labelValid );

        ossHeaderValidLabels << labelValid;
        ossHeaderPredLabels << labelValid;

        ++itMapOfIndicesValid;

        if( itMapOfIndicesValid != mapOfIndicesValid.end() )
          {
          ossHeaderValidLabels << separatorChar;
          ossHeaderPredLabels << separatorChar;
          }
        else
          {
          ossHeaderValidLabels << std::endl;
          ossHeaderPredLabels << std::endl;
          }
        }

      std::ofstream outFile;
      outFile.open( this->GetParameterString( "io.confmatout" ).c_str() );
      outFile << std::fixed;
      outFile.precision( 10 );

      /////////////////////////////////////
      // Writing the 2 headers
      outFile << ossHeaderValidLabels.str();
      outFile << ossHeaderPredLabels.str();
      /////////////////////////////////////

      unsigned int indexLabelValid = 0, indexLabelPred = 0;

      for( itMapOfIndicesValid = mapOfIndicesValid.begin();
           itMapOfIndicesValid != mapOfIndicesValid.end(); ++itMapOfIndicesValid )
        {
        indexLabelPred = 0;

        for( itMapOfIndicesPred = mapOfIndicesValid.begin();
             itMapOfIndicesPred != mapOfIndicesValid.end(); ++itMapOfIndicesPred )
          {
          // Writing the confusion matrix (sorted in otbConfusionMatrixCalculator) in the output file
          outFile << confusionMatrix( indexLabelValid, indexLabelPred );
          if( indexLabelPred < ( nbClassesPred - 1 ) )
            {
            outFile << separatorChar;
            }
          else
            {
            outFile << std::endl;
            }
          ++indexLabelPred;
          }

        ++indexLabelValid;
        }

      outFile.close();
      }
  }

  /**
   * Display the log of the confusion matrix computed with
   * \param confMatCalc the input confusion matrix to display
   */
  void LogConfusionMatrix(ConfusionMatrixCalculatorType *confMatCalc)
  {
    ConfusionMatrixCalculatorType::ConfusionMatrixType matrix = confMatCalc->GetConfusionMatrix();

    // Compute minimal width
    size_t minwidth = 0;

    for( unsigned int i = 0; i < matrix.Rows(); i++ )
      {
      for( unsigned int j = 0; j < matrix.Cols(); j++ )
        {
        std::ostringstream os;
        os << matrix( i, j );
        size_t size = os.str().size();

        if( size > minwidth )
          {
          minwidth = size;
          }
        }
      }

    MapOfIndicesType mapOfIndices = confMatCalc->GetMapOfIndices();

    MapOfIndicesType::const_iterator it = mapOfIndices.begin();
    MapOfIndicesType::const_iterator end = mapOfIndices.end();

    for( ; it != end; ++it )
      {
      std::ostringstream os;
      os << "[" << it->second << "]";

      size_t size = os.str().size();
      if( size > minwidth )
        {
        minwidth = size;
        }
      }

    // Generate matrix string, with 'minwidth' as size specifier
    std::ostringstream os;

    // Header line
    for( size_t i = 0; i < minwidth; ++i )
      os << " ";
    os << " ";

    it = mapOfIndices.begin();
    end = mapOfIndices.end();
    for( ; it != end; ++it )
      {
      os << "[" << it->second << "]" << " ";
      }

    os << std::endl;

    // Each line of confusion matrix
    for( unsigned int i = 0; i < matrix.Rows(); i++ )
      {
      ConfusionMatrixCalculatorType::ClassLabelType label = mapOfIndices[i];
      os << "[" << std::setw( minwidth - 2 ) << label << "]" << " ";
      for( unsigned int j = 0; j < matrix.Cols(); j++ )
        {
        os << std::setw( minwidth ) << matrix( i, j ) << " ";
        }
      os << std::endl;
      }

    otbAppLogINFO( "Confusion matrix (rows = reference labels, columns = produced labels):\n" << os.str() );
  }

};
}
}

OTB_APPLICATION_EXPORT( otb::Wrapper::TrainVectorClassifier )
<commit_msg>ENH: Compute and write contingency table.<commit_after>/*=========================================================================
 Program:   ORFEO Toolbox
 Language:  C++
 Date:      $Date$
 Version:   $Revision$

 Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
 See OTBCopyright.txt for details.

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

 =========================================================================*/
#include "otbTrainVectorBase.h"

// Validation
#include "otbConfusionMatrixCalculator.h"
#include "otbContingencyTableCalculator.h"

namespace otb
{
namespace Wrapper
{

class TrainVectorClassifier : public TrainVectorBase
{
public:
  typedef TrainVectorClassifier Self;
  typedef TrainVectorBase Superclass;
  typedef itk::SmartPointer<Self> Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;
  itkNewMacro( Self )

  itkTypeMacro( Self, Superclass )

  typedef Superclass::SampleType SampleType;
  typedef Superclass::ListSampleType ListSampleType;
  typedef Superclass::TargetListSampleType TargetListSampleType;

  // Estimate performance on validation sample
  typedef otb::ConfusionMatrixCalculator<TargetListSampleType, TargetListSampleType> ConfusionMatrixCalculatorType;
  typedef ConfusionMatrixCalculatorType::ConfusionMatrixType ConfusionMatrixType;
  typedef ConfusionMatrixCalculatorType::MapOfIndicesType MapOfIndicesType;
  typedef ConfusionMatrixCalculatorType::ClassLabelType ClassLabelType;

private:
  void DoTrainInit()
  {
    // Nothing to do here
  }

  void DoTrainUpdateParameters()
  {
    // Nothing to do here
  }

  void DoBeforeTrainExecute()
  {
    // Enforce the need of class field name in supervised mode
    if (GetClassifierCategory() == Supervised)
      {
      featuresInfo.SetClassFieldNames( GetChoiceNames( "cfield" ), GetSelectedItems( "cfield" ) );

      if( featuresInfo.m_SelectedCFieldIdx.empty() )
        {
        otbAppLogFATAL( << "No field has been selected for data labelling!" );
        }
      }
  }

  void DoAfterTrainExecute()
  {

    if (GetClassifierCategory() == Supervised)
      {
      ConfusionMatrixCalculatorType::Pointer confMatCalc = ComputeConfusionMatrix( predictedList,
                                                                                classificationListSamples.labeledListSample );
      WriteConfusionMatrix( confMatCalc );
      }
    else
      {
      WriteContingencyTable();
      }
  }

  void WriteContingencyTable()
  {
    // Compute contingency table
    typedef ContingencyTableCalculator<ClassLabelType> ContigencyTableCalcutaltorType;
    ContigencyTableCalcutaltorType::Pointer contingencyTableCalculator = ContigencyTableCalcutaltorType::New();
    contingencyTableCalculator->Compute(predictedList->Begin(), predictedList->End(),
                                        classificationListSamples.labeledListSample->Begin(),
                                        classificationListSamples.labeledListSample->End());
    ContingencyTable<ClassLabelType> contingencyTable = contingencyTableCalculator->GetContingencyTable();

    // Write contingency table
    std::ofstream outFile;
    outFile.open( this->GetParameterString( "io.confmatout" ).c_str() );
    outFile << contingencyTable.to_csv();
  }

  ConfusionMatrixCalculatorType::Pointer
  ComputeConfusionMatrix(const TargetListSampleType::Pointer &predictedListSample,
                         const TargetListSampleType::Pointer &performanceLabeledListSample)
  {
    ConfusionMatrixCalculatorType::Pointer confMatCalc = ConfusionMatrixCalculatorType::New();

    otbAppLogINFO( "Predicted list size : " << predictedListSample->Size() );
    otbAppLogINFO( "ValidationLabeledListSample size : " << performanceLabeledListSample->Size() );
    confMatCalc->SetReferenceLabels( performanceLabeledListSample );
    confMatCalc->SetProducedLabels( predictedListSample );
    confMatCalc->Compute();

    otbAppLogINFO( "training performances" );
    LogConfusionMatrix( confMatCalc );

    for( unsigned int itClasses = 0; itClasses < confMatCalc->GetNumberOfClasses(); itClasses++ )
      {
      ConfusionMatrixCalculatorType::ClassLabelType classLabel = confMatCalc->GetMapOfIndices()[itClasses];

      otbAppLogINFO( "Precision of class [" << classLabel << "] vs all: " << confMatCalc->GetPrecisions()[itClasses] );
      otbAppLogINFO( "Recall of class    [" << classLabel << "] vs all: " << confMatCalc->GetRecalls()[itClasses] );
      otbAppLogINFO(
              "F-score of class   [" << classLabel << "] vs all: " << confMatCalc->GetFScores()[itClasses] << "\n" );
      }
    otbAppLogINFO( "Global performance, Kappa index: " << confMatCalc->GetKappaIndex() );
    return confMatCalc;
  }

  /**
   * Write the confidence matrix into a file if output is provided.
   * \param confMatCalc the input matrix to write.
   */
  void WriteConfusionMatrix(const ConfusionMatrixCalculatorType::Pointer &confMatCalc)
  {
    if( this->HasValue( "io.confmatout" ) )
      {
      // Writing the confusion matrix in the output .CSV file

      MapOfIndicesType::iterator itMapOfIndicesValid, itMapOfIndicesPred;
      ClassLabelType labelValid = 0;

      ConfusionMatrixType confusionMatrix = confMatCalc->GetConfusionMatrix();
      MapOfIndicesType mapOfIndicesValid = confMatCalc->GetMapOfIndices();

      unsigned long nbClassesPred = mapOfIndicesValid.size();

      /////////////////////////////////////////////
      // Filling the 2 headers for the output file
      const std::string commentValidStr = "#Reference labels (rows):";
      const std::string commentPredStr = "#Produced labels (columns):";
      const char separatorChar = ',';
      std::ostringstream ossHeaderValidLabels, ossHeaderPredLabels;

      // Filling ossHeaderValidLabels and ossHeaderPredLabels for the output file
      ossHeaderValidLabels << commentValidStr;
      ossHeaderPredLabels << commentPredStr;

      itMapOfIndicesValid = mapOfIndicesValid.begin();

      while( itMapOfIndicesValid != mapOfIndicesValid.end() )
        {
        // labels labelValid of mapOfIndicesValid are already sorted in otbConfusionMatrixCalculator
        labelValid = itMapOfIndicesValid->second;

        otbAppLogINFO( "mapOfIndicesValid[" << itMapOfIndicesValid->first << "] = " << labelValid );

        ossHeaderValidLabels << labelValid;
        ossHeaderPredLabels << labelValid;

        ++itMapOfIndicesValid;

        if( itMapOfIndicesValid != mapOfIndicesValid.end() )
          {
          ossHeaderValidLabels << separatorChar;
          ossHeaderPredLabels << separatorChar;
          }
        else
          {
          ossHeaderValidLabels << std::endl;
          ossHeaderPredLabels << std::endl;
          }
        }

      std::ofstream outFile;
      outFile.open( this->GetParameterString( "io.confmatout" ).c_str() );
      outFile << std::fixed;
      outFile.precision( 10 );

      /////////////////////////////////////
      // Writing the 2 headers
      outFile << ossHeaderValidLabels.str();
      outFile << ossHeaderPredLabels.str();
      /////////////////////////////////////

      unsigned int indexLabelValid = 0, indexLabelPred = 0;

      for( itMapOfIndicesValid = mapOfIndicesValid.begin();
           itMapOfIndicesValid != mapOfIndicesValid.end(); ++itMapOfIndicesValid )
        {
        indexLabelPred = 0;

        for( itMapOfIndicesPred = mapOfIndicesValid.begin();
             itMapOfIndicesPred != mapOfIndicesValid.end(); ++itMapOfIndicesPred )
          {
          // Writing the confusion matrix (sorted in otbConfusionMatrixCalculator) in the output file
          outFile << confusionMatrix( indexLabelValid, indexLabelPred );
          if( indexLabelPred < ( nbClassesPred - 1 ) )
            {
            outFile << separatorChar;
            }
          else
            {
            outFile << std::endl;
            }
          ++indexLabelPred;
          }

        ++indexLabelValid;
        }

      outFile.close();
      }
  }

  /**
   * Display the log of the confusion matrix computed with
   * \param confMatCalc the input confusion matrix to display
   */
  void LogConfusionMatrix(ConfusionMatrixCalculatorType *confMatCalc)
  {
    ConfusionMatrixCalculatorType::ConfusionMatrixType matrix = confMatCalc->GetConfusionMatrix();

    // Compute minimal width
    size_t minwidth = 0;

    for( unsigned int i = 0; i < matrix.Rows(); i++ )
      {
      for( unsigned int j = 0; j < matrix.Cols(); j++ )
        {
        std::ostringstream os;
        os << matrix( i, j );
        size_t size = os.str().size();

        if( size > minwidth )
          {
          minwidth = size;
          }
        }
      }

    MapOfIndicesType mapOfIndices = confMatCalc->GetMapOfIndices();

    MapOfIndicesType::const_iterator it = mapOfIndices.begin();
    MapOfIndicesType::const_iterator end = mapOfIndices.end();

    for( ; it != end; ++it )
      {
      std::ostringstream os;
      os << "[" << it->second << "]";

      size_t size = os.str().size();
      if( size > minwidth )
        {
        minwidth = size;
        }
      }

    // Generate matrix string, with 'minwidth' as size specifier
    std::ostringstream os;

    // Header line
    for( size_t i = 0; i < minwidth; ++i )
      os << " ";
    os << " ";

    it = mapOfIndices.begin();
    end = mapOfIndices.end();
    for( ; it != end; ++it )
      {
      os << "[" << it->second << "]" << " ";
      }

    os << std::endl;

    // Each line of confusion matrix
    for( unsigned int i = 0; i < matrix.Rows(); i++ )
      {
      ConfusionMatrixCalculatorType::ClassLabelType label = mapOfIndices[i];
      os << "[" << std::setw( minwidth - 2 ) << label << "]" << " ";
      for( unsigned int j = 0; j < matrix.Cols(); j++ )
        {
        os << std::setw( minwidth ) << matrix( i, j ) << " ";
        }
      os << std::endl;
      }

    otbAppLogINFO( "Confusion matrix (rows = reference labels, columns = produced labels):\n" << os.str() );
  }

};
}
}

OTB_APPLICATION_EXPORT( otb::Wrapper::TrainVectorClassifier )
<|endoftext|>


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

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

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

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

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

#include "otbImage.h"
#include "otbImageToNoDataMaskFilter.h"
#include "itkImageRegionIterator.h"

int otbImageToNoDataMaskFilter(int itkNotUsed(argc),char * itkNotUsed(argv) [])
{

  // Build an image
  typedef otb::Image<double> ImageType;
  ImageType::Pointer img = ImageType::New();

  ImageType::SizeType size;
  size.Fill(20);

  ImageType::RegionType region;
  region.SetSize(size);

  // Fill it with a default value
  img->SetRegions(region);
  img->Allocate();
  img->FillBuffer(10);

  // Write no-data flags to it
  std::vector<bool> flags(1,true);
  std::vector<double> values(1,-10.);
  otb::WriteNoDataFlags(flags,values,img->GetMetaDataDictionary());

  // Fill half of the pixels with no-data values
  itk::ImageRegionIterator<ImageType> it(img,region);
  unsigned int count = 0;
  for(it.GoToBegin();!it.IsAtEnd();++it,++count)
    {
    if (count%2 == 0)
      it.Set(-10.);
    }

  // Instanciate filter
  typedef otb::ImageToNoDataMaskFilter<ImageType,ImageType> FilterType;
  FilterType::Pointer filter = FilterType::New();

  filter->SetInput(img);
  filter->SetInsideValue(255);
  filter->SetOutsideValue(0);
  filter->Update();

  // Check output
  it = itk::ImageRegionIterator<ImageType>(filter->GetOutput(),region);
  count = 0;

  bool failed = false;

  for(it.GoToBegin();!it.IsAtEnd();++it,++count)
    {
    if (count%2 == 0 and it.Get()!=0)
      {
      std::cerr<<"Pixel should be masked"<<std::endl;
      failed = true;
      }
    else if(count%2 == 1 and it.Get()!=255)
      {
      std::cerr<<"Pixel should not be masked"<<std::endl;
      failed = true;
      }
    }

  if(failed)
    return EXIT_FAILURE;

  return EXIT_SUCCESS;
}
<commit_msg>COMP: replace and by && for win32<commit_after>/*=========================================================================

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

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

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

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

#include "otbImage.h"
#include "otbImageToNoDataMaskFilter.h"
#include "itkImageRegionIterator.h"

int otbImageToNoDataMaskFilter(int itkNotUsed(argc),char * itkNotUsed(argv) [])
{

  // Build an image
  typedef otb::Image<double> ImageType;
  ImageType::Pointer img = ImageType::New();

  ImageType::SizeType size;
  size.Fill(20);

  ImageType::RegionType region;
  region.SetSize(size);

  // Fill it with a default value
  img->SetRegions(region);
  img->Allocate();
  img->FillBuffer(10);

  // Write no-data flags to it
  std::vector<bool> flags(1,true);
  std::vector<double> values(1,-10.);
  otb::WriteNoDataFlags(flags,values,img->GetMetaDataDictionary());

  // Fill half of the pixels with no-data values
  itk::ImageRegionIterator<ImageType> it(img,region);
  unsigned int count = 0;
  for(it.GoToBegin();!it.IsAtEnd();++it,++count)
    {
    if (count%2 == 0)
      it.Set(-10.);
    }

  // Instanciate filter
  typedef otb::ImageToNoDataMaskFilter<ImageType,ImageType> FilterType;
  FilterType::Pointer filter = FilterType::New();

  filter->SetInput(img);
  filter->SetInsideValue(255);
  filter->SetOutsideValue(0);
  filter->Update();

  // Check output
  it = itk::ImageRegionIterator<ImageType>(filter->GetOutput(),region);
  count = 0;

  bool failed = false;

  for(it.GoToBegin();!it.IsAtEnd();++it,++count)
    {
    if (count%2 == 0 && it.Get()!=0)
      {
      std::cerr<<"Pixel should be masked"<<std::endl;
      failed = true;
      }
    else if(count%2 == 1 && it.Get()!=255)
      {
      std::cerr<<"Pixel should not be masked"<<std::endl;
      failed = true;
      }
    }

  if(failed)
    return EXIT_FAILURE;

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>
#include "SchedulingManagerFactory.h"
#include "TimeWarpEventSetFactory.h"
#include "TimeWarpSimulationManager.h"
#include "SimulationConfiguration.h"
#include "SchedulingManager.h"
#include "DefaultSchedulingManager.h"
#include "TimeWarpMultiSetSchedulingManager.h"
#include <WarpedDebug.h>
/*
#if USE_TIMEWARP
#include "threadedtimewarp/ThreadedTimeWarpSimulationManager.h"
#include "threadedtimewarp/ThreadedSchedulingManager.h"
#endif
*/
#include "ThreadedTimeWarpSimulationManager.h"
#include "ThreadedTimeWarpMultiSetSchedulingManager.h"
using std::cerr;
using std::endl;

SchedulingManagerFactory::SchedulingManagerFactory(){}

SchedulingManagerFactory::~SchedulingManagerFactory(){
  // myScheduler will be deleted by the end user - the
  // TimeWarpSimulationManager
}

Configurable *
SchedulingManagerFactory::allocate( SimulationConfiguration &configuration,
				    Configurable *parent ) const {

  SchedulingManager *retval = 0;

  std::string simulationType = configuration.get_string({"Simulation"}, "Sequential");
  std::string schedulerType = configuration.get_string({"TimeWarp", "Scheduler", "Type"},
                                                        "Default");

  if(schedulerType == "MultiSet"){
    TimeWarpSimulationManager *mySimulationManager = dynamic_cast<TimeWarpSimulationManager *>( parent );
    ASSERT(mySimulationManager!=0);
    retval = new TimeWarpMultiSetSchedulingManager( mySimulationManager );
    debug::debugout << " a TimeWarpMultiSetSchedulingManager." << endl;
  } else {
    dynamic_cast<TimeWarpSimulationManager *>(parent)->shutdown(
       "Unknown SCHEDULER choice \"" + schedulerType + "\"" );
  }

#if USE_TIMEWARP
	if (simulationType == "ThreadedTimeWarp") {
		if (schedulerType == "MultiSet") {
			ThreadedTimeWarpSimulationManager *mySimulationManager =
					dynamic_cast<ThreadedTimeWarpSimulationManager *> (parent);
			ASSERT(mySimulationManager!=0);
			retval = new ThreadedTimeWarpMultiSetSchedulingManager(mySimulationManager);
			debug::debugout << " a Threaded TimeWarpMultiSetSchedulingManager." << endl;
		} else {
			dynamic_cast<TimeWarpSimulationManager *> (parent)->shutdown(
					"Unknown SCHEDULER choice \"" + schedulerType + "\"");
		}
	}
#endif

  return retval;
}

const SchedulingManagerFactory *
SchedulingManagerFactory::instance(){
  static SchedulingManagerFactory *singleton = new SchedulingManagerFactory();
  return singleton;
}
<commit_msg>Removed USE_TIMEWARP macro usage<commit_after>
#include "SchedulingManagerFactory.h"
#include "TimeWarpEventSetFactory.h"
#include "TimeWarpSimulationManager.h"
#include "SimulationConfiguration.h"
#include "SchedulingManager.h"
#include "DefaultSchedulingManager.h"
#include "TimeWarpMultiSetSchedulingManager.h"
#include <WarpedDebug.h>

#include "ThreadedTimeWarpSimulationManager.h"
#include "ThreadedTimeWarpMultiSetSchedulingManager.h"
using std::cerr;
using std::endl;

SchedulingManagerFactory::SchedulingManagerFactory(){}

SchedulingManagerFactory::~SchedulingManagerFactory(){
  // myScheduler will be deleted by the end user - the
  // TimeWarpSimulationManager
}

Configurable *
SchedulingManagerFactory::allocate( SimulationConfiguration &configuration,
				    Configurable *parent ) const {

  SchedulingManager *retval = 0;

  std::string simulationType = configuration.get_string({"Simulation"}, "Sequential");
  std::string schedulerType = configuration.get_string({"TimeWarp", "Scheduler", "Type"},
                                                        "Default");

  if(schedulerType == "MultiSet"){
    TimeWarpSimulationManager *mySimulationManager = dynamic_cast<TimeWarpSimulationManager *>( parent );
    ASSERT(mySimulationManager!=0);
    retval = new TimeWarpMultiSetSchedulingManager( mySimulationManager );
    debug::debugout << " a TimeWarpMultiSetSchedulingManager." << endl;
  } else {
    dynamic_cast<TimeWarpSimulationManager *>(parent)->shutdown(
       "Unknown SCHEDULER choice \"" + schedulerType + "\"" );
  }

	if (simulationType == "ThreadedTimeWarp") {
		if (schedulerType == "MultiSet") {
			ThreadedTimeWarpSimulationManager *mySimulationManager =
					dynamic_cast<ThreadedTimeWarpSimulationManager *> (parent);
			ASSERT(mySimulationManager!=0);
			retval = new ThreadedTimeWarpMultiSetSchedulingManager(mySimulationManager);
			debug::debugout << " a Threaded TimeWarpMultiSetSchedulingManager." << endl;
		} else {
			dynamic_cast<TimeWarpSimulationManager *> (parent)->shutdown(
					"Unknown SCHEDULER choice \"" + schedulerType + "\"");
		}
	}

  return retval;
}

const SchedulingManagerFactory *
SchedulingManagerFactory::instance(){
  static SchedulingManagerFactory *singleton = new SchedulingManagerFactory();
  return singleton;
}
<|endoftext|>


<commit_before>#include "nxtKitInterpreterPlugin.h"

#include <QtWidgets/QApplication>

#include <twoDModel/engine/twoDModelEngineFacade.h>

using namespace nxt;
using namespace qReal;

const Id robotDiagramType = Id("RobotsMetamodel", "RobotsDiagram", "RobotsDiagramNode");
const Id subprogramDiagramType = Id("RobotsMetamodel", "RobotsDiagram", "SubprogramDiagram");

NxtKitInterpreterPlugin::NxtKitInterpreterPlugin()
	: mUsbRealRobotModel(kitId(), "nxtKitUsbRobot") // todo: somewhere generate robotId for each robot
	, mBluetoothRealRobotModel(kitId(), "nxtKitBluetoothRobot")
	, mTwoDRobotModel(mUsbRealRobotModel)
	, mBlocksFactory(new blocks::NxtBlocksFactory)
{
	mAdditionalPreferences = new NxtAdditionalPreferences(mBluetoothRealRobotModel.name());

	auto modelEngine = new twoDModel::engine::TwoDModelEngineFacade(mTwoDRobotModel);

	mTwoDRobotModel.setEngine(modelEngine->engine());
	mTwoDModel.reset(modelEngine);

	connect(mAdditionalPreferences, &NxtAdditionalPreferences::settingsChanged
			, &mUsbRealRobotModel, &robotModel::real::RealRobotModel::rereadSettings);
	connect(mAdditionalPreferences, &NxtAdditionalPreferences::settingsChanged
			, &mBluetoothRealRobotModel, &robotModel::real::RealRobotModel::rereadSettings);
	connect(mAdditionalPreferences, &NxtAdditionalPreferences::settingsChanged
			, &mTwoDRobotModel, &robotModel::twoD::TwoDRobotModel::rereadSettings);
}

NxtKitInterpreterPlugin::~NxtKitInterpreterPlugin()
{
	if (mOwnsAdditionalPreferences) {
		delete mAdditionalPreferences;
	}

	if (mOwnsBlocksFactory) {
		delete mBlocksFactory;
	}
}

void NxtKitInterpreterPlugin::init(const kitBase::KitPluginConfigurator &configurator)
{
	connect(&configurator.eventsForKitPlugin(), &kitBase::EventsForKitPluginInterface::robotModelChanged
			, [this](const QString &modelName) { mCurrentlySelectedModelName = modelName; });

	connect(&configurator.qRealConfigurator().systemEvents(), &qReal::SystemEvents::activeTabChanged
			, this, &NxtKitInterpreterPlugin::onActiveTabChanged);

	qReal::gui::MainWindowInterpretersInterface &interpretersInterface
			= configurator.qRealConfigurator().mainWindowInterpretersInterface();
	connect(&mUsbRealRobotModel, &robotModel::real::RealRobotModel::errorOccured
			, [&interpretersInterface](const QString &message) {
				interpretersInterface.errorReporter()->addError(message);
	});
	connect(&mBluetoothRealRobotModel, &robotModel::real::RealRobotModel::errorOccured
			, [&interpretersInterface](const QString &message) {
				interpretersInterface.errorReporter()->addError(message);
	});
	mUsbRealRobotModel.checkConnection();
	mBluetoothRealRobotModel.checkConnection();

	mTwoDModel->init(configurator.eventsForKitPlugin()
			, configurator.qRealConfigurator().systemEvents()
			, configurator.qRealConfigurator().graphicalModelApi()
			, configurator.qRealConfigurator().logicalModelApi()
			, interpretersInterface
			, configurator.interpreterControl());

}

QString NxtKitInterpreterPlugin::kitId() const
{
	return "nxtKit";
}

QString NxtKitInterpreterPlugin::friendlyKitName() const
{
	return tr("Lego NXT");
}

QList<kitBase::robotModel::RobotModelInterface *> NxtKitInterpreterPlugin::robotModels()
{
	return {&mUsbRealRobotModel, &mBluetoothRealRobotModel, &mTwoDRobotModel};
}

kitBase::blocksBase::BlocksFactoryInterface *NxtKitInterpreterPlugin::blocksFactoryFor(
		const kitBase::robotModel::RobotModelInterface *model)
{
	Q_UNUSED(model);
	mOwnsBlocksFactory = false;
	return mBlocksFactory;
}

kitBase::robotModel::RobotModelInterface *NxtKitInterpreterPlugin::defaultRobotModel()
{
	return &mTwoDRobotModel;
}

QList<kitBase::AdditionalPreferences *> NxtKitInterpreterPlugin::settingsWidgets()
{
	mOwnsAdditionalPreferences = false;
	return {mAdditionalPreferences};
}

QList<qReal::ActionInfo> NxtKitInterpreterPlugin::customActions()
{
	return { mTwoDModel->showTwoDModelWidgetActionInfo() };
}

QList<HotKeyActionInfo> NxtKitInterpreterPlugin::hotKeyActions()
{
	mTwoDModel->showTwoDModelWidgetActionInfo().action()->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_2));

	HotKeyActionInfo d2ModelActionInfo("Interpreter.Show2dModelForNxt", tr("Show 2d model")
			, mTwoDModel->showTwoDModelWidgetActionInfo().action());

	return { d2ModelActionInfo };
}

QString NxtKitInterpreterPlugin::defaultSettingsFile() const
{
	return ":/nxtDefaultSettings.ini";
}

QIcon NxtKitInterpreterPlugin::iconForFastSelector(
		const kitBase::robotModel::RobotModelInterface &robotModel) const
{
	return &robotModel == &mUsbRealRobotModel
			? QIcon(":/icons/switch-real-nxt-usb.svg")
			: &robotModel == &mBluetoothRealRobotModel
					? QIcon(":/icons/switch-real-nxt-bluetooth.svg")
					: QIcon(":/icons/switch-2d.svg");
}

kitBase::DevicesConfigurationProvider * NxtKitInterpreterPlugin::devicesConfigurationProvider()
{
	return &mTwoDModel->devicesConfigurationProvider();
}

void NxtKitInterpreterPlugin::onActiveTabChanged(const TabInfo &info)
{
	const Id type = info.rootDiagramId().type();
	const bool enabled = type == robotDiagramType || type == subprogramDiagramType
			&& mCurrentlySelectedModelName == mTwoDRobotModel.name();
	mTwoDModel->showTwoDModelWidgetActionInfo().action()->setVisible(enabled);
}
<commit_msg>Fixed extra NXT 2D model action visible in all modes<commit_after>#include "nxtKitInterpreterPlugin.h"

#include <QtWidgets/QApplication>

#include <twoDModel/engine/twoDModelEngineFacade.h>

using namespace nxt;
using namespace qReal;

const Id robotDiagramType = Id("RobotsMetamodel", "RobotsDiagram", "RobotsDiagramNode");
const Id subprogramDiagramType = Id("RobotsMetamodel", "RobotsDiagram", "SubprogramDiagram");

NxtKitInterpreterPlugin::NxtKitInterpreterPlugin()
	: mUsbRealRobotModel(kitId(), "nxtKitUsbRobot") // todo: somewhere generate robotId for each robot
	, mBluetoothRealRobotModel(kitId(), "nxtKitBluetoothRobot")
	, mTwoDRobotModel(mUsbRealRobotModel)
	, mBlocksFactory(new blocks::NxtBlocksFactory)
{
	mAdditionalPreferences = new NxtAdditionalPreferences(mBluetoothRealRobotModel.name());

	auto modelEngine = new twoDModel::engine::TwoDModelEngineFacade(mTwoDRobotModel);

	mTwoDRobotModel.setEngine(modelEngine->engine());
	mTwoDModel.reset(modelEngine);

	connect(mAdditionalPreferences, &NxtAdditionalPreferences::settingsChanged
			, &mUsbRealRobotModel, &robotModel::real::RealRobotModel::rereadSettings);
	connect(mAdditionalPreferences, &NxtAdditionalPreferences::settingsChanged
			, &mBluetoothRealRobotModel, &robotModel::real::RealRobotModel::rereadSettings);
	connect(mAdditionalPreferences, &NxtAdditionalPreferences::settingsChanged
			, &mTwoDRobotModel, &robotModel::twoD::TwoDRobotModel::rereadSettings);
}

NxtKitInterpreterPlugin::~NxtKitInterpreterPlugin()
{
	if (mOwnsAdditionalPreferences) {
		delete mAdditionalPreferences;
	}

	if (mOwnsBlocksFactory) {
		delete mBlocksFactory;
	}
}

void NxtKitInterpreterPlugin::init(const kitBase::KitPluginConfigurator &configurator)
{
	connect(&configurator.eventsForKitPlugin(), &kitBase::EventsForKitPluginInterface::robotModelChanged
			, [this](const QString &modelName) { mCurrentlySelectedModelName = modelName; });

	connect(&configurator.qRealConfigurator().systemEvents(), &qReal::SystemEvents::activeTabChanged
			, this, &NxtKitInterpreterPlugin::onActiveTabChanged);

	qReal::gui::MainWindowInterpretersInterface &interpretersInterface
			= configurator.qRealConfigurator().mainWindowInterpretersInterface();
	connect(&mUsbRealRobotModel, &robotModel::real::RealRobotModel::errorOccured
			, [&interpretersInterface](const QString &message) {
				interpretersInterface.errorReporter()->addError(message);
	});
	connect(&mBluetoothRealRobotModel, &robotModel::real::RealRobotModel::errorOccured
			, [&interpretersInterface](const QString &message) {
				interpretersInterface.errorReporter()->addError(message);
	});
	mUsbRealRobotModel.checkConnection();
	mBluetoothRealRobotModel.checkConnection();

	mTwoDModel->init(configurator.eventsForKitPlugin()
			, configurator.qRealConfigurator().systemEvents()
			, configurator.qRealConfigurator().graphicalModelApi()
			, configurator.qRealConfigurator().logicalModelApi()
			, interpretersInterface
			, configurator.interpreterControl());

}

QString NxtKitInterpreterPlugin::kitId() const
{
	return "nxtKit";
}

QString NxtKitInterpreterPlugin::friendlyKitName() const
{
	return tr("Lego NXT");
}

QList<kitBase::robotModel::RobotModelInterface *> NxtKitInterpreterPlugin::robotModels()
{
	return {&mUsbRealRobotModel, &mBluetoothRealRobotModel, &mTwoDRobotModel};
}

kitBase::blocksBase::BlocksFactoryInterface *NxtKitInterpreterPlugin::blocksFactoryFor(
		const kitBase::robotModel::RobotModelInterface *model)
{
	Q_UNUSED(model);
	mOwnsBlocksFactory = false;
	return mBlocksFactory;
}

kitBase::robotModel::RobotModelInterface *NxtKitInterpreterPlugin::defaultRobotModel()
{
	return &mTwoDRobotModel;
}

QList<kitBase::AdditionalPreferences *> NxtKitInterpreterPlugin::settingsWidgets()
{
	mOwnsAdditionalPreferences = false;
	return {mAdditionalPreferences};
}

QList<qReal::ActionInfo> NxtKitInterpreterPlugin::customActions()
{
	return { mTwoDModel->showTwoDModelWidgetActionInfo() };
}

QList<HotKeyActionInfo> NxtKitInterpreterPlugin::hotKeyActions()
{
	mTwoDModel->showTwoDModelWidgetActionInfo().action()->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_2));

	HotKeyActionInfo d2ModelActionInfo("Interpreter.Show2dModelForNxt", tr("Show 2d model")
			, mTwoDModel->showTwoDModelWidgetActionInfo().action());

	return { d2ModelActionInfo };
}

QString NxtKitInterpreterPlugin::defaultSettingsFile() const
{
	return ":/nxtDefaultSettings.ini";
}

QIcon NxtKitInterpreterPlugin::iconForFastSelector(
		const kitBase::robotModel::RobotModelInterface &robotModel) const
{
	return &robotModel == &mUsbRealRobotModel
			? QIcon(":/icons/switch-real-nxt-usb.svg")
			: &robotModel == &mBluetoothRealRobotModel
					? QIcon(":/icons/switch-real-nxt-bluetooth.svg")
					: QIcon(":/icons/switch-2d.svg");
}

kitBase::DevicesConfigurationProvider * NxtKitInterpreterPlugin::devicesConfigurationProvider()
{
	return &mTwoDModel->devicesConfigurationProvider();
}

void NxtKitInterpreterPlugin::onActiveTabChanged(const TabInfo &info)
{
	const Id type = info.rootDiagramId().type();
	const bool enabled = (type == robotDiagramType || type == subprogramDiagramType)
			&& mCurrentlySelectedModelName == mTwoDRobotModel.name();
	mTwoDModel->showTwoDModelWidgetActionInfo().action()->setVisible(enabled);
}
<|endoftext|>


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

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

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

#include "QmitkImageStatisticsWidget.h"

#include "QmitkTableModelToStringConverter.h"
#include "QmitkImageStatisticsTreeModel.h"

#include <QSortFilterProxyModel>
#include <QClipboard>

QmitkImageStatisticsWidget::QmitkImageStatisticsWidget(QWidget* parent) : QWidget(parent)
{
  m_Controls.setupUi(this);
  m_imageStatisticsModel = new QmitkImageStatisticsTreeModel(parent);
  CreateConnections();
  m_ProxyModel = new QSortFilterProxyModel(this);
  m_Controls.treeViewStatistics->setEnabled(false);
  m_Controls.treeViewStatistics->setModel(m_ProxyModel);
  m_ProxyModel->setSourceModel(m_imageStatisticsModel);
  connect(m_imageStatisticsModel, &QmitkImageStatisticsTreeModel::dataAvailable, this, &QmitkImageStatisticsWidget::OnDataAvailable);
}

void QmitkImageStatisticsWidget::SetDataStorage(mitk::DataStorage* newDataStorage)
{
  m_imageStatisticsModel->SetDataStorage(newDataStorage);
}

void QmitkImageStatisticsWidget::SetImageNodes(const std::vector<mitk::DataNode::ConstPointer>& nodes)
{
  m_imageStatisticsModel->SetImageNodes(nodes);
}

void QmitkImageStatisticsWidget::SetMaskNodes(const std::vector<mitk::DataNode::ConstPointer>& nodes)
{
  m_imageStatisticsModel->SetMaskNodes(nodes);
}

void QmitkImageStatisticsWidget::Reset()
{
  m_imageStatisticsModel->Clear();
  m_Controls.treeViewStatistics->setEnabled(false);
  m_Controls.buttonCopyImageStatisticsToClipboard->setEnabled(false);
}

void QmitkImageStatisticsWidget::CreateConnections()
{
	connect(m_Controls.buttonCopyImageStatisticsToClipboard, &QPushButton::clicked, this, &QmitkImageStatisticsWidget::OnClipboardButtonClicked);
}

void QmitkImageStatisticsWidget::OnDataAvailable()
{
  m_Controls.buttonCopyImageStatisticsToClipboard->setEnabled(true);
  m_Controls.treeViewStatistics->setEnabled(true);
}

void QmitkImageStatisticsWidget::OnClipboardButtonClicked()
{
  QmitkTableModelToStringConverter converter;
  converter.SetTableModel(m_imageStatisticsModel);
  converter.SetIncludeHeaderData(true);
  converter.SetColumnDelimiter('\t');

  QString clipboardAsString = converter.GetString();
  QApplication::clipboard()->setText(clipboardAsString, QClipboard::Clipboard);
}
<commit_msg>auto expand by default after loading<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

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

#include "QmitkImageStatisticsWidget.h"

#include "QmitkTableModelToStringConverter.h"
#include "QmitkImageStatisticsTreeModel.h"

#include <QSortFilterProxyModel>
#include <QClipboard>

QmitkImageStatisticsWidget::QmitkImageStatisticsWidget(QWidget* parent) : QWidget(parent)
{
  m_Controls.setupUi(this);
  m_imageStatisticsModel = new QmitkImageStatisticsTreeModel(parent);
  CreateConnections();
  m_ProxyModel = new QSortFilterProxyModel(this);
  m_Controls.treeViewStatistics->setEnabled(false);
  m_Controls.treeViewStatistics->setModel(m_ProxyModel);
  m_ProxyModel->setSourceModel(m_imageStatisticsModel);
  connect(m_imageStatisticsModel, &QmitkImageStatisticsTreeModel::dataAvailable, this, &QmitkImageStatisticsWidget::OnDataAvailable);
  connect(m_imageStatisticsModel,
          &QmitkImageStatisticsTreeModel::modelChanged,
          m_Controls.treeViewStatistics,
          &QTreeView::expandAll);
}

void QmitkImageStatisticsWidget::SetDataStorage(mitk::DataStorage* newDataStorage)
{
  m_imageStatisticsModel->SetDataStorage(newDataStorage);
}

void QmitkImageStatisticsWidget::SetImageNodes(const std::vector<mitk::DataNode::ConstPointer>& nodes)
{
  m_imageStatisticsModel->SetImageNodes(nodes);
}

void QmitkImageStatisticsWidget::SetMaskNodes(const std::vector<mitk::DataNode::ConstPointer>& nodes)
{
  m_imageStatisticsModel->SetMaskNodes(nodes);
}

void QmitkImageStatisticsWidget::Reset()
{
  m_imageStatisticsModel->Clear();
  m_Controls.treeViewStatistics->setEnabled(false);
  m_Controls.buttonCopyImageStatisticsToClipboard->setEnabled(false);
}

void QmitkImageStatisticsWidget::CreateConnections()
{
	connect(m_Controls.buttonCopyImageStatisticsToClipboard, &QPushButton::clicked, this, &QmitkImageStatisticsWidget::OnClipboardButtonClicked);
}

void QmitkImageStatisticsWidget::OnDataAvailable()
{
  m_Controls.buttonCopyImageStatisticsToClipboard->setEnabled(true);
  m_Controls.treeViewStatistics->setEnabled(true);
}

void QmitkImageStatisticsWidget::OnClipboardButtonClicked()
{
  QmitkTableModelToStringConverter converter;
  converter.SetTableModel(m_imageStatisticsModel);
  converter.SetIncludeHeaderData(true);
  converter.SetColumnDelimiter('\t');

  QString clipboardAsString = converter.GetString();
  QApplication::clipboard()->setText(clipboardAsString, QClipboard::Clipboard);
}
<|endoftext|>


<commit_before>// faster alternative to PPTrajectory.eval() in Matlab
// Michael Kaess, June 2013

#include <mex.h>
#include <Eigen/Dense>
#include <unsupported/Eigen/MatrixFunctions>
#include <vector>
#include <iostream>

using namespace Eigen;
using namespace std;

// Initialization:
//   obj = PPTmex(breaks,coefs,order,dims)
// Evaluation:
//   y = PPTmex(obj, 1, t)
//
// t:      1      single evaluation point
//
// breaks: n+1
// coefs:  nxd1xd2 x p
// order:  1       p
// dims:   2       d1,d2
//
// y:      p

class PPTrajectory {

private:

  VectorXd m_breaks;
  MatrixXd m_coefs;
  const int m_d1, m_d2, m_order;

  int m_cached_idx;

public:

  PPTrajectory(const VectorXd& breaks, const MatrixXd& coefs, int order, int d1, int d2)
  : m_breaks(breaks), m_coefs(coefs), m_order(order), m_d1(d1), m_d2(d2), m_cached_idx(-1)
  {}

  int d1() {
    return m_d1;
  }

  int d2() {
    return m_d2;
  }

  void eval(double t, Map<MatrixXd>& y) {

    if (t<m_breaks(0)) t=m_breaks(0);
    if (t>m_breaks(m_breaks.rows()-1)) t=m_breaks(m_breaks.rows()-1);

    Map<VectorXd> r(y.data(), m_d1*m_d2); // reshape

    // use cached index if possible
    int idx;
    if (m_cached_idx >= 0 && m_cached_idx < m_breaks.rows() // valid m_cached_idx?
        && t < m_breaks[m_cached_idx+1] // still in same interval?
        && ((m_cached_idx == 0) || (t >= m_breaks[m_cached_idx]))) { // left up to -infinity
      idx = m_cached_idx;
    } else {
      // search for the correct interval
      // todo: binary search
      for (int b=static_cast<int>(m_breaks.rows())-2; b>=1; b--) { // ignore first and last break
        if (t < m_breaks(b)) idx=b-1;
      }
      m_cached_idx = idx;
    }

    int base = idx*m_d1*m_d2;
    double local = t - m_breaks[idx];
    r = m_coefs.block(base, 0, m_d1*m_d2, 1);
    for (int i=2; i<=m_order; i++) {
      r = local*r + m_coefs.block(base, i-1, m_d1*m_d2, 1);
    }
  }
};

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
  if (nrhs == 4 && nlhs == 1) {

    // create object
    Map<VectorXd> breaks(mxGetPr(prhs[0]), mxGetNumberOfElements(prhs[0]));
    Map<MatrixXd>  coefs(mxGetPr(prhs[1]), mxGetM(prhs[1]), mxGetN(prhs[1]));
    int order = static_cast<int>(mxGetScalar(prhs[2]));
    Map<VectorXd>   dims(mxGetPr(prhs[3]), mxGetNumberOfElements(prhs[3]));

    int d1 = static_cast<int>(dims(0));
    int d2 = 1;
    if (dims.rows() > 1)
      d2 = static_cast<int>(dims(1));
    PPTrajectory *ppt = new PPTrajectory(breaks, coefs, order, d1, d2);
    mxClassID cid;
    if (sizeof(ppt)==4) cid = mxUINT32_CLASS;
    else if (sizeof(ppt)==8) cid = mxUINT64_CLASS;
    else mexErrMsgIdAndTxt("Drake:PPTmex:PointerSize","Are you on a 32-bit machine or 64-bit machine??");
    plhs[0] = mxCreateNumericMatrix(1,1,cid,mxREAL);
    memcpy(mxGetData(plhs[0]),&ppt,sizeof(ppt));

  } else {

    // retrieve object
    PPTrajectory *ppt = NULL;
    if (nrhs==0 || !mxIsNumeric(prhs[0]) || mxGetNumberOfElements(prhs[0])!=1)
      mexErrMsgIdAndTxt("Drake:PPTmex:BadInputs","the first argument should be the mex_ptr");
    memcpy(&ppt,mxGetData(prhs[0]),sizeof(ppt));

    if (nrhs == 1) {

      // delete object
      delete ppt;

    } else {

      // eval() function call
      if (nrhs < 2) {
        mexErrMsgIdAndTxt("Drake:PPTmex:WrongNumberOfInputs","Usage obj = PPTmex(breaks,coefs,order,dims) or y = PPTmex(obj,t)");
      }

      double *command = mxGetPr(prhs[1]);

      switch ((int)(*command)) {

      case 1: { // eval
        double *t = mxGetPr(prhs[2]);
        int d1 = ppt->d1();
        int d2 = ppt->d2();
        plhs[0] = mxCreateDoubleMatrix(d1,d2,mxREAL);
        Map<MatrixXd> y(mxGetPr(plhs[0]),d1,d2);
        ppt->eval(*t, y);
        break;
      }

      default:
        mexErrMsgIdAndTxt("Drake:PPTmex:UnknownCommand","Check arguments");
      }

    }

  }

}
<commit_msg>not sure how this line got zapped...<commit_after>// faster alternative to PPTrajectory.eval() in Matlab
// Michael Kaess, June 2013

#include <mex.h>
#include <Eigen/Dense>
#include <unsupported/Eigen/MatrixFunctions>
#include <vector>
#include <iostream>

using namespace Eigen;
using namespace std;

// Initialization:
//   obj = PPTmex(breaks,coefs,order,dims)
// Evaluation:
//   y = PPTmex(obj, 1, t)
//
// t:      1      single evaluation point
//
// breaks: n+1
// coefs:  nxd1xd2 x p
// order:  1       p
// dims:   2       d1,d2
//
// y:      p

class PPTrajectory {

private:

  VectorXd m_breaks;
  MatrixXd m_coefs;
  const int m_d1, m_d2, m_order;

  int m_cached_idx;

public:

  PPTrajectory(const VectorXd& breaks, const MatrixXd& coefs, int order, int d1, int d2)
  : m_breaks(breaks), m_coefs(coefs), m_order(order), m_d1(d1), m_d2(d2), m_cached_idx(-1)
  {}

  int d1() {
    return m_d1;
  }

  int d2() {
    return m_d2;
  }

  void eval(double t, Map<MatrixXd>& y) {

    if (t<m_breaks(0)) t=m_breaks(0);
    if (t>m_breaks(m_breaks.rows()-1)) t=m_breaks(m_breaks.rows()-1);

    Map<VectorXd> r(y.data(), m_d1*m_d2); // reshape

    // use cached index if possible
    int idx;
    if (m_cached_idx >= 0 && m_cached_idx < m_breaks.rows() // valid m_cached_idx?
        && t < m_breaks[m_cached_idx+1] // still in same interval?
        && ((m_cached_idx == 0) || (t >= m_breaks[m_cached_idx]))) { // left up to -infinity
      idx = m_cached_idx;
    } else {
      // search for the correct interval
      idx = m_breaks.rows()-2;
      // todo: binary search
      for (int b=static_cast<int>(m_breaks.rows())-2; b>=1; b--) { // ignore first and last break
        if (t < m_breaks(b)) idx=b-1;
      }
      m_cached_idx = idx;
    }

    int base = idx*m_d1*m_d2;
    double local = t - m_breaks[idx];
    r = m_coefs.block(base, 0, m_d1*m_d2, 1);
    for (int i=2; i<=m_order; i++) {
      r = local*r + m_coefs.block(base, i-1, m_d1*m_d2, 1);
    }
  }
};

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
  if (nrhs == 4 && nlhs == 1) {

    // create object
    Map<VectorXd> breaks(mxGetPr(prhs[0]), mxGetNumberOfElements(prhs[0]));
    Map<MatrixXd>  coefs(mxGetPr(prhs[1]), mxGetM(prhs[1]), mxGetN(prhs[1]));
    int order = static_cast<int>(mxGetScalar(prhs[2]));
    Map<VectorXd>   dims(mxGetPr(prhs[3]), mxGetNumberOfElements(prhs[3]));

    int d1 = static_cast<int>(dims(0));
    int d2 = 1;
    if (dims.rows() > 1)
      d2 = static_cast<int>(dims(1));
    PPTrajectory *ppt = new PPTrajectory(breaks, coefs, order, d1, d2);
    mxClassID cid;
    if (sizeof(ppt)==4) cid = mxUINT32_CLASS;
    else if (sizeof(ppt)==8) cid = mxUINT64_CLASS;
    else mexErrMsgIdAndTxt("Drake:PPTmex:PointerSize","Are you on a 32-bit machine or 64-bit machine??");
    plhs[0] = mxCreateNumericMatrix(1,1,cid,mxREAL);
    memcpy(mxGetData(plhs[0]),&ppt,sizeof(ppt));

  } else {

    // retrieve object
    PPTrajectory *ppt = NULL;
    if (nrhs==0 || !mxIsNumeric(prhs[0]) || mxGetNumberOfElements(prhs[0])!=1)
      mexErrMsgIdAndTxt("Drake:PPTmex:BadInputs","the first argument should be the mex_ptr");
    memcpy(&ppt,mxGetData(prhs[0]),sizeof(ppt));

    if (nrhs == 1) {

      // delete object
      delete ppt;

    } else {

      // eval() function call
      if (nrhs < 2) {
        mexErrMsgIdAndTxt("Drake:PPTmex:WrongNumberOfInputs","Usage obj = PPTmex(breaks,coefs,order,dims) or y = PPTmex(obj,t)");
      }

      double *command = mxGetPr(prhs[1]);

      switch ((int)(*command)) {

      case 1: { // eval
        double *t = mxGetPr(prhs[2]);
        int d1 = ppt->d1();
        int d2 = ppt->d2();
        plhs[0] = mxCreateDoubleMatrix(d1,d2,mxREAL);
        Map<MatrixXd> y(mxGetPr(plhs[0]),d1,d2);
        ppt->eval(*t, y);
        break;
      }

      default:
        mexErrMsgIdAndTxt("Drake:PPTmex:UnknownCommand","Check arguments");
      }

    }

  }

}
<|endoftext|>


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

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

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 "QmitkSimpleExampleFunctionality.h"
#include "QmitkSimpleExampleControls.h"

#include <qaction.h>
#include "slicer.xpm"

// for slice-navigation
#include <mitkEventMapper.h>
#include <mitkGlobalInteraction.h>
#include <mitkBaseRenderer.h>
#include "QmitkRenderWindow.h"
#include "QmitkSelectableGLWidget.h"
#include "QmitkStdMultiWidget.h"
#include <QmitkStepperAdapter.h>
#include <mitkMovieGenerator.h>

#include <qpushbutton.h>
#include <qfiledialog.h>

// for stereo setting
#include <mitkOpenGLRenderer.h>
#include <mitkVtkRenderWindow.h>
#include <vtkRenderWindow.h>

// for zoom/pan
#include <mitkDisplayCoordinateOperation.h>
#include <mitkDisplayVectorInteractor.h>
#include <mitkDisplayInteractor.h>
#include <mitkInteractionConst.h>

QmitkSimpleExampleFunctionality::QmitkSimpleExampleFunctionality(QObject *parent, const char *name, QmitkStdMultiWidget *mitkStdMultiWidget, mitk::DataTreeIteratorBase* it) : QmitkFunctionality(parent, name, it) ,
controls(NULL), multiWidget(mitkStdMultiWidget), m_NavigatorsInitialized(false)
{
    SetAvailability(true);
}

QmitkSimpleExampleFunctionality::~QmitkSimpleExampleFunctionality()
{
//  delete moveNzoom;
}

QWidget * QmitkSimpleExampleFunctionality::CreateMainWidget(QWidget *parent)
{
    QWidget *result = NULL;

    if (multiWidget == NULL)
    {
        multiWidget = new QmitkStdMultiWidget(parent);
        result = multiWidget;
    }
    else
    {
        result = NULL;
    }
    return result;
}

QWidget * QmitkSimpleExampleFunctionality::CreateControlWidget(QWidget *parent)
{
    if (controls == NULL)
    {
        controls = new QmitkSimpleExampleControls(parent);
        new QmitkStepperAdapter(controls->getSliceNavigatorTransversal(), multiWidget->mitkWidget1->GetSliceNavigationController()->GetSlice(), "sliceNavigatorTransversalFromSimpleExample");
        new QmitkStepperAdapter(controls->getSliceNavigatorSagittal(), multiWidget->mitkWidget2->GetSliceNavigationController()->GetSlice(), "sliceNavigatorSagittalFromSimpleExample");
        new QmitkStepperAdapter(controls->getSliceNavigatorFrontal(), multiWidget->mitkWidget3->GetSliceNavigationController()->GetSlice(), "sliceNavigatorFrontalFromSimpleExample");
        new QmitkStepperAdapter(controls->getSliceNavigatorTime(), multiWidget->GetTimeNavigationController()->GetTime(), "sliceNavigatorTimeFromSimpleExample");
        new QmitkStepperAdapter(controls->getMovieNavigatorTime(), multiWidget->GetTimeNavigationController()->GetTime(), "movieNavigatorTimeFromSimpleExample");
    }
    return controls;
}

void QmitkSimpleExampleFunctionality::CreateConnections()
{
  if ( controls )
  {
    connect(controls->getStereoSelect(), SIGNAL(activated(int)), this, SLOT(stereoSelectionChanged(int)) );
    connect(controls->getReInitializeNavigatorsButton(), SIGNAL(clicked()), this, SLOT(initNavigators()) );
    connect(controls->getGenerateMovieButton(), SIGNAL(clicked()), this, SLOT(generateMovie()) );
  }
}

QAction * QmitkSimpleExampleFunctionality::CreateAction(QActionGroup *parent)
{
    QAction* action;
    action = new QAction( tr( "Simple Example" ), QPixmap((const char**)slicer_xpm), tr( "&Simple Example" ), CTRL + Key_L, parent, "simple example" );
    return action;
}

void QmitkSimpleExampleFunctionality::initNavigators()
{
  m_NavigatorsInitialized = multiWidget->InitializeStandardViews(m_DataTreeIterator.GetPointer());
}

void QmitkSimpleExampleFunctionality::generateMovie()
{
  mitk::Stepper::Pointer stepper = multiWidget->mitkWidget1->GetSliceNavigationController()->GetSlice();
  mitk::MovieGenerator::Pointer movieGenerator = mitk::MovieGenerator::New();
  if (movieGenerator.IsNotNull()) {
    movieGenerator->SetStepper( stepper );
    movieGenerator->SetRenderer( multiWidget->mitkWidget1->GetRenderer() );
    QString movieFileName = QFileDialog::getSaveFileName( QString::null, "Movie (*.avi)", 0, "movie file dialog", "Choose a file name" );
    movieGenerator->SetFileName( movieFileName.ascii() );
    movieGenerator->WriteMovie();
  }
}

void QmitkSimpleExampleFunctionality::TreeChanged()
{
}

void QmitkSimpleExampleFunctionality::Activated()
{
  QmitkFunctionality::Activated();
  assert( multiWidget != NULL );
  // init widget 4 as a 3D widget
  multiWidget->mitkWidget4->GetRenderer()->SetMapperID(2);

  if(m_NavigatorsInitialized)
  {
    multiWidget->ReInitializeStandardViews();
  }
}

void QmitkSimpleExampleFunctionality::stereoSelectionChanged( int id )
{
  vtkRenderWindow * vtkrenderwindow =
    ((mitk::OpenGLRenderer*)(multiWidget->mitkWidget4->GetRenderer()))->GetVtkRenderWindow();
  switch(id)
  {
  case 0:
    vtkrenderwindow->StereoRenderOff();
    break;
  case 1:
    vtkrenderwindow->SetStereoTypeToRedBlue();
    vtkrenderwindow->StereoRenderOn();
    break;
  case 2:
    vtkrenderwindow->SetStereoTypeToDresden();
    vtkrenderwindow->StereoRenderOn();
    break;
  }
  multiWidget->mitkWidget4->GetRenderer()->SetMapperID(2);
  multiWidget->mitkWidget4->GetRenderer()->GetRenderWindow()->RequestUpdate();
}
<commit_msg>FIX: Crash when canceling movie recording in SimpleFunctionality<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

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 "QmitkSimpleExampleFunctionality.h"
#include "QmitkSimpleExampleControls.h"

#include <qaction.h>
#include "slicer.xpm"

// for slice-navigation
#include <mitkEventMapper.h>
#include <mitkGlobalInteraction.h>
#include <mitkBaseRenderer.h>
#include "QmitkRenderWindow.h"
#include "QmitkSelectableGLWidget.h"
#include "QmitkStdMultiWidget.h"
#include <QmitkStepperAdapter.h>
#include <mitkMovieGenerator.h>

#include <qpushbutton.h>
#include <qfiledialog.h>

// for stereo setting
#include <mitkOpenGLRenderer.h>
#include <mitkVtkRenderWindow.h>
#include <vtkRenderWindow.h>

// for zoom/pan
#include <mitkDisplayCoordinateOperation.h>
#include <mitkDisplayVectorInteractor.h>
#include <mitkDisplayInteractor.h>
#include <mitkInteractionConst.h>

QmitkSimpleExampleFunctionality::QmitkSimpleExampleFunctionality(QObject *parent, const char *name, QmitkStdMultiWidget *mitkStdMultiWidget, mitk::DataTreeIteratorBase* it) : QmitkFunctionality(parent, name, it) ,
controls(NULL), multiWidget(mitkStdMultiWidget), m_NavigatorsInitialized(false)
{
    SetAvailability(true);
}

QmitkSimpleExampleFunctionality::~QmitkSimpleExampleFunctionality()
{
//  delete moveNzoom;
}

QWidget * QmitkSimpleExampleFunctionality::CreateMainWidget(QWidget *parent)
{
    QWidget *result = NULL;

    if (multiWidget == NULL)
    {
        multiWidget = new QmitkStdMultiWidget(parent);
        result = multiWidget;
    }
    else
    {
        result = NULL;
    }
    return result;
}

QWidget * QmitkSimpleExampleFunctionality::CreateControlWidget(QWidget *parent)
{
    if (controls == NULL)
    {
        controls = new QmitkSimpleExampleControls(parent);
        new QmitkStepperAdapter(controls->getSliceNavigatorTransversal(), multiWidget->mitkWidget1->GetSliceNavigationController()->GetSlice(), "sliceNavigatorTransversalFromSimpleExample");
        new QmitkStepperAdapter(controls->getSliceNavigatorSagittal(), multiWidget->mitkWidget2->GetSliceNavigationController()->GetSlice(), "sliceNavigatorSagittalFromSimpleExample");
        new QmitkStepperAdapter(controls->getSliceNavigatorFrontal(), multiWidget->mitkWidget3->GetSliceNavigationController()->GetSlice(), "sliceNavigatorFrontalFromSimpleExample");
        new QmitkStepperAdapter(controls->getSliceNavigatorTime(), multiWidget->GetTimeNavigationController()->GetTime(), "sliceNavigatorTimeFromSimpleExample");
        new QmitkStepperAdapter(controls->getMovieNavigatorTime(), multiWidget->GetTimeNavigationController()->GetTime(), "movieNavigatorTimeFromSimpleExample");
    }
    return controls;
}

void QmitkSimpleExampleFunctionality::CreateConnections()
{
  if ( controls )
  {
    connect(controls->getStereoSelect(), SIGNAL(activated(int)), this, SLOT(stereoSelectionChanged(int)) );
    connect(controls->getReInitializeNavigatorsButton(), SIGNAL(clicked()), this, SLOT(initNavigators()) );
    connect(controls->getGenerateMovieButton(), SIGNAL(clicked()), this, SLOT(generateMovie()) );
  }
}

QAction * QmitkSimpleExampleFunctionality::CreateAction(QActionGroup *parent)
{
    QAction* action;
    action = new QAction( tr( "Simple Example" ), QPixmap((const char**)slicer_xpm), tr( "&Simple Example" ), CTRL + Key_L, parent, "simple example" );
    return action;
}

void QmitkSimpleExampleFunctionality::initNavigators()
{
  m_NavigatorsInitialized = multiWidget->InitializeStandardViews(m_DataTreeIterator.GetPointer());
}

void QmitkSimpleExampleFunctionality::generateMovie()
{
  mitk::Stepper::Pointer stepper = multiWidget->mitkWidget1->GetSliceNavigationController()->GetSlice();
  mitk::MovieGenerator::Pointer movieGenerator = mitk::MovieGenerator::New();
  if (movieGenerator.IsNotNull()) {
    movieGenerator->SetStepper( stepper );
    movieGenerator->SetRenderer( multiWidget->mitkWidget1->GetRenderer() );
    QString movieFileName = QFileDialog::getSaveFileName( QString::null, "Movie (*.avi)", 0, "movie file dialog", "Choose a file name" );
    if (!movieFileName.isEmpty()) {
      movieGenerator->SetFileName( movieFileName.ascii() );
      movieGenerator->WriteMovie();
    }
  }
}

void QmitkSimpleExampleFunctionality::TreeChanged()
{
}

void QmitkSimpleExampleFunctionality::Activated()
{
  QmitkFunctionality::Activated();
  assert( multiWidget != NULL );
  // init widget 4 as a 3D widget
  multiWidget->mitkWidget4->GetRenderer()->SetMapperID(2);

  if(m_NavigatorsInitialized)
  {
    multiWidget->ReInitializeStandardViews();
  }
}

void QmitkSimpleExampleFunctionality::stereoSelectionChanged( int id )
{
  vtkRenderWindow * vtkrenderwindow =
    ((mitk::OpenGLRenderer*)(multiWidget->mitkWidget4->GetRenderer()))->GetVtkRenderWindow();
  switch(id)
  {
  case 0:
    vtkrenderwindow->StereoRenderOff();
    break;
  case 1:
    vtkrenderwindow->SetStereoTypeToRedBlue();
    vtkrenderwindow->StereoRenderOn();
    break;
  case 2:
    vtkrenderwindow->SetStereoTypeToDresden();
    vtkrenderwindow->StereoRenderOn();
    break;
  }
  multiWidget->mitkWidget4->GetRenderer()->SetMapperID(2);
  multiWidget->mitkWidget4->GetRenderer()->GetRenderWindow()->RequestUpdate();
}
<|endoftext|>


<commit_before>// -*- mode:c++; indent-tabs-mode:nil; -*-

/*
  Copyright (c) 2014, Anders Ronnbrant, anders.ronnbrant@gmail.com

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*/

#include "RecorderBase.h"

#include <algorithm>
#include <atomic>
#include <cstdlib>
#include <cstring>
#include <memory>
#include <string>

#include <zmq.hpp>

#include "zmqutils.h"

namespace {
void Error(char const* msg) { std::fprintf(stderr, "%s\n", msg); }
std::atomic<int16_t> g_recorder_id = ATOMIC_VAR_INIT(0);
}

// Static definitions for RecorderBase
// ----------------------------------------------------------------------------
void
RecorderBase::setContext(zmq::context_t* context) {
  socket_context = context;
}

void
RecorderBase::setAddress(std::string address) {
  printf("Address: %s\n", address.c_str());
  socket_address = address;
}

std::string
RecorderBase::getAddress() {
  return RecorderBase::socket_address;
}

zmq::context_t* RecorderBase::socket_context = nullptr;
std::string     RecorderBase::socket_address = "";

thread_local
RecorderBase::SendBuffer RecorderBase::send_buffer;

thread_local
RecorderBase::SendBuffer::size_type RecorderBase::send_buffer_index = 0;
// ----------------------------------------------------------------------------

RecorderBase::RecorderBase(std::string name, int32_t id)
    : external_id_(id)
    , recorder_id_(g_recorder_id.fetch_add(1))
    , recorder_name_(name) {
  bool error = false;

  if (RecorderBase::socket_context == nullptr) {
    Error("setContext() must be called before instantiation");
    error = true;
  }

  if (RecorderBase::socket_address.empty()) {
    Error("Socket address empty, setAddress() must be called");
    Error("before first instantiation");
    error = true;
  }

  if (error) {
    std::exit(1);
  }

  int constexpr linger = 3000;
  int constexpr sendtimeout = 2;

  socket_.reset(new zmq::socket_t(*RecorderBase::socket_context, ZMQ_PUSH));
  socket_->setsockopt(ZMQ_LINGER, &linger, sizeof(linger));
  socket_->setsockopt(ZMQ_SNDTIMEO, &sendtimeout, sizeof(sendtimeout));
  zmqutils::connect(socket_.get(), RecorderBase::socket_address);
}

RecorderBase::~RecorderBase() {
  flushSendBuffer();
  socket_->close();
}

void
RecorderBase::flushSendBuffer() {
  auto constexpr frame = PayloadType::DATA;
  auto constexpr item_size = sizeof(decltype(send_buffer)::value_type);
  if (send_buffer_index > 0) {
    socket_->send(&frame, sizeof(frame), ZMQ_SNDMORE);
    socket_->send(send_buffer.data(), send_buffer_index * item_size);
    send_buffer_index = 0;
  }
}

void
RecorderBase::setupRecorder(int32_t num_items) {
  auto constexpr frame = PayloadType::INIT_RECORDER;
  InitRecorder const init_rec(
      external_id_, recorder_id_, num_items, recorder_name_);
  socket_->send(&frame, sizeof(frame), ZMQ_SNDMORE);
  socket_->send(&init_rec, sizeof(init_rec));
}

void
RecorderBase::setupItem(InitItem const& init_item) {
  auto constexpr frame = PayloadType::INIT_ITEM;
  socket_->send(&frame, sizeof(frame), ZMQ_SNDMORE);
  socket_->send(&init_item, sizeof(init_item));
}

void
RecorderBase::record(Item const& item) {
  send_buffer[send_buffer_index++] = item;
  if (send_buffer_index == send_buffer.max_size()) {
    flushSendBuffer();
  }
}
<commit_msg>Add socket creator, for thread local static initialization<commit_after>// -*- mode:c++; indent-tabs-mode:nil; -*-

/*
  Copyright (c) 2014, Anders Ronnbrant, anders.ronnbrant@gmail.com

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*/

#include "RecorderBase.h"

#include <algorithm>
#include <atomic>
#include <cstdlib>
#include <cstring>
#include <memory>
#include <string>

#include <zmq.hpp>

#include "zmqutils.h"

// Static definitions for RecorderBase
// ----------------------------------------------------------------------------
void
RecorderBase::setContext(zmq::context_t* context) {
  socket_context = context;
}

void
RecorderBase::setAddress(std::string address) {
  printf("Address: %s\n", address.c_str());
  socket_address = address;
}

std::string
RecorderBase::getAddress() {
  return RecorderBase::socket_address;
}

zmq::context_t* RecorderBase::socket_context = nullptr;
std::string     RecorderBase::socket_address = "";

thread_local
RecorderBase::SendBuffer RecorderBase::send_buffer;

thread_local
RecorderBase::SendBuffer::size_type RecorderBase::send_buffer_index = 0;
// ----------------------------------------------------------------------------

namespace {
void Error(char const* msg) { std::fprintf(stderr, "%s\n", msg); }
std::atomic<int16_t> g_recorder_id = ATOMIC_VAR_INIT(0);

// Socket creator class
class SocketCreator {
 public:
  SocketCreator(zmq::context_t* ctx,
                std::string const& address,
                std::shared_ptr<zmq::socket_t>* socket) {
    printf("%s: %lu\n", __func__, std::this_thread::get_id());
    int constexpr linger = 3000;
    int constexpr sendtimeout = 2;
    int constexpr sendhwm = 16000;
    socket->reset(new zmq::socket_t(*ctx, ZMQ_PUSH));
    (*socket)->setsockopt(ZMQ_LINGER, &linger, sizeof(linger));
    (*socket)->setsockopt(ZMQ_SNDTIMEO, &sendtimeout, sizeof(sendtimeout));
    (*socket)->setsockopt(ZMQ_SNDHWM, &sendhwm, sizeof(sendhwm));
    zmqutils::connect(socket->get(), address);
  }
};

}  // namespace

RecorderBase::RecorderBase(std::string name, int32_t id)
    : external_id_(id)
    , recorder_id_(g_recorder_id.fetch_add(1))
    , recorder_name_(name) {
  bool error = false;

  if (RecorderBase::socket_context == nullptr) {
    Error("setContext() must be called before instantiation");
    error = true;
  }

  if (RecorderBase::socket_address.empty()) {
    Error("Socket address empty, setAddress() must be called");
    Error("before first instantiation");
    error = true;
  }

  if (error) {
    std::exit(1);
  }

  int constexpr linger = 3000;
  int constexpr sendtimeout = 2;

  socket_.reset(new zmq::socket_t(*RecorderBase::socket_context, ZMQ_PUSH));
  socket_->setsockopt(ZMQ_LINGER, &linger, sizeof(linger));
  socket_->setsockopt(ZMQ_SNDTIMEO, &sendtimeout, sizeof(sendtimeout));
  zmqutils::connect(socket_.get(), RecorderBase::socket_address);
}

RecorderBase::~RecorderBase() {
  flushSendBuffer();
  socket_->close();
}

void
RecorderBase::flushSendBuffer() {
  auto constexpr frame = PayloadType::DATA;
  auto constexpr item_size = sizeof(decltype(send_buffer)::value_type);
  if (send_buffer_index > 0) {
    socket_->send(&frame, sizeof(frame), ZMQ_SNDMORE);
    socket_->send(send_buffer.data(), send_buffer_index * item_size);
    send_buffer_index = 0;
  }
}

void
RecorderBase::setupRecorder(int32_t num_items) {
  auto constexpr frame = PayloadType::INIT_RECORDER;
  InitRecorder const init_rec(
      external_id_, recorder_id_, num_items, recorder_name_);
  socket_->send(&frame, sizeof(frame), ZMQ_SNDMORE);
  socket_->send(&init_rec, sizeof(init_rec));
}

void
RecorderBase::setupItem(InitItem const& init_item) {
  auto constexpr frame = PayloadType::INIT_ITEM;
  socket_->send(&frame, sizeof(frame), ZMQ_SNDMORE);
  socket_->send(&init_item, sizeof(init_item));
}

void
RecorderBase::record(Item const& item) {
  send_buffer[send_buffer_index++] = item;
  if (send_buffer_index == send_buffer.max_size()) {
    flushSendBuffer();
  }
}
<|endoftext|>


<commit_before>#include "vtkConditionVariable.h"

#include "vtkObjectFactory.h"

#include <errno.h>

vtkStandardNewMacro(vtkConditionVariable);

#ifndef EPERM
#  define EPERM 1
#endif
#ifndef ENOMEM
#  define ENOMEM 12
#endif
#ifndef EBUSY
#  define EBUSY 16
#endif
#ifndef EINVAL
#  define EINVAL 22
#endif
#ifndef EAGAIN
#  define EAGAIN 35
#endif

#if ! defined(VTK_USE_PTHREADS) && ! defined(VTK_HP_PTHREADS) && ! defined(VTK_USE_WIN32_THREADS)
typedef int pthread_condattr_t;

int pthread_cond_init( vtkConditionType* cv, const pthread_condattr_t* )
{
  *cv = 0;
  return 0;
}

int pthread_cond_destroy( vtkConditionType* cv )
{
  if ( *cv )
    return EBUSY;
  return 0;
}

int pthread_cond_signal( vtkConditionType* cv )
{
  *cv = 1;
  return 0;
}

int pthread_cond_broadcast( vtkConditionType* cv )
{
  *cv = 1;
  return 0;
}

int pthread_cond_wait( vtkConditionType* cv, vtkMutexType* lock )
{
#ifdef VTK_USE_SPROC
  release_lock( lock );
#else // VTK_USE_SPROC
  *lock = 0;
#endif // VTK_USE_SPROC
  while ( ! *cv );
#ifdef VTK_USE_SPROC
  spin_lock( lock );
#else // VTK_USE_SPROC
  *lock = 1;
#endif // VTK_USE_SPROC
}
#endif // ! defined(VTK_USE_PTHREADS) && ! defined(VTK_HP_PTHREADS) && ! defined(VTK_USE_WIN32_THREADS)

#ifdef VTK_USE_WIN32_THREADS
typedef int pthread_condattr_t;

#  if 1
int pthread_cond_init( pthread_cond_t* cv, const pthread_condattr_t* )
{
  cv->WaitingThreadCount = 0;
  cv->WasBroadcast = 0;
  cv->Semaphore = CreateSemaphore(
    NULL,       // no security
    0,          // initially 0
    0x7fffffff, // max count
    NULL );     // unnamed
  InitializeCriticalSection( &cv->WaitingThreadCountCritSec );
  cv->DoneWaiting = CreateEvent(
    NULL,   // no security
    FALSE,  // auto-reset
    FALSE,  // non-signaled initially
    NULL ); // unnamed

  return 0;
}

int pthread_cond_wait( pthread_cond_t* cv, vtkMutexType* externalMutex )
{
  // Avoid race conditions.
  EnterCriticalSection( &cv->WaitingThreadCountCritSec );
  ++ cv->WaitingThreadCount;
  LeaveCriticalSection( &cv->WaitingThreadCountCritSec );

  // This call atomically releases the mutex and waits on the
  // semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>
  // are called by another thread.
  SignalObjectAndWait( *externalMutex, cv->Semaphore, INFINITE, FALSE );

  // Reacquire lock to avoid race conditions.
  EnterCriticalSection( &cv->WaitingThreadCountCritSec );

  // We're no longer waiting...
  -- cv->WaitingThreadCount;

  // Check to see if we're the last waiter after <pthread_cond_broadcast>.
  int last_waiter = cv->WasBroadcast && cv->WaitingThreadCount == 0;

  LeaveCriticalSection( &cv->WaitingThreadCountCritSec );

  // If we're the last waiter thread during this particular broadcast
  // then let all the other threads proceed.
  if ( last_waiter )
    {
    // This call atomically signals the <DoneWaiting> event and waits until
    // it can acquire the <externalMutex>.  This is required to ensure fairness.
    SignalObjectAndWait( cv->DoneWaiting, *externalMutex, INFINITE, FALSE );
    }
  else
    {
    // Always regain the external mutex since that's the guarantee we
    // give to our callers.
    WaitForSingleObject( *externalMutex, INFINITE );
    }
  return 0;
}

int pthread_cond_signal( pthread_cond_t* cv )
{
  EnterCriticalSection( &cv->WaitingThreadCountCritSec );
  int have_waiters = cv->WaitingThreadCount > 0;
  LeaveCriticalSection( &cv->WaitingThreadCountCritSec );

  // If there aren't any waiters, then this is a no-op.
  if ( have_waiters )
    {
    ReleaseSemaphore( cv->Semaphore, 1, 0 );
    }
  return 0;
}

int pthread_cond_broadcast( pthread_cond_t* cv )
{
  // This is needed to ensure that <WaitingThreadCount> and <WasBroadcast> are
  // consistent relative to each other.
  EnterCriticalSection( &cv->WaitingThreadCountCritSec );
  int have_waiters = 0;

  if ( cv->WaitingThreadCount > 0 )
    {
    // We are broadcasting, even if there is just one waiter...
    // Record that we are broadcasting, which helps optimize
    // pthread_cond_wait for the non-broadcast case.
    cv->WasBroadcast = 1;
    have_waiters = 1;
    }

  if (have_waiters)
    {
    // Wake up all the waiters atomically.
    ReleaseSemaphore( cv->Semaphore, cv->WaitingThreadCount, 0 );
    LeaveCriticalSection( &cv->WaitingThreadCountCritSec );

    // Wait for all the awakened threads to acquire the counting semaphore.
    WaitForSingleObject( cv->DoneWaiting, INFINITE );
    // This assignment is okay, even without the <WaitingThreadCountCritSec> held
    // because no other waiter threads can wake up to access it.
    cv->WasBroadcast = 0;
    }
  else
    {
    LeaveCriticalSection( &cv->WaitingThreadCountCritSec );
    }

  return 0;
}

int pthread_cond_destroy( pthread_cond_t* cv )
{
  DeleteCriticalSection( &cv->WaitingThreadCountCritSec );
  CloseHandle( cv->Semaphore );
  //CloseHandle( cv->Event );
  if ( cv->WaitingThreadCount > 0 && ! cv->DoneWaiting )
    {
    return EBUSY;
    }
  return 0;
}
#  else // 0
int pthread_cond_init( pthread_cond_t* cv, const pthread_condattr_t * )
{
  if ( ! cv )
    {
    return EINVAL;
    }

  cv->WaitingThreadCount = 0;
  cv->NotifyCount = 0;
  cv->ReleaseCount = 0;

  // Create a manual-reset event.
  cv->Event = CreateEvent(
    NULL,   // no security
    TRUE,   // manual-reset
    FALSE,  // non-signaled initially
    NULL ); // unnamed

  InitializeCriticalSection( &cv->WaitingThreadCountCritSec );

  return 0;
}

int pthread_cond_wait( pthread_cond_t* cv, vtkMutexType* externalMutex )
{
  // Avoid race conditions.
  EnterCriticalSection( &cv->WaitingThreadCountCritSec );

  // Increment count of waiters.
  ++ cv->WaitingThreadCount;

  // Store the notification we should respond to.
  int tmpNotify = cv->NotifyCount;

  LeaveCriticalSection( &cv->WaitingThreadCountCritSec );
  ReleaseMutex( *externalMutex );

  while ( 1 )
    {
    // Wait until the event is signaled.
    WaitForSingleObject( cv->Event, INFINITE );

    EnterCriticalSection( &cv->WaitingThreadCountCritSec );
    // Exit the loop when cv->Event is signaled, the
    // release count indicates more threads need to receive
    // the signal/broadcast, and the signal occurred after
    // we started waiting.
    int waitDone =
      ( cv->ReleaseCount > 0 ) &&
      ( cv->NotifyCount != tmpNotify );
    LeaveCriticalSection( &cv->WaitingThreadCountCritSec );

    if ( waitDone )
      break;
    }

  WaitForSingleObject( *externalMutex, INFINITE );
  EnterCriticalSection( &cv->WaitingThreadCountCritSec );
  -- cv->WaitingThreadCount;
  -- cv->ReleaseCount;
  int lastWaiter = ( cv->ReleaseCount == 0 );
  LeaveCriticalSection( &cv->WaitingThreadCountCritSec );

  // If we're the last waiter to be notified, reset the manual event.
  if ( lastWaiter )
    ResetEvent( cv->Event );

  return 0;
}

int pthread_cond_signal( pthread_cond_t* cv )
{
  EnterCriticalSection( &cv->WaitingThreadCountCritSec );
  if ( cv->WaitingThreadCount > cv->ReleaseCount )
    {
    SetEvent( cv->Event ); // Signal the manual-reset event.
    ++ cv->ReleaseCount;
    ++ cv->NotifyCount;
    }
  LeaveCriticalSection( &cv->WaitingThreadCountCritSec );
  return 0;
}

int pthread_cond_broadcast( pthread_cond_t* cv )
{
  EnterCriticalSection( &cv->WaitingThreadCountCritSec );
  if ( cv->WaitingThreadCount > 0 )
    {
    SetEvent( cv->Event );
    // Release all the threads in this generation.
    cv->ReleaseCount = cv->WaitingThreadCount;
    ++ cv->NotifyCount;
    }
  LeaveCriticalSection( &cv->WaitingThreadCountCritSec );
  return 0;
}

int pthread_cond_destroy( pthread_cond_t* cv )
{
  if ( cv->WaitingThreadCount > 0 )
    {
    return EBUSY;
    }
  CloseHandle( cv->Event );
  DeleteCriticalSection( &cv->WaitingThreadCountCritSec );
  return 0;
}
#  endif // 0
#endif // VTK_USE_WIN32_THREADS

vtkSimpleConditionVariable::vtkSimpleConditionVariable()
{
  int result = pthread_cond_init( &this->ConditionVariable, 0 );
  switch ( result )
    {
  case EINVAL:
      {
      vtkGenericWarningMacro( "Invalid condition variable attributes." );
      }
    break;
  case ENOMEM:
      {
      vtkGenericWarningMacro( "Not enough memory to create a condition variable." );
      }
    break;
  case EAGAIN:
      {
      vtkGenericWarningMacro( "Temporarily not enough memory to create a condition variable." );
      }
    break;
    }
}

vtkSimpleConditionVariable::~vtkSimpleConditionVariable()
{
  int result = pthread_cond_destroy( &this->ConditionVariable );
  switch ( result )
    {
  case EINVAL:
      {
      vtkGenericWarningMacro( "Could not destroy condition variable (invalid value)" );
      }
    break;
  case EBUSY:
      {
      vtkGenericWarningMacro( "Could not destroy condition variable (locked by another thread)" );
      }
    break;
    }
}

void vtkSimpleConditionVariable::Signal()
{
  pthread_cond_signal( &this->ConditionVariable );
}

void vtkSimpleConditionVariable::Broadcast()
{
  pthread_cond_broadcast( &this->ConditionVariable );
}

int vtkSimpleConditionVariable::Wait( vtkSimpleMutexLock& lock )
{
  return pthread_cond_wait( &this->ConditionVariable, &lock.MutexLock );
}

void vtkConditionVariable::PrintSelf( ostream& os, vtkIndent indent )
{
  this->Superclass::PrintSelf( os, indent );
  os << indent << "SimpleConditionVariable: " << &this->SimpleConditionVariable << "\n";
  os << indent << "ThreadingModel: "
#ifdef VTK_USE_PTHREADS
    << "pthreads "
#endif
#ifdef VTK_HP_PTHREADS
    << "HP pthreads "
#endif
#ifdef VTK_USE_WIN32_THREADS
    << "win32 threads "
#endif
    << "\n";
}

<commit_msg>Place fake pthread symbols in namespace.<commit_after>#include "vtkConditionVariable.h"

#include "vtkObjectFactory.h"

#include <errno.h>

vtkStandardNewMacro(vtkConditionVariable);

#ifndef EPERM
#  define EPERM 1
#endif
#ifndef ENOMEM
#  define ENOMEM 12
#endif
#ifndef EBUSY
#  define EBUSY 16
#endif
#ifndef EINVAL
#  define EINVAL 22
#endif
#ifndef EAGAIN
#  define EAGAIN 35
#endif

#if ! defined(VTK_USE_PTHREADS) && ! defined(VTK_HP_PTHREADS) && ! defined(VTK_USE_WIN32_THREADS)
// Why is this encapsulated in a namespace?  Because you can get errors if
// these symbols (particularly the typedef) are already defined.  We run
// into this problem on a system that has pthread headers but no libraries
// (which can happen when, for example, cross compiling).  By using the
// namespace, we will at worst get a warning.
namespace {

typedef int pthread_condattr_t;

int pthread_cond_init( vtkConditionType* cv, const pthread_condattr_t* )
{
  *cv = 0;
  return 0;
}

int pthread_cond_destroy( vtkConditionType* cv )
{
  if ( *cv )
    return EBUSY;
  return 0;
}

int pthread_cond_signal( vtkConditionType* cv )
{
  *cv = 1;
  return 0;
}

int pthread_cond_broadcast( vtkConditionType* cv )
{
  *cv = 1;
  return 0;
}

int pthread_cond_wait( vtkConditionType* cv, vtkMutexType* lock )
{
#ifdef VTK_USE_SPROC
  release_lock( lock );
#else // VTK_USE_SPROC
  *lock = 0;
#endif // VTK_USE_SPROC
  while ( ! *cv );
#ifdef VTK_USE_SPROC
  spin_lock( lock );
#else // VTK_USE_SPROC
  *lock = 1;
#endif // VTK_USE_SPROC
  return 0;
}

}
#endif // ! defined(VTK_USE_PTHREADS) && ! defined(VTK_HP_PTHREADS) && ! defined(VTK_USE_WIN32_THREADS)

#ifdef VTK_USE_WIN32_THREADS
typedef int pthread_condattr_t;

#  if 1
int pthread_cond_init( pthread_cond_t* cv, const pthread_condattr_t* )
{
  cv->WaitingThreadCount = 0;
  cv->WasBroadcast = 0;
  cv->Semaphore = CreateSemaphore(
    NULL,       // no security
    0,          // initially 0
    0x7fffffff, // max count
    NULL );     // unnamed
  InitializeCriticalSection( &cv->WaitingThreadCountCritSec );
  cv->DoneWaiting = CreateEvent(
    NULL,   // no security
    FALSE,  // auto-reset
    FALSE,  // non-signaled initially
    NULL ); // unnamed

  return 0;
}

int pthread_cond_wait( pthread_cond_t* cv, vtkMutexType* externalMutex )
{
  // Avoid race conditions.
  EnterCriticalSection( &cv->WaitingThreadCountCritSec );
  ++ cv->WaitingThreadCount;
  LeaveCriticalSection( &cv->WaitingThreadCountCritSec );

  // This call atomically releases the mutex and waits on the
  // semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>
  // are called by another thread.
  SignalObjectAndWait( *externalMutex, cv->Semaphore, INFINITE, FALSE );

  // Reacquire lock to avoid race conditions.
  EnterCriticalSection( &cv->WaitingThreadCountCritSec );

  // We're no longer waiting...
  -- cv->WaitingThreadCount;

  // Check to see if we're the last waiter after <pthread_cond_broadcast>.
  int last_waiter = cv->WasBroadcast && cv->WaitingThreadCount == 0;

  LeaveCriticalSection( &cv->WaitingThreadCountCritSec );

  // If we're the last waiter thread during this particular broadcast
  // then let all the other threads proceed.
  if ( last_waiter )
    {
    // This call atomically signals the <DoneWaiting> event and waits until
    // it can acquire the <externalMutex>.  This is required to ensure fairness.
    SignalObjectAndWait( cv->DoneWaiting, *externalMutex, INFINITE, FALSE );
    }
  else
    {
    // Always regain the external mutex since that's the guarantee we
    // give to our callers.
    WaitForSingleObject( *externalMutex, INFINITE );
    }
  return 0;
}

int pthread_cond_signal( pthread_cond_t* cv )
{
  EnterCriticalSection( &cv->WaitingThreadCountCritSec );
  int have_waiters = cv->WaitingThreadCount > 0;
  LeaveCriticalSection( &cv->WaitingThreadCountCritSec );

  // If there aren't any waiters, then this is a no-op.
  if ( have_waiters )
    {
    ReleaseSemaphore( cv->Semaphore, 1, 0 );
    }
  return 0;
}

int pthread_cond_broadcast( pthread_cond_t* cv )
{
  // This is needed to ensure that <WaitingThreadCount> and <WasBroadcast> are
  // consistent relative to each other.
  EnterCriticalSection( &cv->WaitingThreadCountCritSec );
  int have_waiters = 0;

  if ( cv->WaitingThreadCount > 0 )
    {
    // We are broadcasting, even if there is just one waiter...
    // Record that we are broadcasting, which helps optimize
    // pthread_cond_wait for the non-broadcast case.
    cv->WasBroadcast = 1;
    have_waiters = 1;
    }

  if (have_waiters)
    {
    // Wake up all the waiters atomically.
    ReleaseSemaphore( cv->Semaphore, cv->WaitingThreadCount, 0 );
    LeaveCriticalSection( &cv->WaitingThreadCountCritSec );

    // Wait for all the awakened threads to acquire the counting semaphore.
    WaitForSingleObject( cv->DoneWaiting, INFINITE );
    // This assignment is okay, even without the <WaitingThreadCountCritSec> held
    // because no other waiter threads can wake up to access it.
    cv->WasBroadcast = 0;
    }
  else
    {
    LeaveCriticalSection( &cv->WaitingThreadCountCritSec );
    }

  return 0;
}

int pthread_cond_destroy( pthread_cond_t* cv )
{
  DeleteCriticalSection( &cv->WaitingThreadCountCritSec );
  CloseHandle( cv->Semaphore );
  //CloseHandle( cv->Event );
  if ( cv->WaitingThreadCount > 0 && ! cv->DoneWaiting )
    {
    return EBUSY;
    }
  return 0;
}
#  else // 0
int pthread_cond_init( pthread_cond_t* cv, const pthread_condattr_t * )
{
  if ( ! cv )
    {
    return EINVAL;
    }

  cv->WaitingThreadCount = 0;
  cv->NotifyCount = 0;
  cv->ReleaseCount = 0;

  // Create a manual-reset event.
  cv->Event = CreateEvent(
    NULL,   // no security
    TRUE,   // manual-reset
    FALSE,  // non-signaled initially
    NULL ); // unnamed

  InitializeCriticalSection( &cv->WaitingThreadCountCritSec );

  return 0;
}

int pthread_cond_wait( pthread_cond_t* cv, vtkMutexType* externalMutex )
{
  // Avoid race conditions.
  EnterCriticalSection( &cv->WaitingThreadCountCritSec );

  // Increment count of waiters.
  ++ cv->WaitingThreadCount;

  // Store the notification we should respond to.
  int tmpNotify = cv->NotifyCount;

  LeaveCriticalSection( &cv->WaitingThreadCountCritSec );
  ReleaseMutex( *externalMutex );

  while ( 1 )
    {
    // Wait until the event is signaled.
    WaitForSingleObject( cv->Event, INFINITE );

    EnterCriticalSection( &cv->WaitingThreadCountCritSec );
    // Exit the loop when cv->Event is signaled, the
    // release count indicates more threads need to receive
    // the signal/broadcast, and the signal occurred after
    // we started waiting.
    int waitDone =
      ( cv->ReleaseCount > 0 ) &&
      ( cv->NotifyCount != tmpNotify );
    LeaveCriticalSection( &cv->WaitingThreadCountCritSec );

    if ( waitDone )
      break;
    }

  WaitForSingleObject( *externalMutex, INFINITE );
  EnterCriticalSection( &cv->WaitingThreadCountCritSec );
  -- cv->WaitingThreadCount;
  -- cv->ReleaseCount;
  int lastWaiter = ( cv->ReleaseCount == 0 );
  LeaveCriticalSection( &cv->WaitingThreadCountCritSec );

  // If we're the last waiter to be notified, reset the manual event.
  if ( lastWaiter )
    ResetEvent( cv->Event );

  return 0;
}

int pthread_cond_signal( pthread_cond_t* cv )
{
  EnterCriticalSection( &cv->WaitingThreadCountCritSec );
  if ( cv->WaitingThreadCount > cv->ReleaseCount )
    {
    SetEvent( cv->Event ); // Signal the manual-reset event.
    ++ cv->ReleaseCount;
    ++ cv->NotifyCount;
    }
  LeaveCriticalSection( &cv->WaitingThreadCountCritSec );
  return 0;
}

int pthread_cond_broadcast( pthread_cond_t* cv )
{
  EnterCriticalSection( &cv->WaitingThreadCountCritSec );
  if ( cv->WaitingThreadCount > 0 )
    {
    SetEvent( cv->Event );
    // Release all the threads in this generation.
    cv->ReleaseCount = cv->WaitingThreadCount;
    ++ cv->NotifyCount;
    }
  LeaveCriticalSection( &cv->WaitingThreadCountCritSec );
  return 0;
}

int pthread_cond_destroy( pthread_cond_t* cv )
{
  if ( cv->WaitingThreadCount > 0 )
    {
    return EBUSY;
    }
  CloseHandle( cv->Event );
  DeleteCriticalSection( &cv->WaitingThreadCountCritSec );
  return 0;
}
#  endif // 0
#endif // VTK_USE_WIN32_THREADS

vtkSimpleConditionVariable::vtkSimpleConditionVariable()
{
  int result = pthread_cond_init( &this->ConditionVariable, 0 );
  switch ( result )
    {
  case EINVAL:
      {
      vtkGenericWarningMacro( "Invalid condition variable attributes." );
      }
    break;
  case ENOMEM:
      {
      vtkGenericWarningMacro( "Not enough memory to create a condition variable." );
      }
    break;
  case EAGAIN:
      {
      vtkGenericWarningMacro( "Temporarily not enough memory to create a condition variable." );
      }
    break;
    }
}

vtkSimpleConditionVariable::~vtkSimpleConditionVariable()
{
  int result = pthread_cond_destroy( &this->ConditionVariable );
  switch ( result )
    {
  case EINVAL:
      {
      vtkGenericWarningMacro( "Could not destroy condition variable (invalid value)" );
      }
    break;
  case EBUSY:
      {
      vtkGenericWarningMacro( "Could not destroy condition variable (locked by another thread)" );
      }
    break;
    }
}

void vtkSimpleConditionVariable::Signal()
{
  pthread_cond_signal( &this->ConditionVariable );
}

void vtkSimpleConditionVariable::Broadcast()
{
  pthread_cond_broadcast( &this->ConditionVariable );
}

int vtkSimpleConditionVariable::Wait( vtkSimpleMutexLock& lock )
{
  return pthread_cond_wait( &this->ConditionVariable, &lock.MutexLock );
}

void vtkConditionVariable::PrintSelf( ostream& os, vtkIndent indent )
{
  this->Superclass::PrintSelf( os, indent );
  os << indent << "SimpleConditionVariable: " << &this->SimpleConditionVariable << "\n";
  os << indent << "ThreadingModel: "
#ifdef VTK_USE_PTHREADS
    << "pthreads "
#endif
#ifdef VTK_HP_PTHREADS
    << "HP pthreads "
#endif
#ifdef VTK_USE_WIN32_THREADS
    << "win32 threads "
#endif
    << "\n";
}

<|endoftext|>


<commit_before>/*
 * libMaia - maiaXmlRpcClient.cpp
 * Copyright (c) 2007 Sebastian Wiedenroth <wiedi@frubar.net>
 *                and Karl Glatz
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
 */

#include "maiaXmlRpcClient.h"
#include "maiaFault.h"

MaiaXmlRpcClient::MaiaXmlRpcClient(QObject* parent) : QObject(parent),
	manager(this), request()
{

	request.setRawHeader("User-Agent", "libmaia 0.2");
	request.setHeader(QNetworkRequest::ContentTypeHeader, "text/xml");

	connect(&manager, SIGNAL(finished(QNetworkReply*)),
		this, SLOT(replyFinished(QNetworkReply*)));
}

MaiaXmlRpcClient::MaiaXmlRpcClient(QUrl url, QObject* parent) : QObject(parent),
	manager(this), request(url)
{
	request.setRawHeader("User-Agent", "libmaia 0.2");
	request.setHeader(QNetworkRequest::ContentTypeHeader, "text/xml");

	connect(&manager, SIGNAL(finished(QNetworkReply*)),
		this, SLOT(replyFinished(QNetworkReply*)));

	setUrl(url);
}

void MaiaXmlRpcClient::setUrl(QUrl url) {
	if(!url.isValid())
		return;

	request.setUrl(url);
}

QNetworkReply* MaiaXmlRpcClient::call(QString method, QList<QVariant> args,
							QObject* responseObject, const char* responseSlot,
							QObject* faultObject, const char* faultSlot) {
	MaiaObject* call = new MaiaObject(this);
	connect(call, SIGNAL(aresponse(QVariant &, QNetworkReply *)), responseObject, responseSlot);
	connect(call, SIGNAL(fault(int, const QString &, QNetworkReply *)), faultObject, faultSlot);

	QNetworkReply* reply = manager.post( request,
		call->prepareCall(method, args).toUtf8() );

	callmap[reply] = call;
	return reply;
}

void MaiaXmlRpcClient::replyFinished(QNetworkReply* reply) {
	QString response;
	if(!callmap.contains(reply))
		return;
	if(reply->error() != QNetworkReply::NoError) {
		MaiaFault fault(-32300, reply->errorString());
		response = fault.toString();
	} else {
		response = QString::fromUtf8(reply->readAll());
	}

	// parseResponse deletes the MaiaObject
	callmap[reply]->parseResponse(response, reply);
	delete reply;
	callmap.remove(reply);
}
<commit_msg>bugfix: use deleteLater() for the reply<commit_after>/*
 * libMaia - maiaXmlRpcClient.cpp
 * Copyright (c) 2007 Sebastian Wiedenroth <wiedi@frubar.net>
 *                and Karl Glatz
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
 */

#include "maiaXmlRpcClient.h"
#include "maiaFault.h"

MaiaXmlRpcClient::MaiaXmlRpcClient(QObject* parent) : QObject(parent),
	manager(this), request()
{

	request.setRawHeader("User-Agent", "libmaia 0.2");
	request.setHeader(QNetworkRequest::ContentTypeHeader, "text/xml");

	connect(&manager, SIGNAL(finished(QNetworkReply*)),
		this, SLOT(replyFinished(QNetworkReply*)));
}

MaiaXmlRpcClient::MaiaXmlRpcClient(QUrl url, QObject* parent) : QObject(parent),
	manager(this), request(url)
{
	request.setRawHeader("User-Agent", "libmaia 0.2");
	request.setHeader(QNetworkRequest::ContentTypeHeader, "text/xml");

	connect(&manager, SIGNAL(finished(QNetworkReply*)),
		this, SLOT(replyFinished(QNetworkReply*)));

	setUrl(url);
}

void MaiaXmlRpcClient::setUrl(QUrl url) {
	if(!url.isValid())
		return;

	request.setUrl(url);
}

QNetworkReply* MaiaXmlRpcClient::call(QString method, QList<QVariant> args,
							QObject* responseObject, const char* responseSlot,
							QObject* faultObject, const char* faultSlot) {
	MaiaObject* call = new MaiaObject(this);
	connect(call, SIGNAL(aresponse(QVariant &, QNetworkReply *)), responseObject, responseSlot);
	connect(call, SIGNAL(fault(int, const QString &, QNetworkReply *)), faultObject, faultSlot);

	QNetworkReply* reply = manager.post( request,
		call->prepareCall(method, args).toUtf8() );

	callmap[reply] = call;
	return reply;
}

void MaiaXmlRpcClient::replyFinished(QNetworkReply* reply) {
	QString response;
	if(!callmap.contains(reply))
		return;
	if(reply->error() != QNetworkReply::NoError) {
		MaiaFault fault(-32300, reply->errorString());
		response = fault.toString();
	} else {
		response = QString::fromUtf8(reply->readAll());
	}

	// parseResponse deletes the MaiaObject
	callmap[reply]->parseResponse(response, reply);
	reply->deleteLater();
	callmap.remove(reply);
}
<|endoftext|>