From 24a8c2a684021b5ca0dada9ee88ea1a53c202dcc Mon Sep 17 00:00:00 2001
From: JamesJCode <13408010-JamesJCode@users.noreply.gitlab.com>
Date: Tue, 18 Mar 2025 12:37:16 +0000
Subject: [PATCH] Ensure PNS length tuning calculation uses correct layer ID
 context

Fixes https://gitlab.com/kicad/code/kicad/-/issues/20372
---
 pcbnew/router/pns_dp_meander_placer.cpp   |  6 ++-
 pcbnew/router/pns_meander_placer.cpp      |  2 +-
 pcbnew/router/pns_meander_skew_placer.cpp |  6 ++-
 pcbnew/router/pns_topology.cpp            | 50 +++++++++++------------
 pcbnew/router/pns_topology.h              |  3 +-
 5 files changed, 36 insertions(+), 31 deletions(-)

diff --git a/pcbnew/router/pns_dp_meander_placer.cpp b/pcbnew/router/pns_dp_meander_placer.cpp
index db991fae61..6c95cadc0b 100644
--- a/pcbnew/router/pns_dp_meander_placer.cpp
+++ b/pcbnew/router/pns_dp_meander_placer.cpp
@@ -104,7 +104,8 @@ bool DP_MEANDER_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
     if( !m_originPair.PLine().SegmentCount() || !m_originPair.NLine().SegmentCount() )
         return false;
 
-    m_tunedPathP = topo.AssembleTuningPath( m_originPair.PLine().GetLink( 0 ), &m_startPad_p, &m_endPad_p );
+    m_tunedPathP = topo.AssembleTuningPath( Router()->GetInterface(), m_originPair.PLine().GetLink( 0 ), &m_startPad_p,
+                                            &m_endPad_p );
 
     m_padToDieP = 0;
 
@@ -114,7 +115,8 @@ bool DP_MEANDER_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
     if( m_endPad_p )
         m_padToDieP += m_endPad_p->GetPadToDie();
 
-    m_tunedPathN = topo.AssembleTuningPath( m_originPair.NLine().GetLink( 0 ), &m_startPad_n, &m_endPad_n );
+    m_tunedPathN = topo.AssembleTuningPath( Router()->GetInterface(), m_originPair.NLine().GetLink( 0 ), &m_startPad_n,
+                                            &m_endPad_n );
 
     m_padToDieN = 0;
 
diff --git a/pcbnew/router/pns_meander_placer.cpp b/pcbnew/router/pns_meander_placer.cpp
index 76c2145504..0d66d0c590 100644
--- a/pcbnew/router/pns_meander_placer.cpp
+++ b/pcbnew/router/pns_meander_placer.cpp
@@ -72,7 +72,7 @@ bool MEANDER_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
     m_originLine = m_world->AssembleLine( m_initialSegment );
 
     TOPOLOGY topo( m_world );
-    m_tunedPath = topo.AssembleTuningPath( m_initialSegment, &m_startPad_n, &m_endPad_n );
+    m_tunedPath = topo.AssembleTuningPath( Router()->GetInterface(), m_initialSegment, &m_startPad_n, &m_endPad_n );
 
     m_padToDieLength = 0;
 
diff --git a/pcbnew/router/pns_meander_skew_placer.cpp b/pcbnew/router/pns_meander_skew_placer.cpp
index 42d73627e9..d62d598ec4 100644
--- a/pcbnew/router/pns_meander_skew_placer.cpp
+++ b/pcbnew/router/pns_meander_skew_placer.cpp
@@ -78,7 +78,8 @@ bool MEANDER_SKEW_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
         !m_originPair.NLine().SegmentCount() )
         return false;
 
-    m_tunedPathP = topo.AssembleTuningPath( m_originPair.PLine().GetLink( 0 ), &m_startPad_p, &m_endPad_p );
+    m_tunedPathP = topo.AssembleTuningPath( Router()->GetInterface(), m_originPair.PLine().GetLink( 0 ), &m_startPad_p,
+                                            &m_endPad_p );
 
     m_padToDieP = 0;
 
@@ -88,7 +89,8 @@ bool MEANDER_SKEW_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
     if( m_endPad_p )
         m_padToDieP += m_endPad_p->GetPadToDie();
 
-    m_tunedPathN = topo.AssembleTuningPath( m_originPair.NLine().GetLink( 0 ), &m_startPad_n, &m_endPad_n );
+    m_tunedPathN = topo.AssembleTuningPath( Router()->GetInterface(), m_originPair.NLine().GetLink( 0 ), &m_startPad_n,
+                                            &m_endPad_n );
 
     m_padToDieN = 0;
 
diff --git a/pcbnew/router/pns_topology.cpp b/pcbnew/router/pns_topology.cpp
index fb5ebdf831..2720a5ef84 100644
--- a/pcbnew/router/pns_topology.cpp
+++ b/pcbnew/router/pns_topology.cpp
@@ -331,7 +331,8 @@ const ITEM_SET TOPOLOGY::AssembleTrivialPath( ITEM* aStart,
 }
 
 
