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
|
@ -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
|
||||
|
|
|
@ -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 ) );
|
||||
|
|
|
@ -94,7 +94,6 @@ wxString DRC_ITEM::GetErrorText( int aCode, bool aTranslate ) const
|
|||
case DRCE_TRACK_NEAR_EDGE: msg = _HKI( "Track too close to board edge" ); break;
|
||||
case DRCE_INVALID_OUTLINE: msg = _HKI( "Board has malformed outline" ); break;
|
||||
|
||||
// use < since this is text ultimately embedded in HTML
|
||||
case DRCE_NETCLASS_TRACKWIDTH: msg = _HKI( "NetClass Track Width too small" ); break;
|
||||
case DRCE_NETCLASS_CLEARANCE: msg = _HKI( "NetClass Clearance too small" ); break;
|
||||
case DRCE_NETCLASS_VIAANNULUS: msg = _HKI( "NetClass via annulus too small" ); break;
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
|
||||
#include <fctsys.h>
|
||||
#include <drc/drc_rule.h>
|
||||
#include <board_design_settings.h>
|
||||
#include <class_board.h>
|
||||
#include <class_board_item.h>
|
||||
|
||||
/*
|
||||
* Match tokens:
|
||||
* match_netclass
|
||||
* match_type
|
||||
* match_layer
|
||||
* match_all
|
||||
* match_area
|
||||
*
|
||||
* (selector (match_area "$board") (rule "OSHParkClass3") (priority 100))
|
||||
*
|
||||
* (selector (match_netclass "HV") (rule "HV_internal"))
|
||||
* (selector (match_netclass "HV") (match_layer "F_Cu") (rule "HV_external"))
|
||||
* (selector (match_netclass "HV") (match_layer "B_Cu") (rule "HV_external"))
|
||||
*
|
||||
* (selector (match_netclass "HV") (match_netclass "HV") (rule "HV2HV"))
|
||||
* (selector (match_netclass "HV") (match_netclass "HV") (match_layer "F_Cu") (rule "HV2HV_external"))
|
||||
* (selector (match_netclass "HV") (match_netclass "HV") (match_layer "B_Cu") (rule "HV2HV_external"))
|
||||
*
|
||||
* TODO: pads for connector pins or wire pads have even larger clearances. How to encode?
|
||||
* User attributes on parent footprint?
|
||||
*
|
||||
* (selector (match_netclass "HV") (match_type "pad") (match_netclass "HV") (match_type "pad") (rule "pad2PadHV"))
|
||||
*
|
||||
* (selector (match_netclass "signal") (match_area "BGA") (rule "neckdown"))
|
||||
*
|
||||
* Type tokens:
|
||||
* track
|
||||
* via
|
||||
* micro_via
|
||||
* blind_via
|
||||
* pad
|
||||
* zone
|
||||
* text
|
||||
* graphic
|
||||
* board_edge
|
||||
* hole
|
||||
* npth
|
||||
* pth
|
||||
*
|
||||
* Rule tokens:
|
||||
* allow
|
||||
* clearance
|
||||
* annulus_width
|
||||
* track_width
|
||||
* hole
|
||||
*
|
||||
* Rule modifiers:
|
||||
* relaxed
|
||||
*
|
||||
* (rule "HV" (clearance 200) (priority 200))
|
||||
* (rule "HV_external" (clearance 400) (priority 200))
|
||||
* (rule "HV2HV" (clearance 200) (priority 200))
|
||||
* (rule "HV2HV_external" (clearance 500) (priority 200))
|
||||
* (rule "pad2padHV" (clearance 500) (priority 200))
|
||||
*
|
||||
* (rule "signal" (clearance 20)) // implied priority of 1
|
||||
* (rule "neckdown" (clearance relaxed 15) (priority 2))
|
||||
*
|
||||
* (rule "allowMicrovias" (allow microvia))
|
||||
*/
|
||||
|
||||
|
||||
void MatchSelectors( const std::vector<DRC_SELECTOR*>& aSelectors,
|
||||
const BOARD_ITEM* aItem, const NETCLASS* aNetclass,
|
||||
const BOARD_ITEM* bItem, const NETCLASS* bNetclass,
|
||||
std::vector<DRC_SELECTOR*>* aSelected )
|
||||
{
|
||||
for( DRC_SELECTOR* candidate : aSelectors )
|
||||
{
|
||||
if( candidate->m_MatchNetclasses.size() == 2 )
|
||||
{
|
||||
if( !bItem )
|
||||
continue;
|
||||
|
||||
NETCLASS* firstNetclass = candidate->m_MatchNetclasses[0];
|
||||
NETCLASS* secondNetclass = candidate->m_MatchNetclasses[1];
|
||||
|
||||
if( !( aNetclass == firstNetclass && bNetclass == secondNetclass )
|
||||
&& !( aNetclass == secondNetclass && bNetclass == firstNetclass ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if( candidate->m_MatchNetclasses.size() == 1 )
|
||||
{
|
||||
NETCLASS* matchNetclass = candidate->m_MatchNetclasses[0];
|
||||
|
||||
if( matchNetclass != aNetclass && !( bItem && matchNetclass == bNetclass ) )
|
||||
continue;
|
||||
}
|
||||
|
||||
if( candidate->m_MatchTypes.size() == 2 )
|
||||
{
|
||||
if( !bItem )
|
||||
continue;
|
||||
|
||||
KICAD_T firstType[2] = { candidate->m_MatchTypes[0], EOT };
|
||||
KICAD_T secondType[2] = { candidate->m_MatchTypes[1], EOT };
|
||||
|
||||
if( !( aItem->IsType( firstType ) && bItem->IsType( secondType ) )
|
||||
&& !( aItem->IsType( secondType ) && bItem->IsType( firstType ) ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if( candidate->m_MatchTypes.size() == 1 )
|
||||
{
|
||||
KICAD_T matchType[2] = { candidate->m_MatchTypes[0], EOT };
|
||||
|
||||
if( !aItem->IsType( matchType ) && !( bItem && bItem->IsType( matchType ) ) )
|
||||
continue;
|
||||
}
|
||||
|
||||
if( candidate->m_MatchLayers.size() )
|
||||
{
|
||||
PCB_LAYER_ID matchLayer = candidate->m_MatchLayers[0];
|
||||
|
||||
if( !aItem->GetLayerSet().test( matchLayer )
|
||||
&& !( bItem && bItem->GetLayerSet().test( matchLayer ) ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if( candidate->m_MatchAreas.size() )
|
||||
{
|
||||
if( candidate->m_MatchAreas[0] == "$board" )
|
||||
{
|
||||
// matches everything
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: area/room matches...
|
||||
}
|
||||
}
|
||||
|
||||
// All tests done; if we're still here then it matches
|
||||
aSelected->push_back( candidate );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* 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_RULE_H
|
||||
#define DRC_RULE_H
|
||||
|
||||
#include <core/typeinfo.h>
|
||||
#include <netclass.h>
|
||||
#include <layers_id_colors_and_visibility.h>
|
||||
|
||||
|
||||
class BOARD_ITEM;
|
||||
|
||||
|
||||
class DRC_RULE
|
||||
{
|
||||
public:
|
||||
wxString m_Name;
|
||||
|
||||
// A 0 value means the property is not modified by this rule.
|
||||
// A positive value is a minimum. A negative value is a relaxed constraint: the minimum
|
||||
// is reduced to the absolute value of the constraint.
|
||||
int m_Clearance;
|
||||
int m_AnnulusWidth;
|
||||
int m_TrackWidth;
|
||||
int m_Hole;
|
||||
};
|
||||
|
||||
|
||||
class DRC_SELECTOR
|
||||
{
|
||||
public:
|
||||
std::vector<NETCLASS*> m_MatchNetclasses;
|
||||
std::vector<KICAD_T> m_MatchTypes;
|
||||
std::vector<PCB_LAYER_ID> m_MatchLayers;
|
||||
std::vector<wxString> m_MatchAreas;
|
||||
|
||||
int m_Priority; // 0 indicates automatic priority generation
|
||||
DRC_RULE* m_Rule;
|
||||
|
||||
public:
|
||||
};
|
||||
|
||||
|
||||
void MatchSelectors( const std::vector<DRC_SELECTOR*>& aSelectors,
|
||||
const BOARD_ITEM* aItem, const NETCLASS* aNetclass,
|
||||
const BOARD_ITEM* bItem, const NETCLASS* bNetclass,
|
||||
std::vector<DRC_SELECTOR*>* aSelected );
|
||||
|
||||
|
||||
|
||||
#endif // DRC_RULE_H
|
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
|
||||
#include <fctsys.h>
|
||||
#include <drc/drc_rule_parser.h>
|
||||
#include <drc_rules_lexer.h>
|
||||
#include <class_board.h>
|
||||
#include <class_board_item.h>
|
||||
|
||||
using namespace DRCRULE_T;
|
||||
|
||||
|
||||
DRC_RULES_PARSER::DRC_RULES_PARSER( BOARD* aBoard, FILE* aFile, const wxString& aFilename ) :
|
||||
DRC_RULES_LEXER( aFile, aFilename ),
|
||||
m_board( aBoard ),
|
||||
m_requiredVersion( 0 ),
|
||||
m_tooRecent( false )
|
||||
{
|
||||
for( LAYER_NUM layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
|
||||
{
|
||||
std::string untranslated = TO_UTF8( wxString( LSET::Name( PCB_LAYER_ID( layer ) ) ) );
|
||||
m_layerMap[ untranslated ] = PCB_LAYER_ID( layer );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DRC_RULES_PARSER::Parse( std::vector<DRC_SELECTOR*>& aSelectors,
|
||||
std::vector<DRC_RULE*>& aRules )
|
||||
{
|
||||
std::vector< std::pair<DRC_SELECTOR*, wxString> > selectorRules;
|
||||
|
||||
T token;
|
||||
|
||||
NeedLEFT();
|
||||
|
||||
if( NextTok() != T_version )
|
||||
Expecting( "version" );
|
||||
|
||||
NeedNUMBER( "version" );
|
||||
m_requiredVersion = (int)strtol( CurText(), NULL, 10 );
|
||||
m_tooRecent = ( m_requiredVersion > DRC_RULE_FILE_VERSION );
|
||||
NeedRIGHT();
|
||||
|
||||
for( token = NextTok(); token != T_EOF; token = NextTok() )
|
||||
{
|
||||
if( token != T_LEFT )
|
||||
Expecting( T_LEFT );
|
||||
|
||||
token = NextTok();
|
||||
|
||||
switch( token )
|
||||
{
|
||||
case T_selector:
|
||||
{
|
||||
wxString ruleName;
|
||||
|
||||
aSelectors.push_back( parseDRC_SELECTOR( &ruleName ) );
|
||||
selectorRules.emplace_back( aSelectors.back(), ruleName );
|
||||
}
|
||||
break;
|
||||
|
||||
case T_rule:
|
||||
aRules.push_back( parseDRC_RULE() );
|
||||
break;
|
||||
|
||||
default:
|
||||
Expecting( "selector or rule" );
|
||||
}
|
||||
}
|
||||
|
||||
// Hook up the selectors to their rules
|
||||
std::map<wxString, DRC_RULE*> ruleMap;
|
||||
|
||||
for( DRC_RULE* rule : aRules )
|
||||
ruleMap[ rule->m_Name ] = rule;
|
||||
|
||||
for( const std::pair<DRC_SELECTOR*, wxString>& entry : selectorRules )
|
||||
entry.first->m_Rule = ruleMap[ entry.second ];
|
||||
}
|
||||
|
||||
|
||||
DRC_SELECTOR* DRC_RULES_PARSER::parseDRC_SELECTOR( wxString* aRuleName )
|
||||
{
|
||||
NETCLASSES& netclasses = m_board->GetDesignSettings().m_NetClasses;
|
||||
DRC_SELECTOR* selector = new DRC_SELECTOR();
|
||||
T token;
|
||||
|
||||
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
|
||||
{
|
||||
if( token != T_LEFT )
|
||||
Expecting( T_LEFT );
|
||||
|
||||
token = NextTok();
|
||||
|
||||
switch( token )
|
||||
{
|
||||
case T_match_netclass:
|
||||
NeedSYMBOL();
|
||||
selector->m_MatchNetclasses.push_back( netclasses.Find( FromUTF8() ).get() );
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_match_type:
|
||||
switch( NextTok() )
|
||||
{
|
||||
case T_track: selector->m_MatchTypes.push_back( PCB_TRACE_T ); break;
|
||||
case T_via: selector->m_MatchTypes.push_back( PCB_LOCATE_STDVIA_T ); break;
|
||||
case T_micro_via: selector->m_MatchTypes.push_back( PCB_LOCATE_UVIA_T ); break;
|
||||
case T_blind_via: selector->m_MatchTypes.push_back( PCB_LOCATE_BBVIA_T ); break;
|
||||
case T_pad: selector->m_MatchTypes.push_back( PCB_PAD_T ); break;
|
||||
case T_zone: selector->m_MatchTypes.push_back( PCB_ZONE_AREA_T ); break;
|
||||
case T_text: selector->m_MatchTypes.push_back( PCB_LOCATE_TEXT_T ); break;
|
||||
case T_graphic: selector->m_MatchTypes.push_back( PCB_LOCATE_GRAPHIC_T ); break;
|
||||
case T_hole: selector->m_MatchTypes.push_back( PCB_LOCATE_HOLE_T ); break;
|
||||
case T_npth: selector->m_MatchTypes.push_back( PCB_LOCATE_NPTH_T ); break;
|
||||
case T_pth: selector->m_MatchTypes.push_back( PCB_LOCATE_PTH_T ); break;
|
||||
case T_board_edge: selector->m_MatchTypes.push_back( PCB_LOCATE_BOARD_EDGE_T ); break;
|
||||
default: Expecting( "track, via, micro_via, blind_via, pad, zone, text, "
|
||||
"graphic, hole, npth, pth, or board_edge" );
|
||||
}
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_match_layer:
|
||||
NeedSYMBOL();
|
||||
selector->m_MatchLayers.push_back( m_layerMap[ curText ] );
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_match_area:
|
||||
// TODO
|
||||
break;
|
||||
|
||||
case T_rule:
|
||||
NeedSYMBOL();
|
||||
*aRuleName = FromUTF8();
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_priority:
|
||||
NeedNUMBER( "priority" );
|
||||
selector->m_Priority = (int)strtol( CurText(), NULL, 10 );
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
default:
|
||||
Expecting( "match_netclass, match_type, match_layer, match_area, rule, or priority" );
|
||||
}
|
||||
}
|
||||
|
||||
return selector;
|
||||
}
|
||||
|
||||
|
||||
DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE()
|
||||
{
|
||||
DRC_RULE* rule = new DRC_RULE();
|
||||
T token;
|
||||
|
||||
NeedSYMBOL();
|
||||
rule->m_Name = FromUTF8();
|
||||
|
||||
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
|
||||
{
|
||||
if( token != T_LEFT )
|
||||
Expecting( T_LEFT );
|
||||
|
||||
int sign = 1;
|
||||
token = NextTok();
|
||||
|
||||
switch( token )
|
||||
{
|
||||
case T_allow:
|
||||
// TODO
|
||||
break;
|
||||
|
||||
case T_clearance:
|
||||
if( NextTok() == T_relaxed )
|
||||
{
|
||||
sign = -1;
|
||||
NextTok();
|
||||
}
|
||||
|
||||
rule->m_Clearance = parseValue( T_clearance ) * sign;
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_track_width:
|
||||
if( NextTok() == T_relaxed )
|
||||
{
|
||||
sign = -1;
|
||||
NextTok();
|
||||
}
|
||||
|
||||
rule->m_TrackWidth = parseValue( T_track_width ) * sign;
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_annulus_width:
|
||||
if( NextTok() == T_relaxed )
|
||||
{
|
||||
sign = -1;
|
||||
NextTok();
|
||||
}
|
||||
|
||||
rule->m_AnnulusWidth = parseValue( T_annulus_width ) * sign;
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_hole:
|
||||
if( NextTok() == T_relaxed )
|
||||
{
|
||||
sign = -1;
|
||||
NextTok();
|
||||
}
|
||||
|
||||
rule->m_Hole = parseValue( T_hole ) * sign;
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
default:
|
||||
Expecting( "allow, clearance, track_width, annulus_width, or hole" );
|
||||
}
|
||||
}
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
|
||||
int DRC_RULES_PARSER::parseValue( DRCRULE_T::T aToken )
|
||||
{
|
||||
char* tmp;
|
||||
|
||||
errno = 0;
|
||||
|
||||
double fval = strtod( CurText(), &tmp );
|
||||
|
||||
if( errno )
|
||||
{
|
||||
wxString error;
|
||||
error.Printf( _( "Invalid floating point number in\nfile: \"%s\"\nline: %d\noffset: %d" ),
|
||||
GetChars( CurSource() ), CurLineNumber(), CurOffset() );
|
||||
|
||||
THROW_IO_ERROR( error );
|
||||
}
|
||||
|
||||
if( CurText() == tmp )
|
||||
{
|
||||
wxString error;
|
||||
error.Printf( _( "Missing floating point number in\nfile: \"%s\"\nline: %d\noffset: %d" ),
|
||||
GetChars( CurSource() ), CurLineNumber(), CurOffset() );
|
||||
|
||||
THROW_IO_ERROR( error );
|
||||
}
|
||||
|
||||
return KiROUND( fval * IU_PER_MM );
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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_RULE_PARSER_H
|
||||
#define DRC_RULE_PARSER_H
|
||||
|
||||
#include <core/typeinfo.h>
|
||||
#include <netclass.h>
|
||||
#include <layers_id_colors_and_visibility.h>
|
||||
#include <drc/drc_rule.h>
|
||||
#include <drc_rules_lexer.h>
|
||||
|
||||
|
||||
class BOARD_ITEM;
|
||||
|
||||
|
||||
#define DRC_RULE_FILE_VERSION 20200515
|
||||
|
||||
|
||||
class DRC_RULES_PARSER : public DRC_RULES_LEXER
|
||||
{
|
||||
public:
|
||||
DRC_RULES_PARSER( BOARD* aBoard, FILE* aFile, const wxString& aFilename );
|
||||
|
||||
void Parse( std::vector<DRC_SELECTOR*>& aSelectors, std::vector<DRC_RULE*>& aRules );
|
||||
|
||||
private:
|
||||
DRC_SELECTOR* parseDRC_SELECTOR( wxString* aRuleName );
|
||||
|
||||
DRC_RULE* parseDRC_RULE();
|
||||
|
||||
int parseValue( DRCRULE_T::T aToken );
|
||||
|
||||
private:
|
||||
BOARD* m_board;
|
||||
int m_requiredVersion;
|
||||
bool m_tooRecent;
|
||||
|
||||
std::unordered_map<std::string, PCB_LAYER_ID> m_layerMap;
|
||||
};
|
||||
|
||||
#endif // DRC_RULE_PARSER_H
|
|
@ -516,20 +516,26 @@ void ZONE_FILLER::knockoutThermalReliefs( const ZONE_CONTAINER* aZone, SHAPE_POL
|
|||
*/
|
||||
void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, SHAPE_POLY_SET& aHoles )
|
||||
{
|
||||
static DRAWSEGMENT dummyEdge;
|
||||
dummyEdge.SetLayer( Edge_Cuts );
|
||||
|
||||
// a small extra clearance to be sure actual track clearance is not smaller
|
||||
// than requested clearance due to many approximations in calculations,
|
||||
// like arc to segment approx, rounding issues...
|
||||
// 2 microns are a good value
|
||||
int extra_margin = Millimeter2iu( 0.002 );
|
||||
|
||||
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
||||
int zone_clearance = aZone->GetClearance();
|
||||
int edgeClearance = m_board->GetDesignSettings().m_CopperEdgeClearance;
|
||||
int zone_to_edgecut_clearance = std::max( aZone->GetZoneClearance(), edgeClearance );
|
||||
int edge_clearance = aZone->GetClearance( &dummyEdge );
|
||||
|
||||
if( bds.m_CopperEdgeClearance > edge_clearance )
|
||||
edge_clearance = bds.m_CopperEdgeClearance;
|
||||
|
||||
// items outside the zone bounding box are skipped
|
||||
// the bounding box is the zone bounding box + the biggest clearance found in Netclass list
|
||||
EDA_RECT zone_boundingbox = aZone->GetBoundingBox();
|
||||
int biggest_clearance = m_board->GetDesignSettings().GetBiggestClearanceValue();
|
||||
int biggest_clearance = bds.GetBiggestClearanceValue();
|
||||
biggest_clearance = std::max( biggest_clearance, zone_clearance ) + extra_margin;
|
||||
zone_boundingbox.Inflate( biggest_clearance );
|
||||
|
||||
|
@ -615,7 +621,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, SHAPE_
|
|||
|
||||
if( aItem->IsOnLayer( Edge_Cuts ) )
|
||||
{
|
||||
gap = zone_to_edgecut_clearance;
|
||||
gap = edge_clearance;
|
||||
|
||||
// edge cuts by definition don't have a width
|
||||
ignoreLineWidth = true;
|
||||
|
|
Loading…
Reference in New Issue