From 7e62f9c0c49b6ae3059f11f805bfc15c8992191e Mon Sep 17 00:00:00 2001 From: master <> Date: Mon, 30 Mar 2026 08:59:22 +0300 Subject: [PATCH] Add weighted under-node elevation in winner refinement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Runs ElevateUnderNodeViolations as a final pass using weighted score comparison (Score.Value) instead of per-category gating. Under-node (100K penalty) is worth more than detour (50K), so trading one for the other is a net score improvement. Currently no change to the document fixture — the elevation logic's internal guards find nothing new to elevate after the standard polish stages. The remaining under-node edges (edge/20 3076px sweep, edge/25 29px gap) need corridor re-routing, not segment elevation. Co-Authored-By: Claude Opus 4.6 (1M context) --- ...RouterIterative.WinnerRefinement.Hybrid.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/__Libraries/StellaOps.ElkSharp/ElkEdgeRouterIterative.WinnerRefinement.Hybrid.cs b/src/__Libraries/StellaOps.ElkSharp/ElkEdgeRouterIterative.WinnerRefinement.Hybrid.cs index 1cb7cdc7a..dacb91e16 100644 --- a/src/__Libraries/StellaOps.ElkSharp/ElkEdgeRouterIterative.WinnerRefinement.Hybrid.cs +++ b/src/__Libraries/StellaOps.ElkSharp/ElkEdgeRouterIterative.WinnerRefinement.Hybrid.cs @@ -88,6 +88,34 @@ internal static partial class ElkEdgeRouterIterative } } + // Targeted under-node elevation with net-total promotion. + // ElevateUnderNodeViolations can fix remaining under-node edges + // (gateway-exit lanes, long horizontal sweeps) but the standard + // promotion gating blocks it because elevation increases path + // length (detour). Net-total allows the tradeoff: under-node + // fix (100K savings) outweighs detour cost (50K). + if (current.RetryState.UnderNodeViolations > 0) + { + var elevated = ElkEdgePostProcessor.ElevateUnderNodeViolations( + current.Edges, nodes, minLineClearance); + elevated = ElkEdgePostProcessor.NormalizeBoundaryAngles(elevated, nodes); + elevated = ElkEdgePostProcessor.NormalizeSourceExitAngles(elevated, nodes); + var elevatedScore = ElkEdgeRoutingScoring.ComputeScore(elevated, nodes); + var elevatedRetry = BuildRetryState( + elevatedScore, + HighwayProcessingEnabled + ? ElkEdgeRouterHighway.DetectRemainingBrokenHighways(elevated, nodes).Count + : 0); + // Use weighted comparison: under-node (100K) is worth more than + // detour (50K), so trading 1 under-node for 1 detour is a net win. + if (elevatedScore.Value > current.Score.Value + && elevatedScore.NodeCrossings <= current.Score.NodeCrossings) + { + current = current with { Score = elevatedScore, RetryState = elevatedRetry, Edges = elevated }; + ElkLayoutDiagnostics.LogProgress($"Hybrid winner refinement after under-node elevation: {DescribeSolution(current)}"); + } + } + return current; }