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:
parent
a16fc5b537
commit
8a9bf02b7e
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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() )
|
||||||
{
|
{
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 ) ) );
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue