[buffer] extend piece analyses, check helper-segments for on-offsetted, on-original,

disjointness. This removes the workaround w.r.t. has_concave
This commit is contained in:
Barend Gehrels
2014-11-22 19:15:17 +01:00
parent 6be98196ed
commit 56fc166435
4 changed files with 168 additions and 30 deletions

View File

@@ -869,6 +869,11 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
typename tag_cast<typename tag<GeometryInput>::type, areal_tag>::type,
areal_tag
>::type::value;
bool const linear = boost::is_same
<
typename tag_cast<typename tag<GeometryInput>::type, linear_tag>::type,
linear_tag
>::type::value;
dispatch::buffer_inserter
<
@@ -885,6 +890,7 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
robust_policy);
collection.get_turns();
collection.classify_turns(linear);
if (areal)
{
collection.check_remaining_points(distance_strategy);

View File

@@ -124,6 +124,7 @@ struct buffer_turn_info
intersection_location_type location;
int count_within;
int count_on_original_boundary;
int count_on_offsetted;
int count_on_helper;
int count_within_near_offsetted;
@@ -138,6 +139,7 @@ struct buffer_turn_info
: turn_index(-1)
, location(location_ok)
, count_within(0)
, count_on_original_boundary(0)
, count_on_offsetted(0)
, count_on_helper(0)
, count_within_near_offsetted(0)

View File

@@ -379,7 +379,7 @@ struct buffered_piece_collection
}
}
inline void classify_turns()
inline void classify_turns(bool linear)
{
for (typename boost::range_iterator<turn_vector_type>::type it =
boost::begin(m_turns); it != boost::end(m_turns); ++it)
@@ -388,6 +388,10 @@ struct buffered_piece_collection
{
it->location = inside_buffer;
}
if (it->count_on_original_boundary > 0 && ! linear)
{
it->location = inside_buffer;
}
if (it->count_within_near_offsetted > 0)
{
// Within can have in rare cases a rounding issue. We don't discard this
@@ -599,10 +603,6 @@ struct buffered_piece_collection
>::apply(m_turns, m_pieces, visitor);
}
classify_turns();
//get_occupation();
}
inline void start_new_ring()

View File

@@ -59,6 +59,9 @@ enum analyse_result
{
analyse_unknown,
analyse_continue,
analyse_disjoint,
analyse_within,
analyse_on_original_boundary,
analyse_on_offsetted,
analyse_near_offsetted
};
@@ -116,13 +119,136 @@ class analyse_turn_wrt_piece
return analyse_continue;
}
template <typename Point>
static inline analyse_result check_helper_segment(Point const& s1,
Point const& s2, Point const& point,
analyse_result return_if_collinear,
Point const& offsetted)
{
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point>::type
>::type side_strategy;
switch(side_strategy::apply(s1, s2, point))
{
case 1 :
return analyse_disjoint; // left of segment
case 0 :
{
// If is collinear, either on segment or before/after
typedef geometry::model::box<Point> box_type;
box_type box;
bg::assign_inverse(box);
bg::expand(box, s1);
bg::expand(box, s2);
if (geometry::covered_by(point, box))
{
// It is on the segment
if (return_if_collinear == analyse_within
&& bg::comparable_distance(point, offsetted) <= 1)
{
// It is close to the offsetted-boundary, take
// any rounding-issues into account
return analyse_near_offsetted;
}
return return_if_collinear;
}
// It is not on the segment
return analyse_continue;
}
break;
}
// right of segment
return analyse_continue;
}
template <typename Point, typename Piece>
static inline analyse_result check_helper_segments(Point const& point, Piece const& piece)
{
geometry::equal_to<Point> comparator;
Point points[4];
int helper_count = piece.robust_ring.size() - piece.offsetted_count;
if (helper_count == 4)
{
for (int i = 0; i < 4; i++)
{
points[i] = piece.robust_ring[piece.offsetted_count + i];
}
}
else if (helper_count == 3)
{
// Triangular piece, assign points but assign second twice
for (int i = 0; i < 4; i++)
{
int index = i < 2 ? i : i - 1;
points[i] = piece.robust_ring[piece.offsetted_count + index];
}
}
else
{
// Some pieces (e.g. around points) do not have helper segments.
// Others should have 3 (join) or 4 (side)
return analyse_continue;
}
// First check point-equality
if (comparator(point, points[0]) || comparator(point, points[3]))
{
return analyse_on_offsetted;
}
if (comparator(point, points[1]) || comparator(point, points[2]))
{
return analyse_on_original_boundary;
}
// Right side
analyse_result result
= check_helper_segment(points[0], points[1], point,
analyse_within, points[0]);
if (result != analyse_continue)
{
return result;
}
// Left side
result = check_helper_segment(points[2], points[3], point,
analyse_within, points[3]);
if (result != analyse_continue)
{
return result;
}
if (! comparator(points[1], points[2]))
{
// Side at original
result = check_helper_segment(points[1], points[2], point,
analyse_on_original_boundary, point);
if (result != analyse_continue)
{
return result;
}
}
return analyse_continue;
}
public :
template <typename Point, typename Piece>
static inline analyse_result apply(Point const& point, Piece const& piece)
{
// TODO: we will check first helper-segments here, if it is left of
// any helper segment we're done (assuming joins stay within the area
// of the helper-segments, even if they have concavities there
analyse_result code = check_helper_segments(point, piece);
if (code != analyse_continue)
{
return code;
}
geometry::equal_to<Point> comparator;
@@ -135,14 +261,15 @@ public :
// (on which any side or side-value would return 0)
if (! comparator(previous, current))
{
analyse_result code = check_segment(previous, current, point);
code = check_segment(previous, current, point);
if (code != analyse_continue)
{
return code;
}
}
}
return analyse_unknown; // Not collinear or very close
return analyse_unknown;
}
};
@@ -186,10 +313,6 @@ public:
return;
}
// TEMPORARY solution to enable one-sided buffer.
// TODO: this will replaced by analyse_piece
bool has_concave = false;
bool neighbour = false;
for (int i = 0; i < 2; i++)
{
@@ -201,11 +324,6 @@ public:
Piece const& pc = m_pieces[turn.operations[i].piece_index];
if (pc.type == strategy::buffer::buffered_concave)
{
has_concave = true;
}
if (pc.left_index == piece.index
|| pc.right_index == piece.index)
{
@@ -225,6 +343,28 @@ public:
}
}
// TODO: mutable_piece to make some on-demand preparations in analyse
analyse_result analyse_code
= analyse_turn_wrt_piece::apply(turn.robust_point, piece);
Turn& mutable_turn = m_turns[turn.turn_index];
switch(analyse_code)
{
case analyse_disjoint :
return;
case analyse_on_offsetted :
mutable_turn.count_on_offsetted++; // value is not used anymore
return;
case analyse_on_original_boundary :
mutable_turn.count_on_original_boundary++;
return;
case analyse_within :
mutable_turn.count_within++;
return;
default :
break;
}
// TODO: this point_in_geometry is a performance-bottleneck here and
// will be replaced completely by extending analyse_piece functionality
int geometry_code = detail::within::point_in_geometry(turn.robust_point, piece.robust_ring);
@@ -241,12 +381,6 @@ public:
return;
}
// TODO: mutable_piece to make some on-demand preparations in analyse
analyse_result analyse_code
= analyse_turn_wrt_piece::apply(turn.robust_point, piece);
Turn& mutable_turn = m_turns[turn.turn_index];
switch(analyse_code)
{
case analyse_on_offsetted :
@@ -259,11 +393,7 @@ public:
}
break;
default :
if (geometry_code == 1 || (geometry_code == 0 && ! has_concave))
{
mutable_turn.count_within++;
}
mutable_turn.count_within++;
break;
}
}