Infrastructure and file format for via stacks

This commit is contained in:
Jon Evans 2024-10-06 16:34:15 -04:00
parent fac5f6aa83
commit 2a605e4a4e
38 changed files with 355 additions and 114 deletions

View File

@ -303,7 +303,7 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
const VIATYPE viatype = via->GetViaType();
const double holediameter = via->GetDrillValue() * BiuTo3dUnits();
const double viasize = via->GetWidth() * BiuTo3dUnits();
const double viasize = via->GetWidth( layer ) * BiuTo3dUnits();
const double plating = GetHolePlatingThickness() * BiuTo3dUnits();
// holes and layer copper extend half info cylinder wall to hide transition
@ -428,7 +428,7 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
{
const int holediameter = via->GetDrillValue();
const int hole_outer_radius = (holediameter / 2) + GetHolePlatingThickness();
const int hole_outer_ring_radius = KiROUND( via->GetWidth() / 2.0 );
const int hole_outer_ring_radius = KiROUND( via->GetWidth( layer ) / 2.0 );
// Add through hole contours
TransformCircleToPolygon( m_TH_ODPolys, via->GetStart(), hole_outer_radius,

View File

@ -80,14 +80,15 @@ size_t hash_fp_item( const EDA_ITEM* aItem, int aFlags )
case PCB_VIA_T:
{
const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem );
ret = hash_val( via->GetWidth() );
hash_combine( ret, via->GetDrillValue() );
ret = hash<int>{}( via->GetDrillValue() );
hash_combine( ret, via->TopLayer() );
hash_combine( ret, via->BottomLayer() );
via->GetLayerSet().RunOnLayers(
[&]( PCB_LAYER_ID layer )
{
hash_combine( ret, via->GetWidth( layer ) );
hash_combine( ret, via->FlashLayer( layer ) );
} );

View File

@ -485,8 +485,9 @@ bool CONNECTIVITY_DATA::IsConnectedOnLayer( const BOARD_CONNECTED_ITEM *aItem, i
if( zone->IsFilled() )
{
const SHAPE_POLY_SET* zoneFill = zone->GetFill( ToLAYER_ID( aLayer ) );
SHAPE_CIRCLE viaHull( via->GetCenter(), via->GetWidth() / 2 );
PCB_LAYER_ID lyr = ToLAYER_ID( aLayer );
const SHAPE_POLY_SET* zoneFill = zone->GetFill( lyr );
SHAPE_CIRCLE viaHull( via->GetCenter(), via->GetWidth( lyr ) / 2 );
for( const VECTOR2I& pt : zoneFill->COutline( islandIdx ).CPoints() )
{

View File

@ -212,7 +212,8 @@ DIALOG_TRACK_VIA_PROPERTIES::DIALOG_TRACK_VIA_PROPERTIES( PCB_BASE_FRAME* aParen
{
m_viaX.SetValue( v->GetPosition().x );
m_viaY.SetValue( v->GetPosition().y );
m_viaDiameter.SetValue( v->GetWidth() );
// TODO(JE) padstacks
m_viaDiameter.SetValue( v->GetWidth( PADSTACK::ALL_LAYERS ) );
m_viaDrill.SetValue( v->GetDrillValue() );
m_vias = true;
viaType = v->GetViaType();
@ -249,7 +250,7 @@ DIALOG_TRACK_VIA_PROPERTIES::DIALOG_TRACK_VIA_PROPERTIES( PCB_BASE_FRAME* aParen
if( m_viaY.GetValue() != v->GetPosition().y )
m_viaY.SetValue( INDETERMINATE_STATE );
if( m_viaDiameter.GetValue() != v->GetWidth() )
if( m_viaDiameter.GetValue() != v->GetWidth( PADSTACK::ALL_LAYERS ) )
m_viaDiameter.SetValue( INDETERMINATE_STATE );
if( m_viaDrill.GetValue() != v->GetDrillValue() )
@ -709,7 +710,7 @@ bool DIALOG_TRACK_VIA_PROPERTIES::TransferDataFromWindow()
v->SanitizeLayers();
if( !m_viaDiameter.IsIndeterminate() )
v->SetWidth( m_viaDiameter.GetIntValue() );
v->SetWidth( PADSTACK::ALL_LAYERS, m_viaDiameter.GetIntValue() );
if( !m_viaDrill.IsIndeterminate() )
v->SetDrill( m_viaDrill.GetIntValue() );

View File

@ -259,7 +259,8 @@ bool DRC_TEST_PROVIDER_ANNULAR_WIDTH::Run()
case PCB_VIA_T:
{
PCB_VIA* via = static_cast<PCB_VIA*>( item );
annularWidth = ( via->GetWidth() - via->GetDrillValue() ) / 2;
// TODO(JE) padstacks
annularWidth = ( via->GetWidth( PADSTACK::ALL_LAYERS ) - via->GetDrillValue() ) / 2;
break;
}

View File

@ -91,7 +91,8 @@ bool DRC_TEST_PROVIDER_VIA_DIAMETER::Run()
bool fail_min = false;
bool fail_max = false;
int constraintDiameter = 0;
int actual = via->GetWidth();
// TODO(JE) padstacks
int actual = via->GetWidth( PADSTACK::ALL_LAYERS );
if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE )
{

View File

@ -204,7 +204,8 @@ static void build_via_testpoints( BOARD *aPcb, std::vector <D356_RECORD>& aRecor
rk.access = via_access_code( aPcb, top_layer, bottom_layer );
rk.x_location = via->GetPosition().x - origin.x;
rk.y_location = origin.y - via->GetPosition().y;
rk.x_size = via->GetWidth();
// TODO(JE) padstacks
rk.x_size = via->GetWidth( PADSTACK::ALL_LAYERS );
rk.y_size = 0; // Round so height = 0
rk.rotation = 0;
rk.soldermask = 3; // XXX always tented?

View File

@ -233,8 +233,8 @@ bool GENCAD_EXPORTER::WriteFile( const wxString& aFullFileName )
// Sort vias for uniqueness
static bool ViaSort( const PCB_VIA* aPadref, const PCB_VIA* aPadcmp )
{
if( aPadref->GetWidth() != aPadcmp->GetWidth() )
return aPadref->GetWidth() < aPadcmp->GetWidth();
if( aPadref->GetWidth( PADSTACK::ALL_LAYERS ) != aPadcmp->GetWidth( PADSTACK::ALL_LAYERS ) )
return aPadref->GetWidth( PADSTACK::ALL_LAYERS ) < aPadcmp->GetWidth( PADSTACK::ALL_LAYERS );
if( aPadref->GetDrillValue() != aPadcmp->GetDrillValue() )
return aPadref->GetDrillValue() < aPadcmp->GetDrillValue();
@ -302,10 +302,10 @@ void GENCAD_EXPORTER::CreatePadsShapesSection()
{
viastacks.push_back( via );
fprintf( m_file, "PAD V%d.%d.%s ROUND %g\nCIRCLE 0 0 %g\n",
via->GetWidth(), via->GetDrillValue(),
via->GetWidth( PADSTACK::ALL_LAYERS ), via->GetDrillValue(),
fmt_mask( via->GetLayerSet() & master_layermask ).c_str(),
via->GetDrillValue() / SCALE_FACTOR,
via->GetWidth() / (SCALE_FACTOR * 2) );
via->GetWidth( PADSTACK::ALL_LAYERS ) / (SCALE_FACTOR * 2) );
}
// Emit component pads
@ -554,14 +554,14 @@ void GENCAD_EXPORTER::CreatePadsShapesSection()
LSET mask = via->GetLayerSet() & master_layermask;
fprintf( m_file, "PADSTACK VIA%d.%d.%s %g\n",
via->GetWidth(), via->GetDrillValue(),
via->GetWidth( PADSTACK::ALL_LAYERS ), via->GetDrillValue(),
fmt_mask( mask ).c_str(),
via->GetDrillValue() / SCALE_FACTOR );
for( PCB_LAYER_ID layer : mask.Seq( gc_seq ) )
{
fprintf( m_file, "PAD V%d.%d.%s %s 0 0\n",
via->GetWidth(), via->GetDrillValue(),
via->GetWidth( PADSTACK::ALL_LAYERS ), via->GetDrillValue(),
fmt_mask( mask ).c_str(),
GenCADLayerName( cu_count, layer ).c_str() );
}
@ -984,7 +984,7 @@ void GENCAD_EXPORTER::CreateRoutesSection()
LSET vset = via->GetLayerSet() & master_layermask;
fprintf( m_file, "VIA VIA%d.%d.%s %g %g ALL %g via%d\n",
via->GetWidth(), via->GetDrillValue(),
via->GetWidth( PADSTACK::ALL_LAYERS ), via->GetDrillValue(),
fmt_mask( vset ).c_str(),
MapXTo( via->GetStart().x ), MapYTo( via->GetStart().y ),
via->GetDrillValue() / SCALE_FACTOR, vianum++ );

View File

@ -233,8 +233,8 @@ HYPERLYNX_PAD_STACK::HYPERLYNX_PAD_STACK( BOARD* aBoard, const PAD* aPad )
HYPERLYNX_PAD_STACK::HYPERLYNX_PAD_STACK( BOARD* aBoard, const PCB_VIA* aVia )
{
m_board = aBoard;
m_sx = aVia->GetWidth();
m_sy = aVia->GetWidth();
// TODO(JE) padstacks
m_sx = m_sy = aVia->GetWidth( PADSTACK::ALL_LAYERS );
m_angle = 0;
m_layers = aVia->GetLayerSet();
m_drill = aVia->GetDrillValue();

View File

@ -1345,11 +1345,11 @@ bool PAD::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
Padstack().ForEachUniqueLayer(
[&]( PCB_LAYER_ID l )
{
if( GetEffectivePolygon( l, ERROR_INSIDE )->Contains( aPosition, -1, aAccuracy ) )
{
contains = true;
if( contains )
return;
}
if( GetEffectivePolygon( l, ERROR_INSIDE )->Contains( aPosition, -1, aAccuracy ) )
contains = true;
} );
return contains;
@ -1380,6 +1380,9 @@ bool PAD::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
Padstack().ForEachUniqueLayer(
[&]( PCB_LAYER_ID aLayer )
{
if( hit )
return;
const std::shared_ptr<SHAPE_POLY_SET>& poly =
GetEffectivePolygon( aLayer, ERROR_INSIDE );

View File

@ -3829,7 +3829,8 @@ void ALTIUM_PCB::ParseVias6Data( const ALTIUM_PCB_COMPOUND_FILE& aAltiumPcbF
std::unique_ptr<PCB_VIA> via = std::make_unique<PCB_VIA>( m_board );
via->SetPosition( elem.position );
via->SetWidth( elem.diameter );
// TODO(JE) padstacks
via->SetWidth( PADSTACK::ALL_LAYERS, elem.diameter );
via->SetDrill( elem.holesize );
via->SetNetCode( GetNetCode( elem.net ) );
via->SetLocked( elem.is_locked );

View File

@ -2603,7 +2603,7 @@ int CADSTAR_PCB_ARCHIVE_LOADER::loadNetVia(
(double) ( (double) getKiCadLength( csViaCode.Shape.Size ) / 1E6 ) );
}
via->SetWidth( getKiCadLength( csViaCode.Shape.Size ) );
via->SetWidth( PADSTACK::ALL_LAYERS, getKiCadLength( csViaCode.Shape.Size ) );
bool start_layer_outside =
csLayerPair.PhysicalLayerStart == 1
@ -2630,7 +2630,7 @@ int CADSTAR_PCB_ARCHIVE_LOADER::loadNetVia(
via->SetNet( getKiCadNet( aCadstarNetID ) );
///todo add netcode to the via
return via->GetWidth();
return via->GetWidth( PADSTACK::ALL_LAYERS );
}

View File

@ -2812,7 +2812,7 @@ void PCB_IO_EAGLE::loadSignals( wxXmlNode* aSignals )
if( v.diam )
{
kidiam = v.diam->ToPcbUnits();
via->SetWidth( kidiam );
via->SetWidth( PADSTACK::ALL_LAYERS, kidiam );
}
else
{
@ -2820,20 +2820,21 @@ void PCB_IO_EAGLE::loadSignals( wxXmlNode* aSignals )
annulus = eagleClamp( m_rules->rlMinViaOuter, annulus,
m_rules->rlMaxViaOuter );
kidiam = KiROUND( drillz + 2 * annulus );
via->SetWidth( kidiam );
via->SetWidth( PADSTACK::ALL_LAYERS, kidiam );
}
via->SetDrill( drillz );
// make sure the via diameter respects the restring rules
if( !v.diam || via->GetWidth() <= via->GetDrill() )
if( !v.diam || via->GetWidth( PADSTACK::ALL_LAYERS ) <= via->GetDrill() )
{
double annulus =
eagleClamp( m_rules->rlMinViaOuter,
(double) ( via->GetWidth() / 2 - via->GetDrill() ),
m_rules->rlMaxViaOuter );
via->SetWidth( drillz + 2 * annulus );
double annulus = eagleClamp(
m_rules->rlMinViaOuter,
static_cast<double>( via->GetWidth( PADSTACK::ALL_LAYERS ) / 2
- via->GetDrill() ),
m_rules->rlMaxViaOuter );
via->SetWidth( PADSTACK::ALL_LAYERS, drillz + 2 * annulus );
}
if( kidiam < m_min_via )

View File

@ -863,7 +863,7 @@ void PCB_IO_EASYEDA_PARSER::ParseToBoardItemContainer(
via->SetPosition( center );
via->SetWidth( kdia );
via->SetWidth( PADSTACK::ALL_LAYERS, kdia );
via->SetNet( getOrAddNetItem( arr[4] ) );
via->SetDrill( kdrill );

View File

@ -1063,7 +1063,7 @@ void PCB_IO_EASYEDAPRO_PARSER::ParseBoard(
via->SetPosition( ScalePos( center ) );
via->SetDrill( ScaleSize( drill ) );
via->SetWidth( ScaleSize( dia ) );
via->SetWidth( PADSTACK::ALL_LAYERS, ScaleSize( dia ) );
via->SetNet( aBoard->FindNet( netname ) );

View File

@ -2526,19 +2526,19 @@ bool FABMASTER::loadVias( BOARD* aBoard )
if( !ds.m_ViasDimensionsList.empty() )
{
new_via->SetWidth( ds.m_ViasDimensionsList[0].m_Diameter );
new_via->SetWidth( PADSTACK::ALL_LAYERS, ds.m_ViasDimensionsList[0].m_Diameter );
new_via->SetDrill( ds.m_ViasDimensionsList[0].m_Drill );
}
else
{
new_via->SetDrillDefault();
new_via->SetWidth( ds.m_ViasMinSize );
new_via->SetWidth( PADSTACK::ALL_LAYERS, ds.m_ViasMinSize );
}
}
else
{
new_via->SetDrill( padstack->second.drill_size_x );
new_via->SetWidth( padstack->second.width );
new_via->SetWidth( PADSTACK::ALL_LAYERS, padstack->second.width );
}
aBoard->Add( new_via, ADD_MODE::APPEND );

View File

@ -1671,7 +1671,7 @@ void PCB_IO_IPC2581::addVia( wxXmlNode* aContentNode, const PCB_VIA* aVia, PCB_L
int hole = aVia->GetDrillValue();
dummy.SetDrillSize( VECTOR2I( hole, hole ) );
dummy.SetPosition( aVia->GetStart() );
dummy.SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( aVia->GetWidth(), aVia->GetWidth() ) );
dummy.SetSize( aLayer, VECTOR2I( aVia->GetWidth( aLayer ), aVia->GetWidth( aLayer ) ) );
addShape( padNode, dummy, aLayer );
}
@ -1777,7 +1777,7 @@ void PCB_IO_IPC2581::addPadStack( wxXmlNode* aContentNode, const PCB_VIA* aVia )
PCB_SHAPE shape( nullptr, SHAPE_T::CIRCLE );
shape.SetEnd( { KiROUND( aVia->GetWidth() / 2.0 ), 0 } );
shape.SetEnd( { KiROUND( aVia->GetWidth( layer ) / 2.0 ), 0 } );
wxXmlNode* padStackPadDefNode = appendNode( padStackDefNode, "PadstackPadDef" );
addAttribute( padStackPadDefNode, "layerRef", m_layer_name_map[layer] );

View File

@ -2231,12 +2231,11 @@ void PCB_IO_KICAD_LEGACY::loadTrackList( int aStructType )
newTrack->SetPosition( VECTOR2I( start_x, start_y ) );
newTrack->SetEnd( VECTOR2I( end_x, end_y ) );
newTrack->SetWidth( width );
if( makeType == PCB_VIA_T ) // Ensure layers are OK when possible:
{
PCB_VIA *via = static_cast<PCB_VIA*>( newTrack );
via->SetViaType( viatype );
via->SetWidth( PADSTACK::ALL_LAYERS, width );
if( drill < 0 )
via->SetDrillDefault();
@ -2266,6 +2265,8 @@ void PCB_IO_KICAD_LEGACY::loadTrackList( int aStructType )
}
else
{
newTrack->SetWidth( width );
// A few legacy boards can have tracks on non existent layers, because
// reducing the number of layers does not remove tracks on removed layers
// If happens, skip them

View File

@ -2489,7 +2489,42 @@ void PCB_IO_KICAD_SEXPR::format( const PCB_TRACK* aTrack, int aNestLevel ) const
m_out->Print( 0, ")" );
}
formatTenting( via->Padstack() );
const PADSTACK& padstack = via->Padstack();
formatTenting( padstack );
if( padstack.Mode() != PADSTACK::MODE::NORMAL )
{
std::string mode =
padstack.Mode() == PADSTACK::MODE::CUSTOM ? "custom" : "front_inner_back";
m_out->Print( 0, "(padstack (mode %s)", mode.c_str() );
if( padstack.Mode() == PADSTACK::MODE::FRONT_INNER_BACK )
{
m_out->Print( 0, "(layer \"Inner\"" );
m_out->Print( 0, " (size %s)",
formatInternalUnits( padstack.Size( PADSTACK::INNER_LAYERS ).x ).c_str() );
m_out->Print( 0, ")(layer \"B.Cu\"" );
m_out->Print( 0, " (size %s)",
formatInternalUnits( padstack.Size( B_Cu ).x ).c_str() );
m_out->Print( 0, ")" );
}
else
{
for( PCB_LAYER_ID layer : LAYER_RANGE( F_Cu, B_Cu, board->GetCopperLayerCount() ) )
{
if( layer == F_Cu )
continue;
m_out->Print( 0, "(layer %s", m_out->Quotew( LSET::Name( layer ) ).c_str() );
m_out->Print( 0, " (size %s)",
formatInternalUnits( padstack.Size( layer ).x ).c_str() );
m_out->Print( 0, ")" );
}
}
m_out->Print( 0, ")" );
}
if( !isDefaultTeardropParameters( via->GetTeardropParams() ) )
{

View File

@ -164,7 +164,8 @@ class PCB_IO_KICAD_SEXPR; // forward decl
//#define SEXPR_BOARD_FILE_VERSION 20240706 // Embedded Files
//#define SEXPR_BOARD_FILE_VERSION 20240819 // Embedded Files - Update hash algorithm to Murmur3
//#define SEXPR_BOARD_FILE_VERSION 20240928 // Component classes
#define SEXPR_BOARD_FILE_VERSION 20240929 // Complex padstacks
//#define SEXPR_BOARD_FILE_VERSION 20240929 // Complex padstacks
#define SEXPR_BOARD_FILE_VERSION 20241006 // Via stacks
#define BOARD_FILE_HOST_VERSION 20200825 ///< Earlier files than this include the host tag
#define LEGACY_ARC_FORMATTING 20210925 ///< These were the last to use old arc formatting

View File

@ -6262,7 +6262,7 @@ PCB_VIA* PCB_IO_KICAD_SEXPR_PARSER::parsePCB_VIA()
break;
case T_size:
via->SetWidth( parseBoardUnits( "via width" ) );
via->SetWidth( PADSTACK::ALL_LAYERS, parseBoardUnits( "via width" ) );
NeedRIGHT();
break;
@ -6333,6 +6333,10 @@ PCB_VIA* PCB_IO_KICAD_SEXPR_PARSER::parsePCB_VIA()
}
break;
case T_padstack:
parseViastack( via.get() );
break;
case T_teardrops:
parseTEARDROP_PARAMETERS( &via->GetTeardropParams() );
break;
@ -6393,6 +6397,103 @@ void PCB_IO_KICAD_SEXPR_PARSER::parseTenting( PADSTACK& aPadstack )
}
void PCB_IO_KICAD_SEXPR_PARSER::parseViastack( PCB_VIA* aVia )
{
PADSTACK& padstack = aVia->Padstack();
for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_mode:
token = NextTok();
switch( token )
{
case T_front_inner_back:
padstack.SetMode( PADSTACK::MODE::FRONT_INNER_BACK );
break;
case T_custom:
padstack.SetMode( PADSTACK::MODE::CUSTOM );
break;
default:
Expecting( "front_inner_back or custom" );
}
NeedRIGHT();
break;
case T_layer:
{
NextTok();
PCB_LAYER_ID curLayer = UNDEFINED_LAYER;
if( curText == "Inner" )
{
if( padstack.Mode() != PADSTACK::MODE::FRONT_INNER_BACK )
{
THROW_IO_ERROR( wxString::Format( _( "Invalid padstack layer in\nfile: %s\n"
"line: %d\noffset: %d." ),
CurSource(), CurLineNumber(), CurOffset() ) );
}
curLayer = PADSTACK::INNER_LAYERS;
}
else
{
curLayer = lookUpLayer( m_layerIndices );
}
if( !IsCopperLayer( curLayer ) )
{
wxString error;
error.Printf( _( "Invalid padstack layer '%s' in file '%s' at line %d, offset %d." ),
curText, CurSource().GetData(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_size:
{
int diameter = parseBoardUnits( "via width" );
padstack.SetSize( { diameter, diameter }, curLayer );
NeedRIGHT();
break;
}
default:
// Currently only supporting custom via diameter per layer, not other properties
Expecting( "size" );
}
}
break;
}
default:
Expecting( "mode or layer" );
break;
}
}
}
ZONE* PCB_IO_KICAD_SEXPR_PARSER::parseZONE( BOARD_ITEM_CONTAINER* aParent )
{
wxCHECK_MSG( CurTok() == T_zone, nullptr,

View File

@ -237,6 +237,7 @@ private:
PCB_ARC* parseARC();
PCB_TRACK* parsePCB_TRACK();
PCB_VIA* parsePCB_VIA();
void parseViastack( PCB_VIA* aVia );
ZONE* parseZONE( BOARD_ITEM_CONTAINER* aParent );
PCB_TARGET* parsePCB_TARGET();
BOARD* parseBOARD();

View File

@ -406,7 +406,7 @@ void FEATURES_MANAGER::InitFeatureList( PCB_LAYER_ID aLayer, std::vector<BOARD_I
AddFeatureAttribute(
*m_featuresList.back(),
ODB_ATTR::GEOMETRY{ "VIA_RoundD"
+ std::to_string( via->GetWidth() ) } );
+ std::to_string( via->GetWidth( aLayer ) ) } );
}
}
else
@ -428,7 +428,7 @@ void FEATURES_MANAGER::InitFeatureList( PCB_LAYER_ID aLayer, std::vector<BOARD_I
AddFeatureAttribute(
*m_featuresList.back(),
ODB_ATTR::GEOMETRY{ "VIA_RoundD"
+ std::to_string( via->GetWidth() ) } );
+ std::to_string( via->GetWidth( aLayer ) ) } );
}
}
}

View File

@ -359,7 +359,7 @@ void PCAD_PAD::AddToBoard( FOOTPRINT* aFootprint )
via->SetPosition( VECTOR2I( m_PositionX, m_PositionY ) );
via->SetEnd( VECTOR2I( m_PositionX, m_PositionY ) );
via->SetWidth( height );
via->SetWidth( PADSTACK::ALL_LAYERS, height );
via->SetViaType( VIATYPE::THROUGH );
via->SetLayerPair( F_Cu, B_Cu );
via->SetDrill( m_Hole );

View File

@ -936,6 +936,7 @@ void PCB_PAINTER::draw( const PCB_VIA* aVia, int aLayer )
if( color == COLOR4D::CLEAR )
return;
PCB_LAYER_ID currentLayer = ToLAYER_ID( aLayer );
PCB_LAYER_ID layerTop, layerBottom;
aVia->LayerPair( &layerTop, &layerBottom );
@ -958,7 +959,7 @@ void PCB_PAINTER::draw( const PCB_VIA* aVia, int aLayer )
return;
double maxSize = PCB_RENDER_SETTINGS::MAX_FONT_SIZE;
double size = aVia->GetWidth();
double size = aVia->GetWidth( currentLayer );
// Font size limits
if( size > maxSize )
@ -1106,12 +1107,12 @@ void PCB_PAINTER::draw( const PCB_VIA* aVia, int aLayer )
m_gal->SetIsStroke( false );
m_gal->SetLineWidth( margin );
m_gal->DrawCircle( center, aVia->GetWidth() / 2.0 + margin );
m_gal->DrawCircle( center, aVia->GetWidth( currentLayer ) / 2.0 + margin );
}
else if( m_pcbSettings.IsPrinting() || IsCopperLayer( aLayer ) )
{
int annular_width = ( aVia->GetWidth() - getViaDrillSize( aVia ) ) / 2.0;
double radius = aVia->GetWidth() / 2.0;
int annular_width = ( aVia->GetWidth( currentLayer ) - getViaDrillSize( aVia ) ) / 2.0;
double radius = aVia->GetWidth( currentLayer ) / 2.0;
bool draw = false;
if( m_pcbSettings.IsPrinting() )
@ -1143,7 +1144,8 @@ void PCB_PAINTER::draw( const PCB_VIA* aVia, int aLayer )
{
m_gal->SetLineWidth( m_lockedShadowMargin );
m_gal->DrawCircle( center, ( aVia->GetWidth() + m_lockedShadowMargin ) / 2.0 );
m_gal->DrawCircle( center,
( aVia->GetWidth( currentLayer ) + m_lockedShadowMargin ) / 2.0 );
}
// Clearance lines
@ -1165,7 +1167,7 @@ void PCB_PAINTER::draw( const PCB_VIA* aVia, int aLayer )
double radius;
if( aVia->FlashLayer( activeLayer ) )
radius = aVia->GetWidth() / 2.0;
radius = aVia->GetWidth( activeLayer ) / 2.0;
else
radius = getViaDrillSize( aVia ) / 2.0 + m_holePlatingThickness;

View File

@ -308,17 +308,34 @@ double PCB_VIA::Similarity( const BOARD_ITEM& aOther ) const
return similarity;
}
#if 0
void PCB_VIA::SetWidth( int aWidth )
{
// This is present because of the parent class. It should never be actually called on a via.
wxASSERT_MSG( false, "Warning: PCB_VIA::SetWidth called without a layer argument" );
m_padStack.SetSize( { aWidth, aWidth }, PADSTACK::ALL_LAYERS );
}
int PCB_VIA::GetWidth() const
{
// This is present because of the parent class. It should never be actually called on a via.
wxASSERT_MSG( false, "Warning: PCB_VIA::GetWidth called without a layer argument" );
return m_padStack.Size( PADSTACK::ALL_LAYERS ).x;
}
#endif
void PCB_VIA::SetWidth( PCB_LAYER_ID aLayer, int aWidth )
{
m_padStack.SetSize( { aWidth, aWidth }, aLayer );
}
int PCB_VIA::GetWidth( PCB_LAYER_ID aLayer ) const
{
return m_padStack.Size( aLayer ).x;
}
void PCB_TRACK::Serialize( google::protobuf::Any &aContainer ) const
@ -447,7 +464,7 @@ bool PCB_VIA::Deserialize( const google::protobuf::Any &aContainer )
return false;
// We don't yet support complex padstacks for vias
SetWidth( m_padStack.Size( PADSTACK::ALL_LAYERS ).x );
SetWidth( PADSTACK::ALL_LAYERS, m_padStack.Size( PADSTACK::ALL_LAYERS ).x );
SetViaType( FromProtoEnum<VIATYPE>( via.type() ) );
SetNetCode( via.net().code().value() );
SetLocked( via.locked() == kiapi::common::types::LockedState::LS_LOCKED );
@ -1307,7 +1324,7 @@ double PCB_VIA::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
if( const BOARD* board = GetBoard() )
visible = board->GetVisibleLayers() & board->GetEnabledLayers();
int width = GetWidth();
int width = GetWidth( ToLAYER_ID( aLayer ) );
// In high contrast mode don't show vias that don't cross the high-contrast layer
if( renderSettings->GetHighContrast() )
@ -1465,7 +1482,9 @@ void PCB_VIA::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITE
GetMsgPanelInfoBase_Common( aFrame, aList );
aList.emplace_back( _( "Layer" ), layerMaskDescribe() );
aList.emplace_back( _( "Diameter" ), aFrame->MessageTextFromValue( GetWidth() ) );
// TODO(JE) padstacks
aList.emplace_back( _( "Diameter" ),
aFrame->MessageTextFromValue( GetWidth( PADSTACK::ALL_LAYERS ) ) );
aList.emplace_back( _( "Hole" ), aFrame->MessageTextFromValue( GetDrillValue() ) );
wxString source;
@ -1565,12 +1584,25 @@ bool PCB_ARC::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
bool PCB_VIA::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
{
int max_dist = aAccuracy + ( GetWidth() / 2 );
bool hit = false;
// rel_pos is aPosition relative to m_Start (or the center of the via)
VECTOR2I rel_pos = aPosition - m_Start;
double dist = (double) rel_pos.x * rel_pos.x + (double) rel_pos.y * rel_pos.y;
return dist <= (double) max_dist * max_dist;
Padstack().ForEachUniqueLayer(
[&]( PCB_LAYER_ID aLayer )
{
if( hit )
return;
int max_dist = aAccuracy + ( GetWidth( aLayer ) / 2 );
// rel_pos is aPosition relative to m_Start (or the center of the via)
VECTOR2D rel_pos = aPosition - m_Start;
double dist = rel_pos.x * rel_pos.x + rel_pos.y * rel_pos.y;
if( dist <= static_cast<double>( max_dist ) * max_dist )
hit = true;
} );
return hit;
}
@ -1609,13 +1641,24 @@ bool PCB_VIA::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) cons
BOX2I arect = aRect;
arect.Inflate( aAccuracy );
BOX2I box( GetStart() );
box.Inflate( GetWidth() / 2 );
bool hit = false;
if( aContained )
return arect.Contains( box );
else
return arect.IntersectsCircle( GetStart(), GetWidth() / 2 );
Padstack().ForEachUniqueLayer(
[&]( PCB_LAYER_ID aLayer )
{
if( hit )
return;
BOX2I box( GetStart() );
box.Inflate( GetWidth( aLayer ) / 2 );
if( aContained )
hit = arect.Contains( box );
else
hit = arect.IntersectsCircle( GetStart(), GetWidth( aLayer ) / 2 );
} );
return hit;
}
@ -1739,7 +1782,8 @@ std::shared_ptr<SHAPE> PCB_VIA::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING
if( aFlash == FLASHING::ALWAYS_FLASHED
|| ( aFlash == FLASHING::DEFAULT && FlashLayer( aLayer ) ) )
{
return std::make_shared<SHAPE_CIRCLE>( m_Start, GetWidth() / 2 );
PCB_LAYER_ID cuLayer = m_padStack.EffectiveLayerFor( aLayer );
return std::make_shared<SHAPE_CIRCLE>( m_Start, GetWidth( cuLayer ) / 2 );
}
else
{
@ -1765,7 +1809,7 @@ void PCB_TRACK::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID a
{
case PCB_VIA_T:
{
int radius = ( static_cast<const PCB_VIA*>( this )->GetWidth() / 2 ) + aClearance;
int radius = ( static_cast<const PCB_VIA*>( this )->GetWidth( aLayer ) / 2 ) + aClearance;
TransformCircleToPolygon( aBuffer, m_Start, radius, aError, aErrorLoc );
break;
}
@ -1854,7 +1898,7 @@ static struct TRACK_VIA_DESC
propMgr.Mask( TYPE_HASH( PCB_VIA ), TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Layer" ) );
propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Diameter" ),
&PCB_VIA::SetWidth, &PCB_VIA::GetWidth, PROPERTY_DISPLAY::PT_SIZE ), groupVia );
&PCB_VIA::SetFrontWidth, &PCB_VIA::GetFrontWidth, PROPERTY_DISPLAY::PT_SIZE ), groupVia );
propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Hole" ),
&PCB_VIA::SetDrill, &PCB_VIA::GetDrillValue, PROPERTY_DISPLAY::PT_SIZE ), groupVia );
propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PCB_LAYER_ID>( _HKI( "Layer Top" ),

View File

@ -385,9 +385,16 @@ public:
const PADSTACK& Padstack() const { return m_padStack; }
PADSTACK& Padstack() { return m_padStack; }
void SetPadstack( const PADSTACK& aPadstack ) { m_padStack = aPadstack; }
#if 0
void SetWidth( int aWidth ) override;
int GetWidth() const override;
#endif
void SetWidth( PCB_LAYER_ID aLayer, int aWidth );
int GetWidth( PCB_LAYER_ID aLayer ) const;
// For properties panel
void SetFrontWidth( int aWidth ) { SetWidth( F_Cu, aWidth ); }
int GetFrontWidth() const { return GetWidth( F_Cu ); }
bool HasHole() const override
{

View File

@ -635,7 +635,8 @@ void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
if( ( aLayerMask & LSET::AllCuMask() ).any() )
width_adj = itemplotter.getFineWidthAdj();
int diameter = via->GetWidth() + 2 * via_margin + width_adj;
// TODO(JE) padstacks
int diameter = via->GetWidth( PADSTACK::ALL_LAYERS ) + 2 * via_margin + width_adj;
/// Vias not connected to copper are optionally not drawn
if( onCopperLayer && !via->FlashLayer( aLayerMask ) )

View File

@ -1201,7 +1201,8 @@ void BRDITEMS_PLOTTER::PlotDrillMarks()
continue;
plotOneDrillMark( PAD_DRILL_SHAPE::CIRCLE, via->GetStart(),
VECTOR2I( via->GetDrillValue(), 0 ), VECTOR2I( via->GetWidth(), 0 ),
VECTOR2I( via->GetDrillValue(), 0 ),
VECTOR2I( via->GetWidth( PADSTACK::ALL_LAYERS ), 0 ),
ANGLE_0, smallDrill );
}
}

View File

@ -1158,7 +1158,6 @@ std::vector<std::unique_ptr<PNS::SOLID>> PNS_KICAD_IFACE_BASE::syncPad( PAD* aPa
return solids;
}
// TODO(JE) padstacks - need to make multiple solids for custom padstack situations
auto makeSolidFromPadLayer =
[&]( PCB_LAYER_ID aLayer )
{
@ -1280,33 +1279,40 @@ std::unique_ptr<PNS::ARC> PNS_KICAD_IFACE_BASE::syncArc( PCB_ARC* aArc )
}
std::unique_ptr<PNS::VIA> PNS_KICAD_IFACE_BASE::syncVia( PCB_VIA* aVia )
std::vector<std::unique_ptr<PNS::VIA>> PNS_KICAD_IFACE_BASE::syncVia( PCB_VIA* aVia )
{
std::vector<std::unique_ptr<PNS::VIA>> vias;
PCB_LAYER_ID top, bottom;
aVia->LayerPair( &top, &bottom );
auto via = std::make_unique<PNS::VIA>( aVia->GetPosition(),
aVia->Padstack().ForEachUniqueLayer(
[&]( PCB_LAYER_ID aLayer )
{
auto via = std::make_unique<PNS::VIA>( aVia->GetPosition(),
SetLayersFromPCBNew( aVia->TopLayer(), aVia->BottomLayer() ),
aVia->GetWidth(),
aVia->GetWidth( aLayer ),
aVia->GetDrillValue(),
aVia->GetNet(),
aVia->GetViaType() );
via->SetParent( aVia );
via->SetParent( aVia );
if( aVia->IsLocked() )
via->Mark( PNS::MK_LOCKED );
if( aVia->IsLocked() )
via->Mark( PNS::MK_LOCKED );
if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aVia->GetParentGroup() ) )
{
if( !generator->HasFlag( IN_EDIT ) )
via->Mark( PNS::MK_LOCKED );
}
if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aVia->GetParentGroup() ) )
{
if( !generator->HasFlag( IN_EDIT ) )
via->Mark( PNS::MK_LOCKED );
}
via->SetIsFree( aVia->GetIsFree() );
via->SetHole( PNS::HOLE::MakeCircularHole( aVia->GetPosition(), aVia->GetDrillValue() / 2 ) );
via->SetIsFree( aVia->GetIsFree() );
via->SetHole( PNS::HOLE::MakeCircularHole( aVia->GetPosition(),
aVia->GetDrillValue() / 2 ) );
vias.emplace_back( std::move( via ) );
} );
return via;
return vias;
}
@ -1694,7 +1700,9 @@ void PNS_KICAD_IFACE_BASE::SyncWorld( PNS::NODE *aWorld )
}
else if( type == PCB_VIA_T )
{
if( std::unique_ptr<PNS::VIA> via = syncVia( static_cast<PCB_VIA*>( t ) ) )
std::vector<std::unique_ptr<PNS::VIA>> vias = syncVia( static_cast<PCB_VIA*>( t ) );
for( std::unique_ptr<PNS::VIA>& via : vias )
aWorld->Add( std::move( via ) );
}
}
@ -1946,7 +1954,7 @@ void PNS_KICAD_IFACE::modifyBoardItem( PNS::ITEM* aItem )
m_commit->Modify( via_board );
via_board->SetPosition( VECTOR2I( via->Pos().x, via->Pos().y ) );
via_board->SetWidth( via->Diameter() );
via_board->SetWidth( PADSTACK::ALL_LAYERS, via->Diameter() );
via_board->SetDrill( via->Drill() );
via_board->SetNet( static_cast<NETINFO_ITEM*>( via->Net() ) );
via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()
@ -2026,7 +2034,7 @@ BOARD_CONNECTED_ITEM* PNS_KICAD_IFACE::createBoardItem( PNS::ITEM* aItem )
PCB_VIA* via_board = new PCB_VIA( m_board );
PNS::VIA* via = static_cast<PNS::VIA*>( aItem );
via_board->SetPosition( VECTOR2I( via->Pos().x, via->Pos().y ) );
via_board->SetWidth( via->Diameter() );
via_board->SetWidth( PADSTACK::ALL_LAYERS, via->Diameter() );
via_board->SetDrill( via->Drill() );
via_board->SetNet( net );
via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()

