read.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
  4. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
  5. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
  6. // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
  7. // Use, modification and distribution is subject to the Boost Software License,
  8. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. #ifndef BOOST_GEOMETRY_IO_WKT_READ_HPP
  11. #define BOOST_GEOMETRY_IO_WKT_READ_HPP
  12. #include <string>
  13. #include <boost/lexical_cast.hpp>
  14. #include <boost/tokenizer.hpp>
  15. #include <boost/algorithm/string.hpp>
  16. #include <boost/mpl/if.hpp>
  17. #include <boost/range.hpp>
  18. #include <boost/type_traits.hpp>
  19. #include <boost/geometry/algorithms/assign.hpp>
  20. #include <boost/geometry/algorithms/append.hpp>
  21. #include <boost/geometry/algorithms/clear.hpp>
  22. #include <boost/geometry/core/access.hpp>
  23. #include <boost/geometry/core/coordinate_dimension.hpp>
  24. #include <boost/geometry/core/exception.hpp>
  25. #include <boost/geometry/core/exterior_ring.hpp>
  26. #include <boost/geometry/core/geometry_id.hpp>
  27. #include <boost/geometry/core/interior_rings.hpp>
  28. #include <boost/geometry/core/mutable_range.hpp>
  29. #include <boost/geometry/geometries/concepts/check.hpp>
  30. #include <boost/geometry/util/coordinate_cast.hpp>
  31. #include <boost/geometry/io/wkt/detail/prefix.hpp>
  32. namespace boost { namespace geometry
  33. {
  34. /*!
  35. \brief Exception showing things wrong with WKT parsing
  36. \ingroup wkt
  37. */
  38. struct read_wkt_exception : public geometry::exception
  39. {
  40. template <typename Iterator>
  41. read_wkt_exception(std::string const& msg,
  42. Iterator const& it, Iterator const& end, std::string const& wkt)
  43. : message(msg)
  44. , wkt(wkt)
  45. {
  46. if (it != end)
  47. {
  48. source = " at '";
  49. source += it->c_str();
  50. source += "'";
  51. }
  52. complete = message + source + " in '" + wkt.substr(0, 100) + "'";
  53. }
  54. read_wkt_exception(std::string const& msg, std::string const& wkt)
  55. : message(msg)
  56. , wkt(wkt)
  57. {
  58. complete = message + "' in (" + wkt.substr(0, 100) + ")";
  59. }
  60. virtual ~read_wkt_exception() throw() {}
  61. virtual const char* what() const throw()
  62. {
  63. return complete.c_str();
  64. }
  65. private :
  66. std::string source;
  67. std::string message;
  68. std::string wkt;
  69. std::string complete;
  70. };
  71. #ifndef DOXYGEN_NO_DETAIL
  72. // (wkt: Well Known Text, defined by OGC for all geometries and implemented by e.g. databases (MySQL, PostGIS))
  73. namespace detail { namespace wkt
  74. {
  75. typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
  76. template <typename Point, std::size_t Dimension, std::size_t DimensionCount>
  77. struct parsing_assigner
  78. {
  79. static inline void apply(tokenizer::iterator& it, tokenizer::iterator end,
  80. Point& point, std::string const& wkt)
  81. {
  82. typedef typename coordinate_type<Point>::type coordinate_type;
  83. // Stop at end of tokens, or at "," ot ")"
  84. bool finished = (it == end || *it == "," || *it == ")");
  85. try
  86. {
  87. // Initialize missing coordinates to default constructor (zero)
  88. // OR
  89. // Use lexical_cast for conversion to double/int
  90. // Note that it is much slower than atof. However, it is more standard
  91. // and in parsing the change in performance falls probably away against
  92. // the tokenizing
  93. set<Dimension>(point, finished
  94. ? coordinate_type()
  95. : coordinate_cast<coordinate_type>::apply(*it));
  96. }
  97. catch(boost::bad_lexical_cast const& blc)
  98. {
  99. throw read_wkt_exception(blc.what(), it, end, wkt);
  100. }
  101. catch(std::exception const& e)
  102. {
  103. throw read_wkt_exception(e.what(), it, end, wkt);
  104. }
  105. catch(...)
  106. {
  107. throw read_wkt_exception("", it, end, wkt);
  108. }
  109. parsing_assigner<Point, Dimension + 1, DimensionCount>::apply(
  110. (finished ? it : ++it), end, point, wkt);
  111. }
  112. };
  113. template <typename Point, std::size_t DimensionCount>
  114. struct parsing_assigner<Point, DimensionCount, DimensionCount>
  115. {
  116. static inline void apply(tokenizer::iterator&, tokenizer::iterator, Point&,
  117. std::string const&)
  118. {
  119. }
  120. };
  121. template <typename Iterator>
  122. inline void handle_open_parenthesis(Iterator& it,
  123. Iterator const& end, std::string const& wkt)
  124. {
  125. if (it == end || *it != "(")
  126. {
  127. throw read_wkt_exception("Expected '('", it, end, wkt);
  128. }
  129. ++it;
  130. }
  131. template <typename Iterator>
  132. inline void handle_close_parenthesis(Iterator& it,
  133. Iterator const& end, std::string const& wkt)
  134. {
  135. if (it != end && *it == ")")
  136. {
  137. ++it;
  138. }
  139. else
  140. {
  141. throw read_wkt_exception("Expected ')'", it, end, wkt);
  142. }
  143. }
  144. template <typename Iterator>
  145. inline void check_end(Iterator& it,
  146. Iterator const& end, std::string const& wkt)
  147. {
  148. if (it != end)
  149. {
  150. throw read_wkt_exception("Too much tokens", it, end, wkt);
  151. }
  152. }
  153. /*!
  154. \brief Internal, parses coordinate sequences, strings are formated like "(1 2,3 4,...)"
  155. \param it token-iterator, should be pre-positioned at "(", is post-positions after last ")"
  156. \param end end-token-iterator
  157. \param out Output itererator receiving coordinates
  158. */
  159. template <typename Point>
  160. struct container_inserter
  161. {
  162. // Version with output iterator
  163. template <typename OutputIterator>
  164. static inline void apply(tokenizer::iterator& it, tokenizer::iterator end,
  165. std::string const& wkt, OutputIterator out)
  166. {
  167. handle_open_parenthesis(it, end, wkt);
  168. Point point;
  169. // Parse points until closing parenthesis
  170. while (it != end && *it != ")")
  171. {
  172. parsing_assigner
  173. <
  174. Point,
  175. 0,
  176. dimension<Point>::value
  177. >::apply(it, end, point, wkt);
  178. out = point;
  179. ++out;
  180. if (it != end && *it == ",")
  181. {
  182. ++it;
  183. }
  184. }
  185. handle_close_parenthesis(it, end, wkt);
  186. }
  187. };
  188. // Geometry is a value-type or reference-type
  189. template <typename Geometry>
  190. struct container_appender
  191. {
  192. typedef typename geometry::point_type
  193. <
  194. typename boost::remove_reference<Geometry>::type
  195. >::type point_type;
  196. static inline void apply(tokenizer::iterator& it, tokenizer::iterator end,
  197. std::string const& wkt, Geometry out)
  198. {
  199. handle_open_parenthesis(it, end, wkt);
  200. point_type point;
  201. // Parse points until closing parenthesis
  202. while (it != end && *it != ")")
  203. {
  204. parsing_assigner
  205. <
  206. point_type,
  207. 0,
  208. dimension<point_type>::value
  209. >::apply(it, end, point, wkt);
  210. geometry::append(out, point);
  211. if (it != end && *it == ",")
  212. {
  213. ++it;
  214. }
  215. }
  216. handle_close_parenthesis(it, end, wkt);
  217. }
  218. };
  219. /*!
  220. \brief Internal, parses a point from a string like this "(x y)"
  221. \note used for parsing points and multi-points
  222. */
  223. template <typename P>
  224. struct point_parser
  225. {
  226. static inline void apply(tokenizer::iterator& it, tokenizer::iterator end,
  227. std::string const& wkt, P& point)
  228. {
  229. handle_open_parenthesis(it, end, wkt);
  230. parsing_assigner<P, 0, dimension<P>::value>::apply(it, end, point, wkt);
  231. handle_close_parenthesis(it, end, wkt);
  232. }
  233. };
  234. template <typename Geometry>
  235. struct linestring_parser
  236. {
  237. static inline void apply(tokenizer::iterator& it, tokenizer::iterator end,
  238. std::string const& wkt, Geometry& geometry)
  239. {
  240. container_appender<Geometry&>::apply(it, end, wkt, geometry);
  241. }
  242. };
  243. template <typename Ring>
  244. struct ring_parser
  245. {
  246. static inline void apply(tokenizer::iterator& it, tokenizer::iterator end,
  247. std::string const& wkt, Ring& ring)
  248. {
  249. // A ring should look like polygon((x y,x y,x y...))
  250. // So handle the extra opening/closing parentheses
  251. // and in between parse using the container-inserter
  252. handle_open_parenthesis(it, end, wkt);
  253. container_appender<Ring&>::apply(it, end, wkt, ring);
  254. handle_close_parenthesis(it, end, wkt);
  255. }
  256. };
  257. /*!
  258. \brief Internal, parses a polygon from a string like this "((x y,x y),(x y,x y))"
  259. \note used for parsing polygons and multi-polygons
  260. */
  261. template <typename Polygon>
  262. struct polygon_parser
  263. {
  264. typedef typename ring_return_type<Polygon>::type ring_return_type;
  265. typedef container_appender<ring_return_type> appender;
  266. static inline void apply(tokenizer::iterator& it, tokenizer::iterator end,
  267. std::string const& wkt, Polygon& poly)
  268. {
  269. handle_open_parenthesis(it, end, wkt);
  270. int n = -1;
  271. // Stop at ")"
  272. while (it != end && *it != ")")
  273. {
  274. // Parse ring
  275. if (++n == 0)
  276. {
  277. appender::apply(it, end, wkt, exterior_ring(poly));
  278. }
  279. else
  280. {
  281. typename ring_type<Polygon>::type ring;
  282. appender::apply(it, end, wkt, ring);
  283. traits::push_back
  284. <
  285. typename boost::remove_reference
  286. <
  287. typename traits::interior_mutable_type<Polygon>::type
  288. >::type
  289. >::apply(interior_rings(poly), ring);
  290. }
  291. if (it != end && *it == ",")
  292. {
  293. // Skip "," after ring is parsed
  294. ++it;
  295. }
  296. }
  297. handle_close_parenthesis(it, end, wkt);
  298. }
  299. };
  300. inline bool one_of(tokenizer::iterator const& it, std::string const& value,
  301. bool& is_present)
  302. {
  303. if (boost::iequals(*it, value))
  304. {
  305. is_present = true;
  306. return true;
  307. }
  308. return false;
  309. }
  310. inline bool one_of(tokenizer::iterator const& it, std::string const& value,
  311. bool& present1, bool& present2)
  312. {
  313. if (boost::iequals(*it, value))
  314. {
  315. present1 = true;
  316. present2 = true;
  317. return true;
  318. }
  319. return false;
  320. }
  321. inline void handle_empty_z_m(tokenizer::iterator& it, tokenizer::iterator end,
  322. bool& has_empty, bool& has_z, bool& has_m)
  323. {
  324. has_empty = false;
  325. has_z = false;
  326. has_m = false;
  327. // WKT can optionally have Z and M (measured) values as in
  328. // POINT ZM (1 1 5 60), POINT M (1 1 80), POINT Z (1 1 5)
  329. // GGL supports any of them as coordinate values, but is not aware
  330. // of any Measured value.
  331. while (it != end
  332. && (one_of(it, "M", has_m)
  333. || one_of(it, "Z", has_z)
  334. || one_of(it, "EMPTY", has_empty)
  335. || one_of(it, "MZ", has_m, has_z)
  336. || one_of(it, "ZM", has_z, has_m)
  337. )
  338. )
  339. {
  340. ++it;
  341. }
  342. }
  343. /*!
  344. \brief Internal, starts parsing
  345. \param tokens boost tokens, parsed with separator " " and keeping separator "()"
  346. \param geometry string to compare with first token
  347. */
  348. template <typename Geometry>
  349. inline bool initialize(tokenizer const& tokens,
  350. std::string const& geometry_name, std::string const& wkt,
  351. tokenizer::iterator& it)
  352. {
  353. it = tokens.begin();
  354. if (it != tokens.end() && boost::iequals(*it++, geometry_name))
  355. {
  356. bool has_empty, has_z, has_m;
  357. handle_empty_z_m(it, tokens.end(), has_empty, has_z, has_m);
  358. // Silence warning C4127: conditional expression is constant
  359. #if defined(_MSC_VER)
  360. #pragma warning(push)
  361. #pragma warning(disable : 4127)
  362. #endif
  363. if (has_z && dimension<Geometry>::type::value < 3)
  364. {
  365. throw read_wkt_exception("Z only allowed for 3 or more dimensions", wkt);
  366. }
  367. #if defined(_MSC_VER)
  368. #pragma warning(pop)
  369. #endif
  370. if (has_empty)
  371. {
  372. check_end(it, tokens.end(), wkt);
  373. return false;
  374. }
  375. // M is ignored at all.
  376. return true;
  377. }
  378. throw read_wkt_exception(std::string("Should start with '") + geometry_name + "'", wkt);
  379. }
  380. template <typename Geometry, template<typename> class Parser, typename PrefixPolicy>
  381. struct geometry_parser
  382. {
  383. static inline void apply(std::string const& wkt, Geometry& geometry)
  384. {
  385. geometry::clear(geometry);
  386. tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
  387. tokenizer::iterator it;
  388. if (initialize<Geometry>(tokens, PrefixPolicy::apply(), wkt, it))
  389. {
  390. Parser<Geometry>::apply(it, tokens.end(), wkt, geometry);
  391. check_end(it, tokens.end(), wkt);
  392. }
  393. }
  394. };
  395. /*!
  396. \brief Supports box parsing
  397. \note OGC does not define the box geometry, and WKT does not support boxes.
  398. However, to be generic GGL supports reading and writing from and to boxes.
  399. Boxes are outputted as a standard POLYGON. GGL can read boxes from
  400. a standard POLYGON, from a POLYGON with 2 points of from a BOX
  401. \tparam Box the box
  402. */
  403. template <typename Box>
  404. struct box_parser
  405. {
  406. static inline void apply(std::string const& wkt, Box& box)
  407. {
  408. bool should_close = false;
  409. tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
  410. tokenizer::iterator it = tokens.begin();
  411. tokenizer::iterator end = tokens.end();
  412. if (it != end && boost::iequals(*it, "POLYGON"))
  413. {
  414. ++it;
  415. bool has_empty, has_z, has_m;
  416. handle_empty_z_m(it, end, has_empty, has_z, has_m);
  417. if (has_empty)
  418. {
  419. assign_zero(box);
  420. return;
  421. }
  422. handle_open_parenthesis(it, end, wkt);
  423. should_close = true;
  424. }
  425. else if (it != end && boost::iequals(*it, "BOX"))
  426. {
  427. ++it;
  428. }
  429. else
  430. {
  431. throw read_wkt_exception("Should start with 'POLYGON' or 'BOX'", wkt);
  432. }
  433. typedef typename point_type<Box>::type point_type;
  434. std::vector<point_type> points;
  435. container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points));
  436. if (should_close)
  437. {
  438. handle_close_parenthesis(it, end, wkt);
  439. }
  440. check_end(it, end, wkt);
  441. int index = 0;
  442. int n = boost::size(points);
  443. if (n == 2)
  444. {
  445. index = 1;
  446. }
  447. else if (n == 4 || n == 5)
  448. {
  449. // In case of 4 or 5 points, we do not check the other ones, just
  450. // take the opposite corner which is always 2
  451. index = 2;
  452. }
  453. else
  454. {
  455. throw read_wkt_exception("Box should have 2,4 or 5 points", wkt);
  456. }
  457. geometry::detail::assign_point_to_index<min_corner>(points.front(), box);
  458. geometry::detail::assign_point_to_index<max_corner>(points[index], box);
  459. }
  460. };
  461. /*!
  462. \brief Supports segment parsing
  463. \note OGC does not define the segment, and WKT does not support segmentes.
  464. However, it is useful to implement it, also for testing purposes
  465. \tparam Segment the segment
  466. */
  467. template <typename Segment>
  468. struct segment_parser
  469. {
  470. static inline void apply(std::string const& wkt, Segment& segment)
  471. {
  472. tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
  473. tokenizer::iterator it = tokens.begin();
  474. tokenizer::iterator end = tokens.end();
  475. if (it != end &&
  476. (boost::iequals(*it, "SEGMENT")
  477. || boost::iequals(*it, "LINESTRING") ))
  478. {
  479. ++it;
  480. }
  481. else
  482. {
  483. throw read_wkt_exception("Should start with 'LINESTRING' or 'SEGMENT'", wkt);
  484. }
  485. typedef typename point_type<Segment>::type point_type;
  486. std::vector<point_type> points;
  487. container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points));
  488. check_end(it, end, wkt);
  489. if (boost::size(points) == 2)
  490. {
  491. geometry::detail::assign_point_to_index<0>(points.front(), segment);
  492. geometry::detail::assign_point_to_index<1>(points.back(), segment);
  493. }
  494. else
  495. {
  496. throw read_wkt_exception("Segment should have 2 points", wkt);
  497. }
  498. }
  499. };
  500. }} // namespace detail::wkt
  501. #endif // DOXYGEN_NO_DETAIL
  502. #ifndef DOXYGEN_NO_DISPATCH
  503. namespace dispatch
  504. {
  505. template <typename Tag, typename Geometry>
  506. struct read_wkt {};
  507. template <typename Point>
  508. struct read_wkt<point_tag, Point>
  509. : detail::wkt::geometry_parser
  510. <
  511. Point,
  512. detail::wkt::point_parser,
  513. detail::wkt::prefix_point
  514. >
  515. {};
  516. template <typename L>
  517. struct read_wkt<linestring_tag, L>
  518. : detail::wkt::geometry_parser
  519. <
  520. L,
  521. detail::wkt::linestring_parser,
  522. detail::wkt::prefix_linestring
  523. >
  524. {};
  525. template <typename Ring>
  526. struct read_wkt<ring_tag, Ring>
  527. : detail::wkt::geometry_parser
  528. <
  529. Ring,
  530. detail::wkt::ring_parser,
  531. detail::wkt::prefix_polygon
  532. >
  533. {};
  534. template <typename Geometry>
  535. struct read_wkt<polygon_tag, Geometry>
  536. : detail::wkt::geometry_parser
  537. <
  538. Geometry,
  539. detail::wkt::polygon_parser,
  540. detail::wkt::prefix_polygon
  541. >
  542. {};
  543. // Box (Non-OGC)
  544. template <typename Box>
  545. struct read_wkt<box_tag, Box>
  546. : detail::wkt::box_parser<Box>
  547. {};
  548. // Segment (Non-OGC)
  549. template <typename Segment>
  550. struct read_wkt<segment_tag, Segment>
  551. : detail::wkt::segment_parser<Segment>
  552. {};
  553. } // namespace dispatch
  554. #endif // DOXYGEN_NO_DISPATCH
  555. /*!
  556. \brief Parses OGC Well-Known Text (\ref WKT) into a geometry (any geometry)
  557. \ingroup wkt
  558. \param wkt string containing \ref WKT
  559. \param geometry output geometry
  560. \par Example:
  561. \note It is case insensitive and can have the WKT forms "point", "point m", "point z", "point zm", "point mz"
  562. \note Empty sequences can have forms as "LINESTRING ()" or "POLYGON(())"
  563. Small example showing how to use read_wkt to build a point
  564. \dontinclude doxygen_1.cpp
  565. \skip example_from_wkt_point
  566. \line {
  567. \until }
  568. \par Example:
  569. Small example showing how to use read_wkt to build a linestring
  570. \dontinclude doxygen_1.cpp
  571. \skip example_from_wkt_linestring
  572. \line {
  573. \until }
  574. \par Example:
  575. Small example showing how to use read_wkt to build a polygon
  576. \dontinclude doxygen_1.cpp
  577. \skip example_from_wkt_polygon
  578. \line {
  579. \until }
  580. */
  581. template <typename Geometry>
  582. inline void read_wkt(std::string const& wkt, Geometry& geometry)
  583. {
  584. geometry::concept::check<Geometry>();
  585. dispatch::read_wkt<typename tag<Geometry>::type, Geometry>::apply(wkt, geometry);
  586. }
  587. }} // namespace boost::geometry
  588. #endif // BOOST_GEOMETRY_IO_WKT_READ_HPP