Files
git.stella-ops.org/src/__Libraries/StellaOps.ElkSharp/ElkEdgeRouterIterative.WinnerRefinement.FinalRestabilized.cs

214 lines
8.2 KiB
C#

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;
}
}