1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands.
4 
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 #ifndef BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_RING_PROXY_HPP
10 #define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_RING_PROXY_HPP
11 
12 // Adapts Geometries from Boost.Polygon for usage in Boost.Geometry
13 // boost::polygon::polygon_with_holes_data -> boost::geometry::polygon
14 //   pair{begin_points, end_points} -> ring_proxy
15 
16 #include <boost/polygon/polygon.hpp>
17 #include <boost/range.hpp>
18 
19 
20 
21 namespace boost { namespace geometry
22 {
23 
24 namespace adapt { namespace bp
25 {
26 
27 namespace detail
28 {
29 
30 template <bool Mutable>
31 struct modify
32 {};
33 
34 template <>
35 struct modify<true>
36 {
37     template <typename Ring, typename Point>
push_backboost::geometry::adapt::bp::detail::modify38     static inline void push_back(Ring& ring, Point const& point)
39     {
40         // Boost.Polygon's polygons are not appendable. So create a temporary vector,
41         // add a record and set it to the original. Of course: this is not efficient.
42         // But there seems no other way (without using a wrapper)
43         std::vector<Point> temporary_vector
44             (
45                 boost::polygon::begin_points(ring),
46                 boost::polygon::end_points(ring)
47             );
48         temporary_vector.push_back(point);
49         boost::polygon::set_points(ring, temporary_vector.begin(), temporary_vector.end());
50     }
51 
52 };
53 
54 template <>
55 struct modify<false>
56 {
57     template <typename Ring, typename Point>
push_backboost::geometry::adapt::bp::detail::modify58     static inline void push_back(Ring& ring, Point const& point)
59     {
60     }
61 
62 };
63 
64 
65 }
66 
67 
68 // Polygon should implement the boost::polygon::polygon_with_holes_concept
69 // Specify constness in the template parameter if necessary
70 template<typename Polygon>
71 class ring_proxy
72 {
73 public :
74     typedef typename boost::polygon::polygon_traits
75         <
76             typename boost::remove_const<Polygon>::type
77         >::iterator_type iterator_type;
78 
79     typedef typename boost::polygon::polygon_with_holes_traits
80         <
81             typename boost::remove_const<Polygon>::type
82         >::iterator_holes_type hole_iterator_type;
83 
84     static const bool is_mutable = !boost::is_const<Polygon>::type::value;
85 
ring_proxy(Polygon & p)86     inline ring_proxy(Polygon& p)
87         : m_polygon_pointer(&p)
88         , m_do_hole(false)
89     {}
90 
91     // Constructor used from hole_iterator
ring_proxy(Polygon & p,hole_iterator_type hole_it)92     inline ring_proxy(Polygon& p, hole_iterator_type hole_it)
93         : m_polygon_pointer(&p)
94         , m_do_hole(true)
95         , m_hole_it(hole_it)
96     {}
97 
98     // Default constructor, for mutable polygons / appending (interior) rings
ring_proxy()99     inline ring_proxy()
100         : m_polygon_pointer(&m_polygon_for_default_constructor)
101         , m_do_hole(false)
102     {}
103 
104 
begin() const105     iterator_type begin() const
106     {
107         return m_do_hole
108             ? boost::polygon::begin_points(*m_hole_it)
109             : boost::polygon::begin_points(*m_polygon_pointer)
110             ;
111     }
112 
begin()113     iterator_type begin()
114     {
115         return m_do_hole
116             ? boost::polygon::begin_points(*m_hole_it)
117             : boost::polygon::begin_points(*m_polygon_pointer)
118             ;
119     }
120 
end() const121     iterator_type end() const
122     {
123         return m_do_hole
124             ? boost::polygon::end_points(*m_hole_it)
125             : boost::polygon::end_points(*m_polygon_pointer)
126             ;
127     }
128 
end()129     iterator_type end()
130     {
131         return m_do_hole
132             ? boost::polygon::end_points(*m_hole_it)
133             : boost::polygon::end_points(*m_polygon_pointer)
134             ;
135     }
136 
137     // Mutable
clear()138     void clear()
139     {
140         Polygon p;
141         if (m_do_hole)
142         {
143             // Does NOT work see comment above
144         }
145         else
146         {
147             boost::polygon::set_points(*m_polygon_pointer,
148                 boost::polygon::begin_points(p),
149                 boost::polygon::end_points(p));
150         }
151     }
152 
resize(std::size_t)153     void resize(std::size_t /*new_size*/)
154     {
155         if (m_do_hole)
156         {
157             // Does NOT work see comment above
158         }
159         else
160         {
161             // TODO: implement this by resizing the container
162         }
163     }
164 
165 
166 
167     template <typename Point>
push_back(Point const & point)168     void push_back(Point const& point)
169     {
170         if (m_do_hole)
171         {
172             //detail::modify<is_mutable>::push_back(*m_hole_it, point);
173             //std::cout << "HOLE: " << typeid(*m_hole_it).name() << std::endl;
174             //std::cout << "HOLE: " << typeid(m_hole_it).name() << std::endl;
175             //std::cout << "HOLE: " << typeid(hole_iterator_type).name() << std::endl;
176 
177             // Note, ths does NOT work because hole_iterator_type is defined
178             // as a const_iterator by Boost.Polygon
179 
180         }
181         else
182         {
183             detail::modify<is_mutable>::push_back(*m_polygon_pointer, point);
184         }
185     }
186 
187 private :
188     Polygon* m_polygon_pointer;
189     bool m_do_hole;
190     hole_iterator_type m_hole_it;
191 
192     Polygon m_polygon_for_default_constructor;
193 };
194 
195 
196 
197 
198 // Support geometry::adapt::bp::ring_proxy for Boost.Range ADP
199 template<typename Polygon>
200 inline typename boost::geometry::adapt::bp::ring_proxy<Polygon>::iterator_type
range_begin(boost::geometry::adapt::bp::ring_proxy<Polygon> & proxy)201             range_begin(boost::geometry::adapt::bp::ring_proxy<Polygon>& proxy)
202 {
203     return proxy.begin();
204 }
205 
206 template<typename Polygon>
207 inline typename boost::geometry::adapt::bp::ring_proxy<Polygon const>::iterator_type
range_begin(boost::geometry::adapt::bp::ring_proxy<Polygon const> const & proxy)208             range_begin(boost::geometry::adapt::bp::ring_proxy<Polygon const> const& proxy)
209 {
210     return proxy.begin();
211 }
212 
213 template<typename Polygon>
214 inline typename boost::geometry::adapt::bp::ring_proxy<Polygon>::iterator_type
range_end(boost::geometry::adapt::bp::ring_proxy<Polygon> & proxy)215             range_end(boost::geometry::adapt::bp::ring_proxy<Polygon>& proxy)
216 {
217     return proxy.end();
218 }
219 
220 template<typename Polygon>
221 inline typename boost::geometry::adapt::bp::ring_proxy<Polygon const>::iterator_type
range_end(boost::geometry::adapt::bp::ring_proxy<Polygon const> const & proxy)222             range_end(boost::geometry::adapt::bp::ring_proxy<Polygon const> const& proxy)
223 {
224     return proxy.end();
225 }
226 
227 
228 
229 
230 }} // namespace adapt::bp
231 
232 
233 namespace traits
234 {
235 
236 template <typename Polygon>
237 struct tag<adapt::bp::ring_proxy<Polygon> >
238 {
239     typedef ring_tag type;
240 };
241 
242 
243 template <typename Polygon>
244 struct rvalue_type<adapt::bp::ring_proxy<Polygon> >
245 {
246     typedef adapt::bp::ring_proxy<Polygon> type;
247 };
248 
249 template <typename Polygon>
250 struct clear<adapt::bp::ring_proxy<Polygon> >
251 {
applyboost::geometry::traits::clear252     static inline void apply(adapt::bp::ring_proxy<Polygon> proxy)
253     {
254         proxy.clear();
255     }
256 };
257 
258 
259 template <typename Polygon>
260 struct resize<adapt::bp::ring_proxy<Polygon> >
261 {
applyboost::geometry::traits::resize262     static inline void apply(adapt::bp::ring_proxy<Polygon> proxy, std::size_t new_size)
263     {
264         proxy.resize(new_size);
265     }
266 };
267 
268 template <typename Polygon>
269 struct push_back<adapt::bp::ring_proxy<Polygon> >
270 {
applyboost::geometry::traits::push_back271     static inline void apply(adapt::bp::ring_proxy<Polygon> proxy,
272         typename boost::polygon::polygon_traits<Polygon>::point_type const& point)
273     {
274         proxy.push_back(point);
275     }
276 };
277 
278 
279 } // namespace traits
280 
281 }} // namespace boost::geometry
282 
283 // Specialize ring_proxy for Boost.Range
284 namespace boost
285 {
286     template<typename Polygon>
287     struct range_mutable_iterator<geometry::adapt::bp::ring_proxy<Polygon> >
288     {
289         typedef typename geometry::adapt::bp::ring_proxy<Polygon>::iterator_type type;
290     };
291 
292     template<typename Polygon>
293     struct range_const_iterator<geometry::adapt::bp::ring_proxy<Polygon> >
294     {
295         typedef typename geometry::adapt::bp::ring_proxy<Polygon const>::iterator_type type;
296     };
297 
298 } // namespace boost
299 
300 
301 #endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_RING_PROXY_HPP
302