1 // Boost.Geometry (aka GGL, Generic Geometry Library) 2 3 // Copyright (c) 2012-2015 Barend Gehrels, Amsterdam, the Netherlands. 4 5 // This file was modified by Oracle on 2015. 6 // Modifications copyright (c) 2015, Oracle and/or its affiliates. 7 8 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle 9 10 // Use, modification and distribution is subject to the Boost Software License, 11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 12 // http://www.boost.org/LICENSE_1_0.txt) 13 14 #ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_ROUND_HPP 15 #define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_ROUND_HPP 16 17 #include <boost/core/ignore_unused.hpp> 18 19 #include <boost/geometry/core/cs.hpp> 20 #include <boost/geometry/strategies/tags.hpp> 21 #include <boost/geometry/util/math.hpp> 22 #include <boost/geometry/util/select_most_precise.hpp> 23 24 #include <boost/geometry/strategies/buffer.hpp> 25 26 27 #include <boost/geometry/io/wkt/wkt.hpp> 28 29 namespace boost { namespace geometry 30 { 31 32 33 namespace strategy { namespace buffer 34 { 35 36 37 /*! 38 \brief Let the buffer create rounded ends 39 \ingroup strategies 40 \details This strategy can be used as EndStrategy for the buffer algorithm. 41 It creates a rounded end for each linestring-end. It can be applied 42 for (multi)linestrings. Also it is applicable for spikes in (multi)polygons. 43 This strategy is only applicable for Cartesian coordinate systems. 44 45 \qbk{ 46 [heading Example] 47 [buffer_end_round] 48 [heading Output] 49 [$img/strategies/buffer_end_round.png] 50 [heading See also] 51 \* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)] 52 \* [link geometry.reference.strategies.strategy_buffer_end_flat end_flat] 53 } 54 */ 55 class end_round 56 { 57 private : 58 std::size_t m_points_per_circle; 59 60 template 61 < 62 typename Point, 63 typename PromotedType, 64 typename DistanceType, 65 typename RangeOut 66 > generate_points(Point const & point,PromotedType alpha,DistanceType const & buffer_distance,RangeOut & range_out) const67 inline void generate_points(Point const& point, 68 PromotedType alpha, // by value 69 DistanceType const& buffer_distance, 70 RangeOut& range_out) const 71 { 72 PromotedType const two_pi = geometry::math::two_pi<PromotedType>(); 73 74 std::size_t point_buffer_count = m_points_per_circle; 75 76 PromotedType const diff = two_pi / PromotedType(point_buffer_count); 77 78 // For half circle: 79 point_buffer_count /= 2; 80 point_buffer_count++; 81 82 for (std::size_t i = 0; i < point_buffer_count; i++, alpha -= diff) 83 { 84 typename boost::range_value<RangeOut>::type p; 85 set<0>(p, get<0>(point) + buffer_distance * cos(alpha)); 86 set<1>(p, get<1>(point) + buffer_distance * sin(alpha)); 87 range_out.push_back(p); 88 } 89 } 90 91 template <typename T, typename P1, typename P2> calculate_angle(P1 const & from_point,P2 const & to_point)92 static inline T calculate_angle(P1 const& from_point, P2 const& to_point) 93 { 94 typedef P1 vector_type; 95 vector_type v = from_point; 96 geometry::subtract_point(v, to_point); 97 return atan2(geometry::get<1>(v), geometry::get<0>(v)); 98 } 99 100 public : 101 102 //! \brief Constructs the strategy 103 //! \param points_per_circle points which would be used for a full circle 104 //! (if points_per_circle is smaller than 4, it is internally set to 4) end_round(std::size_t points_per_circle=90)105 explicit inline end_round(std::size_t points_per_circle = 90) 106 : m_points_per_circle((points_per_circle < 4u) ? 4u : points_per_circle) 107 {} 108 109 #ifndef DOXYGEN_SHOULD_SKIP_THIS 110 111 //! Fills output_range with a flat end 112 template <typename Point, typename RangeOut, typename DistanceStrategy> apply(Point const & penultimate_point,Point const & perp_left_point,Point const & ultimate_point,Point const & perp_right_point,buffer_side_selector side,DistanceStrategy const & distance,RangeOut & range_out) const113 inline void apply(Point const& penultimate_point, 114 Point const& perp_left_point, 115 Point const& ultimate_point, 116 Point const& perp_right_point, 117 buffer_side_selector side, 118 DistanceStrategy const& distance, 119 RangeOut& range_out) const 120 { 121 boost::ignore_unused(perp_left_point); 122 typedef typename coordinate_type<Point>::type coordinate_type; 123 124 typedef typename geometry::select_most_precise 125 < 126 coordinate_type, 127 double 128 >::type promoted_type; 129 130 promoted_type const dist_left = distance.apply(penultimate_point, ultimate_point, buffer_side_left); 131 promoted_type const dist_right = distance.apply(penultimate_point, ultimate_point, buffer_side_right); 132 promoted_type const alpha 133 = calculate_angle<promoted_type>(penultimate_point, ultimate_point) 134 - geometry::math::half_pi<promoted_type>(); 135 136 if (geometry::math::equals(dist_left, dist_right)) 137 { 138 generate_points(ultimate_point, alpha, dist_left, range_out); 139 } 140 else 141 { 142 static promoted_type const two = 2.0; 143 promoted_type const dist_average = (dist_left + dist_right) / two; 144 promoted_type const dist_half 145 = (side == buffer_side_right 146 ? (dist_right - dist_left) 147 : (dist_left - dist_right)) / two; 148 149 Point shifted_point; 150 set<0>(shifted_point, get<0>(ultimate_point) + dist_half * cos(alpha)); 151 set<1>(shifted_point, get<1>(ultimate_point) + dist_half * sin(alpha)); 152 generate_points(shifted_point, alpha, dist_average, range_out); 153 } 154 155 if (m_points_per_circle % 2 == 1) 156 { 157 // For a half circle, if the number of points is not even, 158 // we should insert the end point too, to generate a full cap 159 range_out.push_back(perp_right_point); 160 } 161 } 162 163 template <typename NumericType> max_distance(NumericType const & distance)164 static inline NumericType max_distance(NumericType const& distance) 165 { 166 return distance; 167 } 168 169 //! Returns the piece_type (flat end) get_piece_type()170 static inline piece_type get_piece_type() 171 { 172 return buffered_round_end; 173 } 174 #endif // DOXYGEN_SHOULD_SKIP_THIS 175 }; 176 177 178 }} // namespace strategy::buffer 179 180 }} // namespace boost::geometry 181 182 #endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_ROUND_HPP 183