1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
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.
7 
8 // This file was modified by Oracle on 2015, 2018, 2019.
9 // Modifications copyright (c) 2015-2019, Oracle and/or its affiliates.
10 
11 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
12 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
13 
14 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
15 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
16 
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)
20 
21 #ifndef BOOST_GEOMETRY_IO_WKT_WRITE_HPP
22 #define BOOST_GEOMETRY_IO_WKT_WRITE_HPP
23 
24 #include <ostream>
25 #include <string>
26 
27 #include <boost/array.hpp>
28 #include <boost/range.hpp>
29 
30 #include <boost/variant/apply_visitor.hpp>
31 #include <boost/variant/static_visitor.hpp>
32 #include <boost/variant/variant_fwd.hpp>
33 
34 #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
35 #include <boost/geometry/algorithms/assign.hpp>
36 #include <boost/geometry/algorithms/convert.hpp>
37 #include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
38 #include <boost/geometry/algorithms/not_implemented.hpp>
39 #include <boost/geometry/core/exterior_ring.hpp>
40 #include <boost/geometry/core/interior_rings.hpp>
41 #include <boost/geometry/core/ring_type.hpp>
42 #include <boost/geometry/core/tags.hpp>
43 
44 #include <boost/geometry/geometries/concepts/check.hpp>
45 #include <boost/geometry/geometries/ring.hpp>
46 
47 #include <boost/geometry/io/wkt/detail/prefix.hpp>
48 
49 #include <boost/geometry/util/condition.hpp>
50 
51 
52 namespace boost { namespace geometry
53 {
54 
55 // Silence warning C4512: 'boost::geometry::wkt_manipulator<Geometry>' : assignment operator could not be generated
56 #if defined(_MSC_VER)
57 #pragma warning(push)
58 #pragma warning(disable : 4512)
59 #endif
60 
61 #ifndef DOXYGEN_NO_DETAIL
62 namespace detail { namespace wkt
63 {
64 
65 template <typename P, int I, int Count>
66 struct stream_coordinate
67 {
68     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::stream_coordinate69     static inline void apply(std::basic_ostream<Char, Traits>& os, P const& p)
70     {
71         os << (I > 0 ? " " : "") << get<I>(p);
72         stream_coordinate<P, I + 1, Count>::apply(os, p);
73     }
74 };
75 
76 template <typename P, int Count>
77 struct stream_coordinate<P, Count, Count>
78 {
79     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::stream_coordinate80     static inline void apply(std::basic_ostream<Char, Traits>&, P const&)
81     {}
82 };
83 
84 struct prefix_linestring_par
85 {
applyboost::geometry::detail::wkt::prefix_linestring_par86     static inline const char* apply() { return "LINESTRING("; }
87 };
88 
89 struct prefix_ring_par_par
90 {
91     // Note, double parentheses are intentional, indicating WKT ring begin/end
applyboost::geometry::detail::wkt::prefix_ring_par_par92     static inline const char* apply() { return "POLYGON(("; }
93 };
94 
95 struct opening_parenthesis
96 {
applyboost::geometry::detail::wkt::opening_parenthesis97     static inline const char* apply() { return "("; }
98 };
99 
100 struct closing_parenthesis
101 {
applyboost::geometry::detail::wkt::closing_parenthesis102     static inline const char* apply() { return ")"; }
103 };
104 
105 struct double_closing_parenthesis
106 {
applyboost::geometry::detail::wkt::double_closing_parenthesis107     static inline const char* apply() { return "))"; }
108 };
109 
110 /*!
111 \brief Stream points as \ref WKT
112 */
113 template <typename Point, typename Policy>
114 struct wkt_point
115 {
116     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::wkt_point117     static inline void apply(std::basic_ostream<Char, Traits>& os, Point const& p, bool)
118     {
119         os << Policy::apply() << "(";
120         stream_coordinate<Point, 0, dimension<Point>::type::value>::apply(os, p);
121         os << ")";
122     }
123 };
124 
125 /*!
126 \brief Stream ranges as WKT
127 \note policy is used to stream prefix/postfix, enabling derived classes to override this
128 */
129 template
130 <
131     typename Range,
132     bool ForceClosurePossible,
133     typename PrefixPolicy,
134     typename SuffixPolicy
135 >
136 struct wkt_range
137 {
138     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::wkt_range139     static inline void apply(std::basic_ostream<Char, Traits>& os,
140                 Range const& range, bool force_closure = ForceClosurePossible)
141     {
142         typedef typename boost::range_iterator<Range const>::type iterator_type;
143 
144         typedef stream_coordinate
145             <
146                 point_type, 0, dimension<point_type>::type::value
147             > stream_type;
148 
149         bool first = true;
150 
151         os << PrefixPolicy::apply();
152 
153         // TODO: check EMPTY here
154 
155         iterator_type begin = boost::begin(range);
156         iterator_type end = boost::end(range);
157         for (iterator_type it = begin; it != end; ++it)
158         {
159             os << (first ? "" : ",");
160             stream_type::apply(os, *it);
161             first = false;
162         }
163 
164         // optionally, close range to ring by repeating the first point
165         if (BOOST_GEOMETRY_CONDITION(ForceClosurePossible)
166             && force_closure
167             && boost::size(range) > 1
168             && wkt_range::disjoint(*begin, *(end - 1)))
169         {
170             os << ",";
171             stream_type::apply(os, *begin);
172         }
173 
174         os << SuffixPolicy::apply();
175     }
176 
177 
178 private:
179     typedef typename boost::range_value<Range>::type point_type;
180 
disjointboost::geometry::detail::wkt::wkt_range181     static inline bool disjoint(point_type const& p1, point_type const& p2)
182     {
183         // TODO: pass strategy
184         typedef typename strategy::disjoint::services::default_strategy
185             <
186                 point_type, point_type
187             >::type strategy_type;
188 
189         return detail::disjoint::disjoint_point_point(p1, p2, strategy_type());
190     }
191 };
192 
193 /*!
194 \brief Stream sequence of points as WKT-part, e.g. (1 2),(3 4)
195 \note Used in polygon, all multi-geometries
196 */
197 template <typename Range, bool ForceClosurePossible = true>
198 struct wkt_sequence
199     : wkt_range
200         <
201             Range,
202             ForceClosurePossible,
203             opening_parenthesis,
204             closing_parenthesis
205         >
206 {};
207 
208 template <typename Polygon, typename PrefixPolicy>
209 struct wkt_poly
210 {
211     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::wkt_poly212     static inline void apply(std::basic_ostream<Char, Traits>& os,
213                 Polygon const& poly, bool force_closure)
214     {
215         typedef typename ring_type<Polygon const>::type ring;
216 
217         os << PrefixPolicy::apply();
218         // TODO: check EMPTY here
219         os << "(";
220         wkt_sequence<ring>::apply(os, exterior_ring(poly), force_closure);
221 
222         typename interior_return_type<Polygon const>::type
223             rings = interior_rings(poly);
224         for (typename detail::interior_iterator<Polygon const>::type
225                 it = boost::begin(rings); it != boost::end(rings); ++it)
226         {
227             os << ",";
228             wkt_sequence<ring>::apply(os, *it, force_closure);
229         }
230         os << ")";
231     }
232 
233 };
234 
235 template <typename Multi, typename StreamPolicy, typename PrefixPolicy>
236 struct wkt_multi
237 {
238     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::wkt_multi239     static inline void apply(std::basic_ostream<Char, Traits>& os,
240                 Multi const& geometry, bool force_closure)
241     {
242         os << PrefixPolicy::apply();
243         // TODO: check EMPTY here
244         os << "(";
245 
246         for (typename boost::range_iterator<Multi const>::type
247                     it = boost::begin(geometry);
248             it != boost::end(geometry);
249             ++it)
250         {
251             if (it != boost::begin(geometry))
252             {
253                 os << ",";
254             }
255             StreamPolicy::apply(os, *it, force_closure);
256         }
257 
258         os << ")";
259     }
260 };
261 
262 template <typename Box>
263 struct wkt_box
264 {
265     typedef typename point_type<Box>::type point_type;
266 
267     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::wkt_box268     static inline void apply(std::basic_ostream<Char, Traits>& os,
269                 Box const& box, bool force_closure)
270     {
271         // Convert to a clockwire ring, then stream.
272         // Never close it based on last point (box might be empty and
273         // that should result in POLYGON((0 0,0 0,0 0,0 0, ...)) )
274         if (force_closure)
275         {
276             do_apply<model::ring<point_type, true, true> >(os, box);
277         }
278         else
279         {
280             do_apply<model::ring<point_type, true, false> >(os, box);
281         }
282     }
283 
284     private:
285 
wkt_boxboost::geometry::detail::wkt::wkt_box286         inline wkt_box()
287         {
288             // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron!
289             //assert_dimension<B, 2>();
290         }
291 
292         template <typename RingType, typename Char, typename Traits>
do_applyboost::geometry::detail::wkt::wkt_box293         static inline void do_apply(std::basic_ostream<Char, Traits>& os,
294                     Box const& box)
295         {
296             RingType ring;
297             geometry::convert(box, ring);
298             os << "POLYGON(";
299             wkt_sequence<RingType, false>::apply(os, ring);
300             os << ")";
301         }
302 
303 };
304 
305 
306 template <typename Segment>
307 struct wkt_segment
308 {
309     typedef typename point_type<Segment>::type point_type;
310 
311     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::wkt_segment312     static inline void apply(std::basic_ostream<Char, Traits>& os,
313                 Segment const& segment, bool)
314     {
315         // Convert to two points, then stream
316         typedef boost::array<point_type, 2> sequence;
317 
318         sequence points;
319         geometry::detail::assign_point_from_index<0>(segment, points[0]);
320         geometry::detail::assign_point_from_index<1>(segment, points[1]);
321 
322         // In Boost.Geometry a segment is represented
323         // in WKT-format like (for 2D): LINESTRING(x y,x y)
324         os << "LINESTRING";
325         wkt_sequence<sequence, false>::apply(os, points);
326     }
327 
328     private:
329 
wkt_segmentboost::geometry::detail::wkt::wkt_segment330         inline wkt_segment()
331         {}
332 };
333 
334 }} // namespace detail::wkt
335 #endif // DOXYGEN_NO_DETAIL
336 
337 #ifndef DOXYGEN_NO_DISPATCH
338 namespace dispatch
339 {
340 
341 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
342 struct wkt: not_implemented<Tag>
343 {};
344 
345 template <typename Point>
346 struct wkt<Point, point_tag>
347     : detail::wkt::wkt_point
348         <
349             Point,
350             detail::wkt::prefix_point
351         >
352 {};
353 
354 template <typename Linestring>
355 struct wkt<Linestring, linestring_tag>
356     : detail::wkt::wkt_range
357         <
358             Linestring,
359             false,
360             detail::wkt::prefix_linestring_par,
361             detail::wkt::closing_parenthesis
362         >
363 {};
364 
365 /*!
366 \brief Specialization to stream a box as WKT
367 \details A "box" does not exist in WKT.
368 It is therefore streamed as a polygon
369 */
370 template <typename Box>
371 struct wkt<Box, box_tag>
372     : detail::wkt::wkt_box<Box>
373 {};
374 
375 template <typename Segment>
376 struct wkt<Segment, segment_tag>
377     : detail::wkt::wkt_segment<Segment>
378 {};
379 
380 /*!
381 \brief Specialization to stream a ring as WKT
382 \details A ring or "linear_ring" does not exist in WKT.
383 A ring is equivalent to a polygon without inner rings
384 It is therefore streamed as a polygon
385 */
386 template <typename Ring>
387 struct wkt<Ring, ring_tag>
388     : detail::wkt::wkt_range
389         <
390             Ring,
391             true,
392             detail::wkt::prefix_ring_par_par,
393             detail::wkt::double_closing_parenthesis
394         >
395 {};
396 
397 /*!
398 \brief Specialization to stream polygon as WKT
399 */
400 template <typename Polygon>
401 struct wkt<Polygon, polygon_tag>
402     : detail::wkt::wkt_poly
403         <
404             Polygon,
405             detail::wkt::prefix_polygon
406         >
407 {};
408 
409 template <typename Multi>
410 struct wkt<Multi, multi_point_tag>
411     : detail::wkt::wkt_multi
412         <
413             Multi,
414             detail::wkt::wkt_point
415                 <
416                     typename boost::range_value<Multi>::type,
417                     detail::wkt::prefix_null
418                 >,
419             detail::wkt::prefix_multipoint
420         >
421 {};
422 
423 template <typename Multi>
424 struct wkt<Multi, multi_linestring_tag>
425     : detail::wkt::wkt_multi
426         <
427             Multi,
428             detail::wkt::wkt_sequence
429                 <
430                     typename boost::range_value<Multi>::type,
431                     false
432                 >,
433             detail::wkt::prefix_multilinestring
434         >
435 {};
436 
437 template <typename Multi>
438 struct wkt<Multi, multi_polygon_tag>
439     : detail::wkt::wkt_multi
440         <
441             Multi,
442             detail::wkt::wkt_poly
443                 <
444                     typename boost::range_value<Multi>::type,
445                     detail::wkt::prefix_null
446                 >,
447             detail::wkt::prefix_multipolygon
448         >
449 {};
450 
451 
452 template <typename Geometry>
453 struct devarianted_wkt
454 {
455     template <typename OutputStream>
applyboost::geometry::dispatch::devarianted_wkt456     static inline void apply(OutputStream& os, Geometry const& geometry,
457                              bool force_closure)
458     {
459         wkt<Geometry>::apply(os, geometry, force_closure);
460     }
461 };
462 
463 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
464 struct devarianted_wkt<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
465 {
466     template <typename OutputStream>
467     struct visitor: static_visitor<void>
468     {
469         OutputStream& m_os;
470         bool m_force_closure;
471 
visitorboost::geometry::dispatch::devarianted_wkt::visitor472         visitor(OutputStream& os, bool force_closure)
473             : m_os(os)
474             , m_force_closure(force_closure)
475         {}
476 
477         template <typename Geometry>
operator ()boost::geometry::dispatch::devarianted_wkt::visitor478         inline void operator()(Geometry const& geometry) const
479         {
480             devarianted_wkt<Geometry>::apply(m_os, geometry, m_force_closure);
481         }
482     };
483 
484     template <typename OutputStream>
applyboost::geometry::dispatch::devarianted_wkt485     static inline void apply(
486         OutputStream& os,
487         variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
488         bool force_closure)
489     {
490         boost::apply_visitor(visitor<OutputStream>(os, force_closure), geometry);
491     }
492 };
493 
494 
495 } // namespace dispatch
496 #endif // DOXYGEN_NO_DISPATCH
497 
498 /*!
499 \brief Generic geometry template manipulator class, takes corresponding output class from traits class
500 \ingroup wkt
501 \details Stream manipulator, streams geometry classes as \ref WKT streams
502 \par Example:
503 Small example showing how to use the wkt class
504 \dontinclude doxygen_1.cpp
505 \skip example_as_wkt_point
506 \line {
507 \until }
508 */
509 template <typename Geometry>
510 class wkt_manipulator
511 {
512     static const bool is_ring = boost::is_same<typename tag<Geometry>::type, ring_tag>::value;
513 
514 public:
515 
516     // Boost.Geometry, by default, closes polygons explictly, but not rings
517     // NOTE: this might change in the future!
wkt_manipulator(Geometry const & g,bool force_closure=!is_ring)518     inline wkt_manipulator(Geometry const& g,
519                            bool force_closure = ! is_ring)
520         : m_geometry(g)
521         , m_force_closure(force_closure)
522     {}
523 
524     template <typename Char, typename Traits>
operator <<(std::basic_ostream<Char,Traits> & os,wkt_manipulator const & m)525     inline friend std::basic_ostream<Char, Traits>& operator<<(
526             std::basic_ostream<Char, Traits>& os,
527             wkt_manipulator const& m)
528     {
529         dispatch::devarianted_wkt<Geometry>::apply(os, m.m_geometry, m.m_force_closure);
530         os.flush();
531         return os;
532     }
533 
534 private:
535     Geometry const& m_geometry;
536     bool m_force_closure;
537 };
538 
539 /*!
540 \brief Main WKT-streaming function
541 \tparam Geometry \tparam_geometry
542 \param geometry \param_geometry
543 \ingroup wkt
544 \qbk{[include reference/io/wkt.qbk]}
545 */
546 template <typename Geometry>
wkt(Geometry const & geometry)547 inline wkt_manipulator<Geometry> wkt(Geometry const& geometry)
548 {
549     concepts::check<Geometry const>();
550 
551     return wkt_manipulator<Geometry>(geometry);
552 }
553 
554 #if defined(_MSC_VER)
555 #pragma warning(pop)
556 #endif
557 
558 }} // namespace boost::geometry
559 
560 #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP
561