e127cebb49
По протоколу регресс-прогона (46 вызовов против 90 в прошлом): feature_delete — ksDocument3D.DeleteObject + RebuildDocument, зависимые уходят каскадом. Неудачная проба больше не требует пересобирать документ (у субагента таких кругов было три). align/vAlign у примитива text: сервер строит, замеряет и сдвигает надпись сам. Ловушка, стоившая двух заходов: ksMoveObj и ksDeleteObj по ссылке от ksConvertTextToCurve возвращают успех и не делают ничего — двигать надо по ссылке ТЕКСТА, а габарит после сдвига считать арифметикой (по текстовой ссылке рамка идёт по ячейке). Поймано тестом, который сверяет заявленный габарит с выдавленной геометрией. list_edges: отбор по типу и координатному окну + концы рёбер в списке. Так адресуется нижний контур под фаску, который иначе не выбрать: индексов не отфильтровать, точек не угадать. Навык: wf меряет пропорцию крупно (1.0→1.25 = +29 %), но квантован ступенями — точную ширину набирают height; прирост каймы указан НА СТОРОНУ и зависит от начертания, а не от шрифта; добавлено предупреждение, что primitive(subtract) режет наехавшие буквы.
107 lines
4.6 KiB
C#
107 lines
4.6 KiB
C#
using Kompas.Mcp.Core.Documents;
|
||
using Kompas.Mcp.Core.Modeling;
|
||
using Kompas.Mcp.Core.Query;
|
||
using System.Globalization;
|
||
using System.Text.RegularExpressions;
|
||
|
||
namespace Kompas.Mcp.Tests.Integration;
|
||
|
||
/// <summary>
|
||
/// Интеграция: выравнивание надписи. КОМПАС кладёт строку только вправо-вверх от точки вставки
|
||
/// (<c>align</c> у <c>ksTextEx</c> её не двигает), поэтому центрирование делает сервер: строит,
|
||
/// замеряет, удаляет и кладёт заново со сдвигом.
|
||
/// </summary>
|
||
[Trait("Category", "Integration")]
|
||
[Collection(KompasCollection.Name)]
|
||
public sealed class TextAlignmentTests : IntegrationTestBase
|
||
{
|
||
private readonly DocumentService _docs;
|
||
private readonly PartModeler _modeler;
|
||
private readonly QueryService _query;
|
||
|
||
public TextAlignmentTests(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, TextAlign align, TextVAlign vAlign) => new()
|
||
{
|
||
Kind = SketchEntityKind.Text,
|
||
Points = [(x, y)],
|
||
Text = text,
|
||
Height = 10,
|
||
FontName = "Arial",
|
||
Align = align,
|
||
VAlign = vAlign,
|
||
};
|
||
|
||
/// <summary>Числа из заметки: minX, maxX, minY, maxY.</summary>
|
||
private static (double MinX, double MaxX, double MinY, double MaxY) Box(string note)
|
||
{
|
||
var n = Regex.Matches(note, @"-?\d+\.\d{2}")
|
||
.Select(m => double.Parse(m.Value, CultureInfo.InvariantCulture)).ToList();
|
||
Assert.True(n.Count >= 4, $"в заметке нет габарита: {note}");
|
||
return (n[0], n[1], n[2], n[3]);
|
||
}
|
||
|
||
[Fact]
|
||
public async Task Centered_text_puts_its_middle_on_the_insertion_point()
|
||
{
|
||
await _docs.CreateAsync(KompasDocumentType.Part);
|
||
try
|
||
{
|
||
var s = await _modeler.OpenSketchAsync(BasePlane.XOY, name: "Надпись по центру");
|
||
var notes = await _modeler.AddEntitiesAsync(
|
||
s, [Text("HHH", 50, 0, TextAlign.Center, TextVAlign.Baseline)], autoClose: true);
|
||
|
||
var box = Box(notes[0]);
|
||
Assert.InRange((box.MinX + box.MaxX) / 2, 49.95, 50.05);
|
||
|
||
// Надпись осталась ОДНА: первая вставка удалена, а не оставлена рядом.
|
||
await _modeler.ExtrudeAsync(s, depth: 2, name: "Рельеф");
|
||
await _modeler.RebuildAsync();
|
||
var modelBox = await _query.GetBoundingBoxAsync();
|
||
var what = $"заметка: {notes[0]}; модель X {modelBox.MinX:F2}…{modelBox.MaxX:F2}";
|
||
Assert.True(Math.Abs(modelBox.MinX - box.MinX) < 0.05, what);
|
||
Assert.True(Math.Abs(modelBox.MaxX - box.MaxX) < 0.05, what);
|
||
}
|
||
finally { await _docs.CloseAsync(save: false); }
|
||
}
|
||
|
||
[Fact]
|
||
public async Task Right_and_middle_anchor_the_box_edges()
|
||
{
|
||
await _docs.CreateAsync(KompasDocumentType.Part);
|
||
try
|
||
{
|
||
var s = await _modeler.OpenSketchAsync(BasePlane.XOY, name: "Надпись по правому краю");
|
||
var notes = await _modeler.AddEntitiesAsync(
|
||
s, [Text("Hy", 90, 20, TextAlign.Right, TextVAlign.Middle)], autoClose: true);
|
||
|
||
var box = Box(notes[0]);
|
||
Assert.InRange(box.MaxX, 89.95, 90.05); // правый край — на якоре
|
||
Assert.InRange((box.MinY + box.MaxY) / 2, 19.95, 20.05); // середина глифов — на якоре
|
||
}
|
||
finally { await _docs.CloseAsync(save: false); }
|
||
}
|
||
|
||
[Fact]
|
||
public async Task Default_alignment_keeps_the_kompas_behaviour()
|
||
{
|
||
await _docs.CreateAsync(KompasDocumentType.Part);
|
||
try
|
||
{
|
||
var s = await _modeler.OpenSketchAsync(BasePlane.XOY, name: "Надпись от точки");
|
||
var notes = await _modeler.AddEntitiesAsync(
|
||
s, [Text("HH", 5, 0, TextAlign.Left, TextVAlign.Baseline)], autoClose: true);
|
||
|
||
var box = Box(notes[0]);
|
||
Assert.True(box.MinX >= 5, "по умолчанию строка кладётся вправо от точки вставки");
|
||
Assert.InRange(box.MinY, -0.5, 0.5); // базовая линия — на y точки вставки
|
||
}
|
||
finally { await _docs.CloseAsync(save: false); }
|
||
}
|
||
}
|