7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-21 00:21:25 +00:00

ADDED: Soldermask layer option for tracks

Allows adding a soldermask opening for individual tracks.
Soldermask expansion can also be specified.

Fixes: https://gitlab.com/kicad/code/kicad/-/issues/2125
This commit is contained in:
Andrzej Wolski 2024-09-29 13:25:21 +02:00 committed by Jon Evans
parent f4e5ae0514
commit 537d3ac81a
18 changed files with 927 additions and 231 deletions

View File

@ -368,10 +368,8 @@ private:
void destroyLayers();
// Helper functions to create the board
void createViaWithMargin( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDstContainer,
int aMargin );
void createTrack( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDstContainer );
void createTrackWithMargin( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDstContainer,
int aMargin = 0 );
void createPadWithMargin( const PAD *aPad, CONTAINER_2D_BASE* aDstContainer,
PCB_LAYER_ID aLayer, const VECTOR2I& aMargin ) const;

View File

@ -273,26 +273,17 @@ void BOARD_ADAPTER::addFootprintShapes( const FOOTPRINT* aFootprint, CONTAINER_2
}
void BOARD_ADAPTER::createViaWithMargin( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDstContainer,
int aMargin )
{
SFVEC2F start3DU = TO_SFVEC2F( aTrack->GetStart() );
SFVEC2F end3DU = TO_SFVEC2F( aTrack->GetEnd() );
const float radius3DU = TO_3DU( ( aTrack->GetWidth() / 2.0 ) + aMargin );
addFILLED_CIRCLE_2D( aDstContainer, start3DU, radius3DU, *aTrack );
}
void BOARD_ADAPTER::createTrack( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDstContainer )
void BOARD_ADAPTER::createTrackWithMargin( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDstContainer,
int aMargin )
{
SFVEC2F start3DU = TO_SFVEC2F( aTrack->GetStart() );
SFVEC2F end3DU = TO_SFVEC2F( aTrack->GetEnd() );
float width3DU = TO_3DU( aTrack->GetWidth() + aMargin * 2 );
switch( aTrack->Type() )
{
case PCB_VIA_T:
addFILLED_CIRCLE_2D( aDstContainer, start3DU, TO_3DU( aTrack->GetWidth() / 2.0 ), *aTrack );
addFILLED_CIRCLE_2D( aDstContainer, start3DU, width3DU / 2.0, *aTrack );
break;
case PCB_ARC_T:
@ -308,7 +299,7 @@ void BOARD_ADAPTER::createTrack( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDs
track.SetWidth( arc->GetWidth() );
track.SetLayer( arc->GetLayer() );
createTrack( &track, aDstContainer );
createTrackWithMargin( &track, aDstContainer, aMargin );
return;
}
@ -334,14 +325,15 @@ void BOARD_ADAPTER::createTrack( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDs
circlesegcount = alg::clamp( 1, circlesegcount, 128 );
}
createArcSegments( center, arc->GetStart(), arc_angle, circlesegcount, arc->GetWidth(),
createArcSegments( center, arc->GetStart(), arc_angle, circlesegcount,
arc->GetWidth() + aMargin * 2,
aDstContainer, *arc );
break;
}
case PCB_TRACE_T: // Track is a usual straight segment
{
addROUND_SEGMENT_2D( aDstContainer, start3DU, end3DU, TO_3DU( aTrack->GetWidth() ), *aTrack );
addROUND_SEGMENT_2D( aDstContainer, start3DU, end3DU, width3DU, *aTrack );
break;
}

View File

@ -280,7 +280,7 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
}
// Add object item to layer container
createTrack( track, layerContainer );
createTrackWithMargin( track, layerContainer );
}
}
@ -872,22 +872,23 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
}
}
// Add via tech layers
if( ( layer == F_Mask || layer == B_Mask ) )
// Add track, via and arc tech layers
if( IsSolderMaskLayer( layer ) )
{
int maskExpansion = GetBoard()->GetDesignSettings().m_SolderMaskExpansion;
// Only vias on a external copper layer can have a solder mask
for( PCB_TRACK* track : m_board->Tracks() )
{
if( !track->IsOnLayer( layer ) )
continue;
// Only vias on a external copper layer can have a solder mask
PCB_LAYER_ID copper_layer = layer == F_Mask ? F_Cu : B_Cu;
if( track->Type() == PCB_VIA_T
&& static_cast<const PCB_VIA*>( track )->FlashLayer( copper_layer )
&& !static_cast<const PCB_VIA*>( track )->IsTented( layer ) )
{
createViaWithMargin( track, layerContainer, maskExpansion );
}
&& !static_cast<const PCB_VIA*>( track )->FlashLayer( copper_layer ) )
continue;
int maskExpansion = track->GetSolderMaskExpansion();
createTrackWithMargin( track, layerContainer, maskExpansion );
}
}

View File

