From db23a1a748962ea790e019cc461665045c260dce Mon Sep 17 00:00:00 2001 From: Shahovalov MIkhail Date: Wed, 27 May 2026 17:07:35 +0300 Subject: [PATCH 1/4] =?UTF-8?q?docs:=20=D1=81=D0=BF=D0=B5=D0=BA=20drawing?= =?UTF-8?q?=5Ffill=5Ftitle=5Fblock=20=E2=80=94=20=D0=BE=D1=81=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2=D0=BD=D0=B0=D1=8F=20=D0=BD=D0=B0=D0=B4=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D1=8C=20=D1=87=D0=B5=D1=80=D1=82=D0=B5=D0=B6=D0=B0=20(API7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Веха 2D-ЧЕРТЁЖ, инкремент 2. Спайк подтвердил round-trip графы: LayoutSheets. ItemByNumber[1].Stamp.Text[id].Str + Update(). Enum StampField→номер графы ГОСТ (designation=2, name=1, material=3). Заполнение нескольких граф за вызов. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../2026-05-27-drawing-title-block-design.md | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 docs/superpowers/specs/2026-05-27-drawing-title-block-design.md diff --git a/docs/superpowers/specs/2026-05-27-drawing-title-block-design.md b/docs/superpowers/specs/2026-05-27-drawing-title-block-design.md new file mode 100644 index 0000000..a4addc6 --- /dev/null +++ b/docs/superpowers/specs/2026-05-27-drawing-title-block-design.md @@ -0,0 +1,95 @@ +# Дизайн: основная надпись чертежа (drawing_fill_title_block) через API7 + +**Дата:** 2026-05-27 +**Статус:** спайк зелёный (round-trip графы подтверждён); спроектировано; на ревью (Codex) + +## Цель + +Веха 2D-ЧЕРТЁЖ, инкремент 2 (оформление). После стандартных видов (`drawing_create_standard_views`) +— заполнить **основную надпись** (штамп, title block) чертежа: обозначение, наименование, материал. +Чертёж с видами + заполненным штампом = презентабельный конструкторский документ. Размеры на видах +— отдельный инкремент 3 (нужен спайк по размерным интерфейсам). + +## Спайк: механизм подтверждён вживую (НЕ разучивать) + +Спайк (`DrawingStampSpikeTests`, зелёный) подтвердил путь API7 — round-trip графы: + +``` +IKompasDocument2D doc2d = (IKompasDocument2D)app.ActiveDocument; // активный чертёж +ILayoutSheet sheet = (ILayoutSheet)doc2d.LayoutSheets.ItemByNumber[1]; // лист 1 (1-based) +IStamp stamp = (IStamp)sheet.Stamp; +stamp.Text[columnId].Str = text; // Text[Int32 Id] — индексированное свойство; Id = номер графы +stamp.Update(); // фиксирует +string readBack = stamp.Text[columnId].Str; // чтение для проверки +``` + +**Проверено:** запись в графу 2 (обозначение) «ДЕТАЛЬ.001» → чтение возвращает «ДЕТАЛЬ.001». +`IText.Str` — read/write; `IStamp.Text[Id]` — индексированное свойство (рефлексия: `get_Text(Int32 Id)`). +`Update()` фиксирует; перестроение документа не нужно. + +**Номера граф ГОСТ (форма 1), `ksStampEnum`:** `ksStPartNumber=1` (наименование изделия), +`ksStDescription=2` (обозначение документа), `ksStMaterial=3` (материал), `ksStScale=6` (масштаб), +`ksStAuthor=110` (разработал) и т.д. + +## Архитектура + +Метод в существующем `DrawingService`. Свой enum `StampField` (паттерн `BasePlane`/`MateType`) +маппится на номера граф — COM-числа не текут в Host/тесты. + +- `src/Kompas.Mcp.Core/Drawings/StampField.cs` — enum `StampField` + static `StampFields` + (`ColumnId(field)` → номер графы). +- `DrawingService.FillTitleBlockAsync(designation?, name?, material?, ct)` — реализация. +- Инструмент `drawing_fill_title_block` в `DrawingTools`. + +## MCP-инструмент + +| Инструмент | Параметры | Поведение | +|---|---|---| +| `drawing_fill_title_block` | `designation?`, `name?`, `material?` (все опц.) | Заполнить графы основной надписи активного чертежа: обозначение (графа 2), наименование (1), материал (3). Передаются только нужные поля (null/пусто — пропускается). Возвращает число заполненных граф. | + +Контракт: активный документ — чертёж; хотя бы одно поле задано (иначе ошибка). Набор полей — +3 ключевые графы ГОСТ (расширяемо). За один вызов заполняются все переданные (меньше round-trip'ов +для LLM-агента, чем у «одна графа за вызов»). + +## Валидация (чистые static, unit-тест) + +- `StampFields.ColumnId(StampField)` — `Designation→2`, `Name→1`, `Material→3` (unit-тест маппинга). +- В сервисе: собрать непустые (после `Trim`) поля; если ни одного — `ArgumentException` + «укажите хотя бы одно поле». (Чистый помощник `StampFields.Collect(...)` → список (columnId,text) + — unit-тестируемо без COM.) + +## Проверка активного документа + +`RequireActiveDrawing()` → `IKompasDocument2D` (тип `ksDocumentDrawing`, иначе раздельная ошибка) — +выделить из существующего `RequireActiveDrawingViews` общий шаг (тот станет надстройкой: вернуть +`.ViewsAndLayersManager.Views`). + +## Реализация + +`FillTitleBlockCore`: собрать поля (`StampFields.Collect`) → если пусто, ошибка → `RequireActiveDrawing` +→ `sheet = LayoutSheets.ItemByNumber[1]` → `stamp = (IStamp)sheet.Stamp` → для каждого поля +`stamp.Text[columnId].Str = text` → `stamp.Update()` (результат проверить) → вернуть число граф. +Транзитные RCW не освобождаем точечно (долг v2-2, как везде). + +## Тестирование + +### Unit (`StampFieldsTests`) +- `StampFields.ColumnId` — каждое поле → ожидаемый номер графы (2/1/3). +- `StampFields.Collect` — пропускает null/пусто/пробелы; при всех пустых даёт пустой список; + собирает заданные с обрезкой пробелов. + +### Integration (`DrawingStampTests`) +Паттерн: создать чертёж → `FillTitleBlockAsync(...)` → перечитать графы напрямую (helper в сервисе +`ReadStampCellAsync(columnId)` для теста ИЛИ проверка через возврат) → `finally CloseAsync` (база +`IntegrationTestBase`). +1. **Заполнение и чтение**: `designation="ДЕТАЛЬ.001", material="Сталь 45"` → 2 графы; чтение графы + 2 == «ДЕТАЛЬ.001», графы 3 == «Сталь 45». +2. **Пустой ввод**: все поля null → `ArgumentException` (ни одной графы не тронуто). +3. **Не-чертёж**: активный документ — деталь → ошибка. + +(Для чтения в тесте — добавить `DrawingService.ReadStampCellAsync(columnId)` — он же подтверждает +round-trip; спайк-файл удаляется.) + +## Дальнейшее (вне спека) +- Прочие графы (масштаб, разработал, даты, литера), размеры/обозначения на видах (инкремент 3), + рамка/формат листа. From 742a97177b2d77fba091eb2ce83bd9d2f5dd2475 Mon Sep 17 00:00:00 2001 From: Shahovalov MIkhail Date: Wed, 27 May 2026 17:20:16 +0300 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20drawing=5Ffill=5Ftitle=5Fblock=20?= =?UTF-8?q?=E2=80=94=20=D0=BE=D1=81=D0=BD=D0=BE=D0=B2=D0=BD=D0=B0=D1=8F=20?= =?UTF-8?q?=D0=BD=D0=B0=D0=B4=D0=BF=D0=B8=D1=81=D1=8C=20=D1=87=D0=B5=D1=80?= =?UTF-8?q?=D1=82=D0=B5=D0=B6=D0=B0=20(API7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Веха 2D-ЧЕРТЁЖ, инкремент 2 (оформление). DrawingService.FillTitleBlockAsync: LayoutSheets.ItemByNumber[1].Stamp.Text[id].Str = text → Update(). Enum StampField → номер графы ГОСТ (designation=2, name=1, material=3). Заполнение нескольких граф за вызов; перезапись (Str замещает, Clear не нужен — подтверждено спайком). Новый инструмент drawing_fill_title_block; ReadStampCellAsync для проверки. Ревью Codex спека учтено: Update() результат проверяется; null-checks (LayoutSheets/sheet/Stamp); RequireActiveDrawing выделен (сохраняет cast-проверку); ColumnId switch с дефолтным throw; счётчик = непустые поля; name=графа 1 однозначно. Валидация — чистый StampFields (ColumnId + Collect). Тесты: +7 unit (StampFields), +4 integration (DrawingStampTests: заполнение+reread 3 граф, перезапись, пустой ввод, не-чертёж). Итого 123 unit + 65 integration = 188. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../2026-05-27-drawing-title-block-design.md | 25 +++++- .../Drawings/DrawingService.cs | 58 +++++++++++-- src/Kompas.Mcp.Core/Drawings/StampField.cs | 47 ++++++++++ src/Kompas.Mcp.Host/Tools/DrawingTools.cs | 15 ++++ .../Integration/DrawingStampTests.cs | 85 +++++++++++++++++++ tests/Kompas.Mcp.Tests/StampFieldsTests.cs | 41 +++++++++ 6 files changed, 265 insertions(+), 6 deletions(-) create mode 100644 src/Kompas.Mcp.Core/Drawings/StampField.cs create mode 100644 tests/Kompas.Mcp.Tests/Integration/DrawingStampTests.cs create mode 100644 tests/Kompas.Mcp.Tests/StampFieldsTests.cs diff --git a/docs/superpowers/specs/2026-05-27-drawing-title-block-design.md b/docs/superpowers/specs/2026-05-27-drawing-title-block-design.md index a4addc6..ef10d9e 100644 --- a/docs/superpowers/specs/2026-05-27-drawing-title-block-design.md +++ b/docs/superpowers/specs/2026-05-27-drawing-title-block-design.md @@ -1,7 +1,30 @@ # Дизайн: основная надпись чертежа (drawing_fill_title_block) через API7 **Дата:** 2026-05-27 -**Статус:** спайк зелёный (round-trip графы подтверждён); спроектировано; на ревью (Codex) +**Статус:** реализовано и проверено (4 интеграционных + 7 unit, всего 188); ревью Codex спека учтено + +## Находка спайка: `Str` ПЕРЕЗАПИСЫВАЕТ (Clear не нужен) + +Двойная запись в графу 2 («ДЕТАЛЬ.001» → «ИЗДЕЛИЕ.002») → чтение даёт «ИЗДЕЛИЕ.002» (не +дописано). Значит `stamp.Text[id].Str = value` **замещает** содержимое — `IText.Clear()` перед +записью НЕ нужен. + +## Правки по ревью Codex + +- **Update() результат проверять**: `if (!stamp.Update()) throw`. +- **null-checks**: `LayoutSheets`, `sheet`, `sheet.Stamp` (ранняя диагностируемая ошибка). +- **`RequireActiveDrawing()`** сохраняет проверку `doc is not IKompasDocument2D` (не только + `DocumentType`); `RequireActiveDrawingViews` становится надстройкой над ним. +- **`ColumnId` switch** — дефолт `ArgumentOutOfRangeException`; unit-тест на `(StampField)999`. +- **Тест**: писать и перечитывать ВСЕ три графы (вкл. `name`=графа 1); явный reread `Text[id].Str`; + тест overwrite (запись дважды → читается второе) — уже подтверждён спайком, перенесём в регрессию. +- **`name` = «Наименование изделия» (графа 1, `ksStPartNumber`)** — однозначно в описании (не путать + с `ksStDocumentName=51`). +- **Счётчик результата** = число непустых (trimmed) полей, записанных до успешного `Update()`. +- **Сигнатура**: `FillTitleBlockAsync(string? designation = null, string? name = null, + string? material = null, ct)`. +- **Scale (графа 6) и прочие — ЯВНО вне scope инкремента 2.** Spike-метод и spike-тест удаляются. +- RCW точечно не освобождаем (v2-2). ## Цель diff --git a/src/Kompas.Mcp.Core/Drawings/DrawingService.cs b/src/Kompas.Mcp.Core/Drawings/DrawingService.cs index ea94d5a..a0b3d9f 100644 --- a/src/Kompas.Mcp.Core/Drawings/DrawingService.cs +++ b/src/Kompas.Mcp.Core/Drawings/DrawingService.cs @@ -30,6 +30,48 @@ public sealed class DrawingService double x, double y, CancellationToken ct = default) => _dispatcher.InvokeAsync(() => CreateStandardViewsCore(partFilePath, scale, x, y), ct); + /// + /// Заполнить графы основной надписи активного чертежа: обозначение (графа 2), наименование + /// изделия (графа 1), материал (графа 3). Передаются только нужные поля (null/пусто — + /// пропускается). Возвращает число заполненных граф. + /// + public Task FillTitleBlockAsync(string? designation = null, string? name = null, + string? material = null, CancellationToken ct = default) + => _dispatcher.InvokeAsync(() => FillTitleBlockCore(designation, name, material), ct); + + private int FillTitleBlockCore(string? designation, string? name, string? material) + { + var fields = StampFields.Collect(designation, name, material); + if (fields.Count == 0) + throw new ArgumentException("Укажите хотя бы одно поле основной надписи (designation/name/material)."); + + var stamp = RequireActiveStamp(); + foreach (var (columnId, text) in fields) + stamp.Text[columnId].Str = text; // Str замещает содержимое (Clear не нужен) + if (!stamp.Update()) + throw new InvalidOperationException("IStamp.Update вернул FALSE — основная надпись не обновлена."); + return fields.Count; + } + + /// Прочитать текст графы основной надписи (для проверки/диагностики). + public Task ReadStampCellAsync(int columnId, CancellationToken ct = default) + => _dispatcher.InvokeAsync(() => + { + var stamp = RequireActiveStamp(); + return stamp.Text[columnId]?.Str ?? string.Empty; + }, ct); + + private IStamp RequireActiveStamp() + { + var doc2d = RequireActiveDrawing(); + var sheets = doc2d.LayoutSheets + ?? throw new InvalidOperationException("Не удалось получить листы оформления чертежа."); + var sheet = sheets.ItemByNumber[1] as ILayoutSheet + ?? throw new InvalidOperationException("На чертеже нет листа оформления #1."); + return sheet.Stamp as IStamp + ?? throw new InvalidOperationException("У листа оформления нет основной надписи (Stamp)."); + } + // Стандартная тройка проекций: ksPtFront=1, ksPtUp=3, ksPtLeft=5 (ksRelativeProjectionTypeEnum). private static readonly object[] StandardProjections = { 1, 3, 5 }; private const int ExpectedCreated = 3; @@ -79,19 +121,25 @@ public sealed class DrawingService } } - private IViews RequireActiveDrawingViews() + /// + /// Получить активный чертёж как . Раздельные ошибки: нет документа / + /// тип != ksDocumentDrawing / не приводится к IKompasDocument2D. + /// + private IKompasDocument2D RequireActiveDrawing() { var doc = _session.Application.ActiveDocument ?? throw new InvalidOperationException("Нет активного документа. Создайте чертёж: document_create drawing."); if (doc.DocumentType != DocumentTypeEnum.ksDocumentDrawing) throw new InvalidOperationException( $"Активный документ не является чертежом (тип: {doc.DocumentType}). Создайте чертёж: document_create drawing."); - if (doc is not IKompasDocument2D doc2d) - throw new InvalidOperationException("Активный документ не приводится к IKompasDocument2D."); - return doc2d.ViewsAndLayersManager?.Views - ?? throw new InvalidOperationException("Не удалось получить коллекцию видов чертежа."); + return doc as IKompasDocument2D + ?? throw new InvalidOperationException("Активный документ не приводится к IKompasDocument2D."); } + private IViews RequireActiveDrawingViews() + => RequireActiveDrawing().ViewsAndLayersManager?.Views + ?? throw new InvalidOperationException("Не удалось получить коллекцию видов чертежа."); + private static HashSet CollectViewNumbers(IViews views) { var set = new HashSet(); diff --git a/src/Kompas.Mcp.Core/Drawings/StampField.cs b/src/Kompas.Mcp.Core/Drawings/StampField.cs new file mode 100644 index 0000000..6b92ce0 --- /dev/null +++ b/src/Kompas.Mcp.Core/Drawings/StampField.cs @@ -0,0 +1,47 @@ +namespace Kompas.Mcp.Core.Drawings; + +/// +/// Поле основной надписи (графа штампа ГОСТ). Маппится на номер графы ksStampEnum. +/// Пока поддержаны три ключевые графы; остальные (масштаб, разработал, даты…) — позже. +/// +public enum StampField +{ + /// Обозначение документа (графа 2, ksStDescription). + Designation, + /// Наименование изделия (графа 1, ksStPartNumber). + Name, + /// Материал (графа 3, ksStMaterial). + Material, +} + +/// Маппинг поля основной надписи → номер графы и сбор непустых полей. +public static class StampFields +{ + /// Номер графы (ksStampEnum) для поля основной надписи. + public static int ColumnId(StampField field) => field switch + { + StampField.Designation => 2, // ksStDescription + StampField.Name => 1, // ksStPartNumber (наименование изделия) + StampField.Material => 3, // ksStMaterial + _ => throw new ArgumentOutOfRangeException(nameof(field), field, "Неизвестное поле основной надписи."), + }; + + /// + /// Собрать непустые (после Trim) поля в список (номер графы, текст). null/пусто/пробелы — + /// пропускаются. Чистая (без COM) — unit-тестируемо. + /// + public static IReadOnlyList<(int ColumnId, string Text)> Collect(string? designation, string? name, string? material) + { + var list = new List<(int, string)>(3); + Add(list, StampField.Designation, designation); + Add(list, StampField.Name, name); + Add(list, StampField.Material, material); + return list; + } + + private static void Add(List<(int, string)> list, StampField field, string? value) + { + if (!string.IsNullOrWhiteSpace(value)) + list.Add((ColumnId(field), value.Trim())); + } +} diff --git a/src/Kompas.Mcp.Host/Tools/DrawingTools.cs b/src/Kompas.Mcp.Host/Tools/DrawingTools.cs index d96ab9b..9ca2ad8 100644 --- a/src/Kompas.Mcp.Host/Tools/DrawingTools.cs +++ b/src/Kompas.Mcp.Host/Tools/DrawingTools.cs @@ -26,4 +26,19 @@ public sealed class DrawingTools(KompasSession session, DrawingService drawing) var r = await drawing.CreateStandardViewsAsync(partFilePath, scale, x, y); return $"Создано {r.Created} стандартных вида на чертеже (всего видов: {r.Total}, масштаб {scale})."; } + + [McpServerTool(Name = "drawing_fill_title_block")] + [Description("Заполнить графы основной надписи (штампа) активного чертежа. Передавайте только нужные поля: " + + "designation — обозначение документа (графа 2); name — наименование изделия (графа 1); " + + "material — материал (графа 3). Незаданные/пустые поля пропускаются (нужно хотя бы одно). " + + "Существующий текст графы перезаписывается. Возвращает число заполненных граф.")] + public async Task FillTitleBlock( + [Description("Обозначение документа (графа 2)")] string? designation = null, + [Description("Наименование изделия (графа 1)")] string? name = null, + [Description("Материал (графа 3)")] string? material = null) + { + await session.ConnectAsync(); + var filled = await drawing.FillTitleBlockAsync(designation, name, material); + return $"Заполнено граф основной надписи: {filled}."; + } } diff --git a/tests/Kompas.Mcp.Tests/Integration/DrawingStampTests.cs b/tests/Kompas.Mcp.Tests/Integration/DrawingStampTests.cs new file mode 100644 index 0000000..005102e --- /dev/null +++ b/tests/Kompas.Mcp.Tests/Integration/DrawingStampTests.cs @@ -0,0 +1,85 @@ +using Kompas.Mcp.Core.Documents; +using Kompas.Mcp.Core.Drawings; +using Kompas.Mcp.Core.Modeling; + +namespace Kompas.Mcp.Tests.Integration; + +/// Интеграция: заполнение основной надписи чертежа (API7 IStamp.Text). +[Trait("Category", "Integration")] +[Collection(KompasCollection.Name)] +public sealed class DrawingStampTests : IntegrationTestBase +{ + private readonly DocumentService _docs; + private readonly DrawingService _drawing; + private readonly PartModeler _modeler; + + public DrawingStampTests(KompasFixture fx) : base(fx) + { + _docs = new DocumentService(fx.Session, fx.Dispatcher); + _drawing = new DrawingService(fx.Session, fx.Dispatcher); + _modeler = new PartModeler(fx.Session, fx.Dispatcher); + } + + [Fact] + public async Task Fills_and_reads_back_title_block_cells() + { + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + var filled = await _drawing.FillTitleBlockAsync( + designation: "ДЕТАЛЬ.001", name: "Кронштейн", material: "Сталь 45"); + Assert.Equal(3, filled); + + // Явный reread каждой графы (графа 2/1/3). + Assert.Equal("ДЕТАЛЬ.001", await _drawing.ReadStampCellAsync(2)); + Assert.Equal("Кронштейн", await _drawing.ReadStampCellAsync(1)); + Assert.Equal("Сталь 45", await _drawing.ReadStampCellAsync(3)); + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task Overwrites_existing_cell_text() + { + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + await _drawing.FillTitleBlockAsync(designation: "СТАРОЕ.000"); + await _drawing.FillTitleBlockAsync(designation: "НОВОЕ.111"); + + // Перезапись, не дописывание. + Assert.Equal("НОВОЕ.111", await _drawing.ReadStampCellAsync(2)); + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task Empty_input_throws() + { + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + await Assert.ThrowsAsync( + () => _drawing.FillTitleBlockAsync(null, " ", null)); + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task Rejects_non_drawing_document() + { + await _docs.CreateAsync(KompasDocumentType.Part); + try + { + // Деталь — не чертёж: FillTitleBlock должен бросить. + var s = await _modeler.OpenSketchAsync(BasePlane.XOY); + await _modeler.AddRectangleAsync(s, 0, 0, 10, 10); + await _modeler.CloseSketchAsync(s); + await _modeler.ExtrudeAsync(s, depth: 5); + + await Assert.ThrowsAsync( + () => _drawing.FillTitleBlockAsync(designation: "X")); + } + finally { await _docs.CloseAsync(save: false); } + } +} diff --git a/tests/Kompas.Mcp.Tests/StampFieldsTests.cs b/tests/Kompas.Mcp.Tests/StampFieldsTests.cs new file mode 100644 index 0000000..90ef195 --- /dev/null +++ b/tests/Kompas.Mcp.Tests/StampFieldsTests.cs @@ -0,0 +1,41 @@ +using Kompas.Mcp.Core.Drawings; + +namespace Kompas.Mcp.Tests; + +[Trait("Category", "Unit")] +public sealed class StampFieldsTests +{ + [Theory] + [InlineData(StampField.Designation, 2)] + [InlineData(StampField.Name, 1)] + [InlineData(StampField.Material, 3)] + public void ColumnId_maps_known_fields(StampField field, int expected) + => Assert.Equal(expected, StampFields.ColumnId(field)); + + [Fact] + public void ColumnId_throws_on_unknown() + => Assert.Throws(() => StampFields.ColumnId((StampField)999)); + + [Fact] + public void Collect_skips_null_empty_and_whitespace() + => Assert.Empty(StampFields.Collect(null, "", " ")); + + [Fact] + public void Collect_trims_and_maps_provided_fields() + { + var result = StampFields.Collect(" ДЕТАЛЬ.001 ", null, "Сталь 45"); + + Assert.Equal(2, result.Count); + Assert.Contains(result, t => t.ColumnId == 2 && t.Text == "ДЕТАЛЬ.001"); // designation + Assert.Contains(result, t => t.ColumnId == 3 && t.Text == "Сталь 45"); // material + Assert.DoesNotContain(result, t => t.ColumnId == 1); // name не задан + } + + [Fact] + public void Collect_includes_name_as_column_1() + { + var result = StampFields.Collect(null, "Кронштейн", null); + Assert.Single(result); + Assert.Equal((1, "Кронштейн"), result[0]); + } +} From eaa4a567088ae6979277c5f6c6d2ce0459c48d85 Mon Sep 17 00:00:00 2001 From: Shahovalov MIkhail Date: Wed, 27 May 2026 17:25:41 +0300 Subject: [PATCH 3/4] =?UTF-8?q?feat:=20drawing=5Ffill=5Ftitle=5Fblock=20?= =?UTF-8?q?=E2=80=94=20=D1=83=D0=BF=D1=80=D0=BE=D1=87=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BF=D0=BE=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E=20?= =?UTF-8?q?Codex=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #3/#6: доступ к графе через RequireStampCell(stamp,columnId) — null-check ячейки + единое место валидации (запись и чтение). #4: проверка columnId>0 в helper (защищает и ReadStampCellAsync). #2/#5: нетранзакционность записи зафиксирована комментарием (откат при Update()==FALSE спекулятивен, не делаем). RCW — долг v2-2. Тесты без изменений в числе: 123 unit + 65 integration = 188 зелёных. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../2026-05-27-drawing-title-block-design.md | 13 ++++++++++++- src/Kompas.Mcp.Core/Drawings/DrawingService.cs | 16 ++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/docs/superpowers/specs/2026-05-27-drawing-title-block-design.md b/docs/superpowers/specs/2026-05-27-drawing-title-block-design.md index ef10d9e..d8057b4 100644 --- a/docs/superpowers/specs/2026-05-27-drawing-title-block-design.md +++ b/docs/superpowers/specs/2026-05-27-drawing-title-block-design.md @@ -1,7 +1,18 @@ # Дизайн: основная надпись чертежа (drawing_fill_title_block) через API7 **Дата:** 2026-05-27 -**Статус:** реализовано и проверено (4 интеграционных + 7 unit, всего 188); ревью Codex спека учтено +**Статус:** реализовано и проверено (4 интеграционных + 7 unit, всего 188); ревью Codex спека и реализации учтено + +## Правки по ревью реализации Codex + +- **null-check ячейки** (#3): доступ к графе через `RequireStampCell(stamp, columnId)` — проверяет + `columnId > 0` и `Text[columnId] != null` с диагностикой; используется в записи и чтении (единое + место валидации, #6). +- **`columnId <= 0`** (#4): валидируется в `RequireStampCell` (защищает и `ReadStampCellAsync`). +- **Нетранзакционность** (#2/#5): записываем все графы, затем один `Update()`; при `Update()==FALSE` + откат старых значений не делаем — зафиксировано комментарием как осознанное поведение (откат + спекулятивен, сценарий невоспроизводим). +- **RCW** — осознанный долг (v2-2), точечный release не вводим. ## Находка спайка: `Str` ПЕРЕЗАПИСЫВАЕТ (Clear не нужен) diff --git a/src/Kompas.Mcp.Core/Drawings/DrawingService.cs b/src/Kompas.Mcp.Core/Drawings/DrawingService.cs index a0b3d9f..7a2d6b8 100644 --- a/src/Kompas.Mcp.Core/Drawings/DrawingService.cs +++ b/src/Kompas.Mcp.Core/Drawings/DrawingService.cs @@ -46,8 +46,11 @@ public sealed class DrawingService throw new ArgumentException("Укажите хотя бы одно поле основной надписи (designation/name/material)."); var stamp = RequireActiveStamp(); + // Нетранзакционно: все графы записываются, затем один Update() фиксирует. При Update()==FALSE + // (на практике не воспроизводится) откат старых значений не делаем — он спекулятивен (Str уже + // на in-memory объектах графы, повторный Update мог бы тоже упасть); сообщаем об ошибке. foreach (var (columnId, text) in fields) - stamp.Text[columnId].Str = text; // Str замещает содержимое (Clear не нужен) + RequireStampCell(stamp, columnId).Str = text; // Str замещает содержимое (Clear не нужен) if (!stamp.Update()) throw new InvalidOperationException("IStamp.Update вернул FALSE — основная надпись не обновлена."); return fields.Count; @@ -58,9 +61,18 @@ public sealed class DrawingService => _dispatcher.InvokeAsync(() => { var stamp = RequireActiveStamp(); - return stamp.Text[columnId]?.Str ?? string.Empty; + return RequireStampCell(stamp, columnId).Str ?? string.Empty; }, ct); + /// Получить графу основной надписи по номеру с диагностикой (номер > 0, ячейка != null). + private static IText RequireStampCell(IStamp stamp, int columnId) + { + if (columnId <= 0) + throw new ArgumentOutOfRangeException(nameof(columnId), "Номер графы основной надписи должен быть > 0."); + return stamp.Text[columnId] + ?? throw new InvalidOperationException($"Графа {columnId} основной надписи недоступна (Text[{columnId}] == null)."); + } + private IStamp RequireActiveStamp() { var doc2d = RequireActiveDrawing(); From 034e9aee243b0b9394ec192fd71f96f698f0f631 Mon Sep 17 00:00:00 2001 From: Shahovalov MIkhail Date: Wed, 27 May 2026 17:31:31 +0300 Subject: [PATCH 4/4] =?UTF-8?q?docs:=20drawing=5Ffill=5Ftitle=5Fblock=20?= =?UTF-8?q?=E2=80=94=20=D0=BE=D1=84=D0=BE=D1=80=D0=BC=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D1=87=D0=B5=D1=80=D1=82=D0=B5=D0=B6=D0=B0=20(74?= =?UTF-8?q?=20=D0=B8=D0=BD=D1=81=D1=82=D1=80=D1=83=D0=BC=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=B0,=20188=20=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit README/CLAUDE/ARCHITECTURE/OPEN_QUESTIONS/presentation.html: счётчики 73→74, 177→188; drawing_fill_title_block в группе Drawing; факты основной надписи (LayoutSheets.ItemByNumber[1].Stamp, Text[id].Str индексировано, StampField→графы). Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 6 +++--- README.md | 6 +++--- docs/ARCHITECTURE.md | 11 ++++++----- docs/OPEN_QUESTIONS.md | 5 ++++- docs/presentation.html | 16 ++++++++-------- 5 files changed, 24 insertions(+), 20 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index a670d76..5041b64 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -25,7 +25,7 @@ The base is committed to the repo (canonical) — no regeneration step. It cover **v1 + v2 + STEP/assembly + direct B-rep edit + structural model inspection implemented and working** (full sketch→feature→inspect→STEP round-trip + move_face + describe_model validated end-to-end). Stack: **.NET 8 (`net8.0-windows`, x64), C#**, MCP via the official `ModelContextProtocol` SDK over **stdio**. -**73 MCP tools, 177 tests green (116 unit + 61 integration).** v2 added: sketch-on-face (by point and by index), revolve (boss/cut + sketch axis), fillet/chamfer (edge-by-point and by index), and Query tools `get_part_info` (МЦХ), `get_bounding_box`, `list_faces`, `list_edges`. After v2: `import_step`, `export_step` (`ConversionService`, `ConversionTools`), `list_components` (assembly traversal via `TopPart → IParts7`). `move_face` (`FaceEditService`, `EditTools`) — direct B-rep face editing. After move_face: **structural model inspection** — `describe_model`, `list_features`, `list_bodies`, `list_variables`, `describe_face`, `describe_edge`, `measure` (`ModelInspectionService`, `InspectionTools`). `describe_model` is the preferred first call over `model_snapshot` (no token cost for image context; gives feature tree, bodies, variables, topology summary, МЦХ). Package A «richer sketches»: 7 new sketch primitives — `sketch_add_arc`, `sketch_add_arc_3points`, `sketch_add_ellipse`, `sketch_add_polyline`, `sketch_add_polygon`, `sketch_add_spline`, `sketch_add_point`. `PartModeler` refactored into partial classes: `PartModeler.cs` (core), `PartModeler.Sketch.cs` (2D primitives), `PartModeler.Features.cs` (extrude/revolve/fillet/chamfer). Static `SketchGeometry` class in `Core/Modeling`. Package B «forming ops» complete: **`shell`** (оболочка, `o3d_shellOperation=43`) + **`rib`** (ребро жёсткости, `o3d_ribOperation=44`) + **`sweep`** (кинематическая операция, `o3d_baseEvolution=45`) + **`loft`** (по сечениям, `o3d_baseLoft=30`). Auxiliary geometry (start of package E): **`sketch_create_on_offset_plane`** (смещённая плоскость, `o3d_planeOffset=14`) — unlocked `loft`. Additional Edit tools: **`split_solid_by_plane`**, **`move_body`**, **`boolean_union`**. Package C «patterns & mirror» complete: **`linear_pattern`** (линейный массив, `o3d_meshCopy=35`) + **`circular_pattern`** (круговой массив, `o3d_circularCopy=36`) + **`mirror_operation`** (зеркальная копия операций, `o3d_mirrorOperation=48`) + **`mirror_body`** (зеркало тела, `o3d_mirrorAllOperation=49`). **`hole`** (`HoleService`, `FeatureTools`) — цилиндрическое отверстие (сквозное или глухое) через **API7** (`IModelContainer`/`IHole3D`/`IHoleDisposal`); первая формообразующая операция на API7 (прецедент ранее только у `move_face`). **`hole_counterbore`** — отверстие с цековкой (`ksHTCounterbore`, `ISpotfacingHoleParameters`). **`hole_countersink`** — отверстие с зенковкой (`ksHTCountersinking`, `ICountersinkHoleParameters`). **`hole_conic`** — коническое отверстие (`ksHTConic`, `IConicHoleParameters`: `ConicType=ksCNAngle`, `ConicAngle`); завершает набор типов отверстий. `HoleCore` рефакторен: принимает `ksHoleTypeEnum holeType` + `Action configure` (настройка `HoleParameters` после установки `HoleType`, т.к. параметрический подынтерфейс недоступен до фиксации типа). Базовый `hole` = `ksHTBase` + `configure=null`. **`draft`** (уклон, `o3d_incline=42`) — наклон граней на угол относительно нейтральной координатной плоскости; реализован через **API5** `ksInclineDefinition` (операция называется Incline в API5, не Draft). Package D «parametrics» started: **`create_variable`**, **`set_variable`**, **`delete_variable`** (`VariableService`, `VariableTools`) — CRUD переменных модели через API5. `list_variables` исправлен (читает `ksPart.GetFeature().VariableCollection`, а не `ksPart.VariableCollection()`). **Ограничение:** переменная управляет геометрией только в параметрической модели (где размеры эскиза связаны с именем переменной); наши эскизы строятся литеральными координатами → `set_variable` хранит/вычисляет значение, но геометрию не меняет. Связь эскизных размеров с переменными (API2D) — не реализована. **Assembly class:** **`assembly_add_component`** (`AssemblyService`, `AssemblyTools`, namespace `Kompas.Mcp.Core.Assemblies`) — вставка компонента (.m3d/.a3d) из файла в активную сборку с заданием положения origin (мм, мировая СК сборки); возвращает индекс и имя вставленного компонента. **`assembly_add_mate`** — наложить сопряжение между гранями двух компонентов активной сборки, выбранными по мировым точкам; `mateType`: `coincidence` (грани заподлицо) | `distance` (зазор `value` мм, `value>0`); решатель позиционирует компоненты; возвращает статус (`valid`). Подтверждено вживую: `coincidence` (ширина сборки 120→40 мм), `distance(30)` (→70 мм). **2D-чертёж (начало вехи):** **`drawing_create_standard_views`** (`DrawingService`, `DrawingTools`, namespace `Kompas.Mcp.Core.Drawings`) — создать стандартные ассоциативные виды (спереди/сверху/слева) сохранённой 3D-модели (.m3d/.a3d) на активном чертеже; возвращает число созданных видов (3). Первый инструмент работы с чертежом. +**74 MCP tools, 188 tests green (123 unit + 65 integration).** v2 added: sketch-on-face (by point and by index), revolve (boss/cut + sketch axis), fillet/chamfer (edge-by-point and by index), and Query tools `get_part_info` (МЦХ), `get_bounding_box`, `list_faces`, `list_edges`. After v2: `import_step`, `export_step` (`ConversionService`, `ConversionTools`), `list_components` (assembly traversal via `TopPart → IParts7`). `move_face` (`FaceEditService`, `EditTools`) — direct B-rep face editing. After move_face: **structural model inspection** — `describe_model`, `list_features`, `list_bodies`, `list_variables`, `describe_face`, `describe_edge`, `measure` (`ModelInspectionService`, `InspectionTools`). `describe_model` is the preferred first call over `model_snapshot` (no token cost for image context; gives feature tree, bodies, variables, topology summary, МЦХ). Package A «richer sketches»: 7 new sketch primitives — `sketch_add_arc`, `sketch_add_arc_3points`, `sketch_add_ellipse`, `sketch_add_polyline`, `sketch_add_polygon`, `sketch_add_spline`, `sketch_add_point`. `PartModeler` refactored into partial classes: `PartModeler.cs` (core), `PartModeler.Sketch.cs` (2D primitives), `PartModeler.Features.cs` (extrude/revolve/fillet/chamfer). Static `SketchGeometry` class in `Core/Modeling`. Package B «forming ops» complete: **`shell`** (оболочка, `o3d_shellOperation=43`) + **`rib`** (ребро жёсткости, `o3d_ribOperation=44`) + **`sweep`** (кинематическая операция, `o3d_baseEvolution=45`) + **`loft`** (по сечениям, `o3d_baseLoft=30`). Auxiliary geometry (start of package E): **`sketch_create_on_offset_plane`** (смещённая плоскость, `o3d_planeOffset=14`) — unlocked `loft`. Additional Edit tools: **`split_solid_by_plane`**, **`move_body`**, **`boolean_union`**. Package C «patterns & mirror» complete: **`linear_pattern`** (линейный массив, `o3d_meshCopy=35`) + **`circular_pattern`** (круговой массив, `o3d_circularCopy=36`) + **`mirror_operation`** (зеркальная копия операций, `o3d_mirrorOperation=48`) + **`mirror_body`** (зеркало тела, `o3d_mirrorAllOperation=49`). **`hole`** (`HoleService`, `FeatureTools`) — цилиндрическое отверстие (сквозное или глухое) через **API7** (`IModelContainer`/`IHole3D`/`IHoleDisposal`); первая формообразующая операция на API7 (прецедент ранее только у `move_face`). **`hole_counterbore`** — отверстие с цековкой (`ksHTCounterbore`, `ISpotfacingHoleParameters`). **`hole_countersink`** — отверстие с зенковкой (`ksHTCountersinking`, `ICountersinkHoleParameters`). **`hole_conic`** — коническое отверстие (`ksHTConic`, `IConicHoleParameters`: `ConicType=ksCNAngle`, `ConicAngle`); завершает набор типов отверстий. `HoleCore` рефакторен: принимает `ksHoleTypeEnum holeType` + `Action configure` (настройка `HoleParameters` после установки `HoleType`, т.к. параметрический подынтерфейс недоступен до фиксации типа). Базовый `hole` = `ksHTBase` + `configure=null`. **`draft`** (уклон, `o3d_incline=42`) — наклон граней на угол относительно нейтральной координатной плоскости; реализован через **API5** `ksInclineDefinition` (операция называется Incline в API5, не Draft). Package D «parametrics» started: **`create_variable`**, **`set_variable`**, **`delete_variable`** (`VariableService`, `VariableTools`) — CRUD переменных модели через API5. `list_variables` исправлен (читает `ksPart.GetFeature().VariableCollection`, а не `ksPart.VariableCollection()`). **Ограничение:** переменная управляет геометрией только в параметрической модели (где размеры эскиза связаны с именем переменной); наши эскизы строятся литеральными координатами → `set_variable` хранит/вычисляет значение, но геометрию не меняет. Связь эскизных размеров с переменными (API2D) — не реализована. **Assembly class:** **`assembly_add_component`** (`AssemblyService`, `AssemblyTools`, namespace `Kompas.Mcp.Core.Assemblies`) — вставка компонента (.m3d/.a3d) из файла в активную сборку с заданием положения origin (мм, мировая СК сборки); возвращает индекс и имя вставленного компонента. **`assembly_add_mate`** — наложить сопряжение между гранями двух компонентов активной сборки, выбранными по мировым точкам; `mateType`: `coincidence` (грани заподлицо) | `distance` (зазор `value` мм, `value>0`); решатель позиционирует компоненты; возвращает статус (`valid`). Подтверждено вживую: `coincidence` (ширина сборки 120→40 мм), `distance(30)` (→70 мм). **2D-чертёж (веха, инкремент 2):** **`drawing_create_standard_views`** (`DrawingService`, `DrawingTools`, namespace `Kompas.Mcp.Core.Drawings`) — создать стандартные ассоциативные виды (спереди/сверху/слева) сохранённой 3D-модели (.m3d/.a3d) на активном чертеже; возвращает число созданных видов (3). **`drawing_fill_title_block`** — заполнить графы основной надписи (штампа) активного чертежа: `designation` (обозначение, графа 2), `name` (наименование изделия, графа 1), `material` (материал, графа 3); передаются только нужные поля (null/пусто пропускается, нужно хотя бы одно); возвращает число заполненных граф. See [`README.md`](README.md) and [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md); design decisions/caveats in [`docs/OPEN_QUESTIONS.md`](docs/OPEN_QUESTIONS.md). @@ -53,7 +53,7 @@ Key implementation facts (don't relearn): - **Structural model inspection** (`ModelInspectionService`, `InspectionTools`): `describe_model` — one-call structural "passport" (bounding box + МЦХ + bodies + topology summary + feature tree + variables); preferred over snapshot. `list_features` — feature tree with params (depth/radius/legs). `list_bodies` — list solid/surface bodies with face count. `list_variables` — model variables (name/expression/value, external/info flags); reads via `ksPart.GetFeature().VariableCollection` (all variables, including user-created) with fallback to `ksPart.VariableCollection()` (external-only — bug was fixed). `describe_face` — drill-down by index (type, area, normal, radius, edge count). `describe_edge` — drill-down by index (type, length, adjacent faces, vertices). `measure` — distance/angle between two objects (face|edge|vertex by index, unit `ST_MIX_MM`). - **Variable management (package D start, `VariableService`, `VariableTools`)**: `create_variable(name, value, note?, external?)` — creates a model variable; `set_variable(name, expression)` — sets expression (constant `"30"` or formula `"width*2+5"`); `delete_variable(name)` — deletes (fails if dependents exist). **Key API facts (don't relearn):** variable creation MUST use `ksPart.GetFeature().VariableCollection` (property on root ksFeature) — NOT `ksPart.VariableCollection()` (returns external-only). Expression is the leading field; value is derived. Changes applied via `ksPart.RebuildModel()` (return checked); after rebuild the RCW variable is stale → re-read via fresh collection (`ReadValueFresh`). Dependent variables recalculate automatically. Deletion fails if dependents exist (RemoveVariable returns FALSE). **Geometry limitation:** variables control geometry only in a parametric model where sketch dimensions are linked to variable names; our sketches are built with literal coordinates → `set_variable` stores/computes the value but does NOT change geometry. Linking sketch dimensions to variables (parametric sketches via API2D) is not yet implemented. - **Feature tree API** (don't relearn): read via API5 `ksPart.GetFeature()` → `(ksFeature).SubFeatureCollection(true,false)` → `ksFeatureCollection`. Cast `(ksFeature)part` does NOT work (RCW QI returns null) — must use `GetFeature()`. `ksFeature.type` returns only coarse `o3d_entity` and does NOT distinguish operations; precise type and params come from `ksFeature.GetObject()` → `ksEntity.GetDefinition()` and matching definition type (`ksBossExtrusionDefinition.GetSideParam`, `ksFilletDefinition.radius`, `ksChamferDefinition.GetChamferParam`, …). Node name ("Элемент выдавливания:1", "Скругление:1") is localized by КОМПАС itself. -- **STEP import/export, `list_components`, `move_face`, `split_solid_by_plane`, `move_body`, `boolean_union`, full inspection layer, richer sketch primitives (package A), `shell`, `rib`, `sweep`, `loft` (package B complete), `sketch_create_on_offset_plane` (package E start), `linear_pattern`, `circular_pattern`, `mirror_operation`, `mirror_body` (package C complete), `hole`, `hole_counterbore`, `hole_countersink`, `hole_conic` (all API7 via `HoleService`; `hole_conic` uses `ksHTConic`/`IConicHoleParameters`), `draft` (API5 `ksInclineDefinition`), `create_variable`/`set_variable`/`delete_variable` (package D start), `assembly_add_component`, `assembly_add_mate` (both API7, `AssemblyService`; mate types `coincidence`/`distance` verified), `drawing_create_standard_views` (API7, `DrawingService`, namespace `Kompas.Mcp.Core.Drawings`) are done.** Not yet done: parametric sketches — **investigated, unavailable via COM API** (`ksCDimWithVariable` cannot be constructed from external automation; see `docs/superpowers/specs/2026-05-27-parametric-sketch-findings.md`); 2D-чертёж: оформление (размеры, рамка, штамп) — далее; additional mate types (parallel/perpendicular/concentric/angle/tangency); package E continuation (axis, angle plane). Known caveat: boss/cut direction on a selected face depends on face-normal orientation (`forward` may need flipping — agent picks via snapshot or `describe_face` normal). See `docs/OPEN_QUESTIONS.md` → «Ревью v2». +- **STEP import/export, `list_components`, `move_face`, `split_solid_by_plane`, `move_body`, `boolean_union`, full inspection layer, richer sketch primitives (package A), `shell`, `rib`, `sweep`, `loft` (package B complete), `sketch_create_on_offset_plane` (package E start), `linear_pattern`, `circular_pattern`, `mirror_operation`, `mirror_body` (package C complete), `hole`, `hole_counterbore`, `hole_countersink`, `hole_conic` (all API7 via `HoleService`; `hole_conic` uses `ksHTConic`/`IConicHoleParameters`), `draft` (API5 `ksInclineDefinition`), `create_variable`/`set_variable`/`delete_variable` (package D start), `assembly_add_component`, `assembly_add_mate` (both API7, `AssemblyService`; mate types `coincidence`/`distance` verified), `drawing_create_standard_views` (API7, `DrawingService`, namespace `Kompas.Mcp.Core.Drawings`), `drawing_fill_title_block` (API7, `DrawingService`; заполнение основной надписи/штампа через `IStamp`) are done.** Not yet done: parametric sketches — **investigated, unavailable via COM API** (`ksCDimWithVariable` cannot be constructed from external automation; see `docs/superpowers/specs/2026-05-27-parametric-sketch-findings.md`); 2D-чертёж: размеры/обозначения на видах, рамка/формат — далее; additional mate types (parallel/perpendicular/concentric/angle/tangency); package E continuation (axis, angle plane). Known caveat: boss/cut direction on a selected face depends on face-normal orientation (`forward` may need flipping — agent picks via snapshot or `describe_face` normal). See `docs/OPEN_QUESTIONS.md` → «Ревью v2». - **"STEP import without history"** detected structurally: `bodyCount > 0 && no formative features && features.Count <= bodyCount+1` (only origin + body). STEP with edits (move_face: "Смещённая плоскость", "Разрезать", "Переместить грани", "Булева операция") — that already has history. - **Topology/measure API**: `ksFaceDefinition.EdgeCollection` / `GetCylinderParam` / `GetSurface().GetNormal` + `normalOrientation`; `ksEdgeDefinition.GetAdjacentFace(bool)` / `GetVertex(bool)` → `ksVertexDefinition.GetPoint`; bodies via `ksPart.BodyCollection()` → `ksBody` (`IsSolid` / `FaceCollection`); all variables via `ksPart.GetFeature().VariableCollection` → `ksVariable` (external-only: `ksPart.VariableCollection()` — do NOT use for reading all variables); measurements via `ksPart.GetMeasurer()` → `ksMeasurer` (`SetObject1/2`, `unit=ST_MIX_MM`, `Calc`, `distance`/`MinDistance`/`angle` in degrees / `IsAngleValid`). - **STEP import COM pattern** (verified): `IApplication.get_Converter((object)(int)ksConverterFromSTEP=-3)` (pass format code, not DLL path) → `IConverter.ConverterParameters(cmd)` → set `IAdditionConvertParameters.Format=ksConverterFromSTEP` → `IKompasDocument3D1.ConvertFromAdditionFormat(path, prm)`. Export: `ConvertToAdditionFormat` with format codes for AP203/AP214/AP242. Param co-classes (AdditionConvertParameters etc.) are NOT CoCreatable — only via converter factories. Assembly traversal: `IKompasDocument3D.TopPart → IPart7.Parts (IParts7)`. Extract component: `prm.NeedCreateComponentsFiles=true` (writes .m3d files next to STEP) + `IPart7.OpenSourceDocument`. @@ -67,7 +67,7 @@ Key implementation facts (don't relearn): - **Hole operations (`hole`, `hole_counterbore`, `hole_countersink`, `hole_conic`)**: all implemented via **API7** (not API5 — `ksHoleDefinition` absent in interop). Service `src/Kompas.Mcp.Core/Modeling/HoleService.cs`. `HoleCore` helper is parameterised with `ksHoleTypeEnum holeType` + `Action configure` callback (configure sets `HoleParameters` **after** `HoleType` is assigned, because the type-specific sub-interface — e.g. `ISpotfacingHoleParameters` — is not accessible until the type is fixed). Base `hole` = `ksHTBase` + `configure=null`. `hole_counterbore`: `ksHTCounterbore` + configure sets `(ISpotfacingHoleParameters)hole.HoleParameters` (`SpotfacingDiameter`, `SpotfacingDepth`); validates `spotDiameter>diameter` and `depth>spotDepth` for blind. `hole_countersink`: `ksHTCountersinking` + configure sets `(ICountersinkHoleParameters)hole.HoleParameters` (`CountersinkType=ksCTDiameterAngle`, `CountersinkDiameter`, `CountersinkAngle`); validates `sinkDiameter>diameter`, `00`). Scope: `coincidence`/`distance` verified live; `parallel`/`perpendicular`/`concentric`/`angle`/`tangency` — future increments. DI: `AddSingleton()` in `Program.cs`. -- **Drawing service (`drawing_create_standard_views`, `DrawingService`, namespace `Kompas.Mcp.Core.Drawings`)**: entry via API7 `IKompasDocument2D` — requires an active drawing document (`DocumentType==ksDocumentDrawing`). Core call: `doc2d.ViewsAndLayersManager.Views.AddStandartViews(path, "#Спереди", projTypes, x, y, scale, dx=20, dy=20)` where `projTypes=object[]{1,3,5}` (ksPtFront/ksPtUp/ksPtLeft passed as SAFEARRAY VT_I4). Success check: `created==3` strictly; content check: sum of `IView.ObjectCount` for newly created views (identified by `IView.Number` delta) must be `>0`, otherwise error + rollback via `IView.Delete`. No rebuild needed — `ObjectCount>0` immediately on a new drawing. Validation: `DrawingValidation.NormalizeModelPath` (accepts .m3d/.a3d), `RequireScale>0`. Model file must be saved (`document_save_as`) before calling. Returns `DrawingViewsResult{Created,Total}`. DI: `AddSingleton()` in `Program.cs`. Confirmed live: `Views.Count` 1→4 (system view + 3 projections). +- **Drawing service (`drawing_create_standard_views`, `drawing_fill_title_block`; `DrawingService`, namespace `Kompas.Mcp.Core.Drawings`)**: entry via API7 `IKompasDocument2D` — requires an active drawing document (`DocumentType==ksDocumentDrawing`). Standard views: `doc2d.ViewsAndLayersManager.Views.AddStandartViews(path, "#Спереди", projTypes, x, y, scale, dx=20, dy=20)` where `projTypes=object[]{1,3,5}` (ksPtFront/ksPtUp/ksPtLeft passed as SAFEARRAY VT_I4). Success check: `created==3` strictly; content check: sum of `IView.ObjectCount` for newly created views (identified by `IView.Number` delta) must be `>0`, otherwise error + rollback via `IView.Delete`. No rebuild needed — `ObjectCount>0` immediately on a new drawing. Validation: `DrawingValidation.NormalizeModelPath` (accepts .m3d/.a3d), `RequireScale>0`. Model file must be saved (`document_save_as`) before calling. Returns `DrawingViewsResult{Created,Total}`. Confirmed live: `Views.Count` 1→4 (system view + 3 projections). **Title block / stamp** (`drawing_fill_title_block`): `doc2d.LayoutSheets.ItemByNumber[1].Stamp` (`IStamp`) → `stamp.Text[columnId].Str = text` (indexed property, `IText.Str` replaces content — no `Clear` needed, overwrite confirmed) → `stamp.Update()`. Own enum `StampField {Designation, Name, Material}` + static `StampFields.ColumnId` (→ 2/1/3, `ksStampEnum`) and `Collect` (gathers non-empty trimmed fields). `RequireStampCell` validates null + `columnId>0`. `RequireActiveDrawing` shared with views check. Write is non-transactional (all cells → single `Update`). New file `src/Kompas.Mcp.Core/Drawings/StampField.cs`; tool added to existing `DrawingTools.cs`. DI: `AddSingleton()` in `Program.cs`. - **Richer sketch primitives (package A, ksDocument2D API5 wrappers)**: `ksArcBy3Points` (3-point arc), `ksArcByAngle` (centre/radius/start-end angles in degrees, counterClockwise flag), `ksEllipse` via `ksEllipseParam` — struct obtained via `KompasObject.GetParamStruct(ko_EllipseParam=22)`; **property names are `A`/`B` (uppercase) in the interop**; `ksRegularPolygon` via `ksRegularPolygonParam` (`ko_RegularPolygonParam=92`) — `describe = !inscribed`; NURBS spline via `ksNurbs(order=4)` + `ksNurbsPoint` loop + `ksEndObj`; `ksPoint`. Param structs are released after use. `PartModeler` split into partial classes: `PartModeler.cs` (registry/helpers/NewParam/reset), `PartModeler.Sketch.cs` (all 2D primitives), `PartModeler.Features.cs` (extrude/revolve/fillet/chamfer). Static `SketchGeometry` class (`Core/Modeling`) holds enum mappings (`ArcDirection`, `PolygonDescribe`) and validators (`RequirePositive`, `RequireVertexCount`, `RequirePoints`). Polyline/spline point lists use `record SketchPoint(X, Y)` with JSON names `x`/`y`. ## КОМПАС-3D API architecture (the critical context) diff --git a/README.md b/README.md index cac8c41..2589b04 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ src/Kompas.Mcp.Host/bin/Release/net8.0-windows/kompas-mcp.exe } ``` -## Инструменты (73 инструмента) +## Инструменты (74 инструмента) | Группа | Инструменты | |---|---| @@ -54,7 +54,7 @@ src/Kompas.Mcp.Host/bin/Release/net8.0-windows/kompas-mcp.exe | Variables | `create_variable`, `set_variable`, `delete_variable` | | Conversion | `import_step`, `export_step` | | Assembly | `assembly_add_component`, `assembly_add_mate` | -| Drawing | `drawing_create_standard_views` | +| Drawing | `drawing_create_standard_views`, `drawing_fill_title_block` | | Validation | `validate_part` | ### Типовой сценарий @@ -73,7 +73,7 @@ src/Kompas.Mcp.Host/bin/Release/net8.0-windows/kompas-mcp.exe ``` src/Kompas.Mcp.Core/ COM-слой: STA-диспетчер, подключение, документы, эскизы/операции, конвертация, снимок, инспекция модели src/Kompas.Mcp.Host/ MCP-сервер (stdio) + определения инструментов -tests/Kompas.Mcp.Tests/ 177 тестов: unit + integration (integration требуют КОМПАС) +tests/Kompas.Mcp.Tests/ 188 тестов: unit + integration (integration требуют КОМПАС) libs/kompas-interop/ вендорские interop-сборки КОМПАС (из SDK Samples/Common) docs/ архитектура, план, презентация, MD-база знаний SDK (Kompas3D_SDK/) usecases/ полигон обкатки подходов (в .gitignore); приёмы поднимаются в навык kompas-3d diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index d0c877d..4c3e185 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -1,6 +1,6 @@ # Архитектура MCP-сервера КОМПАС-3D (предлагаемый вариант) -> Статус: **реализовано и работает** (v1+v2+STEP/assembly+direct-edit+inspection+package-A «богатые эскизы»+package-B «shell+rib+sweep+loft»+package-C «массивы и зеркало»+package-D start «переменные»+package-E «offset plane»+`hole`+`hole_counterbore`+`hole_countersink`+`hole_conic`+`draft`+`assembly_add_component`+`assembly_add_mate`+`drawing_create_standard_views` (начало вехи «2D-чертёж»)). Актуализировано по коду. +> Статус: **реализовано и работает** (v1+v2+STEP/assembly+direct-edit+inspection+package-A «богатые эскизы»+package-B «shell+rib+sweep+loft»+package-C «массивы и зеркало»+package-D start «переменные»+package-E «offset plane»+`hole`+`hole_counterbore`+`hole_countersink`+`hole_conic`+`draft`+`assembly_add_component`+`assembly_add_mate`+`drawing_create_standard_views`+`drawing_fill_title_block` (веха «2D-чертёж», инкремент 2)). Актуализировано по коду. > Сопутствующий контекст по COM API КОМПАС — в [`../CLAUDE.md`](../CLAUDE.md). > Имена интерфейсов и перечислений сверены со справкой SDK по MD-базе знаний `docs/Kompas3D_SDK/` (навык `kompas-sdk-research`). @@ -113,7 +113,7 @@ MCP client ──stdio──> Host (поток-пул, async) |---|---| | **Kompas.Mcp.Host** | Точка входа. Сборка MCP-сервера (stdio), DI (в т.ч. `ConversionService`), логи в stderr, старт и владение STA-потоком, graceful shutdown. Определения инструментов по категориям (System / Documents / Sketch / Features / Query / Conversion). **Тонкий слой**: валидация аргументов → постановка задачи на STA-поток → форматирование результата/ошибки в MCP-ответ. | | **Kompas.Mcp.Core** | COM-слой. Менеджер соединения, менеджер документов, построитель эскизов и операций, `ConversionService` (STEP импорт/экспорт), `QueryService` (МЦХ, грани, рёбра, компоненты), `ModelInspectionService` (дерево операций, тела, переменные, drill-down, измерения), `AssemblyService` (вставка компонентов в сборку, namespace `Kompas.Mcp.Core.Assemblies`), `DrawingService` (стандартные виды чертежа, namespace `Kompas.Mcp.Core.Drawings`), снимок. Все паттерны API5/API7 живут здесь. | -| **Kompas.Mcp.Tests** | Юнит (без COM) + интеграционные (требуют КОМПАС). 177 тестов (116 unit + 61 integration). Все интеграционные классы наследуют `IntegrationTestBase` (`IAsyncLifetime`), который вызывает `DocumentService.CloseAllAsync` после каждого теста. | +| **Kompas.Mcp.Tests** | Юнит (без COM) + интеграционные (требуют КОМПАС). 188 тестов (123 unit + 65 integration). Все интеграционные классы наследуют `IntegrationTestBase` (`IAsyncLifetime`), который вызывает `DocumentService.CloseAllAsync` после каждого теста. | Принцип: **только `Core` знает про COM**. `Host`/Tools оперируют доменными DTO и вызывают `Core`; `Host` не содержит бизнес-логики. @@ -121,7 +121,7 @@ MCP client ──stdio──> Host (поток-пул, async) --- -## 5. Карта инструментов (73 инструмента) +## 5. Карта инструментов (74 инструмента) Сгруппированы вокруг центрального цикла «эскиз ↔ операция». Имена — `snake_case`. @@ -210,6 +210,7 @@ MCP client ──stdio──> Host (поток-пул, async) **Drawing — 2D-чертёж (`DrawingService`, `DrawingTools`, namespace `Kompas.Mcp.Core.Drawings`)** - `drawing_create_standard_views(partFilePath, scale, x, y)` — создать стандартные ассоциативные виды (спереди/сверху/слева, `ksPtFront/ksPtUp/ksPtLeft`) сохранённой 3D-модели (.m3d/.a3d) на активном чертеже. Реализовано через API7 `IKompasDocument2D.ViewsAndLayersManager.Views.AddStandartViews(path, "#Спереди", object[]{1,3,5}, x, y, scale, dx=20, dy=20)` — `object[]` передаётся как SAFEARRAY VT_I4. Проверки: `created==3` строго; непустота — сумма `IView.ObjectCount` новых видов (по разнице `IView.Number`) `>0`, иначе ошибка + откат (`IView.Delete`). Возвращает `DrawingViewsResult{Created,Total}`. Модель должна быть сохранена до вызова. +- `drawing_fill_title_block(designation?, name?, material?)` — заполнить графы основной надписи (штампа) активного чертежа. `designation` = обозначение документа (графа 2), `name` = наименование изделия (графа 1), `material` = материал (графа 3); нужно хотя бы одно поле. Реализовано: `doc2d.LayoutSheets.ItemByNumber[1].Stamp` (`IStamp`) → `stamp.Text[columnId].Str = text` (индексированное свойство; `IText.Str` замещает содержимое без `Clear`) → `stamp.Update()`. Номера граф `ksStampEnum`: обозначение=2, наименование=1, материал=3. Свой enum `StampField` + `StampFields.ColumnId/Collect` в `src/Kompas.Mcp.Core/Drawings/StampField.cs`. Возвращает число заполненных граф. **Vision — визуальная обратная связь (fallback)** - `model_snapshot` — отрендерить активный 3D-документ в PNG и вернуть **как image-контент MCP**, @@ -344,14 +345,14 @@ dotnet build -c Release -r win-x64 # сборка ## 10. Дорожная карта -**Реализовано (v1+v2+STEP/assembly+direct-edit+inspection+package-A+package-B+package-C+package-D start+package-E start+hole+hole_counterbore+hole_countersink+hole_conic+draft+assembly_add_component+assembly_add_mate+drawing_create_standard_views):** документы, эскизы (полный набор 2D-примитивов: линия, окружность, дуга, дуга по 3 точкам, прямоугольник, эллипс, ломаная, правильный многоугольник, сплайн NURBS, точка), **вспомогательная геометрия (`sketch_create_on_offset_plane`)**, выдавливание/вырез, вращение, скругление/фаска, **оболочка (`shell`)**, **ребро жёсткости (`rib`)**, **кинематическая операция (`sweep`)**, **операция по сечениям (`loft`)**, **линейный/круговой массив и зеркало (`linear_pattern`, `circular_pattern`, `mirror_operation`, `mirror_body`)**, **отверстие (`hole`, API7)**, **цековка (`hole_counterbore`, API7)**, **зенковка (`hole_countersink`, API7)**, **коническое отверстие (`hole_conic`, API7)**, **уклон (`draft`, API5 `ksInclineDefinition`)**, снимок; `get_part_info`, `get_bounding_box`, `list_faces`, `list_edges`; `import_step`, `export_step`, `list_components`; **`move_face`**, **`split_solid_by_plane`**, **`move_body`**, **`boolean_union`** (прямое редактирование и булевы операции); **`describe_model`, `list_features`, `list_bodies`, `list_variables`, `describe_face`, `describe_edge`, `measure`** (структурный осмотр модели); **`create_variable`, `set_variable`, `delete_variable`** (управление переменными, package D start); **`assembly_add_component`** (вставка компонента в сборку, API7, `AssemblyService`); **`assembly_add_mate`** (сопряжения `coincidence`/`distance`, API7, `IMateConstraints3D`); **`drawing_create_standard_views`** (стандартные ассоциативные виды чертежа, API7, `DrawingService`). +**Реализовано (v1+v2+STEP/assembly+direct-edit+inspection+package-A+package-B+package-C+package-D start+package-E start+hole+hole_counterbore+hole_countersink+hole_conic+draft+assembly_add_component+assembly_add_mate+drawing_create_standard_views+drawing_fill_title_block):** документы, эскизы (полный набор 2D-примитивов: линия, окружность, дуга, дуга по 3 точкам, прямоугольник, эллипс, ломаная, правильный многоугольник, сплайн NURBS, точка), **вспомогательная геометрия (`sketch_create_on_offset_plane`)**, выдавливание/вырез, вращение, скругление/фаска, **оболочка (`shell`)**, **ребро жёсткости (`rib`)**, **кинематическая операция (`sweep`)**, **операция по сечениям (`loft`)**, **линейный/круговой массив и зеркало (`linear_pattern`, `circular_pattern`, `mirror_operation`, `mirror_body`)**, **отверстие (`hole`, API7)**, **цековка (`hole_counterbore`, API7)**, **зенковка (`hole_countersink`, API7)**, **коническое отверстие (`hole_conic`, API7)**, **уклон (`draft`, API5 `ksInclineDefinition`)**, снимок; `get_part_info`, `get_bounding_box`, `list_faces`, `list_edges`; `import_step`, `export_step`, `list_components`; **`move_face`**, **`split_solid_by_plane`**, **`move_body`**, **`boolean_union`** (прямое редактирование и булевы операции); **`describe_model`, `list_features`, `list_bodies`, `list_variables`, `describe_face`, `describe_edge`, `measure`** (структурный осмотр модели); **`create_variable`, `set_variable`, `delete_variable`** (управление переменными, package D start); **`assembly_add_component`** (вставка компонента в сборку, API7, `AssemblyService`); **`assembly_add_mate`** (сопряжения `coincidence`/`distance`, API7, `IMateConstraints3D`); **`drawing_create_standard_views`** (стандартные ассоциативные виды чертежа, API7, `DrawingService`); **`drawing_fill_title_block`** (заполнение основной надписи/штампа: обозначение, наименование, материал; `IStamp.Text[id].Str`, API7, `DrawingService`). **Следующие приоритеты:** 1. Пакет D «параметрика» (продолжение) — связь размеров эскизов с переменными (параметрические эскизы через API2D). ⚠️ **Исследовано**: `ksCDimWithVariable` недоступен из внешней автоматизации — см. `docs/superpowers/specs/2026-05-27-parametric-sketch-findings.md`. 2. Пакет E «вспомогательная геометрия» (продолжение) — ось, точка, плоскость по трём точкам / по углу. 3. Рассечение/перемещение тела как MCP-инструменты (`SplitSolids`/`BodyRepositions`) — механика есть, продуктизация не закончена. 4. Свойства документа: `IPropertyMng` / `IPropertyKeeper`. -5. **2D-чертёж (продолжение):** оформление — размеры (`ILinearDimension`, …), рамка, штамп, штриховки, тексты. Стандартные виды реализованы (`drawing_create_standard_views`). +5. **2D-чертёж (продолжение):** размеры на видах (`ILinearDimension`, …), рамка/формат, штриховки, тексты. Стандартные виды реализованы (`drawing_create_standard_views`); основная надпись/штамп реализована (`drawing_fill_title_block`). 6. Сборки — продолжение: дополнительные типы сопряжений (`parallel`, `perpendicular`, `concentric`, `angle`, `tangency`; `coincidence`/`distance` реализованы); авто-позиционирование компонентов; спецификации (`ISpecification`). 7. Транспорт **HTTP/SSE** — как опция для удалённых клиентов. diff --git a/docs/OPEN_QUESTIONS.md b/docs/OPEN_QUESTIONS.md index 5999fdb..16fa7d6 100644 --- a/docs/OPEN_QUESTIONS.md +++ b/docs/OPEN_QUESTIONS.md @@ -190,4 +190,7 @@ stateful-сессии? Пока полагаемся на последовате **Решено (инкремент 2).** Новый инструмент `assembly_add_mate(mateType, x1,y1,z1, x2,y2,z2, value=0)`. Паттерн API7: `top.MateConstraints` (`IMateConstraints3D`) → `Add(MateConstraintType)` → `BaseObject1/2` (грани через `top.FindObjectsByPoint(x,y,z,FirstLevel=false)`) → `ParamValue` → `Update()` → `RebuildModel(true)`; проверка `mate.Valid`. Типы `mc_Coincidence=0`/`mc_Distance=5` проверены вживую. Enum `MateType` + static `Mates` в `src/Kompas.Mcp.Core/Assemblies/MateType.cs`. Итог: **72 инструмента, 156 тестов (98 unit + 58 integration).** Следующий шаг: прочие типы сопряжений (`parallel`, `perpendicular`, `concentric`, `angle`, `tangency`). ### ✅ Стандартные виды чертежа — реализованы (начало вехи «2D-чертёж») -**Решено.** Новый инструмент `drawing_create_standard_views(partFilePath, scale, x, y)` — создаёт ассоциативные виды (спереди/сверху/слева) на активном чертеже. Реализовано через API7 `DrawingService` (namespace `Kompas.Mcp.Core.Drawings`), `DrawingTools`. Паттерн: `IKompasDocument2D.ViewsAndLayersManager.Views.AddStandartViews(path, "#Спереди", object[]{1,3,5}, x, y, scale, 20, 20)` — `object[]` как SAFEARRAY VT_I4. Проверено вживую: `Views.Count` 1→4, `ObjectCount>0` сразу (rebuild не нужен). Итог: **73 инструмента, 177 тестов (116 unit + 61 integration).** Следующий шаг: оформление чертежа (размеры, рамка, штамп). +**Решено.** Новый инструмент `drawing_create_standard_views(partFilePath, scale, x, y)` — создаёт ассоциативные виды (спереди/сверху/слева) на активном чертеже. Реализовано через API7 `DrawingService` (namespace `Kompas.Mcp.Core.Drawings`), `DrawingTools`. Паттерн: `IKompasDocument2D.ViewsAndLayersManager.Views.AddStandartViews(path, "#Спереди", object[]{1,3,5}, x, y, scale, 20, 20)` — `object[]` как SAFEARRAY VT_I4. Проверено вживую: `Views.Count` 1→4, `ObjectCount>0` сразу (rebuild не нужен). + +### ✅ Основная надпись (штамп) чертежа — реализована (инкремент 2 вехи «2D-чертёж») +**Решено.** Новый инструмент `drawing_fill_title_block(designation?, name?, material?)` — заполняет графы основной надписи активного чертежа. Паттерн API7: `doc2d.LayoutSheets.ItemByNumber[1].Stamp` (`IStamp`) → `stamp.Text[columnId].Str = text` → `stamp.Update()`. `IText.Str` замещает содержимое напрямую (повторная запись перезаписывает — `Clear` не нужен, подтверждено round-trip тестом). Номера граф `ksStampEnum`: обозначение=2, наименование=1, материал=3. Свой enum `StampField` + `StampFields.ColumnId/Collect` в `src/Kompas.Mcp.Core/Drawings/StampField.cs`; инструмент в `DrawingTools.cs`. Итог: **74 инструмента, 188 тестов (123 unit + 65 integration).** Следующий шаг: размеры на видах. diff --git a/docs/presentation.html b/docs/presentation.html index 2b503b7..000f030 100644 --- a/docs/presentation.html +++ b/docs/presentation.html @@ -128,7 +128,7 @@
- Статус: v3+ работает — эскиз→операции→STEP→сборка→move_face→структурный осмотр→богатые эскизы→shell+rib+sweep+loft+массивы+зеркало+hole+hole_counterbore+hole_countersink+hole_conic+draft+переменные+assembly_add_component+assembly_add_mate+drawing_create_standard_views (73 инструмента) + Статус: v3+ работает — эскиз→операции→STEP→сборка→move_face→структурный осмотр→богатые эскизы→shell+rib+sweep+loft+массивы+зеркало+hole+hole_counterbore+hole_countersink+hole_conic+draft+переменные+assembly_add_component+assembly_add_mate+drawing_create_standard_views+drawing_fill_title_block (74 инструмента)

КОМПАС-3D MCP-сервер
управление CAD языком LLM

MCP-сервер, который превращает операции КОМПАС-3D — создание документов, эскизы, 3D-операции, параметры — в инструменты для языковой модели. Под капотом — @@ -261,7 +261,7 @@ впереди.

-
Общий прогрессv3+: STEP · move_face · структурный осмотр · богатые эскизы (пакет A) · shell+rib+sweep+loft (пакет B) · массивы+зеркало (пакет C) · переменные (пакет D start) · offset-plane (пакет E start) · hole (API7) · hole_counterbore · hole_countersink · hole_conic · draft (API5) · assembly_add_component · assembly_add_mate · drawing_create_standard_views · навык kompas-3d · 73 инструмента · 177 тестов
+
Общий прогрессv3+: STEP · move_face · структурный осмотр · богатые эскизы (пакет A) · shell+rib+sweep+loft (пакет B) · массивы+зеркало (пакет C) · переменные (пакет D start) · offset-plane (пакет E start) · hole (API7) · hole_counterbore · hole_countersink · hole_conic · draft (API5) · assembly_add_component · assembly_add_mate · drawing_create_standard_views · drawing_fill_title_block · навык kompas-3d · 74 инструмента · 188 тестов
@@ -297,7 +297,7 @@

Инструменты v3+ ГОТОВО

-

73 инструмента, отдаются по MCP-протоколу

+

74 инструмента, отдаются по MCP-протоколу

  • System: connect · status · set_visible
  • Documents: create · open · save · save_as · close · active
  • @@ -310,8 +310,8 @@
  • Variables: create_variable · set_variable · delete_variable (пакет D)
  • Conversion: import_step · export_step
  • Assembly: assembly_add_component (вставка компонента .m3d/.a3d в сборку, API7) · assembly_add_mate (сопряжения coincidence/distance, API7)
  • -
  • Drawing: drawing_create_standard_views (стандартные ассоциативные виды чертежа, API7)
  • -
  • 2D-чертёж: оформление (размеры, рамка, штамп) · пакет E (ось, угловая плоскость) · пакет D параметрика: параметрические эскизы (API2D) — исследовано, недоступно через COM API · прочие типы сопряжений (parallel/perpendicular/concentric/angle/tangency)
  • +
  • Drawing: drawing_create_standard_views (стандартные ассоциативные виды чертежа, API7) · drawing_fill_title_block (основная надпись/штамп: обозначение, наименование, материал, API7)
  • +
  • 2D-чертёж: размеры/обозначения на видах, рамка/формат · пакет E (ось, угловая плоскость) · пакет D параметрика: параметрические эскизы (API2D) — исследовано, недоступно через COM API · прочие типы сопряжений (parallel/perpendicular/concentric/angle/tangency)
@@ -322,7 +322,7 @@
  • Unit-тесты — без COM: диспетчер, enum-маппинг, StepFormat, InspectionText
  • Интеграционные тесты с КОМПАС: подключение, документы, снимок, цикл, STEP round-trip, сборка, move_face, инспекция
  • -
  • Итого 177 тестов зелёных (116 unit + 61 integration)
  • +
  • Итого 188 тестов зелёных (123 unit + 65 integration)
  • Сборка kompas-mcp.exe, README с конфигом клиента
  • Навык kompas-3d (методика) + полигон usecases/
  • In-process тест MCP-клиента, релизный publish
  • @@ -351,8 +351,8 @@
    отверстия под крепёж · готово ✓

    Цековка, зенковка и конус

    hole_counterbore (ksHTCounterbore) · hole_countersink (ksHTCountersinking) · hole_conic (ksHTConic, IConicHoleParameters) · HoleCore рефакторен (configure-колбэк) · 70 инструментов · 119 тестов

    сборки start · готово ✓

    Вставка компонентов

    assembly_add_component (API7 IParts7.AddFromFile + IPlacement3D)

    сборки инкремент 2 · готово ✓

    Сопряжения

    assembly_add_mate (coincidence/distance, API7 IMateConstraints3D) · IntegrationTestBase · 72 инструмента · 156 тестов

    -
    2D-чертёж · начато ▶

    Стандартные виды

    drawing_create_standard_views (AddStandartViews, API7) · 73 инструмента · 177 тестов · далее: оформление (размеры, рамка, штамп)

    -
    далее · в очереди

    пакет E + прочее

    вспомогательная геометрия (ось, угловая плоскость) · прочие типы сопряжений (parallel/perpendicular/concentric/angle/tangency) · пакет D параметрика — параметрические эскизы недоступны через COM API

    +
    2D-чертёж · инкремент 2 ✓

    Стандартные виды + основная надпись

    drawing_create_standard_views (AddStandartViews, API7) · drawing_fill_title_block (IStamp.Text[id].Str, API7) · 74 инструмента · 188 тестов · далее: размеры на видах

    +
    далее · в работе ▶

    Размеры и оформление

    Размеры/обозначения на видах · рамка/формат · пакет E (ось, угловая плоскость) · прочие типы сопряжений (parallel/perpendicular/concentric/angle/tangency) · пакет D параметрика — параметрические эскизы недоступны через COM API