using Kompas.Mcp.Core.Documents; using Kompas.Mcp.Core.Modeling; using Kompas.Mcp.Core.Query; namespace Kompas.Mcp.Tests.Integration; /// /// Интеграция: надпись в эскизе. Текст сам по себе — оформление, выдавить его нельзя; /// примитив type=text переводит его в кривые (ksConvertTextToCurve), и контур глифов /// становится обычным сечением операции. /// [Trait("Category", "Integration")] [Collection(KompasCollection.Name)] public sealed class SketchTextTests : IntegrationTestBase { private readonly DocumentService _docs; private readonly PartModeler _modeler; private readonly QueryService _query; public SketchTextTests(KompasFixture fx) : base(fx) { _docs = new DocumentService(fx.Session, fx.Dispatcher); _modeler = new PartModeler(fx.Session, fx.Dispatcher); _query = new QueryService(fx.Session, fx.Dispatcher); } private static SketchEntity Text(string text, double x, double y, double height, string? font = null) => new() { Kind = SketchEntityKind.Text, Points = [(x, y)], Text = text, Height = height, FontName = font, }; [Fact] public async Task Text_becomes_curves_and_extrudes() { await _docs.CreateAsync(KompasDocumentType.Part); try { var s = await _modeler.OpenSketchAsync(BasePlane.XOY); var notes = await _modeler.AddEntitiesAsync(s, [Text("HI", 0, 0, 10, "Arial")], autoClose: true); await _modeler.ExtrudeAsync(s, depth: 2); await _modeler.RebuildAsync(); // Длина строки нужна агенту для выравнивания: до выдавливания её узнать неоткуда. Assert.Contains("длина", notes[0], StringComparison.Ordinal); var info = await _query.GetPartInfoAsync(); Assert.True(info.Volume > 0, "надпись не дала объёма — текст не переведён в кривые"); var box = await _query.GetBoundingBoxAsync(); Assert.InRange(box.SizeZ, 1.99, 2.01); Assert.InRange(box.SizeY, 6, 11); // высота прописных ≈ height Assert.True(box.SizeX > box.SizeY); // «HI» шире, чем выше } finally { await _docs.CloseAsync(save: false); } } [Fact] public async Task Unknown_font_is_reported_by_name() { await _docs.CreateAsync(KompasDocumentType.Part); try { var s = await _modeler.OpenSketchAsync(BasePlane.XOY); var bad = Text("HI", 0, 0, 10, "No Such Font 12345"); // КОМПАС подставляет замену вместо отсутствующего шрифта, поэтому надпись // всё равно строится — важно, что она не рушит пакет и даёт геометрию. var notes = await _modeler.AddEntitiesAsync(s, [bad], autoClose: true); Assert.False(string.IsNullOrEmpty(notes[0])); } finally { await _docs.CloseAsync(save: false); } } [Fact] public async Task Thin_wall_outward_grows_the_contour() { await _docs.CreateAsync(KompasDocumentType.Part); try { // Квадрат 20×20 стенкой 2 мм наружу: габарит вырастает на 2·2 мм по каждой оси, // а объём равен объёму рамки, а не сплошной плиты. var s = await _modeler.OpenSketchAsync(BasePlane.XOY); await _modeler.AddRectangleAsync(s, 0, 0, 20, 20); await _modeler.CloseSketchAsync(s); await _modeler.ExtrudeAsync(s, depth: 5, thinThickness: 2, thinSide: ThinSide.Outward); await _modeler.RebuildAsync(); var box = await _query.GetBoundingBoxAsync(); Assert.InRange(box.SizeX, 23.9, 24.1); Assert.InRange(box.SizeY, 23.9, 24.1); var v = (await _query.GetPartInfoAsync()).Volume; // (24² − 20²)·5 = 880 Assert.InRange(v, 880 * 0.98, 880 * 1.02); } finally { await _docs.CloseAsync(save: false); } } [Fact] public async Task Thin_wall_inward_keeps_the_contour_and_hollows_it() { await _docs.CreateAsync(KompasDocumentType.Part); try { // Стенка внутрь контура: габарит остаётся 20×20, материал — только рамка по периметру. var s = await _modeler.OpenSketchAsync(BasePlane.XOY); await _modeler.AddRectangleAsync(s, 0, 0, 20, 20); await _modeler.CloseSketchAsync(s); await _modeler.ExtrudeAsync(s, depth: 5, thinThickness: 2, thinSide: ThinSide.Inward); await _modeler.RebuildAsync(); var box = await _query.GetBoundingBoxAsync(); Assert.InRange(box.SizeX, 19.9, 20.1); Assert.InRange(box.SizeY, 19.9, 20.1); // (20² − 16²)·5 = 720; сплошная плита дала бы 2000 — так ловится «стенка не применилась». var v = (await _query.GetPartInfoAsync()).Volume; Assert.InRange(v, 720 * 0.98, 720 * 1.02); } finally { await _docs.CloseAsync(save: false); } } }