pcbnew: Optimize pad connection revision
This modifies that logic for optimizing pad connections.
1) Custom pads now prefer the connections to their longer side. This is
particularly important to match the behavior in a rectangular pad
2) Costs for straight lines are non-zero. This favors fewer connections
3) Custom pad breakouts are at the polygon boundary rather than offset
by 0.1mm. This also matches the circular and rectangular paradigm.
4) Line Heads contained in the pad itself are not optimized. This
prevents escaping the pad unnecessarily
Fixes: lp:1824182
* https://bugs.launchpad.net/kicad/+bug/1824182
(cherry picked from commit 06cb21cc47
)
This commit is contained in:
parent
6796e8fff6
commit
fb565caf7b
|
@ -45,10 +45,10 @@ int COST_ESTIMATOR::CornerCost( const SEG& aA, const SEG& aB )
|
|||
switch( dir_a.Angle( dir_b ) )
|
||||
{
|
||||
case DIRECTION_45::ANG_OBTUSE:
|
||||
return 1;
|
||||
return 10;
|
||||
|
||||
case DIRECTION_45::ANG_STRAIGHT:
|
||||
return 0;
|
||||
return 5;
|
||||
|
||||
case DIRECTION_45::ANG_ACUTE:
|
||||
return 50;
|
||||
|
@ -674,7 +674,7 @@ OPTIMIZER::BREAKOUT_LIST OPTIMIZER::customBreakouts( int aWidth,
|
|||
BOX2I bbox = convex->BBox( 0 );
|
||||
VECTOR2I p0 = static_cast<const SOLID*>( aItem )->Pos();
|
||||
// must be large enough to guarantee intersecting the convex polygon
|
||||
int length = bbox.GetSize().EuclideanNorm() / 2 + 5;
|
||||
int length = std::max( bbox.GetWidth(), bbox.GetHeight() ) / 2 + 5;
|
||||
|
||||
for( int angle = 0; angle < 360; angle += ( aPermitDiagonal ? 45 : 90 ) )
|
||||
{
|
||||
|
@ -694,10 +694,10 @@ OPTIMIZER::BREAKOUT_LIST OPTIMIZER::customBreakouts( int aWidth,
|
|||
//l.Append( intersections[0].p + (v0 - p0).Resize( (intersections[0].p - p0).EuclideanNorm() * 0.4 ) );
|
||||
|
||||
// for an absolute breakout distance, e.g. 0.1 mm
|
||||
l.Append( intersections[0].p + (v0 - p0).Resize( 100000 ) );
|
||||
//l.Append( intersections[0].p + (v0 - p0).Resize( 100000 ) );
|
||||
|
||||
// for the breakout right on the polygon edge
|
||||
//l.Append( intersections[0].p );
|
||||
l.Append( intersections[0].p );
|
||||
|
||||
breakouts.push_back( l );
|
||||
}
|
||||
|
@ -828,8 +828,6 @@ ITEM* OPTIMIZER::findPadOrVia( int aLayer, int aNet, const VECTOR2I& aP ) const
|
|||
|
||||
int OPTIMIZER::smartPadsSingle( LINE* aLine, ITEM* aPad, bool aEnd, int aEndVertex )
|
||||
{
|
||||
int min_cost = INT_MAX; // COST_ESTIMATOR::CornerCost( line );
|
||||
int min_len = INT_MAX;
|
||||
DIRECTION_45 dir;
|
||||
|
||||
const int ForbiddenAngles = DIRECTION_45::ANG_ACUTE | DIRECTION_45::ANG_RIGHT |
|
||||
|
@ -845,39 +843,40 @@ int OPTIMIZER::smartPadsSingle( LINE* aLine, ITEM* aPad, bool aEnd, int aEndVert
|
|||
return -1;
|
||||
|
||||
|
||||
BREAKOUT_LIST breakouts = computeBreakouts( aLine->Width(), aPad, true );
|
||||
|
||||
BREAKOUT_LIST breakouts = computeBreakouts( aLine->Width(), aPad, true );
|
||||
SHAPE_LINE_CHAIN line = ( aEnd ? aLine->CLine().Reverse() : aLine->CLine() );
|
||||
int p_end = std::min( aEndVertex, std::min( 3, line.PointCount() - 1 ) );
|
||||
|
||||
|
||||
int p_end = std::min( aEndVertex, std::min( 3, line.PointCount() - 1 ) );
|
||||
|
||||
// Start at 1 to find a potentially better breakout (0 is the pad connection)
|
||||
for( int p = 1; p <= p_end; p++ )
|
||||
{
|
||||
for( SHAPE_LINE_CHAIN & l : breakouts ) {
|
||||
// If the line is contained inside the pad, don't optimize
|
||||
if( solid->Shape() && !solid->Shape()->Collide(
|
||||
SEG( line.CPoint( 0 ), line.CPoint( p ) ), aLine->Width() / 2 ) )
|
||||
continue;
|
||||
|
||||
for( SHAPE_LINE_CHAIN & breakout : breakouts ) {
|
||||
|
||||
for( int diag = 0; diag < 2; diag++ )
|
||||
{
|
||||
SHAPE_LINE_CHAIN v;
|
||||
SHAPE_LINE_CHAIN connect = dir.BuildInitialTrace( l.CPoint( -1 ),
|
||||
line.CPoint( p ), diag == 0 );
|
||||
SHAPE_LINE_CHAIN connect = dir.BuildInitialTrace(
|
||||
breakout.CPoint( -1 ), line.CPoint( p ), diag == 0 );
|
||||
|
||||
DIRECTION_45 dir_bkout( l.CSegment( -1 ) );
|
||||
DIRECTION_45 dir_bkout( breakout.CSegment( -1 ) );
|
||||
|
||||
if(!connect.SegmentCount())
|
||||
continue;
|
||||
|
||||
int ang1 = dir_bkout.Angle( DIRECTION_45( connect.CSegment( 0 ) ) );
|
||||
int ang2 = 0;
|
||||
|
||||
if( (ang1 | ang2) & ForbiddenAngles )
|
||||
if( ang1 & ForbiddenAngles )
|
||||
continue;
|
||||
|
||||
if( l.Length() > line.Length() )
|
||||
if( breakout.Length() > line.Length() )
|
||||
continue;
|
||||
|
||||
v = l;
|
||||
|
||||
v = breakout;
|
||||
v.Append( connect );
|
||||
|
||||
for( int i = p + 1; i < line.PointCount(); i++ )
|
||||
|
@ -898,6 +897,12 @@ int OPTIMIZER::smartPadsSingle( LINE* aLine, ITEM* aPad, bool aEnd, int aEndVert
|
|||
}
|
||||
}
|
||||
|
||||
// We attempt to minimize the corner cost (minimizes the segments and types of corners)
|
||||
// but given two, equally valid costs, we want to pick the longer pad exit. The logic
|
||||
// here is that if the pad is oblong, the track should not exit the shorter side and parallel
|
||||
// the pad but should follow the pad's preferential direction before exiting.
|
||||
int min_cost = INT_MAX;
|
||||
int max_length = 0;
|
||||
SHAPE_LINE_CHAIN l_best;
|
||||
bool found = false;
|
||||
int p_best = -1;
|
||||
|
@ -910,14 +915,14 @@ int OPTIMIZER::smartPadsSingle( LINE* aLine, ITEM* aPad, bool aEnd, int aEndVert
|
|||
|
||||
if( !checkColliding( &tmp ) )
|
||||
{
|
||||
if( cost < min_cost || ( cost == min_cost && len < min_len ) )
|
||||
if( cost < min_cost || ( cost == min_cost && len > max_length ) )
|
||||
{
|
||||
l_best = vp.second;
|
||||
p_best = vp.first;
|
||||
found = true;
|
||||
|
||||
if( cost == min_cost )
|
||||
min_len = std::min( len, min_len );
|
||||
if( cost <= min_cost )
|
||||
max_length = std::max<int>( len, max_length );
|
||||
|
||||
min_cost = std::min( cost, min_cost );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue