<commit_before>#include <algorithm>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <limits>
#include <numeric>
#include <string>
#include <sstream>

#include <cmath>

#include "filtrations/Data.hh"

#include "geometry/RipsExpander.hh"

#include "persistenceDiagrams/Norms.hh"
#include "persistenceDiagrams/PersistenceDiagram.hh"

#include "persistentHomology/ConnectedComponents.hh"

#include "topology/CliqueGraph.hh"
#include "topology/ConnectedComponents.hh"
#include "topology/Simplex.hh"
#include "topology/SimplicialComplex.hh"

#include "topology/io/EdgeLists.hh"
#include "topology/io/GML.hh"
#include "topology/io/Pajek.hh"

#include "utilities/Filesystem.hh"

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

std::string formatOutput( const std::string& prefix, unsigned k, unsigned K )
{
  std::ostringstream stream;
  stream << prefix;
  stream << std::setw( int( std::log10( K ) + 1 ) ) << std::setfill( '0' ) << k;
  stream << ".txt";

  return stream.str();
}

void usage()
{
  std::cerr << "Usage: clique-persistence-diagram FILE K\n"
            << "\n"
            << "Calculates the clique persistence diagram for FILE, which is\n"
            << "supposed to be a weighted graph. The K parameter denotes the\n"
            << "maximum dimension of a simplex for extracting a clique graph\n"
            << "and tracking persistence of clique communities.\n\n";
}

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

  std::string filename = argv[1];
  unsigned maxK        = static_cast<unsigned>( std::stoul( argv[2] ) );

  SimplicialComplex K;

  // Input -------------------------------------------------------------

  std::cerr << "* Reading '" << filename << "'...";

  // Optional map of node labels. If the graph contains node labels and
  // I am able to read them, this map will be filled.
  std::map<VertexType, std::string> labels;

  if( aleph::utilities::extension( filename ) == ".gml" )
  {
    aleph::topology::io::GMLReader reader;
    reader( filename, K );

    auto labelMap = reader.getNodeAttribute( "label" );

    // Note that this assumes that the labels are convertible to
    // numbers.
    //
    // TODO: Solve this generically?
    for( auto&& pair : labelMap )
      if( !pair.second.empty() )
        labels[ static_cast<VertexType>( std::stoul( pair.first ) ) ] = pair.second;

    if( labels.empty() )
      labels.clear();
  }
  else if( aleph::utilities::extension( filename ) == ".net" )
  {
    aleph::topology::io::PajekReader reader;
    reader( filename, K );

    auto labelMap = reader.getLabelMap();

    // Note that this assumes that the labels are convertible to
    // numbers.
    //
    // TODO: Solve this generically?
    for( auto&& pair : labelMap )
      if( !pair.second.empty() )
        labels[ static_cast<VertexType>( std::stoul( pair.first ) ) ] = pair.second;

    if( labels.empty() )
      labels.clear();

  }
  else
  {
    aleph::io::EdgeListReader reader;
    reader.setReadWeights( true );
    reader.setTrimLines( true );

    reader( filename, K );
  }

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

  DataType maxWeight = std::numeric_limits<DataType>::lowest();
  for( auto&& simplex : K )
    maxWeight = std::max( maxWeight, simplex.data() );

  // TODO: Make weight inversion configurable. It is not required for all data
  // sets but should be used on an as-needed basis.

  std::cerr << "* Inverting filtration weights...";

  for( auto it = K.begin(); it != K.end(); ++it )
  {
    if( K.dimension() == 0 )
      continue;

    auto s = *it;
    s.setData( maxWeight - s.data() );

    K.replace( it, s );
  }

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

  // Expansion ---------------------------------------------------------

  std::cerr << "* Expanding simplicial complex to k=" << maxK << "...";

  aleph::geometry::RipsExpander<SimplicialComplex> ripsExpander;
  K = ripsExpander( K, maxK );
  K = ripsExpander.assignMaximumWeight( K );

  std::cerr << "finished\n"
            << "* Expanded simplicial complex has " << K.size() << " simplices\n";

  K.sort( aleph::filtrations::Data<Simplex>() );

  // Stores the accumulated persistence of vertices. Persistence
  // accumulates if a vertex participates in a clique community.
  std::map<VertexType, double> accumulatedPersistenceMap;

  // Stores the number of clique communities a vertex is a part of.
  // I am using this only for debugging the algorithm.
  std::map<VertexType, unsigned> numberOfCliqueCommunities;

  std::vector<double> totalPersistenceValues;
  totalPersistenceValues.reserve( maxK );

  for( unsigned k = 1; k <= maxK; k++ )
  {
    std::cerr << "* Extracting " << k << "-cliques graph...";

    auto C
        = aleph::topology::getCliqueGraph( K, k );

    C.sort( aleph::filtrations::Data<Simplex>() );

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

    std::cerr << "* " << k << "-cliques graph has " << C.size() << " simplices\n";

    if( C.empty() )
    {
      std::cerr << "* Stopping here because no further cliques for processing exist\n";
      break;
    }

    auto&& tuple = aleph::calculateZeroDimensionalPersistenceDiagram( C );
    auto&& pd    = std::get<0>( tuple );
    auto&& pp    = std::get<1>( tuple );

    auto itPoint = pd.begin();
    for( auto itPair = pp.begin(); itPair != pp.end(); ++itPair )
    {
      // Skip zero-dimensional persistence pairs
      if( itPoint->x() == itPoint->y() )
      {
        ++itPoint;
        continue;
      }

      SimplicialComplex filteredComplex;

      {
        std::vector<Simplex> simplices;
        if( itPair->second < C.size() )
        {
          simplices.reserve( itPair->second );

          std::copy( C.begin() + itPair->first, C.begin() + itPair->second, std::back_inserter( simplices ) );
          filteredComplex = SimplicialComplex( simplices.begin(), simplices.end() );
        }
        else
          filteredComplex = C;
      }

      auto uf          = calculateConnectedComponents( filteredComplex );
      auto desiredRoot = *C.at( itPair->first ).begin();
      auto root        = uf.find( desiredRoot ); // Normally, this should be a self-assignment,
                                                 // but in some cases the order of traversal is
                                                 // slightly different, resulting in unexpected
                                                 // roots.

      std::set<VertexType> cliqueVertices;
      std::vector<VertexType> vertices;
      uf.get( root, std::back_inserter( vertices ) );

      for( auto&& vertex : vertices )
      {
        // Notice that the vertex identifier represents the index
        // within the filtration of the _original_ complex, hence
        // I can just access the corresponding simplex that way.
        auto s = K.at( vertex );

        cliqueVertices.insert( s.begin(), s.end() );
      }

      for( auto&& cliqueVertex : cliqueVertices )
      {
        accumulatedPersistenceMap[cliqueVertex] += std::isfinite( itPoint->persistence() ) ? itPoint->persistence() : maxWeight - itPoint->x();
        numberOfCliqueCommunities[cliqueVertex] += 1;
      }

      ++itPoint;
    }

    {
      using namespace aleph::utilities;
      auto outputFilename = formatOutput( "/tmp/" + stem( basename( filename ) ) + "_k", k, maxK );

      std::cerr << "* Storing output in '" << outputFilename << "'...\n";

      pd.removeDiagonal();

      std::transform( pd.begin(), pd.end(), pd.begin(),
                      [&maxWeight] ( const PersistenceDiagram::Point& p )
                      {
                        if( !std::isfinite( p.y() ) )
                          return PersistenceDiagram::Point( p.x(), maxWeight );
                        else
                          return PersistenceDiagram::Point( p );
                      } );

      totalPersistenceValues.push_back( aleph::totalPersistence( pd, 1.0 ) );

      std::ofstream out( outputFilename );
      out << "# Original filename: " << filename << "\n";
      out << "# k                : " << k        << "\n";
      out << pd << "\n";
    }
  }

  {
    using namespace aleph::utilities;
    auto outputFilename = "/tmp/" + stem( basename( filename ) ) + ".txt";

    std::cerr << "* Storing accumulated persistence values in '" << outputFilename << "'...\n";

    std::ofstream out( outputFilename );

    auto normalizationFactor
      = std::accumulate( totalPersistenceValues.begin(), totalPersistenceValues.end(), 0.0 );

    for( auto&& pair : accumulatedPersistenceMap )
      out << pair.first << "\t" << pair.second / normalizationFactor << "\t" << numberOfCliqueCommunities.at(pair.first) <<  ( labels.empty() ? "" : "\t" + labels.at( pair.first ) ) << "\n";
  }
}
<commit_msg>Fiddling with different weights for accumulated vertex persistence<commit_after>#include <algorithm>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <limits>
#include <numeric>
#include <string>
#include <sstream>

#include <cmath>

#include "filtrations/Data.hh"

#include "geometry/RipsExpander.hh"

#include "persistenceDiagrams/Norms.hh"
#include "persistenceDiagrams/PersistenceDiagram.hh"

#include "persistentHomology/ConnectedComponents.hh"

#include "topology/CliqueGraph.hh"
#include "topology/ConnectedComponents.hh"
#include "topology/Simplex.hh"
#include "topology/SimplicialComplex.hh"

#include "topology/io/EdgeLists.hh"
#include "topology/io/GML.hh"
#include "topology/io/Pajek.hh"

#include "utilities/Filesystem.hh"

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

std::string formatOutput( const std::string& prefix, unsigned k, unsigned K )
{
  std::ostringstream stream;
  stream << prefix;
  stream << std::setw( int( std::log10( K ) + 1 ) ) << std::setfill( '0' ) << k;
  stream << ".txt";

  return stream.str();
}

void usage()
{
  std::cerr << "Usage: clique-persistence-diagram FILE K\n"
            << "\n"
            << "Calculates the clique persistence diagram for FILE, which is\n"
            << "supposed to be a weighted graph. The K parameter denotes the\n"
            << "maximum dimension of a simplex for extracting a clique graph\n"
            << "and tracking persistence of clique communities.\n\n";
}

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

  std::string filename = argv[1];
  unsigned maxK        = static_cast<unsigned>( std::stoul( argv[2] ) );

  SimplicialComplex K;

  // Input -------------------------------------------------------------

  std::cerr << "* Reading '" << filename << "'...";

  // Optional map of node labels. If the graph contains node labels and
  // I am able to read them, this map will be filled.
  std::map<VertexType, std::string> labels;

  if( aleph::utilities::extension( filename ) == ".gml" )
  {
    aleph::topology::io::GMLReader reader;
    reader( filename, K );

    auto labelMap = reader.getNodeAttribute( "label" );

    // Note that this assumes that the labels are convertible to
    // numbers.
    //
    // TODO: Solve this generically?
    for( auto&& pair : labelMap )
      if( !pair.second.empty() )
        labels[ static_cast<VertexType>( std::stoul( pair.first ) ) ] = pair.second;

    if( labels.empty() )
      labels.clear();
  }
  else if( aleph::utilities::extension( filename ) == ".net" )
  {
    aleph::topology::io::PajekReader reader;
    reader( filename, K );

    auto labelMap = reader.getLabelMap();

    // Note that this assumes that the labels are convertible to
    // numbers.
    //
    // TODO: Solve this generically?
    for( auto&& pair : labelMap )
      if( !pair.second.empty() )
        labels[ static_cast<VertexType>( std::stoul( pair.first ) ) ] = pair.second;

    if( labels.empty() )
      labels.clear();

  }
  else
  {
    aleph::io::EdgeListReader reader;
    reader.setReadWeights( true );
    reader.setTrimLines( true );

    reader( filename, K );
  }

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

  DataType maxWeight = std::numeric_limits<DataType>::lowest();
  for( auto&& simplex : K )
    maxWeight = std::max( maxWeight, simplex.data() );

  // TODO: Make weight inversion configurable. It is not required for all data
  // sets but should be used on an as-needed basis.

  std::cerr << "* Inverting filtration weights...";

  for( auto it = K.begin(); it != K.end(); ++it )
  {
    if( K.dimension() == 0 )
      continue;

    auto s = *it;
    s.setData( maxWeight - s.data() );

    K.replace( it, s );
  }

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

  // Expansion ---------------------------------------------------------

  std::cerr << "* Expanding simplicial complex to k=" << maxK << "...";

  aleph::geometry::RipsExpander<SimplicialComplex> ripsExpander;
  K = ripsExpander( K, maxK );
  K = ripsExpander.assignMaximumWeight( K );

  std::cerr << "finished\n"
            << "* Expanded simplicial complex has " << K.size() << " simplices\n";

  K.sort( aleph::filtrations::Data<Simplex>() );

  // Stores the accumulated persistence of vertices. Persistence
  // accumulates if a vertex participates in a clique community.
  std::map<VertexType, double> accumulatedPersistenceMap;

  // Stores the number of clique communities a vertex is a part of.
  // I am using this only for debugging the algorithm.
  std::map<VertexType, unsigned> numberOfCliqueCommunities;

  std::vector<double> totalPersistenceValues;
  totalPersistenceValues.reserve( maxK );

  for( unsigned k = 1; k <= maxK; k++ )
  {
    std::cerr << "* Extracting " << k << "-cliques graph...";

    auto C
        = aleph::topology::getCliqueGraph( K, k );

    C.sort( aleph::filtrations::Data<Simplex>() );

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

    std::cerr << "* " << k << "-cliques graph has " << C.size() << " simplices\n";

    if( C.empty() )
    {
      std::cerr << "* Stopping here because no further cliques for processing exist\n";
      break;
    }

    auto&& tuple = aleph::calculateZeroDimensionalPersistenceDiagram( C );
    auto&& pd    = std::get<0>( tuple );
    auto&& pp    = std::get<1>( tuple );

    auto itPoint = pd.begin();
    for( auto itPair = pp.begin(); itPair != pp.end(); ++itPair )
    {
      // Skip zero-dimensional persistence pairs
      if( itPoint->x() == itPoint->y() )
      {
        ++itPoint;
        continue;
      }

      SimplicialComplex filteredComplex;

      {
        std::vector<Simplex> simplices;
        if( itPair->second < C.size() )
        {
          simplices.reserve( itPair->second );

          std::copy( C.begin() + itPair->first, C.begin() + itPair->second, std::back_inserter( simplices ) );
          filteredComplex = SimplicialComplex( simplices.begin(), simplices.end() );
        }
        else
          filteredComplex = C;
      }

      auto uf          = calculateConnectedComponents( filteredComplex );
      auto desiredRoot = *C.at( itPair->first ).begin();
      auto root        = uf.find( desiredRoot ); // Normally, this should be a self-assignment,
                                                 // but in some cases the order of traversal is
                                                 // slightly different, resulting in unexpected
                                                 // roots.

      std::set<VertexType> cliqueVertices;
      std::vector<VertexType> vertices;
      uf.get( root, std::back_inserter( vertices ) );

      for( auto&& vertex : vertices )
      {
        // Notice that the vertex identifier represents the index
        // within the filtration of the _original_ complex, hence
        // I can just access the corresponding simplex that way.
        auto s = K.at( vertex );

        cliqueVertices.insert( s.begin(), s.end() );
      }

      for( auto&& cliqueVertex : cliqueVertices )
      {
        auto persistence = std::isfinite( itPoint->persistence() ) ? std::pow( itPoint->persistence(), 2 ) : std::pow( 2*maxWeight - itPoint->x(), 2 );

        accumulatedPersistenceMap[cliqueVertex] += persistence;
        numberOfCliqueCommunities[cliqueVertex] += 1;
      }

      ++itPoint;
    }

    {
      using namespace aleph::utilities;
      auto outputFilename = formatOutput( "/tmp/" + stem( basename( filename ) ) + "_k", k, maxK );

      std::cerr << "* Storing output in '" << outputFilename << "'...\n";

      pd.removeDiagonal();

      std::transform( pd.begin(), pd.end(), pd.begin(),
                      [&maxWeight] ( const PersistenceDiagram::Point& p )
                      {
                        if( !std::isfinite( p.y() ) )
                          return PersistenceDiagram::Point( p.x(), maxWeight );
                        else
                          return PersistenceDiagram::Point( p );
                      } );

      totalPersistenceValues.push_back( aleph::totalPersistence( pd, 1.0 ) );

      std::ofstream out( outputFilename );
      out << "# Original filename: " << filename << "\n";
      out << "# k                : " << k        << "\n";
      out << pd << "\n";
    }
  }

  {
    using namespace aleph::utilities;
    auto outputFilename = "/tmp/" + stem( basename( filename ) ) + ".txt";

    std::cerr << "* Storing accumulated persistence values in '" << outputFilename << "'...\n";

    std::ofstream out( outputFilename );

    auto normalizationFactor
      = std::accumulate( totalPersistenceValues.begin(), totalPersistenceValues.end(), 0.0 );

    for( auto&& pair : accumulatedPersistenceMap )
      out << pair.first << "\t" << pair.second / normalizationFactor << "\t" << numberOfCliqueCommunities.at(pair.first) <<  ( labels.empty() ? "" : "\t" + labels.at( pair.first ) ) << "\n";
  }
}
<|endoftext|>


<commit_before>// Copyright (c) Wiesław Šoltés. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include "StdAfx.h"
#include "utilities\UnicodeUtf8.h"
#include "utilities\Utf8String.h"
#include "XmlConfigurationBase.h"
#include "XmlConfiguration.h"

XmlConfiguration::XmlConfiguration()
{

}

XmlConfiguration::~XmlConfiguration()
{

}

void XmlConfiguration::GetOptions(tinyxml2::XMLElement *pOptionsElem, COptions &m_Options)
{
    tinyxml2::XMLElement *pOptionElem;

    pOptionElem = pOptionsElem->FirstChildElement("SelectedLanguage");
    if (pOptionElem)
        m_Options.szSelectedLanguage = ToCString(pOptionElem->GetText());

    pOptionElem = pOptionsElem->FirstChildElement("SelectedFormat");
    if (pOptionElem)
        m_Options.nSelectedFormat = ToInt(pOptionElem->GetText());

    pOptionElem = pOptionsElem->FirstChildElement("OutputPath");
    if (pOptionElem)
        m_Options.szOutputPath = ToCString(pOptionElem->GetText());

    pOptionElem = pOptionsElem->FirstChildElement("DeleteSourceFiles");
    if (pOptionElem)
        m_Options.bDeleteSourceFiles = ToBool(pOptionElem->GetText());

    pOptionElem = pOptionsElem->FirstChildElement("RecurseChecked");
    if (pOptionElem)
        m_Options.bRecurseChecked = ToBool(pOptionElem->GetText());

    pOptionElem = pOptionsElem->FirstChildElement("ShutdownWhenFinished");
    if (pOptionElem)
        m_Options.bShutdownWhenFinished = ToBool(pOptionElem->GetText());

    pOptionElem = pOptionsElem->FirstChildElement("DoNotSaveConfiguration");
    if (pOptionElem)
        m_Options.bDoNotSaveConfiguration = ToBool(pOptionElem->GetText());

    pOptionElem = pOptionsElem->FirstChildElement("DeleteOnErrors");
    if (pOptionElem)
        m_Options.bDeleteOnErrors = ToBool(pOptionElem->GetText());

    pOptionElem = pOptionsElem->FirstChildElement("StopOnErrors");
    if (pOptionElem)
        m_Options.bStopOnErrors = ToBool(pOptionElem->GetText());

    pOptionElem = pOptionsElem->FirstChildElement("HideConsoleWindow");
    if (pOptionElem)
        m_Options.bHideConsoleWindow = ToBool(pOptionElem->GetText());

    pOptionElem = pOptionsElem->FirstChildElement("TryToFindDecoder");
    if (pOptionElem)
        m_Options.bTryToFindDecoder = ToBool(pOptionElem->GetText());

    pOptionElem = pOptionsElem->FirstChildElement("EnsureItemIsVisible");
    if (pOptionElem)
        m_Options.bEnsureItemIsVisible = ToBool(pOptionElem->GetText());

    pOptionElem = pOptionsElem->FirstChildElement("ValidateInputFiles");
    if (pOptionElem)
        m_Options.bValidateInputFiles = ToBool(pOptionElem->GetText());

    pOptionElem = pOptionsElem->FirstChildElement("OverwriteExistingFiles");
    if (pOptionElem)
        m_Options.bOverwriteExistingFiles = ToBool(pOptionElem->GetText());

    pOptionElem = pOptionsElem->FirstChildElement("ThreadCount");
    if (pOptionElem)
        m_Options.nThreadCount = ToInt(pOptionElem->GetText());

    pOptionElem = pOptionsElem->FirstChildElement("MainWindowResize");
    if (pOptionElem)
        m_Options.szMainWindowResize = ToCString(pOptionElem->GetText());

    pOptionElem = pOptionsElem->FirstChildElement("FileListColumns");
    if (pOptionElem)
        m_Options.szFileListColumns = ToCString(pOptionElem->GetText());

    pOptionElem = pOptionsElem->FirstChildElement("PresetsDialogResize");
    if (pOptionElem)
        m_Options.szPresetsDialogResize = ToCString(pOptionElem->GetText());

    pOptionElem = pOptionsElem->FirstChildElement("PresetsListColumns");
    if (pOptionElem)
        m_Options.szPresetsListColumns = ToCString(pOptionElem->GetText());

    pOptionElem = pOptionsElem->FirstChildElement("FormatsDialogResize");
    if (pOptionElem)
        m_Options.szFormatsDialogResize = ToCString(pOptionElem->GetText());

    pOptionElem = pOptionsElem->FirstChildElement("FormatsListColumns");
    if (pOptionElem)
        m_Options.szFormatsListColumns = ToCString(pOptionElem->GetText());
}

void XmlConfiguration::SetOptions(tinyxml2::XMLElement *pOptionsElem, COptions &m_Options)
{
    tinyxml2::XMLElement *pOptionElem;

    pOptionElem = this->NewElement("SelectedLanguage");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(m_Options.szSelectedLanguage).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);

    pOptionElem = this->NewElement("SelectedFormat");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(ToCString(m_Options.nSelectedFormat)).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);

    pOptionElem = this->NewElement("OutputPath");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(m_Options.szOutputPath).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);

    pOptionElem = this->NewElement("DeleteSourceFiles");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(ToCString(m_Options.bDeleteSourceFiles)).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);

    pOptionElem = this->NewElement("RecurseChecked");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(ToCString(m_Options.bRecurseChecked)).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);

    pOptionElem = this->NewElement("ShutdownWhenFinished");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(ToCString(m_Options.bShutdownWhenFinished)).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);

    pOptionElem = this->NewElement("DoNotSaveConfiguration");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(ToCString(m_Options.bDoNotSaveConfiguration)).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);

    pOptionElem = this->NewElement("DeleteOnErrors");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(ToCString(m_Options.bDeleteOnErrors)).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);

    pOptionElem = this->NewElement("StopOnErrors");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(ToCString(m_Options.bStopOnErrors)).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);

    pOptionElem = this->NewElement("HideConsoleWindow");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(ToCString(m_Options.bHideConsoleWindow)).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);

    pOptionElem = this->NewElement("TryToFindDecoder");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(ToCString(m_Options.bTryToFindDecoder)).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);

    pOptionElem = this->NewElement("EnsureItemIsVisible");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(ToCString(m_Options.bEnsureItemIsVisible)).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);

    pOptionElem = this->NewElement("ValidateInputFiles");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(ToCString(m_Options.bValidateInputFiles)).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);

    pOptionElem = this->NewElement("OverwriteExistingFiles");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(ToCString(m_Options.bOverwriteExistingFiles)).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);

    pOptionElem = this->NewElement("ThreadCount");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(ToCString(m_Options.nThreadCount)).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);

    pOptionElem = this->NewElement("MainWindowResize");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(m_Options.szMainWindowResize).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);

    pOptionElem = this->NewElement("FileListColumns");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(m_Options.szFileListColumns).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);

    pOptionElem = this->NewElement("PresetsDialogResize");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(m_Options.szPresetsDialogResize).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);

    pOptionElem = this->NewElement("PresetsListColumns");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(m_Options.szPresetsListColumns).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);

    pOptionElem = this->NewElement("FormatsDialogResize");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(m_Options.szFormatsDialogResize).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);

    pOptionElem = this->NewElement("FormatsListColumns");
    pOptionElem->LinkEndChild(this->NewText(CUtf8String(m_Options.szFormatsListColumns).m_Result));
    pOptionsElem->LinkEndChild(pOptionElem);
}

void XmlConfiguration::GetPresets(tinyxml2::XMLElement *pPresetsElem, CPresetsList &m_Presets)
{
    tinyxml2::XMLElement *pPresetElem = pPresetsElem->FirstChildElement("Preset");
    for (pPresetElem; pPresetElem; pPresetElem = pPresetElem->NextSiblingElement())
    {
        const char *pszName = pPresetElem->Attribute("name");
        const char *pszOptions = pPresetElem->Attribute("options");
        if (pszName != NULL && pszOptions != NULL)
        {
            CPreset preset;
            preset.szName = ToCString(pszName);
            preset.szOptions = ToCString(pszOptions);
            m_Presets.Insert(preset);
        }
    }
}

void XmlConfiguration::SetPresets(tinyxml2::XMLElement *pPresetsElem, CPresetsList &m_Presets)
{
    tinyxml2::XMLElement *pPresetElem;

    int nPresets = m_Presets.Count();
    for (int i = 0; i < nPresets; i++)
    {
        CPreset& preset = m_Presets.Get(i);
        pPresetElem = this->NewElement("Preset");
        pPresetElem->SetAttribute("name", CUtf8String(preset.szName).m_Result);
        pPresetElem->SetAttribute("options", CUtf8String(preset.szOptions).m_Result);
        pPresetsElem->LinkEndChild(pPresetElem);
    }
}

