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:
Barend Gehrels
2012-01-28 21:13:39 +00:00
parent 3b26c5f6c0
commit a4bb2f9de1
5 changed files with 167 additions and 113 deletions

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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
{