]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/geometry/include/boost/geometry/io/wkt/write.hpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / geometry / include / boost / geometry / io / wkt / write.hpp
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>
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)
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>
130 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>
168 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>
196 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>
223 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>
252 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
266 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>
280 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
298 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>
421 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
435 visitor(OutputStream& os)
436 : m_os(os)
437 {}
438
439 template <typename Geometry>
440 inline void operator()(Geometry const& geometry) const
441 {
442 devarianted_wkt<Geometry>::apply(m_os, geometry);
443 }
444 };
445
446 template <typename OutputStream>
447 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
476 inline wkt_manipulator(Geometry const& g)
477 : m_geometry(g)
478 {}
479
480 template <typename Char, typename Traits>
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>
502 inline wkt_manipulator<Geometry> wkt(Geometry const& geometry)
503 {
504 concepts::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