Chris@16: // Boost.Geometry (aka GGL, Generic Geometry Library) Chris@16: Chris@16: // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. Chris@16: // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. Chris@16: // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. Chris@16: Chris@101: // This file was modified by Oracle on 2014. Chris@101: // Modifications copyright (c) 2014 Oracle and/or its affiliates. Chris@101: Chris@101: // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle Chris@101: Chris@16: // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library Chris@16: // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. Chris@16: Chris@16: // Use, modification and distribution is subject to the Boost Software License, Chris@16: // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #ifndef BOOST_GEOMETRY_IO_WKT_READ_HPP Chris@16: #define BOOST_GEOMETRY_IO_WKT_READ_HPP Chris@16: Chris@101: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@101: #include Chris@101: #include Chris@16: Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost { namespace geometry Chris@16: { Chris@16: Chris@16: /*! Chris@16: \brief Exception showing things wrong with WKT parsing Chris@16: \ingroup wkt Chris@16: */ Chris@16: struct read_wkt_exception : public geometry::exception Chris@16: { Chris@16: template Chris@16: read_wkt_exception(std::string const& msg, Chris@16: Iterator const& it, Iterator const& end, std::string const& wkt) Chris@16: : message(msg) Chris@16: , wkt(wkt) Chris@16: { Chris@16: if (it != end) Chris@16: { Chris@16: source = " at '"; Chris@16: source += it->c_str(); Chris@16: source += "'"; Chris@16: } Chris@16: complete = message + source + " in '" + wkt.substr(0, 100) + "'"; Chris@16: } Chris@16: Chris@16: read_wkt_exception(std::string const& msg, std::string const& wkt) Chris@16: : message(msg) Chris@16: , wkt(wkt) Chris@16: { Chris@16: complete = message + "' in (" + wkt.substr(0, 100) + ")"; Chris@16: } Chris@16: Chris@16: virtual ~read_wkt_exception() throw() {} Chris@16: Chris@16: virtual const char* what() const throw() Chris@16: { Chris@16: return complete.c_str(); Chris@16: } Chris@16: private : Chris@16: std::string source; Chris@16: std::string message; Chris@16: std::string wkt; Chris@16: std::string complete; Chris@16: }; Chris@16: Chris@16: Chris@16: #ifndef DOXYGEN_NO_DETAIL Chris@16: // (wkt: Well Known Text, defined by OGC for all geometries and implemented by e.g. databases (MySQL, PostGIS)) Chris@16: namespace detail { namespace wkt Chris@16: { Chris@16: Chris@16: typedef boost::tokenizer > tokenizer; Chris@16: Chris@101: template ::value> Chris@16: struct parsing_assigner Chris@16: { Chris@16: static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, Chris@16: Point& point, std::string const& wkt) Chris@16: { Chris@16: typedef typename coordinate_type::type coordinate_type; Chris@16: Chris@16: // Stop at end of tokens, or at "," ot ")" Chris@16: bool finished = (it == end || *it == "," || *it == ")"); Chris@16: Chris@16: try Chris@16: { Chris@16: // Initialize missing coordinates to default constructor (zero) Chris@16: // OR Chris@16: // Use lexical_cast for conversion to double/int Chris@16: // Note that it is much slower than atof. However, it is more standard Chris@16: // and in parsing the change in performance falls probably away against Chris@16: // the tokenizing Chris@16: set(point, finished Chris@16: ? coordinate_type() Chris@16: : coordinate_cast::apply(*it)); Chris@16: } Chris@16: catch(boost::bad_lexical_cast const& blc) Chris@16: { Chris@16: throw read_wkt_exception(blc.what(), it, end, wkt); Chris@16: } Chris@16: catch(std::exception const& e) Chris@16: { Chris@16: throw read_wkt_exception(e.what(), it, end, wkt); Chris@16: } Chris@16: catch(...) Chris@16: { Chris@16: throw read_wkt_exception("", it, end, wkt); Chris@16: } Chris@16: Chris@16: parsing_assigner::apply( Chris@16: (finished ? it : ++it), end, point, wkt); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct parsing_assigner Chris@16: { Chris@16: static inline void apply(tokenizer::iterator&, tokenizer::iterator, Point&, Chris@16: std::string const&) Chris@16: { Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: Chris@16: template Chris@16: inline void handle_open_parenthesis(Iterator& it, Chris@16: Iterator const& end, std::string const& wkt) Chris@16: { Chris@16: if (it == end || *it != "(") Chris@16: { Chris@16: throw read_wkt_exception("Expected '('", it, end, wkt); Chris@16: } Chris@16: ++it; Chris@16: } Chris@16: Chris@16: Chris@16: template Chris@16: inline void handle_close_parenthesis(Iterator& it, Chris@16: Iterator const& end, std::string const& wkt) Chris@16: { Chris@16: if (it != end && *it == ")") Chris@16: { Chris@16: ++it; Chris@16: } Chris@16: else Chris@16: { Chris@16: throw read_wkt_exception("Expected ')'", it, end, wkt); Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: inline void check_end(Iterator& it, Chris@16: Iterator const& end, std::string const& wkt) Chris@16: { Chris@16: if (it != end) Chris@16: { Chris@16: throw read_wkt_exception("Too much tokens", it, end, wkt); Chris@16: } Chris@16: } Chris@16: Chris@16: /*! Chris@16: \brief Internal, parses coordinate sequences, strings are formated like "(1 2,3 4,...)" Chris@16: \param it token-iterator, should be pre-positioned at "(", is post-positions after last ")" Chris@16: \param end end-token-iterator Chris@16: \param out Output itererator receiving coordinates Chris@16: */ Chris@16: template Chris@16: struct container_inserter Chris@16: { Chris@16: // Version with output iterator Chris@16: template Chris@16: static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, Chris@16: std::string const& wkt, OutputIterator out) Chris@16: { Chris@16: handle_open_parenthesis(it, end, wkt); Chris@16: Chris@16: Point point; Chris@16: Chris@16: // Parse points until closing parenthesis Chris@16: Chris@16: while (it != end && *it != ")") Chris@16: { Chris@101: parsing_assigner::apply(it, end, point, wkt); Chris@16: out = point; Chris@16: ++out; Chris@16: if (it != end && *it == ",") Chris@16: { Chris@16: ++it; Chris@16: } Chris@16: } Chris@16: Chris@16: handle_close_parenthesis(it, end, wkt); Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@101: template ::value> Chris@101: struct stateful_range_appender Chris@101: { Chris@101: typedef typename geometry::point_type::type point_type; Chris@101: Chris@101: // NOTE: Geometry is a reference Chris@101: inline void append(Geometry geom, point_type const& point, bool) Chris@101: { Chris@101: geometry::append(geom, point); Chris@101: } Chris@101: }; Chris@101: Chris@101: template Chris@101: struct stateful_range_appender Chris@101: { Chris@101: typedef typename geometry::point_type::type point_type; Chris@101: typedef typename boost::range_size Chris@101: < Chris@101: typename util::bare_type::type Chris@101: >::type size_type; Chris@101: Chris@101: BOOST_STATIC_ASSERT(( boost::is_same Chris@101: < Chris@101: typename tag::type, Chris@101: ring_tag Chris@101: >::value )); Chris@101: Chris@101: inline stateful_range_appender() Chris@101: : pt_index(0) Chris@101: {} Chris@101: Chris@101: // NOTE: Geometry is a reference Chris@101: inline void append(Geometry geom, point_type const& point, bool is_next_expected) Chris@101: { Chris@101: bool should_append = true; Chris@101: Chris@101: if (pt_index == 0) Chris@101: { Chris@101: first_point = point; Chris@101: //should_append = true; Chris@101: } Chris@101: else Chris@101: { Chris@101: // NOTE: if there is not enough Points, they're always appended Chris@101: should_append Chris@101: = is_next_expected Chris@101: || pt_index < core_detail::closure::minimum_ring_size::value Chris@101: || !detail::equals::equals_point_point(point, first_point); Chris@101: } Chris@101: ++pt_index; Chris@101: Chris@101: if (should_append) Chris@101: { Chris@101: geometry::append(geom, point); Chris@101: } Chris@101: } Chris@101: Chris@101: private: Chris@101: size_type pt_index; Chris@101: point_type first_point; Chris@101: }; Chris@101: Chris@16: // Geometry is a value-type or reference-type Chris@16: template Chris@16: struct container_appender Chris@16: { Chris@101: typedef typename geometry::point_type::type point_type; Chris@16: Chris@16: static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, Chris@101: std::string const& wkt, Geometry out) Chris@16: { Chris@16: handle_open_parenthesis(it, end, wkt); Chris@16: Chris@101: stateful_range_appender appender; Chris@16: Chris@16: // Parse points until closing parenthesis Chris@16: while (it != end && *it != ")") Chris@16: { Chris@101: point_type point; Chris@16: Chris@101: parsing_assigner::apply(it, end, point, wkt); Chris@101: Chris@101: bool const is_next_expected = it != end && *it == ","; Chris@101: Chris@101: appender.append(out, point, is_next_expected); Chris@101: Chris@101: if (is_next_expected) Chris@16: { Chris@16: ++it; Chris@16: } Chris@16: } Chris@16: Chris@16: handle_close_parenthesis(it, end, wkt); Chris@16: } Chris@16: }; Chris@16: Chris@16: /*! Chris@16: \brief Internal, parses a point from a string like this "(x y)" Chris@16: \note used for parsing points and multi-points Chris@16: */ Chris@16: template Chris@16: struct point_parser Chris@16: { Chris@16: static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, Chris@16: std::string const& wkt, P& point) Chris@16: { Chris@16: handle_open_parenthesis(it, end, wkt); Chris@101: parsing_assigner

