Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / geometry / io / dsv / write.hpp
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
5 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
6 // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
7
8 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
9 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
10
11 // Use, modification and distribution is subject to the Boost Software License,
12 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
13 // http://www.boost.org/LICENSE_1_0.txt)
14
15 #ifndef BOOST_GEOMETRY_IO_DSV_WRITE_HPP
16 #define BOOST_GEOMETRY_IO_DSV_WRITE_HPP
17
18 #include <cstddef>
19 #include <ostream>
20 #include <string>
21
22 #include <boost/concept_check.hpp>
23 #include <boost/range.hpp>
24
25 #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
26
27 #include <boost/geometry/core/exterior_ring.hpp>
28 #include <boost/geometry/core/interior_rings.hpp>
29 #include <boost/geometry/core/ring_type.hpp>
30 #include <boost/geometry/core/tag_cast.hpp>
31 #include <boost/geometry/core/tags.hpp>
32
33 #include <boost/geometry/geometries/concepts/check.hpp>
34
35 namespace boost { namespace geometry
36 {
37
38 #ifndef DOXYGEN_NO_DETAIL
39 namespace detail { namespace dsv
40 {
41
42 struct dsv_settings
43 {
44     std::string coordinate_separator;
45     std::string point_open;
46     std::string point_close;
47     std::string point_separator;
48     std::string list_open;
49     std::string list_close;
50     std::string list_separator;
51
52     dsv_settings(std::string const& sep
53             , std::string const& open
54             , std::string const& close
55             , std::string const& psep
56             , std::string const& lopen
57             , std::string const& lclose
58             , std::string const& lsep
59             )
60         : coordinate_separator(sep)
61         , point_open(open)
62         , point_close(close)
63         , point_separator(psep)
64         , list_open(lopen)
65         , list_close(lclose)
66         , list_separator(lsep)
67     {}
68 };
69
70 /*!
71 \brief Stream coordinate of a point as \ref DSV
72 */
73 template <typename Point, std::size_t Dimension, std::size_t Count>
74 struct stream_coordinate
75 {
76     template <typename Char, typename Traits>
77     static inline void apply(std::basic_ostream<Char, Traits>& os,
78             Point const& point,
79             dsv_settings const& settings)
80     {
81         os << (Dimension > 0 ? settings.coordinate_separator : "")
82             << get<Dimension>(point);
83
84         stream_coordinate
85             <
86                 Point, Dimension + 1, Count
87             >::apply(os, point, settings);
88     }
89 };
90
91 template <typename Point, std::size_t Count>
92 struct stream_coordinate<Point, Count, Count>
93 {
94     template <typename Char, typename Traits>
95     static inline void apply(std::basic_ostream<Char, Traits>&,
96             Point const&,
97             dsv_settings const& )
98     {
99     }
100 };
101
102 /*!
103 \brief Stream indexed coordinate of a box/segment as \ref DSV
104 */
105 template
106 <
107     typename Geometry,
108     std::size_t Index,
109     std::size_t Dimension,
110     std::size_t Count
111 >
112 struct stream_indexed
113 {
114     template <typename Char, typename Traits>
115     static inline void apply(std::basic_ostream<Char, Traits>& os,
116             Geometry const& geometry,
117             dsv_settings const& settings)
118     {
119         os << (Dimension > 0 ? settings.coordinate_separator : "")
120             << get<Index, Dimension>(geometry);
121         stream_indexed
122             <
123                 Geometry, Index, Dimension + 1, Count
124             >::apply(os, geometry, settings);
125     }
126 };
127
128 template <typename Geometry, std::size_t Index, std::size_t Count>
129 struct stream_indexed<Geometry, Index, Count, Count>
130 {
131     template <typename Char, typename Traits>
132     static inline void apply(std::basic_ostream<Char, Traits>&, Geometry const&,
133             dsv_settings const& )
134     {
135     }
136 };
137
138 /*!
139 \brief Stream points as \ref DSV
140 */
141 template <typename Point>
142 struct dsv_point
143 {
144     template <typename Char, typename Traits>
145     static inline void apply(std::basic_ostream<Char, Traits>& os,
146             Point const& p,
147             dsv_settings const& settings)
148     {
149         os << settings.point_open;
150         stream_coordinate<Point, 0, dimension<Point>::type::value>::apply(os, p, settings);
151         os << settings.point_close;
152     }
153 };
154
155 /*!
156 \brief Stream ranges as DSV
157 \note policy is used to stream prefix/postfix, enabling derived classes to override this
158 */
159 template <typename Range>
160 struct dsv_range
161 {
162     template <typename Char, typename Traits>
163     static inline void apply(std::basic_ostream<Char, Traits>& os,
164             Range const& range,
165             dsv_settings const& settings)
166     {
167         typedef typename boost::range_iterator<Range const>::type iterator_type;
168
169         bool first = true;
170
171         os << settings.list_open;
172
173         for (iterator_type it = boost::begin(range);
174             it != boost::end(range);
175             ++it)
176         {
177             os << (first ? "" : settings.point_separator)
178                 << settings.point_open;
179
180             stream_coordinate
181                 <
182                     point_type, 0, dimension<point_type>::type::value
183                 >::apply(os, *it, settings);
184             os << settings.point_close;
185
186             first = false;
187         }
188
189         os << settings.list_close;
190     }
191
192 private:
193     typedef typename boost::range_value<Range>::type point_type;
194 };
195
196 /*!
197 \brief Stream sequence of points as DSV-part, e.g. (1 2),(3 4)
198 \note Used in polygon, all multi-geometries
199 */
200
201 template <typename Polygon>
202 struct dsv_poly
203 {
204     template <typename Char, typename Traits>
205     static inline void apply(std::basic_ostream<Char, Traits>& os,
206                 Polygon const& poly,
207                 dsv_settings const& settings)
208     {
209         typedef typename ring_type<Polygon>::type ring;
210
211         os << settings.list_open;
212
213         dsv_range<ring>::apply(os, exterior_ring(poly), settings);
214
215         typename interior_return_type<Polygon const>::type
216             rings = interior_rings(poly);
217         for (typename detail::interior_iterator<Polygon const>::type
218                 it = boost::begin(rings); it != boost::end(rings); ++it)
219         {
220             os << settings.list_separator;
221             dsv_range<ring>::apply(os, *it, settings);
222         }
223         os << settings.list_close;
224     }
225 };
226
227 template <typename Geometry, std::size_t Index>
228 struct dsv_per_index
229 {
230     typedef typename point_type<Geometry>::type point_type;
231
232     template <typename Char, typename Traits>
233     static inline void apply(std::basic_ostream<Char, Traits>& os,
234             Geometry const& geometry,
235             dsv_settings const& settings)
236     {
237         os << settings.point_open;
238         stream_indexed
239             <
240                 Geometry, Index, 0, dimension<Geometry>::type::value
241             >::apply(os, geometry, settings);
242         os << settings.point_close;
243     }
244 };
245
246 template <typename Geometry>
247 struct dsv_indexed
248 {
249     typedef typename point_type<Geometry>::type point_type;
250
251     template <typename Char, typename Traits>
252     static inline void apply(std::basic_ostream<Char, Traits>& os,
253             Geometry const& geometry,
254             dsv_settings const& settings)
255     {
256         os << settings.list_open;
257         dsv_per_index<Geometry, 0>::apply(os, geometry, settings);
258         os << settings.point_separator;
259         dsv_per_index<Geometry, 1>::apply(os, geometry, settings);
260         os << settings.list_close;
261     }
262 };
263
264 }} // namespace detail::dsv
265 #endif // DOXYGEN_NO_DETAIL
266
267 #ifndef DOXYGEN_NO_DISPATCH
268 namespace dispatch
269 {
270
271 template <typename Tag, typename Geometry>
272 struct dsv {};
273
274 template <typename Point>
275 struct dsv<point_tag, Point>
276     : detail::dsv::dsv_point<Point>
277 {};
278
279 template <typename Linestring>
280 struct dsv<linestring_tag, Linestring>
281     : detail::dsv::dsv_range<Linestring>
282 {};
283
284 template <typename Box>
285 struct dsv<box_tag, Box>
286     : detail::dsv::dsv_indexed<Box>
287 {};
288
289 template <typename Segment>
290 struct dsv<segment_tag, Segment>
291     : detail::dsv::dsv_indexed<Segment>
292 {};
293
294 template <typename Ring>
295 struct dsv<ring_tag, Ring>
296     : detail::dsv::dsv_range<Ring>
297 {};
298
299 template <typename Polygon>
300 struct dsv<polygon_tag, Polygon>
301     : detail::dsv::dsv_poly<Polygon>
302 {};
303
304 } // namespace dispatch
305 #endif // DOXYGEN_NO_DISPATCH
306
307 #ifndef DOXYGEN_NO_DETAIL
308 namespace detail { namespace dsv
309 {
310
311 // FIXME: This class is not copyable/assignable but it is used as such --mloskot
312 template <typename Geometry>
313 class dsv_manipulator
314 {
315 public:
316
317     inline dsv_manipulator(Geometry const& g,
318             dsv_settings const& settings)
319         : m_geometry(g)
320         , m_settings(settings)
321     {}
322
323     template <typename Char, typename Traits>
324     inline friend std::basic_ostream<Char, Traits>& operator<<(
325             std::basic_ostream<Char, Traits>& os,
326             dsv_manipulator const& m)
327     {
328         dispatch::dsv
329             <
330                 typename tag_cast
331                     <
332                         typename tag<Geometry>::type,
333                         multi_tag
334                     >::type,
335                 Geometry
336             >::apply(os, m.m_geometry, m.m_settings);
337         os.flush();
338         return os;
339     }
340
341 private:
342     Geometry const& m_geometry;
343     dsv_settings m_settings;
344 };
345
346
347 template <typename MultiGeometry>
348 struct dsv_multi
349 {
350     typedef dispatch::dsv
351                 <
352                     typename single_tag_of
353                         <
354                             typename tag<MultiGeometry>::type
355                         >::type,
356                     typename boost::range_value<MultiGeometry>::type
357                 > dispatch_one;
358
359     typedef typename boost::range_iterator
360         <
361             MultiGeometry const
362         >::type iterator;
363
364
365     template <typename Char, typename Traits>
366     static inline void apply(std::basic_ostream<Char, Traits>& os,
367                 MultiGeometry const& multi,
368                 dsv_settings const& settings)
369     {
370         os << settings.list_open;
371
372         bool first = true;
373         for(iterator it = boost::begin(multi);
374             it != boost::end(multi);
375             ++it, first = false)
376         {
377             os << (first ? "" : settings.list_separator);
378             dispatch_one::apply(os, *it, settings);
379         }
380         os << settings.list_close;
381     }
382 };
383
384 }} // namespace detail::dsv
385 #endif // DOXYGEN_NO_DETAIL
386
387 // TODO: The alternative to this could be a forward declaration of dispatch::dsv<>
388 //       or braking the code into the interface and implementation part
389 #ifndef DOXYGEN_NO_DISPATCH
390 namespace dispatch
391 {
392
393 template <typename Geometry>
394 struct dsv<multi_tag, Geometry>
395     : detail::dsv::dsv_multi<Geometry>
396 {};
397
398 } // namespace dispatch
399 #endif // DOXYGEN_NO_DISPATCH
400
401 /*!
402 \brief Main DSV-streaming function
403 \details DSV stands for Delimiter Separated Values. Geometries can be streamed
404     as DSV. There are defaults for all separators.
405 \note Useful for examples and testing purposes
406 \note With this function GeoJSON objects can be created, using the right
407     delimiters
408 \ingroup utility
409 */
410 template <typename Geometry>
411 inline detail::dsv::dsv_manipulator<Geometry> dsv(Geometry const& geometry
412     , std::string const& coordinate_separator = ", "
413     , std::string const& point_open = "("
414     , std::string const& point_close = ")"
415     , std::string const& point_separator = ", "
416     , std::string const& list_open = "("
417     , std::string const& list_close = ")"
418     , std::string const& list_separator = ", "
419     )
420 {
421     concept::check<Geometry const>();
422
423     return detail::dsv::dsv_manipulator<Geometry>(geometry,
424         detail::dsv::dsv_settings(coordinate_separator,
425             point_open, point_close, point_separator,
426             list_open, list_close, list_separator));
427 }
428
429 }} // namespace boost::geometry
430
431 #endif // BOOST_GEOMETRY_IO_DSV_WRITE_HPP