Add edge and margin clearances to message panel.

This commit is contained in:
Jeff Young 2022-07-15 16:14:11 +01:00
parent 50bb7c93a1
commit 2de10080cd
13 changed files with 124 additions and 131 deletions

View File

@ -117,6 +117,11 @@ public:
return IsCopperLayer( GetLayer() ); return IsCopperLayer( GetLayer() );
} }
virtual bool HasHole() const
{
return false;
}
virtual bool IsTented() const virtual bool IsTented() const
{ {
return false; return false;

View File

@ -116,7 +116,7 @@ bool DRC_CACHE_GENERATOR::Run()
{ {
PAD* pad = static_cast<PAD*>( item ); PAD* pad = static_cast<PAD*>( item );
if( pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0 ) if( pad->HasHole() )
layers |= LSET::AllCuMask(); layers |= LSET::AllCuMask();
} }

View File

@ -121,7 +121,7 @@ public:
{ {
PAD* pad = static_cast<PAD*>( aItem ); PAD* pad = static_cast<PAD*>( aItem );
if( pad->GetDrillSizeX() ) if( pad->HasHole() )
{ {
const SHAPE* hole = pad->GetEffectiveHoleShape(); const SHAPE* hole = pad->GetEffectiveHoleShape();
subshapes.push_back( const_cast<SHAPE*>( hole ) ); subshapes.push_back( const_cast<SHAPE*>( hole ) );

View File

@ -276,8 +276,7 @@ int DRC_TEST_PROVIDER::forEachGeometryItem( const std::vector<KICAD_T>& aTypes,
for( PAD* pad : footprint->Pads() ) for( PAD* pad : footprint->Pads() )
{ {
// Careful: if a pad has a hole then it pierces all layers // Careful: if a pad has a hole then it pierces all layers
if( ( pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0 ) if( pad->HasHole() || ( pad->GetLayerSet() & aLayers ).any() )
|| ( pad->GetLayerSet() & aLayers ).any() )
{ {
if( !aFunc( pad ) ) if( !aFunc( pad ) )
return n; return n;

View File

@ -244,7 +244,6 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run()
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_ALLOWED_ITEMS ) ) if( !m_drcEngine->IsErrorLimitExceeded( DRCE_ALLOWED_ITEMS ) )
{ {
ZONE* zone = dynamic_cast<ZONE*>( item ); ZONE* zone = dynamic_cast<ZONE*>( item );
PAD* pad = dynamic_cast<PAD*>( item );
if( zone && zone->GetIsRuleArea() ) if( zone && zone->GetIsRuleArea() )
return true; return true;
@ -253,22 +252,10 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run()
checkDisallow( item ); checkDisallow( item );
bool hasHole; if( item->HasHole() )
switch( item->Type() )
{
case PCB_VIA_T: hasHole = true; break;
case PCB_PAD_T: hasHole = pad && pad->GetDrillSizeX() > 0; break;
default: hasHole = false; break;
}
if( hasHole )
{ {
item->SetFlags( HOLE_PROXY ); item->SetFlags( HOLE_PROXY );
{ checkDisallow( item );
checkDisallow( item );
}
item->ClearFlags( HOLE_PROXY ); item->ClearFlags( HOLE_PROXY );
} }
} }

View File

@ -136,19 +136,9 @@ bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::Run()
LSET layers = item->GetLayerSet(); LSET layers = item->GetLayerSet();
// Special-case holes and edge-cuts which pierce all physical layers // Special-case holes and edge-cuts which pierce all physical layers
if( item->Type() == PCB_PAD_T ) if( item->HasHole() )
{ {
PAD* pad = static_cast<PAD*>( item ); layers |= LSET::PhysicalLayersMask() | courtyards;
if( pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0 )
layers |= LSET::PhysicalLayersMask() | courtyards;
}
else if( item->Type() == PCB_VIA_T )
{
PCB_VIA* via = static_cast<PCB_VIA*>( item );
if( via->GetDrill() > 0 )
layers |= LSET::PhysicalLayersMask() | courtyards;
} }
else if( item->Type() == PCB_FOOTPRINT_T ) else if( item->Type() == PCB_FOOTPRINT_T )
{ {

View File

@ -103,6 +103,11 @@ public:
return false; return false;
} }
bool HasHole() const override
{
return GetDrillSizeX() > 0 && GetDrillSizeY() > 0;
}
FOOTPRINT* GetParent() const; FOOTPRINT* GetParent() const;
wxString GetParentAsString() const { return m_parent->m_Uuid.AsString(); } wxString GetParentAsString() const { return m_parent->m_Uuid.AsString(); }

View File

@ -353,6 +353,11 @@ public:
VIATYPE GetViaType() const { return m_viaType; } VIATYPE GetViaType() const { return m_viaType; }
void SetViaType( VIATYPE aViaType ) { m_viaType = aViaType; } void SetViaType( VIATYPE aViaType ) { m_viaType = aViaType; }
bool HasHole() const override
{
return true;
}
bool IsTented() const override; bool IsTented() const override;
int GetSolderMaskExpansion() const; int GetSolderMaskExpansion() const;

View File

@ -2546,7 +2546,7 @@ void ALTIUM_PCB::ConvertPads6ToFootprintItemOnCopper( FOOTPRINT* aFootprint, con
break; break;
} }
if( pad->GetAttribute() == PAD_ATTRIB::NPTH && pad->GetDrillSizeX() ) if( pad->GetAttribute() == PAD_ATTRIB::NPTH && pad->HasHole() )
{ {
// KiCad likes NPTH pads to be the same size & shape as their holes // KiCad likes NPTH pads to be the same size & shape as their holes
pad->SetShape( pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE ? PAD_SHAPE::CIRCLE pad->SetShape( pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE ? PAD_SHAPE::CIRCLE

View File

@ -138,12 +138,10 @@ void TEARDROP_MANAGER::collectPadsCandidate( std::vector< VIAPAD >& aList,
continue; continue;
} }
bool has_hole = pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0; if( pad->HasHole() && !aDrilledViaPad )
if( has_hole && !aDrilledViaPad )
continue; continue;
if( has_hole || aIncludeNotDrilled ) if( pad->HasHole() || aIncludeNotDrilled )
aList.emplace_back( pad ); aList.emplace_back( pad );
} }
} }

View File

@ -504,22 +504,6 @@ void BOARD_INSPECTION_TOOL::InspectDRCError( const std::shared_ptr<RC_ITEM>& aDR
} }
bool hasHole( BOARD_ITEM* aItem )
{
PAD* pad = dynamic_cast<PAD*>( aItem );
if( pad && pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0 )
return true;
PCB_VIA* via = dynamic_cast<PCB_VIA*>( aItem );
if( via )
return true;
return false;
};
int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent ) int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent )
{ {
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>(); PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
@ -878,17 +862,17 @@ int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent )
} }
} }
if( hasHole( a ) || hasHole( b ) ) if( a->HasHole() || b->HasHole() )
{ {
PCB_LAYER_ID layer = UNDEFINED_LAYER; PCB_LAYER_ID layer = UNDEFINED_LAYER;
if( hasHole( a ) && b->IsOnLayer( active ) && IsCopperLayer( active ) ) if( a->HasHole() && b->IsOnLayer( active ) && IsCopperLayer( active ) )
layer = active; layer = active;
else if( hasHole( b ) && a->IsOnLayer( active ) && IsCopperLayer( active ) ) else if( b->HasHole() && a->IsOnLayer( active ) && IsCopperLayer( active ) )
layer = active; layer = active;
else if( hasHole( a ) && b->IsOnCopperLayer() ) else if( a->HasHole() && b->IsOnCopperLayer() )
layer = b->GetLayer(); layer = b->GetLayer();
else if( hasHole( b ) && b->IsOnCopperLayer() ) else if( b->HasHole() && b->IsOnCopperLayer() )
layer = a->GetLayer(); layer = a->GetLayer();
if( layer >= 0 ) if( layer >= 0 )
@ -1007,15 +991,15 @@ int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent )
reportPhysicalClearance( B_CrtYd ); reportPhysicalClearance( B_CrtYd );
} }
if( hasHole( a ) || hasHole( b ) ) if( a->HasHole() || b->HasHole() )
{ {
PCB_LAYER_ID layer; PCB_LAYER_ID layer;
if( hasHole( a ) && b->IsOnLayer( active ) ) if( a->HasHole() && b->IsOnLayer( active ) )
layer = active; layer = active;
else if( hasHole( b ) && a->IsOnLayer( active ) ) else if( b->HasHole() && a->IsOnLayer( active ) )
layer = active; layer = active;
else if( hasHole( a ) ) else if( a->HasHole() )
layer = b->GetLayer(); layer = b->GetLayer();
else else
layer = a->GetLayer(); layer = a->GetLayer();

View File

@ -106,6 +106,8 @@ public:
return !m_currentlyHighlighted.empty(); return !m_currentlyHighlighted.empty();
} }
static bool HasHole( BOARD_ITEM* aItem );
private: private:
///< Recalculate dynamic ratsnest for the current selection. ///< Recalculate dynamic ratsnest for the current selection.
void calculateSelectionRatsnest( const VECTOR2I& aDelta ); void calculateSelectionRatsnest( const VECTOR2I& aDelta );

