ADDED Clearance Inspector.
This commit is contained in:
parent
e31705d4b3
commit
fc1665ff28
|
@ -81,7 +81,7 @@ NETCLASS* BOARD_CONNECTED_ITEM::GetEffectiveNetclass() const
|
||||||
* LEVEL 3: Accumulated local settings, netclass settings, & board design settings
|
* LEVEL 3: Accumulated local settings, netclass settings, & board design settings
|
||||||
*/
|
*/
|
||||||
int BOARD_CONNECTED_ITEM::GetClearance( PCB_LAYER_ID aLayer, BOARD_ITEM* aItem,
|
int BOARD_CONNECTED_ITEM::GetClearance( PCB_LAYER_ID aLayer, BOARD_ITEM* aItem,
|
||||||
wxString* aSource ) const
|
wxString* aSource, REPORTER* aReporter ) const
|
||||||
{
|
{
|
||||||
BOARD* board = GetBoard();
|
BOARD* board = GetBoard();
|
||||||
int clearance = 0;
|
int clearance = 0;
|
||||||
|
@ -111,7 +111,7 @@ int BOARD_CONNECTED_ITEM::GetClearance( PCB_LAYER_ID aLayer, BOARD_ITEM* aItem,
|
||||||
|
|
||||||
// LEVEL 2: Rules
|
// LEVEL 2: Rules
|
||||||
//
|
//
|
||||||
if( GetRuleClearance( aItem, aLayer, &clearance, aSource ) )
|
if( GetRuleClearance( aItem, aLayer, &clearance, aSource, aReporter ) )
|
||||||
return clearance;
|
return clearance;
|
||||||
|
|
||||||
// LEVEL 3: Accumulated local settings, netclass settings, & board design settings
|
// LEVEL 3: Accumulated local settings, netclass settings, & board design settings
|
||||||
|
@ -153,10 +153,11 @@ int BOARD_CONNECTED_ITEM::GetClearance( PCB_LAYER_ID aLayer, BOARD_ITEM* aItem,
|
||||||
|
|
||||||
|
|
||||||
bool BOARD_CONNECTED_ITEM::GetRuleClearance( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer,
|
bool BOARD_CONNECTED_ITEM::GetRuleClearance( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer,
|
||||||
int* aClearance, wxString* aSource ) const
|
int* aClearance, wxString* aSource,
|
||||||
|
REPORTER* aReporter ) const
|
||||||
{
|
{
|
||||||
const DRC_CONSTRAINT* constraint = GetConstraint( this, aItem, DRC_RULE_ID_CLEARANCE, aLayer,
|
const DRC_CONSTRAINT* constraint = GetConstraint( this, aItem, DRC_RULE_ID_CLEARANCE, aLayer,
|
||||||
aSource );
|
aSource, aReporter );
|
||||||
|
|
||||||
if( constraint )
|
if( constraint )
|
||||||
{
|
{
|
||||||
|
@ -164,6 +165,13 @@ bool BOARD_CONNECTED_ITEM::GetRuleClearance( BOARD_ITEM* aItem, PCB_LAYER_ID aLa
|
||||||
*aSource = wxString::Format( _( "'%s' rule" ), *aSource );
|
*aSource = wxString::Format( _( "'%s' rule" ), *aSource );
|
||||||
|
|
||||||
*aClearance = constraint->m_Value.Min();
|
*aClearance = constraint->m_Value.Min();
|
||||||
|
|
||||||
|
if( aReporter )
|
||||||
|
{
|
||||||
|
wxString clearance = StringFromValue( aReporter->GetUnits(), *aClearance, true );
|
||||||
|
aReporter->Report( wxString::Format( _( "Clearance: %s." ), clearance ) );
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
#include <class_board_item.h>
|
#include <class_board_item.h>
|
||||||
#include <netinfo.h>
|
#include <netinfo.h>
|
||||||
|
#include <reporter.h>
|
||||||
#include <kicad_string.h>
|
#include <kicad_string.h>
|
||||||
|
|
||||||
class NETCLASS;
|
class NETCLASS;
|
||||||
|
@ -167,7 +168,7 @@ public:
|
||||||
* @return int - the clearance in internal units.
|
* @return int - the clearance in internal units.
|
||||||
*/
|
*/
|
||||||
virtual int GetClearance( PCB_LAYER_ID aLayer, BOARD_ITEM* aItem = nullptr,
|
virtual int GetClearance( PCB_LAYER_ID aLayer, BOARD_ITEM* aItem = nullptr,
|
||||||
wxString* aSource = nullptr ) const;
|
wxString* aSource = nullptr, REPORTER* aReporter = nullptr ) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function GetRuleClearance
|
* Function GetRuleClearance
|
||||||
|
@ -178,7 +179,7 @@ public:
|
||||||
* @return true if a rule was fired
|
* @return true if a rule was fired
|
||||||
*/
|
*/
|
||||||
virtual bool GetRuleClearance( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, int* aClearance,
|
virtual bool GetRuleClearance( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, int* aClearance,
|
||||||
wxString* aSource ) const;
|
wxString* aSource, REPORTER* aReporter = nullptr ) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function GetLocalClearanceOverrides
|
* Function GetLocalClearanceOverrides
|
||||||
|
|
|
@ -31,7 +31,8 @@
|
||||||
|
|
||||||
|
|
||||||
const DRC_CONSTRAINT* GetConstraint( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem,
|
const DRC_CONSTRAINT* GetConstraint( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem,
|
||||||
int aConstraint, PCB_LAYER_ID aLayer, wxString* aRuleName )
|
int aConstraint, PCB_LAYER_ID aLayer, wxString* aRuleName,
|
||||||
|
REPORTER* aReporter )
|
||||||
{
|
{
|
||||||
BOARD* board = aItem->GetBoard();
|
BOARD* board = aItem->GetBoard();
|
||||||
|
|
||||||
|
@ -40,33 +41,76 @@ const DRC_CONSTRAINT* GetConstraint( const BOARD_ITEM* aItem, const BOARD_ITEM*
|
||||||
|
|
||||||
for( DRC_RULE* rule : board->GetDesignSettings().m_DRCRules )
|
for( DRC_RULE* rule : board->GetDesignSettings().m_DRCRules )
|
||||||
{
|
{
|
||||||
if( !rule->m_LayerCondition.test( aLayer ) )
|
if( aReporter )
|
||||||
continue;
|
|
||||||
|
|
||||||
for( const DRC_CONSTRAINT& constraint : rule->m_Constraints )
|
|
||||||
{
|
{
|
||||||
if( constraint.m_Type != aConstraint )
|
aReporter->Report( wxString::Format( _( "Checking rule \"%s\"." ),
|
||||||
continue;
|
rule->m_Name ) );
|
||||||
|
}
|
||||||
|
|
||||||
if( !rule->m_LayerCondition.test( aLayer ) )
|
if( !rule->m_LayerCondition.test( aLayer ) )
|
||||||
|
{
|
||||||
|
if( aReporter )
|
||||||
|
{
|
||||||
|
aReporter->Report( wxString::Format( _( "Rule layer \"%s\" not matched." ),
|
||||||
|
rule->m_LayerSource ) );
|
||||||
|
aReporter->Report( "Rule not applied." );
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DRC_CONSTRAINT* constraint = nullptr;
|
||||||
|
|
||||||
|
for( const DRC_CONSTRAINT& candidate : rule->m_Constraints )
|
||||||
|
{
|
||||||
|
if( candidate.m_Type == aConstraint )
|
||||||
|
{
|
||||||
|
constraint = &candidate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( aReporter && !constraint )
|
||||||
|
{
|
||||||
|
aReporter->Report( _( "Rule contains no applicable constraints." ) );
|
||||||
|
aReporter->Report( _( "Rule not applied." ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( aReporter )
|
||||||
|
{
|
||||||
|
aReporter->Report( wxString::Format( _( "Checking rule condition \"%s\"." ),
|
||||||
|
rule->m_Condition.m_Expression ) );
|
||||||
|
}
|
||||||
|
|
||||||
if( rule->m_Condition.EvaluateFor( aItem, bItem, aLayer ) )
|
if( rule->m_Condition.EvaluateFor( aItem, bItem, aLayer ) )
|
||||||
{
|
{
|
||||||
|
if( aReporter )
|
||||||
|
aReporter->Report( "Rule applied." );
|
||||||
|
|
||||||
if( aRuleName )
|
if( aRuleName )
|
||||||
*aRuleName = rule->m_Name;
|
*aRuleName = rule->m_Name;
|
||||||
|
|
||||||
return &constraint;
|
return constraint;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( bItem && rule->m_Condition.EvaluateFor( bItem, aItem, aLayer ) )
|
if( bItem && rule->m_Condition.EvaluateFor( bItem, aItem, aLayer ) )
|
||||||
{
|
{
|
||||||
|
if( aReporter )
|
||||||
|
aReporter->Report( "Rule applied." );
|
||||||
|
|
||||||
if( aRuleName )
|
if( aRuleName )
|
||||||
*aRuleName = rule->m_Name;
|
*aRuleName = rule->m_Name;
|
||||||
|
|
||||||
return &constraint;
|
return constraint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( aReporter )
|
||||||
|
aReporter->Report( "Condition not satisfied; rule not applied." );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( aReporter )
|
||||||
|
aReporter->Report( "" );
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -97,21 +141,37 @@ DRC_RULE_CONDITION::~DRC_RULE_CONDITION()
|
||||||
|
|
||||||
|
|
||||||
bool DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB,
|
bool DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB,
|
||||||
PCB_LAYER_ID aLayer )
|
PCB_LAYER_ID aLayer, REPORTER* aReporter )
|
||||||
{
|
{
|
||||||
// An unconditional rule is always true
|
|
||||||
if( m_Expression.IsEmpty() )
|
if( m_Expression.IsEmpty() )
|
||||||
return true;
|
{
|
||||||
|
if( aReporter )
|
||||||
|
aReporter->Report( _( "Unconditional constraint." ) );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( aReporter )
|
||||||
|
aReporter->Report( _( "Evaluating expression \"" + m_Expression + "\"." ) );
|
||||||
|
|
||||||
// A rule which failed to compile is always false
|
|
||||||
if( !m_ucode )
|
if( !m_ucode )
|
||||||
|
{
|
||||||
|
if( aReporter )
|
||||||
|
aReporter->Report( _( "ERROR in expression." ) );
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
BOARD_ITEM* a = const_cast<BOARD_ITEM*>( aItemA );
|
BOARD_ITEM* a = const_cast<BOARD_ITEM*>( aItemA );
|
||||||
BOARD_ITEM* b = aItemB ? const_cast<BOARD_ITEM*>( aItemB ) : DELETED_BOARD_ITEM::GetInstance();
|
BOARD_ITEM* b = aItemB ? const_cast<BOARD_ITEM*>( aItemB ) : DELETED_BOARD_ITEM::GetInstance();
|
||||||
|
|
||||||
PCB_EXPR_CONTEXT ctx( aLayer );
|
PCB_EXPR_CONTEXT ctx( aLayer );
|
||||||
ctx.SetItems( a, b );
|
ctx.SetItems( a, b );
|
||||||
|
ctx.SetErrorCallback( [&]( const wxString& aMessage, int aOffset )
|
||||||
|
{
|
||||||
|
if( aReporter )
|
||||||
|
aReporter->Report( _( "ERROR: " ) + aMessage );
|
||||||
|
} );
|
||||||
|
|
||||||
return m_ucode->Run( &ctx )->AsDouble() != 0.0;
|
return m_ucode->Run( &ctx )->AsDouble() != 0.0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,8 +88,7 @@ class DRC_CONSTRAINT
|
||||||
public:
|
public:
|
||||||
DRC_CONSTRAINT() :
|
DRC_CONSTRAINT() :
|
||||||
m_Type( DRC_RULE_ID_UNKNOWN ),
|
m_Type( DRC_RULE_ID_UNKNOWN ),
|
||||||
m_DisallowFlags( 0 ),
|
m_DisallowFlags( 0 )
|
||||||
m_LayerCondition( LSET::AllLayersMask() )
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
const MINOPTMAX<int>& GetValue() const { return m_Value; }
|
const MINOPTMAX<int>& GetValue() const { return m_Value; }
|
||||||
|
@ -99,7 +98,6 @@ public:
|
||||||
DRC_CONSTRAINT_TYPE_T m_Type;
|
DRC_CONSTRAINT_TYPE_T m_Type;
|
||||||
MINOPTMAX<int> m_Value;
|
MINOPTMAX<int> m_Value;
|
||||||
int m_DisallowFlags;
|
int m_DisallowFlags;
|
||||||
LSET m_LayerCondition;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -109,7 +107,8 @@ public:
|
||||||
DRC_RULE_CONDITION();
|
DRC_RULE_CONDITION();
|
||||||
~DRC_RULE_CONDITION();
|
~DRC_RULE_CONDITION();
|
||||||
|
|
||||||
bool EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB, PCB_LAYER_ID aLayer );
|
bool EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB, PCB_LAYER_ID aLayer,
|
||||||
|
REPORTER* aReporter = nullptr );
|
||||||
bool Compile( REPORTER* aReporter, int aSourceLine, int aSourceOffset );
|
bool Compile( REPORTER* aReporter, int aSourceLine, int aSourceOffset );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -128,6 +127,7 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
wxString m_Name;
|
wxString m_Name;
|
||||||
|
wxString m_LayerSource;
|
||||||
LSET m_LayerCondition;
|
LSET m_LayerCondition;
|
||||||
wxString m_TestProviderName;
|
wxString m_TestProviderName;
|
||||||
DRC_RULE_CONDITION m_Condition;
|
DRC_RULE_CONDITION m_Condition;
|
||||||
|
@ -136,7 +136,9 @@ public:
|
||||||
|
|
||||||
|
|
||||||
const DRC_CONSTRAINT* GetConstraint( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem,
|
const DRC_CONSTRAINT* GetConstraint( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem,
|
||||||
int aConstraint, PCB_LAYER_ID aLayer, wxString* aRuleName );
|
int aConstraint, PCB_LAYER_ID aLayer,
|
||||||
|
wxString* aRuleName = nullptr,
|
||||||
|
REPORTER* aReporter = nullptr );
|
||||||
|
|
||||||
|
|
||||||
#endif // DRC_RULE_H
|
#endif // DRC_RULE_H
|
||||||
|
|
|
@ -215,6 +215,7 @@ DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_layer:
|
case T_layer:
|
||||||
|
rule->m_LayerSource = FromUTF8();
|
||||||
rule->m_LayerCondition = parseLayer();
|
rule->m_LayerCondition = parseLayer();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -453,7 +454,7 @@ LSET DRC_RULES_PARSER::parseLayer()
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !retVal.any() )
|
if( !retVal.any() )
|
||||||
reportError( wxString::Format( _( "Unrecognized layer '%s' " ), layerName ) );
|
reportError( wxString::Format( _( "Unrecognized layer '%s'." ), layerName ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( (int) NextTok() != DSN_RIGHT )
|
if( (int) NextTok() != DSN_RIGHT )
|
||||||
|
|
|
@ -372,6 +372,7 @@ void PCB_EDIT_FRAME::ReCreateMenuBar()
|
||||||
|
|
||||||
inspectMenu->AppendSeparator();
|
inspectMenu->AppendSeparator();
|
||||||
inspectMenu->Add( PCB_ACTIONS::runDRC );
|
inspectMenu->Add( PCB_ACTIONS::runDRC );
|
||||||
|
inspectMenu->Add( PCB_ACTIONS::inspectClearance );
|
||||||
|
|
||||||
|
|
||||||
//-- Tools menu ----------------------------------------------------------
|
//-- Tools menu ----------------------------------------------------------
|
||||||
|
|
|
@ -204,23 +204,21 @@ bool EDIT_TOOL::Init()
|
||||||
auto specialToolsSubMenu = std::make_shared<SPECIAL_TOOLS_CONTEXT_MENU>( this );
|
auto specialToolsSubMenu = std::make_shared<SPECIAL_TOOLS_CONTEXT_MENU>( this );
|
||||||
menu.AddSeparator();
|
menu.AddSeparator();
|
||||||
m_selectionTool->GetToolMenu().AddSubMenu( specialToolsSubMenu );
|
m_selectionTool->GetToolMenu().AddSubMenu( specialToolsSubMenu );
|
||||||
menu.AddMenu( specialToolsSubMenu.get(), SELECTION_CONDITIONS::NotEmpty );
|
menu.AddMenu( specialToolsSubMenu.get(), SELECTION_CONDITIONS::NotEmpty, 100 );
|
||||||
|
|
||||||
menu.AddSeparator();
|
menu.AddSeparator( 150 );
|
||||||
menu.AddItem( ACTIONS::cut, SELECTION_CONDITIONS::NotEmpty );
|
menu.AddItem( ACTIONS::cut, SELECTION_CONDITIONS::NotEmpty, 150 );
|
||||||
menu.AddItem( ACTIONS::copy, SELECTION_CONDITIONS::NotEmpty );
|
menu.AddItem( ACTIONS::copy, SELECTION_CONDITIONS::NotEmpty, 150 );
|
||||||
// Selection tool handles the context menu for some other tools, such as the Picker.
|
// Selection tool handles the context menu for some other tools, such as the Picker.
|
||||||
// Don't add things like Paste when another tool is active.
|
// Don't add things like Paste when another tool is active.
|
||||||
menu.AddItem( ACTIONS::paste, noActiveToolCondition );
|
menu.AddItem( ACTIONS::paste, noActiveToolCondition, 150 );
|
||||||
|
menu.AddItem( ACTIONS::selectAll, noItemsCondition, 150 );
|
||||||
menu.AppendSeparator();
|
|
||||||
menu.AddItem( ACTIONS::selectAll, noItemsCondition );
|
|
||||||
|
|
||||||
// Footprint actions
|
// Footprint actions
|
||||||
menu.AddSeparator();
|
menu.AddSeparator( 150 );
|
||||||
menu.AddItem( PCB_ACTIONS::editFpInFpEditor, singleModuleCondition );
|
menu.AddItem( PCB_ACTIONS::editFpInFpEditor, singleModuleCondition, 150 );
|
||||||
menu.AddItem( PCB_ACTIONS::updateFootprint, singleModuleCondition );
|
menu.AddItem( PCB_ACTIONS::updateFootprint, singleModuleCondition, 150 );
|
||||||
menu.AddItem( PCB_ACTIONS::changeFootprint, singleModuleCondition );
|
menu.AddItem( PCB_ACTIONS::changeFootprint, singleModuleCondition, 150 );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1025,6 +1025,12 @@ TOOL_ACTION PCB_ACTIONS::boardStatistics( "pcbnew.InspectionTool.ShowStatisticsD
|
||||||
_( "Show Board Statistics" ), _( "Shows board statistics" ),
|
_( "Show Board Statistics" ), _( "Shows board statistics" ),
|
||||||
pcbnew_xpm );
|
pcbnew_xpm );
|
||||||
|
|
||||||
|
TOOL_ACTION PCB_ACTIONS::inspectClearance( "pcbnew.InspectionTool.InspectClearance",
|
||||||
|
AS_GLOBAL, 0, "",
|
||||||
|
_( "Clearance Resolution..." ),
|
||||||
|
_( "Show clearance resolution for the active layer between two selected objects" ),
|
||||||
|
mw_add_gap_xpm );
|
||||||
|
|
||||||
//Geographic re-annotation tool
|
//Geographic re-annotation tool
|
||||||
TOOL_ACTION PCB_ACTIONS::boardReannotate( "pcbnew.ReannotateTool.ShowReannotateDialog",
|
TOOL_ACTION PCB_ACTIONS::boardReannotate( "pcbnew.ReannotateTool.ShowReannotateDialog",
|
||||||
AS_GLOBAL, 0, "",
|
AS_GLOBAL, 0, "",
|
||||||
|
|
|
@ -417,6 +417,7 @@ public:
|
||||||
static TOOL_ACTION boardStatistics;
|
static TOOL_ACTION boardStatistics;
|
||||||
static TOOL_ACTION boardReannotate;
|
static TOOL_ACTION boardReannotate;
|
||||||
static TOOL_ACTION repairBoard;
|
static TOOL_ACTION repairBoard;
|
||||||
|
static TOOL_ACTION inspectClearance;
|
||||||
|
|
||||||
// Appearance controls
|
// Appearance controls
|
||||||
static TOOL_ACTION clearHighlight;
|
static TOOL_ACTION clearHighlight;
|
||||||
|
|
|
@ -243,9 +243,10 @@ bool PCB_EDITOR_CONTROL::Init()
|
||||||
toolMenu.AddSubMenu( lockMenu );
|
toolMenu.AddSubMenu( lockMenu );
|
||||||
toolMenu.AddSubMenu( groupMenu );
|
toolMenu.AddSubMenu( groupMenu );
|
||||||
|
|
||||||
|
menu.AddMenu( groupMenu.get(), SELECTION_CONDITIONS::NotEmpty, 100 );
|
||||||
|
menu.AddMenu( lockMenu.get(), SELECTION_CONDITIONS::OnlyTypes( GENERAL_COLLECTOR::LockableItems ), 100 );
|
||||||
|
|
||||||
menu.AddMenu( zoneMenu.get(), SELECTION_CONDITIONS::OnlyType( PCB_ZONE_AREA_T ), 200 );
|
menu.AddMenu( zoneMenu.get(), SELECTION_CONDITIONS::OnlyType( PCB_ZONE_AREA_T ), 200 );
|
||||||
menu.AddMenu( lockMenu.get(), SELECTION_CONDITIONS::OnlyTypes( GENERAL_COLLECTOR::LockableItems ), 200 );
|
|
||||||
menu.AddMenu( groupMenu.get(), SELECTION_CONDITIONS::NotEmpty, 200 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DRAWING_TOOL* drawingTool = m_toolMgr->GetTool<DRAWING_TOOL>();
|
DRAWING_TOOL* drawingTool = m_toolMgr->GetTool<DRAWING_TOOL>();
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <pcb_painter.h>
|
#include <pcb_painter.h>
|
||||||
#include <connectivity/connectivity_data.h>
|
#include <connectivity/connectivity_data.h>
|
||||||
#include <profile.h>
|
#include <profile.h>
|
||||||
|
#include <dialogs/wx_html_report_box.h>
|
||||||
#include "pcb_inspection_tool.h"
|
#include "pcb_inspection_tool.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,7 +78,9 @@ bool PCB_INSPECTION_TOOL::Init()
|
||||||
CONDITIONAL_MENU& menu = selectionTool->GetToolMenu().GetMenu();
|
CONDITIONAL_MENU& menu = selectionTool->GetToolMenu().GetMenu();
|
||||||
|
|
||||||
selectionTool->GetToolMenu().AddSubMenu( netSubMenu );
|
selectionTool->GetToolMenu().AddSubMenu( netSubMenu );
|
||||||
menu.AddMenu( netSubMenu.get(), SELECTION_CONDITIONS::OnlyTypes( connectedTypes ) );
|
|
||||||
|
menu.AddMenu( netSubMenu.get(), SELECTION_CONDITIONS::OnlyTypes( connectedTypes ), 200 );
|
||||||
|
menu.AddItem( PCB_ACTIONS::inspectClearance, SELECTION_CONDITIONS::Count( 2 ), 200 );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -97,6 +100,195 @@ int PCB_INSPECTION_TOOL::ShowStatisticsDialog( const TOOL_EVENT& aEvent )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void reportZoneConnection( ZONE_CONTAINER* aZone, D_PAD* aPad, REPORTER* r )
|
||||||
|
{
|
||||||
|
ENUM_MAP<ZONE_CONNECTION> connectionEnum = ENUM_MAP<ZONE_CONNECTION>::Instance();
|
||||||
|
wxString source;
|
||||||
|
ZONE_CONNECTION connection = aZone->GetPadConnection( aPad, &source );
|
||||||
|
|
||||||
|
r->Report( "" );
|
||||||
|
|
||||||
|
r->Report( wxString::Format( _( "Zone connection type: %s." ),
|
||||||
|
connectionEnum.ToString( aZone->GetPadConnection() ) ) );
|
||||||
|
|
||||||
|
if( source != _( "zone" ) )
|
||||||
|
{
|
||||||
|
r->Report( wxString::Format( _( "Overridden by %s; connection type: %s." ),
|
||||||
|
source,
|
||||||
|
connectionEnum.ToString( connection ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve complex connection types into simple types
|
||||||
|
if( connection == ZONE_CONNECTION::THT_THERMAL )
|
||||||
|
{
|
||||||
|
if( aPad->GetAttribute() == PAD_ATTRIB_STANDARD )
|
||||||
|
{
|
||||||
|
connection = ZONE_CONNECTION::THERMAL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
connection = ZONE_CONNECTION::FULL;
|
||||||
|
r->Report( wxString::Format( _( "Pad is not a PTH pad; connection will be: %s." ),
|
||||||
|
connectionEnum.ToString( ZONE_CONNECTION::FULL ) ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r->Report( "" );
|
||||||
|
|
||||||
|
// Process simple connection types
|
||||||
|
if( connection == ZONE_CONNECTION::THERMAL )
|
||||||
|
{
|
||||||
|
int gap = aZone->GetThermalReliefGap();
|
||||||
|
|
||||||
|
r->Report( wxString::Format( _( "Zone thermal relief: %s." ),
|
||||||
|
StringFromValue( r->GetUnits(), gap, true ) ) );
|
||||||
|
|
||||||
|
gap = aZone->GetThermalReliefGap( aPad, &source );
|
||||||
|
|
||||||
|
if( source != _( "zone" ) )
|
||||||
|
{
|
||||||
|
r->Report( wxString::Format( _( "Overridden by %s; thermal relief: %s." ),
|
||||||
|
source,
|
||||||
|
StringFromValue( r->GetUnits(), gap, true ) ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( connection == ZONE_CONNECTION::NONE )
|
||||||
|
{
|
||||||
|
int clearance = aZone->GetLocalClearance();
|
||||||
|
|
||||||
|
r->Report( wxString::Format( _( "Zone clearance: %s." ),
|
||||||
|
StringFromValue( r->GetUnits(), clearance, true ) ) );
|
||||||
|
|
||||||
|
if( aZone->GetThermalReliefGap( aPad ) > clearance )
|
||||||
|
{
|
||||||
|
clearance = aZone->GetThermalReliefGap( aPad, &source );
|
||||||
|
|
||||||
|
if( source != _( "zone" ) )
|
||||||
|
{
|
||||||
|
r->Report( wxString::Format( _( "Overridden by larger thermal relief from %s;"
|
||||||
|
"clearance: %s." ),
|
||||||
|
source,
|
||||||
|
StringFromValue( r->GetUnits(), clearance, true ) ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r->Report( _( "Clearance is 0." ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void reportCopperClearance( PCB_LAYER_ID aLayer, BOARD_CONNECTED_ITEM* aA, BOARD_ITEM* aB,
|
||||||
|
REPORTER* r )
|
||||||
|
{
|
||||||
|
wxString source;
|
||||||
|
|
||||||
|
r->Report( "" );
|
||||||
|
|
||||||
|
// JEY TODO: hook this up to new DRC engine to get "classic" sources as well; right now
|
||||||
|
// we're just reporting on rules....
|
||||||
|
aA->GetClearance( aLayer, aB, &source, r );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int PCB_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent )
|
||||||
|
{
|
||||||
|
SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
|
||||||
|
const PCBNEW_SELECTION& selection = selTool->GetSelection();
|
||||||
|
PCB_LAYER_ID layer = m_frame->GetActiveLayer();
|
||||||
|
|
||||||
|
if( selection.Size() != 2 )
|
||||||
|
{
|
||||||
|
m_frame->ShowInfoBarError( _( "Select two items for a clearance resolution report." ) );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_inspectClearanceDialog == nullptr )
|
||||||
|
{
|
||||||
|
m_inspectClearanceDialog = std::make_unique<DIALOG_HTML_REPORTER>( m_frame );
|
||||||
|
m_inspectClearanceDialog->SetTitle( _( "Clearance Report" ) );
|
||||||
|
|
||||||
|
m_inspectClearanceDialog->Connect( wxEVT_CLOSE_WINDOW,
|
||||||
|
wxCommandEventHandler( PCB_INSPECTION_TOOL::onInspectClearanceDialogClosed ),
|
||||||
|
nullptr, this );
|
||||||
|
}
|
||||||
|
|
||||||
|
WX_HTML_REPORT_BOX* r = m_inspectClearanceDialog->m_Reporter;
|
||||||
|
r->SetUnits( m_frame->GetUserUnits() );
|
||||||
|
r->Clear();
|
||||||
|
|
||||||
|
BOARD_ITEM* a = static_cast<BOARD_ITEM*>( selection.GetItem( 0 ) );
|
||||||
|
BOARD_ITEM* b = static_cast<BOARD_ITEM*>( selection.GetItem( 1 ) );
|
||||||
|
|
||||||
|
if( a->Type() != PCB_ZONE_AREA_T && b->Type() == PCB_ZONE_AREA_T )
|
||||||
|
std::swap( a, b );
|
||||||
|
else if( !a->IsConnected() && b->IsConnected() )
|
||||||
|
std::swap( a, b );
|
||||||
|
|
||||||
|
if( !IsCopperLayer( layer ) )
|
||||||
|
{
|
||||||
|
r->Report( wxString::Format( _( "Active layer (%s) is not a copper layer. "
|
||||||
|
"No clearance defined." ),
|
||||||
|
m_frame->GetBoard()->GetLayerName( layer ) ) );
|
||||||
|
}
|
||||||
|
else if( !a->GetLayerSet().test( layer ) )
|
||||||
|
{
|
||||||
|
r->Report( wxString::Format( _( "%s not present on layer %s. No clearance defined." ),
|
||||||
|
a->GetSelectMenuText( r->GetUnits() ),
|
||||||
|
m_frame->GetBoard()->GetLayerName( layer ) ) );
|
||||||
|
}
|
||||||
|
else if( !b->GetLayerSet().test( layer ) )
|
||||||
|
{
|
||||||
|
r->Report( wxString::Format( _( "%s not present on layer %s. No clearance defined." ),
|
||||||
|
b->GetSelectMenuText( r->GetUnits() ),
|
||||||
|
m_frame->GetBoard()->GetLayerName( layer ) ) );
|
||||||
|
}
|
||||||
|
else if( !a->IsConnected() )
|
||||||
|
{
|
||||||
|
r->Report( _( "Items have no electrical connections. No clearance defined." ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r->Report( _( "<h7>Clearance resolution for:</h7>" ) );
|
||||||
|
|
||||||
|
r->Report( wxString::Format( _( "<ul><li>Layer %s</li><li>%s</li><li>%s</li></ul>" ),
|
||||||
|
m_frame->GetBoard()->GetLayerName( layer ),
|
||||||
|
a->GetSelectMenuText( r->GetUnits() ),
|
||||||
|
b->GetSelectMenuText( r->GetUnits() ) ) );
|
||||||
|
|
||||||
|
BOARD_CONNECTED_ITEM* ac = dynamic_cast<BOARD_CONNECTED_ITEM*>( a );
|
||||||
|
BOARD_CONNECTED_ITEM* bc = dynamic_cast<BOARD_CONNECTED_ITEM*>( b );
|
||||||
|
|
||||||
|
if( ac && bc && ac->GetNetCode() > 0 && ac->GetNetCode() == bc->GetNetCode() )
|
||||||
|
{
|
||||||
|
// Same nets....
|
||||||
|
|
||||||
|
if( ac->Type() == PCB_ZONE_AREA_T && bc->Type() == PCB_PAD_T )
|
||||||
|
{
|
||||||
|
reportZoneConnection( static_cast<ZONE_CONTAINER*>( ac ),
|
||||||
|
static_cast<D_PAD*>( bc ), r );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r->Report( _( "Items belong to the same net. Clearance is 0." ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Different nets (or second unconnected)....
|
||||||
|
|
||||||
|
reportCopperClearance( layer, ac, b, r );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r->Flush();
|
||||||
|
|
||||||
|
m_inspectClearanceDialog->Show( true );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int PCB_INSPECTION_TOOL::CrossProbePcbToSch( const TOOL_EVENT& aEvent )
|
int PCB_INSPECTION_TOOL::CrossProbePcbToSch( const TOOL_EVENT& aEvent )
|
||||||
{
|
{
|
||||||
// Don't get in an infinite loop PCB -> SCH -> PCB -> SCH -> ...
|
// Don't get in an infinite loop PCB -> SCH -> PCB -> SCH -> ...
|
||||||
|
@ -537,6 +729,16 @@ void PCB_INSPECTION_TOOL::onListNetsDialogClosed( wxCommandEvent& event )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PCB_INSPECTION_TOOL::onInspectClearanceDialogClosed( wxCommandEvent& event )
|
||||||
|
{
|
||||||
|
m_inspectClearanceDialog->Disconnect( wxEVT_CLOSE_WINDOW,
|
||||||
|
wxCommandEventHandler( PCB_INSPECTION_TOOL::onListNetsDialogClosed ), nullptr, this );
|
||||||
|
|
||||||
|
m_inspectClearanceDialog->Destroy();
|
||||||
|
m_inspectClearanceDialog.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int PCB_INSPECTION_TOOL::HideNet( const TOOL_EVENT& aEvent )
|
int PCB_INSPECTION_TOOL::HideNet( const TOOL_EVENT& aEvent )
|
||||||
{
|
{
|
||||||
doHideNet( aEvent.Parameter<intptr_t>(), true );
|
doHideNet( aEvent.Parameter<intptr_t>(), true );
|
||||||
|
@ -595,6 +797,7 @@ void PCB_INSPECTION_TOOL::setTransitions()
|
||||||
|
|
||||||
Go( &PCB_INSPECTION_TOOL::ListNets, PCB_ACTIONS::listNets.MakeEvent() );
|
Go( &PCB_INSPECTION_TOOL::ListNets, PCB_ACTIONS::listNets.MakeEvent() );
|
||||||
Go( &PCB_INSPECTION_TOOL::ShowStatisticsDialog, PCB_ACTIONS::boardStatistics.MakeEvent() );
|
Go( &PCB_INSPECTION_TOOL::ShowStatisticsDialog, PCB_ACTIONS::boardStatistics.MakeEvent() );
|
||||||
|
Go( &PCB_INSPECTION_TOOL::InspectClearance, PCB_ACTIONS::inspectClearance.MakeEvent() );
|
||||||
|
|
||||||
Go( &PCB_INSPECTION_TOOL::HighlightNet, PCB_ACTIONS::highlightNet.MakeEvent() );
|
Go( &PCB_INSPECTION_TOOL::HighlightNet, PCB_ACTIONS::highlightNet.MakeEvent() );
|
||||||
Go( &PCB_INSPECTION_TOOL::HighlightNet, PCB_ACTIONS::highlightNetSelection.MakeEvent() );
|
Go( &PCB_INSPECTION_TOOL::HighlightNet, PCB_ACTIONS::highlightNetSelection.MakeEvent() );
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include <dialogs/dialog_board_statistics.h>
|
#include <dialogs/dialog_board_statistics.h>
|
||||||
#include <dialogs/dialog_select_net_from_list.h>
|
#include <dialogs/dialog_select_net_from_list.h>
|
||||||
|
#include <dialogs/dialog_HTML_reporter_base.h>
|
||||||
#include <pcb_edit_frame.h>
|
#include <pcb_edit_frame.h>
|
||||||
#include <tools/pcb_actions.h>
|
#include <tools/pcb_actions.h>
|
||||||
#include <tools/pcb_tool_base.h>
|
#include <tools/pcb_tool_base.h>
|
||||||
|
@ -89,6 +90,9 @@ public:
|
||||||
///> Show the ratsnest for a given net
|
///> Show the ratsnest for a given net
|
||||||
int ShowNet( const TOOL_EVENT& aEvent );
|
int ShowNet( const TOOL_EVENT& aEvent );
|
||||||
|
|
||||||
|
///> Show the clearance resolution for two selected items
|
||||||
|
int InspectClearance( const TOOL_EVENT& aEvent );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
///> Event handler to recalculate dynamic ratsnest
|
///> Event handler to recalculate dynamic ratsnest
|
||||||
void ratsnestTimer( wxTimerEvent& aEvent );
|
void ratsnestTimer( wxTimerEvent& aEvent );
|
||||||
|
@ -103,7 +107,8 @@ private:
|
||||||
///> Bind handlers to corresponding TOOL_ACTIONs
|
///> Bind handlers to corresponding TOOL_ACTIONs
|
||||||
void setTransitions() override;
|
void setTransitions() override;
|
||||||
|
|
||||||
void onListNetsDialogClosed( wxCommandEvent& event );
|
void onListNetsDialogClosed( wxCommandEvent& aEvent );
|
||||||
|
void onInspectClearanceDialogClosed( wxCommandEvent& aEvent );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PCB_EDIT_FRAME* m_frame; // Pointer to the currently used edit frame.
|
PCB_EDIT_FRAME* m_frame; // Pointer to the currently used edit frame.
|
||||||
|
@ -116,6 +121,7 @@ private:
|
||||||
std::unique_ptr<DIALOG_SELECT_NET_FROM_LIST> m_listNetsDialog;
|
std::unique_ptr<DIALOG_SELECT_NET_FROM_LIST> m_listNetsDialog;
|
||||||
DIALOG_SELECT_NET_FROM_LIST::SETTINGS m_listNetsDialogSettings;
|
DIALOG_SELECT_NET_FROM_LIST::SETTINGS m_listNetsDialogSettings;
|
||||||
|
|
||||||
|
std::unique_ptr<DIALOG_HTML_REPORTER> m_inspectClearanceDialog;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //__BOARD_STATISTICS_TOOL_H
|
#endif //__BOARD_STATISTICS_TOOL_H
|
||||||
|
|
Loading…
Reference in New Issue