Hook board edge clearance constraints up to zone filling.

Also hooks them up to the clearance resolution reporter, and makes
some general improvements to reporting.

Fixes https://gitlab.com/kicad/code/kicad/issues/5947
This commit is contained in:
Jeff Young 2020-10-12 18:29:54 +01:00
parent 32dffd27ab
commit af90642440
5 changed files with 89 additions and 80 deletions

View File

@ -641,35 +641,6 @@ int D_PAD::GetLocalClearance( wxString* aSource ) const
}
int D_PAD::GetClearance( PCB_LAYER_ID aLayer, BOARD_ITEM* aItem, wxString* aSource ) const
{
DRC_CONSTRAINT constraint;
if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine )
{
BOARD_DESIGN_SETTINGS& bds = GetBoard()->GetDesignSettings();
DRC_CONSTRAINT_TYPE_T constraintType = DRC_CONSTRAINT_TYPE_CLEARANCE;
// A PTH pad has a plated cylinder around the hole so copper clearances apply
// whether or not there's a flashed pad. Not true for NPTHs.
if( GetAttribute() == PAD_ATTRIB_NPTH && !FlashLayer( aLayer ) )
constraintType = DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE;
constraint = bds.m_DRCEngine->EvalRulesForItems( constraintType, this, aItem, aLayer );
}
if( constraint.Value().HasMin() )
{
if( aSource )
*aSource = constraint.GetName();
return constraint.Value().Min();
}
return 0;
}
// Mask margins handling:
int D_PAD::GetSolderMaskMargin() const

View File

