]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/geometry/include/boost/geometry/io/wkt/write.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / geometry / include / boost / geometry / io / wkt / write.hpp
CommitLineData
7c673cae
FG
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
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>
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*/
126template <typename Range, typename PrefixPolicy, typename SuffixPolicy>
127struct 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
174private:
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*/
182template <typename Range>
183struct wkt_sequence
184 : wkt_range
185 <
186 Range,
187 opening_parenthesis,
188 closing_parenthesis
189 >
190{};
191
192template <typename Polygon, typename PrefixPolicy>
193struct 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
219template <typename Multi, typename StreamPolicy, typename PrefixPolicy>
220struct 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
246template <typename Box>
247struct 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
274template <typename Segment>
275struct 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
306namespace dispatch
307{
308
309template <typename Geometry, typename Tag = typename tag<Geometry>::type>
310struct wkt: not_implemented<Tag>
311{};
312
313template <typename Point>
314struct wkt<Point, point_tag>
315 : detail::wkt::wkt_point
316 <
317 Point,
318 detail::wkt::prefix_point
319 >
320{};
321
322template <typename Linestring>
323struct 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.
335It is therefore streamed as a polygon
336*/
337template <typename Box>
338struct wkt<Box, box_tag>
339 : detail::wkt::wkt_box<Box>
340{};
341
342template <typename Segment>
343struct 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.
350A ring is equivalent to a polygon without inner rings
351It is therefore streamed as a polygon
352*/
353template <typename Ring>
354struct 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*/
366template <typename Polygon>
367struct wkt<Polygon, polygon_tag>
368 : detail::wkt::wkt_poly
369 <
370 Polygon,
371 detail::wkt::prefix_polygon
372 >
373{};
374
375template <typename Multi>
376struct 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
389template <typename Multi>
390struct 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
402template <typename Multi>
403struct 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
417template <typename Geometry>
418struct 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
427template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
428struct 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:
465Small example showing how to use the wkt class
466\dontinclude doxygen_1.cpp
467\skip example_as_wkt_point
468\line {
469\until }
470*/
471template <typename Geometry>
472class wkt_manipulator
473{
474public:
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
490private:
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*/
501template <typename Geometry>
502inline 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