ADDED allow physical_clearance between courtyards & zone fills.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/6966
This commit is contained in:
Jeff Young 2024-05-01 13:07:53 +01:00
parent 58ddffe3dd
commit 6b797420d5
5 changed files with 58 additions and 29 deletions

View File

@ -1251,6 +1251,9 @@ int BOARD_DESIGN_SETTINGS::GetBiggestClearanceValue() const
m_DRCEngine->QueryWorstConstraint( CLEARANCE_CONSTRAINT, constraint );
biggest = std::max( biggest, constraint.Value().Min() );
m_DRCEngine->QueryWorstConstraint( PHYSICAL_CLEARANCE_CONSTRAINT, constraint );
biggest = std::max( biggest, constraint.Value().Min() );
m_DRCEngine->QueryWorstConstraint( HOLE_CLEARANCE_CONSTRAINT, constraint );
biggest = std::max( biggest, constraint.Value().Min() );

View File

@ -263,6 +263,11 @@ For the latter use a `(layer "layer_name")` clause in the rule.
(constraint thermal_spoke_width (min 12mil))
(condition "A.Name == 'zone_GND' || A.Name == 'zone_PWR'"))
# Prevent copper fills under the courtyards of capacitors
(rule no_copper_under_caps
(constraint physical_clearance (min 0mm))
(condition "A.Type == 'Zone' && B.Reference == 'C*'"))
# Prevent solder wicking from SMD pads
(rule holes_in_pads

View File

@ -717,34 +717,25 @@ int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent )
}
// a or b could be null after group tests above.
wxCHECK( a && b, 0 );
if( !a || !b )
return 0;
auto checkFootprint =
[&]( FOOTPRINT* footprint ) -> BOARD_ITEM*
{
if( footprint->Pads().empty() )
{
m_frame->ShowInfoBarError( _( "Cannot generate clearance report on footprint "
"with no pads." ) );
return nullptr;
}
PAD* foundPad = nullptr;
for( PAD* pad : footprint->Pads() )
{
if( !foundPad || pad->SameLogicalPadAs( foundPad ) )
{
foundPad = pad;
}
else
{
m_frame->ShowInfoBarError( _( "Cannot generate clearance report on footprint "
"with multiple pads. Select a single pad." ) );
return nullptr;
}
return footprint;
}
if( !foundPad )
return footprint;
return foundPad;
};
@ -755,7 +746,8 @@ int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent )
b = checkFootprint( static_cast<FOOTPRINT*>( b ) );
// a or b could be null after footprint tests above.
wxCHECK( a && b, 0 );
if( !a || !b )
return 0;
DIALOG_BOOK_REPORTER* dialog = m_frame->GetInspectClearanceDialog();

View File

@ -979,7 +979,7 @@ void ZONE_FILLER::knockoutThermalReliefs( const ZONE* aZone, PCB_LAYER_ID aLayer
* not connected to it.
*/
void ZONE_FILLER::buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLayer,
const std::vector<PAD*> aNoConnectionPads,
const std::vector<PAD*>& aNoConnectionPads,
SHAPE_POLY_SET& aHoles )
{
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
@ -1006,6 +1006,10 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLa
PCB_LAYER_ID aEvalLayer ) -> int
{
DRC_CONSTRAINT c = bds.m_DRCEngine->EvalRules( aConstraint, a, b, aEvalLayer );
if( c.IsNull() )
return -1;
else
return c.GetValue().Min();
};
@ -1026,7 +1030,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLa
aZone, aPad, aLayer ) );
}
if( flashLayer && gap > 0 )
if( flashLayer && gap >= 0 )
addKnockout( aPad, aLayer, gap + extra_margin, aHoles );
if( hasHole )
@ -1041,7 +1045,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLa
gap = std::max( gap, evalRulesForItems( HOLE_CLEARANCE_CONSTRAINT,
aZone, aPad, aLayer ) );
if( gap > 0 )
if( gap >= 0 )
addHoleKnockout( aPad, gap + extra_margin, aHoles );
}
};
@ -1102,7 +1106,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLa
aZone, via, aLayer ) );
}
if( gap > 0 )
if( gap >= 0 )
{
int radius = via->GetDrillValue() / 2;
@ -1113,7 +1117,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLa
}
else
{
if( gap > 0 )
if( gap >= 0 )
{
aTrack->TransformShapeToPolygon( aHoles, aLayer, gap + extra_margin,
m_maxError, ERROR_OUTSIDE );
@ -1176,14 +1180,39 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLa
aZone, aItem, aLayer ) );
}
if( gap > 0 )
addKnockout( aItem, aLayer, gap + extra_margin, ignoreLineWidths, aHoles );
if( gap >= 0 )
{
gap += extra_margin;
addKnockout( aItem, aLayer, gap, ignoreLineWidths, aHoles );
}
}
}
};
auto knockoutCourtyardClearance =
[&]( FOOTPRINT* aFootprint )
{
if( aFootprint->GetBoundingBox().Intersects( zone_boundingbox ) )
{
int gap = evalRulesForItems( PHYSICAL_CLEARANCE_CONSTRAINT, aZone,
aFootprint, aLayer );
if( gap == 0 )
{
aHoles.Append( aFootprint->GetCourtyard( aLayer ) );
}
else if( gap > 0 )
{
SHAPE_POLY_SET hole = aFootprint->GetCourtyard( aLayer );
hole.Inflate( gap, CORNER_STRATEGY::ROUND_ALL_CORNERS, m_maxError );
aHoles.Append( hole );
}
}
};
for( FOOTPRINT* footprint : m_board->Footprints() )
{
knockoutCourtyardClearance( footprint );
knockoutGraphicClearance( &footprint->Reference() );
knockoutGraphicClearance( &footprint->Value() );
@ -1273,11 +1302,11 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLa
}
else
{
int gap = evalRulesForItems( PHYSICAL_CLEARANCE_CONSTRAINT, aZone,
aKnockout, aLayer );
int gap = std::max( 0, evalRulesForItems( PHYSICAL_CLEARANCE_CONSTRAINT,
aZone, aKnockout, aLayer ) );
gap = std::max( gap, evalRulesForItems( CLEARANCE_CONSTRAINT, aZone,
aKnockout, aLayer ) );
gap = std::max( gap, evalRulesForItems( CLEARANCE_CONSTRAINT,
aZone, aKnockout, aLayer ) );
SHAPE_POLY_SET poly;
aKnockout->TransformShapeToPolygon( poly, aLayer, gap + extra_margin,

View File

@ -73,7 +73,7 @@ private:
std::vector<PAD*>& aNoConnectionPads );
void buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLayer,
const std::vector<PAD*> aNoConnectionPads,
const std::vector<PAD*>& aNoConnectionPads,
SHAPE_POLY_SET& aHoles );
void subtractHigherPriorityZones( const ZONE* aZone, PCB_LAYER_ID aLayer,