diff --git a/pcbnew/pcb_track.cpp b/pcbnew/pcb_track.cpp index 50a9cb64a0..c50b06c2cd 100644 --- a/pcbnew/pcb_track.cpp +++ b/pcbnew/pcb_track.cpp @@ -888,6 +888,28 @@ bool PCB_VIA::IsOnLayer( PCB_LAYER_ID aLayer ) const } +bool PCB_VIA::HasValidLayerPair( int aCopperLayerCount ) +{ + // return true if top and bottom layers are valid, depending on the copper layer count + // aCopperLayerCount is expected >= 2 + + int layer_id = aCopperLayerCount*2; + + if( Padstack().Drill().start > B_Cu ) + { + if( Padstack().Drill().start > layer_id ) + return false; + } + if( Padstack().Drill().end > B_Cu ) + { + if( Padstack().Drill().end > layer_id ) + return false; + } + + return true; +} + + PCB_LAYER_ID PCB_VIA::GetLayer() const { return Padstack().Drill().start; @@ -915,9 +937,15 @@ LSET PCB_VIA::GetLayerSet() const { LAYER_RANGE range( Padstack().Drill().start, Padstack().Drill().end, BoardCopperLayerCount() ); + int cnt = BoardCopperLayerCount(); // PCB_LAYER_IDs are numbered from front to back, this is top to bottom. for( PCB_LAYER_ID id : range ) + { layermask.set( id ); + + if( --cnt <= 0 ) + break; + } } if( !IsTented( F_Mask ) && layermask.test( F_Cu ) ) @@ -935,52 +963,40 @@ void PCB_VIA::SetLayerSet( const LSET& aLayerSet ) // Vias do not use a LSET, just a top and bottom layer pair // So we need to set these 2 layers according to the allowed layers in aLayerSet - if( GetViaType() == VIATYPE::THROUGH ) // Only F_Cu and B_Cu are allowed + // For via through, only F_Cu and B_Cu are allowed. aLayerSet is ignored + if( GetViaType() == VIATYPE::THROUGH ) { Padstack().Drill().start = F_Cu; Padstack().Drill().end = B_Cu; return; } - // top and bottom layer are always copper layers: - LSET copperInnerLayerSet = aLayerSet & LSET::InternalCuMask(); + // For blind buried vias, find the top and bottom layers + bool top_found = false; + bool bottom_found = false; - // F_Cu and B_Cu layers are always allowed for vias. - // blind vias can have the start and/or end layers on other layers, so we need to - // recalculate the first and the last allowed layers if they are internal copper layers - - // Fix start layer (first allowed layer) - if( Padstack().Drill().start != F_Cu ) - { - bool found = false; - - copperInnerLayerSet.RunOnLayers( - [&]( PCB_LAYER_ID layer ) + aLayerSet.RunOnLayers( + [&]( PCB_LAYER_ID layer ) + { + // tpo layer and bottom Layer are copper layers, so consider only copper layers + if( IsCopperLayer( layer ) ) { - // Start is the first allowed inner layer >= initial start layer - if( !found && Padstack().Drill().start <= layer ) + // The top layer is the first layer found in list and + // cannot the B_Cu + if( !top_found && layer != B_Cu ) { Padstack().Drill().start = layer; - found = true; + top_found = true; } - } ); - } - // Fix end layer (last allowed layer) - if( Padstack().Drill().end != B_Cu ) - { - int end_ly = Padstack().Drill().end; - - copperInnerLayerSet.RunOnLayers( - [&]( PCB_LAYER_ID layer ) - { - // end is the last allowed inner layer <= initial end layer - if( end_ly >= layer ) - { + // The bottom layer is the last layer found in list or B_Cu + if( !bottom_found ) Padstack().Drill().end = layer; - } - } ); - } + + if( layer == B_Cu ) + bottom_found = true; + } + } ); } diff --git a/pcbnew/pcb_track.h b/pcbnew/pcb_track.h index 9624d22755..a223cdf4bf 100644 --- a/pcbnew/pcb_track.h +++ b/pcbnew/pcb_track.h @@ -374,6 +374,11 @@ public: return false; } + /** + * @return true if top and bottom layers are valid, depending on the copper layer count + */ + bool HasValidLayerPair( int aCopperLayerCount ); + VIATYPE GetViaType() const { return m_viaType; } void SetViaType( VIATYPE aViaType ) { m_viaType = aViaType; } diff --git a/pcbnew/tools/pcb_control.cpp b/pcbnew/tools/pcb_control.cpp index 61eb5bb801..a9cc58c50d 100644 --- a/pcbnew/tools/pcb_control.cpp +++ b/pcbnew/tools/pcb_control.cpp @@ -926,8 +926,16 @@ void PCB_CONTROL::pruneItemLayers( std::vector& aItems ) else { LSET allowed = item->GetLayerSet() & enabledLayers; + bool item_valid = true; - if( allowed.any() ) + // Ensure, for vias, the top and bottom layers are compatible with + // the current board copper layers. + // Otherwise they must be skipped, even is one layer is valid + if( item->Type() == PCB_VIA_T ) + item_valid = static_cast( item )->HasValidLayerPair( + board()->GetCopperLayerCount() ); + + if( allowed.any() && item_valid ) { item->SetLayerSet( allowed ); returnItems.push_back( item );