diff options
Diffstat (limited to 'boost/geometry/strategies/cartesian/buffer_join_miter.hpp')
-rw-r--r-- | boost/geometry/strategies/cartesian/buffer_join_miter.hpp | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/boost/geometry/strategies/cartesian/buffer_join_miter.hpp b/boost/geometry/strategies/cartesian/buffer_join_miter.hpp new file mode 100644 index 0000000000..8fcf3b996c --- /dev/null +++ b/boost/geometry/strategies/cartesian/buffer_join_miter.hpp @@ -0,0 +1,140 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_MITER_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_MITER_HPP + +#include <boost/assert.hpp> +#include <boost/geometry/core/cs.hpp> +#include <boost/geometry/policies/compare.hpp> +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/select_most_precise.hpp> + +#include <boost/geometry/strategies/buffer.hpp> + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace buffer +{ + +/*! +\brief Let the buffer create sharp corners +\ingroup strategies +\details This strategy can be used as JoinStrategy for the buffer algorithm. + It creates a sharp corners around each convex vertex. It can be applied + for (multi)linestrings and (multi)polygons. + If corners are sharp by themselves, the miters might become very long. Therefore + there is a limit (miter_limit), in terms of the used distance, which limits + their length. The miter is not changed to a bevel form (as done in some + other software), it is just adapted to the specified miter_limit but keeps + its miter form. + This strategy is only applicable for Cartesian coordinate systems. + +\qbk{ +[heading Example] +[buffer_join_miter] +[heading Output] +[$img/strategies/buffer_join_miter.png] +[heading See also] +\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)] +\* [link geometry.reference.strategies.strategy_buffer_join_round join_round] +} + */ +class join_miter +{ +public: + + //! \brief Constructs the strategy + //! \param miter_limit The miter limit, to avoid excessively long miters around sharp corners + explicit inline join_miter(double miter_limit = 5.0) + : m_miter_limit(valid_limit(miter_limit)) + {} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + //! Fills output_range with a sharp shape around a vertex + template <typename Point, typename DistanceType, typename RangeOut> + inline bool apply(Point const& ip, Point const& vertex, + Point const& perp1, Point const& perp2, + DistanceType const& buffer_distance, + RangeOut& range_out) const + { + geometry::equal_to<Point> equals; + if (equals(ip, vertex)) + { + return false; + } + if (equals(perp1, perp2)) + { + return false; + } + + typedef typename coordinate_type<Point>::type coordinate_type; + typedef typename geometry::select_most_precise + < + coordinate_type, + double + >::type promoted_type; + + Point p = ip; + + // Check the distance ip-vertex (= miter distance) + // (We calculate it manually (not using Pythagoras strategy) to reuse + // dx and dy) + coordinate_type const dx = get<0>(p) - get<0>(vertex); + coordinate_type const dy = get<1>(p) - get<1>(vertex); + + promoted_type const distance = geometry::math::sqrt(dx * dx + dy * dy); + + promoted_type const max_distance + = m_miter_limit * geometry::math::abs(buffer_distance); + + if (distance > max_distance) + { + BOOST_ASSERT(distance != 0.0); + + promoted_type const proportion = max_distance / distance; + set<0>(p, get<0>(vertex) + dx * proportion); + set<1>(p, get<1>(vertex) + dy * proportion); + } + + range_out.push_back(perp1); + range_out.push_back(p); + range_out.push_back(perp2); + return true; + } + + template <typename NumericType> + inline NumericType max_distance(NumericType const& distance) const + { + return distance * m_miter_limit; + } + +#endif // DOXYGEN_SHOULD_SKIP_THIS + +private : + double valid_limit(double miter_limit) const + { + if (miter_limit < 1.0) + { + // It should always exceed the buffer distance + miter_limit = 1.0; + } + return miter_limit; + } + + double m_miter_limit; +}; + +}} // namespace strategy::buffer + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_MITER_HPP |