buffer_join_miter.hpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Use, modification and distribution is subject to the Boost Software License,
  4. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_MITER_HPP
  7. #define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_MITER_HPP
  8. #include <boost/geometry/core/assert.hpp>
  9. #include <boost/geometry/core/cs.hpp>
  10. #include <boost/geometry/policies/compare.hpp>
  11. #include <boost/geometry/util/math.hpp>
  12. #include <boost/geometry/util/select_most_precise.hpp>
  13. #include <boost/geometry/strategies/buffer.hpp>
  14. namespace boost { namespace geometry
  15. {
  16. namespace strategy { namespace buffer
  17. {
  18. /*!
  19. \brief Let the buffer create sharp corners
  20. \ingroup strategies
  21. \details This strategy can be used as JoinStrategy for the buffer algorithm.
  22. It creates a sharp corners around each convex vertex. It can be applied
  23. for (multi)linestrings and (multi)polygons.
  24. If corners are sharp by themselves, the miters might become very long. Therefore
  25. there is a limit (miter_limit), in terms of the used distance, which limits
  26. their length. The miter is not changed to a bevel form (as done in some
  27. other software), it is just adapted to the specified miter_limit but keeps
  28. its miter form.
  29. If the buffer distance is 5.0, and the miter limit is 2.0, generated points
  30. will be located at a distance of at most 10.0 (2*5) units.
  31. This strategy is only applicable for Cartesian coordinate systems.
  32. \qbk{
  33. [heading Example]
  34. [buffer_join_miter]
  35. [heading Output]
  36. [$img/strategies/buffer_join_miter.png]
  37. [heading See also]
  38. \* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
  39. \* [link geometry.reference.strategies.strategy_buffer_join_round join_round]
  40. }
  41. */
  42. class join_miter
  43. {
  44. public:
  45. //! \brief Constructs the strategy
  46. //! \param miter_limit The miter limit, to avoid excessively long miters around sharp corners
  47. explicit inline join_miter(double miter_limit = 5.0)
  48. : m_miter_limit(valid_limit(miter_limit))
  49. {}
  50. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  51. //! Fills output_range with a sharp shape around a vertex
  52. template <typename Point, typename DistanceType, typename RangeOut>
  53. inline bool apply(Point const& ip, Point const& vertex,
  54. Point const& perp1, Point const& perp2,
  55. DistanceType const& buffer_distance,
  56. RangeOut& range_out) const
  57. {
  58. geometry::equal_to<Point> equals;
  59. if (equals(ip, vertex))
  60. {
  61. return false;
  62. }
  63. if (equals(perp1, perp2))
  64. {
  65. return false;
  66. }
  67. typedef typename coordinate_type<Point>::type coordinate_type;
  68. typedef typename geometry::select_most_precise
  69. <
  70. coordinate_type,
  71. double
  72. >::type promoted_type;
  73. Point p = ip;
  74. // Check the distance ip-vertex (= miter distance)
  75. // (We calculate it manually (not using Pythagoras strategy) to reuse
  76. // dx and dy)
  77. coordinate_type const dx = get<0>(p) - get<0>(vertex);
  78. coordinate_type const dy = get<1>(p) - get<1>(vertex);
  79. promoted_type const distance = geometry::math::sqrt(dx * dx + dy * dy);
  80. promoted_type const max_distance
  81. = m_miter_limit * geometry::math::abs(buffer_distance);
  82. if (distance > max_distance)
  83. {
  84. BOOST_GEOMETRY_ASSERT(distance != 0.0);
  85. promoted_type const proportion = max_distance / distance;
  86. set<0>(p, get<0>(vertex) + dx * proportion);
  87. set<1>(p, get<1>(vertex) + dy * proportion);
  88. }
  89. range_out.push_back(perp1);
  90. range_out.push_back(p);
  91. range_out.push_back(perp2);
  92. return true;
  93. }
  94. template <typename NumericType>
  95. inline NumericType max_distance(NumericType const& distance) const
  96. {
  97. return distance * m_miter_limit;
  98. }
  99. #endif // DOXYGEN_SHOULD_SKIP_THIS
  100. private :
  101. double valid_limit(double miter_limit) const
  102. {
  103. if (miter_limit < 1.0)
  104. {
  105. // It should always exceed the buffer distance
  106. miter_limit = 1.0;
  107. }
  108. return miter_limit;
  109. }
  110. double m_miter_limit;
  111. };
  112. }} // namespace strategy::buffer
  113. }} // namespace boost::geometry
  114. #endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_MITER_HPP