Implement progress reporting for DRC RTree.

Also fixes a bug in silk-to-mask checking which wasn't checking
zones on the mask layer.

Also a perfomance fix for the DRC RTree to use a hash table (std::map)
instead of a std::set for keeping track of known collisions.

Fixes https://gitlab.com/kicad/code/kicad/issues/5851
This commit is contained in:
Jeff Young 2020-10-12 23:59:01 +01:00
parent 5f6d309d36
commit cd1a5ed6fb
4 changed files with 69 additions and 41 deletions

View File

@ -322,24 +322,35 @@ public:
typedef std::pair<PCB_LAYER_ID, PCB_LAYER_ID> LAYER_PAIR;
struct PAIR_INFO
{
PAIR_INFO( LAYER_PAIR aPair, ITEM_WITH_SHAPE* aRef, ITEM_WITH_SHAPE* aTest ) :
layerPair( aPair ),
refItem( aRef ),
testItem( aTest )
{ };
LAYER_PAIR layerPair;
ITEM_WITH_SHAPE* refItem;
ITEM_WITH_SHAPE* testItem;
};
int QueryCollidingPairs( DRC_RTREE* aRefTree,
std::vector<LAYER_PAIR> aLayers,
std::function<bool( const LAYER_PAIR&,
ITEM_WITH_SHAPE*, ITEM_WITH_SHAPE*,
bool* aCollision )> aVisitor,
int aMaxClearance )
int aMaxClearance,
std::function<bool(int, int )> aProgressReporter )
{
// keep track of BOARD_ITEMs pairs that have been already found to collide (some items
// might be build of COMPOUND/triangulated shapes and a single subshape collision
// means we have a hit)
std::set< std::pair<BOARD_ITEM*, BOARD_ITEM*>> collidingCompounds;
std::vector< PAIR_INFO > pairsToVisit;
for( auto refLayerIter : aLayers )
for( LAYER_PAIR& refLayerIter : aLayers )
{
const PCB_LAYER_ID refLayer = refLayerIter.first;
const PCB_LAYER_ID targetLayer = refLayerIter.second;
for( auto refItem : aRefTree->OnLayer( refLayer ) )
for( ITEM_WITH_SHAPE* refItem : aRefTree->OnLayer( refLayer ) )
{
BOX2I box = refItem->shape->BBox();
box.Inflate( aMaxClearance );
@ -350,30 +361,44 @@ public:
auto visit =
[&]( ITEM_WITH_SHAPE* aItemToTest ) -> bool
{
const std::pair<BOARD_ITEM*, BOARD_ITEM*>
chkCompoundPair( refItem->parent, aItemToTest->parent );
// don't report multiple collisions for compound or triangulated shapes
if( alg::contains( collidingCompounds, chkCompoundPair ) )
return true;
// don't collide items against themselves
if( refLayer == targetLayer && aItemToTest->parent == refItem->parent )
return true;
bool collisionDetected = false;
bool continueSearch = aVisitor( refLayerIter, refItem, aItemToTest,
&collisionDetected );
if( collisionDetected )
collidingCompounds.insert( chkCompoundPair );
return continueSearch;
pairsToVisit.emplace_back( refLayerIter, refItem, aItemToTest );
return true;
};
this->m_tree[targetLayer]->Search( min, max, visit );
};
}
// keep track of BOARD_ITEMs pairs that have been already found to collide (some items
// might be build of COMPOUND/triangulated shapes and a single subshape collision
// means we have a hit)
std::map< std::pair<BOARD_ITEM*, BOARD_ITEM*>, int> collidingCompounds;
int progress = 0;
int count = pairsToVisit.size();
for( PAIR_INFO& pair : pairsToVisit )
{
if( !aProgressReporter( progress++, count ) )
break;
// don't report multiple collisions for compound or triangulated shapes
if( collidingCompounds.count( { pair.refItem->parent, pair.testItem->parent } ) )
continue;
bool collisionDetected = false;
if( !aVisitor( pair.layerPair, pair.refItem, pair.testItem, &collisionDetected ) )
break;
if( collisionDetected )
collidingCompounds[ { pair.refItem->parent, pair.testItem->parent } ] = 1;
}
return 0;
}

