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