如何使用模板类设置Boost RTree节点



我有两个文件:header.h和code.cpp,我不能在code.cpp上写任何boost命名空间,所以所有的"boost::geometry::etc"调用header.h。这个想法是实现两个模板类:一个用于RTree,另一个用于RTree节点,这样用户就可以包括header.h文件,并使用header.h上的两个模板类来在code.cpp上实现RTree

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 ) );
}    
};

我得到的一些错误:

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;
|                 ^~~~

在我看来,我必须使用可索引的。尽管我不确定我应该如何使用我已经拥有的代码来完成它。欢迎任何帮助,提前谢谢。

我们不得不猜测BBox是什么。但总的来说,它看起来像你"只是";想要一个节点为(box,name(的树。

我建议跳过Node类(以及所有无论如何都不起作用的泛型,因为您将转换硬编码为Node<T>,只有当几何图形是可转换的(长方体和长方体不相互转换(时才起作用。

在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";
}

打印

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

更多

如果你真的没有显示全貌,并且你需要Node<T>比显示的更多,那么考虑

  • std::pair派生并使用现有的indexable<>实现
  • 提供您自己的IndexeableGetter

在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 {};

没有进一步的更改,仍在打印

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

供将来参考。

我很难理解Boost是如何为用户设置接口以将自己的对象定义为RTree节点的。似乎有不止一种方法可以做到这一点(例如使用宏(。其中之一就是@sehe所指出的,通过使用可索引的函子。因此,这个带有函数描述的笨拙结构Getter是一个重载() operator的函子,这就是Boost知道如何从我自己的类中获取坐标的方式。

最新更新