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_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: Chris@101: #include Chris@101: #include Chris@101: #include Chris@101: Chris@101: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: 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@101: Range const& range, bool force_closed) Chris@16: { Chris@16: typedef typename boost::range_iterator::type iterator_type; Chris@16: Chris@101: typedef stream_coordinate Chris@101: < Chris@101: point_type, 0, dimension::type::value Chris@101: > stream_type; Chris@101: Chris@16: bool first = true; Chris@16: Chris@16: os << PrefixPolicy::apply(); Chris@16: Chris@16: // TODO: check EMPTY here Chris@16: Chris@101: iterator_type begin = boost::begin(range); Chris@101: iterator_type end = boost::end(range); Chris@101: for (iterator_type it = begin; it != end; ++it) Chris@16: { Chris@16: os << (first ? "" : ","); Chris@101: stream_type::apply(os, *it); Chris@16: first = false; Chris@16: } Chris@16: Chris@101: // optionally, close range to ring by repeating the first point Chris@101: if (force_closed Chris@101: && boost::size(range) > 1 Chris@101: && geometry::disjoint(*begin, *(end - 1))) Chris@101: { Chris@101: os << ","; Chris@101: stream_type::apply(os, *begin); Chris@101: } Chris@101: Chris@16: os << SuffixPolicy::apply(); Chris@16: } Chris@16: Chris@101: template Chris@101: static inline void apply(std::basic_ostream& os, Chris@101: Range const& range) Chris@101: { Chris@101: apply(os, range, false); Chris@101: } Chris@101: 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@101: bool const force_closed = true; Chris@16: Chris@16: os << PrefixPolicy::apply(); Chris@16: // TODO: check EMPTY here Chris@16: os << "("; Chris@101: wkt_sequence::apply(os, exterior_ring(poly), force_closed); 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 << ","; Chris@101: wkt_sequence::apply(os, *it, force_closed); Chris@16: } Chris@16: os << ")"; Chris@16: } Chris@16: }; Chris@16: Chris@101: template Chris@101: struct wkt_multi Chris@101: { Chris@101: template Chris@101: static inline void apply(std::basic_ostream& os, Chris@101: Multi const& geometry) Chris@101: { Chris@101: os << PrefixPolicy::apply(); Chris@101: // TODO: check EMPTY here Chris@101: os << "("; Chris@101: Chris@101: for (typename boost::range_iterator::type Chris@101: it = boost::begin(geometry); Chris@101: it != boost::end(geometry); Chris@101: ++it) Chris@101: { Chris@101: if (it != boost::begin(geometry)) Chris@101: { Chris@101: os << ","; Chris@101: } Chris@101: StreamPolicy::apply(os, *it); Chris@101: } Chris@101: Chris@101: os << ")"; Chris@101: } Chris@101: }; Chris@101: 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@101: template Chris@101: struct wkt Chris@101: : detail::wkt::wkt_multi Chris@101: < Chris@101: Multi, Chris@101: detail::wkt::wkt_point Chris@101: < Chris@101: typename boost::range_value::type, Chris@101: detail::wkt::prefix_null Chris@101: >, Chris@101: detail::wkt::prefix_multipoint Chris@101: > Chris@101: {}; Chris@101: Chris@101: template Chris@101: struct wkt Chris@101: : detail::wkt::wkt_multi Chris@101: < Chris@101: Multi, Chris@101: detail::wkt::wkt_sequence Chris@101: < Chris@101: typename boost::range_value::type Chris@101: >, Chris@101: detail::wkt::prefix_multilinestring Chris@101: > Chris@101: {}; Chris@101: Chris@101: template Chris@101: struct wkt Chris@101: : detail::wkt::wkt_multi Chris@101: < Chris@101: Multi, Chris@101: detail::wkt::wkt_poly Chris@101: < Chris@101: typename boost::range_value::type, Chris@101: detail::wkt::prefix_null Chris@101: >, Chris@101: detail::wkt::prefix_multipolygon Chris@101: > Chris@101: {}; Chris@101: 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@101: \tparam Geometry \tparam_geometry Chris@101: \param geometry \param_geometry Chris@16: \ingroup wkt Chris@101: \qbk{[include reference/io/wkt.qbk]} 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