Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to inherit from boost::geometry::model::point?

I'd like to inherit from bg::model::point to extend it with own functionality. The *point*s shall be stored in an rtree.

The following minimal example fails to compile the usage of my derived point (boost 1.54, gcc 4.7.2):

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <iostream>
#include <boost/shared_ptr.hpp>

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

namespace boost { namespace geometry { namespace index {

// apparently necessary:
template <typename Box>
struct indexable< boost::shared_ptr<Box> >
{
    typedef boost::shared_ptr<Box> V;

    typedef Box const& result_type;
    result_type operator()(V const& v) const { return *v; }
};

}}} // namespace boost::geometry::index


namespace { // anonymous namespace

// myPoint
template<typename CoordinateType, std::size_t DimensionCount, typename CoordinateSystem>
class myPoint : public bg::model::point<CoordinateType, DimensionCount, CoordinateSystem>{
public:
    void sayHello(void);
};

template<typename CoordinateType, std::size_t DimensionCount, typename CoordinateSystem>
void myPoint< CoordinateType, DimensionCount, CoordinateSystem >::sayHello() {
    std::cout<<"Hello!"<<std::endl;
}

} // end anonymous namespace

int main(void)
{
    typedef bg::model::point<float, 2, bg::cs::cartesian> point; // boost point version
    typedef myPoint<float, 2, bg::cs::cartesian> mypoint; // custom point version

    // create the rtree using default constructor
    bgi::rtree< boost::shared_ptr<point>, bgi::rstar<16, 4> > rtree; // that works
    bgi::rtree< boost::shared_ptr<mypoint>, bgi::rstar<16, 4> > myrtree; // that doesn't works

    return 0;
}

how can i derive from bg::model::point? or, instead of inheriting, is there a better approach?

thanks!

like image 918
the_ducky Avatar asked Oct 04 '22 08:10

the_ducky


1 Answers

Boost.Geometry requires that your Point type is adapted to the Point Concept described here:

http://www.boost.org/doc/libs/1_54_0/libs/geometry/doc/html/geometry/reference/concepts/concept_point.html

Your derived type myPoint must also be adapted because it's a different type than your base type, model::pointer<>. The reason for this is that the library allows to adapt legacy classes and use them as Geometries without the need for modification.

To adapt it you must either use one of the registration macros or specialize all required traits by yourself. Besides the exmaple mentioned in the comment, see those:

http://www.boost.org/doc/libs/1_54_0/libs/geometry/doc/html/geometry/examples.html

In the second one the Point type is adapted by manual specialization of all required traits, which is the most flexible approach. In your case this would look like this:

namespace boost { namespace geometry { namespace traits {

template <typename C, std::size_t D, typename S>
struct tag< myPoint<C, D, S> >
{
    typedef point_tag type;
};
template <typename C, std::size_t D, typename S>
struct coordinate_type< myPoint<C, D, S> >
{
    typedef C type;
};
template <typename C, std::size_t D, typename S>
struct coordinate_system< myPoint<C, D, S> >
{
    typedef S type;
};
template <typename C, std::size_t D, typename S>
struct dimension< myPoint<C, D, S> >
{
    static const std::size_t value = D;
};
template <typename C, std::size_t D, typename S, std::size_t I>
struct access<myPoint<C, D, S>, I>
{
    static inline C get(myPoint<C, D, S> const& p)
    {
        return p.template get<I>();
    }

    static inline void set(myPoint<C, D, S> & p, C const& v)
    {
        p.template set<I>(v);
    }
};

}}}

Just paste it after your Point definition and you're done.

like image 111
Adam Wulkiewicz Avatar answered Oct 12 '22 12:10

Adam Wulkiewicz