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