]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/geometry/io/wkt/write.hpp
import quincy beta 17.1.0
[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-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>
72 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>
83 static inline void apply(std::basic_ostream<Char, Traits>&, P const&)
84 {}
85 };
86
87 struct prefix_linestring_par
88 {
89 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
95 static inline const char* apply() { return "POLYGON(("; }
96 };
97
98 struct opening_parenthesis
99 {
100 static inline const char* apply() { return "("; }
101 };
102
103 struct closing_parenthesis
104 {
105 static inline const char* apply() { return ")"; }
106 };
107
108 struct double_closing_parenthesis
109 {
110 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>
120 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>
142 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
184 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>
215 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>
242 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>
271 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
289 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>
296 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>
315 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
333 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>
459 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
475 visitor(OutputStream& os, bool force_closure)
476 : m_os(os)
477 , m_force_closure(force_closure)
478 {}
479
480 template <typename Geometry>
481 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>
488 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!
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>
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>
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