// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2017 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2017 Bruno Lalande, Paris, France. // Copyright (c) 2009-2017 Mateusz Loskot, London, UK. // Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2015, 2018, 2019. // Modifications copyright (c) 2015-2019, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // 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 #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, bool) { 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 < typename Range, bool ForceClosurePossible, typename PrefixPolicy, typename SuffixPolicy > struct wkt_range { template static inline void apply(std::basic_ostream& os, Range const& range, bool force_closure = ForceClosurePossible) { 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 (BOOST_GEOMETRY_CONDITION(ForceClosurePossible) && force_closure && boost::size(range) > 1 && wkt_range::disjoint(*begin, *(end - 1))) { os << ","; stream_type::apply(os, *begin); } os << SuffixPolicy::apply(); } private: typedef typename boost::range_value::type point_type; static inline bool disjoint(point_type const& p1, point_type const& p2) { // TODO: pass strategy typedef typename strategy::disjoint::services::default_strategy < point_type, point_type >::type strategy_type; return detail::disjoint::disjoint_point_point(p1, p2, strategy_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, ForceClosurePossible, opening_parenthesis, closing_parenthesis > {}; template struct wkt_poly { template static inline void apply(std::basic_ostream& os, Polygon const& poly, bool force_closure) { typedef typename ring_type::type ring; os << PrefixPolicy::apply(); // TODO: check EMPTY here os << "("; wkt_sequence::apply(os, exterior_ring(poly), force_closure); 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_closure); } os << ")"; } }; template struct wkt_multi { template static inline void apply(std::basic_ostream& os, Multi const& geometry, bool force_closure) { 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, force_closure); } os << ")"; } }; template struct wkt_box { typedef typename point_type::type point_type; template static inline void apply(std::basic_ostream& os, Box const& box, bool force_closure) { // Convert to a clockwire ring, then stream. // Never close it based on last point (box might be empty and // that should result in POLYGON((0 0,0 0,0 0,0 0, ...)) ) if (force_closure) { do_apply >(os, box); } else { do_apply >(os, box); } } private: inline wkt_box() { // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron! //assert_dimension(); } template static inline void do_apply(std::basic_ostream& os, Box const& box) { RingType ring; geometry::convert(box, ring); os << "POLYGON("; wkt_sequence::apply(os, ring); os << ")"; } }; template struct wkt_segment { typedef typename point_type::type point_type; template static inline void apply(std::basic_ostream& os, Segment const& segment, bool) { // 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, false, 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, true, 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, false >, 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, bool force_closure) { wkt::apply(os, geometry, force_closure); } }; template struct devarianted_wkt > { template struct visitor: static_visitor { OutputStream& m_os; bool m_force_closure; visitor(OutputStream& os, bool force_closure) : m_os(os) , m_force_closure(force_closure) {} template inline void operator()(Geometry const& geometry) const { devarianted_wkt::apply(m_os, geometry, m_force_closure); } }; template static inline void apply( OutputStream& os, variant const& geometry, bool force_closure) { boost::apply_visitor(visitor(os, force_closure), 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 { static const bool is_ring = boost::is_same::type, ring_tag>::value; public: // Boost.Geometry, by default, closes polygons explictly, but not rings // NOTE: this might change in the future! inline wkt_manipulator(Geometry const& g, bool force_closure = ! is_ring) : m_geometry(g) , m_force_closure(force_closure) {} template inline friend std::basic_ostream& operator<<( std::basic_ostream& os, wkt_manipulator const& m) { dispatch::devarianted_wkt::apply(os, m.m_geometry, m.m_force_closure); os.flush(); return os; } private: Geometry const& m_geometry; bool m_force_closure; }; /*! \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) { concepts::check(); return wkt_manipulator(geometry); } #if defined(_MSC_VER) #pragma warning(pop) #endif }} // namespace boost::geometry #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP