File indexing completed on 2025-09-18 08:43:20
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
0462 template <typename TokenizerIterator>
0463 inline bool one_of(TokenizerIterator const& it,
0464 std::string const& value,
0465 bool& is_present)
0466 {
0467 if (boost::iequals(*it, value))
0468 {
0469 is_present = true;
0470 return true;
0471 }
0472 return false;
0473 }
0474
0475 template <typename TokenizerIterator>
0476 inline bool one_of(TokenizerIterator const& it,
0477 std::string const& value,
0478 bool& present1,
0479 bool& present2)
0480 {
0481 if (boost::iequals(*it, value))
0482 {
0483 present1 = true;
0484 present2 = true;
0485 return true;
0486 }
0487 return false;
0488 }
0489
0490
0491 template <typename TokenizerIterator>
0492 inline void handle_empty_z_m(TokenizerIterator& it,
0493 TokenizerIterator const& end,
0494 bool& has_empty,
0495 bool& has_z,
0496 bool& has_m)
0497 {
0498 has_empty = false;
0499 has_z = false;
0500 has_m = false;
0501
0502
0503
0504
0505
0506 while (it != end
0507 && (one_of(it, "M", has_m)
0508 || one_of(it, "Z", has_z)
0509 || one_of(it, "EMPTY", has_empty)
0510 || one_of(it, "MZ", has_m, has_z)
0511 || one_of(it, "ZM", has_z, has_m)
0512 )
0513 )
0514 {
0515 ++it;
0516 }
0517 }
0518
0519
0520 template <typename Geometry, typename Tag = geometry::tag_t<Geometry>>
0521 struct dimension
0522 : geometry::dimension<Geometry>
0523 {};
0524
0525
0526
0527 template <typename Geometry>
0528 struct dimension<Geometry, geometry_collection_tag>
0529 : geometry::dimension
0530 <
0531 typename util::sequence_front
0532 <
0533 typename traits::geometry_types<Geometry>::type
0534 >::type
0535 >
0536 {};
0537
0538
0539
0540
0541
0542
0543 template <typename Geometry, typename TokenizerIterator>
0544 inline bool initialize(TokenizerIterator& it,
0545 TokenizerIterator const& end,
0546 std::string const& wkt,
0547 std::string const& geometry_name)
0548 {
0549 if (it == end || ! boost::iequals(*it++, geometry_name))
0550 {
0551 BOOST_THROW_EXCEPTION(read_wkt_exception(std::string("Should start with '") + geometry_name + "'", wkt));
0552 }
0553
0554 bool has_empty, has_z, has_m;
0555
0556 handle_empty_z_m(it, end, has_empty, has_z, has_m);
0557
0558
0559 #if defined(_MSC_VER)
0560 #pragma warning(push)
0561 #pragma warning(disable : 4127)
0562 #endif
0563
0564 if (has_z && dimension<Geometry>::value < 3)
0565 {
0566 BOOST_THROW_EXCEPTION(read_wkt_exception("Z only allowed for 3 or more dimensions", wkt));
0567 }
0568
0569 #if defined(_MSC_VER)
0570 #pragma warning(pop)
0571 #endif
0572
0573 if (has_empty)
0574 {
0575 return false;
0576 }
0577
0578
0579 return true;
0580 }
0581
0582
0583 template <typename Geometry, template<typename> class Parser, typename PrefixPolicy>
0584 struct geometry_parser
0585 {
0586 static inline void apply(std::string const& wkt, Geometry& geometry)
0587 {
0588 geometry::clear(geometry);
0589
0590 auto const tokens{make_tokenizer(wkt)};
0591 auto it = tokens.begin();
0592 auto const end = tokens.end();
0593
0594 apply(it, end, wkt, geometry);
0595
0596 check_end(it, end, wkt);
0597 }
0598
0599 template <typename TokenizerIterator>
0600 static inline void apply(TokenizerIterator& it,
0601 TokenizerIterator const& end,
0602 std::string const& wkt,
0603 Geometry& geometry)
0604 {
0605 if (initialize<Geometry>(it, end, wkt, PrefixPolicy::apply()))
0606 {
0607 Parser<Geometry>::apply(it, end, wkt, geometry);
0608 }
0609 }
0610 };
0611
0612
0613 template <typename MultiGeometry, template<typename> class Parser, typename PrefixPolicy>
0614 struct multi_parser
0615 {
0616 static inline void apply(std::string const& wkt, MultiGeometry& geometry)
0617 {
0618 traits::clear<MultiGeometry>::apply(geometry);
0619
0620 auto const tokens{make_tokenizer(wkt)};
0621 auto it = tokens.begin();
0622 auto const end = tokens.end();
0623
0624 apply(it, end, wkt, geometry);
0625
0626 check_end(it, end, wkt);
0627 }
0628
0629 template <typename TokenizerIterator>
0630 static inline void apply(TokenizerIterator& it,
0631 TokenizerIterator const& end,
0632 std::string const& wkt,
0633 MultiGeometry& geometry)
0634 {
0635 if (initialize<MultiGeometry>(it, end, wkt, PrefixPolicy::apply()))
0636 {
0637 handle_open_parenthesis(it, end, wkt);
0638
0639
0640 while(it != end && *it != ")")
0641 {
0642 traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1);
0643 Parser
0644 <
0645 typename boost::range_value<MultiGeometry>::type
0646 >::apply(it, end, wkt, *(boost::end(geometry) - 1));
0647 if (it != end && *it == ",")
0648 {
0649
0650 ++it;
0651 }
0652 }
0653
0654 handle_close_parenthesis(it, end, wkt);
0655 }
0656 }
0657 };
0658
0659 template <typename P>
0660 struct noparenthesis_point_parser
0661 {
0662 template <typename TokenizerIterator>
0663 static inline void apply(TokenizerIterator& it,
0664 TokenizerIterator const& end,
0665 std::string const& wkt,
0666 P& point)
0667 {
0668 parsing_assigner<P>::apply(it, end, point, wkt);
0669 }
0670 };
0671
0672 template <typename MultiGeometry, typename PrefixPolicy>
0673 struct multi_point_parser
0674 {
0675 static inline void apply(std::string const& wkt, MultiGeometry& geometry)
0676 {
0677 traits::clear<MultiGeometry>::apply(geometry);
0678
0679 auto const tokens{make_tokenizer(wkt)};
0680 auto it = tokens.begin();
0681 auto const end = tokens.end();
0682
0683 apply(it, end, wkt, geometry);
0684
0685 check_end(it, end, wkt);
0686 }
0687
0688 template <typename TokenizerIterator>
0689 static inline void apply(TokenizerIterator& it,
0690 TokenizerIterator const& end,
0691 std::string const& wkt,
0692 MultiGeometry& geometry)
0693 {
0694 if (initialize<MultiGeometry>(it, end, wkt, PrefixPolicy::apply()))
0695 {
0696 handle_open_parenthesis(it, end, wkt);
0697
0698
0699
0700 bool using_brackets = (it != end && *it == "(");
0701
0702 while(it != end && *it != ")")
0703 {
0704 traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1);
0705
0706 if (using_brackets)
0707 {
0708 point_parser
0709 <
0710 typename boost::range_value<MultiGeometry>::type
0711 >::apply(it, end, wkt, *(boost::end(geometry) - 1));
0712 }
0713 else
0714 {
0715 noparenthesis_point_parser
0716 <
0717 typename boost::range_value<MultiGeometry>::type
0718 >::apply(it, end, wkt, *(boost::end(geometry) - 1));
0719 }
0720
0721 if (it != end && *it == ",")
0722 {
0723
0724 ++it;
0725 }
0726 }
0727
0728 handle_close_parenthesis(it, end, wkt);
0729 }
0730 }
0731 };
0732
0733
0734
0735
0736
0737
0738
0739
0740
0741
0742 template <typename Box>
0743 struct box_parser
0744 {
0745 static inline void apply(std::string const& wkt, Box& box)
0746 {
0747 auto const tokens{make_tokenizer(wkt)};
0748 auto it = tokens.begin();
0749 auto const end = tokens.end();
0750
0751 apply(it, end, wkt, box);
0752
0753 check_end(it, end, wkt);
0754 }
0755
0756 template <typename TokenizerIterator>
0757 static inline void apply(TokenizerIterator& it,
0758 TokenizerIterator const& end,
0759 std::string const& wkt,
0760 Box& box)
0761 {
0762 bool should_close = false;
0763 if (it != end && boost::iequals(*it, "POLYGON"))
0764 {
0765 ++it;
0766 bool has_empty, has_z, has_m;
0767 handle_empty_z_m(it, end, has_empty, has_z, has_m);
0768 if (has_empty)
0769 {
0770 assign_zero(box);
0771 return;
0772 }
0773 handle_open_parenthesis(it, end, wkt);
0774 should_close = true;
0775 }
0776 else if (it != end && boost::iequals(*it, "BOX"))
0777 {
0778 ++it;
0779 }
0780 else
0781 {
0782 BOOST_THROW_EXCEPTION(read_wkt_exception("Should start with 'POLYGON' or 'BOX'", wkt));
0783 }
0784
0785 using point_type = point_type_t<Box>;
0786 std::vector<point_type> points;
0787 container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points));
0788
0789 if (should_close)
0790 {
0791 handle_close_parenthesis(it, end, wkt);
0792 }
0793
0794 unsigned int index = 0;
0795 std::size_t n = boost::size(points);
0796 if (n == 2)
0797 {
0798 index = 1;
0799 }
0800 else if (n == 4 || n == 5)
0801 {
0802
0803
0804 index = 2;
0805 }
0806 else
0807 {
0808 BOOST_THROW_EXCEPTION(read_wkt_exception("Box should have 2,4 or 5 points", wkt));
0809 }
0810
0811 geometry::detail::assign_point_to_index<min_corner>(points.front(), box);
0812 geometry::detail::assign_point_to_index<max_corner>(points[index], box);
0813 }
0814 };
0815
0816
0817
0818
0819
0820
0821
0822
0823 template <typename Segment>
0824 struct segment_parser
0825 {
0826 static inline void apply(std::string const& wkt, Segment& segment)
0827 {
0828 auto const tokens{make_tokenizer(wkt)};
0829 auto it = tokens.begin();
0830 auto const end = tokens.end();
0831
0832 apply(it, end, wkt, segment);
0833
0834 check_end(it, end, wkt);
0835 }
0836
0837 template <typename TokenizerIterator>
0838 static inline void apply(TokenizerIterator& it,
0839 TokenizerIterator const& end,
0840 std::string const& wkt,
0841 Segment& segment)
0842 {
0843 if (it != end
0844 && (boost::iequals(*it, prefix_segment::apply())
0845 || boost::iequals(*it, prefix_linestring::apply())))
0846 {
0847 ++it;
0848 }
0849 else
0850 {
0851 BOOST_THROW_EXCEPTION(read_wkt_exception("Should start with 'LINESTRING' or 'SEGMENT'", wkt));
0852 }
0853
0854 using point_type = point_type_t<Segment>;
0855 std::vector<point_type> points;
0856 container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points));
0857
0858 if (boost::size(points) == 2)
0859 {
0860 geometry::detail::assign_point_to_index<0>(points.front(), segment);
0861 geometry::detail::assign_point_to_index<1>(points.back(), segment);
0862 }
0863 else
0864 {
0865 BOOST_THROW_EXCEPTION(read_wkt_exception("Segment should have 2 points", wkt));
0866 }
0867 }
0868 };
0869
0870
0871 struct dynamic_move_assign
0872 {
0873 template <typename DynamicGeometry, typename Geometry>
0874 static void apply(DynamicGeometry& dynamic_geometry, Geometry & geometry)
0875 {
0876 dynamic_geometry = std::move(geometry);
0877 }
0878 };
0879
0880 struct dynamic_move_emplace_back
0881 {
0882 template <typename GeometryCollection, typename Geometry>
0883 static void apply(GeometryCollection& geometry_collection, Geometry & geometry)
0884 {
0885 traits::emplace_back<GeometryCollection>::apply(geometry_collection, std::move(geometry));
0886 }
0887 };
0888
0889 template
0890 <
0891 typename Geometry,
0892 template <typename, typename> class ReadWkt,
0893 typename AppendPolicy
0894 >
0895 struct dynamic_readwkt_caller
0896 {
0897 template <typename TokenizerIterator>
0898 static inline void apply(TokenizerIterator& it,
0899 TokenizerIterator const& end,
0900 std::string const& wkt,
0901 Geometry& geometry)
0902 {
0903 static const char* tag_point = prefix_point::apply();
0904 static const char* tag_linestring = prefix_linestring::apply();
0905 static const char* tag_polygon = prefix_polygon::apply();
0906
0907 static const char* tag_multi_point = prefix_multipoint::apply();
0908 static const char* tag_multi_linestring = prefix_multilinestring::apply();
0909 static const char* tag_multi_polygon = prefix_multipolygon::apply();
0910
0911 static const char* tag_segment = prefix_segment::apply();
0912 static const char* tag_box = prefix_box::apply();
0913 static const char* tag_gc = prefix_geometrycollection::apply();
0914
0915 if (boost::iequals(*it, tag_point))
0916 {
0917 parse_geometry<util::is_point>(tag_point, it, end, wkt, geometry);
0918 }
0919 else if (boost::iequals(*it, tag_multi_point))
0920 {
0921 parse_geometry<util::is_multi_point>(tag_multi_point, it, end, wkt, geometry);
0922 }
0923 else if (boost::iequals(*it, tag_segment))
0924 {
0925 parse_geometry<util::is_segment>(tag_segment, it, end, wkt, geometry);
0926 }
0927 else if (boost::iequals(*it, tag_linestring))
0928 {
0929 parse_geometry<util::is_linestring>(tag_linestring, it, end, wkt, geometry, false)
0930 || parse_geometry<util::is_segment>(tag_linestring, it, end, wkt, geometry);
0931 }
0932 else if (boost::iequals(*it, tag_multi_linestring))
0933 {
0934 parse_geometry<util::is_multi_linestring>(tag_multi_linestring, it, end, wkt, geometry);
0935 }
0936 else if (boost::iequals(*it, tag_box))
0937 {
0938 parse_geometry<util::is_box>(tag_box, it, end, wkt, geometry);
0939 }
0940 else if (boost::iequals(*it, tag_polygon))
0941 {
0942 parse_geometry<util::is_polygon>(tag_polygon, it, end, wkt, geometry, false)
0943 || parse_geometry<util::is_ring>(tag_polygon, it, end, wkt, geometry, false)
0944 || parse_geometry<util::is_box>(tag_polygon, it, end, wkt, geometry);
0945 }
0946 else if (boost::iequals(*it, tag_multi_polygon))
0947 {
0948 parse_geometry<util::is_multi_polygon>(tag_multi_polygon, it, end, wkt, geometry);
0949 }
0950 else if (boost::iequals(*it, tag_gc))
0951 {
0952 parse_geometry<util::is_geometry_collection>(tag_gc, it, end, wkt, geometry);
0953 }
0954 else
0955 {
0956 BOOST_THROW_EXCEPTION(read_wkt_exception(
0957 "Should start with geometry's type, for example 'POINT', 'LINESTRING', 'POLYGON'",
0958 wkt));
0959 }
0960 }
0961
0962 private:
0963 template
0964 <
0965 template <typename> class UnaryPred,
0966 typename TokenizerIterator,
0967 typename Geom = typename util::sequence_find_if
0968 <
0969 typename traits::geometry_types<Geometry>::type, UnaryPred
0970 >::type,
0971 std::enable_if_t<! std::is_void<Geom>::value, int> = 0
0972 >
0973 static bool parse_geometry(const char * ,
0974 TokenizerIterator& it,
0975 TokenizerIterator const& end,
0976 std::string const& wkt,
0977 Geometry& geometry,
0978 bool = true)
0979 {
0980 Geom g;
0981 ReadWkt<Geom, tag_t<Geom>>::apply(it, end, wkt, g);
0982 AppendPolicy::apply(geometry, g);
0983 return true;
0984 }
0985
0986 template
0987 <
0988 template <typename> class UnaryPred,
0989 typename TokenizerIterator,
0990 typename Geom = typename util::sequence_find_if
0991 <
0992 typename traits::geometry_types<Geometry>::type, UnaryPred
0993 >::type,
0994 std::enable_if_t<std::is_void<Geom>::value, int> = 0
0995 >
0996 static bool parse_geometry(const char * name,
0997 TokenizerIterator& ,
0998 TokenizerIterator const& ,
0999 std::string const& wkt,
1000 Geometry& ,
1001 bool throw_on_misfit = true)
1002 {
1003 if (throw_on_misfit)
1004 {
1005 std::string msg = std::string("Unable to store '") + name + "' in this geometry";
1006 BOOST_THROW_EXCEPTION(read_wkt_exception(msg, wkt));
1007 }
1008
1009 return false;
1010 }
1011 };
1012
1013
1014 }}
1015 #endif
1016
1017 #ifndef DOXYGEN_NO_DISPATCH
1018 namespace dispatch
1019 {
1020
1021 template <typename Geometry, typename Tag = tag_t<Geometry>>
1022 struct read_wkt {};
1023
1024
1025 template <typename Point>
1026 struct read_wkt<Point, point_tag>
1027 : detail::wkt::geometry_parser
1028 <
1029 Point,
1030 detail::wkt::point_parser,
1031 detail::wkt::prefix_point
1032 >
1033 {};
1034
1035
1036 template <typename L>
1037 struct read_wkt<L, linestring_tag>
1038 : detail::wkt::geometry_parser
1039 <
1040 L,
1041 detail::wkt::linestring_parser,
1042 detail::wkt::prefix_linestring
1043 >
1044 {};
1045
1046 template <typename Ring>
1047 struct read_wkt<Ring, ring_tag>
1048 : detail::wkt::geometry_parser
1049 <
1050 Ring,
1051 detail::wkt::ring_parser,
1052 detail::wkt::prefix_polygon
1053 >
1054 {};
1055
1056 template <typename Geometry>
1057 struct read_wkt<Geometry, polygon_tag>
1058 : detail::wkt::geometry_parser
1059 <
1060 Geometry,
1061 detail::wkt::polygon_parser,
1062 detail::wkt::prefix_polygon
1063 >
1064 {};
1065
1066
1067 template <typename MultiGeometry>
1068 struct read_wkt<MultiGeometry, multi_point_tag>
1069 : detail::wkt::multi_point_parser
1070 <
1071 MultiGeometry,
1072 detail::wkt::prefix_multipoint
1073 >
1074 {};
1075
1076 template <typename MultiGeometry>
1077 struct read_wkt<MultiGeometry, multi_linestring_tag>
1078 : detail::wkt::multi_parser
1079 <
1080 MultiGeometry,
1081 detail::wkt::linestring_parser,
1082 detail::wkt::prefix_multilinestring
1083 >
1084 {};
1085
1086 template <typename MultiGeometry>
1087 struct read_wkt<MultiGeometry, multi_polygon_tag>
1088 : detail::wkt::multi_parser
1089 <
1090 MultiGeometry,
1091 detail::wkt::polygon_parser,
1092 detail::wkt::prefix_multipolygon
1093 >
1094 {};
1095
1096
1097
1098 template <typename Box>
1099 struct read_wkt<Box, box_tag>
1100 : detail::wkt::box_parser<Box>
1101 {};
1102
1103
1104 template <typename Segment>
1105 struct read_wkt<Segment, segment_tag>
1106 : detail::wkt::segment_parser<Segment>
1107 {};
1108
1109
1110 template <typename DynamicGeometry>
1111 struct read_wkt<DynamicGeometry, dynamic_geometry_tag>
1112 {
1113 static inline void apply(std::string const& wkt, DynamicGeometry& dynamic_geometry)
1114 {
1115 auto tokens{detail::wkt::make_tokenizer(wkt)};
1116 auto it = tokens.begin();
1117 auto const end = tokens.end();
1118 if (it == end)
1119 {
1120 BOOST_THROW_EXCEPTION(read_wkt_exception(
1121 "Should start with geometry's type, for example 'POINT', 'LINESTRING', 'POLYGON'",
1122 wkt));
1123 }
1124
1125 detail::wkt::dynamic_readwkt_caller
1126 <
1127 DynamicGeometry, dispatch::read_wkt, detail::wkt::dynamic_move_assign
1128 >::apply(it, end, wkt, dynamic_geometry);
1129
1130 detail::wkt::check_end(it, end, wkt);
1131 }
1132 };
1133
1134
1135 template <typename Geometry>
1136 struct read_wkt<Geometry, geometry_collection_tag>
1137 {
1138 static inline void apply(std::string const& wkt, Geometry& geometry)
1139 {
1140 range::clear(geometry);
1141
1142 auto tokens{detail::wkt::make_tokenizer(wkt)};
1143 auto it = tokens.begin();
1144 auto const end = tokens.end();
1145
1146 apply(it, end, wkt, geometry);
1147
1148 detail::wkt::check_end(it, end, wkt);
1149 }
1150
1151 template <typename TokenizerIterator>
1152 static inline void apply(TokenizerIterator& it,
1153 TokenizerIterator const& end,
1154 std::string const& wkt,
1155 Geometry& geometry)
1156 {
1157 if (detail::wkt::initialize<Geometry>(it, end, wkt,
1158 detail::wkt::prefix_geometrycollection::apply()))
1159 {
1160 detail::wkt::handle_open_parenthesis(it, end, wkt);
1161
1162
1163 while (it != end && *it != ")")
1164 {
1165 detail::wkt::dynamic_readwkt_caller
1166 <
1167 Geometry, dispatch::read_wkt, detail::wkt::dynamic_move_emplace_back
1168 >::apply(it, end, wkt, geometry);
1169
1170 if (it != end && *it == ",")
1171 {
1172
1173 ++it;
1174 }
1175 }
1176
1177 detail::wkt::handle_close_parenthesis(it, end, wkt);
1178 }
1179 }
1180 };
1181
1182
1183 }
1184 #endif
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195 template <typename Geometry>
1196 inline void read_wkt(std::string const& wkt, Geometry& geometry)
1197 {
1198 geometry::concepts::check<Geometry>();
1199 dispatch::read_wkt<Geometry>::apply(wkt, geometry);
1200 }
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210 template <typename Geometry>
1211 inline Geometry from_wkt(std::string const& wkt)
1212 {
1213 Geometry geometry;
1214 geometry::concepts::check<Geometry>();
1215 dispatch::read_wkt<Geometry>::apply(wkt, geometry);
1216 return geometry;
1217 }
1218
1219 }}
1220
1221 #endif