mirror of
https://github.com/boostorg/geometry.git
synced 2026-02-17 13:52:09 +00:00
Harmonized offset with buffer, using range_buffer, and making hooklets vary on parameter.
This repairs offset (broken few days) [SVN r76767]
This commit is contained in:
@@ -11,20 +11,12 @@
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined(BOOST_MSVC_FULL_VER)
|
||||
#pragma message ("WARNING: offset might give wrong results, will be harmonized with range_buffer")
|
||||
#else
|
||||
#warning "WARNING: offset might give wrong results, will be harmonized with range_buffer"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#include <boost/range/functions.hpp>
|
||||
#include <boost/range/metafunctions.hpp>
|
||||
|
||||
#include <boost/geometry/core/point_type.hpp>
|
||||
#include <boost/geometry/extensions/algorithms/buffer/buffer_appender.hpp>
|
||||
#include <boost/geometry/extensions/algorithms/buffer/line_line_intersection.hpp>
|
||||
#include <boost/geometry/extensions/algorithms/buffer/range_buffer.hpp>
|
||||
#include <boost/geometry/extensions/algorithms/offset_appender.hpp>
|
||||
#include <boost/geometry/algorithms/detail/disjoint.hpp>
|
||||
#include <boost/geometry/geometries/concepts/check.hpp>
|
||||
|
||||
@@ -44,81 +36,26 @@ template
|
||||
typename Range,
|
||||
typename RangeOut,
|
||||
typename JoinStrategy,
|
||||
typename Distance
|
||||
typename DistanceStrategy
|
||||
>
|
||||
struct offset_range
|
||||
: public geometry::detail::buffer::range_buffer
|
||||
<
|
||||
RangeOut,
|
||||
DistanceStrategy,
|
||||
JoinStrategy,
|
||||
linestring_tag
|
||||
>
|
||||
{
|
||||
typedef typename coordinate_type<RangeOut>::type coordinate_type;
|
||||
typedef typename point_type<RangeOut>::type output_point_type;
|
||||
typedef model::referring_segment<output_point_type const> segment_type;
|
||||
typedef typename boost::range_iterator<Range const>::type iterator_type;
|
||||
|
||||
template <typename Appender>
|
||||
static inline void apply(Range const& range,
|
||||
Appender& appender,
|
||||
JoinStrategy const& join,
|
||||
Distance const& distance)
|
||||
DistanceStrategy const& distance,
|
||||
JoinStrategy const& join)
|
||||
{
|
||||
output_point_type previous_p1, previous_p2;
|
||||
output_point_type first_p1, first_p2;
|
||||
|
||||
bool first = true;
|
||||
|
||||
iterator_type it = boost::begin(range);
|
||||
for (iterator_type prev = it++; it != boost::end(range); ++it)
|
||||
{
|
||||
if (! detail::equals::equals_point_point(*prev, *it))
|
||||
{
|
||||
// Simulate a vector d (dx,dy)
|
||||
coordinate_type dx = get<0>(*it) - get<0>(*prev);
|
||||
coordinate_type dy = get<1>(*it) - get<1>(*prev);
|
||||
|
||||
// For normalization [0,1] (=dot product d.d, sqrt)
|
||||
coordinate_type length = sqrt(dx * dx + dy * dy);
|
||||
|
||||
// Because coordinates are not equal, length should not be zero
|
||||
BOOST_ASSERT((! geometry::math::equals(length, 0)));
|
||||
|
||||
// Generate the normalized perpendicular p, to the left (ccw)
|
||||
coordinate_type px = -dy / length;
|
||||
coordinate_type py = dx / length;
|
||||
|
||||
output_point_type p1, p2;
|
||||
|
||||
set<0>(p2, get<0>(*it) + px * distance);
|
||||
set<1>(p2, get<1>(*it) + py * distance);
|
||||
|
||||
set<0>(p1, get<0>(*prev) + px * distance);
|
||||
set<1>(p1, get<1>(*prev) + py * distance);
|
||||
|
||||
if (! first)
|
||||
{
|
||||
output_point_type p;
|
||||
segment_type s1(p1, p2);
|
||||
segment_type s2(previous_p1, previous_p2);
|
||||
if (detail::buffer::line_line_intersection<output_point_type, segment_type>::apply(s1, s2, p))
|
||||
{
|
||||
join.apply(p, *prev, previous_p2, p1, distance, appender);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
first = false;
|
||||
first_p1 = p1;
|
||||
first_p2 = p2;
|
||||
|
||||
appender.append(p1);
|
||||
}
|
||||
|
||||
previous_p1 = p1;
|
||||
previous_p2 = p2;
|
||||
prev = it;
|
||||
}
|
||||
}
|
||||
|
||||
// Last one
|
||||
appender.append(previous_p2);
|
||||
|
||||
iterate(appender, boost::begin(range), boost::end(range),
|
||||
buffer_side_left,
|
||||
distance, join);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -138,7 +75,7 @@ template
|
||||
typename Geometry,
|
||||
typename GeometryOut,
|
||||
typename JoinStrategy,
|
||||
typename Distance
|
||||
typename DistanceStrategy
|
||||
>
|
||||
struct offset
|
||||
{};
|
||||
@@ -149,7 +86,7 @@ template
|
||||
typename Geometry,
|
||||
typename GeometryOut,
|
||||
typename JoinStrategy,
|
||||
typename Distance
|
||||
typename DistanceStrategy
|
||||
>
|
||||
struct offset
|
||||
<
|
||||
@@ -158,14 +95,14 @@ struct offset
|
||||
Geometry,
|
||||
GeometryOut,
|
||||
JoinStrategy,
|
||||
Distance
|
||||
DistanceStrategy
|
||||
>
|
||||
: detail::offset::offset_range
|
||||
<
|
||||
Geometry,
|
||||
GeometryOut,
|
||||
JoinStrategy,
|
||||
Distance
|
||||
DistanceStrategy
|
||||
>
|
||||
{};
|
||||
|
||||
@@ -188,7 +125,14 @@ inline void offset(Geometry const& geometry, GeometryOut& out,
|
||||
concept::check<Geometry const>();
|
||||
concept::check<GeometryOut>();
|
||||
|
||||
typedef detail::buffer::buffer_appender
|
||||
typedef strategy::buffer::distance_assymetric
|
||||
<
|
||||
typename geometry::coordinate_type<Geometry>::type
|
||||
> distance_strategy_type;
|
||||
distance_strategy_type distance_strategy(distance, distance);
|
||||
|
||||
|
||||
typedef detail::offset::offset_appender
|
||||
<
|
||||
GeometryOut
|
||||
> appender_type;
|
||||
@@ -202,8 +146,8 @@ inline void offset(Geometry const& geometry, GeometryOut& out,
|
||||
Geometry,
|
||||
GeometryOut,
|
||||
JoinStrategy,
|
||||
Distance
|
||||
>::apply(geometry, appender, join, distance);
|
||||
distance_strategy_type
|
||||
>::apply(geometry, appender, distance_strategy, join);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2007-2012 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_ALGORITHMS_DETAIL_OFFSET_APPENDER_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OFFSET_APPENDER_HPP
|
||||
|
||||
|
||||
#include <boost/range.hpp>
|
||||
|
||||
#include <boost/geometry/core/point_type.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace offset
|
||||
{
|
||||
|
||||
// Appends points to an output range (linestring/ring).
|
||||
template
|
||||
<
|
||||
typename Range
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
|
||||
, typename Mapper
|
||||
#endif
|
||||
>
|
||||
struct offset_appender
|
||||
{
|
||||
typedef Range range_type;
|
||||
|
||||
typedef typename geometry::point_type<Range>::type point_type;
|
||||
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
|
||||
Mapper const& m_mapper;
|
||||
inline offset_appender(Range& r, Mapper const& mapper)
|
||||
: m_range(r)
|
||||
, m_mapper(mapper)
|
||||
#else
|
||||
inline offset_appender(Range& r)
|
||||
: m_range(r)
|
||||
#endif
|
||||
|
||||
{}
|
||||
|
||||
inline void append(point_type const& point)
|
||||
{
|
||||
do_append(point);
|
||||
}
|
||||
|
||||
inline void append_begin_join(point_type const& point)
|
||||
{
|
||||
do_append(point);
|
||||
}
|
||||
|
||||
inline void append_end_join(point_type const& point)
|
||||
{
|
||||
do_append(point);
|
||||
}
|
||||
|
||||
inline void append_begin_hooklet(point_type const& point)
|
||||
{
|
||||
do_append(point);
|
||||
}
|
||||
|
||||
inline void append_end_hooklet(point_type const& point)
|
||||
{
|
||||
do_append(point);
|
||||
}
|
||||
|
||||
|
||||
private :
|
||||
|
||||
Range& m_range;
|
||||
|
||||
inline void do_append(point_type const& point)
|
||||
{
|
||||
m_range.push_back(point);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}} // namespace detail::offset
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OFFSET_APPENDER_HPP
|
||||
@@ -92,7 +92,7 @@ struct join_mapper
|
||||
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
|
||||
// Forget this, it will go
|
||||
template<typename PointIn, typename PointOut, typename Mapper>
|
||||
template<typename PointIn, typename PointOut, bool AddHooklets, typename Mapper>
|
||||
struct join_miter : public join_mapper<PointIn, Mapper>
|
||||
{
|
||||
join_miter(Mapper const& mapper) : join_mapper(mapper) {}
|
||||
@@ -102,7 +102,8 @@ struct join_miter : public join_mapper<PointIn, Mapper>
|
||||
template
|
||||
<
|
||||
typename PointIn,
|
||||
typename PointOut
|
||||
typename PointOut,
|
||||
bool AddHooklets = true
|
||||
>
|
||||
struct join_miter
|
||||
{
|
||||
@@ -125,11 +126,15 @@ struct join_miter
|
||||
|
||||
if (side::apply(perp1, ip, perp2) == signum)
|
||||
{
|
||||
// If it is concave (corner to left), add helperline
|
||||
// The helper-line IS essential for buffering holes. Without,
|
||||
// holes might be generated, while they should NOT be there.
|
||||
appender.append_begin_hooklet(perp1);
|
||||
appender.append_end_hooklet(perp2);
|
||||
if (AddHooklets)
|
||||
{
|
||||
appender.append_begin_hooklet(perp1);
|
||||
appender.append_end_hooklet(perp2);
|
||||
}
|
||||
else
|
||||
{
|
||||
appender.append(ip);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -210,7 +215,7 @@ struct join_bevel
|
||||
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
|
||||
// Forget this, it will go
|
||||
template<typename PointIn, typename PointOut, typename Mapper>
|
||||
template<typename PointIn, typename PointOut, bool Hooklets, typename Mapper>
|
||||
struct join_round : public join_mapper<PointIn, Mapper>
|
||||
{
|
||||
join_round(Mapper const& mapper, int max_level = 4)
|
||||
@@ -223,7 +228,8 @@ struct join_round : public join_mapper<PointIn, Mapper>
|
||||
template
|
||||
<
|
||||
typename PointIn,
|
||||
typename PointOut
|
||||
typename PointOut,
|
||||
bool AddHooklets = true
|
||||
>
|
||||
struct join_round
|
||||
{
|
||||
@@ -291,8 +297,15 @@ struct join_round
|
||||
if (side::apply(perp1, ip, perp2) == signum)
|
||||
{
|
||||
// If it is concave (corner to left), add helperline
|
||||
appender.append_begin_hooklet(perp1);
|
||||
appender.append_end_hooklet(perp2);
|
||||
if (AddHooklets)
|
||||
{
|
||||
appender.append_begin_hooklet(perp1);
|
||||
appender.append_end_hooklet(perp2);
|
||||
}
|
||||
else
|
||||
{
|
||||
appender.append(ip);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user