View File

@ -314,7 +314,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* aItem )
void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
{
// This is the number of tests between 2 calls to the progress bar
const int delta = m_drcEngine->GetTestTracksAgainstZones() ? 25 : 100;
const int delta = 25;
int count = m_board->Tracks().size();
reportAux( "Testing %d tracks...", count );

View File

@ -179,8 +179,7 @@ bool DRC_TEST_PROVIDER_SILK_CLEARANCE::Run()
return true;
};
forEachGeometryItem( { PCB_SHAPE_T, PCB_FP_SHAPE_T, PCB_TEXT_T, PCB_FP_TEXT_T },
LSET( 2, F_SilkS, B_SilkS ), addToSilkTree );
forEachGeometryItem( {}, LSET( 2, F_SilkS, B_SilkS ), addToSilkTree );
forEachGeometryItem( {}, LSET::FrontMask() | LSET::BackMask(), addToTargetTree );
reportAux( _("Testing %d silkscreen features against %d board items."),
@ -204,10 +203,17 @@ bool DRC_TEST_PROVIDER_SILK_CLEARANCE::Run()
DRC_RTREE::LAYER_PAIR( B_SilkS, B_CrtYd ),
DRC_RTREE::LAYER_PAIR( B_SilkS, B_Fab ),
DRC_RTREE::LAYER_PAIR( B_SilkS, B_Cu ),
DRC_RTREE::LAYER_PAIR( B_SilkS, Edge_Cuts ),
DRC_RTREE::LAYER_PAIR( B_SilkS, Edge_Cuts )
};
targetTree.QueryCollidingPairs( &silkTree, layerPairs, checkClearance, m_largestClearance );
// This is the number of tests between 2 calls to the progress bar
const int delta = 250;
targetTree.QueryCollidingPairs( &silkTree, layerPairs, checkClearance, m_largestClearance,
[this]( int aCount, int aSize ) -> bool
{
return reportProgress( aCount, aSize, delta );
} );
reportRuleStatistics();

View File

@ -161,20 +161,10 @@ bool DRC_TEST_PROVIDER_SILK_TO_MASK::Run()
return true;
};
int numPads = forEachGeometryItem( { PCB_PAD_T,
PCB_SHAPE_T,
PCB_FP_SHAPE_T,
PCB_TEXT_T,
PCB_FP_TEXT_T },
LSET( 2, F_Mask, B_Mask ), addMaskToTree );
int numMask = forEachGeometryItem( {}, LSET( 2, F_Mask, B_Mask ), addMaskToTree );
int numSilk = forEachGeometryItem( {}, LSET( 2, F_SilkS, B_SilkS ), addSilkToTree );
int numSilk = forEachGeometryItem( { PCB_SHAPE_T,
PCB_FP_SHAPE_T,
PCB_TEXT_T,
PCB_FP_TEXT_T },
LSET( 2, F_SilkS, B_SilkS ), addSilkToTree );
reportAux( _("Testing %d exposed copper against %d silkscreen features."), numPads, numSilk );
reportAux( _("Testing %d mask apertures against %d silkscreen features."), numMask, numSilk );
const std::vector<DRC_RTREE::LAYER_PAIR> layerPairs =
{
@ -182,7 +172,14 @@ bool DRC_TEST_PROVIDER_SILK_TO_MASK::Run()
DRC_RTREE::LAYER_PAIR( B_SilkS, B_Mask )
};
maskTree.QueryCollidingPairs( &silkTree, layerPairs, checkClearance, m_largestClearance );
// This is the number of tests between 2 calls to the progress bar
const int delta = 250;
maskTree.QueryCollidingPairs( &silkTree, layerPairs, checkClearance, m_largestClearance,
[this]( int aCount, int aSize ) -> bool
{
return reportProgress( aCount, aSize, delta );
} );
reportRuleStatistics();