1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
5 // Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
6 // Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland.
8 // This file was modified by Oracle on 2015.
9 // Modifications copyright (c) 2015, 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)
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
126 template <typename Range, typename PrefixPolicy, typename SuffixPolicy>
129 template <typename Char, typename Traits>
130 static inline void apply(std::basic_ostream<Char, Traits>& os,
131 Range const& range, bool force_closed)
133 typedef typename boost::range_iterator<Range const>::type iterator_type;
135 typedef stream_coordinate
137 point_type, 0, dimension<point_type>::type::value
142 os << PrefixPolicy::apply();
144 // TODO: check EMPTY here
146 iterator_type begin = boost::begin(range);
147 iterator_type end = boost::end(range);
148 for (iterator_type it = begin; it != end; ++it)
150 os << (first ? "" : ",");
151 stream_type::apply(os, *it);
155 // optionally, close range to ring by repeating the first point
157 && boost::size(range) > 1
158 && detail::disjoint::disjoint_point_point(*begin, *(end - 1)))
161 stream_type::apply(os, *begin);
164 os << SuffixPolicy::apply();
167 template <typename Char, typename Traits>
168 static inline void apply(std::basic_ostream<Char, Traits>& os,
171 apply(os, range, false);
175 typedef typename boost::range_value<Range>::type point_type;
179 \brief Stream sequence of points as WKT-part, e.g. (1 2),(3 4)
180 \note Used in polygon, all multi-geometries
182 template <typename Range>
192 template <typename Polygon, typename PrefixPolicy>
195 template <typename Char, typename Traits>
196 static inline void apply(std::basic_ostream<Char, Traits>& os,
199 typedef typename ring_type<Polygon const>::type ring;
200 bool const force_closed = true;
202 os << PrefixPolicy::apply();
203 // TODO: check EMPTY here
205 wkt_sequence<ring>::apply(os, exterior_ring(poly), force_closed);
207 typename interior_return_type<Polygon const>::type
208 rings = interior_rings(poly);
209 for (typename detail::interior_iterator<Polygon const>::type
210 it = boost::begin(rings); it != boost::end(rings); ++it)
213 wkt_sequence<ring>::apply(os, *it, force_closed);
219 template <typename Multi, typename StreamPolicy, typename PrefixPolicy>
222 template <typename Char, typename Traits>
223 static inline void apply(std::basic_ostream<Char, Traits>& os,
224 Multi const& geometry)
226 os << PrefixPolicy::apply();
227 // TODO: check EMPTY here
230 for (typename boost::range_iterator<Multi const>::type
231 it = boost::begin(geometry);
232 it != boost::end(geometry);
235 if (it != boost::begin(geometry))
239 StreamPolicy::apply(os, *it);
246 template <typename Box>
249 typedef typename point_type<Box>::type point_type;
251 template <typename Char, typename Traits>
252 static inline void apply(std::basic_ostream<Char, Traits>& os,
255 // Convert to ring, then stream
256 typedef model::ring<point_type> ring_type;
258 geometry::convert(box, ring);
260 wkt_sequence<ring_type>::apply(os, ring);
268 // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron!
269 //assert_dimension<B, 2>();
274 template <typename Segment>
277 typedef typename point_type<Segment>::type point_type;
279 template <typename Char, typename Traits>
280 static inline void apply(std::basic_ostream<Char, Traits>& os,
281 Segment const& segment)
283 // Convert to two points, then stream
284 typedef boost::array<point_type, 2> sequence;
287 geometry::detail::assign_point_from_index<0>(segment, points[0]);
288 geometry::detail::assign_point_from_index<1>(segment, points[1]);
290 // In Boost.Geometry a segment is represented
291 // in WKT-format like (for 2D): LINESTRING(x y,x y)
293 wkt_sequence<sequence>::apply(os, points);
302 }} // namespace detail::wkt
303 #endif // DOXYGEN_NO_DETAIL
305 #ifndef DOXYGEN_NO_DISPATCH
309 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
310 struct wkt: not_implemented<Tag>
313 template <typename Point>
314 struct wkt<Point, point_tag>
315 : detail::wkt::wkt_point
318 detail::wkt::prefix_point
322 template <typename Linestring>
323 struct wkt<Linestring, linestring_tag>
324 : detail::wkt::wkt_range
327 detail::wkt::prefix_linestring_par,
328 detail::wkt::closing_parenthesis
333 \brief Specialization to stream a box as WKT
334 \details A "box" does not exist in WKT.
335 It is therefore streamed as a polygon
337 template <typename Box>
338 struct wkt<Box, box_tag>
339 : detail::wkt::wkt_box<Box>
342 template <typename Segment>
343 struct wkt<Segment, segment_tag>
344 : detail::wkt::wkt_segment<Segment>
348 \brief Specialization to stream a ring as WKT
349 \details A ring or "linear_ring" does not exist in WKT.
350 A ring is equivalent to a polygon without inner rings
351 It is therefore streamed as a polygon
353 template <typename Ring>
354 struct wkt<Ring, ring_tag>
355 : detail::wkt::wkt_range
358 detail::wkt::prefix_ring_par_par,
359 detail::wkt::double_closing_parenthesis
364 \brief Specialization to stream polygon as WKT
366 template <typename Polygon>
367 struct wkt<Polygon, polygon_tag>
368 : detail::wkt::wkt_poly
371 detail::wkt::prefix_polygon
375 template <typename Multi>
376 struct wkt<Multi, multi_point_tag>
377 : detail::wkt::wkt_multi
380 detail::wkt::wkt_point
382 typename boost::range_value<Multi>::type,
383 detail::wkt::prefix_null
385 detail::wkt::prefix_multipoint
389 template <typename Multi>
390 struct wkt<Multi, multi_linestring_tag>
391 : detail::wkt::wkt_multi
394 detail::wkt::wkt_sequence
396 typename boost::range_value<Multi>::type
398 detail::wkt::prefix_multilinestring
402 template <typename Multi>
403 struct wkt<Multi, multi_polygon_tag>
404 : detail::wkt::wkt_multi
407 detail::wkt::wkt_poly
409 typename boost::range_value<Multi>::type,
410 detail::wkt::prefix_null
412 detail::wkt::prefix_multipolygon
417 template <typename Geometry>
418 struct devarianted_wkt
420 template <typename OutputStream>
421 static inline void apply(OutputStream& os, Geometry const& geometry)
423 wkt<Geometry>::apply(os, geometry);
427 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
428 struct devarianted_wkt<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
430 template <typename OutputStream>
431 struct visitor: static_visitor<void>
435 visitor(OutputStream& os)
439 template <typename Geometry>
440 inline void operator()(Geometry const& geometry) const
442 devarianted_wkt<Geometry>::apply(m_os, geometry);
446 template <typename OutputStream>
447 static inline void apply(
449 variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry
452 boost::apply_visitor(visitor<OutputStream>(os), geometry);
457 } // namespace dispatch
458 #endif // DOXYGEN_NO_DISPATCH
461 \brief Generic geometry template manipulator class, takes corresponding output class from traits class
463 \details Stream manipulator, streams geometry classes as \ref WKT streams
465 Small example showing how to use the wkt class
466 \dontinclude doxygen_1.cpp
467 \skip example_as_wkt_point
471 template <typename Geometry>
472 class wkt_manipulator
476 inline wkt_manipulator(Geometry const& g)
480 template <typename Char, typename Traits>
481 inline friend std::basic_ostream<Char, Traits>& operator<<(
482 std::basic_ostream<Char, Traits>& os,
483 wkt_manipulator const& m)
485 dispatch::devarianted_wkt<Geometry>::apply(os, m.m_geometry);
491 Geometry const& m_geometry;
495 \brief Main WKT-streaming function
496 \tparam Geometry \tparam_geometry
497 \param geometry \param_geometry
499 \qbk{[include reference/io/wkt.qbk]}
501 template <typename Geometry>
502 inline wkt_manipulator<Geometry> wkt(Geometry const& geometry)
504 concepts::check<Geometry const>();
506 return wkt_manipulator<Geometry>(geometry);
509 #if defined(_MSC_VER)
513 }} // namespace boost::geometry
515 #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP