Updating DRC to handle vias with differing layers

This commit is contained in:
Seth Hillbrand 2020-07-29 19:24:38 -07:00
parent 9a66a5acad
commit 41edf5c5bf
6 changed files with 475 additions and 428 deletions

View File

@ -592,7 +592,15 @@ void DRC::testTracks( BOARD_COMMIT& aCommit, wxWindow *aActiveWindow, bool aShow
} }
// Test new segment against tracks and pads, optionally against copper zones // Test new segment against tracks and pads, optionally against copper zones
doTrackDrc( aCommit, *seg_it, seg_it + 1, m_pcb->Tracks().end(), m_testTracksAgainstZones ); LSEQ layer_seq = ( *seg_it )->GetLayerSet().Seq();
if( ( *seg_it )->Type() == PCB_VIA_T )
doSingleViaDRC( aCommit, static_cast<VIA*>( *seg_it ) );
else
doSingleTrackDRC( aCommit, *seg_it );
for( PCB_LAYER_ID layer : layer_seq )
doTrackDrc( aCommit, *seg_it, seg_it + 1, m_pcb->Tracks().end(), m_testTracksAgainstZones, layer );
// Test for dangling items // Test for dangling items
int code = (*seg_it)->Type() == PCB_VIA_T ? DRCE_DANGLING_VIA : DRCE_DANGLING_TRACK; int code = (*seg_it)->Type() == PCB_VIA_T ? DRCE_DANGLING_VIA : DRCE_DANGLING_TRACK;

View File

