| Home | Libraries | People | FAQ | More

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