Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:35:35

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 \ref 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 = 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         // 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 = 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         // 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 = 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 \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 \ref 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 \param significant_digits Specifies the no of significant digits to use in the output wkt
0571 \ingroup wkt
0572 \qbk{[include reference/io/to_wkt.qbk]}
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 }} // namespace boost::geometry
0596 
0597 #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP