router: improve the feel of the walkaround algorithm
Makes walkaround more 'huggy' - the trace being routed sticks to obstacles instead of jumping around in uncontrollable way.
This commit is contained in:
parent
8148b5d81f
commit
e66bbfd1ec
|
@ -426,14 +426,106 @@ VECTOR2I closestProjectedPoint( const SHAPE_LINE_CHAIN& line, const VECTOR2I& p
|
|||
}
|
||||
|
||||
|
||||
static bool cursorDistMinimum( const SHAPE_LINE_CHAIN& aL, const VECTOR2I& aCursor, double lengthThreshold, int& theDist, VECTOR2I& aNearest )
|
||||
{
|
||||
std::vector<int> dists;
|
||||
std::vector<VECTOR2I> pts;
|
||||
|
||||
if( aL.PointCount() == 0 )
|
||||
return false;
|
||||
|
||||
VECTOR2I lastP = aL.CPoint(-1);
|
||||
int accumulatedDist = 0;
|
||||
|
||||
dists.reserve( 2 * aL.PointCount() );
|
||||
|
||||
for( int i = 0; i < aL.SegmentCount(); i++ )
|
||||
{
|
||||
const SEG& s = aL.CSegment( i );
|
||||
|
||||
dists.push_back( ( aCursor - s.A ).EuclideanNorm() );
|
||||
pts.push_back( s.A );
|
||||
auto pn = s.NearestPoint( aCursor );
|
||||
|
||||
if( pn != s.A && pn != s.B )
|
||||
{
|
||||
dists.push_back( ( pn - aCursor ).EuclideanNorm() );
|
||||
pts.push_back( pn );
|
||||
}
|
||||
|
||||
accumulatedDist += s.Length();
|
||||
|
||||
if ( accumulatedDist > lengthThreshold )
|
||||
{
|
||||
lastP = s.B;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dists.push_back( ( aCursor - lastP ).EuclideanNorm() );
|
||||
pts.push_back( lastP );
|
||||
|
||||
int minDistLoc = std::numeric_limits<int>::max();
|
||||
int minPLoc = -1;
|
||||
int minDistGlob = std::numeric_limits<int>::max();
|
||||
int minPGlob = -1;
|
||||
|
||||
for( int i = 0; i < dists.size() - 3; i++ )
|
||||
{
|
||||
if( dists[i + 2] > dists[i + 1] && dists[i] > dists[i + 1] )
|
||||
{
|
||||
int d = dists[i + 1];
|
||||
if( d < minDistLoc )
|
||||
{
|
||||
minDistLoc = d;
|
||||
minPLoc = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( dists.back() < minDistLoc && minPLoc >= 0 )
|
||||
{
|
||||
minDistLoc = dists.back();
|
||||
minPLoc = dists.size() - 1;
|
||||
}
|
||||
|
||||
for( int i = 0; i < dists.size(); i++ )
|
||||
{
|
||||
int d = dists[i];
|
||||
if( d < minDistGlob )
|
||||
{
|
||||
minDistGlob = d;
|
||||
minPGlob = i;
|
||||
}
|
||||
}
|
||||
|
||||
// fixme: I didn't make my mind yet if local or global minimum feels better. I'm leaving both
|
||||
// in the code, enabling the global one by default
|
||||
minPLoc = -1;
|
||||
|
||||
if( minPLoc < 0 )
|
||||
{
|
||||
theDist = minDistGlob;
|
||||
aNearest = pts[minPGlob];
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
theDist = minDistLoc;
|
||||
aNearest = pts[minPLoc];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LINE_PLACER::rhWalkOnly( const VECTOR2I& aP, LINE& aNewHead )
|
||||
{
|
||||
LINE initTrack( m_head );
|
||||
LINE walkFull( m_head );
|
||||
int effort = 0;
|
||||
bool rv = true, viaOk;
|
||||
bool viaOk = false;
|
||||
|
||||
viaOk = buildInitialLine( aP, initTrack );
|
||||
VECTOR2I walkP = aP;
|
||||
|
||||
WALKAROUND walkaround( m_currentNode, Router() );
|
||||
|
||||
|
@ -442,37 +534,101 @@ bool LINE_PLACER::rhWalkOnly( const VECTOR2I& aP, LINE& aNewHead )
|
|||
walkaround.SetLogger( Logger() );
|
||||
walkaround.SetIterationLimit( Settings().WalkaroundIterationLimit() );
|
||||
|
||||
WALKAROUND::RESULT wr = walkaround.Route( initTrack );
|
||||
//WALKAROUND::WALKAROUND_STATUS wf = walkaround.Route( initTrack, walkFull, false );
|
||||
int round = 0;
|
||||
|
||||
SHAPE_LINE_CHAIN l_cw = wr.lineCw.CLine();
|
||||
SHAPE_LINE_CHAIN l_ccw = wr.lineCcw.CLine();
|
||||
do {
|
||||
viaOk = buildInitialLine( walkP, initTrack, round == 0 );
|
||||
printf("round %d vok %d\n", round, viaOk?1:0);
|
||||
|
||||
double initialLength = initTrack.CLine().Length();
|
||||
double hugThresholdLength = initialLength * Settings().WalkaroundHugLengthThreshold();
|
||||
|
||||
if( wr.statusCcw == WALKAROUND::ALMOST_DONE || wr.statusCw == WALKAROUND::ALMOST_DONE )
|
||||
{
|
||||
WALKAROUND::RESULT wr = walkaround.Route( initTrack );
|
||||
|
||||
VECTOR2I p_cw = closestProjectedPoint( l_cw, aP );
|
||||
VECTOR2I p_ccw = closestProjectedPoint( l_ccw, aP );
|
||||
SHAPE_LINE_CHAIN l_cw = wr.lineCw.CLine();
|
||||
SHAPE_LINE_CHAIN l_ccw = wr.lineCcw.CLine();
|
||||
|
||||
int idx_cw = l_cw.Split( p_cw );
|
||||
int idx_ccw = l_ccw.Split( p_ccw );
|
||||
if( wr.statusCcw == WALKAROUND::DONE || wr.statusCw == WALKAROUND::DONE )
|
||||
{
|
||||
int len_cw = wr.statusCw == WALKAROUND::DONE ? l_cw.Length() : INT_MAX;
|
||||
int len_ccw = wr.statusCcw == WALKAROUND::DONE ? l_ccw.Length() : INT_MAX;
|
||||
|
||||
l_cw = l_cw.Slice( 0, idx_cw );
|
||||
l_ccw = l_ccw.Slice( 0, idx_ccw );
|
||||
Dbg()->AddLine( wr.lineCw.CLine(), 6, 10000, "wf-result-cw" );
|
||||
Dbg()->AddLine( wr.lineCcw.CLine(), 5, 20000, "wf-result-ccw" );
|
||||
|
||||
//Dbg()->AddLine( wr.lineCw.CLine(), 3, 40000 );
|
||||
|
||||
int bestLength = len_cw < len_ccw ? len_cw : len_ccw;
|
||||
|
||||
//Dbg()->AddPoint( p_cw, 4 );
|
||||
//Dbg()->AddPoint( p_ccw, 5 );
|
||||
if( bestLength > hugThresholdLength )
|
||||
{
|
||||
wr.statusCw = WALKAROUND::ALMOST_DONE;
|
||||
wr.statusCcw = WALKAROUND::ALMOST_DONE;
|
||||
}
|
||||
|
||||
Dbg()->AddLine( wr.lineCw.CLine(), 4, 1000 );
|
||||
Dbg()->AddLine( wr.lineCcw.CLine(), 5, 1000 );
|
||||
SHAPE_LINE_CHAIN& bestLine = len_cw < len_ccw ? l_cw : l_ccw;
|
||||
walkFull.SetShape( bestLine );
|
||||
}
|
||||
|
||||
}
|
||||
if( wr.statusCcw == WALKAROUND::ALMOST_DONE || wr.statusCw == WALKAROUND::ALMOST_DONE )
|
||||
{
|
||||
bool valid_cw = false, valid_ccw = false;
|
||||
VECTOR2I p_cw, p_ccw;
|
||||
int dist_ccw, dist_cw;
|
||||
|
||||
if( wr.statusCcw == WALKAROUND::ALMOST_DONE )
|
||||
{
|
||||
valid_ccw = cursorDistMinimum( l_ccw, aP, hugThresholdLength, dist_ccw, p_ccw );
|
||||
if( valid_ccw )
|
||||
{
|
||||
int idx_ccw = l_ccw.Split( p_ccw );
|
||||
l_ccw = l_ccw.Slice( 0, idx_ccw );
|
||||
Dbg()->AddPoint( p_ccw, 5, 500000, "hug-target-ccw" );
|
||||
// Dbg()->AddLine( l_ccw, 5, 200000, "wh-result-ccw" );
|
||||
|
||||
walkFull.SetShape( l_ccw.Length() < l_cw.Length() ? l_ccw : l_cw );
|
||||
|
||||
Dbg()->AddLine( walkFull.CLine(), 2, 100000, "walk-full" );
|
||||
}
|
||||
}
|
||||
if( wr.statusCw == WALKAROUND::ALMOST_DONE )
|
||||
{
|
||||
valid_cw = cursorDistMinimum( l_cw, aP, hugThresholdLength, dist_cw, p_cw );
|
||||
if( valid_cw )
|
||||
{
|
||||
int idx_cw = l_cw.Split( p_cw );
|
||||
l_cw = l_cw.Slice( 0, idx_cw );
|
||||
Dbg()->AddPoint( p_cw, 4, 500000, "hug-target-cw" );
|
||||
// Dbg()->AddLine( l_cw, 6, 200000, "wh-result-cw" );
|
||||
}
|
||||
}
|
||||
|
||||
// return false;
|
||||
|
||||
if( dist_cw < dist_ccw && valid_cw )
|
||||
{
|
||||
walkFull.SetShape( l_cw );
|
||||
walkP = p_cw;
|
||||
}
|
||||
else if ( valid_ccw )
|
||||
{
|
||||
walkFull.SetShape( l_ccw );
|
||||
walkP = p_ccw;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( wr.statusCcw == WALKAROUND::STUCK || wr.statusCw == WALKAROUND::STUCK )
|
||||
{
|
||||
printf("FINISH3\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
round++;
|
||||
} while( round < 2 && m_placingVia );
|
||||
|
||||
Dbg()->AddLine( walkFull.CLine(), 2, 200000, "walk-full" );
|
||||
|
||||
|
||||
switch( Settings().OptimizerEffort() )
|
||||
{
|
||||
|
@ -489,28 +645,23 @@ bool LINE_PLACER::rhWalkOnly( const VECTOR2I& aP, LINE& aNewHead )
|
|||
if( Settings().SmartPads() && !m_mouseTrailTracer.IsManuallyForced() )
|
||||
effort |= OPTIMIZER::SMART_PADS;
|
||||
|
||||
if( wr.statusCw == WALKAROUND::STUCK || wr.statusCcw == WALKAROUND::STUCK )
|
||||
{
|
||||
walkFull = walkFull.ClipToNearestObstacle( m_currentNode );
|
||||
rv = true;
|
||||
}
|
||||
else if( m_placingVia && viaOk )
|
||||
if( m_placingVia && viaOk )
|
||||
{
|
||||
walkFull.AppendVia( makeVia( walkFull.CPoint( -1 ) ) );
|
||||
}
|
||||
|
||||
OPTIMIZER::Optimize( &walkFull, effort, m_currentNode );
|
||||
|
||||
|
||||
if( m_currentNode->CheckColliding( &walkFull ) )
|
||||
{
|
||||
aNewHead = m_head;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_head = walkFull;
|
||||
aNewHead = walkFull;
|
||||
Dbg()->AddLine( walkFull.CLine(), 2, 200000, "walk-full" );
|
||||
|
||||
return rv;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -751,11 +902,14 @@ void LINE_PLACER::routeStep( const VECTOR2I& aP )
|
|||
if( !new_head.Is45Degree() )
|
||||
fail = true;
|
||||
|
||||
if( !Settings().FollowMouse() )
|
||||
if( fail )
|
||||
return;
|
||||
|
||||
m_head = new_head;
|
||||
|
||||
if( !Settings().FollowMouse() )
|
||||
return;
|
||||
|
||||
if( handleSelfIntersections() )
|
||||
{
|
||||
n_iter++;
|
||||
|
@ -1365,7 +1519,7 @@ void LINE_PLACER::SetOrthoMode( bool aOrthoMode )
|
|||
}
|
||||
|
||||
|
||||
bool LINE_PLACER::buildInitialLine( const VECTOR2I& aP, LINE& aHead )
|
||||
bool LINE_PLACER::buildInitialLine( const VECTOR2I& aP, LINE& aHead, bool aForceNoVia )
|
||||
{
|
||||
SHAPE_LINE_CHAIN l;
|
||||
DIRECTION_45 guessedDir = m_mouseTrailTracer.GetPosture( aP );
|
||||
|
@ -1406,7 +1560,7 @@ bool LINE_PLACER::buildInitialLine( const VECTOR2I& aP, LINE& aHead )
|
|||
aHead.SetLayer( m_currentLayer );
|
||||
aHead.SetShape( l );
|
||||
|
||||
if( !m_placingVia )
|
||||
if( !m_placingVia || aForceNoVia )
|
||||
return true;
|
||||
|
||||
VIA v( makeVia( aP ) );
|
||||
|
|
|
@ -319,7 +319,7 @@ private:
|
|||
|
||||
const VIA makeVia( const VECTOR2I& aP );
|
||||
|
||||
bool buildInitialLine( const VECTOR2I& aP, LINE& aHead );
|
||||
bool buildInitialLine( const VECTOR2I& aP, LINE& aHead, bool aForceNoVia = false );
|
||||
|
||||
|
||||
DIRECTION_45 m_direction; ///< current routing direction
|
||||
|
|
|
@ -52,6 +52,7 @@ ROUTING_SETTINGS::ROUTING_SETTINGS( JSON_SETTINGS* aParent, const std::string& a
|
|||
m_snapToPads = false;
|
||||
m_optimizeEntireDraggedTrack = false;
|
||||
m_cornerMode = CORNER_MODE::MITERED_45;
|
||||
m_walkaroundHugLengthThreshold = 1.5;
|
||||
m_autoPosture = true;
|
||||
m_fixAllSegments = true;
|
||||
|
||||
|
@ -100,6 +101,8 @@ ROUTING_SETTINGS::ROUTING_SETTINGS( JSON_SETTINGS* aParent, const std::string& a
|
|||
CORNER_MODE::MITERED_45, CORNER_MODE::ROUNDED_90,
|
||||
CORNER_MODE::MITERED_45 ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<double>( "walkaround_hug_length_threshold", &m_walkaroundHugLengthThreshold, 1.5 ) );
|
||||
|
||||
LoadFromFile();
|
||||
}
|
||||
|
||||
|
|
|
@ -164,6 +164,8 @@ public:
|
|||
bool GetFixAllSegments() const { return m_fixAllSegments; }
|
||||
void SetFixAllSegments( bool aEnable ) { m_fixAllSegments = aEnable; }
|
||||
|
||||
double WalkaroundHugLengthThreshold() const { return m_walkaroundHugLengthThreshold; }
|
||||
|
||||
private:
|
||||
bool m_shoveVias;
|
||||
bool m_startDiagonal;
|
||||
|
@ -189,6 +191,8 @@ private:
|
|||
|
||||
int m_walkaroundIterationLimit;
|
||||
int m_shoveIterationLimit;
|
||||
double m_walkaroundHugLengthThreshold;
|
||||
|
||||
TIME_LIMIT m_shoveTimeLimit;
|
||||
TIME_LIMIT m_walkaroundTimeLimit;
|
||||
};
|
||||
|
|
|
@ -52,8 +52,7 @@ NODE::OPT_OBSTACLE WALKAROUND::nearestObstacle( const LINE& aPath )
|
|||
}
|
||||
|
||||
|
||||
WALKAROUND::WALKAROUND_STATUS WALKAROUND::singleStep( LINE& aPath,
|
||||
bool aWindingDirection )
|
||||
WALKAROUND::WALKAROUND_STATUS WALKAROUND::singleStep( LINE& aPath, bool aWindingDirection )
|
||||
{
|
||||
OPT<OBSTACLE>& current_obs =
|
||||
aWindingDirection ? m_currentObstacle[0] : m_currentObstacle[1];
|
||||
|
@ -61,47 +60,10 @@ WALKAROUND::WALKAROUND_STATUS WALKAROUND::singleStep( LINE& aPath,
|
|||
if( !current_obs )
|
||||
return DONE;
|
||||
|
||||
SHAPE_LINE_CHAIN path_walk[2];
|
||||
SHAPE_LINE_CHAIN path_walk;
|
||||
|
||||
if( aPath.PointCount() > 1 )
|
||||
{
|
||||
VECTOR2I last = aPath.CPoint( -1 );
|
||||
|
||||
if( ( current_obs->m_hull ).PointInside( last ) || ( current_obs->m_hull ).PointOnEdge( last ) )
|
||||
{
|
||||
m_recursiveBlockageCount++;
|
||||
|
||||
if( m_recursiveBlockageCount < 3 )
|
||||
aPath.Line().Append( current_obs->m_hull.NearestPoint( last ) );
|
||||
else
|
||||
{
|
||||
aPath = aPath.ClipToNearestObstacle( m_world );
|
||||
return DONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aPath.Walkaround( current_obs->m_hull, path_walk[0],
|
||||
bool s_cw = aPath.Walkaround( current_obs->m_hull, path_walk,
|
||||
aWindingDirection );
|
||||
aPath.Walkaround( current_obs->m_hull, path_walk[1],
|
||||
!aWindingDirection );
|
||||
|
||||
if( !aPath.Walkaround( current_obs->m_hull, path_walk[1], !aWindingDirection ) )
|
||||
return STUCK;
|
||||
|
||||
auto l =aPath.CLine();
|
||||
|
||||
#if 0
|
||||
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() )
|
||||
{
|
||||
|
@ -111,70 +73,21 @@ WALKAROUND::WALKAROUND_STATUS WALKAROUND::singleStep( LINE& aPath,
|
|||
Dbg()->AddLine( current_obs->m_hull, 1, 1, name);
|
||||
snprintf(name, sizeof(name), "path-%s-%d", aWindingDirection ? "cw" : "ccw", m_iteration );
|
||||
Dbg()->AddLine( aPath.CLine(), 2, 1, name );
|
||||
snprintf(name, sizeof(name), "result-%s-%d", aWindingDirection ? "cw" : "ccw", m_iteration );
|
||||
Dbg()->AddLine( path_walk, 3, 10000, name );
|
||||
Dbg()->Message( wxString::Format( "Stat cw %d", !!s_cw ) );
|
||||
Dbg()->EndGroup();
|
||||
}
|
||||
|
||||
int len_pre = path_walk[0].Length();
|
||||
int len_alt = path_walk[1].Length();
|
||||
current_obs = nearestObstacle( LINE( aPath, path_walk ) );
|
||||
|
||||
LINE walk_path( aPath, path_walk[1] );
|
||||
|
||||
bool alt_collides = static_cast<bool>( m_world->CheckColliding( &walk_path, m_itemMask ) );
|
||||
|
||||
SHAPE_LINE_CHAIN pnew;
|
||||
|
||||
/*if( !m_forceLongerPath && len_alt < len_pre && !alt_collides && !prev_recursive )
|
||||
{
|
||||
pnew = path_pre[1];
|
||||
pnew.Append( path_walk[1] );
|
||||
pnew.Append( path_post[1] );
|
||||
|
||||
if( !path_post[1].PointCount() || !path_walk[1].PointCount() )
|
||||
current_obs = nearestObstacle( LINE( aPath, path_pre[1] ) );
|
||||
else
|
||||
current_obs = nearestObstacle( LINE( aPath, path_post[1] ) );
|
||||
}
|
||||
else*/
|
||||
{
|
||||
pnew = path_walk[0];
|
||||
current_obs = nearestObstacle( LINE( aPath, path_walk[0] ) );
|
||||
}
|
||||
|
||||
pnew.Simplify();
|
||||
aPath.SetShape( pnew );
|
||||
path_walk.Simplify();
|
||||
aPath.SetShape( path_walk );
|
||||
|
||||
return IN_PROGRESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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 );
|
||||
|
@ -210,21 +123,12 @@ const WALKAROUND::RESULT WALKAROUND::Route( const LINE& aInitialPath )
|
|||
|
||||
while( m_iteration < m_iterationLimit )
|
||||
{
|
||||
if( s_cw != STUCK )
|
||||
if( s_cw != STUCK && s_cw != ALMOST_DONE )
|
||||
s_cw = singleStep( path_cw, true );
|
||||
|
||||
if( s_ccw != STUCK )
|
||||
if( s_ccw != STUCK && s_ccw != ALMOST_DONE )
|
||||
s_ccw = singleStep( path_ccw, false );
|
||||
|
||||
auto old = path_cw.CLine();
|
||||
|
||||
if( clipToLoopStart( path_cw.Line() ) )
|
||||
s_cw = ALMOST_DONE;
|
||||
|
||||
if( clipToLoopStart( path_ccw.Line() ) )
|
||||
s_ccw = ALMOST_DONE;
|
||||
|
||||
|
||||
if( s_cw != IN_PROGRESS )
|
||||
{
|
||||
result.lineCw = path_cw;
|
||||
|
@ -255,9 +159,6 @@ const WALKAROUND::RESULT WALKAROUND::Route( const LINE& aInitialPath )
|
|||
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;
|
||||
|
@ -361,40 +262,6 @@ WALKAROUND::WALKAROUND_STATUS WALKAROUND::Route( const LINE& aInitialPath,
|
|||
aWalkPath = ( len_cw < len_ccw ? path_cw : path_ccw );
|
||||
}
|
||||
|
||||
if( m_cursorApproachMode )
|
||||
{
|
||||
// int len_cw = path_cw.GetCLine().Length();
|
||||
// int len_ccw = path_ccw.GetCLine().Length();
|
||||
bool found = false;
|
||||
|
||||
SHAPE_LINE_CHAIN l = aWalkPath.CLine();
|
||||
|
||||
for( int i = 0; i < l.SegmentCount(); i++ )
|
||||
{
|
||||
const SEG s = l.Segment( i );
|
||||
|
||||
VECTOR2I nearest = s.NearestPoint( m_cursorPos );
|
||||
VECTOR2I::extended_type dist_a = ( s.A - m_cursorPos ).SquaredEuclideanNorm();
|
||||
VECTOR2I::extended_type dist_b = ( s.B - m_cursorPos ).SquaredEuclideanNorm();
|
||||
VECTOR2I::extended_type dist_n = ( nearest - m_cursorPos ).SquaredEuclideanNorm();
|
||||
|
||||
if( dist_n <= dist_a && dist_n < dist_b )
|
||||
{
|
||||
l.Remove( i + 1, -1 );
|
||||
l.Append( nearest );
|
||||
l.Simplify();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( found )
|
||||
{
|
||||
aWalkPath = aInitialPath;
|
||||
aWalkPath.SetShape( l );
|
||||
}
|
||||
}
|
||||
|
||||
aWalkPath.Line().Simplify();
|
||||
|
||||
if( aWalkPath.SegmentCount() < 1 )
|
||||
|
|
Loading…
Reference in New Issue