write.hpp 12 KB

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