mirror of
https://github.com/boostorg/geometry.git
synced 2026-02-12 00:02:09 +00:00
[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:
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user