123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593 |
- // 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.
- // Copyright (c) 2020 Baidyanath Kundu, Haldia, India.
- // This file was modified by Oracle on 2015-2020.
- // Modifications copyright (c) 2015-2020, 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 <ostream>
- #include <string>
- #include <boost/array.hpp>
- #include <boost/range/begin.hpp>
- #include <boost/range/end.hpp>
- #include <boost/range/size.hpp>
- #include <boost/range/value_type.hpp>
- #include <boost/variant/apply_visitor.hpp>
- #include <boost/variant/static_visitor.hpp>
- #include <boost/variant/variant_fwd.hpp>
- #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
- #include <boost/geometry/algorithms/assign.hpp>
- #include <boost/geometry/algorithms/convert.hpp>
- #include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
- #include <boost/geometry/algorithms/not_implemented.hpp>
- #include <boost/geometry/core/exterior_ring.hpp>
- #include <boost/geometry/core/interior_rings.hpp>
- #include <boost/geometry/core/ring_type.hpp>
- #include <boost/geometry/core/tags.hpp>
- #include <boost/geometry/geometries/concepts/check.hpp>
- #include <boost/geometry/geometries/ring.hpp>
- #include <boost/geometry/io/wkt/detail/prefix.hpp>
- #include <boost/geometry/strategies/io/cartesian.hpp>
- #include <boost/geometry/strategies/io/geographic.hpp>
- #include <boost/geometry/strategies/io/spherical.hpp>
- #include <boost/geometry/util/condition.hpp>
- #include <boost/geometry/util/type_traits.hpp>
- namespace boost { namespace geometry
- {
- // Silence warning C4512: 'boost::geometry::wkt_manipulator<Geometry>' : 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 <typename P, int I, int Count>
- struct stream_coordinate
- {
- template <typename Char, typename Traits>
- static inline void apply(std::basic_ostream<Char, Traits>& os, P const& p)
- {
- os << (I > 0 ? " " : "") << get<I>(p);
- stream_coordinate<P, I + 1, Count>::apply(os, p);
- }
- };
- template <typename P, int Count>
- struct stream_coordinate<P, Count, Count>
- {
- template <typename Char, typename Traits>
- static inline void apply(std::basic_ostream<Char, Traits>&, 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 <typename Point, typename Policy>
- struct wkt_point
- {
- template <typename Char, typename Traits>
- static inline void apply(std::basic_ostream<Char, Traits>& os, Point const& p, bool)
- {
- os << Policy::apply() << "(";
- stream_coordinate<Point, 0, dimension<Point>::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 <typename Char, typename Traits>
- static inline void apply(std::basic_ostream<Char, Traits>& os,
- Range const& range, bool force_closure = ForceClosurePossible)
- {
- typedef typename boost::range_iterator<Range const>::type iterator_type;
- typedef stream_coordinate
- <
- point_type, 0, dimension<point_type>::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<Range>::type point_type;
- static inline bool disjoint(point_type const& p1, point_type const& p2)
- {
- // TODO: pass strategy
- typedef typename strategies::io::services::default_strategy
- <
- 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 <typename Range, bool ForceClosurePossible = true>
- struct wkt_sequence
- : wkt_range
- <
- Range,
- ForceClosurePossible,
- opening_parenthesis,
- closing_parenthesis
- >
- {};
- template <typename Polygon, typename PrefixPolicy>
- struct wkt_poly
- {
- template <typename Char, typename Traits>
- static inline void apply(std::basic_ostream<Char, Traits>& os,
- Polygon const& poly, bool force_closure)
- {
- typedef typename ring_type<Polygon const>::type ring;
- os << PrefixPolicy::apply();
- // TODO: check EMPTY here
- os << "(";
- wkt_sequence<ring>::apply(os, exterior_ring(poly), force_closure);
- typename interior_return_type<Polygon const>::type
- rings = interior_rings(poly);
- for (typename detail::interior_iterator<Polygon const>::type
- it = boost::begin(rings); it != boost::end(rings); ++it)
- {
- os << ",";
- wkt_sequence<ring>::apply(os, *it, force_closure);
- }
- os << ")";
- }
- };
- template <typename Multi, typename StreamPolicy, typename PrefixPolicy>
- struct wkt_multi
- {
- template <typename Char, typename Traits>
- static inline void apply(std::basic_ostream<Char, Traits>& os,
- Multi const& geometry, bool force_closure)
- {
- os << PrefixPolicy::apply();
- // TODO: check EMPTY here
- os << "(";
- for (typename boost::range_iterator<Multi const>::type
- it = boost::begin(geometry);
- it != boost::end(geometry);
- ++it)
- {
- if (it != boost::begin(geometry))
- {
- os << ",";
- }
- StreamPolicy::apply(os, *it, force_closure);
- }
- os << ")";
- }
- };
- template <typename Box>
- struct wkt_box
- {
- typedef typename point_type<Box>::type point_type;
- template <typename Char, typename Traits>
- static inline void apply(std::basic_ostream<Char, Traits>& 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<model::ring<point_type, true, true> >(os, box);
- }
- else
- {
- do_apply<model::ring<point_type, true, false> >(os, box);
- }
- }
- private:
- inline wkt_box()
- {
- // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron!
- //assert_dimension<B, 2>();
- }
- template <typename RingType, typename Char, typename Traits>
- static inline void do_apply(std::basic_ostream<Char, Traits>& os,
- Box const& box)
- {
- RingType ring;
- geometry::convert(box, ring);
- os << "POLYGON(";
- wkt_sequence<RingType, false>::apply(os, ring);
- os << ")";
- }
- };
- template <typename Segment>
- struct wkt_segment
- {
- typedef typename point_type<Segment>::type point_type;
- template <typename Char, typename Traits>
- static inline void apply(std::basic_ostream<Char, Traits>& os,
- Segment const& segment, bool)
- {
- // Convert to two points, then stream
- typedef boost::array<point_type, 2> 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<sequence, false>::apply(os, points);
- }
- private:
- inline wkt_segment()
- {}
- };
- }} // namespace detail::wkt
- #endif // DOXYGEN_NO_DETAIL
- #ifndef DOXYGEN_NO_DISPATCH
- namespace dispatch
- {
- template <typename Geometry, typename Tag = typename tag<Geometry>::type>
- struct wkt: not_implemented<Tag>
- {};
- template <typename Point>
- struct wkt<Point, point_tag>
- : detail::wkt::wkt_point
- <
- Point,
- detail::wkt::prefix_point
- >
- {};
- template <typename Linestring>
- struct wkt<Linestring, linestring_tag>
- : 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 <typename Box>
- struct wkt<Box, box_tag>
- : detail::wkt::wkt_box<Box>
- {};
- template <typename Segment>
- struct wkt<Segment, segment_tag>
- : detail::wkt::wkt_segment<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 <typename Ring>
- struct wkt<Ring, ring_tag>
- : 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 <typename Polygon>
- struct wkt<Polygon, polygon_tag>
- : detail::wkt::wkt_poly
- <
- Polygon,
- detail::wkt::prefix_polygon
- >
- {};
- template <typename Multi>
- struct wkt<Multi, multi_point_tag>
- : detail::wkt::wkt_multi
- <
- Multi,
- detail::wkt::wkt_point
- <
- typename boost::range_value<Multi>::type,
- detail::wkt::prefix_null
- >,
- detail::wkt::prefix_multipoint
- >
- {};
- template <typename Multi>
- struct wkt<Multi, multi_linestring_tag>
- : detail::wkt::wkt_multi
- <
- Multi,
- detail::wkt::wkt_sequence
- <
- typename boost::range_value<Multi>::type,
- false
- >,
- detail::wkt::prefix_multilinestring
- >
- {};
- template <typename Multi>
- struct wkt<Multi, multi_polygon_tag>
- : detail::wkt::wkt_multi
- <
- Multi,
- detail::wkt::wkt_poly
- <
- typename boost::range_value<Multi>::type,
- detail::wkt::prefix_null
- >,
- detail::wkt::prefix_multipolygon
- >
- {};
- template <typename Geometry>
- struct devarianted_wkt
- {
- template <typename OutputStream>
- static inline void apply(OutputStream& os, Geometry const& geometry,
- bool force_closure)
- {
- wkt<Geometry>::apply(os, geometry, force_closure);
- }
- };
- template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
- struct devarianted_wkt<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
- {
- template <typename OutputStream>
- struct visitor: static_visitor<void>
- {
- OutputStream& m_os;
- bool m_force_closure;
- visitor(OutputStream& os, bool force_closure)
- : m_os(os)
- , m_force_closure(force_closure)
- {}
- template <typename Geometry>
- inline void operator()(Geometry const& geometry) const
- {
- devarianted_wkt<Geometry>::apply(m_os, geometry, m_force_closure);
- }
- };
- template <typename OutputStream>
- static inline void apply(
- OutputStream& os,
- variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
- bool force_closure)
- {
- boost::apply_visitor(visitor<OutputStream>(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 <typename Geometry>
- class wkt_manipulator
- {
- static const bool is_ring = util::is_ring<Geometry>::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 <typename Char, typename Traits>
- inline friend std::basic_ostream<Char, Traits>& operator<<(
- std::basic_ostream<Char, Traits>& os,
- wkt_manipulator const& m)
- {
- dispatch::devarianted_wkt<Geometry>::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 <typename Geometry>
- inline wkt_manipulator<Geometry> wkt(Geometry const& geometry)
- {
- concepts::check<Geometry const>();
- return wkt_manipulator<Geometry>(geometry);
- }
- /*!
- \brief WKT-string formulating function
- \tparam Geometry \tparam_geometry
- \param geometry \param_geometry
- \param significant_digits Specifies the no of significant digits to use in the output wkt
- \ingroup wkt
- \qbk{[include reference/io/to_wkt.qbk]}
- */
- template <typename Geometry>
- inline std::string to_wkt(Geometry const& geometry)
- {
- std::stringstream ss;
- ss << boost::geometry::wkt(geometry);
- return ss.str();
- }
- template <typename Geometry>
- inline std::string to_wkt(Geometry const& geometry, int significant_digits)
- {
- std::stringstream ss;
- ss.precision(significant_digits);
- ss << boost::geometry::wkt(geometry);
- return ss.str();
- }
- #if defined(_MSC_VER)
- #pragma warning(pop)
- #endif
- }} // namespace boost::geometry
- #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP
|