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