write.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
  4. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
  5. // Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland.
  6. // This file was modified by Oracle on 2015.
  7. // Modifications copyright (c) 2015, Oracle and/or its affiliates.
  8. // Contributed and/or modified by Menelaos Karavelas, 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_WKT_WRITE_HPP
  15. #define BOOST_GEOMETRY_IO_WKT_WRITE_HPP
  16. #include <ostream>
  17. #include <string>
  18. #include <boost/array.hpp>
  19. #include <boost/range.hpp>
  20. #include <boost/variant/apply_visitor.hpp>
  21. #include <boost/variant/static_visitor.hpp>
  22. #include <boost/variant/variant_fwd.hpp>
  23. #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
  24. #include <boost/geometry/algorithms/assign.hpp>
  25. #include <boost/geometry/algorithms/convert.hpp>
  26. #include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
  27. #include <boost/geometry/algorithms/not_implemented.hpp>
  28. #include <boost/geometry/core/exterior_ring.hpp>
  29. #include <boost/geometry/core/interior_rings.hpp>
  30. #include <boost/geometry/core/ring_type.hpp>
  31. #include <boost/geometry/core/tags.hpp>
  32. #include <boost/geometry/geometries/concepts/check.hpp>
  33. #include <boost/geometry/geometries/ring.hpp>
  34. #include <boost/geometry/io/wkt/detail/prefix.hpp>
  35. namespace boost { namespace geometry
  36. {
  37. // Silence warning C4512: 'boost::geometry::wkt_manipulator<Geometry>' : assignment operator could not be generated
  38. #if defined(_MSC_VER)
  39. #pragma warning(push)
  40. #pragma warning(disable : 4512)
  41. #endif
  42. #ifndef DOXYGEN_NO_DETAIL
  43. namespace detail { namespace wkt
  44. {
  45. template <typename P, int I, int Count>
  46. struct stream_coordinate
  47. {
  48. template <typename Char, typename Traits>
  49. static inline void apply(std::basic_ostream<Char, Traits>& os, P const& p)
  50. {
  51. os << (I > 0 ? " " : "") << get<I>(p);
  52. stream_coordinate<P, I + 1, Count>::apply(os, p);
  53. }
  54. };
  55. template <typename P, int Count>
  56. struct stream_coordinate<P, Count, Count>
  57. {
  58. template <typename Char, typename Traits>
  59. static inline void apply(std::basic_ostream<Char, Traits>&, P const&)
  60. {}
  61. };
  62. struct prefix_linestring_par
  63. {
  64. static inline const char* apply() { return "LINESTRING("; }
  65. };
  66. struct prefix_ring_par_par
  67. {
  68. // Note, double parentheses are intentional, indicating WKT ring begin/end
  69. static inline const char* apply() { return "POLYGON(("; }
  70. };
  71. struct opening_parenthesis
  72. {
  73. static inline const char* apply() { return "("; }
  74. };
  75. struct closing_parenthesis
  76. {
  77. static inline const char* apply() { return ")"; }
  78. };
  79. struct double_closing_parenthesis
  80. {
  81. static inline const char* apply() { return "))"; }
  82. };
  83. /*!
  84. \brief Stream points as \ref WKT
  85. */
  86. template <typename Point, typename Policy>
  87. struct wkt_point
  88. {
  89. template <typename Char, typename Traits>
  90. static inline void apply(std::basic_ostream<Char, Traits>& os, Point const& p)
  91. {
  92. os << Policy::apply() << "(";
  93. stream_coordinate<Point, 0, dimension<Point>::type::value>::apply(os, p);
  94. os << ")";
  95. }
  96. };
  97. /*!
  98. \brief Stream ranges as WKT
  99. \note policy is used to stream prefix/postfix, enabling derived classes to override this
  100. */
  101. template <typename Range, typename PrefixPolicy, typename SuffixPolicy>
  102. struct wkt_range
  103. {
  104. template <typename Char, typename Traits>
  105. static inline void apply(std::basic_ostream<Char, Traits>& os,
  106. Range const& range, bool force_closed)
  107. {
  108. typedef typename boost::range_iterator<Range const>::type iterator_type;
  109. typedef stream_coordinate
  110. <
  111. point_type, 0, dimension<point_type>::type::value
  112. > stream_type;
  113. bool first = true;
  114. os << PrefixPolicy::apply();
  115. // TODO: check EMPTY here
  116. iterator_type begin = boost::begin(range);
  117. iterator_type end = boost::end(range);
  118. for (iterator_type it = begin; it != end; ++it)
  119. {
  120. os << (first ? "" : ",");
  121. stream_type::apply(os, *it);
  122. first = false;
  123. }
  124. // optionally, close range to ring by repeating the first point
  125. if (force_closed
  126. && boost::size(range) > 1
  127. && detail::disjoint::disjoint_point_point(*begin, *(end - 1)))
  128. {
  129. os << ",";
  130. stream_type::apply(os, *begin);
  131. }
  132. os << SuffixPolicy::apply();
  133. }
  134. template <typename Char, typename Traits>
  135. static inline void apply(std::basic_ostream<Char, Traits>& os,
  136. Range const& range)
  137. {
  138. apply(os, range, false);
  139. }
  140. private:
  141. typedef typename boost::range_value<Range>::type point_type;
  142. };
  143. /*!
  144. \brief Stream sequence of points as WKT-part, e.g. (1 2),(3 4)
  145. \note Used in polygon, all multi-geometries
  146. */
  147. template <typename Range>
  148. struct wkt_sequence
  149. : wkt_range
  150. <
  151. Range,
  152. opening_parenthesis,
  153. closing_parenthesis
  154. >
  155. {};
  156. template <typename Polygon, typename PrefixPolicy>
  157. struct wkt_poly
  158. {
  159. template <typename Char, typename Traits>
  160. static inline void apply(std::basic_ostream<Char, Traits>& os,
  161. Polygon const& poly)
  162. {
  163. typedef typename ring_type<Polygon const>::type ring;
  164. bool const force_closed = true;
  165. os << PrefixPolicy::apply();
  166. // TODO: check EMPTY here
  167. os << "(";
  168. wkt_sequence<ring>::apply(os, exterior_ring(poly), force_closed);
  169. typename interior_return_type<Polygon const>::type
  170. rings = interior_rings(poly);
  171. for (typename detail::interior_iterator<Polygon const>::type
  172. it = boost::begin(rings); it != boost::end(rings); ++it)
  173. {
  174. os << ",";
  175. wkt_sequence<ring>::apply(os, *it, force_closed);
  176. }
  177. os << ")";
  178. }
  179. };
  180. template <typename Multi, typename StreamPolicy, typename PrefixPolicy>
  181. struct wkt_multi
  182. {
  183. template <typename Char, typename Traits>
  184. static inline void apply(std::basic_ostream<Char, Traits>& os,
  185. Multi const& geometry)
  186. {
  187. os << PrefixPolicy::apply();
  188. // TODO: check EMPTY here
  189. os << "(";
  190. for (typename boost::range_iterator<Multi const>::type
  191. it = boost::begin(geometry);
  192. it != boost::end(geometry);
  193. ++it)
  194. {
  195. if (it != boost::begin(geometry))
  196. {
  197. os << ",";
  198. }
  199. StreamPolicy::apply(os, *it);
  200. }
  201. os << ")";
  202. }
  203. };
  204. template <typename Box>
  205. struct wkt_box
  206. {
  207. typedef typename point_type<Box>::type point_type;
  208. template <typename Char, typename Traits>
  209. static inline void apply(std::basic_ostream<Char, Traits>& os,
  210. Box const& box)
  211. {
  212. // Convert to ring, then stream
  213. typedef model::ring<point_type> ring_type;
  214. ring_type ring;
  215. geometry::convert(box, ring);
  216. os << "POLYGON(";
  217. wkt_sequence<ring_type>::apply(os, ring);
  218. os << ")";
  219. }
  220. private:
  221. inline wkt_box()
  222. {
  223. // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron!
  224. //assert_dimension<B, 2>();
  225. }
  226. };
  227. template <typename Segment>
  228. struct wkt_segment
  229. {
  230. typedef typename point_type<Segment>::type point_type;
  231. template <typename Char, typename Traits>
  232. static inline void apply(std::basic_ostream<Char, Traits>& os,
  233. Segment const& segment)
  234. {
  235. // Convert to two points, then stream
  236. typedef boost::array<point_type, 2> sequence;
  237. sequence points;
  238. geometry::detail::assign_point_from_index<0>(segment, points[0]);
  239. geometry::detail::assign_point_from_index<1>(segment, points[1]);
  240. // In Boost.Geometry a segment is represented
  241. // in WKT-format like (for 2D): LINESTRING(x y,x y)
  242. os << "LINESTRING";
  243. wkt_sequence<sequence>::apply(os, points);
  244. }
  245. private:
  246. inline wkt_segment()
  247. {}
  248. };
  249. }} // namespace detail::wkt
  250. #endif // DOXYGEN_NO_DETAIL
  251. #ifndef DOXYGEN_NO_DISPATCH
  252. namespace dispatch
  253. {
  254. template <typename Geometry, typename Tag = typename tag<Geometry>::type>
  255. struct wkt: not_implemented<Tag>
  256. {};
  257. template <typename Point>
  258. struct wkt<Point, point_tag>
  259. : detail::wkt::wkt_point
  260. <
  261. Point,
  262. detail::wkt::prefix_point
  263. >
  264. {};
  265. template <typename Linestring>
  266. struct wkt<Linestring, linestring_tag>
  267. : detail::wkt::wkt_range
  268. <
  269. Linestring,
  270. detail::wkt::prefix_linestring_par,
  271. detail::wkt::closing_parenthesis
  272. >
  273. {};
  274. /*!
  275. \brief Specialization to stream a box as WKT
  276. \details A "box" does not exist in WKT.
  277. It is therefore streamed as a polygon
  278. */
  279. template <typename Box>
  280. struct wkt<Box, box_tag>
  281. : detail::wkt::wkt_box<Box>
  282. {};
  283. template <typename Segment>
  284. struct wkt<Segment, segment_tag>
  285. : detail::wkt::wkt_segment<Segment>
  286. {};
  287. /*!
  288. \brief Specialization to stream a ring as WKT
  289. \details A ring or "linear_ring" does not exist in WKT.
  290. A ring is equivalent to a polygon without inner rings
  291. It is therefore streamed as a polygon
  292. */
  293. template <typename Ring>
  294. struct wkt<Ring, ring_tag>
  295. : detail::wkt::wkt_range
  296. <
  297. Ring,
  298. detail::wkt::prefix_ring_par_par,
  299. detail::wkt::double_closing_parenthesis
  300. >
  301. {};
  302. /*!
  303. \brief Specialization to stream polygon as WKT
  304. */
  305. template <typename Polygon>
  306. struct wkt<Polygon, polygon_tag>
  307. : detail::wkt::wkt_poly
  308. <
  309. Polygon,
  310. detail::wkt::prefix_polygon
  311. >
  312. {};
  313. template <typename Multi>
  314. struct wkt<Multi, multi_point_tag>
  315. : detail::wkt::wkt_multi
  316. <
  317. Multi,
  318. detail::wkt::wkt_point
  319. <
  320. typename boost::range_value<Multi>::type,
  321. detail::wkt::prefix_null
  322. >,
  323. detail::wkt::prefix_multipoint
  324. >
  325. {};
  326. template <typename Multi>
  327. struct wkt<Multi, multi_linestring_tag>
  328. : detail::wkt::wkt_multi
  329. <
  330. Multi,
  331. detail::wkt::wkt_sequence
  332. <
  333. typename boost::range_value<Multi>::type
  334. >,
  335. detail::wkt::prefix_multilinestring
  336. >
  337. {};
  338. template <typename Multi>
  339. struct wkt<Multi, multi_polygon_tag>
  340. : detail::wkt::wkt_multi
  341. <
  342. Multi,
  343. detail::wkt::wkt_poly
  344. <
  345. typename boost::range_value<Multi>::type,
  346. detail::wkt::prefix_null
  347. >,
  348. detail::wkt::prefix_multipolygon
  349. >
  350. {};
  351. template <typename Geometry>
  352. struct devarianted_wkt
  353. {
  354. template <typename OutputStream>
  355. static inline void apply(OutputStream& os, Geometry const& geometry)
  356. {
  357. wkt<Geometry>::apply(os, geometry);
  358. }
  359. };
  360. template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
  361. struct devarianted_wkt<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
  362. {
  363. template <typename OutputStream>
  364. struct visitor: static_visitor<void>
  365. {
  366. OutputStream& m_os;
  367. visitor(OutputStream& os)
  368. : m_os(os)
  369. {}
  370. template <typename Geometry>
  371. inline void operator()(Geometry const& geometry) const
  372. {
  373. devarianted_wkt<Geometry>::apply(m_os, geometry);
  374. }
  375. };
  376. template <typename OutputStream>
  377. static inline void apply(
  378. OutputStream& os,
  379. variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry
  380. )
  381. {
  382. boost::apply_visitor(visitor<OutputStream>(os), geometry);
  383. }
  384. };
  385. } // namespace dispatch
  386. #endif // DOXYGEN_NO_DISPATCH
  387. /*!
  388. \brief Generic geometry template manipulator class, takes corresponding output class from traits class
  389. \ingroup wkt
  390. \details Stream manipulator, streams geometry classes as \ref WKT streams
  391. \par Example:
  392. Small example showing how to use the wkt class
  393. \dontinclude doxygen_1.cpp
  394. \skip example_as_wkt_point
  395. \line {
  396. \until }
  397. */
  398. template <typename Geometry>
  399. class wkt_manipulator
  400. {
  401. public:
  402. inline wkt_manipulator(Geometry const& g)
  403. : m_geometry(g)
  404. {}
  405. template <typename Char, typename Traits>
  406. inline friend std::basic_ostream<Char, Traits>& operator<<(
  407. std::basic_ostream<Char, Traits>& os,
  408. wkt_manipulator const& m)
  409. {
  410. dispatch::devarianted_wkt<Geometry>::apply(os, m.m_geometry);
  411. os.flush();
  412. return os;
  413. }
  414. private:
  415. Geometry const& m_geometry;
  416. };
  417. /*!
  418. \brief Main WKT-streaming function
  419. \tparam Geometry \tparam_geometry
  420. \param geometry \param_geometry
  421. \ingroup wkt
  422. \qbk{[include reference/io/wkt.qbk]}
  423. */
  424. template <typename Geometry>
  425. inline wkt_manipulator<Geometry> wkt(Geometry const& geometry)
  426. {
  427. concept::check<Geometry const>();
  428. return wkt_manipulator<Geometry>(geometry);
  429. }
  430. #if defined(_MSC_VER)
  431. #pragma warning(pop)
  432. #endif
  433. }} // namespace boost::geometry
  434. #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP