annotate DEPENDENCIES/generic/include/boost/geometry/io/wkt/read.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
Chris@16 1 // Boost.Geometry (aka GGL, Generic Geometry Library)
Chris@16 2
Chris@16 3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
Chris@16 4 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
Chris@16 5 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
Chris@16 6
Chris@101 7 // This file was modified by Oracle on 2014.
Chris@101 8 // Modifications copyright (c) 2014 Oracle and/or its affiliates.
Chris@101 9
Chris@101 10 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
Chris@101 11
Chris@16 12 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
Chris@16 13 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
Chris@16 14
Chris@16 15 // Use, modification and distribution is subject to the Boost Software License,
Chris@16 16 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
Chris@16 17 // http://www.boost.org/LICENSE_1_0.txt)
Chris@16 18
Chris@16 19 #ifndef BOOST_GEOMETRY_IO_WKT_READ_HPP
Chris@16 20 #define BOOST_GEOMETRY_IO_WKT_READ_HPP
Chris@16 21
Chris@101 22 #include <cstddef>
Chris@16 23 #include <string>
Chris@16 24
Chris@16 25 #include <boost/lexical_cast.hpp>
Chris@16 26 #include <boost/tokenizer.hpp>
Chris@16 27
Chris@16 28 #include <boost/algorithm/string.hpp>
Chris@16 29 #include <boost/mpl/if.hpp>
Chris@16 30 #include <boost/range.hpp>
Chris@16 31
Chris@16 32 #include <boost/type_traits.hpp>
Chris@16 33
Chris@16 34 #include <boost/geometry/algorithms/assign.hpp>
Chris@16 35 #include <boost/geometry/algorithms/append.hpp>
Chris@16 36 #include <boost/geometry/algorithms/clear.hpp>
Chris@101 37 #include <boost/geometry/algorithms/detail/equals/point_point.hpp>
Chris@16 38
Chris@16 39 #include <boost/geometry/core/access.hpp>
Chris@16 40 #include <boost/geometry/core/coordinate_dimension.hpp>
Chris@16 41 #include <boost/geometry/core/exception.hpp>
Chris@16 42 #include <boost/geometry/core/exterior_ring.hpp>
Chris@16 43 #include <boost/geometry/core/geometry_id.hpp>
Chris@16 44 #include <boost/geometry/core/interior_rings.hpp>
Chris@16 45 #include <boost/geometry/core/mutable_range.hpp>
Chris@101 46 #include <boost/geometry/core/point_type.hpp>
Chris@101 47 #include <boost/geometry/core/tag_cast.hpp>
Chris@101 48 #include <boost/geometry/core/tags.hpp>
Chris@16 49
Chris@16 50 #include <boost/geometry/geometries/concepts/check.hpp>
Chris@16 51
Chris@16 52 #include <boost/geometry/util/coordinate_cast.hpp>
Chris@16 53
Chris@16 54 #include <boost/geometry/io/wkt/detail/prefix.hpp>
Chris@16 55
Chris@16 56 namespace boost { namespace geometry
Chris@16 57 {
Chris@16 58
Chris@16 59 /*!
Chris@16 60 \brief Exception showing things wrong with WKT parsing
Chris@16 61 \ingroup wkt
Chris@16 62 */
Chris@16 63 struct read_wkt_exception : public geometry::exception
Chris@16 64 {
Chris@16 65 template <typename Iterator>
Chris@16 66 read_wkt_exception(std::string const& msg,
Chris@16 67 Iterator const& it, Iterator const& end, std::string const& wkt)
Chris@16 68 : message(msg)
Chris@16 69 , wkt(wkt)
Chris@16 70 {
Chris@16 71 if (it != end)
Chris@16 72 {
Chris@16 73 source = " at '";
Chris@16 74 source += it->c_str();
Chris@16 75 source += "'";
Chris@16 76 }
Chris@16 77 complete = message + source + " in '" + wkt.substr(0, 100) + "'";
Chris@16 78 }
Chris@16 79
Chris@16 80 read_wkt_exception(std::string const& msg, std::string const& wkt)
Chris@16 81 : message(msg)
Chris@16 82 , wkt(wkt)
Chris@16 83 {
Chris@16 84 complete = message + "' in (" + wkt.substr(0, 100) + ")";
Chris@16 85 }
Chris@16 86
Chris@16 87 virtual ~read_wkt_exception() throw() {}
Chris@16 88
Chris@16 89 virtual const char* what() const throw()
Chris@16 90 {
Chris@16 91 return complete.c_str();
Chris@16 92 }
Chris@16 93 private :
Chris@16 94 std::string source;
Chris@16 95 std::string message;
Chris@16 96 std::string wkt;
Chris@16 97 std::string complete;
Chris@16 98 };
Chris@16 99
Chris@16 100
Chris@16 101 #ifndef DOXYGEN_NO_DETAIL
Chris@16 102 // (wkt: Well Known Text, defined by OGC for all geometries and implemented by e.g. databases (MySQL, PostGIS))
Chris@16 103 namespace detail { namespace wkt
Chris@16 104 {
Chris@16 105
Chris@16 106 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
Chris@16 107
Chris@101 108 template <typename Point,
Chris@101 109 std::size_t Dimension = 0,
Chris@101 110 std::size_t DimensionCount = geometry::dimension<Point>::value>
Chris@16 111 struct parsing_assigner
Chris@16 112 {
Chris@16 113 static inline void apply(tokenizer::iterator& it, tokenizer::iterator end,
Chris@16 114 Point& point, std::string const& wkt)
Chris@16 115 {
Chris@16 116 typedef typename coordinate_type<Point>::type coordinate_type;
Chris@16 117
Chris@16 118 // Stop at end of tokens, or at "," ot ")"
Chris@16 119 bool finished = (it == end || *it == "," || *it == ")");
Chris@16 120
Chris@16 121 try
Chris@16 122 {
Chris@16 123 // Initialize missing coordinates to default constructor (zero)
Chris@16 124 // OR
Chris@16 125 // Use lexical_cast for conversion to double/int
Chris@16 126 // Note that it is much slower than atof. However, it is more standard
Chris@16 127 // and in parsing the change in performance falls probably away against
Chris@16 128 // the tokenizing
Chris@16 129 set<Dimension>(point, finished
Chris@16 130 ? coordinate_type()
Chris@16 131 : coordinate_cast<coordinate_type>::apply(*it));
Chris@16 132 }
Chris@16 133 catch(boost::bad_lexical_cast const& blc)
Chris@16 134 {
Chris@16 135 throw read_wkt_exception(blc.what(), it, end, wkt);
Chris@16 136 }
Chris@16 137 catch(std::exception const& e)
Chris@16 138 {
Chris@16 139 throw read_wkt_exception(e.what(), it, end, wkt);
Chris@16 140 }
Chris@16 141 catch(...)
Chris@16 142 {
Chris@16 143 throw read_wkt_exception("", it, end, wkt);
Chris@16 144 }
Chris@16 145
Chris@16 146 parsing_assigner<Point, Dimension + 1, DimensionCount>::apply(
Chris@16 147 (finished ? it : ++it), end, point, wkt);
Chris@16 148 }
Chris@16 149 };
Chris@16 150
Chris@16 151 template <typename Point, std::size_t DimensionCount>
Chris@16 152 struct parsing_assigner<Point, DimensionCount, DimensionCount>
Chris@16 153 {
Chris@16 154 static inline void apply(tokenizer::iterator&, tokenizer::iterator, Point&,
Chris@16 155 std::string const&)
Chris@16 156 {
Chris@16 157 }
Chris@16 158 };
Chris@16 159
Chris@16 160
Chris@16 161
Chris@16 162 template <typename Iterator>
Chris@16 163 inline void handle_open_parenthesis(Iterator& it,
Chris@16 164 Iterator const& end, std::string const& wkt)
Chris@16 165 {
Chris@16 166 if (it == end || *it != "(")
Chris@16 167 {
Chris@16 168 throw read_wkt_exception("Expected '('", it, end, wkt);
Chris@16 169 }
Chris@16 170 ++it;
Chris@16 171 }
Chris@16 172
Chris@16 173
Chris@16 174 template <typename Iterator>
Chris@16 175 inline void handle_close_parenthesis(Iterator& it,
Chris@16 176 Iterator const& end, std::string const& wkt)
Chris@16 177 {
Chris@16 178 if (it != end && *it == ")")
Chris@16 179 {
Chris@16 180 ++it;
Chris@16 181 }
Chris@16 182 else
Chris@16 183 {
Chris@16 184 throw read_wkt_exception("Expected ')'", it, end, wkt);
Chris@16 185 }
Chris@16 186 }
Chris@16 187
Chris@16 188 template <typename Iterator>
Chris@16 189 inline void check_end(Iterator& it,
Chris@16 190 Iterator const& end, std::string const& wkt)
Chris@16 191 {
Chris@16 192 if (it != end)
Chris@16 193 {
Chris@16 194 throw read_wkt_exception("Too much tokens", it, end, wkt);
Chris@16 195 }
Chris@16 196 }
Chris@16 197
Chris@16 198 /*!
Chris@16 199 \brief Internal, parses coordinate sequences, strings are formated like "(1 2,3 4,...)"
Chris@16 200 \param it token-iterator, should be pre-positioned at "(", is post-positions after last ")"
Chris@16 201 \param end end-token-iterator
Chris@16 202 \param out Output itererator receiving coordinates
Chris@16 203 */
Chris@16 204 template <typename Point>
Chris@16 205 struct container_inserter
Chris@16 206 {
Chris@16 207 // Version with output iterator
Chris@16 208 template <typename OutputIterator>
Chris@16 209 static inline void apply(tokenizer::iterator& it, tokenizer::iterator end,
Chris@16 210 std::string const& wkt, OutputIterator out)
Chris@16 211 {
Chris@16 212 handle_open_parenthesis(it, end, wkt);
Chris@16 213
Chris@16 214 Point point;
Chris@16 215
Chris@16 216 // Parse points until closing parenthesis
Chris@16 217
Chris@16 218 while (it != end && *it != ")")
Chris@16 219 {
Chris@101 220 parsing_assigner<Point>::apply(it, end, point, wkt);
Chris@16 221 out = point;
Chris@16 222 ++out;
Chris@16 223 if (it != end && *it == ",")
Chris@16 224 {
Chris@16 225 ++it;
Chris@16 226 }
Chris@16 227 }
Chris@16 228
Chris@16 229 handle_close_parenthesis(it, end, wkt);
Chris@16 230 }
Chris@16 231 };
Chris@16 232
Chris@16 233
Chris@101 234 template <typename Geometry,
Chris@101 235 closure_selector Closure = closure<Geometry>::value>
Chris@101 236 struct stateful_range_appender
Chris@101 237 {
Chris@101 238 typedef typename geometry::point_type<Geometry>::type point_type;
Chris@101 239
Chris@101 240 // NOTE: Geometry is a reference
Chris@101 241 inline void append(Geometry geom, point_type const& point, bool)
Chris@101 242 {
Chris@101 243 geometry::append(geom, point);
Chris@101 244 }
Chris@101 245 };
Chris@101 246
Chris@101 247 template <typename Geometry>
Chris@101 248 struct stateful_range_appender<Geometry, open>
Chris@101 249 {
Chris@101 250 typedef typename geometry::point_type<Geometry>::type point_type;
Chris@101 251 typedef typename boost::range_size
Chris@101 252 <
Chris@101 253 typename util::bare_type<Geometry>::type
Chris@101 254 >::type size_type;
Chris@101 255
Chris@101 256 BOOST_STATIC_ASSERT(( boost::is_same
Chris@101 257 <
Chris@101 258 typename tag<Geometry>::type,
Chris@101 259 ring_tag
Chris@101 260 >::value ));
Chris@101 261
Chris@101 262 inline stateful_range_appender()
Chris@101 263 : pt_index(0)
Chris@101 264 {}
Chris@101 265
Chris@101 266 // NOTE: Geometry is a reference
Chris@101 267 inline void append(Geometry geom, point_type const& point, bool is_next_expected)
Chris@101 268 {
Chris@101 269 bool should_append = true;
Chris@101 270
Chris@101 271 if (pt_index == 0)
Chris@101 272 {
Chris@101 273 first_point = point;
Chris@101 274 //should_append = true;
Chris@101 275 }
Chris@101 276 else
Chris@101 277 {
Chris@101 278 // NOTE: if there is not enough Points, they're always appended
Chris@101 279 should_append
Chris@101 280 = is_next_expected
Chris@101 281 || pt_index < core_detail::closure::minimum_ring_size<open>::value
Chris@101 282 || !detail::equals::equals_point_point(point, first_point);
Chris@101 283 }
Chris@101 284 ++pt_index;
Chris@101 285
Chris@101 286 if (should_append)
Chris@101 287 {
Chris@101 288 geometry::append(geom, point);
Chris@101 289 }
Chris@101 290 }
Chris@101 291
Chris@101 292 private:
Chris@101 293 size_type pt_index;
Chris@101 294 point_type first_point;
Chris@101 295 };
Chris@101 296
Chris@16 297 // Geometry is a value-type or reference-type
Chris@16 298 template <typename Geometry>
Chris@16 299 struct container_appender
Chris@16 300 {
Chris@101 301 typedef typename geometry::point_type<Geometry>::type point_type;
Chris@16 302
Chris@16 303 static inline void apply(tokenizer::iterator& it, tokenizer::iterator end,
Chris@101 304 std::string const& wkt, Geometry out)
Chris@16 305 {
Chris@16 306 handle_open_parenthesis(it, end, wkt);
Chris@16 307
Chris@101 308 stateful_range_appender<Geometry> appender;
Chris@16 309
Chris@16 310 // Parse points until closing parenthesis
Chris@16 311 while (it != end && *it != ")")
Chris@16 312 {
Chris@101 313 point_type point;
Chris@16 314
Chris@101 315 parsing_assigner<point_type>::apply(it, end, point, wkt);
Chris@101 316
Chris@101 317 bool const is_next_expected = it != end && *it == ",";
Chris@101 318
Chris@101 319 appender.append(out, point, is_next_expected);
Chris@101 320
Chris@101 321 if (is_next_expected)
Chris@16 322 {
Chris@16 323 ++it;
Chris@16 324 }
Chris@16 325 }
Chris@16 326
Chris@16 327 handle_close_parenthesis(it, end, wkt);
Chris@16 328 }
Chris@16 329 };
Chris@16 330
Chris@16 331 /*!
Chris@16 332 \brief Internal, parses a point from a string like this "(x y)"
Chris@16 333 \note used for parsing points and multi-points
Chris@16 334 */
Chris@16 335 template <typename P>
Chris@16 336 struct point_parser
Chris@16 337 {
Chris@16 338 static inline void apply(tokenizer::iterator& it, tokenizer::iterator end,
Chris@16 339 std::string const& wkt, P& point)
Chris@16 340 {
Chris@16 341 handle_open_parenthesis(it, end, wkt);
Chris@101 342 parsing_assigner<P>::apply(it, end, point, wkt);
Chris@16 343 handle_close_parenthesis(it, end, wkt);
Chris@16 344 }
Chris@16 345 };
Chris@16 346
Chris@16 347
Chris@16 348 template <typename Geometry>
Chris@16 349 struct linestring_parser
Chris@16 350 {
Chris@16 351 static inline void apply(tokenizer::iterator& it, tokenizer::iterator end,
Chris@16 352 std::string const& wkt, Geometry& geometry)
Chris@16 353 {
Chris@16 354 container_appender<Geometry&>::apply(it, end, wkt, geometry);
Chris@16 355 }
Chris@16 356 };
Chris@16 357
Chris@16 358
Chris@16 359 template <typename Ring>
Chris@16 360 struct ring_parser
Chris@16 361 {
Chris@16 362 static inline void apply(tokenizer::iterator& it, tokenizer::iterator end,
Chris@16 363 std::string const& wkt, Ring& ring)
Chris@16 364 {
Chris@16 365 // A ring should look like polygon((x y,x y,x y...))
Chris@16 366 // So handle the extra opening/closing parentheses
Chris@16 367 // and in between parse using the container-inserter
Chris@16 368 handle_open_parenthesis(it, end, wkt);
Chris@16 369 container_appender<Ring&>::apply(it, end, wkt, ring);
Chris@16 370 handle_close_parenthesis(it, end, wkt);
Chris@16 371 }
Chris@16 372 };
Chris@16 373
Chris@16 374
Chris@16 375 /*!
Chris@16 376 \brief Internal, parses a polygon from a string like this "((x y,x y),(x y,x y))"
Chris@16 377 \note used for parsing polygons and multi-polygons
Chris@16 378 */
Chris@16 379 template <typename Polygon>
Chris@16 380 struct polygon_parser
Chris@16 381 {
Chris@16 382 typedef typename ring_return_type<Polygon>::type ring_return_type;
Chris@16 383 typedef container_appender<ring_return_type> appender;
Chris@16 384
Chris@16 385 static inline void apply(tokenizer::iterator& it, tokenizer::iterator end,
Chris@16 386 std::string const& wkt, Polygon& poly)
Chris@16 387 {
Chris@16 388
Chris@16 389 handle_open_parenthesis(it, end, wkt);
Chris@16 390
Chris@16 391 int n = -1;
Chris@16 392
Chris@16 393 // Stop at ")"
Chris@16 394 while (it != end && *it != ")")
Chris@16 395 {
Chris@16 396 // Parse ring
Chris@16 397 if (++n == 0)
Chris@16 398 {
Chris@16 399 appender::apply(it, end, wkt, exterior_ring(poly));
Chris@16 400 }
Chris@16 401 else
Chris@16 402 {
Chris@16 403 typename ring_type<Polygon>::type ring;
Chris@16 404 appender::apply(it, end, wkt, ring);
Chris@16 405 traits::push_back
Chris@16 406 <
Chris@16 407 typename boost::remove_reference
Chris@16 408 <
Chris@16 409 typename traits::interior_mutable_type<Polygon>::type
Chris@16 410 >::type
Chris@16 411 >::apply(interior_rings(poly), ring);
Chris@16 412 }
Chris@16 413
Chris@16 414 if (it != end && *it == ",")
Chris@16 415 {
Chris@16 416 // Skip "," after ring is parsed
Chris@16 417 ++it;
Chris@16 418 }
Chris@16 419 }
Chris@16 420
Chris@16 421 handle_close_parenthesis(it, end, wkt);
Chris@16 422 }
Chris@16 423 };
Chris@16 424
Chris@101 425
Chris@16 426 inline bool one_of(tokenizer::iterator const& it, std::string const& value,
Chris@16 427 bool& is_present)
Chris@16 428 {
Chris@16 429 if (boost::iequals(*it, value))
Chris@16 430 {
Chris@16 431 is_present = true;
Chris@16 432 return true;
Chris@16 433 }
Chris@16 434 return false;
Chris@16 435 }
Chris@16 436
Chris@16 437 inline bool one_of(tokenizer::iterator const& it, std::string const& value,
Chris@16 438 bool& present1, bool& present2)
Chris@16 439 {
Chris@16 440 if (boost::iequals(*it, value))
Chris@16 441 {
Chris@16 442 present1 = true;
Chris@16 443 present2 = true;
Chris@16 444 return true;
Chris@16 445 }
Chris@16 446 return false;
Chris@16 447 }
Chris@16 448
Chris@16 449
Chris@16 450 inline void handle_empty_z_m(tokenizer::iterator& it, tokenizer::iterator end,
Chris@16 451 bool& has_empty, bool& has_z, bool& has_m)
Chris@16 452 {
Chris@16 453 has_empty = false;
Chris@16 454 has_z = false;
Chris@16 455 has_m = false;
Chris@16 456
Chris@16 457 // WKT can optionally have Z and M (measured) values as in
Chris@16 458 // POINT ZM (1 1 5 60), POINT M (1 1 80), POINT Z (1 1 5)
Chris@16 459 // GGL supports any of them as coordinate values, but is not aware
Chris@16 460 // of any Measured value.
Chris@16 461 while (it != end
Chris@16 462 && (one_of(it, "M", has_m)
Chris@16 463 || one_of(it, "Z", has_z)
Chris@16 464 || one_of(it, "EMPTY", has_empty)
Chris@16 465 || one_of(it, "MZ", has_m, has_z)
Chris@16 466 || one_of(it, "ZM", has_z, has_m)
Chris@16 467 )
Chris@16 468 )
Chris@16 469 {
Chris@16 470 ++it;
Chris@16 471 }
Chris@16 472 }
Chris@16 473
Chris@16 474 /*!
Chris@16 475 \brief Internal, starts parsing
Chris@16 476 \param tokens boost tokens, parsed with separator " " and keeping separator "()"
Chris@16 477 \param geometry string to compare with first token
Chris@16 478 */
Chris@16 479 template <typename Geometry>
Chris@16 480 inline bool initialize(tokenizer const& tokens,
Chris@16 481 std::string const& geometry_name, std::string const& wkt,
Chris@16 482 tokenizer::iterator& it)
Chris@16 483 {
Chris@16 484 it = tokens.begin();
Chris@16 485 if (it != tokens.end() && boost::iequals(*it++, geometry_name))
Chris@16 486 {
Chris@16 487 bool has_empty, has_z, has_m;
Chris@16 488
Chris@16 489 handle_empty_z_m(it, tokens.end(), has_empty, has_z, has_m);
Chris@16 490
Chris@16 491 // Silence warning C4127: conditional expression is constant
Chris@16 492 #if defined(_MSC_VER)
Chris@16 493 #pragma warning(push)
Chris@16 494 #pragma warning(disable : 4127)
Chris@16 495 #endif
Chris@16 496
Chris@16 497 if (has_z && dimension<Geometry>::type::value < 3)
Chris@16 498 {
Chris@16 499 throw read_wkt_exception("Z only allowed for 3 or more dimensions", wkt);
Chris@16 500 }
Chris@16 501
Chris@16 502 #if defined(_MSC_VER)
Chris@16 503 #pragma warning(pop)
Chris@16 504 #endif
Chris@16 505
Chris@16 506 if (has_empty)
Chris@16 507 {
Chris@16 508 check_end(it, tokens.end(), wkt);
Chris@16 509 return false;
Chris@16 510 }
Chris@16 511 // M is ignored at all.
Chris@16 512
Chris@16 513 return true;
Chris@16 514 }
Chris@16 515 throw read_wkt_exception(std::string("Should start with '") + geometry_name + "'", wkt);
Chris@16 516 }
Chris@16 517
Chris@16 518
Chris@16 519 template <typename Geometry, template<typename> class Parser, typename PrefixPolicy>
Chris@16 520 struct geometry_parser
Chris@16 521 {
Chris@16 522 static inline void apply(std::string const& wkt, Geometry& geometry)
Chris@16 523 {
Chris@16 524 geometry::clear(geometry);
Chris@16 525
Chris@16 526 tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
Chris@16 527 tokenizer::iterator it;
Chris@16 528 if (initialize<Geometry>(tokens, PrefixPolicy::apply(), wkt, it))
Chris@16 529 {
Chris@16 530 Parser<Geometry>::apply(it, tokens.end(), wkt, geometry);
Chris@16 531 check_end(it, tokens.end(), wkt);
Chris@16 532 }
Chris@16 533 }
Chris@16 534 };
Chris@16 535
Chris@16 536
Chris@101 537 template <typename MultiGeometry, template<typename> class Parser, typename PrefixPolicy>
Chris@101 538 struct multi_parser
Chris@101 539 {
Chris@101 540 static inline void apply(std::string const& wkt, MultiGeometry& geometry)
Chris@101 541 {
Chris@101 542 traits::clear<MultiGeometry>::apply(geometry);
Chris@16 543
Chris@101 544 tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
Chris@101 545 tokenizer::iterator it;
Chris@101 546 if (initialize<MultiGeometry>(tokens, PrefixPolicy::apply(), wkt, it))
Chris@101 547 {
Chris@101 548 handle_open_parenthesis(it, tokens.end(), wkt);
Chris@101 549
Chris@101 550 // Parse sub-geometries
Chris@101 551 while(it != tokens.end() && *it != ")")
Chris@101 552 {
Chris@101 553 traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1);
Chris@101 554 Parser
Chris@101 555 <
Chris@101 556 typename boost::range_value<MultiGeometry>::type
Chris@101 557 >::apply(it, tokens.end(), wkt, *(boost::end(geometry) - 1));
Chris@101 558 if (it != tokens.end() && *it == ",")
Chris@101 559 {
Chris@101 560 // Skip "," after multi-element is parsed
Chris@101 561 ++it;
Chris@101 562 }
Chris@101 563 }
Chris@101 564
Chris@101 565 handle_close_parenthesis(it, tokens.end(), wkt);
Chris@101 566 }
Chris@101 567
Chris@101 568 check_end(it, tokens.end(), wkt);
Chris@101 569 }
Chris@101 570 };
Chris@101 571
Chris@101 572 template <typename P>
Chris@101 573 struct noparenthesis_point_parser
Chris@101 574 {
Chris@101 575 static inline void apply(tokenizer::iterator& it, tokenizer::iterator end,
Chris@101 576 std::string const& wkt, P& point)
Chris@101 577 {
Chris@101 578 parsing_assigner<P>::apply(it, end, point, wkt);
Chris@101 579 }
Chris@101 580 };
Chris@101 581
Chris@101 582 template <typename MultiGeometry, typename PrefixPolicy>
Chris@101 583 struct multi_point_parser
Chris@101 584 {
Chris@101 585 static inline void apply(std::string const& wkt, MultiGeometry& geometry)
Chris@101 586 {
Chris@101 587 traits::clear<MultiGeometry>::apply(geometry);
Chris@101 588
Chris@101 589 tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
Chris@101 590 tokenizer::iterator it;
Chris@101 591
Chris@101 592 if (initialize<MultiGeometry>(tokens, PrefixPolicy::apply(), wkt, it))
Chris@101 593 {
Chris@101 594 handle_open_parenthesis(it, tokens.end(), wkt);
Chris@101 595
Chris@101 596 // If first point definition starts with "(" then parse points as (x y)
Chris@101 597 // otherwise as "x y"
Chris@101 598 bool using_brackets = (it != tokens.end() && *it == "(");
Chris@101 599
Chris@101 600 while(it != tokens.end() && *it != ")")
Chris@101 601 {
Chris@101 602 traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1);
Chris@101 603
Chris@101 604 if (using_brackets)
Chris@101 605 {
Chris@101 606 point_parser
Chris@101 607 <
Chris@101 608 typename boost::range_value<MultiGeometry>::type
Chris@101 609 >::apply(it, tokens.end(), wkt, *(boost::end(geometry) - 1));
Chris@101 610 }
Chris@101 611 else
Chris@101 612 {
Chris@101 613 noparenthesis_point_parser
Chris@101 614 <
Chris@101 615 typename boost::range_value<MultiGeometry>::type
Chris@101 616 >::apply(it, tokens.end(), wkt, *(boost::end(geometry) - 1));
Chris@101 617 }
Chris@101 618
Chris@101 619 if (it != tokens.end() && *it == ",")
Chris@101 620 {
Chris@101 621 // Skip "," after point is parsed
Chris@101 622 ++it;
Chris@101 623 }
Chris@101 624 }
Chris@101 625
Chris@101 626 handle_close_parenthesis(it, tokens.end(), wkt);
Chris@101 627 }
Chris@101 628
Chris@101 629 check_end(it, tokens.end(), wkt);
Chris@101 630 }
Chris@101 631 };
Chris@16 632
Chris@16 633
Chris@16 634 /*!
Chris@16 635 \brief Supports box parsing
Chris@16 636 \note OGC does not define the box geometry, and WKT does not support boxes.
Chris@16 637 However, to be generic GGL supports reading and writing from and to boxes.
Chris@16 638 Boxes are outputted as a standard POLYGON. GGL can read boxes from
Chris@16 639 a standard POLYGON, from a POLYGON with 2 points of from a BOX
Chris@16 640 \tparam Box the box
Chris@16 641 */
Chris@16 642 template <typename Box>
Chris@16 643 struct box_parser
Chris@16 644 {
Chris@16 645 static inline void apply(std::string const& wkt, Box& box)
Chris@16 646 {
Chris@16 647 bool should_close = false;
Chris@16 648 tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
Chris@16 649 tokenizer::iterator it = tokens.begin();
Chris@16 650 tokenizer::iterator end = tokens.end();
Chris@16 651 if (it != end && boost::iequals(*it, "POLYGON"))
Chris@16 652 {
Chris@16 653 ++it;
Chris@16 654 bool has_empty, has_z, has_m;
Chris@16 655 handle_empty_z_m(it, end, has_empty, has_z, has_m);
Chris@16 656 if (has_empty)
Chris@16 657 {
Chris@16 658 assign_zero(box);
Chris@16 659 return;
Chris@16 660 }
Chris@16 661 handle_open_parenthesis(it, end, wkt);
Chris@16 662 should_close = true;
Chris@16 663 }
Chris@16 664 else if (it != end && boost::iequals(*it, "BOX"))
Chris@16 665 {
Chris@16 666 ++it;
Chris@16 667 }
Chris@16 668 else
Chris@16 669 {
Chris@16 670 throw read_wkt_exception("Should start with 'POLYGON' or 'BOX'", wkt);
Chris@16 671 }
Chris@16 672
Chris@16 673 typedef typename point_type<Box>::type point_type;
Chris@16 674 std::vector<point_type> points;
Chris@16 675 container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points));
Chris@16 676
Chris@16 677 if (should_close)
Chris@16 678 {
Chris@16 679 handle_close_parenthesis(it, end, wkt);
Chris@16 680 }
Chris@16 681 check_end(it, end, wkt);
Chris@16 682
Chris@101 683 unsigned int index = 0;
Chris@101 684 std::size_t n = boost::size(points);
Chris@16 685 if (n == 2)
Chris@16 686 {
Chris@16 687 index = 1;
Chris@16 688 }
Chris@16 689 else if (n == 4 || n == 5)
Chris@16 690 {
Chris@16 691 // In case of 4 or 5 points, we do not check the other ones, just
Chris@16 692 // take the opposite corner which is always 2
Chris@16 693 index = 2;
Chris@16 694 }
Chris@16 695 else
Chris@16 696 {
Chris@16 697 throw read_wkt_exception("Box should have 2,4 or 5 points", wkt);
Chris@16 698 }
Chris@16 699
Chris@16 700 geometry::detail::assign_point_to_index<min_corner>(points.front(), box);
Chris@16 701 geometry::detail::assign_point_to_index<max_corner>(points[index], box);
Chris@16 702 }
Chris@16 703 };
Chris@16 704
Chris@16 705
Chris@16 706 /*!
Chris@16 707 \brief Supports segment parsing
Chris@16 708 \note OGC does not define the segment, and WKT does not support segmentes.
Chris@16 709 However, it is useful to implement it, also for testing purposes
Chris@16 710 \tparam Segment the segment
Chris@16 711 */
Chris@16 712 template <typename Segment>
Chris@16 713 struct segment_parser
Chris@16 714 {
Chris@16 715 static inline void apply(std::string const& wkt, Segment& segment)
Chris@16 716 {
Chris@16 717 tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
Chris@16 718 tokenizer::iterator it = tokens.begin();
Chris@16 719 tokenizer::iterator end = tokens.end();
Chris@16 720 if (it != end &&
Chris@16 721 (boost::iequals(*it, "SEGMENT")
Chris@16 722 || boost::iequals(*it, "LINESTRING") ))
Chris@16 723 {
Chris@16 724 ++it;
Chris@16 725 }
Chris@16 726 else
Chris@16 727 {
Chris@16 728 throw read_wkt_exception("Should start with 'LINESTRING' or 'SEGMENT'", wkt);
Chris@16 729 }
Chris@16 730
Chris@16 731 typedef typename point_type<Segment>::type point_type;
Chris@16 732 std::vector<point_type> points;
Chris@16 733 container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points));
Chris@16 734
Chris@16 735 check_end(it, end, wkt);
Chris@16 736
Chris@16 737 if (boost::size(points) == 2)
Chris@16 738 {
Chris@16 739 geometry::detail::assign_point_to_index<0>(points.front(), segment);
Chris@16 740 geometry::detail::assign_point_to_index<1>(points.back(), segment);
Chris@16 741 }
Chris@16 742 else
Chris@16 743 {
Chris@16 744 throw read_wkt_exception("Segment should have 2 points", wkt);
Chris@16 745 }
Chris@16 746
Chris@16 747 }
Chris@16 748 };
Chris@16 749
Chris@16 750
Chris@16 751 }} // namespace detail::wkt
Chris@16 752 #endif // DOXYGEN_NO_DETAIL
Chris@16 753
Chris@16 754 #ifndef DOXYGEN_NO_DISPATCH
Chris@16 755 namespace dispatch
Chris@16 756 {
Chris@16 757
Chris@16 758 template <typename Tag, typename Geometry>
Chris@16 759 struct read_wkt {};
Chris@16 760
Chris@16 761
Chris@16 762 template <typename Point>
Chris@16 763 struct read_wkt<point_tag, Point>
Chris@16 764 : detail::wkt::geometry_parser
Chris@16 765 <
Chris@16 766 Point,
Chris@16 767 detail::wkt::point_parser,
Chris@16 768 detail::wkt::prefix_point
Chris@16 769 >
Chris@16 770 {};
Chris@16 771
Chris@16 772
Chris@16 773 template <typename L>
Chris@16 774 struct read_wkt<linestring_tag, L>
Chris@16 775 : detail::wkt::geometry_parser
Chris@16 776 <
Chris@16 777 L,
Chris@16 778 detail::wkt::linestring_parser,
Chris@16 779 detail::wkt::prefix_linestring
Chris@16 780 >
Chris@16 781 {};
Chris@16 782
Chris@16 783 template <typename Ring>
Chris@16 784 struct read_wkt<ring_tag, Ring>
Chris@16 785 : detail::wkt::geometry_parser
Chris@16 786 <
Chris@16 787 Ring,
Chris@16 788 detail::wkt::ring_parser,
Chris@16 789 detail::wkt::prefix_polygon
Chris@16 790 >
Chris@16 791 {};
Chris@16 792
Chris@16 793 template <typename Geometry>
Chris@16 794 struct read_wkt<polygon_tag, Geometry>
Chris@16 795 : detail::wkt::geometry_parser
Chris@16 796 <
Chris@16 797 Geometry,
Chris@16 798 detail::wkt::polygon_parser,
Chris@16 799 detail::wkt::prefix_polygon
Chris@16 800 >
Chris@16 801 {};
Chris@16 802
Chris@16 803
Chris@101 804 template <typename MultiGeometry>
Chris@101 805 struct read_wkt<multi_point_tag, MultiGeometry>
Chris@101 806 : detail::wkt::multi_point_parser
Chris@101 807 <
Chris@101 808 MultiGeometry,
Chris@101 809 detail::wkt::prefix_multipoint
Chris@101 810 >
Chris@101 811 {};
Chris@101 812
Chris@101 813 template <typename MultiGeometry>
Chris@101 814 struct read_wkt<multi_linestring_tag, MultiGeometry>
Chris@101 815 : detail::wkt::multi_parser
Chris@101 816 <
Chris@101 817 MultiGeometry,
Chris@101 818 detail::wkt::linestring_parser,
Chris@101 819 detail::wkt::prefix_multilinestring
Chris@101 820 >
Chris@101 821 {};
Chris@101 822
Chris@101 823 template <typename MultiGeometry>
Chris@101 824 struct read_wkt<multi_polygon_tag, MultiGeometry>
Chris@101 825 : detail::wkt::multi_parser
Chris@101 826 <
Chris@101 827 MultiGeometry,
Chris@101 828 detail::wkt::polygon_parser,
Chris@101 829 detail::wkt::prefix_multipolygon
Chris@101 830 >
Chris@101 831 {};
Chris@101 832
Chris@101 833
Chris@16 834 // Box (Non-OGC)
Chris@16 835 template <typename Box>
Chris@16 836 struct read_wkt<box_tag, Box>
Chris@16 837 : detail::wkt::box_parser<Box>
Chris@16 838 {};
Chris@16 839
Chris@16 840 // Segment (Non-OGC)
Chris@16 841 template <typename Segment>
Chris@16 842 struct read_wkt<segment_tag, Segment>
Chris@16 843 : detail::wkt::segment_parser<Segment>
Chris@16 844 {};
Chris@16 845
Chris@16 846
Chris@16 847 } // namespace dispatch
Chris@16 848 #endif // DOXYGEN_NO_DISPATCH
Chris@16 849
Chris@16 850 /*!
Chris@16 851 \brief Parses OGC Well-Known Text (\ref WKT) into a geometry (any geometry)
Chris@16 852 \ingroup wkt
Chris@101 853 \tparam Geometry \tparam_geometry
Chris@16 854 \param wkt string containing \ref WKT
Chris@101 855 \param geometry \param_geometry output geometry
Chris@101 856 \ingroup wkt
Chris@101 857 \qbk{[include reference/io/read_wkt.qbk]}
Chris@16 858 */
Chris@16 859 template <typename Geometry>
Chris@16 860 inline void read_wkt(std::string const& wkt, Geometry& geometry)
Chris@16 861 {
Chris@16 862 geometry::concept::check<Geometry>();
Chris@16 863 dispatch::read_wkt<typename tag<Geometry>::type, Geometry>::apply(wkt, geometry);
Chris@16 864 }
Chris@16 865
Chris@16 866 }} // namespace boost::geometry
Chris@16 867
Chris@16 868 #endif // BOOST_GEOMETRY_IO_WKT_READ_HPP