From 41edf5c5bfd9f549bdff6f4d4519c42398912305 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Wed, 29 Jul 2020 19:24:38 -0700 Subject: [PATCH] Updating DRC to handle vias with differing layers --- pcbnew/drc/drc.cpp | 10 +- pcbnew/drc/drc.h | 19 +- pcbnew/drc/drc_clearance_test_functions.cpp | 437 +++++++++--------- qa/drc_proto/drc.cpp | 11 +- qa/drc_proto/drc.h | 21 +- qa/drc_proto/drc_clearance_test_functions.cpp | 405 ++++++++-------- 6 files changed, 475 insertions(+), 428 deletions(-) diff --git a/pcbnew/drc/drc.cpp b/pcbnew/drc/drc.cpp index af934843f1..0dbe94a256 100644 --- a/pcbnew/drc/drc.cpp +++ b/pcbnew/drc/drc.cpp @@ -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 - 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( *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 int code = (*seg_it)->Type() == PCB_VIA_T ? DRCE_DANGLING_VIA : DRCE_DANGLING_TRACK; diff --git a/pcbnew/drc/drc.h b/pcbnew/drc/drc.h index eb0e1eb339..9b54b0be28 100644 --- a/pcbnew/drc/drc.h +++ b/pcbnew/drc/drc.h @@ -213,11 +213,28 @@ private: * @param aStartIt the iterator to the first track to test * @param aEndIt the marker for the iterator end * @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 * filled in with the problem information. */ 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: /** diff --git a/pcbnew/drc/drc_clearance_test_functions.cpp b/pcbnew/drc/drc_clearance_test_functions.cpp index 68c121e6a9..9f0b860175 100644 --- a/pcbnew/drc/drc_clearance_test_functions.cpp +++ b/pcbnew/drc/drc_clearance_test_functions.cpp @@ -35,20 +35,178 @@ #include #include - -void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt, - TRACKS::iterator aEndIt, bool aTestZones ) +void DRC::doSingleViaDRC( BOARD_COMMIT& aCommit, VIA* aRefVia ) { - BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings(); + BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings(); + + // test if the via size is smaller than minimum + if( aRefVia->GetViaType() == VIATYPE::MICROVIA ) + { + 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() ); - PCB_LAYER_ID refLayer = aRefSeg->GetLayer(); - LSET refLayerSet = aRefSeg->GetLayerSet(); - EDA_RECT refSegBB = aRefSeg->GetBoundingBox(); 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 : */ @@ -56,9 +214,16 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS if( aRefSeg->Type() == PCB_VIA_T ) { - VIA *refvia = static_cast( aRefSeg ); + VIA* refvia = static_cast( aRefSeg ); int viaAnnulus = ( refvia->GetWidth() - refvia->GetDrill() ) / 2; - int minAnnulus = refvia->GetMinAnnulus( refvia->GetLayer(), &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 if( refvia->GetViaType() == VIATYPE::MICROVIA ) @@ -78,21 +243,6 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS 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 ); - - 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 { @@ -117,140 +267,9 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS 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 ); - - 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 = DRC_ITEM::Create( 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 = DRC_ITEM::Create( DRCE_ALLOWED_ITEMS ); - - m_msg.Printf( _( "Microvia not allowed (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 = DRC_ITEM::Create( DRCE_ALLOWED_ITEMS ); - - m_msg.Printf( _( "Blind/buried via not allowed (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 = 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( 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_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 ); - } - } - /******************************************/ /* 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; 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() ) ) continue; - if( !( pad->GetLayerSet() & refLayerSet ).any() ) + if( !( pad->IsOnLayer( aLayer ) ) ) continue; // 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 DRC_CONSTRAINT* constraint = GetConstraint( aRefSeg, pad, - DRC_RULE_ID_CLEARANCE, refLayer, + DRC_RULE_ID_CLEARANCE, aLayer, &m_clearanceSource ); int minClearance; int actual; @@ -305,7 +314,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS } else { - minClearance = aRefSeg->GetClearance( refLayer, nullptr, + minClearance = aRefSeg->GetClearance( aLayer, nullptr, &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 - if( !pad->IsPadOnLayer( refLayer ) ) + if( !pad->IsPadOnLayer( aLayer ) ) continue; 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() ) continue; - // No problem if tracks are on different layers: - // 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 ) + if( !track->GetLayerSet().test( aLayer ) ) continue; // 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; 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( track ); + + if( !via->IsPadOnLayer( aLayer ) ) + trackSeg.SetWidth( via->GetDrillValue() ); + } + // Check two tracks crossing first as it reports a DRCE without distances if( OPT_VECTOR2I intersection = refSeg.GetSeg().Intersect( trackSeg.GetSeg() ) ) { @@ -446,50 +444,43 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS // Can be *very* time consumming. if( aTestZones ) { - SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() ); for( ZONE_CONTAINER* zone : m_pcb->Zones() ) { - if( zone->GetIsKeepout() ) + if( !zone->GetLayerSet().test( aLayer ) || zone->GetIsKeepout() ) continue; if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() ) continue; - for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() ) + if( zone->GetFilledPolysList( aLayer ).IsEmpty() ) + continue; + + // to avoid false positive, due to rounding issues and approxiamtions + // in distance and clearance calculations, use a small threshold for distance + // (1 micron) + #define THRESHOLD_DIST Millimeter2iu( 0.001 ) + + + int minClearance = aRefSeg->GetClearance( aLayer, zone, &m_clearanceSource ); + int allowedDist = minClearance + halfWidth + THRESHOLD_DIST; + int actual; + + if( zone->GetFilledPolysList( aLayer ).Collide( testSeg, allowedDist, &actual ) ) { - if( !refLayerSet.test( layer ) ) - continue; + actual = std::max( 0, actual - halfWidth ); + DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE ); - if( zone->GetFilledPolysList( layer ).IsEmpty() ) - continue; + m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), + m_clearanceSource, + MessageTextFromValue( userUnits(), minClearance, true ), + MessageTextFromValue( userUnits(), actual, true ) ); - // to avoid false positive, due to rounding issues and approxiamtions - // in distance and clearance calculations, use a small threshold for distance - // (1 micron) - #define THRESHOLD_DIST Millimeter2iu( 0.001 ) + drcItem->SetErrorMessage( m_msg ); + drcItem->SetItems( aRefSeg, zone ); - int minClearance = aRefSeg->GetClearance( layer, zone, &m_clearanceSource ); - int widths = refSegWidth / 2; - int allowedDist = minClearance + widths + THRESHOLD_DIST; - int actual; - - if( zone->GetFilledPolysList( layer ).Collide( testSeg, allowedDist, &actual ) ) - { - actual = std::max( 0, actual - widths ); - DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE ); - - m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), - m_clearanceSource, - MessageTextFromValue( userUnits(), minClearance, true ), - MessageTextFromValue( userUnits(), actual, true ) ); - - drcItem->SetErrorMessage( m_msg ); - drcItem->SetItems( aRefSeg, zone ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, GetLocation( aRefSeg, zone ) ); - addMarkerToPcb( aCommit, marker ); - } + MARKER_PCB* marker = new MARKER_PCB( drcItem, GetLocation( aRefSeg, zone ) ); + addMarkerToPcb( aCommit, marker ); } } } @@ -508,8 +499,6 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS aRefSeg->GetRuleClearance( &dummyEdge, aRefSeg->GetLayer(), &minClearance, &m_clearanceSource ); - SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() ); - int halfWidth = refSegWidth / 2; int center2centerAllowed = minClearance + halfWidth; for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ ) diff --git a/qa/drc_proto/drc.cpp b/qa/drc_proto/drc.cpp index 0c38139950..870265797d 100644 --- a/qa/drc_proto/drc.cpp +++ b/qa/drc_proto/drc.cpp @@ -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 - 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( *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 int code = (*seg_it)->Type() == PCB_VIA_T ? DRCE_DANGLING_VIA : DRCE_DANGLING_TRACK; diff --git a/qa/drc_proto/drc.h b/qa/drc_proto/drc.h index 8c2ac13a7f..6f6f17959d 100644 --- a/qa/drc_proto/drc.h +++ b/qa/drc_proto/drc.h @@ -140,7 +140,7 @@ class wxTextCtrl; class DRC_ENGINE { - + } /** @@ -262,11 +262,28 @@ private: * @param aStartIt the iterator to the first track to test * @param aEndIt the marker for the iterator end * @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 * filled in with the problem information. */ 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 ); //--------------------------------------------------- diff --git a/qa/drc_proto/drc_clearance_test_functions.cpp b/qa/drc_proto/drc_clearance_test_functions.cpp index ba67583a6d..1eaeecbcd1 100644 --- a/qa/drc_proto/drc_clearance_test_functions.cpp +++ b/qa/drc_proto/drc_clearance_test_functions.cpp @@ -136,18 +136,178 @@ bool poly2segmentDRC( wxPoint* aTref, int aTrefCount, wxPoint aSegStart, wxPoint } -void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt, - TRACKS::iterator aEndIt, bool aTestZones ) +void DRC::doSingleViaDRC( BOARD_COMMIT& aCommit, VIA* aRefVia ) { - BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings(); + BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings(); - SEG refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() ); - PCB_LAYER_ID refLayer = aRefSeg->GetLayer(); - LSET refLayerSet = aRefSeg->GetLayerSet(); + // test if the via size is smaller than minimum + if( aRefVia->GetViaType() == VIATYPE::MICROVIA ) + { + if( aRefVia->GetWidth() < bds.m_MicroViasMinSize ) + { + DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_MICROVIA ); - EDA_RECT refSegBB = aRefSeg->GetBoundingBox(); - int refSegWidth = aRefSeg->GetWidth(); + 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(); + 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 : */ @@ -155,18 +315,25 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS if( aRefSeg->Type() == PCB_VIA_T ) { - VIA *refvia = static_cast( aRefSeg ); + VIA* refvia = static_cast( aRefSeg ); 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 if( refvia->GetViaType() == VIATYPE::MICROVIA ) { 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, MessageTextFromValue( userUnits(), minAnnulus, 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() ); 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 { @@ -203,9 +355,9 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS 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, MessageTextFromValue( userUnits(), minAnnulus, 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() ); 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() ) ) continue; - if( !( pad->GetLayerSet() & refLayerSet ).any() ) + if( !pad->IsOnLayer( aLayer ) ) continue; // 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(); SEG slotSeg( slotStart, slotEnd ); - int widths = ( slotWidth + refSegWidth ) / 2; - int center2centerAllowed = minClearance + widths + bds.GetDRCEpsilon(); + int center2centerAllowed = minClearance + halfWidth + bds.GetDRCEpsilon(); // Avoid square-roots if possible (for performance) SEG::ecoord center2center_squared = refSeg.SquaredDistance( slotSeg ); 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 ); 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 actual; - if( !checkClearanceSegmToPad( refSeg, refSegWidth, pad, clearanceAllowed, &actual ) ) + if( !checkClearanceSegmToPad( refSeg, refSeg.GetWidth(), pad, clearanceAllowed, &actual ) ) { actual = std::max( 0, actual ); 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() ) continue; - // No problem if tracks are on different layers: - // 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 ) + if( !track->GetLayerSet().test( aLayer ) ) continue; // 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 ) ) continue; - int minClearance = aRefSeg->GetClearance( track, &m_clearanceSource ); + int minClearance = aRefSeg->GetClearance( aLayer, track, &m_clearanceSource ); 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( track ); + + if( !via->IsPadOnLayer( aLayer ) ) + widths = ( via->GetDrillValue() / 2 ) + halfWidth; + } + int center2centerAllowed = minClearance + widths; // 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() ) { - if( zone->GetFilledPolysList().IsEmpty() || zone->GetIsKeepout() ) - continue; - - if( !( refLayerSet & zone->GetLayerSet() ).any() ) + if( !zone->GetLayerSet().test( aLayer ) || zone->GetFilledPolysList( aLayer ).IsEmpty() + || zone->GetIsKeepout() ) continue; if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() ) continue; - int minClearance = aRefSeg->GetClearance( zone, &m_clearanceSource ); - int widths = refSegWidth / 2; - int center2centerAllowed = minClearance + widths; - SHAPE_POLY_SET* outline = const_cast( &zone->GetFilledPolysList() ); + int minClearance = aRefSeg->GetClearance( aLayer, zone, &m_clearanceSource ); + int center2centerAllowed = minClearance + halfWidth; + SHAPE_POLY_SET* outline = const_cast( &zone->GetFilledPolysList( aLayer ) ); 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 ) ) { - 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 ); 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; 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() */; SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() ); - int halfWidth = refSegWidth / 2; int center2centerAllowed = minClearance + halfWidth; for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ )