Program Listing for File hgrid3D_view_builder.hpp

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

#pragma once

/*******************************************************************************
 * Includes
 ******************************************************************************/
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/filtered_graph.hpp>
#include <boost/optional.hpp>
#include <vector>
#include <algorithm>

#include "rcppsw/ds/graph/graph.hpp"
#include "rcppsw/math/vector3.hpp"

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

/*******************************************************************************
 * Class Definitions
 ******************************************************************************/
template <typename TSpecType>
struct hgrid3D_view_builder {
 public:
  using bgl_impl_type = typename TSpecType::bgl_impl_type;
  using vertex_descriptor = typename bgl_impl_type::vertex_descriptor;
  using edge_descriptor = typename bgl_impl_type::edge_descriptor;

  struct trace_data {
    rmath::vector3z ll{};
    rmath::vector3z ur{};
  };

  hgrid3D_view_builder(const bgl_impl_type& graph,
                       const vertex_descriptor& start,
                       size_t max_dist,
                       boost::optional<rmath::vector3z> axis)
      : mc_max_dist(max_dist),
        m_distances(max_visited_vertices(max_dist)) {
    std::vector<boost::default_color_type> colormap(max_visited_vertices(max_dist));

    /*
     * Record the LL, UR corners of the bounding box for the subgraph to provide
     * efficient computation of graph geometry/bounding box.
     */
    m_trace.ll = m_trace.ur = graph[start].coord;

    auto stop_when = [&](vertex_descriptor vd, const bgl_impl_type&) {
                       m_trace.ll = std::min(m_trace.ll, graph[vd].coord);
                       m_trace.ur = std::max(m_trace.ur, graph[vd].coord);
                       /*
                        * Only vertices that are:
                        *
                        * - Have the same {X,Y,Z} coordinate as the starting
                        *   vertex, depending on the axes (maybe).
                        *
                        * - Are within the max distance from the starting
                        *   vertex.
                        *
                        * Are eligible for inclusion in the filtered graph.
                        */
                       bool same_axis = true;
                       if (axis) {
                         same_axis = graph[vd].coord.mask((*axis)) ==
                                     graph[start].coord.mask((*axis));
                       }
                       bool included = same_axis &&
                                       rmath::l2norm(graph[vd].coord,
                                                     graph[start].coord) <= max_dist;
                       return !included;
                     };

    boost::depth_first_visit(graph,
                             start,
                             make_dfs_visitor(record_distances(m_distances.data(),
                                                               boost::on_tree_edge())),
                             colormap.data(),
                             stop_when);
  }

  bool operator()(edge_descriptor) const { return true; }
  bool operator()(vertex_descriptor vd) const {
    return m_distances[vd] > -1 && m_distances[vd] <= mc_max_dist;
  }

  const trace_data& trace(void) const { return m_trace; }

 private:
  static constexpr size_t max_visited_vertices(size_t max_dist) {
    return static_cast<size_t>(std::pow(2*max_dist, 3));
  }

  /* clang-format off */
  const size_t            mc_max_dist;
  std::vector<double>     m_distances{};
  trace_data              m_trace{};
  /* clang-format on */
};

} /* namespace rcppsw::ds::detail, graph */