1
// Boost.Geometry (aka GGL, Generic Geometry Library)
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.
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)
11
// Custom polygon example
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>
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>
26
// Sample point, having x/y
29
my_point(double a = 0, double b = 0)
35
// Sample polygon, having legacy methods
36
// (similar to e.g. COM objects)
39
std::vector<my_point> points;
41
void add_point(my_point const& p) { points.push_back(p); }
44
my_point const& get_point(std::size_t i) const
46
assert(i < points.size());
51
my_point & get_point(std::size_t i)
53
assert(i < points.size());
58
int point_count() const { return points.size(); }
59
void erase_all() { points.clear(); }
61
inline void set_size(int n) { points.resize(n); }
64
// ----------------------------------------------------------------------------
65
// Adaption: implement iterator and range-extension, and register with Boost.Geometry
67
// 1) implement iterator (const and non-const versions)
68
template <bool IsConst>
69
struct custom_iterator : public boost::iterator_facade
71
custom_iterator<IsConst>,
73
boost::random_access_traversal_tag,
74
typename boost::geometry::add_const_if_c<IsConst, my_point>::type&
77
// Constructor for begin()
78
explicit custom_iterator(typename boost::geometry::add_const_if_c<IsConst, my_polygon>::type& polygon)
83
// Constructor for end()
84
explicit custom_iterator(bool, typename boost::geometry::add_const_if_c<IsConst, my_polygon>::type& polygon)
86
, m_index(polygon.point_count())
92
friend class boost::iterator_core_access;
94
typedef boost::iterator_facade
96
custom_iterator<IsConst>,
98
boost::random_access_traversal_tag,
99
typename boost::geometry::add_const_if_c<IsConst, my_point>::type&
102
typename boost::geometry::add_const_if_c<IsConst, my_polygon>::type* m_polygon;
105
bool equal(custom_iterator const& other) const
107
return this->m_index == other.m_index;
109
typename facade::difference_type distance_to(custom_iterator const& other) const
111
return other.m_index - this->m_index;
114
void advance(typename facade::difference_type n)
118
&& (m_index >= m_polygon->point_count()
122
m_index = m_polygon->point_count();
136
// const and non-const dereference of this iterator
137
typename boost::geometry::add_const_if_c<IsConst, my_point>::type& dereference() const
139
return m_polygon->get_point(m_index);
146
// 2) Implement Boost.Range const functionality
147
// using method 2, "provide free-standing functions and specialize metafunctions"
148
// 2a) meta-functions
151
template<> struct range_mutable_iterator<my_polygon>
153
typedef custom_iterator<false> type;
156
template<> struct range_const_iterator<my_polygon>
158
typedef custom_iterator<true> type;
162
template<> struct range_size<my_polygon>
164
typedef std::size_t type;
167
} // namespace 'boost'
170
// 2b) free-standing function for Boost.Range ADP
171
inline custom_iterator<false> range_begin(my_polygon& polygon)
173
return custom_iterator<false>(polygon);
176
inline custom_iterator<true> range_begin(my_polygon const& polygon)
178
return custom_iterator<true>(polygon);
181
inline custom_iterator<false> range_end(my_polygon& polygon)
183
return custom_iterator<false>(true, polygon);
186
inline custom_iterator<true> range_end(my_polygon const& polygon)
188
return custom_iterator<true>(true, polygon);
193
// 3) optional, for writable geometries only, implement push_back/resize/clear
194
namespace boost { namespace geometry { namespace traits
197
template<> struct push_back<my_polygon>
199
static inline void apply(my_polygon& polygon, my_point const& point)
201
polygon.add_point(point);
205
template<> struct resize<my_polygon>
207
static inline void apply(my_polygon& polygon, std::size_t new_size)
209
polygon.set_size(new_size);
216
// 4) register with Boost.Geometry
217
BOOST_GEOMETRY_REGISTER_POINT_2D(my_point, double, cs::cartesian, x, y)
219
BOOST_GEOMETRY_REGISTER_RING(my_polygon)
223
// ----------------------------------------------------------------------------
226
void walk_using_iterator(my_polygon const& polygon)
228
for (custom_iterator<true> it = custom_iterator<true>(polygon);
229
it != custom_iterator<true>(true, polygon);
232
std::cout << boost::geometry::dsv(*it) << std::endl;
234
std::cout << std::endl;
238
void walk_using_range(my_polygon const& polygon)
240
for (boost::range_iterator<my_polygon const>::type it
241
= boost::begin(polygon);
242
it != boost::end(polygon);
245
std::cout << boost::geometry::dsv(*it) << std::endl;
247
std::cout << std::endl;
253
my_polygon container1;
255
// Create (as an example) a regular polygon
257
const double d = (360 / n) * boost::geometry::math::d2r;
259
for (int i = 0; i < n + 1; i++, a += d)
261
container1.add_point(my_point(sin(a), cos(a)));
264
std::cout << "Walk using Boost.Iterator derivative" << std::endl;
265
walk_using_iterator(container1);
267
std::cout << "Walk using Boost.Range extension" << std::endl << std::endl;
268
walk_using_range(container1);
270
std::cout << "Use it by Boost.Geometry" << std::endl;
271
std::cout << "Area: " << boost::geometry::area(container1) << std::endl;
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++)
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));
281
std::cout << "Second container is not closed:" << std::endl;
282
walk_using_range(container2);
284
// Correct (= close it)
285
boost::geometry::correct(container2);
287
std::cout << "Now it is closed:" << std::endl;
288
walk_using_range(container2);
289
std::cout << "Area: " << boost::geometry::area(container2) << std::endl;
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;