write.hpp 10.0 KB

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