Rewrite broken collision routine SHAPE_ARC::Collide( SEG& aSeg )

This commit is contained in:
Roberto Fernandez Bautista 2021-11-12 15:40:22 +00:00
parent 9b43689a76
commit d47bd3a04d
3 changed files with 100 additions and 56 deletions

View File

@ -231,66 +231,23 @@ bool SHAPE_ARC::Collide( const SEG& aSeg, int aClearance, int* aActual, VECTOR2I
if( aSeg.A == aSeg.B ) if( aSeg.A == aSeg.B )
return Collide( aSeg.A, aClearance, aActual, aLocation ); return Collide( aSeg.A, aClearance, aActual, aLocation );
int minDist = aClearance + m_width / 2;
VECTOR2I center = GetCenter(); VECTOR2I center = GetCenter();
ecoord dist_sq; CIRCLE circle( center, GetRadius() );
ecoord closest_dist_sq = VECTOR2I::ECOORD_MAX;
VECTOR2I nearest;
VECTOR2I ab = ( aSeg.B - aSeg.A ); // Possible points of the collision are:
VECTOR2I ac = ( center - aSeg.A ); // 1. Intersetion of the segment with the full circle
// 2. Closest point on the segment to the center of the circle
// 3. End points of the segment
ecoord lenAbSq = ab.SquaredEuclideanNorm(); std::vector<VECTOR2I> candidatePts = circle.Intersect( aSeg );
double lambda = (double) ac.Dot( ab ) / (double) lenAbSq;
if( lambda >= 0.0 && lambda <= 1.0 ) candidatePts.push_back( aSeg.NearestPoint( center ) );
candidatePts.push_back( aSeg.A );
candidatePts.push_back( aSeg.B );
for( const VECTOR2I& candidate : candidatePts )
{ {
VECTOR2I p; if( Collide( candidate, aClearance, aActual, aLocation ) )
p.x = (double) aSeg.A.x * lambda + (double) aSeg.B.x * (1.0 - lambda);
p.y = (double) aSeg.A.y * lambda + (double) aSeg.B.y * (1.0 - lambda);
dist_sq = ( m_start - p ).SquaredEuclideanNorm();
if( dist_sq < closest_dist_sq )
{
closest_dist_sq = dist_sq;
nearest = p;
}
dist_sq = ( m_end - p ).SquaredEuclideanNorm();
if( dist_sq < closest_dist_sq )
{
closest_dist_sq = dist_sq;
nearest = p;
}
}
dist_sq = aSeg.SquaredDistance( m_start );
if( dist_sq < closest_dist_sq )
{
closest_dist_sq = dist_sq;
nearest = m_start;
}
dist_sq = aSeg.SquaredDistance( m_end );
if( dist_sq < closest_dist_sq )
{
closest_dist_sq = dist_sq;
nearest = m_end;
}
if( closest_dist_sq == 0 || closest_dist_sq < SEG::Square( minDist ) )
{
if( aLocation )
*aLocation = nearest;
if( aActual )
*aActual = std::max( 0, (int) sqrt( closest_dist_sq ) - m_width / 2 );
return true; return true;
} }

View File

@ -844,6 +844,31 @@ BOOST_AUTO_TEST_CASE( CollideArc )
} }
BOOST_AUTO_TEST_CASE( CollideArcToShapeLineChain )
{
SHAPE_ARC arc( VECTOR2I( 206000000, 140110000 ), VECTOR2I( 201574617, 139229737 ),
VECTOR2I( 197822958, 136722959 ), 250000 );
SHAPE_LINE_CHAIN lc( { VECTOR2I( 159600000, 142500000 ), VECTOR2I( 159600000, 142600000 ),
VECTOR2I( 166400000, 135800000 ), VECTOR2I( 166400000, 111600000 ),
VECTOR2I( 190576804, 111600000 ), VECTOR2I( 192242284, 113265480 ),
VECTOR2I( 192255720, 113265480 ), VECTOR2I( 203682188, 124691948 ),
VECTOR2I( 203682188, 140332188 ), VECTOR2I( 206000000, 142650000 ) },
false );
SHAPE* arc_sh = &arc;
SHAPE* lc_sh = &lc;
BOOST_CHECK_EQUAL( arc_sh->Collide( &lc, 100000 ), true );
BOOST_CHECK_EQUAL( lc_sh->Collide( &arc, 100000 ), true );
SEG seg( VECTOR2I( 203682188, 124691948 ), VECTOR2I( 203682188, 140332188 ) );
BOOST_CHECK_EQUAL( arc.Collide( seg, 0 ), true );
}
BOOST_AUTO_TEST_CASE( CollideArcToPolygonApproximation ) BOOST_AUTO_TEST_CASE( CollideArcToPolygonApproximation )
{ {
SHAPE_ARC arc( VECTOR2I( 73843527, 74355869 ), VECTOR2I( 71713528, 72965869 ), -76.36664803, SHAPE_ARC arc( VECTOR2I( 73843527, 74355869 ), VECTOR2I( 71713528, 72965869 ), -76.36664803,

View File

@ -225,8 +225,70 @@ int playground_main_func( int argc, char* argv[] )
return 0; return 0;
} }
int drawShapes( int argc, char* argv[] )
{
SHAPE_ARC arc( VECTOR2I( 206000000, 140110000 ), VECTOR2I( 201574617, 139229737 ),
VECTOR2I( 197822958, 136722959 ), 250000 );
SHAPE_LINE_CHAIN lc( { /* VECTOR2I( 159600000, 142500000 ), VECTOR2I( 159600000, 142600000 ),
VECTOR2I( 166400000, 135800000 ), VECTOR2I( 166400000, 111600000 ),
VECTOR2I( 190576804, 111600000 ), VECTOR2I( 192242284, 113265480 ),
VECTOR2I( 192255720, 113265480 ),*/
VECTOR2I( 203682188, 124691948 ), VECTOR2I( 203682188, 140332188 ),
/* VECTOR2I( 206000000, 142650000 ) */ },
false );
auto frame = new PNS_LOG_VIEWER_FRAME( nullptr );
Pgm().App().SetTopWindow( frame ); // wxApp gets a face.
frame->Show();
overlay = frame->GetOverlay();
overlay->SetIsFill( false );
overlay->SetLineWidth( arc.GetWidth() );
overlay->SetStrokeColor( RED );
overlay->Arc( arc );
overlay->SetLineWidth( arc.GetWidth() / 20 );
overlay->SetStrokeColor( GREEN );
overlay->Polyline( lc );
overlay->SetLineWidth( 80000.0 );
overlay->SetStrokeColor( CYAN );
for( int i = 0; i < lc.PointCount(); ++i )
{
int mult = ( i % 2 ) ? 1 : -1;
overlay->AnnotatedPoint( lc.GetPoint( i ), arc.GetWidth() * 2 );
overlay->SetGlyphSize( { 800000.0, 800000.0 } );
overlay->BitmapText( wxString::Format( "x=%d, y=%d", lc.GetPoint( i ).x, lc.GetPoint( i ).y ),
lc.GetPoint( i ) + VECTOR2I( 0, mult*arc.GetWidth() * 4 ), 0 );
}
arc.Collide( &lc, 100000 );
BOX2I vp = arc.BBox();
vp.Merge( lc.BBox() );
vp.Inflate( (800000 + arc.GetWidth() * 4 )*2);
frame->GetPanel()->GetView()->SetViewport( BOX2D( vp.GetOrigin(), vp.GetSize() ) );
overlay = nullptr;
return 0;
}
static bool registered = UTILITY_REGISTRY::Register( { static bool registered = UTILITY_REGISTRY::Register( {
"playground", "playground",
"Geometry/drawing playground", "Geometry/drawing playground",
playground_main_func, playground_main_func,
} ); } );
static bool registered1 = UTILITY_REGISTRY::Register( {
"drawShapes",
"drawing shapes",
drawShapes,
} );