diff --git a/pcbnew/drc/drc_test_provider_copper_clearance.cpp b/pcbnew/drc/drc_test_provider_copper_clearance.cpp index 1b79059ee7..da3531835e 100644 --- a/pcbnew/drc/drc_test_provider_copper_clearance.cpp +++ b/pcbnew/drc/drc_test_provider_copper_clearance.cpp @@ -79,6 +79,14 @@ public: } private: + /** + * Checks for track/via/hole <-> clearance + * @param track Track to text + * @param trackShape Primitive track shape + * @param layer Which layer to test (in case of vias this can be multiple + * @param other item against which to test the track item + * @return false if there is a clearance violation reported, true if there is none + */ bool testTrackAgainstItem( PCB_TRACK* track, SHAPE* trackShape, PCB_LAYER_ID layer, BOARD_ITEM* other ); @@ -92,6 +100,18 @@ private: void testItemAgainstZone( BOARD_ITEM* aItem, ZONE* aZone, PCB_LAYER_ID aLayer ); + typedef struct checked + { + checked() + : layers(), has_error( false ) {} + + checked( PCB_LAYER_ID aLayer ) + : layers( aLayer ), has_error( false ) {} + + LSET layers; + bool has_error; + } layers_checked; + private: int m_drcEpsilon; }; @@ -171,6 +191,7 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackAgainstItem( PCB_TRACK* track, int clearance = -1; int actual; VECTOR2I pos; + bool has_error = false; std::shared_ptr otherShape = other->GetEffectiveShape( layer ); @@ -204,7 +225,7 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackAgainstItem( PCB_TRACK* track, reportViolation( drcItem, *intersection, layer ); - return m_drcEngine->GetReportAllTrackErrors(); + return false; } } @@ -228,6 +249,7 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackAgainstItem( PCB_TRACK* track, drce->SetViolatingRule( constraint.GetParentRule() ); reportViolation( drce, pos, layer ); + has_error = true; if( !m_drcEngine->GetReportAllTrackErrors() ) return false; @@ -241,9 +263,7 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackAgainstItem( PCB_TRACK* track, std::array b{ other, track }; std::array a_shape{ trackShape, otherShape.get() }; - bool has_error = false; - - for( size_t ii = 0; ii < 2 && !has_error; ++ii ) + for( size_t ii = 0; ii < 2; ++ii ) { std::shared_ptr holeShape; @@ -282,16 +302,13 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackAgainstItem( PCB_TRACK* track, drce->SetViolatingRule( constraint.GetParentRule() ); reportViolation( drce, pos, layer ); - has_error = true; - - if( !m_drcEngine->GetReportAllTrackErrors() ) - return false; + return false; } } } } - return !m_drcEngine->IsCancelled(); + return !has_error; } @@ -419,8 +436,8 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances() reportAux( wxT( "Testing %d tracks & vias..." ), m_board->Tracks().size() ); - std::map freePadsUsageMap; - std::unordered_map checkedPairs; + std::map freePadsUsageMap; + std::unordered_map checkedPairs; for( PCB_TRACK* track : m_board->Tracks() ) { @@ -450,13 +467,14 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances() auto it = checkedPairs.find( { a, b } ); - if( it != checkedPairs.end() && it->second.test( layer ) ) + if( it != checkedPairs.end() && ( it->second.layers.test( layer ) + || ( it->second.has_error && !m_drcEngine->GetReportAllTrackErrors() ) ) ) { return false; } else { - checkedPairs[ { a, b } ].set( layer ); + checkedPairs[ { a, b } ].layers.set( layer ); return true; } }, @@ -481,7 +499,27 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances() } } - return testTrackAgainstItem( track, trackShape.get(), layer, other ); + BOARD_ITEM* a = track; + BOARD_ITEM* b = other; + + // store canonical order so we don't collide in both directions + // (a:b and b:a) + if( static_cast( a ) > static_cast( b ) ) + std::swap( a, b ); + + auto it = checkedPairs.find( { a, b } ); + + // If we get an error, mark the pair as having a clearance error already + // Only continue if we are reporting all track errors + if( !testTrackAgainstItem( track, trackShape.get(), layer, other ) ) + { + if( it != checkedPairs.end() ) + it->second.has_error = true; + + return m_drcEngine->GetReportAllTrackErrors() && !m_drcEngine->IsCancelled(); + } + + return !m_drcEngine->IsCancelled(); }, m_board->m_DRCMaxClearance );