write.hpp 16 KB

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