Refactor ElkSharp hybrid routing and document speed path
This commit is contained in:
@@ -0,0 +1,213 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
|
||||
namespace StellaOps.ElkSharp;
|
||||
|
||||
internal static partial class ElkEdgeRouterIterative
|
||||
{
|
||||
internal static ElkRoutedEdge[] BuildFinalRestabilizedCandidate(
|
||||
ElkRoutedEdge[] edges,
|
||||
ElkPositionedNode[] nodes,
|
||||
ElkLayoutDirection direction,
|
||||
double minLineClearance,
|
||||
IReadOnlyCollection<string>? restrictedEdgeIds = null)
|
||||
{
|
||||
var focusEdgeIds = restrictedEdgeIds?.Count > 0
|
||||
? restrictedEdgeIds
|
||||
: edges
|
||||
.Select(edge => edge.Id)
|
||||
.OrderBy(edgeId => edgeId, StringComparer.Ordinal)
|
||||
.ToArray();
|
||||
var focusEdgeSet = focusEdgeIds.ToHashSet(StringComparer.Ordinal);
|
||||
|
||||
var candidate = ChoosePreferredHardRuleLayout(
|
||||
edges,
|
||||
CloseRemainingTerminalViolations(edges, nodes, direction, minLineClearance, restrictedEdgeIds),
|
||||
nodes);
|
||||
if (focusEdgeIds.Count > 0)
|
||||
{
|
||||
candidate = ChoosePreferredHardRuleLayout(
|
||||
candidate,
|
||||
ApplyAggressiveSharedLaneClosure(
|
||||
candidate,
|
||||
nodes,
|
||||
direction,
|
||||
minLineClearance,
|
||||
focusEdgeIds),
|
||||
nodes);
|
||||
}
|
||||
|
||||
candidate = BuildFinalBoundarySlotCandidate(
|
||||
candidate,
|
||||
nodes,
|
||||
direction,
|
||||
minLineClearance,
|
||||
restrictedEdgeIds,
|
||||
allowLateRestabilizedClosure: false);
|
||||
if (focusEdgeIds.Count > 0)
|
||||
{
|
||||
candidate = ChoosePreferredHardRuleLayout(
|
||||
candidate,
|
||||
ApplyAggressiveSharedLaneClosure(
|
||||
candidate,
|
||||
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);
|
||||
if (focusEdgeIds.Count > 0)
|
||||
{
|
||||
var lateHardRuleCandidate = ApplyAggressiveSharedLaneClosure(
|
||||
candidate,
|
||||
nodes,
|
||||
direction,
|
||||
minLineClearance,
|
||||
focusEdgeIds);
|
||||
lateHardRuleCandidate = CloseRemainingTerminalViolations(
|
||||
lateHardRuleCandidate,
|
||||
nodes,
|
||||
direction,
|
||||
minLineClearance,
|
||||
focusEdgeIds);
|
||||
candidate = ChoosePreferredHardRuleLayout(candidate, lateHardRuleCandidate, nodes);
|
||||
|
||||
var remainingBadAngles = new Dictionary<string, int>(StringComparer.Ordinal);
|
||||
ElkEdgeRoutingScoring.CountBadBoundaryAngles(candidate, nodes, remainingBadAngles, 10);
|
||||
var remainingTerminalFocus = ExpandWinningSolutionFocus(
|
||||
candidate,
|
||||
remainingBadAngles.Keys.Where(focusEdgeSet.Contains))
|
||||
.Where(focusEdgeSet.Contains)
|
||||
.OrderBy(edgeId => edgeId, StringComparer.Ordinal)
|
||||
.ToArray();
|
||||
if (remainingTerminalFocus.Length > 0)
|
||||
{
|
||||
var terminalFocus = (IReadOnlyCollection<string>)remainingTerminalFocus;
|
||||
var lateTerminalCandidate = ElkEdgePostProcessor.RepairBoundaryAnglesAndTargetApproaches(
|
||||
candidate,
|
||||
nodes,
|
||||
minLineClearance,
|
||||
terminalFocus);
|
||||
lateTerminalCandidate = BuildFinalBoundarySlotCandidate(
|
||||
lateTerminalCandidate,
|
||||
nodes,
|
||||
direction,
|
||||
minLineClearance,
|
||||
terminalFocus,
|
||||
allowLateRestabilizedClosure: false);
|
||||
lateTerminalCandidate = CloseRemainingTerminalViolations(
|
||||
lateTerminalCandidate,
|
||||
nodes,
|
||||
direction,
|
||||
minLineClearance,
|
||||
terminalFocus);
|
||||
candidate = ChoosePreferredBoundarySlotRepairLayout(candidate, lateTerminalCandidate, nodes);
|
||||
}
|
||||
}
|
||||
|
||||
candidate = ChoosePreferredBoundarySlotRepairLayout(
|
||||
candidate,
|
||||
ElkEdgePostProcessor.SnapBoundarySlotAssignments(
|
||||
candidate,
|
||||
nodes,
|
||||
minLineClearance,
|
||||
restrictedEdgeIds,
|
||||
enforceAllNodeEndpoints: true),
|
||||
nodes);
|
||||
candidate = ChoosePreferredBoundarySlotRepairLayout(
|
||||
candidate,
|
||||
ApplyPostSlotDetourClosure(candidate, nodes, minLineClearance, restrictedEdgeIds),
|
||||
nodes);
|
||||
candidate = ChoosePreferredBoundarySlotRepairLayout(
|
||||
candidate,
|
||||
ElkEdgePostProcessor.SnapBoundarySlotAssignments(
|
||||
candidate,
|
||||
nodes,
|
||||
minLineClearance,
|
||||
restrictedEdgeIds,
|
||||
enforceAllNodeEndpoints: true),
|
||||
nodes);
|
||||
candidate = ApplyLateBoundarySlotRestabilization(
|
||||
candidate,
|
||||
nodes,
|
||||
minLineClearance,
|
||||
focusEdgeIds);
|
||||
candidate = ChoosePreferredBoundarySlotRepairLayout(
|
||||
candidate,
|
||||
ElkEdgePostProcessor.SnapBoundarySlotAssignments(
|
||||
candidate,
|
||||
nodes,
|
||||
minLineClearance,
|
||||
restrictedEdgeIds,
|
||||
enforceAllNodeEndpoints: true),
|
||||
nodes);
|
||||
|
||||
if (focusEdgeIds.Count > 0)
|
||||
{
|
||||
var finalSharedLaneCandidate = ElkEdgePostProcessor.SeparateSharedLaneConflicts(
|
||||
candidate,
|
||||
nodes,
|
||||
minLineClearance,
|
||||
focusEdgeIds);
|
||||
candidate = ChoosePreferredSharedLanePolishLayout(candidate, finalSharedLaneCandidate, nodes);
|
||||
|
||||
var finalSourceJoinCandidate = ElkEdgePostProcessor.SpreadSourceDepartureJoins(
|
||||
finalSharedLaneCandidate,
|
||||
nodes,
|
||||
minLineClearance,
|
||||
focusEdgeIds);
|
||||
candidate = ChoosePreferredSharedLanePolishLayout(candidate, finalSourceJoinCandidate, nodes);
|
||||
|
||||
var finalTargetJoinCandidate = ElkEdgePostProcessor.SpreadTargetApproachJoins(
|
||||
finalSourceJoinCandidate,
|
||||
nodes,
|
||||
minLineClearance,
|
||||
focusEdgeIds,
|
||||
forceOutwardAxisSpacing: true);
|
||||
candidate = ChoosePreferredSharedLanePolishLayout(candidate, finalTargetJoinCandidate, nodes);
|
||||
|
||||
var finalAggressiveCandidate = ApplyAggressiveSharedLaneClosure(
|
||||
candidate,
|
||||
nodes,
|
||||
direction,
|
||||
minLineClearance,
|
||||
focusEdgeIds);
|
||||
candidate = ChoosePreferredSharedLanePolishLayout(candidate, finalAggressiveCandidate, nodes);
|
||||
|
||||
var forcedFinalSharedLaneCandidate = ElkEdgePostProcessor.SeparateSharedLaneConflicts(
|
||||
candidate,
|
||||
nodes,
|
||||
minLineClearance,
|
||||
focusEdgeIds);
|
||||
var baselineSharedLaneViolations = ElkEdgeRoutingScoring.CountSharedLaneViolations(candidate, nodes);
|
||||
var forcedSharedLaneViolations = ElkEdgeRoutingScoring.CountSharedLaneViolations(forcedFinalSharedLaneCandidate, nodes);
|
||||
if (forcedSharedLaneViolations < baselineSharedLaneViolations)
|
||||
{
|
||||
var baselineScore = ElkEdgeRoutingScoring.ComputeScore(candidate, nodes);
|
||||
var forcedScore = ElkEdgeRoutingScoring.ComputeScore(forcedFinalSharedLaneCandidate, nodes);
|
||||
if (forcedScore.NodeCrossings <= baselineScore.NodeCrossings)
|
||||
{
|
||||
candidate = forcedFinalSharedLaneCandidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user