From 56ed2cb0cf656ffdccf324be2f95345e4e01234c Mon Sep 17 00:00:00 2001 From: Shahovalov MIkhail Date: Wed, 27 May 2026 23:19:37 +0300 Subject: [PATCH 1/3] =?UTF-8?q?feat(drawing):=20=D1=84=D0=BE=D1=80=D0=BC?= =?UTF-8?q?=D0=B0=D1=82=20=D0=B8=20=D0=BE=D1=80=D0=B8=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BB=D0=B8=D1=81=D1=82=D0=B0=20(dr?= =?UTF-8?q?awing=5Fset=5Fsheet=5Fformat)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Задать формат (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) --- .../2026-05-27-drawing-sheet-format-design.md | 119 ++++++++++++++++++ .../Drawings/DrawingService.cs | 57 +++++++++ .../Drawings/DrawingValidation.cs | 20 +++ src/Kompas.Mcp.Core/Drawings/PaperFormat.cs | 70 +++++++++++ .../Drawings/SheetFormatResult.cs | 17 +++ src/Kompas.Mcp.Host/Tools/DrawingTools.cs | 20 +++ .../DrawingValidationTests.cs | 28 +++++ .../Integration/DrawingSheetFormatTests.cs | 111 ++++++++++++++++ tests/Kompas.Mcp.Tests/PaperFormatsTests.cs | 28 +++++ 9 files changed, 470 insertions(+) create mode 100644 docs/superpowers/specs/2026-05-27-drawing-sheet-format-design.md create mode 100644 src/Kompas.Mcp.Core/Drawings/PaperFormat.cs create mode 100644 src/Kompas.Mcp.Core/Drawings/SheetFormatResult.cs create mode 100644 tests/Kompas.Mcp.Tests/Integration/DrawingSheetFormatTests.cs create mode 100644 tests/Kompas.Mcp.Tests/PaperFormatsTests.cs diff --git a/docs/superpowers/specs/2026-05-27-drawing-sheet-format-design.md b/docs/superpowers/specs/2026-05-27-drawing-sheet-format-design.md new file mode 100644 index 0000000..98fad39 --- /dev/null +++ b/docs/superpowers/specs/2026-05-27-drawing-sheet-format-design.md @@ -0,0 +1,119 @@ +# Дизайн: формат и ориентация листа чертежа (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** `SheetFormatResult` — `public sealed record` с `public required … { get; init; }` (как + `DrawingDimensionResult`/`DrawingViewsResult`). +- **H** интеграционные сравнения размеров — через `Assert.InRange` (допуск на float). +- **I** члены `PaperFormat` — с XML-`` (как `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-``) + `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.Parse` — `A0..A5`/`user` (+ регистр/пробелы); неизвестное → `ArgumentException`; null → `ArgumentNullException`. +- Новый `DrawingValidation.ValidateFormatDimensions(PaperFormat format, double width, double height)`: + для `User` — `width` и `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=true` → `Format=="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=300` → `Format=="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`); привязка к дуге, угловой/шероховатость; выноски/базы/допуски формы. diff --git a/src/Kompas.Mcp.Core/Drawings/DrawingService.cs b/src/Kompas.Mcp.Core/Drawings/DrawingService.cs index 10e8aaa..faa94ec 100644 --- a/src/Kompas.Mcp.Core/Drawings/DrawingService.cs +++ b/src/Kompas.Mcp.Core/Drawings/DrawingService.cs @@ -84,6 +84,63 @@ public sealed class DrawingService ?? throw new InvalidOperationException("У листа оформления нет основной надписи (Stamp)."); } + /// Лист оформления чертежа по номеру (1-based) с диагностикой (номер > 0, лист существует). + private ILayoutSheet RequireLayoutSheet(int sheetNumber) + { + if (sheetNumber <= 0) + throw new ArgumentOutOfRangeException(nameof(sheetNumber), "Номер листа должен быть > 0."); + var doc2d = RequireActiveDrawing(); + var sheets = doc2d.LayoutSheets + ?? throw new InvalidOperationException("Не удалось получить листы оформления чертежа."); + return sheets.ItemByNumber[sheetNumber] as ILayoutSheet + ?? throw new InvalidOperationException($"На чертеже нет листа оформления #{sheetNumber}."); + } + + /// + /// Задать формат (: A0–A5 или user) и ориентацию листа + /// активного чертежа. Для стандартного формата размеры авто + /// (/ запрещены); для user — заданные width/height (мм), + /// при этом игнорируется (ориентация из соотношения сторон). Возвращает + /// итоговый формат, размеры и ориентацию (read-back из COM). + /// + public Task SetSheetFormatAsync(PaperFormat format, bool landscape, double width, + double height, int sheetNumber = 1, CancellationToken ct = default) + => _dispatcher.InvokeAsync(() => SetSheetFormatCore(format, landscape, width, height, sheetNumber), ct); + + private SheetFormatResult SetSheetFormatCore(PaperFormat format, bool landscape, double width, + double height, int sheetNumber) + { + DrawingValidation.ValidateFormatDimensions(format, width, height); + + var sheet = RequireLayoutSheet(sheetNumber); + var fmt = sheet.Format + ?? throw new InvalidOperationException("У листа недоступен формат (Format == null)."); + fmt.Format = PaperFormats.ToKompas(format); + if (format == PaperFormat.User) + { + // Для пользовательского ориентация задаётся соотношением width/height — VerticalOrientation не трогаем. + fmt.FormatWidth = width; + fmt.FormatHeight = height; + } + else + { + fmt.VerticalOrientation = !landscape; // стандартный: размеры авто по формату+ориентации + } + // FormatMultiplicity оставляем на COM-дефолте (1). + if (!sheet.Update()) + throw new InvalidOperationException("ILayoutSheet.Update вернул FALSE — формат листа не задан."); + + var fmt2 = sheet.Format + ?? throw new InvalidOperationException("Формат листа недоступен после Update (Format == null)."); + return new SheetFormatResult + { + Format = PaperFormats.FromKompas(fmt2.Format).ToString(), + Width = fmt2.FormatWidth, + Height = fmt2.FormatHeight, + Landscape = !fmt2.VerticalOrientation, + }; + } + /// /// Поставить линейный размер на виде активного чертежа между точками (x1,y1)-(x2,y2) в ЛОКАЛЬНОЙ /// СК вида (мм); размерная линия проходит через (x3,y3). — номер вида diff --git a/src/Kompas.Mcp.Core/Drawings/DrawingValidation.cs b/src/Kompas.Mcp.Core/Drawings/DrawingValidation.cs index 2cbefa9..ab4108c 100644 --- a/src/Kompas.Mcp.Core/Drawings/DrawingValidation.cs +++ b/src/Kompas.Mcp.Core/Drawings/DrawingValidation.cs @@ -55,6 +55,26 @@ public static class DrawingValidation throw new ArgumentException("Текст не должен быть пустым.", paramName); } + /// + /// Проверить размеры формата листа: для — ширина и высота оба + /// конечны и > 0; для стандартного формата — оба должны быть 0 (размеры авто, задавать нельзя). + /// + public static void ValidateFormatDimensions(PaperFormat format, double width, double height) + { + if (format == PaperFormat.User) + { + if (!double.IsFinite(width) || width <= 0 || !double.IsFinite(height) || height <= 0) + throw new ArgumentOutOfRangeException(nameof(width), + "Для format=user ширина и высота должны быть конечными и > 0."); + } + else if (width != 0 || height != 0) + { + throw new ArgumentException( + "Ширина/высота задаются только для format=user; для стандартного формата размеры авто (передайте 0).", + nameof(width)); + } + } + /// Минимальное расстояние между выносными точками линейного размера (мм). private const double MinPointDistance = 1e-7; diff --git a/src/Kompas.Mcp.Core/Drawings/PaperFormat.cs b/src/Kompas.Mcp.Core/Drawings/PaperFormat.cs new file mode 100644 index 0000000..ea5cdd7 --- /dev/null +++ b/src/Kompas.Mcp.Core/Drawings/PaperFormat.cs @@ -0,0 +1,70 @@ +using Kompas6Constants; + +namespace Kompas.Mcp.Core.Drawings; + +/// Формат листа чертежа (обёртка над ). +public enum PaperFormat +{ + /// A0 (841×1189 мм). + A0, + /// A1 (594×841 мм). + A1, + /// A2 (420×594 мм). + A2, + /// A3 (297×420 мм). + A3, + /// A4 (210×297 мм). + A4, + /// A5 (148×210 мм). + A5, + /// Пользовательский формат с явной шириной/высотой. + User, +} + +/// Маппинг формата листа ↔ перечисление КОМПАС и разбор строки. +public static class PaperFormats +{ + public static ksDocumentFormatEnum ToKompas(PaperFormat format) => format switch + { + PaperFormat.A0 => ksDocumentFormatEnum.ksFormatA0, + PaperFormat.A1 => ksDocumentFormatEnum.ksFormatA1, + PaperFormat.A2 => ksDocumentFormatEnum.ksFormatA2, + PaperFormat.A3 => ksDocumentFormatEnum.ksFormatA3, + PaperFormat.A4 => ksDocumentFormatEnum.ksFormatA4, + PaperFormat.A5 => ksDocumentFormatEnum.ksFormatA5, + PaperFormat.User => ksDocumentFormatEnum.ksFormatUser, + _ => throw new ArgumentOutOfRangeException(nameof(format), format, "Неизвестный формат листа."), + }; + + /// Обратный маппинг (для read-back дружелюбного имени). + public static PaperFormat FromKompas(ksDocumentFormatEnum format) => format switch + { + ksDocumentFormatEnum.ksFormatA0 => PaperFormat.A0, + ksDocumentFormatEnum.ksFormatA1 => PaperFormat.A1, + ksDocumentFormatEnum.ksFormatA2 => PaperFormat.A2, + ksDocumentFormatEnum.ksFormatA3 => PaperFormat.A3, + ksDocumentFormatEnum.ksFormatA4 => PaperFormat.A4, + ksDocumentFormatEnum.ksFormatA5 => PaperFormat.A5, + ksDocumentFormatEnum.ksFormatUser => PaperFormat.User, + _ => throw new ArgumentOutOfRangeException(nameof(format), format, "Неизвестный формат листа КОМПАС."), + }; + + /// Разобрать строку формата (A0..A5 / user, регистр/пробелы) в . + public static PaperFormat Parse(string value) + { + ArgumentNullException.ThrowIfNull(value); + return value.Trim().ToLowerInvariant() switch + { + "a0" => PaperFormat.A0, + "a1" => PaperFormat.A1, + "a2" => PaperFormat.A2, + "a3" => PaperFormat.A3, + "a4" => PaperFormat.A4, + "a5" => PaperFormat.A5, + "user" or "custom" or "пользовательский" => PaperFormat.User, + _ => throw new ArgumentException( + $"Неизвестный формат листа '{value}'. Допустимо: A0, A1, A2, A3, A4, A5, user.", + nameof(value)), + }; + } +} diff --git a/src/Kompas.Mcp.Core/Drawings/SheetFormatResult.cs b/src/Kompas.Mcp.Core/Drawings/SheetFormatResult.cs new file mode 100644 index 0000000..befe2f3 --- /dev/null +++ b/src/Kompas.Mcp.Core/Drawings/SheetFormatResult.cs @@ -0,0 +1,17 @@ +namespace Kompas.Mcp.Core.Drawings; + +/// Результат задания формата листа чертежа (read-back из COM). +public sealed record SheetFormatResult +{ + /// Итоговый формат («A0»…«A5» или «User»). + public required string Format { get; init; } + + /// Ширина листа, мм. + public required double Width { get; init; } + + /// Высота листа, мм. + public required double Height { get; init; } + + /// Альбомная ориентация (true) либо книжная (false). + public required bool Landscape { get; init; } +} diff --git a/src/Kompas.Mcp.Host/Tools/DrawingTools.cs b/src/Kompas.Mcp.Host/Tools/DrawingTools.cs index 966a8d0..c4e5907 100644 --- a/src/Kompas.Mcp.Host/Tools/DrawingTools.cs +++ b/src/Kompas.Mcp.Host/Tools/DrawingTools.cs @@ -187,4 +187,24 @@ public sealed class DrawingTools(KompasSession session, DrawingService drawing) var lines = await drawing.SetTechnicalRequirementsAsync(text); return $"Технические требования заданы ({lines} стр.)."; } + + [McpServerTool(Name = "drawing_set_sheet_format")] + [Description("Задать формат и ориентацию листа активного чертежа. format: A0|A1|A2|A3|A4|A5|user. " + + "landscape: false = книжная (portrait), true = альбомная (landscape). Для стандартного формата " + + "размеры вычисляются автоматически — width/height передавать НЕ нужно (должны быть 0). Для format=user " + + "задайте width и height в мм (>0); при user флаг landscape игнорируется (ориентация — из соотношения " + + "сторон). sheetNumber — номер листа (1 = первый). Возвращает итоговый формат, размеры и ориентацию.")] + public async Task SetSheetFormat( + [Description("Формат: A0|A1|A2|A3|A4|A5|user")] string format = "A4", + [Description("Альбомная ориентация (true) или книжная (false)")] bool landscape = false, + [Description("Ширина листа, мм (только для format=user)")] double width = 0, + [Description("Высота листа, мм (только для format=user)")] double height = 0, + [Description("Номер листа (1 = первый)")] int sheetNumber = 1) + { + await session.ConnectAsync(); + var f = PaperFormats.Parse(format); + var r = await drawing.SetSheetFormatAsync(f, landscape, width, height, sheetNumber); + var orient = r.Landscape ? "альбомная" : "книжная"; + return $"Формат листа {sheetNumber}: {r.Format}, {r.Width:0.#}×{r.Height:0.#} мм, {orient}."; + } } diff --git a/tests/Kompas.Mcp.Tests/DrawingValidationTests.cs b/tests/Kompas.Mcp.Tests/DrawingValidationTests.cs index b072e47..87c82d5 100644 --- a/tests/Kompas.Mcp.Tests/DrawingValidationTests.cs +++ b/tests/Kompas.Mcp.Tests/DrawingValidationTests.cs @@ -91,4 +91,32 @@ public sealed class DrawingValidationTests [Fact] public void RequireNonEmptyText_accepts_non_empty() => Assert.Null(Record.Exception(() => DrawingValidation.RequireNonEmptyText("Ra 1.6", "text"))); + + [Theory] + [InlineData(0, 300)] + [InlineData(500, 0)] + [InlineData(-1, 300)] + [InlineData(double.NaN, 300)] + [InlineData(500, double.PositiveInfinity)] + public void ValidateFormatDimensions_user_throws_on_non_positive_or_non_finite(double w, double h) + => Assert.Throws( + () => DrawingValidation.ValidateFormatDimensions(PaperFormat.User, w, h)); + + [Fact] + public void ValidateFormatDimensions_user_accepts_positive() + => Assert.Null(Record.Exception( + () => DrawingValidation.ValidateFormatDimensions(PaperFormat.User, 500, 300))); + + [Theory] + [InlineData(500, 0)] + [InlineData(0, 300)] + [InlineData(500, 300)] + public void ValidateFormatDimensions_standard_throws_when_dimensions_given(double w, double h) + => Assert.Throws( + () => DrawingValidation.ValidateFormatDimensions(PaperFormat.A3, w, h)); + + [Fact] + public void ValidateFormatDimensions_standard_accepts_zero_dimensions() + => Assert.Null(Record.Exception( + () => DrawingValidation.ValidateFormatDimensions(PaperFormat.A3, 0, 0))); } diff --git a/tests/Kompas.Mcp.Tests/Integration/DrawingSheetFormatTests.cs b/tests/Kompas.Mcp.Tests/Integration/DrawingSheetFormatTests.cs new file mode 100644 index 0000000..f5a3b66 --- /dev/null +++ b/tests/Kompas.Mcp.Tests/Integration/DrawingSheetFormatTests.cs @@ -0,0 +1,111 @@ +using Kompas.Mcp.Core.Documents; +using Kompas.Mcp.Core.Drawings; + +namespace Kompas.Mcp.Tests.Integration; + +/// Интеграция: формат и ориентация листа чертежа (API7 ILayoutSheet.Format / ISheetFormat). +[Trait("Category", "Integration")] +[Collection(KompasCollection.Name)] +public sealed class DrawingSheetFormatTests : IntegrationTestBase +{ + private readonly DocumentService _docs; + private readonly DrawingService _drawing; + + public DrawingSheetFormatTests(KompasFixture fx) : base(fx) + { + _docs = new DocumentService(fx.Session, fx.Dispatcher); + _drawing = new DrawingService(fx.Session, fx.Dispatcher); + } + + [Fact] + public async Task A3_landscape() + { + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + var r = await _drawing.SetSheetFormatAsync(PaperFormat.A3, landscape: true, width: 0, height: 0); + Assert.Equal("A3", r.Format); + Assert.InRange(r.Width, 419.5, 420.5); + Assert.InRange(r.Height, 296.5, 297.5); + Assert.True(r.Landscape); + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task A4_portrait() + { + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + var r = await _drawing.SetSheetFormatAsync(PaperFormat.A4, landscape: false, width: 0, height: 0); + Assert.Equal("A4", r.Format); + Assert.InRange(r.Width, 209.5, 210.5); + Assert.InRange(r.Height, 296.5, 297.5); + Assert.False(r.Landscape); + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task User_format_with_dimensions() + { + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + var r = await _drawing.SetSheetFormatAsync(PaperFormat.User, landscape: false, width: 500, height: 300); + Assert.Equal("User", r.Format); + Assert.InRange(r.Width, 499.5, 500.5); + Assert.InRange(r.Height, 299.5, 300.5); + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task User_without_dimensions_throws() + { + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + await Assert.ThrowsAsync(() => + _drawing.SetSheetFormatAsync(PaperFormat.User, landscape: false, width: 0, height: 0)); + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task Standard_with_dimensions_throws() + { + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + await Assert.ThrowsAsync(() => + _drawing.SetSheetFormatAsync(PaperFormat.A3, landscape: false, width: 400, height: 0)); + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task Nonexistent_sheet_throws() + { + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + await Assert.ThrowsAsync(() => + _drawing.SetSheetFormatAsync(PaperFormat.A4, landscape: false, width: 0, height: 0, sheetNumber: 99)); + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task Active_document_not_drawing_throws() + { + await _docs.CreateAsync(KompasDocumentType.Part); + try + { + await Assert.ThrowsAsync(() => + _drawing.SetSheetFormatAsync(PaperFormat.A4, landscape: false, width: 0, height: 0)); + } + finally { await _docs.CloseAsync(save: false); } + } +} diff --git a/tests/Kompas.Mcp.Tests/PaperFormatsTests.cs b/tests/Kompas.Mcp.Tests/PaperFormatsTests.cs new file mode 100644 index 0000000..db232fc --- /dev/null +++ b/tests/Kompas.Mcp.Tests/PaperFormatsTests.cs @@ -0,0 +1,28 @@ +using Kompas.Mcp.Core.Drawings; + +namespace Kompas.Mcp.Tests; + +[Trait("Category", "Unit")] +public sealed class PaperFormatsTests +{ + [Theory] + [InlineData("A4", PaperFormat.A4)] + [InlineData("a3", PaperFormat.A3)] + [InlineData(" A2 ", PaperFormat.A2)] + [InlineData("a0", PaperFormat.A0)] + [InlineData("A5", PaperFormat.A5)] + [InlineData("user", PaperFormat.User)] + [InlineData("USER", PaperFormat.User)] + public void Parse_maps_known(string value, PaperFormat expected) + => Assert.Equal(expected, PaperFormats.Parse(value)); + + [Fact] + public void Parse_throws_on_unknown() + => Assert.Throws(() => PaperFormats.Parse("A6")); + + [Fact] + public void Parse_throws_on_null() + => Assert.Throws(() => PaperFormats.Parse(null!)); + + // ToKompas/FromKompas (↔ ksDocumentFormatEnum) — граница проекта, проверяются интеграцией. +} From 24f3531a3c277924fcaabba83236bd62baf8cb95 Mon Sep 17 00:00:00 2001 From: Shahovalov MIkhail Date: Wed, 27 May 2026 23:28:34 +0300 Subject: [PATCH 2/3] =?UTF-8?q?review(drawing):=20=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=BF=D0=BE=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E=20?= =?UTF-8?q?=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8=20?= =?UTF-8?q?(Codex=20+=20pi/glm-5.1=20+=20pi/kimi-k2.6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - K1 (kimi, Major): спайк подтвердил — для User КОМПАС САМ выводит VerticalOrientation из W/H (игнорирует флаг, W/H не свопает); read-back корректен, правка не нужна — задокументировано комментарием + тесты на Landscape (500×300→альбомная, 300×500→книжная) - K2: ValidateFormatDimensions называет точный нарушивший параметр (width/height) - тесты: A1 в Parse (C3), A4 landscape со свопом 297×210 (G2), sheetNumber=0 (C2/G3) - отклонено (нит): алиасы в описании (G4), сообщение NaN (G5), тип исключения standard (K5) 308 тестов зелёных, сборка Release чистая. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Drawings/DrawingService.cs | 4 +- .../Drawings/DrawingValidation.cs | 11 +++-- .../Integration/DrawingSheetFormatTests.cs | 47 ++++++++++++++++++- tests/Kompas.Mcp.Tests/PaperFormatsTests.cs | 1 + 4 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/Kompas.Mcp.Core/Drawings/DrawingService.cs b/src/Kompas.Mcp.Core/Drawings/DrawingService.cs index faa94ec..bbacfa3 100644 --- a/src/Kompas.Mcp.Core/Drawings/DrawingService.cs +++ b/src/Kompas.Mcp.Core/Drawings/DrawingService.cs @@ -118,7 +118,9 @@ public sealed class DrawingService fmt.Format = PaperFormats.ToKompas(format); if (format == PaperFormat.User) { - // Для пользовательского ориентация задаётся соотношением width/height — VerticalOrientation не трогаем. + // Для пользовательского КОМПАС САМ выводит VerticalOrientation из соотношения width/height + // (W>H → альбомная, H>W → книжная) и игнорирует заданный флаг, W/H не свопает — проверено + // спайком. Поэтому VerticalOrientation не трогаем; read-back ниже даёт верную ориентацию. fmt.FormatWidth = width; fmt.FormatHeight = height; } diff --git a/src/Kompas.Mcp.Core/Drawings/DrawingValidation.cs b/src/Kompas.Mcp.Core/Drawings/DrawingValidation.cs index ab4108c..d7b176e 100644 --- a/src/Kompas.Mcp.Core/Drawings/DrawingValidation.cs +++ b/src/Kompas.Mcp.Core/Drawings/DrawingValidation.cs @@ -63,15 +63,20 @@ public static class DrawingValidation { if (format == PaperFormat.User) { - if (!double.IsFinite(width) || width <= 0 || !double.IsFinite(height) || height <= 0) + if (!double.IsFinite(width) || width <= 0) throw new ArgumentOutOfRangeException(nameof(width), - "Для format=user ширина и высота должны быть конечными и > 0."); + "Для format=user ширина должна быть конечной и > 0."); + if (!double.IsFinite(height) || height <= 0) + throw new ArgumentOutOfRangeException(nameof(height), + "Для format=user высота должна быть конечной и > 0."); } else if (width != 0 || height != 0) { + // Точное имя нарушившего параметра (а не всегда width). + var offender = width != 0 ? nameof(width) : nameof(height); throw new ArgumentException( "Ширина/высота задаются только для format=user; для стандартного формата размеры авто (передайте 0).", - nameof(width)); + offender); } } diff --git a/tests/Kompas.Mcp.Tests/Integration/DrawingSheetFormatTests.cs b/tests/Kompas.Mcp.Tests/Integration/DrawingSheetFormatTests.cs index f5a3b66..4edf39a 100644 --- a/tests/Kompas.Mcp.Tests/Integration/DrawingSheetFormatTests.cs +++ b/tests/Kompas.Mcp.Tests/Integration/DrawingSheetFormatTests.cs @@ -48,15 +48,48 @@ public sealed class DrawingSheetFormatTests : IntegrationTestBase } [Fact] - public async Task User_format_with_dimensions() + public async Task A4_landscape_swaps_dimensions() { await _docs.CreateAsync(KompasDocumentType.Drawing); try { + var r = await _drawing.SetSheetFormatAsync(PaperFormat.A4, landscape: true, width: 0, height: 0); + Assert.Equal("A4", r.Format); + Assert.InRange(r.Width, 296.5, 297.5); // своп: альбомная A4 = 297×210 + Assert.InRange(r.Height, 209.5, 210.5); + Assert.True(r.Landscape); + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task User_landscape_dimensions_derive_orientation() + { + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + // 500×300 (W>H) → КОМПАС выводит альбомную ориентацию (Landscape=true), W/H литеральны. var r = await _drawing.SetSheetFormatAsync(PaperFormat.User, landscape: false, width: 500, height: 300); Assert.Equal("User", r.Format); Assert.InRange(r.Width, 499.5, 500.5); Assert.InRange(r.Height, 299.5, 300.5); + Assert.True(r.Landscape); // ориентация выведена из соотношения сторон (не из флага landscape=false) + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task User_portrait_dimensions_derive_orientation() + { + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + // 300×500 (H>W) → книжная (Landscape=false). + var r = await _drawing.SetSheetFormatAsync(PaperFormat.User, landscape: true, width: 300, height: 500); + Assert.Equal("User", r.Format); + Assert.InRange(r.Width, 299.5, 300.5); + Assert.InRange(r.Height, 499.5, 500.5); + Assert.False(r.Landscape); // landscape=true проигнорирован — ориентация из сторон } finally { await _docs.CloseAsync(save: false); } } @@ -97,6 +130,18 @@ public sealed class DrawingSheetFormatTests : IntegrationTestBase finally { await _docs.CloseAsync(save: false); } } + [Fact] + public async Task Nonpositive_sheet_number_throws() + { + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + await Assert.ThrowsAsync(() => + _drawing.SetSheetFormatAsync(PaperFormat.A4, landscape: false, width: 0, height: 0, sheetNumber: 0)); + } + finally { await _docs.CloseAsync(save: false); } + } + [Fact] public async Task Active_document_not_drawing_throws() { diff --git a/tests/Kompas.Mcp.Tests/PaperFormatsTests.cs b/tests/Kompas.Mcp.Tests/PaperFormatsTests.cs index db232fc..8195575 100644 --- a/tests/Kompas.Mcp.Tests/PaperFormatsTests.cs +++ b/tests/Kompas.Mcp.Tests/PaperFormatsTests.cs @@ -10,6 +10,7 @@ public sealed class PaperFormatsTests [InlineData("a3", PaperFormat.A3)] [InlineData(" A2 ", PaperFormat.A2)] [InlineData("a0", PaperFormat.A0)] + [InlineData("A1", PaperFormat.A1)] [InlineData("A5", PaperFormat.A5)] [InlineData("user", PaperFormat.User)] [InlineData("USER", PaperFormat.User)] From 4937b9e677921ed041f66e0923718e31c4c01c99 Mon Sep 17 00:00:00 2001 From: Shahovalov MIkhail Date: Wed, 27 May 2026 23:34:15 +0300 Subject: [PATCH 3/3] =?UTF-8?q?docs:=20=D1=84=D0=BE=D1=80=D0=BC=D0=B0?= =?UTF-8?q?=D1=82/=D0=BE=D1=80=D0=B8=D0=B5=D0=BD=D1=82=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BB=D0=B8=D1=81=D1=82=D0=B0=20=E2=80=94=20TODO,=20R?= =?UTF-8?q?EADME,=20ARCHITECTURE,=20OPEN=5FQUESTIONS,=20presentation,=20CL?= =?UTF-8?q?AUDE.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Инкремент 8. 82 инструмента, 308 тестов. + заметка о ревью реализации в спеке (Codex + pi/glm-5.1 + pi/kimi-k2.6; K1 снят спайком — КОМПАС сам выводит ориентацию user). Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 7 ++++--- README.md | 6 +++--- docs/ARCHITECTURE.md | 11 ++++++----- docs/OPEN_QUESTIONS.md | 7 ++++++- docs/TODO.md | 5 +++-- docs/presentation.html | 15 ++++++++------- .../2026-05-27-drawing-sheet-format-design.md | 16 +++++++++++++++- 7 files changed, 45 insertions(+), 22 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index e90b695..b82a972 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -24,12 +24,12 @@ The base is committed to the repo (canonical) — no regeneration step. It cover ## Current state **Status:** v1 + v2 + STEP/assembly + direct B-rep edit + structural inspection + 2D drawings — 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**. **81 MCP tools, 278 tests green (168 unit + 110 integration).** +Stack: **.NET 8 (`net8.0-windows`, x64), C#**, MCP via the official `ModelContextProtocol` SDK over **stdio**. **82 MCP tools, 308 tests green (188 unit + 120 integration).** Where to look (single source of truth — do **not** duplicate these lists here): -- **Full tool catalog** (by group, all 81) → [`README.md`](README.md) §«Инструменты». +- **Full tool catalog** (by group, all 82) → [`README.md`](README.md) §«Инструменты». - **Roadmap / what's already done** → [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) §10. -- **Backlog / what's left** → [`docs/TODO.md`](docs/TODO.md) (canonical; top of «2D-ЧЕРТЁЖ» = next priority. Associative diametral/radial→circle binding done via `associate` flag — next: arc/angular/rough binding, sheet format, leaders, bases, tolerances; plus extra mate types, package E continuation). +- **Backlog / what's left** → [`docs/TODO.md`](docs/TODO.md) (canonical; top of «2D-ЧЕРТЁЖ» = next priority. Associative diametral/radial→circle binding (`associate` flag) and sheet format/orientation (`drawing_set_sheet_format`) done — next: arc/angular/rough binding, leaders, bases, tolerances; plus extra mate types, package E continuation). - **Design decisions / caveats** → [`docs/OPEN_QUESTIONS.md`](docs/OPEN_QUESTIONS.md). Known caveat («Ревью v2»): boss/cut direction on a selected face depends on face-normal orientation — `forward` may need flipping; the agent picks via snapshot or `describe_face` normal. - **Verified COM call-chains & gotchas** → «Key implementation facts» below + memory files (`kompas-*-api*.md`). @@ -88,6 +88,7 @@ dotnet run --project src/Kompas.Mcp.Host # start the MCP server (stdio) - `drawing_add_text` — **text lives in `IDrawingContainer`, NOT `ISymbols2DContainer`, and NOT in `IView.ObjectCount`**: `(IDrawingContainer)view.DrawingTexts.Add()`/`IDrawingText` (`X/Y/Angle`) + `(IText)dt.Str` = text; count via `DrawingTexts.Count`. Do NOT set `Height` (that's block height, not font). - `drawing_set_technical_requirements` — **document-level**: `(IDrawingDocument)doc.TechnicalDemand`/`ITechnicalDemand`: `td.Text.Str = text` → `td.Update()` (`IsCreated` False→True on first set; overwrites; `\n` multiline). - `DrawingAnnotationResult{Value(read-back), ViewNumber}` is the shared result for rough/text. + - `drawing_set_sheet_format` — `RequireLayoutSheet(n).Format` (`ISheetFormat`): `Format`=`ksDocumentFormatEnum` (`PaperFormat{A0..A5,User}`+`PaperFormats.Parse/ToKompas/FromKompas`), standard → set `VerticalOrientation=!landscape` (W/H auto-computed from enum+orientation, e.g. A3 landscape→420×297); **User → set `FormatWidth/Height` only, КОМПАС auto-derives `VerticalOrientation` from W/H and ignores the flag, never swaps W/H (spike)** → `sheet.Update()`. New drawing defaults A4 portrait. `ValidateFormatDimensions`: User needs W/H>0, standard forbids W/H (must be 0). - **Richer sketch primitives (API5 `ksDocument2D` wrappers)**: `ksArcBy3Points`; `ksArcByAngle` (centre/radius/start-end angles in degrees + counterClockwise flag); `ksEllipse` via `ksEllipseParam` (`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 released after use. `PartModeler` is partial: `.cs` (registry/helpers/`NewParam`/reset), `.Sketch.cs` (2D primitives), `.Features.cs` (extrude/revolve/fillet/chamfer). Static `SketchGeometry` (`Core/Modeling`) holds enum maps + validators (`RequirePositive`, `RequireVertexCount`, `RequirePoints`, `RequireMin`). Point lists use `record SketchPoint(X, Y)` (JSON names `x`/`y`). ## КОМПАС-3D API architecture (the critical context) diff --git a/README.md b/README.md index b0b0091..58b02a3 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ src/Kompas.Mcp.Host/bin/Release/net8.0-windows/kompas-mcp.exe } ``` -## Инструменты (81 инструмент) +## Инструменты (82 инструмента) | Группа | Инструменты | |---|---| @@ -56,7 +56,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_fill_title_block`, `drawing_add_linear_dimension`, `drawing_add_diametral_dimension`, `drawing_add_radial_dimension`, `drawing_add_angular_dimension`, `drawing_add_rough`, `drawing_add_text`, `drawing_set_technical_requirements` | +| Drawing | `drawing_create_standard_views`, `drawing_fill_title_block`, `drawing_add_linear_dimension`, `drawing_add_diametral_dimension`, `drawing_add_radial_dimension`, `drawing_add_angular_dimension`, `drawing_add_rough`, `drawing_add_text`, `drawing_set_technical_requirements`, `drawing_set_sheet_format` | | Validation | `validate_part` | ### Типовой сценарий @@ -75,7 +75,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/ 278 тестов: unit + integration (integration требуют КОМПАС) +tests/Kompas.Mcp.Tests/ 308 тестов: 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 0816a95..de87c4c 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`+`drawing_fill_title_block`+`drawing_add_linear_dimension`+`drawing_add_diametral_dimension`+`drawing_add_radial_dimension`+`drawing_add_angular_dimension`+`drawing_add_rough`+`drawing_add_text`+`drawing_set_technical_requirements`+ассоциативная привязка диаметрального/радиального к окружности (веха «2D-чертёж», инкремент 7)). Актуализировано по коду. +> Статус: **реализовано и работает** (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`+`drawing_add_linear_dimension`+`drawing_add_diametral_dimension`+`drawing_add_radial_dimension`+`drawing_add_angular_dimension`+`drawing_add_rough`+`drawing_add_text`+`drawing_set_technical_requirements`+ассоциативная привязка диаметрального/радиального к окружности (веха «2D-чертёж», инкремент 7)+`drawing_set_sheet_format` (формат и ориентация листа, инкремент 8)). Актуализировано по коду. > Сопутствующий контекст по 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) + интеграционные (требуют КОМПАС). 278 тестов (168 unit + 110 integration). Все интеграционные классы наследуют `IntegrationTestBase` (`IAsyncLifetime`), который вызывает `DocumentService.CloseAllAsync` после каждого теста. | +| **Kompas.Mcp.Tests** | Юнит (без COM) + интеграционные (требуют КОМПАС). 308 тестов (188 unit + 120 integration). Все интеграционные классы наследуют `IntegrationTestBase` (`IAsyncLifetime`), который вызывает `DocumentService.CloseAllAsync` после каждого теста. | Принцип: **только `Core` знает про COM**. `Host`/Tools оперируют доменными DTO и вызывают `Core`; `Host` не содержит бизнес-логики. @@ -121,7 +121,7 @@ MCP client ──stdio──> Host (поток-пул, async) --- -## 5. Карта инструментов (81 инструмент) +## 5. Карта инструментов (82 инструмента) Сгруппированы вокруг центрального цикла «эскиз ↔ операция». Имена — `snake_case`. @@ -218,6 +218,7 @@ MCP client ──stdio──> Host (поток-пул, async) - `drawing_add_rough(x,y, value?, signType, angle, viewNumber)` — поставить знак шероховатости на виде. `x,y` — положение знака в локальной СК вида (мм); `value` — текст параметра (напр. `"Ra 1.6"`; пусто = знак без значения); `signType`: `"delete"` (с удалением слоя материала) | `"without"` (без удаления) | `"none"` (без указания); `angle` — угол наклона оси знака (°, по умолч. 0); `viewNumber` — номер вида. Реализовано: `ISymbols2DContainer.Roughs.Add()` → `IRough` (`BranchX0/Y0/Angle`) → `(IRoughParams)rough` (`SignType=ksRoughSignEnum`, `RoughParamText.Str = value`) → `Update()` → `Valid`. Новый enum `RoughSignType {NoProcessing, DeleteMaterial, WithoutDeleteMaterial}` + `RoughSignTypes.Parse/ToKompas` в `Drawings/RoughSignType.cs`. Возвращает `DrawingAnnotationResult { Value, ViewNumber }`. - `drawing_add_text(x,y, text, angle, viewNumber)` — свободная текстовая надпись на виде стилем по умолчанию. `x,y` — точка привязки (СК вида, мм); `text` — содержимое (`\n` — многострочно); `angle` — угол (°, по умолч. 0); `viewNumber` — номер вида. Реализовано: `(IDrawingContainer)view.DrawingTexts.Add()` → `IDrawingText` (`X/Y/Angle`) → `(IText)dt.Str = text` → `Update()` → `Valid`. ВАЖНО: текст живёт в `IDrawingContainer` (контейнер геометрии вида), НЕ в `ISymbols2DContainer`; попадание проверяется через `DrawingTexts.Count`. Возвращает `DrawingAnnotationResult { Value, ViewNumber }`. - `drawing_set_technical_requirements(text)` — технические требования чертежа (единый текстовый блок, уровень документа, не вида). `text` — строки через `\n`. Реализовано: `(IDrawingDocument)doc.TechnicalDemand` → `td.Text.Str = text` → `td.Update()`. Перезаписывает прежние (не добавляет). Возвращает число строк. +- `drawing_set_sheet_format(format, landscape, width?, height?, sheetNumber=1)` — задать формат и ориентацию листа активного чертежа. `format`: `"A0"|"A1"|"A2"|"A3"|"A4"|"A5"|"user"`; `landscape`: `false`=книжная/`true`=альбомная; `width`/`height` только для `format=user` (мм, >0, для стандартного должны быть 0). Для `format=user` КОМПАС выводит ориентацию из соотношения сторон, флаг `landscape` игнорируется. Возвращает итоговые формат, ширину, высоту, ориентацию (read-back из COM). Реализовано: `ILayoutSheet.Format` (`ISheetFormat`: `Format=ksDocumentFormatEnum`, `VerticalOrientation`, `FormatWidth/Height`) → `sheet.Update()`. Новые: enum `PaperFormat {A0,A1,A2,A3,A4,A5,User}` + `PaperFormats.Parse/ToKompas/FromKompas`; record `SheetFormatResult {Format,Width,Height,Landscape}`; валидатор `DrawingValidation.ValidateFormatDimensions`; хелпер `RequireLayoutSheet`. API7, `DrawingService`. **Vision — визуальная обратная связь (fallback)** - `model_snapshot` — отрендерить активный 3D-документ в PNG и вернуть **как image-контент MCP**, @@ -352,14 +353,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+drawing_fill_title_block+drawing_add_linear_dimension+drawing_add_diametral_dimension+drawing_add_radial_dimension+drawing_add_angular_dimension+drawing_add_rough+drawing_add_text+drawing_set_technical_requirements+associate для диаметрального/радиального):** документы, эскизы (полный набор 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`); **`drawing_add_linear_dimension`** (линейный размер на виде чертежа: `ISymbols2DContainer`/`LineDimensions.Add`/`ILineDimension`, координаты в локальной СК вида, API7, `DrawingService`); **`drawing_add_diametral_dimension`** (диаметральный размер Ø: `ISymbols2DContainer.DiametralDimensions.Add`/`IDiametralDimension`, Xc/Yc/Radius/Angle в радианах, API7, `DrawingService`; **`associate=true`** — ассоциативная привязка к спроецированной окружности через `dim.BaseObject`, `CircularObjectMatch`); **`drawing_add_radial_dimension`** (радиальный размер R: `ISymbols2DContainer.RadialDimensions.Add`/`IRadialDimension`, значение = радиус, API7, `DrawingService`; **`associate=true`** — ассоциативная привязка аналогично диаметральному); **`drawing_add_angular_dimension`** (угловой размер: `ISymbols2DContainer.AngleDimensions.Add`/`IAngleDimension`, `angleType`=min/max/more, значение в градусах, API7, `DrawingService`); **`drawing_add_rough`** (знак шероховатости: `ISymbols2DContainer.Roughs.Add`/`IRough`/`IRoughParams`, `signType`=delete/without/none, API7, `DrawingService`); **`drawing_add_text`** (свободная текстовая надпись на виде: `IDrawingContainer.DrawingTexts.Add`/`IDrawingText`/`IText`, API7, `DrawingService`); **`drawing_set_technical_requirements`** (технические требования чертежа: `IDrawingDocument.TechnicalDemand`/`ITechnicalDemand`/`IText`, уровень документа, API7, `DrawingService`). Класс «2D-чертёж» (инкремент 6): стандартные виды, основная надпись, размеры (линейный, диаметральный, радиальный, угловой), текстовые обозначения (шероховатость, свободный текст, технические требования). **Инкремент 7**: ассоциативная привязка диаметрального и радиального размеров к спроецированной окружности (`IDrawingContainer.Circles`, поиск по центру+радиусу с допуском 1 мм, `CircularObjectMatch`, `dim.BaseObject = circle`); первый шаг к «умному» чертежу. +**Реализовано (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+drawing_add_linear_dimension+drawing_add_diametral_dimension+drawing_add_radial_dimension+drawing_add_angular_dimension+drawing_add_rough+drawing_add_text+drawing_set_technical_requirements+associate для диаметрального/радиального+drawing_set_sheet_format):** документы, эскизы (полный набор 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`); **`drawing_add_linear_dimension`** (линейный размер на виде чертежа: `ISymbols2DContainer`/`LineDimensions.Add`/`ILineDimension`, координаты в локальной СК вида, API7, `DrawingService`); **`drawing_add_diametral_dimension`** (диаметральный размер Ø: `ISymbols2DContainer.DiametralDimensions.Add`/`IDiametralDimension`, Xc/Yc/Radius/Angle в радианах, API7, `DrawingService`; **`associate=true`** — ассоциативная привязка к спроецированной окружности через `dim.BaseObject`, `CircularObjectMatch`); **`drawing_add_radial_dimension`** (радиальный размер R: `ISymbols2DContainer.RadialDimensions.Add`/`IRadialDimension`, значение = радиус, API7, `DrawingService`; **`associate=true`** — ассоциативная привязка аналогично диаметральному); **`drawing_add_angular_dimension`** (угловой размер: `ISymbols2DContainer.AngleDimensions.Add`/`IAngleDimension`, `angleType`=min/max/more, значение в градусах, API7, `DrawingService`); **`drawing_add_rough`** (знак шероховатости: `ISymbols2DContainer.Roughs.Add`/`IRough`/`IRoughParams`, `signType`=delete/without/none, API7, `DrawingService`); **`drawing_add_text`** (свободная текстовая надпись на виде: `IDrawingContainer.DrawingTexts.Add`/`IDrawingText`/`IText`, API7, `DrawingService`); **`drawing_set_technical_requirements`** (технические требования чертежа: `IDrawingDocument.TechnicalDemand`/`ITechnicalDemand`/`IText`, уровень документа, API7, `DrawingService`); **`drawing_set_sheet_format`** (формат и ориентация листа: `ILayoutSheet.Format`/`ISheetFormat`, `ksDocumentFormatEnum`, `VerticalOrientation`/`FormatWidth`/`FormatHeight`, `PaperFormat` enum, API7, `DrawingService`). Класс «2D-чертёж» (инкремент 6): стандартные виды, основная надпись, размеры (линейный, диаметральный, радиальный, угловой), текстовые обозначения (шероховатость, свободный текст, технические требования). **Инкремент 7**: ассоциативная привязка диаметрального и радиального размеров к спроецированной окружности (`IDrawingContainer.Circles`, поиск по центру+радиусу с допуском 1 мм, `CircularObjectMatch`, `dim.BaseObject = circle`); первый шаг к «умному» чертежу. **Инкремент 8**: задание формата и ориентации листа (`drawing_set_sheet_format`); для `format=user` ориентация определяется КОМПАС из соотношения сторон. **Следующие приоритеты:** 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-чертёж (продолжение):** инкремент 7 добавил ассоциативную привязку диаметрального/радиального размера к окружности (`associate=true`). Нереализовано: привязка к дуге (`Arcs`), ассоциативный угловой размер (BaseObject1/2, отрезки), ассоциативная шероховатость (`IRough.BaseObject`), рамка/формат листа, выноски (`Leaders`), обозначения баз (`Bases`), допуски формы (`Tolerances`). +5. **2D-чертёж (продолжение):** инкремент 8 добавил формат и ориентацию листа (`drawing_set_sheet_format`). Нереализовано: рамка по ГОСТ-стилю (`LayoutLibraryFileName`/`LayoutStyleNumber`), несколько листов; привязка к дуге (`Arcs`), ассоциативный угловой размер (BaseObject1/2, отрезки), ассоциативная шероховатость (`IRough.BaseObject`); выноски (`Leaders`), обозначения баз (`Bases`), допуски формы (`Tolerances`). 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 f48e4da..477a6e8 100644 --- a/docs/OPEN_QUESTIONS.md +++ b/docs/OPEN_QUESTIONS.md @@ -224,4 +224,9 @@ stateful-сессии? Пока полагаемся на последовате ### ✅ Ассоциативная привязка диаметрального/радиального к окружности — реализована (инкремент 7 вехи «2D-чертёж») **Решено (частично).** Параметр `associate=true` добавлен к `drawing_add_diametral_dimension` и `drawing_add_radial_dimension`. Реализация (API7, `DrawingService`): новый класс `CircularObjectMatch` — отбирает окружность-кандидата в `IDrawingContainer.Circles` по центру (xc,yc) + радиусу с допуском 1 мм; бросает при отсутствии или неоднозначности (концентрические окружности различаются по радиусу). Хелпер `RequireViewContainers` получает одновременно `ISymbols2DContainer` и `IDrawingContainer` для вида. `_Circle` реализует `IDrawingObject`, поэтому `dim.BaseObject = circle` без дополнительного приведения. `associate=false` — прежнее «свободное» поведение без изменений. Подтверждено спайком: `BaseObject=circle` без задания Xc/Yc/Radius → `Valid`, `NominalValue` из геометрии (цилиндр R10: Ø=20 / R=10). +5 unit-тестов (`CircularObjectMatchTests`) + 6 интеграционных (`DrawingAssociativeDimensionTests`). Итог: **81 инструмент, 278 тестов (168 unit + 110 integration).** -Нереализовано (следующие инкременты): привязка к дуге (`IDrawingContainer.Arcs`), ассоциативный угловой размер (`BaseObject1/2`, отрезки), ассоциативная шероховатость (`IRough.BaseObject`), рамка/формат листа, выноски (`Leaders`), обозначения баз (`Bases`), допуски формы (`Tolerances`). +Нереализовано (следующие инкременты): привязка к дуге (`IDrawingContainer.Arcs`), ассоциативный угловой размер (`BaseObject1/2`, отрезки), ассоциативная шероховатость (`IRough.BaseObject`); рамка/основная надпись по ГОСТ-стилю (`LayoutLibraryFileName`/`LayoutStyleNumber`), несколько листов; выноски (`Leaders`), обозначения баз (`Bases`), допуски формы (`Tolerances`). + +### ✅ Формат и ориентация листа чертежа — реализованы (инкремент 8 вехи «2D-чертёж») +**Решено.** Новый инструмент `drawing_set_sheet_format(format, landscape, width?, height?, sheetNumber=1)` — задаёт формат и ориентацию активного листа чертежа. Паттерн API7: `doc2d.LayoutSheets.ItemByNumber[sheetNumber]` → `ILayoutSheet.Format` (`ISheetFormat`: `Format=ksDocumentFormatEnum`, `VerticalOrientation=!landscape`, `FormatWidth/Height` только для `format=user`) → `sheet.Update()`. Дефолтный лист нового чертежа — A4 книжный. Новые типы: enum `PaperFormat {A0,A1,A2,A3,A4,A5,User}` + `PaperFormats.Parse/ToKompas/FromKompas`; record `SheetFormatResult`; валидатор `DrawingValidation.ValidateFormatDimensions`; хелпер `RequireLayoutSheet`. Ключевая тонкость: для `format=user` КОМПАС выводит `VerticalOrientation` из соотношения сторон (`height>width`), флаг `landscape` в этом случае игнорируется — результат читается read-back из COM. Для стандартных форматов `width`/`height` запрещены (должны быть 0). +20 unit-тестов (`PaperFormats.Parse`, `ValidateFormatDimensions`) + 10 интеграционных (`DrawingSheetFormatTests`). Итог: **82 инструмента, 308 тестов (188 unit + 120 integration).** + +Нереализовано: рамка по ГОСТ-стилю (`LayoutLibraryFileName`/`LayoutStyleNumber`), несколько листов. diff --git a/docs/TODO.md b/docs/TODO.md index c92bcd6..7b7f465 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -22,8 +22,9 @@ - ☐ **Угловой** → пара отрезков (`BaseObject1/2`, `LineSegments`). - ☐ **Шероховатость** → `IRough.BaseObject` (привязка к контуру/ребру). - ⛔/☐ **Линейный** — у `ILineDimension` нет `BaseObject`; нужен иной механизм (отложено). -- ☐ **Рамка/формат листа** (A4/A3…, ориентация) — `ILayoutSheet`/`SheetFormat`. Быстрый фундаментальный - шаг, вероятно без спайка. Делает чертёж «правильным» по ГОСТ. +- ✓ **Формат/ориентация листа** (A0–A5/user, книжная/альбомная) — `drawing_set_sheet_format` + (инкремент 8); `ILayoutSheet.Format`/`ISheetFormat`. Остаётся: ☐ рамка/основная надпись по + конкретному ГОСТ-стилю оформления (`LayoutLibraryFileName`/`LayoutStyleNumber`), несколько листов. - ☐ **Выноски** (`Leaders`) — `ISymbols2DContainer.Leaders` (полки-выноски с текстом). - ☐ **Обозначения баз** (`Bases`) — `ISymbols2DContainer.Bases`. - ☐ **Допуски формы и расположения** (`Tolerances`) — `ISymbols2DContainer.Tolerances` (обычно в связке с базой). diff --git a/docs/presentation.html b/docs/presentation.html index 44651ba..279c663 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+drawing_fill_title_block+drawing_add_linear_dimension+drawing_add_diametral_dimension+drawing_add_radial_dimension+drawing_add_angular_dimension+drawing_add_rough+drawing_add_text+drawing_set_technical_requirements+associate (81 инструмент) + Статус: 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+drawing_add_linear_dimension+drawing_add_diametral_dimension+drawing_add_radial_dimension+drawing_add_angular_dimension+drawing_add_rough+drawing_add_text+drawing_set_technical_requirements+associate+drawing_set_sheet_format (82 инструмента)

КОМПАС-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 · drawing_fill_title_block · drawing_add_linear_dimension · drawing_add_diametral_dimension · drawing_add_radial_dimension · drawing_add_angular_dimension · drawing_add_rough · drawing_add_text · drawing_set_technical_requirements · associate (ассоциативная привязка диам./радиального) · навык kompas-3d · 81 инструмент · 278 тестов
+
Общий прогресс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 · drawing_add_linear_dimension · drawing_add_diametral_dimension · drawing_add_radial_dimension · drawing_add_angular_dimension · drawing_add_rough · drawing_add_text · drawing_set_technical_requirements · associate (ассоциативная привязка диам./радиального) · drawing_set_sheet_format (формат листа) · навык kompas-3d · 82 инструмента · 308 тестов
@@ -297,7 +297,7 @@

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

-

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

+

82 инструмента, отдаются по 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) · drawing_fill_title_block (основная надпись/штамп: обозначение, наименование, материал, API7) · drawing_add_linear_dimension (линейный размер на виде, ISymbols2DContainer, API7) · drawing_add_diametral_dimension (диаметральный размер Ø, IDiametralDimension, associate=true для ассоциативной привязки к окружности, API7) · drawing_add_radial_dimension (радиальный размер R, IRadialDimension, associate=true аналогично, API7) · drawing_add_angular_dimension (угловой размер, IAngleDimension, angleType=min/max/more, API7) · drawing_add_rough (знак шероховатости, IRough/IRoughParams, signType=delete/without/none, API7) · drawing_add_text (свободный текст на виде, IDrawingContainer/IDrawingText, API7) · drawing_set_technical_requirements (тех. требования документа, IDrawingDocument/TechnicalDemand, API7)
  • -
  • 2D-чертёж: привязка к дуге (Arcs), ассоциативный угловой размер, ассоциативная шероховатость (IRough.BaseObject), рамка/формат, выноски (Leaders), обозначения баз (Bases), допуски формы (Tolerances) · пакет E (ось, угловая плоскость) · пакет D параметрика: параметрические эскизы (API2D) — исследовано, недоступно через COM API · прочие типы сопряжений (parallel/perpendicular/concentric/angle/tangency)
  • +
  • Drawing: drawing_create_standard_views (стандартные ассоциативные виды чертежа, API7) · drawing_fill_title_block (основная надпись/штамп: обозначение, наименование, материал, API7) · drawing_add_linear_dimension (линейный размер на виде, ISymbols2DContainer, API7) · drawing_add_diametral_dimension (диаметральный размер Ø, IDiametralDimension, associate=true для ассоциативной привязки к окружности, API7) · drawing_add_radial_dimension (радиальный размер R, IRadialDimension, associate=true аналогично, API7) · drawing_add_angular_dimension (угловой размер, IAngleDimension, angleType=min/max/more, API7) · drawing_add_rough (знак шероховатости, IRough/IRoughParams, signType=delete/without/none, API7) · drawing_add_text (свободный текст на виде, IDrawingContainer/IDrawingText, API7) · drawing_set_technical_requirements (тех. требования документа, IDrawingDocument/TechnicalDemand, API7) · drawing_set_sheet_format (формат и ориентация листа, ILayoutSheet/ISheetFormat, PaperFormat A0–A5/user, API7)
  • +
  • 2D-чертёж: рамка/основная надпись по ГОСТ-стилю (LayoutLibraryFileName/LayoutStyleNumber), несколько листов · привязка к дуге (Arcs), ассоциативный угловой размер, ассоциативная шероховатость (IRough.BaseObject) · выноски (Leaders), обозначения баз (Bases), допуски формы (Tolerances) · пакет E (ось, угловая плоскость) · пакет D параметрика: параметрические эскизы (API2D) — исследовано, недоступно через COM API · прочие типы сопряжений (parallel/perpendicular/concentric/angle/tangency)
@@ -322,7 +322,7 @@
  • Unit-тесты — без COM: диспетчер, enum-маппинг, StepFormat, InspectionText
  • Интеграционные тесты с КОМПАС: подключение, документы, снимок, цикл, STEP round-trip, сборка, move_face, инспекция
  • -
  • Итого 278 тестов зелёных (168 unit + 110 integration)
  • +
  • Итого 308 тестов зелёных (188 unit + 120 integration)
  • Сборка kompas-mcp.exe, README с конфигом клиента
  • Навык kompas-3d (методика) + полигон usecases/
  • In-process тест MCP-клиента, релизный publish
  • @@ -357,7 +357,8 @@
    2D-чертёж · инкремент 5 ✓

    Радиальный и угловой размеры

    drawing_add_radial_dimension (IRadialDimension, DimensionType=true, API7) · drawing_add_angular_dimension (IAngleDimension, angleType=min/max/more, AngleDimensionType enum, API7) · базовое семейство размеров завершено · 78 инструментов · 241 тест

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

    Текстовые обозначения

    drawing_add_rough (IRough/IRoughParams, signType=delete/without/none, API7) · drawing_add_text (IDrawingContainer/IDrawingText/IText, API7) · drawing_set_technical_requirements (IDrawingDocument/TechnicalDemand, уровень документа, API7) · DrawingAnnotationResult · RoughSignType enum · 81 инструмент · 267 тестов

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

    Ассоциативная привязка к окружности

    associate=true у drawing_add_diametral_dimension и drawing_add_radial_dimension · CircularObjectMatch (поиск по центру+радиусу, допуск 1 мм) · RequireViewContainers · dim.BaseObject=circle · значение из геометрии · 81 инструмент · 278 тестов

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

    Оформление чертежа

    Привязка к дуге (Arcs) · ассоциативный угловой размер · ассоциативная шероховатость (IRough.BaseObject) · рамка/формат · выноски (Leaders) · обозначения баз (Bases) · допуски формы (Tolerances) · пакет E (ось, угловая плоскость) · прочие типы сопряжений (parallel/perpendicular/concentric/angle/tangency) · пакет D параметрика — параметрические эскизы недоступны через COM API

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

    Формат и ориентация листа

    drawing_set_sheet_format (ILayoutSheet.Format / ISheetFormat, ksDocumentFormatEnum, A0–A5/user, VerticalOrientation) · PaperFormat enum · SheetFormatResult · ValidateFormatDimensions · 82 инструмента · 308 тестов

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

    Оформление чертежа

    Рамка/надпись по ГОСТ-стилю (LayoutLibraryFileName) · несколько листов · привязка к дуге (Arcs) · ассоциативный угловой размер · ассоциативная шероховатость (IRough.BaseObject) · выноски (Leaders) · обозначения баз (Bases) · допуски формы (Tolerances) · пакет E (ось, угловая плоскость) · прочие типы сопряжений (parallel/perpendicular/concentric/angle/tangency) · пакет D параметрика — параметрические эскизы недоступны через COM API

diff --git a/docs/superpowers/specs/2026-05-27-drawing-sheet-format-design.md b/docs/superpowers/specs/2026-05-27-drawing-sheet-format-design.md index 98fad39..1f9abf7 100644 --- a/docs/superpowers/specs/2026-05-27-drawing-sheet-format-design.md +++ b/docs/superpowers/specs/2026-05-27-drawing-sheet-format-design.md @@ -3,7 +3,21 @@ **Дата:** 2026-05-27 **Статус:** дизайн согласован, спайк проведён, ревью pi/glm-5.1 + pi/kimi-k2.6 учтено — к реализации -## Правки по ревью (pi/glm-5.1 + pi/kimi-k2.6) +## Правки по ревью реализации (Codex + pi/glm-5.1 + pi/kimi-k2.6) + +- **K1 (kimi, Major)** — опасение, что для `User` read-back ориентации устаревший (VerticalOrientation + не задаётся). **Снято спайком:** КОМПАС САМ выводит `VerticalOrientation` из соотношения W/H + (500×300→альбомная, 300×500→книжная), игнорирует заданный флаг и НЕ свопает W/H → read-back верный, + код корректен. Документировано комментарием; добавлены тесты на `Landscape` для User (обе ориентации). +- **K2** — `ValidateFormatDimensions` теперь называет точный нарушивший параметр (`width`/`height`). +- **C1/G1/K3** — тесты User проверяют `Landscape`. **C2/G3** — тест `sheetNumber=0`→`ArgumentOutOfRangeException`. + **C3** — A1 в `Parse`-тесте. **G2** — тест A4 landscape (своп 297×210). +- Отклонено (нит): **G4** алиасы в описании (lenient parse — намеренно), **G5** сообщение при NaN + (для стандартного «размеры только для user» приемлемо), **K5** тип исключения для стандартного формата (ArgumentException + для «неверная комбинация» vs AOORE для «вне диапазона» — намеренное различие, на нём держатся тесты), + **G6** «нет unit для ValidateFormatDimensions» — ложно, покрыто в `DrawingValidationTests`. + +## Правки по ревью спека (pi/glm-5.1 + pi/kimi-k2.6) - **A** для `user` флаг `landscape` **игнорируется** — ориентация задаётся соотношением `width`/`height` (КОМПАС сам выставит `VerticalOrientation`). `VerticalOrientation=!landscape` ставим ТОЛЬКО для