void XmlConfiguration::GetFormat(tinyxml2::XMLElement *pFormatElem, CFormat &m_Format)
{
    const char *pszId = pFormatElem->Attribute("id");
    if (pszId != NULL)
        m_Format.szId = ToCString(pszId);

    const char *pszName = pFormatElem->Attribute("name");
    if (pszName != NULL)
        m_Format.szName = ToCString(pszName);

    const char *pszTemplate = pFormatElem->Attribute("template");
    if (pszTemplate != NULL)
        m_Format.szTemplate = ToCString(pszTemplate);

    const char *pszPipesInput = pFormatElem->Attribute("input");
    if (pszPipesInput != NULL)
        m_Format.bPipeInput = ToBool(pszPipesInput);

    const char *pszPipesOutput = pFormatElem->Attribute("output");
    if (pszPipesOutput != NULL)
        m_Format.bPipeOutput = ToBool(pszPipesOutput);

    const char *pszFunction = pFormatElem->Attribute("function");
    if (pszFunction != NULL)
        m_Format.szFunction = ToCString(pszFunction);

    const char *pszPath = pFormatElem->Attribute("path");
    if (pszPath != NULL)
        m_Format.szPath = ToCString(pszPath);

    const char *pszExitCodeSuccess = pFormatElem->Attribute("success");
    if (pszExitCodeSuccess != NULL)
        m_Format.nExitCodeSuccess = ToInt(pszExitCodeSuccess);

    const char *pszType = pFormatElem->Attribute("type");
    if (pszType != NULL)
        m_Format.nType = ToInt(pszType);

    const char *pszFormats = pFormatElem->Attribute("formats");
    if (pszFormats != NULL)
        m_Format.szInputExtensions = ToCString(pszFormats);

    const char *pszExtension = pFormatElem->Attribute("extension");
    if (pszExtension != NULL)
        m_Format.szOutputExtension = ToCString(pszExtension);

    const char *pszDefaultPreset = pFormatElem->Attribute("default");
    if (pszDefaultPreset != NULL)
        m_Format.nDefaultPreset = ToInt(pszDefaultPreset);

    tinyxml2::XMLElement *pPresetsElem = pFormatElem->FirstChildElement("Presets");
    this->GetPresets(pPresetsElem, m_Format.m_Presets);
}

void XmlConfiguration::SetFormat(tinyxml2::XMLElement *pFormatElem, CFormat &m_Format)
{
    pFormatElem->SetAttribute("id", CUtf8String(m_Format.szId).m_Result);
    pFormatElem->SetAttribute("name", CUtf8String(m_Format.szName).m_Result);
    pFormatElem->SetAttribute("template", CUtf8String(m_Format.szTemplate).m_Result);
    pFormatElem->SetAttribute("input", CUtf8String(ToCString(m_Format.bPipeInput)).m_Result);
    pFormatElem->SetAttribute("output", CUtf8String(ToCString(m_Format.bPipeOutput)).m_Result);
    pFormatElem->SetAttribute("function", CUtf8String(m_Format.szFunction).m_Result);
    pFormatElem->SetAttribute("path", CUtf8String(m_Format.szPath).m_Result);
    pFormatElem->SetAttribute("success", CUtf8String(ToCString(m_Format.nExitCodeSuccess)).m_Result);
    pFormatElem->SetAttribute("type", CUtf8String(ToCString(m_Format.nType)).m_Result);
    pFormatElem->SetAttribute("formats", CUtf8String(m_Format.szInputExtensions).m_Result);
    pFormatElem->SetAttribute("extension", CUtf8String(m_Format.szOutputExtension).m_Result);
    pFormatElem->SetAttribute("default", CUtf8String(ToCString(m_Format.nDefaultPreset)).m_Result);

    tinyxml2::XMLElement *pPresetsElem = this->NewElement("Presets");
    pFormatElem->LinkEndChild(pPresetsElem);
    this->SetPresets(pPresetsElem, m_Format.m_Presets);
}

void XmlConfiguration::GetFormats(tinyxml2::XMLElement *pFormatsElem, CFormatsList &m_Formats)
{
    tinyxml2::XMLElement *pFormatElem = pFormatsElem->FirstChildElement("Format");
    for (pFormatElem; pFormatElem; pFormatElem = pFormatElem->NextSiblingElement())
    {
        CFormat format;
        this->GetFormat(pFormatElem, format);
        m_Formats.Insert(format);
    }
}

void XmlConfiguration::SetFormats(tinyxml2::XMLElement *pFormatsElem, CFormatsList &m_Formats)
{
    int nFormats = m_Formats.Count();
    for (int i = 0; i < nFormats; i++)
    {
        CFormat& format = m_Formats.Get(i);
        tinyxml2::XMLElement *pFormatElem = this->NewElement("Format");
        this->SetFormat(pFormatElem, format);
        pFormatsElem->LinkEndChild(pFormatElem);
    }
}

void XmlConfiguration::GetItems(tinyxml2::XMLElement *pItemsElem, CItemsList &m_Items)
{
    tinyxml2::XMLElement *pItemElem = pItemsElem->FirstChildElement("Item");
    for (pItemElem; pItemElem; pItemElem = pItemElem->NextSiblingElement())
    {
        CItem item;

        const char *pszId = pItemElem->Attribute("id");
        if (pszId != NULL)
            item.nId = _tstoi(ToCString(pszId));

        const char *pszPath = pItemElem->Attribute("path");
        if (pszPath != NULL)
            item.szPath = ToCString(pszPath);

        const char *pszSize = pItemElem->Attribute("size");
        if (pszSize != NULL)
            item.szSize = ToCString(pszSize);

        const char *pszName = pItemElem->Attribute("name");
        if (pszName != NULL)
            item.szName = ToCString(pszName);

        const char *pszExtension = pItemElem->Attribute("extension");
        if (pszExtension != NULL)
            item.szExtension = ToCString(pszExtension);

        const char *pszFormatId = pItemElem->Attribute("format");
        if (pszFormatId != NULL)
            item.szFormatId = ToCString(pszFormatId);

        const char *pszPreset = pItemElem->Attribute("preset");
        if (pszPreset != NULL)
            item.nPreset = ToInt(pszPreset);

        const char *pszChecked = pItemElem->Attribute("checked");
        if (pszChecked != NULL)
            item.bChecked = ToBool(pszChecked);

        const char *pszTime = pItemElem->Attribute("time");
        if (pszTime != NULL)
            item.szTime = ToCString(pszTime);

        const char *pszStatus = pItemElem->Attribute("status");
        if (pszStatus != NULL)
            item.szStatus = ToCString(pszStatus);

        m_Items.Insert(item);
    }
}

void XmlConfiguration::SetItems(tinyxml2::XMLElement *pItemsElem, CItemsList &m_Items)
{
    tinyxml2::XMLElement *pItemElem;
    int nItems = m_Items.Count();
    for (int i = 0; i < nItems; i++)
    {
        CItem& item = m_Items.Get(i);
        pItemElem = this->NewElement("Item");
        pItemElem->SetAttribute("id", CUtf8String(ToCString(i)).m_Result);
        pItemElem->SetAttribute("path", CUtf8String(item.szPath).m_Result);
        pItemElem->SetAttribute("size", CUtf8String(item.szSize).m_Result);
        pItemElem->SetAttribute("name", CUtf8String(item.szName).m_Result);
        pItemElem->SetAttribute("extension", CUtf8String(item.szExtension).m_Result);
        pItemElem->SetAttribute("format", CUtf8String(item.szFormatId).m_Result);
        pItemElem->SetAttribute("preset", CUtf8String(ToCString(item.nPreset)).m_Result);
        pItemElem->SetAttribute("checked", CUtf8String(ToCString(item.bChecked)).m_Result);
        pItemElem->SetAttribute("time", CUtf8String(item.szTime).m_Result);
        pItemElem->SetAttribute("status", CUtf8String(item.szStatus).m_Result);
        pItemsElem->LinkEndChild(pItemElem);
    }
}

void XmlConfiguration::GetLanguage(tinyxml2::XMLElement *pLanguageElem, CLanguage &m_Language)
{
    const char *pszId = pLanguageElem->Attribute("id");
    if (pszId != NULL)
        m_Language.szId = ToCString(pszId);

    const char *pszOriginal = pLanguageElem->Attribute("original");
    if (pszOriginal != NULL)
        m_Language.szOriginalName = ToCString(pszOriginal);

    const char *pszTranslated = pLanguageElem->Attribute("translated");
    if (pszTranslated != NULL)
        m_Language.szTranslatedName = ToCString(pszTranslated);

    tinyxml2::XMLElement *pStringElem = pLanguageElem->FirstChildElement("String");
    for (pStringElem; pStringElem; pStringElem = pStringElem->NextSiblingElement())
    {
        const char *pszKey = pStringElem->Attribute("key");
        const char *pszValue = pStringElem->Attribute("value");
        if (pszKey != NULL && pszValue != NULL)
        {
            int nKey;
            CString szValue;
            _stscanf(ToCString(pszKey), _T("%x"), &nKey);
            szValue = ToCString(pszValue);
            m_Language.m_Strings.Insert(nKey, szValue);
        }
    }
}

void XmlConfiguration::SetLanguage(tinyxml2::XMLElement *pLanguageElem, CLanguage &m_Language)
{
    pLanguageElem->SetAttribute("id", CUtf8String(m_Language.szId).m_Result);
    pLanguageElem->SetAttribute("original", CUtf8String(m_Language.szOriginalName).m_Result);
    pLanguageElem->SetAttribute("translated", CUtf8String(m_Language.szTranslatedName).m_Result);

    tinyxml2::XMLElement *pStringElem;
    POSITION pos = m_Language.m_Strings.m_Map.GetStartPosition();
    while (pos != NULL)
    {
        CString rValue;
        CString szKey;
        int nKey;
        m_Language.m_Strings.m_Map.GetNextAssoc(pos, nKey, rValue);
        szKey.Format(_T("%X"), nKey);
        pStringElem = this->NewElement("String");
        pStringElem->SetAttribute("key", CUtf8String(szKey).m_Result);
        pStringElem->SetAttribute("value", CUtf8String(rValue).m_Result);
        pLanguageElem->LinkEndChild(pStringElem);
    }
}

void XmlConfiguration::GetLanguages(tinyxml2::XMLElement *pLanguagesElem, CLanguagesList &m_Languages)
{
    tinyxml2::XMLElement *pLanguageElem = pLanguagesElem->FirstChildElement("Language");
    for (pLanguageElem; pLanguageElem; pLanguageElem = pLanguageElem->NextSiblingElement())
    {
        CLanguage language;
        this->GetLanguage(pLanguageElem, language);
        m_Languages.Insert(language);
    }
}

void XmlConfiguration::SetLanguages(tinyxml2::XMLElement *pLanguagesElem, CLanguagesList &m_Languages)
{
    int nLanguages = m_Languages.Count();
    for (int i = 0; i < nLanguages; i++)
    {
        CLanguage& language = m_Languages.Get(i);
        tinyxml2::XMLElement *pLanguageElem = this->NewElement("Language");
        this->SetLanguage(pLanguageElem, language);
        pLanguagesElem->LinkEndChild(pLanguageElem);
    }
}

void XmlConfiguration::GetOptions(COptions &m_Options)
{
    tinyxml2::XMLElement *pOptionsElem = this->FirstChildElement("Options");
    if (pOptionsElem != NULL)
        this->GetOptions(pOptionsElem, m_Options);
}

void XmlConfiguration::SetOptions(COptions &m_Options)
{
    tinyxml2::XMLDeclaration* decl = this->NewDeclaration(m_Utf8DocumentDeclaration);
    this->LinkEndChild(decl);

    tinyxml2::XMLElement *pOptionsElem = this->NewElement("Options");
    this->LinkEndChild(pOptionsElem);

    this->SetOptions(pOptionsElem, m_Options);
}

void XmlConfiguration::GetPresets(CPresetsList &m_Presets)
{
    tinyxml2::XMLElement *pPresetsElem = this->FirstChildElement("Presets");
    if (pPresetsElem != NULL)
        this->GetPresets(pPresetsElem, m_Presets);
}

void XmlConfiguration::SetPresets(CPresetsList &m_Presets)
{
    tinyxml2::XMLDeclaration* decl = this->NewDeclaration(m_Utf8DocumentDeclaration);
    this->LinkEndChild(decl);

    tinyxml2::XMLElement *pPresetsElem = this->NewElement("Presets");
    this->LinkEndChild(pPresetsElem);

    this->SetPresets(pPresetsElem, m_Presets);
}

void XmlConfiguration::GetFormat(CFormat &m_Format)
{
    tinyxml2::XMLElement *pFormatElem = this->FirstChildElement("Format");
    if (pFormatElem != NULL)
        this->GetFormat(pFormatElem, m_Format);
}

void XmlConfiguration::SetFormat(CFormat &m_Format)
{
    tinyxml2::XMLDeclaration* decl = this->NewDeclaration(m_Utf8DocumentDeclaration);
    this->LinkEndChild(decl);

    tinyxml2::XMLElement *pFormatElem = this->NewElement("Format");
    this->LinkEndChild(pFormatElem);

    this->SetFormat(pFormatElem, m_Format);
}

