Performance enhancements for DRC.

This commit is contained in:
Jeff Young 2020-05-18 01:20:16 +01:00
parent d72a778f19
commit 05855a5a1c
31 changed files with 1181 additions and 953 deletions

View File

@ -214,6 +214,9 @@ public:
std::vector<DRC_SELECTOR*> m_DRCRuleSelectors; std::vector<DRC_SELECTOR*> m_DRCRuleSelectors;
std::vector<DRC_RULE*> m_DRCRules; std::vector<DRC_RULE*> m_DRCRules;
// Temporary storage for rule matching.
std::vector<DRC_SELECTOR*> m_matched;
bool m_MicroViasAllowed; ///< true to allow micro vias bool m_MicroViasAllowed; ///< true to allow micro vias
bool m_BlindBuriedViaAllowed; ///< true to allow blind/buried vias bool m_BlindBuriedViaAllowed; ///< true to allow blind/buried vias
VIATYPE m_CurrentViaType; ///< (VIA_BLIND_BURIED, VIA_THROUGH, VIA_MICROVIA) VIATYPE m_CurrentViaType; ///< (VIA_BLIND_BURIED, VIA_THROUGH, VIA_MICROVIA)
@ -331,9 +334,9 @@ public:
* Function GetDefault * Function GetDefault
* @return the default netclass. * @return the default netclass.
*/ */
inline NETCLASSPTR GetDefault() const inline NETCLASS* GetDefault() const
{ {
return m_NetClasses.GetDefault(); return m_NetClasses.GetDefaultPtr();
} }
/** /**

View File

@ -234,6 +234,9 @@ set( PCBNEW_MICROWAVE_SRCS
set( PCBNEW_DRC_SRCS set( PCBNEW_DRC_SRCS
drc/drc_courtyard_tester.cpp drc/drc_courtyard_tester.cpp
drc/drc_drilled_hole_tester.cpp drc/drc_drilled_hole_tester.cpp
drc/drc_keepout_tester.cpp
drc/drc_netclass_tester.cpp
drc/drc_textvar_tester.cpp
drc/drc.cpp drc/drc.cpp
drc/drc_clearance_test_functions.cpp drc/drc_clearance_test_functions.cpp
drc/drc_rule_parser.cpp drc/drc_rule_parser.cpp

View File

@ -81,57 +81,56 @@ bool BOARD_CONNECTED_ITEM::SetNetCode( int aNetCode, bool aNoAssert )
int BOARD_CONNECTED_ITEM::GetClearance( BOARD_ITEM* aItem, wxString* aSource ) const int BOARD_CONNECTED_ITEM::GetClearance( BOARD_ITEM* aItem, wxString* aSource ) const
{ {
BOARD* board = GetBoard();
// No clearance if "this" is not (yet) linked to a board therefore no available netclass
if( !board )
return 0;
BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings();
NETCLASS* myNetclass = nullptr; NETCLASS* myNetclass = nullptr;
NETCLASS* itemNetclass = nullptr; NETCLASS* itemNetclass = nullptr;
BOARD_DESIGN_SETTINGS* bds = nullptr;
// NB: we must check the net first, as when it is 0 GetNetClass() will return the // NB: we must check the net first, as when it is 0 GetNetClass() will return the
// orphaned net netclass, not the default netclass. // orphaned net netclass, not the default netclass.
if( GetBoard() ) if( m_netinfo->GetNet() == 0 )
myNetclass = bds.GetDefault();
else
myNetclass = GetNetClass();
if( aItem && aItem->IsConnected() )
{ {
if( m_netinfo->GetNet() == 0 ) if( static_cast<BOARD_CONNECTED_ITEM*>( aItem )->GetNet()->GetNet() == 0 )
myNetclass = GetBoard()->GetDesignSettings().GetDefault().get(); itemNetclass = bds.GetDefault();
else else
myNetclass = GetNetClass().get(); itemNetclass = static_cast<BOARD_CONNECTED_ITEM*>( aItem )->GetNetClass();
bds = &GetBoard()->GetDesignSettings();
}
// No clearance if "this" is not (yet) linked to a board therefore no available netclass
if( aItem && aItem->GetBoard() && dynamic_cast<BOARD_CONNECTED_ITEM*>( aItem ) )
{
if( dynamic_cast<BOARD_CONNECTED_ITEM*>( aItem )->GetNet()->GetNet() == 0 )
itemNetclass = GetBoard()->GetDesignSettings().GetDefault().get();
else
itemNetclass = dynamic_cast<BOARD_CONNECTED_ITEM*>( aItem )->GetNetClass().get();
bds = &aItem->GetBoard()->GetDesignSettings();
} }
int myClearance = myNetclass ? myNetclass->GetClearance() : 0; int clearance = bds.GetRuleClearance( this, myNetclass, aItem, itemNetclass, aSource );
int itemClearance = itemNetclass ? itemNetclass->GetClearance() : 0;
wxString ruleSource;
int ruleClearance = bds ? bds->GetRuleClearance( this, myNetclass,
aItem, itemNetclass, &ruleSource ) : 0;
int clearance = std::max( std::max( myClearance, itemClearance ), ruleClearance );
if( aSource ) if( myNetclass )
{ {
if( clearance == myClearance && myNetclass ) int myClearance = myNetclass->GetClearance();
if( myClearance > clearance )
{ {
*aSource = wxString::Format( _( "'%s' netclass clearance" ), myNetclass->GetName() ); clearance = myClearance;
if( aSource )
*aSource = wxString::Format( _( "'%s' netclass clearance" ), myNetclass->GetName() );
} }
else if( clearance == itemClearance && itemNetclass ) }
if( itemNetclass )
{
int itemClearance = myNetclass->GetClearance();
if( itemClearance > clearance )
{ {
*aSource = wxString::Format( _( "'%s' netclass clearance" ), itemNetclass->GetName() ); clearance = itemClearance;
}
else if( clearance == ruleClearance && !ruleSource.IsEmpty() ) if( aSource )
{ *aSource = wxString::Format( _( "'%s' netclass clearance" ), itemNetclass->GetName() );
*aSource = wxString::Format( _( "'%s' rule clearance" ), ruleSource );
}
else
{
*aSource = _( "No netclass" );
} }
} }
@ -139,9 +138,11 @@ int BOARD_CONNECTED_ITEM::GetClearance( BOARD_ITEM* aItem, wxString* aSource ) c
} }
NETCLASSPTR BOARD_CONNECTED_ITEM::GetNetClass() const // Note: do NOT return a std::shared_ptr from this. It is used heavily in DRC, and the
// std::shared_ptr stuff shows up large in performance profiling.
NETCLASS* BOARD_CONNECTED_ITEM::GetNetClass() const
{ {
NETCLASSPTR netclass = m_netinfo->GetNetClass(); NETCLASS* netclass = m_netinfo->GetNetClass();
if( netclass ) if( netclass )
return netclass; return netclass;

View File

@ -163,11 +163,14 @@ public:
*/ */
virtual int GetClearance( BOARD_ITEM* aItem = nullptr, wxString* aSource = nullptr ) const; virtual int GetClearance( BOARD_ITEM* aItem = nullptr, wxString* aSource = nullptr ) const;
/** /**
* Function GetNetClass * Function GetNetClassPtr
* returns the NETCLASS for this item. * returns the NETCLASS for this item.
*/ *
std::shared_ptr<NETCLASS> GetNetClass() const; * Note: do NOT return a std::shared_ptr from this. It is used heavily in DRC, and the
* std::shared_ptr stuff shows up large in performance profiling.
*/
NETCLASS* GetNetClass() const;
/** /**
* Function GetNetClassName * Function GetNetClassName

View File

@ -961,9 +961,9 @@ bool BOARD_DESIGN_SETTINGS::SetCurrentNetClass( const wxString& aNetClassName )
int BOARD_DESIGN_SETTINGS::GetBiggestClearanceValue() int BOARD_DESIGN_SETTINGS::GetBiggestClearanceValue()
{ {
int clearance = m_NetClasses.GetDefault()->GetClearance(); int clearance = GetDefault()->GetClearance();
for( const std::pair<wxString, NETCLASSPTR>& netclass : m_NetClasses.NetClasses() ) for( const std::pair<const wxString, NETCLASSPTR>& netclass : m_NetClasses.NetClasses() )
clearance = std::max( clearance, netclass.second->GetClearance() ); clearance = std::max( clearance, netclass.second->GetClearance() );
for( const DRC_RULE* rule : m_DRCRules ) for( const DRC_RULE* rule : m_DRCRules )
@ -975,9 +975,9 @@ int BOARD_DESIGN_SETTINGS::GetBiggestClearanceValue()
int BOARD_DESIGN_SETTINGS::GetSmallestClearanceValue() int BOARD_DESIGN_SETTINGS::GetSmallestClearanceValue()
{ {
int clearance = m_NetClasses.GetDefault()->GetClearance(); int clearance = GetDefault()->GetClearance();
for( const std::pair<wxString, NETCLASSPTR>& netclass : m_NetClasses.NetClasses() ) for( const std::pair<const wxString, NETCLASSPTR>& netclass : m_NetClasses.NetClasses() )
clearance = std::min( clearance, netclass.second->GetClearance() ); clearance = std::min( clearance, netclass.second->GetClearance() );
return clearance; return clearance;
@ -988,11 +988,18 @@ int BOARD_DESIGN_SETTINGS::GetRuleClearance( const BOARD_ITEM* aItem, const NETC
const BOARD_ITEM* bItem, const NETCLASS* bNetclass, const BOARD_ITEM* bItem, const NETCLASS* bNetclass,
wxString* aSource ) wxString* aSource )
{ {
std::vector<DRC_SELECTOR*> matched; if( !m_matched.empty() )
m_matched.clear(); // yes, the difference can be seen in profiles
MatchSelectors( m_DRCRuleSelectors, aItem, aNetclass, bItem, bNetclass, &matched ); if( m_DRCRuleSelectors.size() == 0 )
return 0;
std::sort( matched.begin(), matched.end(), MatchSelectors( m_DRCRuleSelectors, aItem, aNetclass, bItem, bNetclass, &m_matched );
if( m_matched.size() == 0 )
return 0;
std::sort( m_matched.begin(), m_matched.end(),
[]( DRC_SELECTOR* a, DRC_SELECTOR* b ) -> bool []( DRC_SELECTOR* a, DRC_SELECTOR* b ) -> bool
{ {
return a->m_Priority < b->m_Priority; return a->m_Priority < b->m_Priority;
@ -1000,7 +1007,7 @@ int BOARD_DESIGN_SETTINGS::GetRuleClearance( const BOARD_ITEM* aItem, const NETC
int clearance = 0; int clearance = 0;
for( DRC_SELECTOR* selector : matched ) for( DRC_SELECTOR* selector : m_matched )
{ {
// ignore hole rules; we're just interested in copper here // ignore hole rules; we're just interested in copper here
for( KICAD_T matchType : selector->m_MatchTypes ) for( KICAD_T matchType : selector->m_MatchTypes )
@ -1012,12 +1019,12 @@ 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 = selector->m_Rule->m_Name; *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 = selector->m_Rule->m_Name; *aSource = wxString::Format( _( "'%s' rule clearance" ), selector->m_Rule->m_Name );
} }
} }

View File

@ -124,7 +124,7 @@ BOARD::BOARD() :
} }
// Initialize default netclass. // Initialize default netclass.
NETCLASSPTR defaultClass = m_designSettings.GetDefault(); NETCLASS* defaultClass = m_designSettings.GetDefault();
defaultClass->SetDescription( _( "This is the default net class." ) ); defaultClass->SetDescription( _( "This is the default net class." ) );
m_designSettings.SetCurrentNetClass( defaultClass->GetName() ); m_designSettings.SetCurrentNetClass( defaultClass->GetName() );
@ -752,6 +752,9 @@ BOARD_ITEM* BOARD::GetItem( const KIID& aID )
if( marker->m_Uuid == aID ) if( marker->m_Uuid == aID )
return marker; return marker;
if( m_Uuid == aID )
return this;
// Not found; weak reference has been deleted. // Not found; weak reference has been deleted.
if( !g_DeletedItem ) if( !g_DeletedItem )
g_DeletedItem = new DELETED_BOARD_ITEM(); g_DeletedItem = new DELETED_BOARD_ITEM();

View File

@ -131,7 +131,7 @@ int VIA::GetDrillValue() const
return m_Drill; return m_Drill;
// Use the default value from the Netclass // Use the default value from the Netclass
NETCLASSPTR netclass = GetNetClass(); NETCLASS* netclass = GetNetClass();
if( GetViaType() == VIATYPE::MICROVIA ) if( GetViaType() == VIATYPE::MICROVIA )
return netclass->GetuViaDrill(); return netclass->GetuViaDrill();
@ -540,7 +540,7 @@ void TRACK::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>
} }
} }
NETCLASSPTR netclass = GetNetClass(); NETCLASS* netclass = GetNetClass();
if( netclass ) if( netclass )
{ {

View File

@ -465,15 +465,11 @@ int ZONE_CONTAINER::GetClearance( BOARD_ITEM* aItem, wxString* aSource ) const
// The actual zone clearance is the biggest of the zone netclass clearance // The actual zone clearance is the biggest of the zone netclass clearance
// and the zone clearance setting in the zone properties dialog. // and the zone clearance setting in the zone properties dialog.
int zoneClearance = m_ZoneClearance; int zoneClearance = m_ZoneClearance;
wxString source; int clearance = BOARD_CONNECTED_ITEM::GetClearance( aItem, aSource );
int clearance = BOARD_CONNECTED_ITEM::GetClearance( aItem, &source );
if( clearance > zoneClearance ) if( clearance > zoneClearance )
{ {
if( aSource )
*aSource = source;
return clearance; return clearance;
} }
else else

View File

@ -170,7 +170,7 @@ void DIALOG_GLOBAL_EDIT_TRACKS_AND_VIAS::buildFilterLists()
wxArrayString netclassNames; wxArrayString netclassNames;
NETCLASSES& netclasses = m_brd->GetDesignSettings().m_NetClasses; NETCLASSES& netclasses = m_brd->GetDesignSettings().m_NetClasses;
netclassNames.push_back(netclasses.GetDefault()->GetName() ); netclassNames.push_back( netclasses.GetDefaultPtr()->GetName() );
for( NETCLASSES::const_iterator nc = netclasses.begin(); nc != netclasses.end(); ++nc ) for( NETCLASSES::const_iterator nc = netclasses.begin(); nc != netclasses.end(); ++nc )
netclassNames.push_back( nc->second->GetName() ); netclassNames.push_back( nc->second->GetName() );
@ -199,7 +199,7 @@ void DIALOG_GLOBAL_EDIT_TRACKS_AND_VIAS::buildNetclassesGrid()
m_netclassGrid->SetCellValue( 0, GRID_uVIADRILL, _( "uVia Drill" ) ); m_netclassGrid->SetCellValue( 0, GRID_uVIADRILL, _( "uVia Drill" ) );
NETCLASSES& netclasses = m_brd->GetDesignSettings().m_NetClasses; NETCLASSES& netclasses = m_brd->GetDesignSettings().m_NetClasses;
NETCLASSPTR defaultNetclass = m_brd->GetDesignSettings().GetDefault(); NETCLASS* defaultNetclass = m_brd->GetDesignSettings().GetDefault();
m_netclassGrid->AppendRows( netclasses.GetCount() + 1 ); m_netclassGrid->AppendRows( netclasses.GetCount() + 1 );
m_netclassGrid->SetCellValue( 1, GRID_NAME, defaultNetclass->GetName() ); m_netclassGrid->SetCellValue( 1, GRID_NAME, defaultNetclass->GetName() );

File diff suppressed because it is too large Load Diff

View File

@ -25,6 +25,7 @@
#ifndef DRC_H #ifndef DRC_H
#define DRC_H #define DRC_H
#include <board_commit.h>
#include <class_board.h> #include <class_board.h>
#include <class_track.h> #include <class_track.h>
#include <class_marker_pcb.h> #include <class_marker_pcb.h>
@ -173,6 +174,13 @@ private:
std::vector<DRC_SELECTOR*> m_ruleSelectors; std::vector<DRC_SELECTOR*> m_ruleSelectors;
std::vector<DRC_RULE*> m_rules; std::vector<DRC_RULE*> m_rules;
// wxString's c'tor is surprisingly expensive, and in the world of DRC everything matters
wxString m_msg;
wxString m_clearanceSource;
// Used during a single DRC run
int m_largestClearance;
///> Sets up handlers for various events. ///> Sets up handlers for various events.
void setTransitions() override; void setTransitions() override;
@ -188,26 +196,16 @@ private:
/** /**
* Adds a DRC marker to the PCB through the COMMIT mechanism. * Adds a DRC marker to the PCB through the COMMIT mechanism.
*/ */
void addMarkerToPcb( MARKER_PCB* aMarker ); void addMarkerToPcb( BOARD_COMMIT& aCommit, MARKER_PCB* aMarker );
/**
* Fetches a reasonable point for marking a violoation between two non-point objects.
*/
wxPoint getLocation( TRACK* aTrack, ZONE_CONTAINER* aConflictZone ) const;
wxPoint getLocation( TRACK* aTrack, const SEG& aConflictSeg ) const;
//-----<categorical group tests>----------------------------------------- //-----<categorical group tests>-----------------------------------------
/** /**
* Go through each NETCLASS and verifies that its clearance, via size, track width, and * Tests whether distance between zones complies with the DRC rules.
* track clearance are larger than those in board.m_designSettings. *
* This is necessary because the actual DRC checks are run against the NETCLASS * @return Errors count
* limits, so in order enforce global limits, we first check the NETCLASSes against
* the global limits.
* @return bool - true if succes, else false but only after
* reporting _all_ NETCLASS violations.
*/ */
bool testNetClasses(); int testZoneToZoneOutlines( BOARD_COMMIT& aCommit );
/** /**
* Perform the DRC on all tracks. * Perform the DRC on all tracks.
@ -217,40 +215,28 @@ private:
* @param aShowProgressBar = true to show a progress bar * @param aShowProgressBar = true to show a progress bar
* (Note: it is shown only if there are many tracks) * (Note: it is shown only if there are many tracks)
*/ */
void testTracks( wxWindow * aActiveWindow, bool aShowProgressBar ); void testTracks( BOARD_COMMIT& aCommit, wxWindow * aActiveWindow, bool aShowProgressBar );
void testPad2Pad(); void testPad2Pad( BOARD_COMMIT& aCommit );
void testDrilledHoles();
void testUnconnected(); void testUnconnected();
void testZones(); void testZones( BOARD_COMMIT& aCommit );
void testKeepoutAreas(); void testCopperDrawItem( BOARD_COMMIT& aCommit, BOARD_ITEM* aDrawing );
// aTextItem is type BOARD_ITEM* to accept either TEXTE_PCB or TEXTE_MODULE void testCopperTextAndGraphics( BOARD_COMMIT& aCommit );
void testCopperTextItem( BOARD_ITEM* aTextItem );
void testCopperDrawItem( DRAWSEGMENT* aDrawing );
void testCopperTextAndGraphics();
// Tests for items placed on disabled layers (causing false connections). // Tests for items placed on disabled layers (causing false connections).
void testDisabledLayers(); void testDisabledLayers( BOARD_COMMIT& aCommit );
// Test for any unresolved text variable references
void testTextVars();
/** /**
* Test that the board outline is contiguous and composed of valid elements * Test that the board outline is contiguous and composed of valid elements
*/ */
void testOutline(); void testOutline( BOARD_COMMIT& aCommit );
//-----<single "item" tests>----------------------------------------- //-----<single "item" tests>-----------------------------------------
bool doNetClass( const std::shared_ptr<NETCLASS>& aNetClass, wxString& msg );
/** /**
* Test the clearance between aRefPad and other pads. * Test the clearance between aRefPad and other pads.
* *
@ -263,7 +249,8 @@ private:
* (i.e. when the current pad pos X in list exceeds this limit, because the list * (i.e. when the current pad pos X in list exceeds this limit, because the list
* is sorted by X coordinate) * is sorted by X coordinate)
*/ */
bool doPadToPadsDrc( D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd, int x_limit ); bool doPadToPadsDrc( BOARD_COMMIT& aCommit, D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd,
int x_limit );
/** /**
* Test the current segment. * Test the current segment.
@ -275,13 +262,8 @@ private:
* @return bool - true if no problems, else false and m_currentMarker is * @return bool - true if no problems, else false and m_currentMarker is
* filled in with the problem information. * filled in with the problem information.
*/ */
void doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterator aEndIt, void doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
bool aTestZones ); TRACKS::iterator aEndIt, bool aTestZones );
/**
* Test for footprint courtyard overlaps.
*/
void doCourtyardsDrc();
//-----<single tests>---------------------------------------------- //-----<single tests>----------------------------------------------
@ -314,13 +296,6 @@ private:
//-----</single tests>--------------------------------------------- //-----</single tests>---------------------------------------------
public: public:
/**
* Tests whether distance between zones complies with the DRC rules.
*
* @return Errors count
*/
int TestZoneToZoneOutlines();
/** /**
* 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.
@ -328,6 +303,12 @@ public:
static void TestFootprints( NETLIST& aNetlist, BOARD* aPCB, EDA_UNITS aUnits, static void TestFootprints( NETLIST& aNetlist, BOARD* aPCB, EDA_UNITS aUnits,
std::vector<DRC_ITEM*>& aDRCList ); std::vector<DRC_ITEM*>& aDRCList );
/**
* Fetches a reasonable point for marking a violoation between two non-point objects.
*/
static wxPoint GetLocation( TRACK* aTrack, ZONE_CONTAINER* aConflictZone );
static wxPoint GetLocation( TRACK* aTrack, const SEG& aConflictSeg );
/** /**
* Open a dialog and prompts the user, then if a test run button is * Open a dialog and prompts the user, then if a test run button is
* clicked, runs the test(s) and creates the MARKERS. The dialog is only * clicked, runs the test(s) and creates the MARKERS. The dialog is only

View File

@ -136,19 +136,20 @@ bool poly2segmentDRC( wxPoint* aTref, int aTrefCount, wxPoint aSegStart, wxPoint
} }
void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterator aEndIt, void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
bool aTestZones ) TRACKS::iterator aEndIt, bool aTestZones )
{ {
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings(); BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
std::vector<DRC_SELECTOR*> matched; std::vector<DRC_SELECTOR*> matched;
wxString msg; SEG refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
SEG refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() ); PCB_LAYER_ID refLayer = aRefSeg->GetLayer();
LSET layerMask = aRefSeg->GetLayerSet(); LSET refLayerSet = aRefSeg->GetLayerSet();
NETCLASS* netclass = aRefSeg->GetNet()->GetNet() == 0 ? bds.GetDefault().get()
: aRefSeg->GetNetClass().get(); NETCLASS* netclass = aRefSeg->GetNet()->GetNet() == 0 ? bds.GetDefault()
EDA_RECT refSegBB = aRefSeg->GetBoundingBox(); : aRefSeg->GetNetClass();
int refSegWidth = aRefSeg->GetWidth(); EDA_RECT refSegBB = aRefSeg->GetBoundingBox();
int refSegWidth = aRefSeg->GetWidth();
MatchSelectors( bds.m_DRCRuleSelectors, aRefSeg, netclass, nullptr, nullptr, &matched ); MatchSelectors( bds.m_DRCRuleSelectors, aRefSeg, netclass, nullptr, nullptr, &matched );
@ -159,17 +160,16 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
if( aRefSeg->Type() == PCB_VIA_T ) if( aRefSeg->Type() == PCB_VIA_T )
{ {
VIA *refvia = static_cast<VIA*>( aRefSeg ); VIA *refvia = static_cast<VIA*>( aRefSeg );
int viaAnnulus = ( refvia->GetWidth() - refvia->GetDrill() ) / 2; int viaAnnulus = ( refvia->GetWidth() - refvia->GetDrill() ) / 2;
int minAnnulus; int minAnnulus;
wxString minAnnulusSource;
for( DRC_SELECTOR* selector : matched ) for( DRC_SELECTOR* selector : matched )
{ {
if( selector->m_Rule->m_AnnulusWidth > minAnnulus ) if( selector->m_Rule->m_AnnulusWidth > minAnnulus )
{ {
minAnnulus = selector->m_Rule->m_AnnulusWidth; minAnnulus = selector->m_Rule->m_AnnulusWidth;
minAnnulusSource = wxString::Format( _( "'%s' rule" ), selector->m_Rule->m_Name ); m_clearanceSource = wxString::Format( _( "'%s' rule" ), selector->m_Rule->m_Name );
} }
} }
@ -180,31 +180,31 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
{ {
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_VIA_ANNULUS ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_VIA_ANNULUS );
msg.Printf( drcItem->GetErrorText() + _( " (%s minimum %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s minimum %s; actual %s)" ),
minAnnulusSource, m_clearanceSource,
MessageTextFromValue( userUnits(), minAnnulus, true ), MessageTextFromValue( userUnits(), minAnnulus, true ),
MessageTextFromValue( userUnits(), viaAnnulus, true ) ); MessageTextFromValue( userUnits(), viaAnnulus, true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia ); drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() ); MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( marker ); addMarkerToPcb( aCommit, marker );
} }
if( refvia->GetWidth() < bds.m_MicroViasMinSize ) if( refvia->GetWidth() < bds.m_MicroViasMinSize )
{ {
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_MICROVIA ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_MICROVIA );
msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
MessageTextFromValue( userUnits(), bds.m_MicroViasMinSize, true ), MessageTextFromValue( userUnits(), bds.m_MicroViasMinSize, true ),
MessageTextFromValue( userUnits(), refvia->GetWidth(), true ) ); MessageTextFromValue( userUnits(), refvia->GetWidth(), true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia ); drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() ); MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( marker ); addMarkerToPcb( aCommit, marker );
} }
} }
else else
@ -212,38 +212,38 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
if( bds.m_ViasMinAnnulus > minAnnulus ) if( bds.m_ViasMinAnnulus > minAnnulus )
{ {
minAnnulus = bds.m_ViasMinAnnulus; minAnnulus = bds.m_ViasMinAnnulus;
minAnnulusSource = _( "board" ); m_clearanceSource = _( "board" );
} }
if( viaAnnulus < minAnnulus ) if( viaAnnulus < minAnnulus )
{ {
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_VIA_ANNULUS ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_VIA_ANNULUS );
msg.Printf( drcItem->GetErrorText() + _( " (%s minimum %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s minimum %s; actual %s)" ),
minAnnulusSource, m_clearanceSource,
MessageTextFromValue( userUnits(), minAnnulus, true ), MessageTextFromValue( userUnits(), minAnnulus, true ),
MessageTextFromValue( userUnits(), viaAnnulus, true ) ); MessageTextFromValue( userUnits(), viaAnnulus, true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia ); drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() ); MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( marker ); addMarkerToPcb( aCommit, marker );
} }
if( refvia->GetWidth() < bds.m_ViasMinSize ) if( refvia->GetWidth() < bds.m_ViasMinSize )
{ {
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_VIA ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_VIA );
msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
MessageTextFromValue( userUnits(), bds.m_ViasMinSize, true ), MessageTextFromValue( userUnits(), bds.m_ViasMinSize, true ),
MessageTextFromValue( userUnits(), refvia->GetWidth(), true ) ); MessageTextFromValue( userUnits(), refvia->GetWidth(), true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia ); drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() ); MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( marker ); addMarkerToPcb( aCommit, marker );
} }
} }
@ -254,15 +254,15 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
{ {
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_VIA_HOLE_BIGGER ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_VIA_HOLE_BIGGER );
msg.Printf( drcItem->GetErrorText() + _( " (diameter %s; drill %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (diameter %s; drill %s)" ),
MessageTextFromValue( userUnits(), refvia->GetWidth(), true ), MessageTextFromValue( userUnits(), refvia->GetWidth(), true ),
MessageTextFromValue( userUnits(), refvia->GetDrillValue(), true ) ); MessageTextFromValue( userUnits(), refvia->GetDrillValue(), true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia ); drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() ); MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( marker ); addMarkerToPcb( aCommit, marker );
} }
// test if the type of via is allowed due to design rules // test if the type of via is allowed due to design rules
@ -270,12 +270,12 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
{ {
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_MICROVIA_NOT_ALLOWED ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_MICROVIA_NOT_ALLOWED );
msg.Printf( drcItem->GetErrorText() + _( " (board design rule constraints)" ) ); m_msg.Printf( drcItem->GetErrorText() + _( " (board design rule constraints)" ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia ); drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() ); MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( marker ); addMarkerToPcb( aCommit, marker );
} }
// test if the type of via is allowed due to design rules // test if the type of via is allowed due to design rules
@ -283,12 +283,12 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
{ {
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_BURIED_VIA_NOT_ALLOWED ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_BURIED_VIA_NOT_ALLOWED );
msg.Printf( drcItem->GetErrorText() + _( " (board design rule constraints)" ) ); m_msg.Printf( drcItem->GetErrorText() + _( " (board design rule constraints)" ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia ); drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() ); MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( marker ); addMarkerToPcb( aCommit, marker );
} }
// For microvias: test if they are blind vias and only between 2 layers // For microvias: test if they are blind vias and only between 2 layers
@ -313,30 +313,30 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
{ {
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_MICROVIA_TOO_MANY_LAYERS ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_MICROVIA_TOO_MANY_LAYERS );
msg.Printf( drcItem->GetErrorText() + _( " (%s and %s not adjacent)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s and %s not adjacent)" ),
m_pcb->GetLayerName( layer1 ), m_pcb->GetLayerName( layer1 ),
m_pcb->GetLayerName( layer2 ) ); m_pcb->GetLayerName( layer2 ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia ); drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() ); MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( marker ); addMarkerToPcb( aCommit, marker );
} }
} }
} }
else // This is a track segment else // This is a track segment
{ {
int minWidth = bds.m_TrackMinWidth; int minWidth = bds.m_TrackMinWidth;
wxString minWidthSource = _( "board" ); m_clearanceSource = _( "board" );
for( DRC_SELECTOR* selector : matched ) for( DRC_SELECTOR* selector : matched )
{ {
if( selector->m_Rule->m_TrackWidth > minWidth ) if( selector->m_Rule->m_TrackWidth > minWidth )
{ {
minWidth = selector->m_Rule->m_AnnulusWidth; minWidth = selector->m_Rule->m_AnnulusWidth;
minWidthSource = wxString::Format( _( "'%s' rule" ), selector->m_Rule->m_Name ); m_clearanceSource = wxString::Format( _( "'%s' rule" ), selector->m_Rule->m_Name );
} }
} }
@ -346,16 +346,16 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_TRACK_WIDTH ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_TRACK_WIDTH );
msg.Printf( drcItem->GetErrorText() + _( " (%s minimum %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s minimum %s; actual %s)" ),
minWidthSource, m_clearanceSource,
MessageTextFromValue( userUnits(), bds.m_TrackMinWidth, true ), MessageTextFromValue( userUnits(), bds.m_TrackMinWidth, true ),
MessageTextFromValue( userUnits(), refSegWidth, true ) ); MessageTextFromValue( userUnits(), refSegWidth, true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefSeg ); drcItem->SetItems( aRefSeg );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refsegMiddle ); MARKER_PCB* marker = new MARKER_PCB( drcItem, refsegMiddle );
addMarkerToPcb( marker ); addMarkerToPcb( aCommit, marker );
} }
} }
@ -375,12 +375,12 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
{ {
// Preflight based on bounding boxes. // Preflight based on bounding boxes.
EDA_RECT inflatedBB = refSegBB; EDA_RECT inflatedBB = refSegBB;
inflatedBB.Inflate( pad->GetBoundingRadius() + aRefSeg->GetClearance( pad, nullptr ) ); inflatedBB.Inflate( pad->GetBoundingRadius() + m_largestClearance );
if( !inflatedBB.Contains( pad->GetPosition() ) ) if( !inflatedBB.Contains( pad->GetPosition() ) )
continue; continue;
if( !( pad->GetLayerSet() & layerMask ).any() ) if( !( pad->GetLayerSet() & refLayerSet ).any() )
continue; continue;
// No need to check pads with the same net as the refSeg. // No need to check pads with the same net as the refSeg.
@ -389,8 +389,7 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
if( pad->GetDrillSize().x > 0 ) if( pad->GetDrillSize().x > 0 )
{ {
wxString clearanceSource; int minClearance = aRefSeg->GetClearance( nullptr, &m_clearanceSource );
int minClearance = aRefSeg->GetClearance( nullptr, &clearanceSource );
/* Treat an oval hole as a line segment along the hole's major axis, /* Treat an oval hole as a line segment along the hole's major axis,
* shortened by half its minor axis. * shortened by half its minor axis.
@ -415,41 +414,41 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
int actual = std::max( 0.0, sqrt( center2center_squared ) - widths ); int actual = std::max( 0.0, sqrt( center2center_squared ) - widths );
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_HOLE ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_HOLE );
msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
clearanceSource, m_clearanceSource,
MessageTextFromValue( userUnits(), minClearance, true ), MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) ); MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefSeg, pad ); drcItem->SetItems( aRefSeg, pad );
MARKER_PCB* marker = new MARKER_PCB( drcItem, getLocation( aRefSeg, slotSeg ) ); MARKER_PCB* marker = new MARKER_PCB( drcItem, GetLocation( aRefSeg, slotSeg ) );
addMarkerToPcb( marker ); addMarkerToPcb( aCommit, marker );
if( !m_reportAllTrackErrors ) if( !m_reportAllTrackErrors )
return; return;
} }
} }
wxString clearanceSource; int minClearance = aRefSeg->GetClearance( pad, &m_clearanceSource );
int minClearance = aRefSeg->GetClearance( pad, &clearanceSource ); int actual;
int actual;
if( !checkClearanceSegmToPad( refSeg, refSegWidth, pad, minClearance, &actual ) ) if( !checkClearanceSegmToPad( refSeg, refSegWidth, pad, minClearance, &actual ) )
{ {
actual = std::max( 0, actual );
SEG padSeg( pad->GetPosition(), pad->GetPosition() ); SEG padSeg( pad->GetPosition(), pad->GetPosition() );
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_PAD ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_PAD );
msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
clearanceSource, m_clearanceSource,
MessageTextFromValue( userUnits(), minClearance, true ), MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) ); MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefSeg, pad ); drcItem->SetItems( aRefSeg, pad );
MARKER_PCB* marker = new MARKER_PCB( drcItem, getLocation( aRefSeg, padSeg ) ); MARKER_PCB* marker = new MARKER_PCB( drcItem, GetLocation( aRefSeg, padSeg ) );
addMarkerToPcb( marker ); addMarkerToPcb( aCommit, marker );
if( !m_reportAllTrackErrors ) if( !m_reportAllTrackErrors )
return; return;
@ -471,21 +470,39 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
continue; continue;
// No problem if tracks are on different layers: // No problem if tracks are on different layers:
if( !( layerMask & track->GetLayerSet() ).any() ) // Note that while the general case of GetLayerSet intersection always works,
// the others are much faster.
bool sameLayers;
if( aRefSeg->Type() == PCB_VIA_T )
{
if( track->Type() == PCB_VIA_T )
sameLayers = ( refLayerSet & track->GetLayerSet() ).any();
else
sameLayers = refLayerSet.test( track->GetLayer() );
}
else
{
if( track->Type() == PCB_VIA_T )
sameLayers = track->GetLayerSet().test( refLayer );
else
sameLayers = track->GetLayer() == refLayer;
}
if( !sameLayers )
continue; continue;
// Preflight based on inflated bounding boxes: // Preflight based on worst-case inflated bounding boxes:
EDA_RECT trackBB = track->GetBoundingBox(); EDA_RECT trackBB = track->GetBoundingBox();
trackBB.Inflate( aRefSeg->GetClearance( track, nullptr ) ); trackBB.Inflate( m_largestClearance );
if( !trackBB.Intersects( refSegBB ) ) if( !trackBB.Intersects( refSegBB ) )
continue; continue;
wxString clearanceSource; int minClearance = aRefSeg->GetClearance( track, &m_clearanceSource );
int minClearance = aRefSeg->GetClearance( track, &clearanceSource ); SEG trackSeg( track->GetStart(), track->GetEnd() );
SEG trackSeg( track->GetStart(), track->GetEnd() ); int widths = ( refSegWidth + track->GetWidth() ) / 2;
int widths = ( refSegWidth + track->GetWidth() ) / 2; int center2centerAllowed = minClearance + widths;
int center2centerAllowed = minClearance + widths;
// Avoid square-roots if possible (for performance) // Avoid square-roots if possible (for performance)
SEG::ecoord center2center_squared = refSeg.SquaredDistance( trackSeg ); SEG::ecoord center2center_squared = refSeg.SquaredDistance( trackSeg );
@ -495,11 +512,11 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
if( intersection ) if( intersection )
{ {
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACKS_CROSSING ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACKS_CROSSING );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefSeg, track ); drcItem->SetItems( aRefSeg, track );
MARKER_PCB* marker = new MARKER_PCB( drcItem, (wxPoint) intersection.get() ); MARKER_PCB* marker = new MARKER_PCB( drcItem, (wxPoint) intersection.get() );
addMarkerToPcb( marker ); addMarkerToPcb( aCommit, marker );
if( !m_reportAllTrackErrors ) if( !m_reportAllTrackErrors )
return; return;
@ -518,16 +535,16 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
int actual = std::max( 0.0, sqrt( center2center_squared ) - widths ); int actual = std::max( 0.0, sqrt( center2center_squared ) - widths );
DRC_ITEM* drcItem = new DRC_ITEM( errorCode ); DRC_ITEM* drcItem = new DRC_ITEM( errorCode );
msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
clearanceSource, m_clearanceSource,
MessageTextFromValue( userUnits(), minClearance, true ), MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) ); MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefSeg, track ); drcItem->SetItems( aRefSeg, track );
MARKER_PCB* marker = new MARKER_PCB( drcItem, getLocation( aRefSeg, trackSeg ) ); MARKER_PCB* marker = new MARKER_PCB( drcItem, GetLocation( aRefSeg, trackSeg ) );
addMarkerToPcb( marker ); addMarkerToPcb( aCommit, marker );
if( !m_reportAllTrackErrors ) if( !m_reportAllTrackErrors )
return; return;
@ -547,14 +564,13 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
if( zone->GetFilledPolysList().IsEmpty() || zone->GetIsKeepout() ) if( zone->GetFilledPolysList().IsEmpty() || zone->GetIsKeepout() )
continue; continue;
if( !( layerMask & zone->GetLayerSet() ).any() ) if( !( refLayerSet & zone->GetLayerSet() ).any() )
continue; continue;
if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() ) if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() )
continue; continue;
wxString clearanceSource; int minClearance = aRefSeg->GetClearance( zone, &m_clearanceSource );
int minClearance = aRefSeg->GetClearance( zone, &clearanceSource );
int widths = refSegWidth / 2; int widths = refSegWidth / 2;
int center2centerAllowed = minClearance + widths; int center2centerAllowed = minClearance + widths;
SHAPE_POLY_SET* outline = const_cast<SHAPE_POLY_SET*>( &zone->GetFilledPolysList() ); SHAPE_POLY_SET* outline = const_cast<SHAPE_POLY_SET*>( &zone->GetFilledPolysList() );
@ -571,16 +587,16 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
int actual = std::max( 0.0, sqrt( center2center_squared ) - widths ); int actual = std::max( 0.0, sqrt( center2center_squared ) - widths );
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_ZONE ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_ZONE );
msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
clearanceSource, m_clearanceSource,
MessageTextFromValue( userUnits(), minClearance, true ), MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) ); MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefSeg, zone ); drcItem->SetItems( aRefSeg, zone );
MARKER_PCB* marker = new MARKER_PCB( drcItem, getLocation( aRefSeg, zone ) ); MARKER_PCB* marker = new MARKER_PCB( drcItem, GetLocation( aRefSeg, zone ) );
addMarkerToPcb( marker ); addMarkerToPcb( aCommit, marker );
} }
} }
} }
@ -592,14 +608,13 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
static DRAWSEGMENT dummyEdge; static DRAWSEGMENT dummyEdge;
dummyEdge.SetLayer( Edge_Cuts ); dummyEdge.SetLayer( Edge_Cuts );
SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() ); SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
wxString clearanceSource; int minClearance = aRefSeg->GetClearance( &dummyEdge, &m_clearanceSource );
int minClearance = aRefSeg->GetClearance( &dummyEdge, &clearanceSource );
if( bds.m_CopperEdgeClearance > minClearance ) if( bds.m_CopperEdgeClearance > minClearance )
{ {
minClearance = bds.m_CopperEdgeClearance; minClearance = bds.m_CopperEdgeClearance;
clearanceSource = _( "board edge" ); m_clearanceSource = _( "board edge" );
} }
int halfWidth = refSegWidth / 2; int halfWidth = refSegWidth / 2;
@ -638,16 +653,16 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
int actual = std::max( 0.0, sqrt( center2center_squared ) - halfWidth ); int actual = std::max( 0.0, sqrt( center2center_squared ) - halfWidth );
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_EDGE ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_EDGE );
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
clearanceSource, m_clearanceSource,
MessageTextFromValue( userUnits(), minClearance, true ), MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) ); MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefSeg, edge ); drcItem->SetItems( aRefSeg, edge );
MARKER_PCB* marker = new MARKER_PCB( drcItem, (wxPoint) pt ); MARKER_PCB* marker = new MARKER_PCB( drcItem, (wxPoint) pt );
addMarkerToPcb( marker ); addMarkerToPcb( aCommit, marker );
} }
} }
} }
@ -934,7 +949,7 @@ bool DRC::checkClearanceSegmToPad( const SEG& refSeg, int refSegWidth, const D_P
if( padShape.DoCollide( refSeg, minClearance + widths, &actual ) ) if( padShape.DoCollide( refSeg, minClearance + widths, &actual ) )
{ {
*aActualDist = actual - widths; *aActualDist = std::max( 0, actual - widths );
return false; return false;
} }
} }
@ -955,7 +970,7 @@ bool DRC::checkClearanceSegmToPad( const SEG& refSeg, int refSegWidth, const D_P
(wxPoint) refSeg.A, (wxPoint) refSeg.B, (wxPoint) refSeg.A, (wxPoint) refSeg.B,
minClearance + widths, &actual ) ) minClearance + widths, &actual ) )
{ {
*aActualDist = actual - widths; *aActualDist = std::max( 0, actual - widths );
return false; return false;
} }
} }

View File

@ -57,7 +57,7 @@ bool DRC_DRILLED_HOLE_TESTER::RunDRC( EDA_UNITS aUnits, BOARD& aBoard )
for( MODULE* mod : aBoard.Modules() ) for( MODULE* mod : aBoard.Modules() )
{ {
for( D_PAD* pad : mod->Pads( ) ) for( D_PAD* pad : mod->Pads( ) )
success |= checkPad( pad ); success &= checkPad( pad );
} }
for( TRACK* track : aBoard.Tracks() ) for( TRACK* track : aBoard.Tracks() )
@ -67,13 +67,13 @@ bool DRC_DRILLED_HOLE_TESTER::RunDRC( EDA_UNITS aUnits, BOARD& aBoard )
if( via ) if( via )
{ {
if( via->GetViaType() == VIATYPE::MICROVIA ) if( via->GetViaType() == VIATYPE::MICROVIA )
success |= checkMicroVia( via ); success &= checkMicroVia( via );
else else
success |= checkVia( via ); success &= checkVia( via );
} }
} }
success |= checkHoles(); success &= checkHoles();
return success; return success;
} }
@ -81,7 +81,6 @@ bool DRC_DRILLED_HOLE_TESTER::RunDRC( EDA_UNITS aUnits, BOARD& aBoard )
bool DRC_DRILLED_HOLE_TESTER::checkPad( D_PAD* aPad ) bool DRC_DRILLED_HOLE_TESTER::checkPad( D_PAD* aPad )
{ {
wxString msg;
bool success = true; bool success = true;
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
@ -92,8 +91,8 @@ bool DRC_DRILLED_HOLE_TESTER::checkPad( D_PAD* aPad )
if( !bds.Ignore( DRCE_TOO_SMALL_PAD_DRILL ) ) if( !bds.Ignore( DRCE_TOO_SMALL_PAD_DRILL ) )
{ {
NETCLASS* netclass = aPad->GetNet()->GetNet() == 0 ? bds.GetDefault().get() NETCLASS* netclass = aPad->GetNet()->GetNet() == 0 ? bds.GetDefault()
: aPad->GetNetClass().get(); : aPad->GetNetClass();
int minHole = bds.m_MinThroughDrill; int minHole = bds.m_MinThroughDrill;
wxString minHoleSource = _( "board" ); wxString minHoleSource = _( "board" );
@ -113,12 +112,12 @@ bool DRC_DRILLED_HOLE_TESTER::checkPad( D_PAD* aPad )
{ {
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_PAD_DRILL ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_PAD_DRILL );
msg.Printf( drcItem->GetErrorText() + _( " (%s min hole %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s min hole %s; actual %s)" ),
minHoleSource, minHoleSource,
MessageTextFromValue( m_units, minHole, true ), MessageTextFromValue( m_units, minHole, true ),
MessageTextFromValue( m_units, holeSize, true ) ); MessageTextFromValue( m_units, holeSize, true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aPad ); drcItem->SetItems( aPad );
HandleMarker( new MARKER_PCB( drcItem, aPad->GetPosition() ) ); HandleMarker( new MARKER_PCB( drcItem, aPad->GetPosition() ) );
@ -137,14 +136,13 @@ bool DRC_DRILLED_HOLE_TESTER::checkPad( D_PAD* aPad )
bool DRC_DRILLED_HOLE_TESTER::checkVia( VIA* via ) bool DRC_DRILLED_HOLE_TESTER::checkVia( VIA* via )
{ {
wxString msg;
bool success = true; bool success = true;
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
if( !bds.Ignore( DRCE_TOO_SMALL_VIA_DRILL ) ) if( !bds.Ignore( DRCE_TOO_SMALL_VIA_DRILL ) )
{ {
NETCLASS* netclass = via->GetNet()->GetNet() == 0 ? bds.GetDefault().get() NETCLASS* netclass = via->GetNet()->GetNet() == 0 ? bds.GetDefault()
: via->GetNetClass().get(); : via->GetNetClass();
int minHole = bds.m_MinThroughDrill; int minHole = bds.m_MinThroughDrill;
wxString minHoleSource = _( "board" ); wxString minHoleSource = _( "board" );
@ -164,12 +162,12 @@ bool DRC_DRILLED_HOLE_TESTER::checkVia( VIA* via )
{ {
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_VIA_DRILL ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_VIA_DRILL );
msg.Printf( drcItem->GetErrorText() + _( " (%s min hole %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s min hole %s; actual %s)" ),
minHoleSource, minHoleSource,
MessageTextFromValue( m_units, minHole, true ), MessageTextFromValue( m_units, minHole, true ),
MessageTextFromValue( m_units, via->GetDrillValue(), true ) ); MessageTextFromValue( m_units, via->GetDrillValue(), true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( via ); drcItem->SetItems( via );
HandleMarker( new MARKER_PCB( drcItem, via->GetPosition() ) ); HandleMarker( new MARKER_PCB( drcItem, via->GetPosition() ) );
@ -188,14 +186,13 @@ bool DRC_DRILLED_HOLE_TESTER::checkVia( VIA* via )
bool DRC_DRILLED_HOLE_TESTER::checkMicroVia( VIA* via ) bool DRC_DRILLED_HOLE_TESTER::checkMicroVia( VIA* via )
{ {
wxString msg;
bool success = true; bool success = true;
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
if( !bds.Ignore( DRCE_TOO_SMALL_MICROVIA_DRILL ) ) if( !bds.Ignore( DRCE_TOO_SMALL_MICROVIA_DRILL ) )
{ {
NETCLASS* netclass = via->GetNet()->GetNet() == 0 ? bds.GetDefault().get() NETCLASS* netclass = via->GetNet()->GetNet() == 0 ? bds.GetDefault()
: via->GetNetClass().get(); : via->GetNetClass();
int minHole = bds.m_MicroViasMinDrill; int minHole = bds.m_MicroViasMinDrill;
wxString minHoleSource = _( "board" ); wxString minHoleSource = _( "board" );
@ -215,12 +212,12 @@ bool DRC_DRILLED_HOLE_TESTER::checkMicroVia( VIA* via )
{ {
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_MICROVIA_DRILL ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_MICROVIA_DRILL );
msg.Printf( drcItem->GetErrorText() + _( " (%s minimum %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s minimum %s; actual %s)" ),
minHoleSource, minHoleSource,
MessageTextFromValue( m_units, minHole, true ), MessageTextFromValue( m_units, minHole, true ),
MessageTextFromValue( m_units, via->GetDrillValue(), true ) ); MessageTextFromValue( m_units, via->GetDrillValue(), true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( via ); drcItem->SetItems( via );
HandleMarker( new MARKER_PCB( drcItem, via->GetPosition() ) ); HandleMarker( new MARKER_PCB( drcItem, via->GetPosition() ) );
@ -248,7 +245,6 @@ void DRC_DRILLED_HOLE_TESTER::addHole( const wxPoint& aLocation, int aRadius, BO
bool DRC_DRILLED_HOLE_TESTER::checkHoles() bool DRC_DRILLED_HOLE_TESTER::checkHoles()
{ {
wxString msg;
bool success = true; bool success = true;
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
@ -291,11 +287,11 @@ bool DRC_DRILLED_HOLE_TESTER::checkHoles()
{ {
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_DRILLED_HOLES_TOO_CLOSE ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_DRILLED_HOLES_TOO_CLOSE );
msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
MessageTextFromValue( m_units, bds.m_HoleToHoleMin, true ), MessageTextFromValue( m_units, bds.m_HoleToHoleMin, true ),
MessageTextFromValue( m_units, actual, true ) ); MessageTextFromValue( m_units, actual, true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refHole.m_owner, checkHole.m_owner ); drcItem->SetItems( refHole.m_owner, checkHole.m_owner );
HandleMarker( new MARKER_PCB( drcItem, refHole.m_location ) ); HandleMarker( new MARKER_PCB( drcItem, refHole.m_location ) );

View File

@ -61,6 +61,8 @@ private:
BOARD* m_board; BOARD* m_board;
std::vector<DRILLED_HOLE> m_holes; std::vector<DRILLED_HOLE> m_holes;
int m_largestRadius; int m_largestRadius;
wxString m_msg; // Construct only once for performance
}; };
#endif // DRC_DRILLED_HOLE_TESTER__H #endif // DRC_DRILLED_HOLE_TESTER__H

View File

@ -0,0 +1,193 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 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 Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <drc/drc_keepout_tester.h>
#include <class_module.h>
#include <drc/drc.h>
DRC_KEEPOUT_TESTER::DRC_KEEPOUT_TESTER( MARKER_HANDLER aMarkerHandler ) :
DRC_TEST_PROVIDER( std::move( aMarkerHandler ) ),
m_units( EDA_UNITS::MILLIMETRES ),
m_board( nullptr )
{
}
bool DRC_KEEPOUT_TESTER::RunDRC( EDA_UNITS aUnits, BOARD& aBoard )
{
bool success = true;
m_units = aUnits;
m_board = &aBoard;
// Get a list of all zones to inspect, from both board and footprints
std::list<ZONE_CONTAINER*> areasToInspect = m_board->GetZoneList( true );
// Test keepout areas for vias, tracks and pads inside keepout areas
for( ZONE_CONTAINER* area : areasToInspect )
{
if( area->GetIsKeepout() )
{
if( area->GetDoNotAllowTracks() || area->GetDoNotAllowVias() )
success &= checkTracksAndVias( area );
if( area->GetDoNotAllowPads() || area->GetDoNotAllowFootprints() )
success &= checkFootprints( area );
}
}
return success;
}
bool DRC_KEEPOUT_TESTER::checkTracksAndVias( ZONE_CONTAINER* aKeepout )
{
bool success = true;
for( TRACK* segm : m_board->Tracks() )
{
if( segm->Type() == PCB_TRACE_T && aKeepout->GetDoNotAllowTracks() )
{
// Ignore if the keepout zone is not on the same layer
if( !aKeepout->IsOnLayer( segm->GetLayer() ) )
continue;
int widths = segm->GetWidth() / 2;
SEG trackSeg( segm->GetStart(), segm->GetEnd() );
SEG::ecoord center2center_squared = aKeepout->Outline()->SquaredDistance( trackSeg );
if( center2center_squared <= SEG::Square( widths) )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_INSIDE_KEEPOUT );
drcItem->SetItems( segm, aKeepout );
HandleMarker( new MARKER_PCB( drcItem, DRC::GetLocation( segm, aKeepout ) ) );
success = false;
}
}
else if( segm->Type() == PCB_VIA_T && aKeepout->GetDoNotAllowVias() )
{
if( !aKeepout->CommonLayerExists( segm->GetLayerSet() ) )
continue;
int widths = segm->GetWidth() / 2;
wxPoint viaPos = segm->GetPosition();
SEG::ecoord center2center_squared = aKeepout->Outline()->SquaredDistance( viaPos );
if( center2center_squared <= SEG::Square( widths) )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_VIA_INSIDE_KEEPOUT );
drcItem->SetItems( segm, aKeepout );
HandleMarker( new MARKER_PCB( drcItem, DRC::GetLocation( segm, aKeepout ) ) );
success = false;
}
}
}
return success;
}
bool DRC_KEEPOUT_TESTER::checkFootprints( ZONE_CONTAINER* aKeepout )
{
bool success = true;
EDA_RECT areaBBox = aKeepout->GetBoundingBox();
bool checkFront = aKeepout->CommonLayerExists( LSET::FrontMask() );
bool checkBack = aKeepout->CommonLayerExists( LSET::BackMask() );
for( MODULE* fp : m_board->Modules() )
{
if( aKeepout->GetDoNotAllowFootprints() && ( fp->IsFlipped() ? checkBack : checkFront ) )
{
// Fast test to detect a footprint inside the keepout area bounding box.
if( areaBBox.Intersects( fp->GetBoundingBox() ) )
{
SHAPE_POLY_SET outline;
if( fp->BuildPolyCourtyard() )
{
outline = fp->IsFlipped() ? fp->GetPolyCourtyardBack()
: fp->GetPolyCourtyardFront();
}
if( outline.OutlineCount() == 0 )
outline = fp->GetBoundingPoly();
// Build the common area between footprint and the keepout area:
outline.BooleanIntersection( *aKeepout->Outline(), SHAPE_POLY_SET::PM_FAST );
// If it's not empty then we have a violation
if( outline.OutlineCount() )
{
const VECTOR2I& pt = outline.CVertex( 0, 0, -1 );
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_FOOTPRINT_INSIDE_KEEPOUT );
drcItem->SetItems( fp, aKeepout );
HandleMarker( new MARKER_PCB( drcItem, (wxPoint) pt ) );
success = false;
}
}
}
if( aKeepout->GetDoNotAllowPads() )
{
for( D_PAD* pad : fp->Pads() )
{
if( !aKeepout->CommonLayerExists( pad->GetLayerSet() ) )
continue;
// Fast test to detect a pad inside the keepout area bounding box.
EDA_RECT padBBox( pad->ShapePos(), wxSize() );
padBBox.Inflate( pad->GetBoundingRadius() );
if( areaBBox.Intersects( padBBox ) )
{
SHAPE_POLY_SET outline;
pad->TransformShapeWithClearanceToPolygon( outline, 0 );
// Build the common area between pad and the keepout area:
outline.BooleanIntersection( *aKeepout->Outline(), SHAPE_POLY_SET::PM_FAST );
// If it's not empty then we have a violation
if( outline.OutlineCount() )
{
const VECTOR2I& pt = outline.CVertex( 0, 0, -1 );
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_PAD_INSIDE_KEEPOUT );
drcItem->SetItems( pad, aKeepout );
HandleMarker( new MARKER_PCB( drcItem, (wxPoint) pt ) );
success = false;
}
}
}
}
}
return success;
}

View File

@ -0,0 +1,52 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 KiCad Developers, see change_log.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 Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef DRC_KEEPOUT_TESTER__H
#define DRC_KEEPOUT_TESTER__H
#include <drc/drc_provider.h>
class BOARD;
class DRC_KEEPOUT_TESTER : public DRC_TEST_PROVIDER
{
public:
DRC_KEEPOUT_TESTER( MARKER_HANDLER aMarkerHandler );
virtual ~DRC_KEEPOUT_TESTER() {};
bool RunDRC( EDA_UNITS aUnits, BOARD& aBoard ) override;
private:
bool checkTracksAndVias( ZONE_CONTAINER* aKeepout );
bool checkFootprints( ZONE_CONTAINER* aKeepout );
private:
EDA_UNITS m_units;
BOARD* m_board;
};
#endif // DRC_KEEPOUT_TESTER__H

View File

@ -0,0 +1,162 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 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 Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <drc/drc_netclass_tester.h>
DRC_NETCLASS_TESTER::DRC_NETCLASS_TESTER( MARKER_HANDLER aMarkerHandler ) :
DRC_TEST_PROVIDER( std::move( aMarkerHandler ) ),
m_units( EDA_UNITS::MILLIMETRES ),
m_board( nullptr )
{
}
bool DRC_NETCLASS_TESTER::RunDRC( EDA_UNITS aUnits, BOARD& aBoard )
{
m_units = aUnits;
m_board = &aBoard;
bool success = true;
NETCLASSES& netclasses = m_board->GetDesignSettings().m_NetClasses;
success &= checkNetClass( netclasses.GetDefault() );
for( NETCLASSES::const_iterator i = netclasses.begin(); i != netclasses.end(); ++i )
success &= checkNetClass( i->second );
return success;
}
bool DRC_NETCLASS_TESTER::checkNetClass( const NETCLASSPTR& nc )
{
bool ret = true;
const BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
if( nc->GetClearance() < bds.m_MinClearance )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_NETCLASS_CLEARANCE );
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; %s netclass %s)" ),
MessageTextFromValue( m_units, bds.m_MinClearance, true ),
nc->GetName(),
MessageTextFromValue( m_units, nc->GetClearance(), true ) );
drcItem->SetErrorMessage( m_msg );
HandleMarker( new MARKER_PCB( drcItem, wxPoint() ) );
ret = false;
}
if( nc->GetTrackWidth() < bds.m_TrackMinWidth )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_NETCLASS_TRACKWIDTH );
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; %s netclass %s)" ),
MessageTextFromValue( m_units, bds.m_TrackMinWidth, true ),
nc->GetName(),
MessageTextFromValue( m_units, nc->GetTrackWidth(), true ) );
drcItem->SetErrorMessage( m_msg );
HandleMarker( new MARKER_PCB( drcItem, wxPoint() ) );
ret = false;
}
if( nc->GetViaDiameter() < bds.m_ViasMinSize )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_NETCLASS_VIASIZE );
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; %s netclass %s)" ),
MessageTextFromValue( m_units, bds.m_ViasMinSize, true ),
nc->GetName(),
MessageTextFromValue( m_units, nc->GetViaDiameter(), true ) );
drcItem->SetErrorMessage( m_msg );
HandleMarker( new MARKER_PCB( drcItem, wxPoint() ) );
ret = false;
}
if( nc->GetViaDrill() < bds.m_MinThroughDrill )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_NETCLASS_VIADRILLSIZE );
m_msg.Printf( drcItem->GetErrorText() + _( " (board min through hole %s; %s netclass %s)" ),
MessageTextFromValue( m_units, bds.m_MinThroughDrill, true ),
nc->GetName(),
MessageTextFromValue( m_units, nc->GetViaDrill(), true ) );
drcItem->SetErrorMessage( m_msg );
HandleMarker( new MARKER_PCB( drcItem, wxPoint() ) );
ret = false;
}
int ncViaAnnulus = ( nc->GetViaDiameter() - nc->GetViaDrill() ) / 2;
if( ncViaAnnulus < bds.m_ViasMinAnnulus )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_NETCLASS_VIAANNULUS );
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; %s netclass %s)" ),
MessageTextFromValue( m_units, bds.m_ViasMinAnnulus, true ),
nc->GetName(),
MessageTextFromValue( m_units, ncViaAnnulus, true ) );
drcItem->SetErrorMessage( m_msg );
HandleMarker( new MARKER_PCB( drcItem, wxPoint() ) );
ret = false;
}
if( nc->GetuViaDiameter() < bds.m_MicroViasMinSize )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_NETCLASS_uVIASIZE );
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; %s netclass %s)" ),
MessageTextFromValue( m_units, bds.m_MicroViasMinSize, true ),
nc->GetName(),
MessageTextFromValue( m_units, nc->GetuViaDiameter(), true ) );
drcItem->SetErrorMessage( m_msg );
HandleMarker( new MARKER_PCB( drcItem, wxPoint() ) );
ret = false;
}
if( nc->GetuViaDrill() < bds.m_MicroViasMinDrill )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_NETCLASS_uVIADRILLSIZE );
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; %s netclass %s)" ),
MessageTextFromValue( m_units, bds.m_MicroViasMinDrill, true ),
nc->GetName(),
MessageTextFromValue( m_units, nc->GetuViaDrill(), true ) );
drcItem->SetErrorMessage( m_msg );
HandleMarker( new MARKER_PCB( drcItem, wxPoint() ) );
ret = false;
}
return ret;
}

View File

@ -0,0 +1,54 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 KiCad Developers, see change_log.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 Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef DRC_NETCLASS_TESTER__H
#define DRC_NETCLASS_TESTER__H
#include <drc/drc_provider.h>
class BOARD;
class BOARD_ITEM;
class DRC_NETCLASS_TESTER : public DRC_TEST_PROVIDER
{
public:
DRC_NETCLASS_TESTER( MARKER_HANDLER aMarkerHandler );
virtual ~DRC_NETCLASS_TESTER() {};
bool RunDRC( EDA_UNITS aUnits, BOARD& aBoard ) override;
private:
bool checkNetClass( const NETCLASSPTR& nc );
private:
EDA_UNITS m_units;
BOARD* m_board;
wxString m_msg; // Construct only once for performance
};
#endif // DRC_NETCLASS_TESTER__H

View File

@ -0,0 +1,87 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 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 Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <drc/drc_textvar_tester.h>
#include <class_module.h>
#include <class_pcb_text.h>
DRC_TEXTVAR_TESTER::DRC_TEXTVAR_TESTER( MARKER_HANDLER aMarkerHandler ) :
DRC_TEST_PROVIDER( std::move( aMarkerHandler ) ),
m_units( EDA_UNITS::MILLIMETRES ),
m_board( nullptr )
{
}
bool DRC_TEXTVAR_TESTER::RunDRC( EDA_UNITS aUnits, BOARD& aBoard )
{
bool success = true;
m_units = aUnits;
m_board = &aBoard;
for( MODULE* module : m_board->Modules() )
{
module->RunOnChildren(
[&]( BOARD_ITEM* child )
{
if( child->Type() == PCB_MODULE_TEXT_T )
{
TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( child );
if( text->GetShownText().Matches( wxT( "*${*}*" ) ) )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_UNRESOLVED_VARIABLE );
drcItem->SetItems( text );
HandleMarker( new MARKER_PCB( drcItem, text->GetPosition() ) );
success = false;
}
}
} );
}
for( BOARD_ITEM* drawing : m_board->Drawings() )
{
if( drawing->Type() == PCB_TEXT_T )
{
TEXTE_PCB* text = static_cast<TEXTE_PCB*>( drawing );
if( text->GetShownText().Matches( wxT( "*${*}*" ) ) )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_UNRESOLVED_VARIABLE );
drcItem->SetItems( text );
HandleMarker( new MARKER_PCB( drcItem, text->GetPosition() ) );
success = false;
}
}
}
return success;
}

View File

@ -0,0 +1,48 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 KiCad Developers, see change_log.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 Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef DRC_TEXTVAR_TESTER__H
#define DRC_TEXTVAR_TESTER__H
#include <drc/drc_provider.h>
class BOARD;
class DRC_TEXTVAR_TESTER : public DRC_TEST_PROVIDER
{
public:
DRC_TEXTVAR_TESTER( MARKER_HANDLER aMarkerHandler );
virtual ~DRC_TEXTVAR_TESTER() {};
bool RunDRC( EDA_UNITS aUnits, BOARD& aBoard ) override;
private:
EDA_UNITS m_units;
BOARD* m_board;
};
#endif // DRC_TEXTVAR_TESTER__H

View File

@ -269,8 +269,8 @@ BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, const
if( m_rules->mdWireWire ) if( m_rules->mdWireWire )
{ {
NETCLASSPTR defaultNetclass = designSettings.GetDefault(); NETCLASS* defaultNetclass = designSettings.GetDefault();
int clearance = KiROUND( m_rules->mdWireWire ); int clearance = KiROUND( m_rules->mdWireWire );
if( clearance < defaultNetclass->GetClearance() ) if( clearance < defaultNetclass->GetClearance() )
defaultNetclass->SetClearance( clearance ); defaultNetclass->SetClearance( clearance );

View File

@ -175,7 +175,7 @@ FOOTPRINT_VIEWER_FRAME::FOOTPRINT_VIEWER_FRAME( KIWAY* aKiway, wxWindow* aParent
// In viewer, the default net clearance is not known (it depends on the actual board). // In viewer, the default net clearance is not known (it depends on the actual board).
// So we do not show the default clearance, by setting it to 0 // So we do not show the default clearance, by setting it to 0
// The footprint or pad specific clearance will be shown // The footprint or pad specific clearance will be shown
GetBoard()->GetDesignSettings().GetDefault()->SetClearance(0); GetBoard()->GetDesignSettings().GetDefault()->SetClearance( 0 );
// Don't show the default board solder mask clearance in the footprint viewer. Only the // Don't show the default board solder mask clearance in the footprint viewer. Only the
// footprint or pad clearance setting should be shown if it is not 0. // footprint or pad clearance setting should be shown if it is not 0.

View File

@ -124,7 +124,7 @@ FOOTPRINT_WIZARD_FRAME::FOOTPRINT_WIZARD_FRAME( KIWAY* aKiway, wxWindow* aParent
// In viewer, the default net clearance is not known (it depends on the actual board). // In viewer, the default net clearance is not known (it depends on the actual board).
// So we do not show the default clearance, by setting it to 0 // So we do not show the default clearance, by setting it to 0
// The footprint or pad specific clearance will be shown // The footprint or pad specific clearance will be shown
GetBoard()->GetDesignSettings().GetDefault()->SetClearance(0); GetBoard()->GetDesignSettings().GetDefault()->SetClearance( 0 );
disp_opts.m_DisplayPadIsol = true; disp_opts.m_DisplayPadIsol = true;
disp_opts.m_DisplayPadNum = true; disp_opts.m_DisplayPadNum = true;

View File

@ -832,13 +832,13 @@ void LEGACY_PLUGIN::loadSHEET()
void LEGACY_PLUGIN::loadSETUP() void LEGACY_PLUGIN::loadSETUP()
{ {
NETCLASSPTR netclass_default = m_board->GetDesignSettings().GetDefault(); NETCLASS* netclass_default = m_board->GetDesignSettings().GetDefault();
// TODO Orson: is it really necessary to first operate on a copy and then apply it? // TODO Orson: is it really necessary to first operate on a copy and then apply it?
// would not it be better to use reference here and apply all the changes instantly? // would not it be better to use reference here and apply all the changes instantly?
BOARD_DESIGN_SETTINGS bds = m_board->GetDesignSettings(); BOARD_DESIGN_SETTINGS bds = m_board->GetDesignSettings();
ZONE_SETTINGS zs = m_board->GetZoneSettings(); ZONE_SETTINGS zs = m_board->GetZoneSettings();
char* line; char* line;
char* saveptr; char* saveptr;
while( ( line = READLINE( m_reader ) ) != NULL ) while( ( line = READLINE( m_reader ) ) != NULL )
{ {

View File

@ -270,6 +270,11 @@ public:
return m_default; return m_default;
} }
NETCLASS* GetDefaultPtr() const
{
return m_default.get();
}
/** /**
* Function Add * Function Add
* takes \a aNetclass and puts it into this NETCLASSES container. * takes \a aNetclass and puts it into this NETCLASSES container.

View File

@ -119,9 +119,15 @@ public:
*/ */
void SetClass( const NETCLASSPTR& aNetClass ); void SetClass( const NETCLASSPTR& aNetClass );
NETCLASSPTR GetNetClass() /**
* Function GetNetClass
*
* Note: do NOT return a std::shared_ptr from this. It is used heavily in DRC, and the
* std::shared_ptr stuff shows up large in performance profiling.
*/
NETCLASS* GetNetClass()
{ {
return m_NetClass; return m_NetClass.get();
} }
/** /**

View File

@ -1432,7 +1432,7 @@ void PCB_PARSER::parseSetup()
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as setup." ) ); wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as setup." ) );
T token; T token;
NETCLASSPTR defaultNetClass = m_board->GetDesignSettings().GetDefault(); NETCLASS* defaultNetClass = m_board->GetDesignSettings().GetDefault();
BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings(); BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings();
ZONE_SETTINGS zoneSettings = m_board->GetZoneSettings(); ZONE_SETTINGS zoneSettings = m_board->GetZoneSettings();

View File

@ -94,7 +94,7 @@ void SIZES_SETTINGS::Init( BOARD* aBoard, ITEM* aStartItem, int aNet )
} }
if( !netClass ) if( !netClass )
netClass = bds.GetDefault(); netClass = bds.m_NetClasses.GetDefault();
m_trackWidth = 0; m_trackWidth = 0;

View File

@ -999,15 +999,15 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
//-----<rules>-------------------------------------------------------- //-----<rules>--------------------------------------------------------
{ {
char rule[80]; char rule[80];
NETCLASSPTR defaultClass = aBoard->GetDesignSettings().GetDefault(); NETCLASS* defaultClass = aBoard->GetDesignSettings().GetDefault();
int defaultTrackWidth = defaultClass->GetTrackWidth(); int defaultTrackWidth = defaultClass->GetTrackWidth();
int defaultClearance = defaultClass->GetClearance(); int defaultClearance = defaultClass->GetClearance();
double clearance = scale( defaultClearance ); double clearance = scale( defaultClearance );
STRINGS& rules = pcb->structure->rules->rules; STRINGS& rules = pcb->structure->rules->rules;
sprintf( rule, "(width %.6g)", scale( defaultTrackWidth ) ); sprintf( rule, "(width %.6g)", scale( defaultTrackWidth ) );
rules.push_back( rule ); rules.push_back( rule );

View File

@ -53,8 +53,7 @@ int GLOBAL_EDIT_TOOL::CleanupTracksAndVias( const TOOL_EVENT& aEvent )
TRACKS_CLEANER::TRACKS_CLEANER( EDA_UNITS aUnits, BOARD* aPcb, BOARD_COMMIT& aCommit ) TRACKS_CLEANER::TRACKS_CLEANER( EDA_UNITS aUnits, BOARD* aPcb, BOARD_COMMIT& aCommit )
: m_units( aUnits ), : m_brd( aPcb ),
m_brd( aPcb ),
m_commit( aCommit ), m_commit( aCommit ),
m_dryRun( true ), m_dryRun( true ),
m_itemsList( nullptr ) m_itemsList( nullptr )

View File

@ -99,7 +99,6 @@ private:
*/ */
bool testTrackEndpointIsNode( TRACK* aTrack, bool aTstStart ); bool testTrackEndpointIsNode( TRACK* aTrack, bool aTstStart );
EDA_UNITS m_units;
BOARD* m_brd; BOARD* m_brd;
BOARD_COMMIT& m_commit; BOARD_COMMIT& m_commit;
bool m_dryRun; bool m_dryRun;