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