Refactor ElkSharp hybrid routing and document speed path

This commit is contained in:
master
2026-03-29 19:33:46 +03:00
parent 7d6bc2b0ab
commit e8f7ad7652
89 changed files with 13280 additions and 10732 deletions

View File

@@ -0,0 +1,149 @@
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Globalization;
namespace StellaOps.ElkSharp;
internal static partial class ElkEdgeRouterIterative
{
private static bool ShouldPreferFastTerminalOnlyHardRuleClosure(RoutingRetryState retryState)
{
return retryState.RemainingShortHighways == 0
&& retryState.RepeatCollectorCorridorViolations == 0
&& retryState.RepeatCollectorNodeClearanceViolations == 0
&& retryState.TargetApproachBacktrackingViolations == 0
&& retryState.ExcessiveDetourViolations == 0
&& retryState.BoundarySlotViolations == 0
&& retryState.BelowGraphViolations == 0
&& retryState.UnderNodeViolations == 0
&& retryState.LongDiagonalViolations == 0
&& retryState.SharedLaneViolations <= 2
&& (retryState.TargetApproachJoinViolations > 0
|| retryState.EntryAngleViolations > 0
|| retryState.GatewaySourceExitViolations > 0
|| retryState.SharedLaneViolations > 0);
}
private static ElkRoutedEdge[] BuildFastTerminalOnlyHardRuleCandidate(
ElkRoutedEdge[] edges,
ElkPositionedNode[] nodes,
ElkLayoutDirection direction,
double minLineClearance,
IReadOnlyCollection<string> restrictedEdgeIds)
{
var candidate = edges;
candidate = ChoosePreferredHardRuleLayout(
candidate,
ElkEdgePostProcessor.SeparateSharedLaneConflicts(
candidate,
nodes,
minLineClearance,
restrictedEdgeIds),
nodes);
candidate = ChoosePreferredHardRuleLayout(
candidate,
ElkEdgePostProcessor.SpreadSourceDepartureJoins(
candidate,
nodes,
minLineClearance,
restrictedEdgeIds),
nodes);
candidate = ChoosePreferredHardRuleLayout(
candidate,
ElkEdgePostProcessor.RepairBoundaryAnglesAndTargetApproaches(
candidate,
nodes,
minLineClearance,
restrictedEdgeIds),
nodes);
candidate = ChoosePreferredHardRuleLayout(
candidate,
ElkEdgePostProcessor.SpreadTargetApproachJoins(
candidate,
nodes,
minLineClearance,
restrictedEdgeIds,
forceOutwardAxisSpacing: true),
nodes);
candidate = ChoosePreferredHardRuleLayout(
candidate,
ElkEdgePostProcessor.NormalizeBoundaryAngles(candidate, nodes),
nodes);
candidate = ChoosePreferredHardRuleLayout(
candidate,
ElkEdgePostProcessor.NormalizeSourceExitAngles(candidate, nodes),
nodes);
candidate = ChoosePreferredHardRuleLayout(
candidate,
ElkEdgePostProcessor.SeparateSharedLaneConflicts(
candidate,
nodes,
minLineClearance,
restrictedEdgeIds),
nodes);
return candidate;
}
private static bool ShouldPreferCompactFocusedTerminalClosure(
RoutingRetryState retryState,
int focusEdgeCount)
{
return focusEdgeCount <= 4
&& retryState.BoundarySlotViolations == 0
&& retryState.BelowGraphViolations == 0
&& retryState.UnderNodeViolations == 0
&& retryState.GatewaySourceExitViolations == 0
&& retryState.EntryAngleViolations == 0
&& retryState.TargetApproachBacktrackingViolations == 0
&& retryState.ExcessiveDetourViolations == 0
&& retryState.TargetApproachJoinViolations <= 1
&& retryState.SharedLaneViolations <= 1
&& (retryState.TargetApproachJoinViolations > 0
|| retryState.SharedLaneViolations > 0);
}
private static ElkRoutedEdge[] ApplyCompactFocusedTerminalClosure(
ElkRoutedEdge[] edges,
ElkPositionedNode[] nodes,
ElkLayoutDirection direction,
double minLineClearance,
IReadOnlyCollection<string> focusedEdgeIds)
{
var candidate = edges;
candidate = ApplyGuardedFocusedHardRulePass(
candidate,
nodes,
current => ElkEdgePostProcessor.SeparateSharedLaneConflicts(current, nodes, minLineClearance, focusedEdgeIds));
candidate = ApplyGuardedFocusedHardRulePass(
candidate,
nodes,
current => ElkEdgePostProcessor.SpreadSourceDepartureJoins(current, nodes, minLineClearance, focusedEdgeIds));
candidate = ApplyGuardedFocusedHardRulePass(
candidate,
nodes,
current => ElkEdgePostProcessor.RepairBoundaryAnglesAndTargetApproaches(current, nodes, minLineClearance, focusedEdgeIds));
candidate = ApplyGuardedFocusedHardRulePass(
candidate,
nodes,
current => ElkEdgePostProcessor.SpreadTargetApproachJoins(
current,
nodes,
minLineClearance,
focusedEdgeIds,
forceOutwardAxisSpacing: true));
candidate = ApplyGuardedFocusedHardRulePass(
candidate,
nodes,
current => ElkEdgePostProcessor.SeparateSharedLaneConflicts(current, nodes, minLineClearance, focusedEdgeIds));
candidate = ApplyGuardedFocusedHardRulePass(
candidate,
nodes,
current => ElkEdgePostProcessor.NormalizeBoundaryAngles(current, nodes));
candidate = ApplyGuardedFocusedHardRulePass(
candidate,
nodes,
current => ElkEdgePostProcessor.NormalizeSourceExitAngles(current, nodes));
return candidate;
}
}