View File

@ -24,6 +24,7 @@
*/ */
#include <tools/edit_tool.h> #include <tools/edit_tool.h>
#include <tools/board_inspection_tool.h>
#include <router/router_tool.h> #include <router/router_tool.h>
#include <pgm_base.h> #include <pgm_base.h>
#include <tools/pcb_actions.h> #include <tools/pcb_actions.h>
@ -1190,11 +1191,13 @@ int PCB_CONTROL::Redo( const TOOL_EVENT& aEvent )
int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent ) int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent )
{ {
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>(); PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
ROUTER_TOOL* routerTool = m_toolMgr->GetTool<ROUTER_TOOL>(); ROUTER_TOOL* routerTool = m_toolMgr->GetTool<ROUTER_TOOL>();
PCB_SELECTION& selection = selTool->GetSelection(); PCB_SELECTION& selection = selTool->GetSelection();
FOOTPRINT_EDIT_FRAME* fpFrame = dynamic_cast<FOOTPRINT_EDIT_FRAME*>( m_frame ); FOOTPRINT_EDIT_FRAME* fpFrame = dynamic_cast<FOOTPRINT_EDIT_FRAME*>( m_frame );
PCB_EDIT_FRAME* pcbFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ); PCB_EDIT_FRAME* pcbFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
std::shared_ptr<DRC_ENGINE> drcEngine = m_frame->GetBoard()->GetDesignSettings().m_DRCEngine;
DRC_CONSTRAINT constraint;
EDA_UNITS units = m_frame->GetUserUnits(); EDA_UNITS units = m_frame->GetUserUnits();
std::vector<MSG_PANEL_ITEM> msgItems; std::vector<MSG_PANEL_ITEM> msgItems;
@ -1214,7 +1217,7 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent )
if( !footprint ) if( !footprint )
return 0; return 0;
wxString msg; wxString msg;
msg = footprint->GetFPID().GetLibNickname().wx_str(); msg = footprint->GetFPID().GetLibNickname().wx_str();
msgItems.emplace_back( MSG_PANEL_ITEM( _( "Library" ), msg ) ); msgItems.emplace_back( MSG_PANEL_ITEM( _( "Library" ), msg ) );
@ -1244,90 +1247,105 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent )
} }
// Pair selection broken into multiple, optional data, starting with the selection item names // Pair selection broken into multiple, optional data, starting with the selection item names
if( selection.GetSize() == 2 ) if( pcbFrame && selection.GetSize() == 2 )
{ {
auto clearanceString =
[&]( const DRC_CONSTRAINT& constraint )
{
return StringFromValue( units, constraint.m_Value.Min(), true );
};
BOARD_ITEM* a = static_cast<BOARD_ITEM*>( selection[0] ); BOARD_ITEM* a = static_cast<BOARD_ITEM*>( selection[0] );
BOARD_ITEM* b = static_cast<BOARD_ITEM*>( selection[1] ); BOARD_ITEM* b = static_cast<BOARD_ITEM*>( selection[1] );
msgItems.emplace_back( MSG_PANEL_ITEM( a->GetSelectMenuText( units ), msgItems.emplace_back( MSG_PANEL_ITEM( a->GetSelectMenuText( units ),
b->GetSelectMenuText( units ) ) ); b->GetSelectMenuText( units ) ) );
}
if( BOARD_CONNECTED_ITEM *a, *b; BOARD_CONNECTED_ITEM* a_conn = dyn_cast<BOARD_CONNECTED_ITEM*>( a );
selection.GetSize() == 2 && pcbFrame && BOARD_CONNECTED_ITEM* b_conn = dyn_cast<BOARD_CONNECTED_ITEM*>( b );
( a = dyn_cast<BOARD_CONNECTED_ITEM*>( selection[0] ) ) &&
( b = dyn_cast<BOARD_CONNECTED_ITEM*>( selection[1] ) ) )
{
LSET overlap = a->GetLayerSet() & b->GetLayerSet() & LSET::AllCuMask();
BOARD_DESIGN_SETTINGS& bds = m_frame->GetBoard()->GetDesignSettings(); if( a_conn && b_conn )
if( overlap.count() > 0
&& ( a->GetNetCode() != b->GetNetCode()
|| a->GetNetCode() < 0
|| b->GetNetCode() < 0 ) )
{ {
PCB_LAYER_ID layer = overlap.CuStack().front(); LSET overlap = a_conn->GetLayerSet() & b_conn->GetLayerSet() & LSET::AllCuMask();
auto aShape = a->GetEffectiveShape( layer ); int a_netcode = a_conn->GetNetCode();
auto bShape = b->GetEffectiveShape( layer ); int b_netcode = b_conn->GetNetCode();
DRC_CONSTRAINT constraint; if( overlap.count() > 0
int clearance = 0; && ( a_netcode != b_netcode || a_netcode < 0 || b_netcode < 0 ) )
{
constraint = drcEngine->EvalRules( CLEARANCE_CONSTRAINT, a, b,
overlap.CuStack().front() );
constraint = bds.m_DRCEngine->EvalRules( CLEARANCE_CONSTRAINT, a, b, layer ); msgItems.emplace_back( MSG_PANEL_ITEM( _( "Resolved clearance" ),
clearance = constraint.m_Value.Min(); clearanceString( constraint ) ) );
msgItems.emplace_back( MSG_PANEL_ITEM( _( "Resolved clearance" ), }
StringFromValue( units, clearance, true ) ) );
} }
}
if( a->HasHole() || b->HasHole() )
auto hasHole = []( EDA_ITEM* aItem ) -> bool
{
PAD* pad = dyn_cast<PAD*>( aItem );
if( pad && pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0 )
return true;
return !!dyn_cast<PCB_VIA*>( aItem );
};
if( selection.GetSize() == 2 && pcbFrame &&
( hasHole( selection[0] ) || hasHole( selection[1] ) ) )
{
PCB_LAYER_ID active = m_frame->GetActiveLayer();
PCB_LAYER_ID layer = UNDEFINED_LAYER;
BOARD_ITEM* a = static_cast<BOARD_ITEM*>( selection[0] );
BOARD_ITEM* b = static_cast<BOARD_ITEM*>( selection[1] );
if( b->IsOnLayer( active ) && IsCopperLayer( active ) )
layer = active;
else if( hasHole( b ) && a->IsOnLayer( active ) && IsCopperLayer( active ) )
layer = active;
else if( hasHole( a ) && b->IsOnCopperLayer() )
layer = b->GetLayer();
else if( hasHole( b ) && b->IsOnCopperLayer() )
layer = a->GetLayer();
if( layer >= 0 )
{ {
PCB_LAYER_ID active = m_frame->GetActiveLayer();
PCB_LAYER_ID layer = UNDEFINED_LAYER;
BOARD_DESIGN_SETTINGS& bds = m_frame->GetBoard()->GetDesignSettings(); if( b->IsOnLayer( active ) && IsCopperLayer( active ) )
DRC_CONSTRAINT constraint; layer = active;
int clearance = 0; else if( b->HasHole() && a->IsOnLayer( active ) && IsCopperLayer( active ) )
layer = active;
else if( a->HasHole() && b->IsOnCopperLayer() )
layer = b->GetLayer();
else if( b->HasHole() && b->IsOnCopperLayer() )
layer = a->GetLayer();
constraint = bds.m_DRCEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer ); if( layer >= 0 )
clearance = constraint.m_Value.Min(); {
msgItems.emplace_back( MSG_PANEL_ITEM( _( "Resolved hole clearance" ), constraint = drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer );
StringFromValue( units, clearance, true ) ) ); msgItems.emplace_back( MSG_PANEL_ITEM( _( "Resolved hole clearance" ),
clearanceString( constraint ) ) );
}
}
for( PCB_LAYER_ID edgeLayer : { Edge_Cuts, Margin } )
{
PCB_LAYER_ID active = m_frame->GetActiveLayer();
PCB_LAYER_ID layer = UNDEFINED_LAYER;
if( a->IsOnLayer( edgeLayer ) && b->Type() != PCB_FOOTPRINT_T )
{
if( b->IsOnLayer( active ) && IsCopperLayer( active ) )
layer = active;
else if( IsCopperLayer( b->GetLayer() ) )
layer = b->GetLayer();
}
else if( b->IsOnLayer( edgeLayer ) && a->Type() != PCB_FOOTPRINT_T )
{
if( a->IsOnLayer( active ) && IsCopperLayer( active ) )
layer = active;
else if( IsCopperLayer( a->GetLayer() ) )
layer = a->GetLayer();
}
if( layer >= 0 )
{
constraint = drcEngine->EvalRules( EDGE_CLEARANCE_CONSTRAINT, a, b, layer );
if( edgeLayer == Edge_Cuts )
{
msgItems.emplace_back( MSG_PANEL_ITEM( _( "Resolved edge clearance" ),
clearanceString( constraint ) ) );
}
else
{
msgItems.emplace_back( MSG_PANEL_ITEM( _( "Resolved margin clearance" ),
clearanceString( constraint ) ) );
}
}
} }
} }
if( msgItems.empty() ) if( msgItems.empty() )
msgItems.emplace_back( {
MSG_PANEL_ITEM( _( "Selected Items" ), wxString msg = wxString::Format( wxT( "%d" ), selection.GetSize() );
wxString::Format( wxT( "%d" ), selection.GetSize() ) ) ); msgItems.emplace_back( MSG_PANEL_ITEM( _( "Selected Items" ), msg ) );
}
m_frame->SetMsgPanel( msgItems ); m_frame->SetMsgPanel( msgItems );