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