Files
kompas3d-mcp/docs/superpowers/specs/2026-05-27-drawing-sheet-format-design.md
T
mikhail 56ed2cb0cf feat(drawing): формат и ориентация листа (drawing_set_sheet_format)
Задать формат (A0–A5/user) и ориентацию (книжная/альбомная) листа чертежа через
API7 ILayoutSheet.Format (ISheetFormat). Стандартный формат — размеры авто; user —
явные width/height (landscape игнорируется, ориентация из соотношения сторон).

- DrawingService.SetSheetFormatAsync + RequireLayoutSheet
- PaperFormat (enum + Parse/ToKompas/FromKompas), SheetFormatResult
- DrawingValidation.ValidateFormatDimensions (user: >0; стандартный: размеры запрещены)
- 19 unit + 7 интеграционных тестов (всего 304 зелёных), сборка Release чистая

Спайк подтвердил: дефолт A4 portrait; стандартный формат пересчитывает W/H авто
(A3 landscape→420×297); user применяет width/height. Ревью спека pi/glm-5.1 + pi/kimi-k2.6
учтено (FromKompas для дружелюбного имени, запрет размеров у стандартного, sheetNumber>0,
landscape игнорируется для user).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 23:19:37 +03:00

9.9 KiB
Raw Blame History

Дизайн: формат и ориентация листа чертежа (drawing_set_sheet_format) через API7

Дата: 2026-05-27 Статус: дизайн согласован, спайк проведён, ревью pi/glm-5.1 + pi/kimi-k2.6 учтено — к реализации

Правки по ревью (pi/glm-5.1 + pi/kimi-k2.6)

  • A для user флаг landscape игнорируется — ориентация задаётся соотношением width/height (КОМПАС сам выставит VerticalOrientation). VerticalOrientation=!landscape ставим ТОЛЬКО для стандартных форматов (избегаем неоднозначного свопа W/H). Задокументировано в описании инструмента.
  • B/E width/height для стандартного формата запрещены: валидатор ValidateFormatDimensions (для User — оба конечны и >0; для стандартного — оба ==0, иначе ArgumentException «размеры только для user»).
  • C read-back формата возвращает дружелюбное имя через новый PaperFormats.FromKompas(ksEnum)SheetFormatResult.Format = "A3"/"User" (симметрия вход/выход), а не COM-имя "ksFormatA3".
  • D RequireLayoutSheet(sheetNumber): sheetNumber>0 (ArgumentOutOfRangeException) + null-check после ItemByNumber[sheetNumber] (InvalidOperationException «нет листа N»); + интеграционный тест.
  • F read-back fmt2 = sheet.Format с null-check.
  • G SheetFormatResultpublic sealed record с public required … { get; init; } (как DrawingDimensionResult/DrawingViewsResult).
  • H интеграционные сравнения размеров — через Assert.InRange (допуск на float).
  • I члены PaperFormatс XML-<summary> (как RoughSignType).
  • J FormatMultiplicity оставляем на COM-дефолте (1) — отмечено в реализации.
  • K (верхняя граница width/height) — отклонено, в OPEN_QUESTIONS как будущее упрочнение (консистентно с RequirePositiveRadius — верхней границы нет).

Цель

Веха 2D-ЧЕРТЁЖ, инкремент 8. Задать формат (A0–A5 или пользовательский) и ориентацию (книжная/альбомная) листа активного чертежа. Фундамент «правильного» по ГОСТ чертежа (сейчас лист всегда дефолтный A4 книжный).

Спайк: механизм подтверждён вживую (НЕ разучивать)

Спайк (_SpikeSheetFormat, прогнан на реальном КОМПАС, затем удалён): новый чертёж → doc.LayoutSheets.ItemByNumber[1] (ILayoutSheet) → sheet.Format (ISheetFormat).

ISheetFormat fmt = sheet.Format;
fmt.Format = ksDocumentFormatEnum.ksFormatA3;   // A0=0..A5=5, User=6
fmt.VerticalOrientation = false;                 // true=книжная (portrait), false=альбомная (landscape)
sheet.Update();   // True
// для стандартного формата FormatWidth/Height пересчитываются АВТО (A3 landscape → 420×297)

Проверено:

  • Дефолт нового чертежа: ksFormatA4, VerticalOrientation=true, 210×297, FormatMultiplicity=1.
  • A3 landscape: Update=True, read-back Format=ksFormatA3, Vertical=False, W=420, H=297 (авто) — для стандартных форматов размеры не задаём, их даёт enum+ориентация.
  • A4 portrait: 210×297.
  • Пользовательский: Format=ksFormatUser + FormatWidth=500 + FormatHeight=300 + Update → применён.

ksDocumentFormatEnum: ksFormatA0=0, A1=1, A2=2, A3=3, A4=4, A5=5, ksFormatUser=6. ISheetFormat: Format (enum), VerticalOrientation (bool), FormatWidth/FormatHeight (double, мм), FormatMultiplicity (int).

MCP-инструмент

Инструмент Параметры Поведение
drawing_set_sheet_format format="A4" (A0|A1|A2|A3|A4|A5|user), landscape=false (false=книжная), width=0,height=0 (ТОЛЬКО для user, мм, >0), sheetNumber=1 Задать формат и ориентацию листа sheetNumber активного чертежа. Стандартный формат — размеры авто (по enum+ориентации), width/height для него запрещены (должны быть 0). user — задать width/height (>0); для user флаг landscape ИГНОРИРУЕТСЯ (ориентация — из соотношения сторон). Возвращает итоговый формат («A3»/«User»), ширину, высоту, ориентацию (read-back).

Архитектура

В DrawingService (namespace Kompas.Mcp.Core.Drawings).

  • SetSheetFormatAsync(PaperFormat format, bool landscape, double width, double height, int sheetNumber, ct)SheetFormatResult.
  • Helper RequireLayoutSheet(sheetNumber)ILayoutSheet: sheetNumber>0 (ArgumentOutOfRangeException) → нет активного чертежа / LayoutSheets null / ItemByNumber[sheetNumber] null («нет листа N») — раздельная диагностика, рядом с RequireActiveStamp.
  • Новый файл src/Kompas.Mcp.Core/Drawings/PaperFormat.cs: enum PaperFormat {A0,A1,A2,A3,A4,A5,User} (каждый член с XML-<summary>) + PaperFormats.Parse(string) / ToKompas(PaperFormat)→ksDocumentFormatEnum / FromKompas(ksDocumentFormatEnum)→PaperFormat (для read-back дружелюбного имени), по образцу RoughSignTypes.
  • Новый файл src/Kompas.Mcp.Core/Drawings/SheetFormatResult.cs: public sealed record SheetFormatResult { public required string Format; public required double Width; public required double Height; public required bool Landscape; } (стиль DrawingDimensionResult).

Реализация

SetSheetFormatCore: DrawingValidation.ValidateFormatDimensions(format, width, height)PaperFormats.ToKompas(format)RequireLayoutSheet(sheetNumber)fmt = sheet.Format (null-check) → fmt.Format = ksEnum; if format==User: fmt.FormatWidth=width, fmt.FormatHeight=height (ориентацию НЕ трогаем — задаётся W/H); else: fmt.VerticalOrientation = !landscape (размеры авто) → sheet.Update() (FALSE → ошибка; объект уровня листа, перезапись идемпотентна — отката Delete нет) → read-back fmt2 = sheet.Format (null-check) → SheetFormatResult { Format = PaperFormats.FromKompas(fmt2.Format) .ToString(), Width = fmt2.FormatWidth, Height = fmt2.FormatHeight, Landscape = !fmt2.VerticalOrientation }.

FormatMultiplicity оставляем на COM-дефолте (1) — не читаем и не задаём. RCW точечно не освобождаем (консистентно; долг v2-2).

Валидация (чистые static, unit)

  • PaperFormats.ParseA0..A5/user (+ регистр/пробелы); неизвестное → ArgumentException; null → ArgumentNullException.
  • Новый DrawingValidation.ValidateFormatDimensions(PaperFormat format, double width, double height): для Userwidth и height оба конечны и > 0 (иначе ArgumentOutOfRangeException); для стандартного — width==0 && height==0 (иначе ArgumentException «размеры задаются только для format=user»).
  • PaperFormats.ToKompas/FromKompas (↔ ksDocumentFormatEnum) НЕ покрываем unit — граница проекта (тест не ссылается на Kompas6Constants), как у прочих enum-маппингов; покрываются интеграцией.

Тестирование

Unit (PaperFormatsTests, DrawingValidationTests)

  • PaperFormats.Parse: A4/a3/ A2 /a0/a5/user → enum; неизвестное → ArgumentException; null → ArgumentNullException.
  • ValidateFormatDimensions:
    • User: бросает на (0,300)/(500,0)/(1,300)/(NaN,300)/(500,∞); пропускает (500,300).
    • стандартный (A4): бросает на (500,0)/(0,300)/(500,300); пропускает (0,0).

Integration (DrawingSheetFormatTests; сравнения размеров — Assert.InRange)

  1. A3 landscape: format=A3, landscape=trueFormat=="A3", Width≈420, Height≈297, Landscape==true.
  2. A4 portrait (landscape=false): → Format=="A4", Width≈210, Height≈297, Landscape==false.
  3. User 500×300: format=user, width=500, height=300Format=="User", Width≈500, Height≈300.
  4. User без размеров (width=0) → ArgumentOutOfRangeException (до COM).
  5. Размеры для стандартного (format=A3, width=400) → ArgumentException (до COM).
  6. Несуществующий лист (sheetNumber=99) → InvalidOperationException.
  7. Активный документ не чертёж (деталь) → понятная ошибка.

Дальнейшее (вне спека)

  • Рамка/основная надпись по конкретному ГОСТ-стилю оформления (LayoutLibraryFileName/LayoutStyleNumber), несколько листов (LayoutSheets.Add); привязка к дуге, угловой/шероховатость; выноски/базы/допуски формы.