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-2020.
9 // Modifications copyright (c) 2015-2020, 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/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>
35 
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>
45 
46 #include <boost/geometry/geometries/concepts/check.hpp>
47 #include <boost/geometry/geometries/ring.hpp>
48 
49 #include <boost/geometry/io/wkt/detail/prefix.hpp>
50 
51 #include <boost/geometry/util/condition.hpp>
52 #include <boost/geometry/util/type_traits.hpp>
53 
54 
55 namespace boost { namespace geometry
56 {
57 
58 // Silence warning C4512: 'boost::geometry::wkt_manipulator<Geometry>' : assignment operator could not be generated
59 #if defined(_MSC_VER)
60 #pragma warning(push)
61 #pragma warning(disable : 4512)
62 #endif
63 
64 #ifndef DOXYGEN_NO_DETAIL
65 namespace detail { namespace wkt
66 {
67 
68 template <typename P, int I, int Count>
69 struct stream_coordinate
70 {
71     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::stream_coordinate72     static inline void apply(std::basic_ostream<Char, Traits>& os, P const& p)
73     {
74         os << (I > 0 ? " " : "") << get<I>(p);
75         stream_coordinate<P, I + 1, Count>::apply(os, p);
76     }
77 };
78 
79 template <typename P, int Count>
80 struct stream_coordinate<P, Count, Count>
81 {
82     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::stream_coordinate83     static inline void apply(std::basic_ostream<Char, Traits>&, P const&)
84     {}
85 };
86 
87 struct prefix_linestring_par
88 {
applyboost::geometry::detail::wkt::prefix_linestring_par89     static inline const char* apply() { return "LINESTRING("; }
90 };
91 
92 struct prefix_ring_par_par
93 {
94     // Note, double parentheses are intentional, indicating WKT ring begin/end
applyboost::geometry::detail::wkt::prefix_ring_par_par95     static inline const char* apply() { return "POLYGON(("; }
96 };
97 
98 struct opening_parenthesis
99 {
applyboost::geometry::detail::wkt::opening_parenthesis100     static inline const char* apply() { return "("; }
101 };
102 
103 struct closing_parenthesis
104 {
applyboost::geometry::detail::wkt::closing_parenthesis105     static inline const char* apply() { return ")"; }
106 };
107 
108 struct double_closing_parenthesis
109 {
applyboost::geometry::detail::wkt::double_closing_parenthesis110     static inline const char* apply() { return "))"; }
111 };
112 
113 /*!
114 \brief Stream points as \ref WKT
115 */
116 template <typename Point, typename Policy>
117 struct wkt_point
118 {
119     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::wkt_point120     static inline void apply(std::basic_ostream<Char, Traits>& os, Point const& p, bool)
121     {
122         os << Policy::apply() << "(";
123         stream_coordinate<Point, 0, dimension<Point>::type::value>::apply(os, p);
124         os << ")";
125     }
126 };
127 
128 /*!
129 \brief Stream ranges as WKT
130 \note policy is used to stream prefix/postfix, enabling derived classes to override this
131 */
132 template
133 <
134     typename Range,
135     bool ForceClosurePossible,
136     typename PrefixPolicy,
137     typename SuffixPolicy
138 >
139 struct wkt_range
140 {
141     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::wkt_range142     static inline void apply(std::basic_ostream<Char, Traits>& os,
143                 Range const& range, bool force_closure = ForceClosurePossible)
144     {
145         typedef typename boost::range_iterator<Range const>::type iterator_type;
146 
147         typedef stream_coordinate
148             <
149                 point_type, 0, dimension<point_type>::type::value
150             > stream_type;
151 
152         bool first = true;
153 
154         os << PrefixPolicy::apply();
155 
156         // TODO: check EMPTY here
157 
158         iterator_type begin = boost::begin(range);
159         iterator_type end = boost::end(range);
160         for (iterator_type it = begin; it != end; ++it)
161         {
162             os << (first ? "" : ",");
163             stream_type::apply(os, *it);
164             first = false;
165         }
166 
167         // optionally, close range to ring by repeating the first point
168         if (BOOST_GEOMETRY_CONDITION(ForceClosurePossible)
169             && force_closure
170             && boost::size(range) > 1
171             && wkt_range::disjoint(*begin, *(end - 1)))
172         {
173             os << ",";
174             stream_type::apply(os, *begin);
175         }
176 
177         os << SuffixPolicy::apply();
178     }
179 
180 
181 private:
182     typedef typename boost::range_value<Range>::type point_type;
183 
disjointboost::geometry::detail::wkt::wkt_range184     static inline bool disjoint(point_type const& p1, point_type const& p2)
185     {
186         // TODO: pass strategy
187         typedef typename strategy::disjoint::services::default_strategy
188             <
189                 point_type, point_type
190             >::type strategy_type;
191 
192         return detail::disjoint::disjoint_point_point(p1, p2, strategy_type());
193     }
194 };
195 
196 /*!
197 \brief Stream sequence of points as WKT-part, e.g. (1 2),(3 4)
198 \note Used in polygon, all multi-geometries
199 */
200 template <typename Range, bool ForceClosurePossible = true>
201 struct wkt_sequence
202     : wkt_range
203         <
204             Range,
205             ForceClosurePossible,
206             opening_parenthesis,
207             closing_parenthesis
208         >
209 {};
210 
211 template <typename Polygon, typename PrefixPolicy>
212 struct wkt_poly
213 {
214     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::wkt_poly215     static inline void apply(std::basic_ostream<Char, Traits>& os,
216                 Polygon const& poly, bool force_closure)
217     {
218         typedef typename ring_type<Polygon const>::type ring;
219 
220         os << PrefixPolicy::apply();
221         // TODO: check EMPTY here
222         os << "(";
223         wkt_sequence<ring>::apply(os, exterior_ring(poly), force_closure);
224 
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)
229         {
230             os << ",";
231             wkt_sequence<ring>::apply(os, *it, force_closure);
232         }
233         os << ")";
234     }
235 
236 };
237 
238 template <typename Multi, typename StreamPolicy, typename PrefixPolicy>
239 struct wkt_multi
240 {
241     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::wkt_multi242     static inline void apply(std::basic_ostream<Char, Traits>& os,
243                 Multi const& geometry, bool force_closure)
244     {
245         os << PrefixPolicy::apply();
246         // TODO: check EMPTY here
247         os << "(";
248 
249         for (typename boost::range_iterator<Multi const>::type
250                     it = boost::begin(geometry);
251             it != boost::end(geometry);
252             ++it)
253         {
254             if (it != boost::begin(geometry))
255             {
256                 os << ",";
257             }
258             StreamPolicy::apply(os, *it, force_closure);
259         }
260 
261         os << ")";
262     }
263 };
264 
265 template <typename Box>
266 struct wkt_box
267 {
268     typedef typename point_type<Box>::type point_type;
269 
270     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::wkt_box271     static inline void apply(std::basic_ostream<Char, Traits>& os,
272                 Box const& box, bool force_closure)
273     {
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, ...)) )
277         if (force_closure)
278         {
279             do_apply<model::ring<point_type, true, true> >(os, box);
280         }
281         else
282         {
283             do_apply<model::ring<point_type, true, false> >(os, box);
284         }
285     }
286 
287     private:
288 
wkt_boxboost::geometry::detail::wkt::wkt_box289         inline wkt_box()
290         {
291             // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron!
292             //assert_dimension<B, 2>();
293         }
294 
295         template <typename RingType, typename Char, typename Traits>
do_applyboost::geometry::detail::wkt::wkt_box296         static inline void do_apply(std::basic_ostream<Char, Traits>& os,
297                     Box const& box)
298         {
299             RingType ring;
300             geometry::convert(box, ring);
301             os << "POLYGON(";
302             wkt_sequence<RingType, false>::apply(os, ring);
303             os << ")";
304         }
305 
306 };
307 
308 
309 template <typename Segment>
310 struct wkt_segment
311 {
312     typedef typename point_type<Segment>::type point_type;
313 
314     template <typename Char, typename Traits>
applyboost::geometry::detail::wkt::wkt_segment315     static inline void apply(std::basic_ostream<Char, Traits>& os,
316                 Segment const& segment, bool)
317     {
318         // Convert to two points, then stream
319         typedef boost::array<point_type, 2> sequence;
320 
321         sequence points;
322         geometry::detail::assign_point_from_index<0>(segment, points[0]);
323         geometry::detail::assign_point_from_index<1>(segment, points[1]);
324 
325         // In Boost.Geometry a segment is represented
326         // in WKT-format like (for 2D): LINESTRING(x y,x y)
327         os << "LINESTRING";
328         wkt_sequence<sequence, false>::apply(os, points);
329     }
330 
331     private:
332 
wkt_segmentboost::geometry::detail::wkt::wkt_segment333         inline wkt_segment()
334         {}
335 };
336 
337 }} // namespace detail::wkt
338 #endif // DOXYGEN_NO_DETAIL
339 
340 #ifndef DOXYGEN_NO_DISPATCH
341 namespace dispatch
342 {
343 
344 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
345 struct wkt: not_implemented<Tag>
346 {};
347 
348 template <typename Point>
349 struct wkt<Point, point_tag>
350     : detail::wkt::wkt_point
351         <
352             Point,
353             detail::wkt::prefix_point
354         >
355 {};
356 
357 template <typename Linestring>
358 struct wkt<Linestring, linestring_tag>
359     : detail::wkt::wkt_range
360         <
361             Linestring,
362             false,
363             detail::wkt::prefix_linestring_par,
364             detail::wkt::closing_parenthesis
365         >
366 {};
367 
368 /*!
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
372 */
373 template <typename Box>
374 struct wkt<Box, box_tag>
375     : detail::wkt::wkt_box<Box>
376 {};
377 
378 template <typename Segment>
379 struct wkt<Segment, segment_tag>
380     : detail::wkt::wkt_segment<Segment>
381 {};
382 
383 /*!
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
388 */
389 template <typename Ring>
390 struct wkt<Ring, ring_tag>
391     : detail::wkt::wkt_range
392         <
393             Ring,
394             true,
395             detail::wkt::prefix_ring_par_par,
396             detail::wkt::double_closing_parenthesis
397         >
398 {};
399 
400 /*!
401 \brief Specialization to stream polygon as WKT
402 */
403 template <typename Polygon>
404 struct wkt<Polygon, polygon_tag>
405     : detail::wkt::wkt_poly
406         <
407             Polygon,
408             detail::wkt::prefix_polygon
409         >
410 {};
411 
412 template <typename Multi>
413 struct wkt<Multi, multi_point_tag>
414     : detail::wkt::wkt_multi
415         <
416             Multi,
417             detail::wkt::wkt_point
418                 <
419                     typename boost::range_value<Multi>::type,
420                     detail::wkt::prefix_null
421                 >,
422             detail::wkt::prefix_multipoint
423         >
424 {};
425 
426 template <typename Multi>
427 struct wkt<Multi, multi_linestring_tag>
428     : detail::wkt::wkt_multi
429         <
430             Multi,
431             detail::wkt::wkt_sequence
432                 <
433                     typename boost::range_value<Multi>::type,
434                     false
435                 >,
436             detail::wkt::prefix_multilinestring
437         >
438 {};
439 
440 template <typename Multi>
441 struct wkt<Multi, multi_polygon_tag>
442     : detail::wkt::wkt_multi
443         <
444             Multi,
445             detail::wkt::wkt_poly
446                 <
447                     typename boost::range_value<Multi>::type,
448                     detail::wkt::prefix_null
449                 >,
450             detail::wkt::prefix_multipolygon
451         >
452 {};
453 
454 
455 template <typename Geometry>
456 struct devarianted_wkt
457 {
458     template <typename OutputStream>
applyboost::geometry::dispatch::devarianted_wkt459     static inline void apply(OutputStream& os, Geometry const& geometry,
460                              bool force_closure)
461     {
462         wkt<Geometry>::apply(os, geometry, force_closure);
463     }
464 };
465 
466 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
467 struct devarianted_wkt<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
468 {
469     template <typename OutputStream>
470     struct visitor: static_visitor<void>
471     {
472         OutputStream& m_os;
473         bool m_force_closure;
474 
visitorboost::geometry::dispatch::devarianted_wkt::visitor475         visitor(OutputStream& os, bool force_closure)
476             : m_os(os)
477             , m_force_closure(force_closure)
478         {}
479 
480         template <typename Geometry>
operator ()boost::geometry::dispatch::devarianted_wkt::visitor481         inline void operator()(Geometry const& geometry) const
482         {
483             devarianted_wkt<Geometry>::apply(m_os, geometry, m_force_closure);
484         }
485     };
486 
487     template <typename OutputStream>
applyboost::geometry::dispatch::devarianted_wkt488     static inline void apply(
489         OutputStream& os,
490         variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
491         bool force_closure)
492     {
493         boost::apply_visitor(visitor<OutputStream>(os, force_closure), geometry);
494     }
495 };
496 
497 
498 } // namespace dispatch
499 #endif // DOXYGEN_NO_DISPATCH
500 
501 /*!
502 \brief Generic geometry template manipulator class, takes corresponding output class from traits class
503 \ingroup wkt
504 \details Stream manipulator, streams geometry classes as \ref WKT streams
505 \par Example:
506 Small example showing how to use the wkt class
507 \dontinclude doxygen_1.cpp
508 \skip example_as_wkt_point
509 \line {
510 \until }
511 */
512 template <typename Geometry>
513 class wkt_manipulator
514 {
515     static const bool is_ring = util::is_ring<Geometry>::value;
516 
517 public:
518 
519     // Boost.Geometry, by default, closes polygons explictly, but not rings
520     // NOTE: this might change in the future!
wkt_manipulator(Geometry const & g,bool force_closure=!is_ring)521     inline wkt_manipulator(Geometry const& g,
522                            bool force_closure = ! is_ring)
523         : m_geometry(g)
524         , m_force_closure(force_closure)
525     {}
526 
527     template <typename Char, typename Traits>
operator <<(std::basic_ostream<Char,Traits> & os,wkt_manipulator const & m)528     inline friend std::basic_ostream<Char, Traits>& operator<<(
529             std::basic_ostream<Char, Traits>& os,
530             wkt_manipulator const& m)
531     {
532         dispatch::devarianted_wkt<Geometry>::apply(os, m.m_geometry, m.m_force_closure);
533         os.flush();
534         return os;
535     }
536 
537 private:
538     Geometry const& m_geometry;
539     bool m_force_closure;
540 };
541 
542 /*!
543 \brief Main WKT-streaming function
544 \tparam Geometry \tparam_geometry
545 \param geometry \param_geometry
546 \ingroup wkt
547 \qbk{[include reference/io/wkt.qbk]}
548 */
549 template <typename Geometry>
wkt(Geometry const & geometry)550 inline wkt_manipulator<Geometry> wkt(Geometry const& geometry)
551 {
552     concepts::check<Geometry const>();
553 
554     return wkt_manipulator<Geometry>(geometry);
555 }
556 
557 #if defined(_MSC_VER)
558 #pragma warning(pop)
559 #endif
560 
561 }} // namespace boost::geometry
562 
563 #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP
564