Convert hole clearance tests from NPTH holes to all holes.
This commit is contained in:
parent
6b48825aa0
commit
a208dac8d8
|
@ -762,53 +762,6 @@ void DRC_ENGINE::RunTests( EDA_UNITS aUnits, bool aReportAllTrackErrors, bool aT
|
|||
}
|
||||
|
||||
|
||||
bool isUnflashedNPTH( const BOARD_ITEM* aItem, PCB_LAYER_ID aLayer )
|
||||
{
|
||||
if( !aItem || aItem->Type() != PCB_PAD_T )
|
||||
return false;
|
||||
|
||||
const PAD* pad = static_cast<const PAD*>( aItem );
|
||||
|
||||
if( pad->GetAttribute() != PAD_ATTRIB::NPTH )
|
||||
return false;
|
||||
|
||||
// Run a couple of quick tests to see if there's any copper
|
||||
|
||||
if( pad->GetShape() == PAD_SHAPE::CIRCLE && pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE
|
||||
&& pad->GetSizeX() <= pad->GetDrillSizeX() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if( pad->GetShape() == PAD_SHAPE::OVAL && pad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG
|
||||
&& pad->GetSizeX() <= pad->GetDrillSizeX()
|
||||
&& pad->GetSizeY() <= pad->GetDrillSizeY() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if( !pad->FlashLayer( aLayer ) )
|
||||
return true;
|
||||
|
||||
// We're out of optimizations. Do it the hard way.
|
||||
|
||||
SHAPE_POLY_SET padOutline;
|
||||
const SHAPE_SEGMENT* drillShape = pad->GetEffectiveHoleShape();
|
||||
const SEG drillSeg = drillShape->GetSeg();
|
||||
SHAPE_POLY_SET drillOutline;
|
||||
|
||||
pad->TransformShapeWithClearanceToPolygon( padOutline, aLayer, 0, ARC_HIGH_DEF,
|
||||
ERROR_LOC::ERROR_INSIDE );
|
||||
|
||||
TransformOvalToPolygon( drillOutline, (wxPoint) drillSeg.A, (wxPoint) drillSeg.B,
|
||||
drillShape->GetWidth(), ARC_HIGH_DEF, ERROR_LOC::ERROR_INSIDE );
|
||||
|
||||
padOutline.BooleanSubtract( drillOutline, SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
|
||||
|
||||
return padOutline.IsEmpty();
|
||||
}
|
||||
|
||||
|
||||
DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM* a,
|
||||
const BOARD_ITEM* b, PCB_LAYER_ID aLayer,
|
||||
REPORTER* aReporter )
|
||||
|
@ -845,7 +798,7 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
|||
REPORT( "" )
|
||||
REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
|
||||
EscapeHTML( a->GetSelectMenuText( UNITS ) ),
|
||||
EscapeHTML( REPORT_VALUE( overrideA ) ) ) )
|
||||
REPORT_VALUE( overrideA ) ) )
|
||||
}
|
||||
|
||||
if( bc && !a_is_non_copper && bc->GetLocalClearanceOverrides( nullptr ) > 0 )
|
||||
|
@ -855,34 +808,20 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
|||
REPORT( "" )
|
||||
REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
|
||||
EscapeHTML( b->GetSelectMenuText( UNITS ) ),
|
||||
EscapeHTML( REPORT_VALUE( overrideB ) ) ) )
|
||||
REPORT_VALUE( overrideB ) ) )
|
||||
}
|
||||
|
||||
if( overrideA || overrideB )
|
||||
{
|
||||
int override = std::max( overrideA, overrideB );
|
||||
|
||||
if( isUnflashedNPTH( a, aLayer ) || isUnflashedNPTH( b, aLayer ) )
|
||||
{
|
||||
if( override < m_designSettings->m_HoleClearance )
|
||||
{
|
||||
override = m_designSettings->m_HoleClearance;
|
||||
|
||||
REPORT( "" )
|
||||
REPORT( wxString::Format( _( "Board minimum hole clearance: %s." ),
|
||||
EscapeHTML( REPORT_VALUE( override ) ) ) )
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( override < m_designSettings->m_MinClearance )
|
||||
{
|
||||
override = m_designSettings->m_MinClearance;
|
||||
|
||||
REPORT( "" )
|
||||
REPORT( wxString::Format( _( "Board minimum clearance: %s." ),
|
||||
EscapeHTML( REPORT_VALUE( override ) ) ) )
|
||||
}
|
||||
REPORT_VALUE( override ) ) )
|
||||
}
|
||||
|
||||
DRC_CONSTRAINT constraint( aConstraintType, m_msg );
|
||||
|
@ -898,44 +837,73 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
|||
|
||||
REPORT( "" )
|
||||
|
||||
if( c->constraint.m_Type == CLEARANCE_CONSTRAINT )
|
||||
switch( c->constraint.m_Type )
|
||||
{
|
||||
case CLEARANCE_CONSTRAINT:
|
||||
case COURTYARD_CLEARANCE_CONSTRAINT:
|
||||
case SILK_CLEARANCE_CONSTRAINT:
|
||||
case HOLE_CLEARANCE_CONSTRAINT:
|
||||
case EDGE_CLEARANCE_CONSTRAINT:
|
||||
{
|
||||
int val = c->constraint.m_Value.Min();
|
||||
REPORT( wxString::Format( _( "Checking %s clearance: %s." ),
|
||||
EscapeHTML( c->constraint.GetName() ),
|
||||
EscapeHTML( REPORT_VALUE( val ) ) ) )
|
||||
REPORT_VALUE( val ) ) )
|
||||
break;
|
||||
}
|
||||
else if( c->constraint.m_Type == COURTYARD_CLEARANCE_CONSTRAINT )
|
||||
|
||||
case TRACK_WIDTH_CONSTRAINT:
|
||||
case ANNULAR_WIDTH_CONSTRAINT:
|
||||
case VIA_DIAMETER_CONSTRAINT:
|
||||
{
|
||||
int val = c->constraint.m_Value.Min();
|
||||
REPORT( wxString::Format( _( "Checking %s clearance: %s." ),
|
||||
EscapeHTML( c->constraint.GetName() ),
|
||||
EscapeHTML( REPORT_VALUE( val ) ) ) )
|
||||
if( aReporter )
|
||||
{
|
||||
wxString min = wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
|
||||
wxString opt = wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
|
||||
wxString max = wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
|
||||
wxString msg;
|
||||
|
||||
if( implicit )
|
||||
{
|
||||
opt = StringFromValue( UNITS, c->constraint.m_Value.Opt(), true );
|
||||
|
||||
switch( c->constraint.m_Type )
|
||||
{
|
||||
case TRACK_WIDTH_CONSTRAINT: msg = "track width"; break;
|
||||
case ANNULAR_WIDTH_CONSTRAINT: msg = "annular width"; break;
|
||||
case VIA_DIAMETER_CONSTRAINT: msg = "via diameter"; break;
|
||||
default: msg = "constraint"; break;
|
||||
}
|
||||
else if( c->constraint.m_Type == SILK_CLEARANCE_CONSTRAINT )
|
||||
{
|
||||
int val = c->constraint.m_Value.Min();
|
||||
REPORT( wxString::Format( _( "Checking %s clearance: %s." ),
|
||||
|
||||
REPORT( wxString::Format( _( "Checking %s %s: %s." ),
|
||||
EscapeHTML( c->constraint.GetName() ),
|
||||
EscapeHTML( REPORT_VALUE( val ) ) ) )
|
||||
}
|
||||
else if( c->constraint.m_Type == HOLE_CLEARANCE_CONSTRAINT )
|
||||
{
|
||||
int val = c->constraint.m_Value.Min();
|
||||
REPORT( wxString::Format( _( "Checking %s clearance: %s." ),
|
||||
EscapeHTML( c->constraint.GetName() ),
|
||||
EscapeHTML( REPORT_VALUE( val ) ) ) )
|
||||
}
|
||||
else if( c->constraint.m_Type == EDGE_CLEARANCE_CONSTRAINT )
|
||||
{
|
||||
int val = c->constraint.m_Value.Min();
|
||||
REPORT( wxString::Format( _( "Checking %s clearance: %s." ),
|
||||
EscapeHTML( c->constraint.GetName() ),
|
||||
EscapeHTML( REPORT_VALUE( val ) ) ) )
|
||||
EscapeHTML( msg ),
|
||||
opt ) )
|
||||
}
|
||||
else
|
||||
{
|
||||
REPORT( wxString::Format( _( "Checking %s." ), c->constraint.GetName() ) )
|
||||
if( c->constraint.m_Value.HasMin() )
|
||||
min = StringFromValue( UNITS, c->constraint.m_Value.Min(), true );
|
||||
|
||||
if( c->constraint.m_Value.HasOpt() )
|
||||
opt = StringFromValue( UNITS, c->constraint.m_Value.Opt(), true );
|
||||
|
||||
if( c->constraint.m_Value.HasMax() )
|
||||
max = StringFromValue( UNITS, c->constraint.m_Value.Max(), true );
|
||||
|
||||
REPORT( wxString::Format( _( "Checking %s: min %s; opt %s; max %s." ),
|
||||
EscapeHTML( c->constraint.GetName() ),
|
||||
min,
|
||||
opt,
|
||||
max ) )
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
REPORT( wxString::Format( _( "Checking %s." ),
|
||||
EscapeHTML( c->constraint.GetName() ) ) )
|
||||
}
|
||||
|
||||
if( c->constraint.m_Type == CLEARANCE_CONSTRAINT )
|
||||
|
@ -1086,17 +1054,9 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
|||
}
|
||||
};
|
||||
|
||||
DRC_CONSTRAINT_T effectiveConstraintType = aConstraintType;
|
||||
|
||||
if( aConstraintType == CLEARANCE_CONSTRAINT
|
||||
&& ( isUnflashedNPTH( a, aLayer ) || isUnflashedNPTH( b, aLayer ) ) )
|
||||
if( m_constraintMap.count( aConstraintType ) )
|
||||
{
|
||||
effectiveConstraintType = HOLE_CLEARANCE_CONSTRAINT;
|
||||
}
|
||||
|
||||
if( m_constraintMap.count( effectiveConstraintType ) )
|
||||
{
|
||||
std::vector<DRC_ENGINE_CONSTRAINT*>* ruleset = m_constraintMap[ effectiveConstraintType ];
|
||||
std::vector<DRC_ENGINE_CONSTRAINT*>* ruleset = m_constraintMap[ aConstraintType ];
|
||||
|
||||
if( aReporter )
|
||||
{
|
||||
|
@ -1134,7 +1094,7 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
|||
REPORT( "" )
|
||||
REPORT( wxString::Format( _( "Local clearance on %s; clearance: %s." ),
|
||||
EscapeHTML( a->GetSelectMenuText( UNITS ) ),
|
||||
EscapeHTML( REPORT_VALUE( localA ) ) ) )
|
||||
REPORT_VALUE( localA ) ) )
|
||||
|
||||
if( localA > clearance )
|
||||
clearance = ac->GetLocalClearance( &m_msg );
|
||||
|
@ -1145,7 +1105,7 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
|||
REPORT( "" )
|
||||
REPORT( wxString::Format( _( "Local clearance on %s; clearance: %s." ),
|
||||
EscapeHTML( b->GetSelectMenuText( UNITS ) ),
|
||||
EscapeHTML( REPORT_VALUE( localB ) ) ) )
|
||||
REPORT_VALUE( localB ) ) )
|
||||
|
||||
if( localB > clearance )
|
||||
clearance = bc->GetLocalClearance( &m_msg );
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2004-2020 KiCad Developers.
|
||||
* Copyright (C) 2004-2021 KiCad Developers.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -22,7 +22,6 @@
|
|||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <board.h>
|
||||
#include <board_design_settings.h>
|
||||
#include <footprint.h>
|
||||
#include <pcb_shape.h>
|
||||
|
@ -32,7 +31,6 @@
|
|||
|
||||
#include <geometry/seg.h>
|
||||
#include <geometry/shape_poly_set.h>
|
||||
#include <geometry/shape_rect.h>
|
||||
#include <geometry/shape_segment.h>
|
||||
|
||||
#include <drc/drc_engine.h>
|
||||
|
@ -43,9 +41,12 @@
|
|||
#include <pcb_dimension.h>
|
||||
|
||||
/*
|
||||
Copper clearance test. Checks all copper items (pads, vias, tracks, drawings, zones) for their electrical clearance.
|
||||
Copper clearance test. Checks all copper items (pads, vias, tracks, drawings, zones) for their
|
||||
electrical clearance.
|
||||
|
||||
Errors generated:
|
||||
- DRCE_CLEARANCE
|
||||
- DRCE_HOLE_CLEARANCE
|
||||
- DRCE_TRACKS_CROSSING
|
||||
- DRCE_ZONES_INTERSECT
|
||||
- DRCE_SHORTING_ITEMS
|
||||
|
@ -90,7 +91,7 @@ private:
|
|||
|
||||
void testPadClearances();
|
||||
|
||||
void testZones();
|
||||
void testZonesToZones();
|
||||
|
||||
void testItemAgainstZones( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer );
|
||||
|
||||
|
@ -239,14 +240,14 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::Run()
|
|||
if( !reportPhase( _( "Checking copper zone clearances..." ) ) )
|
||||
return false; // DRC cancelled
|
||||
|
||||
testZones();
|
||||
testZonesToZones();
|
||||
}
|
||||
else if( !m_drcEngine->IsErrorLimitExceeded( DRCE_ZONES_INTERSECT ) )
|
||||
{
|
||||
if( !reportPhase( _( "Checking zones..." ) ) )
|
||||
return false; // DRC cancelled
|
||||
|
||||
testZones();
|
||||
testZonesToZones();
|
||||
}
|
||||
|
||||
reportRuleStatistics();
|
||||
|
@ -348,7 +349,7 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackAgainstItem( PCB_TRACK* track,
|
|||
track->GetLayer() );
|
||||
clearance = constraint.GetValue().Min();
|
||||
|
||||
if( clearance >= 0 && trackShape->Collide( holeShape.get(),
|
||||
if( clearance > 0 && trackShape->Collide( holeShape.get(),
|
||||
std::max( 0, clearance - m_drcEpsilon ),
|
||||
&actual, &pos ) )
|
||||
{
|
||||
|
@ -380,9 +381,6 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZones( BOARD_ITEM* aItem
|
|||
{
|
||||
for( ZONE* zone : m_zones )
|
||||
{
|
||||
if( m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE ) )
|
||||
break;
|
||||
|
||||
if( !zone->GetLayerSet().test( aLayer ) )
|
||||
continue;
|
||||
|
||||
|
@ -394,16 +392,27 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZones( BOARD_ITEM* aItem
|
|||
|
||||
if( aItem->GetBoundingBox().Intersects( zone->GetCachedBoundingBox() ) )
|
||||
{
|
||||
auto constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, aItem, zone, aLayer );
|
||||
int clearance = constraint.GetValue().Min();
|
||||
bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
|
||||
bool testHoles = !m_drcEngine->IsErrorLimitExceeded( DRCE_HOLE_CLEARANCE );
|
||||
|
||||
if( clearance < 0 )
|
||||
continue;
|
||||
if( !testClearance && !testHoles )
|
||||
return;
|
||||
|
||||
int actual;
|
||||
VECTOR2I pos;
|
||||
DRC_RTREE* zoneTree = m_board->m_CopperZoneRTrees[ zone ].get();
|
||||
EDA_RECT itemBBox = aItem->GetBoundingBox();
|
||||
DRC_CONSTRAINT constraint;
|
||||
int clearance = -1;
|
||||
int actual;
|
||||
VECTOR2I pos;
|
||||
|
||||
if( testClearance )
|
||||
{
|
||||
constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, aItem, zone, aLayer );
|
||||
clearance = constraint.GetValue().Min();
|
||||
}
|
||||
|
||||
if( clearance >= 0 )
|
||||
{
|
||||
std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape( aLayer );
|
||||
|
||||
if( aItem->Type() == PCB_PAD_T )
|
||||
|
@ -444,6 +453,52 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZones( BOARD_ITEM* aItem
|
|||
reportViolation( drce, (wxPoint) pos );
|
||||
}
|
||||
}
|
||||
|
||||
if( testHoles && ( aItem->Type() == PCB_VIA_T || aItem->Type() == PCB_PAD_T ) )
|
||||
{
|
||||
std::unique_ptr<SHAPE_SEGMENT> holeShape;
|
||||
|
||||
if( aItem->Type() == PCB_VIA_T )
|
||||
{
|
||||
PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
|
||||
pos = via->GetPosition();
|
||||
|
||||
if( via->GetLayerSet().Contains( aLayer ) )
|
||||
holeShape.reset( new SHAPE_SEGMENT( pos, pos, via->GetDrill() ) );
|
||||
}
|
||||
else if( aItem->Type() == PCB_PAD_T )
|
||||
{
|
||||
PAD* pad = static_cast<PAD*>( aItem );
|
||||
|
||||
if( pad->GetDrillSize().x )
|
||||
holeShape.reset( new SHAPE_SEGMENT( *pad->GetEffectiveHoleShape() ) );
|
||||
}
|
||||
|
||||
if( holeShape )
|
||||
{
|
||||
constraint = m_drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, aItem, zone,
|
||||
aLayer );
|
||||
clearance = constraint.GetValue().Min();
|
||||
|
||||
if( zoneTree->QueryColliding( itemBBox, holeShape.get(), aLayer,
|
||||
clearance - m_drcEpsilon, &actual, &pos ) )
|
||||
{
|
||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
|
||||
|
||||
m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
|
||||
constraint.GetName(),
|
||||
MessageTextFromValue( userUnits(), clearance ),
|
||||
MessageTextFromValue( userUnits(), actual ) );
|
||||
|
||||
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
|
||||
drce->SetItems( aItem, zone );
|
||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drce, (wxPoint) pos );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -533,17 +588,43 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* pa
|
|||
testHoles = false;
|
||||
}
|
||||
|
||||
PAD* otherPad = nullptr;
|
||||
PCB_VIA* otherVia = nullptr;
|
||||
|
||||
if( other->Type() == PCB_PAD_T )
|
||||
otherPad = static_cast<PAD*>( other );
|
||||
|
||||
if( other->Type() == PCB_VIA_T )
|
||||
otherVia = static_cast<PCB_VIA*>( other );
|
||||
|
||||
if( !IsCopperLayer( layer ) )
|
||||
testClearance = false;
|
||||
|
||||
// A NPTH has no cylinder, but it may still have pads on some layers
|
||||
if( pad->GetAttribute() == PAD_ATTRIB::NPTH && !pad->FlashLayer( layer ) )
|
||||
testClearance = false;
|
||||
|
||||
if( !IsCopperLayer( layer ) )
|
||||
if( otherPad && otherPad->GetAttribute() == PAD_ATTRIB::NPTH && !otherPad->FlashLayer( layer ) )
|
||||
testClearance = false;
|
||||
|
||||
// Track clearances are tested in testTrackClearances()
|
||||
if( dynamic_cast<PCB_TRACK*>( other) )
|
||||
testClearance = false;
|
||||
|
||||
// Pads of the same (defined) net get a waiver on clearance and hole tests
|
||||
if( otherPad && pad->GetNetCode() && otherPad->GetNetCode() == pad->GetNetCode() )
|
||||
{
|
||||
testClearance = false;
|
||||
testHoles = false;
|
||||
}
|
||||
|
||||
if( !( pad->GetDrillSize().x > 0 )
|
||||
&& !( otherPad && otherPad->GetDrillSize().x > 0 )
|
||||
&& !( otherVia && otherVia->GetDrill() > 0 ) )
|
||||
{
|
||||
testHoles = false;
|
||||
}
|
||||
|
||||
if( !testClearance && !testShorting && !testHoles )
|
||||
return false;
|
||||
|
||||
|
@ -553,14 +634,11 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* pa
|
|||
int actual;
|
||||
VECTOR2I pos;
|
||||
|
||||
if( other->Type() == PCB_PAD_T )
|
||||
if( otherPad && pad->SameLogicalPadAs( otherPad ) )
|
||||
{
|
||||
PAD* otherPad = static_cast<PAD*>( other );
|
||||
|
||||
// If pads are equivalent (ie: from the same footprint with the same pad number)...
|
||||
if( pad->SameLogicalPadAs( otherPad ) )
|
||||
{
|
||||
// ...and have nets, then they must be the same net
|
||||
// ... and have nets...
|
||||
// then they must be the same net
|
||||
if( pad->GetNetCode() && otherPad->GetNetCode()
|
||||
&& pad->GetNetCode() != otherPad->GetNetCode()
|
||||
&& testShorting )
|
||||
|
@ -580,62 +658,6 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* pa
|
|||
return true;
|
||||
}
|
||||
|
||||
if( testHoles && pad->FlashLayer( layer ) && otherPad->GetDrillSize().x )
|
||||
{
|
||||
constraint = m_drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, pad, otherPad, layer );
|
||||
clearance = constraint.GetValue().Min();
|
||||
|
||||
if( clearance >= 0 && padShape->Collide( otherPad->GetEffectiveHoleShape(),
|
||||
std::max( 0, clearance - m_drcEpsilon ),
|
||||
&actual, &pos ) )
|
||||
{
|
||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
|
||||
|
||||
m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
|
||||
constraint.GetName(),
|
||||
MessageTextFromValue( userUnits(), clearance ),
|
||||
MessageTextFromValue( userUnits(), actual ) );
|
||||
|
||||
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
|
||||
drce->SetItems( pad, other );
|
||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drce, (wxPoint) pos );
|
||||
}
|
||||
}
|
||||
|
||||
if( testHoles && otherPad->FlashLayer( layer ) && pad->GetDrillSize().x )
|
||||
{
|
||||
constraint = m_drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, pad, otherPad, layer );
|
||||
clearance = constraint.GetValue().Min();
|
||||
|
||||
if( clearance >= 0 && otherShape->Collide( pad->GetEffectiveHoleShape(),
|
||||
std::max( 0, clearance - m_drcEpsilon ),
|
||||
&actual, &pos ) )
|
||||
{
|
||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
|
||||
|
||||
m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
|
||||
constraint.GetName(),
|
||||
MessageTextFromValue( userUnits(), clearance ),
|
||||
MessageTextFromValue( userUnits(), actual ) );
|
||||
|
||||
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
|
||||
drce->SetItems( pad, other );
|
||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drce, (wxPoint) pos );
|
||||
}
|
||||
}
|
||||
|
||||
// Pads of the same (defined) net get a waiver on clearance tests
|
||||
if( pad->GetNetCode() && otherPad->GetNetCode() == pad->GetNetCode() )
|
||||
testClearance = false;
|
||||
|
||||
if( otherPad->GetAttribute() == PAD_ATTRIB::NPTH && !otherPad->FlashLayer( layer ) )
|
||||
testClearance = false;
|
||||
}
|
||||
|
||||
if( testClearance )
|
||||
{
|
||||
constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, pad, other, layer );
|
||||
|
@ -656,6 +678,81 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* pa
|
|||
drce->SetItems( pad, other );
|
||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drce, (wxPoint) pos );
|
||||
testHoles = false; // No need for multiple violations
|
||||
}
|
||||
}
|
||||
|
||||
if( testHoles )
|
||||
{
|
||||
constraint = m_drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, pad, other, layer );
|
||||
clearance = constraint.GetValue().Min();
|
||||
}
|
||||
|
||||
if( testHoles && otherPad && pad->FlashLayer( layer ) && otherPad->GetDrillSize().x )
|
||||
{
|
||||
if( clearance > 0 && padShape->Collide( otherPad->GetEffectiveHoleShape(),
|
||||
std::max( 0, clearance - m_drcEpsilon ),
|
||||
&actual, &pos ) )
|
||||
{
|
||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
|
||||
|
||||
m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
|
||||
constraint.GetName(),
|
||||
MessageTextFromValue( userUnits(), clearance ),
|
||||
MessageTextFromValue( userUnits(), actual ) );
|
||||
|
||||
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
|
||||
drce->SetItems( pad, other );
|
||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drce, (wxPoint) pos );
|
||||
testHoles = false; // No need for multiple violations
|
||||
}
|
||||
}
|
||||
|
||||
if( testHoles && otherPad && otherPad->FlashLayer( layer ) && pad->GetDrillSize().x )
|
||||
{
|
||||
if( clearance >= 0 && otherShape->Collide( pad->GetEffectiveHoleShape(),
|
||||
std::max( 0, clearance - m_drcEpsilon ),
|
||||
&actual, &pos ) )
|
||||
{
|
||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
|
||||
|
||||
m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
|
||||
constraint.GetName(),
|
||||
MessageTextFromValue( userUnits(), clearance ),
|
||||
MessageTextFromValue( userUnits(), actual ) );
|
||||
|
||||
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
|
||||
drce->SetItems( pad, other );
|
||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drce, (wxPoint) pos );
|
||||
testHoles = false; // No need for multiple violations
|
||||
}
|
||||
}
|
||||
|
||||
if( testHoles && otherVia && otherVia->IsOnLayer( layer ) )
|
||||
{
|
||||
pos = otherVia->GetPosition();
|
||||
otherShape.reset( new SHAPE_SEGMENT( pos, pos, otherVia->GetDrill() ) );
|
||||
|
||||
if( clearance > 0 && padShape->Collide( otherShape.get(),
|
||||
std::max( 0, clearance - m_drcEpsilon ),
|
||||
&actual, &pos ) )
|
||||
{
|
||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
|
||||
|
||||
m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
|
||||
constraint.GetName(),
|
||||
MessageTextFromValue( userUnits(), clearance ),
|
||||
MessageTextFromValue( userUnits(), actual ) );
|
||||
|
||||
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
|
||||
drce->SetItems( pad, otherVia );
|
||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drce, (wxPoint) pos );
|
||||
}
|
||||
}
|
||||
|
@ -725,7 +822,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( )
|
|||
}
|
||||
|
||||
|
||||
void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZones()
|
||||
void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
|
||||
{
|
||||
const int delta = 50; // This is the number of tests between 2 calls to the progress bar
|
||||
|
||||
|
|
|
@ -540,8 +540,7 @@ bool PCB_VIA::FlashLayer( int aLayer ) const
|
|||
if( m_keepTopBottomLayer && ( aLayer == m_layer || aLayer == m_bottomLayer ) )
|
||||
return true;
|
||||
|
||||
return board->GetConnectivity()->IsConnectedOnLayer( this, static_cast<int>( aLayer ),
|
||||
types );
|
||||
return board->GetConnectivity()->IsConnectedOnLayer( this, static_cast<int>( aLayer ), types );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1031,9 +1030,18 @@ std::shared_ptr<SHAPE> PCB_TRACK::GetEffectiveShape( PCB_LAYER_ID aLayer ) const
|
|||
std::shared_ptr<SHAPE> PCB_VIA::GetEffectiveShape( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
if( FlashLayer( aLayer ) )
|
||||
{
|
||||
return std::make_shared<SHAPE_CIRCLE>( m_Start, m_Width / 2 );
|
||||
}
|
||||
else
|
||||
return std::make_shared<SHAPE_CIRCLE>( m_Start, GetDrillValue() / 2 );
|
||||
{
|
||||
int radius = GetDrillValue() / 2;
|
||||
|
||||
if( GetBoard() )
|
||||
radius += GetBoard()->GetDesignSettings().GetHolePlatingThickness();
|
||||
|
||||
return std::make_shared<SHAPE_CIRCLE>( m_Start, radius );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -527,6 +527,33 @@ int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent )
|
|||
}
|
||||
|
||||
|
||||
wxString reportMin( EDA_UNITS aUnits, DRC_CONSTRAINT& aConstraint )
|
||||
{
|
||||
if( aConstraint.m_Value.HasMin() )
|
||||
return StringFromValue( aUnits, aConstraint.m_Value.Min(), true );
|
||||
else
|
||||
return wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
|
||||
}
|
||||
|
||||
|
||||
wxString reportOpt( EDA_UNITS aUnits, DRC_CONSTRAINT& aConstraint )
|
||||
{
|
||||
if( aConstraint.m_Value.HasOpt() )
|
||||
return StringFromValue( aUnits, aConstraint.m_Value.Opt(), true );
|
||||
else
|
||||
return wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
|
||||
}
|
||||
|
||||
|
||||
wxString reportMax( EDA_UNITS aUnits, DRC_CONSTRAINT& aConstraint )
|
||||
{
|
||||
if( aConstraint.m_Value.HasMax() )
|
||||
return StringFromValue( aUnits, aConstraint.m_Value.Max(), true );
|
||||
else
|
||||
return wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
|
||||
}
|
||||
|
||||
|
||||
int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
|
||||
|
@ -600,19 +627,11 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
|
|||
auto constraint = drcEngine.EvalRules( TRACK_WIDTH_CONSTRAINT, item, nullptr,
|
||||
item->GetLayer(), r );
|
||||
|
||||
wxString min = _( "undefined" );
|
||||
wxString max = _( "undefined" );
|
||||
|
||||
if( constraint.m_Value.HasMin() )
|
||||
min = StringFromValue( r->GetUnits(), constraint.m_Value.Min(), true );
|
||||
|
||||
if( constraint.m_Value.HasMax() )
|
||||
max = StringFromValue( r->GetUnits(), constraint.m_Value.Max(), true );
|
||||
|
||||
r->Report( "" );
|
||||
r->Report( wxString::Format( _( "Width constraints: min %s max %s." ),
|
||||
min,
|
||||
max ) );
|
||||
r->Report( wxString::Format( _( "Width constraints: min %s; opt %s; max %s." ),
|
||||
reportMin( r->GetUnits(), constraint ),
|
||||
reportOpt( r->GetUnits(), constraint ),
|
||||
reportMax( r->GetUnits(), constraint ) ) );
|
||||
}
|
||||
|
||||
r->Flush();
|
||||
|
@ -638,19 +657,11 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
|
|||
auto constraint = drcEngine.EvalRules( VIA_DIAMETER_CONSTRAINT, item, nullptr,
|
||||
UNDEFINED_LAYER, r );
|
||||
|
||||
wxString min = _( "undefined" );
|
||||
wxString max = _( "undefined" );
|
||||
|
||||
if( constraint.m_Value.HasMin() )
|
||||
min = StringFromValue( r->GetUnits(), constraint.m_Value.Min(), true );
|
||||
|
||||
if( constraint.m_Value.HasMax() )
|
||||
max = StringFromValue( r->GetUnits(), constraint.m_Value.Max(), true );
|
||||
|
||||
r->Report( "" );
|
||||
r->Report( wxString::Format( _( "Diameter constraints: min %s max %s." ),
|
||||
min,
|
||||
max ) );
|
||||
r->Report( wxString::Format( _( "Diameter constraints: min %s; opt %s; max %s." ),
|
||||
reportMin( r->GetUnits(), constraint ),
|
||||
reportOpt( r->GetUnits(), constraint ),
|
||||
reportMax( r->GetUnits(), constraint ) ) );
|
||||
}
|
||||
|
||||
r->Flush();
|
||||
|
@ -673,19 +684,11 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
|
|||
auto constraint = drcEngine.EvalRules( ANNULAR_WIDTH_CONSTRAINT, item, nullptr,
|
||||
UNDEFINED_LAYER, r );
|
||||
|
||||
wxString min = _( "undefined" );
|
||||
wxString max = _( "undefined" );
|
||||
|
||||
if( constraint.m_Value.HasMin() )
|
||||
min = StringFromValue( r->GetUnits(), constraint.m_Value.Min(), true );
|
||||
|
||||
if( constraint.m_Value.HasMax() )
|
||||
max = StringFromValue( r->GetUnits(), constraint.m_Value.Max(), true );
|
||||
|
||||
r->Report( "" );
|
||||
r->Report( wxString::Format( _( "Annular width constraints: min %s max %s." ),
|
||||
min,
|
||||
max ) );
|
||||
r->Report( wxString::Format( _( "Annular width constraints: min %s; opt %s; max %s." ),
|
||||
reportMin( r->GetUnits(), constraint ),
|
||||
reportOpt( r->GetUnits(), constraint ),
|
||||
reportMax( r->GetUnits(), constraint ) ) );
|
||||
}
|
||||
|
||||
r->Flush();
|
||||
|
|
|
@ -569,6 +569,20 @@ void ZONE_FILLER::addKnockout( PAD* aPad, PCB_LAYER_ID aLayer, int aGap, SHAPE_P
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a knockout for a pad's hole.
|
||||
*/
|
||||
void ZONE_FILLER::addHoleKnockout( PAD* aPad, int aGap, SHAPE_POLY_SET& aHoles )
|
||||
{
|
||||
// Note: drill size represents finish size, which means the actual hole size is the plating
|
||||
// thickness larger.
|
||||
if( aPad->GetAttribute() == PAD_ATTRIB::PTH )
|
||||
aGap += aPad->GetBoard()->GetDesignSettings().GetHolePlatingThickness();
|
||||
|
||||
aPad->TransformHoleWithClearanceToPolygon( aHoles, aGap, m_maxError, ERROR_OUTSIDE );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a knockout for a graphic item. The knockout is 'aGap' larger than the item (which
|
||||
* might be either the electrical clearance or the board edge clearance).
|
||||
|
@ -691,34 +705,36 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLa
|
|||
{
|
||||
if( aPad->GetBoundingBox().Intersects( zone_boundingbox ) )
|
||||
{
|
||||
int gap;
|
||||
int gap = 0;
|
||||
bool knockoutHoleClearance = true;
|
||||
|
||||
// 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( aPad->GetNetCode() > 0 && aPad->GetNetCode() == aZone->GetNetCode() )
|
||||
gap = std::max( zone_clearance, aZone->GetThermalReliefGap( aPad ) );
|
||||
else
|
||||
gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aPad, aLayer );
|
||||
|
||||
gap += extra_margin;
|
||||
|
||||
// If the pad isn't on the current layer but has a hole, knock out the hole.
|
||||
if( !aPad->FlashLayer( aLayer ) )
|
||||
{
|
||||
if( aPad->GetDrillSize().x == 0 && aPad->GetDrillSize().y == 0 )
|
||||
return;
|
||||
|
||||
// Note: drill size represents finish size, which means the actual hole
|
||||
// size is the plating thickness larger.
|
||||
if( aPad->GetAttribute() == PAD_ATTRIB::PTH )
|
||||
gap += aPad->GetBoard()->GetDesignSettings().GetHolePlatingThickness();
|
||||
|
||||
aPad->TransformHoleWithClearanceToPolygon( aHoles, gap, m_maxError,
|
||||
ERROR_OUTSIDE );
|
||||
// For pads having the same netcode as the zone, the net and hole
|
||||
// clearances have no meanings.
|
||||
// So just knock out the greater of the zone's local clearance and
|
||||
// thermal relief.
|
||||
gap = std::max( zone_clearance, aZone->GetThermalReliefGap( aPad ) );
|
||||
knockoutHoleClearance = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aPad, aLayer );
|
||||
}
|
||||
|
||||
gap += extra_margin;
|
||||
|
||||
if( aPad->FlashLayer( aLayer ) )
|
||||
addKnockout( aPad, aLayer, gap, aHoles );
|
||||
else if( aPad->GetDrillSize().x > 0 )
|
||||
addHoleKnockout( aPad, gap, aHoles );
|
||||
|
||||
if( knockoutHoleClearance && aPad->GetDrillSize().x > 0 )
|
||||
{
|
||||
gap = evalRulesForItems( HOLE_CLEARANCE_CONSTRAINT, aZone, aPad, aLayer );
|
||||
gap += extra_margin;
|
||||
|
||||
addHoleKnockout( aPad, gap, aHoles );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -746,29 +762,50 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLa
|
|||
{
|
||||
if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
|
||||
{
|
||||
int gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aTrack, aLayer );
|
||||
|
||||
gap += extra_margin;
|
||||
|
||||
if( aTrack->Type() == PCB_VIA_T )
|
||||
{
|
||||
PCB_VIA* via = static_cast<PCB_VIA*>( aTrack );
|
||||
int gap = 0;
|
||||
bool checkHoleClearance = true;
|
||||
|
||||
if( !via->FlashLayer( aLayer ) && via->GetNetCode() != aZone->GetNetCode() )
|
||||
if( via->GetNetCode() > 0 && via->GetNetCode() == aZone->GetNetCode() )
|
||||
{
|
||||
// For pads having the same netcode as the zone, the net and hole
|
||||
// clearances have no meanings.
|
||||
// So just knock out the zone's local clearance.
|
||||
gap = zone_clearance;
|
||||
checkHoleClearance = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aTrack, aLayer );
|
||||
}
|
||||
|
||||
if( via->FlashLayer( aLayer ) )
|
||||
{
|
||||
via->TransformShapeWithClearanceToPolygon( aHoles, aLayer,
|
||||
gap + extra_margin,
|
||||
m_maxError, ERROR_OUTSIDE );
|
||||
}
|
||||
|
||||
if( checkHoleClearance )
|
||||
{
|
||||
gap = std::max( gap, evalRulesForItems( HOLE_CLEARANCE_CONSTRAINT,
|
||||
aZone, via, aLayer ) );
|
||||
}
|
||||
|
||||
int radius = via->GetDrillValue() / 2 + bds.GetHolePlatingThickness();
|
||||
TransformCircleToPolygon( aHoles, via->GetPosition(), radius + gap,
|
||||
|
||||
TransformCircleToPolygon( aHoles, via->GetPosition(),
|
||||
radius + gap + extra_margin,
|
||||
m_maxError, ERROR_OUTSIDE );
|
||||
}
|
||||
else
|
||||
{
|
||||
via->TransformShapeWithClearanceToPolygon( aHoles, aLayer, gap,
|
||||
m_maxError, ERROR_OUTSIDE );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aTrack->TransformShapeWithClearanceToPolygon( aHoles, aLayer, gap,
|
||||
int gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aTrack, aLayer );
|
||||
|
||||
aTrack->TransformShapeWithClearanceToPolygon( aHoles, aLayer,
|
||||
gap + extra_margin,
|
||||
m_maxError, ERROR_OUTSIDE );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,8 @@ private:
|
|||
void addKnockout( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, int aGap, bool aIgnoreLineWidth,
|
||||
SHAPE_POLY_SET& aHoles );
|
||||
|
||||
void addHoleKnockout( PAD* aPad, int aGap, SHAPE_POLY_SET& aHoles );
|
||||
|
||||
void knockoutThermalReliefs( const ZONE* aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET& aFill );
|
||||
|
||||
void buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLayer,
|
||||
|
|
|
@ -48,7 +48,13 @@
|
|||
"min_clearance": 0.508
|
||||
}
|
||||
},
|
||||
"diff_pair_dimensions": [],
|
||||
"diff_pair_dimensions": [
|
||||
{
|
||||
"gap": 0.0,
|
||||
"via_gap": 0.0,
|
||||
"width": 0.0
|
||||
}
|
||||
],
|
||||
"drc_exclusions": [],
|
||||
"meta": {
|
||||
"version": 2
|
||||
|
@ -108,8 +114,15 @@
|
|||
"min_via_diameter": 0.39999999999999997,
|
||||
"use_height_for_length_calcs": true
|
||||
},
|
||||
"track_widths": [],
|
||||
"via_dimensions": [],
|
||||
"track_widths": [
|
||||
0.0
|
||||
],
|
||||
"via_dimensions": [
|
||||
{
|
||||
"diameter": 0.0,
|
||||
"drill": 0.0
|
||||
}
|
||||
],
|
||||
"zones_allow_external_fillets": false,
|
||||
"zones_use_no_outline": true
|
||||
},
|
||||
|
|
|
@ -106,7 +106,7 @@ BOOST_FIXTURE_TEST_CASE( DRCFalseNegativeRegressions, DRC_REGRESSION_TEST_FIXTUR
|
|||
{ "issue2528", 1 },
|
||||
{ "issue5750", 4 },
|
||||
{ "issue5854", 3 },
|
||||
{ "issue6879", 7 },
|
||||
{ "issue6879", 6 },
|
||||
{ "issue6945", 2 },
|
||||
{ "issue7241", 1 },
|
||||
{ "issue7267", 4 },
|
||||
|
|
Loading…
Reference in New Issue