temp: raise diagnostic logs to Warning level for visibility

This commit is contained in:
master
2026-04-02 19:19:35 +03:00
parent 9ae5936f88
commit da628531f8
32 changed files with 5940 additions and 43 deletions

View File

@@ -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] };