mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-04-20 20:11:41 +00:00
DRC rules parser and engine.
Fixes https://gitlab.com/kicad/code/kicad/issues/2182 Fixes https://gitlab.com/kicad/code/kicad/issues/2116 Fixes https://gitlab.com/kicad/code/kicad/issues/1958 Fixes https://gitlab.com/kicad/code/kicad/issues/1965
This commit is contained in:
parent
1d914133c9
commit
d3f017d825
.gitignore
common
include
pcbnew
CMakeLists.txtboard_connected_item.cppboard_connected_item.hboard_design_settings.cppclass_dimension.hclass_drawsegment.hclass_edge_mod.hclass_pad.cppclass_pad.hclass_pcb_text.hclass_text_mod.hclass_track.cppclass_track.hclass_zone.cppclass_zone.h
dialogs
drc
drc.cppdrc.hdrc_clearance_test_functions.cppdrc_item.cppdrc_rule.cppdrc_rule.hdrc_rule_parser.cppdrc_rule_parser.h
zone_filler.cpp
2
.gitignore
vendored
2
.gitignore
vendored
@ -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
|
||||
|
@ -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
25
common/drc_rules.keywords
Normal 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
|
@ -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_
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 );
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 );
|
||||
|
@ -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(); }
|
||||
|
||||
/**
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user