write.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  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/geometry/algorithms/detail/interior_iterator.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. typedef typename boost::range_iterator<Range const>::type iterator_type;
  153. bool first = true;
  154. os << settings.list_open;
  155. for (iterator_type it = boost::begin(range);
  156. it != boost::end(range);
  157. ++it)
  158. {
  159. os << (first ? "" : settings.point_separator)
  160. << settings.point_open;
  161. stream_coordinate
  162. <
  163. point_type, 0, dimension<point_type>::type::value
  164. >::apply(os, *it, settings);
  165. os << settings.point_close;
  166. first = false;
  167. }
  168. os << settings.list_close;
  169. }
  170. private:
  171. typedef typename boost::range_value<Range>::type point_type;
  172. };
  173. /*!
  174. \brief Stream sequence of points as DSV-part, e.g. (1 2),(3 4)
  175. \note Used in polygon, all multi-geometries
  176. */
  177. template <typename Polygon>
  178. struct dsv_poly
  179. {
  180. template <typename Char, typename Traits>
  181. static inline void apply(std::basic_ostream<Char, Traits>& os,
  182. Polygon const& poly,
  183. dsv_settings const& settings)
  184. {
  185. typedef typename ring_type<Polygon>::type ring;
  186. os << settings.list_open;
  187. dsv_range<ring>::apply(os, exterior_ring(poly), settings);
  188. typename interior_return_type<Polygon const>::type
  189. rings = interior_rings(poly);
  190. for (typename detail::interior_iterator<Polygon const>::type
  191. it = boost::begin(rings); it != boost::end(rings); ++it)
  192. {
  193. os << settings.list_separator;
  194. dsv_range<ring>::apply(os, *it, settings);
  195. }
  196. os << settings.list_close;
  197. }
  198. };
  199. template <typename Geometry, std::size_t Index>
  200. struct dsv_per_index
  201. {
  202. typedef typename point_type<Geometry>::type point_type;
  203. template <typename Char, typename Traits>
  204. static inline void apply(std::basic_ostream<Char, Traits>& os,
  205. Geometry const& geometry,
  206. dsv_settings const& settings)
  207. {
  208. os << settings.point_open;
  209. stream_indexed
  210. <
  211. Geometry, Index, 0, dimension<Geometry>::type::value
  212. >::apply(os, geometry, settings);
  213. os << settings.point_close;
  214. }
  215. };
  216. template <typename Geometry>
  217. struct dsv_indexed
  218. {
  219. typedef typename point_type<Geometry>::type point_type;
  220. template <typename Char, typename Traits>
  221. static inline void apply(std::basic_ostream<Char, Traits>& os,
  222. Geometry const& geometry,
  223. dsv_settings const& settings)
  224. {
  225. os << settings.list_open;
  226. dsv_per_index<Geometry, 0>::apply(os, geometry, settings);
  227. os << settings.point_separator;
  228. dsv_per_index<Geometry, 1>::apply(os, geometry, settings);
  229. os << settings.list_close;
  230. }
  231. };
  232. }} // namespace detail::dsv
  233. #endif // DOXYGEN_NO_DETAIL
  234. #ifndef DOXYGEN_NO_DISPATCH
  235. namespace dispatch
  236. {
  237. template <typename Tag, typename Geometry>
  238. struct dsv {};
  239. template <typename Point>
  240. struct dsv<point_tag, Point>
  241. : detail::dsv::dsv_point<Point>
  242. {};
  243. template <typename Linestring>
  244. struct dsv<linestring_tag, Linestring>
  245. : detail::dsv::dsv_range<Linestring>
  246. {};
  247. template <typename Box>
  248. struct dsv<box_tag, Box>
  249. : detail::dsv::dsv_indexed<Box>
  250. {};
  251. template <typename Segment>
  252. struct dsv<segment_tag, Segment>
  253. : detail::dsv::dsv_indexed<Segment>
  254. {};
  255. template <typename Ring>
  256. struct dsv<ring_tag, Ring>
  257. : detail::dsv::dsv_range<Ring>
  258. {};
  259. template <typename Polygon>
  260. struct dsv<polygon_tag, Polygon>
  261. : detail::dsv::dsv_poly<Polygon>
  262. {};
  263. } // namespace dispatch
  264. #endif // DOXYGEN_NO_DISPATCH
  265. #ifndef DOXYGEN_NO_DETAIL
  266. namespace detail { namespace dsv
  267. {
  268. // FIXME: This class is not copyable/assignable but it is used as such --mloskot
  269. template <typename Geometry>
  270. class dsv_manipulator
  271. {
  272. public:
  273. inline dsv_manipulator(Geometry const& g,
  274. dsv_settings const& settings)
  275. : m_geometry(g)
  276. , m_settings(settings)
  277. {}
  278. template <typename Char, typename Traits>
  279. inline friend std::basic_ostream<Char, Traits>& operator<<(
  280. std::basic_ostream<Char, Traits>& os,
  281. dsv_manipulator const& m)
  282. {
  283. dispatch::dsv
  284. <
  285. typename tag_cast
  286. <
  287. typename tag<Geometry>::type,
  288. multi_tag
  289. >::type,
  290. Geometry
  291. >::apply(os, m.m_geometry, m.m_settings);
  292. os.flush();
  293. return os;
  294. }
  295. private:
  296. Geometry const& m_geometry;
  297. dsv_settings m_settings;
  298. };
  299. template <typename MultiGeometry>
  300. struct dsv_multi
  301. {
  302. typedef dispatch::dsv
  303. <
  304. typename single_tag_of
  305. <
  306. typename tag<MultiGeometry>::type
  307. >::type,
  308. typename boost::range_value<MultiGeometry>::type
  309. > dispatch_one;
  310. typedef typename boost::range_iterator
  311. <
  312. MultiGeometry const
  313. >::type iterator;
  314. template <typename Char, typename Traits>
  315. static inline void apply(std::basic_ostream<Char, Traits>& os,
  316. MultiGeometry const& multi,
  317. dsv_settings const& settings)
  318. {
  319. os << settings.list_open;
  320. bool first = true;
  321. for(iterator it = boost::begin(multi);
  322. it != boost::end(multi);
  323. ++it, first = false)
  324. {
  325. os << (first ? "" : settings.list_separator);
  326. dispatch_one::apply(os, *it, settings);
  327. }
  328. os << settings.list_close;
  329. }
  330. };
  331. }} // namespace detail::dsv
  332. #endif // DOXYGEN_NO_DETAIL
  333. // TODO: The alternative to this could be a forward declaration of dispatch::dsv<>
  334. // or braking the code into the interface and implementation part
  335. #ifndef DOXYGEN_NO_DISPATCH
  336. namespace dispatch
  337. {
  338. template <typename Geometry>
  339. struct dsv<multi_tag, Geometry>
  340. : detail::dsv::dsv_multi<Geometry>
  341. {};
  342. } // namespace dispatch
  343. #endif // DOXYGEN_NO_DISPATCH
  344. /*!
  345. \brief Main DSV-streaming function
  346. \details DSV stands for Delimiter Separated Values. Geometries can be streamed
  347. as DSV. There are defaults for all separators.
  348. \note Useful for examples and testing purposes
  349. \note With this function GeoJSON objects can be created, using the right
  350. delimiters
  351. \ingroup dsv
  352. */
  353. template <typename Geometry>
  354. inline detail::dsv::dsv_manipulator<Geometry> dsv(Geometry const& geometry
  355. , std::string const& coordinate_separator = ", "
  356. , std::string const& point_open = "("
  357. , std::string const& point_close = ")"
  358. , std::string const& point_separator = ", "
  359. , std::string const& list_open = "("
  360. , std::string const& list_close = ")"
  361. , std::string const& list_separator = ", "
  362. )
  363. {
  364. concepts::check<Geometry const>();
  365. return detail::dsv::dsv_manipulator<Geometry>(geometry,
  366. detail::dsv::dsv_settings(coordinate_separator,
  367. point_open, point_close, point_separator,
  368. list_open, list_close, list_separator));
  369. }
  370. }} // namespace boost::geometry
  371. #endif // BOOST_GEOMETRY_IO_DSV_WRITE_HPP