elksharp stabilization
This commit is contained in:
@@ -69,6 +69,12 @@ internal static class ElkEdgePostProcessorSimplify
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!changed && TryApplyOrthogonalShortcut(cleaned, obstacles, excludeIds))
|
||||
{
|
||||
changed = true;
|
||||
anyChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove trailing duplicates (bend point == endpoint)
|
||||
@@ -110,8 +116,12 @@ internal static class ElkEdgePostProcessorSimplify
|
||||
|
||||
var graphMinY = nodes.Min(n => n.Y);
|
||||
var graphMaxY = nodes.Max(n => n.Y + n.Height);
|
||||
const double minMargin = 12d;
|
||||
const double laneGap = 8d;
|
||||
var serviceNodes = nodes.Where(n => n.Kind is not "Start" and not "End").ToArray();
|
||||
var minLineClearance = serviceNodes.Length > 0
|
||||
? Math.Min(serviceNodes.Average(n => n.Width), serviceNodes.Average(n => n.Height)) / 2d
|
||||
: 50d;
|
||||
var minMargin = Math.Max(12d, minLineClearance + 4d);
|
||||
var laneGap = Math.Max(8d, minLineClearance + 4d);
|
||||
|
||||
var outerEdges = new List<(int Index, double CorridorY, bool IsAbove)>();
|
||||
for (var i = 0; i < edges.Length; i++)
|
||||
@@ -250,6 +260,110 @@ internal static class ElkEdgePostProcessorSimplify
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool TryApplyOrthogonalShortcut(
|
||||
List<ElkPoint> points,
|
||||
(double L, double T, double R, double B, string Id)[] obstacles,
|
||||
HashSet<string> excludeIds)
|
||||
{
|
||||
if (points.Count < 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var startIndex = 0; startIndex < points.Count - 2; startIndex++)
|
||||
{
|
||||
for (var endIndex = points.Count - 1; endIndex >= startIndex + 2; endIndex--)
|
||||
{
|
||||
var start = points[startIndex];
|
||||
var end = points[endIndex];
|
||||
var existingLength = ComputeSubpathLength(points, startIndex, endIndex);
|
||||
|
||||
foreach (var shortcut in BuildShortcutCandidates(start, end))
|
||||
{
|
||||
if (shortcut.Count < 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ShortcutClearsObstacles(shortcut, obstacles, excludeIds))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var shortcutLength = ComputePathLength(shortcut);
|
||||
if (shortcutLength >= existingLength - 8d)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
points.RemoveRange(startIndex + 1, endIndex - startIndex - 1);
|
||||
if (shortcut.Count > 2)
|
||||
{
|
||||
points.InsertRange(startIndex + 1, shortcut.Skip(1).Take(shortcut.Count - 2));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static IReadOnlyList<List<ElkPoint>> BuildShortcutCandidates(ElkPoint start, ElkPoint end)
|
||||
{
|
||||
var candidates = new List<List<ElkPoint>>();
|
||||
if (Math.Abs(start.X - end.X) < 1d || Math.Abs(start.Y - end.Y) < 1d)
|
||||
{
|
||||
candidates.Add([start, end]);
|
||||
return candidates;
|
||||
}
|
||||
|
||||
var corner1 = new ElkPoint { X = start.X, Y = end.Y };
|
||||
var corner2 = new ElkPoint { X = end.X, Y = start.Y };
|
||||
candidates.Add([start, corner1, end]);
|
||||
candidates.Add([start, corner2, end]);
|
||||
return candidates;
|
||||
}
|
||||
|
||||
private static bool ShortcutClearsObstacles(
|
||||
IReadOnlyList<ElkPoint> shortcut,
|
||||
(double L, double T, double R, double B, string Id)[] obstacles,
|
||||
HashSet<string> excludeIds)
|
||||
{
|
||||
for (var i = 0; i < shortcut.Count - 1; i++)
|
||||
{
|
||||
if (!SegmentClearsObstacles(shortcut[i], shortcut[i + 1], obstacles, excludeIds))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static double ComputeSubpathLength(IReadOnlyList<ElkPoint> points, int startIndex, int endIndex)
|
||||
{
|
||||
var length = 0d;
|
||||
for (var i = startIndex; i < endIndex; i++)
|
||||
{
|
||||
length += ElkEdgeRoutingGeometry.ComputeSegmentLength(points[i], points[i + 1]);
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static double ComputePathLength(IReadOnlyList<ElkPoint> points)
|
||||
{
|
||||
var length = 0d;
|
||||
for (var i = 0; i < points.Count - 1; i++)
|
||||
{
|
||||
length += ElkEdgeRoutingGeometry.ComputeSegmentLength(points[i], points[i + 1]);
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static void NormalizeCorridorYValues(
|
||||
List<(int Index, double CorridorY, bool IsAbove)> outerEdges,
|
||||
ElkRoutedEdge[] edges,
|
||||
|
||||
Reference in New Issue
Block a user