View File

@ -107,7 +107,7 @@ protected:
std::vector<std::unique_ptr<PNS::SOLID>> syncPad( PAD* aPad );
std::unique_ptr<PNS::SEGMENT> syncTrack( PCB_TRACK* aTrack );
std::unique_ptr<PNS::ARC> syncArc( PCB_ARC* aArc );
std::unique_ptr<PNS::VIA> syncVia( PCB_VIA* aVia );
std::vector<std::unique_ptr<PNS::VIA>> syncVia( PCB_VIA* aVia );
bool syncTextItem( PNS::NODE* aWorld, PCB_TEXT* aText, PCB_LAYER_ID aLayer );
bool syncGraphicalItem( PNS::NODE* aWorld, PCB_SHAPE* aItem );
bool syncZone( PNS::NODE* aWorld, ZONE* aZone, SHAPE_POLY_SET* aBoardOutline );

View File

@ -1028,7 +1028,9 @@ PADSTACK* SPECCTRA_DB::makeVia( const PCB_VIA* aVia )
if( topLayer > botLayer )
std::swap( topLayer, botLayer );
return makeVia( aVia->GetWidth(), aVia->GetDrillValue(), topLayer, botLayer );
// TODO(JE) padstacks
return makeVia( aVia->GetWidth( ::PADSTACK::ALL_LAYERS ), aVia->GetDrillValue(),
topLayer, botLayer );
}

View File

@ -228,7 +228,7 @@ PCB_VIA* SPECCTRA_DB::makeVIA( WIRE_VIA*aVia, PADSTACK* aPadstack, const POINT&
via->SetPosition( mapPt( aPoint, m_routeResolution ) );
via->SetDrill( drill_diam_iu );
via->SetViaType( VIATYPE::THROUGH );
via->SetWidth( viaDiam );
via->SetWidth( ::PADSTACK::ALL_LAYERS, viaDiam );
via->SetLayerPair( F_Cu, B_Cu );
}
else if( shapeCount == copperLayerCount )
@ -249,7 +249,7 @@ PCB_VIA* SPECCTRA_DB::makeVIA( WIRE_VIA*aVia, PADSTACK* aPadstack, const POINT&
via->SetPosition( mapPt( aPoint, m_routeResolution ) );
via->SetDrill( drill_diam_iu );
via->SetViaType( VIATYPE::THROUGH );
via->SetWidth( viaDiam );
via->SetWidth( ::PADSTACK::ALL_LAYERS, viaDiam );
via->SetLayerPair( F_Cu, B_Cu );
}
else // VIA_MICROVIA or VIA_BLIND_BURIED
@ -304,7 +304,7 @@ PCB_VIA* SPECCTRA_DB::makeVIA( WIRE_VIA*aVia, PADSTACK* aPadstack, const POINT&
via->SetViaType( VIATYPE::BLIND_BURIED );
}
via->SetWidth( viaDiam );
via->SetWidth( ::PADSTACK::ALL_LAYERS, viaDiam );
via->SetLayerPair( m_pcbLayer2kicad[ topLayerNdx ], m_pcbLayer2kicad[ botLayerNdx ] );
}

