From 5e850911c57587ae79a111cc545ce8bcff453051 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Fri, 29 Mar 2024 09:49:43 -0700 Subject: [PATCH] When dragging a via, we need to get all obstacles The clearance epsilon should not be used to limit which force elements we return in the query. Otherwise, we can drag elements into a DRC-violating space Fixes https://gitlab.com/kicad/code/kicad/-/issues/16293 --- pcbnew/router/pns_item.cpp | 3 +++ pcbnew/router/pns_node.cpp | 14 ++++++++++---- pcbnew/router/pns_node.h | 13 +++++++++++-- pcbnew/router/pns_via.cpp | 7 ++++++- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/pcbnew/router/pns_item.cpp b/pcbnew/router/pns_item.cpp index 042fe0e497..c42f4cfe9e 100644 --- a/pcbnew/router/pns_item.cpp +++ b/pcbnew/router/pns_item.cpp @@ -192,6 +192,9 @@ bool ITEM::collideSimple( const ITEM* aHead, const NODE* aNode, } else { + if( aCtx && !aCtx->options.m_useClearanceEpsilon ) + clearanceEpsilon = 0; + clearance = aNode->GetClearance( this, aHead, aCtx ? aCtx->options.m_useClearanceEpsilon : false ); } diff --git a/pcbnew/router/pns_node.cpp b/pcbnew/router/pns_node.cpp index 3bec2d8b1c..cb71b95cd0 100644 --- a/pcbnew/router/pns_node.cpp +++ b/pcbnew/router/pns_node.cpp @@ -409,12 +409,18 @@ NODE::OPT_OBSTACLE NODE::CheckColliding( const ITEM_SET& aSet, int aKindMask ) NODE::OPT_OBSTACLE NODE::CheckColliding( const ITEM* aItemA, int aKindMask ) { - OBSTACLES obs; COLLISION_SEARCH_OPTIONS opts; opts.m_kindMask = aKindMask; opts.m_limitCount = 1; + return CheckColliding( aItemA, opts ); +} + +NODE::OPT_OBSTACLE NODE::CheckColliding( const ITEM* aItemA, const COLLISION_SEARCH_OPTIONS& aOpts ) +{ + OBSTACLES obs; + if( aItemA->Kind() == ITEM::LINE_T ) { int n = 0; @@ -428,7 +434,7 @@ NODE::OPT_OBSTACLE NODE::CheckColliding( const ITEM* aItemA, int aKindMask ) // Disabling the cache will lead to slowness. const SEGMENT s( *line, l.CSegment( i ) ); - n += QueryColliding( &s, obs, opts ); + n += QueryColliding( &s, obs, aOpts ); if( n ) return OPT_OBSTACLE( *obs.begin() ); @@ -436,13 +442,13 @@ NODE::OPT_OBSTACLE NODE::CheckColliding( const ITEM* aItemA, int aKindMask ) if( line->EndsWithVia() ) { - n += QueryColliding( &line->Via(), obs, opts ); + n += QueryColliding( &line->Via(), obs, aOpts ); if( n ) return OPT_OBSTACLE( *obs.begin() ); } } - else if( QueryColliding( aItemA, obs, opts ) > 0 ) + else if( QueryColliding( aItemA, obs, aOpts ) > 0 ) { return OPT_OBSTACLE( *obs.begin() ); } diff --git a/pcbnew/router/pns_node.h b/pcbnew/router/pns_node.h index c2b1fc4433..da6eaceaad 100644 --- a/pcbnew/router/pns_node.h +++ b/pcbnew/router/pns_node.h @@ -279,8 +279,7 @@ public: * starting point. * * @param aLine the item to find collisions with - * @param aKindMask mask of obstacle types to take into account - * @param aRestrictedSet is an optional set of items that should be considered as obstacles + * @param aOpts options for the search * @return the obstacle, if found, otherwise empty. */ OPT_OBSTACLE NearestObstacle( const LINE* aLine, @@ -307,6 +306,16 @@ public: */ OPT_OBSTACLE CheckColliding( const ITEM_SET& aSet, int aKindMask = ITEM::ANY_T ); + /** + * Check if the item collides with anything else in the world, and if found, returns the + * obstacle. + * + * @param aItem the item to find collisions with + * @param aOpts options for the search + * @return the obstacle, if found, otherwise empty. + */ + OPT_OBSTACLE CheckColliding( const ITEM* aItem, const COLLISION_SEARCH_OPTIONS& aOpts ); + /** * Find all items that contain the point \a aPoint. * diff --git a/pcbnew/router/pns_via.cpp b/pcbnew/router/pns_via.cpp index dfc85a4842..169d8ebb79 100644 --- a/pcbnew/router/pns_via.cpp +++ b/pcbnew/router/pns_via.cpp @@ -61,7 +61,12 @@ bool VIA::PushoutForce( NODE* aNode, const VECTOR2I& aDirection, VECTOR2I& aForc while( iter < aMaxIterations ) { - NODE::OPT_OBSTACLE obs = aNode->CheckColliding( &mv, aCollisionMask ); + COLLISION_SEARCH_OPTIONS opt; + opt.m_limitCount = 1; + opt.m_kindMask = aCollisionMask; + opt.m_useClearanceEpsilon = false; + + NODE::OPT_OBSTACLE obs = aNode->CheckColliding( &mv, opt ); if( !obs ) break;