1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
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.
7 
8 // This file was modified by Oracle on 2015.
9 // Modifications copyright (c) 2015, Oracle and/or its affiliates.
10 
11 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
12 
13 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
14 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
15 
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)
19 
20 #ifndef BOOST_GEOMETRY_IO_WKT_WRITE_HPP
21 #define BOOST_GEOMETRY_IO_WKT_WRITE_HPP
22 
23 #include <ostream>
24 #include <string>
25 
26 #include <boost/array.hpp>
27 #include <boost/range.hpp>
28 
29 #include <boost/variant/apply_visitor.hpp>
30 #include <boost/variant/static_visitor.hpp>
31 #include <boost/variant/variant_fwd.hpp>
32 
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>
42 
43 #include <boost/geometry/geometries/concepts/check.hpp>
44 #include <boost/geometry/geometries/ring.hpp>
45 
46 #include <boost/geometry/io/wkt/detail/prefix.hpp>
47 
48 
49 namespace boost { namespace geometry
50 {
51 
52 // Silence warning C4512: 'boost::geometry::wkt_manipulator<Geometry>' : assignment operator could not be generated
53 #if defined(_MSC_VER)
54 #pragma warning(push)
55 #pragma warning(disable : 4512)
56 #endif
57 
58 #ifndef DOXYGEN_NO_DETAIL
59 namespace detail { namespace wkt
60 {
61 
62 template <typename P, int I, int Count>
63 struct stream_coordinate
64 {
65     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::stream_coordinate66     static inline void apply(std::basic_ostream<Char, Traits>& os, P const& p)
67     {
68         os << (I > 0 ? " " : "") << get<I>(p);
69         stream_coordinate<P, I + 1, Count>::apply(os, p);
70     }
71 };
72 
73 template <typename P, int Count>
74 struct stream_coordinate<P, Count, Count>
75 {
76     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::stream_coordinate77     static inline void apply(std::basic_ostream<Char, Traits>&, P const&)
78     {}
79 };
80 
81 struct prefix_linestring_par
82 {
applyboost::geometry::detail::wkt::prefix_linestring_par83     static inline const char* apply() { return "LINESTRING("; }
84 };
85 
86 struct prefix_ring_par_par
87 {
88     // Note, double parentheses are intentional, indicating WKT ring begin/end
applyboost::geometry::detail::wkt::prefix_ring_par_par89     static inline const char* apply() { return "POLYGON(("; }
90 };
91 
92 struct opening_parenthesis
93 {
applyboost::geometry::detail::wkt::opening_parenthesis94     static inline const char* apply() { return "("; }
95 };
96 
97 struct closing_parenthesis
98 {
applyboost::geometry::detail::wkt::closing_parenthesis99     static inline const char* apply() { return ")"; }
100 };
101 
102 struct double_closing_parenthesis
103 {
applyboost::geometry::detail::wkt::double_closing_parenthesis104     static inline const char* apply() { return "))"; }
105 };
106 
107 /*!
108 \brief Stream points as \ref WKT
109 */
110 template <typename Point, typename Policy>
111 struct wkt_point
112 {
113     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::wkt_point114     static inline void apply(std::basic_ostream<Char, Traits>& os, Point const& p)
115     {
116         os << Policy::apply() << "(";
117         stream_coordinate<Point, 0, dimension<Point>::type::value>::apply(os, p);
118         os << ")";
119     }
120 };
121 
122 /*!
123 \brief Stream ranges as WKT
124 \note policy is used to stream prefix/postfix, enabling derived classes to override this
125 */
126 template <typename Range, typename PrefixPolicy, typename SuffixPolicy>
127 struct wkt_range
128 {
129     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::wkt_range130     static inline void apply(std::basic_ostream<Char, Traits>& os,
131                 Range const& range, bool force_closed)
132     {
133         typedef typename boost::range_iterator<Range const>::type iterator_type;
134 
135         typedef stream_coordinate
136             <
137                 point_type, 0, dimension<point_type>::type::value
138             > stream_type;
139 
140         bool first = true;
141 
142         os << PrefixPolicy::apply();
143 
144         // TODO: check EMPTY here
145 
146         iterator_type begin = boost::begin(range);
147         iterator_type end = boost::end(range);
148         for (iterator_type it = begin; it != end; ++it)
149         {
150             os << (first ? "" : ",");
151             stream_type::apply(os, *it);
152             first = false;
153         }
154 
155         // optionally, close range to ring by repeating the first point
156         if (force_closed
157             && boost::size(range) > 1
158             && detail::disjoint::disjoint_point_point(*begin, *(end - 1)))
159         {
160             os << ",";
161             stream_type::apply(os, *begin);
162         }
163 
164         os << SuffixPolicy::apply();
165     }
166 
167     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::wkt_range168     static inline void apply(std::basic_ostream<Char, Traits>& os,
169                 Range const& range)
170     {
171         apply(os, range, false);
172     }
173 
174 private:
175     typedef typename boost::range_value<Range>::type point_type;
176 };
177 
178 /*!
179 \brief Stream sequence of points as WKT-part, e.g. (1 2),(3 4)
180 \note Used in polygon, all multi-geometries
181 */
182 template <typename Range>
183 struct wkt_sequence
184     : wkt_range
185         <
186             Range,
187             opening_parenthesis,
188             closing_parenthesis
189         >
190 {};
191 
192 template <typename Polygon, typename PrefixPolicy>
193 struct wkt_poly
194 {
195     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::wkt_poly196     static inline void apply(std::basic_ostream<Char, Traits>& os,
197                 Polygon const& poly)
198     {
199         typedef typename ring_type<Polygon const>::type ring;
200         bool const force_closed = true;
201 
202         os << PrefixPolicy::apply();
203         // TODO: check EMPTY here
204         os << "(";
205         wkt_sequence<ring>::apply(os, exterior_ring(poly), force_closed);
206 
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)
211         {
212             os << ",";
213             wkt_sequence<ring>::apply(os, *it, force_closed);
214         }
215         os << ")";
216     }
217 };
218 
219 template <typename Multi, typename StreamPolicy, typename PrefixPolicy>
220 struct wkt_multi
221 {
222     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::wkt_multi223     static inline void apply(std::basic_ostream<Char, Traits>& os,
224                 Multi const& geometry)
225     {
226         os << PrefixPolicy::apply();
227         // TODO: check EMPTY here
228         os << "(";
229 
230         for (typename boost::range_iterator<Multi const>::type
231                     it = boost::begin(geometry);
232             it != boost::end(geometry);
233             ++it)
234         {
235             if (it != boost::begin(geometry))
236             {
237                 os << ",";
238             }
239             StreamPolicy::apply(os, *it);
240         }
241 
242         os << ")";
243     }
244 };
245 
246 template <typename Box>
247 struct wkt_box
248 {
249     typedef typename point_type<Box>::type point_type;
250 
251     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::wkt_box252     static inline void apply(std::basic_ostream<Char, Traits>& os,
253                 Box const& box)
254     {
255         // Convert to ring, then stream
256         typedef model::ring<point_type> ring_type;
257         ring_type ring;
258         geometry::convert(box, ring);
259         os << "POLYGON(";
260         wkt_sequence<ring_type>::apply(os, ring);
261         os << ")";
262     }
263 
264     private:
265 
wkt_boxboost::geometry::detail::wkt::wkt_box266         inline wkt_box()
267         {
268             // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron!
269             //assert_dimension<B, 2>();
270         }
271 };
272 
273 
274 template <typename Segment>
275 struct wkt_segment
276 {
277     typedef typename point_type<Segment>::type point_type;
278 
279     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::wkt_segment280     static inline void apply(std::basic_ostream<Char, Traits>& os,
281                 Segment const& segment)
282     {
283         // Convert to two points, then stream
284         typedef boost::array<point_type, 2> sequence;
285 
286         sequence points;
287         geometry::detail::assign_point_from_index<0>(segment, points[0]);
288         geometry::detail::assign_point_from_index<1>(segment, points[1]);
289 
290         // In Boost.Geometry a segment is represented
291         // in WKT-format like (for 2D): LINESTRING(x y,x y)
292         os << "LINESTRING";
293         wkt_sequence<sequence>::apply(os, points);
294     }
295 
296     private:
297 
wkt_segmentboost::geometry::detail::wkt::wkt_segment298         inline wkt_segment()
299         {}
300 };
301 
302 }} // namespace detail::wkt
303 #endif // DOXYGEN_NO_DETAIL
304 
305 #ifndef DOXYGEN_NO_DISPATCH
306 namespace dispatch
307 {
308 
309 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
310 struct wkt: not_implemented<Tag>
311 {};
312 
313 template <typename Point>
314 struct wkt<Point, point_tag>
315     : detail::wkt::wkt_point
316         <
317             Point,
318             detail::wkt::prefix_point
319         >
320 {};
321 
322 template <typename Linestring>
323 struct wkt<Linestring, linestring_tag>
324     : detail::wkt::wkt_range
325         <
326             Linestring,
327             detail::wkt::prefix_linestring_par,
328             detail::wkt::closing_parenthesis
329         >
330 {};
331 
332 /*!
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
336 */
337 template <typename Box>
338 struct wkt<Box, box_tag>
339     : detail::wkt::wkt_box<Box>
340 {};
341 
342 template <typename Segment>
343 struct wkt<Segment, segment_tag>
344     : detail::wkt::wkt_segment<Segment>
345 {};
346 
347 /*!
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
352 */
353 template <typename Ring>
354 struct wkt<Ring, ring_tag>
355     : detail::wkt::wkt_range
356         <
357             Ring,
358             detail::wkt::prefix_ring_par_par,
359             detail::wkt::double_closing_parenthesis
360         >
361 {};
362 
363 /*!
364 \brief Specialization to stream polygon as WKT
365 */
366 template <typename Polygon>
367 struct wkt<Polygon, polygon_tag>
368     : detail::wkt::wkt_poly
369         <
370             Polygon,
371             detail::wkt::prefix_polygon
372         >
373 {};
374 
375 template <typename Multi>
376 struct wkt<Multi, multi_point_tag>
377     : detail::wkt::wkt_multi
378         <
379             Multi,
380             detail::wkt::wkt_point
381                 <
382                     typename boost::range_value<Multi>::type,
383                     detail::wkt::prefix_null
384                 >,
385             detail::wkt::prefix_multipoint
386         >
387 {};
388 
389 template <typename Multi>
390 struct wkt<Multi, multi_linestring_tag>
391     : detail::wkt::wkt_multi
392         <
393             Multi,
394             detail::wkt::wkt_sequence
395                 <
396                     typename boost::range_value<Multi>::type
397                 >,
398             detail::wkt::prefix_multilinestring
399         >
400 {};
401 
402 template <typename Multi>
403 struct wkt<Multi, multi_polygon_tag>
404     : detail::wkt::wkt_multi
405         <
406             Multi,
407             detail::wkt::wkt_poly
408                 <
409                     typename boost::range_value<Multi>::type,
410                     detail::wkt::prefix_null
411                 >,
412             detail::wkt::prefix_multipolygon
413         >
414 {};
415 
416 
417 template <typename Geometry>
418 struct devarianted_wkt
419 {
420     template <typename OutputStream>
applyboost::geometry::dispatch::devarianted_wkt421     static inline void apply(OutputStream& os, Geometry const& geometry)
422     {
423         wkt<Geometry>::apply(os, geometry);
424     }
425 };
426 
427 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
428 struct devarianted_wkt<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
429 {
430     template <typename OutputStream>
431     struct visitor: static_visitor<void>
432     {
433         OutputStream& m_os;
434 
visitorboost::geometry::dispatch::devarianted_wkt::visitor435         visitor(OutputStream& os)
436             : m_os(os)
437         {}
438 
439         template <typename Geometry>
operator ()boost::geometry::dispatch::devarianted_wkt::visitor440         inline void operator()(Geometry const& geometry) const
441         {
442             devarianted_wkt<Geometry>::apply(m_os, geometry);
443         }
444     };
445 
446     template <typename OutputStream>
applyboost::geometry::dispatch::devarianted_wkt447     static inline void apply(
448         OutputStream& os,
449         variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry
450     )
451     {
452         boost::apply_visitor(visitor<OutputStream>(os), geometry);
453     }
454 };
455 
456 
457 } // namespace dispatch
458 #endif // DOXYGEN_NO_DISPATCH
459 
460 /*!
461 \brief Generic geometry template manipulator class, takes corresponding output class from traits class
462 \ingroup wkt
463 \details Stream manipulator, streams geometry classes as \ref WKT streams
464 \par Example:
465 Small example showing how to use the wkt class
466 \dontinclude doxygen_1.cpp
467 \skip example_as_wkt_point
468 \line {
469 \until }
470 */
471 template <typename Geometry>
472 class wkt_manipulator
473 {
474 public:
475 
wkt_manipulator(Geometry const & g)476     inline wkt_manipulator(Geometry const& g)
477         : m_geometry(g)
478     {}
479 
480     template <typename Char, typename Traits>
operator <<(std::basic_ostream<Char,Traits> & os,wkt_manipulator const & m)481     inline friend std::basic_ostream<Char, Traits>& operator<<(
482             std::basic_ostream<Char, Traits>& os,
483             wkt_manipulator const& m)
484     {
485         dispatch::devarianted_wkt<Geometry>::apply(os, m.m_geometry);
486         os.flush();
487         return os;
488     }
489 
490 private:
491     Geometry const& m_geometry;
492 };
493 
494 /*!
495 \brief Main WKT-streaming function
496 \tparam Geometry \tparam_geometry
497 \param geometry \param_geometry
498 \ingroup wkt
499 \qbk{[include reference/io/wkt.qbk]}
500 */
501 template <typename Geometry>
wkt(Geometry const & geometry)502 inline wkt_manipulator<Geometry> wkt(Geometry const& geometry)
503 {
504     concept::check<Geometry const>();
505 
506     return wkt_manipulator<Geometry>(geometry);
507 }
508 
509 #if defined(_MSC_VER)
510 #pragma warning(pop)
511 #endif
512 
513 }} // namespace boost::geometry
514 
515 #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP
516