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

  Program:   Insight Segmentation & Registration Toolkit
  Module:    ImageRegistration14.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

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

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

// Software Guide : BeginLatex
//
//  This example illustrates how to do registration with a 2D Rigid Transform
//  and with the Normalized Mutual Information metric.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
#include "itkImageRegistrationMethod.h"

#include "itkCenteredRigid2DTransform.h"
#include "itkCenteredTransformInitializer.h"

#include "itkNormalizedMutualInformationHistogramImageToImageMetric.h"
#include "itkLinearInterpolateImageFunction.h"
#include "itkOnePlusOneEvolutionaryOptimizer.h"
#include "itkNormalVariateGenerator.h"

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"

#include "itkResampleImageFilter.h"
#include "itkCastImageFilter.h"

//  The following section of code implements a Command observer
//  used to monitor the evolution of the registration process.
//
#include "itkCommand.h"
class CommandIterationUpdate : public itk::Command
{
public:
  typedef  CommandIterationUpdate   Self;
  typedef  itk::Command             Superclass;
  typedef itk::SmartPointer<Self>  Pointer;
  itkNewMacro( Self );
protected:
  CommandIterationUpdate() {};
public:
  typedef itk::OnePlusOneEvolutionaryOptimizer     OptimizerType;
  typedef   const OptimizerType   *    OptimizerPointer;

  void Execute(itk::Object *caller, const itk::EventObject & event)
    {
      Execute( (const itk::Object *)caller, event);
    }

  void Execute(const itk::Object * object, const itk::EventObject & event)
    {
      OptimizerPointer optimizer =
        dynamic_cast< OptimizerPointer >( object );
      if( typeid( event ) != typeid( itk::IterationEvent ) )
        {
        return;
        }
      double currentValue = optimizer->GetValue();
      // Only print out when the Metric value changes
      if( fabs( m_LastMetricValue - currentValue ) > 1e-7 )
        {
        std::cout << optimizer->GetCurrentIteration() << "   ";
        std::cout << currentValue << "   ";
        std::cout << optimizer->GetCurrentPosition() << std::endl;
        m_LastMetricValue = currentValue;
        }
    }
private:
  double m_LastMetricValue;
};

int main( int argc, char *argv[] )
{
  if( argc < 3 )
    {
    std::cerr << "Missing Parameters " << std::endl;
    std::cerr << "Usage: " << argv[0];
    std::cerr << " fixedImageFile  movingImageFile ";
    std::cerr << "outputImagefile [differenceImage]" << std::endl;
    return 1;
    }

  const    unsigned int    Dimension = 2;
  typedef  unsigned char   PixelType;

  typedef itk::Image< PixelType, Dimension >  FixedImageType;
  typedef itk::Image< PixelType, Dimension >  MovingImageType;

  typedef itk::CenteredRigid2DTransform< double > TransformType;

  typedef itk::OnePlusOneEvolutionaryOptimizer       OptimizerType;
  typedef itk::LinearInterpolateImageFunction<
                                    MovingImageType,
                                    double             > InterpolatorType;
  typedef itk::ImageRegistrationMethod<
                                    FixedImageType,
                                    MovingImageType    > RegistrationType;

  typedef itk::NormalizedMutualInformationHistogramImageToImageMetric<
                                          FixedImageType,
                                          MovingImageType >    MetricType;

  TransformType::Pointer      transform     = TransformType::New();
  OptimizerType::Pointer      optimizer     = OptimizerType::New();
  InterpolatorType::Pointer   interpolator  = InterpolatorType::New();
  RegistrationType::Pointer   registration  = RegistrationType::New();

  registration->SetOptimizer(     optimizer     );
  registration->SetTransform(     transform     );
  registration->SetInterpolator(  interpolator  );

  MetricType::Pointer metric = MetricType::New();
  registration->SetMetric( metric  );

  unsigned int numberOfBins = 32;
  MetricType::HistogramType::SizeType histogramSize;
  histogramSize[0] = numberOfBins;
  histogramSize[1] = numberOfBins;
  metric->SetHistogramSize( histogramSize );

  const unsigned int numberOfParameters = transform->GetNumberOfParameters();

  typedef MetricType::ScalesType ScalesType;
  ScalesType scales( numberOfParameters );

  scales.Fill( 1.0 );

  metric->SetDerivativeStepLengthScales(scales);

  typedef itk::ImageFileReader< FixedImageType  > FixedImageReaderType;
  typedef itk::ImageFileReader< MovingImageType > MovingImageReaderType;

  FixedImageReaderType::Pointer  fixedImageReader  = FixedImageReaderType::New();
  MovingImageReaderType::Pointer movingImageReader = MovingImageReaderType::New();

  fixedImageReader->SetFileName(  argv[1] );
  movingImageReader->SetFileName( argv[2] );

  registration->SetFixedImage(    fixedImageReader->GetOutput()    );
  registration->SetMovingImage(   movingImageReader->GetOutput()   );

  fixedImageReader->Update();

  registration->SetFixedImageRegion(
       fixedImageReader->GetOutput()->GetBufferedRegion() );

  typedef itk::CenteredTransformInitializer<
                                    TransformType,
                                    FixedImageType,
                                    MovingImageType >  TransformInitializerType;
  TransformInitializerType::Pointer initializer = TransformInitializerType::New();

  initializer->SetTransform(   transform );
  initializer->SetFixedImage(  fixedImageReader->GetOutput() );
  initializer->SetMovingImage( movingImageReader->GetOutput() );
  initializer->GeometryOn();
  initializer->InitializeTransform();

  transform->SetAngle( 0.0 );

  registration->SetInitialTransformParameters( transform->GetParameters() );

  std::cout << "Initial transform parameters = ";
  std::cout << transform->GetParameters() << std::endl;

  typedef OptimizerType::ScalesType       OptimizerScalesType;
  OptimizerScalesType optimizerScales( transform->GetNumberOfParameters() );

  const double translationScale = 1.0 / 100.0;
  const double centerScale = 1000.0;  // prevent the center from changing

  optimizerScales[0] = 1.0;
  optimizerScales[1] = translationScale;
  optimizerScales[2] = translationScale;
  optimizerScales[3] = translationScale;
  optimizerScales[4] = translationScale;
  optimizer->SetScales( optimizerScales );

  typedef itk::Statistics::NormalVariateGenerator  GeneratorType;

  GeneratorType::Pointer generator = GeneratorType::New();
  generator->Initialize(12345);

  optimizer->MaximizeOn();

  optimizer->SetNormalVariateGenerator( generator );

  const double initialRadius = 0.01;

  optimizer->Initialize( initialRadius );
  optimizer->SetEpsilon( 0.001 );
  optimizer->SetMaximumIteration( 4000 );

  // Create the Command observer and register it with the optimizer.
  //
  CommandIterationUpdate::Pointer observer = CommandIterationUpdate::New();
  optimizer->AddObserver( itk::IterationEvent(), observer );

  try
    {
    registration->StartRegistration();
    }
  catch( itk::ExceptionObject & err )
    {
    std::cout << "ExceptionObject caught !" << std::endl;
    std::cout << err << std::endl;
    return -1;
    }

  typedef RegistrationType::ParametersType ParametersType;

  ParametersType finalParameters = registration->GetLastTransformParameters();

  const double finalAngle           = finalParameters[0];
  const double finalRotationCenterX = finalParameters[1];
  const double finalRotationCenterY = finalParameters[2];
  const double finalTranslationX    = finalParameters[3];
  const double finalTranslationY    = finalParameters[4];

  unsigned int numberOfIterations = optimizer->GetCurrentIteration();

  double bestValue = optimizer->GetValue();

  // Print out results
  //

  const double finalAngleInDegrees = finalAngle * 45.0 / atan(1.0);

  std::cout << "Result = " << std::endl;
  std::cout << " Angle (radians) " << finalAngle  << std::endl;
  std::cout << " Angle (degrees) " << finalAngleInDegrees  << std::endl;
  std::cout << " Center X      = " << finalRotationCenterX  << std::endl;
  std::cout << " Center Y      = " << finalRotationCenterY  << std::endl;
  std::cout << " Translation X = " << finalTranslationX  << std::endl;
  std::cout << " Translation Y = " << finalTranslationY  << std::endl;
  std::cout << " Iterations    = " << numberOfIterations << std::endl;
  std::cout << " Metric value  = " << bestValue          << std::endl;

  typedef itk::ResampleImageFilter<
                            MovingImageType,
                            FixedImageType >    ResampleFilterType;

  TransformType::Pointer finalTransform = TransformType::New();

  finalTransform->SetParameters( finalParameters );

  ResampleFilterType::Pointer resample = ResampleFilterType::New();

  resample->SetTransform( finalTransform );
  resample->SetInput( movingImageReader->GetOutput() );

  FixedImageType::Pointer fixedImage = fixedImageReader->GetOutput();

  resample->SetSize(    fixedImage->GetLargestPossibleRegion().GetSize() );
  resample->SetOutputOrigin(  fixedImage->GetOrigin() );
  resample->SetOutputSpacing( fixedImage->GetSpacing() );
  resample->SetDefaultPixelValue( 100 );

  typedef itk::Image< PixelType, Dimension > OutputImageType;

  typedef itk::ImageFileWriter< OutputImageType >  WriterType;

  WriterType::Pointer      writer =  WriterType::New();

  writer->SetFileName( argv[3] );

  writer->SetInput( resample->GetOutput() );
  writer->Update();

// Software Guide : EndCodeSnippet

  return 0;
}

<commit_msg>ENH: Fine tunning parameters to accelerate convergence.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    ImageRegistration14.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

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

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

// Software Guide : BeginLatex
//
//  This example illustrates how to do registration with a 2D Rigid Transform
//  and with the Normalized Mutual Information metric.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
#include "itkImageRegistrationMethod.h"

#include "itkCenteredRigid2DTransform.h"
#include "itkCenteredTransformInitializer.h"

#include "itkNormalizedMutualInformationHistogramImageToImageMetric.h"
#include "itkLinearInterpolateImageFunction.h"
#include "itkOnePlusOneEvolutionaryOptimizer.h"
#include "itkNormalVariateGenerator.h"

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"

#include "itkResampleImageFilter.h"
#include "itkCastImageFilter.h"

//  The following section of code implements a Command observer
//  used to monitor the evolution of the registration process.
//
#include "itkCommand.h"
class CommandIterationUpdate : public itk::Command
{
public:
  typedef  CommandIterationUpdate   Self;
  typedef  itk::Command             Superclass;
  typedef itk::SmartPointer<Self>  Pointer;
  itkNewMacro( Self );
protected:
  CommandIterationUpdate() {};
public:
  typedef itk::OnePlusOneEvolutionaryOptimizer     OptimizerType;
  typedef   const OptimizerType   *    OptimizerPointer;

  void Execute(itk::Object *caller, const itk::EventObject & event)
    {
      Execute( (const itk::Object *)caller, event);
    }

  void Execute(const itk::Object * object, const itk::EventObject & event)
    {
      OptimizerPointer optimizer =
        dynamic_cast< OptimizerPointer >( object );
      if( typeid( event ) != typeid( itk::IterationEvent ) )
        {
        return;
        }
      double currentValue = optimizer->GetValue();
      // Only print out when the Metric value changes
      if( fabs( m_LastMetricValue - currentValue ) > 1e-7 )
        {
        std::cout << optimizer->GetCurrentIteration() << "   ";
        std::cout << currentValue << "   ";
        std::cout << optimizer->GetCurrentPosition() << std::endl;
        m_LastMetricValue = currentValue;
        }
    }
private:
  double m_LastMetricValue;
};

int main( int argc, char *argv[] )
{
  if( argc < 3 )
    {
    std::cerr << "Missing Parameters " << std::endl;
    std::cerr << "Usage: " << argv[0];
    std::cerr << " fixedImageFile  movingImageFile ";
    std::cerr << "outputImagefile [differenceImage]" << std::endl;
    return 1;
    }

  const    unsigned int    Dimension = 2;
  typedef  unsigned char   PixelType;

  typedef itk::Image< PixelType, Dimension >  FixedImageType;
  typedef itk::Image< PixelType, Dimension >  MovingImageType;

  typedef itk::CenteredRigid2DTransform< double > TransformType;

  typedef itk::OnePlusOneEvolutionaryOptimizer       OptimizerType;
  typedef itk::LinearInterpolateImageFunction<
                                    MovingImageType,
                                    double             > InterpolatorType;
  typedef itk::ImageRegistrationMethod<
                                    FixedImageType,
                                    MovingImageType    > RegistrationType;

  typedef itk::NormalizedMutualInformationHistogramImageToImageMetric<
                                          FixedImageType,
                                          MovingImageType >    MetricType;

  TransformType::Pointer      transform     = TransformType::New();
  OptimizerType::Pointer      optimizer     = OptimizerType::New();
  InterpolatorType::Pointer   interpolator  = InterpolatorType::New();
  RegistrationType::Pointer   registration  = RegistrationType::New();

  registration->SetOptimizer(     optimizer     );
  registration->SetTransform(     transform     );
  registration->SetInterpolator(  interpolator  );

  MetricType::Pointer metric = MetricType::New();
  registration->SetMetric( metric  );

  unsigned int numberOfBins = 32;
  MetricType::HistogramType::SizeType histogramSize;
  histogramSize[0] = numberOfBins;
  histogramSize[1] = numberOfBins;
  metric->SetHistogramSize( histogramSize );

  const unsigned int numberOfParameters = transform->GetNumberOfParameters();

  typedef MetricType::ScalesType ScalesType;
  ScalesType scales( numberOfParameters );

  scales.Fill( 1.0 );

  metric->SetDerivativeStepLengthScales(scales);

  typedef itk::ImageFileReader< FixedImageType  > FixedImageReaderType;
  typedef itk::ImageFileReader< MovingImageType > MovingImageReaderType;

  FixedImageReaderType::Pointer  fixedImageReader  = FixedImageReaderType::New();
  MovingImageReaderType::Pointer movingImageReader = MovingImageReaderType::New();

  fixedImageReader->SetFileName(  argv[1] );
  movingImageReader->SetFileName( argv[2] );

  registration->SetFixedImage(    fixedImageReader->GetOutput()    );
  registration->SetMovingImage(   movingImageReader->GetOutput()   );

  fixedImageReader->Update();

  registration->SetFixedImageRegion(
       fixedImageReader->GetOutput()->GetBufferedRegion() );

  typedef itk::CenteredTransformInitializer<
                                    TransformType,
                                    FixedImageType,
                                    MovingImageType >  TransformInitializerType;
  TransformInitializerType::Pointer initializer = TransformInitializerType::New();

  initializer->SetTransform(   transform );
  initializer->SetFixedImage(  fixedImageReader->GetOutput() );
  initializer->SetMovingImage( movingImageReader->GetOutput() );
  initializer->GeometryOn();
  initializer->InitializeTransform();

  transform->SetAngle( 0.0 );

  registration->SetInitialTransformParameters( transform->GetParameters() );

  std::cout << "Initial transform parameters = ";
  std::cout << transform->GetParameters() << std::endl;

  typedef OptimizerType::ScalesType       OptimizerScalesType;
  OptimizerScalesType optimizerScales( transform->GetNumberOfParameters() );

  const double translationScale = 1.0 / 100.0;
  const double centerScale = 1000.0;  // prevent the center from changing

  optimizerScales[0] = 1.0;
  optimizerScales[1] = translationScale;
  optimizerScales[2] = translationScale;
  optimizerScales[3] = translationScale;
  optimizerScales[4] = translationScale;
  optimizer->SetScales( optimizerScales );

  typedef itk::Statistics::NormalVariateGenerator  GeneratorType;

  GeneratorType::Pointer generator = GeneratorType::New();
  generator->Initialize(12345);

  optimizer->MaximizeOn();

  optimizer->SetNormalVariateGenerator( generator );

  const double initialRadius = 0.05;

  optimizer->Initialize( initialRadius );
  optimizer->SetEpsilon( 0.001 );
  optimizer->SetMaximumIteration( 500 );

  // Create the Command observer and register it with the optimizer.
  //
  CommandIterationUpdate::Pointer observer = CommandIterationUpdate::New();
  optimizer->AddObserver( itk::IterationEvent(), observer );

  try
    {
    registration->StartRegistration();
    }
  catch( itk::ExceptionObject & err )
    {
    std::cout << "ExceptionObject caught !" << std::endl;
    std::cout << err << std::endl;
    return -1;
    }

  typedef RegistrationType::ParametersType ParametersType;

  ParametersType finalParameters = registration->GetLastTransformParameters();

  const double finalAngle           = finalParameters[0];
  const double finalRotationCenterX = finalParameters[1];
  const double finalRotationCenterY = finalParameters[2];
  const double finalTranslationX    = finalParameters[3];
  const double finalTranslationY    = finalParameters[4];

  unsigned int numberOfIterations = optimizer->GetCurrentIteration();

  double bestValue = optimizer->GetValue();

  // Print out results
  //

  const double finalAngleInDegrees = finalAngle * 45.0 / atan(1.0);

  std::cout << "Result = " << std::endl;
  std::cout << " Angle (radians) " << finalAngle  << std::endl;
  std::cout << " Angle (degrees) " << finalAngleInDegrees  << std::endl;
  std::cout << " Center X      = " << finalRotationCenterX  << std::endl;
  std::cout << " Center Y      = " << finalRotationCenterY  << std::endl;
  std::cout << " Translation X = " << finalTranslationX  << std::endl;
  std::cout << " Translation Y = " << finalTranslationY  << std::endl;
  std::cout << " Iterations    = " << numberOfIterations << std::endl;
  std::cout << " Metric value  = " << bestValue          << std::endl;

  typedef itk::ResampleImageFilter<
                            MovingImageType,
                            FixedImageType >    ResampleFilterType;

  TransformType::Pointer finalTransform = TransformType::New();

  finalTransform->SetParameters( finalParameters );

  ResampleFilterType::Pointer resample = ResampleFilterType::New();

  resample->SetTransform( finalTransform );
  resample->SetInput( movingImageReader->GetOutput() );

  FixedImageType::Pointer fixedImage = fixedImageReader->GetOutput();

  resample->SetSize(    fixedImage->GetLargestPossibleRegion().GetSize() );
  resample->SetOutputOrigin(  fixedImage->GetOrigin() );
  resample->SetOutputSpacing( fixedImage->GetSpacing() );
  resample->SetDefaultPixelValue( 100 );

  typedef itk::Image< PixelType, Dimension > OutputImageType;

  typedef itk::ImageFileWriter< OutputImageType >  WriterType;

  WriterType::Pointer      writer =  WriterType::New();

  writer->SetFileName( argv[3] );

  writer->SetInput( resample->GetOutput() );
  writer->Update();

// Software Guide : EndCodeSnippet

  return 0;
}

<|endoftext|>


<commit_before>/*
Copyright 2016 Colin Girling

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

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.
*/

#ifndef OCL_GUARD_TEST_TESTSTRINGUTILITY_HPP
#define OCL_GUARD_TEST_TESTSTRINGUTILITY_HPP

#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include "TestMemoryUtility.hpp"
#include "TestConverterUtility.hpp"

namespace ocl
{

/*
    String utility class providing features such as:
        allocation, de-allocation, filling, copying, appending

    Functions that don't do pointer checking start with Unsafe in the name.
*/

struct TestStringUtility
{
    // NOTE: size_type is not used as it causes
    // possible loss of data warnings for some compilers.
    typedef unsigned int size_type;

    template<typename IntType>
    static char const* GetMinSignedIntAsString(IntType size_of_int) throw()
    {
        switch (size_of_int)
        {
            case 1: return "-128";
            case 2: return "-32768";
            case 4: return "-2147483648";
            case 8: return "-9223372036854775808";
        }

        return "";
    }

    template<typename IntType>
    static char const* GetMaxSignedIntAsString(IntType size_of_int) throw()
    {
        switch (size_of_int)
        {
            case 1: return "127";
            case 2: return "32767";
            case 4: return "2147483647";
            case 8: return "9223372036854775807";
        }

        return "";
    }

    template<typename IntType>
    static char const* GetMaxUnsignedIntAsString(IntType size_of_int) throw()
    {
        switch (size_of_int)
        {
            case 1: return "255";
            case 2: return "65535";
            case 4: return "4294967295";
            case 8: return "18446744073709551615";
        }

        return "";
    }

    template<typename IntType>
    static size_type GetMinSignedIntCharCount(IntType size_of_int) throw()
    {
        switch (size_of_int)
        {
            case 1: return 4U;
            case 2: return 6U;
            case 4: return 11U;
            case 8: return 20U;
        }

        return 0U;
    }

    template<typename IntType>
    static size_type GetMaxSignedIntCharCount(IntType size_of_int) throw()
    {
        switch (size_of_int)
        {
            case 1: return 3U;
            case 2: return 5U;
            case 4: return 10U;
            case 8: return 19U;
        }

        return 0U;
    }

    template<typename IntType>
    static size_type GetMaxUnsignedIntCharCount(IntType size_of_int) throw()
    {
        switch (size_of_int)
        {
            case 1: return 3U;
            case 2: return 5U;
            case 4: return 10U;
            case 8: return 20U;
        }

        return 0U;
    }

    template<typename T>
    static char* GetString(T value)
    {
        size_type len = 0U;
        return TestConverterUtility<T>::GetString(value, len);
    }

    template<typename Type, typename SizeType>
    static char* GetString(Type value, SizeType& length)
    {
        return TestConverterUtility<Type, SizeType>::GetString(value, length);
    }

    static void UnsafeFill(char* str, char ch, size_type len)
    {
        char* end = str + len;
        for (; str < end; ++str)
            *str = ch;
        *str = '\0';
    }

    static size_type SafeLength(char const* str)
    {
        size_type len = str != NULL ? static_cast<size_type>(::strlen(str)) : 0U;
        return len;
    }

    static bool UnsafeFind(char const* str, char ch, size_type& pos, size_type start = 0)
    {
        char const* pch = str + start;
        for (; (*pch != '\0') && (*pch != ch); ++pch)
            ;
        if ((ch != '\0') && (*pch == '\0'))
            return false;
        pos = static_cast<size_type>(pch - str);
        return true;
    }

    static void Allocate(char*& dest, size_type dest_len)
    {
        dest = TestMemoryUtility<char>::Allocate(dest_len + 1);
    }

    static void FastFree(char* str)
    {
        TestMemoryUtility<char>::FastFree(str);
    }

    static void SafeFree(char*& str)
    {
        TestMemoryUtility<char>::SafeFree(str);
    }

    static void SafeAllocateCopy(char*& dest,
                                 size_type& dest_len,
                                 char const* src,
                                 size_type src_len)
    {
        if ((src != NULL) && (src_len > 0))
        {
            dest = TestMemoryUtility<char>::UnsafeAllocateCopy(src, src_len + 1);
            if (dest != NULL)
            {
                dest_len = src_len;

                // If src is longer than src_len, add the terminating '\0'.
                if (*(src + src_len) != '\0')
                    *(dest + dest_len) = '\0';
            }
            else
                dest_len = static_cast<size_type>(0);
        }
        else
        {
            dest = NULL;
            dest_len = 0;
        }
    }

    static void SafeAllocateCopy(char*& dest, size_type& dest_len, char const* src)
    {
        if (src == NULL)
        {
            dest = NULL;
            dest_len = 0;
        }
        else
            UnsafeAllocateCopy(dest, dest_len, src);
    }

    static void UnsafeAllocateCopy(char*& dest, size_type& dest_len, char const* src)
    {
        size_type src_len = static_cast<size_type>(::strlen(src));
        dest = TestMemoryUtility<char>::UnsafeAllocateCopy(src, src_len + 1);
        dest_len = (dest != NULL) ? src_len : static_cast<size_type>(0);
    }

    static void SafeReallocCopy(char*& dest,
                                size_type& dest_len,
                                char const* src,
                                size_type src_len)
    {
        FastFree(dest);
        SafeAllocateCopy(dest, dest_len, src, src_len);
    }

    static void SafeReallocCopy(char*& dest, size_type& dest_len, char const* src)
    {
        FastFree(dest);
        SafeAllocateCopy(dest, dest_len, src);
    }

    /// Allocate enough space in dest to copy str1 and append str2.
    /// @note It is safe for dest and str1 or str2 to be the same string.
    /// Also str1 or str2 can be NULL.
    static void SafeAllocAppend(char*& dest,
                                size_type& dest_len,
                                char const* str1,
                                size_type str1_len,
                                char const* str2,
                                size_type str2_len)
    {
        size_type new_len = str1_len + str2_len;
        if (new_len > 0)
        {
            char* new_dest = NULL;
            Allocate(new_dest, new_len);
            if (new_dest != NULL)
            {
                if ((str1 != NULL) && (str1_len > 0))
                    ::memcpy(new_dest, str1, str1_len);
                else
                {
                    new_len -= str1_len;
                    str1_len = 0;
                }
                if ((str2 != NULL) && (str2_len > 0))
                    ::memcpy(new_dest + str1_len, str2, str2_len);
                else
                    new_len -= str2_len;
                *(new_dest + new_len) = '\0';
                dest_len = new_len;
            }
            else
                dest_len = 0;
            FastFree(dest);
            dest = new_dest;
        }
        else
        {
            dest = NULL;
            dest_len = 0;
        }
    }

    /// Same as AllocAppend, except dest is first freed
    /// before being set with str1 and str2.
    static void SafeReallocAppend(char*& dest,
                                  size_type& dest_len,
                                  char const* str1,
                                  size_type str1_len,
                                  char const* str2,
                                  size_type str2_len)
    {
        char* new_dest = NULL;
        size_type new_dest_len = 0;
        SafeAllocAppend(new_dest, new_dest_len, str1, str1_len, str2, str2_len);
        FastFree(dest);
        dest = new_dest;
        dest_len = new_dest_len;
    }
};

} // namespace ocl

#endif // OCL_GUARD_TEST_TESTSTRINGUTILITY_HPP
<commit_msg>Fixed possible memory leak in TestStringUtility class when appending an empty string.<commit_after>/*
Copyright 2016 Colin Girling

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

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.
*/

#ifndef OCL_GUARD_TEST_TESTSTRINGUTILITY_HPP
#define OCL_GUARD_TEST_TESTSTRINGUTILITY_HPP

#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include "TestMemoryUtility.hpp"
#include "TestConverterUtility.hpp"

namespace ocl
{

/*
    String utility class providing features such as:
        allocation, de-allocation, filling, copying, appending

    Functions that don't do pointer checking start with Unsafe in the name.
*/

struct TestStringUtility
{
    // NOTE: size_type is not used as it causes
    // possible loss of data warnings for some compilers.
    typedef unsigned int size_type;

    template<typename IntType>
    static char const* GetMinSignedIntAsString(IntType size_of_int) throw()
    {
        switch (size_of_int)
        {
            case 1: return "-128";
            case 2: return "-32768";
            case 4: return "-2147483648";
            case 8: return "-9223372036854775808";
        }

        return "";
    }

    template<typename IntType>
    static char const* GetMaxSignedIntAsString(IntType size_of_int) throw()
    {
        switch (size_of_int)
        {
            case 1: return "127";
            case 2: return "32767";
            case 4: return "2147483647";
            case 8: return "9223372036854775807";
        }

        return "";
    }

    template<typename IntType>
    static char const* GetMaxUnsignedIntAsString(IntType size_of_int) throw()
    {
        switch (size_of_int)
        {
            case 1: return "255";
            case 2: return "65535";
            case 4: return "4294967295";
            case 8: return "18446744073709551615";
        }

        return "";
    }

    template<typename IntType>
    static size_type GetMinSignedIntCharCount(IntType size_of_int) throw()
    {
        switch (size_of_int)
        {
            case 1: return 4U;
            case 2: return 6U;
            case 4: return 11U;
            case 8: return 20U;
        }

        return 0U;
    }

    template<typename IntType>
    static size_type GetMaxSignedIntCharCount(IntType size_of_int) throw()
    {
        switch (size_of_int)
        {
            case 1: return 3U;
            case 2: return 5U;
            case 4: return 10U;
            case 8: return 19U;
        }

        return 0U;
    }

    template<typename IntType>
    static size_type GetMaxUnsignedIntCharCount(IntType size_of_int) throw()
    {
        switch (size_of_int)
        {
            case 1: return 3U;
            case 2: return 5U;
            case 4: return 10U;
            case 8: return 20U;
        }

        return 0U;
    }

    template<typename T>
    static char* GetString(T value)
    {
        size_type len = 0U;
        return TestConverterUtility<T>::GetString(value, len);
    }

    template<typename Type, typename SizeType>
    static char* GetString(Type value, SizeType& length)
    {
        return TestConverterUtility<Type, SizeType>::GetString(value, length);
    }

    static void UnsafeFill(char* str, char ch, size_type len)
    {
        char* end = str + len;
        for (; str < end; ++str)
            *str = ch;
        *str = '\0';
    }

    static size_type SafeLength(char const* str)
    {
        size_type len = str != NULL ? static_cast<size_type>(::strlen(str)) : 0U;
        return len;
    }

    static bool UnsafeFind(char const* str, char ch, size_type& pos, size_type start = 0)
    {
        char const* pch = str + start;
        for (; (*pch != '\0') && (*pch != ch); ++pch)
            ;
        if ((ch != '\0') && (*pch == '\0'))
            return false;
        pos = static_cast<size_type>(pch - str);
        return true;
    }

    static void Allocate(char*& dest, size_type dest_len)
    {
        dest = TestMemoryUtility<char>::Allocate(dest_len + 1);
    }

    static void FastFree(char* str)
    {
        TestMemoryUtility<char>::FastFree(str);
    }

    static void SafeFree(char*& str)
    {
        TestMemoryUtility<char>::SafeFree(str);
    }

    static void SafeAllocateCopy(char*& dest,
                                 size_type& dest_len,
                                 char const* src,
                                 size_type src_len)
    {
        if ((src != NULL) && (src_len > 0))
        {
            dest = TestMemoryUtility<char>::UnsafeAllocateCopy(src, src_len + 1);
            if (dest != NULL)
            {
                dest_len = src_len;

                // If src is longer than src_len, add the terminating '\0'.
                if (*(src + src_len) != '\0')
                    *(dest + dest_len) = '\0';
            }
            else
                dest_len = static_cast<size_type>(0);
        }
        else
        {
            dest = NULL;
            dest_len = 0;
        }
    }

    static void SafeAllocateCopy(char*& dest, size_type& dest_len, char const* src)
    {
        if (src == NULL)
        {
            dest = NULL;
            dest_len = 0;
        }
        else
            UnsafeAllocateCopy(dest, dest_len, src);
    }

    static void UnsafeAllocateCopy(char*& dest, size_type& dest_len, char const* src)
    {
        size_type src_len = static_cast<size_type>(::strlen(src));
        dest = TestMemoryUtility<char>::UnsafeAllocateCopy(src, src_len + 1);
        dest_len = (dest != NULL) ? src_len : static_cast<size_type>(0);
    }

    static void SafeReallocCopy(char*& dest,
                                size_type& dest_len,
                                char const* src,
                                size_type src_len)
    {
        FastFree(dest);
        SafeAllocateCopy(dest, dest_len, src, src_len);
    }

    static void SafeReallocCopy(char*& dest, size_type& dest_len, char const* src)
    {
        FastFree(dest);
        SafeAllocateCopy(dest, dest_len, src);
    }

    /// Allocate enough space in dest to copy str1 and append str2.
    /// @note It is safe for dest and str1 or str2 to be the same string.
    /// Also str1 or str2 can be NULL.
    static void SafeAllocAppend(char*& dest,
                                size_type& dest_len,
                                char const* str1,
                                size_type str1_len,
                                char const* str2,
                                size_type str2_len)
    {
        size_type new_len = str1_len + str2_len;
        if (new_len > 0)
        {
            char* new_dest = NULL;
            Allocate(new_dest, new_len);
            if (new_dest != NULL)
            {
                if ((str1 != NULL) && (str1_len > 0))
                    ::memcpy(new_dest, str1, str1_len);
                else
                {
                    new_len -= str1_len;
                    str1_len = 0;
                }
                if ((str2 != NULL) && (str2_len > 0))
                    ::memcpy(new_dest + str1_len, str2, str2_len);
                else
                    new_len -= str2_len;
                *(new_dest + new_len) = '\0';
                dest_len = new_len;
            }
            else
                dest_len = 0;
            FastFree(dest);
            dest = new_dest;
        }
        else
        {
            SafeFree(dest);
            dest_len = 0;
        }
    }

    /// Same as AllocAppend, except dest is first freed
    /// before being set with str1 and str2.
    static void SafeReallocAppend(char*& dest,
                                  size_type& dest_len,
                                  char const* str1,
                                  size_type str1_len,
                                  char const* str2,
                                  size_type str2_len)
    {
        char* new_dest = NULL;
        size_type new_dest_len = 0;
        SafeAllocAppend(new_dest, new_dest_len, str1, str1_len, str2, str2_len);
        FastFree(dest);
        dest = new_dest;
        dest_len = new_dest_len;
    }
};

} // namespace ocl

#endif // OCL_GUARD_TEST_TESTSTRINGUTILITY_HPP
<|endoftext|>


<commit_before>typedef double scalar;

struct test {
  scalar a;
  union {
    ;
    int c;
  };
scalar b;
  union {
    ;
    int e;
    double f;
  };
scalar d;
  struct XX {
    scalar a;
  };
  struct YY {
    scalar b;
    int c;
  };
  struct ZZ {
    scalar d;
    int e;
    double f;
  };
};<commit_msg>Fixed test file code.<commit_after>typedef double scalar;

struct test {
  union {
    scalar a;
  };
  union {
    scalar b;
    int c;
  };
  union {
    scalar d;
    int e;
    double f;
  };
  union XX {
    scalar a;
  };
  union YY {
    scalar b;
    int c;
  };
  union ZZ {
    scalar d;
    int e;
    double f;
  };
};<|endoftext|>


<commit_before>// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "vulkan_surface_producer.h"

#include <lib/async/cpp/task.h>
#include <lib/async/default.h>

#include <memory>
#include <string>
#include <vector>

#include "flutter/fml/trace_event.h"
#include "third_party/skia/include/gpu/GrBackendSemaphore.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "third_party/skia/include/gpu/GrContext.h"
#include "third_party/skia/include/gpu/vk/GrVkBackendContext.h"
#include "third_party/skia/include/gpu/vk/GrVkTypes.h"

namespace flutter_runner {

namespace {

constexpr int kGrCacheMaxCount = 8192;
// Tuning advice:
// If you see the following 3 things happening simultaneously in a trace:
//   * Over budget ("flutter", "GPURasterizer::Draw") durations
//   * Many ("skia", "GrGpu::createTexture") events within the
//     "GPURasterizer::Draw"s
//   * The Skia GPU resource cache is full, as indicated by the
//     "SkiaCacheBytes" field in the ("flutter", "SurfacePool") trace counter
//     (compare it to the bytes value here)
// then you should consider increasing the size of the GPU resource cache.
constexpr size_t kGrCacheMaxByteSize = 16 * (1 << 20);

}  // namespace

VulkanSurfaceProducer::VulkanSurfaceProducer(scenic::Session* scenic_session) {
  valid_ = Initialize(scenic_session);

  if (valid_) {
    FML_DLOG(INFO)
        << "Flutter engine: Vulkan surface producer initialization: Successful";
  } else {
    FML_LOG(ERROR)
        << "Flutter engine: Vulkan surface producer initialization: Failed";
  }
}

VulkanSurfaceProducer::~VulkanSurfaceProducer() {
  // Make sure queue is idle before we start destroying surfaces
  if (valid_) {
    VkResult wait_result = VK_CALL_LOG_ERROR(
        vk_->QueueWaitIdle(logical_device_->GetQueueHandle()));
    FML_DCHECK(wait_result == VK_SUCCESS);
  }
};

bool VulkanSurfaceProducer::Initialize(scenic::Session* scenic_session) {
  vk_ = fml::MakeRefCounted<vulkan::VulkanProcTable>();

  std::vector<std::string> extensions = {
      VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME,
  };
  application_ = std::make_unique<vulkan::VulkanApplication>(
      *vk_, "FlutterRunner", std::move(extensions), VK_MAKE_VERSION(1, 0, 0),
      VK_MAKE_VERSION(1, 1, 0));

  if (!application_->IsValid() || !vk_->AreInstanceProcsSetup()) {
    // Make certain the application instance was created and it setup the
    // instance proc table entries.
    FML_LOG(ERROR) << "Instance proc addresses have not been setup.";
    return false;
  }

  // Create the device.

  logical_device_ = application_->AcquireFirstCompatibleLogicalDevice();

  if (logical_device_ == nullptr || !logical_device_->IsValid() ||
      !vk_->AreDeviceProcsSetup()) {
    // Make certain the device was created and it setup the device proc table
    // entries.
    FML_LOG(ERROR) << "Device proc addresses have not been setup.";
    return false;
  }

  if (!vk_->HasAcquiredMandatoryProcAddresses()) {
    FML_LOG(ERROR) << "Failed to acquire mandatory proc addresses.";
    return false;
  }

  if (!vk_->IsValid()) {
    FML_LOG(ERROR) << "VulkanProcTable invalid";
    return false;
  }

  auto getProc = vk_->CreateSkiaGetProc();

  if (getProc == nullptr) {
    FML_LOG(ERROR) << "Failed to create skia getProc.";
    return false;
  }

  uint32_t skia_features = 0;
  if (!logical_device_->GetPhysicalDeviceFeaturesSkia(&skia_features)) {
    FML_LOG(ERROR) << "Failed to get physical device features.";

    return false;
  }

  GrVkBackendContext backend_context;
  backend_context.fInstance = application_->GetInstance();
  backend_context.fPhysicalDevice = logical_device_->GetPhysicalDeviceHandle();
  backend_context.fDevice = logical_device_->GetHandle();
  backend_context.fQueue = logical_device_->GetQueueHandle();
  backend_context.fGraphicsQueueIndex =
      logical_device_->GetGraphicsQueueIndex();
  backend_context.fMinAPIVersion = application_->GetAPIVersion();
  backend_context.fFeatures = skia_features;
  backend_context.fGetProc = std::move(getProc);
  backend_context.fOwnsInstanceAndDevice = false;

  context_ = GrContext::MakeVulkan(backend_context);

  // Use local limits specified in this file above instead of flutter defaults.
  context_->setResourceCacheLimits(kGrCacheMaxCount, kGrCacheMaxByteSize);

  surface_pool_ =
      std::make_unique<VulkanSurfacePool>(*this, context_, scenic_session);

  return true;
}

void VulkanSurfaceProducer::OnSurfacesPresented(
    std::vector<
        std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>>
        surfaces) {
  TRACE_EVENT0("flutter", "VulkanSurfaceProducer::OnSurfacesPresented");

  // Do a single flush for all canvases derived from the context.
  {
    TRACE_EVENT0("flutter", "GrContext::flushAndSignalSemaphores");
    context_->flush();
  }

  if (!TransitionSurfacesToExternal(surfaces))
    FML_LOG(ERROR) << "TransitionSurfacesToExternal failed";

  // Submit surface
  for (auto& surface : surfaces) {
    SubmitSurface(std::move(surface));
  }

  // Buffer management.
  surface_pool_->AgeAndCollectOldBuffers();

  // If no further surface production has taken place for 10 frames (TODO:
  // Don't hardcode refresh rate here), then shrink our surface pool to fit.
  constexpr auto kShouldShrinkThreshold = zx::msec(10 * 16.67);
  async::PostDelayedTask(
      async_get_default_dispatcher(),
      [self = weak_factory_.GetWeakPtr(), kShouldShrinkThreshold] {
        if (!self) {
          return;
        }
        auto time_since_last_produce =
            async::Now(async_get_default_dispatcher()) -
            self->last_produce_time_;
        if (time_since_last_produce >= kShouldShrinkThreshold) {
          self->surface_pool_->ShrinkToFit();
        }
      },
      kShouldShrinkThreshold);
}

bool VulkanSurfaceProducer::TransitionSurfacesToExternal(
    const std::vector<
        std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>>&
        surfaces) {
  for (auto& surface : surfaces) {
    auto vk_surface = static_cast<VulkanSurface*>(surface.get());

    vulkan::VulkanCommandBuffer* command_buffer =
        vk_surface->GetCommandBuffer(logical_device_->GetCommandPool());
    if (!command_buffer->Begin())
      return false;

    GrBackendRenderTarget backendRT =
        vk_surface->GetSkiaSurface()->getBackendRenderTarget(
            SkSurface::kFlushRead_BackendHandleAccess);
    if (!backendRT.isValid()) {
      return false;
    }
    GrVkImageInfo imageInfo;
    if (!backendRT.getVkImageInfo(&imageInfo)) {
      return false;
    }

    VkImageMemoryBarrier image_barrier = {
        .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
        .pNext = nullptr,
        .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
        .dstAccessMask = 0,
        .oldLayout = imageInfo.fImageLayout,
        .newLayout = VK_IMAGE_LAYOUT_GENERAL,
        .srcQueueFamilyIndex = 0,
        .dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL_KHR,
        .image = vk_surface->GetVkImage(),
        .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}};

    if (!command_buffer->InsertPipelineBarrier(
            VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
            VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
            0,           // dependencyFlags
            0, nullptr,  // memory barriers
            0, nullptr,  // buffer barriers
            1, &image_barrier))
      return false;

    backendRT.setVkImageLayout(image_barrier.newLayout);

    if (!command_buffer->End())
      return false;

    if (!logical_device_->QueueSubmit(
            {}, {}, {vk_surface->GetAcquireVkSemaphore()},
            {command_buffer->Handle()}, vk_surface->GetCommandBufferFence()))
      return false;
  }
  return true;
}

std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>
VulkanSurfaceProducer::ProduceSurface(
    const SkISize& size,
    const flutter::LayerRasterCacheKey& layer_key,
    std::unique_ptr<scenic::EntityNode> entity_node) {
  FML_DCHECK(valid_);
  last_produce_time_ = async::Now(async_get_default_dispatcher());
  auto surface = surface_pool_->AcquireSurface(size);
  surface->SetRetainedInfo(layer_key, std::move(entity_node));
  return surface;
}

void VulkanSurfaceProducer::SubmitSurface(
    std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>
        surface) {
  FML_DCHECK(valid_ && surface != nullptr);
  surface_pool_->SubmitSurface(std::move(surface));
}

}  // namespace flutter_runner
<commit_msg>[fuchsia] Adjust Skia GPU resource cache size (#17798)<commit_after>// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "vulkan_surface_producer.h"

#include <lib/async/cpp/task.h>
#include <lib/async/default.h>

#include <memory>
#include <string>
#include <vector>

#include "flutter/fml/trace_event.h"
#include "third_party/skia/include/gpu/GrBackendSemaphore.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "third_party/skia/include/gpu/GrContext.h"
#include "third_party/skia/include/gpu/vk/GrVkBackendContext.h"
#include "third_party/skia/include/gpu/vk/GrVkTypes.h"

namespace flutter_runner {

namespace {

constexpr int kGrCacheMaxCount = 8192;
// Tuning advice:
// If you see the following 3 things happening simultaneously in a trace:
//   * Over budget ("flutter", "GPURasterizer::Draw") durations
//   * Many ("skia", "GrGpu::createTexture") events within the
//     "GPURasterizer::Draw"s
//   * The Skia GPU resource cache is full, as indicated by the
//     "SkiaCacheBytes" field in the ("flutter", "SurfacePool") trace counter
//     (compare it to the bytes value here)
// then you should consider increasing the size of the GPU resource cache.
constexpr size_t kGrCacheMaxByteSize = 1024 * 600 * 12 * 4;

}  // namespace

VulkanSurfaceProducer::VulkanSurfaceProducer(scenic::Session* scenic_session) {
  valid_ = Initialize(scenic_session);

  if (valid_) {
    FML_DLOG(INFO)
        << "Flutter engine: Vulkan surface producer initialization: Successful";
  } else {
    FML_LOG(ERROR)
        << "Flutter engine: Vulkan surface producer initialization: Failed";
  }
}

VulkanSurfaceProducer::~VulkanSurfaceProducer() {
  // Make sure queue is idle before we start destroying surfaces
  if (valid_) {
    VkResult wait_result = VK_CALL_LOG_ERROR(
        vk_->QueueWaitIdle(logical_device_->GetQueueHandle()));
    FML_DCHECK(wait_result == VK_SUCCESS);
  }
};

bool VulkanSurfaceProducer::Initialize(scenic::Session* scenic_session) {
  vk_ = fml::MakeRefCounted<vulkan::VulkanProcTable>();

  std::vector<std::string> extensions = {
      VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME,
  };
  application_ = std::make_unique<vulkan::VulkanApplication>(
      *vk_, "FlutterRunner", std::move(extensions), VK_MAKE_VERSION(1, 0, 0),
      VK_MAKE_VERSION(1, 1, 0));

  if (!application_->IsValid() || !vk_->AreInstanceProcsSetup()) {
    // Make certain the application instance was created and it setup the
    // instance proc table entries.
    FML_LOG(ERROR) << "Instance proc addresses have not been setup.";
    return false;
  }

  // Create the device.

  logical_device_ = application_->AcquireFirstCompatibleLogicalDevice();

  if (logical_device_ == nullptr || !logical_device_->IsValid() ||
      !vk_->AreDeviceProcsSetup()) {
    // Make certain the device was created and it setup the device proc table
    // entries.
    FML_LOG(ERROR) << "Device proc addresses have not been setup.";
    return false;
  }

  if (!vk_->HasAcquiredMandatoryProcAddresses()) {
    FML_LOG(ERROR) << "Failed to acquire mandatory proc addresses.";
    return false;
  }

  if (!vk_->IsValid()) {
    FML_LOG(ERROR) << "VulkanProcTable invalid";
    return false;
  }

  auto getProc = vk_->CreateSkiaGetProc();

  if (getProc == nullptr) {
    FML_LOG(ERROR) << "Failed to create skia getProc.";
    return false;
  }

  uint32_t skia_features = 0;
  if (!logical_device_->GetPhysicalDeviceFeaturesSkia(&skia_features)) {
    FML_LOG(ERROR) << "Failed to get physical device features.";

    return false;
  }

  GrVkBackendContext backend_context;
  backend_context.fInstance = application_->GetInstance();
  backend_context.fPhysicalDevice = logical_device_->GetPhysicalDeviceHandle();
  backend_context.fDevice = logical_device_->GetHandle();
  backend_context.fQueue = logical_device_->GetQueueHandle();
  backend_context.fGraphicsQueueIndex =
      logical_device_->GetGraphicsQueueIndex();
  backend_context.fMinAPIVersion = application_->GetAPIVersion();
  backend_context.fFeatures = skia_features;
  backend_context.fGetProc = std::move(getProc);
  backend_context.fOwnsInstanceAndDevice = false;

  context_ = GrContext::MakeVulkan(backend_context);

  // Use local limits specified in this file above instead of flutter defaults.
  context_->setResourceCacheLimits(kGrCacheMaxCount, kGrCacheMaxByteSize);

  surface_pool_ =
      std::make_unique<VulkanSurfacePool>(*this, context_, scenic_session);

  return true;
}

void VulkanSurfaceProducer::OnSurfacesPresented(
    std::vector<
        std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>>
        surfaces) {
  TRACE_EVENT0("flutter", "VulkanSurfaceProducer::OnSurfacesPresented");

  // Do a single flush for all canvases derived from the context.
  {
    TRACE_EVENT0("flutter", "GrContext::flushAndSignalSemaphores");
    context_->flush();
  }

  if (!TransitionSurfacesToExternal(surfaces))
    FML_LOG(ERROR) << "TransitionSurfacesToExternal failed";

  // Submit surface
  for (auto& surface : surfaces) {
    SubmitSurface(std::move(surface));
  }

  // Buffer management.
  surface_pool_->AgeAndCollectOldBuffers();

  // If no further surface production has taken place for 10 frames (TODO:
  // Don't hardcode refresh rate here), then shrink our surface pool to fit.
  constexpr auto kShouldShrinkThreshold = zx::msec(10 * 16.67);
  async::PostDelayedTask(
      async_get_default_dispatcher(),
      [self = weak_factory_.GetWeakPtr(), kShouldShrinkThreshold] {
        if (!self) {
          return;
        }
        auto time_since_last_produce =
            async::Now(async_get_default_dispatcher()) -
            self->last_produce_time_;
        if (time_since_last_produce >= kShouldShrinkThreshold) {
          self->surface_pool_->ShrinkToFit();
        }
      },
      kShouldShrinkThreshold);
}

bool VulkanSurfaceProducer::TransitionSurfacesToExternal(
    const std::vector<
        std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>>&
        surfaces) {
  for (auto& surface : surfaces) {
    auto vk_surface = static_cast<VulkanSurface*>(surface.get());

    vulkan::VulkanCommandBuffer* command_buffer =
        vk_surface->GetCommandBuffer(logical_device_->GetCommandPool());
    if (!command_buffer->Begin())
      return false;

    GrBackendRenderTarget backendRT =
        vk_surface->GetSkiaSurface()->getBackendRenderTarget(
            SkSurface::kFlushRead_BackendHandleAccess);
    if (!backendRT.isValid()) {
      return false;
    }
    GrVkImageInfo imageInfo;
    if (!backendRT.getVkImageInfo(&imageInfo)) {
      return false;
    }

    VkImageMemoryBarrier image_barrier = {
        .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
        .pNext = nullptr,
        .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
        .dstAccessMask = 0,
        .oldLayout = imageInfo.fImageLayout,
        .newLayout = VK_IMAGE_LAYOUT_GENERAL,
        .srcQueueFamilyIndex = 0,
        .dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL_KHR,
        .image = vk_surface->GetVkImage(),
        .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}};

    if (!command_buffer->InsertPipelineBarrier(
            VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
            VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
            0,           // dependencyFlags
            0, nullptr,  // memory barriers
            0, nullptr,  // buffer barriers
            1, &image_barrier))
      return false;

    backendRT.setVkImageLayout(image_barrier.newLayout);

    if (!command_buffer->End())
      return false;

    if (!logical_device_->QueueSubmit(
            {}, {}, {vk_surface->GetAcquireVkSemaphore()},
            {command_buffer->Handle()}, vk_surface->GetCommandBufferFence()))
      return false;
  }
  return true;
}

std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>
VulkanSurfaceProducer::ProduceSurface(
    const SkISize& size,
    const flutter::LayerRasterCacheKey& layer_key,
    std::unique_ptr<scenic::EntityNode> entity_node) {
  FML_DCHECK(valid_);
  last_produce_time_ = async::Now(async_get_default_dispatcher());
  auto surface = surface_pool_->AcquireSurface(size);
  surface->SetRetainedInfo(layer_key, std::move(entity_node));
  return surface;
}

void VulkanSurfaceProducer::SubmitSurface(
    std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>
        surface) {
  FML_DCHECK(valid_ && surface != nullptr);
  surface_pool_->SubmitSurface(std::move(surface));
}

}  // namespace flutter_runner
<|endoftext|>


<commit_before>#include "FPSRole.h"
#include "Engine.h"
#include "Creature.h"
#include "AnimationBlend.h"
#include "WorldEffect.h"

CFPSRole::CFPSRole(void)
{
	m_nFire = 0;
	m_fAniCoolingTime = 0;
	m_fAniNowCoolingTime = 0;
	m_fSudCoolingTime = 0;
	m_fEmitCoolingTime = 0;

	m_fEmitNowCoolingTime = 0;
	m_fSudNowCoolingTime = 0;

	m_strMuzzleBone = "wuqi02";
	m_pArmsMesh = NULL;
	m_pBulletParticle = NULL;
	m_strBulletName = "data/effect/particle/zgfwq_sj_02.node";
	m_strMuzzleEffect  = "data/effect/particle/zgfwq_sj_01.node";
}
CFPSRole::~CFPSRole(void)
{
	g_Engine.pGame->RemoveNode(m_pBulletParticle);
	g_Engine.pGame->RemoveNode(m_pMuzzleEffect);
}

int CFPSRole::Init( int nRoleID,const char* strCharFile )
{
	if(CRoleBase::Init(nRoleID,strCharFile))
	{
		m_pStand[0] = (CAnimationBlendRotate*)m_pCreature->GetAnimationBlend("stand_h");
		m_pFire[0] = (CAnimationBlendRotate*)m_pCreature->GetAnimationBlend("fire_h");
		m_pStand[1] = (CAnimationBlendRotate*)m_pCreature->GetAnimationBlend("stand_v");
		m_pFire[1] = (CAnimationBlendRotate*)m_pCreature->GetAnimationBlend("fire_v");
		m_pRun[0] = (CAnimationBlendDual*)m_pCreature->GetAnimationBlend("run_h");
		m_pRun[1] = (CAnimationBlendDual*)m_pCreature->GetAnimationBlend("run_v");

		m_fAniNowCoolingTime = 0.0f;
		m_fAniCoolingTime = 1.0f / m_pFire[0]->GetTriggerSpeed();
		m_fEmitNowCoolingTime = 0;
		m_fSudNowCoolingTime = 0;

		m_fSudCoolingTime = m_fAniCoolingTime  * 4.0f; //ֵ
		m_fEmitCoolingTime = m_fAniCoolingTime * 3.0f;//ֵ

		m_pBulletParticle = (CObjectParticles*)g_Engine.pGame->LoadNode(m_strBulletName);
		m_pBulletParticle->GetTracker(TRACKER_CUSTOM)->SetTrackValue(0,0.0f,vec4(1.0f,1.0f,1.0f,0.8f));
		m_pBulletParticle->SetName(CUtilStr::Format("%d",m_nRoleID));

		m_pMuzzleEffect = (CWorldEffect*)g_Engine.pGame->LoadNode(m_strMuzzleEffect);
		m_pMuzzleEffect->Stop();

		m_pMuzzleEffect->SetLoop(0);
		m_pMuzzleEffect->SetLoopCount(1);

	}
	return 1;//always return 1;
}

void CFPSRole::OnKeyFrame( _ActionCallback_KeyFrame* pKeyInfo )
{
	//I will finish this function later.
}

void CFPSRole::OnActionComplete( _ActionCallback_Complete* pActInfo )
{
	return CRoleBase::OnActionComplete(pActInfo);
}

void CFPSRole::SetPaceAnimationF_B( int nF_B )
{
	switch(nF_B)
	{
	case 0:
		m_pRun[0]->CloseBlend();
		break;
	case 1:
		m_pRun[0]->PlayAnimationA();
		break;
	case 2:
		m_pRun[0]->PlayAnimationB();
		break;
	}
}

void CFPSRole::SetPaceAnimationL_R( int nF_B )
{
	switch(nF_B)
	{
	case 0:
		m_pRun[1]->CloseBlend();
		break;
	case 1:
		m_pRun[1]->PlayAnimationA();
		break;
	case 2:
		m_pRun[1]->PlayAnimationB();
		break;
	}
}

void CFPSRole::OnFire( float fCoolingTime )
{

}

void CFPSRole::UpdateMuzzleTransform()
{
	m_pFire[0]->LockFrame(2.3f);
	m_pFire[1]->LockFrame(2.3f);
	m_pStand[0]->LockFrame(2.3f);
	m_pStand[1]->LockFrame(2.3f);

	m_pArmsMesh->UpdateLink_Bone();
	m_pArmsMesh->SetTransform(m_pArmsMesh->GetTransform());

	m_matMuzzleTransform = m_pArmsMesh->GetWorldBoneTransform(m_nMuzzleBone);

}

void CFPSRole::SetMuzzleSpinL_R( float vValue )
{
	m_pStand[1]->SetRotateSpin(vValue);
	m_pFire[1]->SetRotateSpin(vValue);
}

void CFPSRole::SetMuzzleSpinU_D( float vValue )
{
	m_pStand[0]->SetRotateSpin(vValue);
	m_pFire[0]->SetRotateSpin(vValue);
}<commit_msg>Signed-off-by: mrlitong <litongtongxue@gmail.com><commit_after>#include "FPSRole.h"
#include "Engine.h"
#include "Creature.h"
#include "AnimationBlend.h"
#include "WorldEffect.h"

CFPSRole::CFPSRole(void)
{
	m_nFire = 0;
	m_fAniCoolingTime = 0;
	m_fAniNowCoolingTime = 0;
	m_fSudCoolingTime = 0;
	m_fEmitCoolingTime = 0;

	m_fEmitNowCoolingTime = 0;
	m_fSudNowCoolingTime = 0;

	m_strMuzzleBone = "wuqi02";
	m_pArmsMesh = NULL;
	m_pBulletParticle = NULL;
	m_strBulletName = "data/effect/particle/zgfwq_sj_02.node";
	m_strMuzzleEffect  = "data/effect/particle/zgfwq_sj_01.node";
}
CFPSRole::~CFPSRole(void)
{
	g_Engine.pGame->RemoveNode(m_pBulletParticle);
	g_Engine.pGame->RemoveNode(m_pMuzzleEffect);
}

int CFPSRole::Init( int nRoleID,const char* strCharFile )
{
	if(CRoleBase::Init(nRoleID,strCharFile))
	{
		m_pStand[0] = (CAnimationBlendRotate*)m_pCreature->GetAnimationBlend("stand_h");
		m_pFire[0] = (CAnimationBlendRotate*)m_pCreature->GetAnimationBlend("fire_h");
		m_pStand[1] = (CAnimationBlendRotate*)m_pCreature->GetAnimationBlend("stand_v");
		m_pFire[1] = (CAnimationBlendRotate*)m_pCreature->GetAnimationBlend("fire_v");
		m_pRun[0] = (CAnimationBlendDual*)m_pCreature->GetAnimationBlend("run_h");
		m_pRun[1] = (CAnimationBlendDual*)m_pCreature->GetAnimationBlend("run_v");

		m_fAniNowCoolingTime = 0.0f;
		m_fAniCoolingTime = 1.0f / m_pFire[0]->GetTriggerSpeed();
		m_fEmitNowCoolingTime = 0;
		m_fSudNowCoolingTime = 0;

		m_fSudCoolingTime = m_fAniCoolingTime  * 4.0f; //ֵ
		m_fEmitCoolingTime = m_fAniCoolingTime * 3.0f;//ֵ

		m_pBulletParticle = (CObjectParticles*)g_Engine.pGame->LoadNode(m_strBulletName);
		m_pBulletParticle->GetTracker(TRACKER_CUSTOM)->SetTrackValue(0,0.0f,vec4(1.0f,1.0f,1.0f,0.8f));
		m_pBulletParticle->SetName(CUtilStr::Format("%d",m_nRoleID));

		m_pMuzzleEffect = (CWorldEffect*)g_Engine.pGame->LoadNode(m_strMuzzleEffect);
		m_pMuzzleEffect->Stop();

		m_pMuzzleEffect->SetLoop(0);
		m_pMuzzleEffect->SetLoopCount(1);

	}
	return 1;//always return 1;
}

void CFPSRole::OnKeyFrame( _ActionCallback_KeyFrame* pKeyInfo )
{
	//I will finish this function later.
}

void CFPSRole::OnActionComplete( _ActionCallback_Complete* pActInfo )
{
	return CRoleBase::OnActionComplete(pActInfo);
}

void CFPSRole::SetPaceAnimationF_B( int nF_B )
{
	switch(nF_B)
	{
	case 0:
		m_pRun[0]->CloseBlend();
		break;
	case 1:
		m_pRun[0]->PlayAnimationA();
		break;
	case 2:
		m_pRun[0]->PlayAnimationB();
		break;
	}
}

void CFPSRole::SetPaceAnimationL_R( int nF_B )
{
	switch(nF_B)
	{
	case 0:
		m_pRun[1]->CloseBlend();
		break;
	case 1:
		m_pRun[1]->PlayAnimationA();
		break;
	case 2:
		m_pRun[1]->PlayAnimationB();
		break;
	}
}

void CFPSRole::OnFire( float fCoolingTime )
{

}

void CFPSRole::UpdateMuzzleTransform()
{
	m_pFire[0]->LockFrame(2.3f);
	m_pFire[1]->LockFrame(2.3f);
	m_pStand[0]->LockFrame(2.3f);
	m_pStand[1]->LockFrame(2.3f);

	m_pArmsMesh->UpdateLink_Bone();
	m_pArmsMesh->SetTransform(m_pArmsMesh->GetTransform());

	m_matMuzzleTransform = m_pArmsMesh->GetWorldBoneTransform(m_nMuzzleBone);

}

void CFPSRole::SetMuzzleSpinL_R( float vValue )
{
	m_pStand[1]->SetRotateSpin(vValue);
	m_pFire[1]->SetRotateSpin(vValue);
}

void CFPSRole::SetMuzzleSpinU_D( float vValue )
{
	m_pStand[0]->SetRotateSpin(vValue);
	m_pFire[0]->SetRotateSpin(vValue);
}

<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2016, Microsoft

// 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 <cstring>
#include <memory>

#include "BitFunnel/Utilities/Allocator.h"
#include "BitFunnel/Utilities/Factories.h"
#include "LoggerInterfaces/Logging.h"

namespace BitFunnel
{
    std::unique_ptr<IAllocator>
        Factories::CreateAllocator(size_t bufferSize)
    {
        return std::unique_ptr<IAllocator>(new Allocator(bufferSize));
    }

    //*************************************************************************
    //
    // Allocator
    //
    //*************************************************************************
    Allocator::Allocator(size_t bufferSize)
      : m_bufferSize(bufferSize),
        m_bytesAllocated(0),
        m_buffer(new char[bufferSize])
    {
        DebugInitialize();
    }

    Allocator::~Allocator()
    {
    }

    void* Allocator::Allocate(size_t size)
    {
        LogAssertB(m_bytesAllocated + size <= m_bufferSize, "Out of memory");

        void* result = static_cast<void*>(m_buffer.get() + m_bytesAllocated);
        m_bytesAllocated += size;

        return result;
    }

    void Allocator::Deallocate(void* block)
    {
        LogAssertB(static_cast<char*>(block) >= m_buffer.get() &&
                       static_cast<char*>(block) < m_buffer.get() + m_bytesAllocated,
                       "Attempting to deallocate memory not owned by this allocator.");

        // Intentional NOP
    }

    size_t Allocator::MaxSize() const
    {
        return m_bufferSize;
    }

    void Allocator::Reset()
    {
        m_bytesAllocated = 0;
#ifdef DEBUG
        DebugInitialize();
#endif
    }

    void Allocator::DebugInitialize()
    {
        memset(m_buffer.get(), 0xcc, m_bufferSize);
    }
}
<commit_msg>Don't DebugInitialize in Release build. Fixes #271.<commit_after>// The MIT License (MIT)

// Copyright (c) 2016, Microsoft

// 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 <cstring>
#include <memory>

#include "BitFunnel/Utilities/Allocator.h"
#include "BitFunnel/Utilities/Factories.h"
#include "LoggerInterfaces/Logging.h"

namespace BitFunnel
{
    std::unique_ptr<IAllocator>
        Factories::CreateAllocator(size_t bufferSize)
    {
        return std::unique_ptr<IAllocator>(new Allocator(bufferSize));
    }

    //*************************************************************************
    //
    // Allocator
    //
    //*************************************************************************
    Allocator::Allocator(size_t bufferSize)
      : m_bufferSize(bufferSize),
        m_bytesAllocated(0),
        m_buffer(new char[bufferSize])
    {
#ifdef DEBUG
        DebugInitialize();
#endif
    }

    Allocator::~Allocator()
    {
    }

    void* Allocator::Allocate(size_t size)
    {
        LogAssertB(m_bytesAllocated + size <= m_bufferSize, "Out of memory");

        void* result = static_cast<void*>(m_buffer.get() + m_bytesAllocated);
        m_bytesAllocated += size;

        return result;
    }

    void Allocator::Deallocate(void* block)
    {
        LogAssertB(static_cast<char*>(block) >= m_buffer.get() &&
                       static_cast<char*>(block) < m_buffer.get() + m_bytesAllocated,
                       "Attempting to deallocate memory not owned by this allocator.");

        // Intentional NOP
    }

    size_t Allocator::MaxSize() const
    {
        return m_bufferSize;
    }

    void Allocator::Reset()
    {
        m_bytesAllocated = 0;
#ifdef DEBUG
        DebugInitialize();
#endif
    }

    void Allocator::DebugInitialize()
    {
        memset(m_buffer.get(), 0xcc, m_bufferSize);
    }
}
<|endoftext|>


<commit_before>#include <aleph/config/Eigen.hh>

#include <aleph/geometry/HeatKernel.hh>

#include <aleph/topology/io/GML.hh>

#include <aleph/topology/Simplex.hh>
#include <aleph/topology/SimplicialComplex.hh>

#include <aleph/utilities/Filesystem.hh>

#ifdef ALEPH_WITH_EIGEN
  #include <Eigen/Eigenvalues>
#endif

#include <algorithm>
#include <iostream>
#include <map>
#include <numeric>
#include <regex>
#include <string>
#include <vector>

// Auxiliary class for storing the spectrum of a graph, i.e. the set of
// eigenvalues. This class offers a simple distance calculation.
template <class T> class Spectrum
{
public:

  template <class InputIterator> Spectrum( InputIterator begin, InputIterator end )
    : _eigenvalues( begin, end )
  {
  }

  std::size_t size() const noexcept
  {
    return _eigenvalues.size();
  }

  T distance( const Spectrum& other ) const noexcept
  {
    auto n         = this->size();
    auto m         = other.size();
    auto spectrum1 = this->_eigenvalues;
    auto spectrum2 = other._eigenvalues;

    spectrum1.resize( std::max(n,m) );
    spectrum2.resize( std::max(n,m) );

    std::sort( spectrum1.begin(), spectrum1.end(), std::greater<T>() );
    std::sort( spectrum2.begin(), spectrum2.end(), std::greater<T>() );

    // Squared Euclidean distance
    return std::inner_product( spectrum1.begin(), spectrum1.end(),
                               spectrum2.begin(),
                               T(0),
                               std::plus<T>(),
                               []( T x,T y )
                               {
                                 return ( x-y )*( x-y );
                               }
    );
  }

private:
  std::vector<T> _eigenvalues;
};

int main( int argc, char** argv )
{
  if( argc <= 1 )
    return -1;

  using DataType          = double;
  using VertexType        = unsigned short;
  using Simplex           = aleph::topology::Simplex<DataType, VertexType>;
  using SimplicialComplex = aleph::topology::SimplicialComplex<Simplex>;
  using Spectrum          = Spectrum<DataType>;

  std::vector<std::string> filenames;

  for( int i = 1; i < argc; i++ )
    filenames.push_back( argv[i] );

  aleph::topology::io::GMLReader reader;

  std::vector<Spectrum> spectra;
  spectra.reserve( filenames.size() );

  for( auto&& filename : filenames )
  {
    std::cerr << "* Processing '" << filename << "'...";

    SimplicialComplex K;
    reader( filename, K );

    K.sort();

    // TODO:
    //  - Extract vertex data
    //  - Use vertex data in Laplacian matrix

    auto L           = aleph::geometry::weightedLaplacianMatrix( K );
    using MatrixType = decltype(L);

    Eigen::SelfAdjointEigenSolver<MatrixType> solver;
    solver.compute( L );

    auto eigenvalues = solver.eigenvalues();

    {
      std::vector<DataType> data;
      for( decltype( eigenvalues.size() ) i = 0; i < eigenvalues.size(); i++ )
        data.push_back( eigenvalues( i ) );

      spectra.push_back( Spectrum( data.begin(), data.end() ) );
    }

    std::cerr << "finished\n";
  }

  // Calculate spectral distances --------------------------------------

  std::vector< std::vector<DataType> > distances( spectra.size(),
    std::vector<DataType>( spectra.size() ) );

  for( std::size_t i = 0; i < spectra.size(); i++ )
  {
    for( std::size_t j = i+1; j < spectra.size(); j++ )
    {
      distances[i][j] = spectra[i].distance( spectra[j] );
      distances[j][i] = distances[i][j];
    }
  }

  for( std::size_t i = 0; i < spectra.size(); i++ )
  {
    for( std::size_t j = 0; j < spectra.size(); j++ )
    {
      if( j != 0 )
        std::cout << " ";

      std::cout << distances[i][j];
    }

    std::cout << "\n";
  }

  std::cout << "\n\n";
}
<commit_msg>Uniform assignment of edge weights<commit_after>#include <aleph/config/Eigen.hh>

#include <aleph/geometry/HeatKernel.hh>

#include <aleph/topology/io/GML.hh>

#include <aleph/topology/Simplex.hh>
#include <aleph/topology/SimplicialComplex.hh>

#include <aleph/utilities/Filesystem.hh>

#ifdef ALEPH_WITH_EIGEN
  #include <Eigen/Eigenvalues>
#endif

#include <algorithm>
#include <iostream>
#include <map>
#include <numeric>
#include <regex>
#include <string>
#include <vector>

// Auxiliary class for storing the spectrum of a graph, i.e. the set of
// eigenvalues. This class offers a simple distance calculation.
template <class T> class Spectrum
{
public:

  template <class InputIterator> Spectrum( InputIterator begin, InputIterator end )
    : _eigenvalues( begin, end )
  {
  }

  std::size_t size() const noexcept
  {
    return _eigenvalues.size();
  }

  T distance( const Spectrum& other ) const noexcept
  {
    auto n         = this->size();
    auto m         = other.size();
    auto spectrum1 = this->_eigenvalues;
    auto spectrum2 = other._eigenvalues;

    spectrum1.resize( std::max(n,m) );
    spectrum2.resize( std::max(n,m) );

    std::sort( spectrum1.begin(), spectrum1.end(), std::greater<T>() );
    std::sort( spectrum2.begin(), spectrum2.end(), std::greater<T>() );

    // Squared Euclidean distance
    return std::inner_product( spectrum1.begin(), spectrum1.end(),
                               spectrum2.begin(),
                               T(0),
                               std::plus<T>(),
                               []( T x,T y )
                               {
                                 return ( x-y )*( x-y );
                               }
    );
  }

private:
  std::vector<T> _eigenvalues;
};

int main( int argc, char** argv )
{
  if( argc <= 1 )
    return -1;

  using DataType          = double;
  using VertexType        = unsigned short;
  using Simplex           = aleph::topology::Simplex<DataType, VertexType>;
  using SimplicialComplex = aleph::topology::SimplicialComplex<Simplex>;
  using Spectrum          = Spectrum<DataType>;

  std::vector<std::string> filenames;

  for( int i = 1; i < argc; i++ )
    filenames.push_back( argv[i] );

  aleph::topology::io::GMLReader reader;

  std::vector<Spectrum> spectra;
  spectra.reserve( filenames.size() );

  for( auto&& filename : filenames )
  {
    std::cerr << "* Processing '" << filename << "'...";

    SimplicialComplex K;
    reader( filename, K );

    // Fall back to adding uniform edge weights ------------------------

    for( auto it = K.begin(); it != K.end(); ++it )
    {
      auto simplex = *it;
      if( simplex.dimension() == 1 )
      {
        simplex.setData( 1 );
        K.replace( it, simplex );
      }
    }

    K.sort();

    // TODO:
    //  - Extract vertex data
    //  - Use vertex data in Laplacian matrix

    auto L           = aleph::geometry::weightedLaplacianMatrix( K );
    using MatrixType = decltype(L);

    Eigen::SelfAdjointEigenSolver<MatrixType> solver;
    solver.compute( L );

    auto eigenvalues = solver.eigenvalues();

    {
      std::vector<DataType> data;
      for( decltype( eigenvalues.size() ) i = 0; i < eigenvalues.size(); i++ )
        data.push_back( eigenvalues( i ) );

      spectra.push_back( Spectrum( data.begin(), data.end() ) );
    }

    std::cerr << "finished\n";

    auto numEdges = std::count_if( K.begin(), K.end(),
      [] ( const Simplex& s )
      {
        return s.dimension() == 1;
      }
    );

    std::cerr << "* Extracted graph has " << numEdges << " edges\n";
  }

  // Calculate spectral distances --------------------------------------

  std::vector< std::vector<DataType> > distances( spectra.size(),
    std::vector<DataType>( spectra.size() ) );

  for( std::size_t i = 0; i < spectra.size(); i++ )
  {
    for( std::size_t j = i+1; j < spectra.size(); j++ )
    {
      distances[i][j] = spectra[i].distance( spectra[j] );
      distances[j][i] = distances[i][j];
    }
  }

  for( std::size_t i = 0; i < spectra.size(); i++ )
  {
    for( std::size_t j = 0; j < spectra.size(); j++ )
    {
      if( j != 0 )
        std::cout << " ";

      std::cout << distances[i][j];
    }

    std::cout << "\n";
  }

  std::cout << "\n\n";
}
<|endoftext|>


<commit_before>/******************************************************************************
 **  Filename:  cntraining.cpp
 **  Purpose:  Generates a normproto and pffmtable.
 **  Author:    Dan Johnson
 **  Revisment:  Christy Russon
 **
 **  (c) Copyright Hewlett-Packard Company, 1988.
 ** 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
 ** 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.
 ******************************************************************************/

/*----------------------------------------------------------------------------
          Include Files and Type Defines
----------------------------------------------------------------------------*/
#include <tesseract/unichar.h>
#include <cmath>
#include <cstdio>
#include <cstring>
#include "cluster.h"
#include "clusttool.h"
#include "commontraining.h"
#include "featdefs.h"
#include "ocrfeatures.h"
#include "oldlist.h"

#define PROGRAM_FEATURE_TYPE "cn"

using namespace tesseract;

/*----------------------------------------------------------------------------
          Private Function Prototypes
----------------------------------------------------------------------------*/

static void WriteNormProtos(const char *Directory, LIST LabeledProtoList,
                            const FEATURE_DESC_STRUCT *feature_desc);

static void WriteProtos(FILE *File, uint16_t N, LIST ProtoList, bool WriteSigProtos,
                        bool WriteInsigProtos);

/*----------------------------------------------------------------------------
          Global Data Definitions and Declarations
----------------------------------------------------------------------------*/
/* global variable to hold configuration parameters to control clustering */
//-M 0.025   -B 0.05   -I 0.8   -C 1e-3
static const CLUSTERCONFIG CNConfig = {elliptical, 0.025, 0.05, 0.8, 1e-3, 0};

/*----------------------------------------------------------------------------
              Public Code
----------------------------------------------------------------------------*/

/**
* This program reads in a text file consisting of feature
* samples from a training page in the following format:
* @verbatim
   FontName CharName NumberOfFeatureTypes(N)
      FeatureTypeName1 NumberOfFeatures(M)
         Feature1
         ...
         FeatureM
      FeatureTypeName2 NumberOfFeatures(M)
         Feature1
         ...
         FeatureM
      ...
      FeatureTypeNameN NumberOfFeatures(M)
         Feature1
         ...
         FeatureM
   FontName CharName ...
@endverbatim
* It then appends these samples into a separate file for each
* character.  The name of the file is
*
*   DirectoryName/FontName/CharName.FeatureTypeName
*
* The DirectoryName can be specified via a command
* line argument.  If not specified, it defaults to the
* current directory.  The format of the resulting files is:
* @verbatim
   NumberOfFeatures(M)
      Feature1
      ...
      FeatureM
   NumberOfFeatures(M)
   ...
@endverbatim
* The output files each have a header which describes the
* type of feature which the file contains.  This header is
* in the format required by the clusterer.  A command line
* argument can also be used to specify that only the first
* N samples of each class should be used.
* @param argc  number of command line arguments
* @param argv  array of command line arguments
* @return 0 on success
*/
int main(int argc, char *argv[]) {
  tesseract::CheckSharedLibraryVersion();

  // Set the global Config parameters before parsing the command line.
  Config = CNConfig;

  const char *PageName;
  LIST CharList = NIL_LIST;
  CLUSTERER *Clusterer = nullptr;
  LIST ProtoList = NIL_LIST;
  LIST NormProtoList = NIL_LIST;
  LIST pCharList;
  LABELEDLIST CharSample;
  FEATURE_DEFS_STRUCT FeatureDefs;
  InitFeatureDefs(&FeatureDefs);

  ParseArguments(&argc, &argv);
  int num_fonts = 0;
  int tessoptind = 1;
  while ((PageName = GetNextFilename(argc, argv, tessoptind)) != nullptr) {
    printf("Reading %s ...\n", PageName);
    FILE *TrainingPage = fopen(PageName, "rb");
    ASSERT_HOST(TrainingPage);
    if (TrainingPage) {
      ReadTrainingSamples(FeatureDefs, PROGRAM_FEATURE_TYPE, 100, nullptr, TrainingPage, &CharList);
      fclose(TrainingPage);
      ++num_fonts;
    }
  }
  printf("Clustering ...\n");
  // To allow an individual font to form a separate cluster,
  // reduce the min samples:
  // Config.MinSamples = 0.5 / num_fonts;
  pCharList = CharList;
  // The norm protos will count the source protos, so we keep them here in
  // freeable_protos, so they can be freed later.
  GenericVector<LIST> freeable_protos;
  iterate(pCharList) {
    // Cluster
    CharSample = reinterpret_cast<LABELEDLIST> first_node(pCharList);
    Clusterer = SetUpForClustering(FeatureDefs, CharSample, PROGRAM_FEATURE_TYPE);
    if (Clusterer == nullptr) { // To avoid a SIGSEGV
      fprintf(stderr, "Error: nullptr clusterer!\n");
      return 1;
    }
    float SavedMinSamples = Config.MinSamples;
    // To disable the tendency to produce a single cluster for all fonts,
    // make MagicSamples an impossible to achieve number:
    // Config.MagicSamples = CharSample->SampleCount * 10;
    Config.MagicSamples = CharSample->SampleCount;
    while (Config.MinSamples > 0.001) {
      ProtoList = ClusterSamples(Clusterer, &Config);
      if (NumberOfProtos(ProtoList, true, false) > 0) {
        break;
      } else {
        Config.MinSamples *= 0.95;
        printf(
            "0 significant protos for %s."
            " Retrying clustering with MinSamples = %f%%\n",
            CharSample->Label, Config.MinSamples);
      }
    }
    Config.MinSamples = SavedMinSamples;
    AddToNormProtosList(&NormProtoList, ProtoList, CharSample->Label);
    freeable_protos.push_back(ProtoList);
    FreeClusterer(Clusterer);
  }
  FreeTrainingSamples(CharList);
  int desc_index = ShortNameToFeatureType(FeatureDefs, PROGRAM_FEATURE_TYPE);
  WriteNormProtos(FLAGS_D.c_str(), NormProtoList, FeatureDefs.FeatureDesc[desc_index]);
  FreeNormProtoList(NormProtoList);
  for (int i = 0; i < freeable_protos.size(); ++i) {
    FreeProtoList(&freeable_protos[i]);
  }
  printf("\n");
  return 0;
} // main

/*----------------------------------------------------------------------------
              Private Code
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------*/
/**
 * This routine writes the specified samples into files which
 * are organized according to the font name and character name
 * of the samples.
 * @param Directory  directory to place sample files into
 * @param LabeledProtoList List of labeled protos
 * @param feature_desc Description of the features
 */
static void WriteNormProtos(const char *Directory, LIST LabeledProtoList,
                            const FEATURE_DESC_STRUCT *feature_desc) {
  FILE *File;
  LABELEDLIST LabeledProto;
  int N;

  std::string Filename = "";
  if (Directory != nullptr && Directory[0] != '\0') {
    Filename += Directory;
    Filename += "/";
  }
  Filename += "normproto";
  printf("\nWriting %s ...", Filename.c_str());
  File = fopen(Filename.c_str(), "wb");
  ASSERT_HOST(File);
  fprintf(File, "%0d\n", feature_desc->NumParams);
  WriteParamDesc(File, feature_desc->NumParams, feature_desc->ParamDesc);
  iterate(LabeledProtoList) {
    LabeledProto = reinterpret_cast<LABELEDLIST> first_node(LabeledProtoList);
    N = NumberOfProtos(LabeledProto->List, true, false);
    if (N < 1) {
      printf(
          "\nError! Not enough protos for %s: %d protos"
          " (%d significant protos"
          ", %d insignificant protos)\n",
          LabeledProto->Label, N, NumberOfProtos(LabeledProto->List, true, false),
          NumberOfProtos(LabeledProto->List, false, true));
      exit(1);
    }
    fprintf(File, "\n%s %d\n", LabeledProto->Label, N);
    WriteProtos(File, feature_desc->NumParams, LabeledProto->List, true, false);
  }
  fclose(File);

} // WriteNormProtos

/*-------------------------------------------------------------------------*/

static void WriteProtos(FILE *File, uint16_t N, LIST ProtoList, bool WriteSigProtos,
                        bool WriteInsigProtos) {
  PROTOTYPE *Proto;

  // write prototypes
  iterate(ProtoList) {
    Proto = reinterpret_cast<PROTOTYPE *> first_node(ProtoList);
    if ((Proto->Significant && WriteSigProtos) || (!Proto->Significant && WriteInsigProtos))
      WritePrototype(File, N, Proto);
  }
} // WriteProtos
<commit_msg>Replace more GenericVector by std::vector for src/training<commit_after>/******************************************************************************
 **  Filename:  cntraining.cpp
 **  Purpose:  Generates a normproto and pffmtable.
 **  Author:    Dan Johnson
 **  Revisment:  Christy Russon
 **
 **  (c) Copyright Hewlett-Packard Company, 1988.
 ** 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
 ** 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.
 ******************************************************************************/

/*----------------------------------------------------------------------------
          Include Files and Type Defines
----------------------------------------------------------------------------*/
#include <tesseract/unichar.h>
#include <cmath>
#include <cstdio>
#include <cstring>
#include "cluster.h"
#include "clusttool.h"
#include "commontraining.h"
#include "featdefs.h"
#include "ocrfeatures.h"
#include "oldlist.h"

#define PROGRAM_FEATURE_TYPE "cn"

using namespace tesseract;

/*----------------------------------------------------------------------------
          Private Function Prototypes
----------------------------------------------------------------------------*/

static void WriteNormProtos(const char *Directory, LIST LabeledProtoList,
                            const FEATURE_DESC_STRUCT *feature_desc);

static void WriteProtos(FILE *File, uint16_t N, LIST ProtoList, bool WriteSigProtos,
                        bool WriteInsigProtos);

/*----------------------------------------------------------------------------
          Global Data Definitions and Declarations
----------------------------------------------------------------------------*/
/* global variable to hold configuration parameters to control clustering */
//-M 0.025   -B 0.05   -I 0.8   -C 1e-3
static const CLUSTERCONFIG CNConfig = {elliptical, 0.025, 0.05, 0.8, 1e-3, 0};

/*----------------------------------------------------------------------------
              Public Code
----------------------------------------------------------------------------*/

/**
* This program reads in a text file consisting of feature
* samples from a training page in the following format:
* @verbatim
   FontName CharName NumberOfFeatureTypes(N)
      FeatureTypeName1 NumberOfFeatures(M)
         Feature1
         ...
         FeatureM
      FeatureTypeName2 NumberOfFeatures(M)
         Feature1
         ...
         FeatureM
      ...
      FeatureTypeNameN NumberOfFeatures(M)
         Feature1
         ...
         FeatureM
   FontName CharName ...
@endverbatim
* It then appends these samples into a separate file for each
* character.  The name of the file is
*
*   DirectoryName/FontName/CharName.FeatureTypeName
*
* The DirectoryName can be specified via a command
* line argument.  If not specified, it defaults to the
* current directory.  The format of the resulting files is:
* @verbatim
   NumberOfFeatures(M)
      Feature1
      ...
      FeatureM
   NumberOfFeatures(M)
   ...
@endverbatim
* The output files each have a header which describes the
* type of feature which the file contains.  This header is
* in the format required by the clusterer.  A command line
* argument can also be used to specify that only the first
* N samples of each class should be used.
* @param argc  number of command line arguments
* @param argv  array of command line arguments
* @return 0 on success
*/
int main(int argc, char *argv[]) {
  tesseract::CheckSharedLibraryVersion();

  // Set the global Config parameters before parsing the command line.
  Config = CNConfig;

  const char *PageName;
  LIST CharList = NIL_LIST;
  CLUSTERER *Clusterer = nullptr;
  LIST ProtoList = NIL_LIST;
  LIST NormProtoList = NIL_LIST;
  LIST pCharList;
  LABELEDLIST CharSample;
  FEATURE_DEFS_STRUCT FeatureDefs;
  InitFeatureDefs(&FeatureDefs);

  ParseArguments(&argc, &argv);
  int num_fonts = 0;
  int tessoptind = 1;
  while ((PageName = GetNextFilename(argc, argv, tessoptind)) != nullptr) {
    printf("Reading %s ...\n", PageName);
    FILE *TrainingPage = fopen(PageName, "rb");
    ASSERT_HOST(TrainingPage);
    if (TrainingPage) {
      ReadTrainingSamples(FeatureDefs, PROGRAM_FEATURE_TYPE, 100, nullptr, TrainingPage, &CharList);
      fclose(TrainingPage);
      ++num_fonts;
    }
  }
  printf("Clustering ...\n");
  // To allow an individual font to form a separate cluster,
  // reduce the min samples:
  // Config.MinSamples = 0.5 / num_fonts;
  pCharList = CharList;
  // The norm protos will count the source protos, so we keep them here in
  // freeable_protos, so they can be freed later.
  std::vector<LIST> freeable_protos;
  iterate(pCharList) {
    // Cluster
    CharSample = reinterpret_cast<LABELEDLIST> first_node(pCharList);
    Clusterer = SetUpForClustering(FeatureDefs, CharSample, PROGRAM_FEATURE_TYPE);
    if (Clusterer == nullptr) { // To avoid a SIGSEGV
      fprintf(stderr, "Error: nullptr clusterer!\n");
      return 1;
    }
    float SavedMinSamples = Config.MinSamples;
    // To disable the tendency to produce a single cluster for all fonts,
    // make MagicSamples an impossible to achieve number:
    // Config.MagicSamples = CharSample->SampleCount * 10;
    Config.MagicSamples = CharSample->SampleCount;
    while (Config.MinSamples > 0.001) {
      ProtoList = ClusterSamples(Clusterer, &Config);
      if (NumberOfProtos(ProtoList, true, false) > 0) {
        break;
      } else {
        Config.MinSamples *= 0.95;
        printf(
            "0 significant protos for %s."
            " Retrying clustering with MinSamples = %f%%\n",
            CharSample->Label, Config.MinSamples);
      }
    }
    Config.MinSamples = SavedMinSamples;
    AddToNormProtosList(&NormProtoList, ProtoList, CharSample->Label);
    freeable_protos.push_back(ProtoList);
    FreeClusterer(Clusterer);
  }
  FreeTrainingSamples(CharList);
  int desc_index = ShortNameToFeatureType(FeatureDefs, PROGRAM_FEATURE_TYPE);
  WriteNormProtos(FLAGS_D.c_str(), NormProtoList, FeatureDefs.FeatureDesc[desc_index]);
  FreeNormProtoList(NormProtoList);
  for (int i = 0; i < freeable_protos.size(); ++i) {
    FreeProtoList(&freeable_protos[i]);
  }
  printf("\n");
  return 0;
} // main

/*----------------------------------------------------------------------------
              Private Code
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------*/
/**
 * This routine writes the specified samples into files which
 * are organized according to the font name and character name
 * of the samples.
 * @param Directory  directory to place sample files into
 * @param LabeledProtoList List of labeled protos
 * @param feature_desc Description of the features
 */
static void WriteNormProtos(const char *Directory, LIST LabeledProtoList,
                            const FEATURE_DESC_STRUCT *feature_desc) {
  FILE *File;
  LABELEDLIST LabeledProto;
  int N;

  std::string Filename = "";
  if (Directory != nullptr && Directory[0] != '\0') {
    Filename += Directory;
    Filename += "/";
  }
  Filename += "normproto";
  printf("\nWriting %s ...", Filename.c_str());
  File = fopen(Filename.c_str(), "wb");
  ASSERT_HOST(File);
  fprintf(File, "%0d\n", feature_desc->NumParams);
  WriteParamDesc(File, feature_desc->NumParams, feature_desc->ParamDesc);
  iterate(LabeledProtoList) {
    LabeledProto = reinterpret_cast<LABELEDLIST> first_node(LabeledProtoList);
    N = NumberOfProtos(LabeledProto->List, true, false);
    if (N < 1) {
      printf(
          "\nError! Not enough protos for %s: %d protos"
          " (%d significant protos"
          ", %d insignificant protos)\n",
          LabeledProto->Label, N, NumberOfProtos(LabeledProto->List, true, false),
          NumberOfProtos(LabeledProto->List, false, true));
      exit(1);
    }
    fprintf(File, "\n%s %d\n", LabeledProto->Label, N);
    WriteProtos(File, feature_desc->NumParams, LabeledProto->List, true, false);
  }
  fclose(File);

} // WriteNormProtos

/*-------------------------------------------------------------------------*/

static void WriteProtos(FILE *File, uint16_t N, LIST ProtoList, bool WriteSigProtos,
                        bool WriteInsigProtos) {
  PROTOTYPE *Proto;

  // write prototypes
  iterate(ProtoList) {
    Proto = reinterpret_cast<PROTOTYPE *> first_node(ProtoList);
    if ((Proto->Significant && WriteSigProtos) || (!Proto->Significant && WriteInsigProtos))
      WritePrototype(File, N, Proto);
  }
} // WriteProtos
<|endoftext|>