Implement a more durable zone bounding box caching strategy.
Fixes https://gitlab.com/kicad/code/kicad/issues/10821
This commit is contained in:
parent
6d298b661a
commit
e49de68a59
|
@ -232,6 +232,7 @@ void BOARD::IncrementTimeStamp()
|
|||
m_DRCCopperZones.clear();
|
||||
m_CopperZoneRTreeCache.clear();
|
||||
m_CopperItemRTreeCache = std::make_unique<DRC_RTREE>();
|
||||
m_ZoneBBoxCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1152,6 +1152,8 @@ public:
|
|||
std::unordered_map<ZONE*, std::unique_ptr<DRC_RTREE>> m_CopperZoneRTreeCache;
|
||||
std::unique_ptr<DRC_RTREE> m_CopperItemRTreeCache;
|
||||
|
||||
mutable std::unordered_map<const ZONE*, BOX2I> m_ZoneBBoxCache;
|
||||
|
||||
// ------------ DRC caches -------------
|
||||
std::vector<ZONE*> m_DRCZones;
|
||||
std::vector<ZONE*> m_DRCCopperZones;
|
||||
|
|
|
@ -149,7 +149,7 @@ void BOARD_COMMIT::dirtyIntersectingZones( BOARD_ITEM* item )
|
|||
continue;
|
||||
|
||||
if( ( zone->GetLayerSet() & layers ).any()
|
||||
&& zone->GetCachedBoundingBox().Intersects( bbox ) )
|
||||
&& zone->GetBoundingBox().Intersects( bbox ) )
|
||||
{
|
||||
zoneFillerTool->DirtyZone( zone );
|
||||
}
|
||||
|
|
|
@ -314,7 +314,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZone( BOARD_ITEM* aItem,
|
|||
|
||||
worstCaseBBox.Inflate( m_board->m_DRCMaxClearance );
|
||||
|
||||
if( !worstCaseBBox.Intersects( aZone->GetCachedBoundingBox() ) )
|
||||
if( !worstCaseBBox.Intersects( aZone->GetBoundingBox() ) )
|
||||
return;
|
||||
|
||||
bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
|
||||
|
|
|
@ -116,8 +116,8 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run()
|
|||
|
||||
ZONE* ruleArea = areaZonePair.first;
|
||||
ZONE* copperZone = areaZonePair.second;
|
||||
BOX2I areaBBox = ruleArea->GetCachedBoundingBox();
|
||||
BOX2I copperBBox = copperZone->GetCachedBoundingBox();
|
||||
BOX2I areaBBox = ruleArea->GetBoundingBox();
|
||||
BOX2I copperBBox = copperZone->GetBoundingBox();
|
||||
bool isInside = false;
|
||||
|
||||
if( copperZone->IsFilled() && areaBBox.Intersects( copperBBox ) )
|
||||
|
|
|
@ -706,7 +706,7 @@ void DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstZones( BOARD_ITEM* aIt
|
|||
|
||||
worstCaseBBox.Inflate( m_board->m_DRCMaxClearance );
|
||||
|
||||
if( !worstCaseBBox.Intersects( zone->GetCachedBoundingBox() ) )
|
||||
if( !worstCaseBBox.Intersects( zone->GetBoundingBox() ) )
|
||||
continue;
|
||||
|
||||
bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
|
||||
|
|
|
@ -582,7 +582,7 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::testMaskItemAgainstZones( BOARD_ITEM* aItem,
|
|||
|
||||
inflatedBBox.Inflate( clearance );
|
||||
|
||||
if( !inflatedBBox.Intersects( zone->GetCachedBoundingBox() ) )
|
||||
if( !inflatedBBox.Intersects( zone->GetBoundingBox() ) )
|
||||
continue;
|
||||
|
||||
DRC_RTREE* zoneTree = m_board->m_CopperZoneRTreeCache[ zone ].get();
|
||||
|
|
|
@ -101,7 +101,7 @@ void DRC_TEST_PROVIDER_ZONE_CONNECTIONS::testZoneLayer( ZONE* aZone, PCB_LAYER_I
|
|||
|
||||
BOX2I item_bbox = pad->GetBoundingBox();
|
||||
|
||||
if( !item_bbox.Intersects( aZone->GetCachedBoundingBox() ) )
|
||||
if( !item_bbox.Intersects( aZone->GetBoundingBox() ) )
|
||||
continue;
|
||||
|
||||
if( !pad->FlashLayer( aLayer ) )
|
||||
|
|
|
@ -406,7 +406,7 @@ static void intersectsBackCourtyardFunc( LIBEVAL::CONTEXT* aCtx, void* self )
|
|||
bool collidesWithArea( BOARD_ITEM* aItem, PCB_EXPR_CONTEXT* aCtx, ZONE* aArea )
|
||||
{
|
||||
BOARD* board = aArea->GetBoard();
|
||||
BOX2I areaBBox = aArea->GetCachedBoundingBox();
|
||||
BOX2I areaBBox = aArea->GetBoundingBox();
|
||||
std::shared_ptr<SHAPE> shape;
|
||||
|
||||
// Collisions include touching, so we need to deflate outline by enough to exclude it.
|
||||
|
@ -621,12 +621,7 @@ static void intersectsAreaFunc( LIBEVAL::CONTEXT* aCtx, void* self )
|
|||
{
|
||||
BOARD* board = item->GetBoard();
|
||||
PCB_LAYER_ID layer = context->GetLayer();
|
||||
BOX2I itemBBox;
|
||||
|
||||
if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
|
||||
itemBBox = static_cast<ZONE*>( item )->GetCachedBoundingBox();
|
||||
else
|
||||
itemBBox = item->GetBoundingBox();
|
||||
BOX2I itemBBox = item->GetBoundingBox();
|
||||
|
||||
if( searchAreas( board, arg->AsString(), context,
|
||||
[&]( ZONE* aArea )
|
||||
|
@ -634,7 +629,7 @@ static void intersectsAreaFunc( LIBEVAL::CONTEXT* aCtx, void* self )
|
|||
if( !aArea || aArea == item || aArea->GetParent() == item )
|
||||
return false;
|
||||
|
||||
if( !aArea->GetCachedBoundingBox().Intersects( itemBBox ) )
|
||||
if( !aArea->GetBoundingBox().Intersects( itemBBox ) )
|
||||
return false;
|
||||
|
||||
std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex );
|
||||
|
@ -689,12 +684,7 @@ static void enclosedByAreaFunc( LIBEVAL::CONTEXT* aCtx, void* self )
|
|||
BOARD* board = item->GetBoard();
|
||||
int maxError = board->GetDesignSettings().m_MaxError;
|
||||
PCB_LAYER_ID layer = context->GetLayer();
|
||||
BOX2I itemBBox;
|
||||
|
||||
if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
|
||||
itemBBox = static_cast<ZONE*>( item )->GetCachedBoundingBox();
|
||||
else
|
||||
itemBBox = item->GetBoundingBox();
|
||||
BOX2I itemBBox = item->GetBoundingBox();
|
||||
|
||||
if( searchAreas( board, arg->AsString(), context,
|
||||
[&]( ZONE* aArea )
|
||||
|
@ -702,7 +692,7 @@ static void enclosedByAreaFunc( LIBEVAL::CONTEXT* aCtx, void* self )
|
|||
if( !aArea || aArea == item || aArea->GetParent() == item )
|
||||
return false;
|
||||
|
||||
if( !aArea->GetCachedBoundingBox().Intersects( itemBBox ) )
|
||||
if( !aArea->GetBoundingBox().Intersects( itemBBox ) )
|
||||
return false;
|
||||
|
||||
std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex );
|
||||
|
|
|
@ -308,10 +308,34 @@ bool ZONE::IsOnLayer( PCB_LAYER_ID aLayer ) const
|
|||
|
||||
const BOX2I ZONE::GetBoundingBox() const
|
||||
{
|
||||
if( const BOARD* parent = GetBoard() )
|
||||
{
|
||||
std::unordered_map<const ZONE*, BOX2I>& cache = parent->m_ZoneBBoxCache;
|
||||
auto cacheIter = cache.find( this );
|
||||
|
||||
if( cacheIter != cache.end() )
|
||||
return cacheIter->second;
|
||||
|
||||
BOX2I bbox = m_Poly->BBox();
|
||||
cache[ this ] = bbox;
|
||||
return bbox;
|
||||
}
|
||||
|
||||
return m_Poly->BBox();
|
||||
}
|
||||
|
||||
|
||||
void ZONE::CacheBoundingBox()
|
||||
{
|
||||
std::unordered_map<const ZONE*, BOX2I>& cache = GetBoard()->m_ZoneBBoxCache;
|
||||
|
||||
auto cacheIter = cache.find( this );
|
||||
|
||||
if( cacheIter == cache.end() )
|
||||
cache[ this ] = m_Poly->BBox();
|
||||
}
|
||||
|
||||
|
||||
int ZONE::GetThermalReliefGap( PAD* aPad, wxString* aSource ) const
|
||||
{
|
||||
if( aPad->GetLocalThermalGapOverride() == 0 )
|
||||
|
@ -972,7 +996,7 @@ bool ZONE::IsIsland( PCB_LAYER_ID aLayer, int aPolyIdx ) const
|
|||
void ZONE::GetInteractingZones( PCB_LAYER_ID aLayer, std::vector<ZONE*>* aZones ) const
|
||||
{
|
||||
int epsilon = pcbIUScale.mmToIU( 0.001 );
|
||||
BOX2I bbox = GetCachedBoundingBox();
|
||||
BOX2I bbox = GetBoundingBox();
|
||||
|
||||
bbox.Inflate( epsilon );
|
||||
|
||||
|
@ -990,7 +1014,7 @@ void ZONE::GetInteractingZones( PCB_LAYER_ID aLayer, std::vector<ZONE*>* aZones
|
|||
if( candidate->GetNetCode() != GetNetCode() )
|
||||
continue;
|
||||
|
||||
if( !candidate->GetCachedBoundingBox().Intersects( bbox ) )
|
||||
if( !candidate->GetBoundingBox().Intersects( bbox ) )
|
||||
continue;
|
||||
|
||||
for( auto iter = m_Poly->CIterate(); iter; iter++ )
|
||||
|
|
|
@ -128,10 +128,10 @@ public:
|
|||
const BOX2I GetBoundingBox() const override;
|
||||
|
||||
/**
|
||||
* ONLY TO BE USED BY CLIENTS WHICH SET UP THE CACHE!
|
||||
* Used to preload the zone bounding box cache so we don't have to worry about mutex-locking
|
||||
* it each time.
|
||||
*/
|
||||
const BOX2I GetCachedBoundingBox() const { return m_bboxCache; }
|
||||
void CacheBoundingBox() { m_bboxCache = GetBoundingBox(); }
|
||||
void CacheBoundingBox();
|
||||
|
||||
/**
|
||||
* Return any local clearances set in the "classic" (ie: pre-rule) system. These are
|
||||
|
@ -869,7 +869,6 @@ protected:
|
|||
std::map<PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>> m_FilledPolysList;
|
||||
|
||||
/// Temp variables used while filling
|
||||
BOX2I m_bboxCache;
|
||||
LSET m_fillFlags;
|
||||
|
||||
/// A hash value used in zone filling calculations to see if the filled areas are up to date
|
||||
|
|
|
@ -216,10 +216,10 @@ bool ZONE_FILLER::Fill( std::vector<ZONE*>& aZones, bool aCheck, wxWindow* aPare
|
|||
|
||||
// A higher priority zone is found: if we intersect and it's not filled yet
|
||||
// then we have to wait.
|
||||
BOX2I inflatedBBox = aZone->GetCachedBoundingBox();
|
||||
BOX2I inflatedBBox = aZone->GetBoundingBox();
|
||||
inflatedBBox.Inflate( m_worstClearance );
|
||||
|
||||
if( !inflatedBBox.Intersects( aOtherZone->GetCachedBoundingBox() ) )
|
||||
if( !inflatedBBox.Intersects( aOtherZone->GetBoundingBox() ) )
|
||||
return false;
|
||||
|
||||
return aZone->Outline()->Collide( aOtherZone->Outline(), m_worstClearance );
|
||||
|
@ -619,7 +619,7 @@ void ZONE_FILLER::knockoutThermalReliefs( const ZONE* aZone, PCB_LAYER_ID aLayer
|
|||
BOX2I padBBox = pad->GetBoundingBox();
|
||||
padBBox.Inflate( m_worstClearance );
|
||||
|
||||
if( !padBBox.Intersects( aZone->GetCachedBoundingBox() ) )
|
||||
if( !padBBox.Intersects( aZone->GetBoundingBox() ) )
|
||||
continue;
|
||||
|
||||
if( pad->GetNetCode() != aZone->GetNetCode() || pad->GetNetCode() <= 0 )
|
||||
|
@ -716,7 +716,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLa
|
|||
// A small extra clearance to be sure actual track clearances are not smaller than
|
||||
// requested clearance due to many approximations in calculations, like arc to segment
|
||||
// approx, rounding issues, etc.
|
||||
BOX2I zone_boundingbox = aZone->GetCachedBoundingBox();
|
||||
BOX2I zone_boundingbox = aZone->GetBoundingBox();
|
||||
int extra_margin = pcbIUScale.mmToIU( ADVANCED_CFG::GetCfg().m_ExtraClearance );
|
||||
|
||||
// Items outside the zone bounding box are skipped, so it needs to be inflated by the
|
||||
|
@ -958,7 +958,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLa
|
|||
if( !aKnockout->GetLayerSet().test( aLayer ) )
|
||||
return;
|
||||
|
||||
if( aKnockout->GetCachedBoundingBox().Intersects( zone_boundingbox ) )
|
||||
if( aKnockout->GetBoundingBox().Intersects( zone_boundingbox ) )
|
||||
{
|
||||
if( aKnockout->GetIsRuleArea() )
|
||||
{
|
||||
|
@ -1032,6 +1032,8 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLa
|
|||
void ZONE_FILLER::subtractHigherPriorityZones( const ZONE* aZone, PCB_LAYER_ID aLayer,
|
||||
SHAPE_POLY_SET& aRawFill )
|
||||
{
|
||||
BOX2I zoneBBox = aZone->GetBoundingBox();
|
||||
|
||||
auto knockoutZoneOutline =
|
||||
[&]( ZONE* aKnockout )
|
||||
{
|
||||
|
@ -1039,7 +1041,7 @@ void ZONE_FILLER::subtractHigherPriorityZones( const ZONE* aZone, PCB_LAYER_ID a
|
|||
if( !aKnockout->GetLayerSet().test( aLayer ) )
|
||||
return;
|
||||
|
||||
if( aKnockout->GetCachedBoundingBox().Intersects( aZone->GetCachedBoundingBox() ) )
|
||||
if( aKnockout->GetBoundingBox().Intersects( zoneBBox ) )
|
||||
{
|
||||
// Processing of arc shapes in zones is not yet supported because Clipper
|
||||
// can't do boolean operations on them. The poly outline must be converted to
|
||||
|
@ -1310,7 +1312,7 @@ bool ZONE_FILLER::fillNonCopperZone( const ZONE* aZone, PCB_LAYER_ID aLayer,
|
|||
SHAPE_POLY_SET& aFillPolys )
|
||||
{
|
||||
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
||||
BOX2I zone_boundingbox = aZone->GetCachedBoundingBox();
|
||||
BOX2I zone_boundingbox = aZone->GetBoundingBox();
|
||||
SHAPE_POLY_SET clearanceHoles;
|
||||
long ticker = 0;
|
||||
|
||||
|
@ -1428,7 +1430,7 @@ void ZONE_FILLER::buildThermalSpokes( const ZONE* aZone, PCB_LAYER_ID aLayer,
|
|||
std::deque<SHAPE_LINE_CHAIN>& aSpokesList )
|
||||
{
|
||||
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
||||
BOX2I zoneBB = aZone->GetCachedBoundingBox();
|
||||
BOX2I zoneBB = aZone->GetBoundingBox();
|
||||
DRC_CONSTRAINT constraint;
|
||||
|
||||
zoneBB.Inflate( std::max( bds.GetBiggestClearanceValue(), aZone->GetLocalClearance() ) );
|
||||
|
@ -1778,7 +1780,7 @@ bool ZONE_FILLER::addHatchFillTypeOnZone( const ZONE* aZone, PCB_LAYER_ID aLayer
|
|||
// one of the holes. Effectively this means their copper outline needs to be expanded
|
||||
// to be at least as wide as the gap so that it is guaranteed to touch at least one
|
||||
// edge.
|
||||
BOX2I zone_boundingbox = aZone->GetCachedBoundingBox();
|
||||
BOX2I zone_boundingbox = aZone->GetBoundingBox();
|
||||
SHAPE_POLY_SET aprons;
|
||||
int min_apron_radius = ( aZone->GetHatchGap() * 10 ) / 19;
|
||||
|
||||
|
|
Loading…
Reference in New Issue