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

128 lines
4.2 KiB
C#

using System.Collections.Concurrent;
using System.Diagnostics;
using System.Globalization;
namespace StellaOps.ElkSharp;
internal static partial class ElkEdgeRouterIterative
{
private static IEnumerable<string> ExpandWinningSolutionFocus(
IReadOnlyCollection<ElkRoutedEdge> edges,
IEnumerable<string> focusEdgeIds)
{
var edgesById = edges.ToDictionary(edge => edge.Id, StringComparer.Ordinal);
var expanded = new HashSet<string>(StringComparer.Ordinal);
foreach (var edgeId in focusEdgeIds)
{
if (!expanded.Add(edgeId) || !edgesById.TryGetValue(edgeId, out var edge))
{
continue;
}
foreach (var peer in edges)
{
if (string.Equals(peer.Id, edge.Id, StringComparison.Ordinal))
{
continue;
}
if (string.Equals(peer.SourceNodeId, edge.SourceNodeId, StringComparison.Ordinal)
|| string.Equals(peer.TargetNodeId, edge.TargetNodeId, StringComparison.Ordinal)
|| string.Equals(peer.SourceNodeId, edge.TargetNodeId, StringComparison.Ordinal)
|| string.Equals(peer.TargetNodeId, edge.SourceNodeId, StringComparison.Ordinal))
{
expanded.Add(peer.Id);
}
}
}
return expanded.OrderBy(edgeId => edgeId, StringComparer.Ordinal);
}
private static IEnumerable<string> ExpandSharedLanePolishFocus(
IReadOnlyCollection<ElkRoutedEdge> edges,
IReadOnlyCollection<ElkPositionedNode> nodes,
string focusEdgeId)
{
var edgesById = edges.ToDictionary(edge => edge.Id, StringComparer.Ordinal);
if (!edgesById.TryGetValue(focusEdgeId, out var focusEdge))
{
return [];
}
var focusedEdgeIds = new HashSet<string>(StringComparer.Ordinal)
{
focusEdgeId,
};
var sharedNodeIds = new HashSet<string>(StringComparer.Ordinal);
foreach (var (leftEdgeId, rightEdgeId) in ElkEdgeRoutingScoring.DetectSharedLaneConflicts(edges, nodes))
{
string partnerEdgeId;
if (string.Equals(leftEdgeId, focusEdgeId, StringComparison.Ordinal))
{
partnerEdgeId = rightEdgeId;
}
else if (string.Equals(rightEdgeId, focusEdgeId, StringComparison.Ordinal))
{
partnerEdgeId = leftEdgeId;
}
else
{
continue;
}
if (!edgesById.TryGetValue(partnerEdgeId, out var partnerEdge))
{
continue;
}
focusedEdgeIds.Add(partnerEdgeId);
CollectSharedConflictNodeIds(focusEdge, partnerEdge, sharedNodeIds);
}
if (sharedNodeIds.Count == 0)
{
return ExpandWinningSolutionFocus(edges, [focusEdgeId]);
}
foreach (var edge in edges)
{
if (focusedEdgeIds.Contains(edge.Id))
{
continue;
}
if ((edge.SourceNodeId is not null && sharedNodeIds.Contains(edge.SourceNodeId))
|| (edge.TargetNodeId is not null && sharedNodeIds.Contains(edge.TargetNodeId)))
{
focusedEdgeIds.Add(edge.Id);
}
}
return focusedEdgeIds.OrderBy(edgeId => edgeId, StringComparer.Ordinal);
}
private static void CollectSharedConflictNodeIds(
ElkRoutedEdge edge,
ElkRoutedEdge partner,
ISet<string> sharedNodeIds)
{
if (edge.SourceNodeId is not null
&& (string.Equals(edge.SourceNodeId, partner.SourceNodeId, StringComparison.Ordinal)
|| string.Equals(edge.SourceNodeId, partner.TargetNodeId, StringComparison.Ordinal)))
{
sharedNodeIds.Add(edge.SourceNodeId);
}
if (edge.TargetNodeId is not null
&& (string.Equals(edge.TargetNodeId, partner.SourceNodeId, StringComparison.Ordinal)
|| string.Equals(edge.TargetNodeId, partner.TargetNodeId, StringComparison.Ordinal)))
{
sharedNodeIds.Add(edge.TargetNodeId);
}
}
}