router: backspace key to undo last fixed segment(s)

This commit is contained in:
Tomasz Wlostowski 2020-02-07 20:57:24 +01:00
parent b5c11f21e5
commit 4525a17076
16 changed files with 322 additions and 32 deletions

View File

@ -297,7 +297,7 @@ void DRAGGER::dragViaWalkaround( const VIA_HANDLE& aHandle, NODE* aNode, const V
LINE origLine( *l ); LINE origLine( *l );
LINE draggedLine( *l ); LINE draggedLine( *l );
draggedLine.DragCorner( aP, origLine.CLine().Find( aHandle.pos ), 0, m_freeAngleMode ); draggedLine.DragCorner( aP, origLine.CLine().Find( aHandle.pos ), m_freeAngleMode );
draggedLine.ClearSegmentLinks(); draggedLine.ClearSegmentLinks();
m_draggedItems.Add( draggedLine ); m_draggedItems.Add( draggedLine );
@ -425,7 +425,7 @@ bool DRAGGER::dragWalkaround( const VECTOR2I& aP )
bool DRAGGER::dragShove( const VECTOR2I& aP ) bool DRAGGER::dragShove( const VECTOR2I& aP )
{ {
bool ok = false; bool ok = false;
if( m_lastNode ) if( m_lastNode )
{ {
delete m_lastNode; delete m_lastNode;

View File

@ -826,7 +826,7 @@ std::unique_ptr<PNS::SEGMENT> PNS_KICAD_IFACE_BASE::syncTrack( TRACK* aTrack )
} }
std::unique_ptr<PNS::ARC> PNS_KICAD_IFACE::syncArc( ARC* aArc ) std::unique_ptr<PNS::ARC> PNS_KICAD_IFACE_BASE::syncArc( ARC* aArc )
{ {
std::unique_ptr< PNS::ARC > arc( std::unique_ptr< PNS::ARC > arc(
new PNS::ARC( SHAPE_ARC( aArc->GetCenter(), aArc->GetStart(), new PNS::ARC( SHAPE_ARC( aArc->GetCenter(), aArc->GetStart(),

View File

@ -228,7 +228,7 @@ bool LINE::Walkaround( SHAPE_LINE_CHAIN aObstacle, SHAPE_LINE_CHAIN& aPre,
else else
p = aObstacle.CSegment(j).Intersect( a ); p = aObstacle.CSegment(j).Intersect( a );
printf("- cont_a %d cont_b %d p %d\n", !!cont_a, !!cont_b, p ? 1 : 0 ); //printf("- cont_a %d cont_b %d p %d\n", !!cont_a, !!cont_b, p ? 1 : 0 );
if ( p ) if ( p )
@ -238,7 +238,7 @@ bool LINE::Walkaround( SHAPE_LINE_CHAIN aObstacle, SHAPE_LINE_CHAIN& aPre,
ip.their = aObstacle.CSegment(j); ip.their = aObstacle.CSegment(j);
ip.p = *p; ip.p = *p;
ips.push_back(ip); ips.push_back(ip);
printf("chb %d %d\n", p->x, p->y); //printf("chb %d %d\n", p->x, p->y);
} }
} }
} }

View File

@ -427,8 +427,8 @@ bool LINE_PLACER::rhWalkOnly( const VECTOR2I& aP, LINE& aNewHead )
//Dbg()->AddPoint( p_cw, 4 ); //Dbg()->AddPoint( p_cw, 4 );
//Dbg()->AddPoint( p_ccw, 5 ); //Dbg()->AddPoint( p_ccw, 5 );
//Dbg()->AddLine( wr.lineCw.CLine(), 4, 1000 ); Dbg()->AddLine( wr.lineCw.CLine(), 4, 1000 );
//Dbg()->AddLine( wr.lineCcw.CLine(), 5, 1000 ); Dbg()->AddLine( wr.lineCcw.CLine(), 5, 1000 );
} }
@ -841,6 +841,7 @@ void LINE_PLACER::routeStep( const VECTOR2I& aP )
n_iter++; n_iter++;
go_back = true; go_back = true;
} }
} }
if( !fail ) if( !fail )
@ -943,7 +944,10 @@ bool LINE_PLACER::SetLayer( int aLayer )
else if( !m_startItem || ( m_startItem->OfKind( ITEM::VIA_T ) && m_startItem->Layers().Overlaps( aLayer ) ) ) else if( !m_startItem || ( m_startItem->OfKind( ITEM::VIA_T ) && m_startItem->Layers().Overlaps( aLayer ) ) )
{ {
m_currentLayer = aLayer; m_currentLayer = aLayer;
initPlacement(); m_head.Line().Clear();
m_tail.Line().Clear();
m_head.SetLayer( m_currentLayer );
m_tail.SetLayer( m_currentLayer );
Move( m_currentEnd, NULL ); Move( m_currentEnd, NULL );
return true; return true;
} }
@ -960,10 +964,21 @@ bool LINE_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
m_startItem = aStartItem; m_startItem = aStartItem;
m_placingVia = false; m_placingVia = false;
m_chainedPlacement = false; m_chainedPlacement = false;
m_fixedTail.Clear();
setInitialDirection( Settings().InitialDirection() ); setInitialDirection( Settings().InitialDirection() );
initPlacement(); initPlacement();
NODE *n;
if ( m_shove )
n = m_shove->CurrentNode();
else
n = m_currentNode;
m_fixedTail.AddStage( m_currentStart, m_currentLayer, m_placingVia, m_direction, n );
return true; return true;
} }
@ -1017,8 +1032,6 @@ bool LINE_PLACER::Move( const VECTOR2I& aP, ITEM* aEndItem )
VECTOR2I p = aP; VECTOR2I p = aP;
int eiDepth = -1; int eiDepth = -1;
printf(" **** lp move %d %d ei %p\n", aP.x, aP.y, aEndItem );
if( aEndItem && aEndItem->Owner() ) if( aEndItem && aEndItem->Owner() )
eiDepth = static_cast<NODE*>( aEndItem->Owner() )->Depth(); eiDepth = static_cast<NODE*>( aEndItem->Owner() )->Depth();
@ -1090,8 +1103,6 @@ bool LINE_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinis
if( pl.EndsWithVia() ) if( pl.EndsWithVia() )
{ {
m_lastNode->Add( Clone( pl.Via() ) ); m_lastNode->Add( Clone( pl.Via() ) );
Router()->CommitRouting( m_lastNode );
m_lastNode = NULL; m_lastNode = NULL;
m_currentNode = NULL; m_currentNode = NULL;
@ -1150,24 +1161,37 @@ bool LINE_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinis
} }
if( pl.EndsWithVia() ) if( pl.EndsWithVia() )
{
m_lastNode->Add( Clone( pl.Via() ) ); m_lastNode->Add( Clone( pl.Via() ) );
}
if( realEnd && lastSeg ) if( realEnd && lastSeg )
simplifyNewLine( m_lastNode, lastSeg ); simplifyNewLine( m_lastNode, lastSeg );
Router()->CommitRouting( m_lastNode );
m_lastNode = NULL;
m_currentNode = NULL;
if( !realEnd ) if( !realEnd )
{ {
setInitialDirection( d_last ); setInitialDirection( d_last );
m_currentStart = m_placingVia ? p_last : p_pre_last; m_currentStart = m_placingVia ? p_last : p_pre_last;
m_fixedTail.AddStage( m_p_start, m_currentLayer, m_placingVia, m_direction, m_currentNode );
m_startItem = NULL; m_startItem = NULL;
m_placingVia = false; m_placingVia = false;
m_chainedPlacement = !pl.EndsWithVia(); m_chainedPlacement = !pl.EndsWithVia();
initPlacement();
m_p_start = m_currentStart;
m_direction = m_initial_direction;
m_head.Line().Clear();
m_tail.Line().Clear();
m_currentNode = m_lastNode;
m_lastNode = m_lastNode->Branch();
if ( m_shove )
{
m_shove->AddLockedSpringbackNode( m_currentNode );
}
} }
else else
{ {
@ -1178,6 +1202,56 @@ bool LINE_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinis
} }
bool LINE_PLACER::UnfixRoute()
{
FIXED_TAIL::STAGE st;
if ( !m_fixedTail.PopStage( st ) )
return false;
m_head.Line().Clear();
m_tail.Line().Clear();
m_startItem = NULL;
m_p_start = st.pts[0].p;
m_direction = st.pts[0].direction;
m_placingVia = st.pts[0].placingVias;
m_currentNode = st.commit;
m_currentLayer = st.pts[0].layer;
m_head.SetLayer( m_currentLayer );
m_tail.SetLayer( m_currentLayer );
m_head.RemoveVia( );
m_tail.RemoveVia( );
if (m_shove)
{
m_shove->RewindSpringbackTo( m_currentNode );
m_shove->UnlockSpringbackNode( m_currentNode );
m_currentNode = m_shove->CurrentNode();
m_currentNode->KillChildren();
}
m_lastNode = m_currentNode->Branch();
return true;
}
bool LINE_PLACER::HasPlacedAnything() const
{
return m_fixedTail.StageCount() > 1;
}
bool LINE_PLACER::CommitPlacement()
{
Router()->CommitRouting( m_lastNode );
m_lastNode = NULL;
m_currentNode = NULL;
return true;
}
void LINE_PLACER::removeLoops( NODE* aNode, LINE& aLatest ) void LINE_PLACER::removeLoops( NODE* aNode, LINE& aLatest )
{ {
if( !aLatest.SegmentCount() ) if( !aLatest.SegmentCount() )
@ -1252,7 +1326,7 @@ void LINE_PLACER::UpdateSizes( const SIZES_SETTINGS& aSizes )
// initPlacement will kill the tail, don't do that unless the track size has changed // initPlacement will kill the tail, don't do that unless the track size has changed
if( !m_idle && aSizes.TrackWidth() != m_sizes.TrackWidth() ) if( !m_idle && aSizes.TrackWidth() != m_sizes.TrackWidth() )
{ {
m_sizes = aSizes; m_sizes = aSizes;
initPlacement(); initPlacement();
} }
@ -1266,8 +1340,8 @@ void LINE_PLACER::updateLeadingRatLine()
SHAPE_LINE_CHAIN ratLine; SHAPE_LINE_CHAIN ratLine;
TOPOLOGY topo( m_lastNode ); TOPOLOGY topo( m_lastNode );
//if( topo.LeadingRatLine( &current, ratLine ) ) if( topo.LeadingRatLine( &current, ratLine ) )
//Dbg()->AddLine( ratLine, 5, 10000 ); Dbg()->AddLine( ratLine, 5, 10000 );
} }
@ -1313,6 +1387,7 @@ bool LINE_PLACER::buildInitialLine( const VECTOR2I& aP, LINE& aHead, bool aInver
} }
} }
aHead.SetLayer( m_currentLayer );
aHead.SetShape( l ); aHead.SetShape( l );
if( !m_placingVia ) if( !m_placingVia )
@ -1351,4 +1426,61 @@ void LINE_PLACER::GetModifiedNets( std::vector<int>& aNets ) const
} }
bool LINE_PLACER::AbortPlacement()
{
m_world->KillChildren();
return true;
}
FIXED_TAIL::FIXED_TAIL ( int aLineCount )
{
}
FIXED_TAIL::~FIXED_TAIL()
{
}
void FIXED_TAIL::Clear()
{
m_stages.clear();
}
void FIXED_TAIL::AddStage( VECTOR2I aStart, int aLayer, bool placingVias, DIRECTION_45 direction, NODE *aNode )
{
STAGE st;
FIX_POINT pt;
pt.p = aStart;
pt.layer = aLayer;
pt.direction = direction;
pt.placingVias = placingVias;
st.pts.push_back(pt);
st.commit = aNode;
m_stages.push_back( st );
}
bool FIXED_TAIL::PopStage( FIXED_TAIL::STAGE& aStage )
{
if( !m_stages.size() )
return false;
aStage = m_stages.back();
if( m_stages.size() > 1 )
m_stages.pop_back();
return true;
}
int FIXED_TAIL::StageCount() const
{
return m_stages.size();
}
} }

