Refactor ElkSharp hybrid routing and document speed path
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
|
||||
namespace StellaOps.ElkSharp;
|
||||
|
||||
internal static partial class ElkEdgeRouterIterative
|
||||
{
|
||||
private static RouteAllEdgesResult? RouteAllEdges(
|
||||
ElkRoutedEdge[] existingEdges,
|
||||
ElkPositionedNode[] nodes,
|
||||
double baseObstacleMargin,
|
||||
RoutingStrategy strategy,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var routedEdges = new ElkRoutedEdge[existingEdges.Length];
|
||||
Array.Copy(existingEdges, routedEdges, existingEdges.Length);
|
||||
|
||||
var obstacleMargin = Math.Max(
|
||||
baseObstacleMargin,
|
||||
Math.Max(strategy.MinLineClearance + 4d, strategy.RoutingParams.Margin));
|
||||
var obstacles = BuildObstacles(nodes, obstacleMargin);
|
||||
var graphMinY = nodes.Length > 0 ? nodes.Min(n => n.Y) : 0d;
|
||||
var graphMaxY = nodes.Length > 0 ? nodes.Max(n => n.Y + n.Height) : 0d;
|
||||
var nodesById = nodes.ToDictionary(n => n.Id, StringComparer.Ordinal);
|
||||
var routedEdgeCount = 0;
|
||||
var skippedEdgeCount = 0;
|
||||
var routedSectionCount = 0;
|
||||
var fallbackSectionCount = 0;
|
||||
|
||||
// Spread endpoints: distribute edges arriving at the same target side
|
||||
var spreadEndpoints = SpreadTargetEndpoints(existingEdges, nodesById, graphMinY, graphMaxY, strategy.MinLineClearance);
|
||||
|
||||
var softObstacles = new List<OrthogonalSoftObstacle>();
|
||||
|
||||
foreach (var edgeIndex in strategy.EdgeOrder)
|
||||
{
|
||||
if (edgeIndex < 0 || edgeIndex >= existingEdges.Length)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var edge = existingEdges[edgeIndex];
|
||||
|
||||
// Skip edges that need special routing (backward, ports, corridors, collectors)
|
||||
if (!CanRepairEdgeLocally(edge, nodes, graphMinY, graphMaxY))
|
||||
{
|
||||
skippedEdgeCount++;
|
||||
foreach (var segment in ElkEdgeRoutingGeometry.FlattenSegments(edge))
|
||||
{
|
||||
softObstacles.Add(new OrthogonalSoftObstacle(segment.Start, segment.End));
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var newSections = new List<ElkEdgeSection>(edge.Sections.Count);
|
||||
|
||||
foreach (var section in edge.Sections)
|
||||
{
|
||||
var endPoint = spreadEndpoints.TryGetValue(edge.Id, out var spread)
|
||||
? spread
|
||||
: section.EndPoint;
|
||||
var (startPoint, adjustedEndPoint) = ResolveRoutingEndpoints(
|
||||
section.StartPoint,
|
||||
endPoint,
|
||||
edge.SourceNodeId,
|
||||
edge.TargetNodeId,
|
||||
nodesById);
|
||||
|
||||
var rerouted = ElkEdgeRouterAStar8Dir.Route(
|
||||
startPoint,
|
||||
adjustedEndPoint,
|
||||
obstacles,
|
||||
edge.SourceNodeId ?? "",
|
||||
edge.TargetNodeId ?? "",
|
||||
strategy.RoutingParams,
|
||||
softObstacles,
|
||||
cancellationToken);
|
||||
|
||||
if (rerouted is not null && rerouted.Count >= 2)
|
||||
{
|
||||
routedSectionCount++;
|
||||
newSections.Add(new ElkEdgeSection
|
||||
{
|
||||
StartPoint = rerouted[0],
|
||||
EndPoint = rerouted[^1],
|
||||
BendPoints = rerouted.Skip(1).Take(rerouted.Count - 2).ToArray(),
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
fallbackSectionCount++;
|
||||
newSections.Add(section);
|
||||
}
|
||||
}
|
||||
|
||||
routedEdgeCount++;
|
||||
|
||||
routedEdges[edgeIndex] = new ElkRoutedEdge
|
||||
{
|
||||
Id = edge.Id,
|
||||
SourceNodeId = edge.SourceNodeId,
|
||||
TargetNodeId = edge.TargetNodeId,
|
||||
SourcePortId = edge.SourcePortId,
|
||||
TargetPortId = edge.TargetPortId,
|
||||
Kind = edge.Kind,
|
||||
Label = edge.Label,
|
||||
Sections = newSections,
|
||||
};
|
||||
|
||||
foreach (var segment in ElkEdgeRoutingGeometry.FlattenSegments(routedEdges[edgeIndex]))
|
||||
{
|
||||
softObstacles.Add(new OrthogonalSoftObstacle(segment.Start, segment.End));
|
||||
}
|
||||
}
|
||||
|
||||
return new RouteAllEdgesResult(
|
||||
routedEdges,
|
||||
new ElkIterativeRouteDiagnostics
|
||||
{
|
||||
Mode = "full-strategy",
|
||||
TotalEdges = existingEdges.Length,
|
||||
RoutedEdges = routedEdgeCount,
|
||||
SkippedEdges = skippedEdgeCount,
|
||||
RoutedSections = routedSectionCount,
|
||||
FallbackSections = fallbackSectionCount,
|
||||
SoftObstacleSegments = softObstacles.Count,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user