void XmlConfiguration::GetFormats(CFormatsList &m_Formats)
{
    tinyxml2::XMLElement *pFormatsElem = this->FirstChildElement("Formats");
    if (pFormatsElem != NULL)
        this->GetFormats(pFormatsElem, m_Formats);
}

void XmlConfiguration::SetFormats(CFormatsList &m_Formats)
{
    tinyxml2::XMLDeclaration* decl = this->NewDeclaration(m_Utf8DocumentDeclaration);
    this->LinkEndChild(decl);

    tinyxml2::XMLElement *pFormatsElem = this->NewElement("Formats");
    this->LinkEndChild(pFormatsElem);

    this->SetFormats(pFormatsElem, m_Formats);
}

void XmlConfiguration::GetItems(CItemsList &m_Items)
{
    tinyxml2::XMLElement *pItemsElem = this->FirstChildElement("Items");
    if (pItemsElem != NULL)
        this->GetItems(pItemsElem, m_Items);
}

void XmlConfiguration::SetItems(CItemsList &m_Items)
{
    tinyxml2::XMLDeclaration* decl = this->NewDeclaration(m_Utf8DocumentDeclaration);
    this->LinkEndChild(decl);

    tinyxml2::XMLElement *pItemsElem = this->NewElement("Items");
    this->LinkEndChild(pItemsElem);

    this->SetItems(pItemsElem, m_Items);
}

void XmlConfiguration::GetLanguage(CLanguage &m_Language)
{
    tinyxml2::XMLElement *pLanguageElem = this->FirstChildElement("Language");
    if (pLanguageElem != NULL)
        this->GetLanguage(pLanguageElem, m_Language);
}

void XmlConfiguration::SetLanguage(CLanguage &m_Language)
{
    tinyxml2::XMLDeclaration* decl = this->NewDeclaration(m_Utf8DocumentDeclaration);
    this->LinkEndChild(decl);

    tinyxml2::XMLElement *pLanguageElem = this->NewElement("Language");
    this->LinkEndChild(pLanguageElem);

    this->SetLanguage(pLanguageElem, m_Language);
}

void XmlConfiguration::GetLanguages(CLanguagesList &m_Languages)
{
    tinyxml2::XMLElement *pLanguagesElem = this->FirstChildElement("Languages");
    if (pLanguagesElem != NULL)
        this->GetLanguages(pLanguagesElem, m_Languages);
}

void XmlConfiguration::SetLanguages(CLanguagesList &m_Languages)
{
    tinyxml2::XMLDeclaration* decl = this->NewDeclaration(m_Utf8DocumentDeclaration);
    this->LinkEndChild(decl);

    tinyxml2::XMLElement *pLanguagesElem = this->NewElement("Languages");
    this->LinkEndChild(pLanguagesElem);

    this->SetLanguages(pLanguagesElem, m_Languages);
}
<commit_msg>Delete XmlConfiguration.cpp<commit_after><|endoftext|>


<commit_before>#include <cstddef>
#include <queue>
#include <utility>
#include <vector>

#include "aim.hpp"

// Algorithm to be tested
// Test based on BFS which is not a right idea at all for this kind of problem

using Location = std::pair<std::size_t, std::size_t>;

bool is_local_min(std::vector<std::vector<int>> const& matrix, std::size_t i, std::size_t j)
{
  const auto H = matrix.size();
  const auto W = matrix[0].size();
  const int& current = matrix[j][i];
  return (i == 0 || current <= matrix[j][i-1])
      && (j == 0 || current <= matrix[j-1][i])
      && (i == W-1 || current <= matrix[j][i+1])
      && (j == H-1 || current <= matrix[j][i+1]);
}

bool is_better(std::vector<std::vector<int>> const& matrix, std::size_t nx, std::size_t ny, std::size_t x, std::size_t y)
{
  const auto H = matrix.size();
  const auto W = matrix[0].size();
  return (nx < W && ny < H && matrix[y][x] < matrix[ny][nx]);
}

std::size_t longest_incr(std::vector<std::vector<int>> const& matrix)
{
  const auto H = matrix.size();
  const auto W = matrix[0].size();

  std::size_t remain_at_depth = 0;
  std::size_t next_depth = 0;
  std::size_t longest = 0;
  std::queue<Location> locations;

  // Push initial starting point
  // It is possible to take every point of the matrix
  // as starting locations
  // An optimized approch consist in starting by local minima
  for (std::size_t j {} ; j != H ; ++j)
  {
    for (std::size_t i {} ; i != W ; ++i)
    {
      if (is_local_min(matrix, i, j))
      {
        ++next_depth;
        locations.emplace(i, j);
      }
    }
  }

  while (! locations.empty())
  {
    if (! remain_at_depth)
    {
      remain_at_depth = next_depth;
      next_depth = 0;
      ++longest;
    }
    auto x = locations.front().first;
    auto y = locations.front().second;
    locations.pop();
    --remain_at_depth;

    // push possible paths from this point
    if (is_better(matrix, x-1, y, x, y))
    {
      ++next_depth;
      locations.emplace(x-1, y);
    }
    if (is_better(matrix, x+1, y, x, y))
    {
      ++next_depth;
      locations.emplace(x+1, y);
    }
    if (is_better(matrix, x, y-1, x, y))
    {
      ++next_depth;
      locations.emplace(x, y-1);
    }
    if (is_better(matrix, x, y+1, x, y))
    {
      ++next_depth;
      locations.emplace(x, y+1);
    }
  }

  return longest;
}

<commit_msg>[longest-incrpath-matrix] Fix typos<commit_after>#include <cstddef>
#include <queue>
#include <utility>
#include <vector>

#include "aim.hpp"

// Algorithm to be tested
// Test based on BFS which is not a right idea at all for this kind of problem

using Location = std::pair<std::size_t, std::size_t>;

bool is_local_min(std::vector<std::vector<int>> const& matrix, std::size_t i, std::size_t j)
{
  const auto H = matrix.size();
  const auto W = matrix[0].size();
  const int& current = matrix[j][i];
  return (i == 0 || current <= matrix[j][i-1])
      && (j == 0 || current <= matrix[j-1][i])
      && (i == W-1 || current <= matrix[j][i+1])
      && (j == H-1 || current <= matrix[j+1][i]);
}

bool is_better(std::vector<std::vector<int>> const& matrix, std::size_t nx, std::size_t ny, std::size_t x, std::size_t y)
{
  const auto H = matrix.size();
  const auto W = matrix[0].size();
  return (nx < W && ny < H && matrix[y][x] < matrix[ny][nx]);
}

std::size_t longest_incr(std::vector<std::vector<int>> const& matrix)
{
  const auto H = matrix.size();
  const auto W = matrix[0].size();

  std::size_t remain_at_depth = 0;
  std::size_t next_depth = 0;
  std::size_t longest = 0;
  std::queue<Location> locations;

  // Push initial starting point
  // It is possible to take every point of the matrix
  // as starting locations
  // An optimized approch consist in starting by local minima
  for (std::size_t j {} ; j != H ; ++j)
  {
    for (std::size_t i {} ; i != W ; ++i)
    {
      if (is_local_min(matrix, i, j))
      {
        ++next_depth;
        locations.emplace(i, j);
      }
    }
  }

  while (! locations.empty())
  {
    if (! remain_at_depth)
    {
      remain_at_depth = next_depth;
      next_depth = 0;
      ++longest;
    }
    auto x = locations.front().first;
    auto y = locations.front().second;
    locations.pop();
    --remain_at_depth;

    // push possible paths from this point
    if (is_better(matrix, x-1, y, x, y))
    {
      ++next_depth;
      locations.emplace(x-1, y);
    }
    if (is_better(matrix, x+1, y, x, y))
    {
      ++next_depth;
      locations.emplace(x+1, y);
    }
    if (is_better(matrix, x, y-1, x, y))
    {
      ++next_depth;
      locations.emplace(x, y-1);
    }
    if (is_better(matrix, x, y+1, x, y))
    {
      ++next_depth;
      locations.emplace(x, y+1);
    }
  }

  return longest;
}

<|endoftext|>


<commit_before>#include "hash.h"
#include <vector>
// #include <cout>
#include <iostream>
#include <emmintrin.h>

int main(int** args) {
    Hash* hash = new Hash();
    int a[4] = {1, 67, 800, 1212123};

    std::vector<uint32_t> foo = {1, 67, 800, 1212123};
    // __m128i foo_SSE = _mm_setzero_si128();
    __m128i foo_SSE = _mm_load_epi32(a);

    __m128i seed_SSE = _mm_set_epi32(1, 1, 1, 1);
    __m128i foo_result_SSE = hash->hash_SSE(foo_SSE, seed_SSE);

    for(size_t i = 0; i < 4; ++i) {
        std::cout << "\n\nNumber " << i << ": \t" << foo[i] << std::endl;
        std::cout << "NumberSSE " << i << ": \t" << foo_SSE[i] << std::endl;

        // std::cout << "\n\nTraditional: " << hash->hash(foo[i], 1, MAX_VALUE) << std::endl;
        // std::cout << "SSE: " << foo_result_SSE[i] % MAX_VALUE << std::endl;
    }

    delete hash;
}<commit_msg>playing around<commit_after>#include "hash.h"
#include <vector>
// #include <cout>
#include <iostream>
#include <emmintrin.h>

int main(int** args) {
    Hash* hash = new Hash();
    int a[4] = {1, 67, 800, 1212123};

    std::vector<uint32_t> foo = {1, 67, 800, 1212123};
    // __m128i foo_SSE = _mm_setzero_si128();
    __m128i foo_SSE = _mm_setr_epi32(1, 67, 800, 1212123);

    __m128i seed_SSE = _mm_set_epi32(2, 2, 2, 2);
    __m128i foo_result_SSE = hash->hash_SSE(foo_SSE, seed_SSE);
    // std::cout << "Size: " << foo_SSE->size() << std::endl;
    for(size_t i = 0; i < 4; ++i) {
        // std::cout << "\n\nNumber " << i << ": \t" << foo[i] << std::endl;

        std::cout << "Traditional: " << hash->hash(foo[i], 2, MAX_VALUE) << std::endl;
        // std::cout << "SSE: " << foo_result_SSE[i] % MAX_VALUE << std::endl;
    }
        std::cout << "\n\nNumberSSE " << 0 << ": \t" << _mm_extract_epi32(foo_result_SSE, 0) << std::endl;
        std::cout << "NumberSSE " << 1 << ": \t" << _mm_extract_epi32(foo_result_SSE, 1) << std::endl;
        std::cout << "NumberSSE " << 2 << ": \t" << _mm_extract_epi32(foo_result_SSE, 2) << std::endl;
        std::cout << "NumberSSE " << 3 << ": \t" << _mm_extract_epi32(foo_result_SSE, 3) << std::endl;

    delete hash;
}<|endoftext|>


<commit_before>// Copyright (c) 2022 by Apex.AI Inc. All rights reserved.
//
// 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.
//
// SPDX-License-Identifier: Apache-2.0

#include "iceoryx_posh/popo/publisher.hpp"

#include "iceoryx_hoofs/cxx/unique_ptr.hpp"
#include "iceoryx_posh/internal/popo/smart_chunk.hpp"
#include "iceoryx_posh/popo/publisher.hpp"
#include "iceoryx_posh/popo/request.hpp"
#include "iceoryx_posh/popo/response.hpp"
#include "iceoryx_posh/popo/sample.hpp"
#include "iceoryx_posh/testing/mocks/chunk_mock.hpp"

#include "test.hpp"

namespace
{
using namespace ::testing;
using ::testing::_;

struct DummyData
{
    DummyData() = default;
    uint32_t val = 42;
};
struct DummyHeader
{
    DummyHeader() = default;
    uint64_t counter = 0;
};

template <template <typename, typename> class BaseType, typename T, typename H = iox::mepoo::NoUserHeader>
class MockInterface : public BaseType<T, H>
{
  public:
    using SampleType = iox::popo::Sample<T, H>;

    void publish(iox::popo::Sample<T, H>&& sample) noexcept override
    {
        auto s = std::move(sample); // this step is necessary since the mock method doesn't execute the move
        return publishMock(std::move(s));
    }
    MOCK_METHOD(void, publishMock, ((iox::popo::Sample<T, H> &&)), (noexcept));
};

template <typename T, typename H = iox::mepoo::NoUserHeader>
using MockPublisherInterface = MockInterface<iox::popo::PublisherInterface, T, H>;

template <typename T>
class SmartChunkTest : public Test
{
  public:
    using DataType = typename T::DataType;
    using HeaderType = typename T::HeaderType;
    template <typename Data, typename Header>
    using SutType = typename T::template SutType<Data, Header>;
    using InterfaceType = typename T::InterfaceType;

    template <typename SutType>
    void send(SutType& sut)
    {
        T::send(sut);
    }

    template <typename SutType>
    HeaderType& getHeader(SutType& sut)
    {
        return T::getHeader(sut);
    }

    template <typename SutType>
    const HeaderType& getConstHeader(const SutType& sut)
    {
        return T::getHeader(sut);
    }

    template <typename T1>
    const T1& makeConst(T1& t)
    {
        return const_cast<const T1&>(t);
    }

    template <typename T1>
    void verifyNotEmpty(T1& sut)
    {
        ASSERT_TRUE(sut);
        ASSERT_THAT(sut.get(), Ne(nullptr));
        ASSERT_THAT(sut.operator->(), Ne(nullptr));
        ASSERT_THAT(makeConst(sut).get(), Ne(nullptr));
        ASSERT_THAT(makeConst(sut).operator->(), Ne(nullptr));
        ASSERT_THAT(sut.getChunkHeader(), Ne(nullptr));
        ASSERT_THAT(makeConst(sut).getChunkHeader(), Ne(nullptr));
    }

    template <typename T1>
    void verifyContent(T1& helper, const uint32_t dataValue, const uint64_t headerValue)
    {
        verifyNotEmpty(helper.sut);

        EXPECT_THAT(helper.sut.get()->val, Eq(dataValue));
        EXPECT_THAT(makeConst(helper.sut).get()->val, Eq(dataValue));
        EXPECT_THAT(helper.sut->val, Eq(dataValue));
        EXPECT_THAT(makeConst(helper.sut)->val, Eq(dataValue));
        EXPECT_THAT((*helper.sut).val, Eq(dataValue));
        EXPECT_THAT((*makeConst(helper.sut)).val, Eq(dataValue));

        EXPECT_THAT(getHeader(helper.sut).counter, Eq(headerValue));
        EXPECT_THAT(getConstHeader(helper.sut).counter, Eq(headerValue));
    }

    template <typename T1>
    void verifyEmpty(T1& helper)
    {
        EXPECT_FALSE(helper.sut);
        EXPECT_THAT(helper.sut.get(), Eq(nullptr));
        EXPECT_THAT(helper.sut.operator->(), Eq(nullptr));
        EXPECT_THAT(makeConst(helper.sut).get(), Eq(nullptr));
        EXPECT_THAT(makeConst(helper.sut).operator->(), Eq(nullptr));
        EXPECT_THAT(helper.sut.getChunkHeader(), Eq(nullptr));
        EXPECT_THAT(makeConst(helper.sut).getChunkHeader(), Eq(nullptr));
    }

    template <typename T1>
    void setUnderlyingData(const T1& sut, const uint32_t dataValue, const uint64_t headerValue)
    {
        const_cast<uint32_t&>(sut.chunk.sample()->val) = dataValue;
        const_cast<uint64_t&>(sut.chunk.userHeader()->counter) = headerValue;
    }

  protected:
    InterfaceType mockInterface{};

    template <typename Data, typename Header>
    struct SutHelper
    {
        SutHelper()
            : sut{iox::cxx::unique_ptr<Data>(this->chunk.sample(), [](Data*) {})}
        {
        }

        SutHelper(InterfaceType& interface)
            : sut{iox::cxx::unique_ptr<Data>(this->chunk.sample(), [](Data*) {}), interface}
        {
        }

        ChunkMock<Data, Header> chunk;
        SutType<Data, Header> sut;
    };

    using ProducerHelper = SutHelper<DataType, HeaderType>;
    using ConsumerHelper = SutHelper<const DataType, const HeaderType>;

    ProducerHelper producer{this->mockInterface};
    ConsumerHelper consumer;
};

struct SampleTestCase
{
    using DataType = DummyData;
    using HeaderType = DummyHeader;
    using InterfaceType = MockInterface<iox::popo::PublisherInterface, DummyData, HeaderType>;

    template <typename Data, typename Header>
    using SutType = iox::popo::Sample<Data, Header>;

    template <typename SutType>
    static void send(SutType& sut)
    {
        sut.publish();
    }

    template <typename SutType>
    static HeaderType& getHeader(SutType& sut)
    {
        return sut.getUserHeader();
    }

    template <typename SutType>
    static const HeaderType& getHeader(const SutType& sut)
    {
        return sut.getUserHeader();
    }
};

using Implementations = Types<SampleTestCase>;

TYPED_TEST_SUITE(SmartChunkTest, Implementations);

TYPED_TEST(SmartChunkTest, ProducerConstructedSmartChunkIsValid)
{
    this->setUnderlyingData(this->producer, 123, 456);

    this->verifyContent(this->producer, 123, 456);
}

TYPED_TEST(SmartChunkTest, ConsumerConstructedSmartChunkIsValid)
{
    this->setUnderlyingData(this->consumer, 789, 1337);

    this->verifyNotEmpty(this->consumer.sut);
}

#if 0
TYPED_TEST(SmartChunkTest, ProducerSmartChunkIsInvalidatedAfterMoveConstruction)
{
    this->producer.sut->val = 1337;
    this->getHeader(this->producer.sut).counter = 73;

    auto moved{std::move(this->producer.sut)};

    verifyContent(moved, 1337, 73);

    verifyEmpty(this->producer.sut);
}

TYPED_TEST(SmartChunkTest, ConsumerSmartChunkIsInvalidatedAfterMoveConstruction)
{
    auto moved{std::move(this->consumer.sut)};

    verifyNotEmpty(moved);

    verifyEmpty(this->consumer.sut);
}

TYPED_TEST(SmartChunkTest, ProducerSmartChunkIsInvalidatedAfterMoveAssignment)
{
    typename TestFixture::ProducerHelper destination(this->mockInterface);
    this->producer.sut->val = 81921;
    this->getHeader(this->producer.sut).counter = 55551;

    destination.sut = std::move(this->producer.sut);

    EXPECT_TRUE(destination.sut);
    ASSERT_THAT(destination.sut.get(), Ne(nullptr));
    EXPECT_THAT(destination.sut.get()->val, Eq(81921));
    EXPECT_THAT(this->getHeader(destination.sut).counter, Eq(55551));

    verifyEmpty(this->producer.sut);
}

TYPED_TEST(SmartChunkTest, ConsumerSmartChunkIsInvalidatedAfterMoveAssignment)
{
    typename TestFixture::ConsumerHelper destination;
    destination.sut = std::move(this->consumer.sut);

    EXPECT_TRUE(destination.sut);

    verifyEmpty(this->consumer.sut);
}

TYPED_TEST(SmartChunkTest, PublishesSmartChunkViaPublisherInterfaceWorks)
{
    ::testing::Test::RecordProperty("TEST_ID", "0b13578c-d654-4802-80a4-f45e5fd73268");

    this->sut.emplace(std::move(this->smartChunkPtr), this->mockInterface);

    EXPECT_CALL(this->mockInterface, publishMock).Times(1);

    this->send();
}

TYPED_TEST(SmartChunkTest, PublishingEmptySmartChunkCallsErrorHandler)
{
    ::testing::Test::RecordProperty("TEST_ID", "b49bdcb3-6f8a-42c1-bb6c-a745f1a49b0e");
    this->sut.emplace(std::move(this->smartChunkPtr), this->mockInterface);

    EXPECT_CALL(this->mockInterface, publishMock).Times(1);
    this->send();

    iox::cxx::optional<iox::Error> detectedError;
    auto errorHandlerGuard = iox::ErrorHandler::setTemporaryErrorHandler(
        [&detectedError](const iox::Error error, const std::function<void()>&, const iox::ErrorLevel errorLevel) {
            detectedError.emplace(error);
            EXPECT_THAT(errorLevel, Eq(iox::ErrorLevel::MODERATE));
        });
    this->send();

    ASSERT_TRUE(detectedError.has_value());
    ASSERT_THAT(detectedError.value(), Eq(iox::Error::kPOSH__PUBLISHING_EMPTY_SAMPLE));
}

TYPED_TEST(SmartChunkTest, CallingGetUserHeaderFromNonConstTypeReturnsCorrectAddress)
{
    ::testing::Test::RecordProperty("TEST_ID", "d26dd24c-0c84-4c3d-96ab-bf51e52c9e9f");
    this->sut.emplace(std::move(this->smartChunkPtr), this->mockInterface);

    auto& header = this->getHeader();

    ASSERT_EQ(&header, this->chunk.userHeader());
}

TYPED_TEST(SmartChunkTest, CallingGetUserHeaderFromConstTypeReturnsCorrectAddress)
{
    ::testing::Test::RecordProperty("TEST_ID", "fb6b6706-7a15-4ae2-a77a-d4b21431ca57");

    this->sut.emplace(std::move(this->smartChunkPtr), this->mockInterface);

    const auto& header = this->getConstHeader();

    ASSERT_EQ(&header, this->chunk.userHeader());
}
#endif
} // namespace
<commit_msg>iox-#27 Finalize smart chunk tests<commit_after>// Copyright (c) 2022 by Apex.AI Inc. All rights reserved.
//
// 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.
//
// SPDX-License-Identifier: Apache-2.0

#include "iceoryx_posh/popo/publisher.hpp"

#include "iceoryx_hoofs/cxx/unique_ptr.hpp"
#include "iceoryx_posh/internal/popo/smart_chunk.hpp"
#include "iceoryx_posh/popo/publisher.hpp"
#include "iceoryx_posh/popo/request.hpp"
#include "iceoryx_posh/popo/response.hpp"
#include "iceoryx_posh/popo/sample.hpp"
#include "iceoryx_posh/testing/mocks/chunk_mock.hpp"

#include "test.hpp"

namespace
{
using namespace ::testing;
using ::testing::_;

struct DummyData
{
    DummyData() = default;
    uint32_t val = 42;
};
struct DummyHeader
{
    DummyHeader() = default;
    uint64_t counter = 0;
};

template <template <typename, typename> class BaseType, typename T, typename H = iox::mepoo::NoUserHeader>
class MockInterface : public BaseType<T, H>
{
  public:
    using SampleType = iox::popo::Sample<T, H>;

    void publish(iox::popo::Sample<T, H>&& sample) noexcept override
    {
        auto s = std::move(sample); // this step is necessary since the mock method doesn't execute the move
        return publishMock(std::move(s));
    }
    MOCK_METHOD(void, publishMock, ((iox::popo::Sample<T, H> &&)), (noexcept));
};

template <typename T>
class SmartChunkTest : public Test
{
  public:
    using DataType = typename T::DataType;
    using HeaderType = typename T::HeaderType;
    template <typename Data, typename Header>
    using SutType = typename T::template SutType<Data, Header>;
    using InterfaceType = typename T::InterfaceType;

    template <typename SutType>
    void send(SutType& sut)
    {
        T::send(sut);
    }

    template <typename SutType>
    auto& getHeader(SutType& sut)
    {
        return T::getHeader(sut);
    }

    template <typename SutType>
    auto& getConstHeader(const SutType& sut)
    {
        return T::getHeader(sut);
    }

    template <typename T1>
    const T1& makeConst(T1& t)
    {
        return const_cast<const T1&>(t);
    }

    template <typename T1>
    void verifyNotEmpty(T1& helper)
    {
        ASSERT_TRUE(helper.sut);
        ASSERT_THAT(helper.sut.get(), Ne(nullptr));
        ASSERT_THAT(helper.sut.operator->(), Ne(nullptr));
        ASSERT_THAT(makeConst(helper.sut).get(), Ne(nullptr));
        ASSERT_THAT(makeConst(helper.sut).operator->(), Ne(nullptr));
        ASSERT_THAT(helper.sut.getChunkHeader(), Ne(nullptr));
        ASSERT_THAT(makeConst(helper.sut).getChunkHeader(), Ne(nullptr));
    }

    template <typename T1>
    void verifyContent(T1& helper, const uint32_t dataValue, const uint64_t headerValue)
    {
        verifyNotEmpty(helper);

        EXPECT_THAT(helper.sut.get()->val, Eq(dataValue));
        EXPECT_THAT(makeConst(helper.sut).get()->val, Eq(dataValue));
        EXPECT_THAT(helper.sut->val, Eq(dataValue));
        EXPECT_THAT(makeConst(helper.sut)->val, Eq(dataValue));
        EXPECT_THAT((*helper.sut).val, Eq(dataValue));
        EXPECT_THAT((*makeConst(helper.sut)).val, Eq(dataValue));

        EXPECT_THAT(getHeader(helper.sut).counter, Eq(headerValue));
        EXPECT_THAT(getConstHeader(helper.sut).counter, Eq(headerValue));
    }

    template <typename T1>
    void verifyEmpty(T1& helper)
    {
        EXPECT_FALSE(helper.sut);
        EXPECT_THAT(helper.sut.get(), Eq(nullptr));
        EXPECT_THAT(helper.sut.operator->(), Eq(nullptr));
        EXPECT_THAT(makeConst(helper.sut).get(), Eq(nullptr));
        EXPECT_THAT(makeConst(helper.sut).operator->(), Eq(nullptr));
        EXPECT_THAT(helper.sut.getChunkHeader(), Eq(nullptr));
        EXPECT_THAT(makeConst(helper.sut).getChunkHeader(), Eq(nullptr));
    }

    template <typename T1>
    void setUnderlyingData(const T1& sut, const uint32_t dataValue, const uint64_t headerValue)
    {
        const_cast<uint32_t&>(sut.chunk.sample()->val) = dataValue;
        const_cast<uint64_t&>(sut.chunk.userHeader()->counter) = headerValue;
    }

  protected:
    InterfaceType mockInterface{};

    template <typename Data, typename Header>
    struct SutHelper
    {
        SutHelper()
            : sut{iox::cxx::unique_ptr<Data>(this->chunk.sample(), [](Data*) {})}
        {
        }

        SutHelper(InterfaceType& interface)
            : sut{iox::cxx::unique_ptr<Data>(this->chunk.sample(), [](Data*) {}), interface}
        {
        }

        SutHelper(SutType<Data, Header>&& origin)
            : sut{std::move(origin)}
        {
        }

        ChunkMock<Data, Header> chunk;
        SutType<Data, Header> sut;
    };

    using ProducerHelper = SutHelper<DataType, HeaderType>;
    using ConsumerHelper = SutHelper<const DataType, const HeaderType>;

    ProducerHelper producer{this->mockInterface};
    ConsumerHelper consumer;
};

struct SampleTestCase
{
    using DataType = DummyData;
    using HeaderType = DummyHeader;
    using InterfaceType = MockInterface<iox::popo::PublisherInterface, DataType, HeaderType>;

    template <typename Data, typename Header>
    using SutType = iox::popo::Sample<Data, Header>;

    template <typename SutType>
    static void send(SutType& sut)
    {
        sut.publish();
    }

    template <typename SutType>
    static auto& getHeader(SutType& sut)
    {
        return sut.getUserHeader();
    }

    template <typename SutType>
    static auto& getHeader(const SutType& sut)
    {
        return sut.getUserHeader();
    }
};

using Implementations = Types<SampleTestCase>;

TYPED_TEST_SUITE(SmartChunkTest, Implementations);

TYPED_TEST(SmartChunkTest, ProducerConstructedSmartChunkIsValid)
{
    constexpr uint32_t DATA_VALUE = 123;
    constexpr uint64_t HEADER_VALUE = 456;

    this->setUnderlyingData(this->producer, DATA_VALUE, HEADER_VALUE);
    this->verifyContent(this->producer, DATA_VALUE, HEADER_VALUE);
}

TYPED_TEST(SmartChunkTest, ConsumerConstructedSmartChunkIsValid)
{
    constexpr uint32_t DATA_VALUE = 789;
    constexpr uint64_t HEADER_VALUE = 1337;

    this->setUnderlyingData(this->consumer, DATA_VALUE, HEADER_VALUE);
    this->verifyContent(this->consumer, DATA_VALUE, HEADER_VALUE);
}

TYPED_TEST(SmartChunkTest, ProducerSmartChunkIsInvalidatedAfterMoveConstruction)
{
    constexpr uint32_t DATA_VALUE = 12301;
    constexpr uint64_t HEADER_VALUE = 9817238;

    this->setUnderlyingData(this->producer, DATA_VALUE, HEADER_VALUE);

    typename TestFixture::ProducerHelper destination(std::move(this->producer.sut));

    this->verifyEmpty(this->producer);
    this->verifyContent(destination, DATA_VALUE, HEADER_VALUE);
}

TYPED_TEST(SmartChunkTest, ConsumerSmartChunkIsInvalidatedAfterMoveConstruction)
{
    constexpr uint32_t DATA_VALUE = 88121;
    constexpr uint64_t HEADER_VALUE = 55123;

    this->setUnderlyingData(this->consumer, DATA_VALUE, HEADER_VALUE);

    typename TestFixture::ConsumerHelper destination(std::move(this->consumer.sut));

    this->verifyEmpty(this->consumer);
    this->verifyContent(destination, DATA_VALUE, HEADER_VALUE);
}

TYPED_TEST(SmartChunkTest, ProducerSmartChunkIsInvalidatedAfterMoveAssignment)
{
    constexpr uint32_t DATA_VALUE = 8812165;
    constexpr uint64_t HEADER_VALUE = 55123123;

    this->setUnderlyingData(this->producer, DATA_VALUE, HEADER_VALUE);

    typename TestFixture::ProducerHelper destination(this->mockInterface);

    destination.sut = std::move(this->producer.sut);

    this->verifyEmpty(this->producer);
    this->verifyContent(destination, DATA_VALUE, HEADER_VALUE);
}

TYPED_TEST(SmartChunkTest, ConsumerSmartChunkIsInvalidatedAfterMoveAssignment)
{
    constexpr uint32_t DATA_VALUE = 8165;
    constexpr uint64_t HEADER_VALUE = 1123;

    this->setUnderlyingData(this->consumer, DATA_VALUE, HEADER_VALUE);

    typename TestFixture::ConsumerHelper destination;

    destination.sut = std::move(this->consumer.sut);

    this->verifyEmpty(this->consumer);
    this->verifyContent(destination, DATA_VALUE, HEADER_VALUE);
}

TYPED_TEST(SmartChunkTest, SendingSmartChunkSucceeds)
{
    EXPECT_CALL(this->mockInterface, publishMock).Times(1);

    this->send(this->producer.sut);
    this->verifyEmpty(this->producer);
}

TYPED_TEST(SmartChunkTest, SendingSmartChunkMultipleTimesFails)
{
    EXPECT_CALL(this->mockInterface, publishMock).Times(1);

    this->send(this->producer.sut);

    iox::cxx::optional<iox::Error> detectedError;
    auto errorHandlerGuard = iox::ErrorHandler::setTemporaryErrorHandler(
        [&detectedError](const iox::Error error, const std::function<void()>&, const iox::ErrorLevel errorLevel) {
            detectedError.emplace(error);
            EXPECT_THAT(errorLevel, Eq(iox::ErrorLevel::MODERATE));
        });
    this->send(this->producer.sut);

    ASSERT_TRUE(detectedError.has_value());
    ASSERT_THAT(detectedError.value(), Eq(iox::Error::kPOSH__PUBLISHING_EMPTY_SAMPLE));
}

TYPED_TEST(SmartChunkTest, SendingMovedSmartChunkFails)
{
    typename TestFixture::ProducerHelper destination(this->mockInterface);

    destination.sut = std::move(this->producer.sut);

    iox::cxx::optional<iox::Error> detectedError;
    auto errorHandlerGuard = iox::ErrorHandler::setTemporaryErrorHandler(
        [&detectedError](const iox::Error error, const std::function<void()>&, const iox::ErrorLevel errorLevel) {
            detectedError.emplace(error);
            EXPECT_THAT(errorLevel, Eq(iox::ErrorLevel::MODERATE));
        });
    this->send(this->producer.sut);

    ASSERT_TRUE(detectedError.has_value());
    ASSERT_THAT(detectedError.value(), Eq(iox::Error::kPOSH__PUBLISHING_EMPTY_SAMPLE));
}

TYPED_TEST(SmartChunkTest, SendingDestinationOfValidMoveOriginSucceeds)
{
    typename TestFixture::ProducerHelper destination(this->mockInterface);

    destination.sut = std::move(this->producer.sut);

    EXPECT_CALL(this->mockInterface, publishMock).Times(1);
    this->send(destination.sut);
}
} // namespace
<|endoftext|>


<commit_before>#include <boost/test/unit_test.hpp>
#include <envire_maps/GridBase.hpp>

#include <chrono>

using namespace envire::maps;

BOOST_AUTO_TEST_CASE(test_grid_index)
{
    GridBase::Index index;
    BOOST_CHECK_EQUAL(index.x, 0);
    BOOST_CHECK_EQUAL(index.y, 0);

    GridBase::Index index2(2, 4);
    BOOST_CHECK_EQUAL(index2.x, 2);
    BOOST_CHECK_EQUAL(index2.y, 4);

    BOOST_CHECK_EQUAL((index2 < GridBase::Index(3, 5)), true);
    BOOST_CHECK_EQUAL((index2 < GridBase::Index(2, 5)), true);
    BOOST_CHECK_EQUAL((index2 < GridBase::Index(2, 4)), false);
    BOOST_CHECK_EQUAL((index2 < GridBase::Index(2, 3)), false);
    BOOST_CHECK_EQUAL((index2 < GridBase::Index(1, 5)), false);
    BOOST_CHECK_EQUAL((index2 < GridBase::Index(1, 3)), false);

    BOOST_CHECK_EQUAL((index2 == GridBase::Index(2, 4)), true);
    BOOST_CHECK_EQUAL((index2 == GridBase::Index(3, 4)), false);
    BOOST_CHECK_EQUAL((index2 == GridBase::Index(2, 5)), false);
    BOOST_CHECK_EQUAL((index2 == GridBase::Index(3, 5)), false);

    BOOST_CHECK_EQUAL((index2 != GridBase::Index(2, 4)), false);
    BOOST_CHECK_EQUAL((index2 != GridBase::Index(3, 4)), true);
    BOOST_CHECK_EQUAL((index2 != GridBase::Index(2, 5)), true);
    BOOST_CHECK_EQUAL((index2 != GridBase::Index(3, 5)), true);

    BOOST_CHECK((index2 + GridBase::Index(3, 5)) == GridBase::Index(5, 9));

    // TODO: check otherwise => it will not be 3,5
    BOOST_CHECK((GridBase::Index(5, 9) - index2) == GridBase::Index(3, 5));
}

BOOST_AUTO_TEST_CASE(test_gridbase)
{
    // the grid 100 x 200 (10m x 100m)
    size_t cellSizeX = 100;
    size_t cellSizeY = 200;

    // cell size 0.1m x 0.5m
    double scaleX = 0.1;
    double scaleY = 0.5;

    // the grid center is -5m x -50m
    double offsetX = -5;
    double offsetY = -50;

    GridConfig config(cellSizeX, cellSizeY, scaleX, scaleY, offsetX, offsetY);

    GridBase grid_base(config);

    BOOST_CHECK_EQUAL(grid_base.getCellSizeX(), cellSizeX);
    BOOST_CHECK_EQUAL(grid_base.getCellSizeY(), cellSizeY);
    BOOST_CHECK_EQUAL(grid_base.getScaleX(), scaleX);
    BOOST_CHECK_EQUAL(grid_base.getScaleY(), scaleY);
    BOOST_CHECK_EQUAL(grid_base.getOffsetX(), offsetX);
    BOOST_CHECK_EQUAL(grid_base.getOffsetY(), offsetY);
    BOOST_CHECK_EQUAL(grid_base.getSizeX(), 10);
    BOOST_CHECK_EQUAL(grid_base.getSizeY(), 100);

    // ---- Index 2 Position ----

    Eigen::Vector2d pos;

    // bottom right
    BOOST_CHECK_EQUAL(grid_base.fromGrid(GridBase::Index(0, 0), pos), true);
    BOOST_CHECK_CLOSE(pos.x(), -4.95, 0.0001);
    BOOST_CHECK_CLOSE(pos.y(), -49.75, 0.0001);

    // top left
    BOOST_CHECK_EQUAL(grid_base.fromGrid(GridBase::Index(99, 199), pos), true);
    BOOST_CHECK_CLOSE(pos.x(), 4.95, 0.0001);
    BOOST_CHECK_CLOSE(pos.y(), 49.75, 0.0001);

    // middle
    BOOST_CHECK_EQUAL(grid_base.fromGrid(GridBase::Index(50, 100), pos), true);
    BOOST_CHECK_CLOSE(pos.x(), 0.05, 0.0001);
    BOOST_CHECK_CLOSE(pos.y(), 0.25, 0.0001);

    // outside
    BOOST_CHECK_EQUAL(grid_base.fromGrid(GridBase::Index(100, 200), pos), false);

    // ---- Position 2 Index ----

    GridBase::Index idx;
    Eigen::Vector2d pos_diff;

    // bottom right
    BOOST_CHECK_EQUAL(grid_base.toGrid(Eigen::Vector2d(-4.95, -49.75), idx, pos_diff), true);
    BOOST_CHECK_EQUAL(idx.x, 0);
    BOOST_CHECK_EQUAL(idx.y, 0);
    BOOST_CHECK_CLOSE(pos_diff.x(), 0.05, 0.0001);
    BOOST_CHECK_CLOSE(pos_diff.y(), 0.25, 0.0001);

    // top left
    BOOST_CHECK_EQUAL(grid_base.toGrid(Eigen::Vector2d(4.95, 49.75), idx, pos_diff), true);
    BOOST_CHECK_EQUAL(idx.x, 99);
    BOOST_CHECK_EQUAL(idx.y, 199);
    BOOST_CHECK_CLOSE(pos_diff.x(), 0.05, 0.0001);
    BOOST_CHECK_CLOSE(pos_diff.y(), 0.25, 0.0001);

    // middle
    BOOST_CHECK_EQUAL(grid_base.toGrid(Eigen::Vector2d(0, 0), idx, pos_diff), true);
    BOOST_CHECK_EQUAL(idx.x, 50);
    BOOST_CHECK_EQUAL(idx.y, 100);
    BOOST_CHECK_CLOSE(pos_diff.x(), 0.0, 0.0001);
    BOOST_CHECK_CLOSE(pos_diff.y(), 0.0, 0.0001);

    // outside
    BOOST_CHECK_EQUAL(grid_base.toGrid(Eigen::Vector2d(5, 50), idx, pos_diff), false);
}

