Chris@16: // Boost.Geometry (aka GGL, Generic Geometry Library) Chris@16: Chris@16: // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. Chris@16: // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. Chris@16: // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. Chris@101: // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. Chris@16: Chris@16: // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library Chris@16: // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. Chris@16: Chris@16: // Use, modification and distribution is subject to the Boost Software License, Chris@16: // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #ifndef BOOST_GEOMETRY_IO_DSV_WRITE_HPP Chris@16: #define BOOST_GEOMETRY_IO_DSV_WRITE_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@101: Chris@101: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost { namespace geometry Chris@16: { Chris@16: Chris@16: #ifndef DOXYGEN_NO_DETAIL Chris@16: namespace detail { namespace dsv Chris@16: { Chris@16: Chris@16: struct dsv_settings Chris@16: { Chris@16: std::string coordinate_separator; Chris@16: std::string point_open; Chris@16: std::string point_close; Chris@16: std::string point_separator; Chris@16: std::string list_open; Chris@16: std::string list_close; Chris@16: std::string list_separator; Chris@16: Chris@16: dsv_settings(std::string const& sep Chris@16: , std::string const& open Chris@16: , std::string const& close Chris@16: , std::string const& psep Chris@16: , std::string const& lopen Chris@16: , std::string const& lclose Chris@16: , std::string const& lsep Chris@16: ) Chris@16: : coordinate_separator(sep) Chris@16: , point_open(open) Chris@16: , point_close(close) Chris@16: , point_separator(psep) Chris@16: , list_open(lopen) Chris@16: , list_close(lclose) Chris@16: , list_separator(lsep) Chris@16: {} Chris@16: }; Chris@16: Chris@16: /*! Chris@16: \brief Stream coordinate of a point as \ref DSV Chris@16: */ Chris@16: template Chris@16: struct stream_coordinate Chris@16: { Chris@16: template Chris@16: static inline void apply(std::basic_ostream& os, Chris@16: Point const& point, Chris@16: dsv_settings const& settings) Chris@16: { Chris@16: os << (Dimension > 0 ? settings.coordinate_separator : "") Chris@16: << get(point); Chris@16: Chris@16: stream_coordinate Chris@16: < Chris@16: Point, Dimension + 1, Count Chris@16: >::apply(os, point, settings); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct stream_coordinate Chris@16: { Chris@16: template Chris@16: static inline void apply(std::basic_ostream&, Chris@16: Point const&, Chris@16: dsv_settings const& ) Chris@16: { Chris@16: } Chris@16: }; Chris@16: Chris@16: /*! Chris@16: \brief Stream indexed coordinate of a box/segment as \ref DSV Chris@16: */ Chris@16: template Chris@16: < Chris@16: typename Geometry, Chris@16: std::size_t Index, Chris@16: std::size_t Dimension, Chris@16: std::size_t Count Chris@16: > Chris@16: struct stream_indexed Chris@16: { Chris@16: template Chris@16: static inline void apply(std::basic_ostream& os, Chris@16: Geometry const& geometry, Chris@16: dsv_settings const& settings) Chris@16: { Chris@16: os << (Dimension > 0 ? settings.coordinate_separator : "") Chris@16: << get(geometry); Chris@16: stream_indexed Chris@16: < Chris@16: Geometry, Index, Dimension + 1, Count Chris@16: >::apply(os, geometry, settings); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct stream_indexed Chris@16: { Chris@16: template Chris@16: static inline void apply(std::basic_ostream&, Geometry const&, Chris@16: dsv_settings const& ) Chris@16: { Chris@16: } Chris@16: }; Chris@16: Chris@16: /*! Chris@16: \brief Stream points as \ref DSV Chris@16: */ Chris@16: template Chris@16: struct dsv_point Chris@16: { Chris@16: template Chris@16: static inline void apply(std::basic_ostream& os, Chris@16: Point const& p, Chris@16: dsv_settings const& settings) Chris@16: { Chris@16: os << settings.point_open; Chris@16: stream_coordinate::type::value>::apply(os, p, settings); Chris@16: os << settings.point_close; Chris@16: } Chris@16: }; Chris@16: Chris@16: /*! Chris@16: \brief Stream ranges as DSV Chris@16: \note policy is used to stream prefix/postfix, enabling derived classes to override this Chris@16: */ Chris@16: template Chris@16: struct dsv_range Chris@16: { Chris@16: template Chris@16: static inline void apply(std::basic_ostream& os, Chris@16: Range const& range, Chris@16: dsv_settings const& settings) Chris@16: { Chris@16: typedef typename boost::range_iterator::type iterator_type; Chris@16: Chris@16: bool first = true; Chris@16: Chris@16: os << settings.list_open; Chris@16: Chris@16: for (iterator_type it = boost::begin(range); Chris@16: it != boost::end(range); Chris@16: ++it) Chris@16: { Chris@16: os << (first ? "" : settings.point_separator) Chris@16: << settings.point_open; Chris@16: Chris@16: stream_coordinate Chris@16: < Chris@16: point_type, 0, dimension::type::value Chris@16: >::apply(os, *it, settings); Chris@16: os << settings.point_close; Chris@16: Chris@16: first = false; Chris@16: } Chris@16: Chris@16: os << settings.list_close; Chris@16: } Chris@16: Chris@16: private: Chris@16: typedef typename boost::range_value::type point_type; Chris@16: }; Chris@16: Chris@16: /*! Chris@16: \brief Stream sequence of points as DSV-part, e.g. (1 2),(3 4) Chris@16: \note Used in polygon, all multi-geometries Chris@16: */ Chris@16: Chris@16: template Chris@16: struct dsv_poly Chris@16: { Chris@16: template Chris@16: static inline void apply(std::basic_ostream& os, Chris@16: Polygon const& poly, Chris@16: dsv_settings const& settings) Chris@16: { Chris@16: typedef typename ring_type::type ring; Chris@16: Chris@16: os << settings.list_open; Chris@16: Chris@16: dsv_range::apply(os, exterior_ring(poly), settings); Chris@16: Chris@101: typename interior_return_type::type Chris@101: rings = interior_rings(poly); Chris@101: for (typename detail::interior_iterator::type Chris@101: it = boost::begin(rings); it != boost::end(rings); ++it) Chris@16: { Chris@16: os << settings.list_separator; Chris@16: dsv_range::apply(os, *it, settings); Chris@16: } Chris@16: os << settings.list_close; Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct dsv_per_index Chris@16: { Chris@16: typedef typename point_type::type point_type; Chris@16: Chris@16: template Chris@16: static inline void apply(std::basic_ostream& os, Chris@16: Geometry const& geometry, Chris@16: dsv_settings const& settings) Chris@16: { Chris@16: os << settings.point_open; Chris@16: stream_indexed Chris@16: < Chris@16: Geometry, Index, 0, dimension::type::value Chris@16: >::apply(os, geometry, settings); Chris@16: os << settings.point_close; Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct dsv_indexed Chris@16: { Chris@16: typedef typename point_type::type point_type; Chris@16: Chris@16: template Chris@16: static inline void apply(std::basic_ostream& os, Chris@16: Geometry const& geometry, Chris@16: dsv_settings const& settings) Chris@16: { Chris@16: os << settings.list_open; Chris@16: dsv_per_index::apply(os, geometry, settings); Chris@16: os << settings.point_separator; Chris@16: dsv_per_index::apply(os, geometry, settings); Chris@16: os << settings.list_close; Chris@16: } Chris@16: }; Chris@16: Chris@16: }} // namespace detail::dsv Chris@16: #endif // DOXYGEN_NO_DETAIL Chris@16: Chris@16: #ifndef DOXYGEN_NO_DISPATCH Chris@16: namespace dispatch Chris@16: { Chris@16: Chris@16: template Chris@16: struct dsv {}; Chris@16: Chris@16: template Chris@16: struct dsv Chris@16: : detail::dsv::dsv_point Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct dsv Chris@16: : detail::dsv::dsv_range Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct dsv Chris@16: : detail::dsv::dsv_indexed Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct dsv Chris@16: : detail::dsv::dsv_indexed Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct dsv Chris@16: : detail::dsv::dsv_range Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct dsv Chris@16: : detail::dsv::dsv_poly Chris@16: {}; Chris@16: Chris@16: } // namespace dispatch Chris@16: #endif // DOXYGEN_NO_DISPATCH Chris@16: Chris@16: #ifndef DOXYGEN_NO_DETAIL Chris@16: namespace detail { namespace dsv Chris@16: { Chris@16: Chris@16: // FIXME: This class is not copyable/assignable but it is used as such --mloskot Chris@16: template Chris@16: class dsv_manipulator Chris@16: { Chris@16: public: Chris@16: Chris@16: inline dsv_manipulator(Geometry const& g, Chris@16: dsv_settings const& settings) Chris@16: : m_geometry(g) Chris@16: , m_settings(settings) Chris@16: {} Chris@16: Chris@16: template Chris@16: inline friend std::basic_ostream& operator<<( Chris@16: std::basic_ostream& os, Chris@16: dsv_manipulator const& m) Chris@16: { Chris@16: dispatch::dsv Chris@16: < Chris@16: typename tag_cast Chris@16: < Chris@16: typename tag::type, Chris@16: multi_tag Chris@16: >::type, Chris@16: Geometry Chris@16: >::apply(os, m.m_geometry, m.m_settings); Chris@16: os.flush(); Chris@16: return os; Chris@16: } Chris@16: Chris@16: private: Chris@16: Geometry const& m_geometry; Chris@16: dsv_settings m_settings; Chris@16: }; Chris@16: Chris@101: Chris@101: template Chris@101: struct dsv_multi Chris@101: { Chris@101: typedef dispatch::dsv Chris@101: < Chris@101: typename single_tag_of Chris@101: < Chris@101: typename tag::type Chris@101: >::type, Chris@101: typename boost::range_value::type Chris@101: > dispatch_one; Chris@101: Chris@101: typedef typename boost::range_iterator Chris@101: < Chris@101: MultiGeometry const Chris@101: >::type iterator; Chris@101: Chris@101: Chris@101: template Chris@101: static inline void apply(std::basic_ostream& os, Chris@101: MultiGeometry const& multi, Chris@101: dsv_settings const& settings) Chris@101: { Chris@101: os << settings.list_open; Chris@101: Chris@101: bool first = true; Chris@101: for(iterator it = boost::begin(multi); Chris@101: it != boost::end(multi); Chris@101: ++it, first = false) Chris@101: { Chris@101: os << (first ? "" : settings.list_separator); Chris@101: dispatch_one::apply(os, *it, settings); Chris@101: } Chris@101: os << settings.list_close; Chris@101: } Chris@101: }; Chris@101: Chris@16: }} // namespace detail::dsv Chris@16: #endif // DOXYGEN_NO_DETAIL Chris@16: Chris@101: // TODO: The alternative to this could be a forward declaration of dispatch::dsv<> Chris@101: // or braking the code into the interface and implementation part Chris@101: #ifndef DOXYGEN_NO_DISPATCH Chris@101: namespace dispatch Chris@101: { Chris@101: Chris@101: template Chris@101: struct dsv Chris@101: : detail::dsv::dsv_multi Chris@101: {}; Chris@101: Chris@101: } // namespace dispatch Chris@101: #endif // DOXYGEN_NO_DISPATCH Chris@101: Chris@16: /*! Chris@16: \brief Main DSV-streaming function Chris@16: \details DSV stands for Delimiter Separated Values. Geometries can be streamed Chris@16: as DSV. There are defaults for all separators. Chris@16: \note Useful for examples and testing purposes Chris@16: \note With this function GeoJSON objects can be created, using the right Chris@16: delimiters Chris@16: \ingroup utility Chris@16: */ Chris@16: template Chris@16: inline detail::dsv::dsv_manipulator dsv(Geometry const& geometry Chris@16: , std::string const& coordinate_separator = ", " Chris@16: , std::string const& point_open = "(" Chris@16: , std::string const& point_close = ")" Chris@16: , std::string const& point_separator = ", " Chris@16: , std::string const& list_open = "(" Chris@16: , std::string const& list_close = ")" Chris@16: , std::string const& list_separator = ", " Chris@16: ) Chris@16: { Chris@16: concept::check(); Chris@16: Chris@16: return detail::dsv::dsv_manipulator(geometry, Chris@16: detail::dsv::dsv_settings(coordinate_separator, Chris@16: point_open, point_close, point_separator, Chris@16: list_open, list_close, list_separator)); Chris@16: } Chris@16: Chris@16: }} // namespace boost::geometry Chris@16: Chris@16: #endif // BOOST_GEOMETRY_IO_DSV_WRITE_HPP