diff --git a/src/__Libraries/StellaOps.ElkSharp/ElkEdgeRouterIterative.WinnerRefinement.Hybrid.cs b/src/__Libraries/StellaOps.ElkSharp/ElkEdgeRouterIterative.WinnerRefinement.Hybrid.cs index 947054a63..47a8e8ad9 100644 --- a/src/__Libraries/StellaOps.ElkSharp/ElkEdgeRouterIterative.WinnerRefinement.Hybrid.cs +++ b/src/__Libraries/StellaOps.ElkSharp/ElkEdgeRouterIterative.WinnerRefinement.Hybrid.cs @@ -315,38 +315,31 @@ internal static partial class ElkEdgeRouterIterative var segLen = Math.Abs(cpath[si + 1].X - cpath[si].X); var laneY = cpath[si].Y; if (segLen < localMinSweep || laneY <= graphMinYLocal - 10d) continue; - // Offset must exceed the target-join detection threshold - // (node-size clearance, not spacing-scaled) so parallel - // corridor segments aren't flagged as joins. var nodeSizeClearance = ElkEdgeRoutingScoring.ResolveNodeSizeClearance(nodes); - var localCorridorY = baseCorridorY - (corridorFixed * (nodeSizeClearance + 4d)); var src = cpath[0]; var tgt = cpath[^1]; var stubX = src.X + 24d; - - // Find the target node to determine approach geometry. var tgtNode = nodesById.TryGetValue(edge.TargetNodeId ?? string.Empty, out var tn) ? tn : null; + + // Both corridors go ABOVE the graph but with large vertical + // separation (2x nodeSizeClearance) so they're visually distinct. + var localCorridorY = baseCorridorY - (corridorFixed * (nodeSizeClearance * 2d)); + List newPath; if (tgtNode is not null && tgtNode.Kind is "End") { - // Enter End from the right side: corridor goes past End, - // descends to End's center Y, approaches from right. - // This avoids the ugly long vertical drop from corridor. - // Offset both X and Y for each corridor edge so they - // enter End at distinct positions (visually traceable). + // Enter End from the right side at a distinct Y position. var rightApproachX = tgtNode.X + tgtNode.Width + 24d + (corridorFixed * (nodeSizeClearance + 4d)); - // Spread entry points across the right face. First edge - // enters at 1/3 from top, second at 2/3, etc. - var slotFraction = (corridorFixed + 1d) / (corridorFixed + 2d); - var centerY = tgtNode.Y + (tgtNode.Height * slotFraction); + var slotFraction = corridorFixed == 0 ? 0.33d : 0.67d; + var entryY = tgtNode.Y + (tgtNode.Height * slotFraction); newPath = [ src, new() { X = stubX, Y = src.Y }, new() { X = stubX, Y = localCorridorY }, new() { X = rightApproachX, Y = localCorridorY }, - new() { X = rightApproachX, Y = centerY }, - new() { X = tgtNode.X + tgtNode.Width, Y = centerY }, + new() { X = rightApproachX, Y = entryY }, + new() { X = tgtNode.X + tgtNode.Width, Y = entryY }, ]; } else