]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/geometry/io/wkt/read.hpp
update sources to v12.2.3
[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.
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>
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 || !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
319 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 {
356 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 {
371 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 {
384 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
409 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
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
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
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>
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 {
557 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 {
575 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 {
610 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 {
622 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 {
682 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 {
752 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>
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