Program Listing for File base_grid2D.hpp

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

#pragma once

/*******************************************************************************
 * Includes
 ******************************************************************************/
#include <algorithm>
#include <boost/multi_array.hpp>

#include "rcppsw/math/vector2.hpp"

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

/*******************************************************************************
 * Class Definitions
 ******************************************************************************/
template <typename T>
class base_grid2D {
 public:
  using value_type = T;
  using coord_type = math::vector2z;

  using grid_type = typename boost::multi_array<T, 2>;
  using grid_view = typename grid_type::template array_view<2>::type;
  using const_grid_view = typename grid_type::template const_array_view<2>::type;
  using index_range = typename grid_type::index_range;

  base_grid2D(void) = default;
  virtual ~base_grid2D(void) = default;

  virtual size_t xsize(void) const = 0;

  virtual size_t ysize(void) const = 0;

  virtual T& access(size_t i, size_t j) = 0;

  T& access(const coord_type& c) { return access(c.x(), c.y()); }

  RCPPSW_PURE T& operator[](const coord_type& c) { return access(c); }
  RCPPSW_PURE const T& operator[](const coord_type& c) const {
    return access(c);
  }

  const T& access(const coord_type& c) const {
    return const_cast<base_grid2D*>(this)->access(c);
  }
  const T& access(size_t i, size_t j) const {
    return const_cast<base_grid2D*>(this)->access(i, j);
  }

  bool contains(size_t i, size_t j) {
    return i < xsize() && j < ysize();
  }

  bool contains(const coord_type& pt) {
    return contains(pt.x(), pt.y());
  }

  grid_view subcircle(const coord_type& c, size_t radius) {
    auto ll_x =
        std::max<int>(0, static_cast<int>(c.x()) - static_cast<int>(radius));
    auto ll_y =
        std::max<int>(0, static_cast<int>(c.y()) - static_cast<int>(radius));

    /*
     * boost uses half open interval for index ranges, and we want a closed
     * interval, so we +1.
     */
    auto ur_x = std::min(c.x() + radius + 1, xsize() - 1);
    auto ur_y = std::min(c.y() + radius + 1, ysize() - 1);

    coord_type ll(ll_x, ll_y);
    coord_type ur(ur_x, ur_y);

    return subgrid(ll, ur);
  }

  const_grid_view subcircle(const coord_type& c, size_t radius) const {
    auto ll_x =
        std::max<int>(0, static_cast<int>(c.x()) - static_cast<int>(radius));
    auto ll_y =
        std::max<int>(0, static_cast<int>(c.y()) - static_cast<int>(radius));

    /*
     * boost uses half open interval for index ranges, and we want a closed
     * interval, so we +1.
     */
    auto ur_x = std::min(c.x() + radius + 1, xsize());
    auto ur_y = std::min(c.y() + radius + 1, ysize());

    coord_type ll(ll_x, ll_y);
    coord_type ur(ur_x, ur_y);
    return subgrid(ll, ur);
  }

  grid_view subgrid(const coord_type& ll, const coord_type& ur) {
    /*
     * boost uses half open interval for index ranges, and we want a closed
     * interval, so we +1.
     */
    index_range x(ll.x(), ur.x() + 1, 1);
    index_range y(ll.y(), ur.y() + 1, 1);
    return grid_view(grid()[boost::indices[x][y]]);
  }

  const_grid_view subgrid(const coord_type& ll,
                          const coord_type& ur) const {
    index_range x(ll.x(), ur.x(), 1);
    index_range y(ll.y(), ur.y(), 1);
    return const_grid_view(grid()[boost::indices[x][y]]);
  }

 protected:
  virtual const grid_type& grid(void) const = 0;
  virtual grid_type& grid(void) = 0;
};

} /* namespace rcppsw::ds */