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