]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/geometry/io/wkt/write.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / geometry / io / wkt / write.hpp
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.
9 // Modifications copyright (c) 2015-2017, 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>
66 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>
77 static inline void apply(std::basic_ostream<Char, Traits>&, P const&)
78 {}
79 };
80
81 struct prefix_linestring_par
82 {
83 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
89 static inline const char* apply() { return "POLYGON(("; }
90 };
91
92 struct opening_parenthesis
93 {
94 static inline const char* apply() { return "("; }
95 };
96
97 struct closing_parenthesis
98 {
99 static inline const char* apply() { return ")"; }
100 };
101
102 struct double_closing_parenthesis
103 {
104 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>
114 static inline void apply(std::basic_ostream<Char, Traits>& os, Point const& p, bool)
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
127 <
128 typename Range,
129 bool ForceClosurePossible,
130 typename PrefixPolicy,
131 typename SuffixPolicy
132 >
133 struct wkt_range
134 {
135 template <typename Char, typename Traits>
136 static inline void apply(std::basic_ostream<Char, Traits>& os,
137 Range const& range, bool force_closure = ForceClosurePossible)
138 {
139 typedef typename boost::range_iterator<Range const>::type iterator_type;
140
141 typedef stream_coordinate
142 <
143 point_type, 0, dimension<point_type>::type::value
144 > stream_type;
145
146 bool first = true;
147
148 os << PrefixPolicy::apply();
149
150 // TODO: check EMPTY here
151
152 iterator_type begin = boost::begin(range);
153 iterator_type end = boost::end(range);
154 for (iterator_type it = begin; it != end; ++it)
155 {
156 os << (first ? "" : ",");
157 stream_type::apply(os, *it);
158 first = false;
159 }
160
161 // optionally, close range to ring by repeating the first point
162 if (ForceClosurePossible
163 && force_closure
164 && boost::size(range) > 1
165 && detail::disjoint::disjoint_point_point(*begin, *(end - 1)))
166 {
167 os << ",";
168 stream_type::apply(os, *begin);
169 }
170
171 os << SuffixPolicy::apply();
172 }
173
174
175 private:
176 typedef typename boost::range_value<Range>::type point_type;
177 };
178
179 /*!
180 \brief Stream sequence of points as WKT-part, e.g. (1 2),(3 4)
181 \note Used in polygon, all multi-geometries
182 */
183 template <typename Range, bool ForceClosurePossible = true>
184 struct wkt_sequence
185 : wkt_range
186 <
187 Range,
188 ForceClosurePossible,
189 opening_parenthesis,
190 closing_parenthesis
191 >
192 {};
193
194 template <typename Polygon, typename PrefixPolicy>
195 struct wkt_poly
196 {
197 template <typename Char, typename Traits>
198 static inline void apply(std::basic_ostream<Char, Traits>& os,
199 Polygon const& poly, bool force_closure)
200 {
201 typedef typename ring_type<Polygon const>::type ring;
202
203 os << PrefixPolicy::apply();
204 // TODO: check EMPTY here
205 os << "(";
206 wkt_sequence<ring>::apply(os, exterior_ring(poly), force_closure);
207
208 typename interior_return_type<Polygon const>::type
209 rings = interior_rings(poly);
210 for (typename detail::interior_iterator<Polygon const>::type
211 it = boost::begin(rings); it != boost::end(rings); ++it)
212 {
213 os << ",";
214 wkt_sequence<ring>::apply(os, *it, force_closure);
215 }
216 os << ")";
217 }
218
219 };
220
221 template <typename Multi, typename StreamPolicy, typename PrefixPolicy>
222 struct wkt_multi
223 {
224 template <typename Char, typename Traits>
225 static inline void apply(std::basic_ostream<Char, Traits>& os,
226 Multi const& geometry, bool force_closure)
227 {
228 os << PrefixPolicy::apply();
229 // TODO: check EMPTY here
230 os << "(";
231
232 for (typename boost::range_iterator<Multi const>::type
233 it = boost::begin(geometry);
234 it != boost::end(geometry);
235 ++it)
236 {
237 if (it != boost::begin(geometry))
238 {
239 os << ",";
240 }
241 StreamPolicy::apply(os, *it, force_closure);
242 }
243
244 os << ")";
245 }
246 };
247
248 template <typename Box>
249 struct wkt_box
250 {
251 typedef typename point_type<Box>::type point_type;
252
253 template <typename Char, typename Traits>
254 static inline void apply(std::basic_ostream<Char, Traits>& os,
255 Box const& box, bool force_closure)
256 {
257 // Convert to a clockwire ring, then stream.
258 // Never close it based on last point (box might be empty and
259 // that should result in POLYGON((0 0,0 0,0 0,0 0, ...)) )
260 if (force_closure)
261 {
262 do_apply<model::ring<point_type, true, true> >(os, box);
263 }
264 else
265 {
266 do_apply<model::ring<point_type, true, false> >(os, box);
267 }
268 }
269
270 private:
271
272 inline wkt_box()
273 {
274 // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron!
275 //assert_dimension<B, 2>();
276 }
277
278 template <typename RingType, typename Char, typename Traits>
279 static inline void do_apply(std::basic_ostream<Char, Traits>& os,
280 Box const& box)
281 {
282 RingType ring;
283 geometry::convert(box, ring);
284 os << "POLYGON(";
285 wkt_sequence<RingType, false>::apply(os, ring);
286 os << ")";
287 }
288
289 };
290
291
292 template <typename Segment>
293 struct wkt_segment
294 {
295 typedef typename point_type<Segment>::type point_type;
296
297 template <typename Char, typename Traits>
298 static inline void apply(std::basic_ostream<Char, Traits>& os,
299 Segment const& segment, bool)
300 {
301 // Convert to two points, then stream
302 typedef boost::array<point_type, 2> sequence;
303
304 sequence points;
305 geometry::detail::assign_point_from_index<0>(segment, points[0]);
306 geometry::detail::assign_point_from_index<1>(segment, points[1]);
307
308 // In Boost.Geometry a segment is represented
309 // in WKT-format like (for 2D): LINESTRING(x y,x y)
310 os << "LINESTRING";
311 wkt_sequence<sequence, false>::apply(os, points);
312 }
313
314 private:
315
316 inline wkt_segment()
317 {}
318 };
319
320 }} // namespace detail::wkt
321 #endif // DOXYGEN_NO_DETAIL
322
323 #ifndef DOXYGEN_NO_DISPATCH
324 namespace dispatch
325 {
326
327 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
328 struct wkt: not_implemented<Tag>
329 {};
330
331 template <typename Point>
332 struct wkt<Point, point_tag>
333 : detail::wkt::wkt_point
334 <
335 Point,
336 detail::wkt::prefix_point
337 >
338 {};
339
340 template <typename Linestring>
341 struct wkt<Linestring, linestring_tag>
342 : detail::wkt::wkt_range
343 <
344 Linestring,
345 false,
346 detail::wkt::prefix_linestring_par,
347 detail::wkt::closing_parenthesis
348 >
349 {};
350
351 /*!
352 \brief Specialization to stream a box as WKT
353 \details A "box" does not exist in WKT.
354 It is therefore streamed as a polygon
355 */
356 template <typename Box>
357 struct wkt<Box, box_tag>
358 : detail::wkt::wkt_box<Box>
359 {};
360
361 template <typename Segment>
362 struct wkt<Segment, segment_tag>
363 : detail::wkt::wkt_segment<Segment>
364 {};
365
366 /*!
367 \brief Specialization to stream a ring as WKT
368 \details A ring or "linear_ring" does not exist in WKT.
369 A ring is equivalent to a polygon without inner rings
370 It is therefore streamed as a polygon
371 */
372 template <typename Ring>
373 struct wkt<Ring, ring_tag>
374 : detail::wkt::wkt_range
375 <
376 Ring,
377 true,
378 detail::wkt::prefix_ring_par_par,
379 detail::wkt::double_closing_parenthesis
380 >
381 {};
382
383 /*!
384 \brief Specialization to stream polygon as WKT
385 */
386 template <typename Polygon>
387 struct wkt<Polygon, polygon_tag>
388 : detail::wkt::wkt_poly
389 <
390 Polygon,
391 detail::wkt::prefix_polygon
392 >
393 {};
394
395 template <typename Multi>
396 struct wkt<Multi, multi_point_tag>
397 : detail::wkt::wkt_multi
398 <
399 Multi,
400 detail::wkt::wkt_point
401 <
402 typename boost::range_value<Multi>::type,
403 detail::wkt::prefix_null
404 >,
405 detail::wkt::prefix_multipoint
406 >
407 {};
408
409 template <typename Multi>
410 struct wkt<Multi, multi_linestring_tag>
411 : detail::wkt::wkt_multi
412 <
413 Multi,
414 detail::wkt::wkt_sequence
415 <
416 typename boost::range_value<Multi>::type,
417 false
418 >,
419 detail::wkt::prefix_multilinestring
420 >
421 {};
422
423 template <typename Multi>
424 struct wkt<Multi, multi_polygon_tag>
425 : detail::wkt::wkt_multi
426 <
427 Multi,
428 detail::wkt::wkt_poly
429 <
430 typename boost::range_value<Multi>::type,
431 detail::wkt::prefix_null
432 >,
433 detail::wkt::prefix_multipolygon
434 >
435 {};
436
437
438 template <typename Geometry>
439 struct devarianted_wkt
440 {
441 template <typename OutputStream>
442 static inline void apply(OutputStream& os, Geometry const& geometry,
443 bool force_closure)
444 {
445 wkt<Geometry>::apply(os, geometry, force_closure);
446 }
447 };
448
449 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
450 struct devarianted_wkt<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
451 {
452 template <typename OutputStream>
453 struct visitor: static_visitor<void>
454 {
455 OutputStream& m_os;
456 bool m_force_closure;
457
458 visitor(OutputStream& os, bool force_closure)
459 : m_os(os)
460 , m_force_closure(force_closure)
461 {}
462
463 template <typename Geometry>
464 inline void operator()(Geometry const& geometry) const
465 {
466 devarianted_wkt<Geometry>::apply(m_os, geometry, m_force_closure);
467 }
468 };
469
470 template <typename OutputStream>
471 static inline void apply(
472 OutputStream& os,
473 variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
474 bool force_closure)
475 {
476 boost::apply_visitor(visitor<OutputStream>(os, force_closure), geometry);
477 }
478 };
479
480
481 } // namespace dispatch
482 #endif // DOXYGEN_NO_DISPATCH
483
484 /*!
485 \brief Generic geometry template manipulator class, takes corresponding output class from traits class
486 \ingroup wkt
487 \details Stream manipulator, streams geometry classes as \ref WKT streams
488 \par Example:
489 Small example showing how to use the wkt class
490 \dontinclude doxygen_1.cpp
491 \skip example_as_wkt_point
492 \line {
493 \until }
494 */
495 template <typename Geometry>
496 class wkt_manipulator
497 {
498 static const bool is_ring = boost::is_same<typename tag<Geometry>::type, ring_tag>::value;
499
500 public:
501
502 // Boost.Geometry, by default, closes polygons explictly, but not rings
503 // NOTE: this might change in the future!
504 inline wkt_manipulator(Geometry const& g,
505 bool force_closure = ! is_ring)
506 : m_geometry(g)
507 , m_force_closure(force_closure)
508 {}
509
510 template <typename Char, typename Traits>
511 inline friend std::basic_ostream<Char, Traits>& operator<<(
512 std::basic_ostream<Char, Traits>& os,
513 wkt_manipulator const& m)
514 {
515 dispatch::devarianted_wkt<Geometry>::apply(os, m.m_geometry, m.m_force_closure);
516 os.flush();
517 return os;
518 }
519
520 private:
521 Geometry const& m_geometry;
522 bool m_force_closure;
523 };
524
525 /*!
526 \brief Main WKT-streaming function
527 \tparam Geometry \tparam_geometry
528 \param geometry \param_geometry
529 \ingroup wkt
530 \qbk{[include reference/io/wkt.qbk]}
531 */
532 template <typename Geometry>
533 inline wkt_manipulator<Geometry> wkt(Geometry const& geometry)
534 {
535 concepts::check<Geometry const>();
536
537 return wkt_manipulator<Geometry>(geometry);
538 }
539
540 #if defined(_MSC_VER)
541 #pragma warning(pop)
542 #endif
543
544 }} // namespace boost::geometry
545
546 #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP