1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2007-2017 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2008-2017 Bruno Lalande, Paris, France.
5 // Copyright (c) 2009-2017 Mateusz Loskot, London, UK.
6 // Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland.
8 // This file was modified by Oracle on 2015-2020.
9 // Modifications copyright (c) 2015-2020, Oracle and/or its affiliates.
11 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
12 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
14 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
15 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
17 // Use, modification and distribution is subject to the Boost Software License,
18 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
19 // http://www.boost.org/LICENSE_1_0.txt)
21 #ifndef BOOST_GEOMETRY_IO_WKT_WRITE_HPP
22 #define BOOST_GEOMETRY_IO_WKT_WRITE_HPP
27 #include <boost/array.hpp>
28 #include <boost/range/begin.hpp>
29 #include <boost/range/end.hpp>
30 #include <boost/range/size.hpp>
31 #include <boost/range/value_type.hpp>
32 #include <boost/variant/apply_visitor.hpp>
33 #include <boost/variant/static_visitor.hpp>
34 #include <boost/variant/variant_fwd.hpp>
36 #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
37 #include <boost/geometry/algorithms/assign.hpp>
38 #include <boost/geometry/algorithms/convert.hpp>
39 #include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
40 #include <boost/geometry/algorithms/not_implemented.hpp>
41 #include <boost/geometry/core/exterior_ring.hpp>
42 #include <boost/geometry/core/interior_rings.hpp>
43 #include <boost/geometry/core/ring_type.hpp>
44 #include <boost/geometry/core/tags.hpp>
46 #include <boost/geometry/geometries/concepts/check.hpp>
47 #include <boost/geometry/geometries/ring.hpp>
49 #include <boost/geometry/io/wkt/detail/prefix.hpp>
51 #include <boost/geometry/util/condition.hpp>
52 #include <boost/geometry/util/type_traits.hpp>
55 namespace boost { namespace geometry
58 // Silence warning C4512: 'boost::geometry::wkt_manipulator<Geometry>' : assignment operator could not be generated
61 #pragma warning(disable : 4512)
64 #ifndef DOXYGEN_NO_DETAIL
65 namespace detail { namespace wkt
68 template <typename P, int I, int Count>
69 struct stream_coordinate
71 template <typename Char, typename Traits>
72 static inline void apply(std::basic_ostream<Char, Traits>& os, P const& p)
74 os << (I > 0 ? " " : "") << get<I>(p);
75 stream_coordinate<P, I + 1, Count>::apply(os, p);
79 template <typename P, int Count>
80 struct stream_coordinate<P, Count, Count>
82 template <typename Char, typename Traits>
83 static inline void apply(std::basic_ostream<Char, Traits>&, P const&)
87 struct prefix_linestring_par
89 static inline const char* apply() { return "LINESTRING("; }
92 struct prefix_ring_par_par
94 // Note, double parentheses are intentional, indicating WKT ring begin/end
95 static inline const char* apply() { return "POLYGON(("; }
98 struct opening_parenthesis
100 static inline const char* apply() { return "("; }
103 struct closing_parenthesis
105 static inline const char* apply() { return ")"; }
108 struct double_closing_parenthesis
110 static inline const char* apply() { return "))"; }
114 \brief Stream points as \ref WKT
116 template <typename Point, typename Policy>
119 template <typename Char, typename Traits>
120 static inline void apply(std::basic_ostream<Char, Traits>& os, Point const& p, bool)
122 os << Policy::apply() << "(";
123 stream_coordinate<Point, 0, dimension<Point>::type::value>::apply(os, p);
129 \brief Stream ranges as WKT
130 \note policy is used to stream prefix/postfix, enabling derived classes to override this
135 bool ForceClosurePossible,
136 typename PrefixPolicy,
137 typename SuffixPolicy
141 template <typename Char, typename Traits>
142 static inline void apply(std::basic_ostream<Char, Traits>& os,
143 Range const& range, bool force_closure = ForceClosurePossible)
145 typedef typename boost::range_iterator<Range const>::type iterator_type;
147 typedef stream_coordinate
149 point_type, 0, dimension<point_type>::type::value
154 os << PrefixPolicy::apply();
156 // TODO: check EMPTY here
158 iterator_type begin = boost::begin(range);
159 iterator_type end = boost::end(range);
160 for (iterator_type it = begin; it != end; ++it)
162 os << (first ? "" : ",");
163 stream_type::apply(os, *it);
167 // optionally, close range to ring by repeating the first point
168 if (BOOST_GEOMETRY_CONDITION(ForceClosurePossible)
170 && boost::size(range) > 1
171 && wkt_range::disjoint(*begin, *(end - 1)))
174 stream_type::apply(os, *begin);
177 os << SuffixPolicy::apply();
182 typedef typename boost::range_value<Range>::type point_type;
184 static inline bool disjoint(point_type const& p1, point_type const& p2)
186 // TODO: pass strategy
187 typedef typename strategy::disjoint::services::default_strategy
189 point_type, point_type
190 >::type strategy_type;
192 return detail::disjoint::disjoint_point_point(p1, p2, strategy_type());
197 \brief Stream sequence of points as WKT-part, e.g. (1 2),(3 4)
198 \note Used in polygon, all multi-geometries
200 template <typename Range, bool ForceClosurePossible = true>
205 ForceClosurePossible,
211 template <typename Polygon, typename PrefixPolicy>
214 template <typename Char, typename Traits>
215 static inline void apply(std::basic_ostream<Char, Traits>& os,
216 Polygon const& poly, bool force_closure)
218 typedef typename ring_type<Polygon const>::type ring;
220 os << PrefixPolicy::apply();
221 // TODO: check EMPTY here
223 wkt_sequence<ring>::apply(os, exterior_ring(poly), force_closure);
225 typename interior_return_type<Polygon const>::type
226 rings = interior_rings(poly);
227 for (typename detail::interior_iterator<Polygon const>::type
228 it = boost::begin(rings); it != boost::end(rings); ++it)
231 wkt_sequence<ring>::apply(os, *it, force_closure);
238 template <typename Multi, typename StreamPolicy, typename PrefixPolicy>
241 template <typename Char, typename Traits>
242 static inline void apply(std::basic_ostream<Char, Traits>& os,
243 Multi const& geometry, bool force_closure)
245 os << PrefixPolicy::apply();
246 // TODO: check EMPTY here
249 for (typename boost::range_iterator<Multi const>::type
250 it = boost::begin(geometry);
251 it != boost::end(geometry);
254 if (it != boost::begin(geometry))
258 StreamPolicy::apply(os, *it, force_closure);
265 template <typename Box>
268 typedef typename point_type<Box>::type point_type;
270 template <typename Char, typename Traits>
271 static inline void apply(std::basic_ostream<Char, Traits>& os,
272 Box const& box, bool force_closure)
274 // Convert to a clockwire ring, then stream.
275 // Never close it based on last point (box might be empty and
276 // that should result in POLYGON((0 0,0 0,0 0,0 0, ...)) )
279 do_apply<model::ring<point_type, true, true> >(os, box);
283 do_apply<model::ring<point_type, true, false> >(os, box);
291 // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron!
292 //assert_dimension<B, 2>();
295 template <typename RingType, typename Char, typename Traits>
296 static inline void do_apply(std::basic_ostream<Char, Traits>& os,
300 geometry::convert(box, ring);
302 wkt_sequence<RingType, false>::apply(os, ring);
309 template <typename Segment>
312 typedef typename point_type<Segment>::type point_type;
314 template <typename Char, typename Traits>
315 static inline void apply(std::basic_ostream<Char, Traits>& os,
316 Segment const& segment, bool)
318 // Convert to two points, then stream
319 typedef boost::array<point_type, 2> sequence;
322 geometry::detail::assign_point_from_index<0>(segment, points[0]);
323 geometry::detail::assign_point_from_index<1>(segment, points[1]);
325 // In Boost.Geometry a segment is represented
326 // in WKT-format like (for 2D): LINESTRING(x y,x y)
328 wkt_sequence<sequence, false>::apply(os, points);
337 }} // namespace detail::wkt
338 #endif // DOXYGEN_NO_DETAIL
340 #ifndef DOXYGEN_NO_DISPATCH
344 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
345 struct wkt: not_implemented<Tag>
348 template <typename Point>
349 struct wkt<Point, point_tag>
350 : detail::wkt::wkt_point
353 detail::wkt::prefix_point
357 template <typename Linestring>
358 struct wkt<Linestring, linestring_tag>
359 : detail::wkt::wkt_range
363 detail::wkt::prefix_linestring_par,
364 detail::wkt::closing_parenthesis
369 \brief Specialization to stream a box as WKT
370 \details A "box" does not exist in WKT.
371 It is therefore streamed as a polygon
373 template <typename Box>
374 struct wkt<Box, box_tag>
375 : detail::wkt::wkt_box<Box>
378 template <typename Segment>
379 struct wkt<Segment, segment_tag>
380 : detail::wkt::wkt_segment<Segment>
384 \brief Specialization to stream a ring as WKT
385 \details A ring or "linear_ring" does not exist in WKT.
386 A ring is equivalent to a polygon without inner rings
387 It is therefore streamed as a polygon
389 template <typename Ring>
390 struct wkt<Ring, ring_tag>
391 : detail::wkt::wkt_range
395 detail::wkt::prefix_ring_par_par,
396 detail::wkt::double_closing_parenthesis
401 \brief Specialization to stream polygon as WKT
403 template <typename Polygon>
404 struct wkt<Polygon, polygon_tag>
405 : detail::wkt::wkt_poly
408 detail::wkt::prefix_polygon
412 template <typename Multi>
413 struct wkt<Multi, multi_point_tag>
414 : detail::wkt::wkt_multi
417 detail::wkt::wkt_point
419 typename boost::range_value<Multi>::type,
420 detail::wkt::prefix_null
422 detail::wkt::prefix_multipoint
426 template <typename Multi>
427 struct wkt<Multi, multi_linestring_tag>
428 : detail::wkt::wkt_multi
431 detail::wkt::wkt_sequence
433 typename boost::range_value<Multi>::type,
436 detail::wkt::prefix_multilinestring
440 template <typename Multi>
441 struct wkt<Multi, multi_polygon_tag>
442 : detail::wkt::wkt_multi
445 detail::wkt::wkt_poly
447 typename boost::range_value<Multi>::type,
448 detail::wkt::prefix_null
450 detail::wkt::prefix_multipolygon
455 template <typename Geometry>
456 struct devarianted_wkt
458 template <typename OutputStream>
459 static inline void apply(OutputStream& os, Geometry const& geometry,
462 wkt<Geometry>::apply(os, geometry, force_closure);
466 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
467 struct devarianted_wkt<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
469 template <typename OutputStream>
470 struct visitor: static_visitor<void>
473 bool m_force_closure;
475 visitor(OutputStream& os, bool force_closure)
477 , m_force_closure(force_closure)
480 template <typename Geometry>
481 inline void operator()(Geometry const& geometry) const
483 devarianted_wkt<Geometry>::apply(m_os, geometry, m_force_closure);
487 template <typename OutputStream>
488 static inline void apply(
490 variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
493 boost::apply_visitor(visitor<OutputStream>(os, force_closure), geometry);
498 } // namespace dispatch
499 #endif // DOXYGEN_NO_DISPATCH
502 \brief Generic geometry template manipulator class, takes corresponding output class from traits class
504 \details Stream manipulator, streams geometry classes as \ref WKT streams
506 Small example showing how to use the wkt class
507 \dontinclude doxygen_1.cpp
508 \skip example_as_wkt_point
512 template <typename Geometry>
513 class wkt_manipulator
515 static const bool is_ring = util::is_ring<Geometry>::value;
519 // Boost.Geometry, by default, closes polygons explictly, but not rings
520 // NOTE: this might change in the future!
521 inline wkt_manipulator(Geometry const& g,
522 bool force_closure = ! is_ring)
524 , m_force_closure(force_closure)
527 template <typename Char, typename Traits>
528 inline friend std::basic_ostream<Char, Traits>& operator<<(
529 std::basic_ostream<Char, Traits>& os,
530 wkt_manipulator const& m)
532 dispatch::devarianted_wkt<Geometry>::apply(os, m.m_geometry, m.m_force_closure);
538 Geometry const& m_geometry;
539 bool m_force_closure;
543 \brief Main WKT-streaming function
544 \tparam Geometry \tparam_geometry
545 \param geometry \param_geometry
547 \qbk{[include reference/io/wkt.qbk]}
549 template <typename Geometry>
550 inline wkt_manipulator<Geometry> wkt(Geometry const& geometry)
552 concepts::check<Geometry const>();
554 return wkt_manipulator<Geometry>(geometry);
557 #if defined(_MSC_VER)
561 }} // namespace boost::geometry
563 #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP