Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:35:35

0001 // Boost.Geometry (aka GGL, Generic Geometry Library)
0002 
0003 // Copyright (c) 2007-2022 Barend Gehrels, Amsterdam, the Netherlands.
0004 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
0005 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
0006 // Copyright (c) 2017-2023 Adam Wulkiewicz, Lodz, Poland.
0007 // Copyright (c) 2020 Baidyanath Kundu, Haldia, India
0008 
0009 // This file was modified by Oracle on 2014-2021.
0010 // Modifications copyright (c) 2014-2021 Oracle and/or its affiliates.
0011 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
0012 
0013 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
0014 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
0015 
0016 // Use, modification and distribution is subject to the Boost Software License,
0017 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0018 // http://www.boost.org/LICENSE_1_0.txt)
0019 
0020 #ifndef BOOST_GEOMETRY_IO_WKT_READ_HPP
0021 #define BOOST_GEOMETRY_IO_WKT_READ_HPP
0022 
0023 #include <cstddef>
0024 #include <string>
0025 
0026 #include <boost/algorithm/string/predicate.hpp>
0027 #include <boost/lexical_cast.hpp>
0028 #include <boost/range/begin.hpp>
0029 #include <boost/range/end.hpp>
0030 #include <boost/range/size.hpp>
0031 #include <boost/range/value_type.hpp>
0032 #include <boost/tokenizer.hpp>
0033 #include <boost/throw_exception.hpp>
0034 
0035 #include <boost/geometry/algorithms/assign.hpp>
0036 #include <boost/geometry/algorithms/append.hpp>
0037 #include <boost/geometry/algorithms/clear.hpp>
0038 #include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
0039 
0040 #include <boost/geometry/core/access.hpp>
0041 #include <boost/geometry/core/coordinate_dimension.hpp>
0042 #include <boost/geometry/core/exception.hpp>
0043 #include <boost/geometry/core/exterior_ring.hpp>
0044 #include <boost/geometry/core/geometry_id.hpp>
0045 #include <boost/geometry/core/geometry_types.hpp>
0046 #include <boost/geometry/core/interior_rings.hpp>
0047 #include <boost/geometry/core/mutable_range.hpp>
0048 #include <boost/geometry/core/point_type.hpp>
0049 #include <boost/geometry/core/tag.hpp>
0050 #include <boost/geometry/core/tags.hpp>
0051 
0052 #include <boost/geometry/geometries/adapted/boost_variant.hpp> // For consistency with other functions
0053 #include <boost/geometry/geometries/concepts/check.hpp>
0054 
0055 #include <boost/geometry/io/wkt/detail/prefix.hpp>
0056 
0057 #include <boost/geometry/strategies/io/cartesian.hpp>
0058 #include <boost/geometry/strategies/io/geographic.hpp>
0059 #include <boost/geometry/strategies/io/spherical.hpp>
0060 
0061 #include <boost/geometry/util/coordinate_cast.hpp>
0062 #include <boost/geometry/util/range.hpp>
0063 #include <boost/geometry/util/sequence.hpp>
0064 #include <boost/geometry/util/type_traits.hpp>
0065 
0066 namespace boost { namespace geometry
0067 {
0068 
0069 /*!
0070 \brief Exception showing things wrong with WKT parsing
0071 \ingroup wkt
0072 */
0073 struct read_wkt_exception : public geometry::exception
0074 {
0075     template <typename Iterator>
0076     read_wkt_exception(std::string const& msg,
0077                        Iterator const& it,
0078                        Iterator const& end,
0079                        std::string const& wkt)
0080         : message(msg)
0081         , wkt(wkt)
0082     {
0083         if (it != end)
0084         {
0085             source = " at '";
0086             source += it->c_str();
0087             source += "'";
0088         }
0089         complete = message + source + " in '" + wkt.substr(0, 100) + "'";
0090     }
0091 
0092     read_wkt_exception(std::string const& msg, std::string const& wkt)
0093         : message(msg)
0094         , wkt(wkt)
0095     {
0096         complete = message + "' in (" + wkt.substr(0, 100) + ")";
0097     }
0098 
0099     const char* what() const noexcept override
0100     {
0101         return complete.c_str();
0102     }
0103 private :
0104     std::string source;
0105     std::string message;
0106     std::string wkt;
0107     std::string complete;
0108 };
0109 
0110 
0111 #ifndef DOXYGEN_NO_DETAIL
0112 // (wkt: Well Known Text, defined by OGC for all geometries and implemented by e.g. databases (MySQL, PostGIS))
0113 namespace detail { namespace wkt
0114 {
0115 
0116 inline auto make_tokenizer(std::string const& wkt)
0117 {
0118     using separator = boost::char_separator<char>;
0119     using tokenizer = boost::tokenizer<separator>;
0120     const tokenizer tokens(wkt, separator(" \n\t\r", ",()"));
0121     return tokens;
0122 }
0123 
0124 template <typename Point,
0125           std::size_t Dimension = 0,
0126           std::size_t DimensionCount = geometry::dimension<Point>::value>
0127 struct parsing_assigner
0128 {
0129     template <typename TokenizerIterator>
0130     static inline void apply(TokenizerIterator& it,
0131                              TokenizerIterator const& end,
0132                              Point& point,
0133                              std::string const& wkt)
0134     {
0135         using coordinate_type = typename coordinate_type<Point>::type;
0136 
0137         // Stop at end of tokens, or at "," ot ")"
0138         bool finished = (it == end || *it == "," || *it == ")");
0139 
0140         try
0141         {
0142             // Initialize missing coordinates to default constructor (zero)
0143             // OR
0144             // Use lexical_cast for conversion to double/int
0145             // Note that it is much slower than atof. However, it is more standard
0146             // and in parsing the change in performance falls probably away against
0147             // the tokenizing
0148             set<Dimension>(point, finished
0149                     ? coordinate_type()
0150                     : coordinate_cast<coordinate_type>::apply(*it));
0151         }
0152         catch(boost::bad_lexical_cast const& blc)
0153         {
0154             BOOST_THROW_EXCEPTION(read_wkt_exception(blc.what(), it, end, wkt));
0155         }
0156         catch(std::exception const& e)
0157         {
0158             BOOST_THROW_EXCEPTION(read_wkt_exception(e.what(), it, end, wkt));
0159         }
0160         catch(...)
0161         {
0162             BOOST_THROW_EXCEPTION(read_wkt_exception("", it, end, wkt));
0163         }
0164 
0165         parsing_assigner<Point, Dimension + 1, DimensionCount>::apply(
0166                         (finished ? it : ++it), end, point, wkt);
0167     }
0168 };
0169 
0170 template <typename Point, std::size_t DimensionCount>
0171 struct parsing_assigner<Point, DimensionCount, DimensionCount>
0172 {
0173     template <typename TokenizerIterator>
0174     static inline void apply(TokenizerIterator&,
0175                              TokenizerIterator const&,
0176                              Point&,
0177                              std::string const&)
0178     {
0179     }
0180 };
0181 
0182 
0183 
0184 template <typename Iterator>
0185 inline void handle_open_parenthesis(Iterator& it,
0186                                     Iterator const& end,
0187                                     std::string const& wkt)
0188 {
0189     if (it == end || *it != "(")
0190     {
0191         BOOST_THROW_EXCEPTION(read_wkt_exception("Expected '('", it, end, wkt));
0192     }
0193     ++it;
0194 }
0195 
0196 
0197 template <typename Iterator>
0198 inline void handle_close_parenthesis(Iterator& it,
0199                                      Iterator const& end,
0200                                      std::string const& wkt)
0201 {
0202     if (it != end && *it == ")")
0203     {
0204         ++it;
0205     }
0206     else
0207     {
0208         BOOST_THROW_EXCEPTION(read_wkt_exception("Expected ')'", it, end, wkt));
0209     }
0210 }
0211 
0212 template <typename Iterator>
0213 inline void check_end(Iterator& it,
0214                       Iterator const& end,
0215                       std::string const& wkt)
0216 {
0217     if (it != end)
0218     {
0219         BOOST_THROW_EXCEPTION(read_wkt_exception("Too many tokens", it, end, wkt));
0220     }
0221 }
0222 
0223 /*!
0224 \brief Internal, parses coordinate sequences, strings are formated like "(1 2,3 4,...)"
0225 \param it token-iterator, should be pre-positioned at "(", is post-positions after last ")"
0226 \param end end-token-iterator
0227 \param out Output itererator receiving coordinates
0228 */
0229 template <typename Point>
0230 struct container_inserter
0231 {
0232     // Version with output iterator
0233     template <typename TokenizerIterator, typename OutputIterator>
0234     static inline void apply(TokenizerIterator& it,
0235                              TokenizerIterator const& end,
0236                              std::string const& wkt,
0237                              OutputIterator out)
0238     {
0239         handle_open_parenthesis(it, end, wkt);
0240 
0241         Point point;
0242 
0243         // Parse points until closing parenthesis
0244 
0245         while (it != end && *it != ")")
0246         {
0247             parsing_assigner<Point>::apply(it, end, point, wkt);
0248             out = point;
0249             ++out;
0250             if (it != end && *it == ",")
0251             {
0252                 ++it;
0253             }
0254         }
0255 
0256         handle_close_parenthesis(it, end, wkt);
0257     }
0258 };
0259 
0260 
0261 template <typename Geometry,
0262           closure_selector Closure = closure<Geometry>::value>
0263 struct stateful_range_appender
0264 {
0265     // NOTE: Geometry is a reference
0266     inline void append(Geometry geom, typename geometry::point_type<Geometry>::type const& point, bool)
0267     {
0268         geometry::append(geom, point);
0269     }
0270 };
0271 
0272 template <typename Geometry>
0273 struct stateful_range_appender<Geometry, open>
0274 {
0275     using point_type = typename geometry::point_type<Geometry>::type;
0276     using size_type = typename boost::range_size
0277         <
0278             typename util::remove_cptrref<Geometry>::type
0279         >::type;
0280 
0281     BOOST_STATIC_ASSERT((util::is_ring<Geometry>::value));
0282 
0283     inline stateful_range_appender()
0284         : pt_index(0)
0285     {}
0286 
0287     // NOTE: Geometry is a reference
0288     inline void append(Geometry geom, point_type const& point, bool is_next_expected)
0289     {
0290         bool should_append = true;
0291 
0292         if (pt_index == 0)
0293         {
0294             first_point = point;
0295         }
0296         else
0297         {
0298             // NOTE: if there are not enough Points, they're always appended
0299             should_append
0300                 = is_next_expected
0301                 || pt_index < core_detail::closure::minimum_ring_size<open>::value
0302                 || disjoint(point, first_point);
0303         }
0304         ++pt_index;
0305 
0306         if (should_append)
0307         {
0308             geometry::append(geom, point);
0309         }
0310     }
0311 
0312 private:
0313     static inline bool disjoint(point_type const& p1, point_type const& p2)
0314     {
0315         // TODO: pass strategy
0316         using strategy_type = typename strategies::io::services::default_strategy
0317             <
0318                 point_type
0319             >::type;
0320 
0321         return detail::disjoint::disjoint_point_point(p1, p2, strategy_type());
0322     }
0323 
0324     size_type pt_index;
0325     point_type first_point;
0326 };
0327 
0328 // Geometry is a value-type or reference-type
0329 template <typename Geometry>
0330 struct container_appender
0331 {
0332     using point_type = typename geometry::point_type<Geometry>::type;
0333 
0334     template <typename TokenizerIterator>
0335     static inline void apply(TokenizerIterator& it,
0336                              TokenizerIterator const& end,
0337                              std::string const& wkt,
0338                              Geometry out)
0339     {
0340         handle_open_parenthesis(it, end, wkt);
0341 
0342         stateful_range_appender<Geometry> appender;
0343 
0344         // Parse points until closing parenthesis
0345         while (it != end && *it != ")")
0346         {
0347             point_type point;
0348 
0349             parsing_assigner<point_type>::apply(it, end, point, wkt);
0350 
0351             bool const is_next_expected = it != end && *it == ",";
0352 
0353             appender.append(out, point, is_next_expected);
0354 
0355             if (is_next_expected)
0356             {
0357                 ++it;
0358             }
0359         }
0360 
0361         handle_close_parenthesis(it, end, wkt);
0362     }
0363 };
0364 
0365 /*!
0366 \brief Internal, parses a point from a string like this "(x y)"
0367 \note used for parsing points and multi-points
0368 */
0369 template <typename P>
0370 struct point_parser
0371 {
0372     template <typename TokenizerIterator>
0373     static inline void apply(TokenizerIterator& it,
0374                              TokenizerIterator const& end,
0375                              std::string const& wkt,
0376                              P& point)
0377     {
0378         handle_open_parenthesis(it, end, wkt);
0379         parsing_assigner<P>::apply(it, end, point, wkt);
0380         handle_close_parenthesis(it, end, wkt);
0381     }
0382 };
0383 
0384 
0385 template <typename Geometry>
0386 struct linestring_parser
0387 {
0388     template <typename TokenizerIterator>
0389     static inline void apply(TokenizerIterator& it,
0390                              TokenizerIterator const& end,
0391                              std::string const& wkt,
0392                              Geometry& geometry)
0393     {
0394         container_appender<Geometry&>::apply(it, end, wkt, geometry);
0395     }
0396 };
0397 
0398 
0399 template <typename Ring>
0400 struct ring_parser
0401 {
0402     template <typename TokenizerIterator>
0403     static inline void apply(TokenizerIterator& it,
0404                              TokenizerIterator const& end,
0405                              std::string const& wkt,
0406                              Ring& ring)
0407     {
0408         // A ring should look like polygon((x y,x y,x y...))
0409         // So handle the extra opening/closing parentheses
0410         // and in between parse using the container-inserter
0411         handle_open_parenthesis(it, end, wkt);
0412         container_appender<Ring&>::apply(it, end, wkt, ring);
0413         handle_close_parenthesis(it, end, wkt);
0414     }
0415 };
0416 
0417 
0418 /*!
0419 \brief Internal, parses a polygon from a string like this "((x y,x y),(x y,x y))"
0420 \note used for parsing polygons and multi-polygons
0421 */
0422 template <typename Polygon>
0423 struct polygon_parser
0424 {
0425     using ring_return_type = typename ring_return_type<Polygon>::type;
0426     using appender = container_appender<ring_return_type>;
0427 
0428     template <typename TokenizerIterator>
0429     static inline void apply(TokenizerIterator& it,
0430                              TokenizerIterator const& end,
0431                              std::string const& wkt,
0432                              Polygon& poly)
0433     {
0434 
0435         handle_open_parenthesis(it, end, wkt);
0436 
0437         int n = -1;
0438 
0439         // Stop at ")"
0440         while (it != end && *it != ")")
0441         {
0442             // Parse ring
0443             if (++n == 0)
0444             {
0445                 appender::apply(it, end, wkt, exterior_ring(poly));
0446             }
0447             else
0448             {
0449                 typename ring_type<Polygon>::type ring;
0450                 appender::apply(it, end, wkt, ring);
0451                 range::push_back(geometry::interior_rings(poly), std::move(ring));
0452             }
0453 
0454             if (it != end && *it == ",")
0455             {
0456                 // Skip "," after ring is parsed
0457                 ++it;
0458             }
0459         }
0460 
0461         handle_close_parenthesis(it, end, wkt);
0462     }
0463 };
0464 
0465 
0466 template <typename TokenizerIterator>
0467 inline bool one_of(TokenizerIterator const& it,
0468                    std::string const& value,
0469                    bool& is_present)
0470 {
0471     if (boost::iequals(*it, value))
0472     {
0473         is_present = true;
0474         return true;
0475     }
0476     return false;
0477 }
0478 
0479 template <typename TokenizerIterator>
0480 inline bool one_of(TokenizerIterator const& it,
0481                    std::string const& value,
0482                    bool& present1,
0483                    bool& present2)
0484 {
0485     if (boost::iequals(*it, value))
0486     {
0487         present1 = true;
0488         present2 = true;
0489         return true;
0490     }
0491     return false;
0492 }
0493 
0494 
0495 template <typename TokenizerIterator>
0496 inline void handle_empty_z_m(TokenizerIterator& it,
0497                              TokenizerIterator const& end,
0498                              bool& has_empty,
0499                              bool& has_z,
0500                              bool& has_m)
0501 {
0502     has_empty = false;
0503     has_z = false;
0504     has_m = false;
0505 
0506     // WKT can optionally have Z and M (measured) values as in
0507     // POINT ZM (1 1 5 60), POINT M (1 1 80), POINT Z (1 1 5)
0508     // GGL supports any of them as coordinate values, but is not aware
0509     // of any Measured value.
0510     while (it != end
0511            && (one_of(it, "M", has_m)
0512                || one_of(it, "Z", has_z)
0513                || one_of(it, "EMPTY", has_empty)
0514                || one_of(it, "MZ", has_m, has_z)
0515                || one_of(it, "ZM", has_z, has_m)
0516                )
0517            )
0518     {
0519         ++it;
0520     }
0521 }
0522 
0523 
0524 template <typename Geometry, typename Tag = typename geometry::tag<Geometry>::type>
0525 struct dimension
0526     : geometry::dimension<Geometry>
0527 {};
0528 
0529 // TODO: For now assume the dimension of the first type defined for GC
0530 //       This should probably be unified for all algorithms
0531 template <typename Geometry>
0532 struct dimension<Geometry, geometry_collection_tag>
0533     : geometry::dimension
0534         <
0535             typename util::sequence_front
0536                 <
0537                     typename traits::geometry_types<Geometry>::type
0538                 >::type
0539         >
0540 {};
0541 
0542 
0543 /*!
0544 \brief Internal, starts parsing
0545 \param geometry_name string to compare with first token
0546 */
0547 template <typename Geometry, typename TokenizerIterator>
0548 inline bool initialize(TokenizerIterator& it,
0549                        TokenizerIterator const& end,
0550                        std::string const& wkt,
0551                        std::string const& geometry_name)
0552 {
0553     if (it == end || ! boost::iequals(*it++, geometry_name))
0554     {
0555         BOOST_THROW_EXCEPTION(read_wkt_exception(std::string("Should start with '") + geometry_name + "'", wkt));
0556     }
0557 
0558     bool has_empty, has_z, has_m;
0559 
0560     handle_empty_z_m(it, end, has_empty, has_z, has_m);
0561 
0562 // Silence warning C4127: conditional expression is constant
0563 #if defined(_MSC_VER)
0564 #pragma warning(push)
0565 #pragma warning(disable : 4127)
0566 #endif
0567 
0568     if (has_z && dimension<Geometry>::value < 3)
0569     {
0570         BOOST_THROW_EXCEPTION(read_wkt_exception("Z only allowed for 3 or more dimensions", wkt));
0571     }
0572 
0573 #if defined(_MSC_VER)
0574 #pragma warning(pop)
0575 #endif
0576 
0577     if (has_empty)
0578     {
0579         return false;
0580     }
0581     // M is ignored at all.
0582 
0583     return true;
0584 }
0585 
0586 
0587 template <typename Geometry, template<typename> class Parser, typename PrefixPolicy>
0588 struct geometry_parser
0589 {
0590     static inline void apply(std::string const& wkt, Geometry& geometry)
0591     {
0592         geometry::clear(geometry);
0593 
0594         auto const tokens{make_tokenizer(wkt)};
0595         auto it = tokens.begin();
0596         auto const end = tokens.end();
0597 
0598         apply(it, end, wkt, geometry);
0599 
0600         check_end(it, end, wkt);
0601     }
0602 
0603     template <typename TokenizerIterator>
0604     static inline void apply(TokenizerIterator& it,
0605                              TokenizerIterator const& end,
0606                              std::string const& wkt,
0607                              Geometry& geometry)
0608     {
0609         if (initialize<Geometry>(it, end, wkt, PrefixPolicy::apply()))
0610         {
0611             Parser<Geometry>::apply(it, end, wkt, geometry);
0612         }
0613     }
0614 };
0615 
0616 
0617 template <typename MultiGeometry, template<typename> class Parser, typename PrefixPolicy>
0618 struct multi_parser
0619 {
0620     static inline void apply(std::string const& wkt, MultiGeometry& geometry)
0621     {
0622         traits::clear<MultiGeometry>::apply(geometry);
0623 
0624         auto const tokens{make_tokenizer(wkt)};
0625         auto it = tokens.begin();
0626         auto const end = tokens.end();
0627 
0628         apply(it, end, wkt, geometry);
0629 
0630         check_end(it, end, wkt);
0631     }
0632 
0633     template <typename TokenizerIterator>
0634     static inline void apply(TokenizerIterator& it,
0635                              TokenizerIterator const& end,
0636                              std::string const& wkt,
0637                              MultiGeometry& geometry)
0638     {
0639         if (initialize<MultiGeometry>(it, end, wkt, PrefixPolicy::apply()))
0640         {
0641             handle_open_parenthesis(it, end, wkt);
0642 
0643             // Parse sub-geometries
0644             while(it != end && *it != ")")
0645             {
0646                 traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1);
0647                 Parser
0648                     <
0649                         typename boost::range_value<MultiGeometry>::type
0650                     >::apply(it, end, wkt, *(boost::end(geometry) - 1));
0651                 if (it != end && *it == ",")
0652                 {
0653                     // Skip "," after multi-element is parsed
0654                     ++it;
0655                 }
0656             }
0657 
0658             handle_close_parenthesis(it, end, wkt);
0659         }
0660     }
0661 };
0662 
0663 template <typename P>
0664 struct noparenthesis_point_parser
0665 {
0666     template <typename TokenizerIterator>
0667     static inline void apply(TokenizerIterator& it,
0668                              TokenizerIterator const& end,
0669                              std::string const& wkt,
0670                              P& point)
0671     {
0672         parsing_assigner<P>::apply(it, end, point, wkt);
0673     }
0674 };
0675 
0676 template <typename MultiGeometry, typename PrefixPolicy>
0677 struct multi_point_parser
0678 {
0679     static inline void apply(std::string const& wkt, MultiGeometry& geometry)
0680     {
0681         traits::clear<MultiGeometry>::apply(geometry);
0682 
0683         auto const tokens{make_tokenizer(wkt)};
0684         auto it = tokens.begin();
0685         auto const end = tokens.end();
0686 
0687         apply(it, end, wkt, geometry);
0688 
0689         check_end(it, end, wkt);
0690     }
0691 
0692     template <typename TokenizerIterator>
0693     static inline void apply(TokenizerIterator& it,
0694                              TokenizerIterator const& end,
0695                              std::string const& wkt,
0696                              MultiGeometry& geometry)
0697     {
0698         if (initialize<MultiGeometry>(it, end, wkt, PrefixPolicy::apply()))
0699         {
0700             handle_open_parenthesis(it, end, wkt);
0701 
0702             // If first point definition starts with "(" then parse points as (x y)
0703             // otherwise as "x y"
0704             bool using_brackets = (it != end && *it == "(");
0705 
0706             while(it != end && *it != ")")
0707             {
0708                 traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1);
0709 
0710                 if (using_brackets)
0711                 {
0712                     point_parser
0713                         <
0714                             typename boost::range_value<MultiGeometry>::type
0715                         >::apply(it, end, wkt, *(boost::end(geometry) - 1));
0716                 }
0717                 else
0718                 {
0719                     noparenthesis_point_parser
0720                         <
0721                             typename boost::range_value<MultiGeometry>::type
0722                         >::apply(it, end, wkt, *(boost::end(geometry) - 1));
0723                 }
0724 
0725                 if (it != end && *it == ",")
0726                 {
0727                     // Skip "," after point is parsed
0728                     ++it;
0729                 }
0730             }
0731 
0732             handle_close_parenthesis(it, end, wkt);
0733         }
0734     }
0735 };
0736 
0737 
0738 /*!
0739 \brief Supports box parsing
0740 \note OGC does not define the box geometry, and WKT does not support boxes.
0741     However, to be generic GGL supports reading and writing from and to boxes.
0742     Boxes are outputted as a standard POLYGON. GGL can read boxes from
0743     a standard POLYGON, from a POLYGON with 2 points of from a BOX
0744 \tparam Box the box
0745 */
0746 template <typename Box>
0747 struct box_parser
0748 {
0749     static inline void apply(std::string const& wkt, Box& box)
0750     {
0751         auto const tokens{make_tokenizer(wkt)};
0752         auto it = tokens.begin();
0753         auto const end = tokens.end();
0754 
0755         apply(it, end, wkt, box);
0756 
0757         check_end(it, end, wkt);
0758     }
0759 
0760     template <typename TokenizerIterator>
0761     static inline void apply(TokenizerIterator& it,
0762                              TokenizerIterator const& end,
0763                              std::string const& wkt,
0764                              Box& box)
0765     {
0766         bool should_close = false;
0767         if (it != end && boost::iequals(*it, "POLYGON"))
0768         {
0769             ++it;
0770             bool has_empty, has_z, has_m;
0771             handle_empty_z_m(it, end, has_empty, has_z, has_m);
0772             if (has_empty)
0773             {
0774                 assign_zero(box);
0775                 return;
0776             }
0777             handle_open_parenthesis(it, end, wkt);
0778             should_close = true;
0779         }
0780         else if (it != end && boost::iequals(*it, "BOX"))
0781         {
0782             ++it;
0783         }
0784         else
0785         {
0786             BOOST_THROW_EXCEPTION(read_wkt_exception("Should start with 'POLYGON' or 'BOX'", wkt));
0787         }
0788 
0789         using point_type = typename point_type<Box>::type;
0790         std::vector<point_type> points;
0791         container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points));
0792 
0793         if (should_close)
0794         {
0795             handle_close_parenthesis(it, end, wkt);
0796         }
0797 
0798         unsigned int index = 0;
0799         std::size_t n = boost::size(points);
0800         if (n == 2)
0801         {
0802             index = 1;
0803         }
0804         else if (n == 4 || n == 5)
0805         {
0806             // In case of 4 or 5 points, we do not check the other ones, just
0807             // take the opposite corner which is always 2
0808             index = 2;
0809         }
0810         else
0811         {
0812             BOOST_THROW_EXCEPTION(read_wkt_exception("Box should have 2,4 or 5 points", wkt));
0813         }
0814 
0815         geometry::detail::assign_point_to_index<min_corner>(points.front(), box);
0816         geometry::detail::assign_point_to_index<max_corner>(points[index], box);
0817     }
0818 };
0819 
0820 
0821 /*!
0822 \brief Supports segment parsing
0823 \note OGC does not define the segment, and WKT does not support segmentes.
0824     However, it is useful to implement it, also for testing purposes
0825 \tparam Segment the segment
0826 */
0827 template <typename Segment>
0828 struct segment_parser
0829 {
0830     static inline void apply(std::string const& wkt, Segment& segment)
0831     {
0832         auto const tokens{make_tokenizer(wkt)};
0833         auto it = tokens.begin();
0834         auto const end = tokens.end();
0835 
0836         apply(it, end, wkt, segment);
0837 
0838         check_end(it, end, wkt);
0839     }
0840 
0841     template <typename TokenizerIterator>
0842     static inline void apply(TokenizerIterator& it,
0843                              TokenizerIterator const& end,
0844                              std::string const& wkt,
0845                              Segment& segment)
0846     {
0847         if (it != end
0848             && (boost::iequals(*it, prefix_segment::apply())
0849                 || boost::iequals(*it, prefix_linestring::apply())))
0850         {
0851             ++it;
0852         }
0853         else
0854         {
0855             BOOST_THROW_EXCEPTION(read_wkt_exception("Should start with 'LINESTRING' or 'SEGMENT'", wkt));
0856         }
0857 
0858         using point_type = typename point_type<Segment>::type;
0859         std::vector<point_type> points;
0860         container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points));
0861 
0862         if (boost::size(points) == 2)
0863         {
0864             geometry::detail::assign_point_to_index<0>(points.front(), segment);
0865             geometry::detail::assign_point_to_index<1>(points.back(), segment);
0866         }
0867         else
0868         {
0869             BOOST_THROW_EXCEPTION(read_wkt_exception("Segment should have 2 points", wkt));
0870         }
0871     }
0872 };
0873 
0874 
0875 struct dynamic_move_assign
0876 {
0877     template <typename DynamicGeometry, typename Geometry>
0878     static void apply(DynamicGeometry& dynamic_geometry, Geometry & geometry)
0879     {
0880         dynamic_geometry = std::move(geometry);
0881     }
0882 };
0883 
0884 struct dynamic_move_emplace_back
0885 {
0886     template <typename GeometryCollection, typename Geometry>
0887     static void apply(GeometryCollection& geometry_collection, Geometry & geometry)
0888     {
0889         traits::emplace_back<GeometryCollection>::apply(geometry_collection, std::move(geometry));
0890     }
0891 };
0892 
0893 template
0894 <
0895     typename Geometry,
0896     template <typename, typename> class ReadWkt,
0897     typename AppendPolicy
0898 >
0899 struct dynamic_readwkt_caller
0900 {
0901     template <typename TokenizerIterator>
0902     static inline void apply(TokenizerIterator& it,
0903                              TokenizerIterator const& end,
0904                              std::string const& wkt,
0905                              Geometry& geometry)
0906     {
0907         static const char* tag_point = prefix_point::apply();
0908         static const char* tag_linestring = prefix_linestring::apply();
0909         static const char* tag_polygon = prefix_polygon::apply();
0910 
0911         static const char* tag_multi_point = prefix_multipoint::apply();
0912         static const char* tag_multi_linestring = prefix_multilinestring::apply();
0913         static const char* tag_multi_polygon = prefix_multipolygon::apply();
0914 
0915         static const char* tag_segment = prefix_segment::apply();
0916         static const char* tag_box = prefix_box::apply();
0917         static const char* tag_gc = prefix_geometrycollection::apply();
0918 
0919         if (boost::iequals(*it, tag_point))
0920         {
0921             parse_geometry<util::is_point>(tag_point, it, end, wkt, geometry);
0922         }
0923         else if (boost::iequals(*it, tag_multi_point))
0924         {
0925             parse_geometry<util::is_multi_point>(tag_multi_point, it, end, wkt, geometry);
0926         }
0927         else if (boost::iequals(*it, tag_segment))
0928         {
0929             parse_geometry<util::is_segment>(tag_segment, it, end, wkt, geometry);
0930         }
0931         else if (boost::iequals(*it, tag_linestring))
0932         {
0933             parse_geometry<util::is_linestring>(tag_linestring, it, end, wkt, geometry, false)
0934             || parse_geometry<util::is_segment>(tag_linestring, it, end, wkt, geometry);
0935         }
0936         else if (boost::iequals(*it, tag_multi_linestring))
0937         {
0938             parse_geometry<util::is_multi_linestring>(tag_multi_linestring, it, end, wkt, geometry);
0939         }
0940         else if (boost::iequals(*it, tag_box))
0941         {
0942             parse_geometry<util::is_box>(tag_box, it, end, wkt, geometry);
0943         }
0944         else if (boost::iequals(*it, tag_polygon))
0945         {
0946             parse_geometry<util::is_polygon>(tag_polygon, it, end, wkt, geometry, false)
0947             || parse_geometry<util::is_ring>(tag_polygon, it, end, wkt, geometry, false)
0948             || parse_geometry<util::is_box>(tag_polygon, it, end, wkt, geometry);
0949         }
0950         else if (boost::iequals(*it, tag_multi_polygon))
0951         {
0952             parse_geometry<util::is_multi_polygon>(tag_multi_polygon, it, end, wkt, geometry);
0953         }
0954         else if (boost::iequals(*it, tag_gc))
0955         {
0956             parse_geometry<util::is_geometry_collection>(tag_gc, it, end, wkt, geometry);
0957         }
0958         else
0959         {
0960             BOOST_THROW_EXCEPTION(read_wkt_exception(
0961                 "Should start with geometry's type, for example 'POINT', 'LINESTRING', 'POLYGON'",
0962                 wkt));
0963         }
0964     }
0965 
0966 private:
0967     template
0968     <
0969         template <typename> class UnaryPred,
0970         typename TokenizerIterator,
0971         typename Geom = typename util::sequence_find_if
0972             <
0973                 typename traits::geometry_types<Geometry>::type, UnaryPred
0974             >::type,
0975         std::enable_if_t<! std::is_void<Geom>::value, int> = 0
0976     >
0977     static bool parse_geometry(const char * ,
0978                                TokenizerIterator& it,
0979                                TokenizerIterator const& end,
0980                                std::string const& wkt,
0981                                Geometry& geometry,
0982                                bool = true)
0983     {
0984         Geom g;
0985         ReadWkt<Geom, typename tag<Geom>::type>::apply(it, end, wkt, g);
0986         AppendPolicy::apply(geometry, g);
0987         return true;
0988     }
0989 
0990     template
0991     <
0992         template <typename> class UnaryPred,
0993         typename TokenizerIterator,
0994         typename Geom = typename util::sequence_find_if
0995             <
0996                 typename traits::geometry_types<Geometry>::type, UnaryPred
0997             >::type,
0998         std::enable_if_t<std::is_void<Geom>::value, int> = 0
0999     >
1000     static bool parse_geometry(const char * name,
1001                                TokenizerIterator& ,
1002                                TokenizerIterator const& ,
1003                                std::string const& wkt,
1004                                Geometry& ,
1005                                bool throw_on_misfit = true)
1006     {
1007         if (throw_on_misfit)
1008         {
1009             std::string msg = std::string("Unable to store '") + name + "' in this geometry";
1010             BOOST_THROW_EXCEPTION(read_wkt_exception(msg, wkt));
1011         }
1012 
1013         return false;
1014     }
1015 };
1016 
1017 
1018 }} // namespace detail::wkt
1019 #endif // DOXYGEN_NO_DETAIL
1020 
1021 #ifndef DOXYGEN_NO_DISPATCH
1022 namespace dispatch
1023 {
1024 
1025 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
1026 struct read_wkt {};
1027 
1028 
1029 template <typename Point>
1030 struct read_wkt<Point, point_tag>
1031     : detail::wkt::geometry_parser
1032         <
1033             Point,
1034             detail::wkt::point_parser,
1035             detail::wkt::prefix_point
1036         >
1037 {};
1038 
1039 
1040 template <typename L>
1041 struct read_wkt<L, linestring_tag>
1042     : detail::wkt::geometry_parser
1043         <
1044             L,
1045             detail::wkt::linestring_parser,
1046             detail::wkt::prefix_linestring
1047         >
1048 {};
1049 
1050 template <typename Ring>
1051 struct read_wkt<Ring, ring_tag>
1052     : detail::wkt::geometry_parser
1053         <
1054             Ring,
1055             detail::wkt::ring_parser,
1056             detail::wkt::prefix_polygon
1057         >
1058 {};
1059 
1060 template <typename Geometry>
1061 struct read_wkt<Geometry, polygon_tag>
1062     : detail::wkt::geometry_parser
1063         <
1064             Geometry,
1065             detail::wkt::polygon_parser,
1066             detail::wkt::prefix_polygon
1067         >
1068 {};
1069 
1070 
1071 template <typename MultiGeometry>
1072 struct read_wkt<MultiGeometry, multi_point_tag>
1073     : detail::wkt::multi_point_parser
1074             <
1075                 MultiGeometry,
1076                 detail::wkt::prefix_multipoint
1077             >
1078 {};
1079 
1080 template <typename MultiGeometry>
1081 struct read_wkt<MultiGeometry, multi_linestring_tag>
1082     : detail::wkt::multi_parser
1083             <
1084                 MultiGeometry,
1085                 detail::wkt::linestring_parser,
1086                 detail::wkt::prefix_multilinestring
1087             >
1088 {};
1089 
1090 template <typename MultiGeometry>
1091 struct read_wkt<MultiGeometry, multi_polygon_tag>
1092     : detail::wkt::multi_parser
1093             <
1094                 MultiGeometry,
1095                 detail::wkt::polygon_parser,
1096                 detail::wkt::prefix_multipolygon
1097             >
1098 {};
1099 
1100 
1101 // Box (Non-OGC)
1102 template <typename Box>
1103 struct read_wkt<Box, box_tag>
1104     : detail::wkt::box_parser<Box>
1105 {};
1106 
1107 // Segment (Non-OGC)
1108 template <typename Segment>
1109 struct read_wkt<Segment, segment_tag>
1110     : detail::wkt::segment_parser<Segment>
1111 {};
1112 
1113 
1114 template <typename DynamicGeometry>
1115 struct read_wkt<DynamicGeometry, dynamic_geometry_tag>
1116 {
1117     static inline void apply(std::string const& wkt, DynamicGeometry& dynamic_geometry)
1118     {
1119         auto tokens{detail::wkt::make_tokenizer(wkt)};
1120         auto it = tokens.begin();
1121         auto const end = tokens.end();
1122         if (it == end)
1123         {
1124             BOOST_THROW_EXCEPTION(read_wkt_exception(
1125                 "Should start with geometry's type, for example 'POINT', 'LINESTRING', 'POLYGON'",
1126                 wkt));
1127         }
1128 
1129         detail::wkt::dynamic_readwkt_caller
1130             <
1131                 DynamicGeometry, dispatch::read_wkt, detail::wkt::dynamic_move_assign
1132             >::apply(it, end, wkt, dynamic_geometry);
1133 
1134         detail::wkt::check_end(it, end, wkt);
1135     }
1136 };
1137 
1138 
1139 template <typename Geometry>
1140 struct read_wkt<Geometry, geometry_collection_tag>
1141 {
1142     static inline void apply(std::string const& wkt, Geometry& geometry)
1143     {
1144         range::clear(geometry);
1145 
1146         auto tokens{detail::wkt::make_tokenizer(wkt)};
1147         auto it = tokens.begin();
1148         auto const end = tokens.end();
1149 
1150         apply(it, end, wkt, geometry);
1151 
1152         detail::wkt::check_end(it, end, wkt);
1153     }
1154 
1155     template <typename TokenizerIterator>
1156     static inline void apply(TokenizerIterator& it,
1157                              TokenizerIterator const& end,
1158                              std::string const& wkt,
1159                              Geometry& geometry)
1160     {
1161         if (detail::wkt::initialize<Geometry>(it, end, wkt,
1162                 detail::wkt::prefix_geometrycollection::apply()))
1163         {
1164             detail::wkt::handle_open_parenthesis(it, end, wkt);
1165 
1166             // Stop at ")"
1167             while (it != end && *it != ")")
1168             {
1169                 detail::wkt::dynamic_readwkt_caller
1170                     <
1171                         Geometry, dispatch::read_wkt, detail::wkt::dynamic_move_emplace_back
1172                     >::apply(it, end, wkt, geometry);
1173 
1174                 if (it != end && *it == ",")
1175                 {
1176                     // Skip "," after geometry is parsed
1177                     ++it;
1178                 }
1179             }
1180 
1181             detail::wkt::handle_close_parenthesis(it, end, wkt);
1182         }
1183     }
1184 };
1185 
1186 
1187 } // namespace dispatch
1188 #endif // DOXYGEN_NO_DISPATCH
1189 
1190 /*!
1191 \brief Parses OGC Well-Known Text (\ref WKT) into a geometry (any geometry)
1192 \ingroup wkt
1193 \tparam Geometry \tparam_geometry
1194 \param wkt string containing \ref WKT
1195 \param geometry \param_geometry output geometry
1196 \ingroup wkt
1197 \qbk{[include reference/io/read_wkt.qbk]}
1198 */
1199 template <typename Geometry>
1200 inline void read_wkt(std::string const& wkt, Geometry& geometry)
1201 {
1202     geometry::concepts::check<Geometry>();
1203     dispatch::read_wkt<Geometry>::apply(wkt, geometry);
1204 }
1205 
1206 /*!
1207 \brief Parses OGC Well-Known Text (\ref WKT) into a geometry (any geometry) and returns it
1208 \ingroup wkt
1209 \tparam Geometry \tparam_geometry
1210 \param wkt string containing \ref WKT
1211 \ingroup wkt
1212 \qbk{[include reference/io/from_wkt.qbk]}
1213 */
1214 template <typename Geometry>
1215 inline Geometry from_wkt(std::string const& wkt)
1216 {
1217     Geometry geometry;
1218     geometry::concepts::check<Geometry>();
1219     dispatch::read_wkt<Geometry>::apply(wkt, geometry);
1220     return geometry;
1221 }
1222 
1223 }} // namespace boost::geometry
1224 
1225 #endif // BOOST_GEOMETRY_IO_WKT_READ_HPP