PageRenderTime 44ms CodeModel.GetById 18ms app.highlight 21ms RepoModel.GetById 1ms app.codeStats 0ms

/Src/Dependencies/Boost/libs/geometry/example/c08_custom_non_std_example.cpp

http://hadesmem.googlecode.com/
C++ | 296 lines | 197 code | 65 blank | 34 comment | 11 complexity | bc4139ca2310f68dbada891ff18dac9f MD5 | raw file
  1// Boost.Geometry (aka GGL, Generic Geometry Library)
  2
  3// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands.
  4// Copyright (c) 2008-2011 Bruno Lalande, Paris, France.
  5// Copyright (c) 2009-2011 Mateusz Loskot, London, UK.
  6
  7// Use, modification and distribution is subject to the Boost Software License,
  8// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  9// http://www.boost.org/LICENSE_1_0.txt)
 10//
 11// Custom polygon example
 12
 13#include <iostream>
 14
 15#include <boost/iterator.hpp>
 16#include <boost/iterator/iterator_adaptor.hpp>
 17#include <boost/iterator/iterator_categories.hpp>
 18#include <boost/iterator/iterator_facade.hpp>
 19
 20
 21#include <boost/geometry/geometry.hpp>
 22#include <boost/geometry/geometries/register/point.hpp>
 23#include <boost/geometry/geometries/register/ring.hpp>
 24#include <boost/geometry/util/add_const_if_c.hpp>
 25
 26// Sample point, having x/y
 27struct my_point
 28{
 29    my_point(double a = 0, double b = 0)
 30        : x(a), y(b)
 31    {}
 32    double x,y;
 33};
 34
 35// Sample polygon, having legacy methods
 36// (similar to e.g. COM objects)
 37class my_polygon
 38{
 39    std::vector<my_point> points;
 40    public :
 41        void add_point(my_point const& p) { points.push_back(p); }
 42
 43        // Const access
 44        my_point const& get_point(std::size_t i) const
 45        {
 46            assert(i < points.size());
 47            return points[i];
 48        }
 49
 50        // Mutable access
 51        my_point & get_point(std::size_t i)
 52        {
 53            assert(i < points.size());
 54            return points[i];
 55        }
 56
 57
 58        int point_count() const { return points.size(); }
 59        void erase_all() { points.clear(); }
 60
 61        inline void set_size(int n) { points.resize(n); }
 62};
 63
 64// ----------------------------------------------------------------------------
 65// Adaption: implement iterator and range-extension, and register with Boost.Geometry
 66
 67// 1) implement iterator (const and non-const versions)
 68template <bool IsConst>
 69struct custom_iterator : public boost::iterator_facade
 70                            <
 71                                custom_iterator<IsConst>,
 72                                my_point,
 73                                boost::random_access_traversal_tag,
 74                                typename boost::geometry::add_const_if_c<IsConst, my_point>::type&
 75                            >
 76{
 77    // Constructor for begin()
 78    explicit custom_iterator(typename boost::geometry::add_const_if_c<IsConst, my_polygon>::type& polygon)
 79        : m_polygon(&polygon)
 80        , m_index(0)
 81    {}
 82
 83    // Constructor for end()
 84    explicit custom_iterator(bool, typename boost::geometry::add_const_if_c<IsConst, my_polygon>::type& polygon)
 85        : m_polygon(&polygon)
 86        , m_index(polygon.point_count())
 87    {}
 88
 89
 90
 91private:
 92    friend class boost::iterator_core_access;
 93
 94    typedef boost::iterator_facade
 95        <
 96            custom_iterator<IsConst>,
 97            my_point,
 98            boost::random_access_traversal_tag,
 99            typename boost::geometry::add_const_if_c<IsConst, my_point>::type&
100        > facade;
101
102    typename boost::geometry::add_const_if_c<IsConst, my_polygon>::type* m_polygon;
103    int m_index;
104
105    bool equal(custom_iterator const& other) const
106    {
107        return this->m_index == other.m_index;
108    }
109    typename facade::difference_type distance_to(custom_iterator const& other) const
110    {
111        return other.m_index - this->m_index;
112    }
113
114    void advance(typename facade::difference_type n)
115    {
116        m_index += n;
117        if(m_polygon != NULL
118            && (m_index >= m_polygon->point_count()
119            || m_index < 0)
120            )
121        {
122            m_index = m_polygon->point_count();
123        }
124    }
125
126    void increment()
127    {
128        advance(1);
129    }
130
131    void decrement()
132    {
133        advance(-1);
134    }
135
136    // const and non-const dereference of this iterator
137    typename boost::geometry::add_const_if_c<IsConst, my_point>::type& dereference() const
138    {
139        return m_polygon->get_point(m_index);
140    }
141};
142
143
144
145
146// 2) Implement Boost.Range const functionality
147//    using method 2, "provide free-standing functions and specialize metafunctions"
148// 2a) meta-functions
149namespace boost
150{
151    template<> struct range_mutable_iterator<my_polygon>
152    {
153        typedef custom_iterator<false> type;
154    };
155
156    template<> struct range_const_iterator<my_polygon>
157    {
158        typedef custom_iterator<true> type;
159    };
160
161    // RangeEx
162    template<> struct range_size<my_polygon>
163    {
164        typedef std::size_t type;
165    };
166
167} // namespace 'boost'
168
169
170// 2b) free-standing function for Boost.Range ADP
171inline custom_iterator<false> range_begin(my_polygon& polygon)
172{
173    return custom_iterator<false>(polygon);
174}
175
176inline custom_iterator<true> range_begin(my_polygon const& polygon)
177{
178    return custom_iterator<true>(polygon);
179}
180
181inline custom_iterator<false> range_end(my_polygon& polygon)
182{
183    return custom_iterator<false>(true, polygon);
184}
185
186inline custom_iterator<true> range_end(my_polygon const& polygon)
187{
188    return custom_iterator<true>(true, polygon);
189}
190
191
192
193// 3) optional, for writable geometries only, implement push_back/resize/clear
194namespace boost { namespace geometry { namespace traits
195{
196
197template<> struct push_back<my_polygon>
198{
199    static inline void apply(my_polygon& polygon, my_point const& point)
200    {
201        polygon.add_point(point);
202    }
203};
204
205template<> struct resize<my_polygon>
206{
207    static inline void apply(my_polygon& polygon, std::size_t new_size)
208    {
209        polygon.set_size(new_size);
210    }
211};
212
213}}}
214
215
216// 4) register with Boost.Geometry
217BOOST_GEOMETRY_REGISTER_POINT_2D(my_point, double, cs::cartesian, x, y)
218
219BOOST_GEOMETRY_REGISTER_RING(my_polygon)
220
221
222// end adaption
223// ----------------------------------------------------------------------------
224
225
226void walk_using_iterator(my_polygon const& polygon)
227{
228    for (custom_iterator<true> it = custom_iterator<true>(polygon);
229        it != custom_iterator<true>(true, polygon);
230        ++it)
231    {
232        std::cout << boost::geometry::dsv(*it) << std::endl;
233    }
234    std::cout << std::endl;
235}
236
237
238void walk_using_range(my_polygon const& polygon)
239{
240    for (boost::range_iterator<my_polygon const>::type it
241            = boost::begin(polygon);
242        it != boost::end(polygon);
243        ++it)
244    {
245        std::cout << boost::geometry::dsv(*it) << std::endl;
246    }
247    std::cout << std::endl;
248}
249
250
251int main()
252{
253    my_polygon container1;
254
255    // Create (as an example) a regular polygon
256    const int n = 5;
257    const double d = (360 / n) * boost::geometry::math::d2r;
258    double a = 0;
259    for (int i = 0; i < n + 1; i++, a += d)
260    {
261        container1.add_point(my_point(sin(a), cos(a)));
262    }
263
264    std::cout << "Walk using Boost.Iterator derivative" << std::endl;
265    walk_using_iterator(container1);
266
267    std::cout << "Walk using Boost.Range extension" << std::endl << std::endl;
268    walk_using_range(container1);
269
270    std::cout << "Use it by Boost.Geometry" << std::endl;
271    std::cout << "Area: " << boost::geometry::area(container1) << std::endl;
272
273    // Container 2 will be modified by Boost.Geometry. Add all points but the last one.
274    my_polygon container2;
275    for (int i = 0; i < n; i++)
276    {
277        // Use here the Boost.Geometry internal way of inserting (but the my_polygon way of getting)
278        boost::geometry::traits::push_back<my_polygon>::apply(container2, container1.get_point(i));
279    }
280
281    std::cout << "Second container is not closed:" << std::endl;
282    walk_using_range(container2);
283
284    // Correct (= close it)
285    boost::geometry::correct(container2);
286
287    std::cout << "Now it is closed:" << std::endl;
288    walk_using_range(container2);
289    std::cout << "Area: " << boost::geometry::area(container2) << std::endl;
290
291    // Use things from std:: using Boost.Range
292    std::reverse(boost::begin(container2), boost::end(container2));
293    std::cout << "Area reversed: " << boost::geometry::area(container2) << std::endl;
294
295    return 0;
296}