]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/geometry/io/wkt/read.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / geometry / io / wkt / read.hpp
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>
71 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
87 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
94 virtual ~read_wkt_exception() throw() {}
95
96 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 {
120 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 {
163 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>
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>
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>
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>
223 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
257 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
278 inline stateful_range_appender()
279 : pt_index(0)
280 {}
281
282 // NOTE: Geometry is a reference
283 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:
309 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
330 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 {
367 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 {
382 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 {
395 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
420 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
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
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
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>
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 {
570 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 {
588 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 {
623 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 {
635 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 {
695 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 {
765 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>
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