// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_RING_PROXY_HPP #define BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_RING_PROXY_HPP // Adapts Geometries from Boost.Polygon for usage in Boost.Geometry // boost::polygon::polygon_with_holes_data -> boost::geometry::polygon // pair{begin_points, end_points} -> ring_proxy #include #include namespace boost { namespace geometry { namespace adapt { namespace bp { namespace detail { template struct modify {}; template <> struct modify { template static inline void push_back(Ring& ring, Point const& point) { // Boost.Polygon's polygons are not appendable. So create a temporary vector, // add a record and set it to the original. Of course: this is not efficient. // But there seems no other way (without using a wrapper) std::vector temporary_vector ( boost::polygon::begin_points(ring), boost::polygon::end_points(ring) ); temporary_vector.push_back(point); boost::polygon::set_points(ring, temporary_vector.begin(), temporary_vector.end()); } }; template <> struct modify { template static inline void push_back(Ring& /*ring*/, Point const& /*point*/) { } }; } // Polygon should implement the boost::polygon::polygon_with_holes_concept // Specify constness in the template parameter if necessary template class ring_proxy { public : typedef typename boost::polygon::polygon_traits < typename boost::remove_const::type >::iterator_type iterator_type; typedef typename boost::polygon::polygon_with_holes_traits < typename boost::remove_const::type >::iterator_holes_type hole_iterator_type; static const bool is_mutable = !boost::is_const::type::value; inline ring_proxy(Polygon& p) : m_polygon_pointer(&p) , m_do_hole(false) {} // Constructor used from hole_iterator inline ring_proxy(Polygon& p, hole_iterator_type hole_it) : m_polygon_pointer(&p) , m_do_hole(true) , m_hole_it(hole_it) {} // Default constructor, for mutable polygons / appending (interior) rings inline ring_proxy() : m_polygon_pointer(&m_polygon_for_default_constructor) , m_do_hole(false) {} iterator_type begin() const { return m_do_hole ? boost::polygon::begin_points(*m_hole_it) : boost::polygon::begin_points(*m_polygon_pointer) ; } iterator_type begin() { return m_do_hole ? boost::polygon::begin_points(*m_hole_it) : boost::polygon::begin_points(*m_polygon_pointer) ; } iterator_type end() const { return m_do_hole ? boost::polygon::end_points(*m_hole_it) : boost::polygon::end_points(*m_polygon_pointer) ; } iterator_type end() { return m_do_hole ? boost::polygon::end_points(*m_hole_it) : boost::polygon::end_points(*m_polygon_pointer) ; } // Mutable void clear() { Polygon p; if (m_do_hole) { // Does NOT work see comment above } else { boost::polygon::set_points(*m_polygon_pointer, boost::polygon::begin_points(p), boost::polygon::end_points(p)); } } void resize(std::size_t /*new_size*/) { if (m_do_hole) { // Does NOT work see comment above } else { // TODO: implement this by resizing the container } } template void push_back(Point const& point) { if (m_do_hole) { //detail::modify::push_back(*m_hole_it, point); //std::cout << "HOLE: " << typeid(*m_hole_it).name() << std::endl; //std::cout << "HOLE: " << typeid(m_hole_it).name() << std::endl; //std::cout << "HOLE: " << typeid(hole_iterator_type).name() << std::endl; // Note, ths does NOT work because hole_iterator_type is defined // as a const_iterator by Boost.Polygon } else { detail::modify::push_back(*m_polygon_pointer, point); } } private : Polygon* m_polygon_pointer; bool m_do_hole; hole_iterator_type m_hole_it; Polygon m_polygon_for_default_constructor; }; // Support geometry::adapt::bp::ring_proxy for Boost.Range ADP template inline typename boost::geometry::adapt::bp::ring_proxy::iterator_type range_begin(boost::geometry::adapt::bp::ring_proxy& proxy) { return proxy.begin(); } template inline typename boost::geometry::adapt::bp::ring_proxy::iterator_type range_begin(boost::geometry::adapt::bp::ring_proxy const& proxy) { return proxy.begin(); } template inline typename boost::geometry::adapt::bp::ring_proxy::iterator_type range_end(boost::geometry::adapt::bp::ring_proxy& proxy) { return proxy.end(); } template inline typename boost::geometry::adapt::bp::ring_proxy::iterator_type range_end(boost::geometry::adapt::bp::ring_proxy const& proxy) { return proxy.end(); } }} // namespace adapt::bp namespace traits { template struct tag > { typedef ring_tag type; }; template struct rvalue_type > { typedef adapt::bp::ring_proxy type; }; template struct clear > { static inline void apply(adapt::bp::ring_proxy proxy) { proxy.clear(); } }; template struct resize > { static inline void apply(adapt::bp::ring_proxy proxy, std::size_t new_size) { proxy.resize(new_size); } }; template struct push_back > { static inline void apply(adapt::bp::ring_proxy proxy, typename boost::polygon::polygon_traits::point_type const& point) { proxy.push_back(point); } }; } // namespace traits }} // namespace boost::geometry // Specialize ring_proxy for Boost.Range namespace boost { template struct range_mutable_iterator > { typedef typename geometry::adapt::bp::ring_proxy::iterator_type type; }; template struct range_const_iterator > { typedef typename geometry::adapt::bp::ring_proxy::iterator_type type; }; } // namespace boost #endif // BOOST_GEOMETRY_GEOMETRIES_ADAPTED_BOOST_POLYGON_RING_PROXY_HPP