From 2a0accd184efc8496d124b0dd5d372c4448f341f Mon Sep 17 00:00:00 2001 From: Tomasz Wlostowski Date: Sun, 13 Mar 2022 00:45:17 +0100 Subject: [PATCH] router: shove algorithm now considers cases where a small via sits 'inside' a fanout of wide (width > via diameter) segments. The shove algorithm can't move the loose track ends. It always needs a via. In case of wide segments stitched with a small via, the collision search finds only colliding segments and does not consider the via. This leads to frequent shove falilures or 'choppy' behaviour when the head line only slightly overlaps with an end of a thick trace. This patch attempts at improving this behaviour by considering the 'tiny via in wide segment' case explicitly. --- pcbnew/router/pns_node.h | 11 ++-- pcbnew/router/pns_shove.cpp | 120 +++++++++++++++++++++++++++++++----- pcbnew/router/pns_shove.h | 6 +- 3 files changed, 115 insertions(+), 22 deletions(-) diff --git a/pcbnew/router/pns_node.h b/pcbnew/router/pns_node.h index d272dc66b1..d88a26cf9f 100644 --- a/pcbnew/router/pns_node.h +++ b/pcbnew/router/pns_node.h @@ -103,12 +103,13 @@ public: */ struct OBSTACLE { - const ITEM* m_head; ///< Item we search collisions with + const ITEM* m_head; ///< Item we search collisions with - ITEM* m_item; ///< Item found to be colliding with m_head - SHAPE_LINE_CHAIN m_hull; ///< Hull of the colliding m_item - VECTOR2I m_ipFirst; ///< First intersection between m_head and m_hull - int m_distFirst; ///< ... and the distance thereof + ITEM* m_item; ///< Item found to be colliding with m_head + SHAPE_LINE_CHAIN m_hull; ///< Hull of the colliding m_item + VECTOR2I m_ipFirst; ///< First intersection between m_head and m_hull + int m_distFirst; ///< ... and the distance thereof + int m_maxFanoutWidth; ///< worst case (largest) width of the tracks connected to the item }; class OBSTACLE_VISITOR diff --git a/pcbnew/router/pns_shove.cpp b/pcbnew/router/pns_shove.cpp index 3558ec9681..0777aa8b19 100644 --- a/pcbnew/router/pns_shove.cpp +++ b/pcbnew/router/pns_shove.cpp @@ -416,7 +416,7 @@ SHOVE::SHOVE_STATUS SHOVE::ShoveObstacleLine( const LINE& aCurLine, const LINE& SHOVE_STATUS rv; bool viaOnEnd = aCurLine.EndsWithVia(); - if( viaOnEnd && ( !aCurLine.LayersOverlap( &aObstacleLine ) || aCurLine.SegmentCount() == 0 ) ) + if( viaOnEnd && ( !aCurLine.Via().LayersOverlap( &aObstacleLine ) || aCurLine.SegmentCount() == 0 ) ) { // Shove aObstacleLine to the hull of aCurLine's via. @@ -642,7 +642,7 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingLine( LINE& aCurrent, LINE& aObstacle ) /* * TODO describe.... */ -SHOVE::SHOVE_STATUS SHOVE::onCollidingSolid( LINE& aCurrent, ITEM* aObstacle ) +SHOVE::SHOVE_STATUS SHOVE::onCollidingSolid( LINE& aCurrent, ITEM* aObstacle, OBSTACLE& aObstacleInfo ) { WALKAROUND walkaround( m_currentNode, Router() ); LINE walkaroundLine( aCurrent ); @@ -666,7 +666,7 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingSolid( LINE& aCurrent, ITEM* aObstacle ) } if( via && via->Collide( aObstacle, m_currentNode ) ) - return onCollidingVia( aObstacle, via ); + return onCollidingVia( aObstacle, via, aObstacleInfo ); } TOPOLOGY topo( m_currentNode ); @@ -967,7 +967,7 @@ SHOVE::SHOVE_STATUS SHOVE::pushOrShoveVia( VIA* aVia, const VECTOR2I& aForce, in * Calculate the minimum translation vector required to resolve a collision with a via and * shove the via by that distance. */ -SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia ) +SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia, OBSTACLE& aObstacleInfo ) { int clearance = getClearance( aCurrent, aObstacleVia ); VECTOR2I mtv; @@ -982,12 +982,18 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia ) if( aCurrent->OfKind( ITEM::LINE_T ) ) { VIA vtmp ( *aObstacleVia ); + + if( aObstacleInfo.m_maxFanoutWidth > 0 && aObstacleInfo.m_maxFanoutWidth > aObstacleVia->Diameter() ) + { + vtmp.SetDiameter( aObstacleInfo.m_maxFanoutWidth ); + } + LINE* currentLine = (LINE*) aCurrent; PNS_DBG( Dbg(), AddItem, currentLine, LIGHTRED, 10000, wxT( "current-line" ) ); PNS_DBG( Dbg(), AddItem, &vtmp, LIGHTRED, 100000, wxT( "orig-via" ) ); - lineCollision = aObstacleVia->Shape()->Collide( currentLine->Shape(), + lineCollision = vtmp.Shape()->Collide( currentLine->Shape(), clearance + currentLine->Width() / 2, &mtvLine ); @@ -995,9 +1001,9 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia ) if( currentLine->EndsWithVia() ) { const VIA& currentVia = currentLine->Via(); - int viaClearance = getClearance( ¤tVia, aObstacleVia ); + int viaClearance = getClearance( ¤tVia, &vtmp ); - viaCollision = aObstacleVia->PushoutForce( m_currentNode, ¤tVia, mtvVia ); + viaCollision = currentVia.Shape()->Collide( vtmp.Shape(), viaClearance, &mtvVia ); } } else if( aCurrent->OfKind( ITEM::SOLID_T ) ) @@ -1014,7 +1020,7 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia ) else mtv = VECTOR2I(0, 0); - SHOVE::SHOVE_STATUS st = pushOrShoveVia( aObstacleVia, -mtv, rank ); + SHOVE::SHOVE_STATUS st = pushOrShoveVia( aObstacleVia, -mtv, aCurrent->Rank() ); PNS_DBGN( Dbg(), EndGroup ); @@ -1200,6 +1206,83 @@ void SHOVE::popLineStack( ) } +bool SHOVE::fixupViaCollisions( const LINE* aCurrent, OBSTACLE& obs ) +{ + // if the current obstacle is a via, consider also the lines connected to it + // if their widths are larger or equal than the via diameter, the shove algorithm + // will very likely fail in the subsequent iterations (as our base assumption is track + // ends can never move on their own, only dragged by force-propagated vias + + // our colliding item is a via: just find the max width of the traces connected to it + if( obs.m_item->OfKind( ITEM::VIA_T ) ) + { + VIA* v = static_cast( obs.m_item ); + int maxw = 0; + JOINT* jv = m_currentNode->FindJoint( v->Pos(), v ); + + for( auto link : jv->Links() ) + { + if( link.item->OfKind( ITEM::SEGMENT_T ) ) // consider segments ... + { + auto seg = static_cast( link.item ); + maxw = std::max( seg->Width(), maxw ); + } + else if( link.item->OfKind( ITEM::ARC_T ) ) // ... or arcs + { + auto arc = static_cast( link.item ); + maxw = std::max( arc->Width(), maxw ); + } + } + + obs.m_maxFanoutWidth = 0; + + if( maxw > 0 && maxw >= v->Diameter() ) + { + obs.m_maxFanoutWidth = maxw + 1; + PNS_DBG( Dbg(), Message, + wxString::Format( "Fixup via: new-w %d via-w %d", maxw, v->Diameter() ) ); + + return true; + } + return false; + } + + + // our colliding item is a segment. check if it has a via on either of the ends. + if( !obs.m_item->OfKind( ITEM::SEGMENT_T ) ) + return false; + + auto s = static_cast( obs.m_item ); + + JOINT* ja = m_currentNode->FindJoint( s->Seg().A, s ); + JOINT* jb = m_currentNode->FindJoint( s->Seg().B, s ); + + VIA* vias[] = { ja->Via(), jb->Via() }; + + for( int i = 0; i < 2; i++ ) + { + VIA* v = vias[i]; + + // via diameter is larger than the segment width - cool, the force propagation algo + // will be able to deal with it, no need to intervene + if( !v || v->Diameter() > s->Width() ) + continue; + + VIA vtest( *v ); + vtest.SetDiameter( s->Width() ); + + // enlarge the via to the width of the segment + if( vtest.Collide( aCurrent, m_currentNode ) ) + { + // if colliding, drop the segment in the shove iteration loop and force-propagate the via instead + obs.m_item = v; + obs.m_maxFanoutWidth = s->Width() + 1; + return true; + } + } + return false; +} + /* * Resolve the next collision. */ @@ -1236,6 +1319,11 @@ SHOVE::SHOVE_STATUS SHOVE::shoveIteration( int aIter ) return SH_OK; } + bool viaFixup = fixupViaCollisions( ¤tLine, nearest.get() ); + + PNS_DBG( Dbg(), Message, wxString::Format( "iter %d: VF %d", aIter, viaFixup?1:0 ) ); + + ITEM* ni = nearest->m_item; unwindLineStack( ni ); @@ -1276,7 +1364,10 @@ SHOVE::SHOVE_STATUS SHOVE::shoveIteration( int aIter ) PNS_DBGN( Dbg(), EndGroup ); if( !pushLineStack( revLine ) ) + { return SH_INCOMPLETE; + } + break; } @@ -1314,7 +1405,8 @@ SHOVE::SHOVE_STATUS SHOVE::shoveIteration( int aIter ) st = onCollidingSegment( currentLine, (SEGMENT*) ni ); if( st == SH_TRY_WALK ) - st = onCollidingSolid( currentLine, ni ); + st = onCollidingSolid( currentLine, ni, nearest.get() ); + PNS_DBGN( Dbg(), EndGroup ); break; @@ -1326,18 +1418,17 @@ SHOVE::SHOVE_STATUS SHOVE::shoveIteration( int aIter ) st = onCollidingArc( currentLine, static_cast( ni ) ); if( st == SH_TRY_WALK ) - st = onCollidingSolid( currentLine, ni ); + st = onCollidingSolid( currentLine, ni, nearest.get() ); PNS_DBGN( Dbg(), EndGroup ); break; case ITEM::VIA_T: - PNS_DBG( Dbg(), BeginGroup, wxString::Format( "iter %d: collide-via (fixup: %d)", aIter, 0 ), 0 ); - st = onCollidingVia( ¤tLine, (VIA*) ni ); + PNS_DBG( Dbg(), BeginGroup, wxString::Format( "iter %d: collide-via (fixup: %d)", aIter, 0 ), 0 ); st = onCollidingVia( ¤tLine, (VIA*) ni, nearest.get() ); if( st == SH_TRY_WALK ) - st = onCollidingSolid( currentLine, ni ); + st = onCollidingSolid( currentLine, ni, nearest.get() ); PNS_DBGN( Dbg(), EndGroup ); @@ -1345,7 +1436,8 @@ SHOVE::SHOVE_STATUS SHOVE::shoveIteration( int aIter ) case ITEM::SOLID_T: PNS_DBG( Dbg(), BeginGroup, wxString::Format( "iter %d: walk-solid ", aIter ), 0); - st = onCollidingSolid( currentLine, (SOLID*) ni ); + st = onCollidingSolid( currentLine, (SOLID*) ni, nearest.get() ); + PNS_DBGN( Dbg(), EndGroup ); break; diff --git a/pcbnew/router/pns_shove.h b/pcbnew/router/pns_shove.h index 26fae23742..3d22453d8d 100644 --- a/pcbnew/router/pns_shove.h +++ b/pcbnew/router/pns_shove.h @@ -132,8 +132,8 @@ private: SHOVE_STATUS onCollidingArc( LINE& aCurrent, ARC* aObstacleArc ); SHOVE_STATUS onCollidingLine( LINE& aCurrent, LINE& aObstacle ); SHOVE_STATUS onCollidingSegment( LINE& aCurrent, SEGMENT* aObstacleSeg ); - SHOVE_STATUS onCollidingSolid( LINE& aCurrent, ITEM* aObstacle ); - SHOVE_STATUS onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia ); + SHOVE_STATUS onCollidingSolid( LINE& aCurrent, ITEM* aObstacle, OBSTACLE& aObstacleInfo ); + SHOVE_STATUS onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia, OBSTACLE& aObstacleInfo ); SHOVE_STATUS onReverseCollidingVia( LINE& aCurrent, VIA* aObstacleVia ); SHOVE_STATUS pushOrShoveVia( VIA* aVia, const VECTOR2I& aForce, int aCurrentRank ); @@ -162,7 +162,7 @@ private: int getClearance( const ITEM* aA, const ITEM* aB ) const; int getHoleClearance( const ITEM* aA, const ITEM* aB ) const; - + bool fixupViaCollisions( const LINE* aCurrent, OBSTACLE& obs ); void sanityCheck( LINE* aOld, LINE* aNew ); std::vector m_nodeStack;