128 lines
4.2 KiB
C#
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);
|
|
}
|
|
}
|
|
|
|
}
|