c++templatesboostr-tree

How to set Boost RTree Node with template class


I have two files: header.h and code.cpp, I can not write any boost namespace on code.cpp, so all "boost::geometry::etc..." calls go on header.h. The idea is to implement two template classes: one for the RTree and other for the RTree Node, this way the user may include the header.h file and implement the RTree on code.cpp using the two template classes on header.h. This is what I have so far:

header.h:

template< class TT > class Node
{
    using PointType     = boost::geometry::model::d2::point_xy< TT >;
    using BoxType       = boost::geometry::model::box< PointType >;
    using NodeType      = std::pair< BoxType, std::string >;
    NodeType node;
public:
    Node(){}
    template< class T >
    Node( const BBox< T > &box, const std::string nodeName ){
        node = std::make_pair( BoxType{ PointType{ box.xLo(), box.yLo() },
                PointType{ box.xHi(), box.yHi() } }, nodeName );
    }
};


template< class TT > class RTree
{
    using RTreeType = boost::geometry::index::rtree< TT, boost::geometry::index::quadratic< 16 > >;
    RTreeType rtree;    
public:
    RTree(){}
    template< T >
    void insertBox( const BBox< T > &box, const std::string nodeName ) {
        rtree.insert( Node< T >( box, nodeName ) );
    }
    
    template< T >
    void query( const BBox< T > &box, std::vector< Node< T > > &queryResult ) {
        rtree.query( boost::geometry::index::intersects( Node< T >( box, "" ) ),
                      std::back_inserter( queryResult ) );
    }    
};

Some of the errors I am getting:

error: could not convert 'boost::geometry::index::detail::indexable<Node<int>, false>::NOT_VALID_INDEXABLE_TYPE31::assert_arg()' from 'mpl_::failed************(boost::geometry::index::detail::indexable<Node<int>, false>::NOT_VALID_INDEXABLE_TYPE::************)(Node<int>)' to 'mpl_::assert<false>::type' {aka 'mpl_::assert<false>'}
31 |     BOOST_MPL_ASSERT_MSG(
|     ^
|     |
|     mpl_::failed************ (boost::geometry::index::detail::indexable<Node<int>, false>::NOT_VALID_INDEXABLE_TYPE::************)(Node<int>)

...

error: could not convert 'boost::geometry::traits::point_type<Node<int> >::NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE45::assert_arg()' from 'mpl_::failed************ (boost::geometry::traits::point_type<Node<int> >::NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE::************)(mpl_::assert_::types<Node<int>, mpl_::na, mpl_::na, mpl_::na>)' to 'mpl_::assert<false>::type' {aka 'mpl_::assert<false>'}
45 |     BOOST_MPL_ASSERT_MSG
|     ^
|     |
|     mpl_::failed************ (boost::geometry::traits::point_type<Node<int> >::NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE::************)(mpl_::assert_::types<Node<int>, mpl_::na, mpl_::na, mpl_::na>)

...

error: no type named 'type' in 'struct boost::geometry::traits::point_type<Node<int> >'
66 |         >::type type;
|                 ^~~~

It seems to me I have to use indexable. Although I am not sure how I am supposed to do it with the code I already have. Any help is welcome, thanks in advance.


Solution

  • We had to guess what BBox is. But all in all it looks like you "just" want a tree with nodes that are (box, name).

    I'd suggest skipping the Node class (and all of the generics that wouldn't work anyways because you hardcoded the conversion to Node<T> anyways, which only works if the geometries were convertable (box and box don't interconvert).

    Live On Coliru

    #include <boost/geometry.hpp>
    #include <boost/geometry/geometries/box.hpp>
    #include <boost/geometry/geometries/point_xy.hpp>
    #include <boost/geometry/index/rtree.hpp>
    namespace bg  = boost::geometry;
    namespace bgi = boost::geometry::index;
    
    namespace detail {
        template <typename Coord> using Point = bg::model::d2::point_xy<Coord>;
        template <typename Coord> using BBox  = bg::model::box<Point<Coord>>;
        template <class Coord> using Node     = std::pair<BBox<Coord>, std::string>;
    }
    
    template <class Coord> struct RTree {
        using Point     = detail::Point<Coord>;
        using Box       = detail::BBox<Coord>;
        using Node      = detail::Node<Coord>;
        using RTreeType = bgi::rtree<Node, bgi::quadratic<16>>;
    
        void insertBox(Box box, const std::string nodeName) {
            rtree.insert(Node(box, nodeName));
        }
    
        using Result = std::vector<Node>;
    
        void query(Box box, Result& queryResult) {
            rtree.query(bgi::intersects(box), back_inserter(queryResult));
        }
    
      private:
        RTreeType rtree;
    };
    
    int main() {
        using Tree = RTree<double>;
        Tree x;
        x.insertBox({{1.0, 2.0}, {7.0, 8.0}}, "first");
        x.insertBox({{2.0, 3.0}, {6.0, 7.0}}, "second");
    
        Tree::Result v;
        x.query({{3.0, 4.0}, {5.0, 6.0}}, v);
    
        for (auto& [box,name] : v)
            std::cout << std::quoted(name) << ": " << bg::wkt(box) << "\n";
    }
    

    Prints

    "first": POLYGON((1 2,1 8,7 8,7 2,1 2))
    "second": POLYGON((2 3,2 7,6 7,6 3,2 3))
    

    More

    If really you're not showing the full picture, and you need Node<T> to be more than shown, consider

    Showing the second Live On Coliru:

    namespace detail {
        template <typename Coord> using Point = bg::model::d2::point_xy<Coord>;
        template <typename Coord> using BBox  = bg::model::box<Point<Coord>>;
    
        template <class Coord> struct Node {
            using Indexable = BBox<Coord>;
            using Id        = std::string;
            Indexable box;
            Id  name;
    
            Node(Indexable b, Id n) : box(std::move(b)), name(std::move(n)) {}
    
            struct Getter {
                using result_type = Indexable const&;
                result_type operator()(Node const& v) const { return v.box; }
            };
        };
    }
    
    template <typename Coord>
    struct bgi::indexable<::detail::Node<Coord>>
        : ::detail::Node<Coord>::Getter {};
    

    No further changes, still printing

    "first": POLYGON((1 2,1 8,7 8,7 2,1 2))
    "second": POLYGON((2 3,2 7,6 7,6 3,2 3))