using Rozpisky.Dxf; using Xunit; namespace Rozpisky.Tests; /// /// Šrafy (HATCH) s hranovými hranicemi (úsečky, oblouky, elipsy) – dřív se tiše přeskočily, /// takže tečky a oblé výplně v logách chyběly. Hodnoty jsou předpočítané ze skutečných DXF. /// public class HatchTesty { private static RecordingRenderer Prehraj(string logo) { var rec = new RecordingRenderer(); new DxfTemplate(TestData.Logo(logo)).Replay(rec); return rec; } private static (double W, double H, double Cx, double Cy) Bbox(IReadOnlyList<(double X, double Y)> loop) { double ax = double.MaxValue, ay = double.MaxValue, bx = double.MinValue, by = double.MinValue; foreach (var (x, y) in loop) { ax = Math.Min(ax, x); ay = Math.Min(ay, y); bx = Math.Max(bx, x); by = Math.Max(by, y); } return (bx - ax, by - ay, (ax + bx) / 2, (ay + by) / 2); } [Fact] public void Tesia_TeckaZKruhoveHrany_SeVyplni() { var rec = Prehraj("tesia.dxf"); // 2 SOLID hatche: obrys žárovky (polyline s bulge) + tečka (plná kruhová hrana r≈0,78). var smycky = rec.Fills.SelectMany(f => f).ToList(); Assert.Equal(2, smycky.Count); // Tečka = menší smyčka; průměr ≈ 1,56 mm (plný kruh z jediné obloukové hrany). var tecka = smycky.OrderBy(l => Bbox(l).W).First(); var (w, h, _, _) = Bbox(tecka); Assert.InRange(w, 1.50, 1.62); Assert.InRange(h, 1.50, 1.62); } [Fact] public void SudopBrno_MichaneUseckoveAObloukoveHrany_DajiUzavreneSmycky() { var rec = Prehraj("sudopBrno.dxf"); // 6 SOLID šraf, všechny jen s hranovými cestami (úsečky + oblouky) → dřív 0 výplní. // Referenční bboxy spočtené nezávisle hustým vzorkováním raw dat hran (512 dílků/oblouk). Assert.Equal(6, rec.Fills.Count); var smycky = rec.Fills.SelectMany(f => f).ToList(); Assert.Equal(7, smycky.Count); // jeden hatch má 2 cesty, ostatní po jedné Assert.All(smycky, l => Assert.True(l.Count >= 3)); // Nezávisle na pořadí (draw order přes SortEntitiesTable může hatche přeuspořádat) ověříme, // že existují smyčky s referenčními bboxy – včetně plné kružnice r=3,825 (7,649²) z jediné // obloukové hrany a řetězů úsečka+oblouk vč. ccw=false (zrcadlené úhly). Chybné znaménko/ // otočení hrany nebo ztracená kružnice by referenci znatelně změnily. MaSmyckuBbox(smycky, 7.649, 7.649); MaSmyckuBbox(smycky, 5.571, 0.626); MaSmyckuBbox(smycky, 2.092, 0.066); MaSmyckuBbox(smycky, 7.807, 1.085); MaSmyckuBbox(smycky, 11.290, 1.733); } private static void MaSmyckuBbox(IReadOnlyList> smycky, double refW, double refH) => Assert.Contains(smycky, l => { var (w, h, _, _) = Bbox(l); return w >= refW - 0.1 && w <= refW + 0.02 && h >= refH - 0.1 && h <= refH + 0.02; }); [Fact] public void Signalprojekt_KruhovaAEliptickaHrana_SeVyplni() { var rec = Prehraj("signalprojekt.dxf"); Assert.Equal(2, rec.Fills.Count); var smycky = rec.Fills.SelectMany(f => f).ToList(); // Eliptická cesta: poloosy 1,16 a 0,759·1,16 → bbox ≈ 1,76 × 2,32 (hlavní osa svisle). Assert.Contains(smycky, l => { var (w, h, _, _) = Bbox(l); double lo = Math.Min(w, h), hi = Math.Max(w, h); return Math.Abs(hi - 2.32) < 0.05 && Math.Abs(lo - 1.76) < 0.05; }); } [Fact] public void PolylinioveHranice_BezRegrese() { // exprojekt: 3 SOLID šrafy čistě s polyline hranicemi – musí zůstat beze změny. var rec = Prehraj("exprojekt.dxf"); Assert.Equal(3, rec.Fills.Count); Assert.All(rec.Fills, f => Assert.All(f, l => Assert.True(l.Count >= 3))); } }