@ -575,6 +575,11 @@ inline bool IsHoleLayer( int aLayer )
|| aLayer == LAYER_NON_PLATEDHOLES;
}
inline bool IsSolderMaskLayer( int aLayer )
{
return aLayer == F_Mask || aLayer == B_Mask;
}
/**
* Test whether a layer is a non copper and a non tech layer.
*

View File

@ -46,6 +46,7 @@ DIALOG_TRACK_VIA_PROPERTIES::DIALOG_TRACK_VIA_PROPERTIES( PCB_BASE_FRAME* aParen
m_trackEndX( aParent, m_TrackEndXLabel, m_TrackEndXCtrl, nullptr ),
m_trackEndY( aParent, m_TrackEndYLabel, m_TrackEndYCtrl, m_TrackEndYUnit ),
m_trackWidth( aParent, m_TrackWidthLabel, m_TrackWidthCtrl, m_TrackWidthUnit ),
m_trackMaskMargin( aParent, m_trackMaskMarginLabel, m_trackMaskMarginCtrl, m_trackMaskMarginUnit ),
m_viaX( aParent, m_ViaXLabel, m_ViaXCtrl, nullptr ),
m_viaY( aParent, m_ViaYLabel, m_ViaYCtrl, m_ViaYUnit ),
m_viaDiameter( aParent, m_ViaDiameterLabel, m_ViaDiameterCtrl, m_ViaDiameterUnit ),
@ -103,6 +104,9 @@ DIALOG_TRACK_VIA_PROPERTIES::DIALOG_TRACK_VIA_PROPERTIES( PCB_BASE_FRAME* aParen
m_tentingBackCtrl->Disable();
m_tentingBackLabel->Disable();
wxFont infoFont = KIUI::GetInfoFont( this );
m_techLayersLabel->SetFont( infoFont );
bool nets = false;
int net = 0;
bool hasLocked = false;
@ -173,6 +177,13 @@ DIALOG_TRACK_VIA_PROPERTIES::DIALOG_TRACK_VIA_PROPERTIES( PCB_BASE_FRAME* aParen
m_trackEndY.SetValue( t->GetEnd().y );
m_trackWidth.SetValue( t->GetWidth() );
track_selection_layer = t->GetLayer();
m_trackHasSolderMask->SetValue ( t->HasSolderMask() );
if( t->GetLocalSolderMaskMargin().has_value() )
m_trackMaskMargin.SetValue( t->GetLocalSolderMaskMargin().value() );
else
m_trackMaskMargin.SetValue( wxEmptyString );
m_tracks = true;
}
else // check if values are the same for every selected track
@ -194,6 +205,12 @@ DIALOG_TRACK_VIA_PROPERTIES::DIALOG_TRACK_VIA_PROPERTIES( PCB_BASE_FRAME* aParen
if( track_selection_layer != t->GetLayer() )
track_selection_layer = UNDEFINED_LAYER;
if( m_trackHasSolderMask->GetValue() != t->HasSolderMask() )
m_trackHasSolderMask->Set3StateValue( wxCHK_UNDETERMINED );
if( m_trackMaskMargin.GetValue() != t->GetLocalSolderMaskMargin() )
m_trackMaskMargin.SetValue( INDETERMINATE_STATE );
}
if( t->IsLocked() )
@ -433,6 +450,9 @@ DIALOG_TRACK_VIA_PROPERTIES::DIALOG_TRACK_VIA_PROPERTIES( PCB_BASE_FRAME* aParen
m_predefinedTrackWidthsCtrl->SetSelection( widthSelection );
m_predefinedTrackWidthsUnits->SetLabel( EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
wxCommandEvent event;
onTrackEdit( event );
}
else
{
@ -628,6 +648,17 @@ bool DIALOG_TRACK_VIA_PROPERTIES::TransferDataFromWindow()
if( layer != UNDEFINED_LAYER )
t->SetLayer( (PCB_LAYER_ID) layer );
if ( m_trackHasSolderMask->Get3StateValue() != wxCHK_UNDETERMINED )
t->SetHasSolderMask( m_trackHasSolderMask->GetValue() );
if( !m_trackMaskMargin.IsIndeterminate() )
{
if( m_trackMaskMargin.IsNull() )
t->SetLocalSolderMaskMargin( {} );
else
t->SetLocalSolderMaskMargin( m_trackMaskMargin.GetIntValue() );
}
if( changeLock )
t->SetLocked( setLock );
@ -935,6 +966,22 @@ void DIALOG_TRACK_VIA_PROPERTIES::onTentingLinkToggle( wxCommandEvent& event )
}
void DIALOG_TRACK_VIA_PROPERTIES::onTrackEdit( wxCommandEvent& aEvent )
{
bool externalCuLayer = m_TrackLayerCtrl->GetLayerSelection() == F_Cu
|| m_TrackLayerCtrl->GetLayerSelection() == B_Cu;
m_techLayersLabel->Enable( externalCuLayer );
m_trackHasSolderMask->Enable( externalCuLayer );
bool showMaskMargin = externalCuLayer && m_trackHasSolderMask->GetValue();
m_trackMaskMarginCtrl->Enable( showMaskMargin );
m_trackMaskMarginLabel->Enable( showMaskMargin );
m_trackMaskMarginUnit->Enable( showMaskMargin );
}
void DIALOG_TRACK_VIA_PROPERTIES::onTeardropsUpdateUi( wxUpdateUIEvent& event )
{
event.Enable( !m_frame->GetBoard()->LegacyTeardrops() );

View File

@ -50,6 +50,7 @@ private:
void onViaEdit( wxCommandEvent& aEvent ) override;
void onTentingLinkToggle( wxCommandEvent& event ) override;
void onFrontTentingChanged( wxCommandEvent& event ) override;
void onTrackEdit( wxCommandEvent& aEvent ) override;
void onUnitsChanged( wxCommandEvent& aEvent );
void onTeardropsUpdateUi( wxUpdateUIEvent& event ) override;
@ -65,6 +66,7 @@ private:
UNIT_BINDER m_trackStartX, m_trackStartY;
UNIT_BINDER m_trackEndX, m_trackEndY;
UNIT_BINDER m_trackWidth;
UNIT_BINDER m_trackMaskMargin;
UNIT_BINDER m_viaX, m_viaY;
UNIT_BINDER m_viaDiameter, m_viaDrill;

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.0.0-0-g0efcecf)
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -153,6 +153,9 @@ DIALOG_TRACK_VIA_PROPERTIES_BASE::DIALOG_TRACK_VIA_PROPERTIES_BASE( wxWindow* pa
m_sbTrackSizer->Add( 0, 0, 0, wxEXPAND|wxRIGHT|wxLEFT, 15 );
wxBoxSizer* bSizerTrackRightControl;
bSizerTrackRightControl = new wxBoxSizer( wxVERTICAL );
wxFlexGridSizer* fgTrackRightSizer;
fgTrackRightSizer = new wxFlexGridSizer( 1, 3, 3, 5 );
fgTrackRightSizer->AddGrowableCol( 2 );
@ -170,7 +173,48 @@ DIALOG_TRACK_VIA_PROPERTIES_BASE::DIALOG_TRACK_VIA_PROPERTIES_BASE( wxWindow* pa
fgTrackRightSizer->Add( m_TrackLayerCtrl, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxRIGHT, 5 );
m_sbTrackSizer->Add( fgTrackRightSizer, 1, 0, 3 );
bSizerTrackRightControl->Add( fgTrackRightSizer, 0, wxEXPAND|wxRIGHT, 3 );
wxBoxSizer* bSizerTrackRemoveSoldermask;
bSizerTrackRemoveSoldermask = new wxBoxSizer( wxVERTICAL );
bSizerTrackRemoveSoldermask->Add( 0, 15, 0, wxEXPAND, 5 );
m_techLayersLabel = new wxStaticText( m_sbTrackSizer->GetStaticBox(), wxID_ANY, _("Technical Layers:"), wxDefaultPosition, wxDefaultSize, 0 );
m_techLayersLabel->Wrap( -1 );
bSizerTrackRemoveSoldermask->Add( m_techLayersLabel, 0, wxALL, 5 );
wxFlexGridSizer* fgSizerTrackMaskMargin;
fgSizerTrackMaskMargin = new wxFlexGridSizer( 0, 4, 3, 5 );
fgSizerTrackMaskMargin->AddGrowableCol( 2 );
fgSizerTrackMaskMargin->SetFlexibleDirection( wxBOTH );
fgSizerTrackMaskMargin->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_trackHasSolderMask = new wxCheckBox( m_sbTrackSizer->GetStaticBox(), wxID_ANY, _("Solder mask"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE );
fgSizerTrackMaskMargin->Add( m_trackHasSolderMask, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_trackMaskMarginLabel = new wxStaticText( m_sbTrackSizer->GetStaticBox(), wxID_ANY, _("Expansion:"), wxDefaultPosition, wxDefaultSize, 0 );
m_trackMaskMarginLabel->Wrap( -1 );
fgSizerTrackMaskMargin->Add( m_trackMaskMarginLabel, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
m_trackMaskMarginCtrl = new wxTextCtrl( m_sbTrackSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_trackMaskMarginCtrl->SetToolTip( _("This is the local clearance between the track and the solder mask opening.\nLeave blank to use the value defined in the Board Setup.") );
fgSizerTrackMaskMargin->Add( m_trackMaskMarginCtrl, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_trackMaskMarginUnit = new wxStaticText( m_sbTrackSizer->GetStaticBox(), wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
m_trackMaskMarginUnit->Wrap( -1 );
fgSizerTrackMaskMargin->Add( m_trackMaskMarginUnit, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
bSizerTrackRemoveSoldermask->Add( fgSizerTrackMaskMargin, 1, wxEXPAND, 3 );
bSizerTrackRightControl->Add( bSizerTrackRemoveSoldermask, 1, wxEXPAND, 3 );
m_sbTrackSizer->Add( bSizerTrackRightControl, 1, wxEXPAND, 5 );
m_MainSizer->Add( m_sbTrackSizer, 0, wxEXPAND|wxRIGHT|wxLEFT, 10 );
@ -615,6 +659,8 @@ DIALOG_TRACK_VIA_PROPERTIES_BASE::DIALOG_TRACK_VIA_PROPERTIES_BASE( wxWindow* pa
m_viaNotFree->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES_BASE::onViaNotFreeClicked ), NULL, this );
m_predefinedTrackWidthsCtrl->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES_BASE::onWidthSelect ), NULL, this );
m_TrackWidthCtrl->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES_BASE::onWidthEdit ), NULL, this );
m_TrackLayerCtrl->Connect( wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES_BASE::onTrackEdit ), NULL, this );
m_trackHasSolderMask->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES_BASE::onTrackEdit ), NULL, this );
m_predefinedViaSizesCtrl->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES_BASE::onViaSelect ), NULL, this );
m_ViaDiameterCtrl->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES_BASE::onViaEdit ), NULL, this );
m_ViaDrillCtrl->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES_BASE::onViaEdit ), NULL, this );
@ -655,6 +701,8 @@ DIALOG_TRACK_VIA_PROPERTIES_BASE::~DIALOG_TRACK_VIA_PROPERTIES_BASE()
m_viaNotFree->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES_BASE::onViaNotFreeClicked ), NULL, this );
m_predefinedTrackWidthsCtrl->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES_BASE::onWidthSelect ), NULL, this );
m_TrackWidthCtrl->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES_BASE::onWidthEdit ), NULL, this );
m_TrackLayerCtrl->Disconnect( wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES_BASE::onTrackEdit ), NULL, this );
m_trackHasSolderMask->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES_BASE::onTrackEdit ), NULL, this );
m_predefinedViaSizesCtrl->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES_BASE::onViaSelect ), NULL, this );
m_ViaDiameterCtrl->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES_BASE::onViaEdit ), NULL, this );
m_ViaDrillCtrl->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_TRACK_VIA_PROPERTIES_BASE::onViaEdit ), NULL, this );

View File

@ -1,34 +1,36 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<wxFormBuilder_Project>
<FileVersion major="1" minor="17"/>
<FileVersion major="1" minor="18"/>
<object class="Project" expanded="true">
<property name="class_decoration">; </property>
<property name="code_generation">C++</property>
<property name="disconnect_events">1</property>
<property name="disconnect_mode">source_name</property>
<property name="disconnect_php_events">0</property>
<property name="disconnect_python_events">0</property>
<property name="cpp_class_decoration">; </property>
<property name="cpp_disconnect_events">1</property>
<property name="cpp_event_generation">connect</property>
<property name="cpp_help_provider">none</property>
<property name="cpp_namespace"></property>
<property name="cpp_precompiled_header"></property>
<property name="cpp_use_array_enum">0</property>
<property name="cpp_use_enum">0</property>
<property name="embedded_files_path">res</property>
<property name="encoding">UTF-8</property>
<property name="event_generation">connect</property>
<property name="file">dialog_track_via_properties_base</property>
<property name="first_id">1000</property>
<property name="help_provider">none</property>
<property name="image_path_wrapper_function_name"></property>
<property name="indent_with_spaces"></property>
<property name="internationalize">1</property>
<property name="lua_skip_events">1</property>
<property name="lua_ui_table">UI</property>
<property name="name">DIALOG_TRACK_VIA_PROPERTIES_BASE</property>
<property name="namespace"></property>
<property name="path">.</property>
<property name="precompiled_header"></property>
<property name="php_disconnect_events">0</property>
<property name="php_disconnect_mode">source_name</property>
<property name="php_skip_events">1</property>
<property name="python_disconnect_events">0</property>
<property name="python_disconnect_mode">source_name</property>
<property name="python_image_path_wrapper_function_name"></property>
<property name="python_indent_with_spaces"></property>
<property name="python_skip_events">1</property>
<property name="relative_path">1</property>
<property name="skip_lua_events">1</property>
<property name="skip_php_events">1</property>
<property name="skip_python_events">1</property>
<property name="ui_table">UI</property>
<property name="use_array_enum">0</property>
<property name="use_enum">0</property>
<property name="use_microsoft_bom">0</property>
<property name="use_native_eol">0</property>
<object class="Dialog" expanded="true">
<property name="aui_managed">0</property>
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
@ -1533,157 +1535,524 @@
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">3</property>
<property name="flag"></property>
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxFlexGridSizer" expanded="true">
<property name="cols">3</property>
<property name="flexible_direction">wxBOTH</property>
<property name="growablecols">2</property>
<property name="growablerows"></property>
<property name="hgap">5</property>
<object class="wxBoxSizer" expanded="true">
<property name="minimum_size"></property>
<property name="name">fgTrackRightSizer</property>
<property name="non_flexible_grow_mode">wxFLEX_GROWMODE_SPECIFIED</property>
<property name="name">bSizerTrackRightControl</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<property name="rows">1</property>
<property name="vgap">3</property>
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT</property>
<object class="sizeritem" expanded="true">
<property name="border">3</property>
<property name="flag">wxEXPAND|wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">0</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Layer:</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<object class="wxFlexGridSizer" expanded="true">
<property name="cols">3</property>
<property name="flexible_direction">wxBOTH</property>
<property name="growablecols">2</property>
<property name="growablerows"></property>
<property name="hgap">5</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_TrackLayerLabel</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
<property name="name">fgTrackRightSizer</property>
<property name="non_flexible_grow_mode">wxFLEX_GROWMODE_SPECIFIED</property>
<property name="permission">none</property>
<property name="rows">1</property>
<property name="vgap">3</property>
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">0</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Layer:</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_TrackLayerLabel</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="spacer" expanded="true">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">25</property>
</object>
</object>
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxEXPAND|wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxBitmapComboBox" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="choices"></property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_TrackLayerCtrl</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="selection">-1</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">PCB_LAYER_BOX_SELECTOR; pcb_layer_box_selector.h</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="border">3</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="spacer" expanded="true">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">25</property>
</object>
</object>
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxEXPAND|wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxBitmapComboBox" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="choices"></property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="proportion">1</property>
<object class="wxBoxSizer" expanded="true">
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_TrackLayerCtrl</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="selection">-1</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">PCB_LAYER_BOX_SELECTOR; pcb_layer_box_selector.h</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="name">bSizerTrackRemoveSoldermask</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="spacer" expanded="true">
<property name="height">15</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Technical Layers:</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_techLayersLabel</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">3</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxFlexGridSizer" expanded="true">
<property name="cols">4</property>
<property name="flexible_direction">wxBOTH</property>
<property name="growablecols">2</property>
<property name="growablerows"></property>
<property name="hgap">5</property>
<property name="minimum_size"></property>
<property name="name">fgSizerTrackMaskMargin</property>
<property name="non_flexible_grow_mode">wxFLEX_GROWMODE_SPECIFIED</property>
<property name="permission">none</property>
<property name="rows">0</property>
<property name="vgap">3</property>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="checked">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Solder mask</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_trackHasSolderMask</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxCHK_3STATE</property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnCheckBox">onTrackEdit</event>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Expansion:</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_trackMaskMarginLabel</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxTextCtrl" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="maxlength">0</property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_trackMaskMarginCtrl</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip">This is the local clearance between the track and the solder mask opening.&#x0A;Leave blank to use the value defined in the Board Setup.</property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">mm</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_trackMaskMarginUnit</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
</object>
</object>
</object>
</object>
</object>
</object>
</object>

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.0.0-0-g0efcecf)
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -38,7 +38,6 @@ class PCB_LAYER_BOX_SELECTOR;
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class DIALOG_TRACK_VIA_PROPERTIES_BASE
///////////////////////////////////////////////////////////////////////////////
@ -79,6 +78,11 @@ class DIALOG_TRACK_VIA_PROPERTIES_BASE : public DIALOG_SHIM
wxStaticText* m_TrackWidthUnit;
wxStaticText* m_TrackLayerLabel;
PCB_LAYER_BOX_SELECTOR* m_TrackLayerCtrl;
wxStaticText* m_techLayersLabel;
wxCheckBox* m_trackHasSolderMask;
wxStaticText* m_trackMaskMarginLabel;
wxTextCtrl* m_trackMaskMarginCtrl;
wxStaticText* m_trackMaskMarginUnit;
wxStaticBoxSizer* m_sbViaSizer;
wxStaticText* m_ViaXLabel;
wxTextCtrl* m_ViaXCtrl;
@ -138,6 +142,7 @@ class DIALOG_TRACK_VIA_PROPERTIES_BASE : public DIALOG_SHIM
virtual void onViaNotFreeClicked( wxCommandEvent& event ) { event.Skip(); }
virtual void onWidthSelect( wxCommandEvent& event ) { event.Skip(); }
virtual void onWidthEdit( wxCommandEvent& event ) { event.Skip(); }
virtual void onTrackEdit( wxCommandEvent& event ) { event.Skip(); }
virtual void onViaSelect( wxCommandEvent& event ) { event.Skip(); }
virtual void onViaEdit( wxCommandEvent& event ) { event.Skip(); }
virtual void onFrontTentingChanged( wxCommandEvent& event ) { event.Skip(); }

View File

@ -2532,32 +2532,41 @@ void PCB_IO_KICAD_SEXPR::format( const PCB_TRACK* aTrack, int aNestLevel ) const
formatTeardropParameters( via->GetTeardropParams(), aNestLevel+1 );
}
}
else if( aTrack->Type() == PCB_ARC_T )
{
const PCB_ARC* arc = static_cast<const PCB_ARC*>( aTrack );
m_out->Print( aNestLevel, "(arc (start %s) (mid %s) (end %s) (width %s)",
formatInternalUnits( arc->GetStart() ).c_str(),
formatInternalUnits( arc->GetMid() ).c_str(),
formatInternalUnits( arc->GetEnd() ).c_str(),
formatInternalUnits( arc->GetWidth() ).c_str() );
if( arc->IsLocked() )
KICAD_FORMAT::FormatBool( m_out, 0, "locked", arc->IsLocked() );
m_out->Print( 0, " (layer %s)", m_out->Quotew( LSET::Name( arc->GetLayer() ) ).c_str() );
}
else
{
m_out->Print( aNestLevel, "(segment (start %s) (end %s) (width %s)",
formatInternalUnits( aTrack->GetStart() ).c_str(),
formatInternalUnits( aTrack->GetEnd() ).c_str(),
formatInternalUnits( aTrack->GetWidth() ).c_str() );
if( aTrack->Type() == PCB_ARC_T )
{
const PCB_ARC* arc = static_cast<const PCB_ARC*>( aTrack );
m_out->Print( aNestLevel, "(arc (start %s) (mid %s) (end %s) (width %s)",
formatInternalUnits( arc->GetStart() ).c_str(),
formatInternalUnits( arc->GetMid() ).c_str(),
formatInternalUnits( arc->GetEnd() ).c_str(),
formatInternalUnits( arc->GetWidth() ).c_str() );
}
else
{
m_out->Print( aNestLevel, "(segment (start %s) (end %s) (width %s)",
formatInternalUnits( aTrack->GetStart() ).c_str(),
formatInternalUnits( aTrack->GetEnd() ).c_str(),
formatInternalUnits( aTrack->GetWidth() ).c_str() );
}
if( aTrack->IsLocked() )
KICAD_FORMAT::FormatBool( m_out, 0, "locked", aTrack->IsLocked() );
m_out->Print( 0, " (layer %s)", m_out->Quotew( LSET::Name( aTrack->GetLayer() ) ).c_str() );
if( aTrack->GetLayerSet().count() > 1 )
formatLayers( aTrack->GetLayerSet() );
else
formatLayer( aTrack->GetLayer() );
if( aTrack->HasSolderMask()
&& aTrack->GetLocalSolderMaskMargin().has_value()
&& ( aTrack->IsOnLayer( F_Cu ) || aTrack->IsOnLayer( B_Cu ) ) )
{
m_out->Print( 0, " (solder_mask_margin %s)",
formatInternalUnits( aTrack->GetLocalSolderMaskMargin().value() ).c_str() );
}
}
m_out->Print( 0, " (net %d)", m_mapping->Translate( aTrack->GetNetCode() ) );

View File

@ -165,7 +165,8 @@ class PCB_IO_KICAD_SEXPR; // forward decl
//#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 20241006 // Via stacks
//#define SEXPR_BOARD_FILE_VERSION 20241006 // Via stacks
#define SEXPR_BOARD_FILE_VERSION 20241007 // Tracks can have soldermask layer and margin
#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

@ -2109,6 +2109,30 @@ LSET PCB_IO_KICAD_SEXPR_PARSER::parseBoardItemLayersAsMask()
}
LSET PCB_IO_KICAD_SEXPR_PARSER::parseLayersForCuItemWithSoldermask()
{
LSET layerMask = parseBoardItemLayersAsMask();
if( ( layerMask & LSET::AllCuMask() ).count() != 1 )
Expecting( "single copper layer" );
if( ( layerMask & LSET( { F_Mask, B_Mask } ) ).count() > 1 )
Expecting( "max one soldermask layer" );
if( ( ( layerMask & LSET::InternalCuMask() ).any()
&& ( layerMask & LSET( { F_Mask, B_Mask } ) ).any() ) )
Expecting( "no mask layer when track is on internal layer" );
if( ( layerMask & LSET( { F_Cu, B_Mask } ) ).count() > 1 )
Expecting( "copper and mask on the same side" );
if( ( layerMask & LSET( { B_Cu, F_Mask } ) ).count() > 1 )
Expecting( "copper and mask on the same side" );
return layerMask;
}
void PCB_IO_KICAD_SEXPR_PARSER::parseSetup()
{
wxCHECK_RET( CurTok() == T_setup,
@ -6098,6 +6122,15 @@ PCB_ARC* PCB_IO_KICAD_SEXPR_PARSER::parseARC()
NeedRIGHT();
break;
case T_layers:
arc->SetLayerSet( parseLayersForCuItemWithSoldermask() );
break;
case T_solder_mask_margin:
arc->SetLocalSolderMaskMargin( parseBoardUnits( "local solder mask margin value" ) );
NeedRIGHT();
break;
case T_net:
if( !arc->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
{
@ -6125,7 +6158,8 @@ PCB_ARC* PCB_IO_KICAD_SEXPR_PARSER::parseARC()
break;
default:
Expecting( "start, mid, end, width, layer, net, tstamp, uuid, or status" );
Expecting( "start, mid, end, width, layer, solder_mask_margin, net, tstamp, uuid, "
"or status" );
}
}
@ -6183,6 +6217,15 @@ PCB_TRACK* PCB_IO_KICAD_SEXPR_PARSER::parsePCB_TRACK()
NeedRIGHT();
break;
case T_layers:
track->SetLayerSet( parseLayersForCuItemWithSoldermask() );
break;
case T_solder_mask_margin:
track->SetLocalSolderMaskMargin( parseBoardUnits( "local solder mask margin value" ) );
NeedRIGHT();
break;
case T_net:
if( !track->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
{
@ -6210,7 +6253,8 @@ PCB_TRACK* PCB_IO_KICAD_SEXPR_PARSER::parsePCB_TRACK()
break;
default:
Expecting( "start, end, width, layer, net, tstamp, uuid, or locked" );
Expecting( "start, end, width, layer, solder_mask_margin, net, tstamp, uuid, "
"or locked" );
}
}

View File

@ -277,6 +277,16 @@ private:
*/
LSET parseBoardItemLayersAsMask();
/**
* Parse the layers definition of a #BOARD_ITEM object
* that has a single copper layer and optional soldermask layer.
*
* @return The mask of layers the parsed #BOARD_ITEM is on.
* @throw IO_ERROR if any of the layers is not valid.
* @throw PARSE_ERROR if the layers syntax is incorrect.
*/
LSET parseLayersForCuItemWithSoldermask();
/**
* Parse a coordinate pair (xy X Y) in board units (mm).
*

View File

@ -719,7 +719,8 @@ void PCB_PAINTER::draw( const PCB_TRACK* aTrack, int aLayer )
renderNetNameForSegment( trackShape, color, aTrack->GetDisplayNetname() );
return;
}
else if( IsCopperLayer( aLayer ) || aLayer == LAYER_LOCKED_ITEM_SHADOW )
else if( IsCopperLayer( aLayer ) || IsSolderMaskLayer( aLayer )
|| aLayer == LAYER_LOCKED_ITEM_SHADOW )
{
// Draw a regular track
bool outline_mode = pcbconfig()
@ -731,6 +732,9 @@ void PCB_PAINTER::draw( const PCB_TRACK* aTrack, int aLayer )
m_gal->SetIsFill( not outline_mode );
m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
if( IsSolderMaskLayer( aLayer ) )
track_width = track_width + aTrack->GetSolderMaskExpansion() * 2;
if( aLayer == LAYER_LOCKED_ITEM_SHADOW )
track_width = track_width + m_lockedShadowMargin;
@ -851,7 +855,8 @@ void PCB_PAINTER::draw( const PCB_ARC* aArc, int aLayer )
// Ummm, yeah. Anyone fancy implementing text on a path?
return;
}
else if( IsCopperLayer( aLayer ) || aLayer == LAYER_LOCKED_ITEM_SHADOW )
else if( IsCopperLayer( aLayer ) || IsSolderMaskLayer( aLayer )
|| aLayer == LAYER_LOCKED_ITEM_SHADOW )
{
// Draw a regular track
bool outline_mode = pcbconfig()
@ -863,6 +868,9 @@ void PCB_PAINTER::draw( const PCB_ARC* aArc, int aLayer )
m_gal->SetIsFill( not outline_mode );
m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
if( IsSolderMaskLayer( aLayer ) )
width = width + aArc->GetSolderMaskExpansion() * 2;
if( aLayer == LAYER_LOCKED_ITEM_SHADOW )
width = width + m_lockedShadowMargin;

View File

@ -61,6 +61,7 @@ PCB_TRACK::PCB_TRACK( BOARD_ITEM* aParent, KICAD_T idtype ) :
BOARD_CONNECTED_ITEM( aParent, idtype )
{
m_Width = pcbIUScale.mmToIU( 0.2 ); // Gives a reasonable default width
m_hasSolderMask = false;
}
@ -178,7 +179,9 @@ bool PCB_TRACK::operator==( const PCB_TRACK& aOther ) const
return m_Start == aOther.m_Start
&& m_End == aOther.m_End
&& m_layer == aOther.m_layer
&& m_Width == aOther.m_Width;
&& m_Width == aOther.m_Width
&& m_hasSolderMask == aOther.m_hasSolderMask
&& m_solderMaskMargin == aOther.m_solderMaskMargin;
}
@ -203,6 +206,12 @@ double PCB_TRACK::Similarity( const BOARD_ITEM& aOther ) const
if( m_End != other.m_End )
similarity *= 0.9;
if( m_hasSolderMask != other.m_hasSolderMask )
similarity *= 0.9;
if( m_solderMaskMargin != other.m_solderMaskMargin )
similarity *= 0.9;
return similarity;
}
@ -224,7 +233,9 @@ bool PCB_ARC::operator==( const PCB_ARC& aOther ) const
&& m_End == aOther.m_End
&& m_Mid == aOther.m_Mid
&& m_layer == aOther.m_layer
&& m_Width == aOther.m_Width;
&& m_Width == aOther.m_Width
&& m_hasSolderMask == aOther.m_hasSolderMask
&& m_solderMaskMargin == aOther.m_solderMaskMargin;
}
@ -252,6 +263,12 @@ double PCB_ARC::Similarity( const BOARD_ITEM& aOther ) const
if( m_Mid != other.m_Mid )
similarity *= 0.9;
if( m_hasSolderMask != other.m_hasSolderMask )
similarity *= 0.9;
if( m_solderMaskMargin != other.m_solderMaskMargin )
similarity *= 0.9;
return similarity;
}
@ -352,6 +369,7 @@ void PCB_TRACK::Serialize( google::protobuf::Any &aContainer ) const
: kiapi::common::types::LockedState::LS_UNLOCKED );
track.mutable_net()->mutable_code()->set_value( GetNetCode() );
track.mutable_net()->set_name( GetNetname() );
// TODO m_hasSolderMask and m_solderMaskMargin
aContainer.PackFrom( track );
}
@ -371,6 +389,7 @@ bool PCB_TRACK::Deserialize( const google::protobuf::Any &aContainer )
SetLayer( FromProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( track.layer() ) );
SetNetCode( track.net().code().value() );
SetLocked( track.locked() == kiapi::common::types::LockedState::LS_LOCKED );
// TODO m_hasSolderMask and m_solderMaskMargin
return true;
}
@ -393,6 +412,7 @@ void PCB_ARC::Serialize( google::protobuf::Any &aContainer ) const
: kiapi::common::types::LockedState::LS_UNLOCKED );
arc.mutable_net()->mutable_code()->set_value( GetNetCode() );
arc.mutable_net()->set_name( GetNetname() );
// TODO m_hasSolderMask and m_solderMaskMargin
aContainer.PackFrom( arc );
}
@ -413,6 +433,7 @@ bool PCB_ARC::Deserialize( const google::protobuf::Any &aContainer )
SetLayer( FromProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( arc.layer() ) );
SetNetCode( arc.net().code().value() );
SetLocked( arc.locked() == kiapi::common::types::LockedState::LS_LOCKED );
// TODO m_hasSolderMask and m_solderMaskMargin
return true;
}
@ -864,6 +885,45 @@ int PCB_VIA::GetSolderMaskExpansion() const
}
int PCB_TRACK::GetSolderMaskExpansion() const
{
int margin = m_solderMaskMargin.value_or( 0 );
// If no local margin is set, get the board's solder mask expansion value
if( !m_solderMaskMargin.has_value() )
{
const BOARD* board = GetBoard();
if( board )
margin = board->GetDesignSettings().m_SolderMaskExpansion;
}
// Ensure the resulting mask opening has a non-negative size
if( margin < 0 )
margin = std::max( margin, -m_Width / 2 );
return margin;
}
bool PCB_TRACK::IsOnLayer( PCB_LAYER_ID aLayer ) const
{
if( aLayer == m_layer )
{
return true;
}
if( m_hasSolderMask
&& ( ( aLayer == F_Mask && m_layer == F_Cu )
|| ( aLayer == B_Mask && m_layer == B_Cu ) ) )
{
return true;
}
return false;
}
bool PCB_VIA::IsOnLayer( PCB_LAYER_ID aLayer ) const
{
#if 0
@ -921,6 +981,35 @@ void PCB_VIA::SetLayer( PCB_LAYER_ID aLayer )
}
void PCB_TRACK::SetLayerSet( const LSET& aLayerSet )
{
aLayerSet.RunOnLayers(
[&]( PCB_LAYER_ID layer )
{
if( IsCopperLayer( layer ) )
SetLayer( layer );
else if( IsSolderMaskLayer( layer ) )
SetHasSolderMask( true );
} );
}
LSET PCB_TRACK::GetLayerSet() const
{
LSET layermask( { m_layer } );
if( m_hasSolderMask )
{
if( layermask.test( F_Cu ) )
layermask.set( F_Mask );
else if( layermask.test( B_Cu ) )
layermask.set( B_Mask );
}
return layermask;
}
LSET PCB_VIA::GetLayerSet() const
{
LSET layermask;
@ -1192,6 +1281,14 @@ void PCB_TRACK::ViewGetLayers( int aLayers[], int& aCount ) const
aLayers[1] = GetNetnameLayer( aLayers[0] );
aCount = 2;
if( m_hasSolderMask )
{
if( m_layer == F_Cu )
aLayers[ aCount++ ] = F_Mask;
else if( m_layer == B_Cu )
aLayers[ aCount++ ] = B_Mask;
}
if( IsLocked() )
aLayers[ aCount++ ] = LAYER_LOCKED_ITEM_SHADOW;
}
@ -1772,7 +1869,12 @@ bool PCB_TRACK::cmp_tracks::operator() ( const PCB_TRACK* a, const PCB_TRACK* b
std::shared_ptr<SHAPE> PCB_TRACK::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
{
return std::make_shared<SHAPE_SEGMENT>( m_Start, m_End, m_Width );
int width = m_Width;
if( IsSolderMaskLayer( aLayer ) )
width += 2 * GetSolderMaskExpansion();
return std::make_shared<SHAPE_SEGMENT>( m_Start, m_End, width );
}
@ -1793,7 +1895,12 @@ std::shared_ptr<SHAPE> PCB_VIA::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING
std::shared_ptr<SHAPE> PCB_ARC::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
{
return std::make_shared<SHAPE_ARC>( GetStart(), GetMid(), GetEnd(), GetWidth() );
int width = GetWidth();
if( IsSolderMaskLayer( aLayer ) )
width += 2 * GetSolderMaskExpansion();
return std::make_shared<SHAPE_ARC>( GetStart(), GetMid(), GetEnd(), width );
}
@ -1818,6 +1925,9 @@ void PCB_TRACK::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID a
const PCB_ARC* arc = static_cast<const PCB_ARC*>( this );
int width = m_Width + ( 2 * aClearance );
if( IsSolderMaskLayer( aLayer ) )
width += 2 * GetSolderMaskExpansion();
TransformArcToPolygon( aBuffer, arc->GetStart(), arc->GetMid(), arc->GetEnd(), width,
aError, aErrorLoc );
break;
@ -1827,7 +1937,11 @@ void PCB_TRACK::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID a
{
int width = m_Width + ( 2 * aClearance );
if( IsSolderMaskLayer( aLayer ) )
width += 2 * GetSolderMaskExpansion();
TransformOvalToPolygon( aBuffer, m_Start, m_End, width, aError, aErrorLoc );
break;
}
}
@ -1883,6 +1997,14 @@ static struct TRACK_VIA_DESC
&PCB_TRACK::SetEndY, &PCB_TRACK::GetEndY, PROPERTY_DISPLAY::PT_COORD,
ORIGIN_TRANSFORMS::ABS_Y_COORD) );
const wxString groupTechLayers = _HKI( "Technical Layers" );
propMgr.AddProperty( new PROPERTY<PCB_TRACK, bool>( _HKI( "Soldermask" ),
&PCB_TRACK::SetHasSolderMask, &PCB_TRACK::HasSolderMask ), groupTechLayers );
propMgr.AddProperty( new PROPERTY<PCB_TRACK, std::optional<int>>( _HKI( "Soldermask Margin Override" ),
&PCB_TRACK::SetLocalSolderMaskMargin, &PCB_TRACK::GetLocalSolderMaskMargin,
PROPERTY_DISPLAY::PT_SIZE ), groupTechLayers );
// Arc
REGISTER_TYPE( PCB_ARC );
propMgr.InheritsAfter( TYPE_HASH( PCB_ARC ), TYPE_HASH( PCB_TRACK ) );

View File

@ -136,7 +136,20 @@ public:
return m_End;
}
void SetHasSolderMask( bool aVal ) { m_hasSolderMask = aVal; }
bool HasSolderMask() const { return m_hasSolderMask; }
void SetLocalSolderMaskMargin( std::optional<int> aMargin ) { m_solderMaskMargin = aMargin; }
std::optional<int> GetLocalSolderMaskMargin() const { return m_solderMaskMargin; }
int GetSolderMaskExpansion() const;
// Virtual function
bool IsOnLayer( PCB_LAYER_ID aLayer ) const override;
virtual LSET GetLayerSet() const override;
virtual void SetLayerSet( const LSET& aLayers ) override;
const BOX2I GetBoundingBox() const override;
/**
@ -247,6 +260,9 @@ protected:
int m_Width; ///< Thickness of track
VECTOR2I m_Start; ///< Line start point
VECTOR2I m_End; ///< Line end point
bool m_hasSolderMask;
std::optional<int> m_solderMaskMargin;
};

View File

@ -599,13 +599,10 @@ void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
}
// Plot vias on copper layers, and if aPlotOpt.GetPlotViaOnMaskLayer() is true,
// plot them on solder mask
GBR_METADATA gbr_metadata;
bool isOnCopperLayer = ( aLayerMask & LSET::AllCuMask() ).any();
if( isOnCopperLayer )
if( onCopperLayer )
{
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_VIAPAD );
gbr_metadata.SetNetAttribType( GBR_NETLIST_METADATA::GBR_NETINFO_NET );
@ -629,7 +626,7 @@ void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
int via_margin = 0;
double width_adj = 0;
if( aLayerMask[B_Mask] || aLayerMask[F_Mask] )
if( onSolderMaskLayer )
via_margin = via->GetSolderMaskExpansion();
if( ( aLayerMask & LSET::AllCuMask() ).any() )
@ -663,7 +660,18 @@ void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
aPlotter->EndBlock( nullptr );
aPlotter->StartBlock( nullptr );
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CONDUCTOR );
if( onCopperLayer )
{
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CONDUCTOR );
gbr_metadata.SetNetAttribType( GBR_NETLIST_METADATA::GBR_NETINFO_NET );
}
else
{
// Reset attributes if non-copper (soldermask) layer
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_NONE );
gbr_metadata.SetNetAttribType( GBR_NETLIST_METADATA::GBR_NETINFO_UNSPECIFIED );
}
// Plot tracks (not vias) :
for( const PCB_TRACK* track : aBoard->Tracks() )
@ -671,7 +679,7 @@ void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
if( track->Type() == PCB_VIA_T )
continue;
if( !aLayerMask[track->GetLayer()] )
if( !( aLayerMask & track->GetLayerSet() ).any() )
continue;
// Some track segments can be not connected (no net).
@ -679,7 +687,14 @@ void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
gbr_metadata.m_NetlistMetadata.m_NotInNet = track->GetNetname().IsEmpty();
gbr_metadata.SetNetName( track->GetNetname() );
int width = track->GetWidth() + itemplotter.getFineWidthAdj();
int margin = 0;
if( onSolderMaskLayer )
margin = track->GetSolderMaskExpansion();
int width = track->GetWidth() + 2 * margin + itemplotter.getFineWidthAdj();
aPlotter->SetColor( itemplotter.getColor( track->GetLayer() ) );
if( track->Type() == PCB_ARC_T )

View File

@ -658,6 +658,8 @@ int EDIT_TOOL::DragArcTrack( const TOOL_EVENT& aEvent )
track->SetLayer( theArc->GetLayer() );
track->SetWidth( theArc->GetWidth() );
track->SetLocked( theArc->IsLocked() );
track->SetHasSolderMask( theArc->HasSolderMask() );
track->SetLocalSolderMaskMargin( theArc->GetLocalSolderMaskMargin() );
track->SetFlags( IS_NEW );
getView()->Add( track );
addedTracks.insert( track );
@ -1150,6 +1152,8 @@ int EDIT_TOOL::FilletTracks( const TOOL_EVENT& aEvent )
tArc->SetWidth( track1->GetWidth() );
tArc->SetNet( track1->GetNet() );
tArc->SetLocked( track1->IsLocked() );
tArc->SetHasSolderMask( track1->HasSolderMask() );
tArc->SetLocalSolderMaskMargin( track1->GetLocalSolderMaskMargin() );
commit.Add( tArc );
itemsToAddToSelection.push_back( tArc );