From 88d0092e436f0e469d9752cb1648a6584dbadfc6 Mon Sep 17 00:00:00 2001 From: Tomasz Wlostowski Date: Wed, 15 Apr 2020 01:11:01 +0200 Subject: [PATCH] libs: added POINT_INSIDE_TRACKER, a state-based class to track if a point is inside/outisde a dynamically built closed polyline --- .../include/geometry/shape_line_chain.h | 31 +++++- libs/kimath/src/geometry/shape_line_chain.cpp | 99 +++++++++++++++++++ 2 files changed, 128 insertions(+), 2 deletions(-) diff --git a/libs/kimath/include/geometry/shape_line_chain.h b/libs/kimath/include/geometry/shape_line_chain.h index 89e5c92a90..648c83fa4c 100644 --- a/libs/kimath/include/geometry/shape_line_chain.h +++ b/libs/kimath/include/geometry/shape_line_chain.h @@ -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 INTERSECTIONS; @@ -583,9 +610,9 @@ public: * generated. * @return true if the point is inside the shape (edge is not treated as being inside). */ - bool PointInside( const VECTOR2I& aPt, int aAccuracy = 0, bool aUseBBoxCache = false ) const; - + bool PointInside( const VECTOR2I& aPt, int aAccuracy = 0, bool aUseBBoxCache = false ) const; + /** * Function PointOnEdge() * diff --git a/libs/kimath/src/geometry/shape_line_chain.cpp b/libs/kimath/src/geometry/shape_line_chain.cpp index a74aefbf25..c59bac2e88 100644 --- a/libs/kimath/src/geometry/shape_line_chain.cpp +++ b/libs/kimath/src/geometry/shape_line_chain.cpp @@ -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; +} +