diff --git a/pcbnew/board.cpp b/pcbnew/board.cpp index fe7a7c3ce4..e621d9af15 100644 --- a/pcbnew/board.cpp +++ b/pcbnew/board.cpp @@ -5,7 +5,7 @@ * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2011 Wayne Stambaugh * - * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -775,18 +775,21 @@ int BOARD::GetMaxClearanceValue() const { int worstClearance = m_designSettings->GetBiggestClearanceValue(); - for( ZONE* zone : m_zones ) - worstClearance = std::max( worstClearance, zone->GetLocalClearance() ); + for( ZONE* zone : m_zones ) + worstClearance = std::max( worstClearance, zone->GetLocalClearance().value() ); for( FOOTPRINT* footprint : m_footprints ) { - worstClearance = std::max( worstClearance, footprint->GetLocalClearance() ); - for( PAD* pad : footprint->Pads() ) - worstClearance = std::max( worstClearance, pad->GetLocalClearance() ); + { + std::optional override = pad->GetClearanceOverrides( nullptr ); + + if( override.has_value() ) + worstClearance = std::max( worstClearance, override.value() ); + } for( ZONE* zone : footprint->Zones() ) - worstClearance = std::max( worstClearance, zone->GetLocalClearance() ); + worstClearance = std::max( worstClearance, zone->GetLocalClearance().value() ); } return worstClearance; diff --git a/pcbnew/board_connected_item.h b/pcbnew/board_connected_item.h index 8d9dbefdb4..38dece90d0 100644 --- a/pcbnew/board_connected_item.h +++ b/pcbnew/board_connected_item.h @@ -3,7 +3,7 @@ * * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck - * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -141,21 +141,36 @@ public: virtual int GetOwnClearance( PCB_LAYER_ID aLayer, wxString* aSource = nullptr ) const; /** - * Return any local clearance overrides set in the "classic" (ie: pre-rule) system. + * Return any clearance overrides set in the "classic" (ie: pre-rule) system. * * @param aSource [out] optionally reports the source as a user-readable string. * @return the clearance in internal units. */ - virtual int GetLocalClearanceOverrides( wxString* aSource ) const { return 0; } + virtual std::optional GetClearanceOverrides( wxString* aSource ) const + { + return std::optional(); + } /** - * Return any local clearances set in the "classic" (ie: pre-rule) system. These are - * things like zone clearance which are **not** an override. + * Return any local clearances set in the "classic" (ie: pre-rule) system. * - * @param aSource [out] optionally reports the source as a user readable string. - * @return the clearance in internal units. + * @return the clearance (if any is specified) in internal units. */ - virtual int GetLocalClearance( wxString* aSource ) const { return 0; } + virtual std::optional GetLocalClearance() const + { + return std::optional(); + } + + /** + * Return any local clearances set in the "classic" (ie: pre-rule) system. + * + * @param aSource [out] optionally reports the source as a user-readable string. + * @return the clearance (if any is specified) in internal units. + */ + virtual std::optional GetLocalClearance( wxString* aSource ) const + { + return std::optional(); + } /** * Return the #NETCLASS for this item. diff --git a/pcbnew/dialogs/dialog_footprint_properties.cpp b/pcbnew/dialogs/dialog_footprint_properties.cpp index 3a21c86366..93345d69bd 100644 --- a/pcbnew/dialogs/dialog_footprint_properties.cpp +++ b/pcbnew/dialogs/dialog_footprint_properties.cpp @@ -4,7 +4,7 @@ * Copyright (C) 2016 Mario Luzeiro * Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2015 Dick Hollenbeck, dick@softplc.com - * Copyright (C) 2004-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2004-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -304,13 +304,29 @@ bool DIALOG_FOOTPRINT_PROPERTIES::TransferDataToWindow() // Local Clearances - m_netClearance.SetValue( m_footprint->GetLocalClearance() ); - m_solderMask.SetValue( m_footprint->GetLocalSolderMaskMargin() ); - m_solderPaste.SetValue( m_footprint->GetLocalSolderPasteMargin() ); - m_solderPasteRatio.SetDoubleValue( m_footprint->GetLocalSolderPasteMarginRatio() * 100.0 ); + if( m_footprint->GetLocalClearance().has_value() ) + m_netClearance.SetValue( m_footprint->GetLocalClearance().value() ); + else + m_netClearance.SetValue( wxEmptyString ); + + if( m_footprint->GetLocalSolderMaskMargin().has_value() ) + m_solderMask.SetValue( m_footprint->GetLocalSolderMaskMargin().value() ); + else + m_solderMask.SetValue( wxEmptyString ); + + if( m_footprint->GetLocalSolderPasteMargin().has_value() ) + m_solderPaste.SetValue( m_footprint->GetLocalSolderPasteMargin().value() ); + else + m_solderPaste.SetValue( wxEmptyString ); + + if( m_footprint->GetLocalSolderPasteMarginRatio().has_value() ) + m_solderPasteRatio.SetDoubleValue( m_footprint->GetLocalSolderPasteMarginRatio().value() * 100.0 ); + else + m_solderPasteRatio.SetValue( wxEmptyString ); + m_allowSolderMaskBridges->SetValue( m_footprint->GetAttributes() & FP_ALLOW_SOLDERMASK_BRIDGES ); - switch( m_footprint->GetZoneConnection() ) + switch( m_footprint->GetLocalZoneConnection() ) { default: case ZONE_CONNECTION::INHERITED: m_ZoneConnectionChoice->SetSelection( 0 ); break; @@ -506,18 +522,33 @@ bool DIALOG_FOOTPRINT_PROPERTIES::TransferDataFromWindow() } // Initialize masks clearances - m_footprint->SetLocalClearance( m_netClearance.GetValue() ); - m_footprint->SetLocalSolderMaskMargin( m_solderMask.GetValue() ); - m_footprint->SetLocalSolderPasteMargin( m_solderPaste.GetValue() ); - m_footprint->SetLocalSolderPasteMarginRatio( m_solderPasteRatio.GetDoubleValue() / 100.0 ); + if( m_netClearance.IsNull() ) + m_footprint->SetLocalClearance( {} ); + else + m_footprint->SetLocalClearance( m_netClearance.GetValue() ); + + if( m_solderMask.IsNull() ) + m_footprint->SetLocalSolderMaskMargin( {} ); + else + m_footprint->SetLocalSolderMaskMargin( m_solderMask.GetValue() ); + + if( m_solderPaste.IsNull() ) + m_footprint->SetLocalSolderPasteMargin( {} ); + else + m_footprint->SetLocalSolderPasteMargin( m_solderPaste.GetValue() ); + + if( m_solderPasteRatio.IsNull() ) + m_footprint->SetLocalSolderPasteMarginRatio( {} ); + else + m_footprint->SetLocalSolderPasteMarginRatio( m_solderPasteRatio.GetDoubleValue() / 100.0 ); switch( m_ZoneConnectionChoice->GetSelection() ) { default: - case 0: m_footprint->SetZoneConnection( ZONE_CONNECTION::INHERITED ); break; - case 1: m_footprint->SetZoneConnection( ZONE_CONNECTION::FULL ); break; - case 2: m_footprint->SetZoneConnection( ZONE_CONNECTION::THERMAL ); break; - case 3: m_footprint->SetZoneConnection( ZONE_CONNECTION::NONE ); break; + case 0: m_footprint->SetLocalZoneConnection( ZONE_CONNECTION::INHERITED ); break; + case 1: m_footprint->SetLocalZoneConnection( ZONE_CONNECTION::FULL ); break; + case 2: m_footprint->SetLocalZoneConnection( ZONE_CONNECTION::THERMAL ); break; + case 3: m_footprint->SetLocalZoneConnection( ZONE_CONNECTION::NONE ); break; } // Set Footprint Position diff --git a/pcbnew/dialogs/dialog_footprint_properties_base.cpp b/pcbnew/dialogs/dialog_footprint_properties_base.cpp index 6e03059901..8b33637dff 100644 --- a/pcbnew/dialogs/dialog_footprint_properties_base.cpp +++ b/pcbnew/dialogs/dialog_footprint_properties_base.cpp @@ -258,7 +258,7 @@ DIALOG_FOOTPRINT_PROPERTIES_BASE::DIALOG_FOOTPRINT_PROPERTIES_BASE( wxWindow* pa m_PanelGeneral->SetSizer( m_PanelPropertiesBoxSizer ); m_PanelGeneral->Layout(); m_PanelPropertiesBoxSizer->Fit( m_PanelGeneral ); - m_NoteBook->AddPage( m_PanelGeneral, _("General"), true ); + m_NoteBook->AddPage( m_PanelGeneral, _("General"), false ); m_PanelClearances = new wxPanel( m_NoteBook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); wxBoxSizer* bSizerPanelClearances; bSizerPanelClearances = new wxBoxSizer( wxVERTICAL ); @@ -266,7 +266,7 @@ DIALOG_FOOTPRINT_PROPERTIES_BASE::DIALOG_FOOTPRINT_PROPERTIES_BASE( wxWindow* pa wxStaticBoxSizer* sbSizerLocalProperties; sbSizerLocalProperties = new wxStaticBoxSizer( new wxStaticBox( m_PanelClearances, wxID_ANY, _("Clearances") ), wxVERTICAL ); - m_staticTextInfo = new wxStaticText( sbSizerLocalProperties->GetStaticBox(), wxID_ANY, _("Set values to 0 to use Board Setup values."), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextInfo = new wxStaticText( sbSizerLocalProperties->GetStaticBox(), wxID_ANY, _("Leave values blank to use Board Setup values."), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextInfo->Wrap( -1 ); sbSizerLocalProperties->Add( m_staticTextInfo, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); @@ -374,7 +374,7 @@ DIALOG_FOOTPRINT_PROPERTIES_BASE::DIALOG_FOOTPRINT_PROPERTIES_BASE( wxWindow* pa m_PanelClearances->SetSizer( bSizerPanelClearances ); m_PanelClearances->Layout(); bSizerPanelClearances->Fit( m_PanelClearances ); - m_NoteBook->AddPage( m_PanelClearances, _("Clearance Overrides and Settings"), false ); + m_NoteBook->AddPage( m_PanelClearances, _("Clearance Overrides and Settings"), true ); m_GeneralBoxSizer->Add( m_NoteBook, 1, wxEXPAND|wxALL, 10 ); diff --git a/pcbnew/dialogs/dialog_footprint_properties_base.fbp b/pcbnew/dialogs/dialog_footprint_properties_base.fbp index 826eaf904a..ef7c11a77c 100644 --- a/pcbnew/dialogs/dialog_footprint_properties_base.fbp +++ b/pcbnew/dialogs/dialog_footprint_properties_base.fbp @@ -124,7 +124,7 @@ General - 1 + 0 1 1 @@ -2049,7 +2049,7 @@ Clearance Overrides and Settings - 0 + 1 1 1 @@ -2150,7 +2150,7 @@ 0 0 wxID_ANY - Set values to 0 to use Board Setup values. + Leave values blank to use Board Setup values. 0 0 diff --git a/pcbnew/dialogs/dialog_footprint_properties_fp_editor.cpp b/pcbnew/dialogs/dialog_footprint_properties_fp_editor.cpp index 35c5412200..366d4e8ccd 100644 --- a/pcbnew/dialogs/dialog_footprint_properties_fp_editor.cpp +++ b/pcbnew/dialogs/dialog_footprint_properties_fp_editor.cpp @@ -4,7 +4,7 @@ * Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2015 Dick Hollenbeck, dick@softplc.com * Copyright (C) 2008 Wayne Stambaugh - * Copyright (C) 2004-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2004-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -313,13 +313,29 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataToWindow() // Local Clearances - m_netClearance.SetValue( m_footprint->GetLocalClearance() ); - m_solderMask.SetValue( m_footprint->GetLocalSolderMaskMargin() ); - m_solderPaste.SetValue( m_footprint->GetLocalSolderPasteMargin() ); - m_solderPasteRatio.SetDoubleValue( m_footprint->GetLocalSolderPasteMarginRatio() * 100.0 ); + if( m_footprint->GetLocalClearance().has_value() ) + m_netClearance.SetValue( m_footprint->GetLocalClearance().value() ); + else + m_netClearance.SetValue( wxEmptyString ); + + if( m_footprint->GetLocalSolderMaskMargin().has_value() ) + m_solderMask.SetValue( m_footprint->GetLocalSolderMaskMargin().value() ); + else + m_solderMask.SetValue( wxEmptyString ); + + if( m_footprint->GetLocalSolderPasteMargin().has_value() ) + m_solderPaste.SetValue( m_footprint->GetLocalSolderPasteMargin().value() ); + else + m_solderPaste.SetValue( wxEmptyString ); + + if( m_footprint->GetLocalSolderPasteMarginRatio().has_value() ) + m_solderPasteRatio.SetDoubleValue( m_footprint->GetLocalSolderPasteMarginRatio().value() * 100.0 ); + else + m_solderPasteRatio.SetValue( wxEmptyString ); + m_allowBridges->SetValue( m_footprint->GetAttributes() & FP_ALLOW_SOLDERMASK_BRIDGES ); - switch( m_footprint->GetZoneConnection() ) + switch( m_footprint->GetLocalZoneConnection() ) { default: case ZONE_CONNECTION::INHERITED: m_ZoneConnectionChoice->SetSelection( 0 ); break; @@ -575,19 +591,34 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataFromWindow() m_footprint->SetAttributes( attributes ); - // Initialize masks clearances - m_footprint->SetLocalClearance( m_netClearance.GetValue() ); - m_footprint->SetLocalSolderMaskMargin( m_solderMask.GetValue() ); - m_footprint->SetLocalSolderPasteMargin( m_solderPaste.GetValue() ); - m_footprint->SetLocalSolderPasteMarginRatio( m_solderPasteRatio.GetDoubleValue() / 100.0 ); + // Initialize mask clearances + if( m_netClearance.IsNull() ) + m_footprint->SetLocalClearance( {} ); + else + m_footprint->SetLocalClearance( m_netClearance.GetValue() ); + + if( m_solderMask.IsNull() ) + m_footprint->SetLocalSolderMaskMargin( {} ); + else + m_footprint->SetLocalSolderMaskMargin( m_solderMask.GetValue() ); + + if( m_solderPaste.IsNull() ) + m_footprint->SetLocalSolderPasteMargin( {} ); + else + m_footprint->SetLocalSolderPasteMargin( m_solderPaste.GetValue() ); + + if( m_solderPasteRatio.IsNull() ) + m_footprint->SetLocalSolderPasteMarginRatio( {} ); + else + m_footprint->SetLocalSolderPasteMarginRatio( m_solderPasteRatio.GetDoubleValue() / 100.0 ); switch( m_ZoneConnectionChoice->GetSelection() ) { default: - case 0: m_footprint->SetZoneConnection( ZONE_CONNECTION::INHERITED ); break; - case 1: m_footprint->SetZoneConnection( ZONE_CONNECTION::FULL ); break; - case 2: m_footprint->SetZoneConnection( ZONE_CONNECTION::THERMAL ); break; - case 3: m_footprint->SetZoneConnection( ZONE_CONNECTION::NONE ); break; + case 0: m_footprint->SetLocalZoneConnection( ZONE_CONNECTION::INHERITED ); break; + case 1: m_footprint->SetLocalZoneConnection( ZONE_CONNECTION::FULL ); break; + case 2: m_footprint->SetLocalZoneConnection( ZONE_CONNECTION::THERMAL ); break; + case 3: m_footprint->SetLocalZoneConnection( ZONE_CONNECTION::NONE ); break; } m_footprint->ClearNetTiePadGroups(); diff --git a/pcbnew/dialogs/dialog_footprint_properties_fp_editor_base.cpp b/pcbnew/dialogs/dialog_footprint_properties_fp_editor_base.cpp index c46eec410a..378e38e13a 100644 --- a/pcbnew/dialogs/dialog_footprint_properties_fp_editor_base.cpp +++ b/pcbnew/dialogs/dialog_footprint_properties_fp_editor_base.cpp @@ -234,7 +234,7 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITO wxStaticBoxSizer* sbSizerLocalProperties; sbSizerLocalProperties = new wxStaticBoxSizer( new wxStaticBox( m_PanelClearances, wxID_ANY, _("Clearances") ), wxVERTICAL ); - m_staticTextInfo = new wxStaticText( sbSizerLocalProperties->GetStaticBox(), wxID_ANY, _("Set values to 0 to use netclass values."), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextInfo = new wxStaticText( sbSizerLocalProperties->GetStaticBox(), wxID_ANY, _("Leave values blank to use netclass values."), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextInfo->Wrap( -1 ); sbSizerLocalProperties->Add( m_staticTextInfo, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); @@ -250,7 +250,7 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITO gbSizer1->Add( m_NetClearanceLabel, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 ); - m_NetClearanceCtrl = new wxTextCtrl( sbSizerLocalProperties->GetStaticBox(), wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 ); + m_NetClearanceCtrl = new wxTextCtrl( sbSizerLocalProperties->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); gbSizer1->Add( m_NetClearanceCtrl, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 ); m_NetClearanceUnits = new wxStaticText( sbSizerLocalProperties->GetStaticBox(), wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 ); diff --git a/pcbnew/dialogs/dialog_footprint_properties_fp_editor_base.fbp b/pcbnew/dialogs/dialog_footprint_properties_fp_editor_base.fbp index 29a67f6aa9..24f3cfec08 100644 --- a/pcbnew/dialogs/dialog_footprint_properties_fp_editor_base.fbp +++ b/pcbnew/dialogs/dialog_footprint_properties_fp_editor_base.fbp @@ -123,7 +123,7 @@ General - 1 + 0 1 1 @@ -1605,7 +1605,7 @@ Clearance Overrides and Settings - 0 + 1 1 1 @@ -1706,7 +1706,7 @@ 0 0 wxID_ANY - Set values to 0 to use netclass values. + Leave values blank to use netclass values. 0 0 @@ -1875,7 +1875,7 @@ wxFILTER_NONE wxDefaultValidator - 0 + diff --git a/pcbnew/dialogs/dialog_pad_properties.cpp b/pcbnew/dialogs/dialog_pad_properties.cpp index 664541639a..e5e31c06fb 100644 --- a/pcbnew/dialogs/dialog_pad_properties.cpp +++ b/pcbnew/dialogs/dialog_pad_properties.cpp @@ -4,7 +4,7 @@ * Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2013 Dick Hollenbeck, dick@softplc.com * Copyright (C) 2008-2013 Wayne Stambaugh - * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -606,13 +606,29 @@ void DIALOG_PAD_PROPERTIES::initValues() m_padToDieOpt->SetValue( m_previewPad->GetPadToDieLength() != 0 ); m_padToDie.ChangeValue( m_previewPad->GetPadToDieLength() ); - m_clearance.ChangeValue( m_previewPad->GetLocalClearance() ); - m_maskMargin.ChangeValue( m_previewPad->GetLocalSolderMaskMargin() ); + if( m_previewPad->GetLocalClearance().has_value() ) + m_clearance.ChangeValue( m_previewPad->GetLocalClearance().value() ); + else + m_clearance.ChangeValue( wxEmptyString ); + + if( m_previewPad->GetLocalSolderMaskMargin().has_value() ) + m_maskMargin.ChangeValue( m_previewPad->GetLocalSolderMaskMargin().value() ); + else + m_maskMargin.ChangeValue( wxEmptyString ); + + if( m_previewPad->GetLocalSolderPasteMargin().has_value() ) + m_pasteMargin.ChangeValue( m_previewPad->GetLocalSolderPasteMargin().value() ); + else + m_pasteMargin.ChangeValue( wxEmptyString ); + + if( m_previewPad->GetLocalSolderPasteMarginRatio().has_value() ) + m_pasteMarginRatio.ChangeDoubleValue( m_previewPad->GetLocalSolderPasteMarginRatio().value() * 100.0 ); + else + m_pasteMarginRatio.ChangeValue( wxEmptyString ); + m_spokeWidth.ChangeValue( m_previewPad->GetThermalSpokeWidth() ); m_spokeAngle.ChangeAngleValue( m_previewPad->GetThermalSpokeAngle() ); m_thermalGap.ChangeValue( m_previewPad->GetThermalGap() ); - m_pasteMargin.ChangeValue( m_previewPad->GetLocalSolderPasteMargin() ); - m_pasteMarginRatio.ChangeDoubleValue( m_previewPad->GetLocalSolderPasteMarginRatio() * 100.0 ); m_pad_orientation.ChangeAngleValue( m_previewPad->GetOrientation() ); m_cbTeardrops->SetValue( m_previewPad->GetTeardropParams().m_Enabled ); @@ -631,7 +647,7 @@ void DIALOG_PAD_PROPERTIES::initValues() else m_curvePointsCtrl->SetValue( 5 ); - switch( m_previewPad->GetZoneConnection() ) + switch( m_previewPad->GetLocalZoneConnection() ) { default: case ZONE_CONNECTION::INHERITED: m_ZoneConnectionChoice->SetSelection( 0 ); break; @@ -1269,9 +1285,11 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK() // Some pads need a negative solder mask clearance (mainly for BGA with small pads) // However the negative solder mask clearance must not create negative mask size // Therefore test for minimal acceptable negative value - if( m_previewPad->GetLocalSolderMaskMargin() < 0 ) + std::optional solderMaskMargin = m_previewPad->GetLocalSolderMaskMargin(); + + if( solderMaskMargin.has_value() && solderMaskMargin.value() < 0 ) { - int absMargin = abs( m_previewPad->GetLocalSolderMaskMargin() ); + int absMargin = abs( solderMaskMargin.value() ); if( m_previewPad->GetShape() == PAD_SHAPE::CUSTOM ) { @@ -1301,8 +1319,8 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK() // So we could ask for user to confirm the choice // For now we just check for disappearing paste wxSize paste_size; - int paste_margin = m_previewPad->GetLocalSolderPasteMargin(); - double paste_ratio = m_previewPad->GetLocalSolderPasteMarginRatio(); + int paste_margin = m_previewPad->GetLocalSolderPasteMargin().value_or( 0 ); + double paste_ratio = m_previewPad->GetLocalSolderPasteMarginRatio().value_or( 0 ); paste_size.x = pad_size.x + paste_margin + KiROUND( pad_size.x * paste_ratio ); paste_size.y = pad_size.y + paste_margin + KiROUND( pad_size.y * paste_ratio ); @@ -1590,7 +1608,7 @@ bool DIALOG_PAD_PROPERTIES::TransferDataFromWindow() m_currentPad->SetRoundRectRadiusRatio( m_masterPad->GetRoundRectRadiusRatio() ); m_currentPad->SetChamferRectRatio( m_masterPad->GetChamferRectRatio() ); m_currentPad->SetChamferPositions( m_masterPad->GetChamferPositions() ); - m_currentPad->SetZoneConnection( m_masterPad->GetZoneConnection() ); + m_currentPad->SetLocalZoneConnection( m_masterPad->GetLocalZoneConnection() ); m_currentPad->GetTeardropParams() = m_masterPad->GetTeardropParams(); @@ -1735,10 +1753,26 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( PAD* aPad ) aPad->GetTeardropParams().m_WidthtoSizeFilterRatio = m_spTeardropHDPercent->GetValue() / 100; // Read pad clearances values: - aPad->SetLocalClearance( m_clearance.GetIntValue() ); - aPad->SetLocalSolderMaskMargin( m_maskMargin.GetIntValue() ); - aPad->SetLocalSolderPasteMargin( m_pasteMargin.GetIntValue() ); - aPad->SetLocalSolderPasteMarginRatio( m_pasteMarginRatio.GetDoubleValue() / 100.0 ); + if( m_clearance.IsNull() ) + aPad->SetLocalClearance( {} ); + else + aPad->SetLocalClearance( m_clearance.GetIntValue() ); + + if( m_maskMargin.IsNull() ) + aPad->SetLocalSolderMaskMargin( {} ); + else + aPad->SetLocalSolderMaskMargin( m_maskMargin.GetIntValue() ); + + if( m_pasteMargin.IsNull() ) + aPad->SetLocalSolderPasteMargin( {} ); + else + aPad->SetLocalSolderPasteMargin( m_pasteMargin.GetIntValue() ); + + if( m_pasteMarginRatio.IsNull() ) + aPad->SetLocalSolderPasteMarginRatio( {} ); + else + aPad->SetLocalSolderPasteMarginRatio( m_pasteMarginRatio.GetDoubleValue() / 100.0 ); + aPad->SetThermalSpokeWidth( m_spokeWidth.GetIntValue() ); aPad->SetThermalSpokeAngle( m_spokeAngle.GetAngleValue() ); aPad->SetThermalGap( m_thermalGap.GetIntValue() ); @@ -1749,10 +1783,10 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( PAD* aPad ) switch( m_ZoneConnectionChoice->GetSelection() ) { default: - case 0: aPad->SetZoneConnection( ZONE_CONNECTION::INHERITED ); break; - case 1: aPad->SetZoneConnection( ZONE_CONNECTION::FULL ); break; - case 2: aPad->SetZoneConnection( ZONE_CONNECTION::THERMAL ); break; - case 3: aPad->SetZoneConnection( ZONE_CONNECTION::NONE ); break; + case 0: aPad->SetLocalZoneConnection( ZONE_CONNECTION::INHERITED ); break; + case 1: aPad->SetLocalZoneConnection( ZONE_CONNECTION::FULL ); break; + case 2: aPad->SetLocalZoneConnection( ZONE_CONNECTION::THERMAL ); break; + case 3: aPad->SetLocalZoneConnection( ZONE_CONNECTION::NONE ); break; } aPad->SetPosition( VECTOR2I( m_posX.GetIntValue(), m_posY.GetIntValue() ) ); diff --git a/pcbnew/dialogs/dialog_pad_properties_base.cpp b/pcbnew/dialogs/dialog_pad_properties_base.cpp index 04f2e225bc..b60078f908 100644 --- a/pcbnew/dialogs/dialog_pad_properties_base.cpp +++ b/pcbnew/dialogs/dialog_pad_properties_base.cpp @@ -928,7 +928,7 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind sbClearancesSizer = new wxStaticBoxSizer( new wxStaticBox( m_localSettingsPanel, wxID_ANY, _("Clearance Overrides") ), wxVERTICAL ); wxStaticText* m_staticTextHint; - m_staticTextHint = new wxStaticText( sbClearancesSizer->GetStaticBox(), wxID_ANY, _("Set values to 0 to use parent footprint or netclass values."), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextHint = new wxStaticText( sbClearancesSizer->GetStaticBox(), wxID_ANY, _("Leave values blank to use parent footprint or netclass values."), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextHint->Wrap( -1 ); sbClearancesSizer->Add( m_staticTextHint, 0, wxBOTTOM|wxLEFT|wxRIGHT, 5 ); diff --git a/pcbnew/dialogs/dialog_pad_properties_base.fbp b/pcbnew/dialogs/dialog_pad_properties_base.fbp index 196e3c2dcc..393d34c9d4 100644 --- a/pcbnew/dialogs/dialog_pad_properties_base.fbp +++ b/pcbnew/dialogs/dialog_pad_properties_base.fbp @@ -1,6 +1,6 @@ - + C++ @@ -10378,7 +10378,7 @@ 0 0 wxID_ANY - Set values to 0 to use parent footprint or netclass values. + Leave values blank to use parent footprint or netclass values. 0 0 diff --git a/pcbnew/drc/drc_engine.cpp b/pcbnew/drc/drc_engine.cpp index d33038dc57..deefe36584 100644 --- a/pcbnew/drc/drc_engine.cpp +++ b/pcbnew/drc/drc_engine.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 2004-2019 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2014 Dick Hollenbeck, dick@softplc.com - * Copyright (C) 2017-2022 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2017-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -739,39 +739,39 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO // Local overrides take precedence over everything *except* board min clearance if( aConstraintType == CLEARANCE_CONSTRAINT || aConstraintType == HOLE_CLEARANCE_CONSTRAINT ) { - int override_val = 0; - int overrideA = 0; - int overrideB = 0; + int override_val = 0; + std::optional overrideA; + std::optional overrideB; if( ac && !b_is_non_copper ) - overrideA = ac->GetLocalClearanceOverrides( nullptr ); + overrideA = ac->GetClearanceOverrides( nullptr ); if( bc && !a_is_non_copper ) - overrideB = bc->GetLocalClearanceOverrides( nullptr ); + overrideB = bc->GetClearanceOverrides( nullptr ); - if( overrideA > 0 || overrideB > 0 ) + if( overrideA.has_value() || overrideB.has_value() ) { wxString msg; - if( overrideA > 0 ) + if( overrideA.has_value() ) { REPORT( "" ) REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ), EscapeHTML( a->GetItemDescription( this ) ), - MessageTextFromValue( overrideA ) ) ) + MessageTextFromValue( overrideA.value() ) ) ) - override_val = ac->GetLocalClearanceOverrides( &msg ); + override_val = ac->GetClearanceOverrides( &msg ).value(); } - if( overrideB > 0 ) + if( overrideB.has_value() ) { REPORT( "" ) REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ), EscapeHTML( b->GetItemDescription( this ) ), - EscapeHTML( MessageTextFromValue( overrideB ) ) ) ) + EscapeHTML( MessageTextFromValue( overrideB.value() ) ) ) ) if( overrideB > override_val ) - override_val = bc->GetLocalClearanceOverrides( &msg ); + override_val = bc->GetClearanceOverrides( &msg ).value(); } if( override_val ) @@ -809,10 +809,10 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO } else if( aConstraintType == ZONE_CONNECTION_CONSTRAINT ) { - if( pad && pad->GetLocalZoneConnectionOverride( nullptr ) != ZONE_CONNECTION::INHERITED ) + if( pad && pad->GetLocalZoneConnection() != ZONE_CONNECTION::INHERITED ) { wxString msg; - ZONE_CONNECTION override = pad->GetLocalZoneConnectionOverride( &msg ); + ZONE_CONNECTION override = pad->GetZoneConnectionOverrides( &msg ); REPORT( "" ) REPORT( wxString::Format( _( "Local override on %s; zone connection: %s." ), @@ -1326,13 +1326,13 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO if( aConstraintType == CLEARANCE_CONSTRAINT ) { int global = constraint.m_Value.Min(); - int localA = ac ? ac->GetLocalClearance( nullptr ) : 0; - int localB = bc ? bc->GetLocalClearance( nullptr ) : 0; int clearance = global; bool needBlankLine = true; - if( localA > 0 ) + if( ac && ac->GetLocalClearance().has_value() ) { + int localA = ac->GetLocalClearance().value(); + if( needBlankLine ) { REPORT( "" ) @@ -1346,15 +1346,17 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO if( localA > clearance ) { wxString msg; - clearance = ac->GetLocalClearance( &msg ); + clearance = ac->GetLocalClearance( &msg ).value(); constraint.SetParentRule( nullptr ); constraint.SetName( msg ); constraint.m_Value.SetMin( clearance ); } } - if( localB > 0 ) + if( bc && bc->GetLocalClearance().has_value() ) { + int localB = bc->GetLocalClearance().value(); + if( needBlankLine ) { REPORT( "" ) @@ -1368,7 +1370,7 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO if( localB > clearance ) { wxString msg; - clearance = bc->GetLocalClearance( &msg ); + clearance = bc->GetLocalClearance( &msg ).value(); constraint.SetParentRule( nullptr ); constraint.SetName( msg ); constraint.m_Value.SetMin( clearance ); @@ -1415,7 +1417,7 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO { if( pad && parentFootprint ) { - ZONE_CONNECTION local = parentFootprint->GetZoneConnection(); + ZONE_CONNECTION local = parentFootprint->GetLocalZoneConnection(); if( local != ZONE_CONNECTION::INHERITED ) { diff --git a/pcbnew/drc/drc_test_provider_library_parity.cpp b/pcbnew/drc/drc_test_provider_library_parity.cpp index 177c6385fc..867d1bc685 100644 --- a/pcbnew/drc/drc_test_provider_library_parity.cpp +++ b/pcbnew/drc/drc_test_provider_library_parity.cpp @@ -192,29 +192,70 @@ bool primitiveNeedsUpdate( const std::shared_ptr& a, } -bool padHasOverrides( const PAD* a, const PAD* b, REPORTER* aReporter ) +bool padHasOverrides( const PAD* a, const PAD* b, REPORTER& aReporter ) { bool diff = false; - TEST( a->GetLocalClearance(), b->GetLocalClearance(), - wxString::Format( _( "%s has clearance override." ), PAD_DESC( a ) ) ); - TEST( a->GetLocalSolderMaskMargin(), b->GetLocalSolderMaskMargin(), - wxString::Format( _( "%s has solder mask expansion override." ), PAD_DESC( a ) ) ); - TEST( a->GetLocalSolderPasteMargin(), b->GetLocalSolderPasteMargin(), - wxString::Format( _( "%s has solder paste clearance override." ), PAD_DESC( a ) ) ); - TEST_D( a->GetLocalSolderPasteMarginRatio(), b->GetLocalSolderPasteMarginRatio(), - wxString::Format( _( "%s has solder paste clearance override." ), PAD_DESC( a ) ) ); +#define REPORT_MSG( s, p ) aReporter.Report( wxString::Format( s, p ) ) - TEST( a->GetZoneConnection(), b->GetZoneConnection(), - wxString::Format( _( "%s has zone connection override." ), PAD_DESC( a ) ) ); - TEST( a->GetThermalGap(), b->GetThermalGap(), - wxString::Format( _( "%s has thermal relief gap override." ), PAD_DESC( a ) ) ); - TEST( a->GetThermalSpokeWidth(), b->GetThermalSpokeWidth(), - wxString::Format( _( "%s has thermal relief spoke width override." ), PAD_DESC( a ) ) ); - TEST_D( a->GetThermalSpokeAngle().AsDegrees(), b->GetThermalSpokeAngle().AsDegrees(), - wxString::Format( _( "%s has thermal relief spoke angle override." ), PAD_DESC( a ) ) ); - TEST( a->GetCustomShapeInZoneOpt(), b->GetCustomShapeInZoneOpt(), - wxString::Format( _( "%s has zone knockout setting override." ), PAD_DESC( a ) ) ); + if( a->GetLocalClearance().has_value() && a->GetLocalClearance() != b->GetLocalClearance() ) + { + diff = true; + REPORT_MSG( _( "%s has clearance override." ), PAD_DESC( a ) ); + } + + if( a->GetLocalSolderMaskMargin().has_value() + && a->GetLocalSolderMaskMargin() != b->GetLocalSolderMaskMargin() ) + { + diff = true; + REPORT_MSG( _( "%s has solder mask expansion override." ), PAD_DESC( a ) ); + } + + + if( a->GetLocalSolderPasteMargin().has_value() + && a->GetLocalSolderPasteMargin() != b->GetLocalSolderPasteMargin() ) + { + diff = true; + REPORT_MSG( _( "%s has solder paste clearance override." ), PAD_DESC( a ) ); + } + + if( a->GetLocalSolderPasteMarginRatio() + && a->GetLocalSolderPasteMarginRatio() != b->GetLocalSolderPasteMarginRatio() ) + { + diff = true; + REPORT_MSG( _( "%s has solder paste clearance override." ), PAD_DESC( a ) ); + } + + if( a->GetLocalZoneConnection() != ZONE_CONNECTION::INHERITED + && a->GetLocalZoneConnection() != b->GetLocalZoneConnection() ) + { + diff = true; + REPORT_MSG( _( "%s has zone connection override." ), PAD_DESC( a ) ); + } + + if( a->GetThermalGap() != b->GetThermalGap() ) + { + diff = true; + REPORT_MSG( _( "%s has thermal relief gap override." ), PAD_DESC( a ) ); + } + + if( a->GetThermalSpokeWidth() != b->GetThermalSpokeWidth() ) + { + diff = true; + REPORT_MSG( _( "%s has thermal relief spoke width override." ), PAD_DESC( a ) ); + } + + if( a->GetThermalSpokeAngle() != b->GetThermalSpokeAngle() ) + { + diff = true; + REPORT_MSG( _( "%s has thermal relief spoke angle override." ), PAD_DESC( a ) ); + } + + if( a->GetCustomShapeInZoneOpt() != b->GetCustomShapeInZoneOpt() ) + { + diff = true; + REPORT_MSG( _( "%s has zone knockout setting override." ), PAD_DESC( a ) ); + } return diff; } @@ -315,7 +356,7 @@ bool padNeedsUpdate( const PAD* a, const PAD* b, REPORTER* aReporter ) // going to be VERY noisy. // // So we just do it when we have a reporter. - if( aReporter && padHasOverrides( a, b, aReporter ) ) + if( aReporter && padHasOverrides( a, b, *aReporter ) ) diff = true; bool primitivesDiffer = false; @@ -594,17 +635,40 @@ bool FOOTPRINT::FootprintNeedsUpdate( const FOOTPRINT* aLibFP, REPORTER* aReport // For now we report them if there's a reporter, but we DON'T generate DRC errors on them. if( aReporter ) { - TEST( GetLocalClearance(), aLibFP->GetLocalClearance(), - _( "Pad clearance overridden." ) ); - TEST( GetLocalSolderMaskMargin(), aLibFP->GetLocalSolderMaskMargin(), - _( "Solder mask expansion overridden." ) ); - TEST( GetLocalSolderPasteMargin(), aLibFP->GetLocalSolderPasteMargin(), - _( "Solder paste absolute clearance overridden." ) ); - TEST_D( GetLocalSolderPasteMarginRatio(), aLibFP->GetLocalSolderPasteMarginRatio(), - _( "Solder paste relative clearance overridden." ) ); + if( GetLocalClearance().has_value() && GetLocalClearance() != aLibFP->GetLocalClearance() ) + { + diff = true; + aReporter->Report( _( "Pad clearance overridden." ) ); + } - TEST( GetZoneConnection(), aLibFP->GetZoneConnection(), - _( "Zone connection overridden." ) ); + if( GetLocalSolderMaskMargin().has_value() + && GetLocalSolderMaskMargin() != aLibFP->GetLocalSolderMaskMargin() ) + { + diff = true; + aReporter->Report( _( "Solder mask expansion overridden." ) ); + } + + + if( GetLocalSolderPasteMargin().has_value() + && GetLocalSolderPasteMargin() != aLibFP->GetLocalSolderPasteMargin() ) + { + diff = true; + aReporter->Report( _( "Solder paste absolute clearance overridden." ) ); + } + + if( GetLocalSolderPasteMarginRatio() + && GetLocalSolderPasteMarginRatio() != aLibFP->GetLocalSolderPasteMarginRatio() ) + { + diff = true; + aReporter->Report( _( "\"Solder paste relative clearance overridden." ) ); + } + + if( GetLocalZoneConnection() != ZONE_CONNECTION::INHERITED + && GetLocalZoneConnection() != aLibFP->GetLocalZoneConnection() ) + { + diff = true; + aReporter->Report( _( "Zone connection overridden." ) ); + } } TEST( GetNetTiePadGroups().size(), aLibFP->GetNetTiePadGroups().size(), @@ -698,7 +762,7 @@ bool FOOTPRINT::FootprintNeedsUpdate( const FOOTPRINT* aLibFP, REPORTER* aReport { if( padNeedsUpdate( *aIt, *bIt, aReporter ) ) diff = true; - else if( aReporter && padHasOverrides( *aIt, *bIt, aReporter ) ) + else if( aReporter && padHasOverrides( *aIt, *bIt, *aReporter ) ) diff = true; } } diff --git a/pcbnew/footprint.cpp b/pcbnew/footprint.cpp index cdb280d1a9..f80d20713d 100644 --- a/pcbnew/footprint.cpp +++ b/pcbnew/footprint.cpp @@ -4,7 +4,7 @@ * Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2015 Wayne Stambaugh - * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -70,12 +70,8 @@ FOOTPRINT::FOOTPRINT( BOARD* parent ) : m_arflag = 0; m_link = 0; m_lastEditTime = 0; - m_localClearance = 0; - m_localSolderMaskMargin = 0; - m_localSolderPasteMargin = 0; - m_localSolderPasteMarginRatio = 0.0; - m_zoneConnection = ZONE_CONNECTION::INHERITED; - m_fileFormatVersionAtLoad = 0; + m_zoneConnection = ZONE_CONNECTION::INHERITED; + m_fileFormatVersionAtLoad = 0; // These are the mandatory fields for the editor to work for( int i = 0; i < MANDATORY_FIELDS; i++ ) @@ -125,10 +121,10 @@ FOOTPRINT::FOOTPRINT( const FOOTPRINT& aFootprint ) : m_cachedHull = aFootprint.m_cachedHull; m_hullCacheTimeStamp = aFootprint.m_hullCacheTimeStamp; - m_localClearance = aFootprint.m_localClearance; - m_localSolderMaskMargin = aFootprint.m_localSolderMaskMargin; - m_localSolderPasteMargin = aFootprint.m_localSolderPasteMargin; - m_localSolderPasteMarginRatio = aFootprint.m_localSolderPasteMarginRatio; + m_clearance = aFootprint.m_clearance; + m_solderMaskMargin = aFootprint.m_solderMaskMargin; + m_solderPasteMargin = aFootprint.m_solderPasteMargin; + m_solderPasteMarginRatio = aFootprint.m_solderPasteMarginRatio; m_zoneConnection = aFootprint.m_zoneConnection; m_netTiePadGroups = aFootprint.m_netTiePadGroups; m_fileFormatVersionAtLoad = aFootprint.m_fileFormatVersionAtLoad; @@ -448,10 +444,10 @@ FOOTPRINT& FOOTPRINT::operator=( FOOTPRINT&& aOther ) m_cachedHull = aOther.m_cachedHull; m_hullCacheTimeStamp = aOther.m_hullCacheTimeStamp; - m_localClearance = aOther.m_localClearance; - m_localSolderMaskMargin = aOther.m_localSolderMaskMargin; - m_localSolderPasteMargin = aOther.m_localSolderPasteMargin; - m_localSolderPasteMarginRatio = aOther.m_localSolderPasteMarginRatio; + m_clearance = aOther.m_clearance; + m_solderMaskMargin = aOther.m_solderMaskMargin; + m_solderPasteMargin = aOther.m_solderPasteMargin; + m_solderPasteMarginRatio = aOther.m_solderPasteMarginRatio; m_zoneConnection = aOther.m_zoneConnection; m_netTiePadGroups = aOther.m_netTiePadGroups; @@ -542,10 +538,10 @@ FOOTPRINT& FOOTPRINT::operator=( const FOOTPRINT& aOther ) m_cachedHull = aOther.m_cachedHull; m_hullCacheTimeStamp = aOther.m_hullCacheTimeStamp; - m_localClearance = aOther.m_localClearance; - m_localSolderMaskMargin = aOther.m_localSolderMaskMargin; - m_localSolderPasteMargin = aOther.m_localSolderPasteMargin; - m_localSolderPasteMarginRatio = aOther.m_localSolderPasteMarginRatio; + m_clearance = aOther.m_clearance; + m_solderMaskMargin = aOther.m_solderMaskMargin; + m_solderPasteMargin = aOther.m_solderPasteMargin; + m_solderPasteMarginRatio = aOther.m_solderPasteMarginRatio; m_zoneConnection = aOther.m_zoneConnection; m_netTiePadGroups = aOther.m_netTiePadGroups; @@ -3528,22 +3524,25 @@ static struct FOOTPRINT_DESC _HKI( "Exempt From Courtyard Requirement" ), &FOOTPRINT::SetAllowMissingCourtyard, &FOOTPRINT::AllowMissingCourtyard ), groupOverrides ); - propMgr.AddProperty( new PROPERTY( _HKI( "Clearance Override" ), + propMgr.AddProperty( new PROPERTY>( + _HKI( "Clearance Override" ), &FOOTPRINT::SetLocalClearance, &FOOTPRINT::GetLocalClearance, PROPERTY_DISPLAY::PT_SIZE ), groupOverrides ); - propMgr.AddProperty( new PROPERTY( _HKI( "Solderpaste Margin Override" ), + propMgr.AddProperty( new PROPERTY>( + _HKI( "Solderpaste Margin Override" ), &FOOTPRINT::SetLocalSolderPasteMargin, &FOOTPRINT::GetLocalSolderPasteMargin, PROPERTY_DISPLAY::PT_SIZE ), groupOverrides ); - propMgr.AddProperty( new PROPERTY( + propMgr.AddProperty( new PROPERTY>( _HKI( "Solderpaste Margin Ratio Override" ), &FOOTPRINT::SetLocalSolderPasteMarginRatio, - &FOOTPRINT::GetLocalSolderPasteMarginRatio ), + &FOOTPRINT::GetLocalSolderPasteMarginRatio, + PROPERTY_DISPLAY::PT_RATIO ), groupOverrides ); propMgr.AddProperty( new PROPERTY_ENUM( _HKI( "Zone Connection Style" ), - &FOOTPRINT::SetZoneConnection, &FOOTPRINT::GetZoneConnection ), + &FOOTPRINT::SetLocalZoneConnection, &FOOTPRINT::GetLocalZoneConnection ), groupOverrides ); } } _FOOTPRINT_DESC; diff --git a/pcbnew/footprint.h b/pcbnew/footprint.h index 6bbaeb8547..3dd8807cc3 100644 --- a/pcbnew/footprint.h +++ b/pcbnew/footprint.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -251,28 +251,20 @@ public: wxString GetFilters() const { return m_filters; } void SetFilters( const wxString& aFilters ) { m_filters = aFilters; } - int GetLocalSolderMaskMargin() const { return m_localSolderMaskMargin; } - void SetLocalSolderMaskMargin( int aMargin ) { m_localSolderMaskMargin = aMargin; } + std::optional GetLocalClearance() const { return m_clearance; } + void SetLocalClearance( std::optional aClearance ) { m_clearance = aClearance; } - int GetLocalClearance() const { return m_localClearance; } - void SetLocalClearance( int aClearance ) { m_localClearance = aClearance; } + std::optional GetLocalSolderMaskMargin() const { return m_solderMaskMargin; } + void SetLocalSolderMaskMargin( std::optional aMargin ) { m_solderMaskMargin = aMargin; } - int GetLocalClearance( wxString* aSource ) const - { - if( aSource ) - *aSource = wxString::Format( _( "footprint %s" ), GetReference() ); + std::optional GetLocalSolderPasteMargin() const { return m_solderPasteMargin; } + void SetLocalSolderPasteMargin( std::optional aMargin ) { m_solderPasteMargin = aMargin; } - return m_localClearance; - } + std::optional GetLocalSolderPasteMarginRatio() const { return m_solderPasteMarginRatio; } + void SetLocalSolderPasteMarginRatio( std::optional aRatio ) { m_solderPasteMarginRatio = aRatio; } - int GetLocalSolderPasteMargin() const { return m_localSolderPasteMargin; } - void SetLocalSolderPasteMargin( int aMargin ) { m_localSolderPasteMargin = aMargin; } - - double GetLocalSolderPasteMarginRatio() const { return m_localSolderPasteMarginRatio; } - void SetLocalSolderPasteMarginRatio( double aRatio ) { m_localSolderPasteMarginRatio = aRatio; } - - void SetZoneConnection( ZONE_CONNECTION aType ) { m_zoneConnection = aType; } - ZONE_CONNECTION GetZoneConnection() const { return m_zoneConnection; } + void SetLocalZoneConnection( ZONE_CONNECTION aType ) { m_zoneConnection = aType; } + ZONE_CONNECTION GetLocalZoneConnection() const { return m_zoneConnection; } int GetAttributes() const { return m_attributes; } void SetAttributes( int aAttributes ) { m_attributes = aAttributes; } @@ -292,6 +284,33 @@ public: return false; } + std::optional GetLocalClearance( wxString* aSource ) const + { + if( m_clearance.has_value() && aSource ) + *aSource = wxString::Format( _( "footprint %s" ), GetReference() ); + + return m_clearance; + } + + /** + * Return any local clearance overrides set in the "classic" (ie: pre-rule) system. + * + * @param aSource [out] optionally reports the source as a user-readable string. + * @return the clearance in internal units. + */ + std::optional GetClearanceOverrides( wxString* aSource ) const + { + return GetLocalClearance( aSource ); + } + + ZONE_CONNECTION GetZoneConnectionOverrides( wxString* aSource ) const + { + if( m_zoneConnection != ZONE_CONNECTION::INHERITED && aSource ) + *aSource = wxString::Format( _( "footprint %s" ), GetReference() ); + + return m_zoneConnection; + } + /** * @return a list of pad groups, each of which is allowed to short nets within their group. * A pad group is a comma-separated list of pad numbers. @@ -991,11 +1010,13 @@ private: // A pad group is a comma-separated list of pad numbers. std::vector m_netTiePadGroups; - ZONE_CONNECTION m_zoneConnection; - int m_localClearance; - int m_localSolderMaskMargin; // Solder mask margin - int m_localSolderPasteMargin; // Solder paste margin absolute value - double m_localSolderPasteMarginRatio; // Solder mask margin ratio value of pad size + // Optional overrides + ZONE_CONNECTION m_zoneConnection; + std::optional m_clearance; + std::optional m_solderMaskMargin; // Solder mask margin + std::optional m_solderPasteMargin; // Solder paste margin absolute value + std::optional m_solderPasteMarginRatio; // Solder mask margin ratio of pad size + // The final margin is the sum of these 2 values wxString m_libDescription; // File name and path for documentation file. wxString m_keywords; // Search keywords to find footprint in library. diff --git a/pcbnew/pad.cpp b/pcbnew/pad.cpp index c6719bd41e..399fab6118 100644 --- a/pcbnew/pad.cpp +++ b/pcbnew/pad.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck - * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -77,10 +77,6 @@ PAD::PAD( FOOTPRINT* parent ) : SetDrillShape( PAD_DRILL_SHAPE_CIRCLE ); // Default pad drill shape is a circle. m_attribute = PAD_ATTRIB::PTH; // Default pad type is plated through hole SetProperty( PAD_PROP::NONE ); // no special fabrication property - m_localClearance = 0; - m_localSolderMaskMargin = 0; - m_localSolderPasteMargin = 0; - m_localSolderPasteMarginRatio = 0.0; // Parameters for round rect only: m_roundedCornerScale = 0.25; // from IPC-7351C standard @@ -805,26 +801,24 @@ bool PAD::IsOnCopperLayer() const } -int PAD::GetLocalClearanceOverrides( wxString* aSource ) const +std::optional PAD::GetLocalClearance( wxString* aSource ) const { - // A pad can have specific clearance that overrides its NETCLASS clearance value - if( GetLocalClearance() ) - return GetLocalClearance( aSource ); + if( m_clearance.has_value() && aSource ) + *aSource = _( "pad" ); - // A footprint can have a specific clearance value - if( GetParentFootprint() && GetParentFootprint()->GetLocalClearance() ) - return GetParentFootprint()->GetLocalClearance( aSource ); - - return 0; + return m_clearance; } -int PAD::GetLocalClearance( wxString* aSource ) const +std::optional PAD::GetClearanceOverrides( wxString* aSource ) const { - if( aSource ) - *aSource = _( "pad" ); + if( m_clearance.has_value() ) + return GetLocalClearance( aSource ); - return m_localClearance; + if( FOOTPRINT* parentFootprint = GetParentFootprint() ) + return parentFootprint->GetClearanceOverrides( aSource ); + + return std::optional(); } @@ -862,35 +856,32 @@ int PAD::GetSolderMaskExpansion() const if( ( m_layerMask & LSET::AllCuMask() ).none() ) return 0; - int margin = m_localSolderMaskMargin; + std::optional margin = m_solderMaskMargin; - if( FOOTPRINT* parentFootprint = GetParentFootprint() ) + if( !margin.has_value() ) { - if( margin == 0 ) - { - if( parentFootprint->GetLocalSolderMaskMargin() ) - margin = parentFootprint->GetLocalSolderMaskMargin(); - } - - if( margin == 0 ) - { - const BOARD* brd = GetBoard(); - - if( brd ) - margin = brd->GetDesignSettings().m_SolderMaskExpansion; - } + if( FOOTPRINT* parentFootprint = GetParentFootprint() ) + margin = parentFootprint->GetLocalSolderMaskMargin(); } + if( !margin.has_value() ) + { + if( const BOARD* brd = GetBoard() ) + margin = brd->GetDesignSettings().m_SolderMaskExpansion; + } + + int marginValue = margin.value_or( 0 ); + // ensure mask have a size always >= 0 - if( margin < 0 ) + if( marginValue < 0 ) { int minsize = -std::min( m_size.x, m_size.y ) / 2; - if( margin < minsize ) - margin = minsize; + if( marginValue < minsize ) + marginValue = minsize; } - return margin; + return marginValue; } @@ -902,31 +893,36 @@ VECTOR2I PAD::GetSolderPasteMargin() const if( ( m_layerMask & LSET::AllCuMask() ).none() ) return VECTOR2I( 0, 0 ); - int margin = m_localSolderPasteMargin; - double mratio = m_localSolderPasteMarginRatio; + std::optional margin = m_solderPasteMargin; + std::optional mratio = m_solderPasteMarginRatio; - if( FOOTPRINT* parentFootprint = GetParentFootprint() ) + if( !margin.has_value() ) { - if( margin == 0 ) + if( FOOTPRINT* parentFootprint = GetParentFootprint() ) margin = parentFootprint->GetLocalSolderPasteMargin(); + } - auto brd = GetBoard(); + if( !margin.has_value() ) + { + if( const BOARD* board = GetBoard() ) + margin = board->GetDesignSettings().m_SolderPasteMargin; + } - if( margin == 0 && brd ) - margin = brd->GetDesignSettings().m_SolderPasteMargin; - - if( mratio == 0.0 ) + if( !mratio.has_value() ) + { + if( FOOTPRINT* parentFootprint = GetParentFootprint() ) mratio = parentFootprint->GetLocalSolderPasteMarginRatio(); + } - if( mratio == 0.0 && brd ) - { - mratio = brd->GetDesignSettings().m_SolderPasteMarginRatio; - } + if( !mratio.has_value() ) + { + if( const BOARD* board = GetBoard() ) + mratio = board->GetDesignSettings().m_SolderPasteMarginRatio; } VECTOR2I pad_margin; - pad_margin.x = margin + KiROUND( m_size.x * mratio ); - pad_margin.y = margin + KiROUND( m_size.y * mratio ); + pad_margin.x = margin.value_or( 0 ) + KiROUND( m_size.x * mratio.value_or( 0 ) ); + pad_margin.y = margin.value_or( 0 ) + KiROUND( m_size.y * mratio.value_or( 0 ) ); // ensure mask have a size always >= 0 if( m_padShape != PAD_SHAPE::CUSTOM ) @@ -942,12 +938,23 @@ VECTOR2I PAD::GetSolderPasteMargin() const } -ZONE_CONNECTION PAD::GetLocalZoneConnectionOverride( wxString* aSource ) const +ZONE_CONNECTION PAD::GetZoneConnectionOverrides( wxString* aSource ) const { - if( m_zoneConnection != ZONE_CONNECTION::INHERITED && aSource ) - *aSource = _( "pad" ); + ZONE_CONNECTION connection = m_zoneConnection; - return m_zoneConnection; + if( connection != ZONE_CONNECTION::INHERITED ) + { + if( aSource ) + *aSource = _( "pad" ); + } + + if( connection == ZONE_CONNECTION::INHERITED ) + { + if( FOOTPRINT* parentFootprint = GetParentFootprint() ) + connection = parentFootprint->GetZoneConnectionOverrides( aSource ); + } + + return connection; } @@ -1544,7 +1551,7 @@ void PAD::ImportSettingsFrom( const PAD& aMasterPad ) SetLocalSolderPasteMargin( aMasterPad.GetLocalSolderPasteMargin() ); SetLocalSolderPasteMarginRatio( aMasterPad.GetLocalSolderPasteMarginRatio() ); - SetZoneConnection( aMasterPad.GetZoneConnection() ); + SetLocalZoneConnection( aMasterPad.GetLocalZoneConnection() ); SetThermalSpokeWidth( aMasterPad.GetThermalSpokeWidth() ); SetThermalSpokeAngle( aMasterPad.GetThermalSpokeAngle() ); SetThermalGap( aMasterPad.GetThermalGap() ); @@ -1733,7 +1740,7 @@ bool PAD::operator==( const BOARD_ITEM& aOther ) const if( GetOrientation() != other.GetOrientation() ) return false; - if( GetZoneConnection() != other.GetZoneConnection() ) + if( GetLocalZoneConnection() != other.GetLocalZoneConnection() ) return false; if( GetThermalSpokeWidth() != other.GetThermalSpokeWidth() ) @@ -1827,7 +1834,7 @@ double PAD::Similarity( const BOARD_ITEM& aOther ) const if( GetOrientation() != other.GetOrientation() ) similarity *= 0.9; - if( GetZoneConnection() != other.GetZoneConnection() ) + if( GetLocalZoneConnection() != other.GetLocalZoneConnection() ) similarity *= 0.9; if( GetThermalSpokeWidth() != other.GetThermalSpokeWidth() ) @@ -2019,25 +2026,30 @@ static struct PAD_DESC const wxString groupOverrides = _HKI( "Overrides" ); - propMgr.AddProperty( new PROPERTY( _HKI( "Clearance Override" ), + propMgr.AddProperty( new PROPERTY>( + _HKI( "Clearance Override" ), &PAD::SetLocalClearance, &PAD::GetLocalClearance, PROPERTY_DISPLAY::PT_SIZE ), groupOverrides ); - propMgr.AddProperty( new PROPERTY( _HKI( "Soldermask Margin Override" ), + propMgr.AddProperty( new PROPERTY>( + _HKI( "Soldermask Margin Override" ), &PAD::SetLocalSolderMaskMargin, &PAD::GetLocalSolderMaskMargin, PROPERTY_DISPLAY::PT_SIZE ), groupOverrides ); - propMgr.AddProperty( new PROPERTY( _HKI( "Solderpaste Margin Override" ), + propMgr.AddProperty( new PROPERTY>( + _HKI( "Solderpaste Margin Override" ), &PAD::SetLocalSolderPasteMargin, &PAD::GetLocalSolderPasteMargin, PROPERTY_DISPLAY::PT_SIZE ), groupOverrides ); - propMgr.AddProperty( new PROPERTY( _HKI( "Solderpaste Margin Ratio Override" ), - &PAD::SetLocalSolderPasteMarginRatio, &PAD::GetLocalSolderPasteMarginRatio ), + propMgr.AddProperty( new PROPERTY>( + _HKI( "Solderpaste Margin Ratio Override" ), + &PAD::SetLocalSolderPasteMarginRatio, &PAD::GetLocalSolderPasteMarginRatio, + PROPERTY_DISPLAY::PT_RATIO ), groupOverrides ); propMgr.AddProperty( new PROPERTY_ENUM( _HKI( "Zone Connection Style" ), - &PAD::SetZoneConnection, &PAD::GetZoneConnection ), groupOverrides ); + &PAD::SetLocalZoneConnection, &PAD::GetLocalZoneConnection ), groupOverrides ); constexpr int minZoneWidth = pcbIUScale.mmToIU( ZONE_THICKNESS_MIN_VALUE_MM ); diff --git a/pcbnew/pad.h b/pcbnew/pad.h index 989517ecb2..9377082301 100644 --- a/pcbnew/pad.h +++ b/pcbnew/pad.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -374,7 +374,7 @@ public: PAD_ATTRIB GetAttribute() const { return m_attribute; } void SetProperty( PAD_PROP aProperty ); - PAD_PROP GetProperty() const { return m_property; } + PAD_PROP GetProperty() const { return m_property; } // We don't currently have an attribute for APERTURE, and adding one will change the file // format, so for now just infer a copper-less pad to be an APERTURE pad. @@ -386,19 +386,28 @@ public: void SetPadToDieLength( int aLength ) { m_lengthPadToDie = aLength; } int GetPadToDieLength() const { return m_lengthPadToDie; } - int GetLocalSolderMaskMargin() const { return m_localSolderMaskMargin; } - void SetLocalSolderMaskMargin( int aMargin ) { m_localSolderMaskMargin = aMargin; } + std::optional GetLocalClearance() const override { return m_clearance; } + void SetLocalClearance( std::optional aClearance ) { m_clearance = aClearance; } - int GetLocalClearance( wxString* aSource ) const override; - int GetLocalClearance() const { return m_localClearance; } - void SetLocalClearance( int aClearance ) { m_localClearance = aClearance; } + std::optional GetLocalSolderMaskMargin() const { return m_solderMaskMargin; } + void SetLocalSolderMaskMargin( std::optional aMargin ) { m_solderMaskMargin = aMargin; } - int GetLocalSolderPasteMargin() const { return m_localSolderPasteMargin; } - void SetLocalSolderPasteMargin( int aMargin ) { m_localSolderPasteMargin = aMargin; } + std::optional GetLocalSolderPasteMargin() const { return m_solderPasteMargin; } + void SetLocalSolderPasteMargin( std::optional aMargin ) { m_solderPasteMargin = aMargin; } - double GetLocalSolderPasteMarginRatio() const { return m_localSolderPasteMarginRatio; } - void SetLocalSolderPasteMarginRatio( double aRatio ) { m_localSolderPasteMarginRatio = aRatio; } + std::optional GetLocalSolderPasteMarginRatio() const { return m_solderPasteMarginRatio; } + void SetLocalSolderPasteMarginRatio( std::optional aRatio ) { m_solderPasteMarginRatio = aRatio; } + void SetLocalZoneConnection( ZONE_CONNECTION aType ) { m_zoneConnection = aType; } + ZONE_CONNECTION GetLocalZoneConnection() const { return m_zoneConnection; } + + /** + * Return the pad's "own" clearance in internal units. + * + * @param aLayer the layer in question. + * @param aSource [out] optionally reports the source as a user-readable string. + * @return the clearance in internal units. + */ int GetOwnClearance( PCB_LAYER_ID aLayer, wxString* aSource = nullptr ) const override; /** @@ -465,7 +474,15 @@ public: * @param aSource [out] optionally reports the source as a user-readable string. * @return the clearance in internal units. */ - int GetLocalClearanceOverrides( wxString* aSource ) const override; + std::optional GetLocalClearance( wxString* aSource ) const override; + + /** + * Return any clearance overrides set in the "classic" (ie: pre-rule) system. + * + * @param aSource [out] optionally reports the source as a user-readable string. + * @return the clearance in internal units. + */ + std::optional GetClearanceOverrides( wxString* aSource ) const override; /** * @return the expansion for the solder mask layer @@ -492,10 +509,7 @@ public: */ VECTOR2I GetSolderPasteMargin() const; - void SetZoneConnection( ZONE_CONNECTION aType ) { m_zoneConnection = aType; } - ZONE_CONNECTION GetZoneConnection() const { return m_zoneConnection; } - - ZONE_CONNECTION GetLocalZoneConnectionOverride( wxString* aSource = nullptr ) const; + ZONE_CONNECTION GetZoneConnectionOverrides( wxString* aSource = nullptr ) const; /** * Set the width of the thermal spokes connecting the pad to a zone. If != 0 this will @@ -821,13 +835,13 @@ private: * LEVEL 2: Rules * LEVEL 3: Accumulated local settings, netclass settings, & board design settings * - * These are the LEVEL 1 settings for a pad. + * These are the LEVEL 1 settings (overrides) for a pad. */ - int m_localClearance; - int m_localSolderMaskMargin; // Local solder mask margin - int m_localSolderPasteMargin; // Local solder paste margin absolute value - double m_localSolderPasteMarginRatio; // Local solder mask margin ratio of pad size - // The final margin is the sum of these 2 values + std::optional m_clearance; + std::optional m_solderMaskMargin; // Solder mask margin + std::optional m_solderPasteMargin; // Solder paste margin absolute value + std::optional m_solderPasteMarginRatio; // Solder mask margin ratio of pad size + // The final margin is the sum of these 2 values /* * How to build the custom shape in zone, to create the clearance area: diff --git a/pcbnew/pcb_io/cadstar/cadstar_pcb_archive_loader.cpp b/pcbnew/pcb_io/cadstar/cadstar_pcb_archive_loader.cpp index 51736db42a..c5872f0165 100644 --- a/pcbnew/pcb_io/cadstar/cadstar_pcb_archive_loader.cpp +++ b/pcbnew/pcb_io/cadstar/cadstar_pcb_archive_loader.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2020-2021 Roberto Fernandez Bautista - * Copyright (C) 2020-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2020-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -1062,12 +1062,20 @@ PAD* CADSTAR_PCB_ARCHIVE_LOADER::getKiCadPad( const COMPONENT_PAD& aCadstarPad, if( kiLayer == F_Mask || kiLayer == B_Mask ) { - if( std::abs( pad->GetLocalSolderMaskMargin() ) < std::abs( newMargin ) ) + std::optional localMargin = pad->GetLocalSolderMaskMargin(); + + if( !localMargin.has_value() ) + pad->SetLocalSolderMaskMargin( newMargin ); + else if( std::abs( localMargin.value() ) < std::abs( newMargin ) ) pad->SetLocalSolderMaskMargin( newMargin ); } else if( kiLayer == F_Paste || kiLayer == B_Paste ) { - if( std::abs( pad->GetLocalSolderPasteMargin() ) < std::abs( newMargin ) ) + std::optional localMargin = pad->GetLocalSolderPasteMargin(); + + if( !localMargin.has_value() ) + pad->SetLocalSolderPasteMargin( newMargin ); + else if( std::abs( localMargin.value() ) < std::abs( newMargin ) ) pad->SetLocalSolderPasteMargin( newMargin ); } else @@ -3748,7 +3756,8 @@ bool CADSTAR_PCB_ARCHIVE_LOADER::calculateZonePriorities( PCB_LAYER_ID& aLayer ) int extra = getKiCadLength( Assignments.Codedefs.SpacingCodes.at( wxT( "C_C" ) ).Spacing ) - m_board->GetDesignSettings().m_MinClearance; - int retval = std::max( aZoneA->GetLocalClearance(), aZoneB->GetLocalClearance() ); + int retval = std::max( aZoneA->GetLocalClearance().value(), + aZoneB->GetLocalClearance().value() ); retval += extra; diff --git a/pcbnew/pcb_io/eagle/pcb_io_eagle.cpp b/pcbnew/pcb_io/eagle/pcb_io_eagle.cpp index 06b2f15cc2..f8d89e84f4 100644 --- a/pcbnew/pcb_io/eagle/pcb_io_eagle.cpp +++ b/pcbnew/pcb_io/eagle/pcb_io_eagle.cpp @@ -2512,7 +2512,7 @@ void PCB_IO_EAGLE::transferPad( const EPAD_COMMON& aEaglePad, PAD* aPad ) const // Solid connection to copper zones if( aEaglePad.thermals && !*aEaglePad.thermals ) - aPad->SetZoneConnection( ZONE_CONNECTION::FULL ); + aPad->SetLocalZoneConnection( ZONE_CONNECTION::FULL ); FOOTPRINT* footprint = aPad->GetParentFootprint(); wxCHECK( footprint, /* void */ ); diff --git a/pcbnew/pcb_io/easyeda/pcb_io_easyeda_parser.cpp b/pcbnew/pcb_io/easyeda/pcb_io_easyeda_parser.cpp index 1bd49c5d43..f62263f6db 100644 --- a/pcbnew/pcb_io/easyeda/pcb_io_easyeda_parser.cpp +++ b/pcbnew/pcb_io/easyeda/pcb_io_easyeda_parser.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2023 Alex Shvartzkop - * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2023-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -532,11 +532,12 @@ void PCB_IO_EASYEDA_PARSER::ParseToBoardItemContainer( zone->SetLayer( layer ); wxString netname = arr[3]; + if( IsCopperLayer( layer ) ) zone->SetNet( getOrAddNetItem( netname ) ); zone->SetLocalClearance( ConvertSize( arr[5] ) ); - zone->SetThermalReliefGap( zone->GetLocalClearance() ); + zone->SetThermalReliefGap( zone->GetLocalClearance().value() ); wxString fillStyle = arr[5]; if( fillStyle == wxS( "none" ) ) diff --git a/pcbnew/pcb_io/kicad_legacy/pcb_io_kicad_legacy.cpp b/pcbnew/pcb_io/kicad_legacy/pcb_io_kicad_legacy.cpp index e3c2ac7a2a..1538e467cf 100644 --- a/pcbnew/pcb_io/kicad_legacy/pcb_io_kicad_legacy.cpp +++ b/pcbnew/pcb_io/kicad_legacy/pcb_io_kicad_legacy.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 2007-2012 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2019 Jean-Pierre Charras, jp.charras@wanadoo.fr - * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -1341,7 +1341,7 @@ void PCB_IO_KICAD_LEGACY::loadFOOTPRINT( FOOTPRINT* aFootprint ) else if( TESTLINE( ".ZoneConnection" ) ) { int tmp = intParse( line + SZ( ".ZoneConnection" ) ); - aFootprint->SetZoneConnection((ZONE_CONNECTION) tmp ); + aFootprint->SetLocalZoneConnection((ZONE_CONNECTION) tmp ); } else if( TESTLINE( ".ThermalWidth" ) ) { @@ -1554,7 +1554,7 @@ void PCB_IO_KICAD_LEGACY::loadPAD( FOOTPRINT* aFootprint ) else if( TESTLINE( ".ZoneConnection" ) ) { int tmp = intParse( line + SZ( ".ZoneConnection" ) ); - pad->SetZoneConnection( (ZONE_CONNECTION) tmp ); + pad->SetLocalZoneConnection( (ZONE_CONNECTION) tmp ); } else if( TESTLINE( ".ThermalWidth" ) ) { diff --git a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp index c9ac3cff22..bb78d85b30 100644 --- a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp +++ b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2012 CERN - * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -1197,34 +1197,34 @@ void PCB_IO_KICAD_SEXPR::format( const FOOTPRINT* aFootprint, int aNestLevel ) c m_out->Quotew( aFootprint->GetSheetfile() ).c_str() ); } - if( aFootprint->GetLocalSolderMaskMargin() != 0 ) + if( aFootprint->GetLocalSolderMaskMargin().has_value() ) { m_out->Print( aNestLevel+1, "(solder_mask_margin %s)\n", - formatInternalUnits( aFootprint->GetLocalSolderMaskMargin() ).c_str() ); + formatInternalUnits( aFootprint->GetLocalSolderMaskMargin().value() ).c_str() ); } - if( aFootprint->GetLocalSolderPasteMargin() != 0 ) + if( aFootprint->GetLocalSolderPasteMargin().has_value() ) { m_out->Print( aNestLevel+1, "(solder_paste_margin %s)\n", - formatInternalUnits( aFootprint->GetLocalSolderPasteMargin() ).c_str() ); + formatInternalUnits( aFootprint->GetLocalSolderPasteMargin().value() ).c_str() ); } - if( aFootprint->GetLocalSolderPasteMarginRatio() != 0 ) + if( aFootprint->GetLocalSolderPasteMarginRatio().has_value() ) { m_out->Print( aNestLevel+1, "(solder_paste_ratio %s)\n", - FormatDouble2Str( aFootprint->GetLocalSolderPasteMarginRatio() ).c_str() ); + FormatDouble2Str( aFootprint->GetLocalSolderPasteMarginRatio().value() ).c_str() ); } - if( aFootprint->GetLocalClearance() != 0 ) + if( aFootprint->GetLocalClearance().has_value() ) { m_out->Print( aNestLevel+1, "(clearance %s)\n", - formatInternalUnits( aFootprint->GetLocalClearance() ).c_str() ); + formatInternalUnits( aFootprint->GetLocalClearance().value() ).c_str() ); } - if( aFootprint->GetZoneConnection() != ZONE_CONNECTION::INHERITED ) + if( aFootprint->GetLocalZoneConnection() != ZONE_CONNECTION::INHERITED ) { m_out->Print( aNestLevel+1, "(zone_connect %d)\n", - static_cast( aFootprint->GetZoneConnection() ) ); + static_cast( aFootprint->GetLocalZoneConnection() ) ); } // Attributes @@ -1623,34 +1623,34 @@ void PCB_IO_KICAD_SEXPR::format( const PAD* aPad, int aNestLevel ) const formatInternalUnits( aPad->GetPadToDieLength() ).c_str() ); } - if( aPad->GetLocalSolderMaskMargin() != 0 ) + if( aPad->GetLocalSolderMaskMargin().has_value() ) { StrPrintf( &output, " (solder_mask_margin %s)", - formatInternalUnits( aPad->GetLocalSolderMaskMargin() ).c_str() ); + formatInternalUnits( aPad->GetLocalSolderMaskMargin().value() ).c_str() ); } - if( aPad->GetLocalSolderPasteMargin() != 0 ) + if( aPad->GetLocalSolderPasteMargin().has_value() ) { StrPrintf( &output, " (solder_paste_margin %s)", - formatInternalUnits( aPad->GetLocalSolderPasteMargin() ).c_str() ); + formatInternalUnits( aPad->GetLocalSolderPasteMargin().value() ).c_str() ); } - if( aPad->GetLocalSolderPasteMarginRatio() != 0 ) + if( aPad->GetLocalSolderPasteMarginRatio().has_value() ) { StrPrintf( &output, " (solder_paste_margin_ratio %s)", - FormatDouble2Str( aPad->GetLocalSolderPasteMarginRatio() ).c_str() ); + FormatDouble2Str( aPad->GetLocalSolderPasteMarginRatio().value() ).c_str() ); } - if( aPad->GetLocalClearance() != 0 ) + if( aPad->GetLocalClearance().has_value() ) { StrPrintf( &output, " (clearance %s)", - formatInternalUnits( aPad->GetLocalClearance() ).c_str() ); + formatInternalUnits( aPad->GetLocalClearance().value() ).c_str() ); } - if( aPad->GetZoneConnection() != ZONE_CONNECTION::INHERITED ) + if( aPad->GetLocalZoneConnection() != ZONE_CONNECTION::INHERITED ) { StrPrintf( &output, " (zone_connect %d)", - static_cast( aPad->GetZoneConnection() ) ); + static_cast( aPad->GetLocalZoneConnection() ) ); } if( aPad->GetThermalSpokeWidth() != 0 ) @@ -2275,9 +2275,11 @@ void PCB_IO_KICAD_SEXPR::format( const ZONE* aZone, int aNestLevel ) const break; } - m_out->Print( 0, " (clearance %s))\n", formatInternalUnits( aZone->GetLocalClearance() ).c_str() ); + m_out->Print( 0, " (clearance %s))\n", + formatInternalUnits( aZone->GetLocalClearance().value() ).c_str() ); - m_out->Print( aNestLevel+1, "(min_thickness %s)", formatInternalUnits( aZone->GetMinThickness() ).c_str() ); + m_out->Print( aNestLevel+1, "(min_thickness %s)", + formatInternalUnits( aZone->GetMinThickness() ).c_str() ); // We continue to write this for 3rd-party parsers, but we no longer read it (as of V7). m_out->Print( 0, " (filled_areas_thickness no)" ); diff --git a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h index 64f452e98c..369be5c45e 100644 --- a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h +++ b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2012 CERN. - * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -148,7 +148,9 @@ class PCB_IO_KICAD_SEXPR; // forward decl //#define SEXPR_BOARD_FILE_VERSION 20231014 // V8 file format normalization //#define SEXPR_BOARD_FILE_VERSION 20231212 // Reference image locking/UUIDs, footprint boolean format //#define SEXPR_BOARD_FILE_VERSION 20231231 // Use 'uuid' rather than 'id' for generators and groups -#define SEXPR_BOARD_FILE_VERSION 20240108 // Convert teardrop parameters to explicit bools +//#define SEXPR_BOARD_FILE_VERSION 20240108 // Convert teardrop parameters to explicit bools +//----------------- Start of 9.0 development ----------------- +#define SEXPR_BOARD_FILE_VERSION 20240201 // Use nullable properties for overrides #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 diff --git a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr_parser.cpp b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr_parser.cpp index 277d86a27f..0220fcf2b6 100644 --- a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr_parser.cpp +++ b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr_parser.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2012 CERN - * Copyright (C) 2012-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2012-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -4188,30 +4188,47 @@ FOOTPRINT* PCB_IO_KICAD_SEXPR_PARSER::parseFOOTPRINT_unchecked( wxArrayString* a break; case T_solder_mask_margin: - footprint->SetLocalSolderMaskMargin( parseBoardUnits( "local solder mask margin " - "value" ) ); + footprint->SetLocalSolderMaskMargin( parseBoardUnits( "local solder mask margin value" ) ); NeedRIGHT(); + + // In pre-9.0 files "0" meant inherit. + if( m_requiredVersion <= 20240201 && footprint->GetLocalSolderMaskMargin() == 0 ) + footprint->SetLocalSolderMaskMargin( {} ); + break; case T_solder_paste_margin: - footprint->SetLocalSolderPasteMargin( parseBoardUnits( "local solder paste margin " - "value" ) ); + footprint->SetLocalSolderPasteMargin( parseBoardUnits( "local solder paste margin value" ) ); NeedRIGHT(); + + // In pre-9.0 files "0" meant inherit. + if( m_requiredVersion <= 20240201 && footprint->GetLocalSolderPasteMargin() == 0 ) + footprint->SetLocalSolderPasteMargin( {} ); + break; - case T_solder_paste_ratio: - footprint->SetLocalSolderPasteMarginRatio( parseDouble( "local solder paste margin " - "ratio value" ) ); + case T_solder_paste_margin_ratio: + footprint->SetLocalSolderPasteMarginRatio( parseDouble( "local solder paste margin ratio value" ) ); NeedRIGHT(); + + // In pre-9.0 files "0" meant inherit. + if( m_requiredVersion <= 20240201 && footprint->GetLocalSolderPasteMarginRatio() == 0 ) + footprint->SetLocalSolderPasteMarginRatio( {} ); + break; case T_clearance: footprint->SetLocalClearance( parseBoardUnits( "local clearance value" ) ); NeedRIGHT(); + + // In pre-9.0 files "0" meant inherit. + if( m_requiredVersion <= 20240201 && footprint->GetLocalClearance() == 0 ) + footprint->SetLocalClearance( {} ); + break; case T_zone_connect: - footprint->SetZoneConnection((ZONE_CONNECTION) parseInt( "zone connection value" ) ); + footprint->SetLocalZoneConnection((ZONE_CONNECTION) parseInt( "zone connection value" ) ); NeedRIGHT(); break; @@ -4592,8 +4609,7 @@ PAD* PCB_IO_KICAD_SEXPR_PARSER::parsePAD( FOOTPRINT* aParent ) // than 0 used to fix a bunch of debug assertions even though it is defined as a // through hole pad. Wouldn't a though hole pad with no drill be a surface mount // pad (or a conn pad which is a smd pad with no solder paste)? - if( ( pad->GetAttribute() != PAD_ATTRIB::SMD ) - && ( pad->GetAttribute() != PAD_ATTRIB::CONN ) ) + if( pad->GetAttribute() != PAD_ATTRIB::SMD && pad->GetAttribute() != PAD_ATTRIB::CONN ) pad->SetDrillSize( drillSize ); else pad->SetDrillSize( VECTOR2I( 0, 0 ) ); @@ -4658,24 +4674,43 @@ PAD* PCB_IO_KICAD_SEXPR_PARSER::parsePAD( FOOTPRINT* aParent ) break; case T_solder_mask_margin: - pad->SetLocalSolderMaskMargin( parseBoardUnits( T_solder_mask_margin ) ); + pad->SetLocalSolderMaskMargin( parseBoardUnits( "local solder mask margin value" ) ); NeedRIGHT(); + + // In pre-9.0 files "0" meant inherit. + if( m_requiredVersion <= 20240201 && pad->GetLocalSolderMaskMargin() == 0 ) + pad->SetLocalSolderMaskMargin( {} ); + break; case T_solder_paste_margin: - pad->SetLocalSolderPasteMargin( parseBoardUnits( T_solder_paste_margin ) ); + pad->SetLocalSolderPasteMargin( parseBoardUnits( "local solder paste margin value" ) ); NeedRIGHT(); + + // In pre-9.0 files "0" meant inherit. + if( m_requiredVersion <= 20240201 && pad->GetLocalSolderPasteMargin() == 0 ) + pad->SetLocalSolderPasteMargin( {} ); + break; case T_solder_paste_margin_ratio: - pad->SetLocalSolderPasteMarginRatio( - parseDouble( "pad local solder paste margin ratio value" ) ); + pad->SetLocalSolderPasteMarginRatio( parseDouble( "local solder paste margin ratio value" ) ); NeedRIGHT(); + + // In pre-9.0 files "0" meant inherit. + if( m_requiredVersion <= 20240201 && pad->GetLocalSolderPasteMarginRatio() == 0 ) + pad->SetLocalSolderPasteMarginRatio( {} ); + break; case T_clearance: pad->SetLocalClearance( parseBoardUnits( "local clearance value" ) ); NeedRIGHT(); + + // In pre-9.0 files "0" meant inherit. + if( m_requiredVersion <= 20240201 && pad->GetLocalClearance() == 0 ) + pad->SetLocalClearance( {} ); + break; case T_teardrops: @@ -4683,7 +4718,7 @@ PAD* PCB_IO_KICAD_SEXPR_PARSER::parsePAD( FOOTPRINT* aParent ) break; case T_zone_connect: - pad->SetZoneConnection( (ZONE_CONNECTION) parseInt( "zone connection value" ) ); + pad->SetLocalZoneConnection( (ZONE_CONNECTION) parseInt( "zone connection value" ) ); NeedRIGHT(); break; diff --git a/pcbnew/pcb_track.cpp b/pcbnew/pcb_track.cpp index 7b57a2ca08..5637bf0c2a 100644 --- a/pcbnew/pcb_track.cpp +++ b/pcbnew/pcb_track.cpp @@ -4,7 +4,7 @@ * Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2012 Wayne Stambaugh - * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -295,13 +295,6 @@ bool PCB_TRACK::ApproxCollinear( const PCB_TRACK& aTrack ) } -int PCB_TRACK::GetLocalClearance( wxString* aSource ) const -{ - // Not currently implemented - return 0; -} - - MINOPTMAX PCB_TRACK::GetWidthConstraint( wxString* aSource ) const { DRC_CONSTRAINT constraint; diff --git a/pcbnew/pcb_track.h b/pcbnew/pcb_track.h index 43cdb601fa..ed58753491 100644 --- a/pcbnew/pcb_track.h +++ b/pcbnew/pcb_track.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com - * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -189,14 +189,6 @@ public: return wxT( "PCB_TRACK" ); } - /** - * Return any local clearance overrides set in the "classic" (ie: pre-rule) system. - * - * @param aSource [out] optionally reports the source as a user-readable string - * @return int - the clearance in internal units. - */ - int GetLocalClearance( wxString* aSource ) const override; - virtual MINOPTMAX GetWidthConstraint( wxString* aSource = nullptr ) const; wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const override; diff --git a/pcbnew/router/pns_kicad_iface.cpp b/pcbnew/router/pns_kicad_iface.cpp index cd443f94b0..03f808dfd9 100644 --- a/pcbnew/router/pns_kicad_iface.cpp +++ b/pcbnew/router/pns_kicad_iface.cpp @@ -2,7 +2,7 @@ * KiRouter - a push-and-(sometimes-)shove PCB router * * Copyright (C) 2013-2016 CERN - * Copyright (C) 2016-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2016-2024 KiCad Developers, see AUTHORS.txt for contributors. * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -1555,7 +1555,10 @@ void PNS_KICAD_IFACE_BASE::SyncWorld( PNS::NODE *aWorld ) if( std::unique_ptr solid = syncPad( pad ) ) aWorld->Add( std::move( solid ) ); - worstClearance = std::max( worstClearance, pad->GetLocalClearance() ); + std::optional clearanceOverride = pad->GetClearanceOverrides( nullptr ); + + if( clearanceOverride.has_value() ) + worstClearance = std::max( worstClearance, clearanceOverride.value() ); if( pad->GetProperty() == PAD_PROP::CASTELLATED ) { diff --git a/pcbnew/teardrop/teardrop_utils.cpp b/pcbnew/teardrop/teardrop_utils.cpp index 1bedffae92..4f69a4bdf0 100644 --- a/pcbnew/teardrop/teardrop_utils.cpp +++ b/pcbnew/teardrop/teardrop_utils.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2021 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2023-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -133,7 +133,7 @@ bool TEARDROP_MANAGER::areItemsInSameZone( BOARD_ITEM* aPadOrVia, PCB_TRACK* aTr PAD *pad = static_cast( aPadOrVia ); if( zone->GetPadConnection() == ZONE_CONNECTION::NONE - || pad->GetZoneConnection() == ZONE_CONNECTION::NONE ) + || pad->GetZoneConnectionOverrides( nullptr ) == ZONE_CONNECTION::NONE ) { return false; } diff --git a/pcbnew/tools/board_inspection_tool.cpp b/pcbnew/tools/board_inspection_tool.cpp index b1c49403bc..7651ca97c4 100644 --- a/pcbnew/tools/board_inspection_tool.cpp +++ b/pcbnew/tools/board_inspection_tool.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2019-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2019-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -782,7 +782,7 @@ int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent ) r->Report( "" ); reportHeader( _( "Zone clearance resolution for:" ), a, b, layer, r ); - clearance = zone->GetLocalClearance(); + clearance = zone->GetLocalClearance().value(); r->Report( "" ); r->Report( wxString::Format( _( "Zone clearance: %s." ), m_frame->StringFromValue( clearance, true ) ) ); diff --git a/pcbnew/tools/drawing_tool.cpp b/pcbnew/tools/drawing_tool.cpp index 843b639bd3..6ad79ce77d 100644 --- a/pcbnew/tools/drawing_tool.cpp +++ b/pcbnew/tools/drawing_tool.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2014-2017 CERN - * Copyright (C) 2018-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2018-2024 KiCad Developers, see AUTHORS.txt for contributors. * @author Maciej Suminski * * This program is free software; you can redistribute it and/or @@ -2814,7 +2814,12 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent ) for( FOOTPRINT* footprint : aFrame->GetBoard()->Footprints() ) { for( PAD* pad : footprint->Pads() ) - m_worstClearance = std::max( m_worstClearance, pad->GetLocalClearance() ); + { + std::optional padOverride = pad->GetClearanceOverrides( nullptr ); + + if( padOverride.has_value() ) + m_worstClearance = std::max( m_worstClearance, padOverride.value() ); + } } } catch( PARSE_ERROR& ) diff --git a/pcbnew/zone.cpp b/pcbnew/zone.cpp index ef2a23644d..e850f9f456 100644 --- a/pcbnew/zone.cpp +++ b/pcbnew/zone.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck - * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -486,15 +486,9 @@ bool ZONE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const } -int ZONE::GetLocalClearance( wxString* aSource ) const +std::optional ZONE::GetLocalClearance() const { - if( m_isRuleArea ) - return 0; - - if( aSource ) - *aSource = _( "zone" ); - - return m_ZoneClearance; + return m_isRuleArea ? 0 : m_ZoneClearance; } @@ -1715,7 +1709,7 @@ static struct ZONE_DESC const wxString groupElectrical = _HKI( "Electrical" ); - auto clearanceOverride = new PROPERTY( _HKI( "Clearance" ), + auto clearanceOverride = new PROPERTY>( _HKI( "Clearance" ), &ZONE::SetLocalClearance, &ZONE::GetLocalClearance, PROPERTY_DISPLAY::PT_SIZE ); clearanceOverride->SetAvailableFunc( isCopperZone ); diff --git a/pcbnew/zone.h b/pcbnew/zone.h index 154a55fdec..e07ae0d06b 100644 --- a/pcbnew/zone.h +++ b/pcbnew/zone.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -148,16 +148,27 @@ public: void CacheBoundingBox(); /** - * Return any local clearances set in the "classic" (ie: pre-rule) system. These are - * things like zone clearance which are NOT an override. + * @return the zone's clearance in internal units. + */ + std::optional GetLocalClearance() const override; + void SetLocalClearance( std::optional aClearance ) { m_ZoneClearance = aClearance.value(); } + + /** + * Return any local clearances set in the "classic" (ie: pre-rule) system. * - * @param aSource [out] optionally reports the source as a user-readable string + * @param aSource [out] optionally reports the source as a user-readable string. * @return the clearance in internal units. */ - int GetLocalClearance( wxString* aSource ) const override; + std::optional GetLocalClearance( wxString* aSource ) const override + { + if( m_isRuleArea ) + return std::optional(); - int GetLocalClearance() const { return GetLocalClearance( nullptr ); } - void SetLocalClearance( int aClearance ) { m_ZoneClearance = aClearance; } + if( aSource ) + *aSource = _( "zone" ); + + return GetLocalClearance(); + } /** * @return true if this zone is on a copper layer, false if on a technical layer. diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp index fdd00c6f7c..179b6280e4 100644 --- a/pcbnew/zone_filler.cpp +++ b/pcbnew/zone_filler.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2014-2017 CERN - * Copyright (C) 2014-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2014-2024 KiCad Developers, see AUTHORS.txt for contributors. * @author Tomasz Włostowski * * This program is free software: you can redistribute it and/or modify it @@ -930,10 +930,10 @@ void ZONE_FILLER::knockoutThermalReliefs( const ZONE* aZone, PCB_LAYER_ID aLayer constraint = bds.m_DRCEngine->EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, pad, aZone, aLayer ); - if( constraint.GetValue().Min() > aZone->GetLocalClearance() ) + if( constraint.GetValue().Min() > aZone->GetLocalClearance().value() ) padClearance = constraint.GetValue().Min(); else - padClearance = aZone->GetLocalClearance(); + padClearance = aZone->GetLocalClearance().value(); if( pad->FlashLayer( aLayer ) ) { @@ -1746,7 +1746,7 @@ void ZONE_FILLER::buildThermalSpokes( const ZONE* aZone, PCB_LAYER_ID aLayer, BOX2I zoneBB = aZone->GetBoundingBox(); DRC_CONSTRAINT constraint; - zoneBB.Inflate( std::max( bds.GetBiggestClearanceValue(), aZone->GetLocalClearance() ) ); + zoneBB.Inflate( std::max( bds.GetBiggestClearanceValue(), aZone->GetLocalClearance().value() ) ); // Is a point on the boundary of the polygon inside or outside? The boundary may be off by // MaxError, and we add 1.5 mil for some wiggle room. diff --git a/pcbnew/zone_settings.cpp b/pcbnew/zone_settings.cpp index 4342728b13..9f05fca52a 100644 --- a/pcbnew/zone_settings.cpp +++ b/pcbnew/zone_settings.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck - * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -132,7 +132,7 @@ ZONE_SETTINGS& ZONE_SETTINGS::operator << ( const ZONE& aSource ) { m_ZonePriority = aSource.GetAssignedPriority(); m_FillMode = aSource.GetFillMode(); - m_ZoneClearance = aSource.GetLocalClearance(); + m_ZoneClearance = aSource.GetLocalClearance().value(); m_ZoneMinThickness = aSource.GetMinThickness(); m_HatchThickness = aSource.GetHatchThickness(); m_HatchGap = aSource.GetHatchGap(); diff --git a/qa/data/pcbnew/prettifier/Reverb_BTDR-1V_formatted.kicad_mod b/qa/data/pcbnew/prettifier/Reverb_BTDR-1V_formatted.kicad_mod index d761465e0e..90b6fea11a 100644 --- a/qa/data/pcbnew/prettifier/Reverb_BTDR-1V_formatted.kicad_mod +++ b/qa/data/pcbnew/prettifier/Reverb_BTDR-1V_formatted.kicad_mod @@ -1,5 +1,5 @@ (footprint "Reverb_BTDR-1V" - (version 20231007) + (version 20240201) (generator pcbnew) (layer "F.Cu") (descr "Digital Reverberation Unit, http://www.belton.co.kr/inc/downfile.php?seq=17&file=pdf (footprint from http://www.uk-electronic.de/PDF/BTDR-1.pdf)") diff --git a/qa/data/pcbnew/prettifier/Samtec_HLE-133-02-xx-DV-PE-LC_2x33_P2.54mm_Horizontal_formatted.kicad_mod b/qa/data/pcbnew/prettifier/Samtec_HLE-133-02-xx-DV-PE-LC_2x33_P2.54mm_Horizontal_formatted.kicad_mod index 06019f277a..f206e05f36 100644 --- a/qa/data/pcbnew/prettifier/Samtec_HLE-133-02-xx-DV-PE-LC_2x33_P2.54mm_Horizontal_formatted.kicad_mod +++ b/qa/data/pcbnew/prettifier/Samtec_HLE-133-02-xx-DV-PE-LC_2x33_P2.54mm_Horizontal_formatted.kicad_mod @@ -1,5 +1,5 @@ (footprint "Samtec_HLE-133-02-xx-DV-PE-LC_2x33_P2.54mm_Horizontal" - (version 20231007) + (version 20240201) (generator pcbnew) (layer "F.Cu") (descr "Samtec HLE .100\" Tiger Beam Cost-effective Single Beam Socket Strip, HLE-133-02-xx-DV-PE-LC, 33 Pins per row (http://suddendocs.samtec.com/prints/hle-1xx-02-xx-dv-xe-xx-mkt.pdf, http://suddendocs.samtec.com/prints/hle-thru.pdf), generated with kicad-footprint-generator") diff --git a/qa/data/pcbnew/prettifier/group_and_image_formatted.kicad_pcb b/qa/data/pcbnew/prettifier/group_and_image_formatted.kicad_pcb index 68ea0290b2..e7cc5595a7 100644 --- a/qa/data/pcbnew/prettifier/group_and_image_formatted.kicad_pcb +++ b/qa/data/pcbnew/prettifier/group_and_image_formatted.kicad_pcb @@ -1,5 +1,5 @@ (kicad_pcb - (version 20231007) + (version 20240201) (generator pcbnew) (general (thickness 1.6) diff --git a/qa/pcbnew_utils/board_test_utils.cpp b/qa/pcbnew_utils/board_test_utils.cpp index 11c16978d9..e00badb00d 100644 --- a/qa/pcbnew_utils/board_test_utils.cpp +++ b/qa/pcbnew_utils/board_test_utils.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2019-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2019-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -42,7 +42,7 @@ #include #include -#define CHECK_ENUM_CLASS_EQUAL( L, R ) \ +#define CHECK_ENUM_CLASS_EQUAL( L, R ) \ BOOST_CHECK_EQUAL( static_cast( L ), static_cast( R ) ) @@ -349,13 +349,15 @@ void CheckFpPad( const PAD* expected, const PAD* pad ) BOOST_CHECK_EQUAL( expected->GetPinFunction(), pad->GetPinFunction() ); BOOST_CHECK_EQUAL( expected->GetPinType(), pad->GetPinType() ); BOOST_CHECK_EQUAL( expected->GetPadToDieLength(), pad->GetPadToDieLength() ); - BOOST_CHECK_EQUAL( expected->GetLocalSolderMaskMargin(), pad->GetLocalSolderMaskMargin() ); - BOOST_CHECK_EQUAL( expected->GetLocalSolderPasteMargin(), - pad->GetLocalSolderPasteMargin() ); - BOOST_CHECK_EQUAL( expected->GetLocalSolderPasteMarginRatio(), - pad->GetLocalSolderPasteMarginRatio() ); - BOOST_CHECK_EQUAL( expected->GetLocalClearance(), pad->GetLocalClearance() ); - CHECK_ENUM_CLASS_EQUAL( expected->GetZoneConnection(), pad->GetZoneConnection() ); + BOOST_CHECK_EQUAL( expected->GetLocalSolderMaskMargin().value_or( 0 ), + pad->GetLocalSolderMaskMargin().value_or( 0 ) ); + BOOST_CHECK_EQUAL( expected->GetLocalSolderPasteMargin().value_or( 0 ), + pad->GetLocalSolderPasteMargin().value_or( 0 ) ); + BOOST_CHECK_EQUAL( expected->GetLocalSolderPasteMarginRatio().value_or( 0 ), + pad->GetLocalSolderPasteMarginRatio().value_or( 0 ) ); + BOOST_CHECK_EQUAL( expected->GetLocalClearance().value_or( 0 ), + pad->GetLocalClearance().value_or( 0 ) ); + CHECK_ENUM_CLASS_EQUAL( expected->GetLocalZoneConnection(), pad->GetLocalZoneConnection() ); BOOST_CHECK_EQUAL( expected->GetThermalSpokeWidth(), pad->GetThermalSpokeWidth() ); BOOST_CHECK_EQUAL( expected->GetThermalSpokeAngle(), pad->GetThermalSpokeAngle() ); BOOST_CHECK_EQUAL( expected->GetThermalGap(), pad->GetThermalGap() ); @@ -467,7 +469,8 @@ void CheckFpZone( const ZONE* expected, const ZONE* zone ) BOOST_CHECK_EQUAL( expected->GetNetCode(), zone->GetNetCode() ); BOOST_CHECK_EQUAL( expected->GetAssignedPriority(), zone->GetAssignedPriority() ); CHECK_ENUM_CLASS_EQUAL( expected->GetPadConnection(), zone->GetPadConnection() ); - BOOST_CHECK_EQUAL( expected->GetLocalClearance(), zone->GetLocalClearance() ); + BOOST_CHECK_EQUAL( expected->GetLocalClearance().value_or( 0 ), + zone->GetLocalClearance().value_or( 0 ) ); BOOST_CHECK_EQUAL( expected->GetMinThickness(), zone->GetMinThickness() ); BOOST_CHECK_EQUAL( expected->GetLayerSet(), zone->GetLayerSet() );