write.hpp 15 KB

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