write.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  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. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
  6. // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
  7. // Use, modification and distribution is subject to the Boost Software License,
  8. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. #ifndef BOOST_GEOMETRY_IO_WKT_WRITE_HPP
  11. #define BOOST_GEOMETRY_IO_WKT_WRITE_HPP
  12. #include <ostream>
  13. #include <string>
  14. #include <boost/array.hpp>
  15. #include <boost/range.hpp>
  16. #include <boost/typeof/typeof.hpp>
  17. #include <boost/geometry/algorithms/assign.hpp>
  18. #include <boost/geometry/algorithms/convert.hpp>
  19. #include <boost/geometry/algorithms/not_implemented.hpp>
  20. #include <boost/geometry/core/exterior_ring.hpp>
  21. #include <boost/geometry/core/interior_rings.hpp>
  22. #include <boost/geometry/core/ring_type.hpp>
  23. #include <boost/geometry/geometries/concepts/check.hpp>
  24. #include <boost/geometry/geometries/ring.hpp>
  25. #include <boost/geometry/io/wkt/detail/prefix.hpp>
  26. #include <boost/variant/apply_visitor.hpp>
  27. #include <boost/variant/static_visitor.hpp>
  28. #include <boost/variant/variant_fwd.hpp>
  29. namespace boost { namespace geometry
  30. {
  31. // Silence warning C4512: 'boost::geometry::wkt_manipulator<Geometry>' : assignment operator could not be generated
  32. #if defined(_MSC_VER)
  33. #pragma warning(push)
  34. #pragma warning(disable : 4512)
  35. #endif
  36. #ifndef DOXYGEN_NO_DETAIL
  37. namespace detail { namespace wkt
  38. {
  39. template <typename P, int I, int Count>
  40. struct stream_coordinate
  41. {
  42. template <typename Char, typename Traits>
  43. static inline void apply(std::basic_ostream<Char, Traits>& os, P const& p)
  44. {
  45. os << (I > 0 ? " " : "") << get<I>(p);
  46. stream_coordinate<P, I + 1, Count>::apply(os, p);
  47. }
  48. };
  49. template <typename P, int Count>
  50. struct stream_coordinate<P, Count, Count>
  51. {
  52. template <typename Char, typename Traits>
  53. static inline void apply(std::basic_ostream<Char, Traits>&, P const&)
  54. {}
  55. };
  56. struct prefix_linestring_par
  57. {
  58. static inline const char* apply() { return "LINESTRING("; }
  59. };
  60. struct prefix_ring_par_par
  61. {
  62. // Note, double parentheses are intentional, indicating WKT ring begin/end
  63. static inline const char* apply() { return "POLYGON(("; }
  64. };
  65. struct opening_parenthesis
  66. {
  67. static inline const char* apply() { return "("; }
  68. };
  69. struct closing_parenthesis
  70. {
  71. static inline const char* apply() { return ")"; }
  72. };
  73. struct double_closing_parenthesis
  74. {
  75. static inline const char* apply() { return "))"; }
  76. };
  77. /*!
  78. \brief Stream points as \ref WKT
  79. */
  80. template <typename Point, typename Policy>
  81. struct wkt_point
  82. {
  83. template <typename Char, typename Traits>
  84. static inline void apply(std::basic_ostream<Char, Traits>& os, Point const& p)
  85. {
  86. os << Policy::apply() << "(";
  87. stream_coordinate<Point, 0, dimension<Point>::type::value>::apply(os, p);
  88. os << ")";
  89. }
  90. };
  91. /*!
  92. \brief Stream ranges as WKT
  93. \note policy is used to stream prefix/postfix, enabling derived classes to override this
  94. */
  95. template <typename Range, typename PrefixPolicy, typename SuffixPolicy>
  96. struct wkt_range
  97. {
  98. template <typename Char, typename Traits>
  99. static inline void apply(std::basic_ostream<Char, Traits>& os,
  100. Range const& range)
  101. {
  102. typedef typename boost::range_iterator<Range const>::type iterator_type;
  103. bool first = true;
  104. os << PrefixPolicy::apply();
  105. // TODO: check EMPTY here
  106. for (iterator_type it = boost::begin(range);
  107. it != boost::end(range);
  108. ++it)
  109. {
  110. os << (first ? "" : ",");
  111. stream_coordinate
  112. <
  113. point_type, 0, dimension<point_type>::type::value
  114. >::apply(os, *it);
  115. first = false;
  116. }
  117. os << SuffixPolicy::apply();
  118. }
  119. private:
  120. typedef typename boost::range_value<Range>::type point_type;
  121. };
  122. /*!
  123. \brief Stream sequence of points as WKT-part, e.g. (1 2),(3 4)
  124. \note Used in polygon, all multi-geometries
  125. */
  126. template <typename Range>
  127. struct wkt_sequence
  128. : wkt_range
  129. <
  130. Range,
  131. opening_parenthesis,
  132. closing_parenthesis
  133. >
  134. {};
  135. template <typename Polygon, typename PrefixPolicy>
  136. struct wkt_poly
  137. {
  138. template <typename Char, typename Traits>
  139. static inline void apply(std::basic_ostream<Char, Traits>& os,
  140. Polygon const& poly)
  141. {
  142. typedef typename ring_type<Polygon const>::type ring;
  143. os << PrefixPolicy::apply();
  144. // TODO: check EMPTY here
  145. os << "(";
  146. wkt_sequence<ring>::apply(os, exterior_ring(poly));
  147. typename interior_return_type<Polygon const>::type rings
  148. = interior_rings(poly);
  149. for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
  150. {
  151. os << ",";
  152. wkt_sequence<ring>::apply(os, *it);
  153. }
  154. os << ")";
  155. }
  156. };
  157. template <typename Box>
  158. struct wkt_box
  159. {
  160. typedef typename point_type<Box>::type point_type;
  161. template <typename Char, typename Traits>
  162. static inline void apply(std::basic_ostream<Char, Traits>& os,
  163. Box const& box)
  164. {
  165. // Convert to ring, then stream
  166. typedef model::ring<point_type> ring_type;
  167. ring_type ring;
  168. geometry::convert(box, ring);
  169. os << "POLYGON(";
  170. wkt_sequence<ring_type>::apply(os, ring);
  171. os << ")";
  172. }
  173. private:
  174. inline wkt_box()
  175. {
  176. // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron!
  177. //assert_dimension<B, 2>();
  178. }
  179. };
  180. template <typename Segment>
  181. struct wkt_segment
  182. {
  183. typedef typename point_type<Segment>::type point_type;
  184. template <typename Char, typename Traits>
  185. static inline void apply(std::basic_ostream<Char, Traits>& os,
  186. Segment const& segment)
  187. {
  188. // Convert to two points, then stream
  189. typedef boost::array<point_type, 2> sequence;
  190. sequence points;
  191. geometry::detail::assign_point_from_index<0>(segment, points[0]);
  192. geometry::detail::assign_point_from_index<1>(segment, points[1]);
  193. // In Boost.Geometry a segment is represented
  194. // in WKT-format like (for 2D): LINESTRING(x y,x y)
  195. os << "LINESTRING";
  196. wkt_sequence<sequence>::apply(os, points);
  197. }
  198. private:
  199. inline wkt_segment()
  200. {}
  201. };
  202. }} // namespace detail::wkt
  203. #endif // DOXYGEN_NO_DETAIL
  204. #ifndef DOXYGEN_NO_DISPATCH
  205. namespace dispatch
  206. {
  207. template <typename Geometry, typename Tag = typename tag<Geometry>::type>
  208. struct wkt: not_implemented<Tag>
  209. {};
  210. template <typename Point>
  211. struct wkt<Point, point_tag>
  212. : detail::wkt::wkt_point
  213. <
  214. Point,
  215. detail::wkt::prefix_point
  216. >
  217. {};
  218. template <typename Linestring>
  219. struct wkt<Linestring, linestring_tag>
  220. : detail::wkt::wkt_range
  221. <
  222. Linestring,
  223. detail::wkt::prefix_linestring_par,
  224. detail::wkt::closing_parenthesis
  225. >
  226. {};
  227. /*!
  228. \brief Specialization to stream a box as WKT
  229. \details A "box" does not exist in WKT.
  230. It is therefore streamed as a polygon
  231. */
  232. template <typename Box>
  233. struct wkt<Box, box_tag>
  234. : detail::wkt::wkt_box<Box>
  235. {};
  236. template <typename Segment>
  237. struct wkt<Segment, segment_tag>
  238. : detail::wkt::wkt_segment<Segment>
  239. {};
  240. /*!
  241. \brief Specialization to stream a ring as WKT
  242. \details A ring or "linear_ring" does not exist in WKT.
  243. A ring is equivalent to a polygon without inner rings
  244. It is therefore streamed as a polygon
  245. */
  246. template <typename Ring>
  247. struct wkt<Ring, ring_tag>
  248. : detail::wkt::wkt_range
  249. <
  250. Ring,
  251. detail::wkt::prefix_ring_par_par,
  252. detail::wkt::double_closing_parenthesis
  253. >
  254. {};
  255. /*!
  256. \brief Specialization to stream polygon as WKT
  257. */
  258. template <typename Polygon>
  259. struct wkt<Polygon, polygon_tag>
  260. : detail::wkt::wkt_poly
  261. <
  262. Polygon,
  263. detail::wkt::prefix_polygon
  264. >
  265. {};
  266. template <typename Geometry>
  267. struct devarianted_wkt
  268. {
  269. template <typename OutputStream>
  270. static inline void apply(OutputStream& os, Geometry const& geometry)
  271. {
  272. wkt<Geometry>::apply(os, geometry);
  273. }
  274. };
  275. template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
  276. struct devarianted_wkt<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
  277. {
  278. template <typename OutputStream>
  279. struct visitor: static_visitor<void>
  280. {
  281. OutputStream& m_os;
  282. visitor(OutputStream& os)
  283. : m_os(os)
  284. {}
  285. template <typename Geometry>
  286. inline void operator()(Geometry const& geometry) const
  287. {
  288. devarianted_wkt<Geometry>::apply(m_os, geometry);
  289. }
  290. };
  291. template <typename OutputStream>
  292. static inline void apply(
  293. OutputStream& os,
  294. variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry
  295. )
  296. {
  297. apply_visitor(visitor<OutputStream>(os), geometry);
  298. }
  299. };
  300. } // namespace dispatch
  301. #endif // DOXYGEN_NO_DISPATCH
  302. /*!
  303. \brief Generic geometry template manipulator class, takes corresponding output class from traits class
  304. \ingroup wkt
  305. \details Stream manipulator, streams geometry classes as \ref WKT streams
  306. \par Example:
  307. Small example showing how to use the wkt class
  308. \dontinclude doxygen_1.cpp
  309. \skip example_as_wkt_point
  310. \line {
  311. \until }
  312. */
  313. template <typename Geometry>
  314. class wkt_manipulator
  315. {
  316. public:
  317. inline wkt_manipulator(Geometry const& g)
  318. : m_geometry(g)
  319. {}
  320. template <typename Char, typename Traits>
  321. inline friend std::basic_ostream<Char, Traits>& operator<<(
  322. std::basic_ostream<Char, Traits>& os,
  323. wkt_manipulator const& m)
  324. {
  325. dispatch::devarianted_wkt<Geometry>::apply(os, m.m_geometry);
  326. os.flush();
  327. return os;
  328. }
  329. private:
  330. Geometry const& m_geometry;
  331. };
  332. /*!
  333. \brief Main WKT-streaming function
  334. \ingroup wkt
  335. \par Example:
  336. Small example showing how to use the wkt helper function
  337. \dontinclude doxygen_1.cpp
  338. \skip example_as_wkt_vector
  339. \line {
  340. \until }
  341. */
  342. template <typename Geometry>
  343. inline wkt_manipulator<Geometry> wkt(Geometry const& geometry)
  344. {
  345. concept::check<Geometry const>();
  346. return wkt_manipulator<Geometry>(geometry);
  347. }
  348. #if defined(_MSC_VER)
  349. #pragma warning(pop)
  350. #endif
  351. }} // namespace boost::geometry
  352. #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP