Fix DRC performance with multi-layer keepout zones.
The main issue was a parameter mismatch which caused On^2 behaviour for zone layers. But there are several other performance optimizations here, along with status bar updating for zones while running the dissallow test. Fixes https://gitlab.com/kicad/code/kicad/issues/8521
This commit is contained in:
parent
b6de4da686
commit
00ed75b891
|
@ -736,7 +736,7 @@ void DRC_ENGINE::RunTests( EDA_UNITS aUnits, bool aReportAllTrackErrors, bool aT
|
|||
|
||||
m_board->m_CopperZoneRTrees[ zone ] = std::make_unique<DRC_RTREE>();
|
||||
|
||||
for( int layer : zone->GetLayerSet().Seq() )
|
||||
for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
|
||||
{
|
||||
if( IsCopperLayer( layer ) )
|
||||
m_board->m_CopperZoneRTrees[ zone ]->Insert( zone, layer );
|
||||
|
|
|
@ -81,16 +81,17 @@ public:
|
|||
|
||||
/**
|
||||
* Function Insert()
|
||||
* Inserts an item into the tree.
|
||||
* Inserts an item into the tree on a particular layer with an optional worst clearance.
|
||||
*/
|
||||
void Insert( BOARD_ITEM* aItem, int aWorstClearance = 0, int aLayer = UNDEFINED_LAYER )
|
||||
void Insert( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, int aWorstClearance = 0 )
|
||||
{
|
||||
std::vector<SHAPE*> subshapes;
|
||||
wxASSERT( aLayer != UNDEFINED_LAYER );
|
||||
|
||||
auto addLayer =
|
||||
[&]( PCB_LAYER_ID layer )
|
||||
{
|
||||
std::shared_ptr<SHAPE> shape = aItem->GetEffectiveShape( layer );
|
||||
if( aItem->Type() == PCB_FP_TEXT_T && !static_cast<FP_TEXT*>( aItem )->IsVisible() )
|
||||
return;
|
||||
|
||||
std::vector<SHAPE*> subshapes;
|
||||
std::shared_ptr<SHAPE> shape = aItem->GetEffectiveShape( ToLAYER_ID( aLayer ) );
|
||||
subshapes.clear();
|
||||
|
||||
if( shape->HasIndexableSubshapes() )
|
||||
|
@ -106,36 +107,11 @@ public:
|
|||
|
||||
const int mmin[2] = { bbox.GetX(), bbox.GetY() };
|
||||
const int mmax[2] = { bbox.GetRight(), bbox.GetBottom() };
|
||||
ITEM_WITH_SHAPE* itemShape = new ITEM_WITH_SHAPE( aItem, subshape, shape );
|
||||
|
||||
m_tree[layer]->Insert( mmin, mmax, new ITEM_WITH_SHAPE( aItem, subshape,
|
||||
shape ) );
|
||||
m_tree[aLayer]->Insert( mmin, mmax, itemShape );
|
||||
m_count++;
|
||||
}
|
||||
};
|
||||
|
||||
if( aItem->Type() == PCB_FP_TEXT_T && !static_cast<FP_TEXT*>( aItem )->IsVisible() )
|
||||
return;
|
||||
|
||||
if( aLayer != UNDEFINED_LAYER )
|
||||
{
|
||||
addLayer( (PCB_LAYER_ID) aLayer );
|
||||
}
|
||||
else
|
||||
{
|
||||
LSET layers = aItem->GetLayerSet();
|
||||
|
||||
// Special-case pad holes which pierce all the copper layers
|
||||
if( aItem->Type() == PCB_PAD_T )
|
||||
{
|
||||
PAD* pad = static_cast<PAD*>( aItem );
|
||||
|
||||
if( pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0 )
|
||||
layers |= LSET::AllCuMask();
|
||||
}
|
||||
|
||||
for( int layer : layers.Seq() )
|
||||
addLayer( (PCB_LAYER_ID) layer );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -261,7 +237,7 @@ public:
|
|||
* position.
|
||||
*/
|
||||
bool QueryColliding( EDA_RECT aBox, SHAPE* aRefShape, PCB_LAYER_ID aLayer, int aClearance,
|
||||
int* aActual = nullptr, VECTOR2I* aPos = nullptr ) const
|
||||
int* aActual, VECTOR2I* aPos ) const
|
||||
{
|
||||
aBox.Inflate( aClearance );
|
||||
|
||||
|
@ -308,6 +284,32 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quicker version of above that just reports a raw yes/no.
|
||||
*/
|
||||
bool QueryColliding( EDA_RECT aBox, SHAPE* aRefShape, PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
int min[2] = { aBox.GetX(), aBox.GetY() };
|
||||
int max[2] = { aBox.GetRight(), aBox.GetBottom() };
|
||||
bool collision = false;
|
||||
|
||||
auto visit =
|
||||
[&]( ITEM_WITH_SHAPE* aItem ) -> bool
|
||||
{
|
||||
if( aRefShape->Collide( aItem->shape, 0 ) )
|
||||
{
|
||||
collision = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
this->m_tree[aLayer]->Search( min, max, visit );
|
||||
|
||||
return collision;
|
||||
}
|
||||
|
||||
typedef std::pair<PCB_LAYER_ID, PCB_LAYER_ID> LAYER_PAIR;
|
||||
|
||||
struct PAIR_INFO
|
||||
|
|
|
@ -165,7 +165,23 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::Run()
|
|||
if( !reportProgress( ii++, count, delta ) )
|
||||
return false;
|
||||
|
||||
m_copperTree.Insert( item, m_largestClearance );
|
||||
LSET layers = item->GetLayerSet();
|
||||
|
||||
// Special-case pad holes which pierce all the copper layers
|
||||
if( item->Type() == PCB_PAD_T )
|
||||
{
|
||||
PAD* pad = static_cast<PAD*>( item );
|
||||
|
||||
if( pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0 )
|
||||
layers |= LSET::AllCuMask();
|
||||
}
|
||||
|
||||
for( PCB_LAYER_ID layer : layers.Seq() )
|
||||
{
|
||||
if( IsCopperLayer( layer ) )
|
||||
m_copperTree.Insert( item, layer, m_largestClearance );
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
|
|
@ -329,7 +329,12 @@ bool test::DRC_TEST_PROVIDER_DIFF_PAIR_COUPLING::Run()
|
|||
auto addToTree =
|
||||
[&copperTree]( BOARD_ITEM *item ) -> bool
|
||||
{
|
||||
copperTree.Insert( item );
|
||||
for( PCB_LAYER_ID layer : item->GetLayerSet().Seq() )
|
||||
{
|
||||
if( IsCopperLayer( layer ) )
|
||||
copperTree.Insert( item, layer );
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
|
|
@ -68,6 +68,12 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run()
|
|||
if( !reportPhase( _( "Checking keepouts & disallow constraints..." ) ) )
|
||||
return false; // DRC cancelled
|
||||
|
||||
// Zones can be expensive (particularly when multi-layer), so we run the progress bar on them
|
||||
BOARD* board = m_drcEngine->GetBoard();
|
||||
int boardZoneCount = board->Zones().size();
|
||||
int delta = std::max( 1, boardZoneCount / board->GetCopperLayerCount() );
|
||||
int ii = 0;
|
||||
|
||||
auto doCheckItem =
|
||||
[&]( BOARD_ITEM* item )
|
||||
{
|
||||
|
@ -123,6 +129,12 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run()
|
|||
|
||||
if( zone->GetIsRuleArea() )
|
||||
return true;
|
||||
|
||||
if( item->Type() == PCB_ZONE_T )
|
||||
{
|
||||
if( !reportProgress( ii++, boardZoneCount, delta ) )
|
||||
return false; // DRC cancelled
|
||||
}
|
||||
}
|
||||
|
||||
item->ClearFlags( HOLE_PROXY );
|
||||
|
|
|
@ -208,7 +208,13 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
|
|||
forEachGeometryItem( s_allBasicItemsButZones, LSET::AllCuMask(), queryBoardGeometryItems );
|
||||
|
||||
for( const std::unique_ptr<PCB_SHAPE>& edge : edges )
|
||||
edgesTree.Insert( edge.get(), m_largestClearance );
|
||||
{
|
||||
for( PCB_LAYER_ID layer : { Edge_Cuts, Margin } )
|
||||
{
|
||||
if( edge->IsOnLayer( layer ) )
|
||||
edgesTree.Insert( edge.get(), layer, m_largestClearance );
|
||||
}
|
||||
}
|
||||
|
||||
wxString val;
|
||||
wxGetEnv( "WXTRACE", &val );
|
||||
|
|
|
@ -151,7 +151,7 @@ bool DRC_TEST_PROVIDER_HOLE_TO_HOLE::Run()
|
|||
|
||||
// We only care about drilled (ie: round) holes
|
||||
if( pad->GetDrillSize().x && pad->GetDrillSize().x == pad->GetDrillSize().y )
|
||||
m_holeTree.Insert( item, m_largestClearance, F_Cu );
|
||||
m_holeTree.Insert( item, F_Cu, m_largestClearance );
|
||||
}
|
||||
else if( item->Type() == PCB_VIA_T )
|
||||
{
|
||||
|
@ -159,7 +159,7 @@ bool DRC_TEST_PROVIDER_HOLE_TO_HOLE::Run()
|
|||
|
||||
// We only care about mechanically drilled (ie: non-laser) holes
|
||||
if( via->GetViaType() == VIATYPE::THROUGH )
|
||||
m_holeTree.Insert( item, m_largestClearance, F_Cu );
|
||||
m_holeTree.Insert( item, F_Cu, m_largestClearance );
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -112,7 +112,12 @@ bool DRC_TEST_PROVIDER_SILK_CLEARANCE::Run()
|
|||
auto addToSilkTree =
|
||||
[&silkTree]( BOARD_ITEM* item ) -> bool
|
||||
{
|
||||
silkTree.Insert( item );
|
||||
for( PCB_LAYER_ID layer : { F_SilkS, B_SilkS } )
|
||||
{
|
||||
if( item->IsOnLayer( layer ) )
|
||||
silkTree.Insert( item, layer );
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
@ -129,7 +134,9 @@ bool DRC_TEST_PROVIDER_SILK_CLEARANCE::Run()
|
|||
if( !reportProgress( ii++, targets, delta ) )
|
||||
return false;
|
||||
|
||||
targetTree.Insert( item );
|
||||
for( PCB_LAYER_ID layer : item->GetLayerSet().Seq() )
|
||||
targetTree.Insert( item, layer );
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
|
|
@ -104,14 +104,24 @@ bool DRC_TEST_PROVIDER_SILK_TO_MASK::Run()
|
|||
auto addMaskToTree =
|
||||
[&maskTree]( BOARD_ITEM *item ) -> bool
|
||||
{
|
||||
maskTree.Insert( item );
|
||||
for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
|
||||
{
|
||||
if( item->IsOnLayer( layer ) )
|
||||
maskTree.Insert( item, layer );
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto addSilkToTree =
|
||||
[&silkTree]( BOARD_ITEM *item ) -> bool
|
||||
{
|
||||
silkTree.Insert( item );
|
||||
for( PCB_LAYER_ID layer : { F_SilkS, B_SilkS } )
|
||||
{
|
||||
if( item->IsOnLayer( layer ) )
|
||||
silkTree.Insert( item, layer );
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
|
|
@ -540,11 +540,13 @@ static void insideArea( LIBEVAL::CONTEXT* aCtx, void* self )
|
|||
|
||||
DRC_RTREE* zoneRTree = board->m_CopperZoneRTrees[ zone ].get();
|
||||
|
||||
std::vector<SHAPE*> shapes;
|
||||
|
||||
if( zoneRTree )
|
||||
{
|
||||
for( PCB_LAYER_ID layer : area->GetLayerSet().Seq() )
|
||||
{
|
||||
if( zoneRTree->QueryColliding( itemBBox, &areaOutline, layer, 0 ) )
|
||||
if( zoneRTree->QueryColliding( itemBBox, &areaOutline, layer ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -275,7 +275,7 @@ void TRACKS_CLEANER::cleanup( bool aDeleteDuplicateVias, bool aDeleteNullSegment
|
|||
for( TRACK* track : m_brd->Tracks() )
|
||||
{
|
||||
track->ClearFlags( IS_DELETED | SKIP_STRUCT );
|
||||
rtree.Insert( track );
|
||||
rtree.Insert( track, track->GetLayer() );
|
||||
}
|
||||
|
||||
std::set<BOARD_ITEM*> toRemove;
|
||||
|
|
Loading…
Reference in New Issue