From 313ebb9dffcd02edb1a93dc139391ea5d55e87c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Sun, 3 Feb 2019 11:21:48 +0100 Subject: [PATCH] router: correct walkaround corner case when both ends of the line lie on the hull edge Fixes: lp:1810935 * https://bugs.launchpad.net/kicad/+bug/1810935 --- common/geometry/shape_line_chain.cpp | 19 ++++++++++++------- include/geometry/shape_line_chain.h | 9 +++++++++ pcbnew/router/pns_line.cpp | 25 +++++++++++++++++++++++++ pcbnew/router/pns_line_placer.cpp | 2 ++ pcbnew/router/router_tool.cpp | 2 ++ 5 files changed, 50 insertions(+), 7 deletions(-) diff --git a/common/geometry/shape_line_chain.cpp b/common/geometry/shape_line_chain.cpp index 84dbf55920..7e690ecc0d 100644 --- a/common/geometry/shape_line_chain.cpp +++ b/common/geometry/shape_line_chain.cpp @@ -377,30 +377,35 @@ bool SHAPE_LINE_CHAIN::PointInside( const VECTOR2I& aP ) const inside = !inside; } } - return inside; + return inside && !PointOnEdge( aP ); } bool SHAPE_LINE_CHAIN::PointOnEdge( const VECTOR2I& aP ) const { - if( !PointCount() ) - return false; + return EdgeContainingPoint( aP ) >= 0; +} + +int SHAPE_LINE_CHAIN::EdgeContainingPoint( const VECTOR2I& aP ) const +{ + if( !PointCount() ) + return -1; else if( PointCount() == 1 ) - return m_points[0] == aP; + return m_points[0] == aP ? 0 : -1; for( int i = 0; i < SegmentCount(); i++ ) { const SEG s = CSegment( i ); if( s.A == aP || s.B == aP ) - return true; + return i; if( s.Distance( aP ) <= 1 ) - return true; + return i; } - return false; + return -1; } diff --git a/include/geometry/shape_line_chain.h b/include/geometry/shape_line_chain.h index 795d0012e0..16c78d8ac6 100644 --- a/include/geometry/shape_line_chain.h +++ b/include/geometry/shape_line_chain.h @@ -564,6 +564,15 @@ public: */ bool PointOnEdge( const VECTOR2I& aP ) const; + /** + * Function EdgeContainingPoint() + * + * Checks if point aP lies on an edge or vertex of the line chain. + * @param aP point to check + * @return index of the first edge containing the point, otherwise negative + */ + int EdgeContainingPoint( const VECTOR2I& aP ) const; + /** * Function CheckClearance() * diff --git a/pcbnew/router/pns_line.cpp b/pcbnew/router/pns_line.cpp index 098988067c..5f2a04e8d1 100644 --- a/pcbnew/router/pns_line.cpp +++ b/pcbnew/router/pns_line.cpp @@ -163,13 +163,21 @@ bool LINE::Walkaround( SHAPE_LINE_CHAIN aObstacle, SHAPE_LINE_CHAIN& aPre, if( line.SegmentCount() < 1 ) return false; + const auto pFirst = line.CPoint(0); + const auto pLast = line.CPoint(-1); + if( aObstacle.PointInside( line.CPoint( 0 ) ) || aObstacle.PointInside( line.CPoint( -1 ) ) ) + { return false; + } SHAPE_LINE_CHAIN::INTERSECTIONS ips; line.Intersect( aObstacle, ips ); + auto eFirst = aObstacle.EdgeContainingPoint( pFirst ); + auto eLast = aObstacle.EdgeContainingPoint( pLast ); + aWalk.Clear(); aPost.Clear(); @@ -177,6 +185,23 @@ bool LINE::Walkaround( SHAPE_LINE_CHAIN aObstacle, SHAPE_LINE_CHAIN& aPre, int farthest_dist = 0; SHAPE_LINE_CHAIN::INTERSECTION nearest, farthest; + SHAPE_LINE_CHAIN::INTERSECTION is; + + if( eFirst >= 0 ) + { + is.our = line.CSegment(0); + is.their = aObstacle.CSegment( eFirst ); + is.p = pFirst; + ips.push_back(is); + } + + if ( eLast >= 0 ) + { + is.our = line.CSegment(-1); + is.their = aObstacle.CSegment( eLast ); + is.p = pLast; + ips.push_back(is); + } for( int i = 0; i < (int) ips.size(); i++ ) { diff --git a/pcbnew/router/pns_line_placer.cpp b/pcbnew/router/pns_line_placer.cpp index 1569ce1394..5fca97ad2a 100644 --- a/pcbnew/router/pns_line_placer.cpp +++ b/pcbnew/router/pns_line_placer.cpp @@ -367,6 +367,7 @@ bool LINE_PLACER::rhWalkOnly( const VECTOR2I& aP, LINE& aNewHead ) WALKAROUND walkaround( m_currentNode, Router() ); walkaround.SetSolidsOnly( false ); + walkaround.SetDebugDecorator( Dbg() ); walkaround.SetIterationLimit( Settings().WalkaroundIterationLimit() ); WALKAROUND::WALKAROUND_STATUS wf = walkaround.Route( initTrack, walkFull, false ); @@ -565,6 +566,7 @@ bool LINE_PLACER::rhShoveOnly( const VECTOR2I& aP, LINE& aNewHead ) walkaround.SetSolidsOnly( true ); walkaround.SetIterationLimit( 10 ); + walkaround.SetDebugDecorator( Dbg() ); WALKAROUND::WALKAROUND_STATUS stat_solids = walkaround.Route( initTrack, walkSolids ); optimizer.SetEffortLevel( OPTIMIZER::MERGE_SEGMENTS ); diff --git a/pcbnew/router/router_tool.cpp b/pcbnew/router/router_tool.cpp index a37ff4b39c..4b6359b8ee 100644 --- a/pcbnew/router/router_tool.cpp +++ b/pcbnew/router/router_tool.cpp @@ -801,6 +801,8 @@ void ROUTER_TOOL::performRouting() // Don't crash if we missed an operation that cancelled routing. wxCHECK2( m_router->RoutingInProgress(), break ); + handleCommonEvents( *evt ); + if( evt->IsMotion() ) { m_router->SetOrthoMode( evt->Modifier( MD_CTRL ) );