router: initial attempt at improved 'aim at mouse cursor' strategy in walkaround mode, wip...

This commit is contained in:
Tomasz Wlostowski 2020-02-19 18:22:37 +01:00
parent 43b71cd9e3
commit 37a754c4dd
3 changed files with 256 additions and 37 deletions

View File

@ -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( &current, ratLine ) )
Dbg()->AddLine( ratLine, 5, 10000 );
//if( topo.LeadingRatLine( &current, ratLine ) )
//Dbg()->AddLine( ratLine, 5, 10000 );
}
@ -1288,12 +1346,5 @@ void LINE_PLACER::GetModifiedNets( std::vector<int>& aNets ) const
aNets.push_back( m_currentNet );
}
LOGGER* LINE_PLACER::Logger()
{
if( m_shove )
return m_shove->Logger();
return NULL;
}
}

View File

@ -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<OBSTACLE>& 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( &current_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( &current_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;

View File

@ -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<ITEM*> m_restrictedSet;
};