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