Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 08:43:20

0001 // Boost.Geometry (aka GGL, Generic Geometry Library)
0002 
0003 // Copyright (c) 2007-2022 Barend Gehrels, Amsterdam, the Netherlands.
0004 // Copyright (c) 2008-2017 Bruno Lalande, Paris, France.
0005 // Copyright (c) 2009-2017 Mateusz Loskot, London, UK.
0006 // Copyright (c) 2014-2023 Adam Wulkiewicz, Lodz, Poland.
0007 // Copyright (c) 2020 Baidyanath Kundu, Haldia, India.
0008 
0009 // This file was modified by Oracle on 2015-2021.
0010 // Modifications copyright (c) 2015-2021, Oracle and/or its affiliates.
0011 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
0012 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
0013 
0014 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
0015 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
0016 
0017 // Use, modification and distribution is subject to the Boost Software License,
0018 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0019 // http://www.boost.org/LICENSE_1_0.txt)
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 // Silence warning C4512: 'boost::geometry::wkt_manipulator<Geometry>' : assignment operator could not be generated
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 \brief Stream points as \wkt
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 \brief Stream ranges as WKT
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             // optionally, close range to ring by repeating the first point
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         // TODO: pass strategy
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 \brief Stream sequence of points as WKT-part, e.g. (1 2),(3 4)
0183 \note Used in polygon, all multi-geometries
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_t = ring_type_t<Polygon const>;
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_t>::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_t>::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 = point_type_t<Box>;
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         // Convert to a clockwire ring, then stream.
0264         // Never close it based on last point (box might be empty and
0265         // that should result in POLYGON((0 0,0 0,0 0,0 0, ...)) )
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             // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron!
0281             //assert_dimension<B, 2>();
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 = point_type_t<Segment>;
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         // Convert to two points, then stream
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         // In Boost.Geometry a segment is represented
0315         // in WKT-format like (for 2D): LINESTRING(x y,x y)
0316         os << "LINESTRING";
0317         wkt_sequence<sequence, false>::apply(os, points);
0318     }
0319 
0320     private:
0321 
0322         inline wkt_segment()
0323         {}
0324 };
0325 
0326 }} // namespace detail::wkt
0327 #endif // DOXYGEN_NO_DETAIL
0328 
0329 #ifndef DOXYGEN_NO_DISPATCH
0330 namespace dispatch
0331 {
0332 
0333 template <typename Geometry, typename Tag = tag_t<Geometry>>
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 \brief Specialization to stream a box as WKT
0357 \details A "box" does not exist in WKT.
0358 It is therefore streamed as a polygon
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 \brief Specialization to stream a ring as WKT
0372 \details A ring or "linear_ring" does not exist in WKT.
0373 A ring is equivalent to a polygon without inner rings
0374 It is therefore streamed as a polygon
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 \brief Specialization to stream polygon as WKT
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 // TODO: Implement non-recursive version
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 } // namespace dispatch
0508 #endif // DOXYGEN_NO_DISPATCH
0509 
0510 /*!
0511 \brief Generic geometry template manipulator class, takes corresponding output class from traits class
0512 \ingroup wkt
0513 \details Stream manipulator, streams geometry classes as \wkt streams
0514 \par Example:
0515 Small example showing how to use the wkt class
0516 \dontinclude doxygen_1.cpp
0517 \skip example_as_wkt_point
0518 \line {
0519 \until }
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     // Boost.Geometry, by default, closes polygons explictly, but not rings
0529     // NOTE: this might change in the future!
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 \brief Main WKT-streaming function
0553 \tparam Geometry \tparam_geometry
0554 \param geometry \param_geometry
0555 \ingroup wkt
0556 \qbk{[include reference/io/wkt.qbk]}
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 \brief WKT-string formulating function
0568 \tparam Geometry \tparam_geometry
0569 \param geometry \param_geometry
0570 \ingroup wkt
0571 \qbk{[include reference/io/to_wkt.qbk]}
0572 */
0573 template <typename Geometry>
0574 inline std::string to_wkt(Geometry const& geometry)
0575 {
0576     std::stringstream ss;
0577     ss << boost::geometry::wkt(geometry);
0578     return ss.str();
0579 }
0580 
0581 /*!
0582 \brief WKT-string formulating function (with significant digits)
0583 \tparam Geometry \tparam_geometry
0584 \param geometry \param_geometry
0585 \param significant_digits Specifies the number of significant digits to use in the output wkt
0586 \ingroup wkt
0587 \qbk{distinguish, with significant digits}
0588 */
0589 template <typename Geometry>
0590 inline std::string to_wkt(Geometry const& geometry, int significant_digits)
0591 {
0592     std::stringstream ss;
0593     ss.precision(significant_digits);
0594     ss << boost::geometry::wkt(geometry);
0595     return ss.str();
0596 }
0597 
0598 #if defined(_MSC_VER)
0599 #pragma warning(pop)
0600 #endif
0601 
0602 }} // namespace boost::geometry
0603 
0604 #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP