// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, 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_IO_WKT_WRITE_HPP #define BOOST_GEOMETRY_IO_WKT_WRITE_HPP #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 wkt { template struct stream_coordinate { template static inline void apply(std::basic_ostream& os, P const& p) { os << (I > 0 ? " " : "") << get(p); stream_coordinate::apply(os, p); } }; template struct stream_coordinate { template static inline void apply(std::basic_ostream&, P const&) {} }; struct prefix_linestring_par { static inline const char* apply() { return "LINESTRING("; } }; struct prefix_ring_par_par { // Note, double parentheses are intentional, indicating WKT ring begin/end static inline const char* apply() { return "POLYGON(("; } }; struct opening_parenthesis { static inline const char* apply() { return "("; } }; struct closing_parenthesis { static inline const char* apply() { return ")"; } }; struct double_closing_parenthesis { static inline const char* apply() { return "))"; } }; /*! \brief Stream points as \ref WKT */ template struct wkt_point { template static inline void apply(std::basic_ostream& os, Point const& p) { os << Policy::apply() << "("; stream_coordinate::type::value>::apply(os, p); os << ")"; } }; /*! \brief Stream ranges as WKT \note policy is used to stream prefix/postfix, enabling derived classes to override this */ template struct wkt_range { template static inline void apply(std::basic_ostream& os, Range const& range) { typedef typename boost::range_iterator::type iterator_type; bool first = true; os << PrefixPolicy::apply(); // TODO: check EMPTY here for (iterator_type it = boost::begin(range); it != boost::end(range); ++it) { os << (first ? "" : ","); stream_coordinate < point_type, 0, dimension::type::value >::apply(os, *it); first = false; } os << SuffixPolicy::apply(); } private: typedef typename boost::range_value::type point_type; }; /*! \brief Stream sequence of points as WKT-part, e.g. (1 2),(3 4) \note Used in polygon, all multi-geometries */ template struct wkt_sequence : wkt_range < Range, opening_parenthesis, closing_parenthesis > {}; template struct wkt_poly { template static inline void apply(std::basic_ostream& os, Polygon const& poly) { typedef typename ring_type::type ring; os << PrefixPolicy::apply(); // TODO: check EMPTY here os << "("; wkt_sequence::apply(os, exterior_ring(poly)); typename interior_return_type::type rings = interior_rings(poly); for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it) { os << ","; wkt_sequence::apply(os, *it); } os << ")"; } }; template struct wkt_box { typedef typename point_type::type point_type; template static inline void apply(std::basic_ostream& os, Box const& box) { // Convert to ring, then stream typedef model::ring ring_type; ring_type ring; geometry::convert(box, ring); os << "POLYGON("; wkt_sequence::apply(os, ring); os << ")"; } private: inline wkt_box() { // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron! //assert_dimension(); } }; template struct wkt_segment { typedef typename point_type::type point_type; template static inline void apply(std::basic_ostream& os, Segment const& segment) { // Convert to two points, then stream typedef boost::array sequence; sequence points; geometry::detail::assign_point_from_index<0>(segment, points[0]); geometry::detail::assign_point_from_index<1>(segment, points[1]); // In Boost.Geometry a segment is represented // in WKT-format like (for 2D): LINESTRING(x y,x y) os << "LINESTRING"; wkt_sequence::apply(os, points); } private: inline wkt_segment() {} }; }} // namespace detail::wkt #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template struct wkt { BOOST_MPL_ASSERT_MSG ( false, NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE , (types) ); }; template struct wkt : detail::wkt::wkt_point < Point, detail::wkt::prefix_point > {}; template struct wkt : detail::wkt::wkt_range < Linestring, detail::wkt::prefix_linestring_par, detail::wkt::closing_parenthesis > {}; /*! \brief Specialization to stream a box as WKT \details A "box" does not exist in WKT. It is therefore streamed as a polygon */ template struct wkt : detail::wkt::wkt_box {}; template struct wkt : detail::wkt::wkt_segment {}; /*! \brief Specialization to stream a ring as WKT \details A ring or "linear_ring" does not exist in WKT. A ring is equivalent to a polygon without inner rings It is therefore streamed as a polygon */ template struct wkt : detail::wkt::wkt_range < Ring, detail::wkt::prefix_ring_par_par, detail::wkt::double_closing_parenthesis > {}; /*! \brief Specialization to stream polygon as WKT */ template struct wkt : detail::wkt::wkt_poly < Polygon, detail::wkt::prefix_polygon > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH /*! \brief Generic geometry template manipulator class, takes corresponding output class from traits class \ingroup wkt \details Stream manipulator, streams geometry classes as \ref WKT streams \par Example: Small example showing how to use the wkt class \dontinclude doxygen_1.cpp \skip example_as_wkt_point \line { \until } */ template class wkt_manipulator { public: inline wkt_manipulator(Geometry const& g) : m_geometry(g) {} template inline friend std::basic_ostream& operator<<( std::basic_ostream& os, wkt_manipulator const& m) { dispatch::wkt < typename tag::type, Geometry >::apply(os, m.m_geometry); os.flush(); return os; } private: Geometry const& m_geometry; }; /*! \brief Main WKT-streaming function \ingroup wkt \par Example: Small example showing how to use the wkt helper function \dontinclude doxygen_1.cpp \skip example_as_wkt_vector \line { \until } */ template inline wkt_manipulator wkt(Geometry const& geometry) { concept::check(); return wkt_manipulator(geometry); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP