7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-20 20:11:41 +00:00
Jeff Young 2020-05-16 00:25:33 +01:00
parent 1d914133c9
commit d3f017d825
31 changed files with 1084 additions and 141 deletions

2
.gitignore vendored
View File

@ -3,6 +3,8 @@ boost_root
Build*
build*
common/fp_lib_table_keywords.cpp
common/drc_rules_keywords.cpp
common/drc_rules_lexer.h
common/netlist_keywords.*
common/netlist_lexer.h
common/pcb_plot_params_lexer.h

View File

@ -463,6 +463,7 @@ set( PCB_COMMON_SRCS
${CMAKE_SOURCE_DIR}/pcbnew/connectivity/connectivity_data.cpp
${CMAKE_SOURCE_DIR}/pcbnew/convert_drawsegment_list_to_polygon.cpp
${CMAKE_SOURCE_DIR}/pcbnew/drc/drc_item.cpp
${CMAKE_SOURCE_DIR}/pcbnew/drc/drc_rule.cpp
${CMAKE_SOURCE_DIR}/pcbnew/eagle_plugin.cpp
${CMAKE_SOURCE_DIR}/pcbnew/footprint_editor_settings.cpp
${CMAKE_SOURCE_DIR}/pcbnew/gpcb_plugin.cpp
@ -525,6 +526,15 @@ make_lexer(
PCBPLOTPARAMS_T
)
# auto-generate drc_rules_lexer.h and drc_rules_keywords.cpp
make_lexer(
common
drc_rules.keywords
drc_rules_lexer.h
drc_rules_keywords.cpp
DRCRULE_T
)
# auto-generate pcbnew_sexpr.h and pcbnew_sexpr.cpp
make_lexer(
pcbcommon

25
common/drc_rules.keywords Normal file
View File

@ -0,0 +1,25 @@
allow
annulus_width
blind_via
board_edge
clearance
track_width
graphic
hole
match_area
match_layer
match_netclass
match_type
micro_via
npth
pad
priority
pth
relaxed
rule
selector
text
track
version
via
zone

View File

@ -29,6 +29,8 @@
#include <netclass.h>
#include <config_params.h>
#include <board_stackup_manager/class_board_stackup.h>
#include <drc/drc_rule.h>
#define DEFAULT_SILK_LINE_WIDTH 0.12
#define DEFAULT_COPPER_LINE_WIDTH 0.20
@ -194,6 +196,7 @@ struct TEXT_ITEM_INFO
// forward declaration from class_track.h
enum class VIATYPE : int;
/**
* BOARD_DESIGN_SETTINGS
* contains design settings for a BOARD object.
@ -207,7 +210,9 @@ public:
std::vector<DIFF_PAIR_DIMENSION> m_DiffPairDimensionsList;
// List of netclasses. There is always the default netclass.
NETCLASSES m_NetClasses;
NETCLASSES m_NetClasses;
std::vector<DRC_SELECTOR*> m_DRCRuleSelectors;
std::vector<DRC_RULE*> m_DRCRules;
bool m_MicroViasAllowed; ///< true to allow micro vias
bool m_BlindBuriedViaAllowed; ///< true to allow blind/buried vias
@ -389,6 +394,10 @@ public:
*/
int GetSmallestClearanceValue();
int GetRuleClearance( const BOARD_ITEM* aItem, const NETCLASS* aItemNetclass,
const BOARD_ITEM* bItem, const NETCLASS* bItemNetclass,
wxString* aSource );
/**
* Function GetCurrentMicroViaSize
* @return the current micro via size,
@ -863,10 +872,6 @@ public:
bool GetTextUpright( PCB_LAYER_ID aLayer ) const;
int GetLayerClass( PCB_LAYER_ID aLayer ) const;
private:
void formatNetClass( NETCLASS* aNetClass, OUTPUTFORMATTER* aFormatter, int aNestLevel,
int aControlBits ) const;
};
#endif // BOARD_DESIGN_SETTINGS_H_

View File

@ -103,6 +103,16 @@ enum KICAD_T
PCB_ITEM_LIST_T, ///< class BOARD_ITEM_LIST, a list of board items
PCB_NETINFO_T, ///< class NETINFO_ITEM, a description of a net
PCB_LOCATE_STDVIA_T,
PCB_LOCATE_UVIA_T,
PCB_LOCATE_BBVIA_T,
PCB_LOCATE_TEXT_T,
PCB_LOCATE_GRAPHIC_T,
PCB_LOCATE_HOLE_T,
PCB_LOCATE_PTH_T,
PCB_LOCATE_NPTH_T,
PCB_LOCATE_BOARD_EDGE_T,
// Schematic draw Items. The order of these items effects the sort order.
// It is currently ordered to mimic the old Eeschema locate behavior where
// the smallest item is the selected item.
@ -235,6 +245,11 @@ constexpr KICAD_T BaseType( const KICAD_T aType )
case SCH_COMPONENT_LOCATE_POWER_T:
return SCH_COMPONENT_T;
case PCB_LOCATE_HOLE_T:
case PCB_LOCATE_PTH_T:
case PCB_LOCATE_NPTH_T:
return PCB_LOCATE_HOLE_T;
default:
return aType;
}

View File

@ -233,6 +233,7 @@ set( PCBNEW_DRC_SRCS
drc/drc_courtyard_tester.cpp
drc/drc.cpp
drc/drc_clearance_test_functions.cpp
drc/drc_rule_parser.cpp
)
set( PCBNEW_NETLIST_SRCS

View File

@ -79,36 +79,63 @@ bool BOARD_CONNECTED_ITEM::SetNetCode( int aNetCode, bool aNoAssert )
}
int BOARD_CONNECTED_ITEM::GetClearance( BOARD_CONNECTED_ITEM* aItem, wxString* aSource ) const
int BOARD_CONNECTED_ITEM::GetClearance( BOARD_ITEM* aItem, wxString* aSource ) const
{
NETCLASSPTR netclass;
NETCLASS* myNetclass = 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
// orphaned net netclass, not the default netclass.
if( GetBoard() )
{
if( m_netinfo->GetNet() == 0 )
netclass = GetBoard()->GetDesignSettings().GetDefault();
myNetclass = GetBoard()->GetDesignSettings().GetDefault().get();
else
netclass = GetNetClass();
myNetclass = GetNetClass().get();
bds = &GetBoard()->GetDesignSettings();
}
// No clearance if "this" is not (yet) linked to a board therefore no available netclass
int myClearance = netclass ? netclass->GetClearance() : 0;
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();
if( aItem && aItem->GetClearance() > myClearance )
return aItem->GetClearance( nullptr, aSource );
bds = &aItem->GetBoard()->GetDesignSettings();
}
int myClearance = myNetclass ? myNetclass->GetClearance() : 0;
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( netclass )
*aSource = wxString::Format( _( "%s netclass clearance" ),
netclass->GetName() );
if( clearance == myClearance && myNetclass )
{
*aSource = wxString::Format( _( "'%s' netclass clearance" ), myNetclass->GetName() );
}
else if( clearance == itemClearance && itemNetclass )
{
*aSource = wxString::Format( _( "'%s' netclass clearance" ), itemNetclass->GetName() );
}
else if( clearance == ruleClearance && !ruleSource.IsEmpty() )
{
*aSource = wxString::Format( _( "'%s' rule clearance" ), ruleSource );
}
else
{
*aSource = _( "No netclass" );
}
}
return myClearance;
return clearance;
}

View File

@ -157,12 +157,11 @@ public:
* returned clearance is the greater of this object's NETCLASS clearance and
* aItem's NETCLASS clearance. If \a aItem is NULL, then this objects clearance
* is returned.
* @param aItem is an optional BOARD_CONNECTED_ITEM
* @param aItem is an optional BOARD_ITEM
* @param aSource [out] optionally reports the source as a user-readable string
* @return int - the clearance in internal units.
*/
virtual int GetClearance( BOARD_CONNECTED_ITEM* aItem = nullptr,
wxString* aSource = nullptr ) const;
virtual int GetClearance( BOARD_ITEM* aItem = nullptr, wxString* aSource = nullptr ) const;
/**
* Function GetNetClass

View File

@ -36,6 +36,7 @@
#include <board_design_settings.h>
#include <drc/drc.h>
#include <widgets/ui_common.h>
#include <drc/drc_rule.h>
#define CopperLayerCountKey wxT( "CopperLayerCount" )
#define BoardThicknessKey wxT( "BoardThickness" )
@ -962,12 +963,11 @@ int BOARD_DESIGN_SETTINGS::GetBiggestClearanceValue()
{
int clearance = m_NetClasses.GetDefault()->GetClearance();
//Read list of Net Classes
for( NETCLASSES::const_iterator nc = m_NetClasses.begin(); nc != m_NetClasses.end(); ++nc )
{
NETCLASSPTR netclass = nc->second;
clearance = std::max( clearance, netclass->GetClearance() );
}
for( const std::pair<wxString, NETCLASSPTR>& netclass : m_NetClasses.NetClasses() )
clearance = std::max( clearance, netclass.second->GetClearance() );
for( const DRC_RULE* rule : m_DRCRules )
clearance = std::max( clearance, rule->m_Clearance );
return clearance;
}
@ -977,11 +977,48 @@ int BOARD_DESIGN_SETTINGS::GetSmallestClearanceValue()
{
int clearance = m_NetClasses.GetDefault()->GetClearance();
//Read list of Net Classes
for( NETCLASSES::const_iterator nc = m_NetClasses.begin(); nc != m_NetClasses.end(); ++nc )
for( const std::pair<wxString, NETCLASSPTR>& netclass : m_NetClasses.NetClasses() )
clearance = std::min( clearance, netclass.second->GetClearance() );
return clearance;
}
int BOARD_DESIGN_SETTINGS::GetRuleClearance( const BOARD_ITEM* aItem, const NETCLASS* aNetclass,
const BOARD_ITEM* bItem, const NETCLASS* bNetclass,
wxString* aSource )
{
std::vector<DRC_SELECTOR*> matched;
MatchSelectors( m_DRCRuleSelectors, aItem, aNetclass, bItem, bNetclass, &matched );
std::sort( matched.begin(), matched.end(),
[]( DRC_SELECTOR* a, DRC_SELECTOR* b ) -> bool
{
return a->m_Priority < b->m_Priority;
});
int clearance = 0;
for( DRC_SELECTOR* selector : matched )
{
NETCLASSPTR netclass = nc->second;
clearance = std::min( clearance, netclass->GetClearance() );
// ignore hole rules; we're just interested in copper here
for( KICAD_T matchType : selector->m_MatchTypes )
{
if( BaseType( matchType ) == PCB_LOCATE_HOLE_T )
continue;
}
if( selector->m_Rule->m_Clearance > 0 )
{
clearance = std::max( clearance, selector->m_Rule->m_Clearance );
*aSource = selector->m_Rule->m_Name;
}
else if( selector->m_Rule->m_Clearance < 0 )
{
clearance = std::min( clearance, abs( selector->m_Rule->m_Clearance ) );
*aSource = selector->m_Rule->m_Name;
}
}
return clearance;

View File

@ -88,6 +88,20 @@ public:
return aItem && PCB_DIMENSION_T == aItem->Type();
}
bool IsType( const KICAD_T aScanTypes[] ) const override
{
if( BOARD_ITEM::IsType( aScanTypes ) )
return true;
for( const KICAD_T* p = aScanTypes; *p != EOT; ++p )
{
if( *p == PCB_LOCATE_GRAPHIC_T )
return true;
}
return false;
}
void SetValue( int aValue ) { m_Value = aValue; }
int GetValue() const { return m_Value; }

View File

@ -77,6 +77,22 @@ public:
return aItem && PCB_LINE_T == aItem->Type();
}
bool IsType( const KICAD_T aScanTypes[] ) const override
{
if( BOARD_ITEM::IsType( aScanTypes ) )
return true;
for( const KICAD_T* p = aScanTypes; *p != EOT; ++p )
{
if( *p == PCB_LOCATE_GRAPHIC_T )
return true;
else if( *p == PCB_LOCATE_BOARD_EDGE_T )
return m_Layer == Edge_Cuts;
}
return false;
}
/** Polygonal shape is not always filled.
* For now it is filled on all layers but Edge_Cut layer
*/

View File

@ -56,6 +56,22 @@ public:
return aItem && PCB_MODULE_EDGE_T == aItem->Type();
}
bool IsType( const KICAD_T aScanTypes[] ) const override
{
if( BOARD_ITEM::IsType( aScanTypes ) )
return true;
for( const KICAD_T* p = aScanTypes; *p != EOT; ++p )
{
if( *p == PCB_LOCATE_GRAPHIC_T )
return true;
else if( *p == PCB_LOCATE_BOARD_EDGE_T )
return m_Layer == Edge_Cuts;
}
return false;
}
/**
* Move an edge of the footprint.
* This is a footprint shape modification.

View File

@ -623,14 +623,14 @@ wxPoint D_PAD::ShapePos() const
}
int D_PAD::GetClearance( BOARD_CONNECTED_ITEM* aItem, wxString* aSource ) const
int D_PAD::GetClearance( BOARD_ITEM* aItem, wxString* aSource ) const
{
int myClearance;
int clearance;
// A pad can have specific clearance that overrides its NETCLASS clearance value
if( m_LocalClearance )
{
myClearance = m_LocalClearance;
clearance = m_LocalClearance;
if( aSource )
*aSource = wxString::Format( _( "pad %s clearance" ), GetName() );
@ -639,22 +639,19 @@ int D_PAD::GetClearance( BOARD_CONNECTED_ITEM* aItem, wxString* aSource ) const
// A footprint can have a specific clearance value
else if( GetParent() && GetParent()->GetLocalClearance() )
{
myClearance = GetParent()->GetLocalClearance();
clearance = GetParent()->GetLocalClearance();
if( aSource )
*aSource = wxString::Format( _( "%s footprint clearance" ), GetParent()->GetReference() );
}
// Otherwise use the baseclass method to fetch the netclass setting
// Otherwise use the baseclass method to fetch the netclass and/or rule setting
else
{
myClearance = BOARD_CONNECTED_ITEM::GetClearance( nullptr, aSource );
clearance = BOARD_CONNECTED_ITEM::GetClearance( aItem, aSource );
}
if( aItem && aItem->GetClearance() > myClearance )
return aItem->GetClearance( nullptr, aSource );
return myClearance;
return clearance;
}

View File

@ -140,6 +140,27 @@ public:
return aItem && PCB_PAD_T == aItem->Type();
}
bool IsType( const KICAD_T aScanTypes[] ) const override
{
if( BOARD_CONNECTED_ITEM::IsType( aScanTypes ) )
return true;
for( const KICAD_T* p = aScanTypes; *p != EOT; ++p )
{
if( m_Drill.x > 0 && m_Drill.y > 0 )
{
if( *p == PCB_LOCATE_HOLE_T )
return true;
else if( *p == PCB_LOCATE_PTH_T && m_Attribute != PAD_ATTRIB_HOLE_NOT_PLATED )
return true;
else if( *p == PCB_LOCATE_NPTH_T && m_Attribute == PAD_ATTRIB_HOLE_NOT_PLATED )
return true;
}
}
return false;
}
MODULE* GetParent() const { return (MODULE*) m_Parent; }
/**
@ -459,12 +480,11 @@ public:
* returned clearance is the greater of this object's clearance and
* aItem's clearance. If \a aItem is NULL, then this objects clearance
* is returned.
* @param aItem is an optional BOARD_CONNECTED_ITEM
* @param aItem is an optional BOARD_ITEM
* @param aSource [out] optionally reports the source as a user-readable string
* @return int - the clearance in internal units.
*/
int GetClearance( BOARD_CONNECTED_ITEM* aItem = nullptr,
wxString* aSource = nullptr ) const override;
int GetClearance( BOARD_ITEM* aItem = nullptr, wxString* aSource = nullptr ) const override;
// Mask margins handling:

View File

@ -53,6 +53,20 @@ public:
return aItem && PCB_TEXT_T == aItem->Type();
}
bool IsType( const KICAD_T aScanTypes[] ) const override
{
if( BOARD_ITEM::IsType( aScanTypes ) )
return true;
for( const KICAD_T* p = aScanTypes; *p != EOT; ++p )
{
if( *p == PCB_LOCATE_TEXT_T )
return true;
}
return false;
}
wxString GetShownText( int aDepth = 0 ) const override;
bool Matches( wxFindReplaceData& aSearchData, void* aAuxData ) override

View File

@ -74,6 +74,20 @@ public:
return aItem && PCB_MODULE_TEXT_T == aItem->Type();
}
bool IsType( const KICAD_T aScanTypes[] ) const override
{
if( BOARD_ITEM::IsType( aScanTypes ) )
return true;
for( const KICAD_T* p = aScanTypes; *p != EOT; ++p )
{
if( *p == PCB_LOCATE_TEXT_T )
return true;
}
return false;
}
bool Matches( wxFindReplaceData& aSearchData, void* aAuxData ) override
{
return BOARD_ITEM::Matches( GetShownText(), aSearchData );

View File

@ -117,7 +117,7 @@ BITMAP_DEF VIA::GetMenuImage() const
}
int TRACK::GetClearance( BOARD_CONNECTED_ITEM* aItem, wxString* aSource ) const
int TRACK::GetClearance( BOARD_ITEM* aItem, wxString* aSource ) const
{
// Currently tracks have no specific clearance parameter on a per track or per
// segment basis. The NETCLASS clearance is used.

View File

@ -200,12 +200,11 @@ public:
* returned clearance is the greater of this object's clearance and
* aItem's clearance. If \a aItem is NULL, then this objects clearance
* is returned.
* @param aItem is an optional BOARD_CONNECTED_ITEM
* @param aItem is an optional BOARD_ITEM
* @param aSource [out] optionally reports the source as a user-readable string
* @return int - the clearance in internal units.
*/
int GetClearance( BOARD_CONNECTED_ITEM* aItem = nullptr,
wxString* aSource = nullptr ) const override;
int GetClearance( BOARD_ITEM* aItem = nullptr, wxString* aSource = nullptr ) const override;
wxString GetSelectMenuText( EDA_UNITS aUnits ) const override;
@ -350,6 +349,24 @@ public:
// Do not create a copy constructor. The one generated by the compiler is adequate.
bool IsType( const KICAD_T aScanTypes[] ) const override
{
if( BOARD_CONNECTED_ITEM::IsType( aScanTypes ) )
return true;
for( const KICAD_T* p = aScanTypes; *p != EOT; ++p )
{
if( *p == PCB_LOCATE_STDVIA_T && m_ViaType == VIATYPE::THROUGH )
return true;
else if( *p == PCB_LOCATE_UVIA_T && m_ViaType == VIATYPE::MICROVIA )
return true;
else if( *p == PCB_LOCATE_BBVIA_T && m_ViaType == VIATYPE::BLIND_BURIED )
return true;
}
return false;
}
bool IsOnLayer( PCB_LAYER_ID aLayer ) const override;
virtual LSET GetLayerSet() const override;

View File

@ -458,33 +458,31 @@ bool ZONE_CONTAINER::HitTest( const EDA_RECT& aRect, bool aContained, int aAccur
}
int ZONE_CONTAINER::GetClearance( BOARD_CONNECTED_ITEM* aItem, wxString* aSource ) const
int ZONE_CONTAINER::GetClearance( BOARD_ITEM* aItem, wxString* aSource ) const
{
if( m_isKeepout )
return 0;
// The actual zone clearance is the biggest of the zone netclass clearance
// and the zone clearance setting in the zone properties dialog.
int myClearance = m_ZoneClearance;
int zoneClearance = m_ZoneClearance;
wxString source;
int clearance = BOARD_CONNECTED_ITEM::GetClearance( aItem, &source );
if( aSource )
*aSource = _( "zone clearance" );
if( !m_isKeepout ) // Net class has no meaning for a keepout area.
if( clearance > zoneClearance )
{
NETCLASSPTR myClass = GetNetClass();
if( aSource )
*aSource = source;
if( myClass->GetClearance() > myClearance )
{
myClearance = myClass->GetClearance();
if( aSource )
*aSource = wxString::Format( _( "'%s' netclass clearance" ), myClass->GetName() );
}
return clearance;
}
else
{
if( aSource )
*aSource = _( "zone clearance" );
// Get the final clearance between me and aItem
if( aItem && aItem->GetClearance() > myClearance )
return aItem->GetClearance( nullptr, aSource );
return myClearance;
return zoneClearance;
}
}

View File

@ -110,8 +110,7 @@ public:
*/
const EDA_RECT GetBoundingBox() const override;
int GetClearance( BOARD_CONNECTED_ITEM* aItem = nullptr,
wxString* aSource = nullptr ) const override;
int GetClearance( BOARD_ITEM* aItem = nullptr, wxString* aSource = nullptr ) const override;
/**
* Function IsOnCopperLayer

View File

@ -60,7 +60,6 @@ DIALOG_DRC::DIALOG_DRC( DRC* aTester, PCB_EDIT_FRAME* aEditorFrame, wxWindow* aP
m_tester = aTester;
m_brdEditor = aEditorFrame;
m_currentBoard = m_brdEditor->GetBoard();
m_BrdSettings = m_brdEditor->GetBoard()->GetDesignSettings();
m_markerTreeModel = new RC_TREE_MODEL( m_brdEditor, m_markerDataView );
m_markerDataView->AssociateModel( m_markerTreeModel );
@ -117,7 +116,6 @@ void DIALOG_DRC::OnActivateDlg( wxActivateEvent& aEvent )
// updating data which can be modified outside the dialog (DRC parameters, units ...)
// because the dialog is not modal
m_BrdSettings = m_brdEditor->GetBoard()->GetDesignSettings();
displayDRCValues();
m_markerTreeModel->SetProvider( m_markersProvider );
@ -129,9 +127,9 @@ void DIALOG_DRC::OnActivateDlg( wxActivateEvent& aEvent )
void DIALOG_DRC::displayDRCValues()
{
m_trackMinWidth.SetValue( m_BrdSettings.m_TrackMinWidth );
m_viaMinSize.SetValue( m_BrdSettings.m_ViasMinSize );
m_uviaMinSize.SetValue( m_BrdSettings.m_MicroViasMinSize );
m_trackMinWidth.SetValue( bds().m_TrackMinWidth );
m_viaMinSize.SetValue( bds().m_ViasMinSize );
m_uviaMinSize.SetValue( bds().m_MicroViasMinSize );
}
@ -162,11 +160,9 @@ void DIALOG_DRC::initValues()
void DIALOG_DRC::setDRCParameters()
{
m_BrdSettings.m_TrackMinWidth = (int) m_trackMinWidth.GetValue();
m_BrdSettings.m_ViasMinSize = (int) m_viaMinSize.GetValue();
m_BrdSettings.m_MicroViasMinSize = (int) m_uviaMinSize.GetValue();
m_brdEditor->GetBoard()->SetDesignSettings( m_BrdSettings );
bds().m_TrackMinWidth = (int) m_trackMinWidth.GetValue();
bds().m_ViasMinSize = (int) m_viaMinSize.GetValue();
bds().m_MicroViasMinSize = (int) m_uviaMinSize.GetValue();
}
@ -287,7 +283,7 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
wxMenu menu;
wxString msg;
switch( m_BrdSettings.m_DRCSeverities[ rcItem->GetErrorCode() ] )
switch( bds().m_DRCSeverities[ rcItem->GetErrorCode() ] )
{
case RPT_SEVERITY_ERROR: listName = _( "errors" ); break;
case RPT_SEVERITY_WARNING: listName = _( "warnings" ); break;
@ -307,7 +303,7 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
menu.AppendSeparator();
if( m_BrdSettings.m_DRCSeverities[ rcItem->GetErrorCode() ] == RPT_SEVERITY_WARNING )
if( bds().m_DRCSeverities[ rcItem->GetErrorCode() ] == RPT_SEVERITY_WARNING )
{
msg.Printf( _( "Change severity to Error for all '%s' violations" ),
rcItem->GetErrorText( rcItem->GetErrorCode() ),
@ -356,8 +352,7 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
break;
case 3:
m_BrdSettings.m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_ERROR;
m_brdEditor->GetBoard()->SetDesignSettings( m_BrdSettings );
bds().m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_ERROR;
// Rebuild model and view
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->SetProvider( m_markersProvider );
@ -365,8 +360,7 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
break;
case 4:
m_BrdSettings.m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_WARNING;
m_brdEditor->GetBoard()->SetDesignSettings( m_BrdSettings );
bds().m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_WARNING;
// Rebuild model and view
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->SetProvider( m_markersProvider );
@ -375,8 +369,7 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
case 5:
{
m_BrdSettings.m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_IGNORE;
m_brdEditor->GetBoard()->SetDesignSettings( m_BrdSettings );
bds().m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_IGNORE;
std::vector<MARKER_PCB*>& markers = m_brdEditor->GetBoard()->Markers();

View File

@ -47,8 +47,6 @@ class
DIALOG_DRC: public DIALOG_DRC_BASE
{
public:
BOARD_DESIGN_SETTINGS m_BrdSettings;
/// Constructors
DIALOG_DRC( DRC* aTester, PCB_EDIT_FRAME* aEditorFrame, wxWindow* aParent );
~DIALOG_DRC();
@ -94,6 +92,8 @@ private:
void deleteAllMarkers();
void refreshBoardEditor();
BOARD_DESIGN_SETTINGS& bds() { return m_currentBoard->GetDesignSettings(); }
BOARD* m_currentBoard; // the board currently on test
DRC* m_tester;
PCB_EDIT_FRAME* m_brdEditor;

View File

@ -54,6 +54,8 @@
#include <drc/drc_item.h>
#include <drc/drc_courtyard_tester.h>
#include <tools/zone_filler_tool.h>
#include <confirm.h>
#include "drc_rule_parser.h"
DRC::DRC() :
PCB_TOOL_BASE( "pcbnew.DRCTool" ),
@ -95,6 +97,8 @@ void DRC::Reset( RESET_REASON aReason )
DestroyDRCDialog( wxID_OK );
m_pcb = m_pcbEditorFrame->GetBoard();
readRules();
}
}
@ -350,8 +354,36 @@ int DRC::TestZoneToZoneOutlines()
}
void DRC::readRules()
{
wxString rulesFilepath = m_pcbEditorFrame->Prj().AbsolutePath( "drc-rules" );
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
bds.m_DRCRuleSelectors.clear();
bds.m_DRCRules.clear();
FILE* fp = wxFopen( rulesFilepath, wxT( "rt" ) );
if( fp )
{
try
{
DRC_RULES_PARSER parser( m_pcb, fp, rulesFilepath );
parser.Parse( bds.m_DRCRuleSelectors, bds.m_DRCRules );
}
catch( PARSE_ERROR& pe )
{
DisplayError( m_drcDialog, pe.What() );
}
}
}
void DRC::RunTests( wxTextCtrl* aMessages )
{
// TODO: timestamp file and read only if newer
readRules();
// be sure m_pcb is the current board, not a old one
// ( the board can be reloaded )
m_pcb = m_pcbEditorFrame->GetBoard();
@ -727,7 +759,7 @@ void DRC::testPad2Pad()
void DRC::testDrilledHoles()
{
BOARD_DESIGN_SETTINGS& dsnSettings = m_pcb->GetDesignSettings();
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
// Test drilled holes to minimize drill bit breakage.
//
@ -738,8 +770,8 @@ void DRC::testDrilledHoles()
struct DRILLED_HOLE
{
wxPoint m_location;
int m_drillRadius;
BOARD_ITEM* m_owner;
int m_drillRadius = 0;
BOARD_ITEM* m_owner = nullptr;
};
std::vector<DRILLED_HOLE> holes;
@ -750,19 +782,37 @@ void DRC::testDrilledHoles()
{
for( D_PAD* pad : mod->Pads( ) )
{
int minDimension = std::min( pad->GetDrillSize().x, pad->GetDrillSize().y );
int holeSize = std::min( pad->GetDrillSize().x, pad->GetDrillSize().y );
if( minDimension == 0 )
if( holeSize == 0 )
continue;
if( !dsnSettings.Ignore( DRCE_TOO_SMALL_PAD_DRILL )
&& minDimension < dsnSettings.m_MinThroughDrill )
NETCLASS* netclass = pad->GetNet()->GetNet() == 0 ? bds.GetDefault().get()
: pad->GetNetClass().get();
int minHole = bds.m_MinThroughDrill;
wxString minHoleSource = _( "board" );
std::vector<DRC_SELECTOR*> matched;
MatchSelectors( bds.m_DRCRuleSelectors, pad, netclass, nullptr, nullptr, &matched );
for( DRC_SELECTOR* selector : matched )
{
if( selector->m_Rule->m_Hole > minHole )
{
minHole = selector->m_Rule->m_Hole;
minHoleSource = wxString::Format( _( "'%s' rule" ), selector->m_Rule->m_Name );
}
}
if( !bds.Ignore( DRCE_TOO_SMALL_PAD_DRILL ) && holeSize < minHole )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_PAD_DRILL );
msg.Printf( drcItem->GetErrorText() + _( " (board min through hole %s; actual %s)" ),
MessageTextFromValue( userUnits(), dsnSettings.m_MinThroughDrill, true ),
MessageTextFromValue( userUnits(), minDimension, true ) );
msg.Printf( drcItem->GetErrorText() + _( " (%s min hole %s; actual %s)" ),
minHoleSource,
MessageTextFromValue( userUnits(), minHole, true ),
MessageTextFromValue( userUnits(), holeSize, true ) );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( pad );
@ -788,15 +838,39 @@ void DRC::testDrilledHoles()
if( !via )
continue;
NETCLASS* netclass = via->GetNet()->GetNet() == 0 ? bds.GetDefault().get()
: via->GetNetClass().get();
int minHole = 0;
wxString minHoleSource;
std::vector<DRC_SELECTOR*> matched;
MatchSelectors( bds.m_DRCRuleSelectors, via, netclass, nullptr, nullptr, &matched );
for( DRC_SELECTOR* selector : matched )
{
if( selector->m_Rule->m_Hole > minHole )
{
minHole = selector->m_Rule->m_Hole;
minHoleSource = wxString::Format( _( "'%s' rule" ), selector->m_Rule->m_Name );
}
}
if( via->GetViaType() == VIATYPE::MICROVIA )
{
if( !dsnSettings.Ignore( DRCE_TOO_SMALL_MICROVIA_DRILL )
&& via->GetDrillValue() < dsnSettings.m_MicroViasMinDrill )
if( bds.m_MicroViasMinDrill > minHole )
{
minHole = bds.m_MicroViasMinDrill;
minHoleSource = _( "board" );
}
if( !bds.Ignore( DRCE_TOO_SMALL_MICROVIA_DRILL ) && via->GetDrillValue() < minHole )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_MICROVIA_DRILL );
msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
MessageTextFromValue( userUnits(), dsnSettings.m_MicroViasMinDrill, true ),
msg.Printf( drcItem->GetErrorText() + _( " (%s minimum %s; actual %s)" ),
minHoleSource,
MessageTextFromValue( userUnits(), minHole, true ),
MessageTextFromValue( userUnits(), via->GetDrillValue(), true ) );
drcItem->SetErrorMessage( msg );
@ -808,13 +882,19 @@ void DRC::testDrilledHoles()
}
else
{
if( !dsnSettings.Ignore( DRCE_TOO_SMALL_VIA_DRILL )
&& via->GetDrillValue() < dsnSettings.m_MinThroughDrill )
if( bds.m_MinThroughDrill > minHole )
{
minHole = bds.m_MinThroughDrill;
minHoleSource = _( "board" );
}
if( !bds.Ignore( DRCE_TOO_SMALL_VIA_DRILL ) && via->GetDrillValue() < minHole )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_VIA_DRILL );
msg.Printf( drcItem->GetErrorText() + _( " (board min through hole %s; actual %s)" ),
MessageTextFromValue( userUnits(), dsnSettings.m_MinThroughDrill, true ),
msg.Printf( drcItem->GetErrorText() + _( " (%s min hole %s; actual %s)" ),
minHoleSource,
MessageTextFromValue( userUnits(), minHole, true ),
MessageTextFromValue( userUnits(), via->GetDrillValue(), true ) );
drcItem->SetErrorMessage( msg );
@ -831,7 +911,7 @@ void DRC::testDrilledHoles()
}
}
if( dsnSettings.m_HoleToHoleMin == 0 || dsnSettings.Ignore( DRCE_DRILLED_HOLES_TOO_CLOSE ) )
if( bds.m_HoleToHoleMin == 0 || bds.Ignore( DRCE_DRILLED_HOLES_TOO_CLOSE ) )
return;
for( size_t ii = 0; ii < holes.size(); ++ii )
@ -849,12 +929,12 @@ void DRC::testDrilledHoles()
int actual = KiROUND( GetLineLength( checkHole.m_location, refHole.m_location ) );
actual = std::max( 0, actual - checkHole.m_drillRadius - refHole.m_drillRadius );
if( actual < dsnSettings.m_HoleToHoleMin )
if( actual < bds.m_HoleToHoleMin )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_DRILLED_HOLES_TOO_CLOSE );
msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
MessageTextFromValue( userUnits(), dsnSettings.m_HoleToHoleMin, true ),
MessageTextFromValue( userUnits(), bds.m_HoleToHoleMin, true ),
MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( msg );

View File

@ -162,7 +162,7 @@ private:
PCB_EDIT_FRAME* m_pcbEditorFrame; // The pcb frame editor which owns the board
BOARD* m_pcb;
SHAPE_POLY_SET m_board_outlines; // The board outline including cutouts
DIALOG_DRC* m_drcDialog;
DIALOG_DRC* m_drcDialog;
std::vector<DRC_ITEM*> m_unconnected; // list of unconnected pads
std::vector<DRC_ITEM*> m_footprints; // list of footprint warnings
@ -177,6 +177,8 @@ private:
*/
void updatePointers();
void readRules();
EDA_UNITS userUnits() const { return m_pcbEditorFrame->GetUserUnits(); }
/**

View File

@ -139,13 +139,18 @@ bool poly2segmentDRC( wxPoint* aTref, int aTrefCount, wxPoint aSegStart, wxPoint
void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterator aEndIt,
bool aTestZones )
{
BOARD_DESIGN_SETTINGS& dsnSettings = m_pcb->GetDesignSettings();
wxString msg;
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
std::vector<DRC_SELECTOR*> matched;
SEG refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
LSET layerMask = aRefSeg->GetLayerSet();
EDA_RECT refSegBB = aRefSeg->GetBoundingBox();
int refSegWidth = aRefSeg->GetWidth();
wxString msg;
SEG refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
LSET layerMask = aRefSeg->GetLayerSet();
NETCLASS* netclass = aRefSeg->GetNet()->GetNet() == 0 ? bds.GetDefault().get()
: aRefSeg->GetNetClass().get();
EDA_RECT refSegBB = aRefSeg->GetBoundingBox();
int refSegWidth = aRefSeg->GetWidth();
MatchSelectors( bds.m_DRCRuleSelectors, aRefSeg, netclass, nullptr, nullptr, &matched );
/******************************************/
@ -154,17 +159,45 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
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 minAnnulus;
wxString minAnnulusSource;
for( DRC_SELECTOR* selector : matched )
{
if( selector->m_Rule->m_AnnulusWidth > minAnnulus )
{
minAnnulus = selector->m_Rule->m_AnnulusWidth;
minAnnulusSource = wxString::Format( _( "'%s' rule" ), selector->m_Rule->m_Name );
}
}
// test if the via size is smaller than minimum
if( refvia->GetViaType() == VIATYPE::MICROVIA )
{
if( refvia->GetWidth() < dsnSettings.m_MicroViasMinSize )
if( viaAnnulus < minAnnulus )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_VIA_ANNULUS );
msg.Printf( drcItem->GetErrorText() + _( " (%s minimum %s; actual %s)" ),
minAnnulusSource,
MessageTextFromValue( userUnits(), minAnnulus, true ),
MessageTextFromValue( userUnits(), viaAnnulus, true ) );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( marker );
}
if( refvia->GetWidth() < bds.m_MicroViasMinSize )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_MICROVIA );
msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
MessageTextFromValue( userUnits(), dsnSettings.m_MicroViasMinSize, true ),
MessageTextFromValue( userUnits(), bds.m_MicroViasMinSize, true ),
MessageTextFromValue( userUnits(), refvia->GetWidth(), true ) );
drcItem->SetErrorMessage( msg );
@ -176,14 +209,19 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
}
else
{
int viaAnnulus = ( refvia->GetWidth() - refvia->GetDrill() ) / 2;
if( bds.m_ViasMinAnnulus > minAnnulus )
{
minAnnulus = bds.m_ViasMinAnnulus;
minAnnulusSource = _( "board" );
}
if( viaAnnulus < dsnSettings.m_ViasMinAnnulus )
if( viaAnnulus < minAnnulus )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_VIA_ANNULUS );
msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
MessageTextFromValue( userUnits(), dsnSettings.m_ViasMinSize, true ),
msg.Printf( drcItem->GetErrorText() + _( " (%s minimum %s; actual %s)" ),
minAnnulusSource,
MessageTextFromValue( userUnits(), minAnnulus, true ),
MessageTextFromValue( userUnits(), viaAnnulus, true ) );
drcItem->SetErrorMessage( msg );
@ -193,12 +231,12 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
addMarkerToPcb( marker );
}
if( refvia->GetWidth() < dsnSettings.m_ViasMinSize )
if( refvia->GetWidth() < bds.m_ViasMinSize )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_VIA );
msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
MessageTextFromValue( userUnits(), dsnSettings.m_ViasMinSize, true ),
MessageTextFromValue( userUnits(), bds.m_ViasMinSize, true ),
MessageTextFromValue( userUnits(), refvia->GetWidth(), true ) );
drcItem->SetErrorMessage( msg );
@ -228,7 +266,7 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
}
// test if the type of via is allowed due to design rules
if( refvia->GetViaType() == VIATYPE::MICROVIA && !dsnSettings.m_MicroViasAllowed )
if( refvia->GetViaType() == VIATYPE::MICROVIA && !bds.m_MicroViasAllowed )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_MICROVIA_NOT_ALLOWED );
@ -241,7 +279,7 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
}
// test if the type of via is allowed due to design rules
if( refvia->GetViaType() == VIATYPE::BLIND_BURIED && !dsnSettings.m_BlindBuriedViaAllowed )
if( refvia->GetViaType() == VIATYPE::BLIND_BURIED && !bds.m_BlindBuriedViaAllowed )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_BURIED_VIA_NOT_ALLOWED );
@ -266,7 +304,7 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
if( layer1 > layer2 )
std::swap( layer1, layer2 );
if( layer2 == B_Cu && layer1 == dsnSettings.GetCopperLayerCount() - 2 )
if( layer2 == B_Cu && layer1 == bds.GetCopperLayerCount() - 2 )
err = false;
else if( layer1 == F_Cu && layer2 == In1_Cu )
err = false;
@ -290,14 +328,27 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
}
else // This is a track segment
{
if( refSegWidth < dsnSettings.m_TrackMinWidth )
int minWidth = bds.m_TrackMinWidth;
wxString minWidthSource = _( "board" );
for( DRC_SELECTOR* selector : matched )
{
if( selector->m_Rule->m_TrackWidth > minWidth )
{
minWidth = selector->m_Rule->m_AnnulusWidth;
minWidthSource = wxString::Format( _( "'%s' rule" ), selector->m_Rule->m_Name );
}
}
if( refSegWidth < minWidth )
{
wxPoint refsegMiddle = ( aRefSeg->GetStart() + aRefSeg->GetEnd() ) / 2;
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_TRACK_WIDTH );
msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
MessageTextFromValue( userUnits(), dsnSettings.m_TrackMinWidth, true ),
msg.Printf( drcItem->GetErrorText() + _( " (%s minimum %s; actual %s)" ),
minWidthSource,
MessageTextFromValue( userUnits(), bds.m_TrackMinWidth, true ),
MessageTextFromValue( userUnits(), refSegWidth, true ) );
drcItem->SetErrorMessage( msg );
@ -538,15 +589,17 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
/* Phase 4: test DRC with to board edge */
/***********************************************/
{
SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
static DRAWSEGMENT dummyEdge;
dummyEdge.SetLayer( Edge_Cuts );
SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
wxString clearanceSource;
int minClearance = aRefSeg->GetClearance( nullptr, &clearanceSource );
int minClearance = aRefSeg->GetClearance( &dummyEdge, &clearanceSource );
if( dsnSettings.m_CopperEdgeClearance > minClearance )
if( bds.m_CopperEdgeClearance > minClearance )
{
minClearance = dsnSettings.m_CopperEdgeClearance;
clearanceSource = _( "board edge clearance" );
minClearance = bds.m_CopperEdgeClearance;
clearanceSource = _( "board edge" );
}
int halfWidth = refSegWidth / 2;
@ -585,7 +638,7 @@ void DRC::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterato
int actual = std::max( 0.0, sqrt( center2center_squared ) - halfWidth );
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_EDGE );
msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
clearanceSource,
MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) );

Some files were not shown because too many files have changed in this diff Show More