libcarla/include/system/boost/geometry/strategies/cartesian/buffer_join_miter.hpp
2024-10-18 13:19:59 +08:00

143 lines
4.4 KiB
C++

// 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/geometry/core/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.
If the buffer distance is 5.0, and the miter limit is 2.0, generated points
will be located at a distance of at most 10.0 (2*5) units.
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)
promoted_type const dx = get<0>(p) - get<0>(vertex);
promoted_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_GEOMETRY_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