pcbnew, router: fix a crash and some other issues related to microvias and blind/buried vias

- fix crash when trying to create a microvia from a internal layer (boards with > 4 layers)
- fix a bug that allowed to create a non through hole via on only one layer
- fix a bug that allowed to create a microvia on non adjacent layer pair
- when placing a via and selecting the target layer from dialog, show only allowed layers.
Fixes #9477
https://gitlab.com/kicad/code/kicad/issues/9477
This commit is contained in:
jean-pierre charras 2021-10-29 17:54:04 +02:00
parent 1051f11683
commit 63d4d84aaa
1 changed files with 63 additions and 4 deletions

View File

@ -807,14 +807,47 @@ int ROUTER_TOOL::handleLayerSwitch( const TOOL_EVENT& aEvent, bool aForceVia )
wxPoint endPoint = (wxPoint) view()->ToScreen( m_endSnapPoint );
endPoint = frame()->GetCanvas()->ClientToScreen( endPoint );
// Build the list of not allowed layer for the target layer
LSET not_allowed_ly = LSET::AllNonCuMask();
if( viaType != VIATYPE::THROUGH )
{
not_allowed_ly.set( currentLayer );
}
if( viaType == VIATYPE::MICROVIA )
{
// Allows only the previous or the next layer from the current layer
int previous_layer = currentLayer == B_Cu ? layerCount - 2
: currentLayer - 1;
int next_layer = currentLayer >= layerCount-2 ? B_Cu
: currentLayer + 1;
not_allowed_ly = LSET::AllLayersMask();
if( previous_layer >= F_Cu && previous_layer != currentLayer )
not_allowed_ly.reset( previous_layer );
if( next_layer != currentLayer )
not_allowed_ly.reset( next_layer );
}
targetLayer = frame()->SelectOneLayer( static_cast<PCB_LAYER_ID>( currentLayer ),
LSET::AllNonCuMask(), endPoint );
not_allowed_ly, endPoint );
// Reset the cursor to the end of the track
controls()->SetCursorPosition( m_endSnapPoint );
if( targetLayer == UNDEFINED_LAYER ) // cancelled by user
return 0;
// One cannot place a blind/buried via on only one layer:
if( viaType != VIATYPE::THROUGH )
{
if( currentLayer == targetLayer )
return 0;
}
}
}
@ -889,7 +922,19 @@ int ROUTER_TOOL::handleLayerSwitch( const TOOL_EVENT& aEvent, bool aForceVia )
break;
case VIATYPE::MICROVIA:
if( currentLayer == F_Cu || currentLayer == In1_Cu )
// Try to use the layer pair preset, if the layers are adjacent,
// because a microvia is usually restricted to 2 adjacent copper layers
if( pairTop > pairBottom ) std::swap( pairTop, pairBottom );
if( currentLayer == pairTop && pairBottom == pairTop+1 )
{
targetLayer = pairBottom;
}
else if( currentLayer == pairBottom && pairBottom == pairTop+1 )
{
targetLayer = pairTop;
}
else if( currentLayer == F_Cu || currentLayer == In1_Cu )
{
// front-side microvia
currentLayer = F_Cu;
@ -907,8 +952,10 @@ int ROUTER_TOOL::handleLayerSwitch( const TOOL_EVENT& aEvent, bool aForceVia )
}
else
{
wxFAIL_MSG( "Invalid implicit layer pair for microvia (must be on "
"or adjacent to an outer layer)." );
// This is not optimal: from an internal layer one can want to switch
// to the previous or the next internal layer
// but at this point we do not know what the user want.
targetLayer = PCB_LAYER_ID( currentLayer + 1 );
}
break;
@ -926,10 +973,22 @@ int ROUTER_TOOL::handleLayerSwitch( const TOOL_EVENT& aEvent, bool aForceVia )
// so fallback and swap to the top layer of the pair by default
targetLayer = pairTop;
}
// Do not create a broken via (i.e. a via on only one copper layer)
if( currentLayer == targetLayer )
{
WX_INFOBAR* infobar = frame()->GetInfoBar();
infobar->ShowMessageFor( _( "Blind/buried via need 2 different layers." ),
2000, wxICON_ERROR,
WX_INFOBAR::MESSAGE_TYPE::DRC_VIOLATION );
return 0;
}
break;
default:
wxFAIL_MSG( "unexpected via type" );
return 0;
break;
}
}