• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, 2018.
9 // Modifications copyright (c) 2014-2018 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/disjoint/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                 || disjoint(point, first_point);
299         }
300         ++pt_index;
301 
302         if (should_append)
303         {
304             geometry::append(geom, point);
305         }
306     }
307 
308 private:
disjointboost::geometry::detail::wkt::stateful_range_appender309     static inline bool disjoint(point_type const& p1, point_type const& p2)
310     {
311         // TODO: pass strategy
312         typedef typename strategy::disjoint::services::default_strategy
313             <
314                 point_type, point_type
315             >::type strategy_type;
316 
317         return detail::disjoint::disjoint_point_point(p1, p2, strategy_type());
318     }
319 
320     size_type pt_index;
321     point_type first_point;
322 };
323 
324 // Geometry is a value-type or reference-type
325 template <typename Geometry>
326 struct container_appender
327 {
328     typedef typename geometry::point_type<Geometry>::type point_type;
329 
applyboost::geometry::detail::wkt::container_appender330     static inline void apply(tokenizer::iterator& it,
331                              tokenizer::iterator const& end,
332                              std::string const& wkt,
333                              Geometry out)
334     {
335         handle_open_parenthesis(it, end, wkt);
336 
337         stateful_range_appender<Geometry> appender;
338 
339         // Parse points until closing parenthesis
340         while (it != end && *it != ")")
341         {
342             point_type point;
343 
344             parsing_assigner<point_type>::apply(it, end, point, wkt);
345 
346             bool const is_next_expected = it != end && *it == ",";
347 
348             appender.append(out, point, is_next_expected);
349 
350             if (is_next_expected)
351             {
352                 ++it;
353             }
354         }
355 
356         handle_close_parenthesis(it, end, wkt);
357     }
358 };
359 
360 /*!
361 \brief Internal, parses a point from a string like this "(x y)"
362 \note used for parsing points and multi-points
363 */
364 template <typename P>
365 struct point_parser
366 {
applyboost::geometry::detail::wkt::point_parser367     static inline void apply(tokenizer::iterator& it,
368                              tokenizer::iterator const& end,
369                              std::string const& wkt,
370                              P& point)
371     {
372         handle_open_parenthesis(it, end, wkt);
373         parsing_assigner<P>::apply(it, end, point, wkt);
374         handle_close_parenthesis(it, end, wkt);
375     }
376 };
377 
378 
379 template <typename Geometry>
380 struct linestring_parser
381 {
applyboost::geometry::detail::wkt::linestring_parser382     static inline void apply(tokenizer::iterator& it,
383                              tokenizer::iterator const& end,
384                              std::string const& wkt,
385                              Geometry& geometry)
386     {
387         container_appender<Geometry&>::apply(it, end, wkt, geometry);
388     }
389 };
390 
391 
392 template <typename Ring>
393 struct ring_parser
394 {
applyboost::geometry::detail::wkt::ring_parser395     static inline void apply(tokenizer::iterator& it,
396                              tokenizer::iterator const& end,
397                              std::string const& wkt,
398                              Ring& ring)
399     {
400         // A ring should look like polygon((x y,x y,x y...))
401         // So handle the extra opening/closing parentheses
402         // and in between parse using the container-inserter
403         handle_open_parenthesis(it, end, wkt);
404         container_appender<Ring&>::apply(it, end, wkt, ring);
405         handle_close_parenthesis(it, end, wkt);
406     }
407 };
408 
409 
410 /*!
411 \brief Internal, parses a polygon from a string like this "((x y,x y),(x y,x y))"
412 \note used for parsing polygons and multi-polygons
413 */
414 template <typename Polygon>
415 struct polygon_parser
416 {
417     typedef typename ring_return_type<Polygon>::type ring_return_type;
418     typedef container_appender<ring_return_type> appender;
419 
applyboost::geometry::detail::wkt::polygon_parser420     static inline void apply(tokenizer::iterator& it,
421                              tokenizer::iterator const& end,
422                              std::string const& wkt,
423                              Polygon& poly)
424     {
425 
426         handle_open_parenthesis(it, end, wkt);
427 
428         int n = -1;
429 
430         // Stop at ")"
431         while (it != end && *it != ")")
432         {
433             // Parse ring
434             if (++n == 0)
435             {
436                 appender::apply(it, end, wkt, exterior_ring(poly));
437             }
438             else
439             {
440                 typename ring_type<Polygon>::type ring;
441                 appender::apply(it, end, wkt, ring);
442                 traits::push_back
443                     <
444                         typename boost::remove_reference
445                         <
446                             typename traits::interior_mutable_type<Polygon>::type
447                         >::type
448                     >::apply(interior_rings(poly), ring);
449             }
450 
451             if (it != end && *it == ",")
452             {
453                 // Skip "," after ring is parsed
454                 ++it;
455             }
456         }
457 
458         handle_close_parenthesis(it, end, wkt);
459     }
460 };
461 
462 
one_of(tokenizer::iterator const & it,std::string const & value,bool & is_present)463 inline bool one_of(tokenizer::iterator const& it,
464                    std::string const& value,
465                    bool& is_present)
466 {
467     if (boost::iequals(*it, value))
468     {
469         is_present = true;
470         return true;
471     }
472     return false;
473 }
474 
one_of(tokenizer::iterator const & it,std::string const & value,bool & present1,bool & present2)475 inline bool one_of(tokenizer::iterator const& it,
476                    std::string const& value,
477                    bool& present1,
478                    bool& present2)
479 {
480     if (boost::iequals(*it, value))
481     {
482         present1 = true;
483         present2 = true;
484         return true;
485     }
486     return false;
487 }
488 
489 
handle_empty_z_m(tokenizer::iterator & it,tokenizer::iterator const & end,bool & has_empty,bool & has_z,bool & has_m)490 inline void handle_empty_z_m(tokenizer::iterator& it,
491                              tokenizer::iterator const& end,
492                              bool& has_empty,
493                              bool& has_z,
494                              bool& has_m)
495 {
496     has_empty = false;
497     has_z = false;
498     has_m = false;
499 
500     // WKT can optionally have Z and M (measured) values as in
501     // POINT ZM (1 1 5 60), POINT M (1 1 80), POINT Z (1 1 5)
502     // GGL supports any of them as coordinate values, but is not aware
503     // of any Measured value.
504     while (it != end
505            && (one_of(it, "M", has_m)
506                || one_of(it, "Z", has_z)
507                || one_of(it, "EMPTY", has_empty)
508                || one_of(it, "MZ", has_m, has_z)
509                || one_of(it, "ZM", has_z, has_m)
510                )
511            )
512     {
513         ++it;
514     }
515 }
516 
517 /*!
518 \brief Internal, starts parsing
519 \param tokens boost tokens, parsed with separator " " and keeping separator "()"
520 \param geometry string to compare with first token
521 */
522 template <typename Geometry>
initialize(tokenizer const & tokens,std::string const & geometry_name,std::string const & wkt,tokenizer::iterator & it,tokenizer::iterator & end)523 inline bool initialize(tokenizer const& tokens,
524                        std::string const& geometry_name,
525                        std::string const& wkt,
526                        tokenizer::iterator& it,
527                        tokenizer::iterator& end)
528 {
529     it = tokens.begin();
530     end = tokens.end();
531 
532     if (it == end || ! boost::iequals(*it++, geometry_name))
533     {
534         BOOST_THROW_EXCEPTION(read_wkt_exception(std::string("Should start with '") + geometry_name + "'", wkt));
535     }
536 
537     bool has_empty, has_z, has_m;
538 
539     handle_empty_z_m(it, end, has_empty, has_z, has_m);
540 
541 // Silence warning C4127: conditional expression is constant
542 #if defined(_MSC_VER)
543 #pragma warning(push)
544 #pragma warning(disable : 4127)
545 #endif
546 
547     if (has_z && dimension<Geometry>::type::value < 3)
548     {
549         BOOST_THROW_EXCEPTION(read_wkt_exception("Z only allowed for 3 or more dimensions", wkt));
550     }
551 
552 #if defined(_MSC_VER)
553 #pragma warning(pop)
554 #endif
555 
556     if (has_empty)
557     {
558         check_end(it, end, wkt);
559         return false;
560     }
561     // M is ignored at all.
562 
563     return true;
564 }
565 
566 
567 template <typename Geometry, template<typename> class Parser, typename PrefixPolicy>
568 struct geometry_parser
569 {
applyboost::geometry::detail::wkt::geometry_parser570     static inline void apply(std::string const& wkt, Geometry& geometry)
571     {
572         geometry::clear(geometry);
573 
574         tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
575         tokenizer::iterator it, end;
576         if (initialize<Geometry>(tokens, PrefixPolicy::apply(), wkt, it, end))
577         {
578             Parser<Geometry>::apply(it, end, wkt, geometry);
579             check_end(it, end, wkt);
580         }
581     }
582 };
583 
584 
585 template <typename MultiGeometry, template<typename> class Parser, typename PrefixPolicy>
586 struct multi_parser
587 {
applyboost::geometry::detail::wkt::multi_parser588     static inline void apply(std::string const& wkt, MultiGeometry& geometry)
589     {
590         traits::clear<MultiGeometry>::apply(geometry);
591 
592         tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
593         tokenizer::iterator it, end;
594         if (initialize<MultiGeometry>(tokens, PrefixPolicy::apply(), wkt, it, end))
595         {
596             handle_open_parenthesis(it, end, wkt);
597 
598             // Parse sub-geometries
599             while(it != end && *it != ")")
600             {
601                 traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1);
602                 Parser
603                     <
604                         typename boost::range_value<MultiGeometry>::type
605                     >::apply(it, end, wkt, *(boost::end(geometry) - 1));
606                 if (it != end && *it == ",")
607                 {
608                     // Skip "," after multi-element is parsed
609                     ++it;
610                 }
611             }
612 
613             handle_close_parenthesis(it, end, wkt);
614         }
615 
616         check_end(it, end, wkt);
617     }
618 };
619 
620 template <typename P>
621 struct noparenthesis_point_parser
622 {
applyboost::geometry::detail::wkt::noparenthesis_point_parser623     static inline void apply(tokenizer::iterator& it,
624                              tokenizer::iterator const& end,
625                              std::string const& wkt,
626                              P& point)
627     {
628         parsing_assigner<P>::apply(it, end, point, wkt);
629     }
630 };
631 
632 template <typename MultiGeometry, typename PrefixPolicy>
633 struct multi_point_parser
634 {
applyboost::geometry::detail::wkt::multi_point_parser635     static inline void apply(std::string const& wkt, MultiGeometry& geometry)
636     {
637         traits::clear<MultiGeometry>::apply(geometry);
638 
639         tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
640         tokenizer::iterator it, end;
641 
642         if (initialize<MultiGeometry>(tokens, PrefixPolicy::apply(), wkt, it, end))
643         {
644             handle_open_parenthesis(it, end, wkt);
645 
646             // If first point definition starts with "(" then parse points as (x y)
647             // otherwise as "x y"
648             bool using_brackets = (it != end && *it == "(");
649 
650             while(it != end && *it != ")")
651             {
652                 traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1);
653 
654                 if (using_brackets)
655                 {
656                     point_parser
657                         <
658                             typename boost::range_value<MultiGeometry>::type
659                         >::apply(it, end, wkt, *(boost::end(geometry) - 1));
660                 }
661                 else
662                 {
663                     noparenthesis_point_parser
664                         <
665                             typename boost::range_value<MultiGeometry>::type
666                         >::apply(it, end, wkt, *(boost::end(geometry) - 1));
667                 }
668 
669                 if (it != end && *it == ",")
670                 {
671                     // Skip "," after point is parsed
672                     ++it;
673                 }
674             }
675 
676             handle_close_parenthesis(it, end, wkt);
677         }
678 
679         check_end(it, end, wkt);
680     }
681 };
682 
683 
684 /*!
685 \brief Supports box parsing
686 \note OGC does not define the box geometry, and WKT does not support boxes.
687     However, to be generic GGL supports reading and writing from and to boxes.
688     Boxes are outputted as a standard POLYGON. GGL can read boxes from
689     a standard POLYGON, from a POLYGON with 2 points of from a BOX
690 \tparam Box the box
691 */
692 template <typename Box>
693 struct box_parser
694 {
applyboost::geometry::detail::wkt::box_parser695     static inline void apply(std::string const& wkt, Box& box)
696     {
697         bool should_close = false;
698         tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
699         tokenizer::iterator it = tokens.begin();
700         tokenizer::iterator end = tokens.end();
701         if (it != end && boost::iequals(*it, "POLYGON"))
702         {
703             ++it;
704             bool has_empty, has_z, has_m;
705             handle_empty_z_m(it, end, has_empty, has_z, has_m);
706             if (has_empty)
707             {
708                 assign_zero(box);
709                 return;
710             }
711             handle_open_parenthesis(it, end, wkt);
712             should_close = true;
713         }
714         else if (it != end && boost::iequals(*it, "BOX"))
715         {
716             ++it;
717         }
718         else
719         {
720             BOOST_THROW_EXCEPTION(read_wkt_exception("Should start with 'POLYGON' or 'BOX'", wkt));
721         }
722 
723         typedef typename point_type<Box>::type point_type;
724         std::vector<point_type> points;
725         container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points));
726 
727         if (should_close)
728         {
729             handle_close_parenthesis(it, end, wkt);
730         }
731         check_end(it, end, wkt);
732 
733         unsigned int index = 0;
734         std::size_t n = boost::size(points);
735         if (n == 2)
736         {
737             index = 1;
738         }
739         else if (n == 4 || n == 5)
740         {
741             // In case of 4 or 5 points, we do not check the other ones, just
742             // take the opposite corner which is always 2
743             index = 2;
744         }
745         else
746         {
747             BOOST_THROW_EXCEPTION(read_wkt_exception("Box should have 2,4 or 5 points", wkt));
748         }
749 
750         geometry::detail::assign_point_to_index<min_corner>(points.front(), box);
751         geometry::detail::assign_point_to_index<max_corner>(points[index], box);
752     }
753 };
754 
755 
756 /*!
757 \brief Supports segment parsing
758 \note OGC does not define the segment, and WKT does not support segmentes.
759     However, it is useful to implement it, also for testing purposes
760 \tparam Segment the segment
761 */
762 template <typename Segment>
763 struct segment_parser
764 {
applyboost::geometry::detail::wkt::segment_parser765     static inline void apply(std::string const& wkt, Segment& segment)
766     {
767         tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
768         tokenizer::iterator it = tokens.begin();
769         tokenizer::iterator end = tokens.end();
770         if (it != end &&
771             (boost::iequals(*it, "SEGMENT")
772             || boost::iequals(*it, "LINESTRING") ))
773         {
774             ++it;
775         }
776         else
777         {
778             BOOST_THROW_EXCEPTION(read_wkt_exception("Should start with 'LINESTRING' or 'SEGMENT'", wkt));
779         }
780 
781         typedef typename point_type<Segment>::type point_type;
782         std::vector<point_type> points;
783         container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points));
784 
785         check_end(it, end, wkt);
786 
787         if (boost::size(points) == 2)
788         {
789             geometry::detail::assign_point_to_index<0>(points.front(), segment);
790             geometry::detail::assign_point_to_index<1>(points.back(), segment);
791         }
792         else
793         {
794             BOOST_THROW_EXCEPTION(read_wkt_exception("Segment should have 2 points", wkt));
795         }
796 
797     }
798 };
799 
800 
801 }} // namespace detail::wkt
802 #endif // DOXYGEN_NO_DETAIL
803 
804 #ifndef DOXYGEN_NO_DISPATCH
805 namespace dispatch
806 {
807 
808 template <typename Tag, typename Geometry>
809 struct read_wkt {};
810 
811 
812 template <typename Point>
813 struct read_wkt<point_tag, Point>
814     : detail::wkt::geometry_parser
815         <
816             Point,
817             detail::wkt::point_parser,
818             detail::wkt::prefix_point
819         >
820 {};
821 
822 
823 template <typename L>
824 struct read_wkt<linestring_tag, L>
825     : detail::wkt::geometry_parser
826         <
827             L,
828             detail::wkt::linestring_parser,
829             detail::wkt::prefix_linestring
830         >
831 {};
832 
833 template <typename Ring>
834 struct read_wkt<ring_tag, Ring>
835     : detail::wkt::geometry_parser
836         <
837             Ring,
838             detail::wkt::ring_parser,
839             detail::wkt::prefix_polygon
840         >
841 {};
842 
843 template <typename Geometry>
844 struct read_wkt<polygon_tag, Geometry>
845     : detail::wkt::geometry_parser
846         <
847             Geometry,
848             detail::wkt::polygon_parser,
849             detail::wkt::prefix_polygon
850         >
851 {};
852 
853 
854 template <typename MultiGeometry>
855 struct read_wkt<multi_point_tag, MultiGeometry>
856     : detail::wkt::multi_point_parser
857             <
858                 MultiGeometry,
859                 detail::wkt::prefix_multipoint
860             >
861 {};
862 
863 template <typename MultiGeometry>
864 struct read_wkt<multi_linestring_tag, MultiGeometry>
865     : detail::wkt::multi_parser
866             <
867                 MultiGeometry,
868                 detail::wkt::linestring_parser,
869                 detail::wkt::prefix_multilinestring
870             >
871 {};
872 
873 template <typename MultiGeometry>
874 struct read_wkt<multi_polygon_tag, MultiGeometry>
875     : detail::wkt::multi_parser
876             <
877                 MultiGeometry,
878                 detail::wkt::polygon_parser,
879                 detail::wkt::prefix_multipolygon
880             >
881 {};
882 
883 
884 // Box (Non-OGC)
885 template <typename Box>
886 struct read_wkt<box_tag, Box>
887     : detail::wkt::box_parser<Box>
888 {};
889 
890 // Segment (Non-OGC)
891 template <typename Segment>
892 struct read_wkt<segment_tag, Segment>
893     : detail::wkt::segment_parser<Segment>
894 {};
895 
896 
897 } // namespace dispatch
898 #endif // DOXYGEN_NO_DISPATCH
899 
900 /*!
901 \brief Parses OGC Well-Known Text (\ref WKT) into a geometry (any geometry)
902 \ingroup wkt
903 \tparam Geometry \tparam_geometry
904 \param wkt string containing \ref WKT
905 \param geometry \param_geometry output geometry
906 \ingroup wkt
907 \qbk{[include reference/io/read_wkt.qbk]}
908 */
909 template <typename Geometry>
read_wkt(std::string const & wkt,Geometry & geometry)910 inline void read_wkt(std::string const& wkt, Geometry& geometry)
911 {
912     geometry::concepts::check<Geometry>();
913     dispatch::read_wkt<typename tag<Geometry>::type, Geometry>::apply(wkt, geometry);
914 }
915 
916 }} // namespace boost::geometry
917 
918 #endif // BOOST_GEOMETRY_IO_WKT_READ_HPP
919