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