using ACadSharp;
using ACadSharp.Entities;
using ACadSharp.Tables;
using CSMath;
using Rozpisky.Dxf;
using Rozpisky.Rendering;
using Xunit;
using AcColor = ACadSharp.Color;
namespace Rozpisky.Tests;
///
/// Entity, které dřív propadly switchem bez default větve, a tedy zmizely tiše:
/// vložené bloky (INSERT), elipsy, body, vyplněné čtyřúhelníky. Uživatel si přidává vlastní
/// loga, takže „nevykreslí se a nikdo se to nedozví" je nejhorší možné chování.
///
public class EntityTesty
{
/// Přehraje dokument sestavený v paměti přes dočasný soubor (DxfTemplate čte ze souboru).
private static (RecordingRenderer G, IReadOnlyDictionary Nezpracovane) Prehraj(CadDocument doc)
{
string cesta = System.IO.Path.Combine(System.IO.Path.GetTempPath(),
"rozpisky-entity-" + Guid.NewGuid().ToString("N") + ".dxf");
try
{
ACadSharp.IO.DxfWriter.Write(cesta, doc, binary: true);
var tpl = new DxfTemplate(cesta);
var g = new RecordingRenderer();
tpl.Replay(g);
return (g, tpl.NezpracovaneEntity);
}
finally
{
try { System.IO.File.Delete(cesta); } catch (System.IO.IOException) { }
}
}
/// Dokument s jedním blokem (čtvercová čára 0,0–10,10) a jeho vložením.
private static CadDocument SBlokem(Action uprav, AcColor? barvaCary = null)
{
var doc = new CadDocument();
var blok = new BlockRecord("ctverec");
blok.Entities.Add(new Line(new XYZ(0, 0, 0), new XYZ(10, 0, 0))
{
Color = barvaCary ?? AcColor.ByLayer,
});
doc.BlockRecords.Add(blok);
var ins = new Insert(blok);
uprav(ins);
doc.Entities.Add(ins);
return doc;
}
[Fact]
public void VsechnaDodavanaDataSeVykresliBezeZbytku()
{
// Šablona i všech 9 log musí projít beze zbytku – jinak se v nich něco nekreslí.
var sablona = new DxfTemplate(TestData.Sablona);
sablona.Replay(new RecordingRenderer(), values: null, includeNoPrint: true);
Assert.Empty(sablona.NezpracovaneEntity);
foreach (var logo in TestData.VsechnaLoga)
{
var tpl = new DxfTemplate(TestData.Logo(logo));
tpl.Replay(new RecordingRenderer());
Assert.True(tpl.NezpracovaneEntity.Count == 0,
$"{logo}: nezpracované entity {string.Join(", ", tpl.NezpracovaneEntity.Select(p => $"{p.Key}×{p.Value}"))}");
}
}
[Fact]
public void VlozenyBlokSeRozvineNaSpravnemMiste()
{
var (g, nezpracovane) = Prehraj(SBlokem(ins => ins.InsertPoint = new XYZ(100, 50, 0)));
Assert.Empty(nezpracovane);
Assert.Equal(1, g.LineCount);
Assert.Equal((100, 50), g.Lines[0].Od);
Assert.Equal((110, 50), g.Lines[0].Do);
}
[Fact]
public void MeritkoANatoceniBlokuSeProjevi()
{
var (g, _) = Prehraj(SBlokem(ins =>
{
ins.InsertPoint = new XYZ(0, 0, 0);
ins.XScale = 2;
ins.YScale = 2;
ins.Rotation = Math.PI / 2; // 90° → úsečka z osy X na osu Y
}));
Assert.Equal(1, g.LineCount);
var (od, doB) = g.Lines[0];
Assert.Equal(0, od.X, 6);
Assert.Equal(0, od.Y, 6);
Assert.Equal(0, doB.X, 6);
Assert.Equal(20, doB.Y, 6);
}
[Fact]
public void BarvaByBlockSeVezmeZVkladajiciEntity()
{
// Tohle je smysl ByBlock: stejný blok vložený dvakrát může mít pokaždé jinou barvu.
var (g, _) = Prehraj(SBlokem(
ins => { ins.InsertPoint = new XYZ(0, 0, 0); ins.Color = new AcColor(5); },
barvaCary: AcColor.ByBlock));
// Stavů jsou dva: jeden za samotný INSERT, druhý za úsečku uvnitř bloku – zajímá nás ten druhý.
var stav = g.PosledniStav;
Assert.Equal(BarvaDruh.Index, stav.Barva.Druh);
Assert.Equal(5, stav.Barva.Index);
}
[Fact]
public void ElipsaSeVykresliJakoLomenaCara()
{
var doc = new CadDocument();
doc.Entities.Add(new Ellipse
{
Center = new XYZ(0, 0, 0),
MajorAxisEndPoint = new XYZ(10, 0, 0),
RadiusRatio = 0.5,
StartParameter = 0,
EndParameter = 2 * Math.PI,
});
var (g, nezpracovane) = Prehraj(doc);
Assert.Empty(nezpracovane);
var body = Assert.Single(g.Polylines);
Assert.True(body.Count >= 8);
// Body musí ležet na elipse s poloosami 10 a 5.
foreach (var (x, y) in body)
Assert.Equal(1.0, x * x / 100 + y * y / 25, 3);
}
[Fact]
public void SolidSeVyplniVeSpravnemPoradiRohu()
{
// V DXF jsou 3. a 4. roh proti obvodu prohozené – při špatném pořadí vyjde přesýpací hodiny.
var doc = new CadDocument();
doc.Entities.Add(new Solid
{
FirstCorner = new XYZ(0, 0, 0),
SecondCorner = new XYZ(10, 0, 0),
ThirdCorner = new XYZ(0, 10, 0),
FourthCorner = new XYZ(10, 10, 0),
});
var (g, nezpracovane) = Prehraj(doc);
Assert.Empty(nezpracovane);
var smycky = Assert.Single(g.Fills);
var body = Assert.Single(smycky);
Assert.Equal(new[] { (0.0, 0.0), (10.0, 0.0), (10.0, 10.0), (0.0, 10.0) },
body.Take(4).Select(p => (Math.Round(p.X, 6), Math.Round(p.Y, 6))));
}
[Fact]
public void NeznamaEntitaSeSpocitaMistoTichehoZahozeni()
{
var doc = new CadDocument();
doc.Entities.Add(new Ray { StartPoint = new XYZ(0, 0, 0), Direction = new XYZ(1, 0, 0) });
var (g, nezpracovane) = Prehraj(doc);
Assert.Empty(g.Polylines);
Assert.Equal(0, g.LineCount);
Assert.Equal(1, nezpracovane.Values.Sum());
}
[Fact]
public void PocitadloSeMeziPruchodyNehromadi()
{
var doc = new CadDocument();
doc.Entities.Add(new Ray { StartPoint = new XYZ(0, 0, 0), Direction = new XYZ(1, 0, 0) });
string cesta = System.IO.Path.Combine(System.IO.Path.GetTempPath(),
"rozpisky-entity-" + Guid.NewGuid().ToString("N") + ".dxf");
try
{
ACadSharp.IO.DxfWriter.Write(cesta, doc, binary: true);
var tpl = new DxfTemplate(cesta);
tpl.Replay(new RecordingRenderer());
tpl.Replay(new RecordingRenderer());
Assert.Equal(1, tpl.NezpracovaneEntity.Values.Sum());
}
finally
{
try { System.IO.File.Delete(cesta); } catch (System.IO.IOException) { }
}
}
}