Back to home page

EIC code displayed by LXR

 
 

    


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

0001 // Boost.Geometry
0002 
0003 // Copyright (c) 2022 Barend Gehrels, Amsterdam, the Netherlands.
0004 
0005 // Use, modification and distribution is subject to the Boost Software License,
0006 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0007 // http://www.boost.org/LICENSE_1_0.txt)
0008 
0009 #ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_BUFFER_END_ROUND_HPP
0010 #define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_BUFFER_END_ROUND_HPP
0011 
0012 #include <boost/range/value_type.hpp>
0013 
0014 #include <boost/geometry/core/radian_access.hpp>
0015 
0016 #include <boost/geometry/srs/spheroid.hpp>
0017 #include <boost/geometry/strategies/buffer.hpp>
0018 #include <boost/geometry/strategies/geographic/buffer_helper.hpp>
0019 #include <boost/geometry/strategies/geographic/parameters.hpp>
0020 #include <boost/geometry/util/math.hpp>
0021 #include <boost/geometry/util/select_calculation_type.hpp>
0022 
0023 
0024 namespace boost { namespace geometry
0025 {
0026 
0027 namespace strategy { namespace buffer
0028 {
0029 
0030 template
0031 <
0032     typename FormulaPolicy = strategy::andoyer,
0033     typename Spheroid = srs::spheroid<double>,
0034     typename CalculationType = void
0035 >
0036 class geographic_end_round
0037 {
0038 public :
0039 
0040     //! \brief Constructs the strategy with a spheroid
0041     //! \param spheroid The spheroid to be used
0042     //! \param points_per_circle Number of points (minimum 4) that would be used for a full circle
0043     explicit inline geographic_end_round(Spheroid const& spheroid,
0044                                          std::size_t points_per_circle = default_points_per_circle)
0045         : m_spheroid(spheroid)
0046         , m_points_per_circle(get_point_count_for_end(points_per_circle))
0047     {}
0048 
0049     //! \brief Constructs the strategy
0050     //! \param points_per_circle Number of points (minimum 4) that would be used for a full circle
0051     explicit inline geographic_end_round(std::size_t points_per_circle = default_points_per_circle)
0052         : m_points_per_circle(get_point_count_for_end(points_per_circle))
0053     {}
0054 
0055 #ifndef DOXYGEN_SHOULD_SKIP_THIS
0056     template <typename T, typename RangeOut>
0057     inline void generate(T lon_rad, T lat_rad, T distance, T azimuth, RangeOut& range_out) const
0058     {
0059         using helper = geographic_buffer_helper<FormulaPolicy, T>;
0060         std::size_t const n = m_points_per_circle / 2;
0061         T const angle_diff = geometry::math::pi<T>() / n;
0062         T azi = math::wrap_azimuth_in_radian(azimuth + angle_diff);
0063 
0064         // Generate points between 0 and n, not including them
0065         // because left and right are inserted before and after this range.
0066         for (std::size_t i = 1; i < n; i++)
0067         {
0068             helper::append_point(lon_rad, lat_rad, distance, azi, m_spheroid, range_out);
0069             azi = math::wrap_azimuth_in_radian(azi + angle_diff);
0070         }
0071     }
0072 
0073     //! Fills output_range with a round end
0074     template <typename Point, typename DistanceStrategy, typename RangeOut>
0075     inline void apply(Point const& penultimate_point, Point const& perp_left_point,
0076                       Point const& ultimate_point, Point const& perp_right_point,
0077                       buffer_side_selector side, DistanceStrategy const& distance,
0078                       RangeOut& range_out) const
0079     {
0080         using calc_t = typename select_calculation_type
0081             <
0082                 Point,
0083                 typename boost::range_value<RangeOut>::type,
0084                 CalculationType
0085             >::type;
0086 
0087         using helper = geographic_buffer_helper<FormulaPolicy, calc_t>;
0088 
0089         calc_t const lon_rad = get_as_radian<0>(ultimate_point);
0090         calc_t const lat_rad = get_as_radian<1>(ultimate_point);
0091 
0092         auto const azimuth = helper::azimuth(lon_rad, lat_rad, perp_left_point, m_spheroid);
0093 
0094         calc_t const dist_left = distance.apply(penultimate_point, ultimate_point, buffer_side_left);
0095         calc_t const dist_right = distance.apply(penultimate_point, ultimate_point, buffer_side_right);
0096 
0097         bool const reversed = (side == buffer_side_left && dist_right < 0 && -dist_right > dist_left)
0098                     || (side == buffer_side_right && dist_left < 0 && -dist_left > dist_right)
0099                     ;
0100 
0101         if (reversed)
0102         {
0103             range_out.push_back(perp_right_point);
0104             // generate
0105             range_out.push_back(perp_left_point);
0106         }
0107         else
0108         {
0109             range_out.push_back(perp_left_point);
0110 
0111             if (geometry::math::equals(dist_left, dist_right))
0112             {
0113                 generate(lon_rad, lat_rad, dist_left, azimuth, range_out);
0114             }
0115             else
0116             {
0117                 static calc_t const two = 2.0;
0118                 calc_t const dist_average = (dist_left + dist_right) / two;
0119                 calc_t const dist_half
0120                         = (side == buffer_side_right
0121                         ? (dist_right - dist_left)
0122                         : (dist_left - dist_right)) / two;
0123                 auto const shifted = helper::direct::apply(lon_rad, lat_rad, dist_half, azimuth, m_spheroid);
0124                 generate(shifted.lon2, shifted.lat2, dist_average, azimuth, range_out);
0125             }
0126 
0127             range_out.push_back(perp_right_point);
0128         }
0129     }
0130 
0131     template <typename NumericType>
0132     static inline NumericType max_distance(NumericType const& distance)
0133     {
0134         return distance;
0135     }
0136 
0137     //! Returns the piece_type (flat end)
0138     static inline piece_type get_piece_type()
0139     {
0140         return buffered_round_end;
0141     }
0142 #endif // DOXYGEN_SHOULD_SKIP_THIS
0143 
0144 private :
0145     Spheroid m_spheroid;
0146     std::size_t m_points_per_circle;
0147 };
0148 
0149 }} // namespace strategy::buffer
0150 
0151 }} // namespace boost::geometry
0152 
0153 #endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_BUFFER_END_ROUND_HPP