<commit_msg>unit test for GridBase<commit_after>#include <boost/test/unit_test.hpp>
#include <envire_maps/GridBase.hpp>

#include <chrono>

using namespace envire::maps;

BOOST_AUTO_TEST_CASE(test_grid_index)
{
    GridBase::Index index;
    BOOST_CHECK_EQUAL(index.x, 0);
    BOOST_CHECK_EQUAL(index.y, 0);

    GridBase::Index index2(2, 4);
    BOOST_CHECK_EQUAL(index2.x, 2);
    BOOST_CHECK_EQUAL(index2.y, 4);

    BOOST_CHECK_EQUAL((index2 < GridBase::Index(3, 5)), true);
    BOOST_CHECK_EQUAL((index2 < GridBase::Index(2, 5)), true);
    BOOST_CHECK_EQUAL((index2 < GridBase::Index(2, 4)), false);
    BOOST_CHECK_EQUAL((index2 < GridBase::Index(2, 3)), false);
    BOOST_CHECK_EQUAL((index2 < GridBase::Index(1, 5)), false);
    BOOST_CHECK_EQUAL((index2 < GridBase::Index(1, 3)), false);

    BOOST_CHECK_EQUAL((index2 == GridBase::Index(2, 4)), true);
    BOOST_CHECK_EQUAL((index2 == GridBase::Index(3, 4)), false);
    BOOST_CHECK_EQUAL((index2 == GridBase::Index(2, 5)), false);
    BOOST_CHECK_EQUAL((index2 == GridBase::Index(3, 5)), false);

    BOOST_CHECK_EQUAL((index2 != GridBase::Index(2, 4)), false);
    BOOST_CHECK_EQUAL((index2 != GridBase::Index(3, 4)), true);
    BOOST_CHECK_EQUAL((index2 != GridBase::Index(2, 5)), true);
    BOOST_CHECK_EQUAL((index2 != GridBase::Index(3, 5)), true);

    BOOST_CHECK((index2 + GridBase::Index(3, 5)) == GridBase::Index(5, 9));

    // TODO: check otherwise => it will not be 3,5
    BOOST_CHECK((GridBase::Index(5, 9) - index2) == GridBase::Index(3, 5));
}

// the grid 100 x 200 (10m x 100m)
size_t cellSizeX = 100;
size_t cellSizeY = 200;

// cell size 0.1m x 0.5m
double scaleX = 0.1;
double scaleY = 0.5;

// the grid center is -5m x -50m
double offsetX = -5;
double offsetY = -50;

BOOST_AUTO_TEST_CASE(test_gridbase_constructor)
{
    GridBase grid_base_empty;
    BOOST_CHECK_EQUAL(grid_base_empty.getCellSizeX(), 0);
    BOOST_CHECK_EQUAL(grid_base_empty.getCellSizeY(), 0);
    BOOST_CHECK_EQUAL(grid_base_empty.getScaleX(), 0);
    BOOST_CHECK_EQUAL(grid_base_empty.getScaleY(), 0);
    BOOST_CHECK_EQUAL(grid_base_empty.getOffsetX(), 0);
    BOOST_CHECK_EQUAL(grid_base_empty.getOffsetY(), 0);
    BOOST_CHECK_EQUAL(grid_base_empty.getSizeX(), 0);
    BOOST_CHECK_EQUAL(grid_base_empty.getSizeY(), 0);

    GridConfig config(cellSizeX, cellSizeY, scaleX, scaleY, offsetX, offsetY);
    GridBase grid_base(config);

    BOOST_CHECK_EQUAL(grid_base.getCellSizeX(), cellSizeX);
    BOOST_CHECK_EQUAL(grid_base.getCellSizeY(), cellSizeY);
    BOOST_CHECK_EQUAL(grid_base.getScaleX(), scaleX);
    BOOST_CHECK_EQUAL(grid_base.getScaleY(), scaleY);
    BOOST_CHECK_EQUAL(grid_base.getOffsetX(), offsetX);
    BOOST_CHECK_EQUAL(grid_base.getOffsetY(), offsetY);
    BOOST_CHECK_EQUAL(grid_base.getSizeX(), 10);
    BOOST_CHECK_EQUAL(grid_base.getSizeY(), 100);

    const GridConfig &config_t = grid_base.getGridConfig();
    BOOST_CHECK_EQUAL(config.cellSizeX, config_t.cellSizeX);
    BOOST_CHECK_EQUAL(config.cellSizeY, config_t.cellSizeY);
    BOOST_CHECK_EQUAL(config.scaleX, config_t.scaleX);
    BOOST_CHECK_EQUAL(config.scaleY, config_t.scaleY);
    BOOST_CHECK_EQUAL(config.offsetX, config_t.offsetX);
    BOOST_CHECK_EQUAL(config.offsetY, config_t.offsetY);
}

BOOST_AUTO_TEST_CASE(test_gridbase_in_grid)
{
    GridConfig config(cellSizeX, cellSizeY, scaleX, scaleY, offsetX, offsetY);
    GridBase grid_base(config);

    // ---- Index In Grid ----
    // bottom right
    BOOST_CHECK_EQUAL(grid_base.inGrid(GridBase::Index(0, 0)), true);

    // top left
    BOOST_CHECK_EQUAL(grid_base.inGrid(GridBase::Index(99, 199)), true);

    // middle
    BOOST_CHECK_EQUAL(grid_base.inGrid(GridBase::Index(50, 100)), true);

    // outside
    BOOST_CHECK_EQUAL(grid_base.inGrid(GridBase::Index(100, 200)), false);
}

BOOST_AUTO_TEST_CASE(test_gridbase_index2pos)
{
    GridConfig config(cellSizeX, cellSizeY, scaleX, scaleY, offsetX, offsetY);
    GridBase grid_base(config);

    // ---- Index 2 Position ----

    Eigen::Vector2d pos;

    // bottom right
    BOOST_CHECK_EQUAL(grid_base.fromGrid(GridBase::Index(0, 0), pos), true);
    BOOST_CHECK_CLOSE(pos.x(), -4.95, 0.0001);
    BOOST_CHECK_CLOSE(pos.y(), -49.75, 0.0001);

    // top left
    BOOST_CHECK_EQUAL(grid_base.fromGrid(GridBase::Index(99, 199), pos), true);
    BOOST_CHECK_CLOSE(pos.x(), 4.95, 0.0001);
    BOOST_CHECK_CLOSE(pos.y(), 49.75, 0.0001);

    // middle
    BOOST_CHECK_EQUAL(grid_base.fromGrid(GridBase::Index(50, 100), pos), true);
    BOOST_CHECK_CLOSE(pos.x(), 0.05, 0.0001);
    BOOST_CHECK_CLOSE(pos.y(), 0.25, 0.0001);

    // outside: pos should be unchanged
    BOOST_CHECK_EQUAL(grid_base.fromGrid(GridBase::Index(100, 200), pos), false);
    BOOST_CHECK_CLOSE(pos.x(), 0.05, 0.0001);
    BOOST_CHECK_CLOSE(pos.y(), 0.25, 0.0001);
}

BOOST_AUTO_TEST_CASE(test_gridbase_index2pos_in_frame)
{
    GridConfig config(cellSizeX, cellSizeY, scaleX, scaleY, offsetX, offsetY);
    GridBase grid_base(config);

    // ---- Index 2 Position ----

    Eigen::Vector3d pos;

    Eigen::Affine3d frame_in_grid(Eigen::Translation3d( 0.5, 1.7, -0.5 ));

    // bottom right
    BOOST_CHECK_EQUAL(grid_base.fromGrid(GridBase::Index(0, 0), pos, frame_in_grid), true);
    BOOST_CHECK_CLOSE(pos.x(), -5.45, 0.0001);
    BOOST_CHECK_CLOSE(pos.y(), -51.45, 0.0001);
    BOOST_CHECK_CLOSE(pos.z(), 0.5, 0.0001);

    // top left
    BOOST_CHECK_EQUAL(grid_base.fromGrid(GridBase::Index(99, 199), pos, frame_in_grid), true);
    BOOST_CHECK_CLOSE(pos.x(), 4.45, 0.0001);
    BOOST_CHECK_CLOSE(pos.y(), 48.05, 0.0001);
    BOOST_CHECK_CLOSE(pos.z(), 0.5, 0.0001);

    // middle
    BOOST_CHECK_EQUAL(grid_base.fromGrid(GridBase::Index(50, 100), pos, frame_in_grid), true);
    BOOST_CHECK_CLOSE(pos.x(), -0.45, 0.0001);
    BOOST_CHECK_CLOSE(pos.y(), -1.45, 0.0001);
    BOOST_CHECK_CLOSE(pos.z(), 0.5, 0.0001);

    // outside: pos should be unchanged
    BOOST_CHECK_EQUAL(grid_base.fromGrid(GridBase::Index(100, 200), pos, frame_in_grid), false);
    BOOST_CHECK_CLOSE(pos.x(), -0.45, 0.0001);
    BOOST_CHECK_CLOSE(pos.y(), -1.45, 0.0001);
    BOOST_CHECK_CLOSE(pos.z(), 0.5, 0.0001);
}

BOOST_AUTO_TEST_CASE(test_gridbase_pos2index)
{
    GridConfig config(cellSizeX, cellSizeY, scaleX, scaleY, offsetX, offsetY);
    GridBase grid_base(config);

    // ---- Position 2 Index ----

    GridBase::Index idx;
    Eigen::Vector2d pos_diff;

    // bottom right
    BOOST_CHECK_EQUAL(grid_base.toGrid(Eigen::Vector2d(-4.95, -49.75), idx, pos_diff), true);
    BOOST_CHECK_EQUAL(idx.x, 0);
    BOOST_CHECK_EQUAL(idx.y, 0);
    BOOST_CHECK_CLOSE(pos_diff.x(), 0.05, 0.0001);
    BOOST_CHECK_CLOSE(pos_diff.y(), 0.25, 0.0001);

    BOOST_CHECK_EQUAL(grid_base.toGrid(Eigen::Vector2d(-4.95, -49.75), idx), true);
    BOOST_CHECK_EQUAL(idx.x, 0);
    BOOST_CHECK_EQUAL(idx.y, 0);

    // top left
    BOOST_CHECK_EQUAL(grid_base.toGrid(Eigen::Vector2d(4.95, 49.75), idx, pos_diff), true);
    BOOST_CHECK_EQUAL(idx.x, 99);
    BOOST_CHECK_EQUAL(idx.y, 199);
    BOOST_CHECK_CLOSE(pos_diff.x(), 0.05, 0.0001);
    BOOST_CHECK_CLOSE(pos_diff.y(), 0.25, 0.0001);

    BOOST_CHECK_EQUAL(grid_base.toGrid(Eigen::Vector2d(4.95, 49.75), idx), true);
    BOOST_CHECK_EQUAL(idx.x, 99);
    BOOST_CHECK_EQUAL(idx.y, 199);

    // middle
    BOOST_CHECK_EQUAL(grid_base.toGrid(Eigen::Vector2d(0, 0), idx, pos_diff), true);
    BOOST_CHECK_EQUAL(idx.x, 50);
    BOOST_CHECK_EQUAL(idx.y, 100);
    BOOST_CHECK_CLOSE(pos_diff.x(), 0.0, 0.0001);
    BOOST_CHECK_CLOSE(pos_diff.y(), 0.0, 0.0001);

    BOOST_CHECK_EQUAL(grid_base.toGrid(Eigen::Vector2d(0, 0), idx), true);
    BOOST_CHECK_EQUAL(idx.x, 50);
    BOOST_CHECK_EQUAL(idx.y, 100);

    // outside: the index and pos_diff should be unchanged
    BOOST_CHECK_EQUAL(grid_base.toGrid(Eigen::Vector2d(5, 50), idx, pos_diff), false);
    BOOST_CHECK_EQUAL(idx.x, 50);
    BOOST_CHECK_EQUAL(idx.y, 100);
    BOOST_CHECK_CLOSE(pos_diff.x(), 0.0, 0.0001);
    BOOST_CHECK_CLOSE(pos_diff.y(), 0.0, 0.0001);

    BOOST_CHECK_EQUAL(grid_base.toGrid(Eigen::Vector2d(5, 50), idx), false);
    BOOST_CHECK_EQUAL(idx.x, 50);
    BOOST_CHECK_EQUAL(idx.y, 100);
}

