buffer_end_round.hpp 5.7 KB

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