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