diff --git a/pcbnew/board.cpp b/pcbnew/board.cpp index 692f07a431..1c02119356 100644 --- a/pcbnew/board.cpp +++ b/pcbnew/board.cpp @@ -232,6 +232,7 @@ void BOARD::IncrementTimeStamp() m_DRCCopperZones.clear(); m_CopperZoneRTreeCache.clear(); m_CopperItemRTreeCache = std::make_unique(); + m_ZoneBBoxCache.clear(); } } diff --git a/pcbnew/board.h b/pcbnew/board.h index d2dd155eb9..5ff56af6b6 100644 --- a/pcbnew/board.h +++ b/pcbnew/board.h @@ -1152,6 +1152,8 @@ public: std::unordered_map> m_CopperZoneRTreeCache; std::unique_ptr m_CopperItemRTreeCache; + mutable std::unordered_map m_ZoneBBoxCache; + // ------------ DRC caches ------------- std::vector m_DRCZones; std::vector m_DRCCopperZones; diff --git a/pcbnew/board_commit.cpp b/pcbnew/board_commit.cpp index b580c7a747..c6845e5e52 100644 --- a/pcbnew/board_commit.cpp +++ b/pcbnew/board_commit.cpp @@ -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 ); } diff --git a/pcbnew/drc/drc_test_provider_copper_clearance.cpp b/pcbnew/drc/drc_test_provider_copper_clearance.cpp index fccee3dfd6..8ee6097917 100644 --- a/pcbnew/drc/drc_test_provider_copper_clearance.cpp +++ b/pcbnew/drc/drc_test_provider_copper_clearance.cpp @@ -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 ); diff --git a/pcbnew/drc/drc_test_provider_disallow.cpp b/pcbnew/drc/drc_test_provider_disallow.cpp index ccc8dd5b93..dd84fdf0fa 100644 --- a/pcbnew/drc/drc_test_provider_disallow.cpp +++ b/pcbnew/drc/drc_test_provider_disallow.cpp @@ -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 ) ) diff --git a/pcbnew/drc/drc_test_provider_physical_clearance.cpp b/pcbnew/drc/drc_test_provider_physical_clearance.cpp index 38defb0f49..3124cdae07 100644 --- a/pcbnew/drc/drc_test_provider_physical_clearance.cpp +++ b/pcbnew/drc/drc_test_provider_physical_clearance.cpp @@ -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 ); diff --git a/pcbnew/drc/drc_test_provider_solder_mask.cpp b/pcbnew/drc/drc_test_provider_solder_mask.cpp index 582b47796b..a102bd1903 100644 --- a/pcbnew/drc/drc_test_provider_solder_mask.cpp +++ b/pcbnew/drc/drc_test_provider_solder_mask.cpp @@ -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(); diff --git a/pcbnew/drc/drc_test_provider_zone_connections.cpp b/pcbnew/drc/drc_test_provider_zone_connections.cpp index 15bacdff1d..3d646d3b25 100644 --- a/pcbnew/drc/drc_test_provider_zone_connections.cpp +++ b/pcbnew/drc/drc_test_provider_zone_connections.cpp @@ -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 ) ) diff --git a/pcbnew/pcb_expr_evaluator.cpp b/pcbnew/pcb_expr_evaluator.cpp index 78636c3c24..889d0071c1 100644 --- a/pcbnew/pcb_expr_evaluator.cpp +++ b/pcbnew/pcb_expr_evaluator.cpp @@ -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; // 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( 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 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( 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 cacheLock( board->m_CachesMutex ); diff --git a/pcbnew/zone.cpp b/pcbnew/zone.cpp index b5eeb1a822..8f95f0a369 100644 --- a/pcbnew/zone.cpp +++ b/pcbnew/zone.cpp @@ -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& 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& 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* 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* 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++ ) diff --git a/pcbnew/zone.h b/pcbnew/zone.h index 937673eab0..439bf36152 100644 --- a/pcbnew/zone.h +++ b/pcbnew/zone.h @@ -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> 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 diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp index 55dcb84f11..8c0666d4d8 100644 --- a/pcbnew/zone_filler.cpp +++ b/pcbnew/zone_filler.cpp @@ -216,10 +216,10 @@ bool ZONE_FILLER::Fill( std::vector& 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& 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;