Smarten up silk clearance & tented item handling.

The inspection tool will report whether or not the item is tented
(indicating in that case that any clearance will only be applied
to any hole).

The DRC test ignores tented items without a hole, and runs the
clearance test against the hole for items with a hole.

Fixes https://gitlab.com/kicad/code/kicad/issues/11954

Fixes https://gitlab.com/kicad/code/kicad/issues/11951
This commit is contained in:
Jeff Young 2022-07-07 15:27:29 -06:00
parent a16fc5b537
commit 8a9bf02b7e
8 changed files with 98 additions and 25 deletions

View File

@ -117,6 +117,11 @@ public:
return IsCopperLayer( GetLayer() ); return IsCopperLayer( GetLayer() );
} }
virtual bool IsTented() const
{
return false;
}
/** /**
* A value of wxPoint(0,0) which can be passed to the Draw() functions. * A value of wxPoint(0,0) which can be passed to the Draw() functions.
*/ */

View File

@ -2251,11 +2251,12 @@ void BOARD::ConvertBrdLayerToPolygonalContours( PCB_LAYER_ID aLayer,
footprint->TransformPadsWithClearanceToPolygon( aOutlines, aLayer, 0, maxError, footprint->TransformPadsWithClearanceToPolygon( aOutlines, aLayer, 0, maxError,
ERROR_INSIDE ); ERROR_INSIDE );
// Micro-wave footprints may have items on copper layers // Microwave footprints may have items on copper layers
footprint->TransformFPShapesWithClearanceToPolygon( aOutlines, aLayer, 0, maxError, footprint->TransformFPShapesWithClearanceToPolygon( aOutlines, aLayer, 0, maxError,
ERROR_INSIDE, ERROR_INSIDE,
true, /* include text */ true, /* include text */
true /* include shapes */ ); true, /* include shapes */
false /* include private items */ );
for( const ZONE* zone : footprint->Zones() ) for( const ZONE* zone : footprint->Zones() )
{ {

View File

@ -25,6 +25,9 @@
#include <board.h> #include <board.h>
#include <footprint.h> #include <footprint.h>
#include <pcb_shape.h> #include <pcb_shape.h>
#include <pcb_track.h>
#include <pad.h>
#include <geometry/shape_segment.h>
#include <geometry/seg.h> #include <geometry/seg.h>
#include <drc/drc_engine.h> #include <drc/drc_engine.h>
#include <drc/drc_item.h> #include <drc/drc_item.h>
@ -176,20 +179,49 @@ bool DRC_TEST_PROVIDER_SILK_CLEARANCE::Run()
[&]( const DRC_RTREE::LAYER_PAIR& aLayers, DRC_RTREE::ITEM_WITH_SHAPE* aRefItemShape, [&]( const DRC_RTREE::LAYER_PAIR& aLayers, DRC_RTREE::ITEM_WITH_SHAPE* aRefItemShape,
DRC_RTREE::ITEM_WITH_SHAPE* aTestItemShape, bool* aCollisionDetected ) -> bool DRC_RTREE::ITEM_WITH_SHAPE* aTestItemShape, bool* aCollisionDetected ) -> bool
{ {
BOARD_ITEM* aRefItem = aRefItemShape->parent; BOARD_ITEM* refItem = aRefItemShape->parent;
SHAPE* aRefShape = aRefItemShape->shape; const SHAPE* refShape = aRefItemShape->shape;
BOARD_ITEM* aTestItem = aTestItemShape->parent; BOARD_ITEM* testItem = aTestItemShape->parent;
SHAPE* aTestShape = aTestItemShape->shape; const SHAPE* testShape = aTestItemShape->shape;
std::unique_ptr<SHAPE> hole;
if( m_drcEngine->IsErrorLimitExceeded( DRCE_OVERLAPPING_SILK ) ) if( m_drcEngine->IsErrorLimitExceeded( DRCE_OVERLAPPING_SILK ) )
return false; return false;
if( isInvisibleText( aRefItem ) || isInvisibleText( aTestItem ) ) if( isInvisibleText( refItem ) || isInvisibleText( testItem ) )
return true; return true;
if( testItem->IsTented() )
{
switch( testItem->Type() )
{
case PCB_VIA_T:
{
PCB_VIA* via = static_cast<PCB_VIA*>( testItem );
hole.reset( via->GetEffectiveShape( UNDEFINED_LAYER,
FLASHING::NEVER_FLASHED )->Clone() );
testShape = hole.get();
break;
}
case PCB_PAD_T:
{
PAD* pad = static_cast<PAD*>( testItem );
if( pad->GetDrillSize().x || pad->GetDrillSize().y )
return true;
hole.reset( pad->GetEffectiveHoleShape()->Clone() );
testShape = hole.get();
break;
}
default:
return true;
}
}
DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( SILK_CLEARANCE_CONSTRAINT, DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( SILK_CLEARANCE_CONSTRAINT,
aRefItem, aTestItem, refItem, testItem,
aLayers.second ); aLayers.second );
if( constraint.IsNull() || constraint.GetSeverity() == RPT_SEVERITY_IGNORE ) if( constraint.IsNull() || constraint.GetSeverity() == RPT_SEVERITY_IGNORE )
@ -205,17 +237,17 @@ bool DRC_TEST_PROVIDER_SILK_CLEARANCE::Run()
// Graphics are often compound shapes so ignore collisions between shapes in a // Graphics are often compound shapes so ignore collisions between shapes in a
// single footprint or on the board. // single footprint or on the board.
if( aRefItem->Type() == PCB_SHAPE_T && aTestItem->Type() == PCB_SHAPE_T ) if( refItem->Type() == PCB_SHAPE_T && testItem->Type() == PCB_SHAPE_T )
{ {
return true; return true;
} }
else if( aRefItem->Type() == PCB_FP_SHAPE_T && aTestItem->Type() == PCB_FP_SHAPE_T else if( refItem->Type() == PCB_FP_SHAPE_T && testItem->Type() == PCB_FP_SHAPE_T
&& aRefItem->GetParentFootprint() == aTestItem->GetParentFootprint() ) && refItem->GetParentFootprint() == testItem->GetParentFootprint() )
{ {
return true; return true;
} }
if( aRefShape->Collide( aTestShape, minClearance, &actual, &pos ) ) if( refShape->Collide( testShape, minClearance, &actual, &pos ) )
{ {
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_OVERLAPPING_SILK ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_OVERLAPPING_SILK );
@ -231,7 +263,7 @@ bool DRC_TEST_PROVIDER_SILK_CLEARANCE::Run()
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg ); drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
} }
drcItem->SetItems( aRefItem, aTestItem ); drcItem->SetItems( refItem, testItem );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
reportViolation( drcItem, pos, aLayers.second ); reportViolation( drcItem, pos, aLayers.second );

View File

@ -2103,8 +2103,9 @@ double FOOTPRINT::CoverageRatio( const GENERAL_COLLECTOR& aCollector ) const
TransformFPShapesWithClearanceToPolygon( coveredRegion, UNDEFINED_LAYER, textMargin, TransformFPShapesWithClearanceToPolygon( coveredRegion, UNDEFINED_LAYER, textMargin,
ARC_LOW_DEF, ERROR_OUTSIDE, ARC_LOW_DEF, ERROR_OUTSIDE,
true, /* include text */ true, /* include text */
false /* include shapes */ ); false, /* include shapes */
false /* include private items */ );
for( int i = 0; i < aCollector.GetCount(); ++i ) for( int i = 0; i < aCollector.GetCount(); ++i )
{ {
@ -2557,12 +2558,16 @@ void FOOTPRINT::TransformFPShapesWithClearanceToPolygon( SHAPE_POLY_SET& aCorner
PCB_LAYER_ID aLayer, int aClearance, PCB_LAYER_ID aLayer, int aClearance,
int aError, ERROR_LOC aErrorLoc, int aError, ERROR_LOC aErrorLoc,
bool aIncludeText, bool aIncludeText,
bool aIncludeShapes ) const bool aIncludeShapes,
bool aIncludePrivateItems ) const
{ {
std::vector<FP_TEXT*> texts; // List of FP_TEXT to convert std::vector<FP_TEXT*> texts; // List of FP_TEXT to convert
for( BOARD_ITEM* item : GraphicalItems() ) for( BOARD_ITEM* item : GraphicalItems() )
{ {
if( GetPrivateLayers().test( item->GetLayer() ) && !aIncludePrivateItems )
continue;
if( item->Type() == PCB_FP_TEXT_T && aIncludeText ) if( item->Type() == PCB_FP_TEXT_T && aIncludeText )
{ {
FP_TEXT* text = static_cast<FP_TEXT*>( item ); FP_TEXT* text = static_cast<FP_TEXT*>( item );

View File

@ -417,7 +417,8 @@ public:
PCB_LAYER_ID aLayer, int aClearance, PCB_LAYER_ID aLayer, int aClearance,
int aError, ERROR_LOC aErrorLoc, int aError, ERROR_LOC aErrorLoc,
bool aIncludeText = true, bool aIncludeText = true,
bool aIncludeShapes = true ) const; bool aIncludeShapes = true,
bool aIncludePrivateItems = false ) const;
/** /**
* This function is the same as TransformGraphicShapesWithClearanceToPolygonSet * This function is the same as TransformGraphicShapesWithClearanceToPolygonSet

View File

@ -400,9 +400,9 @@ bool PCB_VIA::IsOnLayer( PCB_LAYER_ID aLayer ) const
if( !IsTented() ) if( !IsTented() )
{ {
if( m_layer == F_Mask ) if( aLayer == F_Mask )
return IsOnLayer( F_Cu ); return IsOnLayer( F_Cu );
else if( m_layer == B_Mask ) else if( aLayer == B_Mask )
return IsOnLayer( B_Cu ); return IsOnLayer( B_Cu );
} }

View File

@ -353,7 +353,7 @@ 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 IsTented() const; bool IsTented() const override;
int GetSolderMaskExpansion() const; int GetSolderMaskExpansion() const;
bool IsOnLayer( PCB_LAYER_ID aLayer ) const override; bool IsOnLayer( PCB_LAYER_ID aLayer ) const override;
@ -495,7 +495,7 @@ public:
// @copydoc BOARD_ITEM::GetEffectiveShape // @copydoc BOARD_ITEM::GetEffectiveShape
std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER, std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER,
FLASHING aFlash = FLASHING::DEFAULT ) const override; FLASHING aFlash = FLASHING::DEFAULT ) const override;
protected: protected:
wxString layerMaskDescribe() const override; wxString layerMaskDescribe() const override;

View File

@ -800,13 +800,38 @@ int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent )
} }
} }
auto isOnCorrespondingLayer=
[&]( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, wxString* aWarning )
{
if( aItem->IsOnLayer( aLayer ) )
return true;
PCB_LAYER_ID correspondingMask = IsFrontLayer( aLayer ) ? F_Mask : B_Mask;
PCB_LAYER_ID correspondingCopper = IsFrontLayer( aLayer ) ? F_Cu : B_Cu;
if( aItem->IsOnLayer( aLayer ) )
return true;
if( aItem->IsOnLayer( correspondingMask ) )
return true;
if( aItem->IsTented() && aItem->IsOnLayer( correspondingCopper ) )
{
*aWarning = wxString::Format( _( "Note: %s is tented; clearance will only be "
"applied to holes." ),
getItemDescription( aItem ) );
return true;
}
return false;
};
for( PCB_LAYER_ID layer : { F_SilkS, B_SilkS } ) for( PCB_LAYER_ID layer : { F_SilkS, B_SilkS } )
{ {
PCB_LAYER_ID correspondingMask = IsFrontLayer( layer ) ? F_Mask : B_Mask; wxString warning;
if( ( a->IsOnLayer( layer ) && b->IsOnLayer( layer ) ) if( ( a->IsOnLayer( layer ) && isOnCorrespondingLayer( b, layer, &warning ) )
|| ( a->IsOnLayer( layer ) && b->IsOnLayer( correspondingMask ) ) || ( b->IsOnLayer( layer ) && isOnCorrespondingLayer( a, layer, &warning ) ) )
|| ( b->IsOnLayer( layer ) && a->IsOnLayer( correspondingMask ) ) )
{ {
r = m_inspectClearanceDialog->AddPage( m_frame->GetBoard()->GetLayerName( layer ) ); r = m_inspectClearanceDialog->AddPage( m_frame->GetBoard()->GetLayerName( layer ) );
reportHeader( _( "Silkscreen clearance resolution for:" ), a, b, layer, r ); reportHeader( _( "Silkscreen clearance resolution for:" ), a, b, layer, r );
@ -818,6 +843,10 @@ int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent )
reportCompileError( r ); reportCompileError( r );
r->Report( "" ); r->Report( "" );
if( !warning.IsEmpty() )
r->Report( warning );
r->Report( wxString::Format( _( "Resolved clearance: %s." ), r->Report( wxString::Format( _( "Resolved clearance: %s." ),
StringFromValue( units, clearance, true ) ) ); StringFromValue( units, clearance, true ) ) );