Fix SHAPE_ARC::Collide and add Unit Tests
This commit is contained in:
parent
1d879e36cc
commit
e4b99b9bb5
|
@ -316,22 +316,39 @@ bool SHAPE_ARC::Collide( const VECTOR2I& aP, int aClearance, int* aActual,
|
||||||
int minDist = aClearance + m_width / 2;
|
int minDist = aClearance + m_width / 2;
|
||||||
auto bbox = BBox( minDist );
|
auto bbox = BBox( minDist );
|
||||||
|
|
||||||
|
// Fast check using bounding box:
|
||||||
if( !bbox.Contains( aP ) )
|
if( !bbox.Contains( aP ) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ecoord min_dist_sq = SEG::Square( minDist );
|
VECTOR2I center = GetCenter();
|
||||||
ecoord r_sq = SEG::Square( GetRadius() );
|
VECTOR2I vec = aP - center;
|
||||||
|
|
||||||
ecoord dist_sq = ( aP - GetCenter() ).SquaredEuclideanNorm();
|
int dist = abs( vec.EuclideanNorm() - GetRadius() );
|
||||||
ecoord dist_to_edge_sq = abs( dist_sq - r_sq );
|
|
||||||
|
|
||||||
if( dist_to_edge_sq == 0 || dist_to_edge_sq < min_dist_sq )
|
// If not a 360 degree arc, need to use arc angles to decide if point collides
|
||||||
|
if( m_start != m_end )
|
||||||
|
{
|
||||||
|
bool ccw = GetCentralAngle() > 0.0;
|
||||||
|
double rotatedVecAngle = NormalizeAngleDegreesPos( NormalizeAngleDegreesPos( RAD2DEG( vec.Angle() ) )
|
||||||
|
- GetStartAngle() );
|
||||||
|
double rotatedEndAngle = NormalizeAngleDegreesPos( GetEndAngle() - GetStartAngle() );
|
||||||
|
|
||||||
|
if( ( ccw && rotatedVecAngle > rotatedEndAngle )
|
||||||
|
|| ( !ccw && rotatedVecAngle < rotatedEndAngle ) )
|
||||||
|
{
|
||||||
|
int distStartpt = ( aP - m_start ).EuclideanNorm();
|
||||||
|
int distEndpt = ( aP - m_end ).EuclideanNorm();
|
||||||
|
dist = std::min( distStartpt, distEndpt );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( dist <= minDist )
|
||||||
{
|
{
|
||||||
if( aLocation )
|
if( aLocation )
|
||||||
*aLocation = ( aP + GetCenter() ) / 2;
|
*aLocation = ( aP + GetCenter() ) / 2;
|
||||||
|
|
||||||
if( aActual )
|
if( aActual )
|
||||||
*aActual = std::max( 0, (int) sqrt( dist_to_edge_sq ) - m_width / 2 );
|
*aActual = std::max( 0, dist - m_width / 2 );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -441,7 +441,7 @@ BOOST_AUTO_TEST_CASE( BasicTTRGeom )
|
||||||
{
|
{
|
||||||
//Swap input segments.
|
//Swap input segments.
|
||||||
seg1 = c.m_geom.m_segment_2;
|
seg1 = c.m_geom.m_segment_2;
|
||||||
seg2 = c.m_geom.m_segment_1;
|
seg2 = c.m_geom.m_segment_1;
|
||||||
|
|
||||||
//The result should swap start and end points and invert the angles:
|
//The result should swap start and end points and invert the angles:
|
||||||
props.m_end_point = c.m_properties.m_start_point;
|
props.m_end_point = c.m_properties.m_start_point;
|
||||||
|
@ -450,7 +450,7 @@ BOOST_AUTO_TEST_CASE( BasicTTRGeom )
|
||||||
props.m_end_angle = c.m_properties.m_start_angle;
|
props.m_end_angle = c.m_properties.m_start_angle;
|
||||||
props.m_center_angle = -c.m_properties.m_center_angle;
|
props.m_center_angle = -c.m_properties.m_center_angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Test all combinations of start and end points for the segments
|
//Test all combinations of start and end points for the segments
|
||||||
if( ( testCase % 4 ) == 1 || ( testCase % 4 ) == 3 )
|
if( ( testCase % 4 ) == 1 || ( testCase % 4 ) == 3 )
|
||||||
{
|
{
|
||||||
|
@ -459,7 +459,7 @@ BOOST_AUTO_TEST_CASE( BasicTTRGeom )
|
||||||
seg1.A = seg1.B;
|
seg1.A = seg1.B;
|
||||||
seg1.B = temp;
|
seg1.B = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ( testCase % 4 ) == 2 || ( testCase % 4 ) == 3 )
|
if( ( testCase % 4 ) == 2 || ( testCase % 4 ) == 3 )
|
||||||
{
|
{
|
||||||
//Swap start and end points for seg2
|
//Swap start and end points for seg2
|
||||||
|
@ -479,6 +479,94 @@ BOOST_AUTO_TEST_CASE( BasicTTRGeom )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct ARC_PT_COLLIDE_CASE
|
||||||
|
{
|
||||||
|
std::string m_ctx_name;
|
||||||
|
ARC_CENTRE_PT_ANGLE m_geom;
|
||||||
|
int m_arc_clearance;
|
||||||
|
VECTOR2I m_point;
|
||||||
|
bool m_exp_result;
|
||||||
|
int m_exp_distance;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
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, 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 },
|
||||||
|
{ " 270deg, 0 cl, 45 deg ", { { 0, 0 }, { 100, 0 }, 270.0 }, 0, { 71, 71 }, true, 0 },
|
||||||
|
{ " 270deg, 0 cl, -45 deg ", { { 0, 0 }, { 100, 0 }, 270.0 }, 0, { 71, -71 }, false, -1 },
|
||||||
|
{ "-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 },
|
||||||
|
{ "-270deg, 0 cl, 45 deg ", { { 0, 0 }, { 100, 0 }, -270.0 }, 0, { 71, 71 }, false, -1 },
|
||||||
|
{ "-270deg, 0 cl, -45 deg ", { { 0, 0 }, { 100, 0 }, -270.0 }, 0, { 71, -71 }, true, 0 },
|
||||||
|
{ " 270deg, 5 cl, 0 deg, 5 pos X", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 105, 0 }, true, 5 },
|
||||||
|
{ " 270deg, 5 cl, 0 deg, 5 pos Y", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 100, -5 }, true, 5 },
|
||||||
|
{ " 270deg, 5 cl, 90 deg, 5 pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 0, 105 }, true, 5 },
|
||||||
|
{ " 270deg, 5 cl, 180 deg, 5 pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { -105, 0 }, true, 5 },
|
||||||
|
{ " 270deg, 5 cl, 270 deg, 5 pos", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 0, -105 }, true, 5 },
|
||||||
|
{ " 270deg, 5 cl, 0 deg, 5 neg", { { 0, 0 }, { 100, 0 }, 270.0 }, 5, { 105, 0 }, true, 5 },
|
||||||
|
{ " 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, { 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 },
|
||||||
|
{ " 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 },
|
||||||
|
{ " -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 },
|
||||||
|
{ " -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 },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE( CollidePt )
|
||||||
|
{
|
||||||
|
for( const auto& c : arc_pt_collide_cases )
|
||||||
|
{
|
||||||
|
BOOST_TEST_CONTEXT( c.m_ctx_name )
|
||||||
|
{
|
||||||
|
SHAPE_ARC arc( c.m_geom.m_center_point, c.m_geom.m_start_point,
|
||||||
|
c.m_geom.m_center_angle );
|
||||||
|
|
||||||
|
// 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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test by changing the width of the arc (distance should equal zero)
|
||||||
|
BOOST_TEST_CONTEXT( "Test Width" )
|
||||||
|
{
|
||||||
|
int dist = -1;
|
||||||
|
arc.SetWidth( c.m_arc_clearance * 2 );
|
||||||
|
BOOST_CHECK_EQUAL( arc.Collide( c.m_point, 0, &dist ), c.m_exp_result );
|
||||||
|
|
||||||
|
if( c.m_exp_result )
|
||||||
|
BOOST_CHECK_EQUAL( dist, 0 );
|
||||||
|
else
|
||||||
|
BOOST_CHECK_EQUAL( dist, -1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct ARC_TO_POLYLINE_CASE
|
struct ARC_TO_POLYLINE_CASE
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue