Program Listing for File rtree.hpp

Return to documentation for file (rcppsw/ds/rtree.hpp)

#pragma once

/*******************************************************************************
 * Includes
 ******************************************************************************/
#include <algorithm>
#include <boost/geometry.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <utility>
#include <vector>

#include "rcppsw/math/vector2.hpp"
#include "rcppsw/math/vector3.hpp"
#include "rcppsw/patterns/decorator/decorator.hpp"

/*******************************************************************************
 * Namespaces/Decls
 ******************************************************************************/
namespace rcppsw::ds {

namespace bg = boost::geometry;
namespace bgi = bg::index;

template <typename TCoordType>
using rtree_point = bg::model::point<typename TCoordType::value_type,
                                     TCoordType::kDIMENSIONALITY,
                                     bg::cs::cartesian>;

template <typename TCoordType>
using rtree_box = bg::model::box<rtree_point<TCoordType>>;

template<typename TCoordType,
         typename TGeometryType,
         typename TValueType,
         size_t MAXELTS = 16>
struct rtree_spec {
  static constexpr const size_t kMAXELTS = 16;

  using coord_type = TCoordType;

  using geometry_type = TGeometryType;

  using value_type = TValueType;

  using element_type = std::pair<geometry_type, value_type>;

  using tree_type = bgi::rtree<element_type, bgi::rstar<MAXELTS>>;
};

/*******************************************************************************
 * Class Definitions
 ******************************************************************************/
template <typename TSpecType>
class rtree : rpdecorator::decorator<typename TSpecType::tree_type> {
 public:
  using spec_type = TSpecType;
  using value_type = typename spec_type::value_type;
  using element_type = typename spec_type::element_type;
  using geometry_type = typename spec_type::geometry_type;
  using coord_type = typename spec_type::coord_type;
  using rpdecorator::decorator<typename spec_type::tree_type>::decoratee;

  rtree(void) = default;

  /* Not move/copy constructable/assignable by default */
  rtree(const rtree&) = delete;
  const rtree& operator=(const rtree&) = delete;
  rtree(rtree&&) = delete;
  rtree& operator=(rtree&&) = delete;

  std::vector<value_type> intersections(const rtree_box<coord_type>& query) const {
    std::vector<element_type> res1;
    res1.reserve(spec_type::kMAXELTS); /* good a guess as any */
    decoratee().query(bgi::intersects(query), std::back_inserter(res1));

    std::vector<value_type> res2;
    res2.reserve(res1.size());
    std::transform(res1.begin(),
                   res1.end(),
                   std::back_inserter(res2),
                   [res2](const auto& pair) { return pair.second; });
    return res2;
  }

  std::vector<value_type> nearest(const rtree_point<coord_type>& query,
                                  size_t k) const {
    std::vector<element_type> res1;
    res1.reserve(spec_type::kMAXELTS); /* good a guess as any */
    decoratee().query(bgi::nearest(query, k), std::back_inserter(res1));

    std::vector<value_type> res2;
    res2.reserve(res1.size());
    std::transform(res1.begin(),
                   res1.end(),
                   std::back_inserter(res2),
                   [res2](const auto& pair) { return pair.second; });
    return res2;
  }

  bool contains(const value_type& key) const {
    auto it =
        std::find_if(decoratee().begin(), decoratee().end(), [key](const auto& pair) {
          return key == pair.second;
        });
    return decoratee().end() != it;
  }

  void insert(const value_type& value, const geometry_type& key) {
    decoratee().insert(element_type(key, value));
  }

  size_t remove(const value_type& value) {
    std::vector<element_type> victims;
    std::copy_if(decoratee().begin(),
                 decoratee().end(),
                 std::back_inserter(victims),
                 [value](const auto& pair) { return value == pair.second; });
    return decoratee().remove(victims.begin(), victims.end());
  }
  size_t remove(const value_type& value, const geometry_type& key) {
    return decoratee().remove(element_type(key, value));
  }

  RCPPSW_DECORATE_DECLDEF(insert);
  RCPPSW_DECORATE_DECLDEF(begin, const);
  RCPPSW_DECORATE_DECLDEF(end, const);
  RCPPSW_DECORATE_DECLDEF(size, const);
};

/*******************************************************************************
 * Free Functions
 ******************************************************************************/
template <typename TCoordType,
          RCPPSW_SFINAE_DECLDEF(rmpl::is_specialization<TCoordType,
                                rmath::vector2>::value)>
rtree_point<TCoordType> make_rtree_point(const TCoordType& c) {
  return rtree_point<TCoordType>(c.x(), c.y());
}

template <typename TCoordType,
          RCPPSW_SFINAE_DECLDEF(rmpl::is_specialization<TCoordType,
                                rmath::vector3>::value)>
rtree_point<TCoordType> make_rtree_point(const TCoordType& c) {
  return rtree_point<TCoordType>(c.x(), c.y(), c.z());
}

template <typename TCoordType,
          RCPPSW_SFINAE_DECLDEF(rmpl::is_specialization<TCoordType,
                                rmath::vector2>::value)>
rtree_box<TCoordType> make_rtree_box(const TCoordType& ll,
                                     const TCoordType& ur) {
  return rtree_box<TCoordType>(rtree_point<TCoordType>(ll.x(),
                                                       ll.y()),
                               rtree_point<TCoordType>(ur.x(),
                                                       ur.y()));
}

template <typename TCoordType,
          RCPPSW_SFINAE_DECLDEF(rmpl::is_specialization<TCoordType,
                                rmath::vector3>::value)>
rtree_box<TCoordType> make_rtree_box(const TCoordType& ll,
                                     const TCoordType& ur) {
  return rtree_box<TCoordType>(rtree_point<TCoordType>(ll.x(),
                                                       ll.y(),
                                                       ll.z()),
                               rtree_point<TCoordType>(ur.x(),
                                                       ur.y(),
                                                       ur.z()));
}

} /* namespace rcppsw::ds */