Adaptive corridor grid + gateway redirect for all gap sizes

- IntermediateGridSpacing now uses average node height (~100px) instead
  of fixed 40px. A* grid cells are node-sized in corridors, forcing edges
  through wide lanes. Fine node-boundary lines still provide precision.
- Gateway redirect (TryRedirectGatewayFaceOverflowEntry) now fires for
  ALL gap sizes, not just when horizontal gaps are large. Preferred over
  spreading because redirect shortens paths (no detour).
- Final target-join repair tries both spread and reassignment, accepts
  whichever fixes the join without creating detours/shared lanes.
- NodeSpacing=40: all tests pass. NodeSpacing=50: target-join+shared-lane
  fixed, 1 ExcessiveDetour remains (from spread, needs FinalScore exclusion).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
master
2026-04-01 18:24:40 +03:00
parent c3c6f2d0c6
commit 214a3a0322
3 changed files with 58 additions and 25 deletions

View File

@@ -83,22 +83,21 @@ internal static partial class ElkEdgeRouterIterative
// Compute the current gap and required spread.
var currentGap = Math.Abs(approachYs[1] - approachYs[0]);
// For gateway targets, try redirecting one edge to the left tip
// regardless of gap size. This is preferred over spreading because
// it shortens the path (no detour). The redirect only applies when
// HasTargetApproachJoin detects convergence.
if (ElkShapeBoundaries.IsGatewayShape(targetNode)
&& ElkEdgeRoutingScoring.HasTargetApproachJoin(
paths[0], paths[1], minClearance, 3))
{
result = TryRedirectGatewayFaceOverflowEntry(
result, edges, groupEdges, paths, targetNode, approachYs);
continue;
}
if (currentGap >= minClearance)
{
// Horizontal approach lanes are well separated, but vertical
// approach segments near the target may still converge (e.g.,
// two edges arriving at a gateway bottom face with parallel
// vertical segments only 28px apart). Redirect the edge whose
// horizontal approach is closest to the node center to the
// upstream face (left tip for LTR).
if (ElkShapeBoundaries.IsGatewayShape(targetNode)
&& ElkEdgeRoutingScoring.HasTargetApproachJoin(
paths[0], paths[1], minClearance, 3))
{
result = TryRedirectGatewayFaceOverflowEntry(
result, edges, groupEdges, paths, targetNode, approachYs);
}
continue;
}