buffer_end_round.hpp 5.9 KB

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