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,
|
DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM* a,
|
||||||
const BOARD_ITEM* b, PCB_LAYER_ID aLayer,
|
const BOARD_ITEM* b, PCB_LAYER_ID aLayer,
|
||||||
REPORTER* aReporter )
|
REPORTER* aReporter )
|
||||||
|
@ -845,7 +798,7 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
||||||
REPORT( "" )
|
REPORT( "" )
|
||||||
REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
|
REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
|
||||||
EscapeHTML( a->GetSelectMenuText( UNITS ) ),
|
EscapeHTML( a->GetSelectMenuText( UNITS ) ),
|
||||||
EscapeHTML( REPORT_VALUE( overrideA ) ) ) )
|
REPORT_VALUE( overrideA ) ) )
|
||||||
}
|
}
|
||||||
|
|
||||||
if( bc && !a_is_non_copper && bc->GetLocalClearanceOverrides( nullptr ) > 0 )
|
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( "" )
|
||||||
REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
|
REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
|
||||||
EscapeHTML( b->GetSelectMenuText( UNITS ) ),
|
EscapeHTML( b->GetSelectMenuText( UNITS ) ),
|
||||||
EscapeHTML( REPORT_VALUE( overrideB ) ) ) )
|
REPORT_VALUE( overrideB ) ) )
|
||||||
}
|
}
|
||||||
|
|
||||||
if( overrideA || overrideB )
|
if( overrideA || overrideB )
|
||||||
{
|
{
|
||||||
int override = std::max( overrideA, overrideB );
|
int override = std::max( overrideA, overrideB );
|
||||||
|
|
||||||
if( isUnflashedNPTH( a, aLayer ) || isUnflashedNPTH( b, aLayer ) )
|
if( override < m_designSettings->m_MinClearance )
|
||||||
{
|
{
|
||||||
if( override < m_designSettings->m_HoleClearance )
|
override = m_designSettings->m_MinClearance;
|
||||||
{
|
|
||||||
override = m_designSettings->m_HoleClearance;
|
|
||||||
|
|
||||||
REPORT( "" )
|
REPORT( "" )
|
||||||
REPORT( wxString::Format( _( "Board minimum hole clearance: %s." ),
|
REPORT( wxString::Format( _( "Board minimum clearance: %s." ),
|
||||||
EscapeHTML( REPORT_VALUE( override ) ) ) )
|
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 ) ) ) )
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DRC_CONSTRAINT constraint( aConstraintType, m_msg );
|
DRC_CONSTRAINT constraint( aConstraintType, m_msg );
|
||||||
|
@ -898,44 +837,73 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
||||||
|
|
||||||
REPORT( "" )
|
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();
|
int val = c->constraint.m_Value.Min();
|
||||||
REPORT( wxString::Format( _( "Checking %s clearance: %s." ),
|
REPORT( wxString::Format( _( "Checking %s clearance: %s." ),
|
||||||
EscapeHTML( c->constraint.GetName() ),
|
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();
|
if( aReporter )
|
||||||
REPORT( wxString::Format( _( "Checking %s clearance: %s." ),
|
{
|
||||||
EscapeHTML( c->constraint.GetName() ),
|
wxString min = wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
|
||||||
EscapeHTML( REPORT_VALUE( val ) ) ) )
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
REPORT( wxString::Format( _( "Checking %s %s: %s." ),
|
||||||
|
EscapeHTML( c->constraint.GetName() ),
|
||||||
|
EscapeHTML( msg ),
|
||||||
|
opt ) )
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
else if( c->constraint.m_Type == SILK_CLEARANCE_CONSTRAINT )
|
|
||||||
{
|
default:
|
||||||
int val = c->constraint.m_Value.Min();
|
REPORT( wxString::Format( _( "Checking %s." ),
|
||||||
REPORT( wxString::Format( _( "Checking %s clearance: %s." ),
|
EscapeHTML( c->constraint.GetName() ) ) )
|
||||||
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 ) ) ) )
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
REPORT( wxString::Format( _( "Checking %s." ), c->constraint.GetName() ) )
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( c->constraint.m_Type == CLEARANCE_CONSTRAINT )
|
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( m_constraintMap.count( aConstraintType ) )
|
||||||
|
|
||||||
if( aConstraintType == CLEARANCE_CONSTRAINT
|
|
||||||
&& ( isUnflashedNPTH( a, aLayer ) || isUnflashedNPTH( b, aLayer ) ) )
|
|
||||||
{
|
{
|
||||||
effectiveConstraintType = HOLE_CLEARANCE_CONSTRAINT;
|
std::vector<DRC_ENGINE_CONSTRAINT*>* ruleset = m_constraintMap[ aConstraintType ];
|
||||||
}
|
|
||||||
|
|
||||||
if( m_constraintMap.count( effectiveConstraintType ) )
|
|
||||||
{
|
|
||||||
std::vector<DRC_ENGINE_CONSTRAINT*>* ruleset = m_constraintMap[ effectiveConstraintType ];
|
|
||||||
|
|
||||||
if( aReporter )
|
if( aReporter )
|
||||||
{
|
{
|
||||||
|
@ -1134,7 +1094,7 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
||||||
REPORT( "" )
|
REPORT( "" )
|
||||||
REPORT( wxString::Format( _( "Local clearance on %s; clearance: %s." ),
|
REPORT( wxString::Format( _( "Local clearance on %s; clearance: %s." ),
|
||||||
EscapeHTML( a->GetSelectMenuText( UNITS ) ),
|
EscapeHTML( a->GetSelectMenuText( UNITS ) ),
|
||||||
EscapeHTML( REPORT_VALUE( localA ) ) ) )
|
REPORT_VALUE( localA ) ) )
|
||||||
|
|
||||||
if( localA > clearance )
|
if( localA > clearance )
|
||||||
clearance = ac->GetLocalClearance( &m_msg );
|
clearance = ac->GetLocalClearance( &m_msg );
|
||||||
|
@ -1145,7 +1105,7 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
||||||
REPORT( "" )
|
REPORT( "" )
|
||||||
REPORT( wxString::Format( _( "Local clearance on %s; clearance: %s." ),
|
REPORT( wxString::Format( _( "Local clearance on %s; clearance: %s." ),
|
||||||
EscapeHTML( b->GetSelectMenuText( UNITS ) ),
|
EscapeHTML( b->GetSelectMenuText( UNITS ) ),
|
||||||
EscapeHTML( REPORT_VALUE( localB ) ) ) )
|
REPORT_VALUE( localB ) ) )
|
||||||
|
|
||||||
if( localB > clearance )
|
if( localB > clearance )
|
||||||
clearance = bc->GetLocalClearance( &m_msg );
|
clearance = bc->GetLocalClearance( &m_msg );
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* 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
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -22,7 +22,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <board.h>
|
|
||||||
#include <board_design_settings.h>
|
#include <board_design_settings.h>
|
||||||
#include <footprint.h>
|
#include <footprint.h>
|
||||||
#include <pcb_shape.h>
|
#include <pcb_shape.h>
|
||||||
|
@ -32,7 +31,6 @@
|
||||||
|
|
||||||
#include <geometry/seg.h>
|
#include <geometry/seg.h>
|
||||||
#include <geometry/shape_poly_set.h>
|
#include <geometry/shape_poly_set.h>
|
||||||
#include <geometry/shape_rect.h>
|
|
||||||
#include <geometry/shape_segment.h>
|
#include <geometry/shape_segment.h>
|
||||||
|
|
||||||
#include <drc/drc_engine.h>
|
#include <drc/drc_engine.h>
|
||||||
|
@ -43,9 +41,12 @@
|
||||||
#include <pcb_dimension.h>
|
#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:
|
Errors generated:
|
||||||
- DRCE_CLEARANCE
|
- DRCE_CLEARANCE
|
||||||
|
- DRCE_HOLE_CLEARANCE
|
||||||
- DRCE_TRACKS_CROSSING
|
- DRCE_TRACKS_CROSSING
|
||||||
- DRCE_ZONES_INTERSECT
|
- DRCE_ZONES_INTERSECT
|
||||||
- DRCE_SHORTING_ITEMS
|
- DRCE_SHORTING_ITEMS
|
||||||
|
@ -90,7 +91,7 @@ private:
|
||||||
|
|
||||||
void testPadClearances();
|
void testPadClearances();
|
||||||
|
|
||||||
void testZones();
|
void testZonesToZones();
|
||||||
|
|
||||||
void testItemAgainstZones( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer );
|
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..." ) ) )
|
if( !reportPhase( _( "Checking copper zone clearances..." ) ) )
|
||||||
return false; // DRC cancelled
|
return false; // DRC cancelled
|
||||||
|
|
||||||
testZones();
|
testZonesToZones();
|
||||||
}
|
}
|
||||||
else if( !m_drcEngine->IsErrorLimitExceeded( DRCE_ZONES_INTERSECT ) )
|
else if( !m_drcEngine->IsErrorLimitExceeded( DRCE_ZONES_INTERSECT ) )
|
||||||
{
|
{
|
||||||
if( !reportPhase( _( "Checking zones..." ) ) )
|
if( !reportPhase( _( "Checking zones..." ) ) )
|
||||||
return false; // DRC cancelled
|
return false; // DRC cancelled
|
||||||
|
|
||||||
testZones();
|
testZonesToZones();
|
||||||
}
|
}
|
||||||
|
|
||||||
reportRuleStatistics();
|
reportRuleStatistics();
|
||||||
|
@ -348,9 +349,9 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackAgainstItem( PCB_TRACK* track,
|
||||||
track->GetLayer() );
|
track->GetLayer() );
|
||||||
clearance = constraint.GetValue().Min();
|
clearance = constraint.GetValue().Min();
|
||||||
|
|
||||||
if( clearance >= 0 && trackShape->Collide( holeShape.get(),
|
if( clearance > 0 && trackShape->Collide( holeShape.get(),
|
||||||
std::max( 0, clearance - m_drcEpsilon ),
|
std::max( 0, clearance - m_drcEpsilon ),
|
||||||
&actual, &pos ) )
|
&actual, &pos ) )
|
||||||
{
|
{
|
||||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
|
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
|
||||||
|
|
||||||
|
@ -380,9 +381,6 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZones( BOARD_ITEM* aItem
|
||||||
{
|
{
|
||||||
for( ZONE* zone : m_zones )
|
for( ZONE* zone : m_zones )
|
||||||
{
|
{
|
||||||
if( m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE ) )
|
|
||||||
break;
|
|
||||||
|
|
||||||
if( !zone->GetLayerSet().test( aLayer ) )
|
if( !zone->GetLayerSet().test( aLayer ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -394,54 +392,111 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZones( BOARD_ITEM* aItem
|
||||||
|
|
||||||
if( aItem->GetBoundingBox().Intersects( zone->GetCachedBoundingBox() ) )
|
if( aItem->GetBoundingBox().Intersects( zone->GetCachedBoundingBox() ) )
|
||||||
{
|
{
|
||||||
auto constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, aItem, zone, aLayer );
|
bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
|
||||||
int clearance = constraint.GetValue().Min();
|
bool testHoles = !m_drcEngine->IsErrorLimitExceeded( DRCE_HOLE_CLEARANCE );
|
||||||
|
|
||||||
if( clearance < 0 )
|
if( !testClearance && !testHoles )
|
||||||
continue;
|
return;
|
||||||
|
|
||||||
int actual;
|
DRC_RTREE* zoneTree = m_board->m_CopperZoneRTrees[ zone ].get();
|
||||||
VECTOR2I pos;
|
EDA_RECT itemBBox = aItem->GetBoundingBox();
|
||||||
DRC_RTREE* zoneTree = m_board->m_CopperZoneRTrees[ zone ].get();
|
DRC_CONSTRAINT constraint;
|
||||||
EDA_RECT itemBBox = aItem->GetBoundingBox();
|
int clearance = -1;
|
||||||
std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape( aLayer );
|
int actual;
|
||||||
|
VECTOR2I pos;
|
||||||
|
|
||||||
if( aItem->Type() == PCB_PAD_T )
|
if( testClearance )
|
||||||
{
|
{
|
||||||
PAD* pad = static_cast<PAD*>( aItem );
|
constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, aItem, zone, aLayer );
|
||||||
|
clearance = constraint.GetValue().Min();
|
||||||
|
}
|
||||||
|
|
||||||
if( !pad->FlashLayer( aLayer ) )
|
if( clearance >= 0 )
|
||||||
|
{
|
||||||
|
std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape( aLayer );
|
||||||
|
|
||||||
|
if( aItem->Type() == PCB_PAD_T )
|
||||||
{
|
{
|
||||||
if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
|
PAD* pad = static_cast<PAD*>( aItem );
|
||||||
continue;
|
|
||||||
|
|
||||||
const SHAPE_SEGMENT* hole = pad->GetEffectiveHoleShape();
|
if( !pad->FlashLayer( aLayer ) )
|
||||||
int size = hole->GetWidth();
|
{
|
||||||
|
if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
// Note: drill size represents finish size, which means the actual hole
|
const SHAPE_SEGMENT* hole = pad->GetEffectiveHoleShape();
|
||||||
// size is the plating thickness larger.
|
int size = hole->GetWidth();
|
||||||
if( pad->GetAttribute() == PAD_ATTRIB::PTH )
|
|
||||||
size += m_board->GetDesignSettings().GetHolePlatingThickness();
|
|
||||||
|
|
||||||
itemShape = std::make_shared<SHAPE_SEGMENT>( hole->GetSeg(), size );
|
// Note: drill size represents finish size, which means the actual hole
|
||||||
|
// size is the plating thickness larger.
|
||||||
|
if( pad->GetAttribute() == PAD_ATTRIB::PTH )
|
||||||
|
size += m_board->GetDesignSettings().GetHolePlatingThickness();
|
||||||
|
|
||||||
|
itemShape = std::make_shared<SHAPE_SEGMENT>( hole->GetSeg(), size );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( zoneTree->QueryColliding( itemBBox, itemShape.get(), aLayer,
|
||||||
|
clearance - m_drcEpsilon, &actual, &pos ) )
|
||||||
|
{
|
||||||
|
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_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 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( zoneTree->QueryColliding( itemBBox, itemShape.get(), aLayer,
|
if( testHoles && ( aItem->Type() == PCB_VIA_T || aItem->Type() == PCB_PAD_T ) )
|
||||||
clearance - m_drcEpsilon, &actual, &pos ) )
|
|
||||||
{
|
{
|
||||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
|
std::unique_ptr<SHAPE_SEGMENT> holeShape;
|
||||||
|
|
||||||
m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
|
if( aItem->Type() == PCB_VIA_T )
|
||||||
constraint.GetName(),
|
{
|
||||||
MessageTextFromValue( userUnits(), clearance ),
|
PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
|
||||||
MessageTextFromValue( userUnits(), actual ) );
|
pos = via->GetPosition();
|
||||||
|
|
||||||
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
|
if( via->GetLayerSet().Contains( aLayer ) )
|
||||||
drce->SetItems( aItem, zone );
|
holeShape.reset( new SHAPE_SEGMENT( pos, pos, via->GetDrill() ) );
|
||||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
}
|
||||||
|
else if( aItem->Type() == PCB_PAD_T )
|
||||||
|
{
|
||||||
|
PAD* pad = static_cast<PAD*>( aItem );
|
||||||
|
|
||||||
reportViolation( drce, (wxPoint) pos );
|
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;
|
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
|
// A NPTH has no cylinder, but it may still have pads on some layers
|
||||||
if( pad->GetAttribute() == PAD_ATTRIB::NPTH && !pad->FlashLayer( layer ) )
|
if( pad->GetAttribute() == PAD_ATTRIB::NPTH && !pad->FlashLayer( layer ) )
|
||||||
testClearance = false;
|
testClearance = false;
|
||||||
|
|
||||||
if( !IsCopperLayer( layer ) )
|
if( otherPad && otherPad->GetAttribute() == PAD_ATTRIB::NPTH && !otherPad->FlashLayer( layer ) )
|
||||||
testClearance = false;
|
testClearance = false;
|
||||||
|
|
||||||
// Track clearances are tested in testTrackClearances()
|
// Track clearances are tested in testTrackClearances()
|
||||||
if( dynamic_cast<PCB_TRACK*>( other) )
|
if( dynamic_cast<PCB_TRACK*>( other) )
|
||||||
testClearance = false;
|
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 )
|
if( !testClearance && !testShorting && !testHoles )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -553,87 +634,28 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* pa
|
||||||
int actual;
|
int actual;
|
||||||
VECTOR2I pos;
|
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 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
|
||||||
|
if( pad->GetNetCode() && otherPad->GetNetCode()
|
||||||
|
&& pad->GetNetCode() != otherPad->GetNetCode()
|
||||||
|
&& testShorting )
|
||||||
{
|
{
|
||||||
// ...and have nets, then they must be the same net
|
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_SHORTING_ITEMS );
|
||||||
if( pad->GetNetCode() && otherPad->GetNetCode()
|
|
||||||
&& pad->GetNetCode() != otherPad->GetNetCode()
|
|
||||||
&& testShorting )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_SHORTING_ITEMS );
|
|
||||||
|
|
||||||
m_msg.Printf( _( "(nets %s and %s)" ),
|
m_msg.Printf( _( "(nets %s and %s)" ),
|
||||||
pad->GetNetname(),
|
pad->GetNetname(),
|
||||||
otherPad->GetNetname() );
|
otherPad->GetNetname() );
|
||||||
|
|
||||||
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
|
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
|
||||||
drce->SetItems( pad, otherPad );
|
drce->SetItems( pad, otherPad );
|
||||||
|
|
||||||
reportViolation( drce, otherPad->GetPosition() );
|
reportViolation( drce, otherPad->GetPosition() );
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( testHoles && pad->FlashLayer( layer ) && otherPad->GetDrillSize().x )
|
return true;
|
||||||
{
|
|
||||||
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 )
|
if( testClearance )
|
||||||
|
@ -656,6 +678,81 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* pa
|
||||||
drce->SetItems( pad, other );
|
drce->SetItems( pad, other );
|
||||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
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 );
|
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
|
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 ) )
|
if( m_keepTopBottomLayer && ( aLayer == m_layer || aLayer == m_bottomLayer ) )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return board->GetConnectivity()->IsConnectedOnLayer( this, static_cast<int>( aLayer ),
|
return board->GetConnectivity()->IsConnectedOnLayer( this, static_cast<int>( aLayer ), types );
|
||||||
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
|
std::shared_ptr<SHAPE> PCB_VIA::GetEffectiveShape( PCB_LAYER_ID aLayer ) const
|
||||||
{
|
{
|
||||||
if( FlashLayer( aLayer ) )
|
if( FlashLayer( aLayer ) )
|
||||||
|
{
|
||||||
return std::make_shared<SHAPE_CIRCLE>( m_Start, m_Width / 2 );
|
return std::make_shared<SHAPE_CIRCLE>( m_Start, m_Width / 2 );
|
||||||
|
}
|
||||||
else
|
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 )
|
int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
|
||||||
{
|
{
|
||||||
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
|
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
|
||||||
|
@ -580,7 +607,7 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
|
||||||
}
|
}
|
||||||
|
|
||||||
WX_HTML_REPORT_BOX* r = nullptr;
|
WX_HTML_REPORT_BOX* r = nullptr;
|
||||||
|
|
||||||
if( item->Type() == PCB_TRACE_T )
|
if( item->Type() == PCB_TRACE_T )
|
||||||
{
|
{
|
||||||
r = m_inspectConstraintsDialog->AddPage( _( "Track Width" ) );
|
r = m_inspectConstraintsDialog->AddPage( _( "Track Width" ) );
|
||||||
|
@ -600,19 +627,11 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
|
||||||
auto constraint = drcEngine.EvalRules( TRACK_WIDTH_CONSTRAINT, item, nullptr,
|
auto constraint = drcEngine.EvalRules( TRACK_WIDTH_CONSTRAINT, item, nullptr,
|
||||||
item->GetLayer(), r );
|
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( "" );
|
||||||
r->Report( wxString::Format( _( "Width constraints: min %s max %s." ),
|
r->Report( wxString::Format( _( "Width constraints: min %s; opt %s; max %s." ),
|
||||||
min,
|
reportMin( r->GetUnits(), constraint ),
|
||||||
max ) );
|
reportOpt( r->GetUnits(), constraint ),
|
||||||
|
reportMax( r->GetUnits(), constraint ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
r->Flush();
|
r->Flush();
|
||||||
|
@ -638,19 +657,11 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
|
||||||
auto constraint = drcEngine.EvalRules( VIA_DIAMETER_CONSTRAINT, item, nullptr,
|
auto constraint = drcEngine.EvalRules( VIA_DIAMETER_CONSTRAINT, item, nullptr,
|
||||||
UNDEFINED_LAYER, r );
|
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( "" );
|
||||||
r->Report( wxString::Format( _( "Diameter constraints: min %s max %s." ),
|
r->Report( wxString::Format( _( "Diameter constraints: min %s; opt %s; max %s." ),
|
||||||
min,
|
reportMin( r->GetUnits(), constraint ),
|
||||||
max ) );
|
reportOpt( r->GetUnits(), constraint ),
|
||||||
|
reportMax( r->GetUnits(), constraint ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
r->Flush();
|
r->Flush();
|
||||||
|
@ -673,19 +684,11 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
|
||||||
auto constraint = drcEngine.EvalRules( ANNULAR_WIDTH_CONSTRAINT, item, nullptr,
|
auto constraint = drcEngine.EvalRules( ANNULAR_WIDTH_CONSTRAINT, item, nullptr,
|
||||||
UNDEFINED_LAYER, r );
|
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( "" );
|
||||||
r->Report( wxString::Format( _( "Annular width constraints: min %s max %s." ),
|
r->Report( wxString::Format( _( "Annular width constraints: min %s; opt %s; max %s." ),
|
||||||
min,
|
reportMin( r->GetUnits(), constraint ),
|
||||||
max ) );
|
reportOpt( r->GetUnits(), constraint ),
|
||||||
|
reportMax( r->GetUnits(), constraint ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
r->Flush();
|
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
|
* 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).
|
* 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 ) )
|
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() )
|
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 )
|
// For pads having the same netcode as the zone, the net and hole
|
||||||
return;
|
// clearances have no meanings.
|
||||||
|
// So just knock out the greater of the zone's local clearance and
|
||||||
// Note: drill size represents finish size, which means the actual hole
|
// thermal relief.
|
||||||
// size is the plating thickness larger.
|
gap = std::max( zone_clearance, aZone->GetThermalReliefGap( aPad ) );
|
||||||
if( aPad->GetAttribute() == PAD_ATTRIB::PTH )
|
knockoutHoleClearance = false;
|
||||||
gap += aPad->GetBoard()->GetDesignSettings().GetHolePlatingThickness();
|
|
||||||
|
|
||||||
aPad->TransformHoleWithClearanceToPolygon( aHoles, gap, m_maxError,
|
|
||||||
ERROR_OUTSIDE );
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aPad, aLayer );
|
||||||
|
}
|
||||||
|
|
||||||
|
gap += extra_margin;
|
||||||
|
|
||||||
|
if( aPad->FlashLayer( aLayer ) )
|
||||||
addKnockout( aPad, aLayer, gap, aHoles );
|
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 ) )
|
if( aTrack->GetBoundingBox().Intersects( zone_boundingbox ) )
|
||||||
{
|
{
|
||||||
int gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aTrack, aLayer );
|
|
||||||
|
|
||||||
gap += extra_margin;
|
|
||||||
|
|
||||||
if( aTrack->Type() == PCB_VIA_T )
|
if( aTrack->Type() == PCB_VIA_T )
|
||||||
{
|
{
|
||||||
PCB_VIA* via = static_cast<PCB_VIA*>( aTrack );
|
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() )
|
||||||
{
|
{
|
||||||
int radius = via->GetDrillValue() / 2 + bds.GetHolePlatingThickness();
|
// For pads having the same netcode as the zone, the net and hole
|
||||||
TransformCircleToPolygon( aHoles, via->GetPosition(), radius + gap,
|
// clearances have no meanings.
|
||||||
m_maxError, ERROR_OUTSIDE );
|
// So just knock out the zone's local clearance.
|
||||||
|
gap = zone_clearance;
|
||||||
|
checkHoleClearance = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
via->TransformShapeWithClearanceToPolygon( aHoles, aLayer, gap,
|
gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aTrack, aLayer );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( via->FlashLayer( aLayer ) )
|
||||||
|
{
|
||||||
|
via->TransformShapeWithClearanceToPolygon( aHoles, aLayer,
|
||||||
|
gap + extra_margin,
|
||||||
m_maxError, ERROR_OUTSIDE );
|
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 + extra_margin,
|
||||||
|
m_maxError, ERROR_OUTSIDE );
|
||||||
}
|
}
|
||||||
else
|
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 );
|
m_maxError, ERROR_OUTSIDE );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,8 @@ private:
|
||||||
void addKnockout( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, int aGap, bool aIgnoreLineWidth,
|
void addKnockout( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, int aGap, bool aIgnoreLineWidth,
|
||||||
SHAPE_POLY_SET& aHoles );
|
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 knockoutThermalReliefs( const ZONE* aZone, PCB_LAYER_ID aLayer, SHAPE_POLY_SET& aFill );
|
||||||
|
|
||||||
void buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLayer,
|
void buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLayer,
|
||||||
|
|
|
@ -48,7 +48,13 @@
|
||||||
"min_clearance": 0.508
|
"min_clearance": 0.508
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"diff_pair_dimensions": [],
|
"diff_pair_dimensions": [
|
||||||
|
{
|
||||||
|
"gap": 0.0,
|
||||||
|
"via_gap": 0.0,
|
||||||
|
"width": 0.0
|
||||||
|
}
|
||||||
|
],
|
||||||
"drc_exclusions": [],
|
"drc_exclusions": [],
|
||||||
"meta": {
|
"meta": {
|
||||||
"version": 2
|
"version": 2
|
||||||
|
@ -108,8 +114,15 @@
|
||||||
"min_via_diameter": 0.39999999999999997,
|
"min_via_diameter": 0.39999999999999997,
|
||||||
"use_height_for_length_calcs": true
|
"use_height_for_length_calcs": true
|
||||||
},
|
},
|
||||||
"track_widths": [],
|
"track_widths": [
|
||||||
"via_dimensions": [],
|
0.0
|
||||||
|
],
|
||||||
|
"via_dimensions": [
|
||||||
|
{
|
||||||
|
"diameter": 0.0,
|
||||||
|
"drill": 0.0
|
||||||
|
}
|
||||||
|
],
|
||||||
"zones_allow_external_fillets": false,
|
"zones_allow_external_fillets": false,
|
||||||
"zones_use_no_outline": true
|
"zones_use_no_outline": true
|
||||||
},
|
},
|
||||||
|
|
|
@ -106,7 +106,7 @@ BOOST_FIXTURE_TEST_CASE( DRCFalseNegativeRegressions, DRC_REGRESSION_TEST_FIXTUR
|
||||||
{ "issue2528", 1 },
|
{ "issue2528", 1 },
|
||||||
{ "issue5750", 4 },
|
{ "issue5750", 4 },
|
||||||
{ "issue5854", 3 },
|
{ "issue5854", 3 },
|
||||||
{ "issue6879", 7 },
|
{ "issue6879", 6 },
|
||||||
{ "issue6945", 2 },
|
{ "issue6945", 2 },
|
||||||
{ "issue7241", 1 },
|
{ "issue7241", 1 },
|
||||||
{ "issue7267", 4 },
|
{ "issue7267", 4 },
|
||||||
|
|
Loading…
Reference in New Issue