• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
5 // Copyright (c) 2009-2012 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/assert.hpp>
16 
17 #include <boost/iterator/iterator_adaptor.hpp>
18 #include <boost/iterator/iterator_categories.hpp>
19 #include <boost/iterator/iterator_facade.hpp>
20 
21 
22 #include <boost/geometry/geometry.hpp>
23 #include <boost/geometry/geometries/register/point.hpp>
24 #include <boost/geometry/geometries/register/ring.hpp>
25 #include <boost/geometry/util/add_const_if_c.hpp>
26 
27 // Sample point, having x/y
28 struct my_point
29 {
my_pointmy_point30     my_point(double a = 0, double b = 0)
31         : x(a), y(b)
32     {}
33     double x,y;
34 };
35 
36 // Sample polygon, having legacy methods
37 // (similar to e.g. COM objects)
38 class my_polygon
39 {
40     std::vector<my_point> points;
41     public :
add_point(my_point const & p)42         void add_point(my_point const& p) { points.push_back(p); }
43 
44         // Const access
get_point(std::size_t i) const45         my_point const& get_point(std::size_t i) const
46         {
47             BOOST_ASSERT(i < points.size());
48             return points[i];
49         }
50 
51         // Mutable access
get_point(std::size_t i)52         my_point & get_point(std::size_t i)
53         {
54             BOOST_ASSERT(i < points.size());
55             return points[i];
56         }
57 
58 
point_count() const59         int point_count() const { return points.size(); }
erase_all()60         void erase_all() { points.clear(); }
61 
set_size(int n)62         inline void set_size(int n) { points.resize(n); }
63 };
64 
65 // ----------------------------------------------------------------------------
66 // Adaption: implement iterator and range-extension, and register with Boost.Geometry
67 
68 // 1) implement iterator (const and non-const versions)
69 template<typename MyPolygon>
70 struct custom_iterator : public boost::iterator_facade
71                             <
72                                 custom_iterator<MyPolygon>,
73                                 my_point,
74                                 boost::random_access_traversal_tag,
75                                 typename boost::mpl::if_
76                                     <
77                                         boost::is_const<MyPolygon>,
78                                         my_point const,
79                                         my_point
80                                     >::type&
81                             >
82 {
83     // Constructor for begin()
custom_iteratorcustom_iterator84     explicit custom_iterator(MyPolygon& polygon)
85         : m_polygon(&polygon)
86         , m_index(0)
87     {}
88 
89     // Constructor for end()
custom_iteratorcustom_iterator90     explicit custom_iterator(bool, MyPolygon& polygon)
91         : m_polygon(&polygon)
92         , m_index(polygon.point_count())
93     {}
94 
95 
96     // Default constructor
custom_iteratorcustom_iterator97     explicit custom_iterator()
98         : m_polygon(NULL)
99         , m_index(-1)
100     {}
101 
102     typedef typename boost::mpl::if_
103         <
104             boost::is_const<MyPolygon>,
105             my_point const,
106             my_point
107         >::type my_point_type;
108 
109 private:
110     friend class boost::iterator_core_access;
111 
112 
113     typedef boost::iterator_facade
114         <
115             custom_iterator<MyPolygon>,
116             my_point,
117             boost::random_access_traversal_tag,
118             my_point_type&
119         > facade;
120 
121     MyPolygon* m_polygon;
122     int m_index;
123 
equalcustom_iterator124     bool equal(custom_iterator const& other) const
125     {
126         return this->m_index == other.m_index;
127     }
distance_tocustom_iterator128     typename facade::difference_type distance_to(custom_iterator const& other) const
129     {
130         return other.m_index - this->m_index;
131     }
132 
advancecustom_iterator133     void advance(typename facade::difference_type n)
134     {
135         m_index += n;
136         if(m_polygon != NULL
137             && (m_index >= m_polygon->point_count()
138             || m_index < 0)
139             )
140         {
141             m_index = m_polygon->point_count();
142         }
143     }
144 
incrementcustom_iterator145     void increment()
146     {
147         advance(1);
148     }
149 
decrementcustom_iterator150     void decrement()
151     {
152         advance(-1);
153     }
154 
155     // const and non-const dereference of this iterator
dereferencecustom_iterator156     my_point_type& dereference() const
157     {
158         return m_polygon->get_point(m_index);
159     }
160 };
161 
162 
163 
164 
165 // 2) Implement Boost.Range const functionality
166 //    using method 2, "provide free-standing functions and specialize metafunctions"
167 // 2a) meta-functions
168 namespace boost
169 {
170     template<> struct range_mutable_iterator<my_polygon>
171     {
172         typedef custom_iterator<my_polygon> type;
173     };
174 
175     template<> struct range_const_iterator<my_polygon>
176     {
177         typedef custom_iterator<my_polygon const> type;
178     };
179 
180     // RangeEx
181     template<> struct range_size<my_polygon>
182     {
183         typedef std::size_t type;
184     };
185 
186 } // namespace 'boost'
187 
188 
189 // 2b) free-standing function for Boost.Range ADP
range_begin(my_polygon & polygon)190 inline custom_iterator<my_polygon> range_begin(my_polygon& polygon)
191 {
192     return custom_iterator<my_polygon>(polygon);
193 }
194 
range_begin(my_polygon const & polygon)195 inline custom_iterator<my_polygon const> range_begin(my_polygon const& polygon)
196 {
197     return custom_iterator<my_polygon const>(polygon);
198 }
199 
range_end(my_polygon & polygon)200 inline custom_iterator<my_polygon> range_end(my_polygon& polygon)
201 {
202     return custom_iterator<my_polygon>(true, polygon);
203 }
204 
range_end(my_polygon const & polygon)205 inline custom_iterator<my_polygon const> range_end(my_polygon const& polygon)
206 {
207     return custom_iterator<my_polygon const>(true, polygon);
208 }
209 
210 
211 
212 // 3) optional, for writable geometries only, implement push_back/resize/clear
213 namespace boost { namespace geometry { namespace traits
214 {
215 
216 template<> struct push_back<my_polygon>
217 {
applyboost::geometry::traits::push_back218     static inline void apply(my_polygon& polygon, my_point const& point)
219     {
220         polygon.add_point(point);
221     }
222 };
223 
224 template<> struct resize<my_polygon>
225 {
applyboost::geometry::traits::resize226     static inline void apply(my_polygon& polygon, std::size_t new_size)
227     {
228         polygon.set_size(new_size);
229     }
230 };
231 
232 template<> struct clear<my_polygon>
233 {
applyboost::geometry::traits::clear234     static inline void apply(my_polygon& polygon)
235     {
236         polygon.erase_all();
237     }
238 };
239 
240 }}}
241 
242 
243 // 4) register with Boost.Geometry
BOOST_GEOMETRY_REGISTER_POINT_2D(my_point,double,cs::cartesian,x,y)244 BOOST_GEOMETRY_REGISTER_POINT_2D(my_point, double, cs::cartesian, x, y)
245 
246 BOOST_GEOMETRY_REGISTER_RING(my_polygon)
247 
248 
249 // end adaption
250 // ----------------------------------------------------------------------------
251 
252 
253 void walk_using_iterator(my_polygon const& polygon)
254 {
255     for (custom_iterator<my_polygon const> it = custom_iterator<my_polygon const>(polygon);
256         it != custom_iterator<my_polygon const>(true, polygon);
257         ++it)
258     {
259         std::cout << boost::geometry::dsv(*it) << std::endl;
260     }
261     std::cout << std::endl;
262 }
263 
264 
walk_using_range(my_polygon const & polygon)265 void walk_using_range(my_polygon const& polygon)
266 {
267     for (boost::range_iterator<my_polygon const>::type it
268             = boost::begin(polygon);
269         it != boost::end(polygon);
270         ++it)
271     {
272         std::cout << boost::geometry::dsv(*it) << std::endl;
273     }
274     std::cout << std::endl;
275 }
276 
277 
main()278 int main()
279 {
280     my_polygon container1;
281 
282     // Create (as an example) a regular polygon
283     const int n = 5;
284     const double d = (360 / n) * boost::geometry::math::d2r;
285     double a = 0;
286     for (int i = 0; i < n + 1; i++, a += d)
287     {
288         container1.add_point(my_point(sin(a), cos(a)));
289     }
290 
291     std::cout << "Walk using Boost.Iterator derivative" << std::endl;
292     walk_using_iterator(container1);
293 
294     std::cout << "Walk using Boost.Range extension" << std::endl << std::endl;
295     walk_using_range(container1);
296 
297     std::cout << "Use it by Boost.Geometry" << std::endl;
298     std::cout << "Area: " << boost::geometry::area(container1) << std::endl;
299 
300     // Container 2 will be modified by Boost.Geometry. Add all points but the last one.
301     my_polygon container2;
302     for (int i = 0; i < n; i++)
303     {
304         // Use here the Boost.Geometry internal way of inserting (but the my_polygon way of getting)
305         boost::geometry::traits::push_back<my_polygon>::apply(container2, container1.get_point(i));
306     }
307 
308     std::cout << "Second container is not closed:" << std::endl;
309     walk_using_range(container2);
310 
311     // Correct (= close it)
312     boost::geometry::correct(container2);
313 
314     std::cout << "Now it is closed:" << std::endl;
315     walk_using_range(container2);
316     std::cout << "Area: " << boost::geometry::area(container2) << std::endl;
317 
318     // Use things from std:: using Boost.Range
319     std::reverse(boost::begin(container2), boost::end(container2));
320     std::cout << "Area reversed: " << boost::geometry::area(container2) << std::endl;
321 
322     return 0;
323 }
324