From d67437a2aa3b79e2d091699bccb51457ae66ca0c Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Thu, 29 Sep 2022 17:07:42 +0100 Subject: [PATCH] Move ratsnest exclusion processing to a post-pass. Also fixes a few cases where we were unnecessarily rebuilding connectivity more than once for an operation. --- include/pcb_base_frame.h | 1 - pcbnew/board.cpp | 55 +++++++----- pcbnew/board.h | 10 +-- pcbnew/board_commit.cpp | 13 +-- pcbnew/connectivity/connectivity_data.cpp | 88 +++---------------- pcbnew/connectivity/connectivity_data.h | 18 ++-- pcbnew/dialogs/dialog_drc.cpp | 45 +++++----- pcbnew/dialogs/panel_setup_layers.cpp | 8 +- pcbnew/drc/drc_test_provider_connectivity.cpp | 30 +++---- pcbnew/edit_zone_helpers.cpp | 2 +- .../netlist_reader/board_netlist_updater.cpp | 2 +- pcbnew/pcb_draw_panel_gal.cpp | 2 +- pcbnew/pcb_edit_frame.cpp | 9 +- pcbnew/ratsnest/ratsnest.cpp | 10 +-- pcbnew/ratsnest/ratsnest_data.cpp | 36 +++----- pcbnew/ratsnest/ratsnest_data.h | 9 +- .../specctra_import.cpp | 2 +- pcbnew/teardrop/teardrop.cpp | 4 +- pcbnew/tools/pcb_control.cpp | 3 - pcbnew/tools/zone_filler_tool.cpp | 8 +- pcbnew/zone_filler.cpp | 12 ++- pcbnew/zone_filler.h | 12 ++- qa/pcbnew_utils/board_test_utils.cpp | 4 +- qa/qa_utils/pcb_test_frame.cpp | 14 +-- qa/unittests/pcbnew/test_tracks_cleaner.cpp | 4 +- 25 files changed, 164 insertions(+), 237 deletions(-) diff --git a/include/pcb_base_frame.h b/include/pcb_base_frame.h index dc721df842..252f427316 100644 --- a/include/pcb_base_frame.h +++ b/include/pcb_base_frame.h @@ -303,7 +303,6 @@ public: * This must be called after a board change (changes for pads, footprints or a read * netlist ). * - * @param aDC is the current device context (can be NULL). * @param aDisplayStatus if true, display the computation results. */ void Compile_Ratsnest( bool aDisplayStatus ); diff --git a/pcbnew/board.cpp b/pcbnew/board.cpp index 7f7bf89d9a..692f07a431 100644 --- a/pcbnew/board.cpp +++ b/pcbnew/board.cpp @@ -155,6 +155,7 @@ BOARD::~BOARD() void BOARD::BuildConnectivity( PROGRESS_REPORTER* aReporter ) { GetConnectivity()->Build( this, aReporter ); + UpdateRatsnestExclusions(); } @@ -234,29 +235,43 @@ void BOARD::IncrementTimeStamp() } } + +void BOARD::UpdateRatsnestExclusions() +{ + std::set> m_ratsnestExclusions; + + for( PCB_MARKER* marker : GetBoard()->Markers() ) + { + if( marker->GetMarkerType() == MARKER_BASE::MARKER_RATSNEST && marker->IsExcluded() ) + { + const std::shared_ptr& rcItem = marker->GetRCItem(); + m_ratsnestExclusions.emplace( rcItem->GetMainItemID(), rcItem->GetAuxItemID() ); + m_ratsnestExclusions.emplace( rcItem->GetAuxItemID(), rcItem->GetMainItemID() ); + } + } + + GetConnectivity()->RunOnUnconnectedEdges( + [&]( CN_EDGE& aEdge ) + { + std::pair ids = { aEdge.GetSourceNode()->Parent()->m_Uuid, + aEdge.GetTargetNode()->Parent()->m_Uuid }; + + aEdge.SetVisible( m_ratsnestExclusions.count( ids ) == 0 ); + + return true; + } ); +} + + std::vector BOARD::ResolveDRCExclusions() { - std::shared_ptr conn = GetConnectivity(); - - auto setExcluded = - [&conn]( PCB_MARKER* aMarker ) - { - if( aMarker->GetMarkerType() == MARKER_BASE::MARKER_RATSNEST ) - { - const std::shared_ptr& rcItem = aMarker->GetRCItem(); - conn->AddExclusion( rcItem->GetMainItemID(), rcItem->GetAuxItemID() ); - } - - aMarker->SetExcluded( true ); - }; - for( PCB_MARKER* marker : GetBoard()->Markers() ) { auto i = m_designSettings->m_DrcExclusions.find( marker->Serialize() ); if( i != m_designSettings->m_DrcExclusions.end() ) { - setExcluded( marker ); + marker->SetExcluded( true ); m_designSettings->m_DrcExclusions.erase( i ); } } @@ -269,7 +284,7 @@ std::vector BOARD::ResolveDRCExclusions() if( marker ) { - setExcluded( marker ); + marker->SetExcluded( true ); newMarkers.push_back( marker ); } } @@ -1148,12 +1163,6 @@ unsigned BOARD::GetNodesCount( int aNet ) const } -unsigned BOARD::GetUnconnectedNetCount() const -{ - return m_connectivity->GetUnconnectedCount(); -} - - BOX2I BOARD::ComputeBoundingBox( bool aBoardEdgesOnly ) const { BOX2I bbox; @@ -1221,7 +1230,7 @@ void BOARD::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector int viaCount = 0; int trackSegmentCount = 0; std::set netCodes; - int unconnected = GetConnectivity()->GetUnconnectedCount(); + int unconnected = GetConnectivity()->GetUnconnectedCount( true ); for( PCB_TRACK* item : m_tracks ) { diff --git a/pcbnew/board.h b/pcbnew/board.h index f3c6e7e033..d2dd155eb9 100644 --- a/pcbnew/board.h +++ b/pcbnew/board.h @@ -456,6 +456,11 @@ public: */ std::vector ResolveDRCExclusions(); + /** + * Update the visibility flags on the current unconnected ratsnest lines. + */ + void UpdateRatsnestExclusions(); + /** * Reset all high light data to the init state */ @@ -724,11 +729,6 @@ public: */ unsigned GetNodesCount( int aNet = -1 ) const; - /** - * @return the number of unconnected nets in the current ratsnest. - */ - unsigned GetUnconnectedNetCount() const; - /** * Return a reference to a list of all the pads. * diff --git a/pcbnew/board_commit.cpp b/pcbnew/board_commit.cpp index 52a72ce09a..b580c7a747 100644 --- a/pcbnew/board_commit.cpp +++ b/pcbnew/board_commit.cpp @@ -34,7 +34,6 @@ #include #include #include -#include #include using namespace std::placeholders; @@ -501,6 +500,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags ) connectivity->PropagateNets( this, PROPAGATE_MODE::RESOLVE_CONFLICTS ); connectivity->RecalculateRatsnest( this ); + board->UpdateRatsnestExclusions(); connectivity->ClearLocalRatsnest(); } @@ -593,10 +593,10 @@ EDA_ITEM* BOARD_COMMIT::parentObject( EDA_ITEM* aItem ) const void BOARD_COMMIT::Revert() { - PICKED_ITEMS_LIST undoList; - KIGFX::VIEW* view = m_toolMgr->GetView(); - BOARD* board = (BOARD*) m_toolMgr->GetModel(); - auto connectivity = board->GetConnectivity(); + PICKED_ITEMS_LIST undoList; + KIGFX::VIEW* view = m_toolMgr->GetView(); + BOARD* board = (BOARD*) m_toolMgr->GetModel(); + std::shared_ptr connectivity = board->GetConnectivity(); std::vector bulkAddedItems; std::vector bulkRemovedItems; @@ -664,7 +664,10 @@ void BOARD_COMMIT::Revert() board->OnItemsChanged( itemsChanged ); if ( !m_isFootprintEditor ) + { connectivity->RecalculateRatsnest(); + board->UpdateRatsnestExclusions(); + } PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool(); selTool->RebuildSelection(); diff --git a/pcbnew/connectivity/connectivity_data.cpp b/pcbnew/connectivity/connectivity_data.cpp index a5fc257ecd..491ed38d6d 100644 --- a/pcbnew/connectivity/connectivity_data.cpp +++ b/pcbnew/connectivity/connectivity_data.cpp @@ -178,7 +178,7 @@ void CONNECTIVITY_DATA::updateRatsnest() [&]( const int a, const int b) { for( int ii = a; ii < b; ++ii ) - dirty_nets[ii]->Update( m_exclusions ); + dirty_nets[ii]->Update(); }).wait(); #ifdef PROFILE @@ -235,9 +235,7 @@ void CONNECTIVITY_DATA::RecalculateRatsnest( BOARD_COMMIT* aCommit ) } if( m_connAlgo->IsNetDirty( net ) ) - { addRatsnestCluster( c ); - } } m_connAlgo->ClearDirtyFlags(); @@ -458,7 +456,7 @@ bool CONNECTIVITY_DATA::IsConnectedOnLayer( const BOARD_CONNECTED_ITEM *aItem, i } -unsigned int CONNECTIVITY_DATA::GetUnconnectedCount() const +unsigned int CONNECTIVITY_DATA::GetUnconnectedCount( bool aVisibleOnly ) const { unsigned int unconnected = 0; @@ -469,7 +467,7 @@ unsigned int CONNECTIVITY_DATA::GetUnconnectedCount() const for( const CN_EDGE& edge : net->GetEdges() ) { - if( edge.IsVisible() ) + if( edge.IsVisible() || !aVisibleOnly ) ++unconnected; } } @@ -546,35 +544,10 @@ CONNECTIVITY_DATA::GetNetItems( int aNetCode, const std::initializer_list& aReport ) -{ - RecalculateRatsnest(); - - for( auto net : m_nets ) - { - if( net ) - { - for( const auto& edge : net->GetEdges() ) - { - CN_DISJOINT_NET_ENTRY ent; - ent.net = edge.GetSourceNode()->Parent()->GetNetCode(); - ent.a = edge.GetSourceNode()->Parent(); - ent.b = edge.GetTargetNode()->Parent(); - ent.anchorA = edge.GetSourceNode()->Pos(); - ent.anchorB = edge.GetTargetNode()->Pos(); - aReport.push_back( ent ); - } - } - } - - return aReport.empty(); -} - - const std::vector CONNECTIVITY_DATA::GetConnectedTracks( const BOARD_CONNECTED_ITEM* aItem ) const { - auto& entry = m_connAlgo->ItemEntry( aItem ); + CN_CONNECTIVITY_ALGO::ITEM_MAP_ENTRY& entry = m_connAlgo->ItemEntry( aItem ); std::set tracks; std::vector rv; @@ -662,14 +635,17 @@ unsigned int CONNECTIVITY_DATA::GetPadCount( int aNet ) const } -void CONNECTIVITY_DATA::GetUnconnectedEdges( std::vector& aEdges) const +void CONNECTIVITY_DATA::RunOnUnconnectedEdges( std::function aFunc ) { - for( const RN_NET* rnNet : m_nets ) + for( RN_NET* rnNet : m_nets ) { if( rnNet ) { - for( const CN_EDGE& edge : rnNet->GetEdges() ) - aEdges.push_back( edge ); + for( CN_EDGE& edge : rnNet->GetEdges() ) + { + if( !aFunc( edge ) ) + return; + } } } } @@ -888,48 +864,6 @@ void CONNECTIVITY_DATA::SetProgressReporter( PROGRESS_REPORTER* aReporter ) } -void CONNECTIVITY_DATA::AddExclusion( const KIID& aBoardItemId1, const KIID& aBoardItemId2 ) -{ - m_exclusions.emplace( aBoardItemId1, aBoardItemId2 ); - m_exclusions.emplace( aBoardItemId2, aBoardItemId1 ); - - for( RN_NET* rnNet : m_nets ) - { - for( CN_EDGE& edge : rnNet->GetEdges() ) - { - if( ( edge.GetSourceNode()->Parent()->m_Uuid == aBoardItemId1 - && edge.GetTargetNode()->Parent()->m_Uuid == aBoardItemId2 ) - || ( edge.GetSourceNode()->Parent()->m_Uuid == aBoardItemId2 - && edge.GetTargetNode()->Parent()->m_Uuid == aBoardItemId1 ) ) - { - edge.SetVisible( false ); - } - } - } -} - - -void CONNECTIVITY_DATA::RemoveExclusion( const KIID& aBoardItemId1, const KIID& aBoardItemId2 ) -{ - m_exclusions.erase( std::pair( aBoardItemId1, aBoardItemId2 ) ); - m_exclusions.erase( std::pair( aBoardItemId2, aBoardItemId1 ) ); - - for( RN_NET* rnNet : m_nets ) - { - for( CN_EDGE& edge : rnNet->GetEdges() ) - { - if( ( edge.GetSourceNode()->Parent()->m_Uuid == aBoardItemId1 - && edge.GetTargetNode()->Parent()->m_Uuid == aBoardItemId2 ) - || ( edge.GetSourceNode()->Parent()->m_Uuid == aBoardItemId2 - && edge.GetTargetNode()->Parent()->m_Uuid == aBoardItemId1 ) ) - { - edge.SetVisible( true ); - } - } - } -} - - const std::vector CONNECTIVITY_DATA::GetRatsnestForItems( std::vector aItems ) { std::set nets; diff --git a/pcbnew/connectivity/connectivity_data.h b/pcbnew/connectivity/connectivity_data.h index c67a5432d0..2eac2bc611 100644 --- a/pcbnew/connectivity/connectivity_data.h +++ b/pcbnew/connectivity/connectivity_data.h @@ -2,7 +2,7 @@ * This program source code file is part of KICAD, a free EDA CAD application. * * Copyright (C) 2013-2017 CERN - * Copyright (C) 2018-2020 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2018-2022 KiCad Developers, see AUTHORS.txt for contributors. * @author Maciej Suminski * @author Tomasz Wlostowski * @@ -176,8 +176,6 @@ public: void PropagateNets( BOARD_COMMIT* aCommit = nullptr, PROPAGATE_MODE aMode = PROPAGATE_MODE::SKIP_CONFLICTS ); - bool CheckConnectivity( std::vector& aReport ); - /** * Function FindIsolatedCopperIslands() * Searches for copper islands in zone aZone that are not connected to any pad. @@ -196,10 +194,10 @@ public: void RecalculateRatsnest( BOARD_COMMIT* aCommit = nullptr ); /** - * Function GetUnconnectedCount() - * Returns the number of remaining edges in the ratsnest. + * @param aVisibleOnly include only visbile edges in the count + * @return the number of remaining edges in the ratsnest */ - unsigned int GetUnconnectedCount() const; + unsigned int GetUnconnectedCount( bool aVisibileOnly ) const; bool IsConnectedOnLayer( const BOARD_CONNECTED_ITEM* aItem, int aLayer, const std::initializer_list& aTypes = {}, @@ -230,7 +228,7 @@ public: const std::initializer_list& aTypes, const int& aMaxError = 0 ) const; - void GetUnconnectedEdges( std::vector& aEdges ) const; + void RunOnUnconnectedEdges( std::function aFunc ); bool TestTrackEndpointDangling( PCB_TRACK* aTrack, VECTOR2I* aPos = nullptr ); @@ -287,9 +285,6 @@ public: const std::map& GetNetclassMap() const { return m_netclassMap; } - void AddExclusion( const KIID& aBoardItemId1, const KIID& aBoardItemId2 ); - void RemoveExclusion( const KIID& aBoardItemId1, const KIID& aBoardItemId2 ); - #ifndef SWIG const std::vector GetRatsnestForItems( const std::vector aItems ); @@ -316,9 +311,6 @@ private: /// Used to suppress ratsnest calculations on dynamic ratsnests bool m_skipRatsnest = false; - /// Ratsnest lines that have been excluded in DRC - std::set> m_exclusions; - KISPINLOCK m_lock; /// Map of netcode -> netclass the net is a member of; used for ratsnest painting diff --git a/pcbnew/dialogs/dialog_drc.cpp b/pcbnew/dialogs/dialog_drc.cpp index 964dcae771..db3e39f6ca 100644 --- a/pcbnew/dialogs/dialog_drc.cpp +++ b/pcbnew/dialogs/dialog_drc.cpp @@ -473,23 +473,24 @@ void DIALOG_DRC::OnDRCItemSelected( wxDataViewEvent& aEvent ) if( !m_frame->GetPcbNewSettings()->m_Display.m_ShowGlobalRatsnest ) m_frame->GetToolManager()->RunAction( PCB_ACTIONS::showRatsnest, true ); - std::vector edges; - m_frame->GetBoard()->GetConnectivity()->GetUnconnectedEdges( edges ); - if( item->Type() == PCB_ZONE_T ) { - for( const CN_EDGE& edge : edges ) - { - if( edge.GetSourceNode()->Parent() == a && edge.GetTargetNode()->Parent() == b ) - { - if( item == a ) - m_frame->FocusOnLocation( edge.GetSourcePos() ); - else - m_frame->FocusOnLocation( edge.GetTargetPos() ); + m_frame->GetBoard()->GetConnectivity()->RunOnUnconnectedEdges( + [&]( CN_EDGE& edge ) + { + if( edge.GetSourceNode()->Parent() == a + && edge.GetTargetNode()->Parent() == b ) + { + if( item == a ) + m_frame->FocusOnLocation( edge.GetSourcePos() ); + else + m_frame->FocusOnLocation( edge.GetTargetPos() ); - break; - } - } + return false; + } + + return true; + } ); } else { @@ -651,12 +652,14 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent ) marker->SetExcluded( false ); if( rcItem->GetErrorCode() == DRCE_UNCONNECTED_ITEMS ) - conn->RemoveExclusion( drcItem->GetMainItemID(), drcItem->GetAuxItemID() ); - - if( rcItem->GetErrorCode() == DRCE_UNCONNECTED_ITEMS ) + { + m_frame->GetBoard()->UpdateRatsnestExclusions(); m_frame->GetCanvas()->RedrawRatsnest(); + } else + { m_frame->GetCanvas()->GetView()->Update( marker ); + } // Update view static_cast( aEvent.GetModel() )->ValueChanged( node ); @@ -675,12 +678,14 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent ) marker->SetExcluded( true ); if( rcItem->GetErrorCode() == DRCE_UNCONNECTED_ITEMS ) - conn->AddExclusion( drcItem->GetMainItemID(), drcItem->GetAuxItemID() ); - - if( rcItem->GetErrorCode() == DRCE_UNCONNECTED_ITEMS ) + { + m_frame->GetBoard()->UpdateRatsnestExclusions(); m_frame->GetCanvas()->RedrawRatsnest(); + } else + { m_frame->GetCanvas()->GetView()->Update( marker ); + } // Update view if( m_severities & RPT_SEVERITY_EXCLUSION ) diff --git a/pcbnew/dialogs/panel_setup_layers.cpp b/pcbnew/dialogs/panel_setup_layers.cpp index 0a0cbb06cb..4240943034 100644 --- a/pcbnew/dialogs/panel_setup_layers.cpp +++ b/pcbnew/dialogs/panel_setup_layers.cpp @@ -572,14 +572,10 @@ bool PANEL_SETUP_LAYERS::TransferDataFromWindow() } } - // If some board items are deleted: Rebuild the connectivity, - // because it is likely some tracks and vias were removed + // If some board items are deleted: Rebuild the connectivity, because it is likely some + // tracks and vias were removed if( hasRemovedBoardItems ) - { - // Rebuild list of nets (full ratsnest rebuild) m_pcb->BuildConnectivity(); - m_frame->Compile_Ratsnest( true ); - } if( modified ) m_frame->OnModify(); diff --git a/pcbnew/drc/drc_test_provider_connectivity.cpp b/pcbnew/drc/drc_test_provider_connectivity.cpp index 7b8f0ad0e6..5e07297bb1 100644 --- a/pcbnew/drc/drc_test_provider_connectivity.cpp +++ b/pcbnew/drc/drc_test_provider_connectivity.cpp @@ -82,7 +82,7 @@ bool DRC_TEST_PROVIDER_CONNECTIVITY::Run() islandsList.emplace_back( CN_ZONE_ISOLATED_ISLAND_LIST( zone ) ); } - // Rebuild just in case. This really needs to be reliable. + // Rebuild (from scratch, ignoring dirty flags) just in case. This really needs to be reliable. connectivity->Clear(); connectivity->Build( board, m_drcEngine->GetProgressReporter() ); connectivity->FindIsolatedCopperIslands( islandsList, true ); @@ -155,24 +155,24 @@ bool DRC_TEST_PROVIDER_CONNECTIVITY::Run() if( !reportPhase( _( "Checking net connections..." ) ) ) return false; // DRC cancelled - std::vector edges; - connectivity->GetUnconnectedEdges( edges ); - ii = 0; - count = edges.size(); + count = connectivity->GetUnconnectedCount( false ); - for( const CN_EDGE& edge : edges ) - { - if( m_drcEngine->IsErrorLimitExceeded( DRCE_UNCONNECTED_ITEMS ) ) - break; + connectivity->RunOnUnconnectedEdges( + [&]( CN_EDGE& edge ) + { + if( m_drcEngine->IsErrorLimitExceeded( DRCE_UNCONNECTED_ITEMS ) ) + return false; - if( !reportProgress( ii++, count, progressDelta ) ) - return false; // DRC cancelled + if( !reportProgress( ii++, count, progressDelta ) ) + return false; // DRC cancelled - std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_UNCONNECTED_ITEMS ); - drcItem->SetItems( edge.GetSourceNode()->Parent(), edge.GetTargetNode()->Parent() ); - reportViolation( drcItem, edge.GetSourceNode()->Pos(), UNDEFINED_LAYER ); - } + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_UNCONNECTED_ITEMS ); + drcItem->SetItems( edge.GetSourceNode()->Parent(), edge.GetTargetNode()->Parent() ); + reportViolation( drcItem, edge.GetSourceNode()->Pos(), UNDEFINED_LAYER ); + + return true; + } ); reportRuleStatistics(); diff --git a/pcbnew/edit_zone_helpers.cpp b/pcbnew/edit_zone_helpers.cpp index 25dee535a2..29a70c2e3e 100644 --- a/pcbnew/edit_zone_helpers.cpp +++ b/pcbnew/edit_zone_helpers.cpp @@ -104,7 +104,7 @@ void PCB_EDIT_FRAME::Edit_Zone_Params( ZONE* aZone ) commit.Stage( pickedList ); commit.Push( _( "Modify zone properties" ), SKIP_CONNECTIVITY ); - GetBoard()->GetConnectivity()->Build( GetBoard() ); + GetBoard()->BuildConnectivity(); pickedList.ClearItemsList(); // s_ItemsListPicker is no longer owner of picked items } diff --git a/pcbnew/netlist_reader/board_netlist_updater.cpp b/pcbnew/netlist_reader/board_netlist_updater.cpp index e61fbf7cf8..56c325ef24 100644 --- a/pcbnew/netlist_reader/board_netlist_updater.cpp +++ b/pcbnew/netlist_reader/board_netlist_updater.cpp @@ -1038,7 +1038,7 @@ bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist ) if( !m_isDryRun ) { - m_board->GetConnectivity()->Build( m_board ); + m_board->BuildConnectivity(); testConnectivity( aNetlist, footprintMap ); for( NETINFO_ITEM* net : m_board->GetNetInfo() ) diff --git a/pcbnew/pcb_draw_panel_gal.cpp b/pcbnew/pcb_draw_panel_gal.cpp index 9a474b8c6f..c0e37a0644 100644 --- a/pcbnew/pcb_draw_panel_gal.cpp +++ b/pcbnew/pcb_draw_panel_gal.cpp @@ -498,7 +498,7 @@ void PCB_DRAW_PANEL_GAL::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, int viaCount = 0; int trackSegmentCount = 0; std::set netCodes; - int unconnected = board->GetConnectivity()->GetUnconnectedCount(); + int unconnected = board->GetConnectivity()->GetUnconnectedCount( true ); for( PCB_TRACK* item : board->Tracks() ) { diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp index 05b8a1f965..efbf33f9d2 100644 --- a/pcbnew/pcb_edit_frame.cpp +++ b/pcbnew/pcb_edit_frame.cpp @@ -52,7 +52,6 @@ #include #include #include -#include #include #include #include @@ -98,7 +97,6 @@ #include #include #include -#include #include #include #include @@ -493,7 +491,7 @@ void PCB_EDIT_FRAME::SetBoard( BOARD* aBoard, bool aBuildConnectivity, aBoard->SetProject( &Prj() ); if( aBuildConnectivity ) - aBoard->GetConnectivity()->Build( aBoard ); + aBoard->BuildConnectivity(); // reload the drawing-sheet SetPageSettings( aBoard->GetPageSettings() ); @@ -949,7 +947,7 @@ void PCB_EDIT_FRAME::ResolveDRCExclusions() commit.Add( marker ); } - commit.Push( wxEmptyString, SKIP_UNDO | SKIP_SET_DIRTY ); + commit.Push( wxEmptyString, SKIP_UNDO | SKIP_SET_DIRTY | SKIP_CONNECTIVITY ); for( PCB_MARKER* marker : GetBoard()->Markers() ) { @@ -959,6 +957,8 @@ void PCB_EDIT_FRAME::ResolveDRCExclusions() GetCanvas()->GetView()->Add( marker ); } } + + GetBoard()->UpdateRatsnestExclusions(); } @@ -1484,7 +1484,6 @@ void PCB_EDIT_FRAME::UpdateUserInterface() // Rebuild list of nets (full ratsnest rebuild) GetBoard()->BuildConnectivity(); - Compile_Ratsnest( true ); // Update info shown by the horizontal toolbars ReCreateLayerBox(); diff --git a/pcbnew/ratsnest/ratsnest.cpp b/pcbnew/ratsnest/ratsnest.cpp index 7c3367cfd9..7232de88b1 100644 --- a/pcbnew/ratsnest/ratsnest.cpp +++ b/pcbnew/ratsnest/ratsnest.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2007-2014 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -23,23 +23,19 @@ */ #include -#include -#include #include -#include #include /** * Function Compile_Ratsnest * Create the entire board ratsnest. - * Must be called after a board change (changes for - * pads, footprints or a read netlist ). - * @param aDC = the current device context (can be NULL) + * Must be called after a board change (changes for pads, footprints or a read netlist ). * @param aDisplayStatus : if true, display the computation results */ void PCB_BASE_FRAME::Compile_Ratsnest( bool aDisplayStatus ) { GetBoard()->GetConnectivity()->RecalculateRatsnest(); + GetBoard()->UpdateRatsnestExclusions(); if( aDisplayStatus ) SetMsgPanel( m_pcb ); diff --git a/pcbnew/ratsnest/ratsnest_data.cpp b/pcbnew/ratsnest/ratsnest_data.cpp index 92ef152864..81d63d95d3 100644 --- a/pcbnew/ratsnest/ratsnest_data.cpp +++ b/pcbnew/ratsnest/ratsnest_data.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KICAD, a free EDA CAD application. * * Copyright (C) 2013-2017 CERN - * Copyright (C) 2019-2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors. * * @author Maciej Suminski * @author Tomasz Wlostowski @@ -107,8 +107,7 @@ private: }; -void RN_NET::kruskalMST( std::vector& aEdges, - const std::set< std::pair >& aExclusions ) +void RN_NET::kruskalMST( const std::vector &aEdges ) { disjoint_set dset( m_nodes.size() ); @@ -119,20 +118,15 @@ void RN_NET::kruskalMST( std::vector& aEdges, for( const std::shared_ptr& node : m_nodes ) node->SetTag( i++ ); - for( CN_EDGE& tmp : aEdges ) + for( const CN_EDGE& tmp : aEdges ) { - const std::shared_ptr& source = tmp.GetSourceNode(); - const std::shared_ptr& target = tmp.GetTargetNode(); + const std::shared_ptr& source = tmp.GetSourceNode(); + const std::shared_ptr& target = tmp.GetTargetNode(); if( dset.unite( source->GetTag(), target->GetTag() ) ) { if( tmp.GetWeight() > 0 ) - { - std::pair ids = { source->Parent()->m_Uuid, target->Parent()->m_Uuid }; - tmp.SetVisible( aExclusions.count( ids ) == 0 ); - m_rnEdges.push_back( tmp ); - } } } } @@ -271,7 +265,7 @@ RN_NET::RN_NET() : m_dirty( true ) } -void RN_NET::compute( const std::set< std::pair >& aExclusions ) +void RN_NET::compute() { // Special cases do not need complicated algorithms (actually, it does not work well with // the Delaunay triangulator) @@ -285,15 +279,9 @@ void RN_NET::compute( const std::set< std::pair >& aExclusions ) auto last = ++m_nodes.begin(); // There can be only one possible connection, but it is missing - CN_EDGE edge( *m_nodes.begin(), *last ); - const std::shared_ptr& source = edge.GetSourceNode(); - const std::shared_ptr& target = edge.GetTargetNode(); - - std::pair ids = { source->Parent()->m_Uuid, target->Parent()->m_Uuid }; - - source->SetTag( 0 ); - target->SetTag( 1 ); - edge.SetVisible( aExclusions.count( ids ) == 0 ); + CN_EDGE edge ( *m_nodes.begin(), *last ); + edge.GetSourceNode()->SetTag( 0 ); + edge.GetTargetNode()->SetTag( 1 ); m_rnEdges.push_back( edge ); } @@ -333,7 +321,7 @@ void RN_NET::compute( const std::set< std::pair >& aExclusions ) #ifdef PROFILE PROF_TIMER cnt2( "mst" ); #endif - kruskalMST( triangEdges, aExclusions ); + kruskalMST( triangEdges ); #ifdef PROFILE cnt2.Show(); #endif @@ -341,9 +329,9 @@ void RN_NET::compute( const std::set< std::pair >& aExclusions ) -void RN_NET::Update( const std::set< std::pair >& aExclusions ) +void RN_NET::Update() { - compute( aExclusions ); + compute(); m_dirty = false; } diff --git a/pcbnew/ratsnest/ratsnest_data.h b/pcbnew/ratsnest/ratsnest_data.h index 437dd2b820..6b3cbb2bc0 100644 --- a/pcbnew/ratsnest/ratsnest_data.h +++ b/pcbnew/ratsnest/ratsnest_data.h @@ -2,7 +2,7 @@ * This program source code file is part of KICAD, a free EDA CAD application. * * Copyright (C) 2013-2015 CERN - * Copyright (C) 2019-2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors. * * @author Maciej Suminski * @@ -80,7 +80,7 @@ public: /** * Recompute ratsnest for a net. */ - void Update( const std::set< std::pair >& aExclusions ); + void Update(); void Clear(); void AddCluster( std::shared_ptr aCluster ); @@ -94,11 +94,10 @@ public: protected: ///< Recompute ratsnest from scratch. - void compute( const std::set< std::pair >& aExclusions ); + void compute(); ///< Compute the minimum spanning tree using Kruskal's algorithm - void kruskalMST( std::vector& aEdges, - const std::set< std::pair >& aExclusions ); + void kruskalMST( const std::vector &aEdges ); ///< Vector of nodes std::multiset, CN_PTR_CMP> m_nodes; diff --git a/pcbnew/specctra_import_export/specctra_import.cpp b/pcbnew/specctra_import_export/specctra_import.cpp index 361ea6dca7..9ff59f607f 100644 --- a/pcbnew/specctra_import_export/specctra_import.cpp +++ b/pcbnew/specctra_import_export/specctra_import.cpp @@ -84,7 +84,7 @@ bool PCB_EDIT_FRAME::ImportSpecctraSession( const wxString& fullFileName ) OnModify(); GetBoard()->GetConnectivity()->Clear(); - GetBoard()->GetConnectivity()->Build( GetBoard() ); + GetBoard()->BuildConnectivity(); if( GetCanvas() ) // Update view: { diff --git a/pcbnew/teardrop/teardrop.cpp b/pcbnew/teardrop/teardrop.cpp index cccd81441b..4e8e6460b4 100644 --- a/pcbnew/teardrop/teardrop.cpp +++ b/pcbnew/teardrop/teardrop.cpp @@ -430,7 +430,9 @@ int TEARDROP_MANAGER::RemoveTeardrops( BOARD_COMMIT* aCommitter, bool aCommitAft (void)filler.Fill( m_board->Zones() ); if( aCommitter && aCommitAfterRemove ) - aCommitter->Push( _( "Remove teardrops" ) ); + aCommitter->Push( _( "Remove teardrops" ), SKIP_CONNECTIVITY ); + + m_board->BuildConnectivity(); } return count; diff --git a/pcbnew/tools/pcb_control.cpp b/pcbnew/tools/pcb_control.cpp index 3ecfa5db8d..c9de6dd31b 100644 --- a/pcbnew/tools/pcb_control.cpp +++ b/pcbnew/tools/pcb_control.cpp @@ -904,9 +904,6 @@ int PCB_CONTROL::Paste( const TOOL_EVENT& aEvent ) } placeBoardItems( clipBoard, true, mode == PASTE_MODE::UNIQUE_ANNOTATIONS ); - - m_frame->GetBoard()->BuildConnectivity(); - m_frame->Compile_Ratsnest( true ); } break; diff --git a/pcbnew/tools/zone_filler_tool.cpp b/pcbnew/tools/zone_filler_tool.cpp index 0131a5ea0a..ddce50ae61 100644 --- a/pcbnew/tools/zone_filler_tool.cpp +++ b/pcbnew/tools/zone_filler_tool.cpp @@ -94,7 +94,7 @@ void ZONE_FILLER_TOOL::CheckAllZones( wxWindow* aCaller, PROGRESS_REPORTER* aRep commit.Revert(); } - board()->GetConnectivity()->Build( board() ); + board()->BuildConnectivity(); canvas()->Refresh(); m_fillInProgress = false; @@ -169,7 +169,7 @@ void ZONE_FILLER_TOOL::FillAllZones( wxWindow* aCaller, PROGRESS_REPORTER* aRepo commit.Revert(); } - board()->GetConnectivity()->Build( board(), reporter.get() ); + board()->BuildConnectivity( reporter.get() ); if( filler.IsDebug() ) frame->UpdateUserInterface(); @@ -251,7 +251,7 @@ int ZONE_FILLER_TOOL::ZoneFillDirty( const TOOL_EVENT& aEvent ) else commit.Revert(); - board()->GetConnectivity()->Build( board(), reporter.get() ); + board()->BuildConnectivity( reporter.get() ); if( filler.IsDebug() ) frame->UpdateUserInterface(); @@ -309,7 +309,7 @@ int ZONE_FILLER_TOOL::ZoneFill( const TOOL_EVENT& aEvent ) commit.Revert(); } - board()->GetConnectivity()->Build( board(), reporter.get() ); + board()->BuildConnectivity( reporter.get() ); canvas()->Refresh(); m_fillInProgress = false; diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp index 4d19db14bc..84b331ed0f 100644 --- a/pcbnew/zone_filler.cpp +++ b/pcbnew/zone_filler.cpp @@ -77,6 +77,16 @@ void ZONE_FILLER::SetProgressReporter( PROGRESS_REPORTER* aReporter ) } +/** + * Fills the given list of zones. + * + * NB: Invalidates connectivity - it is up to the caller to obtain a lock on the connectivity + * data before calling Fill to prevent access to stale data by other coroutines (for example, + * ratsnest redraw). This will generally be required if a UI-based progress reporter has been + * installed. + * + * Caller is also responsible for re-building connectivity afterwards. + */ bool ZONE_FILLER::Fill( std::vector& aZones, bool aCheck, wxWindow* aParent ) { std::lock_guard lock( m_board->GetConnectivity()->GetLock() ); @@ -87,7 +97,7 @@ bool ZONE_FILLER::Fill( std::vector& aZones, bool aCheck, wxWindow* aPare std::shared_ptr connectivity = m_board->GetConnectivity(); - // Rebuild just in case. This really needs to be reliable. + // Rebuild (from scratch, ignoring dirty flags) just in case. This really needs to be reliable. connectivity->Clear(); connectivity->Build( m_board, m_progressReporter ); diff --git a/pcbnew/zone_filler.h b/pcbnew/zone_filler.h index fe30c9035d..e1b1e74042 100644 --- a/pcbnew/zone_filler.h +++ b/pcbnew/zone_filler.h @@ -46,10 +46,14 @@ public: PROGRESS_REPORTER* GetProgressReporter() const { return m_progressReporter; } /** - * Fills the given list of zones. Invalidates connectivity - it is up to the caller to obtain - * a lock on the connectivity data before calling Fill to prevent access to stale data by other - * coroutines (for example, ratsnest redraw). This will generally be required if a UI-based - * progress reporter has been installed. + * Fills the given list of zones. + * + * NB: Invalidates connectivity - it is up to the caller to obtain a lock on the connectivity + * data before calling Fill to prevent access to stale data by other coroutines (for example, + * ratsnest redraw). This will generally be required if a UI-based progress reporter has been + * installed. + * + * Caller is also responsible for re-building connectivity afterwards. */ bool Fill( std::vector& aZones, bool aCheck = false, wxWindow* aParent = nullptr ); diff --git a/qa/pcbnew_utils/board_test_utils.cpp b/qa/pcbnew_utils/board_test_utils.cpp index 2c7d45f30c..5bcf5ad927 100644 --- a/qa/pcbnew_utils/board_test_utils.cpp +++ b/qa/pcbnew_utils/board_test_utils.cpp @@ -118,7 +118,9 @@ void FillZones( BOARD* m_board ) toFill.push_back( zone ); if( filler.Fill( toFill, false, nullptr ) ) - commit.Push( _( "Fill Zone(s)" ), SKIP_UNDO | SKIP_SET_DIRTY | ZONE_FILL_OP ); + commit.Push( _( "Fill Zone(s)" ), SKIP_UNDO | SKIP_SET_DIRTY | ZONE_FILL_OP | SKIP_CONNECTIVITY ); + + m_board->BuildConnectivity(); } diff --git a/qa/qa_utils/pcb_test_frame.cpp b/qa/qa_utils/pcb_test_frame.cpp index cd7d9eec6f..11d7c3b605 100644 --- a/qa/qa_utils/pcb_test_frame.cpp +++ b/qa/qa_utils/pcb_test_frame.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2013-2017 CERN - * Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.txt for contributors. * @author Tomasz Wlostowski * * This program is free software; you can redistribute it and/or @@ -23,11 +23,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -//#define USE_TOOL_MANAGER -#include -#include -#include #include #include #include @@ -38,7 +34,6 @@ #include #include -#include #include #include #include @@ -47,23 +42,18 @@ #include #include #include - #include -#include #include #include #include #include -#include #include #include #include #include -#include -#include #include #include "pcb_test_frame.h" @@ -78,7 +68,7 @@ void PCB_TEST_FRAME_BASE::SetBoard( std::shared_ptr b ) m_board = b; PROF_TIMER cntConnectivity( "connectivity-build" ); - m_board->GetConnectivity()->Build( m_board.get() ); + m_board->BuildConnectivity(); cntConnectivity.Stop(); PROF_TIMER cntView("view-build"); diff --git a/qa/unittests/pcbnew/test_tracks_cleaner.cpp b/qa/unittests/pcbnew/test_tracks_cleaner.cpp index d656946caf..d1a149ae1a 100644 --- a/qa/unittests/pcbnew/test_tracks_cleaner.cpp +++ b/qa/unittests/pcbnew/test_tracks_cleaner.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -78,6 +78,7 @@ BOOST_FIXTURE_TEST_CASE( FailedToCleanRegressionTests, TRACK_CLEANER_TEST_FIXTUR KI_TEST::LoadBoard( m_settingsManager, entry.m_File, m_board ); KI_TEST::FillZones( m_board.get() ); m_board->GetConnectivity()->RecalculateRatsnest(); + m_board->UpdateRatsnestExclusions(); TOOL_MANAGER toolMgr; toolMgr.SetEnvironment( m_board.get(), nullptr, nullptr, nullptr, nullptr ); @@ -146,6 +147,7 @@ BOOST_FIXTURE_TEST_CASE( TrackCleanerRegressionTests, TRACK_CLEANER_TEST_FIXTURE KI_TEST::LoadBoard( m_settingsManager, relPath, m_board ); KI_TEST::FillZones( m_board.get() ); m_board->GetConnectivity()->RecalculateRatsnest(); + m_board->UpdateRatsnestExclusions(); TOOL_MANAGER toolMgr; toolMgr.SetEnvironment( m_board.get(), nullptr, nullptr, nullptr, nullptr );