// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_VIEWS_DETAIL_BOUNDARY_VIEW_IMPLEMENTATION_HPP #define BOOST_GEOMETRY_VIEWS_DETAIL_BOUNDARY_VIEW_IMPLEMENTATION_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace boundary_views { template < typename Polygon, typename Value = typename ring_type::type, typename Reference = typename ring_return_type::type, typename Difference = typename boost::range_difference < typename boost::remove_reference < typename interior_return_type::type >::type >::type > class polygon_rings_iterator : public boost::iterator_facade < polygon_rings_iterator, Value, boost::random_access_traversal_tag, Reference, Difference > { typedef typename boost::range_size < typename boost::remove_reference < typename interior_return_type::type >::type >::type size_type; public: // default constructor polygon_rings_iterator() : m_polygon(NULL) , m_index(0) {} // for begin polygon_rings_iterator(Polygon& polygon) : m_polygon(boost::addressof(polygon)) , m_index(0) {} // for end polygon_rings_iterator(Polygon& polygon, bool) : m_polygon(boost::addressof(polygon)) , m_index(static_cast(num_rings(polygon))) {} template < typename OtherPolygon, typename OtherValue, typename OtherReference, typename OtherDifference > polygon_rings_iterator(polygon_rings_iterator < OtherPolygon, OtherValue, OtherReference, OtherDifference > const& other) : m_polygon(other.m_polygon) , m_index(other.m_index) { static const bool is_convertible = boost::is_convertible::value; BOOST_MPL_ASSERT_MSG((is_convertible), NOT_CONVERTIBLE, (types)); } private: friend class boost::iterator_core_access; template < typename OtherPolygon, typename OtherValue, typename OtherReference, typename OtherDifference > friend class polygon_rings_iterator; static inline std::size_t num_rings(Polygon const& polygon) { return geometry::num_interior_rings(polygon) + 1; } inline Reference dereference() const { if (m_index == 0) { return exterior_ring(*m_polygon); } return range::at(interior_rings(*m_polygon), m_index - 1); } template < typename OtherPolygon, typename OtherValue, typename OtherReference, typename OtherDifference > inline bool equal(polygon_rings_iterator < OtherPolygon, OtherValue, OtherReference, OtherDifference > const& other) const { BOOST_GEOMETRY_ASSERT(m_polygon == other.m_polygon); return m_index == other.m_index; } inline void increment() { ++m_index; } inline void decrement() { --m_index; } template < typename OtherPolygon, typename OtherValue, typename OtherReference, typename OtherDifference > inline Difference distance_to(polygon_rings_iterator < OtherPolygon, OtherValue, OtherReference, OtherDifference > const& other) const { return static_cast(other.m_index) - static_cast(m_index); } inline void advance(Difference n) { m_index += n; } private: Polygon* m_polygon; size_type m_index; }; template class ring_boundary : closeable_view::value>::type { private: typedef typename closeable_view::value>::type base_type; public: typedef typename base_type::iterator iterator; typedef typename base_type::const_iterator const_iterator; typedef linestring_tag tag_type; explicit ring_boundary(Ring& ring) : base_type(ring) {} iterator begin() { return base_type::begin(); } iterator end() { return base_type::end(); } const_iterator begin() const { return base_type::begin(); } const_iterator end() const { return base_type::end(); } }; template ::type> struct num_rings {}; template struct num_rings { static inline std::size_t apply(Polygon const& polygon) { return geometry::num_interior_rings(polygon) + 1; } }; template struct num_rings { static inline std::size_t apply(MultiPolygon const& multipolygon) { return geometry::num_interior_rings(multipolygon) + static_cast(boost::size(multipolygon)); } }; template ::type> struct views_container_initializer {}; template struct views_container_initializer { template static inline void apply(Polygon const& polygon, BoundaryView* views) { typedef polygon_rings_iterator rings_iterator_type; std::uninitialized_copy(rings_iterator_type(polygon), rings_iterator_type(polygon, true), views); } }; template class views_container_initializer { typedef typename boost::mpl::if_ < boost::is_const, typename boost::range_value::type const, typename boost::range_value::type >::type polygon_type; typedef polygon_rings_iterator inner_iterator_type; struct polygon_rings_begin { static inline inner_iterator_type apply(polygon_type& polygon) { return inner_iterator_type(polygon); } }; struct polygon_rings_end { static inline inner_iterator_type apply(polygon_type& polygon) { return inner_iterator_type(polygon, true); } }; typedef flatten_iterator < typename boost::range_iterator::type, inner_iterator_type, typename std::iterator_traits::value_type, polygon_rings_begin, polygon_rings_end, typename std::iterator_traits::reference > rings_iterator_type; public: template static inline void apply(MultiPolygon const& multipolygon, BoundaryView* views) { rings_iterator_type first(boost::begin(multipolygon), boost::end(multipolygon)); rings_iterator_type last(boost::end(multipolygon)); std::uninitialized_copy(first, last, views); } }; template class areal_boundary { typedef boundary_view::type> boundary_view_type; typedef views_container_initializer exception_safe_initializer; template struct automatic_deallocator { automatic_deallocator(T* ptr) : m_ptr(ptr) {} ~automatic_deallocator() { operator delete(m_ptr); } inline void release() { m_ptr = NULL; } T* m_ptr; }; inline void initialize_views(Areal const& areal) { // initialize number of rings std::size_t n_rings = num_rings::apply(areal); if (n_rings == 0) { return; } // allocate dynamic memory boundary_view_type* views_ptr = static_cast < boundary_view_type* >(operator new(sizeof(boundary_view_type) * n_rings)); // initialize; if exceptions are thrown by constructors // they are handled automatically by automatic_deallocator automatic_deallocator deallocator(views_ptr); exception_safe_initializer::apply(areal, views_ptr); deallocator.release(); // now initialize member variables safely m_views = views_ptr; m_num_rings = n_rings; } // disallow copies and/or assignments areal_boundary(areal_boundary const&); areal_boundary& operator=(areal_boundary const&); public: typedef boundary_view_type* iterator; typedef boundary_view_type const* const_iterator; typedef multi_linestring_tag tag_type; explicit areal_boundary(Areal& areal) : m_views(NULL) , m_num_rings(0) { initialize_views(areal); } ~areal_boundary() { boundary_view_type* last = m_views + m_num_rings; for (boundary_view_type* it = m_views; it != last; ++it) { it->~boundary_view_type(); } operator delete(m_views); } inline iterator begin() { return m_views; } inline iterator end() { return m_views + m_num_rings; } inline const_iterator begin() const { return m_views; } inline const_iterator end() const { return m_views + m_num_rings; } private: boundary_view_type* m_views; std::size_t m_num_rings; }; }} // namespace detail::boundary_view #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace detail_dispatch { template struct boundary_view : detail::boundary_views::ring_boundary { explicit boundary_view(Ring& ring) : detail::boundary_views::ring_boundary(ring) {} }; template struct boundary_view : detail::boundary_views::areal_boundary { explicit boundary_view(Polygon& polygon) : detail::boundary_views::areal_boundary(polygon) {} }; template struct boundary_view : detail::boundary_views::areal_boundary { explicit boundary_view(MultiPolygon& multipolygon) : detail::boundary_views::areal_boundary < MultiPolygon >(multipolygon) {} }; } // namespace detail_dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_VIEWS_DETAIL_BOUNDARY_VIEW_IMPLEMENTATION_HPP