<commit_before>#ifndef LEPP2_SPLIT_APPROXIMATOR_H__
#define LEPP2_SPLIT_APPROXIMATOR_H__
#include "lepp2/ObjectApproximator.hpp"
#include "lepp2/models/ObjectModel.h"

#include <deque>
#include <pcl/common/pca.h>
#include <pcl/common/common.h>

namespace lepp {

/**
 * An approximator implementation that will generate an approximation by
 * splitting the given object into multiple parts. Each part approximation is
 * generated by delegating to a wrapped `ObjectApproximator` instance, allowing
 * clients to vary the algorithm used for approximations, while keeping the
 * logic of incrementally splitting up the object.
 */
template<class PointT>
class SplitObjectApproximator : public ObjectApproximator<PointT> {
public:
  /**
   * Create a new `SplitObjectApproximator` that will approximate each part by
   * using the given approximator instance.
   */
  SplitObjectApproximator(boost::shared_ptr<ObjectApproximator<PointT> > approx)
      : approximator_(approx) {}
  /**
   * `ObjectApproximator` interface method.
   */
  boost::shared_ptr<CompositeModel> approximate(
      const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud);
private:
  /**
   * Splits the given point_cloud into two parts and places them in the
   * ``first`` and ``second`` PointCloud references.
   */
  void splitCloud(
      const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud,
      pcl::PointCloud<PointT>& first,
      pcl::PointCloud<PointT>& second);

  /**
   * An `ObjectApproximator` used to generate approximations for object parts.
   */
  boost::shared_ptr<ObjectApproximator<PointT> > approximator_;
};

template<class PointT>
boost::shared_ptr<CompositeModel> SplitObjectApproximator<PointT>::approximate(
    const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud) {
  boost::shared_ptr<CompositeModel> approx(new CompositeModel);
  typedef typename pcl::PointCloud<PointT>::ConstPtr PointCloudConstPtr;
  typedef typename pcl::PointCloud<PointT>::Ptr PointCloudPtr;
  std::deque<PointCloudConstPtr> queue;
  queue.push_back(point_cloud);

  int iteration = 0;
  while (!queue.empty()) {
    PointCloudConstPtr current_cloud = queue[0];
    queue.pop_front();

    // Delegates to the wrapped approximator for each part's approximation.
    ObjectModelPtr model = approximator_->approximate(current_cloud);
    // TODO Decide whether the model fits well enough for the current cloud.
    // For now we fix the number of split iterations.
    if (iteration == 0) {
      // The approximation should be improved. Try doing it for the split clouds
      PointCloudPtr first(new pcl::PointCloud<PointT>());
      PointCloudPtr second(new pcl::PointCloud<PointT>());
      splitCloud(current_cloud, *first, *second);
      queue.push_back(first);
      queue.push_back(second);
    } else {
      // Keep the approximation
      approx->addModel(model);
    }
    ++iteration;
  }

  return approx;
}

template<class PointT>
void SplitObjectApproximator<PointT>::splitCloud(
    const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud,
    pcl::PointCloud<PointT>& first,
    pcl::PointCloud<PointT>& second) {
  // Compute PCA for the input cloud
  pcl::PCA<PointT> pca;
  pca.setInputCloud(point_cloud);
  Eigen::Vector3f eigenvalues = pca.getEigenValues();
  Eigen::Matrix3f eigenvectors = pca.getEigenVectors();

  Eigen::Vector3d main_pca_axis = eigenvectors.col(0).cast<double>();

  // Compute the centroid
  Eigen::Vector4d centroid;<commit_msg>Refactor the BFS in split approx: track the tree depth<commit_after>#ifndef LEPP2_SPLIT_APPROXIMATOR_H__
#define LEPP2_SPLIT_APPROXIMATOR_H__
#include "lepp2/ObjectApproximator.hpp"
#include "lepp2/models/ObjectModel.h"

#include <deque>
#include <map>

#include <pcl/common/pca.h>
#include <pcl/common/common.h>

namespace lepp {

/**
 * An approximator implementation that will generate an approximation by
 * splitting the given object into multiple parts. Each part approximation is
 * generated by delegating to a wrapped `ObjectApproximator` instance, allowing
 * clients to vary the algorithm used for approximations, while keeping the
 * logic of incrementally splitting up the object.
 */
template<class PointT>
class SplitObjectApproximator : public ObjectApproximator<PointT> {
public:
  /**
   * Create a new `SplitObjectApproximator` that will approximate each part by
   * using the given approximator instance.
   */
  SplitObjectApproximator(boost::shared_ptr<ObjectApproximator<PointT> > approx)
      : approximator_(approx) {}
  /**
   * `ObjectApproximator` interface method.
   */
  boost::shared_ptr<CompositeModel> approximate(
      const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud);
private:
  /**
   * Splits the given point_cloud into two parts and places them in the
   * ``first`` and ``second`` PointCloud references.
   */
  void splitCloud(
      const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud,
      pcl::PointCloud<PointT>& first,
      pcl::PointCloud<PointT>& second);

  /**
   * An `ObjectApproximator` used to generate approximations for object parts.
   */
  boost::shared_ptr<ObjectApproximator<PointT> > approximator_;
};

template<class PointT>
boost::shared_ptr<CompositeModel> SplitObjectApproximator<PointT>::approximate(
    const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud) {
  boost::shared_ptr<CompositeModel> approx(new CompositeModel);
  typedef typename pcl::PointCloud<PointT>::ConstPtr PointCloudConstPtr;
  typedef typename pcl::PointCloud<PointT>::Ptr PointCloudPtr;
  std::deque<std::pair<int, PointCloudConstPtr> > queue;
  queue.push_back(std::make_pair(0, point_cloud));

  while (!queue.empty()) {
    int const depth = queue[0].first;
    PointCloudConstPtr const current_cloud = queue[0].second;
    queue.pop_front();

    // Delegates to the wrapped approximator for each part's approximation.
    ObjectModelPtr model = approximator_->approximate(current_cloud);
    // TODO Decide whether the model fits well enough for the current cloud.
    // For now we fix the number of split iterations.
    if (depth == 0) {
      // The approximation should be improved. Try doing it for the split clouds
      PointCloudPtr first(new pcl::PointCloud<PointT>());
      PointCloudPtr second(new pcl::PointCloud<PointT>());
      splitCloud(current_cloud, *first, *second);
      queue.push_back(std::make_pair(depth + 1, first));
      queue.push_back(std::make_pair(depth + 1, second));
    } else {
      // Keep the approximation
      approx->addModel(model);
    }
  }

  return approx;
}

template<class PointT>
void SplitObjectApproximator<PointT>::splitCloud(
    const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud,
    pcl::PointCloud<PointT>& first,
    pcl::PointCloud<PointT>& second) {
  // Compute PCA for the input cloud
  pcl::PCA<PointT> pca;
  pca.setInputCloud(point_cloud);
  Eigen::Vector3f eigenvalues = pca.getEigenValues();
  Eigen::Matrix3f eigenvectors = pca.getEigenVectors();

  Eigen::Vector3d main_pca_axis = eigenvectors.col(0).cast<double>();

  // Compute the centroid
  Eigen::Vector4d centroid;
{'fraction_non_alphanumeric': 0.10713282785734345, 'fraction_numerical': 0.0037910699241786015, 'mean_word_length': 4.748991121872478, 'pattern_counts': {'":': 0, '<': 67, '<?xml version=': 0, '>': 71, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5900174', 'n_tokens_mistral': 2193, 'n_tokens_neox': 2135, 'n_words': 555}