Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-13 08:36:16

0001 // Boost.Geometry (aka GGL, Generic Geometry Library)
0002 
0003 // Copyright (c) 2012-2015 Barend Gehrels, Amsterdam, the Netherlands.
0004 
0005 // This file was modified by Oracle on 2015-2023.
0006 // Modifications copyright (c) 2015-2023, Oracle and/or its affiliates.
0007 // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
0008 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
0009 
0010 // Use, modification and distribution is subject to the Boost Software License,
0011 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0012 // http://www.boost.org/LICENSE_1_0.txt)
0013 
0014 #ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_ROUND_HPP
0015 #define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_ROUND_HPP
0016 
0017 #include <boost/core/ignore_unused.hpp>
0018 
0019 #include <boost/geometry/arithmetic/arithmetic.hpp>
0020 #include <boost/geometry/core/cs.hpp>
0021 #include <boost/geometry/core/access.hpp>
0022 #include <boost/geometry/strategies/tags.hpp>
0023 #include <boost/geometry/util/math.hpp>
0024 #include <boost/geometry/util/select_most_precise.hpp>
0025 
0026 #include <boost/geometry/strategies/buffer.hpp>
0027 
0028 
0029 namespace boost { namespace geometry
0030 {
0031 
0032 
0033 namespace strategy { namespace buffer
0034 {
0035 
0036 
0037 /*!
0038 \brief Let the buffer create rounded ends
0039 \ingroup strategies
0040 \details This strategy can be used as EndStrategy for the buffer algorithm.
0041     It creates a rounded end for each linestring-end. It can be applied
0042     for (multi)linestrings. Also it is applicable for spikes in (multi)polygons.
0043     This strategy is only applicable for Cartesian coordinate systems.
0044 
0045 \qbk{
0046 [heading Example]
0047 [buffer_end_round]
0048 [heading Output]
0049 [$img/strategies/buffer_end_round.png]
0050 [heading See also]
0051 \* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
0052 \* [link geometry.reference.strategies.strategy_buffer_end_flat end_flat]
0053 }
0054  */
0055 class end_round
0056 {
0057 private :
0058     std::size_t m_points_per_circle;
0059 
0060     template
0061     <
0062         typename Point,
0063         typename PromotedType,
0064         typename DistanceType,
0065         typename RangeOut
0066     >
0067     inline void generate_points(Point const& point,
0068                 PromotedType alpha, // by value
0069                 DistanceType const& buffer_distance,
0070                 RangeOut& range_out) const
0071     {
0072         PromotedType const two_pi = geometry::math::two_pi<PromotedType>();
0073 
0074         std::size_t point_buffer_count = m_points_per_circle;
0075 
0076         PromotedType const diff = two_pi / PromotedType(point_buffer_count);
0077 
0078         // For half circle:
0079         point_buffer_count /= 2;
0080         point_buffer_count++;
0081 
0082         for (std::size_t i = 0; i < point_buffer_count; i++, alpha -= diff)
0083         {
0084             typename boost::range_value<RangeOut>::type p;
0085             geometry::set<0>(p, geometry::get<0>(point) + buffer_distance * cos(alpha));
0086             geometry::set<1>(p, geometry::get<1>(point) + buffer_distance * sin(alpha));
0087             range_out.push_back(p);
0088         }
0089     }
0090 
0091     template <typename T, typename P1, typename P2>
0092     static inline T calculate_angle(P1 const& from_point, P2 const& to_point)
0093     {
0094         typedef P1 vector_type;
0095         vector_type v = from_point;
0096         geometry::subtract_point(v, to_point);
0097         return atan2(geometry::get<1>(v), geometry::get<0>(v));
0098     }
0099 
0100 public :
0101 
0102     //! \brief Constructs the strategy
0103     //! \param points_per_circle Number of points (minimum 4) that would be used for a full circle
0104     explicit inline end_round(std::size_t points_per_circle = default_points_per_circle)
0105         : m_points_per_circle(get_point_count_for_end(points_per_circle))
0106     {}
0107 
0108 #ifndef DOXYGEN_SHOULD_SKIP_THIS
0109 
0110     //! Fills output_range with a round end
0111     template <typename Point, typename DistanceStrategy, typename RangeOut>
0112     inline void apply(Point const& penultimate_point,
0113                 Point const& perp_left_point,
0114                 Point const& ultimate_point,
0115                 Point const& perp_right_point,
0116                 buffer_side_selector side,
0117                 DistanceStrategy const& distance,
0118                 RangeOut& range_out) const
0119     {
0120         boost::ignore_unused(perp_left_point);
0121 
0122         using promoted_type = typename geometry::select_most_precise
0123         <
0124             coordinate_type_t<Point>,
0125             double
0126         >::type;
0127 
0128         promoted_type const dist_left = distance.apply(penultimate_point, ultimate_point, buffer_side_left);
0129         promoted_type const dist_right = distance.apply(penultimate_point, ultimate_point, buffer_side_right);
0130         promoted_type const alpha
0131                 = calculate_angle<promoted_type>(penultimate_point, ultimate_point)
0132                     - geometry::math::half_pi<promoted_type>();
0133 
0134         if (geometry::math::equals(dist_left, dist_right))
0135         {
0136             generate_points(ultimate_point, alpha, dist_left, range_out);
0137         }
0138         else
0139         {
0140             static promoted_type const two = 2.0;
0141             promoted_type const dist_average = (dist_left + dist_right) / two;
0142             promoted_type const dist_half
0143                     = (side == buffer_side_right
0144                     ? (dist_right - dist_left)
0145                     : (dist_left - dist_right)) / two;
0146 
0147             Point shifted_point;
0148             geometry::set<0>(shifted_point, geometry::get<0>(ultimate_point) + dist_half * cos(alpha));
0149             geometry::set<1>(shifted_point, geometry::get<1>(ultimate_point) + dist_half * sin(alpha));
0150             generate_points(shifted_point, alpha, dist_average, range_out);
0151         }
0152 
0153         if (m_points_per_circle % 2 == 1)
0154         {
0155             // For a half circle, if the number of points is not even,
0156             // we should insert the end point too, to generate a full cap
0157             range_out.push_back(perp_right_point);
0158         }
0159     }
0160 
0161     template <typename NumericType>
0162     static inline NumericType max_distance(NumericType const& distance)
0163     {
0164         return distance;
0165     }
0166 
0167     //! Returns the piece_type (round end)
0168     static inline piece_type get_piece_type()
0169     {
0170         return buffered_round_end;
0171     }
0172 #endif // DOXYGEN_SHOULD_SKIP_THIS
0173 };
0174 
0175 
0176 }} // namespace strategy::buffer
0177 
0178 }} // namespace boost::geometry
0179 
0180 #endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_ROUND_HPP