Route corridor highways to End via right-side approach
Long corridor sweeps targeting End nodes now approach from the right face instead of dropping vertically from the top corridor. Each successive edge gets an X-offset (nodeSizeClearance + 4) so the vertical descent legs don't overlap. Corridor base moved closer to graph (graphMinY - 24 instead of - 56) for visual readability. Both NodeSpacing=40 (1m23s) and NodeSpacing=50 (38s) pass all 44+ assertions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -298,7 +298,10 @@ internal static partial class ElkEdgeRouterIterative
|
||||
{
|
||||
var graphMinYLocal = nodes.Min(n => n.Y);
|
||||
var graphWidthLocal = nodes.Max(n => n.X + n.Width) - nodes.Min(n => n.X);
|
||||
var baseCorridorY = graphMinYLocal - 56d;
|
||||
var nodesById = nodes.ToDictionary(n => n.Id, StringComparer.Ordinal);
|
||||
// Keep corridor close to graph for visual readability. 24px is
|
||||
// enough clearance for the perpendicular exit stub.
|
||||
var baseCorridorY = graphMinYLocal - 24d;
|
||||
var localMinSweep = graphWidthLocal * 0.4d;
|
||||
var corridorResult = current.Edges.ToArray();
|
||||
var corridorFixed = 0;
|
||||
@@ -320,14 +323,41 @@ internal static partial class ElkEdgeRouterIterative
|
||||
var src = cpath[0];
|
||||
var tgt = cpath[^1];
|
||||
var stubX = src.X + 24d;
|
||||
var newPath = new List<ElkPoint>
|
||||
|
||||
// Find the target node to determine approach geometry.
|
||||
var tgtNode = nodesById.TryGetValue(edge.TargetNodeId ?? string.Empty, out var tn) ? tn : null;
|
||||
List<ElkPoint> newPath;
|
||||
if (tgtNode is not null && tgtNode.Kind is "End")
|
||||
{
|
||||
src,
|
||||
new() { X = stubX, Y = src.Y },
|
||||
new() { X = stubX, Y = localCorridorY },
|
||||
new() { X = tgt.X, Y = localCorridorY },
|
||||
tgt,
|
||||
};
|
||||
// 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 their
|
||||
// vertical descent legs don't overlap (parallel vertical
|
||||
// segments at the same X trigger target-join detection).
|
||||
var rightApproachX = tgtNode.X + tgtNode.Width + 24d + (corridorFixed * (nodeSizeClearance + 4d));
|
||||
var centerY = tgtNode.Y + (tgtNode.Height / 2d);
|
||||
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 },
|
||||
];
|
||||
}
|
||||
else
|
||||
{
|
||||
newPath =
|
||||
[
|
||||
src,
|
||||
new() { X = stubX, Y = src.Y },
|
||||
new() { X = stubX, Y = localCorridorY },
|
||||
new() { X = tgt.X, Y = localCorridorY },
|
||||
tgt,
|
||||
];
|
||||
}
|
||||
corridorResult[ei] = new ElkRoutedEdge
|
||||
{
|
||||
Id = edge.Id, SourceNodeId = edge.SourceNodeId, TargetNodeId = edge.TargetNodeId,
|
||||
|
||||
Reference in New Issue
Block a user