Rewrite broken collision routine SHAPE_ARC::Collide( SEG& aSeg )
This commit is contained in:
parent
9b43689a76
commit
d47bd3a04d
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
} );
|
||||||
|
|
Loading…
Reference in New Issue