Chris@102: // Boost.Geometry (aka GGL, Generic Geometry Library) Chris@102: Chris@102: // Copyright (c) 2012-2014 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_END_ROUND_HPP Chris@102: #define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_ROUND_HPP Chris@102: Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: Chris@102: #include Chris@102: Chris@102: Chris@102: #include 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: /*! Chris@102: \brief Let the buffer create rounded ends Chris@102: \ingroup strategies Chris@102: \details This strategy can be used as EndStrategy for the buffer algorithm. Chris@102: It creates a rounded end for each linestring-end. It can be applied Chris@102: for (multi)linestrings. Also it is applicable for spikes in (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_end_round] Chris@102: [heading Output] Chris@102: [$img/strategies/buffer_end_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_end_flat end_flat] Chris@102: } Chris@102: */ Chris@102: class end_round Chris@102: { Chris@102: private : Chris@102: std::size_t m_points_per_circle; Chris@102: Chris@102: template Chris@102: < Chris@102: typename Point, Chris@102: typename PromotedType, Chris@102: typename DistanceType, Chris@102: typename RangeOut Chris@102: > Chris@102: inline void generate_points(Point const& point, Chris@102: PromotedType alpha, // by value Chris@102: DistanceType const& buffer_distance, Chris@102: RangeOut& range_out) const Chris@102: { Chris@102: PromotedType const two = 2.0; Chris@102: PromotedType const two_pi = two * geometry::math::pi(); Chris@102: Chris@102: std::size_t point_buffer_count = m_points_per_circle; Chris@102: Chris@102: PromotedType const diff = two_pi / PromotedType(point_buffer_count); Chris@102: Chris@102: // For half circle: Chris@102: point_buffer_count /= 2; Chris@102: point_buffer_count++; Chris@102: Chris@102: for (std::size_t i = 0; i < point_buffer_count; i++, alpha -= diff) Chris@102: { Chris@102: typename boost::range_value::type p; Chris@102: set<0>(p, get<0>(point) + buffer_distance * cos(alpha)); Chris@102: set<1>(p, get<1>(point) + buffer_distance * sin(alpha)); Chris@102: range_out.push_back(p); Chris@102: } Chris@102: } Chris@102: Chris@102: template Chris@102: static inline T calculate_angle(P1 const& from_point, P2 const& to_point) Chris@102: { Chris@102: typedef P1 vector_type; Chris@102: vector_type v = from_point; Chris@102: geometry::subtract_point(v, to_point); Chris@102: return atan2(geometry::get<1>(v), geometry::get<0>(v)); Chris@102: } 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: //! (if points_per_circle is smaller than 4, it is internally set to 4) Chris@102: explicit inline end_round(std::size_t points_per_circle = 90) Chris@102: : m_points_per_circle((points_per_circle < 4u) ? 4u : points_per_circle) Chris@102: {} Chris@102: Chris@102: #ifndef DOXYGEN_SHOULD_SKIP_THIS Chris@102: Chris@102: //! Fills output_range with a flat end Chris@102: template Chris@102: inline void apply(Point const& penultimate_point, Chris@102: Point const& perp_left_point, Chris@102: Point const& ultimate_point, Chris@102: Point const& perp_right_point, Chris@102: buffer_side_selector side, Chris@102: DistanceStrategy const& distance, Chris@102: RangeOut& range_out) const Chris@102: { Chris@102: typedef typename coordinate_type::type coordinate_type; Chris@102: Chris@102: typedef typename geometry::select_most_precise Chris@102: < Chris@102: coordinate_type, Chris@102: double Chris@102: >::type promoted_type; Chris@102: Chris@102: promoted_type const alpha = calculate_angle(perp_left_point, ultimate_point); Chris@102: Chris@102: promoted_type const dist_left = distance.apply(penultimate_point, ultimate_point, buffer_side_left); Chris@102: promoted_type const dist_right = distance.apply(penultimate_point, ultimate_point, buffer_side_right); Chris@102: if (geometry::math::equals(dist_left, dist_right)) Chris@102: { Chris@102: generate_points(ultimate_point, alpha, dist_left, range_out); Chris@102: } Chris@102: else Chris@102: { Chris@102: promoted_type const two = 2.0; Chris@102: promoted_type dist_half_diff = (dist_left - dist_right) / two; Chris@102: Chris@102: if (side == buffer_side_right) Chris@102: { Chris@102: dist_half_diff = -dist_half_diff; Chris@102: } Chris@102: Chris@102: Point shifted_point; Chris@102: set<0>(shifted_point, get<0>(ultimate_point) + dist_half_diff * cos(alpha)); Chris@102: set<1>(shifted_point, get<1>(ultimate_point) + dist_half_diff * sin(alpha)); Chris@102: generate_points(shifted_point, alpha, (dist_left + dist_right) / two, range_out); Chris@102: } Chris@102: Chris@102: if (m_points_per_circle % 2 == 1) Chris@102: { Chris@102: // For a half circle, if the number of points is not even, Chris@102: // we should insert the end point too, to generate a full cap Chris@102: range_out.push_back(perp_right_point); Chris@102: } 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: //! Returns the piece_type (flat end) Chris@102: static inline piece_type get_piece_type() Chris@102: { Chris@102: return buffered_round_end; Chris@102: } Chris@102: #endif // DOXYGEN_SHOULD_SKIP_THIS 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_END_ROUND_HPP