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_JOIN_MITER_HPP Chris@102: #define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_MITER_HPP Chris@102: Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: Chris@102: #include Chris@102: Chris@102: Chris@102: namespace boost { namespace geometry Chris@102: { Chris@102: Chris@102: namespace strategy { namespace buffer Chris@102: { Chris@102: Chris@102: /*! Chris@102: \brief Let the buffer create sharp corners Chris@102: \ingroup strategies Chris@102: \details This strategy can be used as JoinStrategy for the buffer algorithm. Chris@102: It creates a sharp corners around each convex vertex. It can be applied Chris@102: for (multi)linestrings and (multi)polygons. Chris@102: If corners are sharp by themselves, the miters might become very long. Therefore Chris@102: there is a limit (miter_limit), in terms of the used distance, which limits Chris@102: their length. The miter is not changed to a bevel form (as done in some Chris@102: other software), it is just adapted to the specified miter_limit but keeps Chris@102: its miter form. Chris@102: If the buffer distance is 5.0, and the miter limit is 2.0, generated points Chris@102: will be located at a distance of at most 10.0 (2*5) units. Chris@102: This strategy is only applicable for Cartesian coordinate systems. Chris@102: Chris@102: \qbk{ Chris@102: [heading Example] Chris@102: [buffer_join_miter] Chris@102: [heading Output] Chris@102: [$img/strategies/buffer_join_miter.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_round join_round] Chris@102: } Chris@102: */ Chris@102: class join_miter Chris@102: { Chris@102: public: Chris@102: Chris@102: //! \brief Constructs the strategy Chris@102: //! \param miter_limit The miter limit, to avoid excessively long miters around sharp corners Chris@102: explicit inline join_miter(double miter_limit = 5.0) Chris@102: : m_miter_limit(valid_limit(miter_limit)) Chris@102: {} Chris@102: Chris@102: #ifndef DOXYGEN_SHOULD_SKIP_THIS Chris@102: //! Fills output_range with a sharp 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: geometry::equal_to equals; Chris@102: if (equals(ip, vertex)) Chris@102: { Chris@102: return false; Chris@102: } Chris@102: if (equals(perp1, perp2)) Chris@102: { Chris@102: return false; Chris@102: } Chris@102: Chris@102: typedef typename coordinate_type::type coordinate_type; 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: Point p = ip; Chris@102: Chris@102: // Check the distance ip-vertex (= miter distance) Chris@102: // (We calculate it manually (not using Pythagoras strategy) to reuse Chris@102: // dx and dy) Chris@102: coordinate_type const dx = get<0>(p) - get<0>(vertex); Chris@102: coordinate_type const dy = get<1>(p) - get<1>(vertex); Chris@102: Chris@102: promoted_type const distance = geometry::math::sqrt(dx * dx + dy * dy); Chris@102: Chris@102: promoted_type const max_distance Chris@102: = m_miter_limit * geometry::math::abs(buffer_distance); Chris@102: Chris@102: if (distance > max_distance) Chris@102: { Chris@102: BOOST_ASSERT(distance != 0.0); Chris@102: Chris@102: promoted_type const proportion = max_distance / distance; Chris@102: set<0>(p, get<0>(vertex) + dx * proportion); Chris@102: set<1>(p, get<1>(vertex) + dy * proportion); Chris@102: } Chris@102: Chris@102: range_out.push_back(perp1); Chris@102: range_out.push_back(p); Chris@102: range_out.push_back(perp2); Chris@102: return true; Chris@102: } Chris@102: Chris@102: template Chris@102: inline NumericType max_distance(NumericType const& distance) const Chris@102: { Chris@102: return distance * m_miter_limit; Chris@102: } Chris@102: Chris@102: #endif // DOXYGEN_SHOULD_SKIP_THIS Chris@102: Chris@102: private : Chris@102: double valid_limit(double miter_limit) const Chris@102: { Chris@102: if (miter_limit < 1.0) Chris@102: { Chris@102: // It should always exceed the buffer distance Chris@102: miter_limit = 1.0; Chris@102: } Chris@102: return miter_limit; Chris@102: } Chris@102: Chris@102: double m_miter_limit; Chris@102: }; Chris@102: Chris@102: }} // namespace strategy::buffer Chris@102: Chris@102: Chris@102: }} // namespace boost::geometry Chris@102: Chris@102: #endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_MITER_HPP