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