Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Example source code: Adapting a legacy geometry object model

Adaption of QPoint

#include <boost/geometry.hpp>

namespace boost
{
    namespace geometry
    {
        namespace traits
        {
            // Adapt QPoint to Boost.Geometry

            template<> struct tag<QPoint>
            { typedef point_tag type; };

            template<> struct coordinate_type<QPoint>
            { typedef QPoint::double type; };

            template<> struct coordinate_system<QPoint>
            { typedef cs::cartesian type; };

            template<> struct dimension<QPoint> : boost::mpl::int_<2> {};

            template<>
            struct access<QPoint, 0>
            {
                static QPoint::double get(QPoint const& p)
                {
                    return p.x;
                }

                static void set(QPoint& p, QPoint::double const& value)
                {
                    p.x = value;
                }
            };

            template<>
            struct access<QPoint, 1>
            {
                static QPoint::double get(QPoint const& p)
                {
                    return p.y;
                }

                static void set(QPoint& p, QPoint::double const& value)
                {
                    p.y = value;
                }
            };
        }
    }
} // namespace boost::geometry::traits

Adaption of QLineString

namespace boost
{
    namespace geometry
    {
        namespace traits
        {
            template<>
            struct tag<QLineString>
            {
                typedef linestring_tag type;
            };
        }
    }
} // namespace boost::geometry::traits

Boost.Range for QLineString

#include <boost/range.hpp>

namespace boost
{
    template <>
    struct range_iterator<QLineString>
    { typedef std::vector<QPoint*>::iterator type; };

    template<>
    struct range_const_iterator<QLineString>
    { typedef std::vector<QPoint*>::const_iterator type; };
}

inline std::vector<QPoint*>::iterator
range_begin(QLineString& qls) {return qls.points.begin();}

inline std::vector<QPoint*>::iterator
range_end(QLineString& qls) {return qls.points.end();}

inline std::vector<QPoint*>::const_iterator
range_begin(const QLineString& qls) {return qls.points.begin();}

inline std::vector<QPoint*>::const_iterator
range_end(const QLineString& qls) {return qls.points.end();}

Adaption of QRing

namespace boost
{
    namespace geometry
    {
        namespace traits
        {
            template<>
            struct tag<QRing>
            {
                typedef ring_tag type;
            };
        }
    }
} // namespace boost::geometry::traits

Boost.Iterator for QRing

#include <boost/iterator/iterator_facade.hpp>

/* Custom iterator type that flattens a 2D array into a 1D array */
template <class I, // Line iterator type
          class R  // Point reference type
         >
