annotate DEPENDENCIES/generic/include/boost/geometry/strategies/cartesian/buffer_end_round.hpp @ 133:4acb5d8d80b6 tip

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