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