write.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2017 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2008-2017 Bruno Lalande, Paris, France.
  4. // Copyright (c) 2009-2017 Mateusz Loskot, London, UK.
  5. // Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland.
  6. // This file was modified by Oracle on 2015.
  7. // Modifications copyright (c) 2015-2017, 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, bool)
  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
  102. <
  103. typename Range,
  104. bool ForceClosurePossible,
  105. typename PrefixPolicy,
  106. typename SuffixPolicy
  107. >
  108. struct wkt_range
  109. {
  110. template <typename Char, typename Traits>
  111. static inline void apply(std::basic_ostream<Char, Traits>& os,
  112. Range const& range, bool force_closure = ForceClosurePossible)
  113. {
  114. typedef typename boost::range_iterator<Range const>::type iterator_type;
  115. typedef stream_coordinate
  116. <
  117. point_type, 0, dimension<point_type>::type::value
  118. > stream_type;
  119. bool first = true;
  120. os << PrefixPolicy::apply();
  121. // TODO: check EMPTY here
  122. iterator_type begin = boost::begin(range);
  123. iterator_type end = boost::end(range);
  124. for (iterator_type it = begin; it != end; ++it)
  125. {
  126. os << (first ? "" : ",");
  127. stream_type::apply(os, *it);
  128. first = false;
  129. }
  130. // optionally, close range to ring by repeating the first point
  131. if (ForceClosurePossible
  132. && force_closure
  133. && boost::size(range) > 1
  134. && detail::disjoint::disjoint_point_point(*begin, *(end - 1)))
  135. {
  136. os << ",";
  137. stream_type::apply(os, *begin);
  138. }
  139. os << SuffixPolicy::apply();
  140. }
  141. private:
  142. typedef typename boost::range_value<Range>::type point_type;
  143. };
  144. /*!
  145. \brief Stream sequence of points as WKT-part, e.g. (1 2),(3 4)
  146. \note Used in polygon, all multi-geometries
  147. */
  148. template <typename Range, bool ForceClosurePossible = true>
  149. struct wkt_sequence
  150. : wkt_range
  151. <
  152. Range,
  153. ForceClosurePossible,
  154. opening_parenthesis,
  155. closing_parenthesis
  156. >
  157. {};
  158. template <typename Polygon, typename PrefixPolicy>
  159. struct wkt_poly
  160. {
  161. template <typename Char, typename Traits>
  162. static inline void apply(std::basic_ostream<Char, Traits>& os,
  163. Polygon const& poly, bool force_closure)
  164. {
  165. typedef typename ring_type<Polygon const>::type ring;
  166. os << PrefixPolicy::apply();
  167. // TODO: check EMPTY here
  168. os << "(";
  169. wkt_sequence<ring>::apply(os, exterior_ring(poly), force_closure);
  170. typename interior_return_type<Polygon const>::type
  171. rings = interior_rings(poly);
  172. for (typename detail::interior_iterator<Polygon const>::type
  173. it = boost::begin(rings); it != boost::end(rings); ++it)
  174. {
  175. os << ",";
  176. wkt_sequence<ring>::apply(os, *it, force_closure);
  177. }
  178. os << ")";
  179. }
  180. };
  181. template <typename Multi, typename StreamPolicy, typename PrefixPolicy>
  182. struct wkt_multi
  183. {
  184. template <typename Char, typename Traits>
  185. static inline void apply(std::basic_ostream<Char, Traits>& os,
  186. Multi const& geometry, bool force_closure)
  187. {
  188. os << PrefixPolicy::apply();
  189. // TODO: check EMPTY here
  190. os << "(";
  191. for (typename boost::range_iterator<Multi const>::type
  192. it = boost::begin(geometry);
  193. it != boost::end(geometry);
  194. ++it)
  195. {
  196. if (it != boost::begin(geometry))
  197. {
  198. os << ",";
  199. }
  200. StreamPolicy::apply(os, *it, force_closure);
  201. }
  202. os << ")";
  203. }
  204. };
  205. template <typename Box>
  206. struct wkt_box
  207. {
  208. typedef typename point_type<Box>::type point_type;
  209. template <typename Char, typename Traits>
  210. static inline void apply(std::basic_ostream<Char, Traits>& os,
  211. Box const& box, bool force_closure)
  212. {
  213. // Convert to a clockwire ring, then stream.
  214. // Never close it based on last point (box might be empty and
  215. // that should result in POLYGON((0 0,0 0,0 0,0 0, ...)) )
  216. if (force_closure)
  217. {
  218. do_apply<model::ring<point_type, true, true> >(os, box);
  219. }
  220. else
  221. {
  222. do_apply<model::ring<point_type, true, false> >(os, box);
  223. }
  224. }
  225. private:
  226. inline wkt_box()
  227. {
  228. // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron!
  229. //assert_dimension<B, 2>();
  230. }
  231. template <typename RingType, typename Char, typename Traits>
  232. static inline void do_apply(std::basic_ostream<Char, Traits>& os,
  233. Box const& box)
  234. {
  235. RingType ring;
  236. geometry::convert(box, ring);
  237. os << "POLYGON(";
  238. wkt_sequence<RingType, false>::apply(os, ring);
  239. os << ")";
  240. }
  241. };
  242. template <typename Segment>
  243. struct wkt_segment
  244. {
  245. typedef typename point_type<Segment>::type point_type;
  246. template <typename Char, typename Traits>
  247. static inline void apply(std::basic_ostream<Char, Traits>& os,
  248. Segment const& segment, bool)
  249. {
  250. // Convert to two points, then stream
  251. typedef boost::array<point_type, 2> sequence;
  252. sequence points;
  253. geometry::detail::assign_point_from_index<0>(segment, points[0]);
  254. geometry::detail::assign_point_from_index<1>(segment, points[1]);
  255. // In Boost.Geometry a segment is represented
  256. // in WKT-format like (for 2D): LINESTRING(x y,x y)
  257. os << "LINESTRING";
  258. wkt_sequence<sequence, false>::apply(os, points);
  259. }
  260. private:
  261. inline wkt_segment()
  262. {}
  263. };
  264. }} // namespace detail::wkt
  265. #endif // DOXYGEN_NO_DETAIL
  266. #ifndef DOXYGEN_NO_DISPATCH
  267. namespace dispatch
  268. {
  269. template <typename Geometry, typename Tag = typename tag<Geometry>::type>
  270. struct wkt: not_implemented<Tag>
  271. {};
  272. template <typename Point>
  273. struct wkt<Point, point_tag>
  274. : detail::wkt::wkt_point
  275. <
  276. Point,
  277. detail::wkt::prefix_point
  278. >
  279. {};
  280. template <typename Linestring>
  281. struct wkt<Linestring, linestring_tag>
  282. : detail::wkt::wkt_range
  283. <
  284. Linestring,
  285. false,
  286. detail::wkt::prefix_linestring_par,
  287. detail::wkt::closing_parenthesis
  288. >
  289. {};
  290. /*!
  291. \brief Specialization to stream a box as WKT
  292. \details A "box" does not exist in WKT.
  293. It is therefore streamed as a polygon
  294. */
  295. template <typename Box>
  296. struct wkt<Box, box_tag>
  297. : detail::wkt::wkt_box<Box>
  298. {};
  299. template <typename Segment>
  300. struct wkt<Segment, segment_tag>
  301. : detail::wkt::wkt_segment<Segment>
  302. {};
  303. /*!
  304. \brief Specialization to stream a ring as WKT
  305. \details A ring or "linear_ring" does not exist in WKT.
  306. A ring is equivalent to a polygon without inner rings
  307. It is therefore streamed as a polygon
  308. */
  309. template <typename Ring>
  310. struct wkt<Ring, ring_tag>
  311. : detail::wkt::wkt_range
  312. <
  313. Ring,
  314. true,
  315. detail::wkt::prefix_ring_par_par,
  316. detail::wkt::double_closing_parenthesis
  317. >
  318. {};
  319. /*!
  320. \brief Specialization to stream polygon as WKT
  321. */
  322. template <typename Polygon>
  323. struct wkt<Polygon, polygon_tag>
  324. : detail::wkt::wkt_poly
  325. <
  326. Polygon,
  327. detail::wkt::prefix_polygon
  328. >
  329. {};
  330. template <typename Multi>
  331. struct wkt<Multi, multi_point_tag>
  332. : detail::wkt::wkt_multi
  333. <
  334. Multi,
  335. detail::wkt::wkt_point
  336. <
  337. typename boost::range_value<Multi>::type,
  338. detail::wkt::prefix_null
  339. >,
  340. detail::wkt::prefix_multipoint
  341. >
  342. {};
  343. template <typename Multi>
  344. struct wkt<Multi, multi_linestring_tag>
  345. : detail::wkt::wkt_multi
  346. <
  347. Multi,
  348. detail::wkt::wkt_sequence
  349. <
  350. typename boost::range_value<Multi>::type,
  351. false
  352. >,
  353. detail::wkt::prefix_multilinestring
  354. >
  355. {};
  356. template <typename Multi>
  357. struct wkt<Multi, multi_polygon_tag>
  358. : detail::wkt::wkt_multi
  359. <
  360. Multi,
  361. detail::wkt::wkt_poly
  362. <
  363. typename boost::range_value<Multi>::type,
  364. detail::wkt::prefix_null
  365. >,
  366. detail::wkt::prefix_multipolygon
  367. >
  368. {};
  369. template <typename Geometry>
  370. struct devarianted_wkt
  371. {
  372. template <typename OutputStream>
  373. static inline void apply(OutputStream& os, Geometry const& geometry,
  374. bool force_closure)
  375. {
  376. wkt<Geometry>::apply(os, geometry, force_closure);
  377. }
  378. };
  379. template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
  380. struct devarianted_wkt<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
  381. {
  382. template <typename OutputStream>
  383. struct visitor: static_visitor<void>
  384. {
  385. OutputStream& m_os;
  386. bool m_force_closure;
  387. visitor(OutputStream& os, bool force_closure)
  388. : m_os(os)
  389. , m_force_closure(force_closure)
  390. {}
  391. template <typename Geometry>
  392. inline void operator()(Geometry const& geometry) const
  393. {
  394. devarianted_wkt<Geometry>::apply(m_os, geometry, m_force_closure);
  395. }
  396. };
  397. template <typename OutputStream>
  398. static inline void apply(
  399. OutputStream& os,
  400. variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
  401. bool force_closure)
  402. {
  403. boost::apply_visitor(visitor<OutputStream>(os, force_closure), geometry);
  404. }
  405. };
  406. } // namespace dispatch
  407. #endif // DOXYGEN_NO_DISPATCH
  408. /*!
  409. \brief Generic geometry template manipulator class, takes corresponding output class from traits class
  410. \ingroup wkt
  411. \details Stream manipulator, streams geometry classes as \ref WKT streams
  412. \par Example:
  413. Small example showing how to use the wkt class
  414. \dontinclude doxygen_1.cpp
  415. \skip example_as_wkt_point
  416. \line {
  417. \until }
  418. */
  419. template <typename Geometry>
  420. class wkt_manipulator
  421. {
  422. static const bool is_ring = boost::is_same<typename tag<Geometry>::type, ring_tag>::value;
  423. public:
  424. // Boost.Geometry, by default, closes polygons explictly, but not rings
  425. // NOTE: this might change in the future!
  426. inline wkt_manipulator(Geometry const& g,
  427. bool force_closure = ! is_ring)
  428. : m_geometry(g)
  429. , m_force_closure(force_closure)
  430. {}
  431. template <typename Char, typename Traits>
  432. inline friend std::basic_ostream<Char, Traits>& operator<<(
  433. std::basic_ostream<Char, Traits>& os,
  434. wkt_manipulator const& m)
  435. {
  436. dispatch::devarianted_wkt<Geometry>::apply(os, m.m_geometry, m.m_force_closure);
  437. os.flush();
  438. return os;
  439. }
  440. private:
  441. Geometry const& m_geometry;
  442. bool m_force_closure;
  443. };
  444. /*!
  445. \brief Main WKT-streaming function
  446. \tparam Geometry \tparam_geometry
  447. \param geometry \param_geometry
  448. \ingroup wkt
  449. \qbk{[include reference/io/wkt.qbk]}
  450. */
  451. template <typename Geometry>
  452. inline wkt_manipulator<Geometry> wkt(Geometry const& geometry)
  453. {
  454. concepts::check<Geometry const>();
  455. return wkt_manipulator<Geometry>(geometry);
  456. }
  457. #if defined(_MSC_VER)
  458. #pragma warning(pop)
  459. #endif
  460. }} // namespace boost::geometry
  461. #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP