Back to home page

EIC code displayed by LXR

 
 

    


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

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