class RingIteratorImpl : public boost::iterator_facade<
        RingIteratorImpl<I,R>, R, std::random_access_iterator_tag, R> //new traversal tag boost::random_access_traversal_tag
{
public:
    RingIteratorImpl() : pointIndex_(0)
    {
    }

    explicit RingIteratorImpl(I lineStringIterCurrent)
    :   lineStringIterCurrent_(lineStringIterCurrent), pointIndex_(0)
    {
    }

    template<class OtherI, class OtherR>
    RingIteratorImpl(RingIteratorImpl<OtherI, OtherR> const& other) :
        lineStringIterCurrent_(other.getLineStrIt()), pointIndex_(other.getPointIdx())
    {
    }

    I getLineStrIt() const {return lineStringIterCurrent_;}

    bool isEmpty() const {return isEmpty;}
    size_t getPointIdx() const {return pointIndex_;}

    typedef typename boost::iterator_facade<RingIteratorImpl<I,R>, R, std::random_access_iterator_tag, R>::difference_type difference_type;

private:
    friend class boost::iterator_core_access;

    void increment()
    {
        ++pointIndex_;
        if (pointIndex_ >= (*lineStringIterCurrent_)->points.size())
        {
            ++lineStringIterCurrent_;
            pointIndex_ = 0;
        }
    }

    void decrement()
    {
        if(pointIndex_>0)
        {
            --pointIndex_;
        }
        else
        {
            --lineStringIterCurrent_;
            pointIndex_ = (*lineStringIterCurrent_)->points.size();
        }
    }

    void advance(difference_type n)
    {
        difference_type counter = n;

        difference_type maxPointIndex, remainderPointIndex;

        while(counter>0)
        {
            maxPointIndex = (*lineStringIterCurrent_)->points.size(),
            remainderPointIndex = maxPointIndex - pointIndex_;

            if(counter>remainderPointIndex)
            {
                counter -= remainderPointIndex;
                ++lineStringIterCurrent_;
            }
            else // (counter<=remainderPointIndex)
            {
                counter = 0;
                pointIndex_ = remainderPointIndex;
            }
        }

    }

    difference_type distance_to(const RingIteratorImpl& other) const
    {
        I currentLineStringIter = getLineStrIt();
        I otherLineStringIter = other.getLineStrIt();

        difference_type count = 0;
        difference_type distance_to_other = std::distance(currentLineStringIter, otherLineStringIter);

        if(distance_to_other < 0)
        {
            count += pointIndex_;

            while(distance_to_other < 0)
            {
            QLineString const* ls = *otherLineStringIter;
            count -= ls->points.size();

            ++otherLineStringIter;
            ++distance_to_other;
            }

            assert(otherLineStringIter==currentLineStringIter);
        }
        else if(distance_to_other > 0)
        {
            count -= pointIndex_;

            while(distance_to_other < 0)
            {
            QLineString const* ls = *currentLineStringIter;
            count += ls->points.size();

            ++currentLineStringIter;
            --distance_to_other;
            }

            assert(otherLineStringIter==currentLineStringIter);
        }
        else
        {
            count = pointIndex_ - other.getPointIdx();
        }

        return count;
    }

    bool equal(const RingIteratorImpl& other) const
    {
        return (lineStringIterCurrent_ == other.getLineStrIt()) &&
               (pointIndex_ == other.getPointIdx());
    }

    R dereference() const {return *(*lineStringIterCurrent_)->points[pointIndex_];}


    I lineStringIterCurrent_;

    bool empty;
    size_t pointIndex_;
};

Boost.Range for QRing

typedef RingIteratorImpl<std::vector<QLineString*>::iterator, QPoint> RingIterator;
typedef RingIteratorImpl<std::vector<QLineString*>::const_iterator, const QPoint> ConstRingIterator;

namespace boost
{
    // Specialize metafunctions. We must include the range.hpp header.
    // We must open the 'boost' namespace.

    template <>
    struct range_iterator<QRing>
    { typedef RingIterator type; };

    template<>
    struct range_const_iterator<QRing>
    { typedef ConstRingIterator type; };

} // namespace 'boost'


// The required Range functions. These should be defined in the same namespace
// as Ring.

inline RingIterator range_begin(QRing& r)
{return RingIterator(r.lines.begin());}

inline ConstRingIterator range_begin(const QRing& r)
{return ConstRingIterator(r.lines.begin());}

inline RingIterator range_end(QRing& r)
{return RingIterator(r.lines.end());}

inline ConstRingIterator range_end(const QRing& r)
{return ConstRingIterator(r.lines.end());}

Adaption of QPolygon

namespace boost {
    namespace geometry {
        namespace traits {
            template<> struct tag<QPolygon> { typedef polygon_tag type; };
            template<> struct ring_const_type<QPolygon> { typedef const QRing& type; };
            template<> struct ring_mutable_type<QPolygon> { typedef QRing& type; };
            template<> struct interior_const_type<QPolygon> { typedef const CustomPolygonRingRange type; };
            template<> struct interior_mutable_type<QPolygon> { typedef CustomPolygonRingRange type; };

            template<> struct exterior_ring<QPolygon>
            {
                static QRing& get(QPolygon& p)
                {
                    return (*p.exterior);
                }
                static QRing const& get(QPolygon const& p)
                {
                    return (*p.exterior);
                }
            };

            template<> struct interior_rings<QPolygon>
            {
                static CustomPolygonRingRange get(QPolygon& p)
                {
                    return CustomPolygonRingRange(PolygonRingIterator(p.interiors.begin()), PolygonRingIterator(p.interiors.end()));
                }
                static const CustomPolygonRingRange get(QPolygon const& p)
                {
                    return CustomPolygonRingRange(ConstPolygonRingIterator(p.interiors.begin()), ConstPolygonRingIterator(p.interiors.end()));
                }
            };
        }
    }
} // namespace boost::geometry::traits

Boost.Iterator for QRings in QPolygon

template <class I, // Line iterator type
          class R  // Point reference type
         >
class PolyRingIterator : public boost::iterator_facade<
        PolyRingIterator<I,R>, R, std::random_access_iterator_tag, R> //new traversal tag
{
public:
    PolyRingIterator() {}

    explicit PolyRingIterator(I ringIter) : _ringIter(ringIter) {}

    template<class OtherI, class OtherR>
    PolyRingIterator(PolyRingIterator<OtherI, OtherR> const& other) :
        _ringIter(other.getRingIter()) {}

    I getRingIter() const {return _ringIter;}

    typedef typename boost::iterator_facade<PolyRingIterator<I,R>, R, std::random_access_iterator_tag, R>::difference_type difference_type;

private:
    friend class boost::iterator_core_access;

    void increment()
    {
        ++_ringIter;
    }

    void decrement()
    {
        --_ringIter;
    }

    void advance(difference_type n)
    {
        std::advance(_ringIter,n);
    }

    difference_type distance_to(const PolyRingIterator& other) const
    {
        return std::distance(_ringIter, other.getRingIter());
    }

    bool equal(const PolyRingIterator& other) const
    {
        return _ringIter == other.getRingIter();
    }

    R dereference() const {return *(*_ringIter);}

    I _ringIter;
};

Boost.Range for PolygonRingIterator

typedef PolyRingIterator<std::vector<QRing*>::iterator, QRing> PolygonRingIterator;
typedef PolyRingIterator<std::vector<QRing*>::const_iterator, const QRing> ConstPolygonRingIterator;

class CustomPolygonRingRange
{
    PolygonRingIterator _begin;
    PolygonRingIterator _end;

    bool isIterSet;

    ConstPolygonRingIterator _cbegin;
    ConstPolygonRingIterator _cend;

    bool isCIterSet;

public:

    CustomPolygonRingRange(PolygonRingIterator begin, PolygonRingIterator end) : _begin(begin), _end(end), isIterSet(true) {}
    CustomPolygonRingRange(ConstPolygonRingIterator begin, ConstPolygonRingIterator end) : _cbegin(begin), _cend(end), isCIterSet(true) {}

    PolygonRingIterator begin()
    {
        assert(isIterSet);
        return _begin;
    }

    ConstPolygonRingIterator cbegin() const
    {
        assert(isCIterSet);
        return _cbegin;
    }

    PolygonRingIterator end()
    {
        assert(isIterSet);
        return _end;
    }

    ConstPolygonRingIterator cend() const
    {
        assert(isCIterSet);
        return _cend;
    }
};

namespace boost
{
    // Specialize metafunctions. We must include the range.hpp header.
    // We must open the 'boost' namespace.

    template <>
    struct range_iterator<CustomPolygonRingRange> { typedef PolygonRingIterator type; };

    template<>
    struct range_const_iterator<CustomPolygonRingRange> { typedef ConstPolygonRingIterator type; };

} // namespace 'boost'


// The required Range functions. These should be defined in the same namespace
// as Ring.

inline PolygonRingIterator range_begin(CustomPolygonRingRange& r)
    {return r.begin();}

inline ConstPolygonRingIterator range_begin(const CustomPolygonRingRange& r)
    {return r.cbegin();}

inline PolygonRingIterator range_end(CustomPolygonRingRange& r)
    {return r.end();}

inline ConstPolygonRingIterator range_end(const CustomPolygonRingRange& r)
    {return r.cend();}

PrevUpHomeNext