1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2015, Oracle and/or its affiliates.
5 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
7 // Licensed under the Boost Software License version 1.0.
8 // http://www.boost.org/users/license.html
10 #ifndef BOOST_GEOMETRY_VIEWS_DETAIL_BOUNDARY_VIEW_IMPLEMENTATION_HPP
11 #define BOOST_GEOMETRY_VIEWS_DETAIL_BOUNDARY_VIEW_IMPLEMENTATION_HPP
21 #include <boost/core/addressof.hpp>
22 #include <boost/iterator.hpp>
23 #include <boost/iterator/iterator_facade.hpp>
24 #include <boost/iterator/iterator_categories.hpp>
25 #include <boost/mpl/assert.hpp>
26 #include <boost/mpl/if.hpp>
27 #include <boost/range.hpp>
28 #include <boost/type_traits/is_const.hpp>
29 #include <boost/type_traits/is_convertible.hpp>
30 #include <boost/type_traits/remove_reference.hpp>
32 #include <boost/geometry/core/assert.hpp>
33 #include <boost/geometry/core/closure.hpp>
34 #include <boost/geometry/core/exterior_ring.hpp>
35 #include <boost/geometry/core/interior_rings.hpp>
36 #include <boost/geometry/core/ring_type.hpp>
37 #include <boost/geometry/core/tags.hpp>
39 #include <boost/geometry/iterators/flatten_iterator.hpp>
41 #include <boost/geometry/util/range.hpp>
43 #include <boost/geometry/views/closeable_view.hpp>
45 #include <boost/geometry/algorithms/num_interior_rings.hpp>
48 namespace boost { namespace geometry
52 #ifndef DOXYGEN_NO_DETAIL
53 namespace detail { namespace boundary_views
60 typename Value = typename ring_type<Polygon>::type,
61 typename Reference = typename ring_return_type<Polygon>::type,
62 typename Difference = typename boost::range_difference
64 typename boost::remove_reference
66 typename interior_return_type<Polygon>::type
70 class polygon_rings_iterator
71 : public boost::iterator_facade
73 polygon_rings_iterator<Polygon, Value, Reference, Difference>,
75 boost::random_access_traversal_tag,
80 typedef typename boost::range_size
82 typename boost::remove_reference
84 typename interior_return_type<Polygon>::type
89 // default constructor
90 polygon_rings_iterator()
96 polygon_rings_iterator(Polygon& polygon)
97 : m_polygon(boost::addressof(polygon))
102 polygon_rings_iterator(Polygon& polygon, bool)
103 : m_polygon(boost::addressof(polygon))
104 , m_index(static_cast<size_type>(num_rings(polygon)))
109 typename OtherPolygon,
111 typename OtherReference,
112 typename OtherDifference
114 polygon_rings_iterator(polygon_rings_iterator
121 : m_polygon(other.m_polygon)
122 , m_index(other.m_index)
124 static const bool is_convertible
125 = boost::is_convertible<OtherPolygon, Polygon>::value;
127 BOOST_MPL_ASSERT_MSG((is_convertible),
129 (types<OtherPolygon>));
133 friend class boost::iterator_core_access;
137 typename OtherPolygon,
139 typename OtherReference,
140 typename OtherDifference
142 friend class polygon_rings_iterator;
145 static inline std::size_t num_rings(Polygon const& polygon)
147 return geometry::num_interior_rings(polygon) + 1;
150 inline Reference dereference() const
154 return exterior_ring(*m_polygon);
156 return range::at(interior_rings(*m_polygon), m_index - 1);
161 typename OtherPolygon,
163 typename OtherReference,
164 typename OtherDifference
166 inline bool equal(polygon_rings_iterator
172 > const& other) const
174 BOOST_GEOMETRY_ASSERT(m_polygon == other.m_polygon);
175 return m_index == other.m_index;
178 inline void increment()
183 inline void decrement()
190 typename OtherPolygon,
192 typename OtherReference,
193 typename OtherDifference
195 inline Difference distance_to(polygon_rings_iterator
201 > const& other) const
203 return static_cast<Difference>(other.m_index)
204 - static_cast<Difference>(m_index);
207 inline void advance(Difference n)
218 template <typename Ring>
219 class ring_boundary : closeable_view<Ring, closure<Ring>::value>::type
222 typedef typename closeable_view<Ring, closure<Ring>::value>::type base_type;
225 typedef typename base_type::iterator iterator;
226 typedef typename base_type::const_iterator const_iterator;
228 typedef linestring_tag tag_type;
230 explicit ring_boundary(Ring& ring)
233 iterator begin() { return base_type::begin(); }
234 iterator end() { return base_type::end(); }
235 const_iterator begin() const { return base_type::begin(); }
236 const_iterator end() const { return base_type::end(); }
240 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
244 template <typename Polygon>
245 struct num_rings<Polygon, polygon_tag>
247 static inline std::size_t apply(Polygon const& polygon)
249 return geometry::num_interior_rings(polygon) + 1;
253 template <typename MultiPolygon>
254 struct num_rings<MultiPolygon, multi_polygon_tag>
256 static inline std::size_t apply(MultiPolygon const& multipolygon)
258 return geometry::num_interior_rings(multipolygon)
259 + static_cast<std::size_t>(boost::size(multipolygon));
264 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
265 struct views_container_initializer
268 template <typename Polygon>
269 struct views_container_initializer<Polygon, polygon_tag>
271 template <typename BoundaryView>
272 static inline void apply(Polygon const& polygon, BoundaryView* views)
274 typedef polygon_rings_iterator<Polygon> rings_iterator_type;
276 std::uninitialized_copy(rings_iterator_type(polygon),
277 rings_iterator_type(polygon, true),
282 template <typename MultiPolygon>
283 class views_container_initializer<MultiPolygon, multi_polygon_tag>
285 typedef typename boost::mpl::if_
287 boost::is_const<MultiPolygon>,
288 typename boost::range_value<MultiPolygon>::type const,
289 typename boost::range_value<MultiPolygon>::type
290 >::type polygon_type;
292 typedef polygon_rings_iterator<polygon_type> inner_iterator_type;
294 struct polygon_rings_begin
296 static inline inner_iterator_type apply(polygon_type& polygon)
298 return inner_iterator_type(polygon);
302 struct polygon_rings_end
304 static inline inner_iterator_type apply(polygon_type& polygon)
306 return inner_iterator_type(polygon, true);
310 typedef flatten_iterator
312 typename boost::range_iterator<MultiPolygon>::type,
314 typename std::iterator_traits<inner_iterator_type>::value_type,
317 typename std::iterator_traits<inner_iterator_type>::reference
318 > rings_iterator_type;
321 template <typename BoundaryView>
322 static inline void apply(MultiPolygon const& multipolygon,
325 rings_iterator_type first(boost::begin(multipolygon),
326 boost::end(multipolygon));
327 rings_iterator_type last(boost::end(multipolygon));
329 std::uninitialized_copy(first, last, views);
334 template <typename Areal>
337 typedef boundary_view<typename ring_type<Areal>::type> boundary_view_type;
338 typedef views_container_initializer<Areal> exception_safe_initializer;
340 template <typename T>
341 struct automatic_deallocator
343 automatic_deallocator(T* ptr) : m_ptr(ptr) {}
345 ~automatic_deallocator()
347 operator delete(m_ptr);
350 inline void release() { m_ptr = NULL; }
355 inline void initialize_views(Areal const& areal)
357 // initialize number of rings
358 std::size_t n_rings = num_rings<Areal>::apply(areal);
365 // allocate dynamic memory
366 boundary_view_type* views_ptr = static_cast
369 >(operator new(sizeof(boundary_view_type) * n_rings));
371 // initialize; if exceptions are thrown by constructors
372 // they are handled automatically by automatic_deallocator
373 automatic_deallocator<boundary_view_type> deallocator(views_ptr);
374 exception_safe_initializer::apply(areal, views_ptr);
375 deallocator.release();
377 // now initialize member variables safely
379 m_num_rings = n_rings;
382 // disallow copies and/or assignments
383 areal_boundary(areal_boundary const&);
384 areal_boundary& operator=(areal_boundary const&);
387 typedef boundary_view_type* iterator;
388 typedef boundary_view_type const* const_iterator;
390 typedef multi_linestring_tag tag_type;
392 explicit areal_boundary(Areal& areal)
396 initialize_views(areal);
401 boundary_view_type* last = m_views + m_num_rings;
402 for (boundary_view_type* it = m_views; it != last; ++it)
404 it->~boundary_view_type();
406 operator delete(m_views);
409 inline iterator begin() { return m_views; }
410 inline iterator end() { return m_views + m_num_rings; }
411 inline const_iterator begin() const { return m_views; }
412 inline const_iterator end() const { return m_views + m_num_rings; }
415 boundary_view_type* m_views;
416 std::size_t m_num_rings;
420 }} // namespace detail::boundary_view
421 #endif // DOXYGEN_NO_DETAIL
424 #ifndef DOXYGEN_NO_DISPATCH
425 namespace detail_dispatch
429 template <typename Ring>
430 struct boundary_view<Ring, ring_tag>
431 : detail::boundary_views::ring_boundary<Ring>
433 explicit boundary_view(Ring& ring)
434 : detail::boundary_views::ring_boundary<Ring>(ring)
438 template <typename Polygon>
439 struct boundary_view<Polygon, polygon_tag>
440 : detail::boundary_views::areal_boundary<Polygon>
442 explicit boundary_view(Polygon& polygon)
443 : detail::boundary_views::areal_boundary<Polygon>(polygon)
447 template <typename MultiPolygon>
448 struct boundary_view<MultiPolygon, multi_polygon_tag>
449 : detail::boundary_views::areal_boundary<MultiPolygon>
451 explicit boundary_view(MultiPolygon& multipolygon)
452 : detail::boundary_views::areal_boundary
460 } // namespace detail_dispatch
461 #endif // DOXYGEN_NO_DISPATCH
464 }} // namespace boost::geometry
466 #endif // BOOST_GEOMETRY_VIEWS_DETAIL_BOUNDARY_VIEW_IMPLEMENTATION_HPP