Chris@102: // Boost.Geometry (aka GGL, Generic Geometry Library) Chris@102: Chris@102: // Copyright (c) 2012-2015 Barend Gehrels, Amsterdam, the Netherlands. Chris@102: Chris@102: // Use, modification and distribution is subject to the Boost Software License, Chris@102: // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at Chris@102: // http://www.boost.org/LICENSE_1_0.txt) Chris@102: Chris@102: #ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_HPP Chris@102: #define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_HPP Chris@102: Chris@102: #include Chris@102: Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: Chris@102: #ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN Chris@102: #include Chris@102: #endif Chris@102: Chris@102: Chris@102: namespace boost { namespace geometry Chris@102: { Chris@102: Chris@102: Chris@102: namespace strategy { namespace buffer Chris@102: { Chris@102: Chris@102: /*! Chris@102: \brief Let the buffer create rounded corners Chris@102: \ingroup strategies Chris@102: \details This strategy can be used as JoinStrategy for the buffer algorithm. Chris@102: It creates a rounded corners around each convex vertex. It can be applied Chris@102: for (multi)linestrings and (multi)polygons. Chris@102: This strategy is only applicable for Cartesian coordinate systems. Chris@102: Chris@102: \qbk{ Chris@102: [heading Example] Chris@102: [buffer_join_round] Chris@102: [heading Output] Chris@102: [$img/strategies/buffer_join_round.png] Chris@102: [heading See also] Chris@102: \* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)] Chris@102: \* [link geometry.reference.strategies.strategy_buffer_join_miter join_miter] Chris@102: } Chris@102: */ Chris@102: class join_round Chris@102: { Chris@102: public : Chris@102: Chris@102: //! \brief Constructs the strategy Chris@102: //! \param points_per_circle points which would be used for a full circle Chris@102: explicit inline join_round(std::size_t points_per_circle = 90) Chris@102: : m_points_per_circle(points_per_circle) Chris@102: {} Chris@102: Chris@102: private : Chris@102: template Chris@102: < Chris@102: typename PromotedType, Chris@102: typename Point, Chris@102: typename DistanceType, Chris@102: typename RangeOut Chris@102: > Chris@102: inline void generate_points(Point const& vertex, Chris@102: Point const& perp1, Point const& perp2, Chris@102: DistanceType const& buffer_distance, Chris@102: RangeOut& range_out) const Chris@102: { Chris@102: PromotedType const dx1 = get<0>(perp1) - get<0>(vertex); Chris@102: PromotedType const dy1 = get<1>(perp1) - get<1>(vertex); Chris@102: PromotedType const dx2 = get<0>(perp2) - get<0>(vertex); Chris@102: PromotedType const dy2 = get<1>(perp2) - get<1>(vertex); Chris@102: Chris@102: PromotedType const two = 2.0; Chris@102: PromotedType const two_pi = two * geometry::math::pi(); Chris@102: Chris@102: PromotedType const angle1 = atan2(dy1, dx1); Chris@102: PromotedType angle2 = atan2(dy2, dx2); Chris@102: while (angle2 > angle1) Chris@102: { Chris@102: angle2 -= two_pi; Chris@102: } Chris@102: PromotedType const angle_diff = angle1 - angle2; Chris@102: Chris@102: // Divide the angle into an integer amount of steps to make it Chris@102: // visually correct also for a low number of points / circle Chris@102: Chris@102: // If a full circle is divided into 3 parts (e.g. angle is 125), Chris@102: // the one point in between must still be generated Chris@102: // The calculation below: Chris@102: // - generates 1 point in between for an angle of 125 based on 3 points Chris@102: // - generates 0 points in between for an angle of 90 based on 4 points Chris@102: Chris@102: int const n = (std::max)(static_cast( Chris@102: ceil(m_points_per_circle * angle_diff / two_pi)), 1); Chris@102: Chris@102: PromotedType const diff = angle_diff / static_cast(n); Chris@102: PromotedType a = angle1 - diff; Chris@102: Chris@102: // Walk to n - 1 to avoid generating the last point Chris@102: for (int i = 0; i < n - 1; i++, a -= diff) Chris@102: { Chris@102: Point p; Chris@102: set<0>(p, get<0>(vertex) + buffer_distance * cos(a)); Chris@102: set<1>(p, get<1>(vertex) + buffer_distance * sin(a)); Chris@102: range_out.push_back(p); Chris@102: } Chris@102: } Chris@102: Chris@102: public : Chris@102: Chris@102: Chris@102: #ifndef DOXYGEN_SHOULD_SKIP_THIS Chris@102: //! Fills output_range with a rounded shape around a vertex Chris@102: template Chris@102: inline bool apply(Point const& ip, Point const& vertex, Chris@102: Point const& perp1, Point const& perp2, Chris@102: DistanceType const& buffer_distance, Chris@102: RangeOut& range_out) const Chris@102: { Chris@102: typedef typename coordinate_type::type coordinate_type; Chris@102: typedef typename boost::range_value::type output_point_type; Chris@102: Chris@102: typedef typename geometry::select_most_precise Chris@102: < Chris@102: typename geometry::select_most_precise Chris@102: < Chris@102: coordinate_type, Chris@102: typename geometry::coordinate_type::type Chris@102: >::type, Chris@102: double Chris@102: >::type promoted_type; Chris@102: Chris@102: geometry::equal_to equals; Chris@102: if (equals(perp1, perp2)) Chris@102: { Chris@102: #ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN Chris@102: std::cout << "Corner for equal points " << geometry::wkt(ip) << " " << geometry::wkt(perp1) << std::endl; Chris@102: #endif Chris@102: return false; Chris@102: } Chris@102: Chris@102: // Generate 'vectors' Chris@102: coordinate_type vix = (get<0>(ip) - get<0>(vertex)); Chris@102: coordinate_type viy = (get<1>(ip) - get<1>(vertex)); Chris@102: Chris@102: promoted_type length_i = geometry::math::sqrt(vix * vix + viy * viy); Chris@102: DistanceType const bd = geometry::math::abs(buffer_distance); Chris@102: promoted_type prop = bd / length_i; Chris@102: Chris@102: Point bp; Chris@102: set<0>(bp, get<0>(vertex) + vix * prop); Chris@102: set<1>(bp, get<1>(vertex) + viy * prop); Chris@102: Chris@102: range_out.push_back(perp1); Chris@102: generate_points(vertex, perp1, perp2, bd, range_out); Chris@102: range_out.push_back(perp2); Chris@102: return true; Chris@102: } Chris@102: Chris@102: template Chris@102: static inline NumericType max_distance(NumericType const& distance) Chris@102: { Chris@102: return distance; Chris@102: } Chris@102: Chris@102: #endif // DOXYGEN_SHOULD_SKIP_THIS Chris@102: Chris@102: private : Chris@102: std::size_t m_points_per_circle; Chris@102: }; Chris@102: Chris@102: Chris@102: }} // namespace strategy::buffer Chris@102: Chris@102: }} // namespace boost::geometry Chris@102: Chris@102: #endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_HPP