Add CIRCLE::Contains( VECTOR2I aP ) and add unit tests

This commit is contained in:
Roberto Fernandez Bautista 2021-03-01 20:38:55 +00:00 committed by Jon Evans
parent a28d9f17e8
commit 14c3d9055e
3 changed files with 125 additions and 0 deletions

View File

@ -54,6 +54,15 @@ public:
*/
CIRCLE& ConstructFromTanTanPt( const SEG& aLineA, const SEG& aLineB, const VECTOR2I& aP );
/**
* Return true if aP is on the circumference of this circle. Note that there is an accepted
* margin of error of SHAPE::MIN_PRECISION_IU to account for integer rounding errors.
*
* @param aP A point to test
* @return true if aP is on the circumference.
*/
bool Contains( const VECTOR2I& aP ) const;
/**
* Compute the point on the circumference of the circle that is the closest to aP.
*

View File

@ -185,6 +185,15 @@ CIRCLE& CIRCLE::ConstructFromTanTanPt( const SEG& aLineA, const SEG& aLineB, con
}
bool CIRCLE::Contains( const VECTOR2I& aP ) const
{
int distance = ( aP - Center ).EuclideanNorm();
return distance <= ( (int64_t) Radius + SHAPE::MIN_PRECISION_IU )
&& distance >= ( (int64_t) Radius - SHAPE::MIN_PRECISION_IU );
}
VECTOR2I CIRCLE::NearestPoint( const VECTOR2I& aP ) const
{
VECTOR2I vec = aP - Center;

View File

@ -23,6 +23,7 @@
#include <geometry/seg.h> // for SEG
#include <geometry/shape.h> // for MIN_PRECISION_IU
const int MIN_PRECISION_45DEG = KiROUND( (double) SHAPE::MIN_PRECISION_IU * 0.7071 );
bool CompareLength( int aLengthA, int aLengthB )
{
@ -72,6 +73,112 @@ BOOST_AUTO_TEST_CASE( ParameterCtorMod )
}
/**
* Struct to hold test cases for a given circle, a point and an expected return boolean
*/
struct CIR_PT_BOOL_CASE
{
std::string m_case_name;
CIRCLE m_circle;
VECTOR2I m_point;
bool m_exp_result;
};
// clang-format off
/**
* Test cases for #CIRCLE::Contains
*/
static const std::vector<CIR_PT_BOOL_CASE> contains_cases = {
{
"on center",
{ { 100, 100 }, 200 },
{ 100, 100 },
false,
},
{
"0 deg",
{ { 100, 100 }, 200 },
{ 300, 100 },
true,
},
{
"0 deg, allowed tolerance pos",
{ { 100, 100 }, 200 },
{ 100, 300 + SHAPE::MIN_PRECISION_IU },
true,
},
{
"0 deg, allowed tolerance neg",
{ { 100, 100 }, 200 },
{ 100, 300 - SHAPE::MIN_PRECISION_IU },
true,
},
{
"0 deg, allowed tolerance pos + 1",
{ { 100, 100 }, 200 },
{ 100, 300 + SHAPE::MIN_PRECISION_IU + 1 },
false,
},
{
"0 deg, allowed tolerance neg - 1",
{ { 100, 100 }, 200 },
{ 100, 300 - SHAPE::MIN_PRECISION_IU - 1 },
false,
},
{
"45 deg",
{ { 100, 100 }, 200 },
{ 241, 241 },
true,
},
{
"45 deg, allowed tolerance pos",
{ { 100, 100 }, 200 },
{ 241 + MIN_PRECISION_45DEG, 241 + MIN_PRECISION_45DEG },
true,
},
{
"45 deg, allowed tolerance pos + 1",
{ { 100, 100 }, 200 },
{ 241 + MIN_PRECISION_45DEG + 1, 241 + MIN_PRECISION_45DEG + 1 },
false,
},
{
"90 deg",
{ { 100, 100 }, 200 },
{ 100, 300 },
true,
},
{
"180 deg",
{ { 100, 100 }, 200 },
{ -100, 100 },
true,
},
{
"270 deg",
{ { 100, 100 }, 200 },
{ 100, -100 },
true,
},
};
// clang-format on
BOOST_AUTO_TEST_CASE( Contains )
{
for( const auto& c : contains_cases )
{
BOOST_TEST_CONTEXT( c.m_case_name )
{
bool ret = c.m_circle.Contains( c.m_point );
BOOST_CHECK_EQUAL( ret, c.m_exp_result );
}
}
}
/**
* Struct to hold test cases for a given circle, a point and an expected return point
*/