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