::apply(it, end, point, wkt); Chris@16: handle_close_parenthesis(it, end, wkt); Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: template Chris@16: struct linestring_parser Chris@16: { Chris@16: static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, Chris@16: std::string const& wkt, Geometry& geometry) Chris@16: { Chris@16: container_appender::apply(it, end, wkt, geometry); Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: template Chris@16: struct ring_parser Chris@16: { Chris@16: static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, Chris@16: std::string const& wkt, Ring& ring) Chris@16: { Chris@16: // A ring should look like polygon((x y,x y,x y...)) Chris@16: // So handle the extra opening/closing parentheses Chris@16: // and in between parse using the container-inserter Chris@16: handle_open_parenthesis(it, end, wkt); Chris@16: container_appender::apply(it, end, wkt, ring); Chris@16: handle_close_parenthesis(it, end, wkt); Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: /*! Chris@16: \brief Internal, parses a polygon from a string like this "((x y,x y),(x y,x y))" Chris@16: \note used for parsing polygons and multi-polygons Chris@16: */ Chris@16: template Chris@16: struct polygon_parser Chris@16: { Chris@16: typedef typename ring_return_type::type ring_return_type; Chris@16: typedef container_appender appender; Chris@16: Chris@16: static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, Chris@16: std::string const& wkt, Polygon& poly) Chris@16: { Chris@16: Chris@16: handle_open_parenthesis(it, end, wkt); Chris@16: Chris@16: int n = -1; Chris@16: Chris@16: // Stop at ")" Chris@16: while (it != end && *it != ")") Chris@16: { Chris@16: // Parse ring Chris@16: if (++n == 0) Chris@16: { Chris@16: appender::apply(it, end, wkt, exterior_ring(poly)); Chris@16: } Chris@16: else Chris@16: { Chris@16: typename ring_type::type ring; Chris@16: appender::apply(it, end, wkt, ring); Chris@16: traits::push_back Chris@16: < Chris@16: typename boost::remove_reference Chris@16: < Chris@16: typename traits::interior_mutable_type::type Chris@16: >::type Chris@16: >::apply(interior_rings(poly), ring); Chris@16: } Chris@16: Chris@16: if (it != end && *it == ",") Chris@16: { Chris@16: // Skip "," after ring is parsed Chris@16: ++it; Chris@16: } Chris@16: } Chris@16: Chris@16: handle_close_parenthesis(it, end, wkt); Chris@16: } Chris@16: }; Chris@16: Chris@101: Chris@16: inline bool one_of(tokenizer::iterator const& it, std::string const& value, Chris@16: bool& is_present) Chris@16: { Chris@16: if (boost::iequals(*it, value)) Chris@16: { Chris@16: is_present = true; Chris@16: return true; Chris@16: } Chris@16: return false; Chris@16: } Chris@16: Chris@16: inline bool one_of(tokenizer::iterator const& it, std::string const& value, Chris@16: bool& present1, bool& present2) Chris@16: { Chris@16: if (boost::iequals(*it, value)) Chris@16: { Chris@16: present1 = true; Chris@16: present2 = true; Chris@16: return true; Chris@16: } Chris@16: return false; Chris@16: } Chris@16: Chris@16: Chris@16: inline void handle_empty_z_m(tokenizer::iterator& it, tokenizer::iterator end, Chris@16: bool& has_empty, bool& has_z, bool& has_m) Chris@16: { Chris@16: has_empty = false; Chris@16: has_z = false; Chris@16: has_m = false; Chris@16: Chris@16: // WKT can optionally have Z and M (measured) values as in Chris@16: // POINT ZM (1 1 5 60), POINT M (1 1 80), POINT Z (1 1 5) Chris@16: // GGL supports any of them as coordinate values, but is not aware Chris@16: // of any Measured value. Chris@16: while (it != end Chris@16: && (one_of(it, "M", has_m) Chris@16: || one_of(it, "Z", has_z) Chris@16: || one_of(it, "EMPTY", has_empty) Chris@16: || one_of(it, "MZ", has_m, has_z) Chris@16: || one_of(it, "ZM", has_z, has_m) Chris@16: ) Chris@16: ) Chris@16: { Chris@16: ++it; Chris@16: } Chris@16: } Chris@16: Chris@16: /*! Chris@16: \brief Internal, starts parsing Chris@16: \param tokens boost tokens, parsed with separator " " and keeping separator "()" Chris@16: \param geometry string to compare with first token Chris@16: */ Chris@16: template Chris@16: inline bool initialize(tokenizer const& tokens, Chris@16: std::string const& geometry_name, std::string const& wkt, Chris@16: tokenizer::iterator& it) Chris@16: { Chris@16: it = tokens.begin(); Chris@16: if (it != tokens.end() && boost::iequals(*it++, geometry_name)) Chris@16: { Chris@16: bool has_empty, has_z, has_m; Chris@16: Chris@16: handle_empty_z_m(it, tokens.end(), has_empty, has_z, has_m); Chris@16: Chris@16: // Silence warning C4127: conditional expression is constant Chris@16: #if defined(_MSC_VER) Chris@16: #pragma warning(push) Chris@16: #pragma warning(disable : 4127) Chris@16: #endif Chris@16: Chris@16: if (has_z && dimension::type::value < 3) Chris@16: { Chris@16: throw read_wkt_exception("Z only allowed for 3 or more dimensions", wkt); Chris@16: } Chris@16: Chris@16: #if defined(_MSC_VER) Chris@16: #pragma warning(pop) Chris@16: #endif Chris@16: Chris@16: if (has_empty) Chris@16: { Chris@16: check_end(it, tokens.end(), wkt); Chris@16: return false; Chris@16: } Chris@16: // M is ignored at all. Chris@16: Chris@16: return true; Chris@16: } Chris@16: throw read_wkt_exception(std::string("Should start with '") + geometry_name + "'", wkt); Chris@16: } Chris@16: Chris@16: Chris@16: template class Parser, typename PrefixPolicy> Chris@16: struct geometry_parser Chris@16: { Chris@16: static inline void apply(std::string const& wkt, Geometry& geometry) Chris@16: { Chris@16: geometry::clear(geometry); Chris@16: Chris@16: tokenizer tokens(wkt, boost::char_separator(" ", ",()")); Chris@16: tokenizer::iterator it; Chris@16: if (initialize(tokens, PrefixPolicy::apply(), wkt, it)) Chris@16: { Chris@16: Parser::apply(it, tokens.end(), wkt, geometry); Chris@16: check_end(it, tokens.end(), wkt); Chris@16: } Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@101: template class Parser, typename PrefixPolicy> Chris@101: struct multi_parser Chris@101: { Chris@101: static inline void apply(std::string const& wkt, MultiGeometry& geometry) Chris@101: { Chris@101: traits::clear::apply(geometry); Chris@16: Chris@101: tokenizer tokens(wkt, boost::char_separator(" ", ",()")); Chris@101: tokenizer::iterator it; Chris@101: if (initialize(tokens, PrefixPolicy::apply(), wkt, it)) Chris@101: { Chris@101: handle_open_parenthesis(it, tokens.end(), wkt); Chris@101: Chris@101: // Parse sub-geometries Chris@101: while(it != tokens.end() && *it != ")") Chris@101: { Chris@101: traits::resize::apply(geometry, boost::size(geometry) + 1); Chris@101: Parser Chris@101: < Chris@101: typename boost::range_value::type Chris@101: >::apply(it, tokens.end(), wkt, *(boost::end(geometry) - 1)); Chris@101: if (it != tokens.end() && *it == ",") Chris@101: { Chris@101: // Skip "," after multi-element is parsed Chris@101: ++it; Chris@101: } Chris@101: } Chris@101: Chris@101: handle_close_parenthesis(it, tokens.end(), wkt); Chris@101: } Chris@101: Chris@101: check_end(it, tokens.end(), wkt); Chris@101: } Chris@101: }; Chris@101: Chris@101: template Chris@101: struct noparenthesis_point_parser Chris@101: { Chris@101: static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, Chris@101: std::string const& wkt, P& point) Chris@101: { Chris@101: parsing_assigner

::apply(it, end, point, wkt); Chris@101: } Chris@101: }; Chris@101: Chris@101: template Chris@101: struct multi_point_parser Chris@101: { Chris@101: static inline void apply(std::string const& wkt, MultiGeometry& geometry) Chris@101: { Chris@101: traits::clear::apply(geometry); Chris@101: Chris@101: tokenizer tokens(wkt, boost::char_separator(" ", ",()")); Chris@101: tokenizer::iterator it; Chris@101: Chris@101: if (initialize(tokens, PrefixPolicy::apply(), wkt, it)) Chris@101: { Chris@101: handle_open_parenthesis(it, tokens.end(), wkt); Chris@101: Chris@101: // If first point definition starts with "(" then parse points as (x y) Chris@101: // otherwise as "x y" Chris@101: bool using_brackets = (it != tokens.end() && *it == "("); Chris@101: Chris@101: while(it != tokens.end() && *it != ")") Chris@101: { Chris@101: traits::resize::apply(geometry, boost::size(geometry) + 1); Chris@101: Chris@101: if (using_brackets) Chris@101: { Chris@101: point_parser Chris@101: < Chris@101: typename boost::range_value::type Chris@101: >::apply(it, tokens.end(), wkt, *(boost::end(geometry) - 1)); Chris@101: } Chris@101: else Chris@101: { Chris@101: noparenthesis_point_parser Chris@101: < Chris@101: typename boost::range_value::type Chris@101: >::apply(it, tokens.end(), wkt, *(boost::end(geometry) - 1)); Chris@101: } Chris@101: Chris@101: if (it != tokens.end() && *it == ",") Chris@101: { Chris@101: // Skip "," after point is parsed Chris@101: ++it; Chris@101: } Chris@101: } Chris@101: Chris@101: handle_close_parenthesis(it, tokens.end(), wkt); Chris@101: } Chris@101: Chris@101: check_end(it, tokens.end(), wkt); Chris@101: } Chris@101: }; Chris@16: Chris@16: Chris@16: /*! Chris@16: \brief Supports box parsing Chris@16: \note OGC does not define the box geometry, and WKT does not support boxes. Chris@16: However, to be generic GGL supports reading and writing from and to boxes. Chris@16: Boxes are outputted as a standard POLYGON. GGL can read boxes from Chris@16: a standard POLYGON, from a POLYGON with 2 points of from a BOX Chris@16: \tparam Box the box Chris@16: */ Chris@16: template Chris@16: struct box_parser Chris@16: { Chris@16: static inline void apply(std::string const& wkt, Box& box) Chris@16: { Chris@16: bool should_close = false; Chris@16: tokenizer tokens(wkt, boost::char_separator(" ", ",()")); Chris@16: tokenizer::iterator it = tokens.begin(); Chris@16: tokenizer::iterator end = tokens.end(); Chris@16: if (it != end && boost::iequals(*it, "POLYGON")) Chris@16: { Chris@16: ++it; Chris@16: bool has_empty, has_z, has_m; Chris@16: handle_empty_z_m(it, end, has_empty, has_z, has_m); Chris@16: if (has_empty) Chris@16: { Chris@16: assign_zero(box); Chris@16: return; Chris@16: } Chris@16: handle_open_parenthesis(it, end, wkt); Chris@16: should_close = true; Chris@16: } Chris@16: else if (it != end && boost::iequals(*it, "BOX")) Chris@16: { Chris@16: ++it; Chris@16: } Chris@16: else Chris@16: { Chris@16: throw read_wkt_exception("Should start with 'POLYGON' or 'BOX'", wkt); Chris@16: } Chris@16: Chris@16: typedef typename point_type::type point_type; Chris@16: std::vector points; Chris@16: container_inserter::apply(it, end, wkt, std::back_inserter(points)); Chris@16: Chris@16: if (should_close) Chris@16: { Chris@16: handle_close_parenthesis(it, end, wkt); Chris@16: } Chris@16: check_end(it, end, wkt); Chris@16: Chris@101: unsigned int index = 0; Chris@101: std::size_t n = boost::size(points); Chris@16: if (n == 2) Chris@16: { Chris@16: index = 1; Chris@16: } Chris@16: else if (n == 4 || n == 5) Chris@16: { Chris@16: // In case of 4 or 5 points, we do not check the other ones, just Chris@16: // take the opposite corner which is always 2 Chris@16: index = 2; Chris@16: } Chris@16: else Chris@16: { Chris@16: throw read_wkt_exception("Box should have 2,4 or 5 points", wkt); Chris@16: } Chris@16: Chris@16: geometry::detail::assign_point_to_index(points.front(), box); Chris@16: geometry::detail::assign_point_to_index(points[index], box); Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: /*! Chris@16: \brief Supports segment parsing Chris@16: \note OGC does not define the segment, and WKT does not support segmentes. Chris@16: However, it is useful to implement it, also for testing purposes Chris@16: \tparam Segment the segment Chris@16: */ Chris@16: template Chris@16: struct segment_parser Chris@16: { Chris@16: static inline void apply(std::string const& wkt, Segment& segment) Chris@16: { Chris@16: tokenizer tokens(wkt, boost::char_separator(" ", ",()")); Chris@16: tokenizer::iterator it = tokens.begin(); Chris@16: tokenizer::iterator end = tokens.end(); Chris@16: if (it != end && Chris@16: (boost::iequals(*it, "SEGMENT") Chris@16: || boost::iequals(*it, "LINESTRING") )) Chris@16: { Chris@16: ++it; Chris@16: } Chris@16: else Chris@16: { Chris@16: throw read_wkt_exception("Should start with 'LINESTRING' or 'SEGMENT'", wkt); Chris@16: } Chris@16: Chris@16: typedef typename point_type::type point_type; Chris@16: std::vector points; Chris@16: container_inserter::apply(it, end, wkt, std::back_inserter(points)); Chris@16: Chris@16: check_end(it, end, wkt); Chris@16: Chris@16: if (boost::size(points) == 2) Chris@16: { Chris@16: geometry::detail::assign_point_to_index<0>(points.front(), segment); Chris@16: geometry::detail::assign_point_to_index<1>(points.back(), segment); Chris@16: } Chris@16: else Chris@16: { Chris@16: throw read_wkt_exception("Segment should have 2 points", wkt); Chris@16: } Chris@16: Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: }} // namespace detail::wkt Chris@16: #endif // DOXYGEN_NO_DETAIL Chris@16: Chris@16: #ifndef DOXYGEN_NO_DISPATCH Chris@16: namespace dispatch Chris@16: { Chris@16: Chris@16: template Chris@16: struct read_wkt {}; Chris@16: Chris@16: Chris@16: template Chris@16: struct read_wkt Chris@16: : detail::wkt::geometry_parser Chris@16: < Chris@16: Point, Chris@16: detail::wkt::point_parser, Chris@16: detail::wkt::prefix_point Chris@16: > Chris@16: {}; Chris@16: Chris@16: Chris@16: template Chris@16: struct read_wkt Chris@16: : detail::wkt::geometry_parser Chris@16: < Chris@16: L, Chris@16: detail::wkt::linestring_parser, Chris@16: detail::wkt::prefix_linestring Chris@16: > Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct read_wkt Chris@16: : detail::wkt::geometry_parser Chris@16: < Chris@16: Ring, Chris@16: detail::wkt::ring_parser, Chris@16: detail::wkt::prefix_polygon Chris@16: > Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct read_wkt Chris@16: : detail::wkt::geometry_parser Chris@16: < Chris@16: Geometry, Chris@16: detail::wkt::polygon_parser, Chris@16: detail::wkt::prefix_polygon Chris@16: > Chris@16: {}; Chris@16: Chris@16: Chris@101: template Chris@101: struct read_wkt Chris@101: : detail::wkt::multi_point_parser Chris@101: < Chris@101: MultiGeometry, Chris@101: detail::wkt::prefix_multipoint Chris@101: > Chris@101: {}; Chris@101: Chris@101: template Chris@101: struct read_wkt Chris@101: : detail::wkt::multi_parser Chris@101: < Chris@101: MultiGeometry, Chris@101: detail::wkt::linestring_parser, Chris@101: detail::wkt::prefix_multilinestring Chris@101: > Chris@101: {}; Chris@101: Chris@101: template Chris@101: struct read_wkt Chris@101: : detail::wkt::multi_parser Chris@101: < Chris@101: MultiGeometry, Chris@101: detail::wkt::polygon_parser, Chris@101: detail::wkt::prefix_multipolygon Chris@101: > Chris@101: {}; Chris@101: Chris@101: Chris@16: // Box (Non-OGC) Chris@16: template Chris@16: struct read_wkt Chris@16: : detail::wkt::box_parser Chris@16: {}; Chris@16: Chris@16: // Segment (Non-OGC) Chris@16: template Chris@16: struct read_wkt Chris@16: : detail::wkt::segment_parser Chris@16: {}; Chris@16: Chris@16: Chris@16: } // namespace dispatch Chris@16: #endif // DOXYGEN_NO_DISPATCH Chris@16: Chris@16: /*! Chris@16: \brief Parses OGC Well-Known Text (\ref WKT) into a geometry (any geometry) Chris@16: \ingroup wkt Chris@101: \tparam Geometry \tparam_geometry Chris@16: \param wkt string containing \ref WKT Chris@101: \param geometry \param_geometry output geometry Chris@101: \ingroup wkt Chris@101: \qbk{[include reference/io/read_wkt.qbk]} Chris@16: */ Chris@16: template Chris@16: inline void read_wkt(std::string const& wkt, Geometry& geometry) Chris@16: { Chris@16: geometry::concept::check(); Chris@16: dispatch::read_wkt::type, Geometry>::apply(wkt, geometry); Chris@16: } Chris@16: Chris@16: }} // namespace boost::geometry Chris@16: Chris@16: #endif // BOOST_GEOMETRY_IO_WKT_READ_HPP