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,170 @@
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Globalization;
namespace StellaOps.ElkSharp;
internal static partial class ElkEdgeRouterIterative
{
private static ElkRoutedEdge[] ApplyLateBoundarySlotRestabilization(
ElkRoutedEdge[] edges,
ElkPositionedNode[] nodes,
double minLineClearance,
IReadOnlyCollection<string> focusEdgeIds)
{
if (focusEdgeIds.Count == 0)
{
return edges;
}
var candidate = ElkEdgePostProcessor.SeparateMixedNodeFaceLaneConflicts(
edges,
nodes,
minLineClearance,
focusEdgeIds);
ElkLayoutDiagnostics.LogProgress("Late boundary-slot restabilization after mixed-face separation");
candidate = ElkEdgePostProcessor.SeparateRepeatCollectorLocalLaneConflicts(
candidate,
nodes,
minLineClearance,
focusEdgeIds);
ElkLayoutDiagnostics.LogProgress("Late boundary-slot restabilization after collector separation");
candidate = ElkEdgePostProcessor.SpreadSourceDepartureJoins(
candidate,
nodes,
minLineClearance,
focusEdgeIds);
ElkLayoutDiagnostics.LogProgress("Late boundary-slot restabilization after source-join spread");
candidate = ElkEdgePostProcessor.SeparateSharedLaneConflicts(
candidate,
nodes,
minLineClearance,
focusEdgeIds);
ElkLayoutDiagnostics.LogProgress("Late boundary-slot restabilization after shared-lane separation");
candidate = ElkEdgePostProcessor.RepairBoundaryAnglesAndTargetApproaches(
candidate,
nodes,
minLineClearance,
focusEdgeIds);
ElkLayoutDiagnostics.LogProgress("Late boundary-slot restabilization after boundary/target repair");
candidate = ElkEdgePostProcessor.SpreadTargetApproachJoins(
candidate,
nodes,
minLineClearance,
focusEdgeIds);
ElkLayoutDiagnostics.LogProgress("Late boundary-slot restabilization after target-join spread");
candidate = ElkEdgePostProcessor.SpreadRectTargetApproachFeederBands(
candidate,
nodes,
minLineClearance,
focusEdgeIds);
ElkLayoutDiagnostics.LogProgress("Late boundary-slot restabilization after feeder-band spread");
candidate = ElkEdgePostProcessor.FinalizeGatewayBoundaryGeometry(candidate, nodes, focusEdgeIds);
ElkLayoutDiagnostics.LogProgress("Late boundary-slot restabilization after gateway finalize");
candidate = ElkEdgePostProcessor.NormalizeBoundaryAngles(candidate, nodes);
candidate = ElkEdgePostProcessor.NormalizeSourceExitAngles(candidate, nodes);
candidate = ElkEdgePostProcessor.SnapBoundarySlotAssignments(
candidate,
nodes,
minLineClearance,
focusEdgeIds,
enforceAllNodeEndpoints: true);
ElkLayoutDiagnostics.LogProgress("Late boundary-slot restabilization after first normalization snap");
candidate = ElkEdgePostProcessor.SeparateRepeatCollectorLocalLaneConflicts(
candidate,
nodes,
minLineClearance,
focusEdgeIds);
ElkLayoutDiagnostics.LogProgress("Late boundary-slot restabilization after second collector separation");
candidate = ElkEdgePostProcessor.SpreadSourceDepartureJoins(
candidate,
nodes,
minLineClearance,
focusEdgeIds);
ElkLayoutDiagnostics.LogProgress("Late boundary-slot restabilization after second source-join spread");
candidate = ElkEdgePostProcessor.SeparateMixedNodeFaceLaneConflicts(
candidate,
nodes,
minLineClearance,
focusEdgeIds);
ElkLayoutDiagnostics.LogProgress("Late boundary-slot restabilization after second mixed-face separation");
candidate = ElkEdgePostProcessor.SeparateSharedLaneConflicts(
candidate,
nodes,
minLineClearance,
focusEdgeIds);
ElkLayoutDiagnostics.LogProgress("Late boundary-slot restabilization after second shared-lane separation");
candidate = ElkEdgePostProcessor.RepairBoundaryAnglesAndTargetApproaches(
candidate,
nodes,
minLineClearance,
focusEdgeIds);
ElkLayoutDiagnostics.LogProgress("Late boundary-slot restabilization after second boundary/target repair");
candidate = ElkEdgePostProcessor.SpreadTargetApproachJoins(
candidate,
nodes,
minLineClearance,
focusEdgeIds);
ElkLayoutDiagnostics.LogProgress("Late boundary-slot restabilization after second target-join spread");
candidate = ElkEdgePostProcessor.SpreadRectTargetApproachFeederBands(
candidate,
nodes,
minLineClearance,
focusEdgeIds);
ElkLayoutDiagnostics.LogProgress("Late boundary-slot restabilization after second feeder-band spread");
candidate = ElkEdgePostProcessor.FinalizeGatewayBoundaryGeometry(candidate, nodes, focusEdgeIds);
ElkLayoutDiagnostics.LogProgress("Late boundary-slot restabilization after second gateway finalize");
candidate = ApplyPostSlotDetourClosure(candidate, nodes, minLineClearance, focusEdgeIds);
ElkLayoutDiagnostics.LogProgress("Late boundary-slot restabilization after detour closure");
candidate = ElkEdgePostProcessor.NormalizeBoundaryAngles(candidate, nodes);
candidate = ElkEdgePostProcessor.NormalizeSourceExitAngles(candidate, nodes);
candidate = ElkEdgePostProcessor.SnapBoundarySlotAssignments(
candidate,
nodes,
minLineClearance,
focusEdgeIds,
enforceAllNodeEndpoints: true);
ElkLayoutDiagnostics.LogProgress("Late boundary-slot restabilization complete");
return ChoosePreferredBoundarySlotRepairLayout(edges, candidate, nodes);
}
private static ElkRoutedEdge[] ApplyLateFocusedBoundarySlotClosure(
ElkRoutedEdge[] edges,
ElkPositionedNode[] nodes,
ElkLayoutDirection direction,
double minLineClearance,
IReadOnlyCollection<string> focusEdgeIds,
IReadOnlyCollection<string>? restrictedEdgeIds)
{
var candidate = ChoosePreferredHardRuleLayout(
edges,
ApplyAggressiveSharedLaneClosure(edges, nodes, direction, minLineClearance, focusEdgeIds),
nodes);
candidate = ChoosePreferredBoundarySlotRepairLayout(
candidate,
ElkEdgePostProcessor.SnapBoundarySlotAssignments(
candidate,
nodes,
minLineClearance,
restrictedEdgeIds,
enforceAllNodeEndpoints: true),
nodes);
candidate = ChoosePreferredBoundarySlotRepairLayout(
candidate,
CloseRemainingTerminalViolations(candidate, nodes, direction, minLineClearance, restrictedEdgeIds),
nodes);
candidate = ApplyLateBoundarySlotRestabilization(candidate, nodes, minLineClearance, focusEdgeIds);
candidate = ChoosePreferredBoundarySlotRepairLayout(
candidate,
ElkEdgePostProcessor.SnapBoundarySlotAssignments(
candidate,
nodes,
minLineClearance,
restrictedEdgeIds,
enforceAllNodeEndpoints: true),
nodes);
return candidate;
}
}