From cec857c0f49d4fd984a4095896306ff5d3a5930e Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Mon, 18 May 2020 17:11:57 +0100 Subject: [PATCH] Complete hookup of zone filler to new clearance engine. --- pcbnew/board_connected_item.cpp | 13 ++++ pcbnew/board_design_settings.cpp | 8 ++- pcbnew/class_zone.cpp | 43 ++++-------- pcbnew/class_zone.h | 3 +- pcbnew/drc/drc.cpp | 45 ++++++------- pcbnew/drc/drc.h | 8 ++- pcbnew/drc/drc_rule.cpp | 6 +- pcbnew/drc/drc_rule.h | 2 +- pcbnew/drc/drc_rule_parser.cpp | 17 ++++- pcbnew/files.cpp | 8 +-- pcbnew/plot_board_layers.cpp | 4 +- pcbnew/zone_filler.cpp | 109 ++++++++++++------------------- 12 files changed, 123 insertions(+), 143 deletions(-) diff --git a/pcbnew/board_connected_item.cpp b/pcbnew/board_connected_item.cpp index e06509e113..635fa00f68 100644 --- a/pcbnew/board_connected_item.cpp +++ b/pcbnew/board_connected_item.cpp @@ -134,6 +134,19 @@ int BOARD_CONNECTED_ITEM::GetClearance( BOARD_ITEM* aItem, wxString* aSource ) c } } + if( aItem && aItem->GetLayer() == Edge_Cuts ) + { + int edgeClearance = bds.m_CopperEdgeClearance; + + if( edgeClearance > clearance ) + { + clearance = edgeClearance; + + if( aSource ) + *aSource = _( "board edge clearance" ); + } + } + return clearance; } diff --git a/pcbnew/board_design_settings.cpp b/pcbnew/board_design_settings.cpp index e1da4d1f23..bff06dd5af 100644 --- a/pcbnew/board_design_settings.cpp +++ b/pcbnew/board_design_settings.cpp @@ -1019,12 +1019,16 @@ int BOARD_DESIGN_SETTINGS::GetRuleClearance( const BOARD_ITEM* aItem, const NETC if( selector->m_Rule->m_Clearance > 0 ) { clearance = std::max( clearance, selector->m_Rule->m_Clearance ); - *aSource = wxString::Format( _( "'%s' rule clearance" ), selector->m_Rule->m_Name ); + + if( aSource ) + *aSource = wxString::Format( _( "'%s' rule clearance" ), selector->m_Rule->m_Name ); } else if( selector->m_Rule->m_Clearance < 0 ) { clearance = std::min( clearance, abs( selector->m_Rule->m_Clearance ) ); - *aSource = wxString::Format( _( "'%s' rule clearance" ), selector->m_Rule->m_Name ); + + if( aSource ) + *aSource = wxString::Format( _( "'%s' rule clearance" ), selector->m_Rule->m_Name ); } } diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp index c4770505cd..c915c15199 100644 --- a/pcbnew/class_zone.cpp +++ b/pcbnew/class_zone.cpp @@ -463,22 +463,17 @@ int ZONE_CONTAINER::GetClearance( BOARD_ITEM* aItem, wxString* aSource ) const if( m_isKeepout ) return 0; - // The actual zone clearance is the biggest of the zone netclass clearance - // and the zone clearance setting in the zone properties dialog. - int zoneClearance = m_ZoneClearance; int clearance = BOARD_CONNECTED_ITEM::GetClearance( aItem, aSource ); - if( clearance > zoneClearance ) - { - return clearance; - } - else + if( m_ZoneClearance > clearance ) { + clearance = m_ZoneClearance; + if( aSource ) *aSource = _( "zone clearance" ); - - return zoneClearance; } + + return clearance; } @@ -1137,35 +1132,19 @@ double ZONE_CONTAINER::CalculateFilledArea() * Convert the zone filled areas polygons to polygons * inflated (optional) by max( aClearanceValue, the zone clearance) * and copy them in aCornerBuffer - * @param aMinClearanceValue the min clearance around outlines - * @param aUseNetClearance true to use a clearance which is the max value between - * aMinClearanceValue and the net clearance - * false to use aMinClearanceValue only - * @param aPreserveCorners an optional set of corners which should not be chamfered/filleted + * @param aClearance the clearance around outlines + * @param aPreserveCorners an optional set of corners which should not be chamfered/filleted */ void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, - int aMinClearanceValue, - bool aUseNetClearance, - std::set* aPreserveCorners ) const + int aClearance, std::set* aPreserveCorners ) const { // Creates the zone outline polygon (with holes if any) SHAPE_POLY_SET polybuffer; BuildSmoothedPoly( polybuffer, aPreserveCorners ); - // add clearance to outline - int clearance = aMinClearanceValue; - - if( aUseNetClearance && IsOnCopperLayer() ) - { - clearance = GetClearance(); - - if( aMinClearanceValue > clearance ) - clearance = aMinClearanceValue; - } - // Calculate the polygon with clearance // holes are linked to the main outline, so only one polygon is created. - if( clearance ) + if( aClearance ) { BOARD* board = GetBoard(); int maxError = ARC_HIGH_DEF; @@ -1173,8 +1152,8 @@ void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon( SHAPE_POLY_SE if( board ) maxError = board->GetDesignSettings().m_MaxError; - int segCount = std::max( GetArcToSegmentCount( clearance, maxError, 360.0 ), 3 ); - polybuffer.Inflate( clearance, segCount ); + int segCount = std::max( GetArcToSegmentCount( aClearance, maxError, 360.0 ), 3 ); + polybuffer.Inflate( aClearance, segCount ); } polybuffer.Fracture( SHAPE_POLY_SET::PM_FAST ); diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index f3c216b3c1..c0b40a6e99 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -316,8 +316,7 @@ public: * if both aMinClearanceValue = 0 and aUseNetClearance = false: create the zone outline polygon. */ void TransformOutlinesShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, - int aMinClearanceValue, bool aUseNetClearance, - std::set* aPreserveCorners = nullptr ) const; + int aMinClearanceValue, std::set* aPreserveCorners = nullptr ) const; /** * Function TransformShapeWithClearanceToPolygon diff --git a/pcbnew/drc/drc.cpp b/pcbnew/drc/drc.cpp index adeed1fd1e..7763051886 100644 --- a/pcbnew/drc/drc.cpp +++ b/pcbnew/drc/drc.cpp @@ -66,7 +66,7 @@ DRC::DRC() : m_pcbEditorFrame( nullptr ), m_pcb( nullptr ), m_drcDialog( nullptr ), - m_rulesFileLastMod( 0 ) + m_largestClearance( 0 ) { // establish initial values for everything: m_doPad2PadTest = true; // enable pad to pad clearance tests @@ -103,8 +103,6 @@ void DRC::Reset( RESET_REASON aReason ) m_pcb = m_pcbEditorFrame->GetBoard(); } - - loadRules(); } @@ -355,38 +353,32 @@ int DRC::testZoneToZoneOutlines( BOARD_COMMIT& aCommit ) } -void DRC::loadRules() +void DRC::LoadRules() { wxString rulesFilepath = m_pcbEditorFrame->Prj().AbsolutePath( "drc-rules" ); wxFileName rulesFile( rulesFilepath ); if( rulesFile.FileExists() ) { - wxLongLong lastMod = rulesFile.GetModificationTime().GetValue(); + m_ruleSelectors.clear(); + m_rules.clear(); - if( lastMod > m_rulesFileLastMod ) + FILE* fp = wxFopen( rulesFilepath, wxT( "rt" ) ); + + if( fp ) { - m_rulesFileLastMod = lastMod; - m_ruleSelectors.clear(); - m_rules.clear(); - - FILE* fp = wxFopen( rulesFilepath, wxT( "rt" ) ); - - if( fp ) + try { - try - { - DRC_RULES_PARSER parser( m_pcb, fp, rulesFilepath ); - parser.Parse( m_ruleSelectors, m_rules ); - } - catch( PARSE_ERROR& pe ) - { - // Don't leave possibly malformed stuff around for us to trip over - m_ruleSelectors.clear(); - m_rules.clear(); + DRC_RULES_PARSER parser( m_pcb, fp, rulesFilepath ); + parser.Parse( m_ruleSelectors, m_rules ); + } + catch( PARSE_ERROR& pe ) + { + // Don't leave possibly malformed stuff around for us to trip over + m_ruleSelectors.clear(); + m_rules.clear(); - DisplayError( m_drcDialog, pe.What() ); - } + DisplayError( m_drcDialog, pe.What() ); } } } @@ -399,7 +391,8 @@ void DRC::loadRules() void DRC::RunTests( wxTextCtrl* aMessages ) { - loadRules(); + // Make absolutely sure these are up-to-date + LoadRules(); wxASSERT( m_pcb == m_pcbEditorFrame->GetBoard() ); diff --git a/pcbnew/drc/drc.h b/pcbnew/drc/drc.h index 463eff4008..4c56cc394c 100644 --- a/pcbnew/drc/drc.h +++ b/pcbnew/drc/drc.h @@ -170,7 +170,6 @@ private: bool m_drcRun; bool m_footprintsTested; - wxLongLong m_rulesFileLastMod; std::vector m_ruleSelectors; std::vector m_rules; @@ -189,8 +188,6 @@ private: */ void updatePointers(); - void loadRules(); - EDA_UNITS userUnits() const { return m_pcbEditorFrame->GetUserUnits(); } /** @@ -296,6 +293,11 @@ private: //-------------------------------------------------- public: + /** + * Load the DRC rules. Must be called after the netclasses have been read. + */ + void LoadRules(); + /** * Test the board footprints against a netlist. Will report DRCE_MISSING_FOOTPRINT, * DRCE_DUPLICATE_FOOTPRINT and DRCE_EXTRA_FOOTPRINT errors in aDRCList. diff --git a/pcbnew/drc/drc_rule.cpp b/pcbnew/drc/drc_rule.cpp index eb97b33802..9ed639b597 100644 --- a/pcbnew/drc/drc_rule.cpp +++ b/pcbnew/drc/drc_rule.cpp @@ -102,8 +102,8 @@ void MatchSelectors( const std::vector& aSelectors, if( !bItem ) continue; - NETCLASS* firstNetclass = candidate->m_MatchNetclasses[0]; - NETCLASS* secondNetclass = candidate->m_MatchNetclasses[1]; + NETCLASS* firstNetclass = candidate->m_MatchNetclasses[0].get(); + NETCLASS* secondNetclass = candidate->m_MatchNetclasses[1].get(); if( !( aNetclass == firstNetclass && bNetclass == secondNetclass ) && !( aNetclass == secondNetclass && bNetclass == firstNetclass ) ) @@ -113,7 +113,7 @@ void MatchSelectors( const std::vector& aSelectors, } else if( candidate->m_MatchNetclasses.size() == 1 ) { - NETCLASS* matchNetclass = candidate->m_MatchNetclasses[0]; + NETCLASS* matchNetclass = candidate->m_MatchNetclasses[0].get(); if( matchNetclass != aNetclass && !( bItem && matchNetclass == bNetclass ) ) continue; diff --git a/pcbnew/drc/drc_rule.h b/pcbnew/drc/drc_rule.h index e715fdeb1b..ca16bc2b98 100644 --- a/pcbnew/drc/drc_rule.h +++ b/pcbnew/drc/drc_rule.h @@ -50,7 +50,7 @@ public: class DRC_SELECTOR { public: - std::vector m_MatchNetclasses; + std::vector m_MatchNetclasses; std::vector m_MatchTypes; std::vector m_MatchLayers; std::vector m_MatchAreas; diff --git a/pcbnew/drc/drc_rule_parser.cpp b/pcbnew/drc/drc_rule_parser.cpp index cb93b6c355..28a8b27d02 100644 --- a/pcbnew/drc/drc_rule_parser.cpp +++ b/pcbnew/drc/drc_rule_parser.cpp @@ -126,9 +126,24 @@ DRC_SELECTOR* DRC_RULES_PARSER::parseDRC_SELECTOR( wxString* aRuleName ) switch( token ) { case T_match_netclass: + { NeedSYMBOL(); - selector->m_MatchNetclasses.push_back( netclasses.Find( FromUTF8() ).get() ); + NETCLASSPTR netclass = netclasses.Find( FromUTF8() ); + + if( netclass ) + { + selector->m_MatchNetclasses.push_back( std::move( netclass ) ); + } + else + { + // Interesting situation here: if we don't inform the user they may have a typo + // and can't figure out why their rules don't work. + // If we do tell them then it gets really noisy if they're using a single rule + // file for a class of board. + } + NeedRIGHT(); + } break; case T_match_type: diff --git a/pcbnew/files.cpp b/pcbnew/files.cpp index 0639d43f88..80570d7992 100644 --- a/pcbnew/files.cpp +++ b/pcbnew/files.cpp @@ -31,7 +31,6 @@ #include #include <3d_viewer/eda_3d_viewer.h> #include -#include #include #include #include @@ -45,10 +44,9 @@ #include #include #include - +#include +#include #include -#include // LEGACY_BOARD_FILE_VERSION - #include #include #include @@ -597,6 +595,8 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, in SetBoard( loadedBoard ); + m_toolManager->GetTool()->LoadRules(); + // we should not ask PLUGINs to do these items: loadedBoard->BuildListOfNets(); loadedBoard->SynchronizeNetsAndNetClasses(); diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp index aa095a533d..9cb2593954 100644 --- a/pcbnew/plot_board_layers.cpp +++ b/pcbnew/plot_board_layers.cpp @@ -859,10 +859,10 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask, zone->GetColinearCorners( aBoard, colinearCorners ); // add shapes inflated by aMinThickness/2 in areas - zone->TransformOutlinesShapeWithClearanceToPolygon( areas, inflate + zone_margin, false, + zone->TransformOutlinesShapeWithClearanceToPolygon( areas, inflate + zone_margin, &colinearCorners ); // add shapes with their exact mask layer size in initialPolys - zone->TransformOutlinesShapeWithClearanceToPolygon( initialPolys, zone_margin, false, + zone->TransformOutlinesShapeWithClearanceToPolygon( initialPolys, zone_margin, &colinearCorners ); } diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp index 936467af0b..dbfd7a3b03 100644 --- a/pcbnew/zone_filler.cpp +++ b/pcbnew/zone_filler.cpp @@ -526,18 +526,13 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, SHAPE_ int extra_margin = Millimeter2iu( 0.002 ); BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); - int zone_clearance = aZone->GetClearance(); - int edge_clearance = aZone->GetClearance( &dummyEdge ); + int zone_clearance = aZone->GetClearance(); + EDA_RECT zone_boundingbox = aZone->GetBoundingBox(); - if( bds.m_CopperEdgeClearance > edge_clearance ) - edge_clearance = bds.m_CopperEdgeClearance; - - // items outside the zone bounding box are skipped - // the bounding box is the zone bounding box + the biggest clearance found in Netclass list - EDA_RECT zone_boundingbox = aZone->GetBoundingBox(); - int biggest_clearance = bds.GetBiggestClearanceValue(); - biggest_clearance = std::max( biggest_clearance, zone_clearance ) + extra_margin; - zone_boundingbox.Inflate( biggest_clearance ); + // items outside the zone bounding box are skipped, so it needs to be inflated by + // the largest clearance value found in the netclasses and rules + int biggest_clearance = std::max( zone_clearance, bds.GetBiggestClearanceValue() ); + zone_boundingbox.Inflate( biggest_clearance + extra_margin ); // Use a dummy pad to calculate hole clearance when a pad has a hole but is not on the // zone's copper layer. The dummy pad has the size and shape of the original pad's hole. @@ -564,25 +559,19 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, SHAPE_ if( pad->GetNetCode() != aZone->GetNetCode() || pad->GetNetCode() <= 0 || aZone->GetPadConnection( pad ) == ZONE_CONNECTION::NONE ) { - // for pads having a netcode different from the zone, use the net clearance: - int gap = std::max( zone_clearance, pad->GetClearance() ); - - // for pads having the same netcode as the zone, the net clearance has no - // meaning (clearance between object of the same net is 0) and the - // zone_clearance can be set to 0 (In this case the netclass clearance is used) - // therefore use the antipad clearance (thermal clearance) or the - // zone_clearance if bigger. - if( pad->GetNetCode() > 0 && pad->GetNetCode() == aZone->GetNetCode() ) + if( pad->GetBoundingBox().Intersects( zone_boundingbox ) ) { - int thermalGap = aZone->GetThermalReliefGap( pad ); - gap = std::max( zone_clearance, thermalGap );; - } + int gap; - EDA_RECT item_boundingbox = pad->GetBoundingBox(); - item_boundingbox.Inflate( pad->GetClearance() ); + // for pads having the same netcode as the zone, the net clearance has no + // meaning so use the greater of the zone clearance and the thermal relief + if( pad->GetNetCode() > 0 && pad->GetNetCode() == aZone->GetNetCode() ) + gap = std::max( zone_clearance, aZone->GetThermalReliefGap( pad ) ); + else + gap = aZone->GetClearance( pad ); - if( item_boundingbox.Intersects( zone_boundingbox ) ) addKnockout( pad, gap, aHoles ); + } } } } @@ -597,38 +586,32 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, SHAPE_ if( track->GetNetCode() == aZone->GetNetCode() && ( aZone->GetNetCode() != 0) ) continue; - int gap = std::max( zone_clearance, track->GetClearance() ) + extra_margin; - EDA_RECT item_boundingbox = track->GetBoundingBox(); + if( track->GetBoundingBox().Intersects( zone_boundingbox ) ) + { + int gap = aZone->GetClearance( track ) + extra_margin; - if( item_boundingbox.Intersects( zone_boundingbox ) ) track->TransformShapeWithClearanceToPolygon( aHoles, gap, m_low_def ); + } } // Add graphic item clearances. They are by definition unconnected, and have no clearance // definitions of their own. // - auto doGraphicItem = [&]( BOARD_ITEM* aItem ) - { - // A item on the Edge_Cuts is always seen as on any layer: - if( !aItem->IsOnLayer( aZone->GetLayer() ) && !aItem->IsOnLayer( Edge_Cuts ) ) - return; + auto doGraphicItem = + [&]( BOARD_ITEM* aItem ) + { + // A item on the Edge_Cuts is always seen as on any layer: + if( !aItem->IsOnLayer( aZone->GetLayer() ) && !aItem->IsOnLayer( Edge_Cuts ) ) + return; - if( !aItem->GetBoundingBox().Intersects( zone_boundingbox ) ) - return; + if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) ) + { + bool ignoreLineWidth = aItem->IsOnLayer( Edge_Cuts ); + int gap = aZone->GetClearance( aItem ); - bool ignoreLineWidth = false; - int gap = zone_clearance; - - if( aItem->IsOnLayer( Edge_Cuts ) ) - { - gap = edge_clearance; - - // edge cuts by definition don't have a width - ignoreLineWidth = true; - } - - addKnockout( aItem, gap, ignoreLineWidth, aHoles ); - }; + addKnockout( aItem, gap, ignoreLineWidth, aHoles ); + } + }; for( auto module : m_board->Modules() ) { @@ -660,26 +643,18 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, SHAPE_ // A higher priority zone or keepout area is found: remove this area EDA_RECT item_boundingbox = zone->GetBoundingBox(); - if( !item_boundingbox.Intersects( zone_boundingbox ) ) - continue; - - // Add the zone outline area. Don't use any clearance for keepouts, or for zones with - // the same net (they will be connected but will honor their own clearance, thermal - // connections, etc.). - bool sameNet = aZone->GetNetCode() == zone->GetNetCode(); - bool useNetClearance = true; - int minClearance = zone_clearance; - - // The final clearance is obviously the max value of each zone clearance - minClearance = std::max( minClearance, zone->GetClearance() ); - - if( zone->GetIsKeepout() || sameNet ) + if( item_boundingbox.Intersects( zone_boundingbox ) ) { - minClearance = 0; - useNetClearance = false; - } + // Add the zone outline area. Don't use any clearance for keepouts, or for zones + // with the same net (they will be connected but will honor their own clearance, + // thermal connections, etc.). + int gap = 0; - zone->TransformOutlinesShapeWithClearanceToPolygon( aHoles, minClearance, useNetClearance ); + if( !zone->GetIsKeepout() && aZone->GetNetCode() != zone->GetNetCode() ) + gap = aZone->GetClearance( zone ); + + zone->TransformOutlinesShapeWithClearanceToPolygon( aHoles, gap ); + } } aHoles.Simplify( SHAPE_POLY_SET::PM_FAST );