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

147 lines
6.4 KiB
C#

using System.Collections.Concurrent;
using System.Diagnostics;
using System.Globalization;
namespace StellaOps.ElkSharp;
internal static partial class ElkEdgeRouterIterative
{
private static CandidateSolution ApplyFinalSharedLanePolish(
CandidateSolution solution,
ElkPositionedNode[] nodes,
ElkLayoutDirection direction,
double minLineClearance,
bool preferLeanTerminalCleanup = false)
{
var current = solution;
if (current.RetryState.SharedLaneViolations <= 0)
{
return current;
}
var maxRounds = preferLeanTerminalCleanup ? 1 : 3;
for (var round = 0; round < maxRounds; round++)
{
var sharedLaneSeverity = new Dictionary<string, int>(StringComparer.Ordinal);
ElkEdgeRoutingScoring.CountSharedLaneViolations(current.Edges, nodes, sharedLaneSeverity, 10);
if (sharedLaneSeverity.Count == 0)
{
break;
}
var improved = false;
foreach (var edgeId in sharedLaneSeverity
.OrderByDescending(pair => pair.Value)
.ThenBy(pair => pair.Key, StringComparer.Ordinal)
.Select(pair => pair.Key))
{
var focusEdgeIds = ExpandSharedLanePolishFocus(current.Edges, nodes, edgeId).ToArray();
if (focusEdgeIds.Length == 0)
{
continue;
}
var directCandidate = ElkEdgePostProcessor.SeparateSharedLaneConflicts(
current.Edges,
nodes,
minLineClearance,
focusEdgeIds);
var directClosureCandidate = preferLeanTerminalCleanup
? ApplyHybridTerminalRuleCleanupRound(
directCandidate,
nodes,
direction,
minLineClearance,
focusEdgeIds)
: CloseRemainingTerminalViolations(
directCandidate,
nodes,
direction,
minLineClearance,
focusEdgeIds);
var closureCandidate = preferLeanTerminalCleanup
? ApplyHybridTerminalRuleCleanupRound(
current.Edges,
nodes,
direction,
minLineClearance,
focusEdgeIds)
: CloseRemainingTerminalViolations(
current.Edges,
nodes,
direction,
minLineClearance,
focusEdgeIds);
var aggressiveCandidate = ApplyAggressiveSharedLaneClosure(
current.Edges,
nodes,
direction,
minLineClearance,
focusEdgeIds);
var directRetryState = BuildRetryState(
ElkEdgeRoutingScoring.ComputeScore(directCandidate, nodes),
HighwayProcessingEnabled
? ElkEdgeRouterHighway.DetectRemainingBrokenHighways(directCandidate, nodes).Count
: 0);
var directClosureRetryState = BuildRetryState(
ElkEdgeRoutingScoring.ComputeScore(directClosureCandidate, nodes),
HighwayProcessingEnabled
? ElkEdgeRouterHighway.DetectRemainingBrokenHighways(directClosureCandidate, nodes).Count
: 0);
var closureRetryState = BuildRetryState(
ElkEdgeRoutingScoring.ComputeScore(closureCandidate, nodes),
HighwayProcessingEnabled
? ElkEdgeRouterHighway.DetectRemainingBrokenHighways(closureCandidate, nodes).Count
: 0);
var aggressiveRetryState = BuildRetryState(
ElkEdgeRoutingScoring.ComputeScore(aggressiveCandidate, nodes),
HighwayProcessingEnabled
? ElkEdgeRouterHighway.DetectRemainingBrokenHighways(aggressiveCandidate, nodes).Count
: 0);
ElkLayoutDiagnostics.LogProgress(
$"Winner shared-lane focus edge={edgeId} focus=[{string.Join(", ", focusEdgeIds)}] " +
$"direct={DescribeRetryState(directRetryState)} " +
$"direct-closure={DescribeRetryState(directClosureRetryState)} " +
$"closure={DescribeRetryState(closureRetryState)} " +
$"aggressive={DescribeRetryState(aggressiveRetryState)}");
var candidateEdges = ChoosePreferredSharedLanePolishLayout(directCandidate, directClosureCandidate, nodes);
candidateEdges = ChoosePreferredSharedLanePolishLayout(candidateEdges, closureCandidate, nodes);
candidateEdges = ChoosePreferredSharedLanePolishLayout(candidateEdges, aggressiveCandidate, nodes);
candidateEdges = ChoosePreferredSharedLanePolishLayout(current.Edges, candidateEdges, nodes);
var candidateScore = ElkEdgeRoutingScoring.ComputeScore(candidateEdges, nodes);
var candidateRetryState = BuildRetryState(
candidateScore,
HighwayProcessingEnabled
? ElkEdgeRouterHighway.DetectRemainingBrokenHighways(candidateEdges, nodes).Count
: 0);
var improvedSharedLanes = candidateRetryState.SharedLaneViolations < current.RetryState.SharedLaneViolations;
if (HasBlockingSharedLanePromotionRegression(candidateRetryState, current.RetryState)
|| (!improvedSharedLanes
&& !IsBetterCandidate(candidateScore, candidateRetryState, current.Score, current.RetryState)))
{
continue;
}
current = current with
{
Score = candidateScore,
RetryState = candidateRetryState,
Edges = candidateEdges,
};
improved = true;
break;
}
if (!improved)
{
break;
}
}
return current;
}
}