Improve walkaround results when last point is inside the hull

Fixes https://gitlab.com/kicad/code/kicad/-/issues/8563
This commit is contained in:
Jon Evans 2021-06-06 12:55:20 -04:00
parent e29b61ccc1
commit 17da050e69
1 changed files with 45 additions and 18 deletions

View File

@ -355,6 +355,13 @@ bool LINE::Walkaround( const SHAPE_LINE_CHAIN& aObstacle, SHAPE_LINE_CHAIN& aPat
vc->neighbours.push_back(vnext);
}
// In the case that the initial path ends *inside* the current obstacle (i.e. the mouse cursor
// is somewhere inside the hull for the current obstacle) we want to end the walkaround at the
// point closest to the cursor
bool inLast = aObstacle.PointInside( CPoint( -1 ) ) && !aObstacle.PointOnEdge( CPoint( -1 ) );
bool appendV = true;
int lastDst = INT_MAX;
int i = 0;
#ifdef TOM_EXTRA_DEBUG
for(auto &v: vts)
@ -373,7 +380,7 @@ bool LINE::Walkaround( const SHAPE_LINE_CHAIN& aObstacle, SHAPE_LINE_CHAIN& aPat
int iterLimit = 1000;
// keep scanning the graph until we reach the end point of the path
while ( v->indexp != (pnew.PointCount() - 1) )
while( v->indexp != ( pnew.PointCount() - 1 ) )
{
iterLimit--;
@ -384,7 +391,7 @@ bool LINE::Walkaround( const SHAPE_LINE_CHAIN& aObstacle, SHAPE_LINE_CHAIN& aPat
return false;
}
if(v->visited)
if( v->visited )
{
// loop found? stop walking
break;
@ -396,17 +403,18 @@ bool LINE::Walkaround( const SHAPE_LINE_CHAIN& aObstacle, SHAPE_LINE_CHAIN& aPat
VERTEX* v_next = nullptr;
if (v->type == OUTSIDE)
if( v->type == OUTSIDE )
{
// current vertex is outside? first look for any vertex further down the path
// that is not inside the hull
out.Append(v->pos);
out.Append( v->pos );
VERTEX* v_next_fallback = nullptr;
for( auto vn : v->neighbours )
{
if( areNeighbours( vn->indexp , v->indexp, pnew.PointCount() ) && vn->type != INSIDE )
if( areNeighbours( vn->indexp , v->indexp, pnew.PointCount() ) &&
vn->type != INSIDE )
{
if( !vn->visited)
if( !vn->visited )
{
v_next = vn;
break;
@ -416,11 +424,11 @@ bool LINE::Walkaround( const SHAPE_LINE_CHAIN& aObstacle, SHAPE_LINE_CHAIN& aPat
}
}
if(!v_next)
if( !v_next )
v_next = v_next_fallback;
// such a vertex must always be present, if not, bummer.
if (!v_next)
if( !v_next )
{
#ifdef TOM_EXTRA_DEBUG
printf("FAIL VN fallback %p\n", v_next_fallback );
@ -429,7 +437,7 @@ bool LINE::Walkaround( const SHAPE_LINE_CHAIN& aObstacle, SHAPE_LINE_CHAIN& aPat
}
}
else if (v->type == ON_EDGE)
else if( v->type == ON_EDGE )
{
// look first for the first vertex outside the hull
for( VERTEX* vn : v->neighbours )
@ -448,12 +456,12 @@ bool LINE::Walkaround( const SHAPE_LINE_CHAIN& aObstacle, SHAPE_LINE_CHAIN& aPat
// no outside vertices found? continue traversing the hull
if( !v_next )
{
for( VERTEX* vn: v->neighbours)
for( VERTEX* vn : v->neighbours )
{
#ifdef TOM_EXTRA_DEBUG
printf("- scan ip %d ih %d type %d\n", vn->indexp, vn->indexh, vn->type );
#endif
if( vn->type == ON_EDGE &&
if( vn->type == ON_EDGE && !vn->isHull &&
areNeighbours( vn->indexp, v->indexp, pnew.PointCount() ) &&
( vn->indexh == ( ( v->indexh + 1 ) % hnew.PointCount() ) ) )
{
@ -467,18 +475,37 @@ bool LINE::Walkaround( const SHAPE_LINE_CHAIN& aObstacle, SHAPE_LINE_CHAIN& aPat
// we should never reach this part of the code, but who really knows?
if( !v_next )
{
for( VERTEX* vn: v->neighbours)
for( VERTEX* vn : v->neighbours )
{
if ( vn->type == ON_EDGE )
if( vn->type == ON_EDGE )
{
if( vn->indexh == ( (v->indexh + 1) % hnew.PointCount() ) )
if( vn->indexh == ( ( v->indexh + 1 ) % hnew.PointCount() ) )
{
v_next = vn;
break;
}
}
}
// Did we get the next hull point but the end of the line is inside? Instead of walking
// around the hull some more (which will just end up taking us back to the start), lets
// just project the normal of the endpoint onto this next segment and call it quits.
if( inLast && v_next )
{
int d = ( v_next->pos - CPoint( -1 ) ).SquaredEuclideanNorm();
if( d < lastDst )
{
lastDst = d;
}
else
{
VECTOR2I proj = SEG( v->pos, v_next->pos ).NearestPoint( CPoint( -1 ) );
out.Append( proj );
appendV = false;
break;
}
}
}
}
@ -486,15 +513,15 @@ bool LINE::Walkaround( const SHAPE_LINE_CHAIN& aObstacle, SHAPE_LINE_CHAIN& aPat
v_prev = v;
v = v_next;
if( !v )
{
return false;
}
}
out.Append( v->pos );
if( appendV )
out.Append( v->pos );
aPath = out;
return true;