-const ITEM_SET TOPOLOGY::AssembleTuningPath( ITEM* aStart, SOLID** aStartPad, SOLID** aEndPad )
+const ITEM_SET TOPOLOGY::AssembleTuningPath( ROUTER_IFACE* aRouterIface, ITEM* aStart, SOLID** aStartPad,
+                                             SOLID** aEndPad )
 {
     std::pair<const JOINT*, const JOINT*> joints;
     ITEM_SET initialPath = AssembleTrivialPath( aStart, &joints, true );
@@ -416,41 +417,40 @@ const ITEM_SET TOPOLOGY::AssembleTuningPath( ITEM* aStart, SOLID** aStartPad, SO
                 aLine.Insert( aForward ? 0 : aLine.PointCount(), aPad->GetPosition() );
             };
 
-    auto processPad =
-            [&]( const JOINT* aJoint, PAD* aPad, PCB_LAYER_ID aLayer )
-            {
-                const auto& shape = aPad->GetEffectivePolygon( aLayer, ERROR_INSIDE );
+    auto processPad = [&]( const JOINT* aJoint, PAD* aPad, int aLayer )
+    {
+        for( int idx = 0; idx < initialPath.Size(); idx++ )
+        {
+            if( initialPath[idx]->Kind() != ITEM::LINE_T )
+                continue;
 
-                for( int idx = 0; idx < initialPath.Size(); idx++ )
-                {
-                    if( initialPath[idx]->Kind() != ITEM::LINE_T )
-                        continue;
+            LINE*        line = static_cast<LINE*>( initialPath[idx] );
+            PCB_LAYER_ID pcbLayer = aRouterIface->GetBoardLayerFromPNSLayer( line->Layer() );
 
-                    LINE* line = static_cast<LINE*>( initialPath[idx] );
+            if( !aPad->FlashLayer( pcbLayer ) )
+                continue;
 
-                    if( !aPad->FlashLayer( line->Layer() ) )
-                        continue;
+            const std::vector<VECTOR2I>& points = line->CLine().CPoints();
 
-                    const std::vector<VECTOR2I>& points = line->CLine().CPoints();
+            if( points.front() != aJoint->Pos() && points.back() != aJoint->Pos() )
+                continue;
 
-                    if( points.front() != aJoint->Pos() && points.back() != aJoint->Pos() )
-                        continue;
+            const auto& shape = aPad->GetEffectivePolygon( pcbLayer, ERROR_INSIDE );
 
-                    SHAPE_LINE_CHAIN& slc = line->Line();
-                    const PCB_LAYER_ID& layer = static_cast<PCB_LAYER_ID>( line->Layer() );
+            SHAPE_LINE_CHAIN& slc = line->Line();
 
-                    if( shape->Contains( slc.CPoint( 0 ) ) )
-                        clipLineToPad( slc, aPad, layer, true );
-                    else if( shape->Contains( slc.CPoint( -1 ) ) )
-                        clipLineToPad( slc, aPad, layer, false );
-                }
-            };
+            if( shape->Contains( slc.CPoint( 0 ) ) )
+                clipLineToPad( slc, aPad, pcbLayer, true );
+            else if( shape->Contains( slc.CPoint( -1 ) ) )
+                clipLineToPad( slc, aPad, pcbLayer, false );
+        }
+    };
 
     if( padA )
-        processPad( joints.first, padA, static_cast<PCB_LAYER_ID>( joints.first->Layer() ) );
+        processPad( joints.first, padA, joints.first->Layer() );
 
     if( padB )
-        processPad( joints.second, padB, static_cast<PCB_LAYER_ID>( joints.second->Layer() ) );
+        processPad( joints.second, padB, joints.second->Layer() );
 
     return initialPath;
 }
diff --git a/pcbnew/router/pns_topology.h b/pcbnew/router/pns_topology.h
index 76e60bd25d..f1ae1d5184 100644
--- a/pcbnew/router/pns_topology.h
+++ b/pcbnew/router/pns_topology.h
@@ -35,6 +35,7 @@ class JOINT;
 class ITEM;
 class SOLID;
 class DIFF_PAIR;
+class ROUTER_IFACE;
 
 class TOPOLOGY
 {
@@ -90,7 +91,7 @@ public:
      * @param aEndPad will be filled with the ending pad of the path, if found.
      * @return an item set containing all the items in the path.
      */
-    const ITEM_SET AssembleTuningPath( ITEM* aStart, SOLID** aStartPad = nullptr,
+    const ITEM_SET AssembleTuningPath( ROUTER_IFACE* aRouterIface, ITEM* aStart, SOLID** aStartPad = nullptr,
                                        SOLID** aEndPad = nullptr );
 
     const DIFF_PAIR AssembleDiffPair( SEGMENT* aStart );