ADDED Clearance Inspector.

This commit is contained in:
Jeff Young 2020-09-10 20:58:05 +01:00
parent e31705d4b3
commit fc1665ff28
12 changed files with 335 additions and 47 deletions

View File

@ -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;
} }

View File

@ -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

View File

@ -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;
} }

View File

@ -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

View File

@ -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 )

View File

@ -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 ----------------------------------------------------------

View File

@ -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;
} }

View File

@ -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, "",

View File

@ -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;

View File

@ -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>();

View File

@ -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() );

View File

@ -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