View File

@ -40,7 +40,35 @@ class SHOVE;
class OPTIMIZER; class OPTIMIZER;
class VIA; class VIA;
class SIZES_SETTINGS; class SIZES_SETTINGS;
class NODE;
class FIXED_TAIL {
public:
FIXED_TAIL ( int aLineCount = 1);
~FIXED_TAIL();
struct FIX_POINT
{
int layer;
bool placingVias;
VECTOR2I p;
DIRECTION_45 direction;
};
struct STAGE {
NODE *commit;
std::vector<FIX_POINT> pts;
};
void Clear();
void AddStage( VECTOR2I aStart, int aLayer, bool placingVias, DIRECTION_45 direction, NODE *aNode );
bool PopStage( STAGE& aStage );
int StageCount() const;
private:
std::vector<STAGE> m_stages;
};
/** /**
* LINE_PLACER * LINE_PLACER
@ -83,6 +111,14 @@ public:
*/ */
bool FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinish ) override; bool FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinish ) override;
bool UnfixRoute() override;
bool CommitPlacement() override;
bool AbortPlacement() override;
bool HasPlacedAnything() const override;
/** /**
* Function ToggleVia() * Function ToggleVia()
* *
@ -187,8 +223,6 @@ public:
void GetModifiedNets( std::vector<int>& aNets ) const override; void GetModifiedNets( std::vector<int>& aNets ) const override;
LOGGER* Logger() override;
/** /**
* Function SplitAdjacentSegments() * Function SplitAdjacentSegments()
* *
@ -398,6 +432,8 @@ private:
bool m_idle; bool m_idle;
bool m_chainedPlacement; bool m_chainedPlacement;
bool m_orthoMode; bool m_orthoMode;
FIXED_TAIL m_fixedTail;
}; };
} }

View File

@ -1276,7 +1276,6 @@ void NODE::Commit( NODE* aNode )
void NODE::KillChildren() void NODE::KillChildren()
{ {
assert( isRoot() );
releaseChildren(); releaseChildren();
} }

View File

@ -423,6 +423,11 @@ public:
return !m_children.empty(); return !m_children.empty();
} }
NODE* GetParent() const
{
return m_parent;
}
///> checks if this branch contains an updated version of the m_item ///> checks if this branch contains an updated version of the m_item
///> from the root branch. ///> from the root branch.
bool Overrides( ITEM* aItem ) const bool Overrides( ITEM* aItem ) const

View File

@ -197,7 +197,7 @@ void OPTIMIZER::removeCachedSegments( LINE* aLine, int aStartVertex, int aEndVer
for( int i = aStartVertex; i < aEndVertex - 1; i++ ) for( int i = aStartVertex; i < aEndVertex - 1; i++ )
{ {
SEGMENT* s = segs[i]; LINKED_ITEM* s = segs[i];
m_cacheTags.erase( s ); m_cacheTags.erase( s );
m_cache.Remove( s ); m_cache.Remove( s );
} }
@ -344,7 +344,7 @@ static bool pointInside2( const SHAPE_LINE_CHAIN& aL, const VECTOR2I& aP )
if( (ipNext.x ==aP.x) || ( ip.y ==aP.y if( (ipNext.x ==aP.x) || ( ip.y ==aP.y
&& ( (ipNext.x >aP.x) == (ip.x <aP.x) ) ) ) && ( (ipNext.x >aP.x) == (ip.x <aP.x) ) ) )
return -1; return -1;
} }
if( (ip.y <aP.y) != (ipNext.y <aP.y) ) if( (ip.y <aP.y) != (ipNext.y <aP.y) )
{ {

View File

@ -78,6 +78,14 @@ public:
*/ */
virtual bool FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinish = false ) = 0; virtual bool FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinish = false ) = 0;
virtual bool UnfixRoute() { return false; };
virtual bool CommitPlacement() { return false; };
virtual bool AbortPlacement() { return false; };
virtual bool HasPlacedAnything() const { return false; }
/** /**
* Function ToggleVia() * Function ToggleVia()
* *
@ -183,6 +191,8 @@ public:
virtual void GetModifiedNets( std::vector<int> &aNets ) const virtual void GetModifiedNets( std::vector<int> &aNets ) const
{ {
} }
}; };
} }

View File

@ -360,6 +360,9 @@ void ROUTER::movePlacing( const VECTOR2I& aP, ITEM* aEndItem )
void ROUTER::CommitRouting( NODE* aNode ) void ROUTER::CommitRouting( NODE* aNode )
{ {
if( m_state == ROUTE_TRACK && !m_placer->HasPlacedAnything() )
return;
NODE::ITEM_VECTOR removed, added; NODE::ITEM_VECTOR removed, added;
aNode->GetUpdatedItems( removed, added ); aNode->GetUpdatedItems( removed, added );
@ -393,13 +396,26 @@ bool ROUTER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinish )
break; break;
} }
if( rv )
StopRouting();
return rv; return rv;
} }
void ROUTER::UndoLastSegment()
{
if( !RoutingInProgress() )
return;
m_placer->UnfixRoute();
}
void ROUTER::CommitRouting()
{
m_placer->CommitPlacement();
StopRouting();
}
void ROUTER::StopRouting() void ROUTER::StopRouting()
{ {
// Update the ratsnest with new changes // Update the ratsnest with new changes

View File

@ -141,6 +141,8 @@ public:
bool FixRoute( const VECTOR2I& aP, ITEM* aItem, bool aForceFinish = false ); bool FixRoute( const VECTOR2I& aP, ITEM* aItem, bool aForceFinish = false );
void BreakSegment( ITEM *aItem, const VECTOR2I& aP ); void BreakSegment( ITEM *aItem, const VECTOR2I& aP );
void UndoLastSegment();
void CommitRouting();
void StopRouting(); void StopRouting();
int GetClearance( const ITEM* aA, const ITEM* aB ) const; int GetClearance( const ITEM* aA, const ITEM* aB ) const;

View File

@ -626,7 +626,7 @@ NODE* SHOVE::reduceSpringback( const ITEM_SET& aHeadSet, VIA_HANDLE& aDraggedVia
auto obs = spTag.m_node->CheckColliding( aHeadSet ); auto obs = spTag.m_node->CheckColliding( aHeadSet );
if( !obs ) if( !obs && !spTag.m_locked )
{ {
aDraggedVia = spTag.m_draggedVia; aDraggedVia = spTag.m_draggedVia;
aDraggedVia.valid = true; aDraggedVia.valid = true;
@ -670,6 +670,9 @@ bool SHOVE::pushSpringback( NODE* aNode, const OPT_BOX2I& aAffectedArea, VIA* aD
} else } else
st.m_affectedArea = prev_area; st.m_affectedArea = prev_area;
st.m_seq = (m_nodeStack.empty() ? 1 : m_nodeStack.back().m_seq + 1);
st.m_locked = false;
m_nodeStack.push_back( st ); m_nodeStack.push_back( st );
return true; return true;
@ -1607,4 +1610,61 @@ void SHOVE::SetInitialLine( LINE& aInitial )
m_root->Remove( aInitial ); m_root->Remove( aInitial );
} }
bool SHOVE::AddLockedSpringbackNode( NODE* aNode )
{
SPRINGBACK_TAG sp;
sp.m_node = aNode;
sp.m_locked = true;
m_nodeStack.push_back(sp);
return true;
} }
bool SHOVE::RewindSpringbackTo( NODE* aNode )
{
bool found = false;
auto iter = m_nodeStack.begin();
while( iter != m_nodeStack.end() )
{
if ( iter->m_node == aNode )
{
printf("FOUND\n");
found = true;
break;
}
iter++;
}
if( !found )
return false;
auto start = iter;
aNode->KillChildren();
m_nodeStack.erase( start, m_nodeStack.end() );
return true;
}
void SHOVE::UnlockSpringbackNode( NODE* aNode )
{
auto iter = m_nodeStack.begin();
while( iter != m_nodeStack.end() )
{
if ( iter->m_node == aNode )
{
iter->m_locked = false;
break;
}
iter++;
}
}
}

View File

@ -86,6 +86,10 @@ public:
void SetInitialLine( LINE& aInitial ); void SetInitialLine( LINE& aInitial );
bool AddLockedSpringbackNode( NODE* aNode );
void UnlockSpringbackNode( NODE* aNode );
bool RewindSpringbackTo( NODE* aNode );
private: private:
typedef std::vector<SHAPE_LINE_CHAIN> HULL_SET; typedef std::vector<SHAPE_LINE_CHAIN> HULL_SET;
typedef OPT<LINE> OPT_LINE; typedef OPT<LINE> OPT_LINE;
@ -99,6 +103,8 @@ private:
VECTOR2I m_p; VECTOR2I m_p;
NODE* m_node; NODE* m_node;
OPT_BOX2I m_affectedArea; OPT_BOX2I m_affectedArea;
int m_seq;
bool m_locked;
}; };
SHOVE_STATUS processHullSet( LINE& aCurrent, LINE& aObstacle, SHOVE_STATUS processHullSet( LINE& aCurrent, LINE& aObstacle,
@ -147,6 +153,7 @@ private:
NODE* m_root; NODE* m_root;
NODE* m_currentNode; NODE* m_currentNode;
int m_restrictSpringbackTagId;
OPT_LINE m_newHead; OPT_LINE m_newHead;

View File

@ -224,20 +224,20 @@ const WALKAROUND::RESULT WALKAROUND::Route( const LINE& aInitialPath )
//Dbg()->AddLine( path_cw.CLine(), 2, 10000 ); //Dbg()->AddLine( path_cw.CLine(), 2, 10000 );
printf("iter %d s_cw %d s_ccw %d\n", m_iteration, s_cw, s_ccw ); //printf("iter %d s_cw %d s_ccw %d\n", m_iteration, s_cw, s_ccw );
auto old = path_cw.CLine(); auto old = path_cw.CLine();
if( clipToLoopStart( path_cw.Line() )) if( clipToLoopStart( path_cw.Line() ))
{ {
printf("ClipCW\n"); //printf("ClipCW\n");
//Dbg()->AddLine( old, 1, 40000 ); //Dbg()->AddLine( old, 1, 40000 );
s_cw = ALMOST_DONE; s_cw = ALMOST_DONE;
} }
if( clipToLoopStart( path_ccw.Line() )) if( clipToLoopStart( path_ccw.Line() ))
{ {
printf("ClipCCW\n"); //printf("ClipCCW\n");
s_ccw = ALMOST_DONE; s_ccw = ALMOST_DONE;
} }

View File

@ -75,6 +75,12 @@ enum VIA_ACTION_FLAGS
#undef _ #undef _
#define _(s) s #define _(s) s
static const TOOL_ACTION ACT_UndoLastSegment( "pcbnew.InteractiveRouter.UndoLastSegment",
AS_CONTEXT,
WXK_BACK, "",
_( "Undo last segment" ), _( "Stops laying the current track." ),
checked_ok_xpm );
static const TOOL_ACTION ACT_EndTrack( "pcbnew.InteractiveRouter.EndTrack", static const TOOL_ACTION ACT_EndTrack( "pcbnew.InteractiveRouter.EndTrack",
AS_CONTEXT, AS_CONTEXT,
WXK_END, "", WXK_END, "",
@ -389,6 +395,7 @@ public:
Add( PCB_ACTIONS::routeSingleTrack ); Add( PCB_ACTIONS::routeSingleTrack );
Add( PCB_ACTIONS::routeDiffPair ); Add( PCB_ACTIONS::routeDiffPair );
Add( ACT_EndTrack ); Add( ACT_EndTrack );
Add( ACT_UndoLastSegment );
Add( PCB_ACTIONS::breakTrack ); Add( PCB_ACTIONS::breakTrack );
Add( PCB_ACTIONS::drag45Degree ); Add( PCB_ACTIONS::drag45Degree );
@ -757,6 +764,8 @@ bool ROUTER_TOOL::finishInteractive()
void ROUTER_TOOL::performRouting() void ROUTER_TOOL::performRouting()
{ {
bool finished = false;
if( !prepareInteractive() ) if( !prepareInteractive() )
return; return;
@ -775,6 +784,12 @@ void ROUTER_TOOL::performRouting()
updateEndItem( *evt ); updateEndItem( *evt );
m_router->Move( m_endSnapPoint, m_endItem ); m_router->Move( m_endSnapPoint, m_endItem );
} }
else if( evt->IsAction( &ACT_UndoLastSegment ) )
{
m_router->UndoLastSegment();
updateEndItem( *evt );
m_router->Move( m_endSnapPoint, m_endItem );
}
else if( evt->IsClick( BUT_LEFT ) || evt->IsAction( &PCB_ACTIONS::routeSingleTrack ) ) else if( evt->IsClick( BUT_LEFT ) || evt->IsAction( &PCB_ACTIONS::routeSingleTrack ) )
{ {
updateEndItem( *evt ); updateEndItem( *evt );
@ -783,7 +798,10 @@ void ROUTER_TOOL::performRouting()
if( m_router->FixRoute( m_endSnapPoint, m_endItem, forceFinish ) ) if( m_router->FixRoute( m_endSnapPoint, m_endItem, forceFinish ) )
{
finished = true;
break; break;
}
if( needLayerSwitch ) if( needLayerSwitch )
switchLayerOnViaPlacement(); switchLayerOnViaPlacement();
@ -840,6 +858,9 @@ void ROUTER_TOOL::performRouting()
} }
} }
m_router->CommitRouting();
m_router->StopRouting();
finishInteractive(); finishInteractive();
} }

View File

@ -189,6 +189,8 @@ public:
/// Activation of the Push and Shove router (skew tuning mode) /// Activation of the Push and Shove router (skew tuning mode)
static TOOL_ACTION routerTuneDiffPairSkew; static TOOL_ACTION routerTuneDiffPairSkew;
static TOOL_ACTION routerUndoLastSegment;
/// Activation of the Push and Shove settings dialogs /// Activation of the Push and Shove settings dialogs
static TOOL_ACTION routerSettingsDialog; static TOOL_ACTION routerSettingsDialog;
static TOOL_ACTION routerDiffPairDialog; static TOOL_ACTION routerDiffPairDialog;