From 700edb95e3980b6cfcda98cb3731c9a815a7400a Mon Sep 17 00:00:00 2001 From: Mike Williams Date: Thu, 22 Sep 2022 14:25:44 -0400 Subject: [PATCH] PCB Actions: Grab Unconnected Grabs the nearest unconnected item for each selected footprint/pad. Fixes: https://gitlab.com/kicad/code/kicad/-/issues/1986 --- pcbnew/connectivity/connectivity_algo.h | 4 ++ pcbnew/tools/pcb_actions.cpp | 9 +++- pcbnew/tools/pcb_actions.h | 3 ++ pcbnew/tools/pcb_selection_tool.cpp | 70 +++++++++++++++++++++++++ pcbnew/tools/pcb_selection_tool.h | 5 ++ 5 files changed, 89 insertions(+), 2 deletions(-) diff --git a/pcbnew/connectivity/connectivity_algo.h b/pcbnew/connectivity/connectivity_algo.h index aef15a56e6..35b6b9e967 100644 --- a/pcbnew/connectivity/connectivity_algo.h +++ b/pcbnew/connectivity/connectivity_algo.h @@ -101,6 +101,10 @@ public: const VECTOR2I GetSourcePos() const { return m_source->Pos(); } const VECTOR2I GetTargetPos() const { return m_target->Pos(); } + const unsigned GetLength() const + { + return ( m_target->Pos() - m_source->Pos() ).EuclideanNorm(); + } private: std::shared_ptr m_source; diff --git a/pcbnew/tools/pcb_actions.cpp b/pcbnew/tools/pcb_actions.cpp index b26584432b..b74d802df8 100644 --- a/pcbnew/tools/pcb_actions.cpp +++ b/pcbnew/tools/pcb_actions.cpp @@ -1320,6 +1320,12 @@ TOOL_ACTION PCB_ACTIONS::selectUnconnected( "pcbnew.InteractiveSelection.SelectU _( "Select All Unconnected Footprints" ), _( "Selects all unconnected footprints belonging to each selected net." ) ); +TOOL_ACTION PCB_ACTIONS::grabUnconnected( "pcbnew.InteractiveSelection.GrabUnconnected", + AS_GLOBAL, + MD_SHIFT + 'O', "", + _( "Grab Nearest Unconnected Footprints" ), + _( "Selects and initiates moving the nearest unconnected footprint on each selected net." ) ); + TOOL_ACTION PCB_ACTIONS::selectOnSheetFromEeschema( "pcbnew.InteractiveSelection.SelectOnSheet", AS_GLOBAL, 0, "", _( "Sheet" ), @@ -1533,5 +1539,4 @@ TOOL_ACTION PCB_ACTIONS::ddAppendBoard( "pcbnew.Control.DdAppendBoard", AS_GLOBAL ); -TOOL_ACTION PCB_ACTIONS::ddImportFootprint( "pcbnew.Control.ddImportFootprint", - AS_GLOBAL ); \ No newline at end of file +TOOL_ACTION PCB_ACTIONS::ddImportFootprint( "pcbnew.Control.ddImportFootprint", AS_GLOBAL ); diff --git a/pcbnew/tools/pcb_actions.h b/pcbnew/tools/pcb_actions.h index 2b823cde63..5b864a5302 100644 --- a/pcbnew/tools/pcb_actions.h +++ b/pcbnew/tools/pcb_actions.h @@ -91,6 +91,9 @@ public: /// Select unconnected footprints from ratsnest of selection static TOOL_ACTION selectUnconnected; + /// Select and move nearest unconnected footprint from ratsnest of selection + static TOOL_ACTION grabUnconnected; + /// Select all components on sheet from Eeschema crossprobing. static TOOL_ACTION selectOnSheetFromEeschema; diff --git a/pcbnew/tools/pcb_selection_tool.cpp b/pcbnew/tools/pcb_selection_tool.cpp index 7f8fee789d..e6b4e1dda1 100644 --- a/pcbnew/tools/pcb_selection_tool.cpp +++ b/pcbnew/tools/pcb_selection_tool.cpp @@ -90,6 +90,7 @@ public: Add( PCB_ACTIONS::selectOnSchematic ); Add( PCB_ACTIONS::selectUnconnected ); + Add( PCB_ACTIONS::grabUnconnected ); } private: @@ -1445,6 +1446,74 @@ int PCB_SELECTION_TOOL::selectUnconnected( const TOOL_EVENT& aEvent ) } +int PCB_SELECTION_TOOL::grabUnconnected( const TOOL_EVENT& aEvent ) +{ + PCB_SELECTION originalSelection = m_selection; + + // Get all pads + std::vector pads; + + for( EDA_ITEM* item : m_selection.GetItems() ) + { + if( item->Type() == PCB_FOOTPRINT_T ) + { + for( PAD* pad : static_cast( item )->Pads() ) + pads.push_back( pad ); + } + else if( item->Type() == PCB_PAD_T ) + { + pads.push_back( static_cast( item ) ); + } + } + + ClearSelection(); + + // Select every footprint on the end of the ratsnest for each pad in our selection + std::shared_ptr conn = board()->GetConnectivity(); + + for( PAD* pad : pads ) + { + const std::vector edges = conn->GetRatsnestForPad( pad ); + + // Need to have something unconnected to grab + if( edges.size() == 0 ) + continue; + + double currentDistance = DBL_MAX; + FOOTPRINT* nearest = nullptr; + + // Check every ratsnest line for the nearest one + for( const CN_EDGE& edge : edges ) + { + // Figure out if we are the source or the target node on the ratnest + std::shared_ptr ourNode = edge.GetSourceNode()->Parent() == pad + ? edge.GetSourceNode() + : edge.GetTargetNode(); + std::shared_ptr otherNode = edge.GetSourceNode()->Parent() != pad + ? edge.GetSourceNode() + : edge.GetTargetNode(); + + // We only want to grab footprints, so the ratnest has to point to a pad + if( otherNode->Parent()->Type() != PCB_PAD_T ) + continue; + + if( edge.GetLength() < currentDistance ) + { + currentDistance = edge.GetLength(); + nearest = static_cast( otherNode->Parent() )->GetParent(); + } + } + + if( nearest != nullptr ) + select( nearest ); + } + + m_toolMgr->RunAction( PCB_ACTIONS::moveIndividually, true ); + + return 0; +} + + void PCB_SELECTION_TOOL::SelectAllItemsOnNet( int aNetCode, bool aSelect ) { std::shared_ptr conn = board()->GetConnectivity(); @@ -3037,6 +3106,7 @@ void PCB_SELECTION_TOOL::setTransitions() Go( &PCB_SELECTION_TOOL::selectNet, PCB_ACTIONS::selectNet.MakeEvent() ); Go( &PCB_SELECTION_TOOL::selectNet, PCB_ACTIONS::deselectNet.MakeEvent() ); Go( &PCB_SELECTION_TOOL::selectUnconnected, PCB_ACTIONS::selectUnconnected.MakeEvent() ); + Go( &PCB_SELECTION_TOOL::grabUnconnected, PCB_ACTIONS::grabUnconnected.MakeEvent() ); Go( &PCB_SELECTION_TOOL::syncSelection, PCB_ACTIONS::syncSelection.MakeEvent() ); Go( &PCB_SELECTION_TOOL::syncSelectionWithNets, PCB_ACTIONS::syncSelectionWithNets.MakeEvent() ); diff --git a/pcbnew/tools/pcb_selection_tool.h b/pcbnew/tools/pcb_selection_tool.h index 667e6f34fc..2789860420 100644 --- a/pcbnew/tools/pcb_selection_tool.h +++ b/pcbnew/tools/pcb_selection_tool.h @@ -303,6 +303,11 @@ private: */ int selectUnconnected( const TOOL_EVENT& aEvent ); + /** + * Select and move other nearest footprint unconnected on same net as selected items. + */ + int grabUnconnected( const TOOL_EVENT& aEvent ); + enum STOP_CONDITION { /**