c08_custom_non_std_example.cpp 8.2 KB

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