Fix target-join at NodeSpacing=50 via final post-pipeline spread

Added final target-join detection and repair after per-edge gateway
fixes. The per-edge redirect can create new target-join convergences
that don't exist during the main optimization loop. The post-pipeline
spread fixes them without normalization (which would undo the spread).

NodeSpacing=50 progress: target-join FIXED, shared-lane FIXED.
Remaining at NodeSpacing=50: ExcessiveDetourViolations=1 (from
target-join spread creating longer path).

NodeSpacing=40: all tests pass (artifact 1/1, StraightExit 2/2,
HybridDeterministicMode 3/3).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
master
2026-04-01 17:37:37 +03:00
parent fafcadbc9a
commit e01549c2d6
2 changed files with 40 additions and 0 deletions

View File

@@ -292,6 +292,29 @@ internal static partial class ElkEdgeRouterIterative
current = RepairRemainingEdgeNodeCrossings(current, nodes);
}
// Final target-join repair: the per-edge gateway fixes may create
// new target-join convergences that didn't exist before. Run the
// spread one more time to catch them.
var finalJoinSeverity = new Dictionary<string, int>(StringComparer.Ordinal);
var finalJoinCount = ElkEdgeRoutingScoring.CountTargetApproachJoinViolations(current.Edges, nodes, finalJoinSeverity, 1);
ElkLayoutDiagnostics.LogProgress(
$"Final target-join check: count={finalJoinCount} edges=[{string.Join(", ", finalJoinSeverity.Keys.OrderBy(k => k))}]");
if (finalJoinSeverity.Count >= 2)
{
var joinFocus = finalJoinSeverity.Keys.ToArray();
var joinCandidate = ElkEdgePostProcessor.SpreadTargetApproachJoins(
current.Edges, nodes, minLineClearance, joinFocus, forceOutwardAxisSpacing: true);
joinCandidate = ElkEdgePostProcessor.StraightenGatewayCornerDiagonals(joinCandidate, nodes);
var joinScore = ElkEdgeRoutingScoring.ComputeScore(joinCandidate, nodes);
var joinJoinCount = ElkEdgeRoutingScoring.CountTargetApproachJoinViolations(joinCandidate, nodes);
if (joinJoinCount < finalJoinCount)
{
current = current with { Score = joinScore, Edges = joinCandidate };
ElkLayoutDiagnostics.LogProgress(
$"Hybrid final target-join repair: joins={joinJoinCount}");
}
}
return current;
}