PNS: Fix propagateDpHeadForces obstacle calculation

Using a synthetic via here doesn't quite let us use VIA::PushoutForce
because it will use the wrong clearance, and also doesn't quite have
the logic we want.  I am not familiar enough with PushoutForce to know
if its logic is a bug in other cases, so instead I just brought in the
parts of its algorithm that are needed here.

Additionally, we prevent pushing more than once from a given obstacle,
which causes walkaround to be more successful when routing diff pairs
against a large collider such as a keepout area.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/8232
This commit is contained in:
Jon Evans 2021-04-17 22:37:30 -04:00
parent 5974446523
commit 6425ad4118
1 changed files with 36 additions and 3 deletions

View File

@ -128,8 +128,6 @@ bool DIFF_PAIR_PLACER::propagateDpHeadForces ( const VECTOR2I& aP, VECTOR2I& aNe
virtHead.SetDiameter( m_sizes.DiffPairGap() + 2 * m_sizes.DiffPairWidth() );
}
VECTOR2I lead( 0, 0 );// = aP - m_currentStart ;
VECTOR2I force;
bool solidsOnly = true;
if( m_currentMode == RM_MarkObstacles )
@ -143,7 +141,42 @@ bool DIFF_PAIR_PLACER::propagateDpHeadForces ( const VECTOR2I& aP, VECTOR2I& aNe
}
// fixme: I'm too lazy to do it well. Circular approximaton will do for the moment.
if( virtHead.PushoutForce( m_currentNode, lead, force, solidsOnly, 40 ) )
// Note: this code is lifted from VIA::PushoutForce and then optimized for this use case and to
// check proper clearances to the diff pair line. It can be removed if some specialized
// pushout for traces / diff pairs is implemented. Just calling VIA::PushoutForce does not work
// as the via may have different resolved clearance to items than the diff pair should.
int maxIter = 40;
int iter = 0;
bool collided = false;
VECTOR2I force, totalForce;
std::set<ITEM*> handled;
while( iter < maxIter )
{
NODE::OPT_OBSTACLE obs = m_currentNode->CheckColliding( &virtHead, solidsOnly ?
ITEM::SOLID_T :
ITEM::ANY_T );
if( !obs || handled.count( obs->m_item ) )
break;
int clearance = m_currentNode->GetClearance( obs->m_item, &m_currentTrace.PLine() );
if( obs->m_item->Shape()->Collide( virtHead.Shape(), clearance, &force ) )
{
collided = true;
totalForce += force;
virtHead.SetPos( virtHead.Pos() + force );
}
handled.insert( obs->m_item );
iter++;
}
bool succeeded = ( !collided || iter != maxIter );
if( succeeded )
{
aNewP = aP + force;
return true;