Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:36:42

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         typedef typename coordinate_type<Point>::type coordinate_type;
0122 
0123         typedef typename geometry::select_most_precise
0124         <
0125             coordinate_type,
0126             double
0127         >::type promoted_type;
0128 
0129         promoted_type const dist_left = distance.apply(penultimate_point, ultimate_point, buffer_side_left);
0130         promoted_type const dist_right = distance.apply(penultimate_point, ultimate_point, buffer_side_right);
0131         promoted_type const alpha
0132                 = calculate_angle<promoted_type>(penultimate_point, ultimate_point)
0133                     - geometry::math::half_pi<promoted_type>();
0134 
0135         if (geometry::math::equals(dist_left, dist_right))
0136         {
0137             generate_points(ultimate_point, alpha, dist_left, range_out);
0138         }
0139         else
0140         {
0141             static promoted_type const two = 2.0;
0142             promoted_type const dist_average = (dist_left + dist_right) / two;
0143             promoted_type const dist_half
0144                     = (side == buffer_side_right
0145                     ? (dist_right - dist_left)
0146                     : (dist_left - dist_right)) / two;
0147 
0148             Point shifted_point;
0149             geometry::set<0>(shifted_point, geometry::get<0>(ultimate_point) + dist_half * cos(alpha));
0150             geometry::set<1>(shifted_point, geometry::get<1>(ultimate_point) + dist_half * sin(alpha));
0151             generate_points(shifted_point, alpha, dist_average, range_out);
0152         }
0153 
0154         if (m_points_per_circle % 2 == 1)
0155         {
0156             // For a half circle, if the number of points is not even,
0157             // we should insert the end point too, to generate a full cap
0158             range_out.push_back(perp_right_point);
0159         }
0160     }
0161 
0162     template <typename NumericType>
0163     static inline NumericType max_distance(NumericType const& distance)
0164     {
0165         return distance;
0166     }
0167 
0168     //! Returns the piece_type (flat end)
0169     static inline piece_type get_piece_type()
0170     {
0171         return buffered_round_end;
0172     }
0173 #endif // DOXYGEN_SHOULD_SKIP_THIS
0174 };
0175 
0176 
0177 }} // namespace strategy::buffer
0178 
0179 }} // namespace boost::geometry
0180 
0181 #endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_ROUND_HPP