From 1ae47b6069e54da89fa43896ab25a18f68e985b3 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Fri, 5 Apr 2019 17:10:59 +0100 Subject: [PATCH] Implement a copper-to-edge-clearance setting. For legacy boards, the setting is picked up from the board outline thickness. If the board outline has mixed thicknesses, then the max is used and a warning is displayed. Fixes: lp:1797787 * https://bugs.launchpad.net/kicad/+bug/1797787 --- 3d-viewer/3d_canvas/create_layer_items.cpp | 2 +- include/board_design_settings.h | 11 + pcbnew/board_design_settings.cpp | 26 +- ...board_items_to_polygon_shape_transform.cpp | 2 +- .../panel_setup_feature_constraints.cpp | 7 +- .../dialogs/panel_setup_feature_constraints.h | 1 + .../panel_setup_feature_constraints_base.cpp | 22 +- .../panel_setup_feature_constraints_base.fbp | 288 +++++++++++++++++- .../panel_setup_feature_constraints_base.h | 5 +- pcbnew/drc_clearance_test_functions.cpp | 8 +- pcbnew/files.cpp | 48 +++ pcbnew/pcb_edit_frame.h | 5 + pcbnew/zone_filler.cpp | 16 +- template/kicad.pro | 3 +- 14 files changed, 417 insertions(+), 27 deletions(-) diff --git a/3d-viewer/3d_canvas/create_layer_items.cpp b/3d-viewer/3d_canvas/create_layer_items.cpp index e0d3a72ec6..313b470400 100644 --- a/3d-viewer/3d_canvas/create_layer_items.cpp +++ b/3d-viewer/3d_canvas/create_layer_items.cpp @@ -690,7 +690,7 @@ void CINFO3D_VISU::createLayers( REPORTER *aStatusTextReporter ) switch( item->Type() ) { - case PCB_LINE_T: // should not exist on copper layers + case PCB_LINE_T: { AddShapeWithClearanceToContainer( (DRAWSEGMENT*)item, layerContainer, diff --git a/include/board_design_settings.h b/include/board_design_settings.h index 58cc0d0413..38060c5a48 100644 --- a/include/board_design_settings.h +++ b/include/board_design_settings.h @@ -66,6 +66,10 @@ #define DEFAULT_MICROVIASMINDRILL 0.1 // micro vias (not vias) min drill diameter #define DEFAULT_HOLETOHOLEMIN 0.25 // separation between drilled hole edges +#define DEFAULT_COPPEREDGECLEARANCE 0.01 // clearance between copper items and edge cuts +#define LEGACY_COPPEREDGECLEARANCE -0.01 // A flag to indicate the legacy method (based + // on edge cut line thicknesses) should be used. + /** * Struct VIA_DIMENSION * is a small helper container to handle a stock of specific vias each with @@ -189,6 +193,7 @@ public: int m_ViasMinDrill; ///< vias (not micro vias) min drill diameter int m_MicroViasMinSize; ///< micro vias (not vias) min diameter int m_MicroViasMinDrill; ///< micro vias (not vias) min drill diameter + int m_CopperEdgeClearance; // Global mask margins: int m_SolderMaskMargin; ///< Solder mask margin @@ -631,6 +636,12 @@ public: */ void SetMinHoleSeparation( int aDistance ); + /** + * Function SetCopperEdgeClearance + * @param aValue The minimum distance between copper items and board edges. + */ + void SetCopperEdgeClearance( int aDistance ); + /** * Function SetRequireCourtyardDefinitions * @param aRequire Set to true to generate DRC violations from missing courtyards. diff --git a/pcbnew/board_design_settings.cpp b/pcbnew/board_design_settings.cpp index d9512d854c..732eef8244 100644 --- a/pcbnew/board_design_settings.cpp +++ b/pcbnew/board_design_settings.cpp @@ -489,11 +489,12 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS() : m_customDiffPair.m_Gap = Millimeter2iu( DEFAULT_CUSTOMDPAIRGAP ); m_customDiffPair.m_ViaGap = Millimeter2iu( DEFAULT_CUSTOMDPAIRVIAGAP ); - m_TrackMinWidth = Millimeter2iu( DEFAULT_TRACKMINWIDTH ); - m_ViasMinSize = Millimeter2iu( DEFAULT_VIASMINSIZE ); - m_ViasMinDrill = Millimeter2iu( DEFAULT_VIASMINDRILL ); - m_MicroViasMinSize = Millimeter2iu( DEFAULT_MICROVIASMINSIZE ); - m_MicroViasMinDrill = Millimeter2iu( DEFAULT_MICROVIASMINDRILL ); + m_TrackMinWidth = Millimeter2iu( DEFAULT_TRACKMINWIDTH ); + m_ViasMinSize = Millimeter2iu( DEFAULT_VIASMINSIZE ); + m_ViasMinDrill = Millimeter2iu( DEFAULT_VIASMINDRILL ); + m_MicroViasMinSize = Millimeter2iu( DEFAULT_MICROVIASMINSIZE ); + m_MicroViasMinDrill = Millimeter2iu( DEFAULT_MICROVIASMINDRILL ); + m_CopperEdgeClearance = Millimeter2iu( DEFAULT_COPPEREDGECLEARANCE ); // Global mask margins: m_SolderMaskMargin = Millimeter2iu( DEFAULT_SOLDERMASK_CLEARANCE ); @@ -564,7 +565,14 @@ void BOARD_DESIGN_SETTINGS::AppendConfigs( BOARD* aBoard, PARAM_CFG_ARRAY* aResu aResult->push_back( new PARAM_CFG_INT_WITH_SCALE( wxT( "MinHoleToHole" ), &m_HoleToHoleMin, - Millimeter2iu( DEFAULT_HOLETOHOLEMIN ), 0, Millimeter2iu( 10.0 ), + Millimeter2iu( DEFAULT_HOLETOHOLEMIN ), Millimeter2iu( 0.0 ), Millimeter2iu( 10.0 ), + nullptr, MM_PER_IU ) ); + + // Note: a clearance of -0.01 is a flag indicating we should use the legacy (pre-6.0) method + // based on the edge cut thicknesses. + aResult->push_back( new PARAM_CFG_INT_WITH_SCALE( wxT( "CopperEdgeClearance" ), + &m_CopperEdgeClearance, + Millimeter2iu( LEGACY_COPPEREDGECLEARANCE ), Millimeter2iu( -0.01 ), Millimeter2iu( 25.0 ), nullptr, MM_PER_IU ) ); aResult->push_back( new PARAM_CFG_TRACKWIDTHS( &m_TrackWidthList ) ); @@ -850,6 +858,12 @@ void BOARD_DESIGN_SETTINGS::SetMinHoleSeparation( int aDistance ) } +void BOARD_DESIGN_SETTINGS::SetCopperEdgeClearance( int aDistance ) +{ + m_CopperEdgeClearance = aDistance; +} + + void BOARD_DESIGN_SETTINGS::SetRequireCourtyardDefinitions( bool aRequire ) { m_RequireCourtyards = aRequire; diff --git a/pcbnew/board_items_to_polygon_shape_transform.cpp b/pcbnew/board_items_to_polygon_shape_transform.cpp index ec9de9285b..695dc93a00 100644 --- a/pcbnew/board_items_to_polygon_shape_transform.cpp +++ b/pcbnew/board_items_to_polygon_shape_transform.cpp @@ -123,7 +123,7 @@ void BOARD::ConvertBrdLayerToPolygonalContours( PCB_LAYER_ID aLayer, SHAPE_POLY_ switch( item->Type() ) { - case PCB_LINE_T: // should not exist on copper layers + case PCB_LINE_T: ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon( aOutlines, 0, segcountforcircle, correctionFactor ); break; diff --git a/pcbnew/dialogs/panel_setup_feature_constraints.cpp b/pcbnew/dialogs/panel_setup_feature_constraints.cpp index a949a3592d..6074e98be8 100644 --- a/pcbnew/dialogs/panel_setup_feature_constraints.cpp +++ b/pcbnew/dialogs/panel_setup_feature_constraints.cpp @@ -37,7 +37,8 @@ PANEL_SETUP_FEATURE_CONSTRAINTS::PANEL_SETUP_FEATURE_CONSTRAINTS( PAGED_DIALOG* m_viaMinDrill( aFrame, m_ViaMinDrillTitle, m_SetViasMinDrillCtrl, m_ViaMinDrillUnits, true ), m_uviaMinSize( aFrame, m_uviaMinSizeLabel, m_uviaMinSizeCtrl, m_uviaMinSizeUnits, true ), m_uviaMinDrill( aFrame, m_uviaMinDrillLabel, m_uviaMinDrillCtrl, m_uviaMinDrillUnits, true ), - m_holeToHoleMin( aFrame, m_HoleToHoleTitle, m_SetHoleToHoleCtrl, m_HoleToHoleUnits, true ) + m_holeToHoleMin( aFrame, m_HoleToHoleTitle, m_SetHoleToHoleCtrl, m_HoleToHoleUnits, true ), + m_edgeClearance( aFrame, m_EdgeClearanceLabel, m_EdgeClearanceCtrl, m_EdgeClearanceUnits, true ) { m_Frame = aFrame; m_BrdSettings = &m_Frame->GetBoard()->GetDesignSettings(); @@ -58,6 +59,8 @@ bool PANEL_SETUP_FEATURE_CONSTRAINTS::TransferDataToWindow() m_holeToHoleMin.SetValue( m_BrdSettings->m_HoleToHoleMin ); + m_edgeClearance.SetValue( m_BrdSettings->m_CopperEdgeClearance ); + m_OptRequireCourtyards->SetValue( m_BrdSettings->m_RequireCourtyards ); m_OptOverlappingCourtyards->SetValue( m_BrdSettings->m_ProhibitOverlappingCourtyards ); @@ -83,6 +86,8 @@ bool PANEL_SETUP_FEATURE_CONSTRAINTS::TransferDataFromWindow() m_BrdSettings->SetMinHoleSeparation( m_holeToHoleMin.GetValue() ); + m_BrdSettings->SetCopperEdgeClearance( m_edgeClearance.GetValue() ); + m_BrdSettings->SetRequireCourtyardDefinitions( m_OptRequireCourtyards->GetValue() ); m_BrdSettings->SetProhibitOverlappingCourtyards( m_OptOverlappingCourtyards->GetValue() ); diff --git a/pcbnew/dialogs/panel_setup_feature_constraints.h b/pcbnew/dialogs/panel_setup_feature_constraints.h index 5c17315d1e..cb52de17da 100644 --- a/pcbnew/dialogs/panel_setup_feature_constraints.h +++ b/pcbnew/dialogs/panel_setup_feature_constraints.h @@ -47,6 +47,7 @@ public: UNIT_BINDER m_uviaMinSize; UNIT_BINDER m_uviaMinDrill; UNIT_BINDER m_holeToHoleMin; + UNIT_BINDER m_edgeClearance; public: PANEL_SETUP_FEATURE_CONSTRAINTS( PAGED_DIALOG* aParent, PCB_EDIT_FRAME* aFrame ); diff --git a/pcbnew/dialogs/panel_setup_feature_constraints_base.cpp b/pcbnew/dialogs/panel_setup_feature_constraints_base.cpp index 2408dd134b..f5573a8121 100644 --- a/pcbnew/dialogs/panel_setup_feature_constraints_base.cpp +++ b/pcbnew/dialogs/panel_setup_feature_constraints_base.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Jun 5 2018) +// C++ code generated with wxFormBuilder (version Dec 30 2017) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! @@ -143,6 +143,26 @@ PANEL_SETUP_FEATURE_CONSTRAINTS_BASE::PANEL_SETUP_FEATURE_CONSTRAINTS_BASE( wxWi fgFeatureConstraints->Add( m_HoleToHoleUnits, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxTOP, 5 ); + fgFeatureConstraints->Add( 0, 0, 1, wxEXPAND, 5 ); + + + fgFeatureConstraints->Add( 0, 0, 1, wxEXPAND, 5 ); + + + fgFeatureConstraints->Add( 0, 0, 1, wxEXPAND, 5 ); + + m_EdgeClearanceLabel = new wxStaticText( this, wxID_ANY, _("Copper edge clearance:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_EdgeClearanceLabel->Wrap( -1 ); + fgFeatureConstraints->Add( m_EdgeClearanceLabel, 0, wxTOP|wxBOTTOM|wxRIGHT, 5 ); + + m_EdgeClearanceCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgFeatureConstraints->Add( m_EdgeClearanceCtrl, 0, wxALL|wxEXPAND, 5 ); + + m_EdgeClearanceUnits = new wxStaticText( this, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 ); + m_EdgeClearanceUnits->Wrap( -1 ); + fgFeatureConstraints->Add( m_EdgeClearanceUnits, 0, wxTOP|wxBOTTOM|wxRIGHT, 5 ); + + sbFeatureConstraints->Add( fgFeatureConstraints, 1, wxEXPAND|wxTOP|wxLEFT, 5 ); diff --git a/pcbnew/dialogs/panel_setup_feature_constraints_base.fbp b/pcbnew/dialogs/panel_setup_feature_constraints_base.fbp index 95329ccec1..fe2bc0f2c5 100644 --- a/pcbnew/dialogs/panel_setup_feature_constraints_base.fbp +++ b/pcbnew/dialogs/panel_setup_feature_constraints_base.fbp @@ -14,7 +14,6 @@ panel_setup_feature_constraints_base 1000 none - 1 panel_setup_feature_constraints_base @@ -2124,6 +2123,293 @@ + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxTOP|wxBOTTOM|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Copper edge clearance: + + 0 + + + 0 + + 1 + m_EdgeClearanceLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; forward_declare + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_EdgeClearanceCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP|wxBOTTOM|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mm + + 0 + + + 0 + + 1 + m_EdgeClearanceUnits + 1 + + + protected + 1 + + Resizable + 1 + + + ; forward_declare + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pcbnew/dialogs/panel_setup_feature_constraints_base.h b/pcbnew/dialogs/panel_setup_feature_constraints_base.h index ce42aba445..ea21254f1e 100644 --- a/pcbnew/dialogs/panel_setup_feature_constraints_base.h +++ b/pcbnew/dialogs/panel_setup_feature_constraints_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Jun 5 2018) +// C++ code generated with wxFormBuilder (version Dec 30 2017) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! @@ -55,6 +55,9 @@ class PANEL_SETUP_FEATURE_CONSTRAINTS_BASE : public wxPanel wxStaticText* m_HoleToHoleTitle; wxTextCtrl* m_SetHoleToHoleCtrl; wxStaticText* m_HoleToHoleUnits; + wxStaticText* m_EdgeClearanceLabel; + wxTextCtrl* m_EdgeClearanceCtrl; + wxStaticText* m_EdgeClearanceUnits; public: diff --git a/pcbnew/drc_clearance_test_functions.cpp b/pcbnew/drc_clearance_test_functions.cpp index e8e7a60b1f..678bb844b9 100644 --- a/pcbnew/drc_clearance_test_functions.cpp +++ b/pcbnew/drc_clearance_test_functions.cpp @@ -737,10 +737,10 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool aTestPads, bool aTestZ { SEG test_seg( aRefSeg->GetStart(), aRefSeg->GetEnd() ); - // the minimum distance = clearance plus half the reference track - // width. Board edges do not have width or clearance values, so we - // look for simple crossing. - SEG::ecoord w_dist = aRefSeg->GetClearance() + aRefSeg->GetWidth() / 2; + int clearance = std::max( aRefSeg->GetClearance(), dsnSettings.m_CopperEdgeClearance ); + + // the minimum distance = clearance plus half the reference track width + SEG::ecoord w_dist = clearance + aRefSeg->GetWidth() / 2; w_dist *= w_dist; for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ ) diff --git a/pcbnew/files.cpp b/pcbnew/files.cpp index 939fe4830d..1dc1f587ca 100644 --- a/pcbnew/files.cpp +++ b/pcbnew/files.cpp @@ -384,6 +384,48 @@ IO_MGR::PCB_FILE_T plugin_type( const wxString& aFileName, int aCtl ) } +int PCB_EDIT_FRAME::inferLegacyEdgeClearance( BOARD* aBoard ) +{ + PCB_LAYER_COLLECTOR collector; + + collector.SetLayerId( Edge_Cuts ); + collector.Collect( aBoard, GENERAL_COLLECTOR::AllBoardItems ); + + int edgeWidth = -1; + bool mixed = false; + + for( int i = 0; i < collector.GetCount(); i++ ) + { + if( collector[i]->Type() == PCB_LINE_T ) + { + int itemWidth = static_cast( collector[i] )->GetWidth(); + + if( edgeWidth != -1 && edgeWidth != itemWidth ) + { + mixed = true; + edgeWidth = std::max( edgeWidth, itemWidth ); + } + else + { + edgeWidth = itemWidth; + } + } + } + + if( mixed ) + { + // If they had different widths then we can't ensure that fills will be the same. + wxMessageBox( _( "If the zones on this board are refilled the Copper Edge Clearance\n" + "setting will be used (see Board Setup > Design Rules). This may\n" + "result in different fills from previous Kicad versions which used\n" + "the line thickness of the board boundary on the Edge Cuts layer." ), + _( "Edge Clearance Warning" ), wxOK|wxICON_WARNING, this ); + } + + return std::max( 0, edgeWidth / 2 ); +} + + bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, int aCtl ) { // This is for python: @@ -518,6 +560,7 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, in std::copy( configBds.m_TextItalic, configBds.m_TextItalic + 4, bds.m_TextItalic ); std::copy( configBds.m_TextUpright, configBds.m_TextUpright + 4, bds.m_TextUpright ); bds.m_DiffPairDimensionsList = configBds.m_DiffPairDimensionsList; + bds.m_CopperEdgeClearance = configBds.m_CopperEdgeClearance; bds.SetElementVisibility( LAYER_GRID, configBds.IsElementVisible( LAYER_GRID ) ); bds.SetElementVisibility( LAYER_RATSNEST, configBds.IsElementVisible( LAYER_RATSNEST ) ); @@ -528,6 +571,11 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, in loadedBoard->BuildListOfNets(); loadedBoard->SynchronizeNetsAndNetClasses(); + // If this is a legacy board then we set the copper edge clearance to 1/2 the edge-cut + // line width (which was a legacy kludge for implementing edge clearances). + if( bds.m_CopperEdgeClearance == Millimeter2iu( LEGACY_COPPEREDGECLEARANCE ) ) + bds.SetCopperEdgeClearance( inferLegacyEdgeClearance( loadedBoard ) ); + GetScreen()->ClrModify(); if( pluginType == IO_MGR::LEGACY && diff --git a/pcbnew/pcb_edit_frame.h b/pcbnew/pcb_edit_frame.h index a916893b27..13d0c0ff6a 100644 --- a/pcbnew/pcb_edit_frame.h +++ b/pcbnew/pcb_edit_frame.h @@ -264,6 +264,11 @@ protected: */ bool importFile( const wxString& aFileName, int aFileType ); + /** + * Use the existing edge_cut line thicknesses to infer the edge clearace. + */ + int inferLegacyEdgeClearance( BOARD* aBoard ); + /** * Rematch orphaned zones and vias to schematic nets. */ diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp index c7bf8308ac..1ae0c2d05c 100644 --- a/pcbnew/zone_filler.cpp +++ b/pcbnew/zone_filler.cpp @@ -332,15 +332,15 @@ void ZONE_FILLER::buildZoneFeatureHoleList( const ZONE_CONTAINER* aZone, aFeatures.RemoveAllContours(); - int outline_half_thickness = aZone->GetMinThickness() / 2; + int zone_clearance = aZone->GetClearance(); + int edgeClearance = m_board->GetDesignSettings().m_CopperEdgeClearance; + int zone_to_edgecut_clearance = std::max( aZone->GetZoneClearance(), edgeClearance ); // When removing holes, the holes must be expanded by outline_half_thickness // to take in account the thickness of the zone outlines - int zone_clearance = aZone->GetClearance() + outline_half_thickness; - - // When holes are created by non copper items (edge cut items), use only - // the m_ZoneClearance parameter (zone clearance with no netclass clearance) - int zone_to_edgecut_clearance = aZone->GetZoneClearance() + outline_half_thickness; + int outline_half_thickness = aZone->GetMinThickness() / 2; + zone_clearance += outline_half_thickness; + zone_to_edgecut_clearance += outline_half_thickness; /* store holes (i.e. tracks and pads areas as polygons outlines) * in a polygon list @@ -531,12 +531,8 @@ void ZONE_FILLER::buildZoneFeatureHoleList( const ZONE_CONTAINER* aZone, // the netclass value, because we do not have a copper item zclearance = zone_to_edgecut_clearance; -#if 0 -// 6.0 TODO: we're leaving this off for 5.1 so that people can continue to use the board -// edge width as a hack for edge clearance. // edge cuts by definition don't have a width ignoreLineWidth = true; -#endif } switch( aItem->Type() ) diff --git a/template/kicad.pro b/template/kicad.pro index 152769cb72..5cd098305b 100644 --- a/template/kicad.pro +++ b/template/kicad.pro @@ -1,4 +1,4 @@ -update=22/05/2015 07:44:53 +update=05/04/2019 20:44:53 version=1 last_client=kicad [general] @@ -24,6 +24,7 @@ SolderMaskMinWidth=0.000000000000 DrawSegmentWidth=0.200000000000 BoardOutlineThickness=0.100000000000 ModuleOutlineThickness=0.150000000000 +CopperEdgeClearance=0.000000000000 [cvpcb] version=1 NetIExt=net