View File

@ -241,7 +241,7 @@ void TEARDROP_MANAGER::UpdateTeardrops( BOARD_COMMIT& aCommit,
continue;
TEARDROP_PARAMETERS tdParams = via->GetTeardropParams();
int annularWidth = via->GetWidth();
int annularWidth = via->GetWidth( track->GetLayer() );
if( !tdParams.m_Enabled )
continue;

View File

@ -66,8 +66,9 @@ int TEARDROP_MANAGER::GetWidth( BOARD_ITEM* aItem )
{
if( aItem->Type() == PCB_VIA_T )
{
// TODO(JE) padstacks
PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
return via->GetWidth();
return via->GetWidth( PADSTACK::ALL_LAYERS );
}
else if( aItem->Type() == PCB_PAD_T )
{

View File

@ -912,10 +912,11 @@ int BOARD_EDITOR_CONTROL::ViaSizeInc( const TOOL_EVENT& aEvent )
if( i> 0 )
dims = bds.m_ViasDimensionsList[ i ];
if( dims.m_Diameter > via->GetWidth() )
// TODO(JE) padstacks
if( dims.m_Diameter > via->GetWidth( PADSTACK::ALL_LAYERS ) )
{
commit.Modify( via );
via->SetWidth( dims.m_Diameter );
via->SetWidth( PADSTACK::ALL_LAYERS, dims.m_Diameter );
via->SetDrill( dims.m_Drill );
break;
}
@ -967,10 +968,11 @@ int BOARD_EDITOR_CONTROL::ViaSizeDec( const TOOL_EVENT& aEvent )
if( i > 0 )
dims = bds.m_ViasDimensionsList[ i ];
if( dims.m_Diameter < via->GetWidth() )
// TODO(JE) padstacks
if( dims.m_Diameter < via->GetWidth( PADSTACK::ALL_LAYERS ) )
{
commit.Modify( via );
via->SetWidth( dims.m_Diameter );
via->SetWidth( PADSTACK::ALL_LAYERS, dims.m_Diameter );
via->SetDrill( dims.m_Drill );
break;
}

View File

@ -3467,7 +3467,8 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
PCB_TRACK* track = static_cast<PCB_TRACK*>( item );
if( TestSegmentHit( position, track->GetStart(), track->GetEnd(),
( track->GetWidth() + aVia->GetWidth() ) / 2 ) )
( track->GetWidth()
+ aVia->GetWidth( track->GetLayer() ) ) / 2 ) )
{
possible_tracks.push_back( track );
}
@ -3476,7 +3477,7 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
{
PCB_ARC* arc = static_cast<PCB_ARC*>( item );
if( arc->HitTest( position, aVia->GetWidth() / 2 ) )
if( arc->HitTest( position, aVia->GetWidth( arc->GetLayer() ) / 2 ) )
possible_tracks.push_back( arc );
}
}
@ -3501,6 +3502,8 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
bool hasDRCViolation( PCB_VIA* aVia, BOARD_ITEM* aOther )
{
PCB_LAYER_ID activeLayer = m_frame->GetActiveLayer();
DRC_CONSTRAINT constraint;
int clearance;
BOARD_CONNECTED_ITEM* connectedItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( aOther );
@ -3509,7 +3512,24 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
if( zone && zone->GetIsRuleArea() )
{
if( zone->GetDoNotAllowVias() )
return zone->Outline()->Collide( aVia->GetPosition(), aVia->GetWidth() / 2 );
{
bool hit = false;
aVia->Padstack().ForEachUniqueLayer(
[&]( PCB_LAYER_ID aLayer )
{
if( hit )
return;
if( zone->Outline()->Collide( aVia->GetPosition(),
aVia->GetWidth( aLayer ) / 2 ) )
{
hit = true;
}
} );
return hit;
}
return false;
}
@ -3638,6 +3658,7 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> items;
KIGFX::PCB_VIEW* view = m_frame->GetCanvas()->GetView();
PCB_LAYER_ID activeLayer = m_frame->GetActiveLayer();
std::vector<PCB_SHAPE*> possible_shapes;
view->Query( bbox, items );
@ -3653,7 +3674,7 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
{
PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
if( shape->HitTest( position, aVia->GetWidth() / 2 ) )
if( shape->HitTest( position, aVia->GetWidth( activeLayer ) / 2 ) )
possible_shapes.push_back( shape );
}
}
@ -4020,12 +4041,13 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
if( via->GetViaType() == VIATYPE::MICROVIA )
{
via->SetWidth( via->GetEffectiveNetClass()->GetuViaDiameter() );
via->SetWidth( PADSTACK::ALL_LAYERS,
via->GetEffectiveNetClass()->GetuViaDiameter() );
via->SetDrill( via->GetEffectiveNetClass()->GetuViaDrill() );
}
else
{
via->SetWidth( bds.GetCurrentViaSize() );
via->SetWidth( PADSTACK::ALL_LAYERS, bds.GetCurrentViaSize() );
via->SetDrill( bds.GetCurrentViaDrill() );
}

View File

@ -960,7 +960,8 @@ int EDIT_TOOL::ChangeTrackWidth( const TOOL_EVENT& aEvent )
}
via->SetDrill( new_drill );
via->SetWidth( new_width );
// TODO(JE) padstacks - is this correct behavior already? If so, also change stack mode
via->SetWidth( PADSTACK::ALL_LAYERS, new_width );
}
else if( item->Type() == PCB_TRACE_T || item->Type() == PCB_ARC_T )
{