Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-16 08:34:23

0001 // Boost.Geometry (aka GGL, Generic Geometry Library)
0002 
0003 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
0004 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
0005 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
0006 // Copyright (c) 2014-2024 Adam Wulkiewicz, Lodz, Poland.
0007 
0008 // This file was modified by Oracle on 2017-2023.
0009 // Modifications copyright (c) 2017-2023, Oracle and/or its affiliates.
0010 // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
0011 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
0012 
0013 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
0014 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
0015 
0016 // Use, modification and distribution is subject to the Boost Software License,
0017 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0018 // http://www.boost.org/LICENSE_1_0.txt)
0019 
0020 #ifndef BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP
0021 #define BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP
0022 
0023 
0024 #include <cstddef>
0025 #include <type_traits>
0026 
0027 #include <boost/range/begin.hpp>
0028 #include <boost/range/end.hpp>
0029 #include <boost/range/size.hpp>
0030 #include <boost/range/value_type.hpp>
0031 #include <boost/variant/static_visitor.hpp>
0032 #include <boost/variant/variant_fwd.hpp>
0033 
0034 #include <boost/geometry/algorithms/clear.hpp>
0035 #include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
0036 #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
0037 #include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
0038 #include <boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp>
0039 #include <boost/geometry/algorithms/not_implemented.hpp>
0040 
0041 #include <boost/geometry/core/closure.hpp>
0042 #include <boost/geometry/core/point_order.hpp>
0043 #include <boost/geometry/core/tag_cast.hpp>
0044 #include <boost/geometry/core/tags.hpp>
0045 
0046 #include <boost/geometry/geometries/concepts/check.hpp>
0047 
0048 #include <boost/geometry/util/numeric_cast.hpp>
0049 #include <boost/geometry/util/range.hpp>
0050 
0051 #include <boost/geometry/views/detail/closed_clockwise_view.hpp>
0052 
0053 
0054 namespace boost { namespace geometry
0055 {
0056 
0057 // Silence warning C4127: conditional expression is constant
0058 // Silence warning C4512: assignment operator could not be generated
0059 #if defined(_MSC_VER)
0060 #pragma warning(push)
0061 #pragma warning(disable : 4127 4512)
0062 #endif
0063 
0064 
0065 #ifndef DOXYGEN_NO_DETAIL
0066 namespace detail { namespace conversion
0067 {
0068 
0069 template
0070 <
0071     typename Point,
0072     typename Box,
0073     std::size_t Index,
0074     std::size_t Dimension,
0075     std::size_t DimensionCount
0076 >
0077 struct point_to_box
0078 {
0079     static inline void apply(Point const& point, Box& box)
0080     {
0081         set<Index, Dimension>(box,
0082                 util::numeric_cast<coordinate_type_t<Box>>(get<Dimension>(point)));
0083         point_to_box
0084             <
0085                 Point, Box,
0086                 Index, Dimension + 1, DimensionCount
0087             >::apply(point, box);
0088     }
0089 };
0090 
0091 
0092 template
0093 <
0094     typename Point,
0095     typename Box,
0096     std::size_t Index,
0097     std::size_t DimensionCount
0098 >
0099 struct point_to_box<Point, Box, Index, DimensionCount, DimensionCount>
0100 {
0101     static inline void apply(Point const& , Box& )
0102     {}
0103 };
0104 
0105 template <typename Box, typename Range, bool Close, bool Reverse>
0106 struct box_to_range
0107 {
0108     static inline void apply(Box const& box, Range& range)
0109     {
0110         traits::resize<Range>::apply(range, Close ? 5 : 4);
0111         assign_box_corners_oriented<Reverse>(box, range);
0112         if (Close)
0113         {
0114             range::at(range, 4) = range::at(range, 0);
0115         }
0116     }
0117 };
0118 
0119 template <typename Segment, typename Range>
0120 struct segment_to_range
0121 {
0122     static inline void apply(Segment const& segment, Range& range)
0123     {
0124         traits::resize<Range>::apply(range, 2);
0125 
0126         auto it = boost::begin(range);
0127 
0128         assign_point_from_index<0>(segment, *it);
0129         ++it;
0130         assign_point_from_index<1>(segment, *it);
0131     }
0132 };
0133 
0134 template
0135 <
0136     typename Range1,
0137     typename Range2,
0138     bool Reverse = false
0139 >
0140 struct range_to_range
0141 {
0142     struct default_policy
0143     {
0144         template <typename Point1, typename Point2>
0145         static inline void apply(Point1 const& point1, Point2 & point2)
0146         {
0147             geometry::detail::conversion::convert_point_to_point(point1, point2);
0148         }
0149     };
0150 
0151     static inline void apply(Range1 const& source, Range2& destination)
0152     {
0153         apply(source, destination, default_policy());
0154     }
0155 
0156     template <typename ConvertPointPolicy>
0157     static inline ConvertPointPolicy apply(Range1 const& source, Range2& destination,
0158                                            ConvertPointPolicy convert_point)
0159     {
0160         geometry::clear(destination);
0161 
0162         using view_type = detail::closed_clockwise_view
0163             <
0164                 Range1 const,
0165                 geometry::closure<Range1>::value,
0166                 Reverse ? counterclockwise : clockwise
0167             >;
0168 
0169         // We consider input always as closed, and skip last
0170         // point for open output.
0171         view_type const view(source);
0172 
0173         auto n = boost::size(view);
0174         if (geometry::closure<Range2>::value == geometry::open)
0175         {
0176             n--;
0177         }
0178 
0179         // If size == 0 && geometry::open <=> n = numeric_limits<size_type>::max()
0180         // but ok, sice below it == end()
0181 
0182         decltype(n) i = 0;
0183         for (auto it = boost::begin(view);
0184             it != boost::end(view) && i < n;
0185             ++it, ++i)
0186         {
0187             typename boost::range_value<Range2>::type point;
0188             convert_point.apply(*it, point);
0189             range::push_back(destination, point);
0190         }
0191 
0192         return convert_point;
0193     }
0194 };
0195 
0196 template <typename Polygon1, typename Polygon2>
0197 struct polygon_to_polygon
0198 {
0199     using per_ring = range_to_range
0200         <
0201             geometry::ring_type_t<Polygon1>,
0202             geometry::ring_type_t<Polygon2>,
0203             geometry::point_order<Polygon1>::value != geometry::point_order<Polygon2>::value
0204         >;
0205 
0206     static inline void apply(Polygon1 const& source, Polygon2& destination)
0207     {
0208         // Clearing managed per ring, and in the resizing of interior rings
0209 
0210         per_ring::apply(geometry::exterior_ring(source),
0211             geometry::exterior_ring(destination));
0212 
0213         // Container should be resizeable
0214         traits::resize
0215             <
0216                 std::remove_reference_t
0217                     <
0218                         typename traits::interior_mutable_type<Polygon2>::type
0219                     >
0220             >::apply(interior_rings(destination), num_interior_rings(source));
0221 
0222         auto const& rings_source = interior_rings(source);
0223         auto&& rings_dest = interior_rings(destination);
0224 
0225         auto it_source = boost::begin(rings_source);
0226         auto it_dest = boost::begin(rings_dest);
0227 
0228         for ( ; it_source != boost::end(rings_source); ++it_source, ++it_dest)
0229         {
0230             per_ring::apply(*it_source, *it_dest);
0231         }
0232     }
0233 };
0234 
0235 template <typename Single, typename Multi, typename Policy>
0236 struct single_to_multi: private Policy
0237 {
0238     static inline void apply(Single const& single, Multi& multi)
0239     {
0240         traits::resize<Multi>::apply(multi, 1);
0241         Policy::apply(single, *boost::begin(multi));
0242     }
0243 };
0244 
0245 
0246 
0247 template <typename Multi1, typename Multi2, typename Policy>
0248 struct multi_to_multi: private Policy
0249 {
0250     static inline void apply(Multi1 const& multi1, Multi2& multi2)
0251     {
0252         traits::resize<Multi2>::apply(multi2, boost::size(multi1));
0253 
0254         auto it1 = boost::begin(multi1);
0255         auto it2 = boost::begin(multi2);
0256 
0257         for (; it1 != boost::end(multi1); ++it1, ++it2)
0258         {
0259             Policy::apply(*it1, *it2);
0260         }
0261     }
0262 };
0263 
0264 
0265 }} // namespace detail::conversion
0266 #endif // DOXYGEN_NO_DETAIL
0267 
0268 
0269 #ifndef DOXYGEN_NO_DISPATCH
0270 namespace dispatch
0271 {
0272 
0273 // TODO: We could use std::is_assignable instead of std::is_same.
0274 //   Then we should rather check ! std::is_array<Geometry2>::value
0275 //   which is Destination.
0276 
0277 template
0278 <
0279     typename Geometry1, typename Geometry2,
0280     typename Tag1 = tag_cast_t<tag_t<Geometry1>, multi_tag>,
0281     typename Tag2 = tag_cast_t<tag_t<Geometry2>, multi_tag>,
0282     std::size_t DimensionCount = dimension<Geometry1>::value,
0283     bool UseAssignment = std::is_same<Geometry1, Geometry2>::value
0284                          && !std::is_array<Geometry1>::value
0285 >
0286 struct convert
0287     : not_implemented
0288         <
0289             Tag1, Tag2,
0290             std::integral_constant<std::size_t, DimensionCount>
0291         >
0292 {};
0293 
0294 
0295 template
0296 <
0297     typename Geometry1, typename Geometry2,
0298     typename Tag,
0299     std::size_t DimensionCount
0300 >
0301 struct convert<Geometry1, Geometry2, Tag, Tag, DimensionCount, true>
0302 {
0303     // Same geometry type -> copy whole geometry
0304     static inline void apply(Geometry1 const& source, Geometry2& destination)
0305     {
0306         destination = source;
0307     }
0308 };
0309 
0310 
0311 template
0312 <
0313     typename Geometry1, typename Geometry2,
0314     std::size_t DimensionCount
0315 >
0316 struct convert<Geometry1, Geometry2, point_tag, point_tag, DimensionCount, false>
0317     : detail::conversion::point_to_point<Geometry1, Geometry2, 0, DimensionCount>
0318 {};
0319 
0320 
0321 template
0322 <
0323     typename Box1, typename Box2,
0324     std::size_t DimensionCount
0325 >
0326 struct convert<Box1, Box2, box_tag, box_tag, DimensionCount, false>
0327     : detail::conversion::indexed_to_indexed<Box1, Box2, 0, DimensionCount>
0328 {};
0329 
0330 
0331 template
0332 <
0333     typename Segment1, typename Segment2,
0334     std::size_t DimensionCount
0335 >
0336 struct convert<Segment1, Segment2, segment_tag, segment_tag, DimensionCount, false>
0337     : detail::conversion::indexed_to_indexed<Segment1, Segment2, 0, DimensionCount>
0338 {};
0339 
0340 
0341 template <typename Segment, typename LineString, std::size_t DimensionCount>
0342 struct convert<Segment, LineString, segment_tag, linestring_tag, DimensionCount, false>
0343     : detail::conversion::segment_to_range<Segment, LineString>
0344 {};
0345 
0346 
0347 template <typename Ring1, typename Ring2, std::size_t DimensionCount>
0348 struct convert<Ring1, Ring2, ring_tag, ring_tag, DimensionCount, false>
0349     : detail::conversion::range_to_range
0350         <
0351             Ring1,
0352             Ring2,
0353             geometry::point_order<Ring1>::value != geometry::point_order<Ring2>::value
0354         >
0355 {};
0356 
0357 template <typename LineString1, typename LineString2, std::size_t DimensionCount>
0358 struct convert<LineString1, LineString2, linestring_tag, linestring_tag, DimensionCount, false>
0359     : detail::conversion::range_to_range<LineString1, LineString2>
0360 {};
0361 
0362 template <typename Polygon1, typename Polygon2, std::size_t DimensionCount>
0363 struct convert<Polygon1, Polygon2, polygon_tag, polygon_tag, DimensionCount, false>
0364     : detail::conversion::polygon_to_polygon<Polygon1, Polygon2>
0365 {};
0366 
0367 template <typename Box, typename Ring>
0368 struct convert<Box, Ring, box_tag, ring_tag, 2, false>
0369     : detail::conversion::box_to_range
0370         <
0371             Box,
0372             Ring,
0373             geometry::closure<Ring>::value == closed,
0374             geometry::point_order<Ring>::value == counterclockwise
0375         >
0376 {};
0377 
0378 
0379 template <typename Box, typename Polygon>
0380 struct convert<Box, Polygon, box_tag, polygon_tag, 2, false>
0381 {
0382     static inline void apply(Box const& box, Polygon& polygon)
0383     {
0384         convert
0385             <
0386                 Box, ring_type_t<Polygon>,
0387                 box_tag, ring_tag,
0388                 2, false
0389             >::apply(box, exterior_ring(polygon));
0390     }
0391 };
0392 
0393 
0394 template <typename Point, typename Box, std::size_t DimensionCount>
0395 struct convert<Point, Box, point_tag, box_tag, DimensionCount, false>
0396 {
0397     static inline void apply(Point const& point, Box& box)
0398     {
0399         detail::conversion::point_to_box
0400             <
0401                 Point, Box, min_corner, 0, DimensionCount
0402             >::apply(point, box);
0403         detail::conversion::point_to_box
0404             <
0405                 Point, Box, max_corner, 0, DimensionCount
0406             >::apply(point, box);
0407     }
0408 };
0409 
0410 
0411 template <typename Ring, typename Polygon, std::size_t DimensionCount>
0412 struct convert<Ring, Polygon, ring_tag, polygon_tag, DimensionCount, false>
0413 {
0414     static inline void apply(Ring const& ring, Polygon& polygon)
0415     {
0416         convert
0417             <
0418                 Ring, ring_type_t<Polygon>,
0419                 ring_tag, ring_tag,
0420                 DimensionCount, false
0421             >::apply(ring, exterior_ring(polygon));
0422     }
0423 };
0424 
0425 
0426 template <typename Polygon, typename Ring, std::size_t DimensionCount>
0427 struct convert<Polygon, Ring, polygon_tag, ring_tag, DimensionCount, false>
0428 {
0429     static inline void apply(Polygon const& polygon, Ring& ring)
0430     {
0431         convert
0432             <
0433                 ring_type_t<Polygon>, Ring,
0434                 ring_tag, ring_tag,
0435                 DimensionCount, false
0436             >::apply(exterior_ring(polygon), ring);
0437     }
0438 };
0439 
0440 
0441 // Dispatch for multi <-> multi, specifying their single-version as policy.
0442 // Note that, even if the multi-types are mutually different, their single
0443 // version types might be the same and therefore we call std::is_same again
0444 
0445 template <typename Multi1, typename Multi2, std::size_t DimensionCount>
0446 struct convert<Multi1, Multi2, multi_tag, multi_tag, DimensionCount, false>
0447     : detail::conversion::multi_to_multi
0448         <
0449             Multi1,
0450             Multi2,
0451             convert
0452                 <
0453                     typename boost::range_value<Multi1>::type,
0454                     typename boost::range_value<Multi2>::type,
0455                     single_tag_of_t<tag_t<Multi1>>,
0456                     single_tag_of_t<tag_t<Multi2>>,
0457                     DimensionCount
0458                 >
0459         >
0460 {};
0461 
0462 
0463 template <typename Single, typename Multi, typename SingleTag, std::size_t DimensionCount>
0464 struct convert<Single, Multi, SingleTag, multi_tag, DimensionCount, false>
0465     : detail::conversion::single_to_multi
0466         <
0467             Single,
0468             Multi,
0469             convert
0470                 <
0471                     Single,
0472                     typename boost::range_value<Multi>::type,
0473                     tag_t<Single>,
0474                     single_tag_of_t<tag_t<Multi>>,
0475                     DimensionCount,
0476                     false
0477                 >
0478         >
0479 {};
0480 
0481 
0482 } // namespace dispatch
0483 #endif // DOXYGEN_NO_DISPATCH
0484 
0485 
0486 namespace resolve_variant {
0487 
0488 template <typename Geometry1, typename Geometry2>
0489 struct convert
0490 {
0491     static inline void apply(Geometry1 const& geometry1, Geometry2& geometry2)
0492     {
0493         concepts::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2>();
0494         dispatch::convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
0495     }
0496 };
0497 
0498 template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
0499 struct convert<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
0500 {
0501     struct visitor: static_visitor<void>
0502     {
0503         Geometry2& m_geometry2;
0504 
0505         visitor(Geometry2& geometry2)
0506             : m_geometry2(geometry2)
0507         {}
0508 
0509         template <typename Geometry1>
0510         inline void operator()(Geometry1 const& geometry1) const
0511         {
0512             convert<Geometry1, Geometry2>::apply(geometry1, m_geometry2);
0513         }
0514     };
0515 
0516     static inline void apply(
0517         boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
0518         Geometry2& geometry2
0519     )
0520     {
0521         boost::apply_visitor(visitor(geometry2), geometry1);
0522     }
0523 };
0524 
0525 }
0526 
0527 
0528 /*!
0529 \brief Converts one geometry to another geometry
0530 \details The convert algorithm converts one geometry, e.g. a BOX, to another
0531 geometry, e.g. a RING. This only works if it is possible and applicable.
0532 If the point-order is different, or the closure is different between two
0533 geometry types, it will be converted correctly by explicitly reversing the
0534 points or closing or opening the polygon rings.
0535 \ingroup convert
0536 \tparam Geometry1 \tparam_geometry
0537 \tparam Geometry2 \tparam_geometry
0538 \param geometry1 \param_geometry (source)
0539 \param geometry2 \param_geometry (target)
0540 
0541 \qbk{[include reference/algorithms/convert.qbk]}
0542  */
0543 template <typename Geometry1, typename Geometry2>
0544 inline void convert(Geometry1 const& geometry1, Geometry2& geometry2)
0545 {
0546     resolve_variant::convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
0547 }
0548 
0549 #if defined(_MSC_VER)
0550 #pragma warning(pop)
0551 #endif
0552 
0553 }} // namespace boost::geometry
0554 
0555 #endif // BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP