diff --git a/pcbnew/router/pns_node.cpp b/pcbnew/router/pns_node.cpp index 3889f30b54..508a180860 100644 --- a/pcbnew/router/pns_node.cpp +++ b/pcbnew/router/pns_node.cpp @@ -873,10 +873,10 @@ void NODE::Replace( ITEM* aOldItem, std::unique_ptr< ITEM > aNewItem ) } -void NODE::Replace( LINE& aOldLine, LINE& aNewLine ) +void NODE::Replace( LINE& aOldLine, LINE& aNewLine, bool aAllowRedundantSegments ) { Remove( aOldLine ); - Add( aNewLine ); + Add( aNewLine, aAllowRedundantSegments ); } diff --git a/pcbnew/router/pns_node.h b/pcbnew/router/pns_node.h index 20e5a7ccc0..377a9520b9 100644 --- a/pcbnew/router/pns_node.h +++ b/pcbnew/router/pns_node.h @@ -389,7 +389,7 @@ public: * @param aNewItem item add instead */ void Replace( ITEM* aOldItem, std::unique_ptr< ITEM > aNewItem ); - void Replace( LINE& aOldLine, LINE& aNewLine ); + void Replace( LINE& aOldLine, LINE& aNewLine, bool aAllowRedundantSegments = false ); /** * Create a lightweight copy (called branch) of self that tracks the changes (added/removed diff --git a/pcbnew/router/pns_shove.cpp b/pcbnew/router/pns_shove.cpp index 721543349e..7b05d22677 100644 --- a/pcbnew/router/pns_shove.cpp +++ b/pcbnew/router/pns_shove.cpp @@ -77,7 +77,7 @@ void SHOVE::replaceItems( ITEM* aOld, std::unique_ptr< ITEM > aNew ) } -SHOVE::ROOT_LINE_ENTRY* SHOVE::replaceLine( LINE& aOld, LINE& aNew, bool aIncludeInChangedArea, NODE* aNode ) +SHOVE::ROOT_LINE_ENTRY* SHOVE::replaceLine( LINE& aOld, LINE& aNew, bool aIncludeInChangedArea, bool aAllowRedundantSegments, NODE* aNode ) { if( aIncludeInChangedArea ) { @@ -142,9 +142,10 @@ SHOVE::ROOT_LINE_ENTRY* SHOVE::replaceLine( LINE& aOld, LINE& aNew, bool aInclud // Now update the NODE (calling Replace invalidates the Links() in a LINE) if( aNode ) - aNode->Replace( aOld, aNew ); + aNode->Replace( aOld, aNew, aAllowRedundantSegments ); else - m_currentNode->Replace( aOld, aNew ); + m_currentNode->Replace( aOld, aNew, aAllowRedundantSegments ); + // point the Links() of the new line to its oldest ancestor for( LINKED_ITEM* link : aNew.Links() ) @@ -298,12 +299,11 @@ bool SHOVE::shoveLineFromLoneVia( const LINE& aCurLine, const LINE& aObstacleLin * Re-walk aObstacleLine around the given set of hulls, returning the result in aResultLine. */ bool SHOVE::shoveLineToHullSet( const LINE& aCurLine, const LINE& aObstacleLine, - LINE& aResultLine, const HULL_SET& aHulls ) + LINE& aResultLine, const HULL_SET& aHulls, bool aPermitAdjustingEndpoints ) { - const SHAPE_LINE_CHAIN& obs = aObstacleLine.CLine(); - + const int c_ENDPOINT_ON_HULL_THRESHOLD = 10000; int attempt; - + PNS_DBG( Dbg(), BeginGroup, "shove-details", 1 ); for( attempt = 0; attempt < 4; attempt++ ) @@ -311,10 +311,85 @@ bool SHOVE::shoveLineToHullSet( const LINE& aCurLine, const LINE& aObstacleLine, bool invertTraversal = ( attempt >= 2 ); bool clockwise = attempt % 2; int vFirst = -1, vLast = -1; - + SHAPE_LINE_CHAIN obs = aObstacleLine.CLine(); LINE l( aObstacleLine ); SHAPE_LINE_CHAIN path( l.CLine() ); + if( aPermitAdjustingEndpoints ) + { + auto minDistP = [&]( VECTOR2I pref, int& mdist, int& minhull ) -> VECTOR2I + { + int min_dist = std::numeric_limits<int>::max(); + VECTOR2I nearestP; + + for( int i = 0; i < (int) aHulls.size(); i++ ) + { + const SHAPE_LINE_CHAIN& hull = + aHulls[invertTraversal ? aHulls.size() - 1 - i : i]; + int dist; + auto p = hull.NearestPoint( pref, true ); + + if( hull.PointInside( pref ) ) + dist = 0; + else + dist = ( p - pref ).EuclideanNorm(); + + if( dist < c_ENDPOINT_ON_HULL_THRESHOLD && dist < min_dist ) + { + bool reject = false; + + /*for( int j = 0; j < (int) aHulls.size(); j++ ) + { + if ( i != j && aHulls[j].PointInside( p ) ) + { + reject = true; + break; + } + }*/ + + if( !reject ) + { + min_dist = dist; + nearestP = p; + minhull = invertTraversal ? aHulls.size() - 1 - i : i; + } + } + } + mdist = min_dist; + return nearestP; + }; + + int minDist0, minDist1, minhull0, minhull1 ; + VECTOR2I p0 = minDistP( l.CPoint( 0 ), minDist0, minhull0 ); + VECTOR2I p1 = minDistP( l.CPoint( -1 ), minDist1, minhull1 ); + + PNS_DBG( Dbg(), Message, wxString::Format( "mindists : %d %d hulls %d %d\n", minDist0, minDist1, minhull0, minhull1 ) ); + + if( minDist1 < c_ENDPOINT_ON_HULL_THRESHOLD ) + { + l.Line().SetPoint( -1, p1 ); + obs = l.CLine(); + path = l.CLine(); + //PNS_DBG( Dbg(), AddPoint, p1, LIGHTRED, 200000, wxString::Format( "round-p1 dist %d besthull %d", dist, bestHull ) ); + } + + if( minDist0 < c_ENDPOINT_ON_HULL_THRESHOLD ) + { + l.Line().SetPoint( 0, p0 ); + obs = l.CLine(); + path = l.CLine(); + /*int dist = std::numeric_limits<int>::max(); + for (auto& h : hulls ) + { + dist = std::min(dist, h.Distance( p0, true )); + } + PNS_DBG( Dbg(), AddPoint, p0, LIGHTRED, 200000, wxString::Format( "round-p0 dist %d", dist ) );*/ + } + } + + + bool failWalk = false; + for( int i = 0; i < (int) aHulls.size(); i++ ) { const SHAPE_LINE_CHAIN& hull = aHulls[invertTraversal ? aHulls.size() - 1 - i : i]; @@ -330,14 +405,17 @@ bool SHOVE::shoveLineToHullSet( const LINE& aCurLine, const LINE& aObstacleLine, l.CLine().Format().c_str(), clockwise? 1 : 0) ); - PNS_DBGN( Dbg(), EndGroup ); - return false; + failWalk = true; + break; } path.Simplify2(); l.SetShape( path ); } + if( failWalk ) + continue; + for( int i = 0; i < std::min( path.PointCount(), obs.PointCount() ); i++ ) { if( path.CPoint( i ) != obs.CPoint( i ) ) @@ -358,7 +436,7 @@ bool SHOVE::shoveLineToHullSet( const LINE& aCurLine, const LINE& aObstacleLine, } } - if( ( vFirst < 0 || vLast < 0 ) && !path.CompareGeometry( aObstacleLine.CLine() ) ) + if( ( vFirst < 0 || vLast < 0 ) && !path.CompareGeometry( obs ) ) { PNS_DBG( Dbg(), Message, wxString::Format( wxT( "attempt %d fail vfirst-last" ), attempt ) ); @@ -429,7 +507,7 @@ bool SHOVE::shoveLineToHullSet( const LINE& aCurLine, const LINE& aObstacleLine, bool SHOVE::ShoveObstacleLine( const LINE& aCurLine, const LINE& aObstacleLine, LINE& aResultLine ) { - const int cHullFailureExpansionFactor = 10; + const int cHullFailureExpansionFactor = 1000; int extraHullExpansion = 0; @@ -469,7 +547,7 @@ bool SHOVE::ShoveObstacleLine( const LINE& aCurLine, const LINE& aObstacleLine, m_router->GetInterface()->GetNetCode( obstacleLine.Net() ), clearance ) );*/ - for( int attempt = 0; attempt < 2; attempt++ ) + for( int attempt = 0; attempt < 3; attempt++ ) { HULL_SET hulls; @@ -508,7 +586,9 @@ bool SHOVE::ShoveObstacleLine( const LINE& aCurLine, const LINE& aObstacleLine, hulls.push_back( aCurLine.Via().Hull( viaClearance, obstacleLineWidth, layer ) ); } - if (shoveLineToHullSet( aCurLine, obstacleLine, aResultLine, hulls ) ) + bool permitMovingEndpoints = (attempt >= 2); + + if (shoveLineToHullSet( aCurLine, obstacleLine, aResultLine, hulls, permitMovingEndpoints ) ) { if( obsVia ) aResultLine.AppendVia( *obsVia ); @@ -572,14 +652,15 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingSegment( LINE& aCurrent, SEGMENT* aObstacl shovedLine.Line().Simplify2(); - sanityCheck( &obstacleLine, &shovedLine ); - replaceLine( obstacleLine, shovedLine ); + replaceLine( obstacleLine, shovedLine, true, false ); if( !pushLineStack( shovedLine ) ) return SH_INCOMPLETE; + + return SH_OK; } - return SH_OK; + return SH_INCOMPLETE; } @@ -622,8 +703,7 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingArc( LINE& aCurrent, ARC* aObstacleArc ) int rank = aCurrent.Rank(); shovedLine.SetRank( rank - 1 ); - sanityCheck( &obstacleLine, &shovedLine ); - replaceLine( obstacleLine, shovedLine ); + replaceLine( obstacleLine, shovedLine, true, false ); if( !pushLineStack( shovedLine ) ) return SH_INCOMPLETE; @@ -657,8 +737,7 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingLine( LINE& aCurrent, LINE& aObstacle, int m_newHead = shovedLine; } #endif - sanityCheck( &aObstacle, &shovedLine ); - replaceLine( aObstacle, shovedLine ); + replaceLine( aObstacle, shovedLine, true, false ); shovedLine.SetRank( aNextRank ); @@ -759,7 +838,6 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingSolid( LINE& aCurrent, ITEM* aObstacle, OB } #endif - sanityCheck( &aCurrent, &walkaroundLine ); if( !m_lineStack.empty() ) { @@ -786,7 +864,7 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingSolid( LINE& aCurrent, ITEM* aObstacle, OB if(!success) return SH_INCOMPLETE; - replaceLine( aCurrent, walkaroundLine ); + replaceLine( aCurrent, walkaroundLine, true, false ); walkaroundLine.SetRank( nextRank ); @@ -941,7 +1019,7 @@ bool SHOVE::pushSpringback( NODE* aNode, const OPT_BOX2I& aAffectedArea ) * Push or shove a via by at least aForce. (The via might be pushed or shoved slightly further * to keep it from landing on an existing joint.) */ -SHOVE::SHOVE_STATUS SHOVE::pushOrShoveVia( VIA* aVia, const VECTOR2I& aForce, int aNewRank ) +SHOVE::SHOVE_STATUS SHOVE::pushOrShoveVia( VIA* aVia, const VECTOR2I& aForce, int aNewRank, bool aDontUnwindStack ) { LINE_PAIR_VEC draggedLines; VECTOR2I p0( aVia->Pos() ); @@ -1015,7 +1093,9 @@ SHOVE::SHOVE_STATUS SHOVE::pushOrShoveVia( VIA* aVia, const VECTOR2I& aForce, in VIA *v2 = pushedVia.get(); - unwindLineStack( aVia ); + if( !aDontUnwindStack ) + unwindLineStack( aVia ); + replaceItems( aVia, std::move( pushedVia ) ); if( draggedLines.empty() ) // stitching via? make sure the router won't forget about it @@ -1029,7 +1109,8 @@ SHOVE::SHOVE_STATUS SHOVE::pushOrShoveVia( VIA* aVia, const VECTOR2I& aForce, in int n = 0; for( LINE_PAIR lp : draggedLines ) { - unwindLineStack( &lp.first ); + if( !aDontUnwindStack ) + unwindLineStack( &lp.first ); PNS_DBG( Dbg(), Message, wxString::Format("fan %d/%d\n", n, (int) draggedLines.size() ) ); n++; @@ -1037,10 +1118,12 @@ SHOVE::SHOVE_STATUS SHOVE::pushOrShoveVia( VIA* aVia, const VECTOR2I& aForce, in if( lp.second.SegmentCount() ) { lp.second.ClearLinks(); - ROOT_LINE_ENTRY* rootEntry = replaceLine( lp.first, lp.second ); + ROOT_LINE_ENTRY* rootEntry = replaceLine( lp.first, lp.second, true, true ); lp.second.LinkVia( v2 ); - unwindLineStack( &lp.second ); + + if( !aDontUnwindStack ) + unwindLineStack( &lp.second ); lp.second.SetRank( aNewRank ); @@ -1273,7 +1356,7 @@ SHOVE::SHOVE_STATUS SHOVE::onReverseCollidingVia( LINE& aCurrent, VIA* aObstacle PNS_DBGN( Dbg(), EndGroup ); int currentRank = aCurrent.Rank(); - replaceLine( aCurrent, shoved ); + replaceLine( aCurrent, shoved, true, false ); if( !pushLineStack( shoved ) ) return SH_INCOMPLETE; @@ -1293,7 +1376,27 @@ void SHOVE::unwindLineStack( const LINKED_ITEM* aSeg ) if( i->ContainsLink( aSeg ) ) { PNS_DBG(Dbg(), Message, wxString::Format("Unwind lc %d (depth %d/%d)", i->SegmentCount(), d, (int)m_lineStack.size() ) ); - i = m_lineStack.erase( i ); +//comment! + if( i->EndsWithVia() && !aSeg->OfKind( ITEM::VIA_T) ) + { + i = m_lineStack.erase( i ); + } + else + { + VIA *via = nullptr; + + for( auto l : i->Links() ) + if( l->OfKind( ITEM::VIA_T ) ) + via = static_cast<VIA*>( l ); + + if( via ) + { + i->ClearLinks( ); + i->LinkVia( via ); + } + i++; + } + } else { @@ -1347,24 +1450,29 @@ bool SHOVE::pushLineStack( const LINE& aL, bool aKeepCurrentOnTop ) m_lineStack.push_back( aL ); } + + pruneLineFromOptimizerQueue( aL ); m_optimizerQueue.push_back( aL ); return true; } -void SHOVE::popLineStack( ) +bool SHOVE::pruneLineFromOptimizerQueue( const LINE& aLine ) { - LINE& l = m_lineStack.back(); - + int pre = m_optimizerQueue.size(); for( std::vector<LINE>::iterator i = m_optimizerQueue.begin(); i != m_optimizerQueue.end(); ) { bool found = false; - for( LINKED_ITEM* s : l.Links() ) + for( LINKED_ITEM* s : aLine.Links() ) { - if( i->ContainsLink( s ) ) + PNS_DBG( Dbg(), Message, + wxString::Format( "cur lc %d lnk %p cnt %d", i->LinkCount(), s, aLine.LinkCount() ) ); + + if( i->ContainsLink( s ) && !s->OfKind( ITEM::VIA_T ) ) { + i = m_optimizerQueue.erase( i ); found = true; break; @@ -1375,6 +1483,13 @@ void SHOVE::popLineStack( ) i++; } + return true; +} + +void SHOVE::popLineStack( ) +{ + LINE& l = m_lineStack.back(); + pruneLineFromOptimizerQueue( l ); m_lineStack.pop_back(); } @@ -2272,11 +2387,11 @@ SHOVE::SHOVE_STATUS SHOVE::Run() PNS_DBG( Dbg(), Message, wxString::Format("process head-via [%d %d] node=%p", l.theVia->pos.x, l.theVia->pos.y, m_currentNode ) ); auto realVia = m_currentNode->FindViaByHandle( *l.theVia ); assert( realVia != nullptr ); - headSet.Add( realVia ); + headSet.Add( realVia->Clone() ); } else { - headSet.Add( *l.origHead ); + headSet.Add( *l.origHead->Clone() ); } } @@ -2324,7 +2439,7 @@ SHOVE::SHOVE_STATUS SHOVE::Run() viaRoot->oldVia = viaToDrag; headLineEntry.draggedVia = viaToDrag; - st = pushOrShoveVia( viaToDrag, ( headLineEntry.viaNewPos - viaToDrag->Pos() ), 0 ); + st = pushOrShoveVia( viaToDrag, ( headLineEntry.viaNewPos - viaToDrag->Pos() ), 0, true ); if( st != SH_OK ) break; diff --git a/pcbnew/router/pns_shove.h b/pcbnew/router/pns_shove.h index 39358d1b84..794c483731 100644 --- a/pcbnew/router/pns_shove.h +++ b/pcbnew/router/pns_shove.h @@ -168,8 +168,10 @@ private: bool m_locked; }; + bool pruneLineFromOptimizerQueue( const LINE& aLine ); + bool shoveLineToHullSet( const LINE& aCurLine, const LINE& aObstacleLine, - LINE& aResultLine, const HULL_SET& aHulls ); + LINE& aResultLine, const HULL_SET& aHulls, bool aPermitAdjustingEndpoints = false ); NODE* reduceSpringback( const ITEM_SET& aHeadSet ); @@ -186,7 +188,7 @@ private: SHOVE_STATUS onCollidingSolid( LINE& aCurrent, ITEM* aObstacle, OBSTACLE& aObstacleInfo ); SHOVE_STATUS onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia, OBSTACLE& aObstacleInfo, int aNextRank ); SHOVE_STATUS onReverseCollidingVia( LINE& aCurrent, VIA* aObstacleVia, OBSTACLE& aObstacleInfo ); - SHOVE_STATUS pushOrShoveVia( VIA* aVia, const VECTOR2I& aForce, int aNextRank ); + SHOVE_STATUS pushOrShoveVia( VIA* aVia, const VECTOR2I& aForce, int aNextRank, bool aDontUnwindStack = false ); OPT_BOX2I totalAffectedArea() const; @@ -203,6 +205,7 @@ private: void replaceItems( ITEM* aOld, std::unique_ptr< ITEM > aNew ); ROOT_LINE_ENTRY* replaceLine( LINE& aOld, LINE& aNew, bool aIncludeInChangedArea = true, + bool aAllowRedundantSegments = true, NODE *aNode = nullptr ); ROOT_LINE_ENTRY* findRootLine( const LINE& aLine );