Make sure physical_clearance rules are run against courtyard layers.
This commit is contained in:
parent
d81378d786
commit
37838dffb9
|
@ -265,3 +265,10 @@ For the latter use a `(layer "layer_name")` clause in the rule.
|
|||
(rule "disallow solder mask margin overrides"
|
||||
(constraint assertion "A.Soldermask_Margin_Override == 0mm")
|
||||
(condition "A.Type == 'Pad'"))
|
||||
|
||||
|
||||
# Enforce a mechanical clearance between components and board edge
|
||||
(rule front_mechanical_board_edge_clearance
|
||||
(layer "F.Courtyard")
|
||||
(constraint physical_clearance (min 3mm))
|
||||
(condition "B.Layer == 'Edge.Cuts'"))
|
||||
|
|
|
@ -145,12 +145,15 @@ bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::Run()
|
|||
|
||||
static const std::vector<KICAD_T> itemTypes = {
|
||||
PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T,
|
||||
PCB_FOOTPRINT_T,
|
||||
PCB_PAD_T,
|
||||
PCB_SHAPE_T, PCB_FP_SHAPE_T,
|
||||
PCB_TEXT_T, PCB_FP_TEXT_T, PCB_TEXTBOX_T, PCB_FP_TEXTBOX_T,
|
||||
PCB_DIMENSION_T
|
||||
};
|
||||
|
||||
static const LSET courtyards( 2, F_CrtYd, B_CrtYd );
|
||||
|
||||
forEachGeometryItem( itemTypes, LSET::AllLayersMask(),
|
||||
[&]( BOARD_ITEM* item ) -> bool
|
||||
{
|
||||
|
@ -172,18 +175,22 @@ bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::Run()
|
|||
PAD* pad = static_cast<PAD*>( item );
|
||||
|
||||
if( pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0 )
|
||||
layers |= LSET::PhysicalLayersMask();
|
||||
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();
|
||||
layers |= LSET::PhysicalLayersMask() | courtyards;
|
||||
}
|
||||
else if( item->Type() == PCB_FOOTPRINT_T )
|
||||
{
|
||||
layers = courtyards;
|
||||
}
|
||||
else if( item->IsOnLayer( Edge_Cuts ) )
|
||||
{
|
||||
layers |= LSET::PhysicalLayersMask();
|
||||
layers |= LSET::PhysicalLayersMask() | courtyards;
|
||||
}
|
||||
|
||||
for( PCB_LAYER_ID layer : layers.Seq() )
|
||||
|
@ -198,7 +205,7 @@ bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::Run()
|
|||
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE )
|
||||
|| !m_drcEngine->IsErrorLimitExceeded( DRCE_HOLE_CLEARANCE ) )
|
||||
{
|
||||
if( !reportPhase( _( "Checking mechanical clearances..." ) ) )
|
||||
if( !reportPhase( _( "Checking physical clearances..." ) ) )
|
||||
return false; // DRC cancelled
|
||||
|
||||
forEachGeometryItem( itemTypes, LSET::AllLayersMask(),
|
||||
|
@ -207,7 +214,12 @@ bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::Run()
|
|||
if( !reportProgress( ii++, count, delta ) )
|
||||
return false;
|
||||
|
||||
for( PCB_LAYER_ID layer : item->GetLayerSet().Seq() )
|
||||
LSET layers = item->GetLayerSet();
|
||||
|
||||
if( item->Type() == PCB_FOOTPRINT_T )
|
||||
layers = courtyards;
|
||||
|
||||
for( PCB_LAYER_ID layer : layers.Seq() )
|
||||
{
|
||||
std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape( layer );
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include <i18n_utility.h>
|
||||
#include <drc/drc_item.h>
|
||||
#include <geometry/shape_segment.h>
|
||||
#include <geometry/shape_simple.h>
|
||||
#include <convert_shape_list_to_polygon.h>
|
||||
#include <geometry/convex_hull.h>
|
||||
#include "fp_textbox.h"
|
||||
|
@ -2131,15 +2132,27 @@ std::shared_ptr<SHAPE> FOOTPRINT::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHI
|
|||
// 2) just the pads and "edges" (ie: non-text graphic items)
|
||||
// 3) the courtyard
|
||||
|
||||
// We'll go with (2) for now....
|
||||
// We'll go with (2) for now, unless the caller is clearly looking for (3)
|
||||
|
||||
for( PAD* pad : Pads() )
|
||||
shape->AddShape( pad->GetEffectiveShape( aLayer, aFlash )->Clone() );
|
||||
|
||||
for( BOARD_ITEM* item : GraphicalItems() )
|
||||
if( aLayer == F_CrtYd || aLayer == B_CrtYd )
|
||||
{
|
||||
if( item->Type() == PCB_FP_SHAPE_T )
|
||||
shape->AddShape( item->GetEffectiveShape( aLayer, aFlash )->Clone() );
|
||||
const SHAPE_POLY_SET& courtyard = GetPolyCourtyard( aLayer );
|
||||
|
||||
if( courtyard.OutlineCount() == 0 ) // malformed/empty polygon
|
||||
return shape;
|
||||
|
||||
shape->AddShape( new SHAPE_SIMPLE( courtyard.COutline( 0 ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
for( PAD* pad : Pads() )
|
||||
shape->AddShape( pad->GetEffectiveShape( aLayer, aFlash )->Clone() );
|
||||
|
||||
for( BOARD_ITEM* item : GraphicalItems() )
|
||||
{
|
||||
if( item->Type() == PCB_FP_SHAPE_T )
|
||||
shape->AddShape( item->GetEffectiveShape( aLayer, aFlash )->Clone() );
|
||||
}
|
||||
}
|
||||
|
||||
return shape;
|
||||
|
|
|
@ -885,14 +885,20 @@ int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent )
|
|||
{
|
||||
PCB_LAYER_ID layer = UNDEFINED_LAYER;
|
||||
|
||||
if( a->IsOnLayer( edgeLayer ) && b->IsOnLayer( active ) && IsCopperLayer( active ) )
|
||||
layer = active;
|
||||
else if( b->IsOnLayer( edgeLayer ) && a->IsOnLayer( active ) && IsCopperLayer( active ) )
|
||||
layer = active;
|
||||
else if( a->IsOnLayer( edgeLayer ) && IsCopperLayer( b->GetLayer() ) )
|
||||
layer = b->GetLayer();
|
||||
else if( b->IsOnLayer( edgeLayer ) && IsCopperLayer( a->GetLayer() ) )
|
||||
layer = a->GetLayer();
|
||||
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 )
|
||||
{
|
||||
|
@ -916,6 +922,35 @@ int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent )
|
|||
|
||||
r = m_inspectClearanceDialog->AddPage( _( "Physical Clearances" ) );
|
||||
|
||||
auto reportPhysicalClearance =
|
||||
[&]( PCB_LAYER_ID aLayer )
|
||||
{
|
||||
reportHeader( _( "Physical clearance resolution for:" ), a, b, aLayer, r );
|
||||
|
||||
constraint = drcEngine.EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, a, b, aLayer, r );
|
||||
clearance = constraint.m_Value.Min();
|
||||
|
||||
if( compileError )
|
||||
{
|
||||
reportCompileError( r );
|
||||
}
|
||||
else if( !drcEngine.HasRulesForConstraintType( PHYSICAL_CLEARANCE_CONSTRAINT ) )
|
||||
{
|
||||
r->Report( "" );
|
||||
r->Report( _( "No 'physical_clearance' constraints defined." ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
r->Report( "" );
|
||||
r->Report( wxString::Format( _( "Resolved clearance: %s." ),
|
||||
StringFromValue( units, clearance, true ) ) );
|
||||
}
|
||||
|
||||
r->Report( "" );
|
||||
r->Report( "" );
|
||||
r->Report( "" );
|
||||
};
|
||||
|
||||
if( layerIntersection.any() )
|
||||
{
|
||||
PCB_LAYER_ID layer = active;
|
||||
|
@ -923,30 +958,24 @@ int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent )
|
|||
if( !layerIntersection.test( layer ) )
|
||||
layer = layerIntersection.Seq().front();
|
||||
|
||||
reportHeader( _( "Physical clearance resolution for:" ), a, b, layer, r );
|
||||
reportPhysicalClearance( layer );
|
||||
}
|
||||
|
||||
constraint = drcEngine.EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, a, b, layer, r );
|
||||
clearance = constraint.m_Value.Min();
|
||||
if( aFP && b->IsOnLayer( Edge_Cuts ) )
|
||||
{
|
||||
if( !aFP->GetPolyCourtyard( F_CrtYd ).IsEmpty() )
|
||||
reportPhysicalClearance( F_CrtYd );
|
||||
|
||||
if( compileError )
|
||||
{
|
||||
reportCompileError( r );
|
||||
}
|
||||
else if( !drcEngine.HasRulesForConstraintType( PHYSICAL_CLEARANCE_CONSTRAINT ) )
|
||||
{
|
||||
r->Report( "" );
|
||||
r->Report( _( "No 'physical_clearance' constraints defined." ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
r->Report( "" );
|
||||
r->Report( wxString::Format( _( "Resolved clearance: %s." ),
|
||||
StringFromValue( units, clearance, true ) ) );
|
||||
}
|
||||
if( !aFP->GetPolyCourtyard( B_CrtYd ).IsEmpty() )
|
||||
reportPhysicalClearance( B_CrtYd );
|
||||
}
|
||||
else if( bFP && a->IsOnLayer( Edge_Cuts ) )
|
||||
{
|
||||
if( !bFP->GetPolyCourtyard( F_CrtYd ).IsEmpty() )
|
||||
reportPhysicalClearance( F_CrtYd );
|
||||
|
||||
r->Report( "" );
|
||||
r->Report( "" );
|
||||
r->Report( "" );
|
||||
if( !bFP->GetPolyCourtyard( B_CrtYd ).IsEmpty() )
|
||||
reportPhysicalClearance( B_CrtYd );
|
||||
}
|
||||
|
||||
if( hasHole( a ) || hasHole( b ) )
|
||||
|
|
Loading…
Reference in New Issue