From 281aa74f30351525b9cc542be742bd6644487415 Mon Sep 17 00:00:00 2001 From: Jeff Young <jeff@rokeby.ie> Date: Wed, 12 Feb 2025 12:13:52 +0000 Subject: [PATCH] Performance improvements for teardrop regeneration. Avoid O(n^2) behaviour when deleting many zones from the board zones list. --- pcbnew/board.cpp | 17 +++++++++++++++++ pcbnew/board.h | 6 ++++++ pcbnew/teardrop/teardrop.cpp | 29 ++++++----------------------- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/pcbnew/board.cpp b/pcbnew/board.cpp index b26bf6d080..3fe27cfdf9 100644 --- a/pcbnew/board.cpp +++ b/pcbnew/board.cpp @@ -1187,6 +1187,23 @@ void BOARD::FinalizeBulkRemove( std::vector<BOARD_ITEM*>& aRemovedItems ) } +void BOARD::BulkRemoveStaleTeardrops( BOARD_COMMIT& aCommit ) +{ + for( int ii = (int) m_zones.size() - 1; ii > 0; --ii ) + { + ZONE* zone = m_zones[ii]; + + if( zone->IsTeardropArea() && zone->HasFlag( STRUCT_DELETED ) ) + { + m_itemByIdCache.erase( zone->m_Uuid ); + m_zones.erase( m_zones.begin() + ii ); + m_connectivity->Remove( zone ); + aCommit.Removed( zone ); + } + } +} + + void BOARD::Remove( BOARD_ITEM* aBoardItem, REMOVE_MODE aRemoveMode ) { // find these calls and fix them! Don't send me no stinking' nullptr. diff --git a/pcbnew/board.h b/pcbnew/board.h index 08c0f5f621..6f304e8ca8 100644 --- a/pcbnew/board.h +++ b/pcbnew/board.h @@ -424,6 +424,12 @@ public: PCB_GENERATOR_T, PCB_FOOTPRINT_T, PCB_TRACE_T, PCB_SHAPE_T } ); + /** + * Remove all teardrop zones with the STRUCT_DELETED flag set. This avoids O(n^2) traversal + * over the zone list. + */ + void BulkRemoveStaleTeardrops( BOARD_COMMIT& aCommit ); + /** * Must be used if Add() is used using a BULK_x ADD_MODE to generate a change event for * listeners. diff --git a/pcbnew/teardrop/teardrop.cpp b/pcbnew/teardrop/teardrop.cpp index e2daf9d0a8..594f5b725a 100644 --- a/pcbnew/teardrop/teardrop.cpp +++ b/pcbnew/teardrop/teardrop.cpp @@ -101,7 +101,6 @@ void TEARDROP_MANAGER::RemoveTeardrops( BOARD_COMMIT& aCommit, const std::set<PCB_TRACK*>* dirtyTracks ) { std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity(); - std::vector<ZONE*> stale_teardrops; auto isStale = [&]( ZONE* zone ) @@ -135,14 +134,10 @@ void TEARDROP_MANAGER::RemoveTeardrops( BOARD_COMMIT& aCommit, for( ZONE* zone : m_board->Zones() ) { if( zone->IsTeardropArea() && isStale( zone ) ) - stale_teardrops.push_back( zone ); + zone->SetFlags( STRUCT_DELETED ); } - for( ZONE* td : stale_teardrops ) - { - m_board->Remove( td, REMOVE_MODE::BULK ); - aCommit.Removed( td ); - } + m_board->BulkRemoveStaleTeardrops( aCommit ); } @@ -162,19 +157,13 @@ void TEARDROP_MANAGER::UpdateTeardrops( BOARD_COMMIT& aCommit, // Old teardrops must be removed, to ensure a clean teardrop rebuild if( aForceFullUpdate ) { - std::vector<ZONE*> teardrops; - for( ZONE* zone : m_board->Zones() ) { if( zone->IsTeardropArea() ) - teardrops.push_back( zone ); + zone->SetFlags( STRUCT_DELETED ); } - for( ZONE* td : teardrops ) - { - m_board->Remove( td, REMOVE_MODE::BULK ); - aCommit.Removed( td ); - } + m_board->BulkRemoveStaleTeardrops( aCommit ); } std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity(); @@ -283,19 +272,13 @@ void TEARDROP_MANAGER::UpdateTeardrops( BOARD_COMMIT& aCommit, void TEARDROP_MANAGER::DeleteTrackToTrackTeardrops( BOARD_COMMIT& aCommit ) { - std::vector<ZONE*> stale_teardrops; - for( ZONE* zone : m_board->Zones() ) { if( zone->IsTeardropArea() && zone->GetTeardropAreaType() == TEARDROP_TYPE::TD_TRACKEND ) - stale_teardrops.push_back( zone ); + zone->SetFlags( STRUCT_DELETED ); } - for( ZONE* td : stale_teardrops ) - { - m_board->Remove( td, REMOVE_MODE::BULK ); - aCommit.Removed( td ); - } + m_board->BulkRemoveStaleTeardrops( aCommit ); }