write.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  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-2020.
  7. // Modifications copyright (c) 2018-2020, 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/begin.hpp>
  21. #include <boost/range/end.hpp>
  22. #include <boost/range/value_type.hpp>
  23. #include <boost/range/size.hpp>
  24. #include <boost/geometry/core/exterior_ring.hpp>
  25. #include <boost/geometry/core/interior_rings.hpp>
  26. #include <boost/geometry/core/ring_type.hpp>
  27. #include <boost/geometry/core/tag_cast.hpp>
  28. #include <boost/geometry/core/tags.hpp>
  29. #include <boost/geometry/geometries/concepts/check.hpp>
  30. namespace boost { namespace geometry
  31. {
  32. #ifndef DOXYGEN_NO_DETAIL
  33. namespace detail { namespace dsv
  34. {
  35. struct dsv_settings
  36. {
  37. std::string coordinate_separator;
  38. std::string point_open;
  39. std::string point_close;
  40. std::string point_separator;
  41. std::string list_open;
  42. std::string list_close;
  43. std::string list_separator;
  44. dsv_settings(std::string const& sep
  45. , std::string const& open
  46. , std::string const& close
  47. , std::string const& psep
  48. , std::string const& lopen
  49. , std::string const& lclose
  50. , std::string const& lsep
  51. )
  52. : coordinate_separator(sep)
  53. , point_open(open)
  54. , point_close(close)
  55. , point_separator(psep)
  56. , list_open(lopen)
  57. , list_close(lclose)
  58. , list_separator(lsep)
  59. {}
  60. };
  61. /*!
  62. \brief Stream coordinate of a point as \ref DSV
  63. */
  64. template <typename Point, std::size_t Dimension, std::size_t Count>
  65. struct stream_coordinate
  66. {
  67. template <typename Char, typename Traits>
  68. static inline void apply(std::basic_ostream<Char, Traits>& os,
  69. Point const& point,
  70. dsv_settings const& settings)
  71. {
  72. os << (Dimension > 0 ? settings.coordinate_separator : "")
  73. << get<Dimension>(point);
  74. stream_coordinate
  75. <
  76. Point, Dimension + 1, Count
  77. >::apply(os, point, settings);
  78. }
  79. };
  80. template <typename Point, std::size_t Count>
  81. struct stream_coordinate<Point, Count, Count>
  82. {
  83. template <typename Char, typename Traits>
  84. static inline void apply(std::basic_ostream<Char, Traits>&,
  85. Point const&,
  86. dsv_settings const& )
  87. {
  88. }
  89. };
  90. /*!
  91. \brief Stream indexed coordinate of a box/segment as \ref DSV
  92. */
  93. template
  94. <
  95. typename Geometry,
  96. std::size_t Index,
  97. std::size_t Dimension,
  98. std::size_t Count
  99. >
  100. struct stream_indexed
  101. {
  102. template <typename Char, typename Traits>
  103. static inline void apply(std::basic_ostream<Char, Traits>& os,
  104. Geometry const& geometry,
  105. dsv_settings const& settings)
  106. {
  107. os << (Dimension > 0 ? settings.coordinate_separator : "")
  108. << get<Index, Dimension>(geometry);
  109. stream_indexed
  110. <
  111. Geometry, Index, Dimension + 1, Count
  112. >::apply(os, geometry, settings);
  113. }
  114. };
  115. template <typename Geometry, std::size_t Index, std::size_t Count>
  116. struct stream_indexed<Geometry, Index, Count, Count>
  117. {
  118. template <typename Char, typename Traits>
  119. static inline void apply(std::basic_ostream<Char, Traits>&, Geometry const&,
  120. dsv_settings const& )
  121. {
  122. }
  123. };
  124. /*!
  125. \brief Stream points as \ref DSV
  126. */
  127. template <typename Point>
  128. struct dsv_point
  129. {
  130. template <typename Char, typename Traits>
  131. static inline void apply(std::basic_ostream<Char, Traits>& os,
  132. Point const& p,
  133. dsv_settings const& settings)
  134. {
  135. os << settings.point_open;
  136. stream_coordinate<Point, 0, dimension<Point>::type::value>::apply(os, p, settings);
  137. os << settings.point_close;
  138. }
  139. };
  140. /*!
  141. \brief Stream ranges as DSV
  142. \note policy is used to stream prefix/postfix, enabling derived classes to override this
  143. */
  144. template <typename Range>
  145. struct dsv_range
  146. {
  147. template <typename Char, typename Traits>
  148. static inline void apply(std::basic_ostream<Char, Traits>& os,
  149. Range const& range,
  150. dsv_settings const& settings)
  151. {
  152. bool first = true;
  153. os << settings.list_open;
  154. for (auto it = boost::begin(range); it != boost::end(range); ++it)
  155. {
  156. os << (first ? "" : settings.point_separator)
  157. << settings.point_open;
  158. stream_coordinate
  159. <
  160. point_type, 0, dimension<point_type>::type::value
  161. >::apply(os, *it, settings);
  162. os << settings.point_close;
  163. first = false;
  164. }
  165. os << settings.list_close;
  166. }
  167. private:
  168. typedef typename boost::range_value<Range>::type point_type;
  169. };
  170. /*!
  171. \brief Stream sequence of points as DSV-part, e.g. (1 2),(3 4)
  172. \note Used in polygon, all multi-geometries
  173. */
  174. template <typename Polygon>
  175. struct dsv_poly
  176. {
  177. template <typename Char, typename Traits>
  178. static inline void apply(std::basic_ostream<Char, Traits>& os,
  179. Polygon const& poly,
  180. dsv_settings const& settings)
  181. {
  182. typedef typename ring_type<Polygon>::type ring;
  183. os << settings.list_open;
  184. dsv_range<ring>::apply(os, exterior_ring(poly), settings);
  185. auto const& rings = interior_rings(poly);
  186. for (auto 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. template <typename Char, typename Traits>
  306. static inline void apply(std::basic_ostream<Char, Traits>& os,
  307. MultiGeometry const& multi,
  308. dsv_settings const& settings)
  309. {
  310. os << settings.list_open;
  311. bool first = true;
  312. for(auto it = boost::begin(multi); it != boost::end(multi); ++it, first = false)
  313. {
  314. os << (first ? "" : settings.list_separator);
  315. dispatch_one::apply(os, *it, settings);
  316. }
  317. os << settings.list_close;
  318. }
  319. };
  320. }} // namespace detail::dsv
  321. #endif // DOXYGEN_NO_DETAIL
  322. // TODO: The alternative to this could be a forward declaration of dispatch::dsv<>
  323. // or braking the code into the interface and implementation part
  324. #ifndef DOXYGEN_NO_DISPATCH
  325. namespace dispatch
  326. {
  327. template <typename Geometry>
  328. struct dsv<multi_tag, Geometry>
  329. : detail::dsv::dsv_multi<Geometry>
  330. {};
  331. } // namespace dispatch
  332. #endif // DOXYGEN_NO_DISPATCH
  333. /*!
  334. \brief Main DSV-streaming function
  335. \details DSV stands for Delimiter Separated Values. Geometries can be streamed
  336. as DSV. There are defaults for all separators.
  337. \note Useful for examples and testing purposes
  338. \note With this function GeoJSON objects can be created, using the right
  339. delimiters
  340. \ingroup dsv
  341. */
  342. template <typename Geometry>
  343. inline detail::dsv::dsv_manipulator<Geometry> dsv(Geometry const& geometry
  344. , std::string const& coordinate_separator = ", "
  345. , std::string const& point_open = "("
  346. , std::string const& point_close = ")"
  347. , std::string const& point_separator = ", "
  348. , std::string const& list_open = "("
  349. , std::string const& list_close = ")"
  350. , std::string const& list_separator = ", "
  351. )
  352. {
  353. concepts::check<Geometry const>();
  354. return detail::dsv::dsv_manipulator<Geometry>(geometry,
  355. detail::dsv::dsv_settings(coordinate_separator,
  356. point_open, point_close, point_separator,
  357. list_open, list_close, list_separator));
  358. }
  359. }} // namespace boost::geometry
  360. #endif // BOOST_GEOMETRY_IO_DSV_WRITE_HPP