write.hpp 12 KB

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