@ -213,11 +213,28 @@ private:
* @param aStartIt the iterator to the first track to test * @param aStartIt the iterator to the first track to test
* @param aEndIt the marker for the iterator end * @param aEndIt the marker for the iterator end
* @param aTestZones true if should do copper zones test. This can be very time consumming * @param aTestZones true if should do copper zones test. This can be very time consumming
* @param aLayer sets the layer to test against
* @return bool - true if no problems, else false and m_currentMarker is * @return bool - true if no problems, else false and m_currentMarker is
* filled in with the problem information. * filled in with the problem information.
*/ */
void doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt, void doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
TRACKS::iterator aEndIt, bool aTestZones ); TRACKS::iterator aEndIt, bool aTestZones, PCB_LAYER_ID aLayer );
/**
* Test a single via for DRC errors
*
* @param aCommit The board commit to add DRC errors
* @param aRefVia The via to test against design settings
*/
void doSingleViaDRC( BOARD_COMMIT& aCommit, VIA* aRefVia );
/**
* Test a single track segment for DRC errors
*
* @param aCommit The board commit to add DRC errors
* @param aRefSeg The track to test against design settings
*/
void doSingleTrackDRC( BOARD_COMMIT& aCommit, TRACK* aRefSeg );
public: public:
/** /**

View File

@ -35,101 +35,42 @@
#include <geometry/shape_segment.h> #include <geometry/shape_segment.h>
#include <convert_basic_shapes_to_polygon.h> #include <convert_basic_shapes_to_polygon.h>
void DRC::doSingleViaDRC( BOARD_COMMIT& aCommit, VIA* aRefVia )
void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
TRACKS::iterator aEndIt, bool aTestZones )
{ {
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings(); BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
SHAPE_SEGMENT refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd(), aRefSeg->GetWidth() );
PCB_LAYER_ID refLayer = aRefSeg->GetLayer();
LSET refLayerSet = aRefSeg->GetLayerSet();
EDA_RECT refSegBB = aRefSeg->GetBoundingBox();
int refSegWidth = aRefSeg->GetWidth();
/******************************************/
/* Phase 0 : via DRC tests : */
/******************************************/
if( aRefSeg->Type() == PCB_VIA_T )
{
VIA *refvia = static_cast<VIA*>( aRefSeg );
int viaAnnulus = ( refvia->GetWidth() - refvia->GetDrill() ) / 2;
int minAnnulus = refvia->GetMinAnnulus( refvia->GetLayer(), &m_clearanceSource );
// test if the via size is smaller than minimum // test if the via size is smaller than minimum
if( refvia->GetViaType() == VIATYPE::MICROVIA ) if( aRefVia->GetViaType() == VIATYPE::MICROVIA )
{ {
if( viaAnnulus < minAnnulus ) if( aRefVia->GetWidth() < bds.m_MicroViasMinSize )
{
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_VIA_ANNULUS );
m_msg.Printf( _( "Via annulus too small (%s %s; actual %s)" ),
m_clearanceSource,
MessageTextFromValue( userUnits(), minAnnulus, true ),
MessageTextFromValue( userUnits(), viaAnnulus, true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
if( refvia->GetWidth() < bds.m_MicroViasMinSize )
{ {
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_MICROVIA ); DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_MICROVIA );
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
MessageTextFromValue( userUnits(), bds.m_MicroViasMinSize, true ), MessageTextFromValue( userUnits(), bds.m_MicroViasMinSize, true ),
MessageTextFromValue( userUnits(), refvia->GetWidth(), true ) ); MessageTextFromValue( userUnits(), aRefVia->GetWidth(), true ) );
drcItem->SetErrorMessage( m_msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia ); drcItem->SetItems( aRefVia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() ); MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
addMarkerToPcb( aCommit, marker ); addMarkerToPcb( aCommit, marker );
} }
} }
else else
{ {
if( bds.m_ViasMinAnnulus > minAnnulus ) if( aRefVia->GetWidth() < bds.m_ViasMinSize )
{
minAnnulus = bds.m_ViasMinAnnulus;
m_clearanceSource = _( "board minimum" );
}
if( viaAnnulus < minAnnulus )
{
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_VIA_ANNULUS );
m_msg.Printf( _( "Via annulus too small (%s %s; actual %s)" ),
m_clearanceSource,
MessageTextFromValue( userUnits(), minAnnulus, true ),
MessageTextFromValue( userUnits(), viaAnnulus, true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
if( refvia->GetWidth() < bds.m_ViasMinSize )
{ {
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_VIA ); DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_VIA );
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
MessageTextFromValue( userUnits(), bds.m_ViasMinSize, true ), MessageTextFromValue( userUnits(), bds.m_ViasMinSize, true ),
MessageTextFromValue( userUnits(), refvia->GetWidth(), true ) ); MessageTextFromValue( userUnits(), aRefVia->GetWidth(), true ) );
drcItem->SetErrorMessage( m_msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia ); drcItem->SetItems( aRefVia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() ); MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
addMarkerToPcb( aCommit, marker ); addMarkerToPcb( aCommit, marker );
} }
} }
@ -137,56 +78,56 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
// test if via's hole is bigger than its diameter // test if via's hole is bigger than its diameter
// This test is necessary since the via hole size and width can be modified // This test is necessary since the via hole size and width can be modified
// and a default via hole can be bigger than some vias sizes // and a default via hole can be bigger than some vias sizes
if( refvia->GetDrillValue() > refvia->GetWidth() ) if( aRefVia->GetDrillValue() > aRefVia->GetWidth() )
{ {
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_VIA_HOLE_BIGGER ); DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_VIA_HOLE_BIGGER );
m_msg.Printf( drcItem->GetErrorText() + _( " (diameter %s; drill %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (diameter %s; drill %s)" ),
MessageTextFromValue( userUnits(), refvia->GetWidth(), true ), MessageTextFromValue( userUnits(), aRefVia->GetWidth(), true ),
MessageTextFromValue( userUnits(), refvia->GetDrillValue(), true ) ); MessageTextFromValue( userUnits(), aRefVia->GetDrillValue(), true ) );
drcItem->SetErrorMessage( m_msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia ); drcItem->SetItems( aRefVia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() ); MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
addMarkerToPcb( aCommit, marker ); addMarkerToPcb( aCommit, marker );
} }
// test if the type of via is allowed due to design rules // test if the type of via is allowed due to design rules
if( refvia->GetViaType() == VIATYPE::MICROVIA && !bds.m_MicroViasAllowed ) if( aRefVia->GetViaType() == VIATYPE::MICROVIA && !bds.m_MicroViasAllowed )
{ {
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_ALLOWED_ITEMS ); DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_ALLOWED_ITEMS );
m_msg.Printf( _( "Microvia not allowed (board design rule constraints)" ) ); m_msg.Printf( _( "Microvia not allowed (board design rule constraints)" ) );
drcItem->SetErrorMessage( m_msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia ); drcItem->SetItems( aRefVia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() ); MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
addMarkerToPcb( aCommit, marker ); addMarkerToPcb( aCommit, marker );
} }
// test if the type of via is allowed due to design rules // test if the type of via is allowed due to design rules
if( refvia->GetViaType() == VIATYPE::BLIND_BURIED && !bds.m_BlindBuriedViaAllowed ) if( aRefVia->GetViaType() == VIATYPE::BLIND_BURIED && !bds.m_BlindBuriedViaAllowed )
{ {
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_ALLOWED_ITEMS ); DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_ALLOWED_ITEMS );
m_msg.Printf( _( "Blind/buried via not allowed (board design rule constraints)" ) ); m_msg.Printf( _( "Blind/buried via not allowed (board design rule constraints)" ) );
drcItem->SetErrorMessage( m_msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia ); drcItem->SetItems( aRefVia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() ); MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
addMarkerToPcb( aCommit, marker ); addMarkerToPcb( aCommit, marker );
} }
// For microvias: test if they are blind vias and only between 2 layers // For microvias: test if they are blind vias and only between 2 layers
// because they are used for very small drill size and are drill by laser // because they are used for very small drill size and are drill by laser
// and **only one layer** can be drilled // and **only one layer** can be drilled
if( refvia->GetViaType() == VIATYPE::MICROVIA ) if( aRefVia->GetViaType() == VIATYPE::MICROVIA )
{ {
PCB_LAYER_ID layer1, layer2; PCB_LAYER_ID layer1, layer2;
bool err = true; bool err = true;
refvia->LayerPair( &layer1, &layer2 ); aRefVia->LayerPair( &layer1, &layer2 );
if( layer1 > layer2 ) if( layer1 > layer2 )
std::swap( layer1, layer2 ); std::swap( layer1, layer2 );
@ -205,16 +146,21 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
m_pcb->GetLayerName( layer2 ) ); m_pcb->GetLayerName( layer2 ) );
drcItem->SetErrorMessage( m_msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia ); drcItem->SetItems( aRefVia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() ); MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
addMarkerToPcb( aCommit, marker ); addMarkerToPcb( aCommit, marker );
} }
} }
} }
else // This is a track segment
void DRC::doSingleTrackDRC( BOARD_COMMIT& aCommit, TRACK* aRefSeg )
{ {
SHAPE_SEGMENT refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd(), aRefSeg->GetWidth() );
EDA_RECT refSegBB = aRefSeg->GetBoundingBox();
int refSegWidth = aRefSeg->GetWidth();
int minWidth, maxWidth; int minWidth, maxWidth;
aRefSeg->GetWidthConstraints( &minWidth, &maxWidth, &m_clearanceSource ); aRefSeg->GetWidthConstraints( &minWidth, &maxWidth, &m_clearanceSource );
@ -252,6 +198,79 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
} }
void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
TRACKS::iterator aEndIt, bool aTestZones, PCB_LAYER_ID aLayer )
{
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
SHAPE_SEGMENT refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd(), aRefSeg->GetWidth() );
EDA_RECT refSegBB = aRefSeg->GetBoundingBox();
SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
int halfWidth = ( aRefSeg->GetWidth() + 1 ) / 2;
/******************************************/
/* Phase 0 : via DRC tests : */
/******************************************/
if( aRefSeg->Type() == PCB_VIA_T )
{
VIA* refvia = static_cast<VIA*>( aRefSeg );
int viaAnnulus = ( refvia->GetWidth() - refvia->GetDrill() ) / 2;
int minAnnulus = refvia->GetMinAnnulus( aLayer, &m_clearanceSource );
if( !refvia->IsPadOnLayer( aLayer ) )
{
halfWidth = ( refvia->GetDrillValue() + 1 ) / 2;
refSegBB = EDA_RECT( refvia->GetStart(),
wxSize( refvia->GetDrillValue(), refvia->GetDrillValue() ) );
}
// test if the via size is smaller than minimum
if( refvia->GetViaType() == VIATYPE::MICROVIA )
{
if( viaAnnulus < minAnnulus )
{
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_VIA_ANNULUS );
m_msg.Printf( _( "Via annulus too small (%s %s; actual %s)" ),
m_clearanceSource,
MessageTextFromValue( userUnits(), minAnnulus, true ),
MessageTextFromValue( userUnits(), viaAnnulus, true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
}
else
{
if( bds.m_ViasMinAnnulus > minAnnulus )
{
minAnnulus = bds.m_ViasMinAnnulus;
m_clearanceSource = _( "board minimum" );
}
if( viaAnnulus < minAnnulus )
{
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_VIA_ANNULUS );
m_msg.Printf( _( "Via annulus too small (%s %s; actual %s)" ),
m_clearanceSource,
MessageTextFromValue( userUnits(), minAnnulus, true ),
MessageTextFromValue( userUnits(), viaAnnulus, true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
}
}
/******************************************/ /******************************************/
/* Phase 1 : test DRC track to pads : */ /* Phase 1 : test DRC track to pads : */
/******************************************/ /******************************************/
@ -269,20 +288,10 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
EDA_RECT inflatedBB = refSegBB; EDA_RECT inflatedBB = refSegBB;
inflatedBB.Inflate( pad->GetBoundingRadius() + m_largestClearance ); inflatedBB.Inflate( pad->GetBoundingRadius() + m_largestClearance );
/// We setup the dummy pad to use in case we need to only draw the hole outline rather
/// than the pad itself
D_PAD dummypad( pad->GetParent() );
dummypad.SetNetCode( pad->GetNetCode() );
dummypad.SetSize( pad->GetDrillSize() );
dummypad.SetOrientation( pad->GetOrientation() );
dummypad.SetShape( pad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG ? PAD_SHAPE_OVAL
: PAD_SHAPE_CIRCLE );
dummypad.SetPosition( pad->GetPosition() );
if( !inflatedBB.Contains( pad->GetPosition() ) ) if( !inflatedBB.Contains( pad->GetPosition() ) )
continue; continue;
if( !( pad->GetLayerSet() & refLayerSet ).any() ) if( !( pad->IsOnLayer( aLayer ) ) )
continue; continue;
// No need to check pads with the same net as the refSeg. // No need to check pads with the same net as the refSeg.
@ -293,7 +302,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
{ {
const SHAPE_SEGMENT* slot = pad->GetEffectiveHoleShape(); const SHAPE_SEGMENT* slot = pad->GetEffectiveHoleShape();
const DRC_CONSTRAINT* constraint = GetConstraint( aRefSeg, pad, const DRC_CONSTRAINT* constraint = GetConstraint( aRefSeg, pad,
DRC_RULE_ID_CLEARANCE, refLayer, DRC_RULE_ID_CLEARANCE, aLayer,
&m_clearanceSource ); &m_clearanceSource );
int minClearance; int minClearance;
int actual; int actual;
@ -305,7 +314,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
} }
else else
{ {
minClearance = aRefSeg->GetClearance( refLayer, nullptr, minClearance = aRefSeg->GetClearance( aLayer, nullptr,
&m_clearanceSource ); &m_clearanceSource );
} }
@ -330,7 +339,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
} }
/// Skip checking pad copper when it has been removed /// Skip checking pad copper when it has been removed
if( !pad->IsPadOnLayer( refLayer ) ) if( !pad->IsPadOnLayer( aLayer ) )
continue; continue;
int minClearance = aRefSeg->GetClearance( aRefSeg->GetLayer(), pad, int minClearance = aRefSeg->GetClearance( aRefSeg->GetLayer(), pad,
@ -371,27 +380,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
if( aRefSeg->GetNetCode() == track->GetNetCode() ) if( aRefSeg->GetNetCode() == track->GetNetCode() )
continue; continue;
// No problem if tracks are on different layers: if( !track->GetLayerSet().test( aLayer ) )
// Note that while the general case of GetLayerSet intersection always works,
// the others are much faster.
bool sameLayers;
if( aRefSeg->Type() == PCB_VIA_T )
{
if( track->Type() == PCB_VIA_T )
sameLayers = ( refLayerSet & track->GetLayerSet() ).any();
else
sameLayers = refLayerSet.test( track->GetLayer() );
}
else
{
if( track->Type() == PCB_VIA_T )
sameLayers = track->GetLayerSet().test( refLayer );
else
sameLayers = track->GetLayer() == refLayer;
}
if( !sameLayers )
continue; continue;
// Preflight based on worst-case inflated bounding boxes: // Preflight based on worst-case inflated bounding boxes:
@ -406,6 +395,15 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
int actual; int actual;
SHAPE_SEGMENT trackSeg( track->GetStart(), track->GetEnd(), track->GetWidth() ); SHAPE_SEGMENT trackSeg( track->GetStart(), track->GetEnd(), track->GetWidth() );
/// Check to see if the via has a pad on this layer
if( track->Type() == PCB_VIA_T )
{
VIA* via = static_cast<VIA*>( track );
if( !via->IsPadOnLayer( aLayer ) )
trackSeg.SetWidth( via->GetDrillValue() );
}
// Check two tracks crossing first as it reports a DRCE without distances // Check two tracks crossing first as it reports a DRCE without distances
if( OPT_VECTOR2I intersection = refSeg.GetSeg().Intersect( trackSeg.GetSeg() ) ) if( OPT_VECTOR2I intersection = refSeg.GetSeg().Intersect( trackSeg.GetSeg() ) )
{ {
@ -446,22 +444,16 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
// Can be *very* time consumming. // Can be *very* time consumming.
if( aTestZones ) if( aTestZones )
{ {
SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
for( ZONE_CONTAINER* zone : m_pcb->Zones() ) for( ZONE_CONTAINER* zone : m_pcb->Zones() )
{ {
if( zone->GetIsKeepout() ) if( !zone->GetLayerSet().test( aLayer ) || zone->GetIsKeepout() )
continue; continue;
if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() ) if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() )
continue; continue;
for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() ) if( zone->GetFilledPolysList( aLayer ).IsEmpty() )
{
if( !refLayerSet.test( layer ) )
continue;
if( zone->GetFilledPolysList( layer ).IsEmpty() )
continue; continue;
// to avoid false positive, due to rounding issues and approxiamtions // to avoid false positive, due to rounding issues and approxiamtions
@ -469,14 +461,14 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
// (1 micron) // (1 micron)
#define THRESHOLD_DIST Millimeter2iu( 0.001 ) #define THRESHOLD_DIST Millimeter2iu( 0.001 )
int minClearance = aRefSeg->GetClearance( layer, zone, &m_clearanceSource );
int widths = refSegWidth / 2; int minClearance = aRefSeg->GetClearance( aLayer, zone, &m_clearanceSource );
int allowedDist = minClearance + widths + THRESHOLD_DIST; int allowedDist = minClearance + halfWidth + THRESHOLD_DIST;
int actual; int actual;
if( zone->GetFilledPolysList( layer ).Collide( testSeg, allowedDist, &actual ) ) if( zone->GetFilledPolysList( aLayer ).Collide( testSeg, allowedDist, &actual ) )
{ {
actual = std::max( 0, actual - widths ); actual = std::max( 0, actual - halfWidth );
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE ); DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
@ -492,7 +484,6 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
} }
} }
} }
}
/***********************************************/ /***********************************************/
/* Phase 4: test DRC with to board edge */ /* Phase 4: test DRC with to board edge */
@ -508,8 +499,6 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
aRefSeg->GetRuleClearance( &dummyEdge, aRefSeg->GetLayer(), &minClearance, aRefSeg->GetRuleClearance( &dummyEdge, aRefSeg->GetLayer(), &minClearance,
&m_clearanceSource ); &m_clearanceSource );
SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
int halfWidth = refSegWidth / 2;
int center2centerAllowed = minClearance + halfWidth; int center2centerAllowed = minClearance + halfWidth;
for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ ) for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ )

View File

@ -625,7 +625,16 @@ void DRC::testTracks( BOARD_COMMIT& aCommit, wxWindow *aActiveWindow, bool aShow
} }
// Test new segment against tracks and pads, optionally against copper zones // Test new segment against tracks and pads, optionally against copper zones
doTrackDrc( aCommit, *seg_it, seg_it + 1, m_pcb->Tracks().end(), m_testTracksAgainstZones ); LSEQ layer_seq = ( *seg_it )->GetLayerSet().Seq();
if( ( *seg_it )->Type() == PCB_VIA_T )
doSingleViaDRC( aCommit, static_cast<VIA*>( *seg_it ) );
else
doSingleTrackDRC( aCommit, *seg_it );
for( PCB_LAYER_ID layer : layer_seq )
doTrackDrc( aCommit, *seg_it, seg_it + 1, m_pcb->Tracks().end(), m_testTracksAgainstZones, layer );
// Test for dangling items // Test for dangling items
int code = (*seg_it)->Type() == PCB_VIA_T ? DRCE_DANGLING_VIA : DRCE_DANGLING_TRACK; int code = (*seg_it)->Type() == PCB_VIA_T ? DRCE_DANGLING_VIA : DRCE_DANGLING_TRACK;

View File

@ -262,11 +262,28 @@ private:
* @param aStartIt the iterator to the first track to test * @param aStartIt the iterator to the first track to test
* @param aEndIt the marker for the iterator end * @param aEndIt the marker for the iterator end
* @param aTestZones true if should do copper zones test. This can be very time consumming * @param aTestZones true if should do copper zones test. This can be very time consumming
* @param aLayer sets the layer to test against
* @return bool - true if no problems, else false and m_currentMarker is * @return bool - true if no problems, else false and m_currentMarker is
* filled in with the problem information. * filled in with the problem information.
*/ */
void doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt, void doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
TRACKS::iterator aEndIt, bool aTestZones ); TRACKS::iterator aEndIt, bool aTestZones, PCB_LAYER_ID aLayer );
/**
* Test a single via for DRC errors
*
* @param aCommit The board commit to add DRC errors
* @param aRefVia The via to test against design settings
*/
void doSingleViaDRC( BOARD_COMMIT& aCommit, VIA* aRefVia );
/**
* Test a single track segment for DRC errors
*
* @param aCommit The board commit to add DRC errors
* @param aRefSeg The track to test against design settings
*/
void doSingleTrackDRC( BOARD_COMMIT& aCommit, TRACK* aRefSeg );
//-----<single tests>---------------------------------------------- //-----<single tests>----------------------------------------------

