mirror of
https://github.com/boostorg/geometry.git
synced 2025-05-11 13:34:10 +00:00
[geometry] reorganized buffer strategies
[SVN r83272]
This commit is contained in:
parent
e8422b1be3
commit
ce3e4e858e
@ -17,13 +17,12 @@
|
||||
|
||||
// Buffer strategies
|
||||
|
||||
#include <boost/geometry/core/cs.hpp>
|
||||
#include <boost/geometry/strategies/tags.hpp>
|
||||
#include <boost/geometry/strategies/side.hpp>
|
||||
#include <boost/geometry/util/math.hpp>
|
||||
#include <boost/geometry/util/select_most_precise.hpp>
|
||||
|
||||
#include <boost/geometry/extensions/strategies/buffer_side.hpp>
|
||||
#include <boost/geometry/extensions/strategies/buffer_join_miter.hpp>
|
||||
#include <boost/geometry/extensions/strategies/buffer_join_round.hpp>
|
||||
#include <boost/geometry/extensions/strategies/buffer_join_round_by_divide.hpp>
|
||||
#include <boost/geometry/extensions/strategies/buffer_distance_symmetric.hpp>
|
||||
#include <boost/geometry/extensions/strategies/buffer_distance_asymmetric.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
@ -61,308 +60,6 @@ namespace strategy { namespace buffer
|
||||
|
||||
|
||||
|
||||
// TODO: merge join_miter with join_round, lot of duplicate code
|
||||
|
||||
template
|
||||
<
|
||||
typename PointIn,
|
||||
typename PointOut
|
||||
>
|
||||
struct join_miter
|
||||
{
|
||||
typedef typename strategy::side::services::default_strategy<typename cs_tag<PointIn>::type>::type side;
|
||||
typedef typename coordinate_type<PointIn>::type coordinate_type;
|
||||
|
||||
|
||||
template <typename RangeOut>
|
||||
inline void apply(PointIn const& ip, PointIn const& vertex,
|
||||
PointIn const& perp1, PointIn const& perp2,
|
||||
coordinate_type const& buffer_distance,
|
||||
RangeOut& range_out) const
|
||||
{
|
||||
coordinate_type zero = 0;
|
||||
int signum = buffer_distance > zero ? 1
|
||||
: buffer_distance < zero ? -1
|
||||
: 0;
|
||||
|
||||
if (side::apply(perp1, ip, perp2) == signum)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
PointIn p = ip;
|
||||
|
||||
// Normalize it and give it X*dist.
|
||||
coordinate_type dx = get<0>(ip) - get<0>(vertex);
|
||||
coordinate_type dy = get<1>(ip) - get<1>(vertex);
|
||||
|
||||
coordinate_type length = sqrt(dx * dx + dy * dy);
|
||||
|
||||
// TODO: make max-mitre-limit flexible
|
||||
coordinate_type ten = 10.0;
|
||||
coordinate_type zero_seven = 0.7;
|
||||
|
||||
coordinate_type max = ten * geometry::math::abs(buffer_distance);
|
||||
|
||||
if (length > max)
|
||||
{
|
||||
|
||||
coordinate_type prop = zero_seven * buffer_distance;
|
||||
prop /= length;
|
||||
set<0>(p, get<0>(vertex) + dx * prop);
|
||||
set<1>(p, get<1>(vertex) + dy * prop);
|
||||
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_BUFFER
|
||||
std::cout << length << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
range_out.push_back(perp1);
|
||||
range_out.push_back(p);
|
||||
range_out.push_back(perp2);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename PointIn,
|
||||
typename PointOut
|
||||
>
|
||||
struct join_bevel
|
||||
{
|
||||
typedef typename coordinate_type<PointIn>::type coordinate_type;
|
||||
|
||||
template <typename RangeOut>
|
||||
inline void apply(PointIn const& ip, PointIn const& vertex,
|
||||
PointIn const& perp1, PointIn const& perp2,
|
||||
coordinate_type const& buffer_distance,
|
||||
RangeOut& range_out) const
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename PointIn,
|
||||
typename PointOut
|
||||
>
|
||||
struct join_round
|
||||
{
|
||||
#ifdef BOOST_GEOMETRY_BUFFER_USE_MIDPOINTS
|
||||
inline join_round(int max_level = 4)
|
||||
: m_max_level(max_level)
|
||||
#else
|
||||
inline join_round(int steps_per_circle = 100)
|
||||
: m_steps_per_circle(steps_per_circle)
|
||||
#endif
|
||||
{}
|
||||
|
||||
typedef typename strategy::side::services::default_strategy<typename cs_tag<PointIn>::type>::type side;
|
||||
typedef typename coordinate_type<PointOut>::type coordinate_type;
|
||||
|
||||
typedef typename geometry::select_most_precise
|
||||
<
|
||||
typename geometry::select_most_precise
|
||||
<
|
||||
typename geometry::coordinate_type<PointIn>::type,
|
||||
typename geometry::coordinate_type<PointOut>::type
|
||||
>::type,
|
||||
double
|
||||
>::type promoted_type;
|
||||
|
||||
|
||||
#ifdef BOOST_GEOMETRY_BUFFER_USE_MIDPOINTS
|
||||
|
||||
int m_max_level;
|
||||
|
||||
template <typename RangeOut>
|
||||
inline void mid_points(PointIn const& vertex,
|
||||
PointIn const& p1, PointIn const& p2,
|
||||
coordinate_type const& buffer_distance,
|
||||
RangeOut& range_out,
|
||||
int level = 1) const
|
||||
{
|
||||
// Generate 'vectors'
|
||||
coordinate_type vp1_x = get<0>(p1) - get<0>(vertex);
|
||||
coordinate_type vp1_y = get<1>(p1) - get<1>(vertex);
|
||||
|
||||
coordinate_type vp2_x = (get<0>(p2) - get<0>(vertex));
|
||||
coordinate_type vp2_y = (get<1>(p2) - get<1>(vertex));
|
||||
|
||||
// Average them to generate vector in between
|
||||
coordinate_type two = 2;
|
||||
coordinate_type v_x = (vp1_x + vp2_x) / two;
|
||||
coordinate_type v_y = (vp1_y + vp2_y) / two;
|
||||
|
||||
coordinate_type length2 = sqrt(v_x * v_x + v_y * v_y);
|
||||
|
||||
coordinate_type prop = buffer_distance / length2;
|
||||
|
||||
PointIn mid_point;
|
||||
set<0>(mid_point, get<0>(vertex) + v_x * prop);
|
||||
set<1>(mid_point, get<1>(vertex) + v_y * prop);
|
||||
|
||||
if (level < m_max_level)
|
||||
{
|
||||
mid_points(vertex, p1, mid_point, buffer_distance, range_out, level + 1);
|
||||
}
|
||||
range_out.push_back(mid_point);
|
||||
if (level < m_max_level)
|
||||
{
|
||||
mid_points(vertex, mid_point, p2, buffer_distance, range_out, level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int m_steps_per_circle;
|
||||
|
||||
template <typename RangeOut>
|
||||
inline void generate_points(PointIn const& vertex,
|
||||
PointIn const& perp1, PointIn const& perp2,
|
||||
promoted_type const& buffer_distance,
|
||||
RangeOut& range_out) const
|
||||
{
|
||||
promoted_type dx1 = get<0>(perp1) - get<0>(vertex);
|
||||
promoted_type dy1 = get<1>(perp1) - get<1>(vertex);
|
||||
promoted_type dx2 = get<0>(perp2) - get<0>(vertex);
|
||||
promoted_type dy2 = get<1>(perp2) - get<1>(vertex);
|
||||
|
||||
dx1 /= buffer_distance;
|
||||
dy1 /= buffer_distance;
|
||||
dx2 /= buffer_distance;
|
||||
dy2 /= buffer_distance;
|
||||
|
||||
promoted_type angle_diff = acos(dx1 * dx2 + dy1 * dy2);
|
||||
|
||||
promoted_type two = 2.0;
|
||||
promoted_type steps = m_steps_per_circle;
|
||||
int n = boost::numeric_cast<int>(steps * angle_diff
|
||||
/ (two * geometry::math::pi<promoted_type>()));
|
||||
|
||||
if (n > 1000)
|
||||
{
|
||||
// TODO change this / verify this
|
||||
std::cout << dx1 << ", " << dy1 << " .. " << dx2 << ", " << dy2 << std::endl;
|
||||
std::cout << angle_diff << " -> " << n << std::endl;
|
||||
n = 1000;
|
||||
}
|
||||
else if (n <= 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
promoted_type const angle1 = atan2(dy1, dx1);
|
||||
promoted_type diff = angle_diff / promoted_type(n);
|
||||
promoted_type a = angle1 - diff;
|
||||
|
||||
for (int i = 0; i < n - 1; i++, a -= diff)
|
||||
{
|
||||
PointIn p;
|
||||
set<0>(p, get<0>(vertex) + buffer_distance * cos(a));
|
||||
set<1>(p, get<1>(vertex) + buffer_distance * sin(a));
|
||||
range_out.push_back(p);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename RangeOut>
|
||||
inline void apply(PointIn const& ip, PointIn const& vertex,
|
||||
PointIn const& perp1, PointIn const& perp2,
|
||||
coordinate_type const& buffer_distance,
|
||||
RangeOut& range_out) const
|
||||
{
|
||||
if (geometry::equals(perp1, perp2))
|
||||
{
|
||||
//std::cout << "Corner for equal points " << geometry::wkt(ip) << " " << geometry::wkt(perp1) << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
coordinate_type zero = 0;
|
||||
int signum = buffer_distance > zero ? 1
|
||||
: buffer_distance < zero ? -1
|
||||
: 0;
|
||||
|
||||
if (side::apply(perp1, ip, perp2) == signum)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
// Generate 'vectors'
|
||||
coordinate_type vix = (get<0>(ip) - get<0>(vertex));
|
||||
coordinate_type viy = (get<1>(ip) - get<1>(vertex));
|
||||
|
||||
coordinate_type length_i = sqrt(vix * vix + viy * viy);
|
||||
|
||||
|
||||
coordinate_type const bd = geometry::math::abs(buffer_distance);
|
||||
coordinate_type prop = bd / length_i;
|
||||
|
||||
PointIn bp;
|
||||
set<0>(bp, get<0>(vertex) + vix * prop);
|
||||
set<1>(bp, get<1>(vertex) + viy * prop);
|
||||
|
||||
range_out.push_back(perp1);
|
||||
|
||||
#ifdef BOOST_GEOMETRY_BUFFER_USE_MIDPOINTS
|
||||
if (m_max_level <= 1)
|
||||
{
|
||||
if (m_max_level == 1)
|
||||
{
|
||||
range_out.push_back(bp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mid_points(vertex, perp1, bp, bd, range_out);
|
||||
range_out.push_back(bp);
|
||||
mid_points(vertex, bp, perp2, bd, range_out);
|
||||
}
|
||||
#else
|
||||
generate_points(vertex, perp1, perp2, bd, range_out);
|
||||
#endif
|
||||
|
||||
range_out.push_back(perp2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename CoordinateType
|
||||
>
|
||||
class distance_assymetric
|
||||
{
|
||||
public :
|
||||
distance_assymetric(CoordinateType const& left,
|
||||
CoordinateType const& right)
|
||||
: m_left(left)
|
||||
, m_right(right)
|
||||
{}
|
||||
|
||||
template <typename Point>
|
||||
inline CoordinateType apply(Point const& , Point const& ,
|
||||
buffer_side_selector side) const
|
||||
{
|
||||
return side == buffer_side_left ? m_left : m_right;
|
||||
}
|
||||
|
||||
inline int factor() const
|
||||
{
|
||||
return m_left < 0 ? -1 : 1;
|
||||
}
|
||||
|
||||
private :
|
||||
CoordinateType m_left;
|
||||
CoordinateType m_right;
|
||||
};
|
||||
|
||||
|
||||
}} // namespace strategy::buffer
|
||||
|
||||
|
@ -0,0 +1,58 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2007-2013 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_EXTENSIONS_STRATEGIES_BUFFER_DISTANCE_ASYMMETRIC_HPP
|
||||
#define BOOST_GEOMETRY_EXTENSIONS_STRATEGIES_BUFFER_DISTANCE_ASYMMETRIC_HPP
|
||||
|
||||
|
||||
// Buffer strategies
|
||||
|
||||
#include <boost/geometry/extensions/strategies/buffer_side.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
namespace strategy { namespace buffer
|
||||
{
|
||||
|
||||
|
||||
template<typename CoordinateType>
|
||||
class distance_asymmetric
|
||||
{
|
||||
public :
|
||||
distance_asymmetric(CoordinateType const& left,
|
||||
CoordinateType const& right)
|
||||
: m_left(left)
|
||||
, m_right(right)
|
||||
{}
|
||||
|
||||
template <typename Point>
|
||||
inline CoordinateType apply(Point const& , Point const& ,
|
||||
buffer_side_selector side) const
|
||||
{
|
||||
return side == buffer_side_left ? m_left : m_right;
|
||||
}
|
||||
|
||||
inline int factor() const
|
||||
{
|
||||
return m_left < 0 ? -1 : 1;
|
||||
}
|
||||
|
||||
private :
|
||||
CoordinateType m_left;
|
||||
CoordinateType m_right;
|
||||
};
|
||||
|
||||
|
||||
}} // namespace strategy::buffer
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_EXTENSIONS_STRATEGIES_BUFFER_DISTANCE_ASYMMETRIC_HPP
|
@ -0,0 +1,55 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2007-2013 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_EXTENSIONS_STRATEGIES_BUFFER_DISTANCE_SYMMETRIC_HPP
|
||||
#define BOOST_GEOMETRY_EXTENSIONS_STRATEGIES_BUFFER_DISTANCE_SYMMETRIC_HPP
|
||||
|
||||
|
||||
// Buffer strategies
|
||||
|
||||
#include <boost/geometry/extensions/strategies/buffer_side.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
namespace strategy { namespace buffer
|
||||
{
|
||||
|
||||
|
||||
template<typename CoordinateType>
|
||||
class distance_symmetric
|
||||
{
|
||||
public :
|
||||
inline distance_symmetric(CoordinateType const& distance)
|
||||
: m_distance(distance)
|
||||
{}
|
||||
|
||||
template <typename Point>
|
||||
inline CoordinateType apply(Point const& , Point const& ,
|
||||
buffer_side_selector side) const
|
||||
{
|
||||
return m_distance;
|
||||
}
|
||||
|
||||
inline int factor() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
private :
|
||||
CoordinateType m_distance;
|
||||
};
|
||||
|
||||
|
||||
}} // namespace strategy::buffer
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_EXTENSIONS_STRATEGIES_BUFFER_DISTANCE_SYMMETRIC_HPP
|
@ -0,0 +1,104 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2007-2013 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_EXTENSIONS_STRATEGIES_BUFFER_JOIN_MITER_HPP
|
||||
#define BOOST_GEOMETRY_EXTENSIONS_STRATEGIES_BUFFER_JOIN_MITER_HPP
|
||||
|
||||
|
||||
// Buffer strategies
|
||||
|
||||
#include <boost/geometry/core/cs.hpp>
|
||||
#include <boost/geometry/strategies/tags.hpp>
|
||||
#include <boost/geometry/strategies/side.hpp>
|
||||
#include <boost/geometry/util/math.hpp>
|
||||
#include <boost/geometry/util/select_most_precise.hpp>
|
||||
|
||||
#include <boost/geometry/extensions/strategies/buffer_side.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
namespace strategy { namespace buffer
|
||||
{
|
||||
|
||||
// TODO: condider merging/baseclassing join strategies to avoid duplicate code
|
||||
|
||||
template
|
||||
<
|
||||
typename PointIn,
|
||||
typename PointOut
|
||||
>
|
||||
struct join_miter
|
||||
{
|
||||
typedef typename strategy::side::services::default_strategy<typename cs_tag<PointIn>::type>::type side;
|
||||
typedef typename coordinate_type<PointIn>::type coordinate_type;
|
||||
|
||||
// Constructor compatible with other join strategies:
|
||||
inline join_miter(int = 0)
|
||||
{}
|
||||
|
||||
template <typename RangeOut>
|
||||
inline void apply(PointIn const& ip, PointIn const& vertex,
|
||||
PointIn const& perp1, PointIn const& perp2,
|
||||
coordinate_type const& buffer_distance,
|
||||
RangeOut& range_out) const
|
||||
{
|
||||
coordinate_type zero = 0;
|
||||
int signum = buffer_distance > zero ? 1
|
||||
: buffer_distance < zero ? -1
|
||||
: 0;
|
||||
|
||||
if (side::apply(perp1, ip, perp2) == signum)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
PointIn p = ip;
|
||||
|
||||
// Normalize it and give it X*dist.
|
||||
coordinate_type dx = get<0>(ip) - get<0>(vertex);
|
||||
coordinate_type dy = get<1>(ip) - get<1>(vertex);
|
||||
|
||||
coordinate_type length = sqrt(dx * dx + dy * dy);
|
||||
|
||||
// TODO: make max-mitre-limit flexible
|
||||
coordinate_type ten = 10.0;
|
||||
coordinate_type zero_seven = 0.7;
|
||||
|
||||
coordinate_type max = ten * geometry::math::abs(buffer_distance);
|
||||
|
||||
if (length > max)
|
||||
{
|
||||
|
||||
coordinate_type prop = zero_seven * buffer_distance;
|
||||
prop /= length;
|
||||
set<0>(p, get<0>(vertex) + dx * prop);
|
||||
set<1>(p, get<1>(vertex) + dy * prop);
|
||||
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_BUFFER
|
||||
std::cout << length << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
range_out.push_back(perp1);
|
||||
range_out.push_back(p);
|
||||
range_out.push_back(perp2);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}} // namespace strategy::buffer
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_EXTENSIONS_STRATEGIES_BUFFER_JOIN_MITER_HPP
|
@ -1,11 +1,6 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
|
||||
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
|
||||
|
||||
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
|
||||
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
|
||||
// Copyright (c) 2007-2013 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
|
||||
@ -15,157 +10,143 @@
|
||||
#define BOOST_GEOMETRY_EXTENSIONS_STRATEGIES_BUFFER_JOIN_ROUND_HPP
|
||||
|
||||
|
||||
// Buffer strategies
|
||||
|
||||
#include <boost/geometry/algorithms/convert.hpp>
|
||||
#include <boost/geometry/arithmetic/arithmetic.hpp>
|
||||
#include <boost/geometry/arithmetic/dot_product.hpp>
|
||||
#include <boost/geometry/core/cs.hpp>
|
||||
#include <boost/geometry/strategies/tags.hpp>
|
||||
#include <boost/geometry/strategies/side.hpp>
|
||||
#include <boost/geometry/util/math.hpp>
|
||||
#include <boost/geometry/util/select_most_precise.hpp>
|
||||
|
||||
#include <boost/geometry/extensions/strategies/buffer_side.hpp>
|
||||
|
||||
|
||||
#define BOOST_GEOMETRY_BUFFER_NO_HELPER_POINTS
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
namespace strategy { namespace buffer
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename PointOut>
|
||||
struct join_round2
|
||||
template
|
||||
<
|
||||
typename PointIn,
|
||||
typename PointOut
|
||||
>
|
||||
struct join_round
|
||||
{
|
||||
typedef PointOut vector_type;
|
||||
|
||||
template <typename Vector, typename Point1, typename Point2>
|
||||
static inline Vector create_vector(Point1 const& p1, Point2 const& p2)
|
||||
{
|
||||
Vector v;
|
||||
geometry::convert(p1, v);
|
||||
subtract_point(v, p2);
|
||||
return v;
|
||||
}
|
||||
|
||||
inline join_round2(int max_level = 4)
|
||||
: m_max_level(max_level)
|
||||
inline join_round(int steps_per_circle = 100)
|
||||
: m_steps_per_circle(steps_per_circle)
|
||||
{}
|
||||
|
||||
typedef typename strategy::side::services::default_strategy<typename cs_tag<PointIn>::type>::type side;
|
||||
typedef typename coordinate_type<PointOut>::type coordinate_type;
|
||||
int m_max_level;
|
||||
|
||||
typedef typename geometry::select_most_precise
|
||||
<
|
||||
typename geometry::select_most_precise
|
||||
<
|
||||
typename geometry::coordinate_type<PointIn>::type,
|
||||
typename geometry::coordinate_type<PointOut>::type
|
||||
>::type,
|
||||
double
|
||||
>::type promoted_type;
|
||||
|
||||
template <typename OutputIterator, typename Point, typename PointP, typename Point1, typename Point2>
|
||||
inline void mid_points(Point const& vertex, PointP const& perpendicular,
|
||||
Point1 const& p1, Point2 const& p2,
|
||||
coordinate_type const& buffer_distance,
|
||||
coordinate_type const& max_distance,
|
||||
OutputIterator out,
|
||||
int level = 1) const
|
||||
int m_steps_per_circle;
|
||||
|
||||
template <typename RangeOut>
|
||||
inline void generate_points(PointIn const& vertex,
|
||||
PointIn const& perp1, PointIn const& perp2,
|
||||
promoted_type const& buffer_distance,
|
||||
RangeOut& range_out) const
|
||||
{
|
||||
// Generate 'vectors'
|
||||
coordinate_type vp1_x = get<0>(p1) - get<0>(vertex);
|
||||
coordinate_type vp1_y = get<1>(p1) - get<1>(vertex);
|
||||
promoted_type dx1 = get<0>(perp1) - get<0>(vertex);
|
||||
promoted_type dy1 = get<1>(perp1) - get<1>(vertex);
|
||||
promoted_type dx2 = get<0>(perp2) - get<0>(vertex);
|
||||
promoted_type dy2 = get<1>(perp2) - get<1>(vertex);
|
||||
|
||||
coordinate_type vp2_x = (get<0>(p2) - get<0>(vertex));
|
||||
coordinate_type vp2_y = (get<1>(p2) - get<1>(vertex));
|
||||
dx1 /= buffer_distance;
|
||||
dy1 /= buffer_distance;
|
||||
dx2 /= buffer_distance;
|
||||
dy2 /= buffer_distance;
|
||||
|
||||
// Average them to generate vector in between
|
||||
coordinate_type two = 2;
|
||||
coordinate_type v_x = (vp1_x + vp2_x) / two;
|
||||
coordinate_type v_y = (vp1_y + vp2_y) / two;
|
||||
promoted_type angle_diff = acos(dx1 * dx2 + dy1 * dy2);
|
||||
|
||||
coordinate_type between_length = sqrt(v_x * v_x + v_y * v_y);
|
||||
promoted_type two = 2.0;
|
||||
promoted_type steps = m_steps_per_circle;
|
||||
int n = boost::numeric_cast<int>(steps * angle_diff
|
||||
/ (two * geometry::math::pi<promoted_type>()));
|
||||
|
||||
coordinate_type const positive_buffer_distance = geometry::math::abs(buffer_distance);
|
||||
coordinate_type prop = positive_buffer_distance / between_length;
|
||||
|
||||
PointOut mid_point;
|
||||
set<0>(mid_point, get<0>(vertex) + v_x * prop);
|
||||
set<1>(mid_point, get<1>(vertex) + v_y * prop);
|
||||
|
||||
if (buffer_distance > max_distance)
|
||||
if (n > 1000)
|
||||
{
|
||||
// Calculate point projected on original perpendicular segment,
|
||||
// using vector maths
|
||||
vector_type v = create_vector<vector_type>(perpendicular, vertex);
|
||||
vector_type w = create_vector<vector_type>(mid_point, vertex);
|
||||
|
||||
coordinate_type c1 = dot_product(w, v);
|
||||
if (c1 > 0)
|
||||
{
|
||||
coordinate_type c2 = dot_product(v, v);
|
||||
if (c2 > c1)
|
||||
{
|
||||
coordinate_type b = c1 / c2;
|
||||
|
||||
PointOut projected_point;
|
||||
|
||||
multiply_value(v, b);
|
||||
geometry::convert(vertex, projected_point);
|
||||
add_point(projected_point, v);
|
||||
|
||||
coordinate_type projected_distance = geometry::distance(projected_point, mid_point);
|
||||
|
||||
if (projected_distance > max_distance)
|
||||
{
|
||||
// Do not generate from here on.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO change this / verify this
|
||||
std::cout << dx1 << ", " << dy1 << " .. " << dx2 << ", " << dy2 << std::endl;
|
||||
std::cout << angle_diff << " -> " << n << std::endl;
|
||||
n = 1000;
|
||||
}
|
||||
else if (n <= 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (level < m_max_level)
|
||||
promoted_type const angle1 = atan2(dy1, dx1);
|
||||
promoted_type diff = angle_diff / promoted_type(n);
|
||||
promoted_type a = angle1 - diff;
|
||||
|
||||
for (int i = 0; i < n - 1; i++, a -= diff)
|
||||
{
|
||||
mid_points(vertex, perpendicular, p1, mid_point, positive_buffer_distance, max_distance, out, level + 1);
|
||||
}
|
||||
*out++ = mid_point;
|
||||
if (level < m_max_level)
|
||||
{
|
||||
mid_points(vertex, perpendicular, mid_point, p2, positive_buffer_distance, max_distance, out, level + 1);
|
||||
PointIn p;
|
||||
set<0>(p, get<0>(vertex) + buffer_distance * cos(a));
|
||||
set<1>(p, get<1>(vertex) + buffer_distance * sin(a));
|
||||
range_out.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename OutputIterator, typename Point, typename Point2>
|
||||
inline OutputIterator apply(Point const& vertex,
|
||||
Point2 const& perpendicular,
|
||||
Point2 const& p1, Point2 const& p2,
|
||||
template <typename RangeOut>
|
||||
inline void apply(PointIn const& ip, PointIn const& vertex,
|
||||
PointIn const& perp1, PointIn const& perp2,
|
||||
coordinate_type const& buffer_distance,
|
||||
coordinate_type const& max_distance,
|
||||
OutputIterator out) const
|
||||
RangeOut& range_out) const
|
||||
{
|
||||
mid_points(vertex, perpendicular, p1, p2, buffer_distance, max_distance, out);
|
||||
return out;
|
||||
if (geometry::equals(perp1, perp2))
|
||||
{
|
||||
//std::cout << "Corner for equal points " << geometry::wkt(ip) << " " << geometry::wkt(perp1) << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
coordinate_type zero = 0;
|
||||
int signum = buffer_distance > zero ? 1
|
||||
: buffer_distance < zero ? -1
|
||||
: 0;
|
||||
|
||||
if (side::apply(perp1, ip, perp2) == signum)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
// Generate 'vectors'
|
||||
coordinate_type vix = (get<0>(ip) - get<0>(vertex));
|
||||
coordinate_type viy = (get<1>(ip) - get<1>(vertex));
|
||||
|
||||
coordinate_type length_i = sqrt(vix * vix + viy * viy);
|
||||
|
||||
coordinate_type const bd = geometry::math::abs(buffer_distance);
|
||||
coordinate_type prop = bd / length_i;
|
||||
|
||||
PointIn bp;
|
||||
set<0>(bp, get<0>(vertex) + vix * prop);
|
||||
set<1>(bp, get<1>(vertex) + viy * prop);
|
||||
|
||||
range_out.push_back(perp1);
|
||||
generate_points(vertex, perp1, perp2, bd, range_out);
|
||||
range_out.push_back(perp2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename PointOut>
|
||||
struct join_none
|
||||
{
|
||||
template <typename OutputIterator, typename Point, typename Point2,
|
||||
typename DistanceType>
|
||||
inline OutputIterator apply(Point const& ,
|
||||
Point2 const& ,
|
||||
Point2 const& , Point2 const& ,
|
||||
DistanceType const& ,
|
||||
DistanceType const& ,
|
||||
OutputIterator out) const
|
||||
{
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}} // namespace strategy::buffer
|
||||
|
@ -0,0 +1,157 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2007-2013 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_EXTENSIONS_STRATEGIES_BUFFER_JOIN_ROUND_BY_DIVIDE_HPP
|
||||
#define BOOST_GEOMETRY_EXTENSIONS_STRATEGIES_BUFFER_JOIN_ROUND_BY_DIVIDE_HPP
|
||||
|
||||
|
||||
// Buffer strategies
|
||||
|
||||
#include <boost/geometry/core/cs.hpp>
|
||||
#include <boost/geometry/strategies/tags.hpp>
|
||||
#include <boost/geometry/strategies/side.hpp>
|
||||
#include <boost/geometry/util/math.hpp>
|
||||
#include <boost/geometry/util/select_most_precise.hpp>
|
||||
|
||||
#include <boost/geometry/extensions/strategies/buffer_side.hpp>
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
|
||||
namespace strategy { namespace buffer
|
||||
{
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename PointIn,
|
||||
typename PointOut
|
||||
>
|
||||
struct join_round_by_divide
|
||||
{
|
||||
inline join_round_by_divide(int max_level = 4)
|
||||
: m_max_level(max_level)
|
||||
{}
|
||||
|
||||
typedef typename strategy::side::services::default_strategy<typename cs_tag<PointIn>::type>::type side;
|
||||
typedef typename coordinate_type<PointOut>::type coordinate_type;
|
||||
|
||||
typedef typename geometry::select_most_precise
|
||||
<
|
||||
typename geometry::select_most_precise
|
||||
<
|
||||
typename geometry::coordinate_type<PointIn>::type,
|
||||
typename geometry::coordinate_type<PointOut>::type
|
||||
>::type,
|
||||
double
|
||||
>::type promoted_type;
|
||||
|
||||
|
||||
int m_max_level;
|
||||
|
||||
template <typename RangeOut>
|
||||
inline void mid_points(PointIn const& vertex,
|
||||
PointIn const& p1, PointIn const& p2,
|
||||
coordinate_type const& buffer_distance,
|
||||
RangeOut& range_out,
|
||||
int level = 1) const
|
||||
{
|
||||
// Generate 'vectors'
|
||||
coordinate_type vp1_x = get<0>(p1) - get<0>(vertex);
|
||||
coordinate_type vp1_y = get<1>(p1) - get<1>(vertex);
|
||||
|
||||
coordinate_type vp2_x = (get<0>(p2) - get<0>(vertex));
|
||||
coordinate_type vp2_y = (get<1>(p2) - get<1>(vertex));
|
||||
|
||||
// Average them to generate vector in between
|
||||
coordinate_type two = 2;
|
||||
coordinate_type v_x = (vp1_x + vp2_x) / two;
|
||||
coordinate_type v_y = (vp1_y + vp2_y) / two;
|
||||
|
||||
coordinate_type length2 = sqrt(v_x * v_x + v_y * v_y);
|
||||
|
||||
coordinate_type prop = buffer_distance / length2;
|
||||
|
||||
PointIn mid_point;
|
||||
set<0>(mid_point, get<0>(vertex) + v_x * prop);
|
||||
set<1>(mid_point, get<1>(vertex) + v_y * prop);
|
||||
|
||||
if (level < m_max_level)
|
||||
{
|
||||
mid_points(vertex, p1, mid_point, buffer_distance, range_out, level + 1);
|
||||
}
|
||||
range_out.push_back(mid_point);
|
||||
if (level < m_max_level)
|
||||
{
|
||||
mid_points(vertex, mid_point, p2, buffer_distance, range_out, level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename RangeOut>
|
||||
inline void apply(PointIn const& ip, PointIn const& vertex,
|
||||
PointIn const& perp1, PointIn const& perp2,
|
||||
coordinate_type const& buffer_distance,
|
||||
RangeOut& range_out) const
|
||||
{
|
||||
if (geometry::equals(perp1, perp2))
|
||||
{
|
||||
//std::cout << "Corner for equal points " << geometry::wkt(ip) << " " << geometry::wkt(perp1) << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
coordinate_type zero = 0;
|
||||
int signum = buffer_distance > zero ? 1
|
||||
: buffer_distance < zero ? -1
|
||||
: 0;
|
||||
|
||||
if (side::apply(perp1, ip, perp2) == signum)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
// Generate 'vectors'
|
||||
coordinate_type vix = (get<0>(ip) - get<0>(vertex));
|
||||
coordinate_type viy = (get<1>(ip) - get<1>(vertex));
|
||||
|
||||
coordinate_type length_i = sqrt(vix * vix + viy * viy);
|
||||
|
||||
coordinate_type const bd = geometry::math::abs(buffer_distance);
|
||||
coordinate_type prop = bd / length_i;
|
||||
|
||||
PointIn bp;
|
||||
set<0>(bp, get<0>(vertex) + vix * prop);
|
||||
set<1>(bp, get<1>(vertex) + viy * prop);
|
||||
|
||||
range_out.push_back(perp1);
|
||||
|
||||
if (m_max_level > 1)
|
||||
{
|
||||
mid_points(vertex, perp1, bp, bd, range_out);
|
||||
range_out.push_back(bp);
|
||||
mid_points(vertex, bp, perp2, bd, range_out);
|
||||
}
|
||||
else if (m_max_level == 1)
|
||||
{
|
||||
range_out.push_back(bp);
|
||||
}
|
||||
|
||||
range_out.push_back(perp2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}} // namespace strategy::buffer
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_EXTENSIONS_STRATEGIES_BUFFER_JOIN_ROUND_BY_DIVIDE_HPP
|
Loading…
x
Reference in New Issue
Block a user