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() );
}
virtual bool HasHole() const
{
return false;
}
virtual bool IsTented() const
{
return false;

View File

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

View File

@ -121,7 +121,7 @@ public:
{
PAD* pad = static_cast<PAD*>( aItem );
if( pad->GetDrillSizeX() )
if( pad->HasHole() )
{
const SHAPE* hole = pad->GetEffectiveHoleShape();
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() )
{
// Careful: if a pad has a hole then it pierces all layers
if( ( pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0 )
|| ( pad->GetLayerSet() & aLayers ).any() )
if( pad->HasHole() || ( pad->GetLayerSet() & aLayers ).any() )
{
if( !aFunc( pad ) )
return n;

View File

@ -244,7 +244,6 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run()
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_ALLOWED_ITEMS ) )
{
ZONE* zone = dynamic_cast<ZONE*>( item );
PAD* pad = dynamic_cast<PAD*>( item );
if( zone && zone->GetIsRuleArea() )
return true;
@ -253,22 +252,10 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run()
checkDisallow( item );
bool 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 )
if( item->HasHole() )
{
item->SetFlags( HOLE_PROXY );
{
checkDisallow( item );
}
checkDisallow( item );
item->ClearFlags( HOLE_PROXY );
}
}

View File

@ -136,19 +136,9 @@ bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::Run()
LSET layers = item->GetLayerSet();
// 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 );
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;
layers |= LSET::PhysicalLayersMask() | courtyards;
}
else if( item->Type() == PCB_FOOTPRINT_T )
{

View File

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

View File

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

View File

@ -2546,7 +2546,7 @@ void ALTIUM_PCB::ConvertPads6ToFootprintItemOnCopper( FOOTPRINT* aFootprint, con
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
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;
}
bool has_hole = pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0;
if( has_hole && !aDrilledViaPad )
if( pad->HasHole() && !aDrilledViaPad )
continue;
if( has_hole || aIncludeNotDrilled )
if( pad->HasHole() || aIncludeNotDrilled )
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 )
{
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;
if( hasHole( a ) && b->IsOnLayer( active ) && IsCopperLayer( active ) )
if( a->HasHole() && b->IsOnLayer( active ) && IsCopperLayer( active ) )
layer = active;
else if( hasHole( b ) && a->IsOnLayer( active ) && IsCopperLayer( active ) )
else if( b->HasHole() && a->IsOnLayer( active ) && IsCopperLayer( active ) )
layer = active;
else if( hasHole( a ) && b->IsOnCopperLayer() )
else if( a->HasHole() && b->IsOnCopperLayer() )
layer = b->GetLayer();
else if( hasHole( b ) && b->IsOnCopperLayer() )
else if( b->HasHole() && b->IsOnCopperLayer() )
layer = a->GetLayer();
if( layer >= 0 )
@ -1007,15 +991,15 @@ int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent )
reportPhysicalClearance( B_CrtYd );
}
if( hasHole( a ) || hasHole( b ) )
if( a->HasHole() || b->HasHole() )
{
PCB_LAYER_ID layer;
if( hasHole( a ) && b->IsOnLayer( active ) )
if( a->HasHole() && b->IsOnLayer( active ) )
layer = active;
else if( hasHole( b ) && a->IsOnLayer( active ) )
else if( b->HasHole() && a->IsOnLayer( active ) )
layer = active;
else if( hasHole( a ) )
else if( a->HasHole() )
layer = b->GetLayer();
else
layer = a->GetLayer();

View File

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

View File

@ -24,6 +24,7 @@
*/
#include <tools/edit_tool.h>
#include <tools/board_inspection_tool.h>
#include <router/router_tool.h>
#include <pgm_base.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 )
{
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
ROUTER_TOOL* routerTool = m_toolMgr->GetTool<ROUTER_TOOL>();
PCB_SELECTION& selection = selTool->GetSelection();
FOOTPRINT_EDIT_FRAME* fpFrame = dynamic_cast<FOOTPRINT_EDIT_FRAME*>( m_frame );
PCB_EDIT_FRAME* pcbFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
ROUTER_TOOL* routerTool = m_toolMgr->GetTool<ROUTER_TOOL>();
PCB_SELECTION& selection = selTool->GetSelection();
FOOTPRINT_EDIT_FRAME* fpFrame = dynamic_cast<FOOTPRINT_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();
std::vector<MSG_PANEL_ITEM> msgItems;
@ -1214,7 +1217,7 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent )
if( !footprint )
return 0;
wxString msg;
wxString msg;
msg = footprint->GetFPID().GetLibNickname().wx_str();
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
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* b = static_cast<BOARD_ITEM*>( selection[1] );
msgItems.emplace_back( MSG_PANEL_ITEM( a->GetSelectMenuText( units ),
b->GetSelectMenuText( units ) ) );
}
if( BOARD_CONNECTED_ITEM *a, *b;
selection.GetSize() == 2 && pcbFrame &&
( 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_CONNECTED_ITEM* a_conn = dyn_cast<BOARD_CONNECTED_ITEM*>( a );
BOARD_CONNECTED_ITEM* b_conn = dyn_cast<BOARD_CONNECTED_ITEM*>( b );
BOARD_DESIGN_SETTINGS& bds = m_frame->GetBoard()->GetDesignSettings();
if( overlap.count() > 0
&& ( a->GetNetCode() != b->GetNetCode()
|| a->GetNetCode() < 0
|| b->GetNetCode() < 0 ) )
if( a_conn && b_conn )
{
PCB_LAYER_ID layer = overlap.CuStack().front();
auto aShape = a->GetEffectiveShape( layer );
auto bShape = b->GetEffectiveShape( layer );
LSET overlap = a_conn->GetLayerSet() & b_conn->GetLayerSet() & LSET::AllCuMask();
int a_netcode = a_conn->GetNetCode();
int b_netcode = b_conn->GetNetCode();
DRC_CONSTRAINT constraint;
int clearance = 0;
if( overlap.count() > 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 );
clearance = constraint.m_Value.Min();
msgItems.emplace_back( MSG_PANEL_ITEM( _( "Resolved clearance" ),
StringFromValue( units, clearance, true ) ) );
msgItems.emplace_back( MSG_PANEL_ITEM( _( "Resolved clearance" ),
clearanceString( constraint ) ) );
}
}
}
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 )
if( a->HasHole() || b->HasHole() )
{
PCB_LAYER_ID active = m_frame->GetActiveLayer();
PCB_LAYER_ID layer = UNDEFINED_LAYER;
BOARD_DESIGN_SETTINGS& bds = m_frame->GetBoard()->GetDesignSettings();
DRC_CONSTRAINT constraint;
int clearance = 0;
if( b->IsOnLayer( active ) && IsCopperLayer( active ) )
layer = active;
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 );
clearance = constraint.m_Value.Min();
msgItems.emplace_back( MSG_PANEL_ITEM( _( "Resolved hole clearance" ),
StringFromValue( units, clearance, true ) ) );
if( layer >= 0 )
{
constraint = drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer );
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() )
msgItems.emplace_back(
MSG_PANEL_ITEM( _( "Selected Items" ),
wxString::Format( wxT( "%d" ), selection.GetSize() ) ) );
{
wxString msg = wxString::Format( wxT( "%d" ), selection.GetSize() );
msgItems.emplace_back( MSG_PANEL_ITEM( _( "Selected Items" ), msg ) );
}
m_frame->SetMsgPanel( msgItems );