]> git.proxmox.com Git - ceph.git/blame - 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
CommitLineData
7c673cae
FG
1// Boost.Geometry (aka GGL, Generic Geometry Library)
2
b32b8144
FG
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.
7c673cae
FG
7
8// This file was modified by Oracle on 2015.
b32b8144 9// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
7c673cae
FG
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
49namespace 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
59namespace detail { namespace wkt
60{
61
62template <typename P, int I, int Count>
63struct 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
73template <typename P, int Count>
74struct 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
81struct prefix_linestring_par
82{
83 static inline const char* apply() { return "LINESTRING("; }
84};
85
86struct 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
92struct opening_parenthesis
93{
94 static inline const char* apply() { return "("; }
95};
96
97struct closing_parenthesis
98{
99 static inline const char* apply() { return ")"; }
100};
101
102struct double_closing_parenthesis
103{
104 static inline const char* apply() { return "))"; }
105};
106
107/*!
108\brief Stream points as \ref WKT
109*/
110template <typename Point, typename Policy>
111struct wkt_point
112{
113 template <typename Char, typename Traits>
b32b8144 114 static inline void apply(std::basic_ostream<Char, Traits>& os, Point const& p, bool)
7c673cae
FG
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*/
b32b8144
FG
126template
127<
128 typename Range,
129 bool ForceClosurePossible,
130 typename PrefixPolicy,
131 typename SuffixPolicy
132>
7c673cae
FG
133struct wkt_range
134{
135 template <typename Char, typename Traits>
136 static inline void apply(std::basic_ostream<Char, Traits>& os,
b32b8144 137 Range const& range, bool force_closure = ForceClosurePossible)
7c673cae
FG
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
b32b8144
FG
162 if (ForceClosurePossible
163 && force_closure
7c673cae
FG
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
7c673cae
FG
174
175private:
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*/
b32b8144 183template <typename Range, bool ForceClosurePossible = true>
7c673cae
FG
184struct wkt_sequence
185 : wkt_range
186 <
187 Range,
b32b8144 188 ForceClosurePossible,
7c673cae
FG
189 opening_parenthesis,
190 closing_parenthesis
191 >
192{};
193
194template <typename Polygon, typename PrefixPolicy>
195struct wkt_poly
196{
197 template <typename Char, typename Traits>
198 static inline void apply(std::basic_ostream<Char, Traits>& os,
b32b8144 199 Polygon const& poly, bool force_closure)
7c673cae
FG
200 {
201 typedef typename ring_type<Polygon const>::type ring;
7c673cae
FG
202
203 os << PrefixPolicy::apply();
204 // TODO: check EMPTY here
205 os << "(";
b32b8144 206 wkt_sequence<ring>::apply(os, exterior_ring(poly), force_closure);
7c673cae
FG
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 << ",";
b32b8144 214 wkt_sequence<ring>::apply(os, *it, force_closure);
7c673cae
FG
215 }
216 os << ")";
217 }
b32b8144 218
7c673cae
FG
219};
220
221template <typename Multi, typename StreamPolicy, typename PrefixPolicy>
222struct wkt_multi
223{
224 template <typename Char, typename Traits>
225 static inline void apply(std::basic_ostream<Char, Traits>& os,
b32b8144 226 Multi const& geometry, bool force_closure)
7c673cae
FG
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 }
b32b8144 241 StreamPolicy::apply(os, *it, force_closure);
7c673cae
FG
242 }
243
244 os << ")";
245 }
246};
247
248template <typename Box>
249struct 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,
b32b8144 255 Box const& box, bool force_closure)
7c673cae 256 {
b32b8144
FG
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 }
7c673cae
FG
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 }
b32b8144
FG
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
7c673cae
FG
289};
290
291
292template <typename Segment>
293struct 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,
b32b8144 299 Segment const& segment, bool)
7c673cae
FG
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";
b32b8144 311 wkt_sequence<sequence, false>::apply(os, points);
7c673cae
FG
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
324namespace dispatch
325{
326
327template <typename Geometry, typename Tag = typename tag<Geometry>::type>
328struct wkt: not_implemented<Tag>
329{};
330
331template <typename Point>
332struct wkt<Point, point_tag>
333 : detail::wkt::wkt_point
334 <
335 Point,
336 detail::wkt::prefix_point
337 >
338{};
339
340template <typename Linestring>
341struct wkt<Linestring, linestring_tag>
342 : detail::wkt::wkt_range
343 <
344 Linestring,
b32b8144 345 false,
7c673cae
FG
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.
354It is therefore streamed as a polygon
355*/
356template <typename Box>
357struct wkt<Box, box_tag>
358 : detail::wkt::wkt_box<Box>
359{};
360
361template <typename Segment>
362struct 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.
369A ring is equivalent to a polygon without inner rings
370It is therefore streamed as a polygon
371*/
372template <typename Ring>
373struct wkt<Ring, ring_tag>
374 : detail::wkt::wkt_range
375 <
376 Ring,
b32b8144 377 true,
7c673cae
FG
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*/
386template <typename Polygon>
387struct wkt<Polygon, polygon_tag>
388 : detail::wkt::wkt_poly
389 <
390 Polygon,
391 detail::wkt::prefix_polygon
392 >
393{};
394
395template <typename Multi>
396struct 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
409template <typename Multi>
410struct wkt<Multi, multi_linestring_tag>
411 : detail::wkt::wkt_multi
412 <
413 Multi,
414 detail::wkt::wkt_sequence
415 <
b32b8144
FG
416 typename boost::range_value<Multi>::type,
417 false
7c673cae
FG
418 >,
419 detail::wkt::prefix_multilinestring
420 >
421{};
422
423template <typename Multi>
424struct 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
438template <typename Geometry>
439struct devarianted_wkt
440{
441 template <typename OutputStream>
b32b8144
FG
442 static inline void apply(OutputStream& os, Geometry const& geometry,
443 bool force_closure)
7c673cae 444 {
b32b8144 445 wkt<Geometry>::apply(os, geometry, force_closure);
7c673cae
FG
446 }
447};
448
449template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
450struct devarianted_wkt<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
451{
452 template <typename OutputStream>
453 struct visitor: static_visitor<void>
454 {
455 OutputStream& m_os;
b32b8144 456 bool m_force_closure;
7c673cae 457
b32b8144 458 visitor(OutputStream& os, bool force_closure)
7c673cae 459 : m_os(os)
b32b8144 460 , m_force_closure(force_closure)
7c673cae
FG
461 {}
462
463 template <typename Geometry>
464 inline void operator()(Geometry const& geometry) const
465 {
b32b8144 466 devarianted_wkt<Geometry>::apply(m_os, geometry, m_force_closure);
7c673cae
FG
467 }
468 };
469
470 template <typename OutputStream>
471 static inline void apply(
472 OutputStream& os,
b32b8144
FG
473 variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
474 bool force_closure)
7c673cae 475 {
b32b8144 476 boost::apply_visitor(visitor<OutputStream>(os, force_closure), geometry);
7c673cae
FG
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:
489Small example showing how to use the wkt class
490\dontinclude doxygen_1.cpp
491\skip example_as_wkt_point
492\line {
493\until }
494*/
495template <typename Geometry>
496class wkt_manipulator
497{
b32b8144
FG
498 static const bool is_ring = boost::is_same<typename tag<Geometry>::type, ring_tag>::value;
499
7c673cae
FG
500public:
501
b32b8144
FG
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)
7c673cae 506 : m_geometry(g)
b32b8144 507 , m_force_closure(force_closure)
7c673cae
FG
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 {
b32b8144 515 dispatch::devarianted_wkt<Geometry>::apply(os, m.m_geometry, m.m_force_closure);
7c673cae
FG
516 os.flush();
517 return os;
518 }
519
520private:
521 Geometry const& m_geometry;
b32b8144 522 bool m_force_closure;
7c673cae
FG
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*/
532template <typename Geometry>
533inline 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