Files
kompas3d-mcp/docs/superpowers/specs/2026-05-27-drawing-title-block-design.md
T
mikhail 742a97177b feat: drawing_fill_title_block — основная надпись чертежа (API7)
Веха 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) <noreply@anthropic.com>
2026-05-27 17:20:16 +03:00

8.7 KiB

Дизайн: основная надпись чертежа (drawing_fill_title_block) через API7

Дата: 2026-05-27 Статус: реализовано и проверено (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).

Цель

Веха 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) → если пусто, ошибка → RequireActiveDrawingsheet = LayoutSheets.ItemByNumber[1]stamp = (IStamp)sheet.Stamp → для каждого поля stamp.Text[columnId].Str = textstamp.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), рамка/формат листа.