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.
9 // Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
11 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
13 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
14 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
16 // Use, modification and distribution is subject to the Boost Software License,
17 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
18 // http://www.boost.org/LICENSE_1_0.txt)
20 #ifndef BOOST_GEOMETRY_IO_WKT_WRITE_HPP
21 #define BOOST_GEOMETRY_IO_WKT_WRITE_HPP
26 #include <boost/array.hpp>
27 #include <boost/range.hpp>
29 #include <boost/variant/apply_visitor.hpp>
30 #include <boost/variant/static_visitor.hpp>
31 #include <boost/variant/variant_fwd.hpp>
33 #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
34 #include <boost/geometry/algorithms/assign.hpp>
35 #include <boost/geometry/algorithms/convert.hpp>
36 #include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
37 #include <boost/geometry/algorithms/not_implemented.hpp>
38 #include <boost/geometry/core/exterior_ring.hpp>
39 #include <boost/geometry/core/interior_rings.hpp>
40 #include <boost/geometry/core/ring_type.hpp>
41 #include <boost/geometry/core/tags.hpp>
43 #include <boost/geometry/geometries/concepts/check.hpp>
44 #include <boost/geometry/geometries/ring.hpp>
46 #include <boost/geometry/io/wkt/detail/prefix.hpp>
49 namespace boost { namespace geometry
52 // Silence warning C4512: 'boost::geometry::wkt_manipulator<Geometry>' : assignment operator could not be generated
55 #pragma warning(disable : 4512)
58 #ifndef DOXYGEN_NO_DETAIL
59 namespace detail { namespace wkt
62 template <typename P, int I, int Count>
63 struct stream_coordinate
65 template <typename Char, typename Traits>
66 static inline void apply(std::basic_ostream<Char, Traits>& os, P const& p)
68 os << (I > 0 ? " " : "") << get<I>(p);
69 stream_coordinate<P, I + 1, Count>::apply(os, p);
73 template <typename P, int Count>
74 struct stream_coordinate<P, Count, Count>
76 template <typename Char, typename Traits>
77 static inline void apply(std::basic_ostream<Char, Traits>&, P const&)
81 struct prefix_linestring_par
83 static inline const char* apply() { return "LINESTRING("; }
86 struct prefix_ring_par_par
88 // Note, double parentheses are intentional, indicating WKT ring begin/end
89 static inline const char* apply() { return "POLYGON(("; }
92 struct opening_parenthesis
94 static inline const char* apply() { return "("; }
97 struct closing_parenthesis
99 static inline const char* apply() { return ")"; }
102 struct double_closing_parenthesis
104 static inline const char* apply() { return "))"; }
108 \brief Stream points as \ref WKT
110 template <typename Point, typename Policy>
113 template <typename Char, typename Traits>
114 static inline void apply(std::basic_ostream<Char, Traits>& os, Point const& p, bool)
116 os << Policy::apply() << "(";
117 stream_coordinate<Point, 0, dimension<Point>::type::value>::apply(os, p);
123 \brief Stream ranges as WKT
124 \note policy is used to stream prefix/postfix, enabling derived classes to override this
129 bool ForceClosurePossible,
130 typename PrefixPolicy,
131 typename SuffixPolicy
135 template <typename Char, typename Traits>
136 static inline void apply(std::basic_ostream<Char, Traits>& os,
137 Range const& range, bool force_closure = ForceClosurePossible)
139 typedef typename boost::range_iterator<Range const>::type iterator_type;
141 typedef stream_coordinate
143 point_type, 0, dimension<point_type>::type::value
148 os << PrefixPolicy::apply();
150 // TODO: check EMPTY here
152 iterator_type begin = boost::begin(range);
153 iterator_type end = boost::end(range);
154 for (iterator_type it = begin; it != end; ++it)
156 os << (first ? "" : ",");
157 stream_type::apply(os, *it);
161 // optionally, close range to ring by repeating the first point
162 if (ForceClosurePossible
164 && boost::size(range) > 1
165 && detail::disjoint::disjoint_point_point(*begin, *(end - 1)))
168 stream_type::apply(os, *begin);
171 os << SuffixPolicy::apply();
176 typedef typename boost::range_value<Range>::type point_type;
180 \brief Stream sequence of points as WKT-part, e.g. (1 2),(3 4)
181 \note Used in polygon, all multi-geometries
183 template <typename Range, bool ForceClosurePossible = true>
188 ForceClosurePossible,
194 template <typename Polygon, typename PrefixPolicy>
197 template <typename Char, typename Traits>
198 static inline void apply(std::basic_ostream<Char, Traits>& os,
199 Polygon const& poly, bool force_closure)
201 typedef typename ring_type<Polygon const>::type ring;
203 os << PrefixPolicy::apply();
204 // TODO: check EMPTY here
206 wkt_sequence<ring>::apply(os, exterior_ring(poly), force_closure);
208 typename interior_return_type<Polygon const>::type
209 rings = interior_rings(poly);
210 for (typename detail::interior_iterator<Polygon const>::type
211 it = boost::begin(rings); it != boost::end(rings); ++it)
214 wkt_sequence<ring>::apply(os, *it, force_closure);
221 template <typename Multi, typename StreamPolicy, typename PrefixPolicy>
224 template <typename Char, typename Traits>
225 static inline void apply(std::basic_ostream<Char, Traits>& os,
226 Multi const& geometry, bool force_closure)
228 os << PrefixPolicy::apply();
229 // TODO: check EMPTY here
232 for (typename boost::range_iterator<Multi const>::type
233 it = boost::begin(geometry);
234 it != boost::end(geometry);
237 if (it != boost::begin(geometry))
241 StreamPolicy::apply(os, *it, force_closure);
248 template <typename Box>
251 typedef typename point_type<Box>::type point_type;
253 template <typename Char, typename Traits>
254 static inline void apply(std::basic_ostream<Char, Traits>& os,
255 Box const& box, bool force_closure)
257 // Convert to a clockwire ring, then stream.
258 // Never close it based on last point (box might be empty and
259 // that should result in POLYGON((0 0,0 0,0 0,0 0, ...)) )
262 do_apply<model::ring<point_type, true, true> >(os, box);
266 do_apply<model::ring<point_type, true, false> >(os, box);
274 // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron!
275 //assert_dimension<B, 2>();
278 template <typename RingType, typename Char, typename Traits>
279 static inline void do_apply(std::basic_ostream<Char, Traits>& os,
283 geometry::convert(box, ring);
285 wkt_sequence<RingType, false>::apply(os, ring);
292 template <typename Segment>
295 typedef typename point_type<Segment>::type point_type;
297 template <typename Char, typename Traits>
298 static inline void apply(std::basic_ostream<Char, Traits>& os,
299 Segment const& segment, bool)
301 // Convert to two points, then stream
302 typedef boost::array<point_type, 2> sequence;
305 geometry::detail::assign_point_from_index<0>(segment, points[0]);
306 geometry::detail::assign_point_from_index<1>(segment, points[1]);
308 // In Boost.Geometry a segment is represented
309 // in WKT-format like (for 2D): LINESTRING(x y,x y)
311 wkt_sequence<sequence, false>::apply(os, points);
320 }} // namespace detail::wkt
321 #endif // DOXYGEN_NO_DETAIL
323 #ifndef DOXYGEN_NO_DISPATCH
327 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
328 struct wkt: not_implemented<Tag>
331 template <typename Point>
332 struct wkt<Point, point_tag>
333 : detail::wkt::wkt_point
336 detail::wkt::prefix_point
340 template <typename Linestring>
341 struct wkt<Linestring, linestring_tag>
342 : detail::wkt::wkt_range
346 detail::wkt::prefix_linestring_par,
347 detail::wkt::closing_parenthesis
352 \brief Specialization to stream a box as WKT
353 \details A "box" does not exist in WKT.
354 It is therefore streamed as a polygon
356 template <typename Box>
357 struct wkt<Box, box_tag>
358 : detail::wkt::wkt_box<Box>
361 template <typename Segment>
362 struct wkt<Segment, segment_tag>
363 : detail::wkt::wkt_segment<Segment>
367 \brief Specialization to stream a ring as WKT
368 \details A ring or "linear_ring" does not exist in WKT.
369 A ring is equivalent to a polygon without inner rings
370 It is therefore streamed as a polygon
372 template <typename Ring>
373 struct wkt<Ring, ring_tag>
374 : detail::wkt::wkt_range
378 detail::wkt::prefix_ring_par_par,
379 detail::wkt::double_closing_parenthesis
384 \brief Specialization to stream polygon as WKT
386 template <typename Polygon>
387 struct wkt<Polygon, polygon_tag>
388 : detail::wkt::wkt_poly
391 detail::wkt::prefix_polygon
395 template <typename Multi>
396 struct wkt<Multi, multi_point_tag>
397 : detail::wkt::wkt_multi
400 detail::wkt::wkt_point
402 typename boost::range_value<Multi>::type,
403 detail::wkt::prefix_null
405 detail::wkt::prefix_multipoint
409 template <typename Multi>
410 struct wkt<Multi, multi_linestring_tag>
411 : detail::wkt::wkt_multi
414 detail::wkt::wkt_sequence
416 typename boost::range_value<Multi>::type,
419 detail::wkt::prefix_multilinestring
423 template <typename Multi>
424 struct wkt<Multi, multi_polygon_tag>
425 : detail::wkt::wkt_multi
428 detail::wkt::wkt_poly
430 typename boost::range_value<Multi>::type,
431 detail::wkt::prefix_null
433 detail::wkt::prefix_multipolygon
438 template <typename Geometry>
439 struct devarianted_wkt
441 template <typename OutputStream>
442 static inline void apply(OutputStream& os, Geometry const& geometry,
445 wkt<Geometry>::apply(os, geometry, force_closure);
449 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
450 struct devarianted_wkt<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
452 template <typename OutputStream>
453 struct visitor: static_visitor<void>
456 bool m_force_closure;
458 visitor(OutputStream& os, bool force_closure)
460 , m_force_closure(force_closure)
463 template <typename Geometry>
464 inline void operator()(Geometry const& geometry) const
466 devarianted_wkt<Geometry>::apply(m_os, geometry, m_force_closure);
470 template <typename OutputStream>
471 static inline void apply(
473 variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
476 boost::apply_visitor(visitor<OutputStream>(os, force_closure), geometry);
481 } // namespace dispatch
482 #endif // DOXYGEN_NO_DISPATCH
485 \brief Generic geometry template manipulator class, takes corresponding output class from traits class
487 \details Stream manipulator, streams geometry classes as \ref WKT streams
489 Small example showing how to use the wkt class
490 \dontinclude doxygen_1.cpp
491 \skip example_as_wkt_point
495 template <typename Geometry>
496 class wkt_manipulator
498 static const bool is_ring = boost::is_same<typename tag<Geometry>::type, ring_tag>::value;
502 // Boost.Geometry, by default, closes polygons explictly, but not rings
503 // NOTE: this might change in the future!
504 inline wkt_manipulator(Geometry const& g,
505 bool force_closure = ! is_ring)
507 , m_force_closure(force_closure)
510 template <typename Char, typename Traits>
511 inline friend std::basic_ostream<Char, Traits>& operator<<(
512 std::basic_ostream<Char, Traits>& os,
513 wkt_manipulator const& m)
515 dispatch::devarianted_wkt<Geometry>::apply(os, m.m_geometry, m.m_force_closure);
521 Geometry const& m_geometry;
522 bool m_force_closure;
526 \brief Main WKT-streaming function
527 \tparam Geometry \tparam_geometry
528 \param geometry \param_geometry
530 \qbk{[include reference/io/wkt.qbk]}
532 template <typename Geometry>
533 inline wkt_manipulator<Geometry> wkt(Geometry const& geometry)
535 concepts::check<Geometry const>();
537 return wkt_manipulator<Geometry>(geometry);
540 #if defined(_MSC_VER)
544 }} // namespace boost::geometry
546 #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP