Files
Rozpisky/Rozpisky.Tests/RecordingRenderer.cs
T
marekandClaude Opus 5 001afc2d81 Šrafy: rozvinout vzor na čáry místo plné výplně
Každá šrafa se kreslila jako plná výplň, bez ohledu na vzor. Logo md_sfdi.dxf
má 3× ANSI31 (šikmé čáry) – vycházel z něj plný blok. Nový SrafaVzor rozvine
definiční čáry vzoru na úsečky: rodina rovnoběžek podle vektoru Offset,
ořezaná hranicemi šrafy sudo-lichou paritou (takže díry ve vnořených smyčkách
vyjdou správně) a čárkováním z DashLengths. Proti zamrznutí náhledu při vadném
měřítku ve zdroji je strop 20 000 úseček na šrafu.

Rozhraní: Fill(loops) dostává druhý parametr Vypln. Rastrové renderery kreslí
rozvinuté čáry (Skia vzory neumí), DXF export je ignoruje a zapíše zpátky HATCH
s původním jménem vzoru, měřítkem a úhlem – v CADu tak zůstane editovatelný.
Když se vzor rozvinout nepodaří, plocha zůstane prázdná; zaplácnout ji načerno
je horší než ji nevyplnit.

Ověřeno i vizuálně: z 9 dodávaných log se změnilo jen md_sfdi, ostatních 8 je
po renderu do PNG pixel po pixelu shodných s předchozím stavem.

105 testů zelených.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 14:36:51 +02:00

72 lines
3.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Rozpisky.Rendering;
namespace Rozpisky.Tests;
/// <summary>
/// Testovací <see cref="IProfileRenderer"/>: nic nekreslí, jen zaznamenává volání primitiv,
/// aby testy mohly assertovat, co přesně parser (<c>DxfTemplate.Replay</c>) vyprodukoval.
/// Obrysy (<see cref="Contour"/>) se pro pohodlné assertování bboxů zaznamenávají jak analyticky
/// (<see cref="FillContours"/>, <see cref="StrokeContours"/>), tak jemně zploštěné na body
/// (<see cref="Fills"/>, <see cref="Polylines"/>) zpětně kompatibilní s dřívějšími testy.
/// </summary>
public sealed class RecordingRenderer : IProfileRenderer
{
public sealed record TextCall(double X, double Y, string Text, double HeightMm, HAlign H, VAlign V,
double RotationDeg, TextStyle Style, double WidthFactor, double MaxWidthMm);
/// <summary>Každé volání Fill = smyčky jednoho HATCH, zploštěné na body.</summary>
public List<IReadOnlyList<IReadOnlyList<(double X, double Y)>>> Fills { get; } = new();
/// <summary>Analytické obrysy jednotlivých volání Fill (se zachovanými oblouky).</summary>
public List<IReadOnlyList<Contour>> FillContours { get; } = new();
/// <summary>Analytické obrysy z volání Stroke (bulge polylinie, samostatné oblouky).</summary>
public List<Contour> StrokeContours { get; } = new();
public List<TextCall> Texts { get; } = new();
/// <summary>Zploštěné polylinie i obrysy ze Stroke (kvůli zpětné kompatibilitě testů).</summary>
public List<IReadOnlyList<(double X, double Y)>> Polylines { get; } = new();
public int LineCount { get; private set; }
public int CircleCount { get; private set; }
/// <summary>Stavy kresby v pořadí, jak přišly testy tak můžou tvrdit i o barvě a hladině.</summary>
public List<KresliciStav> Stavy { get; } = new();
/// <summary>Stav platný pro naposledy zaznamenanou entitu.</summary>
public KresliciStav PosledniStav => Stavy.Count > 0 ? Stavy[^1] : KresliciStav.Vychozi;
public void Stav(in KresliciStav s) => Stavy.Add(s);
public void Line(double x1, double y1, double x2, double y2) => LineCount++;
public void Polyline(IReadOnlyList<(double X, double Y)> pts, bool closed = false) => Polylines.Add(pts);
public void Circle(double cx, double cy, double r) => CircleCount++;
public void Stroke(Contour c)
{
StrokeContours.Add(c);
Polylines.Add(Zplosti(c));
}
public void Text(double x, double y, string text, double heightMm,
HAlign h = HAlign.Left, VAlign v = VAlign.Baseline, double rotationDeg = 0,
TextStyle style = default, double widthFactor = 1, double maxWidthMm = 0)
=> Texts.Add(new TextCall(x, y, text, heightMm, h, v, rotationDeg, style, widthFactor, maxWidthMm));
/// <summary>Druh výplně u jednotlivých volání Fill (plná / vzor a jeho čáry).</summary>
public List<Vypln> Vyplne { get; } = new();
public void Fill(IReadOnlyList<Contour> loops, Vypln vypln = default)
{
FillContours.Add(loops);
Vyplne.Add(vypln);
Fills.Add(loops.Select(Zplosti).ToList());
}
/// <summary>Zploští obrys na body (jemně, sagitta ≤ 0,02 mm) pro bbox asserty v testech.</summary>
private static IReadOnlyList<(double X, double Y)> Zplosti(Contour c)
{
var pts = new List<(double X, double Y)>();
foreach (var e in c.Edges) e.AppendPoints(pts, maxSagitta: 0.02);
if (c.Edges.Count > 0) pts.Add((c.Edges[^1].EX, c.Edges[^1].EY));
return pts;
}
}