<commit_before>/*=========================================================================
*
* Copyright Marius Staring, Stefan Klein, David Doria. 2011.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*=========================================================================*/
/** \file
 \brief This program combines multiple segmentations into one.

 \verbinclude combinesegmentations.help
 */
#include "itkCommandLineArgumentParser.h"
#include "ITKToolsHelpers.h"
#include "combinesegmentations.h"

/**
 * ******************* GetHelpString *******************
 */

std::string GetHelpString( void )
{
  std::stringstream ss;
  ss << "ITKTools v" << itktools::GetITKToolsVersion() << "\n"
    << "This program combines multiple segmentations into one.\n"
    << "Usage:\n"
    << "pxcombinesegmentations\n"
    << "[-m]     {STAPLE, VOTE, MULTISTAPLE, MULTISTAPLE2, VOTE_MULTISTAPLE2}:\n"
    << "        the method used to combine the segmentations. default: MULTISTAPLE2.\n"
    << "        VOTE_MULTISTAPLE2 is in fact just VOTE followed by MULTISTAPLE2.\n"
    << "-in      inputFilename0 [inputFileName1 ... ]: the input segmentations,\n"
    << "        as unsigned char images. More than 2 labels are allowed, but\n"
    << "        with some restrictions: {0,1,2}=ok, {0,3,4}=bad, {1,2,3}=bad.\n"
    << "[-n]     numberOfClasses: the number of classes to segment;\n"
    << "        default: 2 (so, 0 and 1).\n"
    << "[-P]     priorProbImageFilename0 priorProbImageFilename1 [...]:\n"
    << "        the names of the prior probabilities for each class, stored as float images.\n"
    << "        This has only effect when using [VOTE_]MULTISTAPLE2.\n"
    << "[-p]     priorProb0 priorProb1 [...]:\n"
    << "        the prior probabilities for each class, independent of x, so a floating point\n"
    << "        number for each class. This parameter is ignored when \"-P\" is provided as well.\n"
    << "        For VOTE this parameter is ignored. For STAPLE, this number is considered\n"
    << "        as a factor which is multiplied with the estimated prior probability.\n"
    << "       For MULTISTAPLE[2], the number is really the prior probability.\n"
    << "        If -p and -P are not provided, the prior probs are estimated from the data.\n"
    << "[-t]     trust0 [trust1 ...]: a factor between 0 and 1 indicating the 'trust' in each observer;\n"
    << "        default: 0.99999 for each observer for [VOTE_]MULTISTAPLE2. 1.0 for VOTE.\n"
    << "        Ignored by STAPLE and MULTISTAPLE; they estimate it by majority voting.\n"
    << "[-e]     termination threshold: a small float. the smaller the more accurate the solution;\n"
    << "        default: 1e-5. Ignored by STAPLE and VOTE.\n"
    << "[-outs]  outputFilename0 outputFileName1 [...]: the output (soft) probabilistic\n"
    << "        segmentations for each label. These will be float images.\n"
    << "[-outh]  outputFilename: the output hard segmentation, stored as a single\n"
    << "        unsigned char image, containing the label numbers.\n"
    << "       The value 'numberOfClasses' corresponds to 'undecided' (if two labels\n"
    << "        are exactly equally likely).\n"
    << "[-outc]  confusionImageFileName: 3d float image, in which each slice resembles\n"
    << "        the confusion matrix for each observer. The x-axis corresponds to the\n"
    << "        real label, the y-axis corresponds to the label given by the observer.\n"
    << "[-mask]  [maskDilationRadius]: Use a mask if this flag is provided.\n"
    << "        Only taken into account by [VOTE_]MULTISTAPLE2 and VOTE.\n"
    << "        The mask is 0 at those pixels were the decision is unanimous, and 1 elsewhere.\n"
    << "        A dilation is performed with a kernel with radius maskDilationRadius (default:1)\n"
    << "        Pixels that are outside the mask, will have class of the first observer.\n"
    << "        Other pixels are passed through the combination algorithm.\n"
    << "        The confusion matrix will be only based on the pixels within the mask.\n"
    << "[-ord]   The order of preferred classes, in cases of undecided pixels. Default: 0 1 2...\n"
    << "        Ignored by STAPLE and MULTISTAPLE. In the default case, class 0 will be\n"
    << "        preferred over class 1, for example.\n"
    << "[-iv]    inputlabels for relabeling\n"
    << "[-ov]    outputlabels for relabeling. Each input label is replaced by the corresponding\n"
    << "        output label, before the combinationMethod is invoked. NumberOfClasses should be\n"
    << "        valid for the situation after relabeling!\n"
    << "[-z]    compression flag; if provided, the output image is compressed\n"
    << "[-threads] maximum number of threads to use.\n"
    << "Supported: 2D/3D.";

  return ss.str();

} // end GetHelpString()

//-------------------------------------------------------------------------------------

int main( int argc, char **argv )
{
  /** Create a command line argument parser. */
  itk::CommandLineArgumentParser::Pointer parser = itk::CommandLineArgumentParser::New();
  parser->SetCommandLineArguments( argc, argv );
  parser->SetProgramHelpText( GetHelpString() );

  parser->MarkArgumentAsRequired( "-in", "The input filename." );

  itk::CommandLineArgumentParser::ReturnValue validateArguments = parser->CheckForRequiredArguments();

  if( validateArguments == itk::CommandLineArgumentParser::FAILED )
  {
    return EXIT_FAILURE;
  }
  else if( validateArguments == itk::CommandLineArgumentParser::HELPREQUESTED )
  {
    return EXIT_SUCCESS;
  }

  /** Get the combination method (mandatory) */
  std::string combinationMethod = "MULTISTAPLE2";
  parser->GetCommandLineArgument( "-m", combinationMethod );

  /** Get the input segmentation file names (mandatory). */
  std::vector< std::string >  inputSegmentationFileNames;
  parser->GetCommandLineArgument( "-in", inputSegmentationFileNames );

  /** Get the settings for the change label image filter (not mandatory) */
  std::vector<unsigned int>  inValues;
  std::vector<unsigned int>  outValues;
  parser->GetCommandLineArgument( "-iv", inValues );
  parser->GetCommandLineArgument( "-ov", outValues );
  if( inValues.size() != outValues.size() )
  {
    std::cerr << "ERROR: Number of values following after \"-iv\" and \"-ov\" should be equal." << std::endl;
    return EXIT_FAILURE;
  }

  /** Get the number of classes to segment (not mandatory) */
  unsigned char numberOfClasses = 2;
  parser->GetCommandLineArgument( "-n", numberOfClasses );

  /** Get the prior probability images (not mandatory) */
  std::vector< std::string >  priorProbImageFileNames;
  bool retP = parser->GetCommandLineArgument( "-P", priorProbImageFileNames );
  if(retP)
  {
    if( priorProbImageFileNames.size() != numberOfClasses )
    {
      std::cerr
        << "ERROR: Number of prior probability images should be equal "
        << "to the number of classes."
        << std::endl;
      std::cerr
        << "i.e., \"-P\" should be followed by "
        << numberOfClasses
        << " filenames or just totally omitted."
        << std::endl;
      return EXIT_FAILURE;
    }
  }

  /** Get the prior probabilities (not mandatory) */
  std::vector< float >  priorProbs(0);
  bool retp = parser->GetCommandLineArgument( "-p", priorProbs );
  if( retp && !retP )
  {
    if( priorProbs.size() != numberOfClasses )
    {
      std::cerr
        << "ERROR: Number of prior probabilities should be equal "
        << "to the number of classes."
        << std::endl;
      std::cerr
        << "i.e., \"-p\" should be followed by "
        << numberOfClasses
        << " numbers or just totally omitted."
        << std::endl;
      return EXIT_FAILURE;
    }
  }
  if( retp && retP )
  {
    std::cout << "WARNING: \"-p\" is ignored when \"-P\" is given as well!" << std::endl;
  }

  /** Get the trust factor for each observer (not mandatory) */
  std::vector< float > trust(0);
  bool rett = parser->GetCommandLineArgument( "-t", trust );
  if( rett )
  {
    if( trust.size() != inputSegmentationFileNames.size() )
    {
      std::cerr
        << "ERROR: Number of trust factors should be equal to the number of "
        << "input segmentations."
        << std::endl;
      std::cerr
        << "i.e., \"-t\" should be followed by "
        << inputSegmentationFileNames.size()
        << " numbers or just totally omitted." << std::endl;
      return EXIT_FAILURE;
    }
  }

  /** Get the number of classes to segment (not mandatory) */
  float terminationThreshold = 1e-5;
  parser->GetCommandLineArgument( "-e", terminationThreshold );

  /** Get the outputFileNames */
  std::vector< std::string > softOutputFileNames;
  std::string hardOutputFileName = "";
  std::string confusionOutputFileName = "";
  bool retouts = parser->GetCommandLineArgument( "-outs", softOutputFileNames );
  if( retouts )
  {
    if( softOutputFileNames.size() != numberOfClasses  &&
         softOutputFileNames.size() != 1 )
    {
      std::cerr
        << "ERROR: Number of soft output image file names should be equal "
        << "to the number of classes."
        << std::endl;
      std::cerr
        << "i.e., \"-outs\" should be followed by "
        << numberOfClasses
        << " filenames or just totally omitted."
        << std::endl;
      return EXIT_FAILURE;
    }
  }
  parser->GetCommandLineArgument( "-outh", hardOutputFileName );
  parser->GetCommandLineArgument( "-outc", confusionOutputFileName );

  /** Use mask or not? If yes, read the maskDilationRadius. */
  unsigned int maskDilationRadius = 1;
  bool useMask = parser->ArgumentExists( "-mask" );
  parser->GetCommandLineArgument( "-mask", maskDilationRadius );

  /** Read the preferred order of classes in case of undecided pixels */
  std::vector<unsigned int> prefOrder(numberOfClasses);
  for( unsigned int i = 0; i < numberOfClasses; ++i )
  {
    prefOrder[ i ] = i;
  }
  parser->GetCommandLineArgument( "-ord", prefOrder );

  /** Use compression */
  const bool useCompression = parser->ArgumentExists( "-z" );

  /** Threads. */
  unsigned int maximumNumberOfThreads
    = itk::MultiThreader::GetGlobalDefaultNumberOfThreads();
  parser->GetCommandLineArgument(
    "-threads", maximumNumberOfThreads );
  itk::MultiThreader::SetGlobalMaximumNumberOfThreads(
    maximumNumberOfThreads );

  /** Determine image properties. */
  itk::ImageIOBase::IOPixelType pixelType = itk::ImageIOBase::UNKNOWNPIXELTYPE;
  itk::ImageIOBase::IOComponentType componentType = itk::ImageIOBase::UNKNOWNCOMPONENTTYPE;
  unsigned int dim = 0;
  unsigned int numberOfComponents = 0;
  bool retgip = itktools::GetImageProperties(
    inputSegmentationFileNames[0], pixelType, componentType, dim, numberOfComponents );
  if( !retgip ) return EXIT_FAILURE;

  std::cout << "The input image has the following properties:" << std::endl;
  /** Do not bother the user with the difference between pixeltype and componenttype:*/
  //std::cout << "\tPixelType:          " << PixelType << std::endl;
  std::cout << "\tPixelType:          " << componentType << std::endl;
  std::cout << "\tDimension:          " << dim << std::endl;
  std::cout << "\tNumberOfComponents: " << numberOfComponents << std::endl;

  /** Check for vector images. */
  bool retNOCCheck = itktools::NumberOfComponentsCheck( numberOfComponents );
  if( !retNOCCheck ) return EXIT_FAILURE;

  /** Class that does the work. */
  ITKToolsCombineSegmentationsBase * filter = 0;

  try
  {
    // now call all possible template combinations.
    //if( !filter ) filter = ITKToolsCombineSegmentations< 2, char >::New( dim, componentType );
    if( !filter ) filter = ITKToolsCombineSegmentations< 2, unsigned char >::New( dim, componentType );

#ifdef ITKTOOLS_3D_SUPPORT
    //if( !filter ) filter = ITKToolsCombineSegmentations< 3, char >::New( dim, componentType );
    if( !filter ) filter = ITKToolsCombineSegmentations< 3, unsigned char >::New( dim, componentType );
#endif
    /** Check if filter was instantiated. */
    bool supported = itktools::IsFilterSupportedCheck( filter, dim, componentType );
    if( !supported ) return EXIT_FAILURE;

    /** Set the filter arguments. */
    filter->m_InputSegmentationFileNames = inputSegmentationFileNames;
    filter->m_PriorProbImageFileNames = priorProbImageFileNames;
    filter->m_SoftOutputFileNames = softOutputFileNames;
    filter->m_HardOutputFileName = hardOutputFileName;
    filter->m_ConfusionOutputFileName = confusionOutputFileName;
    filter->m_NumberOfClasses = numberOfClasses;
    filter->m_PriorProbs = priorProbs;
    filter->m_Trust = trust;
    filter->m_TerminationThreshold = terminationThreshold;
    filter->m_CombinationMethod = combinationMethod;
    filter->m_UseMask = useMask;
    filter->m_MaskDilationRadius = maskDilationRadius;
    filter->m_PrefOrder = prefOrder;
    filter->m_InValues = inValues;
    filter->m_OutValues = outValues;

    filter->Run();

    delete filter;
  }
  catch( itk::ExceptionObject & excp )
  {
    std::cerr << "ERROR: Caught ITK exception: " << excp << std::endl;
    delete filter;
    return EXIT_FAILURE;
  }

  /** End program. */
  return EXIT_SUCCESS;

} // end main
<commit_msg>BUG: assign filter->m_UseCompression = useCompression<commit_after>/*=========================================================================
*
* Copyright Marius Staring, Stefan Klein, David Doria. 2011.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*=========================================================================*/
/** \file
 \brief This program combines multiple segmentations into one.

 \verbinclude combinesegmentations.help
 */
#include "itkCommandLineArgumentParser.h"
#include "ITKToolsHelpers.h"
#include "combinesegmentations.h"

/**
 * ******************* GetHelpString *******************
 */

std::string GetHelpString( void )
{
  std::stringstream ss;
  ss << "ITKTools v" << itktools::GetITKToolsVersion() << "\n"
    << "This program combines multiple segmentations into one.\n"
    << "Usage:\n"
    << "pxcombinesegmentations\n"
    << "[-m]     {STAPLE, VOTE, MULTISTAPLE, MULTISTAPLE2, VOTE_MULTISTAPLE2}:\n"
    << "        the method used to combine the segmentations. default: MULTISTAPLE2.\n"
    << "        VOTE_MULTISTAPLE2 is in fact just VOTE followed by MULTISTAPLE2.\n"
    << "-in      inputFilename0 [inputFileName1 ... ]: the input segmentations,\n"
    << "        as unsigned char images. More than 2 labels are allowed, but\n"
    << "        with some restrictions: {0,1,2}=ok, {0,3,4}=bad, {1,2,3}=bad.\n"
    << "[-n]     numberOfClasses: the number of classes to segment;\n"
    << "        default: 2 (so, 0 and 1).\n"
    << "[-P]     priorProbImageFilename0 priorProbImageFilename1 [...]:\n"
    << "        the names of the prior probabilities for each class, stored as float images.\n"
    << "        This has only effect when using [VOTE_]MULTISTAPLE2.\n"
    << "[-p]     priorProb0 priorProb1 [...]:\n"
    << "        the prior probabilities for each class, independent of x, so a floating point\n"
    << "        number for each class. This parameter is ignored when \"-P\" is provided as well.\n"
    << "        For VOTE this parameter is ignored. For STAPLE, this number is considered\n"
    << "        as a factor which is multiplied with the estimated prior probability.\n"
    << "       For MULTISTAPLE[2], the number is really the prior probability.\n"
    << "        If -p and -P are not provided, the prior probs are estimated from the data.\n"
    << "[-t]     trust0 [trust1 ...]: a factor between 0 and 1 indicating the 'trust' in each observer;\n"
    << "        default: 0.99999 for each observer for [VOTE_]MULTISTAPLE2. 1.0 for VOTE.\n"
    << "        Ignored by STAPLE and MULTISTAPLE; they estimate it by majority voting.\n"
    << "[-e]     termination threshold: a small float. the smaller the more accurate the solution;\n"
    << "        default: 1e-5. Ignored by STAPLE and VOTE.\n"
    << "[-outs]  outputFilename0 outputFileName1 [...]: the output (soft) probabilistic\n"
    << "        segmentations for each label. These will be float images.\n"
    << "[-outh]  outputFilename: the output hard segmentation, stored as a single\n"
    << "        unsigned char image, containing the label numbers.\n"
    << "       The value 'numberOfClasses' corresponds to 'undecided' (if two labels\n"
    << "        are exactly equally likely).\n"
    << "[-outc]  confusionImageFileName: 3d float image, in which each slice resembles\n"
    << "        the confusion matrix for each observer. The x-axis corresponds to the\n"
    << "        real label, the y-axis corresponds to the label given by the observer.\n"
    << "[-mask]  [maskDilationRadius]: Use a mask if this flag is provided.\n"
    << "        Only taken into account by [VOTE_]MULTISTAPLE2 and VOTE.\n"
    << "        The mask is 0 at those pixels were the decision is unanimous, and 1 elsewhere.\n"
    << "        A dilation is performed with a kernel with radius maskDilationRadius (default:1)\n"
    << "        Pixels that are outside the mask, will have class of the first observer.\n"
    << "        Other pixels are passed through the combination algorithm.\n"
    << "        The confusion matrix will be only based on the pixels within the mask.\n"
    << "[-ord]   The order of preferred classes, in cases of undecided pixels. Default: 0 1 2...\n"
    << "        Ignored by STAPLE and MULTISTAPLE. In the default case, class 0 will be\n"
    << "        preferred over class 1, for example.\n"
    << "[-iv]    inputlabels for relabeling\n"
    << "[-ov]    outputlabels for relabeling. Each input label is replaced by the corresponding\n"
    << "        output label, before the combinationMethod is invoked. NumberOfClasses should be\n"
    << "        valid for the situation after relabeling!\n"
    << "[-z]    compression flag; if provided, the output image is compressed\n"
    << "[-threads] maximum number of threads to use.\n"
    << "Supported: 2D/3D.";

  return ss.str();

} // end GetHelpString()

//-------------------------------------------------------------------------------------

int main( int argc, char **argv )
{
  /** Create a command line argument parser. */
  itk::CommandLineArgumentParser::Pointer parser = itk::CommandLineArgumentParser::New();
  parser->SetCommandLineArguments( argc, argv );
  parser->SetProgramHelpText( GetHelpString() );

  parser->MarkArgumentAsRequired( "-in", "The input filename." );

  itk::CommandLineArgumentParser::ReturnValue validateArguments = parser->CheckForRequiredArguments();

  if( validateArguments == itk::CommandLineArgumentParser::FAILED )
  {
    return EXIT_FAILURE;
  }
  else if( validateArguments == itk::CommandLineArgumentParser::HELPREQUESTED )
  {
    return EXIT_SUCCESS;
  }

  /** Get the combination method (mandatory) */
  std::string combinationMethod = "MULTISTAPLE2";
  parser->GetCommandLineArgument( "-m", combinationMethod );

  /** Get the input segmentation file names (mandatory). */
  std::vector< std::string >  inputSegmentationFileNames;
  parser->GetCommandLineArgument( "-in", inputSegmentationFileNames );

  /** Get the settings for the change label image filter (not mandatory) */
  std::vector<unsigned int>  inValues;
  std::vector<unsigned int>  outValues;
  parser->GetCommandLineArgument( "-iv", inValues );
  parser->GetCommandLineArgument( "-ov", outValues );
  if( inValues.size() != outValues.size() )
  {
    std::cerr << "ERROR: Number of values following after \"-iv\" and \"-ov\" should be equal." << std::endl;
    return EXIT_FAILURE;
  }

  /** Get the number of classes to segment (not mandatory) */
  unsigned char numberOfClasses = 2;
  parser->GetCommandLineArgument( "-n", numberOfClasses );

  /** Get the prior probability images (not mandatory) */
  std::vector< std::string >  priorProbImageFileNames;
  bool retP = parser->GetCommandLineArgument( "-P", priorProbImageFileNames );
  if(retP)
  {
    if( priorProbImageFileNames.size() != numberOfClasses )
    {
      std::cerr
        << "ERROR: Number of prior probability images should be equal "
        << "to the number of classes."
        << std::endl;
      std::cerr
        << "i.e., \"-P\" should be followed by "
        << numberOfClasses
        << " filenames or just totally omitted."
        << std::endl;
      return EXIT_FAILURE;
    }
  }

  /** Get the prior probabilities (not mandatory) */
  std::vector< float >  priorProbs(0);
  bool retp = parser->GetCommandLineArgument( "-p", priorProbs );
  if( retp && !retP )
  {
    if( priorProbs.size() != numberOfClasses )
    {
      std::cerr
        << "ERROR: Number of prior probabilities should be equal "
        << "to the number of classes."
        << std::endl;
      std::cerr
        << "i.e., \"-p\" should be followed by "
        << numberOfClasses
        << " numbers or just totally omitted."
        << std::endl;
      return EXIT_FAILURE;
    }
  }
  if( retp && retP )
  {
    std::cout << "WARNING: \"-p\" is ignored when \"-P\" is given as well!" << std::endl;
  }

  /** Get the trust factor for each observer (not mandatory) */
  std::vector< float > trust(0);
  bool rett = parser->GetCommandLineArgument( "-t", trust );
  if( rett )
  {
    if( trust.size() != inputSegmentationFileNames.size() )
    {
      std::cerr
        << "ERROR: Number of trust factors should be equal to the number of "
        << "input segmentations."
        << std::endl;
      std::cerr
        << "i.e., \"-t\" should be followed by "
        << inputSegmentationFileNames.size()
        << " numbers or just totally omitted." << std::endl;
      return EXIT_FAILURE;
    }
  }

  /** Get the number of classes to segment (not mandatory) */
  float terminationThreshold = 1e-5;
  parser->GetCommandLineArgument( "-e", terminationThreshold );

  /** Get the outputFileNames */
  std::vector< std::string > softOutputFileNames;
  std::string hardOutputFileName = "";
  std::string confusionOutputFileName = "";
  bool retouts = parser->GetCommandLineArgument( "-outs", softOutputFileNames );
  if( retouts )
  {
    if( softOutputFileNames.size() != numberOfClasses  &&
         softOutputFileNames.size() != 1 )
    {
      std::cerr
        << "ERROR: Number of soft output image file names should be equal "
        << "to the number of classes."
        << std::endl;
      std::cerr
        << "i.e., \"-outs\" should be followed by "
        << numberOfClasses
        << " filenames or just totally omitted."
        << std::endl;
      return EXIT_FAILURE;
    }
  }
  parser->GetCommandLineArgument( "-outh", hardOutputFileName );
  parser->GetCommandLineArgument( "-outc", confusionOutputFileName );

  /** Use mask or not? If yes, read the maskDilationRadius. */
  unsigned int maskDilationRadius = 1;
  bool useMask = parser->ArgumentExists( "-mask" );
  parser->GetCommandLineArgument( "-mask", maskDilationRadius );

  /** Read the preferred order of classes in case of undecided pixels */
  std::vector<unsigned int> prefOrder(numberOfClasses);
  for( unsigned int i = 0; i < numberOfClasses; ++i )
  {
    prefOrder[ i ] = i;
  }
  parser->GetCommandLineArgument( "-ord", prefOrder );

  /** Use compression */
  const bool useCompression = parser->ArgumentExists( "-z" );

  /** Threads. */
  unsigned int maximumNumberOfThreads
    = itk::MultiThreader::GetGlobalDefaultNumberOfThreads();
  parser->GetCommandLineArgument(
    "-threads", maximumNumberOfThreads );
  itk::MultiThreader::SetGlobalMaximumNumberOfThreads(
    maximumNumberOfThreads );

  /** Determine image properties. */
  itk::ImageIOBase::IOPixelType pixelType = itk::ImageIOBase::UNKNOWNPIXELTYPE;
  itk::ImageIOBase::IOComponentType componentType = itk::ImageIOBase::UNKNOWNCOMPONENTTYPE;
  unsigned int dim = 0;
  unsigned int numberOfComponents = 0;
  bool retgip = itktools::GetImageProperties(
    inputSegmentationFileNames[0], pixelType, componentType, dim, numberOfComponents );
  if( !retgip ) return EXIT_FAILURE;

  std::cout << "The input image has the following properties:" << std::endl;
  /** Do not bother the user with the difference between pixeltype and componenttype:*/
  //std::cout << "\tPixelType:          " << PixelType << std::endl;
  std::cout << "\tPixelType:          " << componentType << std::endl;
  std::cout << "\tDimension:          " << dim << std::endl;
  std::cout << "\tNumberOfComponents: " << numberOfComponents << std::endl;

  /** Check for vector images. */
  bool retNOCCheck = itktools::NumberOfComponentsCheck( numberOfComponents );
  if( !retNOCCheck ) return EXIT_FAILURE;

  /** Class that does the work. */
  ITKToolsCombineSegmentationsBase * filter = 0;

  try
  {
    // now call all possible template combinations.
    //if( !filter ) filter = ITKToolsCombineSegmentations< 2, char >::New( dim, componentType );
    if( !filter ) filter = ITKToolsCombineSegmentations< 2, unsigned char >::New( dim, componentType );

#ifdef ITKTOOLS_3D_SUPPORT
    //if( !filter ) filter = ITKToolsCombineSegmentations< 3, char >::New( dim, componentType );
    if( !filter ) filter = ITKToolsCombineSegmentations< 3, unsigned char >::New( dim, componentType );
#endif
    /** Check if filter was instantiated. */
    bool supported = itktools::IsFilterSupportedCheck( filter, dim, componentType );
    if( !supported ) return EXIT_FAILURE;

    /** Set the filter arguments. */
    filter->m_InputSegmentationFileNames = inputSegmentationFileNames;
    filter->m_PriorProbImageFileNames = priorProbImageFileNames;
    filter->m_SoftOutputFileNames = softOutputFileNames;
    filter->m_HardOutputFileName = hardOutputFileName;
    filter->m_ConfusionOutputFileName = confusionOutputFileName;
    filter->m_NumberOfClasses = numberOfClasses;
    filter->m_PriorProbs = priorProbs;
    filter->m_Trust = trust;
    filter->m_TerminationThreshold = terminationThreshold;
    filter->m_CombinationMethod = combinationMethod;
    filter->m_UseMask = useMask;
    filter->m_MaskDilationRadius = maskDilationRadius;
    filter->m_PrefOrder = prefOrder;
    filter->m_InValues = inValues;
    filter->m_OutValues = outValues;
    filter->m_UseCompression = useCompression;

    filter->Run();

    delete filter;
  }
  catch( itk::ExceptionObject & excp )
  {
    std::cerr << "ERROR: Caught ITK exception: " << excp << std::endl;
    delete filter;
    return EXIT_FAILURE;
  }

  /** End program. */
  return EXIT_SUCCESS;

} // end main
<|endoftext|>


<commit_before>/**
 * @file nca_main.cpp
 * @author Ryan Curtin
 *
 * Executable for Neighborhood Components Analysis.
 */
#include <mlpack/core.hpp>
#include <mlpack/core/metrics/lmetric.hpp>

#include "nca.hpp"

// Define parameters.
PROGRAM_INFO("Neighborhood Components Analysis (NCA)",
    "This program implements Neighborhood Components Analysis, both a linear "
    "dimensionality reduction technique and a distance learning technique.  The"
    " method seeks to improve k-nearest-neighbor classification on a dataset "
    "by scaling the dimensions.  The method is nonparametric, and does not "
    "require a value of k.  It works by using stochastic (\"soft\") neighbor "
    "assignments and using optimization techniques over the gradient of the "
    "accuracy of the neighbor assignments.\n"
    "\n"
    "For more details, see the following published paper:\n\n"
    "@inproceedings{\n"
    "  author = {Goldberger, Jacob and Roweis, Sam and Hinton, Geoff and\n"
    "      Salakhutdinov, Ruslan},\n"
    "  booktitle = {Advances in Neural Information Processing Systems 17},\n"
    "  pages = {513--520},\n"
    "  publisher = {MIT Press},\n"
    "  title = {{Neighbourhood Components Analysis}},\n"
    "  year = {2004}\n"
    "}\n"
    "\n"
    "To work, this algorithm needs labeled data.  It can be given as the last "
    "row of the input dataset (--input_file), or alternatively in a separate "
    "file (--labels_file).");

PARAM_STRING_REQ("input_file", "Input dataset to run NCA on.", "i");
PARAM_STRING_REQ("output_file", "Output file for learned distance matrix.",
    "o");
PARAM_STRING("labels_file", "File of labels for input dataset.", "l", "");

using namespace mlpack;
using namespace mlpack::nca;
using namespace mlpack::metric;
using namespace std;
using namespace arma;

int main(int argc, char* argv[])
{
  // Parse command line.
  CLI::ParseCommandLine(argc, argv);

  const string inputFile = CLI::GetParam<string>("input_file");
  const string labelsFile = CLI::GetParam<string>("labels_file");
  const string outputFile = CLI::GetParam<string>("output_file");

  // Load data.
  mat data;
  data::Load(inputFile.c_str(), data, true);

  // Do we want to load labels separately?
  umat labels(data.n_cols, 1);
  if (labelsFile != "")
  {
    data::Load(labelsFile.c_str(), labels, true);

    if (labels.n_rows == 1)
      labels = trans(labels);

    if (labels.n_cols > 1)
      Log::Fatal << "Labels must have only one column or row!" << endl;
  }
  else
  {
    for (size_t i = 0; i < data.n_cols; i++)
      labels[i] = (int) data(data.n_rows - 1, i);

    data.shed_row(data.n_rows - 1);
  }

  // Now create the NCA object and run the optimization.
  NCA<LMetric<2> > nca(data, labels.unsafe_col(0));

  mat distance;
  nca.LearnDistance(distance);

  // Save the output.
  data::Save(CLI::GetParam<string>("output_file").c_str(), distance, true);
}
<commit_msg>Remove citation from -h output.<commit_after>/**
 * @file nca_main.cpp
 * @author Ryan Curtin
 *
 * Executable for Neighborhood Components Analysis.
 */
#include <mlpack/core.hpp>
#include <mlpack/core/metrics/lmetric.hpp>

#include "nca.hpp"

// Define parameters.
PROGRAM_INFO("Neighborhood Components Analysis (NCA)",
    "This program implements Neighborhood Components Analysis, both a linear "
    "dimensionality reduction technique and a distance learning technique.  The"
    " method seeks to improve k-nearest-neighbor classification on a dataset "
    "by scaling the dimensions.  The method is nonparametric, and does not "
    "require a value of k.  It works by using stochastic (\"soft\") neighbor "
    "assignments and using optimization techniques over the gradient of the "
    "accuracy of the neighbor assignments.\n"
    "\n"
    "To work, this algorithm needs labeled data.  It can be given as the last "
    "row of the input dataset (--input_file), or alternatively in a separate "
    "file (--labels_file).");

PARAM_STRING_REQ("input_file", "Input dataset to run NCA on.", "i");
PARAM_STRING_REQ("output_file", "Output file for learned distance matrix.",
    "o");
PARAM_STRING("labels_file", "File of labels for input dataset.", "l", "");

using namespace mlpack;
using namespace mlpack::nca;
using namespace mlpack::metric;
using namespace std;
using namespace arma;

int main(int argc, char* argv[])
{
  // Parse command line.
  CLI::ParseCommandLine(argc, argv);

  const string inputFile = CLI::GetParam<string>("input_file");
  const string labelsFile = CLI::GetParam<string>("labels_file");
  const string outputFile = CLI::GetParam<string>("output_file");

  // Load data.
  mat data;
  data::Load(inputFile.c_str(), data, true);

  // Do we want to load labels separately?
  umat labels(data.n_cols, 1);
  if (labelsFile != "")
  {
    data::Load(labelsFile.c_str(), labels, true);

    if (labels.n_rows == 1)
      labels = trans(labels);

    if (labels.n_cols > 1)
      Log::Fatal << "Labels must have only one column or row!" << endl;
  }
  else
  {
    for (size_t i = 0; i < data.n_cols; i++)
      labels[i] = (int) data(data.n_rows - 1, i);

    data.shed_row(data.n_rows - 1);
  }

  // Now create the NCA object and run the optimization.
  NCA<LMetric<2> > nca(data, labels.unsafe_col(0));

  mat distance;
  nca.LearnDistance(distance);

  // Save the output.
  data::Save(CLI::GetParam<string>("output_file").c_str(), distance, true);
}
<|endoftext|>


<commit_before>#include <string.h>

#include "glm/gtx/bit.hpp"
#include "stbimage/stb_image.h"

#include "pixelboost/file/fileSystem.h"
#include "pixelboost/graphics/device/texture.h"

using namespace pb;

Texture::Texture()
    : _Data(0)
{

}

Texture::~Texture()
{
    if (_Data)
        delete[] _Data;
}

bool Texture::LoadFromBytes(const unsigned char* data, int width, int height, bool createMips, TextureFormat format, bool hasPremultipliedAlpha)
{
#ifdef PIXELBOOST_GRAPHICS_HANDLE_CONTEXT_LOST
    if (_Data != 0 && _Data != data)
    {
        delete[] _Data;
        _Data = 0;
    }

    _DataFormat = format;
    _DataCreateMips = createMips;
    _Size = glm::vec2(width, height);

    if (_Data == 0)
    {
        switch (format)
        {
            case kTextureFormatRGB:
                _Data = new unsigned char[width*height*3];
                memcpy(_Data, data, width*height*3);
            case kTextureFormatRGBA:
                _Data = new unsigned char[width*height*4];
                memcpy(_Data, data, width*height*4);
                break;
        }
    }
#endif

    _HasPremultipliedAlpha = hasPremultipliedAlpha;

    return true;
}

