File indexing completed on 2026-08-09 08:46:02
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020 #ifndef BOOST_GEOMETRY_IO_WKT_READ_HPP
0021 #define BOOST_GEOMETRY_IO_WKT_READ_HPP
0022
0023 #include <cstddef>
0024 #include <string>
0025
0026 #include <boost/algorithm/string/predicate.hpp>
0027 #include <boost/lexical_cast.hpp>
0028 #include <boost/range/begin.hpp>
0029 #include <boost/range/end.hpp>
0030 #include <boost/range/size.hpp>
0031 #include <boost/range/value_type.hpp>
0032 #include <boost/tokenizer.hpp>
0033 #include <boost/throw_exception.hpp>
0034
0035 #include <boost/geometry/algorithms/assign.hpp>
0036 #include <boost/geometry/algorithms/append.hpp>
0037 #include <boost/geometry/algorithms/clear.hpp>
0038 #include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
0039
0040 #include <boost/geometry/core/access.hpp>
0041 #include <boost/geometry/core/coordinate_dimension.hpp>
0042 #include <boost/geometry/core/exception.hpp>
0043 #include <boost/geometry/core/exterior_ring.hpp>
0044 #include <boost/geometry/core/geometry_id.hpp>
0045 #include <boost/geometry/core/geometry_types.hpp>
0046 #include <boost/geometry/core/interior_rings.hpp>
0047 #include <boost/geometry/core/mutable_range.hpp>
0048 #include <boost/geometry/core/point_type.hpp>
0049 #include <boost/geometry/core/tag.hpp>
0050 #include <boost/geometry/core/tags.hpp>
0051
0052 #include <boost/geometry/geometries/adapted/boost_variant.hpp> // For consistency with other functions
0053 #include <boost/geometry/geometries/concepts/check.hpp>
0054
0055 #include <boost/geometry/io/wkt/detail/prefix.hpp>
0056
0057 #include <boost/geometry/strategies/io/cartesian.hpp>
0058 #include <boost/geometry/strategies/io/geographic.hpp>
0059 #include <boost/geometry/strategies/io/spherical.hpp>
0060
0061 #include <boost/geometry/util/coordinate_cast.hpp>
0062 #include <boost/geometry/util/range.hpp>
0063 #include <boost/geometry/util/sequence.hpp>
0064 #include <boost/geometry/util/type_traits.hpp>
0065
0066 namespace boost { namespace geometry
0067 {
0068
0069
0070
0071
0072
0073 struct read_wkt_exception : public geometry::exception
0074 {
0075 template <typename Iterator>
0076 read_wkt_exception(std::string const& msg,
0077 Iterator const& it,
0078 Iterator const& end,
0079 std::string const& wkt)
0080 : message(msg)
0081 , wkt(wkt)
0082 {
0083 if (it != end)
0084 {
0085 source = " at '";
0086 source += it->c_str();
0087 source += "'";
0088 }
0089 complete = message + source + " in '" + wkt.substr(0, 100) + "'";
0090 }
0091
0092 read_wkt_exception(std::string const& msg, std::string const& wkt)
0093 : message(msg)
0094 , wkt(wkt)
0095 {
0096 complete = message + "' in (" + wkt.substr(0, 100) + ")";
0097 }
0098
0099 const char* what() const noexcept override
0100 {
0101 return complete.c_str();
0102 }
0103 private :
0104 std::string source;
0105 std::string message;
0106 std::string wkt;
0107 std::string complete;
0108 };
0109
0110
0111 #ifndef DOXYGEN_NO_DETAIL
0112
0113 namespace detail { namespace wkt
0114 {
0115
0116 inline auto make_tokenizer(std::string const& wkt)
0117 {
0118 using separator = boost::char_separator<char>;
0119 using tokenizer = boost::tokenizer<separator>;
0120 const tokenizer tokens(wkt, separator(" \n\t\r", ",()"));
0121 return tokens;
0122 }
0123
0124 template <typename Point,
0125 std::size_t Dimension = 0,
0126 std::size_t DimensionCount = geometry::dimension<Point>::value>
0127 struct parsing_assigner
0128 {
0129 template <typename TokenizerIterator>
0130 static inline void apply(TokenizerIterator& it,
0131 TokenizerIterator const& end,
0132 Point& point,
0133 std::string const& wkt)
0134 {
0135 using coordinate_type = coordinate_type_t<Point>;
0136
0137
0138 bool finished = (it == end || *it == "," || *it == ")");
0139
0140 try
0141 {
0142
0143
0144
0145
0146
0147
0148 set<Dimension>(point, finished
0149 ? coordinate_type()
0150 : coordinate_cast<coordinate_type>::apply(*it));
0151 }
0152 catch(boost::bad_lexical_cast const& blc)
0153 {
0154 BOOST_THROW_EXCEPTION(read_wkt_exception(blc.what(), it, end, wkt));
0155 }
0156 catch(std::exception const& e)
0157 {
0158 BOOST_THROW_EXCEPTION(read_wkt_exception(e.what(), it, end, wkt));
0159 }
0160 catch(...)
0161 {
0162 BOOST_THROW_EXCEPTION(read_wkt_exception("", it, end, wkt));
0163 }
0164
0165 parsing_assigner<Point, Dimension + 1, DimensionCount>::apply(
0166 (finished ? it : ++it), end, point, wkt);
0167 }
0168 };
0169
0170 template <typename Point, std::size_t DimensionCount>
0171 struct parsing_assigner<Point, DimensionCount, DimensionCount>
0172 {
0173 template <typename TokenizerIterator>
0174 static inline void apply(TokenizerIterator&,
0175 TokenizerIterator const&,
0176 Point&,
0177 std::string const&)
0178 {
0179 }
0180 };
0181
0182
0183
0184 template <typename Iterator>
0185 inline void handle_open_parenthesis(Iterator& it,
0186 Iterator const& end,
0187 std::string const& wkt)
0188 {
0189 if (it == end || *it != "(")
0190 {
0191 BOOST_THROW_EXCEPTION(read_wkt_exception("Expected '('", it, end, wkt));
0192 }
0193 ++it;
0194 }
0195
0196
0197 template <typename Iterator>
0198 inline void handle_close_parenthesis(Iterator& it,
0199 Iterator const& end,
0200 std::string const& wkt)
0201 {
0202 if (it != end && *it == ")")
0203 {
0204 ++it;
0205 }
0206 else
0207 {
0208 BOOST_THROW_EXCEPTION(read_wkt_exception("Expected ')'", it, end, wkt));
0209 }
0210 }
0211
0212 template <typename Iterator>
0213 inline void check_end(Iterator& it,
0214 Iterator const& end,
0215 std::string const& wkt)
0216 {
0217 if (it != end)
0218 {
0219 BOOST_THROW_EXCEPTION(read_wkt_exception("Too many tokens", it, end, wkt));
0220 }
0221 }
0222
0223
0224
0225
0226
0227
0228
0229 template <typename Point>
0230 struct container_inserter
0231 {
0232
0233 template <typename TokenizerIterator, typename OutputIterator>
0234 static inline void apply(TokenizerIterator& it,
0235 TokenizerIterator const& end,
0236 std::string const& wkt,
0237 OutputIterator out)
0238 {
0239 handle_open_parenthesis(it, end, wkt);
0240
0241 Point point;
0242
0243
0244
0245 while (it != end && *it != ")")
0246 {
0247 parsing_assigner<Point>::apply(it, end, point, wkt);
0248 out = point;
0249 ++out;
0250 if (it != end && *it == ",")
0251 {
0252 ++it;
0253 }
0254 }
0255
0256 handle_close_parenthesis(it, end, wkt);
0257 }
0258 };
0259
0260
0261 template <typename Geometry,
0262 closure_selector Closure = closure<Geometry>::value>
0263 struct stateful_range_appender
0264 {
0265
0266 inline void append(Geometry geom, geometry::point_type_t<Geometry> const& point, bool)
0267 {
0268 geometry::append(geom, point);
0269 }
0270 };
0271
0272 template <typename Geometry>
0273 struct stateful_range_appender<Geometry, open>
0274 {
0275 using point_type = geometry::point_type_t<Geometry>;
0276 using size_type = typename boost::range_size<util::remove_cptrref_t<Geometry>>::type;
0277
0278 BOOST_STATIC_ASSERT((util::is_ring<Geometry>::value));
0279
0280 inline stateful_range_appender()
0281 : pt_index(0)
0282 {}
0283
0284
0285 inline void append(Geometry geom, point_type const& point, bool is_next_expected)
0286 {
0287 bool should_append = true;
0288
0289 if (pt_index == 0)
0290 {
0291 first_point = point;
0292 }
0293 else
0294 {
0295
0296 should_append
0297 = is_next_expected
0298 || pt_index < core_detail::closure::minimum_ring_size<open>::value
0299 || disjoint(point, first_point);
0300 }
0301 ++pt_index;
0302
0303 if (should_append)
0304 {
0305 geometry::append(geom, point);
0306 }
0307 }
0308
0309 private:
0310 static inline bool disjoint(point_type const& p1, point_type const& p2)
0311 {
0312
0313 using strategy_type = typename strategies::io::services::default_strategy
0314 <
0315 point_type
0316 >::type;
0317
0318 return detail::disjoint::disjoint_point_point(p1, p2, strategy_type());
0319 }
0320
0321 size_type pt_index;
0322 point_type first_point;
0323 };
0324
0325
0326 template <typename Geometry>
0327 struct container_appender
0328 {
0329 using point_type = geometry::point_type_t<Geometry>;
0330
0331 template <typename TokenizerIterator>
0332 static inline void apply(TokenizerIterator& it,
0333 TokenizerIterator const& end,
0334 std::string const& wkt,
0335 Geometry out)
0336 {
0337 handle_open_parenthesis(it, end, wkt);
0338
0339 stateful_range_appender<Geometry> appender;
0340
0341
0342 while (it != end && *it != ")")
0343 {
0344 point_type point;
0345
0346 parsing_assigner<point_type>::apply(it, end, point, wkt);
0347
0348 bool const is_next_expected = it != end && *it == ",";
0349
0350 appender.append(out, point, is_next_expected);
0351
0352 if (is_next_expected)
0353 {
0354 ++it;
0355 }
0356 }
0357
0358 handle_close_parenthesis(it, end, wkt);
0359 }
0360 };
0361
0362
0363
0364
0365
0366 template <typename P>
0367 struct point_parser
0368 {
0369 template <typename TokenizerIterator>
0370 static inline void apply(TokenizerIterator& it,
0371 TokenizerIterator const& end,
0372 std::string const& wkt,
0373 P& point)
0374 {
0375 handle_open_parenthesis(it, end, wkt);
0376 parsing_assigner<P>::apply(it, end, point, wkt);
0377 handle_close_parenthesis(it, end, wkt);
0378 }
0379 };
0380
0381
0382 template <typename Geometry>
0383 struct linestring_parser
0384 {
0385 template <typename TokenizerIterator>
0386 static inline void apply(TokenizerIterator& it,
0387 TokenizerIterator const& end,
0388 std::string const& wkt,
0389 Geometry& geometry)
0390 {
0391 container_appender<Geometry&>::apply(it, end, wkt, geometry);
0392 }
0393 };
0394
0395
0396 template <typename Ring>
0397 struct ring_parser
0398 {
0399 template <typename TokenizerIterator>
0400 static inline void apply(TokenizerIterator& it,
0401 TokenizerIterator const& end,
0402 std::string const& wkt,
0403 Ring& ring)
0404 {
0405
0406
0407
0408 handle_open_parenthesis(it, end, wkt);
0409 container_appender<Ring&>::apply(it, end, wkt, ring);
0410 handle_close_parenthesis(it, end, wkt);
0411 }
0412 };
0413
0414
0415
0416
0417
0418
0419 template <typename Polygon>
0420 struct polygon_parser
0421 {
0422 using appender = container_appender<ring_return_type_t<Polygon>>;
0423
0424 template <typename TokenizerIterator>
0425 static inline void apply(TokenizerIterator& it,
0426 TokenizerIterator const& end,
0427 std::string const& wkt,
0428 Polygon& poly)
0429 {
0430
0431 handle_open_parenthesis(it, end, wkt);
0432
0433 int n = -1;
0434
0435
0436 while (it != end && *it != ")")
0437 {
0438
0439 if (++n == 0)
0440 {
0441 appender::apply(it, end, wkt, exterior_ring(poly));
0442 }
0443 else
0444 {
0445 ring_type_t<Polygon> ring;
0446 appender::apply(it, end, wkt, ring);
0447 range::push_back(geometry::interior_rings(poly), std::move(ring));
0448 }
0449
0450 if (it != end && *it == ",")
0451 {
0452
0453 ++it;
0454 }
0455 }
0456
0457 handle_close_parenthesis(it, end, wkt);
0458 }
0459 };
0460
0461 template<typename PolyhedralSurface>
0462 struct polyhedral_surface_parser
0463 {
0464 using polygon_t = typename PolyhedralSurface::polygon_type;
0465
0466 template <typename TokenizerIterator>
0467 static inline void apply(TokenizerIterator& it,
0468 TokenizerIterator const& end,
0469 std::string const& wkt,
0470 PolyhedralSurface& polyhedral)
0471 {
0472 handle_open_parenthesis(it, end, wkt);
0473
0474
0475 while (it != end && *it != ")")
0476 {
0477 traits::resize<PolyhedralSurface>::apply(polyhedral, boost::size(polyhedral) + 1);
0478 polygon_parser<polygon_t>::apply(it, end, wkt, *(boost::end(polyhedral) - 1));
0479 if (it != end && *it == ",")
0480 {
0481
0482 ++it;
0483 }
0484 }
0485
0486 handle_close_parenthesis(it, end, wkt);
0487 }
0488 };
0489
0490
0491 template <typename TokenizerIterator>
0492 inline bool one_of(TokenizerIterator const& it,
0493 std::string const& value,
0494 bool& is_present)
0495 {
0496 if (boost::iequals(*it, value))
0497 {
0498 is_present = true;
0499 return true;
0500 }
0501 return false;
0502 }
0503
0504 template <typename TokenizerIterator>
0505 inline bool one_of(TokenizerIterator const& it,
0506 std::string const& value,
0507 bool& present1,
0508 bool& present2)
0509 {
0510 if (boost::iequals(*it, value))
0511 {
0512 present1 = true;
0513 present2 = true;
0514 return true;
0515 }
0516 return false;
0517 }
0518
0519
0520 template <typename TokenizerIterator>
0521 inline void handle_empty_z_m(TokenizerIterator& it,
0522 TokenizerIterator const& end,
0523 bool& has_empty,
0524 bool& has_z,
0525 bool& has_m)
0526 {
0527 has_empty = false;
0528 has_z = false;
0529 has_m = false;
0530
0531
0532
0533
0534
0535 while (it != end
0536 && (one_of(it, "M", has_m)
0537 || one_of(it, "Z", has_z)
0538 || one_of(it, "EMPTY", has_empty)
0539 || one_of(it, "MZ", has_m, has_z)
0540 || one_of(it, "ZM", has_z, has_m)
0541 )
0542 )
0543 {
0544 ++it;
0545 }
0546 }
0547
0548
0549 template <typename Geometry, typename Tag = geometry::tag_t<Geometry>>
0550 struct dimension
0551 : geometry::dimension<Geometry>
0552 {};
0553
0554
0555
0556 template <typename Geometry>
0557 struct dimension<Geometry, geometry_collection_tag>
0558 : geometry::dimension
0559 <
0560 typename util::sequence_front
0561 <
0562 typename traits::geometry_types<Geometry>::type
0563 >::type
0564 >
0565 {};
0566
0567
0568
0569
0570
0571
0572 template <typename Geometry, typename TokenizerIterator>
0573 inline bool initialize(TokenizerIterator& it,
0574 TokenizerIterator const& end,
0575 std::string const& wkt,
0576 std::string const& geometry_name)
0577 {
0578 if (it == end || ! boost::iequals(*it++, geometry_name))
0579 {
0580 BOOST_THROW_EXCEPTION(read_wkt_exception(std::string("Should start with '") + geometry_name + "'", wkt));
0581 }
0582
0583 bool has_empty, has_z, has_m;
0584
0585 handle_empty_z_m(it, end, has_empty, has_z, has_m);
0586
0587
0588 #if defined(_MSC_VER)
0589 #pragma warning(push)
0590 #pragma warning(disable : 4127)
0591 #endif
0592
0593 if (has_z && dimension<Geometry>::value < 3)
0594 {
0595 BOOST_THROW_EXCEPTION(read_wkt_exception("Z only allowed for 3 or more dimensions", wkt));
0596 }
0597
0598 #if defined(_MSC_VER)
0599 #pragma warning(pop)
0600 #endif
0601
0602 if (has_empty)
0603 {
0604 return false;
0605 }
0606
0607
0608 return true;
0609 }
0610
0611
0612 template <typename Geometry, template<typename> class Parser, typename PrefixPolicy>
0613 struct geometry_parser
0614 {
0615 static inline void apply(std::string const& wkt, Geometry& geometry)
0616 {
0617 geometry::clear(geometry);
0618
0619 auto const tokens{make_tokenizer(wkt)};
0620 auto it = tokens.begin();
0621 auto const end = tokens.end();
0622
0623 apply(it, end, wkt, geometry);
0624
0625 check_end(it, end, wkt);
0626 }
0627
0628 template <typename TokenizerIterator>
0629 static inline void apply(TokenizerIterator& it,
0630 TokenizerIterator const& end,
0631 std::string const& wkt,
0632 Geometry& geometry)
0633 {
0634 if (initialize<Geometry>(it, end, wkt, PrefixPolicy::apply()))
0635 {
0636 Parser<Geometry>::apply(it, end, wkt, geometry);
0637 }
0638 }
0639 };
0640
0641
0642 template <typename MultiGeometry, template<typename> class Parser, typename PrefixPolicy>
0643 struct multi_parser
0644 {
0645 static inline void apply(std::string const& wkt, MultiGeometry& geometry)
0646 {
0647 traits::clear<MultiGeometry>::apply(geometry);
0648
0649 auto const tokens{make_tokenizer(wkt)};
0650 auto it = tokens.begin();
0651 auto const end = tokens.end();
0652
0653 apply(it, end, wkt, geometry);
0654
0655 check_end(it, end, wkt);
0656 }
0657
0658 template <typename TokenizerIterator>
0659 static inline void apply(TokenizerIterator& it,
0660 TokenizerIterator const& end,
0661 std::string const& wkt,
0662 MultiGeometry& geometry)
0663 {
0664 if (initialize<MultiGeometry>(it, end, wkt, PrefixPolicy::apply()))
0665 {
0666 handle_open_parenthesis(it, end, wkt);
0667
0668
0669 while(it != end && *it != ")")
0670 {
0671 traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1);
0672 Parser
0673 <
0674 typename boost::range_value<MultiGeometry>::type
0675 >::apply(it, end, wkt, *(boost::end(geometry) - 1));
0676 if (it != end && *it == ",")
0677 {
0678
0679 ++it;
0680 }
0681 }
0682
0683 handle_close_parenthesis(it, end, wkt);
0684 }
0685 }
0686 };
0687
0688 template <typename P>
0689 struct noparenthesis_point_parser
0690 {
0691 template <typename TokenizerIterator>
0692 static inline void apply(TokenizerIterator& it,
0693 TokenizerIterator const& end,
0694 std::string const& wkt,
0695 P& point)
0696 {
0697 parsing_assigner<P>::apply(it, end, point, wkt);
0698 }
0699 };
0700
0701 template <typename MultiGeometry, typename PrefixPolicy>
0702 struct multi_point_parser
0703 {
0704 static inline void apply(std::string const& wkt, MultiGeometry& geometry)
0705 {
0706 traits::clear<MultiGeometry>::apply(geometry);
0707
0708 auto const tokens{make_tokenizer(wkt)};
0709 auto it = tokens.begin();
0710 auto const end = tokens.end();
0711
0712 apply(it, end, wkt, geometry);
0713
0714 check_end(it, end, wkt);
0715 }
0716
0717 template <typename TokenizerIterator>
0718 static inline void apply(TokenizerIterator& it,
0719 TokenizerIterator const& end,
0720 std::string const& wkt,
0721 MultiGeometry& geometry)
0722 {
0723 if (initialize<MultiGeometry>(it, end, wkt, PrefixPolicy::apply()))
0724 {
0725 handle_open_parenthesis(it, end, wkt);
0726
0727
0728
0729 bool using_brackets = (it != end && *it == "(");
0730
0731 while(it != end && *it != ")")
0732 {
0733 traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1);
0734
0735 if (using_brackets)
0736 {
0737 point_parser
0738 <
0739 typename boost::range_value<MultiGeometry>::type
0740 >::apply(it, end, wkt, *(boost::end(geometry) - 1));
0741 }
0742 else
0743 {
0744 noparenthesis_point_parser
0745 <
0746 typename boost::range_value<MultiGeometry>::type
0747 >::apply(it, end, wkt, *(boost::end(geometry) - 1));
0748 }
0749
0750 if (it != end && *it == ",")
0751 {
0752
0753 ++it;
0754 }
0755 }
0756
0757 handle_close_parenthesis(it, end, wkt);
0758 }
0759 }
0760 };
0761
0762
0763
0764
0765
0766
0767
0768
0769
0770
0771 template <typename Box>
0772 struct box_parser
0773 {
0774 static inline void apply(std::string const& wkt, Box& box)
0775 {
0776 auto const tokens{make_tokenizer(wkt)};
0777 auto it = tokens.begin();
0778 auto const end = tokens.end();
0779
0780 apply(it, end, wkt, box);
0781
0782 check_end(it, end, wkt);
0783 }
0784
0785 template <typename TokenizerIterator>
0786 static inline void apply(TokenizerIterator& it,
0787 TokenizerIterator const& end,
0788 std::string const& wkt,
0789 Box& box)
0790 {
0791 bool should_close = false;
0792 if (it != end && boost::iequals(*it, "POLYGON"))
0793 {
0794 ++it;
0795 bool has_empty, has_z, has_m;
0796 handle_empty_z_m(it, end, has_empty, has_z, has_m);
0797 if (has_empty)
0798 {
0799 assign_zero(box);
0800 return;
0801 }
0802 handle_open_parenthesis(it, end, wkt);
0803 should_close = true;
0804 }
0805 else if (it != end && boost::iequals(*it, "BOX"))
0806 {
0807 ++it;
0808 }
0809 else
0810 {
0811 BOOST_THROW_EXCEPTION(read_wkt_exception("Should start with 'POLYGON' or 'BOX'", wkt));
0812 }
0813
0814 using point_type = point_type_t<Box>;
0815 std::vector<point_type> points;
0816 container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points));
0817
0818 if (should_close)
0819 {
0820 handle_close_parenthesis(it, end, wkt);
0821 }
0822
0823 unsigned int index = 0;
0824 std::size_t n = boost::size(points);
0825 if (n == 2)
0826 {
0827 index = 1;
0828 }
0829 else if (n == 4 || n == 5)
0830 {
0831
0832
0833 index = 2;
0834 }
0835 else
0836 {
0837 BOOST_THROW_EXCEPTION(read_wkt_exception("Box should have 2,4 or 5 points", wkt));
0838 }
0839
0840 geometry::detail::assign_point_to_index<min_corner>(points.front(), box);
0841 geometry::detail::assign_point_to_index<max_corner>(points[index], box);
0842 }
0843 };
0844
0845
0846
0847
0848
0849
0850
0851
0852 template <typename Segment>
0853 struct segment_parser
0854 {
0855 static inline void apply(std::string const& wkt, Segment& segment)
0856 {
0857 auto const tokens{make_tokenizer(wkt)};
0858 auto it = tokens.begin();
0859 auto const end = tokens.end();
0860
0861 apply(it, end, wkt, segment);
0862
0863 check_end(it, end, wkt);
0864 }
0865
0866 template <typename TokenizerIterator>
0867 static inline void apply(TokenizerIterator& it,
0868 TokenizerIterator const& end,
0869 std::string const& wkt,
0870 Segment& segment)
0871 {
0872 if (it != end
0873 && (boost::iequals(*it, prefix_segment::apply())
0874 || boost::iequals(*it, prefix_linestring::apply())))
0875 {
0876 ++it;
0877 }
0878 else
0879 {
0880 BOOST_THROW_EXCEPTION(read_wkt_exception("Should start with 'LINESTRING' or 'SEGMENT'", wkt));
0881 }
0882
0883 using point_type = point_type_t<Segment>;
0884 std::vector<point_type> points;
0885 container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points));
0886
0887 if (boost::size(points) == 2)
0888 {
0889 geometry::detail::assign_point_to_index<0>(points.front(), segment);
0890 geometry::detail::assign_point_to_index<1>(points.back(), segment);
0891 }
0892 else
0893 {
0894 BOOST_THROW_EXCEPTION(read_wkt_exception("Segment should have 2 points", wkt));
0895 }
0896 }
0897 };
0898
0899
0900 struct dynamic_move_assign
0901 {
0902 template <typename DynamicGeometry, typename Geometry>
0903 static void apply(DynamicGeometry& dynamic_geometry, Geometry & geometry)
0904 {
0905 dynamic_geometry = std::move(geometry);
0906 }
0907 };
0908
0909 struct dynamic_move_emplace_back
0910 {
0911 template <typename GeometryCollection, typename Geometry>
0912 static void apply(GeometryCollection& geometry_collection, Geometry & geometry)
0913 {
0914 traits::emplace_back<GeometryCollection>::apply(geometry_collection, std::move(geometry));
0915 }
0916 };
0917
0918 template
0919 <
0920 typename Geometry,
0921 template <typename, typename> class ReadWkt,
0922 typename AppendPolicy
0923 >
0924 struct dynamic_readwkt_caller
0925 {
0926 template <typename TokenizerIterator>
0927 static inline void apply(TokenizerIterator& it,
0928 TokenizerIterator const& end,
0929 std::string const& wkt,
0930 Geometry& geometry)
0931 {
0932 static const char* tag_point = prefix_point::apply();
0933 static const char* tag_linestring = prefix_linestring::apply();
0934 static const char* tag_polygon = prefix_polygon::apply();
0935
0936 static const char* tag_multi_point = prefix_multipoint::apply();
0937 static const char* tag_multi_linestring = prefix_multilinestring::apply();
0938 static const char* tag_multi_polygon = prefix_multipolygon::apply();
0939
0940 static const char* tag_segment = prefix_segment::apply();
0941 static const char* tag_box = prefix_box::apply();
0942 static const char* tag_gc = prefix_geometrycollection::apply();
0943
0944 if (boost::iequals(*it, tag_point))
0945 {
0946 parse_geometry<util::is_point>(tag_point, it, end, wkt, geometry);
0947 }
0948 else if (boost::iequals(*it, tag_multi_point))
0949 {
0950 parse_geometry<util::is_multi_point>(tag_multi_point, it, end, wkt, geometry);
0951 }
0952 else if (boost::iequals(*it, tag_segment))
0953 {
0954 parse_geometry<util::is_segment>(tag_segment, it, end, wkt, geometry);
0955 }
0956 else if (boost::iequals(*it, tag_linestring))
0957 {
0958 parse_geometry<util::is_linestring>(tag_linestring, it, end, wkt, geometry, false)
0959 || parse_geometry<util::is_segment>(tag_linestring, it, end, wkt, geometry);
0960 }
0961 else if (boost::iequals(*it, tag_multi_linestring))
0962 {
0963 parse_geometry<util::is_multi_linestring>(tag_multi_linestring, it, end, wkt, geometry);
0964 }
0965 else if (boost::iequals(*it, tag_box))
0966 {
0967 parse_geometry<util::is_box>(tag_box, it, end, wkt, geometry);
0968 }
0969 else if (boost::iequals(*it, tag_polygon))
0970 {
0971 parse_geometry<util::is_polygon>(tag_polygon, it, end, wkt, geometry, false)
0972 || parse_geometry<util::is_ring>(tag_polygon, it, end, wkt, geometry, false)
0973 || parse_geometry<util::is_box>(tag_polygon, it, end, wkt, geometry);
0974 }
0975 else if (boost::iequals(*it, tag_multi_polygon))
0976 {
0977 parse_geometry<util::is_multi_polygon>(tag_multi_polygon, it, end, wkt, geometry);
0978 }
0979 else if (boost::iequals(*it, tag_gc))
0980 {
0981 parse_geometry<util::is_geometry_collection>(tag_gc, it, end, wkt, geometry);
0982 }
0983 else
0984 {
0985 BOOST_THROW_EXCEPTION(read_wkt_exception(
0986 "Should start with geometry's type, for example 'POINT', 'LINESTRING', 'POLYGON'",
0987 wkt));
0988 }
0989 }
0990
0991 private:
0992 template
0993 <
0994 template <typename> class UnaryPred,
0995 typename TokenizerIterator,
0996 typename Geom = typename util::sequence_find_if
0997 <
0998 typename traits::geometry_types<Geometry>::type, UnaryPred
0999 >::type,
1000 std::enable_if_t<! std::is_void<Geom>::value, int> = 0
1001 >
1002 static bool parse_geometry(const char * ,
1003 TokenizerIterator& it,
1004 TokenizerIterator const& end,
1005 std::string const& wkt,
1006 Geometry& geometry,
1007 bool = true)
1008 {
1009 Geom g;
1010 ReadWkt<Geom, tag_t<Geom>>::apply(it, end, wkt, g);
1011 AppendPolicy::apply(geometry, g);
1012 return true;
1013 }
1014
1015 template
1016 <
1017 template <typename> class UnaryPred,
1018 typename TokenizerIterator,
1019 typename Geom = typename util::sequence_find_if
1020 <
1021 typename traits::geometry_types<Geometry>::type, UnaryPred
1022 >::type,
1023 std::enable_if_t<std::is_void<Geom>::value, int> = 0
1024 >
1025 static bool parse_geometry(const char * name,
1026 TokenizerIterator& ,
1027 TokenizerIterator const& ,
1028 std::string const& wkt,
1029 Geometry& ,
1030 bool throw_on_misfit = true)
1031 {
1032 if (throw_on_misfit)
1033 {
1034 std::string msg = std::string("Unable to store '") + name + "' in this geometry";
1035 BOOST_THROW_EXCEPTION(read_wkt_exception(msg, wkt));
1036 }
1037
1038 return false;
1039 }
1040 };
1041
1042
1043 }}
1044 #endif
1045
1046 #ifndef DOXYGEN_NO_DISPATCH
1047 namespace dispatch
1048 {
1049
1050 template <typename Geometry, typename Tag = tag_t<Geometry>>
1051 struct read_wkt {};
1052
1053
1054 template <typename Point>
1055 struct read_wkt<Point, point_tag>
1056 : detail::wkt::geometry_parser
1057 <
1058 Point,
1059 detail::wkt::point_parser,
1060 detail::wkt::prefix_point
1061 >
1062 {};
1063
1064
1065 template <typename L>
1066 struct read_wkt<L, linestring_tag>
1067 : detail::wkt::geometry_parser
1068 <
1069 L,
1070 detail::wkt::linestring_parser,
1071 detail::wkt::prefix_linestring
1072 >
1073 {};
1074
1075 template <typename Ring>
1076 struct read_wkt<Ring, ring_tag>
1077 : detail::wkt::geometry_parser
1078 <
1079 Ring,
1080 detail::wkt::ring_parser,
1081 detail::wkt::prefix_polygon
1082 >
1083 {};
1084
1085 template <typename Geometry>
1086 struct read_wkt<Geometry, polygon_tag>
1087 : detail::wkt::geometry_parser
1088 <
1089 Geometry,
1090 detail::wkt::polygon_parser,
1091 detail::wkt::prefix_polygon
1092 >
1093 {};
1094
1095 template <typename Geometry>
1096 struct read_wkt<Geometry, polyhedral_surface_tag>
1097 : detail::wkt::geometry_parser
1098 <
1099 Geometry,
1100 detail::wkt::polyhedral_surface_parser,
1101 detail::wkt::prefix_polyhedral_surface
1102 >
1103 {};
1104
1105 template <typename MultiGeometry>
1106 struct read_wkt<MultiGeometry, multi_point_tag>
1107 : detail::wkt::multi_point_parser
1108 <
1109 MultiGeometry,
1110 detail::wkt::prefix_multipoint
1111 >
1112 {};
1113
1114 template <typename MultiGeometry>
1115 struct read_wkt<MultiGeometry, multi_linestring_tag>
1116 : detail::wkt::multi_parser
1117 <
1118 MultiGeometry,
1119 detail::wkt::linestring_parser,
1120 detail::wkt::prefix_multilinestring
1121 >
1122 {};
1123
1124 template <typename MultiGeometry>
1125 struct read_wkt<MultiGeometry, multi_polygon_tag>
1126 : detail::wkt::multi_parser
1127 <
1128 MultiGeometry,
1129 detail::wkt::polygon_parser,
1130 detail::wkt::prefix_multipolygon
1131 >
1132 {};
1133
1134
1135
1136 template <typename Box>
1137 struct read_wkt<Box, box_tag>
1138 : detail::wkt::box_parser<Box>
1139 {};
1140
1141
1142 template <typename Segment>
1143 struct read_wkt<Segment, segment_tag>
1144 : detail::wkt::segment_parser<Segment>
1145 {};
1146
1147
1148 template <typename DynamicGeometry>
1149 struct read_wkt<DynamicGeometry, dynamic_geometry_tag>
1150 {
1151 static inline void apply(std::string const& wkt, DynamicGeometry& dynamic_geometry)
1152 {
1153 auto tokens{detail::wkt::make_tokenizer(wkt)};
1154 auto it = tokens.begin();
1155 auto const end = tokens.end();
1156 if (it == end)
1157 {
1158 BOOST_THROW_EXCEPTION(read_wkt_exception(
1159 "Should start with geometry's type, for example 'POINT', 'LINESTRING', 'POLYGON'",
1160 wkt));
1161 }
1162
1163 detail::wkt::dynamic_readwkt_caller
1164 <
1165 DynamicGeometry, dispatch::read_wkt, detail::wkt::dynamic_move_assign
1166 >::apply(it, end, wkt, dynamic_geometry);
1167
1168 detail::wkt::check_end(it, end, wkt);
1169 }
1170 };
1171
1172
1173 template <typename Geometry>
1174 struct read_wkt<Geometry, geometry_collection_tag>
1175 {
1176 static inline void apply(std::string const& wkt, Geometry& geometry)
1177 {
1178 range::clear(geometry);
1179
1180 auto tokens{detail::wkt::make_tokenizer(wkt)};
1181 auto it = tokens.begin();
1182 auto const end = tokens.end();
1183
1184 apply(it, end, wkt, geometry);
1185
1186 detail::wkt::check_end(it, end, wkt);
1187 }
1188
1189 template <typename TokenizerIterator>
1190 static inline void apply(TokenizerIterator& it,
1191 TokenizerIterator const& end,
1192 std::string const& wkt,
1193 Geometry& geometry)
1194 {
1195 if (detail::wkt::initialize<Geometry>(it, end, wkt,
1196 detail::wkt::prefix_geometrycollection::apply()))
1197 {
1198 detail::wkt::handle_open_parenthesis(it, end, wkt);
1199
1200
1201 while (it != end && *it != ")")
1202 {
1203 detail::wkt::dynamic_readwkt_caller
1204 <
1205 Geometry, dispatch::read_wkt, detail::wkt::dynamic_move_emplace_back
1206 >::apply(it, end, wkt, geometry);
1207
1208 if (it != end && *it == ",")
1209 {
1210
1211 ++it;
1212 }
1213 }
1214
1215 detail::wkt::handle_close_parenthesis(it, end, wkt);
1216 }
1217 }
1218 };
1219
1220
1221 }
1222 #endif
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233 template <typename Geometry>
1234 inline void read_wkt(std::string const& wkt, Geometry& geometry)
1235 {
1236 geometry::concepts::check<Geometry>();
1237 dispatch::read_wkt<Geometry>::apply(wkt, geometry);
1238 }
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248 template <typename Geometry>
1249 inline Geometry from_wkt(std::string const& wkt)
1250 {
1251 Geometry geometry;
1252 geometry::concepts::check<Geometry>();
1253 dispatch::read_wkt<Geometry>::apply(wkt, geometry);
1254 return geometry;
1255 }
1256
1257 }}
1258
1259 #endif