// 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. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // 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 #include #include #include #include #include namespace boost { namespace geometry { // Silence warning C4512: 'boost::geometry::wkt_manipulator' : assignment operator could not be generated #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4512) #endif #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, bool force_closed) { typedef typename boost::range_iterator::type iterator_type; typedef stream_coordinate < point_type, 0, dimension::type::value > stream_type; bool first = true; os << PrefixPolicy::apply(); // TODO: check EMPTY here iterator_type begin = boost::begin(range); iterator_type end = boost::end(range); for (iterator_type it = begin; it != end; ++it) { os << (first ? "" : ","); stream_type::apply(os, *it); first = false; } // optionally, close range to ring by repeating the first point if (force_closed && boost::size(range) > 1 && geometry::disjoint(*begin, *(end - 1))) { os << ","; stream_type::apply(os, *begin); } os << SuffixPolicy::apply(); } template static inline void apply(std::basic_ostream& os, Range const& range) { apply(os, range, false); } 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; bool const force_closed = true; os << PrefixPolicy::apply(); // TODO: check EMPTY here os << "("; wkt_sequence::apply(os, exterior_ring(poly), force_closed); typename interior_return_type::type rings = interior_rings(poly); for (typename detail::interior_iterator::type it = boost::begin(rings); it != boost::end(rings); ++it) { os << ","; wkt_sequence::apply(os, *it, force_closed); } os << ")"; } }; template struct wkt_multi { template static inline void apply(std::basic_ostream& os, Multi const& geometry) { os << PrefixPolicy::apply(); // TODO: check EMPTY here os << "("; for (typename boost::range_iterator::type it = boost::begin(geometry); it != boost::end(geometry); ++it) { if (it != boost::begin(geometry)) { os << ","; } StreamPolicy::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 ::type> struct wkt: not_implemented {}; 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 > {}; template struct wkt : detail::wkt::wkt_multi < Multi, detail::wkt::wkt_point < typename boost::range_value::type, detail::wkt::prefix_null >, detail::wkt::prefix_multipoint > {}; template struct wkt : detail::wkt::wkt_multi < Multi, detail::wkt::wkt_sequence < typename boost::range_value::type >, detail::wkt::prefix_multilinestring > {}; template struct wkt : detail::wkt::wkt_multi < Multi, detail::wkt::wkt_poly < typename boost::range_value::type, detail::wkt::prefix_null >, detail::wkt::prefix_multipolygon > {}; template struct devarianted_wkt { template static inline void apply(OutputStream& os, Geometry const& geometry) { wkt::apply(os, geometry); } }; template struct devarianted_wkt > { template struct visitor: static_visitor { OutputStream& m_os; visitor(OutputStream& os) : m_os(os) {} template inline void operator()(Geometry const& geometry) const { devarianted_wkt::apply(m_os, geometry); } }; template static inline void apply( OutputStream& os, variant const& geometry ) { apply_visitor(visitor(os), geometry); } }; } // 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::devarianted_wkt::apply(os, m.m_geometry); os.flush(); return os; } private: Geometry const& m_geometry; }; /*! \brief Main WKT-streaming function \tparam Geometry \tparam_geometry \param geometry \param_geometry \ingroup wkt \qbk{[include reference/io/wkt.qbk]} */ template inline wkt_manipulator wkt(Geometry const& geometry) { concept::check(); return wkt_manipulator(geometry); } #if defined(_MSC_VER) #pragma warning(pop) #endif }} // namespace boost::geometry #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP