...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
#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
namespace boost { namespace geometry { namespace traits { template<> struct tag<QLineString> { typedef linestring_tag type; }; } } } // namespace boost::geometry::traits
#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();}
namespace boost { namespace geometry { namespace traits { template<> struct tag<QRing> { typedef ring_tag type; }; } } } // namespace boost::geometry::traits
#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_; };
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());}
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
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; };
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();}