From 37a754c4ddb6580c6826a9a50e93fea2009f38f4 Mon Sep 17 00:00:00 2001 From: Tomasz Wlostowski Date: Wed, 19 Feb 2020 18:22:37 +0100 Subject: [PATCH] router: initial attempt at improved 'aim at mouse cursor' strategy in walkaround mode, wip... --- pcbnew/router/pns_line_placer.cpp | 75 ++++++++++-- pcbnew/router/pns_walkaround.cpp | 196 +++++++++++++++++++++++++++--- pcbnew/router/pns_walkaround.h | 22 +++- 3 files changed, 256 insertions(+), 37 deletions(-) diff --git a/pcbnew/router/pns_line_placer.cpp b/pcbnew/router/pns_line_placer.cpp index f3fb2d785a..cbe65c5da9 100644 --- a/pcbnew/router/pns_line_placer.cpp +++ b/pcbnew/router/pns_line_placer.cpp @@ -366,10 +366,32 @@ bool LINE_PLACER::mergeHead() } +VECTOR2I closestProjectedPoint( const SHAPE_LINE_CHAIN& line, const VECTOR2I& p ) +{ + int min_dist = INT_MAX; + VECTOR2I closest; + + for(int i = 0; i < line.SegmentCount(); i++ ) + { + const auto& s = line.CSegment(i); + auto a = s.NearestPoint( p ); + auto d = (a - p).EuclideanNorm(); + + if( d < min_dist ) + { + min_dist = d; + closest = a; + } + } + + return closest; +} + + bool LINE_PLACER::rhWalkOnly( const VECTOR2I& aP, LINE& aNewHead ) { LINE initTrack( m_head ); - LINE walkFull; + LINE walkFull( m_head ); int effort = 0; bool rv = true, viaOk; @@ -379,9 +401,40 @@ bool LINE_PLACER::rhWalkOnly( const VECTOR2I& aP, LINE& aNewHead ) walkaround.SetSolidsOnly( false ); walkaround.SetDebugDecorator( Dbg() ); + walkaround.SetLogger( Logger() ); walkaround.SetIterationLimit( Settings().WalkaroundIterationLimit() ); - WALKAROUND::WALKAROUND_STATUS wf = walkaround.Route( initTrack, walkFull, false ); + WALKAROUND::RESULT wr = walkaround.Route( initTrack ); + //WALKAROUND::WALKAROUND_STATUS wf = walkaround.Route( initTrack, walkFull, false ); + + auto l_cw = wr.lineCw.CLine(); + auto l_ccw = wr.lineCcw.CLine(); + + if( wr.statusCcw == WALKAROUND::ALMOST_DONE || wr.statusCw == WALKAROUND::ALMOST_DONE ) + { + + auto p_cw = closestProjectedPoint( l_cw, aP ); + auto p_ccw = closestProjectedPoint( l_ccw, aP ); + + int idx_cw = l_cw.Split( p_cw ); + int idx_ccw = l_ccw.Split( p_ccw ); + + l_cw = l_cw.Slice( 0, idx_cw ); + l_ccw = l_ccw.Slice( 0, idx_ccw ); + + //Dbg()->AddLine( wr.lineCw.CLine(), 3, 40000 ); + + //Dbg()->AddPoint( p_cw, 4 ); + //Dbg()->AddPoint( p_ccw, 5 ); + + //Dbg()->AddLine( wr.lineCw.CLine(), 4, 1000 ); + //Dbg()->AddLine( wr.lineCcw.CLine(), 5, 1000 ); + + } + + walkFull.SetShape( l_ccw.Length() < l_cw.Length() ? l_ccw : l_cw ); + + Dbg()->AddLine( walkFull.CLine(), 2, 100000, "walk-full" ); switch( Settings().OptimizerEffort() ) { @@ -398,7 +451,7 @@ bool LINE_PLACER::rhWalkOnly( const VECTOR2I& aP, LINE& aNewHead ) if( Settings().SmartPads() ) effort |= OPTIMIZER::SMART_PADS; - if( wf == WALKAROUND::STUCK ) + if( wr.statusCw == WALKAROUND::STUCK || wr.statusCcw == WALKAROUND::STUCK ) { walkFull = walkFull.ClipToNearestObstacle( m_currentNode ); rv = true; @@ -578,6 +631,10 @@ bool LINE_PLACER::rhShoveOnly( const VECTOR2I& aP, LINE& aNewHead ) bool viaOk = buildInitialLine( aP, initTrack ); m_currentNode = m_shove->CurrentNode(); + + m_shove->SetLogger( Logger() ); + m_shove->SetDebugDecorator( Dbg() ); + OPTIMIZER optimizer( m_currentNode ); WALKAROUND walkaround( m_currentNode, Router() ); @@ -585,6 +642,7 @@ bool LINE_PLACER::rhShoveOnly( const VECTOR2I& aP, LINE& aNewHead ) walkaround.SetSolidsOnly( true ); walkaround.SetIterationLimit( 10 ); walkaround.SetDebugDecorator( Dbg() ); + walkaround.SetLogger( Logger() ); WALKAROUND::WALKAROUND_STATUS stat_solids = walkaround.Route( initTrack, walkSolids ); optimizer.SetEffortLevel( OPTIMIZER::MERGE_SEGMENTS ); @@ -1204,8 +1262,8 @@ void LINE_PLACER::updateLeadingRatLine() SHAPE_LINE_CHAIN ratLine; TOPOLOGY topo( m_lastNode ); - if( topo.LeadingRatLine( ¤t, ratLine ) ) - Dbg()->AddLine( ratLine, 5, 10000 ); + //if( topo.LeadingRatLine( ¤t, ratLine ) ) + //Dbg()->AddLine( ratLine, 5, 10000 ); } @@ -1288,12 +1346,5 @@ void LINE_PLACER::GetModifiedNets( std::vector& aNets ) const aNets.push_back( m_currentNet ); } -LOGGER* LINE_PLACER::Logger() -{ - if( m_shove ) - return m_shove->Logger(); - - return NULL; -} } diff --git a/pcbnew/router/pns_walkaround.cpp b/pcbnew/router/pns_walkaround.cpp index 07c64823b2..7b800d5ad3 100644 --- a/pcbnew/router/pns_walkaround.cpp +++ b/pcbnew/router/pns_walkaround.cpp @@ -27,6 +27,7 @@ #include "pns_optimizer.h" #include "pns_utils.h" #include "pns_router.h" +#include "pns_debug_decorator.h" namespace PNS { @@ -57,8 +58,6 @@ WALKAROUND::WALKAROUND_STATUS WALKAROUND::singleStep( LINE& aPath, OPT& current_obs = aWindingDirection ? m_currentObstacle[0] : m_currentObstacle[1]; - bool& prev_recursive = aWindingDirection ? m_recursiveCollision[0] : m_recursiveCollision[1]; - if( !current_obs ) return DONE; @@ -79,23 +78,36 @@ WALKAROUND::WALKAROUND_STATUS WALKAROUND::singleStep( LINE& aPath, } } - if( ! aPath.Walkaround( current_obs->m_hull, path_pre[0], path_walk[0], - path_post[0], aWindingDirection ) ) - return STUCK; + aPath.Walkaround( current_obs->m_hull, path_pre[0], path_walk[0], + path_post[0], aWindingDirection ); + aPath.Walkaround( current_obs->m_hull, path_pre[1], path_walk[1], + path_post[1], !aWindingDirection ); if( ! aPath.Walkaround( current_obs->m_hull, path_pre[1], path_walk[1], path_post[1], !aWindingDirection ) ) return STUCK; - + auto l =aPath.CLine(); #ifdef DEBUG - m_logger.NewGroup( aWindingDirection ? "walk-cw" : "walk-ccw", m_iteration ); - m_logger.Log( &path_walk[0], 0, "path-walk" ); - m_logger.Log( &path_pre[0], 1, "path-pre" ); - m_logger.Log( &path_post[0], 4, "path-post" ); - m_logger.Log( ¤t_obs->m_hull, 2, "hull" ); - m_logger.Log( current_obs->m_item, 3, "item" ); + if( m_logger ) + { + m_logger->NewGroup( aWindingDirection ? "walk-cw" : "walk-ccw", m_iteration ); + m_logger->Log( &path_walk[0], 0, "path_walk" ); + m_logger->Log( &path_pre[0], 1, "path_pre" ); + m_logger->Log( &path_post[0], 4, "path_post" ); + m_logger->Log( ¤t_obs->m_hull, 2, "hull" ); + m_logger->Log( current_obs->m_item, 3, "item" ); + } #endif + if ( Dbg() ) + { + char name[128]; + snprintf(name, sizeof(name), "hull-%s-%d", aWindingDirection ? "cw" : "ccw", m_iteration ); + Dbg()->AddLine( current_obs->m_hull, 0, 1, name); + snprintf(name, sizeof(name), "path-%s-%d", aWindingDirection ? "cw" : "ccw", m_iteration ); + Dbg()->AddLine( aPath.CLine(), 1, 1, name ); + } + int len_pre = path_walk[0].Length(); int len_alt = path_walk[1].Length(); @@ -105,7 +117,7 @@ WALKAROUND::WALKAROUND_STATUS WALKAROUND::singleStep( LINE& aPath, SHAPE_LINE_CHAIN pnew; - if( !m_forceLongerPath && len_alt < len_pre && !alt_collides && !prev_recursive ) + /*if( !m_forceLongerPath && len_alt < len_pre && !alt_collides && !prev_recursive ) { pnew = path_pre[1]; pnew.Append( path_walk[1] ); @@ -115,26 +127,22 @@ WALKAROUND::WALKAROUND_STATUS WALKAROUND::singleStep( LINE& aPath, current_obs = nearestObstacle( LINE( aPath, path_pre[1] ) ); else current_obs = nearestObstacle( LINE( aPath, path_post[1] ) ); - prev_recursive = false; } - else + else*/ { pnew = path_pre[0]; pnew.Append( path_walk[0] ); pnew.Append( path_post[0] ); - if( !path_post[0].PointCount() || !path_walk[0].PointCount() ) + if( path_post[0].PointCount() == 0 || path_walk[0].PointCount() == 0 ) current_obs = nearestObstacle( LINE( aPath, path_pre[0] ) ); else current_obs = nearestObstacle( LINE( aPath, path_walk[0] ) ); if( !current_obs ) { - prev_recursive = false; current_obs = nearestObstacle( LINE( aPath, path_post[0] ) ); } - else - prev_recursive = true; } pnew.Simplify(); @@ -144,6 +152,154 @@ WALKAROUND::WALKAROUND_STATUS WALKAROUND::singleStep( LINE& aPath, } + +bool clipToLoopStart( SHAPE_LINE_CHAIN& l ) +{ + auto ip = l.SelfIntersecting(); + + if(!ip) + return false; + else { + int pidx = l.Split( ip->p ); + auto lead = l.Slice(0, pidx); + auto tail = l.Slice(pidx + 1, -1); + + int pidx2 = tail.Split( ip->p ); + + auto dbg = ROUTER::GetInstance()->GetInterface()->GetDebugDecorator(); + dbg->AddPoint( ip->p, 5 ); + + l = lead; + l.Append( tail.Slice( 0, pidx2 ) ); + //l = l.Slice(0, pidx); + return true; + } + + +} + + + +const WALKAROUND::RESULT WALKAROUND::Route( const LINE& aInitialPath ) +{ + LINE path_cw( aInitialPath ), path_ccw( aInitialPath ); + WALKAROUND_STATUS s_cw = IN_PROGRESS, s_ccw = IN_PROGRESS; + SHAPE_LINE_CHAIN best_path; + RESULT result; + + // special case for via-in-the-middle-of-track placement + if( aInitialPath.PointCount() <= 1 ) + { + if( aInitialPath.EndsWithVia() && m_world->CheckColliding( &aInitialPath.Via(), m_itemMask ) ) + return RESULT( STUCK, STUCK ); + + return RESULT( DONE, DONE, aInitialPath, aInitialPath ); + } + + start( aInitialPath ); + + m_currentObstacle[0] = m_currentObstacle[1] = nearestObstacle( aInitialPath ); + m_recursiveBlockageCount = 0; + + result.lineCw = aInitialPath; + result.lineCcw = aInitialPath; + + if( m_forceWinding ) + { + s_cw = m_forceCw ? IN_PROGRESS : STUCK; + s_ccw = m_forceCw ? STUCK : IN_PROGRESS; + m_forceSingleDirection = true; + } else { + m_forceSingleDirection = false; + } + + while( m_iteration < m_iterationLimit ) + { + if( s_cw != STUCK ) + s_cw = singleStep( path_cw, true ); + + if( s_ccw != STUCK ) + s_ccw = singleStep( path_ccw, false ); + + //Dbg()->AddLine( path_cw.CLine(), 2, 10000 ); + + + printf("iter %d s_cw %d s_ccw %d\n", m_iteration, s_cw, s_ccw ); + + auto old = path_cw.CLine(); + + if( clipToLoopStart( path_cw.Line() )) + { + printf("ClipCW\n"); + //Dbg()->AddLine( old, 1, 40000 ); + s_cw = ALMOST_DONE; + } + + if( clipToLoopStart( path_ccw.Line() )) + { + printf("ClipCCW\n"); + s_ccw = ALMOST_DONE; + } + + + if( s_cw != IN_PROGRESS ) + { + result.lineCw = path_cw; + result.statusCw = s_cw; + } + + if( s_ccw != IN_PROGRESS ) + { + result.lineCcw = path_ccw; + result.statusCcw = s_ccw; + } + + if( s_cw != IN_PROGRESS && s_ccw != IN_PROGRESS ) + break; + + m_iteration++; + } + + if( s_cw == IN_PROGRESS ) + { + result.lineCw = path_cw; + result.statusCw = ALMOST_DONE; + } + + if( s_ccw == IN_PROGRESS ) + { + result.lineCcw = path_ccw; + result.statusCcw = ALMOST_DONE; + } + + result.lineCw.Line().Simplify(); + result.lineCcw.Line().Simplify(); + + if( result.lineCw.SegmentCount() < 1 || result.lineCw.CPoint( 0 ) != aInitialPath.CPoint( 0 ) ) + { + result.statusCw = STUCK; + } + + if( result.lineCw.PointCount() > 0 && result.lineCw.CPoint( -1 ) != aInitialPath.CPoint( -1 ) ) + { + result.statusCw = ALMOST_DONE; + } + + if( result.lineCcw.SegmentCount() < 1 || result.lineCcw.CPoint( 0 ) != aInitialPath.CPoint( 0 ) ) + { + result.statusCcw = STUCK; + } + + if( result.lineCcw.PointCount() > 0 && result.lineCcw.CPoint( -1 ) != aInitialPath.CPoint( -1 ) ) + { + result.statusCcw = ALMOST_DONE; + } + + return result; +} + + + WALKAROUND::WALKAROUND_STATUS WALKAROUND::Route( const LINE& aInitialPath, LINE& aWalkPath, bool aOptimize ) { @@ -261,7 +417,7 @@ WALKAROUND::WALKAROUND_STATUS WALKAROUND::Route( const LINE& aInitialPath, if( aWalkPath.SegmentCount() < 1 ) return STUCK; if( aWalkPath.CPoint( -1 ) != aInitialPath.CPoint( -1 ) ) - return STUCK; + return ALMOST_DONE; if( aWalkPath.CPoint( 0 ) != aInitialPath.CPoint( 0 ) ) return STUCK; diff --git a/pcbnew/router/pns_walkaround.h b/pcbnew/router/pns_walkaround.h index 1524c07325..b0150290f3 100644 --- a/pcbnew/router/pns_walkaround.h +++ b/pcbnew/router/pns_walkaround.h @@ -60,10 +60,25 @@ public: enum WALKAROUND_STATUS { IN_PROGRESS = 0, + ALMOST_DONE, DONE, STUCK }; + struct RESULT + { + RESULT( WALKAROUND_STATUS aStatusCw = STUCK, WALKAROUND_STATUS aStatusCcw = STUCK, const LINE& aLineCw = LINE(), const LINE& aLineCcw = LINE() ) + { + statusCw = aStatusCw; + statusCcw = aStatusCcw; + lineCw = aLineCw; + lineCcw = aLineCcw; + } + + WALKAROUND_STATUS statusCw, statusCcw; + LINE lineCw, lineCcw; + }; + void SetWorld( NODE* aNode ) { m_world = aNode; @@ -121,10 +136,7 @@ public: WALKAROUND_STATUS Route( const LINE& aInitialPath, LINE& aWalkPath, bool aOptimize = true ); - virtual LOGGER* Logger() override - { - return &m_logger; - } + const RESULT Route( const LINE& aInitialPath ); private: void start( const LINE& aInitialPath ); @@ -142,10 +154,10 @@ private: bool m_cursorApproachMode; bool m_forceWinding; bool m_forceCw; + bool m_forceUniqueWindingDirection; VECTOR2I m_cursorPos; NODE::OPT_OBSTACLE m_currentObstacle[2]; bool m_recursiveCollision[2]; - LOGGER m_logger; std::set m_restrictedSet; };