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
0021 #ifndef BOOST_GEOMETRY_IO_WKT_WRITE_HPP
0022 #define BOOST_GEOMETRY_IO_WKT_WRITE_HPP
0023
0024 #include <array>
0025 #include <ostream>
0026 #include <string>
0027
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
0033 #include <boost/geometry/algorithms/assign.hpp>
0034 #include <boost/geometry/algorithms/convert.hpp>
0035 #include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
0036 #include <boost/geometry/algorithms/not_implemented.hpp>
0037 #include <boost/geometry/core/exterior_ring.hpp>
0038 #include <boost/geometry/core/interior_rings.hpp>
0039 #include <boost/geometry/core/ring_type.hpp>
0040 #include <boost/geometry/core/tags.hpp>
0041 #include <boost/geometry/core/visit.hpp>
0042
0043 #include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
0044 #include <boost/geometry/geometries/concepts/check.hpp>
0045 #include <boost/geometry/geometries/ring.hpp>
0046
0047 #include <boost/geometry/io/wkt/detail/prefix.hpp>
0048
0049 #include <boost/geometry/strategies/io/cartesian.hpp>
0050 #include <boost/geometry/strategies/io/geographic.hpp>
0051 #include <boost/geometry/strategies/io/spherical.hpp>
0052
0053 #include <boost/geometry/util/constexpr.hpp>
0054 #include <boost/geometry/util/type_traits.hpp>
0055
0056
0057 namespace boost { namespace geometry
0058 {
0059
0060
0061 #if defined(_MSC_VER)
0062 #pragma warning(push)
0063 #pragma warning(disable : 4512)
0064 #endif
0065
0066 #ifndef DOXYGEN_NO_DETAIL
0067 namespace detail { namespace wkt
0068 {
0069
0070 template <typename P, int I, int Count>
0071 struct stream_coordinate
0072 {
0073 template <typename Char, typename Traits>
0074 static inline void apply(std::basic_ostream<Char, Traits>& os, P const& p)
0075 {
0076 os << (I > 0 ? " " : "") << get<I>(p);
0077 stream_coordinate<P, I + 1, Count>::apply(os, p);
0078 }
0079 };
0080
0081 template <typename P, int Count>
0082 struct stream_coordinate<P, Count, Count>
0083 {
0084 template <typename Char, typename Traits>
0085 static inline void apply(std::basic_ostream<Char, Traits>&, P const&)
0086 {}
0087 };
0088
0089
0090
0091
0092 template <typename Point, typename Policy>
0093 struct wkt_point
0094 {
0095 template <typename Char, typename Traits>
0096 static inline void apply(std::basic_ostream<Char, Traits>& os, Point const& p, bool)
0097 {
0098 os << Policy::apply() << "(";
0099 stream_coordinate<Point, 0, dimension<Point>::type::value>::apply(os, p);
0100 os << ")";
0101 }
0102 };
0103
0104
0105
0106
0107 template
0108 <
0109 typename Range,
0110 typename PrefixPolicy,
0111 bool ForceClosurePossible = false,
0112 bool WriteDoubleBrackets = false
0113 >
0114 struct wkt_range
0115 {
0116 template <typename Char, typename Traits>
0117 static inline void apply(std::basic_ostream<Char, Traits>& os,
0118 Range const& range, bool force_closure = ForceClosurePossible)
0119 {
0120 using stream_type = stream_coordinate
0121 <
0122 point_type, 0, dimension<point_type>::type::value
0123 >;
0124
0125 bool first = true;
0126
0127 os << PrefixPolicy::apply();
0128 os << "(";
0129
0130 if (boost::size(range) > 0)
0131 {
0132 if BOOST_GEOMETRY_CONSTEXPR (WriteDoubleBrackets)
0133 {
0134 os << "(";
0135 }
0136 auto begin = boost::begin(range);
0137 auto const end = boost::end(range);
0138 for (auto it = begin; it != end; ++it)
0139 {
0140 os << (first ? "" : ",");
0141 stream_type::apply(os, *it);
0142 first = false;
0143 }
0144
0145
0146 if BOOST_GEOMETRY_CONSTEXPR (ForceClosurePossible)
0147 {
0148 if (force_closure
0149 && boost::size(range) > 1
0150 && wkt_range::disjoint(*begin, *(end - 1)))
0151 {
0152 os << ",";
0153 stream_type::apply(os, *begin);
0154 }
0155 }
0156 if BOOST_GEOMETRY_CONSTEXPR (WriteDoubleBrackets)
0157 {
0158 os << ")";
0159 }
0160 }
0161
0162 os << ")";
0163 }
0164
0165
0166 private:
0167 using point_type = typename boost::range_value<Range>::type;
0168
0169 static inline bool disjoint(point_type const& p1, point_type const& p2)
0170 {
0171
0172 using strategy_type = typename strategies::io::services::default_strategy
0173 <
0174 point_type
0175 >::type;
0176
0177 return detail::disjoint::disjoint_point_point(p1, p2, strategy_type());
0178 }
0179 };
0180
0181
0182
0183
0184
0185 template <typename Range, bool ForceClosurePossible = true>
0186 struct wkt_sequence
0187 : wkt_range
0188 <
0189 Range,
0190 prefix_null,
0191 ForceClosurePossible
0192 >
0193 {};
0194
0195 template <typename Polygon, typename PrefixPolicy>
0196 struct wkt_poly
0197 {
0198 template <typename Char, typename Traits>
0199 static inline void apply(std::basic_ostream<Char, Traits>& os,
0200 Polygon const& poly, bool force_closure)
0201 {
0202 using ring = typename ring_type<Polygon const>::type;
0203
0204 auto const& exterior = exterior_ring(poly);
0205 auto const& rings = interior_rings(poly);
0206
0207 std::size_t point_count = boost::size(exterior);
0208 for (auto it = boost::begin(rings); it != boost::end(rings); ++it)
0209 {
0210 point_count += boost::size(*it);
0211 }
0212
0213 os << PrefixPolicy::apply();
0214
0215 os << "(";
0216 if (point_count > 0)
0217 {
0218 wkt_sequence<ring>::apply(os, exterior, force_closure);
0219
0220 for (auto it = boost::begin(rings); it != boost::end(rings); ++it)
0221 {
0222 os << ",";
0223 wkt_sequence<ring>::apply(os, *it, force_closure);
0224 }
0225 }
0226 os << ")";
0227 }
0228
0229 };
0230
0231 template <typename Multi, typename StreamPolicy, typename PrefixPolicy>
0232 struct wkt_multi
0233 {
0234 template <typename Char, typename Traits>
0235 static inline void apply(std::basic_ostream<Char, Traits>& os,
0236 Multi const& geometry, bool force_closure)
0237 {
0238 os << PrefixPolicy::apply();
0239 os << "(";
0240
0241 for (auto it = boost::begin(geometry); it != boost::end(geometry); ++it)
0242 {
0243 if (it != boost::begin(geometry))
0244 {
0245 os << ",";
0246 }
0247 StreamPolicy::apply(os, *it, force_closure);
0248 }
0249
0250 os << ")";
0251 }
0252 };
0253
0254 template <typename Box>
0255 struct wkt_box
0256 {
0257 using point_type = typename point_type<Box>::type;
0258
0259 template <typename Char, typename Traits>
0260 static inline void apply(std::basic_ostream<Char, Traits>& os,
0261 Box const& box, bool force_closure)
0262 {
0263
0264
0265
0266 if (force_closure)
0267 {
0268 do_apply<model::ring<point_type, true, true> >(os, box);
0269 }
0270 else
0271 {
0272 do_apply<model::ring<point_type, true, false> >(os, box);
0273 }
0274 }
0275
0276 private:
0277
0278 inline wkt_box()
0279 {
0280
0281
0282 }
0283
0284 template <typename RingType, typename Char, typename Traits>
0285 static inline void do_apply(std::basic_ostream<Char, Traits>& os,
0286 Box const& box)
0287 {
0288 RingType ring;
0289 geometry::convert(box, ring);
0290 os << "POLYGON(";
0291 wkt_sequence<RingType, false>::apply(os, ring);
0292 os << ")";
0293 }
0294
0295 };
0296
0297
0298 template <typename Segment>
0299 struct wkt_segment
0300 {
0301 using point_type = typename point_type<Segment>::type;
0302
0303 template <typename Char, typename Traits>
0304 static inline void apply(std::basic_ostream<Char, Traits>& os,
0305 Segment const& segment, bool)
0306 {
0307
0308 using sequence = std::array<point_type, 2>;
0309
0310 sequence points;
0311 geometry::detail::assign_point_from_index<0>(segment, points[0]);
0312 geometry::detail::assign_point_from_index<1>(segment, points[1]);
0313
0314
0315
0316 os << "LINESTRING";
0317 wkt_sequence<sequence, false>::apply(os, points);
0318 }
0319
0320 private:
0321
0322 inline wkt_segment()
0323 {}
0324 };
0325
0326 }}
0327 #endif
0328
0329 #ifndef DOXYGEN_NO_DISPATCH
0330 namespace dispatch
0331 {
0332
0333 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
0334 struct wkt: not_implemented<Tag>
0335 {};
0336
0337 template <typename Point>
0338 struct wkt<Point, point_tag>
0339 : detail::wkt::wkt_point
0340 <
0341 Point,
0342 detail::wkt::prefix_point
0343 >
0344 {};
0345
0346 template <typename Linestring>
0347 struct wkt<Linestring, linestring_tag>
0348 : detail::wkt::wkt_range
0349 <
0350 Linestring,
0351 detail::wkt::prefix_linestring
0352 >
0353 {};
0354
0355
0356
0357
0358
0359
0360 template <typename Box>
0361 struct wkt<Box, box_tag>
0362 : detail::wkt::wkt_box<Box>
0363 {};
0364
0365 template <typename Segment>
0366 struct wkt<Segment, segment_tag>
0367 : detail::wkt::wkt_segment<Segment>
0368 {};
0369
0370
0371
0372
0373
0374
0375
0376 template <typename Ring>
0377 struct wkt<Ring, ring_tag>
0378 : detail::wkt::wkt_range
0379 <
0380 Ring,
0381 detail::wkt::prefix_polygon,
0382 true,
0383 true
0384 >
0385 {};
0386
0387
0388
0389
0390 template <typename Polygon>
0391 struct wkt<Polygon, polygon_tag>
0392 : detail::wkt::wkt_poly
0393 <
0394 Polygon,
0395 detail::wkt::prefix_polygon
0396 >
0397 {};
0398
0399 template <typename Multi>
0400 struct wkt<Multi, multi_point_tag>
0401 : detail::wkt::wkt_multi
0402 <
0403 Multi,
0404 detail::wkt::wkt_point
0405 <
0406 typename boost::range_value<Multi>::type,
0407 detail::wkt::prefix_null
0408 >,
0409 detail::wkt::prefix_multipoint
0410 >
0411 {};
0412
0413 template <typename Multi>
0414 struct wkt<Multi, multi_linestring_tag>
0415 : detail::wkt::wkt_multi
0416 <
0417 Multi,
0418 detail::wkt::wkt_sequence
0419 <
0420 typename boost::range_value<Multi>::type,
0421 false
0422 >,
0423 detail::wkt::prefix_multilinestring
0424 >
0425 {};
0426
0427 template <typename Multi>
0428 struct wkt<Multi, multi_polygon_tag>
0429 : detail::wkt::wkt_multi
0430 <
0431 Multi,
0432 detail::wkt::wkt_poly
0433 <
0434 typename boost::range_value<Multi>::type,
0435 detail::wkt::prefix_null
0436 >,
0437 detail::wkt::prefix_multipolygon
0438 >
0439 {};
0440
0441
0442 template <typename Geometry>
0443 struct wkt<Geometry, dynamic_geometry_tag>
0444 {
0445 template <typename OutputStream>
0446 static inline void apply(OutputStream& os, Geometry const& geometry,
0447 bool force_closure)
0448 {
0449 traits::visit<Geometry>::apply([&](auto const& g)
0450 {
0451 wkt<util::remove_cref_t<decltype(g)>>::apply(os, g, force_closure);
0452 }, geometry);
0453 }
0454 };
0455
0456
0457 template <typename Geometry>
0458 struct wkt<Geometry, geometry_collection_tag>
0459 {
0460 template <typename OutputStream>
0461 static inline void apply(OutputStream& os, Geometry const& geometry,
0462 bool force_closure)
0463 {
0464 wkt::output_or_recursive_call(os, geometry, force_closure);
0465 }
0466
0467 private:
0468 template
0469 <
0470 typename OutputStream, typename Geom,
0471 std::enable_if_t<util::is_geometry_collection<Geom>::value, int> = 0
0472 >
0473 static void output_or_recursive_call(OutputStream& os, Geom const& geom, bool force_closure)
0474 {
0475 os << "GEOMETRYCOLLECTION(";
0476
0477 bool first = true;
0478 auto const end = boost::end(geom);
0479 for (auto it = boost::begin(geom); it != end; ++it)
0480 {
0481 if (first)
0482 first = false;
0483 else
0484 os << ',';
0485
0486 traits::iter_visit<Geom>::apply([&](auto const& g)
0487 {
0488 wkt::output_or_recursive_call(os, g, force_closure);
0489 }, it);
0490 }
0491
0492 os << ')';
0493 }
0494
0495 template
0496 <
0497 typename OutputStream, typename Geom,
0498 std::enable_if_t<! util::is_geometry_collection<Geom>::value, int> = 0
0499 >
0500 static void output_or_recursive_call(OutputStream& os, Geom const& geom, bool force_closure)
0501 {
0502 wkt<Geom>::apply(os, geom, force_closure);
0503 }
0504 };
0505
0506
0507 }
0508 #endif
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521 template <typename Geometry>
0522 class wkt_manipulator
0523 {
0524 static const bool is_ring = util::is_ring<Geometry>::value;
0525
0526 public:
0527
0528
0529
0530 inline wkt_manipulator(Geometry const& g,
0531 bool force_closure = ! is_ring)
0532 : m_geometry(g)
0533 , m_force_closure(force_closure)
0534 {}
0535
0536 template <typename Char, typename Traits>
0537 inline friend std::basic_ostream<Char, Traits>& operator<<(
0538 std::basic_ostream<Char, Traits>& os,
0539 wkt_manipulator const& m)
0540 {
0541 dispatch::wkt<Geometry>::apply(os, m.m_geometry, m.m_force_closure);
0542 os.flush();
0543 return os;
0544 }
0545
0546 private:
0547 Geometry const& m_geometry;
0548 bool m_force_closure;
0549 };
0550
0551
0552
0553
0554
0555
0556
0557
0558 template <typename Geometry>
0559 inline wkt_manipulator<Geometry> wkt(Geometry const& geometry)
0560 {
0561 concepts::check<Geometry const>();
0562
0563 return wkt_manipulator<Geometry>(geometry);
0564 }
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574 template <typename Geometry>
0575 inline std::string to_wkt(Geometry const& geometry)
0576 {
0577 std::stringstream ss;
0578 ss << boost::geometry::wkt(geometry);
0579 return ss.str();
0580 }
0581
0582 template <typename Geometry>
0583 inline std::string to_wkt(Geometry const& geometry, int significant_digits)
0584 {
0585 std::stringstream ss;
0586 ss.precision(significant_digits);
0587 ss << boost::geometry::wkt(geometry);
0588 return ss.str();
0589 }
0590
0591 #if defined(_MSC_VER)
0592 #pragma warning(pop)
0593 #endif
0594
0595 }}
0596
0597 #endif