@ -366,20 +366,6 @@ public:
double GetLocalSolderPasteMarginRatio() const { return m_localSolderPasteMarginRatio; }
void SetLocalSolderPasteMarginRatio( double aRatio ) { m_localSolderPasteMarginRatio = aRatio; }
/**
* Function GetClearance
* returns the clearance in internal units. If \a aItem is not NULL then the
* returned clearance is the greater of this object's NETCLASS clearance and
* aItem's NETCLASS clearance. If \a aItem is NULL, then this objects clearance
* is returned.
* @param aLayer the layer in question
* @param aItem is an optional BOARD_ITEM
* @param aSource [out] optionally reports the source as a user-readable string
* @return int - the clearance in internal units.
*/
int GetClearance( PCB_LAYER_ID aLayer, BOARD_ITEM* aItem = nullptr,
wxString* aSource = nullptr ) const override;
/**
* Function TransformShapeWithClearanceToPolygon
* Convert the pad shape to a closed polygon. Circles and arcs are approximated by segments.

View File

@ -565,6 +565,19 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRulesForItems( DRC_CONSTRAINT_TYPE_T aConstraintI
* kills performance when running bulk DRC tests (where aReporter is nullptr).
*/
if( aConstraintId == DRC_CONSTRAINT_TYPE_CLEARANCE )
{
// A PTH pad has a plated cylinder around the hole so copper clearances apply
// whether or not there's a flashed pad. Not true for NPTHs.
if( a->Type() == PCB_PAD_T )
{
const D_PAD* pad = static_cast<const D_PAD*>( a );
if( pad->GetAttribute() == PAD_ATTRIB_NPTH && !pad->FlashLayer( aLayer ) )
aConstraintId = DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE;
}
}
const BOARD_CONNECTED_ITEM* connectedA = dynamic_cast<const BOARD_CONNECTED_ITEM*>( a );
const BOARD_CONNECTED_ITEM* connectedB = dynamic_cast<const BOARD_CONNECTED_ITEM*>( b );
const DRC_CONSTRAINT* constraintRef = nullptr;
@ -616,16 +629,41 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRulesForItems( DRC_CONSTRAINT_TYPE_T aConstraintI
REPORT( "" )
if( aConstraintId == DRC_CONSTRAINT_TYPE_CLEARANCE
|| aConstraintId == DRC_CONSTRAINT_TYPE_SILK_CLEARANCE
|| aConstraintId == DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE
|| aConstraintId == DRC_CONSTRAINT_TYPE_COURTYARD_CLEARANCE )
if( aConstraintId == DRC_CONSTRAINT_TYPE_CLEARANCE )
{
int clearance = rcons->constraint.m_Value.Min();
REPORT( wxString::Format( _( "Checking %s; clearance: %s." ),
rcons->constraint.GetName(),
MessageTextFromValue( UNITS, clearance ) ) )
}
else if( aConstraintId == DRC_CONSTRAINT_TYPE_COURTYARD_CLEARANCE )
{
int clearance = rcons->constraint.m_Value.Min();
REPORT( wxString::Format( _( "Checking %s; courtyard clearance: %s." ),
rcons->constraint.GetName(),
MessageTextFromValue( UNITS, clearance ) ) )
}
else if( aConstraintId == DRC_CONSTRAINT_TYPE_SILK_CLEARANCE )
{
int clearance = rcons->constraint.m_Value.Min();
REPORT( wxString::Format( _( "Checking %s; silk clearance: %s." ),
rcons->constraint.GetName(),
MessageTextFromValue( UNITS, clearance ) ) )
}
else if( aConstraintId == DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE )
{
int clearance = rcons->constraint.m_Value.Min();
REPORT( wxString::Format( _( "Checking %s; hole clearance: %s." ),
rcons->constraint.GetName(),
MessageTextFromValue( UNITS, clearance ) ) )
}
else if( aConstraintId == DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE )
{
int clearance = rcons->constraint.m_Value.Min();
REPORT( wxString::Format( _( "Checking %s; edge clearance: %s." ),
rcons->constraint.GetName(),
MessageTextFromValue( UNITS, clearance ) ) )
}
else
{
REPORT( wxString::Format( _( "Checking %s." ),
@ -638,7 +676,7 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRulesForItems( DRC_CONSTRAINT_TYPE_T aConstraintI
{
REPORT( wxString::Format( _( "Rule layer \"%s\" not matched." ),
rcons->parentRule->m_LayerSource ) )
REPORT( "Rule not applied." )
REPORT( "Rule ignored." )
}
continue;
@ -663,7 +701,7 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRulesForItems( DRC_CONSTRAINT_TYPE_T aConstraintI
if( rcons->condition->EvaluateFor( a, b, aLayer, aReporter ) )
{
REPORT( implicit ? _( "Constraint applicable." )
REPORT( implicit ? _( "Constraint applied." )
: _( "Rule applied. (No further rules will be checked.)" ) )
constraintRef = &rcons->constraint;
@ -671,8 +709,8 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRulesForItems( DRC_CONSTRAINT_TYPE_T aConstraintI
}
else
{
REPORT( implicit ? _( "Membership not satisfied; constraint not applicable." )
: _( "Condition not satisfied; rule not applied." ) )
REPORT( implicit ? _( "Membership not satisfied; constraint ignored." )
: _( "Condition not satisfied; rule ignored." ) )
}
}
}

View File

@ -202,15 +202,25 @@ void PCB_INSPECTION_TOOL::reportClearance( DRC_CONSTRAINT_TYPE_T aClearanceType,
return;
}
int clearance = 0;
if( aClearanceType == DRC_CONSTRAINT_TYPE_CLEARANCE )
{
auto edgeConstraint = drcEngine.EvalRulesForItems( DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE,
aA, aB, aLayer, r );
clearance = edgeConstraint.m_Value.HasMin() ? edgeConstraint.m_Value.Min() : 0;
}
auto constraint = drcEngine.EvalRulesForItems( aClearanceType, aA, aB, aLayer, r );
if( r )
{
wxString clearance = StringFromValue( r->GetUnits(), constraint.m_Value.Min(), true );
if( constraint.m_Value.HasMin() && constraint.m_Value.Min() > clearance )
clearance = constraint.m_Value.Min();
wxString clearanceStr = StringFromValue( r->GetUnits(), clearance, true );
r->Report( "" );
r->Report( wxString::Format( _( "Clearance: %s." ), clearance ) );
}
r->Report( wxString::Format( _( "Resolved clearance: %s." ), clearanceStr ) );
}
@ -271,12 +281,6 @@ int PCB_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent )
reportClearance( DRC_CONSTRAINT_TYPE_SILK_CLEARANCE, layer, a, b, r );
}
else if( !IsCopperLayer( layer ) )
{
r->Report( wxString::Format( _( "Active layer (%s) is not a silk or copper layer. "
"No clearance defined." ),
m_frame->GetBoard()->GetLayerName( layer ) ) );
}
else if( !( a->GetLayerSet() & LSET( 2, layer, Edge_Cuts ) ).any() )
{
r->Report( wxString::Format( _( "%s not present on layer %s. No clearance defined." ),
@ -289,10 +293,6 @@ int PCB_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent )
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>" ) );
@ -320,10 +320,10 @@ int PCB_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent )
r->Report( _( "Items belong to the same net. Clearance is 0." ) );
}
}
else if( ac )
else
{
// Different nets (or second unconnected)....
reportClearance( DRC_CONSTRAINT_TYPE_CLEARANCE, layer, ac, b, r );
// Different nets (or one or both unconnected)....
reportClearance( DRC_CONSTRAINT_TYPE_CLEARANCE, layer, a, b, r );
}
}

View File

@ -719,6 +719,14 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, PCB_LA
MODULE dummymodule( m_board );
D_PAD dummypad( &dummymodule );
auto evalRulesForItems =
[&]( DRC_CONSTRAINT_TYPE_T aConstraint, const BOARD_ITEM* a, const BOARD_ITEM* b,
PCB_LAYER_ID aLayer ) -> int
{
DRC_CONSTRAINT c = bds.m_DRCEngine->EvalRulesForItems( aConstraint, a, b, aLayer );
return c.Value().HasMin() ? c.Value().Min() : 0;
};
// Add non-connected pad clearances
//
for( MODULE* module : m_board->Modules() )
@ -744,9 +752,14 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, PCB_LA
// for pads having the same netcode as the zone, the net clearance has no
// meaning so use the greater of the zone clearance and the thermal relief
if( pad->GetNetCode() > 0 && pad->GetNetCode() == aZone->GetNetCode() )
{
gap = std::max( zone_clearance, aZone->GetThermalReliefGap( pad ) );
}
else
gap = aZone->GetClearance( aLayer, pad );
{
gap = evalRulesForItems( DRC_CONSTRAINT_TYPE_CLEARANCE, aZone, pad,
aLayer );
}
addKnockout( pad, aLayer, gap, aHoles );
}
@ -766,7 +779,9 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, PCB_LA
if( track->GetBoundingBox().Intersects( zone_boundingbox ) )
{
int gap = aZone->GetClearance( aLayer, track ) + extra_margin;
int gap = evalRulesForItems( DRC_CONSTRAINT_TYPE_CLEARANCE, aZone, track, aLayer );
gap += extra_margin;
if( track->Type() == PCB_VIA_T )
{
@ -801,18 +816,16 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, PCB_LA
if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
{
PCB_LAYER_ID layer = aLayer;
bool ignoreLineWidth = false;
int gap = evalRulesForItems( DRC_CONSTRAINT_TYPE_CLEARANCE, aZone, aItem,
aLayer );
if( aItem->IsOnLayer( Edge_Cuts ) )
{
layer = Edge_Cuts;
ignoreLineWidth = true;
gap = std::max( gap, evalRulesForItems( DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE,
aZone, aItem, Edge_Cuts ) );
}
int gap = aZone->GetClearance( aLayer, aItem ) + extra_margin;
addKnockout( aItem, layer, gap, ignoreLineWidth, aHoles );
addKnockout( aItem, aLayer, gap, aItem->IsOnLayer( Edge_Cuts ), aHoles );
}
};
@ -847,7 +860,8 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, PCB_LA
}
else
{
int gap = aZone->GetClearance( aLayer, aKnockout );
int gap = evalRulesForItems( DRC_CONSTRAINT_TYPE_CLEARANCE, aZone,
aKnockout, aLayer );
if( bds.m_ZoneFillVersion == 5 )
{