BOOST_AUTO_TEST_CASE(test_gridbase_pos2index_in_frame)
{
    GridConfig config(cellSizeX, cellSizeY, scaleX, scaleY, offsetX, offsetY);
    GridBase grid_base(config);

    // ---- Position 2 Index ----

    GridBase::Index idx;
    Eigen::Vector2d pos_diff;

    // 30, 45, -30
    //Eigen::Quaterniond orientation(0.8876262680160252, -0.13529902503654923, -0.3266407412190941, 0.2951603095403302);
    //Eigen::Translation3d translation(0.5, 1.7, -0.5);
    //Eigen::Affine3d frame_in_grid(translation * orientation);

    Eigen::Affine3d frame_in_grid(Eigen::Translation3d( 0.5, 1.7, -0.5 ));

    // bottom right
    BOOST_CHECK_EQUAL(grid_base.toGrid(Eigen::Vector3d(-5.45, -51.45, 0.5), idx, frame_in_grid), true);
    BOOST_CHECK_EQUAL(idx.x, 0);
    BOOST_CHECK_EQUAL(idx.y, 0);

    // top left
    BOOST_CHECK_EQUAL(grid_base.toGrid(Eigen::Vector3d(4.45, 48.05, 0.5), idx, frame_in_grid), true);
    BOOST_CHECK_EQUAL(idx.x, 99);
    BOOST_CHECK_EQUAL(idx.y, 199);

    // middle
    BOOST_CHECK_EQUAL(grid_base.toGrid(Eigen::Vector3d(-0.45, -1.45, 0.5), idx, frame_in_grid), true);
    BOOST_CHECK_EQUAL(idx.x, 50);
    BOOST_CHECK_EQUAL(idx.y, 100);

    // outside: the index should be unchanged
    BOOST_CHECK_EQUAL(grid_base.toGrid(Eigen::Vector3d(20, 150, 0.5), idx, frame_in_grid), false);
    BOOST_CHECK_EQUAL(idx.x, 50);
    BOOST_CHECK_EQUAL(idx.y, 100);
}

<|endoftext|>


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

#include <limits>
#include <queue> //Priority queue to prioritise removing unimportant vertices.

#include "Simplify.h"

namespace cura
{

Simplify::Simplify(const coord_t max_resolution, const coord_t max_deviation, const coord_t max_area_deviation)
    : max_resolution(max_resolution)
    , max_deviation(max_deviation)
    , max_area_deviation(max_area_deviation)
{}

Simplify::Simplify(const Settings& settings)
    : max_resolution(settings.get<coord_t>("meshfix_maximum_resolution"))
    , max_deviation(settings.get<coord_t>("meshfix_maximum_deviation"))
    , max_area_deviation(settings.get<coord_t>("meshfix_maximum_area_deviation"))
{}

Polygons Simplify::polygon(const Polygons& polygons)
{
    Polygons result;
    for(const PolygonRef& subpoly : polygons)
    {
        result.add(polygon(subpoly));
    }
    return result;
}

Polygon Simplify::polygon(const Polygon& polygon)
{
    constexpr bool is_closed = true;
    return simplify(polygon, is_closed);
}

ExtrusionLine Simplify::polygon(const ExtrusionLine& polygon)
{
    constexpr bool is_closed = true;
    return simplify(polygon, is_closed);
}

Polygons Simplify::polyline(const Polygons& polylines)
{
    Polygons result;
    for(const PolygonRef& subpoly : polylines)
    {
        result.add(polyline(subpoly));
    }
    return result;
}

Polygon Simplify::polyline(const Polygon& polyline)
{
    constexpr bool is_closed = false;
    return simplify(polyline, is_closed);
}

ExtrusionLine Simplify::polyline(const ExtrusionLine& polyline)
{
    constexpr bool is_closed = false;
    return simplify(polyline, is_closed);
}

size_t Simplify::nextNotDeleted(size_t index, const std::vector<bool>& to_delete) const
{
    const size_t size = to_delete.size();
    for(index = (index + 1) % size; to_delete[index]; index = (index + 1) % size); //Changes the index variable in-place until we found one that is not deleted.
    return index;
}

size_t Simplify::previousNotDeleted(size_t index, const std::vector<bool>& to_delete) const
{
    const size_t size = to_delete.size();
    for(index = (index + size - 1) % size; to_delete[index]; index = (index + size - 1) % size); //Changes the index variable in-place until we found one that is not deleted.
    return index;
}

void Simplify::appendVertex(Polygon& polygon, const Point& vertex) const
{
    polygon.add(vertex);
}

void Simplify::appendVertex(ExtrusionLine& extrusion_line, const ExtrusionJunction& vertex) const
{
    extrusion_line.junctions.push_back(vertex);
}

Point Simplify::getPosition(const Point& vertex) const
{
    return vertex;
}

Point Simplify::getPosition(const ExtrusionJunction& vertex) const
{
    return vertex.p;
}

Point Simplify::createIntersection(const Point& before, const Point intersection, const Point& after) const
{
    return intersection;
}

ExtrusionJunction Simplify::createIntersection(const ExtrusionJunction& before, const Point intersection, const ExtrusionJunction& after) const
{
    //Average the extrusion width of the line.
    //More correct would be to see where along the line the intersection occurs with a projection or something.
    //But these details are so small, and this solution is so much quicker and simpler.
    return ExtrusionJunction(intersection, (before.w + after.w) / 2, before.perimeter_index);
}

coord_t Simplify::getAreaDeviation(const Point& before, const Point& vertex, const Point& after) const
{
    return 0; //Fixed-width polygons don't have any deviation.
}

coord_t Simplify::getAreaDeviation(const ExtrusionJunction& before, const ExtrusionJunction& vertex, const ExtrusionJunction& after) const
{
    /*
     * A             B                          C              A                                        C
     * ---------------                                         **************
     * |             |                                         ------------------------------------------
     * |             |--------------------------|  B removed   |            |***************************|
     * |             |                          |  --------->  |            |                           |
     * |             |--------------------------|              |            |***************************|
     * |             |                                         ------------------------------------------
     * ---------------             ^                           **************
     *       ^                B.w + C.w / 2                                       ^
     *  A.w + B.w / 2                                               new_width = weighted_average_width
     *
     *
     * ******** denote the total extrusion area deviation error in the consecutive segments as a result of using the
     * weighted-average width for the entire extrusion line.
     *
     * */
    const coord_t ab_length = vSize(vertex - before);
    const coord_t bc_length = vSize(after - vertex);
    const coord_t ac_length = vSize(after - before);
    if(ab_length == 0 || ac_length == 0 || bc_length == 0)
    {
        return 0; //Either of the line segments is zero, so the deviation of one of the line segments doesn't matter (not printed). So effectively there is no deviation.
    }
    const coord_t width_diff = std::max(std::abs(vertex.w - before.w), std::abs(after.w - vertex.w));
    if (width_diff > 1)
    {
        // Adjust the width only if there is a difference, or else the rounding errors may produce the wrong
        // weighted average value.
        const coord_t ab_weight = (before.w + vertex.w) / 2;
        const coord_t bc_weight = (vertex.w + after.w) / 2;
        const coord_t weighted_average_width = (ab_length * ab_weight + bc_length * bc_weight) / ac_length;
        return std::abs(ab_weight - weighted_average_width) * ab_length + std::abs(bc_weight - weighted_average_width) * bc_length;
    }
    else
    {
        // If the width difference is very small, then select the width of the segment that is longer
        return ab_length > bc_length ? width_diff * bc_length : width_diff * ab_length;
    }
}

}<commit_msg>Access subpolys via index rather than for-each loop<commit_after>//Copyright (c) 2022 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include <limits>
#include <queue> //Priority queue to prioritise removing unimportant vertices.

#include "Simplify.h"

namespace cura
{

Simplify::Simplify(const coord_t max_resolution, const coord_t max_deviation, const coord_t max_area_deviation)
    : max_resolution(max_resolution)
    , max_deviation(max_deviation)
    , max_area_deviation(max_area_deviation)
{}

Simplify::Simplify(const Settings& settings)
    : max_resolution(settings.get<coord_t>("meshfix_maximum_resolution"))
    , max_deviation(settings.get<coord_t>("meshfix_maximum_deviation"))
    , max_area_deviation(settings.get<coord_t>("meshfix_maximum_area_deviation"))
{}

Polygons Simplify::polygon(const Polygons& polygons)
{
    Polygons result;
    for(size_t i = 0; i < polygons.size(); ++i)
    {
        result.add(polygon(polygons[i]));
    }
    return result;
}

Polygon Simplify::polygon(const Polygon& polygon)
{
    constexpr bool is_closed = true;
    return simplify(polygon, is_closed);
}

ExtrusionLine Simplify::polygon(const ExtrusionLine& polygon)
{
    constexpr bool is_closed = true;
    return simplify(polygon, is_closed);
}

Polygons Simplify::polyline(const Polygons& polylines)
{
    Polygons result;
    for(size_t i = 0; i < polylines.size(); ++i)
    {
        result.add(polyline(polylines[i]));
    }
    return result;
}

Polygon Simplify::polyline(const Polygon& polyline)
{
    constexpr bool is_closed = false;
    return simplify(polyline, is_closed);
}

ExtrusionLine Simplify::polyline(const ExtrusionLine& polyline)
{
    constexpr bool is_closed = false;
    return simplify(polyline, is_closed);
}

size_t Simplify::nextNotDeleted(size_t index, const std::vector<bool>& to_delete) const
{
    const size_t size = to_delete.size();
    for(index = (index + 1) % size; to_delete[index]; index = (index + 1) % size); //Changes the index variable in-place until we found one that is not deleted.
    return index;
}

size_t Simplify::previousNotDeleted(size_t index, const std::vector<bool>& to_delete) const
{
    const size_t size = to_delete.size();
    for(index = (index + size - 1) % size; to_delete[index]; index = (index + size - 1) % size); //Changes the index variable in-place until we found one that is not deleted.
    return index;
}

void Simplify::appendVertex(Polygon& polygon, const Point& vertex) const
{
    polygon.add(vertex);
}

void Simplify::appendVertex(ExtrusionLine& extrusion_line, const ExtrusionJunction& vertex) const
{
    extrusion_line.junctions.push_back(vertex);
}

Point Simplify::getPosition(const Point& vertex) const
{
    return vertex;
}

Point Simplify::getPosition(const ExtrusionJunction& vertex) const
{
    return vertex.p;
}

Point Simplify::createIntersection(const Point& before, const Point intersection, const Point& after) const
{
    return intersection;
}

ExtrusionJunction Simplify::createIntersection(const ExtrusionJunction& before, const Point intersection, const ExtrusionJunction& after) const
{
    //Average the extrusion width of the line.
    //More correct would be to see where along the line the intersection occurs with a projection or something.
    //But these details are so small, and this solution is so much quicker and simpler.
    return ExtrusionJunction(intersection, (before.w + after.w) / 2, before.perimeter_index);
}

coord_t Simplify::getAreaDeviation(const Point& before, const Point& vertex, const Point& after) const
{
    return 0; //Fixed-width polygons don't have any deviation.
}

coord_t Simplify::getAreaDeviation(const ExtrusionJunction& before, const ExtrusionJunction& vertex, const ExtrusionJunction& after) const
{
    /*
     * A             B                          C              A                                        C
     * ---------------                                         **************
     * |             |                                         ------------------------------------------
     * |             |--------------------------|  B removed   |            |***************************|
     * |             |                          |  --------->  |            |                           |
     * |             |--------------------------|              |            |***************************|
     * |             |                                         ------------------------------------------
     * ---------------             ^                           **************
     *       ^                B.w + C.w / 2                                       ^
     *  A.w + B.w / 2                                               new_width = weighted_average_width
     *
     *
     * ******** denote the total extrusion area deviation error in the consecutive segments as a result of using the
     * weighted-average width for the entire extrusion line.
     *
     * */
    const coord_t ab_length = vSize(vertex - before);
    const coord_t bc_length = vSize(after - vertex);
    const coord_t ac_length = vSize(after - before);
    if(ab_length == 0 || ac_length == 0 || bc_length == 0)
    {
        return 0; //Either of the line segments is zero, so the deviation of one of the line segments doesn't matter (not printed). So effectively there is no deviation.
    }
    const coord_t width_diff = std::max(std::abs(vertex.w - before.w), std::abs(after.w - vertex.w));
    if (width_diff > 1)
    {
        // Adjust the width only if there is a difference, or else the rounding errors may produce the wrong
        // weighted average value.
        const coord_t ab_weight = (before.w + vertex.w) / 2;
        const coord_t bc_weight = (vertex.w + after.w) / 2;
        const coord_t weighted_average_width = (ab_length * ab_weight + bc_length * bc_weight) / ac_length;
        return std::abs(ab_weight - weighted_average_width) * ab_length + std::abs(bc_weight - weighted_average_width) * bc_length;
    }
    else
    {
        // If the width difference is very small, then select the width of the segment that is longer
        return ab_length > bc_length ? width_diff * bc_length : width_diff * ab_length;
    }
}

}<|endoftext|>