Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 08:43:20

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 = coordinate_type_t<Point>;
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, geometry::point_type_t<Geometry> 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 = geometry::point_type_t<Geometry>;
0276     using size_type = typename boost::range_size<util::remove_cptrref_t<Geometry>>::type;
0277 
0278     BOOST_STATIC_ASSERT((util::is_ring<Geometry>::value));
0279 
0280     inline stateful_range_appender()
0281         : pt_index(0)
0282     {}
0283 
0284     // NOTE: Geometry is a reference
0285     inline void append(Geometry geom, point_type const& point, bool is_next_expected)
0286     {
0287         bool should_append = true;
0288 
0289         if (pt_index == 0)
0290         {
0291             first_point = point;
0292         }
0293         else
0294         {
0295             // NOTE: if there are not enough Points, they're always appended
0296             should_append
0297                 = is_next_expected
0298                 || pt_index < core_detail::closure::minimum_ring_size<open>::value
0299                 || disjoint(point, first_point);
0300         }
0301         ++pt_index;
0302 
0303         if (should_append)
0304         {
0305             geometry::append(geom, point);
0306         }
0307     }
0308 
0309 private:
0310     static inline bool disjoint(point_type const& p1, point_type const& p2)
0311     {
0312         // TODO: pass strategy
0313         using strategy_type = typename strategies::io::services::default_strategy
0314             <
0315                 point_type
0316             >::type;
0317 
0318         return detail::disjoint::disjoint_point_point(p1, p2, strategy_type());
0319     }
0320 
0321     size_type pt_index;
0322     point_type first_point;
0323 };
0324 
0325 // Geometry is a value-type or reference-type
0326 template <typename Geometry>
0327 struct container_appender
0328 {
0329     using point_type = geometry::point_type_t<Geometry>;
0330 
0331     template <typename TokenizerIterator>
0332     static inline void apply(TokenizerIterator& it,
0333                              TokenizerIterator const& end,
0334                              std::string const& wkt,
0335                              Geometry out)
0336     {
0337         handle_open_parenthesis(it, end, wkt);
0338 
0339         stateful_range_appender<Geometry> appender;
0340 
0341         // Parse points until closing parenthesis
0342         while (it != end && *it != ")")
0343         {
0344             point_type point;
0345 
0346             parsing_assigner<point_type>::apply(it, end, point, wkt);
0347 
0348             bool const is_next_expected = it != end && *it == ",";
0349 
0350             appender.append(out, point, is_next_expected);
0351 
0352             if (is_next_expected)
0353             {
0354                 ++it;
0355             }
0356         }
0357 
0358         handle_close_parenthesis(it, end, wkt);
0359     }
0360 };
0361 
0362 /*!
0363 \brief Internal, parses a point from a string like this "(x y)"
0364 \note used for parsing points and multi-points
0365 */
0366 template <typename P>
0367 struct point_parser
0368 {
0369     template <typename TokenizerIterator>
0370     static inline void apply(TokenizerIterator& it,
0371                              TokenizerIterator const& end,
0372                              std::string const& wkt,
0373                              P& point)
0374     {
0375         handle_open_parenthesis(it, end, wkt);
0376         parsing_assigner<P>::apply(it, end, point, wkt);
0377         handle_close_parenthesis(it, end, wkt);
0378     }
0379 };
0380 
0381 
0382 template <typename Geometry>
0383 struct linestring_parser
0384 {
0385     template <typename TokenizerIterator>
0386     static inline void apply(TokenizerIterator& it,
0387                              TokenizerIterator const& end,
0388                              std::string const& wkt,
0389                              Geometry& geometry)
0390     {
0391         container_appender<Geometry&>::apply(it, end, wkt, geometry);
0392     }
0393 };
0394 
0395 
0396 template <typename Ring>
0397 struct ring_parser
0398 {
0399     template <typename TokenizerIterator>
0400     static inline void apply(TokenizerIterator& it,
0401                              TokenizerIterator const& end,
0402                              std::string const& wkt,
0403                              Ring& ring)
0404     {
0405         // A ring should look like polygon((x y,x y,x y...))
0406         // So handle the extra opening/closing parentheses
0407         // and in between parse using the container-inserter
0408         handle_open_parenthesis(it, end, wkt);
0409         container_appender<Ring&>::apply(it, end, wkt, ring);
0410         handle_close_parenthesis(it, end, wkt);
0411     }
0412 };
0413 
0414 
0415 /*!
0416 \brief Internal, parses a polygon from a string like this "((x y,x y),(x y,x y))"
0417 \note used for parsing polygons and multi-polygons
0418 */
0419 template <typename Polygon>
0420 struct polygon_parser
0421 {
0422     using appender = container_appender<ring_return_type_t<Polygon>>;
0423 
0424     template <typename TokenizerIterator>
0425     static inline void apply(TokenizerIterator& it,
0426                              TokenizerIterator const& end,
0427                              std::string const& wkt,
0428                              Polygon& poly)
0429     {
0430 
0431         handle_open_parenthesis(it, end, wkt);
0432 
0433         int n = -1;
0434 
0435         // Stop at ")"
0436         while (it != end && *it != ")")
0437         {
0438             // Parse ring
0439             if (++n == 0)
0440             {
0441                 appender::apply(it, end, wkt, exterior_ring(poly));
0442             }
0443             else
0444             {
0445                 ring_type_t<Polygon> ring;
0446                 appender::apply(it, end, wkt, ring);
0447                 range::push_back(geometry::interior_rings(poly), std::move(ring));
0448             }
0449 
0450             if (it != end && *it == ",")
0451             {
0452                 // Skip "," after ring is parsed
0453                 ++it;
0454             }
0455         }
0456 
0457         handle_close_parenthesis(it, end, wkt);
0458     }
0459 };
0460 
0461 
0462 template <typename TokenizerIterator>
0463 inline bool one_of(TokenizerIterator const& it,
0464                    std::string const& value,
0465                    bool& is_present)
0466 {
0467     if (boost::iequals(*it, value))
0468     {
0469         is_present = true;
0470         return true;
0471     }
0472     return false;
0473 }
0474 
0475 template <typename TokenizerIterator>
0476 inline bool one_of(TokenizerIterator const& it,
0477                    std::string const& value,
0478                    bool& present1,
0479                    bool& present2)
0480 {
0481     if (boost::iequals(*it, value))
0482     {
0483         present1 = true;
0484         present2 = true;
0485         return true;
0486     }
0487     return false;
0488 }
0489 
0490 
0491 template <typename TokenizerIterator>
0492 inline void handle_empty_z_m(TokenizerIterator& it,
0493                              TokenizerIterator const& end,
0494                              bool& has_empty,
0495                              bool& has_z,
0496                              bool& has_m)
0497 {
0498     has_empty = false;
0499     has_z = false;
0500     has_m = false;
0501 
0502     // WKT can optionally have Z and M (measured) values as in
0503     // POINT ZM (1 1 5 60), POINT M (1 1 80), POINT Z (1 1 5)
0504     // GGL supports any of them as coordinate values, but is not aware
0505     // of any Measured value.
0506     while (it != end
0507            && (one_of(it, "M", has_m)
0508                || one_of(it, "Z", has_z)
0509                || one_of(it, "EMPTY", has_empty)
0510                || one_of(it, "MZ", has_m, has_z)
0511                || one_of(it, "ZM", has_z, has_m)
0512                )
0513            )
0514     {
0515         ++it;
0516     }
0517 }
0518 
0519 
0520 template <typename Geometry, typename Tag = geometry::tag_t<Geometry>>
0521 struct dimension
0522     : geometry::dimension<Geometry>
0523 {};
0524 
0525 // TODO: For now assume the dimension of the first type defined for GC
0526 //       This should probably be unified for all algorithms
0527 template <typename Geometry>
0528 struct dimension<Geometry, geometry_collection_tag>
0529     : geometry::dimension
0530         <
0531             typename util::sequence_front
0532                 <
0533                     typename traits::geometry_types<Geometry>::type
0534                 >::type
0535         >
0536 {};
0537 
0538 
0539 /*!
0540 \brief Internal, starts parsing
0541 \param geometry_name string to compare with first token
0542 */
0543 template <typename Geometry, typename TokenizerIterator>
0544 inline bool initialize(TokenizerIterator& it,
0545                        TokenizerIterator const& end,
0546                        std::string const& wkt,
0547                        std::string const& geometry_name)
0548 {
0549     if (it == end || ! boost::iequals(*it++, geometry_name))
0550     {
0551         BOOST_THROW_EXCEPTION(read_wkt_exception(std::string("Should start with '") + geometry_name + "'", wkt));
0552     }
0553 
0554     bool has_empty, has_z, has_m;
0555 
0556     handle_empty_z_m(it, end, has_empty, has_z, has_m);
0557 
0558 // Silence warning C4127: conditional expression is constant
0559 #if defined(_MSC_VER)
0560 #pragma warning(push)
0561 #pragma warning(disable : 4127)
0562 #endif
0563 
0564     if (has_z && dimension<Geometry>::value < 3)
0565     {
0566         BOOST_THROW_EXCEPTION(read_wkt_exception("Z only allowed for 3 or more dimensions", wkt));
0567     }
0568 
0569 #if defined(_MSC_VER)
0570 #pragma warning(pop)
0571 #endif
0572 
0573     if (has_empty)
0574     {
0575         return false;
0576     }
0577     // M is ignored at all.
0578 
0579     return true;
0580 }
0581 
0582 
0583 template <typename Geometry, template<typename> class Parser, typename PrefixPolicy>
0584 struct geometry_parser
0585 {
0586     static inline void apply(std::string const& wkt, Geometry& geometry)
0587     {
0588         geometry::clear(geometry);
0589 
0590         auto const tokens{make_tokenizer(wkt)};
0591         auto it = tokens.begin();
0592         auto const end = tokens.end();
0593 
0594         apply(it, end, wkt, geometry);
0595 
0596         check_end(it, end, wkt);
0597     }
0598 
0599     template <typename TokenizerIterator>
0600     static inline void apply(TokenizerIterator& it,
0601                              TokenizerIterator const& end,
0602                              std::string const& wkt,
0603                              Geometry& geometry)
0604     {
0605         if (initialize<Geometry>(it, end, wkt, PrefixPolicy::apply()))
0606         {
0607             Parser<Geometry>::apply(it, end, wkt, geometry);
0608         }
0609     }
0610 };
0611 
0612 
0613 template <typename MultiGeometry, template<typename> class Parser, typename PrefixPolicy>
0614 struct multi_parser
0615 {
0616     static inline void apply(std::string const& wkt, MultiGeometry& geometry)
0617     {
0618         traits::clear<MultiGeometry>::apply(geometry);
0619 
0620         auto const tokens{make_tokenizer(wkt)};
0621         auto it = tokens.begin();
0622         auto const end = tokens.end();
0623 
0624         apply(it, end, wkt, geometry);
0625 
0626         check_end(it, end, wkt);
0627     }
0628 
0629     template <typename TokenizerIterator>
0630     static inline void apply(TokenizerIterator& it,
0631                              TokenizerIterator const& end,
0632                              std::string const& wkt,
0633                              MultiGeometry& geometry)
0634     {
0635         if (initialize<MultiGeometry>(it, end, wkt, PrefixPolicy::apply()))
0636         {
0637             handle_open_parenthesis(it, end, wkt);
0638 
0639             // Parse sub-geometries
0640             while(it != end && *it != ")")
0641             {
0642                 traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1);
0643                 Parser
0644                     <
0645                         typename boost::range_value<MultiGeometry>::type
0646                     >::apply(it, end, wkt, *(boost::end(geometry) - 1));
0647                 if (it != end && *it == ",")
0648                 {
0649                     // Skip "," after multi-element is parsed
0650                     ++it;
0651                 }
0652             }
0653 
0654             handle_close_parenthesis(it, end, wkt);
0655         }
0656     }
0657 };
0658 
0659 template <typename P>
0660 struct noparenthesis_point_parser
0661 {
0662     template <typename TokenizerIterator>
0663     static inline void apply(TokenizerIterator& it,
0664                              TokenizerIterator const& end,
0665                              std::string const& wkt,
0666                              P& point)
0667     {
0668         parsing_assigner<P>::apply(it, end, point, wkt);
0669     }
0670 };
0671 
0672 template <typename MultiGeometry, typename PrefixPolicy>
0673 struct multi_point_parser
0674 {
0675     static inline void apply(std::string const& wkt, MultiGeometry& geometry)
0676     {
0677         traits::clear<MultiGeometry>::apply(geometry);
0678 
0679         auto const tokens{make_tokenizer(wkt)};
0680         auto it = tokens.begin();
0681         auto const end = tokens.end();
0682 
0683         apply(it, end, wkt, geometry);
0684 
0685         check_end(it, end, wkt);
0686     }
0687 
0688     template <typename TokenizerIterator>
0689     static inline void apply(TokenizerIterator& it,
0690                              TokenizerIterator const& end,
0691                              std::string const& wkt,
0692                              MultiGeometry& geometry)
0693     {
0694         if (initialize<MultiGeometry>(it, end, wkt, PrefixPolicy::apply()))
0695         {
0696             handle_open_parenthesis(it, end, wkt);
0697 
0698             // If first point definition starts with "(" then parse points as (x y)
0699             // otherwise as "x y"
0700             bool using_brackets = (it != end && *it == "(");
0701 
0702             while(it != end && *it != ")")
0703             {
0704                 traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1);
0705 
0706                 if (using_brackets)
0707                 {
0708                     point_parser
0709                         <
0710                             typename boost::range_value<MultiGeometry>::type
0711                         >::apply(it, end, wkt, *(boost::end(geometry) - 1));
0712                 }
0713                 else
0714                 {
0715                     noparenthesis_point_parser
0716                         <
0717                             typename boost::range_value<MultiGeometry>::type
0718                         >::apply(it, end, wkt, *(boost::end(geometry) - 1));
0719                 }
0720 
0721                 if (it != end && *it == ",")
0722                 {
0723                     // Skip "," after point is parsed
0724                     ++it;
0725                 }
0726             }
0727 
0728             handle_close_parenthesis(it, end, wkt);
0729         }
0730     }
0731 };
0732 
0733 
0734 /*!
0735 \brief Supports box parsing
0736 \note OGC does not define the box geometry, and WKT does not support boxes.
0737     However, to be generic GGL supports reading and writing from and to boxes.
0738     Boxes are outputted as a standard POLYGON. GGL can read boxes from
0739     a standard POLYGON, from a POLYGON with 2 points of from a BOX
0740 \tparam Box the box
0741 */
0742 template <typename Box>
0743 struct box_parser
0744 {
0745     static inline void apply(std::string const& wkt, Box& box)
0746     {
0747         auto const tokens{make_tokenizer(wkt)};
0748         auto it = tokens.begin();
0749         auto const end = tokens.end();
0750 
0751         apply(it, end, wkt, box);
0752 
0753         check_end(it, end, wkt);
0754     }
0755 
0756     template <typename TokenizerIterator>
0757     static inline void apply(TokenizerIterator& it,
0758                              TokenizerIterator const& end,
0759                              std::string const& wkt,
0760                              Box& box)
0761     {
0762         bool should_close = false;
0763         if (it != end && boost::iequals(*it, "POLYGON"))
0764         {
0765             ++it;
0766             bool has_empty, has_z, has_m;
0767             handle_empty_z_m(it, end, has_empty, has_z, has_m);
0768             if (has_empty)
0769             {
0770                 assign_zero(box);
0771                 return;
0772             }
0773             handle_open_parenthesis(it, end, wkt);
0774             should_close = true;
0775         }
0776         else if (it != end && boost::iequals(*it, "BOX"))
0777         {
0778             ++it;
0779         }
0780         else
0781         {
0782             BOOST_THROW_EXCEPTION(read_wkt_exception("Should start with 'POLYGON' or 'BOX'", wkt));
0783         }
0784 
0785         using point_type = point_type_t<Box>;
0786         std::vector<point_type> points;
0787         container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points));
0788 
0789         if (should_close)
0790         {
0791             handle_close_parenthesis(it, end, wkt);
0792         }
0793 
0794         unsigned int index = 0;
0795         std::size_t n = boost::size(points);
0796         if (n == 2)
0797         {
0798             index = 1;
0799         }
0800         else if (n == 4 || n == 5)
0801         {
0802             // In case of 4 or 5 points, we do not check the other ones, just
0803             // take the opposite corner which is always 2
0804             index = 2;
0805         }
0806         else
0807         {
0808             BOOST_THROW_EXCEPTION(read_wkt_exception("Box should have 2,4 or 5 points", wkt));
0809         }
0810 
0811         geometry::detail::assign_point_to_index<min_corner>(points.front(), box);
0812         geometry::detail::assign_point_to_index<max_corner>(points[index], box);
0813     }
0814 };
0815 
0816 
0817 /*!
0818 \brief Supports segment parsing
0819 \note OGC does not define the segment, and WKT does not support segmentes.
0820     However, it is useful to implement it, also for testing purposes
0821 \tparam Segment the segment
0822 */
0823 template <typename Segment>
0824 struct segment_parser
0825 {
0826     static inline void apply(std::string const& wkt, Segment& segment)
0827     {
0828         auto const tokens{make_tokenizer(wkt)};
0829         auto it = tokens.begin();
0830         auto const end = tokens.end();
0831 
0832         apply(it, end, wkt, segment);
0833 
0834         check_end(it, end, wkt);
0835     }
0836 
0837     template <typename TokenizerIterator>
0838     static inline void apply(TokenizerIterator& it,
0839                              TokenizerIterator const& end,
0840                              std::string const& wkt,
0841                              Segment& segment)
0842     {
0843         if (it != end
0844             && (boost::iequals(*it, prefix_segment::apply())
0845                 || boost::iequals(*it, prefix_linestring::apply())))
0846         {
0847             ++it;
0848         }
0849         else
0850         {
0851             BOOST_THROW_EXCEPTION(read_wkt_exception("Should start with 'LINESTRING' or 'SEGMENT'", wkt));
0852         }
0853 
0854         using point_type = point_type_t<Segment>;
0855         std::vector<point_type> points;
0856         container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points));
0857 
0858         if (boost::size(points) == 2)
0859         {
0860             geometry::detail::assign_point_to_index<0>(points.front(), segment);
0861             geometry::detail::assign_point_to_index<1>(points.back(), segment);
0862         }
0863         else
0864         {
0865             BOOST_THROW_EXCEPTION(read_wkt_exception("Segment should have 2 points", wkt));
0866         }
0867     }
0868 };
0869 
0870 
0871 struct dynamic_move_assign
0872 {
0873     template <typename DynamicGeometry, typename Geometry>
0874     static void apply(DynamicGeometry& dynamic_geometry, Geometry & geometry)
0875     {
0876         dynamic_geometry = std::move(geometry);
0877     }
0878 };
0879 
0880 struct dynamic_move_emplace_back
0881 {
0882     template <typename GeometryCollection, typename Geometry>
0883     static void apply(GeometryCollection& geometry_collection, Geometry & geometry)
0884     {
0885         traits::emplace_back<GeometryCollection>::apply(geometry_collection, std::move(geometry));
0886     }
0887 };
0888 
0889 template
0890 <
0891     typename Geometry,
0892     template <typename, typename> class ReadWkt,
0893     typename AppendPolicy
0894 >
0895 struct dynamic_readwkt_caller
0896 {
0897     template <typename TokenizerIterator>
0898     static inline void apply(TokenizerIterator& it,
0899                              TokenizerIterator const& end,
0900                              std::string const& wkt,
0901                              Geometry& geometry)
0902     {
0903         static const char* tag_point = prefix_point::apply();
0904         static const char* tag_linestring = prefix_linestring::apply();
0905         static const char* tag_polygon = prefix_polygon::apply();
0906 
0907         static const char* tag_multi_point = prefix_multipoint::apply();
0908         static const char* tag_multi_linestring = prefix_multilinestring::apply();
0909         static const char* tag_multi_polygon = prefix_multipolygon::apply();
0910 
0911         static const char* tag_segment = prefix_segment::apply();
0912         static const char* tag_box = prefix_box::apply();
0913         static const char* tag_gc = prefix_geometrycollection::apply();
0914 
0915         if (boost::iequals(*it, tag_point))
0916         {
0917             parse_geometry<util::is_point>(tag_point, it, end, wkt, geometry);
0918         }
0919         else if (boost::iequals(*it, tag_multi_point))
0920         {
0921             parse_geometry<util::is_multi_point>(tag_multi_point, it, end, wkt, geometry);
0922         }
0923         else if (boost::iequals(*it, tag_segment))
0924         {
0925             parse_geometry<util::is_segment>(tag_segment, it, end, wkt, geometry);
0926         }
0927         else if (boost::iequals(*it, tag_linestring))
0928         {
0929             parse_geometry<util::is_linestring>(tag_linestring, it, end, wkt, geometry, false)
0930             || parse_geometry<util::is_segment>(tag_linestring, it, end, wkt, geometry);
0931         }
0932         else if (boost::iequals(*it, tag_multi_linestring))
0933         {
0934             parse_geometry<util::is_multi_linestring>(tag_multi_linestring, it, end, wkt, geometry);
0935         }
0936         else if (boost::iequals(*it, tag_box))
0937         {
0938             parse_geometry<util::is_box>(tag_box, it, end, wkt, geometry);
0939         }
0940         else if (boost::iequals(*it, tag_polygon))
0941         {
0942             parse_geometry<util::is_polygon>(tag_polygon, it, end, wkt, geometry, false)
0943             || parse_geometry<util::is_ring>(tag_polygon, it, end, wkt, geometry, false)
0944             || parse_geometry<util::is_box>(tag_polygon, it, end, wkt, geometry);
0945         }
0946         else if (boost::iequals(*it, tag_multi_polygon))
0947         {
0948             parse_geometry<util::is_multi_polygon>(tag_multi_polygon, it, end, wkt, geometry);
0949         }
0950         else if (boost::iequals(*it, tag_gc))
0951         {
0952             parse_geometry<util::is_geometry_collection>(tag_gc, it, end, wkt, geometry);
0953         }
0954         else
0955         {
0956             BOOST_THROW_EXCEPTION(read_wkt_exception(
0957                 "Should start with geometry's type, for example 'POINT', 'LINESTRING', 'POLYGON'",
0958                 wkt));
0959         }
0960     }
0961 
0962 private:
0963     template
0964     <
0965         template <typename> class UnaryPred,
0966         typename TokenizerIterator,
0967         typename Geom = typename util::sequence_find_if
0968             <
0969                 typename traits::geometry_types<Geometry>::type, UnaryPred
0970             >::type,
0971         std::enable_if_t<! std::is_void<Geom>::value, int> = 0
0972     >
0973     static bool parse_geometry(const char * ,
0974                                TokenizerIterator& it,
0975                                TokenizerIterator const& end,
0976                                std::string const& wkt,
0977                                Geometry& geometry,
0978                                bool = true)
0979     {
0980         Geom g;
0981         ReadWkt<Geom, tag_t<Geom>>::apply(it, end, wkt, g);
0982         AppendPolicy::apply(geometry, g);
0983         return true;
0984     }
0985 
0986     template
0987     <
0988         template <typename> class UnaryPred,
0989         typename TokenizerIterator,
0990         typename Geom = typename util::sequence_find_if
0991             <
0992                 typename traits::geometry_types<Geometry>::type, UnaryPred
0993             >::type,
0994         std::enable_if_t<std::is_void<Geom>::value, int> = 0
0995     >
0996     static bool parse_geometry(const char * name,
0997                                TokenizerIterator& ,
0998                                TokenizerIterator const& ,
0999                                std::string const& wkt,
1000                                Geometry& ,
1001                                bool throw_on_misfit = true)
1002     {
1003         if (throw_on_misfit)
1004         {
1005             std::string msg = std::string("Unable to store '") + name + "' in this geometry";
1006             BOOST_THROW_EXCEPTION(read_wkt_exception(msg, wkt));
1007         }
1008 
1009         return false;
1010     }
1011 };
1012 
1013 
1014 }} // namespace detail::wkt
1015 #endif // DOXYGEN_NO_DETAIL
1016 
1017 #ifndef DOXYGEN_NO_DISPATCH
1018 namespace dispatch
1019 {
1020 
1021 template <typename Geometry, typename Tag = tag_t<Geometry>>
1022 struct read_wkt {};
1023 
1024 
1025 template <typename Point>
1026 struct read_wkt<Point, point_tag>
1027     : detail::wkt::geometry_parser
1028         <
1029             Point,
1030             detail::wkt::point_parser,
1031             detail::wkt::prefix_point
1032         >
1033 {};
1034 
1035 
1036 template <typename L>
1037 struct read_wkt<L, linestring_tag>
1038     : detail::wkt::geometry_parser
1039         <
1040             L,
1041             detail::wkt::linestring_parser,
1042             detail::wkt::prefix_linestring
1043         >
1044 {};
1045 
1046 template <typename Ring>
1047 struct read_wkt<Ring, ring_tag>
1048     : detail::wkt::geometry_parser
1049         <
1050             Ring,
1051             detail::wkt::ring_parser,
1052             detail::wkt::prefix_polygon
1053         >
1054 {};
1055 
1056 template <typename Geometry>
1057 struct read_wkt<Geometry, polygon_tag>
1058     : detail::wkt::geometry_parser
1059         <
1060             Geometry,
1061             detail::wkt::polygon_parser,
1062             detail::wkt::prefix_polygon
1063         >
1064 {};
1065 
1066 
1067 template <typename MultiGeometry>
1068 struct read_wkt<MultiGeometry, multi_point_tag>
1069     : detail::wkt::multi_point_parser
1070             <
1071                 MultiGeometry,
1072                 detail::wkt::prefix_multipoint
1073             >
1074 {};
1075 
1076 template <typename MultiGeometry>
1077 struct read_wkt<MultiGeometry, multi_linestring_tag>
1078     : detail::wkt::multi_parser
1079             <
1080                 MultiGeometry,
1081                 detail::wkt::linestring_parser,
1082                 detail::wkt::prefix_multilinestring
1083             >
1084 {};
1085 
1086 template <typename MultiGeometry>
1087 struct read_wkt<MultiGeometry, multi_polygon_tag>
1088     : detail::wkt::multi_parser
1089             <
1090                 MultiGeometry,
1091                 detail::wkt::polygon_parser,
1092                 detail::wkt::prefix_multipolygon
1093             >
1094 {};
1095 
1096 
1097 // Box (Non-OGC)
1098 template <typename Box>
1099 struct read_wkt<Box, box_tag>
1100     : detail::wkt::box_parser<Box>
1101 {};
1102 
1103 // Segment (Non-OGC)
1104 template <typename Segment>
1105 struct read_wkt<Segment, segment_tag>
1106     : detail::wkt::segment_parser<Segment>
1107 {};
1108 
1109 
1110 template <typename DynamicGeometry>
1111 struct read_wkt<DynamicGeometry, dynamic_geometry_tag>
1112 {
1113     static inline void apply(std::string const& wkt, DynamicGeometry& dynamic_geometry)
1114     {
1115         auto tokens{detail::wkt::make_tokenizer(wkt)};
1116         auto it = tokens.begin();
1117         auto const end = tokens.end();
1118         if (it == end)
1119         {
1120             BOOST_THROW_EXCEPTION(read_wkt_exception(
1121                 "Should start with geometry's type, for example 'POINT', 'LINESTRING', 'POLYGON'",
1122                 wkt));
1123         }
1124 
1125         detail::wkt::dynamic_readwkt_caller
1126             <
1127                 DynamicGeometry, dispatch::read_wkt, detail::wkt::dynamic_move_assign
1128             >::apply(it, end, wkt, dynamic_geometry);
1129 
1130         detail::wkt::check_end(it, end, wkt);
1131     }
1132 };
1133 
1134 
1135 template <typename Geometry>
1136 struct read_wkt<Geometry, geometry_collection_tag>
1137 {
1138     static inline void apply(std::string const& wkt, Geometry& geometry)
1139     {
1140         range::clear(geometry);
1141 
1142         auto tokens{detail::wkt::make_tokenizer(wkt)};
1143         auto it = tokens.begin();
1144         auto const end = tokens.end();
1145 
1146         apply(it, end, wkt, geometry);
1147 
1148         detail::wkt::check_end(it, end, wkt);
1149     }
1150 
1151     template <typename TokenizerIterator>
1152     static inline void apply(TokenizerIterator& it,
1153                              TokenizerIterator const& end,
1154                              std::string const& wkt,
1155                              Geometry& geometry)
1156     {
1157         if (detail::wkt::initialize<Geometry>(it, end, wkt,
1158                 detail::wkt::prefix_geometrycollection::apply()))
1159         {
1160             detail::wkt::handle_open_parenthesis(it, end, wkt);
1161 
1162             // Stop at ")"
1163             while (it != end && *it != ")")
1164             {
1165                 detail::wkt::dynamic_readwkt_caller
1166                     <
1167                         Geometry, dispatch::read_wkt, detail::wkt::dynamic_move_emplace_back
1168                     >::apply(it, end, wkt, geometry);
1169 
1170                 if (it != end && *it == ",")
1171                 {
1172                     // Skip "," after geometry is parsed
1173                     ++it;
1174                 }
1175             }
1176 
1177             detail::wkt::handle_close_parenthesis(it, end, wkt);
1178         }
1179     }
1180 };
1181 
1182 
1183 } // namespace dispatch
1184 #endif // DOXYGEN_NO_DISPATCH
1185 
1186 /*!
1187 \brief Parses OGC \well_known_text (\wkt) into a geometry (any geometry)
1188 \ingroup wkt
1189 \tparam Geometry \tparam_geometry
1190 \param wkt string containing \wkt
1191 \param geometry \param_geometry output geometry
1192 \ingroup wkt
1193 \qbk{[include reference/io/read_wkt.qbk]}
1194 */
1195 template <typename Geometry>
1196 inline void read_wkt(std::string const& wkt, Geometry& geometry)
1197 {
1198     geometry::concepts::check<Geometry>();
1199     dispatch::read_wkt<Geometry>::apply(wkt, geometry);
1200 }
1201 
1202 /*!
1203 \brief Parses OGC \well_known_text (\wkt) into a geometry (any geometry) and returns it
1204 \ingroup wkt
1205 \tparam Geometry \tparam_geometry
1206 \param wkt string containing \wkt
1207 \ingroup wkt
1208 \qbk{[include reference/io/from_wkt.qbk]}
1209 */
1210 template <typename Geometry>
1211 inline Geometry from_wkt(std::string const& wkt)
1212 {
1213     Geometry geometry;
1214     geometry::concepts::check<Geometry>();
1215     dispatch::read_wkt<Geometry>::apply(wkt, geometry);
1216     return geometry;
1217 }
1218 
1219 }} // namespace boost::geometry
1220 
1221 #endif // BOOST_GEOMETRY_IO_WKT_READ_HPP