7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-21 00:21:25 +00:00

Collide (and generate violations) based on a well-defined order...

... so that exclusion checking against previously-generated
violations will work.
This commit is contained in:
Jeff Young 2024-12-17 18:32:16 +00:00
parent 0b98706876
commit 2ae321084f
5 changed files with 90 additions and 33 deletions

View File

@ -92,8 +92,8 @@ private:
* @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 testSingleLayerItemAgainstItem( BOARD_CONNECTED_ITEM* item, SHAPE* itemShape,
PCB_LAYER_ID layer, BOARD_ITEM* other );
bool testSingleLayerItemAgainstItem( BOARD_ITEM* item, SHAPE* itemShape, PCB_LAYER_ID layer,
BOARD_ITEM* other );
void testTrackClearances();
@ -198,7 +198,7 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::Run()
}
bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testSingleLayerItemAgainstItem( BOARD_CONNECTED_ITEM* item,
bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testSingleLayerItemAgainstItem( BOARD_ITEM* item,
SHAPE* itemShape,
PCB_LAYER_ID layer,
BOARD_ITEM* other )
@ -211,12 +211,19 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testSingleLayerItemAgainstItem( BOARD_C
int actual;
VECTOR2I pos;
bool has_error = false;
int otherNet = 0;
NETINFO_ITEM* net = nullptr;
NETINFO_ITEM* otherNet = nullptr;
if( BOARD_CONNECTED_ITEM* connectedItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
net = connectedItem->GetNet();
NETINFO_ITEM* trackNet = net;
if( BOARD_CONNECTED_ITEM* connectedItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( other ) )
otherNet = connectedItem->GetNetCode();
otherNet = connectedItem->GetNet();
std::shared_ptr<SHAPE> otherShape = other->GetEffectiveShape( layer );
std::shared_ptr<SHAPE> otherShapeStorage = other->GetEffectiveShape( layer );
SHAPE* otherShape = otherShapeStorage.get();
if( other->Type() == PCB_PAD_T )
{
@ -234,6 +241,15 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testSingleLayerItemAgainstItem( BOARD_C
if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE && clearance > 0 )
{
// Collide (and generate violations) based on a well-defined order so that exclusion
// checking against previously-generated violations will work.
if( item->m_Uuid > other->m_Uuid )
{
std::swap( item, other );
std::swap( itemShape, otherShape );
std::swap( net, otherNet );
}
// Special processing for track:track intersections
if( item->Type() == PCB_TRACE_T && other->Type() == PCB_TRACE_T )
{
@ -255,9 +271,9 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testSingleLayerItemAgainstItem( BOARD_C
}
}
if( itemShape->Collide( otherShape.get(), clearance - m_drcEpsilon, &actual, &pos ) )
if( itemShape->Collide( otherShape, clearance - m_drcEpsilon, &actual, &pos ) )
{
if( m_drcEngine->IsNetTieExclusion( item->GetNetCode(), layer, pos, other ) )
if( m_drcEngine->IsNetTieExclusion( trackNet->GetNetCode(), layer, pos, other ) )
{
// Collision occurred as track was entering a pad marked as a net-tie. We
// allow these.
@ -267,8 +283,7 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testSingleLayerItemAgainstItem( BOARD_C
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_SHORTING_ITEMS );
wxString msg;
msg.Printf( _( "(nets %s and %s)" ), item->GetNetname(),
static_cast<BOARD_CONNECTED_ITEM*>( other )->GetNetname() );
msg.Printf( _( "(nets %s and %s)" ), net->GetNetname(), otherNet->GetNetname() );
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
drce->SetItems( item, other );
@ -304,7 +319,7 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testSingleLayerItemAgainstItem( BOARD_C
{
std::array<BOARD_ITEM*, 2> a{ item, other };
std::array<BOARD_ITEM*, 2> b{ other, item };
std::array<SHAPE*, 2> a_shape{ itemShape, otherShape.get() };
std::array<SHAPE*, 2> a_shape{ itemShape, otherShape };
for( size_t ii = 0; ii < 2; ++ii )
{
@ -316,6 +331,7 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testSingleLayerItemAgainstItem( BOARD_C
{
continue;
}
if( b[ii]->Type() == PCB_VIA_T )
{
if( b[ii]->GetLayerSet().Contains( layer ) )

View File

@ -153,9 +153,22 @@ bool DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testCourtyardClearances()
const int progressDelta = 100;
int ii = 0;
for( auto itA = m_board->Footprints().begin(); itA != m_board->Footprints().end(); itA++ )
// Stable sorting gives stable violation generation (and stable comparisons to previously-
// generated violations for exclusion checking).
std::vector<FOOTPRINT*> footprints;
footprints.insert( footprints.begin(), m_board->Footprints().begin(),
m_board->Footprints().end() );
std::sort( footprints.begin(), footprints.end(),
[]( const FOOTPRINT* a, const FOOTPRINT* b )
{
return a->m_Uuid < b->m_Uuid;
} );
for( auto itA = footprints.begin(); itA != footprints.end(); itA++ )
{
if( !reportProgress( ii++, m_board->Footprints().size(), progressDelta ) )
if( !reportProgress( ii++, footprints.size(), progressDelta ) )
return false; // DRC cancelled
// Ensure tests realted to courtyard constraints are not fully disabled:
@ -186,7 +199,7 @@ bool DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testCourtyardClearances()
BOX2I fpA_bbox = fpA->GetBoundingBox();
for( auto itB = itA + 1; itB != m_board->Footprints().end(); itB++ )
for( auto itB = itA + 1; itB != footprints.end(); itB++ )
{
FOOTPRINT* fpB = *itB;
const SHAPE_POLY_SET& frontB = fpB->GetCourtyard( F_CrtYd );

View File

@ -291,6 +291,11 @@ bool DRC_TEST_PROVIDER_HOLE_TO_HOLE::testHoleAgainstHole( BOARD_ITEM* aItem, SHA
{
if( reportCoLocation )
{
// Generate violations based on a well-defined order so that exclusion checking
// against previously-generated violations will work.
if( aItem->m_Uuid > aOther->m_Uuid )
std::swap( aItem, aOther );
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_DRILLED_HOLES_COLOCATED );
drce->SetItems( aItem, aOther );
reportViolation( drce, aHole->GetCenter(), UNDEFINED_LAYER );
@ -309,6 +314,11 @@ bool DRC_TEST_PROVIDER_HOLE_TO_HOLE::testHoleAgainstHole( BOARD_ITEM* aItem, SHA
&& minClearance >= 0
&& actual < minClearance )
{
// Generate violations based on a well-defined order so that exclusion checking
// against previously-generated violations will work.
if( aItem->m_Uuid > aOther->m_Uuid )
std::swap( aItem, aOther );
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_DRILLED_HOLES_TOO_CLOSE );
wxString msg = formatMsg( _( "(%s min %s; actual %s)" ),
constraint.GetName(),

View File

@ -73,7 +73,7 @@ public:
private:
int testItemAgainstItem( BOARD_ITEM* aItem, SHAPE* aItemShape, PCB_LAYER_ID aLayer,
BOARD_ITEM* other );
BOARD_ITEM* aOther );
void testItemAgainstZones( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer );
@ -611,9 +611,9 @@ void DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testZoneLayer( ZONE* aZone, PCB_LAYER
int DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstItem( BOARD_ITEM* aItem,
SHAPE* aItemShape,
PCB_LAYER_ID aLayer,
BOARD_ITEM* other )
SHAPE* aItemShape,
PCB_LAYER_ID aLayer,
BOARD_ITEM* aOther )
{
bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
bool testHoles = !m_drcEngine->IsErrorLimitExceeded( DRCE_HOLE_CLEARANCE );
@ -623,17 +623,26 @@ int DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstItem( BOARD_ITEM* aItem
int violations = 0;
VECTOR2I pos;
std::shared_ptr<SHAPE> otherShape = other->GetEffectiveShape( aLayer );
std::shared_ptr<SHAPE> otherShapeStorage = aOther->GetEffectiveShape( aLayer );
SHAPE* otherShape = otherShapeStorage.get();
if( testClearance )
{
constraint = m_drcEngine->EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, aItem, other, aLayer );
constraint = m_drcEngine->EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, aItem, aOther, aLayer );
clearance = constraint.GetValue().Min();
}
if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE && clearance > 0 )
{
if( aItemShape->Collide( otherShape.get(), clearance, &actual, &pos ) )
// Collide (and generate violations) based on a well-defined order so that exclusion
// checking against previously-generated violations will work.
if( aItem->m_Uuid > aOther->m_Uuid )
{
std::swap( aItem, aOther );
std::swap( aItemShape, otherShape );
}
if( aItemShape->Collide( otherShape, clearance, &actual, &pos ) )
{
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
wxString msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
@ -642,7 +651,7 @@ int DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstItem( BOARD_ITEM* aItem
actual );
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
drce->SetItems( aItem, other );
drce->SetItems( aItem, aOther );
drce->SetViolatingRule( constraint.GetParentRule() );
reportViolation( drce, pos, aLayer );
@ -679,9 +688,9 @@ int DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstItem( BOARD_ITEM* aItem
itemHoleShape = aItem->GetEffectiveHoleShape();
}
if( other->Type() == PCB_VIA_T )
if( aOther->Type() == PCB_VIA_T )
{
LSET layers = other->GetLayerSet();
LSET layers = aOther->GetLayerSet();
if( layers.Contains( F_Cu ) )
layers |= LSET::FrontBoardTechMask().set( F_CrtYd );
@ -695,23 +704,23 @@ int DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstItem( BOARD_ITEM* aItem
wxCHECK_MSG( layers.Contains( aLayer ), violations,
wxT( "Bug! Vias should only be checked for layers on which they exist" ) );
otherHoleShape = other->GetEffectiveHoleShape();
otherHoleShape = aOther->GetEffectiveHoleShape();
}
else if( other->HasHole() )
else if( aOther->HasHole() )
{
otherHoleShape = other->GetEffectiveHoleShape();
otherHoleShape = aOther->GetEffectiveHoleShape();
}
if( itemHoleShape || otherHoleShape )
{
constraint = m_drcEngine->EvalRules( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT, other, aItem,
constraint = m_drcEngine->EvalRules( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT, aOther, aItem,
aLayer );
clearance = constraint.GetValue().Min();
}
if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE && clearance > 0 )
{
if( itemHoleShape && itemHoleShape->Collide( otherShape.get(), clearance, &actual, &pos ) )
if( itemHoleShape && itemHoleShape->Collide( otherShape, clearance, &actual, &pos ) )
{
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
wxString msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
@ -720,7 +729,7 @@ int DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstItem( BOARD_ITEM* aItem
actual );
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
drce->SetItems( aItem, other );
drce->SetItems( aItem, aOther );
drce->SetViolatingRule( constraint.GetParentRule() );
reportViolation( drce, pos, aLayer );
@ -736,7 +745,7 @@ int DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstItem( BOARD_ITEM* aItem
actual );
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
drce->SetItems( aItem, other );
drce->SetItems( aItem, aOther );
drce->SetViolatingRule( constraint.GetParentRule() );
reportViolation( drce, pos, aLayer );

View File

@ -23,8 +23,6 @@
#include <common.h>
#include <board.h>
#include <footprint.h>
#include <pcb_shape.h>
#include <pcb_track.h>
#include <geometry/shape_segment.h>
#include <geometry/seg.h>
@ -226,6 +224,17 @@ bool DRC_TEST_PROVIDER_SILK_CLEARANCE::Run()
return true;
}
// Collide (and generate violations) based on a well-defined order so that
// exclusion checking against previously-generated violations will work.
if( aLayers.first == aLayers.second )
{
if( refItem->m_Uuid > testItem->m_Uuid )
{
std::swap( refItem, testItem );
std::swap( refShape, testShape );
}
}
if( refShape->Collide( testShape, minClearance, &actual, &pos ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_OVERLAPPING_SILK );