Fix rounding errors in SHAPE_ARC::Collide + fix qa tests

Use CIRCLE::NearestPoint to ensure consistency
This commit is contained in:
Roberto Fernandez Bautista 2022-04-11 13:38:57 +01:00
parent 3b796265a0
commit 4defc946ef
2 changed files with 29 additions and 26 deletions

View File

@ -369,28 +369,28 @@ bool SHAPE_ARC::IsClockwise() const
bool SHAPE_ARC::Collide( const VECTOR2I& aP, int aClearance, int* aActual,
VECTOR2I* aLocation ) const
{
int minDist = aClearance + std::max( m_width / 2, 1 );
int minDist = aClearance + m_width / 2;
auto bbox = BBox( minDist );
// Fast check using bounding box:
if( !bbox.Contains( aP ) )
return false;
VECTOR2I center = GetCenter();
VECTOR2I vec = aP - center;
CIRCLE fullCircle( GetCenter(), GetRadius() );
VECTOR2I nearestPt = fullCircle.NearestPoint( aP );
int dist = abs( vec.EuclideanNorm() - GetRadius() );
int dist = ( nearestPt - aP ).EuclideanNorm();
// If not a 360 degree arc, need to use arc angles to decide if point collides
if( m_start != m_end )
{
bool ccw = GetCentralAngle() > ANGLE_0;
EDA_ANGLE vecAngle( vec );
EDA_ANGLE rotatedVecAngle = ( vecAngle.Normalize() - GetStartAngle() ).Normalize();
EDA_ANGLE angleToPt( aP - fullCircle.Center ); // Angle from center to the point
EDA_ANGLE rotatedPtAngle = ( angleToPt.Normalize() - GetStartAngle() ).Normalize();
EDA_ANGLE rotatedEndAngle = ( GetEndAngle() - GetStartAngle() ).Normalize();
if( ( ccw && rotatedVecAngle > rotatedEndAngle )
|| ( !ccw && rotatedVecAngle < rotatedEndAngle ) )
if( ( ccw && rotatedPtAngle > rotatedEndAngle )
|| ( !ccw && rotatedPtAngle < rotatedEndAngle ) )
{
int distStartpt = ( aP - m_start ).EuclideanNorm();
int distEndpt = ( aP - m_end ).EuclideanNorm();

View File

@ -558,7 +558,7 @@ struct ARC_PT_COLLIDE_CASE
static const std::vector<ARC_PT_COLLIDE_CASE> arc_pt_collide_cases = {
{ " 270deg, 0 cl, 0 deg ", { { 0, 0 }, { 100, 0 }, 270.0 }, 0, { 100, 0 }, true, 0 },
{ " 270deg, 0 cl, 0 deg ", { { 0, 0 }, { 100, 0 }, 270.0 }, 0, { 100, 0 }, true, 0 },
{ " 270deg, 0 cl, 90 deg ", { { 0, 0 }, { 100, 0 }, 270.0 }, 0, { 0, 100 }, true, 0 },
{ " 270deg, 0 cl, 180 deg ", { { 0, 0 }, { 100, 0 }, 270.0 }, 0, { -100, 0 }, true, 0 },
{ " 270deg, 0 cl, 270 deg ", { { 0, 0 }, { 100, 0 }, 270.0 }, 0, { 0, -100 }, true, 0 },
@ -579,14 +579,14 @@ static const std::vector<ARC_PT_COLLIDE_CASE> arc_pt_collide_cases = {
{ " 270deg, 5 cl, 90 deg, 5 neg", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 0, 105 }, true, 5 },
{ " 270deg, 5 cl, 180 deg, 5 neg", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { -105, 0 }, true, 5 },
{ " 270deg, 5 cl, 270 deg, 5 neg", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 0, -105 }, true, 5 },
{ " 270deg, 5 cl, 45 deg, 5 pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 75, 74 }, true, 5 },
{ " 270deg, 5 cl, -45 deg, 5 pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 75, -74 }, false, -1 },
{ " 270deg, 5 cl, 45 deg, 5 neg", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 67, 68 }, true, 5 },
{ " 270deg, 5 cl, -45 deg, 5 neg", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 67, -68 }, false, -1 },
{ " 270deg, 4 cl, 0 deg pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 4, { 106, 0 }, false, -1 },
{ " 270deg, 4 cl, 90 deg pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 4, { 0, 106 }, false, -1 },
{ " 270deg, 4 cl, 180 deg pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 4, { -106, 0 }, false, -1 },
{ " 270deg, 4 cl, 270 deg pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 4, { 0, -106 }, false, -1 },
{ " 270deg, 5 cl, 45 deg, 5 pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 74, 75 }, true, 5 }, // 74.246, -74.246
{ " 270deg, 5 cl, -45 deg, 5 pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 74, -75 }, false, -1 }, //74.246, -74.246
{ " 270deg, 5 cl, 45 deg, 5 neg", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 67, 67 }, true, 5 }, // 67.17, 67.17
{ " 270deg, 5 cl, -45 deg, 5 neg", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 67, -67 }, false, -1 }, // 67.17, -67.17
{ " 270deg, 4 cl, 0 deg pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 4, { 105, 0 }, false, -1 },
{ " 270deg, 4 cl, 90 deg pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 4, { 0, 105 }, false, -1 },
{ " 270deg, 4 cl, 180 deg pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 4, { -105, 0 }, false, -1 },
{ " 270deg, 4 cl, 270 deg pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 4, { 0, -105 }, false, -1 },
{ " 90deg, 0 cl, 0 deg ", { { 0, 0 }, { 71, -71 }, 90.0 }, 0, { 71, -71 }, true, 0 },
{ " 90deg, 0 cl, 45 deg ", { { 0, 0 }, { 71, -71 }, 90.0 }, 0, { 100, 0 }, true, 0 },
{ " 90deg, 0 cl, 90 deg ", { { 0, 0 }, { 71, -71 }, 90.0 }, 0, { 71, 71 }, true, 0 },
@ -597,6 +597,12 @@ static const std::vector<ARC_PT_COLLIDE_CASE> arc_pt_collide_cases = {
{ " -90deg, 0 cl, 90 deg ", { { 0, 0 }, { 71, 71 }, -90.0 }, 0, { 71, 71 }, true, 0 },
{ " -90deg, 0 cl, 135 deg ", { { 0, 0 }, { 71, 71 }, -90.0 }, 0, { 0, -100 }, false, -1 },
{ " -90deg, 0 cl, -45 deg ", { { 0, 0 }, { 71, 71 }, -90.0 }, 0, { 0, 100 }, false, -1 },
{ "issue 11358",
{ { 119888000, 60452000 }, { 120904000, 60452000 }, 360.0 },
0,
{ 120395500, 59571830 },
true,
0 },
};
@ -609,16 +615,13 @@ BOOST_AUTO_TEST_CASE( CollidePt )
SHAPE_ARC arc( c.m_geom.m_center_point, c.m_geom.m_start_point,
EDA_ANGLE( c.m_geom.m_center_angle, DEGREES_T ) );
if( c.m_arc_clearance > 0 )
// Test a zero width arc (distance should equal the clearance)
BOOST_TEST_CONTEXT( "Test Clearance" )
{
// Test a zero width arc (distance should equal the clearance)
BOOST_TEST_CONTEXT( "Test Clearance" )
{
int dist = -1;
BOOST_CHECK_EQUAL( arc.Collide( c.m_point, c.m_arc_clearance, &dist ),
c.m_exp_result );
BOOST_CHECK_EQUAL( dist, c.m_exp_distance );
}
int dist = -1;
BOOST_CHECK_EQUAL( arc.Collide( c.m_point, c.m_arc_clearance, &dist ),
c.m_exp_result );
BOOST_CHECK_EQUAL( dist, c.m_exp_distance );
}
// Test by changing the width of the arc (distance should equal zero)