temp: raise diagnostic logs to Warning level for visibility
This commit is contained in:
@@ -232,10 +232,7 @@ public sealed class WorkflowRenderSvgRenderer
|
||||
edgeLabels));
|
||||
}
|
||||
|
||||
// Bridge gaps disabled: the white "cut" marks at edge crossings are
|
||||
// distracting at small rendering scales. Simple overlapping crossings
|
||||
// are cleaner and more readable.
|
||||
var bridgeGapsByPathIndex = new Dictionary<int, List<BridgeGap>>();
|
||||
var bridgeGapsByPathIndex = ResolveBridgeGaps(renderedPaths);
|
||||
for (var pathIndex = 0; pathIndex < renderedPaths.Count; pathIndex++)
|
||||
{
|
||||
if (bridgeGapsByPathIndex.TryGetValue(pathIndex, out var bridgeGaps))
|
||||
@@ -1856,15 +1853,40 @@ public sealed class WorkflowRenderSvgRenderer
|
||||
|
||||
for (var pathIndex = 1; pathIndex < paths.Count; pathIndex++)
|
||||
{
|
||||
var overSegments = EnumerateSegments(paths[pathIndex].Points).ToArray();
|
||||
var overPath = paths[pathIndex];
|
||||
|
||||
// Collector trunks (highway/endSink merged paths) should not
|
||||
// participate in bridge gap detection — they are thick grouping
|
||||
// lines, not individual edge crossings.
|
||||
if (overPath.IsCollector)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var overSegments = EnumerateEffectiveSegments(overPath.Points, 40d);
|
||||
for (var underPathIndex = 0; underPathIndex < pathIndex; underPathIndex++)
|
||||
{
|
||||
var underSegments = EnumerateSegments(paths[underPathIndex].Points).ToArray();
|
||||
var underPath = paths[underPathIndex];
|
||||
|
||||
// Skip collector trunks as under-paths too.
|
||||
if (underPath.IsCollector)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip crossings between edges in the same highway/endSink
|
||||
// group — they share a collector and should not gap each other.
|
||||
if (overPath.GroupId != null && overPath.GroupId == underPath.GroupId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var underSegments = EnumerateEffectiveSegments(underPath.Points, 40d);
|
||||
foreach (var underSegment in underSegments)
|
||||
{
|
||||
foreach (var overSegment in overSegments)
|
||||
{
|
||||
if (!TryCreateBridgeGap(underSegment, overSegment, paths[underPathIndex].StrokeWidth, out var bridgeGap))
|
||||
if (!TryCreateBridgeGap(underSegment, overSegment, underPath.StrokeWidth, out var bridgeGap))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -1890,25 +1912,129 @@ public sealed class WorkflowRenderSvgRenderer
|
||||
return bridgeGapsByPathIndex;
|
||||
}
|
||||
|
||||
private static IEnumerable<RenderedSegment> EnumerateSegments(IReadOnlyList<WorkflowRenderPoint> points)
|
||||
/// <summary>
|
||||
/// Returns only the straight portions of the rendered edge path — after
|
||||
/// the same preprocessing (backtrack/jog removal) and corner pull-back
|
||||
/// that <see cref="BuildRoundedEdgePath"/> applies. This ensures bridge
|
||||
/// gap detection operates on what the user actually sees, not the raw
|
||||
/// waypoints.
|
||||
/// </summary>
|
||||
private static RenderedSegment[] EnumerateEffectiveSegments(
|
||||
IReadOnlyList<WorkflowRenderPoint> points,
|
||||
double cornerRadius)
|
||||
{
|
||||
for (var index = 0; index < points.Count - 1; index++)
|
||||
if (points.Count < 2)
|
||||
{
|
||||
var start = points[index];
|
||||
var end = points[index + 1];
|
||||
if (Math.Abs(start.X - end.X) <= 0.01d && Math.Abs(start.Y - end.Y) <= 0.01d)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var isHorizontal = Math.Abs(start.Y - end.Y) <= 0.01d;
|
||||
if (!isHorizontal && Math.Abs(start.X - end.X) > 0.01d)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return new RenderedSegment(start, end, isHorizontal);
|
||||
return [];
|
||||
}
|
||||
|
||||
// --- Step 1: same preprocessing as BuildRoundedEdgePath ---
|
||||
|
||||
var pts = points.ToList();
|
||||
|
||||
// Backtrack removal (same axis, direction reversal).
|
||||
for (var i = 1; i < pts.Count - 1; i++)
|
||||
{
|
||||
var prev = pts[i - 1];
|
||||
var curr = pts[i];
|
||||
var next = pts[i + 1];
|
||||
var sameX = Math.Abs(prev.X - curr.X) < 2d && Math.Abs(curr.X - next.X) < 2d;
|
||||
var sameY = Math.Abs(prev.Y - curr.Y) < 2d && Math.Abs(curr.Y - next.Y) < 2d;
|
||||
if (sameX && (curr.Y - prev.Y) * (next.Y - curr.Y) < 0d)
|
||||
{
|
||||
if (i + 1 == pts.Count - 1) pts.RemoveRange(i, 2); else pts.RemoveAt(i);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sameY && (curr.X - prev.X) * (next.X - curr.X) < 0d)
|
||||
{
|
||||
if (i + 1 == pts.Count - 1) pts.RemoveRange(i, 2); else pts.RemoveAt(i);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Tiny jog removal (<30px) with axis snap.
|
||||
var cleaned = new List<WorkflowRenderPoint> { pts[0] };
|
||||
for (var i = 1; i < pts.Count; i++)
|
||||
{
|
||||
var prev = cleaned[^1];
|
||||
var curr = pts[i];
|
||||
var dxIn = Math.Abs(curr.X - prev.X);
|
||||
var dyIn = Math.Abs(curr.Y - prev.Y);
|
||||
if (dxIn + dyIn < 30d && i < pts.Count - 1)
|
||||
{
|
||||
var next = pts[i + 1];
|
||||
pts[i + 1] = dxIn < dyIn
|
||||
? new WorkflowRenderPoint { X = next.X, Y = prev.Y }
|
||||
: new WorkflowRenderPoint { X = prev.X, Y = next.Y };
|
||||
continue;
|
||||
}
|
||||
|
||||
cleaned.Add(curr);
|
||||
}
|
||||
|
||||
if (cleaned.Count < 2)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
// --- Step 2: compute effective radius at each interior point ---
|
||||
|
||||
var radii = new double[cleaned.Count];
|
||||
for (var i = 1; i < cleaned.Count - 1; i++)
|
||||
{
|
||||
var prev = cleaned[i - 1];
|
||||
var curr = cleaned[i];
|
||||
var next = cleaned[i + 1];
|
||||
var lenIn = Math.Sqrt(Sqr(curr.X - prev.X) + Sqr(curr.Y - prev.Y));
|
||||
var lenOut = Math.Sqrt(Sqr(next.X - curr.X) + Sqr(next.Y - curr.Y));
|
||||
var r = Math.Min(cornerRadius, Math.Min(lenIn / 3d, lenOut / 3d));
|
||||
if (lenIn < 30d && lenOut < 30d) r = 0d;
|
||||
if (r < 0.5d || lenIn < 1d || lenOut < 1d) r = 0d;
|
||||
radii[i] = r;
|
||||
}
|
||||
|
||||
// --- Step 3: shrink each segment by the corner radii at its ends ---
|
||||
|
||||
var segments = new List<RenderedSegment>();
|
||||
for (var i = 0; i < cleaned.Count - 1; i++)
|
||||
{
|
||||
var a = cleaned[i];
|
||||
var b = cleaned[i + 1];
|
||||
var dx = b.X - a.X;
|
||||
var dy = b.Y - a.Y;
|
||||
var len = Math.Sqrt(dx * dx + dy * dy);
|
||||
if (len < 1d) continue;
|
||||
|
||||
var startShrink = radii[i];
|
||||
var endShrink = radii[i + 1];
|
||||
if (startShrink + endShrink >= len) continue;
|
||||
|
||||
var effStart = new WorkflowRenderPoint
|
||||
{
|
||||
X = a.X + dx / len * startShrink,
|
||||
Y = a.Y + dy / len * startShrink,
|
||||
};
|
||||
var effEnd = new WorkflowRenderPoint
|
||||
{
|
||||
X = b.X - dx / len * endShrink,
|
||||
Y = b.Y - dy / len * endShrink,
|
||||
};
|
||||
|
||||
var isHorizontal = Math.Abs(effStart.Y - effEnd.Y) <= 0.5d;
|
||||
if (!isHorizontal && Math.Abs(effStart.X - effEnd.X) > 0.5d)
|
||||
{
|
||||
continue; // diagonal — skip
|
||||
}
|
||||
|
||||
segments.Add(new RenderedSegment(effStart, effEnd, isHorizontal));
|
||||
}
|
||||
|
||||
return segments.ToArray();
|
||||
|
||||
static double Sqr(double v) => v * v;
|
||||
}
|
||||
|
||||
private static bool TryCreateBridgeGap(
|
||||
@@ -1940,19 +2066,19 @@ public sealed class WorkflowRenderSvgRenderer
|
||||
|
||||
if (underSegment.IsHorizontal)
|
||||
{
|
||||
var gapHalfLength = Math.Max(5d, underStrokeWidth * 2.6d);
|
||||
var gapHalfLength = Math.Max(3d, underStrokeWidth * 1.5d);
|
||||
bridgeGap = new BridgeGap(
|
||||
new WorkflowRenderPoint { X = intersectionX - gapHalfLength, Y = intersectionY },
|
||||
new WorkflowRenderPoint { X = intersectionX + gapHalfLength, Y = intersectionY },
|
||||
underStrokeWidth + 4d);
|
||||
underStrokeWidth + 2d);
|
||||
return true;
|
||||
}
|
||||
|
||||
var verticalGapHalfLength = Math.Max(5d, underStrokeWidth * 2.6d);
|
||||
var verticalGapHalfLength = Math.Max(3d, underStrokeWidth * 1.5d);
|
||||
bridgeGap = new BridgeGap(
|
||||
new WorkflowRenderPoint { X = intersectionX, Y = intersectionY - verticalGapHalfLength },
|
||||
new WorkflowRenderPoint { X = intersectionX, Y = intersectionY + verticalGapHalfLength },
|
||||
underStrokeWidth + 4d);
|
||||
underStrokeWidth + 2d);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2100,12 +2226,6 @@ public sealed class WorkflowRenderSvgRenderer
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG: log cleaned points for edge/4 area
|
||||
{
|
||||
var dbg = string.Join(" -> ", mutablePoints.Select(p => $"({p.X:F0},{p.Y:F0})"));
|
||||
System.IO.File.WriteAllText(@"C:\dev\New folder\git.stella-ops.org\edge4-debug.txt",
|
||||
$"After backtrack removal ({mutablePoints.Count} pts): {dbg}\n");
|
||||
}
|
||||
|
||||
// Remove tiny jog segments (< 30px) that create visible zigzag steps.
|
||||
var cleaned = new List<WorkflowRenderPoint> { mutablePoints[0] };
|
||||
|
||||
Reference in New Issue
Block a user