View File

@ -136,18 +136,178 @@ bool poly2segmentDRC( wxPoint* aTref, int aTrefCount, wxPoint aSegStart, wxPoint
} }
void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt, void DRC::doSingleViaDRC( BOARD_COMMIT& aCommit, VIA* aRefVia )
TRACKS::iterator aEndIt, bool aTestZones )
{ {
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings(); BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
SEG refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() ); // test if the via size is smaller than minimum
PCB_LAYER_ID refLayer = aRefSeg->GetLayer(); if( aRefVia->GetViaType() == VIATYPE::MICROVIA )
LSET refLayerSet = aRefSeg->GetLayerSet(); {
if( aRefVia->GetWidth() < bds.m_MicroViasMinSize )
{
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_MICROVIA );
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
MessageTextFromValue( userUnits(), bds.m_MicroViasMinSize, true ),
MessageTextFromValue( userUnits(), aRefVia->GetWidth(), true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefVia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
}
else
{
if( aRefVia->GetWidth() < bds.m_ViasMinSize )
{
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_VIA );
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
MessageTextFromValue( userUnits(), bds.m_ViasMinSize, true ),
MessageTextFromValue( userUnits(), aRefVia->GetWidth(), true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefVia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
}
// test if via's hole is bigger than its diameter
// This test is necessary since the via hole size and width can be modified
// and a default via hole can be bigger than some vias sizes
if( aRefVia->GetDrillValue() > aRefVia->GetWidth() )
{
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_VIA_HOLE_BIGGER );
m_msg.Printf( drcItem->GetErrorText() + _( " (diameter %s; drill %s)" ),
MessageTextFromValue( userUnits(), aRefVia->GetWidth(), true ),
MessageTextFromValue( userUnits(), aRefVia->GetDrillValue(), true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefVia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
// test if the type of via is allowed due to design rules
if( aRefVia->GetViaType() == VIATYPE::MICROVIA && !bds.m_MicroViasAllowed )
{
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_ALLOWED_ITEMS );
m_msg.Printf( _( "Microvia not allowed (board design rule constraints)" ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefVia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
// test if the type of via is allowed due to design rules
if( aRefVia->GetViaType() == VIATYPE::BLIND_BURIED && !bds.m_BlindBuriedViaAllowed )
{
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_ALLOWED_ITEMS );
m_msg.Printf( _( "Blind/buried via not allowed (board design rule constraints)" ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefVia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
// For microvias: test if they are blind vias and only between 2 layers
// because they are used for very small drill size and are drill by laser
// and **only one layer** can be drilled
if( aRefVia->GetViaType() == VIATYPE::MICROVIA )
{
PCB_LAYER_ID layer1, layer2;
bool err = true;
aRefVia->LayerPair( &layer1, &layer2 );
if( layer1 > layer2 )
std::swap( layer1, layer2 );
if( layer2 == B_Cu && layer1 == bds.GetCopperLayerCount() - 2 )
err = false;
else if( layer1 == F_Cu && layer2 == In1_Cu )
err = false;
if( err )
{
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_PADSTACK );
m_msg.Printf( _( "Microvia through too many layers (%s and %s not adjacent)" ),
m_pcb->GetLayerName( layer1 ),
m_pcb->GetLayerName( layer2 ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefVia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefVia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
}
}
void DRC::doSingleTrackDRC( BOARD_COMMIT& aCommit, TRACK* aRefSeg )
{
SHAPE_SEGMENT refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd(), aRefSeg->GetWidth() );
EDA_RECT refSegBB = aRefSeg->GetBoundingBox(); EDA_RECT refSegBB = aRefSeg->GetBoundingBox();
int refSegWidth = aRefSeg->GetWidth(); int refSegWidth = aRefSeg->GetWidth();
int minWidth, maxWidth;
aRefSeg->GetWidthConstraints( &minWidth, &maxWidth, &m_clearanceSource );
int errorCode = 0;
int constraintWidth;
if( refSegWidth < minWidth )
{
errorCode = DRCE_TRACK_WIDTH;
constraintWidth = minWidth;
}
else if( refSegWidth > maxWidth )
{
errorCode = DRCE_TRACK_WIDTH;
constraintWidth = maxWidth;
}
if( errorCode )
{
wxPoint refsegMiddle = ( aRefSeg->GetStart() + aRefSeg->GetEnd() ) / 2;
DRC_ITEM* drcItem = DRC_ITEM::Create( errorCode );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
m_clearanceSource,
MessageTextFromValue( userUnits(), constraintWidth, true ),
MessageTextFromValue( userUnits(), refSegWidth, true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefSeg );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refsegMiddle );
addMarkerToPcb( aCommit, marker );
}
}
void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
TRACKS::iterator aEndIt, bool aTestZones, PCB_LAYER_ID aLayer )
{
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
SHAPE_SEGMENT refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd(), aRefSeg->GetWidth() );
EDA_RECT refSegBB = aRefSeg->GetBoundingBox();
SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
int halfWidth = ( aRefSeg->GetWidth() + 1 ) / 2;
/******************************************/ /******************************************/
/* Phase 0 : via DRC tests : */ /* Phase 0 : via DRC tests : */
@ -157,16 +317,23 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
{ {
VIA* refvia = static_cast<VIA*>( aRefSeg ); VIA* refvia = static_cast<VIA*>( aRefSeg );
int viaAnnulus = ( refvia->GetWidth() - refvia->GetDrill() ) / 2; int viaAnnulus = ( refvia->GetWidth() - refvia->GetDrill() ) / 2;
int minAnnulus = refvia->GetMinAnnulus( &m_clearanceSource ); int minAnnulus = refvia->GetMinAnnulus( aLayer, &m_clearanceSource );
if( !refvia->IsPadOnLayer( aLayer ) )
{
halfWidth = ( refvia->GetDrillValue() + 1 ) / 2;
refSegBB = EDA_RECT( refvia->GetStart(),
wxSize( refvia->GetDrillValue(), refvia->GetDrillValue() ) );
}
// test if the via size is smaller than minimum // test if the via size is smaller than minimum
if( refvia->GetViaType() == VIATYPE::MICROVIA ) if( refvia->GetViaType() == VIATYPE::MICROVIA )
{ {
if( viaAnnulus < minAnnulus ) if( viaAnnulus < minAnnulus )
{ {
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_VIA_ANNULUS ); DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_VIA_ANNULUS );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ), m_msg.Printf( _( "Via annulus too small (%s %s; actual %s)" ),
m_clearanceSource, m_clearanceSource,
MessageTextFromValue( userUnits(), minAnnulus, true ), MessageTextFromValue( userUnits(), minAnnulus, true ),
MessageTextFromValue( userUnits(), viaAnnulus, true ) ); MessageTextFromValue( userUnits(), viaAnnulus, true ) );
@ -177,21 +344,6 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() ); MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( aCommit, marker ); addMarkerToPcb( aCommit, marker );
} }
if( refvia->GetWidth() < bds.m_MicroViasMinSize )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_MICROVIA );
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
MessageTextFromValue( userUnits(), bds.m_MicroViasMinSize, true ),
MessageTextFromValue( userUnits(), refvia->GetWidth(), true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
} }
else else
{ {
@ -203,9 +355,9 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
if( viaAnnulus < minAnnulus ) if( viaAnnulus < minAnnulus )
{ {
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_VIA_ANNULUS ); DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_VIA_ANNULUS );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ), m_msg.Printf( _( "Via annulus too small (%s %s; actual %s)" ),
m_clearanceSource, m_clearanceSource,
MessageTextFromValue( userUnits(), minAnnulus, true ), MessageTextFromValue( userUnits(), minAnnulus, true ),
MessageTextFromValue( userUnits(), viaAnnulus, true ) ); MessageTextFromValue( userUnits(), viaAnnulus, true ) );
@ -216,138 +368,8 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() ); MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( aCommit, marker ); addMarkerToPcb( aCommit, marker );
} }
if( refvia->GetWidth() < bds.m_ViasMinSize )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_VIA );
m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
MessageTextFromValue( userUnits(), bds.m_ViasMinSize, true ),
MessageTextFromValue( userUnits(), refvia->GetWidth(), true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
} }
// test if via's hole is bigger than its diameter
// This test is necessary since the via hole size and width can be modified
// and a default via hole can be bigger than some vias sizes
if( refvia->GetDrillValue() > refvia->GetWidth() )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_VIA_HOLE_BIGGER );
m_msg.Printf( drcItem->GetErrorText() + _( " (diameter %s; drill %s)" ),
MessageTextFromValue( userUnits(), refvia->GetWidth(), true ),
MessageTextFromValue( userUnits(), refvia->GetDrillValue(), true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
// test if the type of via is allowed due to design rules
if( refvia->GetViaType() == VIATYPE::MICROVIA && !bds.m_MicroViasAllowed )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_MICROVIA_NOT_ALLOWED );
m_msg.Printf( drcItem->GetErrorText() + _( " (board design rule constraints)" ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
// test if the type of via is allowed due to design rules
if( refvia->GetViaType() == VIATYPE::BLIND_BURIED && !bds.m_BlindBuriedViaAllowed )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_BURIED_VIA_NOT_ALLOWED );
m_msg.Printf( drcItem->GetErrorText() + _( " (board design rule constraints)" ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
// For microvias: test if they are blind vias and only between 2 layers
// because they are used for very small drill size and are drill by laser
// and **only one layer** can be drilled
if( refvia->GetViaType() == VIATYPE::MICROVIA )
{
PCB_LAYER_ID layer1, layer2;
bool err = true;
refvia->LayerPair( &layer1, &layer2 );
if( layer1 > layer2 )
std::swap( layer1, layer2 );
if( layer2 == B_Cu && layer1 == bds.GetCopperLayerCount() - 2 )
err = false;
else if( layer1 == F_Cu && layer2 == In1_Cu )
err = false;
if( err )
{
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_MICROVIA_TOO_MANY_LAYERS );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s and %s not adjacent)" ),
m_pcb->GetLayerName( layer1 ),
m_pcb->GetLayerName( layer2 ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( refvia );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
addMarkerToPcb( aCommit, marker );
}
}
}
else // This is a track segment
{
int minWidth, maxWidth;
aRefSeg->GetWidthConstraints( &minWidth, &maxWidth, &m_clearanceSource );
int errorCode = 0;
int constraintWidth;
if( refSegWidth < minWidth )
{
errorCode = DRCE_TOO_SMALL_TRACK_WIDTH;
constraintWidth = minWidth;
}
else if( refSegWidth > maxWidth )
{
errorCode = DRCE_TOO_LARGE_TRACK_WIDTH;
constraintWidth = maxWidth;
}
if( errorCode )
{
wxPoint refsegMiddle = ( aRefSeg->GetStart() + aRefSeg->GetEnd() ) / 2;
DRC_ITEM* drcItem = new DRC_ITEM( errorCode );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
m_clearanceSource,
MessageTextFromValue( userUnits(), constraintWidth, true ),
MessageTextFromValue( userUnits(), refSegWidth, true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefSeg );
MARKER_PCB* marker = new MARKER_PCB( drcItem, refsegMiddle );
addMarkerToPcb( aCommit, marker );
}
} }
@ -371,7 +393,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
if( !inflatedBB.Contains( pad->GetPosition() ) ) if( !inflatedBB.Contains( pad->GetPosition() ) )
continue; continue;
if( !( pad->GetLayerSet() & refLayerSet ).any() ) if( !pad->IsOnLayer( aLayer ) )
continue; continue;
// No need to check pads with the same net as the refSeg. // No need to check pads with the same net as the refSeg.
@ -415,15 +437,14 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
slotEnd += pad->GetPosition(); slotEnd += pad->GetPosition();
SEG slotSeg( slotStart, slotEnd ); SEG slotSeg( slotStart, slotEnd );
int widths = ( slotWidth + refSegWidth ) / 2; int center2centerAllowed = minClearance + halfWidth + bds.GetDRCEpsilon();
int center2centerAllowed = minClearance + widths + bds.GetDRCEpsilon();
// Avoid square-roots if possible (for performance) // Avoid square-roots if possible (for performance)
SEG::ecoord center2center_squared = refSeg.SquaredDistance( slotSeg ); SEG::ecoord center2center_squared = refSeg.SquaredDistance( slotSeg );
if( center2center_squared < SEG::Square( center2centerAllowed ) ) if( center2center_squared < SEG::Square( center2centerAllowed ) )
{ {
int actual = std::max( 0.0, sqrt( center2center_squared ) - widths ); int actual = std::max( 0.0, sqrt( center2center_squared ) - halfWidth );
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_HOLE ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_HOLE );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
@ -442,11 +463,11 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
} }
} }
int minClearance = aRefSeg->GetClearance( pad, &m_clearanceSource ); int minClearance = aRefSeg->GetClearance( aLayer, pad, &m_clearanceSource );
int clearanceAllowed = minClearance - bds.GetDRCEpsilon(); int clearanceAllowed = minClearance - bds.GetDRCEpsilon();
int actual; int actual;
if( !checkClearanceSegmToPad( refSeg, refSegWidth, pad, clearanceAllowed, &actual ) ) if( !checkClearanceSegmToPad( refSeg, refSeg.GetWidth(), pad, clearanceAllowed, &actual ) )
{ {
actual = std::max( 0, actual ); actual = std::max( 0, actual );
SEG padSeg( pad->GetPosition(), pad->GetPosition() ); SEG padSeg( pad->GetPosition(), pad->GetPosition() );
@ -482,27 +503,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
if( aRefSeg->GetNetCode() == track->GetNetCode() ) if( aRefSeg->GetNetCode() == track->GetNetCode() )
continue; continue;
// No problem if tracks are on different layers: if( !track->GetLayerSet().test( aLayer ) )
// Note that while the general case of GetLayerSet intersection always works,
// the others are much faster.
bool sameLayers;
if( aRefSeg->Type() == PCB_VIA_T )
{
if( track->Type() == PCB_VIA_T )
sameLayers = ( refLayerSet & track->GetLayerSet() ).any();
else
sameLayers = refLayerSet.test( track->GetLayer() );
}
else
{
if( track->Type() == PCB_VIA_T )
sameLayers = track->GetLayerSet().test( refLayer );
else
sameLayers = track->GetLayer() == refLayer;
}
if( !sameLayers )
continue; continue;
// Preflight based on worst-case inflated bounding boxes: // Preflight based on worst-case inflated bounding boxes:
@ -512,9 +513,19 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
if( !trackBB.Intersects( refSegBB ) ) if( !trackBB.Intersects( refSegBB ) )
continue; continue;
int minClearance = aRefSeg->GetClearance( track, &m_clearanceSource ); int minClearance = aRefSeg->GetClearance( aLayer, track, &m_clearanceSource );
SEG trackSeg( track->GetStart(), track->GetEnd() ); SEG trackSeg( track->GetStart(), track->GetEnd() );
int widths = ( refSegWidth + track->GetWidth() ) / 2; int widths = ( track->GetWidth() / 2 ) + halfWidth;
/// Check to see if the via has a pad on this layer
if( track->Type() == PCB_VIA_T )
{
VIA* via = static_cast<VIA*>( track );
if( !via->IsPadOnLayer( aLayer ) )
widths = ( via->GetDrillValue() / 2 ) + halfWidth;
}
int center2centerAllowed = minClearance + widths; int center2centerAllowed = minClearance + widths;
// Avoid square-roots if possible (for performance) // Avoid square-roots if possible (for performance)
@ -574,19 +585,16 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
for( ZONE_CONTAINER* zone : m_pcb->Zones() ) for( ZONE_CONTAINER* zone : m_pcb->Zones() )
{ {
if( zone->GetFilledPolysList().IsEmpty() || zone->GetIsKeepout() ) if( !zone->GetLayerSet().test( aLayer ) || zone->GetFilledPolysList( aLayer ).IsEmpty()
continue; || zone->GetIsKeepout() )
if( !( refLayerSet & zone->GetLayerSet() ).any() )
continue; continue;
if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() ) if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() )
continue; continue;
int minClearance = aRefSeg->GetClearance( zone, &m_clearanceSource ); int minClearance = aRefSeg->GetClearance( aLayer, zone, &m_clearanceSource );
int widths = refSegWidth / 2; int center2centerAllowed = minClearance + halfWidth;
int center2centerAllowed = minClearance + widths; SHAPE_POLY_SET* outline = const_cast<SHAPE_POLY_SET*>( &zone->GetFilledPolysList( aLayer ) );
SHAPE_POLY_SET* outline = const_cast<SHAPE_POLY_SET*>( &zone->GetFilledPolysList() );
SEG::ecoord center2center_squared = outline->SquaredDistance( testSeg ); SEG::ecoord center2center_squared = outline->SquaredDistance( testSeg );
@ -597,7 +605,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
if( center2center_squared + THRESHOLD_DIST < SEG::Square( center2centerAllowed ) ) if( center2center_squared + THRESHOLD_DIST < SEG::Square( center2centerAllowed ) )
{ {
int actual = std::max( 0.0, sqrt( center2center_squared ) - widths ); int actual = std::max( 0.0, sqrt( center2center_squared ) - halfWidth );
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_ZONE ); DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_ZONE );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
@ -625,11 +633,10 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
static DRAWSEGMENT dummyEdge; static DRAWSEGMENT dummyEdge;
dummyEdge.SetLayer( Edge_Cuts ); dummyEdge.SetLayer( Edge_Cuts );
if( aRefSeg->GetRuleClearance( &dummyEdge, &minClearance, &m_clearanceSource ) ) if( aRefSeg->GetRuleClearance( &dummyEdge, aLayer, &minClearance, &m_clearanceSource ) )
/* minClearance and m_clearanceSource set in GetRuleClearance() */; /* minClearance and m_clearanceSource set in GetRuleClearance() */;
SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() ); SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
int halfWidth = refSegWidth / 2;
int center2centerAllowed = minClearance + halfWidth; int center2centerAllowed = minClearance + halfWidth;
for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ ) for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ )