Fix entry-angle violations and add boundary-first routing infrastructure
The short-stub fallback in NormalizeExitPath fixes 2 entry-angle violations (edge/7, edge/27) that persisted because the default long-stub normalization created horizontal segments crossing nodes in occupied Y-bands. When the long stub fails HasClearSourceExitSegment, the normalizer now tries a 24px short stub that creates a perpendicular dog-leg exit avoiding the blocking node. Also adds boundary-first routing infrastructure (not yet active in the main path) including global boundary slot pre-computation, A* routing with pre-assigned slots, coordinated cluster repair with net-total promotion criterion, and gateway target approach overshoot clipping. The net-total criterion (CountTotalHardViolations) is proven to reduce violations from 10 to 7 but requires expensive BuildFinalRestabilizedCandidate calls that exceed the 15s speed budget. Root cause analysis confirms the remaining 8 violations (3 gateway hooks, 1 target join, 1 shared lane, 3 under-node) are caused by Sugiyama node placement creating routing corridors too narrow for clean edge routing. The fix must happen upstream in node placement, not edge post-processing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
namespace StellaOps.ElkSharp;
|
||||
|
||||
internal static partial class ElkEdgeRouterIterative
|
||||
{
|
||||
private static ElkRoutedEdge[] ApplyBoundaryFirstVerification(
|
||||
ElkRoutedEdge[] edges,
|
||||
ElkRoutedEdge[] originalEdges,
|
||||
ElkPositionedNode[] nodes,
|
||||
ElkLayoutDirection direction,
|
||||
double minLineClearance)
|
||||
{
|
||||
// Minimal structural safety only — the hybrid winner refinement
|
||||
// handles remaining violations after boundary-first is promoted.
|
||||
var result = ElkEdgePostProcessor.AvoidNodeCrossings(edges, nodes, direction);
|
||||
result = ElkEdgePostProcessor.EliminateDiagonalSegments(result, nodes);
|
||||
result = ElkEdgePostProcessorSimplify.SimplifyEdgePaths(result, nodes);
|
||||
result = ElkEdgePostProcessorSimplify.TightenOuterCorridors(result, nodes);
|
||||
if (HighwayProcessingEnabled)
|
||||
{
|
||||
result = ElkEdgeRouterHighway.BreakShortHighways(result, nodes);
|
||||
}
|
||||
|
||||
// Normalize boundary geometry for the slot-pinned endpoints.
|
||||
result = ElkEdgePostProcessor.NormalizeBoundaryAngles(result, nodes);
|
||||
result = ElkEdgePostProcessor.NormalizeSourceExitAngles(result, nodes);
|
||||
|
||||
// Collector-specific structural repairs.
|
||||
result = RestoreProtectedRepeatCollectorCorridors(result, originalEdges, nodes);
|
||||
|
||||
// Below-graph clamping and final crossing check.
|
||||
result = ClampBelowGraphEdges(result, nodes);
|
||||
result = ElkEdgePostProcessor.AvoidNodeCrossings(result, nodes, direction);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user