PCB Editor: (Auto)Route Selected (From Other End)

3x Selection-Based Routing Tools. Takes a selection of routable objects
and routes them one at a time individually, with an attempted finish, or
from the other end, depending on the action given.
This commit is contained in:
Mike Williams 2022-08-22 08:19:22 -04:00
parent dc20e24c4a
commit 1a023f5dd0
4 changed files with 172 additions and 0 deletions

View File

@ -1309,6 +1309,10 @@ void ROUTER_TOOL::performRouting()
else
{
VECTOR2I moveResultPoint;
bool* autoRouted = evt->Parameter<bool*>();
if( autoRouted != nullptr )
*autoRouted = false;
// Keep moving until we don't change position
do
@ -1322,13 +1326,30 @@ void ROUTER_TOOL::performRouting()
&& otherEndLayers.Overlaps( m_router->GetCurrentLayer() ) )
{
if( m_router->FixRoute( otherEnd, &current, false ) )
{
// When we're routing a group of signals automatically we want
// to break up the undo stack every time we have to manually route
// so the user gets nice checkpoints. Remove the APPEND_UNDO flag.
if( autoRouted != nullptr )
{
*autoRouted = true;
}
break;
}
// This acts as check if we were called by the autorouter; we don't want
// to reset APPEND_UNDO if we're auto finishing after route-other-end
else if( autoRouted != nullptr )
m_iface->SetCommitFlags( 0 );
}
// Otherwise warp the mouse so the user is at the point we managed to route to
else
{
m_iface->SetCommitFlags( 0 );
controls()->WarpMouseCursor( moveResultPoint, true, true );
}
}
}
else if( evt->IsClick( BUT_LEFT ) || evt->IsDrag( BUT_LEFT ) || evt->IsAction( &PCB_ACTIONS::routeSingleTrack ) )
{
updateEndItem( *evt );
@ -1490,6 +1511,129 @@ void ROUTER_TOOL::breakTrack()
}
int ROUTER_TOOL::RouteSelected( const TOOL_EVENT& aEvent )
{
PNS::ROUTER_MODE mode = aEvent.Parameter<PNS::ROUTER_MODE>();
PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
VIEW_CONTROLS* controls = getViewControls();
PCB_LAYER_ID originalLayer = frame->GetActiveLayer();
bool autoRoute = aEvent.Matches( PCB_ACTIONS::routerAutorouteSelected.MakeEvent() );
bool otherEnd = aEvent.Matches( PCB_ACTIONS::routerRouteSelectedFromEnd.MakeEvent() );
if( m_router->RoutingInProgress() )
return 0;
// Save selection then clear it for interactive routing
PCB_SELECTION selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
if( selection.Size() == 0 )
return 0;
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
std::string tool = aEvent.GetCommandStr().value();
frame->PushTool( tool );
auto setCursor =
[&]()
{
frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
};
Activate();
// Must be done after Activate() so that it gets set into the correct context
controls->ShowCursor( true );
controls->ForceCursorPosition( false );
// Set initial cursor
setCursor();
// Get all connected board items, adding pads for any footprints selected
std::vector<BOARD_CONNECTED_ITEM*> itemList;
for( EDA_ITEM* item : selection.GetItemsSortedBySelectionOrder() )
{
if( item->Type() == PCB_FOOTPRINT_T )
{
const PADS& fpPads = ( static_cast<FOOTPRINT*>( item ) )->Pads();
for( PAD* pad : fpPads )
itemList.push_back( pad );
}
else if( dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) != nullptr )
itemList.push_back( static_cast<BOARD_CONNECTED_ITEM*>( item ) );
}
std::shared_ptr<CONNECTIVITY_DATA> connectivity = frame->GetBoard()->GetConnectivity();
// For putting sequential tracks that successfully autoroute into one undo commit
bool groupStart = true;
for( BOARD_CONNECTED_ITEM* item : itemList )
{
// This code is similar to GetRatsnestForPad() but it only adds the anchor for
// the side of the connectivity on this pad. It also checks for ratsnest points
// inside the pad (like a trace end) and counts them.
RN_NET* net = connectivity->GetRatsnestForNet( item->GetNetCode() );
std::vector<std::shared_ptr<CN_ANCHOR>> anchors;
for( const CN_EDGE& edge : net->GetEdges() )
{
std::shared_ptr<CN_ANCHOR> target = edge.GetTargetNode();
std::shared_ptr<CN_ANCHOR> source = edge.GetSourceNode();
if( source->Parent() == item )
anchors.push_back( edge.GetSourceNode() );
else if( target->Parent() == item )
anchors.push_back( edge.GetTargetNode() );
}
// Route them
for( std::shared_ptr<CN_ANCHOR> anchor : anchors )
{
// Try to return to the original layer as indicating the user's preferred
// layer for autorouting tracks. The layer can be changed by the user to
// finish tracks that can't complete automatically, but should be changed
// back after.
if( frame->GetActiveLayer() != originalLayer )
frame->SetActiveLayer( originalLayer );
VECTOR2I ignore;
m_startItem = m_router->GetWorld()->FindItemByParent( anchor->Parent() );
m_startSnapPoint = anchor->Pos();
m_router->SetMode( mode );
// Prime the interactive routing to attempt finish if we are autorouting
bool autoRouted = false;
if( autoRoute )
m_toolMgr->RunAction( PCB_ACTIONS::routerAttemptFinish, false, &autoRouted );
else if( otherEnd )
m_toolMgr->RunAction( PCB_ACTIONS::routerContinueFromEnd, false );
// We want autorouted tracks to all be in one undo group except for
// any tracks that need to be manually finished.
// The undo appending for manually finished tracks is handled in peformRouting()
if( groupStart )
groupStart = false;
else
m_iface->SetCommitFlags( APPEND_UNDO );
// Start interactive routing. Will automatically finish if possible.
performRouting();
// Route didn't complete automatically, need to a new undo commit
// for the next line so those can group as far as they autoroute
if( !autoRouted )
groupStart = true;
}
}
m_iface->SetCommitFlags( 0 );
frame->PopTool( tool );
return 0;
}
int ROUTER_TOOL::MainLoop( const TOOL_EVENT& aEvent )
{
PNS::ROUTER_MODE mode = aEvent.Parameter<PNS::ROUTER_MODE>();
@ -2305,6 +2449,9 @@ void ROUTER_TOOL::setTransitions()
Go( &ROUTER_TOOL::MainLoop, PCB_ACTIONS::routeSingleTrack.MakeEvent() );
Go( &ROUTER_TOOL::MainLoop, PCB_ACTIONS::routeDiffPair.MakeEvent() );
Go( &ROUTER_TOOL::RouteSelected, PCB_ACTIONS::routerRouteSelected.MakeEvent() );
Go( &ROUTER_TOOL::RouteSelected, PCB_ACTIONS::routerRouteSelectedFromEnd.MakeEvent() );
Go( &ROUTER_TOOL::RouteSelected, PCB_ACTIONS::routerAutorouteSelected.MakeEvent() );
Go( &ROUTER_TOOL::DpDimensionsDialog, PCB_ACTIONS::routerDiffPairDialog.MakeEvent() );
Go( &ROUTER_TOOL::SettingsDialog, PCB_ACTIONS::routerSettingsDialog.MakeEvent() );
Go( &ROUTER_TOOL::ChangeRouterMode, PCB_ACTIONS::routerHighlightMode.MakeEvent() );

View File

@ -35,6 +35,7 @@ public:
void Reset( RESET_REASON aReason ) override;
int MainLoop( const TOOL_EVENT& aEvent );
int RouteSelected( const TOOL_EVENT& aEvent );
int InlineBreakTrack( const TOOL_EVENT& aEvent );
bool CanInlineDrag( int aDragMode );

View File

@ -1454,6 +1454,27 @@ TOOL_ACTION PCB_ACTIONS::routerAttemptFinish( "pcbnew.InteractiveRouter.AttemptF
_( "Attempt Finish" ),
_( "Attempts to complete current route to nearest ratsnest end." ) );
TOOL_ACTION PCB_ACTIONS::routerRouteSelected( "pcbnew.InteractiveRouter.RouteSelected",
AS_GLOBAL,
MD_SHIFT + 'X', "",
_( "Route Selected" ),
_( "Sequentially route selected items from ratsnest anchor." ),
BITMAPS::INVALID_BITMAP, AF_ACTIVATE, (void *) PNS::PNS_MODE_ROUTE_SINGLE);
TOOL_ACTION PCB_ACTIONS::routerRouteSelectedFromEnd( "pcbnew.InteractiveRouter.RouteSelectedFromEnd",
AS_GLOBAL,
MD_SHIFT + 'E', "",
_( "Route Selected From Other End" ),
_( "Sequentially route selected items from other end of ratsnest anchor." ),
BITMAPS::INVALID_BITMAP, AF_ACTIVATE, (void *) PNS::PNS_MODE_ROUTE_SINGLE);
TOOL_ACTION PCB_ACTIONS::routerAutorouteSelected( "pcbnew.InteractiveRouter.Autoroute",
AS_GLOBAL,
MD_SHIFT + 'F', "",
_( "Attempt Finish Selected (Autoroute)" ),
_( "Sequentially attempt to automatically route all selected pads." ),
BITMAPS::INVALID_BITMAP, AF_ACTIVATE, (void *) PNS::PNS_MODE_ROUTE_SINGLE);
TOOL_ACTION PCB_ACTIONS::breakTrack( "pcbnew.InteractiveRouter.BreakTrack",
AS_GLOBAL, 0, "",
_( "Break Track" ),

View File

@ -203,6 +203,9 @@ public:
static TOOL_ACTION routerContinueFromEnd;
static TOOL_ACTION routerAttemptFinish;
static TOOL_ACTION routerRouteSelected;
static TOOL_ACTION routerRouteSelectedFromEnd;
static TOOL_ACTION routerAutorouteSelected;
/// Activation of the Push and Shove settings dialogs
static TOOL_ACTION routerSettingsDialog;