]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/geometry/io/wkt/write.hpp
update ceph source to reef 18.1.2
[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 // Copyright (c) 2020 Baidyanath Kundu, Haldia, India.
8
9 // This file was modified by Oracle on 2015-2021.
10 // Modifications copyright (c) 2015-2021, Oracle and/or its affiliates.
11
12 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
13 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
14
15 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
16 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
17
18 // Use, modification and distribution is subject to the Boost Software License,
19 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
20 // http://www.boost.org/LICENSE_1_0.txt)
21
22 #ifndef BOOST_GEOMETRY_IO_WKT_WRITE_HPP
23 #define BOOST_GEOMETRY_IO_WKT_WRITE_HPP
24
25 #include <ostream>
26 #include <string>
27
28 #include <boost/array.hpp>
29 #include <boost/range/begin.hpp>
30 #include <boost/range/end.hpp>
31 #include <boost/range/size.hpp>
32 #include <boost/range/value_type.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 #include <boost/geometry/core/visit.hpp>
44
45 #include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
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/strategies/io/cartesian.hpp>
52 #include <boost/geometry/strategies/io/geographic.hpp>
53 #include <boost/geometry/strategies/io/spherical.hpp>
54
55 #include <boost/geometry/util/condition.hpp>
56 #include <boost/geometry/util/type_traits.hpp>
57
58
59 namespace boost { namespace geometry
60 {
61
62 // Silence warning C4512: 'boost::geometry::wkt_manipulator<Geometry>' : assignment operator could not be generated
63 #if defined(_MSC_VER)
64 #pragma warning(push)
65 #pragma warning(disable : 4512)
66 #endif
67
68 #ifndef DOXYGEN_NO_DETAIL
69 namespace detail { namespace wkt
70 {
71
72 template <typename P, int I, int Count>
73 struct stream_coordinate
74 {
75 template <typename Char, typename Traits>
76 static inline void apply(std::basic_ostream<Char, Traits>& os, P const& p)
77 {
78 os << (I > 0 ? " " : "") << get<I>(p);
79 stream_coordinate<P, I + 1, Count>::apply(os, p);
80 }
81 };
82
83 template <typename P, int Count>
84 struct stream_coordinate<P, Count, Count>
85 {
86 template <typename Char, typename Traits>
87 static inline void apply(std::basic_ostream<Char, Traits>&, P const&)
88 {}
89 };
90
91 struct prefix_linestring_par
92 {
93 static inline const char* apply() { return "LINESTRING("; }
94 };
95
96 struct prefix_ring_par_par
97 {
98 // Note, double parentheses are intentional, indicating WKT ring begin/end
99 static inline const char* apply() { return "POLYGON(("; }
100 };
101
102 struct opening_parenthesis
103 {
104 static inline const char* apply() { return "("; }
105 };
106
107 struct closing_parenthesis
108 {
109 static inline const char* apply() { return ")"; }
110 };
111
112 struct double_closing_parenthesis
113 {
114 static inline const char* apply() { return "))"; }
115 };
116
117 /*!
118 \brief Stream points as \ref WKT
119 */
120 template <typename Point, typename Policy>
121 struct wkt_point
122 {
123 template <typename Char, typename Traits>
124 static inline void apply(std::basic_ostream<Char, Traits>& os, Point const& p, bool)
125 {
126 os << Policy::apply() << "(";
127 stream_coordinate<Point, 0, dimension<Point>::type::value>::apply(os, p);
128 os << ")";
129 }
130 };
131
132 /*!
133 \brief Stream ranges as WKT
134 \note policy is used to stream prefix/postfix, enabling derived classes to override this
135 */
136 template
137 <
138 typename Range,
139 bool ForceClosurePossible,
140 typename PrefixPolicy,
141 typename SuffixPolicy
142 >
143 struct wkt_range
144 {
145 template <typename Char, typename Traits>
146 static inline void apply(std::basic_ostream<Char, Traits>& os,
147 Range const& range, bool force_closure = ForceClosurePossible)
148 {
149 typedef typename boost::range_iterator<Range const>::type iterator_type;
150
151 typedef stream_coordinate
152 <
153 point_type, 0, dimension<point_type>::type::value
154 > stream_type;
155
156 bool first = true;
157
158 os << PrefixPolicy::apply();
159
160 // TODO: check EMPTY here
161
162 iterator_type begin = boost::begin(range);
163 iterator_type end = boost::end(range);
164 for (iterator_type it = begin; it != end; ++it)
165 {
166 os << (first ? "" : ",");
167 stream_type::apply(os, *it);
168 first = false;
169 }
170
171 // optionally, close range to ring by repeating the first point
172 if (BOOST_GEOMETRY_CONDITION(ForceClosurePossible)
173 && force_closure
174 && boost::size(range) > 1
175 && wkt_range::disjoint(*begin, *(end - 1)))
176 {
177 os << ",";
178 stream_type::apply(os, *begin);
179 }
180
181 os << SuffixPolicy::apply();
182 }
183
184
185 private:
186 typedef typename boost::range_value<Range>::type point_type;
187
188 static inline bool disjoint(point_type const& p1, point_type const& p2)
189 {
190 // TODO: pass strategy
191 typedef typename strategies::io::services::default_strategy
192 <
193 point_type
194 >::type strategy_type;
195
196 return detail::disjoint::disjoint_point_point(p1, p2, strategy_type());
197 }
198 };
199
200 /*!
201 \brief Stream sequence of points as WKT-part, e.g. (1 2),(3 4)
202 \note Used in polygon, all multi-geometries
203 */
204 template <typename Range, bool ForceClosurePossible = true>
205 struct wkt_sequence
206 : wkt_range
207 <
208 Range,
209 ForceClosurePossible,
210 opening_parenthesis,
211 closing_parenthesis
212 >
213 {};
214
215 template <typename Polygon, typename PrefixPolicy>
216 struct wkt_poly
217 {
218 template <typename Char, typename Traits>
219 static inline void apply(std::basic_ostream<Char, Traits>& os,
220 Polygon const& poly, bool force_closure)
221 {
222 typedef typename ring_type<Polygon const>::type ring;
223
224 os << PrefixPolicy::apply();
225 // TODO: check EMPTY here
226 os << "(";
227 wkt_sequence<ring>::apply(os, exterior_ring(poly), force_closure);
228
229 typename interior_return_type<Polygon const>::type
230 rings = interior_rings(poly);
231 for (typename detail::interior_iterator<Polygon const>::type
232 it = boost::begin(rings); it != boost::end(rings); ++it)
233 {
234 os << ",";
235 wkt_sequence<ring>::apply(os, *it, force_closure);
236 }
237 os << ")";
238 }
239
240 };
241
242 template <typename Multi, typename StreamPolicy, typename PrefixPolicy>
243 struct wkt_multi
244 {
245 template <typename Char, typename Traits>
246 static inline void apply(std::basic_ostream<Char, Traits>& os,
247 Multi const& geometry, bool force_closure)
248 {
249 os << PrefixPolicy::apply();
250 // TODO: check EMPTY here
251 os << "(";
252
253 for (typename boost::range_iterator<Multi const>::type
254 it = boost::begin(geometry);
255 it != boost::end(geometry);
256 ++it)
257 {
258 if (it != boost::begin(geometry))
259 {
260 os << ",";
261 }
262 StreamPolicy::apply(os, *it, force_closure);
263 }
264
265 os << ")";
266 }
267 };
268
269 template <typename Box>
270 struct wkt_box
271 {
272 typedef typename point_type<Box>::type point_type;
273
274 template <typename Char, typename Traits>
275 static inline void apply(std::basic_ostream<Char, Traits>& os,
276 Box const& box, bool force_closure)
277 {
278 // Convert to a clockwire ring, then stream.
279 // Never close it based on last point (box might be empty and
280 // that should result in POLYGON((0 0,0 0,0 0,0 0, ...)) )
281 if (force_closure)
282 {
283 do_apply<model::ring<point_type, true, true> >(os, box);
284 }
285 else
286 {
287 do_apply<model::ring<point_type, true, false> >(os, box);
288 }
289 }
290
291 private:
292
293 inline wkt_box()
294 {
295 // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron!
296 //assert_dimension<B, 2>();
297 }
298
299 template <typename RingType, typename Char, typename Traits>
300 static inline void do_apply(std::basic_ostream<Char, Traits>& os,
301 Box const& box)
302 {
303 RingType ring;
304 geometry::convert(box, ring);
305 os << "POLYGON(";
306 wkt_sequence<RingType, false>::apply(os, ring);
307 os << ")";
308 }
309
310 };
311
312
313 template <typename Segment>
314 struct wkt_segment
315 {
316 typedef typename point_type<Segment>::type point_type;
317
318 template <typename Char, typename Traits>
319 static inline void apply(std::basic_ostream<Char, Traits>& os,
320 Segment const& segment, bool)
321 {
322 // Convert to two points, then stream
323 typedef boost::array<point_type, 2> sequence;
324
325 sequence points;
326 geometry::detail::assign_point_from_index<0>(segment, points[0]);
327 geometry::detail::assign_point_from_index<1>(segment, points[1]);
328
329 // In Boost.Geometry a segment is represented
330 // in WKT-format like (for 2D): LINESTRING(x y,x y)
331 os << "LINESTRING";
332 wkt_sequence<sequence, false>::apply(os, points);
333 }
334
335 private:
336
337 inline wkt_segment()
338 {}
339 };
340
341 }} // namespace detail::wkt
342 #endif // DOXYGEN_NO_DETAIL
343
344 #ifndef DOXYGEN_NO_DISPATCH
345 namespace dispatch
346 {
347
348 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
349 struct wkt: not_implemented<Tag>
350 {};
351
352 template <typename Point>
353 struct wkt<Point, point_tag>
354 : detail::wkt::wkt_point
355 <
356 Point,
357 detail::wkt::prefix_point
358 >
359 {};
360
361 template <typename Linestring>
362 struct wkt<Linestring, linestring_tag>
363 : detail::wkt::wkt_range
364 <
365 Linestring,
366 false,
367 detail::wkt::prefix_linestring_par,
368 detail::wkt::closing_parenthesis
369 >
370 {};
371
372 /*!
373 \brief Specialization to stream a box as WKT
374 \details A "box" does not exist in WKT.
375 It is therefore streamed as a polygon
376 */
377 template <typename Box>
378 struct wkt<Box, box_tag>
379 : detail::wkt::wkt_box<Box>
380 {};
381
382 template <typename Segment>
383 struct wkt<Segment, segment_tag>
384 : detail::wkt::wkt_segment<Segment>
385 {};
386
387 /*!
388 \brief Specialization to stream a ring as WKT
389 \details A ring or "linear_ring" does not exist in WKT.
390 A ring is equivalent to a polygon without inner rings
391 It is therefore streamed as a polygon
392 */
393 template <typename Ring>
394 struct wkt<Ring, ring_tag>
395 : detail::wkt::wkt_range
396 <
397 Ring,
398 true,
399 detail::wkt::prefix_ring_par_par,
400 detail::wkt::double_closing_parenthesis
401 >
402 {};
403
404 /*!
405 \brief Specialization to stream polygon as WKT
406 */
407 template <typename Polygon>
408 struct wkt<Polygon, polygon_tag>
409 : detail::wkt::wkt_poly
410 <
411 Polygon,
412 detail::wkt::prefix_polygon
413 >
414 {};
415
416 template <typename Multi>
417 struct wkt<Multi, multi_point_tag>
418 : detail::wkt::wkt_multi
419 <
420 Multi,
421 detail::wkt::wkt_point
422 <
423 typename boost::range_value<Multi>::type,
424 detail::wkt::prefix_null
425 >,
426 detail::wkt::prefix_multipoint
427 >
428 {};
429
430 template <typename Multi>
431 struct wkt<Multi, multi_linestring_tag>
432 : detail::wkt::wkt_multi
433 <
434 Multi,
435 detail::wkt::wkt_sequence
436 <
437 typename boost::range_value<Multi>::type,
438 false
439 >,
440 detail::wkt::prefix_multilinestring
441 >
442 {};
443
444 template <typename Multi>
445 struct wkt<Multi, multi_polygon_tag>
446 : detail::wkt::wkt_multi
447 <
448 Multi,
449 detail::wkt::wkt_poly
450 <
451 typename boost::range_value<Multi>::type,
452 detail::wkt::prefix_null
453 >,
454 detail::wkt::prefix_multipolygon
455 >
456 {};
457
458
459 template <typename Geometry>
460 struct wkt<Geometry, dynamic_geometry_tag>
461 {
462 template <typename OutputStream>
463 static inline void apply(OutputStream& os, Geometry const& geometry,
464 bool force_closure)
465 {
466 traits::visit<Geometry>::apply([&](auto const& g)
467 {
468 wkt<util::remove_cref_t<decltype(g)>>::apply(os, g, force_closure);
469 }, geometry);
470 }
471 };
472
473 // TODO: Implement non-recursive version
474 template <typename Geometry>
475 struct wkt<Geometry, geometry_collection_tag>
476 {
477 template <typename OutputStream>
478 static inline void apply(OutputStream& os, Geometry const& geometry,
479 bool force_closure)
480 {
481 wkt::output_or_recursive_call(os, geometry, force_closure);
482 }
483
484 private:
485 template
486 <
487 typename OutputStream, typename Geom,
488 std::enable_if_t<util::is_geometry_collection<Geom>::value, int> = 0
489 >
490 static void output_or_recursive_call(OutputStream& os, Geom const& geom, bool force_closure)
491 {
492 os << "GEOMETRYCOLLECTION(";
493
494 bool first = true;
495 auto const end = boost::end(geom);
496 for (auto it = boost::begin(geom); it != end; ++it)
497 {
498 if (first)
499 first = false;
500 else
501 os << ',';
502
503 traits::iter_visit<Geom>::apply([&](auto const& g)
504 {
505 wkt::output_or_recursive_call(os, g, force_closure);
506 }, it);
507 }
508
509 os << ')';
510 }
511
512 template
513 <
514 typename OutputStream, typename Geom,
515 std::enable_if_t<! util::is_geometry_collection<Geom>::value, int> = 0
516 >
517 static void output_or_recursive_call(OutputStream& os, Geom const& geom, bool force_closure)
518 {
519 wkt<Geom>::apply(os, geom, force_closure);
520 }
521 };
522
523
524 } // namespace dispatch
525 #endif // DOXYGEN_NO_DISPATCH
526
527 /*!
528 \brief Generic geometry template manipulator class, takes corresponding output class from traits class
529 \ingroup wkt
530 \details Stream manipulator, streams geometry classes as \ref WKT streams
531 \par Example:
532 Small example showing how to use the wkt class
533 \dontinclude doxygen_1.cpp
534 \skip example_as_wkt_point
535 \line {
536 \until }
537 */
538 template <typename Geometry>
539 class wkt_manipulator
540 {
541 static const bool is_ring = util::is_ring<Geometry>::value;
542
543 public:
544
545 // Boost.Geometry, by default, closes polygons explictly, but not rings
546 // NOTE: this might change in the future!
547 inline wkt_manipulator(Geometry const& g,
548 bool force_closure = ! is_ring)
549 : m_geometry(g)
550 , m_force_closure(force_closure)
551 {}
552
553 template <typename Char, typename Traits>
554 inline friend std::basic_ostream<Char, Traits>& operator<<(
555 std::basic_ostream<Char, Traits>& os,
556 wkt_manipulator const& m)
557 {
558 dispatch::wkt<Geometry>::apply(os, m.m_geometry, m.m_force_closure);
559 os.flush();
560 return os;
561 }
562
563 private:
564 Geometry const& m_geometry;
565 bool m_force_closure;
566 };
567
568 /*!
569 \brief Main WKT-streaming function
570 \tparam Geometry \tparam_geometry
571 \param geometry \param_geometry
572 \ingroup wkt
573 \qbk{[include reference/io/wkt.qbk]}
574 */
575 template <typename Geometry>
576 inline wkt_manipulator<Geometry> wkt(Geometry const& geometry)
577 {
578 concepts::check<Geometry const>();
579
580 return wkt_manipulator<Geometry>(geometry);
581 }
582
583 /*!
584 \brief WKT-string formulating function
585 \tparam Geometry \tparam_geometry
586 \param geometry \param_geometry
587 \param significant_digits Specifies the no of significant digits to use in the output wkt
588 \ingroup wkt
589 \qbk{[include reference/io/to_wkt.qbk]}
590 */
591 template <typename Geometry>
592 inline std::string to_wkt(Geometry const& geometry)
593 {
594 std::stringstream ss;
595 ss << boost::geometry::wkt(geometry);
596 return ss.str();
597 }
598
599 template <typename Geometry>
600 inline std::string to_wkt(Geometry const& geometry, int significant_digits)
601 {
602 std::stringstream ss;
603 ss.precision(significant_digits);
604 ss << boost::geometry::wkt(geometry);
605 return ss.str();
606 }
607
608 #if defined(_MSC_VER)
609 #pragma warning(pop)
610 #endif
611
612 }} // namespace boost::geometry
613
614 #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP