libs: added POINT_INSIDE_TRACKER, a state-based class to track if a point is inside/outisde a dynamically built closed polyline

This commit is contained in:
Tomasz Wlostowski 2020-04-15 01:11:01 +02:00
parent c121f8f52c
commit 88d0092e43
2 changed files with 128 additions and 2 deletions

View File

@ -73,6 +73,33 @@ public:
VECTOR2I p;
};
/**
* Class POINT_INSIDE_TRACKER
*
* A dynamic state checking if a point lies within polygon with a dynamically built outline (
* with each piece of the outline added by AddPolyline ()
*/
class POINT_INSIDE_TRACKER
{
public:
POINT_INSIDE_TRACKER( const VECTOR2I& aPoint );
void AddPolyline( const SHAPE_LINE_CHAIN& aPolyline );
bool IsInside();
private:
bool processVertex ( const VECTOR2I& ip, const VECTOR2I& ipNext );
VECTOR2I m_point;
VECTOR2I m_lastPoint;
VECTOR2I m_firstPoint;
bool m_finished;
int m_state;
int m_count;
};
typedef std::vector<INTERSECTION> INTERSECTIONS;

View File

@ -1011,3 +1011,102 @@ double SHAPE_LINE_CHAIN::Area() const
return -area * 0.5;
}
SHAPE_LINE_CHAIN::POINT_INSIDE_TRACKER::POINT_INSIDE_TRACKER( const VECTOR2I& aPoint ) :
m_point( aPoint ),
m_state( 0 ),
m_count( 0 )
{
}
bool SHAPE_LINE_CHAIN::POINT_INSIDE_TRACKER::processVertex(
const VECTOR2I& ip, const VECTOR2I& ipNext )
{
if( ipNext.y == m_point.y )
{
if( ( ipNext.x == m_point.x )
|| ( ip.y == m_point.y && ( ( ipNext.x > m_point.x ) == ( ip.x < m_point.x ) ) ) )
{
m_finished = true;
m_state = -1;
return false;
}
}
if( ( ip.y < m_point.y ) != ( ipNext.y < m_point.y ) )
{
if( ip.x >= m_point.x )
{
if( ipNext.x > m_point.x )
{
m_state = 1 - m_state;
}
else
{
double d = (double) ( ip.x - m_point.x ) * ( ipNext.y - m_point.y )
- (double) ( ipNext.x - m_point.x ) * ( ip.y - m_point.y );
if( !d )
{
m_finished = true;
m_state = -1;
return false;
}
if( ( d > 0 ) == ( ipNext.y > ip.y ) )
m_state = 1 - m_state;
}
}
else
{
if( ipNext.x > m_point.x )
{
double d = (double) ( ip.x - m_point.x ) * ( ipNext.y - m_point.y )
- (double) ( ipNext.x - m_point.x ) * ( ip.y - m_point.y );
if( !d )
{
m_finished = true;
m_state = -1;
return false;
}
if( ( d > 0 ) == ( ipNext.y > ip.y ) )
m_state = 1 - m_state;
}
}
}
return true;
}
void SHAPE_LINE_CHAIN::POINT_INSIDE_TRACKER::AddPolyline( const SHAPE_LINE_CHAIN& aPolyline )
{
if( !m_count )
{
m_lastPoint = aPolyline.CPoint(0);
m_firstPoint = aPolyline.CPoint(0);
}
m_count += aPolyline.PointCount();
for (int i = 1; i < aPolyline.PointCount(); i++ )
{
auto p = aPolyline.CPoint( i );
if( !processVertex( m_lastPoint, p ))
return;
m_lastPoint = p;
}
}
bool SHAPE_LINE_CHAIN::POINT_INSIDE_TRACKER::IsInside()
{
processVertex( m_lastPoint, m_firstPoint );
return m_state > 0;
}