Remove stale teardrops before rebuilding connectivity.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/15398
This commit is contained in:
Jeff Young 2023-08-15 10:46:31 +01:00
parent 918ada9b16
commit b986391a04
3 changed files with 95 additions and 40 deletions

View File

@ -174,6 +174,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
undoList.SetDescription( aMessage ); undoList.SetDescription( aMessage );
TEARDROP_MANAGER teardropMgr( board, m_toolMgr );
std::shared_ptr<CONNECTIVITY_DATA> connectivity = board->GetConnectivity(); std::shared_ptr<CONNECTIVITY_DATA> connectivity = board->GetConnectivity();
// Note: frame == nullptr happens in QA tests // Note: frame == nullptr happens in QA tests
@ -194,14 +195,9 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
for( COMMIT_LINE& ent : m_changes ) for( COMMIT_LINE& ent : m_changes )
{ {
int changeType = ent.m_type & CHT_TYPE;
int changeFlags = ent.m_type & CHT_FLAGS;
BOARD_ITEM* boardItem = dynamic_cast<BOARD_ITEM*>( ent.m_item ); BOARD_ITEM* boardItem = dynamic_cast<BOARD_ITEM*>( ent.m_item );
wxASSERT( ent.m_item ); if( m_isBoardEditor && boardItem )
wxCHECK2( boardItem, continue );
if( m_isBoardEditor )
{ {
if( boardItem->Type() == PCB_VIA_T || boardItem->Type() == PCB_FOOTPRINT_T if( boardItem->Type() == PCB_VIA_T || boardItem->Type() == PCB_FOOTPRINT_T
|| boardItem->IsOnLayer( F_Mask ) || boardItem->IsOnLayer( B_Mask ) ) || boardItem->IsOnLayer( F_Mask ) || boardItem->IsOnLayer( B_Mask ) )
@ -211,7 +207,12 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
if( !( aCommitFlags & SKIP_TEARDROPS ) ) if( !( aCommitFlags & SKIP_TEARDROPS ) )
{ {
if( boardItem->Type() == PCB_PAD_T || boardItem->Type() == PCB_VIA_T ) if( boardItem->Type() == PCB_FOOTPRINT_T )
{
for( PAD* pad : static_cast<FOOTPRINT*>( boardItem )->Pads() )
staleTeardropPadsAndVias.push_back( pad );
}
else if( boardItem->Type() == PCB_PAD_T || boardItem->Type() == PCB_VIA_T )
{ {
staleTeardropPadsAndVias.push_back( boardItem ); staleTeardropPadsAndVias.push_back( boardItem );
} }
@ -235,8 +236,22 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
} }
} }
if( boardItem->IsSelected() ) if( boardItem && boardItem->IsSelected() )
selectedModified = true; selectedModified = true;
}
// Old teardrops must be removed before connectivity is rebuilt
if( !staleTeardropPadsAndVias.empty() || !staleTeardropTracks.empty() )
teardropMgr.RemoveTeardrops( *this, &staleTeardropPadsAndVias, &staleTeardropTracks );
for( COMMIT_LINE& ent : m_changes )
{
int changeType = ent.m_type & CHT_TYPE;
int changeFlags = ent.m_type & CHT_FLAGS;
BOARD_ITEM* boardItem = dynamic_cast<BOARD_ITEM*>( ent.m_item );
wxASSERT( ent.m_item );
wxCHECK2( boardItem, continue );
switch( changeType ) switch( changeType )
{ {
@ -448,10 +463,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
} }
if( !staleTeardropPadsAndVias.empty() || !staleTeardropTracks.empty() ) if( !staleTeardropPadsAndVias.empty() || !staleTeardropTracks.empty() )
{
TEARDROP_MANAGER teardropMgr( board, m_toolMgr );
teardropMgr.UpdateTeardrops( *this, &staleTeardropPadsAndVias, &staleTeardropTracks ); teardropMgr.UpdateTeardrops( *this, &staleTeardropPadsAndVias, &staleTeardropTracks );
}
// Log undo items for any connectivity or teardrop changes // Log undo items for any connectivity or teardrop changes
for( size_t i = num_changes; i < m_changes.size(); ++i ) for( size_t i = num_changes; i < m_changes.size(); ++i )
@ -465,7 +477,6 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
if( !( aCommitFlags & SKIP_UNDO ) ) if( !( aCommitFlags & SKIP_UNDO ) )
{ {
ITEM_PICKER itemWrapper( nullptr, boardItem, convert( ent.m_type & CHT_TYPE ) ); ITEM_PICKER itemWrapper( nullptr, boardItem, convert( ent.m_type & CHT_TYPE ) );
wxASSERT( boardItemCopy );
itemWrapper.SetLink( boardItemCopy ); itemWrapper.SetLink( boardItemCopy );
undoList.PushItem( itemWrapper ); undoList.PushItem( itemWrapper );
} }

View File

@ -96,6 +96,58 @@ ZONE* TEARDROP_MANAGER::createTeardrop( TEARDROP_VARIANT aTeardropVariant,
} }
void TEARDROP_MANAGER::RemoveTeardrops( BOARD_COMMIT& aCommit,
const std::vector<BOARD_ITEM*>* dirtyPadsAndVias,
const std::set<PCB_TRACK*>* dirtyTracks )
{
std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
std::vector<ZONE*> stale_teardrops;
for( ZONE* zone : m_board->Zones() )
{
if( zone->IsTeardropArea() )
{
bool stale = false;
std::vector<PAD*> connectedPads;
std::vector<PCB_VIA*> connectedVias;
connectivity->GetConnectedPadsAndVias( zone, &connectedPads, &connectedVias );
for( PAD* pad : connectedPads )
{
if( alg::contains( *dirtyPadsAndVias, pad ) )
{
stale = true;
break;
}
}
if( !stale )
{
for( PCB_VIA* via : connectedVias )
{
if( alg::contains( *dirtyPadsAndVias, via ) )
{
stale = true;
break;
}
}
}
if( stale )
stale_teardrops.push_back( zone );
}
}
for( ZONE* td : stale_teardrops )
{
m_board->Remove( td, REMOVE_MODE::BULK );
aCommit.Removed( td );
}
}
void TEARDROP_MANAGER::UpdateTeardrops( BOARD_COMMIT& aCommit, void TEARDROP_MANAGER::UpdateTeardrops( BOARD_COMMIT& aCommit,
const std::vector<BOARD_ITEM*>* dirtyPadsAndVias, const std::vector<BOARD_ITEM*>* dirtyPadsAndVias,
const std::set<PCB_TRACK*>* dirtyTracks, const std::set<PCB_TRACK*>* dirtyTracks,
@ -109,41 +161,25 @@ void TEARDROP_MANAGER::UpdateTeardrops( BOARD_COMMIT& aCommit,
buildTrackCaches(); buildTrackCaches();
std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
// Old teardrops must be removed, to ensure a clean teardrop rebuild // Old teardrops must be removed, to ensure a clean teardrop rebuild
std::vector<ZONE*> stale_teardrops; if( aForceFullUpdate )
for( ZONE* zone : m_board->Zones() )
{ {
if( zone->IsTeardropArea() ) std::vector<ZONE*> teardrops;
for( ZONE* zone : m_board->Zones() )
{ {
bool stale = aForceFullUpdate; if( zone->IsTeardropArea() )
teardrops.push_back( zone );
}
if( !stale ) for( ZONE* td : teardrops )
{ {
std::vector<PAD*> connectedPads; m_board->Remove( td, REMOVE_MODE::BULK );
std::vector<PCB_VIA*> connectedVias; aCommit.Removed( td );
connectivity->GetConnectedPadsAndVias( zone, &connectedPads, &connectedVias );
for( PAD* pad : connectedPads )
stale = stale || alg::contains( *dirtyPadsAndVias, pad );
for( PCB_VIA* via : connectedVias )
stale = stale || alg::contains( *dirtyPadsAndVias, via );
}
if( stale )
stale_teardrops.push_back( zone );
} }
} }
for( ZONE* td : stale_teardrops ) std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
{
m_board->Remove( td, REMOVE_MODE::BULK );
aCommit.Removed( td );
}
for( PCB_TRACK* track : m_board->Tracks() ) for( PCB_TRACK* track : m_board->Tracks() )
{ {

View File

@ -106,6 +106,14 @@ public:
TEARDROP_MANAGER( BOARD* aBoard, TOOL_MANAGER* aToolManager ); TEARDROP_MANAGER( BOARD* aBoard, TOOL_MANAGER* aToolManager );
/**
* Remove teardrops connected to any dirty pads, vias or tracks. They need to be removed
* before being rebuilt.
*
* NB: this must be called BEFORE the connectivity is updated for the change in question.
*/
void RemoveTeardrops( BOARD_COMMIT& aCommit, const std::vector<BOARD_ITEM*>* dirtyPadsAndVias,
const std::set<PCB_TRACK*>* dirtyTracks );
/** /**
* Update teardrops on a list of items. * Update teardrops on a list of items.
*/ */