[buffer] use monotonic sections for checking point-in-original

This can enhance performance with 20%
This commit is contained in:
Barend Gehrels
2014-12-21 19:07:37 +01:00
parent 083b402447
commit c4ca3eef2f
2 changed files with 46 additions and 11 deletions

View File

@@ -203,6 +203,9 @@ struct buffered_piece_collection
struct robust_original
{
typedef robust_ring_type original_robust_ring_type;
typedef geometry::sections<robust_box_type, 1> sections_type;
inline robust_original()
: m_is_interior(false)
, m_has_interiors(true)
@@ -224,9 +227,7 @@ struct buffered_piece_collection
robust_ring_type m_ring;
robust_box_type m_box;
geometry::sections<robust_box_type, 1> m_sections;
typedef robust_ring_type original_robust_ring_type;
sections_type m_sections;
bool m_is_interior;
bool m_has_interiors;

View File

@@ -73,20 +73,54 @@ template <typename Point, typename Original>
inline int point_in_original(Point const& point, Original const& original)
{
typedef strategy::within::winding<Point> strategy_type;
strategy_type strategy;
typedef typename Original::original_robust_ring_type ring_type;
typedef typename Original::sections_type sections_type;
typedef typename boost::range_iterator<ring_type const>::type iterator_type;
typename strategy_type::state_type state;
iterator_type it = boost::begin(original.m_ring);
typedef typename boost::range_iterator<sections_type const>::type siterator_type;
for (iterator_type previous = it++;
it != boost::end(original.m_ring);
++previous, ++it)
typename geometry::coordinate_type<Point>::type const point_y
= geometry::get<1>(point);
typename strategy_type::state_type state;
strategy_type strategy;
// Walk through all monotonic sections
for (siterator_type sit = boost::begin(original.m_sections);
sit != boost::end(original.m_sections);
++sit)
{
if (! strategy.apply(point, *previous, *it, state))
typename boost::range_value<sections_type const>::type const& section = *sit;
if (! section.duplicate
&& section.begin_index < section.end_index
&& point_y >= geometry::get<min_corner, 1>(section.bounding_box)
&& point_y <= geometry::get<max_corner, 1>(section.bounding_box))
{
break;
// Walk through this section
iterator_type it
= boost::begin(original.m_ring) + section.begin_index;
iterator_type const end
= boost::begin(original.m_ring) + section.end_index + 1;
for (iterator_type previous = it++; it != end; ++previous, ++it)
{
if (! strategy.apply(point, *previous, *it, state))
{
break;
}
// Depending on sections.direction we can quit the inner loop
typename geometry::coordinate_type<Point>::type const ring_y
= geometry::get<1>(*it);
if (section.directions[0] == 1 && point_y < ring_y)
{
break;
}
else if (section.directions[0] == -1 && point_y > ring_y)
{
break;
}
}
}
}