Complete hookup of zone filler to new clearance engine.

This commit is contained in:
Jeff Young 2020-05-18 17:11:57 +01:00
parent d7bd4c9b04
commit cec857c0f4
12 changed files with 123 additions and 143 deletions

View File

@ -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; return clearance;
} }

View File

@ -1019,12 +1019,16 @@ int BOARD_DESIGN_SETTINGS::GetRuleClearance( const BOARD_ITEM* aItem, const NETC
if( selector->m_Rule->m_Clearance > 0 ) if( selector->m_Rule->m_Clearance > 0 )
{ {
clearance = std::max( clearance, selector->m_Rule->m_Clearance ); 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 ) else if( selector->m_Rule->m_Clearance < 0 )
{ {
clearance = std::min( clearance, abs( selector->m_Rule->m_Clearance ) ); 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 );
} }
} }

View File

@ -463,22 +463,17 @@ int ZONE_CONTAINER::GetClearance( BOARD_ITEM* aItem, wxString* aSource ) const
if( m_isKeepout ) if( m_isKeepout )
return 0; 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 ); int clearance = BOARD_CONNECTED_ITEM::GetClearance( aItem, aSource );
if( clearance > zoneClearance ) if( m_ZoneClearance > clearance )
{
return clearance;
}
else
{ {
clearance = m_ZoneClearance;
if( aSource ) if( aSource )
*aSource = _( "zone clearance" ); *aSource = _( "zone clearance" );
return zoneClearance;
} }
return clearance;
} }
@ -1137,35 +1132,19 @@ double ZONE_CONTAINER::CalculateFilledArea()
* Convert the zone filled areas polygons to polygons * Convert the zone filled areas polygons to polygons
* inflated (optional) by max( aClearanceValue, the zone clearance) * inflated (optional) by max( aClearanceValue, the zone clearance)
* and copy them in aCornerBuffer * and copy them in aCornerBuffer
* @param aMinClearanceValue the min clearance around outlines * @param aClearance the clearance around outlines
* @param aUseNetClearance true to use a clearance which is the max value between * @param aPreserveCorners an optional set of corners which should not be chamfered/filleted
* aMinClearanceValue and the net clearance
* false to use aMinClearanceValue only
* @param aPreserveCorners an optional set of corners which should not be chamfered/filleted
*/ */
void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aMinClearanceValue, int aClearance, std::set<VECTOR2I>* aPreserveCorners ) const
bool aUseNetClearance,
std::set<VECTOR2I>* aPreserveCorners ) const
{ {
// Creates the zone outline polygon (with holes if any) // Creates the zone outline polygon (with holes if any)
SHAPE_POLY_SET polybuffer; SHAPE_POLY_SET polybuffer;
BuildSmoothedPoly( polybuffer, aPreserveCorners ); 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 // Calculate the polygon with clearance
// holes are linked to the main outline, so only one polygon is created. // holes are linked to the main outline, so only one polygon is created.
if( clearance ) if( aClearance )
{ {
BOARD* board = GetBoard(); BOARD* board = GetBoard();
int maxError = ARC_HIGH_DEF; int maxError = ARC_HIGH_DEF;
@ -1173,8 +1152,8 @@ void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon( SHAPE_POLY_SE
if( board ) if( board )
maxError = board->GetDesignSettings().m_MaxError; maxError = board->GetDesignSettings().m_MaxError;
int segCount = std::max( GetArcToSegmentCount( clearance, maxError, 360.0 ), 3 ); int segCount = std::max( GetArcToSegmentCount( aClearance, maxError, 360.0 ), 3 );
polybuffer.Inflate( clearance, segCount ); polybuffer.Inflate( aClearance, segCount );
} }
polybuffer.Fracture( SHAPE_POLY_SET::PM_FAST ); polybuffer.Fracture( SHAPE_POLY_SET::PM_FAST );

View File

@ -316,8 +316,7 @@ public:
* if both aMinClearanceValue = 0 and aUseNetClearance = false: create the zone outline polygon. * if both aMinClearanceValue = 0 and aUseNetClearance = false: create the zone outline polygon.
*/ */
void TransformOutlinesShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, void TransformOutlinesShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aMinClearanceValue, bool aUseNetClearance, int aMinClearanceValue, std::set<VECTOR2I>* aPreserveCorners = nullptr ) const;
std::set<VECTOR2I>* aPreserveCorners = nullptr ) const;
/** /**
* Function TransformShapeWithClearanceToPolygon * Function TransformShapeWithClearanceToPolygon

View File

@ -66,7 +66,7 @@ DRC::DRC() :
m_pcbEditorFrame( nullptr ), m_pcbEditorFrame( nullptr ),
m_pcb( nullptr ), m_pcb( nullptr ),
m_drcDialog( nullptr ), m_drcDialog( nullptr ),
m_rulesFileLastMod( 0 ) m_largestClearance( 0 )
{ {
// establish initial values for everything: // establish initial values for everything:
m_doPad2PadTest = true; // enable pad to pad clearance tests m_doPad2PadTest = true; // enable pad to pad clearance tests
@ -103,8 +103,6 @@ void DRC::Reset( RESET_REASON aReason )
m_pcb = m_pcbEditorFrame->GetBoard(); 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" ); wxString rulesFilepath = m_pcbEditorFrame->Prj().AbsolutePath( "drc-rules" );
wxFileName rulesFile( rulesFilepath ); wxFileName rulesFile( rulesFilepath );
if( rulesFile.FileExists() ) 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; try
m_ruleSelectors.clear();
m_rules.clear();
FILE* fp = wxFopen( rulesFilepath, wxT( "rt" ) );
if( fp )
{ {
try DRC_RULES_PARSER parser( m_pcb, fp, rulesFilepath );
{ parser.Parse( m_ruleSelectors, m_rules );
DRC_RULES_PARSER parser( m_pcb, fp, rulesFilepath ); }
parser.Parse( m_ruleSelectors, m_rules ); catch( PARSE_ERROR& pe )
} {
catch( PARSE_ERROR& pe ) // Don't leave possibly malformed stuff around for us to trip over
{ m_ruleSelectors.clear();
// Don't leave possibly malformed stuff around for us to trip over m_rules.clear();
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 ) void DRC::RunTests( wxTextCtrl* aMessages )
{ {
loadRules(); // Make absolutely sure these are up-to-date
LoadRules();
wxASSERT( m_pcb == m_pcbEditorFrame->GetBoard() ); wxASSERT( m_pcb == m_pcbEditorFrame->GetBoard() );

View File

@ -170,7 +170,6 @@ private:
bool m_drcRun; bool m_drcRun;
bool m_footprintsTested; bool m_footprintsTested;
wxLongLong m_rulesFileLastMod;
std::vector<DRC_SELECTOR*> m_ruleSelectors; std::vector<DRC_SELECTOR*> m_ruleSelectors;
std::vector<DRC_RULE*> m_rules; std::vector<DRC_RULE*> m_rules;
@ -189,8 +188,6 @@ private:
*/ */
void updatePointers(); void updatePointers();
void loadRules();
EDA_UNITS userUnits() const { return m_pcbEditorFrame->GetUserUnits(); } EDA_UNITS userUnits() const { return m_pcbEditorFrame->GetUserUnits(); }
/** /**
@ -296,6 +293,11 @@ private:
//-----</single tests>--------------------------------------------- //-----</single tests>---------------------------------------------
public: 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, * Test the board footprints against a netlist. Will report DRCE_MISSING_FOOTPRINT,
* DRCE_DUPLICATE_FOOTPRINT and DRCE_EXTRA_FOOTPRINT errors in aDRCList. * DRCE_DUPLICATE_FOOTPRINT and DRCE_EXTRA_FOOTPRINT errors in aDRCList.

View File

@ -102,8 +102,8 @@ void MatchSelectors( const std::vector<DRC_SELECTOR*>& aSelectors,
if( !bItem ) if( !bItem )
continue; continue;
NETCLASS* firstNetclass = candidate->m_MatchNetclasses[0]; NETCLASS* firstNetclass = candidate->m_MatchNetclasses[0].get();
NETCLASS* secondNetclass = candidate->m_MatchNetclasses[1]; NETCLASS* secondNetclass = candidate->m_MatchNetclasses[1].get();
if( !( aNetclass == firstNetclass && bNetclass == secondNetclass ) if( !( aNetclass == firstNetclass && bNetclass == secondNetclass )
&& !( aNetclass == secondNetclass && bNetclass == firstNetclass ) ) && !( aNetclass == secondNetclass && bNetclass == firstNetclass ) )
@ -113,7 +113,7 @@ void MatchSelectors( const std::vector<DRC_SELECTOR*>& aSelectors,
} }
else if( candidate->m_MatchNetclasses.size() == 1 ) 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 ) ) if( matchNetclass != aNetclass && !( bItem && matchNetclass == bNetclass ) )
continue; continue;

View File

@ -50,7 +50,7 @@ public:
class DRC_SELECTOR class DRC_SELECTOR
{ {
public: public:
std::vector<NETCLASS*> m_MatchNetclasses; std::vector<NETCLASSPTR> m_MatchNetclasses;
std::vector<KICAD_T> m_MatchTypes; std::vector<KICAD_T> m_MatchTypes;
std::vector<PCB_LAYER_ID> m_MatchLayers; std::vector<PCB_LAYER_ID> m_MatchLayers;
std::vector<wxString> m_MatchAreas; std::vector<wxString> m_MatchAreas;

View File

@ -126,9 +126,24 @@ DRC_SELECTOR* DRC_RULES_PARSER::parseDRC_SELECTOR( wxString* aRuleName )
switch( token ) switch( token )
{ {
case T_match_netclass: case T_match_netclass:
{
NeedSYMBOL(); 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(); NeedRIGHT();
}
break; break;
case T_match_type: case T_match_type:

View File

@ -31,7 +31,6 @@
#include <macros.h> #include <macros.h>
#include <3d_viewer/eda_3d_viewer.h> #include <3d_viewer/eda_3d_viewer.h>
#include <richio.h> #include <richio.h>
#include <filter_reader.h>
#include <pgm_base.h> #include <pgm_base.h>
#include <msgpanel.h> #include <msgpanel.h>
#include <fp_lib_table.h> #include <fp_lib_table.h>
@ -45,10 +44,9 @@
#include <pcbnew_id.h> #include <pcbnew_id.h>
#include <io_mgr.h> #include <io_mgr.h>
#include <wildcards_and_files_ext.h> #include <wildcards_and_files_ext.h>
#include <tool/tool_manager.h>
#include <drc/drc.h>
#include <class_board.h> #include <class_board.h>
#include <build_version.h> // LEGACY_BOARD_FILE_VERSION
#include <wx/stdpaths.h> #include <wx/stdpaths.h>
#include <pcb_layer_widget.h> #include <pcb_layer_widget.h>
#include <wx/wupdlock.h> #include <wx/wupdlock.h>
@ -597,6 +595,8 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
SetBoard( loadedBoard ); SetBoard( loadedBoard );
m_toolManager->GetTool<DRC>()->LoadRules();
// we should not ask PLUGINs to do these items: // we should not ask PLUGINs to do these items:
loadedBoard->BuildListOfNets(); loadedBoard->BuildListOfNets();
loadedBoard->SynchronizeNetsAndNetClasses(); loadedBoard->SynchronizeNetsAndNetClasses();

View File

@ -859,10 +859,10 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
zone->GetColinearCorners( aBoard, colinearCorners ); zone->GetColinearCorners( aBoard, colinearCorners );
// add shapes inflated by aMinThickness/2 in areas // add shapes inflated by aMinThickness/2 in areas
zone->TransformOutlinesShapeWithClearanceToPolygon( areas, inflate + zone_margin, false, zone->TransformOutlinesShapeWithClearanceToPolygon( areas, inflate + zone_margin,
&colinearCorners ); &colinearCorners );
// add shapes with their exact mask layer size in initialPolys // add shapes with their exact mask layer size in initialPolys
zone->TransformOutlinesShapeWithClearanceToPolygon( initialPolys, zone_margin, false, zone->TransformOutlinesShapeWithClearanceToPolygon( initialPolys, zone_margin,
&colinearCorners ); &colinearCorners );
} }

View File

@ -526,18 +526,13 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, SHAPE_
int extra_margin = Millimeter2iu( 0.002 ); int extra_margin = Millimeter2iu( 0.002 );
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
int zone_clearance = aZone->GetClearance(); int zone_clearance = aZone->GetClearance();
int edge_clearance = aZone->GetClearance( &dummyEdge ); EDA_RECT zone_boundingbox = aZone->GetBoundingBox();
if( bds.m_CopperEdgeClearance > edge_clearance ) // items outside the zone bounding box are skipped, so it needs to be inflated by
edge_clearance = bds.m_CopperEdgeClearance; // the largest clearance value found in the netclasses and rules
int biggest_clearance = std::max( zone_clearance, bds.GetBiggestClearanceValue() );
// items outside the zone bounding box are skipped zone_boundingbox.Inflate( biggest_clearance + extra_margin );
// 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 );
// Use a dummy pad to calculate hole clearance when a pad has a hole but is not on the // 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. // 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 if( pad->GetNetCode() != aZone->GetNetCode() || pad->GetNetCode() <= 0
|| aZone->GetPadConnection( pad ) == ZONE_CONNECTION::NONE ) || aZone->GetPadConnection( pad ) == ZONE_CONNECTION::NONE )
{ {
// for pads having a netcode different from the zone, use the net clearance: if( pad->GetBoundingBox().Intersects( zone_boundingbox ) )
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() )
{ {
int thermalGap = aZone->GetThermalReliefGap( pad ); int gap;
gap = std::max( zone_clearance, thermalGap );;
}
EDA_RECT item_boundingbox = pad->GetBoundingBox(); // for pads having the same netcode as the zone, the net clearance has no
item_boundingbox.Inflate( pad->GetClearance() ); // 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 ); 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) ) if( track->GetNetCode() == aZone->GetNetCode() && ( aZone->GetNetCode() != 0) )
continue; continue;
int gap = std::max( zone_clearance, track->GetClearance() ) + extra_margin; if( track->GetBoundingBox().Intersects( zone_boundingbox ) )
EDA_RECT item_boundingbox = track->GetBoundingBox(); {
int gap = aZone->GetClearance( track ) + extra_margin;
if( item_boundingbox.Intersects( zone_boundingbox ) )
track->TransformShapeWithClearanceToPolygon( aHoles, gap, m_low_def ); track->TransformShapeWithClearanceToPolygon( aHoles, gap, m_low_def );
}
} }
// Add graphic item clearances. They are by definition unconnected, and have no clearance // Add graphic item clearances. They are by definition unconnected, and have no clearance
// definitions of their own. // definitions of their own.
// //
auto doGraphicItem = [&]( BOARD_ITEM* aItem ) 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 ) ) // A item on the Edge_Cuts is always seen as on any layer:
return; if( !aItem->IsOnLayer( aZone->GetLayer() ) && !aItem->IsOnLayer( Edge_Cuts ) )
return;
if( !aItem->GetBoundingBox().Intersects( zone_boundingbox ) ) if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
return; {
bool ignoreLineWidth = aItem->IsOnLayer( Edge_Cuts );
int gap = aZone->GetClearance( aItem );
bool ignoreLineWidth = false; addKnockout( aItem, gap, ignoreLineWidth, aHoles );
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 );
};
for( auto module : m_board->Modules() ) 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 // A higher priority zone or keepout area is found: remove this area
EDA_RECT item_boundingbox = zone->GetBoundingBox(); EDA_RECT item_boundingbox = zone->GetBoundingBox();
if( !item_boundingbox.Intersects( zone_boundingbox ) ) 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 )
{ {
minClearance = 0; // Add the zone outline area. Don't use any clearance for keepouts, or for zones
useNetClearance = false; // 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 ); aHoles.Simplify( SHAPE_POLY_SET::PM_FAST );