bool Texture::LoadFromFile(pb::FileLocation location, const std::string& path, bool createMips, bool hasPremultipliedAlpha)
{
    bool status = true;

    if (path.substr(path.length()-4) == ".jpa")
    {
        pb::File* file = pb::FileSystem::Instance()->OpenFile(location, path);
        if (!file)
            return false;

        int rgbLength;
        int alphaLength;

        file->Read(rgbLength);
        file->Read(alphaLength);

        unsigned char* encodedRgbData = new unsigned char[rgbLength];
        unsigned char* encodedAlphaData = new unsigned char[alphaLength];

        file->Read(encodedRgbData, rgbLength);
        file->Read(encodedAlphaData, alphaLength);

        int width, height, components;
        unsigned char* decodedRgb = stbi_load_from_memory(encodedRgbData, rgbLength, &width, &height, &components, STBI_default);
        unsigned char* decodedAlpha = stbi_load_from_memory(encodedAlphaData, alphaLength, &width, &height, &components, STBI_default);

        unsigned char* decoded = new unsigned char[width*height*4];

        unsigned char* decodedTemp = decoded;
        unsigned char* rgbTemp = decodedRgb;
        unsigned char* alphaTemp = decodedAlpha;

        for (int y=0; y<height; y++)
        {
            for (int x=0; x<width; x++)
            {
                decodedTemp[0] = rgbTemp[0];
                decodedTemp[1] = rgbTemp[1];
                decodedTemp[2] = rgbTemp[2];
                decodedTemp[3] = *alphaTemp;

                decodedTemp += 4;
                rgbTemp += 3;
                alphaTemp++;
            }
        }

        stbi_image_free(decodedRgb);
        stbi_image_free(decodedAlpha);

        status = LoadFromBytes(decoded, width, height, createMips, kTextureFormatRGBA, hasPremultipliedAlpha);

        delete[] decoded;
    } else {
        std::vector<unsigned char> data;
        unsigned char* decoded;

        pb::File* file = pb::FileSystem::Instance()->OpenFile(location, path);
        if (!file)
            return false;

        file->ReadAll(data);

        int width, height, components;
        decoded = stbi_load_from_memory(&data[0], data.size(), &width, &height, &components, STBI_default);

        if (!glm::isPowerOfTwo(width) || !glm::isPowerOfTwo(height))
            createMips = false;

        delete file;

        status = LoadFromBytes(decoded, width, height, createMips, components == 3 ? kTextureFormatRGB : kTextureFormatRGBA, hasPremultipliedAlpha);

        stbi_image_free(decoded);
    }

    return status;
}

const glm::vec2& Texture::GetSize() const
{
    return _Size;
}

bool Texture::HasPremultipliedAlpha() const
{
    return _HasPremultipliedAlpha;
}

void Texture::OnContextLost()
{
    LoadFromBytes(_Data, _Size.x, _Size.y, _DataCreateMips, _DataFormat, _HasPremultipliedAlpha);
}
<commit_msg>Force image type in load jpeg+png alpha<commit_after>#include <string.h>

#include "glm/gtx/bit.hpp"
#include "stbimage/stb_image.h"

#include "pixelboost/file/fileSystem.h"
#include "pixelboost/graphics/device/texture.h"

using namespace pb;

Texture::Texture()
    : _Data(0)
{

}

Texture::~Texture()
{
    if (_Data)
        delete[] _Data;
}

bool Texture::LoadFromBytes(const unsigned char* data, int width, int height, bool createMips, TextureFormat format, bool hasPremultipliedAlpha)
{
#ifdef PIXELBOOST_GRAPHICS_HANDLE_CONTEXT_LOST
    if (_Data != 0 && _Data != data)
    {
        delete[] _Data;
        _Data = 0;
    }

    _DataFormat = format;
    _DataCreateMips = createMips;
    _Size = glm::vec2(width, height);

    if (_Data == 0)
    {
        switch (format)
        {
            case kTextureFormatRGB:
                _Data = new unsigned char[width*height*3];
                memcpy(_Data, data, width*height*3);
            case kTextureFormatRGBA:
                _Data = new unsigned char[width*height*4];
                memcpy(_Data, data, width*height*4);
                break;
        }
    }
#endif

    _HasPremultipliedAlpha = hasPremultipliedAlpha;

    return true;
}

bool Texture::LoadFromFile(pb::FileLocation location, const std::string& path, bool createMips, bool hasPremultipliedAlpha)
{
    bool status = true;

    if (path.substr(path.length()-4) == ".jpa")
    {
        pb::File* file = pb::FileSystem::Instance()->OpenFile(location, path);
        if (!file)
            return false;

        int rgbLength;
        int alphaLength;

        file->Read(rgbLength);
        file->Read(alphaLength);

        unsigned char* encodedRgbData = new unsigned char[rgbLength];
        unsigned char* encodedAlphaData = new unsigned char[alphaLength];

        file->Read(encodedRgbData, rgbLength);
        file->Read(encodedAlphaData, alphaLength);

        int width, height, components;
        unsigned char* decodedRgb = stbi_load_from_memory(encodedRgbData, rgbLength, &width, &height, &components, STBI_rgb);
        unsigned char* decodedAlpha = stbi_load_from_memory(encodedAlphaData, alphaLength, &width, &height, &components, STBI_grey);

        unsigned char* decoded = new unsigned char[width*height*4];

        unsigned char* decodedTemp = decoded;
        unsigned char* rgbTemp = decodedRgb;
        unsigned char* alphaTemp = decodedAlpha;

        for (int y=0; y<height; y++)
        {
            for (int x=0; x<width; x++)
            {
                decodedTemp[0] = rgbTemp[0];
                decodedTemp[1] = rgbTemp[1];
                decodedTemp[2] = rgbTemp[2];
                decodedTemp[3] = *alphaTemp;

                decodedTemp += 4;
                rgbTemp += 3;
                alphaTemp++;
            }
        }

        stbi_image_free(decodedRgb);
        stbi_image_free(decodedAlpha);

        status = LoadFromBytes(decoded, width, height, createMips, kTextureFormatRGBA, hasPremultipliedAlpha);

        delete[] decoded;
    } else {
        std::vector<unsigned char> data;
        unsigned char* decoded;

        pb::File* file = pb::FileSystem::Instance()->OpenFile(location, path);
        if (!file)
            return false;

        file->ReadAll(data);

        int width, height, components;
        decoded = stbi_load_from_memory(&data[0], data.size(), &width, &height, &components, STBI_default);

        if (!glm::isPowerOfTwo(width) || !glm::isPowerOfTwo(height))
            createMips = false;

        delete file;

        status = LoadFromBytes(decoded, width, height, createMips, components == 3 ? kTextureFormatRGB : kTextureFormatRGBA, hasPremultipliedAlpha);

        stbi_image_free(decoded);
    }

    return status;
}

const glm::vec2& Texture::GetSize() const
{
    return _Size;
}

bool Texture::HasPremultipliedAlpha() const
{
    return _HasPremultipliedAlpha;
}

void Texture::OnContextLost()
{
    LoadFromBytes(_Data, _Size.x, _Size.y, _DataCreateMips, _DataFormat, _HasPremultipliedAlpha);
}
<|endoftext|>


<commit_before>#ifndef MODBUS_HELP_COMMAND_HPP
#define MODBUS_HELP_COMMAND_HPP

#include "ModbusCommand.hpp"
#include <stdexcept>

struct ModbusCliHelpForCommand : std::runtime_error {
                                ModbusCliHelpForCommand(const std::string& cmd) : std::runtime_error(cmd) {}
};

struct ModbusCliHelpListCommands : std::runtime_error {
                                ModbusCliHelpListCommands() : std::runtime_error("") {}
};

class ModbusHelpCommand : public ModbusCommand {
public:
    inline                                          ModbusHelpCommand(const ModbusCommandsMap& commands);
    void                                            exec(ModbusClient& client, const std::vector<std::string>& args) override;
    std::string                                     getShortHelpText() const override;
    std::string                                     getHelpText() const override;

private:
    using OptionsDescription = boost::program_options::options_description;
    using PositionalOptionsDescription = boost::program_options::positional_options_description;

    void                                            show_commands_list() const;
    void                                            show_command_help() const;

    const ModbusCommandsMap                        &m_commands;
    std::string                                     m_cmd;
    OptionsDescription                              m_options;
    PositionalOptionsDescription                    m_positional_options;
};

ModbusHelpCommand::ModbusHelpCommand(const ModbusCommandsMap& commands) :
    ModbusCommand(),
    m_commands(commands),
    m_cmd(),
    m_options("options"),
    m_positional_options()
{
    namespace po = boost::program_options;

    m_options.add_options()
        ("cmd", po::value<std::string>(&m_cmd)->default_value(""), "show help for a command");

    m_positional_options.add("cmd", 1);
}

void ModbusHelpCommand::exec(ModbusClient& /*client*/, const std::vector<std::string>& args) {
    namespace po = boost::program_options;

    po::variables_map vm;
    po::store(po::command_line_parser(args).options(m_options).positional(m_positional_options).run(), vm);
    po::notify(vm);

    if (m_cmd == "")
        show_commands_list();
    else
        show_command_help();
}

void ModbusHelpCommand::show_commands_list() const {
    std::cout << "List of available commands:" << std::endl;

    for (const auto& kv: m_commands)
        std::cout << "    " << std::setw(15) << kv.first << " - " << kv.second->getShortHelpText() << std::endl;

    std::cout << "Type 'help <cmd>' to see details for each command." << std::endl;
}

void ModbusHelpCommand::show_command_help() const {
    auto cmdobj = m_commands.find(m_cmd);

    if (cmdobj == m_commands.end())
        std::cout << "No such command: " << m_cmd << std::endl;
    else
        std::cout << cmdobj->second->getHelpText() << std::endl;
}

std::string ModbusHelpCommand::getShortHelpText() const {
    return "Get list of available commands and help about each one";
}

std::string ModbusHelpCommand::getHelpText() const {
    std::stringstream ss;

    ss << getShortHelpText() << std::endl
       << "Usage:" << std::endl
       << "    help [<cmd>]" << std::endl
       << "If no command is given, a list of available commands is printed." << std::endl;

    return ss.str();
}

#endif

<commit_msg>Fix fill character for list of commands<commit_after>#ifndef MODBUS_HELP_COMMAND_HPP
#define MODBUS_HELP_COMMAND_HPP

#include "ModbusCommand.hpp"
#include <stdexcept>

struct ModbusCliHelpForCommand : std::runtime_error {
                                ModbusCliHelpForCommand(const std::string& cmd) : std::runtime_error(cmd) {}
};

struct ModbusCliHelpListCommands : std::runtime_error {
                                ModbusCliHelpListCommands() : std::runtime_error("") {}
};

class ModbusHelpCommand : public ModbusCommand {
public:
    inline                                          ModbusHelpCommand(const ModbusCommandsMap& commands);
    void                                            exec(ModbusClient& client, const std::vector<std::string>& args) override;
    std::string                                     getShortHelpText() const override;
    std::string                                     getHelpText() const override;

private:
    using OptionsDescription = boost::program_options::options_description;
    using PositionalOptionsDescription = boost::program_options::positional_options_description;

    void                                            show_commands_list() const;
    void                                            show_command_help() const;

    const ModbusCommandsMap                        &m_commands;
    std::string                                     m_cmd;
    OptionsDescription                              m_options;
    PositionalOptionsDescription                    m_positional_options;
};

ModbusHelpCommand::ModbusHelpCommand(const ModbusCommandsMap& commands) :
    ModbusCommand(),
    m_commands(commands),
    m_cmd(),
    m_options("options"),
    m_positional_options()
{
    namespace po = boost::program_options;

    m_options.add_options()
        ("cmd", po::value<std::string>(&m_cmd)->default_value(""), "show help for a command");

    m_positional_options.add("cmd", 1);
}

void ModbusHelpCommand::exec(ModbusClient& /*client*/, const std::vector<std::string>& args) {
    namespace po = boost::program_options;

    po::variables_map vm;
    po::store(po::command_line_parser(args).options(m_options).positional(m_positional_options).run(), vm);
    po::notify(vm);

    if (m_cmd == "")
        show_commands_list();
    else
        show_command_help();
}

void ModbusHelpCommand::show_commands_list() const {
    std::cout << "List of available commands:" << std::endl;
    std::cout << std::setfill(' ');

    for (const auto& kv: m_commands)
        std::cout << "    " << std::setw(15) << kv.first << " - " << kv.second->getShortHelpText() << std::endl;

    std::cout << "Type 'help <cmd>' to see details for each command." << std::endl;
}

void ModbusHelpCommand::show_command_help() const {
    auto cmdobj = m_commands.find(m_cmd);

    if (cmdobj == m_commands.end())
        std::cout << "No such command: " << m_cmd << std::endl;
    else
        std::cout << cmdobj->second->getHelpText() << std::endl;
}

std::string ModbusHelpCommand::getShortHelpText() const {
    return "Get list of available commands and help about each one";
}

std::string ModbusHelpCommand::getHelpText() const {
    std::stringstream ss;

    ss << getShortHelpText() << std::endl
       << "Usage:" << std::endl
       << "    help [<cmd>]" << std::endl
       << "If no command is given, a list of available commands is printed." << std::endl;

    return ss.str();
}

#endif

<|endoftext|>


<commit_before>/******************/
/*  hierarch.cpp  */
/******************/

#include "fctsys.h"
#include "gr_basic.h"
#include "common.h"
#include "class_drawpanel.h"
#include "confirm.h"
#include "bitmaps.h"

#include "program.h"
#include "general.h"

#include "wx/imaglist.h"
#include "wx/treectrl.h"

static bool UpdateScreenFromSheet( WinEDA_SchematicFrame* frame );

enum
{
    ID_TREECTRL_HIERARCHY = 1600
};

class WinEDA_HierFrame;

/* This class derived from wxTreeItemData stores the SCH_SHEET_PATH of each
 * sheet in hierarchy in each TreeItem, in its associated data buffer
*/
class TreeItemData : public wxTreeItemData
{
public:
    SCH_SHEET_PATH m_SheetPath;
    TreeItemData( SCH_SHEET_PATH sheet ) : wxTreeItemData()
    {
        m_SheetPath = sheet;
    }
};

/* Class to handle hierarchy tree. */
class WinEDA_Tree : public wxTreeCtrl
{
private:
    WinEDA_HierFrame* m_Parent;
    wxImageList*      imageList;

public:
    WinEDA_Tree() { }
    WinEDA_Tree( WinEDA_HierFrame* parent );

    DECLARE_DYNAMIC_CLASS( WinEDA_Tree )
};

IMPLEMENT_DYNAMIC_CLASS( WinEDA_Tree, wxTreeCtrl )

WinEDA_Tree::WinEDA_Tree( WinEDA_HierFrame* parent ) :
    wxTreeCtrl( (wxWindow*)parent, ID_TREECTRL_HIERARCHY,
                wxDefaultPosition, wxDefaultSize,
                wxTR_HAS_BUTTONS, wxDefaultValidator, wxT( "HierachyTreeCtrl" ) )
{
    m_Parent = parent;

    // Make an image list containing small icons
    imageList = new wxImageList( 16, 15, TRUE, 2 );

    imageList->Add( wxBitmap( tree_nosel_xpm ) );
    imageList->Add( wxBitmap( tree_sel_xpm ) );

    AssignImageList( imageList );
}

class WinEDA_HierFrame : public wxDialog
{
public:
    WinEDA_SchematicFrame* m_Parent;
    WinEDA_Tree*           m_Tree;
    int    m_nbsheets;
    wxDC*  m_DC;

private:
    wxSize m_TreeSize;
    int    maxposx;

public:
    WinEDA_HierFrame( WinEDA_SchematicFrame* parent, wxDC* DC, const wxPoint& pos );
    void BuildSheetsTree( SCH_SHEET_PATH* list, wxTreeItemId* previousmenu );

    ~WinEDA_HierFrame();

    void OnSelect( wxTreeEvent& event );

private:
    void OnQuit( wxCommandEvent& event );

    DECLARE_EVENT_TABLE()
};

BEGIN_EVENT_TABLE( WinEDA_HierFrame, wxDialog )
    EVT_TREE_ITEM_ACTIVATED( ID_TREECTRL_HIERARCHY,
                             WinEDA_HierFrame::OnSelect )
END_EVENT_TABLE()

void WinEDA_SchematicFrame::InstallHierarchyFrame( wxDC* DC, wxPoint& pos )
{
    WinEDA_HierFrame* treeframe = new WinEDA_HierFrame( this, DC, pos );

    treeframe->ShowModal();
    treeframe->Destroy();
}

WinEDA_HierFrame::WinEDA_HierFrame( WinEDA_SchematicFrame* parent, wxDC* DC,
                                    const wxPoint& pos ) :
    wxDialog( parent, -1, _( "Navigator" ), pos, wxSize( 110, 50 ),
              DIALOG_STYLE )
{
    wxTreeItemId cellule;

    m_Parent = parent;
    m_DC   = DC;
    m_Tree = new WinEDA_Tree( this );

    m_nbsheets = 1;

    cellule = m_Tree->AddRoot( _( "Root" ), 0, 1 );
    m_Tree->SetItemBold( cellule, TRUE );
    SCH_SHEET_PATH list;
    list.Push( g_RootSheet );
    m_Tree->SetItemData( cellule, new TreeItemData( list ) );

    wxRect itemrect;
#ifdef __UNIX__
    itemrect.SetWidth( 100 );
    itemrect.SetHeight( 20 );
#else
    m_Tree->GetBoundingRect( cellule, itemrect );
#endif
    m_TreeSize.x = itemrect.GetWidth() + 10;
    m_TreeSize.y = 20;

    if( m_Parent->GetSheet()->Last() == g_RootSheet )
        m_Tree->SelectItem( cellule ); //root.

    maxposx = 15;
    BuildSheetsTree( &list, &cellule );

    if( m_nbsheets > 1 )
    {
        m_Tree->Expand( cellule );

        // Readjust the size of the frame to an optimal value.
        m_TreeSize.y += m_nbsheets * itemrect.GetHeight();
        m_TreeSize.x  = MIN( m_TreeSize.x, 250 );
        m_TreeSize.y  = MIN( m_TreeSize.y, 350 );
        SetClientSize( m_TreeSize );
    }
}

WinEDA_HierFrame::~WinEDA_HierFrame()
{
}

void WinEDA_HierFrame::OnQuit( wxCommandEvent& WXUNUSED (event) )
{
    // true is to force the frame to close
    Close( true );
}

/* Routine to create the tree in the navigation hierarchy
 * Schematic
 * This routine is re-entrant!
 */
void WinEDA_HierFrame::BuildSheetsTree( SCH_SHEET_PATH* list,
                                        wxTreeItemId*  previousmenu )

{
    wxTreeItemId menu;

    if( m_nbsheets > NB_MAX_SHEET )
    {
        if( m_nbsheets == (NB_MAX_SHEET + 1) )
        {
            wxString msg;
            msg << wxT( "BuildSheetsTree: Error: nbsheets > " ) << NB_MAX_SHEET;
            DisplayError( this, msg );
            m_nbsheets++;
        }
        return;
    }

    maxposx += m_Tree->GetIndent();
    SCH_ITEM* schitem = list->LastDrawList();
    while( schitem && m_nbsheets < NB_MAX_SHEET )
    {
        if( schitem->Type() == DRAW_SHEET_STRUCT_TYPE )
        {
            SCH_SHEET* sheet = (SCH_SHEET*) schitem;
            m_nbsheets++;
            menu = m_Tree->AppendItem( *previousmenu, sheet->m_SheetName, 0, 1 );
            list->Push( sheet );
            m_Tree->SetItemData( menu, new TreeItemData( *list ) );
            int ll = m_Tree->GetItemText( menu ).Len();
#ifdef __WINDOWS__
            ll *= 9;    //  * char width
#else
            ll *= 12;   //  * char width
#endif
            ll += maxposx + 20;
            m_TreeSize.x  = MAX( m_TreeSize.x, ll );
            m_TreeSize.y += 1;
            if( *list == *( m_Parent->GetSheet() ) )
            {
                m_Tree->EnsureVisible( menu );
                m_Tree->SelectItem( menu );
            }
            BuildSheetsTree( list, &menu );
            m_Tree->Expand( menu );
            list->Pop();
        }
        schitem = schitem->Next();
    }

    maxposx -= m_Tree->GetIndent();
}

/* Called on a double-click on a tree item:
 * Open the selected sheet, and display the corresponding screen
 */
void WinEDA_HierFrame::OnSelect( wxTreeEvent& event )

{
    wxTreeItemId ItemSel = m_Tree->GetSelection();

    *(m_Parent->m_CurrentSheet) =
        ( (TreeItemData*) m_Tree->GetItemData( ItemSel ) )->m_SheetPath;
    UpdateScreenFromSheet( m_Parent );
    Close( TRUE );
}

/* Set the current screen to display the parent sheet of the current
 * displayed sheet
 */
void WinEDA_SchematicFrame::InstallPreviousSheet()
{
    if( m_CurrentSheet->Last() == g_RootSheet )
        return;

    g_ItemToRepeat = NULL;
    ClearMsgPanel();

    //make a copy for testing purposes.
    SCH_SHEET_PATH listtemp = *m_CurrentSheet;
    listtemp.Pop();
    if( listtemp.LastScreen() == NULL )
    {
        DisplayError( this,
                      wxT( "InstallPreviousScreen() Error: Sheet not found" ) );
        return;
    }
    m_CurrentSheet->Pop();
    UpdateScreenFromSheet( this );
}

/* Routine installation of the screen corresponding to the symbol edge Sheet
 * Be careful here because the SCH_SHEETs within the EEDrawList
 * don't actually have a valid m_AssociatedScreen (on purpose -- you need the
 * m_SubSheet hierarchy to maintain path info (well, this is but one way to
 * maintain path info..)
 */
void WinEDA_SchematicFrame::InstallNextScreen( SCH_SHEET* Sheet )
{
    if( Sheet == NULL )
    {
        DisplayError( this, wxT( "InstallNextScreen() error" ) ); return;
    }
    m_CurrentSheet->Push( Sheet );
    g_ItemToRepeat = NULL;
    ClearMsgPanel();
    UpdateScreenFromSheet( this );
}

/* Find and install the screen on the sheet symbol Sheet.
 * If Sheet == NULL installation of the screen base (Root).
 */
static bool UpdateScreenFromSheet( WinEDA_SchematicFrame* frame )
{
    SCH_SCREEN* NewScreen;

    NewScreen = frame->m_CurrentSheet->LastScreen();
    if( !NewScreen )
    {
        DisplayError( frame, wxT( "Screen not found for this sheet" ) );
        return false;
    }

    // Reset display settings of the new screen
    // Assumes m_CurrentSheet has already been updated.
    frame->ClearMsgPanel();
    frame->DrawPanel->SetScrollbars( NewScreen->m_ZoomScalar,
                                     NewScreen->m_ZoomScalar,
                                     NewScreen->m_ScrollbarNumber.x,
                                     NewScreen->m_ScrollbarNumber.y,
                                     NewScreen->m_ScrollbarPos.x,
                                     NewScreen->m_ScrollbarPos.y, TRUE );

    // update the References
    frame->m_CurrentSheet->UpdateAllScreenReferences();
    frame->SetSheetNumberAndCount();
    frame->DrawPanel->m_CanStartBlock = -1;
    ActiveScreen = frame->m_CurrentSheet->LastScreen();

    if( NewScreen->m_FirstRedraw )
    {
        NewScreen->m_FirstRedraw = FALSE;
        frame->Zoom_Automatique( TRUE );
    }
    else
    {
        frame->DrawPanel->MouseToCursorSchema();
    }

    frame->DrawPanel->Refresh();
    return true;
}
<commit_msg>Fixed problem in eeschema when leaving sub sheet in a hierarchy. (two scrolling parameters were different when calling SetScroolBars in drawframe.cpp and hierarch.cpp <commit_after>/******************/
/*  hierarch.cpp  */
/******************/

#include "fctsys.h"
#include "gr_basic.h"
#include "common.h"
#include "class_drawpanel.h"
#include "confirm.h"
#include "bitmaps.h"

#include "program.h"
#include "general.h"

#include "wx/imaglist.h"
#include "wx/treectrl.h"

static bool UpdateScreenFromSheet( WinEDA_SchematicFrame* frame );

enum
{
    ID_TREECTRL_HIERARCHY = 1600
};

class WinEDA_HierFrame;

/* This class derived from wxTreeItemData stores the SCH_SHEET_PATH of each
 * sheet in hierarchy in each TreeItem, in its associated data buffer
*/
class TreeItemData : public wxTreeItemData
{
public:
    SCH_SHEET_PATH m_SheetPath;
    TreeItemData( SCH_SHEET_PATH sheet ) : wxTreeItemData()
    {
        m_SheetPath = sheet;
    }
};

/* Class to handle hierarchy tree. */
class WinEDA_Tree : public wxTreeCtrl
{
private:
    WinEDA_HierFrame* m_Parent;
    wxImageList*      imageList;

public:
    WinEDA_Tree() { }
    WinEDA_Tree( WinEDA_HierFrame* parent );

    DECLARE_DYNAMIC_CLASS( WinEDA_Tree )
};

IMPLEMENT_DYNAMIC_CLASS( WinEDA_Tree, wxTreeCtrl )

WinEDA_Tree::WinEDA_Tree( WinEDA_HierFrame* parent ) :
    wxTreeCtrl( (wxWindow*)parent, ID_TREECTRL_HIERARCHY,
                wxDefaultPosition, wxDefaultSize,
                wxTR_HAS_BUTTONS, wxDefaultValidator, wxT( "HierachyTreeCtrl" ) )
{
    m_Parent = parent;

    // Make an image list containing small icons
    imageList = new wxImageList( 16, 15, TRUE, 2 );

    imageList->Add( wxBitmap( tree_nosel_xpm ) );
    imageList->Add( wxBitmap( tree_sel_xpm ) );

    AssignImageList( imageList );
}

class WinEDA_HierFrame : public wxDialog
{
public:
    WinEDA_SchematicFrame* m_Parent;
    WinEDA_Tree*           m_Tree;
    int    m_nbsheets;
    wxDC*  m_DC;

private:
    wxSize m_TreeSize;
    int    maxposx;

public:
    WinEDA_HierFrame( WinEDA_SchematicFrame* parent, wxDC* DC, const wxPoint& pos );
    void BuildSheetsTree( SCH_SHEET_PATH* list, wxTreeItemId* previousmenu );

    ~WinEDA_HierFrame();

    void OnSelect( wxTreeEvent& event );

private:
    void OnQuit( wxCommandEvent& event );

    DECLARE_EVENT_TABLE()
};

BEGIN_EVENT_TABLE( WinEDA_HierFrame, wxDialog )
    EVT_TREE_ITEM_ACTIVATED( ID_TREECTRL_HIERARCHY,
                             WinEDA_HierFrame::OnSelect )
END_EVENT_TABLE()

void WinEDA_SchematicFrame::InstallHierarchyFrame( wxDC* DC, wxPoint& pos )
{
    WinEDA_HierFrame* treeframe = new WinEDA_HierFrame( this, DC, pos );

    treeframe->ShowModal();
    treeframe->Destroy();
}

WinEDA_HierFrame::WinEDA_HierFrame( WinEDA_SchematicFrame* parent, wxDC* DC,
                                    const wxPoint& pos ) :
    wxDialog( parent, -1, _( "Navigator" ), pos, wxSize( 110, 50 ),
              DIALOG_STYLE )
{
    wxTreeItemId cellule;

    m_Parent = parent;
    m_DC   = DC;
    m_Tree = new WinEDA_Tree( this );

    m_nbsheets = 1;

    cellule = m_Tree->AddRoot( _( "Root" ), 0, 1 );
    m_Tree->SetItemBold( cellule, TRUE );
    SCH_SHEET_PATH list;
    list.Push( g_RootSheet );
    m_Tree->SetItemData( cellule, new TreeItemData( list ) );

    wxRect itemrect;
#ifdef __UNIX__
    itemrect.SetWidth( 100 );
    itemrect.SetHeight( 20 );
#else
    m_Tree->GetBoundingRect( cellule, itemrect );
#endif
    m_TreeSize.x = itemrect.GetWidth() + 10;
    m_TreeSize.y = 20;

    if( m_Parent->GetSheet()->Last() == g_RootSheet )
        m_Tree->SelectItem( cellule ); //root.

    maxposx = 15;
    BuildSheetsTree( &list, &cellule );

    if( m_nbsheets > 1 )
    {
        m_Tree->Expand( cellule );

        // Readjust the size of the frame to an optimal value.
        m_TreeSize.y += m_nbsheets * itemrect.GetHeight();
        m_TreeSize.x  = MIN( m_TreeSize.x, 250 );
        m_TreeSize.y  = MIN( m_TreeSize.y, 350 );
        SetClientSize( m_TreeSize );
    }
}

WinEDA_HierFrame::~WinEDA_HierFrame()
{
}

void WinEDA_HierFrame::OnQuit( wxCommandEvent& WXUNUSED (event) )
{
    // true is to force the frame to close
    Close( true );
}

/* Routine to create the tree in the navigation hierarchy
 * Schematic
 * This routine is re-entrant!
 */
void WinEDA_HierFrame::BuildSheetsTree( SCH_SHEET_PATH* list,
                                        wxTreeItemId*  previousmenu )

{
    wxTreeItemId menu;

    if( m_nbsheets > NB_MAX_SHEET )
    {
        if( m_nbsheets == (NB_MAX_SHEET + 1) )
        {
            wxString msg;
            msg << wxT( "BuildSheetsTree: Error: nbsheets > " ) << NB_MAX_SHEET;
            DisplayError( this, msg );
            m_nbsheets++;
        }
        return;
    }

    maxposx += m_Tree->GetIndent();
    SCH_ITEM* schitem = list->LastDrawList();
    while( schitem && m_nbsheets < NB_MAX_SHEET )
    {
        if( schitem->Type() == DRAW_SHEET_STRUCT_TYPE )
        {
            SCH_SHEET* sheet = (SCH_SHEET*) schitem;
            m_nbsheets++;
            menu = m_Tree->AppendItem( *previousmenu, sheet->m_SheetName, 0, 1 );
            list->Push( sheet );
            m_Tree->SetItemData( menu, new TreeItemData( *list ) );
            int ll = m_Tree->GetItemText( menu ).Len();
#ifdef __WINDOWS__
            ll *= 9;    //  * char width
#else
            ll *= 12;   //  * char width
#endif
            ll += maxposx + 20;
            m_TreeSize.x  = MAX( m_TreeSize.x, ll );
            m_TreeSize.y += 1;
            if( *list == *( m_Parent->GetSheet() ) )
            {
                m_Tree->EnsureVisible( menu );
                m_Tree->SelectItem( menu );
            }
            BuildSheetsTree( list, &menu );
            m_Tree->Expand( menu );
            list->Pop();
        }
        schitem = schitem->Next();
    }

    maxposx -= m_Tree->GetIndent();
}

/* Called on a double-click on a tree item:
 * Open the selected sheet, and display the corresponding screen
 */
void WinEDA_HierFrame::OnSelect( wxTreeEvent& event )

{
    wxTreeItemId ItemSel = m_Tree->GetSelection();

    *(m_Parent->m_CurrentSheet) =
        ( (TreeItemData*) m_Tree->GetItemData( ItemSel ) )->m_SheetPath;
    UpdateScreenFromSheet( m_Parent );
    Close( TRUE );
}

/* Set the current screen to display the parent sheet of the current
 * displayed sheet
 */
void WinEDA_SchematicFrame::InstallPreviousSheet()
{
    if( m_CurrentSheet->Last() == g_RootSheet )
        return;

    g_ItemToRepeat = NULL;
    ClearMsgPanel();

    //make a copy for testing purposes.
    SCH_SHEET_PATH listtemp = *m_CurrentSheet;
    listtemp.Pop();
    if( listtemp.LastScreen() == NULL )
    {
        DisplayError( this,
                      wxT( "InstallPreviousScreen() Error: Sheet not found" ) );
        return;
    }
    m_CurrentSheet->Pop();
    UpdateScreenFromSheet( this );
}

/* Routine installation of the screen corresponding to the symbol edge Sheet
 * Be careful here because the SCH_SHEETs within the EEDrawList
 * don't actually have a valid m_AssociatedScreen (on purpose -- you need the
 * m_SubSheet hierarchy to maintain path info (well, this is but one way to
 * maintain path info..)
 */
void WinEDA_SchematicFrame::InstallNextScreen( SCH_SHEET* Sheet )
{
    if( Sheet == NULL )
    {
        DisplayError( this, wxT( "InstallNextScreen() error" ) ); return;
    }
    m_CurrentSheet->Push( Sheet );
    g_ItemToRepeat = NULL;
    ClearMsgPanel();
    UpdateScreenFromSheet( this );
}

/* Find and install the screen on the sheet symbol Sheet.
 * If Sheet == NULL installation of the screen base (Root).
 */
static bool UpdateScreenFromSheet( WinEDA_SchematicFrame* frame )
{
    SCH_SCREEN* NewScreen;

    NewScreen = frame->m_CurrentSheet->LastScreen();
    if( !NewScreen )
    {
        DisplayError( frame, wxT( "Screen not found for this sheet" ) );
        return false;
    }

    // Reset display settings of the new screen
    // Assumes m_CurrentSheet has already been updated.
    frame->ClearMsgPanel();
    int pixelsPerUnitX = 1;
    int pixelsPerUnitY = 1;
    frame->DrawPanel->SetScrollbars( pixelsPerUnitX, pixelsPerUnitY,
                                     NewScreen->m_ScrollbarNumber.x,
                                     NewScreen->m_ScrollbarNumber.y,
                                     NewScreen->m_ScrollbarPos.x,
                                     NewScreen->m_ScrollbarPos.y, TRUE );

    // update the References
    frame->m_CurrentSheet->UpdateAllScreenReferences();
    frame->SetSheetNumberAndCount();
    frame->DrawPanel->m_CanStartBlock = -1;
    ActiveScreen = frame->m_CurrentSheet->LastScreen();

    if( NewScreen->m_FirstRedraw )
    {
        NewScreen->m_FirstRedraw = FALSE;
        frame->Zoom_Automatique( TRUE );
    }
    else
    {
        frame->DrawPanel->MouseToCursorSchema();
    }

    frame->DrawPanel->Refresh();
    return true;
}
<|endoftext|>


<commit_before><commit_msg>Add output to the thread test<commit_after><|endoftext|>


<commit_before>/*
 * DynamicHyperbolicGenerator.cpp
 *
 *  Created on: 29.07.2014
 *      Author: moritzl
 */

#include <cmath>

#include "DynamicHyperbolicGenerator.h"
#include "HyperbolicGenerator.h"
#include "../geometric/HyperbolicSpace.h"

using std::vector;
namespace NetworKit {

DynamicHyperbolicGenerator::DynamicHyperbolicGenerator() {
	// TODO Auto-generated constructor stub

}

DynamicHyperbolicGenerator::DynamicHyperbolicGenerator(count n, double initialFactor, double alpha, double stretch, double moveEachStep, double factorgrowth, double moveDistance) {
	nodes = n;
	currentfactor = initialFactor;
	this->alpha = alpha;
	this->stretch = stretch;
	this->moveEachStep = moveEachStep;
	this->factorgrowth = factorgrowth;
	this->moveDistance = moveDistance;
	this->initialized = false;
}

DynamicHyperbolicGenerator::DynamicHyperbolicGenerator(vector<double> &angles, vector<double> &radii, double R, double initialFactor, double moveEachStep, double factorgrowth, double moveDistance) {
	this->angles = angles;
	this->radii = radii;
	this->nodes = angles.size();
	assert(radii.size() == nodes);
	double r = HyperbolicSpace::hyperbolicRadiusToEuclidean(R);
	quad = Quadtree<index>(r);
	currentfactor = initialFactor;
	this->alpha = 1;//not needed any more
	this->stretch = 1;//not needed any more
	this->moveEachStep = moveEachStep;
	this->factorgrowth = factorgrowth;
	this->moveDistance = moveDistance;
	this->initialized = true;
	for (index i = 0; i < nodes; i++) {
		assert(radii[i] < r);
		quad.addContent(i, angles[i], radii[i]);
	}
	INFO("Filled Quadtree");
}

DynamicHyperbolicGenerator::~DynamicHyperbolicGenerator() {
	// TODO Auto-generated destructor stub
}

void DynamicHyperbolicGenerator::initializeQuadTree() {
	if (initialized) return;
	else initialized = true;
	double R = stretch*acosh((double)nodes/(2*M_PI)+1);
	angles.resize(nodes);
	radii.resize(nodes);
	double rad_nom = (cosh(R)-1);
	double rad_denom = (cosh(R)+1);
	double r = sqrt(rad_nom/rad_denom);
	quad = Quadtree<index>(r);
	HyperbolicSpace::fillPoints(&angles, &radii, stretch, alpha);
	INFO("Generated Points");
	for (index i = 0; i < nodes; i++) {
		assert(radii[i] < R);
		quad.addContent(i, angles[i], radii[i]);
	}
	INFO("Filled Quadtree");
}

Graph DynamicHyperbolicGenerator::getGraph() {
	if (!initialized) initializeQuadTree();//this is horribly expensive, since it constructs a new Quadtree
	double R = stretch*acosh((double)nodes/(2*M_PI)+1);
	double r = HyperbolicSpace::hyperbolicRadiusToEuclidean(R);
	/**
	 * The next call is unnecessarily expensive, since it constructs a new QuadTree.
	 * Reduces code duplication, though.
	 */
	return HyperbolicGenerator::generate(&angles, &radii, r, currentfactor*R);
}

std::vector<Point<float> > DynamicHyperbolicGenerator::getCoordinates() const {
	count n = angles.size();
	assert(radii.size() == n);
	std::vector<Point<float> > result;
	for (index i = 0; i < angles.size(); i++) {
		Point2D<double> coord = HyperbolicSpace::polarToCartesian(angles[i], radii[i]);
		Point<float> temp(coord[0], coord[1]);
		result.push_back(temp);
	}
	return result;
}

std::vector<Point<float> > DynamicHyperbolicGenerator::getHyperbolicCoordinates() const {
	count n = angles.size();
	assert(radii.size() == n);
	std::vector<Point<float> > result;
	for (index i = 0; i < angles.size(); i++) {
		Point2D<double> coord = HyperbolicSpace::polarToCartesian(angles[i], HyperbolicSpace::EuclideanRadiusToHyperbolic(radii[i]));
		Point<float> temp(coord[0], coord[1]);
		result.push_back(temp);
	}
	return result;
}

std::vector<GraphEvent> DynamicHyperbolicGenerator::generate(count nSteps) {
	if (!initialized) initializeQuadTree();
	assert(quad.size() == nodes);
	vector<GraphEvent> result;
	double R = stretch*acosh((double)nodes/(2*M_PI)+1);
	double r = HyperbolicSpace::hyperbolicRadiusToEuclidean(R);

	for (index step = 0; step < nSteps; step++) {
		count oldStreamMarker = result.size();
		assert(factorgrowth == 0 || moveEachStep == 0 || moveDistance == 0);
		if (factorgrowth != 0) {
			//nodes are stationary, growing factors
			double newfactor = currentfactor + factorgrowth;
/**
 * TODO: get all neighbours in the beginning, sort them by hyperbolic distance, move along edge array.
 */
			#pragma omp parallel for
			for (index i = 0; i < nodes; i++) {
				assert(R*newfactor > R*currentfactor);
				vector<index> oldset = quad.getCloseElements(HyperbolicSpace::polarToCartesian(angles[i], radii[i]), R*currentfactor);
				//we only add new edges, don't remove any. The order of the points should be the same
				vector<index> newset = quad.getCloseElements(HyperbolicSpace::polarToCartesian(angles[i], radii[i]), R*newfactor);
				assert(newset.size() >= oldset.size());
				std::sort(oldset.begin(), oldset.end());
				std::sort(newset.begin(), newset.end());
				vector<index> difference(newset.size());

				//get new edges
				auto it = std::set_difference(newset.begin(), newset.end(), oldset.begin(), oldset.end(), difference.begin());

				//keep only those pointing to higher node indices, we don't want any multiedges
				it = std::remove_if(difference.begin(), it, [i](index edge){return i >= edge;});
				difference.resize(it - difference.begin());

				#pragma omp critical
				{
					for (auto edge : difference) {
						result.emplace_back(GraphEvent::EDGE_ADDITION, i, edge);
					}
				}

			}
			currentfactor = newfactor;
		}
		else {
			vector<index> toWiggle;
			vector<vector<index> > oldNeighbours;
			//TODO: One could parallelize this.
			for (index i = 0; i < nodes; i++) {
				if (Aux::Random::real(1) < moveEachStep) {
					toWiggle.push_back(i);
					oldNeighbours.push_back(quad.getCloseElements(HyperbolicSpace::polarToCartesian(angles[i], radii[i]), R*currentfactor));
				}
			}
			/**
			 * Tried to parallelize this, didn't bring any benefit.
			 * Not surprising, since most of the work - manipulating the QuadTree - needs to be done in a critical section
			 */
			for (index j = 0; j < toWiggle.size(); j++) {
				//wiggle this node!
				double hyperbolicRadius = HyperbolicSpace::EuclideanRadiusToHyperbolic(radii[toWiggle[j]]);

				//angular movement

				double maxcdf = cosh(R);
				double mincdf = 1;
				double currcdf = cosh(hyperbolicRadius);

				double offset = moveEachStep*50;
				double random = Aux::Random::real(currcdf-offset, currcdf+offset);
				if (random > maxcdf) {
					random -= 2*(random - maxcdf);
				}
				if (random < mincdf) {
					random += 2*(mincdf - random);
				}
				double newradius = acosh(random)/alpha;
				//assert(abs(newradius - hyperbolicRadius) < moveEachStep);
				if (newradius >= R) newradius = std::nextafter(R, std::numeric_limits<double>::lowest());
				assert(newradius < R);
				assert(newradius >= 0);

				double angleMovement = Aux::Random::real(-moveEachStep/hyperbolicRadius, moveEachStep/hyperbolicRadius);
				double newphi = angles[toWiggle[j]] + angleMovement;
				if (newphi < 0) newphi += (floor(-newphi/(2*M_PI))+1)*2*M_PI;
				if (newphi > 2*M_PI) newphi -= floor(newphi/(2*M_PI))*2*M_PI;

				//bounce off the boundary
				newradius = HyperbolicSpace::hyperbolicRadiusToEuclidean(newradius);
				if (newradius >= r) newradius = std::nextafter(newradius, std::numeric_limits<double>::lowest());

				//updating Quadtree
				bool removed = quad.removeContent(toWiggle[j], angles[toWiggle[j]], radii[toWiggle[j]]);
				assert(removed);
				angles[toWiggle[j]] = newphi;
				radii[toWiggle[j]] = newradius;
				quad.addContent(toWiggle[j], newphi, newradius);

			}

			//now get the new edges and see what changed
			#pragma omp parallel for
			for (index j = 0; j < toWiggle.size(); j++) {
				vector<index> newNeighbours = quad.getCloseElements(HyperbolicSpace::polarToCartesian(angles[toWiggle[j]], radii[toWiggle[j]]), R*currentfactor);
				std::sort(oldNeighbours[j].begin(), oldNeighbours[j].end());
				std::sort(newNeighbours.begin(), newNeighbours.end());
				vector<index> newEdges(newNeighbours.size());
				auto it = std::set_difference(newNeighbours.begin(), newNeighbours.end(), oldNeighbours[j].begin(), oldNeighbours[j].end(), newEdges.begin());
				newEdges.erase(it, newEdges.end());//trim empty space

				vector<index> brokenEdges(oldNeighbours[j].size() - (newNeighbours.size() - newEdges.size()));//this should be the number of broken edges
				it = std::set_difference(oldNeighbours[j].begin(), oldNeighbours[j].end(), newNeighbours.begin(), newNeighbours.end(), brokenEdges.begin());
				assert(it == brokenEdges.end());

				#pragma omp critical
				{
					for (index edge : newEdges) {
						result.emplace_back(GraphEvent::EDGE_ADDITION, toWiggle[j], edge);
					}
					for (index edge : brokenEdges) {
						result.emplace_back(GraphEvent::EDGE_REMOVAL, toWiggle[j], edge);
					}
				}
			}

			/**
			 * since we didn't know whether the other endpoint of an edge was wiggled or not, we may
			 * have added some of them twice.
			 * Remove the doubles:
			 */
			for (auto it = result.begin()+oldStreamMarker; it < result.end(); it++) {
				if (it->u > it->v) std::swap(it->u, it->v);
			}
			std::sort(result.begin()+oldStreamMarker, result.end(), GraphEvent::compare);
			auto end = std::unique(result.begin()+oldStreamMarker, result.end(), GraphEvent::equal);
			result.erase(end, result.end());
		}
		result.push_back(GraphEvent(GraphEvent::TIME_STEP));
	}
	return result;
}
} /* namespace NetworKit */
<commit_msg>fixed embarassing bug in DynamicHyperbolicGenerator<commit_after>/*
 * DynamicHyperbolicGenerator.cpp
 *
 *  Created on: 29.07.2014
 *      Author: moritzl
 */

#include <cmath>

#include "DynamicHyperbolicGenerator.h"
#include "HyperbolicGenerator.h"
#include "../geometric/HyperbolicSpace.h"

using std::vector;
namespace NetworKit {

DynamicHyperbolicGenerator::DynamicHyperbolicGenerator() {
	// TODO Auto-generated constructor stub

}

DynamicHyperbolicGenerator::DynamicHyperbolicGenerator(count n, double initialFactor, double alpha, double stretch, double moveEachStep, double factorgrowth, double moveDistance) {
	nodes = n;
	currentfactor = initialFactor;
	this->alpha = alpha;
	this->stretch = stretch;
	this->moveEachStep = moveEachStep;
	this->factorgrowth = factorgrowth;
	this->moveDistance = moveDistance;
	this->initialized = false;
}

DynamicHyperbolicGenerator::DynamicHyperbolicGenerator(vector<double> &angles, vector<double> &radii, double R, double initialFactor, double moveEachStep, double factorgrowth, double moveDistance) {
	this->angles = angles;
	this->radii = radii;
	this->nodes = angles.size();
	assert(radii.size() == nodes);
	double r = HyperbolicSpace::hyperbolicRadiusToEuclidean(R);
	quad = Quadtree<index>(r);
	currentfactor = initialFactor;
	this->alpha = 1;//not needed any more
	this->stretch = 1;//not needed any more
	this->moveEachStep = moveEachStep;
	this->factorgrowth = factorgrowth;
	this->moveDistance = moveDistance;
	this->initialized = true;
	for (index i = 0; i < nodes; i++) {
		assert(radii[i] < r);
		quad.addContent(i, angles[i], radii[i]);
	}
	INFO("Filled Quadtree");
}

DynamicHyperbolicGenerator::~DynamicHyperbolicGenerator() {
	// TODO Auto-generated destructor stub
}

void DynamicHyperbolicGenerator::initializeQuadTree() {
	if (initialized) return;
	else initialized = true;
	double R = stretch*acosh((double)nodes/(2*M_PI)+1);
	angles.resize(nodes);
	radii.resize(nodes);
	double rad_nom = (cosh(R)-1);
	double rad_denom = (cosh(R)+1);
	double r = sqrt(rad_nom/rad_denom);
	quad = Quadtree<index>(r);
	HyperbolicSpace::fillPoints(&angles, &radii, stretch, alpha);
	INFO("Generated Points");
	for (index i = 0; i < nodes; i++) {
		assert(radii[i] < R);
		quad.addContent(i, angles[i], radii[i]);
	}
	INFO("Filled Quadtree");
}

Graph DynamicHyperbolicGenerator::getGraph() {
	if (!initialized) initializeQuadTree();//this is horribly expensive, since it constructs a new Quadtree
	double R = stretch*acosh((double)nodes/(2*M_PI)+1);
	double r = HyperbolicSpace::hyperbolicRadiusToEuclidean(R);
	/**
	 * The next call is unnecessarily expensive, since it constructs a new QuadTree.
	 * Reduces code duplication, though.
	 */
	return HyperbolicGenerator::generate(&angles, &radii, r, currentfactor*R);
}

std::vector<Point<float> > DynamicHyperbolicGenerator::getCoordinates() const {
	count n = angles.size();
	assert(radii.size() == n);
	std::vector<Point<float> > result;
	for (index i = 0; i < angles.size(); i++) {
		Point2D<double> coord = HyperbolicSpace::polarToCartesian(angles[i], radii[i]);
		Point<float> temp(coord[0], coord[1]);
		result.push_back(temp);
	}
	return result;
}

std::vector<Point<float> > DynamicHyperbolicGenerator::getHyperbolicCoordinates() const {
	count n = angles.size();
	assert(radii.size() == n);
	std::vector<Point<float> > result;
	for (index i = 0; i < angles.size(); i++) {
		Point2D<double> coord = HyperbolicSpace::polarToCartesian(angles[i], HyperbolicSpace::EuclideanRadiusToHyperbolic(radii[i]));
		Point<float> temp(coord[0], coord[1]);
		result.push_back(temp);
	}
	return result;
}

std::vector<GraphEvent> DynamicHyperbolicGenerator::generate(count nSteps) {
	if (!initialized) initializeQuadTree();
	assert(quad.size() == nodes);
	vector<GraphEvent> result;
	double R = stretch*acosh((double)nodes/(2*M_PI)+1);
	double r = HyperbolicSpace::hyperbolicRadiusToEuclidean(R);

	for (index step = 0; step < nSteps; step++) {
		count oldStreamMarker = result.size();
		assert(factorgrowth == 0 || moveEachStep == 0 || moveDistance == 0);
		if (factorgrowth != 0) {
			//nodes are stationary, growing factors
			double newfactor = currentfactor + factorgrowth;
/**
 * TODO: get all neighbours in the beginning, sort them by hyperbolic distance, move along edge array.
 */
			#pragma omp parallel for
			for (index i = 0; i < nodes; i++) {
				assert(R*newfactor > R*currentfactor);
				vector<index> oldset = quad.getCloseElements(HyperbolicSpace::polarToCartesian(angles[i], radii[i]), R*currentfactor);
				//we only add new edges, don't remove any. The order of the points should be the same
				vector<index> newset = quad.getCloseElements(HyperbolicSpace::polarToCartesian(angles[i], radii[i]), R*newfactor);
				assert(newset.size() >= oldset.size());
				std::sort(oldset.begin(), oldset.end());
				std::sort(newset.begin(), newset.end());
				vector<index> difference(newset.size());

				//get new edges
				auto it = std::set_difference(newset.begin(), newset.end(), oldset.begin(), oldset.end(), difference.begin());

				//keep only those pointing to higher node indices, we don't want any multiedges
				it = std::remove_if(difference.begin(), it, [i](index edge){return i >= edge;});
				difference.resize(it - difference.begin());

				#pragma omp critical
				{
					for (auto edge : difference) {
						result.emplace_back(GraphEvent::EDGE_ADDITION, i, edge);
					}
				}

			}
			currentfactor = newfactor;
		}
		else {
			vector<index> toWiggle;
			vector<vector<index> > oldNeighbours;
			//TODO: One could parallelize this.
			for (index i = 0; i < nodes; i++) {
				if (Aux::Random::real(1) < moveEachStep) {
					toWiggle.push_back(i);
					oldNeighbours.push_back(quad.getCloseElements(HyperbolicSpace::polarToCartesian(angles[i], radii[i]), R*currentfactor));
				}
			}
			/**
			 * Tried to parallelize this, didn't bring any benefit.
			 * Not surprising, since most of the work - manipulating the QuadTree - needs to be done in a critical section
			 */
			for (index j = 0; j < toWiggle.size(); j++) {
				//wiggle this node!
				double hyperbolicRadius = HyperbolicSpace::EuclideanRadiusToHyperbolic(radii[toWiggle[j]]);

				//angular movement

				double maxcdf = cosh(R);
				double mincdf = 1;
				double currcdf = cosh(hyperbolicRadius);

				double offset = moveDistance;
				double random = Aux::Random::real(currcdf-offset, currcdf+offset);
				if (random > maxcdf) {
					random -= 2*(random - maxcdf);
				}
				if (random < mincdf) {
					random += 2*(mincdf - random);
				}
				double newradius = acosh(random)/alpha;
				//assert(abs(newradius - hyperbolicRadius) < moveEachStep);
				if (newradius >= R) newradius = std::nextafter(R, std::numeric_limits<double>::lowest());
				assert(newradius < R);
				assert(newradius >= 0);

				double angleMovement = Aux::Random::real(-moveDistance/hyperbolicRadius, moveDistance/hyperbolicRadius);
				double newphi = angles[toWiggle[j]] + angleMovement;
				if (newphi < 0) newphi += (floor(-newphi/(2*M_PI))+1)*2*M_PI;
				if (newphi > 2*M_PI) newphi -= floor(newphi/(2*M_PI))*2*M_PI;

				//bounce off the boundary
				newradius = HyperbolicSpace::hyperbolicRadiusToEuclidean(newradius);
				if (newradius >= r) newradius = std::nextafter(newradius, std::numeric_limits<double>::lowest());

				//updating Quadtree
				bool removed = quad.removeContent(toWiggle[j], angles[toWiggle[j]], radii[toWiggle[j]]);
				assert(removed);
				angles[toWiggle[j]] = newphi;
				radii[toWiggle[j]] = newradius;
				quad.addContent(toWiggle[j], newphi, newradius);

			}

			//now get the new edges and see what changed
			#pragma omp parallel for
			for (index j = 0; j < toWiggle.size(); j++) {
				vector<index> newNeighbours = quad.getCloseElements(HyperbolicSpace::polarToCartesian(angles[toWiggle[j]], radii[toWiggle[j]]), R*currentfactor);
				std::sort(oldNeighbours[j].begin(), oldNeighbours[j].end());
				std::sort(newNeighbours.begin(), newNeighbours.end());
				vector<index> newEdges(newNeighbours.size());
				auto it = std::set_difference(newNeighbours.begin(), newNeighbours.end(), oldNeighbours[j].begin(), oldNeighbours[j].end(), newEdges.begin());
				newEdges.erase(it, newEdges.end());//trim empty space

				vector<index> brokenEdges(oldNeighbours[j].size() - (newNeighbours.size() - newEdges.size()));//this should be the number of broken edges
				it = std::set_difference(oldNeighbours[j].begin(), oldNeighbours[j].end(), newNeighbours.begin(), newNeighbours.end(), brokenEdges.begin());
				assert(it == brokenEdges.end());

				#pragma omp critical
				{
					for (index edge : newEdges) {
						result.emplace_back(GraphEvent::EDGE_ADDITION, toWiggle[j], edge);
					}
					for (index edge : brokenEdges) {
						result.emplace_back(GraphEvent::EDGE_REMOVAL, toWiggle[j], edge);
					}
				}
			}

			/**
			 * since we didn't know whether the other endpoint of an edge was wiggled or not, we may
			 * have added some of them twice.
			 * Remove the doubles:
			 */
			for (auto it = result.begin()+oldStreamMarker; it < result.end(); it++) {
				if (it->u > it->v) std::swap(it->u, it->v);
			}
			std::sort(result.begin()+oldStreamMarker, result.end(), GraphEvent::compare);
			auto end = std::unique(result.begin()+oldStreamMarker, result.end(), GraphEvent::equal);
			result.erase(end, result.end());
		}
		result.push_back(GraphEvent(GraphEvent::TIME_STEP));
	}
	return result;
}
} /* namespace NetworKit */
<|endoftext|>