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@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_WKT_WRITE_HPP Chris@16: #define BOOST_GEOMETRY_IO_WKT_WRITE_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost { namespace geometry Chris@16: { Chris@16: Chris@16: // Silence warning C4512: 'boost::geometry::wkt_manipulator' : assignment operator could not be generated Chris@16: #if defined(_MSC_VER) Chris@16: #pragma warning(push) Chris@16: #pragma warning(disable : 4512) Chris@16: #endif Chris@16: Chris@16: #ifndef DOXYGEN_NO_DETAIL Chris@16: namespace detail { namespace wkt 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& os, P const& p) Chris@16: { Chris@16: os << (I > 0 ? " " : "") << get(p); Chris@16: stream_coordinate::apply(os, p); 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&, P const&) Chris@16: {} Chris@16: }; Chris@16: Chris@16: struct prefix_linestring_par Chris@16: { Chris@16: static inline const char* apply() { return "LINESTRING("; } Chris@16: }; Chris@16: Chris@16: struct prefix_ring_par_par Chris@16: { Chris@16: // Note, double parentheses are intentional, indicating WKT ring begin/end Chris@16: static inline const char* apply() { return "POLYGON(("; } Chris@16: }; Chris@16: Chris@16: struct opening_parenthesis Chris@16: { Chris@16: static inline const char* apply() { return "("; } Chris@16: }; Chris@16: Chris@16: struct closing_parenthesis Chris@16: { Chris@16: static inline const char* apply() { return ")"; } Chris@16: }; Chris@16: Chris@16: struct double_closing_parenthesis Chris@16: { Chris@16: static inline const char* apply() { return "))"; } Chris@16: }; Chris@16: Chris@16: /*! Chris@16: \brief Stream points as \ref WKT Chris@16: */ Chris@16: template Chris@16: struct wkt_point Chris@16: { Chris@16: template Chris@16: static inline void apply(std::basic_ostream& os, Point const& p) Chris@16: { Chris@16: os << Policy::apply() << "("; Chris@16: stream_coordinate::type::value>::apply(os, p); Chris@16: os << ")"; Chris@16: } Chris@16: }; Chris@16: Chris@16: /*! Chris@16: \brief Stream ranges as WKT Chris@16: \note policy is used to stream prefix/postfix, enabling derived classes to override this Chris@16: */ Chris@16: template Chris@16: struct wkt_range Chris@16: { Chris@16: template Chris@16: static inline void apply(std::basic_ostream& os, Chris@16: Range const& range) Chris@16: { Chris@16: typedef typename boost::range_iterator::type iterator_type; Chris@16: Chris@16: bool first = true; Chris@16: Chris@16: os << PrefixPolicy::apply(); Chris@16: Chris@16: // TODO: check EMPTY here 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 ? "" : ","); Chris@16: stream_coordinate Chris@16: < Chris@16: point_type, 0, dimension::type::value Chris@16: >::apply(os, *it); Chris@16: first = false; Chris@16: } Chris@16: Chris@16: os << SuffixPolicy::apply(); 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 WKT-part, e.g. (1 2),(3 4) Chris@16: \note Used in polygon, all multi-geometries Chris@16: */ Chris@16: template Chris@16: struct wkt_sequence Chris@16: : wkt_range Chris@16: < Chris@16: Range, Chris@16: opening_parenthesis, Chris@16: closing_parenthesis Chris@16: > Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct wkt_poly Chris@16: { Chris@16: template Chris@16: static inline void apply(std::basic_ostream& os, Chris@16: Polygon const& poly) Chris@16: { Chris@16: typedef typename ring_type::type ring; Chris@16: Chris@16: os << PrefixPolicy::apply(); Chris@16: // TODO: check EMPTY here Chris@16: os << "("; Chris@16: wkt_sequence::apply(os, exterior_ring(poly)); Chris@16: Chris@16: typename interior_return_type::type rings Chris@16: = interior_rings(poly); Chris@16: for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it) Chris@16: { Chris@16: os << ","; Chris@16: wkt_sequence::apply(os, *it); Chris@16: } Chris@16: os << ")"; Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct wkt_box 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: Box const& box) Chris@16: { Chris@16: // Convert to ring, then stream Chris@16: typedef model::ring ring_type; Chris@16: ring_type ring; Chris@16: geometry::convert(box, ring); Chris@16: os << "POLYGON("; Chris@16: wkt_sequence::apply(os, ring); Chris@16: os << ")"; Chris@16: } Chris@16: Chris@16: private: Chris@16: Chris@16: inline wkt_box() Chris@16: { Chris@16: // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron! Chris@16: //assert_dimension(); Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: template Chris@16: struct wkt_segment 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: Segment const& segment) Chris@16: { Chris@16: // Convert to two points, then stream Chris@16: typedef boost::array sequence; Chris@16: Chris@16: sequence points; Chris@16: geometry::detail::assign_point_from_index<0>(segment, points[0]); Chris@16: geometry::detail::assign_point_from_index<1>(segment, points[1]); Chris@16: Chris@16: // In Boost.Geometry a segment is represented Chris@16: // in WKT-format like (for 2D): LINESTRING(x y,x y) Chris@16: os << "LINESTRING"; Chris@16: wkt_sequence::apply(os, points); Chris@16: } Chris@16: Chris@16: private: Chris@16: Chris@16: inline wkt_segment() Chris@16: {} Chris@16: }; Chris@16: Chris@16: }} // namespace detail::wkt 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 ::type> Chris@16: struct wkt: not_implemented Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct wkt Chris@16: : detail::wkt::wkt_point Chris@16: < Chris@16: Point, Chris@16: detail::wkt::prefix_point Chris@16: > Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct wkt Chris@16: : detail::wkt::wkt_range Chris@16: < Chris@16: Linestring, Chris@16: detail::wkt::prefix_linestring_par, Chris@16: detail::wkt::closing_parenthesis Chris@16: > Chris@16: {}; Chris@16: Chris@16: /*! Chris@16: \brief Specialization to stream a box as WKT Chris@16: \details A "box" does not exist in WKT. Chris@16: It is therefore streamed as a polygon Chris@16: */ Chris@16: template Chris@16: struct wkt Chris@16: : detail::wkt::wkt_box Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct wkt Chris@16: : detail::wkt::wkt_segment Chris@16: {}; Chris@16: Chris@16: /*! Chris@16: \brief Specialization to stream a ring as WKT Chris@16: \details A ring or "linear_ring" does not exist in WKT. Chris@16: A ring is equivalent to a polygon without inner rings Chris@16: It is therefore streamed as a polygon Chris@16: */ Chris@16: template Chris@16: struct wkt Chris@16: : detail::wkt::wkt_range Chris@16: < Chris@16: Ring, Chris@16: detail::wkt::prefix_ring_par_par, Chris@16: detail::wkt::double_closing_parenthesis Chris@16: > Chris@16: {}; Chris@16: Chris@16: /*! Chris@16: \brief Specialization to stream polygon as WKT Chris@16: */ Chris@16: template Chris@16: struct wkt Chris@16: : detail::wkt::wkt_poly Chris@16: < Chris@16: Polygon, Chris@16: detail::wkt::prefix_polygon Chris@16: > Chris@16: {}; Chris@16: Chris@16: Chris@16: template Chris@16: struct devarianted_wkt Chris@16: { Chris@16: template Chris@16: static inline void apply(OutputStream& os, Geometry const& geometry) Chris@16: { Chris@16: wkt::apply(os, geometry); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct devarianted_wkt > Chris@16: { Chris@16: template Chris@16: struct visitor: static_visitor Chris@16: { Chris@16: OutputStream& m_os; Chris@16: Chris@16: visitor(OutputStream& os) Chris@16: : m_os(os) Chris@16: {} Chris@16: Chris@16: template Chris@16: inline void operator()(Geometry const& geometry) const Chris@16: { Chris@16: devarianted_wkt::apply(m_os, geometry); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: static inline void apply( Chris@16: OutputStream& os, Chris@16: variant const& geometry Chris@16: ) Chris@16: { Chris@16: apply_visitor(visitor(os), geometry); Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: } // namespace dispatch Chris@16: #endif // DOXYGEN_NO_DISPATCH Chris@16: Chris@16: /*! Chris@16: \brief Generic geometry template manipulator class, takes corresponding output class from traits class Chris@16: \ingroup wkt Chris@16: \details Stream manipulator, streams geometry classes as \ref WKT streams Chris@16: \par Example: Chris@16: Small example showing how to use the wkt class Chris@16: \dontinclude doxygen_1.cpp Chris@16: \skip example_as_wkt_point Chris@16: \line { Chris@16: \until } Chris@16: */ Chris@16: template Chris@16: class wkt_manipulator Chris@16: { Chris@16: public: Chris@16: Chris@16: inline wkt_manipulator(Geometry const& g) Chris@16: : m_geometry(g) Chris@16: {} Chris@16: Chris@16: template Chris@16: inline friend std::basic_ostream& operator<<( Chris@16: std::basic_ostream& os, Chris@16: wkt_manipulator const& m) Chris@16: { Chris@16: dispatch::devarianted_wkt::apply(os, m.m_geometry); Chris@16: os.flush(); Chris@16: return os; Chris@16: } Chris@16: Chris@16: private: Chris@16: Geometry const& m_geometry; Chris@16: }; Chris@16: Chris@16: /*! Chris@16: \brief Main WKT-streaming function Chris@16: \ingroup wkt Chris@16: \par Example: Chris@16: Small example showing how to use the wkt helper function Chris@16: \dontinclude doxygen_1.cpp Chris@16: \skip example_as_wkt_vector Chris@16: \line { Chris@16: \until } Chris@16: */ Chris@16: template Chris@16: inline wkt_manipulator wkt(Geometry const& geometry) Chris@16: { Chris@16: concept::check(); Chris@16: Chris@16: return wkt_manipulator(geometry); Chris@16: } Chris@16: Chris@16: #if defined(_MSC_VER) Chris@16: #pragma warning(pop) Chris@16: #endif Chris@16: Chris@16: }} // namespace boost::geometry Chris@16: Chris@16: #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP