write.hpp 15 KB

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